soloforge 1.2.8 → 1.2.10

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 (405) hide show
  1. package/README.md +105 -321
  2. package/dist/adapters/claude_code/claude_md.d.ts +5 -0
  3. package/dist/adapters/claude_code/claude_md.d.ts.map +1 -1
  4. package/dist/adapters/claude_code/claude_md.js +6 -0
  5. package/dist/adapters/claude_code/claude_md.js.map +1 -1
  6. package/dist/adapters/claude_code/hooks.d.ts +4 -0
  7. package/dist/adapters/claude_code/hooks.d.ts.map +1 -1
  8. package/dist/adapters/claude_code/hooks.js +5 -0
  9. package/dist/adapters/claude_code/hooks.js.map +1 -1
  10. package/dist/adapters/claude_code/server.d.ts.map +1 -1
  11. package/dist/adapters/claude_code/server.js +9 -21
  12. package/dist/adapters/claude_code/server.js.map +1 -1
  13. package/dist/adapters/claude_code/tools.d.ts +5 -0
  14. package/dist/adapters/claude_code/tools.d.ts.map +1 -1
  15. package/dist/adapters/claude_code/tools.js +619 -205
  16. package/dist/adapters/claude_code/tools.js.map +1 -1
  17. package/dist/adapters/codex/codex_config.d.ts +9 -0
  18. package/dist/adapters/codex/codex_config.d.ts.map +1 -1
  19. package/dist/adapters/codex/codex_config.js +11 -3
  20. package/dist/adapters/codex/codex_config.js.map +1 -1
  21. package/dist/adapters/codex/codex_rules.d.ts +5 -0
  22. package/dist/adapters/codex/codex_rules.d.ts.map +1 -1
  23. package/dist/adapters/codex/codex_rules.js +8 -1
  24. package/dist/adapters/codex/codex_rules.js.map +1 -1
  25. package/dist/adapters/shared/workflow_template.d.ts +5 -0
  26. package/dist/adapters/shared/workflow_template.d.ts.map +1 -1
  27. package/dist/adapters/shared/workflow_template.js +32 -79
  28. package/dist/adapters/shared/workflow_template.js.map +1 -1
  29. package/dist/adapters/trae/trae_config.d.ts +4 -0
  30. package/dist/adapters/trae/trae_config.d.ts.map +1 -1
  31. package/dist/adapters/trae/trae_config.js +5 -7
  32. package/dist/adapters/trae/trae_config.js.map +1 -1
  33. package/dist/adapters/trae/trae_rules.d.ts +5 -0
  34. package/dist/adapters/trae/trae_rules.d.ts.map +1 -1
  35. package/dist/adapters/trae/trae_rules.js +7 -1
  36. package/dist/adapters/trae/trae_rules.js.map +1 -1
  37. package/dist/bin/config_commands.d.ts +33 -0
  38. package/dist/bin/config_commands.d.ts.map +1 -0
  39. package/dist/bin/config_commands.js +222 -0
  40. package/dist/bin/config_commands.js.map +1 -0
  41. package/dist/bin/soloforge.js +609 -119
  42. package/dist/bin/soloforge.js.map +1 -1
  43. package/dist/engine/artifact_contract_registry.d.ts +138 -0
  44. package/dist/engine/artifact_contract_registry.d.ts.map +1 -0
  45. package/dist/engine/artifact_contract_registry.js +427 -0
  46. package/dist/engine/artifact_contract_registry.js.map +1 -0
  47. package/dist/engine/audit_pool.d.ts +40 -0
  48. package/dist/engine/audit_pool.d.ts.map +1 -1
  49. package/dist/engine/audit_pool.js +37 -1
  50. package/dist/engine/audit_pool.js.map +1 -1
  51. package/dist/engine/audit_sampler.d.ts +5 -0
  52. package/dist/engine/audit_sampler.d.ts.map +1 -1
  53. package/dist/engine/audit_sampler.js +6 -0
  54. package/dist/engine/audit_sampler.js.map +1 -1
  55. package/dist/engine/audit_verifier.d.ts.map +1 -1
  56. package/dist/engine/audit_verifier.js +5 -1
  57. package/dist/engine/audit_verifier.js.map +1 -1
  58. package/dist/engine/batch1_manifest.d.ts +61 -0
  59. package/dist/engine/batch1_manifest.d.ts.map +1 -0
  60. package/dist/engine/batch1_manifest.js +220 -0
  61. package/dist/engine/batch1_manifest.js.map +1 -0
  62. package/dist/engine/batch1_reality_gate.d.ts +40 -0
  63. package/dist/engine/batch1_reality_gate.d.ts.map +1 -0
  64. package/dist/engine/batch1_reality_gate.js +290 -0
  65. package/dist/engine/batch1_reality_gate.js.map +1 -0
  66. package/dist/engine/batch1_scenario_registry.d.ts +62 -0
  67. package/dist/engine/batch1_scenario_registry.d.ts.map +1 -0
  68. package/dist/engine/batch1_scenario_registry.js +392 -0
  69. package/dist/engine/batch1_scenario_registry.js.map +1 -0
  70. package/dist/engine/batch1_scenario_runners.d.ts +42 -0
  71. package/dist/engine/batch1_scenario_runners.d.ts.map +1 -0
  72. package/dist/engine/batch1_scenario_runners.js +292 -0
  73. package/dist/engine/batch1_scenario_runners.js.map +1 -0
  74. package/dist/engine/capability_action_advisor.d.ts +3 -0
  75. package/dist/engine/capability_action_advisor.d.ts.map +1 -1
  76. package/dist/engine/capability_action_advisor.js +10 -0
  77. package/dist/engine/capability_action_advisor.js.map +1 -1
  78. package/dist/engine/capability_registry.d.ts +21 -0
  79. package/dist/engine/capability_registry.d.ts.map +1 -1
  80. package/dist/engine/capability_registry.js +113 -0
  81. package/dist/engine/capability_registry.js.map +1 -1
  82. package/dist/engine/capability_state_store.d.ts +63 -0
  83. package/dist/engine/capability_state_store.d.ts.map +1 -1
  84. package/dist/engine/capability_state_store.js +49 -1
  85. package/dist/engine/capability_state_store.js.map +1 -1
  86. package/dist/engine/change_coordinator.d.ts.map +1 -1
  87. package/dist/engine/change_coordinator.js +5 -4
  88. package/dist/engine/change_coordinator.js.map +1 -1
  89. package/dist/engine/classifier.d.ts +15 -5
  90. package/dist/engine/classifier.d.ts.map +1 -1
  91. package/dist/engine/classifier.js +70 -69
  92. package/dist/engine/classifier.js.map +1 -1
  93. package/dist/engine/code_reviewer.d.ts +14 -0
  94. package/dist/engine/code_reviewer.d.ts.map +1 -1
  95. package/dist/engine/code_reviewer.js +109 -10
  96. package/dist/engine/code_reviewer.js.map +1 -1
  97. package/dist/engine/cognitive_anchor.d.ts +14 -0
  98. package/dist/engine/cognitive_anchor.d.ts.map +1 -1
  99. package/dist/engine/cognitive_anchor.js +26 -2
  100. package/dist/engine/cognitive_anchor.js.map +1 -1
  101. package/dist/engine/command_execution_contract.d.ts +226 -0
  102. package/dist/engine/command_execution_contract.d.ts.map +1 -0
  103. package/dist/engine/command_execution_contract.js +571 -0
  104. package/dist/engine/command_execution_contract.js.map +1 -0
  105. package/dist/engine/confidence_scorer.d.ts.map +1 -1
  106. package/dist/engine/confidence_scorer.js +1 -0
  107. package/dist/engine/confidence_scorer.js.map +1 -1
  108. package/dist/engine/config_precedence_contract.d.ts +269 -0
  109. package/dist/engine/config_precedence_contract.d.ts.map +1 -0
  110. package/dist/engine/config_precedence_contract.js +948 -0
  111. package/dist/engine/config_precedence_contract.js.map +1 -0
  112. package/dist/engine/conflict_gate.d.ts +13 -0
  113. package/dist/engine/conflict_gate.d.ts.map +1 -1
  114. package/dist/engine/conflict_gate.js +20 -2
  115. package/dist/engine/conflict_gate.js.map +1 -1
  116. package/dist/engine/consumable_asset_registry.d.ts +46 -0
  117. package/dist/engine/consumable_asset_registry.d.ts.map +1 -0
  118. package/dist/engine/consumable_asset_registry.js +758 -0
  119. package/dist/engine/consumable_asset_registry.js.map +1 -0
  120. package/dist/engine/contract_guard.d.ts +4 -0
  121. package/dist/engine/contract_guard.d.ts.map +1 -1
  122. package/dist/engine/contract_guard.js +15 -7
  123. package/dist/engine/contract_guard.js.map +1 -1
  124. package/dist/engine/convention_detector.d.ts.map +1 -1
  125. package/dist/engine/convention_detector.js +5 -2
  126. package/dist/engine/convention_detector.js.map +1 -1
  127. package/dist/engine/core_engineering_principles.d.ts +155 -0
  128. package/dist/engine/core_engineering_principles.d.ts.map +1 -0
  129. package/dist/engine/core_engineering_principles.js +426 -0
  130. package/dist/engine/core_engineering_principles.js.map +1 -0
  131. package/dist/engine/debt_reporter.d.ts.map +1 -1
  132. package/dist/engine/debt_reporter.js +3 -1
  133. package/dist/engine/debt_reporter.js.map +1 -1
  134. package/dist/engine/debt_tracker.d.ts.map +1 -1
  135. package/dist/engine/debt_tracker.js +9 -3
  136. package/dist/engine/debt_tracker.js.map +1 -1
  137. package/dist/engine/debugger.d.ts.map +1 -1
  138. package/dist/engine/debugger.js +2 -0
  139. package/dist/engine/debugger.js.map +1 -1
  140. package/dist/engine/decision_contract.d.ts +11 -2
  141. package/dist/engine/decision_contract.d.ts.map +1 -1
  142. package/dist/engine/decision_contract.js +17 -2
  143. package/dist/engine/decision_contract.js.map +1 -1
  144. package/dist/engine/delivery.d.ts +7 -0
  145. package/dist/engine/delivery.d.ts.map +1 -1
  146. package/dist/engine/delivery.js +89 -36
  147. package/dist/engine/delivery.js.map +1 -1
  148. package/dist/engine/dependency_scanner.d.ts.map +1 -1
  149. package/dist/engine/dependency_scanner.js +14 -9
  150. package/dist/engine/dependency_scanner.js.map +1 -1
  151. package/dist/engine/developer_sovereignty.d.ts.map +1 -1
  152. package/dist/engine/developer_sovereignty.js +8 -2
  153. package/dist/engine/developer_sovereignty.js.map +1 -1
  154. package/dist/engine/diff_ownership.d.ts.map +1 -1
  155. package/dist/engine/diff_ownership.js +8 -0
  156. package/dist/engine/diff_ownership.js.map +1 -1
  157. package/dist/engine/diff_ownership_store.d.ts +26 -10
  158. package/dist/engine/diff_ownership_store.d.ts.map +1 -1
  159. package/dist/engine/diff_ownership_store.js +47 -20
  160. package/dist/engine/diff_ownership_store.js.map +1 -1
  161. package/dist/engine/dual_layer_mechanism_registry.d.ts +66 -0
  162. package/dist/engine/dual_layer_mechanism_registry.d.ts.map +1 -0
  163. package/dist/engine/dual_layer_mechanism_registry.js +1077 -0
  164. package/dist/engine/dual_layer_mechanism_registry.js.map +1 -0
  165. package/dist/engine/escape_report.d.ts +50 -0
  166. package/dist/engine/escape_report.d.ts.map +1 -1
  167. package/dist/engine/escape_report.js +38 -0
  168. package/dist/engine/escape_report.js.map +1 -1
  169. package/dist/engine/evolver.d.ts.map +1 -1
  170. package/dist/engine/evolver.js +12 -2
  171. package/dist/engine/evolver.js.map +1 -1
  172. package/dist/engine/exploration.d.ts.map +1 -1
  173. package/dist/engine/exploration.js +87 -0
  174. package/dist/engine/exploration.js.map +1 -1
  175. package/dist/engine/failure_classifier.d.ts.map +1 -1
  176. package/dist/engine/failure_classifier.js +8 -0
  177. package/dist/engine/failure_classifier.js.map +1 -1
  178. package/dist/engine/feasibility_checker.d.ts +8 -0
  179. package/dist/engine/feasibility_checker.d.ts.map +1 -1
  180. package/dist/engine/feasibility_checker.js +12 -0
  181. package/dist/engine/feasibility_checker.js.map +1 -1
  182. package/dist/engine/git_deps.d.ts +4 -1
  183. package/dist/engine/git_deps.d.ts.map +1 -1
  184. package/dist/engine/git_deps.js +5 -1
  185. package/dist/engine/git_deps.js.map +1 -1
  186. package/dist/engine/governance_report.d.ts +57 -1
  187. package/dist/engine/governance_report.d.ts.map +1 -1
  188. package/dist/engine/governance_report.js +91 -1
  189. package/dist/engine/governance_report.js.map +1 -1
  190. package/dist/engine/impact_analyzer.d.ts.map +1 -1
  191. package/dist/engine/impact_analyzer.js +5 -1
  192. package/dist/engine/impact_analyzer.js.map +1 -1
  193. package/dist/engine/implementation_roadmap_registry.d.ts +105 -0
  194. package/dist/engine/implementation_roadmap_registry.d.ts.map +1 -0
  195. package/dist/engine/implementation_roadmap_registry.js +813 -0
  196. package/dist/engine/implementation_roadmap_registry.js.map +1 -0
  197. package/dist/engine/input_material_contract_registry.d.ts +185 -0
  198. package/dist/engine/input_material_contract_registry.d.ts.map +1 -0
  199. package/dist/engine/input_material_contract_registry.js +563 -0
  200. package/dist/engine/input_material_contract_registry.js.map +1 -0
  201. package/dist/engine/intent_expander.d.ts +8 -27
  202. package/dist/engine/intent_expander.d.ts.map +1 -1
  203. package/dist/engine/intent_expander.js +1170 -139
  204. package/dist/engine/intent_expander.js.map +1 -1
  205. package/dist/engine/intent_router.d.ts +82 -0
  206. package/dist/engine/intent_router.d.ts.map +1 -0
  207. package/dist/engine/intent_router.js +458 -0
  208. package/dist/engine/intent_router.js.map +1 -0
  209. package/dist/engine/io_controller.d.ts.map +1 -1
  210. package/dist/engine/io_controller.js +25 -13
  211. package/dist/engine/io_controller.js.map +1 -1
  212. package/dist/engine/java_quality_guard.d.ts.map +1 -1
  213. package/dist/engine/java_quality_guard.js +8 -4
  214. package/dist/engine/java_quality_guard.js.map +1 -1
  215. package/dist/engine/job_manager.d.ts +35 -0
  216. package/dist/engine/job_manager.d.ts.map +1 -1
  217. package/dist/engine/job_manager.js +53 -9
  218. package/dist/engine/job_manager.js.map +1 -1
  219. package/dist/engine/knowledge_config_loader.d.ts +12 -1
  220. package/dist/engine/knowledge_config_loader.d.ts.map +1 -1
  221. package/dist/engine/knowledge_config_loader.js +50 -10
  222. package/dist/engine/knowledge_config_loader.js.map +1 -1
  223. package/dist/engine/knowledge_injection_boundary.d.ts +56 -0
  224. package/dist/engine/knowledge_injection_boundary.d.ts.map +1 -0
  225. package/dist/engine/knowledge_injection_boundary.js +561 -0
  226. package/dist/engine/knowledge_injection_boundary.js.map +1 -0
  227. package/dist/engine/knowledge_manager.d.ts +73 -0
  228. package/dist/engine/knowledge_manager.d.ts.map +1 -1
  229. package/dist/engine/knowledge_manager.js +163 -21
  230. package/dist/engine/knowledge_manager.js.map +1 -1
  231. package/dist/engine/knowledge_sovereignty.d.ts +1 -0
  232. package/dist/engine/knowledge_sovereignty.d.ts.map +1 -1
  233. package/dist/engine/knowledge_sovereignty.js +8 -3
  234. package/dist/engine/knowledge_sovereignty.js.map +1 -1
  235. package/dist/engine/llm_gateway.d.ts +74 -3
  236. package/dist/engine/llm_gateway.d.ts.map +1 -1
  237. package/dist/engine/llm_gateway.js +75 -4
  238. package/dist/engine/llm_gateway.js.map +1 -1
  239. package/dist/engine/main_path_integration_contract.d.ts +383 -0
  240. package/dist/engine/main_path_integration_contract.d.ts.map +1 -0
  241. package/dist/engine/main_path_integration_contract.js +1581 -0
  242. package/dist/engine/main_path_integration_contract.js.map +1 -0
  243. package/dist/engine/mechanism_contract_registry.d.ts +59 -0
  244. package/dist/engine/mechanism_contract_registry.d.ts.map +1 -0
  245. package/dist/engine/mechanism_contract_registry.js +484 -0
  246. package/dist/engine/mechanism_contract_registry.js.map +1 -0
  247. package/dist/engine/migration_guard.d.ts.map +1 -1
  248. package/dist/engine/migration_guard.js +24 -15
  249. package/dist/engine/migration_guard.js.map +1 -1
  250. package/dist/engine/mutation_audit.d.ts +10 -0
  251. package/dist/engine/mutation_audit.d.ts.map +1 -1
  252. package/dist/engine/mutation_audit.js +19 -2
  253. package/dist/engine/mutation_audit.js.map +1 -1
  254. package/dist/engine/observability.d.ts.map +1 -1
  255. package/dist/engine/observability.js +17 -6
  256. package/dist/engine/observability.js.map +1 -1
  257. package/dist/engine/onboarding.d.ts.map +1 -1
  258. package/dist/engine/onboarding.js +20 -4
  259. package/dist/engine/onboarding.js.map +1 -1
  260. package/dist/engine/policy_drift_detector.d.ts +6 -0
  261. package/dist/engine/policy_drift_detector.d.ts.map +1 -1
  262. package/dist/engine/policy_drift_detector.js +16 -0
  263. package/dist/engine/policy_drift_detector.js.map +1 -1
  264. package/dist/engine/privacy_secret_contract.d.ts +320 -0
  265. package/dist/engine/privacy_secret_contract.d.ts.map +1 -0
  266. package/dist/engine/privacy_secret_contract.js +874 -0
  267. package/dist/engine/privacy_secret_contract.js.map +1 -0
  268. package/dist/engine/regression_matrix.d.ts +21 -8
  269. package/dist/engine/regression_matrix.d.ts.map +1 -1
  270. package/dist/engine/regression_matrix.js +37 -8
  271. package/dist/engine/regression_matrix.js.map +1 -1
  272. package/dist/engine/risk_sampler.d.ts +6 -0
  273. package/dist/engine/risk_sampler.d.ts.map +1 -1
  274. package/dist/engine/risk_sampler.js +9 -0
  275. package/dist/engine/risk_sampler.js.map +1 -1
  276. package/dist/engine/runtime_safety.d.ts.map +1 -1
  277. package/dist/engine/runtime_safety.js +7 -3
  278. package/dist/engine/runtime_safety.js.map +1 -1
  279. package/dist/engine/scaffolder.d.ts.map +1 -1
  280. package/dist/engine/scaffolder.js +7 -1
  281. package/dist/engine/scaffolder.js.map +1 -1
  282. package/dist/engine/scope_controller.d.ts.map +1 -1
  283. package/dist/engine/scope_controller.js +12 -1
  284. package/dist/engine/scope_controller.js.map +1 -1
  285. package/dist/engine/scope_lease.d.ts +43 -0
  286. package/dist/engine/scope_lease.d.ts.map +1 -1
  287. package/dist/engine/scope_lease.js +44 -0
  288. package/dist/engine/scope_lease.js.map +1 -1
  289. package/dist/engine/semantic_evidence.d.ts +6 -0
  290. package/dist/engine/semantic_evidence.d.ts.map +1 -1
  291. package/dist/engine/semantic_evidence.js +9 -0
  292. package/dist/engine/semantic_evidence.js.map +1 -1
  293. package/dist/engine/task_context.d.ts +36 -1
  294. package/dist/engine/task_context.d.ts.map +1 -1
  295. package/dist/engine/task_context.js +252 -13
  296. package/dist/engine/task_context.js.map +1 -1
  297. package/dist/engine/task_planner.d.ts.map +1 -1
  298. package/dist/engine/task_planner.js +13 -3
  299. package/dist/engine/task_planner.js.map +1 -1
  300. package/dist/engine/team_awareness.d.ts.map +1 -1
  301. package/dist/engine/team_awareness.js +8 -7
  302. package/dist/engine/team_awareness.js.map +1 -1
  303. package/dist/engine/template_mechanism_auditor.d.ts +93 -0
  304. package/dist/engine/template_mechanism_auditor.d.ts.map +1 -0
  305. package/dist/engine/template_mechanism_auditor.js +622 -0
  306. package/dist/engine/template_mechanism_auditor.js.map +1 -0
  307. package/dist/engine/test_generator.d.ts.map +1 -1
  308. package/dist/engine/test_generator.js +6 -0
  309. package/dist/engine/test_generator.js.map +1 -1
  310. package/dist/engine/test_quality.d.ts +6 -0
  311. package/dist/engine/test_quality.d.ts.map +1 -1
  312. package/dist/engine/test_quality.js +26 -10
  313. package/dist/engine/test_quality.js.map +1 -1
  314. package/dist/engine/tool_invocation_contract_registry.d.ts +136 -0
  315. package/dist/engine/tool_invocation_contract_registry.d.ts.map +1 -0
  316. package/dist/engine/tool_invocation_contract_registry.js +731 -0
  317. package/dist/engine/tool_invocation_contract_registry.js.map +1 -0
  318. package/dist/engine/traceability.d.ts +3 -0
  319. package/dist/engine/traceability.d.ts.map +1 -1
  320. package/dist/engine/traceability.js +12 -4
  321. package/dist/engine/traceability.js.map +1 -1
  322. package/dist/engine/user_feedback_contract.d.ts +162 -0
  323. package/dist/engine/user_feedback_contract.d.ts.map +1 -0
  324. package/dist/engine/user_feedback_contract.js +356 -0
  325. package/dist/engine/user_feedback_contract.js.map +1 -0
  326. package/dist/engine/verifier.d.ts +6 -1
  327. package/dist/engine/verifier.d.ts.map +1 -1
  328. package/dist/engine/verifier.js +114 -1
  329. package/dist/engine/verifier.js.map +1 -1
  330. package/dist/engine/workflow_contract_registry.d.ts +70 -0
  331. package/dist/engine/workflow_contract_registry.d.ts.map +1 -0
  332. package/dist/engine/workflow_contract_registry.js +501 -0
  333. package/dist/engine/workflow_contract_registry.js.map +1 -0
  334. package/dist/engine/workspace_resumer.d.ts.map +1 -1
  335. package/dist/engine/workspace_resumer.js +8 -0
  336. package/dist/engine/workspace_resumer.js.map +1 -1
  337. package/dist/engine/zero_config_init.d.ts +67 -2
  338. package/dist/engine/zero_config_init.d.ts.map +1 -1
  339. package/dist/engine/zero_config_init.js +410 -28
  340. package/dist/engine/zero_config_init.js.map +1 -1
  341. package/dist/git/operations.d.ts +101 -0
  342. package/dist/git/operations.d.ts.map +1 -1
  343. package/dist/git/operations.js +125 -9
  344. package/dist/git/operations.js.map +1 -1
  345. package/dist/index.d.ts +1 -1
  346. package/dist/index.js +16 -5
  347. package/dist/index.js.map +1 -1
  348. package/dist/knowledge/conflict_detector.d.ts +6 -0
  349. package/dist/knowledge/conflict_detector.d.ts.map +1 -1
  350. package/dist/knowledge/conflict_detector.js +7 -0
  351. package/dist/knowledge/conflict_detector.js.map +1 -1
  352. package/dist/knowledge/health_checker.d.ts +16 -0
  353. package/dist/knowledge/health_checker.d.ts.map +1 -1
  354. package/dist/knowledge/health_checker.js +24 -1
  355. package/dist/knowledge/health_checker.js.map +1 -1
  356. package/dist/knowledge/index_manager.d.ts +140 -2
  357. package/dist/knowledge/index_manager.d.ts.map +1 -1
  358. package/dist/knowledge/index_manager.js +186 -26
  359. package/dist/knowledge/index_manager.js.map +1 -1
  360. package/dist/knowledge/loader.d.ts +8 -1
  361. package/dist/knowledge/loader.d.ts.map +1 -1
  362. package/dist/knowledge/loader.js +56 -2
  363. package/dist/knowledge/loader.js.map +1 -1
  364. package/dist/knowledge/writer.d.ts +49 -1
  365. package/dist/knowledge/writer.d.ts.map +1 -1
  366. package/dist/knowledge/writer.js +55 -1
  367. package/dist/knowledge/writer.js.map +1 -1
  368. package/dist/types.d.ts +255 -1
  369. package/dist/types.d.ts.map +1 -1
  370. package/dist/utils/logger.d.ts +3 -0
  371. package/dist/utils/logger.d.ts.map +1 -0
  372. package/dist/utils/logger.js +29 -0
  373. package/dist/utils/logger.js.map +1 -0
  374. package/package.json +7 -7
  375. package/templates/knowledge/checklists//344/270/273/351/223/276/350/267/257/346/216/245/345/205/245/351/252/214/346/224/266/346/270/205/345/215/225.md +16 -0
  376. package/templates/knowledge/checklists//345/267/245/344/275/234/346/265/201/351/252/214/346/224/266/346/270/205/345/215/225.md +17 -0
  377. package/templates/knowledge/checklists//346/240/270/345/277/203/345/267/245/347/250/213/346/211/247/350/241/214/351/252/214/346/224/266/346/270/205/345/215/225.md +43 -0
  378. package/templates/knowledge/checklists//347/237/245/350/257/206/346/263/250/345/205/245/351/252/214/346/224/266/346/270/205/345/215/225.md +17 -0
  379. package/templates/knowledge/checklists//351/232/220/347/247/201/345/256/241/346/237/245/346/270/205/345/215/225.md +15 -0
  380. package/templates/knowledge/checklists//351/252/214/350/257/201/351/252/214/346/224/266/346/270/205/345/215/225.md +16 -0
  381. package/templates/knowledge/patterns/core//345/206/263/347/255/226/347/275/221/345/205/263.md +1 -0
  382. package/templates/knowledge/procedures//344/270/273/351/223/276/350/267/257/346/216/245/345/205/245/351/252/214/350/257/201/346/265/201/347/250/213.md +23 -0
  383. package/templates/knowledge/procedures//345/221/275/344/273/244/346/211/247/350/241/214/346/265/201/347/250/213.md +19 -0
  384. package/templates/knowledge/procedures//345/267/245/345/205/267/350/260/203/347/224/250/346/265/201/347/250/213.md +15 -0
  385. package/templates/knowledge/procedures//346/204/217/345/233/276/350/267/257/347/224/261/346/265/201/347/250/213.md +15 -0
  386. package/templates/knowledge/procedures//346/272/220/347/240/201/345/216/237/345/236/213/344/272/244/344/273/230/346/265/201/347/250/213.md +1 -1
  387. package/templates/knowledge/procedures//347/274/226/347/240/201/345/211/215/346/276/204/346/270/205/346/265/201/347/250/213.md +53 -0
  388. package/templates/knowledge/rules//344/272/247/347/211/251/345/245/221/347/272/246/350/247/204/345/210/231.md +21 -0
  389. package/templates/knowledge/rules//345/221/275/344/273/244/346/211/247/350/241/214/350/247/204/345/210/231.md +25 -0
  390. package/templates/knowledge/rules//345/267/245/344/275/234/346/265/201/345/245/221/347/272/246/350/247/204/345/210/231.md +20 -0
  391. package/templates/knowledge/rules//345/267/245/345/205/267/350/260/203/347/224/250/350/247/204/345/210/231.md +25 -0
  392. package/templates/knowledge/rules//346/204/217/345/233/276/350/267/257/347/224/261/350/247/204/345/210/231.md +26 -0
  393. package/templates/knowledge/rules//346/211/247/350/241/214/345/256/210/345/215/253/350/257/204/344/274/260/350/247/204/345/210/231.md +24 -0
  394. package/templates/knowledge/rules//346/225/217/346/204/237/344/277/241/346/201/257/345/244/204/347/220/206/350/247/204/345/210/231.md +20 -0
  395. package/templates/knowledge/rules//346/240/270/345/277/203/345/267/245/347/250/213/346/211/247/350/241/214/345/216/237/345/210/231.md +125 -0
  396. package/templates/knowledge/rules//346/263/250/345/206/214/350/241/250/345/237/272/347/241/200/350/256/276/346/226/275/350/247/204/345/210/231.md +26 -0
  397. package/templates/knowledge/rules//347/224/250/346/210/267/345/217/215/351/246/210/345/245/221/347/272/246/350/247/204/345/210/231.md +22 -0
  398. package/templates/knowledge/rules//347/237/245/350/257/206/346/263/250/345/205/245/350/276/271/347/225/214/350/247/204/345/210/231.md +25 -0
  399. package/templates/knowledge/rules//350/276/223/345/205/245/346/235/220/346/226/231/345/245/221/347/272/246/350/247/204/345/210/231.md +27 -0
  400. package/templates/knowledge/rules//351/205/215/347/275/256/344/274/230/345/205/210/347/272/247/350/247/204/345/210/231.md +22 -0
  401. package/templates/knowledge/rules//351/230/262/345/255/244/345/262/233/345/256/236/347/216/260/350/247/204/345/210/231.md +24 -0
  402. package/templates/knowledge/rules//351/233/266/351/205/215/347/275/256/345/210/235/345/247/213/345/214/226/350/247/204/345/210/231.md +28 -0
  403. package/templates/knowledge/rules//351/252/214/350/257/201/345/245/221/347/272/246/350/247/204/345/210/231.md +25 -0
  404. package/templates/knowledge/templates/{review_summary.md → /345/256/241/346/237/245/346/221/230/350/246/201.md} +1 -1
  405. package/templates/config.yaml +0 -53
