soloforge 1.3.1 → 1.3.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 (118) hide show
  1. package/README.md +6 -3
  2. package/dist/adapters/claude_code/claude_md.d.ts.map +1 -1
  3. package/dist/adapters/claude_code/claude_md.js +4 -0
  4. package/dist/adapters/claude_code/claude_md.js.map +1 -1
  5. package/dist/adapters/claude_code/tools.d.ts +10 -10
  6. package/dist/adapters/claude_code/tools.d.ts.map +1 -1
  7. package/dist/adapters/claude_code/tools.js +317 -18
  8. package/dist/adapters/claude_code/tools.js.map +1 -1
  9. package/dist/adapters/shared/workflow_template.d.ts +26 -0
  10. package/dist/adapters/shared/workflow_template.d.ts.map +1 -1
  11. package/dist/adapters/shared/workflow_template.js +139 -46
  12. package/dist/adapters/shared/workflow_template.js.map +1 -1
  13. package/dist/bin/soloforge.d.ts.map +1 -1
  14. package/dist/bin/soloforge.js +85 -53
  15. package/dist/bin/soloforge.js.map +1 -1
  16. package/dist/engine/asset_manifest.d.ts +7 -1
  17. package/dist/engine/asset_manifest.d.ts.map +1 -1
  18. package/dist/engine/asset_manifest.js +28 -18
  19. package/dist/engine/asset_manifest.js.map +1 -1
  20. package/dist/engine/consumable_asset_registry.d.ts.map +1 -1
  21. package/dist/engine/consumable_asset_registry.js +26 -0
  22. package/dist/engine/consumable_asset_registry.js.map +1 -1
  23. package/dist/engine/consumption_trace_store.d.ts +8 -8
  24. package/dist/engine/consumption_trace_store.d.ts.map +1 -1
  25. package/dist/engine/consumption_trace_store.js +11 -7
  26. package/dist/engine/consumption_trace_store.js.map +1 -1
  27. package/dist/engine/decision_workshop.d.ts +160 -0
  28. package/dist/engine/decision_workshop.d.ts.map +1 -0
  29. package/dist/engine/decision_workshop.js +279 -0
  30. package/dist/engine/decision_workshop.js.map +1 -0
  31. package/dist/engine/dual_layer_mechanism_registry.d.ts.map +1 -1
  32. package/dist/engine/dual_layer_mechanism_registry.js +176 -2
  33. package/dist/engine/dual_layer_mechanism_registry.js.map +1 -1
  34. package/dist/engine/explicit_asset_registry.d.ts +30 -0
  35. package/dist/engine/explicit_asset_registry.d.ts.map +1 -0
  36. package/dist/engine/explicit_asset_registry.js +3508 -0
  37. package/dist/engine/explicit_asset_registry.js.map +1 -0
  38. package/dist/engine/implementation_roadmap_registry.d.ts +2 -2
  39. package/dist/engine/implementation_roadmap_registry.d.ts.map +1 -1
  40. package/dist/engine/implementation_roadmap_registry.js +44 -16
  41. package/dist/engine/implementation_roadmap_registry.js.map +1 -1
  42. package/dist/engine/intent_expander.d.ts.map +1 -1
  43. package/dist/engine/intent_expander.js +46 -2
  44. package/dist/engine/intent_expander.js.map +1 -1
  45. package/dist/engine/intent_router.d.ts +1 -1
  46. package/dist/engine/intent_router.d.ts.map +1 -1
  47. package/dist/engine/intent_router.js +2 -1
  48. package/dist/engine/intent_router.js.map +1 -1
  49. package/dist/engine/knowledge_injection_boundary.d.ts +3 -0
  50. package/dist/engine/knowledge_injection_boundary.d.ts.map +1 -1
  51. package/dist/engine/knowledge_injection_boundary.js +48 -5
  52. package/dist/engine/knowledge_injection_boundary.js.map +1 -1
  53. package/dist/engine/mechanism_contract_registry.d.ts +1 -1
  54. package/dist/engine/mechanism_contract_registry.d.ts.map +1 -1
  55. package/dist/engine/mechanism_contract_registry.js +74 -2
  56. package/dist/engine/mechanism_contract_registry.js.map +1 -1
  57. package/dist/engine/observed_consumption.d.ts +54 -0
  58. package/dist/engine/observed_consumption.d.ts.map +1 -0
  59. package/dist/engine/observed_consumption.js +377 -0
  60. package/dist/engine/observed_consumption.js.map +1 -0
  61. package/dist/engine/release_issue_scenario_registry.d.ts +64 -0
  62. package/dist/engine/release_issue_scenario_registry.d.ts.map +1 -0
  63. package/dist/engine/release_issue_scenario_registry.js +1349 -0
  64. package/dist/engine/release_issue_scenario_registry.js.map +1 -0
  65. package/dist/engine/release_readiness_gate.d.ts +1 -1
  66. package/dist/engine/release_readiness_gate.d.ts.map +1 -1
  67. package/dist/engine/release_readiness_gate.js +574 -46
  68. package/dist/engine/release_readiness_gate.js.map +1 -1
  69. package/dist/engine/release_tool_harness.d.ts +71 -0
  70. package/dist/engine/release_tool_harness.d.ts.map +1 -0
  71. package/dist/engine/release_tool_harness.js +161 -0
  72. package/dist/engine/release_tool_harness.js.map +1 -0
  73. package/dist/engine/scaffolder.d.ts.map +1 -1
  74. package/dist/engine/scaffolder.js +144 -7
  75. package/dist/engine/scaffolder.js.map +1 -1
  76. package/dist/engine/standard_asset_contract.d.ts +75 -0
  77. package/dist/engine/standard_asset_contract.d.ts.map +1 -0
  78. package/dist/engine/standard_asset_contract.js +388 -0
  79. package/dist/engine/standard_asset_contract.js.map +1 -0
  80. package/dist/engine/standard_asset_coverage.d.ts +45 -0
  81. package/dist/engine/standard_asset_coverage.d.ts.map +1 -0
  82. package/dist/engine/standard_asset_coverage.js +220 -0
  83. package/dist/engine/standard_asset_coverage.js.map +1 -0
  84. package/dist/engine/template_asset_contract_registry.d.ts +162 -0
  85. package/dist/engine/template_asset_contract_registry.d.ts.map +1 -0
  86. package/dist/engine/template_asset_contract_registry.js +598 -0
  87. package/dist/engine/template_asset_contract_registry.js.map +1 -0
  88. package/dist/engine/template_asset_visibility.d.ts +109 -0
  89. package/dist/engine/template_asset_visibility.d.ts.map +1 -0
  90. package/dist/engine/template_asset_visibility.js +321 -0
  91. package/dist/engine/template_asset_visibility.js.map +1 -0
  92. package/dist/engine/template_init_sync.d.ts +68 -0
  93. package/dist/engine/template_init_sync.d.ts.map +1 -0
  94. package/dist/engine/template_init_sync.js +218 -0
  95. package/dist/engine/template_init_sync.js.map +1 -0
  96. package/dist/engine/template_manifest_io.d.ts +10 -0
  97. package/dist/engine/template_manifest_io.d.ts.map +1 -1
  98. package/dist/engine/template_manifest_io.js +63 -30
  99. package/dist/engine/template_manifest_io.js.map +1 -1
  100. package/dist/engine/template_mechanism_auditor.d.ts +3 -1
  101. package/dist/engine/template_mechanism_auditor.d.ts.map +1 -1
  102. package/dist/engine/template_mechanism_auditor.js +27 -24
  103. package/dist/engine/template_mechanism_auditor.js.map +1 -1
  104. package/dist/engine/tool_invocation_contract_registry.d.ts.map +1 -1
  105. package/dist/engine/tool_invocation_contract_registry.js +11 -1
  106. package/dist/engine/tool_invocation_contract_registry.js.map +1 -1
  107. package/dist/knowledge/index_manager.d.ts +20 -0
  108. package/dist/knowledge/index_manager.d.ts.map +1 -1
  109. package/dist/knowledge/index_manager.js +234 -3
  110. package/dist/knowledge/index_manager.js.map +1 -1
  111. package/dist/types.d.ts +36 -1
  112. package/dist/types.d.ts.map +1 -1
  113. package/package.json +2 -2
  114. package/templates/knowledge/rules//346/240/207/345/207/206/350/265/204/344/272/247/350/246/206/347/233/226/350/247/204/345/210/231.md +29 -0
  115. package/templates/knowledge/rules//346/250/241/346/235/277/350/265/204/344/272/247/345/217/257/350/247/201/346/200/247/350/247/204/345/210/231.md +27 -0
  116. package/templates/knowledge/rules//347/224/250/346/210/267/345/217/215/351/246/210/345/245/221/347/272/246/350/247/204/345/210/231.md +62 -1
  117. package/templates/knowledge/rules//351/200/232/347/224/250/345/206/263/347/255/226/347/240/224/350/256/250/350/247/204/345/210/231.md +30 -0
  118. package/templates/knowledge/rules//351/252/214/346/224/266/346/250/241/346/235/277/350/276/223/345/207/272/345/245/221/347/272/246/350/247/204/345/210/231.md +50 -0
