@haaaiawd/loom 0.10.0 → 1.1.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 (58) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/LICENSE +21 -0
  3. package/README.md +147 -74
  4. package/cli/bin/loom.js +428 -105
  5. package/cli/help/asset.md +36 -0
  6. package/cli/help/atelier.md +37 -0
  7. package/cli/help/capability.md +68 -0
  8. package/cli/help/concepts.md +100 -72
  9. package/cli/help/doctor.md +71 -121
  10. package/cli/help/loop.md +120 -135
  11. package/cli/help/patch.md +33 -0
  12. package/cli/help/preview.md +2 -1
  13. package/cli/help/proposals.md +21 -0
  14. package/cli/help/version.md +92 -16
  15. package/cli/help/workflow.md +101 -100
  16. package/cli/src/activate.js +349 -73
  17. package/cli/src/asset-library.js +384 -0
  18. package/cli/src/atelier.js +331 -0
  19. package/cli/src/capability-graph.js +351 -0
  20. package/cli/src/capability-proposals.js +225 -0
  21. package/cli/src/diagnostics.js +240 -44
  22. package/cli/src/guide.js +155 -40
  23. package/cli/src/init.js +58 -32
  24. package/cli/src/intent-draft.js +303 -0
  25. package/cli/src/intent-map.js +560 -54
  26. package/cli/src/patch.js +214 -0
  27. package/cli/src/philosophy.js +177 -154
  28. package/cli/src/preview-prompt.md +13 -6
  29. package/cli/src/preview.js +1 -0
  30. package/cli/src/shared/intent-ref.js +38 -0
  31. package/cli/src/shared/proof-reference.js +19 -0
  32. package/cli/src/shared/verification-method.js +32 -0
  33. package/cli/src/verify.js +202 -62
  34. package/cli/src/version.js +5 -4
  35. package/dimensions/AUTHORSHIP.md +45 -0
  36. package/dimensions/PART_DECOMPOSITION.md +42 -203
  37. package/dimensions/SEARCH_METHODOLOGY.md +101 -97
  38. package/dimensions/examples/AGENT_SYSTEM/README.md +1 -1
  39. package/dimensions/examples/CLI_TOOL/README.md +1 -1
  40. package/dimensions/universal/COLLABORATION_PHILOSOPHY.md +28 -77
  41. package/dimensions/universal/ENGINEERING_CREED.md +30 -74
  42. package/dimensions/universal/PRODUCT_PHILOSOPHY.md +32 -70
  43. package/meta/BASELINE.md +91 -276
  44. package/meta/INTENT_LOOP.md +289 -737
  45. package/meta/PHILOSOPHY_WEAVER.md +110 -343
  46. package/meta/ROLE_ACTIVATION.md +109 -267
  47. package/package.json +13 -7
  48. package/roles/architect.md +84 -111
  49. package/roles/forge.md +105 -126
  50. package/roles/keeper.md +109 -223
  51. package/roles/visionary.md +57 -86
  52. package/templates/ASSET_LIBRARY_MANIFEST_TEMPLATE.json +10 -0
  53. package/templates/ATELIER_RECORD_TEMPLATE.json +48 -0
  54. package/templates/CAPABILITY_BRIEF_TEMPLATE.md +34 -0
  55. package/templates/CAPABILITY_GRAPH_TEMPLATE.json +11 -0
  56. package/templates/INTENT_MAP_TEMPLATE.json +26 -10
  57. package/templates/PHILOSOPHY_TEMPLATE.md +44 -75
  58. package/templates/VISION_TEMPLATE.md +44 -67
