sillyspec 3.31.0 → 3.32.1

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 (74) hide show
  1. package/.claude/skills/sillyspec-auto/SKILL.md +1 -1
  2. package/.claude/skills/sillyspec-brainstorm/SKILL.md +2 -2
  3. package/.claude/skills/sillyspec-commit/SKILL.md +1 -1
  4. package/.claude/skills/sillyspec-flow/SKILL.md +10 -6
  5. package/.claude/skills/sillyspec-quick/SKILL.md +105 -7
  6. package/.zcodeignore +66 -0
  7. package/AGENTS.md +16 -16
  8. package/assets/command-cards/flow.md +9 -3
  9. package/assets/command-cards/run-quick.md +4 -1
  10. package/package.json +2 -2
  11. package/src/agent-session-log.js +27 -5
  12. package/src/config-schema.js +21 -0
  13. package/src/datetime.js +51 -0
  14. package/src/db.js +10 -3
  15. package/src/decision-distill.js +21 -12
  16. package/src/design-facts.js +46 -6
  17. package/src/flow-draft.js +468 -95
  18. package/src/flow-parity.js +199 -5
  19. package/src/flow-review.js +136 -6
  20. package/src/flow.js +786 -145
  21. package/src/foreign-declared.js +75 -3
  22. package/src/fr-index.js +148 -162
  23. package/src/git-helper.js +16 -3
  24. package/src/hooks/worktree-guard.js +16 -5
  25. package/src/hunk-attribution.js +28 -5
  26. package/src/index.js +186 -19
  27. package/src/knowledge-classify.js +3 -1
  28. package/src/knowledge-digest.js +55 -26
  29. package/src/knowledge-match.js +135 -7
  30. package/src/knowledge-stats.js +105 -4
  31. package/src/knowledge-vector.js +160 -0
  32. package/src/machine-interface.js +90 -2
  33. package/src/module-impact.js +22 -1
  34. package/src/modules.js +9 -0
  35. package/src/progress/change-registry.js +20 -0
  36. package/src/progress/stage-machine.js +4 -7
  37. package/src/progress.js +8 -1
  38. package/src/quicklog.js +20 -0
  39. package/src/redomain.js +23 -7
  40. package/src/route-hindsight.js +276 -0
  41. package/src/run/archive-distill.js +3 -1
  42. package/src/run/command.js +65 -12
  43. package/src/run/complete-handlers.js +219 -5
  44. package/src/run/complete.js +99 -22
  45. package/src/run/gate-snapshot.js +15 -0
  46. package/src/run/gates.js +60 -4
  47. package/src/run/prompt.js +159 -31
  48. package/src/run/quick-audit.js +66 -7
  49. package/src/run/shared.js +6 -11
  50. package/src/run/stage.js +5 -1
  51. package/src/run/verify-quality-scan.js +84 -0
  52. package/src/scan-facts.js +2 -1
  53. package/src/scope-audit.js +138 -5
  54. package/src/sentinel-assertions.js +67 -16
  55. package/src/stage-contract-engine.js +4 -1
  56. package/src/stage-contract-spec.js +103 -4
  57. package/src/stage-contract.js +55 -7
  58. package/src/stages/brainstorm.js +27 -14
  59. package/src/stages/knowledge.js +4 -3
  60. package/src/stages/plan-postcheck.js +98 -3
  61. package/src/stages/plan.js +22 -2
  62. package/src/stages/quick.js +1 -1
  63. package/src/stages/verify.js +2 -1
  64. package/src/task-review.js +1 -1
  65. package/src/task-tick.js +121 -0
  66. package/src/taskcard-frontmatter.js +31 -0
  67. package/src/ui-visual.js +43 -8
  68. package/src/verify-postcheck.js +518 -38
  69. package/src/verify-probes.js +216 -5
  70. package/src/watcher.js +1067 -1031
  71. package/src/worktree-apply.js +9 -1
  72. package/src/worktree.js +21 -6
  73. package/templates/agents-instruction.md +15 -15
  74. package/templates/prompts/taskcard-rules.md +1 -0
@@ -51,4 +51,4 @@ sillyspec run auto --input "<用户需求>" [--mode <模式>]
51
51
  ### 边界
52
52
 
53
53
  - 中断恢复:直接重跑 `sillyspec run auto`(进度已落盘,从断点续)。
54
- - 分类为小变更(原 quick 类):CLI 会提示改走轻量变更 `sillyspec flow start --change <名> --input "..."`(quick 通道已退役,v3.31.0 起),照提示执行。
54
+ - 分类为 quick 的小变更:CLI 会提示改跑 `sillyspec run quick`,照提示执行。
@@ -67,12 +67,12 @@ sillyspec run brainstorm --done --answer "..." --output "..." # 一步完成
67
67
  ```
68
68
  ┌─ scale=large → plan(四件套齐)
69
69
  scan → brainstorm ┤
70
- └─ scale=small → flow start 收编(仅 design.md)
70
+ └─ scale=small → quick --linked-changes(仅 design.md)
71
71
  ```
72
72
 
73
73
  brainstorm 完成时按 design.md frontmatter 的 `scale` 分叉:
74
74
  - **large**(多文件/跨模块/有状态机或 schema 变更):四件套齐 + Design Grill 审查通过(tier=independent 时由独立审查子代理产出 stage review.json)→ `sillyspec run plan --change <变更名>`
75
- - **small**(≤2 文件、单模块、无跨模块依赖):仅生成 design.md → `sillyspec flow start --change <变更名>`(头脑风暴产物自动收编续跑轻量变更,不重复起草;design 以头脑风暴版为准)
75
+ - **small**(≤2 文件、单模块、无跨模块依赖):仅生成 design.md → `sillyspec run quick --linked-changes <变更名>`
76
76
 
77
77
  > 规模由 AI 在 brainstorm 最后一步评估并写入 design.md frontmatter。判错可手动改 `scale` 后再跑相应阶段。
78
78
 
