@haaaiawd/loom 1.3.1 → 2.0.0

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 (84) hide show
  1. package/CHANGELOG.md +11 -86
  2. package/CONTRIBUTING.md +37 -0
  3. package/EVIL_EVAL.md +112 -0
  4. package/README.md +193 -445
  5. package/README.zh-CN.md +174 -0
  6. package/SECURITY.md +11 -0
  7. package/cli/bin/loom.js +171 -998
  8. package/cli/src/protocol.js +367 -0
  9. package/cli/src/store.js +626 -0
  10. package/design.md +194 -0
  11. package/docs/PROMPT_CATALOG.md +99 -0
  12. package/docs/RELEASE_CHECKLIST.md +53 -0
  13. package/docs/UX_FLOW.md +171 -0
  14. package/docs/brand/loom-mark.svg +18 -0
  15. package/docs/brand/loom-readme-header.svg +34 -0
  16. package/docs/brand/loom-readme-header.zh-CN.svg +29 -0
  17. package/docs/loom-eval-loop.drawio +21 -0
  18. package/docs/loom-eval-loop.svg +56 -0
  19. package/docs/loom-production-loop.drawio +41 -0
  20. package/docs/loom-production-loop.svg +92 -0
  21. package/package.json +43 -40
  22. package/EXTERNAL_ACQUISITION_DESIGN.md +0 -143
  23. package/cli/help/asset.md +0 -36
  24. package/cli/help/atelier.md +0 -37
  25. package/cli/help/atlas.md +0 -48
  26. package/cli/help/capability.md +0 -118
  27. package/cli/help/concepts.md +0 -105
  28. package/cli/help/doctor.md +0 -80
  29. package/cli/help/expertise.md +0 -52
  30. package/cli/help/loop.md +0 -134
  31. package/cli/help/patch.md +0 -33
  32. package/cli/help/proposals.md +0 -21
  33. package/cli/help/version.md +0 -136
  34. package/cli/help/workflow.md +0 -116
  35. package/cli/src/activate.js +0 -505
  36. package/cli/src/asset-library.js +0 -384
  37. package/cli/src/atelier.js +0 -331
  38. package/cli/src/atlas.js +0 -282
  39. package/cli/src/auto.js +0 -116
  40. package/cli/src/capability-graph.js +0 -724
  41. package/cli/src/capability-proposals.js +0 -225
  42. package/cli/src/diagnostics.js +0 -859
  43. package/cli/src/expertise-pack.js +0 -336
  44. package/cli/src/guide.js +0 -548
  45. package/cli/src/help.js +0 -41
  46. package/cli/src/init.js +0 -187
  47. package/cli/src/intent-draft.js +0 -303
  48. package/cli/src/intent-map.js +0 -747
  49. package/cli/src/patch.js +0 -214
  50. package/cli/src/philosophy.js +0 -331
  51. package/cli/src/shared/intent-ref.js +0 -38
  52. package/cli/src/shared/md-utils.js +0 -125
  53. package/cli/src/shared/paths.js +0 -73
  54. package/cli/src/shared/proof-reference.js +0 -19
  55. package/cli/src/shared/verification-method.js +0 -32
  56. package/cli/src/verify.js +0 -394
  57. package/cli/src/version.js +0 -134
  58. package/dimensions/AUTHORSHIP.md +0 -45
  59. package/dimensions/PART_DECOMPOSITION.md +0 -42
  60. package/dimensions/SEARCH_METHODOLOGY.md +0 -101
  61. package/dimensions/examples/AGENT_SYSTEM/README.md +0 -219
  62. package/dimensions/examples/CLI_TOOL/README.md +0 -163
  63. package/dimensions/universal/COLLABORATION_PHILOSOPHY.md +0 -28
  64. package/dimensions/universal/ENGINEERING_CREED.md +0 -30
  65. package/dimensions/universal/PRODUCT_PHILOSOPHY.md +0 -32
  66. package/meta/BASELINE.md +0 -91
  67. package/meta/INTENT_LOOP.md +0 -296
  68. package/meta/PHILOSOPHY_WEAVER.md +0 -110
  69. package/meta/ROLE_ACTIVATION.md +0 -114
  70. package/roles/architect.md +0 -92
  71. package/roles/forge.md +0 -110
  72. package/roles/impact-reviewer.md +0 -37
  73. package/roles/keeper.md +0 -113
  74. package/roles/visionary.md +0 -57
  75. package/templates/ASSET_LIBRARY_MANIFEST_TEMPLATE.json +0 -10
  76. package/templates/ATELIER_RECORD_TEMPLATE.json +0 -48
  77. package/templates/ATLAS_TEMPLATE.html +0 -104
  78. package/templates/CAPABILITY_BRIEF_TEMPLATE.md +0 -36
  79. package/templates/CAPABILITY_GRAPH_EXAMPLE.json +0 -188
  80. package/templates/CAPABILITY_GRAPH_TEMPLATE.json +0 -78
  81. package/templates/EXPERTISE_PACK_TEMPLATE.json +0 -22
  82. package/templates/INTENT_MAP_TEMPLATE.json +0 -85
  83. package/templates/PHILOSOPHY_TEMPLATE.md +0 -44
  84. package/templates/VISION_TEMPLATE.md +0 -44
