soloforge 1.2.2 → 1.2.3

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 (156) hide show
  1. package/README.md +78 -18
  2. package/dist/adapters/claude_code/tools.d.ts.map +1 -1
  3. package/dist/adapters/claude_code/tools.js +319 -5
  4. package/dist/adapters/claude_code/tools.js.map +1 -1
  5. package/dist/adapters/shared/workflow_template.d.ts.map +1 -1
  6. package/dist/adapters/shared/workflow_template.js +25 -0
  7. package/dist/adapters/shared/workflow_template.js.map +1 -1
  8. package/dist/bin/soloforge.js +169 -13
  9. package/dist/bin/soloforge.js.map +1 -1
  10. package/dist/engine/audit_pool.d.ts +36 -0
  11. package/dist/engine/audit_pool.d.ts.map +1 -0
  12. package/dist/engine/audit_pool.js +83 -0
  13. package/dist/engine/audit_pool.js.map +1 -0
  14. package/dist/engine/audit_sampler.d.ts +15 -0
  15. package/dist/engine/audit_sampler.d.ts.map +1 -0
  16. package/dist/engine/audit_sampler.js +26 -0
  17. package/dist/engine/audit_sampler.js.map +1 -0
  18. package/dist/engine/capability_action_advisor.d.ts +24 -0
  19. package/dist/engine/capability_action_advisor.d.ts.map +1 -0
  20. package/dist/engine/capability_action_advisor.js +147 -0
  21. package/dist/engine/capability_action_advisor.js.map +1 -0
  22. package/dist/engine/capability_registry.d.ts +23 -1
  23. package/dist/engine/capability_registry.d.ts.map +1 -1
  24. package/dist/engine/capability_registry.js +511 -19
  25. package/dist/engine/capability_registry.js.map +1 -1
  26. package/dist/engine/capability_state_store.d.ts +50 -0
  27. package/dist/engine/capability_state_store.d.ts.map +1 -0
  28. package/dist/engine/capability_state_store.js +123 -0
  29. package/dist/engine/capability_state_store.js.map +1 -0
  30. package/dist/engine/cognitive_anchor.d.ts +59 -0
  31. package/dist/engine/cognitive_anchor.d.ts.map +1 -0
  32. package/dist/engine/cognitive_anchor.js +68 -0
  33. package/dist/engine/cognitive_anchor.js.map +1 -0
  34. package/dist/engine/conflict_gate.d.ts +36 -0
  35. package/dist/engine/conflict_gate.d.ts.map +1 -0
  36. package/dist/engine/conflict_gate.js +73 -0
  37. package/dist/engine/conflict_gate.js.map +1 -0
  38. package/dist/engine/decision_contract.d.ts +29 -0
  39. package/dist/engine/decision_contract.d.ts.map +1 -0
  40. package/dist/engine/decision_contract.js +41 -0
  41. package/dist/engine/decision_contract.js.map +1 -0
  42. package/dist/engine/delivery.d.ts.map +1 -1
  43. package/dist/engine/delivery.js +83 -0
  44. package/dist/engine/delivery.js.map +1 -1
  45. package/dist/engine/developer_sovereignty.d.ts +62 -0
  46. package/dist/engine/developer_sovereignty.d.ts.map +1 -0
  47. package/dist/engine/developer_sovereignty.js +134 -0
  48. package/dist/engine/developer_sovereignty.js.map +1 -0
  49. package/dist/engine/diff_ownership.d.ts +74 -0
  50. package/dist/engine/diff_ownership.d.ts.map +1 -0
  51. package/dist/engine/diff_ownership.js +143 -0
  52. package/dist/engine/diff_ownership.js.map +1 -0
  53. package/dist/engine/diff_ownership_store.d.ts +76 -0
  54. package/dist/engine/diff_ownership_store.d.ts.map +1 -0
  55. package/dist/engine/diff_ownership_store.js +264 -0
  56. package/dist/engine/diff_ownership_store.js.map +1 -0
  57. package/dist/engine/escape_report.d.ts +45 -0
  58. package/dist/engine/escape_report.d.ts.map +1 -0
  59. package/dist/engine/escape_report.js +97 -0
  60. package/dist/engine/escape_report.js.map +1 -0
  61. package/dist/engine/exploration.d.ts +54 -0
  62. package/dist/engine/exploration.d.ts.map +1 -1
  63. package/dist/engine/exploration.js +138 -0
  64. package/dist/engine/exploration.js.map +1 -1
  65. package/dist/engine/governance_report.d.ts +36 -0
  66. package/dist/engine/governance_report.d.ts.map +1 -0
  67. package/dist/engine/governance_report.js +79 -0
  68. package/dist/engine/governance_report.js.map +1 -0
  69. package/dist/engine/java_quality_guard.d.ts +52 -0
  70. package/dist/engine/java_quality_guard.d.ts.map +1 -0
  71. package/dist/engine/java_quality_guard.js +237 -0
  72. package/dist/engine/java_quality_guard.js.map +1 -0
  73. package/dist/engine/job_manager.d.ts +76 -0
  74. package/dist/engine/job_manager.d.ts.map +1 -0
  75. package/dist/engine/job_manager.js +225 -0
  76. package/dist/engine/job_manager.js.map +1 -0
  77. package/dist/engine/knowledge_sovereignty.d.ts +61 -0
  78. package/dist/engine/knowledge_sovereignty.d.ts.map +1 -0
  79. package/dist/engine/knowledge_sovereignty.js +190 -0
  80. package/dist/engine/knowledge_sovereignty.js.map +1 -0
  81. package/dist/engine/mutation_audit.d.ts +43 -0
  82. package/dist/engine/mutation_audit.d.ts.map +1 -0
  83. package/dist/engine/mutation_audit.js +118 -0
  84. package/dist/engine/mutation_audit.js.map +1 -0
  85. package/dist/engine/policy_drift_detector.d.ts +46 -0
  86. package/dist/engine/policy_drift_detector.d.ts.map +1 -0
  87. package/dist/engine/policy_drift_detector.js +181 -0
  88. package/dist/engine/policy_drift_detector.js.map +1 -0
  89. package/dist/engine/regression_matrix.d.ts +102 -0
  90. package/dist/engine/regression_matrix.d.ts.map +1 -0
  91. package/dist/engine/regression_matrix.js +380 -0
  92. package/dist/engine/regression_matrix.js.map +1 -0
  93. package/dist/engine/risk_sampler.d.ts +37 -0
  94. package/dist/engine/risk_sampler.d.ts.map +1 -0
  95. package/dist/engine/risk_sampler.js +69 -0
  96. package/dist/engine/risk_sampler.js.map +1 -0
  97. package/dist/engine/runtime_safety.d.ts +80 -0
  98. package/dist/engine/runtime_safety.d.ts.map +1 -0
  99. package/dist/engine/runtime_safety.js +195 -0
  100. package/dist/engine/runtime_safety.js.map +1 -0
  101. package/dist/engine/scope_lease.d.ts +45 -0
  102. package/dist/engine/scope_lease.d.ts.map +1 -0
  103. package/dist/engine/scope_lease.js +122 -0
  104. package/dist/engine/scope_lease.js.map +1 -0
  105. package/dist/engine/semantic_evidence.d.ts +23 -0
  106. package/dist/engine/semantic_evidence.d.ts.map +1 -0
  107. package/dist/engine/semantic_evidence.js +81 -0
  108. package/dist/engine/semantic_evidence.js.map +1 -0
  109. package/dist/engine/task_context.d.ts +16 -0
  110. package/dist/engine/task_context.d.ts.map +1 -1
  111. package/dist/engine/task_context.js +58 -0
  112. package/dist/engine/task_context.js.map +1 -1
  113. package/dist/engine/verifier.d.ts.map +1 -1
  114. package/dist/engine/verifier.js +22 -1
  115. package/dist/engine/verifier.js.map +1 -1
  116. package/dist/engine/workspace_resumer.d.ts +43 -0
  117. package/dist/engine/workspace_resumer.d.ts.map +1 -1
  118. package/dist/engine/workspace_resumer.js +119 -4
  119. package/dist/engine/workspace_resumer.js.map +1 -1
  120. package/dist/engine/zero_config_init.d.ts +87 -0
  121. package/dist/engine/zero_config_init.d.ts.map +1 -0
  122. package/dist/engine/zero_config_init.js +427 -0
  123. package/dist/engine/zero_config_init.js.map +1 -0
  124. package/dist/knowledge/index_manager.d.ts +19 -0
  125. package/dist/knowledge/index_manager.d.ts.map +1 -1
  126. package/dist/knowledge/index_manager.js +31 -0
  127. package/dist/knowledge/index_manager.js.map +1 -1
  128. package/dist/knowledge/writer.d.ts.map +1 -1
  129. package/dist/knowledge/writer.js +1 -0
  130. package/dist/knowledge/writer.js.map +1 -1
  131. package/dist/types.d.ts +61 -1
  132. package/dist/types.d.ts.map +1 -1
  133. package/package.json +2 -2
  134. package/templates/knowledge/patterns/core/Diff/345/275/222/345/261/236/350/277/275/350/270/252.md +47 -0
  135. package/templates/knowledge/patterns/core/Java/350/264/250/351/207/217/351/227/250/347/246/201.md +46 -0
  136. package/templates/knowledge/patterns/core/LLM/351/242/204/347/256/227/347/275/221/345/205/263.md +46 -0
  137. package/templates/knowledge/patterns/core//344/273/273/345/212/241/344/270/212/344/270/213/346/226/207/347/224/237/345/221/275/345/221/250/346/234/237.md +47 -0
  138. package/templates/knowledge/patterns/core//344/273/273/345/212/241/347/256/241/347/220/206/345/231/250.md +47 -0
  139. package/templates/knowledge/patterns/core//344/275/234/347/224/250/345/237/237/344/270/216/345/257/206/351/222/245/346/213/246/346/210/252.md +46 -0
  140. package/templates/knowledge/patterns/core//344/275/234/347/224/250/345/237/237/347/247/237/347/272/246.md +47 -0
  141. package/templates/knowledge/patterns/core//345/206/262/347/252/201/351/227/250/347/246/201.md +47 -0
  142. package/templates/knowledge/patterns/core//345/206/263/347/255/226/347/275/221/345/205/263.md +30 -11
  143. package/templates/knowledge/patterns/core//345/217/230/345/274/202/345/256/241/350/256/241.md +20 -0
  144. package/templates/knowledge/patterns/core//345/233/236/345/275/222/347/237/251/351/230/265.md +46 -0
  145. package/templates/knowledge/patterns/core//345/267/245/344/275/234/345/214/272/344/272/222/346/226/245/351/224/201.md +44 -0
  146. package/templates/knowledge/patterns/core//345/267/245/344/275/234/345/214/272/345/224/244/351/206/222.md +46 -0
  147. package/templates/knowledge/patterns/core//345/271/266/345/217/221/351/224/201.md +29 -16
  148. package/templates/knowledge/patterns/core//345/274/200/345/217/221/350/200/205/345/256/252/346/263/225.md +20 -0
  149. package/templates/knowledge/patterns/core//346/225/217/346/204/237/344/277/241/346/201/257/346/211/253/346/217/217.md +45 -0
  150. package/templates/knowledge/patterns/core//346/262/273/347/220/206/350/277/220/350/241/214/346/227/266/345/276/252/347/216/257.md +48 -0
  151. package/templates/knowledge/patterns/core//346/265/201/345/274/217/345/277/203/350/267/263.md +20 -0
  152. package/templates/knowledge/patterns/core//347/237/245/350/257/206/344/270/273/346/235/203.md +20 -0
  153. package/templates/knowledge/patterns/core//350/257/255/344/271/211/350/257/201/346/215/256.md +47 -0
  154. package/templates/knowledge/patterns/core//350/277/220/350/241/214/345/256/211/345/205/250/345/214/205.md +50 -0
  155. package/templates/knowledge/patterns/core//351/233/266/351/205/215/347/275/256/345/210/235/345/247/213/345/214/226.md +47 -0
  156. package/templates/knowledge/patterns/core//351/252/214/350/257/201/345/221/275/344/273/244/347/224/237/346/210/220.md +46 -0