@@ -0,0 +1,1581 @@
1
+ /**
2
+ * Main Path Integration Contract
3
+ *
4
+ * 新增能力主链路接入防孤岛机制。
5
+ * 任何新增生产代码不能只证明"文件存在、单测通过",必须证明它已经进入
6
+ * 真实主链路,并能被用户入口触发、被生产代码调用、留下可观测证据、通过集成验证。
7
+ *
8
+ * 核心完成定义:
9
+ * Done = implemented + wired + reachable + observable + verified
10
+ */
11
+ // ── 常量定义 ──
12
+ /** 不被承认为"接入"的引用类型 */
13
+ const NON_INTEGRATION_REFERENCES = [
14
+ "test_import",
15
+ "index_export",
16
+ "registry_declaration",
17
+ "type_reference",
18
+ "barrel_export",
19
+ "readme",
20
+ "design_doc",
21
+ "demo",
22
+ "example",
23
+ ];
24
+ export { NON_INTEGRATION_REFERENCES };
25
+ /** 允许豁免的文件模式 */
26
+ const EXEMPT_PATTERNS = [
27
+ { pattern: /\.d\.ts$/, reason: "类型声明文件" },
28
+ { pattern: /\/types\//, reason: "类型目录" },
29
+ { pattern: /\.test\./, reason: "测试文件不应在 src" },
30
+ { pattern: /\.spec\./, reason: "测试文件不应在 src" },
31
+ { pattern: /\/fixtures?\//, reason: "测试 fixture" },
32
+ ];
33
+ export { EXEMPT_PATTERNS };
34
+ /** SoloForge 机制层特殊规则: 能力类型 → 必须接入的目标 */
35
+ const SOLOFORGE_WIRING_RULES = {
36
+ contract: "Unified Contract Registry 或明确为 advisory/experimental",
37
+ guard: "Guard Evaluation",
38
+ verifier: "Guard Evaluation",
39
+ workflow: "Workflow Contract Registry 和真实编排",
40
+ knowledge_rule: "Knowledge Injection Boundary 或明确 manual_reference",
41
+ cli_command: "bin/soloforge",
42
+ adapter_behavior: "对应 adapter 模板和 adapter 测试",
43
+ diagnostic_code: "真实路径产出",
44
+ governance_report: "真实命令或真实 workflow 输出",
45
+ business_service: "controller/job/page/consumer/public API 入口",
46
+ other: "生产调用路径",
47
+ };
48
+ export { SOLOFORGE_WIRING_RULES };
49
+ /** hard_fail 的状态 */
50
+ const HARD_FAIL_STATUSES = [
51
+ "implemented_not_integrated",
52
+ "dead_code_candidate",
53
+ ];
54
+ /** 允许的状态 */
55
+ const ALLOW_STATUSES = [
56
+ "integrated",
57
+ ];
58
+ /** warning 的状态 */
59
+ const WARNING_STATUSES = [
60
+ "experimental_isolated",
61
+ "planned_integration",
62
+ ];
63
+ // ── Query functions ──
64
+ /**
65
+ * 判断文件是否为豁免文件。
66
+ * @param modulePath - 模块路径
67
+ * @returns 豁免结果及原因
68
+ */
69
+ export function isExemptFile(modulePath) {
70
+ for (const { pattern, reason } of EXEMPT_PATTERNS) {
71
+ if (pattern.test(modulePath)) {
72
+ return { exempt: true, reason };
73
+ }
74
+ }
75
+ return { exempt: false };
76
+ }
77
+ /**
78
+ * 判断引用类型是否为非接入引用。
79
+ * @param refType - 引用类型
80
+ * @returns 是否为非接入引用
81
+ */
82
+ export function isNonIntegrationReference(refType) {
83
+ return NON_INTEGRATION_REFERENCES.includes(refType);
84
+ }
85
+ /**
86
+ * 获取指定能力类型的接入要求。
87
+ * @param kind - 能力类型
88
+ * @returns 接入要求描述
89
+ */
90
+ export function getWiringRequirement(kind) {
91
+ return SOLOFORGE_WIRING_RULES[kind];
92
+ }
93
+ /** 判断模块是否只被测试导入 */
94
+ export function isTestOnlyModule(modulePath, importers) {
95
+ const prodImporters = importers.filter((i) => !i.path.startsWith("tests/") &&
96
+ !i.path.includes(".test.") &&
97
+ !i.path.includes(".spec.") &&
98
+ !isNonIntegrationReference(i.ref_type));
99
+ return prodImporters.length === 0 && importers.length > 0;
100
+ }
101
+ /** 判断模块是否只有 registry/index export 引用 */
102
+ export function isRegistryOnlyModule(modulePath, importers) {
103
+ const realImporters = importers.filter((i) => !isNonIntegrationReference(i.ref_type));
104
+ return realImporters.length === 0 && importers.length > 0;
105
+ }
106
+ /** 判断是否有入口链路 */
107
+ /**
108
+ * 判断契约是否有入口链路。
109
+ * @param contract - 主链路接入契约
110
+ * @returns 是否有入口链路
111
+ */
112
+ export function hasEntryTrace(contract) {
113
+ return contract.entry_traces.length > 0 &&
114
+ contract.entry_traces.some((t) => t.call_chain.length > 0);
115
+ }
116
+ /** 判断是否有可观测证据 */
117
+ /**
118
+ * 判断契约是否有可观测证据。
119
+ * @param contract - 主链路接入契约
120
+ * @returns 是否有可观测证据
121
+ */
122
+ export function hasObservability(contract) {
123
+ return contract.observability_refs.length > 0;
124
+ }
125
+ /** 判断是否有集成测试 */
126
+ /**
127
+ * 判断契约是否有集成测试。
128
+ * @param contract - 主链路接入契约
129
+ * @returns 是否有集成测试
130
+ */
131
+ export function hasIntegrationTest(contract) {
132
+ return contract.integration_tests.length > 0;
133
+ }
134
+ /** 判断是否有生产调用 */
135
+ /**
136
+ * 判断契约是否有生产调用。
137
+ * @param contract - 主链路接入契约
138
+ * @returns 是否有生产调用
139
+ */
140
+ export function hasProductionImport(contract) {
141
+ return contract.production_imports.length > 0;
142
+ }
143
+ // ── Orphan Implementation Gate ──
144
+ /**
145
+ * 孤岛模块门禁检查。
146
+ * 检查模块是否存在只被测试导入、无入口链路等问题。
147
+ * @param contract - 主链路接入契约
148
+ * @param capabilityKind - 能力类型(可选)
149
+ * @returns 集成发现列表
150
+ */
151
+ export function orphanGate(contract, capabilityKind) {
152
+ const findings = [];
153
+ const path = contract.module_path;
154
+ console.error(`[soloForge] 主链路接入: 开始孤岛门禁检查 — ${path}`);
155
+ // 豁免文件始终允许
156
+ const exempt = isExemptFile(path);
157
+ if (exempt.exempt) {
158
+ console.error("[soloForge] 主链路接入: 孤岛门禁 — 豁免文件 " + path + " (" + exempt.reason + ")");
159
+ findings.push({
160
+ severity: "allow",
161
+ module_path: path,
162
+ reason: `豁免文件: ${exempt.reason}`,
163
+ recommended_action: "allow",
164
+ });
165
+ return findings;
166
+ }
167
+ // 规则 1: 只被测试导入 → hard_fail
168
+ if (contract.production_imports.length === 0 && contract.integration_tests.length > 0) {
169
+ console.error("[soloForge] 主链路接入: 孤岛门禁 — 规则1命中: " + path + " 只被测试导入");
170
+ findings.push({
171
+ severity: "hard_fail",
172
+ module_path: path,
173
+ reason: `模块 ${path} 只被测试导入,无生产代码调用`,
174
+ recommended_action: "wire_to_main_path",
175
+ });
176
+ }
177
+ // 规则 1b: 被导入但从未被调用(仅导入)→ hard_fail
178
+ if (contract.production_imports.length === 0 && contract.status === "implemented_not_integrated") {
179
+ console.error("[soloForge] 主链路接入: 孤岛门禁 — 规则1b命中: " + path + " 被导入但从未被调用");
180
+ findings.push({
181
+ severity: "hard_fail",
182
+ module_path: path,
183
+ reason: `模块 ${path} 被导入但从未被调用,无真实调用证据`,
184
+ recommended_action: "wire_to_main_path",
185
+ });
186
+ }
187
+ // 规则 2: enforced 能力无入口链路 → hard_fail
188
+ if (contract.status === "implemented_not_integrated" && !hasEntryTrace(contract)) {
189
+ console.error("[soloForge] 主链路接入: 孤岛门禁 — 规则2命中: " + path + " 无入口链路");
190
+ findings.push({
191
+ severity: "hard_fail",
192
+ module_path: path,
193
+ reason: `新增 enforced 能力 ${path} 无入口链路`,
194
+ recommended_action: "add_entry_trace",
195
+ });
196
+ }
197
+ // 规则 3: guard/verifier/contract 只被测试调用 → hard_fail
198
+ if (capabilityKind &&
199
+ (capabilityKind === "guard" || capabilityKind === "verifier" || capabilityKind === "contract") &&
200
+ !hasProductionImport(contract)) {
201
+ console.error("[soloForge] 主链路接入: 孤岛门禁 — 规则3命中: " + capabilityKind + " " + path + " 只被测试调用");
202
+ findings.push({
203
+ severity: "hard_fail",
204
+ module_path: path,
205
+ reason: `新增 ${capabilityKind} ${path} 只被测试调用`,
206
+ recommended_action: "wire_to_main_path",
207
+ });
208
+ }
209
+ // 规则 4: 影响交付结论但无可观测证据 → hard_fail
210
+ if (contract.status === "integrated" &&
211
+ !hasObservability(contract) &&
212
+ (capabilityKind === "contract" || capabilityKind === "guard" || capabilityKind === "verifier")) {
213
+ findings.push({
214
+ severity: "hard_fail",
215
+ module_path: path,
216
+ reason: `新增代码影响交付结论但无可观测证据: ${path}`,
217
+ recommended_action: "add_entry_trace",
218
+ });
219
+ }
220
+ // 规则 5: 无集成测试 → hard_fail (experimental_isolated 降级 warning)
221
+ if (!hasIntegrationTest(contract) && contract.status !== "experimental_isolated") {
222
+ console.error("[soloForge] 主链路接入: 孤岛门禁 — 规则5命中: " + path + " 缺少集成测试");
223
+ findings.push({
224
+ severity: "hard_fail",
225
+ module_path: path,
226
+ reason: `模块 ${path} 缺少集成/契约测试`,
227
+ recommended_action: "add_integration_test",
228
+ });
229
+ }
230
+ // 规则 6: experimental_isolated 无入口 → warning (not hard_fail)
231
+ if (contract.status === "experimental_isolated" && !hasEntryTrace(contract)) {
232
+ findings.push({
233
+ severity: "warning",
234
+ module_path: path,
235
+ reason: `experimental 代码 ${path} 无入口但已明确隔离`,
236
+ recommended_action: "mark_experimental",
237
+ });
238
+ }
239
+ // 规则 7: dead_code_candidate
240
+ if (contract.status === "dead_code_candidate") {
241
+ findings.push({
242
+ severity: "warning",
243
+ module_path: path,
244
+ reason: `模块 ${path} 为 dead_code_candidate`,
245
+ recommended_action: "retire_dead_code",
246
+ });
247
+ }
248
+ console.error("[soloForge] 主链路接入: 孤岛门禁完成 — " + path + " 发现 " + findings.length + " 个问题");
249
+ return findings;
250
+ }
251
+ // ── Integration Audit ──
252
+ /**
253
+ * 集成审计。
254
+ * 审计所有契约的接入状态,生成审计报告。
255
+ * @param contracts - 主链路接入契约列表
256
+ * @param capabilityKinds - 模块路径到能力类型的映射(可选)
257
+ * @returns 集成审计报告
258
+ */
259
+ export function auditIntegration(contracts, capabilityKinds) {
260
+ console.error(`[soloForge] 主链路接入: 开始集成审计 — 共 ${contracts.length} 个契约`);
261
+ const report = {
262
+ orphan_modules: [],
263
+ registry_only_modules: [],
264
+ test_only_modules: [],
265
+ unreachable_capabilities: [],
266
+ missing_observability: [],
267
+ required_entry_traces: [],
268
+ findings: [],
269
+ };
270
+ for (const c of contracts) {
271
+ const kind = capabilityKinds?.get(c.module_path);
272
+ const gateFindings = orphanGate(c, kind);
273
+ report.findings.push(...gateFindings);
274
+ // 孤岛模块: 仅测试导入
275
+ if (c.production_imports.length === 0 && c.integration_tests.length > 0) {
276
+ report.orphan_modules.push(c.module_path);
277
+ }
278
+ // 仅注册表: 只有注册表/index 引用
279
+ if (c.production_imports.length === 0 && c.entry_traces.length === 0) {
280
+ report.registry_only_modules.push(c.module_path);
281
+ }
282
+ // 仅测试模块
283
+ if (!hasProductionImport(c) && c.integration_tests.length > 0) {
284
+ report.test_only_modules.push(c.module_path);
285
+ }
286
+ // 不可达能力: 状态非 integrated 且无入口链路
287
+ if (!hasEntryTrace(c) && c.status !== "experimental_isolated") {
288
+ report.unreachable_capabilities.push(c.module_path);
289
+ }
290
+ // 缺少可观测性
291
+ if (!hasObservability(c) && c.status === "integrated") {
292
+ report.missing_observability.push(c.module_path);
293
+ }
294
+ // 非接入模块需要的入口链路
295
+ if (!hasEntryTrace(c) && c.status !== "integrated" && c.status !== "experimental_isolated") {
296
+ report.required_entry_traces.push({
297
+ entry_type: "cli",
298
+ entry_id: `required-for-${c.module_path}`,
299
+ call_chain: [],
300
+ trigger_example: `需要为 ${c.module_path} 建立入口链路`,
301
+ });
302
+ }
303
+ }
304
+ console.error("[soloForge] 主链路接入: 集成审计完成 — 孤岛 " + report.orphan_modules.length + ", 注册表 " + report.registry_only_modules.length + ", 仅测试 " + report.test_only_modules.length + ", 不可达 " + report.unreachable_capabilities.length);
305
+ return report;
306
+ }
307
+ // ── Factory ──
308
+ /**
309
+ * 创建主链路接入契约。
310
+ * @param params.module_path - 模块路径
311
+ * @param params.owner - 负责人
312
+ * @returns 主链路接入契约
313
+ */
314
+ export function createMainPathIntegrationContract(params) {
315
+ return {
316
+ module_path: params.module_path,
317
+ capability_id: params.capability_id,
318
+ contract_id: params.contract_id,
319
+ issue_id: params.issue_id,
320
+ status: params.status ?? "implemented_not_integrated",
321
+ production_imports: params.production_imports ?? [],
322
+ entry_traces: params.entry_traces ?? [],
323
+ observability_refs: params.observability_refs ?? [],
324
+ integration_tests: params.integration_tests ?? [],
325
+ allowed_isolation_reason: params.allowed_isolation_reason,
326
+ owner: params.owner,
327
+ };
328
+ }
329
+ /**
330
+ * 创建入口链路追踪记录。
331
+ * @param params - 入口追踪参数
332
+ * @returns 入口链路追踪
333
+ */
334
+ export function createEntryPointTrace(params) {
335
+ return {
336
+ entry_type: params.entry_type,
337
+ entry_id: params.entry_id,
338
+ call_chain: params.call_chain,
339
+ trigger_example: params.trigger_example,
340
+ evidence_ref: params.evidence_ref,
341
+ };
342
+ }
343
+ /**
344
+ * 验证交付答案。
345
+ * @param answers - 交付答案
346
+ * @returns 集成发现列表
347
+ */
348
+ export function validateDeliveryAnswers(answers) {
349
+ const findings = [];
350
+ for (const mod of answers.new_modules) {
351
+ if (answers.called_by.length === 0) {
352
+ findings.push({
353
+ severity: "hard_fail",
354
+ module_path: mod,
355
+ reason: `新增模块 ${mod} 没有被任何生产代码调用`,
356
+ recommended_action: "wire_to_main_path",
357
+ });
358
+ }
359
+ if (!answers.user_trigger) {
360
+ findings.push({
361
+ severity: "hard_fail",
362
+ module_path: mod,
363
+ reason: `新增模块 ${mod} 没有用户触发路径`,
364
+ recommended_action: "add_entry_trace",
365
+ });
366
+ }
367
+ }
368
+ for (const f of answers.test_only_files) {
369
+ findings.push({
370
+ severity: "hard_fail",
371
+ module_path: f,
372
+ reason: `文件 ${f} 只被测试导入`,
373
+ recommended_action: "wire_to_main_path",
374
+ });
375
+ }
376
+ for (const r of answers.registered_not_executed) {
377
+ findings.push({
378
+ severity: "hard_fail",
379
+ module_path: r,
380
+ reason: `能力 ${r} 只注册未执行`,
381
+ recommended_action: "wire_to_main_path",
382
+ });
383
+ }
384
+ for (const s of answers.non_integrated_statuses) {
385
+ if (s === "implemented_not_integrated" || s === "dead_code_candidate") {
386
+ findings.push({
387
+ severity: "warning",
388
+ module_path: "*",
389
+ reason: `存在 ${s} 状态的模块`,
390
+ recommended_action: "wire_to_main_path",
391
+ });
392
+ }
393
+ }
394
+ return findings;
395
+ }
396
+ // ── Chinese Labels ──
397
+ /**
398
+ * 获取接入状态的中文标签。
399
+ * @param status - 接入状态
400
+ * @returns 中文标签
401
+ */
402
+ export function statusLabel(status) {
403
+ const labels = {
404
+ integrated: "已接入",
405
+ implemented_not_integrated: "已实现未接入",
406
+ experimental_isolated: "实验性隔离",
407
+ planned_integration: "计划接入",
408
+ dead_code_candidate: "废弃候选",
409
+ };
410
+ return labels[status];
411
+ }
412
+ /**
413
+ * 获取入口类型的中文标签。
414
+ * @param type - 入口类型
415
+ * @returns 中文标签
416
+ */
417
+ export function entryTypeLabel(type) {
418
+ const labels = {
419
+ cli: "CLI 命令",
420
+ mcp_tool: "MCP 工具",
421
+ workflow: "工作流",
422
+ adapter_prompt: "Adapter 提示",
423
+ frontend_route: "前端路由",
424
+ backend_route: "后端路由",
425
+ job: "后台任务",
426
+ consumer: "消费者",
427
+ cron: "定时任务",
428
+ webhook: "Webhook",
429
+ public_api: "公开 API",
430
+ command: "命令",
431
+ };
432
+ return labels[type];
433
+ }
434
+ /**
435
+ * 构建集成反馈信息。
436
+ * @param contract - 主链路接入契约
437
+ * @returns 格式化的反馈文本
438
+ */
439
+ export function buildIntegrationFeedback(contract) {
440
+ const lines = [];
441
+ lines.push(`模块: ${contract.module_path}`);
442
+ lines.push(`状态: ${statusLabel(contract.status)}`);
443
+ lines.push(`负责人: ${contract.owner}`);
444
+ if (contract.entry_traces.length > 0) {
445
+ lines.push(`入口链路:`);
446
+ for (const t of contract.entry_traces) {
447
+ lines.push(` - ${entryTypeLabel(t.entry_type)}: ${t.entry_id}`);
448
+ lines.push(` 调用链: ${t.call_chain.join(" -> ")}`);
449
+ lines.push(` 触发示例: ${t.trigger_example}`);
450
+ }
451
+ }
452
+ else {
453
+ lines.push(`入口链路: 无 (模块未接入主链路)`);
454
+ }
455
+ lines.push(`生产调用: ${contract.production_imports.length > 0 ? contract.production_imports.join(", ") : "无"}`);
456
+ lines.push(`可观测: ${contract.observability_refs.length > 0 ? contract.observability_refs.join(", ") : "无"}`);
457
+ lines.push(`集成测试: ${contract.integration_tests.length > 0 ? contract.integration_tests.join(", ") : "无"}`);
458
+ if (contract.allowed_isolation_reason) {
459
+ lines.push(`豁免原因: ${contract.allowed_isolation_reason}`);
460
+ }
461
+ return lines.join("\n");
462
+ }
463
+ // ── Governance Validation ──
464
+ /**
465
+ * 验证主链路接入。
466
+ * @param options.contracts - 主链路接入契约列表
467
+ * @param options.capabilityKinds - 模块路径到能力类型的映射(可选)
468
+ * @returns 治理发现列表
469
+ */
470
+ export function validateMainPathIntegration(options) {
471
+ const findings = [];
472
+ console.error(`[soloForge] 主链路接入: 开始治理验证 — 共 ${options.contracts.length} 个契约`);
473
+ for (const c of options.contracts) {
474
+ const kind = options.capabilityKinds?.get(c.module_path);
475
+ // 规则 1: 新增 src/** 生产代码只被测试导入 → hard_fail
476
+ if (c.module_path.startsWith("src/") && !hasProductionImport(c) && c.integration_tests.length > 0 && !isExemptFile(c.module_path).exempt) {
477
+ findings.push({
478
+ severity: "hard_fail",
479
+ rule: "gc-test-only-module",
480
+ module_path: c.module_path,
481
+ message: `新增 src/ 生产代码 ${c.module_path} 只被测试导入,必须 hard_fail`,
482
+ });
483
+ }
484
+ // 规则 2: enforced contract/guard/verifier/workflow 无入口链路 → hard_fail
485
+ if (kind &&
486
+ (kind === "contract" || kind === "guard" || kind === "verifier" || kind === "workflow") &&
487
+ c.status !== "experimental_isolated" &&
488
+ !hasEntryTrace(c)) {
489
+ findings.push({
490
+ severity: "hard_fail",
491
+ rule: "gc-enforced-no-entry",
492
+ module_path: c.module_path,
493
+ message: `新增 enforced ${kind} ${c.module_path} 没有入口链路和真实编排路径`,
494
+ });
495
+ }
496
+ // 规则 3: registry-only / manifest-only / index-export-only 不得视为完成
497
+ if (c.status === "integrated" &&
498
+ !hasProductionImport(c) &&
499
+ !hasEntryTrace(c)) {
500
+ findings.push({
501
+ severity: "hard_fail",
502
+ rule: "gc-registry-only-completion",
503
+ module_path: c.module_path,
504
+ message: `模块 ${c.module_path} 只有 registry/index export 引用,不得标记为 integrated`,
505
+ });
506
+ }
507
+ // 规则 4: 必须有至少一条集成测试证明真实入口触发
508
+ if (c.status === "integrated" &&
509
+ !hasIntegrationTest(c) &&
510
+ !isExemptFile(c.module_path).exempt) {
511
+ findings.push({
512
+ severity: "hard_fail",
513
+ rule: "gc-no-integration-test",
514
+ module_path: c.module_path,
515
+ message: `已接入模块 ${c.module_path} 必须有集成测试证明真实入口能触发`,
516
+ });
517
+ }
518
+ // 规则 5: 必须有可观测痕迹
519
+ if (c.status === "integrated" &&
520
+ !hasObservability(c) &&
521
+ kind &&
522
+ (kind === "contract" || kind === "guard" || kind === "verifier" || kind === "diagnostic_code" || kind === "governance_report")) {
523
+ findings.push({
524
+ severity: "hard_fail",
525
+ rule: "gc-no-observability",
526
+ module_path: c.module_path,
527
+ message: `新增 ${kind} ${c.module_path} 缺少可观测痕迹`,
528
+ });
529
+ }
530
+ // 规则 6: diagnostic_code 必须能由真实路径产出
531
+ if (kind === "diagnostic_code" && !hasEntryTrace(c)) {
532
+ findings.push({
533
+ severity: "hard_fail",
534
+ rule: "gc-diagnostic-no-path",
535
+ module_path: c.module_path,
536
+ message: `新增诊断码 ${c.module_path} 无法由真实路径产出`,
537
+ });
538
+ }
539
+ // 规则 7: workflow 没有实际编排路径 → hard_fail
540
+ if (kind === "workflow" && c.status !== "experimental_isolated" && !hasEntryTrace(c)) {
541
+ findings.push({
542
+ severity: "hard_fail",
543
+ rule: "gc-workflow-no-orchestration",
544
+ module_path: c.module_path,
545
+ message: `新增 workflow ${c.module_path} 没有实际编排路径`,
546
+ });
547
+ }
548
+ // 规则 8: 新增 CLI 能力必须接入 bin/soloforge
549
+ if (kind === "cli_command" && !c.entry_traces.some(t => t.entry_type === "cli")) {
550
+ findings.push({
551
+ severity: "hard_fail",
552
+ rule: "gc-cli-no-bin",
553
+ module_path: c.module_path,
554
+ message: `新增 CLI 能力 ${c.module_path} 必须接入 bin/soloforge`,
555
+ });
556
+ }
557
+ // 规则 9: advisory 能力有 registry 但暂无入口 → warning
558
+ if (c.status === "experimental_isolated" && !hasEntryTrace(c)) {
559
+ findings.push({
560
+ severity: "warning",
561
+ rule: "gc-advisory-no-entry",
562
+ module_path: c.module_path,
563
+ message: `advisory/experimental 能力 ${c.module_path} 有 registry 但暂无入口`,
564
+ });
565
+ }
566
+ // 规则 10: implemented_not_integrated 不应标记完成
567
+ if (c.status === "implemented_not_integrated") {
568
+ findings.push({
569
+ severity: "warning",
570
+ rule: "gc-not-integrated-status",
571
+ module_path: c.module_path,
572
+ message: `模块 ${c.module_path} 状态为 implemented_not_integrated,不能标记完成`,
573
+ });
574
+ }
575
+ }
576
+ console.error(`[soloForge] 主链路接入: 治理验证完成 — 发现 ${findings.length} 个问题`);
577
+ return findings;
578
+ }
579
+ // ═══════════════════════════════════════════════════════════════
580
+ // Real Scanning Infrastructure — 真实主链路接入扫描
581
+ // ═══════════════════════════════════════════════════════════════
582
+ import fs from "node:fs";
583
+ import fspath from "node:path";
584
+ /** 生产源码扩展名 */
585
+ const PRODUCTION_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx", ".java", ".kt", ".go", ".py"]);
586
+ /** 表示非生产文件的匹配模式 */
587
+ const NON_PRODUCTION_PATTERNS = [
588
+ /\.d\.ts$/,
589
+ /\.test\./,
590
+ /\.spec\./,
591
+ /\/tests\//,
592
+ /^tests?\//,
593
+ /\/__tests__\//,
594
+ /\/fixtures?\//,
595
+ /\/demo\//,
596
+ /(?:^|\/src\/)examples?\//,
597
+ /\/docs?\//,
598
+ /\/mocks?\//,
599
+ ];
600
+ /**
601
+ * Determine if a file is a production source file.
602
+ * Uses config scope, extension, and exclusion patterns.
603
+ */
604
+ /**
605
+ * 判断文件是否为生产源码文件。
606
+ * @param filePath - 文件路径
607
+ * @param config - 扫描配置(可选)
608
+ * @returns 是否为生产文件
609
+ */
610
+ export function isProductionFile(filePath, config) {
611
+ const normalized = filePath.replace(/\\/g, "/");
612
+ const ext = fspath.extname(normalized);
613
+ if (!PRODUCTION_EXTENSIONS.has(ext)) {
614
+ return { isProd: false, reason: `非生产扩展名: ${ext}` };
615
+ }
616
+ for (const p of NON_PRODUCTION_PATTERNS) {
617
+ if (p.test(normalized)) {
618
+ return { isProd: false, reason: `非生产文件: ${p.source}` };
619
+ }
620
+ }
621
+ const exempt = isExemptFile(normalized);
622
+ if (exempt.exempt) {
623
+ return { isProd: false, reason: exempt.reason };
624
+ }
625
+ // 如果提供了配置,检查作用域
626
+ if (config) {
627
+ const inScope = isInScope(normalized, config);
628
+ if (!inScope) {
629
+ return { isProd: false, reason: "不在项目 scope 范围内" };
630
+ }
631
+ }
632
+ return { isProd: true };
633
+ }
634
+ function isInScope(normalizedPath, config) {
635
+ const scopes = [];
636
+ if (config.scope?.backend)
637
+ scopes.push(...config.scope.backend);
638
+ if (config.scope?.frontend)
639
+ scopes.push(...config.scope.frontend);
640
+ for (const repo of config.repos ?? []) {
641
+ if (repo.scope)
642
+ scopes.push(...repo.scope);
643
+ scopes.push(repo.path.replace(/\\/g, "/"));
644
+ }
645
+ if (scopes.length === 0)
646
+ return normalizedPath.startsWith("src/");
647
+ return scopes.some((s) => {
648
+ const ns = s.replace(/\\/g, "/").replace(/^\.\//, "");
649
+ return normalizedPath.startsWith(ns);
650
+ });
651
+ }
652
+ /**
653
+ * Walk a directory recursively, collecting all file paths.
654
+ */
655
+ /**
656
+ * 递归遍历目录,收集所有文件路径。
657
+ * @param dir - 目录路径
658
+ * @returns 文件路径列表
659
+ */
660
+ export function walkDir(dir) {
661
+ console.error("[soloForge] 主链路接入: 遍历目录 — " + dir);
662
+ const results = [];
663
+ if (!fs.existsSync(dir)) {
664
+ console.error("[soloForge] 主链路接入: 遍历目录 — 目录不存在: " + dir);
665
+ return results;
666
+ }
667
+ try {
668
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
669
+ const full = fspath.join(dir, entry.name);
670
+ if (entry.isDirectory())
671
+ results.push(...walkDir(full));
672
+ else
673
+ results.push(full);
674
+ }
675
+ }
676
+ catch (e) {
677
+ console.error("[soloForge] 主链路接入: 遍历目录异常 — " + dir + ": " + (e instanceof Error ? e.message : String(e)));
678
+ }
679
+ console.error("[soloForge] 主链路接入: 遍历目录完成 — " + dir + " 共 " + results.length + " 个文件");
680
+ return results;
681
+ }
682
+ // ── Call Evidence Detection ──
683
+ /** 从 TS/JS 导入语句中提取导入的符号名称 */
684
+ function extractImportedNames(content, targetNorm) {
685
+ const names = [];
686
+ const modBasename = targetNorm.split("/").pop();
687
+ const modJsExt = modBasename.replace(/\.ts$/, ".js");
688
+ const escaped = modBasename.replace(/\./g, "\\.");
689
+ const escapedJs = modJsExt.replace(/\./g, "\\.");
690
+ const namedRe = new RegExp(`import\\s+\\{([^}]+)\\}\\s+from\\s+['"][^'"]*(?:${escaped}|${escapedJs})[^'"]*['"]`, "g");
691
+ let m;
692
+ while ((m = namedRe.exec(content)) !== null) {
693
+ for (const name of m[1].split(",")) {
694
+ const trimmed = name.trim().replace(/\s+as\s+\w+/, "").trim();
695
+ if (trimmed)
696
+ names.push(trimmed);
697
+ }
698
+ }
699
+ const defaultRe = new RegExp(`import\\s+(\\w+)\\s+from\\s+['"][^'"]*(?:${escaped}|${escapedJs})[^'"]*['"]`, "g");
700
+ while ((m = defaultRe.exec(content)) !== null)
701
+ names.push(m[1]);
702
+ const nsRe = new RegExp(`import\\s+\\*\\s+as\\s+(\\w+)\\s+from\\s+['"][^'"]*(?:${escaped}|${escapedJs})[^'"]*['"]`, "g");
703
+ while ((m = nsRe.exec(content)) !== null)
704
+ names.push(m[1]);
705
+ return [...new Set(names)];
706
+ }
707
+ /** 从 Java/Kotlin 导入语句中提取导入的符号名称(全限定名 → 简单名称) */
708
+ function extractJavaImportedNames(content, targetFqn) {
709
+ const names = [];
710
+ const parts = targetFqn.split(".");
711
+ const simpleName = parts[parts.length - 1];
712
+ if (content.includes(simpleName))
713
+ names.push(simpleName);
714
+ return names;
715
+ }
716
+ /** Extract imported names from Go import */
717
+ function extractGoImportedNames(_content, _pkgPath) {
718
+ return [];
719
+ }
720
+ /** Extract imported names from Python import */
721
+ function extractPythonImportedNames(content, modulePath) {
722
+ const names = [];
723
+ const parts = modulePath.split(".");
724
+ const modName = parts[parts.length - 1];
725
+ const asRe = new RegExp(`import\\s+${modName}\\s+as\\s+(\\w+)`);
726
+ const asMatch = content.match(asRe);
727
+ if (asMatch)
728
+ names.push(asMatch[1]);
729
+ if (content.includes(modName))
730
+ names.push(modName);
731
+ return [...new Set(names)];
732
+ }
733
+ /**
734
+ * Detect call evidence in TS/JS/TSX/JSX content.
735
+ * Returns list of evidence pattern descriptions.
736
+ */
737
+ function detectTsCallEvidence(content, names) {
738
+ // 移除 import/export 行以避免导入路径误报(例如 "noop.js")
739
+ const codeOnly = content.replace(/^import\s.+$/gm, "").replace(/^export\s+\{[^}]*\}\s+from\s+.+$/gm, "");
740
+ const evidence = [];
741
+ for (const name of names) {
742
+ if (new RegExp(`\\b${name}\\s*\\(`).test(codeOnly))
743
+ evidence.push(`${name}()`);
744
+ if (new RegExp(`new\\s+${name}\\s*[\\(\\{]`).test(codeOnly))
745
+ evidence.push(`new ${name}()`);
746
+ if (new RegExp(`\\b${name}\\s*\\.`).test(codeOnly))
747
+ evidence.push(`${name}.method()`);
748
+ if (new RegExp(`<${name}[\\s/>]`).test(codeOnly))
749
+ evidence.push(`<${name} />`);
750
+ }
751
+ return evidence;
752
+ }
753
+ /** Detect call evidence in Java/Kotlin content */
754
+ function detectJavaCallEvidence(content, names) {
755
+ const evidence = [];
756
+ for (const name of names) {
757
+ const nameRe = name.replace(/\./g, "\\.");
758
+ // new ServiceClass(...) 或 Kotlin: ServiceClass(...)
759
+ if (new RegExp(`(?:new\\s+)?${nameRe}\\s*\\(`).test(content)) {
760
+ evidence.push(new RegExp(`new\\s+${nameRe}`).test(content) ? `new ${name}()` : `${name}()`);
761
+ }
762
+ // 方法调用: service.method(...)
763
+ if (new RegExp(`\\b${nameRe}\\s*\\.`).test(content))
764
+ evidence.push(`${name}.method()`);
765
+ // @Inject / @Autowired 字段
766
+ if (new RegExp(`@(?:Inject|Autowired|Resource)\\b.*${nameRe}`).test(content))
767
+ evidence.push(`@Inject ${name}`);
768
+ // 构造函数参数或字段类型
769
+ if (new RegExp(`\\b${nameRe}\\s+\\w+[,)=]`).test(content))
770
+ evidence.push(`${name} param`);
771
+ }
772
+ return evidence;
773
+ }
774
+ /** Detect call evidence in Python content */
775
+ function detectPythonCallEvidence(content, names) {
776
+ const evidence = [];
777
+ for (const name of names) {
778
+ if (new RegExp(`\\b${name}\\s*\\(`).test(content))
779
+ evidence.push(`${name}()`);
780
+ if (new RegExp(`\\b${name}\\s*\\.`).test(content))
781
+ evidence.push(`${name}.method()`);
782
+ }
783
+ return evidence;
784
+ }
785
+ /** Detect call evidence in Go content */
786
+ function detectGoCallEvidence(content, names) {
787
+ const evidence = [];
788
+ for (const name of names) {
789
+ if (new RegExp(`\\b${name}\\s*\\.`).test(content))
790
+ evidence.push(`${name}.Method()`);
791
+ if (new RegExp(`\\b${name}\\s*\\(`).test(content))
792
+ evidence.push(`${name}()`);
793
+ }
794
+ return evidence;
795
+ }
796
+ // ── Import Resolution ──
797
+ /**
798
+ * Extract import/require paths from source content.
799
+ */
800
+ /**
801
+ * 从源码内容中提取 import/require 路径。
802
+ * @param content - 源码内容
803
+ * @param filePath - 文件路径
804
+ * @returns 导入路径列表
805
+ */
806
+ export function extractImportPaths(content, filePath) {
807
+ console.error("[soloForge] 主链路接入: 提取导入路径 — " + filePath);
808
+ const paths = [];
809
+ const ext = fspath.extname(filePath);
810
+ if (ext === ".java" || ext === ".kt") {
811
+ const re = /import\s+([\w.]+)\s*;?/g;
812
+ let m;
813
+ while ((m = re.exec(content)) !== null)
814
+ paths.push(m[1]);
815
+ }
816
+ else if (ext === ".go") {
817
+ // import "path" 和 import ( ... "path" ... )
818
+ const singleRe = /import\s+"([^"]+)"/g;
819
+ let m;
820
+ while ((m = singleRe.exec(content)) !== null)
821
+ paths.push(m[1]);
822
+ const multiRe = /import\s*\(\s*([\s\S]*?)\)/g;
823
+ while ((m = multiRe.exec(content)) !== null) {
824
+ const inner = m[1];
825
+ const lines = inner.match(/"([^"]+)"/g);
826
+ if (lines)
827
+ for (const l of lines)
828
+ paths.push(l.replace(/"/g, ""));
829
+ }
830
+ }
831
+ else if (ext === ".py") {
832
+ const fromRe = /from\s+([\w.]+)\s+import/g;
833
+ let m;
834
+ while ((m = fromRe.exec(content)) !== null)
835
+ paths.push(m[1]);
836
+ const importRe = /\bimport\s+([\w.]+)/g;
837
+ while ((m = importRe.exec(content)) !== null)
838
+ paths.push(m[1]);
839
+ }
840
+ else {
841
+ // TypeScript/JavaScript
842
+ const fromRe = /(?:import|export)\s+(?:type\s+)?[^'"]*?\s+from\s+['"]([^'"]+)['"]/g;
843
+ let m;
844
+ while ((m = fromRe.exec(content)) !== null)
845
+ paths.push(m[1]);
846
+ const reqRe = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
847
+ while ((m = reqRe.exec(content)) !== null)
848
+ paths.push(m[1]);
849
+ }
850
+ console.error("[soloForge] 主链路接入: 提取导入路径完成 — " + filePath + " 共 " + paths.length + " 条");
851
+ return paths;
852
+ }
853
+ /**
854
+ * Resolve a relative import to a normalized project-relative path.
855
+ */
856
+ /**
857
+ * 将相对导入解析为标准化的项目相对路径。
858
+ * @param importSpecifier - 导入指定器
859
+ * @param fromFileRel - 来源文件的相对路径
860
+ * @param projectPath - 项目根路径
861
+ * @returns 解析后的相对路径
862
+ */
863
+ export function resolveImportPath(importSpecifier, fromFileRel, projectPath) {
864
+ if (!importSpecifier.startsWith("."))
865
+ return null;
866
+ console.error("[soloForge] 主链路接入: 解析导入路径 — " + importSpecifier + " (from " + fromFileRel + ")");
867
+ let spec = importSpecifier;
868
+ // 去除 .js/.jsx 扩展名 — 实际文件可能是 .ts 或 .tsx
869
+ const hasExt = /\.(ts|tsx|js|jsx)$/.test(spec);
870
+ if (spec.endsWith(".js"))
871
+ spec = spec.slice(0, -3);
872
+ else if (spec.endsWith(".jsx"))
873
+ spec = spec.slice(0, -4);
874
+ const fromDir = fspath.dirname(fspath.resolve(projectPath, fromFileRel));
875
+ const resolved = fspath.resolve(fromDir, spec);
876
+ // 优先尝试精确匹配(如果指定器有直接映射的扩展名)
877
+ if (hasExt && fs.existsSync(resolved)) {
878
+ return fspath.relative(projectPath, resolved).replace(/\\/g, "/");
879
+ }
880
+ // 尝试所有生产扩展名
881
+ for (const ext of [".ts", ".tsx", ".js", ".jsx"]) {
882
+ const p = resolved + ext;
883
+ if (fs.existsSync(p))
884
+ return fspath.relative(projectPath, p).replace(/\\/g, "/");
885
+ }
886
+ for (const idx of ["index.ts", "index.tsx", "index.js", "index.jsx"]) {
887
+ const p = fspath.join(resolved, idx);
888
+ if (fs.existsSync(p))
889
+ return fspath.relative(projectPath, p).replace(/\\/g, "/");
890
+ }
891
+ return null;
892
+ }
893
+ /** Normalize a module path by stripping extension for comparison */
894
+ function normalizeModulePath(p) {
895
+ return p.replace(/\.(ts|tsx|js|jsx)$/, "").replace(/\\/g, "/");
896
+ }
897
+ // ── Java/Kotlin FQN Resolution ──
898
+ /**
899
+ * Compute the Fully Qualified Name of a Java/Kotlin file from its package + class.
900
+ */
901
+ /**
902
+ * 从 Java/Kotlin 文件计算全限定名。
903
+ * @param filePath - 文件路径
904
+ * @param projectPath - 项目根路径
905
+ * @returns 全限定名
906
+ */
907
+ export function computeJavaFqn(filePath, projectPath) {
908
+ console.error("[soloForge] 主链路接入: 计算Java全限定名 — " + filePath);
909
+ let content;
910
+ try {
911
+ content = fs.readFileSync(fspath.join(projectPath, filePath), "utf-8");
912
+ }
913
+ catch (e) {
914
+ console.error("[soloForge] 主链路接入: 计算Java全限定名失败 — " + filePath + ": " + (e instanceof Error ? e.message : String(e)));
915
+ return null;
916
+ }
917
+ const pkgMatch = content.match(/package\s+([\w.]+)\s*;?/);
918
+ if (!pkgMatch) {
919
+ console.error("[soloForge] 主链路接入: 计算Java全限定名 — 未找到 package 声明: " + filePath);
920
+ return null;
921
+ }
922
+ const pkg = pkgMatch[1];
923
+ const classMatch = content.match(/(?:public\s+)?(?:class|interface|enum|record)\s+(\w+)/);
924
+ if (!classMatch) {
925
+ console.error("[soloForge] 主链路接入: 计算Java全限定名 — 未找到类声明: " + filePath);
926
+ return null;
927
+ }
928
+ const fqn = `${pkg}.${classMatch[1]}`;
929
+ console.error("[soloForge] 主链路接入: 计算Java全限定名完成 — " + fqn);
930
+ return fqn;
931
+ }
932
+ /**
933
+ * Match a Java FQN against import statements in another Java file.
934
+ */
935
+ function matchJavaFqn(importerContent, targetFqn) {
936
+ const fqnImport = "import " + targetFqn;
937
+ const wildcardImport = "import " + targetFqn.split(".").slice(0, -1).join(".") + ".*";
938
+ return importerContent.includes(fqnImport + ";") ||
939
+ importerContent.includes(fqnImport + "\n") ||
940
+ importerContent.includes(wildcardImport + ";") ||
941
+ importerContent.includes(wildcardImport + "\n");
942
+ }
943
+ // ── Python Module Path Resolution ──
944
+ /**
945
+ * Compute Python module path from file path.
946
+ * e.g. src/services/user.py → services.user
947
+ */
948
+ function computePythonModulePath(filePath) {
949
+ const normalized = filePath.replace(/\\/g, "/");
950
+ const noExt = normalized.replace(/\.py$/, "");
951
+ const parts = noExt.split("/");
952
+ // 去除常见前缀如 src/
953
+ const srcIdx = parts.findIndex(p => p === "src");
954
+ if (srcIdx >= 0)
955
+ return parts.slice(srcIdx + 1).join(".");
956
+ return parts.join(".");
957
+ }
958
+ // ── Go Package Path Resolution ──
959
+ /**
960
+ * Resolve Go import path from file path and module name.
961
+ * Simplified: returns directory-based package path.
962
+ */
963
+ function computeGoPkgPath(filePath) {
964
+ return fspath.dirname(filePath.replace(/\\/g, "/")).replace(/\\/g, "/");
965
+ }
966
+ // ── Core Scanning ──
967
+ /**
968
+ * Scan all project files to find who imports a given module.
969
+ * Classifies each importer and detects call evidence.
970
+ */
971
+ /**
972
+ * 扫描项目中所有文件,查找谁导入了指定模块。
973
+ * @param projectPath - 项目根路径
974
+ * @param moduleRelPath - 模块相对路径
975
+ * @returns 导入者扫描结果
976
+ */
977
+ export function scanModuleImporters(projectPath, moduleRelPath) {
978
+ console.error("[soloForge] 主链路接入: 扫描模块导入者 — " + moduleRelPath);
979
+ const result = {
980
+ production_imports: [],
981
+ production_calls: [],
982
+ test_imports: [],
983
+ barrel_exports: [],
984
+ registry_declarations: [],
985
+ import_only: [],
986
+ };
987
+ const targetNorm = normalizeModulePath(moduleRelPath);
988
+ const moduleExt = fspath.extname(moduleRelPath);
989
+ const allFiles = walkDir(projectPath);
990
+ // 预计算 Java/Kotlin 目标全限定名
991
+ let targetJavaFqn = null;
992
+ if (moduleExt === ".java" || moduleExt === ".kt") {
993
+ targetJavaFqn = computeJavaFqn(moduleRelPath, projectPath);
994
+ }
995
+ // 预计算 Python 目标模块路径
996
+ let targetPyModule = null;
997
+ if (moduleExt === ".py") {
998
+ targetPyModule = computePythonModulePath(moduleRelPath);
999
+ }
1000
+ // 预计算 Go 包路径
1001
+ let targetGoPkg = null;
1002
+ if (moduleExt === ".go") {
1003
+ targetGoPkg = computeGoPkgPath(moduleRelPath);
1004
+ }
1005
+ for (const file of allFiles) {
1006
+ const rel = fspath.relative(projectPath, file).replace(/\\/g, "/");
1007
+ if (normalizeModulePath(rel) === targetNorm)
1008
+ continue;
1009
+ const ext = fspath.extname(file);
1010
+ if (![".ts", ".tsx", ".js", ".jsx", ".java", ".kt", ".go", ".py"].includes(ext))
1011
+ continue;
1012
+ let content;
1013
+ try {
1014
+ content = fs.readFileSync(file, "utf-8");
1015
+ }
1016
+ catch {
1017
+ continue;
1018
+ }
1019
+ // ── Match imports using language-specific resolution ──
1020
+ let matched = false;
1021
+ let importedNames = [];
1022
+ if (moduleExt === ".java" || moduleExt === ".kt") {
1023
+ // Java/Kotlin: 通过全限定名匹配
1024
+ if (targetJavaFqn && matchJavaFqn(content, targetJavaFqn)) {
1025
+ matched = true;
1026
+ importedNames = extractJavaImportedNames(content, targetJavaFqn);
1027
+ }
1028
+ }
1029
+ else if (moduleExt === ".py") {
1030
+ // Python: 通过模块路径匹配
1031
+ if (targetPyModule) {
1032
+ const importerPaths = extractImportPaths(content, rel);
1033
+ for (const imp of importerPaths) {
1034
+ if (imp === targetPyModule || imp.startsWith(targetPyModule + ".")) {
1035
+ matched = true;
1036
+ importedNames = extractPythonImportedNames(content, targetPyModule);
1037
+ break;
1038
+ }
1039
+ }
1040
+ }
1041
+ }
1042
+ else if (moduleExt === ".go") {
1043
+ // Go: 通过包路径匹配
1044
+ if (targetGoPkg) {
1045
+ const importerPaths = extractImportPaths(content, rel);
1046
+ for (const imp of importerPaths) {
1047
+ if (imp.endsWith(targetGoPkg) || imp === targetGoPkg) {
1048
+ matched = true;
1049
+ importedNames = extractGoImportedNames(content, targetGoPkg);
1050
+ break;
1051
+ }
1052
+ }
1053
+ }
1054
+ }
1055
+ else {
1056
+ // TS/JS/TSX/JSX: 通过相对导入解析匹配
1057
+ const imports = extractImportPaths(content, rel);
1058
+ for (const imp of imports) {
1059
+ if (!imp.startsWith("."))
1060
+ continue;
1061
+ const resolved = resolveImportPath(imp, rel, projectPath);
1062
+ if (resolved && normalizeModulePath(resolved) === targetNorm) {
1063
+ matched = true;
1064
+ importedNames = extractImportedNames(content, targetNorm);
1065
+ break;
1066
+ }
1067
+ }
1068
+ }
1069
+ if (!matched)
1070
+ continue;
1071
+ // ── Classify the importer ──
1072
+ const isTest = /\.test\.|\.spec\.|\/tests\/|\/__tests__\//.test(rel);
1073
+ if (isTest) {
1074
+ result.test_imports.push(rel);
1075
+ continue;
1076
+ }
1077
+ if (isOnlyReExport(content, targetNorm, ext)) {
1078
+ result.barrel_exports.push(rel);
1079
+ continue;
1080
+ }
1081
+ if (isRegistryOnlyImport(content, targetNorm, ext)) {
1082
+ result.registry_declarations.push(rel);
1083
+ continue;
1084
+ }
1085
+ // ── Detect call evidence ──
1086
+ let callEvidence = [];
1087
+ if (ext === ".java" || ext === ".kt") {
1088
+ callEvidence = detectJavaCallEvidence(content, importedNames);
1089
+ }
1090
+ else if (ext === ".py") {
1091
+ callEvidence = detectPythonCallEvidence(content, importedNames);
1092
+ }
1093
+ else if (ext === ".go") {
1094
+ callEvidence = detectGoCallEvidence(content, importedNames);
1095
+ }
1096
+ else {
1097
+ callEvidence = detectTsCallEvidence(content, importedNames);
1098
+ }
1099
+ if (callEvidence.length > 0) {
1100
+ result.production_imports.push(rel);
1101
+ result.production_calls.push({ importer: rel, patterns: callEvidence });
1102
+ }
1103
+ else {
1104
+ // 仅导入,无调用证据
1105
+ result.import_only.push(rel);
1106
+ }
1107
+ }
1108
+ console.error("[soloForge] 主链路接入: 扫描模块导入者完成 — " + moduleRelPath + " 生产导入 " + result.production_imports.length + " 测试导入 " + result.test_imports.length + " 调用证据 " + result.production_calls.length);
1109
+ return result;
1110
+ }
1111
+ /** Check if a file only re-exports the module (barrel export) */
1112
+ function isOnlyReExport(content, targetNorm, ext) {
1113
+ if (ext === ".java" || ext === ".kt" || ext === ".go" || ext === ".py")
1114
+ return false;
1115
+ const modBasename = targetNorm.split("/").pop();
1116
+ const escaped = modBasename.replace(/\./g, "\\.");
1117
+ const escapedJs = modBasename.replace(/\.ts$/, ".js").replace(/\./g, "\\.");
1118
+ const reExportRe = new RegExp(`export\\s+(?:\\*|\\{[^}]*\\})\\s+from\\s+['"][^'"]*(?:${escaped}|${escapedJs})[^'"]*['"]`);
1119
+ if (!reExportRe.test(content))
1120
+ return false;
1121
+ const usageRe = new RegExp(`(?<!export\\s)(?<!from\\s['"])${modBasename.replace(/\./g, "\\.")}`, "g");
1122
+ const usageMatches = content.match(usageRe);
1123
+ return !usageMatches || usageMatches.length <= 2;
1124
+ }
1125
+ /** Check if a file only has registry-style declarations for the module */
1126
+ function isRegistryOnlyImport(content, targetNorm, ext) {
1127
+ if (ext === ".java" || ext === ".kt" || ext === ".go" || ext === ".py")
1128
+ return false;
1129
+ const modBasename = targetNorm.split("/").pop();
1130
+ const modJsExt = modBasename.replace(/\.ts$/, ".js");
1131
+ const escaped = modBasename.replace(/\./g, "\\.");
1132
+ const escapedJs = modJsExt.replace(/\./g, "\\.");
1133
+ const regPatterns = [
1134
+ new RegExp(`\\.push\\s*\\(`, "s"),
1135
+ new RegExp(`register\\s*\\(`, "s"),
1136
+ new RegExp(`entries\\s*[:=]`, "s"),
1137
+ ];
1138
+ const hasRegistry = regPatterns.some(p => p.test(content));
1139
+ if (!hasRegistry)
1140
+ return false;
1141
+ const importLineRe = new RegExp(`import\\s+.*from\\s+['"][^'"]*(?:${escaped}|${escapedJs})[^'"]*['"]`);
1142
+ const lines = content.split("\n");
1143
+ let importCount = 0;
1144
+ let usageCount = 0;
1145
+ for (const line of lines) {
1146
+ if (importLineRe.test(line)) {
1147
+ importCount++;
1148
+ continue;
1149
+ }
1150
+ if (line.includes(modBasename))
1151
+ usageCount++;
1152
+ }
1153
+ return usageCount <= 1 && importCount > 0;
1154
+ }
1155
+ /**
1156
+ * Identify entry points in the project by directory/file naming conventions.
1157
+ */
1158
+ /**
1159
+ * 通过目录/文件命名约定识别项目入口点。
1160
+ * @param projectPath - 项目根路径
1161
+ * @returns 入口点追踪列表
1162
+ */
1163
+ export function identifyProjectEntryPoints(projectPath) {
1164
+ console.error("[soloForge] 主链路接入: 识别项目入口点 — " + projectPath);
1165
+ const eps = [];
1166
+ const allFiles = walkDir(projectPath);
1167
+ const patterns = [
1168
+ { test: /adapters\/.*tools?\.ts$/, type: "mcp_tool", example: "MCP tool handler" },
1169
+ { test: /\/bin\//, type: "cli", example: "CLI command" },
1170
+ { test: /\/cli\//, type: "cli", example: "CLI entry" },
1171
+ { test: /\/commands?\//, type: "command", example: "Command handler" },
1172
+ { test: /\/routes?\//, type: "backend_route", example: "HTTP route" },
1173
+ { test: /\/controllers?\//, type: "backend_route", example: "Controller" },
1174
+ { test: /\/api\//, type: "public_api", example: "API endpoint" },
1175
+ { test: /\/pages?\//, type: "frontend_route", example: "Page component" },
1176
+ { test: /\/app\//, type: "frontend_route", example: "App entry" },
1177
+ { test: /\/jobs?\//, type: "job", example: "Background job" },
1178
+ { test: /\/consumers?\//, type: "consumer", example: "Event consumer" },
1179
+ { test: /\/workers?\//, type: "job", example: "Worker" },
1180
+ { test: /\/crons?\//, type: "cron", example: "Cron job" },
1181
+ { test: /\/webhooks?\//, type: "webhook", example: "Webhook handler" },
1182
+ ];
1183
+ for (const file of allFiles) {
1184
+ const rel = fspath.relative(projectPath, file).replace(/\\/g, "/");
1185
+ const ext = fspath.extname(file);
1186
+ if (!PRODUCTION_EXTENSIONS.has(ext))
1187
+ continue;
1188
+ if (/\.test\.|\.spec\.|\.d\.ts/.test(rel))
1189
+ continue;
1190
+ if (!fs.existsSync(file))
1191
+ continue;
1192
+ for (const { test, type, example } of patterns) {
1193
+ if (test.test(rel)) {
1194
+ eps.push(createEntryPointTrace({
1195
+ entry_type: type,
1196
+ entry_id: rel,
1197
+ call_chain: [rel],
1198
+ trigger_example: example,
1199
+ }));
1200
+ break;
1201
+ }
1202
+ }
1203
+ }
1204
+ console.error("[soloForge] 主链路接入: 识别项目入口点完成 — 共 " + eps.length + " 个入口");
1205
+ return eps;
1206
+ }
1207
+ /**
1208
+ * Trace from entry points to a target module via import chains.
1209
+ * Uses DFS with depth limit to prevent infinite loops.
1210
+ * Supports TS/JS, Java/Kotlin (FQN), Python, Go.
1211
+ */
1212
+ /**
1213
+ * 从入口点通过导入链追踪到目标模块。
1214
+ * @param projectPath - 项目根路径
1215
+ * @param moduleRelPath - 模块相对路径
1216
+ * @param entryPoints - 入口点列表
1217
+ * @returns 可达的入口点列表
1218
+ */
1219
+ export function traceModuleReachability(projectPath, moduleRelPath, entryPoints) {
1220
+ console.error("[soloForge] 主链路接入: 追踪模块可达性 — " + moduleRelPath + " 从 " + entryPoints.length + " 个入口");
1221
+ const targetNorm = normalizeModulePath(moduleRelPath);
1222
+ const moduleExt = fspath.extname(moduleRelPath);
1223
+ const reachable = [];
1224
+ let targetJavaFqn = null;
1225
+ if (moduleExt === ".java" || moduleExt === ".kt") {
1226
+ targetJavaFqn = computeJavaFqn(moduleRelPath, projectPath);
1227
+ }
1228
+ let targetPyModule = null;
1229
+ if (moduleExt === ".py") {
1230
+ targetPyModule = computePythonModulePath(moduleRelPath);
1231
+ }
1232
+ let targetGoPkg = null;
1233
+ if (moduleExt === ".go") {
1234
+ targetGoPkg = computeGoPkgPath(moduleRelPath);
1235
+ }
1236
+ for (const ep of entryPoints) {
1237
+ const epFile = fspath.resolve(projectPath, ep.entry_id);
1238
+ if (!fs.existsSync(epFile))
1239
+ continue;
1240
+ const chain = [];
1241
+ const visited = new Set();
1242
+ if (dfsTrace(epFile, targetNorm, projectPath, visited, chain, targetJavaFqn, targetPyModule, targetGoPkg)) {
1243
+ reachable.push({
1244
+ ...ep,
1245
+ call_chain: [ep.entry_id, ...chain],
1246
+ });
1247
+ }
1248
+ }
1249
+ console.error("[soloForge] 主链路接入: 追踪模块可达性完成 — " + moduleRelPath + " 可达 " + reachable.length + " 个入口");
1250
+ return reachable;
1251
+ }
1252
+ function dfsTrace(currentFile, targetNorm, projectPath, visited, chain, targetJavaFqn, targetPyModule, targetGoPkg, depth = 0) {
1253
+ if (depth > 15)
1254
+ return false;
1255
+ const abs = fspath.resolve(currentFile);
1256
+ if (visited.has(abs))
1257
+ return false;
1258
+ visited.add(abs);
1259
+ let content;
1260
+ try {
1261
+ content = fs.readFileSync(abs, "utf-8");
1262
+ }
1263
+ catch {
1264
+ return false;
1265
+ }
1266
+ const rel = fspath.relative(projectPath, abs).replace(/\\/g, "/");
1267
+ const ext = fspath.extname(rel);
1268
+ // 检查当前文件是否直接导入了目标模块
1269
+ if (targetJavaFqn && (ext === ".java" || ext === ".kt")) {
1270
+ if (matchJavaFqn(content, targetJavaFqn)) {
1271
+ if (depth > 0)
1272
+ chain.push(rel);
1273
+ return true;
1274
+ }
1275
+ }
1276
+ else if (targetPyModule && ext === ".py") {
1277
+ const importerPaths = extractImportPaths(content, rel);
1278
+ for (const imp of importerPaths) {
1279
+ if (imp === targetPyModule || imp.startsWith(targetPyModule + ".")) {
1280
+ if (depth > 0)
1281
+ chain.push(rel);
1282
+ return true;
1283
+ }
1284
+ }
1285
+ }
1286
+ else if (targetGoPkg && ext === ".go") {
1287
+ const importerPaths = extractImportPaths(content, rel);
1288
+ for (const imp of importerPaths) {
1289
+ if (imp.endsWith(targetGoPkg) || imp === targetGoPkg) {
1290
+ if (depth > 0)
1291
+ chain.push(rel);
1292
+ return true;
1293
+ }
1294
+ }
1295
+ }
1296
+ else {
1297
+ // TS/JS: 检查相对导入
1298
+ const imports = extractImportPaths(content, rel);
1299
+ for (const imp of imports) {
1300
+ if (!imp.startsWith("."))
1301
+ continue;
1302
+ const resolved = resolveImportPath(imp, rel, projectPath);
1303
+ if (resolved && normalizeModulePath(resolved) === targetNorm) {
1304
+ chain.push(resolved);
1305
+ return true;
1306
+ }
1307
+ }
1308
+ }
1309
+ // 递归: 跟随 TS/JS 文件的导入链
1310
+ if (!targetJavaFqn && !targetPyModule && !targetGoPkg) {
1311
+ const imports = extractImportPaths(content, rel);
1312
+ for (const imp of imports) {
1313
+ if (!imp.startsWith("."))
1314
+ continue;
1315
+ const resolved = resolveImportPath(imp, rel, projectPath);
1316
+ if (!resolved)
1317
+ continue;
1318
+ const nextAbs = fspath.resolve(projectPath, resolved);
1319
+ if (dfsTrace(nextAbs, targetNorm, projectPath, visited, chain, null, null, null, depth + 1)) {
1320
+ chain.unshift(resolved);
1321
+ return true;
1322
+ }
1323
+ }
1324
+ }
1325
+ return false;
1326
+ }
1327
+ /**
1328
+ * Collect observability evidence for a module.
1329
+ */
1330
+ /**
1331
+ * 收集模块的可观测性证据。
1332
+ * @param projectPath - 项目根路径
1333
+ * @param moduleRelPath - 模块相对路径
1334
+ * @returns 可观测性引用列表
1335
+ */
1336
+ export function collectModuleObservability(projectPath, moduleRelPath) {
1337
+ console.error("[soloForge] 主链路接入: 收集模块可观测性 — " + moduleRelPath);
1338
+ const refs = [];
1339
+ const fullPath = fspath.join(projectPath, moduleRelPath);
1340
+ let content;
1341
+ try {
1342
+ content = fs.readFileSync(fullPath, "utf-8");
1343
+ }
1344
+ catch (e) {
1345
+ console.error("[soloForge] 主链路接入: 收集模块可观测性失败 — " + moduleRelPath + ": " + (e instanceof Error ? e.message : String(e)));
1346
+ return refs;
1347
+ }
1348
+ const patterns = [
1349
+ { re: /VerifyResult|TaskContext|GovernanceReport|DeliveryResult/, desc: "结果类型引用" },
1350
+ { re: /main_path_integration/, desc: "main_path_integration 字段" },
1351
+ { re: /summary\s*[:+=]/, desc: "summary 生成" },
1352
+ { re: /console\.|logger\.|log\(/, desc: "日志输出" },
1353
+ ];
1354
+ for (const { re, desc } of patterns) {
1355
+ if (re.test(content))
1356
+ refs.push(`${moduleRelPath}: ${desc}`);
1357
+ }
1358
+ const modBasename = fspath.basename(moduleRelPath, fspath.extname(moduleRelPath));
1359
+ const allFiles = walkDir(projectPath);
1360
+ for (const file of allFiles) {
1361
+ const rel = fspath.relative(projectPath, file).replace(/\\/g, "/");
1362
+ if (normalizeModulePath(rel) === normalizeModulePath(moduleRelPath))
1363
+ continue;
1364
+ if (/\.test\.|\.spec\.|\/tests\//.test(rel))
1365
+ continue;
1366
+ try {
1367
+ const fc = fs.readFileSync(file, "utf-8");
1368
+ if (fc.includes(modBasename) && /result|response|output|report|evidence/.test(fc)) {
1369
+ refs.push(`referenced in ${rel}`);
1370
+ }
1371
+ }
1372
+ catch {
1373
+ continue;
1374
+ }
1375
+ }
1376
+ console.error("[soloForge] 主链路接入: 收集模块可观测性完成 — " + moduleRelPath + " 共 " + refs.length + " 条证据");
1377
+ return refs;
1378
+ }
1379
+ /**
1380
+ * Find integration test files for a module.
1381
+ */
1382
+ function stripComments(source) {
1383
+ let s = source.replace(/\/\/.*$/gm, "");
1384
+ s = s.replace(/\/\*[\s\S]*?\*\//g, "");
1385
+ return s;
1386
+ }
1387
+ /**
1388
+ * Determine if a test file constitutes integration/contract test evidence
1389
+ * for the target module. Uses structural analysis, not basename text matching.
1390
+ *
1391
+ * Integration test: test imports an entry point that can reach the target module.
1392
+ * Contract test: test directly imports the target module AND has real call evidence.
1393
+ * Mere mentions in comments or strings are ignored.
1394
+ */
1395
+ /**
1396
+ * 查找模块的集成测试文件。
1397
+ * @param projectPath - 项目根路径
1398
+ * @param moduleRelPath - 模块相对路径
1399
+ * @returns 集成测试文件路径列表
1400
+ */
1401
+ export function findIntegrationTests(projectPath, moduleRelPath) {
1402
+ console.error("[soloForge] 主链路接入: 查找集成测试 — " + moduleRelPath);
1403
+ const tests = [];
1404
+ const allFiles = walkDir(projectPath);
1405
+ const moduleExt = fspath.extname(moduleRelPath);
1406
+ const normalized = moduleRelPath.replace(/\\/g, "/");
1407
+ const entryPoints = identifyProjectEntryPoints(projectPath);
1408
+ for (const file of allFiles) {
1409
+ const rel = fspath.relative(projectPath, file).replace(/\\/g, "/");
1410
+ if (!/\.test\.|\.spec\.|\/tests?\/|[Tt]est\.(?:ts|tsx|js|jsx|java|kt)|(?:integration|contract)[._-]/i.test(rel))
1411
+ continue;
1412
+ let content;
1413
+ try {
1414
+ content = fs.readFileSync(file, "utf-8");
1415
+ }
1416
+ catch {
1417
+ continue;
1418
+ }
1419
+ const ext = fspath.extname(rel);
1420
+ const codeOnly = stripComments(content);
1421
+ if (ext === ".java" || ext === ".kt") {
1422
+ const targetFqn = computeJavaFqn(normalized, projectPath);
1423
+ if (!targetFqn)
1424
+ continue;
1425
+ if (!matchJavaFqn(codeOnly, targetFqn))
1426
+ continue;
1427
+ const importedNames = extractJavaImportedNames(codeOnly, targetFqn);
1428
+ if (importedNames.length === 0)
1429
+ continue;
1430
+ const callEvidence = detectJavaCallEvidence(codeOnly, importedNames);
1431
+ if (callEvidence.length > 0)
1432
+ tests.push(rel);
1433
+ }
1434
+ else if (ext === ".py") {
1435
+ const targetPyModule = computePythonModulePath(normalized);
1436
+ const imports = extractImportPaths(codeOnly, rel);
1437
+ const hasImport = imports.some((imp) => imp === targetPyModule || imp.endsWith("." + targetPyModule.split(".").pop()));
1438
+ if (!hasImport)
1439
+ continue;
1440
+ const names = extractPythonImportedNames(codeOnly, targetPyModule);
1441
+ const callEvidence = detectPythonCallEvidence(codeOnly, names);
1442
+ if (callEvidence.length > 0)
1443
+ tests.push(rel);
1444
+ }
1445
+ else {
1446
+ // TS/JS: 两种路径
1447
+ // 路径 1: integration test — test imports an entry point that can reach the module
1448
+ const testImports = extractImportPaths(codeOnly, rel);
1449
+ let isIntegrationTest = false;
1450
+ for (const imp of testImports) {
1451
+ if (!imp.startsWith("."))
1452
+ continue;
1453
+ const resolved = resolveImportPath(imp, rel, projectPath);
1454
+ if (!resolved)
1455
+ continue;
1456
+ const epMatch = entryPoints.find((ep) => ep.entry_id === resolved);
1457
+ if (epMatch) {
1458
+ const traces = traceModuleReachability(projectPath, normalized, [epMatch]);
1459
+ if (traces.length > 0) {
1460
+ isIntegrationTest = true;
1461
+ break;
1462
+ }
1463
+ }
1464
+ }
1465
+ if (isIntegrationTest) {
1466
+ tests.push(rel);
1467
+ continue;
1468
+ }
1469
+ // 路径 2: contract test — test directly imports the target module with call evidence
1470
+ const targetNorm = normalizeModulePath(normalized);
1471
+ const importedNames = extractImportedNames(codeOnly, normalized);
1472
+ if (importedNames.length === 0)
1473
+ continue;
1474
+ const callEvidence = detectTsCallEvidence(codeOnly, importedNames);
1475
+ if (callEvidence.length > 0)
1476
+ tests.push(rel);
1477
+ }
1478
+ }
1479
+ console.error("[soloForge] 主链路接入: 查找集成测试完成 — " + moduleRelPath + " 共 " + tests.length + " 个测试");
1480
+ return tests;
1481
+ }
1482
+ /**
1483
+ * Build real MainPathIntegrationContracts from filesystem scanning.
1484
+ * This is the main entry point for integration checking.
1485
+ *
1486
+ * integrated requires BOTH call evidence AND entry_traces.
1487
+ * Import-only (no call) or no entry trace → implemented_not_integrated.
1488
+ */
1489
+ /**
1490
+ * 通过文件系统扫描构建真实的主链路接入契约。
1491
+ * @param projectPath - 项目根路径
1492
+ * @param changedFiles - 变更文件列表
1493
+ * @param config - 扫描配置(可选)
1494
+ * @returns 主链路接入契约列表
1495
+ */
1496
+ export function buildMainPathIntegrationContracts(projectPath, changedFiles, config) {
1497
+ const contracts = [];
1498
+ console.error(`[soloForge] 主链路接入: 开始扫描变更文件 — 共 ${changedFiles.length} 个文件`);
1499
+ const entryPoints = identifyProjectEntryPoints(projectPath);
1500
+ for (const filePath of changedFiles) {
1501
+ const normalized = filePath.replace(/\\/g, "/");
1502
+ const prodCheck = isProductionFile(normalized, config);
1503
+ if (!prodCheck.isProd)
1504
+ continue;
1505
+ console.error("[soloForge] 主链路接入: 扫描生产文件 — " + normalized);
1506
+ const fullPath = fspath.join(projectPath, normalized);
1507
+ if (!fs.existsSync(fullPath)) {
1508
+ console.error("[soloForge] 主链路接入: 文件不存在 — " + normalized);
1509
+ continue;
1510
+ }
1511
+ // 步骤 1: Scan who imports this module
1512
+ const scanResult = scanModuleImporters(projectPath, normalized);
1513
+ // 步骤 2: Trace reachability from entry points
1514
+ const entryTraces = traceModuleReachability(projectPath, normalized, entryPoints);
1515
+ // 步骤 3: Determine integration status
1516
+ // integrated 需要同时满足: 真实调用证据 (production_imports) 和入口链路 (entry_traces)
1517
+ const hasCallEvidence = scanResult.production_imports.length > 0;
1518
+ const hasEntryTrace = entryTraces.length > 0;
1519
+ let status;
1520
+ if (hasCallEvidence && hasEntryTrace) {
1521
+ status = "integrated";
1522
+ }
1523
+ else if (hasCallEvidence && !hasEntryTrace) {
1524
+ // 有调用证据但无入口链路 → 未完全接入
1525
+ status = "implemented_not_integrated";
1526
+ }
1527
+ else if (scanResult.import_only.length > 0) {
1528
+ // 仅被导入从未被调用
1529
+ status = "implemented_not_integrated";
1530
+ }
1531
+ else if (scanResult.barrel_exports.length > 0 || scanResult.registry_declarations.length > 0) {
1532
+ status = "implemented_not_integrated";
1533
+ }
1534
+ else if (scanResult.test_imports.length > 0) {
1535
+ status = "implemented_not_integrated";
1536
+ }
1537
+ else {
1538
+ status = "implemented_not_integrated";
1539
+ }
1540
+ console.error("[soloForge] 主链路接入: 状态判定 — " + normalized + " → " + status);
1541
+ // 步骤 4: Collect observability evidence
1542
+ const observabilityRefs = collectModuleObservability(projectPath, normalized);
1543
+ // 步骤 5: Find integration tests
1544
+ const intTests = findIntegrationTests(projectPath, normalized);
1545
+ contracts.push({
1546
+ module_path: normalized,
1547
+ status,
1548
+ production_imports: scanResult.production_imports,
1549
+ entry_traces: entryTraces,
1550
+ observability_refs: observabilityRefs,
1551
+ integration_tests: intTests,
1552
+ owner: "",
1553
+ });
1554
+ }
1555
+ console.error("[soloForge] 主链路接入: 扫描变更文件完成 — 共 " + contracts.length + " 个契约");
1556
+ return contracts;
1557
+ }
1558
+ /**
1559
+ * Collect all production files across repos and scopes.
1560
+ */
1561
+ /**
1562
+ * 收集所有生产文件。
1563
+ * @param projectPath - 项目根路径
1564
+ * @param config - 扫描配置(可选)
1565
+ * @returns 生产文件路径列表
1566
+ */
1567
+ export function collectAllProductionFiles(projectPath, config) {
1568
+ console.error("[soloForge] 主链路接入: 收集所有生产文件 — " + projectPath);
1569
+ const files = [];
1570
+ const allFiles = walkDir(projectPath);
1571
+ for (const file of allFiles) {
1572
+ const rel = fspath.relative(projectPath, file).replace(/\\/g, "/");
1573
+ const prodCheck = isProductionFile(rel, config);
1574
+ if (prodCheck.isProd) {
1575
+ files.push(rel);
1576
+ }
1577
+ }
1578
+ console.error("[soloForge] 主链路接入: 收集所有生产文件完成 — 共 " + files.length + " 个文件");
1579
+ return files;
1580
+ }
1581
+ //# sourceMappingURL=main_path_integration_contract.js.map