sillyspec 3.27.2 → 3.27.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/sillyspec-execute/SKILL.md +8 -0
- package/.claude/skills/sillyspec-quick/SKILL.md +2 -1
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-archive/SKILL.md +87 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-auto/SKILL.md +93 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-commit/SKILL.md +67 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-continue/SKILL.md +47 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-execute/SKILL.md +214 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-explore/SKILL.md +102 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-export/SKILL.md +57 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-init/SKILL.md +177 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-plan/SKILL.md +156 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-quick/SKILL.md +116 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-resume/SKILL.md +70 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-scan/SKILL.md +79 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-state/SKILL.md +64 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-status/SKILL.md +54 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-verify/SKILL.md +87 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
- package/.claude/worktrees/sillyspec-data-model-research/.gitattributes +2 -0
- package/.claude/worktrees/sillyspec-data-model-research/.husky/pre-push +20 -0
- package/.claude/worktrees/sillyspec-data-model-research/README.md +203 -0
- package/.claude/worktrees/sillyspec-data-model-research/SKILL.md +91 -0
- package/.claude/worktrees/sillyspec-data-model-research/bin/sillyspec.js +2 -0
- package/.claude/worktrees/sillyspec-data-model-research/logo.jpg +0 -0
- package/.claude/worktrees/sillyspec-data-model-research/package-lock.json +977 -0
- package/.claude/worktrees/sillyspec-data-model-research/package.json +39 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/favicon.jpg +0 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/index.html +16 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/logo.jpg +0 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/prototype-dashboard.html +836 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/prototype-overview.html +256 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/package.json +25 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/executor.js +95 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/index.js +679 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/parser.js +526 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/watcher.js +357 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/agent-session-log.js +803 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/change-list.js +290 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/change-risk-profile.js +270 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/check-primitives.js +65 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/classify-change.js +109 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/commit-suggest.js +202 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/config-cat.js +88 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/config-schema.js +328 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/constants.js +97 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/contract-matrix.js +480 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/datetime.js +20 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/db-engine.js +55 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/db.js +381 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/decision-distill.js +517 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/backends/local-agent.js +155 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/backends/sillyhub-mcp.js +245 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/probe.js +246 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/strategy.js +121 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/docs-check.js +825 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/docs-debt.js +393 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/docs-gate.js +107 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/doctor-diagnostics.js +1099 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/endpoint-extractor.js +420 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/foreign-declared.js +78 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/fs-atomic.js +73 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/git-helper.js +150 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/hooks/claude-pre-tool-use.cjs +130 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/hooks/worktree-guard.js +892 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/index.js +2798 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/init.js +626 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/knowledge-match.js +231 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/local-detect.js +128 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/local-register.js +104 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/machine-interface.js +543 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/migrate.js +127 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/module-impact.js +166 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/module-resolve.js +222 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/modules.js +580 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/progress/change-registry.js +336 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/progress/consistency-doctor.js +355 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/progress/shared.js +36 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/progress/stage-machine.js +594 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/progress/step-store.js +265 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/progress.js +1304 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/quick-recommend.js +115 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/quicklog.js +852 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/review-tier.js +77 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/command.js +1595 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/complete-handlers.js +1552 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/complete.js +1259 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/concurrent-detect.js +156 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/gates.js +1084 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/multi-repo-context.js +208 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/next.js +128 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/prompt.js +843 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/quick-audit.js +186 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/scan-profile.js +269 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/shared.js +1562 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/stage.js +584 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run.js +23 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/scan-diff.js +388 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/scan-postcheck.js +512 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/scan-staleness.js +95 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/setup.js +414 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/sillyhub-mcp/client.js +597 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/sillyhub-mcp/config.js +62 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/spec-dir-typo.js +50 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/spec-sync.js +358 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract-engine.js +171 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract-spec.js +550 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract.js +889 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stage-review.js +597 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/archive.js +199 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/brainstorm-auto.js +236 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/brainstorm.js +617 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/cmd-existence.js +145 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/doctor.js +540 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/execute.js +1275 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/explore.js +43 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/index.js +29 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/knowledge.js +514 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/plan-postcheck.js +1344 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/plan.js +650 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/quick.js +167 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/scan.js +608 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/status.js +64 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/verify.js +246 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/sync.js +1470 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/task-review.js +1498 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/taskcard.js +210 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/verify-postcheck.js +1718 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/verify-probes.js +277 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/version.js +19 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/workflow.js +600 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/workspace.js +125 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/worktree-apply.js +1446 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/worktree-deps.js +576 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/worktree.js +1715 -0
- package/.claude/worktrees/sillyspec-data-model-research/templates/claude-instruction.md +23 -0
- package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/taskcard-rules.md +28 -0
- package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/testcase-design.md +12 -0
- package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/verify-probes.md +32 -0
- package/.claude/worktrees/sillyspec-data-model-research/templates/workflows/archive-impact.yaml +79 -0
- package/.claude/worktrees/sillyspec-data-model-research/templates/workflows/scan-docs.yaml +132 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-archive/SKILL.md +87 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-auto/SKILL.md +93 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-commit/SKILL.md +67 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-continue/SKILL.md +47 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-execute/SKILL.md +214 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-explore/SKILL.md +102 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-export/SKILL.md +57 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-init/SKILL.md +177 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-plan/SKILL.md +156 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-propose/SKILL.md +87 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-quick/SKILL.md +116 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-resume/SKILL.md +70 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-scan/SKILL.md +79 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-state/SKILL.md +64 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-status/SKILL.md +54 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-verify/SKILL.md +87 -0
- package/.worktrees/8d2d0392/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
- package/.worktrees/8d2d0392/.claude/skills/verify-per-user/SKILL.md +6 -0
- package/.worktrees/8d2d0392/.gitattributes +2 -0
- package/.worktrees/8d2d0392/.husky/pre-push +20 -0
- package/.worktrees/8d2d0392/README.md +203 -0
- package/.worktrees/8d2d0392/SKILL.md +91 -0
- package/.worktrees/8d2d0392/architecture-analysis.md +448 -0
- package/.worktrees/8d2d0392/bin/sillyspec.js +2 -0
- package/.worktrees/8d2d0392/eval/README.md +86 -0
- package/.worktrees/8d2d0392/eval/eval.config.json +28 -0
- package/.worktrees/8d2d0392/eval/lib/adapters/cli.mjs +63 -0
- package/.worktrees/8d2d0392/eval/lib/adapters/dryrun.mjs +27 -0
- package/.worktrees/8d2d0392/eval/lib/config.mjs +82 -0
- package/.worktrees/8d2d0392/eval/lib/db.mjs +76 -0
- package/.worktrees/8d2d0392/eval/lib/report.mjs +120 -0
- package/.worktrees/8d2d0392/eval/lib/runner.mjs +157 -0
- package/.worktrees/8d2d0392/eval/lib/tasks.mjs +73 -0
- package/.worktrees/8d2d0392/eval/lib/util.mjs +107 -0
- package/.worktrees/8d2d0392/eval/lib/workdir.mjs +30 -0
- package/.worktrees/8d2d0392/eval/run.mjs +83 -0
- package/.worktrees/8d2d0392/eval/tasks/001-slugify/files/package.json +6 -0
- package/.worktrees/8d2d0392/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
- package/.worktrees/8d2d0392/eval/tasks/001-slugify/task.json +6 -0
- package/.worktrees/8d2d0392/eval/tasks/001-slugify/verify.mjs +28 -0
- package/.worktrees/8d2d0392/eval/tasks/002-each-day/files/package.json +6 -0
- package/.worktrees/8d2d0392/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
- package/.worktrees/8d2d0392/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
- package/.worktrees/8d2d0392/eval/tasks/002-each-day/task.json +6 -0
- package/.worktrees/8d2d0392/eval/tasks/002-each-day/verify.mjs +31 -0
- package/.worktrees/8d2d0392/eval/tasks/003-word-report/files/data/notes.txt +5 -0
- package/.worktrees/8d2d0392/eval/tasks/003-word-report/files/package.json +6 -0
- package/.worktrees/8d2d0392/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
- package/.worktrees/8d2d0392/eval/tasks/003-word-report/task.json +6 -0
- package/.worktrees/8d2d0392/eval/tasks/003-word-report/verify.mjs +38 -0
- package/.worktrees/8d2d0392/logo.jpg +0 -0
- package/.worktrees/8d2d0392/package-lock.json +977 -0
- package/.worktrees/8d2d0392/package.json +41 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/favicon.jpg +0 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/index.html +16 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/logo.jpg +0 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/prototype-dashboard.html +836 -0
- package/.worktrees/8d2d0392/packages/dashboard/dist/prototype-overview.html +256 -0
- package/.worktrees/8d2d0392/packages/dashboard/package.json +25 -0
- package/.worktrees/8d2d0392/packages/dashboard/server/executor.js +95 -0
- package/.worktrees/8d2d0392/packages/dashboard/server/index.js +679 -0
- package/.worktrees/8d2d0392/packages/dashboard/server/parser.js +526 -0
- package/.worktrees/8d2d0392/packages/dashboard/server/watcher.js +357 -0
- package/.worktrees/8d2d0392/src/agent-session-log.js +803 -0
- package/.worktrees/8d2d0392/src/change-list.js +290 -0
- package/.worktrees/8d2d0392/src/change-risk-profile.js +339 -0
- package/.worktrees/8d2d0392/src/check-primitives.js +65 -0
- package/.worktrees/8d2d0392/src/classify-change.js +109 -0
- package/.worktrees/8d2d0392/src/commit-suggest.js +202 -0
- package/.worktrees/8d2d0392/src/config-cat.js +88 -0
- package/.worktrees/8d2d0392/src/config-schema.js +328 -0
- package/.worktrees/8d2d0392/src/constants.js +97 -0
- package/.worktrees/8d2d0392/src/contract-matrix.js +533 -0
- package/.worktrees/8d2d0392/src/datetime.js +20 -0
- package/.worktrees/8d2d0392/src/db-engine.js +55 -0
- package/.worktrees/8d2d0392/src/db.js +381 -0
- package/.worktrees/8d2d0392/src/decision-distill.js +517 -0
- package/.worktrees/8d2d0392/src/dispatch/backends/local-agent.js +155 -0
- package/.worktrees/8d2d0392/src/dispatch/backends/sillyhub-mcp.js +245 -0
- package/.worktrees/8d2d0392/src/dispatch/probe.js +246 -0
- package/.worktrees/8d2d0392/src/dispatch/strategy.js +121 -0
- package/.worktrees/8d2d0392/src/docs-check.js +825 -0
- package/.worktrees/8d2d0392/src/docs-debt.js +393 -0
- package/.worktrees/8d2d0392/src/docs-gate.js +107 -0
- package/.worktrees/8d2d0392/src/doctor-diagnostics.js +1099 -0
- package/.worktrees/8d2d0392/src/endpoint-extractor.js +409 -0
- package/.worktrees/8d2d0392/src/foreign-declared.js +78 -0
- package/.worktrees/8d2d0392/src/fs-atomic.js +73 -0
- package/.worktrees/8d2d0392/src/git-helper.js +150 -0
- package/.worktrees/8d2d0392/src/hooks/claude-pre-tool-use.cjs +130 -0
- package/.worktrees/8d2d0392/src/hooks/worktree-guard.js +892 -0
- package/.worktrees/8d2d0392/src/index.js +2854 -0
- package/.worktrees/8d2d0392/src/init.js +626 -0
- package/.worktrees/8d2d0392/src/knowledge-match.js +231 -0
- package/.worktrees/8d2d0392/src/local-detect.js +128 -0
- package/.worktrees/8d2d0392/src/local-register.js +104 -0
- package/.worktrees/8d2d0392/src/machine-interface.js +543 -0
- package/.worktrees/8d2d0392/src/migrate.js +127 -0
- package/.worktrees/8d2d0392/src/module-impact.js +166 -0
- package/.worktrees/8d2d0392/src/module-resolve.js +222 -0
- package/.worktrees/8d2d0392/src/modules.js +580 -0
- package/.worktrees/8d2d0392/src/plan-adopt-waves.js +126 -0
- package/.worktrees/8d2d0392/src/progress/change-registry.js +336 -0
- package/.worktrees/8d2d0392/src/progress/consistency-doctor.js +355 -0
- package/.worktrees/8d2d0392/src/progress/shared.js +36 -0
- package/.worktrees/8d2d0392/src/progress/stage-machine.js +594 -0
- package/.worktrees/8d2d0392/src/progress/step-store.js +265 -0
- package/.worktrees/8d2d0392/src/progress.js +1304 -0
- package/.worktrees/8d2d0392/src/quick-recommend.js +115 -0
- package/.worktrees/8d2d0392/src/quicklog.js +883 -0
- package/.worktrees/8d2d0392/src/review-tier.js +77 -0
- package/.worktrees/8d2d0392/src/run/command.js +1641 -0
- package/.worktrees/8d2d0392/src/run/complete-handlers.js +1552 -0
- package/.worktrees/8d2d0392/src/run/complete.js +1259 -0
- package/.worktrees/8d2d0392/src/run/concurrent-detect.js +156 -0
- package/.worktrees/8d2d0392/src/run/gates.js +1094 -0
- package/.worktrees/8d2d0392/src/run/multi-repo-context.js +208 -0
- package/.worktrees/8d2d0392/src/run/next.js +128 -0
- package/.worktrees/8d2d0392/src/run/prompt.js +843 -0
- package/.worktrees/8d2d0392/src/run/quick-audit.js +186 -0
- package/.worktrees/8d2d0392/src/run/scan-profile.js +269 -0
- package/.worktrees/8d2d0392/src/run/shared.js +1562 -0
- package/.worktrees/8d2d0392/src/run/stage.js +587 -0
- package/.worktrees/8d2d0392/src/run.js +23 -0
- package/.worktrees/8d2d0392/src/scan-diff.js +388 -0
- package/.worktrees/8d2d0392/src/scan-postcheck.js +524 -0
- package/.worktrees/8d2d0392/src/scan-staleness.js +95 -0
- package/.worktrees/8d2d0392/src/setup.js +414 -0
- package/.worktrees/8d2d0392/src/sillyhub-mcp/client.js +597 -0
- package/.worktrees/8d2d0392/src/sillyhub-mcp/config.js +62 -0
- package/.worktrees/8d2d0392/src/spec-dir-typo.js +50 -0
- package/.worktrees/8d2d0392/src/spec-sync.js +358 -0
- package/.worktrees/8d2d0392/src/stage-contract-engine.js +171 -0
- package/.worktrees/8d2d0392/src/stage-contract-spec.js +551 -0
- package/.worktrees/8d2d0392/src/stage-contract.js +948 -0
- package/.worktrees/8d2d0392/src/stage-review.js +597 -0
- package/.worktrees/8d2d0392/src/stages/archive.js +199 -0
- package/.worktrees/8d2d0392/src/stages/brainstorm-auto.js +285 -0
- package/.worktrees/8d2d0392/src/stages/brainstorm.js +624 -0
- package/.worktrees/8d2d0392/src/stages/cmd-existence.js +145 -0
- package/.worktrees/8d2d0392/src/stages/doctor.js +540 -0
- package/.worktrees/8d2d0392/src/stages/execute.js +1277 -0
- package/.worktrees/8d2d0392/src/stages/explore.js +43 -0
- package/.worktrees/8d2d0392/src/stages/index.js +29 -0
- package/.worktrees/8d2d0392/src/stages/knowledge.js +514 -0
- package/.worktrees/8d2d0392/src/stages/plan-postcheck.js +1398 -0
- package/.worktrees/8d2d0392/src/stages/plan.js +651 -0
- package/.worktrees/8d2d0392/src/stages/quick.js +167 -0
- package/.worktrees/8d2d0392/src/stages/scan.js +608 -0
- package/.worktrees/8d2d0392/src/stages/status.js +64 -0
- package/.worktrees/8d2d0392/src/stages/verify.js +246 -0
- package/.worktrees/8d2d0392/src/sync.js +1470 -0
- package/.worktrees/8d2d0392/src/task-review.js +1498 -0
- package/.worktrees/8d2d0392/src/taskcard-placeholders.js +21 -0
- package/.worktrees/8d2d0392/src/taskcard.js +217 -0
- package/.worktrees/8d2d0392/src/verify-postcheck.js +1718 -0
- package/.worktrees/8d2d0392/src/verify-probes.js +327 -0
- package/.worktrees/8d2d0392/src/version.js +19 -0
- package/.worktrees/8d2d0392/src/workflow.js +600 -0
- package/.worktrees/8d2d0392/src/workspace.js +125 -0
- package/.worktrees/8d2d0392/src/worktree-apply.js +1611 -0
- package/.worktrees/8d2d0392/src/worktree-deps.js +576 -0
- package/.worktrees/8d2d0392/src/worktree.js +1838 -0
- package/.worktrees/8d2d0392/templates/claude-instruction.md +23 -0
- package/.worktrees/8d2d0392/templates/prompts/taskcard-rules.md +29 -0
- package/.worktrees/8d2d0392/templates/prompts/testcase-design.md +12 -0
- package/.worktrees/8d2d0392/templates/prompts/verify-probes.md +32 -0
- package/.worktrees/8d2d0392/templates/workflows/archive-impact.yaml +79 -0
- package/.worktrees/8d2d0392/templates/workflows/scan-docs.yaml +132 -0
- package/architecture-analysis.md +448 -0
- package/eval/README.md +86 -0
- package/eval/eval.config.json +28 -0
- package/eval/lib/adapters/cli.mjs +63 -0
- package/eval/lib/adapters/dryrun.mjs +27 -0
- package/eval/lib/config.mjs +82 -0
- package/eval/lib/db.mjs +76 -0
- package/eval/lib/report.mjs +120 -0
- package/eval/lib/runner.mjs +157 -0
- package/eval/lib/tasks.mjs +73 -0
- package/eval/lib/util.mjs +107 -0
- package/eval/lib/workdir.mjs +30 -0
- package/eval/run.mjs +83 -0
- package/eval/tasks/001-slugify/files/package.json +6 -0
- package/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
- package/eval/tasks/001-slugify/task.json +6 -0
- package/eval/tasks/001-slugify/verify.mjs +28 -0
- package/eval/tasks/002-each-day/files/package.json +6 -0
- package/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
- package/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
- package/eval/tasks/002-each-day/task.json +6 -0
- package/eval/tasks/002-each-day/verify.mjs +31 -0
- package/eval/tasks/003-word-report/files/data/notes.txt +5 -0
- package/eval/tasks/003-word-report/files/package.json +6 -0
- package/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
- package/eval/tasks/003-word-report/task.json +6 -0
- package/eval/tasks/003-word-report/verify.mjs +38 -0
- package/package.json +4 -2
- package/src/agent-session-log.js +45 -5
- package/src/change-risk-profile.js +83 -14
- package/src/config-schema.js +18 -3
- package/src/contract-matrix.js +90 -29
- package/src/datetime.js +20 -0
- package/src/decision-distill.js +517 -0
- package/src/dispatch/backends/local-agent.js +4 -4
- package/src/docs-check.js +227 -0
- package/src/docs-debt.js +187 -24
- package/src/doctor-diagnostics.js +102 -2
- package/src/endpoint-extractor.js +41 -52
- package/src/foreign-declared.js +155 -0
- package/src/index.js +95 -13
- package/src/init.js +9 -7
- package/src/knowledge-match.js +107 -6
- package/src/local-register.js +7 -1
- package/src/module-resolve.js +12 -1
- package/src/modules.js +2 -1
- package/src/plan-adopt-waves.js +126 -0
- package/src/quicklog.js +50 -4
- package/src/run/command.js +124 -44
- package/src/run/complete-handlers.js +48 -19
- package/src/run/complete.js +5 -2
- package/src/run/gates.js +104 -22
- package/src/run/prompt.js +84 -42
- package/src/run/quick-audit.js +11 -0
- package/src/run/shared.js +152 -10
- package/src/run/stage.js +8 -5
- package/src/run.js +2 -2
- package/src/scan-postcheck.js +30 -17
- package/src/stage-contract-spec.js +3 -2
- package/src/stage-contract.js +68 -4
- package/src/stages/archive.js +53 -12
- package/src/stages/brainstorm-auto.js +50 -1
- package/src/stages/brainstorm.js +13 -0
- package/src/stages/doctor.js +157 -1
- package/src/stages/execute.js +32 -6
- package/src/stages/plan-postcheck.js +76 -17
- package/src/stages/plan.js +9 -4
- package/src/stages/quick.js +6 -1
- package/src/stages/verify.js +32 -15
- package/src/sync.js +41 -3
- package/src/task-review.js +2 -2
- package/src/taskcard-placeholders.js +21 -0
- package/src/taskcard.js +43 -1
- package/src/verify-postcheck.js +315 -13
- package/src/verify-probes.js +73 -10
- package/src/worktree-apply.js +569 -227
- package/src/worktree-deps.js +150 -1
- package/src/worktree.js +285 -77
- package/templates/prompts/taskcard-rules.md +2 -1
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SillySpec A/B 评测入口。
|
|
3
|
+
// A 臂 = 裸 agent 直接做任务;B 臂 = 同 agent + SillySpec 流程。同任务、同模型、同判分脚本(verify.mjs),
|
|
4
|
+
// 差值 Δ 即 SillySpec 的真实增量。详细文档见 eval/README.md。
|
|
5
|
+
import { loadConfig } from './lib/config.mjs';
|
|
6
|
+
import { runEval } from './lib/runner.mjs';
|
|
7
|
+
import { buildReport, printReport, setBaseline } from './lib/report.mjs';
|
|
8
|
+
import { spawnCapture, tail } from './lib/util.mjs';
|
|
9
|
+
|
|
10
|
+
function parseArgs(argv) {
|
|
11
|
+
const opts = {
|
|
12
|
+
dryRun: false, dryMode: 'mixed', taskIds: [], arms: [], sample: 0,
|
|
13
|
+
force: false, onlyFailed: false, report: false, setBaseline: false, preflight: false, help: false,
|
|
14
|
+
};
|
|
15
|
+
for (let i = 0; i < argv.length; i++) {
|
|
16
|
+
const a = argv[i];
|
|
17
|
+
if (a === '--dry-run') opts.dryRun = true;
|
|
18
|
+
else if (a.startsWith('--dry-run=')) { opts.dryRun = true; opts.dryMode = a.slice('--dry-run='.length); }
|
|
19
|
+
else if (a === '--task') opts.taskIds.push(argv[++i]);
|
|
20
|
+
else if (a === '--arm') opts.arms.push(...(argv[++i] ?? '').split(',').map((s) => s.trim().toUpperCase()).filter(Boolean));
|
|
21
|
+
else if (a === '--sample') opts.sample = Number(argv[++i]);
|
|
22
|
+
else if (a === '--pilot') opts.sample = 20; // pilot = 前 20 个任务双臂
|
|
23
|
+
else if (a === '--force') opts.force = true;
|
|
24
|
+
else if (a === '--rerun-failed') opts.onlyFailed = true;
|
|
25
|
+
else if (a === '--report') opts.report = true;
|
|
26
|
+
else if (a === '--set-baseline') opts.setBaseline = true;
|
|
27
|
+
else if (a === '--preflight') opts.preflight = true;
|
|
28
|
+
else if (a === '--help' || a === '-h') opts.help = true;
|
|
29
|
+
else { console.error(`未知参数: ${a}`); opts.help = true; }
|
|
30
|
+
}
|
|
31
|
+
return opts;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function help() {
|
|
35
|
+
console.log(`SillySpec A/B 评测(A=裸 agent,B=SillySpec 流程,verify.mjs 客观判分)
|
|
36
|
+
|
|
37
|
+
用法:node eval/run.mjs <选项>
|
|
38
|
+
|
|
39
|
+
--dry-run[=mixed|pass|fail] 零 token 验证管道(假 agent,不调模型不装依赖)
|
|
40
|
+
--preflight 检查 Node 版本与 agent CLI 可用性(零 token)
|
|
41
|
+
--pilot 真跑 pilot:前 20 个任务 × 双臂(消耗真实 token)
|
|
42
|
+
--task <id> 只跑指定任务(可重复)
|
|
43
|
+
--arm A|B|A,B 只跑指定臂
|
|
44
|
+
--sample <N> 只跑前 N 个任务
|
|
45
|
+
--rerun-failed 只重跑上一轮 fail/timeout/error(省 token 的定向重跑)
|
|
46
|
+
--force 忽略缓存强制重跑
|
|
47
|
+
--report [--dry-run] 查看报告(Wilson CI / Δ / flaky / 基线对比)
|
|
48
|
+
--set-baseline 把当前成绩固化为回归基线(发版前对比用)`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function preflight(config) {
|
|
52
|
+
const major = Number(process.versions.node.split('.')[0]);
|
|
53
|
+
console.log(`Node ${process.version} ${major >= 22 ? '✓' : '✗(eval 需 >= 22,node:sqlite)'}`);
|
|
54
|
+
const bin = config.adapter.command[0];
|
|
55
|
+
const r = await spawnCapture({ args: [bin, '--version'], timeoutMs: 20_000 });
|
|
56
|
+
if (r.code === 0) {
|
|
57
|
+
console.log(`${bin} --version ✓ ${tail(r.stdout, 120)}`);
|
|
58
|
+
} else {
|
|
59
|
+
console.log(`${bin} --version ✗ 不可用(${tail(r.stderr || `exit ${r.code}`, 120)})`);
|
|
60
|
+
console.log(' 提示:先安装该 agent CLI 并在终端手动登录一次;认证沿用其登录态,本评测不接管密钥。');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const opts = parseArgs(process.argv.slice(2));
|
|
65
|
+
if (opts.help) {
|
|
66
|
+
help();
|
|
67
|
+
process.exit(0);
|
|
68
|
+
}
|
|
69
|
+
const config = loadConfig();
|
|
70
|
+
if (opts.preflight) {
|
|
71
|
+
await preflight(config);
|
|
72
|
+
process.exit(0);
|
|
73
|
+
}
|
|
74
|
+
if (opts.report) {
|
|
75
|
+
printReport(config, buildReport(config, opts));
|
|
76
|
+
process.exit(0);
|
|
77
|
+
}
|
|
78
|
+
if (opts.setBaseline) {
|
|
79
|
+
setBaseline(config, opts);
|
|
80
|
+
process.exit(0);
|
|
81
|
+
}
|
|
82
|
+
await runEval(config, opts);
|
|
83
|
+
printReport(config, buildReport(config, opts)); // 跑完顺手出报告
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// 参考解(dry-run 假 agent 使用,也供人工对照)。
|
|
2
|
+
// 思路:空白先归一为 \u0000 哨兵;字符过滤同时保留 [a-z0-9]、哨兵和字面分隔符;
|
|
3
|
+
// 再把「哨兵/分隔符的连续串」折叠为单个分隔符并去首尾。
|
|
4
|
+
// 注意不能只折叠哨兵——输入里本来就有的连续分隔符(如 'a--b')也要折叠。
|
|
5
|
+
const SENTINEL = '\u0000';
|
|
6
|
+
|
|
7
|
+
function escapeRe(ch) {
|
|
8
|
+
return ch.replace(/[.*+?^${}()|[\]\\-]/g, '\\$&');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function slugify(value, options = {}) {
|
|
12
|
+
if (value === null || value === undefined) return '';
|
|
13
|
+
const sep = options.hyphen ?? '-';
|
|
14
|
+
if (typeof sep !== 'string' || sep.length !== 1) {
|
|
15
|
+
throw new TypeError('hyphen must be a single character');
|
|
16
|
+
}
|
|
17
|
+
const esc = escapeRe(sep);
|
|
18
|
+
return String(value)
|
|
19
|
+
.toLowerCase()
|
|
20
|
+
.replace(/\s+/g, SENTINEL)
|
|
21
|
+
.replace(new RegExp(`[^a-z0-9\\u0000${esc}]`, 'g'), '')
|
|
22
|
+
.replace(new RegExp(`[\\u0000${esc}]+`, 'g'), sep)
|
|
23
|
+
.replace(new RegExp(`^${esc}+|${esc}+$`, 'g'), '');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default slugify;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "001-slugify",
|
|
3
|
+
"title": "实现 slugify 工具函数",
|
|
4
|
+
"tags": ["greenfield", "utility", "edge-case"],
|
|
5
|
+
"instruction": "在当前目录新建 src/slugify.mjs(package.json 已存在且 type=module,禁止安装任何第三方依赖),实现并导出具名函数 slugify(同时提供指向同一函数的 default 导出)。\n\n函数签名:slugify(value, options = {}),返回字符串。\n\n转换规则(按顺序执行,分隔符记为 sep,默认 '-'):\n1. value 为 null 或 undefined 时返回空字符串;其余值先 String() 转字符串。\n2. 整体 toLowerCase() 小写化。\n3. 连续空白字符(\\s+)替换为单个 sep。\n4. 删除所有不属于 [a-z0-9] 且不等于 sep 的字符。\n5. 连续多个 sep 合并为一个,并去掉首尾的 sep。\n\noptions 支持:\n- options.hyphen:分隔符 sep,默认 '-'。必须是长度为 1 的字符串,否则抛出 TypeError('hyphen must be a single character')。\n\n示例:\nslugify(' Hello World! ') === 'hello-world'\nslugify('a--b') === 'a-b'\nslugify('Ünïcode Test') === 'ncode-test'\nslugify(null) === ''\nslugify(42) === '42'\nslugify('Hello World', { hyphen: '_' }) === 'hello_world'"
|
|
6
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// 判分脚本:以「被测工作目录」为 cwd 运行(node <本文件>,cwd=workdir)。退出码 0 = 通过。
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { cwd } from 'node:process';
|
|
5
|
+
import { pathToFileURL } from 'node:url';
|
|
6
|
+
|
|
7
|
+
const mod = await import(pathToFileURL(join(cwd(), 'src', 'slugify.mjs')).href);
|
|
8
|
+
const slugify = mod.slugify ?? mod.default?.slugify;
|
|
9
|
+
assert.equal(typeof slugify, 'function', '应导出具名函数 slugify');
|
|
10
|
+
assert.equal(typeof mod.default, 'function', '应提供 default 导出');
|
|
11
|
+
|
|
12
|
+
assert.equal(slugify(null), '');
|
|
13
|
+
assert.equal(slugify(undefined), '');
|
|
14
|
+
assert.equal(slugify(''), '');
|
|
15
|
+
assert.equal(slugify(42), '42');
|
|
16
|
+
assert.equal(slugify(' Hello World! '), 'hello-world');
|
|
17
|
+
assert.equal(slugify('Foo Bar BAZ'), 'foo-bar-baz');
|
|
18
|
+
assert.equal(slugify('a--b'), 'a-b');
|
|
19
|
+
assert.equal(slugify('!!!'), '');
|
|
20
|
+
assert.equal(slugify('Ünïcode Test'), 'ncode-test');
|
|
21
|
+
assert.equal(slugify('tab\tand\nnewline'), 'tab-and-newline');
|
|
22
|
+
assert.equal(slugify('-leading and trailing-'), 'leading-and-trailing');
|
|
23
|
+
assert.equal(slugify('Hello World', { hyphen: '_' }), 'hello_world');
|
|
24
|
+
assert.equal(slugify('a b', { hyphen: '+' }), 'a+b');
|
|
25
|
+
assert.throws(() => slugify('a b', { hyphen: '--' }), TypeError);
|
|
26
|
+
assert.throws(() => slugify('a b', { hyphen: '' }), TypeError);
|
|
27
|
+
|
|
28
|
+
console.log('001-slugify verify OK');
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// 参考解(dry-run 假 agent 使用,也供人工对照)。
|
|
2
|
+
const DATE_PREFIX = /^(\d{4})-(\d{2})-(\d{2})(?:[T ].*)?$/;
|
|
3
|
+
const DAY_MS = 86_400_000;
|
|
4
|
+
|
|
5
|
+
function parseUtc(value) {
|
|
6
|
+
if (typeof value !== 'string') throw new TypeError('invalid date');
|
|
7
|
+
const m = DATE_PREFIX.exec(value.trim());
|
|
8
|
+
if (!m) throw new TypeError('invalid date');
|
|
9
|
+
const y = Number(m[1]);
|
|
10
|
+
const mo = Number(m[2]);
|
|
11
|
+
const d = Number(m[3]);
|
|
12
|
+
const ts = Date.UTC(y, mo - 1, d);
|
|
13
|
+
const dt = new Date(ts);
|
|
14
|
+
// 往返校验拦住 '2024-02-30' 这类被 Date 自动进位的假日期
|
|
15
|
+
if (dt.getUTCFullYear() !== y || dt.getUTCMonth() !== mo - 1 || dt.getUTCDate() !== d) {
|
|
16
|
+
throw new TypeError('invalid date');
|
|
17
|
+
}
|
|
18
|
+
return ts;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function eachDay(start, end) {
|
|
22
|
+
const s = parseUtc(start);
|
|
23
|
+
const e = parseUtc(end);
|
|
24
|
+
if (e < s) throw new RangeError('end must not be before start');
|
|
25
|
+
const days = [];
|
|
26
|
+
for (let t = s; t <= e; t += DAY_MS) {
|
|
27
|
+
days.push(new Date(t).toISOString().slice(0, 10));
|
|
28
|
+
}
|
|
29
|
+
return days;
|
|
30
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "002-each-day",
|
|
3
|
+
"title": "实现 eachDay 日期区间函数(棕地补全)",
|
|
4
|
+
"tags": ["brownfield", "date", "validation"],
|
|
5
|
+
"instruction": "src/dates.mjs 已有函数骨架 eachDay(start, end)(当前直接 throw),在原文件完成实现,保持具名导出 eachDay 不变,禁止引入第三方依赖。\n\n契约:\n- 入参为字符串,接受 'YYYY-MM-DD',或以它开头的时间形式(如 '2024-01-01T10:00:00Z'、'2024-01-01 08:00');只取日期部分参与运算。\n- 返回闭区间 [start, end] 内每一天的 'YYYY-MM-DD' 字符串数组(含两端;起止同天返回单元素数组)。\n- 日期运算一律用 UTC(避免时区/DST 干扰)。\n- end 的日期小于 start 时抛 RangeError。\n- 格式非法(不匹配 'YYYY-MM-DD' 前缀、日期不存在如 '2024-02-30'、或非字符串)抛 TypeError('invalid date')。\n\n示例:\neachDay('2024-02-27', '2024-03-02') → ['2024-02-27','2024-02-28','2024-02-29','2024-03-01','2024-03-02']\neachDay('2024-01-15', '2024-01-15') → ['2024-01-15']"
|
|
6
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// 判分脚本:cwd=被测工作目录,退出码 0 = 通过。
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { cwd } from 'node:process';
|
|
5
|
+
import { pathToFileURL } from 'node:url';
|
|
6
|
+
|
|
7
|
+
const mod = await import(pathToFileURL(join(cwd(), 'src', 'dates.mjs')).href);
|
|
8
|
+
const eachDay = mod.eachDay ?? mod.default?.eachDay;
|
|
9
|
+
assert.equal(typeof eachDay, 'function', '应导出具名函数 eachDay');
|
|
10
|
+
|
|
11
|
+
assert.deepEqual(
|
|
12
|
+
eachDay('2024-02-27', '2024-03-02'),
|
|
13
|
+
['2024-02-27', '2024-02-28', '2024-02-29', '2024-03-01', '2024-03-02'],
|
|
14
|
+
);
|
|
15
|
+
assert.deepEqual(
|
|
16
|
+
eachDay('2024-12-30', '2025-01-02'),
|
|
17
|
+
['2024-12-30', '2024-12-31', '2025-01-01', '2025-01-02'],
|
|
18
|
+
);
|
|
19
|
+
assert.deepEqual(eachDay('2024-01-15', '2024-01-15'), ['2024-01-15']);
|
|
20
|
+
assert.deepEqual(
|
|
21
|
+
eachDay('2024-01-01T10:00:00Z', '2024-01-03T23:00:00Z'),
|
|
22
|
+
['2024-01-01', '2024-01-02', '2024-01-03'],
|
|
23
|
+
);
|
|
24
|
+
// 2100 是「逢百年不闰」的非闰年
|
|
25
|
+
assert.deepEqual(eachDay('2100-02-28', '2100-03-01'), ['2100-02-28', '2100-03-01']);
|
|
26
|
+
assert.throws(() => eachDay('2024-03-01', '2024-02-28'), RangeError);
|
|
27
|
+
assert.throws(() => eachDay('2024-02-30', '2024-03-01'), TypeError);
|
|
28
|
+
assert.throws(() => eachDay('2024-1-1', '2024-01-02'), TypeError);
|
|
29
|
+
assert.throws(() => eachDay(null, '2024-01-02'), TypeError);
|
|
30
|
+
|
|
31
|
+
console.log('002-each-day verify OK');
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// 参考解(dry-run 假 agent 使用,也供人工对照)。
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
|
|
5
|
+
function parseArgs(argv) {
|
|
6
|
+
const out = { input: 'data/notes.txt', top: 5, minLen: 1 };
|
|
7
|
+
for (let i = 0; i < argv.length; i++) {
|
|
8
|
+
const a = argv[i];
|
|
9
|
+
if (a === '--input') out.input = argv[++i];
|
|
10
|
+
else if (a === '--top') out.top = Number(argv[++i]);
|
|
11
|
+
else if (a === '--min-len') out.minLen = Number(argv[++i]);
|
|
12
|
+
}
|
|
13
|
+
return out;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const { input, top, minLen } = parseArgs(process.argv.slice(2));
|
|
17
|
+
let text;
|
|
18
|
+
try {
|
|
19
|
+
text = readFileSync(input, 'utf8');
|
|
20
|
+
} catch (err) {
|
|
21
|
+
console.error(`无法读取输入文件: ${input}(${err.code ?? err.message})`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const counts = new Map();
|
|
26
|
+
for (const word of text.toLowerCase().split(/\s+/)) {
|
|
27
|
+
if (!word || word.length < minLen) continue;
|
|
28
|
+
counts.set(word, (counts.get(word) ?? 0) + 1);
|
|
29
|
+
}
|
|
30
|
+
const totalWords = [...counts.values()].reduce((a, b) => a + b, 0);
|
|
31
|
+
const topWords = [...counts.entries()]
|
|
32
|
+
.sort((a, b) => b[1] - a[1] || (a[0] < b[0] ? -1 : 1))
|
|
33
|
+
.slice(0, top)
|
|
34
|
+
.map(([word, count]) => ({ word, count }));
|
|
35
|
+
|
|
36
|
+
process.stdout.write(`${JSON.stringify({ totalWords, top: topWords })}\n`);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "003-word-report",
|
|
3
|
+
"title": "实现词频统计 CLI",
|
|
4
|
+
"tags": ["greenfield", "cli", "output-contract"],
|
|
5
|
+
"instruction": "当前目录 data/notes.txt 已提供输入样本。新建 bin/report.mjs(纯 Node 实现,禁止第三方依赖,package.json 已是 type=module)。\n\n功能:词频统计 CLI。用法:node bin/report.mjs [--input <路径>] [--top N] [--min-len M]\n- --input:输入文件路径,默认 data/notes.txt(相对当前工作目录解析)。\n- 读取文本,小写化后按空白切分为词。\n- --min-len:过滤掉长度小于 M 的词,默认 1。\n- --top:输出频次最高的前 N 个词,默认 5;频次相同时按词的字典序升序排列。\n- stdout 输出且仅输出一行 JSON:{\"totalWords\":<过滤后的总词数>,\"top\":[{\"word\":<词>,\"count\":<次数>}, ...]}\n- 输入文件不存在或不可读时:向 stderr 输出错误信息,退出码 1。"
|
|
6
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// 判分脚本:cwd=被测工作目录,退出码 0 = 通过。
|
|
2
|
+
// 期望值基于 data/notes.txt 的固定内容硬编码,保证判分独立于被测实现。
|
|
3
|
+
import assert from 'node:assert/strict';
|
|
4
|
+
import { spawnSync } from 'node:child_process';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { cwd } from 'node:process';
|
|
7
|
+
|
|
8
|
+
const reportCli = join(cwd(), 'bin', 'report.mjs');
|
|
9
|
+
const run = (args) => spawnSync('node', [reportCli, ...args], { encoding: 'utf8' });
|
|
10
|
+
|
|
11
|
+
const run1 = run(['--top', '3']);
|
|
12
|
+
assert.equal(run1.status, 0, `CLI 应成功运行: ${run1.stderr}`);
|
|
13
|
+
assert.ok(run1.stdout.trim().startsWith('{'), 'stdout 应为 JSON');
|
|
14
|
+
assert.equal(run1.stdout.trim().split('\n').length, 1, '只允许输出一行 JSON');
|
|
15
|
+
assert.deepEqual(JSON.parse(run1.stdout), {
|
|
16
|
+
totalWords: 29,
|
|
17
|
+
top: [
|
|
18
|
+
{ word: 'the', count: 4 },
|
|
19
|
+
{ word: 'apple', count: 3 },
|
|
20
|
+
{ word: 'quick', count: 3 },
|
|
21
|
+
],
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const run2 = run(['--top', '2', '--min-len', '5']);
|
|
25
|
+
assert.equal(run2.status, 0);
|
|
26
|
+
assert.deepEqual(JSON.parse(run2.stdout), {
|
|
27
|
+
totalWords: 9,
|
|
28
|
+
top: [
|
|
29
|
+
{ word: 'apple', count: 3 },
|
|
30
|
+
{ word: 'quick', count: 3 },
|
|
31
|
+
],
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const run3 = run(['--input', 'no-such-file.txt']);
|
|
35
|
+
assert.notEqual(run3.status, 0, '文件不存在应非零退出');
|
|
36
|
+
assert.ok((run3.stderr ?? '').trim().length > 0, '应向 stderr 输出错误信息');
|
|
37
|
+
|
|
38
|
+
console.log('003-word-report verify OK');
|
|
Binary file
|