package/README.md CHANGED
@@ -10,14 +10,51 @@ SoloForge 是一个 [MCP (Model Context Protocol)](https://modelcontextprotocol.
10
10
  # 全局安装
11
11
  npm install -g soloforge
12
12
 
13
- # 或直接使用(不安装)
14
- npx soloforge init
13
+ # 初始化(默认适配器: Claude Code)
14
+ soloforge init
15
15
 
16
- # 更新到最新版本
16
+ # Trae IDE / Codex App / 全部适配器
17
+ soloforge init --adapter trae
18
+ soloforge init --adapter codex
19
+ soloforge init --adapter all
20
+
21
+ # 交互式配置(引导输入项目名称、技术栈等)
22
+ soloforge init --interactive
23
+
24
+ # 指定项目路径
25
+ soloforge init --project-path /path/to/project
26
+ ```
27
+
28
+ `init` 会生成 `.soloforge/config.yaml`、初始化知识模板、并为你的 AI 工具生成适配配置(hooks、规则文件等)。
29
+
30
+ ### 更新与重新生成
31
+
32
+ SoloForge 更新后,需要重新生成适配器配置以获取最新的 hooks 和规则:
33
+
34
+ ```bash
35
+ # 更新 SoloForge
17
36
  npm update -g soloforge
37
+
38
+ # 重新生成当前适配器的配置(不会覆盖 config.yaml 和已有知识)
39
+ soloforge init # Claude Code: .claude/settings.json + CLAUDE.md
40
+ soloforge generate-hooks # 仅重新生成 hooks
41
+ soloforge generate-claude-md # 仅重新生成 CLAUDE.md
42
+ soloforge generate-trae # 仅重新生成 .trae/ 配置
43
+ soloforge generate-codex # 仅重新生成 .codex/ 配置 + AGENTS.md
44
+
45
+ # 查看版本
46
+ soloforge version
18
47
  ```
19
48
 
20
- `init` 命令会生成项目配置(`.soloforge/config.yaml`)、初始化知识模板、并为你的 AI 工具生成适配配置。
49
+ ### 日常命令
50
+
51
+ ```bash
52
+ # 验证配置和知识文件
53
+ soloforge validate
54
+
55
+ # 查看当前项目状态
56
+ soloforge status
57
+ ```
21
58
 
22
59
  ## 工作原理
23
60
 
@@ -28,9 +65,9 @@ SoloForge 以 MCP Server(stdio 传输)运行。AI 助手在开发过程中
28
65
  ← 知识、规则、模板
29
66
  ```
30
67
 
31
- SoloForge **零 AI/LLM 依赖**。所有智能来自宿主 AISoloForge 提供结构、规则和知识。
68
+ SoloForge 引擎不直接调用 LLM API,由宿主 AI 中转。所有智能来自宿主 AI(Claude Code、Cursor、Trae),SoloForge 提供结构、规则和知识。
32
69
 
33
- ## MCP 工具(27 个)
70
+ ## MCP 工具(32 个)
34
71
 
35
72
  ### 核心管线(Phase 1)
36
73
 
@@ -62,7 +99,7 @@ SoloForge **零 AI/LLM 依赖**。所有智能来自宿主 AI,SoloForge 提供
62
99
  | `sf_contract_check` | 检测接口契约的破坏性变更 |
63
100
  | `sf_onboard` | 引导式入职:项目概览 → 代码导览 → 首任务 |
64
101
 
65
- ### 自维护(仅 SoloForge 自身项目)
102
+ ### 知识维护
66
103
 
67
104
  | 工具 | 说明 |
68
105
  |------|------|
@@ -88,18 +125,27 @@ SoloForge **零 AI/LLM 依赖**。所有智能来自宿主 AI,SoloForge 提供
88
125
  | `sf_dependency_scan` | 扫描依赖漏洞,支持 npm/maven/gradle |
89
126
  | `sf_debt_report` | 技术债务聚合报告:分类、趋势、优先级 |
90
127
 
128
+ ### 治理闭环
129
+
130
+ | 工具 | 说明 |
131
+ |------|------|
132
+ | `sf_audit_sample` | 按风险加权抽样,critical 100% 抽中 |
133
+ | `sf_escape_report` | 记录逃逸/误伤/工具故障 |
134
+ | `sf_governance_report` | 汇总治理健康报告 |
135
+ | `sf_capability_update` | 人工确认后更新能力状态 |
136
+
91
137
  ## 知识体系
92
138
 
93
- SoloForge 内置 **108+ 知识模板**,覆盖 6 种类型:
139
+ SoloForge 内置知识模板(含全局模式),覆盖 6 种类型:
94
140
 
95
- | 类型 | 数量 | 用途 |
96
- |------|------|------|
97
- | `pattern` | 50 | 决策规则 + 验收标准 |
98
- | `procedure` | 24 | 操作流程 + 检查点 |
99
- | `domain` | 9 | 业务规则、约束条件、例外情况 |
100
- | `acceptance_template` | 19 | 质量门禁 + 自动化检查命令 |
101
- | `review_rule` | 6 | 正则驱动的代码审查规则 |
102
- | `pipeline_procedure` | — | CI/CD 流水线阶段定义 |
141
+ | 类型 | 用途 |
142
+ |------|------|
143
+ | `pattern` | 决策规则 + 验收标准 |
144
+ | `procedure` | 操作流程 + 检查点 |
145
+ | `domain` | 业务规则、约束条件、例外情况 |
146
+ | `acceptance_template` | 质量门禁 + 自动化检查命令 |
147
+ | `review_rule` | 正则驱动的代码审查规则 |
148
+ | `pipeline_procedure` | CI/CD 流水线阶段定义 |
103
149
 
104
150
  知识文件采用 Markdown + YAML frontmatter 格式:
105
151
 
@@ -163,17 +209,31 @@ scope:
163
209
  ```
164
210
  知识层 机制层 适配层
165
211
  +------------------+ +---------------------+ +------------------+
166
- | 108+ 知识模板 | | 分类器 | | Claude Code |
212
+ | 知识模板 | | 分类器 | | Claude Code |
167
213
  | 6 种知识类型 | | 意图膨胀器 | | Cursor |
168
214
  | 产品 Profile | | 验证器 | | Trae |
169
215
  | | | 代码审查器 | | CLI |
170
216
  | 项目专属知识 | | 任务规划器 | | |
171
217
  | | | 脚手架生成器 | | |
172
218
  | | | 自动交付 | | |
219
+ | | | 契约治理内核 | | |
173
220
  | | | + 20+ 个引擎模块 | | |
174
221
  +------------------+ +---------------------+ +------------------+
175
222
  ```
176
223
 
224
+ ## 契约治理内核
225
+
226
+ SoloForge 的治理能力按四级状态管理,新增治理能力不伪装 hard block:
227
+
228
+ | 状态 | 含义 |
229
+ |------|------|
230
+ | `enforced` | 强制执行,阻断不合规操作 |
231
+ | `advisory` | 建议性告警,由开发者决策 |
232
+ | `experimental` | 实验性,需晋级计划才能升级 |
233
+ | `removed` | 已移除,不再生效 |
234
+
235
+ 治理闭环:任务完成入池 → 按风险加权抽样 → 逃逸记录 → 治理报告 → 人工确认后状态更新。所有状态变更必须经 `sf_capability_update` + 人工确认,不自动执行。
236
+
177
237
  ## 开发
178
238
 
179
239
  ```bash
@@ -183,7 +243,7 @@ npm install
183
243
  # 构建
184
244
  npm run build
185
245
 
186
- # 运行测试(447 个测试)
246
+ # 运行测试(1256 tests / 86 files)
187
247
  npm test
188
248
 
189
249
  # 类型检查
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/adapters/claude_code/tools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAA+B,MAAM,gBAAgB,CAAC;AACjF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AA2BvE,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAIzD;;;;;;;GAOG;AAEH;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,aAAa;IACb,MAAM,EAAE,aAAa,CAAC;IACtB,cAAc;IACd,cAAc,EAAE,qBAAqB,CAAC;IACtC,eAAe;IACf,WAAW,EAAE,kBAAkB,CAAC;IAChC,yDAAyD;IACzD,OAAO,CAAC,EAAE,UAAU,CAAC;CACtB;AAwHD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI,CAygC1E"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/adapters/claude_code/tools.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAA+B,MAAM,gBAAgB,CAAC;AACjF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AA4BvE,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAYzD;;;;;;;GAOG;AAEH;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,aAAa;IACb,MAAM,EAAE,aAAa,CAAC;IACtB,cAAc;IACd,cAAc,EAAE,qBAAqB,CAAC;IACtC,eAAe;IACf,WAAW,EAAE,kBAAkB,CAAC;IAChC,yDAAyD;IACzD,OAAO,CAAC,EAAE,UAAU,CAAC;CACtB;AA0HD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI,CAg4C1E"}
@@ -1,4 +1,6 @@
1
1
  import { z } from "zod";
2
+ import path from "node:path";
3
+ import fss from "node:fs";
2
4
  import { classify } from "../../engine/classifier.js";
3
5
  import { expand } from "../../engine/intent_expander.js";
4
6
  import { generateVerifyCommands } from "../../engine/verifier.js";
@@ -18,6 +20,7 @@ import { auditKnowledge, addKnowledge, updateKnowledge } from "../../engine/know
18
20
  import { checkFeasibility } from "../../engine/feasibility_checker.js";
19
21
  import { debugError } from "../../engine/debugger.js";
20
22
  import { generateReport } from "../../engine/observability.js";
23
+ import { generateReport as generateGovernanceReport } from "../../engine/governance_report.js";
21
24
  import { analyzeMigration } from "../../engine/migration_guard.js";
22
25
  import { generateTestGuide } from "../../engine/test_generator.js";
23
26
  import { analyzeTestQuality } from "../../engine/test_quality.js";
@@ -27,7 +30,15 @@ import { exploreSolutions } from "../../engine/exploration.js";
27
30
  import { scanAndResume } from "../../engine/workspace_resumer.js";
28
31
  import { LLMGateway } from "../../engine/llm_gateway.js";
29
32
  import { IOController } from "../../engine/io_controller.js";
30
- import { getSummary as getCapabilitySummary } from "../../engine/capability_registry.js";
33
+ import { getSummary as getCapabilitySummary, getAllCapabilities } from "../../engine/capability_registry.js";
34
+ import { validateDecisionOutput } from "../../engine/decision_contract.js";
35
+ import { readMapJson, checkAnchorStaleness, filterRelevantAnchors } from "../../engine/cognitive_anchor.js";
36
+ import { JobManager } from "../../engine/job_manager.js";
37
+ import { AuditPool } from "../../engine/audit_pool.js";
38
+ import { EscapeReportStore } from "../../engine/escape_report.js";
39
+ import { sampleAuditItems } from "../../engine/audit_sampler.js";
40
+ import { decideAction } from "../../engine/capability_action_advisor.js";
41
+ import { CapabilityStateStore } from "../../engine/capability_state_store.js";
31
42
  // ── Zod Schema 定义 ──
32
43
  const ClassifySchema = {
33
44
  intent: z.string().describe("开发者意图描述"),
@@ -54,6 +65,8 @@ const LearnSchema = {
54
65
  const StatusSchema = {
55
66
  task_id: z.string().optional().describe("任务 ID(不传则查当前任务)"),
56
67
  action: z.enum(["current", "recent", "resume", "cancel"]).optional().describe("操作类型"),
68
+ job_id: z.string().optional().describe("Job ID(用于 job_status / job_resume / job_cancel)"),
69
+ job_action: z.enum(["job_status", "job_resume", "job_cancel"]).optional().describe("Job 操作: 查询状态、从 checkpoint 恢复、取消 job(advisory)"),
57
70
  };
58
71
  const PlanSchema = {
59
72
  task_id: z.string().describe("sf_classify 返回的任务 ID"),
@@ -154,6 +167,58 @@ export function registerTools(server, deps) {
154
167
  }
155
168
  });
156
169
  }
170
+ // 加载认知锚点上下文 — 必须提供相关性参数,禁止全量加载
171
+ function loadRelevantAnchors(query) {
172
+ const stateDir = taskContext.getStateDir();
173
+ const mapPath = path.join(stateDir, "cognitive.map.json");
174
+ const mapData = readMapJson(mapPath);
175
+ if (!mapData || mapData.anchors.length === 0)
176
+ return undefined;
177
+ const existingFiles = new Set();
178
+ try {
179
+ for (const anchor of mapData.anchors) {
180
+ for (const ref of anchor.source_refs) {
181
+ if (ref.type === "file" && fss.existsSync(path.join(projectPath, ref.ref))) {
182
+ existingFiles.add(ref.ref);
183
+ }
184
+ }
185
+ }
186
+ }
187
+ catch { /* ignore */ }
188
+ const checked = checkAnchorStaleness(mapData.anchors, existingFiles);
189
+ // 必须有 module 或 file_paths,否则不返回任何锚点(禁止全量加载)
190
+ if (!query.module && (!query.file_paths || query.file_paths.length === 0))
191
+ return undefined;
192
+ // Collect anchors matching ANY of the provided file_paths or module
193
+ const seen = new Set();
194
+ const relevant = [];
195
+ if (query.module) {
196
+ for (const a of filterRelevantAnchors(checked, { module: query.module })) {
197
+ if (!seen.has(a.anchor_id)) {
198
+ seen.add(a.anchor_id);
199
+ relevant.push(a);
200
+ }
201
+ }
202
+ }
203
+ if (query.file_paths) {
204
+ for (const fp of query.file_paths) {
205
+ for (const a of filterRelevantAnchors(checked, { file_path: fp })) {
206
+ if (!seen.has(a.anchor_id)) {
207
+ seen.add(a.anchor_id);
208
+ relevant.push(a);
209
+ }
210
+ }
211
+ }
212
+ }
213
+ if (relevant.length === 0)
214
+ return undefined;
215
+ return relevant.map((a) => ({
216
+ anchor_id: a.anchor_id,
217
+ module: a.module,
218
+ summary: a.core_contracts.slice(0, 3).join("; "),
219
+ stale_anchor: a.stale_anchor,
220
+ }));
221
+ }
157
222
  // ── sf_classify: 意图分类入口,创建任务上下文并返回分类结果 ──
158
223
  registerSafeTool("sf_classify", "分析开发者意图,返回任务类型、风险、复杂度和执行策略", ClassifySchema, async (args) => {
159
224
  // 检查是否存在进行中的任务
@@ -284,6 +349,11 @@ export function registerTools(server, deps) {
284
349
  advisories.h1_advisory = h1Warning;
285
350
  if (h4LockWarning)
286
351
  advisories.h4_advisory = h4LockWarning;
352
+ // 决策契约 advisory: 校验 expand 输出是否包含默认决策字段
353
+ const decisionContract = validateDecisionOutput(expansion);
354
+ if (!decisionContract.passed) {
355
+ advisories.decision_contract_advisory = decisionContract.advisory;
356
+ }
287
357
  // 存储膨胀结果
288
358
  try {
289
359
  await taskContext.setExpansion(args.task_id, expansion);
@@ -349,10 +419,17 @@ export function registerTools(server, deps) {
349
419
  await taskContext.updateStatus(args.task_id, "verifying");
350
420
  // 存储验证结果
351
421
  await taskContext.setVerification(args.task_id, verifyResult);
422
+ // 认知锚点上下文回放(按变更文件相关性)
423
+ const verifyAnchors = loadRelevantAnchors({ file_paths: args.changed_files });
424
+ const verifyExtras = {};
425
+ if (h4Warning)
426
+ verifyExtras.h4_advisory = h4Warning;
427
+ if (verifyAnchors && verifyAnchors.length > 0)
428
+ verifyExtras.cognitive_anchors = verifyAnchors;
352
429
  return {
353
430
  content: [{
354
431
  type: "text",
355
- text: JSON.stringify(h4Warning ? { ...verifyResult, h4_advisory: h4Warning } : verifyResult, null, 2),
432
+ text: JSON.stringify(Object.keys(verifyExtras).length > 0 ? { ...verifyResult, ...verifyExtras } : verifyResult, null, 2),
356
433
  }],
357
434
  };
358
435
  });
@@ -415,6 +492,64 @@ export function registerTools(server, deps) {
415
492
  // ── sf_status: 任务状态查询(current/recent/resume/cancel) ──
416
493
  registerSafeTool("sf_status", "查询当前任务状态、列出近期任务、恢复中断任务或取消任务", StatusSchema, async (args) => {
417
494
  const action = args.action || "current";
495
+ // Job actions — advisory, independent of task actions
496
+ if (args.job_action) {
497
+ if (!args.job_id) {
498
+ return {
499
+ content: [{ type: "text", text: JSON.stringify({ error: "job 操作需要 job_id" }) }],
500
+ isError: true,
501
+ };
502
+ }
503
+ const jm = new JobManager(taskContext.getStateDir());
504
+ const taskId = args.task_id ?? await jm.resolveTaskId(args.job_id) ?? "";
505
+ if (args.job_action === "job_status") {
506
+ const status = await jm.getJobStatus(args.job_id, taskId);
507
+ if (!status) {
508
+ return {
509
+ content: [{ type: "text", text: JSON.stringify({ error: `job ${args.job_id} 不存在或已过期` }) }],
510
+ isError: true,
511
+ };
512
+ }
513
+ return {
514
+ content: [{ type: "text", text: JSON.stringify({ job: status }, null, 2) }],
515
+ };
516
+ }
517
+ if (args.job_action === "job_resume") {
518
+ const checkpoint = await jm.resumeFromCheckpoint(args.job_id, taskId);
519
+ if (!checkpoint) {
520
+ return {
521
+ content: [{ type: "text", text: JSON.stringify({ error: `job ${args.job_id} 无可恢复的 checkpoint` }) }],
522
+ isError: true,
523
+ };
524
+ }
525
+ return {
526
+ content: [{
527
+ type: "text",
528
+ text: JSON.stringify({
529
+ advisory: "job 恢复为 advisory 操作,需确认 checkpoint 数据与当前状态一致",
530
+ job_id: checkpoint.job_id,
531
+ task_id: checkpoint.task_id,
532
+ phase: checkpoint.phase,
533
+ checkpoint_number: checkpoint.checkpoint_number,
534
+ cognitive_anchor: checkpoint.cognitive_anchor,
535
+ }, null, 2),
536
+ }],
537
+ };
538
+ }
539
+ if (args.job_action === "job_cancel") {
540
+ const removed = await jm.cancelJob(args.job_id, taskId);
541
+ return {
542
+ content: [{
543
+ type: "text",
544
+ text: JSON.stringify({
545
+ advisory: "job 取消为 advisory 操作",
546
+ job_id: args.job_id,
547
+ cancelled: removed,
548
+ }),
549
+ }],
550
+ };
551
+ }
552
+ }
418
553
  switch (action) {
419
554
  case "current": {
420
555
  const ctx = args.task_id
@@ -445,6 +580,24 @@ export function registerTools(server, deps) {
445
580
  result.changed_files = ctx.execution.changed_files;
446
581
  result.attempt_count = ctx.execution.attempt_count;
447
582
  }
583
+ // JobManager advisory: 查询关联 job 状态
584
+ try {
585
+ const jm = new JobManager(taskContext.getStateDir());
586
+ const activeJobs = await jm.listActiveJobs();
587
+ const relatedJob = activeJobs.find((j) => j.task_id === ctx.task_id);
588
+ if (relatedJob) {
589
+ result.job = {
590
+ job_id: relatedJob.job_id,
591
+ phase: relatedJob.current_phase,
592
+ checkpoint_count: relatedJob.checkpoint_count,
593
+ is_alive: relatedJob.is_alive,
594
+ latest_anchor_summary: relatedJob.latest_anchor?.summary,
595
+ };
596
+ }
597
+ }
598
+ catch {
599
+ // JobManager advisory — ignore errors
600
+ }
448
601
  return {
449
602
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
450
603
  };
@@ -492,6 +645,9 @@ export function registerTools(server, deps) {
492
645
  changed_files: ctx.execution.changed_files,
493
646
  attempt_count: ctx.execution.attempt_count,
494
647
  } : undefined,
648
+ cognitive_anchors: ctx.execution?.changed_files?.length
649
+ ? loadRelevantAnchors({ file_paths: ctx.execution.changed_files })
650
+ : undefined,
495
651
  }, null, 2),
496
652
  }],
497
653
  };
@@ -604,8 +760,14 @@ export function registerTools(server, deps) {
604
760
  projectPath,
605
761
  });
606
762
  result.task_id = args.task_id;
763
+ // 决策契约 advisory: 校验 analyze 输出
764
+ const decisionContract = validateDecisionOutput(result);
765
+ const advisoryExtras = {};
766
+ if (!decisionContract.passed) {
767
+ advisoryExtras.decision_contract_advisory = decisionContract.advisory;
768
+ }
607
769
  return {
608
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
770
+ content: [{ type: "text", text: JSON.stringify(Object.keys(advisoryExtras).length > 0 ? { ...result, ...advisoryExtras } : result, null, 2) }],
609
771
  };
610
772
  });
611
773
  // ── sf_review: 代码审查(质量、安全、性能、技术债务) ──
@@ -629,8 +791,14 @@ export function registerTools(server, deps) {
629
791
  }, tracker);
630
792
  result.task_id = args.task_id;
631
793
  await taskContext.setCodeReview(args.task_id, result);
794
+ // 决策契约 advisory: 校验 review 输出
795
+ const decisionContract = validateDecisionOutput(result);
796
+ const reviewExtras = {};
797
+ if (!decisionContract.passed) {
798
+ reviewExtras.decision_contract_advisory = decisionContract.advisory;
799
+ }
632
800
  return {
633
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
801
+ content: [{ type: "text", text: JSON.stringify(Object.keys(reviewExtras).length > 0 ? { ...result, ...reviewExtras } : result, null, 2) }],
634
802
  };
635
803
  });
636
804
  // ── sf_scaffold: 生成标准化代码骨架 ──
@@ -836,8 +1004,14 @@ export function registerTools(server, deps) {
836
1004
  classification,
837
1005
  knowledgeIndex,
838
1006
  });
1007
+ // 决策契约 advisory: sf_explore 应始终通过(10 字段已内置)
1008
+ const decisionContract = validateDecisionOutput(result);
1009
+ const exploreExtras = {};
1010
+ if (!decisionContract.passed) {
1011
+ exploreExtras.decision_contract_advisory = decisionContract.advisory;
1012
+ }
839
1013
  return {
840
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
1014
+ content: [{ type: "text", text: JSON.stringify(Object.keys(exploreExtras).length > 0 ? { ...result, ...exploreExtras } : result, null, 2) }],
841
1015
  };
842
1016
  });
843
1017
  // ── sf_knowledge_audit: 知识库健康审计 ──
@@ -900,9 +1074,149 @@ export function registerTools(server, deps) {
900
1074
  // ── sf_resume_workspace: 工作区状态唤醒(解决前端刷新导致UUID丢失) ──
901
1075
  registerSafeTool("sf_resume_workspace", "扫描 .soloforge/state/ 目录,恢复中断工单并播报当前进度。新会话启动时必须优先调用", {}, async () => {
902
1076
  const result = await scanAndResume(taskContext);
1077
+ // 认知锚点:按恢复任务的 changed_files 相关性加载,禁止全量
1078
+ if (result.task) {
1079
+ const ctx = await taskContext.load(result.task.task_id);
1080
+ const changedFiles = ctx?.execution?.changed_files;
1081
+ if (changedFiles && changedFiles.length > 0) {
1082
+ const anchors = loadRelevantAnchors({ file_paths: changedFiles });
1083
+ if (anchors && anchors.length > 0) {
1084
+ result.cognitive_anchors = anchors;
1085
+ }
1086
+ }
1087
+ }
1088
+ // JobManager advisory: 查询活跃 jobs
1089
+ try {
1090
+ const jm = new JobManager(taskContext.getStateDir());
1091
+ const activeJobs = await jm.listActiveJobs();
1092
+ if (activeJobs.length > 0) {
1093
+ result.active_jobs = activeJobs.map((j) => ({
1094
+ job_id: j.job_id,
1095
+ task_id: j.task_id,
1096
+ phase: j.current_phase,
1097
+ is_alive: j.is_alive,
1098
+ latest_anchor_summary: j.latest_anchor?.summary,
1099
+ checkpoint_count: j.checkpoint_count,
1100
+ }));
1101
+ }
1102
+ }
1103
+ catch {
1104
+ // JobManager advisory — ignore errors
1105
+ }
903
1106
  return {
904
1107
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
905
1108
  };
906
1109
  });
1110
+ // ── sf_audit_sample: 从审计池按风险加权抽样生成抽检清单 ──
1111
+ const AuditSampleSchema = {
1112
+ seed: z.number().optional().describe("抽样种子(默认 0,同种子可复现)"),
1113
+ };
1114
+ registerSafeTool("sf_audit_sample", "从审计池按风险加权抽样,生成抽检清单(SamplingDecision 列表)。只读,不落盘,不生成逃逸报告,不改能力状态", AuditSampleSchema, async (args) => {
1115
+ const stateDir = taskContext.getStateDir();
1116
+ const pool = new AuditPool(stateDir);
1117
+ const items = pool.list();
1118
+ const seed = args.seed ?? 0;
1119
+ const result = sampleAuditItems(items, seed);
1120
+ return {
1121
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
1122
+ };
1123
+ });
1124
+ // ── sf_escape_report: 记录逃逸/误伤/工具故障报告 ──
1125
+ const EscapeReportSchema = {
1126
+ escape_id: z.string().describe("逃逸报告唯一 ID"),
1127
+ task_id: z.string().describe("关联任务 ID"),
1128
+ policy_id: z.string().describe("关联能力 policy ID"),
1129
+ failure_type: z.enum(["rule_gap", "weak_test", "bad_evidence", "ai_escape", "human_miss", "tool_bug", "false_positive"]).describe("失败类型"),
1130
+ expected_guard: z.string().describe("期望的守卫行为"),
1131
+ actual_escape: z.string().describe("实际的逃逸行为"),
1132
+ evidence: z.string().describe("证据"),
1133
+ root_cause: z.string().describe("根因分析"),
1134
+ fix_required: z.string().describe("修复要求"),
1135
+ owner: z.string().describe("负责人"),
1136
+ due_date: z.string().describe("修复截止日期"),
1137
+ capability_action: z.enum(["keep", "downgrade", "disable", "promote_blocked"]).describe("建议的能力动作"),
1138
+ created_at: z.string().optional().describe("报告时间(ISO,默认当前时间)"),
1139
+ };
1140
+ registerSafeTool("sf_escape_report", "记录逃逸、误伤或工具故障报告。只落盘记录,不自动降级,不改能力状态", EscapeReportSchema, async (args) => {
1141
+ const stateDir = taskContext.getStateDir();
1142
+ const store = new EscapeReportStore(stateDir);
1143
+ const report = {
1144
+ escape_id: args.escape_id,
1145
+ task_id: args.task_id,
1146
+ policy_id: args.policy_id,
1147
+ failure_type: args.failure_type,
1148
+ expected_guard: args.expected_guard,
1149
+ actual_escape: args.actual_escape,
1150
+ evidence: args.evidence,
1151
+ root_cause: args.root_cause,
1152
+ fix_required: args.fix_required,
1153
+ owner: args.owner,
1154
+ due_date: args.due_date,
1155
+ capability_action: args.capability_action,
1156
+ created_at: args.created_at ?? new Date().toISOString(),
1157
+ };
1158
+ store.append(report);
1159
+ return {
1160
+ content: [{ type: "text", text: JSON.stringify({ recorded: true, escape_id: report.escape_id }, null, 2) }],
1161
+ };
1162
+ });
1163
+ // ── sf_capability_update: 根据复盘结果更新 Capability Registry ──
1164
+ const CapabilityUpdateSchema = {
1165
+ policy_id: z.string().describe("要更新的 policy ID(如 CAP-003)"),
1166
+ target_state: z.enum(["enforced", "advisory", "experimental", "removed"]).describe("目标状态"),
1167
+ reason: z.string().describe("变更原因"),
1168
+ evidence_ids: z.array(z.string()).describe("支撑此变更的 escape report ID 列表"),
1169
+ confirmed_by: z.string().describe("人工确认者标识(如操作者名字)"),
1170
+ dry_run: z.boolean().optional().describe("dry_run 模式:只校验不持久化(默认 false)"),
1171
+ confirm: z.boolean().describe("人工确认标志,必须为 true 才能执行变更"),
1172
+ };
1173
+ registerSafeTool("sf_capability_update", "根据复盘结果更新 Capability Registry 状态。支持 dry_run 校验、证据校验、人工确认。不会自动触发,必须显式调用", CapabilityUpdateSchema, async (args) => {
1174
+ const stateDir = taskContext.getStateDir();
1175
+ const escapeStore = new EscapeReportStore(stateDir);
1176
+ const stateStore = new CapabilityStateStore(stateDir);
1177
+ const escapeReports = escapeStore.list();
1178
+ const capabilities = getAllCapabilities();
1179
+ const cap = capabilities.find((c) => c.policy_id === args.policy_id);
1180
+ const currentState = stateStore.getEffectiveState(args.policy_id, cap?.state ?? "experimental");
1181
+ const result = stateStore.apply({
1182
+ policy_id: args.policy_id,
1183
+ target_state: args.target_state,
1184
+ reason: args.reason,
1185
+ evidence_ids: args.evidence_ids,
1186
+ confirmed_by: args.confirmed_by,
1187
+ dry_run: args.dry_run ?? false,
1188
+ confirm: args.confirm,
1189
+ }, currentState, cap?.id ?? null, escapeReports);
1190
+ return {
1191
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
1192
+ };
1193
+ });
1194
+ // ── sf_governance_report: 治理健康报告 ──
1195
+ const GovernanceReportSchema = {
1196
+ seed: z.number().optional().describe("抽样种子(用于计算 sampled_count,默认 0)"),
1197
+ };
1198
+ registerSafeTool("sf_governance_report", "生成治理健康报告:汇总审计池、逃逸报告、能力动作决策。只读,不改状态", GovernanceReportSchema, async (args) => {
1199
+ const stateDir = taskContext.getStateDir();
1200
+ const seed = args.seed ?? 0;
1201
+ const pool = new AuditPool(stateDir);
1202
+ const escapeStore = new EscapeReportStore(stateDir);
1203
+ const auditItems = pool.list();
1204
+ const auditStats = pool.stats();
1205
+ const escapeReports = escapeStore.list();
1206
+ const escapeStats = escapeStore.stats();
1207
+ // Generate action decisions for all capabilities (using effective states)
1208
+ const capabilities = getAllCapabilities();
1209
+ const stateStore = new CapabilityStateStore(stateDir);
1210
+ const decisions = capabilities.map((cap) => {
1211
+ const effectiveState = stateStore.getEffectiveState(cap.policy_id, cap.state);
1212
+ return decideAction(escapeReports, effectiveState, cap.policy_id);
1213
+ });
1214
+ // Generate sample decisions for sampled_count
1215
+ const sampleResult = sampleAuditItems(auditItems, seed);
1216
+ const report = generateGovernanceReport(auditStats, auditItems, escapeReports, escapeStats, decisions, new Date(), sampleResult.decisions);
1217
+ return {
1218
+ content: [{ type: "text", text: JSON.stringify(report, null, 2) }],
1219
+ };
1220
+ });
907
1221
  }
908
1222
  //# sourceMappingURL=tools.js.map