@@ -86,6 +86,7 @@ def _print_banner() -> None:
8686 { g } register{ r } Register a repository in the multi-repo registry
8787 { g } unregister{ r } Remove a repository from the registry
8888 { g } repos{ r } List registered repositories
89+ { g } postprocess{ r } Run post-processing { d } (flows, communities, FTS){ r }
8990 { g } eval{ r } Run evaluation benchmarks
9091 { g } serve{ r } Start MCP server
9192
@@ -226,11 +227,37 @@ def main() -> None:
226227 # build
227228 build_cmd = sub .add_parser ("build" , help = "Full graph build (re-parse all files)" )
228229 build_cmd .add_argument ("--repo" , default = None , help = "Repository root (auto-detected)" )
230+ build_cmd .add_argument (
231+ "--skip-flows" , action = "store_true" ,
232+ help = "Skip flow/community detection (signatures + FTS only)" ,
233+ )
234+ build_cmd .add_argument (
235+ "--skip-postprocess" , action = "store_true" ,
236+ help = "Skip all post-processing (raw parse only)" ,
237+ )
229238
230239 # update
231240 update_cmd = sub .add_parser ("update" , help = "Incremental update (only changed files)" )
232241 update_cmd .add_argument ("--base" , default = "HEAD~1" , help = "Git diff base (default: HEAD~1)" )
233242 update_cmd .add_argument ("--repo" , default = None , help = "Repository root (auto-detected)" )
243+ update_cmd .add_argument (
244+ "--skip-flows" , action = "store_true" ,
245+ help = "Skip flow/community detection (signatures + FTS only)" ,
246+ )
247+ update_cmd .add_argument (
248+ "--skip-postprocess" , action = "store_true" ,
249+ help = "Skip all post-processing (raw parse only)" ,
250+ )
251+
252+ # postprocess
253+ pp_cmd = sub .add_parser (
254+ "postprocess" ,
255+ help = "Run post-processing on existing graph (flows, communities, FTS)" ,
256+ )
257+ pp_cmd .add_argument ("--repo" , default = None , help = "Repository root (auto-detected)" )
258+ pp_cmd .add_argument ("--no-flows" , action = "store_true" , help = "Skip flow detection" )
259+ pp_cmd .add_argument ("--no-communities" , action = "store_true" , help = "Skip community detection" )
260+ pp_cmd .add_argument ("--no-fts" , action = "store_true" , help = "Skip FTS rebuild" )
234261
235262 # watch
236263 watch_cmd = sub .add_parser ("watch" , help = "Watch for changes and auto-update" )
@@ -243,6 +270,12 @@ def main() -> None:
243270 # visualize
244271 vis_cmd = sub .add_parser ("visualize" , help = "Generate interactive HTML graph visualization" )
245272 vis_cmd .add_argument ("--repo" , default = None , help = "Repository root (auto-detected)" )
273+ vis_cmd .add_argument (
274+ "--mode" ,
275+ choices = ["auto" , "full" , "community" , "file" ],
276+ default = "auto" ,
277+ help = "Rendering mode: auto (default), full, community, or file" ,
278+ )
246279 vis_cmd .add_argument (
247280 "--serve" , action = "store_true" ,
248281 help = "Start a local HTTP server to view the visualization (localhost:8765)" ,
@@ -402,6 +435,30 @@ def main() -> None:
402435 watch ,
403436 )
404437
438+ if args .command == "postprocess" :
439+ repo_root = Path (args .repo ) if args .repo else find_project_root ()
440+ db_path = get_db_path (repo_root )
441+ store = GraphStore (db_path )
442+ try :
443+ from .tools .build import run_postprocess
444+ result = run_postprocess (
445+ flows = not getattr (args , "no_flows" , False ),
446+ communities = not getattr (args , "no_communities" , False ),
447+ fts = not getattr (args , "no_fts" , False ),
448+ repo_root = str (repo_root ),
449+ )
450+ parts = []
451+ if result .get ("flows_detected" ):
452+ parts .append (f"{ result ['flows_detected' ]} flows" )
453+ if result .get ("communities_detected" ):
454+ parts .append (f"{ result ['communities_detected' ]} communities" )
455+ if result .get ("fts_indexed" ):
456+ parts .append (f"{ result ['fts_indexed' ]} FTS entries" )
457+ print (f"Post-processing: { ', ' .join (parts ) or 'done' } " )
458+ finally :
459+ store .close ()
460+ return
461+
405462 if args .command in ("update" , "detect-changes" ):
406463 # update and detect-changes require git for diffing
407464 repo_root = Path (args .repo ) if args .repo else find_repo_root ()
@@ -420,19 +477,40 @@ def main() -> None:
420477
421478 try :
422479 if args .command == "build" :
423- result = full_build (repo_root , store )
480+ pp = "none" if getattr (args , "skip_postprocess" , False ) else (
481+ "minimal" if getattr (args , "skip_flows" , False ) else "full"
482+ )
483+ from .tools .build import build_or_update_graph
484+ result = build_or_update_graph (
485+ full_rebuild = True , repo_root = str (repo_root ), postprocess = pp ,
486+ )
487+ parsed = result .get ("files_parsed" , 0 )
488+ nodes = result .get ("total_nodes" , 0 )
489+ edges = result .get ("total_edges" , 0 )
424490 print (
425- f"Full build: { result ['files_parsed' ]} files, "
426- f"{ result ['total_nodes' ]} nodes, { result ['total_edges' ]} edges"
491+ f"Full build: { parsed } files, "
492+ f"{ nodes } nodes, { edges } edges"
493+ f" (postprocess={ pp } )"
427494 )
428- if result [ "errors" ] :
495+ if result . get ( "errors" ) :
429496 print (f"Errors: { len (result ['errors' ])} " )
430497
431498 elif args .command == "update" :
432- result = incremental_update (repo_root , store , base = args .base )
499+ pp = "none" if getattr (args , "skip_postprocess" , False ) else (
500+ "minimal" if getattr (args , "skip_flows" , False ) else "full"
501+ )
502+ from .tools .build import build_or_update_graph
503+ result = build_or_update_graph (
504+ full_rebuild = False , repo_root = str (repo_root ),
505+ base = args .base , postprocess = pp ,
506+ )
507+ updated = result .get ("files_updated" , 0 )
508+ nodes = result .get ("total_nodes" , 0 )
509+ edges = result .get ("total_edges" , 0 )
433510 print (
434- f"Incremental: { result ['files_updated' ]} files updated, "
435- f"{ result ['total_nodes' ]} nodes, { result ['total_edges' ]} edges"
511+ f"Incremental: { updated } files updated, "
512+ f"{ nodes } nodes, { edges } edges"
513+ f" (postprocess={ pp } )"
436514 )
437515
438516 elif args .command == "status" :
@@ -464,8 +542,9 @@ def main() -> None:
464542 elif args .command == "visualize" :
465543 from .visualization import generate_html
466544 html_path = repo_root / ".code-review-graph" / "graph.html"
467- generate_html (store , html_path )
468- print (f"Visualization: { html_path } " )
545+ vis_mode = getattr (args , "mode" , "auto" ) or "auto"
546+ generate_html (store , html_path , mode = vis_mode )
547+ print (f"Visualization ({ vis_mode } ): { html_path } " )
469548 if getattr (args , "serve" , False ):
470549 import functools
471550 import http .server
0 commit comments