2121 index_dir_has_existing_artifacts ,
2222 resolve_operator_config ,
2323)
24- from java_codebase_rag .pipeline import clip , run_build_ast_graph , run_cocoindex_drop , run_cocoindex_update
24+ from java_codebase_rag .pipeline import clip , run_build_ast_graph , run_build_ast_graph_incremental , run_cocoindex_drop , run_cocoindex_update
25+ from refresh_decision import choose_refresh_mode
2526from java_ontology import VALID_UNRESOLVED_CALL_REASONS
2627
27- KUZU_INCREMENTAL_TRACKING_ISSUE_URL = "https://github.com/HumanBean17/java-codebase-rag/issues/73"
28-
29- _INCREMENT_WARNING_LINES = (
30- "WARNING: AST graph (Kuzu) incremental rebuild is not yet implemented." ,
31- "The graph reflects the index state from the last `init` or `reprocess`," ,
32- "which means `find`, `neighbors`, and `describe` may return stale results" ,
33- "for files changed since then." ,
34- "" ,
35- "Lance vector index has been updated incrementally and is current." ,
36- "" ,
37- "For an up-to-date graph, run:" ,
38- " java-codebase-rag reprocess" ,
39- "" ,
40- "Track progress on Kuzu incremental rebuild:" ,
41- f" { KUZU_INCREMENTAL_TRACKING_ISSUE_URL } " ,
42- )
43-
4428_REFRESH_DEPRECATION = (
4529 "WARN: 'refresh' is deprecated; use 'reprocess'. "
4630 "This alias will be removed in the next release."
@@ -178,11 +162,6 @@ def _emit(value: Any) -> None:
178162 print (json .dumps (payload , default = _jsonable , sort_keys = True , indent = None ))
179163
180164
181- def _emit_increment_kuzu_warning () -> None :
182- for line in _INCREMENT_WARNING_LINES :
183- print (line , file = sys .stderr )
184-
185-
186165def _parse_source_root (ns : argparse .Namespace ) -> Path | None :
187166 if ns .source_root :
188167 return Path (ns .source_root ).expanduser ().resolve ()
@@ -298,15 +277,25 @@ def _cmd_increment(args: argparse.Namespace) -> int:
298277 cfg = _resolved_from_ns (args )
299278 _startup_hints (cfg )
300279 cfg .apply_to_os_environ ()
301- _emit_increment_kuzu_warning ()
302280
303281 def work () -> int :
304282 env = cfg .subprocess_env ()
283+ verbose = bool (args .verbose )
284+
285+ # Decide refresh mode first so Lance mode is known
286+ decision = choose_refresh_mode (
287+ cfg .source_root ,
288+ cfg .kuzu_path ,
289+ mode = "auto" ,
290+ )
291+
292+ # Lance update — full when decision engine says so (config/pipeline change)
293+ lance_full = decision .lance_mode == "full"
305294 coco = run_cocoindex_update (
306295 env ,
307- full_reprocess = False ,
296+ full_reprocess = lance_full ,
308297 quiet = bool (args .quiet ),
309- verbose = bool ( args . verbose ) ,
298+ verbose = verbose ,
310299 lance_project_root = None if args .quiet else cfg .source_root ,
311300 )
312301 if coco .returncode != 0 :
@@ -320,7 +309,72 @@ def work() -> int:
320309 }
321310 )
322311 return 1
323- _emit ({"success" : True , "message" : "increment completed (Lance only; graph may be stale — see stderr)" })
312+
313+ # Kuzu rebuild based on decision
314+ if decision .kuzu_mode == "incremental" and decision .detected_changes .modified :
315+ changed = set (decision .detected_changes .modified + decision .detected_changes .added )
316+ if not args .quiet and verbose :
317+ for r in decision .reasons :
318+ print (f" [graph] { r } " , file = sys .stderr )
319+ g = run_build_ast_graph_incremental (
320+ source_root = cfg .source_root ,
321+ kuzu_path = cfg .kuzu_path ,
322+ changed_paths = changed ,
323+ verbose = verbose ,
324+ quiet = bool (args .quiet ),
325+ env = env ,
326+ )
327+ if g .returncode != 0 :
328+ # Incremental failed — fall back to full
329+ print (
330+ f"[graph] incremental failed (exit { g .returncode } ), falling back to full rebuild" ,
331+ file = sys .stderr ,
332+ )
333+ g = run_build_ast_graph (
334+ source_root = cfg .source_root ,
335+ kuzu_path = cfg .kuzu_path ,
336+ verbose = verbose ,
337+ quiet = bool (args .quiet ),
338+ env = env ,
339+ )
340+ if g .returncode != 0 :
341+ _emit (
342+ {
343+ "success" : False ,
344+ "exit_code" : g .returncode ,
345+ "stdout" : clip (g .stdout , 4000 ),
346+ "stderr" : clip (g .stderr , 4000 ),
347+ "message" : f"graph builder exit { g .returncode } " ,
348+ }
349+ )
350+ return 1
351+ else :
352+ # Full Kuzu rebuild
353+ if not args .quiet :
354+ for r in decision .reasons :
355+ print (f" [graph] { r } " , file = sys .stderr )
356+ if decision .reasons :
357+ print (" [graph] falling back to full Kuzu rebuild" , file = sys .stderr )
358+ g = run_build_ast_graph (
359+ source_root = cfg .source_root ,
360+ kuzu_path = cfg .kuzu_path ,
361+ verbose = verbose ,
362+ quiet = bool (args .quiet ),
363+ env = env ,
364+ )
365+ if g .returncode != 0 :
366+ _emit (
367+ {
368+ "success" : False ,
369+ "exit_code" : g .returncode ,
370+ "stdout" : clip (g .stdout , 4000 ),
371+ "stderr" : clip (g .stderr , 4000 ),
372+ "message" : f"graph builder exit { g .returncode } " ,
373+ }
374+ )
375+ return 1
376+
377+ _emit ({"success" : True , "message" : "increment completed" })
324378 return 0
325379
326380 return _run_with_pipeline_progress ("increment" , cfg , quiet = bool (args .quiet ), work = work )
@@ -615,7 +669,7 @@ def build_parser() -> argparse.ArgumentParser:
615669 "--quiet suppresses that stream; stdout remains the machine-readable payload.\n \n "
616670 "Lifecycle (manage the index):\n "
617671 " init Create a fresh index from a Java repository.\n "
618- " increment Pick up changes since the last index update (Lance only ).\n "
672+ " increment Pick up changes since the last index update (Lance + Kuzu incremental ).\n "
619673 " reprocess Full vector + graph rebuild (default); optional --vectors-only / --graph-only.\n "
620674 " erase Delete the index from disk.\n \n "
621675 "Introspection (inspect the index):\n "
@@ -650,7 +704,7 @@ def build_parser() -> argparse.ArgumentParser:
650704 increment = subparsers .add_parser (
651705 "increment" ,
652706 help = "Pick up changes since the last index update." ,
653- description = "Runs cocoindex catch-up (no full reprocess). Does not rebuild Kuzu; see stderr warning ." ,
707+ description = "Runs cocoindex catch-up (no full reprocess). Kuzu graph updated incrementally when safe; full rebuild as fallback ." ,
654708 )
655709 _add_index_embedding_flags (increment )
656710 _add_verbosity_flags (increment )
0 commit comments