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,15 +1,19 @@
1
1
  #!/usr/bin/env node
2
+ import crypto from "node:crypto";
2
3
  import fss from "node:fs";
3
4
  import path from "node:path";
4
- import { loadProjectConfig, getProjectKnowledgeDir, getGlobalPatternsDir } from "../knowledge/loader.js";
5
+ import { resolveProjectConfig, getProjectKnowledgeDir, getGlobalPatternsDir } from "../knowledge/loader.js";
5
6
  import { generateHooksConfig } from "../adapters/claude_code/hooks.js";
6
7
  import { generateClaudeMd } from "../adapters/claude_code/hooks.js";
7
8
  import { generateTraeRules } from "../adapters/trae/trae_rules.js";
8
9
  import { generateTraeMcpConfig } from "../adapters/trae/trae_config.js";
9
10
  import { generateCodexMcpConfig, generateCodexHooksConfig } from "../adapters/codex/codex_config.js";
10
11
  import { generateCodexAgentsMd } from "../adapters/codex/codex_rules.js";
11
- import { detectFingerprint, generateConfigDraft, validateConfigDraft } from "../engine/zero_config_init.js";
12
+ import { detectFingerprint, generateConfigDraft, validateConfigDraft, generateConfigEvidence, canAutoWrite, parseBlueprint, generateBlueprintEvidence, } from "../engine/zero_config_init.js";
12
13
  import YAML from "yaml";
14
+ import { cmdConfigResolve, cmdConfigExplain, cmdConfigConfirm, cmdConfigUnset, loadConfigEvidenceEntries, } from "./config_commands.js";
15
+ import { resolveCurrentProjectConfigReports, validateConfigPrecedence, } from "../engine/config_precedence_contract.js";
16
+ import { isReadForbidden } from "../engine/privacy_secret_contract.js";
13
17
  const command = process.argv[2];
14
18
  const args = process.argv.slice(3);
