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/knowledge-match.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* knowledge-match.js — knowledge 关键词匹配引擎
|
|
3
|
-
* 从 INDEX.md 解析知识条目,按任务上下文匹配并生成 hit report
|
|
3
|
+
* 从 INDEX.md 解析知识条目,按任务上下文匹配并生成 hit report;
|
|
4
|
+
* 扫描范围含 decisions 决策库(knowledge/decisions/<域>.md,经 INDEX.md ## Decisions 段
|
|
5
|
+
* 路由行发现——路由行由 decision-distill 幂等写入,本引擎只消费不写)——命中路由行的
|
|
6
|
+
* 决策文件解析为 decisionHits(rejected 优先),供 brainstorm Step2 防复潮注入(task-04,FR-05)。
|
|
7
|
+
* decisions 库不存在时(INDEX 无 Decisions 段/文件不存在)一切行为与无 decisions 库时一致。
|
|
4
8
|
*/
|
|
5
9
|
|
|
6
10
|
import { existsSync, readFileSync } from 'fs'
|
|
@@ -41,6 +45,86 @@ export function parseKnowledgeIndex(indexDir) {
|
|
|
41
45
|
return entries
|
|
42
46
|
}
|
|
43
47
|
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
// decisions 决策库扫描(task-04,FR-05):经 INDEX.md ## Decisions 段路由行发现
|
|
50
|
+
// knowledge/decisions/<域>.md 并解析 D-xxx@vN 条目。条目格式与 decision-distill 的
|
|
51
|
+
// renderBlockLines 逐字对齐(字段行是机械解析契约):`## D-xxx@vN <短标题>` +
|
|
52
|
+
// `状态:implemented|rejected` / `锚点:` / `最近确认:` / `理由:`(rejected 追加
|
|
53
|
+
// `否决理由:` / `复潮条件:`)。
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
/** INDEX 条目是否为 decisions 库路由行(目标文件在 decisions/ 下) */
|
|
57
|
+
function isDecisionRoute(entry) {
|
|
58
|
+
return /^decisions\//.test(String(entry.file || '').replace(/\\/g, '/'))
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const DECISION_HEADER_RE = /^##\s+(D-\d+@v\d+)\s*(.*)$/
|
|
62
|
+
const DECISION_FIELD_RE = /^(状态|理由|否决理由|复潮条件)\s*[::]\s*(.*)$/
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 解析单个 decisions/<域>.md 的 D-xxx@vN 条目。
|
|
66
|
+
* reason 语义:rejected 条目取「否决理由」(expects_from task-02 的 reject_reason),
|
|
67
|
+
* 其余条目回退「理由」一句话;revisitWhen 仅 rejected 条目非空(复潮条件)。
|
|
68
|
+
* @param {string} filePath 决策文件绝对路径
|
|
69
|
+
* @param {string} file INDEX 相对路径(decisions/<域>.md),原样进 decisionHits.file
|
|
70
|
+
* @returns {{ file: string, id: string, title: string, status: string, reason: string, revisitWhen: string }[]}
|
|
71
|
+
*/
|
|
72
|
+
function parseDecisionFile(filePath, file) {
|
|
73
|
+
let content
|
|
74
|
+
try { content = readFileSync(filePath, 'utf8') } catch { return [] }
|
|
75
|
+
const hits = []
|
|
76
|
+
let cur = null
|
|
77
|
+
const flush = () => {
|
|
78
|
+
if (cur) hits.push(cur)
|
|
79
|
+
cur = null
|
|
80
|
+
}
|
|
81
|
+
for (const line of content.replace(/\r\n/g, '\n').split('\n')) {
|
|
82
|
+
const h = line.match(DECISION_HEADER_RE)
|
|
83
|
+
if (h) {
|
|
84
|
+
flush()
|
|
85
|
+
cur = { file, id: h[1], title: h[2].trim(), status: '', reason: '', revisitWhen: '' }
|
|
86
|
+
continue
|
|
87
|
+
}
|
|
88
|
+
if (!cur) continue
|
|
89
|
+
const f = line.match(DECISION_FIELD_RE)
|
|
90
|
+
if (!f) continue
|
|
91
|
+
const value = f[2].trim()
|
|
92
|
+
if (f[1] === '状态') cur.status = value.toLowerCase()
|
|
93
|
+
else if (f[1] === '否决理由') cur.reason = value
|
|
94
|
+
else if (f[1] === '复潮条件') cur.revisitWhen = value
|
|
95
|
+
else if (!cur.reason) cur.reason = value // 理由:仅作 implemented(或否决理由缺失)时的回填
|
|
96
|
+
}
|
|
97
|
+
flush()
|
|
98
|
+
return hits
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* 解析 knowledge/decisions/ 决策库——扫描范围扩到 decisions/*.md,但只经 INDEX.md
|
|
103
|
+
* Decisions 段路由行发现目标文件(路由行由 decision-distill 幂等维护)。
|
|
104
|
+
* @param {string} indexDir knowledge 目录路径
|
|
105
|
+
* @param {Array} [indexEntries] parseKnowledgeIndex 输出(缺省时自行解析 INDEX;传入时
|
|
106
|
+
* 只解析这些条目中指向 decisions/ 的路由行,matchKnowledge 用它做「路由行已命中」过滤)
|
|
107
|
+
* @returns {{ file: string, id: string, title: string, status: string, reason: string, revisitWhen: string }[]}
|
|
108
|
+
* 路由行不存在/目标文件不存在/解析失败 → [](与无 decisions 库时行为完全一致)
|
|
109
|
+
*/
|
|
110
|
+
export function parseDecisionEntries(indexDir, indexEntries = null) {
|
|
111
|
+
const routes = (indexEntries || parseKnowledgeIndex(indexDir)).filter(isDecisionRoute)
|
|
112
|
+
const hits = []
|
|
113
|
+
for (const route of routes) {
|
|
114
|
+
const filePath = join(indexDir, route.file)
|
|
115
|
+
if (!existsSync(filePath)) continue // 路由行失效(域文件已删)→ 跳过不阻断
|
|
116
|
+
hits.push(...parseDecisionFile(filePath, route.file))
|
|
117
|
+
}
|
|
118
|
+
// 多条路由行指向同一域文件时按 file+id 去重
|
|
119
|
+
const seen = new Set()
|
|
120
|
+
return hits.filter(h => {
|
|
121
|
+
const key = `${h.file}#${h.id}`
|
|
122
|
+
if (seen.has(key)) return false
|
|
123
|
+
seen.add(key)
|
|
124
|
+
return true
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
|
|
44
128
|
function escapeRegex(s) {
|
|
45
129
|
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
46
130
|
}
|
|
@@ -62,7 +146,11 @@ function keywordMatchesContext(keyword, contextLower) {
|
|
|
62
146
|
* 用任务上下文匹配知识条目
|
|
63
147
|
* @param {string} indexDir - knowledge 目录路径
|
|
64
148
|
* @param {string} taskContext - 任务上下文(task 名称 + 描述,用于关键词匹配)
|
|
65
|
-
* @returns {{ matched: boolean, entries: Array, report: string, json: object
|
|
149
|
+
* @returns {{ matched: boolean, entries: Array, report: string, json: object,
|
|
150
|
+
* decisionHits: Array<{ file: string, id: string, title: string, status: string, reason: string, revisitWhen: string }> }}
|
|
151
|
+
* matched/entries/report/json 既有四字段结构与语义不变;decisionHits(task-04 新增)= 任务上下文
|
|
152
|
+
* 命中的 Decisions 路由行所指向 decisions/<域>.md 内的全部 D-xxx@vN 条目,rejected 优先排序;
|
|
153
|
+
* 无 decisions 库 / 路由行未命中 → decisionHits: [](其余字段行为与现状一致)。
|
|
66
154
|
*/
|
|
67
155
|
export function matchKnowledge(indexDir, taskContext) {
|
|
68
156
|
const indexPath = join(indexDir, 'INDEX.md')
|
|
@@ -73,7 +161,8 @@ export function matchKnowledge(indexDir, taskContext) {
|
|
|
73
161
|
matched: false,
|
|
74
162
|
entries: [],
|
|
75
163
|
report: 'Status: no matches (INDEX.md not found)',
|
|
76
|
-
json: { matched: false, entry_count: 0, entries: [] }
|
|
164
|
+
json: { matched: false, entry_count: 0, entries: [] },
|
|
165
|
+
decisionHits: []
|
|
77
166
|
}
|
|
78
167
|
}
|
|
79
168
|
|
|
@@ -83,7 +172,8 @@ export function matchKnowledge(indexDir, taskContext) {
|
|
|
83
172
|
matched: false,
|
|
84
173
|
entries: [],
|
|
85
174
|
report: 'Status: no matches',
|
|
86
|
-
json: { matched: false, entry_count: 0, entries: [] }
|
|
175
|
+
json: { matched: false, entry_count: 0, entries: [] },
|
|
176
|
+
decisionHits: []
|
|
87
177
|
}
|
|
88
178
|
}
|
|
89
179
|
|
|
@@ -97,7 +187,8 @@ export function matchKnowledge(indexDir, taskContext) {
|
|
|
97
187
|
matched: false,
|
|
98
188
|
entries: [],
|
|
99
189
|
report: 'Status: no matches',
|
|
100
|
-
json: { matched: false, entry_count: 0, entries: [] }
|
|
190
|
+
json: { matched: false, entry_count: 0, entries: [] },
|
|
191
|
+
decisionHits: []
|
|
101
192
|
}
|
|
102
193
|
}
|
|
103
194
|
|
|
@@ -126,5 +217,15 @@ export function matchKnowledge(indexDir, taskContext) {
|
|
|
126
217
|
}))
|
|
127
218
|
}
|
|
128
219
|
|
|
129
|
-
|
|
220
|
+
// decisionHits(task-04):任务上下文命中的 Decisions 路由行 → 解析其指向的
|
|
221
|
+
// decisions/<域>.md 内全部条目;rejected 优先排序(防复潮信息最先可见,组内保持文件序)。
|
|
222
|
+
// 不引入新顶层 hits 字段,不改 matched/entries/report/json 四个既有键。
|
|
223
|
+
const decisionRoutes = matched.filter(isDecisionRoute)
|
|
224
|
+
const allDecisionHits = decisionRoutes.length > 0 ? parseDecisionEntries(indexDir, decisionRoutes) : []
|
|
225
|
+
const decisionHits = [
|
|
226
|
+
...allDecisionHits.filter(h => h.status === 'rejected'),
|
|
227
|
+
...allDecisionHits.filter(h => h.status !== 'rejected')
|
|
228
|
+
]
|
|
229
|
+
|
|
230
|
+
return { matched: true, entries: matched, report, json, decisionHits }
|
|
130
231
|
}
|
package/src/local-register.js
CHANGED
|
@@ -44,7 +44,9 @@ export function registerRepoInLocalYaml(yamlPath, key, repoPath) {
|
|
|
44
44
|
|
|
45
45
|
const existed = existsSync(yamlPath)
|
|
46
46
|
// CRLF 归一后按 LF 写回(同 task 卡锚点写入的 CRLF 坑;local.yaml 各 CLI 写入口径均 LF)
|
|
47
|
-
const
|
|
47
|
+
const raw0 = existed ? readFileSync(yamlPath, 'utf8') : ''
|
|
48
|
+
const hadCr = raw0.includes('\r') // 磁盘原文带 CRLF → 幂等路径也要落盘治愈(见下方幂等分支)
|
|
49
|
+
const raw = existed ? raw0.replace(/\r\n?/g, '\n') : ''
|
|
48
50
|
const posixPath = String(repoPath).replace(/\\/g, '/')
|
|
49
51
|
const entryLine = ` ${key}: ${posixPath}`
|
|
50
52
|
|
|
@@ -79,6 +81,10 @@ export function registerRepoInLocalYaml(yamlPath, key, repoPath) {
|
|
|
79
81
|
for (let i = reposIdx + 1; i < end; i++) {
|
|
80
82
|
if (keyRe.test(lines[i])) {
|
|
81
83
|
if (lines[i] === entryLine) {
|
|
84
|
+
// 坑 register-repo-crlf-idempotent-loop:磁盘原文带 CRLF 时(agent Write 工具/Windows
|
|
85
|
+
// 编辑器写入),内存归一后比对相等直接跳过 → 磁盘永不治愈 + CLI 报 ✅ 假成功 → 解析侧
|
|
86
|
+
// (修复前)空 Map → MultiRepoContext 报「未注册」→ 死循环。幂等路径也落盘一次治愈。
|
|
87
|
+
if (hadCr) write(lines.join('\n'))
|
|
82
88
|
return { fileCreated: false, sectionCreated: false, replaced: false } // 值未变,幂等跳过
|
|
83
89
|
}
|
|
84
90
|
lines[i] = entryLine
|
package/src/module-resolve.js
CHANGED
|
@@ -20,6 +20,11 @@
|
|
|
20
20
|
* - 判定语义(哪个模块才是「对的」)仍归 agent——本表只是机械最优匹配
|
|
21
21
|
*/
|
|
22
22
|
import { existsSync, readFileSync, readdirSync, statSync } from 'fs'
|
|
23
|
+
|
|
24
|
+
/** 模块卡字数预算(字节):超限在 resolve 表标 ⚠️ 并提示精简——文档是 agent 的读取税
|
|
25
|
+
* (对标 deepseek-harness verify-doc-budgets 理念:预算只降不升;2026-08-24 起 runtime.md
|
|
26
|
+
* 28KB/worktree.md 24KB 已在付税)。advisory 不阻断,16 为 dogfood 校准前缺省。 */
|
|
27
|
+
const MODULE_CARD_BUDGET_BYTES = 16 * 1024
|
|
23
28
|
import { join, relative } from 'path'
|
|
24
29
|
import { parseModuleMapSimple } from './modules.js'
|
|
25
30
|
import { parseTaskRegistry } from './stages/execute.js'
|
|
@@ -197,9 +202,12 @@ export function renderModuleResolveTable({ cwd, specBase, changeName }) {
|
|
|
197
202
|
'| task | 模块 | 粒度 | 模块卡(只读命中的卡,勿按目录整读) | 体量 | 读取建议 |',
|
|
198
203
|
'|---|---|---|---|---|---|',
|
|
199
204
|
]
|
|
205
|
+
const budgetBreached = new Set()
|
|
200
206
|
for (const r of rows) {
|
|
201
207
|
if (r.moduleId) {
|
|
202
|
-
|
|
208
|
+
const over = r.cardBytes > MODULE_CARD_BUDGET_BYTES
|
|
209
|
+
if (over) budgetBreached.add(r.moduleId)
|
|
210
|
+
L.push(`| ${r.taskId} | ${r.moduleId} | ${r.granularity === 'fine' ? '细' : '粗'} | \`${r.cardPath}\` | ${kb(r.cardBytes)}${over ? ' ⚠️超预算' : ''} | ${r.advice} |`)
|
|
203
211
|
} else {
|
|
204
212
|
L.push(`| ${r.taskId} | — | — | (无命中,跳过模块文档) | — | — |`)
|
|
205
213
|
}
|
|
@@ -207,5 +215,8 @@ export function renderModuleResolveTable({ cwd, specBase, changeName }) {
|
|
|
207
215
|
L.push('')
|
|
208
216
|
L.push('> 匹配规则:全部 _module-map.yaml 跨层最长前缀(子项目细卡优先于根层大卡),源=tasks 卡 allowed_paths。')
|
|
209
217
|
L.push('> 细卡整卡可读;仅粗卡命中且体量大时**按节读**——只读「契约摘要/注意事项/定位」,跳过「变更索引/人工备注」历史累积段。')
|
|
218
|
+
if (budgetBreached.size > 0) {
|
|
219
|
+
L.push(`> ⚠️ 模块卡超预算(>${Math.round(MODULE_CARD_BUDGET_BYTES / 1024)}KB):${[...budgetBreached].join('、')}——文档是 agent 的读取税,本次变更触及该模块,收尾时顺手 \`sillyspec modules split-changelog\` 迁出历史段或精简正文(对标 deepseek-harness verify-doc-budgets:预算只降不升)。`)
|
|
220
|
+
}
|
|
210
221
|
return L.join('\n')
|
|
211
222
|
}
|
package/src/modules.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, readdirSync, readFileSync, writeFileSync } from 'fs';
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import { gitQuiet } from './git-helper.js';
|
|
4
|
+
import { nowWallClock } from './datetime.js';
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -112,7 +113,7 @@ export async function rebuildModuleMap(cwd, { force = false } = {}) {
|
|
|
112
113
|
|
|
113
114
|
// 生成新的 _module-map.yaml
|
|
114
115
|
// 保留已有的完整字段,补齐新卡片
|
|
115
|
-
const now =
|
|
116
|
+
const now = nowWallClock();
|
|
116
117
|
let headCommit = '';
|
|
117
118
|
try {
|
|
118
119
|
// QUAL-01 收口:走 git-helper 统一入口(safe.directory + 数组形式)
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* plan-adopt-waves.js — `sillyspec plan-adopt-waves` 把 plan.md 的 Wave 段一键重排为
|
|
3
|
+
* depends_on 拓扑分组(坑 wave-manual-mismatch-noise,2026-08-24 用户反馈二期:主控手排
|
|
4
|
+
* Wave 与 CLI 拓扑比对不一致只能手动改;依赖方向违规修复后,本命令给一条零手写出路)。
|
|
5
|
+
*
|
|
6
|
+
* 行为:
|
|
7
|
+
* - depMap(tasks/*.md 的 depends_on,collectTaskDepMap 与 postcheck 同源)→ topoSortWaves
|
|
8
|
+
* - 重写 plan.md 的 `## Wave N` 段块(段内按编号排序;首段「并行,无依赖」、其余「依赖前序 Wave」)
|
|
9
|
+
* - 无显式 Wave 标题 → 插在「## 任务总表」前(无总表则文末追加)
|
|
10
|
+
* - best-effort 同步任务总表的 W 列(仅认 7 列模板行;不匹配的行 warn 不强改)
|
|
11
|
+
* - Wave 段内若含非引用内容(正文/表格)→ 拒绝重写(防误删),提示先手动整理
|
|
12
|
+
* - 写后复跑 validateBlueprintConsistency 打印结果(防 adopt 把手工安全串行收敛出
|
|
13
|
+
* 同 Wave 共享路径冲突——topo 只看依赖不看文件重叠)
|
|
14
|
+
* - --dry-run 只打印将写入的 Wave 段不落盘;幂等(重复跑产出相同结构);行尾统一 LF
|
|
15
|
+
*/
|
|
16
|
+
import { existsSync, readFileSync, writeFileSync } from 'fs'
|
|
17
|
+
import { join } from 'path'
|
|
18
|
+
import { topoSortWaves, collectTaskDepMap, validateBlueprintConsistency } from './stages/plan-postcheck.js'
|
|
19
|
+
|
|
20
|
+
const WAVE_HEADING_RE = /^#+\s*Wave\s+\d+/i
|
|
21
|
+
const TASK_REF_RE = /^[-*]\s+(?:\[[ x]\]\s*)?task-\d+\s*[::\s]*$/i
|
|
22
|
+
const LEGACY_TASK_REF_RE = /^[-*]\s*\[[ x]\]\s*task-\d+/i
|
|
23
|
+
const SUMMARY_HEADING_RE = /^#+\s*任务总表/
|
|
24
|
+
|
|
25
|
+
/** 渲染标准 Wave 段块(段落间空行分隔,结尾不带多余空行——由调用方控制拼接) */
|
|
26
|
+
function renderWaveBlock(waves) {
|
|
27
|
+
const L = []
|
|
28
|
+
waves.forEach((wave, i) => {
|
|
29
|
+
const sorted = [...wave].sort((a, b) =>
|
|
30
|
+
parseInt(String(a).replace(/\D/g, ''), 10) - parseInt(String(b).replace(/\D/g, ''), 10))
|
|
31
|
+
L.push(`## Wave ${i + 1}(${i === 0 ? '并行,无依赖' : '依赖前序 Wave'})`)
|
|
32
|
+
for (const t of sorted) L.push(`- ${t}`)
|
|
33
|
+
if (i < waves.length - 1) L.push('')
|
|
34
|
+
})
|
|
35
|
+
return L
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** best-effort 更新任务总表 W 列:仅认 `| task-XX | … | W1 | … |` 形态的 7+ 列模板行 */
|
|
39
|
+
function updateSummaryWaveColumn(lines, waveOf) {
|
|
40
|
+
let inSummary = false
|
|
41
|
+
let updated = 0
|
|
42
|
+
let skipped = 0
|
|
43
|
+
for (let i = 0; i < lines.length; i++) {
|
|
44
|
+
const line = lines[i]
|
|
45
|
+
if (/^#+\s/.test(line)) { inSummary = SUMMARY_HEADING_RE.test(line); continue }
|
|
46
|
+
if (!inSummary) continue
|
|
47
|
+
const m = line.match(/^\|\s*task-(\d+)\s*\|/)
|
|
48
|
+
if (!m) continue
|
|
49
|
+
const cells = line.split('|')
|
|
50
|
+
// 模板 7 列:| 编号 | 任务 | Wave | 优先级 | 依赖 | 覆盖 FR/D | 说明 | → split 后首尾空串
|
|
51
|
+
if (cells.length < 8 || !/^\s*W\d+\s*$/.test(cells[3] || '')) { skipped++; continue }
|
|
52
|
+
const taskId = `task-${String(m[1]).padStart(2, '0')}`
|
|
53
|
+
const waveIdx = waveOf.get(taskId)
|
|
54
|
+
if (waveIdx === undefined) { skipped++; continue }
|
|
55
|
+
cells[3] = ` W${waveIdx + 1} `
|
|
56
|
+
lines[i] = cells.join('|')
|
|
57
|
+
updated++
|
|
58
|
+
}
|
|
59
|
+
return { updated, skipped }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @param {{ changeDir: string, dryRun?: boolean }} opts
|
|
64
|
+
* @returns {{ ok: boolean, error?: string, waves?: string[][], planPath: string, dryRun: boolean,
|
|
65
|
+
* waveBlock?: string[], tableRowsUpdated?: number, tableRowsSkipped?: number,
|
|
66
|
+
* postcheck?: { errors: string[], warnings: string[] } }}
|
|
67
|
+
*/
|
|
68
|
+
export function adoptPlanWaves({ changeDir, dryRun = false }) {
|
|
69
|
+
const planPath = join(changeDir, 'plan.md')
|
|
70
|
+
if (!existsSync(planPath)) return { ok: false, error: `plan.md 不存在: ${planPath}`, planPath, dryRun }
|
|
71
|
+
const tasksDir = join(changeDir, 'tasks')
|
|
72
|
+
if (!existsSync(tasksDir)) return { ok: false, error: `tasks/ 目录不存在: ${tasksDir}`, planPath, dryRun }
|
|
73
|
+
const depMap = collectTaskDepMap(tasksDir)
|
|
74
|
+
if (depMap.size === 0) return { ok: false, error: 'tasks/ 下没有 task-NN.md 卡片,无从推导 Wave 分组', planPath, dryRun }
|
|
75
|
+
|
|
76
|
+
const { waves, error: topoError } = topoSortWaves(depMap)
|
|
77
|
+
if (topoError) return { ok: false, error: `拓扑排序失败: ${topoError}`, planPath, dryRun }
|
|
78
|
+
|
|
79
|
+
const original = readFileSync(planPath, 'utf8')
|
|
80
|
+
const lines = original.split(/\r?\n/)
|
|
81
|
+
const waveBlock = renderWaveBlock(waves)
|
|
82
|
+
const waveOf = new Map()
|
|
83
|
+
waves.forEach((ws, i) => { for (const t of ws) waveOf.set(t, i) })
|
|
84
|
+
|
|
85
|
+
const firstWaveIdx = lines.findIndex(l => WAVE_HEADING_RE.test(l))
|
|
86
|
+
if (firstWaveIdx >= 0) {
|
|
87
|
+
// Wave 段块末尾 = 最后一个 Wave 标题之后连续的任务引用行(空行容忍但不断段;
|
|
88
|
+
// 遇非 Wave 标题即止)。段内混入非引用内容 → 拒绝重写(防误删正文/表格)。
|
|
89
|
+
let endIdx = firstWaveIdx
|
|
90
|
+
for (let i = firstWaveIdx; i < lines.length; i++) {
|
|
91
|
+
if (WAVE_HEADING_RE.test(lines[i])) { endIdx = i; continue }
|
|
92
|
+
if (TASK_REF_RE.test(lines[i]) || LEGACY_TASK_REF_RE.test(lines[i])) { endIdx = i; continue }
|
|
93
|
+
if (lines[i].trim() === '') continue
|
|
94
|
+
if (/^#+\s/.test(lines[i])) break
|
|
95
|
+
return { ok: false, error: `Wave 段内含非引用内容(第 ${i + 1} 行「${lines[i].slice(0, 40)}」)——为防误删拒绝重写,请先把 Wave 段整理为纯 "- task-XX" 引用行`, planPath, dryRun }
|
|
96
|
+
}
|
|
97
|
+
lines.splice(firstWaveIdx, endIdx - firstWaveIdx + 1, ...waveBlock)
|
|
98
|
+
} else {
|
|
99
|
+
// 无显式 Wave 标题:插在「## 任务总表」前;无总表则文末追加
|
|
100
|
+
const summaryIdx = lines.findIndex(l => SUMMARY_HEADING_RE.test(l))
|
|
101
|
+
if (summaryIdx >= 0) {
|
|
102
|
+
lines.splice(summaryIdx, 0, ...waveBlock, '')
|
|
103
|
+
} else {
|
|
104
|
+
while (lines.length > 0 && lines[lines.length - 1].trim() === '') lines.pop()
|
|
105
|
+
lines.push('', ...waveBlock)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const { updated, skipped } = updateSummaryWaveColumn(lines, waveOf)
|
|
110
|
+
const content = lines.join('\n').replace(/\n*$/, '\n')
|
|
111
|
+
|
|
112
|
+
if (dryRun) {
|
|
113
|
+
return { ok: true, waves, planPath, dryRun: true, waveBlock, tableRowsUpdated: updated, tableRowsSkipped: skipped }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
writeFileSync(planPath, content, 'utf8')
|
|
117
|
+
// 复跑 blueprint 一致性(advisory 打印):topo 只看依赖不看文件重叠——adopt 可能把手工
|
|
118
|
+
// 安全串行收敛出同 Wave 共享路径冲突,立即暴露而非留到 execute 撞
|
|
119
|
+
let postcheck = null
|
|
120
|
+
try {
|
|
121
|
+
postcheck = validateBlueprintConsistency(changeDir)
|
|
122
|
+
} catch (e) {
|
|
123
|
+
postcheck = { errors: [`复跑校验异常: ${e?.message || e}`], warnings: [] }
|
|
124
|
+
}
|
|
125
|
+
return { ok: true, waves, planPath, dryRun: false, waveBlock, tableRowsUpdated: updated, tableRowsSkipped: skipped, postcheck }
|
|
126
|
+
}
|
package/src/quicklog.js
CHANGED
|
@@ -32,13 +32,15 @@ const sleep = (ms) => new Promise(r => setTimeout(r, ms))
|
|
|
32
32
|
* 与 rename 之间),相比旧实现的必现双进已可忽略。
|
|
33
33
|
* @param {string} lockPath 锁文件路径(建议与被保护文件同目录)
|
|
34
34
|
* @param {() => (any|Promise<any>)} fn 临界区
|
|
35
|
-
* @param {{staleMs?:number, timeoutMs?:number, retryMs?:number}} opts
|
|
35
|
+
* @param {{staleMs?:number, timeoutMs?:number, retryMs?:number, content?:string}} opts
|
|
36
|
+
* content:锁文件内容(默认 pid-randomId)。供超时报错时展示持有者语义(如 apply 锁写
|
|
37
|
+
* {pid, changeName})——仅展示用途,抢占/偷锁逻辑只比对内容一致性不解析语义。
|
|
36
38
|
*/
|
|
37
39
|
export async function withFileLock(lockPath, fn, opts = {}) {
|
|
38
|
-
const { staleMs = 30000, timeoutMs = 10000, retryMs = 50 } = opts
|
|
40
|
+
const { staleMs = 30000, timeoutMs = 10000, retryMs = 50, content = null } = opts
|
|
39
41
|
mkdirSync(dirname(lockPath), { recursive: true })
|
|
40
42
|
const start = Date.now()
|
|
41
|
-
const myId = `${process.pid}-${randomBytes(6).toString('hex')}`
|
|
43
|
+
const myId = content || `${process.pid}-${randomBytes(6).toString('hex')}`
|
|
42
44
|
let fd = null
|
|
43
45
|
// 抢锁循环
|
|
44
46
|
while (true) {
|
|
@@ -174,6 +176,9 @@ function buildPushPayloadFromRaw(rawBlock, { ql_id, author_raw, status, linked_c
|
|
|
174
176
|
payload.timestamp = parts[1] || null
|
|
175
177
|
payload.title = parts.slice(2).join('|').trim() || payload.title
|
|
176
178
|
}
|
|
179
|
+
// 顶层标签白名单(^ 行首锚定):D-004@v1 根因块嵌套四子字段(- 现象:/- 根因:/- 护栏:/- 证据: 列表行)
|
|
180
|
+
// 因「- 」前缀不匹配本正则——它们是根因块正文内的列表行续行,不是新顶层标签,经 lastLabel 挂载
|
|
181
|
+
// 进 body_sections[根因](见下方 inFiles 复位注释)。顶层四字段边界解析不受影响(R-03)。
|
|
177
182
|
const labelRe = /^(状态|关联变更|文件|审计|需求|根因|方案|结果)\s*[::]\s*(.*)$/
|
|
178
183
|
const bulletRe = /^-\s+(.*)$/
|
|
179
184
|
let inFiles = false
|
|
@@ -190,7 +195,9 @@ function buildPushPayloadFromRaw(rawBlock, { ql_id, author_raw, status, linked_c
|
|
|
190
195
|
else if (label === '关联变更') { payload.linked_changes = value.split(/[,,、+;;]/).map(s => s.trim()).filter(Boolean); inLinked = true; inFiles = false }
|
|
191
196
|
else if (label === '文件') { if (value) payload.files.push(...value.split(/[,,、+;;]/).map(s => s.trim()).filter(Boolean).map(p => ({ path: p, note: null }))); inFiles = true; inLinked = false }
|
|
192
197
|
else if (label === '审计') { /* D-8 advisory 行:只进 raw_block 不进结构化段(body_sections 不扩 schema),并阻断续行误挂 */ lastLabel = null; inFiles = false; inLinked = false }
|
|
193
|
-
|
|
198
|
+
// 进入 需求/根因/方案/结果 字段块须关闭 inFiles/inLinked 续行模式(task-07 / D-004@v1):否则根因块内
|
|
199
|
+
// 嵌套子字段列表行(- 现象:… 等)会命中下方「文件 bullet」分支被劫进 payload.files,从根因正文截断丢失。
|
|
200
|
+
else { payload.body_sections[label] = value; lastLabel = label; inFiles = false; inLinked = false }
|
|
194
201
|
continue
|
|
195
202
|
}
|
|
196
203
|
if (bulletRe.test(stripped) && inFiles) {
|
|
@@ -332,6 +339,37 @@ export function parseFileNotes(raw) {
|
|
|
332
339
|
.filter(Boolean)
|
|
333
340
|
}
|
|
334
341
|
|
|
342
|
+
/**
|
|
343
|
+
* 校验 --file-notes 原文格式(坑 quick-file-notes-format-silent,2026-08-24 用户反馈二期②:
|
|
344
|
+
* 多文件分隔符是 `||` 双竖线,写错成 `|`/`,` 时整段被当成第一个文件的括注静默落盘,只能手工修
|
|
345
|
+
* QUICKLOG)。命令入口 fail-fast 用:每个 `||` 段必须是 `path::括注`(`::` 必填,括注可空);
|
|
346
|
+
* 括注内再出现 `::` 视为疑似漏写 `||` 分隔符。返回问题清单供调用方拼报错。
|
|
347
|
+
* @param {string} raw
|
|
348
|
+
* @returns {{ ok: boolean, problems: Array<{ seg: string, reason: string, hint: string }> }}
|
|
349
|
+
*/
|
|
350
|
+
export function validateFileNotesFormat(raw) {
|
|
351
|
+
const problems = []
|
|
352
|
+
if (!raw) return { ok: true, problems }
|
|
353
|
+
for (const seg of String(raw).split('||')) {
|
|
354
|
+
const s = seg.trim()
|
|
355
|
+
if (!s) continue
|
|
356
|
+
const idx = s.indexOf('::')
|
|
357
|
+
if (idx === -1) {
|
|
358
|
+
problems.push({ seg: s, reason: '缺 `::` 路径/括注分隔符', hint: '格式为 path::括注;不要括注也要写 path::(括注可空)' })
|
|
359
|
+
continue
|
|
360
|
+
}
|
|
361
|
+
const path = s.slice(0, idx).trim()
|
|
362
|
+
if (!path) {
|
|
363
|
+
problems.push({ seg: s, reason: '`::` 前路径为空', hint: '格式为 path::括注' })
|
|
364
|
+
continue
|
|
365
|
+
}
|
|
366
|
+
if (s.slice(idx + 2).includes('::')) {
|
|
367
|
+
problems.push({ seg: s, reason: '括注内出现 `::`', hint: '疑似多文件漏写 `||` 分隔符(双竖线)——多文件写法:path1::括注1 || path2::括注2' })
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return { ok: problems.length === 0, problems }
|
|
371
|
+
}
|
|
372
|
+
|
|
335
373
|
// 结果块必填字段(quick step3 --done --output 的结构化结果模板,见 src/stages/quick.js)。
|
|
336
374
|
// 4 个必填字段标签从 manifest 同源(stage-contract-spec.js quick.result-labels),prompt 事前契约与本校验单源。
|
|
337
375
|
const RESULT_REQUIRED_LABELS = getRule('quick.result-labels').data.literals
|
|
@@ -344,6 +382,8 @@ const RESULT_REQUIRED_LABELS = getRule('quick.result-labels').data.literals
|
|
|
344
382
|
* @returns {{ ok: boolean, missing: string[] }} ok=true 通过;missing=缺失的字段名列表
|
|
345
383
|
*/
|
|
346
384
|
export function validateQuickResult(text) {
|
|
385
|
+
// 子串包含判定:根因块含嵌套四子字段列表行(- 现象:… 等,task-07 / D-004@v1 合法形态)时,
|
|
386
|
+
// 顶层四标签仍须齐备(模板契约),嵌套行不影响判定(「- 」前缀不构成顶层标签,亦不缺字段)。
|
|
347
387
|
const missing = RESULT_REQUIRED_LABELS.filter(label => !String(text || '').includes(label))
|
|
348
388
|
return { ok: missing.length === 0, missing }
|
|
349
389
|
}
|
|
@@ -486,6 +526,9 @@ async function checkTaskCheckbox(specBase, change, qlId) {
|
|
|
486
526
|
// 前缀」或正则 split(/(?=需求:|根因:|方案:|结果:)/))因前导是「/|( 等非边界字符而跳过。严格失败
|
|
487
527
|
// (如真实标签前导是「,」这类弱标点)退回宽松顺序扫描(上一标签之后首次出现)。缺标签返回 null → 落单行
|
|
488
528
|
// 兜底(--done 契约校验仍会拦缺字段)。残余边界:正文引用标签且前导恰好是空白/句末标点时仍可能错位。
|
|
529
|
+
// task-07 / D-004@v1 声明:本切分只作用于「单行四字段压缩归一」路径,嵌套四子字段(- 现象:/- 根因:/
|
|
530
|
+
// - 护栏:/- 证据: 列表行)必须以多行列表行形态写入根因块正文——按序扫描先命中顶层「根因:」标签,
|
|
531
|
+
// 其后的嵌套「- 根因:」等字样落在根因字段正文内不构成新边界,无需改动三个边界函数即天然兼容(Grill C-15)。
|
|
489
532
|
function isFieldBoundary(body, idx) {
|
|
490
533
|
if (idx <= 0) return true
|
|
491
534
|
const prev = body[idx - 1]
|
|
@@ -567,6 +610,9 @@ function flipEntryInContent(content, qlId, result, changedFiles = [], fileNotes
|
|
|
567
610
|
if (segs) body = segs.join('\n')
|
|
568
611
|
}
|
|
569
612
|
// 多行结果(结构化 需求/根因/方案/结果 字段块):逐行插入为独立字段行。
|
|
613
|
+
// 根因块嵌套四子字段(- 现象:/- 根因:/- 护栏:/- 证据: 列表行,D-004@v1 postmortem 形态)属
|
|
614
|
+
// 根因块正文:在此随多行结果逐行原样落盘(带「- 」前缀、保序含换行),不被字段边界扫描误切——
|
|
615
|
+
// 单行归一切分只认「- 」前缀之外的需求:/根因:/方案:/结果: 标签,嵌套行天然不参与边界判定。
|
|
570
616
|
// 单行结果:保持「结果:<一句话>」一行,向后兼容简单用例。
|
|
571
617
|
const resultLines = /\r?\n/.test(body)
|
|
572
618
|
? body.split(/\r?\n/).filter(l => l.trim() !== '')
|