@@ -48,7 +48,7 @@ CLI 已接管全部手工收集(上次 commit 时间过滤 QUICKLOG 条目、
48
48
 
49
49
  | 来源 | type | 示例 |
50
50
  |---|---|---|
51
- | 只有存量 quick 条目(旧项目遗留 QUICKLOG;quick 已退役不再产生新条目) | fix | fix: 手机号校验修复(含正则修正) |
51
+ | 只有 quick 条目 | fix | fix: 手机号校验修复(含正则修正) |
52
52
  | 只有 execute 已勾 task | feat | feat: <变更名> 完成 task ×N |
53
53
  | 只有阶段产出 | docs | docs: sillyspec scan 完成 |
54
54
  | 混合来源 | 取最主要的 type | body 里列出所有条目 |
@@ -16,11 +16,15 @@ description: 轻量变更(默认快道)——需求明确的小/中改动两
16
16
  ### ① flow start(立项 + 锁基线)
17
17
 
18
18
  ```bash
19
- sillyspec flow start --change <变更名> --input "<需求>"
19
+ sillyspec flow start --change <变更名> --input "<动机与背景>
20
+
21
+ 成功标准:
22
+ - <可验证标准>"
20
23
  ```
21
24
 
22
- `--input` 过门格式(清晰度门按此提取,缺「成功标准」条目会被拦下):
23
- 先写动机/背景;随后独立一行只写「成功标准:」;再每行一条「- <可验证标准>」。
25
+ `--input` 过门格式(清晰度门按此提取,缺「成功标准」条目会被拦下):引号内换行合法,上方命令即完整可照抄实例。
26
+
27
+ 变更标题(面板显示用):总结一句中文概括,≤50 字、建议 ~20 字——`--input` 首行写这句即成标题(缺省取首行推导),或显式 `--title "<标题>"` 指定(重入 start 可改)。
24
28
 
25
29
  示例:
26
30
 
@@ -36,7 +40,7 @@ sillyspec flow start --change <变更名> --input "<需求>"
36
40
  改代码、写测试。治理工件(proposal/requirements/design)CLI 机器起草,你只需要:
37
41
 
38
42
  - 填 design.md 四节 AGENT 槽(做法概述/接口契约/边界并发四问/风险与死路)——每节至少一行,写「不适用:<理由>」也算答,空槽 flow done 拒收
39
- - 干活时逐条勾 tasks.md 的 `task-NN`(勾选是收口哨兵的证据面)
43
+ - 干活以 tasks.md 为进度源:做一件 → 勾一格(`- [ ]` → `- [x]`)→ 继续下一条,勿攒一把勾(勾选是收口哨兵的证据面——逐 task 核提交 token/review.json);`flow status --change <名>` 为自愿查看/恢复面(②阶段给下一任务指针与进度,非协议必需——D-007)
40
44
  - 交付代码用显式 pathspec 提交(`git commit -m "..." -- 文件1 文件2`;patch 冻结面=baseline..HEAD 提交面,未提交的代码不进审计件)
41
45
 
42
46
  ### ③ flow done(收口)
@@ -45,11 +49,11 @@ sillyspec flow start --change <变更名> --input "<需求>"
45
49
  sillyspec flow done --change <变更名>
46
50
  ```
47
51
 
48
- CLI 亲自实测 `.sillyspec/local.yaml` 的 `commands.test` / `commands.lint`(实测失败中断于对应子步、断点续,修好重跑即可);按危险证据定档独立评审;patch 留档变更级归档。
52
+ CLI 亲自实测(测试面按变更动态推断——本变更测试 ∪ FR 关联回归 ∪ import 依赖,runner 自项目结构推断;lint 走 `local.yaml` 的 `commands.lint`;实测失败中断于对应子步、断点续,修好重跑即可);按危险证据定档独立评审;patch 留档变更级归档。
49
53
 
50
54
  ## 边界
51
55
 
52
- - 中断恢复:进度已落盘,`sillyspec flow status --change <名>` 随时查看,重跑续接
56
+ - 中断恢复:进度已落盘,`sillyspec flow status --change <名>` 随时查看,重跑续接(自愿查看/恢复面——②阶段给下一个未勾任务与进度)
53
57
  - 轻量→完整转道是用户决策:征得用户同意后带 `--upgrade-thick` 重启;轻量变更实测失败自动升厚
54
58
  - 流程状态、断点要求、收尾动作以 CLI 输出为准,不要自行编造或跳过
55
59
 
@@ -1,18 +1,116 @@
1
1
  ---
2
2
  name: sillyspec:quick
3
- description: 已废弃重定向 — quick 通道已退役(v3.31.0 起拒绝新会话)。小改动请走轻量变更 /sillyspec:flow。适合用户说"直接改、快速修、顺手调整、修个小 bug、更新一个文件"——一律转用 /sillyspec:flow。
3
+ description: 用于明确、低风险、范围很小的直接任务。适合用户说"直接改、快速修、顺手调整、改个文案、修个小 bug、更新一个文件、不要完整流程"。跳过 brainstorm/plan,但仍按 sillyspec quick 流程执行。
4
4
  ---
5
5
 
6
- ## quick 通道已退役(重定向到 flow 轻量变更)
6
+ ## 何时使用
7
7
 
8
- quick 通道已于 v3.31.0 直接退役:`sillyspec run quick` 对新会话一律拒绝(exit 1 并指路 flow start)。本 skill 只保留触发词重定向,**勿尝试执行任何 `run quick` 新会话命令**。
8
+ - 明确、低风险、范围小的直接修改:改文案、修小 bug、更新单个文件
9
+ - 用户说"直接改、快速修、顺手调整、不要完整流程"
10
+ - brainstorm 判定 `scale=small` 的变更:带 design.md 进 quick(`sillyspec run quick --linked-changes <变更名>`),design 当背景
11
+ - 跳过 brainstorm/plan,但仍走 quick 的 3 步流程(理解任务 → 实现 → 自检提交)
9
12
 
10
- 用户说"直接改 / 快速修 / 顺手调整 / 修个小 bug / 更新一个文件"时,**直接执行 `/sillyspec:flow`**:
13
+ ## 多变更说明(quick 特殊,务必注意)
11
14
 
12
- - 轻量变更同是小改动的心智(flow start → 直接干活 → flow done,全程 2 次协议调用),且带实测门、测试绑定与 patch 留档,治理工件 CLI 机器起草
13
- - 需求不清晰时 CLI 会在 flow start 处拦下给两选一(头脑风暴预段 / 确认输入已含决策),照提示走即可
15
+ quick 阶段的 `--change` 语义是「关联变更」**且会触发步骤重置**,**不要用 `--change` 来指定关联变更**。多活跃变更时改用:
14
16
 
15
- 升级前遗留的在途 quick 会话仍可收尾:`sillyspec run quick --change <会话ID>` 续跑 / `--done` 收口 / `--cancel` 取消(拒绝文案里有同款指引,以 CLI 输出为准)。
17
+ - `--linked-changes none`:不关联,仅记 QUICKLOG(CLI 启动时写入)
18
+ - `--linked-changes a,b`:显式关联到变更 a、b
19
+ - `--non-interactive`:CI/脚本环境,默认不关联(避免交互 prompt 崩溃)
20
+
21
+ 首次 `sillyspec run quick` 选定的关联会持久化到 `.runtime/quick-sessions/<quick-session-id>/guard.json`(每个 quick 会话独立,多会话并发不互覆盖),后续 `--done` 自动复用,**不会重复弹交互 prompt**。
22
+
23
+ ## 步骤生命周期(所有阶段通用)
24
+
25
+ > `sillyspec quick` 是 `sillyspec run quick` 的顶层别名,两者等价。
26
+
27
+ ```bash
28
+ sillyspec run quick # 输出当前步骤 prompt(首次会记录 baseline)
29
+ sillyspec run quick --done --output "摘要" # 完成当前步骤
30
+ sillyspec run quick --status # 查看阶段进度
31
+ sillyspec run quick --skip # 跳过可选步骤
32
+ sillyspec run quick --reset # 重置阶段(从头开始)
33
+ sillyspec run quick --reopen --from-step N # 重新打开已完成阶段修订(N=序号或名称)
34
+ ```
35
+
36
+ ### 已有进行中会话的恢复(sessionId)
37
+
38
+ `sillyspec run quick` / `run quick --done` / `--status` **不带 `--change` 时,是启动一个新 quick 会话**(CLI 分配新 `quick-<hash>` + 新 ql-ID,QUICKLOG 追加「进行中」条目),不是恢复正在进行的旧会话。多会话并发或中断恢复时,必须带上启动时 CLI 打印的 sessionId:
39
+
40
+ ```bash
41
+ sillyspec run quick --change quick-<hash> # 恢复查看该会话当前 step prompt
42
+ sillyspec run quick --done --change quick-<hash> --output "…" # 完成该会话步骤
43
+ ```
44
+
45
+ - 这里的 `--change quick-<hash>` 是「恢复到该 CLI 生成的 session」,与下方 `--linked-changes` 的关联业务变更语义不同:想关联真实业务变更才用 `--linked-changes`。
46
+ - 误启动的空壳会话:`sillyspec run quick --cancel --change quick-<hash>` 一键取消(QUICKLOG 条目翻「已取消」+ tasks.md 挂载行移除 + 会话目录清理 + db 行注销;已完成/已勾选的拒绝取消)。
47
+
48
+ ## 通用参数(所有阶段适用)
49
+
50
+ | 参数 | 说明 |
51
+ |---|---|
52
+ | `--spec-dir <path>` | 指定规范目录(默认 `<项目>/.sillyspec`) |
53
+ | `--input "<一句话任务描述>"` | 通用参数,**quick 启动时强烈建议带**:作为 QUICKLOG 条目标题,条目从第一分钟即语义可读。不带则落「(quick 任务)」占位标题——平台「快速修复」列表默认隐藏进行中的占位条目,语义标题要到最终 `--done` 才回填(关联变更有 proposal/design 标题时可自动提取,免传) |
54
+ | `--non-interactive` | CI/脚本下禁用交互式 prompt |
55
+ | `--interactive` | 强制交互(即便 stdin 非 TTY) |
56
+ | `--skip-approval` | 跳过阶段转换/审批检查(不能跳产物校验 gate——review.json/文档产物硬校验仍在) |
57
+
58
+ ## quick 特有参数
59
+
60
+ | 参数 | 说明 |
61
+ |---|---|
62
+ | `--linked-changes none\|a,b` | **显式关联变更(取代 `--change`,推荐)**。none=不关联,a,b=关联列表 |
63
+ | `--files a.js,b.js` | 显式声明本次允许修改的文件(边界保护 + 声明即归属:多 agent 并发仓防他者窗口文件混入 QUICKLOG 文件行,未声明窗口文件进「审计:」行追溯;**他向亦然**——其他 active 会话已声明的文件在你的 `--done` 审计中自动剔除归该会话,不再误拦、无需 `--force-baseline`)。**中途可追加**:发现要改声明外文件(如新写的测试)时,带新增文件恢复会话即并入边界(追加不替换)——`sillyspec run quick --files <新增> --change <sessionId>`;不带 `--files` 恢复则边界原样保留 |
64
+ | `--file-notes "p::注 \|\| p::注"` | quick `--done` 用:QUICKLOG「文件:」行落盘为多行带括注 bullet(省事后手改文件行)。格式 `path::括注`,`\|\|` 分隔多条;**只随 step3 --done 同命令传**(CLI 短进程,step1/step2 传无效,不带到 step3) |
65
+ | `--allow-new` | 允许新增文件(默认禁止,防意外创建) |
66
+ | `--allow-delete` | 允许删除文件(默认 fail-closed,删除是破坏性操作;确认删除带此 flag 显式解锁) |
67
+ | `--force-baseline` | 允许覆盖 baseline 受保护文件 / 压制 `.sillyspec/` 危险判定(危险,慎用) |
68
+ | `--confirm` | ⚠️ 仅打印变更概览,**不解锁 blocked**(blocked 仍 exit 1)。真正解锁用 `--force-baseline`/`--allow-new`/`--allow-delete` |
69
+
70
+ ## 审计与并发变更(`--done` 边界审计)
71
+
72
+ `--done` 收尾时对比 step1 baseline 与当前 `git status`,拦「危险文件 / 新增文件 / 覆盖 baseline」。要点:
73
+
74
+ - **并发其他会话的 `.sillyspec/changes/<非关联变更>/` 不再被本 quick 拦截**。quick 自己没有 `changes/` 目录,该路径下非关联内容视为并发会话的工作,整体放行(确定性审计无法区分「并发工作」与「本 quick 偷建变更」,后者这类意图软判定留给 sillyhub)。
75
+ - **其他 active 会话已声明的文件自动豁免(`--files` 的他向语义)**。多 agent 并发时,并行 quick 会话 `--files` 显式声明的文件(如它的 `daemon/router.py`)出现在你的窗口内(它在你启动后改的、不在你的 baseline)——`--done` 审计自动剔除归该会话边界管,不再判危险 BLOCK、无需 `--force-baseline`。放行可见:输出 🔗 软警告逐文件列归属会话;若确系你的改动,恢复会话时 `--files` 追加声明;超 7 天未收尾的僵尸会话声明自动失效(`sillyspec run quick --cancel --change <他者会话ID>` 清理)。豁免只认他者**显式声明**——未声明的他者文件照旧走各门判定(漏声明的补 `--files`,危险文件仍需 `--force-baseline`)。
76
+ - **关联变更的文件仍走审计**:reverse-sync 改自己关联变更的 `design.md` 会被拦,需 `--force-baseline` 显式确认。
77
+ - **baseline 折叠目录前缀匹配**:step1 启动时整片 `changes/` 未跟踪会被 git 折叠成 `?? .sillyspec/changes/`(带尾斜杠 token);审计时若该目录下文件被并发会话跟踪而展开成文件级路径,按尾斜杠 token 前缀放行其下所有文件,不误判。
78
+ - **同文件并发 warn(advisory,不阻断)**:step1 启动时若你的某个 `allowedFile` 已在他者脏文件列表里(他者也改了这文件),--done 时 CLI 会比对当前内容 hash 与启动时录入的 hash——不一致(你也改了它)即判「同文件并发」并 warn:整文件 pathspec 提交会夹带他者 hunk。warn 给出分离指引(`git add -p <file>` 交互选你自己的 hunk,或 `git diff <file> > mine.patch` 编辑后 `git apply --cached mine.patch` 再 commit)。这**不阻断** --done(你可能有意整文件提交),看 warn 后自行决定是否分离。
79
+ - **`--confirm` ≠ 解锁**:它只打印概览。blocked 时真正解锁的是 `--force-baseline`(压制 `.sillyspec/` 危险判定 + baseline 覆盖)/`--allow-new`(放行新增)/`--allow-delete`(放行删除,删除是破坏性操作默认 fail-closed,须显式 opt-in),三者可在 step1 或 `--done` 传,都生效。
80
+
81
+ ## 典型用法
82
+
83
+ ```bash
84
+ # 推荐启动:带一句话语义标题(QUICKLOG/平台快速修复列表进行中即可见可读)
85
+ sillyspec run quick --input "修复登录限流 INCR 计数误清" --linked-changes none --files src/auth.ts
86
+
87
+ # 单变更项目,直接开始
88
+ sillyspec run quick
89
+
90
+ # 多变更项目,显式不关联
91
+ sillyspec run quick --linked-changes none
92
+
93
+ # 多变更项目,关联到指定变更
94
+ sillyspec run quick --linked-changes 2026-07-03-add-login
95
+
96
+ # CI/脚本(非交互,避免 prompt 崩溃)
97
+ sillyspec run quick --non-interactive
98
+ sillyspec run quick --done --linked-changes none --output "修复手机号校验"
99
+
100
+ # 限定修改文件范围
101
+ sillyspec run quick --files src/phone.ts,src/phone.test.ts
102
+ ```
103
+
104
+ ## 铁律
105
+
106
+ - **必须用 exec 工具(shell)执行 CLI,不要自己编造流程**
107
+ - quick 直接在主工作区改代码(不创建 worktree),范围必须小且明确
108
+ - 完成后立即 `--done`,不跳过
109
+ - QUICKLOG 记录的**骨架由 CLI 接管**:启动时 CLI 自动分配 ql-ID 并在 `.sillyspec/quicklog/QUICKLOG-<user>.md` 写「进行中」条目(含关联变更 tasks.md),`--done` 时 CLI 自动翻「已完成」+ 勾选 task + 回填文件路径。ql-ID 分配/状态/task 你无需手写,只需用注入的 `<quicklog-id>` 在模块文档变更索引引用
110
+ - **QUICKLOG 落盘已结构化(`--done` 后按需核对,多数无需手改)**:CLI 已落盘结构化条目——标题从 `--output` 的「需求:」自动提取、正文四字段自动分行、文件行用 `--file-notes` 时为多行带括注。`--done` 后只需核对:标题弱才改(禁留 `(quick 任务)` 占位);没用 `--file-notes` 时文件行是单行、可事后补括注(参照同文件早期丰富条目);正文 `需求:`/`根因:`/`方案:`/`结果:` 四段按需充实(禁只留一段「结果:」)。一条 quick = 一条独立 ql,不追加到旧条目
111
+ - **收尾顺序(模块文档在 `--done` 前,QUICKLOG 在 `--done` 后,别记混)**:① 命中模块→改模块文档→`git add`;② `sillyspec run quick --done --change <id> --output "四字段" [--file-notes "..."]`(CLI 自动翻完成 + 勾 task + 落盘 QUICKLOG 标题/文件/正文;若 `--linked-changes` 关联的真实变更其 tasks.md 已全部勾选**且该变更未进入完整流程**(进度库阶段停在 brainstorm 及之前),CLI 会自动将其归档到 `changes/archive/`;已走到 plan/execute/verify/archive 的变更不自动归档(tasks.md 全勾不等于流程收尾),须走原流程收尾);③ 核对 QUICKLOG 标题(CLI 已从「需求:」提取并截断,写成短标题则无需改)→若改了再 `git add`
112
+ - **最后一步 `--done` 必须给全四字段**(逐项一句话):🔧 **推荐四参数形式**(CLI 自动合成结构化模板,无格式事故面):`--done --change <id> --req "一句语义化短标题" --cause "为什么改" --solution "怎么改的" --result "验证结果"`。兼容旧形式 `--output "需求:… 根因:… 方案:… 结果:…"`(手拼须懂截断规则、禁嵌套全角冒号,缺字段被拒 exit 1)。这是 QUICKLOG「结果:」归档的唯一来源。**`--req` 写一句语义化短标题**(写「改了什么」,如「登录限流修复——INCR 计数误清」)——CLI 把它提取为 QUICKLOG 条目标题,截到首个标点、超 80 字截断;写完整需求长句会被截成语义不完整的状语前半段,需求背景放 `--cause`/`--solution`。前两个 step 的 `--output` 是中间摘要,不用此模板
113
+ - **禁止**在没有运行 CLI 的情况下自行决定流程
16
114
 
17
115
  ## 用户指令
18
116
  $ARGUMENTS
package/.zcodeignore ADDED
@@ -0,0 +1,66 @@
1
+ .DS_Store
2
+ STATE.md
3
+ node_modules/
4
+ .npm-publish-token
5
+ .sillyspec/codebase/SCAN-RAW.md
6
+ .sillyspec/local.yaml
7
+ .sillyspec/.runtime/
8
+ .idea
9
+ .playwright-mcp/
10
+ .zcode/
11
+
12
+ # SQLite WAL 模式侧车文件(node:sqlite 运行时产物,勿提交)
13
+ *.db-wal
14
+ *.db-shm
15
+
16
+ # 平台模式运行时指针/接管声明/时间戳(每次运行重写,勿提交)
17
+ .sillyspec-platform.json
18
+ .sillyspec-platform-managed
19
+ .sillyspec-platform-cleaned
20
+
21
+ # eval A/B 评测运行时产物(评测库/工作副本/agent日志/基线快照),勿提交
22
+ eval/results/
23
+ .worktrees/
24
+
25
+ # 临时产物
26
+ attachments/
27
+ sa-rename-probe/
28
+
29
+ # 本地构建产物与会话残留(不入库)
30
+ /sillyspec-*.tgz
31
+ *.stackdump
32
+ /r7-test-env/demo-project/
33
+ /round5/_gsd/
34
+ .sillyspec/sillyspec.db/
35
+ .sillyspec/sillyspec.db
36
+
37
+ # ===== ↑ 以上同步自 .gitignore(「从 .gitignore 同步」只重写以上部分)=====
38
+ .git/
39
+ .hg/
40
+ .svn/
41
+ bower_components/
42
+ jspm_packages/
43
+ __pycache__/
44
+ site-packages/
45
+ venv/
46
+ coverage/
47
+ htmlcov/
48
+ lcov-report/
49
+ cmakefiles/
50
+ cmake-build-*/
51
+ bazel-*/
52
+ pods/
53
+ deriveddata/
54
+ storybook-static/
55
+ playwright-report/
56
+ test-results/
57
+ allure-results/
58
+ allure-report/
59
+ cdk.out/
60
+ *.egg-info/
61
+ *.dist-info/
62
+ eggs/
63
+ pip-wheel-metadata/
64
+ wheels/
65
+ # ----- ↑ 以上为 ZCode 默认排除规则(自定义规则请写在本行下方,不会被同步/恢复改动)-----
66
+ # 自定义规则写在下方(本行提示可删除)
package/AGENTS.md CHANGED
@@ -1,4 +1,4 @@
1
- <!-- SillySpec v3.31.0 — 由 sillyspec init 生成,可自由编辑;重跑 init 同版本不更新 -->
1
+ <!-- SillySpec v3.30.0 — 由 sillyspec init 生成,可自由编辑;重跑 init 同版本不更新 -->
2
2
  # Agent 指引
3
3
 
4
4
  ## 项目说明
@@ -7,26 +7,25 @@
7
7
  ## 选道(动手前先对号入座)
8
8
  | 需求形态 | 走法 |
9
9
  |---|---|
10
- | 需求已含决策(改什么、成功标准说得清) | **轻量变更(默认快道)**:`flow start` → 直接干活 → `flow done`,全程 2 次协议调用 |
11
- | 需求不清晰 / 需要方案探索 | 头脑风暴预段:`run brainstorm --change <名>` → 完成后 `flow start --change <名>` 收编续跑(产物自动接管,不重复起草;design 以头脑风暴版为准) |
12
- | 大改动:跨模块取舍 / 需要 Wave 计划编排 / 多阶段治理 / 设计期人机对抗 | 完整流程:`run brainstorm → plan → execute → verify → archive` 五阶段(每阶段一次渲染 + 一次 --done 收口;local.yaml 开 stage.burst 时一次下发全部步骤说明书;verify 用 `verify-probes --init --draft` 机器预填) |
13
- | 代码已先写好(倒推收尾) | 不回头补 brainstorm/plan 装样子:`flow start --change <名> --input "<已做改动的描述+成功标准>"` → `flow done`,实测门+测试绑定+patch 留档一步收口 |
10
+ | 需求已含决策(改什么、成功标准说得清) | **轻量变更(默认快道)**:`flow start` → 直接干活 → `flow done`(2 次协议调用;操作细节见 `/sillyspec:flow` skill 与 flow start 输出) |
11
+ | 需求不清晰 / 需要方案探索 | 头脑风暴预段:`run brainstorm --change <名>` → 完成后 `flow start --change <名>` 收编续跑(design 以头脑风暴版为准) |
12
+ | 大改动:跨模块取舍 / Wave 计划编排 / 多阶段治理 / 设计期人机对抗 | 完整流程五阶段:`run brainstorm → plan → execute → verify → archive`(每阶段一次渲染 + 一次 --done 收口;细节见各阶段 skill 与 CLI 输出) |
13
+ | 代码已先写好(倒推收尾) | 不回头补流程装样子:`flow start --change <YYYY-MM-DD-名> --input` 按下方过门格式写(动机=已做改动的描述,成功标准=已验证达标的行为)→ `flow done` 一步收口 |
14
14
 
15
- 选道看流程形态需求,不看技术关键词——风险面由收口评审按证据(承诺词/diff 原语/盲维作答)判定。轻量→完整转道是用户决策:须征得用户同意并带 `--upgrade-thick`(同意门留痕,无 flag 拒跑);轻量变更实测失败自动升厚。
15
+ `--input` 过门格式(轻量道首次调用即过,勿靠报错学;引号内换行合法,下例可照抄):
16
16
 
17
- ## 轻量变更(默认快道)
18
- `sillyspec flow start --change <名> --input "<需求>"` → 改代码、写测试(治理工件 CLI 机器起草,不用你写)→ `sillyspec flow done --change <名>`。
17
+ ```bash
18
+ sillyspec flow start --change <YYYY-MM-DD-名> --input "<动机与背景>
19
19
 
20
- `--input` 过门格式(清晰度门按此提取,缺「成功标准」条目会被拦下):
21
- 先写动机/背景;随后独立一行只写「成功标准:」;再每行一条「- <可验证标准>」。
20
+ 成功标准:
21
+ - <可验证标准>"
22
+ ```
22
23
 
23
- start 之后:按提示填 design.md 四节 AGENT 槽(做法/接口契约/边界并发四问/风险,每节至少一行,写「不适用:<理由>」也算答——空槽 flow done 拒收);干活时逐条勾 tasks.md 的 task-NN(勾选是收口哨兵证据面);收口前交付代码先用显式 pathspec 提交(patch 冻结面=baseline..HEAD 提交面,未提交的代码不进审计件)。
24
+ 选道看流程形态需求,不看技术关键词——风险面由收口评审按证据(承诺词/diff 原语/盲维作答)判定。轻量→完整转道是用户决策:须征得用户同意并带 `--upgrade-thick`(同意门留痕,无 flag 拒跑);轻量变更实测失败自动升厚。
24
25
 
25
- ## 常用命令速查
26
- - 看进度:`sillyspec progress show`;轻量变更恢复:重跑 `sillyspec flow start --change <名>`(输出恢复简报)或 `sillyspec flow status --change <名>`;完整流程恢复:`run <stage> --change <名>` 续跑。不直接 commit 半成品
27
- - 跨会话交接:`sillyspec handoff --change <名>`(生成交接块,新会话零背景可续)
28
- - 变更列表 / 状态:`sillyspec status`
29
- - 自检修复:`sillyspec doctor`
26
+ ## 恢复与查看
27
+ - 轻量变更恢复:重跑 `sillyspec flow start --change <名>`(输出恢复简报)或 `flow status --change <名>`;完整流程恢复:`run <stage> --change <名>` 续跑。不直接 commit 半成品
28
+ - 跨会话交接:`sillyspec handoff --change <名>`;变更列表:`sillyspec status`;自检修复:`sillyspec doctor`
30
29
  - 知识库:`sillyspec knowledge search "<关键词>"`(命中知识 CLI 会自动注入 prompt,勿自行重复检索)
31
30
 
32
31
  ## 核心规则
@@ -42,3 +41,4 @@ start 之后:按提示填 design.md 四节 AGENT 槽(做法/接口契约/边
42
41
  10. **会话启动先立身份**:`export SILLYSPEC_SESSION_ID=<唯一标识>`(如 agent 名+任务名)——多会话并行时 change 所有权判定(apply / cleanup / 归档对他会话活跃变更的接管拒绝)依赖此标识;缺省降级为 `anon@<主机名>` 机器级标识(只拦他机,同机并行不设防)。部分 harness 的 shell 状态不持久(env 随命令丢失),此时接管类命令每条显式带 flag:`sillyspec worktree apply <change> --session <唯一标识>`(`--session` 优先级高于 env)。
43
42
  11. **禁止目录级 git add / git add -A**(多会话共享仓):目录级暂存会夹带并行会话的进行中文件甚至误删已提交文件。提交一律用显式 pathspec,且 **add 与 commit 用同一份清单**:`git commit -m "..." -- 文件1 文件2`——带 pathspec 的 commit 只提交这些路径,他侧已 staged 的条目既不被带走、也原样留给对方;裸 `git commit` 提交的是整个共享暂存区,他会话 add 过的文件会被一并扫入。核对暂存面固定用 `git diff --cached --name-only` 全量读取,禁用过滤式核对(过滤正是致盲原因);核对与提交分开两条命令执行,不得链在同一命令里(链行没有拦截点)。安装了 commit-guard hook 的仓会对超声明面的 staged 文件警告(只警告不阻断)。
44
43
  12. **不奉承用户**,禁止"你说得对"类话术,直接给结论、依据、方案。
44
+ 13. **边干边勾(任务进度唯一源=变更的 tasks.md)**:完成一个任务单元(实现到位 + 相关测试跑绿)当场勾对应格——`sillyspec task tick --change <名> --task task-NN`(即时回显进度与下一任务)或直接 Edit 翻格 `- [ ]`→`- [x]`,勿攒到收口一把勾。harness 自带的 TodoWrite 类工具是会话内便利面,不替代 tasks.md——平台进度投影、收口哨兵、断点恢复只读 tasks.md。
@@ -10,9 +10,15 @@ description: 轻量变更(默认快道):需求明确的小/中改动两步
10
10
 
11
11
  ```bash
12
12
  export SILLYSPEC_SESSION_ID=<agent名+任务名> # 每条命令都带(shell 状态不持久;多会话并行的所有权判定依赖它)
13
- # ① 立项 + 锁基线(--input 缺「成功标准」条目会被清晰度门拦下):
14
- sillyspec flow start --change <变更名> --input "<动机与背景;随后独立一行『成功标准:』;再每行一条『- <可验证标准>』>"
15
- # ② 直接干活:改代码写测试;填 design.md 四节 AGENT 槽(空槽 flow done 拒收);逐条勾 tasks.md 的 task-NN
13
+ # ① 立项 + 锁基线(--input 引号内换行合法,可照抄;缺「成功标准」条目会被清晰度门拦下):
14
+ sillyspec flow start --change <变更名> --input "<动机与背景>
15
+
16
+ 成功标准:
17
+ - <可验证标准>"
18
+ # ② 直接干活:改代码写测试;填 design.md 四节(空节 flow done 拒收;列改动文件用独立「## 文件变更清单」节);
19
+ # tasks.md 是你的工作队列——机器种子改写为实现步骤(每行做什么+怎么验证,保持 `- [ ] task-NN:` 行形态),
20
+ # 执行循环:Working on task N/M → 做一件 → 测试绿后当场勾一格(sillyspec task tick --change <名> --task task-NN
21
+ # 即时回显进度与下一任务)→ 下一行;每格勾选要有对应提交(消息带 task-NN),一把勾收口被拒。
16
22
  # 交付代码显式 pathspec 提交(patch 冻结面=baseline..HEAD 提交面,未提交不进审计件)
17
23
  # ③ 收口(CLI 亲自实测 test/lint + 独立评审定档 + patch 留档):
18
24
  sillyspec flow done --change <变更名>
@@ -9,7 +9,10 @@ quick 通道已于 v3.31.0 直接退役:`sillyspec run quick` 对新会话一
9
9
  范围明确的小修补请走**轻量变更**(/sillyspec:flow):
10
10
 
11
11
  ```bash
12
- sillyspec flow start --change <变更名> --input "<动机与背景;随后独立一行『成功标准:』;再每行一条『- <可验证标准>』>"
12
+ sillyspec flow start --change <变更名> --input "<动机与背景>
13
+
14
+ 成功标准:
15
+ - <可验证标准>"
13
16
  # → 直接干活(改代码写测试,治理工件 CLI 机器起草)
14
17
  sillyspec flow done --change <变更名>
15
18
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sillyspec",
3
- "version": "3.31.0",
3
+ "version": "3.32.1",
4
4
  "description": "SillySpec CLI — 流程状态机,让 AI 严格按步骤来",
5
5
  "icon": "logo.jpg",
6
6
  "homepage": "https://sillyspec.ppdmq.top/",
@@ -24,7 +24,7 @@
24
24
  ],
25
25
  "license": "MIT",
26
26
  "scripts": {
27
- "test:core": "node --test test/preview-migration.test.mjs test/preview-progress.test.mjs test/preview-outlet.test.mjs test/preview-gc.test.mjs test/preview-gate-isolation.test.mjs test/db-engine.test.mjs test/db-concurrency.test.mjs test/db-atomic-write.test.mjs test/platform-sync-schema.test.mjs test/platform-sync-serialization.test.mjs test/change-ownership-guards.test.mjs test/watcher.test.mjs test/watcher-alerts.test.mjs test/watcher-timeline.test.mjs test/sentinel-rules.test.mjs test/handoff.test.mjs test/execution-mode-render.test.mjs test/knowledge-inbox.test.mjs test/knowledge-baseline.test.mjs test/quick-laststep-fourfields-preview.test.mjs test/doctor-align-execute-progress.test.mjs test/test-ledger.test.mjs test/test-bindings.test.mjs test/flow-draft-binding-extract.test.mjs test/gate-snapshot-lifecycle.test.mjs test/gate-snapshot-cleanup.test.mjs test/verify-trace-residual.test.mjs test/platform-creds-fallback.test.mjs test/archive-timeline-bake.test.mjs",
27
+ "test:core": "node --test test/preview-migration.test.mjs test/preview-progress.test.mjs test/preview-outlet.test.mjs test/preview-gc.test.mjs test/preview-gate-isolation.test.mjs test/db-engine.test.mjs test/db-concurrency.test.mjs test/db-atomic-write.test.mjs test/platform-sync-schema.test.mjs test/platform-sync-serialization.test.mjs test/change-ownership-guards.test.mjs test/watcher.test.mjs test/watcher-alerts.test.mjs test/watcher-timeline.test.mjs test/sentinel-rules.test.mjs test/handoff.test.mjs test/execution-mode-render.test.mjs test/knowledge-inbox.test.mjs test/knowledge-baseline.test.mjs test/quick-laststep-fourfields-preview.test.mjs test/doctor-align-execute-progress.test.mjs test/test-ledger.test.mjs test/test-bindings.test.mjs test/flow-draft-binding-extract.test.mjs test/gate-snapshot-lifecycle.test.mjs test/gate-snapshot-cleanup.test.mjs test/verify-trace-residual.test.mjs test/platform-creds-fallback.test.mjs test/archive-timeline-bake.test.mjs test/doc-ref-check.test.mjs test/flow-status-json.test.mjs test/flow-status-title.test.mjs test/flow-resume-title.test.mjs test/datetime-timeago.test.mjs test/resume-domain-flip.test.mjs test/fr-regress-cap-drop.test.mjs test/fr-priority-overlap.test.mjs test/archive-commit-suggest-race.test.mjs test/flow-done-fail-brief.test.mjs test/verify-probes-refresh-backup.test.mjs test/taskcard-yaml-triage-validate.test.mjs test/gate-last-reader.test.mjs test/status-multi-active-list.test.mjs test/gate-docs-only.test.mjs test/probe7-fr-prefill.test.mjs test/plan-fill-batch-config.test.mjs test/step-guide-prune.test.mjs test/gate-stage-review-hint.test.mjs test/design-ref-suggest.test.mjs test/flow-friction-batch3.test.mjs test/wave-auto-adopt.test.mjs test/test-incremental-rerun.test.mjs",
28
28
  "test": "node test/run-tests.mjs",
29
29
  "lint": "node test/check-syntax.mjs",
30
30
  "eval:dry": "node eval/run.mjs --dry-run",
@@ -550,7 +550,7 @@ function detectCursorAgentTranscripts(ctx) {
550
550
  return entries.slice(0, 3);
551
551
  }
552
552
 
553
- const HARNESS_DETECTORS = [
553
+ export const HARNESS_DETECTORS = [
554
554
  { name: 'claude-code', tier: 'precise', detect: detectClaudeCode },
555
555
  { name: 'codex', tier: 'precise', detect: detectCodex },
556
556
  { name: 'zcode', tier: 'precise', detect: detectZcode },
@@ -561,6 +561,28 @@ const HARNESS_DETECTORS = [
561
561
  { name: 'opencode', tier: 'loose', detect: detectOpencode },
562
562
  ];
563
563
 
564
+ /** name → 人读展示名(--detect 空态提示用)。缺省回退 name 原样:新 harness 无映射也不漏项,
565
+ * 只是展示不美化(坑 agent-log-detect-hint,2026-10-06 实证:提示硬编码 3 家与注册表 8 家
566
+ * 漂移——派生后注册表是唯一真相源,映射只是展示层)。 */
567
+ export const HARNESS_DISPLAY_NAMES = {
568
+ 'claude-code': 'Claude Code',
569
+ codex: 'Codex',
570
+ zcode: 'ZCode',
571
+ pi: 'pi',
572
+ 'deepseek-dsh': 'DeepSeek DSH',
573
+ 'cursor-agent': 'cursor-agent',
574
+ cursor: 'Cursor',
575
+ opencode: 'opencode',
576
+ };
577
+
578
+ /** --detect 空态提示行:从探测器注册表派生(注册表新增 harness 提示自动跟上,不再手工同步)。
579
+ * @param {Array<{name: string}>} [detectors] - 默认 HARNESS_DETECTORS(测试可注入)
580
+ * @returns {string} 提示行(含 SILLYSPEC_AGENT_LOG 显式指定通道指引) */
581
+ export function renderDetectEmptyHint(detectors = HARNESS_DETECTORS) {
582
+ const names = detectors.map(h => HARNESS_DISPLAY_NAMES[h.name] ?? h.name).join(' / ');
583
+ return ` 支持: ${names} 自动探测;其他 CLI 用 SILLYSPEC_AGENT_LOG=<日志绝对路径> 显式指定。`;
584
+ }
585
+
564
586
  // ── 会话身份锚定器(2026-09-11-agent-log-attribution-refactor,D-001/D-008)──
565
587
  //
566
588
  // own 集合 = 本 run 所属 agent 会话的日志文件(锚定主会话 + zcode parent_id 子代理链)。
@@ -1062,7 +1084,7 @@ export function readAgentLogArtifact(runtimeRoot) {
1062
1084
  }
1063
1085
 
1064
1086
  /**
1065
- * 登记 agent 会话日志路径进 <runtimeRoot>/agent-session-log.json(run 命令入口调用)。
1087
+ * 登记 agent 会话日志路径进 <runtimeRoot>/agent-session-log.json(run/flow 命令入口调用)。
1066
1088
  *
1067
1089
  * 合并语义:按 log_path 去重——同路径 invocations+1 / 刷新 last_seen_at 与文件 stat;
1068
1090
  * 新路径追加;entries 按 last_seen_at 新→旧排序(同毫秒平局按 seq 登记序决胜),
@@ -1299,7 +1321,7 @@ export async function cmdAgentLog(subArgs, { json = false, cwd = process.cwd(),
1299
1321
  }
1300
1322
  if (detected.length === 0) {
1301
1323
  console.log('📭 未探测到本地 agent 会话日志。');
1302
- console.log(' 支持: Claude Code / Codex / ZCode 自动探测;其他 CLI 用 SILLYSPEC_AGENT_LOG=<日志绝对路径> 显式指定。');
1324
+ console.log(renderDetectEmptyHint());
1303
1325
  return;
1304
1326
  }
1305
1327
  console.log(`🔍 现场探测到 ${detected.length} 条 agent 日志:`);
@@ -1318,7 +1340,7 @@ export async function cmdAgentLog(subArgs, { json = false, cwd = process.cwd(),
1318
1340
  }
1319
1341
  if (!artifact || !Array.isArray(artifact.entries) || artifact.entries.length === 0) {
1320
1342
  console.log(`📭 无 agent 日志登记产物(${toPosix(artifactPath)})。`);
1321
- console.log(' run <stage> 命令在 agent 环境内执行时自动登记;或用 agent-log --detect 现场探测。');
1343
+ console.log(' run <stage> / flow <子命令> 在 agent 环境内执行时自动登记;或用 agent-log --detect 现场探测。');
1322
1344
  return;
1323
1345
  }
1324
1346
  console.log(`📄 本地 agent 会话日志登记(${toPosix(artifactPath)},${artifact.entries.length} 条)`);
@@ -1332,5 +1354,5 @@ export async function cmdAgentLog(subArgs, { json = false, cwd = process.cwd(),
1332
1354
  .filter(Boolean).join(' / ');
1333
1355
  console.log(` ${meta} / 见过 ${e.invocations} 次 / 最近 ${e.last_seen_at}${e.last_command ? ` / ${e.last_command}` : ''}`);
1334
1356
  }
1335
- console.log(' 协议: docs/platform-agent-log-protocol.md(run 命令自动 REST 上报平台 POST /api/agent-logs;此产物为本地留底)');
1357
+ console.log(' 协议: docs/platform-agent-log-protocol.md(run / flow 命令自动 REST 上报平台 POST /api/agent-logs;此产物为本地留底)');
1336
1358
  }
@@ -74,6 +74,7 @@ export const LOCAL_YAML_SCHEMA = {
74
74
  { path: 'commands.lint_timeout_sec', type: 'number', optional: true, status: 'live', readers: ['runVerifyLintCheck (src/verify-postcheck.js)'], desc: 'commands.lint 超时秒数——优先级 显式调用参 > 本键 > env SILLYSPEC_LINT_TIMEOUT_MS > 缺省 180(快照内 junction I/O 慢,快照路径调用侧显式传 300)。', example: '600' },
75
75
  { path: 'commands.smoke', type: 'string', optional: true, status: 'live', readers: ['executeVerifyQualityScan (src/run/verify-quality-scan.js)'], desc: '接口冒烟命令——verify 阶段 CLI 亲跑(脚本自理服务生命周期:后台起服+轮询就绪+finally 杀),300s 超时帽,失败/超时只记失败态不阻断本步、触发 PASS 封顶(D-002);指纹含此键,未变不重跑。', example: 'node scripts/smoke.mjs' },
76
76
  { path: 'commands.install', type: 'string', optional: true, status: 'live', readers: ['extractInstallCommand (src/worktree-deps.js)'], desc: '依赖安装命令(worktree 依赖 provisioning 用)。', example: 'npm install' },
77
+ { path: 'commands.knowledge-gate', type: 'boolean', optional: true, status: 'live', readers: ['completeStep (src/run/complete.js)'], desc: '【2026-09-28-unclear-req-to-brainstorm FR-03/D-004】brainstorm 方案步(提出 2-3 种方案)--done 知识检索命中回显开关——缺省 true=开(对 --output 与 decisions.md 条目跑既有检索匹配器,命中 warn 回显「须 evidence 回应或说明不复潮」不阻断);false(或 off)关回显,无命中时输出与现状一致。', example: 'false' },
77
78
  ],
78
79
  },
79
80
  {
@@ -120,6 +121,7 @@ export const LOCAL_YAML_SCHEMA = {
120
121
  title: '测试策略',
121
122
  note: 'verify 阶段 CLI 对账的收窄策略(D-005@v2:skip 接线兑现 + evidence-auto 新增,full/module 语义不变)。',
122
123
  keys: [
124
+ { path: 'verify.test_rerun', type: 'enum', values: ['incremental', 'full'], optional: true, status: 'live', readers: ['readTestRerunConfig (src/verify-postcheck.js — dynamic-subset 分支增量档)'], desc: '实测门失败后重跑档:incremental(缺省)= 前轮失败后,下轮只跑「失败批测试文件 ∪ 自失败基线以来变更文件」的三源推断面(未触碰绿面复用,返工轮分钟级);full = 恒全子集重跑(2026-10-07 前现状,保守项目用)。env SILLYSPEC_TEST_RERUN 优先。仅作用 dynamic-subset 档(显式 test_strategy: full 不受影响)。', example: 'verify: { test_rerun: full }' },
123
125
  { path: 'test_strategy', type: 'enum', values: ['full', 'module', 'skip', 'evidence-auto'], optional: true, status: 'live', readers: ['extractTestStrategy (src/verify-postcheck.js)', 'resolveTestStrategy (src/verify-postcheck.js)'], desc: '【2026-09-26-dynamic-test-inference 起】full=全量(commands.test 在场生效,否则结构推断);module=已退役折算动态子集(超集覆盖:变更文件面收窄 + FR 关联回归 + import 依赖);skip=真跳过(R-07 不变);evidence-auto=按 module-impact.md 推荐(行为→动态子集、文档/门禁→skip)。缺省=动态子集:三源并集非空实测、空则不硬跑全量(防超时/预存失败面)。', example: 'full' },
124
126
  ],
125
127
  },
@@ -188,6 +190,15 @@ export const LOCAL_YAML_SCHEMA = {
188
190
  { path: 'stage.wall', type: 'enum', values: ['advisory', 'hard'], optional: true, status: 'live', readers: ['readStageWall (src/run/shared.js) + runStage 入口墙 (src/run/stage.js)'], desc: '阶段边界会话墙:advisory(缺省)= 阶段完成时提示可 handoff 换会话,不阻断;hard = 同一会话(SILLYSPEC_SESSION_ID 相同)刚收口前驱阶段后硬续墙后阶段(execute/verify)→ run <stage> 拒启动(exit 1),指引 sillyspec handoff 生成交接块换新会话续跑;--same-session 显式逃生口(应急/平台编排)。墙后阶段 = execute/verify(上下文最贵两段:R15 实测 execute 均轮 263K,断崖拆会话后回落 120-170K)。stage-session ledger 缺失/会话标识不可判定 → 放行(fail-open,与账本 best-effort 一致)。', example: 'hard' },
189
191
  ],
190
192
  },
193
+ {
194
+ id: 'plan',
195
+ title: '计划阶段派发',
196
+ note: 'plan 阶段 TaskCard 填充派发策略。默认主 agent 直填(2026-09-20 对撞实验:6 个填卡子代理 6.7M token 纯誊写,独立性价值为零);task 总数超阈值且跨模块才 batch 派子代理——阈值按项目体系可调(厚流程实证 11 任务 3 子代理 430 万 token 模板化产出后引入)。',
197
+ keys: [
198
+ { path: 'plan.fill_batch_min_tasks', type: 'integer', optional: true, status: 'live', readers: ['buildCoordinatorStep (src/stages/plan.js — 协调器 prompt 阈值插值)'], desc: '填卡 batch 派发阈值:task 总数 ≤N(或单仓单模块)→ 主 agent 直填不派子代理;>N 且跨模块/跨仓才按 batch 分派。≥1 整数,缺省 8(内置);非法值回退 8(fail-safe)。调大 = 更少派子代理省 token;调小 = 大变更更早并行省墙钟。', example: '12' },
199
+ { path: 'plan.auto_adopt_waves', type: 'boolean', optional: true, status: 'live', readers: ['executePlanPostcheck 自动重排门 (src/stages/plan-postcheck.js — tryAutoAdoptWaves)'], desc: 'Wave 形态错误自动重排:plan postcheck 发现「同 Wave 冲突/伪并行串行链」且无其他类错误时,自动跑 plan-adopt-waves 按 depends_on 拓扑重排并整体复跑校验(预算 1 次防环)。缺省 true;置 false 关闭(报错指路手工跑,2026-10-07 前现状)。方向违规自动修复(既有)不受本键影响。', example: 'true' },
200
+ ],
201
+ },
191
202
  {
192
203
  id: 'auto_mode',
193
204
  title: '变更规模自动分类',
@@ -362,6 +373,7 @@ commands:
362
373
  # install: npm install # worktree 依赖安装命令
363
374
  # test_timeout_sec: 2400 # commands.test 超时秒数(慢仓提帽;缺省 600,env SILLYSPEC_TEST_TIMEOUT_MS 同效)
364
375
  # lint_timeout_sec: 600 # commands.lint 超时秒数(缺省 180)
376
+ # knowledge-gate: false # 方案步 --done 知识检索命中回显开关(缺省 true 开;false 关回显)
365
377
 
366
378
  # ── SillyHub MCP 客户端凭据(派发到 worker 用)──
367
379
  # agent 手填,或 sillyspec platform connect 在 mcp 段缺失时同源自动填。
@@ -409,6 +421,8 @@ dispatch:
409
421
  # skip=真跳过测试(不回退全量,verify 输出显式标注留审计痕迹)
410
422
  # evidence-auto=按变更 module-impact.md 影响面推荐(行为→动态子集、文档→docs-check、门禁→gate)
411
423
  # test_strategy: full # 缺省注释态=动态子集(评审 P3-5 清偿:复制即全量道的自相矛盾陷阱——缺省注释才与上方「缺省=动态子集」一致);确要全量再解注释
424
+ # verify:
425
+ # test_rerun: incremental # 实测门失败后重跑档:incremental(缺省,下轮只跑失败批∪修复面)| full(恒全子集重跑,保守项目用)
412
426
 
413
427
  # ── 证据门档位(2026-09-27-ui-visual-guidance / 2026-09-27-hunk-attribution-gate;注释态=缺省档位生效)──
414
428
  # ui_visual_gate: warn # UI 视觉证据分级门:warn(缺省,缺 visual-evidence.md 仅警告)| error(缺证据即阻断)| off(探针整体关闭;视觉降级无用户裁决留痕时无论档位恒阻断)
@@ -503,6 +517,13 @@ docs-check:
503
517
  # change-ownership:
504
518
  # heartbeat_minutes: 15 # 所有者活跃心跳窗口(分钟)
505
519
 
520
+ # ── 计划阶段派发(plan:TaskCard 填充派发策略)──
521
+ # 默认主 agent 直填(对撞实验:6 个填卡子代理 6.7M token 纯誊写,独立性价值为零);
522
+ # 仅 task 总数超阈值且跨模块/跨仓才按 batch 派子代理(并行省墙钟有真实收益)。
523
+ # plan:
524
+ # fill_batch_min_tasks: 12 # 填卡 batch 派发阈值(内置 8;调大=更少派子代理省 token,调小=大变更更早并行)
525
+ # auto_adopt_waves: true # Wave 形态错误自动拓扑重排(内置 true;false=报错指路手工跑)
526
+
506
527
  # ── 评审仪式档位(ceremony tier:S0~S3 由 CLI 按 blast/span/friction 三轴风险客观定价)──
507
528
  # blast 轴输入=项目声明危险面(_module-map.yaml 顶层 blast 段);完成门声明追赶重定价(无摩擦随声明、有摩擦地板不退)。
508
529
  # 项目化定价(每个项目体系不一样,起点与阈值可配——只升不降纪律不开放配置):
package/src/datetime.js CHANGED
@@ -18,3 +18,54 @@ export function nowWallClock(d = new Date()) {
18
18
  return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} `
19
19
  + `${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
20
20
  }
21
+
22
+ /**
23
+ * 输入 → Date 的私有强转(toWallClock/timeAgo 共用):Date 实例 / epoch 毫秒数 /
24
+ * 时间字符串(解析委托 Date 构造器——开放解析面归语言规范,不建格式枚举白名单)。
25
+ * 无效输入(非三类之一,或解析产物为 NaN 时刻)抛 TypeError,message 含输入的字符串形式。
26
+ */
27
+ function coerceClock(input, fnName) {
28
+ const d = input instanceof Date ? input
29
+ : (typeof input === 'number' || typeof input === 'string') ? new Date(input)
30
+ : null;
31
+ if (!d || Number.isNaN(d.getTime())) {
32
+ throw new TypeError(`${fnName}: 无法解析的时间输入:${String(input)}`);
33
+ }
34
+ return d;
35
+ }
36
+
37
+ /**
38
+ * 任意时刻输入 → 本地墙钟串(YYYY-MM-DD HH:mm:ss):Date 实例 / epoch 毫秒数 /
39
+ * 时间字符串。无效输入抛 TypeError,message 含输入的字符串形式。
40
+ * @param {Date|number|string} input
41
+ * @returns {string}
42
+ */
43
+ export function toWallClock(input) {
44
+ return nowWallClock(coerceClock(input, 'toWallClock'));
45
+ }
46
+
47
+ /**
48
+ * 任意时刻输入 → 人读相对时间串,档位与进度面板(stage-machine._timeAgo)逐字同构:
49
+ * 差值折算分钟 floor 后 <1(含负差/未来时间)→「刚刚」;<60 →「N 分钟前」;折算小时
50
+ * 后 <24 →「N 小时前」;否则「N 天前」。人读串硬编码不依赖 locale/ICU(与 nowWallClock
51
+ * 同理:Node small-icu 构建下 toLocaleString 不可靠)。
52
+ * @param {Date|number|string} input
53
+ * @param {Date|number} [now] 可注入「当前时刻」(测试钉档位边界用),缺省当前时间;
54
+ * 仅接受 Date 实例或 epoch 毫秒,非法值抛 TypeError
55
+ * @returns {string}
56
+ */
57
+ export function timeAgo(input, now = new Date()) {
58
+ const ts = coerceClock(input, 'timeAgo').getTime();
59
+ const nowTs = now instanceof Date ? now.getTime()
60
+ : typeof now === 'number' ? now
61
+ : NaN;
62
+ if (!Number.isFinite(nowTs)) {
63
+ throw new TypeError(`timeAgo: 无法解析的当前时刻:${String(now)}`);
64
+ }
65
+ const minutes = Math.floor((nowTs - ts) / 60000);
66
+ if (minutes < 1) return '刚刚';
67
+ if (minutes < 60) return `${minutes} 分钟前`;
68
+ const hours = Math.floor(minutes / 60);
69
+ if (hours < 24) return `${hours} 小时前`;
70
+ return `${Math.floor(hours / 24)} 天前`;
71
+ }
package/src/db.js CHANGED
@@ -71,7 +71,10 @@ export class DB {
71
71
  // 4. 创建表结构(仅当 schema 版本戳不匹配时——W4-H):
72
72
  // schema 已最新则跳过建表,省 DDL 开销。node:sqlite 打开即持久化,
73
73
  // _createSchema 内 DDL 直接落盘,无需 _save。
74
- // 戳在但 db 缺表属"手动改 db"边角(SillySpec 不支持),不在本层兜底。
74
+ // 戳只对它伴生的库文件作证:库文件被删而戳残留(孤儿戳)时戳匹配是假信号——
75
+ // _openWithFallback 的全新建库分支以 _freshCreate 标记(2026-10-06-status-multi-active-list
76
+ // 实测:空库无表首个 SELECT 即 no such table 崩溃)。戳在但库有内容的缺表属
77
+ // "手动改 db"边角(SillySpec 不支持),仍不在本层兜底。
75
78
  const versionPath = `${this.dbPath}.schema-version`;
76
79
  let schemaCurrent = false;
77
80
  try {
@@ -79,7 +82,7 @@ export class DB {
79
82
  && readFileSync(versionPath, 'utf8').trim() === String(DB_SCHEMA_VERSION);
80
83
  } catch { /* 戳读取失败保守重跑 schema */ }
81
84
 
82
- if (!schemaCurrent) {
85
+ if (!schemaCurrent || this._freshCreate) {
83
86
  this._createSchema();
84
87
  try { writeFileSync(versionPath, String(DB_SCHEMA_VERSION)); } catch { /* 戳写入失败不阻断,下次重跑 */ }
85
88
  }
@@ -183,7 +186,11 @@ export class DB {
183
186
 
184
187
  // 3. 都不可用
185
188
  if (readValid(this.dbPath) === null) {
186
- // 主库与备份都不存在 → 全新项目,建空库
189
+ // 主库与备份都不存在 → 全新项目,建空库。
190
+ // 全新标记(2026-10-06-status-multi-active-list):schema 戳只对它伴生的库文件作证——
191
+ // 库文件被删而戳残留时,init() 步骤4 的戳匹配会让全新空库跳过建表(孤儿戳空库,
192
+ // 首个 SELECT 即 no such table 崩溃,实测)。全新空库必须无视残留戳重跑 _createSchema。
193
+ this._freshCreate = true;
187
194
  return openDatabase(this.dbPath);
188
195
  }
189
196
  // 主库曾存在(空/损坏)但无法恢复 → 数据丢失,必须 fail-loud(不静默建空库吞进度)