soloforge 1.1.40 → 1.1.42

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 +57 -0
  2. package/dist/adapters/shared/workflow_template.js +1 -1
  3. package/dist/bin/commands/check_write.d.ts +1 -1
  4. package/dist/bin/commands/check_write.d.ts.map +1 -1
  5. package/dist/bin/commands/check_write.js +13 -34
  6. package/dist/bin/commands/check_write.js.map +1 -1
  7. package/dist/bin/commands/modify.d.ts +2 -1
  8. package/dist/bin/commands/modify.d.ts.map +1 -1
  9. package/dist/bin/commands/modify.js +29 -15
  10. package/dist/bin/commands/modify.js.map +1 -1
  11. package/dist/bin/commands/review.d.ts +3 -2
  12. package/dist/bin/commands/review.d.ts.map +1 -1
  13. package/dist/bin/commands/review.js +179 -46
  14. package/dist/bin/commands/review.js.map +1 -1
  15. package/dist/bin/soloforge.js +0 -18
  16. package/dist/bin/soloforge.js.map +1 -1
  17. package/dist/engine/context_engine/companion_injector.d.ts +16 -3
  18. package/dist/engine/context_engine/companion_injector.d.ts.map +1 -1
  19. package/dist/engine/context_engine/companion_injector.js +228 -35
  20. package/dist/engine/context_engine/companion_injector.js.map +1 -1
  21. package/dist/engine/contracts/artifact_contract_registry.d.ts +1 -43
  22. package/dist/engine/contracts/artifact_contract_registry.d.ts.map +1 -1
  23. package/dist/engine/contracts/artifact_contract_registry.js +24 -100
  24. package/dist/engine/contracts/artifact_contract_registry.js.map +1 -1
  25. package/dist/engine/contracts/artifact_process_rules.d.ts.map +1 -1
  26. package/dist/engine/contracts/artifact_process_rules.js +0 -12
  27. package/dist/engine/contracts/artifact_process_rules.js.map +1 -1
  28. package/dist/engine/contracts/artifact_schema_registry.d.ts.map +1 -1
  29. package/dist/engine/contracts/artifact_schema_registry.js +0 -24
  30. package/dist/engine/contracts/artifact_schema_registry.js.map +1 -1
  31. package/dist/engine/contracts/tool_invocation_contract_registry.d.ts +29 -0
  32. package/dist/engine/contracts/tool_invocation_contract_registry.d.ts.map +1 -1
  33. package/dist/engine/contracts/tool_invocation_contract_registry.js +32 -21
  34. package/dist/engine/contracts/tool_invocation_contract_registry.js.map +1 -1
  35. package/dist/engine/core/paths.d.ts +0 -2
  36. package/dist/engine/core/paths.d.ts.map +1 -1
  37. package/dist/engine/core/paths.js +0 -2
  38. package/dist/engine/core/paths.js.map +1 -1
  39. package/dist/engine/knowledge/knowledge_writer.js +1 -1
  40. package/dist/engine/pipeline/artifact_aliases.d.ts +56 -3
  41. package/dist/engine/pipeline/artifact_aliases.d.ts.map +1 -1
  42. package/dist/engine/pipeline/artifact_aliases.js +377 -24
  43. package/dist/engine/pipeline/artifact_aliases.js.map +1 -1
  44. package/dist/engine/pipeline/artifact_resolver.d.ts +82 -0
  45. package/dist/engine/pipeline/artifact_resolver.d.ts.map +1 -0
  46. package/dist/engine/pipeline/artifact_resolver.js +458 -0
  47. package/dist/engine/pipeline/artifact_resolver.js.map +1 -0
  48. package/dist/engine/pipeline/intent_expander/knowledge_resolution.d.ts +2 -2
  49. package/dist/engine/pipeline/intent_expander/knowledge_resolution.d.ts.map +1 -1
  50. package/dist/engine/pipeline/intent_expander/knowledge_resolution.js.map +1 -1
  51. package/dist/engine/pipeline/orchestrate_single_artifact.d.ts +185 -0
  52. package/dist/engine/pipeline/orchestrate_single_artifact.d.ts.map +1 -0
  53. package/dist/engine/pipeline/orchestrate_single_artifact.js +772 -0
  54. package/dist/engine/pipeline/orchestrate_single_artifact.js.map +1 -0
  55. package/dist/engine/pipeline/scope_resolver.js +1 -1
  56. package/dist/engine/pipeline/scope_resolver.js.map +1 -1
  57. package/dist/engine/pipeline/state_machine/certainty_gate.d.ts.map +1 -1
  58. package/dist/engine/pipeline/state_machine/certainty_gate.js +122 -9
  59. package/dist/engine/pipeline/state_machine/certainty_gate.js.map +1 -1
  60. package/dist/engine/pipeline/state_machine/pipeline_state_machine.d.ts +1 -13
  61. package/dist/engine/pipeline/state_machine/pipeline_state_machine.d.ts.map +1 -1
  62. package/dist/engine/pipeline/state_machine/pipeline_state_machine.js +65 -73
  63. package/dist/engine/pipeline/state_machine/pipeline_state_machine.js.map +1 -1
  64. package/dist/engine/pipeline/state_machine/sf_command_parser.d.ts.map +1 -1
  65. package/dist/engine/pipeline/state_machine/sf_command_parser.js +24 -19
  66. package/dist/engine/pipeline/state_machine/sf_command_parser.js.map +1 -1
  67. package/dist/engine/pipeline/state_machine/stage_command_registry.d.ts.map +1 -1
  68. package/dist/engine/pipeline/state_machine/stage_command_registry.js +7 -0
  69. package/dist/engine/pipeline/state_machine/stage_command_registry.js.map +1 -1
  70. package/dist/engine/pipeline/state_machine/stage_executor.d.ts.map +1 -1
  71. package/dist/engine/pipeline/state_machine/stage_executor.js +5 -11
  72. package/dist/engine/pipeline/state_machine/stage_executor.js.map +1 -1
  73. package/dist/engine/pipeline/state_machine/static_route_table.d.ts +2 -0
  74. package/dist/engine/pipeline/state_machine/static_route_table.d.ts.map +1 -1
  75. package/dist/engine/pipeline/state_machine/static_route_table.js +2 -0
  76. package/dist/engine/pipeline/state_machine/static_route_table.js.map +1 -1
  77. package/dist/engine/pipeline/state_machine/uncertainty_bridge.d.ts +25 -0
  78. package/dist/engine/pipeline/state_machine/uncertainty_bridge.d.ts.map +1 -1
  79. package/dist/engine/pipeline/state_machine/uncertainty_bridge.js +18 -0
  80. package/dist/engine/pipeline/state_machine/uncertainty_bridge.js.map +1 -1
  81. package/dist/engine/pipeline/target_classifier.d.ts +48 -0
  82. package/dist/engine/pipeline/target_classifier.d.ts.map +1 -0
  83. package/dist/engine/pipeline/target_classifier.js +129 -0
  84. package/dist/engine/pipeline/target_classifier.js.map +1 -0
  85. package/dist/engine/pipeline/task_planner.js +1 -1
  86. package/dist/engine/pipeline/task_planner.js.map +1 -1
  87. package/dist/engine/release/foundation_scenario_registry.js +1 -1
  88. package/dist/engine/release/foundation_scenario_registry.js.map +1 -1
  89. package/dist/engine/templates/asset_manifest.d.ts.map +1 -1
  90. package/dist/engine/templates/asset_manifest.js +1 -0
  91. package/dist/engine/templates/asset_manifest.js.map +1 -1
  92. package/dist/engine/templates/explicit_asset_registry/rules_shared.d.ts.map +1 -1
  93. package/dist/engine/templates/explicit_asset_registry/rules_shared.js +22 -0
  94. package/dist/engine/templates/explicit_asset_registry/rules_shared.js.map +1 -1
  95. package/dist/server/tools/cep_assessment.d.ts +6 -0
  96. package/dist/server/tools/cep_assessment.d.ts.map +1 -1
  97. package/dist/server/tools/cep_assessment.js +23 -0
  98. package/dist/server/tools/cep_assessment.js.map +1 -1
  99. package/dist/server/tools/middleware.d.ts.map +1 -1
  100. package/dist/server/tools/middleware.js +78 -1
  101. package/dist/server/tools/middleware.js.map +1 -1
  102. package/dist/server/tools/tool_groups/product_operations.d.ts +5 -3
  103. package/dist/server/tools/tool_groups/product_operations.d.ts.map +1 -1
  104. package/dist/server/tools/tool_groups/product_operations.js +5 -105
  105. package/dist/server/tools/tool_groups/product_operations.js.map +1 -1
  106. package/dist/server/tools/tool_groups/state_machine.d.ts +34 -3
  107. package/dist/server/tools/tool_groups/state_machine.d.ts.map +1 -1
  108. package/dist/server/tools/tool_groups/state_machine.js +454 -236
  109. package/dist/server/tools/tool_groups/state_machine.js.map +1 -1
  110. package/dist/server/tools/tool_names.d.ts +0 -3
  111. package/dist/server/tools/tool_names.d.ts.map +1 -1
  112. package/dist/server/tools/tool_names.js +1 -4
  113. package/dist/server/tools/tool_names.js.map +1 -1
  114. package/dist/types/state_machine.d.ts +28 -1
  115. package/dist/types/state_machine.d.ts.map +1 -1
  116. package/dist/types/state_machine.js +1 -1
  117. package/dist/types/state_machine.js.map +1 -1
  118. package/package.json +1 -1
  119. package/templates/artifacts/existing-system//344/270/200/351/224/256/345/274/200/345/205/263/351/205/215/347/275/256/346/250/241/347/211/210.json +2 -1
  120. package/templates/artifacts/existing-system//345/216/206/345/217/262/346/225/260/346/215/256/346/270/205/346/264/227/350/204/232/346/234/254/346/250/241/347/211/210.md +1 -0
  121. package/templates/artifacts/existing-system//345/216/206/345/217/262/351/201/227/347/225/231/351/233/267/345/214/272/346/270/205/345/215/225/346/250/241/347/211/210.md +3 -1
  122. package/templates/artifacts/existing-system//345/220/221/345/220/216/345/205/274/345/256/271/346/200/247/345/220/210/350/247/204/346/212/245/345/221/212/346/250/241/347/211/210.md +1 -0
  123. package/templates/artifacts/existing-system//345/242/236/351/207/217/350/276/271/347/225/214/347/225/214/345/256/232/346/226/207/346/241/243/346/250/241/347/211/210.md +1 -0
  124. package/templates/artifacts/existing-system//346/224/271/351/200/240/345/275/261/345/223/215/350/214/203/345/233/264/350/257/204/344/274/260/346/250/241/347/211/210.md +1 -0
  125. package/templates/artifacts/existing-system//346/225/260/346/215/256/350/241/200/347/274/230/345/233/276/346/250/241/347/211/210.md +3 -2
  126. package/templates/artifacts/existing-system//346/226/260/350/200/201/351/200/273/350/276/221/346/257/224/345/257/271/346/227/245/345/277/227/346/250/241/347/211/210.md +3 -1
  127. package/templates/artifacts/existing-system//347/264/247/346/200/245/345/233/236/346/273/232/346/211/213/345/206/214/346/250/241/347/211/210.md +3 -2
  128. package/templates/artifacts/existing-system//351/232/224/347/246/273/351/200/202/351/205/215/345/231/250/346/226/271/346/241/210/346/250/241/347/211/210.md +1 -0
  129. package/templates/artifacts/shared/API/346/216/245/345/217/243/350/247/204/346/240/274/346/226/207/346/241/243/346/250/241/347/211/210.md +3 -3
  130. package/templates/artifacts/shared//344/273/243/347/240/201/345/256/241/346/237/245/346/212/245/345/221/212/346/250/241/347/211/210.md +1 -1
  131. package/templates/artifacts/shared//345/210/207/347/211/207/350/256/241/345/210/222/346/250/241/347/211/210.md +6 -2
  132. package/templates/artifacts/shared//345/216/237/345/236/213/350/257/264/346/230/216/346/250/241/347/211/210.md +5 -3
  133. package/templates/artifacts/shared//346/216/245/345/217/243/345/257/271/346/216/245/346/226/271/346/241/210/346/250/241/347/211/210.md +2 -2
  134. package/templates/artifacts/shared//346/225/260/346/215/256/345/272/223/345/217/230/346/233/264/346/226/271/346/241/210/346/250/241/347/211/210.md +2 -2
  135. package/templates/artifacts/shared//346/225/260/346/215/256/345/272/223/350/256/276/350/256/241/346/226/207/346/241/243/346/250/241/347/211/210.md +2 -2
  136. package/templates/artifacts/shared//346/236/266/346/236/204/350/256/276/350/256/241/346/250/241/347/211/210.md +6 -3
  137. package/templates/artifacts/shared//350/256/276/350/256/241/344/270/200/350/207/264/346/200/247/351/252/214/346/224/266/346/212/245/345/221/212/346/250/241/347/211/210.md +5 -5
  138. package/templates/artifacts/shared//350/257/246/347/273/206/350/256/276/350/256/241/346/250/241/347/211/210.md +3 -3
  139. package/templates/artifacts/shared//351/234/200/346/261/202/345/216/237/345/236/213/350/256/276/350/256/241/345/256/236/347/216/260/350/277/275/350/270/252/347/237/251/351/230/265/346/250/241/347/211/210.md +7 -6
  140. package/templates/checklists//344/274/232/350/257/235/346/201/242/345/244/215.md +1 -1
  141. package/templates/gates/shared/gate-/344/273/243/347/240/201/345/256/241/346/237/245.yaml +7 -0
  142. package/templates/gates/shared/gate-/345/210/207/347/211/207/345/256/241/346/237/245.yaml +14 -2
  143. package/templates/gates/shared/gate-/347/274/226/347/240/201/345/256/236/347/216/260.yaml +12 -0
  144. package/templates/internal/patterns/Hook/345/261/202/344/272/247/347/211/251/347/273/223/346/236/204/346/240/241/351/252/214.md +1 -1
  145. package/templates/procedures/Schema/345/217/230/346/233/264/346/265/201/346/260/264/347/272/277.md +2 -2
  146. package/templates/procedures//345/256/211/345/205/250/345/212/240/345/233/272/346/265/201/346/260/264/347/272/277.md +2 -2
  147. package/templates/procedures//346/200/247/350/203/275/346/265/201/346/260/264/347/272/277.md +2 -2
  148. package/templates/procedures//346/216/245/345/217/243/351/233/206/346/210/220/346/265/201/346/260/264/347/272/277.md +1 -1
  149. package/templates/procedures//346/236/266/346/236/204/350/256/276/350/256/241/345/267/245/344/275/234/346/265/201.md +1 -2
  150. package/templates/procedures//346/246/202/345/277/265/351/252/214/350/257/201/346/265/201/346/260/264/347/272/277.md +2 -2
  151. package/templates/procedures//346/272/220/347/240/201/345/216/237/345/236/213/344/272/244/344/273/230/346/265/201/347/250/213.md +2 -2
  152. package/templates/procedures//347/264/247/346/200/245/344/277/256/345/244/215/346/265/201/346/260/264/347/272/277.md +2 -2
  153. package/templates/procedures//350/277/201/347/247/273/346/265/201/346/260/264/347/272/277.md +2 -2
  154. package/templates/procedures//351/207/215/346/236/204/346/265/201/346/260/264/347/272/277.md +2 -2
  155. package/templates/rules/shared//344/273/243/347/240/201/345/217/257/347/273/264/346/212/244/346/200/247/344/270/216/345/217/257/350/247/202/346/265/213/346/200/247/345/256/241/346/237/245.md +21 -3
  156. package/templates/rules/shared//344/273/243/347/240/201/346/263/250/351/207/212/344/270/216/346/227/245/345/277/227/345/245/221/347/272/246/350/247/204/345/210/231.md +122 -0
