ref-agents 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. ref_agents/__init__.py +9 -0
  2. ref_agents/api_keys.json.example +8 -0
  3. ref_agents/auth.py +129 -0
  4. ref_agents/codemap/..md +62 -0
  5. ref_agents/codemap/CODE_MAP.md +37 -0
  6. ref_agents/codemap/core.md +43 -0
  7. ref_agents/codemap/models.md +43 -0
  8. ref_agents/codemap/prompts.md +40 -0
  9. ref_agents/codemap/security.md +45 -0
  10. ref_agents/codemap/tools.md +94 -0
  11. ref_agents/codemap/tools_browser.md +44 -0
  12. ref_agents/codemap/utils.md +42 -0
  13. ref_agents/codemap/workflow.md +42 -0
  14. ref_agents/config/ai_patterns.yaml +101 -0
  15. ref_agents/config/frameworks/angular.yaml +104 -0
  16. ref_agents/config/frameworks/aspnet.yaml +84 -0
  17. ref_agents/config/frameworks/ef_core.yaml +81 -0
  18. ref_agents/config/frameworks/react.yaml +111 -0
  19. ref_agents/config/frameworks/spring_boot.yaml +117 -0
  20. ref_agents/config/languages/csharp.yaml +153 -0
  21. ref_agents/config/languages/java.yaml +188 -0
  22. ref_agents/config/languages/javascript.yaml +172 -0
  23. ref_agents/config/languages/python.yaml +153 -0
  24. ref_agents/config/languages/typescript.yaml +193 -0
  25. ref_agents/constants.py +553 -0
  26. ref_agents/core/__init__.py +15 -0
  27. ref_agents/core/config_loader.py +160 -0
  28. ref_agents/core/config_models.py +167 -0
  29. ref_agents/core/config_parsing.py +84 -0
  30. ref_agents/core/language_detector.py +388 -0
  31. ref_agents/core/validation_models.py +66 -0
  32. ref_agents/core/validation_primitives.py +176 -0
  33. ref_agents/errors.py +34 -0
  34. ref_agents/license_client.py +247 -0
  35. ref_agents/models/__init__.py +22 -0
  36. ref_agents/models/gherkin.py +45 -0
  37. ref_agents/models/hierarchy.py +80 -0
  38. ref_agents/models/invest.py +59 -0
  39. ref_agents/models/version.py +49 -0
  40. ref_agents/prompts/__init__.py +9 -0
  41. ref_agents/prompts/start_agent.py +772 -0
  42. ref_agents/rules/architecture/backend_patterns.md +43 -0
  43. ref_agents/rules/architecture/diagramming.md +100 -0
  44. ref_agents/rules/architecture/frontend_patterns.md +40 -0
  45. ref_agents/rules/architecture/impact_analysis.md +129 -0
  46. ref_agents/rules/architecture/migration_strategy.md +208 -0
  47. ref_agents/rules/architecture/regression_protocol.md +77 -0
  48. ref_agents/rules/architecture/system_design.md +97 -0
  49. ref_agents/rules/common/codemap_standard.md +97 -0
  50. ref_agents/rules/common/core_protocol.md +59 -0
  51. ref_agents/rules/common/prompt_engineering.md +294 -0
  52. ref_agents/rules/development/debugging.md +32 -0
  53. ref_agents/rules/development/implementation.md +205 -0
  54. ref_agents/rules/operations/completion.md +119 -0
  55. ref_agents/rules/operations/cutover_protocol.md +218 -0
  56. ref_agents/rules/operations/discovery.md +179 -0
  57. ref_agents/rules/operations/fix_workflow.md +87 -0
  58. ref_agents/rules/operations/forensics.md +278 -0
  59. ref_agents/rules/operations/platform.md +263 -0
  60. ref_agents/rules/operations/synchronous_flow.md +25 -0
  61. ref_agents/rules/product/ac_validation.md +25 -0
  62. ref_agents/rules/product/brainstorming.md +27 -0
  63. ref_agents/rules/product/ref_flow.md +101 -0
  64. ref_agents/rules/product/requirements_std.md +114 -0
  65. ref_agents/rules/product/spec_writing.md +235 -0
  66. ref_agents/rules/product/strategy.md +96 -0
  67. ref_agents/rules/quality/documentation_standards.md +46 -0
  68. ref_agents/rules/quality/parity_testing.md +234 -0
  69. ref_agents/rules/quality/project_documentation.md +56 -0
  70. ref_agents/rules/quality/qa_lead.md +111 -0
  71. ref_agents/rules/quality/test_design.md +146 -0
  72. ref_agents/rules/quality/testing_standards.md +293 -0
  73. ref_agents/rules/review/pr_review.md +116 -0
  74. ref_agents/rules/security/security_audit.md +83 -0
  75. ref_agents/security/__init__.py +22 -0
  76. ref_agents/security/dependency_audit.py +188 -0
  77. ref_agents/security/file_audit.py +208 -0
  78. ref_agents/security/network_scan.py +179 -0
  79. ref_agents/security/report_generator.py +313 -0
  80. ref_agents/security/secret_scan.py +252 -0
  81. ref_agents/security/url_scan.py +240 -0
  82. ref_agents/security_scan.py +236 -0
  83. ref_agents/server.py +1586 -0
  84. ref_agents/session.py +100 -0
  85. ref_agents/tool_names.py +55 -0
  86. ref_agents/tools/__init__.py +8 -0
  87. ref_agents/tools/agents_generator.py +315 -0
  88. ref_agents/tools/ai_pattern_detector.py +815 -0
  89. ref_agents/tools/brownfield_populator.py +529 -0
  90. ref_agents/tools/browser/__init__.py +50 -0
  91. ref_agents/tools/browser/evidence_verifier.py +302 -0
  92. ref_agents/tools/browser/execution_logger.py +249 -0
  93. ref_agents/tools/browser/playwright_mcp_client.py +259 -0
  94. ref_agents/tools/browser/screenshot_utils.py +184 -0
  95. ref_agents/tools/browser/test_executor.py +537 -0
  96. ref_agents/tools/code_quality_scanner.py +629 -0
  97. ref_agents/tools/codemap/..md +93 -0
  98. ref_agents/tools/codemap/CODE_MAP.md +30 -0
  99. ref_agents/tools/codemap/browser.md +44 -0
  100. ref_agents/tools/codemap.py +403 -0
  101. ref_agents/tools/codemap_freshness.py +234 -0
  102. ref_agents/tools/comment_smell_scanner.py +346 -0
  103. ref_agents/tools/complexity.py +436 -0
  104. ref_agents/tools/complexity_ast.py +333 -0
  105. ref_agents/tools/compliance.py +246 -0
  106. ref_agents/tools/compliance_remediation.py +846 -0
  107. ref_agents/tools/context_graph.py +839 -0
  108. ref_agents/tools/context_manager.py +550 -0
  109. ref_agents/tools/context_tools.py +121 -0
  110. ref_agents/tools/cross_repo_linker.py +393 -0
  111. ref_agents/tools/dead_code_scanner.py +637 -0
  112. ref_agents/tools/debt_scanner.py +1092 -0
  113. ref_agents/tools/dependency_graph.py +272 -0
  114. ref_agents/tools/discovery_audit.py +372 -0
  115. ref_agents/tools/docs_scanner.py +600 -0
  116. ref_agents/tools/evaluate_gate.py +119 -0
  117. ref_agents/tools/external_detector.py +524 -0
  118. ref_agents/tools/features_generator.py +282 -0
  119. ref_agents/tools/flow_gap_detector.py +373 -0
  120. ref_agents/tools/flow_mapper.py +327 -0
  121. ref_agents/tools/full_suite_runner.py +740 -0
  122. ref_agents/tools/gherkin_parser.py +227 -0
  123. ref_agents/tools/guard_tools.py +139 -0
  124. ref_agents/tools/handoff_tools.py +282 -0
  125. ref_agents/tools/health_scanner.py +1211 -0
  126. ref_agents/tools/hierarchy_manager.py +289 -0
  127. ref_agents/tools/invest_scorer.py +249 -0
  128. ref_agents/tools/jira_confluence_export.py +306 -0
  129. ref_agents/tools/json_output.py +76 -0
  130. ref_agents/tools/migration_mapper.py +946 -0
  131. ref_agents/tools/migration_readiness_scanner.py +209 -0
  132. ref_agents/tools/pattern_learner.py +522 -0
  133. ref_agents/tools/report_utils.py +155 -0
  134. ref_agents/tools/requirements_serializer.py +225 -0
  135. ref_agents/tools/security_audit_tool.py +106 -0
  136. ref_agents/tools/sequencing_engine.py +288 -0
  137. ref_agents/tools/summary_generator.py +275 -0
  138. ref_agents/tools/symbol_resolver.py +306 -0
  139. ref_agents/tools/symbol_smoke_runner.py +336 -0
  140. ref_agents/tools/test_plan_validator.py +189 -0
  141. ref_agents/tools/test_smell_walker.py +902 -0
  142. ref_agents/tools/tier1_fixer.py +502 -0
  143. ref_agents/tools/validators/__init__.py +419 -0
  144. ref_agents/tools/validators/architect.py +268 -0
  145. ref_agents/tools/validators/cutover_engineer.py +167 -0
  146. ref_agents/tools/validators/developer.py +180 -0
  147. ref_agents/tools/validators/discovery.py +150 -0
  148. ref_agents/tools/validators/forensic_engineer.py +191 -0
  149. ref_agents/tools/validators/impact_architect.py +181 -0
  150. ref_agents/tools/validators/migration_planner.py +166 -0
  151. ref_agents/tools/validators/parity_tester.py +155 -0
  152. ref_agents/tools/validators/platform_engineer.py +134 -0
  153. ref_agents/tools/validators/pr_reviewer.py +129 -0
  154. ref_agents/tools/validators/product_manager.py +291 -0
  155. ref_agents/tools/validators/qa_lead.py +172 -0
  156. ref_agents/tools/validators/scrum_master.py +212 -0
  157. ref_agents/tools/validators/security_owner.py +162 -0
  158. ref_agents/tools/validators/specifier.py +134 -0
  159. ref_agents/tools/validators/strategist.py +149 -0
  160. ref_agents/tools/validators/tester.py +121 -0
  161. ref_agents/tools/version_manager.py +202 -0
  162. ref_agents/tools/workflow_tools.py +1549 -0
  163. ref_agents/utils/__init__.py +21 -0
  164. ref_agents/utils/git_utils.py +351 -0
  165. ref_agents/utils/handoff_logger.py +368 -0
  166. ref_agents/utils/ignore_matcher.py +270 -0
  167. ref_agents/workflow/__init__.py +19 -0
  168. ref_agents/workflow/capabilities.py +328 -0
  169. ref_agents/workflow/state_machine.py +708 -0
  170. ref_agents/workflow/transitions.py +658 -0
  171. ref_agents-1.0.0.dist-info/METADATA +365 -0
  172. ref_agents-1.0.0.dist-info/RECORD +175 -0
  173. ref_agents-1.0.0.dist-info/WHEEL +4 -0
  174. ref_agents-1.0.0.dist-info/entry_points.txt +2 -0
  175. ref_agents-1.0.0.dist-info/licenses/LICENSE +115 -0
