sillyspec 3.27.12 → 3.28.2
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/.claude/skills/sillyspec-execute/SKILL.md +214 -214
- package/.claude/skills/sillyspec-plan/SKILL.md +156 -156
- package/.claude/skills/sillyspec-quick/SKILL.md +116 -116
- package/package.json +1 -1
- package/src/agent-session-log.js +77 -10
- package/src/archive-delta.js +419 -0
- package/src/config-schema.js +2 -2
- package/src/contract-matrix.js +15 -2
- package/src/design-facts.js +354 -0
- package/src/docs-check.js +79 -8
- package/src/doctor-diagnostics.js +75 -3
- package/src/endpoint-baseline.js +109 -0
- package/src/endpoint-extractor.js +100 -24
- package/src/git-helper.js +31 -0
- package/src/index.js +248 -8
- package/src/machine-interface.js +63 -0
- package/src/modules.js +41 -12
- package/src/progress/change-registry.js +20 -0
- package/src/progress/consistency-doctor.js +124 -5
- package/src/progress/stage-machine.js +118 -2
- package/src/progress.js +6 -0
- package/src/quicklog.js +51 -0
- package/src/run/command.js +71 -2
- package/src/run/complete-handlers.js +84 -7
- package/src/run/complete.js +58 -5
- package/src/run/gates.js +333 -2
- package/src/run/prompt.js +70 -0
- package/src/run/quick-audit.js +98 -0
- package/src/run/scan-profile.js +98 -6
- package/src/run/shared.js +66 -1
- package/src/run/stage.js +25 -12
- package/src/scan-diff.js +54 -1
- package/src/scan-facts.js +173 -0
- package/src/scan-postcheck.js +110 -3
- package/src/spec-sync.js +210 -16
- package/src/stage-review.js +62 -3
- package/src/stages/archive.js +5 -5
- package/src/stages/brainstorm.js +10 -10
- package/src/stages/execute.js +21 -15
- package/src/stages/plan-postcheck.js +194 -1
- package/src/stages/plan.js +6 -2
- package/src/stages/scan.js +44 -102
- package/src/stages/verify.js +9 -7
- package/src/sync.js +122 -4
- package/src/task-review.js +51 -4
- package/src/taskcard.js +8 -1
- package/src/verify-postcheck.js +670 -10
- package/src/verify-probes.js +92 -10
- package/src/workflow.js +30 -0
- package/templates/agents-instruction.md +1 -1
- package/templates/prompts/taskcard-rules.md +5 -0
- package/templates/workflows/scan-docs.yaml +6 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-archive/SKILL.md +0 -87
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-auto/SKILL.md +0 -93
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-brainstorm/SKILL.md +0 -114
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-commit/SKILL.md +0 -67
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-continue/SKILL.md +0 -47
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-doctor/SKILL.md +0 -76
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-execute/SKILL.md +0 -214
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-explore/SKILL.md +0 -102
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-export/SKILL.md +0 -57
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-init/SKILL.md +0 -177
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-knowledge/SKILL.md +0 -270
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-plan/SKILL.md +0 -156
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-quick/SKILL.md +0 -116
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-resume/SKILL.md +0 -70
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-scan/SKILL.md +0 -79
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-state/SKILL.md +0 -64
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-status/SKILL.md +0 -54
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-verify/SKILL.md +0 -87
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-workspace/SKILL.md +0 -175
- package/.claude/worktrees/sillyspec-data-model-research/.gitattributes +0 -2
- package/.claude/worktrees/sillyspec-data-model-research/.husky/pre-push +0 -20
- package/.claude/worktrees/sillyspec-data-model-research/README.md +0 -203
- package/.claude/worktrees/sillyspec-data-model-research/SKILL.md +0 -91
- package/.claude/worktrees/sillyspec-data-model-research/bin/sillyspec.js +0 -2
- package/.claude/worktrees/sillyspec-data-model-research/logo.jpg +0 -0
- package/.claude/worktrees/sillyspec-data-model-research/package-lock.json +0 -977
- package/.claude/worktrees/sillyspec-data-model-research/package.json +0 -39
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/assets/index-Bq_Z2hne.js +0 -7446
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/assets/index-O2W5RV4z.css +0 -1
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/favicon.jpg +0 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/index.html +0 -16
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/logo.jpg +0 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/prototype-dashboard.html +0 -836
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/prototype-overview.html +0 -256
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/package.json +0 -25
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/executor.js +0 -95
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/index.js +0 -679
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/parser.js +0 -526
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/watcher.js +0 -357
- package/.claude/worktrees/sillyspec-data-model-research/src/agent-session-log.js +0 -803
- package/.claude/worktrees/sillyspec-data-model-research/src/change-list.js +0 -290
- package/.claude/worktrees/sillyspec-data-model-research/src/change-risk-profile.js +0 -270
- package/.claude/worktrees/sillyspec-data-model-research/src/check-primitives.js +0 -65
- package/.claude/worktrees/sillyspec-data-model-research/src/classify-change.js +0 -109
- package/.claude/worktrees/sillyspec-data-model-research/src/commit-suggest.js +0 -202
- package/.claude/worktrees/sillyspec-data-model-research/src/config-cat.js +0 -88
- package/.claude/worktrees/sillyspec-data-model-research/src/config-schema.js +0 -328
- package/.claude/worktrees/sillyspec-data-model-research/src/constants.js +0 -97
- package/.claude/worktrees/sillyspec-data-model-research/src/contract-matrix.js +0 -480
- package/.claude/worktrees/sillyspec-data-model-research/src/datetime.js +0 -20
- package/.claude/worktrees/sillyspec-data-model-research/src/db-engine.js +0 -55
- package/.claude/worktrees/sillyspec-data-model-research/src/db.js +0 -381
- package/.claude/worktrees/sillyspec-data-model-research/src/decision-distill.js +0 -517
- package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/backends/local-agent.js +0 -155
- package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/backends/sillyhub-mcp.js +0 -245
- package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/probe.js +0 -246
- package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/strategy.js +0 -121
- package/.claude/worktrees/sillyspec-data-model-research/src/docs-check.js +0 -825
- package/.claude/worktrees/sillyspec-data-model-research/src/docs-debt.js +0 -393
- package/.claude/worktrees/sillyspec-data-model-research/src/docs-gate.js +0 -107
- package/.claude/worktrees/sillyspec-data-model-research/src/doctor-diagnostics.js +0 -1099
- package/.claude/worktrees/sillyspec-data-model-research/src/endpoint-extractor.js +0 -420
- package/.claude/worktrees/sillyspec-data-model-research/src/foreign-declared.js +0 -78
- package/.claude/worktrees/sillyspec-data-model-research/src/fs-atomic.js +0 -73
- package/.claude/worktrees/sillyspec-data-model-research/src/git-helper.js +0 -150
- package/.claude/worktrees/sillyspec-data-model-research/src/hooks/claude-pre-tool-use.cjs +0 -130
- package/.claude/worktrees/sillyspec-data-model-research/src/hooks/worktree-guard.js +0 -892
- package/.claude/worktrees/sillyspec-data-model-research/src/index.js +0 -2798
- package/.claude/worktrees/sillyspec-data-model-research/src/init.js +0 -626
- package/.claude/worktrees/sillyspec-data-model-research/src/knowledge-match.js +0 -231
- package/.claude/worktrees/sillyspec-data-model-research/src/local-detect.js +0 -128
- package/.claude/worktrees/sillyspec-data-model-research/src/local-register.js +0 -104
- package/.claude/worktrees/sillyspec-data-model-research/src/machine-interface.js +0 -543
- package/.claude/worktrees/sillyspec-data-model-research/src/migrate.js +0 -127
- package/.claude/worktrees/sillyspec-data-model-research/src/module-impact.js +0 -166
- package/.claude/worktrees/sillyspec-data-model-research/src/module-resolve.js +0 -222
- package/.claude/worktrees/sillyspec-data-model-research/src/modules.js +0 -580
- package/.claude/worktrees/sillyspec-data-model-research/src/progress/change-registry.js +0 -336
- package/.claude/worktrees/sillyspec-data-model-research/src/progress/consistency-doctor.js +0 -355
- package/.claude/worktrees/sillyspec-data-model-research/src/progress/shared.js +0 -36
- package/.claude/worktrees/sillyspec-data-model-research/src/progress/stage-machine.js +0 -594
- package/.claude/worktrees/sillyspec-data-model-research/src/progress/step-store.js +0 -265
- package/.claude/worktrees/sillyspec-data-model-research/src/progress.js +0 -1304
- package/.claude/worktrees/sillyspec-data-model-research/src/quick-recommend.js +0 -115
- package/.claude/worktrees/sillyspec-data-model-research/src/quicklog.js +0 -852
- package/.claude/worktrees/sillyspec-data-model-research/src/review-tier.js +0 -77
- package/.claude/worktrees/sillyspec-data-model-research/src/run/command.js +0 -1595
- package/.claude/worktrees/sillyspec-data-model-research/src/run/complete-handlers.js +0 -1552
- package/.claude/worktrees/sillyspec-data-model-research/src/run/complete.js +0 -1259
- package/.claude/worktrees/sillyspec-data-model-research/src/run/concurrent-detect.js +0 -156
- package/.claude/worktrees/sillyspec-data-model-research/src/run/gates.js +0 -1084
- package/.claude/worktrees/sillyspec-data-model-research/src/run/multi-repo-context.js +0 -208
- package/.claude/worktrees/sillyspec-data-model-research/src/run/next.js +0 -128
- package/.claude/worktrees/sillyspec-data-model-research/src/run/prompt.js +0 -843
- package/.claude/worktrees/sillyspec-data-model-research/src/run/quick-audit.js +0 -186
- package/.claude/worktrees/sillyspec-data-model-research/src/run/scan-profile.js +0 -269
- package/.claude/worktrees/sillyspec-data-model-research/src/run/shared.js +0 -1562
- package/.claude/worktrees/sillyspec-data-model-research/src/run/stage.js +0 -584
- package/.claude/worktrees/sillyspec-data-model-research/src/run.js +0 -23
- package/.claude/worktrees/sillyspec-data-model-research/src/scan-diff.js +0 -388
- package/.claude/worktrees/sillyspec-data-model-research/src/scan-postcheck.js +0 -512
- package/.claude/worktrees/sillyspec-data-model-research/src/scan-staleness.js +0 -95
- package/.claude/worktrees/sillyspec-data-model-research/src/setup.js +0 -414
- package/.claude/worktrees/sillyspec-data-model-research/src/sillyhub-mcp/client.js +0 -597
- package/.claude/worktrees/sillyspec-data-model-research/src/sillyhub-mcp/config.js +0 -62
- package/.claude/worktrees/sillyspec-data-model-research/src/spec-dir-typo.js +0 -50
- package/.claude/worktrees/sillyspec-data-model-research/src/spec-sync.js +0 -358
- package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract-engine.js +0 -171
- package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract-spec.js +0 -550
- package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract.js +0 -889
- package/.claude/worktrees/sillyspec-data-model-research/src/stage-review.js +0 -597
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/archive.js +0 -199
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/brainstorm-auto.js +0 -236
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/brainstorm.js +0 -617
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/cmd-existence.js +0 -145
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/doctor.js +0 -540
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/execute.js +0 -1275
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/explore.js +0 -43
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/index.js +0 -29
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/knowledge.js +0 -514
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/plan-postcheck.js +0 -1344
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/plan.js +0 -650
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/quick.js +0 -167
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/scan.js +0 -608
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/status.js +0 -64
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/verify.js +0 -246
- package/.claude/worktrees/sillyspec-data-model-research/src/sync.js +0 -1470
- package/.claude/worktrees/sillyspec-data-model-research/src/task-review.js +0 -1498
- package/.claude/worktrees/sillyspec-data-model-research/src/taskcard.js +0 -210
- package/.claude/worktrees/sillyspec-data-model-research/src/verify-postcheck.js +0 -1718
- package/.claude/worktrees/sillyspec-data-model-research/src/verify-probes.js +0 -277
- package/.claude/worktrees/sillyspec-data-model-research/src/version.js +0 -19
- package/.claude/worktrees/sillyspec-data-model-research/src/workflow.js +0 -600
- package/.claude/worktrees/sillyspec-data-model-research/src/workspace.js +0 -125
- package/.claude/worktrees/sillyspec-data-model-research/src/worktree-apply.js +0 -1446
- package/.claude/worktrees/sillyspec-data-model-research/src/worktree-deps.js +0 -576
- package/.claude/worktrees/sillyspec-data-model-research/src/worktree.js +0 -1715
- package/.claude/worktrees/sillyspec-data-model-research/templates/claude-instruction.md +0 -23
- package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/taskcard-rules.md +0 -28
- package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/testcase-design.md +0 -12
- package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/verify-probes.md +0 -32
- package/.claude/worktrees/sillyspec-data-model-research/templates/workflows/archive-impact.yaml +0 -79
- package/.claude/worktrees/sillyspec-data-model-research/templates/workflows/scan-docs.yaml +0 -132
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-archive/SKILL.md +0 -87
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-auto/SKILL.md +0 -93
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-brainstorm/SKILL.md +0 -114
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-commit/SKILL.md +0 -67
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-continue/SKILL.md +0 -47
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-doctor/SKILL.md +0 -76
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-execute/SKILL.md +0 -214
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-explore/SKILL.md +0 -102
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-export/SKILL.md +0 -57
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-init/SKILL.md +0 -177
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-knowledge/SKILL.md +0 -270
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-plan/SKILL.md +0 -156
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-propose/SKILL.md +0 -87
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-quick/SKILL.md +0 -116
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-resume/SKILL.md +0 -70
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-scan/SKILL.md +0 -79
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-state/SKILL.md +0 -64
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-status/SKILL.md +0 -54
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-verify/SKILL.md +0 -87
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-workspace/SKILL.md +0 -175
- package/.worktrees/2c37b1d7/.claude/skills/verify-per-user/SKILL.md +0 -6
- package/.worktrees/2c37b1d7/.gitattributes +0 -2
- package/.worktrees/2c37b1d7/.husky/pre-push +0 -20
- package/.worktrees/2c37b1d7/README.md +0 -203
- package/.worktrees/2c37b1d7/SKILL.md +0 -91
- package/.worktrees/2c37b1d7/architecture-analysis.md +0 -448
- package/.worktrees/2c37b1d7/bin/sillyspec.js +0 -2
- package/.worktrees/2c37b1d7/eval/README.md +0 -86
- package/.worktrees/2c37b1d7/eval/eval.config.json +0 -28
- package/.worktrees/2c37b1d7/eval/lib/adapters/cli.mjs +0 -63
- package/.worktrees/2c37b1d7/eval/lib/adapters/dryrun.mjs +0 -27
- package/.worktrees/2c37b1d7/eval/lib/config.mjs +0 -82
- package/.worktrees/2c37b1d7/eval/lib/db.mjs +0 -76
- package/.worktrees/2c37b1d7/eval/lib/report.mjs +0 -120
- package/.worktrees/2c37b1d7/eval/lib/runner.mjs +0 -157
- package/.worktrees/2c37b1d7/eval/lib/tasks.mjs +0 -73
- package/.worktrees/2c37b1d7/eval/lib/util.mjs +0 -107
- package/.worktrees/2c37b1d7/eval/lib/workdir.mjs +0 -30
- package/.worktrees/2c37b1d7/eval/run.mjs +0 -83
- package/.worktrees/2c37b1d7/eval/tasks/001-slugify/files/package.json +0 -6
- package/.worktrees/2c37b1d7/eval/tasks/001-slugify/solution/src/slugify.mjs +0 -26
- package/.worktrees/2c37b1d7/eval/tasks/001-slugify/task.json +0 -6
- package/.worktrees/2c37b1d7/eval/tasks/001-slugify/verify.mjs +0 -28
- package/.worktrees/2c37b1d7/eval/tasks/002-each-day/files/package.json +0 -6
- package/.worktrees/2c37b1d7/eval/tasks/002-each-day/files/src/dates.mjs +0 -4
- package/.worktrees/2c37b1d7/eval/tasks/002-each-day/solution/src/dates.mjs +0 -30
- package/.worktrees/2c37b1d7/eval/tasks/002-each-day/task.json +0 -6
- package/.worktrees/2c37b1d7/eval/tasks/002-each-day/verify.mjs +0 -31
- package/.worktrees/2c37b1d7/eval/tasks/003-word-report/files/data/notes.txt +0 -5
- package/.worktrees/2c37b1d7/eval/tasks/003-word-report/files/package.json +0 -6
- package/.worktrees/2c37b1d7/eval/tasks/003-word-report/solution/bin/report.mjs +0 -36
- package/.worktrees/2c37b1d7/eval/tasks/003-word-report/task.json +0 -6
- package/.worktrees/2c37b1d7/eval/tasks/003-word-report/verify.mjs +0 -38
- package/.worktrees/2c37b1d7/logo.jpg +0 -0
- package/.worktrees/2c37b1d7/package-lock.json +0 -977
- package/.worktrees/2c37b1d7/package.json +0 -41
- package/.worktrees/2c37b1d7/packages/dashboard/dist/assets/index-Bq_Z2hne.js +0 -7446
- package/.worktrees/2c37b1d7/packages/dashboard/dist/assets/index-O2W5RV4z.css +0 -1
- package/.worktrees/2c37b1d7/packages/dashboard/dist/favicon.jpg +0 -0
- package/.worktrees/2c37b1d7/packages/dashboard/dist/index.html +0 -16
- package/.worktrees/2c37b1d7/packages/dashboard/dist/logo.jpg +0 -0
- package/.worktrees/2c37b1d7/packages/dashboard/dist/prototype-dashboard.html +0 -836
- package/.worktrees/2c37b1d7/packages/dashboard/dist/prototype-overview.html +0 -256
- package/.worktrees/2c37b1d7/packages/dashboard/package.json +0 -25
- package/.worktrees/2c37b1d7/packages/dashboard/server/executor.js +0 -95
- package/.worktrees/2c37b1d7/packages/dashboard/server/index.js +0 -679
- package/.worktrees/2c37b1d7/packages/dashboard/server/parser.js +0 -526
- package/.worktrees/2c37b1d7/packages/dashboard/server/watcher.js +0 -357
- package/.worktrees/2c37b1d7/src/agent-session-log.js +0 -803
- package/.worktrees/2c37b1d7/src/change-list.js +0 -290
- package/.worktrees/2c37b1d7/src/change-risk-profile.js +0 -339
- package/.worktrees/2c37b1d7/src/check-primitives.js +0 -65
- package/.worktrees/2c37b1d7/src/classify-change.js +0 -109
- package/.worktrees/2c37b1d7/src/commit-suggest.js +0 -202
- package/.worktrees/2c37b1d7/src/config-cat.js +0 -88
- package/.worktrees/2c37b1d7/src/config-schema.js +0 -328
- package/.worktrees/2c37b1d7/src/constants.js +0 -97
- package/.worktrees/2c37b1d7/src/contract-matrix.js +0 -533
- package/.worktrees/2c37b1d7/src/datetime.js +0 -20
- package/.worktrees/2c37b1d7/src/db-engine.js +0 -55
- package/.worktrees/2c37b1d7/src/db.js +0 -381
- package/.worktrees/2c37b1d7/src/decision-distill.js +0 -517
- package/.worktrees/2c37b1d7/src/dispatch/backends/local-agent.js +0 -155
- package/.worktrees/2c37b1d7/src/dispatch/backends/sillyhub-mcp.js +0 -245
- package/.worktrees/2c37b1d7/src/dispatch/probe.js +0 -246
- package/.worktrees/2c37b1d7/src/dispatch/strategy.js +0 -121
- package/.worktrees/2c37b1d7/src/docs-check.js +0 -825
- package/.worktrees/2c37b1d7/src/docs-debt.js +0 -393
- package/.worktrees/2c37b1d7/src/docs-gate.js +0 -107
- package/.worktrees/2c37b1d7/src/doctor-diagnostics.js +0 -1099
- package/.worktrees/2c37b1d7/src/endpoint-extractor.js +0 -409
- package/.worktrees/2c37b1d7/src/foreign-declared.js +0 -155
- package/.worktrees/2c37b1d7/src/fs-atomic.js +0 -73
- package/.worktrees/2c37b1d7/src/git-helper.js +0 -150
- package/.worktrees/2c37b1d7/src/hooks/claude-pre-tool-use.cjs +0 -130
- package/.worktrees/2c37b1d7/src/hooks/worktree-guard.js +0 -892
- package/.worktrees/2c37b1d7/src/index.js +0 -2854
- package/.worktrees/2c37b1d7/src/init.js +0 -626
- package/.worktrees/2c37b1d7/src/knowledge-match.js +0 -231
- package/.worktrees/2c37b1d7/src/local-detect.js +0 -128
- package/.worktrees/2c37b1d7/src/local-register.js +0 -104
- package/.worktrees/2c37b1d7/src/machine-interface.js +0 -543
- package/.worktrees/2c37b1d7/src/migrate.js +0 -127
- package/.worktrees/2c37b1d7/src/module-impact.js +0 -166
- package/.worktrees/2c37b1d7/src/module-resolve.js +0 -222
- package/.worktrees/2c37b1d7/src/modules.js +0 -580
- package/.worktrees/2c37b1d7/src/plan-adopt-waves.js +0 -126
- package/.worktrees/2c37b1d7/src/progress/change-registry.js +0 -336
- package/.worktrees/2c37b1d7/src/progress/consistency-doctor.js +0 -355
- package/.worktrees/2c37b1d7/src/progress/shared.js +0 -36
- package/.worktrees/2c37b1d7/src/progress/stage-machine.js +0 -594
- package/.worktrees/2c37b1d7/src/progress/step-store.js +0 -265
- package/.worktrees/2c37b1d7/src/progress.js +0 -1304
- package/.worktrees/2c37b1d7/src/quick-recommend.js +0 -115
- package/.worktrees/2c37b1d7/src/quicklog.js +0 -883
- package/.worktrees/2c37b1d7/src/review-tier.js +0 -77
- package/.worktrees/2c37b1d7/src/run/command.js +0 -1641
- package/.worktrees/2c37b1d7/src/run/complete-handlers.js +0 -1552
- package/.worktrees/2c37b1d7/src/run/complete.js +0 -1259
- package/.worktrees/2c37b1d7/src/run/concurrent-detect.js +0 -156
- package/.worktrees/2c37b1d7/src/run/gates.js +0 -1111
- package/.worktrees/2c37b1d7/src/run/multi-repo-context.js +0 -208
- package/.worktrees/2c37b1d7/src/run/next.js +0 -128
- package/.worktrees/2c37b1d7/src/run/prompt.js +0 -843
- package/.worktrees/2c37b1d7/src/run/quick-audit.js +0 -186
- package/.worktrees/2c37b1d7/src/run/scan-profile.js +0 -269
- package/.worktrees/2c37b1d7/src/run/shared.js +0 -1562
- package/.worktrees/2c37b1d7/src/run/stage.js +0 -587
- package/.worktrees/2c37b1d7/src/run.js +0 -23
- package/.worktrees/2c37b1d7/src/scan-diff.js +0 -388
- package/.worktrees/2c37b1d7/src/scan-postcheck.js +0 -524
- package/.worktrees/2c37b1d7/src/scan-staleness.js +0 -95
- package/.worktrees/2c37b1d7/src/setup.js +0 -414
- package/.worktrees/2c37b1d7/src/sillyhub-mcp/client.js +0 -597
- package/.worktrees/2c37b1d7/src/sillyhub-mcp/config.js +0 -62
- package/.worktrees/2c37b1d7/src/spec-dir-typo.js +0 -50
- package/.worktrees/2c37b1d7/src/spec-sync.js +0 -358
- package/.worktrees/2c37b1d7/src/stage-contract-engine.js +0 -171
- package/.worktrees/2c37b1d7/src/stage-contract-spec.js +0 -551
- package/.worktrees/2c37b1d7/src/stage-contract.js +0 -948
- package/.worktrees/2c37b1d7/src/stage-review.js +0 -597
- package/.worktrees/2c37b1d7/src/stages/archive.js +0 -199
- package/.worktrees/2c37b1d7/src/stages/brainstorm-auto.js +0 -285
- package/.worktrees/2c37b1d7/src/stages/brainstorm.js +0 -624
- package/.worktrees/2c37b1d7/src/stages/cmd-existence.js +0 -145
- package/.worktrees/2c37b1d7/src/stages/doctor.js +0 -540
- package/.worktrees/2c37b1d7/src/stages/execute.js +0 -1277
- package/.worktrees/2c37b1d7/src/stages/explore.js +0 -43
- package/.worktrees/2c37b1d7/src/stages/index.js +0 -29
- package/.worktrees/2c37b1d7/src/stages/knowledge.js +0 -514
- package/.worktrees/2c37b1d7/src/stages/plan-postcheck.js +0 -1398
- package/.worktrees/2c37b1d7/src/stages/plan.js +0 -655
- package/.worktrees/2c37b1d7/src/stages/quick.js +0 -167
- package/.worktrees/2c37b1d7/src/stages/scan.js +0 -608
- package/.worktrees/2c37b1d7/src/stages/status.js +0 -64
- package/.worktrees/2c37b1d7/src/stages/verify.js +0 -246
- package/.worktrees/2c37b1d7/src/sync.js +0 -1470
- package/.worktrees/2c37b1d7/src/task-review.js +0 -1498
- package/.worktrees/2c37b1d7/src/taskcard-placeholders.js +0 -21
- package/.worktrees/2c37b1d7/src/taskcard.js +0 -250
- package/.worktrees/2c37b1d7/src/verify-postcheck.js +0 -1718
- package/.worktrees/2c37b1d7/src/verify-probes.js +0 -327
- package/.worktrees/2c37b1d7/src/version.js +0 -19
- package/.worktrees/2c37b1d7/src/workflow.js +0 -600
- package/.worktrees/2c37b1d7/src/workspace.js +0 -125
- package/.worktrees/2c37b1d7/src/worktree-apply.js +0 -1611
- package/.worktrees/2c37b1d7/src/worktree-deps.js +0 -668
- package/.worktrees/2c37b1d7/src/worktree.js +0 -1849
- package/.worktrees/2c37b1d7/templates/claude-instruction.md +0 -23
- package/.worktrees/2c37b1d7/templates/prompts/taskcard-rules.md +0 -29
- package/.worktrees/2c37b1d7/templates/prompts/testcase-design.md +0 -12
- package/.worktrees/2c37b1d7/templates/prompts/verify-probes.md +0 -32
- package/.worktrees/2c37b1d7/templates/workflows/archive-impact.yaml +0 -79
- package/.worktrees/2c37b1d7/templates/workflows/scan-docs.yaml +0 -132
- package/.worktrees/542c4415/.claude/skills/sillyspec-archive/SKILL.md +0 -87
- package/.worktrees/542c4415/.claude/skills/sillyspec-auto/SKILL.md +0 -93
- package/.worktrees/542c4415/.claude/skills/sillyspec-brainstorm/SKILL.md +0 -114
- package/.worktrees/542c4415/.claude/skills/sillyspec-commit/SKILL.md +0 -67
- package/.worktrees/542c4415/.claude/skills/sillyspec-continue/SKILL.md +0 -47
- package/.worktrees/542c4415/.claude/skills/sillyspec-doctor/SKILL.md +0 -76
- package/.worktrees/542c4415/.claude/skills/sillyspec-execute/SKILL.md +0 -214
- package/.worktrees/542c4415/.claude/skills/sillyspec-explore/SKILL.md +0 -102
- package/.worktrees/542c4415/.claude/skills/sillyspec-export/SKILL.md +0 -57
- package/.worktrees/542c4415/.claude/skills/sillyspec-init/SKILL.md +0 -177
- package/.worktrees/542c4415/.claude/skills/sillyspec-knowledge/SKILL.md +0 -270
- package/.worktrees/542c4415/.claude/skills/sillyspec-plan/SKILL.md +0 -156
- package/.worktrees/542c4415/.claude/skills/sillyspec-quick/SKILL.md +0 -116
- package/.worktrees/542c4415/.claude/skills/sillyspec-resume/SKILL.md +0 -70
- package/.worktrees/542c4415/.claude/skills/sillyspec-scan/SKILL.md +0 -79
- package/.worktrees/542c4415/.claude/skills/sillyspec-state/SKILL.md +0 -64
- package/.worktrees/542c4415/.claude/skills/sillyspec-status/SKILL.md +0 -54
- package/.worktrees/542c4415/.claude/skills/sillyspec-verify/SKILL.md +0 -87
- package/.worktrees/542c4415/.claude/skills/sillyspec-workspace/SKILL.md +0 -175
- package/.worktrees/542c4415/.gitattributes +0 -2
- package/.worktrees/542c4415/.husky/pre-push +0 -20
- package/.worktrees/542c4415/README.md +0 -203
- package/.worktrees/542c4415/SKILL.md +0 -91
- package/.worktrees/542c4415/architecture-analysis.md +0 -448
- package/.worktrees/542c4415/bin/sillyspec.js +0 -2
- package/.worktrees/542c4415/eval/README.md +0 -86
- package/.worktrees/542c4415/eval/eval.config.json +0 -28
- package/.worktrees/542c4415/eval/lib/adapters/cli.mjs +0 -63
- package/.worktrees/542c4415/eval/lib/adapters/dryrun.mjs +0 -27
- package/.worktrees/542c4415/eval/lib/config.mjs +0 -82
- package/.worktrees/542c4415/eval/lib/db.mjs +0 -76
- package/.worktrees/542c4415/eval/lib/report.mjs +0 -120
- package/.worktrees/542c4415/eval/lib/runner.mjs +0 -157
- package/.worktrees/542c4415/eval/lib/tasks.mjs +0 -73
- package/.worktrees/542c4415/eval/lib/util.mjs +0 -107
- package/.worktrees/542c4415/eval/lib/workdir.mjs +0 -30
- package/.worktrees/542c4415/eval/run.mjs +0 -83
- package/.worktrees/542c4415/eval/tasks/001-slugify/files/package.json +0 -6
- package/.worktrees/542c4415/eval/tasks/001-slugify/solution/src/slugify.mjs +0 -26
- package/.worktrees/542c4415/eval/tasks/001-slugify/task.json +0 -6
- package/.worktrees/542c4415/eval/tasks/001-slugify/verify.mjs +0 -28
- package/.worktrees/542c4415/eval/tasks/002-each-day/files/package.json +0 -6
- package/.worktrees/542c4415/eval/tasks/002-each-day/files/src/dates.mjs +0 -4
- package/.worktrees/542c4415/eval/tasks/002-each-day/solution/src/dates.mjs +0 -30
- package/.worktrees/542c4415/eval/tasks/002-each-day/task.json +0 -6
- package/.worktrees/542c4415/eval/tasks/002-each-day/verify.mjs +0 -31
- package/.worktrees/542c4415/eval/tasks/003-word-report/files/data/notes.txt +0 -5
- package/.worktrees/542c4415/eval/tasks/003-word-report/files/package.json +0 -6
- package/.worktrees/542c4415/eval/tasks/003-word-report/solution/bin/report.mjs +0 -36
- package/.worktrees/542c4415/eval/tasks/003-word-report/task.json +0 -6
- package/.worktrees/542c4415/eval/tasks/003-word-report/verify.mjs +0 -38
- package/.worktrees/542c4415/logo.jpg +0 -0
- package/.worktrees/542c4415/package-lock.json +0 -977
- package/.worktrees/542c4415/package.json +0 -41
- package/.worktrees/542c4415/packages/dashboard/dist/assets/index-Bq_Z2hne.js +0 -7446
- package/.worktrees/542c4415/packages/dashboard/dist/assets/index-O2W5RV4z.css +0 -1
- package/.worktrees/542c4415/packages/dashboard/dist/favicon.jpg +0 -0
- package/.worktrees/542c4415/packages/dashboard/dist/index.html +0 -16
- package/.worktrees/542c4415/packages/dashboard/dist/logo.jpg +0 -0
- package/.worktrees/542c4415/packages/dashboard/dist/prototype-dashboard.html +0 -836
- package/.worktrees/542c4415/packages/dashboard/dist/prototype-overview.html +0 -256
- package/.worktrees/542c4415/packages/dashboard/package.json +0 -25
- package/.worktrees/542c4415/packages/dashboard/server/executor.js +0 -95
- package/.worktrees/542c4415/packages/dashboard/server/index.js +0 -679
- package/.worktrees/542c4415/packages/dashboard/server/parser.js +0 -526
- package/.worktrees/542c4415/packages/dashboard/server/watcher.js +0 -357
- package/.worktrees/542c4415/src/agent-session-log.js +0 -803
- package/.worktrees/542c4415/src/change-list.js +0 -290
- package/.worktrees/542c4415/src/change-risk-profile.js +0 -339
- package/.worktrees/542c4415/src/check-primitives.js +0 -65
- package/.worktrees/542c4415/src/classify-change.js +0 -109
- package/.worktrees/542c4415/src/commit-suggest.js +0 -202
- package/.worktrees/542c4415/src/config-cat.js +0 -88
- package/.worktrees/542c4415/src/config-schema.js +0 -328
- package/.worktrees/542c4415/src/constants.js +0 -97
- package/.worktrees/542c4415/src/contract-matrix.js +0 -533
- package/.worktrees/542c4415/src/datetime.js +0 -20
- package/.worktrees/542c4415/src/db-engine.js +0 -55
- package/.worktrees/542c4415/src/db.js +0 -381
- package/.worktrees/542c4415/src/decision-distill.js +0 -517
- package/.worktrees/542c4415/src/dispatch/backends/local-agent.js +0 -155
- package/.worktrees/542c4415/src/dispatch/backends/sillyhub-mcp.js +0 -245
- package/.worktrees/542c4415/src/dispatch/probe.js +0 -246
- package/.worktrees/542c4415/src/dispatch/strategy.js +0 -121
- package/.worktrees/542c4415/src/docs-check.js +0 -825
- package/.worktrees/542c4415/src/docs-debt.js +0 -393
- package/.worktrees/542c4415/src/docs-gate.js +0 -107
- package/.worktrees/542c4415/src/doctor-diagnostics.js +0 -1099
- package/.worktrees/542c4415/src/endpoint-extractor.js +0 -409
- package/.worktrees/542c4415/src/foreign-declared.js +0 -155
- package/.worktrees/542c4415/src/fs-atomic.js +0 -73
- package/.worktrees/542c4415/src/git-helper.js +0 -150
- package/.worktrees/542c4415/src/hooks/claude-pre-tool-use.cjs +0 -130
- package/.worktrees/542c4415/src/hooks/worktree-guard.js +0 -892
- package/.worktrees/542c4415/src/index.js +0 -2854
- package/.worktrees/542c4415/src/init.js +0 -626
- package/.worktrees/542c4415/src/knowledge-match.js +0 -231
- package/.worktrees/542c4415/src/local-detect.js +0 -128
- package/.worktrees/542c4415/src/local-register.js +0 -104
- package/.worktrees/542c4415/src/machine-interface.js +0 -543
- package/.worktrees/542c4415/src/migrate.js +0 -127
- package/.worktrees/542c4415/src/module-impact.js +0 -166
- package/.worktrees/542c4415/src/module-resolve.js +0 -222
- package/.worktrees/542c4415/src/modules.js +0 -580
- package/.worktrees/542c4415/src/plan-adopt-waves.js +0 -126
- package/.worktrees/542c4415/src/progress/change-registry.js +0 -336
- package/.worktrees/542c4415/src/progress/consistency-doctor.js +0 -355
- package/.worktrees/542c4415/src/progress/shared.js +0 -36
- package/.worktrees/542c4415/src/progress/stage-machine.js +0 -594
- package/.worktrees/542c4415/src/progress/step-store.js +0 -265
- package/.worktrees/542c4415/src/progress.js +0 -1304
- package/.worktrees/542c4415/src/quick-recommend.js +0 -115
- package/.worktrees/542c4415/src/quicklog.js +0 -883
- package/.worktrees/542c4415/src/review-tier.js +0 -77
- package/.worktrees/542c4415/src/run/command.js +0 -1641
- package/.worktrees/542c4415/src/run/complete-handlers.js +0 -1552
- package/.worktrees/542c4415/src/run/complete.js +0 -1259
- package/.worktrees/542c4415/src/run/concurrent-detect.js +0 -156
- package/.worktrees/542c4415/src/run/gates.js +0 -1111
- package/.worktrees/542c4415/src/run/multi-repo-context.js +0 -208
- package/.worktrees/542c4415/src/run/next.js +0 -128
- package/.worktrees/542c4415/src/run/prompt.js +0 -843
- package/.worktrees/542c4415/src/run/quick-audit.js +0 -186
- package/.worktrees/542c4415/src/run/scan-profile.js +0 -269
- package/.worktrees/542c4415/src/run/shared.js +0 -1562
- package/.worktrees/542c4415/src/run/stage.js +0 -587
- package/.worktrees/542c4415/src/run.js +0 -23
- package/.worktrees/542c4415/src/scan-diff.js +0 -388
- package/.worktrees/542c4415/src/scan-postcheck.js +0 -524
- package/.worktrees/542c4415/src/scan-staleness.js +0 -95
- package/.worktrees/542c4415/src/setup.js +0 -414
- package/.worktrees/542c4415/src/sillyhub-mcp/client.js +0 -597
- package/.worktrees/542c4415/src/sillyhub-mcp/config.js +0 -62
- package/.worktrees/542c4415/src/spec-dir-typo.js +0 -50
- package/.worktrees/542c4415/src/spec-sync.js +0 -358
- package/.worktrees/542c4415/src/stage-contract-engine.js +0 -171
- package/.worktrees/542c4415/src/stage-contract-spec.js +0 -551
- package/.worktrees/542c4415/src/stage-contract.js +0 -948
- package/.worktrees/542c4415/src/stage-review.js +0 -597
- package/.worktrees/542c4415/src/stages/archive.js +0 -199
- package/.worktrees/542c4415/src/stages/brainstorm-auto.js +0 -285
- package/.worktrees/542c4415/src/stages/brainstorm.js +0 -624
- package/.worktrees/542c4415/src/stages/cmd-existence.js +0 -145
- package/.worktrees/542c4415/src/stages/doctor.js +0 -540
- package/.worktrees/542c4415/src/stages/execute.js +0 -1277
- package/.worktrees/542c4415/src/stages/explore.js +0 -43
- package/.worktrees/542c4415/src/stages/index.js +0 -29
- package/.worktrees/542c4415/src/stages/knowledge.js +0 -514
- package/.worktrees/542c4415/src/stages/plan-postcheck.js +0 -1398
- package/.worktrees/542c4415/src/stages/plan.js +0 -655
- package/.worktrees/542c4415/src/stages/quick.js +0 -167
- package/.worktrees/542c4415/src/stages/scan.js +0 -608
- package/.worktrees/542c4415/src/stages/status.js +0 -64
- package/.worktrees/542c4415/src/stages/verify.js +0 -246
- package/.worktrees/542c4415/src/sync.js +0 -1470
- package/.worktrees/542c4415/src/task-review.js +0 -1498
- package/.worktrees/542c4415/src/taskcard-placeholders.js +0 -21
- package/.worktrees/542c4415/src/taskcard.js +0 -250
- package/.worktrees/542c4415/src/verify-postcheck.js +0 -1718
- package/.worktrees/542c4415/src/verify-probes.js +0 -327
- package/.worktrees/542c4415/src/version.js +0 -19
- package/.worktrees/542c4415/src/workflow.js +0 -600
- package/.worktrees/542c4415/src/workspace.js +0 -125
- package/.worktrees/542c4415/src/worktree-apply.js +0 -1611
- package/.worktrees/542c4415/src/worktree-deps.js +0 -668
- package/.worktrees/542c4415/src/worktree.js +0 -1849
- package/.worktrees/542c4415/templates/claude-instruction.md +0 -23
- package/.worktrees/542c4415/templates/prompts/taskcard-rules.md +0 -29
- package/.worktrees/542c4415/templates/prompts/testcase-design.md +0 -12
- package/.worktrees/542c4415/templates/prompts/verify-probes.md +0 -32
- package/.worktrees/542c4415/templates/workflows/archive-impact.yaml +0 -79
- package/.worktrees/542c4415/templates/workflows/scan-docs.yaml +0 -132
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-archive/SKILL.md +0 -87
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-auto/SKILL.md +0 -93
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-brainstorm/SKILL.md +0 -114
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-commit/SKILL.md +0 -67
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-continue/SKILL.md +0 -47
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-doctor/SKILL.md +0 -76
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-execute/SKILL.md +0 -214
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-explore/SKILL.md +0 -102
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-export/SKILL.md +0 -57
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-init/SKILL.md +0 -177
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-knowledge/SKILL.md +0 -270
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-plan/SKILL.md +0 -156
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-propose/SKILL.md +0 -87
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-quick/SKILL.md +0 -116
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-resume/SKILL.md +0 -70
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-scan/SKILL.md +0 -79
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-state/SKILL.md +0 -64
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-status/SKILL.md +0 -54
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-verify/SKILL.md +0 -87
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-workspace/SKILL.md +0 -175
- package/.worktrees/8d2d0392/.claude/skills/verify-per-user/SKILL.md +0 -6
- package/.worktrees/8d2d0392/.gitattributes +0 -2
- package/.worktrees/8d2d0392/.husky/pre-push +0 -20
- package/.worktrees/8d2d0392/README.md +0 -203
- package/.worktrees/8d2d0392/SKILL.md +0 -91
- package/.worktrees/8d2d0392/architecture-analysis.md +0 -448
- package/.worktrees/8d2d0392/bin/sillyspec.js +0 -2
- package/.worktrees/8d2d0392/eval/README.md +0 -86
- package/.worktrees/8d2d0392/eval/eval.config.json +0 -28
- package/.worktrees/8d2d0392/eval/lib/adapters/cli.mjs +0 -63
- package/.worktrees/8d2d0392/eval/lib/adapters/dryrun.mjs +0 -27
- package/.worktrees/8d2d0392/eval/lib/config.mjs +0 -82
- package/.worktrees/8d2d0392/eval/lib/db.mjs +0 -76
- package/.worktrees/8d2d0392/eval/lib/report.mjs +0 -120
- package/.worktrees/8d2d0392/eval/lib/runner.mjs +0 -157
- package/.worktrees/8d2d0392/eval/lib/tasks.mjs +0 -73
- package/.worktrees/8d2d0392/eval/lib/util.mjs +0 -107
- package/.worktrees/8d2d0392/eval/lib/workdir.mjs +0 -30
- package/.worktrees/8d2d0392/eval/run.mjs +0 -83
- package/.worktrees/8d2d0392/eval/tasks/001-slugify/files/package.json +0 -6
- package/.worktrees/8d2d0392/eval/tasks/001-slugify/solution/src/slugify.mjs +0 -26
- package/.worktrees/8d2d0392/eval/tasks/001-slugify/task.json +0 -6
- package/.worktrees/8d2d0392/eval/tasks/001-slugify/verify.mjs +0 -28
- package/.worktrees/8d2d0392/eval/tasks/002-each-day/files/package.json +0 -6
- package/.worktrees/8d2d0392/eval/tasks/002-each-day/files/src/dates.mjs +0 -4
- package/.worktrees/8d2d0392/eval/tasks/002-each-day/solution/src/dates.mjs +0 -30
- package/.worktrees/8d2d0392/eval/tasks/002-each-day/task.json +0 -6
- package/.worktrees/8d2d0392/eval/tasks/002-each-day/verify.mjs +0 -31
- package/.worktrees/8d2d0392/eval/tasks/003-word-report/files/data/notes.txt +0 -5
- package/.worktrees/8d2d0392/eval/tasks/003-word-report/files/package.json +0 -6
- package/.worktrees/8d2d0392/eval/tasks/003-word-report/solution/bin/report.mjs +0 -36
- package/.worktrees/8d2d0392/eval/tasks/003-word-report/task.json +0 -6
- package/.worktrees/8d2d0392/eval/tasks/003-word-report/verify.mjs +0 -38
- package/.worktrees/8d2d0392/logo.jpg +0 -0
- package/.worktrees/8d2d0392/package-lock.json +0 -977
- package/.worktrees/8d2d0392/package.json +0 -41
- package/.worktrees/8d2d0392/packages/dashboard/dist/assets/index-Bq_Z2hne.js +0 -7446
- package/.worktrees/8d2d0392/packages/dashboard/dist/assets/index-O2W5RV4z.css +0 -1
- package/.worktrees/8d2d0392/packages/dashboard/dist/favicon.jpg +0 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/index.html +0 -16
- package/.worktrees/8d2d0392/packages/dashboard/dist/logo.jpg +0 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/prototype-dashboard.html +0 -836
- package/.worktrees/8d2d0392/packages/dashboard/dist/prototype-overview.html +0 -256
- package/.worktrees/8d2d0392/packages/dashboard/package.json +0 -25
- package/.worktrees/8d2d0392/packages/dashboard/server/executor.js +0 -95
- package/.worktrees/8d2d0392/packages/dashboard/server/index.js +0 -679
- package/.worktrees/8d2d0392/packages/dashboard/server/parser.js +0 -526
- package/.worktrees/8d2d0392/packages/dashboard/server/watcher.js +0 -357
- package/.worktrees/8d2d0392/src/agent-session-log.js +0 -803
- package/.worktrees/8d2d0392/src/change-list.js +0 -290
- package/.worktrees/8d2d0392/src/change-risk-profile.js +0 -339
- package/.worktrees/8d2d0392/src/check-primitives.js +0 -65
- package/.worktrees/8d2d0392/src/classify-change.js +0 -109
- package/.worktrees/8d2d0392/src/commit-suggest.js +0 -202
- package/.worktrees/8d2d0392/src/config-cat.js +0 -88
- package/.worktrees/8d2d0392/src/config-schema.js +0 -328
- package/.worktrees/8d2d0392/src/constants.js +0 -97
- package/.worktrees/8d2d0392/src/contract-matrix.js +0 -533
- package/.worktrees/8d2d0392/src/datetime.js +0 -20
- package/.worktrees/8d2d0392/src/db-engine.js +0 -55
- package/.worktrees/8d2d0392/src/db.js +0 -381
- package/.worktrees/8d2d0392/src/decision-distill.js +0 -517
- package/.worktrees/8d2d0392/src/dispatch/backends/local-agent.js +0 -155
- package/.worktrees/8d2d0392/src/dispatch/backends/sillyhub-mcp.js +0 -245
- package/.worktrees/8d2d0392/src/dispatch/probe.js +0 -246
- package/.worktrees/8d2d0392/src/dispatch/strategy.js +0 -121
- package/.worktrees/8d2d0392/src/docs-check.js +0 -825
- package/.worktrees/8d2d0392/src/docs-debt.js +0 -393
- package/.worktrees/8d2d0392/src/docs-gate.js +0 -107
- package/.worktrees/8d2d0392/src/doctor-diagnostics.js +0 -1099
- package/.worktrees/8d2d0392/src/endpoint-extractor.js +0 -409
- package/.worktrees/8d2d0392/src/foreign-declared.js +0 -78
- package/.worktrees/8d2d0392/src/fs-atomic.js +0 -73
- package/.worktrees/8d2d0392/src/git-helper.js +0 -150
- package/.worktrees/8d2d0392/src/hooks/claude-pre-tool-use.cjs +0 -130
- package/.worktrees/8d2d0392/src/hooks/worktree-guard.js +0 -892
- package/.worktrees/8d2d0392/src/index.js +0 -2854
- package/.worktrees/8d2d0392/src/init.js +0 -626
- package/.worktrees/8d2d0392/src/knowledge-match.js +0 -231
- package/.worktrees/8d2d0392/src/local-detect.js +0 -128
- package/.worktrees/8d2d0392/src/local-register.js +0 -104
- package/.worktrees/8d2d0392/src/machine-interface.js +0 -543
- package/.worktrees/8d2d0392/src/migrate.js +0 -127
- package/.worktrees/8d2d0392/src/module-impact.js +0 -166
- package/.worktrees/8d2d0392/src/module-resolve.js +0 -222
- package/.worktrees/8d2d0392/src/modules.js +0 -580
- package/.worktrees/8d2d0392/src/plan-adopt-waves.js +0 -126
- package/.worktrees/8d2d0392/src/progress/change-registry.js +0 -336
- package/.worktrees/8d2d0392/src/progress/consistency-doctor.js +0 -355
- package/.worktrees/8d2d0392/src/progress/shared.js +0 -36
- package/.worktrees/8d2d0392/src/progress/stage-machine.js +0 -594
- package/.worktrees/8d2d0392/src/progress/step-store.js +0 -265
- package/.worktrees/8d2d0392/src/progress.js +0 -1304
- package/.worktrees/8d2d0392/src/quick-recommend.js +0 -115
- package/.worktrees/8d2d0392/src/quicklog.js +0 -883
- package/.worktrees/8d2d0392/src/review-tier.js +0 -77
- package/.worktrees/8d2d0392/src/run/command.js +0 -1641
- package/.worktrees/8d2d0392/src/run/complete-handlers.js +0 -1552
- package/.worktrees/8d2d0392/src/run/complete.js +0 -1259
- package/.worktrees/8d2d0392/src/run/concurrent-detect.js +0 -156
- package/.worktrees/8d2d0392/src/run/gates.js +0 -1094
- package/.worktrees/8d2d0392/src/run/multi-repo-context.js +0 -208
- package/.worktrees/8d2d0392/src/run/next.js +0 -128
- package/.worktrees/8d2d0392/src/run/prompt.js +0 -843
- package/.worktrees/8d2d0392/src/run/quick-audit.js +0 -186
- package/.worktrees/8d2d0392/src/run/scan-profile.js +0 -269
- package/.worktrees/8d2d0392/src/run/shared.js +0 -1562
- package/.worktrees/8d2d0392/src/run/stage.js +0 -587
- package/.worktrees/8d2d0392/src/run.js +0 -23
- package/.worktrees/8d2d0392/src/scan-diff.js +0 -388
- package/.worktrees/8d2d0392/src/scan-postcheck.js +0 -524
- package/.worktrees/8d2d0392/src/scan-staleness.js +0 -95
- package/.worktrees/8d2d0392/src/setup.js +0 -414
- package/.worktrees/8d2d0392/src/sillyhub-mcp/client.js +0 -597
- package/.worktrees/8d2d0392/src/sillyhub-mcp/config.js +0 -62
- package/.worktrees/8d2d0392/src/spec-dir-typo.js +0 -50
- package/.worktrees/8d2d0392/src/spec-sync.js +0 -358
- package/.worktrees/8d2d0392/src/stage-contract-engine.js +0 -171
- package/.worktrees/8d2d0392/src/stage-contract-spec.js +0 -551
- package/.worktrees/8d2d0392/src/stage-contract.js +0 -948
- package/.worktrees/8d2d0392/src/stage-review.js +0 -597
- package/.worktrees/8d2d0392/src/stages/archive.js +0 -199
- package/.worktrees/8d2d0392/src/stages/brainstorm-auto.js +0 -285
- package/.worktrees/8d2d0392/src/stages/brainstorm.js +0 -624
- package/.worktrees/8d2d0392/src/stages/cmd-existence.js +0 -145
- package/.worktrees/8d2d0392/src/stages/doctor.js +0 -540
- package/.worktrees/8d2d0392/src/stages/execute.js +0 -1277
- package/.worktrees/8d2d0392/src/stages/explore.js +0 -43
- package/.worktrees/8d2d0392/src/stages/index.js +0 -29
- package/.worktrees/8d2d0392/src/stages/knowledge.js +0 -514
- package/.worktrees/8d2d0392/src/stages/plan-postcheck.js +0 -1398
- package/.worktrees/8d2d0392/src/stages/plan.js +0 -651
- package/.worktrees/8d2d0392/src/stages/quick.js +0 -167
- package/.worktrees/8d2d0392/src/stages/scan.js +0 -608
- package/.worktrees/8d2d0392/src/stages/status.js +0 -64
- package/.worktrees/8d2d0392/src/stages/verify.js +0 -246
- package/.worktrees/8d2d0392/src/sync.js +0 -1470
- package/.worktrees/8d2d0392/src/task-review.js +0 -1498
- package/.worktrees/8d2d0392/src/taskcard-placeholders.js +0 -21
- package/.worktrees/8d2d0392/src/taskcard.js +0 -217
- package/.worktrees/8d2d0392/src/verify-postcheck.js +0 -1718
- package/.worktrees/8d2d0392/src/verify-probes.js +0 -327
- package/.worktrees/8d2d0392/src/version.js +0 -19
- package/.worktrees/8d2d0392/src/workflow.js +0 -600
- package/.worktrees/8d2d0392/src/workspace.js +0 -125
- package/.worktrees/8d2d0392/src/worktree-apply.js +0 -1611
- package/.worktrees/8d2d0392/src/worktree-deps.js +0 -576
- package/.worktrees/8d2d0392/src/worktree.js +0 -1838
- package/.worktrees/8d2d0392/templates/claude-instruction.md +0 -23
- package/.worktrees/8d2d0392/templates/prompts/taskcard-rules.md +0 -29
- package/.worktrees/8d2d0392/templates/prompts/testcase-design.md +0 -12
- package/.worktrees/8d2d0392/templates/prompts/verify-probes.md +0 -32
- package/.worktrees/8d2d0392/templates/workflows/archive-impact.yaml +0 -79
- package/.worktrees/8d2d0392/templates/workflows/scan-docs.yaml +0 -132
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-archive/SKILL.md +0 -87
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-auto/SKILL.md +0 -93
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-brainstorm/SKILL.md +0 -114
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-commit/SKILL.md +0 -67
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-continue/SKILL.md +0 -47
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-doctor/SKILL.md +0 -76
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-execute/SKILL.md +0 -214
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-explore/SKILL.md +0 -102
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-export/SKILL.md +0 -57
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-init/SKILL.md +0 -177
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-knowledge/SKILL.md +0 -270
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-plan/SKILL.md +0 -156
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-quick/SKILL.md +0 -116
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-resume/SKILL.md +0 -70
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-scan/SKILL.md +0 -79
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-state/SKILL.md +0 -64
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-status/SKILL.md +0 -54
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-verify/SKILL.md +0 -87
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-workspace/SKILL.md +0 -175
- package/.worktrees/c1eae35e/.gitattributes +0 -2
- package/.worktrees/c1eae35e/.husky/pre-push +0 -20
- package/.worktrees/c1eae35e/README.md +0 -203
- package/.worktrees/c1eae35e/SKILL.md +0 -91
- package/.worktrees/c1eae35e/architecture-analysis.md +0 -448
- package/.worktrees/c1eae35e/bin/sillyspec.js +0 -2
- package/.worktrees/c1eae35e/eval/README.md +0 -86
- package/.worktrees/c1eae35e/eval/eval.config.json +0 -28
- package/.worktrees/c1eae35e/eval/lib/adapters/cli.mjs +0 -63
- package/.worktrees/c1eae35e/eval/lib/adapters/dryrun.mjs +0 -27
- package/.worktrees/c1eae35e/eval/lib/config.mjs +0 -82
- package/.worktrees/c1eae35e/eval/lib/db.mjs +0 -76
- package/.worktrees/c1eae35e/eval/lib/report.mjs +0 -120
- package/.worktrees/c1eae35e/eval/lib/runner.mjs +0 -157
- package/.worktrees/c1eae35e/eval/lib/tasks.mjs +0 -73
- package/.worktrees/c1eae35e/eval/lib/util.mjs +0 -107
- package/.worktrees/c1eae35e/eval/lib/workdir.mjs +0 -30
- package/.worktrees/c1eae35e/eval/run.mjs +0 -83
- package/.worktrees/c1eae35e/eval/tasks/001-slugify/files/package.json +0 -6
- package/.worktrees/c1eae35e/eval/tasks/001-slugify/solution/src/slugify.mjs +0 -26
- package/.worktrees/c1eae35e/eval/tasks/001-slugify/task.json +0 -6
- package/.worktrees/c1eae35e/eval/tasks/001-slugify/verify.mjs +0 -28
- package/.worktrees/c1eae35e/eval/tasks/002-each-day/files/package.json +0 -6
- package/.worktrees/c1eae35e/eval/tasks/002-each-day/files/src/dates.mjs +0 -4
- package/.worktrees/c1eae35e/eval/tasks/002-each-day/solution/src/dates.mjs +0 -30
- package/.worktrees/c1eae35e/eval/tasks/002-each-day/task.json +0 -6
- package/.worktrees/c1eae35e/eval/tasks/002-each-day/verify.mjs +0 -31
- package/.worktrees/c1eae35e/eval/tasks/003-word-report/files/data/notes.txt +0 -5
- package/.worktrees/c1eae35e/eval/tasks/003-word-report/files/package.json +0 -6
- package/.worktrees/c1eae35e/eval/tasks/003-word-report/solution/bin/report.mjs +0 -36
- package/.worktrees/c1eae35e/eval/tasks/003-word-report/task.json +0 -6
- package/.worktrees/c1eae35e/eval/tasks/003-word-report/verify.mjs +0 -38
- package/.worktrees/c1eae35e/logo.jpg +0 -0
- package/.worktrees/c1eae35e/package-lock.json +0 -977
- package/.worktrees/c1eae35e/package.json +0 -41
- package/.worktrees/c1eae35e/packages/dashboard/dist/assets/index-Bq_Z2hne.js +0 -7446
- package/.worktrees/c1eae35e/packages/dashboard/dist/assets/index-O2W5RV4z.css +0 -1
- package/.worktrees/c1eae35e/packages/dashboard/dist/favicon.jpg +0 -0
- package/.worktrees/c1eae35e/packages/dashboard/dist/index.html +0 -16
- package/.worktrees/c1eae35e/packages/dashboard/dist/logo.jpg +0 -0
- package/.worktrees/c1eae35e/packages/dashboard/dist/prototype-dashboard.html +0 -836
- package/.worktrees/c1eae35e/packages/dashboard/dist/prototype-overview.html +0 -256
- package/.worktrees/c1eae35e/packages/dashboard/package.json +0 -25
- package/.worktrees/c1eae35e/packages/dashboard/server/executor.js +0 -95
- package/.worktrees/c1eae35e/packages/dashboard/server/index.js +0 -679
- package/.worktrees/c1eae35e/packages/dashboard/server/parser.js +0 -526
- package/.worktrees/c1eae35e/packages/dashboard/server/watcher.js +0 -357
- package/.worktrees/c1eae35e/src/agent-session-log.js +0 -803
- package/.worktrees/c1eae35e/src/change-list.js +0 -290
- package/.worktrees/c1eae35e/src/change-risk-profile.js +0 -339
- package/.worktrees/c1eae35e/src/check-primitives.js +0 -65
- package/.worktrees/c1eae35e/src/classify-change.js +0 -109
- package/.worktrees/c1eae35e/src/commit-suggest.js +0 -202
- package/.worktrees/c1eae35e/src/config-cat.js +0 -88
- package/.worktrees/c1eae35e/src/config-schema.js +0 -328
- package/.worktrees/c1eae35e/src/constants.js +0 -97
- package/.worktrees/c1eae35e/src/contract-matrix.js +0 -533
- package/.worktrees/c1eae35e/src/datetime.js +0 -20
- package/.worktrees/c1eae35e/src/db-engine.js +0 -55
- package/.worktrees/c1eae35e/src/db.js +0 -381
- package/.worktrees/c1eae35e/src/decision-distill.js +0 -517
- package/.worktrees/c1eae35e/src/dispatch/backends/local-agent.js +0 -155
- package/.worktrees/c1eae35e/src/dispatch/backends/sillyhub-mcp.js +0 -245
- package/.worktrees/c1eae35e/src/dispatch/probe.js +0 -246
- package/.worktrees/c1eae35e/src/dispatch/strategy.js +0 -121
- package/.worktrees/c1eae35e/src/docs-check.js +0 -825
- package/.worktrees/c1eae35e/src/docs-debt.js +0 -393
- package/.worktrees/c1eae35e/src/docs-gate.js +0 -107
- package/.worktrees/c1eae35e/src/doctor-diagnostics.js +0 -1099
- package/.worktrees/c1eae35e/src/endpoint-extractor.js +0 -409
- package/.worktrees/c1eae35e/src/foreign-declared.js +0 -155
- package/.worktrees/c1eae35e/src/fs-atomic.js +0 -73
- package/.worktrees/c1eae35e/src/git-helper.js +0 -150
- package/.worktrees/c1eae35e/src/hooks/claude-pre-tool-use.cjs +0 -130
- package/.worktrees/c1eae35e/src/hooks/worktree-guard.js +0 -892
- package/.worktrees/c1eae35e/src/index.js +0 -2854
- package/.worktrees/c1eae35e/src/init.js +0 -626
- package/.worktrees/c1eae35e/src/knowledge-match.js +0 -231
- package/.worktrees/c1eae35e/src/local-detect.js +0 -128
- package/.worktrees/c1eae35e/src/local-register.js +0 -104
- package/.worktrees/c1eae35e/src/machine-interface.js +0 -543
- package/.worktrees/c1eae35e/src/migrate.js +0 -127
- package/.worktrees/c1eae35e/src/module-impact.js +0 -166
- package/.worktrees/c1eae35e/src/module-resolve.js +0 -222
- package/.worktrees/c1eae35e/src/modules.js +0 -580
- package/.worktrees/c1eae35e/src/plan-adopt-waves.js +0 -126
- package/.worktrees/c1eae35e/src/progress/change-registry.js +0 -336
- package/.worktrees/c1eae35e/src/progress/consistency-doctor.js +0 -355
- package/.worktrees/c1eae35e/src/progress/shared.js +0 -36
- package/.worktrees/c1eae35e/src/progress/stage-machine.js +0 -594
- package/.worktrees/c1eae35e/src/progress/step-store.js +0 -265
- package/.worktrees/c1eae35e/src/progress.js +0 -1304
- package/.worktrees/c1eae35e/src/quick-recommend.js +0 -115
- package/.worktrees/c1eae35e/src/quicklog.js +0 -883
- package/.worktrees/c1eae35e/src/review-tier.js +0 -77
- package/.worktrees/c1eae35e/src/run/command.js +0 -1641
- package/.worktrees/c1eae35e/src/run/complete-handlers.js +0 -1552
- package/.worktrees/c1eae35e/src/run/complete.js +0 -1259
- package/.worktrees/c1eae35e/src/run/concurrent-detect.js +0 -156
- package/.worktrees/c1eae35e/src/run/gates.js +0 -1111
- package/.worktrees/c1eae35e/src/run/multi-repo-context.js +0 -208
- package/.worktrees/c1eae35e/src/run/next.js +0 -128
- package/.worktrees/c1eae35e/src/run/prompt.js +0 -843
- package/.worktrees/c1eae35e/src/run/quick-audit.js +0 -186
- package/.worktrees/c1eae35e/src/run/scan-profile.js +0 -269
- package/.worktrees/c1eae35e/src/run/shared.js +0 -1562
- package/.worktrees/c1eae35e/src/run/stage.js +0 -587
- package/.worktrees/c1eae35e/src/run.js +0 -23
- package/.worktrees/c1eae35e/src/scan-diff.js +0 -388
- package/.worktrees/c1eae35e/src/scan-postcheck.js +0 -524
- package/.worktrees/c1eae35e/src/scan-staleness.js +0 -95
- package/.worktrees/c1eae35e/src/setup.js +0 -414
- package/.worktrees/c1eae35e/src/sillyhub-mcp/client.js +0 -597
- package/.worktrees/c1eae35e/src/sillyhub-mcp/config.js +0 -62
- package/.worktrees/c1eae35e/src/spec-dir-typo.js +0 -50
- package/.worktrees/c1eae35e/src/spec-sync.js +0 -358
- package/.worktrees/c1eae35e/src/stage-contract-engine.js +0 -171
- package/.worktrees/c1eae35e/src/stage-contract-spec.js +0 -551
- package/.worktrees/c1eae35e/src/stage-contract.js +0 -948
- package/.worktrees/c1eae35e/src/stage-review.js +0 -597
- package/.worktrees/c1eae35e/src/stages/archive.js +0 -199
- package/.worktrees/c1eae35e/src/stages/brainstorm-auto.js +0 -285
- package/.worktrees/c1eae35e/src/stages/brainstorm.js +0 -624
- package/.worktrees/c1eae35e/src/stages/cmd-existence.js +0 -145
- package/.worktrees/c1eae35e/src/stages/doctor.js +0 -540
- package/.worktrees/c1eae35e/src/stages/execute.js +0 -1277
- package/.worktrees/c1eae35e/src/stages/explore.js +0 -43
- package/.worktrees/c1eae35e/src/stages/index.js +0 -29
- package/.worktrees/c1eae35e/src/stages/knowledge.js +0 -514
- package/.worktrees/c1eae35e/src/stages/plan-postcheck.js +0 -1398
- package/.worktrees/c1eae35e/src/stages/plan.js +0 -655
- package/.worktrees/c1eae35e/src/stages/quick.js +0 -167
- package/.worktrees/c1eae35e/src/stages/scan.js +0 -608
- package/.worktrees/c1eae35e/src/stages/status.js +0 -64
- package/.worktrees/c1eae35e/src/stages/verify.js +0 -246
- package/.worktrees/c1eae35e/src/sync.js +0 -1470
- package/.worktrees/c1eae35e/src/task-review.js +0 -1498
- package/.worktrees/c1eae35e/src/taskcard-placeholders.js +0 -21
- package/.worktrees/c1eae35e/src/taskcard.js +0 -250
- package/.worktrees/c1eae35e/src/verify-postcheck.js +0 -1718
- package/.worktrees/c1eae35e/src/verify-probes.js +0 -327
- package/.worktrees/c1eae35e/src/version.js +0 -19
- package/.worktrees/c1eae35e/src/workflow.js +0 -600
- package/.worktrees/c1eae35e/src/workspace.js +0 -125
- package/.worktrees/c1eae35e/src/worktree-apply.js +0 -1611
- package/.worktrees/c1eae35e/src/worktree-deps.js +0 -668
- package/.worktrees/c1eae35e/src/worktree.js +0 -1849
- package/.worktrees/c1eae35e/templates/claude-instruction.md +0 -23
- package/.worktrees/c1eae35e/templates/prompts/taskcard-rules.md +0 -29
- package/.worktrees/c1eae35e/templates/prompts/testcase-design.md +0 -12
- package/.worktrees/c1eae35e/templates/prompts/verify-probes.md +0 -32
- package/.worktrees/c1eae35e/templates/workflows/archive-impact.yaml +0 -79
- package/.worktrees/c1eae35e/templates/workflows/scan-docs.yaml +0 -132
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-archive/SKILL.md +0 -87
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-auto/SKILL.md +0 -93
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-brainstorm/SKILL.md +0 -114
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-commit/SKILL.md +0 -67
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-continue/SKILL.md +0 -47
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-doctor/SKILL.md +0 -76
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-execute/SKILL.md +0 -214
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-explore/SKILL.md +0 -102
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-export/SKILL.md +0 -57
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-init/SKILL.md +0 -177
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-knowledge/SKILL.md +0 -270
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-plan/SKILL.md +0 -156
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-propose/SKILL.md +0 -87
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-quick/SKILL.md +0 -116
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-resume/SKILL.md +0 -70
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-scan/SKILL.md +0 -79
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-state/SKILL.md +0 -64
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-status/SKILL.md +0 -54
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-verify/SKILL.md +0 -87
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-workspace/SKILL.md +0 -175
- package/.worktrees/dafc71ad/.gitattributes +0 -2
- package/.worktrees/dafc71ad/.husky/pre-push +0 -20
- package/.worktrees/dafc71ad/README.md +0 -203
- package/.worktrees/dafc71ad/SKILL.md +0 -91
- package/.worktrees/dafc71ad/analysis.md +0 -366
- package/.worktrees/dafc71ad/architecture-analysis.md +0 -448
- package/.worktrees/dafc71ad/bin/sillyspec.js +0 -2
- package/.worktrees/dafc71ad/eval/README.md +0 -86
- package/.worktrees/dafc71ad/eval/eval.config.json +0 -28
- package/.worktrees/dafc71ad/eval/lib/adapters/cli.mjs +0 -63
- package/.worktrees/dafc71ad/eval/lib/adapters/dryrun.mjs +0 -27
- package/.worktrees/dafc71ad/eval/lib/config.mjs +0 -82
- package/.worktrees/dafc71ad/eval/lib/db.mjs +0 -76
- package/.worktrees/dafc71ad/eval/lib/report.mjs +0 -120
- package/.worktrees/dafc71ad/eval/lib/runner.mjs +0 -157
- package/.worktrees/dafc71ad/eval/lib/tasks.mjs +0 -73
- package/.worktrees/dafc71ad/eval/lib/util.mjs +0 -107
- package/.worktrees/dafc71ad/eval/lib/workdir.mjs +0 -30
- package/.worktrees/dafc71ad/eval/run.mjs +0 -83
- package/.worktrees/dafc71ad/eval/tasks/001-slugify/files/package.json +0 -6
- package/.worktrees/dafc71ad/eval/tasks/001-slugify/solution/src/slugify.mjs +0 -26
- package/.worktrees/dafc71ad/eval/tasks/001-slugify/task.json +0 -6
- package/.worktrees/dafc71ad/eval/tasks/001-slugify/verify.mjs +0 -28
- package/.worktrees/dafc71ad/eval/tasks/002-each-day/files/package.json +0 -6
- package/.worktrees/dafc71ad/eval/tasks/002-each-day/files/src/dates.mjs +0 -4
- package/.worktrees/dafc71ad/eval/tasks/002-each-day/solution/src/dates.mjs +0 -30
- package/.worktrees/dafc71ad/eval/tasks/002-each-day/task.json +0 -6
- package/.worktrees/dafc71ad/eval/tasks/002-each-day/verify.mjs +0 -31
- package/.worktrees/dafc71ad/eval/tasks/003-word-report/files/data/notes.txt +0 -5
- package/.worktrees/dafc71ad/eval/tasks/003-word-report/files/package.json +0 -6
- package/.worktrees/dafc71ad/eval/tasks/003-word-report/solution/bin/report.mjs +0 -36
- package/.worktrees/dafc71ad/eval/tasks/003-word-report/task.json +0 -6
- package/.worktrees/dafc71ad/eval/tasks/003-word-report/verify.mjs +0 -38
- package/.worktrees/dafc71ad/logo.jpg +0 -0
- package/.worktrees/dafc71ad/package-lock.json +0 -977
- package/.worktrees/dafc71ad/package.json +0 -41
- package/.worktrees/dafc71ad/packages/dashboard/dist/assets/index-Bq_Z2hne.js +0 -7446
- package/.worktrees/dafc71ad/packages/dashboard/dist/assets/index-O2W5RV4z.css +0 -1
- package/.worktrees/dafc71ad/packages/dashboard/dist/favicon.jpg +0 -0
- package/.worktrees/dafc71ad/packages/dashboard/dist/index.html +0 -16
- package/.worktrees/dafc71ad/packages/dashboard/dist/logo.jpg +0 -0
- package/.worktrees/dafc71ad/packages/dashboard/dist/prototype-dashboard.html +0 -836
- package/.worktrees/dafc71ad/packages/dashboard/dist/prototype-overview.html +0 -256
- package/.worktrees/dafc71ad/packages/dashboard/package.json +0 -25
- package/.worktrees/dafc71ad/packages/dashboard/server/executor.js +0 -95
- package/.worktrees/dafc71ad/packages/dashboard/server/index.js +0 -679
- package/.worktrees/dafc71ad/packages/dashboard/server/parser.js +0 -526
- package/.worktrees/dafc71ad/packages/dashboard/server/watcher.js +0 -357
- package/.worktrees/dafc71ad/src/agent-session-log.js +0 -803
- package/.worktrees/dafc71ad/src/change-list.js +0 -290
- package/.worktrees/dafc71ad/src/change-risk-profile.js +0 -339
- package/.worktrees/dafc71ad/src/check-primitives.js +0 -65
- package/.worktrees/dafc71ad/src/classify-change.js +0 -109
- package/.worktrees/dafc71ad/src/commit-suggest.js +0 -202
- package/.worktrees/dafc71ad/src/config-cat.js +0 -88
- package/.worktrees/dafc71ad/src/config-schema.js +0 -328
- package/.worktrees/dafc71ad/src/constants.js +0 -97
- package/.worktrees/dafc71ad/src/contract-matrix.js +0 -533
- package/.worktrees/dafc71ad/src/datetime.js +0 -20
- package/.worktrees/dafc71ad/src/db-engine.js +0 -55
- package/.worktrees/dafc71ad/src/db.js +0 -381
- package/.worktrees/dafc71ad/src/decision-distill.js +0 -517
- package/.worktrees/dafc71ad/src/dispatch/backends/local-agent.js +0 -155
- package/.worktrees/dafc71ad/src/dispatch/backends/sillyhub-mcp.js +0 -245
- package/.worktrees/dafc71ad/src/dispatch/probe.js +0 -246
- package/.worktrees/dafc71ad/src/dispatch/strategy.js +0 -121
- package/.worktrees/dafc71ad/src/docs-check.js +0 -825
- package/.worktrees/dafc71ad/src/docs-debt.js +0 -393
- package/.worktrees/dafc71ad/src/docs-gate.js +0 -107
- package/.worktrees/dafc71ad/src/doctor-diagnostics.js +0 -1099
- package/.worktrees/dafc71ad/src/endpoint-extractor.js +0 -409
- package/.worktrees/dafc71ad/src/foreign-declared.js +0 -155
- package/.worktrees/dafc71ad/src/fs-atomic.js +0 -73
- package/.worktrees/dafc71ad/src/git-helper.js +0 -150
- package/.worktrees/dafc71ad/src/hooks/claude-pre-tool-use.cjs +0 -130
- package/.worktrees/dafc71ad/src/hooks/worktree-guard.js +0 -892
- package/.worktrees/dafc71ad/src/index.js +0 -2854
- package/.worktrees/dafc71ad/src/init.js +0 -626
- package/.worktrees/dafc71ad/src/knowledge-match.js +0 -231
- package/.worktrees/dafc71ad/src/local-detect.js +0 -128
- package/.worktrees/dafc71ad/src/local-register.js +0 -104
- package/.worktrees/dafc71ad/src/machine-interface.js +0 -543
- package/.worktrees/dafc71ad/src/migrate.js +0 -127
- package/.worktrees/dafc71ad/src/module-impact.js +0 -166
- package/.worktrees/dafc71ad/src/module-resolve.js +0 -222
- package/.worktrees/dafc71ad/src/modules.js +0 -580
- package/.worktrees/dafc71ad/src/plan-adopt-waves.js +0 -126
- package/.worktrees/dafc71ad/src/progress/change-registry.js +0 -336
- package/.worktrees/dafc71ad/src/progress/consistency-doctor.js +0 -355
- package/.worktrees/dafc71ad/src/progress/shared.js +0 -36
- package/.worktrees/dafc71ad/src/progress/stage-machine.js +0 -594
- package/.worktrees/dafc71ad/src/progress/step-store.js +0 -265
- package/.worktrees/dafc71ad/src/progress.js +0 -1304
- package/.worktrees/dafc71ad/src/quick-recommend.js +0 -115
- package/.worktrees/dafc71ad/src/quicklog.js +0 -883
- package/.worktrees/dafc71ad/src/review-tier.js +0 -77
- package/.worktrees/dafc71ad/src/run/command.js +0 -1641
- package/.worktrees/dafc71ad/src/run/complete-handlers.js +0 -1552
- package/.worktrees/dafc71ad/src/run/complete.js +0 -1259
- package/.worktrees/dafc71ad/src/run/concurrent-detect.js +0 -156
- package/.worktrees/dafc71ad/src/run/gates.js +0 -1111
- package/.worktrees/dafc71ad/src/run/multi-repo-context.js +0 -208
- package/.worktrees/dafc71ad/src/run/next.js +0 -128
- package/.worktrees/dafc71ad/src/run/prompt.js +0 -843
- package/.worktrees/dafc71ad/src/run/quick-audit.js +0 -186
- package/.worktrees/dafc71ad/src/run/scan-profile.js +0 -269
- package/.worktrees/dafc71ad/src/run/shared.js +0 -1562
- package/.worktrees/dafc71ad/src/run/stage.js +0 -587
- package/.worktrees/dafc71ad/src/run.js +0 -23
- package/.worktrees/dafc71ad/src/scan-diff.js +0 -388
- package/.worktrees/dafc71ad/src/scan-postcheck.js +0 -524
- package/.worktrees/dafc71ad/src/scan-staleness.js +0 -95
- package/.worktrees/dafc71ad/src/setup.js +0 -414
- package/.worktrees/dafc71ad/src/sillyhub-mcp/client.js +0 -597
- package/.worktrees/dafc71ad/src/sillyhub-mcp/config.js +0 -62
- package/.worktrees/dafc71ad/src/spec-dir-typo.js +0 -50
- package/.worktrees/dafc71ad/src/spec-sync.js +0 -358
- package/.worktrees/dafc71ad/src/stage-contract-engine.js +0 -171
- package/.worktrees/dafc71ad/src/stage-contract-spec.js +0 -551
- package/.worktrees/dafc71ad/src/stage-contract.js +0 -948
- package/.worktrees/dafc71ad/src/stage-review.js +0 -597
- package/.worktrees/dafc71ad/src/stages/archive.js +0 -199
- package/.worktrees/dafc71ad/src/stages/brainstorm-auto.js +0 -285
- package/.worktrees/dafc71ad/src/stages/brainstorm.js +0 -624
- package/.worktrees/dafc71ad/src/stages/cmd-existence.js +0 -145
- package/.worktrees/dafc71ad/src/stages/doctor.js +0 -540
- package/.worktrees/dafc71ad/src/stages/execute.js +0 -1277
- package/.worktrees/dafc71ad/src/stages/explore.js +0 -43
- package/.worktrees/dafc71ad/src/stages/index.js +0 -29
- package/.worktrees/dafc71ad/src/stages/knowledge.js +0 -514
- package/.worktrees/dafc71ad/src/stages/plan-postcheck.js +0 -1398
- package/.worktrees/dafc71ad/src/stages/plan.js +0 -655
- package/.worktrees/dafc71ad/src/stages/quick.js +0 -167
- package/.worktrees/dafc71ad/src/stages/scan.js +0 -608
- package/.worktrees/dafc71ad/src/stages/status.js +0 -64
- package/.worktrees/dafc71ad/src/stages/verify.js +0 -246
- package/.worktrees/dafc71ad/src/sync.js +0 -1470
- package/.worktrees/dafc71ad/src/task-review.js +0 -1498
- package/.worktrees/dafc71ad/src/taskcard-placeholders.js +0 -21
- package/.worktrees/dafc71ad/src/taskcard.js +0 -250
- package/.worktrees/dafc71ad/src/verify-postcheck.js +0 -1718
- package/.worktrees/dafc71ad/src/verify-probes.js +0 -327
- package/.worktrees/dafc71ad/src/version.js +0 -19
- package/.worktrees/dafc71ad/src/workflow.js +0 -600
- package/.worktrees/dafc71ad/src/workspace.js +0 -125
- package/.worktrees/dafc71ad/src/worktree-apply.js +0 -1611
- package/.worktrees/dafc71ad/src/worktree-deps.js +0 -668
- package/.worktrees/dafc71ad/src/worktree.js +0 -1849
- package/.worktrees/dafc71ad/templates/claude-instruction.md +0 -23
- package/.worktrees/dafc71ad/templates/prompts/taskcard-rules.md +0 -29
- package/.worktrees/dafc71ad/templates/prompts/testcase-design.md +0 -12
- package/.worktrees/dafc71ad/templates/prompts/verify-probes.md +0 -32
- package/.worktrees/dafc71ad/templates/workflows/archive-impact.yaml +0 -79
- package/.worktrees/dafc71ad/templates/workflows/scan-docs.yaml +0 -132
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-archive/SKILL.md +0 -87
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-auto/SKILL.md +0 -93
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-brainstorm/SKILL.md +0 -114
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-commit/SKILL.md +0 -67
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-continue/SKILL.md +0 -47
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-doctor/SKILL.md +0 -76
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-execute/SKILL.md +0 -214
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-explore/SKILL.md +0 -102
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-export/SKILL.md +0 -57
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-init/SKILL.md +0 -177
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-knowledge/SKILL.md +0 -270
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-plan/SKILL.md +0 -156
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-propose/SKILL.md +0 -87
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-quick/SKILL.md +0 -116
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-resume/SKILL.md +0 -70
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-scan/SKILL.md +0 -79
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-state/SKILL.md +0 -64
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-status/SKILL.md +0 -54
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-verify/SKILL.md +0 -87
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-workspace/SKILL.md +0 -175
- package/.worktrees/e58fcc4c/.gitattributes +0 -2
- package/.worktrees/e58fcc4c/.husky/pre-push +0 -20
- package/.worktrees/e58fcc4c/README.md +0 -203
- package/.worktrees/e58fcc4c/SKILL.md +0 -91
- package/.worktrees/e58fcc4c/architecture-analysis.md +0 -503
- package/.worktrees/e58fcc4c/bin/sillyspec.js +0 -2
- package/.worktrees/e58fcc4c/eval/README.md +0 -86
- package/.worktrees/e58fcc4c/eval/eval.config.json +0 -28
- package/.worktrees/e58fcc4c/eval/lib/adapters/cli.mjs +0 -63
- package/.worktrees/e58fcc4c/eval/lib/adapters/dryrun.mjs +0 -27
- package/.worktrees/e58fcc4c/eval/lib/config.mjs +0 -82
- package/.worktrees/e58fcc4c/eval/lib/db.mjs +0 -76
- package/.worktrees/e58fcc4c/eval/lib/report.mjs +0 -120
- package/.worktrees/e58fcc4c/eval/lib/runner.mjs +0 -157
- package/.worktrees/e58fcc4c/eval/lib/tasks.mjs +0 -73
- package/.worktrees/e58fcc4c/eval/lib/util.mjs +0 -107
- package/.worktrees/e58fcc4c/eval/lib/workdir.mjs +0 -30
- package/.worktrees/e58fcc4c/eval/run.mjs +0 -83
- package/.worktrees/e58fcc4c/eval/tasks/001-slugify/files/package.json +0 -6
- package/.worktrees/e58fcc4c/eval/tasks/001-slugify/solution/src/slugify.mjs +0 -26
- package/.worktrees/e58fcc4c/eval/tasks/001-slugify/task.json +0 -6
- package/.worktrees/e58fcc4c/eval/tasks/001-slugify/verify.mjs +0 -28
- package/.worktrees/e58fcc4c/eval/tasks/002-each-day/files/package.json +0 -6
- package/.worktrees/e58fcc4c/eval/tasks/002-each-day/files/src/dates.mjs +0 -4
- package/.worktrees/e58fcc4c/eval/tasks/002-each-day/solution/src/dates.mjs +0 -30
- package/.worktrees/e58fcc4c/eval/tasks/002-each-day/task.json +0 -6
- package/.worktrees/e58fcc4c/eval/tasks/002-each-day/verify.mjs +0 -31
- package/.worktrees/e58fcc4c/eval/tasks/003-word-report/files/data/notes.txt +0 -5
- package/.worktrees/e58fcc4c/eval/tasks/003-word-report/files/package.json +0 -6
- package/.worktrees/e58fcc4c/eval/tasks/003-word-report/solution/bin/report.mjs +0 -36
- package/.worktrees/e58fcc4c/eval/tasks/003-word-report/task.json +0 -6
- package/.worktrees/e58fcc4c/eval/tasks/003-word-report/verify.mjs +0 -38
- package/.worktrees/e58fcc4c/logo.jpg +0 -0
- package/.worktrees/e58fcc4c/package-lock.json +0 -977
- package/.worktrees/e58fcc4c/package.json +0 -41
- package/.worktrees/e58fcc4c/packages/dashboard/dist/assets/index-Bq_Z2hne.js +0 -7446
- package/.worktrees/e58fcc4c/packages/dashboard/dist/assets/index-O2W5RV4z.css +0 -1
- package/.worktrees/e58fcc4c/packages/dashboard/dist/favicon.jpg +0 -0
- package/.worktrees/e58fcc4c/packages/dashboard/dist/index.html +0 -16
- package/.worktrees/e58fcc4c/packages/dashboard/dist/logo.jpg +0 -0
- package/.worktrees/e58fcc4c/packages/dashboard/dist/prototype-dashboard.html +0 -836
- package/.worktrees/e58fcc4c/packages/dashboard/dist/prototype-overview.html +0 -256
- package/.worktrees/e58fcc4c/packages/dashboard/package.json +0 -25
- package/.worktrees/e58fcc4c/packages/dashboard/server/executor.js +0 -95
- package/.worktrees/e58fcc4c/packages/dashboard/server/index.js +0 -679
- package/.worktrees/e58fcc4c/packages/dashboard/server/parser.js +0 -526
- package/.worktrees/e58fcc4c/packages/dashboard/server/watcher.js +0 -357
- package/.worktrees/e58fcc4c/src/agent-session-log.js +0 -803
- package/.worktrees/e58fcc4c/src/change-list.js +0 -290
- package/.worktrees/e58fcc4c/src/change-risk-profile.js +0 -339
- package/.worktrees/e58fcc4c/src/check-primitives.js +0 -65
- package/.worktrees/e58fcc4c/src/classify-change.js +0 -109
- package/.worktrees/e58fcc4c/src/commit-suggest.js +0 -202
- package/.worktrees/e58fcc4c/src/config-cat.js +0 -88
- package/.worktrees/e58fcc4c/src/config-schema.js +0 -328
- package/.worktrees/e58fcc4c/src/constants.js +0 -97
- package/.worktrees/e58fcc4c/src/contract-matrix.js +0 -533
- package/.worktrees/e58fcc4c/src/datetime.js +0 -20
- package/.worktrees/e58fcc4c/src/db-engine.js +0 -55
- package/.worktrees/e58fcc4c/src/db.js +0 -381
- package/.worktrees/e58fcc4c/src/decision-distill.js +0 -517
- package/.worktrees/e58fcc4c/src/dispatch/backends/local-agent.js +0 -155
- package/.worktrees/e58fcc4c/src/dispatch/backends/sillyhub-mcp.js +0 -245
- package/.worktrees/e58fcc4c/src/dispatch/probe.js +0 -246
- package/.worktrees/e58fcc4c/src/dispatch/strategy.js +0 -121
- package/.worktrees/e58fcc4c/src/docs-check.js +0 -825
- package/.worktrees/e58fcc4c/src/docs-debt.js +0 -393
- package/.worktrees/e58fcc4c/src/docs-gate.js +0 -107
- package/.worktrees/e58fcc4c/src/doctor-diagnostics.js +0 -1099
- package/.worktrees/e58fcc4c/src/endpoint-extractor.js +0 -409
- package/.worktrees/e58fcc4c/src/foreign-declared.js +0 -155
- package/.worktrees/e58fcc4c/src/fs-atomic.js +0 -73
- package/.worktrees/e58fcc4c/src/git-helper.js +0 -150
- package/.worktrees/e58fcc4c/src/hooks/claude-pre-tool-use.cjs +0 -130
- package/.worktrees/e58fcc4c/src/hooks/worktree-guard.js +0 -892
- package/.worktrees/e58fcc4c/src/index.js +0 -2854
- package/.worktrees/e58fcc4c/src/init.js +0 -626
- package/.worktrees/e58fcc4c/src/knowledge-match.js +0 -231
- package/.worktrees/e58fcc4c/src/local-detect.js +0 -128
- package/.worktrees/e58fcc4c/src/local-register.js +0 -104
- package/.worktrees/e58fcc4c/src/machine-interface.js +0 -543
- package/.worktrees/e58fcc4c/src/migrate.js +0 -127
- package/.worktrees/e58fcc4c/src/module-impact.js +0 -166
- package/.worktrees/e58fcc4c/src/module-resolve.js +0 -222
- package/.worktrees/e58fcc4c/src/modules.js +0 -580
- package/.worktrees/e58fcc4c/src/plan-adopt-waves.js +0 -126
- package/.worktrees/e58fcc4c/src/progress/change-registry.js +0 -336
- package/.worktrees/e58fcc4c/src/progress/consistency-doctor.js +0 -355
- package/.worktrees/e58fcc4c/src/progress/shared.js +0 -36
- package/.worktrees/e58fcc4c/src/progress/stage-machine.js +0 -594
- package/.worktrees/e58fcc4c/src/progress/step-store.js +0 -265
- package/.worktrees/e58fcc4c/src/progress.js +0 -1304
- package/.worktrees/e58fcc4c/src/quick-recommend.js +0 -115
- package/.worktrees/e58fcc4c/src/quicklog.js +0 -883
- package/.worktrees/e58fcc4c/src/review-tier.js +0 -77
- package/.worktrees/e58fcc4c/src/run/command.js +0 -1641
- package/.worktrees/e58fcc4c/src/run/complete-handlers.js +0 -1552
- package/.worktrees/e58fcc4c/src/run/complete.js +0 -1259
- package/.worktrees/e58fcc4c/src/run/concurrent-detect.js +0 -156
- package/.worktrees/e58fcc4c/src/run/gates.js +0 -1111
- package/.worktrees/e58fcc4c/src/run/multi-repo-context.js +0 -208
- package/.worktrees/e58fcc4c/src/run/next.js +0 -128
- package/.worktrees/e58fcc4c/src/run/prompt.js +0 -843
- package/.worktrees/e58fcc4c/src/run/quick-audit.js +0 -186
- package/.worktrees/e58fcc4c/src/run/scan-profile.js +0 -269
- package/.worktrees/e58fcc4c/src/run/shared.js +0 -1562
- package/.worktrees/e58fcc4c/src/run/stage.js +0 -587
- package/.worktrees/e58fcc4c/src/run.js +0 -23
- package/.worktrees/e58fcc4c/src/scan-diff.js +0 -388
- package/.worktrees/e58fcc4c/src/scan-postcheck.js +0 -524
- package/.worktrees/e58fcc4c/src/scan-staleness.js +0 -95
- package/.worktrees/e58fcc4c/src/setup.js +0 -414
- package/.worktrees/e58fcc4c/src/sillyhub-mcp/client.js +0 -597
- package/.worktrees/e58fcc4c/src/sillyhub-mcp/config.js +0 -62
- package/.worktrees/e58fcc4c/src/spec-dir-typo.js +0 -50
- package/.worktrees/e58fcc4c/src/spec-sync.js +0 -358
- package/.worktrees/e58fcc4c/src/stage-contract-engine.js +0 -171
- package/.worktrees/e58fcc4c/src/stage-contract-spec.js +0 -551
- package/.worktrees/e58fcc4c/src/stage-contract.js +0 -948
- package/.worktrees/e58fcc4c/src/stage-review.js +0 -597
- package/.worktrees/e58fcc4c/src/stages/archive.js +0 -199
- package/.worktrees/e58fcc4c/src/stages/brainstorm-auto.js +0 -285
- package/.worktrees/e58fcc4c/src/stages/brainstorm.js +0 -624
- package/.worktrees/e58fcc4c/src/stages/cmd-existence.js +0 -145
- package/.worktrees/e58fcc4c/src/stages/doctor.js +0 -540
- package/.worktrees/e58fcc4c/src/stages/execute.js +0 -1277
- package/.worktrees/e58fcc4c/src/stages/explore.js +0 -43
- package/.worktrees/e58fcc4c/src/stages/index.js +0 -29
- package/.worktrees/e58fcc4c/src/stages/knowledge.js +0 -514
- package/.worktrees/e58fcc4c/src/stages/plan-postcheck.js +0 -1398
- package/.worktrees/e58fcc4c/src/stages/plan.js +0 -655
- package/.worktrees/e58fcc4c/src/stages/quick.js +0 -167
- package/.worktrees/e58fcc4c/src/stages/scan.js +0 -608
- package/.worktrees/e58fcc4c/src/stages/status.js +0 -64
- package/.worktrees/e58fcc4c/src/stages/verify.js +0 -246
- package/.worktrees/e58fcc4c/src/sync.js +0 -1470
- package/.worktrees/e58fcc4c/src/task-review.js +0 -1498
- package/.worktrees/e58fcc4c/src/taskcard-placeholders.js +0 -21
- package/.worktrees/e58fcc4c/src/taskcard.js +0 -250
- package/.worktrees/e58fcc4c/src/verify-postcheck.js +0 -1718
- package/.worktrees/e58fcc4c/src/verify-probes.js +0 -327
- package/.worktrees/e58fcc4c/src/version.js +0 -19
- package/.worktrees/e58fcc4c/src/workflow.js +0 -600
- package/.worktrees/e58fcc4c/src/workspace.js +0 -125
- package/.worktrees/e58fcc4c/src/worktree-apply.js +0 -1611
- package/.worktrees/e58fcc4c/src/worktree-deps.js +0 -668
- package/.worktrees/e58fcc4c/src/worktree.js +0 -1849
- package/.worktrees/e58fcc4c/templates/claude-instruction.md +0 -23
- package/.worktrees/e58fcc4c/templates/prompts/taskcard-rules.md +0 -29
- package/.worktrees/e58fcc4c/templates/prompts/testcase-design.md +0 -12
- package/.worktrees/e58fcc4c/templates/prompts/verify-probes.md +0 -32
- package/.worktrees/e58fcc4c/templates/workflows/archive-impact.yaml +0 -79
- package/.worktrees/e58fcc4c/templates/workflows/scan-docs.yaml +0 -132
|
@@ -1,1498 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SillySpec Task Review Gate — execute 阶段任务级评审校验
|
|
3
|
-
*
|
|
4
|
-
* execute 阶段每个 task 完成后,controller 必须写入 review.json。
|
|
5
|
-
* execute --done 时 CLI 硬校验:缺失 review 或 verdict 不通过则阻断。
|
|
6
|
-
*
|
|
7
|
-
* 目录结构:
|
|
8
|
-
* .sillyspec/.runtime/execute-runs/<runId>/tasks/<taskId>/review.json
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { existsSync, readFileSync, mkdirSync, writeFileSync, readdirSync, statSync } from 'fs'
|
|
12
|
-
import { join, resolve } from 'path'
|
|
13
|
-
import { git, unquoteGitPath } from './git-helper.js'
|
|
14
|
-
import { pathMatches } from './change-list.js'
|
|
15
|
-
import { parseAllowedPaths, parseRepo, parseBaseCommit, parseHeadCommit } from './stages/plan-postcheck.js'
|
|
16
|
-
import { resolveVerifyChangedFiles } from './verify-postcheck.js'
|
|
17
|
-
import { WorktreeManager } from './worktree.js'
|
|
18
|
-
import { resolveRuntimeRoot } from './run/shared.js'
|
|
19
|
-
|
|
20
|
-
// ── review.json schema version ──
|
|
21
|
-
//
|
|
22
|
-
// design §7.4 / R-07:task-review 的 review.json schemaVersion 1→2(新增可选 repo 字段),
|
|
23
|
-
// 旧 v1(无 repo)向后兼容视 'main',不阻断既有 change archive。
|
|
24
|
-
//
|
|
25
|
-
// 关于常量与"1→2":REVIEW_SCHEMA_VERSION 常量被 stage-review.js(文档型阶段评审)共享——
|
|
26
|
-
// stage-review.test.mjs:358 + register.test.mjs:40 断言其值 === 1,且 stage-review.js 不在本次
|
|
27
|
-
// 变更的 allowed_paths 内。两个 schema(task code-review / stage doc-review)逻辑独立,但历史共享
|
|
28
|
-
// 同一常量。本期保持 REVIEW_SCHEMA_VERSION=1 作 stage-review 写侧默认值(不破坏 stage-review),
|
|
29
|
-
// 同时用 REVIEW_SCHEMA_VERSIONS_ACCEPTED=[1,2] 表达"读侧接受两版"——validateReviewSchema 兼容 v1/v2,
|
|
30
|
-
// 跨仓 task 写 review.json 可用 v2 带 repo 字段,单仓/旧 change 仍用 v1。后续可拆分 stage-review 专用
|
|
31
|
-
// 常量,本期遵循 allowed_paths 约束不扩散到 stage-review.js。
|
|
32
|
-
export const REVIEW_SCHEMA_VERSION = 1
|
|
33
|
-
const REVIEW_SCHEMA_VERSIONS_ACCEPTED = [1, 2]
|
|
34
|
-
// repo 缺省值(review.repo / task 卡 repo 缺省时统一按 'main' 处理)。design §7.2 / §7.4。
|
|
35
|
-
const DEFAULT_REPO_KEY = 'main'
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* 规范化 review.repo / task 卡 repo 字段为有效 repoKey。
|
|
39
|
-
* 缺省 / 非字符串 / 空串 → 'main'(向后兼容旧 v1 review + 无 repo 声明的单仓 task)。
|
|
40
|
-
* @param {any} repo
|
|
41
|
-
* @returns {string}
|
|
42
|
-
*/
|
|
43
|
-
export function normalizeRepoKey(repo) {
|
|
44
|
-
if (typeof repo !== 'string' || repo.trim() === '') return DEFAULT_REPO_KEY
|
|
45
|
-
return repo.trim()
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// ── 合法 verdict 枚举 ──
|
|
49
|
-
export const VALID_VERDICTS = ['pass', 'fail', 'cannot_verify']
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* 解析 plan.md 中的 task 列表
|
|
53
|
-
* @param {string} planContent - plan.md 文件内容
|
|
54
|
-
* @returns {string[]} task id 列表,如 ['task-01', 'task-02']
|
|
55
|
-
*/
|
|
56
|
-
function parseTaskIdsFromPlan(planContent) {
|
|
57
|
-
if (!planContent) return []
|
|
58
|
-
const ids = new Set()
|
|
59
|
-
const re = /^\s*[-*]\s*\[[ x]\]\s*task-(\d+)/gim
|
|
60
|
-
for (const m of planContent.matchAll(re)) {
|
|
61
|
-
ids.add(`task-${m[1].padStart(2, '0')}`)
|
|
62
|
-
}
|
|
63
|
-
return [...ids].sort()
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* 统计 plan.md/tasks.md 中 task-NN checkbox 的勾选情况(降级口径)。
|
|
68
|
-
* 与 progress.js readPlanCheckboxStatus 同语义,但纯函数、无类依赖,供 summarizeTaskCompletion 降级复用。
|
|
69
|
-
*/
|
|
70
|
-
function countPlanCheckboxes(planContent) {
|
|
71
|
-
const re = /^\s*[-*]\s+\[([ xX])\]\s+task-\d+/gm
|
|
72
|
-
let total = 0
|
|
73
|
-
let checked = 0
|
|
74
|
-
let m
|
|
75
|
-
while ((m = re.exec(planContent)) !== null) {
|
|
76
|
-
total++
|
|
77
|
-
if (m[1] === 'x' || m[1] === 'X') checked++
|
|
78
|
-
}
|
|
79
|
-
return { total, checked }
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* 汇总变更的任务完成度 —— archive Step1「任务完成度检查」的客观真相源。
|
|
84
|
-
*
|
|
85
|
-
* 以 execute 阶段产出的 review.json verdict 为准(task-NN 的 specVerdict + qualityVerdict 均 ≠ fail
|
|
86
|
-
* 视为完成),而非 plan.md checkbox。原因:plan.md checkbox 依赖 autoCheckPlanFromReviews 回填,
|
|
87
|
-
* 而 runId marker / review.json 缺失时回填静默 no-op,checkbox 会停在未勾态,导致完成度失真
|
|
88
|
-
* (archive 误判「全未完成」)。review.json 是 task 级客观 verdict,不受回填断裂影响。
|
|
89
|
-
*
|
|
90
|
-
* runId 解析:优先 current-execute-run-id-<changeName> marker(最新一次 execute run);
|
|
91
|
-
* marker 缺失则扫描 execute-runs/ 下子目录、取 mtime 最新的,尽力定位。
|
|
92
|
-
*
|
|
93
|
-
* fail-safe:无 plan / 无 runId / review 全缺等任何异常,降级到 plan.md checkbox 统计 + 标注 source,
|
|
94
|
-
* 绝不抛错、绝不阻断 archive(最坏退回「数 checkbox」现状,不比修复前差)。
|
|
95
|
-
*
|
|
96
|
-
* @param {{ changeDir: string, runtimeRoot: string, changeName: string }} opts
|
|
97
|
-
* @returns {{ source: string, total: number, completed: number, pending: Array<{id:string,reason:string}>, report: string }}
|
|
98
|
-
* source: 'review.json'(客观源可用)/ 'plan-checkbox-fallback'(降级)/ 'no-plan' / 'no-tasks'
|
|
99
|
-
* report: 人类可读报告,供 prompt {TASK_COMPLETION_REPORT} 注入
|
|
100
|
-
*/
|
|
101
|
-
export function summarizeTaskCompletion({ changeDir, runtimeRoot, changeName }) {
|
|
102
|
-
const noPlan = {
|
|
103
|
-
source: 'no-plan', total: 0, completed: 0, pending: [],
|
|
104
|
-
report: '⚠️ 未找到 plan.md/tasks.md,无法计算任务完成度。请确认变更目录完整。'
|
|
105
|
-
}
|
|
106
|
-
if (!changeDir) return noPlan
|
|
107
|
-
|
|
108
|
-
// 2026-08-20-task-truth-unify:任务清单唯一真相在 tasks.md,优先读注册表;plan.md 回退
|
|
109
|
-
// (旧归档变更兼容读侧——新契约 plan.md 为纯 ID 引用行,无 checkbox 可解析)
|
|
110
|
-
const planPath = join(changeDir, 'plan.md')
|
|
111
|
-
const tasksPath = join(changeDir, 'tasks.md')
|
|
112
|
-
let planContent = null
|
|
113
|
-
if (existsSync(tasksPath)) planContent = readFileSync(tasksPath, 'utf8')
|
|
114
|
-
else if (existsSync(planPath)) planContent = readFileSync(planPath, 'utf8')
|
|
115
|
-
else return noPlan
|
|
116
|
-
|
|
117
|
-
const taskIds = parseTaskIdsFromPlan(planContent)
|
|
118
|
-
if (taskIds.length === 0) {
|
|
119
|
-
return { source: 'no-tasks', total: 0, completed: 0, pending: [],
|
|
120
|
-
report: '⚠️ tasks.md 未解析出任何 task-NN 条目(任务注册表可能未按规范写 checkbox 列表)。' }
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// runId 解析(坑 worktree-cleanup-marker-chain 根治):归属化解析 resolveExecuteRunForChange——
|
|
124
|
-
// marker 优先但校验覆盖度;marker 断裂(worktree cleanup / 归档清理 / 并行误删)时按 change 戳
|
|
125
|
-
// 精确归属,旧 run 退覆盖度启发。不再盲目 mtime 最新(曾把其他变更的 run 错配给本变更 →
|
|
126
|
-
// 全部 task 误报「review.json 缺失」→ 手工回填 7 份实际存在于正确 run 里的 review)。
|
|
127
|
-
const resolved = resolveExecuteRunForChange({ runtimeRoot, changeName, taskIds })
|
|
128
|
-
const runId = resolved ? resolved.runId : null
|
|
129
|
-
if (resolved && resolved.relocated) {
|
|
130
|
-
console.warn(`[sillyspec] execute run 归属修正:marker 指向的 run 对变更 ${changeName} 零覆盖,改用 ${resolved.origin === 'stamp' ? 'change 戳' : '覆盖度'}命中的 run ${runId}(真实 review 所在)`)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// 无归属 run → 降级 plan.md checkbox 统计;报告区分「无法归属」与「没跑过 execute」,
|
|
134
|
-
// 避免把定位失败误导成「review 全缺、需手工回填」
|
|
135
|
-
if (!runId) {
|
|
136
|
-
const { total, checked } = countPlanCheckboxes(planContent)
|
|
137
|
-
let runsNote = '无 execute-runs 目录(本变更未跑过 execute?)'
|
|
138
|
-
try {
|
|
139
|
-
const runsDir = join(runtimeRoot, 'execute-runs')
|
|
140
|
-
if (existsSync(runsDir)) {
|
|
141
|
-
const n = readdirSync(runsDir).filter(e => { try { return statSync(join(runsDir, e)).isDirectory() } catch { return false } }).length
|
|
142
|
-
if (n > 0) runsNote = `execute-runs/ 有 ${n} 个 run 但无一能归属到本变更(无 change 戳且零覆盖——marker 链断裂且 review 可能从未生成)`
|
|
143
|
-
}
|
|
144
|
-
} catch {}
|
|
145
|
-
return {
|
|
146
|
-
source: 'plan-checkbox-fallback', total, completed: checked,
|
|
147
|
-
pending: taskIds.slice(0, Math.max(0, total - checked)).map(id => ({ id, reason: 'checkbox 未勾(降级口径)' })),
|
|
148
|
-
report:
|
|
149
|
-
'⚠️ 客观源不可用(execute run 无法归属到本变更:' + runsNote + ')→ 降级用 plan.md checkbox。\n' +
|
|
150
|
-
`- 总任务:${total}\n- plan.md 已勾选:${checked}\n` +
|
|
151
|
-
'⚠️ checkbox 可能因 autoCheckPlanFromReviews 回填断裂而失真,务必交叉核对 .runtime/execute-runs/*/tasks/task-NN/review.json 的 verdict 再下结论。'
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// 有 runId → 读 review.json verdict;cannot_verify 草稿单列(不是真正复核,归档前应可见)
|
|
156
|
-
const completed = []
|
|
157
|
-
const pending = []
|
|
158
|
-
let cannotVerifyCount = 0
|
|
159
|
-
for (const id of taskIds) {
|
|
160
|
-
const reviewPath = join(runtimeRoot, 'execute-runs', runId, 'tasks', id, 'review.json')
|
|
161
|
-
const r = readReview(reviewPath)
|
|
162
|
-
if (r.ok && r.review && r.review.specVerdict !== 'fail' && r.review.qualityVerdict !== 'fail') {
|
|
163
|
-
completed.push(id)
|
|
164
|
-
if (r.review.specVerdict === 'cannot_verify' || r.review.qualityVerdict === 'cannot_verify') cannotVerifyCount++
|
|
165
|
-
} else if (r.ok && r.review) {
|
|
166
|
-
pending.push({ id, reason: `verdict 未通过(spec=${r.review.specVerdict}, quality=${r.review.qualityVerdict})` })
|
|
167
|
-
} else {
|
|
168
|
-
pending.push({ id, reason: 'review.json 缺失(task 未走完 execute 评审)' })
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const pendingLines = pending.length > 0
|
|
173
|
-
? pending.map(p => ` - ${p.id}: ${p.reason}`).join('\n')
|
|
174
|
-
: ' (无)'
|
|
175
|
-
const draftLines = cannotVerifyCount > 0
|
|
176
|
-
? `- cannot_verify 草稿(未真正复核): ${cannotVerifyCount}\n` +
|
|
177
|
-
' ⚠️ 这些 task 的 review 是 cannot_verify(含自动草稿兜底)而非 pass——归档前应确认 verify 阶段已兑现其 requiredEvidence,否则派独立子代理对照 task brief + git diff 补真实复核,勿静默放行\n'
|
|
178
|
-
: ''
|
|
179
|
-
return {
|
|
180
|
-
source: 'review.json', total: taskIds.length, completed: completed.length, pending, cannotVerify: cannotVerifyCount, runId,
|
|
181
|
-
report:
|
|
182
|
-
`客观任务完成度(真相源 = review.json verdict,runId=${runId}${resolved.origin !== 'marker' ? `,归属=${resolved.origin}` : ''}):\n` +
|
|
183
|
-
`- 总任务:${taskIds.length}\n` +
|
|
184
|
-
`- 已通过(spec + quality verdict 均非 fail):${completed.length}\n` +
|
|
185
|
-
draftLines +
|
|
186
|
-
`- 未通过 / 缺失:${pending.length}\n` +
|
|
187
|
-
`- 未完成列表:\n${pendingLines}\n` +
|
|
188
|
-
'注:以 review.json verdict 为准;plan.md checkbox 仅作显示态(回填断裂时会与客观 verdict 不一致,以下方客观点为准)。'
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* 校验单个 review.json 文件
|
|
194
|
-
*
|
|
195
|
-
* schema 版本(design §7.4 / R-07):接受 v1(无 repo,单仓向后兼容)+ v2(新增可选 repo 字段,
|
|
196
|
-
* 跨仓 task 标记 repo: <key>)。repo 缺省 / 非字符串 → 视 'main'(normalizeRepoKey),不阻断。
|
|
197
|
-
* repo 的真实存在性(local.yaml repos 注册)由 MultiRepoContext 约束② fail-closed 兜底,schema 层
|
|
198
|
-
* 只做"非字符串时不阻断"的宽松类型校验(review.json 是 agent 手写产物,宽松避免误杀)。
|
|
199
|
-
*
|
|
200
|
-
* @param {object} review - 解析后的 JSON 对象
|
|
201
|
-
* @returns {{ ok: boolean, errors: string[] }}
|
|
202
|
-
*/
|
|
203
|
-
export function validateReviewSchema(review) {
|
|
204
|
-
const errors = []
|
|
205
|
-
if (!review || typeof review !== 'object') {
|
|
206
|
-
errors.push('review.json 不是有效 JSON 对象')
|
|
207
|
-
return { ok: false, errors }
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (!REVIEW_SCHEMA_VERSIONS_ACCEPTED.includes(review.schemaVersion)) {
|
|
211
|
-
errors.push(`schemaVersion 应为 ${REVIEW_SCHEMA_VERSIONS_ACCEPTED.join(' 或 ')},实际为 ${review.schemaVersion}`)
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (!review.task || typeof review.task !== 'string') {
|
|
215
|
-
errors.push('缺少 task 字段(应为 "task-XX" 格式)')
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// repo(可选,v2 新增):类型宽松校验。非字符串 / 空串 → 视 'main',不阻断 schema。
|
|
219
|
-
// 跨仓 repo 的注册存在性由 MultiRepoContext 构造时 fail-closed 校验(约束②)。
|
|
220
|
-
if (review.repo !== undefined && typeof review.repo !== 'string') {
|
|
221
|
-
errors.push(`repo 字段(若提供)应为字符串,实际类型为 ${typeof review.repo}`)
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (!VALID_VERDICTS.includes(review.specVerdict)) {
|
|
225
|
-
errors.push(`specVerdict 无效:${review.specVerdict}(应为 ${VALID_VERDICTS.join('/')})`)
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if (!VALID_VERDICTS.includes(review.qualityVerdict)) {
|
|
229
|
-
errors.push(`qualityVerdict 无效:${review.qualityVerdict}(应为 ${VALID_VERDICTS.join('/')})`)
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// cannot_verify 必须提供 requiredEvidence
|
|
233
|
-
if (review.specVerdict === 'cannot_verify' || review.qualityVerdict === 'cannot_verify') {
|
|
234
|
-
if (!Array.isArray(review.requiredEvidence) || review.requiredEvidence.length === 0) {
|
|
235
|
-
errors.push('cannot_verify 的 verdict 必须提供非空的 requiredEvidence 数组')
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// base/head 非空检查
|
|
240
|
-
if (!review.base || typeof review.base !== 'string') {
|
|
241
|
-
errors.push('缺少 base 字段(git commit hash)')
|
|
242
|
-
}
|
|
243
|
-
if (!review.head || typeof review.head !== 'string') {
|
|
244
|
-
errors.push('缺少 head 字段(git commit hash)')
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
return { ok: errors.length === 0, errors }
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* 增强 JSON.parse 失败的定位:从 V8 的 "at position N" 算出 line:col + 出错行上下文,
|
|
252
|
-
* 并对常见非法转义(正则的反斜杠序列误入 JSON 字符串)给针对性修复指引。
|
|
253
|
-
* @param {string} raw 原始文件内容
|
|
254
|
-
* @param {string} message V8 抛出的错误消息
|
|
255
|
-
* @returns {string} 增强后的可读消息
|
|
256
|
-
*/
|
|
257
|
-
export function enrichJsonParseError(raw, message) {
|
|
258
|
-
const m = /at position (\d+)/.exec(message)
|
|
259
|
-
if (!m) return message
|
|
260
|
-
const pos = Math.min(Number(m[1]), raw.length)
|
|
261
|
-
let line = 1, col = 1
|
|
262
|
-
for (let i = 0; i < pos; i++) {
|
|
263
|
-
if (raw[i] === '\n') { line++; col = 1 } else { col++ }
|
|
264
|
-
}
|
|
265
|
-
const lineStart = raw.lastIndexOf('\n', pos - 1) + 1
|
|
266
|
-
const nlAfter = raw.indexOf('\n', pos)
|
|
267
|
-
const lineEnd = nlAfter === -1 ? raw.length : nlAfter
|
|
268
|
-
const snippet = raw.slice(lineStart, lineEnd)
|
|
269
|
-
const caret = ' '.repeat(Math.max(0, col - 1)) + '^'
|
|
270
|
-
// 单行注释内的反斜杠序列是纯文本,不触发块注释终止;正则字面量在函数体内正常解析。
|
|
271
|
-
let out = message + '\n → 第 ' + line + ' 行第 ' + col + ' 列:\n ' + snippet + '\n ' + caret
|
|
272
|
-
// 先移除合法的成对反斜杠(JSON 中 \\ 表字面 \),否则 "\\z" 会被逐字符正则误判为 "\z" 非法转义
|
|
273
|
-
const hasBadEscape = message.includes('Bad escaped character') || /\\[^"\\/bfnrtu]/.test(snippet.replace(/\\\\/g, ''))
|
|
274
|
-
if (hasBadEscape) {
|
|
275
|
-
out += '\n → 疑似正则转义(如 \\s \\d \\w)混入 JSON 字符串。修复:双写反斜杠(\\\\s),或用 JSON.stringify(obj) 重写 review.json。'
|
|
276
|
-
}
|
|
277
|
-
return out
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* 读取单个 task 的 review.json
|
|
282
|
-
* @param {string} reviewPath - review.json 文件路径
|
|
283
|
-
* @returns {{ ok: boolean, review: object|null, errors: string[] }}
|
|
284
|
-
*/
|
|
285
|
-
export function readReview(reviewPath) {
|
|
286
|
-
if (!existsSync(reviewPath)) {
|
|
287
|
-
return { ok: false, review: null, errors: ['review.json 不存在'] }
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
let raw
|
|
291
|
-
try {
|
|
292
|
-
raw = readFileSync(reviewPath, 'utf8')
|
|
293
|
-
} catch (e) {
|
|
294
|
-
return { ok: false, review: null, parseError: true, errors: [`review.json 读取失败: ${e.message}`] }
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
let parsed
|
|
298
|
-
try {
|
|
299
|
-
parsed = JSON.parse(raw)
|
|
300
|
-
} catch (e) {
|
|
301
|
-
// 文件存在但 JSON 非法:review 设为 null 但标记 parseError=true,错误消息带行列定位 + 转义修复指引
|
|
302
|
-
return { ok: false, review: null, parseError: true, errors: [`review.json 解析失败: ${enrichJsonParseError(raw, e.message)}`] }
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
const schemaResult = validateReviewSchema(parsed)
|
|
306
|
-
if (!schemaResult.ok) {
|
|
307
|
-
return { ok: false, review: parsed, schemaError: true, errors: schemaResult.errors }
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
return { ok: true, review: parsed, errors: [] }
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* 校验 plan.md 里所有「已勾选 [x]」task 的 review.json 是否 schema 完整(坑 review-json-field-gap)。
|
|
315
|
-
*
|
|
316
|
-
* Task Review Gate(validateTaskReviews)只在 execute 整阶段完成时跑,单 task --done 不校验 →
|
|
317
|
-
* 子代理勾了 checkbox 却漏写/漏字段 review.json,要到收尾才暴露,用户被迫事后批量补。本函数供
|
|
318
|
-
* enforceReviewJsonGate 在每次 execute --done 调用:已勾 [x] = 声称完成 = 必有完整 review.json;
|
|
319
|
-
* 未勾 task 不校验(还没做)。readReview 已区分 missing/parseError/schemaError,这里只聚合。
|
|
320
|
-
*
|
|
321
|
-
* @param {{ planContent: string, runtimeRoot: string, executeRunId: string }} opts
|
|
322
|
-
* @returns {{ ok: boolean, failures: Array<{ taskId:string, reviewPath:string, kind:string, errors:string[] }> }}
|
|
323
|
-
* kind ∈ missing(review.json 不存在)/ parseError(JSON 坏)/ schemaError(字段缺)
|
|
324
|
-
*/
|
|
325
|
-
export function validateCheckedTaskReviews({ planContent, runtimeRoot, executeRunId }) {
|
|
326
|
-
const failures = []
|
|
327
|
-
const re = /^\s*[-*]\s*\[x\]\s*task-(\d+)/gim
|
|
328
|
-
let m
|
|
329
|
-
while ((m = re.exec(planContent)) !== null) {
|
|
330
|
-
const taskId = `task-${m[1].padStart(2, '0')}`
|
|
331
|
-
const reviewPath = join(runtimeRoot, 'execute-runs', executeRunId, 'tasks', taskId, 'review.json')
|
|
332
|
-
const r = readReview(reviewPath)
|
|
333
|
-
if (!r.ok) {
|
|
334
|
-
const kind = r.parseError ? 'parseError' : (r.schemaError ? 'schemaError' : 'missing')
|
|
335
|
-
failures.push({ taskId, reviewPath, kind, errors: r.errors })
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
return { ok: failures.length === 0, failures }
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* execute --done 时的 task review 总校验
|
|
343
|
-
*
|
|
344
|
-
* 规则:
|
|
345
|
-
* - 每个 plan task 必须有 review.json
|
|
346
|
-
* - specVerdict 或 qualityVerdict 为 fail → 整体 fail
|
|
347
|
-
* - specVerdict 或 qualityVerdict 为 cannot_verify → warning(requiredEvidence 非空)
|
|
348
|
-
* - cannot_verify + requiredEvidence 为空 → fail(agent 逃避判断)
|
|
349
|
-
* - cannot_verify 的 requiredEvidence 汇总到 requiredEvidence 字段,供 verify 阶段消费
|
|
350
|
-
*
|
|
351
|
-
* @param {object} opts
|
|
352
|
-
* @param {string} opts.planContent - plan.md 内容
|
|
353
|
-
* @param {string} opts.runtimeRoot - .sillyspec/.runtime 的绝对路径
|
|
354
|
-
* @param {string} opts.executeRunId - execute run id(如 'exec-2026-06-23-131400')
|
|
355
|
-
* @param {boolean} [opts.allowCannotVerify=true] - 是否允许 cannot_verify(默认允许,给 warning)
|
|
356
|
-
* @param {string} [opts.changeDir] - change 目录(读 task-NN.md frontmatter 判 low_risk)
|
|
357
|
-
* @param {string} [opts.gitDir] - 主仓 git 工作目录(单仓 review 真实性校验 cwd;无 ctx 时用此)
|
|
358
|
-
* @param {object} [opts.ctx] - MultiRepoContext 实例(D-013:缺省/null → 走 opts.gitDir 单仓零回归;
|
|
359
|
-
* 有 ctx 时按 review.repo(缺省 'main')从 ctx.resolve(repo).gitDir 取每条 review 的校验 cwd,
|
|
360
|
-
* 跨仓 gitDir=跨仓仓根,使 base..head diff 在正确仓跑——design §6 task-review A1 行)
|
|
361
|
-
* @returns {{ ok: boolean, errors: string[], warnings: string[], requiredEvidence: Array<{task: string, verdict: string, evidence: string[]}> }}
|
|
362
|
-
*/
|
|
363
|
-
/**
|
|
364
|
-
* 读取 task-XX.md frontmatter,判断是否声明 low_risk: true(type-only/机械迁移等低逻辑风险)。
|
|
365
|
-
* 声明 low_risk 的 task 缺 review.json 时只 warning 不 error(B2:免逐个评审仪式)。
|
|
366
|
-
*/
|
|
367
|
-
function isTaskLowRisk(changeDir, taskId) {
|
|
368
|
-
if (!changeDir) return false
|
|
369
|
-
const taskFile = join(changeDir, 'tasks', `${taskId}.md`)
|
|
370
|
-
if (!existsSync(taskFile)) return false
|
|
371
|
-
try {
|
|
372
|
-
const content = readFileSync(taskFile, 'utf8')
|
|
373
|
-
const fm = content.match(/^---\n([\s\S]*?)\n---/)
|
|
374
|
-
if (!fm) return false
|
|
375
|
-
return /^low_risk:\s*true\s*$/im.test(fm[1])
|
|
376
|
-
} catch {
|
|
377
|
-
return false
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* 纯验证 task 判定(坑 verification-task-zero-diff,2026-08-21 实证):task-10/11 类
|
|
383
|
-
* 「跑测试/部署验证/观测确认」型任务无代码 diff 是本质属性而非伪造——emptyDiff 判伪造
|
|
384
|
-
* 对它们必误杀,此前只能引用验证区间并手工披露归属绕过。task 卡 frontmatter 显式声明
|
|
385
|
-
* `task_type: verification`(或 `verification_only: true`)即走合法零 diff 通道:
|
|
386
|
-
* emptyDiff 不判伪造(转 warning),但 review 必须带非空 requiredEvidence(披露验证
|
|
387
|
-
* 区间/结论出处)——不能拿声明逃掉披露义务。
|
|
388
|
-
* @returns {boolean}
|
|
389
|
-
*/
|
|
390
|
-
function isTaskVerification(changeDir, taskId) {
|
|
391
|
-
if (!changeDir) return false
|
|
392
|
-
const taskFile = join(changeDir, 'tasks', `${taskId}.md`)
|
|
393
|
-
if (!existsSync(taskFile)) return false
|
|
394
|
-
try {
|
|
395
|
-
const content = readFileSync(taskFile, 'utf8')
|
|
396
|
-
const fm = content.match(/^---\r?\n([\s\S]*?)\r?\n---/)
|
|
397
|
-
if (!fm) return false
|
|
398
|
-
return /^task_type:\s*['"]?verification['"]?\s*$/im.test(fm[1])
|
|
399
|
-
|| /^verification_only:\s*true\s*$/im.test(fm[1])
|
|
400
|
-
} catch {
|
|
401
|
-
return false
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
export function validateTaskReviews(opts) {
|
|
406
|
-
const { planContent, runtimeRoot, executeRunId, allowCannotVerify = true, changeDir = null, gitDir = null, ctx = null } = opts
|
|
407
|
-
|
|
408
|
-
const taskIds = parseTaskIdsFromPlan(planContent)
|
|
409
|
-
|
|
410
|
-
// 如果 plan 里没有 task,跳过校验(向后兼容)
|
|
411
|
-
if (taskIds.length === 0) {
|
|
412
|
-
return { ok: true, errors: [], warnings: [], requiredEvidence: [] }
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
const errors = []
|
|
416
|
-
const warnings = []
|
|
417
|
-
const requiredEvidence = []
|
|
418
|
-
// PERF-01:整个循环共享一份 git 结果缓存(同 gitDir 的探测/status、同 (base,head) 的
|
|
419
|
-
// diff 在多 task 间高度重复;N task 从 5N 个 git 子进程降到 ~2+去重后数量)
|
|
420
|
-
const evidenceCache = {}
|
|
421
|
-
|
|
422
|
-
for (const taskId of taskIds) {
|
|
423
|
-
const reviewDir = join(runtimeRoot, 'execute-runs', executeRunId, 'tasks', taskId)
|
|
424
|
-
const reviewPath = join(reviewDir, 'review.json')
|
|
425
|
-
|
|
426
|
-
const result = readReview(reviewPath)
|
|
427
|
-
|
|
428
|
-
if (!result.ok) {
|
|
429
|
-
if (result.parseError) {
|
|
430
|
-
// review.json 存在但 JSON 非法
|
|
431
|
-
errors.push(`${taskId}: review.json 解析失败 — ${result.errors.join('; ')}`)
|
|
432
|
-
} else if (result.schemaError) {
|
|
433
|
-
// review.json 存在且 JSON 合法,但 schema 校验失败
|
|
434
|
-
errors.push(`${taskId}: review.json 校验失败 — ${result.errors.join('; ')}`)
|
|
435
|
-
} else {
|
|
436
|
-
// review.json 不存在:声明 low_risk 的 task 豁免(B2:type-only/机械迁移免逐个评审)
|
|
437
|
-
if (isTaskLowRisk(changeDir, taskId)) {
|
|
438
|
-
warnings.push(`${taskId}: 缺少 review.json — task 声明 low_risk: true,已豁免评审(type-only/机械迁移)`)
|
|
439
|
-
} else {
|
|
440
|
-
errors.push(`${taskId}: 缺少 review.json — task 未经过评审(期望路径:${reviewPath},execute run ID: ${executeRunId})`)
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
continue
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
const review = result.review
|
|
447
|
-
|
|
448
|
-
// 检查 review.task 是否与 plan 中的 taskId 一致
|
|
449
|
-
if (review.task && review.task !== taskId) {
|
|
450
|
-
errors.push(`${taskId}: review.json 中的 task 字段为 "${review.task}",与 plan 不一致(应为 "${taskId}")— agent 可能复制模板未修改`)
|
|
451
|
-
continue
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
// 检查 fail verdict
|
|
455
|
-
if (review.specVerdict === 'fail' || review.qualityVerdict === 'fail') {
|
|
456
|
-
errors.push(`${taskId}: review 未通过 — spec: ${review.specVerdict}, quality: ${review.qualityVerdict}`)
|
|
457
|
-
if (review.reviewerNotes) {
|
|
458
|
-
errors.push(`${taskId}: ${review.reviewerNotes}`)
|
|
459
|
-
}
|
|
460
|
-
continue
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
// ── git 真实性交叉校验:base/head 必须是真实 commit,diff 不能为空 ──
|
|
464
|
-
// D-013 + design §6 A1:有 ctx 时按 review.repo(缺省 'main')切 gitDir——跨仓 review 的
|
|
465
|
-
// base/head 是跨仓仓 commit,必须在跨仓仓根跑 rev-parse/diff,否则判伪造误杀。无 ctx 时退回
|
|
466
|
-
// opts.gitDir(单仓零回归)。reviewGitDir 为 null 则跳过证据校验(与原逻辑一致)。
|
|
467
|
-
let reviewGitDir = gitDir
|
|
468
|
-
if (ctx) {
|
|
469
|
-
const repoKey = normalizeRepoKey(review.repo)
|
|
470
|
-
const entry = ctx.resolve(repoKey)
|
|
471
|
-
if (entry && entry.gitDir) {
|
|
472
|
-
reviewGitDir = entry.gitDir
|
|
473
|
-
} else if (repoKey !== 'main') {
|
|
474
|
-
// 跨仓 repo 在 ctx 中未注册 → 不应发生(MultiRepoContext 构造已 fail-closed 拦截未注册),
|
|
475
|
-
// 防御性降级为 warning 提示,不阻断(review.json schema 已过,仓库解析交给 ctx 上游负责)。
|
|
476
|
-
// 坑7 教训:此分支发生时后续主仓校验必报「疑似伪造」,文案须直接指向真实排查方向。
|
|
477
|
-
warnings.push(`${taskId}: review.repo="${repoKey}" 在 MultiRepoContext 未解析到 entry,退回主仓 gitDir 校验——下方若报 commit 不真实/疑似伪造,先查 repo 声明(plan.md 内联块或 tasks/task-NN.md 的 repo:)与 local.yaml repos: 注册,非 review 伪造`)
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
if (reviewGitDir) {
|
|
481
|
-
const evidence = verifyReviewGitEvidence(review, reviewGitDir, evidenceCache)
|
|
482
|
-
for (const w of evidence.warnings) warnings.push(`${taskId}: ${w}`)
|
|
483
|
-
if (!evidence.ok) {
|
|
484
|
-
for (const err of evidence.errors) errors.push(`${taskId}: ${err}`)
|
|
485
|
-
continue
|
|
486
|
-
}
|
|
487
|
-
if (evidence.emptyDiff) {
|
|
488
|
-
if (isTaskLowRisk(changeDir, taskId)) {
|
|
489
|
-
warnings.push(`${taskId}: base..head 无代码变更(task 声明 low_risk: true,不阻断)`)
|
|
490
|
-
} else if (isTaskVerification(changeDir, taskId)) {
|
|
491
|
-
// 纯验证 task 零 diff 通道(坑 verification-task-zero-diff):声明 task_type: verification
|
|
492
|
-
// 的「跑测试/部署验证/观测」型任务无代码 diff 是本质属性——不判伪造,但披露义务不豁免:
|
|
493
|
-
// requiredEvidence 为空 → error(声明不能替代证据)
|
|
494
|
-
if (Array.isArray(review.requiredEvidence) && review.requiredEvidence.length > 0) {
|
|
495
|
-
warnings.push(`${taskId}: base..head 无代码变更 — task 声明 task_type: verification(纯验证任务),零 diff 合法;requiredEvidence 已披露验证区间/结论出处`)
|
|
496
|
-
} else {
|
|
497
|
-
errors.push(`${taskId}: 纯验证 task(task_type: verification)零 diff 合法,但 review 缺 requiredEvidence(须披露验证区间/命令/结论出处)——声明不能替代披露`)
|
|
498
|
-
}
|
|
499
|
-
} else {
|
|
500
|
-
errors.push(`${taskId}: base..head(${review.base.slice(0, 8)}..${review.head.slice(0, 8)})无任何代码变更 — 评审了一个零改动的任务,review 疑似伪造`)
|
|
501
|
-
continue
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
// 检查 cannot_verify
|
|
507
|
-
if (review.specVerdict === 'cannot_verify' || review.qualityVerdict === 'cannot_verify') {
|
|
508
|
-
if (!allowCannotVerify) {
|
|
509
|
-
errors.push(`${taskId}: cannot_verify 不被允许 — 必须提供评审结果`)
|
|
510
|
-
continue
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
if (review.requiredEvidence && review.requiredEvidence.length > 0) {
|
|
514
|
-
const verdicts = []
|
|
515
|
-
if (review.specVerdict === 'cannot_verify') verdicts.push('spec')
|
|
516
|
-
if (review.qualityVerdict === 'cannot_verify') verdicts.push('quality')
|
|
517
|
-
warnings.push(`${taskId}: ${verdicts.join('+')}=cannot_verify,requiredEvidence 必须在 verify 阶段满足`)
|
|
518
|
-
requiredEvidence.push({
|
|
519
|
-
task: taskId,
|
|
520
|
-
verdict: verdicts.join('+'),
|
|
521
|
-
evidence: review.requiredEvidence,
|
|
522
|
-
})
|
|
523
|
-
} else {
|
|
524
|
-
// cannot_verify + 空 requiredEvidence = agent 逃避判断
|
|
525
|
-
errors.push(`${taskId}: cannot_verify 但 requiredEvidence 为空 — 这是无效评审`)
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
// 额外检查:扫描 execute-runs/<runId>/tasks/ 下是否有 plan 里没有的 task review
|
|
531
|
-
// (agent 可能写错了 task id)
|
|
532
|
-
try {
|
|
533
|
-
const tasksDir = join(runtimeRoot, 'execute-runs', executeRunId, 'tasks')
|
|
534
|
-
if (existsSync(tasksDir)) {
|
|
535
|
-
const taskDirs = readdirSync(tasksDir, { withFileTypes: true })
|
|
536
|
-
.filter(e => e.isDirectory())
|
|
537
|
-
.map(e => e.name)
|
|
538
|
-
const taskIdSet = new Set(taskIds)
|
|
539
|
-
for (const dirName of taskDirs) {
|
|
540
|
-
if (!taskIdSet.has(dirName) && existsSync(join(tasksDir, dirName, 'review.json'))) {
|
|
541
|
-
warnings.push(`${dirName}: 存在 review.json 但不在 plan.md 的 task 列表中(可能是多余文件)`)
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
} catch (e) {
|
|
546
|
-
warnings.push(`task review extra-check 异常: ${e.message}`)
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
return {
|
|
550
|
-
ok: errors.length === 0,
|
|
551
|
-
errors,
|
|
552
|
-
warnings,
|
|
553
|
-
requiredEvidence,
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
// ── Git 真实性交叉校验 ──
|
|
558
|
-
|
|
559
|
-
// QUAL-01 收口:原为本地 execFileSync('git')(无 safe.directory、与 git-helper 口径分裂),
|
|
560
|
-
// 现走统一入口;抛错/trim 语义不变,timeout 15000 保留(rev-parse/diff 大仓余量)
|
|
561
|
-
function runGit(gitDir, args, opts = {}) {
|
|
562
|
-
return git(gitDir, args, { timeout: 15000, ...opts })
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
// porcelain 状态行 → 变更文件路径(对齐 shared.js:343 parsePorcelainPath:`XY path`、引号包裹、
|
|
566
|
-
// rename `R old -> new` 取箭头后)。未 commit 的 working-tree 改动对账用。
|
|
567
|
-
// ⚠️ 入参必须是【未 trim】的原始输出(git(..., {trim:false}))——porcelain 行首空格是状态码
|
|
568
|
-
// 一部分,git() 默认 trim 会把 ' M feature.js' 削成 'M feature.js',slice(3) 再咬掉路径首字符
|
|
569
|
-
// (实测 'eature.js')→ 未提交文件对账全错位(verifyReviewGitEvidence 相交比对误判「完全不相交」)。
|
|
570
|
-
function parsePorcelainFiles(statusOut) {
|
|
571
|
-
const files = []
|
|
572
|
-
for (const line of String(statusOut).split('\n')) {
|
|
573
|
-
if (line.trim() === '') continue
|
|
574
|
-
let p = line.slice(3).trim()
|
|
575
|
-
if (p.length >= 2 && p.startsWith('"') && p.endsWith('"')) p = unquoteGitPath(p.slice(1, -1))
|
|
576
|
-
const arrow = p.indexOf(' -> ')
|
|
577
|
-
if (arrow !== -1) p = p.slice(arrow + 4)
|
|
578
|
-
if (p) files.push(p.replace(/\\/g, '/'))
|
|
579
|
-
}
|
|
580
|
-
return files
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
/**
|
|
584
|
-
* 校验 review.json 的 base/head 是否指向真实 git 提交,且 diff 非空。
|
|
585
|
-
*
|
|
586
|
-
* 历史漏洞:base/head 只做非空字符串检查,agent 可以填任意假 hash 批量伪造
|
|
587
|
-
* review.json 通过 Task Review Gate。此函数用 git 做客观交叉校验:
|
|
588
|
-
* 1. base/head 必须是仓库中可解析的真实 commit
|
|
589
|
-
* 2. base..head 的 diff 不能为空(评审一个零改动的"任务"无意义)
|
|
590
|
-
* 3. review.changedFiles(如提供)必须与实际 diff 文件有交集
|
|
591
|
-
*
|
|
592
|
-
* git 环境不可用(非 git 仓库 / git 缺失)时返回 unavailable,由调用方降级为
|
|
593
|
-
* warning——不因环境问题误杀,但记录在输出中。
|
|
594
|
-
*
|
|
595
|
-
/**
|
|
596
|
-
* @param {object} review - 已通过 schema 校验的 review 对象
|
|
597
|
-
* @param {string} gitDir - 执行 git 命令的目录(worktree 优先,回退主仓库)
|
|
598
|
-
* @param {object} [cache] - 进程内单次校验批的共享缓存(体检 PERF-01:N task × 5 个 git
|
|
599
|
-
* 子进程去重——gitDir 探测与 status --porcelain 结果按 gitDir 恒同,commit 校验按
|
|
600
|
-
* (gitDir,hash)、diff 按 (gitDir,base,head) 在多 task 间高度重复。validateTaskReviews
|
|
601
|
-
* 整个循环传同一份;不传则退化为逐次执行(单测/独立调用零回归)。缓存生命周期 =
|
|
602
|
-
* 一次校验批:working-tree status 是快照语义,跨批复用会读到陈旧状态。
|
|
603
|
-
* @returns {{ ok: boolean, emptyDiff: boolean, errors: string[], warnings: string[], unavailable: boolean }}
|
|
604
|
-
*/
|
|
605
|
-
export function verifyReviewGitEvidence(review, gitDir, cache = null) {
|
|
606
|
-
const errors = []
|
|
607
|
-
const warnings = []
|
|
608
|
-
const c = cache || (cache = {})
|
|
609
|
-
c.gitOk = c.gitOk || new Map()
|
|
610
|
-
c.verified = c.verified || new Set()
|
|
611
|
-
c.diffs = c.diffs || new Map()
|
|
612
|
-
c.wtStatus = c.wtStatus || new Map()
|
|
613
|
-
|
|
614
|
-
// git 环境探测:失败即 unavailable,交由调用方降级(同 gitDir 结果恒同,批内缓存)
|
|
615
|
-
if (!c.gitOk.has(gitDir)) {
|
|
616
|
-
try {
|
|
617
|
-
runGit(gitDir, ['rev-parse', '--git-dir'])
|
|
618
|
-
c.gitOk.set(gitDir, true)
|
|
619
|
-
} catch (e) {
|
|
620
|
-
c.gitOk.set(gitDir, false)
|
|
621
|
-
return {
|
|
622
|
-
ok: true,
|
|
623
|
-
emptyDiff: false,
|
|
624
|
-
errors: [],
|
|
625
|
-
warnings: [`git 环境不可用(${gitDir}),跳过 review 真实性交叉校验: ${e.message?.split('\n')[0] || e.message}`],
|
|
626
|
-
unavailable: true,
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
} else if (c.gitOk.get(gitDir) === false) {
|
|
630
|
-
return {
|
|
631
|
-
ok: true,
|
|
632
|
-
emptyDiff: false,
|
|
633
|
-
errors: [],
|
|
634
|
-
warnings: [`git 环境不可用(${gitDir}),跳过 review 真实性交叉校验(批内缓存判定)`],
|
|
635
|
-
unavailable: true,
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
for (const field of ['base', 'head']) {
|
|
640
|
-
const hash = review[field]
|
|
641
|
-
const vkey = `${gitDir}\u0000${hash}`
|
|
642
|
-
if (c.verified.has(vkey)) continue
|
|
643
|
-
try {
|
|
644
|
-
runGit(gitDir, ['rev-parse', '--verify', '--quiet', `${hash}^{commit}`])
|
|
645
|
-
c.verified.add(vkey)
|
|
646
|
-
} catch {
|
|
647
|
-
// 可执行指引(坑 review-head-real-commit-late,2026-08-22 实证:head 必须真实 commit 的
|
|
648
|
-
// 要求撞门才知道——报错直接给操作序列:worktree 改动先 commit,取 HEAD 作 head)
|
|
649
|
-
errors.push(`${field} "${hash}" 不是仓库中的真实 commit — review.json 疑似伪造。` +
|
|
650
|
-
`head/base 必须是 git rev-parse 可解析的 commit hash:worktree 内先 git add -A && git commit -m "<task>",` +
|
|
651
|
-
`再取 git rev-parse HEAD 作 head(base 用 task 卡锡点或基线 commit);不要填分支名/伪 hash/working-tree 描述`)
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
if (errors.length > 0) {
|
|
655
|
-
return { ok: false, emptyDiff: false, errors, warnings, unavailable: false }
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
let diffFiles = []
|
|
659
|
-
const dkey = `${gitDir}\u0000${review.base}\u0000${review.head}`
|
|
660
|
-
if (c.diffs.has(dkey)) {
|
|
661
|
-
diffFiles = c.diffs.get(dkey)
|
|
662
|
-
} else {
|
|
663
|
-
try {
|
|
664
|
-
const out = runGit(gitDir, ['diff', '--name-only', `${review.base}..${review.head}`])
|
|
665
|
-
diffFiles = out ? out.split('\n').filter(Boolean) : []
|
|
666
|
-
c.diffs.set(dkey, diffFiles)
|
|
667
|
-
} catch (e) {
|
|
668
|
-
warnings.push(`git diff ${review.base}..${review.head} 执行失败,跳过 diff 校验: ${e.message?.split('\n')[0] || e.message}`)
|
|
669
|
-
return { ok: true, emptyDiff: false, errors, warnings, unavailable: false }
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
// 并入 working-tree 未提交改动(execute 复盘 a):子代理默认不 commit,base..head 无 commit diff 时
|
|
674
|
-
// diffFiles 留空 → 下方交叉比对拿空集对非空 changedFiles 必判「完全不相交」伪造,逼 agent 强制 commit
|
|
675
|
-
// + 改 7 个 review head。对齐 checkExecuteCodeEvidence(stage-contract.js 同时查 working-tree)语义,
|
|
676
|
-
// 未提交改动也算有效对账源。working-tree 有改动时无条件并入(覆盖「部分 commit + 未提交」)。
|
|
677
|
-
// PERF-01:同 gitDir 的 status 快照按批缓存(单次校验批内恒同,跨批复用会读到陈旧状态)
|
|
678
|
-
const commitDiffFiles = diffFiles.slice()
|
|
679
|
-
try {
|
|
680
|
-
let wtStatus = c.wtStatus.get(gitDir)
|
|
681
|
-
if (wtStatus === undefined) {
|
|
682
|
-
wtStatus = runGit(gitDir, ['status', '--porcelain', '--untracked-files=all'], { trim: false })
|
|
683
|
-
c.wtStatus.set(gitDir, wtStatus)
|
|
684
|
-
}
|
|
685
|
-
if (wtStatus && wtStatus.trim().length > 0) {
|
|
686
|
-
const wtFiles = parsePorcelainFiles(wtStatus)
|
|
687
|
-
if (wtFiles.length > 0) diffFiles = diffFiles.concat(wtFiles)
|
|
688
|
-
if (commitDiffFiles.length === 0) {
|
|
689
|
-
warnings.push(`base..head 无 commit diff(${review.base.slice(0, 8)}..${review.head.slice(0, 8)}),交叉对账并入 working-tree 未提交改动 ${wtFiles.length} 个文件 —— 按有效改动处理,不判零改动伪造`)
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
} catch {}
|
|
693
|
-
diffFiles = [...new Set(diffFiles)].filter(Boolean)
|
|
694
|
-
|
|
695
|
-
const emptyDiff = diffFiles.length === 0
|
|
696
|
-
|
|
697
|
-
// changedFiles 交叉比对:完全不相交 = review 描述的改动与实际 diff 无关(diffFiles 已含 working-tree)
|
|
698
|
-
if (!emptyDiff && Array.isArray(review.changedFiles) && review.changedFiles.length > 0) {
|
|
699
|
-
// 注记剥离(坑 changedfiles-annotation-suffix-mismatch,2026-08-22 实证:changedFiles 带
|
|
700
|
-
// 「src/a.js(新增)」类注记后缀被判完全不相交,agent 用正则修还贪婪吞了路径段两轮才对)。
|
|
701
|
-
// 结构化剥法:只剥「路径尾部」的注记形态——全角/半角括号注记、// 与 # 行内注释、空白后的
|
|
702
|
-
// 说明文字;注记本身不参与匹配(想写说明放 reviewerNotes/requiredEvidence)。
|
|
703
|
-
const normalize = (p) => String(p)
|
|
704
|
-
.replace(/^\.\//, '')
|
|
705
|
-
.replace(/[((][^(())]*[))]\s*$/, '') // 尾部(注记)/(note)——中段括号(路径段)不动
|
|
706
|
-
.replace(/\s+(\/\/|#).*$/, '') // 空格后的 // 或 # 注释
|
|
707
|
-
.trim()
|
|
708
|
-
const diffSet = new Set(diffFiles.map(normalize))
|
|
709
|
-
const hasOverlap = review.changedFiles.some(f => {
|
|
710
|
-
const nf = normalize(f)
|
|
711
|
-
if (!nf) return false
|
|
712
|
-
// 兼容 review 写相对/部分路径:前后缀匹配即可
|
|
713
|
-
return diffSet.has(nf) || diffFiles.some(d => d.endsWith(nf) || nf.endsWith(d))
|
|
714
|
-
})
|
|
715
|
-
if (!hasOverlap) {
|
|
716
|
-
errors.push(`changedFiles 与实际 git diff(${review.base.slice(0, 8)}..${review.head.slice(0, 8)},${diffFiles.length} 个文件)完全不相交 — review 内容与代码变更无关。` +
|
|
717
|
-
`检查:changedFiles 必须是纯文件路径(注记/说明写 reviewerNotes,不拼进路径数组);路径拼写与 diff 对照`)
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
return { ok: errors.length === 0, emptyDiff, errors, warnings, unavailable: false }
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
/**
|
|
725
|
-
* 将 cannot_verify 的 requiredEvidence 写入 change 目录
|
|
726
|
-
* 供 verify 阶段消费
|
|
727
|
-
*
|
|
728
|
-
* @param {string} changeDir - 变更目录(.sillyspec/changes/<name>)
|
|
729
|
-
* @param {Array<{task: string, verdict: string, evidence: string[]}>} requiredEvidence
|
|
730
|
-
* @returns {string|null} 写入的文件路径,null 表示无需写入
|
|
731
|
-
*/
|
|
732
|
-
export function writeVerifyRequiredEvidence(changeDir, requiredEvidence) {
|
|
733
|
-
if (!requiredEvidence || requiredEvidence.length === 0) return null
|
|
734
|
-
|
|
735
|
-
const filePath = join(changeDir, 'verify-required-evidence.json')
|
|
736
|
-
const data = {
|
|
737
|
-
generatedAt: new Date().toISOString(),
|
|
738
|
-
schemaVersion: 1,
|
|
739
|
-
items: requiredEvidence,
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
mkdirSync(changeDir, { recursive: true })
|
|
743
|
-
writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n')
|
|
744
|
-
|
|
745
|
-
return filePath
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
/**
|
|
749
|
-
* 生成 execute run id
|
|
750
|
-
* @returns {string} 如 'exec-2026-06-23-131400'
|
|
751
|
-
*/
|
|
752
|
-
export function generateExecuteRunId() {
|
|
753
|
-
const now = new Date()
|
|
754
|
-
const pad = (n) => String(n).padStart(2, '0')
|
|
755
|
-
return `exec-${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
/**
|
|
759
|
-
* execute run id 格式校验:exec-YYYY-MM-DD-HHMMSS。
|
|
760
|
-
* marker 文件是 agent 可写内容,读回后既注入 prompt({EXECUTE_RUN_ID})又拼进
|
|
761
|
-
* join(runtimeRoot, 'execute-runs', runId) 路径——格式校验同时防提示词注入与路径穿越
|
|
762
|
-
* (对齐 stage-review marker 的 review- 前缀校验范式)。
|
|
763
|
-
* @param {string} runId
|
|
764
|
-
* @returns {boolean}
|
|
765
|
-
*/
|
|
766
|
-
export function isValidExecuteRunId(runId) {
|
|
767
|
-
return typeof runId === 'string' && /^exec-\d{4}-\d{2}-\d{2}-\d{6}$/.test(runId)
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
/**
|
|
771
|
-
* 解析最新 execute run id:优先 current-execute-run-id-<changeName> marker;
|
|
772
|
-
* marker 缺失/为空则扫描 execute-runs/ 下子目录、取 mtime 最新的(尽力定位已有 run)。
|
|
773
|
-
*
|
|
774
|
-
* 与 getLatestStageReviewRunId 的目录扫描兜底同语义——避免 marker 丢失(cleanup/并行/手删)
|
|
775
|
-
* 而 agent 已用旧 runId 落了 execute-runs/<旧ID>/ 时,调用方直接 generate 新 ID 找不到旧 review、
|
|
776
|
-
* 误判缺 review.json(gates.js execute 完成门坑)。返回 null 表示既无 marker 也无既有 run 目录。
|
|
777
|
-
*
|
|
778
|
-
* @param {{ runtimeRoot: string, changeName: string }} opts
|
|
779
|
-
* @returns {string|null} runId(exec- 前缀),无则 null
|
|
780
|
-
*/
|
|
781
|
-
/**
|
|
782
|
-
* 扫描 execute-runs/,返回 mtime 最新且真正含 tasks/ 子目录的 runId。
|
|
783
|
-
*
|
|
784
|
-
* 专治 execute run marker 漂移(prompt-control-debt.md gate-atom-a):generateExecuteRunId 只写
|
|
785
|
-
* marker 字符串、run 目录由 ensureTaskReviewDir 在写 review.json 时才建,marker 漂到「尚未建目录 /
|
|
786
|
-
* 未写任何 task review」的新 run 后,旧 run 里齐备的 review.json 全部失联。resolveLatestExecuteRunId
|
|
787
|
-
* 见 marker 非空即原样返回(不校验目录),接不住这种漂移;本函数无视 marker、只看真实目录内容,
|
|
788
|
-
* 供 enforceReviewJsonGate 在 marker 指向的 run 缺 tasks/ 时兜底重定位,避免误报「review.json 不存在」。
|
|
789
|
-
* 全部 run 都无 tasks/(真没写 review)返回 null——调用方维持原阻断,不误放行。
|
|
790
|
-
*
|
|
791
|
-
* @param {{ runtimeRoot: string }} opts
|
|
792
|
-
* @returns {string|null} 含 tasks/ 的最新 runId,无则 null
|
|
793
|
-
*/
|
|
794
|
-
export function resolveLatestExecuteRunIdWithTasks({ runtimeRoot, changeName = null }) {
|
|
795
|
-
try {
|
|
796
|
-
const runsDir = join(runtimeRoot, 'execute-runs')
|
|
797
|
-
if (!existsSync(runsDir)) return null
|
|
798
|
-
const entries = readdirSync(runsDir)
|
|
799
|
-
.map(e => ({ e, p: join(runsDir, e) }))
|
|
800
|
-
.filter(x => { try { return statSync(x.p).isDirectory() } catch { return false } })
|
|
801
|
-
.filter(x => { try { return statSync(join(x.p, 'tasks')).isDirectory() } catch { return false } })
|
|
802
|
-
.map(x => ({ e: x.e, mtime: statSync(x.p).mtimeMs }))
|
|
803
|
-
.sort((a, b) => b.mtime - a.mtime)
|
|
804
|
-
if (entries.length === 0) return null
|
|
805
|
-
// changeName 给定时优先 change 戳等值的 run(坑 worktree-cleanup-marker-chain:mtime 最新
|
|
806
|
-
// 会错拿其他变更的 run);无戳命中退回 mtime 最新(向后兼容,调用方多为 marker 漂移兜底,
|
|
807
|
-
// 宁可拿最新 run 也不空手而归——覆盖度由调用方 validateTaskReviews 复校验)
|
|
808
|
-
if (changeName) {
|
|
809
|
-
for (const x of entries) {
|
|
810
|
-
try {
|
|
811
|
-
const c = readFileSync(join(runsDir, x.e, 'change'), 'utf8').trim()
|
|
812
|
-
if (c === changeName) return x.e
|
|
813
|
-
} catch {}
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
return entries[0].e
|
|
817
|
-
} catch {
|
|
818
|
-
return null
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
export function resolveLatestExecuteRunId({ runtimeRoot, changeName }) {
|
|
823
|
-
const marker = join(runtimeRoot, `current-execute-run-id-${changeName}`)
|
|
824
|
-
try {
|
|
825
|
-
if (existsSync(marker)) {
|
|
826
|
-
const c = readFileSync(marker, 'utf8').trim()
|
|
827
|
-
if (c && !isValidExecuteRunId(c)) console.warn(`[sillyspec] execute run marker 内容非法(期望 exec-YYYY-MM-DD-HHMMSS,实得 ${JSON.stringify(c.slice(0, 60))}),忽略并回退目录扫描`)
|
|
828
|
-
if (isValidExecuteRunId(c)) return c
|
|
829
|
-
}
|
|
830
|
-
} catch {}
|
|
831
|
-
// marker 缺失(worktree cleanup / 归档清理 / 并行会话误删——坑 worktree-cleanup-marker-chain)
|
|
832
|
-
// 时不再盲目取 mtime 最新(会拿到其他变更的 run):先按 change 归属戳过滤,命中才返回;
|
|
833
|
-
// 无戳(旧 run)退回 mtime 最新保持向后兼容。
|
|
834
|
-
try {
|
|
835
|
-
const candidates = listExecuteRunCandidates(runtimeRoot, changeName)
|
|
836
|
-
if (candidates.stamped.length > 0) return candidates.stamped[0]
|
|
837
|
-
if (candidates.all.length > 0) return candidates.all[0]
|
|
838
|
-
} catch {}
|
|
839
|
-
return null
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
// ── execute run 的 change 归属戳(坑 worktree-cleanup-marker-chain 根治)──
|
|
843
|
-
//
|
|
844
|
-
// 背景:run 目录 execute-runs/<runId>/ 本身不带变更身份,change→run 的唯一链接是
|
|
845
|
-
// current-execute-run-id-<change> marker;worktree cleanup / 归档 marker 清理 / 并行会话
|
|
846
|
-
// 误删后链即断,各 fallback(mtime 最新)会错拿其他变更的 run → archive 完成度报告把
|
|
847
|
-
// 已实现 task 全报「review.json 缺失」,只能手工回填。
|
|
848
|
-
// 修法:marker 写入点同步在 run 目录落 `change` 戳;marker 断裂后按戳精确归属,
|
|
849
|
-
// 旧 run(无戳)退回覆盖度启发式(run 的 tasks/ 含本变更 task-NN review 才算命中)。
|
|
850
|
-
|
|
851
|
-
/**
|
|
852
|
-
* 在 run 目录写入 change 归属戳(execute-runs/<runId>/change,内容为 changeName)。
|
|
853
|
-
* 与 marker 写入点同步调用(stage.js 主点 + gates.js/task-review.js 补写点)。
|
|
854
|
-
* best-effort:失败仅 warn 不抛(戳是归属优化的载体,缺了退回覆盖度启发式,不阻断主流程)。
|
|
855
|
-
* @param {string} runtimeRoot
|
|
856
|
-
* @param {string} runId
|
|
857
|
-
* @param {string} changeName
|
|
858
|
-
*/
|
|
859
|
-
export function stampExecuteRunChange(runtimeRoot, runId, changeName) {
|
|
860
|
-
if (!runtimeRoot || !runId || !changeName) return
|
|
861
|
-
try {
|
|
862
|
-
// run 目录可能尚未创建(本 helper 先于 review 落盘调用的路径)——mkdir 保证自洽
|
|
863
|
-
mkdirSync(join(runtimeRoot, 'execute-runs', runId), { recursive: true })
|
|
864
|
-
writeFileSync(join(runtimeRoot, 'execute-runs', runId, 'change'), changeName + '\n')
|
|
865
|
-
} catch (e) {
|
|
866
|
-
console.warn(`[sillyspec] execute run change 戳写入失败(归属 fallback 退回覆盖度启发式,不阻断): ${e.message}`)
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
/**
|
|
871
|
-
* 读 run 目录的 change 归属戳。
|
|
872
|
-
* @returns {string|null} 戳内容(trim 后非空),无戳/读失败返回 null
|
|
873
|
-
*/
|
|
874
|
-
function readExecuteRunChangeStamp(runtimeRoot, runId) {
|
|
875
|
-
try {
|
|
876
|
-
const c = readFileSync(join(runtimeRoot, 'execute-runs', runId, 'change'), 'utf8').trim()
|
|
877
|
-
return c || null
|
|
878
|
-
} catch { return null }
|
|
879
|
-
}
|
|
880
|
-
|
|
881
|
-
/**
|
|
882
|
-
* 扫描 execute-runs/ 候选 run(mtime 最新优先),按 change 归属戳分组。
|
|
883
|
-
* @returns {{ stamped: string[], all: string[] }} stamped=戳等 changeName 的 runId(新→旧);
|
|
884
|
-
* all=全部 runId(新→旧,含无戳旧 run,供覆盖度启发式与向后兼容 fallback)
|
|
885
|
-
*/
|
|
886
|
-
function listExecuteRunCandidates(runtimeRoot, changeName) {
|
|
887
|
-
const runsDir = join(runtimeRoot, 'execute-runs')
|
|
888
|
-
const out = { stamped: [], all: [] }
|
|
889
|
-
if (!existsSync(runsDir)) return out
|
|
890
|
-
const entries = readdirSync(runsDir)
|
|
891
|
-
.map(e => ({ e, p: join(runsDir, e) }))
|
|
892
|
-
.filter(x => { try { return statSync(x.p).isDirectory() } catch { return false } })
|
|
893
|
-
.map(x => ({ e: x.e, mtime: statSync(x.p).mtimeMs }))
|
|
894
|
-
.sort((a, b) => b.mtime - a.mtime)
|
|
895
|
-
for (const x of entries) {
|
|
896
|
-
out.all.push(x.e)
|
|
897
|
-
if (changeName && readExecuteRunChangeStamp(runtimeRoot, x.e) === changeName) out.stamped.push(x.e)
|
|
898
|
-
}
|
|
899
|
-
return out
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
/**
|
|
903
|
-
* 判定 run 对本变更 taskIds 的覆盖度:tasks/ 下存在多少个 task-NN/review.json ∈ taskIds。
|
|
904
|
-
* taskIds 为空时退化为「tasks/ 下存在任意 task-NN/review.json」(保守启发)。
|
|
905
|
-
* @returns {number} 命中的 review 数
|
|
906
|
-
*/
|
|
907
|
-
function executeRunCoverage(runtimeRoot, runId, taskIds) {
|
|
908
|
-
try {
|
|
909
|
-
const tasksDir = join(runtimeRoot, 'execute-runs', runId, 'tasks')
|
|
910
|
-
if (!existsSync(tasksDir)) return 0
|
|
911
|
-
const entries = readdirSync(tasksDir).filter(e => /^task-\d+$/.test(e))
|
|
912
|
-
if (taskIds.length > 0) return entries.filter(e => taskIds.includes(e) && existsSync(join(tasksDir, e, 'review.json'))).length
|
|
913
|
-
return entries.filter(e => existsSync(join(tasksDir, e, 'review.json'))).length
|
|
914
|
-
} catch { return 0 }
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
/**
|
|
918
|
-
* 归属化解析本变更的 execute run(marker 链断裂的根治入口)。
|
|
919
|
-
*
|
|
920
|
-
* 解析顺序:
|
|
921
|
-
* 1. marker(格式校验)指向的 run,若其对本变更有覆盖(tasks/ 有本变更 review)或戳匹配 → 用它;
|
|
922
|
-
* 2. marker 缺失/非法/零覆盖(坑10 型漂移:marker 指向空 run)→ 扫描候选:
|
|
923
|
-
* a. change 戳等值的最新的 run;
|
|
924
|
-
* b.(旧 run 无戳)覆盖度 ≥1 的最新 run;
|
|
925
|
-
* 3. 都不命中 → null(调用方降级,报告明确「run 无法归属」而非「review 全缺」)。
|
|
926
|
-
*
|
|
927
|
-
* fail-safe:任何异常 → null,绝不抛。
|
|
928
|
-
* @param {{ runtimeRoot: string, changeName: string, taskIds?: string[] }} opts
|
|
929
|
-
* @returns {{ runId: string, origin: 'marker'|'stamp'|'coverage', relocated?: boolean }|null}
|
|
930
|
-
*/
|
|
931
|
-
export function resolveExecuteRunForChange({ runtimeRoot, changeName, taskIds = [] }) {
|
|
932
|
-
try {
|
|
933
|
-
// 1. marker
|
|
934
|
-
let markerRunId = null
|
|
935
|
-
try {
|
|
936
|
-
const marker = join(runtimeRoot, `current-execute-run-id-${changeName}`)
|
|
937
|
-
if (existsSync(marker)) {
|
|
938
|
-
const c = readFileSync(marker, 'utf8').trim()
|
|
939
|
-
if (c && !isValidExecuteRunId(c)) console.warn(`[sillyspec] execute run marker 内容非法(期望 exec-YYYY-MM-DD-HHMMSS,实得 ${JSON.stringify(c.slice(0, 60))}),忽略并回退归属扫描`)
|
|
940
|
-
if (isValidExecuteRunId(c)) markerRunId = c
|
|
941
|
-
}
|
|
942
|
-
} catch {}
|
|
943
|
-
if (markerRunId) {
|
|
944
|
-
const stamped = readExecuteRunChangeStamp(runtimeRoot, markerRunId) === changeName
|
|
945
|
-
const covered = executeRunCoverage(runtimeRoot, markerRunId, taskIds)
|
|
946
|
-
if (stamped || covered > 0) return { runId: markerRunId, origin: 'marker' }
|
|
947
|
-
// marker 零覆盖且无戳:疑似漂移(坑10:marker 在、真实 review 在别的 run),下探扫描
|
|
948
|
-
}
|
|
949
|
-
|
|
950
|
-
// 2. 扫描:戳优先 → 覆盖度启发(旧 run)。
|
|
951
|
-
// 覆盖度启发跳过「戳属他变更」的 run:task-NN 命名跨变更同构(都从 task-01 起),只看覆盖度
|
|
952
|
-
// 会把他变更 run 的 task-01 review 误配给本变更;戳存在且不等值 = 该 run 有明确主人,排除。
|
|
953
|
-
const candidates = listExecuteRunCandidates(runtimeRoot, changeName)
|
|
954
|
-
if (candidates.stamped.length > 0) {
|
|
955
|
-
return { runId: candidates.stamped[0], origin: 'stamp', relocated: markerRunId ? markerRunId !== candidates.stamped[0] : true }
|
|
956
|
-
}
|
|
957
|
-
for (const runId of candidates.all) {
|
|
958
|
-
const stamp = readExecuteRunChangeStamp(runtimeRoot, runId)
|
|
959
|
-
if (stamp && stamp !== changeName) continue
|
|
960
|
-
if (executeRunCoverage(runtimeRoot, runId, taskIds) > 0) {
|
|
961
|
-
return { runId, origin: 'coverage', relocated: markerRunId ? markerRunId !== runId : true }
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
|
-
return null
|
|
965
|
-
} catch {
|
|
966
|
-
return null
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
/**
|
|
971
|
-
* worktree execute「主 agent 直接实现」模式收尾兜底:per-task review.json 缺失时,
|
|
972
|
-
* 据 git diff base..head 按 task allowed_paths 归属,自动落盘 cannot_verify 草稿。
|
|
973
|
-
*
|
|
974
|
-
* 根因(坑 worktree-execute-apply-friction 坑2):per-task review.json 无程序化 writer,
|
|
975
|
-
* 全靠子代理手写;主 agent 统一实现强依赖链/机械 task 时不走子代理 review 流程 →
|
|
976
|
-
* review.json 全缺,execute --done 的 Task Review Gate 报「task-XX 缺少 review.json」阻断。
|
|
977
|
-
*
|
|
978
|
-
* 复用(与 Task Review Gate / verify 同源,单一真相):
|
|
979
|
-
* - resolveVerifyChangedFiles(worktree-aware,meta.json 为权威)→ base..head diff 文件集
|
|
980
|
-
* - WorktreeManager.getMeta → baseHash(base)+ worktreePath(决定 head/gitDir,同 gates.js reviewGitDir)
|
|
981
|
-
* - parseAllowedPaths + pathMatches(同 worktree-apply Gate2 口径)→ task 文件归属
|
|
982
|
-
* - exec-id 解析同 gates.js:269 / autoCheckPlanFromReviews:current-execute-run-id-<change> marker,
|
|
983
|
-
* 缺失则 generateExecuteRunId + 落盘(保证草稿与后续 gate 读同一 run 目录)
|
|
984
|
-
*
|
|
985
|
-
* 行为:
|
|
986
|
-
* - 仅 review.json 不存在时写(幂等,已有人工/子代理 verdict 一律跳过,绝不覆盖)
|
|
987
|
-
* - changedFiles 为空的 task 不生成(verifyReviewGitEvidence 判空 diff 伪造,留给 agent)
|
|
988
|
-
* - 草稿 verdict=cannot_verify + 非空 requiredEvidence(过 schema,流转 verify 阶段兑现)
|
|
989
|
-
* - 不属任何 task 的文件累计 unattributed(顺带修复/非源码),不强塞某 task
|
|
990
|
-
*
|
|
991
|
-
* fail-open:任何异常 → 返回统计,仅 console.warn,不阻断 execute 完成(草稿是兜底,
|
|
992
|
-
* 缺了也只是退回原状——gate 报缺 review.json,agent 手补,不比修复前差)。
|
|
993
|
-
*
|
|
994
|
-
* @param {{ changeName: string, cwd: string, platformOpts?: object, ctx?: object|null }} opts
|
|
995
|
-
* @returns {Promise<{ generated: number, skipped: number, unattributed: string[], reason?: string, executeRunId?: string }>}
|
|
996
|
-
*/
|
|
997
|
-
export async function generateTaskReviewDrafts({ changeName, cwd, platformOpts = {}, ctx = null }) {
|
|
998
|
-
const specBase = platformOpts.specRoot || join(cwd, '.sillyspec')
|
|
999
|
-
const runtimeRoot = resolveRuntimeRoot(platformOpts, specBase)
|
|
1000
|
-
const changeDir = join(specBase, 'changes', changeName)
|
|
1001
|
-
const tasksDir = join(changeDir, 'tasks')
|
|
1002
|
-
|
|
1003
|
-
if (!changeName) {
|
|
1004
|
-
return { generated: 0, skipped: 0, unattributed: [], reason: '无 changeName' }
|
|
1005
|
-
}
|
|
1006
|
-
// 无 task 卡片目录 → 非多 task 变更,无需补草稿
|
|
1007
|
-
if (!existsSync(tasksDir)) {
|
|
1008
|
-
return { generated: 0, skipped: 0, unattributed: [], reason: '无 tasks/ 目录' }
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
// exec-id:与 Task Review Gate(gates.js:269)/ autoCheckPlanFromReviews 同源
|
|
1012
|
-
const runIdFile = join(runtimeRoot, 'current-execute-run-id-' + changeName)
|
|
1013
|
-
let executeRunId = ''
|
|
1014
|
-
try {
|
|
1015
|
-
if (existsSync(runIdFile)) {
|
|
1016
|
-
const c = readFileSync(runIdFile, 'utf8').trim()
|
|
1017
|
-
if (c && !isValidExecuteRunId(c)) console.warn(`[sillyspec] execute run marker 内容非法(期望 exec-YYYY-MM-DD-HHMMSS,实得 ${JSON.stringify(c.slice(0, 60))}),视为缺失重新生成`)
|
|
1018
|
-
if (isValidExecuteRunId(c)) executeRunId = c
|
|
1019
|
-
}
|
|
1020
|
-
} catch {}
|
|
1021
|
-
if (!executeRunId) {
|
|
1022
|
-
executeRunId = generateExecuteRunId()
|
|
1023
|
-
// D-001#1 fallback 写入点:mkdir execute-runs/<runId>/tasks 先于 marker(不变量:marker 在则目录在)。
|
|
1024
|
-
// 保留 fail-open 契约(调用方 catch 降级)——只去静默:失败 console.error 留痕,不 throw
|
|
1025
|
-
//(草稿兜底缺了也只是退回 gate 报缺 review.json,不比修复前差)。
|
|
1026
|
-
try {
|
|
1027
|
-
mkdirSync(join(runtimeRoot, 'execute-runs', executeRunId, 'tasks'), { recursive: true })
|
|
1028
|
-
writeFileSync(runIdFile, executeRunId + '\n')
|
|
1029
|
-
stampExecuteRunChange(runtimeRoot, executeRunId, changeName)
|
|
1030
|
-
} catch (e) {
|
|
1031
|
-
console.error(`[sillyspec] execute run marker/目录写入失败(降级继续,草稿落盘仍尝试): ${e.message}`)
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1035
|
-
// base..head diff 文件集(worktree-aware;null=git 不可用,[]=无 commit diff)
|
|
1036
|
-
let diffFiles = resolveVerifyChangedFiles(cwd, changeName)
|
|
1037
|
-
// ⚠️ 并入 worktree 未提交改动(坑 draft-attribution-uncommitted-worktree,2026-08-21 实证):
|
|
1038
|
-
// 子代理默认不 commit(execute 复盘 a 同源事实),真实改动全在 worktree working-tree——只看
|
|
1039
|
-
// base..HEAD commit diff 时归属恒空,9/9 草稿全成「无归属」靠主代理手写升级。与
|
|
1040
|
-
// verifyReviewGitEvidence 的 working-tree 并入口径同源:status --porcelain 文件(排除
|
|
1041
|
-
// .sillyspec/ 运行时产物)并入归属集,按 allowed_paths 正常路径归属;review.head 仍为 HEAD
|
|
1042
|
-
// commit——evidence 校验对「commit diff 空 + working-tree 有改动」明示不判伪造,语义一致。
|
|
1043
|
-
try {
|
|
1044
|
-
const wm = new WorktreeManager({ cwd })
|
|
1045
|
-
const meta = wm.getMeta(changeName)
|
|
1046
|
-
if (meta) {
|
|
1047
|
-
const wtGitDir = (meta.worktreePath && meta.mode !== 'in-place-fallback' && existsSync(meta.worktreePath))
|
|
1048
|
-
? meta.worktreePath
|
|
1049
|
-
: cwd
|
|
1050
|
-
const wtStatus = runGit(wtGitDir, ['status', '--porcelain', '--untracked-files=all'], { trim: false })
|
|
1051
|
-
const wtFiles = parsePorcelainFiles(wtStatus)
|
|
1052
|
-
.map(p => String(p).replace(/\\/g, '/'))
|
|
1053
|
-
.filter(p => p !== '.sillyspec' && !p.startsWith('.sillyspec/'))
|
|
1054
|
-
if (wtFiles.length > 0) {
|
|
1055
|
-
diffFiles = [...new Set([...(Array.isArray(diffFiles) ? diffFiles : []), ...wtFiles])]
|
|
1056
|
-
console.log(`[sillyspec] 草稿归属并入 ${wtFiles.length} 个 worktree 未提交文件(子代理未 commit 的改动按 allowed_paths 归属)`)
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
} catch { /* working-tree 并入失败退回 commit diff 口径(fail-open,不阻断草稿) */ }
|
|
1060
|
-
// 单仓模式(无 ctx):主仓无 diff 即无任何 task 可生成 → 提前返回(原逻辑零回归)。
|
|
1061
|
-
// 有 ctx:主仓无 diff 不阻断——跨仓 task 的 diff 在跨仓仓根独立取(per-task),主仓 task 自然跳过(空 changedFiles)。
|
|
1062
|
-
if (!ctx && (!diffFiles || diffFiles.length === 0)) {
|
|
1063
|
-
return { generated: 0, skipped: 0, unattributed: [], executeRunId, reason: 'base..head 无代码 diff(改动未 commit?)' }
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
// base/head + gitDir:与 gates.js reviewGitDir 同源(worktree 优先,in-place 回退 cwd)
|
|
1067
|
-
// 有 ctx 时主仓 base/head 仅供主仓 task 用;ctx 主仓 entry 也可提供 base(meta.baseHash 同源)。
|
|
1068
|
-
// 主仓 base/head 解析失败 + 无 ctx → 提前返回(原逻辑);有 ctx → 仅记 null,主仓 task 后续跳过(不阻断跨仓 task)。
|
|
1069
|
-
let base = null
|
|
1070
|
-
let head = null
|
|
1071
|
-
let reviewGitDir = cwd
|
|
1072
|
-
try {
|
|
1073
|
-
const wm = new WorktreeManager({ cwd })
|
|
1074
|
-
const meta = wm.getMeta(changeName)
|
|
1075
|
-
base = (meta && (meta.baselineCommit || meta.baseHash)) || null
|
|
1076
|
-
if (meta && meta.worktreePath && meta.mode !== 'in-place-fallback' && existsSync(meta.worktreePath)) {
|
|
1077
|
-
reviewGitDir = meta.worktreePath
|
|
1078
|
-
}
|
|
1079
|
-
} catch {}
|
|
1080
|
-
if (!base) {
|
|
1081
|
-
if (!ctx) {
|
|
1082
|
-
return { generated: 0, skipped: 0, unattributed: diffFiles, executeRunId, reason: '无 worktree meta.baseHash(无法定 base/head)' }
|
|
1083
|
-
}
|
|
1084
|
-
// 有 ctx:主仓 base 缺失(主仓无 worktree / 单纯跨仓 change)→ 主仓 task 后续跳过,跨仓 task 照常
|
|
1085
|
-
} else {
|
|
1086
|
-
try {
|
|
1087
|
-
head = runGit(reviewGitDir, ['rev-parse', 'HEAD'])
|
|
1088
|
-
} catch {
|
|
1089
|
-
if (!ctx) {
|
|
1090
|
-
return { generated: 0, skipped: 0, unattributed: diffFiles, executeRunId, reason: 'git rev-parse HEAD 失败(' + reviewGitDir + ')' }
|
|
1091
|
-
}
|
|
1092
|
-
// 有 ctx:主仓 HEAD 失败不阻断跨仓 task;head 留 null,主仓 task 后续按空 changedFiles 跳过
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
const taskFiles = readdirSync(tasksDir).filter(f => /^task-\d+\.md$/.test(f)).sort()
|
|
1097
|
-
let generated = 0
|
|
1098
|
-
let skipped = 0
|
|
1099
|
-
let noAttributionCount = 0
|
|
1100
|
-
const attributed = new Set()
|
|
1101
|
-
|
|
1102
|
-
for (const tf of taskFiles) {
|
|
1103
|
-
const taskId = tf.replace(/\.md$/, '')
|
|
1104
|
-
const reviewDir = join(runtimeRoot, 'execute-runs', executeRunId, 'tasks', taskId)
|
|
1105
|
-
const reviewPath = join(reviewDir, 'review.json')
|
|
1106
|
-
|
|
1107
|
-
// 幂等:review.json 已存在(无论合法/解析错/schema 错)一律跳过,绝不覆盖人工/子代理 verdict
|
|
1108
|
-
const existing = readReview(reviewPath)
|
|
1109
|
-
if (existing.ok || existing.parseError || existing.schemaError) {
|
|
1110
|
-
skipped++
|
|
1111
|
-
continue
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
|
-
const content = readFileSync(join(tasksDir, tf), 'utf8')
|
|
1115
|
-
const allowedPaths = parseAllowedPaths(content)
|
|
1116
|
-
|
|
1117
|
-
// ── 多仓分支(design §6 A2 / D-006 / D-010):跨仓 task 用 task 卡双锡点 + 跨仓仓 diff ──
|
|
1118
|
-
const taskRepo = normalizeRepoKey(parseRepo(content))
|
|
1119
|
-
const crossEntry = (ctx && taskRepo !== DEFAULT_REPO_KEY) ? ctx.resolve(taskRepo) : null
|
|
1120
|
-
let taskBase = base
|
|
1121
|
-
let taskHead = head
|
|
1122
|
-
let taskChangedFiles
|
|
1123
|
-
let draftRepo
|
|
1124
|
-
|
|
1125
|
-
if (crossEntry) {
|
|
1126
|
-
// 跨仓 task:base/head 必须读 task 卡锡点(跨仓仓无 meta.json)。缺任一 → 跳过留给 agent。
|
|
1127
|
-
const baseCommit = parseBaseCommit(content)
|
|
1128
|
-
const headCommit = parseHeadCommit(content)
|
|
1129
|
-
if (!baseCommit || !headCommit) {
|
|
1130
|
-
skipped++
|
|
1131
|
-
continue
|
|
1132
|
-
}
|
|
1133
|
-
taskBase = baseCommit
|
|
1134
|
-
taskHead = headCommit
|
|
1135
|
-
draftRepo = taskRepo
|
|
1136
|
-
// 跨仓 diff 在跨仓仓根跑(base..head 锡点锚定,非瞬时 HEAD——D-010 head 精度)
|
|
1137
|
-
let crossDiffFiles = []
|
|
1138
|
-
try {
|
|
1139
|
-
const out = runGit(crossEntry.gitDir, ['diff', '--name-only', `${baseCommit}..${headCommit}`])
|
|
1140
|
-
crossDiffFiles = out ? out.split('\n').filter(Boolean).map(p => p.replace(/\\/g, '/')) : []
|
|
1141
|
-
} catch {
|
|
1142
|
-
// git diff 失败(锡点非真实 commit 等)→ 不生成伪造草稿,留给 agent 手补
|
|
1143
|
-
skipped++
|
|
1144
|
-
continue
|
|
1145
|
-
}
|
|
1146
|
-
taskChangedFiles = allowedPaths.length > 0
|
|
1147
|
-
? crossDiffFiles.filter(f => allowedPaths.some(p => pathMatches(f, p)))
|
|
1148
|
-
: crossDiffFiles
|
|
1149
|
-
} else {
|
|
1150
|
-
// 主仓 task(taskRepo='main' 或无 ctx 跨仓解析失败 → 退单仓口径)
|
|
1151
|
-
// diffFiles 可能为 null(git 不可用)——有 ctx 时主仓 git 异常不阻断跨仓 task,主仓 task 自然跳过。
|
|
1152
|
-
const mainDiff = Array.isArray(diffFiles) ? diffFiles : []
|
|
1153
|
-
taskChangedFiles = allowedPaths.length > 0
|
|
1154
|
-
? mainDiff.filter(f => allowedPaths.some(p => pathMatches(f, p)))
|
|
1155
|
-
: []
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
|
-
// 主仓 task 缺 base/head(meta 缺失 / HEAD 解析失败,见上方 :968-981 注释承诺的"后续跳过"):
|
|
1159
|
-
// 跳过留给 agent 手补。此前 null.slice(0,8) 直接 TypeError 崩掉整个草稿生成(体检 BUG-06)
|
|
1160
|
-
if (!crossEntry && (!taskBase || !taskHead)) {
|
|
1161
|
-
skipped++
|
|
1162
|
-
continue
|
|
1163
|
-
}
|
|
1164
|
-
// unattributed 只统计主仓 diff(跨仓 diff 路径相对跨仓仓根,与主仓 unattributed 语义无关)
|
|
1165
|
-
if (!crossEntry) {
|
|
1166
|
-
taskChangedFiles.forEach(f => attributed.add(f))
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
// 空 changedFiles 的 task 也生成「无归属」草稿(坑 task-review-draft-skip-leak,2026-08-21
|
|
1170
|
-
// 实证:task-08/task-10 两次都因 allowed_paths 未命中 diff 被静默跳过,--done gate 拦截后
|
|
1171
|
-
// agent 只能从零手写 review.json)。cannot_verify 草稿本就待复核(verify 阶段兑现
|
|
1172
|
-
// requiredEvidence),空 changedFiles 不触发 emptyDiff 伪造误判(该判定看真实 git diff 而非
|
|
1173
|
-
// review.changedFiles),shouldAutoCheckTask 零 diff 守卫也保证不会被自动勾选——草稿从
|
|
1174
|
-
// 「漏了让 agent 从零写」变成「给了骨架让 agent 升级 verdict」。
|
|
1175
|
-
if (taskChangedFiles.length === 0) {
|
|
1176
|
-
const draft = {
|
|
1177
|
-
schemaVersion: REVIEW_SCHEMA_VERSION,
|
|
1178
|
-
task: taskId,
|
|
1179
|
-
base: taskBase,
|
|
1180
|
-
head: taskHead,
|
|
1181
|
-
changedFiles: [],
|
|
1182
|
-
specVerdict: 'cannot_verify',
|
|
1183
|
-
qualityVerdict: 'cannot_verify',
|
|
1184
|
-
requiredEvidence: ['auto-generated draft (no-attributed-diff): ' + taskId +
|
|
1185
|
-
' 的 allowed_paths 未命中本次 diff 任何文件(task 未实现 / 改动与他人同文件 / 路径不匹配 / 纯验证任务)——' +
|
|
1186
|
-
'需人工确认实际改动后升级 verdict,确属未实现则回 fail;若是纯验证任务(跑测试/部署验证/观测,无代码 diff 是本质属性),' +
|
|
1187
|
-
'task 卡 frontmatter 声明 task_type: verification + review 披露验证区间即走合法零 diff 通道'],
|
|
1188
|
-
reviewerNotes: 'auto-generated draft from git diff ' + taskBase.slice(0, 8) + '..' + taskHead.slice(0, 8) +
|
|
1189
|
-
';verdict=未评审(无归属 diff 兜底草稿,坑 task-review-draft-skip-leak)',
|
|
1190
|
-
}
|
|
1191
|
-
if (draftRepo) draft.repo = draftRepo
|
|
1192
|
-
// fail-open(对齐函数头契约 + execute-run-dir-fail-loud 测试锁定的「写失败返回统计不抛」):
|
|
1193
|
-
// 无归属草稿写入失败(如 tasks/ 被普通文件占位 ENOTDIR)降级 skipped,不崩整个草稿生成
|
|
1194
|
-
try {
|
|
1195
|
-
mkdirSync(reviewDir, { recursive: true })
|
|
1196
|
-
writeFileSync(reviewPath, JSON.stringify(draft, null, 2) + '\n')
|
|
1197
|
-
generated++
|
|
1198
|
-
noAttributionCount++
|
|
1199
|
-
} catch (e) {
|
|
1200
|
-
console.error(`[sillyspec] task ${taskId} 无归属草稿落盘失败(降级留给 agent 手补): ${e.message}`)
|
|
1201
|
-
skipped++
|
|
1202
|
-
}
|
|
1203
|
-
continue
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
const draft = {
|
|
1207
|
-
schemaVersion: REVIEW_SCHEMA_VERSION,
|
|
1208
|
-
task: taskId,
|
|
1209
|
-
base: taskBase,
|
|
1210
|
-
head: taskHead,
|
|
1211
|
-
changedFiles: taskChangedFiles,
|
|
1212
|
-
specVerdict: 'cannot_verify',
|
|
1213
|
-
qualityVerdict: 'cannot_verify',
|
|
1214
|
-
requiredEvidence: ['auto-generated draft: 待 agent 对照 ' + taskId + ' brief + diff 复核后升级为 pass/fail'],
|
|
1215
|
-
reviewerNotes: 'auto-generated draft from git diff ' + taskBase.slice(0, 8) + '..' + taskHead.slice(0, 8) + ';verdict=未评审(worktree execute 主 agent 实现模式兜底,坑2)',
|
|
1216
|
-
}
|
|
1217
|
-
if (draftRepo) draft.repo = draftRepo
|
|
1218
|
-
mkdirSync(reviewDir, { recursive: true })
|
|
1219
|
-
writeFileSync(reviewPath, JSON.stringify(draft, null, 2) + '\n')
|
|
1220
|
-
generated++
|
|
1221
|
-
}
|
|
1222
|
-
|
|
1223
|
-
const unattributed = (Array.isArray(diffFiles) ? diffFiles : []).filter(f => !attributed.has(f))
|
|
1224
|
-
return { generated, skipped, noAttribution: noAttributionCount, unattributed, executeRunId }
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
/**
|
|
1228
|
-
* adoptTaskReviewMechanics —— 已存在 review.json 的 mechanics 字段一键重算代填(保 verdict)。
|
|
1229
|
-
*
|
|
1230
|
-
* 背景(2026-08-21 agent-手工产出审计项①):review.json 里 schemaVersion/task/base/head/
|
|
1231
|
-
* changedFiles(/repo) 全部可由 CLI 从 git + task 卡机械推导(generateTaskReviewDrafts 已证明),
|
|
1232
|
-
* agent/子代理手算 hash、手抄 diff 清单是纯错误面——而 gate(verifyReviewGitEvidence)校验的
|
|
1233
|
-
* 恰是这些字段。与草稿生成互补:草稿只补「缺失」,adopt 修「已存在但 mechanics 错/缺」——
|
|
1234
|
-
* 保留人工语义字段(specVerdict/qualityVerdict/requiredEvidence/reviewerNotes),只重写 mechanics。
|
|
1235
|
-
*
|
|
1236
|
-
* verdict 保护策略(不猜 agent 本意):
|
|
1237
|
-
* - 合法 verdict(VALID_VERDICTS)原样保留;
|
|
1238
|
-
* - 非法/缺失 verdict 降级 cannot_verify,reviewerNotes 追加标记,requiredEvidence 缺失补占位
|
|
1239
|
-
* (schema 要求 cannot_verify 必带非空 requiredEvidence);
|
|
1240
|
-
* - JSON 解析失败的 review 不救(无法可信保留任何字段),报出来留给 agent 修 JSON 后重跑。
|
|
1241
|
-
*
|
|
1242
|
-
* fail-open:与草稿生成同契约——缺数据返回统计与 reasons,不抛。
|
|
1243
|
-
*
|
|
1244
|
-
* @param {{ changeName: string, cwd: string, platformOpts?: object, ctx?: object|null }} opts
|
|
1245
|
-
* @returns {Promise<{ adopted: number, unchanged: number, skipped: number, missing: number,
|
|
1246
|
-
* downgraded: string[], reasons: string[], executeRunId?: string }>}
|
|
1247
|
-
*/
|
|
1248
|
-
export async function adoptTaskReviewMechanics({ changeName, cwd, platformOpts = {}, ctx = null }) {
|
|
1249
|
-
const specBase = platformOpts.specRoot || join(cwd, '.sillyspec')
|
|
1250
|
-
const runtimeRoot = resolveRuntimeRoot(platformOpts, specBase)
|
|
1251
|
-
const tasksDir = join(specBase, 'changes', changeName, 'tasks')
|
|
1252
|
-
const reasons = []
|
|
1253
|
-
|
|
1254
|
-
if (!changeName) {
|
|
1255
|
-
return { adopted: 0, unchanged: 0, skipped: 0, missing: 0, downgraded: [], reasons: ['无 changeName'] }
|
|
1256
|
-
}
|
|
1257
|
-
if (!existsSync(tasksDir)) {
|
|
1258
|
-
return { adopted: 0, unchanged: 0, skipped: 0, missing: 0, downgraded: [], reasons: ['无 tasks/ 目录'] }
|
|
1259
|
-
}
|
|
1260
|
-
|
|
1261
|
-
// executeRunId:与草稿/gate 同源 marker。缺 marker 不新建 run——adopt 修的是当前 run 里
|
|
1262
|
-
// 已存在的 review,marker 丢失说明无「当前 run」语义,无对象可修(gate 对 marker 缺失放行,
|
|
1263
|
-
// 下游 Task Review Gate 兜底,这里同口径不造 run)。
|
|
1264
|
-
const runIdFile = join(runtimeRoot, 'current-execute-run-id-' + changeName)
|
|
1265
|
-
let executeRunId = ''
|
|
1266
|
-
try {
|
|
1267
|
-
if (existsSync(runIdFile)) {
|
|
1268
|
-
const c = readFileSync(runIdFile, 'utf8').trim()
|
|
1269
|
-
if (isValidExecuteRunId(c)) executeRunId = c
|
|
1270
|
-
}
|
|
1271
|
-
} catch {}
|
|
1272
|
-
if (!executeRunId) {
|
|
1273
|
-
return { adopted: 0, unchanged: 0, skipped: 0, missing: 0, downgraded: [], reasons: ['无 execute run marker——无当前 run,adopt 无对象'] }
|
|
1274
|
-
}
|
|
1275
|
-
|
|
1276
|
-
// base/head + diff:与 generateTaskReviewDrafts 同源口径(meta 锡点 + worktree rev-parse +
|
|
1277
|
-
// resolveVerifyChangedFiles),保证 adopt 产物与 gate 校验输入一致。
|
|
1278
|
-
const diffFiles = resolveVerifyChangedFiles(cwd, changeName)
|
|
1279
|
-
let base = null
|
|
1280
|
-
let head = null
|
|
1281
|
-
let reviewGitDir = cwd
|
|
1282
|
-
try {
|
|
1283
|
-
const wm = new WorktreeManager({ cwd })
|
|
1284
|
-
const meta = wm.getMeta(changeName)
|
|
1285
|
-
base = (meta && (meta.baselineCommit || meta.baseHash)) || null
|
|
1286
|
-
if (meta && meta.worktreePath && meta.mode !== 'in-place-fallback' && existsSync(meta.worktreePath)) {
|
|
1287
|
-
reviewGitDir = meta.worktreePath
|
|
1288
|
-
}
|
|
1289
|
-
} catch {}
|
|
1290
|
-
if (base) {
|
|
1291
|
-
try {
|
|
1292
|
-
head = runGit(reviewGitDir, ['rev-parse', 'HEAD'])
|
|
1293
|
-
} catch {
|
|
1294
|
-
head = null
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
|
|
1298
|
-
const taskFiles = readdirSync(tasksDir).filter(f => /^task-\d+\.md$/.test(f)).sort()
|
|
1299
|
-
let adopted = 0
|
|
1300
|
-
let unchanged = 0
|
|
1301
|
-
let skipped = 0
|
|
1302
|
-
let missing = 0
|
|
1303
|
-
const downgraded = []
|
|
1304
|
-
|
|
1305
|
-
for (const tf of taskFiles) {
|
|
1306
|
-
const taskId = tf.replace(/\.md$/, '')
|
|
1307
|
-
const reviewPath = join(runtimeRoot, 'execute-runs', executeRunId, 'tasks', taskId, 'review.json')
|
|
1308
|
-
if (!existsSync(reviewPath)) {
|
|
1309
|
-
missing++
|
|
1310
|
-
continue
|
|
1311
|
-
}
|
|
1312
|
-
|
|
1313
|
-
const existing = readReview(reviewPath)
|
|
1314
|
-
if (existing.parseError) {
|
|
1315
|
-
skipped++
|
|
1316
|
-
reasons.push(`${taskId}: JSON 解析失败,adopt 不猜字段——先修 JSON 再重跑`)
|
|
1317
|
-
continue
|
|
1318
|
-
}
|
|
1319
|
-
const prev = existing.review || {}
|
|
1320
|
-
|
|
1321
|
-
const content = readFileSync(join(tasksDir, tf), 'utf8')
|
|
1322
|
-
const allowedPaths = parseAllowedPaths(content)
|
|
1323
|
-
const taskRepo = normalizeRepoKey(parseRepo(content))
|
|
1324
|
-
const crossEntry = (ctx && taskRepo !== DEFAULT_REPO_KEY) ? ctx.resolve(taskRepo) : null
|
|
1325
|
-
let taskBase = base
|
|
1326
|
-
let taskHead = head
|
|
1327
|
-
let taskChangedFiles
|
|
1328
|
-
let draftRepo
|
|
1329
|
-
|
|
1330
|
-
if (crossEntry) {
|
|
1331
|
-
const baseCommit = parseBaseCommit(content)
|
|
1332
|
-
const headCommit = parseHeadCommit(content)
|
|
1333
|
-
if (!baseCommit || !headCommit) {
|
|
1334
|
-
skipped++
|
|
1335
|
-
reasons.push(`${taskId}: 跨仓 task 卡缺 base/head 锡点,无法 adopt`)
|
|
1336
|
-
continue
|
|
1337
|
-
}
|
|
1338
|
-
taskBase = baseCommit
|
|
1339
|
-
taskHead = headCommit
|
|
1340
|
-
draftRepo = taskRepo
|
|
1341
|
-
let crossDiffFiles = []
|
|
1342
|
-
try {
|
|
1343
|
-
const out = runGit(crossEntry.gitDir, ['diff', '--name-only', `${baseCommit}..${headCommit}`])
|
|
1344
|
-
crossDiffFiles = out ? out.split('\n').filter(Boolean).map(p => p.replace(/\\/g, '/')) : []
|
|
1345
|
-
} catch {
|
|
1346
|
-
skipped++
|
|
1347
|
-
reasons.push(`${taskId}: 跨仓 git diff 失败(${crossEntry.gitDir})`)
|
|
1348
|
-
continue
|
|
1349
|
-
}
|
|
1350
|
-
taskChangedFiles = allowedPaths.length > 0
|
|
1351
|
-
? crossDiffFiles.filter(f => allowedPaths.some(p => pathMatches(f, p)))
|
|
1352
|
-
: crossDiffFiles
|
|
1353
|
-
} else {
|
|
1354
|
-
const mainDiff = Array.isArray(diffFiles) ? diffFiles : []
|
|
1355
|
-
taskChangedFiles = allowedPaths.length > 0
|
|
1356
|
-
? mainDiff.filter(f => allowedPaths.some(p => pathMatches(f, p)))
|
|
1357
|
-
: []
|
|
1358
|
-
}
|
|
1359
|
-
|
|
1360
|
-
if (!crossEntry && (!taskBase || !taskHead)) {
|
|
1361
|
-
skipped++
|
|
1362
|
-
reasons.push(`${taskId}: 主仓缺 worktree meta base/head,无法 adopt`)
|
|
1363
|
-
continue
|
|
1364
|
-
}
|
|
1365
|
-
|
|
1366
|
-
const merged = { ...prev }
|
|
1367
|
-
merged.schemaVersion = REVIEW_SCHEMA_VERSION
|
|
1368
|
-
merged.task = taskId
|
|
1369
|
-
merged.base = taskBase
|
|
1370
|
-
merged.head = taskHead
|
|
1371
|
-
merged.changedFiles = taskChangedFiles
|
|
1372
|
-
if (draftRepo) merged.repo = draftRepo
|
|
1373
|
-
|
|
1374
|
-
let verdictTouched = false
|
|
1375
|
-
for (const v of ['specVerdict', 'qualityVerdict']) {
|
|
1376
|
-
if (!VALID_VERDICTS.includes(merged[v])) {
|
|
1377
|
-
merged[v] = 'cannot_verify'
|
|
1378
|
-
verdictTouched = true
|
|
1379
|
-
}
|
|
1380
|
-
}
|
|
1381
|
-
if (verdictTouched) downgraded.push(taskId)
|
|
1382
|
-
let evidenceFilled = false
|
|
1383
|
-
if ((merged.specVerdict === 'cannot_verify' || merged.qualityVerdict === 'cannot_verify')
|
|
1384
|
-
&& (!Array.isArray(merged.requiredEvidence) || merged.requiredEvidence.length === 0)) {
|
|
1385
|
-
merged.requiredEvidence = [`adopt 代填:原 review 缺 requiredEvidence(verdict=${merged.specVerdict}/${merged.qualityVerdict}),待人工复核补证据`]
|
|
1386
|
-
evidenceFilled = true
|
|
1387
|
-
}
|
|
1388
|
-
if (verdictTouched) {
|
|
1389
|
-
merged.reviewerNotes = String(merged.reviewerNotes || '') + (merged.reviewerNotes ? '; ' : '')
|
|
1390
|
-
+ 'adopt: 原 verdict 非法/缺失已降级 cannot_verify(不猜本意)'
|
|
1391
|
-
}
|
|
1392
|
-
|
|
1393
|
-
const mechanicsChanged = prev.schemaVersion !== merged.schemaVersion
|
|
1394
|
-
|| prev.base !== merged.base
|
|
1395
|
-
|| prev.head !== merged.head
|
|
1396
|
-
|| JSON.stringify(prev.changedFiles ?? null) !== JSON.stringify(merged.changedFiles)
|
|
1397
|
-
|| prev.repo !== merged.repo
|
|
1398
|
-
|
|
1399
|
-
try {
|
|
1400
|
-
if (mechanicsChanged || verdictTouched || evidenceFilled) {
|
|
1401
|
-
writeFileSync(reviewPath, JSON.stringify(merged, null, 2) + '\n')
|
|
1402
|
-
adopted++
|
|
1403
|
-
} else {
|
|
1404
|
-
unchanged++
|
|
1405
|
-
}
|
|
1406
|
-
} catch (e) {
|
|
1407
|
-
skipped++
|
|
1408
|
-
reasons.push(`${taskId}: 写回失败 ${e.message}`)
|
|
1409
|
-
}
|
|
1410
|
-
}
|
|
1411
|
-
|
|
1412
|
-
return { adopted, unchanged, skipped, missing, downgraded, reasons, executeRunId }
|
|
1413
|
-
}
|
|
1414
|
-
|
|
1415
|
-
/**
|
|
1416
|
-
* 获取当前(或最新)execute run id
|
|
1417
|
-
* 从 runtime 目录下查找 execute-runs/ 子目录
|
|
1418
|
-
*
|
|
1419
|
-
* @param {string} runtimeRoot - .sillyspec/.runtime 路径
|
|
1420
|
-
* @returns {string|null} 最新 run id,null 表示无任何 run
|
|
1421
|
-
*/
|
|
1422
|
-
/**
|
|
1423
|
-
* 获取当前 execute run id
|
|
1424
|
-
* 优先从 current-execute-run-id 标记文件读取(execute 阶段启动时写入),
|
|
1425
|
-
* fallback 到 execute-runs/ 下最新的 exec- 前缀目录。
|
|
1426
|
-
*
|
|
1427
|
-
* @param {string} runtimeRoot - .sillyspec/.runtime 路径
|
|
1428
|
-
* @returns {string|null} 当前 run id,null 表示无任何 run
|
|
1429
|
-
*/
|
|
1430
|
-
export function getLatestExecuteRunId(runtimeRoot) {
|
|
1431
|
-
// 优先读标记文件(execute 阶段启动时由 run.js 写入,生命周期内不变)
|
|
1432
|
-
const markerPath = join(runtimeRoot, 'current-execute-run-id')
|
|
1433
|
-
try {
|
|
1434
|
-
if (existsSync(markerPath)) {
|
|
1435
|
-
const content = readFileSync(markerPath, 'utf8').trim()
|
|
1436
|
-
if (content && !isValidExecuteRunId(content)) console.warn(`[sillyspec] execute run marker 内容非法(期望 exec-YYYY-MM-DD-HHMMSS,实得 ${JSON.stringify(content.slice(0, 60))}),忽略并回退目录扫描`)
|
|
1437
|
-
if (isValidExecuteRunId(content)) return content
|
|
1438
|
-
}
|
|
1439
|
-
} catch {}
|
|
1440
|
-
|
|
1441
|
-
// fallback:扫描 execute-runs/ 目录
|
|
1442
|
-
const runsDir = join(runtimeRoot, 'execute-runs')
|
|
1443
|
-
if (!existsSync(runsDir)) return null
|
|
1444
|
-
|
|
1445
|
-
try {
|
|
1446
|
-
const entries = readdirSync(runsDir, { withFileTypes: true })
|
|
1447
|
-
.filter(e => e.isDirectory() && e.name.startsWith('exec-'))
|
|
1448
|
-
.map(e => e.name)
|
|
1449
|
-
.sort()
|
|
1450
|
-
.reverse()
|
|
1451
|
-
return entries[0] || null
|
|
1452
|
-
} catch {
|
|
1453
|
-
return null
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
|
-
/**
|
|
1458
|
-
* 确保 task review 目录存在
|
|
1459
|
-
* @param {string} runtimeRoot
|
|
1460
|
-
* @param {string} executeRunId
|
|
1461
|
-
* @param {string} taskId
|
|
1462
|
-
* @returns {string} task review 目录路径
|
|
1463
|
-
*/
|
|
1464
|
-
export function ensureTaskReviewDir(runtimeRoot, executeRunId, taskId) {
|
|
1465
|
-
const dir = join(runtimeRoot, 'execute-runs', executeRunId, 'tasks', taskId)
|
|
1466
|
-
mkdirSync(dir, { recursive: true })
|
|
1467
|
-
return dir
|
|
1468
|
-
}
|
|
1469
|
-
|
|
1470
|
-
/**
|
|
1471
|
-
* 打印校验结果
|
|
1472
|
-
* @param {{ ok: boolean, errors: string[], warnings: string[], requiredEvidence: Array }} result
|
|
1473
|
-
*/
|
|
1474
|
-
export function printReviewResult(result, context = {}) {
|
|
1475
|
-
if (result.ok && result.warnings.length === 0) {
|
|
1476
|
-
console.log('\n✅ Task Review Gate — 所有任务评审通过')
|
|
1477
|
-
return
|
|
1478
|
-
}
|
|
1479
|
-
|
|
1480
|
-
if (result.errors.length > 0) {
|
|
1481
|
-
console.error('\n🚫 Task Review Gate — FAILED')
|
|
1482
|
-
for (const err of result.errors) {
|
|
1483
|
-
console.error(` - ${err}`)
|
|
1484
|
-
}
|
|
1485
|
-
const hint = context.runtimeRoot && context.executeRunId
|
|
1486
|
-
? `期望路径:${context.runtimeRoot}/execute-runs/${context.executeRunId}/tasks/<task-XX>/review.json`
|
|
1487
|
-
: '为缺失/失败的任务补充 review.json'
|
|
1488
|
-
console.error(`\n 提示:${hint},然后重新 --done`)
|
|
1489
|
-
}
|
|
1490
|
-
|
|
1491
|
-
if (result.warnings.length > 0) {
|
|
1492
|
-
console.warn('\n⚠️ Task Review Gate — WARNING')
|
|
1493
|
-
for (const w of result.warnings) {
|
|
1494
|
-
console.warn(` - ${w}`)
|
|
1495
|
-
}
|
|
1496
|
-
console.warn('\n cannot_verify 的 requiredEvidence 将在 verify 阶段校验')
|
|
1497
|
-
}
|
|
1498
|
-
}
|