sillyspec 3.27.2 → 3.27.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/sillyspec-execute/SKILL.md +8 -0
- package/.claude/skills/sillyspec-quick/SKILL.md +2 -1
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-archive/SKILL.md +87 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-auto/SKILL.md +93 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-commit/SKILL.md +67 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-continue/SKILL.md +47 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-execute/SKILL.md +214 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-explore/SKILL.md +102 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-export/SKILL.md +57 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-init/SKILL.md +177 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-plan/SKILL.md +156 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-quick/SKILL.md +116 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-resume/SKILL.md +70 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-scan/SKILL.md +79 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-state/SKILL.md +64 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-status/SKILL.md +54 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-verify/SKILL.md +87 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
- package/.claude/worktrees/sillyspec-data-model-research/.gitattributes +2 -0
- package/.claude/worktrees/sillyspec-data-model-research/.husky/pre-push +20 -0
- package/.claude/worktrees/sillyspec-data-model-research/README.md +203 -0
- package/.claude/worktrees/sillyspec-data-model-research/SKILL.md +91 -0
- package/.claude/worktrees/sillyspec-data-model-research/bin/sillyspec.js +2 -0
- package/.claude/worktrees/sillyspec-data-model-research/logo.jpg +0 -0
- package/.claude/worktrees/sillyspec-data-model-research/package-lock.json +977 -0
- package/.claude/worktrees/sillyspec-data-model-research/package.json +39 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/favicon.jpg +0 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/index.html +16 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/logo.jpg +0 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/prototype-dashboard.html +836 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/prototype-overview.html +256 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/package.json +25 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/executor.js +95 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/index.js +679 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/parser.js +526 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/watcher.js +357 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/agent-session-log.js +803 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/change-list.js +290 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/change-risk-profile.js +270 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/check-primitives.js +65 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/classify-change.js +109 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/commit-suggest.js +202 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/config-cat.js +88 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/config-schema.js +328 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/constants.js +97 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/contract-matrix.js +480 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/datetime.js +20 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/db-engine.js +55 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/db.js +381 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/decision-distill.js +517 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/backends/local-agent.js +155 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/backends/sillyhub-mcp.js +245 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/probe.js +246 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/strategy.js +121 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/docs-check.js +825 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/docs-debt.js +393 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/docs-gate.js +107 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/doctor-diagnostics.js +1099 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/endpoint-extractor.js +420 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/foreign-declared.js +78 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/fs-atomic.js +73 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/git-helper.js +150 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/hooks/claude-pre-tool-use.cjs +130 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/hooks/worktree-guard.js +892 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/index.js +2798 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/init.js +626 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/knowledge-match.js +231 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/local-detect.js +128 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/local-register.js +104 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/machine-interface.js +543 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/migrate.js +127 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/module-impact.js +166 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/module-resolve.js +222 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/modules.js +580 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/progress/change-registry.js +336 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/progress/consistency-doctor.js +355 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/progress/shared.js +36 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/progress/stage-machine.js +594 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/progress/step-store.js +265 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/progress.js +1304 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/quick-recommend.js +115 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/quicklog.js +852 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/review-tier.js +77 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/command.js +1595 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/complete-handlers.js +1552 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/complete.js +1259 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/concurrent-detect.js +156 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/gates.js +1084 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/multi-repo-context.js +208 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/next.js +128 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/prompt.js +843 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/quick-audit.js +186 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/scan-profile.js +269 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/shared.js +1562 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/stage.js +584 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run.js +23 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/scan-diff.js +388 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/scan-postcheck.js +512 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/scan-staleness.js +95 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/setup.js +414 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/sillyhub-mcp/client.js +597 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/sillyhub-mcp/config.js +62 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/spec-dir-typo.js +50 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/spec-sync.js +358 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract-engine.js +171 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract-spec.js +550 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract.js +889 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stage-review.js +597 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/archive.js +199 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/brainstorm-auto.js +236 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/brainstorm.js +617 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/cmd-existence.js +145 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/doctor.js +540 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/execute.js +1275 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/explore.js +43 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/index.js +29 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/knowledge.js +514 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/plan-postcheck.js +1344 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/plan.js +650 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/quick.js +167 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/scan.js +608 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/status.js +64 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/verify.js +246 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/sync.js +1470 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/task-review.js +1498 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/taskcard.js +210 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/verify-postcheck.js +1718 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/verify-probes.js +277 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/version.js +19 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/workflow.js +600 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/workspace.js +125 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/worktree-apply.js +1446 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/worktree-deps.js +576 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/worktree.js +1715 -0
- package/.claude/worktrees/sillyspec-data-model-research/templates/claude-instruction.md +23 -0
- package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/taskcard-rules.md +28 -0
- package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/testcase-design.md +12 -0
- package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/verify-probes.md +32 -0
- package/.claude/worktrees/sillyspec-data-model-research/templates/workflows/archive-impact.yaml +79 -0
- package/.claude/worktrees/sillyspec-data-model-research/templates/workflows/scan-docs.yaml +132 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-archive/SKILL.md +87 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-auto/SKILL.md +93 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-commit/SKILL.md +67 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-continue/SKILL.md +47 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-execute/SKILL.md +214 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-explore/SKILL.md +102 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-export/SKILL.md +57 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-init/SKILL.md +177 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-plan/SKILL.md +156 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-propose/SKILL.md +87 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-quick/SKILL.md +116 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-resume/SKILL.md +70 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-scan/SKILL.md +79 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-state/SKILL.md +64 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-status/SKILL.md +54 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-verify/SKILL.md +87 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
- package/.worktrees/8d2d0392/.claude/skills/verify-per-user/SKILL.md +6 -0
- package/.worktrees/8d2d0392/.gitattributes +2 -0
- package/.worktrees/8d2d0392/.husky/pre-push +20 -0
- package/.worktrees/8d2d0392/README.md +203 -0
- package/.worktrees/8d2d0392/SKILL.md +91 -0
- package/.worktrees/8d2d0392/architecture-analysis.md +448 -0
- package/.worktrees/8d2d0392/bin/sillyspec.js +2 -0
- package/.worktrees/8d2d0392/eval/README.md +86 -0
- package/.worktrees/8d2d0392/eval/eval.config.json +28 -0
- package/.worktrees/8d2d0392/eval/lib/adapters/cli.mjs +63 -0
- package/.worktrees/8d2d0392/eval/lib/adapters/dryrun.mjs +27 -0
- package/.worktrees/8d2d0392/eval/lib/config.mjs +82 -0
- package/.worktrees/8d2d0392/eval/lib/db.mjs +76 -0
- package/.worktrees/8d2d0392/eval/lib/report.mjs +120 -0
- package/.worktrees/8d2d0392/eval/lib/runner.mjs +157 -0
- package/.worktrees/8d2d0392/eval/lib/tasks.mjs +73 -0
- package/.worktrees/8d2d0392/eval/lib/util.mjs +107 -0
- package/.worktrees/8d2d0392/eval/lib/workdir.mjs +30 -0
- package/.worktrees/8d2d0392/eval/run.mjs +83 -0
- package/.worktrees/8d2d0392/eval/tasks/001-slugify/files/package.json +6 -0
- package/.worktrees/8d2d0392/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
- package/.worktrees/8d2d0392/eval/tasks/001-slugify/task.json +6 -0
- package/.worktrees/8d2d0392/eval/tasks/001-slugify/verify.mjs +28 -0
- package/.worktrees/8d2d0392/eval/tasks/002-each-day/files/package.json +6 -0
- package/.worktrees/8d2d0392/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
- package/.worktrees/8d2d0392/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
- package/.worktrees/8d2d0392/eval/tasks/002-each-day/task.json +6 -0
- package/.worktrees/8d2d0392/eval/tasks/002-each-day/verify.mjs +31 -0
- package/.worktrees/8d2d0392/eval/tasks/003-word-report/files/data/notes.txt +5 -0
- package/.worktrees/8d2d0392/eval/tasks/003-word-report/files/package.json +6 -0
- package/.worktrees/8d2d0392/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
- package/.worktrees/8d2d0392/eval/tasks/003-word-report/task.json +6 -0
- package/.worktrees/8d2d0392/eval/tasks/003-word-report/verify.mjs +38 -0
- package/.worktrees/8d2d0392/logo.jpg +0 -0
- package/.worktrees/8d2d0392/package-lock.json +977 -0
- package/.worktrees/8d2d0392/package.json +41 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/favicon.jpg +0 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/index.html +16 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/logo.jpg +0 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/prototype-dashboard.html +836 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/prototype-overview.html +256 -0
- package/.worktrees/8d2d0392/packages/dashboard/package.json +25 -0
- package/.worktrees/8d2d0392/packages/dashboard/server/executor.js +95 -0
- package/.worktrees/8d2d0392/packages/dashboard/server/index.js +679 -0
- package/.worktrees/8d2d0392/packages/dashboard/server/parser.js +526 -0
- package/.worktrees/8d2d0392/packages/dashboard/server/watcher.js +357 -0
- package/.worktrees/8d2d0392/src/agent-session-log.js +803 -0
- package/.worktrees/8d2d0392/src/change-list.js +290 -0
- package/.worktrees/8d2d0392/src/change-risk-profile.js +339 -0
- package/.worktrees/8d2d0392/src/check-primitives.js +65 -0
- package/.worktrees/8d2d0392/src/classify-change.js +109 -0
- package/.worktrees/8d2d0392/src/commit-suggest.js +202 -0
- package/.worktrees/8d2d0392/src/config-cat.js +88 -0
- package/.worktrees/8d2d0392/src/config-schema.js +328 -0
- package/.worktrees/8d2d0392/src/constants.js +97 -0
- package/.worktrees/8d2d0392/src/contract-matrix.js +533 -0
- package/.worktrees/8d2d0392/src/datetime.js +20 -0
- package/.worktrees/8d2d0392/src/db-engine.js +55 -0
- package/.worktrees/8d2d0392/src/db.js +381 -0
- package/.worktrees/8d2d0392/src/decision-distill.js +517 -0
- package/.worktrees/8d2d0392/src/dispatch/backends/local-agent.js +155 -0
- package/.worktrees/8d2d0392/src/dispatch/backends/sillyhub-mcp.js +245 -0
- package/.worktrees/8d2d0392/src/dispatch/probe.js +246 -0
- package/.worktrees/8d2d0392/src/dispatch/strategy.js +121 -0
- package/.worktrees/8d2d0392/src/docs-check.js +825 -0
- package/.worktrees/8d2d0392/src/docs-debt.js +393 -0
- package/.worktrees/8d2d0392/src/docs-gate.js +107 -0
- package/.worktrees/8d2d0392/src/doctor-diagnostics.js +1099 -0
- package/.worktrees/8d2d0392/src/endpoint-extractor.js +409 -0
- package/.worktrees/8d2d0392/src/foreign-declared.js +78 -0
- package/.worktrees/8d2d0392/src/fs-atomic.js +73 -0
- package/.worktrees/8d2d0392/src/git-helper.js +150 -0
- package/.worktrees/8d2d0392/src/hooks/claude-pre-tool-use.cjs +130 -0
- package/.worktrees/8d2d0392/src/hooks/worktree-guard.js +892 -0
- package/.worktrees/8d2d0392/src/index.js +2854 -0
- package/.worktrees/8d2d0392/src/init.js +626 -0
- package/.worktrees/8d2d0392/src/knowledge-match.js +231 -0
- package/.worktrees/8d2d0392/src/local-detect.js +128 -0
- package/.worktrees/8d2d0392/src/local-register.js +104 -0
- package/.worktrees/8d2d0392/src/machine-interface.js +543 -0
- package/.worktrees/8d2d0392/src/migrate.js +127 -0
- package/.worktrees/8d2d0392/src/module-impact.js +166 -0
- package/.worktrees/8d2d0392/src/module-resolve.js +222 -0
- package/.worktrees/8d2d0392/src/modules.js +580 -0
- package/.worktrees/8d2d0392/src/plan-adopt-waves.js +126 -0
- package/.worktrees/8d2d0392/src/progress/change-registry.js +336 -0
- package/.worktrees/8d2d0392/src/progress/consistency-doctor.js +355 -0
- package/.worktrees/8d2d0392/src/progress/shared.js +36 -0
- package/.worktrees/8d2d0392/src/progress/stage-machine.js +594 -0
- package/.worktrees/8d2d0392/src/progress/step-store.js +265 -0
- package/.worktrees/8d2d0392/src/progress.js +1304 -0
- package/.worktrees/8d2d0392/src/quick-recommend.js +115 -0
- package/.worktrees/8d2d0392/src/quicklog.js +883 -0
- package/.worktrees/8d2d0392/src/review-tier.js +77 -0
- package/.worktrees/8d2d0392/src/run/command.js +1641 -0
- package/.worktrees/8d2d0392/src/run/complete-handlers.js +1552 -0
- package/.worktrees/8d2d0392/src/run/complete.js +1259 -0
- package/.worktrees/8d2d0392/src/run/concurrent-detect.js +156 -0
- package/.worktrees/8d2d0392/src/run/gates.js +1094 -0
- package/.worktrees/8d2d0392/src/run/multi-repo-context.js +208 -0
- package/.worktrees/8d2d0392/src/run/next.js +128 -0
- package/.worktrees/8d2d0392/src/run/prompt.js +843 -0
- package/.worktrees/8d2d0392/src/run/quick-audit.js +186 -0
- package/.worktrees/8d2d0392/src/run/scan-profile.js +269 -0
- package/.worktrees/8d2d0392/src/run/shared.js +1562 -0
- package/.worktrees/8d2d0392/src/run/stage.js +587 -0
- package/.worktrees/8d2d0392/src/run.js +23 -0
- package/.worktrees/8d2d0392/src/scan-diff.js +388 -0
- package/.worktrees/8d2d0392/src/scan-postcheck.js +524 -0
- package/.worktrees/8d2d0392/src/scan-staleness.js +95 -0
- package/.worktrees/8d2d0392/src/setup.js +414 -0
- package/.worktrees/8d2d0392/src/sillyhub-mcp/client.js +597 -0
- package/.worktrees/8d2d0392/src/sillyhub-mcp/config.js +62 -0
- package/.worktrees/8d2d0392/src/spec-dir-typo.js +50 -0
- package/.worktrees/8d2d0392/src/spec-sync.js +358 -0
- package/.worktrees/8d2d0392/src/stage-contract-engine.js +171 -0
- package/.worktrees/8d2d0392/src/stage-contract-spec.js +551 -0
- package/.worktrees/8d2d0392/src/stage-contract.js +948 -0
- package/.worktrees/8d2d0392/src/stage-review.js +597 -0
- package/.worktrees/8d2d0392/src/stages/archive.js +199 -0
- package/.worktrees/8d2d0392/src/stages/brainstorm-auto.js +285 -0
- package/.worktrees/8d2d0392/src/stages/brainstorm.js +624 -0
- package/.worktrees/8d2d0392/src/stages/cmd-existence.js +145 -0
- package/.worktrees/8d2d0392/src/stages/doctor.js +540 -0
- package/.worktrees/8d2d0392/src/stages/execute.js +1277 -0
- package/.worktrees/8d2d0392/src/stages/explore.js +43 -0
- package/.worktrees/8d2d0392/src/stages/index.js +29 -0
- package/.worktrees/8d2d0392/src/stages/knowledge.js +514 -0
- package/.worktrees/8d2d0392/src/stages/plan-postcheck.js +1398 -0
- package/.worktrees/8d2d0392/src/stages/plan.js +651 -0
- package/.worktrees/8d2d0392/src/stages/quick.js +167 -0
- package/.worktrees/8d2d0392/src/stages/scan.js +608 -0
- package/.worktrees/8d2d0392/src/stages/status.js +64 -0
- package/.worktrees/8d2d0392/src/stages/verify.js +246 -0
- package/.worktrees/8d2d0392/src/sync.js +1470 -0
- package/.worktrees/8d2d0392/src/task-review.js +1498 -0
- package/.worktrees/8d2d0392/src/taskcard-placeholders.js +21 -0
- package/.worktrees/8d2d0392/src/taskcard.js +217 -0
- package/.worktrees/8d2d0392/src/verify-postcheck.js +1718 -0
- package/.worktrees/8d2d0392/src/verify-probes.js +327 -0
- package/.worktrees/8d2d0392/src/version.js +19 -0
- package/.worktrees/8d2d0392/src/workflow.js +600 -0
- package/.worktrees/8d2d0392/src/workspace.js +125 -0
- package/.worktrees/8d2d0392/src/worktree-apply.js +1611 -0
- package/.worktrees/8d2d0392/src/worktree-deps.js +576 -0
- package/.worktrees/8d2d0392/src/worktree.js +1838 -0
- package/.worktrees/8d2d0392/templates/claude-instruction.md +23 -0
- package/.worktrees/8d2d0392/templates/prompts/taskcard-rules.md +29 -0
- package/.worktrees/8d2d0392/templates/prompts/testcase-design.md +12 -0
- package/.worktrees/8d2d0392/templates/prompts/verify-probes.md +32 -0
- package/.worktrees/8d2d0392/templates/workflows/archive-impact.yaml +79 -0
- package/.worktrees/8d2d0392/templates/workflows/scan-docs.yaml +132 -0
- package/architecture-analysis.md +448 -0
- package/eval/README.md +86 -0
- package/eval/eval.config.json +28 -0
- package/eval/lib/adapters/cli.mjs +63 -0
- package/eval/lib/adapters/dryrun.mjs +27 -0
- package/eval/lib/config.mjs +82 -0
- package/eval/lib/db.mjs +76 -0
- package/eval/lib/report.mjs +120 -0
- package/eval/lib/runner.mjs +157 -0
- package/eval/lib/tasks.mjs +73 -0
- package/eval/lib/util.mjs +107 -0
- package/eval/lib/workdir.mjs +30 -0
- package/eval/run.mjs +83 -0
- package/eval/tasks/001-slugify/files/package.json +6 -0
- package/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
- package/eval/tasks/001-slugify/task.json +6 -0
- package/eval/tasks/001-slugify/verify.mjs +28 -0
- package/eval/tasks/002-each-day/files/package.json +6 -0
- package/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
- package/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
- package/eval/tasks/002-each-day/task.json +6 -0
- package/eval/tasks/002-each-day/verify.mjs +31 -0
- package/eval/tasks/003-word-report/files/data/notes.txt +5 -0
- package/eval/tasks/003-word-report/files/package.json +6 -0
- package/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
- package/eval/tasks/003-word-report/task.json +6 -0
- package/eval/tasks/003-word-report/verify.mjs +38 -0
- package/package.json +4 -2
- package/src/agent-session-log.js +45 -5
- package/src/change-risk-profile.js +83 -14
- package/src/config-schema.js +18 -3
- package/src/contract-matrix.js +90 -29
- package/src/datetime.js +20 -0
- package/src/decision-distill.js +517 -0
- package/src/dispatch/backends/local-agent.js +4 -4
- package/src/docs-check.js +227 -0
- package/src/docs-debt.js +187 -24
- package/src/doctor-diagnostics.js +102 -2
- package/src/endpoint-extractor.js +41 -52
- package/src/foreign-declared.js +155 -0
- package/src/index.js +95 -13
- package/src/init.js +9 -7
- package/src/knowledge-match.js +107 -6
- package/src/local-register.js +7 -1
- package/src/module-resolve.js +12 -1
- package/src/modules.js +2 -1
- package/src/plan-adopt-waves.js +126 -0
- package/src/quicklog.js +50 -4
- package/src/run/command.js +124 -44
- package/src/run/complete-handlers.js +48 -19
- package/src/run/complete.js +5 -2
- package/src/run/gates.js +104 -22
- package/src/run/prompt.js +84 -42
- package/src/run/quick-audit.js +11 -0
- package/src/run/shared.js +152 -10
- package/src/run/stage.js +8 -5
- package/src/run.js +2 -2
- package/src/scan-postcheck.js +30 -17
- package/src/stage-contract-spec.js +3 -2
- package/src/stage-contract.js +68 -4
- package/src/stages/archive.js +53 -12
- package/src/stages/brainstorm-auto.js +50 -1
- package/src/stages/brainstorm.js +13 -0
- package/src/stages/doctor.js +157 -1
- package/src/stages/execute.js +32 -6
- package/src/stages/plan-postcheck.js +76 -17
- package/src/stages/plan.js +9 -4
- package/src/stages/quick.js +6 -1
- package/src/stages/verify.js +32 -15
- package/src/sync.js +41 -3
- package/src/task-review.js +2 -2
- package/src/taskcard-placeholders.js +21 -0
- package/src/taskcard.js +43 -1
- package/src/verify-postcheck.js +315 -13
- package/src/verify-probes.js +73 -10
- package/src/worktree-apply.js +569 -227
- package/src/worktree-deps.js +150 -1
- package/src/worktree.js +285 -77
- package/templates/prompts/taskcard-rules.md +2 -1
package/src/run/command.js
CHANGED
|
@@ -23,7 +23,7 @@ import { basename, join, resolve, dirname } from 'node:path'
|
|
|
23
23
|
import { existsSync, readdirSync, mkdirSync, writeFileSync, readFileSync, rmSync } from 'node:fs'
|
|
24
24
|
import { randomBytes, randomUUID } from 'node:crypto'
|
|
25
25
|
import { writeAtomicSync } from '../fs-atomic.js'
|
|
26
|
-
import { resolveSpecDir, countAncestorSpecDirs, resolveChangeDir, triggerSync, getStageSteps, formatWaitOptions, checkApproval, warnApprovalUnknown, didYouMean, assertSafeChangeName, detectQuickSessionDrift, detectWorktreeSpecDrift, resolveRuntimeRoot, writePlatformPointer, checkPlatformManaged, PLATFORM_MANAGED_FILENAME } from './shared.js'
|
|
26
|
+
import { resolveSpecDir, countAncestorSpecDirs, resolveChangeDir, triggerSync, getStageSteps, formatWaitOptions, checkApproval, warnApprovalUnknown, didYouMean, assertSafeChangeName, detectQuickSessionDrift, detectWorktreeSpecDrift, resolveRuntimeRoot, writePlatformPointer, checkPlatformManaged, isSelfReferentialSpecRoot, PLATFORM_MANAGED_FILENAME } from './shared.js'
|
|
27
27
|
import { resolveQuickLinkedChanges } from './quick-audit.js'
|
|
28
28
|
import { outputStep } from './prompt.js'
|
|
29
29
|
import { completeStep, skipStep, waitStep, continueStep } from './complete.js'
|
|
@@ -319,19 +319,27 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
319
319
|
try {
|
|
320
320
|
const { readFileSync } = await import('fs')
|
|
321
321
|
const saved = JSON.parse(readFileSync(platformOptsFile, 'utf8'))
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
322
|
+
// 自指指针免疫(FR-4,变更 2026-08-23-repo-native-spec-backfill):saved.specRoot 经
|
|
323
|
+
// realpath 解析回本地 .sillyspec(repo-native junction 回环,旧模板投毒残留)→ 整体
|
|
324
|
+
// 忽略恢复(specRoot/runtimeRoot/workspaceId/scanRunId 全不回填,platformOpts 保持
|
|
325
|
+
// 无平台参数状态),按本地模式运行——内置 sync 走本地链路,specRoot 保持本地取值链。
|
|
326
|
+
if (isSelfReferentialSpecRoot(cwd, saved.specRoot)) {
|
|
327
|
+
console.warn(`⚠️ 检测到自指平台指针(repo-native junction 回环,specRoot 指回本地 .sillyspec),已忽略并按本地模式运行: ${platformOptsFile}`)
|
|
328
|
+
} else {
|
|
329
|
+
if (saved.specRoot) platformOpts.specRoot = saved.specRoot
|
|
330
|
+
if (saved.runtimeRoot) platformOpts.runtimeRoot = saved.runtimeRoot
|
|
331
|
+
if (saved.workspaceId) platformOpts.workspaceId = saved.workspaceId
|
|
332
|
+
if (saved.scanRunId) platformOpts.scanRunId = saved.scanRunId
|
|
333
|
+
// 平台模式 fail-fast:文件存在但缺少 specRoot
|
|
334
|
+
if (!platformOpts.specRoot && !platformOpts.runtimeRoot) {
|
|
335
|
+
console.error(`❌ 平台模式参数文件存在但缺少 specRoot/runtimeRoot: ${platformOptsFile}`)
|
|
336
|
+
console.error(' 可能原因:platform-scan.json 损坏或写入不完整')
|
|
337
|
+
console.error(' 解决:重新运行首次 scan 并传入 --spec-root')
|
|
338
|
+
process.exit(2) // 环境错(平台文件损坏)→ exit 2
|
|
339
|
+
}
|
|
340
|
+
// 恢复成功:更新 specRoot(初始值可能是 cwd/.sillyspec,恢复后应为真实 specDir)
|
|
341
|
+
specRoot = platformOpts.specRoot || specRoot
|
|
332
342
|
}
|
|
333
|
-
// 恢复成功:更新 specRoot(初始值可能是 cwd/.sillyspec,恢复后应为真实 specDir)
|
|
334
|
-
specRoot = platformOpts.specRoot || specRoot
|
|
335
343
|
} catch (e) {
|
|
336
344
|
console.error(`❌ 平台模式参数文件读取失败: ${platformOptsFile}`)
|
|
337
345
|
console.error(` 错误: ${e.message}`)
|
|
@@ -349,12 +357,20 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
349
357
|
if (!platformOpts.specRoot && !platformOpts.runtimeRoot && !platformFileExists) {
|
|
350
358
|
const decl = checkPlatformManaged(cwd)
|
|
351
359
|
if (decl) {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
//
|
|
356
|
-
|
|
357
|
-
|
|
360
|
+
// 陈旧自指声明降级(FR-4,变更 2026-08-23-repo-native-spec-backfill):decl.specRoot 经
|
|
361
|
+
// realpath 解析回本地 .sillyspec(repo-native junction 投毒残留、指针已被清理)→ 视为
|
|
362
|
+
// 陈旧声明,warn 后按本地模式继续(不 exit 1)——声明描述的"平台接管"物理上指向本地
|
|
363
|
+
// .sillyspec,无跨库状态分裂风险;非自指声明维持 fail-closed 原样(状态保护阻断)。
|
|
364
|
+
if (isSelfReferentialSpecRoot(cwd, decl.specRoot)) {
|
|
365
|
+
console.warn(`⚠️ 检测到陈旧的自指平台接管声明(repo-native junction 回环,原 specRoot 指回本地 .sillyspec),已降级并按本地模式运行;可 sillyspec platform disconnect 清理残留声明: ${join(cwd, PLATFORM_MANAGED_FILENAME)}`)
|
|
366
|
+
} else {
|
|
367
|
+
console.error(`❌ 平台接管声明生效:本项目已由平台托管(原 specRoot: ${decl.specRoot || '(未记录)'}),但恢复指针缺失,拒绝静默回退本地模式。`)
|
|
368
|
+
console.error(` 声明文件: ${join(cwd, PLATFORM_MANAGED_FILENAME)}`)
|
|
369
|
+
console.error(' 恢复:① 重跑平台 scan/init(带 --spec-root)重建指针;② 确认不再使用平台:sillyspec platform disconnect(删除接管声明);③ 显式 --spec-dir <路径> 临时指定目录。')
|
|
370
|
+
// exit(1) 而非邻近环境错的 exit(2):这是"状态保护阻断"(对齐 PointerUnreachableError
|
|
371
|
+
// 顶层 catch 语义),非"用法/环境错"——见 design.md §5.3 v2 复审观察 (a)
|
|
372
|
+
process.exit(1)
|
|
373
|
+
}
|
|
358
374
|
}
|
|
359
375
|
}
|
|
360
376
|
// 持久化 platformOpts
|
|
@@ -369,29 +385,6 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
369
385
|
// let:下方 worktree 副本漂移守卫命中时锚回 wt.mainSpecBase(task-05/D-03)
|
|
370
386
|
let specBase = platformOpts.specRoot || join(cwd, '.sillyspec')
|
|
371
387
|
|
|
372
|
-
// ── 本地 agent 会话日志登记 + 上报(平台会话展示用,best-effort)──
|
|
373
|
-
// 平台/daemon 模式下 SillyHub 只能看到 CLI 阶段信息,看不到本地 agent 的实际执行日志。
|
|
374
|
-
// 在此探测当前 agent 环境(Claude Code / Codex / ZCode transcript / SILLYSPEC_AGENT_LOG
|
|
375
|
-
// 覆盖),把日志本地路径登记进 <runtimeRoot>/agent-session-log.json(留底)并立即
|
|
376
|
-
// REST 上报平台(POST /api/agent-logs,与进度上报同风格;协议见
|
|
377
|
-
// docs/platform-agent-log-protocol.md)。探测不到不发不写;任何失败只 warn 一行,
|
|
378
|
-
// 绝不阻断 run 主流程。
|
|
379
|
-
try {
|
|
380
|
-
const { recordAgentLogInvocation } = await import('../agent-session-log.js')
|
|
381
|
-
const r = await recordAgentLogInvocation({
|
|
382
|
-
cwd,
|
|
383
|
-
invokedCwd,
|
|
384
|
-
platformOpts,
|
|
385
|
-
specBase,
|
|
386
|
-
// 只记 flag 名不记值(--output 等 flag 值是 agent 工作文本,不进产物)
|
|
387
|
-
command: [stageName, ...flags.filter(t => typeof t === 'string' && t.startsWith('--'))].join(' '),
|
|
388
|
-
})
|
|
389
|
-
if (r && r.isNew && r.latestLogPath) {
|
|
390
|
-
const pushNote = r.pushed === true ? '已上报平台' : r.pushed === false ? '上报失败(本地已留底)' : '本地留底'
|
|
391
|
-
console.log(`📄 本地 agent 日志已登记(${pushNote}): ${r.latestLogPath}`)
|
|
392
|
-
}
|
|
393
|
-
} catch { /* best-effort:登记失败不影响 run 主流程 */ }
|
|
394
|
-
|
|
395
388
|
// 漂移提醒:cwd 祖先链 ≥2 个 .sillyspec = monorepo 多实例,当前命中的「最近」实例
|
|
396
389
|
// 可能不是用户意图的项目(如 cd 进被独立 scan 的子项目跑测试后忘回根)。
|
|
397
390
|
// 平台模式 / 显式 --spec-dir 跳过(已明确指定,无歧义)。仅提醒不阻断。
|
|
@@ -424,7 +417,11 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
424
417
|
// ⚠️ 同 init.js:必须保护真实资产(changes/、projects/、sillyspec.db)。
|
|
425
418
|
// 只在「首次」执行一次——用 cwd 下的 .sillyspec-platform-cleaned 标记文件记录已处理,
|
|
426
419
|
// 后续每次 run 直接跳过,避免重复检查 + 红叉噪声(此清理不阻塞流程、不动真实资产)。
|
|
427
|
-
|
|
420
|
+
// 自指守卫(FR-4,变更 2026-08-23-repo-native-spec-backfill):显式自指 --spec-root
|
|
421
|
+
// (repo-native junction 回环)下 cwd/.sillyspec 与 specRoot 同物理目录——它就是平台
|
|
422
|
+
// 规范目录本体,绝非"旧版本残留";跳过整个清理决策(含 marker 写入,防后续真平台
|
|
423
|
+
// 接入被误标记已清理)。否则 rmSync 会删掉 repo-native 唯一真理源并留下悬空链接。
|
|
424
|
+
if (platformOpts.specRoot && !isSelfReferentialSpecRoot(cwd, platformOpts.specRoot)) {
|
|
428
425
|
const legacyDir = join(cwd, '.sillyspec')
|
|
429
426
|
const cleanedMarker = join(cwd, '.sillyspec-platform-cleaned')
|
|
430
427
|
if (!existsSync(cleanedMarker)) {
|
|
@@ -492,6 +489,20 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
492
489
|
const inputValue = getFlagValue('--input')
|
|
493
490
|
if (inputValue !== null) inputText = inputValue
|
|
494
491
|
|
|
492
|
+
// quick 位置参数 → 任务描述(与 auto 模式建议的 `sillyspec run quick "需求"` 用法一致)。
|
|
493
|
+
// 旧行为静默忽略裸 token(QUICKLOG 标题回退占位);现显式消费——跳过值类 flag 的值
|
|
494
|
+
// (--files src/a.js 的 src/a.js 不是位置参数),取第一个真位置 token。配合下方
|
|
495
|
+
// 「新会话必须带描述」启动门(坑 quick-no-input-placeholder-title)。
|
|
496
|
+
if (stageName === 'quick' && inputText === null) {
|
|
497
|
+
for (let i = 0; i < flags.length; i++) {
|
|
498
|
+
const t = flags[i]
|
|
499
|
+
if (typeof t !== 'string') continue
|
|
500
|
+
if (t.startsWith('--')) { if (VALUE_FLAGS.has(t)) i++; continue }
|
|
501
|
+
inputText = t
|
|
502
|
+
break
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
495
506
|
// 解析 --linked-changes <a,b|none>(quick 专用:显式声明关联变更,CI/脚本友好)
|
|
496
507
|
// 与 --change 解耦:--linked-changes 语义清晰(关联变更),不与「指定变更名」混淆。
|
|
497
508
|
// null = 未指定(走持久化/交互/兼容回退);[] = 显式 none(不关联);[...] = 显式列表
|
|
@@ -546,6 +557,7 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
546
557
|
const QUICK_SID_RE = /^quick-[0-9a-f]{8}$/
|
|
547
558
|
let quickSessionId = null
|
|
548
559
|
let quickFallbackUsed = false // Q7: --done 未带 --change 时 fallback 读 current-quick-run-id 命中(区别于显式 --change quick-<hex>)
|
|
560
|
+
let quickSidFresh = false // 本轮刚生成全新 sessionId(非 --change 精确恢复 / 非 fallback)——供下方「新会话必须带 --input」门判定
|
|
549
561
|
if (stageName === 'quick') {
|
|
550
562
|
// 1373-1376 已把 quick 的 --change 值清进 linkedChanges、changeName 置 null。
|
|
551
563
|
// 此处回看 --change 原始值:若恰好是单个 quick-<8hex> → 识别为本会话 sessionId(精确恢复),
|
|
@@ -574,6 +586,7 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
574
586
|
}
|
|
575
587
|
if (!quickSessionId) {
|
|
576
588
|
quickSessionId = 'quick-' + randomUUID().slice(0, 8)
|
|
589
|
+
quickSidFresh = true
|
|
577
590
|
}
|
|
578
591
|
changeName = quickSessionId
|
|
579
592
|
} else {
|
|
@@ -582,6 +595,43 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
582
595
|
}
|
|
583
596
|
}
|
|
584
597
|
|
|
598
|
+
// ── 本地 agent 会话日志登记 + 上报(平台会话展示用,best-effort)──
|
|
599
|
+
// 平台/daemon 模式下 SillyHub 只能看到 CLI 阶段信息,看不到本地 agent 的实际执行日志。
|
|
600
|
+
// 在此探测当前 agent 环境(Claude Code / Codex / ZCode transcript / SILLYSPEC_AGENT_LOG
|
|
601
|
+
// 覆盖),把日志本地路径登记进 <runtimeRoot>/agent-session-log.json(留底)并立即
|
|
602
|
+
// REST 上报平台(POST /api/agent-logs,与进度上报同风格;协议见
|
|
603
|
+
// docs/platform-agent-log-protocol.md)。探测不到不发不写;任何失败只 warn 一行,
|
|
604
|
+
// 绝不阻断 run 主流程。
|
|
605
|
+
// 位置(2026-08-23-agent-activity-sessions task-01):必须在上方 changeName/quickSessionId
|
|
606
|
+
// 解析完成之后——上报携带会话化上下文 context:entry 级 changeKey/quickId(平台按
|
|
607
|
+
// (workspace, harness, entry.ctx) 聚合建会话;quick 会话 quickId 优先且与 changeKey 互斥)
|
|
608
|
+
// + body 级 hubSessionId(daemon 派发平台会话时注入 env SILLYHUB_SESSION_ID,非空才带)。
|
|
609
|
+
// 两段解析均在顶层作用域,此处统一算一次 context 两值皆可达。
|
|
610
|
+
try {
|
|
611
|
+
const isQuickSession = stageName === 'quick' && Boolean(quickSessionId)
|
|
612
|
+
const hubSessionIdEnv = typeof process.env.SILLYHUB_SESSION_ID === 'string' ? process.env.SILLYHUB_SESSION_ID.trim() : ''
|
|
613
|
+
const agentLogContext = {
|
|
614
|
+
hubSessionId: hubSessionIdEnv || null,
|
|
615
|
+
// quick 会话 → quickId(quick-<8hex> 完整原样,不剥前缀);普通场景 → changeKey(--change 值,无则 null)
|
|
616
|
+
changeKey: isQuickSession ? null : (changeName || null),
|
|
617
|
+
quickId: isQuickSession ? quickSessionId : null,
|
|
618
|
+
}
|
|
619
|
+
const { recordAgentLogInvocation } = await import('../agent-session-log.js')
|
|
620
|
+
const r = await recordAgentLogInvocation({
|
|
621
|
+
cwd,
|
|
622
|
+
invokedCwd,
|
|
623
|
+
platformOpts,
|
|
624
|
+
specBase,
|
|
625
|
+
context: agentLogContext,
|
|
626
|
+
// 只记 flag 名不记值(--output 等 flag 值是 agent 工作文本,不进产物)
|
|
627
|
+
command: [stageName, ...flags.filter(t => typeof t === 'string' && t.startsWith('--'))].join(' '),
|
|
628
|
+
})
|
|
629
|
+
if (r && r.isNew && r.latestLogPath) {
|
|
630
|
+
const pushNote = r.pushed === true ? '已上报平台' : r.pushed === false ? '上报失败(本地已留底)' : '本地留底'
|
|
631
|
+
console.log(`📄 本地 agent 日志已登记(${pushNote}): ${r.latestLogPath}`)
|
|
632
|
+
}
|
|
633
|
+
} catch { /* best-effort:登记失败不影响 run 主流程 */ }
|
|
634
|
+
|
|
585
635
|
// quick 关联变更存在性守卫(坑 quick-change-phantom-linked):quick 的 --change/--linked-changes
|
|
586
636
|
// 被解析为关联变更后静默接受不存在的名字(quick 不建变更,链接幻影名必是笔误/语义误用——想给
|
|
587
637
|
// 会话起名却传了 --change),后果是 QUICKLOG 挂悬空关联污染 change 关联图谱 + --done 时 sessionId
|
|
@@ -620,10 +670,23 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
620
670
|
// 解析 --file-notes "path::括注 || path::括注"(quick 专用:QUICKLOG「文件:」行落盘多行括注)。
|
|
621
671
|
// 旁路注入 quicklog.js(per-process setter),不经 complete 收尾路径透传(避碰多 agent 并发改的收尾热点)。
|
|
622
672
|
// completeQuicklogEntry 读后即清;不传 → '' → 回填审计到的实际文件单行(向后兼容)。
|
|
673
|
+
// 格式 fail-fast(坑 quick-file-notes-format-silent,2026-08-24):分隔符写错(`|`/`,` 等)时
|
|
674
|
+
// 整段会被静默挤进第一个文件的括注、QUICKLOG 落盘后只能手工修——解析处直接拦。
|
|
623
675
|
let quickFileNotes = ''
|
|
624
676
|
const fileNotesValue = getFlagValue('--file-notes')
|
|
625
677
|
if (fileNotesValue !== null) {
|
|
626
678
|
quickFileNotes = fileNotesValue
|
|
679
|
+
const { validateFileNotesFormat } = await import('../quicklog.js')
|
|
680
|
+
const fv = validateFileNotesFormat(quickFileNotes)
|
|
681
|
+
if (!fv.ok) {
|
|
682
|
+
console.error(`❌ --file-notes 格式不对(${fv.problems.length} 处),已拒绝执行(旧行为会静默挤错进 QUICKLOG,只能手工修):`)
|
|
683
|
+
for (const p of fv.problems.slice(0, 5)) {
|
|
684
|
+
console.error(` 「${p.seg.slice(0, 80)}」${p.reason}——${p.hint}`)
|
|
685
|
+
}
|
|
686
|
+
if (fv.problems.length > 5) console.error(` …等共 ${fv.problems.length} 处`)
|
|
687
|
+
console.error(' 正确格式: --file-notes "path1::括注1 || path2::括注2"(`||` 双竖线分隔多文件,`::` 分隔路径与括注)')
|
|
688
|
+
process.exit(2) // 用法错(--file-notes 格式非法)→ exit 2
|
|
689
|
+
}
|
|
627
690
|
}
|
|
628
691
|
setQuickFileNotes(quickFileNotes)
|
|
629
692
|
|
|
@@ -660,6 +723,7 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
660
723
|
'--json', '--dir', '--help',
|
|
661
724
|
'--reopen', '--from-step', '--mode',
|
|
662
725
|
'--deep', '--quick', '--standard', // scan profile 三档显式选择(scan-profile.js 从 argv 读;互斥见下方 PROFILE_FLAGS 检测)
|
|
726
|
+
'--adopt-branch', // execute 显式收编既有 sillyspec/<change> 分支为 worktree 工作分支(坑 worktree-user-branch-conflict)
|
|
663
727
|
'--diff', '--base', '--full', '--report', // scan diff(D-001:command.js 只补 flag,裸 token 解析归 index.js 子命令拦截)
|
|
664
728
|
'-h',
|
|
665
729
|
])
|
|
@@ -693,6 +757,22 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
693
757
|
process.exit(0)
|
|
694
758
|
}
|
|
695
759
|
|
|
760
|
+
// 坑 quick-no-input-placeholder-title(2026-08-24 用户反馈二期①):全新 quick 会话(上方
|
|
761
|
+
// 刚生成新 sessionId)不带 --input 且无 --linked-changes 可取标题 → 拒绝启动(exit 2)。
|
|
762
|
+
// 旧行为只 warn 提示「建议放弃重启」,占位标题「(quick 任务)」已落盘、只能 reset 重来——
|
|
763
|
+
// 语义标题要拖到最终 --done 才回填,平台「快速修复」列表全程隐藏。此刻零沉没成本(progress
|
|
764
|
+
// 行/QUICKLOG/guard 均未创建),直接拒掉最便宜。放在 --help 短路之后(help 查询不该被拦)、
|
|
765
|
+
// 任何会话副作用之前。精确恢复(--change quick-<hex>)与 done-like(--done/--reset/--cancel/
|
|
766
|
+
// --status/--skip/--reopen)不受限;--linked-changes 启动可从关联变更 proposal/design 提取标题。
|
|
767
|
+
if (stageName === 'quick' && quickSidFresh
|
|
768
|
+
&& !(isDone || isStatus || isSkip || isReset || isReopen || isCancel)
|
|
769
|
+
&& !inputText && !(Array.isArray(linkedChanges) && linkedChanges.length > 0)) {
|
|
770
|
+
console.error('❌ 新 quick 会话必须带 --input "<一句话任务描述>"(或 --linked-changes <a,b> 从关联变更取标题)。')
|
|
771
|
+
console.error(' 不带描述启动会落「(quick 任务)」占位标题:平台「快速修复」列表隐藏占位条目、语义标题要拖到最终 --done 才回填,长任务全程不可见。')
|
|
772
|
+
console.error(' 用法: sillyspec run quick --input "<一句话任务描述>" [--linked-changes <a,b>] [--files <...>]')
|
|
773
|
+
process.exit(2) // 用法错(新会话无任务描述)→ exit 2
|
|
774
|
+
}
|
|
775
|
+
|
|
696
776
|
const isAuxiliary = auxiliaryStages.includes(stageName)
|
|
697
777
|
// scan 元数据追踪(存储在 stageData.scanMeta 中,completeStep 通过 progress 访问)
|
|
698
778
|
|
|
@@ -1162,7 +1242,7 @@ export async function runCommand(args, cwd, specDir = null, opts = {}) {
|
|
|
1162
1242
|
}
|
|
1163
1243
|
|
|
1164
1244
|
// 默认:输出当前步骤
|
|
1165
|
-
return await runStage(pm, progress, stageName, cwd, effectiveChange, isSkipApproval, platformOpts, { quickFiles, isAllowNew, isAllowDelete, isForceBaseline, isForceRescan, linkedChanges, taskDescription: inputText })
|
|
1245
|
+
return await runStage(pm, progress, stageName, cwd, effectiveChange, isSkipApproval, platformOpts, { quickFiles, isAllowNew, isAllowDelete, isForceBaseline, isForceRescan, linkedChanges, taskDescription: inputText, adoptBranch: stageName === 'execute' && flags.includes('--adopt-branch') })
|
|
1166
1246
|
}
|
|
1167
1247
|
|
|
1168
1248
|
/**
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
import { basename, join, resolve, relative, isAbsolute } from 'node:path'
|
|
26
26
|
import { existsSync, readdirSync, readFileSync, writeFileSync, mkdirSync, unlinkSync, rmSync } from 'node:fs'
|
|
27
27
|
import { renameSyncRetry, writeAtomicSync } from '../fs-atomic.js'
|
|
28
|
-
import { resolveChangeDir, resolveQuickSessionsDir, safeGit, auditQuickCompletion, triggerSync, isQuickMetadata, resolveRuntimeRoot } from './shared.js'
|
|
28
|
+
import { resolveChangeDir, resolveQuickSessionsDir, safeGit, auditQuickCompletion, triggerSync, isQuickMetadata, resolveRuntimeRoot, collectOtherQuickSessionDeclarations } from './shared.js'
|
|
29
29
|
import { detectConcurrentChanges, formatConcurrentWarning, resolveConcurrentAnchor } from './concurrent-detect.js'
|
|
30
30
|
import { stageRegistry } from '../stages/index.js'
|
|
31
31
|
import { SCAN_STATUS, POINTER_STATUS } from '../constants.js'
|
|
@@ -431,7 +431,11 @@ export async function handleArchiveConfirmStep({ stageName, steps, currentIdx, c
|
|
|
431
431
|
console.log('⚠️ 请添加 --confirm 确认归档,例如:sillyspec run archive --done --confirm --output "确认归档"')
|
|
432
432
|
return { stageCompleted: false, currentIdx, nextPendingIdx: currentIdx }
|
|
433
433
|
}
|
|
434
|
-
|
|
434
|
+
// 主仓互斥锁(坑 main-repo-no-mutex 二批):archiveChangeDirectory 改主仓共享状态(目录
|
|
435
|
+
// rename + 共享 index 的 git add + marker 删除 + worktree 清理),与并行会话的 apply/cleanup
|
|
436
|
+
// 互踩。exit 钩子兜底:其内部 guard 失败 exit(1) 时锁也会被清(见 withMainRepoLock)。
|
|
437
|
+
const { withMainRepoLock } = await import('../worktree-apply.js')
|
|
438
|
+
const archivedDir = await withMainRepoLock(cwd, changeName, 'archive-finalize', () => archiveChangeDirectory(pm, cwd, progress, specBase, platformOpts))
|
|
435
439
|
if (archivedDir && existsSync(archivedDir)) {
|
|
436
440
|
// 内存快照同步(坑 archive-progress-show-stale,2026-08-21 实证):archiveChangeDirectory 内
|
|
437
441
|
// unregisterChange 已在 DB 写 current_stage='archive'(终态一致化),但本进程 progress 是命令
|
|
@@ -863,6 +867,11 @@ export async function handleQuickStageCompletion({ stageName, steps, currentIdx,
|
|
|
863
867
|
// (平台模式 resolveSpecDir(cwd) 会 miss specRoot 静默丢信号,plan 审查 gap-5)
|
|
864
868
|
specBase,
|
|
865
869
|
projectName: progress?.project || null,
|
|
870
|
+
// 他者 active 会话声明索引(坑 foreign-session-declared-false-block):多 agent 并发时
|
|
871
|
+
// 并行会话 --files 声明的文件退栈归该会话审计,不再误拦本会话。与上方 guard 读取同源
|
|
872
|
+
// (resolveQuickSessionsDir 同参,平台模式 runtimeRoot 对齐);fail-open:采集失败 → 空
|
|
873
|
+
// → 回到无豁免现状。
|
|
874
|
+
otherSessionsDeclared: collectOtherQuickSessionDeclarations(platformOpts, specBase, changeName),
|
|
866
875
|
}
|
|
867
876
|
review = await auditQuickCompletion(cwd, mergedGuard, { isConfirm: confirm })
|
|
868
877
|
printQuickAuditReview(review)
|
|
@@ -913,8 +922,9 @@ export async function handleQuickStageCompletion({ stageName, steps, currentIdx,
|
|
|
913
922
|
const isLastStep = currentIdx === steps.length - 1
|
|
914
923
|
if (isLastStep && !outputText) {
|
|
915
924
|
console.error('\n❌ quick 最后一步 --done 必须带 --output(四字段结果模板)。')
|
|
916
|
-
console.error(' --output 是 QUICKLOG「结果:」归档的唯一来源。补全后重跑 --done
|
|
917
|
-
console.error(' sillyspec run quick --done --change <changeName> --
|
|
925
|
+
console.error(' --output 是 QUICKLOG「结果:」归档的唯一来源。补全后重跑 --done(不丢进度),推荐四参数形式(CLI 自动合成,无嵌套冒号事故面):')
|
|
926
|
+
console.error(' sillyspec run quick --done --change <changeName> --req "一句话语义化短标题" --cause "为什么这样改" --solution "怎么改的" --result "验证情况(测试数 / lint / typecheck / 部署状态)"')
|
|
927
|
+
console.error(' 兼容旧形式:--output "需求:… 根因:… 方案:… 结果:…"')
|
|
918
928
|
steps[currentIdx].status = 'pending'
|
|
919
929
|
steps[currentIdx].completedAt = null
|
|
920
930
|
process.exit(1)
|
|
@@ -924,7 +934,9 @@ export async function handleQuickStageCompletion({ stageName, steps, currentIdx,
|
|
|
924
934
|
if (!resultCheck.ok) {
|
|
925
935
|
console.error('\n' + getRule('quick.result-labels').failMessage.replaceAll('${missing}', resultCheck.missing.join('、')))
|
|
926
936
|
console.error(` --output 是 QUICKLOG「结果:」归档的唯一来源,四个标签必须放在 --output 里(不是 --input)。`)
|
|
927
|
-
console.error(` 补全后重跑 --done
|
|
937
|
+
console.error(` 补全后重跑 --done(不丢进度)。推荐四参数形式(CLI 自动合成结构化模板,避免旧形式嵌套全角冒号被拆分判定缺字段):`)
|
|
938
|
+
console.error(` sillyspec run quick --done --change <changeName> --req "一句话语义化短标题(即 QUICKLOG 条目标题)" --cause "为什么这样改(纯新增/样式则写「无,纯新增/纯样式」)" --solution "怎么改的" --result "验证情况(测试数 / lint / typecheck / 部署状态)"`)
|
|
939
|
+
console.error(` 或照抄旧形式模板:`)
|
|
928
940
|
console.error(` sillyspec run quick --done --change <changeName> --output "需求:用户/任务要什么`)
|
|
929
941
|
console.error(` 根因:为什么这样改(纯新增/样式则写「无,纯新增/纯样式」)`)
|
|
930
942
|
console.error(` 方案:怎么改的`)
|
|
@@ -1331,22 +1343,39 @@ export async function handleExecuteWorktreeCleanup({ stageName, changeName, cwd
|
|
|
1331
1343
|
} else if (meta.mode === 'native-worktree') {
|
|
1332
1344
|
console.log('🔗 Worktree: kept (外部隔离环境)');
|
|
1333
1345
|
} else {
|
|
1334
|
-
// in-place 模式不再短路:cleanup 现在能安全处理 in-place(只清 meta
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
const cleanResult =
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1346
|
+
// in-place 模式不再短路:cleanup 现在能安全处理 in-place(只清 meta,不碰主工作区)。
|
|
1347
|
+
// 主仓互斥锁(坑 main-repo-no-mutex 二批):检查+清理与并行会话的 apply/cleanup 互斥
|
|
1348
|
+
// (防 TOCTOU:检查时他者正在 apply → 判定漂移)。best-effort:锁超时不阻断 execute
|
|
1349
|
+
// 完成,降级为保留 worktree + 手动清理指引。
|
|
1350
|
+
try {
|
|
1351
|
+
const { withMainRepoLock } = await import('../worktree-apply.js')
|
|
1352
|
+
const cleanResult = await withMainRepoLock(cwd, changeName, 'execute-cleanup', () => {
|
|
1353
|
+
const check = wm.hasUnappliedChanges(changeName);
|
|
1354
|
+
if (check.hasChanges) {
|
|
1355
|
+
return { kept: true, check }
|
|
1356
|
+
}
|
|
1357
|
+
return { kept: false, result: wm.cleanup(changeName) }
|
|
1358
|
+
})
|
|
1359
|
+
if (cleanResult.kept) {
|
|
1360
|
+
console.log(`🔗 Worktree: pending apply (${cleanResult.check.changedFiles.length} 个未应用变更)`);
|
|
1361
|
+
console.log(` 下一步: sillyspec worktree apply ${changeName}`);
|
|
1362
|
+
} else {
|
|
1363
|
+
console.log(`🔗 Worktree: ${cleanResult.result.result}`);
|
|
1364
|
+
if (cleanResult.result.residual?.length > 0) {
|
|
1365
|
+
console.warn(` ⚠️ 清理残留: ${cleanResult.result.residual.join('; ')}`);
|
|
1366
|
+
console.warn(` 手动处理: sillyspec worktree cleanup ${changeName} --force`);
|
|
1367
|
+
} else if (cleanResult.result.details?.length > 0) {
|
|
1368
|
+
for (const d of cleanResult.result.details) {
|
|
1369
|
+
if (d.startsWith('⚠️')) console.log(` ${d}`);
|
|
1370
|
+
}
|
|
1348
1371
|
}
|
|
1349
1372
|
}
|
|
1373
|
+
} catch (lockErr) {
|
|
1374
|
+
if (/互斥锁被占用/.test(String(lockErr.message))) {
|
|
1375
|
+
console.log(`🔗 Worktree 自动清理跳过(主仓互斥锁被他者会话持有)——稍后手动: sillyspec worktree cleanup ${changeName}`);
|
|
1376
|
+
} else {
|
|
1377
|
+
console.warn(`⚠️ worktree 清理异常(不阻断): ${lockErr.message}`);
|
|
1378
|
+
}
|
|
1350
1379
|
}
|
|
1351
1380
|
}
|
|
1352
1381
|
} catch (e) {
|
package/src/run/complete.js
CHANGED
|
@@ -996,8 +996,11 @@ export async function waitStep(pm, progress, stageName, cwd, outputText, waitRea
|
|
|
996
996
|
// requiresWait 语义前置(坑 archive-step3-wait-answer-hint-late):--continue --answer 只是中继回答,
|
|
997
997
|
// 本步会回到待执行(回答后还需执行动作再 --done 收尾);不想两段式可用 --done --answer 一步完成。
|
|
998
998
|
// 提示落在标记 --wait 的此刻,而非等 agent 撞 --done 报错才知道。
|
|
999
|
-
|
|
1000
|
-
|
|
999
|
+
// conditionalWait(坑 archive-subconfirm-redundant 后 archive step3 降级软门)+ repeatableWait 的
|
|
1000
|
+
// --wait 同样回 pending(continueStep shouldReturnToCurrentStep),提示同样适用。
|
|
1001
|
+
if (stepDef.requiresWait === true || currentStep.requiresWait === true
|
|
1002
|
+
|| stepDef.conditionalWait === true || currentStep.conditionalWait === true) {
|
|
1003
|
+
console.log(` 注:本步为需回执的等待步骤(requiresWait/conditionalWait)——--continue --answer 后本步回到待执行,完成动作后需再 --done 收尾`)
|
|
1001
1004
|
console.log(` 或一步完成:sillyspec run ${stageName} --done --answer "你的选择"${changeName ? ` --change ${changeName}` : ''} --output "你的摘要"`)
|
|
1002
1005
|
}
|
|
1003
1006
|
}
|
package/src/run/gates.js
CHANGED
|
@@ -463,6 +463,33 @@ function rollbackCompletionAndReturn(pm, progress, stageData, steps, currentIdx,
|
|
|
463
463
|
*/
|
|
464
464
|
export async function runStageCompletionGates({ stageName, cwd, changeName, platformOpts, specBase, progress, pm, stageData, steps, currentIdx, ctx = null }) {
|
|
465
465
|
const projectName = progress.project || basename(cwd)
|
|
466
|
+
// decisions.md header 自动补齐(坑 decisions-header-late-warning,2026-08-24 用户反馈二期):
|
|
467
|
+
// brainstorm step8 旧模板自带无 frontmatter 的 decisions 样例,存量变更照抄必缺 author/created_at,
|
|
468
|
+
// 拖到平台同步/后续环节才提示。gate 前幂等补机械字段(先例:autoCheckPlanFromReviews 同层写
|
|
469
|
+
// tasks.md),validator 读到的即已补齐版——补的是 CLI 可自证的机械字段,不替 agent 产出语义内容。
|
|
470
|
+
if (['brainstorm', 'plan', 'verify'].includes(stageName) && changeName) {
|
|
471
|
+
try {
|
|
472
|
+
const { ensureDecisionDocHeader } = await import('../stage-contract.js')
|
|
473
|
+
ensureDecisionDocHeader(resolveChangeDir(cwd, changeName, platformOpts?.specRoot))
|
|
474
|
+
} catch { /* 补齐失败不阻断 gate */ }
|
|
475
|
+
}
|
|
476
|
+
// TaskCard 骨架幂等预生成(坑 taskcard-parallel-cli-lock,2026-08-25 用户实证:并行 batch
|
|
477
|
+
// 子代理各自起 sillyspec taskcard CLI 撞进度库 SQLite 锁,改主代理预生成+子代理只 Edit 才稳)。
|
|
478
|
+
// gate 前主流程单进程补齐缺卡骨架(已存在跳过),与 ensureDecisionDocHeader 同层同范式——
|
|
479
|
+
// 补的是 CLI 可自证的机械骨架,占位符硬拦(plan-postcheck)仍逼子代理 Edit 填语义。
|
|
480
|
+
if (stageName === 'plan' && changeName) {
|
|
481
|
+
try {
|
|
482
|
+
const { ensureTaskcardSkeletons } = await import('../taskcard.js')
|
|
483
|
+
const r = ensureTaskcardSkeletons(changeName, { cwd, specDir: platformOpts?.specRoot })
|
|
484
|
+
if (r.created.length > 0) {
|
|
485
|
+
console.log(`📌 已预生成 ${r.created.length} 张 TaskCard 骨架(主流程单进程生成,子代理只 Edit 填充,勿并行跑 taskcard CLI):`)
|
|
486
|
+
for (const f of r.created.slice(0, 8)) console.log(` + ${f}`)
|
|
487
|
+
if (r.created.length > 8) console.log(` … 共 ${r.created.length} 张`)
|
|
488
|
+
}
|
|
489
|
+
} catch (e) {
|
|
490
|
+
console.warn(`⚠️ TaskCard 骨架预生成失败(不阻断 gate,仍可逐卡手动 sillyspec taskcard 生成): ${e.message}`)
|
|
491
|
+
}
|
|
492
|
+
}
|
|
466
493
|
const contractResult = runValidators(stageName, cwd, changeName, { projectName, specRoot: platformOpts?.specRoot })
|
|
467
494
|
if (contractResult.errors.length > 0) {
|
|
468
495
|
console.error(`\n❌ 阶段 ${stageName} 校验失败:`)
|
|
@@ -498,6 +525,37 @@ export async function runStageCompletionGates({ stageName, cwd, changeName, plat
|
|
|
498
525
|
printVerifyTestCheck(testCheck)
|
|
499
526
|
if (testCheck.status === 'failed') {
|
|
500
527
|
console.error('\n❌ verify 阶段被阻断:verify-result.md 自报告通过,但 CLI 实测测试失败。')
|
|
528
|
+
// 并行 WIP 归因鉴别(坑 verify-reconcile-foreign-wip):实测跑在主仓共享工作区,并行会话
|
|
529
|
+
// 在途 WIP 物理在场——他者文件命中声明集时提示复验归因(EADDRINUSE 鉴别同款风格),不静默背锅。
|
|
530
|
+
try {
|
|
531
|
+
const { collectForeignDeclaredFiles } = await import('../verify-postcheck.js')
|
|
532
|
+
const { gitQuiet } = await import('../git-helper.js')
|
|
533
|
+
const foreignMap = collectForeignDeclaredFiles(cwd, changeName)
|
|
534
|
+
if (foreignMap.size > 0) {
|
|
535
|
+
const dirty = (gitQuiet(cwd, ['diff', '--name-only', 'HEAD']) || '')
|
|
536
|
+
.split('\n').filter(Boolean).map(f => f.replace(/\\/g, '/'))
|
|
537
|
+
const hitForeign = dirty.filter(f => foreignMap.has(f))
|
|
538
|
+
if (hitForeign.length > 0) {
|
|
539
|
+
console.error(` ℹ️ 归因提示:主仓检出 ${hitForeign.length} 个并行会话声明的在途文件(${hitForeign.slice(0, 5).join(', ')}${hitForeign.length > 5 ? ' 等' : ''})——实测失败可能混入他者 WIP 而非本变更问题。待其提交/收尾后复验,仍失败才是本变更的。`)
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
// 第二判据(坑 derived-artifact-stale-baseline):本变更 apply 的文件(apply-pathspec 落盘)
|
|
543
|
+
// 与主仓近期提交重叠——本变更旧基线的生成产物可能覆盖了已合入内容,先在新基线重跑生成命令再复验
|
|
544
|
+
try {
|
|
545
|
+
const pathspecFile = join(resolveRuntimeRoot(platformOpts, specBase), `apply-pathspec-${changeName}.txt`)
|
|
546
|
+
if (changeName && existsSync(pathspecFile)) {
|
|
547
|
+
const ownFiles = new Set(readFileSync(pathspecFile, 'utf8').split('\n').map(l => l.trim()).filter(Boolean).map(f => f.replace(/\\/g, '/')))
|
|
548
|
+
if (ownFiles.size > 0) {
|
|
549
|
+
const recent = (gitQuiet(cwd, ['log', '-n', '10', '--name-only', '--pretty=format:']) || '')
|
|
550
|
+
.split('\n').map(l => l.trim().replace(/\\/g, '/')).filter(Boolean)
|
|
551
|
+
const overlap = [...new Set(recent)].filter(f => ownFiles.has(f))
|
|
552
|
+
if (overlap.length > 0) {
|
|
553
|
+
console.error(` ℹ️ 归因提示②:本变更有 ${overlap.length} 个文件与主仓最近 10 条提交重叠(${overlap.slice(0, 5).join(', ')}${overlap.length > 5 ? ' 等' : ''})——若为生成产物(api-types 等),本变更可能在旧基线生成并覆盖了已合入内容;先在新基线重跑生成命令(如 gen:types)再复验。`)
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
} catch { /* 判据②失败不影响主流程 */ }
|
|
558
|
+
} catch { /* 归因提示失败不影响阻断语义 */ }
|
|
501
559
|
console.error(' 请修复失败的测试并更新 verify-result.md 后重新完成此步骤。')
|
|
502
560
|
return await rollbackCompletionAndReturn(pm, progress, stageData, steps, currentIdx, cwd, changeName, platformOpts)
|
|
503
561
|
}
|
|
@@ -543,29 +601,10 @@ export async function runStageCompletionGates({ stageName, cwd, changeName, plat
|
|
|
543
601
|
}
|
|
544
602
|
}
|
|
545
603
|
}
|
|
546
|
-
// ── verify 服务进程回收(坑 verify-service-process-leak
|
|
547
|
-
//
|
|
548
|
-
// 此处收尾逐个 kill + 清文件。best-effort:ESRCH(已退出)静默,kill 失败 warn 不阻断 verify。
|
|
604
|
+
// ── verify 服务进程回收(坑 verify-service-process-leak;坑 verify-pids-cross-session-kill
|
|
605
|
+
// 见 reapVerifyServices 注释)──
|
|
549
606
|
try {
|
|
550
|
-
|
|
551
|
-
if (existsSync(servicesPath)) {
|
|
552
|
-
const pids = readFileSync(servicesPath, 'utf8').split('\n').map(l => l.trim()).filter(l => /^\d+$/.test(l))
|
|
553
|
-
const reaped = []; const failed = []
|
|
554
|
-
for (const pid of pids) {
|
|
555
|
-
try { process.kill(parseInt(pid, 10), 'SIGTERM'); reaped.push(pid) }
|
|
556
|
-
catch (e) { if (e.code !== 'ESRCH') failed.push(`${pid}(${e.code || e.message})`) }
|
|
557
|
-
}
|
|
558
|
-
try { unlinkSync(servicesPath) } catch {}
|
|
559
|
-
if (reaped.length > 0) console.log(`🧹 verify 服务进程已回收 ${reaped.length} 个(PID: ${reaped.join(', ')})`)
|
|
560
|
-
// CLI 回执(坑 verify-literal-evidence-mismatch):回收即真实启动的结构化证据——
|
|
561
|
-
// checkIntegrationEvidence(stage-contract)读回执注入匹配,agent 措辞差异不再误拦
|
|
562
|
-
try {
|
|
563
|
-
writeFileSync(join(dirname(servicesPath), 'verify-services.receipt.json'), JSON.stringify({
|
|
564
|
-
change: changeName || null, reapedPidCount: reaped.length, reapedAt: new Date().toISOString(),
|
|
565
|
-
}, null, 2) + '\n')
|
|
566
|
-
} catch {}
|
|
567
|
-
if (failed.length > 0) console.warn(`⚠️ 服务进程回收失败 ${failed.length} 个:${failed.join(', ')} — 手动处理:taskkill /PID <pid> /F(Windows)/ kill -9 <pid>`)
|
|
568
|
-
}
|
|
607
|
+
reapVerifyServices(platformOpts, specBase, changeName)
|
|
569
608
|
} catch (e) { console.warn(`⚠️ verify 服务进程回收异常(不阻断): ${e.message}`) }
|
|
570
609
|
|
|
571
610
|
console.log('\n✅ 验证通过,下一步:sillyspec run archive')
|
|
@@ -1027,3 +1066,46 @@ export async function completeStageGates({ stageName, cwd, changeName, platformO
|
|
|
1027
1066
|
return null
|
|
1028
1067
|
}
|
|
1029
1068
|
|
|
1069
|
+
|
|
1070
|
+
/**
|
|
1071
|
+
* verify 服务进程回收(verify --done 收尾调用)。
|
|
1072
|
+
*
|
|
1073
|
+
* 坑 verify-service-process-leak(2026-08-21):真实启动验证起的长驻服务(uvicorn 等)漏挂
|
|
1074
|
+
* 一天多——verify prompt 要求 PID 按变更分片登记 .runtime/verify-services-<change>.pids。
|
|
1075
|
+
* 坑 verify-pids-cross-session-kill(2026-08-23):原单文件无归属,A 会话 --done 会把 B 正在
|
|
1076
|
+
* 收集 Runtime Evidence 的服务一并杀掉——分片后各回收各的;旧单文件兼容回收(升级过渡期)。
|
|
1077
|
+
* 回执同样按变更分片(原单份被并行会话后写覆盖),checkIntegrationEvidence(stage-contract)
|
|
1078
|
+
* 读分片名注入证据匹配。best-effort:ESRCH(已退出)静默,kill 失败 warn 不阻断 verify。
|
|
1079
|
+
*
|
|
1080
|
+
* @returns {{ reaped: number, receiptPath: string|null }}
|
|
1081
|
+
*/
|
|
1082
|
+
export function reapVerifyServices(platformOpts, specBase, changeName) {
|
|
1083
|
+
const runtimeDir = resolveRuntimeRoot(platformOpts, specBase)
|
|
1084
|
+
const reapFile = (path, label) => {
|
|
1085
|
+
if (!existsSync(path)) return null
|
|
1086
|
+
const pids = readFileSync(path, 'utf8').split('\n').map(l => l.trim()).filter(l => /^\d+$/.test(l))
|
|
1087
|
+
const reaped = []; const failed = []
|
|
1088
|
+
for (const pid of pids) {
|
|
1089
|
+
try { process.kill(parseInt(pid, 10), 'SIGTERM'); reaped.push(pid) }
|
|
1090
|
+
catch (e) { if (e.code !== 'ESRCH') failed.push(`${pid}(${e.code || e.message})`) }
|
|
1091
|
+
}
|
|
1092
|
+
try { unlinkSync(path) } catch {}
|
|
1093
|
+
if (reaped.length > 0) console.log(`🧹 verify 服务进程已回收 ${reaped.length} 个${label}(PID: ${reaped.join(', ')})`)
|
|
1094
|
+
return { reaped: reaped.length, failed }
|
|
1095
|
+
}
|
|
1096
|
+
const own = reapFile(join(runtimeDir, `verify-services-${changeName}.pids`), '')
|
|
1097
|
+
const legacy = reapFile(join(runtimeDir, 'verify-services.pids'), '(旧格式单文件,兼容回收)')
|
|
1098
|
+
const reapedTotal = (own?.reaped || 0) + (legacy?.reaped || 0)
|
|
1099
|
+
const failedAll = [...(own?.failed || []), ...(legacy?.failed || [])]
|
|
1100
|
+
let receiptPath = null
|
|
1101
|
+
if (reapedTotal > 0) {
|
|
1102
|
+
try {
|
|
1103
|
+
receiptPath = join(runtimeDir, `verify-services-${changeName}.receipt.json`)
|
|
1104
|
+
writeFileSync(receiptPath, JSON.stringify({
|
|
1105
|
+
change: changeName || null, reapedPidCount: reapedTotal, reapedAt: new Date().toISOString(),
|
|
1106
|
+
}, null, 2) + '\n')
|
|
1107
|
+
} catch { receiptPath = null }
|
|
1108
|
+
}
|
|
1109
|
+
if (failedAll.length > 0) console.warn(`⚠️ 服务进程回收失败 ${failedAll.length} 个:${failedAll.join(', ')} — 手动处理:taskkill /PID <pid> /F(Windows)/ kill -9 <pid>`)
|
|
1110
|
+
return { reaped: reapedTotal, receiptPath }
|
|
1111
|
+
}
|