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
@@ -21,7 +21,7 @@ import { getCrossWorktreeMeta, cleanupCrossWorktrees } from './worktree-cross.js
21
21
  import { parseFileChangeList, parseFileChangeListDetailed, pathMatches } from './change-list.js';
22
22
  import { parseAllowedPaths, parseRepo } from './stages/plan-postcheck.js';
23
23
  import { git, gitQuiet, safeGit, unquoteGitPath } from './git-helper.js';
24
- import { resolveLatestExecuteRunId, resolveLatestExecuteRunIdWithTasks, readReview, normalizeRepoKey } from './task-review.js';
24
+ import { resolveLatestExecuteRunId, resolveLatestExecuteRunIdWithTasks, readReview, readExecuteRunChangeStamp, normalizeRepoKey } from './task-review.js';
25
25
  import { collectActiveQuickGuardFiles } from './quicklog.js';
26
26
  import { appendWriteAudit, WRITE_AUDIT_FILE_CAP } from './write-audit.js';
27
27
  import { detectCommittedDrift, formatCommittedDriftWarning } from './run/concurrent-detect.js';
@@ -861,6 +861,14 @@ export function collectReviewDeclaredFiles(projectRoot, changeName, opts = {}) {
861
861
  || join(projectRoot, '.sillyspec', '.runtime');
862
862
  const runId = resolveLatestExecuteRunIdWithTasks({ runtimeRoot, changeName });
863
863
  if (!runId) return byRepo;
864
+ // 归属戳门控(2026-10-05-review-declared-unstamped-gate):resolver 无戳命中时回退拿
865
+ // mtime 最新的无主 run——从未跑过 execute 的变更会误挂无关历史 run 的 review 声明
866
+ // (实证:14 个 8 月无戳 run 文件误报「review 声明了越权文件」)。review changedFiles 是
867
+ // reviewer 对该 run 实际改动的经验证陈述,信任不跨 run 迁移——无戳即无法证明归属本变更,
868
+ // 声明面空集(fail-closed:少一份放松面;本变更 run 真丢戳时 apply 收紧报 violations,
869
+ // 补 design 清单/allowed_paths 即过)。resolver 本体不动——无主回退服务 task-done 等
870
+ // marker 漂移恢复场景。
871
+ if (readExecuteRunChangeStamp(runtimeRoot, runId) !== changeName) return byRepo;
864
872
  const runTasksDir = join(runtimeRoot, 'execute-runs', runId, 'tasks');
865
873
  if (!existsSync(runTasksDir)) return byRepo;
866
874
  for (const taskId of readdirSync(runTasksDir)) {
package/src/worktree.js CHANGED
@@ -1232,8 +1232,12 @@ export class WorktreeManager {
1232
1232
  const meta = parseJSON(readFileSync(metaPath, 'utf8'));
1233
1233
  if (!meta) continue;
1234
1234
  results.push({
1235
- changeName: meta.changeName,
1236
- branch: meta.branch,
1235
+ // 缺字段 meta 读侧归一化(2026-10-05-wt-list-resilience):注册表目录名恒由
1236
+ // create() 以 validateChangeName 过的变更名创建,是缺 changeName 件(e2e/旧版
1237
+ // 写入形态残留)的权威事实;branch 缺失展示 '-'。消费端(CLI list 渲染的
1238
+ // i.changeName.length、doctor 孤儿匹配的 metaNames)都要求 string。
1239
+ changeName: typeof meta.changeName === 'string' && meta.changeName ? meta.changeName : entry.name,
1240
+ branch: typeof meta.branch === 'string' && meta.branch ? meta.branch : '-',
1237
1241
  baseHash: meta.baseHash,
1238
1242
  baseBranch: meta.baseBranch,
1239
1243
  createdAt: meta.createdAt,
@@ -1295,11 +1299,22 @@ export class WorktreeManager {
1295
1299
  visit(runsDir);
1296
1300
  if (candidates.size === 0) return [];
1297
1301
  const refs = [];
1302
+ // 双探针(2026-10-05-branch-ref-anchor-scope):worktree 分支自带全部主仓历史,单探针
1303
+ // 「hash 是分支祖先或自身」会把旧 review.json 对历史主仓 commit 的引用全部误中(实证:
1304
+ // 56 个无关历史引用触发锚定打 tag)。锚定只护「分支独有」commit——删分支 ref 后真正会
1305
+ // 悬空的只有 baseline checkpoint/task commit;主仓 HEAD 可达的历史 commit 恒可达,不计入。
1306
+ // 探针二对象显式主仓根(_resolveMainRepoRoot)——native-worktree 复用路径下 cwd 是
1307
+ // worktree、其 HEAD 即分支自身,按 cwd 探会「永不锚定」fail-open。
1308
+ const mainRoot = this._resolveMainRepoRoot();
1298
1309
  for (const [hash, paths] of candidates) {
1299
- // merge-base --is-ancestor:祖先或自身 → exit 0 输出空串(gitQuiet 返回 ''≠null);
1300
- // 非祖先 → exit 1 → null;未知/畸形 hash → 报错非零 → null(不在分支内,语义正确)
1301
- const probe = gitQuiet(this.cwd, ['merge-base', '--is-ancestor', hash, branch]);
1302
- if (probe !== null) refs.push(...paths);
1310
+ // 探针一(语义不变):merge-base --is-ancestor 祖先或自身 → exit 0 输出空串(gitQuiet
1311
+ // 返回 ''≠null);非祖先 → exit 1 → null;未知/畸形 hash → 报错非零 → null(不在分支
1312
+ // 内,语义正确——非真实对象无可悬空链)
1313
+ if (gitQuiet(this.cwd, ['merge-base', '--is-ancestor', hash, branch]) === null) continue;
1314
+ // 探针二(新增):主仓 HEAD 祖先或自身 → ''≠null → 不计入(删分支后仍可达);探针失败
1315
+ // (null)按「不在主仓可达」处理即计入——fail-closed 宁误锚不误删
1316
+ if (gitQuiet(mainRoot, ['merge-base', '--is-ancestor', hash, 'HEAD']) !== null) continue;
1317
+ refs.push(...paths);
1303
1318
  }
1304
1319
  return [...new Set(refs)];
1305
1320
  }
@@ -6,26 +6,25 @@
6
6
  ## 选道(动手前先对号入座)
7
7
  | 需求形态 | 走法 |
8
8
  |---|---|
9
- | 需求已含决策(改什么、成功标准说得清) | **轻量变更(默认快道)**:`flow start` → 直接干活 → `flow done`,全程 2 次协议调用 |
10
- | 需求不清晰 / 需要方案探索 | 头脑风暴预段:`run brainstorm --change <名>` → 完成后 `flow start --change <名>` 收编续跑(产物自动接管,不重复起草;design 以头脑风暴版为准) |
11
- | 大改动:跨模块取舍 / 需要 Wave 计划编排 / 多阶段治理 / 设计期人机对抗 | 完整流程:`run brainstorm → plan → execute → verify → archive` 五阶段(每阶段一次渲染 + 一次 --done 收口;local.yaml 开 stage.burst 时一次下发全部步骤说明书;verify 用 `verify-probes --init --draft` 机器预填) |
12
- | 代码已先写好(倒推收尾) | 不回头补 brainstorm/plan 装样子:`flow start --change <名> --input "<已做改动的描述+成功标准>"` → `flow done`,实测门+测试绑定+patch 留档一步收口 |
9
+ | 需求已含决策(改什么、成功标准说得清) | **轻量变更(默认快道)**:`flow start` → 直接干活 → `flow done`(2 次协议调用;操作细节见 `/sillyspec:flow` skill 与 flow start 输出) |
10
+ | 需求不清晰 / 需要方案探索 | 头脑风暴预段:`run brainstorm --change <名>` → 完成后 `flow start --change <名>` 收编续跑(design 以头脑风暴版为准) |
11
+ | 大改动:跨模块取舍 / Wave 计划编排 / 多阶段治理 / 设计期人机对抗 | 完整流程五阶段:`run brainstorm → plan → execute → verify → archive`(每阶段一次渲染 + 一次 --done 收口;细节见各阶段 skill 与 CLI 输出) |
12
+ | 代码已先写好(倒推收尾) | 不回头补流程装样子:`flow start --change <YYYY-MM-DD-名> --input` 按下方过门格式写(动机=已做改动的描述,成功标准=已验证达标的行为)→ `flow done` 一步收口 |
13
13
 
14
- 选道看流程形态需求,不看技术关键词——风险面由收口评审按证据(承诺词/diff 原语/盲维作答)判定。轻量→完整转道是用户决策:须征得用户同意并带 `--upgrade-thick`(同意门留痕,无 flag 拒跑);轻量变更实测失败自动升厚。
14
+ `--input` 过门格式(轻量道首次调用即过,勿靠报错学;引号内换行合法,下例可照抄):
15
15
 
16
- ## 轻量变更(默认快道)
17
- `sillyspec flow start --change <名> --input "<需求>"` → 改代码、写测试(治理工件 CLI 机器起草,不用你写)→ `sillyspec flow done --change <名>`。
16
+ ```bash
17
+ sillyspec flow start --change <YYYY-MM-DD-名> --input "<动机与背景>
18
18
 
19
- `--input` 过门格式(清晰度门按此提取,缺「成功标准」条目会被拦下):
20
- 先写动机/背景;随后独立一行只写「成功标准:」;再每行一条「- <可验证标准>」。
19
+ 成功标准:
20
+ - <可验证标准>"
21
+ ```
21
22
 
22
- start 之后:按提示填 design.md 四节 AGENT 槽(做法/接口契约/边界并发四问/风险,每节至少一行,写「不适用:<理由>」也算答——空槽 flow done 拒收);干活时逐条勾 tasks.md 的 task-NN(勾选是收口哨兵证据面);收口前交付代码先用显式 pathspec 提交(patch 冻结面=baseline..HEAD 提交面,未提交的代码不进审计件)。
23
+ 选道看流程形态需求,不看技术关键词——风险面由收口评审按证据(承诺词/diff 原语/盲维作答)判定。轻量→完整转道是用户决策:须征得用户同意并带 `--upgrade-thick`(同意门留痕,无 flag 拒跑);轻量变更实测失败自动升厚。
23
24
 
24
- ## 常用命令速查
25
- - 看进度:`sillyspec progress show`;轻量变更恢复:重跑 `sillyspec flow start --change <名>`(输出恢复简报)或 `sillyspec flow status --change <名>`;完整流程恢复:`run <stage> --change <名>` 续跑。不直接 commit 半成品
26
- - 跨会话交接:`sillyspec handoff --change <名>`(生成交接块,新会话零背景可续)
27
- - 变更列表 / 状态:`sillyspec status`
28
- - 自检修复:`sillyspec doctor`
25
+ ## 恢复与查看
26
+ - 轻量变更恢复:重跑 `sillyspec flow start --change <名>`(输出恢复简报)或 `flow status --change <名>`;完整流程恢复:`run <stage> --change <名>` 续跑。不直接 commit 半成品
27
+ - 跨会话交接:`sillyspec handoff --change <名>`;变更列表:`sillyspec status`;自检修复:`sillyspec doctor`
29
28
  - 知识库:`sillyspec knowledge search "<关键词>"`(命中知识 CLI 会自动注入 prompt,勿自行重复检索)
30
29
 
31
30
  ## 核心规则
@@ -41,3 +40,4 @@ start 之后:按提示填 design.md 四节 AGENT 槽(做法/接口契约/边
41
40
  10. **会话启动先立身份**:`export SILLYSPEC_SESSION_ID=<唯一标识>`(如 agent 名+任务名)——多会话并行时 change 所有权判定(apply / cleanup / 归档对他会话活跃变更的接管拒绝)依赖此标识;缺省降级为 `anon@<主机名>` 机器级标识(只拦他机,同机并行不设防)。部分 harness 的 shell 状态不持久(env 随命令丢失),此时接管类命令每条显式带 flag:`sillyspec worktree apply <change> --session <唯一标识>`(`--session` 优先级高于 env)。
42
41
  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 文件警告(只警告不阻断)。
43
42
  12. **不奉承用户**,禁止"你说得对"类话术,直接给结论、依据、方案。
43
+ 13. **边干边勾(任务进度唯一源=变更的 tasks.md)**:完成一个任务单元(实现到位 + 相关测试跑绿)当场勾对应格——`sillyspec task tick --change <名> --task task-NN`(即时回显进度与下一任务)或直接 Edit 翻格 `- [ ]`→`- [x]`,勿攒到收口一把勾。harness 自带的 TodoWrite 类工具是会话内便利面,不替代 tasks.md——平台进度投影、收口哨兵、断点恢复只读 tasks.md。
@@ -33,3 +33,4 @@ TaskCard 格式规则(必须严格遵守):
33
33
  - allowed_paths 非空(至少一个真实源文件路径;回归类 task 无源码改动时填被验证的关键入口文件)
34
34
  - acceptance 与 verify 都在 frontmatter 内(漏写会被 plan-postcheck 报「缺少验收标准」/「缺少验证步骤」)
35
35
  - **生成方式**:由主 agent 一次性 `sillyspec taskcard <change-name> --all` 预生成全部安全骨架(LF 行尾 + frontmatter 必闭合 + 九个硬校验字段齐全 + author/created_at 自动填;幂等,已存在跳过)。**子代理不要并行跑 taskcard CLI**(2026-08-25 实证撞进度库 SQLite 锁),只往骨架里填语义内容(LF 行尾 + frontmatter 必闭合 + 九个硬校验字段齐全 + author/created_at 自动填),再往骨架里填语义内容——**勿用 Write tool 整文件手写**(CRLF / 漏闭合 `---` / 漏字段的根源,postcheck 报错大多由此来);已存在的卡命令会跳过不覆盖,局部修改用 Edit 定点改
36
+ - **填完即自检**:`sillyspec taskcard <change-name> --validate`——plan 门禁同源规则的零成本快照(frontmatter YAML 合法性含中文分诊/必要字段/占位符/target_files 形态),报错即门禁报错,修复后重跑至通过再推进(免 Step 4 门禁批量报错返工)