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
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Machine Interface v1 — 机器接口层(SillyHub driver 模式地基)
|
|
3
|
+
*
|
|
4
|
+
* 把 SillySpec 既有的门控与事实核验从「埋在 run <stage> --done 人类可读输出流里」
|
|
5
|
+
* 抽象成可被程序化消费的统一 JSON envelope + 退出码契约。
|
|
6
|
+
*
|
|
7
|
+
* 设计原则(见 change 2026-07-09-machine-interface-v1 design.md §2/§3):
|
|
8
|
+
* - 方案 B:独立模块单点封装,不污染既有 run/progress 输出
|
|
9
|
+
* - 只聚合不新增校验:复用 stage-contract / task-review / verify-postcheck 既有策略引擎
|
|
10
|
+
* - 只读语义边界(D-002@v1):只调 ProgressManager 读路径,不写 sillyspec.db
|
|
11
|
+
* - stdout 纯 JSON(D-005@v1):--json 模式下由 CLI 层(src/index.js 的 withJsonOutput)
|
|
12
|
+
* 在调用 runGate/runDerive 期间劫持 console.log 到 stderr,防被调模块污染机器输出
|
|
13
|
+
* - 退出码 0/1/2 三段语义(D-004@v1):0=通过,1=事实阻断,2=无法核验
|
|
14
|
+
*
|
|
15
|
+
* 仅依赖 Node 18+ 原生 API,零新增外部依赖。
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { existsSync, readFileSync } from 'fs';
|
|
19
|
+
import { join } from 'path';
|
|
20
|
+
import { ProgressManager, resolveSpecDir } from './progress.js';
|
|
21
|
+
import { resolveRuntimeRoot } from './run/shared.js';
|
|
22
|
+
import { runValidators, checkTransition, checkExecuteCodeEvidence } from './stage-contract.js';
|
|
23
|
+
import { validateTaskReviews, resolveLatestExecuteRunId } from './task-review.js';
|
|
24
|
+
import { runVerifyTestCheck } from './verify-postcheck.js';
|
|
25
|
+
|
|
26
|
+
// ============ 退出码常量(D-004@v1)============
|
|
27
|
+
|
|
28
|
+
export const EXIT_OK = 0; // 核验通过(可含 warnings)
|
|
29
|
+
export const EXIT_BLOCKED = 1; // 事实性阻断(JSON 含 errors)
|
|
30
|
+
export const EXIT_UNKNOWN = 2; // 无法核验(用法错/变更不存在/环境错/内部异常)
|
|
31
|
+
|
|
32
|
+
// ============ envelope schema 版本(D-005@v1)============
|
|
33
|
+
|
|
34
|
+
export const SCHEMA_VERSION = 1;
|
|
35
|
+
|
|
36
|
+
// ============ envelope 组装 ============
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 组装统一的 JSON envelope。
|
|
40
|
+
*
|
|
41
|
+
* 顶层固定字段:schema_version / command / change / ok / errors / warnings / generated_at。
|
|
42
|
+
* stage / facet / checks / data 仅在显式传参(!== undefined)时出现——保持 envelope 紧凑,
|
|
43
|
+
* daemon 可只看顶层 ok/errors/warnings。
|
|
44
|
+
*
|
|
45
|
+
* @param {object} fields
|
|
46
|
+
* @param {string|undefined} [fields.command]
|
|
47
|
+
* @param {string|undefined} [fields.stage]
|
|
48
|
+
* @param {string|undefined} [fields.facet]
|
|
49
|
+
* @param {string|undefined} [fields.change]
|
|
50
|
+
* @param {boolean} fields.ok
|
|
51
|
+
* @param {string[]} [fields.errors=[]]
|
|
52
|
+
* @param {string[]} [fields.warnings=[]]
|
|
53
|
+
* @param {Array<object>|undefined} [fields.checks]
|
|
54
|
+
* @param {object|undefined} [fields.data]
|
|
55
|
+
* @returns {object} 可直接 JSON.stringify 的 envelope 对象
|
|
56
|
+
*/
|
|
57
|
+
export function buildEnvelope({
|
|
58
|
+
command,
|
|
59
|
+
stage,
|
|
60
|
+
facet,
|
|
61
|
+
change,
|
|
62
|
+
ok,
|
|
63
|
+
errors = [],
|
|
64
|
+
warnings = [],
|
|
65
|
+
checks,
|
|
66
|
+
data,
|
|
67
|
+
}) {
|
|
68
|
+
const envelope = {
|
|
69
|
+
schema_version: SCHEMA_VERSION,
|
|
70
|
+
command,
|
|
71
|
+
change,
|
|
72
|
+
ok,
|
|
73
|
+
errors,
|
|
74
|
+
warnings,
|
|
75
|
+
generated_at: new Date().toISOString(),
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// 按需字段:仅当显式传参时挂上,避免空 null 污染
|
|
79
|
+
if (stage !== undefined) envelope.stage = stage;
|
|
80
|
+
if (facet !== undefined) envelope.facet = facet;
|
|
81
|
+
if (checks !== undefined) envelope.checks = checks;
|
|
82
|
+
if (data !== undefined) envelope.data = data;
|
|
83
|
+
|
|
84
|
+
return envelope;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ============ 输出纪律(design §8)============
|
|
88
|
+
// --json 模式的 stdout 劫持(console.log/info → stderr)由 CLI 层 src/index.js 的
|
|
89
|
+
// withJsonOutput 在调用 runGate/runDerive 期间统一处理(覆盖整个调用期,非仅输出瞬间)。
|
|
90
|
+
// 本模块只返回 { envelope, exitCode },不直接写 stdout。
|
|
91
|
+
|
|
92
|
+
// ============ gate 聚合门控 ============
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 聚合「变更 <changeName> 的 <stage> 阶段此刻能否被标记完成」的综合结论。
|
|
96
|
+
*
|
|
97
|
+
* 只读:仅调 ProgressManager.read,不写状态(D-002@v1)。
|
|
98
|
+
* 只聚合:每个 check 复用既有策略引擎,不在本模块重写校验逻辑(design §2)。
|
|
99
|
+
*
|
|
100
|
+
* @param {string} stage - 目标阶段(brainstorm/plan/execute/verify/...)
|
|
101
|
+
* @param {string} changeName - 变更名
|
|
102
|
+
* @param {object} opts
|
|
103
|
+
* @param {string} opts.cwd - 项目根目录
|
|
104
|
+
* @param {string} [opts.specBase] - .sillyspec(或平台 specRoot)目录;默认 resolveSpecDir(cwd)
|
|
105
|
+
* @param {string} [opts.runtimeRoot] - .runtime 目录;默认 resolveRuntimeRoot 三级优先级解析
|
|
106
|
+
* @param {string} [opts.specDriftAnchor] - drift 场景主仓 specBase 锚点(坑 execute-runs-isolation)。
|
|
107
|
+
* drift 守卫命中时由调用方传入,task-reviews 的 execute-run-id marker 落点经
|
|
108
|
+
* resolveRuntimeRoot 锚主仓 .runtime,不读 worktree 副本(与 contract-matrix 调用方同语义)。
|
|
109
|
+
* @param {object} [opts.ctx] - MultiRepoContext 单例(W3 task-09,D-013)。缺省=null 退化单仓。
|
|
110
|
+
* 透传给 validateTaskReviews(execute task-reviews check)+ runVerifyTestCheck(verify-test check),
|
|
111
|
+
* 让两函数按 ctx 切跨仓 gitDir / per-repo cwd。null 时两函数按既有单仓行为零回归。
|
|
112
|
+
* @returns {Promise<{ envelope: object, exitCode: number }>}
|
|
113
|
+
*/
|
|
114
|
+
export async function runGate(stage, changeName, { cwd, specBase, runtimeRoot, specDriftAnchor, ctx = null } = {}) {
|
|
115
|
+
const specRoot = specBase || resolveSpecDir(cwd);
|
|
116
|
+
// A4:pm 用 specRoot(而非默认 resolveSpecDir(cwd))——--spec-dir/平台模式下 specBase 是真实
|
|
117
|
+
// specDir,默认解析会指向本地孤儿库,与下方 planContent/changeDir 的 specRoot 两套事实源混拼。
|
|
118
|
+
const pm = new ProgressManager({ specDir: specRoot });
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
// ── 只读契约守卫(D-002@v1):db 不存在时 fail-closed 返回 exit 2,不触发建库落盘 ──
|
|
122
|
+
// pm.read → _ensureDB → db.init() 在 db 不存在/schema 戳落后时会 _createSchema + _save 落盘
|
|
123
|
+
// (db.js:init),这会让一个声明只读的查询命令在 spec 目录凭空建 sillyspec.db,违反只读契约。
|
|
124
|
+
// db 还没建 = 该变更从未跑过流程,无从核验 → 显式返回「无法核验」而非建库。
|
|
125
|
+
const dbPath = join(specRoot, '.runtime', 'sillyspec.db');
|
|
126
|
+
if (!existsSync(dbPath)) {
|
|
127
|
+
const envelope = buildEnvelope({
|
|
128
|
+
command: 'gate',
|
|
129
|
+
stage,
|
|
130
|
+
change: changeName,
|
|
131
|
+
ok: false,
|
|
132
|
+
errors: [`无法核验:进度库不存在(${dbPath})——变更 ${changeName} 尚未运行过任何阶段,只读 gate 不会为其建库`],
|
|
133
|
+
});
|
|
134
|
+
return { envelope, exitCode: EXIT_UNKNOWN };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ── 读进度:变更不存在 → exit 2(D-004@v1)──
|
|
138
|
+
const progress = pm.read(cwd, changeName);
|
|
139
|
+
if (!progress) {
|
|
140
|
+
const envelope = buildEnvelope({
|
|
141
|
+
command: 'gate',
|
|
142
|
+
stage,
|
|
143
|
+
change: changeName,
|
|
144
|
+
ok: false,
|
|
145
|
+
errors: [`变更不存在: ${changeName}`],
|
|
146
|
+
});
|
|
147
|
+
return { envelope, exitCode: EXIT_UNKNOWN };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const currentStage = progress.currentStage || '';
|
|
151
|
+
const checks = [];
|
|
152
|
+
|
|
153
|
+
// W4-G (D-008):execute 阶段预计算 code evidence 一次,供 artifacts check(经 runValidators
|
|
154
|
+
// → validateExecuteOutputs)与下方 execute-evidence check 共享——避免各调一次 checkExecuteCodeEvidence
|
|
155
|
+
// 各 spawn 2 个 git 进程(gate execute 一次省 ≈ 60-200ms on Windows)。
|
|
156
|
+
const sharedEvidence = stage === 'execute' ? checkExecuteCodeEvidence(cwd, changeName) : undefined;
|
|
157
|
+
|
|
158
|
+
// ── a. artifacts:阶段产物校验(全部阶段)──
|
|
159
|
+
const r = runValidators(stage, cwd, changeName, {
|
|
160
|
+
projectName: progress.project,
|
|
161
|
+
specRoot,
|
|
162
|
+
...(sharedEvidence ? { evidence: sharedEvidence } : {}),
|
|
163
|
+
});
|
|
164
|
+
checks.push({
|
|
165
|
+
id: 'artifacts',
|
|
166
|
+
ok: r.ok,
|
|
167
|
+
errors: r.errors || [],
|
|
168
|
+
warnings: r.warnings || [],
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// ── b. transition:状态转换合法性(参与综合 ok,与 completeStep 硬阻断一致)──
|
|
172
|
+
// 与 run.js runStage 同源:传 fromStageData 触发 failed_post_check 门控。
|
|
173
|
+
// transition 必须参与 ok:否则 gate 返回 ok=true、exit 0,Agent 据此 --done 却被
|
|
174
|
+
// runStage 的 checkTransition 硬阻断(exit 1),gate/run 判定分裂(design §8 漂移)。
|
|
175
|
+
const fromStageData = (progress.stages && currentStage && progress.stages[currentStage]) || undefined;
|
|
176
|
+
const t = checkTransition(currentStage, stage, fromStageData ? { fromStageData } : {});
|
|
177
|
+
checks.push({
|
|
178
|
+
id: 'transition',
|
|
179
|
+
ok: t.allowed,
|
|
180
|
+
errors: t.allowed ? [] : [t.reason].filter(Boolean),
|
|
181
|
+
warnings: [],
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// ── c. execute 阶段追加 execute-evidence + task-reviews ──
|
|
185
|
+
// D-008 + W4-G:checkExecuteCodeEvidence 整个 runGate 只调一次(顶部 sharedEvidence 预计算),
|
|
186
|
+
// 这里复用——真正落实去重(原注释声称"只调一次"但实现里 execute-evidence check 仍重复调了第二次)。
|
|
187
|
+
if (stage === 'execute') {
|
|
188
|
+
const ev = sharedEvidence;
|
|
189
|
+
checks.push({
|
|
190
|
+
id: 'execute-evidence',
|
|
191
|
+
ok: ev.status !== 'unchanged',
|
|
192
|
+
errors: ev.status === 'unchanged' ? [`base..head 无代码变更: ${ev.detail}`] : [],
|
|
193
|
+
warnings: ev.status === 'unknown' ? [`无法判定代码变更: ${ev.detail}`] : [],
|
|
194
|
+
data: { status: ev.status, detail: ev.detail },
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// task-reviews:参数组装照抄 run.js:3223-3249 现成范式
|
|
198
|
+
const planDir = join(specRoot, 'changes', changeName);
|
|
199
|
+
const planPath = join(planDir, 'plan.md');
|
|
200
|
+
let planContent = '';
|
|
201
|
+
if (existsSync(planPath)) {
|
|
202
|
+
try {
|
|
203
|
+
planContent = readFileSync(planPath, 'utf8');
|
|
204
|
+
} catch {
|
|
205
|
+
planContent = '';
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// drift 场景经 resolveRuntimeRoot 三级优先级解析(runtimeRoot > specDriftAnchor > 本地兜底),
|
|
210
|
+
// 锚主仓 .runtime,不读 worktree 副本(坑 execute-runs-isolation,与 contract-matrix 调用方同语义)
|
|
211
|
+
const rtRoot = resolveRuntimeRoot({ runtimeRoot, specDriftAnchor }, specRoot);
|
|
212
|
+
// marker 缺失/为空时先扫描 execute-runs/ 找回真实 runId(与 gates.js #6 同源),
|
|
213
|
+
// 避免拿 '' 进 validateTaskReviews 拼出 execute-runs//tasks/... 产出全量误导 errors。
|
|
214
|
+
let executeRunId = '';
|
|
215
|
+
try {
|
|
216
|
+
executeRunId = resolveLatestExecuteRunId({ runtimeRoot: rtRoot, changeName }) || '';
|
|
217
|
+
} catch {
|
|
218
|
+
executeRunId = '';
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// git 真实性交叉校验目录:worktree 存在用 worktreePath,否则 null(交由 task-review 降级 warning)
|
|
222
|
+
let gitDir = null;
|
|
223
|
+
try {
|
|
224
|
+
const { WorktreeManager } = await import('./worktree.js');
|
|
225
|
+
const wm = new WorktreeManager({ cwd });
|
|
226
|
+
const meta = wm.getMeta(changeName);
|
|
227
|
+
if (meta?.worktreePath && meta.mode !== 'in-place-fallback' && existsSync(meta.worktreePath)) {
|
|
228
|
+
gitDir = meta.worktreePath;
|
|
229
|
+
}
|
|
230
|
+
} catch {
|
|
231
|
+
gitDir = null;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const tr = validateTaskReviews({
|
|
235
|
+
planContent,
|
|
236
|
+
runtimeRoot: rtRoot,
|
|
237
|
+
executeRunId,
|
|
238
|
+
changeDir: planDir,
|
|
239
|
+
gitDir,
|
|
240
|
+
ctx,
|
|
241
|
+
});
|
|
242
|
+
checks.push({
|
|
243
|
+
id: 'task-reviews',
|
|
244
|
+
ok: tr.ok,
|
|
245
|
+
errors: tr.errors || [],
|
|
246
|
+
warnings: tr.warnings || [],
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ── d. verify 阶段追加 verify-test(CLI 实测 local.yaml commands.test)──
|
|
251
|
+
if (stage === 'verify') {
|
|
252
|
+
const vt = runVerifyTestCheck({ cwd, specBase: specRoot, changeName, ctx });
|
|
253
|
+
const vtWarnings = [];
|
|
254
|
+
if (vt.status === 'skipped') {
|
|
255
|
+
vtWarnings.push(`⚠️ verify-test SKIPPED — gate 未核验测试(${vt.reason || 'local.yaml 未配置 commands.test 或显式无测试'})。本次 gate 结论不含测试客观核验,driver 不应据 exit 0 判定测试通过;integration-critical 变更应在 verify 阶段降级 FAIL`);
|
|
256
|
+
}
|
|
257
|
+
// known_failures 豁免披露:本次 PASS 含豁免,driver 应提示人工复核清单是否过宽
|
|
258
|
+
if (vt.exemptedCount > 0) {
|
|
259
|
+
vtWarnings.push(`⚠️ verify-test PASS 含 ${vt.exemptedCount} 个 known_failures 豁免(${vt.reason || ''});driver 应提示人工复核豁免清单是否过宽(避免误豁免本变更引入的真实失败)`);
|
|
260
|
+
}
|
|
261
|
+
// 全量 fallback 明示:跑了全量 commands.test 但非变更范围子集,失败可能含未变更
|
|
262
|
+
// 模块的预存错误——driver 不应据 exit 0 判定本次变更范围已客观测试(见 3.24 verify 坑1)。
|
|
263
|
+
if (vt.status !== 'skipped' && vt.mode === 'full' && vt.fallbackReason) {
|
|
264
|
+
vtWarnings.push(`⚠️ verify-test 跑的是全量 commands.test(${vt.fallbackReason});失败可能含未变更模块的预存错误,driver 不应据 exit 0 判定本次变更范围已测`);
|
|
265
|
+
}
|
|
266
|
+
checks.push({
|
|
267
|
+
id: 'verify-test',
|
|
268
|
+
ok: vt.status !== 'failed',
|
|
269
|
+
errors: vt.status === 'failed' ? [`测试失败: ${vt.reason || ''}`] : [],
|
|
270
|
+
warnings: vtWarnings,
|
|
271
|
+
data: {
|
|
272
|
+
status: vt.status,
|
|
273
|
+
exitCode: vt.exitCode,
|
|
274
|
+
durationMs: vt.durationMs,
|
|
275
|
+
resultPath: vt.resultPath,
|
|
276
|
+
mode: vt.mode ?? null,
|
|
277
|
+
fallbackReason: vt.fallbackReason ?? null,
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// ── 综合结论:所有非 informational check 均 ok ──
|
|
283
|
+
const ok = checks.filter((c) => !c.informational).every((c) => c.ok);
|
|
284
|
+
const exitCode = ok ? EXIT_OK : EXIT_BLOCKED;
|
|
285
|
+
|
|
286
|
+
const errors = [];
|
|
287
|
+
const warnings = [];
|
|
288
|
+
for (const c of checks) {
|
|
289
|
+
if (c.errors && c.errors.length) errors.push(...c.errors);
|
|
290
|
+
if (c.warnings && c.warnings.length) warnings.push(...c.warnings);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const envelope = buildEnvelope({
|
|
294
|
+
command: 'gate',
|
|
295
|
+
stage,
|
|
296
|
+
change: changeName,
|
|
297
|
+
ok,
|
|
298
|
+
errors,
|
|
299
|
+
warnings,
|
|
300
|
+
checks,
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
return { envelope, exitCode };
|
|
304
|
+
} catch (e) {
|
|
305
|
+
// 内部异常兜底(D-004@v1 / design §3.5):保证 stdout 永远是合法 JSON 结构,exit 2
|
|
306
|
+
const envelope = buildEnvelope({
|
|
307
|
+
command: 'gate',
|
|
308
|
+
stage,
|
|
309
|
+
change: changeName,
|
|
310
|
+
ok: false,
|
|
311
|
+
errors: [`internal: ${e.message}`],
|
|
312
|
+
});
|
|
313
|
+
return { envelope, exitCode: EXIT_UNKNOWN };
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// ============ derive 单项事实核验 ============
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* facet 枚举(D-003@v1)。machine 接口对外只接受这四个值。
|
|
321
|
+
*/
|
|
322
|
+
export const FACETS = ['execute-evidence', 'verify-test', 'task-reviews', 'artifacts'];
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* 单项事实核验:针对变更 <changeName> 查询某一 facet 的真实状态(design §3.2)。
|
|
326
|
+
*
|
|
327
|
+
* 与 gate 的差异:gate 聚合某阶段所有 check 的综合结论;derive 只返回单一 facet 的结构化 data,
|
|
328
|
+
* daemon 用来做细粒度事实采集(如轮询 execute-evidence 判断代码是否变更)。
|
|
329
|
+
*
|
|
330
|
+
* 只读语义边界同 gate(D-002@v1):仅调 ProgressManager.read,不写 sillyspec.db。
|
|
331
|
+
* 唯一例外是 verify-test 会真实执行测试并落盘 test-result.json(产物取证,非状态写入,design §3.3)。
|
|
332
|
+
*
|
|
333
|
+
* 退出码语义(D-004@v1):0=事实通过,1=事实性阻断,2=无法核验(用法错/变更不存在/内部异常)。
|
|
334
|
+
*
|
|
335
|
+
* @param {string} facet - 必须 ∈ FACETS
|
|
336
|
+
* @param {string} changeName - 变更名
|
|
337
|
+
* @param {object} opts
|
|
338
|
+
* @param {string} opts.cwd - 项目根目录
|
|
339
|
+
* @param {string} [opts.specBase] - .sillyspec(或平台 specRoot)目录;默认 resolveSpecDir(cwd)
|
|
340
|
+
* @param {string} [opts.runtimeRoot] - .runtime 目录;默认 resolveRuntimeRoot 三级优先级解析
|
|
341
|
+
* @param {string} [opts.specDriftAnchor] - drift 场景主仓 specBase 锚点(坑 execute-runs-isolation),
|
|
342
|
+
* task-reviews facet 的 execute-run-id marker 落点经 resolveRuntimeRoot 锚主仓 .runtime,不读副本。
|
|
343
|
+
* @param {object} [opts.ctx] - MultiRepoContext 单例(W3 task-09,D-013)。缺省=null 退化单仓。
|
|
344
|
+
* 透传给 verify-test / task-reviews facet(runVerifyTestCheck + validateTaskReviews)。
|
|
345
|
+
* @returns {Promise<{ envelope: object, exitCode: number }>}
|
|
346
|
+
*/
|
|
347
|
+
export async function runDerive(facet, changeName, { cwd, specBase, runtimeRoot, specDriftAnchor, ctx = null } = {}) {
|
|
348
|
+
// ── 非法 facet:用法错 → exit 2(D-004@v1)──
|
|
349
|
+
if (!FACETS.includes(facet)) {
|
|
350
|
+
const envelope = buildEnvelope({
|
|
351
|
+
command: 'derive',
|
|
352
|
+
facet,
|
|
353
|
+
change: changeName,
|
|
354
|
+
ok: false,
|
|
355
|
+
errors: [`非法 facet: ${facet},合法值: ${FACETS.join(', ')}`],
|
|
356
|
+
});
|
|
357
|
+
return { envelope, exitCode: EXIT_UNKNOWN };
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const specRoot = specBase || resolveSpecDir(cwd);
|
|
361
|
+
// A4:同 runGate——pm 用 specRoot 统一事实源,平台/--spec-dir 模式不读本地孤儿库。
|
|
362
|
+
const pm = new ProgressManager({ specDir: specRoot });
|
|
363
|
+
|
|
364
|
+
try {
|
|
365
|
+
// ── 只读契约守卫(D-002@v1,同 runGate):db 不存在时 fail-closed 返回 exit 2,不建库落盘 ──
|
|
366
|
+
const dbPath = join(specRoot, '.runtime', 'sillyspec.db');
|
|
367
|
+
if (!existsSync(dbPath)) {
|
|
368
|
+
const envelope = buildEnvelope({
|
|
369
|
+
command: 'derive',
|
|
370
|
+
facet,
|
|
371
|
+
change: changeName,
|
|
372
|
+
ok: false,
|
|
373
|
+
errors: [`无法核验:进度库不存在(${dbPath})——变更 ${changeName} 尚未运行过任何阶段,只读 derive 不会为其建库`],
|
|
374
|
+
});
|
|
375
|
+
return { envelope, exitCode: EXIT_UNKNOWN };
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// ── 读进度:变更不存在 → exit 2 ──
|
|
379
|
+
const progress = pm.read(cwd, changeName);
|
|
380
|
+
if (!progress) {
|
|
381
|
+
const envelope = buildEnvelope({
|
|
382
|
+
command: 'derive',
|
|
383
|
+
facet,
|
|
384
|
+
change: changeName,
|
|
385
|
+
ok: false,
|
|
386
|
+
errors: [`变更不存在: ${changeName}`],
|
|
387
|
+
});
|
|
388
|
+
return { envelope, exitCode: EXIT_UNKNOWN };
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const currentStage = progress.currentStage || '';
|
|
392
|
+
|
|
393
|
+
let data;
|
|
394
|
+
let ok;
|
|
395
|
+
let errors = [];
|
|
396
|
+
let warnings = [];
|
|
397
|
+
let exitCode;
|
|
398
|
+
|
|
399
|
+
switch (facet) {
|
|
400
|
+
// ── a. execute-evidence:base..head 代码变更判定 ──
|
|
401
|
+
// 语义与 validateExecuteOutputs 一致:unknown 不等于失败(无法判定不应阻断)。
|
|
402
|
+
case 'execute-evidence': {
|
|
403
|
+
const ev = checkExecuteCodeEvidence(cwd, changeName);
|
|
404
|
+
data = { status: ev.status, detail: ev.detail };
|
|
405
|
+
ok = ev.status !== 'unchanged';
|
|
406
|
+
errors = ev.status === 'unchanged' ? [`base..head 无代码变更: ${ev.detail}`] : [];
|
|
407
|
+
warnings = ev.status === 'unknown' ? [`无法判定代码变更: ${ev.detail}`] : [];
|
|
408
|
+
exitCode = ok ? EXIT_OK : EXIT_BLOCKED;
|
|
409
|
+
break;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// ── b. verify-test:真实执行测试命令并取证 ──
|
|
413
|
+
case 'verify-test': {
|
|
414
|
+
const vt = runVerifyTestCheck({ cwd, specBase: specRoot, changeName, ctx });
|
|
415
|
+
data = {
|
|
416
|
+
status: vt.status,
|
|
417
|
+
exitCode: vt.exitCode,
|
|
418
|
+
durationMs: vt.durationMs,
|
|
419
|
+
resultPath: vt.resultPath,
|
|
420
|
+
mode: vt.mode ?? null,
|
|
421
|
+
fallbackReason: vt.fallbackReason ?? null,
|
|
422
|
+
};
|
|
423
|
+
ok = vt.status !== 'failed';
|
|
424
|
+
errors = vt.status === 'failed' ? [`测试失败: ${vt.reason || ''}`] : [];
|
|
425
|
+
warnings = vt.status === 'skipped'
|
|
426
|
+
? ['测试被跳过']
|
|
427
|
+
: (vt.mode === 'full' && vt.fallbackReason)
|
|
428
|
+
? [`⚠️ verify-test 跑的是全量 commands.test(${vt.fallbackReason});失败可能含未变更模块的预存错误`]
|
|
429
|
+
: [];
|
|
430
|
+
exitCode = ok ? EXIT_OK : EXIT_BLOCKED;
|
|
431
|
+
break;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// ── c. task-reviews:plan 任务评审核验(参数组装照抄 runGate execute 段)──
|
|
435
|
+
case 'task-reviews': {
|
|
436
|
+
const changeDir = join(specRoot, 'changes', changeName);
|
|
437
|
+
const planPath = join(changeDir, 'plan.md');
|
|
438
|
+
let planContent = '';
|
|
439
|
+
if (existsSync(planPath)) {
|
|
440
|
+
try {
|
|
441
|
+
planContent = readFileSync(planPath, 'utf8');
|
|
442
|
+
} catch {
|
|
443
|
+
planContent = '';
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// drift 场景经 resolveRuntimeRoot 三级优先级解析(同 runGate execute 段),锚主仓 .runtime 不读副本
|
|
448
|
+
const rtRoot = resolveRuntimeRoot({ runtimeRoot, specDriftAnchor }, specRoot);
|
|
449
|
+
// marker 缺失/为空时先扫描 execute-runs/ 找回真实 runId(同 runGate execute 段),避免拿 '' 误导校验
|
|
450
|
+
let executeRunId = '';
|
|
451
|
+
try {
|
|
452
|
+
executeRunId = resolveLatestExecuteRunId({ runtimeRoot: rtRoot, changeName }) || '';
|
|
453
|
+
} catch {
|
|
454
|
+
executeRunId = '';
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// git 真实性交叉校验目录:worktree 存在用 worktreePath,否则 null(交由 task-review 降级 warning)
|
|
458
|
+
let gitDir = null;
|
|
459
|
+
try {
|
|
460
|
+
const { WorktreeManager } = await import('./worktree.js');
|
|
461
|
+
const wm = new WorktreeManager({ cwd });
|
|
462
|
+
const meta = wm.getMeta(changeName);
|
|
463
|
+
if (meta?.worktreePath && meta.mode !== 'in-place-fallback' && existsSync(meta.worktreePath)) {
|
|
464
|
+
gitDir = meta.worktreePath;
|
|
465
|
+
}
|
|
466
|
+
} catch {
|
|
467
|
+
gitDir = null;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
const tr = validateTaskReviews({
|
|
471
|
+
planContent,
|
|
472
|
+
runtimeRoot: rtRoot,
|
|
473
|
+
executeRunId,
|
|
474
|
+
changeDir,
|
|
475
|
+
gitDir,
|
|
476
|
+
ctx,
|
|
477
|
+
});
|
|
478
|
+
data = {
|
|
479
|
+
ok: tr.ok,
|
|
480
|
+
errors: tr.errors,
|
|
481
|
+
warnings: tr.warnings,
|
|
482
|
+
requiredEvidence: tr.requiredEvidence,
|
|
483
|
+
};
|
|
484
|
+
ok = tr.ok;
|
|
485
|
+
errors = tr.errors || [];
|
|
486
|
+
warnings = tr.warnings || [];
|
|
487
|
+
exitCode = ok ? EXIT_OK : EXIT_BLOCKED;
|
|
488
|
+
break;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// ── d. artifacts:当前阶段产物校验 ──
|
|
492
|
+
// runValidators 需要 stage:用 progress.currentStage(若为空串则校验器内部处理)。
|
|
493
|
+
case 'artifacts': {
|
|
494
|
+
const r = runValidators(currentStage, cwd, changeName, {
|
|
495
|
+
projectName: progress.project,
|
|
496
|
+
specRoot,
|
|
497
|
+
});
|
|
498
|
+
data = { ok: r.ok, errors: r.errors, warnings: r.warnings };
|
|
499
|
+
ok = r.ok;
|
|
500
|
+
errors = r.errors || [];
|
|
501
|
+
warnings = r.warnings || [];
|
|
502
|
+
exitCode = ok ? EXIT_OK : EXIT_BLOCKED;
|
|
503
|
+
break;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// 不可达:facet 已在入口白名单校验
|
|
507
|
+
default: {
|
|
508
|
+
const envelope = buildEnvelope({
|
|
509
|
+
command: 'derive',
|
|
510
|
+
facet,
|
|
511
|
+
change: changeName,
|
|
512
|
+
ok: false,
|
|
513
|
+
errors: [`非法 facet: ${facet},合法值: ${FACETS.join(', ')}`],
|
|
514
|
+
});
|
|
515
|
+
return { envelope, exitCode: EXIT_UNKNOWN };
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// stage 仅 artifacts 时出现(产物校验绑定阶段语义);其余 facet 不传 stage。
|
|
520
|
+
const envelope = buildEnvelope({
|
|
521
|
+
command: 'derive',
|
|
522
|
+
facet,
|
|
523
|
+
change: changeName,
|
|
524
|
+
ok,
|
|
525
|
+
errors,
|
|
526
|
+
warnings,
|
|
527
|
+
data,
|
|
528
|
+
stage: facet === 'artifacts' ? currentStage : undefined,
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
return { envelope, exitCode };
|
|
532
|
+
} catch (e) {
|
|
533
|
+
// 内部异常兜底(D-004@v1 / design §3.5):保证 stdout 永远是合法 JSON 结构,exit 2
|
|
534
|
+
const envelope = buildEnvelope({
|
|
535
|
+
command: 'derive',
|
|
536
|
+
facet,
|
|
537
|
+
change: changeName,
|
|
538
|
+
ok: false,
|
|
539
|
+
errors: [`internal: ${e.message}`],
|
|
540
|
+
});
|
|
541
|
+
return { envelope, exitCode: EXIT_UNKNOWN };
|
|
542
|
+
}
|
|
543
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, writeFileSync, mkdirSync, renameSync, copyFileSync, statSync, cpSync } from 'fs';
|
|
2
|
+
import { basename, join, resolve } from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Migrate old .sillyspec/ structure to unified .sillyspec/docs/<project>/ structure
|
|
7
|
+
* @param {string} projectDir - Path to the project directory
|
|
8
|
+
*/
|
|
9
|
+
export function migrateDocs(projectDir) {
|
|
10
|
+
const sillyspecDir = join(projectDir, '.sillyspec');
|
|
11
|
+
if (!existsSync(sillyspecDir)) {
|
|
12
|
+
console.error('❌ .sillyspec/ 目录不存在');
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Determine project name from projects/*.yaml or directory name
|
|
17
|
+
let projectName = basename(resolve(projectDir));
|
|
18
|
+
const projectsDir = join(sillyspecDir, 'projects');
|
|
19
|
+
if (existsSync(projectsDir)) {
|
|
20
|
+
const yamlFiles = readdirSync(projectsDir).filter(f => f.endsWith('.yaml'));
|
|
21
|
+
if (yamlFiles.length > 0) {
|
|
22
|
+
projectName = yamlFiles[0].replace('.yaml', '');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
console.log(chalk.cyan(`📦 迁移项目: ${projectName}`));
|
|
27
|
+
console.log('');
|
|
28
|
+
|
|
29
|
+
const docsBase = join(sillyspecDir, 'docs', projectName);
|
|
30
|
+
let migrated = 0;
|
|
31
|
+
|
|
32
|
+
// 1. codebase/ → .sillyspec/docs/<project>/scan/
|
|
33
|
+
const codebaseDir = join(sillyspecDir, 'codebase');
|
|
34
|
+
if (existsSync(codebaseDir)) {
|
|
35
|
+
const targetDir = join(docsBase, 'scan');
|
|
36
|
+
mkdirSync(targetDir, { recursive: true });
|
|
37
|
+
const files = readdirSync(codebaseDir).filter(f => f.endsWith('.md'));
|
|
38
|
+
for (const file of files) {
|
|
39
|
+
const src = join(codebaseDir, file);
|
|
40
|
+
const dest = join(targetDir, file);
|
|
41
|
+
if (!existsSync(dest)) {
|
|
42
|
+
copyFileSync(src, dest);
|
|
43
|
+
console.log(chalk.green(' ✅') + ` scan/${file}`);
|
|
44
|
+
migrated++;
|
|
45
|
+
} else {
|
|
46
|
+
console.log(chalk.yellow(' ⏭️') + ` scan/${file} (已存在)`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 2. specs/ is deprecated — designs live in changes/<变更名>/design.md
|
|
52
|
+
|
|
53
|
+
// 3. changes/archive/ → .sillyspec/docs/<project>/archive/
|
|
54
|
+
const archiveDir = join(sillyspecDir, 'changes', 'archive');
|
|
55
|
+
if (existsSync(archiveDir)) {
|
|
56
|
+
const targetDir = join(docsBase, 'archive');
|
|
57
|
+
mkdirSync(targetDir, { recursive: true });
|
|
58
|
+
const entries = readdirSync(archiveDir);
|
|
59
|
+
for (const entry of entries) {
|
|
60
|
+
const src = join(archiveDir, entry);
|
|
61
|
+
const dest = join(targetDir, entry);
|
|
62
|
+
if (!existsSync(dest)) {
|
|
63
|
+
// 归档变更本身是目录(含 design.md 等),copyFileSync 对目录源抛 EISDIR;
|
|
64
|
+
// 按类型分发:目录用 cpSync 递归、文件用 copyFileSync,单条失败 try/catch 不中断整体迁移
|
|
65
|
+
try {
|
|
66
|
+
if (statSync(src).isDirectory()) {
|
|
67
|
+
cpSync(src, dest, { recursive: true });
|
|
68
|
+
} else {
|
|
69
|
+
copyFileSync(src, dest);
|
|
70
|
+
}
|
|
71
|
+
console.log(chalk.green(' ✅') + ` archive/${entry}`);
|
|
72
|
+
migrated++;
|
|
73
|
+
} catch (err) {
|
|
74
|
+
console.log(chalk.yellow(' ⚠️') + ` archive/${entry} 迁移失败: ${err.message}`);
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
console.log(chalk.yellow(' ⏭️') + ` archive/${entry} (已存在)`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 4. knowledge/ → .sillyspec/docs/<project>/archive/ (append knowledge files)
|
|
83
|
+
const knowledgeDir = join(sillyspecDir, 'knowledge');
|
|
84
|
+
if (existsSync(knowledgeDir)) {
|
|
85
|
+
const targetDir = join(docsBase, 'archive');
|
|
86
|
+
mkdirSync(targetDir, { recursive: true });
|
|
87
|
+
const files = readdirSync(knowledgeDir).filter(f => f.endsWith('.md'));
|
|
88
|
+
for (const file of files) {
|
|
89
|
+
const src = join(knowledgeDir, file);
|
|
90
|
+
const dest = join(targetDir, `knowledge-${file}`);
|
|
91
|
+
if (!existsSync(dest)) {
|
|
92
|
+
copyFileSync(src, dest);
|
|
93
|
+
console.log(chalk.green(' ✅') + ` archive/knowledge-${file}`);
|
|
94
|
+
migrated++;
|
|
95
|
+
} else {
|
|
96
|
+
console.log(chalk.yellow(' ⏭️') + ` archive/knowledge-${file} (已存在)`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 5. quicklog/ → .sillyspec/docs/<project>/quicklog/
|
|
102
|
+
const quicklogDir = join(sillyspecDir, 'quicklog');
|
|
103
|
+
if (existsSync(quicklogDir)) {
|
|
104
|
+
const targetDir = join(docsBase, 'quicklog');
|
|
105
|
+
mkdirSync(targetDir, { recursive: true });
|
|
106
|
+
const files = readdirSync(quicklogDir).filter(f => f.endsWith('.md'));
|
|
107
|
+
for (const file of files) {
|
|
108
|
+
const src = join(quicklogDir, file);
|
|
109
|
+
const dest = join(targetDir, file);
|
|
110
|
+
if (!existsSync(dest)) {
|
|
111
|
+
copyFileSync(src, dest);
|
|
112
|
+
console.log(chalk.green(' ✅') + ` quicklog/${file}`);
|
|
113
|
+
migrated++;
|
|
114
|
+
} else {
|
|
115
|
+
console.log(chalk.yellow(' ⏭️') + ` quicklog/${file} (已存在)`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
console.log('');
|
|
121
|
+
if (migrated > 0) {
|
|
122
|
+
console.log(chalk.green(` ✅ 迁移完成,共迁移 ${migrated} 个文件`));
|
|
123
|
+
console.log(chalk.dim(' 旧文件保留在原位,确认无误后可手动删除'));
|
|
124
|
+
} else {
|
|
125
|
+
console.log(chalk.yellow(' 没有需要迁移的文件'));
|
|
126
|
+
}
|
|
127
|
+
}
|