@@ -0,0 +1,772 @@
1
+ /**
2
+ * 四层编排共享内核 — 单产物操作的统一编排函数。
3
+ *
4
+ * 三种场景共用此内核:
5
+ * - 场景 A:sf_command([sf] 审查/修改/生成/迭代 某某产物)
6
+ * - 场景 B:sf_single_artifact(结构化参数快捷入口)
7
+ * - 场景 C:CLI review/modify 命令
8
+ *
9
+ * 四层编排:
10
+ * Layer 1 — 模板层:从模板 frontmatter 读取 companion_rules / companion_gates / consumes
11
+ * Layer 2 — 引擎层:解析 consumes → 加载上游产物内容
12
+ * Layer 3 — 上下文引擎:运行 requires_context 视图
13
+ * Layer 4 — 规则层 + 门禁层:injectCompanions 按 operation 过滤加载
14
+ * Layer 5 — 范围约束:allowed_paths + read_only_paths
15
+ *
16
+ * 按方案 SoloForge-模板体系四层职责分离方案.md Section 2.4 实现。
17
+ */
18
+ import fs from "node:fs";
19
+ import path from "node:path";
20
+ import matter from "gray-matter";
21
+ import { ensureCanonicalPaths, findArtifactPathsByKind, findTemplatePath, hasArtifactAlias, } from "./artifact_resolver.js";
22
+ import { findArtifactAlias } from "./artifact_aliases.js";
23
+ import { injectCompanions } from "../context_engine/companion_injector.js";
24
+ // ── 类型定义 ──
25
+ /** OperationType → injectCompanions operation 映射 */
26
+ const OPERATION_TO_COMPANION = {
27
+ extract: "execute", // 生成/创建 → 加载全部规则
28
+ review: "review", // 审查 → 加载 :review + :check
29
+ fix: "execute", // 修改/修复 → 加载全部规则
30
+ iterate: "execute", // 迭代/优化 → 加载全部规则
31
+ };
32
+ // ── 辅助函数 ──
33
+ /**
34
+ * 加载输入路径内容。
35
+ * 文件 → 读取文本;目录 → 列出子文件(.md/.yaml)+ 非文本文件清单。
36
+ */
37
+ function loadInputContents(relPaths, base) {
38
+ const result = {};
39
+ for (const rel of relPaths) {
40
+ const abs = path.join(base, rel);
41
+ if (!fs.existsSync(abs))
42
+ continue;
43
+ try {
44
+ const stat = fs.statSync(abs);
45
+ if (stat.isDirectory()) {
46
+ const entries = fs.readdirSync(abs, {
47
+ recursive: true,
48
+ withFileTypes: false,
49
+ });
50
+ // 读取文本文件
51
+ for (const entry of entries) {
52
+ if (typeof entry === "string" &&
53
+ (entry.endsWith(".md") || entry.endsWith(".yaml") || entry.endsWith(".yml"))) {
54
+ try {
55
+ result[path.join(rel, entry)] = fs.readFileSync(path.join(abs, entry), "utf-8");
56
+ }
57
+ catch {
58
+ /* 跳过 */
59
+ }
60
+ }
61
+ }
62
+ // 非文本文件清单
63
+ const nonText = entries.filter((e) => typeof e === "string" &&
64
+ !e.endsWith(".md") &&
65
+ !e.endsWith(".yaml") &&
66
+ !e.endsWith(".yml"));
67
+ if (nonText.length > 0) {
68
+ result[rel] = `[目录,包含文件: ${nonText.join(", ")}]`;
69
+ }
70
+ }
71
+ else {
72
+ result[rel] = fs.readFileSync(abs, "utf-8");
73
+ }
74
+ }
75
+ catch {
76
+ /* 读取失败跳过 */
77
+ }
78
+ }
79
+ return result;
80
+ }
81
+ /**
82
+ * 为 review/fix 操作构建上游对比指令。
83
+ *
84
+ * 审查必须用上游产物内容校验一致性和遗漏,
85
+ * 否则偏差会传导至后续架构、编码、验证阶段。
86
+ */
87
+ function buildUpstreamComparisonDirective(operation, targetName, upstreamInputs) {
88
+ // extract 不需要上游对比;review/fix/iterate 都需要(iterate 循环中第一轮审查必须对比上游)
89
+ if (operation === "extract")
90
+ return "";
91
+ const loadedInputs = upstreamInputs.filter((i) => !i.missing && Object.keys(i.contents).length > 0);
92
+ if (loadedInputs.length === 0)
93
+ return "";
94
+ const inputList = loadedInputs.map((i) => {
95
+ const contentKeys = Object.keys(i.contents);
96
+ return `- 「${i.ref}」(${contentKeys.length} 个文件: ${contentKeys.slice(0, 3).join(", ")}${contentKeys.length > 3 ? " ..." : ""})`;
97
+ }).join("\n");
98
+ if (operation === "review") {
99
+ return [
100
+ "## 上游对比要求(强制)",
101
+ "",
102
+ `审查「${targetName}」时,必须逐项与以下上游产物对比,检查一致性和遗漏:`,
103
+ inputList,
104
+ "",
105
+ "对比维度:",
106
+ "1. **完整性**:上游提到的每个功能点/实体/流程,目标产物是否都有覆盖?",
107
+ "2. **一致性**:目标产物中的数据/描述/逻辑是否与上游一致?",
108
+ "3. **无遗漏**:是否存在上游有但目标产物完全未提及的内容?",
109
+ "",
110
+ "对每个偏差项标注:❌ 不一致 / ⚠️ 遗漏 / ✅ 一致",
111
+ ].join("\n");
112
+ }
113
+ // fix 操作
114
+ return [
115
+ "## 修复约束(强制)",
116
+ "",
117
+ `修复「${targetName}」时,必须参考以下上游产物确保修复后一致:`,
118
+ inputList,
119
+ "",
120
+ "修复原则:",
121
+ "1. 仅修正已标注的偏差项,不改动已正确的部分",
122
+ "2. 修复后必须与上游产物内容一致",
123
+ "3. 不得引入上游中不存在的新内容",
124
+ ].join("\n");
125
+ }
126
+ /**
127
+ * 为 iterate 操作构建自动迭代循环指令。
128
+ *
129
+ * 核心流程:review → 发现问题 → fix → 再 review → 直到全部通过。
130
+ * 这不是内核的自动化循环(内核不运行 AI),而是在 injection_text 中
131
+ * 告诉 AI 遵循的迭代协议。
132
+ */
133
+ export function buildIterateDirective(operation, targetName, targetPaths, gateNames) {
134
+ // extract 是首次创建,不需要迭代循环;review/fix/iterate 都需要
135
+ if (operation === "extract")
136
+ return "";
137
+ const maxIterations = 5;
138
+ const gatesSection = gateNames.length > 0
139
+ ? gateNames.map((g) => `「${g}」`).join("、")
140
+ : "结构完整性检查";
141
+ return [
142
+ "## 对抗性审查-修复协议(强制)",
143
+ "",
144
+ `你正在处理「${targetName}」。你是严格的质量审查员,你的职责是发现问题,不是放行。`,
145
+ "",
146
+ "### 审查原则(违反任何一条等同审查失败)",
147
+ "",
148
+ "1. 默认立场:每一条门禁检查项都是 ❌,除非你能引用产物中的具体内容作为证据",
149
+ "2. 无证据的 ✅ 等同于 ❌ — 你必须引用章节名或行号 + 原文",
150
+ "3. 你不可以批量标记 ✅ — 每条必须独立检查并附证据",
151
+ "4. 你不可以跳过任何检查项",
152
+ "",
153
+ "### 执行流程",
154
+ "",
155
+ `阶段 A: 对抗性审查`,
156
+ ` 对每一条门禁检查项(${gatesSection}):`,
157
+ " 1. 读取产物文件的相关部分",
158
+ " 2. 引用具体内容(章节名/行号 + 引文)",
159
+ " 3. 标注 ❌ + 问题描述 + 修复方案,或 ✅ + 证据(引用原文)",
160
+ " → 产出完整审查报告",
161
+ "",
162
+ "阶段 B: 强制修复",
163
+ " 对审查报告中的每一个 ❌ 和 ⚠️ 项:",
164
+ " 1. 按修复方案逐项修复",
165
+ ` 2. 修复后重写完整产物到: ${targetPaths.join(" 或 ")}`,
166
+ " 3. 不允许只报告不修复",
167
+ "",
168
+ "阶段 C: 独立重审(强制)",
169
+ " 修复完成后,你必须再次调用 [sf] 审查 工具进行独立重审。",
170
+ " 这不是可选的——这是强制性的质量保证步骤。",
171
+ " 独立重审会以全新视角重新加载门禁规则,确保审查不受修复过程的偏见影响。",
172
+ ` 如果重审发现问题 → 回到阶段 B 继续修复(最多 ${maxIterations} 轮)。`,
173
+ "",
174
+ "### 终止条件",
175
+ "",
176
+ "1. 审查报告零 ❌/⚠️ 项 → 结束,报告「审查通过」",
177
+ `2. 达到最大 ${maxIterations} 轮 → 结束,报告剩余未修复项`,
178
+ "",
179
+ "### 输出要求",
180
+ "",
181
+ `- 每轮修复后必须将完整产物写入: ${targetPaths.join(" 或 ")}`,
182
+ "- 最终输出审查通过的产物内容",
183
+ "- 附上迭代摘要:修复了哪些问题、经过几轮",
184
+ "",
185
+ "⚠️ 绝对不允许只输出审查报告就停下来。必须看到产物被修复并通过审查。",
186
+ "⚠️ 绝对不允许无证据地批量标记 ✅。",
187
+ ].join("\n");
188
+ }
189
+ /**
190
+ * 构建 extract 操作的质量纪律指令。
191
+ *
192
+ * extract 是首次创建产物,无迭代循环也无上游对比。
193
+ * 此函数注入创建质量纪律,防止 AI 产出空洞内容。
194
+ */
195
+ export function buildExtractQualityDirective(operation, targetName, targetPaths, gateNames) {
196
+ // 仅 extract 操作需要此指令
197
+ if (operation !== "extract")
198
+ return "";
199
+ const gatesSection = gateNames.length > 0
200
+ ? `门禁检查:${gateNames.map((g) => `「${g}」`).join("、")}`
201
+ : "结构完整性检查";
202
+ return [
203
+ "## 创建质量纪律(强制)",
204
+ "",
205
+ `你正在创建「${targetName}」。以下纪律不可违反:`,
206
+ "",
207
+ "### 禁止空洞(anti-laziness 基线)",
208
+ "1. 每个模板章节必须填写完整内容,禁止留空、使用占位符(如「待补充」「TBD」)",
209
+ "2. 必须穷尽上游产物中引用的所有实体/流程/字段 — 上游提到的每个名词都必须在产物中有对应描述",
210
+ "3. 无上游内容的章节必须基于模板要求自行补全,不可以「上游未提供」为由留空",
211
+ "",
212
+ "### 完整性自检(产出后必须执行)",
213
+ `产出完成后,逐条核对以下${gatesSection}:`,
214
+ "- 对每条门禁:引用你产物中的具体内容作为证据",
215
+ "- 如果任何门禁无法提供证据 → 立即补充内容,不要停下来问用户",
216
+ "- 自检不通过 → 修复 → 重新自检(最多 5 轮)",
217
+ "",
218
+ "### 输出要求",
219
+ `- 完整产物写入: ${targetPaths.join(" 或 ")}`,
220
+ "- 附自检报告:每条门禁 ✅ + 证据 或 ❌ + 修复说明",
221
+ ].join("\n");
222
+ }
223
+ // ── 核心函数 ──
224
+ /**
225
+ * 四层编排共享内核 — 单产物操作统一入口。
226
+ *
227
+ * @param params.kind - 产物类型(ArtifactKind)
228
+ * @param params.operation - 操作类型(extract/review/fix/iterate)
229
+ * @param params.projectPath - 项目根路径
230
+ * @returns 编排结果(OrchestrateResult)
231
+ */
232
+ export async function orchestrateSingleArtifact(params) {
233
+ const { kind, operation, projectPath, original_command } = params;
234
+ // ── Step 0: 获取 alias 元数据 ──
235
+ const alias = findArtifactAlias(kind);
236
+ if (!alias) {
237
+ return {
238
+ mode: "single_artifact",
239
+ status: "error",
240
+ error: `未注册的产物类型: "${kind}"`,
241
+ target_kind: kind,
242
+ target_name: kind,
243
+ target_paths: [],
244
+ };
245
+ }
246
+ // ── Step 0b: 确保产物文件名与 canonical_paths 一致,再查找 ──
247
+ ensureCanonicalPaths(kind, projectPath);
248
+ const existingPaths = findArtifactPathsByKind(kind, projectPath);
249
+ // ── Layer 1: 模板层 ──
250
+ const templatePath = alias.template
251
+ ? findTemplatePath(alias.template, projectPath)
252
+ : null;
253
+ if (!templatePath) {
254
+ return {
255
+ mode: "single_artifact",
256
+ status: "no_template",
257
+ error: alias.template
258
+ ? `找不到模板文件: "${alias.template}"`
259
+ : `产物类型「${alias.defaultName}」无模板定义,不支持自动编排`,
260
+ target_kind: kind,
261
+ target_name: alias.defaultName,
262
+ target_paths: existingPaths,
263
+ };
264
+ }
265
+ const templateRaw = fs.readFileSync(templatePath, "utf-8");
266
+ const templateParsed = matter(templateRaw);
267
+ const fm = (templateParsed.data ?? {});
268
+ // 解析 frontmatter 字段 — 支持 structured YAML 和 旧字符串格式
269
+ const fmConsumes = fm.consumes ?? [];
270
+ const fmCompanionRules = fm.companion_rules;
271
+ const fmCompanionGates = fm.companion_gates;
272
+ const fmRequiresContext = fm.requires_context ?? [];
273
+ // 老系统管线专属规则:companion_rules_legacy 仅在 systemType="老系统" 时合并
274
+ if (params.systemType === "老系统") {
275
+ const legacyRules = fm.companion_rules_legacy;
276
+ if (legacyRules && legacyRules.length > 0) {
277
+ fmCompanionRules.push(...legacyRules);
278
+ }
279
+ }
280
+ // ── Layer 2: Consumes 解析(上游输入加载) ──
281
+ const upstreamInputs = [];
282
+ for (const ref of fmConsumes) {
283
+ // 跳过 mechanism ID(mc- 前缀)——不是产物 kind
284
+ if (typeof ref === "string" && ref.startsWith("mc-")) {
285
+ continue;
286
+ }
287
+ // 策略 1:已注册的 artifact kind → 查 canonical_paths
288
+ if (hasArtifactAlias(ref)) {
289
+ ensureCanonicalPaths(ref, projectPath);
290
+ const resolvedPaths = findArtifactPathsByKind(ref, projectPath);
291
+ const contents = loadInputContents(resolvedPaths, projectPath);
292
+ const missing = resolvedPaths.length === 0;
293
+ upstreamInputs.push({ ref, resolved_kind: ref, paths: resolvedPaths, contents, missing });
294
+ continue;
295
+ }
296
+ // 策略 2:非 kind 路径兜底(如 docs/api/openapi.yaml)
297
+ const fullPath = path.join(projectPath, ref);
298
+ if (fs.existsSync(fullPath)) {
299
+ const contents = loadInputContents([ref], projectPath);
300
+ upstreamInputs.push({ ref, paths: [ref], contents, missing: false });
301
+ }
302
+ else {
303
+ // 非核心路径缺失不阻断(如 openapi.yaml 可能还未生成)
304
+ upstreamInputs.push({ ref, paths: [], contents: {}, missing: false });
305
+ }
306
+ }
307
+ // ── Consumes OR 替代:缺失的 kind 查 consumes_alternatives ──
308
+ // 当模板 frontmatter 声明了 consumes_alternatives(如 prototype_spec → data_lineage_diagram),
309
+ // 缺失的 kind 会尝试用替代产物补充
310
+ const fmAlternatives = fm.consumes_alternatives;
311
+ if (fmAlternatives) {
312
+ for (let i = 0; i < upstreamInputs.length; i++) {
313
+ const input = upstreamInputs[i];
314
+ if (!input.missing || !input.resolved_kind)
315
+ continue;
316
+ const alternatives = fmAlternatives[input.ref] ?? fmAlternatives[input.resolved_kind];
317
+ if (!alternatives || alternatives.length === 0)
318
+ continue;
319
+ for (const altKind of alternatives) {
320
+ if (!hasArtifactAlias(altKind))
321
+ continue;
322
+ ensureCanonicalPaths(altKind, projectPath);
323
+ const altPaths = findArtifactPathsByKind(altKind, projectPath);
324
+ if (altPaths.length > 0) {
325
+ const altContents = loadInputContents(altPaths, projectPath);
326
+ upstreamInputs[i] = {
327
+ ref: `${input.ref}(替代:${altKind})`,
328
+ resolved_kind: altKind,
329
+ paths: altPaths,
330
+ contents: altContents,
331
+ missing: false,
332
+ };
333
+ break;
334
+ }
335
+ }
336
+ }
337
+ }
338
+ // ── 缺失上游检测 ──
339
+ const missingInputs = upstreamInputs.filter((i) => i.missing);
340
+ const availableInputs = upstreamInputs.filter((i) => !i.missing);
341
+ if (missingInputs.length > 0) {
342
+ const missingWithTemplates = missingInputs.map((input) => {
343
+ const inputAlias = input.resolved_kind ? findArtifactAlias(input.resolved_kind) : undefined;
344
+ const templatePathForMissing = inputAlias?.template
345
+ ? findTemplatePath(inputAlias.template, projectPath)
346
+ : null;
347
+ return {
348
+ ref: input.ref,
349
+ kind: input.resolved_kind,
350
+ template_name: inputAlias?.template,
351
+ template_path: templatePathForMissing,
352
+ available_upstream: availableInputs.map((ai) => ({
353
+ ref: ai.ref,
354
+ kind: ai.resolved_kind,
355
+ paths: ai.paths,
356
+ missing: ai.missing,
357
+ })),
358
+ message: `上游产物「${inputAlias?.defaultName ?? input.ref}」缺失`,
359
+ };
360
+ });
361
+ return {
362
+ mode: "single_artifact",
363
+ status: "missing_upstream",
364
+ target_kind: kind,
365
+ target_name: alias.defaultName,
366
+ target_paths: existingPaths,
367
+ missing_inputs: missingWithTemplates,
368
+ available_inputs: availableInputs.map((ai) => ({
369
+ ref: ai.ref,
370
+ kind: ai.resolved_kind,
371
+ paths: ai.paths,
372
+ missing: ai.missing,
373
+ })),
374
+ suggested_action: {
375
+ produce_first: `请先读取模板产出缺失的上游产物,已有上游内容已附在 available_inputs 中`,
376
+ then_resume: original_command
377
+ ? `上游产物就绪后,重新执行: ${original_command}`
378
+ : `上游产物就绪后,重新执行操作`,
379
+ },
380
+ original_task: {
381
+ kind,
382
+ description: alias.defaultName,
383
+ command: original_command ?? "",
384
+ },
385
+ };
386
+ }
387
+ // ── 非 extract 操作 + 产物不存在 → 引导补产 ──
388
+ // review/fix/iterate 要求产物已存在,不存在时应引导用户先 extract
389
+ if (operation !== "extract" && existingPaths.length === 0) {
390
+ return {
391
+ mode: "single_artifact",
392
+ status: "missing_upstream",
393
+ target_kind: kind,
394
+ target_name: alias.defaultName,
395
+ target_paths: [],
396
+ missing_inputs: [{
397
+ ref: kind,
398
+ kind,
399
+ template_name: alias.template,
400
+ template_path: alias.template ? findTemplatePath(alias.template, projectPath) : null,
401
+ available_upstream: availableInputs.map((ai) => ({
402
+ ref: ai.ref,
403
+ kind: ai.resolved_kind,
404
+ paths: ai.paths,
405
+ missing: ai.missing,
406
+ })),
407
+ message: `目标产物「${alias.defaultName}」尚未创建,${operation} 操作要求产物已存在`,
408
+ }],
409
+ available_inputs: availableInputs.map((ai) => ({
410
+ ref: ai.ref,
411
+ kind: ai.resolved_kind,
412
+ paths: ai.paths,
413
+ missing: ai.missing,
414
+ })),
415
+ suggested_action: {
416
+ produce_first: `请先使用 extract 操作创建「${alias.defaultName}」,模板和上游内容已准备就绪`,
417
+ then_resume: original_command
418
+ ? `产物创建完成后,重新执行: ${original_command}`
419
+ : `产物创建完成后,重新执行 ${operation} 操作`,
420
+ },
421
+ original_task: {
422
+ kind,
423
+ description: alias.defaultName,
424
+ command: original_command ?? "",
425
+ },
426
+ };
427
+ }
428
+ // ── 目标路径解析 ──
429
+ // 合并已存在路径 + 缺失的精确 canonical_paths(存在则覆盖,不存在则新建)
430
+ // 通配符路径由 expandGlob 展开到 existingPaths,不再额外添加 pattern
431
+ const targetPaths = [...existingPaths];
432
+ for (const cp of alias.canonical_paths) {
433
+ // 跳过通配符路径(已由 expandGlob 展开)
434
+ if (cp.includes("*") || cp.includes("**"))
435
+ continue;
436
+ if (!targetPaths.includes(cp)) {
437
+ targetPaths.push(cp);
438
+ }
439
+ }
440
+ // ── Layer 3: 上下文引擎 ──
441
+ let contextAnalysis;
442
+ if (fmRequiresContext.length > 0) {
443
+ try {
444
+ const { resolveContext } = await import("../context_engine/index.js");
445
+ const { getView, dispatchView } = await import("../context_engine/view_registry.js");
446
+ for (const viewName of fmRequiresContext) {
447
+ const resolved = resolveContext({ view: viewName, source: "auto" }, null, // single_artifact 无管线阶段
448
+ { scopeRoots: targetPaths });
449
+ if (getView(resolved.view)) {
450
+ const vr = await dispatchView(resolved.view, projectPath, {
451
+ targets: resolved.targets,
452
+ scope: resolved.scope,
453
+ });
454
+ if (!contextAnalysis)
455
+ contextAnalysis = vr.summary;
456
+ else
457
+ contextAnalysis += "\n\n" + vr.summary;
458
+ }
459
+ }
460
+ }
461
+ catch {
462
+ // 上下文引擎失败不阻断
463
+ }
464
+ }
465
+ // ── Layer 4 + 5: 规则层 + 门禁层 ──
466
+ const companionOperation = OPERATION_TO_COMPANION[operation];
467
+ const companionResult = injectCompanions({
468
+ baseDir: projectPath,
469
+ companion_rules: fmCompanionRules,
470
+ companion_gates: fmCompanionGates,
471
+ operation: companionOperation,
472
+ systemType: params.systemType,
473
+ });
474
+ // ── Layer 6: 范围约束 ──
475
+ const consumedPaths = upstreamInputs.flatMap((input) => input.paths);
476
+ // ── 注入上游对比指令(review/fix 操作必须对比上游) ──
477
+ const upstreamComparisonDirective = buildUpstreamComparisonDirective(operation, alias.defaultName, upstreamInputs);
478
+ // ── 注入迭代循环指令(iterate 操作的自循环协议) ──
479
+ const iterateDirective = buildIterateDirective(operation, alias.defaultName, targetPaths, companionResult.gates.map((g) => g.name));
480
+ // ── 注入创建质量纪律(extract 操作的 anti-laziness) ──
481
+ const extractQualityDirective = buildExtractQualityDirective(operation, alias.defaultName, targetPaths, companionResult.gates.map((g) => g.name));
482
+ const finalInjectionText = [
483
+ upstreamComparisonDirective,
484
+ companionResult.injection_text,
485
+ extractQualityDirective,
486
+ iterateDirective,
487
+ ].filter(Boolean).join("\n\n");
488
+ // ── 构建结果 ──
489
+ return {
490
+ mode: "single_artifact",
491
+ status: "ready",
492
+ operation,
493
+ // 产物信息
494
+ target_kind: kind,
495
+ target_name: alias.defaultName,
496
+ target_paths: targetPaths,
497
+ suggested_target_paths: undefined,
498
+ // 模板
499
+ template_name: alias.template,
500
+ template_body: templateParsed.content,
501
+ // Layer 2: 上游输入
502
+ upstream_inputs: upstreamInputs.map((input) => ({
503
+ ref: input.ref,
504
+ kind: input.resolved_kind,
505
+ paths: input.paths,
506
+ missing: input.missing,
507
+ contents: input.contents,
508
+ })),
509
+ // Layer 3: 引擎分析
510
+ context_analysis: contextAnalysis,
511
+ // Layer 4 + 5: 规则与门禁
512
+ rules: companionResult.rules,
513
+ missing_rules: companionResult.missing_rules,
514
+ gates: companionResult.gates,
515
+ missing_gates: companionResult.missing_gates,
516
+ injection_text: finalInjectionText,
517
+ // Layer 6: 范围约束
518
+ scope: {
519
+ allowed_paths: targetPaths,
520
+ read_only_paths: consumedPaths,
521
+ },
522
+ };
523
+ }
524
+ /** 将单产物状态映射为阶段级摘要状态 */
525
+ function mapSingleStatus(status) {
526
+ if (status === "ready")
527
+ return "ready";
528
+ if (status === "missing_upstream" || status === "need_target_info")
529
+ return "missing_upstream";
530
+ if (status === "no_template")
531
+ return "no_template";
532
+ return "missing_target";
533
+ }
534
+ /** 构建阶段级审查 injection_text */
535
+ export function buildStageReviewInjection(stage, results, gates) {
536
+ const ready = results.filter((r) => r.status === "ready");
537
+ const skipped = results.filter((r) => r.status !== "ready");
538
+ const lines = [];
539
+ // 标题
540
+ lines.push(`# 阶段级审查 —「${stage}」`);
541
+ lines.push("");
542
+ // 审查范围
543
+ lines.push("## 审查范围");
544
+ lines.push("");
545
+ if (ready.length > 0) {
546
+ lines.push("### 可审查产物");
547
+ for (const item of ready) {
548
+ lines.push(`- **${item.name}** (${item.kind}): ${item.paths.join(", ")}`);
549
+ }
550
+ lines.push("");
551
+ }
552
+ if (skipped.length > 0) {
553
+ lines.push("### 跳过的产物(缺失上游或无模板)");
554
+ for (const item of skipped) {
555
+ lines.push(`- ~~${item.name}~~ (${item.status}): ${item.error ?? item.status}`);
556
+ }
557
+ lines.push("");
558
+ }
559
+ // 审查顺序
560
+ lines.push("## 阶段级审查-修复循环协议(强制)");
561
+ lines.push("");
562
+ lines.push(`你现在必须执行「${stage}」阶段全部 ${ready.length} 个产物的审查-修复循环,禁止中途停下来。`);
563
+ lines.push("");
564
+ lines.push("### 审查顺序");
565
+ for (let i = 0; i < ready.length; i++) {
566
+ lines.push(`${i + 1}. 审查「${ready[i].name}」`);
567
+ }
568
+ lines.push("");
569
+ // ── 审查原则(对抗性框架 — 同改造 3 统一原则)──
570
+ lines.push("### 审查原则(违反任何一条等同审查失败)");
571
+ lines.push("");
572
+ lines.push("1. **默认立场**:每一条门禁检查项都是 ❌,除非你能引用产物中的具体内容作为证据");
573
+ lines.push("2. **无证据的 ✅ 等同于 ❌** — 你必须引用章节名或行号 + 原文");
574
+ lines.push("3. **禁止批量标记 ✅** — 每条必须独立检查并附证据");
575
+ lines.push("4. **禁止跳过任何检查项** — 包括跨产物一致性检查");
576
+ lines.push("");
577
+ // ── 门禁 ──
578
+ const uniqueGates = [...new Map(gates.map((g) => [g.name, g])).values()];
579
+ if (uniqueGates.length > 0) {
580
+ lines.push("### 质量标准");
581
+ lines.push("");
582
+ lines.push(`门禁检查:${uniqueGates.map((g) => `「${g.name}」`).join("、")} — 全部通过才可结束`);
583
+ lines.push("");
584
+ }
585
+ // ── 每个产物的专属审查规则 ──
586
+ for (const item of ready) {
587
+ if (item.injection_text) {
588
+ lines.push(`## 「${item.name}」专属审查规则`);
589
+ lines.push("");
590
+ lines.push(item.injection_text);
591
+ lines.push("");
592
+ }
593
+ }
594
+ // ── 执行流程(三阶段:对抗审查 → 强制修复 → 独立重审)──
595
+ lines.push("### 执行流程");
596
+ lines.push("");
597
+ // 阶段 A: 对抗性审查
598
+ lines.push("**阶段 A: 对抗性审查**");
599
+ lines.push("");
600
+ lines.push(`对「${stage}」阶段全部 ${ready.length} 个产物执行逐个审查:`);
601
+ for (const item of ready) {
602
+ lines.push(`- 读取「${item.name}」产物的相关部分`);
603
+ }
604
+ lines.push("对每一条门禁检查项:");
605
+ lines.push(" 1. 引用产物具体内容(章节名/行号 + 引文)");
606
+ lines.push(" 2. 标注 ❌ + 问题描述 + 修复方案,或 ✅ + 证据(引用原文)");
607
+ lines.push("→ 产出完整审查报告");
608
+ lines.push("");
609
+ // 跨产物一致性(多产物时额外要求)
610
+ if (ready.length > 1) {
611
+ lines.push("**阶段 A-2: 跨产物一致性校验(强制)**");
612
+ lines.push("");
613
+ lines.push(`除逐个审查外,你还必须检查「${stage}」阶段内各产物之间的一致性:`);
614
+ lines.push("");
615
+ lines.push("1. **术语一致**:同一实体/概念在不同产物中的命名是否一致?引用两个产物中的原文作为证据");
616
+ lines.push("2. **引用一致**:产物 A 引用的设计决策/实体在产物 B 中是否有对应描述?引用对应段落");
617
+ lines.push("3. **覆盖完整**:架构设计文档中的每个模块是否都有对应的数据库表和 API 端点?逐一列出映射关系");
618
+ lines.push("4. **无冲突**:不同产物之间是否存在互相矛盾的描述?引用矛盾处原文");
619
+ lines.push("");
620
+ lines.push("⚠️ 跨产物一致性检查也适用审查原则:无证据的 ✅ 等同于 ❌。必须引用两个产物中的对应内容。");
621
+ lines.push("");
622
+ }
623
+ // 阶段 B: 强制修复
624
+ lines.push("**阶段 B: 强制修复**");
625
+ lines.push("");
626
+ lines.push("对审查报告中的每一个 ❌ 和 ⚠️ 项:");
627
+ lines.push(" 1. 按修复方案逐项修复");
628
+ lines.push(" 2. 修复后重写完整产物到对应文件");
629
+ lines.push(" 3. 不允许只报告不修复");
630
+ lines.push("");
631
+ // 阶段 C: 独立重审
632
+ lines.push("**阶段 C: 独立重审(强制)**");
633
+ lines.push("");
634
+ lines.push("修复完成后,你必须再次调用 `[sf] 审查 ${stage}` 工具进行独立重审。");
635
+ lines.push("这不是可选的——这是强制性的质量保证步骤。");
636
+ lines.push("独立重审会以全新视角重新加载门禁规则,确保审查不受修复过程的偏见影响。");
637
+ lines.push("如果重审发现问题 → 回到阶段 B 继续修复(最多 5 轮)。");
638
+ lines.push("");
639
+ // 终止条件
640
+ lines.push("### 终止条件");
641
+ lines.push("");
642
+ lines.push("1. 全部产物审查报告零 ❌/⚠️ 项(含跨产物一致性) → 结束,报告「审查通过」");
643
+ lines.push("2. 达到最大 5 轮 → 结束,报告剩余未修复项");
644
+ lines.push("");
645
+ // 输出要求
646
+ lines.push("### 输出要求");
647
+ lines.push("");
648
+ lines.push("- 每轮修复后必须将完整产物写入对应文件");
649
+ lines.push("- 每条门禁检查项必须附证据:✅ + 引用原文 或 ❌ + 修复说明");
650
+ lines.push("- 最终输出阶段级审查通过的确认 + 迭代摘要");
651
+ lines.push("");
652
+ lines.push("⚠️ 绝对不允许只输出审查报告就停下来。必须看到所有产物被修复并通过审查。");
653
+ lines.push("⚠️ 绝对不允许无证据地批量标记 ✅。");
654
+ lines.push("⚠️ 独立重审是强制步骤,不是可选建议。");
655
+ return lines.join("\n");
656
+ }
657
+ /**
658
+ * 阶段级审查编排 — 审查指定阶段的全部产出。
659
+ *
660
+ * 对该阶段的所有注册产物逐一调用 orchestrateSingleArtifact(review),
661
+ * 聚合结果为统一的 StageReviewResult。
662
+ */
663
+ export async function orchestrateStageReview(params) {
664
+ const { stage, projectPath, original_command, systemType } = params;
665
+ const { getArtifactsByStage } = await import("./artifact_aliases.js");
666
+ const aliases = getArtifactsByStage(stage, systemType);
667
+ if (aliases.length === 0) {
668
+ return {
669
+ mode: "stage_review",
670
+ status: "no_artifacts",
671
+ stage,
672
+ artifact_results: [],
673
+ injection_text: `阶段「${stage}」没有可审查的产物。`,
674
+ };
675
+ }
676
+ // 逐一编排
677
+ const artifactResults = [];
678
+ const allReady = [];
679
+ const partialIssues = [];
680
+ const allGates = [];
681
+ const allAllowedPaths = [];
682
+ const allReadOnlyPaths = [];
683
+ for (const alias of aliases) {
684
+ let singleResult = await orchestrateSingleArtifact({
685
+ kind: alias.kind,
686
+ operation: "review",
687
+ projectPath,
688
+ original_command,
689
+ systemType,
690
+ });
691
+ // 阶段级审查:产物不存在(status=missing_upstream 且仅自身缺失)
692
+ // → 回退到 extract 模式创建+审查
693
+ // 条件:仅当缺失项只有产物本身(上游全部就绪),且 extract 产出非空 injection_text
694
+ const isOnlySelfMissing = singleResult.status === "missing_upstream"
695
+ && singleResult.missing_inputs?.length === 1
696
+ && singleResult.missing_inputs[0].ref === alias.kind
697
+ && singleResult.missing_inputs[0].message?.includes("尚未创建");
698
+ if (isOnlySelfMissing) {
699
+ // 额外守卫:
700
+ // 1. 根产物(consumes=[])在空项目中无上游内容可创建,跳过回退
701
+ // 2. extract 必须产出非空 injection_text 才采纳
702
+ const hasUpstreamContent = singleResult.upstream_inputs
703
+ && singleResult.upstream_inputs.length > 0;
704
+ if (hasUpstreamContent) {
705
+ const extractResult = await orchestrateSingleArtifact({
706
+ kind: alias.kind,
707
+ operation: "extract",
708
+ projectPath,
709
+ original_command,
710
+ systemType,
711
+ });
712
+ if (extractResult.status === "ready" && extractResult.injection_text) {
713
+ singleResult = {
714
+ ...extractResult,
715
+ injection_text: `# 阶段审查 — 创建并审查「${alias.defaultName}」\n\n`
716
+ + `此产物尚未存在,阶段级审查要求你先创建再审查。\n\n`
717
+ + `---\n\n${extractResult.injection_text}`,
718
+ };
719
+ }
720
+ }
721
+ }
722
+ const entry = {
723
+ kind: alias.kind,
724
+ name: alias.defaultName,
725
+ paths: singleResult.target_paths,
726
+ status: mapSingleStatus(singleResult.status),
727
+ injection_text: singleResult.injection_text,
728
+ upstream_inputs: singleResult.upstream_inputs,
729
+ template_body: singleResult.template_body,
730
+ rules: singleResult.rules,
731
+ gates: singleResult.gates,
732
+ missing_inputs: singleResult.missing_inputs,
733
+ error: singleResult.error,
734
+ };
735
+ artifactResults.push(entry);
736
+ // 收集 scope
737
+ if (singleResult.scope) {
738
+ allAllowedPaths.push(...singleResult.scope.allowed_paths);
739
+ allReadOnlyPaths.push(...singleResult.scope.read_only_paths);
740
+ }
741
+ // 收集门禁
742
+ if (singleResult.gates)
743
+ allGates.push(...singleResult.gates);
744
+ // 统计状态
745
+ if (singleResult.status === "ready") {
746
+ allReady.push(alias.defaultName);
747
+ }
748
+ else {
749
+ partialIssues.push(`「${alias.defaultName}」: ${singleResult.status}`);
750
+ }
751
+ }
752
+ // 构建聚合 injection_text
753
+ const injectionText = buildStageReviewInjection(stage, artifactResults, allGates);
754
+ // 总体状态
755
+ const overallStatus = partialIssues.length === 0
756
+ ? "ready"
757
+ : allReady.length > 0
758
+ ? "partial"
759
+ : "no_artifacts";
760
+ return {
761
+ mode: "stage_review",
762
+ status: overallStatus,
763
+ stage,
764
+ artifact_results: artifactResults,
765
+ injection_text: injectionText,
766
+ scope: {
767
+ allowed_paths: [...new Set(allAllowedPaths)],
768
+ read_only_paths: [...new Set(allReadOnlyPaths)],
769
+ },
770
+ };
771
+ }
772
+ //# sourceMappingURL=orchestrate_single_artifact.js.map