@@ -114,17 +114,17 @@ def parse_repository(
114114 if language == "python" :
115115 result = _parse_python (repo_path , output_dir , processing_level , skip_tests , name , library_mode )
116116 elif language == "javascript" :
117- result = _parse_javascript (repo_path , output_dir , processing_level , skip_tests , name )
117+ result = _parse_javascript (repo_path , output_dir , processing_level , skip_tests , name , library_mode )
118118 elif language == "go" :
119- result = _parse_go (repo_path , output_dir , processing_level , skip_tests , name )
119+ result = _parse_go (repo_path , output_dir , processing_level , skip_tests , name , library_mode )
120120 elif language == "c" :
121- result = _parse_c (repo_path , output_dir , processing_level , skip_tests , name )
121+ result = _parse_c (repo_path , output_dir , processing_level , skip_tests , name , library_mode )
122122 elif language == "ruby" :
123- result = _parse_ruby (repo_path , output_dir , processing_level , skip_tests , name )
123+ result = _parse_ruby (repo_path , output_dir , processing_level , skip_tests , name , library_mode )
124124 elif language == "php" :
125- result = _parse_php (repo_path , output_dir , processing_level , skip_tests , name )
125+ result = _parse_php (repo_path , output_dir , processing_level , skip_tests , name , library_mode )
126126 elif language == "zig" :
127- result = _parse_zig (repo_path , output_dir , processing_level , skip_tests , name )
127+ result = _parse_zig (repo_path , output_dir , processing_level , skip_tests , name , library_mode )
128128 else :
129129 raise ValueError (f"Unsupported language: { language } " )
130130
@@ -192,26 +192,10 @@ def _maybe_apply_diff_filter(
192192# Reachability filter (shared by Python path; JS/Go handle it internally)
193193# ---------------------------------------------------------------------------
194194
195- def _library_seed_ids (functions : dict ) -> "set[str]" :
196- """Public-API seed set for library-mode reachability.
197-
198- A pure library exposes no main/route/CLI entry point, so the structural
199- detector finds nothing and the whole library is filtered out (0 reachable).
200- In library-mode the *public surface* IS the entry surface: seed every
201- exported/public function and let the forward BFS pull in its callees.
202-
203- Public = exported AND not name-private. ``is_exported`` is honoured when the
204- parser provides it (C/Go/JS — excludes ``static``/unexported); for parsers
205- without the field (python/ruby/php) it defaults True and the name heuristic
206- (leading underscore = private) decides. The bias is intentionally toward
207- over-seeding (more reachable = more analysed), never under-seeding.
208- """
209- seeds : set [str ] = set ()
210- for func_id , fd in functions .items ():
211- name = (fd .get ("name" ) or func_id .rsplit (":" , 1 )[- 1 ]).split ("." )[- 1 ]
212- if fd .get ("is_exported" , True ) and not name .startswith ("_" ):
213- seeds .add (func_id )
214- return seeds
195+ # library_seed_ids is now shared in utilities/agentic_enhancer/entry_point_detector.py
196+ # so every parser pipeline (not just Python) can seed the public API. It is loaded
197+ # below via the same importlib path as EntryPointDetector to dodge the heavy
198+ # utilities/__init__ imports.
215199
216200
217201def apply_reachability_filter (
@@ -263,6 +247,7 @@ def _load_module(name, filename):
263247 _ra = _load_module ("reachability_analyzer" , "reachability_analyzer.py" )
264248 EntryPointDetector = _epd .EntryPointDetector
265249 blackout_warning = _epd .blackout_warning
250+ library_seed_ids = _epd .library_seed_ids
266251 ReachabilityAnalyzer = _ra .ReachabilityAnalyzer
267252
268253 call_graph_path = os .path .join (output_dir , "call_graph.json" )
@@ -290,7 +275,7 @@ def _load_module(name, filename):
290275 # never demotes a structurally-detected app entry point, so an app scan with
291276 # the flag on can only gain reachable units, never lose one.
292277 if library_mode :
293- entry_points = entry_points | _library_seed_ids (functions )
278+ entry_points = entry_points | library_seed_ids (functions )
294279
295280 units = dataset .get ("units" , [])
296281 original_count = len (units )
@@ -544,7 +529,7 @@ def _file_lock(lock_path: Path):
544529 f .close ()
545530
546531
547- def _parse_javascript (repo_path : str , output_dir : str , processing_level : str , skip_tests : bool = True , name : str = None ) -> ParseResult :
532+ def _parse_javascript (repo_path : str , output_dir : str , processing_level : str , skip_tests : bool = True , name : str = None , library_mode : bool = False ) -> ParseResult :
548533 """Invoke the JavaScript/TypeScript parser.
549534
550535 The JS parser is a PipelineTest class that runs Node.js subprocesses.
@@ -568,6 +553,8 @@ def _parse_javascript(repo_path: str, output_dir: str, processing_level: str, sk
568553 cmd .extend (["--name" , name ])
569554 if skip_tests :
570555 cmd .append ("--skip-tests" )
556+ if library_mode :
557+ cmd .append ("--library-mode" )
571558
572559 result = subprocess .run (
573560 cmd ,
@@ -603,7 +590,7 @@ def _parse_javascript(repo_path: str, output_dir: str, processing_level: str, sk
603590# Go parser
604591# ---------------------------------------------------------------------------
605592
606- def _parse_go (repo_path : str , output_dir : str , processing_level : str , skip_tests : bool = True , name : str = None ) -> ParseResult :
593+ def _parse_go (repo_path : str , output_dir : str , processing_level : str , skip_tests : bool = True , name : str = None , library_mode : bool = False ) -> ParseResult :
607594 """Invoke the Go parser.
608595
609596 The Go parser is a PipelineTest class that calls a compiled Go binary.
@@ -624,6 +611,8 @@ def _parse_go(repo_path: str, output_dir: str, processing_level: str, skip_tests
624611 cmd .extend (["--name" , name ])
625612 if skip_tests :
626613 cmd .append ("--skip-tests" )
614+ if library_mode :
615+ cmd .append ("--library-mode" )
627616
628617 result = subprocess .run (
629618 cmd ,
@@ -659,7 +648,7 @@ def _parse_go(repo_path: str, output_dir: str, processing_level: str, skip_tests
659648# C/C++ parser
660649# ---------------------------------------------------------------------------
661650
662- def _parse_c (repo_path : str , output_dir : str , processing_level : str , skip_tests : bool = True , name : str = None ) -> ParseResult :
651+ def _parse_c (repo_path : str , output_dir : str , processing_level : str , skip_tests : bool = True , name : str = None , library_mode : bool = False ) -> ParseResult :
663652 """Invoke the C/C++ parser.
664653
665654 The C parser uses tree-sitter for function extraction and call graph
@@ -682,6 +671,8 @@ def _parse_c(repo_path: str, output_dir: str, processing_level: str, skip_tests:
682671 cmd .extend (["--name" , name ])
683672 if skip_tests :
684673 cmd .append ("--skip-tests" )
674+ if library_mode :
675+ cmd .append ("--library-mode" )
685676
686677 result = subprocess .run (
687678 cmd ,
@@ -718,7 +709,7 @@ def _parse_c(repo_path: str, output_dir: str, processing_level: str, skip_tests:
718709# Ruby parser
719710# ---------------------------------------------------------------------------
720711
721- def _parse_ruby (repo_path : str , output_dir : str , processing_level : str , skip_tests : bool = True , name : str = None ) -> ParseResult :
712+ def _parse_ruby (repo_path : str , output_dir : str , processing_level : str , skip_tests : bool = True , name : str = None , library_mode : bool = False ) -> ParseResult :
722713 """Invoke the Ruby parser.
723714
724715 The Ruby parser uses tree-sitter for function extraction and call graph
@@ -741,6 +732,8 @@ def _parse_ruby(repo_path: str, output_dir: str, processing_level: str, skip_tes
741732 cmd .extend (["--name" , name ])
742733 if skip_tests :
743734 cmd .append ("--skip-tests" )
735+ if library_mode :
736+ cmd .append ("--library-mode" )
744737
745738 result = subprocess .run (
746739 cmd ,
@@ -777,7 +770,7 @@ def _parse_ruby(repo_path: str, output_dir: str, processing_level: str, skip_tes
777770# PHP parser
778771# ---------------------------------------------------------------------------
779772
780- def _parse_php (repo_path : str , output_dir : str , processing_level : str , skip_tests : bool = True , name : str = None ) -> ParseResult :
773+ def _parse_php (repo_path : str , output_dir : str , processing_level : str , skip_tests : bool = True , name : str = None , library_mode : bool = False ) -> ParseResult :
781774 """Invoke the PHP parser.
782775
783776 The PHP parser uses tree-sitter for function extraction and call graph
@@ -800,6 +793,8 @@ def _parse_php(repo_path: str, output_dir: str, processing_level: str, skip_test
800793 cmd .extend (["--name" , name ])
801794 if skip_tests :
802795 cmd .append ("--skip-tests" )
796+ if library_mode :
797+ cmd .append ("--library-mode" )
803798
804799 result = subprocess .run (
805800 cmd ,
@@ -836,7 +831,7 @@ def _parse_php(repo_path: str, output_dir: str, processing_level: str, skip_test
836831# Zig parser
837832# ---------------------------------------------------------------------------
838833
839- def _parse_zig (repo_path : str , output_dir : str , processing_level : str , skip_tests : bool = True , name : str = None ) -> ParseResult :
834+ def _parse_zig (repo_path : str , output_dir : str , processing_level : str , skip_tests : bool = True , name : str = None , library_mode : bool = False ) -> ParseResult :
840835 """Invoke the Zig parser.
841836
842837 The Zig parser uses tree-sitter for function extraction and call graph
@@ -859,6 +854,8 @@ def _parse_zig(repo_path: str, output_dir: str, processing_level: str, skip_test
859854 cmd .extend (["--name" , name ])
860855 if skip_tests :
861856 cmd .append ("--skip-tests" )
857+ if library_mode :
858+ cmd .append ("--library-mode" )
862859
863860 result = subprocess .run (
864861 cmd ,
0 commit comments