15
19
  async function main() {
@@ -18,6 +22,9 @@ async function main() {
18
22
  if (args.includes("--auto")) {
19
23
  await cmdInitAuto();
20
24
  }
25
+ else if (args.includes("--blueprint")) {
26
+ await cmdInitBlueprint();
27
+ }
21
28
  else {
22
29
  await cmdInit();
23
30
  }
@@ -40,6 +47,15 @@ async function main() {
40
47
  case "validate":
41
48
  await cmdValidate();
42
49
  break;
50
+ case "validate-mechanisms":
51
+ await cmdValidateMechanisms();
52
+ break;
53
+ case "audit-template-mechanisms":
54
+ await cmdAuditTemplateMechanisms();
55
+ break;
56
+ case "validate-batch1":
57
+ await cmdValidateBatch1();
58
+ break;
43
59
  case "generate-trae":
44
60
  await cmdGenerateTrae();
45
61
  break;
@@ -51,6 +67,31 @@ async function main() {
51
67
  case "--version":
52
68
  cmdVersion();
53
69
  break;
70
+ case "config": {
71
+ const subCommand = args[0];
72
+ switch (subCommand) {
73
+ case "resolve":
74
+ await cmdConfigResolve();
75
+ break;
76
+ case "explain":
77
+ await cmdConfigExplain();
78
+ break;
79
+ case "confirm":
80
+ await cmdConfigConfirm();
81
+ break;
82
+ case "unset":
83
+ await cmdConfigUnset();
84
+ break;
85
+ default:
86
+ console.log("用法: soloforge config <resolve|explain|confirm|unset> [options]");
87
+ console.log("");
88
+ console.log(" resolve 解析配置字段优先级(只读,显示所有候选来源)");
89
+ console.log(" explain 解释指定字段的来源和优先级(只读,中文输出)");
90
+ console.log(" confirm 确认配置字段值(写入 config + evidence)");
91
+ console.log(" unset 移除指定字段的确认配置和 evidence");
92
+ }
93
+ break;
94
+ }
54
95
  case "status":
55
96
  await cmdStatus();
56
97
  break;
@@ -71,29 +112,37 @@ async function main() {
71
112
  generate-codex 生成 .codex/ 配置和 AGENTS.md
72
113
  check-write PreToolUse hook,用于范围检查(读取 TOOL_INPUT 环境变量)
73
114
  post-bash PostToolUse hook,用于跟踪 Bash 执行结果
74
- validate 验证 .soloforge/config.yaml 和知识文件
115
+ validate 验证项目配置和知识文件(config.yaml 可选,缺失时自动推断)
116
+ validate-mechanisms 验证双层机制承载模型完整性(模板层 + 机制层)
117
+ audit-template-mechanisms 扫描模板与机制注册表交叉校验(--json 输出完整报告,--changed-only 仅检查变更文件)
75
118
  version 显示 SoloForge 版本信息
76
- status 显示当前项目的 SoloForge 状态
119
+ config resolve 解析配置字段优先级(只读)
120
+ config explain 解释配置字段来源(只读,中文)
121
+ config confirm <field> <value> 确认配置字段(写入 config + evidence)
122
+ config unset <field> 移除确认配置
123
+ status 显示当前项目的 SoloForge 状态
77
124
  `);
78
125
  }
79
126
  }
80
127
  async function cmdInitAuto() {
128
+ console.error("[soloForge] CLI: 执行 cmdInitAuto");
81
129
  const dryRun = args.includes("--dry-run");
82
- const yesMode = args.includes("--yes");
83
130
  const projectPathArg = getArgValue("--project-path");
84
131
  const projectPath = projectPathArg ? path.resolve(projectPathArg) : process.cwd();
85
132
  // 层 1: 确定性指纹探测
86
133
  const fp = await detectFingerprint(projectPath);
87
134
  // 层 2: 规则推导 → config 草案
88
135
  const draft = generateConfigDraft(fp);
89
- // 为每个关键配置项标注 confidence evidence
90
- const configItems = annotateConfigWithEvidence(fp, draft);
136
+ // 3: 字段级 evidence
137
+ const evidence = generateConfigEvidence(fp, draft, "auto");
138
+ // 展示探测结果 + evidence
91
139
  console.log("\nSoloForge 自动配置探测结果:");
92
140
  console.log("=".repeat(50));
93
- for (const item of configItems) {
94
- const icon = item.confidence === "high" ? "✅" : item.confidence === "medium" ? "⚠️" : "❓";
95
- console.log(` ${icon} ${item.key}: ${item.value} (${item.confidence})`);
96
- console.log(` evidence: ${item.evidence}`);
141
+ for (const [key, field] of Object.entries(evidence.fields)) {
142
+ const icon = field.confidence === "high" ? "✅" : field.confidence === "medium" ? "⚠️" : "❓";
143
+ const valStr = typeof field.value === "object" ? JSON.stringify(field.value) : String(field.value);
144
+ console.log(` ${icon} ${key}: ${valStr} (${field.confidence}, ${field.confidence_source})`);
145
+ console.log(` evidence: ${field.evidence.join(", ")}`);
97
146
  }
98
147
  console.log("=".repeat(50));
99
148
  console.log(`综合置信度: ${draft.confidence}`);
@@ -123,21 +172,20 @@ async function cmdInitAuto() {
123
172
  console.log("\n[dry-run] 不写入文件。使用不带 --dry-run 的命令执行写入。");
124
173
  return;
125
174
  }
126
- // 渐进式确认: --yes 只接受高置信项,低/中置信项禁止写入
127
- const hasLowOrMedium = configItems.some((i) => i.confidence !== "high");
128
- if (hasLowOrMedium) {
129
- if (yesMode) {
130
- console.log("\n❌ --yes 只能接受高置信度确定项;存在低/中置信度配置,拒绝写入。");
131
- console.log("请手动运行 `soloforge init` 或 `soloforge init --interactive` 补充配置。");
132
- return;
175
+ // 写入门禁: 所有必要字段必须 high confidence + detected/user_declared/confirmed
176
+ const gate = canAutoWrite(evidence);
177
+ if (!gate.allowed) {
178
+ console.log(`\n⚠️ 存在低/中置信度配置项,拒绝写入:`);
179
+ for (const f of gate.blockedFields) {
180
+ console.log(` - ${f}`);
133
181
  }
134
- console.log("\n⚠️ 存在低/中置信度配置项,--yes 也不接受。请手动编辑 .soloforge/config.yaml。");
182
+ console.log("请使用 `soloforge init --interactive` 或 `soloforge init --blueprint \"...\"` 生成配置。");
135
183
  return;
136
184
  }
137
- // 写入配置
138
- await finishInitAutoConfig(projectPath, draft);
185
+ // 写入配置 + evidence
186
+ await finishInitAutoConfig(projectPath, draft, evidence);
139
187
  }
140
- async function finishInitAutoConfig(projectPath, draft) {
188
+ async function finishInitAutoConfig(projectPath, draft, evidence) {
141
189
  const dirs = [
142
190
  ".soloforge/state", ".soloforge/state/debt",
143
191
  ".soloforge/knowledge/patterns", ".soloforge/knowledge/patterns/core",
@@ -151,7 +199,16 @@ async function finishInitAutoConfig(projectPath, draft) {
151
199
  for (const dir of dirs) {
152
200
  fss.mkdirSync(path.join(projectPath, dir), { recursive: true });
153
201
  }
202
+ writeConfigWithEvidence(projectPath, draft, evidence);
203
+ ensureGitignore(projectPath);
204
+ // 继续执行普通 init 的模板复制和适配器生成
205
+ await copyGlobalPatterns(projectPath);
206
+ await copyKnowledgeTemplates(projectPath);
207
+ await generateAdapterConfigs(projectPath, "claude-code");
208
+ }
209
+ function writeConfigWithEvidence(projectPath, draft, evidence) {
154
210
  const configPath = path.join(projectPath, ".soloforge", "config.yaml");
211
+ const evidencePath = path.join(projectPath, ".soloforge", "config.evidence.json");
155
212
  const yamlConfig = {
156
213
  schema_version: 1,
157
214
  name: draft.name,
@@ -162,48 +219,117 @@ async function finishInitAutoConfig(projectPath, draft) {
162
219
  scope: draft.scope,
163
220
  };
164
221
  fss.writeFileSync(configPath, YAML.stringify(yamlConfig), "utf-8");
165
- console.log(`\n✅ .soloforge/config.yaml created (${draft.confidence} confidence)`);
222
+ // Write legacy evidence format (backward compat) + schema v2 entries
223
+ fss.writeFileSync(evidencePath, JSON.stringify(evidence, null, 2), "utf-8");
224
+ // Also write schema v2 entries
225
+ const v2Entries = Object.entries(evidence.fields).map(([key, field]) => ({
226
+ field_path: key,
227
+ value_hash: hashConfigValue(JSON.stringify(field.value)),
228
+ source: mapLegacySource(field.confidence_source),
229
+ confidence: field.confidence === "high" ? 1.0 : field.confidence === "medium" ? 0.6 : 0.3,
230
+ evidence_refs: field.evidence || [],
231
+ lifetime: "project_persistent",
232
+ collected_at: evidence.generated_at || new Date().toISOString(),
233
+ }));
234
+ // Merge v2 entries into the evidence file
235
+ try {
236
+ const existing = JSON.parse(fss.readFileSync(evidencePath, "utf-8"));
237
+ existing.entries = v2Entries;
238
+ existing.updated_at = new Date().toISOString();
239
+ fss.writeFileSync(evidencePath, JSON.stringify(existing, null, 2), "utf-8");
240
+ }
241
+ catch (e) {
242
+ console.error(`[soloForge] 更新 evidence 文件失败: ${e instanceof Error ? e.message : String(e)}`);
243
+ }
244
+ console.log(`\n✅ .soloforge/config.yaml + config.evidence.json created`);
245
+ }
246
+ function hashConfigValue(str) {
247
+ return crypto.createHash("sha256").update(str).digest("hex").slice(0, 16);
248
+ }
249
+ function mapLegacySource(source) {
250
+ switch (source) {
251
+ case "detected": return "detected";
252
+ case "user_declared": return "user_declared";
253
+ case "confirmed": return "confirmed";
254
+ default: return "knowledge_default";
255
+ }
256
+ }
257
+ async function cmdInitBlueprint() {
258
+ console.error("[soloForge] CLI: 执行 cmdInitBlueprint");
259
+ const blueprintText = getArgValue("--blueprint");
260
+ if (!blueprintText) {
261
+ console.error("❌ --blueprint 需要提供描述文本,例如: soloforge init --blueprint \"Spring Boot + React 的 B2B 内部管理系统\"");
262
+ return;
263
+ }
264
+ const projectPathArg = getArgValue("--project-path");
265
+ const projectPath = projectPathArg ? path.resolve(projectPathArg) : process.cwd();
266
+ const parsed = parseBlueprint(blueprintText);
267
+ if (!parsed.parsed) {
268
+ console.log("⚠️ 无法从蓝图文本解析技术栈,请使用 --interactive。");
269
+ console.log("支持的框架关键词: Spring Boot, Go, Rust, Gradle, React, Vue, Angular, Next.js, Nuxt");
270
+ return;
271
+ }
272
+ // Build draft from parsed blueprint
273
+ const draft = {
274
+ name: path.basename(projectPath),
275
+ tech_stack: {
276
+ backend: parsed.tech_stack.backend ?? { lang: "", framework: "", version: "" },
277
+ frontend: parsed.tech_stack.frontend ?? { lang: "", framework: "", version: "" },
278
+ },
279
+ product_profile: parsed.product_profile ?? "default",
280
+ build_commands: {
281
+ backend: blueprintBackendCommands(parsed.tech_stack.backend?.framework),
282
+ frontend: blueprintFrontendCommands(parsed.tech_stack.frontend?.framework),
283
+ },
284
+ scope: {
285
+ backend: parsed.tech_stack.backend ? ["src/"] : [],
286
+ frontend: parsed.tech_stack.frontend ? ["src/"] : [],
287
+ },
288
+ advisory_notes: [],
289
+ confidence: "high",
290
+ };
291
+ const evidence = generateBlueprintEvidence(blueprintText, draft, projectPath);
292
+ // Create dirs + write config + evidence
293
+ const dirs = [
294
+ ".soloforge/state", ".soloforge/state/debt",
295
+ ".soloforge/knowledge/patterns", ".soloforge/knowledge/patterns/core",
296
+ ".soloforge/knowledge/patterns/temp",
297
+ ".soloforge/knowledge/procedures", ".soloforge/knowledge/domain/backend",
298
+ ".soloforge/knowledge/domain/frontend", ".soloforge/knowledge/acceptance_templates",
299
+ ".soloforge/knowledge/review_rules", ".soloforge/knowledge/product_profiles",
300
+ ".soloforge/knowledge/checklists", ".soloforge/knowledge/templates",
301
+ ".soloforge/staged",
302
+ ];
303
+ for (const dir of dirs) {
304
+ fss.mkdirSync(path.join(projectPath, dir), { recursive: true });
305
+ }
306
+ writeConfigWithEvidence(projectPath, draft, evidence);
166
307
  ensureGitignore(projectPath);
167
- // 继续执行普通 init 的模板复制和适配器生成
168
308
  await copyGlobalPatterns(projectPath);
169
309
  await copyKnowledgeTemplates(projectPath);
170
310
  await generateAdapterConfigs(projectPath, "claude-code");
171
311
  }
172
- function annotateConfigWithEvidence(fp, draft) {
173
- const items = [];
174
- items.push({
175
- key: "backend",
176
- value: `${fp.backend?.lang ?? "unknown"}/${fp.backend?.framework ?? "unknown"} ${fp.backend?.version ?? "?"}`,
177
- confidence: fp.backend ? "high" : "low",
178
- evidence: fp.backend ? `detected: ${fp.backend.detected_from}` : "no backend marker found",
179
- });
180
- items.push({
181
- key: "frontend",
182
- value: `${fp.frontend?.lang ?? "unknown"}/${fp.frontend?.framework ?? "unknown"} ${fp.frontend?.version ?? "?"}`,
183
- confidence: fp.frontend ? "high" : "low",
184
- evidence: fp.frontend ? `detected: ${fp.frontend.detected_from}` : "no frontend marker found",
185
- });
186
- items.push({
187
- key: "build_commands.backend",
188
- value: draft.build_commands.backend?.build ?? "unknown",
189
- confidence: fp.backend ? "high" : "low",
190
- evidence: fp.backend ? `inferred from ${fp.backend.framework}` : "no backend framework to infer from",
191
- });
192
- items.push({
193
- key: "build_commands.frontend",
194
- value: draft.build_commands.frontend?.build ?? "unknown",
195
- confidence: fp.frontend ? "high" : "low",
196
- evidence: fp.frontend ? `inferred from ${fp.frontend.framework}` : "no frontend framework to infer from",
197
- });
198
- items.push({
199
- key: "scope.backend",
200
- value: draft.scope.backend?.join(", ") ?? "none",
201
- confidence: fp.backend && (draft.scope.backend?.length ?? 0) > 0 ? "high" : fp.backend ? "medium" : "low",
202
- evidence: fp.backend ? `inferred from ${fp.backend.framework} conventions` : "unknown backend, no scope inferred",
203
- });
204
- return items;
312
+ function blueprintBackendCommands(framework) {
313
+ switch (framework) {
314
+ case "spring-boot": return { build: "./mvnw compile -q", test: "./mvnw test -q", full: "./mvnw verify -q" };
315
+ case "gradle": return { build: "./gradlew compileJava", test: "./gradlew test", full: "./gradlew check" };
316
+ case "stdlib": return { build: "go build ./...", test: "go test ./...", full: "go test -race ./..." };
317
+ case "cargo": return { build: "cargo build", test: "cargo test", full: "cargo test --all" };
318
+ default: return { build: "echo 'no backend build'", test: "echo 'no backend tests'", full: "echo 'no backend'" };
319
+ }
320
+ }
321
+ function blueprintFrontendCommands(framework) {
322
+ switch (framework) {
323
+ case "react":
324
+ case "vue":
325
+ return { build: "npm run build", test: "npm test", full: "npm run build && npm test" };
326
+ case "angular":
327
+ return { build: "npx ng build", test: "npx ng test", full: "npx ng build && npx ng test" };
328
+ default: return { build: "echo 'no frontend build'", test: "echo 'no frontend tests'", full: "echo 'no frontend'" };
329
+ }
205
330
  }
206
331
  async function cmdInit() {
332
+ console.error("[soloForge] CLI: 执行 cmdInit");
207
333
  const interactive = args.includes("--interactive");
208
334
  const adapter = getArgValue("--adapter") || "claude-code";
209
335
  const projectPathArg = getArgValue("--project-path");
@@ -228,14 +354,18 @@ async function cmdInit() {
228
354
  for (const dir of dirs) {
229
355
  fss.mkdirSync(path.join(projectPath, dir), { recursive: true });
230
356
  }
231
- // 若不存在则生成 config.yaml
232
- const configPath = path.join(projectPath, ".soloforge", "config.yaml");
233
- if (!fss.existsSync(configPath) || interactive) {
234
- const config = interactive ? await interactiveConfig() : defaultConfig(projectPath);
235
- fss.writeFileSync(configPath, YAML.stringify(config), "utf-8");
236
- console.log("✅ .soloforge/config.yaml created");
357
+ // --interactive 模式生成 config.yaml + evidence;普通 init 不再生成
358
+ if (interactive) {
359
+ const config = await interactiveConfig(projectPath);
360
+ if (config) {
361
+ // config is { draft, evidence }
362
+ writeConfigWithEvidence(projectPath, config.draft, config.evidence);
363
+ }
364
+ else if (!process.stdin.isTTY) {
365
+ console.log("⚠️ interactive requires TTY. 请使用 --auto 或 --blueprint。");
366
+ }
237
367
  }
238
- // 生成 .mcp.json(SoloForge + Playwright + Figma
368
+ // 生成 .mcp.json(SoloForge + Playwright)
239
369
  if (adapter === "claude-code" || adapter === "all") {
240
370
  const mcpPath = path.join(projectPath, ".mcp.json");
241
371
  if (!fss.existsSync(mcpPath)) {
@@ -250,14 +380,10 @@ async function cmdInit() {
250
380
  command: "npx",
251
381
  args: ["@playwright/mcp@latest", "--headless"],
252
382
  },
253
- figma: {
254
- type: "http",
255
- url: "https://mcp.figma.com/mcp",
256
- },
257
383
  },
258
384
  };
259
385
  fss.writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
260
- console.log("✅ .mcp.json created (soloforge + playwright + figma)");
386
+ console.log("✅ .mcp.json created (soloforge + playwright)");
261
387
  }
262
388
  // 生成 hooks
263
389
  await cmdGenerateHooks(projectPath);
@@ -333,11 +459,10 @@ async function generateAdapterConfigs(projectPath, adapter) {
333
459
  mcpServers: {
334
460
  soloforge: { command: "soloforge", args: ["mcp"], env: { SOLOFORGE_PROJECT: projectPath } },
335
461
  playwright: { command: "npx", args: ["@playwright/mcp@latest", "--headless"] },
336
- figma: { type: "http", url: "https://mcp.figma.com/mcp" },
337
462
  },
338
463
  };
339
464
  fss.writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
340
- console.log("✅ .mcp.json created (soloforge + playwright + figma)");
465
+ console.log("✅ .mcp.json created (soloforge + playwright)");
341
466
  }
342
467
  await cmdGenerateHooks(projectPath);
343
468
  await cmdGenerateClaudeMdInner(projectPath);
@@ -399,7 +524,7 @@ async function cmdGenerateCodexInner(projectPath) {
399
524
  fss.writeFileSync(path.join(codexDir, "hooks.json"), hooksContent, "utf-8");
400
525
  console.log("✅ .codex/hooks.json created");
401
526
  // 生成 AGENTS.md
402
- const config = await loadProjectConfig(projectPath);
527
+ const { config } = await resolveProjectConfig(projectPath);
403
528
  const agentsContent = generateCodexAgentsMd(config);
404
529
  fss.writeFileSync(path.join(projectPath, "AGENTS.md"), agentsContent, "utf-8");
405
530
  console.log("✅ AGENTS.md created");
@@ -415,18 +540,19 @@ async function cmdGenerateTraeInner(projectPath) {
415
540
  // 生成 .trae/rules/project_rules.md
416
541
  const rulesDir = path.join(traeDir, "rules");
417
542
  fss.mkdirSync(rulesDir, { recursive: true });
418
- const config = await loadProjectConfig(projectPath);
543
+ const { config } = await resolveProjectConfig(projectPath);
419
544
  const rulesContent = generateTraeRules(config);
420
545
  fss.writeFileSync(path.join(rulesDir, "project_rules.md"), rulesContent, "utf-8");
421
546
  console.log("✅ .trae/rules/project_rules.md created");
422
547
  }
423
548
  async function cmdGenerateClaudeMdInner(projectPath) {
424
- const config = await loadProjectConfig(projectPath);
549
+ const { config } = await resolveProjectConfig(projectPath);
425
550
  const content = generateClaudeMd(config);
426
551
  fss.writeFileSync(path.join(projectPath, "CLAUDE.md"), content, "utf-8");
427
552
  console.log("✅ CLAUDE.md created");
428
553
  }
429
554
  async function cmdCheckWrite() {
555
+ console.error("[soloForge] CLI: 执行 cmdCheckWrite");
430
556
  try {
431
557
  // 检测运行环境: Claude Code 通过 TOOL_INPUT 环境变量,Codex 通过 stdin JSON
432
558
  const isClaudeCode = !!process.env.TOOL_INPUT;
@@ -466,7 +592,7 @@ async function cmdCheckWrite() {
466
592
  }
467
593
  // 加载配置
468
594
  const projectPath = resolveProjectPath();
469
- const config = await loadProjectConfig(projectPath);
595
+ const { config } = await resolveProjectConfig(projectPath);
470
596
  // 从配置中收集所有允许路径
471
597
  const allowedPaths = [
472
598
  ...(config.scope.backend || []),
@@ -476,6 +602,28 @@ async function cmdCheckWrite() {
476
602
  // 使用 scope_controller 统一检查
477
603
  const { checkScope } = await import("../engine/scope_controller.js");
478
604
  const result = checkScope(filePath, allowedPaths, content || undefined);
605
+ // Privacy / Secret Contract: forbidden read patterns
606
+ if (isReadForbidden(filePath)) {
607
+ if (isClaudeCode) {
608
+ console.error(JSON.stringify({
609
+ allowed: false,
610
+ reason: `隐私策略: ${filePath} 匹配禁止读取模式`,
611
+ has_secrets: true,
612
+ severity: "blocked",
613
+ }));
614
+ process.exit(1);
615
+ }
616
+ else {
617
+ process.stdout.write(JSON.stringify({
618
+ hookSpecificOutput: {
619
+ hookEventName: "PreToolUse",
620
+ permissionDecision: "deny",
621
+ permissionDecisionReason: `隐私策略: ${filePath} 匹配禁止读取模式`,
622
+ },
623
+ }));
624
+ process.exit(0);
625
+ }
626
+ }
479
627
  if (result.severity === "blocked") {
480
628
  if (isClaudeCode) {
481
629
  console.error(JSON.stringify(result));
@@ -504,7 +652,7 @@ async function cmdCheckWrite() {
504
652
  }
505
653
  catch (e) {
506
654
  console.error(`SoloForge check-write error: ${e instanceof Error ? e.message : String(e)}`);
507
- process.exit(0); // 出错时放行(hooks 的 fail-open 策略)
655
+ process.exit(1); // 出错时拦截(fail-closed 策略:安全钩子宁可误拦也不放行)
508
656
  }
509
657
  }
510
658
  function resolveProjectPath() {
@@ -526,20 +674,122 @@ function resolveProjectPath() {
526
674
  return process.cwd();
527
675
  }
528
676
  async function cmdPostBash() {
677
+ console.error("[soloForge] CLI: 执行 cmdPostBash");
529
678
  // Bash 的 PostToolUse hook — 目前为空操作占位符
530
679
  // 未来: 跟踪命令结果,检测构建/测试失败
531
680
  process.exit(0);
532
681
  }
533
- async function cmdValidate() {
534
- const projectPath = process.cwd();
682
+ async function checkEvidenceWarnings(projectPath) {
683
+ console.error("[soloForge] CLI: 执行 checkEvidenceWarnings — " + projectPath);
684
+ const warnings = [];
535
685
  const configPath = path.join(projectPath, ".soloforge", "config.yaml");
536
- if (!fss.existsSync(configPath)) {
537
- console.error("❌ 未找到 .soloforge/config.yaml,请先运行 'soloforge init'。");
538
- process.exit(1);
686
+ const evidencePath = path.join(projectPath, ".soloforge", "config.evidence.json");
687
+ if (!fss.existsSync(configPath))
688
+ return warnings;
689
+ if (!fss.existsSync(evidencePath)) {
690
+ warnings.push("config.yaml exists but config.evidence.json is missing — source traceability lost");
691
+ return warnings;
692
+ }
693
+ // Check mtime staleness
694
+ try {
695
+ const configStat = fss.statSync(configPath);
696
+ const evidenceStat = fss.statSync(evidencePath);
697
+ if (configStat.mtimeMs > evidenceStat.mtimeMs) {
698
+ warnings.push("config.evidence.json is stale (config.yaml was modified after evidence was generated)");
699
+ }
700
+ }
701
+ catch { }
702
+ // Legacy field consistency check (schema v1 evidence)
703
+ try {
704
+ const evidenceRaw = JSON.parse(fss.readFileSync(evidencePath, "utf-8"));
705
+ const configContent = fss.readFileSync(configPath, "utf-8");
706
+ const config = YAML.parse(configContent);
707
+ for (const [key, field] of Object.entries(evidenceRaw.fields)) {
708
+ const actualValue = getConfigFieldValue(config, key);
709
+ if (actualValue !== undefined && JSON.stringify(field.value) !== JSON.stringify(actualValue)) {
710
+ warnings.push(`evidence field '${key}' value does not match config.yaml`);
711
+ }
712
+ }
713
+ }
714
+ catch { }
715
+ // Config precedence validation using schema v2 entries
716
+ try {
717
+ const entries = loadConfigEvidenceEntries(projectPath);
718
+ // Check C-class auto-write violations
719
+ for (const e of entries) {
720
+ if (e.source === "cli_flag" || e.source === "mcp_param") {
721
+ if (e.lifetime === "project_persistent") {
722
+ warnings.push(`CLI/MCP parameter (${e.source}) persisted to config — field: ${e.field_path}`);
723
+ }
724
+ }
725
+ }
726
+ // Run config precedence validation with live resolution
727
+ try {
728
+ const { reports } = await resolveCurrentProjectConfigReports(projectPath);
729
+ const findings = validateConfigPrecedence(reports, entries);
730
+ for (const f of findings) {
731
+ if (f.severity === "hard_fail") {
732
+ warnings.push(`[${f.rule}] ${f.message}`);
733
+ }
734
+ }
735
+ }
736
+ catch { }
737
+ }
738
+ catch { }
739
+ return warnings;
740
+ }
741
+ function getConfigFieldValue(config, key) {
742
+ const parts = key.split(".");
743
+ let obj = config;
744
+ for (const part of parts) {
745
+ if (obj == null || typeof obj !== "object")
746
+ return undefined;
747
+ obj = obj[part];
539
748
  }
749
+ return obj;
750
+ }
751
+ async function cmdValidate() {
752
+ console.error("[soloForge] CLI: 执行 cmdValidate");
753
+ const projectPath = process.cwd();
540
754
  try {
541
- const config = await loadProjectConfig(projectPath);
542
- console.log("✅ config.yaml is valid");
755
+ const { config, source } = await resolveProjectConfig(projectPath);
756
+ if (source === "inferred") {
757
+ console.log("ℹ️ No .soloforge/config.yaml found — using auto-inferred configuration.");
758
+ console.log(" Run 'soloforge init --auto' to persist.");
759
+ }
760
+ else {
761
+ console.log("✅ config.yaml is valid");
762
+ }
763
+ // Config precedence validation using shared function
764
+ let hasHardFail = false;
765
+ try {
766
+ const { reports, entries } = await resolveCurrentProjectConfigReports(projectPath);
767
+ const findings = validateConfigPrecedence(reports, entries);
768
+ const hardFails = findings.filter(f => f.severity === "hard_fail");
769
+ const advisory = findings.filter(f => f.severity === "advisory");
770
+ if (hardFails.length > 0) {
771
+ hasHardFail = true;
772
+ console.log(`❌ 配置优先级: ${hardFails.length} hard_fail`);
773
+ for (const f of hardFails) {
774
+ console.log(` - [${f.rule}] ${f.field_path ?? "N/A"}: ${f.message}`);
775
+ }
776
+ }
777
+ if (advisory.length > 0) {
778
+ console.log(`⚠️ 配置优先级: ${advisory.length} advisory`);
779
+ for (const f of advisory) {
780
+ console.log(` - [${f.rule}] ${f.field_path ?? "N/A"}: ${f.message}`);
781
+ }
782
+ }
783
+ if (hardFails.length === 0 && advisory.length === 0) {
784
+ console.log("✅ 配置优先级验证通过");
785
+ }
786
+ }
787
+ catch { }
788
+ // Evidence checks
789
+ const evidenceWarnings = await checkEvidenceWarnings(projectPath);
790
+ for (const w of evidenceWarnings) {
791
+ console.log(`⚠️ evidence: ${w}`);
792
+ }
543
793
  // 检查知识文件
544
794
  const knowledgeDir = getProjectKnowledgeDir(config);
545
795
  if (fss.existsSync(knowledgeDir)) {
@@ -556,19 +806,263 @@ async function cmdValidate() {
556
806
  }
557
807
  }
558
808
  }
809
+ // 双层机制验证 (仅限 SoloForge 自身源码目录)
810
+ if (fss.existsSync(path.join(projectPath, "src", "engine", "dual_layer_mechanism_registry.ts"))) {
811
+ const { validateMechanismLayerMaps } = await import("../engine/dual_layer_mechanism_registry.js");
812
+ const dlFindings = validateMechanismLayerMaps();
813
+ const dlHard = dlFindings.filter((f) => f.severity === "hard_fail");
814
+ const dlAdvisory = dlFindings.filter((f) => f.severity === "advisory");
815
+ if (dlHard.length > 0) {
816
+ console.log(`❌ 双层机制验证: ${dlHard.length} hard_fail`);
817
+ for (const f of dlHard) {
818
+ console.log(` - [${f.finding_type}] ${f.mechanism_id}: ${f.message}`);
819
+ }
820
+ console.error(`❌ validate 失败: 双层机制存在 ${dlHard.length} hard_fail`);
821
+ process.exit(1);
822
+ }
823
+ else {
824
+ console.log(`✅ 双层机制验证: ${dlAdvisory.length} advisory, 0 hard_fail`);
825
+ }
826
+ } // end dual-layer check
827
+ if (hasHardFail) {
828
+ console.error("❌ validate 失败: 配置优先级存在 hard_fail");
829
+ process.exit(1);
830
+ }
559
831
  }
560
832
  catch (e) {
561
833
  console.error(`❌ 验证失败: ${e.message}`);
562
834
  process.exit(1);
563
835
  }
564
836
  }
837
+ async function cmdValidateMechanisms() {
838
+ console.error("[soloForge] CLI: 执行 cmdValidateMechanisms");
839
+ // Resolve root from compiled binary location: dist/bin/soloforge.js -> project root
840
+ const soloforgeRoot = path.resolve(import.meta.dirname, "..", "..");
841
+ const projectPath = fss.existsSync(path.join(soloforgeRoot, "src", "engine"))
842
+ ? soloforgeRoot
843
+ : process.cwd();
844
+ try {
845
+ const { validateMechanismLayerMaps } = await import("../engine/dual_layer_mechanism_registry.js");
846
+ const findings = validateMechanismLayerMaps(undefined, projectPath);
847
+ const hardFails = findings.filter((f) => f.severity === "hard_fail");
848
+ const advisory = findings.filter((f) => f.severity === "advisory");
849
+ if (findings.length === 0) {
850
+ console.log("✅ 所有双层机制映射验证通过,无发现。");
851
+ process.exit(0);
852
+ return;
853
+ }
854
+ if (advisory.length > 0) {
855
+ console.log(`⚠️ advisory findings (${advisory.length}):`);
856
+ for (const f of advisory) {
857
+ console.log(` - [${f.finding_type}] ${f.mechanism_id}: ${f.message}`);
858
+ }
859
+ }
860
+ if (hardFails.length > 0) {
861
+ console.log(`❌ hard_fail findings (${hardFails.length}):`);
862
+ for (const f of hardFails) {
863
+ console.log(` - [${f.finding_type}] ${f.mechanism_id}: ${f.message}`);
864
+ }
865
+ console.log(`\n❌ 双层机制验证失败: ${hardFails.length} hard_fail`);
866
+ process.exit(1);
867
+ }
868
+ console.log(`\n✅ 双层机制验证通过,${advisory.length} advisory findings`);
869
+ // Audit summary
870
+ try {
871
+ const { auditTemplateMechanisms } = await import("../engine/template_mechanism_auditor.js");
872
+ const audit = auditTemplateMechanisms(projectPath);
873
+ if (audit.hard_fail_count > 0) {
874
+ console.log(`\n⚠️ 模板审计摘要: ${audit.hard_fail_count} hard_fail, ${audit.unmapped_template_assets.length} unmapped`);
875
+ }
876
+ else {
877
+ console.log(`\n📊 模板审计: ${audit.total_template_files} 文件, ${audit.unmapped_template_assets.length} unmapped, ${audit.advisory_count} advisory`);
878
+ }
879
+ }
880
+ catch {
881
+ // audit is advisory, not blocking
882
+ }
883
+ }
884
+ catch (e) {
885
+ console.error(`❌ validate-mechanisms 失败: ${e.message}`);
886
+ process.exit(1);
887
+ }
888
+ }
889
+ async function cmdAuditTemplateMechanisms() {
890
+ console.error("[soloForge] CLI: 执行 cmdAuditTemplateMechanisms");
891
+ const asJson = args.includes("--json");
892
+ const changedOnly = args.includes("--changed-only");
893
+ // Resolve root from compiled binary location
894
+ const soloforgeRoot = path.resolve(import.meta.dirname, "..", "..");
895
+ const projectPath = fss.existsSync(path.join(soloforgeRoot, "src", "engine"))
896
+ ? soloforgeRoot
897
+ : process.cwd();
898
+ try {
899
+ const { auditTemplateMechanisms } = await import("../engine/template_mechanism_auditor.js");
900
+ const report = auditTemplateMechanisms(projectPath);
901
+ if (asJson) {
902
+ console.log(JSON.stringify(report, null, 2));
903
+ if (report.hard_fail_count > 0) {
904
+ process.exit(1);
905
+ }
906
+ return;
907
+ }
908
+ // Human-readable output
909
+ console.log(`模板-机制审计报告 (${report.generated_at})`);
910
+ console.log(` 模板文件: ${report.total_template_files}`);
911
+ console.log(` 注册资产: ${report.total_registered_assets}`);
912
+ console.log(` 机制总数: ${report.total_mechanisms}`);
913
+ console.log("");
914
+ if (report.unmapped_template_assets.length > 0) {
915
+ console.log(`⚠️ 未注册模板 (${report.unmapped_template_assets.length}):`);
916
+ for (const u of report.unmapped_template_assets) {
917
+ console.log(` - ${u.path}`);
918
+ }
919
+ }
920
+ if (report.unconsumed_template_assets.length > 0) {
921
+ console.log(`⚠️ 未消费资产 (${report.unconsumed_template_assets.length}):`);
922
+ for (const u of report.unconsumed_template_assets) {
923
+ console.log(` - ${u.path} (mode=${u.consumption_mode})`);
924
+ }
925
+ }
926
+ if (report.code_only_mechanisms.length > 0) {
927
+ console.log(`⚠️ 仅代码机制 (无模板层):`);
928
+ for (const m of report.code_only_mechanisms) {
929
+ console.log(` - ${m.mechanism_id} (${m.priority}, ${m.status})`);
930
+ }
931
+ }
932
+ if (report.template_only_mechanisms.length > 0) {
933
+ console.log(`⚠️ 仅模板机制 (无代码层):`);
934
+ for (const m of report.template_only_mechanisms) {
935
+ console.log(` - ${m.mechanism_id} (${m.priority}, ${m.status})`);
936
+ }
937
+ }
938
+ if (report.required_assets_without_enforcer.length > 0) {
939
+ console.log(`❌ Required 资产无 enforcer (${report.required_assets_without_enforcer.length}):`);
940
+ for (const r of report.required_assets_without_enforcer) {
941
+ console.log(` - ${r.path} (mechanism=${r.owner_mechanism_id})`);
942
+ }
943
+ }
944
+ if (report.overpromised_adapter_rules.length > 0) {
945
+ console.log(`❌ 适配器过度承诺 (${report.overpromised_adapter_rules.length}):`);
946
+ for (const o of report.overpromised_adapter_rules) {
947
+ console.log(` - ${o.source_file}: ${o.promised_mechanism_id} (${o.promise_keywords.join(",")})`);
948
+ }
949
+ }
950
+ if (report.deprecated_assets_injected.length > 0) {
951
+ console.log(`⚠️ Deprecated 资产仍被注入:`);
952
+ for (const d of report.deprecated_assets_injected) {
953
+ console.log(` - ${d.path}`);
954
+ }
955
+ }
956
+ if (report.template_mechanism_drift.length > 0) {
957
+ const driftHard = report.template_mechanism_drift.filter((f) => f.severity === "hard_fail");
958
+ const driftAdvisory = report.template_mechanism_drift.filter((f) => f.severity === "advisory");
959
+ if (driftAdvisory.length > 0) {
960
+ console.log(`⚠️ 漂移 advisory (${driftAdvisory.length}):`);
961
+ for (const f of driftAdvisory) {
962
+ console.log(` - [${f.finding_type}] ${f.mechanism_id}: ${f.message}`);
963
+ }
964
+ }
965
+ if (driftHard.length > 0) {
966
+ console.log(`❌ 漂移 hard_fail (${driftHard.length}):`);
967
+ for (const f of driftHard) {
968
+ console.log(` - [${f.finding_type}] ${f.mechanism_id}: ${f.message}`);
969
+ }
970
+ }
971
+ }
972
+ console.log("");
973
+ if (report.hard_fail_count > 0) {
974
+ console.log(`❌ 审计失败: ${report.hard_fail_count} hard_fail, ${report.advisory_count} advisory`);
975
+ process.exit(1);
976
+ }
977
+ else {
978
+ console.log(`✅ 审计通过: 0 hard_fail, ${report.advisory_count} advisory`);
979
+ }
980
+ }
981
+ catch (e) {
982
+ console.error(`❌ audit-template-mechanisms 失败: ${e.message}`);
983
+ process.exit(1);
984
+ }
985
+ }
986
+ async function cmdValidateBatch1() {
987
+ console.error("[soloForge] CLI: 执行 cmdValidateBatch1");
988
+ const { validateMechanismLayerMaps, listMechanismLayerMaps } = await import("../engine/dual_layer_mechanism_registry.js");
989
+ const { auditTemplateMechanisms } = await import("../engine/template_mechanism_auditor.js");
990
+ const { validateBatch1Scenarios, validateBatch1ProblemMatrix } = await import("../engine/batch1_scenario_registry.js");
991
+ const cwd = process.cwd();
992
+ const maps = listMechanismLayerMaps();
993
+ const mechFindings = validateMechanismLayerMaps(maps, cwd);
994
+ const mechanismsPass = mechFindings.filter((f) => f.severity === "hard_fail").length === 0;
995
+ const auditReport = auditTemplateMechanisms(cwd);
996
+ const auditPass = auditReport.hard_fail_count === 0;
997
+ const scenarioResults = await validateBatch1Scenarios(mechanismsPass, auditPass, true);
998
+ const allPass = scenarioResults.every((s) => s.status === "PASS");
999
+ const isJson = process.argv.includes("--json");
1000
+ if (isJson) {
1001
+ const problemMatrix = validateBatch1ProblemMatrix(cwd);
1002
+ const problemAllPass = problemMatrix.every((p) => Object.values(p.dimensions).every((d) => d.status === "PASS"));
1003
+ console.log(JSON.stringify({
1004
+ mechanisms_pass: mechanismsPass,
1005
+ audit_pass: auditPass,
1006
+ all_pass: allPass && problemAllPass,
1007
+ problem_matrix_count: problemMatrix.length,
1008
+ problem_matrix: problemMatrix,
1009
+ scenarios: scenarioResults,
1010
+ }, null, 2));
1011
+ }
1012
+ else {
1013
+ for (const s of scenarioResults) {
1014
+ const icon = s.status === "PASS" ? "✓" : "✗";
1015
+ console.log(`${icon} ${s.scenario_id}: ${s.scenario_name} — ${s.status}`);
1016
+ for (const r of s.rules) {
1017
+ const ri = r.status === "PASS" ? " ✓" : " ✗";
1018
+ console.log(`${ri} ${r.rule}: ${r.evidence}`);
1019
+ }
1020
+ }
1021
+ console.log(allPass ? "\nAll scenarios PASS" : "\nSome scenarios FAIL");
1022
+ }
1023
+ process.exit(allPass ? 0 : 1);
1024
+ }
565
1025
  async function cmdStatus() {
1026
+ console.error("[soloForge] CLI: 执行 cmdStatus");
566
1027
  const projectPath = process.cwd();
567
1028
  console.log(`SoloForge 状态: ${projectPath}`);
568
- const config = await loadProjectConfig(projectPath);
1029
+ const { config, source } = await resolveProjectConfig(projectPath);
1030
+ console.log(` 配置来源: ${source === "config_file" ? "config.yaml" : "自动推断"}`);
569
1031
  console.log(` 产品: ${config.product_profile}`);
570
1032
  console.log(` 后端: ${config.tech_stack.backend.framework || "未配置"}`);
571
1033
  console.log(` 前端: ${config.tech_stack.frontend.framework || "未配置"}`);
1034
+ // Per-field config precedence status
1035
+ try {
1036
+ const { resolutions, entries } = await resolveCurrentProjectConfigReports(projectPath);
1037
+ if (resolutions.length > 0) {
1038
+ console.log("");
1039
+ console.log(" 字段解析状态:");
1040
+ for (const r of resolutions) {
1041
+ const stale = r.stale_warning ? " ⚠️ stale" : "";
1042
+ const conflict = r.conflict_report ? " ⚠️ conflict" : "";
1043
+ console.log(` ${r.field_path}: ${JSON.stringify(r.resolved_value)} (${r.source}${stale}${conflict})`);
1044
+ }
1045
+ }
1046
+ const schemaPath = path.join(projectPath, ".soloforge", "config.evidence.json");
1047
+ if (fss.existsSync(schemaPath)) {
1048
+ try {
1049
+ const raw = JSON.parse(fss.readFileSync(schemaPath, "utf-8"));
1050
+ console.log(` evidence: schema_version=${raw.schema_version ?? 1}, ${entries.length} entries`);
1051
+ }
1052
+ catch {
1053
+ console.log(" evidence: 无法解析");
1054
+ }
1055
+ }
1056
+ else if (source === "config_file") {
1057
+ console.log(" evidence: ⚠️ config.evidence.json 缺失");
1058
+ }
1059
+ }
1060
+ catch { }
1061
+ // Evidence warnings
1062
+ const evidenceWarnings = await checkEvidenceWarnings(projectPath);
1063
+ for (const w of evidenceWarnings) {
1064
+ console.log(` ⚠️ evidence: ${w}`);
1065
+ }
572
1066
  const knowledgeDir = getProjectKnowledgeDir(config);
573
1067
  if (fss.existsSync(knowledgeDir)) {
574
1068
  const { KnowledgeIndexManager } = await import("../knowledge/index_manager.js");
@@ -581,34 +1075,8 @@ async function cmdStatus() {
581
1075
  console.log(" 知识: 未初始化");
582
1076
  }
583
1077
  }
584
- function defaultConfig(projectPath) {
585
- const backendLang = process.env.SOLOFORGE_BACKEND_LANG || "java";
586
- const backendFramework = process.env.SOLOFORGE_BACKEND_FRAMEWORK || "spring-boot";
587
- const frontendLang = process.env.SOLOFORGE_FRONTEND_LANG || "typescript";
588
- const frontendFramework = process.env.SOLOFORGE_FRONTEND_FRAMEWORK || "react";
589
- return {
590
- schema_version: 1,
591
- name: path.basename(projectPath),
592
- tech_stack: {
593
- backend: { lang: backendLang, framework: backendFramework, version: "3.x" },
594
- frontend: { lang: frontendLang, framework: frontendFramework, version: "18" },
595
- },
596
- product_profile: "default",
597
- repos: [
598
- { name: "backend", path: "./backend", lang: backendLang, framework: backendFramework, scope: ["src/main/java", "src/test/java"] },
599
- { name: "frontend", path: "./frontend", lang: frontendLang, framework: frontendFramework, scope: ["src"] },
600
- ],
601
- build_commands: {
602
- backend: { build: "cd backend && mvn compile -q", test: "cd backend && mvn test", full: "cd backend && mvn verify" },
603
- frontend: { build: "cd frontend && npm run build", test: "cd frontend && npm test", full: "cd frontend && npm run build && npm test" },
604
- },
605
- scope: {
606
- backend: ["backend/src"],
607
- frontend: ["frontend/src"],
608
- },
609
- };
610
- }
611
- async function interactiveConfig() {
1078
+ async function interactiveConfig(projectPath) {
1079
+ console.error("[soloForge] CLI: 执行 interactiveConfig");
612
1080
  if (!process.stdin.isTTY)
613
1081
  return undefined;
614
1082
  const readline = await import("node:readline");
@@ -619,20 +1087,42 @@ async function interactiveConfig() {
619
1087
  const backendFramework = await ask("后端框架 (spring-boot): ") || "spring-boot";
620
1088
  const frontendFramework = await ask("前端框架 (react): ") || "react";
621
1089
  rl.close();
622
- return {
623
- schema_version: 1,
1090
+ const draft = {
624
1091
  name,
625
- product_profile: product,
626
1092
  tech_stack: {
627
- backend: { lang: "java", framework: backendFramework, version: "" },
1093
+ backend: { lang: backendFramework === "go" ? "go" : "java", framework: backendFramework, version: "" },
628
1094
  frontend: { lang: "typescript", framework: frontendFramework, version: "" },
629
1095
  },
630
- repos: [],
631
- build_commands: { backend: { build: "", test: "", full: "" }, frontend: { build: "", test: "", full: "" } },
632
- scope: { backend: [], frontend: [] },
1096
+ product_profile: product,
1097
+ build_commands: {
1098
+ backend: blueprintBackendCommands(backendFramework),
1099
+ frontend: blueprintFrontendCommands(frontendFramework),
1100
+ },
1101
+ scope: { backend: ["src/"], frontend: ["src/"] },
1102
+ advisory_notes: [],
1103
+ confidence: "high",
1104
+ };
1105
+ const src = "confirmed";
1106
+ const evidence = {
1107
+ schema_version: 1,
1108
+ generated_at: new Date().toISOString(),
1109
+ mode: "interactive",
1110
+ project_root: projectPath,
1111
+ fields: {
1112
+ "name": { value: name, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
1113
+ "tech_stack.backend": { value: draft.tech_stack.backend, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
1114
+ "tech_stack.frontend": { value: draft.tech_stack.frontend, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
1115
+ "build_commands.backend": { value: draft.build_commands.backend, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
1116
+ "build_commands.frontend": { value: draft.build_commands.frontend, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
1117
+ "product_profile": { value: product, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
1118
+ "scope.backend": { value: draft.scope.backend, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
1119
+ "scope.frontend": { value: draft.scope.frontend, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
1120
+ },
633
1121
  };
1122
+ return { draft, evidence };
634
1123
  }
635
1124
  function cmdVersion() {
1125
+ console.error("[soloForge] CLI: 执行 cmdVersion");
636
1126
  // dist/bin/soloforge.js → dist/package.json (local) 或 package.json (global npm)
637
1127
  const pkgPath = path.resolve(import.meta.dirname, "..", "package.json");
638
1128
  try {