@@ -0,0 +1,93 @@
1
+ # CODE_MAP: `.`
2
+
3
+
4
+ ## Purpose
5
+ <!-- REF:MANUAL -->
6
+ [Describe the purpose of this module]
7
+
8
+
9
+
10
+ ## Directory Structure
11
+ <!-- REF:AUTO -->
12
+ | Item | Type | Purpose | Dependencies |
13
+ |------|------|---------|--------------|
14
+ | `browser/` | Dir | [Desc] | - |
15
+ | `codemap/` | Dir | [Desc] | - |
16
+ | `ref-reports/` | Dir | [Desc] | - |
17
+ | `invest_scorer.py` | File | [Desc] | - |
18
+ | `workflow_tools.py` | File | [Desc] | - |
19
+ | `test_plan_validator.py` | File | [Desc] | - |
20
+ | `compliance_remediation.py` | File | [Desc] | - |
21
+ | `jira_confluence_export.py` | File | [Desc] | - |
22
+ | `context_manager.py` | File | [Desc] | - |
23
+ | `agents_generator.py` | File | [Desc] | - |
24
+ | `requirements_serializer.py` | File | [Desc] | - |
25
+ | `debt_scanner.py` | File | [Desc] | - |
26
+ | `version_manager.py` | File | [Desc] | - |
27
+ | `report_utils.py` | File | [Desc] | - |
28
+ | `compliance.py` | File | [Desc] | - |
29
+ | `flow_mapper.py` | File | [Desc] | - |
30
+ | `ai_pattern_detector.py` | File | [Desc] | - |
31
+ | `dependency_graph.py` | File | [Desc] | - |
32
+ | `migration_readiness_scanner.py` | File | [Desc] | - |
33
+ | `complexity.py` | File | [Desc] | - |
34
+ | `health_scanner.py` | File | [Desc] | - |
35
+ | `summary_generator.py` | File | [Desc] | - |
36
+ | `external_detector.py` | File | [Desc] | - |
37
+ | `__init__.py` | File | [Desc] | - |
38
+ | `dead_code_scanner.py` | File | [Desc] | - |
39
+ | `codemap.py` | File | [Desc] | - |
40
+ | `tier1_fixer.py` | File | [Desc] | - |
41
+ | `brownfield_populator.py` | File | [Desc] | - |
42
+ | `pattern_learner.py` | File | [Desc] | - |
43
+ | `context_tools.py` | File | [Desc] | - |
44
+ | `context_graph.py` | File | [Desc] | - |
45
+ | `json_output.py` | File | [Desc] | - |
46
+ | `evaluate_gate.py` | File | [Desc] | - |
47
+ | `docs_scanner.py` | File | [Desc] | - |
48
+ | `guard_tools.py` | File | [Desc] | - |
49
+ | `gherkin_parser.py` | File | [Desc] | - |
50
+ | `sequencing_engine.py` | File | [Desc] | - |
51
+ | `symbol_resolver.py` | File | [Desc] | - |
52
+ | `test_smell_walker.py` | File | [Desc] | - |
53
+ | `code_quality_scanner.py` | File | [Desc] | - |
54
+ | `flow_gap_detector.py` | File | [Desc] | - |
55
+ | `features_generator.py` | File | [Desc] | - |
56
+ | `complexity_ast.py` | File | [Desc] | - |
57
+ | `codemap_freshness.py` | File | [Desc] | - |
58
+ | `discovery_audit.py` | File | [Desc] | - |
59
+ | `migration_mapper.py` | File | [Desc] | - |
60
+ | `handoff_tools.py` | File | [Desc] | - |
61
+ | `full_suite_runner.py` | File | [Desc] | - |
62
+ | `security_audit_tool.py` | File | [Desc] | - |
63
+ | `cross_repo_linker.py` | File | [Desc] | - |
64
+ | `hierarchy_manager.py` | File | [Desc] | - |
65
+
66
+
67
+ ## Key Classes / Functions
68
+ <!-- REF:MANUAL -->
69
+ | Name | File | Purpose | Dependencies |
70
+ |------|------|---------|--------------|
71
+ | ... | ... | ... | ... |
72
+
73
+
74
+
75
+ ## External Dependencies
76
+ <!-- REF:AUTO -->
77
+ *Auto-detected by external_detector.py*
78
+
79
+ ### Hardcoded External URLs
80
+
81
+ | Domain | File | Line | Notes |
82
+ |--------|------|------|-------|
83
+ | `cdn.jsdelivr.net` | `context_graph.py` | 713 | ⚠️ Consider env var |
84
+
85
+
86
+
87
+ ## Integration Boundaries
88
+ <!-- REF:MANUAL -->
89
+ *Where this module connects to external systems*
90
+
91
+ | Boundary Type | Local Code | External System | Data Flow | Risk Level |
92
+ |---------------|------------|-----------------|-----------|------------|
93
+ | API Call | [file.py] | [External API] | Outbound | Medium |
@@ -0,0 +1,30 @@
1
+ # CODE_MAP: Project Overview
2
+
3
+
4
+ ## Purpose
5
+ <!-- REF:MANUAL -->
6
+ [Describe the overall project purpose]
7
+
8
+
9
+
10
+ ## Package Index
11
+ <!-- REF:AUTO -->
12
+ | Package | Path | Purpose |
13
+ |---------|------|---------|
14
+ | [tools](./..md) | `.` | [Desc] |
15
+ | [browser](./browser.md) | `browser` | [Desc] |
16
+
17
+
18
+ ## Project Statistics
19
+ <!-- REF:AUTO -->
20
+ - **Total Packages:** 2
21
+ - **Generated:** Auto-updated by discovery
22
+
23
+
24
+ ## Quick Navigation
25
+ <!-- REF:MANUAL -->
26
+ *Add frequently accessed modules here*
27
+
28
+ | Module | Description |
29
+ |--------|-------------|
30
+ | ... | ... |
@@ -0,0 +1,44 @@
1
+ # CODE_MAP: `browser`
2
+
3
+
4
+ ## Purpose
5
+ <!-- REF:MANUAL -->
6
+ [Describe the purpose of this module]
7
+
8
+
9
+
10
+ ## Directory Structure
11
+ <!-- REF:AUTO -->
12
+ | Item | Type | Purpose | Dependencies |
13
+ |------|------|---------|--------------|
14
+ | `screenshot_utils.py` | File | [Desc] | - |
15
+ | `__init__.py` | File | [Desc] | - |
16
+ | `evidence_verifier.py` | File | [Desc] | - |
17
+ | `test_executor.py` | File | [Desc] | - |
18
+ | `execution_logger.py` | File | [Desc] | - |
19
+ | `playwright_mcp_client.py` | File | [Desc] | - |
20
+
21
+
22
+ ## Key Classes / Functions
23
+ <!-- REF:MANUAL -->
24
+ | Name | File | Purpose | Dependencies |
25
+ |------|------|---------|--------------|
26
+ | ... | ... | ... | ... |
27
+
28
+
29
+
30
+ ## External Dependencies
31
+ <!-- REF:AUTO -->
32
+ *Auto-detected by external_detector.py*
33
+
34
+ No external dependencies detected.
35
+
36
+
37
+
38
+ ## Integration Boundaries
39
+ <!-- REF:MANUAL -->
40
+ *Where this module connects to external systems*
41
+
42
+ | Boundary Type | Local Code | External System | Data Flow | Risk Level |
43
+ |---------------|------------|-----------------|-----------|------------|
44
+ | API Call | [file.py] | [External API] | Outbound | Medium |
@@ -0,0 +1,403 @@
1
+ """REF Code Map Generation Tool.
2
+
3
+ Generates centralized CODE_MAP.md files in codemap/ directory.
4
+ Supports merge strategy with REF:MANUAL/REF:AUTO section markers.
5
+ Finds Python packages by __init__.py presence.
6
+
7
+ Usage:
8
+ from ref_agents.tools.codemap import generate_codemaps
9
+ result = generate_codemaps("/path/to/project")
10
+ """
11
+
12
+ from pathlib import Path
13
+ from typing import NamedTuple
14
+
15
+ import structlog
16
+
17
+ from ref_agents.tools.external_detector import scan_directory
18
+
19
+ logger = structlog.get_logger(__name__)
20
+
21
+ # Directories to skip during package discovery
22
+ SKIP_DIRS = {
23
+ ".git",
24
+ ".venv",
25
+ "venv",
26
+ "__pycache__",
27
+ "node_modules",
28
+ ".mypy_cache",
29
+ ".pytest_cache",
30
+ ".ruff_cache",
31
+ "dist",
32
+ "build",
33
+ ".tox",
34
+ "htmlcov",
35
+ ".eggs",
36
+ "*.egg-info",
37
+ }
38
+
39
+
40
+ class Section(NamedTuple):
41
+ """Parsed markdown section."""
42
+
43
+ name: str
44
+ content: str
45
+ is_manual: bool # True if marked REF:MANUAL
46
+
47
+
48
+ def find_python_packages(root: Path) -> list[Path]:
49
+ """Find all Python packages (dirs with __init__.py).
50
+
51
+ Args:
52
+ root: Project root directory.
53
+
54
+ Returns:
55
+ List of package directories sorted by path.
56
+ """
57
+ packages: list[Path] = []
58
+
59
+ for path in root.rglob("__init__.py"):
60
+ pkg_dir = path.parent
61
+
62
+ # Skip if in excluded directory
63
+ skip = False
64
+ for part in pkg_dir.parts:
65
+ if part in SKIP_DIRS or part.endswith(".egg-info"):
66
+ skip = True
67
+ break
68
+ if skip:
69
+ continue
70
+
71
+ packages.append(pkg_dir)
72
+
73
+ # Sort by path depth then alphabetically
74
+ return sorted(packages, key=lambda p: (len(p.parts), str(p)))
75
+
76
+
77
+ def _parse_sections(content: str) -> dict[str, Section]:
78
+ """Parse markdown into sections by ## headers.
79
+
80
+ Args:
81
+ content: Markdown content.
82
+
83
+ Returns:
84
+ Dict mapping section name to Section.
85
+ """
86
+ sections: dict[str, Section] = {}
87
+ current_name = "_header"
88
+ current_lines: list[str] = []
89
+ is_manual = False
90
+
91
+ for line in content.splitlines():
92
+ if line.startswith("## "):
93
+ # Save previous section
94
+ if current_lines:
95
+ sections[current_name] = Section(
96
+ name=current_name,
97
+ content="\n".join(current_lines),
98
+ is_manual=is_manual,
99
+ )
100
+ current_name = line[3:].strip()
101
+ current_lines = [line]
102
+ is_manual = False
103
+ elif "<!-- REF:MANUAL -->" in line:
104
+ is_manual = True
105
+ current_lines.append(line)
106
+ else:
107
+ current_lines.append(line)
108
+
109
+ # Save last section
110
+ if current_lines:
111
+ sections[current_name] = Section(
112
+ name=current_name,
113
+ content="\n".join(current_lines),
114
+ is_manual=is_manual,
115
+ )
116
+
117
+ return sections
118
+
119
+
120
+ def _merge_sections(existing: str, new: str) -> str:
121
+ """Merge existing and new content, preserving manual sections.
122
+
123
+ Args:
124
+ existing: Existing file content.
125
+ new: Newly generated content.
126
+
127
+ Returns:
128
+ Merged content.
129
+ """
130
+ existing_sections = _parse_sections(existing)
131
+ new_sections = _parse_sections(new)
132
+
133
+ # Start with new content structure
134
+ merged_lines: list[str] = []
135
+
136
+ for section_name, new_section in new_sections.items():
137
+ if section_name in existing_sections:
138
+ existing_section = existing_sections[section_name]
139
+ if existing_section.is_manual:
140
+ # Preserve manual sections
141
+ merged_lines.append(existing_section.content)
142
+ else:
143
+ # Use new content for auto sections
144
+ merged_lines.append(new_section.content)
145
+ else:
146
+ merged_lines.append(new_section.content)
147
+
148
+ return "\n\n".join(merged_lines)
149
+
150
+
151
+ def _generate_external_deps_section(directory: Path) -> str:
152
+ """Generate External Dependencies section using auto-detection.
153
+
154
+ Args:
155
+ directory: Path to scan for external dependencies.
156
+
157
+ Returns:
158
+ Markdown formatted External Dependencies section.
159
+ """
160
+ result = scan_directory(directory)
161
+
162
+ output = "## External Dependencies\n"
163
+ output += "<!-- REF:AUTO -->\n"
164
+ output += "*Auto-detected by external_detector.py*\n\n"
165
+
166
+ if not result.dependencies:
167
+ output += "No external dependencies detected.\n\n"
168
+ return output
169
+
170
+ # Environment variables
171
+ if result.env_vars:
172
+ output += "### Environment Variables (External Endpoints)\n\n"
173
+ output += "| Variable | File | Line | Notes |\n"
174
+ output += "|----------|------|------|-------|\n"
175
+ for dep in result.env_vars:
176
+ filename = Path(dep.source_file).name
177
+ line = dep.line_number if dep.line_number else "-"
178
+ output += f"| `{dep.name}` | `{filename}` | {line} | {dep.description} |\n"
179
+ output += "\n"
180
+
181
+ # API clients
182
+ if result.api_clients:
183
+ output += "### External API Clients\n\n"
184
+ output += "| Library | Service | File | Line |\n"
185
+ output += "|---------|---------|------|------|\n"
186
+ for dep in result.api_clients:
187
+ filename = Path(dep.source_file).name
188
+ line = dep.line_number if dep.line_number else "-"
189
+ output += f"| `{dep.name}` | {dep.description} | `{filename}` | {line} |\n"
190
+ output += "\n"
191
+
192
+ # Hardcoded URLs
193
+ if result.urls:
194
+ output += "### Hardcoded External URLs\n\n"
195
+ output += "| Domain | File | Line | Notes |\n"
196
+ output += "|--------|------|------|-------|\n"
197
+ for dep in result.urls:
198
+ filename = Path(dep.source_file).name
199
+ line = dep.line_number if dep.line_number else "-"
200
+ output += f"| `{dep.name}` | `{filename}` | {line} | ⚠️ Consider env var |\n"
201
+ output += "\n"
202
+
203
+ logger.info(
204
+ "external_deps_detected",
205
+ env_vars=len(result.env_vars),
206
+ api_clients=len(result.api_clients),
207
+ urls=len(result.urls),
208
+ )
209
+
210
+ return output
211
+
212
+
213
+ def _generate_package_codemap(pkg_dir: Path, root: Path) -> str:
214
+ """Generate CODE_MAP content for a Python package.
215
+
216
+ Args:
217
+ pkg_dir: Package directory path.
218
+ root: Project root for relative path calculation.
219
+
220
+ Returns:
221
+ Markdown content for the package codemap.
222
+ """
223
+ rel_path = pkg_dir.relative_to(root)
224
+
225
+ files = [
226
+ f.name for f in pkg_dir.iterdir() if f.is_file() and not f.name.startswith(".")
227
+ ]
228
+ subdirs = [
229
+ d.name for d in pkg_dir.iterdir() if d.is_dir() and not d.name.startswith(".")
230
+ ]
231
+
232
+ template = f"""# CODE_MAP: `{rel_path}`
233
+
234
+ ## Purpose
235
+ <!-- REF:MANUAL -->
236
+ [Describe the purpose of this module]
237
+
238
+ ## Directory Structure
239
+ <!-- REF:AUTO -->
240
+ | Item | Type | Purpose | Dependencies |
241
+ |------|------|---------|--------------|
242
+ """
243
+ for sub in subdirs:
244
+ if sub in SKIP_DIRS:
245
+ continue
246
+ template += f"| `{sub}/` | Dir | [Desc] | - |\n"
247
+
248
+ for f in files:
249
+ template += f"| `{f}` | File | [Desc] | - |\n"
250
+
251
+ template += """
252
+ ## Key Classes / Functions
253
+ <!-- REF:MANUAL -->
254
+ | Name | File | Purpose | Dependencies |
255
+ |------|------|---------|--------------|
256
+ | ... | ... | ... | ... |
257
+
258
+ """
259
+
260
+ # Auto-detect external dependencies
261
+ template += _generate_external_deps_section(pkg_dir)
262
+
263
+ template += """
264
+ ## Integration Boundaries
265
+ <!-- REF:MANUAL -->
266
+ *Where this module connects to external systems*
267
+
268
+ | Boundary Type | Local Code | External System | Data Flow | Risk Level |
269
+ |---------------|------------|-----------------|-----------|------------|
270
+ | API Call | [file.py] | [External API] | Outbound | Medium |
271
+ """
272
+
273
+ return template
274
+
275
+
276
+ def _generate_meta_map(packages: list[Path], root: Path, codemap_dir: Path) -> str:
277
+ """Generate root CODE_MAP.md linking all package maps.
278
+
279
+ Args:
280
+ packages: List of package directories.
281
+ root: Project root.
282
+ codemap_dir: Path to codemap/ directory.
283
+
284
+ Returns:
285
+ Markdown content for meta-map.
286
+ """
287
+ template = """# CODE_MAP: Project Overview
288
+
289
+ ## Purpose
290
+ <!-- REF:MANUAL -->
291
+ [Describe the overall project purpose]
292
+
293
+ ## Package Index
294
+ <!-- REF:AUTO -->
295
+ | Package | Path | Purpose |
296
+ |---------|------|---------|
297
+ """
298
+ for pkg in packages:
299
+ rel_path = pkg.relative_to(root)
300
+ map_name = str(rel_path).replace("/", "_") + ".md"
301
+ template += f"| [{pkg.name}](./{map_name}) | `{rel_path}` | [Desc] |\n"
302
+
303
+ template += f"""
304
+ ## Project Statistics
305
+ <!-- REF:AUTO -->
306
+ - **Total Packages:** {len(packages)}
307
+ - **Generated:** Auto-updated by discovery
308
+
309
+ ## Quick Navigation
310
+ <!-- REF:MANUAL -->
311
+ *Add frequently accessed modules here*
312
+
313
+ | Module | Description |
314
+ |--------|-------------|
315
+ | ... | ... |
316
+ """
317
+
318
+ return template
319
+
320
+
321
+ def generate_codemaps(directory: str) -> str:
322
+ """Generate centralized CODE_MAPs for all Python packages.
323
+
324
+ Creates codemap/ directory at project root with:
325
+ - CODE_MAP.md (meta-map linking all packages)
326
+ - <package>_CODE_MAP.md for each Python package
327
+
328
+ Merges with existing files, preserving REF:MANUAL sections.
329
+
330
+ Args:
331
+ directory: Path to project root.
332
+
333
+ Returns:
334
+ Status message with summary.
335
+ """
336
+ root = Path(directory)
337
+ if not root.exists():
338
+ return f"Error: Directory {directory} does not exist."
339
+
340
+ # Create codemap directory
341
+ codemap_dir = root / "codemap"
342
+ codemap_dir.mkdir(exist_ok=True)
343
+
344
+ packages = find_python_packages(root)
345
+
346
+ if not packages:
347
+ return (
348
+ f"No Python packages found in {directory}. Ensure __init__.py files exist."
349
+ )
350
+
351
+ generated = 0
352
+ updated = 0
353
+
354
+ # Generate per-package maps
355
+ for pkg in packages:
356
+ rel_path = pkg.relative_to(root)
357
+ map_name = str(rel_path).replace("/", "_") + ".md"
358
+ map_path = codemap_dir / map_name
359
+
360
+ new_content = _generate_package_codemap(pkg, root)
361
+
362
+ if map_path.exists():
363
+ existing_content = map_path.read_text(encoding="utf-8")
364
+ merged = _merge_sections(existing_content, new_content)
365
+ map_path.write_text(merged, encoding="utf-8")
366
+ updated += 1
367
+ logger.info("codemap_updated", package=str(rel_path), path=str(map_path))
368
+ else:
369
+ map_path.write_text(new_content, encoding="utf-8")
370
+ generated += 1
371
+ logger.info("codemap_generated", package=str(rel_path), path=str(map_path))
372
+
373
+ # Generate meta-map
374
+ meta_path = codemap_dir / "CODE_MAP.md"
375
+ meta_content = _generate_meta_map(packages, root, codemap_dir)
376
+
377
+ if meta_path.exists():
378
+ existing_meta = meta_path.read_text(encoding="utf-8")
379
+ merged_meta = _merge_sections(existing_meta, meta_content)
380
+ meta_path.write_text(merged_meta, encoding="utf-8")
381
+ else:
382
+ meta_path.write_text(meta_content, encoding="utf-8")
383
+
384
+ return (
385
+ f"✅ CODE_MAPs generated in `{codemap_dir}`\n\n"
386
+ f"**Packages:** {len(packages)}\n"
387
+ f"**Generated:** {generated}\n"
388
+ f"**Updated:** {updated}\n\n"
389
+ f"Meta-map: `{meta_path}`"
390
+ )
391
+
392
+
393
+ # Legacy function for backward compatibility
394
+ def generate_codemap_tool(directory: str) -> str:
395
+ """Legacy wrapper - redirects to centralized codemap generation.
396
+
397
+ Args:
398
+ directory: Path to directory to scan.
399
+
400
+ Returns:
401
+ Status message with codemap paths.
402
+ """
403
+ return generate_codemaps(directory)