sillyspec 3.27.6 → 3.27.9
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-archive/SKILL.md +87 -87
- package/.claude/skills/sillyspec-auto/SKILL.md +93 -93
- package/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -114
- package/.claude/skills/sillyspec-commit/SKILL.md +67 -67
- package/.claude/skills/sillyspec-continue/SKILL.md +47 -47
- package/.claude/skills/sillyspec-doctor/SKILL.md +76 -76
- package/.claude/skills/sillyspec-execute/SKILL.md +214 -214
- package/.claude/skills/sillyspec-explore/SKILL.md +102 -102
- package/.claude/skills/sillyspec-export/SKILL.md +57 -57
- package/.claude/skills/sillyspec-init/SKILL.md +177 -177
- package/.claude/skills/sillyspec-knowledge/SKILL.md +269 -269
- package/.claude/skills/sillyspec-plan/SKILL.md +156 -156
- package/.claude/skills/sillyspec-propose/SKILL.md +87 -0
- package/.claude/skills/sillyspec-quick/SKILL.md +116 -116
- package/.claude/skills/sillyspec-resume/SKILL.md +70 -70
- package/.claude/skills/sillyspec-scan/SKILL.md +79 -79
- package/.claude/skills/sillyspec-state/SKILL.md +64 -64
- package/.claude/skills/sillyspec-status/SKILL.md +54 -54
- package/.claude/skills/sillyspec-verify/SKILL.md +87 -87
- package/.claude/skills/sillyspec-workspace/SKILL.md +175 -175
- package/.claude/skills/verify-per-user/SKILL.md +6 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-archive/SKILL.md +87 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-auto/SKILL.md +93 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-commit/SKILL.md +67 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-continue/SKILL.md +47 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-execute/SKILL.md +214 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-explore/SKILL.md +102 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-export/SKILL.md +57 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-init/SKILL.md +177 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-plan/SKILL.md +156 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-propose/SKILL.md +87 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-quick/SKILL.md +116 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-resume/SKILL.md +70 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-scan/SKILL.md +79 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-state/SKILL.md +64 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-status/SKILL.md +54 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-verify/SKILL.md +87 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
- package/.worktrees/2c37b1d7/.claude/skills/verify-per-user/SKILL.md +6 -0
- package/.worktrees/2c37b1d7/.gitattributes +2 -0
- package/.worktrees/2c37b1d7/.husky/pre-push +20 -0
- package/.worktrees/2c37b1d7/README.md +203 -0
- package/.worktrees/2c37b1d7/SKILL.md +91 -0
- package/.worktrees/2c37b1d7/architecture-analysis.md +448 -0
- package/.worktrees/2c37b1d7/bin/sillyspec.js +2 -0
- package/.worktrees/2c37b1d7/eval/README.md +86 -0
- package/.worktrees/2c37b1d7/eval/eval.config.json +28 -0
- package/.worktrees/2c37b1d7/eval/lib/adapters/cli.mjs +63 -0
- package/.worktrees/2c37b1d7/eval/lib/adapters/dryrun.mjs +27 -0
- package/.worktrees/2c37b1d7/eval/lib/config.mjs +82 -0
- package/.worktrees/2c37b1d7/eval/lib/db.mjs +76 -0
- package/.worktrees/2c37b1d7/eval/lib/report.mjs +120 -0
- package/.worktrees/2c37b1d7/eval/lib/runner.mjs +157 -0
- package/.worktrees/2c37b1d7/eval/lib/tasks.mjs +73 -0
- package/.worktrees/2c37b1d7/eval/lib/util.mjs +107 -0
- package/.worktrees/2c37b1d7/eval/lib/workdir.mjs +30 -0
- package/.worktrees/2c37b1d7/eval/run.mjs +83 -0
- package/.worktrees/2c37b1d7/eval/tasks/001-slugify/files/package.json +6 -0
- package/.worktrees/2c37b1d7/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
- package/.worktrees/2c37b1d7/eval/tasks/001-slugify/task.json +6 -0
- package/.worktrees/2c37b1d7/eval/tasks/001-slugify/verify.mjs +28 -0
- package/.worktrees/2c37b1d7/eval/tasks/002-each-day/files/package.json +6 -0
- package/.worktrees/2c37b1d7/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
- package/.worktrees/2c37b1d7/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
- package/.worktrees/2c37b1d7/eval/tasks/002-each-day/task.json +6 -0
- package/.worktrees/2c37b1d7/eval/tasks/002-each-day/verify.mjs +31 -0
- package/.worktrees/2c37b1d7/eval/tasks/003-word-report/files/data/notes.txt +5 -0
- package/.worktrees/2c37b1d7/eval/tasks/003-word-report/files/package.json +6 -0
- package/.worktrees/2c37b1d7/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
- package/.worktrees/2c37b1d7/eval/tasks/003-word-report/task.json +6 -0
- package/.worktrees/2c37b1d7/eval/tasks/003-word-report/verify.mjs +38 -0
- package/.worktrees/2c37b1d7/logo.jpg +0 -0
- package/.worktrees/2c37b1d7/package-lock.json +977 -0
- package/.worktrees/2c37b1d7/package.json +41 -0
- package/.worktrees/2c37b1d7/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
- package/.worktrees/2c37b1d7/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
- package/.worktrees/2c37b1d7/packages/dashboard/dist/favicon.jpg +0 -0
- package/.worktrees/2c37b1d7/packages/dashboard/dist/index.html +16 -0
- package/.worktrees/2c37b1d7/packages/dashboard/dist/logo.jpg +0 -0
- package/.worktrees/2c37b1d7/packages/dashboard/dist/prototype-dashboard.html +836 -0
- package/.worktrees/2c37b1d7/packages/dashboard/dist/prototype-overview.html +256 -0
- package/.worktrees/2c37b1d7/packages/dashboard/package.json +25 -0
- package/.worktrees/2c37b1d7/packages/dashboard/server/executor.js +95 -0
- package/.worktrees/2c37b1d7/packages/dashboard/server/index.js +679 -0
- package/.worktrees/2c37b1d7/packages/dashboard/server/parser.js +526 -0
- package/.worktrees/2c37b1d7/packages/dashboard/server/watcher.js +357 -0
- package/.worktrees/2c37b1d7/src/agent-session-log.js +803 -0
- package/.worktrees/2c37b1d7/src/change-list.js +290 -0
- package/.worktrees/2c37b1d7/src/change-risk-profile.js +339 -0
- package/.worktrees/2c37b1d7/src/check-primitives.js +65 -0
- package/.worktrees/2c37b1d7/src/classify-change.js +109 -0
- package/.worktrees/2c37b1d7/src/commit-suggest.js +202 -0
- package/.worktrees/2c37b1d7/src/config-cat.js +88 -0
- package/.worktrees/2c37b1d7/src/config-schema.js +328 -0
- package/.worktrees/2c37b1d7/src/constants.js +97 -0
- package/.worktrees/2c37b1d7/src/contract-matrix.js +533 -0
- package/.worktrees/2c37b1d7/src/datetime.js +20 -0
- package/.worktrees/2c37b1d7/src/db-engine.js +55 -0
- package/.worktrees/2c37b1d7/src/db.js +381 -0
- package/.worktrees/2c37b1d7/src/decision-distill.js +517 -0
- package/.worktrees/2c37b1d7/src/dispatch/backends/local-agent.js +155 -0
- package/.worktrees/2c37b1d7/src/dispatch/backends/sillyhub-mcp.js +245 -0
- package/.worktrees/2c37b1d7/src/dispatch/probe.js +246 -0
- package/.worktrees/2c37b1d7/src/dispatch/strategy.js +121 -0
- package/.worktrees/2c37b1d7/src/docs-check.js +825 -0
- package/.worktrees/2c37b1d7/src/docs-debt.js +393 -0
- package/.worktrees/2c37b1d7/src/docs-gate.js +107 -0
- package/.worktrees/2c37b1d7/src/doctor-diagnostics.js +1099 -0
- package/.worktrees/2c37b1d7/src/endpoint-extractor.js +409 -0
- package/.worktrees/2c37b1d7/src/foreign-declared.js +155 -0
- package/.worktrees/2c37b1d7/src/fs-atomic.js +73 -0
- package/.worktrees/2c37b1d7/src/git-helper.js +150 -0
- package/.worktrees/2c37b1d7/src/hooks/claude-pre-tool-use.cjs +130 -0
- package/.worktrees/2c37b1d7/src/hooks/worktree-guard.js +892 -0
- package/.worktrees/2c37b1d7/src/index.js +2854 -0
- package/.worktrees/2c37b1d7/src/init.js +626 -0
- package/.worktrees/2c37b1d7/src/knowledge-match.js +231 -0
- package/.worktrees/2c37b1d7/src/local-detect.js +128 -0
- package/.worktrees/2c37b1d7/src/local-register.js +104 -0
- package/.worktrees/2c37b1d7/src/machine-interface.js +543 -0
- package/.worktrees/2c37b1d7/src/migrate.js +127 -0
- package/.worktrees/2c37b1d7/src/module-impact.js +166 -0
- package/.worktrees/2c37b1d7/src/module-resolve.js +222 -0
- package/.worktrees/2c37b1d7/src/modules.js +580 -0
- package/.worktrees/2c37b1d7/src/plan-adopt-waves.js +126 -0
- package/.worktrees/2c37b1d7/src/progress/change-registry.js +336 -0
- package/.worktrees/2c37b1d7/src/progress/consistency-doctor.js +355 -0
- package/.worktrees/2c37b1d7/src/progress/shared.js +36 -0
- package/.worktrees/2c37b1d7/src/progress/stage-machine.js +594 -0
- package/.worktrees/2c37b1d7/src/progress/step-store.js +265 -0
- package/.worktrees/2c37b1d7/src/progress.js +1304 -0
- package/.worktrees/2c37b1d7/src/quick-recommend.js +115 -0
- package/.worktrees/2c37b1d7/src/quicklog.js +883 -0
- package/.worktrees/2c37b1d7/src/review-tier.js +77 -0
- package/.worktrees/2c37b1d7/src/run/command.js +1641 -0
- package/.worktrees/2c37b1d7/src/run/complete-handlers.js +1552 -0
- package/.worktrees/2c37b1d7/src/run/complete.js +1259 -0
- package/.worktrees/2c37b1d7/src/run/concurrent-detect.js +156 -0
- package/.worktrees/2c37b1d7/src/run/gates.js +1111 -0
- package/.worktrees/2c37b1d7/src/run/multi-repo-context.js +208 -0
- package/.worktrees/2c37b1d7/src/run/next.js +128 -0
- package/.worktrees/2c37b1d7/src/run/prompt.js +843 -0
- package/.worktrees/2c37b1d7/src/run/quick-audit.js +186 -0
- package/.worktrees/2c37b1d7/src/run/scan-profile.js +269 -0
- package/.worktrees/2c37b1d7/src/run/shared.js +1562 -0
- package/.worktrees/2c37b1d7/src/run/stage.js +587 -0
- package/.worktrees/2c37b1d7/src/run.js +23 -0
- package/.worktrees/2c37b1d7/src/scan-diff.js +388 -0
- package/.worktrees/2c37b1d7/src/scan-postcheck.js +524 -0
- package/.worktrees/2c37b1d7/src/scan-staleness.js +95 -0
- package/.worktrees/2c37b1d7/src/setup.js +414 -0
- package/.worktrees/2c37b1d7/src/sillyhub-mcp/client.js +597 -0
- package/.worktrees/2c37b1d7/src/sillyhub-mcp/config.js +62 -0
- package/.worktrees/2c37b1d7/src/spec-dir-typo.js +50 -0
- package/.worktrees/2c37b1d7/src/spec-sync.js +358 -0
- package/.worktrees/2c37b1d7/src/stage-contract-engine.js +171 -0
- package/.worktrees/2c37b1d7/src/stage-contract-spec.js +551 -0
- package/.worktrees/2c37b1d7/src/stage-contract.js +948 -0
- package/.worktrees/2c37b1d7/src/stage-review.js +597 -0
- package/.worktrees/2c37b1d7/src/stages/archive.js +199 -0
- package/.worktrees/2c37b1d7/src/stages/brainstorm-auto.js +285 -0
- package/.worktrees/2c37b1d7/src/stages/brainstorm.js +624 -0
- package/.worktrees/2c37b1d7/src/stages/cmd-existence.js +145 -0
- package/.worktrees/2c37b1d7/src/stages/doctor.js +540 -0
- package/.worktrees/2c37b1d7/src/stages/execute.js +1277 -0
- package/.worktrees/2c37b1d7/src/stages/explore.js +43 -0
- package/.worktrees/2c37b1d7/src/stages/index.js +29 -0
- package/.worktrees/2c37b1d7/src/stages/knowledge.js +514 -0
- package/.worktrees/2c37b1d7/src/stages/plan-postcheck.js +1398 -0
- package/.worktrees/2c37b1d7/src/stages/plan.js +655 -0
- package/.worktrees/2c37b1d7/src/stages/quick.js +167 -0
- package/.worktrees/2c37b1d7/src/stages/scan.js +608 -0
- package/.worktrees/2c37b1d7/src/stages/status.js +64 -0
- package/.worktrees/2c37b1d7/src/stages/verify.js +246 -0
- package/.worktrees/2c37b1d7/src/sync.js +1470 -0
- package/.worktrees/2c37b1d7/src/task-review.js +1498 -0
- package/.worktrees/2c37b1d7/src/taskcard-placeholders.js +21 -0
- package/.worktrees/2c37b1d7/src/taskcard.js +250 -0
- package/.worktrees/2c37b1d7/src/verify-postcheck.js +1718 -0
- package/.worktrees/2c37b1d7/src/verify-probes.js +327 -0
- package/.worktrees/2c37b1d7/src/version.js +19 -0
- package/.worktrees/2c37b1d7/src/workflow.js +600 -0
- package/.worktrees/2c37b1d7/src/workspace.js +125 -0
- package/.worktrees/2c37b1d7/src/worktree-apply.js +1611 -0
- package/.worktrees/2c37b1d7/src/worktree-deps.js +668 -0
- package/.worktrees/2c37b1d7/src/worktree.js +1849 -0
- package/.worktrees/2c37b1d7/templates/claude-instruction.md +23 -0
- package/.worktrees/2c37b1d7/templates/prompts/taskcard-rules.md +29 -0
- package/.worktrees/2c37b1d7/templates/prompts/testcase-design.md +12 -0
- package/.worktrees/2c37b1d7/templates/prompts/verify-probes.md +32 -0
- package/.worktrees/2c37b1d7/templates/workflows/archive-impact.yaml +79 -0
- package/.worktrees/2c37b1d7/templates/workflows/scan-docs.yaml +132 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-archive/SKILL.md +87 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-auto/SKILL.md +93 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-commit/SKILL.md +67 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-continue/SKILL.md +47 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-execute/SKILL.md +214 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-explore/SKILL.md +102 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-export/SKILL.md +57 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-init/SKILL.md +177 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-plan/SKILL.md +156 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-quick/SKILL.md +116 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-resume/SKILL.md +70 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-scan/SKILL.md +79 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-state/SKILL.md +64 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-status/SKILL.md +54 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-verify/SKILL.md +87 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
- package/.worktrees/542c4415/.gitattributes +2 -0
- package/.worktrees/542c4415/.husky/pre-push +20 -0
- package/.worktrees/542c4415/README.md +203 -0
- package/.worktrees/542c4415/SKILL.md +91 -0
- package/.worktrees/542c4415/architecture-analysis.md +448 -0
- package/.worktrees/542c4415/bin/sillyspec.js +2 -0
- package/.worktrees/542c4415/eval/README.md +86 -0
- package/.worktrees/542c4415/eval/eval.config.json +28 -0
- package/.worktrees/542c4415/eval/lib/adapters/cli.mjs +63 -0
- package/.worktrees/542c4415/eval/lib/adapters/dryrun.mjs +27 -0
- package/.worktrees/542c4415/eval/lib/config.mjs +82 -0
- package/.worktrees/542c4415/eval/lib/db.mjs +76 -0
- package/.worktrees/542c4415/eval/lib/report.mjs +120 -0
- package/.worktrees/542c4415/eval/lib/runner.mjs +157 -0
- package/.worktrees/542c4415/eval/lib/tasks.mjs +73 -0
- package/.worktrees/542c4415/eval/lib/util.mjs +107 -0
- package/.worktrees/542c4415/eval/lib/workdir.mjs +30 -0
- package/.worktrees/542c4415/eval/run.mjs +83 -0
- package/.worktrees/542c4415/eval/tasks/001-slugify/files/package.json +6 -0
- package/.worktrees/542c4415/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
- package/.worktrees/542c4415/eval/tasks/001-slugify/task.json +6 -0
- package/.worktrees/542c4415/eval/tasks/001-slugify/verify.mjs +28 -0
- package/.worktrees/542c4415/eval/tasks/002-each-day/files/package.json +6 -0
- package/.worktrees/542c4415/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
- package/.worktrees/542c4415/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
- package/.worktrees/542c4415/eval/tasks/002-each-day/task.json +6 -0
- package/.worktrees/542c4415/eval/tasks/002-each-day/verify.mjs +31 -0
- package/.worktrees/542c4415/eval/tasks/003-word-report/files/data/notes.txt +5 -0
- package/.worktrees/542c4415/eval/tasks/003-word-report/files/package.json +6 -0
- package/.worktrees/542c4415/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
- package/.worktrees/542c4415/eval/tasks/003-word-report/task.json +6 -0
- package/.worktrees/542c4415/eval/tasks/003-word-report/verify.mjs +38 -0
- package/.worktrees/542c4415/logo.jpg +0 -0
- package/.worktrees/542c4415/package-lock.json +977 -0
- package/.worktrees/542c4415/package.json +41 -0
- package/.worktrees/542c4415/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
- package/.worktrees/542c4415/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
- package/.worktrees/542c4415/packages/dashboard/dist/favicon.jpg +0 -0
- package/.worktrees/542c4415/packages/dashboard/dist/index.html +16 -0
- package/.worktrees/542c4415/packages/dashboard/dist/logo.jpg +0 -0
- package/.worktrees/542c4415/packages/dashboard/dist/prototype-dashboard.html +836 -0
- package/.worktrees/542c4415/packages/dashboard/dist/prototype-overview.html +256 -0
- package/.worktrees/542c4415/packages/dashboard/package.json +25 -0
- package/.worktrees/542c4415/packages/dashboard/server/executor.js +95 -0
- package/.worktrees/542c4415/packages/dashboard/server/index.js +679 -0
- package/.worktrees/542c4415/packages/dashboard/server/parser.js +526 -0
- package/.worktrees/542c4415/packages/dashboard/server/watcher.js +357 -0
- package/.worktrees/542c4415/src/agent-session-log.js +803 -0
- package/.worktrees/542c4415/src/change-list.js +290 -0
- package/.worktrees/542c4415/src/change-risk-profile.js +339 -0
- package/.worktrees/542c4415/src/check-primitives.js +65 -0
- package/.worktrees/542c4415/src/classify-change.js +109 -0
- package/.worktrees/542c4415/src/commit-suggest.js +202 -0
- package/.worktrees/542c4415/src/config-cat.js +88 -0
- package/.worktrees/542c4415/src/config-schema.js +328 -0
- package/.worktrees/542c4415/src/constants.js +97 -0
- package/.worktrees/542c4415/src/contract-matrix.js +533 -0
- package/.worktrees/542c4415/src/datetime.js +20 -0
- package/.worktrees/542c4415/src/db-engine.js +55 -0
- package/.worktrees/542c4415/src/db.js +381 -0
- package/.worktrees/542c4415/src/decision-distill.js +517 -0
- package/.worktrees/542c4415/src/dispatch/backends/local-agent.js +155 -0
- package/.worktrees/542c4415/src/dispatch/backends/sillyhub-mcp.js +245 -0
- package/.worktrees/542c4415/src/dispatch/probe.js +246 -0
- package/.worktrees/542c4415/src/dispatch/strategy.js +121 -0
- package/.worktrees/542c4415/src/docs-check.js +825 -0
- package/.worktrees/542c4415/src/docs-debt.js +393 -0
- package/.worktrees/542c4415/src/docs-gate.js +107 -0
- package/.worktrees/542c4415/src/doctor-diagnostics.js +1099 -0
- package/.worktrees/542c4415/src/endpoint-extractor.js +409 -0
- package/.worktrees/542c4415/src/foreign-declared.js +155 -0
- package/.worktrees/542c4415/src/fs-atomic.js +73 -0
- package/.worktrees/542c4415/src/git-helper.js +150 -0
- package/.worktrees/542c4415/src/hooks/claude-pre-tool-use.cjs +130 -0
- package/.worktrees/542c4415/src/hooks/worktree-guard.js +892 -0
- package/.worktrees/542c4415/src/index.js +2854 -0
- package/.worktrees/542c4415/src/init.js +626 -0
- package/.worktrees/542c4415/src/knowledge-match.js +231 -0
- package/.worktrees/542c4415/src/local-detect.js +128 -0
- package/.worktrees/542c4415/src/local-register.js +104 -0
- package/.worktrees/542c4415/src/machine-interface.js +543 -0
- package/.worktrees/542c4415/src/migrate.js +127 -0
- package/.worktrees/542c4415/src/module-impact.js +166 -0
- package/.worktrees/542c4415/src/module-resolve.js +222 -0
- package/.worktrees/542c4415/src/modules.js +580 -0
- package/.worktrees/542c4415/src/plan-adopt-waves.js +126 -0
- package/.worktrees/542c4415/src/progress/change-registry.js +336 -0
- package/.worktrees/542c4415/src/progress/consistency-doctor.js +355 -0
- package/.worktrees/542c4415/src/progress/shared.js +36 -0
- package/.worktrees/542c4415/src/progress/stage-machine.js +594 -0
- package/.worktrees/542c4415/src/progress/step-store.js +265 -0
- package/.worktrees/542c4415/src/progress.js +1304 -0
- package/.worktrees/542c4415/src/quick-recommend.js +115 -0
- package/.worktrees/542c4415/src/quicklog.js +883 -0
- package/.worktrees/542c4415/src/review-tier.js +77 -0
- package/.worktrees/542c4415/src/run/command.js +1641 -0
- package/.worktrees/542c4415/src/run/complete-handlers.js +1552 -0
- package/.worktrees/542c4415/src/run/complete.js +1259 -0
- package/.worktrees/542c4415/src/run/concurrent-detect.js +156 -0
- package/.worktrees/542c4415/src/run/gates.js +1111 -0
- package/.worktrees/542c4415/src/run/multi-repo-context.js +208 -0
- package/.worktrees/542c4415/src/run/next.js +128 -0
- package/.worktrees/542c4415/src/run/prompt.js +843 -0
- package/.worktrees/542c4415/src/run/quick-audit.js +186 -0
- package/.worktrees/542c4415/src/run/scan-profile.js +269 -0
- package/.worktrees/542c4415/src/run/shared.js +1562 -0
- package/.worktrees/542c4415/src/run/stage.js +587 -0
- package/.worktrees/542c4415/src/run.js +23 -0
- package/.worktrees/542c4415/src/scan-diff.js +388 -0
- package/.worktrees/542c4415/src/scan-postcheck.js +524 -0
- package/.worktrees/542c4415/src/scan-staleness.js +95 -0
- package/.worktrees/542c4415/src/setup.js +414 -0
- package/.worktrees/542c4415/src/sillyhub-mcp/client.js +597 -0
- package/.worktrees/542c4415/src/sillyhub-mcp/config.js +62 -0
- package/.worktrees/542c4415/src/spec-dir-typo.js +50 -0
- package/.worktrees/542c4415/src/spec-sync.js +358 -0
- package/.worktrees/542c4415/src/stage-contract-engine.js +171 -0
- package/.worktrees/542c4415/src/stage-contract-spec.js +551 -0
- package/.worktrees/542c4415/src/stage-contract.js +948 -0
- package/.worktrees/542c4415/src/stage-review.js +597 -0
- package/.worktrees/542c4415/src/stages/archive.js +199 -0
- package/.worktrees/542c4415/src/stages/brainstorm-auto.js +285 -0
- package/.worktrees/542c4415/src/stages/brainstorm.js +624 -0
- package/.worktrees/542c4415/src/stages/cmd-existence.js +145 -0
- package/.worktrees/542c4415/src/stages/doctor.js +540 -0
- package/.worktrees/542c4415/src/stages/execute.js +1277 -0
- package/.worktrees/542c4415/src/stages/explore.js +43 -0
- package/.worktrees/542c4415/src/stages/index.js +29 -0
- package/.worktrees/542c4415/src/stages/knowledge.js +514 -0
- package/.worktrees/542c4415/src/stages/plan-postcheck.js +1398 -0
- package/.worktrees/542c4415/src/stages/plan.js +655 -0
- package/.worktrees/542c4415/src/stages/quick.js +167 -0
- package/.worktrees/542c4415/src/stages/scan.js +608 -0
- package/.worktrees/542c4415/src/stages/status.js +64 -0
- package/.worktrees/542c4415/src/stages/verify.js +246 -0
- package/.worktrees/542c4415/src/sync.js +1470 -0
- package/.worktrees/542c4415/src/task-review.js +1498 -0
- package/.worktrees/542c4415/src/taskcard-placeholders.js +21 -0
- package/.worktrees/542c4415/src/taskcard.js +250 -0
- package/.worktrees/542c4415/src/verify-postcheck.js +1718 -0
- package/.worktrees/542c4415/src/verify-probes.js +327 -0
- package/.worktrees/542c4415/src/version.js +19 -0
- package/.worktrees/542c4415/src/workflow.js +600 -0
- package/.worktrees/542c4415/src/workspace.js +125 -0
- package/.worktrees/542c4415/src/worktree-apply.js +1611 -0
- package/.worktrees/542c4415/src/worktree-deps.js +668 -0
- package/.worktrees/542c4415/src/worktree.js +1849 -0
- package/.worktrees/542c4415/templates/claude-instruction.md +23 -0
- package/.worktrees/542c4415/templates/prompts/taskcard-rules.md +29 -0
- package/.worktrees/542c4415/templates/prompts/testcase-design.md +12 -0
- package/.worktrees/542c4415/templates/prompts/verify-probes.md +32 -0
- package/.worktrees/542c4415/templates/workflows/archive-impact.yaml +79 -0
- package/.worktrees/542c4415/templates/workflows/scan-docs.yaml +132 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-archive/SKILL.md +87 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-auto/SKILL.md +93 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-commit/SKILL.md +67 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-continue/SKILL.md +47 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-execute/SKILL.md +214 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-explore/SKILL.md +102 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-export/SKILL.md +57 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-init/SKILL.md +177 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-plan/SKILL.md +156 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-quick/SKILL.md +116 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-resume/SKILL.md +70 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-scan/SKILL.md +79 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-state/SKILL.md +64 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-status/SKILL.md +54 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-verify/SKILL.md +87 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
- package/.worktrees/c1eae35e/.gitattributes +2 -0
- package/.worktrees/c1eae35e/.husky/pre-push +20 -0
- package/.worktrees/c1eae35e/README.md +203 -0
- package/.worktrees/c1eae35e/SKILL.md +91 -0
- package/.worktrees/c1eae35e/architecture-analysis.md +448 -0
- package/.worktrees/c1eae35e/bin/sillyspec.js +2 -0
- package/.worktrees/c1eae35e/eval/README.md +86 -0
- package/.worktrees/c1eae35e/eval/eval.config.json +28 -0
- package/.worktrees/c1eae35e/eval/lib/adapters/cli.mjs +63 -0
- package/.worktrees/c1eae35e/eval/lib/adapters/dryrun.mjs +27 -0
- package/.worktrees/c1eae35e/eval/lib/config.mjs +82 -0
- package/.worktrees/c1eae35e/eval/lib/db.mjs +76 -0
- package/.worktrees/c1eae35e/eval/lib/report.mjs +120 -0
- package/.worktrees/c1eae35e/eval/lib/runner.mjs +157 -0
- package/.worktrees/c1eae35e/eval/lib/tasks.mjs +73 -0
- package/.worktrees/c1eae35e/eval/lib/util.mjs +107 -0
- package/.worktrees/c1eae35e/eval/lib/workdir.mjs +30 -0
- package/.worktrees/c1eae35e/eval/run.mjs +83 -0
- package/.worktrees/c1eae35e/eval/tasks/001-slugify/files/package.json +6 -0
- package/.worktrees/c1eae35e/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
- package/.worktrees/c1eae35e/eval/tasks/001-slugify/task.json +6 -0
- package/.worktrees/c1eae35e/eval/tasks/001-slugify/verify.mjs +28 -0
- package/.worktrees/c1eae35e/eval/tasks/002-each-day/files/package.json +6 -0
- package/.worktrees/c1eae35e/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
- package/.worktrees/c1eae35e/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
- package/.worktrees/c1eae35e/eval/tasks/002-each-day/task.json +6 -0
- package/.worktrees/c1eae35e/eval/tasks/002-each-day/verify.mjs +31 -0
- package/.worktrees/c1eae35e/eval/tasks/003-word-report/files/data/notes.txt +5 -0
- package/.worktrees/c1eae35e/eval/tasks/003-word-report/files/package.json +6 -0
- package/.worktrees/c1eae35e/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
- package/.worktrees/c1eae35e/eval/tasks/003-word-report/task.json +6 -0
- package/.worktrees/c1eae35e/eval/tasks/003-word-report/verify.mjs +38 -0
- package/.worktrees/c1eae35e/logo.jpg +0 -0
- package/.worktrees/c1eae35e/package-lock.json +977 -0
- package/.worktrees/c1eae35e/package.json +41 -0
- package/.worktrees/c1eae35e/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
- package/.worktrees/c1eae35e/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
- package/.worktrees/c1eae35e/packages/dashboard/dist/favicon.jpg +0 -0
- package/.worktrees/c1eae35e/packages/dashboard/dist/index.html +16 -0
- package/.worktrees/c1eae35e/packages/dashboard/dist/logo.jpg +0 -0
- package/.worktrees/c1eae35e/packages/dashboard/dist/prototype-dashboard.html +836 -0
- package/.worktrees/c1eae35e/packages/dashboard/dist/prototype-overview.html +256 -0
- package/.worktrees/c1eae35e/packages/dashboard/package.json +25 -0
- package/.worktrees/c1eae35e/packages/dashboard/server/executor.js +95 -0
- package/.worktrees/c1eae35e/packages/dashboard/server/index.js +679 -0
- package/.worktrees/c1eae35e/packages/dashboard/server/parser.js +526 -0
- package/.worktrees/c1eae35e/packages/dashboard/server/watcher.js +357 -0
- package/.worktrees/c1eae35e/src/agent-session-log.js +803 -0
- package/.worktrees/c1eae35e/src/change-list.js +290 -0
- package/.worktrees/c1eae35e/src/change-risk-profile.js +339 -0
- package/.worktrees/c1eae35e/src/check-primitives.js +65 -0
- package/.worktrees/c1eae35e/src/classify-change.js +109 -0
- package/.worktrees/c1eae35e/src/commit-suggest.js +202 -0
- package/.worktrees/c1eae35e/src/config-cat.js +88 -0
- package/.worktrees/c1eae35e/src/config-schema.js +328 -0
- package/.worktrees/c1eae35e/src/constants.js +97 -0
- package/.worktrees/c1eae35e/src/contract-matrix.js +533 -0
- package/.worktrees/c1eae35e/src/datetime.js +20 -0
- package/.worktrees/c1eae35e/src/db-engine.js +55 -0
- package/.worktrees/c1eae35e/src/db.js +381 -0
- package/.worktrees/c1eae35e/src/decision-distill.js +517 -0
- package/.worktrees/c1eae35e/src/dispatch/backends/local-agent.js +155 -0
- package/.worktrees/c1eae35e/src/dispatch/backends/sillyhub-mcp.js +245 -0
- package/.worktrees/c1eae35e/src/dispatch/probe.js +246 -0
- package/.worktrees/c1eae35e/src/dispatch/strategy.js +121 -0
- package/.worktrees/c1eae35e/src/docs-check.js +825 -0
- package/.worktrees/c1eae35e/src/docs-debt.js +393 -0
- package/.worktrees/c1eae35e/src/docs-gate.js +107 -0
- package/.worktrees/c1eae35e/src/doctor-diagnostics.js +1099 -0
- package/.worktrees/c1eae35e/src/endpoint-extractor.js +409 -0
- package/.worktrees/c1eae35e/src/foreign-declared.js +155 -0
- package/.worktrees/c1eae35e/src/fs-atomic.js +73 -0
- package/.worktrees/c1eae35e/src/git-helper.js +150 -0
- package/.worktrees/c1eae35e/src/hooks/claude-pre-tool-use.cjs +130 -0
- package/.worktrees/c1eae35e/src/hooks/worktree-guard.js +892 -0
- package/.worktrees/c1eae35e/src/index.js +2854 -0
- package/.worktrees/c1eae35e/src/init.js +626 -0
- package/.worktrees/c1eae35e/src/knowledge-match.js +231 -0
- package/.worktrees/c1eae35e/src/local-detect.js +128 -0
- package/.worktrees/c1eae35e/src/local-register.js +104 -0
- package/.worktrees/c1eae35e/src/machine-interface.js +543 -0
- package/.worktrees/c1eae35e/src/migrate.js +127 -0
- package/.worktrees/c1eae35e/src/module-impact.js +166 -0
- package/.worktrees/c1eae35e/src/module-resolve.js +222 -0
- package/.worktrees/c1eae35e/src/modules.js +580 -0
- package/.worktrees/c1eae35e/src/plan-adopt-waves.js +126 -0
- package/.worktrees/c1eae35e/src/progress/change-registry.js +336 -0
- package/.worktrees/c1eae35e/src/progress/consistency-doctor.js +355 -0
- package/.worktrees/c1eae35e/src/progress/shared.js +36 -0
- package/.worktrees/c1eae35e/src/progress/stage-machine.js +594 -0
- package/.worktrees/c1eae35e/src/progress/step-store.js +265 -0
- package/.worktrees/c1eae35e/src/progress.js +1304 -0
- package/.worktrees/c1eae35e/src/quick-recommend.js +115 -0
- package/.worktrees/c1eae35e/src/quicklog.js +883 -0
- package/.worktrees/c1eae35e/src/review-tier.js +77 -0
- package/.worktrees/c1eae35e/src/run/command.js +1641 -0
- package/.worktrees/c1eae35e/src/run/complete-handlers.js +1552 -0
- package/.worktrees/c1eae35e/src/run/complete.js +1259 -0
- package/.worktrees/c1eae35e/src/run/concurrent-detect.js +156 -0
- package/.worktrees/c1eae35e/src/run/gates.js +1111 -0
- package/.worktrees/c1eae35e/src/run/multi-repo-context.js +208 -0
- package/.worktrees/c1eae35e/src/run/next.js +128 -0
- package/.worktrees/c1eae35e/src/run/prompt.js +843 -0
- package/.worktrees/c1eae35e/src/run/quick-audit.js +186 -0
- package/.worktrees/c1eae35e/src/run/scan-profile.js +269 -0
- package/.worktrees/c1eae35e/src/run/shared.js +1562 -0
- package/.worktrees/c1eae35e/src/run/stage.js +587 -0
- package/.worktrees/c1eae35e/src/run.js +23 -0
- package/.worktrees/c1eae35e/src/scan-diff.js +388 -0
- package/.worktrees/c1eae35e/src/scan-postcheck.js +524 -0
- package/.worktrees/c1eae35e/src/scan-staleness.js +95 -0
- package/.worktrees/c1eae35e/src/setup.js +414 -0
- package/.worktrees/c1eae35e/src/sillyhub-mcp/client.js +597 -0
- package/.worktrees/c1eae35e/src/sillyhub-mcp/config.js +62 -0
- package/.worktrees/c1eae35e/src/spec-dir-typo.js +50 -0
- package/.worktrees/c1eae35e/src/spec-sync.js +358 -0
- package/.worktrees/c1eae35e/src/stage-contract-engine.js +171 -0
- package/.worktrees/c1eae35e/src/stage-contract-spec.js +551 -0
- package/.worktrees/c1eae35e/src/stage-contract.js +948 -0
- package/.worktrees/c1eae35e/src/stage-review.js +597 -0
- package/.worktrees/c1eae35e/src/stages/archive.js +199 -0
- package/.worktrees/c1eae35e/src/stages/brainstorm-auto.js +285 -0
- package/.worktrees/c1eae35e/src/stages/brainstorm.js +624 -0
- package/.worktrees/c1eae35e/src/stages/cmd-existence.js +145 -0
- package/.worktrees/c1eae35e/src/stages/doctor.js +540 -0
- package/.worktrees/c1eae35e/src/stages/execute.js +1277 -0
- package/.worktrees/c1eae35e/src/stages/explore.js +43 -0
- package/.worktrees/c1eae35e/src/stages/index.js +29 -0
- package/.worktrees/c1eae35e/src/stages/knowledge.js +514 -0
- package/.worktrees/c1eae35e/src/stages/plan-postcheck.js +1398 -0
- package/.worktrees/c1eae35e/src/stages/plan.js +655 -0
- package/.worktrees/c1eae35e/src/stages/quick.js +167 -0
- package/.worktrees/c1eae35e/src/stages/scan.js +608 -0
- package/.worktrees/c1eae35e/src/stages/status.js +64 -0
- package/.worktrees/c1eae35e/src/stages/verify.js +246 -0
- package/.worktrees/c1eae35e/src/sync.js +1470 -0
- package/.worktrees/c1eae35e/src/task-review.js +1498 -0
- package/.worktrees/c1eae35e/src/taskcard-placeholders.js +21 -0
- package/.worktrees/c1eae35e/src/taskcard.js +250 -0
- package/.worktrees/c1eae35e/src/verify-postcheck.js +1718 -0
- package/.worktrees/c1eae35e/src/verify-probes.js +327 -0
- package/.worktrees/c1eae35e/src/version.js +19 -0
- package/.worktrees/c1eae35e/src/workflow.js +600 -0
- package/.worktrees/c1eae35e/src/workspace.js +125 -0
- package/.worktrees/c1eae35e/src/worktree-apply.js +1611 -0
- package/.worktrees/c1eae35e/src/worktree-deps.js +668 -0
- package/.worktrees/c1eae35e/src/worktree.js +1849 -0
- package/.worktrees/c1eae35e/templates/claude-instruction.md +23 -0
- package/.worktrees/c1eae35e/templates/prompts/taskcard-rules.md +29 -0
- package/.worktrees/c1eae35e/templates/prompts/testcase-design.md +12 -0
- package/.worktrees/c1eae35e/templates/prompts/verify-probes.md +32 -0
- package/.worktrees/c1eae35e/templates/workflows/archive-impact.yaml +79 -0
- package/.worktrees/c1eae35e/templates/workflows/scan-docs.yaml +132 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-archive/SKILL.md +87 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-auto/SKILL.md +93 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-commit/SKILL.md +67 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-continue/SKILL.md +47 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-execute/SKILL.md +214 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-explore/SKILL.md +102 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-export/SKILL.md +57 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-init/SKILL.md +177 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-plan/SKILL.md +156 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-propose/SKILL.md +87 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-quick/SKILL.md +116 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-resume/SKILL.md +70 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-scan/SKILL.md +79 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-state/SKILL.md +64 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-status/SKILL.md +54 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-verify/SKILL.md +87 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
- package/.worktrees/dafc71ad/.gitattributes +2 -0
- package/.worktrees/dafc71ad/.husky/pre-push +20 -0
- package/.worktrees/dafc71ad/README.md +203 -0
- package/.worktrees/dafc71ad/SKILL.md +91 -0
- package/.worktrees/dafc71ad/analysis.md +366 -0
- package/.worktrees/dafc71ad/architecture-analysis.md +448 -0
- package/.worktrees/dafc71ad/bin/sillyspec.js +2 -0
- package/.worktrees/dafc71ad/eval/README.md +86 -0
- package/.worktrees/dafc71ad/eval/eval.config.json +28 -0
- package/.worktrees/dafc71ad/eval/lib/adapters/cli.mjs +63 -0
- package/.worktrees/dafc71ad/eval/lib/adapters/dryrun.mjs +27 -0
- package/.worktrees/dafc71ad/eval/lib/config.mjs +82 -0
- package/.worktrees/dafc71ad/eval/lib/db.mjs +76 -0
- package/.worktrees/dafc71ad/eval/lib/report.mjs +120 -0
- package/.worktrees/dafc71ad/eval/lib/runner.mjs +157 -0
- package/.worktrees/dafc71ad/eval/lib/tasks.mjs +73 -0
- package/.worktrees/dafc71ad/eval/lib/util.mjs +107 -0
- package/.worktrees/dafc71ad/eval/lib/workdir.mjs +30 -0
- package/.worktrees/dafc71ad/eval/run.mjs +83 -0
- package/.worktrees/dafc71ad/eval/tasks/001-slugify/files/package.json +6 -0
- package/.worktrees/dafc71ad/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
- package/.worktrees/dafc71ad/eval/tasks/001-slugify/task.json +6 -0
- package/.worktrees/dafc71ad/eval/tasks/001-slugify/verify.mjs +28 -0
- package/.worktrees/dafc71ad/eval/tasks/002-each-day/files/package.json +6 -0
- package/.worktrees/dafc71ad/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
- package/.worktrees/dafc71ad/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
- package/.worktrees/dafc71ad/eval/tasks/002-each-day/task.json +6 -0
- package/.worktrees/dafc71ad/eval/tasks/002-each-day/verify.mjs +31 -0
- package/.worktrees/dafc71ad/eval/tasks/003-word-report/files/data/notes.txt +5 -0
- package/.worktrees/dafc71ad/eval/tasks/003-word-report/files/package.json +6 -0
- package/.worktrees/dafc71ad/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
- package/.worktrees/dafc71ad/eval/tasks/003-word-report/task.json +6 -0
- package/.worktrees/dafc71ad/eval/tasks/003-word-report/verify.mjs +38 -0
- package/.worktrees/dafc71ad/logo.jpg +0 -0
- package/.worktrees/dafc71ad/package-lock.json +977 -0
- package/.worktrees/dafc71ad/package.json +41 -0
- package/.worktrees/dafc71ad/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
- package/.worktrees/dafc71ad/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
- package/.worktrees/dafc71ad/packages/dashboard/dist/favicon.jpg +0 -0
- package/.worktrees/dafc71ad/packages/dashboard/dist/index.html +16 -0
- package/.worktrees/dafc71ad/packages/dashboard/dist/logo.jpg +0 -0
- package/.worktrees/dafc71ad/packages/dashboard/dist/prototype-dashboard.html +836 -0
- package/.worktrees/dafc71ad/packages/dashboard/dist/prototype-overview.html +256 -0
- package/.worktrees/dafc71ad/packages/dashboard/package.json +25 -0
- package/.worktrees/dafc71ad/packages/dashboard/server/executor.js +95 -0
- package/.worktrees/dafc71ad/packages/dashboard/server/index.js +679 -0
- package/.worktrees/dafc71ad/packages/dashboard/server/parser.js +526 -0
- package/.worktrees/dafc71ad/packages/dashboard/server/watcher.js +357 -0
- package/.worktrees/dafc71ad/src/agent-session-log.js +803 -0
- package/.worktrees/dafc71ad/src/change-list.js +290 -0
- package/.worktrees/dafc71ad/src/change-risk-profile.js +339 -0
- package/.worktrees/dafc71ad/src/check-primitives.js +65 -0
- package/.worktrees/dafc71ad/src/classify-change.js +109 -0
- package/.worktrees/dafc71ad/src/commit-suggest.js +202 -0
- package/.worktrees/dafc71ad/src/config-cat.js +88 -0
- package/.worktrees/dafc71ad/src/config-schema.js +328 -0
- package/.worktrees/dafc71ad/src/constants.js +97 -0
- package/.worktrees/dafc71ad/src/contract-matrix.js +533 -0
- package/.worktrees/dafc71ad/src/datetime.js +20 -0
- package/.worktrees/dafc71ad/src/db-engine.js +55 -0
- package/.worktrees/dafc71ad/src/db.js +381 -0
- package/.worktrees/dafc71ad/src/decision-distill.js +517 -0
- package/.worktrees/dafc71ad/src/dispatch/backends/local-agent.js +155 -0
- package/.worktrees/dafc71ad/src/dispatch/backends/sillyhub-mcp.js +245 -0
- package/.worktrees/dafc71ad/src/dispatch/probe.js +246 -0
- package/.worktrees/dafc71ad/src/dispatch/strategy.js +121 -0
- package/.worktrees/dafc71ad/src/docs-check.js +825 -0
- package/.worktrees/dafc71ad/src/docs-debt.js +393 -0
- package/.worktrees/dafc71ad/src/docs-gate.js +107 -0
- package/.worktrees/dafc71ad/src/doctor-diagnostics.js +1099 -0
- package/.worktrees/dafc71ad/src/endpoint-extractor.js +409 -0
- package/.worktrees/dafc71ad/src/foreign-declared.js +155 -0
- package/.worktrees/dafc71ad/src/fs-atomic.js +73 -0
- package/.worktrees/dafc71ad/src/git-helper.js +150 -0
- package/.worktrees/dafc71ad/src/hooks/claude-pre-tool-use.cjs +130 -0
- package/.worktrees/dafc71ad/src/hooks/worktree-guard.js +892 -0
- package/.worktrees/dafc71ad/src/index.js +2854 -0
- package/.worktrees/dafc71ad/src/init.js +626 -0
- package/.worktrees/dafc71ad/src/knowledge-match.js +231 -0
- package/.worktrees/dafc71ad/src/local-detect.js +128 -0
- package/.worktrees/dafc71ad/src/local-register.js +104 -0
- package/.worktrees/dafc71ad/src/machine-interface.js +543 -0
- package/.worktrees/dafc71ad/src/migrate.js +127 -0
- package/.worktrees/dafc71ad/src/module-impact.js +166 -0
- package/.worktrees/dafc71ad/src/module-resolve.js +222 -0
- package/.worktrees/dafc71ad/src/modules.js +580 -0
- package/.worktrees/dafc71ad/src/plan-adopt-waves.js +126 -0
- package/.worktrees/dafc71ad/src/progress/change-registry.js +336 -0
- package/.worktrees/dafc71ad/src/progress/consistency-doctor.js +355 -0
- package/.worktrees/dafc71ad/src/progress/shared.js +36 -0
- package/.worktrees/dafc71ad/src/progress/stage-machine.js +594 -0
- package/.worktrees/dafc71ad/src/progress/step-store.js +265 -0
- package/.worktrees/dafc71ad/src/progress.js +1304 -0
- package/.worktrees/dafc71ad/src/quick-recommend.js +115 -0
- package/.worktrees/dafc71ad/src/quicklog.js +883 -0
- package/.worktrees/dafc71ad/src/review-tier.js +77 -0
- package/.worktrees/dafc71ad/src/run/command.js +1641 -0
- package/.worktrees/dafc71ad/src/run/complete-handlers.js +1552 -0
- package/.worktrees/dafc71ad/src/run/complete.js +1259 -0
- package/.worktrees/dafc71ad/src/run/concurrent-detect.js +156 -0
- package/.worktrees/dafc71ad/src/run/gates.js +1111 -0
- package/.worktrees/dafc71ad/src/run/multi-repo-context.js +208 -0
- package/.worktrees/dafc71ad/src/run/next.js +128 -0
- package/.worktrees/dafc71ad/src/run/prompt.js +843 -0
- package/.worktrees/dafc71ad/src/run/quick-audit.js +186 -0
- package/.worktrees/dafc71ad/src/run/scan-profile.js +269 -0
- package/.worktrees/dafc71ad/src/run/shared.js +1562 -0
- package/.worktrees/dafc71ad/src/run/stage.js +587 -0
- package/.worktrees/dafc71ad/src/run.js +23 -0
- package/.worktrees/dafc71ad/src/scan-diff.js +388 -0
- package/.worktrees/dafc71ad/src/scan-postcheck.js +524 -0
- package/.worktrees/dafc71ad/src/scan-staleness.js +95 -0
- package/.worktrees/dafc71ad/src/setup.js +414 -0
- package/.worktrees/dafc71ad/src/sillyhub-mcp/client.js +597 -0
- package/.worktrees/dafc71ad/src/sillyhub-mcp/config.js +62 -0
- package/.worktrees/dafc71ad/src/spec-dir-typo.js +50 -0
- package/.worktrees/dafc71ad/src/spec-sync.js +358 -0
- package/.worktrees/dafc71ad/src/stage-contract-engine.js +171 -0
- package/.worktrees/dafc71ad/src/stage-contract-spec.js +551 -0
- package/.worktrees/dafc71ad/src/stage-contract.js +948 -0
- package/.worktrees/dafc71ad/src/stage-review.js +597 -0
- package/.worktrees/dafc71ad/src/stages/archive.js +199 -0
- package/.worktrees/dafc71ad/src/stages/brainstorm-auto.js +285 -0
- package/.worktrees/dafc71ad/src/stages/brainstorm.js +624 -0
- package/.worktrees/dafc71ad/src/stages/cmd-existence.js +145 -0
- package/.worktrees/dafc71ad/src/stages/doctor.js +540 -0
- package/.worktrees/dafc71ad/src/stages/execute.js +1277 -0
- package/.worktrees/dafc71ad/src/stages/explore.js +43 -0
- package/.worktrees/dafc71ad/src/stages/index.js +29 -0
- package/.worktrees/dafc71ad/src/stages/knowledge.js +514 -0
- package/.worktrees/dafc71ad/src/stages/plan-postcheck.js +1398 -0
- package/.worktrees/dafc71ad/src/stages/plan.js +655 -0
- package/.worktrees/dafc71ad/src/stages/quick.js +167 -0
- package/.worktrees/dafc71ad/src/stages/scan.js +608 -0
- package/.worktrees/dafc71ad/src/stages/status.js +64 -0
- package/.worktrees/dafc71ad/src/stages/verify.js +246 -0
- package/.worktrees/dafc71ad/src/sync.js +1470 -0
- package/.worktrees/dafc71ad/src/task-review.js +1498 -0
- package/.worktrees/dafc71ad/src/taskcard-placeholders.js +21 -0
- package/.worktrees/dafc71ad/src/taskcard.js +250 -0
- package/.worktrees/dafc71ad/src/verify-postcheck.js +1718 -0
- package/.worktrees/dafc71ad/src/verify-probes.js +327 -0
- package/.worktrees/dafc71ad/src/version.js +19 -0
- package/.worktrees/dafc71ad/src/workflow.js +600 -0
- package/.worktrees/dafc71ad/src/workspace.js +125 -0
- package/.worktrees/dafc71ad/src/worktree-apply.js +1611 -0
- package/.worktrees/dafc71ad/src/worktree-deps.js +668 -0
- package/.worktrees/dafc71ad/src/worktree.js +1849 -0
- package/.worktrees/dafc71ad/templates/claude-instruction.md +23 -0
- package/.worktrees/dafc71ad/templates/prompts/taskcard-rules.md +29 -0
- package/.worktrees/dafc71ad/templates/prompts/testcase-design.md +12 -0
- package/.worktrees/dafc71ad/templates/prompts/verify-probes.md +32 -0
- package/.worktrees/dafc71ad/templates/workflows/archive-impact.yaml +79 -0
- package/.worktrees/dafc71ad/templates/workflows/scan-docs.yaml +132 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-archive/SKILL.md +87 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-auto/SKILL.md +93 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-commit/SKILL.md +67 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-continue/SKILL.md +47 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-execute/SKILL.md +214 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-explore/SKILL.md +102 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-export/SKILL.md +57 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-init/SKILL.md +177 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-plan/SKILL.md +156 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-propose/SKILL.md +87 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-quick/SKILL.md +116 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-resume/SKILL.md +70 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-scan/SKILL.md +79 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-state/SKILL.md +64 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-status/SKILL.md +54 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-verify/SKILL.md +87 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
- package/.worktrees/e58fcc4c/.gitattributes +2 -0
- package/.worktrees/e58fcc4c/.husky/pre-push +20 -0
- package/.worktrees/e58fcc4c/README.md +203 -0
- package/.worktrees/e58fcc4c/SKILL.md +91 -0
- package/.worktrees/e58fcc4c/architecture-analysis.md +503 -0
- package/.worktrees/e58fcc4c/bin/sillyspec.js +2 -0
- package/.worktrees/e58fcc4c/eval/README.md +86 -0
- package/.worktrees/e58fcc4c/eval/eval.config.json +28 -0
- package/.worktrees/e58fcc4c/eval/lib/adapters/cli.mjs +63 -0
- package/.worktrees/e58fcc4c/eval/lib/adapters/dryrun.mjs +27 -0
- package/.worktrees/e58fcc4c/eval/lib/config.mjs +82 -0
- package/.worktrees/e58fcc4c/eval/lib/db.mjs +76 -0
- package/.worktrees/e58fcc4c/eval/lib/report.mjs +120 -0
- package/.worktrees/e58fcc4c/eval/lib/runner.mjs +157 -0
- package/.worktrees/e58fcc4c/eval/lib/tasks.mjs +73 -0
- package/.worktrees/e58fcc4c/eval/lib/util.mjs +107 -0
- package/.worktrees/e58fcc4c/eval/lib/workdir.mjs +30 -0
- package/.worktrees/e58fcc4c/eval/run.mjs +83 -0
- package/.worktrees/e58fcc4c/eval/tasks/001-slugify/files/package.json +6 -0
- package/.worktrees/e58fcc4c/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
- package/.worktrees/e58fcc4c/eval/tasks/001-slugify/task.json +6 -0
- package/.worktrees/e58fcc4c/eval/tasks/001-slugify/verify.mjs +28 -0
- package/.worktrees/e58fcc4c/eval/tasks/002-each-day/files/package.json +6 -0
- package/.worktrees/e58fcc4c/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
- package/.worktrees/e58fcc4c/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
- package/.worktrees/e58fcc4c/eval/tasks/002-each-day/task.json +6 -0
- package/.worktrees/e58fcc4c/eval/tasks/002-each-day/verify.mjs +31 -0
- package/.worktrees/e58fcc4c/eval/tasks/003-word-report/files/data/notes.txt +5 -0
- package/.worktrees/e58fcc4c/eval/tasks/003-word-report/files/package.json +6 -0
- package/.worktrees/e58fcc4c/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
- package/.worktrees/e58fcc4c/eval/tasks/003-word-report/task.json +6 -0
- package/.worktrees/e58fcc4c/eval/tasks/003-word-report/verify.mjs +38 -0
- package/.worktrees/e58fcc4c/logo.jpg +0 -0
- package/.worktrees/e58fcc4c/package-lock.json +977 -0
- package/.worktrees/e58fcc4c/package.json +41 -0
- package/.worktrees/e58fcc4c/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
- package/.worktrees/e58fcc4c/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
- package/.worktrees/e58fcc4c/packages/dashboard/dist/favicon.jpg +0 -0
- package/.worktrees/e58fcc4c/packages/dashboard/dist/index.html +16 -0
- package/.worktrees/e58fcc4c/packages/dashboard/dist/logo.jpg +0 -0
- package/.worktrees/e58fcc4c/packages/dashboard/dist/prototype-dashboard.html +836 -0
- package/.worktrees/e58fcc4c/packages/dashboard/dist/prototype-overview.html +256 -0
- package/.worktrees/e58fcc4c/packages/dashboard/package.json +25 -0
- package/.worktrees/e58fcc4c/packages/dashboard/server/executor.js +95 -0
- package/.worktrees/e58fcc4c/packages/dashboard/server/index.js +679 -0
- package/.worktrees/e58fcc4c/packages/dashboard/server/parser.js +526 -0
- package/.worktrees/e58fcc4c/packages/dashboard/server/watcher.js +357 -0
- package/.worktrees/e58fcc4c/src/agent-session-log.js +803 -0
- package/.worktrees/e58fcc4c/src/change-list.js +290 -0
- package/.worktrees/e58fcc4c/src/change-risk-profile.js +339 -0
- package/.worktrees/e58fcc4c/src/check-primitives.js +65 -0
- package/.worktrees/e58fcc4c/src/classify-change.js +109 -0
- package/.worktrees/e58fcc4c/src/commit-suggest.js +202 -0
- package/.worktrees/e58fcc4c/src/config-cat.js +88 -0
- package/.worktrees/e58fcc4c/src/config-schema.js +328 -0
- package/.worktrees/e58fcc4c/src/constants.js +97 -0
- package/.worktrees/e58fcc4c/src/contract-matrix.js +533 -0
- package/.worktrees/e58fcc4c/src/datetime.js +20 -0
- package/.worktrees/e58fcc4c/src/db-engine.js +55 -0
- package/.worktrees/e58fcc4c/src/db.js +381 -0
- package/.worktrees/e58fcc4c/src/decision-distill.js +517 -0
- package/.worktrees/e58fcc4c/src/dispatch/backends/local-agent.js +155 -0
- package/.worktrees/e58fcc4c/src/dispatch/backends/sillyhub-mcp.js +245 -0
- package/.worktrees/e58fcc4c/src/dispatch/probe.js +246 -0
- package/.worktrees/e58fcc4c/src/dispatch/strategy.js +121 -0
- package/.worktrees/e58fcc4c/src/docs-check.js +825 -0
- package/.worktrees/e58fcc4c/src/docs-debt.js +393 -0
- package/.worktrees/e58fcc4c/src/docs-gate.js +107 -0
- package/.worktrees/e58fcc4c/src/doctor-diagnostics.js +1099 -0
- package/.worktrees/e58fcc4c/src/endpoint-extractor.js +409 -0
- package/.worktrees/e58fcc4c/src/foreign-declared.js +155 -0
- package/.worktrees/e58fcc4c/src/fs-atomic.js +73 -0
- package/.worktrees/e58fcc4c/src/git-helper.js +150 -0
- package/.worktrees/e58fcc4c/src/hooks/claude-pre-tool-use.cjs +130 -0
- package/.worktrees/e58fcc4c/src/hooks/worktree-guard.js +892 -0
- package/.worktrees/e58fcc4c/src/index.js +2854 -0
- package/.worktrees/e58fcc4c/src/init.js +626 -0
- package/.worktrees/e58fcc4c/src/knowledge-match.js +231 -0
- package/.worktrees/e58fcc4c/src/local-detect.js +128 -0
- package/.worktrees/e58fcc4c/src/local-register.js +104 -0
- package/.worktrees/e58fcc4c/src/machine-interface.js +543 -0
- package/.worktrees/e58fcc4c/src/migrate.js +127 -0
- package/.worktrees/e58fcc4c/src/module-impact.js +166 -0
- package/.worktrees/e58fcc4c/src/module-resolve.js +222 -0
- package/.worktrees/e58fcc4c/src/modules.js +580 -0
- package/.worktrees/e58fcc4c/src/plan-adopt-waves.js +126 -0
- package/.worktrees/e58fcc4c/src/progress/change-registry.js +336 -0
- package/.worktrees/e58fcc4c/src/progress/consistency-doctor.js +355 -0
- package/.worktrees/e58fcc4c/src/progress/shared.js +36 -0
- package/.worktrees/e58fcc4c/src/progress/stage-machine.js +594 -0
- package/.worktrees/e58fcc4c/src/progress/step-store.js +265 -0
- package/.worktrees/e58fcc4c/src/progress.js +1304 -0
- package/.worktrees/e58fcc4c/src/quick-recommend.js +115 -0
- package/.worktrees/e58fcc4c/src/quicklog.js +883 -0
- package/.worktrees/e58fcc4c/src/review-tier.js +77 -0
- package/.worktrees/e58fcc4c/src/run/command.js +1641 -0
- package/.worktrees/e58fcc4c/src/run/complete-handlers.js +1552 -0
- package/.worktrees/e58fcc4c/src/run/complete.js +1259 -0
- package/.worktrees/e58fcc4c/src/run/concurrent-detect.js +156 -0
- package/.worktrees/e58fcc4c/src/run/gates.js +1111 -0
- package/.worktrees/e58fcc4c/src/run/multi-repo-context.js +208 -0
- package/.worktrees/e58fcc4c/src/run/next.js +128 -0
- package/.worktrees/e58fcc4c/src/run/prompt.js +843 -0
- package/.worktrees/e58fcc4c/src/run/quick-audit.js +186 -0
- package/.worktrees/e58fcc4c/src/run/scan-profile.js +269 -0
- package/.worktrees/e58fcc4c/src/run/shared.js +1562 -0
- package/.worktrees/e58fcc4c/src/run/stage.js +587 -0
- package/.worktrees/e58fcc4c/src/run.js +23 -0
- package/.worktrees/e58fcc4c/src/scan-diff.js +388 -0
- package/.worktrees/e58fcc4c/src/scan-postcheck.js +524 -0
- package/.worktrees/e58fcc4c/src/scan-staleness.js +95 -0
- package/.worktrees/e58fcc4c/src/setup.js +414 -0
- package/.worktrees/e58fcc4c/src/sillyhub-mcp/client.js +597 -0
- package/.worktrees/e58fcc4c/src/sillyhub-mcp/config.js +62 -0
- package/.worktrees/e58fcc4c/src/spec-dir-typo.js +50 -0
- package/.worktrees/e58fcc4c/src/spec-sync.js +358 -0
- package/.worktrees/e58fcc4c/src/stage-contract-engine.js +171 -0
- package/.worktrees/e58fcc4c/src/stage-contract-spec.js +551 -0
- package/.worktrees/e58fcc4c/src/stage-contract.js +948 -0
- package/.worktrees/e58fcc4c/src/stage-review.js +597 -0
- package/.worktrees/e58fcc4c/src/stages/archive.js +199 -0
- package/.worktrees/e58fcc4c/src/stages/brainstorm-auto.js +285 -0
- package/.worktrees/e58fcc4c/src/stages/brainstorm.js +624 -0
- package/.worktrees/e58fcc4c/src/stages/cmd-existence.js +145 -0
- package/.worktrees/e58fcc4c/src/stages/doctor.js +540 -0
- package/.worktrees/e58fcc4c/src/stages/execute.js +1277 -0
- package/.worktrees/e58fcc4c/src/stages/explore.js +43 -0
- package/.worktrees/e58fcc4c/src/stages/index.js +29 -0
- package/.worktrees/e58fcc4c/src/stages/knowledge.js +514 -0
- package/.worktrees/e58fcc4c/src/stages/plan-postcheck.js +1398 -0
- package/.worktrees/e58fcc4c/src/stages/plan.js +655 -0
- package/.worktrees/e58fcc4c/src/stages/quick.js +167 -0
- package/.worktrees/e58fcc4c/src/stages/scan.js +608 -0
- package/.worktrees/e58fcc4c/src/stages/status.js +64 -0
- package/.worktrees/e58fcc4c/src/stages/verify.js +246 -0
- package/.worktrees/e58fcc4c/src/sync.js +1470 -0
- package/.worktrees/e58fcc4c/src/task-review.js +1498 -0
- package/.worktrees/e58fcc4c/src/taskcard-placeholders.js +21 -0
- package/.worktrees/e58fcc4c/src/taskcard.js +250 -0
- package/.worktrees/e58fcc4c/src/verify-postcheck.js +1718 -0
- package/.worktrees/e58fcc4c/src/verify-probes.js +327 -0
- package/.worktrees/e58fcc4c/src/version.js +19 -0
- package/.worktrees/e58fcc4c/src/workflow.js +600 -0
- package/.worktrees/e58fcc4c/src/workspace.js +125 -0
- package/.worktrees/e58fcc4c/src/worktree-apply.js +1611 -0
- package/.worktrees/e58fcc4c/src/worktree-deps.js +668 -0
- package/.worktrees/e58fcc4c/src/worktree.js +1849 -0
- package/.worktrees/e58fcc4c/templates/claude-instruction.md +23 -0
- package/.worktrees/e58fcc4c/templates/prompts/taskcard-rules.md +29 -0
- package/.worktrees/e58fcc4c/templates/prompts/testcase-design.md +12 -0
- package/.worktrees/e58fcc4c/templates/prompts/verify-probes.md +32 -0
- package/.worktrees/e58fcc4c/templates/workflows/archive-impact.yaml +79 -0
- package/.worktrees/e58fcc4c/templates/workflows/scan-docs.yaml +132 -0
- package/package.json +1 -1
- package/src/contract-matrix.js +45 -14
- package/src/foreign-declared.js +11 -5
- package/src/fs-atomic.js +20 -3
- package/src/hooks/worktree-guard.js +9 -3
- package/src/index.js +52 -12
- package/src/module-impact.js +1 -1
- package/src/modules.js +23 -21
- package/src/progress/stage-machine.js +26 -1
- package/src/progress.js +38 -2
- package/src/quicklog.js +7 -5
- package/src/run/command.js +51 -20
- package/src/run/complete-handlers.js +26 -2
- package/src/run/complete.js +43 -21
- package/src/run/gates.js +52 -7
- package/src/run/multi-repo-context.js +42 -4
- package/src/run/next.js +4 -3
- package/src/run/prompt.js +66 -6
- package/src/run/scan-profile.js +1 -0
- package/src/run/shared.js +12 -6
- package/src/run/stage.js +35 -9
- package/src/scan-diff.js +4 -2
- package/src/stage-contract.js +36 -15
- package/src/stages/brainstorm.js +22 -8
- package/src/stages/execute.js +69 -22
- package/src/stages/knowledge.js +18 -5
- package/src/stages/plan-postcheck.js +63 -7
- package/src/stages/plan.js +13 -2
- package/src/sync.js +27 -11
- package/src/task-review.js +12 -3
- package/src/taskcard.js +2 -0
- package/src/verify-postcheck.js +24 -13
- package/src/verify-probes.js +12 -7
- package/src/worktree-apply.js +234 -18
- package/src/worktree-cross.js +294 -0
- package/src/worktree-deps.js +157 -59
- package/src/worktree.js +7 -2
|
@@ -0,0 +1,948 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StageContract — 阶段协议
|
|
3
|
+
*
|
|
4
|
+
* 每个阶段声明:允许的前置阶段、必须的产出、校验器、后续阶段。
|
|
5
|
+
* CLI 不再相信 prompt 完成,completeStep 后必须过 validator。
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { existsSync, readdirSync, readFileSync, writeFileSync } from 'fs'
|
|
9
|
+
import { join, basename } from 'path'
|
|
10
|
+
import { safeGit } from './git-helper.js'
|
|
11
|
+
import { nowWallClock } from './datetime.js'
|
|
12
|
+
import { detectChangeRisk, checkIntegrationEvidence, VERIFICATION_NEEDS, RISK_LEVEL_CAUSES } from './change-risk-profile.js'
|
|
13
|
+
import { SCAN_REQUIRED_DOCS, AUXILIARY_STAGES } from './constants.js'
|
|
14
|
+
import { evaluateRules } from './stage-contract-engine.js'
|
|
15
|
+
import { getRule } from './stage-contract-spec.js'
|
|
16
|
+
import { backfillFrontmatter } from './scan-postcheck.js'
|
|
17
|
+
import { parseAllowedPaths } from './stages/plan-postcheck.js'
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 校验结果
|
|
21
|
+
* @typedef {{ ok: boolean, errors: string[], warnings: string[] }} ValidationResult
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 阶段合约
|
|
26
|
+
* @typedef {{
|
|
27
|
+
* stage: string,
|
|
28
|
+
* description: string,
|
|
29
|
+
* allowedFrom: string[],
|
|
30
|
+
* allowedTo: string[],
|
|
31
|
+
* validators: Function[],
|
|
32
|
+
* }} StageContract
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
// ============ Validators ============
|
|
36
|
+
|
|
37
|
+
function resolveChangeDir(cwd, changeName, specRoot = null) {
|
|
38
|
+
const changesRoot = specRoot ? join(specRoot, 'changes') : join(cwd, '.sillyspec', 'changes')
|
|
39
|
+
return join(changesRoot, changeName)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* --change 变更名存在性校验(治 cwd 漂移误匹配,缺陷 execute-in-place-windows-pitfalls 坑5)。
|
|
44
|
+
*
|
|
45
|
+
* 多项目 monorepo 下,cwd 在子项目目录会让 resolveSpecDir 命中子项目 spec,
|
|
46
|
+
* 此时 --change 传根项目变更名,旧逻辑(resolveChangeDir 纯拼路径)不报错而静默
|
|
47
|
+
* fallback 误启动子项目流程。本校验对「操作已有变更」的阶段强制 changes/<changeName>
|
|
48
|
+
* 存在,不存在则 fail-fast,把 cwd 漂移暴露给用户。
|
|
49
|
+
*
|
|
50
|
+
* 豁免:
|
|
51
|
+
* - 非 plan/execute/verify/archive 阶段(scan/brainstorm/quick/explore 不校验:
|
|
52
|
+
* brainstorm 可新建变更、quick 用 sessionId、scan/explore 无 change 语义)
|
|
53
|
+
* - quick-<8hex> sessionId(quick 会话 changeName 是 sessionId,不在 changes/)
|
|
54
|
+
*
|
|
55
|
+
* @param {string} specBase - 规范根目录(.sillyspec 或平台 specRoot)
|
|
56
|
+
* @param {string} stageName - 阶段名
|
|
57
|
+
* @param {string} changeName - 变更名(--change 或 auto)
|
|
58
|
+
* @returns {{ changeName: string, specBase: string, message: string } | null} null=通过,对象=失败
|
|
59
|
+
*/
|
|
60
|
+
export function validateChangeExists(specBase, stageName, changeName) {
|
|
61
|
+
const STAGES_REQUIRE_EXISTING_CHANGE = new Set(['plan', 'execute', 'verify', 'archive'])
|
|
62
|
+
if (!changeName || !STAGES_REQUIRE_EXISTING_CHANGE.has(stageName)) return null
|
|
63
|
+
if (/^quick-[0-9a-f]{8}$/.test(changeName)) return null
|
|
64
|
+
if (existsSync(join(specBase, 'changes', changeName))) return null
|
|
65
|
+
|
|
66
|
+
// archive 特例:step4 --confirm 已把变更从 changes/<name>/ 移到 changes/archive/<name>/。
|
|
67
|
+
// step5(更新路线图/提交)--change <name> 不应因 changes/<name>/ 已移走而被前置校验误拦。
|
|
68
|
+
if (stageName === 'archive') {
|
|
69
|
+
const archiveRoot = join(specBase, 'changes', 'archive')
|
|
70
|
+
if (existsSync(archiveRoot) && existsSync(join(archiveRoot, changeName))) {
|
|
71
|
+
return null
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
changeName,
|
|
76
|
+
specBase,
|
|
77
|
+
message: `变更 "${changeName}" 在当前 spec 下不存在:${join(specBase, 'changes', changeName)}\n` +
|
|
78
|
+
` 排查方向(三选一):① 变更名是否打错(sillyspec status 或 progress show 查看活跃变更名);` +
|
|
79
|
+
`② cwd 是否漂到了子项目目录(回到项目根再跑,或加 --spec-dir <根>/.sillyspec);` +
|
|
80
|
+
`③ 是否该先跑 sillyspec run brainstorm 新建该变更。`,
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function collectIdsFromLine(line, re, ids) {
|
|
85
|
+
for (const match of line.matchAll(re)) {
|
|
86
|
+
ids.add(match[0].toUpperCase())
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function extractIds(content, prefix) {
|
|
91
|
+
if (!content) return []
|
|
92
|
+
const ids = new Set()
|
|
93
|
+
const idRe = new RegExp(`\\b${prefix}-\\d+(?:@v\\d+)?\\b`, 'gi')
|
|
94
|
+
const headingLineRe = /^\s{0,3}#{1,6}\s+/i
|
|
95
|
+
const fieldLineRe = /^\s*(?:[-*]\s*)?(?:id|decision[-_ ]?ids?|requirement[-_ ]?ids?|covers?|coverage|references?|impacts?|覆盖(?:来源|决策|需求)?)\s*[::]/i
|
|
96
|
+
const tableLineRe = /^\s*\|/
|
|
97
|
+
const listStartsWithIdRe = new RegExp(`^\\s*(?:[-*]|\\d+\\.)\\s*(?:\\[[ xX]\\]\\s*)?${prefix}-\\d+(?:@v\\d+)?\\b`, 'i')
|
|
98
|
+
|
|
99
|
+
for (const line of content.split(/\r?\n/)) {
|
|
100
|
+
if (!headingLineRe.test(line) && !fieldLineRe.test(line) && !tableLineRe.test(line) && !listStartsWithIdRe.test(line)) continue
|
|
101
|
+
collectIdsFromLine(line, idRe, ids)
|
|
102
|
+
}
|
|
103
|
+
return [...ids].sort()
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function readDecisionField(body, fieldPattern, fallback = '') {
|
|
107
|
+
const re = new RegExp(`^\\s*(?:[-*]\\s*)?(?:${fieldPattern})\\s*[::]\\s*([^\\n]+)`, 'im')
|
|
108
|
+
return (body.match(re)?.[1] || fallback).trim()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function buildDecisionRecord(id, body) {
|
|
112
|
+
const status = readDecisionField(body, 'status', 'accepted').toLowerCase()
|
|
113
|
+
const blockerValue = readDecisionField(body, 'blocker', 'false').toLowerCase()
|
|
114
|
+
const blocker = ['true', 'yes', '1'].includes(blockerValue)
|
|
115
|
+
const priorityValue = readDecisionField(body, 'priority|level|severity')
|
|
116
|
+
const priorityMissing = priorityValue.length === 0
|
|
117
|
+
const fallbackPriority = (['unresolved', 'blocking'].includes(status) || blocker) ? 'P1' : 'P2'
|
|
118
|
+
const priority = (priorityValue.match(/P[0-2]/i)?.[0] || fallbackPriority).toUpperCase()
|
|
119
|
+
// 解析 supersedes 字段:记录本条决策取代了哪个旧版本
|
|
120
|
+
const supersedesRaw = readDecisionField(body, 'supersedes', '')
|
|
121
|
+
const supersedes = supersedesRaw
|
|
122
|
+
? supersedesRaw.split(',').map(s => s.trim().toUpperCase().replace(/['"]/g, '')).filter(Boolean)
|
|
123
|
+
: []
|
|
124
|
+
return { id: id.toUpperCase(), body, status, priority, blocker, priorityMissing, supersedes }
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function findNextDecisionBoundary(content, startIndex) {
|
|
128
|
+
const boundaryRe = /^(\s{0,3}#{2,6}\s+D-\d+(?:@v\d+)?\b|\s*(?:[-*]\s*)?(?:id|decision[-_ ]?id|decision)\s*[::]\s*D-\d+(?:@v\d+)?\b)/gmi
|
|
129
|
+
boundaryRe.lastIndex = startIndex
|
|
130
|
+
const next = boundaryRe.exec(content)
|
|
131
|
+
return next ? next.index : content.length
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function isInsideRange(index, ranges) {
|
|
135
|
+
return ranges.some(range => index >= range.start && index < range.end)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function parseDecisionRecords(content) {
|
|
139
|
+
if (!content) return []
|
|
140
|
+
const records = []
|
|
141
|
+
const ranges = []
|
|
142
|
+
const headingRe = /^\s{0,3}#{2,6}\s+(D-\d+(?:@v\d+)?)(?:\b|:)[^\n]*$/gmi
|
|
143
|
+
const headings = []
|
|
144
|
+
let match
|
|
145
|
+
while ((match = headingRe.exec(content)) !== null) {
|
|
146
|
+
headings.push({ id: match[1].toUpperCase(), index: match.index, end: headingRe.lastIndex })
|
|
147
|
+
}
|
|
148
|
+
for (let i = 0; i < headings.length; i++) {
|
|
149
|
+
const current = headings[i]
|
|
150
|
+
const next = headings[i + 1]
|
|
151
|
+
const body = content.slice(current.end, next ? next.index : content.length)
|
|
152
|
+
const end = next ? next.index : content.length
|
|
153
|
+
ranges.push({ start: current.index, end })
|
|
154
|
+
records.push(buildDecisionRecord(current.id, body))
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const idLineRe = /^\s*(?:[-*]\s*)?(?:id|decision[-_ ]?id|decision)\s*[::]\s*(D-\d+(?:@v\d+)?)(?:\b|$)/gmi
|
|
158
|
+
while ((match = idLineRe.exec(content)) !== null) {
|
|
159
|
+
if (isInsideRange(match.index, ranges)) continue
|
|
160
|
+
const bodyEnd = findNextDecisionBoundary(content, idLineRe.lastIndex)
|
|
161
|
+
const body = content.slice(match.index, bodyEnd)
|
|
162
|
+
records.push(buildDecisionRecord(match[1], body))
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return records
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* decisions.md 缺 author/created_at header 时自动补齐(坑 decisions-header-late-warning,
|
|
170
|
+
* 2026-08-24 用户反馈二期:brainstorm step8 模板曾自带无 frontmatter 的 decisions 样例——
|
|
171
|
+
* agent 照抄生成必缺 header,拖到后续环节才提示。模板已修;本函数兜存量:gate 前幂等补
|
|
172
|
+
* 机械字段(author=git user / created_at=now),与 scan-fix-headers 同一 backfillFrontmatter 实现。
|
|
173
|
+
* @param {string} changeDir - changes/<name> 目录
|
|
174
|
+
* @returns {boolean} true = 本次补齐过(false = 无 decisions.md / header 已齐 / 写失败)
|
|
175
|
+
*/
|
|
176
|
+
export function ensureDecisionDocHeader(changeDir) {
|
|
177
|
+
try {
|
|
178
|
+
const decisionPath = join(changeDir, 'decisions.md')
|
|
179
|
+
if (!existsSync(decisionPath)) return false
|
|
180
|
+
const content = readFileSync(decisionPath, 'utf8')
|
|
181
|
+
let author = 'unknown'
|
|
182
|
+
const gitUser = safeGit(changeDir, ['config', 'user.name'])
|
|
183
|
+
if (gitUser && gitUser.value) author = String(gitUser.value).trim() || 'unknown'
|
|
184
|
+
const r = backfillFrontmatter(content, { author, createdAt: nowWallClock() })
|
|
185
|
+
if (!r.changed) return false
|
|
186
|
+
writeFileSync(decisionPath, r.content)
|
|
187
|
+
console.log(`ℹ️ 已自动补齐 decisions.md 缺失的 author/created_at header: ${decisionPath}`)
|
|
188
|
+
return true
|
|
189
|
+
} catch { /* 补齐失败不阻断 gate——decisions 内容校验照常进行 */ }
|
|
190
|
+
return false
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function extractCurrentDecisionIds(content) {
|
|
194
|
+
const records = parseDecisionRecords(content)
|
|
195
|
+
if (records.length === 0) return extractIds(content, 'D')
|
|
196
|
+
// 收集所有被 supersedes 声明取代的旧版本 ID
|
|
197
|
+
const supersededIds = new Set()
|
|
198
|
+
for (const r of records) {
|
|
199
|
+
for (const oldId of r.supersedes) {
|
|
200
|
+
supersededIds.add(oldId)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return records
|
|
204
|
+
.filter(r => !['superseded', 'rejected'].includes(r.status))
|
|
205
|
+
.filter(r => !supersededIds.has(r.id)) // 被新版本显式取代的旧版本不再校验
|
|
206
|
+
.map(r => r.id)
|
|
207
|
+
.sort()
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function findBlockingDecisionIssues(content) {
|
|
211
|
+
return parseDecisionRecords(content)
|
|
212
|
+
.filter(r => (r.blocker || ['unresolved', 'blocking'].includes(r.status)) && ['P0', 'P1'].includes(r.priority))
|
|
213
|
+
.map(r => `${r.id} (${r.priority}${r.priorityMissing ? ', priority=missing->P1' : ''}, status=${r.status})`)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function readIfExists(file) {
|
|
217
|
+
return existsSync(file) ? readFileSync(file, 'utf8') : ''
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function warnMissingIds(warnings, ids, targetContent, targetName, sourceName) {
|
|
221
|
+
// 剥版本后缀(@vN)按基号词边界匹配:target 里写裸号 D-001 即视为引用了 D-001@V1
|
|
222
|
+
// 的当前版本(prompt 常裸号引用,旧版字面 includes("D-001@V1") 会批量误报)。
|
|
223
|
+
// 大小写不敏感:target 整体大写后比对。
|
|
224
|
+
const targetUpper = targetContent.toUpperCase()
|
|
225
|
+
for (const id of ids) {
|
|
226
|
+
const base = id.replace(/@V\d+$/, '')
|
|
227
|
+
const re = new RegExp(`\\b${base}\\b`)
|
|
228
|
+
if (!re.test(targetUpper)) {
|
|
229
|
+
warnings.push(getRule('shared.id-traceability').failMessage.replaceAll('${target}', targetName).replaceAll('${source}', sourceName).replaceAll('${id}', id))
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* scan 完成校验:检查 7 份 scan 文档 + manifest
|
|
236
|
+
*/
|
|
237
|
+
function validateScanOutputs(cwd, changeName, context = {}) {
|
|
238
|
+
const { projectName, specRoot } = context
|
|
239
|
+
// 平台模式:specRoot 直接是规范目录(含 docs/)
|
|
240
|
+
// 本地模式:规范目录是 cwd/.sillyspec
|
|
241
|
+
// 不用 isSpecDir 启发式猜测——很多项目根目录有自己的 docs/,会误判
|
|
242
|
+
const specBase = specRoot || join(cwd, '.sillyspec')
|
|
243
|
+
const docsRoot = projectName
|
|
244
|
+
? join(specBase, 'docs', projectName, 'scan')
|
|
245
|
+
: join(specBase, 'docs', 'scan')
|
|
246
|
+
|
|
247
|
+
// 7 份 scan 文档存在性由引擎消费 manifest(与 SCAN_REQUIRED_DOCS 单源,文案/事前契约同源)
|
|
248
|
+
const engineResult = evaluateRules('scan', { docsRoot })
|
|
249
|
+
const errors = [...engineResult.errors]
|
|
250
|
+
const warnings = [...engineResult.warnings]
|
|
251
|
+
|
|
252
|
+
// 检查 modules 目录
|
|
253
|
+
const modulesRoot = projectName
|
|
254
|
+
? join(specBase, 'docs', projectName, 'modules')
|
|
255
|
+
: join(specBase, 'docs', 'modules')
|
|
256
|
+
if (!existsSync(modulesRoot)) {
|
|
257
|
+
warnings.push('modules 目录不存在')
|
|
258
|
+
} else {
|
|
259
|
+
const modules = readdirSync(modulesRoot).filter(f => f.endsWith('.md'))
|
|
260
|
+
if (modules.length === 0) {
|
|
261
|
+
warnings.push('modules 目录为空')
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return { ok: errors.length === 0, errors, warnings }
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* brainstorm 完成校验:检查四件套规范文件是否生成
|
|
270
|
+
*/
|
|
271
|
+
function validateBrainstormOutputs(cwd, changeName, context = {}) {
|
|
272
|
+
const { specRoot } = context
|
|
273
|
+
const changesRoot = specRoot ? join(specRoot, 'changes') : join(cwd, '.sillyspec', 'changes')
|
|
274
|
+
if (specRoot && !existsSync(changesRoot)) {
|
|
275
|
+
return { ok: false, errors: [`平台模式 specRoot 缺少 changes 目录: ${changesRoot}`], warnings: [] }
|
|
276
|
+
}
|
|
277
|
+
const changeDir = resolveChangeDir(cwd, changeName, specRoot)
|
|
278
|
+
// 读 design.md frontmatter scale(若有)传入引擎 ctx,供 BRAINSTORM_RULES 的 condition 判定:
|
|
279
|
+
// scale=small → proposal/requirements/tasks 三规则跳过(小变更只产 design.md,与末步 prompt 一致,
|
|
280
|
+
// 避免"照 Step8 small 指引只写 design.md 后 --done 必撞四件套 error墙")。
|
|
281
|
+
// fail-safe:design.md 不存在或无 scale → null → condition(ne 'small')成立 → 四件套全要求(保守走重流程)。
|
|
282
|
+
const designPath = join(changeDir, 'design.md')
|
|
283
|
+
let scale = null
|
|
284
|
+
let designContent = null
|
|
285
|
+
if (existsSync(designPath)) {
|
|
286
|
+
designContent = readFileSync(designPath, 'utf8')
|
|
287
|
+
const fm = designContent.match(/^---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*\r?\n/)
|
|
288
|
+
const sm = fm && fm[1].match(/^scale:[ \t]*['"]?(\w+)/m)
|
|
289
|
+
if (sm) scale = sm[1]
|
|
290
|
+
}
|
|
291
|
+
// 纯 kind 规则(四件套存在性 + proposal/requirements/design 章节 + tasks 列表)由引擎消费
|
|
292
|
+
// stage-contract-spec.js manifest,与报错文案 + prompt 事前契约严格同源(事前给的 == 事后查的)。
|
|
293
|
+
// custom kind(lifecycle / decisions)保留下方旧逻辑,数据/文案在 Batch 3 迁入 manifest。
|
|
294
|
+
const engineResult = evaluateRules('brainstorm', { changeDir, scale })
|
|
295
|
+
const errors = [...engineResult.errors]
|
|
296
|
+
const warnings = [...engineResult.warnings]
|
|
297
|
+
|
|
298
|
+
if (designContent) {
|
|
299
|
+
const content = designContent
|
|
300
|
+
|
|
301
|
+
// lifecycle-exemption(custom kind):判定算法保留(trigger/exemption/table 三段短路),
|
|
302
|
+
// data + failMessage/exemptionPassedMessage 从 stage-contract-spec.js manifest 同源。
|
|
303
|
+
const lcRule = getRule('brainstorm.design.lifecycle-table')
|
|
304
|
+
const { trigger: lcTrigger, exemptions: lcExempts, table: lcTable } = lcRule.data
|
|
305
|
+
if (new RegExp(lcTrigger.pattern, lcTrigger.flags).test(content)) {
|
|
306
|
+
const declaresNotApplicable = lcExempts.some(e => new RegExp(e.pattern, e.flags).test(content))
|
|
307
|
+
if (declaresNotApplicable) {
|
|
308
|
+
warnings.push(lcRule.exemptionPassedMessage)
|
|
309
|
+
} else {
|
|
310
|
+
const hasLifecycleTable = lcTable.some(t => new RegExp(t.pattern, t.flags).test(content))
|
|
311
|
+
if (!hasLifecycleTable) {
|
|
312
|
+
errors.push(lcRule.failMessage)
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// ── 风险判级提前提示(坑 risk-first-use-opaque,2026-08-24 用户实证)──
|
|
318
|
+
// verify --done 的 risk gate 既往只在流程末段暴露,首次使用者撞墙后才知道 frontmatter
|
|
319
|
+
// risk_level 覆盖通道。design --done 即按同款 detectChangeRisk 预判一次(此时 plan.md 尚未
|
|
320
|
+
// 产出,verify 时会连 plan 一起重判、级别可能上浮——本提示 advisory 不作为定论):
|
|
321
|
+
// 高危关键词命中 / 存在否定抑制 → 透出判级结果 + 覆盖指引,把机制可见性提前到 design 阶段。
|
|
322
|
+
{
|
|
323
|
+
const profile = detectChangeRisk({ designContent: content })
|
|
324
|
+
if (['integration-critical', 'deployment-critical'].includes(profile.level) && !profile.explicit) {
|
|
325
|
+
warnings.push(
|
|
326
|
+
`[risk] 本次 design 判级 ${profile.level}(命中关键词:${profile.triggers.join('、')})——verify --done 将强制真实集成证据门控。` +
|
|
327
|
+
`若属关键词误伤(实际未触碰 daemon/session/启动入口),现在就在 design.md frontmatter 加 risk_level: <真实等级>(如 unit-sufficient)显式覆盖,免得到 verify 阶段才发现而返工。`
|
|
328
|
+
)
|
|
329
|
+
}
|
|
330
|
+
if ((profile.suppressedTriggers || []).length > 0) {
|
|
331
|
+
warnings.push(
|
|
332
|
+
`[risk] 关键词命中 ${profile.suppressedTriggers.join('、')} 已被同句否定语境抑制,当前判级 ${profile.level}。` +
|
|
333
|
+
`若实际涉及对应改动,请在 design.md frontmatter 声明高危级(抑制可审计,防静默降级逃证据门控)。`
|
|
334
|
+
)
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const decisionsFile = join(changeDir, 'decisions.md')
|
|
340
|
+
if (existsSync(decisionsFile)) {
|
|
341
|
+
const decisions = readFileSync(decisionsFile, 'utf8')
|
|
342
|
+
const blockers = findBlockingDecisionIssues(decisions)
|
|
343
|
+
for (const issue of blockers) {
|
|
344
|
+
errors.push(getRule('shared.decision-blocker').failMessage.replace('${issue}', issue))
|
|
345
|
+
}
|
|
346
|
+
const decisionIds = extractCurrentDecisionIds(decisions)
|
|
347
|
+
if (decisionIds.length === 0) {
|
|
348
|
+
warnings.push('decisions.md 存在但没有当前版本 D-xxx@vN 决策 ID')
|
|
349
|
+
} else {
|
|
350
|
+
const design = readIfExists(join(changeDir, 'design.md'))
|
|
351
|
+
const requirements = readIfExists(join(changeDir, 'requirements.md'))
|
|
352
|
+
const tasks = readIfExists(join(changeDir, 'tasks.md'))
|
|
353
|
+
// decision 的天然引用落点是 design.md;requirements(需求按 FR 组织)与
|
|
354
|
+
// tasks(骨架,待 plan 展开)不强求逐条引用每个架构决策,否则批量误报。
|
|
355
|
+
warnMissingIds(warnings, decisionIds, design, 'design.md', 'decisions.md')
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return { ok: errors.length === 0, errors, warnings }
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* plan 完成校验:检查 plan.md 生成
|
|
364
|
+
*/
|
|
365
|
+
function validatePlanOutputs(cwd, changeName, context = {}) {
|
|
366
|
+
const { specRoot } = context
|
|
367
|
+
const changeDir = resolveChangeDir(cwd, changeName, specRoot)
|
|
368
|
+
const planFile = join(changeDir, 'plan.md')
|
|
369
|
+
|
|
370
|
+
// 读 design.md frontmatter scale(若有)传入引擎 ctx,供 plan.module-impact.exists 的 condition
|
|
371
|
+
// (scale≠small)判定——large 要求 module-impact 首版,small 豁免(走 quick)。fail-safe:无 scale→null→
|
|
372
|
+
// condition(ne 'small')成立→保守要求 module-impact(同 brainstorm scale 读取模式,line 264-272)。
|
|
373
|
+
const designPathForScale = join(changeDir, 'design.md')
|
|
374
|
+
let scale = null
|
|
375
|
+
if (existsSync(designPathForScale)) {
|
|
376
|
+
const fm = readFileSync(designPathForScale, 'utf8').match(/^---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*\r?\n/)
|
|
377
|
+
const sm = fm && fm[1].match(/^scale:[ \t]*['"]?(\w+)/m)
|
|
378
|
+
if (sm) scale = sm[1]
|
|
379
|
+
}
|
|
380
|
+
// plan.md 存在性由引擎消费 manifest。entryPoint/id-trace/decisions 为 custom kind(下方保留)。
|
|
381
|
+
const engineResult = evaluateRules('plan', { changeDir, scale })
|
|
382
|
+
const errors = [...engineResult.errors]
|
|
383
|
+
const warnings = [...engineResult.warnings]
|
|
384
|
+
|
|
385
|
+
if (existsSync(planFile)) {
|
|
386
|
+
const plan = readFileSync(planFile, 'utf8')
|
|
387
|
+
const requirements = readIfExists(join(changeDir, 'requirements.md'))
|
|
388
|
+
const requirementIds = extractIds(requirements, 'FR')
|
|
389
|
+
warnMissingIds(warnings, requirementIds, plan, 'plan.md', 'requirements.md')
|
|
390
|
+
|
|
391
|
+
const decisions = readIfExists(join(changeDir, 'decisions.md'))
|
|
392
|
+
const blockers = findBlockingDecisionIssues(decisions)
|
|
393
|
+
for (const issue of blockers) {
|
|
394
|
+
errors.push(getRule('shared.decision-blocker').failMessage.replace('${issue}', issue))
|
|
395
|
+
}
|
|
396
|
+
const decisionIds = extractCurrentDecisionIds(decisions)
|
|
397
|
+
warnMissingIds(warnings, decisionIds, plan, 'plan.md', 'decisions.md')
|
|
398
|
+
}
|
|
399
|
+
// ── P0: 生产接线路径检查:design 提到入口但 task 的 allowed_paths 不含入口文件 ──
|
|
400
|
+
// entry-point-wiring(custom):trigger/file 抽取/exemption/failMessage 从 manifest 同源
|
|
401
|
+
// (stage-contract-spec.js),保留多源 allowed_paths 收集 + 逐文件对账 + 豁免算法。
|
|
402
|
+
const designContent = readIfExists(join(changeDir, 'design.md'))
|
|
403
|
+
if (designContent) {
|
|
404
|
+
const epRule = getRule('plan.entry-point-wiring')
|
|
405
|
+
const { entryPointPatterns, fileExtractionPattern, exemptionPattern } = epRule.data
|
|
406
|
+
const fileExtractRe = new RegExp(fileExtractionPattern.pattern, fileExtractionPattern.flags)
|
|
407
|
+
const mentionedFiles = new Set()
|
|
408
|
+
for (const ep of entryPointPatterns) {
|
|
409
|
+
const pattern = new RegExp(ep.pattern, ep.flags)
|
|
410
|
+
pattern.lastIndex = 0
|
|
411
|
+
for (const match of designContent.matchAll(pattern)) {
|
|
412
|
+
const fileMatch = match[0].match(fileExtractRe)
|
|
413
|
+
if (fileMatch) mentionedFiles.add(fileMatch[1].toLowerCase())
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
if (mentionedFiles.size > 0) {
|
|
417
|
+
const tasksDir = join(changeDir, 'tasks')
|
|
418
|
+
const allAllowedPaths = new Set()
|
|
419
|
+
if (existsSync(tasksDir)) {
|
|
420
|
+
const taskFiles = readdirSync(tasksDir).filter(f => /^task-\d+\.md$/i.test(f))
|
|
421
|
+
for (const taskFile of taskFiles) {
|
|
422
|
+
const taskContent = readFileSync(join(tasksDir, taskFile), 'utf8')
|
|
423
|
+
// 复用 parseAllowedPaths(坑6①:认 inline 数组/缩进块/顶格块 + 剥反引号 + CRLF 归一,
|
|
424
|
+
// 消除此处内联正则与 plan-postcheck 的解析漂移)。卡片无 frontmatter 时退全文扫描
|
|
425
|
+
// (包裹伪 frontmatter 复用同一解析器)——原内联正则是全文匹配语义,entry-point-wiring
|
|
426
|
+
// 只关心路径覆盖,卡片格式合法性归 plan-postcheck 把关,此处不收紧。
|
|
427
|
+
const paths = parseAllowedPaths(taskContent)
|
|
428
|
+
const effective = paths.length > 0 ? paths : parseAllowedPaths(`---\n${taskContent}\n---`)
|
|
429
|
+
for (const p of effective) allAllowedPaths.add(p.toLowerCase())
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
// 也从 plan.md 文件变更清单中收集
|
|
433
|
+
if (existsSync(planFile)) {
|
|
434
|
+
const planContent = readFileSync(planFile, 'utf8')
|
|
435
|
+
const planFileChanges = planContent.match(/\|\s*(?:新增|修改|new|modify|update)\s*\|\s*`?([^`|]+)`?\s*\|/gi) || []
|
|
436
|
+
for (const line of planFileChanges) {
|
|
437
|
+
const file = line.match(/\|\s*(?:新增|修改|new|modify|update)\s*\|\s*`?([^`|]+)`?\s*\|/i)
|
|
438
|
+
if (file) allAllowedPaths.add(file[1].trim().toLowerCase())
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
for (const mentionedFile of mentionedFiles) {
|
|
442
|
+
const found = [...allAllowedPaths].some(p => p.includes(mentionedFile))
|
|
443
|
+
if (!found) {
|
|
444
|
+
const noChangePattern = new RegExp(exemptionPattern.replaceAll('${file}', mentionedFile), 'i')
|
|
445
|
+
if (!noChangePattern.test(designContent)) {
|
|
446
|
+
errors.push(epRule.failMessage.replaceAll('${file}', mentionedFile))
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
return { ok: errors.length === 0, errors, warnings }
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* 从 verify-result.md 提取结论关键词(PASS / PASS WITH NOTES / FAIL)。
|
|
457
|
+
* 标题放宽:含「结论/Conclusion/Result/结果」的二级标题均可(B3c),
|
|
458
|
+
* PASS/FAIL 可在标题行本身(如「## 验收结论:✅ PASS」)或紧邻标题的正文里。
|
|
459
|
+
* 历史教训:原正则锚定确切「## 结论」,用户写「## 验收结论:✅ PASS」不被识别。
|
|
460
|
+
*/
|
|
461
|
+
function extractVerifyConclusion(verify) {
|
|
462
|
+
const headingRe = /^##\s[^\n]*(?:结论|conclusion|result|结果)/im
|
|
463
|
+
const headingMatch = verify.match(headingRe)
|
|
464
|
+
if (!headingMatch) return ''
|
|
465
|
+
const start = headingMatch.index
|
|
466
|
+
const slice = verify.slice(start, start + 400)
|
|
467
|
+
const kw = slice.match(/\b(PASS(?:\s+WITH\s+NOTES)?|FAIL)\b/i)
|
|
468
|
+
return kw ? kw[1].toUpperCase().replace(/\s+/g, ' ') : ''
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function validateVerifyOutputs(cwd, changeName, context = {}) {
|
|
472
|
+
const { specRoot } = context
|
|
473
|
+
const changeDir = resolveChangeDir(cwd, changeName, specRoot)
|
|
474
|
+
|
|
475
|
+
if (!existsSync(changeDir)) {
|
|
476
|
+
return { ok: false, errors: [`变更目录缺失: ${changeDir}`], warnings: [] }
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// 核心文档存在性(verify-result.md / design.md / plan.md)由引擎消费 manifest。
|
|
480
|
+
// verify-result.md 不存在则不能完成——历史教训:AI 可能跳过报告直接 --done 导致"假完成"。
|
|
481
|
+
const engineResult = evaluateRules('verify', { changeDir })
|
|
482
|
+
const errors = [...engineResult.errors]
|
|
483
|
+
const warnings = [...engineResult.warnings]
|
|
484
|
+
|
|
485
|
+
const verifyResult = join(changeDir, 'verify-result.md')
|
|
486
|
+
if (existsSync(verifyResult)) {
|
|
487
|
+
const verify = readFileSync(verifyResult, 'utf8')
|
|
488
|
+
const decisions = readIfExists(join(changeDir, 'decisions.md'))
|
|
489
|
+
const blockers = findBlockingDecisionIssues(decisions)
|
|
490
|
+
for (const issue of blockers) {
|
|
491
|
+
errors.push(getRule('shared.decision-blocker').failMessage.replace('${issue}', issue))
|
|
492
|
+
}
|
|
493
|
+
const decisionIds = extractCurrentDecisionIds(decisions)
|
|
494
|
+
warnMissingIds(warnings, decisionIds, verify, 'verify-result.md', 'decisions.md')
|
|
495
|
+
|
|
496
|
+
// ── FAIL 结论门控(适用于所有变更,不限风险等级)──
|
|
497
|
+
// verify-result.md 结论为 FAIL 时,verify 阶段不能 completed。
|
|
498
|
+
// 历史教训:CLI 曾不校验结论,AI 写 FAIL 后 verify 仍被标记完成并提示"验证通过可以归档"。
|
|
499
|
+
const conclusionStr = extractVerifyConclusion(verify)
|
|
500
|
+
if (conclusionStr === 'FAIL') {
|
|
501
|
+
errors.push(getRule('verify.conclusion.fail-gate').failMessage)
|
|
502
|
+
} else if (!conclusionStr) {
|
|
503
|
+
warnings.push(getRule('verify.conclusion.fail-gate').noConclusionWarning)
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// ── P0: Change Risk Gate — 核心功能缺少真实集成验证时 FAIL ──
|
|
507
|
+
const changeRiskProfile = detectChangeRisk({
|
|
508
|
+
designContent: readIfExists(join(changeDir, 'design.md')),
|
|
509
|
+
planContent: readIfExists(join(changeDir, 'plan.md')),
|
|
510
|
+
})
|
|
511
|
+
const conclusion = extractVerifyConclusion(verify)
|
|
512
|
+
// ── 否定抑制审计(坑 risk-negation-blindness)──
|
|
513
|
+
// 关键词命中被同句否定语境抑制而不参与判级时必须透出:抑制是把双刃剑(「本次不新增
|
|
514
|
+
// daemon」真豁免 vs 靠堆否定措辞静默降级逃证据门控),这里让每次抑制可见可核对;
|
|
515
|
+
// frontmatter risk_level 仍是双向权威覆盖通道。
|
|
516
|
+
if ((changeRiskProfile.suppressedTriggers || []).length > 0) {
|
|
517
|
+
warnings.push(
|
|
518
|
+
`[${changeRiskProfile.level}] 风险判级:关键词命中 ${changeRiskProfile.suppressedTriggers.join(', ')} 已被同句否定语境(不/未/无/避免…)抑制,未参与判级。` +
|
|
519
|
+
`若本变更实际涉及跨进程/状态机/启动入口改动,请在 design.md frontmatter 加 risk_level: integration-critical(或 deployment-critical)显式声明或提供真实集成证据——抑制可审计,不许用来静默降级。`
|
|
520
|
+
)
|
|
521
|
+
}
|
|
522
|
+
if (['integration-critical', 'deployment-critical'].includes(changeRiskProfile.level)) {
|
|
523
|
+
// 关键词误伤早期引导(坑2,FR-02):命中高危关键词且无 frontmatter risk_level 时,
|
|
524
|
+
// 无条件透出 frontmatter 覆盖指引(不依赖 conclusion / evidence),让 agent 早期即可
|
|
525
|
+
// 判断是否属误判并显式覆盖,而非撞到 evidence gate 末尾才发现出路③。含否定语境的
|
|
526
|
+
// 命中已在 detectChangeRisk 内被同句否定抑制(见 change-risk-profile.js NEGATION_CUES),
|
|
527
|
+
// 此处命中的都是无否定语境的真命中;仍误伤的走 frontmatter 显式覆盖通道。
|
|
528
|
+
if (!changeRiskProfile.explicit) {
|
|
529
|
+
warnings.push(
|
|
530
|
+
`[${changeRiskProfile.level}] 本次变更被关键词判级(命中:${changeRiskProfile.triggers.join(', ')})。` +
|
|
531
|
+
`若属关键词误伤(实际未触碰 daemon/session/启动入口/跨进程),可在 design.md frontmatter 加 risk_level: <真实等级>(如 unit-sufficient)显式覆盖后重跑。`
|
|
532
|
+
)
|
|
533
|
+
}
|
|
534
|
+
// 显式 risk_level 声明(design frontmatter,非关键词误判)下,PASS WITH NOTES 视为对残留项的
|
|
535
|
+
// 诚实声明,不强求全量集成证据——豁免本就来自 design 的明确判断。自动关键词判级维持严格:
|
|
536
|
+
// PASS WITH NOTES 仍要求证据齐全,防 agent 用 PASS WITH NOTES 绕证据门控。
|
|
537
|
+
const requiresEvidence = conclusion === 'PASS' || (conclusion === 'PASS WITH NOTES' && !changeRiskProfile.explicit)
|
|
538
|
+
if (conclusion === 'PASS WITH NOTES' && changeRiskProfile.explicit) {
|
|
539
|
+
warnings.push(`[${changeRiskProfile.level}] 结论 PASS WITH NOTES:design frontmatter 显式声明 risk_level=${changeRiskProfile.level},残留项须为真实集成证据缺口,并在 verify-result.md 如实说明`)
|
|
540
|
+
}
|
|
541
|
+
if (requiresEvidence) {
|
|
542
|
+
// CLI 回执注入(坑 verify-literal-evidence-mismatch,2026-08-22 实证:证据第一轮就齐
|
|
543
|
+
// 但自然措辞不含字面词被误拦三轮):verify 服务回收器落的回执 = 真实启动+PID 登记
|
|
544
|
+
// 的结构化证据,作为附加匹配文本——有回执不依赖 agent 措辞;无回执维持原字面匹配
|
|
545
|
+
let receiptText = ''
|
|
546
|
+
try {
|
|
547
|
+
// 回执按变更分片(坑 verify-pids-cross-session-kill:原单份被并行会话后写覆盖),
|
|
548
|
+
// 优先读本变更分片,兼容旧单份名(升级过渡期 receipt.change 过滤仍生效)
|
|
549
|
+
const runtimeDir = join(cwd, '.sillyspec', '.runtime')
|
|
550
|
+
const receiptPath = existsSync(join(runtimeDir, `verify-services-${changeName}.receipt.json`))
|
|
551
|
+
? join(runtimeDir, `verify-services-${changeName}.receipt.json`)
|
|
552
|
+
: join(runtimeDir, 'verify-services.receipt.json')
|
|
553
|
+
if (existsSync(receiptPath)) {
|
|
554
|
+
const receipt = JSON.parse(readFileSync(receiptPath, 'utf8'))
|
|
555
|
+
if (receipt && (receipt.reapedPidCount || 0) > 0 && (!receipt.change || receipt.change === changeName)) {
|
|
556
|
+
receiptText = `CLI 回执:verify 服务进程已回收 ${receipt.reapedPidCount} 个(PID 已登记,真实启动,运行时证据 reapedAt=${receipt.reapedAt})`
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
} catch { /* 回执损坏按无回执处理(fail 回原字面匹配) */ }
|
|
560
|
+
const evidenceCheck = checkIntegrationEvidence(verify, changeRiskProfile.requiredVerification, { extraEvidenceText: receiptText })
|
|
561
|
+
if (!evidenceCheck.ok) {
|
|
562
|
+
// A: 报错说人话 —— 把「缺哪一项、要写/做什么、判级原因」逐条列出,
|
|
563
|
+
// 让 agent 不必靠改结论文案撞墙。detail 指明真实启动须是本变更实际改动的
|
|
564
|
+
// 部署/启动入口(非无关进程),以及每项的字面期望。
|
|
565
|
+
const needs = changeRiskProfile.requiredVerification
|
|
566
|
+
.filter(k => VERIFICATION_NEEDS[k] && VERIFICATION_NEEDS[k].desc)
|
|
567
|
+
.map(k => {
|
|
568
|
+
const vn = VERIFICATION_NEEDS[k]
|
|
569
|
+
const lit = vn.literals && vn.literals.length ? '字面命中其一:' + vn.literals.join(' / ') : ''
|
|
570
|
+
return `\n 〔${k}〕${vn.desc}${lit}`
|
|
571
|
+
})
|
|
572
|
+
.join('')
|
|
573
|
+
const cause = changeRiskProfile.explicit
|
|
574
|
+
? RISK_LEVEL_CAUSES.explicit
|
|
575
|
+
: (RISK_LEVEL_CAUSES[changeRiskProfile.level] || '')
|
|
576
|
+
errors.push(
|
|
577
|
+
`[${changeRiskProfile.level}] 验证结论为 ${conclusion},但缺少真实集成证据。\n` +
|
|
578
|
+
` 缺失项(需在 verify-result.md 如实提供并满足):${evidenceCheck.errors.join('; ')}\n` +
|
|
579
|
+
` 每项要提供什么:${needs}\n` +
|
|
580
|
+
` 风险判级原因:${cause}\n` +
|
|
581
|
+
` 命中触发词:${changeRiskProfile.triggers.join(', ')}\n` +
|
|
582
|
+
` 出路:① 补全上述缺失的真实集成证据(真实启动 daemon/backend、集成测试、运行日志)后保持 PASS;` +
|
|
583
|
+
`或 ② 如实改结论 FAIL(承认端到端未验,留待部署后补);` +
|
|
584
|
+
`或 ③ 若判级是关键词误伤(实际并未触碰 daemon/session/启动入口),在 design.md frontmatter 加 risk_level: <真实等级>(如 unit-sufficient)显式覆盖后重跑。` +
|
|
585
|
+
`仅改结论文案/措辞蹭字面关键词会被对账。`
|
|
586
|
+
)
|
|
587
|
+
}
|
|
588
|
+
warnings.push(...evidenceCheck.warnings)
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
return { ok: errors.length === 0, errors, warnings }
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* 计算归档目标目录名:保持原变更名不变,直接移入 archive/。
|
|
598
|
+
*/
|
|
599
|
+
export function archiveDestDirName(date, changeName) {
|
|
600
|
+
return String(changeName)
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* archive 完成校验:检查归档目录完整性
|
|
605
|
+
*/
|
|
606
|
+
function validateArchiveOutputs(cwd, changeName) {
|
|
607
|
+
const archiveDir = join(cwd, '.sillyspec', 'changes', 'archive')
|
|
608
|
+
const destDir = join(archiveDir, changeName)
|
|
609
|
+
|
|
610
|
+
// 归档目录不存在 early return(引擎在存在时才跑)
|
|
611
|
+
if (!existsSync(destDir)) {
|
|
612
|
+
return { ok: false, errors: [`归档目录缺失: ${destDir}`], warnings: [] }
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// plan.md(必备)/design.md/module-impact.md(推荐)存在性由引擎消费 manifest
|
|
616
|
+
const engineResult = evaluateRules('archive', { archiveDir: destDir }, undefined, { source: 'validateArchiveOutputs' })
|
|
617
|
+
return { ok: engineResult.errors.length === 0, errors: engineResult.errors, warnings: engineResult.warnings }
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* archive 前置校验:所有主流程阶段完成
|
|
622
|
+
*/
|
|
623
|
+
function validateChangeClosed(cwd, changeName) {
|
|
624
|
+
const errors = []
|
|
625
|
+
const warnings = []
|
|
626
|
+
|
|
627
|
+
// 检查前置阶段状态
|
|
628
|
+
const progressDir = join(cwd, '.sillyspec', '.runtime')
|
|
629
|
+
// 这里只做文件层面的检查,DB 检查在 run.js 里做
|
|
630
|
+
const changeDir = join(cwd, '.sillyspec', 'changes', changeName)
|
|
631
|
+
if (!existsSync(changeDir)) {
|
|
632
|
+
errors.push(`变更目录不存在: ${changeDir}`)
|
|
633
|
+
return { ok: false, errors, warnings }
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// plan.md 存在性由引擎消费 manifest(source 区分 validateChangeClosed vs validateArchiveOutputs)
|
|
637
|
+
const engineResult = evaluateRules('archive', { changeDir }, undefined, { source: 'validateChangeClosed' })
|
|
638
|
+
return { ok: engineResult.errors.length === 0, errors: engineResult.errors, warnings: engineResult.warnings }
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// ============ Execute 代码变更客观核验 ============
|
|
642
|
+
|
|
643
|
+
// QUAL-01 收口:本地 execFileSync 裸调(无 safe.directory)→ git-helper safeGit 统一入口,
|
|
644
|
+
// {ok,out,error} 适配语义与 timeout 15000 不变
|
|
645
|
+
function gitTry(dir, args) {
|
|
646
|
+
const r = safeGit(dir, args, { timeout: 15000 })
|
|
647
|
+
if (r.value !== null) return { ok: true, out: r.value }
|
|
648
|
+
return { ok: false, out: '', error: r.error || 'git 执行失败' }
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* 客观核验 execute 阶段是否产生了真实代码变更。
|
|
653
|
+
*
|
|
654
|
+
* 历史漏洞:execute 无 stage-level validator,agent 勾选 plan.md 全部 checkbox
|
|
655
|
+
* 即可让 execute 被标 completed,代码完成度与真实变更完全脱钩。
|
|
656
|
+
*
|
|
657
|
+
* 判定顺序(fail-open on uncertainty,避免环境差异误杀):
|
|
658
|
+
* 1. worktree meta 存在且有 baseHash → 在 worktree 内查 baseHash..HEAD diff + 未提交改动
|
|
659
|
+
* 2. sillyspec/<change> 分支存在 → 查 merge-base..branch diff
|
|
660
|
+
* 3. 主工作区存在未提交改动(apply 后未 commit 的常见形态)→ changed
|
|
661
|
+
* 4. 均无法判定 → unknown(由调用方降级为 warning)
|
|
662
|
+
*
|
|
663
|
+
* @returns {{ status: 'changed'|'unchanged'|'unknown', detail: string }}
|
|
664
|
+
*/
|
|
665
|
+
export function checkExecuteCodeEvidence(cwd, changeName) {
|
|
666
|
+
const metaPath = join(cwd, '.sillyspec', '.runtime', 'worktrees', changeName, 'meta.json')
|
|
667
|
+
let meta = null
|
|
668
|
+
if (existsSync(metaPath)) {
|
|
669
|
+
try { meta = JSON.parse(readFileSync(metaPath, 'utf8')) } catch {}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// 1. worktree(或 in-place)meta 有 baseHash:最权威的对账基准
|
|
673
|
+
if (meta?.baseHash) {
|
|
674
|
+
const gitDir = (meta.worktreePath && meta.mode !== 'in-place-fallback' && existsSync(meta.worktreePath))
|
|
675
|
+
? meta.worktreePath
|
|
676
|
+
: cwd
|
|
677
|
+
const diff = gitTry(gitDir, ['diff', '--name-only', `${meta.baseHash}..HEAD`])
|
|
678
|
+
const status = gitTry(gitDir, ['status', '--porcelain'])
|
|
679
|
+
if (diff.ok && status.ok) {
|
|
680
|
+
const committedFiles = diff.out ? diff.out.split('\n').filter(Boolean).length : 0
|
|
681
|
+
const hasUncommitted = status.out.trim().length > 0
|
|
682
|
+
if (committedFiles > 0 || hasUncommitted) {
|
|
683
|
+
return { status: 'changed', detail: `${committedFiles} 个已提交变更文件${hasUncommitted ? ' + 未提交改动' : ''}(base ${meta.baseHash.slice(0, 8)})` }
|
|
684
|
+
}
|
|
685
|
+
return { status: 'unchanged', detail: `${gitDir} 相对 base ${meta.baseHash.slice(0, 8)} 无任何提交或未提交改动` }
|
|
686
|
+
}
|
|
687
|
+
return { status: 'unknown', detail: `git 核验失败: ${diff.error || status.error}` }
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// 2. worktree 已清理但分支残留:diff merge-base..branch
|
|
691
|
+
const branch = `sillyspec/${changeName}`
|
|
692
|
+
const branchHash = gitTry(cwd, ['rev-parse', '--verify', '--quiet', branch])
|
|
693
|
+
if (branchHash.ok && branchHash.out) {
|
|
694
|
+
const mergeBase = gitTry(cwd, ['merge-base', 'HEAD', branch])
|
|
695
|
+
if (mergeBase.ok && mergeBase.out) {
|
|
696
|
+
const diff = gitTry(cwd, ['diff', '--name-only', `${mergeBase.out}..${branch}`])
|
|
697
|
+
if (diff.ok && diff.out.split('\n').filter(Boolean).length > 0) {
|
|
698
|
+
return { status: 'changed', detail: `分支 ${branch} 相对 merge-base 有变更` }
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
// 3. 主工作区未提交改动(worktree apply 后的常见形态)
|
|
704
|
+
const status = gitTry(cwd, ['status', '--porcelain'])
|
|
705
|
+
if (status.ok && status.out.trim()) {
|
|
706
|
+
return { status: 'changed', detail: '主工作区存在未提交改动' }
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
return { status: 'unknown', detail: '无 worktree meta 且无可对账的分支/未提交改动(变更可能已 apply 并提交),无法客观判定' }
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
/**
|
|
713
|
+
* execute 完成校验:plan.md 声明了任务时,必须存在真实代码变更。
|
|
714
|
+
* 防止"勾选 checkbox = 完成 execute"的谎报路径。
|
|
715
|
+
*/
|
|
716
|
+
function validateExecuteOutputs(cwd, changeName, context = {}) {
|
|
717
|
+
const { specRoot, evidence: passedEvidence } = context
|
|
718
|
+
const errors = []
|
|
719
|
+
const warnings = []
|
|
720
|
+
|
|
721
|
+
const changeDir = resolveChangeDir(cwd, changeName, specRoot)
|
|
722
|
+
const planPath = join(changeDir, 'plan.md')
|
|
723
|
+
// 无 plan.md 的 execute(旧流程/quick 混用)不在此核验范围
|
|
724
|
+
if (!existsSync(planPath)) return { ok: true, errors, warnings }
|
|
725
|
+
|
|
726
|
+
const planContent = readFileSync(planPath, 'utf8')
|
|
727
|
+
const hasTasks = /^\s*[-*]\s*\[[ xX]\]\s*task-\d+/m.test(planContent)
|
|
728
|
+
if (!hasTasks) return { ok: true, errors, warnings }
|
|
729
|
+
|
|
730
|
+
// W4-G (D-008):evidence 可由调用方(runGate)预先算好传入,避免与 execute-evidence check
|
|
731
|
+
// 重复 spawn git(gate execute 一次省 2 个 git 进程 ≈ 60-200ms on Windows)。未传则内部算(向后兼容)。
|
|
732
|
+
const evidence = passedEvidence || checkExecuteCodeEvidence(cwd, changeName)
|
|
733
|
+
if (evidence.status === 'unchanged') {
|
|
734
|
+
errors.push(`execute 代码变更核验失败:plan.md 声明了任务,但 ${evidence.detail} — 勾选 checkbox 不等于完成实现`)
|
|
735
|
+
} else if (evidence.status === 'unknown') {
|
|
736
|
+
warnings.push(`execute 代码变更无法客观核验:${evidence.detail}`)
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
return { ok: errors.length === 0, errors, warnings }
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// ============ Contract Registry ============
|
|
743
|
+
|
|
744
|
+
/**
|
|
745
|
+
* 主流程阶段(有严格转换顺序)
|
|
746
|
+
*/
|
|
747
|
+
const mainFlowStages = ['brainstorm', 'plan', 'execute', 'verify']
|
|
748
|
+
|
|
749
|
+
// 辅助阶段(可独立运行,无严格转换顺序)定义在 constants.js 的 AUXILIARY_STAGES,
|
|
750
|
+
// 与 stages/index.js 共用单一真相源,避免两处逐字重复分叉。
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* @type {Object<string, StageContract>}
|
|
754
|
+
*/
|
|
755
|
+
const contracts = {
|
|
756
|
+
// === 主流程 ===
|
|
757
|
+
brainstorm: {
|
|
758
|
+
stage: 'brainstorm',
|
|
759
|
+
description: '需求分析与设计',
|
|
760
|
+
allowedFrom: [], // 任何变更的起始阶段
|
|
761
|
+
allowedTo: ['plan'],
|
|
762
|
+
validators: [validateBrainstormOutputs],
|
|
763
|
+
},
|
|
764
|
+
plan: {
|
|
765
|
+
stage: 'plan',
|
|
766
|
+
description: '任务拆解与规划',
|
|
767
|
+
allowedFrom: ['brainstorm'],
|
|
768
|
+
allowedTo: ['execute'],
|
|
769
|
+
validators: [validatePlanOutputs],
|
|
770
|
+
},
|
|
771
|
+
execute: {
|
|
772
|
+
stage: 'execute',
|
|
773
|
+
description: '代码实现',
|
|
774
|
+
allowedFrom: ['plan'],
|
|
775
|
+
allowedTo: ['verify'],
|
|
776
|
+
validators: [validateExecuteOutputs],
|
|
777
|
+
},
|
|
778
|
+
verify: {
|
|
779
|
+
stage: 'verify',
|
|
780
|
+
description: '验证与测试',
|
|
781
|
+
allowedFrom: ['execute'],
|
|
782
|
+
allowedTo: ['archive'],
|
|
783
|
+
validators: [validateVerifyOutputs],
|
|
784
|
+
},
|
|
785
|
+
archive: {
|
|
786
|
+
stage: 'archive',
|
|
787
|
+
description: '归档与收口',
|
|
788
|
+
allowedFrom: ['verify'],
|
|
789
|
+
allowedTo: [],
|
|
790
|
+
// 阶段级 validator 全部移除,改为 run.js 中 step 4 完成后的硬编码校验。
|
|
791
|
+
// 理由:两个 validator 的生效窗口互斥 ——
|
|
792
|
+
// validateChangeClosed 要求变更目录存在(step 4 --confirm 后已被移到 archive 目录)
|
|
793
|
+
// validateArchiveOutputs 要求 archive 目录存在(step 4 前还不存在)
|
|
794
|
+
// 注册为阶段级 validator 会导致每步都误报错误。
|
|
795
|
+
// run.js:893-909 已在正确的时机(step 4 完成后)执行相同检查。
|
|
796
|
+
validators: [],
|
|
797
|
+
},
|
|
798
|
+
|
|
799
|
+
// === 辅助阶段 ===
|
|
800
|
+
scan: {
|
|
801
|
+
stage: 'scan',
|
|
802
|
+
description: '项目扫描',
|
|
803
|
+
allowedFrom: [], // 无前置要求
|
|
804
|
+
allowedTo: [], // 不进入主流程
|
|
805
|
+
validators: [validateScanOutputs],
|
|
806
|
+
},
|
|
807
|
+
quick: {
|
|
808
|
+
stage: 'quick',
|
|
809
|
+
description: '快速任务',
|
|
810
|
+
allowedFrom: [], // 无前置要求
|
|
811
|
+
allowedTo: [], // 不进入主流程
|
|
812
|
+
validators: [],
|
|
813
|
+
},
|
|
814
|
+
explore: {
|
|
815
|
+
stage: 'explore',
|
|
816
|
+
description: '代码探索',
|
|
817
|
+
allowedFrom: [],
|
|
818
|
+
allowedTo: [],
|
|
819
|
+
validators: [],
|
|
820
|
+
},
|
|
821
|
+
status: {
|
|
822
|
+
stage: 'status',
|
|
823
|
+
description: '项目快照',
|
|
824
|
+
allowedFrom: [],
|
|
825
|
+
allowedTo: [],
|
|
826
|
+
validators: [],
|
|
827
|
+
},
|
|
828
|
+
doctor: {
|
|
829
|
+
stage: 'doctor',
|
|
830
|
+
description: '环境诊断',
|
|
831
|
+
allowedFrom: [],
|
|
832
|
+
allowedTo: [],
|
|
833
|
+
validators: [],
|
|
834
|
+
},
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
// ============ Public API ============
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* 获取阶段合约
|
|
841
|
+
*/
|
|
842
|
+
export function getContract(stageName) {
|
|
843
|
+
return contracts[stageName] || null
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
/**
|
|
847
|
+
* 校验状态转换是否允许
|
|
848
|
+
* @param {string} fromStage - 当前阶段(空字符串表示变更起始)
|
|
849
|
+
* @param {string} toStage - 目标阶段
|
|
850
|
+
* @param {{ fromStageData?: { status?: string } | undefined }} [options] - 可选,从 progress.stages[prevStage] 提取
|
|
851
|
+
* @returns {{ allowed: boolean, reason?: string }}
|
|
852
|
+
*/
|
|
853
|
+
export function checkTransition(fromStage, toStage, options = {}) {
|
|
854
|
+
const { fromStageData } = options // { status?: string } | undefined
|
|
855
|
+
const contract = contracts[toStage]
|
|
856
|
+
if (!contract) {
|
|
857
|
+
return { allowed: false, reason: `未知阶段: ${toStage}` }
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// 辅助阶段随时可执行(archive 除外:从主流程进入 archive 需要校验)
|
|
861
|
+
if (AUXILIARY_STAGES.includes(toStage) && toStage !== 'archive') {
|
|
862
|
+
return { allowed: true }
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
// 同阶段内重复运行:允许(继续执行当前阶段的下一步、或修订模式继续)
|
|
866
|
+
if (fromStage === toStage) {
|
|
867
|
+
return { allowed: true }
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
// task-07: failed_post_check 门控
|
|
871
|
+
// scan post-check 未通过时,禁止进入主流程的下游阶段(brainstorm/plan/execute/verify/archive)
|
|
872
|
+
// 必须先重跑 scan 修复。toStage === 'scan' 的重跑路径已被上方 fromStage === toStage 放行。
|
|
873
|
+
// fromStageData.status 缺失(旧数据)时门控不触发(向后兼容)。
|
|
874
|
+
if (fromStage === 'scan' && fromStageData?.status === 'failed_post_check' && toStage !== 'scan') {
|
|
875
|
+
return {
|
|
876
|
+
allowed: false,
|
|
877
|
+
reason: 'scan post-check 未通过(failed_post_check),需修复后重跑 scan 再进入 ' + toStage,
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
// archive 特殊处理:从 verify 来的允许,从其他主流程阶段来的需要校验
|
|
882
|
+
if (toStage === 'archive') {
|
|
883
|
+
if (fromStage === 'verify') {
|
|
884
|
+
return { allowed: true }
|
|
885
|
+
}
|
|
886
|
+
// 独立运行 archive(无前置)也允许
|
|
887
|
+
if (!fromStage || AUXILIARY_STAGES.includes(fromStage)) {
|
|
888
|
+
return { allowed: true }
|
|
889
|
+
}
|
|
890
|
+
return { allowed: false, reason: 'archive 的前置阶段是 verify,不能从 ' + fromStage + ' 跳转' }
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
// 从辅助阶段进入主流程:允许
|
|
894
|
+
if (AUXILIARY_STAGES.includes(fromStage)) {
|
|
895
|
+
return { allowed: true }
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
// 无前置阶段(变更起始):只能开始 brainstorm 或辅助阶段
|
|
899
|
+
if (!fromStage) {
|
|
900
|
+
// 主流程必须从 brainstorm 开始
|
|
901
|
+
if (contract.allowedFrom.length === 0) {
|
|
902
|
+
return { allowed: true }
|
|
903
|
+
}
|
|
904
|
+
return { allowed: false, reason: `${toStage} 需要先完成 ${contract.allowedFrom.join(' 或 ')}` }
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
// 主流程内部跳转:检查目标阶段的 allowedFrom 是否包含 fromStage
|
|
908
|
+
if (contract.allowedFrom.includes(fromStage)) {
|
|
909
|
+
return { allowed: true }
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
return { allowed: false, reason: `${toStage} 的前置阶段是 ${contract.allowedFrom.join(' 或 ')},不能从 ${fromStage} 跳转` }
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
/**
|
|
916
|
+
* 执行阶段完成校验
|
|
917
|
+
* @param {string} stageName
|
|
918
|
+
* @param {string} cwd
|
|
919
|
+
* @param {string} changeName
|
|
920
|
+
* @param {object} context - 额外上下文(如 projectName)
|
|
921
|
+
* @returns {ValidationResult}
|
|
922
|
+
*/
|
|
923
|
+
export function runValidators(stageName, cwd, changeName, context = {}) {
|
|
924
|
+
const contract = contracts[stageName]
|
|
925
|
+
if (!contract || contract.validators.length === 0) {
|
|
926
|
+
return { ok: true, errors: [], warnings: [] }
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
const allErrors = []
|
|
930
|
+
const allWarnings = []
|
|
931
|
+
|
|
932
|
+
for (const validator of contract.validators) {
|
|
933
|
+
try {
|
|
934
|
+
const result = validator(cwd, changeName, context)
|
|
935
|
+
allErrors.push(...(result.errors || []))
|
|
936
|
+
allWarnings.push(...(result.warnings || []))
|
|
937
|
+
} catch (e) {
|
|
938
|
+
allErrors.push(`校验器 ${validator.name || 'unknown'} 异常: ${e.message}`)
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
return { ok: allErrors.length === 0, errors: allErrors, warnings: allWarnings }
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
/**
|
|
946
|
+
* 获取所有主流程阶段
|
|
947
|
+
*/
|
|
948
|
+
export { mainFlowStages, AUXILIARY_STAGES as auxiliaryStages }
|