@@ -0,0 +1,218 @@
1
+ /**
2
+ * 模板初始化同步 — init 命令的知识模板复制与全局模式安装。
3
+ *
4
+ * 将 CLI copyKnowledgeTemplates / copyGlobalPatterns 的核心逻辑抽为生产模块,
5
+ * 由 CLI、release gate、observed_consumption 共同调用。
6
+ * 每次调用均记录 consumption_trace,保证 trace 来源真实一致。
7
+ * 同步完成后写入 sync-manifest.json,记录每个同步文件的来源身份元数据。
8
+ */
9
+ import path from "node:path";
10
+ import fs from "node:fs";
11
+ import crypto from "node:crypto";
12
+ import { fileURLToPath } from "node:url";
13
+ import { getContractDecision } from "./template_asset_contract_registry.js";
14
+ import { recordConsumptionTrace } from "./consumption_trace_store.js";
15
+ const MANIFEST_PATH = ".soloforge/sync-manifest.json";
16
+ /**
17
+ * 读取同步清单。
18
+ */
19
+ export function readSyncManifest(projectPath) {
20
+ const manifestPath = path.join(projectPath, MANIFEST_PATH);
21
+ if (!fs.existsSync(manifestPath))
22
+ return null;
23
+ try {
24
+ return JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
25
+ }
26
+ catch {
27
+ return null;
28
+ }
29
+ }
30
+ /**
31
+ * 写入同步清单。
32
+ */
33
+ function writeSyncManifest(projectPath, manifest) {
34
+ const manifestPath = path.join(projectPath, MANIFEST_PATH);
35
+ fs.mkdirSync(path.dirname(manifestPath), { recursive: true });
36
+ fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
37
+ }
38
+ /** 计算文件 body SHA256(排除健康检查会修改的字段:frontmatter 和 YAML status/updated_at) */
39
+ function fileHash(filePath) {
40
+ const content = fs.readFileSync(filePath, "utf-8");
41
+ if (filePath.endsWith(".yaml") || filePath.endsWith(".yml")) {
42
+ // YAML 文件: 移除 status 和 updated_at 行后哈希
43
+ const stripped = content.split("\n")
44
+ .filter(line => !/^(status|updated_at)\s*:/.test(line.trim()))
45
+ .join("\n");
46
+ return crypto.createHash("sha256").update(stripped).digest("hex").substring(0, 16);
47
+ }
48
+ // Markdown: 排除 frontmatter 后哈希 body
49
+ const bodyStart = content.indexOf("---", content.indexOf("---") + 3);
50
+ const body = bodyStart >= 0 ? content.substring(bodyStart + 3).trimStart() : content;
51
+ return crypto.createHash("sha256").update(body).digest("hex").substring(0, 16);
52
+ }
53
+ /**
54
+ * 从权威来源(当前安装的模板包)计算 source_contract_path 的 body hash。
55
+ * 用于替代 sync-manifest.json 中用户可编辑的 source_hash。
56
+ * 返回 null 表示权威来源文件不存在(用户可能已卸载/升级包)。
57
+ */
58
+ export function computeAuthoritativeHash(sourceContractPath) {
59
+ const thisDir = path.dirname(fileURLToPath(import.meta.url));
60
+ const absPath = path.resolve(thisDir, "..", "..", sourceContractPath);
61
+ if (!fs.existsSync(absPath))
62
+ return null;
63
+ return fileHash(absPath);
64
+ }
65
+ /**
66
+ * 按目标 knowledge relativePath 反向解析权威来源身份。
67
+ * 不依赖用户可编辑 manifest 中的 source_contract_path/source_asset_id。
68
+ * 返回 null 表示无对应权威映射(非同步资产或模板包缺失)。
69
+ */
70
+ export function resolveAuthoritativeIdentity(knowledgeRelPath) {
71
+ const contractPath = `templates/knowledge/${knowledgeRelPath}`;
72
+ const hash = computeAuthoritativeHash(contractPath);
73
+ if (hash === null)
74
+ return null;
75
+ // getContractDecision 同步可用(已由 import 引入)
76
+ // 此函数由 KIM 在 filterByContractGate 中调用,KIM 已 import getContractDecision
77
+ // 直接返回路径和 hash,让 KIM 通过 getContractDecision 获取合同
78
+ return {
79
+ source_contract_path: contractPath,
80
+ source_asset_id: "", // 由 KIM 通过 getContractDecision 填充
81
+ source_hash: hash,
82
+ };
83
+ }
84
+ /**
85
+ * 遍历 templates/knowledge 下所有文件,通过 getContractDecision 门禁,
86
+ * 记录 consumption_trace 后复制到用户项目 .soloforge/knowledge/ 目录。
87
+ * 同步完成后写入 sync-manifest.json 记录来源身份。
88
+ */
89
+ export async function copyKnowledgeToProject(templatesRootDir, projectPath) {
90
+ const result = {
91
+ copied: 0,
92
+ skipped_internal: 0,
93
+ skipped_no_contract: 0,
94
+ patterns_copied: 0,
95
+ patterns_skipped: 0,
96
+ };
97
+ const knowledgeTemplatesDir = path.join(templatesRootDir, "templates", "knowledge");
98
+ if (!fs.existsSync(knowledgeTemplatesDir))
99
+ return result;
100
+ // 读取现有清单或创建新清单
101
+ const manifest = readSyncManifest(projectPath) ?? { version: 1, entries: {} };
102
+ const stack = [knowledgeTemplatesDir];
103
+ while (stack.length > 0) {
104
+ const currentDir = stack.pop();
105
+ for (const entry of fs.readdirSync(currentDir, { withFileTypes: true })) {
106
+ const srcPath = path.join(currentDir, entry.name);
107
+ if (entry.isDirectory()) {
108
+ stack.push(srcPath);
109
+ continue;
110
+ }
111
+ if (!/\.(md|yaml|yml)$/.test(entry.name))
112
+ continue;
113
+ const relPath = path.relative(knowledgeTemplatesDir, srcPath).replace(/\\/g, "/");
114
+ const fullRelPath = `templates/knowledge/${relPath}`;
115
+ const destPath = path.join(projectPath, ".soloforge", "knowledge", relPath);
116
+ const decision = getContractDecision(fullRelPath);
117
+ if (decision.decision === "unregistered") {
118
+ recordConsumptionTrace({
119
+ consumer: "init", asset_id: fullRelPath, asset_path: fullRelPath,
120
+ contract_decision: "unregistered",
121
+ fields_consumed: ["asset_path", "contract_decision", "target_path"],
122
+ matched_reason: "无合同注册",
123
+ task_id_or_route: "copyKnowledgeTemplates",
124
+ consumed_at: new Date().toISOString(),
125
+ });
126
+ result.skipped_no_contract++;
127
+ continue;
128
+ }
129
+ if (decision.decision === "denied") {
130
+ recordConsumptionTrace({
131
+ consumer: "init", asset_id: decision.contract?.asset_id ?? fullRelPath,
132
+ asset_path: fullRelPath, contract_decision: "denied",
133
+ fields_consumed: ["asset_path", "contract_decision", "target_path"],
134
+ matched_reason: `内部资产: ${decision.contract?.asset_visibility}`,
135
+ task_id_or_route: "copyKnowledgeTemplates",
136
+ consumed_at: new Date().toISOString(),
137
+ });
138
+ result.skipped_internal++;
139
+ continue;
140
+ }
141
+ if (decision.contract && !decision.contract.sync_to_user_project) {
142
+ recordConsumptionTrace({
143
+ consumer: "init", asset_id: decision.contract.asset_id,
144
+ asset_path: fullRelPath, contract_decision: "denied",
145
+ fields_consumed: ["asset_path", "contract_decision", "target_path"],
146
+ matched_reason: "sync_to_user_project=false",
147
+ task_id_or_route: "copyKnowledgeTemplates",
148
+ consumed_at: new Date().toISOString(),
149
+ });
150
+ result.skipped_internal++;
151
+ continue;
152
+ }
153
+ if (!fs.existsSync(destPath)) {
154
+ fs.mkdirSync(path.dirname(destPath), { recursive: true });
155
+ fs.copyFileSync(srcPath, destPath);
156
+ }
157
+ // 写入来源身份元数据到清单
158
+ manifest.entries[relPath] = {
159
+ source_asset_id: decision.contract.asset_id,
160
+ source_contract_path: fullRelPath,
161
+ source_hash: fileHash(srcPath),
162
+ synced_at: new Date().toISOString(),
163
+ };
164
+ recordConsumptionTrace({
165
+ consumer: "init", asset_id: decision.contract.asset_id,
166
+ asset_path: fullRelPath, contract_decision: "allowed",
167
+ fields_consumed: ["asset_path", "contract_decision", "target_path"],
168
+ matched_reason: "复制到用户项目",
169
+ task_id_or_route: "copyKnowledgeTemplates",
170
+ consumed_at: new Date().toISOString(),
171
+ declared_consumer: decision.contract.mainline_consumer,
172
+ });
173
+ result.copied++;
174
+ }
175
+ }
176
+ writeSyncManifest(projectPath, manifest);
177
+ return result;
178
+ }
179
+ /**
180
+ * 安装全局模式到指定目录。
181
+ * 遍历 templates/patterns 下所有文件,记录 consumption_trace。
182
+ */
183
+ export async function copyPatternsToGlobal(templatesRootDir, patternsDestDir) {
184
+ let copied = 0;
185
+ let skipped = 0;
186
+ const templatesDir = path.join(templatesRootDir, "templates", "patterns");
187
+ if (!fs.existsSync(templatesDir))
188
+ return { copied: 0, skipped: 0 };
189
+ fs.mkdirSync(patternsDestDir, { recursive: true });
190
+ const files = fs.readdirSync(templatesDir).filter(f => f.endsWith(".md"));
191
+ for (const f of files) {
192
+ const src = path.join(templatesDir, f);
193
+ const dest = path.join(patternsDestDir, f);
194
+ const fullRelPath = `templates/patterns/${f}`;
195
+ const decision = getContractDecision(fullRelPath);
196
+ recordConsumptionTrace({
197
+ consumer: "init",
198
+ asset_id: decision.contract?.asset_id ?? fullRelPath,
199
+ asset_path: fullRelPath,
200
+ contract_decision: decision.decision === "allowed" ? "allowed" : decision.decision === "denied" ? "denied" : "unregistered",
201
+ fields_consumed: ["asset_path", "contract_decision", "target_path"],
202
+ matched_reason: decision.decision === "allowed" ? "全局模式可复制" : `${decision.decision}`,
203
+ task_id_or_route: "copyGlobalPatterns",
204
+ consumed_at: new Date().toISOString(),
205
+ });
206
+ if (decision.decision === "allowed") {
207
+ if (!fs.existsSync(dest)) {
208
+ fs.copyFileSync(src, dest);
209
+ copied++;
210
+ }
211
+ else {
212
+ skipped++;
213
+ }
214
+ }
215
+ }
216
+ return { copied, skipped };
217
+ }
218
+ //# sourceMappingURL=template_init_sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template_init_sync.js","sourceRoot":"","sources":["../../src/engine/template_init_sync.ts"],"names":[],"mappings":"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"}
@@ -25,7 +25,17 @@ export declare function writeFileSyncRecursive(filePath: string, content: string
25
25
  * templates/patterns/{file} → .soloforge/knowledge/patterns/{file}(全局模式项目级副本)
26
26
  * templates/scaffolds/* → 不纳入模板同步(由 scaffold 命令管理)
27
27
  */
28
+ export interface ManifestBuildStats {
29
+ included: number;
30
+ skipped_internal: number;
31
+ skipped_unregistered: number;
32
+ skipped_scaffold: string[];
33
+ }
28
34
  export declare function buildTemplateManifestFromSource(sourceDir: string, packageVersion: string): TemplateManifestEntry[];
35
+ export declare function buildTemplateManifestWithStats(sourceDir: string, packageVersion: string): {
36
+ manifest: TemplateManifestEntry[];
37
+ stats: ManifestBuildStats;
38
+ };
29
39
  /** 读取项目已安装清单,不存在返回 null */
30
40
  export declare function loadProjectManifest(projectPath: string): TemplateManifestEntry[] | null;
31
41
  /** 写入项目已安装清单 */
@@ -1 +1 @@
1
- {"version":3,"file":"template_manifest_io.d.ts","sourceRoot":"","sources":["../../src/engine/template_manifest_io.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAG/E,YAAY,EAAE,qBAAqB,EAAE,CAAC;AAItC,2BAA2B;AAC3B,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAE1D;AAED,mCAAmC;AACnC,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOxD;AAED,wBAAwB;AACxB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAO1E;AAID,kBAAkB;AAClB,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGvF;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,GACrB,qBAAqB,EAAE,CAsEzB;AAMD,2BAA2B;AAC3B,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,qBAAqB,EAAE,GAAG,IAAI,CAQvF;AAED,gBAAgB;AAChB,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,qBAAqB,EAAE,GAChC,IAAI,CAGN;AAMD,aAAa;AACb,MAAM,WAAW,kBAAkB;IACjC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,yBAAyB,EAAE,MAAM,CAAC;IAClC,yBAAyB,EAAE,MAAM,CAAC;IAClC,yBAAyB,EAAE,MAAM,CAAC;IAClC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,0BAA0B;AAC1B,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAOjF;AAED,eAAe;AACf,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAEzF"}
1
+ {"version":3,"file":"template_manifest_io.d.ts","sourceRoot":"","sources":["../../src/engine/template_manifest_io.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAK/E,YAAY,EAAE,qBAAqB,EAAE,CAAC;AAItC,2BAA2B;AAC3B,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAE1D;AAED,mCAAmC;AACnC,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOxD;AAED,wBAAwB;AACxB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAO1E;AAID,kBAAkB;AAClB,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGvF;AAID;;;;;;;;;;GAUG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAiBD,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,GACrB,qBAAqB,EAAE,CAGzB;AAED,wBAAgB,8BAA8B,CAC5C,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,GACrB;IAAE,QAAQ,EAAE,qBAAqB,EAAE,CAAC;IAAC,KAAK,EAAE,kBAAkB,CAAA;CAAE,CAyFlE;AAMD,2BAA2B;AAC3B,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,qBAAqB,EAAE,GAAG,IAAI,CAQvF;AAED,gBAAgB;AAChB,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,qBAAqB,EAAE,GAChC,IAAI,CAGN;AAMD,aAAa;AACb,MAAM,WAAW,kBAAkB;IACjC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,yBAAyB,EAAE,MAAM,CAAC;IAClC,yBAAyB,EAAE,MAAM,CAAC;IAClC,yBAAyB,EAAE,MAAM,CAAC;IAClC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,0BAA0B;AAC1B,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAOjF;AAED,eAAe;AACf,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAEzF"}
@@ -8,6 +8,8 @@ import { createHash } from "node:crypto";
8
8
  import fs from "node:fs";
9
9
  import path from "node:path";
10
10
  import { findConsumableAssetByPath } from "./consumable_asset_registry.js";
11
+ import { getContractDecision } from "./template_asset_contract_registry.js";
12
+ import { recordConsumptionTrace } from "./consumption_trace_store.js";
11
13
  // ── 哈希工具 ──
12
14
  /** 计算内容的 SHA-256 十六进制摘要 */
13
15
  export function sha256Hex(content) {
@@ -39,41 +41,57 @@ export function writeFileSyncRecursive(filePath, content) {
39
41
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
40
42
  fs.writeFileSync(filePath, content);
41
43
  }
42
- // ── 清单构建 ──
43
- /**
44
- * 从模板源目录构建清单。
45
- *
46
- * 扫描 templates/ 目录下的文件,交叉引用 BUILTIN_CONSUMABLE_ASSETS
47
- * 获取 asset_id 和 asset_kind,计算源文件哈希。
48
- *
49
- * target_path 映射规则:
50
- * templates/knowledge/{sub} → .soloforge/knowledge/{sub}
51
- * templates/patterns/{file} → .soloforge/knowledge/patterns/{file}(全局模式项目级副本)
52
- * templates/scaffolds/* → 不纳入模板同步(由 scaffold 命令管理)
53
- */
44
+ /** 递归扫描目录下所有 .md/.yaml/.yml 文件 */
45
+ function walkDirRecursive(dir) {
46
+ const results = [];
47
+ const stack = [dir];
48
+ while (stack.length > 0) {
49
+ const current = stack.pop();
50
+ for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
51
+ const absPath = path.join(current, entry.name);
52
+ if (entry.isDirectory()) {
53
+ stack.push(absPath);
54
+ continue;
55
+ }
56
+ if (/\.(md|yaml|yml)$/.test(entry.name))
57
+ results.push(absPath);
58
+ }
59
+ }
60
+ return results;
61
+ }
54
62
  export function buildTemplateManifestFromSource(sourceDir, packageVersion) {
63
+ const { manifest } = buildTemplateManifestWithStats(sourceDir, packageVersion);
64
+ return manifest;
65
+ }
66
+ export function buildTemplateManifestWithStats(sourceDir, packageVersion) {
55
67
  const manifest = [];
56
- const now = new Date().toISOString();
57
- // 知识模板子目录(与 copyKnowledgeTemplates 一致)
58
- const knowledgeSubDirs = [
59
- "procedures", "domain", "product_profiles", "acceptance_templates",
60
- "review_rules", "patterns/core", "checklists", "templates", "rules",
61
- ];
62
- // 扫描知识模板
68
+ const stats = { included: 0, skipped_internal: 0, skipped_unregistered: 0, skipped_scaffold: [] };
69
+ // 递归扫描 templates/knowledge 下所有文件(不使用硬编码子目录列表)
63
70
  const knowledgeDir = path.join(sourceDir, "knowledge");
64
- for (const subDir of knowledgeSubDirs) {
65
- const absDir = path.join(knowledgeDir, subDir);
66
- if (!fs.existsSync(absDir))
67
- continue;
68
- const files = fs.readdirSync(absDir).filter((f) => f.endsWith(".md") || f.endsWith(".yaml") || f.endsWith(".yml"));
69
- for (const file of files) {
70
- const relSource = `templates/knowledge/${subDir}/${file}`;
71
- const absSource = path.join(absDir, file);
71
+ if (fs.existsSync(knowledgeDir)) {
72
+ const knowledgeFiles = walkDirRecursive(knowledgeDir);
73
+ for (const absSource of knowledgeFiles) {
74
+ const relFromKnowledge = path.relative(knowledgeDir, absSource).replace(/\\/g, "/");
75
+ const relSource = `templates/knowledge/${relFromKnowledge}`;
76
+ const file = path.basename(absSource);
77
+ // 合同门禁: 逐文件调用 getContractDecision
78
+ const decision = getContractDecision(relSource);
79
+ if (decision.decision === "denied") {
80
+ recordConsumptionTrace({ consumer: "sync_templates", asset_id: decision.contract?.asset_id ?? relSource, asset_path: relSource, contract_decision: "denied", fields_consumed: ["asset_path", "contract_decision", "source_hash"], matched_reason: "内部资产跳过", task_id_or_route: "buildTemplateManifest", consumed_at: new Date().toISOString() });
81
+ stats.skipped_internal++;
82
+ continue;
83
+ }
84
+ if (decision.decision === "unregistered") {
85
+ recordConsumptionTrace({ consumer: "sync_templates", asset_id: relSource, asset_path: relSource, contract_decision: "unregistered", fields_consumed: ["asset_path", "contract_decision", "source_hash"], matched_reason: "未注册资产跳过", task_id_or_route: "buildTemplateManifest", consumed_at: new Date().toISOString() });
86
+ stats.skipped_unregistered++;
87
+ continue;
88
+ }
72
89
  const sourceHash = hashFile(absSource) ?? "";
73
90
  const asset = findConsumableAssetByPath(relSource);
74
- const targetPath = `.soloforge/knowledge/${subDir}/${file}`;
91
+ const subDir = path.dirname(relFromKnowledge);
92
+ const targetPath = `.soloforge/knowledge/${relFromKnowledge}`;
75
93
  // 推导 sovereignty
76
- const isCore = subDir === "patterns/core" ||
94
+ const isCore = relFromKnowledge.startsWith("patterns/core/") ||
77
95
  (asset?.consumption_mode === "required" && asset?.asset_kind === "capability_knowledge_doc");
78
96
  manifest.push({
79
97
  asset_id: asset?.id ?? `tpl-${subDir}-${file}`,
@@ -87,6 +105,8 @@ export function buildTemplateManifestFromSource(sourceDir, packageVersion) {
87
105
  source_package_version: packageVersion,
88
106
  sovereignty: isCore ? "core" : "normal",
89
107
  });
108
+ recordConsumptionTrace({ consumer: "sync_templates", asset_id: asset?.id ?? `tpl-${subDir}-${file}`, asset_path: relSource, contract_decision: "allowed", fields_consumed: ["asset_path", "contract_decision", "source_hash"], matched_reason: "清单收录", task_id_or_route: "buildTemplateManifest", consumed_at: new Date().toISOString() });
109
+ stats.included++;
90
110
  }
91
111
  }
92
112
  // 扫描全局模式(项目级副本)
@@ -96,6 +116,17 @@ export function buildTemplateManifestFromSource(sourceDir, packageVersion) {
96
116
  for (const file of files) {
97
117
  const relSource = `templates/patterns/${file}`;
98
118
  const absSource = path.join(patternsDir, file);
119
+ const decision = getContractDecision(relSource);
120
+ if (decision.decision === "denied") {
121
+ recordConsumptionTrace({ consumer: "sync_templates", asset_id: decision.contract?.asset_id ?? relSource, asset_path: relSource, contract_decision: "denied", fields_consumed: ["asset_path", "contract_decision", "source_hash"], matched_reason: "内部资产跳过", task_id_or_route: "buildTemplateManifest", consumed_at: new Date().toISOString() });
122
+ stats.skipped_internal++;
123
+ continue;
124
+ }
125
+ if (decision.decision === "unregistered") {
126
+ recordConsumptionTrace({ consumer: "sync_templates", asset_id: relSource, asset_path: relSource, contract_decision: "unregistered", fields_consumed: ["asset_path", "contract_decision", "source_hash"], matched_reason: "未注册资产跳过", task_id_or_route: "buildTemplateManifest", consumed_at: new Date().toISOString() });
127
+ stats.skipped_unregistered++;
128
+ continue;
129
+ }
99
130
  const sourceHash = hashFile(absSource) ?? "";
100
131
  const asset = findConsumableAssetByPath(relSource);
101
132
  manifest.push({
@@ -110,9 +141,11 @@ export function buildTemplateManifestFromSource(sourceDir, packageVersion) {
110
141
  source_package_version: packageVersion,
111
142
  sovereignty: "normal",
112
143
  });
144
+ recordConsumptionTrace({ consumer: "sync_templates", asset_id: asset?.id ?? `pat-${file}`, asset_path: relSource, contract_decision: "allowed", fields_consumed: ["asset_path", "contract_decision", "source_hash"], matched_reason: "清单收录", task_id_or_route: "buildTemplateManifest", consumed_at: new Date().toISOString() });
145
+ stats.included++;
113
146
  }
114
147
  }
115
- return manifest;
148
+ return { manifest, stats };
116
149
  }
117
150
  // ── 清单持久化 ──
118
151
  const MANIFEST_FILE = ".soloforge/manifest.json";
@@ -1 +1 @@
1
- {"version":3,"file":"template_manifest_io.js","sourceRoot":"","sources":["../../src/engine/template_manifest_io.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"template_manifest_io.js","sourceRoot":"","sources":["../../src/engine/template_manifest_io.ts"],"names":[],"mappings":"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"}
@@ -77,7 +77,9 @@ export interface TemplateMechanismAuditReport {
77
77
  * @param rootDir - 项目根目录
78
78
  * @returns 完整的审计报告
79
79
  */
80
- export declare function auditTemplateMechanisms(rootDir: string): TemplateMechanismAuditReport;
80
+ export declare function auditTemplateMechanisms(rootDir: string, options?: {
81
+ workflowContentOverride?: string;
82
+ }): TemplateMechanismAuditReport;
81
83
  /**
82
84
  * 检查资产是否允许注入到当前上下文。
83
85
  * 基于资产消费模式、所属机制状态、当前路由和工作流进行多重校验。
@@ -1 +1 @@
1
- {"version":3,"file":"template_mechanism_auditor.d.ts","sourceRoot":"","sources":["../../src/engine/template_mechanism_auditor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAA+B,KAAK,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACtG,OAAO,EAEL,KAAK,qBAAqB,EAE3B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EACV,0BAA0B,EAC1B,wBAAwB,EAEzB,MAAM,aAAa,CAAC;AAuBrB,eAAe;AACf,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,UAAU,GAAG,YAAY,GAAG,oBAAoB,GAAG,qBAAqB,CAAC;CAClF;AAED,aAAa;AACb,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,wBAAwB,CAAC;IACjC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,YAAY,CAAC,EAAE,qBAAqB,CAAC;IACrC,KAAK,CAAC,EAAE,eAAe,GAAG,WAAW,GAAG,mBAAmB,CAAC;CAC7D;AAED,gBAAgB;AAChB,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,gBAAgB,CAAC,EAAE,wBAAwB,CAAC;IAC5C,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC;CAClC;AAED,eAAe;AACf,MAAM,WAAW,4BAA4B;IAC3C,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,uBAAuB,EAAE,MAAM,CAAC;IAChC,gBAAgB,EAAE,MAAM,CAAC;IAEzB,+CAA+C;IAC/C,wBAAwB,EAAE,uBAAuB,EAAE,CAAC;IACpD,sBAAsB;IACtB,0BAA0B,EAAE,uBAAuB,EAAE,CAAC;IACtD,sBAAsB;IACtB,wBAAwB,EAAE,mBAAmB,EAAE,CAAC;IAChD,sBAAsB;IACtB,oBAAoB,EAAE,mBAAmB,EAAE,CAAC;IAC5C,wBAAwB;IACxB,0BAA0B,EAAE,wBAAwB,EAAE,CAAC;IACvD,gBAAgB;IAChB,wBAAwB,EAAE,0BAA0B,EAAE,CAAC;IACvD,kBAAkB;IAClB,0BAA0B,EAAE,uBAAuB,EAAE,CAAC;IACtD,2BAA2B;IAC3B,gCAAgC,EAAE,uBAAuB,EAAE,CAAC;IAC5D,uBAAuB;IACvB,gBAAgB,EAAE,mBAAmB,EAAE,CAAC;IACxC,uBAAuB;IACvB,sBAAsB,EAAE,0BAA0B,EAAE,CAAC;IACrD,yBAAyB;IACzB,2BAA2B,EAAE,0BAA0B,EAAE,CAAC;IAE1D,qBAAqB;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,oBAAoB;IACpB,cAAc,EAAE,MAAM,CAAC;CACxB;AAaD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,4BAA4B,CAyNrF;AAmLD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,kBAAkB,EACzB,YAAY,CAAC,EAAE,MAAM,EACrB,eAAe,CAAC,EAAE,MAAM,GACvB;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAoDvC"}
1
+ {"version":3,"file":"template_mechanism_auditor.d.ts","sourceRoot":"","sources":["../../src/engine/template_mechanism_auditor.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,7 @@ import path from "node:path";
9
9
  import { listBuiltinConsumableAssets } from "./consumable_asset_registry.js";
10
10
  import { listMechanismLayerMaps, checkDualLayerCompleteness, } from "./dual_layer_mechanism_registry.js";
11
11
  import { WORKFLOW_TEMPLATE_HARD_RULES } from "./asset_manifest.js";
12
+ import { generateWorkflowRules } from "../adapters/shared/workflow_template.js";
12
13
  import { debug } from "./logger.js";
13
14
  // ── 模板扫描目录 ──
14
15
  const TEMPLATE_SCAN_DIRS = [
@@ -39,7 +40,7 @@ const ENFORCED_PROMISE_PATTERNS = [
39
40
  * @param rootDir - 项目根目录
40
41
  * @returns 完整的审计报告
41
42
  */
42
- export function auditTemplateMechanisms(rootDir) {
43
+ export function auditTemplateMechanisms(rootDir, options) {
43
44
  debug("TemplateMechanismAuditor", "开始模板机制审计");
44
45
  const assets = listBuiltinConsumableAssets();
45
46
  const maps = listMechanismLayerMaps();
@@ -82,6 +83,8 @@ export function auditTemplateMechanisms(rootDir) {
82
83
  // 5. 仅代码的机制
83
84
  const codeOnlyMechanisms = [];
84
85
  for (const m of maps) {
86
+ if (m.status === "experimental_dual_layer")
87
+ continue;
85
88
  const completeness = checkDualLayerCompleteness(m);
86
89
  if (!completeness.has_template_layer && completeness.has_code_layer) {
87
90
  codeOnlyMechanisms.push({
@@ -166,7 +169,8 @@ export function auditTemplateMechanisms(rootDir) {
166
169
  // 11. 薄模板发现(厚重内容、过大模板)
167
170
  const thinTemplateFindings = computeThinTemplateFindings(rootDir);
168
171
  // 12. 工作流硬性规则发现
169
- const workflowHardRuleFindings = computeWorkflowHardRuleFindings(rootDir, mechanismMap);
172
+ const wfContent = options?.workflowContentOverride ?? generateWorkflowRules({});
173
+ const workflowHardRuleFindings = computeWorkflowHardRuleFindings(rootDir, mechanismMap, wfContent);
170
174
  // 计算统计数量
171
175
  const allFindings = [
172
176
  ...driftFindings,
@@ -276,6 +280,8 @@ function computeDriftFindings(maps, assets, rootDir) {
276
280
  const findings = [];
277
281
  const assetPathSet = new Set(assets.map((a) => a.path));
278
282
  for (const m of maps) {
283
+ if (m.status === "experimental_dual_layer")
284
+ continue;
279
285
  if ((m.priority === "P0" || m.priority === "P1") && m.status !== "dual_layer_enforced") {
280
286
  findings.push({
281
287
  severity: "hard_fail",
@@ -522,31 +528,28 @@ function computeThinTemplateFindings(rootDir) {
522
528
  * 检查工作流模板硬性规则的一致性。
523
529
  * 校验 marker 与 manifest 的对应关系、source_ref 有效性和机制状态。
524
530
  */
525
- function computeWorkflowHardRuleFindings(rootDir, mechanismMap) {
531
+ function computeWorkflowHardRuleFindings(rootDir, mechanismMap, workflowContent) {
526
532
  const findings = [];
527
533
  const registeredRules = new Map(WORKFLOW_TEMPLATE_HARD_RULES.map(r => [r.rule_id, r]));
528
- const wfPath = path.join(rootDir, "src/adapters/shared/workflow_template.ts");
529
- // 收集模板文件中所有 marker
534
+ // 收集生成输出中所有 marker(单真源方向: manifest → hardRuleTag → 输出)
530
535
  const markerIds = new Set();
531
536
  const markerMechanisms = new Map();
532
- if (fs.existsSync(wfPath)) {
533
- const content = fs.readFileSync(wfPath, "utf-8");
534
- const markerRegex = /@sf-hard-rule\s+id=(\S+)\s+mechanism=(\S+)/g;
535
- let match;
536
- while ((match = markerRegex.exec(content)) !== null) {
537
- markerIds.add(match[1]);
538
- markerMechanisms.set(match[1], match[2]);
539
- }
540
- // 检查 1: marker manifest(marker 存在但未在 manifest 中注册)
541
- for (const markerId of markerIds) {
542
- if (!registeredRules.has(markerId)) {
543
- findings.push({
544
- severity: "hard_fail",
545
- mechanism_id: "workflow_hard_rule",
546
- finding_type: "unregistered_hard_rule",
547
- message: `@sf-hard-rule id=${markerId} 未在 WORKFLOW_TEMPLATE_HARD_RULES 中注册`,
548
- });
549
- }
537
+ const content = workflowContent ?? generateWorkflowRules({});
538
+ const markerRegex = /@sf-hard-rule\s+id=(\S+)\s+mechanism=(\S+)/g;
539
+ let match;
540
+ while ((match = markerRegex.exec(content)) !== null) {
541
+ markerIds.add(match[1]);
542
+ markerMechanisms.set(match[1], match[2]);
543
+ }
544
+ // 检查 1: marker → manifest(marker 存在但未在 manifest 中注册)
545
+ for (const markerId of markerIds) {
546
+ if (!registeredRules.has(markerId)) {
547
+ findings.push({
548
+ severity: "hard_fail",
549
+ mechanism_id: "workflow_hard_rule",
550
+ finding_type: "unregistered_hard_rule",
551
+ message: `@sf-hard-rule id=${markerId} 未在 WORKFLOW_TEMPLATE_HARD_RULES 中注册`,
552
+ });
550
553
  }
551
554
  }
552
555
  // 检查 2: manifest → marker(manifest 规则在模板中无对应 marker)
@@ -609,7 +612,7 @@ function computeWorkflowHardRuleFindings(rootDir, mechanismMap) {
609
612
  message: `manifest rule ${rule.rule_id} mechanism_id=${rule.mechanism_id} 未在机制注册表中找到`,
610
613
  });
611
614
  }
612
- else if (mech.status !== "dual_layer_enforced") {
615
+ else if (mech.status !== "dual_layer_enforced" && mech.status !== "experimental_dual_layer") {
613
616
  findings.push({
614
617
  severity: "hard_fail",
615
618
  mechanism_id: rule.mechanism_id,