@haaaiawd/loom 0.7.0 → 0.8.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.
package/README.md CHANGED
@@ -57,12 +57,14 @@ Keeper 验证(四维度:意图忠实度 / 哲学一致性 / 底线合规 /
57
57
 
58
58
  ### 步骤 0:诊断当前阶段
59
59
 
60
- ```bash
61
- loom guide
62
- ```
63
-
64
- guide 检测项目当前在哪个阶段,输出"你在阶段 X,下一步做 Y"。
65
- Agent 每完成一步都跑 guide 确认下一步。
60
+ ```bash
61
+ loom guide
62
+ loom guide --dry-run # 只读诊断,不写 heartbeat
63
+ ```
64
+
65
+ guide 检测项目当前在哪个阶段,输出"你在阶段 X,下一步做 Y"。
66
+ Agent 每完成一步都跑 guide 确认下一步。
67
+ 如果只是审计或探测,不希望产生任何状态写入,用 `loom guide --dry-run`。
66
68
 
67
69
  ### AUTO 模式
68
70
 
@@ -145,24 +147,34 @@ loom intent status
145
147
 
146
148
  ### 步骤 6:人类预览
147
149
 
148
- ```bash
149
- loom preview
150
- ```
151
-
152
- 输出提示词,Agent 按提示词读 `.loom/` 文件、拆解信息、生成 HTML 可视化预览。
153
- 人类用浏览器打开 `loom-preview.html` 看全局——哲学、愿景、架构、Intent 进度、验证历史。
154
- 这是只读投影,修改请编辑源文件后重新生成。
150
+ ```bash
151
+ loom preview status # 先检查 preview 是否新鲜
152
+ loom preview # 新鲜则打开;过期则提示重新生成
153
+ loom preview --regen # 输出生成提示词,让 Agent 重写 loom-preview.html
154
+ ```
155
+
156
+ preview 是人类总览用的只读投影:哲学、愿景、架构、Intent 进度、验证历史。
157
+ `loom preview` 会用 mtime 检查 `.loom/v{N}` 是否比 `loom-preview.html` 更新:
158
+ - 新鲜:直接打开 `loom-preview.html`
159
+ - 过期:不打开旧投影,提示 `loom preview --regen`
160
+ - 强行打开旧投影:`loom preview --stale`
161
+
162
+ Agent 在用户说"看看进度 / 打开 preview / 看全局"时,先跑 `loom preview status`。
155
163
 
156
164
  **CLI 命令一览**:
157
165
 
158
166
  | 命令 | 用途 |
159
167
  |---|---|
160
- | `loom init` | 初始化项目 |
161
- | `loom guide` | 诊断当前阶段,输出下一步引导 |
162
- | `loom auto on\|off\|status` | AUTO 模式开关 |
163
- | `loom activate <role>` | 输出角色激活提示词 |
164
- | `loom preview` | 输出提示词,AI 生成 HTML 可视化预览 |
165
- | `loom help <topic>` | 分层指南(workflow\|concepts\|loop\|version\|doctor) |
168
+ | `loom init` | 初始化项目 |
169
+ | `loom guide` | 诊断当前阶段,输出下一步引导 |
170
+ | `loom guide --dry-run` | 只读诊断当前阶段,不写 heartbeat |
171
+ | `loom auto on\|off\|status` | AUTO 模式开关 |
172
+ | `loom activate <role>` | 输出角色激活提示词 |
173
+ | `loom preview` | 打开新鲜 HTML 预览;过期时提示重新生成 |
174
+ | `loom preview status` | 检查 `loom-preview.html` 是否存在、是否新鲜 |
175
+ | `loom preview --regen` | 输出提示词,让 Agent 重写 HTML 预览 |
176
+ | `loom preview --stale` | 强行打开过期预览 |
177
+ | `loom help <topic>` | 分层指南(workflow\|concepts\|loop\|version\|doctor\|preview) |
166
178
  | `loom version list` | 列出所有版本(* 标记当前) |
167
179
  | `loom version new` | 创建新版本 + 自动切换(Major 升级) |
168
180
  | `loom version use <v>` | 切换当前版本 |
package/cli/bin/loom.js CHANGED
@@ -11,7 +11,7 @@ import { findLoomRoot, findVersionDir, readCurrentPointer } from '../src/shared/
11
11
  const __dirname = dirname(fileURLToPath(import.meta.url));
12
12
 
13
13
  import { getNextIntent, getStatus, getDependencyGraph, getIntent, loadIntentMap, updateIntentStatus, getNarrative } from '../src/intent-map.js';
14
- import { getPhilosophy, listPhilosophyFiles } from '../src/philosophy.js';
14
+ import { getPhilosophy, listPhilosophyFiles, validateInspirationSources, validatePartDecomposition } from '../src/philosophy.js';
15
15
  import { writeVerification, getVerificationHistory, getPendingVerifications, listVerifications, getVerificationContract } from '../src/verify.js';
16
16
  import { initProject } from '../src/init.js';
17
17
  import { activateRole } from '../src/activate.js';
@@ -20,7 +20,7 @@ import { doctor, contextSummary, traceIntent, reverseDep, reverseRef } from '../
20
20
  import { getHelpTopic, listHelpTopics } from '../src/help.js';
21
21
  import { guideProject } from '../src/guide.js';
22
22
  import { isAutoOn, autoOn, autoOff, autoStatus } from '../src/auto.js';
23
- import { generatePreviewPrompt } from '../src/preview.js';
23
+ import { generatePreviewPrompt, getPreviewStatus } from '../src/preview.js';
24
24
 
25
25
  // ─── 路径解析 ──────────────────────────────────────────
26
26
  // findLoomRoot / findVersionDir / readCurrentPointer 已提取到 shared/paths.js
@@ -180,8 +180,38 @@ try {
180
180
  case 'list':
181
181
  output(listPhilosophyFiles(getPhilosophyDir(versionDir)));
182
182
  break;
183
+ case 'check': {
184
+ const philDir = getPhilosophyDir(versionDir);
185
+ const inspiration = validateInspirationSources(philDir);
186
+ const decomposition = validatePartDecomposition(philDir);
187
+ const allIssues = [...inspiration.issues, ...decomposition.issues];
188
+ const allPassed = inspiration.passed && decomposition.passed;
189
+
190
+ if (allPassed) {
191
+ console.log('✓ 哲学文档校验通过');
192
+ console.log(' 灵感来源:');
193
+ for (const { file, sources } of inspiration.sources) {
194
+ console.log(` ${file}: ${sources.length} 个源`);
195
+ }
196
+ console.log(' 实现部分拆解:');
197
+ for (const part of decomposition.parts) {
198
+ console.log(` - ${part}`);
199
+ }
200
+ } else {
201
+ const high = allIssues.filter((i) => i.severity === 'high').length;
202
+ const medium = allIssues.filter((i) => i.severity === 'medium').length;
203
+ console.log(`✗ 哲学文档校验未通过(${allIssues.length} 个问题: ${high} high, ${medium} medium)`);
204
+ for (const issue of allIssues) {
205
+ const icon = issue.severity === 'high' ? '⚠' : '·';
206
+ console.log(` ${icon} [${issue.severity}] ${issue.msg}`);
207
+ }
208
+ console.log('\n参见 meta/PHILOSOPHY_WEAVER.md + dimensions/PART_DECOMPOSITION.md + dimensions/SEARCH_METHODOLOGY.md。');
209
+ exit(1);
210
+ }
211
+ break;
212
+ }
183
213
  default:
184
- die(`未知子命令: philosophy ${sub}\n用法: loom philosophy [get <anchor>|list]`);
214
+ die(`未知子命令: philosophy ${sub}\n用法: loom philosophy [get <anchor>|list|check]`);
185
215
  }
186
216
  break;
187
217
  }
