soloforge 1.2.1 → 1.2.2

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 (50) hide show
  1. package/dist/adapters/claude_code/server.d.ts.map +1 -1
  2. package/dist/adapters/claude_code/server.js +2 -25
  3. package/dist/adapters/claude_code/server.js.map +1 -1
  4. package/dist/adapters/claude_code/tools.d.ts +8 -13
  5. package/dist/adapters/claude_code/tools.d.ts.map +1 -1
  6. package/dist/adapters/claude_code/tools.js +192 -85
  7. package/dist/adapters/claude_code/tools.js.map +1 -1
  8. package/dist/adapters/codex/codex_rules.d.ts.map +1 -1
  9. package/dist/adapters/codex/codex_rules.js +23 -1
  10. package/dist/adapters/codex/codex_rules.js.map +1 -1
  11. package/dist/bin/soloforge.js +0 -5
  12. package/dist/bin/soloforge.js.map +1 -1
  13. package/dist/engine/audit_verifier.d.ts +1 -1
  14. package/dist/engine/audit_verifier.js +1 -1
  15. package/dist/engine/audit_verifier.js.map +1 -1
  16. package/dist/engine/capability_registry.d.ts +36 -0
  17. package/dist/engine/capability_registry.d.ts.map +1 -0
  18. package/dist/engine/capability_registry.js +133 -0
  19. package/dist/engine/capability_registry.js.map +1 -0
  20. package/dist/engine/knowledge_config_loader.d.ts +1 -1
  21. package/dist/engine/knowledge_config_loader.js +1 -1
  22. package/dist/engine/llm_gateway.js +2 -2
  23. package/dist/engine/llm_gateway.js.map +1 -1
  24. package/dist/engine/task_context.js +1 -1
  25. package/dist/engine/task_context.js.map +1 -1
  26. package/dist/engine/test_quality.js +2 -2
  27. package/dist/engine/test_quality.js.map +1 -1
  28. package/dist/engine/verifier.d.ts.map +1 -1
  29. package/dist/engine/verifier.js +91 -19
  30. package/dist/engine/verifier.js.map +1 -1
  31. package/dist/types.d.ts +0 -84
  32. package/dist/types.d.ts.map +1 -1
  33. package/package.json +1 -1
  34. package/templates/knowledge/domain//345/256/241/350/256/241/346/227/245/345/277/227.md +6 -7
  35. package/templates/knowledge/domain//345/257/274/345/205/245/345/257/274/345/207/272/350/247/204/345/210/231.md +3 -3
  36. package/templates/knowledge/domain//351/200/232/347/224/250/346/234/272/346/242/260/346/235/241/346/254/276.md +24 -14
  37. package/templates/knowledge/procedures//347/264/247/346/200/245/344/277/256/345/244/215/346/265/201/346/260/264/347/272/277.md +1 -1
  38. package/templates/knowledge/procedures//347/264/247/346/200/245/344/277/256/345/244/215/346/265/201/347/250/213.md +1 -1
  39. package/templates/knowledge/review_rules//345/271/266/345/217/221/345/256/241/346/237/245/350/247/204/345/210/231.md +1 -1
  40. package/templates/knowledge/review_rules//346/200/247/350/203/275/345/256/241/346/237/245/350/247/204/345/210/231.md +1 -1
  41. package/templates/knowledge/review_rules//346/216/245/345/217/243/345/245/221/347/272/246/345/256/241/346/237/245/350/247/204/345/210/231.md +1 -1
  42. package/templates/knowledge/review_rules//346/236/266/346/236/204/345/256/241/346/237/245/350/247/204/345/210/231.md +1 -1
  43. package/templates/knowledge/review_rules//350/264/250/351/207/217/345/256/241/346/237/245/350/247/204/345/210/231.md +1 -1
  44. /package/templates/knowledge/checklists/{session_recovery.md → /344/274/232/350/257/235/346/201/242/345/244/215.md"} +0 -0
  45. /package/templates/knowledge/patterns/core/{decision_gateway.md → /345/206/263/347/255/226/347/275/221/345/205/263.md"} +0 -0
  46. /package/templates/knowledge/patterns/core/{mutation_audit.md → /345/217/230/345/274/202/345/256/241/350/256/241.md"} +0 -0
  47. /package/templates/knowledge/patterns/core/{concurrency_lock.md → /345/271/266/345/217/221/351/224/201.md"} +0 -0
  48. /package/templates/knowledge/patterns/core/{developer_constitution.md → /345/274/200/345/217/221/350/200/205/345/256/252/346/263/225.md"} +0 -0
  49. /package/templates/knowledge/patterns/core/{streaming_protocol.md → /346/265/201/345/274/217/345/277/203/350/267/263.md"} +0 -0
  50. /package/templates/knowledge/patterns/core/{authority.md → /347/237/245/350/257/206/344/270/273/346/235/203.md"} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/adapters/claude_code/server.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAElE;;;;;GAKG;AAEH;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,aAAa,CAAC;IACtB,cAAc,EAAE,qBAAqB,CAAC;IACtC,WAAW,EAAE,kBAAkB,CAAC;CACjC;AAqBD;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA0DjE"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/adapters/claude_code/server.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAElE;;;;;GAKG;AAEH;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,aAAa,CAAC;IACtB,cAAc,EAAE,qBAAqB,CAAC;IACtC,WAAW,EAAE,kBAAkB,CAAC;CACjC;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAwDjE"}
@@ -1,27 +1,6 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
2
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
3
  import { registerTools } from "./tools.js";
6
- /**
7
- * 检查当前项目是否为 SoloForge 自身项目(内部方法)。
8
- * @description 通过检查 package.json 中的 name 字段判断是否为 SoloForge 自身。
9
- * SoloForge 自身项目会额外注册知识维护工具(sf_knowledge_audit/add/update)。
10
- * @param config - 项目配置对象
11
- * @returns 是否为 SoloForge 自身项目
12
- */
13
- function isSoloForgeProject(config) {
14
- const projectPath = config._projectPath || process.cwd();
15
- try {
16
- const pkgPath = path.join(projectPath, "package.json");
17
- const raw = fs.readFileSync(pkgPath, "utf-8");
18
- const pkg = JSON.parse(raw);
19
- return pkg.name === "soloforge";
20
- }
21
- catch {
22
- return false;
23
- }
24
- }
25
4
  /**
26
5
  * 启动 SoloForge MCP 服务器。
27
6
  * @description 创建 McpServer 实例,注册工具,通过 stdio 传输连接 Claude Code,
@@ -32,11 +11,9 @@ export async function startServer(deps) {
32
11
  const { config, knowledgeIndex, taskContext } = deps;
33
12
  const server = new McpServer({
34
13
  name: "soloforge",
35
- version: "0.1.0",
36
- });
37
- registerTools(server, { config, knowledgeIndex, taskContext }, {
38
- isSelfProject: isSoloForgeProject(config),
14
+ version: "1.2.1",
39
15
  });
16
+ registerTools(server, { config, knowledgeIndex, taskContext });
40
17
  const transport = new StdioServerTransport();
41
18
  await server.connect(transport);
42
19
  let shuttingDown = false;
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/adapters/claude_code/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/adapters/claude_code/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAsB3C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAgB;IAChD,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IAErD,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,aAAa,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;IAE/D,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,4BAA4B;IAC5B,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QAC1B,IAAI,YAAY;YAAE,OAAO;QACzB,YAAY,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC;YACH,IAAI,cAAc;gBAAE,MAAM,cAAc,CAAC,KAAK,EAAE,CAAC;YACjD,MAAM,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC;QAC5B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;QAClC,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/B,8BAA8B;IAC9B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;QACzB,QAAQ,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,uBAAuB;IACvB,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QAC5C,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;QACvC,IAAI,CAAC;YACH,IAAI,cAAc;gBAAE,MAAM,cAAc,CAAC,KAAK,EAAE,CAAC;YACjD,MAAM,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC;QAC5B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;QAClC,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IACH,8BAA8B;IAC9B,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QAChD,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,MAAM,CAAC,CAAC;QACpD,IAAI,CAAC;YACH,IAAI,cAAc;gBAAE,MAAM,cAAc,CAAC,KAAK,EAAE,CAAC;YACjD,MAAM,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC;QAC5B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;QAClC,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -2,17 +2,18 @@ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import type { ProjectConfig } from "../../types.js";
3
3
  import type { KnowledgeIndexManager } from "../../knowledge/index_manager.js";
4
4
  import type { TaskContextManager } from "../../engine/task_context.js";
5
+ import { LLMGateway } from "../../engine/llm_gateway.js";
5
6
  /**
6
7
  * MCP 工具注册模块。
7
8
  * @description 将 SoloForge 的全部功能封装为 MCP 工具,注册到 McpServer 实例。
8
9
  * 每个工具通过统一的错误处理包装器(registerSafeTool)注册,确保异常不会导致服务崩溃。
9
10
  * 工具分为三类:核心流程工具(classify/expand/verify/learn/status)、
10
- * 辅助工具(plan/review/scaffold/deliver 等)、自维护工具(knowledge_audit/add/update)。
11
- * 自维护工具仅在 SoloForge 自身项目中注册。
11
+ * 辅助工具(plan/review/scaffold/deliver 等)、知识维护工具(knowledge_audit/add/update/resume_workspace)。
12
+ * 所有工具在所有项目中均注册。
12
13
  */
13
14
  /**
14
15
  * SoloForge 核心依赖项。
15
- * @description 封装所有 MCP 工具共享的依赖:项目配置、知识索引和任务上下文。
16
+ * @description 封装所有 MCP 工具共享的依赖:项目配置、知识索引、任务上下文和可选的 LLM 网关。
16
17
  */
17
18
  export interface SoloForgeDeps {
18
19
  /** 项目配置对象 */
@@ -21,13 +22,8 @@ export interface SoloForgeDeps {
21
22
  knowledgeIndex: KnowledgeIndexManager;
22
23
  /** 任务上下文管理器 */
23
24
  taskContext: TaskContextManager;
24
- }
25
- /**
26
- * 工具注册选项。
27
- */
28
- export interface RegisterToolsOptions {
29
- /** 是否为 SoloForge 自身项目(true 时注册自维护工具) */
30
- isSelfProject?: boolean;
25
+ /** 可选的 LLM 网关(测试时注入 depleted gateway 以验证 H1 advisory) */
26
+ gateway?: LLMGateway;
31
27
  }
32
28
  /**
33
29
  * 注册所有 SoloForge MCP 工具。
@@ -37,10 +33,9 @@ export interface RegisterToolsOptions {
37
33
  * sf_deliver、sf_coord_check、sf_team_status、sf_contract_check、
38
34
  * sf_onboard、sf_feasibility_check、sf_debug、sf_observability、
39
35
  * sf_migration_check、sf_test_guide、sf_test_quality、sf_dependency_scan、
40
- * sf_debt_report,以及条件注册的 sf_knowledge_audit/add/update。
36
+ * sf_debt_report、sf_explore、sf_knowledge_audit/add/update、sf_resume_workspace
41
37
  * @param server - MCP 服务器实例
42
38
  * @param deps - SoloForge 核心依赖项
43
- * @param options - 注册选项(控制自维护工具是否注册)
44
39
  */
45
- export declare function registerTools(server: McpServer, deps: SoloForgeDeps, options?: RegisterToolsOptions): void;
40
+ export declare function registerTools(server: McpServer, deps: SoloForgeDeps): void;
46
41
  //# sourceMappingURL=tools.d.ts.map
@@ -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,EAAkB,MAAM,gBAAgB,CAAC;AACpE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AA8BvE;;;;;;;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;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,wCAAwC;IACxC,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAuHD;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,IAAI,CA+5B1G"}
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"}
@@ -25,6 +25,9 @@ import { scanDependencies } from "../../engine/dependency_scanner.js";
25
25
  import { generateDebtReport } from "../../engine/debt_reporter.js";
26
26
  import { exploreSolutions } from "../../engine/exploration.js";
27
27
  import { scanAndResume } from "../../engine/workspace_resumer.js";
28
+ import { LLMGateway } from "../../engine/llm_gateway.js";
29
+ import { IOController } from "../../engine/io_controller.js";
30
+ import { getSummary as getCapabilitySummary } from "../../engine/capability_registry.js";
28
31
  // ── Zod Schema 定义 ──
29
32
  const ClassifySchema = {
30
33
  intent: z.string().describe("开发者意图描述"),
@@ -126,14 +129,17 @@ const ExploreSchema = {
126
129
  * sf_deliver、sf_coord_check、sf_team_status、sf_contract_check、
127
130
  * sf_onboard、sf_feasibility_check、sf_debug、sf_observability、
128
131
  * sf_migration_check、sf_test_guide、sf_test_quality、sf_dependency_scan、
129
- * sf_debt_report,以及条件注册的 sf_knowledge_audit/add/update。
132
+ * sf_debt_report、sf_explore、sf_knowledge_audit/add/update、sf_resume_workspace
130
133
  * @param server - MCP 服务器实例
131
134
  * @param deps - SoloForge 核心依赖项
132
- * @param options - 注册选项(控制自维护工具是否注册)
133
135
  */
134
- export function registerTools(server, deps, options) {
136
+ export function registerTools(server, deps) {
135
137
  const { config, knowledgeIndex, taskContext } = deps;
136
138
  const projectPath = config._projectPath || process.cwd();
139
+ // H1: LLM Gateway — Token 预算熔断,防止单任务 Token 超支
140
+ const gateway = deps.gateway ?? new LLMGateway();
141
+ // H4: IO Controller — 工作区互斥锁,防止外部修改导致的静默覆盖
142
+ const ioController = new IOController(projectPath);
137
143
  // 统一错误处理包装器,捕获工具执行中的异常并返回结构化错误响应
138
144
  function registerSafeTool(name, desc, schema, handler) {
139
145
  server.tool(name, desc, schema, async (args) => {
@@ -173,8 +179,9 @@ export function registerTools(server, deps, options) {
173
179
  const classification = classify(input);
174
180
  // 存储分类结果
175
181
  await taskContext.setClassification(ctx.task_id, classification);
176
- // 转换到膨胀阶段
177
- await taskContext.updateStatus(ctx.task_id, "expanding");
182
+ if (classification.strategy === "skip_soloForge") {
183
+ await taskContext.updateStatus(ctx.task_id, "done");
184
+ }
178
185
  return {
179
186
  content: [{
180
187
  type: "text",
@@ -194,6 +201,16 @@ export function registerTools(server, deps, options) {
194
201
  isError: true,
195
202
  };
196
203
  }
204
+ // 状态守卫:classifying → expanding 或允许 expanding 恢复(中断重试)
205
+ if (ctx.status === "classifying") {
206
+ await taskContext.updateStatus(args.task_id, "expanding");
207
+ }
208
+ else if (ctx.status !== "expanding") {
209
+ return {
210
+ content: [{ type: "text", text: JSON.stringify({ error: `任务状态 ${ctx.status} 不可膨胀,需要 classifying 或 expanding`, status: ctx.status }) }],
211
+ isError: true,
212
+ };
213
+ }
197
214
  // 构建计划上下文(如果存在计划)
198
215
  let planContext;
199
216
  if (ctx.planning && ctx.planning.sub_tasks.length > 0 && ctx.planning.current_step_index < ctx.planning.sub_tasks.length) {
@@ -215,24 +232,88 @@ export function registerTools(server, deps, options) {
215
232
  }
216
233
  planContext = { current_step: currentStep, previous_outputs: previousOutputs };
217
234
  }
218
- const expansion = await expand({
219
- intent: ctx.intent,
220
- classification: ctx.classification,
221
- projectPath,
222
- config,
223
- knowledgeIndex,
224
- clarificationAnswers: args.clarification_answers,
225
- plan_context: planContext,
226
- });
235
+ // H1: Token 预算检查 — advisory 模式,仅警告不阻断
236
+ gateway.beginTask(args.task_id);
237
+ let h1Warning;
238
+ try {
239
+ const gateResult = gateway.request("solution_brainstorm");
240
+ if (!gateResult.allowed) {
241
+ h1Warning = { warning: `H1 advisory: ${gateResult.reason}`, budget_remaining: gateResult.remaining_budget };
242
+ }
243
+ }
244
+ catch (e) {
245
+ h1Warning = { warning: `H1 advisory: ${e.message}`, budget_remaining: 0 };
246
+ }
247
+ // H4: advisory-only — 不获取持久锁,仅检查当前锁定状态
248
+ let h4LockWarning;
249
+ const lockStatus = await ioController.isLocked();
250
+ if (lockStatus.locked && lockStatus.task_id !== args.task_id) {
251
+ h4LockWarning = `H4 advisory: 工作区已被任务 ${lockStatus.task_id} 锁定(${lockStatus.reason ?? "未知"}),当前 H4 未进入强制层`;
252
+ }
253
+ let expansion;
254
+ try {
255
+ expansion = await expand({
256
+ intent: ctx.intent,
257
+ classification: ctx.classification,
258
+ projectPath,
259
+ config,
260
+ knowledgeIndex,
261
+ clarificationAnswers: args.clarification_answers,
262
+ plan_context: planContext,
263
+ });
264
+ }
265
+ catch (expandErr) {
266
+ // 尝试回退到 failed 状态,避免任务停留在 expanding
267
+ try {
268
+ await taskContext.updateStatus(args.task_id, "failed");
269
+ }
270
+ catch {
271
+ // 状态转换非法(如已非 expanding),忽略
272
+ }
273
+ throw expandErr;
274
+ }
275
+ finally {
276
+ if (!h1Warning)
277
+ gateway.completeOperation();
278
+ gateway.endTask();
279
+ }
227
280
  expansion.task_id = args.task_id;
281
+ // 注入 H1/H4 advisory warnings
282
+ const advisories = {};
283
+ if (h1Warning)
284
+ advisories.h1_advisory = h1Warning;
285
+ if (h4LockWarning)
286
+ advisories.h4_advisory = h4LockWarning;
228
287
  // 存储膨胀结果
229
- await taskContext.setExpansion(args.task_id, expansion);
288
+ try {
289
+ await taskContext.setExpansion(args.task_id, expansion);
290
+ }
291
+ catch (setErr) {
292
+ try {
293
+ await taskContext.updateStatus(args.task_id, "failed");
294
+ }
295
+ catch {
296
+ // 状态转换非法,忽略
297
+ }
298
+ throw setErr;
299
+ }
230
300
  // 转换到执行阶段
231
- await taskContext.updateStatus(args.task_id, "executing");
301
+ try {
302
+ await taskContext.updateStatus(args.task_id, "executing");
303
+ }
304
+ catch (updateErr) {
305
+ try {
306
+ await taskContext.updateStatus(args.task_id, "failed");
307
+ }
308
+ catch {
309
+ // 状态转换非法,忽略
310
+ }
311
+ throw updateErr;
312
+ }
232
313
  return {
233
314
  content: [{
234
315
  type: "text",
235
- text: JSON.stringify(expansion, null, 2),
316
+ text: JSON.stringify(Object.keys(advisories).length > 0 ? { ...expansion, advisories } : expansion, null, 2),
236
317
  }],
237
318
  };
238
319
  });
@@ -245,9 +326,21 @@ export function registerTools(server, deps, options) {
245
326
  isError: true,
246
327
  };
247
328
  }
329
+ const VALID_VERIFY_STATES = ["executing", "retrying"];
330
+ if (!VALID_VERIFY_STATES.includes(ctx.status)) {
331
+ return {
332
+ content: [{ type: "text", text: JSON.stringify({ error: `任务状态 ${ctx.status} 不可验证,需要 executing 或 retrying`, status: ctx.status }) }],
333
+ isError: true,
334
+ };
335
+ }
248
336
  const acceptanceItems = ctx.expansion
249
337
  ? [...ctx.expansion.acceptance.automated, ...ctx.expansion.acceptance.manual]
250
338
  : [];
339
+ // H4: 工作区完整性检查 — advisory 模式,仅警告不阻断
340
+ const integrity = await ioController.verify();
341
+ const h4Warning = !integrity.clean
342
+ ? { warning: `H4 advisory: ${integrity.message}`, dirty_files: integrity.dirty_files }
343
+ : undefined;
251
344
  const verifyResult = generateVerifyCommands(config, args.changed_files, acceptanceItems);
252
345
  verifyResult.task_id = args.task_id;
253
346
  // 记录变更文件
@@ -259,7 +352,7 @@ export function registerTools(server, deps, options) {
259
352
  return {
260
353
  content: [{
261
354
  type: "text",
262
- text: JSON.stringify(verifyResult, null, 2),
355
+ text: JSON.stringify(h4Warning ? { ...verifyResult, h4_advisory: h4Warning } : verifyResult, null, 2),
263
356
  }],
264
357
  };
265
358
  });
@@ -272,6 +365,13 @@ export function registerTools(server, deps, options) {
272
365
  isError: true,
273
366
  };
274
367
  }
368
+ const VALID_LEARN_STATES = ["verifying", "executing"];
369
+ if (!VALID_LEARN_STATES.includes(ctx.status)) {
370
+ return {
371
+ content: [{ type: "text", text: JSON.stringify({ error: `任务状态 ${ctx.status} 不可学习,需要 verifying 或 executing`, status: ctx.status }) }],
372
+ isError: true,
373
+ };
374
+ }
275
375
  // 如适用,记录失败
276
376
  if (args.result === "failure" && args.failure_type) {
277
377
  await taskContext.setExecution(args.task_id, [], {
@@ -574,6 +674,11 @@ export function registerTools(server, deps, options) {
574
674
  isError: true,
575
675
  };
576
676
  }
677
+ // H4: 交付前工作区完整性检查 — advisory 模式,仅警告不阻断
678
+ const deliverIntegrity = await ioController.verify();
679
+ const h4DeliverWarning = !deliverIntegrity.clean
680
+ ? { warning: `H4 advisory: ${deliverIntegrity.message}`, dirty_files: deliverIntegrity.dirty_files }
681
+ : undefined;
577
682
  const result = await deliver({
578
683
  taskContext: ctx,
579
684
  config,
@@ -585,7 +690,10 @@ export function registerTools(server, deps, options) {
585
690
  });
586
691
  await taskContext.setDelivery(args.task_id, result);
587
692
  return {
588
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
693
+ content: [{
694
+ type: "text",
695
+ text: JSON.stringify(h4DeliverWarning ? { ...result, h4_advisory: h4DeliverWarning } : result, null, 2),
696
+ }],
589
697
  };
590
698
  });
591
699
  // ── sf_coord_check: 预测性冲突检测和跨仓库协调 ──
@@ -670,11 +778,13 @@ export function registerTools(server, deps, options) {
670
778
  };
671
779
  });
672
780
  // ── sf_observability: 系统可观测和运行报告 ──
673
- registerSafeTool("sf_observability", "系统可观测:运行指标、成本估算、告警检测、周期报告", ObservabilitySchema, async (args) => {
781
+ registerSafeTool("sf_observability", "系统可观测:运行指标、成本估算、告警检测、能力状态、周期报告", ObservabilitySchema, async (args) => {
674
782
  const stateDir = taskContext.getStateDir();
675
783
  const result = await generateReport(stateDir, args.period_days);
784
+ const capability = getCapabilitySummary();
785
+ const output = { ...result, capability };
676
786
  return {
677
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
787
+ content: [{ type: "text", text: JSON.stringify(output, null, 2) }],
678
788
  };
679
789
  });
680
790
  // ── sf_migration_check: 数据库迁移安全性分析 ──
@@ -730,72 +840,69 @@ export function registerTools(server, deps, options) {
730
840
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
731
841
  };
732
842
  });
733
- // ── 自维护工具(仅在 SoloForge 自身项目中注册) ──
734
- if (options?.isSelfProject) {
735
- // ── sf_knowledge_audit: 知识库健康审计 ──
736
- registerSafeTool("sf_knowledge_audit", "审计知识库:识别过时条目、重复触发词、格式缺失、覆盖缺口。定期执行或手动触发", {}, async () => {
737
- const result = await auditKnowledge(knowledgeIndex, config);
738
- return {
739
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
740
- };
741
- });
742
- // ── sf_knowledge_add: 新增知识条目(默认保存为草稿) ──
743
- const KnowledgeAddSchema = {
744
- title: z.string().describe("知识条目标题(英文 kebab-case,如 payment-rules)"),
745
- type: z.enum(["pattern", "procedure", "pipeline_procedure", "domain", "acceptance_template", "review_rule"]).describe("知识类型"),
746
- scope: z.array(z.string()).describe("适用范围(如 [backend]、[frontend]、[backend, frontend])"),
747
- when_triggers: z.string().describe("触发关键词(逗号分隔)"),
748
- decision_rules: z.string().optional().describe("决策规则(每行一条)"),
749
- save_to_drafts: z.boolean().optional().describe("是否保存为草稿(默认 true,需人工 review 后移入正式目录)"),
750
- auto_enrich: z.boolean().optional().describe("是否返回行业最佳实践探索指引(默认 true,宿主 AI 将自动执行探索并填充内容)"),
843
+ // ── sf_knowledge_audit: 知识库健康审计 ──
844
+ registerSafeTool("sf_knowledge_audit", "审计知识库:识别过时条目、重复触发词、格式缺失、覆盖缺口。定期执行或手动触发", {}, async () => {
845
+ const result = await auditKnowledge(knowledgeIndex, config);
846
+ return {
847
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
751
848
  };
752
- registerSafeTool("sf_knowledge_add", "新增知识条目。默认保存为草稿到 .soloforge/knowledge/drafts/,人工确认后移入正式目录", KnowledgeAddSchema, async (args) => {
753
- const result = await addKnowledge({
754
- title: args.title,
755
- type: args.type,
756
- scope: args.scope,
849
+ });
850
+ // ── sf_knowledge_add: 新增知识条目(默认保存为草稿) ──
851
+ const KnowledgeAddSchema = {
852
+ title: z.string().describe("知识条目标题(英文 kebab-case,如 payment-rules)"),
853
+ type: z.enum(["pattern", "procedure", "pipeline_procedure", "domain", "acceptance_template", "review_rule"]).describe("知识类型"),
854
+ scope: z.array(z.string()).describe("适用范围(如 [backend]、[frontend]、[backend, frontend])"),
855
+ when_triggers: z.string().describe("触发关键词(逗号分隔)"),
856
+ decision_rules: z.string().optional().describe("决策规则(每行一条)"),
857
+ save_to_drafts: z.boolean().optional().describe("是否保存为草稿(默认 true,需人工 review 后移入正式目录)"),
858
+ auto_enrich: z.boolean().optional().describe("是否返回行业最佳实践探索指引(默认 true,宿主 AI 将自动执行探索并填充内容)"),
859
+ };
860
+ registerSafeTool("sf_knowledge_add", "新增知识条目。默认保存为草稿到 .soloforge/knowledge/drafts/,人工确认后移入正式目录", KnowledgeAddSchema, async (args) => {
861
+ const result = await addKnowledge({
862
+ title: args.title,
863
+ type: args.type,
864
+ scope: args.scope,
865
+ when_triggers: args.when_triggers,
866
+ decision_rules: args.decision_rules,
867
+ save_to_drafts: args.save_to_drafts,
868
+ auto_enrich: args.auto_enrich,
869
+ }, config);
870
+ return {
871
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
872
+ };
873
+ });
874
+ // ── sf_knowledge_update: 更新已有知识条目(自动创建备份) ──
875
+ const KnowledgeUpdateSchema = {
876
+ entry_name: z.string().describe("要更新的知识条目名称(如 payment-rules)"),
877
+ when_triggers: z.string().optional().describe("新的触发关键词(替换现有)"),
878
+ add_decision_rules: z.array(z.string()).optional().describe("追加的决策规则"),
879
+ add_acceptance_criteria: z.array(z.string()).optional().describe("追加的验收项"),
880
+ status: z.enum(["active", "deprecated"]).optional().describe("更新条目状态"),
881
+ };
882
+ registerSafeTool("sf_knowledge_update", "更新已有知识条目:追加规则、更新触发词、标记废弃。自动创建备份", KnowledgeUpdateSchema, async (args) => {
883
+ const result = await updateKnowledge({
884
+ entry_name: args.entry_name,
885
+ updates: {
757
886
  when_triggers: args.when_triggers,
758
- decision_rules: args.decision_rules,
759
- save_to_drafts: args.save_to_drafts,
760
- auto_enrich: args.auto_enrich,
761
- }, config);
762
- return {
763
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
764
- };
765
- });
766
- // ── sf_knowledge_update: 更新已有知识条目(自动创建备份) ──
767
- const KnowledgeUpdateSchema = {
768
- entry_name: z.string().describe("要更新的知识条目名称(如 payment-rules)"),
769
- when_triggers: z.string().optional().describe("新的触发关键词(替换现有)"),
770
- add_decision_rules: z.array(z.string()).optional().describe("追加的决策规则"),
771
- add_acceptance_criteria: z.array(z.string()).optional().describe("追加的验收项"),
772
- status: z.enum(["active", "deprecated"]).optional().describe("更新条目状态"),
887
+ add_decision_rules: args.add_decision_rules,
888
+ add_acceptance_criteria: args.add_acceptance_criteria,
889
+ status: args.status,
890
+ },
891
+ }, knowledgeIndex, config);
892
+ // 重载知识索引
893
+ if (result.success) {
894
+ await knowledgeIndex.reload();
895
+ }
896
+ return {
897
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
773
898
  };
774
- registerSafeTool("sf_knowledge_update", "更新已有知识条目:追加规则、更新触发词、标记废弃。自动创建备份", KnowledgeUpdateSchema, async (args) => {
775
- const result = await updateKnowledge({
776
- entry_name: args.entry_name,
777
- updates: {
778
- when_triggers: args.when_triggers,
779
- add_decision_rules: args.add_decision_rules,
780
- add_acceptance_criteria: args.add_acceptance_criteria,
781
- status: args.status,
782
- },
783
- }, knowledgeIndex, config);
784
- // 重载知识索引
785
- if (result.success) {
786
- await knowledgeIndex.reload();
787
- }
788
- return {
789
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
790
- };
791
- });
792
- // ── sf_resume_workspace: 工作区状态唤醒(解决前端刷新导致UUID丢失) ──
793
- registerSafeTool("sf_resume_workspace", "扫描 .soloforge/state/ 目录,恢复中断工单并播报当前进度。新会话启动时必须优先调用", {}, async () => {
794
- const result = await scanAndResume(taskContext);
795
- return {
796
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
797
- };
798
- });
799
- } // end isSelfProject guard
899
+ });
900
+ // ── sf_resume_workspace: 工作区状态唤醒(解决前端刷新导致UUID丢失) ──
901
+ registerSafeTool("sf_resume_workspace", "扫描 .soloforge/state/ 目录,恢复中断工单并播报当前进度。新会话启动时必须优先调用", {}, async () => {
902
+ const result = await scanAndResume(taskContext);
903
+ return {
904
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
905
+ };
906
+ });
800
907
  }
801
908
  //# sourceMappingURL=tools.js.map