@@ -1,100 +1,101 @@
1
- ## LOOM 工作流
2
-
3
- 从零到交付的完整流程。每个阶段有明确的产出和验收标准。
4
-
5
- ## 第一步:诊断当前阶段
6
-
7
- \`\`\`bash
8
- loom guide
9
- \`\`\`
10
-
11
- guide 检测项目当前在哪个阶段,输出"你在阶段 X,下一步做 Y"。
12
- Agent 每完成一步都跑 guide 确认下一步。
13
- 审计、预演、子代理探测时用 `loom guide --dry-run`,避免写 `.loom/heartbeat.json`。
14
-
15
- ## AUTO 模式
16
-
17
- \`\`\`bash
18
- loom auto on # 开启:Agent 自动连续执行,不等确认
19
- loom auto off # 关闭:每步需要用户确认
20
- \`\`\`
21
-
22
- AUTO on Agent 一路跑到底,跑完生成 preview 给人看。
23
- AUTO off 时每步停下等用户说继续。
24
-
25
- ## 阶段 1:织造哲学(Weaver)
26
-
27
- \`\`\`bash
28
- loom activate weaver
29
- \`\`\`
30
-
31
- Weaver 根据项目特征从真实思想体系织造定制化哲学。产出:
32
- - PRODUCT_PHILOSOPHY.md — 产品价值观、反模式清单、决策取舍规则
33
- - ENGINEERING_CREED.md — 工程原则(按需)
34
- - DECISION_RUBRIC.md — 冲突时的优先级(按需)
35
- - PROJECT_BASELINE.md — 项目特定底线(按需)
36
-
37
- **验收**:哲学有北极星、有反模式、有决策标准。全是空话就重做。
38
-
39
- ## 阶段 2:定义愿景(Visionary)
40
-
41
- \`\`\`bash
42
- loom activate visionary
43
- \`\`\`
44
-
45
- 基于哲学定义产品愿景,为每个 Intent 写意图叙事("为什么存在")。产出:
46
- - 01_VISION.md — 北极星 + 意图叙事列表
47
-
48
- **验收**:叙事是"为什么"不是"做什么"。写成功能列表就重做。
49
-
50
- ## 阶段 3:设计系统(Architect)
51
-
52
- \`\`\`bash
53
- loom activate architect
54
- \`\`\`
55
-
56
- 基于愿景设计系统结构,绘制 Intent Map。产出:
57
- - 02_ARCHITECTURE.md — 系统设计
58
- - 04_INTENT_MAP.json — Intent 依赖图 + 验收契约 + 哲学锚点
59
-
60
- **验收**:验收契约具体到可验证,依赖无环,每个 Intent 有叙事引用。
61
- 跑 \`loom intent validate\` 校验结构,跑 \`loom doctor\` 检查完整性。
62
-
63
- ## 阶段 4:Intent Loop
64
-
65
- \`\`\`bash
66
- loom activate keeper # Keeper 选 Intent、验证
67
- loom activate forge # Forge 实现
68
- loom intent next # 下一个可执行 Intent
69
- loom context # 当前状态摘要
70
- \`\`\`
71
-
72
- 每个 Intent 独立走一圈:选 → 实现 → 验证 → 闭合或修正。
73
- 详细流程见 \`loom help loop\`。
74
-
75
- ## 阶段 5:人类预览
76
-
77
- \`\`\`bash
78
- loom preview status
79
- loom preview
80
- loom preview --regen
81
- \`\`\`
82
-
83
- preview 是给人看的只读投影。Agent 应先跑 `loom preview status`:
84
- - `fresh=true` → 运行 `loom preview` 打开
85
- - `fresh=false`运行 `loom preview --regen`,按提示词重写 `loom-preview.html`,再打开
86
- - 用户明确要看旧版`loom preview --stale`
87
-
88
- 详细规则见 `loom help preview`。
89
-
90
- ## 阶段 6:版本演进(按需)
91
-
92
- 当哲学前提/愿景北极星/架构边界变了,需要 Major 升级。
93
- 详细流程见 \`loom help version\`。
94
-
95
- ## 核心原则
96
-
97
- - **哲学是经线,意图是纬线** 所有角色共享哲学锚点
98
- - **底线不可协商** BASELINE 5 + 项目特定底线,角色激活时强制加载
99
- - **意图可回溯** 每个 Intent 携带叙事,Keeper 独立验证忠实度
100
- - **文档开销不超过开发开销** — 小项目可以粗粒度,不必教条
1
+ ## LOOM 工作流
2
+
3
+ ## 0. 诊断
4
+
5
+ ```bash
6
+ loom guide
7
+ loom context
8
+ ```
9
+
10
+ 只读探测使用 `loom guide --dry-run`。
11
+
12
+ ## 1. Doctrine — Weaver
13
+
14
+ ```bash
15
+ loom activate weaver
16
+ loom philosophy check
17
+ ```
18
+
19
+ 输出项目长期判断、卓越标准、决策原则、创作空间、反模式与 Evidence Map。
20
+ 研究数量不设配额;只保留真实改变判断、能够追溯的证据。
21
+
22
+ ## 2. Intent Visionary
23
+
24
+ ```bash
25
+ loom activate visionary
26
+ ```
27
+
28
+ 输出产品目标、成功图景、非目标与 Intent narrative。Visionary 不写 acceptance、DAG 或架构。
29
+
30
+ ## 3. Capability Graph — Architect
31
+
32
+ ```bash
33
+ loom activate architect
34
+ loom capability graph
35
+ loom capability frontier
36
+ loom capability coverage
37
+ ```
38
+
39
+ 在写 Intent Map 前,Architect 先把愿景展开为项目问题面、能力缺口、风险与证据。图谱不是待办列表:高影响节点必须继续展开、形成项目化 Capability Brief、编译为 Intent,或带理由地延后/排除。每个 Intent 必须回链图谱;只有边界清楚且可独立验证的结果才进入 Intent Map。
40
+
41
+ ## 4. Contract — Architect
42
+
43
+ ```bash
44
+ loom activate architect
45
+ loom intent validate
46
+ loom doctor
47
+ ```
48
+
49
+ Architect 产出系统边界、Intent DAG、完成契约和可选质量契约,并声明
50
+ `capability_needs` `creative_scope`。
51
+
52
+ 完成契约定义 **Reliability Floor**:做到什么才算可靠完成。
53
+ 质量契约定义 **Distinctive Ceiling**:什么可观察差异让结果不止合格。
54
+
55
+ ## 5. Quality Engine — Forge 与 Keeper
56
+
57
+ ```bash
58
+ loom intent next
59
+ loom intent update <id> --status in_progress
60
+ loom activate forge --intent <id>
61
+ loom activate keeper --intent <id>
62
+ ```
63
+
64
+ Forge 编译 Expertise Pack,在 Quality Arena 中实现与比较。
65
+ Keeper 从当前磁盘事实和契约独立验证,不继承 Forge 的解释。
66
+
67
+ 无质量契约时,四个基础维度通过即可闭合。存在质量契约时,额外验证
68
+ `quality_achievement`;声明相对提升时,在该维度中链接 Quality Proof:
69
+
70
+ ```bash
71
+ loom verify pass <id> \
72
+ --summary "<具体证据>" \
73
+ --reproduction-command "<可复现命令>" \
74
+ --quality-proof "<基线、比较和稳定性证据的位置>"
75
+
76
+ loom intent done <id>
77
+ ```
78
+
79
+ 复杂或混合判定使用 `loom verify write --json-file <path>`。
80
+
81
+ ## 6. Reflow
82
+
83
+ 验证偏离时,不要把所有问题都扔回 Forge:
84
+
85
+ - Doctrine 不足 Weaver
86
+ - 产品目标错误Visionary
87
+ - 问题面、能力缺口或 Intent 路由遗漏 → Architect 更新 Capability Graph
88
+ - 契约、边界或依赖错误 Architect
89
+ - 专业判断或实现不足 → Forge
90
+ - 证据不足 → Keeper 补证或 `pending_human`
91
+
92
+ 连续三次 `deviated` 自动升级为 `blocked`。所有当前 revision 和当前验证 epoch 的 Intent 都有最新 passed
93
+ 记录,且没有 `needs_review`、`loom doctor` 没有 fatal/high 风险时,本轮收敛。
94
+
95
+ ## 7. 演进
96
+
97
+ - Patch:不改变 Intent 语义,验证后记录 changelog。
98
+ - Minor:用 `loom intent add|revise` 创建 draft,经限定作用域的 Visionary/Architect 更新后 finalize。
99
+ - Major:Doctrine、北极星或主要架构边界改变,使用 `loom version new`。
100
+
101
+ 原则只有一句:流程成本必须小于它降低的风险;质量声明必须小于等于它拥有的证据。
@@ -1,73 +1,349 @@
1
- // activate — 输出角色激活提示词
2
- // 把角色文件 + 哲学锚点 + 底线拼成激活上下文,供上层编排器使用。
3
-
4
- import { readFileSync, existsSync } from 'node:fs';
5
- import { join, resolve, dirname } from 'node:path';
6
- import { fileURLToPath } from 'node:url';
7
- import { getLoomRoot } from './shared/paths.js';
8
-
9
- const __dirname = dirname(fileURLToPath(import.meta.url));
10
-
11
- /** 合法角色名 */
12
- const VALID_ROLES = ['weaver', 'visionary', 'architect', 'forge', 'keeper'];
13
-
14
- /** 角色文件映射 */
15
- const ROLE_FILES = {
16
- weaver: 'meta/PHILOSOPHY_WEAVER.md',
17
- visionary: 'roles/visionary.md',
18
- architect: 'roles/architect.md',
19
- forge: 'roles/forge.md',
20
- keeper: 'roles/keeper.md',
21
- };
22
-
23
- /**
24
- * 输出角色激活提示词。
25
- * @param {string} role — 角色名
26
- * @param {string} versionDir — .loom/v{N} 目录(可选,weaver 不需要)
27
- * @returns {string} 激活提示词
28
- */
29
- export function activateRole(role, versionDir) {
30
- if (!VALID_ROLES.includes(role)) {
31
- throw new Error(`未知角色: ${role}\n合法角色: ${VALID_ROLES.join(', ')}`);
32
- }
33
-
34
- const loomRoot = getLoomRoot();
35
- const parts = [];
36
-
37
- // 1. 角色文件
38
- const roleFile = join(loomRoot, ROLE_FILES[role]);
39
- if (!existsSync(roleFile)) {
40
- throw new Error(`角色文件不存在: ${roleFile}`);
41
- }
42
- parts.push(readFileSync(roleFile, 'utf-8'));
43
-
44
- // 2. BASELINE 摘要(不重复全文——全文见 meta/BASELINE.md)
45
- // 5 条底线压缩成摘要,角色需要知道底线存在 + 一句话内容。
46
- // 如果角色需要底线细节(如 Weaver 织造哲学时),自行 readFileSync 全文。
47
- parts.push('\n---\n\n## 强制加载:BASELINE 摘要\n\n');
48
- parts.push('> 完整底线见 `meta/BASELINE.md`。以下是 5 条底线的摘要——\n');
49
- parts.push('> 角色激活时必须知道这些底线存在,违反任何一条必须立即停止。\n');
50
- parts.push('> Philosophy Weaver 织造哲学时必须读取完整 BASELINE.md 作为硬约束输入。\n\n');
51
- parts.push('| 编号 | 底线 | 一句话 |\n');
52
- parts.push('|------|------|--------|\n');
53
- parts.push('| B1 | 必须有结构设计 | 编码前必须有明确的目录结构 + 模块职责边界 + 显式依赖关系 |\n');
54
- parts.push('| B2 | 禁止硬编码 | 密钥/配置/环境特定值/魔法数字不进代码,用环境变量或集中配置 |\n');
55
- parts.push('| B3 | 接口契约必须显式 | API/CLI/配置/错误语义/跨系统协议必须有显式定义,变更可追溯 |\n');
56
- parts.push('| B4 | 决策必须可追溯 | 影响架构/接口/技术栈/依赖的决策必须记录(ADR 或等效格式) |\n');
57
- parts.push('| B5 | 意图必须可回溯 | 每个实现单元有意图叙事("为什么存在"),可被 Keeper 引用对照 |\n');
58
- parts.push('\n> 底线不可被哲学覆盖。如果织造的哲学与底线冲突,底线优先。\n');
59
-
60
- // 3. 项目特定底线(如果有 versionDir)
61
- if (versionDir) {
62
- const projectBaseline = join(versionDir, '00_PHILOSOPHY/PROJECT_BASELINE.md');
63
- if (existsSync(projectBaseline)) {
64
- parts.push('\n---\n\n## 强制加载:项目特定底线\n\n' + readFileSync(projectBaseline, 'utf-8'));
65
- }
66
-
67
- // 4. 角色激活协议
68
- const activationFile = join(loomRoot, 'meta/ROLE_ACTIVATION.md');
69
- parts.push('\n---\n\n## 角色激活协议\n\n' + readFileSync(activationFile, 'utf-8'));
70
- }
71
-
72
- return parts.join('\n');
73
- }
1
+ // activate — compile a role- and intent-scoped Context Pack.
2
+
3
+ import { readFileSync, existsSync } from 'node:fs';
4
+ import { join } 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
+
14
+ const VALID_ROLES = ['weaver', 'visionary', 'architect', 'forge', 'keeper'];
15
+
16
+ const ROLE_FILES = {
17
+ weaver: 'meta/PHILOSOPHY_WEAVER.md',
18
+ visionary: 'roles/visionary.md',
19
+ architect: 'roles/architect.md',
20
+ forge: 'roles/forge.md',
21
+ keeper: 'roles/keeper.md',
22
+ };
23
+
24
+ const ROLE_PHILOSOPHY_FILES = {
25
+ visionary: ['PRODUCT_PHILOSOPHY.md', 'DECISION_RUBRIC.md'],
26
+ architect: ['ENGINEERING_CREED.md', 'DECISION_RUBRIC.md'],
27
+ forge: ['ENGINEERING_CREED.md'],
28
+ keeper: ['PRODUCT_PHILOSOPHY.md', 'DECISION_RUBRIC.md'],
29
+ };
30
+
31
+ const BASELINE_SUMMARY = [
32
+ '- B1:实质修改前理解真实结构,不创建平行体系。',
33
+ '- B2:秘密、环境值和可变配置不写死。',
34
+ '- B3:用户或系统可观察的行为具有显式契约。',
35
+ '- B4:重要且会影响未来的判断可追溯。',
36
+ '- B5:完成关联原始意图和当前 revision 证据;质量提升具有基线相对证据。',
37
+ ].join('\n');
38
+
39
+ function section(title, body) {
40
+ const content = String(body || '').trim();
41
+ return `## ${title}\n\n${content || '无。'}`;
42
+ }
43
+
44
+ function readRole(role) {
45
+ const filePath = join(getLoomRoot(), ROLE_FILES[role]);
46
+ if (!existsSync(filePath)) throw new Error(`角色文件不存在: ${filePath}`);
47
+ return readFileSync(filePath, 'utf-8');
48
+ }
49
+
50
+ function getVerificationMethod(intent) {
51
+ return intent?.verification_method || intent?._optional?.verification_method || null;
52
+ }
53
+
54
+ function resolveContractReference(versionDir, value, label) {
55
+ if (!value) return null;
56
+ if (typeof value !== 'string') return JSON.stringify(value, null, 2);
57
+ const match = value.trim().match(/^(?:see\s+)?([^#]+)#([\w-]+)$/i);
58
+ if (!match) return value;
59
+ const [, file, anchor] = match;
60
+ if (file.includes('/') || file.includes('\\') || file !== '05_VERIFICATION.md') {
61
+ throw new Error(`${label}引用必须位于 05_VERIFICATION.md: ${value}`);
62
+ }
63
+ const filePath = join(versionDir, file);
64
+ if (!existsSync(filePath)) throw new Error(`${label}引用的文件不存在: ${filePath}`);
65
+ return extractMdSection(readFileSync(filePath, 'utf-8'), anchor, label);
66
+ }
67
+
68
+ function compileEnvelope(role, intentId) {
69
+ const scope = intentId ? `仅 ${intentId}` : '当前角色的项目阶段';
70
+ const lines = [
71
+ `- role: ${role}`,
72
+ `- scope: ${scope}`,
73
+ '- 本 Context Pack 不会清除现有会话记忆。',
74
+ '- system、developer 与用户指令优先;项目事实冲突时报告,不静默混用。',
75
+ '- 只在当前角色权限和明确作用域内行动。',
76
+ ];
77
+ if (role === 'keeper') {
78
+ lines.push('- Keeper 必须在新的 Agent thread 中运行;同一会话切换角色不构成独立验证。');
79
+ lines.push('- 无法获得独立上下文时降低声明,关键判断使用 pending_human。');
80
+ }
81
+ return lines.join('\n');
82
+ }
83
+
84
+ function compileObjective(role, versionDir, intentId) {
85
+ if (!intentId) {
86
+ return {
87
+ body: role === 'weaver'
88
+ ? '织造当前项目的 Project Doctrine。先读取真实项目与完整 BASELINE,不预写产品或架构。'
89
+ : `履行 ${role} 的当前项目阶段职责;未指定 Intent,不得自行选择并处理实现任务。`,
90
+ intent: null,
91
+ draft: null,
92
+ narrative: null,
93
+ };
94
+ }
95
+
96
+ if (role === 'visionary' || role === 'architect') {
97
+ const draft = getIntentDraft(versionDir, intentId);
98
+ const match = draft.narrative_ref.match(/^([^#]+)#([\w-]+)$/);
99
+ if (!match || match[1] !== '01_VISION.md') throw new Error(`draft narrative_ref 非法: ${draft.narrative_ref}`);
100
+ const narrative = extractMdSection(
101
+ readFileSync(join(versionDir, match[1]), 'utf-8'),
102
+ match[2],
103
+ 'draft 意图叙事',
104
+ );
105
+ const visibleDraft = role === 'visionary'
106
+ ? {
107
+ id: draft.id,
108
+ revision: draft.revision,
109
+ title: draft.title,
110
+ narrative_ref: draft.narrative_ref,
111
+ depends_on: draft.depends_on,
112
+ }
113
+ : draft;
114
+ return {
115
+ body: [
116
+ '只处理下面这个 draft。不要修改官方 Intent Map,不要处理其他 Intent,不要自行 finalize。',
117
+ '',
118
+ '### Draft',
119
+ '',
120
+ '```json',
121
+ JSON.stringify(visibleDraft, null, 2),
122
+ '```',
123
+ '',
124
+ '### Narrative',
125
+ '',
126
+ narrative,
127
+ ].join('\n'),
128
+ intent: null,
129
+ draft,
130
+ narrative,
131
+ };
132
+ }
133
+
134
+ const intent = getIntent(versionDir, intentId);
135
+ if (['forge', 'keeper'].includes(role)) {
136
+ const unfinishedDependencies = intent.depends_on.filter((dependencyId) => getIntent(versionDir, dependencyId).status !== 'completed');
137
+ if (unfinishedDependencies.length) {
138
+ throw new Error(`Intent ${intentId} 的依赖尚未闭合: ${unfinishedDependencies.join(', ')}。不得通过 activate --intent 绕过执行顺序;先运行 loom intent next 或完成依赖 Intent。`);
139
+ }
140
+ }
141
+ const narrative = getNarrative(versionDir, intentId);
142
+ const objectiveView = {
143
+ id: intent.id,
144
+ revision: intent.revision,
145
+ title: intent.title,
146
+ status: intent.status,
147
+ narrative_ref: intent.narrative_ref,
148
+ depends_on: intent.depends_on,
149
+ };
150
+ return {
151
+ body: [
152
+ '只实现或验证下面这个官方 Intent。不得加载或顺便处理其他 Intent。',
153
+ '',
154
+ '### Intent',
155
+ '',
156
+ '```json',
157
+ JSON.stringify(objectiveView, null, 2),
158
+ '```',
159
+ '',
160
+ '### Narrative',
161
+ '',
162
+ narrative,
163
+ ].join('\n'),
164
+ intent,
165
+ draft: null,
166
+ narrative,
167
+ };
168
+ }
169
+
170
+ function compileInvariants(role, versionDir) {
171
+ const blocks = [];
172
+ const baselinePath = join(getLoomRoot(), 'meta/BASELINE.md');
173
+ blocks.push(role === 'weaver' ? readFileSync(baselinePath, 'utf-8') : BASELINE_SUMMARY);
174
+ if (versionDir) {
175
+ const projectBaseline = join(versionDir, '00_PHILOSOPHY', 'PROJECT_BASELINE.md');
176
+ if (existsSync(projectBaseline)) {
177
+ blocks.push(`### Project Baseline\n\n${readFileSync(projectBaseline, 'utf-8')}`);
178
+ }
179
+ }
180
+ return blocks.join('\n\n');
181
+ }
182
+
183
+ function compileContracts(role, versionDir, objective) {
184
+ const subject = objective.intent || objective.draft;
185
+ if (!subject || role === 'visionary') {
186
+ return role === 'visionary'
187
+ ? 'Visionary 只定义目标、非目标和 narrative;不要编写 acceptance 或架构。'
188
+ : '按当前角色 Output Contract 交付。';
189
+ }
190
+
191
+ const blocks = [];
192
+ if (subject.acceptance) {
193
+ const acceptance = objective.intent
194
+ ? getVerificationContract(versionDir, subject.id)
195
+ : resolveContractReference(versionDir, subject.acceptance, 'draft 完成契约');
196
+ blocks.push(`### Acceptance / Reliability Floor\n\n${acceptance}`);
197
+ }
198
+ if (subject.quality_contract) {
199
+ blocks.push(
200
+ `### Quality Contract / Distinctive Ceiling\n\n` +
201
+ resolveContractReference(versionDir, subject.quality_contract, '质量契约'),
202
+ );
203
+ }
204
+ const verificationMethod = getVerificationMethod(subject);
205
+ blocks.push(`### Verification Method\n\n${verificationMethod || '未声明:Keeper 使用适当的静态检查;需要运行时或人类判断却缺少入口时回流 Architect。'}`);
206
+ const continuity = subject.continuity_required
207
+ ? '此 Intent 已启用状态守恒门:通过前必须证明“旧状态 → 本轮操作 → 新状态”的完整序列中,未获明确授权删除或替换的既有价值、数据和可见结果仍被保留。'
208
+ : '默认不启用状态守恒门;若本 Intent 会变更既有用户数据、持久状态、迁移结果或既有工作流,Architect 必须把 continuity_required 设为 true,并在 acceptance 写出保留项与时序验证。';
209
+ blocks.push(
210
+ '### Completion Gate / Codex Goal Alignment\n\n' +
211
+ '将当前 Intent 视为本轮 Codex goal 的可闭合单元。goal 保持 active,直到结果达成、适用的状态守恒和可复现证据同时成立;goal/status 只是运行记录,不能替代验证证据。\n\n' +
212
+ continuity,
213
+ );
214
+ return blocks.join('\n\n');
215
+ }
216
+
217
+ function compileProjectJudgment(role, versionDir, objective) {
218
+ if (!versionDir || role === 'weaver') {
219
+ return role === 'weaver'
220
+ ? '从用户目标、仓库事实与决策相关证据建立 Project Doctrine。'
221
+ : '当前版本目录不可用。';
222
+ }
223
+
224
+ const philosophyDir = join(versionDir, '00_PHILOSOPHY');
225
+ const blocks = [];
226
+ const missing = [];
227
+ const anchors = (objective.intent || objective.draft)?.philosophy_anchors || [];
228
+
229
+ if (anchors.length > 0) {
230
+ for (const anchor of anchors) {
231
+ blocks.push(`### ${anchor}\n\n${getPhilosophy(philosophyDir, anchor)}`);
232
+ }
233
+ } else {
234
+ for (const file of ROLE_PHILOSOPHY_FILES[role] || []) {
235
+ const filePath = join(philosophyDir, file);
236
+ if (!existsSync(filePath)) {
237
+ missing.push(file);
238
+ continue;
239
+ }
240
+ blocks.push(`### ${file}\n\n${readFileSync(filePath, 'utf-8')}`);
241
+ }
242
+ if (missing.length) {
243
+ blocks.push(
244
+ `### Context Warning\n\n缺少: ${missing.join(', ')}。` +
245
+ '不要用通用偏好伪造项目判断;回流 Weaver 或向用户索取必要决定。',
246
+ );
247
+ }
248
+ }
249
+ return blocks.join('\n\n');
250
+ }
251
+
252
+ function compileExpertiseInputs(role, versionDir, objective) {
253
+ const subject = objective.intent || objective.draft;
254
+ if (!subject || !['architect', 'forge', 'keeper'].includes(role)) {
255
+ return '当前阶段不编译任务级 Expertise Pack。';
256
+ }
257
+ const needs = Array.isArray(subject.capability_needs) ? subject.capability_needs : [];
258
+ const qualityStrategy = subject.quality_strategy ?? 'adaptive';
259
+ const lines = [
260
+ `- capability_needs: ${needs.length ? needs.join(', ') : '未声明;按当前任务发现必要能力'}`,
261
+ `- creative_scope: ${subject.creative_scope || '未声明;遵循最小完整干预'}`,
262
+ `- quality_strategy: ${qualityStrategy}`,
263
+ '- Skill、工具和资产名称只代表可发现入口;实际检查并加载后才进入 Expertise Pack。',
264
+ ];
265
+ if (versionDir && objective.intent) {
266
+ const compiled = compileCapabilityInputs(versionDir, objective.intent.id);
267
+ if (!compiled.available) {
268
+ lines.push(`- Capability Graph: ${compiled.warnings.join(' ')}`);
269
+ } else if (compiled.nodes.length === 0) {
270
+ lines.push('- Capability Graph: 当前 Intent 没有回链节点;不得凭任务标题猜测能力,回流 Architect 补图谱或明确兼容原因。');
271
+ } else {
272
+ lines.push('- Capability Graph: 以下节点是本 Intent 的能力与风险输入:');
273
+ for (const node of compiled.nodes) {
274
+ lines.push(` - ${node.id} [${node.kind}/${node.impact}] ${node.title}${node.question ? ` — ${node.question}` : ''}`);
275
+ }
276
+ for (const brief of compiled.briefs) {
277
+ lines.push(`\n### Capability Brief: ${brief.node_id}\n\n${brief.content.trim()}`);
278
+ }
279
+ for (const warning of compiled.warnings) lines.push(`- Capability Graph warning: ${warning}`);
280
+ }
281
+ }
282
+ if (role === 'keeper') {
283
+ lines.push('- 不继承 Forge Expertise Pack;按契约独立准备验证能力。');
284
+ if (qualityStrategy === 'atelier') {
285
+ const record = getAtelierRecord(versionDir, subject.id);
286
+ lines.push(
287
+ '- 当前 Intent 使用 Atelier:以下 Record 是创作证据入口,不是通过结论。',
288
+ `\n### Atelier Record\n\n\`\`\`json\n${JSON.stringify(record, null, 2)}\n\`\`\``,
289
+ );
290
+ }
291
+ }
292
+ if (role === 'forge' && qualityStrategy === 'atelier') {
293
+ const authorshipPath = join(getLoomRoot(), 'dimensions', 'AUTHORSHIP.md');
294
+ if (!existsSync(authorshipPath)) {
295
+ throw new Error(`Atelier 方法文件不存在: ${authorshipPath}`);
296
+ }
297
+ lines.push(
298
+ '- 当前 Intent 进入 Atelier Path:先冻结基线并形成 Authorial Stance,再生成机制不同的候选。',
299
+ `- Atelier Record: \`09_ATELIER/${subject.id}.json\`;候选必须绑定 stance_revision。`,
300
+ '- Author 只能修正局部创作假设;结构性发现提交 provenance-backed Capability Graph proposal,由 Architect 裁决。',
301
+ `\n### Authorship Method\n\n${readFileSync(authorshipPath, 'utf-8').trim()}`,
302
+ );
303
+ }
304
+ return lines.join('\n');
305
+ }
306
+
307
+ function compileWorkingFacts(versionDir, objective) {
308
+ if (!versionDir) return '检查当前仓库、用户输入和可用工具。';
309
+ const subject = objective.intent || objective.draft;
310
+ const refs = [
311
+ '- architecture: `.loom/.../02_ARCHITECTURE.md`(只读取与当前决定相关部分)',
312
+ '- capability_graph: 从 `07_CAPABILITY_GRAPH.json` 查询与当前 Intent 回链的能力、风险与 Brief;不能用会话记忆补全未路由分支。',
313
+ '- artifacts: 从真实工作区检查,不从会话记忆猜测。',
314
+ ];
315
+ const systemId = subject?._optional?.system_id || subject?.system_id;
316
+ if (systemId) refs.push(`- system_id: ${systemId}`);
317
+ if (subject?.quality_contract) refs.push('- baseline: 声明相对提升时,修改前证据必须在实现前保存。');
318
+ return refs.join('\n');
319
+ }
320
+
321
+ /**
322
+ * Compile a role-scoped Context Pack.
323
+ * @param {string} role
324
+ * @param {string | null} versionDir
325
+ * @param {string | null} intentId
326
+ */
327
+ export function activateRole(role, versionDir, intentId = null) {
328
+ if (!VALID_ROLES.includes(role)) {
329
+ throw new Error(`未知角色: ${role}\n合法角色: ${VALID_ROLES.join(', ')}`);
330
+ }
331
+ if (intentId && !versionDir) throw new Error('--intent 需要当前 LOOM 版本');
332
+ if (intentId && !['visionary', 'architect', 'forge', 'keeper'].includes(role)) {
333
+ throw new Error(`角色 ${role} 不支持 --intent;draft 用 visionary/architect,官方 Intent 用 forge/keeper`);
334
+ }
335
+
336
+ const objective = compileObjective(role, versionDir, intentId);
337
+ const parts = [
338
+ '# LOOM Context Pack',
339
+ section('1. Execution Envelope', compileEnvelope(role, intentId)),
340
+ section('2. Active Objective', objective.body),
341
+ section('3. Hard Invariants', compileInvariants(role, versionDir)),
342
+ section('4. Success Contracts', compileContracts(role, versionDir, objective)),
343
+ section('5. Project Judgment', compileProjectJudgment(role, versionDir, objective)),
344
+ section('6. Expertise Inputs', compileExpertiseInputs(role, versionDir, objective)),
345
+ section('7. Working Facts', compileWorkingFacts(versionDir, objective)),
346
+ section('8. Role Contract / Output / Reflow / Stop', readRole(role)),
347
+ ];
348
+ return `${parts.join('\n\n---\n\n')}\n`;
349
+ }