@@ -338,12 +368,16 @@ try {
338
368
  break;
339
369
  }
340
370
 
341
- case 'guide': {
342
- const result = guideProject(cwd());
343
- console.log(`阶段 ${result.stage_num}: ${result.stage}`);
344
- if (result.auto) {
345
- console.log(`模式: AUTO(自动执行,不等确认)`);
346
- } else {
371
+ case 'guide': {
372
+ const dryRun = argv.includes('--dry-run');
373
+ const result = guideProject(cwd(), { dryRun });
374
+ console.log(`阶段 ${result.stage_num}: ${result.stage}`);
375
+ if (dryRun) {
376
+ console.log('诊断: dry-run(不写 heartbeat)');
377
+ }
378
+ if (result.auto) {
379
+ console.log(`模式: AUTO(自动执行,不等确认)`);
380
+ } else {
347
381
  console.log(`模式: 手动(每步需用户确认)`);
348
382
  }
349
383
  console.log(`\n${result.message}`);
@@ -395,15 +429,39 @@ try {
395
429
  break;
396
430
  }
397
431
 
398
- case 'preview': {
399
- const previewFile = join(cwd(), 'loom-preview.html');
400
- const hasPreview = existsSync(previewFile);
401
- const regenOnly = argv.includes('--regen') || argv.includes('-r');
402
-
403
- // 已有 HTML 且没指定 --regen:直接打开浏览器
404
- if (hasPreview && !regenOnly) {
405
- const { spawn } = await import('node:child_process');
406
- const target = previewFile.replace(/\\/g, '/');
432
+ case 'preview': {
433
+ const previewFile = join(cwd(), 'loom-preview.html');
434
+ if (argv.includes('--help') || argv.includes('-h')) {
435
+ console.log(`用法:
436
+ loom preview 打开新鲜 preview;过期时提示重新生成
437
+ loom preview --regen 输出生成提示词,让 Agent 重写 loom-preview.html
438
+ loom preview status 检查 preview 是否存在、是否新鲜
439
+ loom preview --stale 强行打开过期 preview
440
+ loom preview --help 显示本帮助`);
441
+ break;
442
+ }
443
+ const status = getPreviewStatus(cwd());
444
+ const hasPreview = status.exists;
445
+ const regenOnly = argv.includes('--regen') || argv.includes('-r');
446
+ const openStale = argv.includes('--stale');
447
+
448
+ if (sub === 'status') {
449
+ output(status);
450
+ break;
451
+ }
452
+
453
+ // 已有 HTML 且没指定 --regen:直接打开浏览器
454
+ if (hasPreview && !regenOnly) {
455
+ if (!status.fresh && !openStale) {
456
+ console.log('preview 已过期:.loom 源文件比 loom-preview.html 更新。');
457
+ console.log(` preview: ${status.preview_mtime || '未知'}`);
458
+ console.log(` 最新源: ${status.source_latest_mtime || '未知'} ${status.latest_source_file ? `(${status.latest_source_file})` : ''}`);
459
+ console.log('\n下一步: loom preview --regen');
460
+ console.log('强行打开旧 preview: loom preview --stale');
461
+ break;
462
+ }
463
+ const { spawn } = await import('node:child_process');
464
+ const target = previewFile.replace(/\\/g, '/');
407
465
  if (process.platform === 'win32') {
408
466
  spawn('cmd', ['/c', 'start', target], { detached: true, stdio: 'ignore' }).unref();
409
467
  } else if (process.platform === 'darwin') {
@@ -412,9 +470,9 @@ try {
412
470
  spawn('xdg-open', [target], { detached: true, stdio: 'ignore' }).unref();
413
471
  }
414
472
  console.log(`已打开浏览器: ${previewFile}`);
415
- console.log(`重新生成: loom preview --regen`);
416
- break;
417
- }
473
+ console.log(status.fresh ? `重新生成: loom preview --regen` : `已打开旧 preview。重新生成: loom preview --regen`);
474
+ break;
475
+ }
418
476
 
419
477
  // 没有 HTML 或指定 --regen:输出提示词让 AI 生成
420
478
  const prompt = generatePreviewPrompt();
@@ -450,9 +508,10 @@ To Human:
450
508
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
451
509
 
452
510
  用法:
453
- loom init 初始化项目(创建 .loom/v1/ 骨架 + 模板)
454
- loom guide 诊断当前阶段,输出下一步引导
455
- loom auto on|off|status AUTO 模式开关(on 时 Agent 自动连续执行)
511
+ loom init 初始化项目(创建 .loom/v1/ 骨架 + 模板)
512
+ loom guide 诊断当前阶段,输出下一步引导
513
+ loom guide --dry-run 只读诊断当前阶段,不写 heartbeat
514
+ loom auto on|off|status AUTO 模式开关(on 时 Agent 自动连续执行)
456
515
  loom activate <role> 输出角色激活提示词(weaver|visionary|architect|forge|keeper)
457
516
 
458
517
  loom version list 列出所有版本(* 标记当前)
@@ -474,12 +533,15 @@ To Human:
474
533
 
475
534
  loom doctor 项目健康检查(一致性+孤儿引用+循环依赖+僵尸)
476
535
  loom context 上下文摘要(进度+下一步+待验证+风险)
477
- loom preview 已有 HTML 则打开浏览器,否则输出提示词让 AI 生成
478
- loom preview --regen 强制重新输出提示词(让 AI 重新生成 HTML)
479
- loom help <topic> 分层指南(workflow|concepts|loop|version|doctor
536
+ loom preview 打开新鲜 HTML;过期则提示重新生成
537
+ loom preview status 检查 preview 是否存在、是否新鲜
538
+ loom preview --regen 强制重新输出提示词(让 AI 重新生成 HTML
539
+ loom preview --stale 强行打开过期 preview
540
+ loom help <topic> 分层指南(workflow|concepts|loop|version|doctor|preview)
480
541
 
481
542
  loom philosophy get <anchor> 按锚点加载哲学章节
482
543
  loom philosophy list 列出哲学文档文件
544
+ loom philosophy check 校验灵感来源质量(源数量/多样性/理由)
483
545
 
484
546
  loom verify contract <id> 返回某 Intent 的验收契约(解析引用)
485
547
  loom verify history <id> 返回某 Intent 验证历史
@@ -6,7 +6,7 @@
6
6
  loom doctor
7
7
  \`\`\`
8
8
 
9
- 检测 6 类问题:
9
+ 检测 7 类问题:
10
10
 
11
11
  | 问题类型 | 严重度 | 说明 |
12
12
  |---|---|---|
@@ -15,9 +15,41 @@ loom doctor
15
15
  | orphan_dependency | high | depends_on 引用不存在的 Intent |
16
16
  | completed_no_record | high | completed 但无验证记录 |
17
17
  | completed_depends_blocked | high | completed 依赖 blocked 的 Intent |
18
+ | inspiration_source | high/medium | 灵感来源质量不达标(源太少/全是 Wikipedia/缺理由) |
19
+ | part_decomposition | high/medium | 缺少实现部分拆解清单(Weaver 跳过了拆解步骤) |
18
20
  | in_progress_no_record | medium | in_progress 但无验证记录(可能中断) |
19
21
  | zombie | medium | in_progress/blocked 超过 7 天无活动 |
20
22
 
23
+ ## 灵感来源校验
24
+
25
+ \`\`\`bash
26
+ loom philosophy check
27
+ \`\`\`
28
+
29
+ 单独校验哲学文档的灵感来源质量。防止 Weaver 从训练数据"背"几个名字就交差。
30
+
31
+ 校验规则:
32
+ - 至少 3 个独立源
33
+ - 至少 2 个非 Wikipedia 链接
34
+ - 每个源必须有选取理由(萃取/转译/启发关系)
35
+ - Wikipedia 占比不超过 70%
36
+
37
+ 不达标时,需要重新织造哲学——真正走搜索漏斗,找原著、论文、工程博客等深度源。
38
+
39
+ ## 实现部分拆解校验
40
+
41
+ \`\`\`bash
42
+ loom philosophy check
43
+ \`\`\`
44
+
45
+ 同时校验哲学文档是否包含"实现部分清单"——Weaver 是否按 PART_DECOMPOSITION.md 拆解了项目的实现部分。
46
+
47
+ 校验规则:
48
+ - 哲学文档中必须有"实现部分清单"章节(或"部分拆解""Part Decomposition"等)
49
+ - 至少识别到 2 个实现部分(小项目建议 3-5 个,大项目 6-10 个)
50
+
51
+ 缺少时,说明 Weaver 跳过了拆解步骤,需要重新织造——按 PART_DECOMPOSITION.md 的方法论识别项目的实现部分。
52
+
21
53
  ## 上下文摘要
22
54
 
23
55
  \`\`\`bash
@@ -25,9 +57,28 @@ loom context
25
57
  \`\`\`
26
58
 
27
59
  一条命令获取:进度 + 下一个 Intent + 待验证 + 不一致项 + 风险。
28
- Agent 重启后先跑这个,快速知道"我在哪、接下来做什么"。
29
-
30
- ## 崩溃恢复
60
+ Agent 重启后先跑这个,快速知道"我在哪、接下来做什么"。
61
+
62
+ ## 只读阶段诊断
63
+
64
+ \`\`\`bash
65
+ loom guide --dry-run
66
+ \`\`\`
67
+
68
+ 用于审计、子代理预演、只读探测。它输出和 `loom guide` 同样的阶段判断,但不写 `.loom/heartbeat.json`。
69
+
70
+ ## Preview 新鲜度诊断
71
+
72
+ \`\`\`bash
73
+ loom preview status
74
+ \`\`\`
75
+
76
+ 检查 `loom-preview.html` 是否比当前 `.loom/v{N}` 源文件更新。人类要求看 preview 时,Agent 先跑这个命令:
77
+ - `fresh=true`:可以 `loom preview`
78
+ - `fresh=false`:不要打开旧投影,先 `loom preview --regen`
79
+ - 必须看旧投影:`loom preview --stale`
80
+
81
+ ## 崩溃恢复
31
82
 
32
83
  ### Forge 崩溃(Intent 留在 in_progress)
33
84
 
@@ -67,4 +118,4 @@ LOOM 假设项目使用 Git。所有 .loom/ 下的文件都应纳入版本控制
67
118
  - 误操作 → 从 Git 回滚
68
119
  - 变更追溯 → Git log 就是审计日志
69
120
 
70
- LOOM 不内置备份、审计、回滚——这些是版本控制的职责。
121
+ LOOM 不内置备份、审计、回滚——这些是版本控制的职责。
@@ -0,0 +1,59 @@
1
+ ## Preview 指南
2
+
3
+ preview 是给人看的只读投影。它把 `.loom/v{N}` 的哲学、愿景、架构、Intent Map 和验证记录压缩成 `loom-preview.html`。
4
+
5
+ ## 常用命令
6
+
7
+ ```bash
8
+ loom preview status # 只读检查 preview 是否存在、是否新鲜
9
+ loom preview # 新鲜则打开;过期则提示重新生成
10
+ loom preview --regen # 输出生成提示词,让 Agent 重写 loom-preview.html
11
+ loom preview --stale # 强行打开过期 preview
12
+ loom preview --help # 查看 preview 命令用法
13
+ ```
14
+
15
+ ## Agent 使用规则
16
+
17
+ 当用户说“看看进度”“打开 preview”“让我看全局”时:
18
+
19
+ 1. 先运行 `loom preview status`
20
+ 2. 如果 `fresh=true`,运行 `loom preview`
21
+ 3. 如果 `fresh=false`,不要打开旧页面,运行 `loom preview --regen`
22
+ 4. 按提示词读取 `.loom/`,重写 `loom-preview.html`
23
+ 5. 再运行 `loom preview` 打开
24
+
25
+ 只有用户明确说要看旧版时,才使用 `loom preview --stale`。
26
+
27
+ ## 新鲜度判断
28
+
29
+ LOOM 使用最小 mtime 机制,不做 hash:
30
+
31
+ ```text
32
+ preview_mtime = loom-preview.html 修改时间
33
+ source_latest_mtime = 当前 .loom/v{N} 核心源文件最新修改时间
34
+
35
+ preview_mtime >= source_latest_mtime → fresh
36
+ 否则 → stale
37
+ ```
38
+
39
+ 核心源文件包括:
40
+ - `00_PHILOSOPHY/`
41
+ - `01_VISION.md`
42
+ - `02_ARCHITECTURE.md`
43
+ - `03_DECISIONS/`
44
+ - `04_INTENT_MAP.json`
45
+ - `05_VERIFICATION.md`
46
+ - `06_CHANGELOG.md`
47
+ - `verifications/`
48
+
49
+ ## 为什么不直接打开旧 preview
50
+
51
+ 旧 preview 是假仪表盘风险:`.loom/` 已经进入 blocked、deviated 或完成新 Intent,但 HTML 仍显示旧状态。
52
+
53
+ 所以普通 `loom preview` 在 stale 时会停止并提示 `loom preview --regen`。
54
+
55
+ ## 生成责任
56
+
57
+ 当前 CLI 不直接生成 HTML。`loom preview --regen` 输出提示词,要求 Agent 读取 `.loom/` 后生成 `loom-preview.html`。
58
+
59
+ CLI 负责判断是否过期和打开文件,Agent 负责把信息做成高质量视觉投影。
@@ -8,8 +8,9 @@
8
8
  loom guide
9
9
  \`\`\`
10
10
 
11
- guide 检测项目当前在哪个阶段,输出"你在阶段 X,下一步做 Y"。
12
- Agent 每完成一步都跑 guide 确认下一步。
11
+ guide 检测项目当前在哪个阶段,输出"你在阶段 X,下一步做 Y"。
12
+ Agent 每完成一步都跑 guide 确认下一步。
13
+ 审计、预演、子代理探测时用 `loom guide --dry-run`,避免写 `.loom/heartbeat.json`。
13
14
 
14
15
  ## AUTO 模式
15
16
 
@@ -71,15 +72,20 @@ loom context # 当前状态摘要
71
72
  每个 Intent 独立走一圈:选 → 实现 → 验证 → 闭合或修正。
72
73
  详细流程见 \`loom help loop\`。
73
74
 
74
- ## 阶段 5:人类预览
75
-
76
- \`\`\`bash
77
- loom preview
78
- \`\`\`
79
-
80
- 输出提示词,Agent 按提示词读 .loom/ 文件、拆解信息、生成 HTML 可视化预览。
81
- 人类用浏览器打开 HTML 看全局——哲学、愿景、架构、Intent 进度、验证历史。
82
- 这是只读投影,修改请编辑源文件后重新生成。
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`。
83
89
 
84
90
  ## 阶段 6:版本演进(按需)
85
91
 
@@ -91,4 +97,4 @@ loom preview
91
97
  - **哲学是经线,意图是纬线** — 所有角色共享哲学锚点
92
98
  - **底线不可协商** — BASELINE 5 条 + 项目特定底线,角色激活时强制加载
93
99
  - **意图可回溯** — 每个 Intent 携带叙事,Keeper 独立验证忠实度
94
- - **文档开销不超过开发开销** — 小项目可以粗粒度,不必教条
100
+ - **文档开销不超过开发开销** — 小项目可以粗粒度,不必教条