@@ -1,505 +0,0 @@
1
- // activate — compile a role- and intent-scoped Context Pack.
2
-
3
- import { readFileSync, existsSync, readdirSync } from 'node:fs';
4
- import { join, relative } from 'node:path';
5
- import { getLoomRoot } from './shared/paths.js';
6
- import { getIntent, getNarrative } from './intent-map.js';
7
- import { getIntentDraft } from './intent-draft.js';
8
- import { getPhilosophy } from './philosophy.js';
9
- import { getVerificationContract } from './verify.js';
10
- import { extractMdSection } from './shared/md-utils.js';
11
- import { compileCapabilityInputs } from './capability-graph.js';
12
- import { getAtelierRecord } from './atelier.js';
13
- import { formatExpertisePackForPrompt, getExpertisePack, getExpertisePackState } from './expertise-pack.js';
14
- import { listCapabilityProposals } from './capability-proposals.js';
15
-
16
- const VALID_ROLES = ['weaver', 'visionary', 'architect', 'impact-reviewer', 'forge', 'keeper'];
17
-
18
- const ROLE_FILES = {
19
- weaver: 'meta/PHILOSOPHY_WEAVER.md',
20
- visionary: 'roles/visionary.md',
21
- architect: 'roles/architect.md',
22
- 'impact-reviewer': 'roles/impact-reviewer.md',
23
- forge: 'roles/forge.md',
24
- keeper: 'roles/keeper.md',
25
- };
26
-
27
- const ROLE_PHILOSOPHY_FILES = {
28
- visionary: ['PRODUCT_PHILOSOPHY.md', 'DECISION_RUBRIC.md'],
29
- architect: ['ENGINEERING_CREED.md', 'DECISION_RUBRIC.md'],
30
- 'impact-reviewer': ['PRODUCT_PHILOSOPHY.md', 'DECISION_RUBRIC.md'],
31
- forge: ['ENGINEERING_CREED.md'],
32
- keeper: ['PRODUCT_PHILOSOPHY.md', 'DECISION_RUBRIC.md'],
33
- };
34
-
35
- const BASELINE_SUMMARY = [
36
- '- B1:实质修改前理解真实结构,不创建平行体系。',
37
- '- B2:秘密、环境值和可变配置不写死。',
38
- '- B3:用户或系统可观察的行为具有显式契约。',
39
- '- B4:重要且会影响未来的判断可追溯。',
40
- '- B5:完成关联原始意图和当前 revision 证据;质量提升具有基线相对证据。',
41
- ].join('\n');
42
-
43
- function section(title, body) {
44
- const content = String(body || '').trim();
45
- return `## ${title}\n\n${content || '无。'}`;
46
- }
47
-
48
- function readRole(role) {
49
- const filePath = join(getLoomRoot(), ROLE_FILES[role]);
50
- if (!existsSync(filePath)) throw new Error(`角色文件不存在: ${filePath}`);
51
- return readFileSync(filePath, 'utf-8');
52
- }
53
-
54
- function getVerificationMethod(intent) {
55
- return intent?.verification_method || intent?._optional?.verification_method || null;
56
- }
57
-
58
- function resolveContractReference(versionDir, value, label) {
59
- if (!value) return null;
60
- if (typeof value !== 'string') return JSON.stringify(value, null, 2);
61
- const match = value.trim().match(/^(?:see\s+)?([^#]+)#([\w-]+)$/i);
62
- if (!match) return value;
63
- const [, file, anchor] = match;
64
- if (file.includes('/') || file.includes('\\') || file !== '05_VERIFICATION.md') {
65
- throw new Error(`${label}引用必须位于 05_VERIFICATION.md: ${value}`);
66
- }
67
- const filePath = join(versionDir, file);
68
- if (!existsSync(filePath)) throw new Error(`${label}引用的文件不存在: ${filePath}`);
69
- return extractMdSection(readFileSync(filePath, 'utf-8'), anchor, label);
70
- }
71
-
72
- function compileEnvelope(role, intentId) {
73
- const scope = intentId ? `仅 ${intentId}` : '当前角色的项目阶段';
74
- const lines = [
75
- `- role: ${role}`,
76
- `- scope: ${scope}`,
77
- '- 本 Context Pack 不会清除现有会话记忆。',
78
- '- system、developer 与用户指令优先;项目事实冲突时报告,不静默混用。',
79
- '- 只在当前角色权限和明确作用域内行动。',
80
- ];
81
- if (role === 'keeper') {
82
- lines.push('- Keeper 必须在新的 Agent thread 中运行;同一会话切换角色不构成独立验证。');
83
- lines.push('- 无法获得独立上下文时降低声明,关键判断使用 pending_human。');
84
- }
85
- if (role === 'impact-reviewer') {
86
- lines.push('- Impact Reviewer 必须在新的 Agent thread 中运行;不得与 Architect 共用本轮推理上下文。');
87
- lines.push('- 只审能力影响等级与外部获取必要性;不改产品目标、不写 Intent、不实现功能。');
88
- }
89
- return lines.join('\n');
90
- }
91
-
92
- function compileObjective(role, versionDir, intentId) {
93
- if (!intentId) {
94
- return {
95
- body: role === 'weaver'
96
- ? '织造当前项目的 Project Doctrine。先读取真实项目与完整 BASELINE,不预写产品或架构。'
97
- : `履行 ${role} 的当前项目阶段职责;未指定 Intent,不得自行选择并处理实现任务。`,
98
- intent: null,
99
- draft: null,
100
- narrative: null,
101
- };
102
- }
103
-
104
- if (role === 'visionary' || role === 'architect') {
105
- const draft = getIntentDraft(versionDir, intentId);
106
- const match = draft.narrative_ref.match(/^([^#]+)#([\w-]+)$/);
107
- if (!match || match[1] !== '01_VISION.md') throw new Error(`draft narrative_ref 非法: ${draft.narrative_ref}`);
108
- const narrative = extractMdSection(
109
- readFileSync(join(versionDir, match[1]), 'utf-8'),
110
- match[2],
111
- 'draft 意图叙事',
112
- );
113
- const visibleDraft = role === 'visionary'
114
- ? {
115
- id: draft.id,
116
- revision: draft.revision,
117
- title: draft.title,
118
- narrative_ref: draft.narrative_ref,
119
- depends_on: draft.depends_on,
120
- }
121
- : draft;
122
- return {
123
- body: [
124
- '只处理下面这个 draft。不要修改官方 Intent Map,不要处理其他 Intent,不要自行 finalize。',
125
- '',
126
- '### Draft',
127
- '',
128
- '```json',
129
- JSON.stringify(visibleDraft, null, 2),
130
- '```',
131
- '',
132
- '### Narrative',
133
- '',
134
- narrative,
135
- ].join('\n'),
136
- intent: null,
137
- draft,
138
- narrative,
139
- };
140
- }
141
-
142
- const intent = getIntent(versionDir, intentId);
143
- if (['forge', 'keeper'].includes(role)) {
144
- const unfinishedDependencies = intent.depends_on.filter((dependencyId) => getIntent(versionDir, dependencyId).status !== 'completed');
145
- if (unfinishedDependencies.length) {
146
- throw new Error(`Intent ${intentId} 的依赖尚未闭合: ${unfinishedDependencies.join(', ')}。不得通过 activate --intent 绕过执行顺序;先运行 loom intent next 或完成依赖 Intent。`);
147
- }
148
- }
149
- const narrative = getNarrative(versionDir, intentId);
150
- const objectiveView = {
151
- id: intent.id,
152
- revision: intent.revision,
153
- title: intent.title,
154
- status: intent.status,
155
- narrative_ref: intent.narrative_ref,
156
- depends_on: intent.depends_on,
157
- };
158
- return {
159
- body: [
160
- '只实现或验证下面这个官方 Intent。不得加载或顺便处理其他 Intent。',
161
- '',
162
- '### Intent',
163
- '',
164
- '```json',
165
- JSON.stringify(objectiveView, null, 2),
166
- '```',
167
- '',
168
- '### Narrative',
169
- '',
170
- narrative,
171
- ].join('\n'),
172
- intent,
173
- draft: null,
174
- narrative,
175
- };
176
- }
177
-
178
- function compileInvariants(role, versionDir) {
179
- const blocks = [];
180
- const baselinePath = join(getLoomRoot(), 'meta/BASELINE.md');
181
- blocks.push(role === 'weaver' ? readFileSync(baselinePath, 'utf-8') : BASELINE_SUMMARY);
182
- if (versionDir) {
183
- const projectBaseline = join(versionDir, '00_PHILOSOPHY', 'PROJECT_BASELINE.md');
184
- if (existsSync(projectBaseline)) {
185
- blocks.push(`### Project Baseline\n\n${readFileSync(projectBaseline, 'utf-8')}`);
186
- }
187
- }
188
- return blocks.join('\n\n');
189
- }
190
-
191
- function compileContracts(role, versionDir, objective) {
192
- const subject = objective.intent || objective.draft;
193
- if (!subject || role === 'visionary') {
194
- return role === 'visionary'
195
- ? 'Visionary 只定义目标、非目标和 narrative;不要编写 acceptance 或架构。'
196
- : '按当前角色 Output Contract 交付。';
197
- }
198
-
199
- const blocks = [];
200
- if (subject.acceptance) {
201
- const acceptance = objective.intent
202
- ? getVerificationContract(versionDir, subject.id)
203
- : resolveContractReference(versionDir, subject.acceptance, 'draft 完成契约');
204
- blocks.push(`### Acceptance / Reliability Floor\n\n${acceptance}`);
205
- }
206
- if (subject.quality_contract) {
207
- blocks.push(
208
- `### Quality Contract / Distinctive Ceiling\n\n` +
209
- resolveContractReference(versionDir, subject.quality_contract, '质量契约'),
210
- );
211
- }
212
- const verificationMethod = getVerificationMethod(subject);
213
- blocks.push(`### Verification Method\n\n${verificationMethod || '未声明:Keeper 使用适当的静态检查;需要运行时或人类判断却缺少入口时回流 Architect。'}`);
214
- const continuity = subject.continuity_required
215
- ? '此 Intent 已启用状态守恒门:通过前必须证明“旧状态 → 本轮操作 → 新状态”的完整序列中,未获明确授权删除或替换的既有价值、数据和可见结果仍被保留。'
216
- : '默认不启用状态守恒门;若本 Intent 会变更既有用户数据、持久状态、迁移结果或既有工作流,Architect 必须把 continuity_required 设为 true,并在 acceptance 写出保留项与时序验证。';
217
- blocks.push(
218
- '### Completion Gate / Codex Goal Alignment\n\n' +
219
- '将当前 Intent 视为本轮 Codex goal 的可闭合单元。goal 保持 active,直到结果达成、适用的状态守恒和可复现证据同时成立;goal/status 只是运行记录,不能替代验证证据。\n\n' +
220
- continuity,
221
- );
222
- return blocks.join('\n\n');
223
- }
224
-
225
- function compileProjectJudgment(role, versionDir, objective) {
226
- if (!versionDir || role === 'weaver') {
227
- return role === 'weaver'
228
- ? '从用户目标、仓库事实与决策相关证据建立 Project Doctrine。'
229
- : '当前版本目录不可用。';
230
- }
231
-
232
- const philosophyDir = join(versionDir, '00_PHILOSOPHY');
233
- const blocks = [];
234
- const missing = [];
235
- const anchors = (objective.intent || objective.draft)?.philosophy_anchors || [];
236
-
237
- if (anchors.length > 0) {
238
- for (const anchor of anchors) {
239
- blocks.push(`### ${anchor}\n\n${getPhilosophy(philosophyDir, anchor)}`);
240
- }
241
- } else {
242
- for (const file of ROLE_PHILOSOPHY_FILES[role] || []) {
243
- const filePath = join(philosophyDir, file);
244
- if (!existsSync(filePath)) {
245
- missing.push(file);
246
- continue;
247
- }
248
- blocks.push(`### ${file}\n\n${readFileSync(filePath, 'utf-8')}`);
249
- }
250
- if (missing.length) {
251
- blocks.push(
252
- `### Context Warning\n\n缺少: ${missing.join(', ')}。` +
253
- '不要用通用偏好伪造项目判断;回流 Weaver 或向用户索取必要决定。',
254
- );
255
- }
256
- }
257
- return blocks.join('\n\n');
258
- }
259
-
260
- function compileExpertiseInputs(role, versionDir, objective) {
261
- const subject = objective.intent || objective.draft;
262
- if (!subject || !['architect', 'forge', 'keeper'].includes(role)) {
263
- return '当前阶段不编译任务级 Expertise Pack。';
264
- }
265
- const needs = Array.isArray(subject.capability_needs) ? subject.capability_needs : [];
266
- const qualityStrategy = subject.quality_strategy ?? 'adaptive';
267
- const lines = [
268
- `- capability_needs: ${needs.length ? needs.join(', ') : '未声明;按当前任务发现必要能力'}`,
269
- `- creative_scope: ${subject.creative_scope || '未声明;遵循最小完整干预'}`,
270
- `- quality_strategy: ${qualityStrategy}`,
271
- '- Skill、工具和资产名称只代表可发现入口;实际检查并加载后才进入 Expertise Pack。',
272
- ];
273
- let compiled = null;
274
- if (versionDir && objective.intent) {
275
- compiled = compileCapabilityInputs(versionDir, objective.intent.id);
276
- if (!compiled.available) {
277
- lines.push(`- Capability Graph: ${compiled.warnings.join(' ')}`);
278
- } else if (compiled.nodes.length === 0) {
279
- lines.push('- Capability Graph: 当前 Intent 没有回链节点;不得凭任务标题猜测能力,回流 Architect 补图谱或明确兼容原因。');
280
- } else {
281
- lines.push('- Capability Graph: 以下节点是本 Intent 的能力与风险输入:');
282
- for (const node of compiled.nodes) {
283
- lines.push(` - ${node.id} [${node.kind}/${node.impact}] ${node.title}${node.question ? ` — ${node.question}` : ''}`);
284
- }
285
- if (compiled.lenses?.length) {
286
- lines.push('- Lens Contract: 以下透镜是本 Intent 不可忽略的结果维度;它们不是额外任务,也不能被“功能能跑”替代。');
287
- for (const lens of compiled.lenses) {
288
- lines.push(` - ${lens.id} / ${lens.title}: ${lens.question}(节点: ${lens.node_refs.join(', ')})`);
289
- }
290
- }
291
- if (compiled.capability_domains?.length) {
292
- lines.push('- Capability Domains: 以下是会改变本 Intent 方案或验证方法的专业领域;它们不是贴在结果上的专家标签。');
293
- for (const domain of compiled.capability_domains) {
294
- lines.push(` - ${domain.id} / ${domain.title}: ${domain.question} 为什么现在需要:${domain.why_now}(能力: ${domain.node_refs.join(', ')})`);
295
- }
296
- }
297
- for (const brief of compiled.briefs) {
298
- lines.push(`\n### Capability Brief: ${brief.node_id}\n\n${brief.content.trim()}`);
299
- }
300
- for (const warning of compiled.warnings) lines.push(`- Capability Graph warning: ${warning}`);
301
- }
302
- }
303
- if (compiled?.acquisition?.nodes?.length) {
304
- lines.push('- External acquisition modes:');
305
- for (const node of compiled.acquisition.nodes) {
306
- lines.push(` - ${node.node_id}: ${node.mode}(${node.reason})`);
307
- }
308
- }
309
- if (versionDir && objective.intent && ['forge', 'keeper'].includes(role)) {
310
- const state = getExpertisePackState(versionDir, subject.id);
311
- if (state.required && !state.ready) {
312
- lines.push(
313
- '\n### External Acquisition Gate — OPEN',
314
- `- required_capabilities: ${state.required_node_ids.join(', ')}`,
315
- '- 先根据 Capability question、Authorial Stance/creative_scope、媒介约束与已观察缺口派生搜索词;搜索词属于本轮计划,不得写死进 Capability Graph。',
316
- '- 必须实际使用外部 find skill、网络搜索、官方文档或研究资料获取信息。模型自行生成的常识、内部复述和未打开的搜索结果不能充当来源。',
317
- `- ${state.reason === 'missing' ? `运行 \`loom expertise init ${subject.id}\`` : `修正 \`10_EXPERTISE_PACKS/${subject.id}.json\``},记录可回查来源与 Capability Capsules,再运行 \`loom expertise validate ${subject.id}\`。`,
318
- '- 门未闭合时,只能完成机械性勘察、基线冻结与检索;不得声称专业方案已形成,也不得通过验证。',
319
- );
320
- } else if (state.required && role === 'forge') {
321
- const pack = getExpertisePack(versionDir, subject.id);
322
- lines.push(
323
- '\n### External Acquisition Gate — READY',
324
- '- 以下内容是本 Intent revision 的来源化核心信息组。它不是永久 Doctrine,也不是复制进仓库的第三方 Skill。',
325
- `\n${formatExpertisePackForPrompt(pack)}`,
326
- );
327
- } else if (state.required && role === 'keeper') {
328
- lines.push(
329
- '\n### External Acquisition Evidence — PRESENT',
330
- `- record_ref: 10_EXPERTISE_PACKS/${subject.id}.json`,
331
- `- required_capabilities: ${state.required_node_ids.join(', ')}`,
332
- `- source_count: ${state.validation.source_count}; capsule_count: ${state.validation.capsule_count}`,
333
- '- 不继承 Forge 的 Capsule 结论。重新打开至少一个关键来源,检查来源确实支持规则与判断门,并把绑定写入本轮验证记录。',
334
- );
335
- }
336
- }
337
- if (role === 'keeper') {
338
- lines.push('- 不继承 Forge Expertise Pack;按契约独立准备验证能力。');
339
- if (qualityStrategy === 'atelier') {
340
- const record = getAtelierRecord(versionDir, subject.id);
341
- lines.push(
342
- '- 当前 Intent 使用 Atelier:以下 Record 是创作证据入口,不是通过结论。',
343
- `\n### Atelier Record\n\n\`\`\`json\n${JSON.stringify(record, null, 2)}\n\`\`\``,
344
- );
345
- }
346
- }
347
- if (role === 'forge' && qualityStrategy === 'atelier') {
348
- const authorshipPath = join(getLoomRoot(), 'dimensions', 'AUTHORSHIP.md');
349
- if (!existsSync(authorshipPath)) {
350
- throw new Error(`Atelier 方法文件不存在: ${authorshipPath}`);
351
- }
352
- lines.push(
353
- '- 当前 Intent 进入 Atelier Path:先冻结基线并形成 Authorial Stance,再生成机制不同的候选。',
354
- `- Atelier Record: \`09_ATELIER/${subject.id}.json\`;候选必须绑定 stance_revision。`,
355
- '- Author 只能修正局部创作假设;结构性发现提交 provenance-backed Capability Graph proposal,由 Architect 裁决。',
356
- `\n### Authorship Method\n\n${readFileSync(authorshipPath, 'utf-8').trim()}`,
357
- );
358
- }
359
- return lines.join('\n');
360
- }
361
-
362
- function compileWorkingFacts(versionDir, objective) {
363
- if (!versionDir) return '检查当前仓库、用户输入和可用工具。';
364
- const subject = objective.intent || objective.draft;
365
- const refs = [
366
- '- architecture: `.loom/.../02_ARCHITECTURE.md`(只读取与当前决定相关部分)',
367
- '- capability_graph: 从 `07_CAPABILITY_GRAPH.json` 查询与当前 Intent 回链的能力、风险与 Brief;不能用会话记忆补全未路由分支。',
368
- '- artifacts: 从真实工作区检查,不从会话记忆猜测。',
369
- ];
370
- const systemId = subject?._optional?.system_id || subject?.system_id;
371
- if (systemId) refs.push(`- system_id: ${systemId}`);
372
- if (subject?.quality_contract) refs.push('- baseline: 声明相对提升时,修改前证据必须在实现前保存。');
373
- return refs.join('\n');
374
- }
375
-
376
- function readStageFile(path, label) {
377
- if (!existsSync(path)) return `> ${label} 当前不存在;不要猜测其内容。按角色契约创建或回流。`;
378
- return readFileSync(path, 'utf-8').trim();
379
- }
380
-
381
- function listMarkdownFiles(root, current = root) {
382
- if (!existsSync(current)) return [];
383
- return readdirSync(current, { withFileTypes: true })
384
- .sort((a, b) => a.name.localeCompare(b.name))
385
- .flatMap((entry) => {
386
- const path = join(current, entry.name);
387
- if (entry.isDirectory()) return listMarkdownFiles(root, path);
388
- return entry.isFile() && entry.name.endsWith('.md')
389
- ? [relative(root, path).replaceAll('\\', '/')]
390
- : [];
391
- });
392
- }
393
-
394
- /**
395
- * Compile the stage inputs that used to be merely named by `loom guide`.
396
- * These are intentionally separate from Working Facts: they are the source
397
- * material for a role's immediate decision, not a request to hunt for paths.
398
- */
399
- function compileStageInputs(role, versionDir, objective) {
400
- if (role === 'weaver') {
401
- const dimensionsRoot = join(getLoomRoot(), 'dimensions');
402
- const catalog = listMarkdownFiles(dimensionsRoot)
403
- .filter((path) => path !== 'SEARCH_METHODOLOGY.md')
404
- .map((path) => `- dimensions/${path}`);
405
- return [
406
- '本节由 `loom activate weaver` 直接装配。不要为了取得这些输入而搜索 CLI 安装目录。',
407
- '',
408
- '### Search Methodology',
409
- '',
410
- readStageFile(join(dimensionsRoot, 'SEARCH_METHODOLOGY.md'), 'SEARCH_METHODOLOGY.md'),
411
- '',
412
- '### Available Dimension Catalog',
413
- '',
414
- catalog.length
415
- ? `${catalog.join('\n')}\n\n只打开会实质改变当前项目原则或取舍的维度;目录本身不是要求逐个阅读。`
416
- : '> 当前没有可用的 dimensions 文档。',
417
- ].join('\n');
418
- }
419
-
420
- if (role === 'architect' && versionDir && !objective.intent && !objective.draft) {
421
- let proposals = [];
422
- let proposalsError = null;
423
- try {
424
- proposals = listCapabilityProposals(versionDir, { unresolvedOnly: true });
425
- } catch (error) {
426
- proposalsError = error.message;
427
- }
428
- return [
429
- '本节由 `loom activate architect` 直接装配。以下是当前设计决策所需的版本化输入,不要先手动查找路径。',
430
- '',
431
- '### Vision Input (01_VISION.md)',
432
- '',
433
- readStageFile(join(versionDir, '01_VISION.md'), '01_VISION.md'),
434
- '',
435
- '### Capability Graph Input (07_CAPABILITY_GRAPH.json)',
436
- '',
437
- readStageFile(join(versionDir, '07_CAPABILITY_GRAPH.json'), '07_CAPABILITY_GRAPH.json'),
438
- '',
439
- '### Intent Map Input (04_INTENT_MAP.json)',
440
- '',
441
- readStageFile(join(versionDir, '04_INTENT_MAP.json'), '04_INTENT_MAP.json'),
442
- '',
443
- '### Open Capability Graph Proposals',
444
- '',
445
- proposalsError
446
- ? `> Proposal 记录无法读取:${proposalsError}。先修复这份记录,不要猜测其状态。`
447
- : proposals.length
448
- ? `\`\`\`json\n${JSON.stringify(proposals, null, 2)}\n\`\`\``
449
- : '无。',
450
- ].join('\n');
451
- }
452
-
453
- if (role === 'impact-reviewer' && versionDir && !objective.intent && !objective.draft) {
454
- return [
455
- '本节由 `loom activate impact-reviewer` 直接装配。以下是独立判断 Impact Gate 所需的最小版本化输入;不要先手动查找路径。',
456
- '',
457
- '### Vision Input (01_VISION.md)',
458
- '',
459
- readStageFile(join(versionDir, '01_VISION.md'), '01_VISION.md'),
460
- '',
461
- '### Proposed Capability Graph (07_CAPABILITY_GRAPH.json)',
462
- '',
463
- readStageFile(join(versionDir, '07_CAPABILITY_GRAPH.json'), '07_CAPABILITY_GRAPH.json'),
464
- ].join('\n');
465
- }
466
-
467
- if (role === 'visionary') {
468
- return '产品哲学与决策准则已在上方 Project Judgment 中装配;不要重新搜索 `.loom` 目录。';
469
- }
470
- if (role === 'forge' || role === 'keeper') {
471
- return '当前 Intent 的叙事、契约、图谱路由与已就绪的 Expertise 输入已在上方装配;只有产物本身需要按 Working Facts 检查。';
472
- }
473
- return '当前角色没有额外的阶段输入。';
474
- }
475
-
476
- /**
477
- * Compile a role-scoped Context Pack.
478
- * @param {string} role
479
- * @param {string | null} versionDir
480
- * @param {string | null} intentId
481
- */
482
- export function activateRole(role, versionDir, intentId = null) {
483
- if (!VALID_ROLES.includes(role)) {
484
- throw new Error(`未知角色: ${role}\n合法角色: ${VALID_ROLES.join(', ')}`);
485
- }
486
- if (intentId && !versionDir) throw new Error('--intent 需要当前 LOOM 版本');
487
- if (intentId && !['visionary', 'architect', 'forge', 'keeper'].includes(role)) {
488
- throw new Error(`角色 ${role} 不支持 --intent;draft 用 visionary/architect,官方 Intent 用 forge/keeper`);
489
- }
490
-
491
- const objective = compileObjective(role, versionDir, intentId);
492
- const parts = [
493
- '# LOOM Context Pack',
494
- section('1. Execution Envelope', compileEnvelope(role, intentId)),
495
- section('2. Active Objective', objective.body),
496
- section('3. Hard Invariants', compileInvariants(role, versionDir)),
497
- section('4. Success Contracts', compileContracts(role, versionDir, objective)),
498
- section('5. Project Judgment', compileProjectJudgment(role, versionDir, objective)),
499
- section('6. Stage Inputs (command-assembled)', compileStageInputs(role, versionDir, objective)),
500
- section('7. Expertise Inputs', compileExpertiseInputs(role, versionDir, objective)),
501
- section('8. Working Facts', compileWorkingFacts(versionDir, objective)),
502
- section('9. Role Contract / Output / Reflow / Stop', readRole(role)),
503
- ];
504
- return `${parts.join('\n\n---\n\n')}\n`;
505
- }