sillyspec 3.27.5 → 3.27.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/sillyspec-archive/SKILL.md +87 -87
- package/.claude/skills/sillyspec-auto/SKILL.md +93 -93
- package/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -114
- package/.claude/skills/sillyspec-commit/SKILL.md +67 -67
- package/.claude/skills/sillyspec-continue/SKILL.md +47 -47
- package/.claude/skills/sillyspec-doctor/SKILL.md +76 -76
- package/.claude/skills/sillyspec-execute/SKILL.md +214 -214
- package/.claude/skills/sillyspec-explore/SKILL.md +102 -102
- package/.claude/skills/sillyspec-export/SKILL.md +57 -57
- package/.claude/skills/sillyspec-init/SKILL.md +177 -177
- package/.claude/skills/sillyspec-knowledge/SKILL.md +269 -269
- package/.claude/skills/sillyspec-plan/SKILL.md +156 -156
- package/.claude/skills/sillyspec-propose/SKILL.md +87 -0
- package/.claude/skills/sillyspec-quick/SKILL.md +116 -116
- package/.claude/skills/sillyspec-resume/SKILL.md +70 -70
- package/.claude/skills/sillyspec-scan/SKILL.md +79 -79
- package/.claude/skills/sillyspec-state/SKILL.md +64 -64
- package/.claude/skills/sillyspec-status/SKILL.md +54 -54
- package/.claude/skills/sillyspec-verify/SKILL.md +87 -87
- package/.claude/skills/sillyspec-workspace/SKILL.md +175 -175
- package/.claude/skills/verify-per-user/SKILL.md +6 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-archive/SKILL.md +87 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-auto/SKILL.md +93 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-commit/SKILL.md +67 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-continue/SKILL.md +47 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-execute/SKILL.md +214 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-explore/SKILL.md +102 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-export/SKILL.md +57 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-init/SKILL.md +177 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-plan/SKILL.md +156 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-propose/SKILL.md +87 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-quick/SKILL.md +116 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-resume/SKILL.md +70 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-scan/SKILL.md +79 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-state/SKILL.md +64 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-status/SKILL.md +54 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-verify/SKILL.md +87 -0
- package/.worktrees/2c37b1d7/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
- package/.worktrees/2c37b1d7/.claude/skills/verify-per-user/SKILL.md +6 -0
- package/.worktrees/2c37b1d7/.gitattributes +2 -0
- package/.worktrees/2c37b1d7/.husky/pre-push +20 -0
- package/.worktrees/2c37b1d7/README.md +203 -0
- package/.worktrees/2c37b1d7/SKILL.md +91 -0
- package/.worktrees/2c37b1d7/architecture-analysis.md +448 -0
- package/.worktrees/2c37b1d7/bin/sillyspec.js +2 -0
- package/.worktrees/2c37b1d7/eval/README.md +86 -0
- package/.worktrees/2c37b1d7/eval/eval.config.json +28 -0
- package/.worktrees/2c37b1d7/eval/lib/adapters/cli.mjs +63 -0
- package/.worktrees/2c37b1d7/eval/lib/adapters/dryrun.mjs +27 -0
- package/.worktrees/2c37b1d7/eval/lib/config.mjs +82 -0
- package/.worktrees/2c37b1d7/eval/lib/db.mjs +76 -0
- package/.worktrees/2c37b1d7/eval/lib/report.mjs +120 -0
- package/.worktrees/2c37b1d7/eval/lib/runner.mjs +157 -0
- package/.worktrees/2c37b1d7/eval/lib/tasks.mjs +73 -0
- package/.worktrees/2c37b1d7/eval/lib/util.mjs +107 -0
- package/.worktrees/2c37b1d7/eval/lib/workdir.mjs +30 -0
- package/.worktrees/2c37b1d7/eval/run.mjs +83 -0
- package/.worktrees/2c37b1d7/eval/tasks/001-slugify/files/package.json +6 -0
- package/.worktrees/2c37b1d7/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
- package/.worktrees/2c37b1d7/eval/tasks/001-slugify/task.json +6 -0
- package/.worktrees/2c37b1d7/eval/tasks/001-slugify/verify.mjs +28 -0
- package/.worktrees/2c37b1d7/eval/tasks/002-each-day/files/package.json +6 -0
- package/.worktrees/2c37b1d7/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
- package/.worktrees/2c37b1d7/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
- package/.worktrees/2c37b1d7/eval/tasks/002-each-day/task.json +6 -0
- package/.worktrees/2c37b1d7/eval/tasks/002-each-day/verify.mjs +31 -0
- package/.worktrees/2c37b1d7/eval/tasks/003-word-report/files/data/notes.txt +5 -0
- package/.worktrees/2c37b1d7/eval/tasks/003-word-report/files/package.json +6 -0
- package/.worktrees/2c37b1d7/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
- package/.worktrees/2c37b1d7/eval/tasks/003-word-report/task.json +6 -0
- package/.worktrees/2c37b1d7/eval/tasks/003-word-report/verify.mjs +38 -0
- package/.worktrees/2c37b1d7/logo.jpg +0 -0
- package/.worktrees/2c37b1d7/package-lock.json +977 -0
- package/.worktrees/2c37b1d7/package.json +41 -0
- package/.worktrees/2c37b1d7/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
- package/.worktrees/2c37b1d7/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
- package/.worktrees/2c37b1d7/packages/dashboard/dist/favicon.jpg +0 -0
- package/.worktrees/2c37b1d7/packages/dashboard/dist/index.html +16 -0
- package/.worktrees/2c37b1d7/packages/dashboard/dist/logo.jpg +0 -0
- package/.worktrees/2c37b1d7/packages/dashboard/dist/prototype-dashboard.html +836 -0
- package/.worktrees/2c37b1d7/packages/dashboard/dist/prototype-overview.html +256 -0
- package/.worktrees/2c37b1d7/packages/dashboard/package.json +25 -0
- package/.worktrees/2c37b1d7/packages/dashboard/server/executor.js +95 -0
- package/.worktrees/2c37b1d7/packages/dashboard/server/index.js +679 -0
- package/.worktrees/2c37b1d7/packages/dashboard/server/parser.js +526 -0
- package/.worktrees/2c37b1d7/packages/dashboard/server/watcher.js +357 -0
- package/.worktrees/2c37b1d7/src/agent-session-log.js +803 -0
- package/.worktrees/2c37b1d7/src/change-list.js +290 -0
- package/.worktrees/2c37b1d7/src/change-risk-profile.js +339 -0
- package/.worktrees/2c37b1d7/src/check-primitives.js +65 -0
- package/.worktrees/2c37b1d7/src/classify-change.js +109 -0
- package/.worktrees/2c37b1d7/src/commit-suggest.js +202 -0
- package/.worktrees/2c37b1d7/src/config-cat.js +88 -0
- package/.worktrees/2c37b1d7/src/config-schema.js +328 -0
- package/.worktrees/2c37b1d7/src/constants.js +97 -0
- package/.worktrees/2c37b1d7/src/contract-matrix.js +533 -0
- package/.worktrees/2c37b1d7/src/datetime.js +20 -0
- package/.worktrees/2c37b1d7/src/db-engine.js +55 -0
- package/.worktrees/2c37b1d7/src/db.js +381 -0
- package/.worktrees/2c37b1d7/src/decision-distill.js +517 -0
- package/.worktrees/2c37b1d7/src/dispatch/backends/local-agent.js +155 -0
- package/.worktrees/2c37b1d7/src/dispatch/backends/sillyhub-mcp.js +245 -0
- package/.worktrees/2c37b1d7/src/dispatch/probe.js +246 -0
- package/.worktrees/2c37b1d7/src/dispatch/strategy.js +121 -0
- package/.worktrees/2c37b1d7/src/docs-check.js +825 -0
- package/.worktrees/2c37b1d7/src/docs-debt.js +393 -0
- package/.worktrees/2c37b1d7/src/docs-gate.js +107 -0
- package/.worktrees/2c37b1d7/src/doctor-diagnostics.js +1099 -0
- package/.worktrees/2c37b1d7/src/endpoint-extractor.js +409 -0
- package/.worktrees/2c37b1d7/src/foreign-declared.js +155 -0
- package/.worktrees/2c37b1d7/src/fs-atomic.js +73 -0
- package/.worktrees/2c37b1d7/src/git-helper.js +150 -0
- package/.worktrees/2c37b1d7/src/hooks/claude-pre-tool-use.cjs +130 -0
- package/.worktrees/2c37b1d7/src/hooks/worktree-guard.js +892 -0
- package/.worktrees/2c37b1d7/src/index.js +2854 -0
- package/.worktrees/2c37b1d7/src/init.js +626 -0
- package/.worktrees/2c37b1d7/src/knowledge-match.js +231 -0
- package/.worktrees/2c37b1d7/src/local-detect.js +128 -0
- package/.worktrees/2c37b1d7/src/local-register.js +104 -0
- package/.worktrees/2c37b1d7/src/machine-interface.js +543 -0
- package/.worktrees/2c37b1d7/src/migrate.js +127 -0
- package/.worktrees/2c37b1d7/src/module-impact.js +166 -0
- package/.worktrees/2c37b1d7/src/module-resolve.js +222 -0
- package/.worktrees/2c37b1d7/src/modules.js +580 -0
- package/.worktrees/2c37b1d7/src/plan-adopt-waves.js +126 -0
- package/.worktrees/2c37b1d7/src/progress/change-registry.js +336 -0
- package/.worktrees/2c37b1d7/src/progress/consistency-doctor.js +355 -0
- package/.worktrees/2c37b1d7/src/progress/shared.js +36 -0
- package/.worktrees/2c37b1d7/src/progress/stage-machine.js +594 -0
- package/.worktrees/2c37b1d7/src/progress/step-store.js +265 -0
- package/.worktrees/2c37b1d7/src/progress.js +1304 -0
- package/.worktrees/2c37b1d7/src/quick-recommend.js +115 -0
- package/.worktrees/2c37b1d7/src/quicklog.js +883 -0
- package/.worktrees/2c37b1d7/src/review-tier.js +77 -0
- package/.worktrees/2c37b1d7/src/run/command.js +1641 -0
- package/.worktrees/2c37b1d7/src/run/complete-handlers.js +1552 -0
- package/.worktrees/2c37b1d7/src/run/complete.js +1259 -0
- package/.worktrees/2c37b1d7/src/run/concurrent-detect.js +156 -0
- package/.worktrees/2c37b1d7/src/run/gates.js +1111 -0
- package/.worktrees/2c37b1d7/src/run/multi-repo-context.js +208 -0
- package/.worktrees/2c37b1d7/src/run/next.js +128 -0
- package/.worktrees/2c37b1d7/src/run/prompt.js +843 -0
- package/.worktrees/2c37b1d7/src/run/quick-audit.js +186 -0
- package/.worktrees/2c37b1d7/src/run/scan-profile.js +269 -0
- package/.worktrees/2c37b1d7/src/run/shared.js +1562 -0
- package/.worktrees/2c37b1d7/src/run/stage.js +587 -0
- package/.worktrees/2c37b1d7/src/run.js +23 -0
- package/.worktrees/2c37b1d7/src/scan-diff.js +388 -0
- package/.worktrees/2c37b1d7/src/scan-postcheck.js +524 -0
- package/.worktrees/2c37b1d7/src/scan-staleness.js +95 -0
- package/.worktrees/2c37b1d7/src/setup.js +414 -0
- package/.worktrees/2c37b1d7/src/sillyhub-mcp/client.js +597 -0
- package/.worktrees/2c37b1d7/src/sillyhub-mcp/config.js +62 -0
- package/.worktrees/2c37b1d7/src/spec-dir-typo.js +50 -0
- package/.worktrees/2c37b1d7/src/spec-sync.js +358 -0
- package/.worktrees/2c37b1d7/src/stage-contract-engine.js +171 -0
- package/.worktrees/2c37b1d7/src/stage-contract-spec.js +551 -0
- package/.worktrees/2c37b1d7/src/stage-contract.js +948 -0
- package/.worktrees/2c37b1d7/src/stage-review.js +597 -0
- package/.worktrees/2c37b1d7/src/stages/archive.js +199 -0
- package/.worktrees/2c37b1d7/src/stages/brainstorm-auto.js +285 -0
- package/.worktrees/2c37b1d7/src/stages/brainstorm.js +624 -0
- package/.worktrees/2c37b1d7/src/stages/cmd-existence.js +145 -0
- package/.worktrees/2c37b1d7/src/stages/doctor.js +540 -0
- package/.worktrees/2c37b1d7/src/stages/execute.js +1277 -0
- package/.worktrees/2c37b1d7/src/stages/explore.js +43 -0
- package/.worktrees/2c37b1d7/src/stages/index.js +29 -0
- package/.worktrees/2c37b1d7/src/stages/knowledge.js +514 -0
- package/.worktrees/2c37b1d7/src/stages/plan-postcheck.js +1398 -0
- package/.worktrees/2c37b1d7/src/stages/plan.js +655 -0
- package/.worktrees/2c37b1d7/src/stages/quick.js +167 -0
- package/.worktrees/2c37b1d7/src/stages/scan.js +608 -0
- package/.worktrees/2c37b1d7/src/stages/status.js +64 -0
- package/.worktrees/2c37b1d7/src/stages/verify.js +246 -0
- package/.worktrees/2c37b1d7/src/sync.js +1470 -0
- package/.worktrees/2c37b1d7/src/task-review.js +1498 -0
- package/.worktrees/2c37b1d7/src/taskcard-placeholders.js +21 -0
- package/.worktrees/2c37b1d7/src/taskcard.js +250 -0
- package/.worktrees/2c37b1d7/src/verify-postcheck.js +1718 -0
- package/.worktrees/2c37b1d7/src/verify-probes.js +327 -0
- package/.worktrees/2c37b1d7/src/version.js +19 -0
- package/.worktrees/2c37b1d7/src/workflow.js +600 -0
- package/.worktrees/2c37b1d7/src/workspace.js +125 -0
- package/.worktrees/2c37b1d7/src/worktree-apply.js +1611 -0
- package/.worktrees/2c37b1d7/src/worktree-deps.js +668 -0
- package/.worktrees/2c37b1d7/src/worktree.js +1849 -0
- package/.worktrees/2c37b1d7/templates/claude-instruction.md +23 -0
- package/.worktrees/2c37b1d7/templates/prompts/taskcard-rules.md +29 -0
- package/.worktrees/2c37b1d7/templates/prompts/testcase-design.md +12 -0
- package/.worktrees/2c37b1d7/templates/prompts/verify-probes.md +32 -0
- package/.worktrees/2c37b1d7/templates/workflows/archive-impact.yaml +79 -0
- package/.worktrees/2c37b1d7/templates/workflows/scan-docs.yaml +132 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-archive/SKILL.md +87 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-auto/SKILL.md +93 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-commit/SKILL.md +67 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-continue/SKILL.md +47 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-execute/SKILL.md +214 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-explore/SKILL.md +102 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-export/SKILL.md +57 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-init/SKILL.md +177 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-plan/SKILL.md +156 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-quick/SKILL.md +116 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-resume/SKILL.md +70 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-scan/SKILL.md +79 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-state/SKILL.md +64 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-status/SKILL.md +54 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-verify/SKILL.md +87 -0
- package/.worktrees/542c4415/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
- package/.worktrees/542c4415/.gitattributes +2 -0
- package/.worktrees/542c4415/.husky/pre-push +20 -0
- package/.worktrees/542c4415/README.md +203 -0
- package/.worktrees/542c4415/SKILL.md +91 -0
- package/.worktrees/542c4415/architecture-analysis.md +448 -0
- package/.worktrees/542c4415/bin/sillyspec.js +2 -0
- package/.worktrees/542c4415/eval/README.md +86 -0
- package/.worktrees/542c4415/eval/eval.config.json +28 -0
- package/.worktrees/542c4415/eval/lib/adapters/cli.mjs +63 -0
- package/.worktrees/542c4415/eval/lib/adapters/dryrun.mjs +27 -0
- package/.worktrees/542c4415/eval/lib/config.mjs +82 -0
- package/.worktrees/542c4415/eval/lib/db.mjs +76 -0
- package/.worktrees/542c4415/eval/lib/report.mjs +120 -0
- package/.worktrees/542c4415/eval/lib/runner.mjs +157 -0
- package/.worktrees/542c4415/eval/lib/tasks.mjs +73 -0
- package/.worktrees/542c4415/eval/lib/util.mjs +107 -0
- package/.worktrees/542c4415/eval/lib/workdir.mjs +30 -0
- package/.worktrees/542c4415/eval/run.mjs +83 -0
- package/.worktrees/542c4415/eval/tasks/001-slugify/files/package.json +6 -0
- package/.worktrees/542c4415/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
- package/.worktrees/542c4415/eval/tasks/001-slugify/task.json +6 -0
- package/.worktrees/542c4415/eval/tasks/001-slugify/verify.mjs +28 -0
- package/.worktrees/542c4415/eval/tasks/002-each-day/files/package.json +6 -0
- package/.worktrees/542c4415/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
- package/.worktrees/542c4415/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
- package/.worktrees/542c4415/eval/tasks/002-each-day/task.json +6 -0
- package/.worktrees/542c4415/eval/tasks/002-each-day/verify.mjs +31 -0
- package/.worktrees/542c4415/eval/tasks/003-word-report/files/data/notes.txt +5 -0
- package/.worktrees/542c4415/eval/tasks/003-word-report/files/package.json +6 -0
- package/.worktrees/542c4415/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
- package/.worktrees/542c4415/eval/tasks/003-word-report/task.json +6 -0
- package/.worktrees/542c4415/eval/tasks/003-word-report/verify.mjs +38 -0
- package/.worktrees/542c4415/logo.jpg +0 -0
- package/.worktrees/542c4415/package-lock.json +977 -0
- package/.worktrees/542c4415/package.json +41 -0
- package/.worktrees/542c4415/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
- package/.worktrees/542c4415/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
- package/.worktrees/542c4415/packages/dashboard/dist/favicon.jpg +0 -0
- package/.worktrees/542c4415/packages/dashboard/dist/index.html +16 -0
- package/.worktrees/542c4415/packages/dashboard/dist/logo.jpg +0 -0
- package/.worktrees/542c4415/packages/dashboard/dist/prototype-dashboard.html +836 -0
- package/.worktrees/542c4415/packages/dashboard/dist/prototype-overview.html +256 -0
- package/.worktrees/542c4415/packages/dashboard/package.json +25 -0
- package/.worktrees/542c4415/packages/dashboard/server/executor.js +95 -0
- package/.worktrees/542c4415/packages/dashboard/server/index.js +679 -0
- package/.worktrees/542c4415/packages/dashboard/server/parser.js +526 -0
- package/.worktrees/542c4415/packages/dashboard/server/watcher.js +357 -0
- package/.worktrees/542c4415/src/agent-session-log.js +803 -0
- package/.worktrees/542c4415/src/change-list.js +290 -0
- package/.worktrees/542c4415/src/change-risk-profile.js +339 -0
- package/.worktrees/542c4415/src/check-primitives.js +65 -0
- package/.worktrees/542c4415/src/classify-change.js +109 -0
- package/.worktrees/542c4415/src/commit-suggest.js +202 -0
- package/.worktrees/542c4415/src/config-cat.js +88 -0
- package/.worktrees/542c4415/src/config-schema.js +328 -0
- package/.worktrees/542c4415/src/constants.js +97 -0
- package/.worktrees/542c4415/src/contract-matrix.js +533 -0
- package/.worktrees/542c4415/src/datetime.js +20 -0
- package/.worktrees/542c4415/src/db-engine.js +55 -0
- package/.worktrees/542c4415/src/db.js +381 -0
- package/.worktrees/542c4415/src/decision-distill.js +517 -0
- package/.worktrees/542c4415/src/dispatch/backends/local-agent.js +155 -0
- package/.worktrees/542c4415/src/dispatch/backends/sillyhub-mcp.js +245 -0
- package/.worktrees/542c4415/src/dispatch/probe.js +246 -0
- package/.worktrees/542c4415/src/dispatch/strategy.js +121 -0
- package/.worktrees/542c4415/src/docs-check.js +825 -0
- package/.worktrees/542c4415/src/docs-debt.js +393 -0
- package/.worktrees/542c4415/src/docs-gate.js +107 -0
- package/.worktrees/542c4415/src/doctor-diagnostics.js +1099 -0
- package/.worktrees/542c4415/src/endpoint-extractor.js +409 -0
- package/.worktrees/542c4415/src/foreign-declared.js +155 -0
- package/.worktrees/542c4415/src/fs-atomic.js +73 -0
- package/.worktrees/542c4415/src/git-helper.js +150 -0
- package/.worktrees/542c4415/src/hooks/claude-pre-tool-use.cjs +130 -0
- package/.worktrees/542c4415/src/hooks/worktree-guard.js +892 -0
- package/.worktrees/542c4415/src/index.js +2854 -0
- package/.worktrees/542c4415/src/init.js +626 -0
- package/.worktrees/542c4415/src/knowledge-match.js +231 -0
- package/.worktrees/542c4415/src/local-detect.js +128 -0
- package/.worktrees/542c4415/src/local-register.js +104 -0
- package/.worktrees/542c4415/src/machine-interface.js +543 -0
- package/.worktrees/542c4415/src/migrate.js +127 -0
- package/.worktrees/542c4415/src/module-impact.js +166 -0
- package/.worktrees/542c4415/src/module-resolve.js +222 -0
- package/.worktrees/542c4415/src/modules.js +580 -0
- package/.worktrees/542c4415/src/plan-adopt-waves.js +126 -0
- package/.worktrees/542c4415/src/progress/change-registry.js +336 -0
- package/.worktrees/542c4415/src/progress/consistency-doctor.js +355 -0
- package/.worktrees/542c4415/src/progress/shared.js +36 -0
- package/.worktrees/542c4415/src/progress/stage-machine.js +594 -0
- package/.worktrees/542c4415/src/progress/step-store.js +265 -0
- package/.worktrees/542c4415/src/progress.js +1304 -0
- package/.worktrees/542c4415/src/quick-recommend.js +115 -0
- package/.worktrees/542c4415/src/quicklog.js +883 -0
- package/.worktrees/542c4415/src/review-tier.js +77 -0
- package/.worktrees/542c4415/src/run/command.js +1641 -0
- package/.worktrees/542c4415/src/run/complete-handlers.js +1552 -0
- package/.worktrees/542c4415/src/run/complete.js +1259 -0
- package/.worktrees/542c4415/src/run/concurrent-detect.js +156 -0
- package/.worktrees/542c4415/src/run/gates.js +1111 -0
- package/.worktrees/542c4415/src/run/multi-repo-context.js +208 -0
- package/.worktrees/542c4415/src/run/next.js +128 -0
- package/.worktrees/542c4415/src/run/prompt.js +843 -0
- package/.worktrees/542c4415/src/run/quick-audit.js +186 -0
- package/.worktrees/542c4415/src/run/scan-profile.js +269 -0
- package/.worktrees/542c4415/src/run/shared.js +1562 -0
- package/.worktrees/542c4415/src/run/stage.js +587 -0
- package/.worktrees/542c4415/src/run.js +23 -0
- package/.worktrees/542c4415/src/scan-diff.js +388 -0
- package/.worktrees/542c4415/src/scan-postcheck.js +524 -0
- package/.worktrees/542c4415/src/scan-staleness.js +95 -0
- package/.worktrees/542c4415/src/setup.js +414 -0
- package/.worktrees/542c4415/src/sillyhub-mcp/client.js +597 -0
- package/.worktrees/542c4415/src/sillyhub-mcp/config.js +62 -0
- package/.worktrees/542c4415/src/spec-dir-typo.js +50 -0
- package/.worktrees/542c4415/src/spec-sync.js +358 -0
- package/.worktrees/542c4415/src/stage-contract-engine.js +171 -0
- package/.worktrees/542c4415/src/stage-contract-spec.js +551 -0
- package/.worktrees/542c4415/src/stage-contract.js +948 -0
- package/.worktrees/542c4415/src/stage-review.js +597 -0
- package/.worktrees/542c4415/src/stages/archive.js +199 -0
- package/.worktrees/542c4415/src/stages/brainstorm-auto.js +285 -0
- package/.worktrees/542c4415/src/stages/brainstorm.js +624 -0
- package/.worktrees/542c4415/src/stages/cmd-existence.js +145 -0
- package/.worktrees/542c4415/src/stages/doctor.js +540 -0
- package/.worktrees/542c4415/src/stages/execute.js +1277 -0
- package/.worktrees/542c4415/src/stages/explore.js +43 -0
- package/.worktrees/542c4415/src/stages/index.js +29 -0
- package/.worktrees/542c4415/src/stages/knowledge.js +514 -0
- package/.worktrees/542c4415/src/stages/plan-postcheck.js +1398 -0
- package/.worktrees/542c4415/src/stages/plan.js +655 -0
- package/.worktrees/542c4415/src/stages/quick.js +167 -0
- package/.worktrees/542c4415/src/stages/scan.js +608 -0
- package/.worktrees/542c4415/src/stages/status.js +64 -0
- package/.worktrees/542c4415/src/stages/verify.js +246 -0
- package/.worktrees/542c4415/src/sync.js +1470 -0
- package/.worktrees/542c4415/src/task-review.js +1498 -0
- package/.worktrees/542c4415/src/taskcard-placeholders.js +21 -0
- package/.worktrees/542c4415/src/taskcard.js +250 -0
- package/.worktrees/542c4415/src/verify-postcheck.js +1718 -0
- package/.worktrees/542c4415/src/verify-probes.js +327 -0
- package/.worktrees/542c4415/src/version.js +19 -0
- package/.worktrees/542c4415/src/workflow.js +600 -0
- package/.worktrees/542c4415/src/workspace.js +125 -0
- package/.worktrees/542c4415/src/worktree-apply.js +1611 -0
- package/.worktrees/542c4415/src/worktree-deps.js +668 -0
- package/.worktrees/542c4415/src/worktree.js +1849 -0
- package/.worktrees/542c4415/templates/claude-instruction.md +23 -0
- package/.worktrees/542c4415/templates/prompts/taskcard-rules.md +29 -0
- package/.worktrees/542c4415/templates/prompts/testcase-design.md +12 -0
- package/.worktrees/542c4415/templates/prompts/verify-probes.md +32 -0
- package/.worktrees/542c4415/templates/workflows/archive-impact.yaml +79 -0
- package/.worktrees/542c4415/templates/workflows/scan-docs.yaml +132 -0
- package/.worktrees/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/.worktrees/c1eae35e/.claude/skills/sillyspec-archive/SKILL.md +87 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-auto/SKILL.md +93 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-commit/SKILL.md +67 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-continue/SKILL.md +47 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-execute/SKILL.md +214 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-explore/SKILL.md +102 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-export/SKILL.md +57 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-init/SKILL.md +177 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-plan/SKILL.md +156 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-quick/SKILL.md +116 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-resume/SKILL.md +70 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-scan/SKILL.md +79 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-state/SKILL.md +64 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-status/SKILL.md +54 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-verify/SKILL.md +87 -0
- package/.worktrees/c1eae35e/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
- package/.worktrees/c1eae35e/.gitattributes +2 -0
- package/.worktrees/c1eae35e/.husky/pre-push +20 -0
- package/.worktrees/c1eae35e/README.md +203 -0
- package/.worktrees/c1eae35e/SKILL.md +91 -0
- package/.worktrees/c1eae35e/architecture-analysis.md +448 -0
- package/.worktrees/c1eae35e/bin/sillyspec.js +2 -0
- package/.worktrees/c1eae35e/eval/README.md +86 -0
- package/.worktrees/c1eae35e/eval/eval.config.json +28 -0
- package/.worktrees/c1eae35e/eval/lib/adapters/cli.mjs +63 -0
- package/.worktrees/c1eae35e/eval/lib/adapters/dryrun.mjs +27 -0
- package/.worktrees/c1eae35e/eval/lib/config.mjs +82 -0
- package/.worktrees/c1eae35e/eval/lib/db.mjs +76 -0
- package/.worktrees/c1eae35e/eval/lib/report.mjs +120 -0
- package/.worktrees/c1eae35e/eval/lib/runner.mjs +157 -0
- package/.worktrees/c1eae35e/eval/lib/tasks.mjs +73 -0
- package/.worktrees/c1eae35e/eval/lib/util.mjs +107 -0
- package/.worktrees/c1eae35e/eval/lib/workdir.mjs +30 -0
- package/.worktrees/c1eae35e/eval/run.mjs +83 -0
- package/.worktrees/c1eae35e/eval/tasks/001-slugify/files/package.json +6 -0
- package/.worktrees/c1eae35e/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
- package/.worktrees/c1eae35e/eval/tasks/001-slugify/task.json +6 -0
- package/.worktrees/c1eae35e/eval/tasks/001-slugify/verify.mjs +28 -0
- package/.worktrees/c1eae35e/eval/tasks/002-each-day/files/package.json +6 -0
- package/.worktrees/c1eae35e/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
- package/.worktrees/c1eae35e/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
- package/.worktrees/c1eae35e/eval/tasks/002-each-day/task.json +6 -0
- package/.worktrees/c1eae35e/eval/tasks/002-each-day/verify.mjs +31 -0
- package/.worktrees/c1eae35e/eval/tasks/003-word-report/files/data/notes.txt +5 -0
- package/.worktrees/c1eae35e/eval/tasks/003-word-report/files/package.json +6 -0
- package/.worktrees/c1eae35e/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
- package/.worktrees/c1eae35e/eval/tasks/003-word-report/task.json +6 -0
- package/.worktrees/c1eae35e/eval/tasks/003-word-report/verify.mjs +38 -0
- package/.worktrees/c1eae35e/logo.jpg +0 -0
- package/.worktrees/c1eae35e/package-lock.json +977 -0
- package/.worktrees/c1eae35e/package.json +41 -0
- package/.worktrees/c1eae35e/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
- package/.worktrees/c1eae35e/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
- package/.worktrees/c1eae35e/packages/dashboard/dist/favicon.jpg +0 -0
- package/.worktrees/c1eae35e/packages/dashboard/dist/index.html +16 -0
- package/.worktrees/c1eae35e/packages/dashboard/dist/logo.jpg +0 -0
- package/.worktrees/c1eae35e/packages/dashboard/dist/prototype-dashboard.html +836 -0
- package/.worktrees/c1eae35e/packages/dashboard/dist/prototype-overview.html +256 -0
- package/.worktrees/c1eae35e/packages/dashboard/package.json +25 -0
- package/.worktrees/c1eae35e/packages/dashboard/server/executor.js +95 -0
- package/.worktrees/c1eae35e/packages/dashboard/server/index.js +679 -0
- package/.worktrees/c1eae35e/packages/dashboard/server/parser.js +526 -0
- package/.worktrees/c1eae35e/packages/dashboard/server/watcher.js +357 -0
- package/.worktrees/c1eae35e/src/agent-session-log.js +803 -0
- package/.worktrees/c1eae35e/src/change-list.js +290 -0
- package/.worktrees/c1eae35e/src/change-risk-profile.js +339 -0
- package/.worktrees/c1eae35e/src/check-primitives.js +65 -0
- package/.worktrees/c1eae35e/src/classify-change.js +109 -0
- package/.worktrees/c1eae35e/src/commit-suggest.js +202 -0
- package/.worktrees/c1eae35e/src/config-cat.js +88 -0
- package/.worktrees/c1eae35e/src/config-schema.js +328 -0
- package/.worktrees/c1eae35e/src/constants.js +97 -0
- package/.worktrees/c1eae35e/src/contract-matrix.js +533 -0
- package/.worktrees/c1eae35e/src/datetime.js +20 -0
- package/.worktrees/c1eae35e/src/db-engine.js +55 -0
- package/.worktrees/c1eae35e/src/db.js +381 -0
- package/.worktrees/c1eae35e/src/decision-distill.js +517 -0
- package/.worktrees/c1eae35e/src/dispatch/backends/local-agent.js +155 -0
- package/.worktrees/c1eae35e/src/dispatch/backends/sillyhub-mcp.js +245 -0
- package/.worktrees/c1eae35e/src/dispatch/probe.js +246 -0
- package/.worktrees/c1eae35e/src/dispatch/strategy.js +121 -0
- package/.worktrees/c1eae35e/src/docs-check.js +825 -0
- package/.worktrees/c1eae35e/src/docs-debt.js +393 -0
- package/.worktrees/c1eae35e/src/docs-gate.js +107 -0
- package/.worktrees/c1eae35e/src/doctor-diagnostics.js +1099 -0
- package/.worktrees/c1eae35e/src/endpoint-extractor.js +409 -0
- package/.worktrees/c1eae35e/src/foreign-declared.js +155 -0
- package/.worktrees/c1eae35e/src/fs-atomic.js +73 -0
- package/.worktrees/c1eae35e/src/git-helper.js +150 -0
- package/.worktrees/c1eae35e/src/hooks/claude-pre-tool-use.cjs +130 -0
- package/.worktrees/c1eae35e/src/hooks/worktree-guard.js +892 -0
- package/.worktrees/c1eae35e/src/index.js +2854 -0
- package/.worktrees/c1eae35e/src/init.js +626 -0
- package/.worktrees/c1eae35e/src/knowledge-match.js +231 -0
- package/.worktrees/c1eae35e/src/local-detect.js +128 -0
- package/.worktrees/c1eae35e/src/local-register.js +104 -0
- package/.worktrees/c1eae35e/src/machine-interface.js +543 -0
- package/.worktrees/c1eae35e/src/migrate.js +127 -0
- package/.worktrees/c1eae35e/src/module-impact.js +166 -0
- package/.worktrees/c1eae35e/src/module-resolve.js +222 -0
- package/.worktrees/c1eae35e/src/modules.js +580 -0
- package/.worktrees/c1eae35e/src/plan-adopt-waves.js +126 -0
- package/.worktrees/c1eae35e/src/progress/change-registry.js +336 -0
- package/.worktrees/c1eae35e/src/progress/consistency-doctor.js +355 -0
- package/.worktrees/c1eae35e/src/progress/shared.js +36 -0
- package/.worktrees/c1eae35e/src/progress/stage-machine.js +594 -0
- package/.worktrees/c1eae35e/src/progress/step-store.js +265 -0
- package/.worktrees/c1eae35e/src/progress.js +1304 -0
- package/.worktrees/c1eae35e/src/quick-recommend.js +115 -0
- package/.worktrees/c1eae35e/src/quicklog.js +883 -0
- package/.worktrees/c1eae35e/src/review-tier.js +77 -0
- package/.worktrees/c1eae35e/src/run/command.js +1641 -0
- package/.worktrees/c1eae35e/src/run/complete-handlers.js +1552 -0
- package/.worktrees/c1eae35e/src/run/complete.js +1259 -0
- package/.worktrees/c1eae35e/src/run/concurrent-detect.js +156 -0
- package/.worktrees/c1eae35e/src/run/gates.js +1111 -0
- package/.worktrees/c1eae35e/src/run/multi-repo-context.js +208 -0
- package/.worktrees/c1eae35e/src/run/next.js +128 -0
- package/.worktrees/c1eae35e/src/run/prompt.js +843 -0
- package/.worktrees/c1eae35e/src/run/quick-audit.js +186 -0
- package/.worktrees/c1eae35e/src/run/scan-profile.js +269 -0
- package/.worktrees/c1eae35e/src/run/shared.js +1562 -0
- package/.worktrees/c1eae35e/src/run/stage.js +587 -0
- package/.worktrees/c1eae35e/src/run.js +23 -0
- package/.worktrees/c1eae35e/src/scan-diff.js +388 -0
- package/.worktrees/c1eae35e/src/scan-postcheck.js +524 -0
- package/.worktrees/c1eae35e/src/scan-staleness.js +95 -0
- package/.worktrees/c1eae35e/src/setup.js +414 -0
- package/.worktrees/c1eae35e/src/sillyhub-mcp/client.js +597 -0
- package/.worktrees/c1eae35e/src/sillyhub-mcp/config.js +62 -0
- package/.worktrees/c1eae35e/src/spec-dir-typo.js +50 -0
- package/.worktrees/c1eae35e/src/spec-sync.js +358 -0
- package/.worktrees/c1eae35e/src/stage-contract-engine.js +171 -0
- package/.worktrees/c1eae35e/src/stage-contract-spec.js +551 -0
- package/.worktrees/c1eae35e/src/stage-contract.js +948 -0
- package/.worktrees/c1eae35e/src/stage-review.js +597 -0
- package/.worktrees/c1eae35e/src/stages/archive.js +199 -0
- package/.worktrees/c1eae35e/src/stages/brainstorm-auto.js +285 -0
- package/.worktrees/c1eae35e/src/stages/brainstorm.js +624 -0
- package/.worktrees/c1eae35e/src/stages/cmd-existence.js +145 -0
- package/.worktrees/c1eae35e/src/stages/doctor.js +540 -0
- package/.worktrees/c1eae35e/src/stages/execute.js +1277 -0
- package/.worktrees/c1eae35e/src/stages/explore.js +43 -0
- package/.worktrees/c1eae35e/src/stages/index.js +29 -0
- package/.worktrees/c1eae35e/src/stages/knowledge.js +514 -0
- package/.worktrees/c1eae35e/src/stages/plan-postcheck.js +1398 -0
- package/.worktrees/c1eae35e/src/stages/plan.js +655 -0
- package/.worktrees/c1eae35e/src/stages/quick.js +167 -0
- package/.worktrees/c1eae35e/src/stages/scan.js +608 -0
- package/.worktrees/c1eae35e/src/stages/status.js +64 -0
- package/.worktrees/c1eae35e/src/stages/verify.js +246 -0
- package/.worktrees/c1eae35e/src/sync.js +1470 -0
- package/.worktrees/c1eae35e/src/task-review.js +1498 -0
- package/.worktrees/c1eae35e/src/taskcard-placeholders.js +21 -0
- package/.worktrees/c1eae35e/src/taskcard.js +250 -0
- package/.worktrees/c1eae35e/src/verify-postcheck.js +1718 -0
- package/.worktrees/c1eae35e/src/verify-probes.js +327 -0
- package/.worktrees/c1eae35e/src/version.js +19 -0
- package/.worktrees/c1eae35e/src/workflow.js +600 -0
- package/.worktrees/c1eae35e/src/workspace.js +125 -0
- package/.worktrees/c1eae35e/src/worktree-apply.js +1611 -0
- package/.worktrees/c1eae35e/src/worktree-deps.js +668 -0
- package/.worktrees/c1eae35e/src/worktree.js +1849 -0
- package/.worktrees/c1eae35e/templates/claude-instruction.md +23 -0
- package/.worktrees/c1eae35e/templates/prompts/taskcard-rules.md +29 -0
- package/.worktrees/c1eae35e/templates/prompts/testcase-design.md +12 -0
- package/.worktrees/c1eae35e/templates/prompts/verify-probes.md +32 -0
- package/.worktrees/c1eae35e/templates/workflows/archive-impact.yaml +79 -0
- package/.worktrees/c1eae35e/templates/workflows/scan-docs.yaml +132 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-archive/SKILL.md +87 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-auto/SKILL.md +93 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-commit/SKILL.md +67 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-continue/SKILL.md +47 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-execute/SKILL.md +214 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-explore/SKILL.md +102 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-export/SKILL.md +57 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-init/SKILL.md +177 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-plan/SKILL.md +156 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-propose/SKILL.md +87 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-quick/SKILL.md +116 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-resume/SKILL.md +70 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-scan/SKILL.md +79 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-state/SKILL.md +64 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-status/SKILL.md +54 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-verify/SKILL.md +87 -0
- package/.worktrees/dafc71ad/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
- package/.worktrees/dafc71ad/.gitattributes +2 -0
- package/.worktrees/dafc71ad/.husky/pre-push +20 -0
- package/.worktrees/dafc71ad/README.md +203 -0
- package/.worktrees/dafc71ad/SKILL.md +91 -0
- package/.worktrees/dafc71ad/analysis.md +366 -0
- package/.worktrees/dafc71ad/architecture-analysis.md +448 -0
- package/.worktrees/dafc71ad/bin/sillyspec.js +2 -0
- package/.worktrees/dafc71ad/eval/README.md +86 -0
- package/.worktrees/dafc71ad/eval/eval.config.json +28 -0
- package/.worktrees/dafc71ad/eval/lib/adapters/cli.mjs +63 -0
- package/.worktrees/dafc71ad/eval/lib/adapters/dryrun.mjs +27 -0
- package/.worktrees/dafc71ad/eval/lib/config.mjs +82 -0
- package/.worktrees/dafc71ad/eval/lib/db.mjs +76 -0
- package/.worktrees/dafc71ad/eval/lib/report.mjs +120 -0
- package/.worktrees/dafc71ad/eval/lib/runner.mjs +157 -0
- package/.worktrees/dafc71ad/eval/lib/tasks.mjs +73 -0
- package/.worktrees/dafc71ad/eval/lib/util.mjs +107 -0
- package/.worktrees/dafc71ad/eval/lib/workdir.mjs +30 -0
- package/.worktrees/dafc71ad/eval/run.mjs +83 -0
- package/.worktrees/dafc71ad/eval/tasks/001-slugify/files/package.json +6 -0
- package/.worktrees/dafc71ad/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
- package/.worktrees/dafc71ad/eval/tasks/001-slugify/task.json +6 -0
- package/.worktrees/dafc71ad/eval/tasks/001-slugify/verify.mjs +28 -0
- package/.worktrees/dafc71ad/eval/tasks/002-each-day/files/package.json +6 -0
- package/.worktrees/dafc71ad/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
- package/.worktrees/dafc71ad/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
- package/.worktrees/dafc71ad/eval/tasks/002-each-day/task.json +6 -0
- package/.worktrees/dafc71ad/eval/tasks/002-each-day/verify.mjs +31 -0
- package/.worktrees/dafc71ad/eval/tasks/003-word-report/files/data/notes.txt +5 -0
- package/.worktrees/dafc71ad/eval/tasks/003-word-report/files/package.json +6 -0
- package/.worktrees/dafc71ad/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
- package/.worktrees/dafc71ad/eval/tasks/003-word-report/task.json +6 -0
- package/.worktrees/dafc71ad/eval/tasks/003-word-report/verify.mjs +38 -0
- package/.worktrees/dafc71ad/logo.jpg +0 -0
- package/.worktrees/dafc71ad/package-lock.json +977 -0
- package/.worktrees/dafc71ad/package.json +41 -0
- package/.worktrees/dafc71ad/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
- package/.worktrees/dafc71ad/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
- package/.worktrees/dafc71ad/packages/dashboard/dist/favicon.jpg +0 -0
- package/.worktrees/dafc71ad/packages/dashboard/dist/index.html +16 -0
- package/.worktrees/dafc71ad/packages/dashboard/dist/logo.jpg +0 -0
- package/.worktrees/dafc71ad/packages/dashboard/dist/prototype-dashboard.html +836 -0
- package/.worktrees/dafc71ad/packages/dashboard/dist/prototype-overview.html +256 -0
- package/.worktrees/dafc71ad/packages/dashboard/package.json +25 -0
- package/.worktrees/dafc71ad/packages/dashboard/server/executor.js +95 -0
- package/.worktrees/dafc71ad/packages/dashboard/server/index.js +679 -0
- package/.worktrees/dafc71ad/packages/dashboard/server/parser.js +526 -0
- package/.worktrees/dafc71ad/packages/dashboard/server/watcher.js +357 -0
- package/.worktrees/dafc71ad/src/agent-session-log.js +803 -0
- package/.worktrees/dafc71ad/src/change-list.js +290 -0
- package/.worktrees/dafc71ad/src/change-risk-profile.js +339 -0
- package/.worktrees/dafc71ad/src/check-primitives.js +65 -0
- package/.worktrees/dafc71ad/src/classify-change.js +109 -0
- package/.worktrees/dafc71ad/src/commit-suggest.js +202 -0
- package/.worktrees/dafc71ad/src/config-cat.js +88 -0
- package/.worktrees/dafc71ad/src/config-schema.js +328 -0
- package/.worktrees/dafc71ad/src/constants.js +97 -0
- package/.worktrees/dafc71ad/src/contract-matrix.js +533 -0
- package/.worktrees/dafc71ad/src/datetime.js +20 -0
- package/.worktrees/dafc71ad/src/db-engine.js +55 -0
- package/.worktrees/dafc71ad/src/db.js +381 -0
- package/.worktrees/dafc71ad/src/decision-distill.js +517 -0
- package/.worktrees/dafc71ad/src/dispatch/backends/local-agent.js +155 -0
- package/.worktrees/dafc71ad/src/dispatch/backends/sillyhub-mcp.js +245 -0
- package/.worktrees/dafc71ad/src/dispatch/probe.js +246 -0
- package/.worktrees/dafc71ad/src/dispatch/strategy.js +121 -0
- package/.worktrees/dafc71ad/src/docs-check.js +825 -0
- package/.worktrees/dafc71ad/src/docs-debt.js +393 -0
- package/.worktrees/dafc71ad/src/docs-gate.js +107 -0
- package/.worktrees/dafc71ad/src/doctor-diagnostics.js +1099 -0
- package/.worktrees/dafc71ad/src/endpoint-extractor.js +409 -0
- package/.worktrees/dafc71ad/src/foreign-declared.js +155 -0
- package/.worktrees/dafc71ad/src/fs-atomic.js +73 -0
- package/.worktrees/dafc71ad/src/git-helper.js +150 -0
- package/.worktrees/dafc71ad/src/hooks/claude-pre-tool-use.cjs +130 -0
- package/.worktrees/dafc71ad/src/hooks/worktree-guard.js +892 -0
- package/.worktrees/dafc71ad/src/index.js +2854 -0
- package/.worktrees/dafc71ad/src/init.js +626 -0
- package/.worktrees/dafc71ad/src/knowledge-match.js +231 -0
- package/.worktrees/dafc71ad/src/local-detect.js +128 -0
- package/.worktrees/dafc71ad/src/local-register.js +104 -0
- package/.worktrees/dafc71ad/src/machine-interface.js +543 -0
- package/.worktrees/dafc71ad/src/migrate.js +127 -0
- package/.worktrees/dafc71ad/src/module-impact.js +166 -0
- package/.worktrees/dafc71ad/src/module-resolve.js +222 -0
- package/.worktrees/dafc71ad/src/modules.js +580 -0
- package/.worktrees/dafc71ad/src/plan-adopt-waves.js +126 -0
- package/.worktrees/dafc71ad/src/progress/change-registry.js +336 -0
- package/.worktrees/dafc71ad/src/progress/consistency-doctor.js +355 -0
- package/.worktrees/dafc71ad/src/progress/shared.js +36 -0
- package/.worktrees/dafc71ad/src/progress/stage-machine.js +594 -0
- package/.worktrees/dafc71ad/src/progress/step-store.js +265 -0
- package/.worktrees/dafc71ad/src/progress.js +1304 -0
- package/.worktrees/dafc71ad/src/quick-recommend.js +115 -0
- package/.worktrees/dafc71ad/src/quicklog.js +883 -0
- package/.worktrees/dafc71ad/src/review-tier.js +77 -0
- package/.worktrees/dafc71ad/src/run/command.js +1641 -0
- package/.worktrees/dafc71ad/src/run/complete-handlers.js +1552 -0
- package/.worktrees/dafc71ad/src/run/complete.js +1259 -0
- package/.worktrees/dafc71ad/src/run/concurrent-detect.js +156 -0
- package/.worktrees/dafc71ad/src/run/gates.js +1111 -0
- package/.worktrees/dafc71ad/src/run/multi-repo-context.js +208 -0
- package/.worktrees/dafc71ad/src/run/next.js +128 -0
- package/.worktrees/dafc71ad/src/run/prompt.js +843 -0
- package/.worktrees/dafc71ad/src/run/quick-audit.js +186 -0
- package/.worktrees/dafc71ad/src/run/scan-profile.js +269 -0
- package/.worktrees/dafc71ad/src/run/shared.js +1562 -0
- package/.worktrees/dafc71ad/src/run/stage.js +587 -0
- package/.worktrees/dafc71ad/src/run.js +23 -0
- package/.worktrees/dafc71ad/src/scan-diff.js +388 -0
- package/.worktrees/dafc71ad/src/scan-postcheck.js +524 -0
- package/.worktrees/dafc71ad/src/scan-staleness.js +95 -0
- package/.worktrees/dafc71ad/src/setup.js +414 -0
- package/.worktrees/dafc71ad/src/sillyhub-mcp/client.js +597 -0
- package/.worktrees/dafc71ad/src/sillyhub-mcp/config.js +62 -0
- package/.worktrees/dafc71ad/src/spec-dir-typo.js +50 -0
- package/.worktrees/dafc71ad/src/spec-sync.js +358 -0
- package/.worktrees/dafc71ad/src/stage-contract-engine.js +171 -0
- package/.worktrees/dafc71ad/src/stage-contract-spec.js +551 -0
- package/.worktrees/dafc71ad/src/stage-contract.js +948 -0
- package/.worktrees/dafc71ad/src/stage-review.js +597 -0
- package/.worktrees/dafc71ad/src/stages/archive.js +199 -0
- package/.worktrees/dafc71ad/src/stages/brainstorm-auto.js +285 -0
- package/.worktrees/dafc71ad/src/stages/brainstorm.js +624 -0
- package/.worktrees/dafc71ad/src/stages/cmd-existence.js +145 -0
- package/.worktrees/dafc71ad/src/stages/doctor.js +540 -0
- package/.worktrees/dafc71ad/src/stages/execute.js +1277 -0
- package/.worktrees/dafc71ad/src/stages/explore.js +43 -0
- package/.worktrees/dafc71ad/src/stages/index.js +29 -0
- package/.worktrees/dafc71ad/src/stages/knowledge.js +514 -0
- package/.worktrees/dafc71ad/src/stages/plan-postcheck.js +1398 -0
- package/.worktrees/dafc71ad/src/stages/plan.js +655 -0
- package/.worktrees/dafc71ad/src/stages/quick.js +167 -0
- package/.worktrees/dafc71ad/src/stages/scan.js +608 -0
- package/.worktrees/dafc71ad/src/stages/status.js +64 -0
- package/.worktrees/dafc71ad/src/stages/verify.js +246 -0
- package/.worktrees/dafc71ad/src/sync.js +1470 -0
- package/.worktrees/dafc71ad/src/task-review.js +1498 -0
- package/.worktrees/dafc71ad/src/taskcard-placeholders.js +21 -0
- package/.worktrees/dafc71ad/src/taskcard.js +250 -0
- package/.worktrees/dafc71ad/src/verify-postcheck.js +1718 -0
- package/.worktrees/dafc71ad/src/verify-probes.js +327 -0
- package/.worktrees/dafc71ad/src/version.js +19 -0
- package/.worktrees/dafc71ad/src/workflow.js +600 -0
- package/.worktrees/dafc71ad/src/workspace.js +125 -0
- package/.worktrees/dafc71ad/src/worktree-apply.js +1611 -0
- package/.worktrees/dafc71ad/src/worktree-deps.js +668 -0
- package/.worktrees/dafc71ad/src/worktree.js +1849 -0
- package/.worktrees/dafc71ad/templates/claude-instruction.md +23 -0
- package/.worktrees/dafc71ad/templates/prompts/taskcard-rules.md +29 -0
- package/.worktrees/dafc71ad/templates/prompts/testcase-design.md +12 -0
- package/.worktrees/dafc71ad/templates/prompts/verify-probes.md +32 -0
- package/.worktrees/dafc71ad/templates/workflows/archive-impact.yaml +79 -0
- package/.worktrees/dafc71ad/templates/workflows/scan-docs.yaml +132 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-archive/SKILL.md +87 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-auto/SKILL.md +93 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-commit/SKILL.md +67 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-continue/SKILL.md +47 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-execute/SKILL.md +214 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-explore/SKILL.md +102 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-export/SKILL.md +57 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-init/SKILL.md +177 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-plan/SKILL.md +156 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-propose/SKILL.md +87 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-quick/SKILL.md +116 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-resume/SKILL.md +70 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-scan/SKILL.md +79 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-state/SKILL.md +64 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-status/SKILL.md +54 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-verify/SKILL.md +87 -0
- package/.worktrees/e58fcc4c/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
- package/.worktrees/e58fcc4c/.gitattributes +2 -0
- package/.worktrees/e58fcc4c/.husky/pre-push +20 -0
- package/.worktrees/e58fcc4c/README.md +203 -0
- package/.worktrees/e58fcc4c/SKILL.md +91 -0
- package/.worktrees/e58fcc4c/architecture-analysis.md +503 -0
- package/.worktrees/e58fcc4c/bin/sillyspec.js +2 -0
- package/.worktrees/e58fcc4c/eval/README.md +86 -0
- package/.worktrees/e58fcc4c/eval/eval.config.json +28 -0
- package/.worktrees/e58fcc4c/eval/lib/adapters/cli.mjs +63 -0
- package/.worktrees/e58fcc4c/eval/lib/adapters/dryrun.mjs +27 -0
- package/.worktrees/e58fcc4c/eval/lib/config.mjs +82 -0
- package/.worktrees/e58fcc4c/eval/lib/db.mjs +76 -0
- package/.worktrees/e58fcc4c/eval/lib/report.mjs +120 -0
- package/.worktrees/e58fcc4c/eval/lib/runner.mjs +157 -0
- package/.worktrees/e58fcc4c/eval/lib/tasks.mjs +73 -0
- package/.worktrees/e58fcc4c/eval/lib/util.mjs +107 -0
- package/.worktrees/e58fcc4c/eval/lib/workdir.mjs +30 -0
- package/.worktrees/e58fcc4c/eval/run.mjs +83 -0
- package/.worktrees/e58fcc4c/eval/tasks/001-slugify/files/package.json +6 -0
- package/.worktrees/e58fcc4c/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
- package/.worktrees/e58fcc4c/eval/tasks/001-slugify/task.json +6 -0
- package/.worktrees/e58fcc4c/eval/tasks/001-slugify/verify.mjs +28 -0
- package/.worktrees/e58fcc4c/eval/tasks/002-each-day/files/package.json +6 -0
- package/.worktrees/e58fcc4c/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
- package/.worktrees/e58fcc4c/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
- package/.worktrees/e58fcc4c/eval/tasks/002-each-day/task.json +6 -0
- package/.worktrees/e58fcc4c/eval/tasks/002-each-day/verify.mjs +31 -0
- package/.worktrees/e58fcc4c/eval/tasks/003-word-report/files/data/notes.txt +5 -0
- package/.worktrees/e58fcc4c/eval/tasks/003-word-report/files/package.json +6 -0
- package/.worktrees/e58fcc4c/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
- package/.worktrees/e58fcc4c/eval/tasks/003-word-report/task.json +6 -0
- package/.worktrees/e58fcc4c/eval/tasks/003-word-report/verify.mjs +38 -0
- package/.worktrees/e58fcc4c/logo.jpg +0 -0
- package/.worktrees/e58fcc4c/package-lock.json +977 -0
- package/.worktrees/e58fcc4c/package.json +41 -0
- package/.worktrees/e58fcc4c/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
- package/.worktrees/e58fcc4c/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
- package/.worktrees/e58fcc4c/packages/dashboard/dist/favicon.jpg +0 -0
- package/.worktrees/e58fcc4c/packages/dashboard/dist/index.html +16 -0
- package/.worktrees/e58fcc4c/packages/dashboard/dist/logo.jpg +0 -0
- package/.worktrees/e58fcc4c/packages/dashboard/dist/prototype-dashboard.html +836 -0
- package/.worktrees/e58fcc4c/packages/dashboard/dist/prototype-overview.html +256 -0
- package/.worktrees/e58fcc4c/packages/dashboard/package.json +25 -0
- package/.worktrees/e58fcc4c/packages/dashboard/server/executor.js +95 -0
- package/.worktrees/e58fcc4c/packages/dashboard/server/index.js +679 -0
- package/.worktrees/e58fcc4c/packages/dashboard/server/parser.js +526 -0
- package/.worktrees/e58fcc4c/packages/dashboard/server/watcher.js +357 -0
- package/.worktrees/e58fcc4c/src/agent-session-log.js +803 -0
- package/.worktrees/e58fcc4c/src/change-list.js +290 -0
- package/.worktrees/e58fcc4c/src/change-risk-profile.js +339 -0
- package/.worktrees/e58fcc4c/src/check-primitives.js +65 -0
- package/.worktrees/e58fcc4c/src/classify-change.js +109 -0
- package/.worktrees/e58fcc4c/src/commit-suggest.js +202 -0
- package/.worktrees/e58fcc4c/src/config-cat.js +88 -0
- package/.worktrees/e58fcc4c/src/config-schema.js +328 -0
- package/.worktrees/e58fcc4c/src/constants.js +97 -0
- package/.worktrees/e58fcc4c/src/contract-matrix.js +533 -0
- package/.worktrees/e58fcc4c/src/datetime.js +20 -0
- package/.worktrees/e58fcc4c/src/db-engine.js +55 -0
- package/.worktrees/e58fcc4c/src/db.js +381 -0
- package/.worktrees/e58fcc4c/src/decision-distill.js +517 -0
- package/.worktrees/e58fcc4c/src/dispatch/backends/local-agent.js +155 -0
- package/.worktrees/e58fcc4c/src/dispatch/backends/sillyhub-mcp.js +245 -0
- package/.worktrees/e58fcc4c/src/dispatch/probe.js +246 -0
- package/.worktrees/e58fcc4c/src/dispatch/strategy.js +121 -0
- package/.worktrees/e58fcc4c/src/docs-check.js +825 -0
- package/.worktrees/e58fcc4c/src/docs-debt.js +393 -0
- package/.worktrees/e58fcc4c/src/docs-gate.js +107 -0
- package/.worktrees/e58fcc4c/src/doctor-diagnostics.js +1099 -0
- package/.worktrees/e58fcc4c/src/endpoint-extractor.js +409 -0
- package/.worktrees/e58fcc4c/src/foreign-declared.js +155 -0
- package/.worktrees/e58fcc4c/src/fs-atomic.js +73 -0
- package/.worktrees/e58fcc4c/src/git-helper.js +150 -0
- package/.worktrees/e58fcc4c/src/hooks/claude-pre-tool-use.cjs +130 -0
- package/.worktrees/e58fcc4c/src/hooks/worktree-guard.js +892 -0
- package/.worktrees/e58fcc4c/src/index.js +2854 -0
- package/.worktrees/e58fcc4c/src/init.js +626 -0
- package/.worktrees/e58fcc4c/src/knowledge-match.js +231 -0
- package/.worktrees/e58fcc4c/src/local-detect.js +128 -0
- package/.worktrees/e58fcc4c/src/local-register.js +104 -0
- package/.worktrees/e58fcc4c/src/machine-interface.js +543 -0
- package/.worktrees/e58fcc4c/src/migrate.js +127 -0
- package/.worktrees/e58fcc4c/src/module-impact.js +166 -0
- package/.worktrees/e58fcc4c/src/module-resolve.js +222 -0
- package/.worktrees/e58fcc4c/src/modules.js +580 -0
- package/.worktrees/e58fcc4c/src/plan-adopt-waves.js +126 -0
- package/.worktrees/e58fcc4c/src/progress/change-registry.js +336 -0
- package/.worktrees/e58fcc4c/src/progress/consistency-doctor.js +355 -0
- package/.worktrees/e58fcc4c/src/progress/shared.js +36 -0
- package/.worktrees/e58fcc4c/src/progress/stage-machine.js +594 -0
- package/.worktrees/e58fcc4c/src/progress/step-store.js +265 -0
- package/.worktrees/e58fcc4c/src/progress.js +1304 -0
- package/.worktrees/e58fcc4c/src/quick-recommend.js +115 -0
- package/.worktrees/e58fcc4c/src/quicklog.js +883 -0
- package/.worktrees/e58fcc4c/src/review-tier.js +77 -0
- package/.worktrees/e58fcc4c/src/run/command.js +1641 -0
- package/.worktrees/e58fcc4c/src/run/complete-handlers.js +1552 -0
- package/.worktrees/e58fcc4c/src/run/complete.js +1259 -0
- package/.worktrees/e58fcc4c/src/run/concurrent-detect.js +156 -0
- package/.worktrees/e58fcc4c/src/run/gates.js +1111 -0
- package/.worktrees/e58fcc4c/src/run/multi-repo-context.js +208 -0
- package/.worktrees/e58fcc4c/src/run/next.js +128 -0
- package/.worktrees/e58fcc4c/src/run/prompt.js +843 -0
- package/.worktrees/e58fcc4c/src/run/quick-audit.js +186 -0
- package/.worktrees/e58fcc4c/src/run/scan-profile.js +269 -0
- package/.worktrees/e58fcc4c/src/run/shared.js +1562 -0
- package/.worktrees/e58fcc4c/src/run/stage.js +587 -0
- package/.worktrees/e58fcc4c/src/run.js +23 -0
- package/.worktrees/e58fcc4c/src/scan-diff.js +388 -0
- package/.worktrees/e58fcc4c/src/scan-postcheck.js +524 -0
- package/.worktrees/e58fcc4c/src/scan-staleness.js +95 -0
- package/.worktrees/e58fcc4c/src/setup.js +414 -0
- package/.worktrees/e58fcc4c/src/sillyhub-mcp/client.js +597 -0
- package/.worktrees/e58fcc4c/src/sillyhub-mcp/config.js +62 -0
- package/.worktrees/e58fcc4c/src/spec-dir-typo.js +50 -0
- package/.worktrees/e58fcc4c/src/spec-sync.js +358 -0
- package/.worktrees/e58fcc4c/src/stage-contract-engine.js +171 -0
- package/.worktrees/e58fcc4c/src/stage-contract-spec.js +551 -0
- package/.worktrees/e58fcc4c/src/stage-contract.js +948 -0
- package/.worktrees/e58fcc4c/src/stage-review.js +597 -0
- package/.worktrees/e58fcc4c/src/stages/archive.js +199 -0
- package/.worktrees/e58fcc4c/src/stages/brainstorm-auto.js +285 -0
- package/.worktrees/e58fcc4c/src/stages/brainstorm.js +624 -0
- package/.worktrees/e58fcc4c/src/stages/cmd-existence.js +145 -0
- package/.worktrees/e58fcc4c/src/stages/doctor.js +540 -0
- package/.worktrees/e58fcc4c/src/stages/execute.js +1277 -0
- package/.worktrees/e58fcc4c/src/stages/explore.js +43 -0
- package/.worktrees/e58fcc4c/src/stages/index.js +29 -0
- package/.worktrees/e58fcc4c/src/stages/knowledge.js +514 -0
- package/.worktrees/e58fcc4c/src/stages/plan-postcheck.js +1398 -0
- package/.worktrees/e58fcc4c/src/stages/plan.js +655 -0
- package/.worktrees/e58fcc4c/src/stages/quick.js +167 -0
- package/.worktrees/e58fcc4c/src/stages/scan.js +608 -0
- package/.worktrees/e58fcc4c/src/stages/status.js +64 -0
- package/.worktrees/e58fcc4c/src/stages/verify.js +246 -0
- package/.worktrees/e58fcc4c/src/sync.js +1470 -0
- package/.worktrees/e58fcc4c/src/task-review.js +1498 -0
- package/.worktrees/e58fcc4c/src/taskcard-placeholders.js +21 -0
- package/.worktrees/e58fcc4c/src/taskcard.js +250 -0
- package/.worktrees/e58fcc4c/src/verify-postcheck.js +1718 -0
- package/.worktrees/e58fcc4c/src/verify-probes.js +327 -0
- package/.worktrees/e58fcc4c/src/version.js +19 -0
- package/.worktrees/e58fcc4c/src/workflow.js +600 -0
- package/.worktrees/e58fcc4c/src/workspace.js +125 -0
- package/.worktrees/e58fcc4c/src/worktree-apply.js +1611 -0
- package/.worktrees/e58fcc4c/src/worktree-deps.js +668 -0
- package/.worktrees/e58fcc4c/src/worktree.js +1849 -0
- package/.worktrees/e58fcc4c/templates/claude-instruction.md +23 -0
- package/.worktrees/e58fcc4c/templates/prompts/taskcard-rules.md +29 -0
- package/.worktrees/e58fcc4c/templates/prompts/testcase-design.md +12 -0
- package/.worktrees/e58fcc4c/templates/prompts/verify-probes.md +32 -0
- package/.worktrees/e58fcc4c/templates/workflows/archive-impact.yaml +79 -0
- package/.worktrees/e58fcc4c/templates/workflows/scan-docs.yaml +132 -0
- package/architecture-analysis.md +448 -0
- package/package.json +1 -1
- package/src/contract-matrix.js +7 -4
- package/src/endpoint-extractor.js +41 -52
- package/src/foreign-declared.js +88 -5
- package/src/fs-atomic.js +20 -3
- package/src/hooks/worktree-guard.js +9 -3
- package/src/index.js +36 -19
- package/src/module-impact.js +1 -1
- package/src/modules.js +23 -21
- package/src/progress/stage-machine.js +23 -0
- package/src/progress.js +38 -2
- package/src/quicklog.js +7 -5
- package/src/run/command.js +7 -6
- package/src/run/complete-handlers.js +6 -2
- package/src/run/complete.js +33 -20
- package/src/run/gates.js +31 -4
- package/src/run/next.js +4 -3
- package/src/run/prompt.js +66 -6
- package/src/run/scan-profile.js +1 -0
- package/src/run/shared.js +11 -5
- package/src/run/stage.js +15 -12
- package/src/scan-diff.js +4 -2
- package/src/stage-contract-spec.js +1 -1
- package/src/stage-contract.js +16 -8
- package/src/stages/brainstorm-auto.js +43 -1
- package/src/stages/brainstorm.js +24 -8
- package/src/stages/execute.js +36 -9
- package/src/stages/knowledge.js +18 -5
- package/src/stages/plan-postcheck.js +63 -7
- package/src/stages/plan.js +13 -6
- package/src/stages/verify.js +1 -1
- package/src/sync.js +27 -11
- package/src/task-review.js +5 -3
- package/src/taskcard.js +35 -0
- package/src/verify-postcheck.js +24 -13
- package/src/verify-probes.js +39 -13
- package/src/worktree-apply.js +481 -292
- package/src/worktree-deps.js +93 -1
- package/src/worktree.js +91 -21
- package/templates/prompts/taskcard-rules.md +1 -1
|
@@ -0,0 +1,825 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* docs-check — 文档行号引用校验核心(change: 2026-08-15-docs-check-productize)
|
|
3
|
+
*
|
|
4
|
+
* 从 dogfood 私有测试 test/doc-ref-check.test.mjs 抽离产品化(design D-001~D-008):
|
|
5
|
+
* 层1 存在性(所有引用必查):文件存在 + 行号 ≥1 且 ≤ 总行数(范围引用查 end)
|
|
6
|
+
* 层2 关键词断言(keywordAssert 可配,缺省开):引用所在文档行内的反引号代码符号 token,
|
|
7
|
+
* 断言源文件 [start-2, end+5] 窗口(实现期口径,非对称——文档行号常指向块起始行
|
|
8
|
+
* 而 token 在体首几行)内含任一 token。多候选宽容:裸文件名多命中时任一候选全过即通过。
|
|
9
|
+
*
|
|
10
|
+
* 纯函数(collectDocRefs/looksLikeCodeSymbol/validateRefLines/extractExpectedTokensFromLine)
|
|
11
|
+
* 无 fs 依赖可单测;resolveCandidates/walkGlob/runDocsCheck 是 IO 面。
|
|
12
|
+
* 校验链路只读(不修改任何被校验文件);applyFixes 是唯一写回面(--fix 显式触发,design §9:
|
|
13
|
+
* 文档非多进程竞争的运行时文件,普通 writeFileSync);纯 Node 内置模块零依赖(D-008:glob 手写 walker,
|
|
14
|
+
* 仅「目录递归」「目录单层」「字面路径」三形态);Windows 路径归一化;兼容 CRLF/LF。
|
|
15
|
+
*/
|
|
16
|
+
import { readFileSync, writeFileSync, existsSync, readdirSync, statSync } from 'node:fs'
|
|
17
|
+
import { join } from 'node:path'
|
|
18
|
+
import jsYaml from 'js-yaml'
|
|
19
|
+
import { parseModuleMapSimple } from './modules.js'
|
|
20
|
+
|
|
21
|
+
/** 提取 file.js:line / file.js:start-end 引用(.js/.mjs,反引号包裹与裸文本均命中,全文扫描 D-006)。
|
|
22
|
+
* repo:// 前缀(2026-08-20):跨仓引用显式标记——`repo://<仓库名>/<路径>.js:行`。
|
|
23
|
+
* 不同设备兄弟仓库位置不同,未配映射时默认跳过本地校验(防跨设备误报);
|
|
24
|
+
* 在本机 .sillyspec/local.yaml 的 docs-check.cross_repo_roots 配
|
|
25
|
+
* `<仓库名>: <本机绝对路径>` 后,走与本地引用完全相同的层1(行号边界)+ 层2(关键词窗口)校验。
|
|
26
|
+
* 正则组:1=仓库名(可选),2=文件,3=start,4=end。 */
|
|
27
|
+
const REF_RE = /(?:repo:\/\/([A-Za-z0-9_.\-]+)\/)?([A-Za-z0-9_.\-\/]+\.(?:js|mjs)):(\d+)(?:-(\d+))?/g
|
|
28
|
+
|
|
29
|
+
/** 缺省扫描范围:docs/ + .sillyspec/docs/(scan/modules 产物同是文档,失效即该暴露;2026-08-16 用户裁决改缺省,见 doc-consistency-debt.md §八) */
|
|
30
|
+
const DEFAULT_DOC_PATHS = ['docs/**/*.md', '.sillyspec/docs/**/*.md']
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 读 local.yaml 的 docs-check 段(best-effort,绝不抛;缺文件/无段 → 全缺省)。
|
|
34
|
+
* @param {string} projectRoot 源码仓根(local.yaml 在 <root>/.sillyspec/local.yaml)
|
|
35
|
+
* @returns {{ paths?: string[], skip: string[], keywordAssert: boolean, crossRepoRoots: Record<string, string> }}
|
|
36
|
+
*/
|
|
37
|
+
export function readDocsCheckConfig(projectRoot) {
|
|
38
|
+
const fallback = { paths: null, skip: [], keywordAssert: true, crossRepoRoots: {} }
|
|
39
|
+
try {
|
|
40
|
+
const p = join(projectRoot, '.sillyspec', 'local.yaml')
|
|
41
|
+
if (!existsSync(p)) return fallback
|
|
42
|
+
const doc = jsYaml.load(readFileSync(p, 'utf8'))
|
|
43
|
+
if (!doc || typeof doc !== 'object') return fallback
|
|
44
|
+
const dc = doc['docs-check']
|
|
45
|
+
if (!dc || typeof dc !== 'object') return fallback
|
|
46
|
+
const crr = dc['cross_repo_roots']
|
|
47
|
+
return {
|
|
48
|
+
paths: Array.isArray(dc.paths) ? dc.paths.filter(s => typeof s === 'string') : null,
|
|
49
|
+
skip: Array.isArray(dc.skip) ? dc.skip.filter(s => typeof s === 'string') : [],
|
|
50
|
+
keywordAssert: typeof dc.keywordAssert === 'boolean' ? dc.keywordAssert : true,
|
|
51
|
+
// repo://<name> → 本机仓库根(每台设备各自配;local.yaml 是 gitignored,绝对路径不入库)
|
|
52
|
+
crossRepoRoots: crr && typeof crr === 'object' && !Array.isArray(crr)
|
|
53
|
+
? Object.fromEntries(
|
|
54
|
+
Object.entries(crr).filter(([, v]) => typeof v === 'string' && v.trim() !== ''),
|
|
55
|
+
)
|
|
56
|
+
: {},
|
|
57
|
+
}
|
|
58
|
+
} catch {
|
|
59
|
+
return fallback
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** 配置错误(glob 形态不支持等)→ CLI exit 2 */
|
|
64
|
+
export class DocsCheckConfigError extends Error {}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 纯函数:从 markdown 全文提取全部 file:line 引用。
|
|
68
|
+
* @param {string} md 文档全文
|
|
69
|
+
* @returns {Array<{ ref, file, start, end, docLine }>} docLine 为 1-based 文档行号
|
|
70
|
+
*/
|
|
71
|
+
export function collectDocRefs(md) {
|
|
72
|
+
if (!md || typeof md !== 'string') return []
|
|
73
|
+
const refs = []
|
|
74
|
+
const re = new RegExp(REF_RE.source, 'g')
|
|
75
|
+
// 行号单遍计算:regex match 天然按 index 升序,游标只前进——原逐引用
|
|
76
|
+
// slice(0,m.index).split() 是 O(引用数 × 文档长度),长文档×多引用退化明显
|
|
77
|
+
let line = 1
|
|
78
|
+
let cursor = 0
|
|
79
|
+
let m
|
|
80
|
+
while ((m = re.exec(md)) !== null) {
|
|
81
|
+
for (let i = cursor; i < m.index; i++) {
|
|
82
|
+
if (md.charCodeAt(i) === 10) line++ // '\n'(\r\n 也以 \n 计数,1-based 行号不受影响)
|
|
83
|
+
}
|
|
84
|
+
cursor = m.index
|
|
85
|
+
refs.push({
|
|
86
|
+
ref: m[0],
|
|
87
|
+
repo: m[1] !== undefined ? m[1] : null,
|
|
88
|
+
file: m[2],
|
|
89
|
+
start: parseInt(m[3], 10),
|
|
90
|
+
end: m[4] !== undefined ? parseInt(m[4], 10) : parseInt(m[3], 10),
|
|
91
|
+
docLine: line,
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
return refs
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* 纯函数:判定 token 是否「像代码符号」:首字符字母/_/$,且含大写字母/下划线/点/$ 之一。
|
|
99
|
+
* 纯小写英文单词(local/platform/abort)→ false(自然语言,跳过断言防误报)。
|
|
100
|
+
*/
|
|
101
|
+
export function looksLikeCodeSymbol(token) {
|
|
102
|
+
if (!/^[A-Za-z_$][A-Za-z0-9_$.]*$/.test(token)) return false
|
|
103
|
+
return /[A-Z_$.]/.test(token)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* 纯函数:层1 行号边界校验。
|
|
108
|
+
* @param {number} totalLines 源文件总行数
|
|
109
|
+
* @param {number} start 1-based 起始行
|
|
110
|
+
* @param {number} end 1-based 结束行(单行引用 = start)
|
|
111
|
+
* @returns {{ ok: boolean, reasons: string[] }}
|
|
112
|
+
*/
|
|
113
|
+
export function validateRefLines(totalLines, start, end) {
|
|
114
|
+
const reasons = []
|
|
115
|
+
if (start < 1 || start > totalLines) reasons.push(`行号超界(start=${start} > 总行数 ${totalLines})`)
|
|
116
|
+
if (end < start || end > totalLines) reasons.push(`范围 end=${end} 超界(总行数 ${totalLines})`)
|
|
117
|
+
return { ok: reasons.length === 0, reasons }
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* 纯函数:层2 token 提取——引用所在的文档行内所有反引号 token 中的代码符号。
|
|
122
|
+
* token 归一:①剥函数括号(getDispatchMode());②点分名拆段(syncMod.checkApproval → 两段)。
|
|
123
|
+
* 空数组 = 纯位置引用,跳过层2。
|
|
124
|
+
* @param {string} line 引用所在的文档行全文
|
|
125
|
+
* @returns {string[]} token 列表
|
|
126
|
+
*/
|
|
127
|
+
export function extractExpectedTokensFromLine(line) {
|
|
128
|
+
if (!line || typeof line !== 'string') return []
|
|
129
|
+
const tokens = new Set()
|
|
130
|
+
for (const mm of line.matchAll(/`([^`\n]{1,60})`/g)) {
|
|
131
|
+
const t = mm[1].split('(')[0].trim()
|
|
132
|
+
if (!looksLikeCodeSymbol(t)) continue
|
|
133
|
+
tokens.add(t)
|
|
134
|
+
if (t.includes('.')) {
|
|
135
|
+
for (const seg of t.split('.')) {
|
|
136
|
+
if (looksLikeCodeSymbol(seg)) tokens.add(seg)
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return [...tokens]
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** 递归收集 dir 下与 baseName 同名的文件(相对 dir 的 POSIX 路径数组;排除 node_modules/.git)。
|
|
144
|
+
* treeCache 给定时按 baseName 复用全树扫描结果(N 条裸名引用同一文件免 N 次 walk) */
|
|
145
|
+
function findInTree(dir, baseName, rel = '', treeCache = null) {
|
|
146
|
+
if (treeCache && rel === '') {
|
|
147
|
+
const hit = treeCache.get(baseName)
|
|
148
|
+
if (hit) return hit
|
|
149
|
+
const result = findInTree(dir, baseName, '', null)
|
|
150
|
+
treeCache.set(baseName, result)
|
|
151
|
+
return result
|
|
152
|
+
}
|
|
153
|
+
const out = []
|
|
154
|
+
let entries
|
|
155
|
+
try { entries = readdirSync(dir, { withFileTypes: true }) } catch { return out }
|
|
156
|
+
for (const e of entries) {
|
|
157
|
+
if (e.name === 'node_modules' || e.name === '.git') continue
|
|
158
|
+
const relPath = rel ? `${rel}/${e.name}` : e.name
|
|
159
|
+
if (e.isDirectory()) out.push(...findInTree(join(dir, e.name), baseName, relPath))
|
|
160
|
+
else if (e.name === baseName) out.push(relPath)
|
|
161
|
+
}
|
|
162
|
+
return out
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* 解析引用文件 → 候选绝对路径数组。文档写法三种混用(首跑实证):
|
|
167
|
+
* ①仓库根相对(src/sync.js / docs/...)→ 直拼;②src/ 内部相对(dispatch/probe.js)→
|
|
168
|
+
* src/ 前缀重试;③裸中缀(backends/sillyhub-mcp.js)→ src/ 树内按路径后缀匹配。
|
|
169
|
+
* 空数组 = 不存在。treeCache(Map basename→findInTree 结果)给定时透传复用全树扫描。
|
|
170
|
+
*/
|
|
171
|
+
export function resolveCandidates(projectRoot, refFile, treeCache = null) {
|
|
172
|
+
if (refFile.includes('/')) {
|
|
173
|
+
const direct = join(projectRoot, refFile)
|
|
174
|
+
if (existsSync(direct)) return [direct]
|
|
175
|
+
const inSrc = join(projectRoot, 'src', refFile)
|
|
176
|
+
if (existsSync(inSrc)) return [inSrc]
|
|
177
|
+
const slash = refFile.lastIndexOf('/')
|
|
178
|
+
const baseName = slash === -1 ? refFile : refFile.slice(slash + 1)
|
|
179
|
+
return findInTree(join(projectRoot, 'src'), baseName, '', treeCache)
|
|
180
|
+
.filter((rel) => ('src/' + rel).endsWith('/' + refFile) || 'src/' + rel === 'src/' + refFile)
|
|
181
|
+
.map((rel) => join(projectRoot, 'src', rel))
|
|
182
|
+
}
|
|
183
|
+
return findInTree(join(projectRoot, 'src'), refFile, '', treeCache).map((rel) => join(projectRoot, 'src', rel))
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** 读文件行数组(CRLF/LF 归一:split(/\r?\n/),层2 只做子串查找不污染原文)。
|
|
187
|
+
* linesCache 给定时按绝对路径复用(同文件被 N 条引用消费免 N 次读盘+split) */
|
|
188
|
+
function readLines(absPath, linesCache = null) {
|
|
189
|
+
if (linesCache) {
|
|
190
|
+
if (linesCache.has(absPath)) return linesCache.get(absPath)
|
|
191
|
+
const lines = readLines(absPath)
|
|
192
|
+
linesCache.set(absPath, lines)
|
|
193
|
+
return lines
|
|
194
|
+
}
|
|
195
|
+
try { return readFileSync(absPath, 'utf8').split(/\r?\n/) } catch { return null }
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** 简单通配匹配(skip 排除用,仅 * 单段) */
|
|
199
|
+
function matchSimple(text, pattern) {
|
|
200
|
+
const parts = pattern.split('*')
|
|
201
|
+
let idx = 0
|
|
202
|
+
for (let i = 0; i < parts.length; i++) {
|
|
203
|
+
if (parts[i] === '') continue
|
|
204
|
+
const found = text.indexOf(parts[i], idx)
|
|
205
|
+
if (found === -1) return false
|
|
206
|
+
if (i === 0 && found !== 0) return false
|
|
207
|
+
idx = found + parts[i].length
|
|
208
|
+
}
|
|
209
|
+
return true
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* glob walker(D-008:手写不引依赖)。仅支持三形态:
|
|
214
|
+
* - `dir/「递归」*.ext` 递归收集(maxDepth 12 兜底防符号链接环)
|
|
215
|
+
* - `dir/*.ext` 单层
|
|
216
|
+
* - 字面路径直传(存在才返回)
|
|
217
|
+
* 其他形态(?、{a,b}、多层 * 混合等)抛 DocsCheckConfigError → CLI exit 2。
|
|
218
|
+
* @param {string} projectRoot 锚点(平台模式也锚源码仓根,design §3.3)
|
|
219
|
+
* @param {string} pattern glob 模式
|
|
220
|
+
* @param {string[]} skip 排除 glob(前缀或单 * 简单匹配)
|
|
221
|
+
* @returns {string[]} 命中文件的 POSIX 相对路径
|
|
222
|
+
*/
|
|
223
|
+
export function walkGlob(projectRoot, pattern, skip = []) {
|
|
224
|
+
const norm = (p) => p.replace(/\\/g, '/')
|
|
225
|
+
const isSkipped = (rel) => skip.some((s) => {
|
|
226
|
+
const sn = norm(s).replace(/\/$/, '')
|
|
227
|
+
return rel === sn || rel.startsWith(sn + '/') ||
|
|
228
|
+
(sn.includes('*') && matchSimple(rel, sn))
|
|
229
|
+
})
|
|
230
|
+
const matchExt = (name, ext) => name.endsWith(ext)
|
|
231
|
+
// 形态 0:**/*.ext(根级递归,无 base 前缀——B11b:原被形态 2 误解析为字面目录 `**` 静默 0 命中)
|
|
232
|
+
let m0 = norm(pattern).match(/^\*\*\/\*(\.[A-Za-z0-9]+)$/)
|
|
233
|
+
if (m0) {
|
|
234
|
+
const [, ext] = m0
|
|
235
|
+
const out = []
|
|
236
|
+
const rec = (dir, rel, depth) => {
|
|
237
|
+
if (depth > 12) return
|
|
238
|
+
let entries
|
|
239
|
+
try { entries = readdirSync(dir, { withFileTypes: true }) } catch { return }
|
|
240
|
+
for (const e of entries) {
|
|
241
|
+
if (e.name === 'node_modules' || e.name === '.git') continue
|
|
242
|
+
const relPath = rel ? `${rel}/${e.name}` : e.name
|
|
243
|
+
if (isSkipped(relPath)) continue
|
|
244
|
+
if (e.isDirectory()) rec(join(dir, e.name), relPath, depth + 1)
|
|
245
|
+
else if (matchExt(e.name, ext)) out.push(relPath)
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
rec(projectRoot, '', 0)
|
|
249
|
+
return out
|
|
250
|
+
}
|
|
251
|
+
// 形态 1:**/*.ext
|
|
252
|
+
let m = norm(pattern).match(/^(.+?)\/\*\*\/\*(\.[A-Za-z0-9]+)$/)
|
|
253
|
+
if (m) {
|
|
254
|
+
const [, baseDir, ext] = m
|
|
255
|
+
const out = []
|
|
256
|
+
const rec = (dir, rel, depth) => {
|
|
257
|
+
if (depth > 12) return
|
|
258
|
+
let entries
|
|
259
|
+
try { entries = readdirSync(dir, { withFileTypes: true }) } catch { return }
|
|
260
|
+
for (const e of entries) {
|
|
261
|
+
if (e.name === 'node_modules' || e.name === '.git') continue
|
|
262
|
+
const relPath = rel ? `${rel}/${e.name}` : e.name
|
|
263
|
+
if (isSkipped(relPath)) continue
|
|
264
|
+
if (e.isDirectory()) rec(join(dir, e.name), relPath, depth + 1)
|
|
265
|
+
else if (matchExt(e.name, ext)) out.push(relPath)
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
rec(join(projectRoot, baseDir), baseDir, 0)
|
|
269
|
+
return out
|
|
270
|
+
}
|
|
271
|
+
// 形态 2:dir/*.ext(单层)
|
|
272
|
+
m = norm(pattern).match(/^(.+?)\/\*(\.[A-Za-z0-9]+)$/)
|
|
273
|
+
if (m) {
|
|
274
|
+
const [, baseDir, ext] = m
|
|
275
|
+
const out = []
|
|
276
|
+
let entries
|
|
277
|
+
try { entries = readdirSync(join(projectRoot, baseDir), { withFileTypes: true }) } catch { return out }
|
|
278
|
+
for (const e of entries) {
|
|
279
|
+
if (!e.isFile()) continue
|
|
280
|
+
const relPath = `${baseDir}/${e.name}`
|
|
281
|
+
if (isSkipped(relPath)) continue
|
|
282
|
+
if (matchExt(e.name, ext)) out.push(relPath)
|
|
283
|
+
}
|
|
284
|
+
return out
|
|
285
|
+
}
|
|
286
|
+
// 形态 3:字面路径(不含任何通配元字符才直传;含 ?、{ }、[ ] 等不支持形态落 error)
|
|
287
|
+
if (!/[*?{}\[\]]/.test(pattern)) {
|
|
288
|
+
const abs = join(projectRoot, pattern)
|
|
289
|
+
if (!existsSync(abs)) return []
|
|
290
|
+
// B11b:目录字面量抛配置错误(原直传 readFileSync 撞 EISDIR 裸崩 exit 1;契约应 exit 2)
|
|
291
|
+
if (statSync(abs).isDirectory()) {
|
|
292
|
+
throw new DocsCheckConfigError(`路径是目录不是文档:${pattern}(文档路径应为 .md 文件或 glob 形态 **/*.ext / dir/**/*.ext / dir/*.ext)`)
|
|
293
|
+
}
|
|
294
|
+
return [norm(pattern)]
|
|
295
|
+
}
|
|
296
|
+
throw new DocsCheckConfigError(`不支持的 glob 形态:${pattern}(当前仅支持 dir/**/*.ext、dir/*.ext、字面路径)`)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/** 候选路径 → 相对 projectRoot 显示(失败信息用;Windows 反斜杠归一) */
|
|
300
|
+
function relDisplay(absPath, projectRoot) {
|
|
301
|
+
return absPath
|
|
302
|
+
.replace(/\\/g, '/')
|
|
303
|
+
.replace(projectRoot.replace(/\\/g, '/') + '/', '')
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* IO 入口:跑一次完整校验。
|
|
308
|
+
* @param {{ projectRoot: string, docs?: string[], paths?: string[], skip?: string[], keywordAssert?: boolean, crossRepoRoots?: Record<string, string> }} opts
|
|
309
|
+
* projectRoot 源码仓根(候选解析与 glob 的锚点,平台模式也传源码仓根)
|
|
310
|
+
* docs 显式文档相对路径列表(优先于 paths glob 展开结果)
|
|
311
|
+
* crossRepoRoots repo://<仓库名> → 本机仓库根映射(未映射的跨仓引用跳过不计失效)
|
|
312
|
+
* @returns {{ ok: boolean, total: number, invalid: Array<{doc, docLine, ref, reason, suggest?: number[], fix: {fixable: boolean, newLine?: number, reason: string}}>, warnings: string[], kwChecked: number, crossRepoSkipped: number }}
|
|
313
|
+
* @throws {DocsCheckConfigError} glob 形态不支持
|
|
314
|
+
*/
|
|
315
|
+
export function runDocsCheck(opts) {
|
|
316
|
+
// paths/docs 显式传 null(readDocsCheckConfig 无 local.yaml 段时的回退值)须落回缺省 glob,
|
|
317
|
+
// 解构默认值只挡 undefined 不挡 null——docs-check 无配置裸跑曾因此 null.flatMap 崩溃。
|
|
318
|
+
const {
|
|
319
|
+
projectRoot, docs = null, paths: rawPaths = DEFAULT_DOC_PATHS, skip = [],
|
|
320
|
+
keywordAssert = true, crossRepoRoots = {},
|
|
321
|
+
} = opts || {}
|
|
322
|
+
const paths = Array.isArray(rawPaths) && rawPaths.length > 0 ? rawPaths : DEFAULT_DOC_PATHS
|
|
323
|
+
const warnings = []
|
|
324
|
+
if (keywordAssert === false) warnings.push('关键词断言已关闭(keywordAssert=false),仅做存在性校验')
|
|
325
|
+
const docFiles = docs && docs.length > 0
|
|
326
|
+
? docs
|
|
327
|
+
: [...new Set(paths.flatMap((p) => walkGlob(projectRoot, p, skip)))].sort()
|
|
328
|
+
|
|
329
|
+
const invalid = []
|
|
330
|
+
let total = 0
|
|
331
|
+
let kwChecked = 0
|
|
332
|
+
// repo:// 跨仓引用:未配映射被跳过的数量(不计入 total/invalid,跨设备零误报)
|
|
333
|
+
let crossRepoSkipped = 0
|
|
334
|
+
// per-call 缓存:裸名引用的 src/ 全树扫描结果 + 候选文件行数组——100 文档 × 10 裸名引用
|
|
335
|
+
// 此前 = 1000 次全树 walk + 同文件 N 次重读(2026-08-21 性能审查 PERF-5)。仅本次调用
|
|
336
|
+
// 生命周期内有效,不跨调用(防测试流程中途改树后读到陈旧结果)
|
|
337
|
+
const treeCache = new Map()
|
|
338
|
+
const linesCache = new Map()
|
|
339
|
+
|
|
340
|
+
for (const docRel of docFiles) {
|
|
341
|
+
const docAbs = join(projectRoot, docRel)
|
|
342
|
+
if (!existsSync(docAbs)) {
|
|
343
|
+
invalid.push({
|
|
344
|
+
doc: docRel, docLine: 0, ref: '', reason: '文档不存在',
|
|
345
|
+
fix: { fixable: false, reason: '文档不存在,无法自动定位' },
|
|
346
|
+
})
|
|
347
|
+
continue
|
|
348
|
+
}
|
|
349
|
+
const md = readFileSync(docAbs, 'utf8')
|
|
350
|
+
const refs = collectDocRefs(md)
|
|
351
|
+
const mdLines = md.split(/\r?\n/)
|
|
352
|
+
|
|
353
|
+
for (const r of refs) {
|
|
354
|
+
// repo:// 跨仓引用:未配映射 → 跳过(不同设备仓库位置不同,不按本仓解析误报);
|
|
355
|
+
// 配了映射 → 以映射根为唯一候选,走与本地引用相同的层1+层2 校验。
|
|
356
|
+
let candidates
|
|
357
|
+
if (r.repo) {
|
|
358
|
+
const repoRoot = crossRepoRoots && typeof crossRepoRoots[r.repo] === 'string'
|
|
359
|
+
? crossRepoRoots[r.repo]
|
|
360
|
+
: null
|
|
361
|
+
if (!repoRoot) {
|
|
362
|
+
crossRepoSkipped++
|
|
363
|
+
continue
|
|
364
|
+
}
|
|
365
|
+
const abs = join(repoRoot, r.file)
|
|
366
|
+
if (!existsSync(abs)) {
|
|
367
|
+
total++
|
|
368
|
+
invalid.push({
|
|
369
|
+
doc: docRel, docLine: r.docLine, ref: r.ref,
|
|
370
|
+
reason: `跨仓 repo://${r.repo} → 文件不存在(cross_repo_roots 映射根:${repoRoot})`,
|
|
371
|
+
fix: { fixable: false, reason: '跨仓引用无法自动定位' },
|
|
372
|
+
})
|
|
373
|
+
continue
|
|
374
|
+
}
|
|
375
|
+
candidates = [abs]
|
|
376
|
+
} else {
|
|
377
|
+
candidates = resolveCandidates(projectRoot, r.file, treeCache)
|
|
378
|
+
}
|
|
379
|
+
total++
|
|
380
|
+
if (candidates.length === 0) {
|
|
381
|
+
invalid.push({
|
|
382
|
+
doc: docRel, docLine: r.docLine, ref: r.ref,
|
|
383
|
+
reason: '文件不存在(含 / 按仓库根解析;裸文件名在 src/ 递归)',
|
|
384
|
+
fix: { fixable: false, reason: '文件不存在,无法自动定位' },
|
|
385
|
+
})
|
|
386
|
+
continue
|
|
387
|
+
}
|
|
388
|
+
// 多候选宽容:逐候选跑层1+层2,任一全过即通过
|
|
389
|
+
const tokens = keywordAssert
|
|
390
|
+
? extractExpectedTokensFromLine(mdLines[r.docLine - 1] || '')
|
|
391
|
+
: []
|
|
392
|
+
const candidateFails = []
|
|
393
|
+
let passedAny = false
|
|
394
|
+
for (const candAbs of candidates) {
|
|
395
|
+
const lines = readLines(candAbs, linesCache)
|
|
396
|
+
if (lines === null) { candidateFails.push(`${relDisplay(candAbs, projectRoot)}: 读取失败`); continue }
|
|
397
|
+
const v = validateRefLines(lines.length, r.start, r.end)
|
|
398
|
+
// 层2:token 任一在 [start-2, end+5] 窗口命中即过
|
|
399
|
+
let kwOk = true
|
|
400
|
+
if (tokens.length > 0) {
|
|
401
|
+
const from = Math.max(0, r.start - 2)
|
|
402
|
+
const to = Math.min(lines.length, r.end + 5)
|
|
403
|
+
const window = lines.slice(from, to).join('\n')
|
|
404
|
+
kwOk = tokens.some((t) => window.includes(t))
|
|
405
|
+
}
|
|
406
|
+
if (v.ok && kwOk) { passedAny = true; break }
|
|
407
|
+
const reasons = [...v.reasons]
|
|
408
|
+
if (!kwOk) reasons.push(`关键词缺失:期望任一「${tokens.join(' / ')}」在 [start-2, end+5] 窗口内`)
|
|
409
|
+
candidateFails.push(`${relDisplay(candAbs, projectRoot)}: ${reasons.join(';')}`)
|
|
410
|
+
}
|
|
411
|
+
if (tokens.length > 0) kwChecked++
|
|
412
|
+
if (!passedAny) {
|
|
413
|
+
// 跨仓校验失败的 reason 加 repo:// 前缀,用户一眼区分「改外部仓引用」还是「改本仓引用」
|
|
414
|
+
const repoPrefix = r.repo ? `跨仓 repo://${r.repo} → ` : ''
|
|
415
|
+
invalid.push({
|
|
416
|
+
doc: docRel, docLine: r.docLine, ref: r.ref,
|
|
417
|
+
reason: repoPrefix + (candidateFails.length > 1 ? `多候选全失败 → ${candidateFails.join(' | ')}` : candidateFails[0]),
|
|
418
|
+
// 建议行号(--suggest):token 在首个候选文件的全量命中行,供人工确认改锚——不自动改文件
|
|
419
|
+
suggest: suggestLines(candidates, tokens, linesCache),
|
|
420
|
+
// 修复分类(--fix 判定依据):全量候选 token 命中打分——唯一命中或选优严格领先可自动重锚
|
|
421
|
+
fix: classifyFix(candidates, tokens, r.start, linesCache),
|
|
422
|
+
})
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return { ok: invalid.length === 0, total, invalid, warnings, kwChecked, crossRepoSkipped }
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* 建议行号计算(--suggest):对失效引用,在候选文件里找 token 全量命中行。
|
|
432
|
+
* 无 token(纯行号断言)时返回空数组——没有符号线索无法定位,只能人工看。
|
|
433
|
+
*/
|
|
434
|
+
function suggestLines(candidates, tokens, linesCache = null) {
|
|
435
|
+
if (tokens.length === 0) return []
|
|
436
|
+
try {
|
|
437
|
+
const lines = readLines(candidates[0], linesCache)
|
|
438
|
+
if (lines === null) return []
|
|
439
|
+
const out = []
|
|
440
|
+
lines.forEach((l, i) => { if (tokens.some((t) => l.includes(t))) out.push(i + 1) })
|
|
441
|
+
return out.slice(0, 8)
|
|
442
|
+
} catch { return [] }
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* 修复分类(--fix 判定依据):对 resolveCandidates 全量候选跑 token 命中统计,跨候选合并行号后——
|
|
447
|
+
* 唯一命中 → fixable=true + newLine(自动重锚唯一解);
|
|
448
|
+
* 多命中 → 打分选优(2026-08-21 docs-ref-auto-pick,替代 D-006 一律人工):top1 严格优于
|
|
449
|
+
* top2(分数差 > 0)自动重锚,同分仍人工。实证:一次大改 34 处漂移只有 2 处唯一命中,
|
|
450
|
+
* 32 处人工逐个挑——多命中不代表歧义,行号漂移多为单次编辑的单调位移。
|
|
451
|
+
* 打分信号(全部来自现有数据,不新增 IO):
|
|
452
|
+
* - 距离:|命中行 - 文档旧行号|(权重封顶 400)——最近的命中大概率是原锚点漂移后的位置
|
|
453
|
+
* - 定义行模式 +50:function/const/let/class/def/export 关键词**紧跟** token(引用锚通常指
|
|
454
|
+
* 定义起始行而非调用点;「keyword 后 60 字符内出现」的宽松口径会把调用点误判为定义)
|
|
455
|
+
* - 注释行 -30(// * # -- 开头)
|
|
456
|
+
* - 含最长 token(点分整串)+10,优于只含拆段
|
|
457
|
+
* 与 suggestLines 的差异:suggest 只查首个候选(candidates[0]),本函数查全量候选(design §12 自审存疑 +
|
|
458
|
+
* R-01——多候选同名文件场景下防止定位到另一文件的同名符号)。合并口径按「去重后的行号集合」:
|
|
459
|
+
* 重锚写回的目标是行号,多个候选命中同一行号仍是唯一改写目标。
|
|
460
|
+
* 纯增量分类,不参与层1/层2 判定(D-004 兼容红线)。
|
|
461
|
+
* @param {string[]} candidates resolveCandidates 返回的全量候选绝对路径
|
|
462
|
+
* @param {string[]} tokens 层2 提取的期望 token(keywordAssert=false 时为空数组)
|
|
463
|
+
* @param {number|null} [refStart] 文档引用的旧行号(打分用距离信号;范围引用取 start)
|
|
464
|
+
* @returns {{ fixable: boolean, newLine?: number, reason: string }}
|
|
465
|
+
*/
|
|
466
|
+
function escapeReLocal(s) {
|
|
467
|
+
return String(s).replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function classifyFix(candidates, tokens, refStart = null, linesCache = null) {
|
|
471
|
+
if (tokens.length === 0) {
|
|
472
|
+
return { fixable: false, reason: '无 token 符号线索(纯位置引用或关键词断言关闭),无法自动定位' }
|
|
473
|
+
}
|
|
474
|
+
const longest = tokens.reduce((a, b) => (b.length > a.length ? b : a), '')
|
|
475
|
+
const defToken = longest.includes('.') ? longest.split('.').pop() : longest
|
|
476
|
+
const defRe = new RegExp(`(?:export\\s+)?(?:async\\s+)?(?:function|const|let|class|def)\\s+${escapeReLocal(defToken)}\\b`)
|
|
477
|
+
const byLine = new Map()
|
|
478
|
+
for (const candAbs of candidates) {
|
|
479
|
+
const lines = readLines(candAbs, linesCache)
|
|
480
|
+
if (lines === null) continue
|
|
481
|
+
lines.forEach((l, i) => {
|
|
482
|
+
if (!tokens.some((t) => l.includes(t))) return
|
|
483
|
+
const lineNo = i + 1
|
|
484
|
+
let score = 0
|
|
485
|
+
if (/^(\/\/|\*|#|--)/.test(l.trim())) score -= 30
|
|
486
|
+
if (defRe.test(l)) score += 50
|
|
487
|
+
if (l.includes(longest)) score += 10
|
|
488
|
+
if (refStart != null && Number.isFinite(refStart)) score -= Math.min(Math.abs(lineNo - refStart), 400)
|
|
489
|
+
// 同一行跨候选取最高分(合并口径不变:重锚目标是行号)
|
|
490
|
+
if (score > (byLine.get(lineNo) ?? -Infinity)) byLine.set(lineNo, score)
|
|
491
|
+
})
|
|
492
|
+
}
|
|
493
|
+
if (byLine.size === 0) {
|
|
494
|
+
return { fixable: false, reason: 'token 在全量候选文件零命中,无法自动定位' }
|
|
495
|
+
}
|
|
496
|
+
if (byLine.size === 1) {
|
|
497
|
+
return { fixable: true, newLine: [...byLine.keys()][0], reason: 'token 在全量候选唯一命中,可自动重锚' }
|
|
498
|
+
}
|
|
499
|
+
const ranked = [...byLine.entries()].sort((a, b) => (b[1] - a[1]) || (a[0] - b[0]))
|
|
500
|
+
const [topLine, topScore] = ranked[0]
|
|
501
|
+
const [runLine, runScore] = ranked[1]
|
|
502
|
+
if (topScore > runScore) {
|
|
503
|
+
return {
|
|
504
|
+
fixable: true,
|
|
505
|
+
newLine: topLine,
|
|
506
|
+
reason: `多命中自动选优:picked=${topLine}(${topScore} 分)runnerUp=${runLine}(${runScore} 分,严格落后才自动改)`,
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
const shown = ranked.slice(0, 8).map(([l]) => l).join('、') + (ranked.length > 8 ? '…' : '')
|
|
510
|
+
return { fixable: false, reason: `token 多处命中且最优两行同分(候选行号:${shown}),歧义需人工确认(D-006 保守默认)` }
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* 将可确定性修复的失效引用写回文档(--fix 消费面,design §7 接口逐字)。
|
|
515
|
+
* 纯机械定点替换:按 docLine + ref 串在该行内的字符偏移替换为 newRef,不解析行号语义、
|
|
516
|
+
* 不改引用文件名与 token(D-003:ref/newRef 一致性由调用方保证);候选定位全部依赖调用方
|
|
517
|
+
* 传入(不读 local.yaml 不解析配置)。范围引用(src/a.js:3-8)newRef 同样由调用方给全串。
|
|
518
|
+
* 同一行多个 fix 按行内偏移从后往前(降序)替换,防前序替换挤偏后序偏移(R-04);
|
|
519
|
+
* 其余字节不动:行内容只动命中片段,行结束符按原文(\r\n / \n 整文件统一口径)原样 join(R-05)。
|
|
520
|
+
* @param {string} projectRoot 源码仓根(doc 相对路径的锚点)
|
|
521
|
+
* @param {Array<{doc: string, docLine: number, ref: string, newRef: string}>} fixes
|
|
522
|
+
* doc 为相对 projectRoot 的文档路径;ref 旧引用串(如 src/a.js:6),newRef 新引用串(如 src/a.js:1)
|
|
523
|
+
* @param {{dryRun?: boolean}} opts dryRun 为真时不写盘仅返回将应用列表
|
|
524
|
+
* @returns {{applied: number, skipped: Array<{ref: string, reason: string}>}}
|
|
525
|
+
* dryRun 时 applied 为「将应用」计数;skipped 条目含 ref 与可读 reason(文档不存在/docLine 越界/
|
|
526
|
+
* 行内找不到 ref 串),跳过不中断批量
|
|
527
|
+
*/
|
|
528
|
+
export function applyFixes(projectRoot, fixes, opts = {}) {
|
|
529
|
+
const dryRun = opts.dryRun === true
|
|
530
|
+
let applied = 0
|
|
531
|
+
const skipped = []
|
|
532
|
+
if (!Array.isArray(fixes) || fixes.length === 0) return { applied, skipped }
|
|
533
|
+
|
|
534
|
+
// 按 doc 分组,每文档一次读改写(design §9:普通 writeFileSync,文档非运行时竞争文件)
|
|
535
|
+
const byDoc = new Map()
|
|
536
|
+
for (const f of fixes) {
|
|
537
|
+
if (!f || typeof f !== 'object' || typeof f.doc !== 'string' || typeof f.docLine !== 'number' ||
|
|
538
|
+
typeof f.ref !== 'string' || typeof f.newRef !== 'string') {
|
|
539
|
+
skipped.push({ ref: f && typeof f.ref === 'string' ? f.ref : '(条目缺失)', reason: 'fix 条目字段不完整(doc/docLine/ref/newRef)' })
|
|
540
|
+
continue
|
|
541
|
+
}
|
|
542
|
+
if (!byDoc.has(f.doc)) byDoc.set(f.doc, [])
|
|
543
|
+
byDoc.get(f.doc).push(f)
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
for (const [docRel, docFixes] of byDoc) {
|
|
547
|
+
const docAbs = join(projectRoot, docRel)
|
|
548
|
+
if (!existsSync(docAbs)) {
|
|
549
|
+
for (const f of docFixes) skipped.push({ ref: f.ref, reason: `文档不存在:${docRel}` })
|
|
550
|
+
continue
|
|
551
|
+
}
|
|
552
|
+
const raw = readFileSync(docAbs, 'utf8')
|
|
553
|
+
// 行结束符检测整文件统一口径(R-05):原文含 \r\n 则 CRLF join,否则 LF——与 readLines 归一逻辑一致
|
|
554
|
+
const eol = raw.includes('\r\n') ? '\r\n' : '\n'
|
|
555
|
+
const lines = raw.split(/\r?\n/)
|
|
556
|
+
let dirty = false
|
|
557
|
+
|
|
558
|
+
// 同一 docLine 的多 fix 按行内偏移从后往前替换(R-04):先按 docLine 分组,
|
|
559
|
+
// 组内按 ref 在该行内的命中偏移降序逐个定点替换
|
|
560
|
+
const byLine = new Map()
|
|
561
|
+
for (const f of docFixes) {
|
|
562
|
+
if (!byLine.has(f.docLine)) byLine.set(f.docLine, [])
|
|
563
|
+
byLine.get(f.docLine).push(f)
|
|
564
|
+
}
|
|
565
|
+
for (const [docLine, lineFixes] of byLine) {
|
|
566
|
+
if (!Number.isInteger(docLine) || docLine < 1 || docLine > lines.length) {
|
|
567
|
+
for (const f of lineFixes) skipped.push({ ref: f.ref, reason: `docLine=${docLine} 越界(文档共 ${lines.length} 行)` })
|
|
568
|
+
continue
|
|
569
|
+
}
|
|
570
|
+
const li = docLine - 1
|
|
571
|
+
const located = []
|
|
572
|
+
let cursor = 0
|
|
573
|
+
for (const f of lineFixes) {
|
|
574
|
+
// 找不到 ref 串、或两次命中同一偏移(重复 fix),该条目跳过不中断批量
|
|
575
|
+
const at = lines[li].indexOf(f.ref, cursor)
|
|
576
|
+
if (at === -1) {
|
|
577
|
+
skipped.push({ ref: f.ref, reason: `docLine=${docLine} 行内未找到引用串` })
|
|
578
|
+
} else {
|
|
579
|
+
located.push({ at, f })
|
|
580
|
+
cursor = at + f.ref.length
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
located.sort((a, b) => b.at - a.at) // 降序:后位先替换,前序替换不挤偏后序偏移
|
|
584
|
+
let line = lines[li]
|
|
585
|
+
for (const { at, f } of located) {
|
|
586
|
+
line = line.slice(0, at) + f.newRef + line.slice(at + f.ref.length)
|
|
587
|
+
applied++
|
|
588
|
+
}
|
|
589
|
+
if (located.length > 0) {
|
|
590
|
+
lines[li] = line
|
|
591
|
+
dirty = true
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
if (dirty && !dryRun) writeFileSync(docAbs, lines.join(eol))
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
return { applied, skipped }
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// ---------------------------------------------------------------------------
|
|
602
|
+
// 决策规则族(advisory,change: 2026-08-23-adopt-harness-practices task-05,FR-06 / D-003@v1)
|
|
603
|
+
//
|
|
604
|
+
// 校验对象:knowledge/decisions/<模块域>.md 的 D-xxx@vN 条目(producer = decision-distill
|
|
605
|
+
// 归档提炼,条目字段行 状态/锚点/最近确认 是本处的机械解析契约)。两项规则:
|
|
606
|
+
// 1) 锚点校验:implemented 条目「锚点:src/…」路径存在性(锚点:未记录 → 补录提示,非失效);
|
|
607
|
+
// 2) behind 复核:锚定模块源码在「最近确认」commit 后的前进数超阈值 → 决策待复核提示
|
|
608
|
+
// (computeModuleBehind 复用 docs-debt 既有 git 口径,C-10)。
|
|
609
|
+
// 铁律(docs-consistency 模块卡):advisory 只 warn 不进 runDocsCheck 的 invalid 阻断链——
|
|
610
|
+
// ok/invalid 判定与 docs gate 阻断行为不受影响;校验链路只读零写盘;无 decisions 库 /
|
|
611
|
+
// 无超阈 → findings 空(无信号零输出)。豁免走 known_failures 新键 decisions.* 命名空间
|
|
612
|
+
// (C-17:条目级语义键匹配,不复用 docs-gate 的 baseline ratchet)。
|
|
613
|
+
// ---------------------------------------------------------------------------
|
|
614
|
+
|
|
615
|
+
/** behind 复核缺省阈值(local.yaml decisions.behind_threshold 可调;schema 注册归 task-11,
|
|
616
|
+
* 本处读键按「存在则读、不存在用缺省」容错,不依赖 schema 注册)。dogfood 校准前取 10。 */
|
|
617
|
+
export const DECISIONS_DEFAULT_BEHIND_THRESHOLD = 10
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* known_failures 键提取——读法逐字对齐 verify-postcheck.extractKnownFailures(块式 + 流式,
|
|
621
|
+
* 剥引号/行内注释,CRLF 归一;注释互指防两处口径漂移)。此处独立复刻不 import
|
|
622
|
+
* verify-postcheck(重模块静态依赖;本模块仅消费 decisions.* 前缀键,见 isDecisionExempt)。
|
|
623
|
+
* @param {string} yamlText local.yaml 全文
|
|
624
|
+
* @returns {string[]} 键列表;无声明返回 []
|
|
625
|
+
*/
|
|
626
|
+
function extractKnownFailureKeys(yamlText) {
|
|
627
|
+
if (!yamlText) return []
|
|
628
|
+
const yaml = String(yamlText).replace(/\r\n?/g, '\n')
|
|
629
|
+
const inline = yaml.match(/^known_failures:\s*\[([^\]]*)\]\s*(?:#.*)?$/m)
|
|
630
|
+
if (inline) {
|
|
631
|
+
return inline[1].split(',').map(s => s.trim().replace(/^['"]|['"]$/g, '')).filter(Boolean)
|
|
632
|
+
}
|
|
633
|
+
const block = yaml.match(/^known_failures:\s*\n((?:[ \t]+-[ \t].+\n?)+)/m)
|
|
634
|
+
if (block) {
|
|
635
|
+
return (block[1].match(/^[ \t]+-[ \t]+(.+)/gm) || [])
|
|
636
|
+
.map(s => s.replace(/^[ \t]+-[ \t]+/, '').trim().replace(/^['"]|['"]$/g, '').replace(/#.*$/, '').trim())
|
|
637
|
+
.filter(Boolean)
|
|
638
|
+
}
|
|
639
|
+
return []
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* 读 local.yaml 的决策规则配置(best-effort 绝不抛;读取模式与 readDocsCheckConfig 一致:
|
|
644
|
+
* 缺文件/无段 → 全缺省)。decisions.behind_threshold 存在则读(数值校验),不存在用缺省 10
|
|
645
|
+
* ——schema 注册(config-schema.js)归 task-11,本处不依赖。
|
|
646
|
+
* @param {string} projectRoot 源码仓根(local.yaml 在 <root>/.sillyspec/local.yaml)
|
|
647
|
+
* @returns {{ behindThreshold: number, knownFailures: string[] }}
|
|
648
|
+
*/
|
|
649
|
+
export function readDecisionRulesConfig(projectRoot) {
|
|
650
|
+
const fallback = { behindThreshold: DECISIONS_DEFAULT_BEHIND_THRESHOLD, knownFailures: [] }
|
|
651
|
+
try {
|
|
652
|
+
const p = join(projectRoot, '.sillyspec', 'local.yaml')
|
|
653
|
+
if (!existsSync(p)) return fallback
|
|
654
|
+
const raw = readFileSync(p, 'utf8')
|
|
655
|
+
const knownFailures = extractKnownFailureKeys(raw)
|
|
656
|
+
const doc = jsYaml.load(raw)
|
|
657
|
+
if (!doc || typeof doc !== 'object') return { ...fallback, knownFailures }
|
|
658
|
+
const d = doc['decisions']
|
|
659
|
+
if (!d || typeof d !== 'object' || Array.isArray(d)) return { ...fallback, knownFailures }
|
|
660
|
+
const t = d['behind_threshold']
|
|
661
|
+
return {
|
|
662
|
+
behindThreshold: typeof t === 'number' && Number.isFinite(t) && t > 0 ? t : fallback.behindThreshold,
|
|
663
|
+
knownFailures,
|
|
664
|
+
}
|
|
665
|
+
} catch {
|
|
666
|
+
return fallback
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/** 豁免键匹配(本变更范围先支持键匹配,非子串):规则级 `decisions.<id>.<kind>` 精确命中,
|
|
671
|
+
* 或条目级 `decisions.<id>` 伞形命中(一条豁免该决策全部规则)。无 decisions. 前缀的键不参与。 */
|
|
672
|
+
function isDecisionExempt(knownFailures, entryId, kind) {
|
|
673
|
+
const ruleKey = `decisions.${entryId}.${kind}`
|
|
674
|
+
const entryKey = `decisions.${entryId}`
|
|
675
|
+
return knownFailures.some(k => k === ruleKey || k === entryKey)
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* 纯函数:解析 knowledge/decisions/<域>.md 的 D-xxx@vN 条目(与 decision-distill.renderBlockLines
|
|
680
|
+
* 的写入契约对偶:producer=decision-distill → consumer=本规则族;字段行非列表项,顶层
|
|
681
|
+
* 「状态:/锚点:/最近确认:」标签精确匹配,防误吞正文)。旧格式字段缺失容错为 null。
|
|
682
|
+
* @param {string} md 域文件全文
|
|
683
|
+
* @returns {Array<{ id: string, title: string, status: string|null, anchor: string|null, lastConfirmed: string|null }>}
|
|
684
|
+
*/
|
|
685
|
+
export function parseDecisionEntries(md) {
|
|
686
|
+
const entries = []
|
|
687
|
+
let cur = null
|
|
688
|
+
const flush = () => { if (cur) entries.push(cur) }
|
|
689
|
+
for (const line of String(md || '').replace(/\r\n?/g, '\n').split('\n')) {
|
|
690
|
+
const h = line.match(/^##\s+(D-\d+)(?:@v(\d+))?\s*(.*)$/)
|
|
691
|
+
if (h) {
|
|
692
|
+
flush()
|
|
693
|
+
const version = h[2] ? parseInt(h[2], 10) : 1
|
|
694
|
+
cur = { id: `${h[1]}@v${version}`, title: h[3].trim(), status: null, anchor: null, lastConfirmed: null }
|
|
695
|
+
continue
|
|
696
|
+
}
|
|
697
|
+
if (!cur) continue
|
|
698
|
+
const f = line.match(/^(状态|锚点|最近确认)\s*[::]\s*(.*)$/)
|
|
699
|
+
if (!f) continue
|
|
700
|
+
if (f[1] === '状态') cur.status = f[2].trim().split(/[\s((]/)[0] || null
|
|
701
|
+
else if (f[1] === '锚点') cur.anchor = f[2].trim()
|
|
702
|
+
else cur.lastConfirmed = f[2].trim()
|
|
703
|
+
}
|
|
704
|
+
flush()
|
|
705
|
+
return entries
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/** 锚点值 → 源码路径:剥「:行号 / :行号-行号 / :符号」后缀(锚点契约 `<src 路径>:<行号或符号>`;
|
|
709
|
+
* 旧条目可能只写路径)。「未记录」/空 → null(补录提示路径,非失效)。
|
|
710
|
+
* export(2026-08-24-decision-touch-cli-drift task-01):docs-debt.computeDecisionTouches
|
|
711
|
+
* 复用同一剥离口径(勿复刻正则防两处漂移);仅加关键字,行为不变。 */
|
|
712
|
+
export function anchorFilePath(anchor) {
|
|
713
|
+
const a = String(anchor || '').trim()
|
|
714
|
+
if (!a || a === '未记录') return null
|
|
715
|
+
return a.replace(/:(?:\d+(?:-\d+)?|[A-Za-z_$][A-Za-z0-9_$]*)$/, '').replace(/\\/g, '/') || null
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/** specBase/docs 下任一项目的 modules/_module-map.yaml 尽力发现(对齐
|
|
719
|
+
* decision-distill.discoverModuleIndex 口径:首个命中;失败 → null,域模块源码集退化为锚点文件兜底)。 */
|
|
720
|
+
function discoverModuleMapIndex(specBase) {
|
|
721
|
+
try {
|
|
722
|
+
const docsDir = join(specBase, 'docs')
|
|
723
|
+
if (!existsSync(docsDir)) return null
|
|
724
|
+
for (const d of readdirSync(docsDir, { withFileTypes: true })) {
|
|
725
|
+
if (!d.isDirectory()) continue
|
|
726
|
+
const mapPath = join(docsDir, d.name, 'modules', '_module-map.yaml')
|
|
727
|
+
if (existsSync(mapPath)) return parseModuleMapSimple(readFileSync(mapPath, 'utf8'))
|
|
728
|
+
}
|
|
729
|
+
} catch { /* 尽力而为,失败归 null */ }
|
|
730
|
+
return null
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
/**
|
|
734
|
+
* IO 入口(advisory):跑一次决策规则族。只产出 findings(warn 语义),不进 runDocsCheck 的
|
|
735
|
+
* invalid 阻断链、不写任何文件——无 decisions 库 / 无信号 → findings 空(零输出)。
|
|
736
|
+
* computeModuleBehind 经动态 import 取自 docs-debt(本模块被 docs-debt 静态 import,静态互引
|
|
737
|
+
* 成 ESM 环——对齐 run/shared.js 对 docs-debt 的动态 import 先例)。
|
|
738
|
+
* @param {{ projectRoot: string, specBase?: string, behindThreshold?: number, knownFailures?: string[], moduleIndex?: object|null }} opts
|
|
739
|
+
* projectRoot 源码仓根(锚点解析与 git 锚);specBase 缺省 = <projectRoot>/.sillyspec;
|
|
740
|
+
* behindThreshold / knownFailures 缺省读 local.yaml(decisions.behind_threshold / known_failures);
|
|
741
|
+
* moduleIndex 缺省按 specBase/docs 下任一项目的 modules/_module-map.yaml 尽力发现
|
|
742
|
+
* @returns {Promise<{ empty: boolean, domains: number, entries: number, implemented: number,
|
|
743
|
+
* threshold: number, findings: Array<{ id: string, domain: string, file: string,
|
|
744
|
+
* kind: 'anchor'|'behind', behind?: number|null, threshold?: number, anchor?: string|null,
|
|
745
|
+
* message: string }>, exempted: Array<{ key: string, id: string, kind: string }> }>}
|
|
746
|
+
* empty=true = decisions 库不存在(冷启动,R-02 由 doctor 层提示);exempted 为经
|
|
747
|
+
* known_failures decisions.* 键豁免的条目(披露不隐藏)
|
|
748
|
+
*/
|
|
749
|
+
export async function runDecisionRules(opts) {
|
|
750
|
+
const { projectRoot, specBase, behindThreshold = null, knownFailures = null, moduleIndex = null } = opts || {}
|
|
751
|
+
const emptyResult = (threshold) => ({ empty: true, domains: 0, entries: 0, implemented: 0, threshold, findings: [], exempted: [] })
|
|
752
|
+
if (!projectRoot) return emptyResult(DECISIONS_DEFAULT_BEHIND_THRESHOLD)
|
|
753
|
+
|
|
754
|
+
const cfg = readDecisionRulesConfig(projectRoot)
|
|
755
|
+
const threshold = typeof behindThreshold === 'number' && Number.isFinite(behindThreshold) && behindThreshold > 0
|
|
756
|
+
? behindThreshold
|
|
757
|
+
: cfg.behindThreshold
|
|
758
|
+
const failures = Array.isArray(knownFailures) ? knownFailures : cfg.knownFailures
|
|
759
|
+
|
|
760
|
+
const kb = specBase || join(projectRoot, '.sillyspec')
|
|
761
|
+
const decisionsDir = join(kb, 'knowledge', 'decisions')
|
|
762
|
+
let domainFiles = []
|
|
763
|
+
try {
|
|
764
|
+
domainFiles = readdirSync(decisionsDir).filter(f => f.endsWith('.md')).sort()
|
|
765
|
+
} catch {
|
|
766
|
+
return emptyResult(threshold) // 库不存在 → 零信号(doctor 层另行提示空库)
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// 模块域 → 源码路径集(module-map paths∪core_files;未命中 map 的域退化为锚点文件兜底)
|
|
770
|
+
const mapIndex = moduleIndex || discoverModuleMapIndex(kb)
|
|
771
|
+
const flatIndex = mapIndex && mapIndex.modules ? mapIndex.modules : mapIndex
|
|
772
|
+
const { computeModuleBehind } = await import('./docs-debt.js')
|
|
773
|
+
|
|
774
|
+
const findings = []
|
|
775
|
+
const exempted = []
|
|
776
|
+
let entriesTotal = 0
|
|
777
|
+
let implementedTotal = 0
|
|
778
|
+
const treeCache = new Map() // resolveCandidates 全树扫描复用(同 docs check 主链路口径)
|
|
779
|
+
|
|
780
|
+
const emit = (id, domain, file, kind, extra, message) => {
|
|
781
|
+
if (isDecisionExempt(failures, id, kind)) {
|
|
782
|
+
exempted.push({ key: `decisions.${id}.${kind}`, id, kind })
|
|
783
|
+
return
|
|
784
|
+
}
|
|
785
|
+
findings.push({ id, domain, file, kind, ...extra, message })
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
for (const f of domainFiles) {
|
|
789
|
+
const domain = f.replace(/\.md$/, '')
|
|
790
|
+
const rel = `knowledge/decisions/${f}`
|
|
791
|
+
let entries
|
|
792
|
+
try { entries = parseDecisionEntries(readFileSync(join(decisionsDir, f), 'utf8')) } catch { continue }
|
|
793
|
+
for (const e of entries) {
|
|
794
|
+
entriesTotal++
|
|
795
|
+
if ((e.status || '').toLowerCase() !== 'implemented') continue // rejected/未知状态不做锚点与 behind 校验
|
|
796
|
+
implementedTotal++
|
|
797
|
+
const anchorPath = anchorFilePath(e.anchor)
|
|
798
|
+
// 规则 1:锚点存在性(未记录 → 补录提示;路径不存在 → 失效提示)
|
|
799
|
+
if (!anchorPath) {
|
|
800
|
+
emit(e.id, domain, rel, 'anchor', { anchor: e.anchor || null },
|
|
801
|
+
`「${e.id}」锚点未记录(${rel})——旧格式条目,补「锚点:src/…」后可机械校验(advisory)`)
|
|
802
|
+
} else if (resolveCandidates(projectRoot, anchorPath, treeCache).length === 0) {
|
|
803
|
+
emit(e.id, domain, rel, 'anchor', { anchor: e.anchor },
|
|
804
|
+
`「${e.id}」锚点文件不存在:${anchorPath}(${rel})——决策落点已漂移,人工复核(advisory)`)
|
|
805
|
+
}
|
|
806
|
+
// 规则 2:behind 复核(「最近确认」后锚定模块源码前进数超阈值 → 决策待复核;
|
|
807
|
+
// 「最近确认」未记录/域无源码集(无 map 无锚点)→ 无法计算,静默跳过——advisory 不产噪声)
|
|
808
|
+
if (!e.lastConfirmed || !/^[0-9a-f]{4,40}$/i.test(e.lastConfirmed)) continue
|
|
809
|
+
let srcPaths = null
|
|
810
|
+
const m = flatIndex && typeof flatIndex === 'object' ? flatIndex[domain] : null
|
|
811
|
+
if (m) srcPaths = [...(Array.isArray(m.paths) ? m.paths : []), ...(Array.isArray(m.core_files) ? m.core_files : [])]
|
|
812
|
+
if ((!srcPaths || srcPaths.length === 0) && anchorPath) srcPaths = [anchorPath]
|
|
813
|
+
if (!srcPaths || srcPaths.length === 0) continue
|
|
814
|
+
const { behind } = computeModuleBehind(domain, e.lastConfirmed, { projectRoot, srcPaths })
|
|
815
|
+
if (behind !== null && behind > threshold) {
|
|
816
|
+
emit(e.id, domain, rel, 'behind', { behind, threshold },
|
|
817
|
+
`「${e.id}」决策待复核:锚定模块 ${domain} 在最近确认 ${e.lastConfirmed} 后源码已前进 ${behind} commit,超阈值 ${threshold}(${rel})——复核后更新「最近确认」`)
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
findings.sort((a, b) => a.file.localeCompare(b.file) || a.id.localeCompare(b.id))
|
|
823
|
+
exempted.sort((a, b) => a.key.localeCompare(b.key))
|
|
824
|
+
return { empty: false, domains: domainFiles.length, entries: entriesTotal, implemented: implementedTotal, threshold, findings, exempted }
|
|
825
|
+
}
|