gsd-remix 1.0.0
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/LICENSE +21 -0
- package/README.md +939 -0
- package/README.zh-CN.md +876 -0
- package/agents/gsd-advisor-researcher.md +127 -0
- package/agents/gsd-ai-researcher.md +133 -0
- package/agents/gsd-assumptions-analyzer.md +105 -0
- package/agents/gsd-code-fixer.md +517 -0
- package/agents/gsd-code-reviewer.md +371 -0
- package/agents/gsd-codebase-mapper.md +781 -0
- package/agents/gsd-debug-session-manager.md +314 -0
- package/agents/gsd-debugger.md +1452 -0
- package/agents/gsd-doc-classifier.md +168 -0
- package/agents/gsd-doc-synthesizer.md +204 -0
- package/agents/gsd-doc-verifier.md +217 -0
- package/agents/gsd-doc-writer.md +615 -0
- package/agents/gsd-domain-researcher.md +153 -0
- package/agents/gsd-eval-auditor.md +191 -0
- package/agents/gsd-eval-planner.md +154 -0
- package/agents/gsd-executor.md +603 -0
- package/agents/gsd-framework-selector.md +160 -0
- package/agents/gsd-integration-checker.md +470 -0
- package/agents/gsd-intel-updater.md +334 -0
- package/agents/gsd-nyquist-auditor.md +203 -0
- package/agents/gsd-pattern-mapper.md +335 -0
- package/agents/gsd-phase-researcher.md +841 -0
- package/agents/gsd-plan-checker.md +978 -0
- package/agents/gsd-planner.md +1251 -0
- package/agents/gsd-project-researcher.md +677 -0
- package/agents/gsd-research-synthesizer.md +247 -0
- package/agents/gsd-roadmapper.md +688 -0
- package/agents/gsd-security-auditor.md +155 -0
- package/agents/gsd-ui-auditor.md +495 -0
- package/agents/gsd-ui-checker.md +309 -0
- package/agents/gsd-ui-researcher.md +380 -0
- package/agents/gsd-user-profiler.md +171 -0
- package/agents/gsd-verifier.md +830 -0
- package/bin/install.js +7062 -0
- package/commands/gsd/add-backlog.md +79 -0
- package/commands/gsd/add-phase.md +43 -0
- package/commands/gsd/add-tests.md +41 -0
- package/commands/gsd/add-todo.md +47 -0
- package/commands/gsd/ai-integration-phase.md +36 -0
- package/commands/gsd/analyze-dependencies.md +34 -0
- package/commands/gsd/audit-fix.md +33 -0
- package/commands/gsd/audit-milestone.md +36 -0
- package/commands/gsd/audit-uat.md +24 -0
- package/commands/gsd/autonomous.md +46 -0
- package/commands/gsd/check-todos.md +45 -0
- package/commands/gsd/cleanup.md +23 -0
- package/commands/gsd/code-review-fix.md +52 -0
- package/commands/gsd/code-review.md +55 -0
- package/commands/gsd/complete-milestone.md +136 -0
- package/commands/gsd/debug.md +263 -0
- package/commands/gsd/discuss-phase.md +69 -0
- package/commands/gsd/do.md +30 -0
- package/commands/gsd/docs-update.md +48 -0
- package/commands/gsd/eval-review.md +32 -0
- package/commands/gsd/execute-phase.md +63 -0
- package/commands/gsd/explore.md +27 -0
- package/commands/gsd/extract_learnings.md +22 -0
- package/commands/gsd/fast.md +30 -0
- package/commands/gsd/forensics.md +56 -0
- package/commands/gsd/from-gsd2.md +47 -0
- package/commands/gsd/graphify.md +201 -0
- package/commands/gsd/health.md +22 -0
- package/commands/gsd/help.md +24 -0
- package/commands/gsd/import.md +37 -0
- package/commands/gsd/inbox.md +38 -0
- package/commands/gsd/ingest-docs.md +42 -0
- package/commands/gsd/insert-phase.md +32 -0
- package/commands/gsd/intel.md +179 -0
- package/commands/gsd/join-discord.md +19 -0
- package/commands/gsd/list-phase-assumptions.md +46 -0
- package/commands/gsd/list-workspaces.md +19 -0
- package/commands/gsd/manager.md +40 -0
- package/commands/gsd/map-codebase.md +71 -0
- package/commands/gsd/milestone-summary.md +51 -0
- package/commands/gsd/new-milestone.md +44 -0
- package/commands/gsd/new-project.md +46 -0
- package/commands/gsd/new-workspace.md +44 -0
- package/commands/gsd/next.md +28 -0
- package/commands/gsd/note.md +34 -0
- package/commands/gsd/pause-work.md +38 -0
- package/commands/gsd/plan-milestone-gaps.md +34 -0
- package/commands/gsd/plan-phase.md +52 -0
- package/commands/gsd/plan-review-convergence.md +52 -0
- package/commands/gsd/plant-seed.md +28 -0
- package/commands/gsd/pr-branch.md +25 -0
- package/commands/gsd/profile-user.md +46 -0
- package/commands/gsd/progress.md +25 -0
- package/commands/gsd/quick.md +173 -0
- package/commands/gsd/reapply-patches.md +331 -0
- package/commands/gsd/remove-phase.md +31 -0
- package/commands/gsd/remove-workspace.md +26 -0
- package/commands/gsd/research-phase.md +195 -0
- package/commands/gsd/resume-work.md +40 -0
- package/commands/gsd/review-backlog.md +62 -0
- package/commands/gsd/review.md +40 -0
- package/commands/gsd/scan.md +26 -0
- package/commands/gsd/secure-phase.md +35 -0
- package/commands/gsd/session-report.md +19 -0
- package/commands/gsd/set-profile.md +12 -0
- package/commands/gsd/settings.md +36 -0
- package/commands/gsd/ship.md +23 -0
- package/commands/gsd/sketch-wrap-up.md +31 -0
- package/commands/gsd/sketch.md +49 -0
- package/commands/gsd/spec-phase.md +62 -0
- package/commands/gsd/spike-wrap-up.md +31 -0
- package/commands/gsd/spike.md +46 -0
- package/commands/gsd/stats.md +18 -0
- package/commands/gsd/sync-skills.md +19 -0
- package/commands/gsd/thread.md +227 -0
- package/commands/gsd/ui-phase.md +34 -0
- package/commands/gsd/ui-review.md +32 -0
- package/commands/gsd/ultraplan-phase.md +33 -0
- package/commands/gsd/undo.md +34 -0
- package/commands/gsd/update.md +37 -0
- package/commands/gsd/validate-phase.md +35 -0
- package/commands/gsd/verify-work.md +38 -0
- package/commands/gsd/workstreams.md +69 -0
- package/get-shit-done/bin/gsd-tools.cjs +1263 -0
- package/get-shit-done/bin/lib/artifacts.cjs +52 -0
- package/get-shit-done/bin/lib/audit.cjs +757 -0
- package/get-shit-done/bin/lib/commands.cjs +1023 -0
- package/get-shit-done/bin/lib/config-schema.cjs +79 -0
- package/get-shit-done/bin/lib/config.cjs +463 -0
- package/get-shit-done/bin/lib/core.cjs +1794 -0
- package/get-shit-done/bin/lib/docs.cjs +267 -0
- package/get-shit-done/bin/lib/frontmatter.cjs +379 -0
- package/get-shit-done/bin/lib/graphify.cjs +494 -0
- package/get-shit-done/bin/lib/gsd2-import.cjs +511 -0
- package/get-shit-done/bin/lib/init.cjs +1878 -0
- package/get-shit-done/bin/lib/intel.cjs +639 -0
- package/get-shit-done/bin/lib/learnings.cjs +378 -0
- package/get-shit-done/bin/lib/milestone.cjs +283 -0
- package/get-shit-done/bin/lib/model-profiles.cjs +71 -0
- package/get-shit-done/bin/lib/phase.cjs +1058 -0
- package/get-shit-done/bin/lib/profile-output.cjs +1080 -0
- package/get-shit-done/bin/lib/profile-pipeline.cjs +539 -0
- package/get-shit-done/bin/lib/roadmap.cjs +523 -0
- package/get-shit-done/bin/lib/schema-detect.cjs +238 -0
- package/get-shit-done/bin/lib/security.cjs +504 -0
- package/get-shit-done/bin/lib/state.cjs +1649 -0
- package/get-shit-done/bin/lib/template.cjs +226 -0
- package/get-shit-done/bin/lib/uat.cjs +288 -0
- package/get-shit-done/bin/lib/verify.cjs +1184 -0
- package/get-shit-done/bin/lib/workstream.cjs +495 -0
- package/get-shit-done/bin/repair-sdk.cjs +177 -0
- package/get-shit-done/contexts/dev.md +21 -0
- package/get-shit-done/contexts/research.md +22 -0
- package/get-shit-done/contexts/review.md +22 -0
- package/get-shit-done/references/agent-contracts.md +79 -0
- package/get-shit-done/references/ai-evals.md +156 -0
- package/get-shit-done/references/ai-frameworks.md +186 -0
- package/get-shit-done/references/artifact-types.md +131 -0
- package/get-shit-done/references/autonomous-smart-discuss.md +277 -0
- package/get-shit-done/references/checkpoints.md +808 -0
- package/get-shit-done/references/common-bug-patterns.md +114 -0
- package/get-shit-done/references/context-budget.md +49 -0
- package/get-shit-done/references/continuation-format.md +253 -0
- package/get-shit-done/references/debugger-philosophy.md +76 -0
- package/get-shit-done/references/decimal-phase-calculation.md +64 -0
- package/get-shit-done/references/doc-conflict-engine.md +91 -0
- package/get-shit-done/references/domain-probes.md +125 -0
- package/get-shit-done/references/executor-examples.md +110 -0
- package/get-shit-done/references/few-shot-examples/plan-checker.md +73 -0
- package/get-shit-done/references/few-shot-examples/verifier.md +109 -0
- package/get-shit-done/references/gate-prompts.md +100 -0
- package/get-shit-done/references/gates.md +70 -0
- package/get-shit-done/references/git-integration.md +295 -0
- package/get-shit-done/references/git-planning-commit.md +40 -0
- package/get-shit-done/references/ios-scaffold.md +123 -0
- package/get-shit-done/references/mandatory-initial-read.md +2 -0
- package/get-shit-done/references/model-profile-resolution.md +38 -0
- package/get-shit-done/references/model-profiles.md +145 -0
- package/get-shit-done/references/phase-argument-parsing.md +61 -0
- package/get-shit-done/references/planner-antipatterns.md +89 -0
- package/get-shit-done/references/planner-gap-closure.md +62 -0
- package/get-shit-done/references/planner-reviews.md +39 -0
- package/get-shit-done/references/planner-revision.md +87 -0
- package/get-shit-done/references/planner-source-audit.md +73 -0
- package/get-shit-done/references/planning-config.md +460 -0
- package/get-shit-done/references/project-skills-discovery.md +19 -0
- package/get-shit-done/references/questioning.md +162 -0
- package/get-shit-done/references/revision-loop.md +97 -0
- package/get-shit-done/references/sketch-interactivity.md +41 -0
- package/get-shit-done/references/sketch-theme-system.md +94 -0
- package/get-shit-done/references/sketch-tooling.md +45 -0
- package/get-shit-done/references/sketch-variant-patterns.md +81 -0
- package/get-shit-done/references/tdd.md +330 -0
- package/get-shit-done/references/thinking-models-debug.md +44 -0
- package/get-shit-done/references/thinking-models-execution.md +50 -0
- package/get-shit-done/references/thinking-models-planning.md +62 -0
- package/get-shit-done/references/thinking-models-research.md +50 -0
- package/get-shit-done/references/thinking-models-verification.md +55 -0
- package/get-shit-done/references/thinking-partner.md +96 -0
- package/get-shit-done/references/ui-brand.md +160 -0
- package/get-shit-done/references/universal-anti-patterns.md +63 -0
- package/get-shit-done/references/user-profiling.md +681 -0
- package/get-shit-done/references/verification-overrides.md +227 -0
- package/get-shit-done/references/verification-patterns.md +612 -0
- package/get-shit-done/references/workstream-flag.md +111 -0
- package/get-shit-done/templates/AI-SPEC.md +246 -0
- package/get-shit-done/templates/DEBUG.md +169 -0
- package/get-shit-done/templates/README.md +76 -0
- package/get-shit-done/templates/SECURITY.md +61 -0
- package/get-shit-done/templates/UAT.md +265 -0
- package/get-shit-done/templates/UI-SPEC.md +100 -0
- package/get-shit-done/templates/VALIDATION.md +76 -0
- package/get-shit-done/templates/claude-md.md +145 -0
- package/get-shit-done/templates/codebase/architecture.md +255 -0
- package/get-shit-done/templates/codebase/concerns.md +310 -0
- package/get-shit-done/templates/codebase/conventions.md +307 -0
- package/get-shit-done/templates/codebase/integrations.md +280 -0
- package/get-shit-done/templates/codebase/stack.md +186 -0
- package/get-shit-done/templates/codebase/structure.md +285 -0
- package/get-shit-done/templates/codebase/testing.md +480 -0
- package/get-shit-done/templates/config.json +56 -0
- package/get-shit-done/templates/context.md +352 -0
- package/get-shit-done/templates/continue-here.md +78 -0
- package/get-shit-done/templates/copilot-instructions.md +7 -0
- package/get-shit-done/templates/debug-subagent-prompt.md +91 -0
- package/get-shit-done/templates/dev-preferences.md +21 -0
- package/get-shit-done/templates/discovery.md +146 -0
- package/get-shit-done/templates/discussion-log.md +63 -0
- package/get-shit-done/templates/milestone-archive.md +123 -0
- package/get-shit-done/templates/milestone.md +115 -0
- package/get-shit-done/templates/phase-prompt.md +610 -0
- package/get-shit-done/templates/planner-subagent-prompt.md +117 -0
- package/get-shit-done/templates/project.md +186 -0
- package/get-shit-done/templates/requirements.md +231 -0
- package/get-shit-done/templates/research-project/ARCHITECTURE.md +204 -0
- package/get-shit-done/templates/research-project/FEATURES.md +147 -0
- package/get-shit-done/templates/research-project/PITFALLS.md +200 -0
- package/get-shit-done/templates/research-project/STACK.md +120 -0
- package/get-shit-done/templates/research-project/SUMMARY.md +170 -0
- package/get-shit-done/templates/research.md +592 -0
- package/get-shit-done/templates/retrospective.md +54 -0
- package/get-shit-done/templates/roadmap.md +202 -0
- package/get-shit-done/templates/spec.md +307 -0
- package/get-shit-done/templates/state.md +184 -0
- package/get-shit-done/templates/summary-complex.md +59 -0
- package/get-shit-done/templates/summary-minimal.md +41 -0
- package/get-shit-done/templates/summary-standard.md +48 -0
- package/get-shit-done/templates/summary.md +248 -0
- package/get-shit-done/templates/user-profile.md +146 -0
- package/get-shit-done/templates/user-setup.md +311 -0
- package/get-shit-done/templates/verification-report.md +322 -0
- package/get-shit-done/workflows/add-phase.md +112 -0
- package/get-shit-done/workflows/add-tests.md +354 -0
- package/get-shit-done/workflows/add-todo.md +160 -0
- package/get-shit-done/workflows/ai-integration-phase.md +284 -0
- package/get-shit-done/workflows/analyze-dependencies.md +96 -0
- package/get-shit-done/workflows/audit-fix.md +175 -0
- package/get-shit-done/workflows/audit-milestone.md +340 -0
- package/get-shit-done/workflows/audit-uat.md +109 -0
- package/get-shit-done/workflows/autonomous.md +789 -0
- package/get-shit-done/workflows/check-todos.md +179 -0
- package/get-shit-done/workflows/cleanup.md +154 -0
- package/get-shit-done/workflows/code-review-fix.md +497 -0
- package/get-shit-done/workflows/code-review.md +515 -0
- package/get-shit-done/workflows/complete-milestone.md +847 -0
- package/get-shit-done/workflows/diagnose-issues.md +238 -0
- package/get-shit-done/workflows/discovery-phase.md +291 -0
- package/get-shit-done/workflows/discuss-phase-assumptions.md +670 -0
- package/get-shit-done/workflows/discuss-phase-power.md +308 -0
- package/get-shit-done/workflows/discuss-phase.md +1378 -0
- package/get-shit-done/workflows/do.md +110 -0
- package/get-shit-done/workflows/docs-update.md +1155 -0
- package/get-shit-done/workflows/eval-review.md +155 -0
- package/get-shit-done/workflows/execute-phase.md +1677 -0
- package/get-shit-done/workflows/execute-plan.md +533 -0
- package/get-shit-done/workflows/explore.md +141 -0
- package/get-shit-done/workflows/extract_learnings.md +242 -0
- package/get-shit-done/workflows/fast.md +105 -0
- package/get-shit-done/workflows/forensics.md +265 -0
- package/get-shit-done/workflows/graduation.md +195 -0
- package/get-shit-done/workflows/health.md +314 -0
- package/get-shit-done/workflows/help.md +667 -0
- package/get-shit-done/workflows/import.md +246 -0
- package/get-shit-done/workflows/inbox.md +387 -0
- package/get-shit-done/workflows/ingest-docs.md +328 -0
- package/get-shit-done/workflows/insert-phase.md +130 -0
- package/get-shit-done/workflows/list-phase-assumptions.md +178 -0
- package/get-shit-done/workflows/list-workspaces.md +56 -0
- package/get-shit-done/workflows/manager.md +365 -0
- package/get-shit-done/workflows/map-codebase.md +393 -0
- package/get-shit-done/workflows/milestone-summary.md +223 -0
- package/get-shit-done/workflows/new-milestone.md +611 -0
- package/get-shit-done/workflows/new-project.md +1391 -0
- package/get-shit-done/workflows/new-workspace.md +239 -0
- package/get-shit-done/workflows/next.md +220 -0
- package/get-shit-done/workflows/node-repair.md +92 -0
- package/get-shit-done/workflows/note.md +158 -0
- package/get-shit-done/workflows/pause-work.md +243 -0
- package/get-shit-done/workflows/plan-milestone-gaps.md +273 -0
- package/get-shit-done/workflows/plan-phase.md +1349 -0
- package/get-shit-done/workflows/plan-review-convergence.md +254 -0
- package/get-shit-done/workflows/plant-seed.md +172 -0
- package/get-shit-done/workflows/pr-branch.md +157 -0
- package/get-shit-done/workflows/profile-user.md +452 -0
- package/get-shit-done/workflows/progress.md +619 -0
- package/get-shit-done/workflows/quick.md +970 -0
- package/get-shit-done/workflows/remove-phase.md +155 -0
- package/get-shit-done/workflows/remove-workspace.md +92 -0
- package/get-shit-done/workflows/research-phase.md +89 -0
- package/get-shit-done/workflows/resume-project.md +326 -0
- package/get-shit-done/workflows/review.md +344 -0
- package/get-shit-done/workflows/scan.md +102 -0
- package/get-shit-done/workflows/secure-phase.md +166 -0
- package/get-shit-done/workflows/session-report.md +146 -0
- package/get-shit-done/workflows/settings.md +319 -0
- package/get-shit-done/workflows/ship.md +302 -0
- package/get-shit-done/workflows/sketch-wrap-up.md +283 -0
- package/get-shit-done/workflows/sketch.md +286 -0
- package/get-shit-done/workflows/spec-phase.md +262 -0
- package/get-shit-done/workflows/spike-wrap-up.md +281 -0
- package/get-shit-done/workflows/spike.md +362 -0
- package/get-shit-done/workflows/stats.md +60 -0
- package/get-shit-done/workflows/sync-skills.md +182 -0
- package/get-shit-done/workflows/transition.md +693 -0
- package/get-shit-done/workflows/ui-phase.md +323 -0
- package/get-shit-done/workflows/ui-review.md +190 -0
- package/get-shit-done/workflows/ultraplan-phase.md +189 -0
- package/get-shit-done/workflows/undo.md +314 -0
- package/get-shit-done/workflows/update.md +587 -0
- package/get-shit-done/workflows/validate-phase.md +176 -0
- package/get-shit-done/workflows/verify-phase.md +465 -0
- package/get-shit-done/workflows/verify-work.md +740 -0
- package/hooks/dist/gsd-check-update-worker.js +108 -0
- package/hooks/dist/gsd-check-update.js +64 -0
- package/hooks/dist/gsd-context-monitor.js +192 -0
- package/hooks/dist/gsd-phase-boundary.sh +28 -0
- package/hooks/dist/gsd-prompt-guard.js +97 -0
- package/hooks/dist/gsd-read-guard.js +82 -0
- package/hooks/dist/gsd-read-injection-scanner.js +152 -0
- package/hooks/dist/gsd-session-state.sh +34 -0
- package/hooks/dist/gsd-statusline.js +293 -0
- package/hooks/dist/gsd-validate-commit.sh +48 -0
- package/hooks/dist/gsd-workflow-guard.js +94 -0
- package/hooks/gsd-check-update-worker.js +108 -0
- package/hooks/gsd-check-update.js +64 -0
- package/hooks/gsd-context-monitor.js +192 -0
- package/hooks/gsd-phase-boundary.sh +28 -0
- package/hooks/gsd-prompt-guard.js +97 -0
- package/hooks/gsd-read-guard.js +82 -0
- package/hooks/gsd-read-injection-scanner.js +152 -0
- package/hooks/gsd-session-state.sh +34 -0
- package/hooks/gsd-statusline.js +293 -0
- package/hooks/gsd-validate-commit.sh +48 -0
- package/hooks/gsd-workflow-guard.js +94 -0
- package/package.json +59 -0
- package/scripts/base64-scan.sh +262 -0
- package/scripts/build-hooks.js +95 -0
- package/scripts/gen-inventory-manifest.cjs +109 -0
- package/scripts/prompt-injection-scan.sh +201 -0
- package/scripts/run-tests.cjs +33 -0
- package/scripts/secret-scan.sh +227 -0
- package/sdk/package-lock.json +1998 -0
- package/sdk/package.json +52 -0
- package/sdk/prompts/agents/gsd-executor.md +110 -0
- package/sdk/prompts/agents/gsd-phase-researcher.md +158 -0
- package/sdk/prompts/agents/gsd-plan-checker.md +160 -0
- package/sdk/prompts/agents/gsd-planner.md +214 -0
- package/sdk/prompts/agents/gsd-project-researcher.md +323 -0
- package/sdk/prompts/agents/gsd-research-synthesizer.md +237 -0
- package/sdk/prompts/agents/gsd-roadmapper.md +670 -0
- package/sdk/prompts/agents/gsd-verifier.md +159 -0
- package/sdk/prompts/templates/project.md +186 -0
- package/sdk/prompts/templates/requirements.md +231 -0
- package/sdk/prompts/templates/research-project/ARCHITECTURE.md +204 -0
- package/sdk/prompts/templates/research-project/FEATURES.md +147 -0
- package/sdk/prompts/templates/research-project/PITFALLS.md +200 -0
- package/sdk/prompts/templates/research-project/STACK.md +120 -0
- package/sdk/prompts/templates/research-project/SUMMARY.md +170 -0
- package/sdk/prompts/templates/roadmap.md +202 -0
- package/sdk/prompts/templates/state.md +175 -0
- package/sdk/prompts/workflows/discuss-phase.md +126 -0
- package/sdk/prompts/workflows/execute-plan.md +106 -0
- package/sdk/prompts/workflows/plan-phase.md +84 -0
- package/sdk/prompts/workflows/research-phase.md +45 -0
- package/sdk/prompts/workflows/verify-phase.md +142 -0
- package/sdk/src/assembled-prompts.test.ts +349 -0
- package/sdk/src/cli-transport.test.ts +388 -0
- package/sdk/src/cli-transport.ts +130 -0
- package/sdk/src/cli.test.ts +383 -0
- package/sdk/src/cli.ts +670 -0
- package/sdk/src/config.test.ts +168 -0
- package/sdk/src/config.ts +177 -0
- package/sdk/src/context-engine.test.ts +295 -0
- package/sdk/src/context-engine.ts +170 -0
- package/sdk/src/context-truncation.test.ts +163 -0
- package/sdk/src/context-truncation.ts +233 -0
- package/sdk/src/e2e.integration.test.ts +178 -0
- package/sdk/src/errors.ts +72 -0
- package/sdk/src/event-stream.test.ts +661 -0
- package/sdk/src/event-stream.ts +441 -0
- package/sdk/src/failure-memory.test.ts +457 -0
- package/sdk/src/failure-memory.ts +1324 -0
- package/sdk/src/golden/capture.ts +95 -0
- package/sdk/src/golden/fixtures/generate-slug.golden.json +1 -0
- package/sdk/src/golden/fixtures/profile-sample-sessions/demo-project/sample.jsonl +3 -0
- package/sdk/src/golden/fixtures/summary-extract-sample.md +26 -0
- package/sdk/src/golden/fixtures/uat-render-checkpoint-sample.md +15 -0
- package/sdk/src/golden/golden-integration-covered.ts +30 -0
- package/sdk/src/golden/golden-mutation-covered.ts +7 -0
- package/sdk/src/golden/golden-policy.test.ts +8 -0
- package/sdk/src/golden/golden-policy.ts +112 -0
- package/sdk/src/golden/golden.integration.test.ts +373 -0
- package/sdk/src/golden/init-golden-normalize.ts +15 -0
- package/sdk/src/golden/read-only-golden-rows.ts +77 -0
- package/sdk/src/golden/read-only-parity.integration.test.ts +125 -0
- package/sdk/src/golden/registry-canonical-commands.ts +31 -0
- package/sdk/src/gsd-tools.test.ts +409 -0
- package/sdk/src/gsd-tools.ts +595 -0
- package/sdk/src/headless-prompts.test.ts +159 -0
- package/sdk/src/index.ts +333 -0
- package/sdk/src/init-e2e.integration.test.ts +136 -0
- package/sdk/src/init-runner.test.ts +783 -0
- package/sdk/src/init-runner.ts +735 -0
- package/sdk/src/lifecycle-e2e.integration.test.ts +258 -0
- package/sdk/src/logger.test.ts +149 -0
- package/sdk/src/logger.ts +113 -0
- package/sdk/src/milestone-runner.test.ts +421 -0
- package/sdk/src/phase-prompt.test.ts +538 -0
- package/sdk/src/phase-prompt.ts +264 -0
- package/sdk/src/phase-runner-types.test.ts +421 -0
- package/sdk/src/phase-runner.integration.test.ts +377 -0
- package/sdk/src/phase-runner.test.ts +2333 -0
- package/sdk/src/phase-runner.ts +1203 -0
- package/sdk/src/plan-parser.test.ts +528 -0
- package/sdk/src/plan-parser.ts +427 -0
- package/sdk/src/prompt-builder.test.ts +306 -0
- package/sdk/src/prompt-builder.ts +193 -0
- package/sdk/src/prompt-sanitizer.test.ts +260 -0
- package/sdk/src/prompt-sanitizer.ts +71 -0
- package/sdk/src/query/QUERY-HANDLERS.md +317 -0
- package/sdk/src/query/audit-open.ts +722 -0
- package/sdk/src/query/check-auto-mode.test.ts +77 -0
- package/sdk/src/query/check-auto-mode.ts +50 -0
- package/sdk/src/query/check-completion.test.ts +113 -0
- package/sdk/src/query/check-completion.ts +182 -0
- package/sdk/src/query/check-gates.test.ts +103 -0
- package/sdk/src/query/check-gates.ts +112 -0
- package/sdk/src/query/check-ship-ready.test.ts +77 -0
- package/sdk/src/query/check-ship-ready.ts +103 -0
- package/sdk/src/query/check-verification-status.test.ts +143 -0
- package/sdk/src/query/check-verification-status.ts +160 -0
- package/sdk/src/query/commit.test.ts +202 -0
- package/sdk/src/query/commit.ts +301 -0
- package/sdk/src/query/config-gates.test.ts +89 -0
- package/sdk/src/query/config-gates.ts +69 -0
- package/sdk/src/query/config-mutation.test.ts +365 -0
- package/sdk/src/query/config-mutation.ts +497 -0
- package/sdk/src/query/config-query.test.ts +161 -0
- package/sdk/src/query/config-query.ts +190 -0
- package/sdk/src/query/context-history.test.ts +165 -0
- package/sdk/src/query/context-history.ts +467 -0
- package/sdk/src/query/decomposed-handlers.test.ts +365 -0
- package/sdk/src/query/detect-custom-files.ts +97 -0
- package/sdk/src/query/detect-phase-type.test.ts +105 -0
- package/sdk/src/query/detect-phase-type.ts +141 -0
- package/sdk/src/query/docs-init.ts +257 -0
- package/sdk/src/query/failure-capture.ts +58 -0
- package/sdk/src/query/frontmatter-array.test.ts +14 -0
- package/sdk/src/query/frontmatter-mutation.test.ts +259 -0
- package/sdk/src/query/frontmatter-mutation.ts +343 -0
- package/sdk/src/query/frontmatter.test.ts +281 -0
- package/sdk/src/query/frontmatter.ts +397 -0
- package/sdk/src/query/helpers.test.ts +426 -0
- package/sdk/src/query/helpers.ts +482 -0
- package/sdk/src/query/index.ts +586 -0
- package/sdk/src/query/init-complex.test.ts +232 -0
- package/sdk/src/query/init-complex.ts +578 -0
- package/sdk/src/query/init.test.ts +522 -0
- package/sdk/src/query/init.ts +1046 -0
- package/sdk/src/query/intel.test.ts +90 -0
- package/sdk/src/query/intel.ts +404 -0
- package/sdk/src/query/normalize-query-command.test.ts +50 -0
- package/sdk/src/query/normalize-query-command.ts +56 -0
- package/sdk/src/query/phase-lifecycle.test.ts +1126 -0
- package/sdk/src/query/phase-lifecycle.ts +1799 -0
- package/sdk/src/query/phase-list-queries.test.ts +88 -0
- package/sdk/src/query/phase-list-queries.ts +152 -0
- package/sdk/src/query/phase-ready.test.ts +65 -0
- package/sdk/src/query/phase-ready.ts +158 -0
- package/sdk/src/query/phase.test.ts +307 -0
- package/sdk/src/query/phase.ts +340 -0
- package/sdk/src/query/pipeline.test.ts +169 -0
- package/sdk/src/query/pipeline.ts +243 -0
- package/sdk/src/query/plan-execution-route.test.ts +166 -0
- package/sdk/src/query/plan-execution-route.ts +209 -0
- package/sdk/src/query/plan-task-structure.test.ts +65 -0
- package/sdk/src/query/plan-task-structure.ts +63 -0
- package/sdk/src/query/profile-extract-messages.ts +247 -0
- package/sdk/src/query/profile-output.ts +908 -0
- package/sdk/src/query/profile-questionnaire-data.ts +181 -0
- package/sdk/src/query/profile-sample.ts +184 -0
- package/sdk/src/query/profile-scan-sessions.ts +174 -0
- package/sdk/src/query/profile.test.ts +74 -0
- package/sdk/src/query/profile.ts +337 -0
- package/sdk/src/query/progress.test.ts +156 -0
- package/sdk/src/query/progress.ts +566 -0
- package/sdk/src/query/registry.test.ts +216 -0
- package/sdk/src/query/registry.ts +174 -0
- package/sdk/src/query/requirements-extract-from-plans.test.ts +58 -0
- package/sdk/src/query/requirements-extract-from-plans.ts +86 -0
- package/sdk/src/query/roadmap-update-plan-progress.ts +132 -0
- package/sdk/src/query/roadmap.test.ts +359 -0
- package/sdk/src/query/roadmap.ts +591 -0
- package/sdk/src/query/route-next-action.test.ts +61 -0
- package/sdk/src/query/route-next-action.ts +345 -0
- package/sdk/src/query/runtime-health.ts +7 -0
- package/sdk/src/query/schema-detect.ts +189 -0
- package/sdk/src/query/skill-manifest.ts +214 -0
- package/sdk/src/query/skills.test.ts +80 -0
- package/sdk/src/query/skills.ts +62 -0
- package/sdk/src/query/state-mutation.test.ts +450 -0
- package/sdk/src/query/state-mutation.ts +1444 -0
- package/sdk/src/query/state-project-load.ts +109 -0
- package/sdk/src/query/state.test.ts +347 -0
- package/sdk/src/query/state.ts +397 -0
- package/sdk/src/query/summary.test.ts +95 -0
- package/sdk/src/query/summary.ts +296 -0
- package/sdk/src/query/template.test.ts +180 -0
- package/sdk/src/query/template.ts +242 -0
- package/sdk/src/query/uat.test.ts +77 -0
- package/sdk/src/query/uat.ts +314 -0
- package/sdk/src/query/utils.test.ts +82 -0
- package/sdk/src/query/utils.ts +92 -0
- package/sdk/src/query/validate.test.ts +656 -0
- package/sdk/src/query/validate.ts +807 -0
- package/sdk/src/query/verify.test.ts +414 -0
- package/sdk/src/query/verify.ts +645 -0
- package/sdk/src/query/websearch.test.ts +31 -0
- package/sdk/src/query/websearch.ts +82 -0
- package/sdk/src/query/workspace.test.ts +119 -0
- package/sdk/src/query/workspace.ts +131 -0
- package/sdk/src/query/workstream.test.ts +51 -0
- package/sdk/src/query/workstream.ts +434 -0
- package/sdk/src/research-gate.test.ts +190 -0
- package/sdk/src/research-gate.ts +94 -0
- package/sdk/src/runtime-health.test.ts +176 -0
- package/sdk/src/runtime-health.ts +387 -0
- package/sdk/src/session-runner.test.ts +98 -0
- package/sdk/src/session-runner.ts +299 -0
- package/sdk/src/tool-scoping.test.ts +160 -0
- package/sdk/src/tool-scoping.ts +61 -0
- package/sdk/src/types.ts +917 -0
- package/sdk/src/workstream-utils.ts +33 -0
- package/sdk/src/ws-flag.test.ts +285 -0
- package/sdk/src/ws-transport.test.ts +161 -0
- package/sdk/src/ws-transport.ts +93 -0
- package/sdk/tsconfig.json +20 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for phase query handlers.
|
|
3
|
+
*
|
|
4
|
+
* Tests findPhase and phasePlanIndex handlers.
|
|
5
|
+
* Uses temp directories with real .planning/ structures.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
9
|
+
import { mkdtemp, writeFile, mkdir, rm } from 'node:fs/promises';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
import { tmpdir } from 'node:os';
|
|
12
|
+
import { GSDError } from '../errors.js';
|
|
13
|
+
|
|
14
|
+
import { findPhase, phasePlanIndex } from './phase.js';
|
|
15
|
+
|
|
16
|
+
// ─── Fixtures ──────────────────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
const PLAN_01_CONTENT = `---
|
|
19
|
+
phase: 09-foundation
|
|
20
|
+
plan: 01
|
|
21
|
+
wave: 1
|
|
22
|
+
autonomous: true
|
|
23
|
+
files_modified:
|
|
24
|
+
- sdk/src/errors.ts
|
|
25
|
+
- sdk/src/errors.test.ts
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
<objective>
|
|
29
|
+
Build error classification system.
|
|
30
|
+
</objective>
|
|
31
|
+
|
|
32
|
+
<tasks>
|
|
33
|
+
<task type="auto">
|
|
34
|
+
<name>Task 1: Create error types</name>
|
|
35
|
+
</task>
|
|
36
|
+
<task type="auto">
|
|
37
|
+
<name>Task 2: Add exit codes</name>
|
|
38
|
+
</task>
|
|
39
|
+
</tasks>
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
const PLAN_02_CONTENT = `---
|
|
43
|
+
phase: 09-foundation
|
|
44
|
+
plan: 02
|
|
45
|
+
wave: 1
|
|
46
|
+
autonomous: false
|
|
47
|
+
files_modified:
|
|
48
|
+
- sdk/src/query/registry.ts
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
<objective>
|
|
52
|
+
Build query registry.
|
|
53
|
+
</objective>
|
|
54
|
+
|
|
55
|
+
<tasks>
|
|
56
|
+
<task type="auto">
|
|
57
|
+
<name>Task 1: Registry class</name>
|
|
58
|
+
</task>
|
|
59
|
+
<task type="checkpoint:human-verify">
|
|
60
|
+
<name>Task 2: Verify registry</name>
|
|
61
|
+
</task>
|
|
62
|
+
</tasks>
|
|
63
|
+
`;
|
|
64
|
+
|
|
65
|
+
const PLAN_03_CONTENT = `---
|
|
66
|
+
phase: 09-foundation
|
|
67
|
+
plan: 03
|
|
68
|
+
wave: 2
|
|
69
|
+
autonomous: true
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
<objective>
|
|
73
|
+
Golden file tests.
|
|
74
|
+
</objective>
|
|
75
|
+
|
|
76
|
+
<tasks>
|
|
77
|
+
<task type="auto">
|
|
78
|
+
<name>Task 1: Setup golden files</name>
|
|
79
|
+
</task>
|
|
80
|
+
</tasks>
|
|
81
|
+
`;
|
|
82
|
+
|
|
83
|
+
let tmpDir: string;
|
|
84
|
+
|
|
85
|
+
// ─── Setup / Teardown ──────────────────────────────────────────────────────
|
|
86
|
+
|
|
87
|
+
beforeEach(async () => {
|
|
88
|
+
tmpDir = await mkdtemp(join(tmpdir(), 'gsd-phase-test-'));
|
|
89
|
+
const planningDir = join(tmpDir, '.planning');
|
|
90
|
+
const phasesDir = join(planningDir, 'phases');
|
|
91
|
+
|
|
92
|
+
await mkdir(phasesDir, { recursive: true });
|
|
93
|
+
|
|
94
|
+
// Phase 09
|
|
95
|
+
const phase09 = join(phasesDir, '09-foundation');
|
|
96
|
+
await mkdir(phase09, { recursive: true });
|
|
97
|
+
await writeFile(join(phase09, '09-01-PLAN.md'), PLAN_01_CONTENT);
|
|
98
|
+
await writeFile(join(phase09, '09-01-SUMMARY.md'), 'Summary 1');
|
|
99
|
+
await writeFile(join(phase09, '09-02-PLAN.md'), PLAN_02_CONTENT);
|
|
100
|
+
await writeFile(join(phase09, '09-02-SUMMARY.md'), 'Summary 2');
|
|
101
|
+
await writeFile(join(phase09, '09-03-PLAN.md'), PLAN_03_CONTENT);
|
|
102
|
+
// No summary for plan 03 (incomplete)
|
|
103
|
+
await writeFile(join(phase09, '09-RESEARCH.md'), 'Research');
|
|
104
|
+
await writeFile(join(phase09, '09-CONTEXT.md'), 'Context');
|
|
105
|
+
|
|
106
|
+
// Phase 10
|
|
107
|
+
const phase10 = join(phasesDir, '10-read-only-queries');
|
|
108
|
+
await mkdir(phase10, { recursive: true });
|
|
109
|
+
await writeFile(join(phase10, '10-01-PLAN.md'), '---\nphase: 10\nplan: 01\n---\n<objective>\nPort helpers.\n</objective>\n<tasks>\n<task type="auto">\n <name>Task 1</name>\n</task>\n</tasks>');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
afterEach(async () => {
|
|
113
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// ─── findPhase ─────────────────────────────────────────────────────────────
|
|
117
|
+
|
|
118
|
+
describe('findPhase', () => {
|
|
119
|
+
it('finds existing phase by number', async () => {
|
|
120
|
+
const result = await findPhase(['9'], tmpDir);
|
|
121
|
+
const data = result.data as Record<string, unknown>;
|
|
122
|
+
|
|
123
|
+
expect(data.found).toBe(true);
|
|
124
|
+
expect(data.phase_number).toBe('09');
|
|
125
|
+
expect(data.phase_name).toBe('foundation');
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('returns posix-style directory path', async () => {
|
|
129
|
+
const result = await findPhase(['9'], tmpDir);
|
|
130
|
+
const data = result.data as Record<string, unknown>;
|
|
131
|
+
|
|
132
|
+
expect(data.directory).toBe('.planning/phases/09-foundation');
|
|
133
|
+
// No backslashes
|
|
134
|
+
expect((data.directory as string)).not.toContain('\\');
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('lists plans and summaries', async () => {
|
|
138
|
+
const result = await findPhase(['9'], tmpDir);
|
|
139
|
+
const data = result.data as Record<string, unknown>;
|
|
140
|
+
|
|
141
|
+
const plans = data.plans as string[];
|
|
142
|
+
const summaries = data.summaries as string[];
|
|
143
|
+
|
|
144
|
+
expect(plans.length).toBe(3);
|
|
145
|
+
expect(summaries.length).toBe(2);
|
|
146
|
+
expect(plans).toContain('09-01-PLAN.md');
|
|
147
|
+
expect(summaries).toContain('09-01-SUMMARY.md');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('returns not found for nonexistent phase', async () => {
|
|
151
|
+
const result = await findPhase(['99'], tmpDir);
|
|
152
|
+
const data = result.data as Record<string, unknown>;
|
|
153
|
+
|
|
154
|
+
expect(data.found).toBe(false);
|
|
155
|
+
expect(data.directory).toBeNull();
|
|
156
|
+
expect(data.phase_number).toBeNull();
|
|
157
|
+
expect(data.plans).toEqual([]);
|
|
158
|
+
expect(data.summaries).toEqual([]);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('throws GSDError with Validation classification when no args', async () => {
|
|
162
|
+
await expect(findPhase([], tmpDir)).rejects.toThrow(GSDError);
|
|
163
|
+
try {
|
|
164
|
+
await findPhase([], tmpDir);
|
|
165
|
+
} catch (err) {
|
|
166
|
+
expect((err as GSDError).classification).toBe('validation');
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('handles two-digit phase numbers', async () => {
|
|
171
|
+
const result = await findPhase(['10'], tmpDir);
|
|
172
|
+
const data = result.data as Record<string, unknown>;
|
|
173
|
+
|
|
174
|
+
expect(data.found).toBe(true);
|
|
175
|
+
expect(data.phase_number).toBe('10');
|
|
176
|
+
expect(data.phase_name).toBe('read-only-queries');
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('includes file stats (research, context)', async () => {
|
|
180
|
+
const result = await findPhase(['9'], tmpDir);
|
|
181
|
+
const data = result.data as Record<string, unknown>;
|
|
182
|
+
|
|
183
|
+
expect(data.has_research).toBe(true);
|
|
184
|
+
expect(data.has_context).toBe(true);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('computes incomplete plans', async () => {
|
|
188
|
+
const result = await findPhase(['9'], tmpDir);
|
|
189
|
+
const data = result.data as Record<string, unknown>;
|
|
190
|
+
const incompletePlans = data.incomplete_plans as string[];
|
|
191
|
+
|
|
192
|
+
expect(incompletePlans.length).toBe(1);
|
|
193
|
+
expect(incompletePlans[0]).toBe('09-03-PLAN.md');
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('searches archived milestone phases', async () => {
|
|
197
|
+
// Create archived milestone directory
|
|
198
|
+
const archiveDir = join(tmpDir, '.planning', 'milestones', 'v1.0-phases', '01-setup');
|
|
199
|
+
await mkdir(archiveDir, { recursive: true });
|
|
200
|
+
await writeFile(join(archiveDir, '01-01-PLAN.md'), '---\nphase: 01\nplan: 01\n---\nPlan');
|
|
201
|
+
await writeFile(join(archiveDir, '01-01-SUMMARY.md'), 'Summary');
|
|
202
|
+
|
|
203
|
+
const result = await findPhase(['1'], tmpDir);
|
|
204
|
+
const data = result.data as Record<string, unknown>;
|
|
205
|
+
|
|
206
|
+
expect(data.found).toBe(true);
|
|
207
|
+
expect(data.archived).toBe('v1.0');
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// ─── phasePlanIndex ────────────────────────────────────────────────────────
|
|
212
|
+
|
|
213
|
+
describe('phasePlanIndex', () => {
|
|
214
|
+
it('returns plan metadata for phase', async () => {
|
|
215
|
+
const result = await phasePlanIndex(['9'], tmpDir);
|
|
216
|
+
const data = result.data as Record<string, unknown>;
|
|
217
|
+
|
|
218
|
+
expect(data.phase).toBe('09');
|
|
219
|
+
const plans = data.plans as Array<Record<string, unknown>>;
|
|
220
|
+
expect(plans.length).toBe(3);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('includes plan details (id, wave, autonomous, objective, task_count)', async () => {
|
|
224
|
+
const result = await phasePlanIndex(['9'], tmpDir);
|
|
225
|
+
const data = result.data as Record<string, unknown>;
|
|
226
|
+
const plans = data.plans as Array<Record<string, unknown>>;
|
|
227
|
+
|
|
228
|
+
const plan1 = plans.find(p => p.id === '09-01');
|
|
229
|
+
expect(plan1).toBeDefined();
|
|
230
|
+
expect(plan1!.wave).toBe(1);
|
|
231
|
+
expect(plan1!.autonomous).toBe(true);
|
|
232
|
+
expect(plan1!.objective).toBe('Build error classification system.');
|
|
233
|
+
expect(plan1!.task_count).toBe(2);
|
|
234
|
+
expect(plan1!.has_summary).toBe(true);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('correctly counts XML task tags', async () => {
|
|
238
|
+
const result = await phasePlanIndex(['9'], tmpDir);
|
|
239
|
+
const data = result.data as Record<string, unknown>;
|
|
240
|
+
const plans = data.plans as Array<Record<string, unknown>>;
|
|
241
|
+
|
|
242
|
+
const plan1 = plans.find(p => p.id === '09-01');
|
|
243
|
+
expect(plan1!.task_count).toBe(2);
|
|
244
|
+
|
|
245
|
+
const plan2 = plans.find(p => p.id === '09-02');
|
|
246
|
+
expect(plan2!.task_count).toBe(2);
|
|
247
|
+
|
|
248
|
+
const plan3 = plans.find(p => p.id === '09-03');
|
|
249
|
+
expect(plan3!.task_count).toBe(1);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it('groups plans by wave', async () => {
|
|
253
|
+
const result = await phasePlanIndex(['9'], tmpDir);
|
|
254
|
+
const data = result.data as Record<string, unknown>;
|
|
255
|
+
const waves = data.waves as Record<string, string[]>;
|
|
256
|
+
|
|
257
|
+
expect(waves['1']).toContain('09-01');
|
|
258
|
+
expect(waves['1']).toContain('09-02');
|
|
259
|
+
expect(waves['2']).toContain('09-03');
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
it('identifies incomplete plans', async () => {
|
|
263
|
+
const result = await phasePlanIndex(['9'], tmpDir);
|
|
264
|
+
const data = result.data as Record<string, unknown>;
|
|
265
|
+
const incomplete = data.incomplete as string[];
|
|
266
|
+
|
|
267
|
+
expect(incomplete).toContain('09-03');
|
|
268
|
+
expect(incomplete).not.toContain('09-01');
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('detects has_checkpoints from non-autonomous plans', async () => {
|
|
272
|
+
const result = await phasePlanIndex(['9'], tmpDir);
|
|
273
|
+
const data = result.data as Record<string, unknown>;
|
|
274
|
+
|
|
275
|
+
// Plan 02 has autonomous: false
|
|
276
|
+
expect(data.has_checkpoints).toBe(true);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('parses files_modified from frontmatter', async () => {
|
|
280
|
+
const result = await phasePlanIndex(['9'], tmpDir);
|
|
281
|
+
const data = result.data as Record<string, unknown>;
|
|
282
|
+
const plans = data.plans as Array<Record<string, unknown>>;
|
|
283
|
+
|
|
284
|
+
const plan1 = plans.find(p => p.id === '09-01');
|
|
285
|
+
const filesModified = plan1!.files_modified as string[];
|
|
286
|
+
|
|
287
|
+
expect(filesModified).toContain('sdk/src/errors.ts');
|
|
288
|
+
expect(filesModified).toContain('sdk/src/errors.test.ts');
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it('throws GSDError with Validation classification when no args', async () => {
|
|
292
|
+
await expect(phasePlanIndex([], tmpDir)).rejects.toThrow(GSDError);
|
|
293
|
+
try {
|
|
294
|
+
await phasePlanIndex([], tmpDir);
|
|
295
|
+
} catch (err) {
|
|
296
|
+
expect((err as GSDError).classification).toBe('validation');
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('returns error for nonexistent phase', async () => {
|
|
301
|
+
const result = await phasePlanIndex(['99'], tmpDir);
|
|
302
|
+
const data = result.data as Record<string, unknown>;
|
|
303
|
+
|
|
304
|
+
expect(data.error).toBe('Phase not found');
|
|
305
|
+
expect(data.plans).toEqual([]);
|
|
306
|
+
});
|
|
307
|
+
});
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase finding and plan index query handlers.
|
|
3
|
+
*
|
|
4
|
+
* Ported from get-shit-done/bin/lib/phase.cjs and core.cjs.
|
|
5
|
+
* Provides find-phase (directory lookup with archived fallback)
|
|
6
|
+
* and phase-plan-index (plan metadata with wave grouping).
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { findPhase, phasePlanIndex } from './phase.js';
|
|
11
|
+
*
|
|
12
|
+
* const found = await findPhase(['9'], '/project');
|
|
13
|
+
* // { data: { found: true, directory: '.planning/phases/09-foundation', ... } }
|
|
14
|
+
*
|
|
15
|
+
* const index = await phasePlanIndex(['9'], '/project');
|
|
16
|
+
* // { data: { phase: '09', plans: [...], waves: { '1': [...] }, ... } }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { readFile, readdir } from 'node:fs/promises';
|
|
21
|
+
import { join } from 'node:path';
|
|
22
|
+
import { GSDError, ErrorClassification } from '../errors.js';
|
|
23
|
+
import { extractFrontmatter } from './frontmatter.js';
|
|
24
|
+
import {
|
|
25
|
+
normalizePhaseName,
|
|
26
|
+
comparePhaseNum,
|
|
27
|
+
phaseTokenMatches,
|
|
28
|
+
toPosixPath,
|
|
29
|
+
planningPaths,
|
|
30
|
+
} from './helpers.js';
|
|
31
|
+
import type { QueryHandler } from './utils.js';
|
|
32
|
+
|
|
33
|
+
// ─── Types ─────────────────────────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
interface PhaseInfo {
|
|
36
|
+
found: boolean;
|
|
37
|
+
directory: string | null;
|
|
38
|
+
phase_number: string | null;
|
|
39
|
+
phase_name: string | null;
|
|
40
|
+
phase_slug: string | null;
|
|
41
|
+
plans: string[];
|
|
42
|
+
summaries: string[];
|
|
43
|
+
incomplete_plans: string[];
|
|
44
|
+
has_research: boolean;
|
|
45
|
+
has_context: boolean;
|
|
46
|
+
has_verification: boolean;
|
|
47
|
+
has_reviews: boolean;
|
|
48
|
+
archived?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ─── Internal helpers ──────────────────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Get file stats for a phase directory.
|
|
55
|
+
*
|
|
56
|
+
* Port of getPhaseFileStats from core.cjs lines 1461-1471.
|
|
57
|
+
*/
|
|
58
|
+
async function getPhaseFileStats(phaseDir: string): Promise<{
|
|
59
|
+
plans: string[];
|
|
60
|
+
summaries: string[];
|
|
61
|
+
hasResearch: boolean;
|
|
62
|
+
hasContext: boolean;
|
|
63
|
+
hasVerification: boolean;
|
|
64
|
+
hasReviews: boolean;
|
|
65
|
+
}> {
|
|
66
|
+
const files = await readdir(phaseDir);
|
|
67
|
+
return {
|
|
68
|
+
plans: files.filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md'),
|
|
69
|
+
summaries: files.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md'),
|
|
70
|
+
hasResearch: files.some(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md'),
|
|
71
|
+
hasContext: files.some(f => f.endsWith('-CONTEXT.md') || f === 'CONTEXT.md'),
|
|
72
|
+
hasVerification: files.some(f => f.endsWith('-VERIFICATION.md') || f === 'VERIFICATION.md'),
|
|
73
|
+
hasReviews: files.some(f => f.endsWith('-REVIEWS.md') || f === 'REVIEWS.md'),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Search for a phase directory matching the normalized name.
|
|
79
|
+
*
|
|
80
|
+
* Port of searchPhaseInDir from core.cjs lines 956-1000.
|
|
81
|
+
*/
|
|
82
|
+
async function searchPhaseInDir(baseDir: string, relBase: string, normalized: string): Promise<PhaseInfo | null> {
|
|
83
|
+
try {
|
|
84
|
+
const entries = await readdir(baseDir, { withFileTypes: true });
|
|
85
|
+
const dirs = entries
|
|
86
|
+
.filter(e => e.isDirectory())
|
|
87
|
+
.map(e => e.name)
|
|
88
|
+
.sort((a, b) => comparePhaseNum(a, b));
|
|
89
|
+
|
|
90
|
+
const match = dirs.find(d => phaseTokenMatches(d, normalized));
|
|
91
|
+
if (!match) return null;
|
|
92
|
+
|
|
93
|
+
// Extract phase number and name
|
|
94
|
+
const dirMatch = match.match(/^(?:[A-Z]{1,6}-)(\d+[A-Z]?(?:\.\d+)*)-?(.*)/i)
|
|
95
|
+
|| match.match(/^(\d+[A-Z]?(?:\.\d+)*)-?(.*)/i)
|
|
96
|
+
|| match.match(/^([A-Z][A-Z0-9]*(?:-[A-Z0-9]+)*)-(.+)/i)
|
|
97
|
+
|| [null, match, null];
|
|
98
|
+
const phaseNumber = dirMatch ? dirMatch[1] : normalized;
|
|
99
|
+
const phaseName = dirMatch && dirMatch[2] ? dirMatch[2] : null;
|
|
100
|
+
const phaseDir = join(baseDir, match);
|
|
101
|
+
|
|
102
|
+
const { plans: unsortedPlans, summaries: unsortedSummaries, hasResearch, hasContext, hasVerification, hasReviews } = await getPhaseFileStats(phaseDir);
|
|
103
|
+
const plans = unsortedPlans.sort();
|
|
104
|
+
const summaries = unsortedSummaries.sort();
|
|
105
|
+
|
|
106
|
+
const completedPlanIds = new Set(
|
|
107
|
+
summaries.map(s => s.replace('-SUMMARY.md', '').replace('SUMMARY.md', ''))
|
|
108
|
+
);
|
|
109
|
+
const incompletePlans = plans.filter(p => {
|
|
110
|
+
const planId = p.replace('-PLAN.md', '').replace('PLAN.md', '');
|
|
111
|
+
return !completedPlanIds.has(planId);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
found: true,
|
|
116
|
+
directory: toPosixPath(join(relBase, match)),
|
|
117
|
+
phase_number: phaseNumber,
|
|
118
|
+
phase_name: phaseName,
|
|
119
|
+
phase_slug: phaseName ? phaseName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') : null,
|
|
120
|
+
plans,
|
|
121
|
+
summaries,
|
|
122
|
+
incomplete_plans: incompletePlans,
|
|
123
|
+
has_research: hasResearch,
|
|
124
|
+
has_context: hasContext,
|
|
125
|
+
has_verification: hasVerification,
|
|
126
|
+
has_reviews: hasReviews,
|
|
127
|
+
};
|
|
128
|
+
} catch {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Extract objective text from plan content.
|
|
135
|
+
*/
|
|
136
|
+
function extractObjective(content: string): string | null {
|
|
137
|
+
const m = content.match(/<objective>\s*\n?\s*(.+)/);
|
|
138
|
+
return m ? m[1].trim() : null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ─── Exported handlers ─────────────────────────────────────────────────────
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Query handler for find-phase.
|
|
145
|
+
*
|
|
146
|
+
* Locates a phase directory by number/identifier, searching current phases
|
|
147
|
+
* first, then archived milestone phases.
|
|
148
|
+
*
|
|
149
|
+
* Port of cmdFindPhase from phase.cjs lines 152-196, combined with
|
|
150
|
+
* findPhaseInternal from core.cjs lines 1002-1038.
|
|
151
|
+
*
|
|
152
|
+
* @param args - args[0] is the phase identifier (required)
|
|
153
|
+
* @param projectDir - Project root directory
|
|
154
|
+
* @returns QueryResult with PhaseInfo
|
|
155
|
+
* @throws GSDError with Validation classification if phase identifier missing
|
|
156
|
+
*/
|
|
157
|
+
export const findPhase: QueryHandler = async (args, projectDir) => {
|
|
158
|
+
const phase = args[0];
|
|
159
|
+
if (!phase) {
|
|
160
|
+
throw new GSDError('phase identifier required', ErrorClassification.Validation);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const phasesDir = planningPaths(projectDir).phases;
|
|
164
|
+
const normalized = normalizePhaseName(phase);
|
|
165
|
+
|
|
166
|
+
const notFound: PhaseInfo = {
|
|
167
|
+
found: false,
|
|
168
|
+
directory: null,
|
|
169
|
+
phase_number: null,
|
|
170
|
+
phase_name: null,
|
|
171
|
+
phase_slug: null,
|
|
172
|
+
plans: [],
|
|
173
|
+
summaries: [],
|
|
174
|
+
incomplete_plans: [],
|
|
175
|
+
has_research: false,
|
|
176
|
+
has_context: false,
|
|
177
|
+
has_verification: false,
|
|
178
|
+
has_reviews: false,
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// Search current phases first
|
|
182
|
+
const relPhasesDir = '.planning/phases';
|
|
183
|
+
const current = await searchPhaseInDir(phasesDir, relPhasesDir, normalized);
|
|
184
|
+
if (current) return { data: current };
|
|
185
|
+
|
|
186
|
+
// Search archived milestone phases (newest first)
|
|
187
|
+
const milestonesDir = join(projectDir, '.planning', 'milestones');
|
|
188
|
+
try {
|
|
189
|
+
const milestoneEntries = await readdir(milestonesDir, { withFileTypes: true });
|
|
190
|
+
const archiveDirs = milestoneEntries
|
|
191
|
+
.filter(e => e.isDirectory() && /^v[\d.]+-phases$/.test(e.name))
|
|
192
|
+
.map(e => e.name)
|
|
193
|
+
.sort()
|
|
194
|
+
.reverse();
|
|
195
|
+
|
|
196
|
+
for (const archiveName of archiveDirs) {
|
|
197
|
+
const versionMatch = archiveName.match(/^(v[\d.]+)-phases$/);
|
|
198
|
+
const version = versionMatch ? versionMatch[1] : archiveName;
|
|
199
|
+
const archivePath = join(milestonesDir, archiveName);
|
|
200
|
+
const relBase = '.planning/milestones/' + archiveName;
|
|
201
|
+
const result = await searchPhaseInDir(archivePath, relBase, normalized);
|
|
202
|
+
if (result) {
|
|
203
|
+
result.archived = version;
|
|
204
|
+
return { data: result };
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
} catch { /* milestones dir doesn't exist */ }
|
|
208
|
+
|
|
209
|
+
return { data: notFound };
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Query handler for phase-plan-index.
|
|
214
|
+
*
|
|
215
|
+
* Returns plan metadata with wave grouping for a specific phase.
|
|
216
|
+
*
|
|
217
|
+
* Port of cmdPhasePlanIndex from phase.cjs lines 203-310.
|
|
218
|
+
*
|
|
219
|
+
* @param args - args[0] is the phase identifier (required)
|
|
220
|
+
* @param projectDir - Project root directory
|
|
221
|
+
* @returns QueryResult with { phase, plans[], waves{}, incomplete[], has_checkpoints }
|
|
222
|
+
* @throws GSDError with Validation classification if phase identifier missing
|
|
223
|
+
*/
|
|
224
|
+
export const phasePlanIndex: QueryHandler = async (args, projectDir) => {
|
|
225
|
+
const phase = args[0];
|
|
226
|
+
if (!phase) {
|
|
227
|
+
throw new GSDError('phase required for phase-plan-index', ErrorClassification.Validation);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const phasesDir = planningPaths(projectDir).phases;
|
|
231
|
+
const normalized = normalizePhaseName(phase);
|
|
232
|
+
|
|
233
|
+
// Find phase directory
|
|
234
|
+
let phaseDir: string | null = null;
|
|
235
|
+
try {
|
|
236
|
+
const entries = await readdir(phasesDir, { withFileTypes: true });
|
|
237
|
+
const dirs = entries
|
|
238
|
+
.filter(e => e.isDirectory())
|
|
239
|
+
.map(e => e.name)
|
|
240
|
+
.sort((a, b) => comparePhaseNum(a, b));
|
|
241
|
+
const match = dirs.find(d => phaseTokenMatches(d, normalized));
|
|
242
|
+
if (match) {
|
|
243
|
+
phaseDir = join(phasesDir, match);
|
|
244
|
+
}
|
|
245
|
+
} catch { /* phases dir doesn't exist */ }
|
|
246
|
+
|
|
247
|
+
if (!phaseDir) {
|
|
248
|
+
return {
|
|
249
|
+
data: {
|
|
250
|
+
phase: normalized,
|
|
251
|
+
error: 'Phase not found',
|
|
252
|
+
plans: [],
|
|
253
|
+
waves: {},
|
|
254
|
+
incomplete: [],
|
|
255
|
+
has_checkpoints: false,
|
|
256
|
+
},
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Get all files in phase directory
|
|
261
|
+
const phaseFiles = await readdir(phaseDir);
|
|
262
|
+
const planFiles = phaseFiles.filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md').sort();
|
|
263
|
+
const summaryFiles = phaseFiles.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md');
|
|
264
|
+
|
|
265
|
+
// Build set of plan IDs with summaries
|
|
266
|
+
const completedPlanIds = new Set(
|
|
267
|
+
summaryFiles.map(s => s.replace('-SUMMARY.md', '').replace('SUMMARY.md', ''))
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
const plans: Array<Record<string, unknown>> = [];
|
|
271
|
+
const waves: Record<string, string[]> = {};
|
|
272
|
+
const incomplete: string[] = [];
|
|
273
|
+
let hasCheckpoints = false;
|
|
274
|
+
|
|
275
|
+
for (const planFile of planFiles) {
|
|
276
|
+
const planId = planFile.replace('-PLAN.md', '').replace('PLAN.md', '');
|
|
277
|
+
const planPath = join(phaseDir, planFile);
|
|
278
|
+
const content = await readFile(planPath, 'utf-8');
|
|
279
|
+
const fm = extractFrontmatter(content);
|
|
280
|
+
|
|
281
|
+
// Count tasks: XML <task> tags (canonical) or ## Task N markdown (legacy)
|
|
282
|
+
const xmlTasks = content.match(/<task[\s>]/gi) || [];
|
|
283
|
+
const mdTasks = content.match(/##\s*Task\s*\d+/gi) || [];
|
|
284
|
+
const taskCount = xmlTasks.length || mdTasks.length;
|
|
285
|
+
|
|
286
|
+
// Parse wave as integer
|
|
287
|
+
const wave = parseInt(String(fm.wave), 10) || 1;
|
|
288
|
+
|
|
289
|
+
// Parse autonomous (default true if not specified)
|
|
290
|
+
let autonomous = true;
|
|
291
|
+
if (fm.autonomous !== undefined) {
|
|
292
|
+
autonomous = fm.autonomous === 'true' || fm.autonomous === true;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (!autonomous) {
|
|
296
|
+
hasCheckpoints = true;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Parse files_modified
|
|
300
|
+
let filesModified: string[] = [];
|
|
301
|
+
const fmFiles = (fm['files_modified'] || fm['files-modified']) as string | string[] | undefined;
|
|
302
|
+
if (fmFiles) {
|
|
303
|
+
filesModified = Array.isArray(fmFiles) ? fmFiles : [fmFiles];
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const hasSummary = completedPlanIds.has(planId);
|
|
307
|
+
if (!hasSummary) {
|
|
308
|
+
incomplete.push(planId);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const plan = {
|
|
312
|
+
id: planId,
|
|
313
|
+
wave,
|
|
314
|
+
autonomous,
|
|
315
|
+
objective: extractObjective(content) || (fm.objective as string) || null,
|
|
316
|
+
files_modified: filesModified,
|
|
317
|
+
task_count: taskCount,
|
|
318
|
+
has_summary: hasSummary,
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
plans.push(plan);
|
|
322
|
+
|
|
323
|
+
// Group by wave
|
|
324
|
+
const waveKey = String(wave);
|
|
325
|
+
if (!waves[waveKey]) {
|
|
326
|
+
waves[waveKey] = [];
|
|
327
|
+
}
|
|
328
|
+
waves[waveKey].push(planId);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return {
|
|
332
|
+
data: {
|
|
333
|
+
phase: normalized,
|
|
334
|
+
plans,
|
|
335
|
+
waves,
|
|
336
|
+
incomplete,
|
|
337
|
+
has_checkpoints: hasCheckpoints,
|
|
338
|
+
},
|
|
339
|
+
};
|
|
340
|
+
};
|