soloforge 1.2.7 → 1.2.9

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 (406) 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/acceptance_templates//345/216/237/345/236/213/350/257/264/346/230/216/346/250/241/347/211/210.md +30 -2
  376. 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
  377. 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
  378. 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
  379. 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
  380. 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
  381. 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
  382. package/templates/knowledge/patterns/core//345/206/263/347/255/226/347/275/221/345/205/263.md +1 -0
  383. 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
  384. 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
  385. 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
  386. 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
  387. package/templates/knowledge/procedures/{Figma → /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 +5 -5
  388. 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
  389. 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
  390. 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
  391. 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
  392. 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
  393. 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
  394. 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
  395. 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
  396. 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
  397. 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
  398. 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
  399. 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
  400. 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
  401. 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
  402. 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
  403. 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
  404. 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
  405. package/templates/knowledge/templates/{review_summary.md → /345/256/241/346/237/245/346/221/230/350/246/201.md} +1 -1
  406. package/templates/config.yaml +0 -53
@@ -1,7 +1,53 @@
1
1
  import Handlebars from "handlebars";
2
+ /**
3
+ * 意图膨胀器 — 将分类结果扩展为包含完整上下文的 AI 执行 prompt。
4
+ *
5
+ * 根据 route_decision.execution_shape 选择不同 prompt 模板:
6
+ * - code_execution_prompt: 代码修改任务
7
+ * - single_artifact_prompt: 单产物生成任务
8
+ * - source_extraction_prompt: 源码/材料提取任务
9
+ * - read_only_analysis_prompt: 只读分析任务
10
+ */
11
+ import path from "node:path";
12
+ import { fileURLToPath } from "node:url";
13
+ import fss from "node:fs";
14
+ import matter from "gray-matter";
2
15
  import { detectConventions } from "./convention_detector.js";
3
- // AI 执行 prompt 模板: 包含任务描述、项目上下文、知识匹配、scope 约束、验收标准
4
- const PROMPT_TEMPLATE = Handlebars.compile(`## 任务
16
+ import { selectPromptTemplate } from "./intent_router.js";
17
+ import { enforceKnowledgeInjectionBoundary, validateInjectionReport, getInjectedEntryIds } from "./knowledge_injection_boundary.js";
18
+ import { createInputMaterial, createIngestionEvidence, buildPromptInjectionPlan, classifyIngestionStatus, } from "./input_material_contract_registry.js";
19
+ import { resolveWorkflow } from "./workflow_contract_registry.js";
20
+ import { createOutputArtifact, getDefaultArtifactPath } from "./artifact_contract_registry.js";
21
+ import { findToolInvocationContractByName } from "./tool_invocation_contract_registry.js";
22
+ import { resolveCurrentProjectConfigReports } from "./config_precedence_contract.js";
23
+ import { evaluatePrivacyGate, redactSensitiveText, } from "./privacy_secret_contract.js";
24
+ import { getTaskLevel, getRequiredPrinciples, getEnforcementLevel, listCorePrinciples } from "./core_engineering_principles.js";
25
+ import { listMechanismLayerMaps } from "./dual_layer_mechanism_registry.js";
26
+ // 配置优先级:委托给 resolveCurrentProjectConfigReports (shared function)
27
+ // ── 产物类型映射 ──
28
+ function mapToArtifactKind(kind) {
29
+ if (kind === "unknown")
30
+ return "custom";
31
+ if (kind === "design_doc")
32
+ return "design_doc";
33
+ if (kind === "api_spec")
34
+ return "api_spec";
35
+ if (kind === "task_breakdown")
36
+ return "task_breakdown";
37
+ if (kind === "root_cause")
38
+ return "root_cause";
39
+ if (kind === "acceptance_checklist")
40
+ return "acceptance_checklist";
41
+ if (kind === "interaction_spec")
42
+ return "interaction_spec";
43
+ if (kind === "domain_model")
44
+ return "domain_model";
45
+ // 其他类型均为合法的 ArtifactKind 值
46
+ return kind;
47
+ }
48
+ // ── Prompt 模板 ──
49
+ // 1. code_execution_prompt: 允许修改业务源码,需要 scope 和验证
50
+ const CODE_EXECUTION_TEMPLATE = Handlebars.compile(`## 任务
5
51
  {{intent}}
6
52
 
7
53
  ## 项目上下文
@@ -58,83 +104,747 @@ const PROMPT_TEMPLATE = Handlebars.compile(`## 任务
58
104
  **注意**: 当前无领域知识匹配,请保守操作,只修改必要文件。
59
105
  {{/if}}
60
106
  `);
107
+ // 2. single_artifact_prompt: 默认不允许修改业务源码,必须有 output_artifact.path
108
+ const SINGLE_ARTIFACT_TEMPLATE = Handlebars.compile(`## 任务
109
+ {{intent}}
110
+
111
+ ## 产物要求
112
+ - 产物类型: {{output_artifact.kind}}
113
+ - 输出路径: {{output_artifact.path}}
114
+ {{#if output_artifact.template}}
115
+ - 参考模板: {{output_artifact.template}}
116
+ {{/if}}
117
+
118
+ ## 项目上下文
119
+ - 技术栈: {{tech_stack}}
120
+ - 产品类型: {{product_profile}}
121
+
122
+ {{#if matched_knowledge}}
123
+ ## 适用知识
124
+ {{#each matched_knowledge}}
125
+ ### {{this.name}}
126
+ {{this.content}}
127
+
128
+ {{/each}}
129
+ {{/if}}
130
+
131
+ ## 约束
132
+ - 默认不允许修改业务源码
133
+ - 只允许写入指定产物路径
134
+ - 产物必须结构完整、证据充分、可交接
135
+
136
+ ## 验收标准
137
+ {{#if acceptance.automated}}
138
+ ### 自动验证
139
+ {{#each acceptance.automated}}
140
+ - [{{this.id}}] {{this.description}}
141
+ {{/each}}
142
+ {{/if}}
143
+ ### 人工验证
144
+ - 产物完整性: 章节齐全,无空白占位
145
+ - 证据充分: 关键结论有引用或出处
146
+ - 可交接性: 下游可基于此产物继续工作
147
+
148
+ {{#if degraded}}
149
+ **注意**: 当前无专用模板,请按同类通用产物结构输出。
150
+ {{/if}}
151
+ `);
152
+ // 3. source_extraction_prompt: 只读输入材料,不允许修改项目源码
153
+ const SOURCE_EXTRACTION_TEMPLATE = Handlebars.compile(`## 任务
154
+ {{intent}}
155
+
156
+ ## 输入材料
157
+ {{#each input_materials}}
158
+ - 类型: {{this.kind}}{{#if this.path}},路径: {{this.path}}{{/if}}{{#if this.ingestion_status}},状态: {{this.ingestion_status}}{{/if}}(只读)
159
+ {{/each}}
160
+
161
+ {{#if input_material_contract_notes}}
162
+ ## 输入材料契约检查
163
+ {{#each input_material_contract_notes}}
164
+ - {{this}}
165
+ {{/each}}
166
+ {{/if}}
167
+
168
+ ## 产物要求
169
+ - 产物类型: {{output_artifact.kind}}
170
+ - 输出路径: {{output_artifact.path}}
171
+ {{#if output_artifact.template}}
172
+ - 参考模板: {{output_artifact.template}}
173
+ {{/if}}
174
+ {{#if pipeline_hint}}
175
+ - 流程提示: {{pipeline_hint}}
176
+ {{/if}}
177
+
178
+ {{#if matched_knowledge}}
179
+ ## 适用知识
180
+ {{#each matched_knowledge}}
181
+ ### {{this.name}}
182
+ {{this.content}}
183
+
184
+ {{/each}}
185
+ {{/if}}
186
+
187
+ ## 约束
188
+ - 输入材料只读,不得修改
189
+ - 不允许修改项目业务源码 (src/)
190
+ - 可将 zip 解压到临时目录读取
191
+ - 源码中无法确认的信息必须标记 [Manual Confirm]
192
+ - 必须标注证据来源(哪个文件/哪段代码)
193
+ - 禁止使用 Figma MCP、浏览器运行态、figma.site、截图或纯 Design 文件补充信息
194
+
195
+ ## 验收标准
196
+ ### 产物完整性
197
+ - 产物结构完整、章节齐全
198
+ - 每条信息有源码出处
199
+ - 缺失信息标记 [Manual Confirm]
200
+
201
+ {{#if degraded}}
202
+ **注意**: 当前无专用模板,请按通用提取产物结构输出。
203
+ {{/if}}
204
+ `);
205
+ // 4. read_only_analysis_prompt: 只读分析,默认不写文件
206
+ const READ_ONLY_ANALYSIS_TEMPLATE = Handlebars.compile(`## 任务
207
+ {{intent}}
208
+
209
+ ## 项目上下文
210
+ - 技术栈: {{tech_stack}}
211
+ - 产品类型: {{product_profile}}
212
+
213
+ {{#if matched_knowledge}}
214
+ ## 适用知识
215
+ {{#each matched_knowledge}}
216
+ ### {{this.name}}
217
+ {{this.content}}
218
+
219
+ {{/each}}
220
+ {{/if}}
221
+
222
+ ## 约束
223
+ - 默认不允许修改业务源码
224
+ - 只读分析当前项目或指定材料
225
+ - 输出结论、证据、风险和建议
226
+ - 默认不写文件,除非明确指定输出路径
227
+
228
+ {{#if output_artifact}}
229
+ ## 输出要求
230
+ - 输出路径: {{output_artifact.path}}
231
+ {{/if}}
232
+
233
+ ## 分析要求
234
+ - 给出明确结论
235
+ - 列出支撑证据
236
+ - 标注风险和假设
237
+ - 给出建议(如有)
238
+ `);
239
+ // 5. verification_only_prompt: 验证命令生成,不修改源码
240
+ const VERIFICATION_ONLY_TEMPLATE = Handlebars.compile(`## 任务
241
+ {{intent}}
242
+
243
+ ## 验证目标
244
+ {{#if relevant_files}}
245
+ ### 相关文件
246
+ {{#each relevant_files}}
247
+ - {{this.path}} ({{this.reason}})
248
+ {{/each}}
249
+ {{/if}}
250
+
251
+ ## 约束
252
+ - 默认不允许修改业务源码
253
+ - 只生成验证命令和检查逻辑
254
+ - 输出验证结果(通过/失败/需人工确认)
255
+
256
+ ## 验证要求
257
+ - 列出具体验证命令
258
+ - 标注预期结果
259
+ - 标注不确定项
260
+ `);
261
+ // 6. direct_answer_prompt: 直接回答,不进入代码执行
262
+ const DIRECT_ANSWER_TEMPLATE = Handlebars.compile(`## 任务
263
+ {{intent}}
264
+
265
+ ## 要求
266
+ - 直接回答用户问题
267
+ - 不修改任何项目文件
268
+ - 给出明确结论和依据
269
+ `);
270
+ /** 保留旧模板名为 CODE_EXECUTION_TEMPLATE 的别名(兼容旧测试) */
271
+ const PROMPT_TEMPLATE = CODE_EXECUTION_TEMPLATE;
272
+ /** 将 PromptInjectionPlan 渲染为 Markdown 段落(统一注入,避免模板内重复) */
273
+ function renderPromptInjectionPlan(plan) {
274
+ const sections = [];
275
+ if (plan.evidence_refs.length > 0) {
276
+ sections.push("## 材料证据引用\n" + plan.evidence_refs.map((r) => "- " + r).join("\n"));
277
+ }
278
+ if (plan.required_summary.length > 0) {
279
+ sections.push("## 必需材料摘要\n" + plan.required_summary.map((s) => "- " + s).join("\n"));
280
+ }
281
+ if (plan.forbidden_notes.length > 0) {
282
+ sections.push("## 禁止/不可用材料\n" + plan.forbidden_notes.map((n) => "- " + n).join("\n"));
283
+ }
284
+ if (plan.manual_confirm_list.length > 0) {
285
+ sections.push("## 人工确认项\n" + plan.manual_confirm_list.map((c) => "- " + c).join("\n"));
286
+ }
287
+ if (plan.allowed_sources.length > 0) {
288
+ sections.push("## 允许的材料来源\n" + plan.allowed_sources.map((s) => "- " + s).join("\n"));
289
+ }
290
+ if (plan.forbidden_sources.length > 0) {
291
+ sections.push("## 禁止的材料来源\n" + plan.forbidden_sources.map((s) => "- " + s).join("\n"));
292
+ }
293
+ return sections.length > 0 ? "---\n\n" + sections.join("\n\n") : "";
294
+ }
295
+ /**
296
+ * 根据执行形态选择 prompt 模板。
297
+ */
298
+ function chooseTemplate(templateName) {
299
+ switch (templateName) {
300
+ case "single_artifact_prompt": return SINGLE_ARTIFACT_TEMPLATE;
301
+ case "source_extraction_prompt": return SOURCE_EXTRACTION_TEMPLATE;
302
+ case "read_only_analysis_prompt": return READ_ONLY_ANALYSIS_TEMPLATE;
303
+ case "verification_only_prompt": return VERIFICATION_ONLY_TEMPLATE;
304
+ case "direct_answer_prompt": return DIRECT_ANSWER_TEMPLATE;
305
+ case "code_execution_prompt":
306
+ default: return CODE_EXECUTION_TEMPLATE;
307
+ }
308
+ }
309
+ /**
310
+ * 解析澄清答案,将路径注入 route_decision.input_materials,
311
+ * 清除已解决的 missing_required_inputs。
312
+ * 返回新的 route_decision(不修改原对象)。
313
+ */
314
+ function resolveClarificationAnswers(decision, intent, answers) {
315
+ const resolved = {
316
+ ...decision,
317
+ input_materials: decision.input_materials.map((m) => ({ ...m })),
318
+ missing_required_inputs: [...decision.missing_required_inputs],
319
+ };
320
+ const addedPaths = [];
321
+ for (const answer of answers) {
322
+ // 提取路径 - absolute paths starting with /
323
+ const absPathPattern = /(?<![^\s])\/[^\s\]]+/g;
324
+ for (const m of answer.matchAll(absPathPattern)) {
325
+ const p = m[0];
326
+ if (p && p.length > 1 && !addedPaths.includes(p)) {
327
+ addedPaths.push(p);
328
+ }
329
+ }
330
+ // 提取相对路径 (word/word.ext 模式)
331
+ const relPathPattern = /[\w][\w.\-]*(?:\/[\w.\-]+)+\.[\w]+/g;
332
+ for (const m of answer.matchAll(relPathPattern)) {
333
+ const p = m[0];
334
+ if (p && !addedPaths.includes(p) && !addedPaths.some((ap) => ap.endsWith("/" + p))) {
335
+ addedPaths.push(p);
336
+ }
337
+ }
338
+ }
339
+ for (const p of addedPaths) {
340
+ if (resolved.input_materials.some((m) => m.path === p))
341
+ continue;
342
+ let kind = "file";
343
+ if (/\.(zip|tar\.gz|gz|rar|7z|jar|war)$/i.test(p))
344
+ kind = "archive";
345
+ else if (/\.log$/i.test(p))
346
+ kind = "log";
347
+ else if (/\.(md|txt|doc|pdf|docx)$/i.test(p))
348
+ kind = "doc";
349
+ else if (/\.(java|py|ts|tsx|js|jsx|go|rs)$/i.test(p))
350
+ kind = "file";
351
+ resolved.input_materials.push({ kind, path: p, required: true });
352
+ }
353
+ // 仅清除路径类型的缺失输入(保留非路径问题如"哪个框架?")
354
+ if (addedPaths.length > 0) {
355
+ resolved.missing_required_inputs = resolved.missing_required_inputs.filter((m) => !/path|路径|目录|文件|folder|directory|file/i.test(m));
356
+ }
357
+ return resolved;
358
+ }
359
+ /**
360
+ * 获取 sf_expand 契约的 next_allowed_tools 和 forbidden_tools。
361
+ */
362
+ function getExpandContractTools() {
363
+ const contract = findToolInvocationContractByName("sf_expand");
364
+ return {
365
+ next_allowed_tools: contract?.default_next_tools ?? [],
366
+ forbidden_tools: contract?.forbidden_next_tools ?? [],
367
+ };
368
+ }
61
369
  /**
62
370
  * 将分类结果扩展为完整的 AI 执行 prompt 和配套元数据。
63
- * @param input - 膨胀输入,包含意图、分类结果、项目配置、知识索引等
64
- * @returns 膨胀结果,包含 prompt / scope / 验收标准 / 执行契约 / 不确定性触发条件
65
371
  */
66
372
  export async function expand(input) {
373
+ console.error("[soloForge] 意图膨胀: 开始扩展,路由=%s", input.route_decision?.route ?? input.classification?.task_type ?? "unknown");
67
374
  const { intent, classification, projectPath, config, knowledgeIndex } = input;
68
- // 1. 查询知识库
375
+ let routeDecision = input.route_decision ?? classification.route_decision;
376
+ const templateName = routeDecision ? selectPromptTemplate(routeDecision) : "code_execution_prompt";
377
+ // 配置优先级解析 — 使用共享函数
378
+ let configResolution;
379
+ try {
380
+ configResolution = await resolveCurrentProjectConfigReports(projectPath);
381
+ }
382
+ catch (e) {
383
+ console.error("[soloForge] 意图扩展: 配置优先级解析失败 —", e);
384
+ configResolution = { reports: [], resolutions: [], warnings: [], entries: [] };
385
+ }
386
+ const configWarnings = configResolution.warnings;
387
+ // 消费澄清答案:解析路径,更新 input_materials,清除已解决的 missing_required_inputs
388
+ if (input.clarificationAnswers && input.clarificationAnswers.length > 0 && routeDecision) {
389
+ routeDecision = resolveClarificationAnswers(routeDecision, intent, input.clarificationAnswers);
390
+ }
391
+ // ── Privacy gate— 提前到所有 early-return 之前 ──
392
+ const privacyGate = evaluatePrivacyGate({
393
+ intent,
394
+ input_materials: input.route_decision?.input_materials?.map((m) => ({ path_or_ref: m.path ?? "" })) ?? [],
395
+ });
396
+ const safeIntent = privacyGate.redacted_text ?? redactSensitiveText(intent, "intent").redacted;
397
+ const safeGoal = redactSensitiveText(intent.slice(0, 200), "intent_goal").redacted;
398
+ // 提前创建产物记录 (在所有 early-return 之前),确保所有路径都携带它
399
+ // task_id 为必需 — block if missing
400
+ let outputArtifactRecord;
401
+ if (routeDecision?.output_artifact && routeDecision.execution_shape !== "none" && routeDecision.execution_shape !== "code_execution") {
402
+ const artifactKind = mapToArtifactKind(routeDecision.output_artifact.kind);
403
+ if (!input.task_id) {
404
+ // task_id 缺失时始终阻止 for artifact routes
405
+ return {
406
+ task_id: "",
407
+ prompt: `## 阻塞:产物缺少 task_id\n\n任务: ${safeIntent}\n\nexpand() 收到 task_id 为空,无法创建产物记录。`,
408
+ scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
409
+ acceptance: { automated: [], manual: [] },
410
+ matched_patterns: [],
411
+ matched_knowledge: [],
412
+ is_legacy_code: false,
413
+ degraded: true,
414
+ contract: {
415
+ goal: safeGoal,
416
+ scope: [],
417
+ constraints: ["task_id 缺失"],
418
+ verification: [],
419
+ stop_conditions: ["task_id 缺失"],
420
+ },
421
+ };
422
+ }
423
+ // 收集源材料引用 from routeDecision.input_materials
424
+ const sourceMaterialRefs = routeDecision.input_materials
425
+ .filter((m) => m.path)
426
+ .map((m) => m.path);
427
+ // 冲突时拒绝 with input.task_id
428
+ if (routeDecision.output_artifact.taskId && routeDecision.output_artifact.taskId !== input.task_id) {
429
+ return {
430
+ task_id: input.task_id,
431
+ prompt: `## Contract Error: task_id 不一致\n\nrouteDecision.taskId=${routeDecision.output_artifact.taskId} !== input.task_id=${input.task_id}`,
432
+ scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
433
+ acceptance: { automated: [], manual: [] },
434
+ matched_patterns: [], matched_knowledge: [],
435
+ is_legacy_code: false, degraded: true,
436
+ contract: { goal: safeGoal, scope: [], constraints: ["task_id 不一致"], verification: [], stop_conditions: ["task_id 不一致"] },
437
+ };
438
+ }
439
+ // 路径始终使用 input.task_id
440
+ outputArtifactRecord = createOutputArtifact({
441
+ kind: artifactKind,
442
+ task_id: input.task_id,
443
+ workflow_id: "pending",
444
+ created_by: "intent_expander",
445
+ path: getDefaultArtifactPath(artifactKind, input.task_id),
446
+ source_material_refs: sourceMaterialRefs,
447
+ });
448
+ }
449
+ // ── 工作流契约解析 ──
450
+ let workflowContract = undefined;
451
+ let workflowGovernanceFindings = [];
452
+ if (routeDecision) {
453
+ workflowContract = resolveWorkflow(routeDecision);
454
+ // 提前绑定 workflow_id to artifact record
455
+ if (workflowContract && outputArtifactRecord) {
456
+ outputArtifactRecord.workflow_id = workflowContract.id;
457
+ }
458
+ console.error("[soloForge] 意图膨胀: 工作流契约已解析,workflow=%s", workflowContract?.id ?? "none");
459
+ if (!workflowContract) {
460
+ return {
461
+ task_id: "",
462
+ prompt: `## 阻塞:无工作流契约\n\n任务: ${safeIntent}\n\nroute="${routeDecision.route}" + execution_shape="${routeDecision.execution_shape}" 没有匹配的工作流契约。\n\n请检查意图路由配置。`,
463
+ scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
464
+ acceptance: { automated: [], manual: [] },
465
+ matched_patterns: [],
466
+ matched_knowledge: [],
467
+ is_legacy_code: false,
468
+ degraded: true,
469
+ workflow_trace: {
470
+ workflow_id: "none",
471
+ route: routeDecision.route,
472
+ execution_shape: routeDecision.execution_shape,
473
+ mutation_allowed: routeDecision.mutation_allowed,
474
+ required_mechanisms: [],
475
+ governance_findings: [{ severity: "hard_fail", rule: "gc-no-workflow", message: `no workflow contract for ${routeDecision.route}+${routeDecision.execution_shape}` }],
476
+ degraded: true,
477
+ state_transition_target: "none",
478
+ },
479
+ contract: {
480
+ goal: safeGoal,
481
+ scope: [],
482
+ constraints: ["无工作流契约"],
483
+ verification: [],
484
+ stop_conditions: ["无工作流契约"],
485
+ },
486
+ output_artifact_record: outputArtifactRecord,
487
+ };
488
+ }
489
+ // mutation_allowed 一致性检查
490
+ if (workflowContract.mutation_allowed !== routeDecision.mutation_allowed) {
491
+ return {
492
+ task_id: "",
493
+ prompt: `## 阻塞:mutation_allowed 不一致\n\n任务: ${safeIntent}\n\n工作流 "${workflowContract.id}" 的 mutation_allowed=${workflowContract.mutation_allowed} 与 route_decision 的 mutation_allowed=${routeDecision.mutation_allowed} 不一致。`,
494
+ scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
495
+ acceptance: { automated: [], manual: [] },
496
+ matched_patterns: [],
497
+ matched_knowledge: [],
498
+ is_legacy_code: false,
499
+ degraded: true,
500
+ workflow_trace: {
501
+ workflow_id: workflowContract.id,
502
+ route: routeDecision.route,
503
+ execution_shape: routeDecision.execution_shape,
504
+ mutation_allowed: workflowContract.mutation_allowed,
505
+ required_mechanisms: workflowContract.required_mechanisms,
506
+ governance_findings: [{ severity: "hard_fail", rule: "gc-mutation-mismatch", message: `mutation_allowed mismatch: workflow=${workflowContract.mutation_allowed} route=${routeDecision.mutation_allowed}` }],
507
+ degraded: true,
508
+ state_transition_target: "none",
509
+ },
510
+ contract: {
511
+ goal: safeGoal,
512
+ scope: [],
513
+ constraints: ["mutation_allowed 不一致"],
514
+ verification: [],
515
+ stop_conditions: ["mutation_allowed 不一致"],
516
+ },
517
+ output_artifact_record: outputArtifactRecord,
518
+ };
519
+ }
520
+ // prompt_template 一致性检查
521
+ if (workflowContract.prompt_template !== templateName) {
522
+ return {
523
+ task_id: "",
524
+ prompt: `## 阻塞:prompt_template 不一致\n\n任务: ${safeIntent}\n\n工作流 "${workflowContract.id}" 要求 prompt_template="${workflowContract.prompt_template}",但 selectPromptTemplate 返回 "${templateName}"。`,
525
+ scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
526
+ acceptance: { automated: [], manual: [] },
527
+ matched_patterns: [],
528
+ matched_knowledge: [],
529
+ is_legacy_code: false,
530
+ degraded: true,
531
+ workflow_trace: {
532
+ workflow_id: workflowContract.id,
533
+ route: routeDecision.route,
534
+ execution_shape: routeDecision.execution_shape,
535
+ mutation_allowed: workflowContract.mutation_allowed,
536
+ required_mechanisms: workflowContract.required_mechanisms,
537
+ governance_findings: [{ severity: "hard_fail", rule: "gc-prompt-template-mismatch", message: `prompt_template mismatch: workflow="${workflowContract.prompt_template}" selected="${templateName}"` }],
538
+ degraded: true,
539
+ state_transition_target: "none",
540
+ },
541
+ contract: {
542
+ goal: safeGoal,
543
+ scope: [],
544
+ constraints: ["prompt_template 不一致"],
545
+ verification: [],
546
+ stop_conditions: ["prompt_template 不一致"],
547
+ },
548
+ };
549
+ }
550
+ }
551
+ // 缺少必需输入时返回澄清,不生成执行 prompt(在 workflow resolution 之后)
552
+ if (routeDecision && routeDecision.missing_required_inputs.length > 0) {
553
+ console.error("[soloForge] 意图膨胀: 缺少必需输入 %d 项,返回澄清请求", routeDecision.missing_required_inputs.length);
554
+ return buildClarificationResult(intent, routeDecision, config, workflowContract, safeIntent, safeGoal);
555
+ }
556
+ // ── 输入材料契约 ──
557
+ let inputMaterials;
558
+ let ingestionEvidences;
559
+ let promptInjectionPlan;
560
+ const contractNotes = [];
561
+ if (routeDecision && routeDecision.input_materials.length > 0) {
562
+ const pathMaterials = routeDecision.input_materials.filter((m) => m.path);
563
+ if (pathMaterials.length > 0) {
564
+ const materials = pathMaterials.map((m) => createInputMaterial({ path_or_ref: m.path }));
565
+ inputMaterials = materials;
566
+ ingestionEvidences = materials.map((m) => createIngestionEvidence(m));
567
+ for (const m of materials) {
568
+ if (m.access_mode === "forbidden") {
569
+ contractNotes.push(`[FORBIDDEN] ${m.path_or_ref}: 禁止读取`);
570
+ }
571
+ else if (m.trust_level === "external_unverified" || m.trust_level === "derived" || m.trust_level === "ai_generated") {
572
+ contractNotes.push(`[Manual Confirm] ${m.path_or_ref}: 信任等级=${m.trust_level}`);
573
+ }
574
+ }
575
+ promptInjectionPlan = buildPromptInjectionPlan(materials, ingestionEvidences);
576
+ }
577
+ }
578
+ // ── 输入材料硬阻断──
579
+ if (inputMaterials) {
580
+ const forbiddenMaterials = inputMaterials.filter((m) => m.access_mode === "forbidden");
581
+ if (forbiddenMaterials.length > 0) {
582
+ const forbiddenPaths = forbiddenMaterials.map((m) => m.path_or_ref).join(", ");
583
+ console.error("[soloForge] 意图膨胀: 输入材料禁止读取: %s", forbiddenPaths);
584
+ return {
585
+ task_id: "",
586
+ prompt: `## 阻塞:输入材料禁止读取\n\n任务: ${safeIntent}\n\n以下材料路径触发禁止规则,不得读取:\n${forbiddenMaterials.map((m) => " - " + m.path_or_ref).join("\\n")}\n\n请移除这些材料后重新调用。`,
587
+ scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
588
+ acceptance: { automated: [], manual: [] },
589
+ matched_patterns: [],
590
+ matched_knowledge: [],
591
+ is_legacy_code: false,
592
+ degraded: true,
593
+ input_materials: inputMaterials,
594
+ ingestion_evidences: ingestionEvidences,
595
+ prompt_injection_plan: promptInjectionPlan,
596
+ contract: {
597
+ goal: safeGoal,
598
+ scope: [],
599
+ constraints: ["输入材料包含禁止路径"],
600
+ verification: [],
601
+ stop_conditions: [],
602
+ },
603
+ output_artifact_record: outputArtifactRecord,
604
+ workflow_trace: workflowContract ? {
605
+ workflow_id: workflowContract.id,
606
+ route: routeDecision.route,
607
+ execution_shape: routeDecision.execution_shape,
608
+ mutation_allowed: workflowContract.mutation_allowed,
609
+ required_mechanisms: workflowContract.required_mechanisms,
610
+ governance_findings: [{ severity: "hard_fail", rule: "gc-forbidden-material", message: `材料禁止读取: ${forbiddenPaths}` }],
611
+ degraded: true,
612
+ state_transition_target: "none",
613
+ } : undefined,
614
+ };
615
+ }
616
+ const confirmations = input.input_material_confirmations ?? [];
617
+ const requiresConfirmationMaterials = inputMaterials.filter((m) => m.access_mode !== "forbidden"
618
+ && classifyIngestionStatus(m.path_or_ref) === "requires_confirmation"
619
+ && !confirmations.includes(m.path_or_ref));
620
+ if (requiresConfirmationMaterials.length > 0) {
621
+ const confirmPaths = requiresConfirmationMaterials.map((m) => m.path_or_ref);
622
+ return {
623
+ task_id: "",
624
+ prompt: `## 澄清请求\n\n任务: ${safeIntent}\n\n以下输入材料需要人工确认后才能使用:\n${confirmPaths.map((p) => " - " + p).join("\\n")}\n\n请确认以上材料安全性后,通过 input_material_confirmations 参数重新调用。`,
625
+ scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
626
+ acceptance: { automated: [], manual: [] },
627
+ matched_patterns: [],
628
+ matched_knowledge: [],
629
+ is_legacy_code: false,
630
+ degraded: true,
631
+ input_materials: inputMaterials,
632
+ ingestion_evidences: ingestionEvidences,
633
+ prompt_injection_plan: promptInjectionPlan,
634
+ contract: {
635
+ goal: safeGoal,
636
+ scope: [],
637
+ constraints: ["输入材料需要确认"],
638
+ verification: [],
639
+ stop_conditions: [],
640
+ },
641
+ output_artifact_record: outputArtifactRecord,
642
+ workflow_trace: workflowContract ? {
643
+ workflow_id: workflowContract.id,
644
+ route: routeDecision.route,
645
+ execution_shape: routeDecision.execution_shape,
646
+ mutation_allowed: workflowContract.mutation_allowed,
647
+ required_mechanisms: workflowContract.required_mechanisms,
648
+ governance_findings: [],
649
+ degraded: true,
650
+ state_transition_target: "clarifying",
651
+ } : undefined,
652
+ };
653
+ }
654
+ }
655
+ // ── 隐私硬阻断门禁 (privacyGate 已在顶部计算) ──
656
+ const privacyLabels = privacyGate.labels;
657
+ const privacyRedactions = privacyGate.redaction_records;
658
+ const privacyFindings = privacyGate.findings;
659
+ // 硬阻断: 意图或输入材料中包含密钥/凭证
660
+ if (privacyGate.hard_fail) {
661
+ console.error("[soloForge] 意图膨胀: 隐私策略阻断,包含 %d 个禁止来源", privacyGate.blocked_sources.length);
662
+ return {
663
+ task_id: "",
664
+ prompt: [
665
+ "## 阻塞:隐私/敏感信息策略",
666
+ "",
667
+ "任务内容已因隐私策略脱敏",
668
+ "",
669
+ "隐私门禁触发 hard_fail,以下来源包含禁止级别的敏感信息:",
670
+ ...privacyGate.blocked_sources.map((s) => " - " + s),
671
+ "",
672
+ "治理发现:",
673
+ ...privacyGate.findings.map((f) => ` [${f.severity}] ${f.rule}: ${f.message}`),
674
+ "",
675
+ "请移除敏感信息后重新调用。",
676
+ ].join("\n"),
677
+ scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
678
+ acceptance: { automated: [], manual: [] },
679
+ matched_patterns: [],
680
+ matched_knowledge: [],
681
+ is_legacy_code: false,
682
+ degraded: true,
683
+ sensitivity_labels: privacyLabels.length > 0 ? privacyLabels : undefined,
684
+ redaction_records: privacyRedactions.length > 0 ? privacyRedactions : undefined,
685
+ privacy_findings: privacyFindings.length > 0 ? privacyFindings : undefined,
686
+ contract: {
687
+ goal: safeGoal,
688
+ scope: [],
689
+ constraints: ["隐私/敏感信息策略阻断"],
690
+ verification: [],
691
+ stop_conditions: ["隐私/敏感信息策略阻断"],
692
+ },
693
+ input_materials: inputMaterials,
694
+ ingestion_evidences: ingestionEvidences,
695
+ prompt_injection_plan: promptInjectionPlan,
696
+ output_artifact_record: outputArtifactRecord,
697
+ workflow_trace: workflowContract ? {
698
+ workflow_id: workflowContract.id,
699
+ route: routeDecision.route,
700
+ execution_shape: routeDecision.execution_shape,
701
+ mutation_allowed: workflowContract.mutation_allowed,
702
+ required_mechanisms: workflowContract.required_mechanisms,
703
+ governance_findings: privacyFindings.map((f) => ({ severity: f.severity, rule: f.rule, message: f.message })),
704
+ degraded: true,
705
+ state_transition_target: "none",
706
+ } : undefined,
707
+ };
708
+ }
709
+ // 1. 查询知识库(路由驱动匹配)
69
710
  const scopeFilters = classification.affected_repos.length > 0
70
711
  ? classification.affected_repos
71
712
  : ["shared"];
72
- // 分级运行: quick_fix 模式减少知识匹配量以控制 Token 成本
73
713
  const knowledgeLimit = classification.strategy === "quick_fix" ? 2 : 5;
74
714
  const skipHeavyAnalysis = classification.strategy === "quick_fix";
75
- const matchedEntries = knowledgeIndex.query({
76
- scope: scopeFilters,
77
- products: [config.product_profile],
78
- keywords: extractKeywords(intent),
79
- limit: knowledgeLimit,
80
- });
81
- // 记录知识使用
82
- if (matchedEntries.length > 0) {
83
- knowledgeIndex.markUsed(matchedEntries.map((e) => e.id));
715
+ const matchedEntries = queryKnowledgeForRoute(knowledgeIndex, intent, scopeFilters, config, routeDecision, knowledgeLimit);
716
+ // 知识注入边界( 三道门过滤)
717
+ const productFilters = [config.product_profile];
718
+ const injectionReport = enforceKnowledgeInjectionBoundary(matchedEntries, routeDecision, scopeFilters, undefined, knowledgeLimit, productFilters);
719
+ const injectedIds = new Set(getInjectedEntryIds(injectionReport));
720
+ const filteredEntries = matchedEntries.filter((e) => injectedIds.has(e.id));
721
+ if (filteredEntries.length > 0) {
722
+ knowledgeIndex.markUsed(filteredEntries.map((e) => e.id));
723
+ }
724
+ // 治理校验:validateInjectionReport
725
+ const governanceFindings = validateInjectionReport(injectionReport);
726
+ const hardFails = governanceFindings.filter((f) => f.severity === "hard_fail");
727
+ const hasMissingRequiredKnowledge = injectionReport.missing_required_knowledge && injectionReport.missing_required_knowledge.length > 0;
728
+ // 存储治理发现 in report
729
+ injectionReport.governance_findings = governanceFindings;
730
+ const degraded = filteredEntries.length === 0 && injectionReport.injected_required.length === 0;
731
+ // 任何 hard_fail 都阻止 from validateInjectionReport — not just missing_required_knowledge
732
+ if (hardFails.length > 0) {
733
+ console.error("[soloForge] 意图膨胀: 注入校验失败,%d 个 hard_fail", hardFails.length);
734
+ const failMessages = hardFails.map((f) => f.message).join("\n");
735
+ const missingDesc = hasMissingRequiredKnowledge
736
+ ? injectionReport.missing_required_knowledge.map((m) => m.reason).join("\n")
737
+ : "";
738
+ const missingSection = missingDesc ? `\n\n缺少的必需知识:\n${missingDesc}` : "";
739
+ return {
740
+ task_id: "",
741
+ prompt: `## 阻塞:注入校验失败\n\n任务: ${safeIntent}\n\n以下硬性校验未通过:\n${failMessages}${missingSection}\n\n请修正后重新调用。`,
742
+ scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
743
+ acceptance: { automated: [], manual: [] },
744
+ matched_patterns: [],
745
+ matched_knowledge: [],
746
+ is_legacy_code: false,
747
+ degraded: true,
748
+ injection_report: injectionReport,
749
+ input_materials: inputMaterials,
750
+ ingestion_evidences: ingestionEvidences,
751
+ prompt_injection_plan: promptInjectionPlan,
752
+ contract: {
753
+ goal: safeGoal,
754
+ scope: [],
755
+ constraints: ["注入校验失败,等待修正"],
756
+ verification: [],
757
+ stop_conditions: ["注入校验失败"],
758
+ },
759
+ output_artifact_record: outputArtifactRecord,
760
+ workflow_trace: workflowContract ? {
761
+ workflow_id: workflowContract.id,
762
+ route: routeDecision?.route ?? "",
763
+ execution_shape: routeDecision?.execution_shape ?? "",
764
+ mutation_allowed: workflowContract.mutation_allowed,
765
+ required_mechanisms: workflowContract.required_mechanisms,
766
+ governance_findings: workflowGovernanceFindings,
767
+ degraded: true,
768
+ state_transition_target: "none",
769
+ } : undefined,
770
+ };
84
771
  }
85
- const degraded = matchedEntries.length === 0;
86
- // 2. 检测遗留惯例(quick_fix 跳过以节省 Token)
772
+ // 2. 检测遗留惯例(只对 code_execution 执行)
87
773
  const legacyConventions = [];
88
774
  let isLegacyCode = false;
89
- if (!skipHeavyAnalysis && !degraded && classification.affected_repos.length > 0) {
775
+ if (templateName === "code_execution_prompt" && !skipHeavyAnalysis && !degraded && classification.affected_repos.length > 0) {
90
776
  try {
91
777
  const repoDirs = classification.affected_repos
92
778
  .map((r) => config.repos.find((repo) => repo.name === r)?.path)
93
779
  .filter(Boolean);
94
- // 检查仓库中第一个已存在文件的惯例
95
780
  const conventions = await detectConventions(repoDirs.map((d) => `${d}/src`).slice(0, 3), projectPath, config.conventions_file);
96
781
  if (conventions.length > 0) {
97
782
  isLegacyCode = true;
98
783
  legacyConventions.push(...conventions.map((c) => c.convention));
99
784
  }
100
785
  }
101
- catch {
786
+ catch (e) {
787
+ console.error("[soloForge] 意图扩展: 惯例检测失败 —", e);
102
788
  // 惯例检测为尽力而为
103
789
  }
104
790
  }
105
- // 3. 确定 scope
106
- const scope = resolveScope(config, classification, degraded);
791
+ // 3. 确定 scope(非代码任务使用简化 scope)
792
+ const scope = resolveScope(config, classification, degraded, routeDecision);
107
793
  // 4. 生成验收标准
108
- const acceptance = generateAcceptance(intent, classification, matchedEntries, config, degraded);
794
+ const acceptance = generateAcceptance(intent, classification, filteredEntries, config, degraded, routeDecision);
109
795
  // 5. 组装 prompt
110
796
  const techStack = buildTechStackLabel(config);
111
- let prompt = PROMPT_TEMPLATE({
112
- intent,
113
- tech_stack: techStack,
114
- product_profile: config.product_profile,
115
- affected_repos: classification.affected_repos.join(", "),
116
- matched_knowledge: matchedEntries.map((e) => ({
117
- name: e.name,
118
- content: e.body || e.when,
119
- })),
120
- relevant_files: scope.allowed_paths.slice(0, 10).map((p) => ({ path: p, reason: "scope 允许路径" })),
121
- is_legacy_code: isLegacyCode,
122
- legacy_conventions: legacyConventions,
123
- scope: {
124
- allowed_paths: scope.allowed_paths.join(", "),
125
- new_files_allowed: scope.new_files_allowed,
126
- new_file_patterns: scope.new_file_patterns?.join(", "),
127
- },
128
- acceptance,
129
- degraded,
130
- });
131
- // 5.1 注入计划阶段上下文(P1: AI 唯一执行者, P2: 模板是护栏, P3: 产物系统)
797
+ const template = chooseTemplate(templateName);
798
+ const templateData = buildTemplateData(safeIntent, techStack, config, classification, scope, filteredEntries, legacyConventions, isLegacyCode, acceptance, degraded, routeDecision);
799
+ if (promptInjectionPlan)
800
+ templateData.prompt_injection_plan = promptInjectionPlan;
801
+ // ── 双层机制模板注入( 路由/状态过滤) ──
802
+ const dlMechanisms = listMechanismLayerMaps();
803
+ const currentRoute = routeDecision?.route ?? "";
804
+ const currentWorkflow = workflowContract?.id ?? "";
805
+ const dlRules = [];
806
+ for (const mech of dlMechanisms) {
807
+ // 仅 dual_layer_enforced or experimental_dual_layer mechanisms inject
808
+ if (mech.status !== "dual_layer_enforced" && mech.status !== "experimental_dual_layer")
809
+ continue;
810
+ // 路由必须匹配 mechanism's injected_routes
811
+ if (mech.injected_routes && mech.injected_routes.length > 0 && currentRoute) {
812
+ if (!mech.injected_routes.includes(currentRoute))
813
+ continue;
814
+ }
815
+ // 工作流必须匹配 mechanism's injected_workflows
816
+ if (mech.injected_workflows && mech.injected_workflows.length > 0 && currentWorkflow) {
817
+ if (!mech.injected_workflows.includes(currentWorkflow))
818
+ continue;
819
+ }
820
+ // 仅注入必需资产; supporting are handled by knowledge injection boundary
821
+ const requiredAssets = mech.template_assets.filter((ta) => ta.consumption_mode === "required");
822
+ for (const ra of requiredAssets) {
823
+ try {
824
+ const content = fss.readFileSync(ra.path, "utf-8").trim();
825
+ if (content)
826
+ dlRules.push(`[${mech.mechanism_name}] ${content}`);
827
+ }
828
+ catch (e) {
829
+ console.error("[soloForge] 意图扩展: 双层机制模板加载失败 —", e);
830
+ }
831
+ }
832
+ }
833
+ if (dlRules.length > 0) {
834
+ templateData.dual_layer_rules = dlRules;
835
+ const existing = templateData.matched_knowledge;
836
+ if (existing) {
837
+ existing.push({ name: "强制机制规则(双层注入)", content: dlRules.join("\n\n") });
838
+ }
839
+ }
840
+ let prompt = template(templateData);
841
+ console.error("[soloForge] 意图膨胀: Prompt 模板渲染完成,模板=%s", templateName);
842
+ // 5.1 注入计划阶段上下文
132
843
  if (input.plan_context) {
133
844
  prompt = injectPlanContext(prompt, input.plan_context, knowledgeIndex);
134
845
  }
135
- // 6. 使用计数已通过 markUsed 更新,无需重复递增
136
846
  // 7. 生成执行契约(能力 1)
137
- const contract = buildExecutionContract(intent, classification, scope, acceptance);
847
+ const contract = buildExecutionContract(safeIntent, classification, scope, acceptance);
138
848
  // 8. 生成不确定性触发条件(quick_fix 跳过)
139
849
  const uncertaintyTriggers = skipHeavyAnalysis
140
850
  ? []
@@ -143,12 +853,12 @@ export async function expand(input) {
143
853
  const breakerResult = checkCircuitBreaker({
144
854
  intent,
145
855
  classification,
146
- matchedEntries,
856
+ matchedEntries: filteredEntries,
147
857
  degraded,
148
858
  });
149
- // 熔断触发时: 注入头脑风暴 prompt,不阻止流程但标记 tripped
150
859
  let circuitBreakerOutput;
151
860
  if (breakerResult.tripped) {
861
+ console.error("[soloForge] 意图膨胀: 意图熔断触发,置信度=%.2f", breakerResult.confidence);
152
862
  circuitBreakerOutput = breakerResult;
153
863
  prompt += `
154
864
 
@@ -167,38 +877,365 @@ ${breakerResult.brainstorm.blind_spots.map((s) => `- ${s}`).join("\n")}
167
877
  ### 【闭环逼问】
168
878
  ${breakerResult.brainstorm.decision_questions.map((q, i) => `${i + 1}. ${q.question}\n A) ${q.option_a}\n B) ${q.option_b}`).join("\n\n")}
169
879
 
170
- **注意**: 请等待人类决策后再输出执行代码。
880
+ **注意**: ${routeDecision?.execution_shape === "code_execution"
881
+ ? "请等待人类决策后再输出执行代码。"
882
+ : "请先补齐阻塞输入,或在产物中标记 [Manual Confirm] 后再生成产物。"}
171
883
  `;
172
884
  }
885
+ const expandTools = getExpandContractTools();
886
+ if (contractNotes.length > 0) {
887
+ prompt += "\n\n---\n\n## 输入材料契约检查\n" + contractNotes.join("\n");
888
+ }
889
+ // 追加配置优先级警告 to prompt
890
+ if (configWarnings.length > 0) {
891
+ prompt += "\n\n---\n\n## 配置优先级警告\n" + configWarnings.join("\n");
892
+ }
893
+ // 核心工程执行原则注入
894
+ const coreTaskLevel = getTaskLevel(routeDecision?.route, routeDecision?.execution_shape);
895
+ const coreRequiredPrinciples = getRequiredPrinciples(coreTaskLevel);
896
+ if (coreRequiredPrinciples.length > 0) {
897
+ const principleLines = listCorePrinciples()
898
+ .filter((p) => getEnforcementLevel(p.id, coreTaskLevel) !== "not_applicable")
899
+ .map((p) => {
900
+ const level = getEnforcementLevel(p.id, coreTaskLevel);
901
+ const tag = level === "required" ? "[REQUIRED]" : "[advisory]";
902
+ return `- **${tag} ${p.name} (${p.chinese_name})**: ${p.rule}`;
903
+ });
904
+ prompt += "\n\n---\n\n## 核心工程执行原则 (任务等级: " + coreTaskLevel + ")\n" + principleLines.join("\n");
905
+ prompt += "\n\n> 以上原则中 [REQUIRED] 为硬性要求,违反将导致验证失败。[advisory] 为建议性要求。";
906
+ }
907
+ // 注入 prompt_injection_plan 段落 into prompt (unified for all routes)
908
+ if (promptInjectionPlan) {
909
+ const rendered = renderPromptInjectionPlan(promptInjectionPlan);
910
+ if (rendered) {
911
+ prompt += "\n\n" + rendered;
912
+ }
913
+ }
914
+ // 用真实引用丰富产物 before returning
915
+ if (outputArtifactRecord) {
916
+ // 绑定知识引用 from matched knowledge entries
917
+ outputArtifactRecord.knowledge_refs = filteredEntries.map((e) => e.id);
918
+ // 绑定摄取证据引用
919
+ if (ingestionEvidences && ingestionEvidences.length > 0) {
920
+ outputArtifactRecord.evidence_refs = ingestionEvidences
921
+ .filter((ie) => ie.access_mode !== "forbidden")
922
+ .map((ie) => `ingestion:${ie.material_id}:${ie.source_ref}`);
923
+ }
924
+ // 解析 workflow_id from workflow contract
925
+ if (workflowContract) {
926
+ outputArtifactRecord.workflow_id = workflowContract.id;
927
+ }
928
+ }
929
+ console.error("[soloForge] 意图膨胀: 扩展完成,degraded=%s, 匹配知识=%d 条", degraded ? "true" : "false", filteredEntries.length);
173
930
  return {
174
- task_id: "", // 由调用方填充
931
+ task_id: "",
175
932
  prompt,
176
933
  scope,
177
934
  acceptance,
178
- matched_patterns: matchedEntries.map((e) => e.name),
179
- matched_knowledge: matchedEntries.map((e) => e.name),
935
+ matched_patterns: filteredEntries.map((e) => e.name),
936
+ matched_knowledge: filteredEntries.map((e) => e.name),
937
+ injection_report: injectionReport,
180
938
  is_legacy_code: isLegacyCode,
181
939
  legacy_conventions: legacyConventions.length > 0 ? legacyConventions : undefined,
182
940
  degraded,
183
941
  contract,
184
942
  uncertainty_triggers: uncertaintyTriggers.length > 0 ? uncertaintyTriggers : undefined,
185
943
  circuit_breaker: circuitBreakerOutput,
944
+ next_allowed_tools: expandTools.next_allowed_tools,
945
+ forbidden_tools: expandTools.forbidden_tools,
946
+ input_materials: inputMaterials,
947
+ ingestion_evidences: ingestionEvidences,
948
+ prompt_injection_plan: promptInjectionPlan,
949
+ output_artifact_record: outputArtifactRecord,
950
+ sensitivity_labels: privacyLabels.length > 0 ? privacyLabels : undefined,
951
+ redaction_records: privacyRedactions.length > 0 ? privacyRedactions : undefined,
952
+ privacy_findings: privacyFindings.length > 0 ? privacyFindings : undefined,
953
+ config_resolution_reports: configResolution.reports.length > 0 ? configResolution.reports : undefined,
954
+ workflow_trace: workflowContract ? {
955
+ workflow_id: workflowContract.id,
956
+ route: routeDecision?.route ?? "",
957
+ execution_shape: routeDecision?.execution_shape ?? "",
958
+ mutation_allowed: workflowContract.mutation_allowed,
959
+ required_mechanisms: workflowContract.required_mechanisms,
960
+ governance_findings: workflowGovernanceFindings,
961
+ degraded,
962
+ state_transition_target: workflowContract.allowed_state_transitions[0] ?? "none",
963
+ checked_items: buildCheckedItems(workflowContract, routeDecision),
964
+ } : undefined,
965
+ };
966
+ }
967
+ function buildCheckedItems(contract, routeDecision) {
968
+ const items = [
969
+ "workflow_resolved",
970
+ "mutation_allowed_checked",
971
+ "prompt_template_checked",
972
+ "required_mechanisms_declared",
973
+ ];
974
+ if (routeDecision && !routeDecision.mutation_allowed) {
975
+ items.push("read_only_scope_checked");
976
+ }
977
+ return items;
978
+ }
979
+ /**
980
+ * 缺少必需输入时返回澄清结果(不生成执行 prompt)。
981
+ */
982
+ function buildClarificationResult(intent, routeDecision, config, workflowContract, safeIntent, safeGoal) {
983
+ const clarification = routeDecision.missing_required_inputs.join("\n");
984
+ return {
985
+ task_id: "",
986
+ prompt: `## 澄清请求\n\n任务: ${safeIntent}\n\n缺少必需输入:\n${clarification}\n\n请补充以上信息后重新调用。`,
987
+ scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
988
+ acceptance: { automated: [], manual: [] },
989
+ matched_patterns: [],
990
+ matched_knowledge: [],
991
+ is_legacy_code: false,
992
+ degraded: true,
993
+ contract: {
994
+ goal: safeGoal,
995
+ scope: [],
996
+ constraints: ["缺少必需输入,等待澄清"],
997
+ verification: [],
998
+ stop_conditions: [],
999
+ },
1000
+ workflow_trace: workflowContract ? {
1001
+ workflow_id: workflowContract.id,
1002
+ route: routeDecision.route,
1003
+ execution_shape: routeDecision.execution_shape,
1004
+ mutation_allowed: workflowContract.mutation_allowed,
1005
+ required_mechanisms: workflowContract.required_mechanisms,
1006
+ governance_findings: [],
1007
+ degraded: true,
1008
+ state_transition_target: "clarifying",
1009
+ } : undefined,
1010
+ };
1011
+ }
1012
+ /**
1013
+ * 根据 pipeline_hint 名称加载内置流程模板。
1014
+ */
1015
+ function loadBuiltinByPipeline(pipelineName) {
1016
+ const entries = [];
1017
+ // pipeline_hint 格式: source-prototype-to-delivery:step-1 → 找源码原型交付流程.md
1018
+ const nameToTemplate = {
1019
+ "source-prototype-to-delivery": "源码原型交付流程.md",
1020
+ };
1021
+ const templateFile = nameToTemplate[pipelineName];
1022
+ if (templateFile) {
1023
+ const entry = loadBuiltinTemplate(templateFile, "procedures");
1024
+ if (entry)
1025
+ entries.push(entry);
1026
+ }
1027
+ return entries;
1028
+ }
1029
+ /** 包内模板知识库根目录 */
1030
+ function getTemplatesRoot() {
1031
+ const thisDir = path.dirname(fileURLToPath(import.meta.url));
1032
+ return path.resolve(thisDir, "..", "..", "templates", "knowledge");
1033
+ }
1034
+ /**
1035
+ * 当知识索引中没有找到内置模板时,从 templates/knowledge/ 加载为 KnowledgeEntry。
1036
+ * 只加载指定名称的文件。
1037
+ */
1038
+ function loadBuiltinTemplate(fileName, subDir) {
1039
+ const templatesRoot = getTemplatesRoot();
1040
+ const safeName = path.basename(fileName); // basename 防止路径穿越
1041
+ const filePath = path.join(templatesRoot, subDir, safeName);
1042
+ try {
1043
+ if (!fss.existsSync(filePath))
1044
+ return null;
1045
+ const raw = fss.readFileSync(filePath, "utf-8");
1046
+ const { data, content: body } = matter(raw);
1047
+ const name = data.name || path.basename(fileName, ".md");
1048
+ const type = inferTypeFromSubDir(subDir);
1049
+ return {
1050
+ id: `builtin-${name}`,
1051
+ file_path: filePath,
1052
+ name,
1053
+ type,
1054
+ when: data.when || "",
1055
+ body,
1056
+ scope: data.scope || ["shared"],
1057
+ products: data.products || ["*"],
1058
+ tech_stack: data.tech_stack,
1059
+ created_at: data.created_at || new Date().toISOString().split("T")[0],
1060
+ updated_at: data.updated_at || new Date().toISOString().split("T")[0],
1061
+ usage_count: 0,
1062
+ confidence: data.confidence ?? 1.0,
1063
+ status: "active",
1064
+ };
1065
+ }
1066
+ catch (e) {
1067
+ console.error("[soloForge] 意图扩展: 内置模板加载失败 —", e);
1068
+ return null;
1069
+ }
1070
+ }
1071
+ function inferTypeFromSubDir(subDir) {
1072
+ if (subDir.includes("procedures"))
1073
+ return "pipeline_procedure";
1074
+ if (subDir.includes("acceptance_templates"))
1075
+ return "acceptance_template";
1076
+ if (subDir.includes("review_rules"))
1077
+ return "review_rule";
1078
+ if (subDir.includes("domain"))
1079
+ return "domain";
1080
+ return "pattern";
1081
+ }
1082
+ /**
1083
+ * 路由驱动的知识匹配。
1084
+ * 优先使用 pipeline_hint、output_artifact.kind、route + execution_shape,
1085
+ * 降级为同类型通用产物 prompt,不退化成编码 prompt。
1086
+ */
1087
+ function queryKnowledgeForRoute(knowledgeIndex, intent, scopeFilters, config, routeDecision, limit) {
1088
+ if (!routeDecision) {
1089
+ // 无 route_decision 时回退到旧逻辑
1090
+ return knowledgeIndex.query({
1091
+ scope: scopeFilters,
1092
+ products: [config.product_profile],
1093
+ keywords: extractKeywords(intent),
1094
+ limit,
1095
+ });
1096
+ }
1097
+ const seen = new Set();
1098
+ const results = [];
1099
+ function addEntries(entries) {
1100
+ for (const e of entries) {
1101
+ if (!seen.has(e.id)) {
1102
+ seen.add(e.id);
1103
+ results.push(e);
1104
+ }
1105
+ }
1106
+ }
1107
+ // 优先级 1: pipeline_hint 精确匹配(不提前 return)
1108
+ if (routeDecision.pipeline_hint) {
1109
+ const pipelineName = routeDecision.pipeline_hint.split(":")[0];
1110
+ const pipelineResults = knowledgeIndex.query({
1111
+ scope: scopeFilters,
1112
+ products: [config.product_profile],
1113
+ type: "pipeline_procedure",
1114
+ keywords: extractKeywords(pipelineName),
1115
+ limit: 3,
1116
+ });
1117
+ addEntries(pipelineResults);
1118
+ // 内置模板回退: pipeline_hint 名称未命中时从 templates/knowledge/ 加载
1119
+ if (pipelineResults.length === 0) {
1120
+ const builtin = loadBuiltinByPipeline(pipelineName);
1121
+ if (builtin)
1122
+ addEntries(builtin);
1123
+ }
1124
+ }
1125
+ // 优先级 2: output_artifact.kind 映射 acceptance_template(不提前 return)
1126
+ if (routeDecision.output_artifact?.kind) {
1127
+ // 先按 template 文件名精确匹配
1128
+ const templateName = routeDecision.output_artifact.template;
1129
+ if (templateName) {
1130
+ const allTemplates = knowledgeIndex.query({
1131
+ scope: scopeFilters,
1132
+ products: [config.product_profile],
1133
+ type: "acceptance_template",
1134
+ keywords: [],
1135
+ limit: 100,
1136
+ });
1137
+ const exactMatch = allTemplates.find((e) => matchesTemplateByName(e, templateName));
1138
+ if (exactMatch)
1139
+ addEntries([exactMatch]);
1140
+ // 内置模板回退: template 名称未命中时从 templates/knowledge/acceptance_templates/ 加载
1141
+ if (!exactMatch) {
1142
+ const builtinTemplate = loadBuiltinTemplate(templateName, "acceptance_templates");
1143
+ if (builtinTemplate)
1144
+ addEntries([builtinTemplate]);
1145
+ }
1146
+ }
1147
+ // 再按 artifact kind 关键词匹配
1148
+ const artifactKeywords = {
1149
+ prototype_spec: ["原型", "prototype", "原型说明"],
1150
+ api_spec: ["接口", "API", "接口设计"],
1151
+ design_doc: ["设计", "架构", "详细设计"],
1152
+ test_plan: ["测试", "测试计划"],
1153
+ migration_plan: ["迁移", "迁移方案"],
1154
+ review_report: ["审查", "review"],
1155
+ task_breakdown: ["任务", "拆解"],
1156
+ root_cause: ["根因", "分析"],
1157
+ incident_review: ["故障", "复盘"],
1158
+ };
1159
+ const artifactKws = artifactKeywords[routeDecision.output_artifact.kind] ?? [];
1160
+ if (artifactKws.length > 0) {
1161
+ const templateResults = knowledgeIndex.query({
1162
+ scope: scopeFilters,
1163
+ products: [config.product_profile],
1164
+ type: "acceptance_template",
1165
+ keywords: artifactKws,
1166
+ limit: 2,
1167
+ });
1168
+ addEntries(templateResults);
1169
+ }
1170
+ }
1171
+ // 优先级 3: intent keywords 补充(填满 limit)
1172
+ if (results.length < limit) {
1173
+ const keywordResults = knowledgeIndex.query({
1174
+ scope: scopeFilters,
1175
+ products: [config.product_profile],
1176
+ keywords: extractKeywords(intent),
1177
+ limit: limit,
1178
+ });
1179
+ addEntries(keywordResults);
1180
+ }
1181
+ return results.slice(0, limit);
1182
+ }
1183
+ /**
1184
+ * 根据执行形态构建模板数据。
1185
+ */
1186
+ function buildTemplateData(intent, techStack, config, classification, scope, matchedEntries, legacyConventions, isLegacyCode, acceptance, degraded, routeDecision) {
1187
+ const base = {
1188
+ intent,
1189
+ tech_stack: techStack,
1190
+ product_profile: config.product_profile,
1191
+ affected_repos: classification.affected_repos.join(", "),
1192
+ matched_knowledge: matchedEntries.map((e) => ({
1193
+ name: e.name,
1194
+ content: e.body || e.when,
1195
+ })),
1196
+ relevant_files: scope.allowed_paths.slice(0, 10).map((p) => ({ path: p, reason: "scope 允许路径" })),
1197
+ is_legacy_code: isLegacyCode,
1198
+ legacy_conventions: legacyConventions,
1199
+ scope: {
1200
+ allowed_paths: scope.allowed_paths.join(", "),
1201
+ new_files_allowed: scope.new_files_allowed,
1202
+ new_file_patterns: scope.new_file_patterns?.join(", "),
1203
+ },
1204
+ acceptance,
1205
+ degraded,
186
1206
  };
1207
+ if (routeDecision) {
1208
+ base.output_artifact = routeDecision.output_artifact;
1209
+ base.input_materials = routeDecision.input_materials;
1210
+ // 根据 ingestion_status 构建 input_material_contract_notes
1211
+ const contractTemplateNotes = [];
1212
+ for (const m of routeDecision.input_materials) {
1213
+ if (m.ingestion_status === "forbidden")
1214
+ contractTemplateNotes.push("FORBIDDEN: " + (m.path ?? "") + " 禁止读取");
1215
+ else if (m.ingestion_status === "requires_confirmation")
1216
+ contractTemplateNotes.push("REQUIRES_CONFIRMATION: " + (m.path ?? "") + " 需确认");
1217
+ }
1218
+ base.input_material_contract_notes = contractTemplateNotes.length > 0 ? contractTemplateNotes : undefined;
1219
+ base.pipeline_hint = routeDecision.pipeline_hint;
1220
+ }
1221
+ return base;
187
1222
  }
188
1223
  /**
189
- * P2(做什么/怎么做分离)+ P3(产物系统):
190
- * 将当前计划步骤的上下文注入到 expansion prompt 中。
191
- * 包括:上一步产出文件内容、输出格式模板、建议工具。
192
- * AI 自主决定执行方式(P4: 评估结果不评估路径)。
193
- * @param prompt - 基础 prompt 文本
194
- * @param planContext - 当前计划步骤上下文
195
- * @param knowledgeIndex - 知识索引管理器,用于查询输出模板
196
- * @returns 注入上下文后的 prompt 文本
1224
+ * 按模板文件名精确匹配知识条目。
1225
+ * 匹配 entry.name、file basename (with/without extension)。
1226
+ */
1227
+ function matchesTemplateByName(entry, templateName) {
1228
+ const requested = templateName.trim();
1229
+ const fileName = path.basename(entry.file_path);
1230
+ const fileStem = path.basename(entry.file_path, path.extname(entry.file_path));
1231
+ return [entry.name, fileName, fileStem].some((c) => c.trim() === requested);
1232
+ }
1233
+ /**
1234
+ * 注入计划阶段上下文(P2 + P3)
197
1235
  */
198
1236
  function injectPlanContext(prompt, planContext, knowledgeIndex) {
199
1237
  const { current_step, previous_outputs } = planContext;
200
1238
  const sections = [];
201
- // 上一步产出(P3: 产物系统,通过文件传递上下文)
202
1239
  const prevEntries = Object.entries(previous_outputs);
203
1240
  if (prevEntries.length > 0) {
204
1241
  sections.push("## 前序阶段产出");
@@ -208,22 +1245,19 @@ function injectPlanContext(prompt, planContext, knowledgeIndex) {
208
1245
  }
209
1246
  }
210
1247
  }
211
- // 输出格式模板(P2: 模板是护栏不是笼子)
212
1248
  if (current_step.output_template) {
213
1249
  const templateEntries = knowledgeIndex.query({
214
1250
  type: "acceptance_template",
215
1251
  keywords: [],
216
1252
  });
217
- const matched = templateEntries.find((e) => e.name === current_step.output_template);
1253
+ const matched = templateEntries.find((e) => matchesOutputTemplate(e, current_step.output_template));
218
1254
  if (matched?.body) {
219
1255
  sections.push(`## 输出格式参考(模板: ${current_step.output_template})\n${matched.body}`);
220
1256
  }
221
1257
  }
222
- // 输出路径(P3: 产出保存位置)
223
1258
  if (current_step.output_path) {
224
1259
  sections.push(`## 产出保存\n将本阶段产出写入: ${current_step.output_path}`);
225
1260
  }
226
- // 建议工具(P2: AI 自主决定是否使用)
227
1261
  if (current_step.suggested_tools && current_step.suggested_tools.length > 0) {
228
1262
  sections.push(`## 建议工具(可选)\n${current_step.suggested_tools.map((t) => `- ${t}`).join("\n")}`);
229
1263
  }
@@ -231,26 +1265,49 @@ function injectPlanContext(prompt, planContext, knowledgeIndex) {
231
1265
  return prompt;
232
1266
  return `${prompt}\n\n---\n\n## 当前计划阶段\n正在执行: **${current_step.title}**\n${current_step.description}\n\n${sections.join("\n\n")}`;
233
1267
  }
234
- /**
235
- * 简单关键词提取: 移除中文虚词后按分隔符拆分,过滤长度不足 2 的词。
236
- * @param intent - 原始意图文本
237
- * @returns 关键词数组
238
- */
1268
+ function matchesOutputTemplate(entry, outputTemplate) {
1269
+ const requested = normalizeTemplateName(outputTemplate);
1270
+ const fileName = path.basename(entry.file_path);
1271
+ const fileStem = path.basename(entry.file_path, path.extname(entry.file_path));
1272
+ return [
1273
+ entry.name,
1274
+ fileName,
1275
+ fileStem,
1276
+ ].some((candidate) => normalizeTemplateName(candidate) === requested);
1277
+ }
1278
+ function normalizeTemplateName(name) {
1279
+ return name.trim();
1280
+ }
239
1281
  function extractKeywords(intent) {
240
- // 简单关键词提取: 按常见分隔符拆分,过滤短词
241
1282
  return intent
242
1283
  .replace(/[的了吗呢把被在从对和与或是]/g, " ")
243
1284
  .split(/[\s,,、;;]+/)
244
1285
  .filter((w) => w.length >= 2);
245
1286
  }
246
1287
  /**
247
- * 解析任务作用域: 基于分类结果的受影响仓库确定允许修改路径和只读路径。
248
- * @param config - 项目配置
249
- * @param classification - 分类结果
250
- * @param degraded - 是否处于降级模式(无知识匹配时降级,禁止新建文件)
251
- * @returns 作用域结果,包含 allowed_paths / readonly_paths / new_files_allowed
1288
+ * 解析 scope: 非代码任务使用简化 scope。
252
1289
  */
253
- function resolveScope(config, classification, degraded) {
1290
+ function resolveScope(config, classification, degraded, routeDecision) {
1291
+ // 非代码任务: scope 仅允许 .soloforge/output/ 和产物路径
1292
+ if (routeDecision && !routeDecision.mutation_allowed) {
1293
+ const outputArtifact = routeDecision.output_artifact;
1294
+ const allowedPaths = [];
1295
+ if (outputArtifact?.path) {
1296
+ // 只允许写产物路径所在的目录
1297
+ const dir = outputArtifact.path.replace(/\/[^/]+$/, "");
1298
+ allowedPaths.push(dir);
1299
+ }
1300
+ else {
1301
+ allowedPaths.push(".soloforge/output/");
1302
+ }
1303
+ return {
1304
+ allowed_paths: allowedPaths,
1305
+ readonly_paths: config.repos.flatMap((r) => r.scope),
1306
+ new_files_allowed: true,
1307
+ new_file_patterns: ["*.md"],
1308
+ };
1309
+ }
1310
+ // 代码修改任务: 原有逻辑
254
1311
  const allowedPaths = [];
255
1312
  for (const repoName of classification.affected_repos) {
256
1313
  const repo = config.repos.find((r) => r.name === repoName);
@@ -258,12 +1315,10 @@ function resolveScope(config, classification, degraded) {
258
1315
  allowedPaths.push(...repo.scope);
259
1316
  }
260
1317
  }
261
- // 无匹配仓库或降级时回退到默认 scope
262
1318
  if (allowedPaths.length === 0) {
263
1319
  allowedPaths.push(...(config.scope.backend || []));
264
1320
  allowedPaths.push(...(config.scope.frontend || []));
265
1321
  }
266
- // 计算 readonly_paths: 不在受影响仓库 scope 内但属于项目的路径
267
1322
  const readonlyPaths = [];
268
1323
  for (const repo of config.repos) {
269
1324
  if (!classification.affected_repos.includes(repo.name)) {
@@ -275,24 +1330,46 @@ function resolveScope(config, classification, degraded) {
275
1330
  readonly_paths: readonlyPaths,
276
1331
  new_files_allowed: !degraded,
277
1332
  new_file_patterns: !degraded && classification.strategy === "full_pipeline"
278
- ? ["**/*"] // full_pipeline 模式下允许新建任意文件
1333
+ ? ["**/*"]
279
1334
  : undefined,
280
1335
  };
281
1336
  }
282
1337
  /**
283
- * 生成验收标准: 降级模式仅含编译+测试,完整模式额外解析知识中的验收项并按任务类型添加人工验收。
284
- * @param intent - 用户意图
285
- * @param classification - 分类结果
286
- * @param matchedEntries - 匹配的知识条目
287
- * @param _config - 项目配置(预留参数)
288
- * @param degraded - 是否处于降级模式
289
- * @returns 自动验收项和人工验收项
1338
+ * 生成验收标准: 根据执行形态选择不同验收。
290
1339
  */
291
- function generateAcceptance(intent, classification, matchedEntries, _config, degraded) {
1340
+ function generateAcceptance(intent, classification, matchedEntries, _config, degraded, routeDecision) {
292
1341
  const automated = [];
293
1342
  const manual = [];
1343
+ // 非代码任务: 产物验收而非编译/测试
1344
+ if (routeDecision && routeDecision.execution_shape !== "code_execution") {
1345
+ if (routeDecision.output_artifact?.path) {
1346
+ automated.push({
1347
+ id: "A-artifact-exists",
1348
+ description: `产物文件已生成: ${routeDecision.output_artifact.path}`,
1349
+ type: "automated",
1350
+ });
1351
+ }
1352
+ automated.push({
1353
+ id: "A-completeness",
1354
+ description: "产物结构完整,无空白占位",
1355
+ type: "automated",
1356
+ });
1357
+ manual.push({
1358
+ id: "M-quality",
1359
+ description: "产物质量满足可交接标准",
1360
+ type: "manual",
1361
+ });
1362
+ // 从知识中解析验收项
1363
+ for (const entry of matchedEntries) {
1364
+ if (entry.body) {
1365
+ const items = parseAcceptanceItems(entry.body);
1366
+ automated.push(...items);
1367
+ }
1368
+ }
1369
+ return { automated, manual };
1370
+ }
1371
+ // 代码修改任务: 原有逻辑
294
1372
  if (degraded) {
295
- // 降级模式: 仅基本验收(sf_verify 独立生成 build/test 命令,此处仅声明验收项)
296
1373
  automated.push({
297
1374
  id: "A-build",
298
1375
  description: "编译通过,无类型错误",
@@ -305,20 +1382,17 @@ function generateAcceptance(intent, classification, matchedEntries, _config, deg
305
1382
  });
306
1383
  return { automated, manual };
307
1384
  }
308
- // 完整模式: 构建 + 模式特定 + 任务类型验收
309
1385
  automated.push({
310
1386
  id: "A-build",
311
1387
  description: "编译通过,无类型错误",
312
1388
  type: "automated",
313
1389
  });
314
- // 模式特定验收: 从知识正文中解析 ## 验收项
315
1390
  for (const entry of matchedEntries) {
316
1391
  if (entry.body) {
317
1392
  const items = parseAcceptanceItems(entry.body);
318
1393
  automated.push(...items);
319
1394
  }
320
1395
  }
321
- // 任务类型特定的人工验收项
322
1396
  if (classification.task_type === "feature") {
323
1397
  manual.push({
324
1398
  id: "M-ux",
@@ -335,12 +1409,6 @@ function generateAcceptance(intent, classification, matchedEntries, _config, deg
335
1409
  }
336
1410
  return { automated, manual };
337
1411
  }
338
- /**
339
- * 从知识条目的 Markdown 正文中解析 "## 验收项" 下的验收条目。
340
- * 支持 `(check: 命令)` 语法提取自动检查命令。
341
- * @param body - 知识条目的 Markdown 正文
342
- * @returns 解析到的验收项数组
343
- */
344
1412
  function parseAcceptanceItems(body) {
345
1413
  const items = [];
346
1414
  if (!body.includes("## 验收项"))
@@ -355,7 +1423,6 @@ function parseAcceptanceItems(body) {
355
1423
  if (inSection && line.startsWith("## "))
356
1424
  break;
357
1425
  if (inSection) {
358
- // 支持 (check: ...) 提取 check_command
359
1426
  const match = line.match(/- \[([A-Z]+-\d+)\]\s*(.+?)(?:\s*\(check:\s*(.+)\))?$/);
360
1427
  if (match) {
361
1428
  const item = { id: match[1], description: match[2].trim(), type: "automated" };
@@ -367,11 +1434,6 @@ function parseAcceptanceItems(body) {
367
1434
  }
368
1435
  return items;
369
1436
  }
370
- /**
371
- * 构建技术栈标签字符串,用于 prompt 中展示项目技术栈信息。
372
- * @param config - 项目配置
373
- * @returns 技术栈标签,如 "spring-boot 3.x + react 18"
374
- */
375
1437
  function buildTechStackLabel(config) {
376
1438
  const parts = [];
377
1439
  if (config.tech_stack.backend.framework) {
@@ -383,19 +1445,9 @@ function buildTechStackLabel(config) {
383
1445
  return parts.join(" + ") || "未知";
384
1446
  }
385
1447
  // ── 能力 1: 执行契约 ──
386
- /**
387
- * 构建执行契约: 根据风险和复杂度生成约束条件和停止条件。
388
- * 高风险任务收紧约束并限制修复循环次数。
389
- * @param intent - 用户意图
390
- * @param classification - 分类结果
391
- * @param scope - 作用域
392
- * @param acceptance - 验收标准
393
- * @returns 执行契约
394
- */
395
1448
  function buildExecutionContract(intent, classification, scope, acceptance) {
396
1449
  const constraints = [];
397
1450
  const stopConditions = [];
398
- // 按 risk 级别收紧约束
399
1451
  if (classification.risk === "high") {
400
1452
  constraints.push("高风险任务:每个变更文件必须有明确来源(任务卡/缺陷/设计锚点)");
401
1453
  constraints.push("禁止顺手重构或范围外变更");
@@ -423,8 +1475,6 @@ function buildExecutionContract(intent, classification, scope, acceptance) {
423
1475
  };
424
1476
  }
425
1477
  // ── 能力 4: 不确定性协议 ──
426
- // 不确定性模式表: 识别高风险领域(DDL 变更、权限、金额、跨系统、状态机、破坏性操作、并发、敏感数据)
427
- // 每个模式包含: 正则匹配、触发类型、描述、选项及权衡、推荐方案
428
1478
  const UNCERTAINTY_PATTERNS = [
429
1479
  {
430
1480
  pattern: /(?:表结构|DDL|加字段|删字段|改字段|索引|migration)/i,
@@ -507,13 +1557,6 @@ const UNCERTAINTY_PATTERNS = [
507
1557
  recommendation: "传输+存储均加密",
508
1558
  },
509
1559
  ];
510
- /**
511
- * 根据意图文本和分类结果生成不确定性触发条件。
512
- * 高风险 + 高歧义时额外追加确认触发。
513
- * @param classification - 分类结果
514
- * @param intent - 用户意图文本
515
- * @returns 匹配到的不确定性触发条件数组
516
- */
517
1560
  function buildUncertaintyTriggers(classification, intent) {
518
1561
  const triggers = [];
519
1562
  for (const pattern of UNCERTAINTY_PATTERNS) {
@@ -526,7 +1569,6 @@ function buildUncertaintyTriggers(classification, intent) {
526
1569
  });
527
1570
  }
528
1571
  }
529
- // 高风险 + 高歧义 = 额外确认
530
1572
  if (classification.risk === "high" && classification.ambiguity === "high") {
531
1573
  triggers.push({
532
1574
  trigger_type: "high_risk_high_ambiguity",
@@ -540,31 +1582,27 @@ function buildUncertaintyTriggers(classification, intent) {
540
1582
  }
541
1583
  return triggers;
542
1584
  }
543
- /** 熔断置信度阈值: 低于此值禁止输出执行代码 */
544
1585
  const CONFIDENCE_THRESHOLD = 0.95;
545
1586
  /**
546
- * 置信度熔断器评估意图清晰度,低于阈值触发 sf_brainstorm 模式。
547
- * 评估维度: 知识匹配度、意图明确性、分类一致性。
548
- * 熔断后不输出执行代码,而是输出头脑风暴结构供人类决策。
1587
+ * 意图熔断器评估意图理解置信度,低于阈值时触发熔断并生成头脑风暴辅助决策。
1588
+ * @param params - 熔断器参数,包含意图、分类结果、匹配知识条目和降级标记
1589
+ * @returns 熔断结果,包含是否触发、置信度、原因和头脑风暴输出
549
1590
  */
550
1591
  export function checkCircuitBreaker(params) {
551
1592
  const { intent, classification, matchedEntries, degraded } = params;
552
1593
  let confidence = 1.0;
553
- // 维度 1: 知识匹配度(权重 0.35)
554
1594
  if (degraded || matchedEntries.length === 0) {
555
1595
  confidence -= 0.35;
556
1596
  }
557
1597
  else if (matchedEntries.length < 2) {
558
1598
  confidence -= 0.15;
559
1599
  }
560
- // 维度 2: 分类一致性(权重 0.35)— ambiguity 非 low 或 strategy 为 skip 时扣分
561
1600
  if (classification.ambiguity === "high") {
562
1601
  confidence -= 0.35;
563
1602
  }
564
1603
  else if (classification.ambiguity === "medium") {
565
1604
  confidence -= 0.15;
566
1605
  }
567
- // 维度 3: 意图明确性(权重 0.30)— 关键词密度不足时扣分
568
1606
  const keywords = extractKeywords(intent);
569
1607
  if (keywords.length < 2) {
570
1608
  confidence -= 0.20;
@@ -572,10 +1610,7 @@ export function checkCircuitBreaker(params) {
572
1610
  else if (keywords.length < 3) {
573
1611
  confidence -= 0.10;
574
1612
  }
575
- // 降级模式额外惩罚
576
- if (degraded) {
577
- confidence -= 0.10;
578
- }
1613
+ // degraded 已在上方 L1826 扣除 -0.35,此处不重复扣分
579
1614
  confidence = Math.max(0, Math.min(1, confidence));
580
1615
  if (confidence < CONFIDENCE_THRESHOLD) {
581
1616
  return {
@@ -587,10 +1622,6 @@ export function checkCircuitBreaker(params) {
587
1622
  }
588
1623
  return { tripped: false, confidence };
589
1624
  }
590
- /**
591
- * 生成头脑风暴结构: 逻辑盲区 + 三轨演进 + 闭环逼问。
592
- * 熔断触发时由 AI 补充具体内容,此处生成骨架。
593
- */
594
1625
  function generateBrainstorm(intent, classification, _matchedEntries) {
595
1626
  const taskLabel = classification.task_type === "feature" ? "新功能" :
596
1627
  classification.task_type === "bugfix" ? "缺陷修复" :