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,591 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Roadmap query handlers — ROADMAP.md analysis and phase lookup.
|
|
3
|
+
*
|
|
4
|
+
* Ported from get-shit-done/bin/lib/roadmap.cjs and core.cjs.
|
|
5
|
+
* Provides roadmap.analyze (multi-pass parsing with disk correlation)
|
|
6
|
+
* and roadmap.get-phase (single phase section extraction).
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { roadmapAnalyze, roadmapGetPhase } from './roadmap.js';
|
|
11
|
+
*
|
|
12
|
+
* const analysis = await roadmapAnalyze([], '/project');
|
|
13
|
+
* // { data: { phases: [...], phase_count: 6, progress_percent: 50, ... } }
|
|
14
|
+
*
|
|
15
|
+
* const phase = await roadmapGetPhase(['10'], '/project');
|
|
16
|
+
* // { data: { found: true, phase_number: '10', phase_name: 'Read-Only Queries', ... } }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { existsSync } from 'node:fs';
|
|
21
|
+
import { readFile, writeFile, readdir } from 'node:fs/promises';
|
|
22
|
+
import { join } from 'node:path';
|
|
23
|
+
import { GSDError, ErrorClassification } from '../errors.js';
|
|
24
|
+
import {
|
|
25
|
+
escapeRegex,
|
|
26
|
+
normalizePhaseName,
|
|
27
|
+
phaseTokenMatches,
|
|
28
|
+
planningPaths,
|
|
29
|
+
} from './helpers.js';
|
|
30
|
+
import type { QueryHandler, QueryResult } from './utils.js';
|
|
31
|
+
|
|
32
|
+
// ─── Internal types ───────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
interface PhaseSection {
|
|
35
|
+
found: boolean;
|
|
36
|
+
phase_number: string;
|
|
37
|
+
phase_name: string;
|
|
38
|
+
goal?: string | null;
|
|
39
|
+
success_criteria?: string[];
|
|
40
|
+
section?: string;
|
|
41
|
+
error?: string;
|
|
42
|
+
message?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ─── Exported helpers ─────────────────────────────────────────────────────
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Strip <details>...</details> blocks from content (shipped milestones).
|
|
49
|
+
*
|
|
50
|
+
* Port of stripShippedMilestones from core.cjs line 1082-1084.
|
|
51
|
+
*/
|
|
52
|
+
export function stripShippedMilestones(content: string): string {
|
|
53
|
+
return content.replace(/<details>[\s\S]*?<\/details>/gi, '');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Read milestone + name from STATE.md frontmatter when ROADMAP does not encode them.
|
|
58
|
+
*/
|
|
59
|
+
async function parseMilestoneFromState(projectDir: string): Promise<{ version: string; name: string } | null> {
|
|
60
|
+
try {
|
|
61
|
+
const stateRaw = await readFile(planningPaths(projectDir).state, 'utf-8');
|
|
62
|
+
const vm = stateRaw.match(/^milestone:\s*(.+)$/m);
|
|
63
|
+
if (!vm) return null;
|
|
64
|
+
const version = vm[1].trim().replace(/^["']|["']$/g, '');
|
|
65
|
+
const nm = stateRaw.match(/^milestone_name:\s*(.+)$/m);
|
|
66
|
+
const name = nm ? nm[1].trim().replace(/^["']|["']$/g, '') : 'milestone';
|
|
67
|
+
return { version, name };
|
|
68
|
+
} catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Get milestone version and name from ROADMAP.md (and optionally STATE.md).
|
|
75
|
+
*
|
|
76
|
+
* Port of getMilestoneInfo from core.cjs lines 1367-1402, extended for:
|
|
77
|
+
* - 🟡 in-flight marker (same list shape as 🚧)
|
|
78
|
+
* - milestone bullets `**vX.Y Title**` before `## Phases` (last = current when listed in semver order)
|
|
79
|
+
* - STATE.md frontmatter when ROADMAP has no parseable milestone
|
|
80
|
+
* - **last** bare `vX.Y` fallback (first match was often v1.0 from the shipped list)
|
|
81
|
+
*
|
|
82
|
+
* @param projectDir - Project root directory
|
|
83
|
+
* @returns Object with version and name
|
|
84
|
+
*/
|
|
85
|
+
export async function getMilestoneInfo(projectDir: string): Promise<{ version: string; name: string }> {
|
|
86
|
+
try {
|
|
87
|
+
const roadmap = await readFile(planningPaths(projectDir).roadmap, 'utf-8');
|
|
88
|
+
|
|
89
|
+
// List-format: construction / blocked (legacy emoji)
|
|
90
|
+
const barricadeMatch = roadmap.match(/🚧\s*\*\*v(\d+(?:\.\d+)+)\s+([^*]+)\*\*/);
|
|
91
|
+
if (barricadeMatch) {
|
|
92
|
+
return { version: 'v' + barricadeMatch[1], name: barricadeMatch[2].trim() };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// List-format: in flight / active (GSD ROADMAP template uses 🟡 for current milestone)
|
|
96
|
+
const inFlightMatch = roadmap.match(/🟡\s*\*\*v(\d+(?:\.\d+)+)\s+([^*]+)\*\*/);
|
|
97
|
+
if (inFlightMatch) {
|
|
98
|
+
return { version: 'v' + inFlightMatch[1], name: inFlightMatch[2].trim() };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Heading-format — strip shipped <details> blocks first
|
|
102
|
+
const cleaned = stripShippedMilestones(roadmap);
|
|
103
|
+
const headingMatch = cleaned.match(/##\s+.*v(\d+(?:\.\d+)+)[:\s]+([^\n(]+)/);
|
|
104
|
+
if (headingMatch) {
|
|
105
|
+
return { version: 'v' + headingMatch[1], name: headingMatch[2].trim() };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Milestone bullet list (## Milestones … ## Phases): use last **vX.Y Title** — typically the current row
|
|
109
|
+
const beforePhases = roadmap.split(/^##\s+Phases\b/m)[0] ?? roadmap;
|
|
110
|
+
const boldMatches = [...beforePhases.matchAll(/\*\*v(\d+(?:\.\d+)+)\s+([^*]+)\*\*/g)];
|
|
111
|
+
if (boldMatches.length > 0) {
|
|
112
|
+
const last = boldMatches[boldMatches.length - 1];
|
|
113
|
+
return { version: 'v' + last[1], name: last[2].trim() };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const fromState = await parseMilestoneFromState(projectDir);
|
|
117
|
+
if (fromState) {
|
|
118
|
+
return fromState;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const allBare = [...cleaned.matchAll(/\bv(\d+(?:\.\d+)+)\b/g)];
|
|
122
|
+
if (allBare.length > 0) {
|
|
123
|
+
const lastBare = allBare[allBare.length - 1];
|
|
124
|
+
return { version: lastBare[0], name: 'milestone' };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return { version: 'v1.0', name: 'milestone' };
|
|
128
|
+
} catch {
|
|
129
|
+
const fromState = await parseMilestoneFromState(projectDir);
|
|
130
|
+
if (fromState) return fromState;
|
|
131
|
+
return { version: 'v1.0', name: 'milestone' };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Extract the current milestone section from ROADMAP.md.
|
|
137
|
+
*
|
|
138
|
+
* Port of extractCurrentMilestone from core.cjs lines 1102-1170.
|
|
139
|
+
*
|
|
140
|
+
* @param content - Full ROADMAP.md content
|
|
141
|
+
* @param projectDir - Working directory for reading STATE.md
|
|
142
|
+
* @returns Content scoped to current milestone
|
|
143
|
+
*/
|
|
144
|
+
export async function extractCurrentMilestone(content: string, projectDir: string): Promise<string> {
|
|
145
|
+
// Get version from STATE.md frontmatter
|
|
146
|
+
let version: string | null = null;
|
|
147
|
+
try {
|
|
148
|
+
const stateRaw = await readFile(planningPaths(projectDir).state, 'utf-8');
|
|
149
|
+
const milestoneMatch = stateRaw.match(/^milestone:\s*(.+)/m);
|
|
150
|
+
if (milestoneMatch) {
|
|
151
|
+
version = milestoneMatch[1].trim();
|
|
152
|
+
}
|
|
153
|
+
} catch { /* intentionally empty */ }
|
|
154
|
+
|
|
155
|
+
// Fallback: derive from ROADMAP in-progress marker
|
|
156
|
+
if (!version) {
|
|
157
|
+
const inProgressMatch = content.match(/(?:🚧|🟡)\s*\*\*v(\d+(?:\.\d+)+)\s/);
|
|
158
|
+
if (inProgressMatch) {
|
|
159
|
+
version = 'v' + inProgressMatch[1];
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (!version) return stripShippedMilestones(content);
|
|
164
|
+
|
|
165
|
+
// Find section matching this version
|
|
166
|
+
const escapedVersion = escapeRegex(version);
|
|
167
|
+
const sectionPattern = new RegExp(
|
|
168
|
+
`(^#{1,3}\\s+.*${escapedVersion}[^\\n]*)`,
|
|
169
|
+
'mi'
|
|
170
|
+
);
|
|
171
|
+
const sectionMatch = content.match(sectionPattern);
|
|
172
|
+
|
|
173
|
+
if (!sectionMatch || sectionMatch.index === undefined) return stripShippedMilestones(content);
|
|
174
|
+
|
|
175
|
+
const sectionStart = sectionMatch.index;
|
|
176
|
+
|
|
177
|
+
// Find end: next milestone heading at same or higher level, or EOF.
|
|
178
|
+
// Skip headings that belong to the SAME version (e.g. "## v2.0 Phase Details").
|
|
179
|
+
const headingLevelMatch = sectionMatch[1].match(/^(#{1,3})\s/);
|
|
180
|
+
const headingLevel = headingLevelMatch ? headingLevelMatch[1].length : 2;
|
|
181
|
+
const restContent = content.slice(sectionStart + sectionMatch[0].length);
|
|
182
|
+
// Extract current version so same-version sub-headings are not treated as boundaries.
|
|
183
|
+
// Capture full semver (major.minor.patch) so v2.0.1 is not collapsed to "2.0".
|
|
184
|
+
const currentVersionMatch = version ? version.match(/v(\d+(?:\.\d+)+)/i) : null;
|
|
185
|
+
const currentVersionStr = currentVersionMatch ? currentVersionMatch[1] : '';
|
|
186
|
+
|
|
187
|
+
const nextMilestoneRegex = new RegExp(
|
|
188
|
+
`^#{1,${headingLevel}}\\s+(?:.*v(\\d+(?:\\.\\d+)+)[^\\n]*|.*(?:✅|📋|🚧|🟡))`,
|
|
189
|
+
'gm'
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
let sectionEnd = content.length;
|
|
193
|
+
let m: RegExpExecArray | null;
|
|
194
|
+
while ((m = nextMilestoneRegex.exec(restContent)) !== null) {
|
|
195
|
+
const matchedVersion = m[1];
|
|
196
|
+
// Skip headings that reference the same version (e.g. "## v2.0 Phase Details").
|
|
197
|
+
if (matchedVersion && currentVersionStr && matchedVersion === currentVersionStr) continue;
|
|
198
|
+
sectionEnd = sectionStart + sectionMatch[0].length + m.index;
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Return only the current milestone section — never include the preamble, which
|
|
203
|
+
// may contain ## Backlog and other non-current-milestone phases.
|
|
204
|
+
return content.slice(sectionStart, sectionEnd);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// ─── Internal helpers ─────────────────────────────────────────────────────
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Search for a phase section in roadmap content.
|
|
211
|
+
*
|
|
212
|
+
* Port of searchPhaseInContent from roadmap.cjs lines 14-73.
|
|
213
|
+
*/
|
|
214
|
+
function searchPhaseInContent(content: string, escapedPhase: string, phaseNum: string): PhaseSection | null {
|
|
215
|
+
// Match "## Phase X:", "### Phase X:", or "#### Phase X:" with optional name
|
|
216
|
+
const phasePattern = new RegExp(
|
|
217
|
+
`#{2,4}\\s*Phase\\s+${escapedPhase}:\\s*([^\\n]+)`,
|
|
218
|
+
'i'
|
|
219
|
+
);
|
|
220
|
+
const headerMatch = content.match(phasePattern);
|
|
221
|
+
|
|
222
|
+
if (!headerMatch) {
|
|
223
|
+
// Fallback: check if phase exists in summary list but missing detail section
|
|
224
|
+
const checklistPattern = new RegExp(
|
|
225
|
+
`-\\s*\\[[ x]\\]\\s*\\*\\*Phase\\s+${escapedPhase}:\\s*([^*]+)\\*\\*`,
|
|
226
|
+
'i'
|
|
227
|
+
);
|
|
228
|
+
const checklistMatch = content.match(checklistPattern);
|
|
229
|
+
|
|
230
|
+
if (checklistMatch) {
|
|
231
|
+
return {
|
|
232
|
+
found: false,
|
|
233
|
+
phase_number: phaseNum,
|
|
234
|
+
phase_name: checklistMatch[1].trim(),
|
|
235
|
+
error: 'malformed_roadmap',
|
|
236
|
+
message: `Phase ${phaseNum} exists in summary list but missing "### Phase ${phaseNum}:" detail section. ROADMAP.md needs both formats.`,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const phaseName = headerMatch[1].trim();
|
|
244
|
+
const headerIndex = headerMatch.index!;
|
|
245
|
+
|
|
246
|
+
// Find the end of this section (next ## or ### phase header, or end of file)
|
|
247
|
+
const restOfContent = content.slice(headerIndex);
|
|
248
|
+
const nextHeaderMatch = restOfContent.match(/\n#{2,4}\s+Phase\s+\d/i);
|
|
249
|
+
const sectionEnd = nextHeaderMatch
|
|
250
|
+
? headerIndex + nextHeaderMatch.index!
|
|
251
|
+
: content.length;
|
|
252
|
+
|
|
253
|
+
const section = content.slice(headerIndex, sectionEnd).trim();
|
|
254
|
+
|
|
255
|
+
// Extract goal if present (supports both **Goal:** and **Goal**: formats)
|
|
256
|
+
const goalMatch = section.match(/\*\*Goal(?::\*\*|\*\*:)\s*([^\n]+)/i);
|
|
257
|
+
const goal = goalMatch ? goalMatch[1].trim() : null;
|
|
258
|
+
|
|
259
|
+
// Extract success criteria as structured array
|
|
260
|
+
const criteriaMatch = section.match(/\*\*Success Criteria\*\*[^\n]*:\s*\n((?:\s*\d+\.\s*[^\n]+\n?)+)/i);
|
|
261
|
+
const success_criteria = criteriaMatch
|
|
262
|
+
? criteriaMatch[1].trim().split('\n').map(line => line.replace(/^\s*\d+\.\s*/, '').trim()).filter(Boolean)
|
|
263
|
+
: [];
|
|
264
|
+
|
|
265
|
+
return {
|
|
266
|
+
found: true,
|
|
267
|
+
phase_number: phaseNum,
|
|
268
|
+
phase_name: phaseName,
|
|
269
|
+
goal,
|
|
270
|
+
success_criteria,
|
|
271
|
+
section,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// ─── Exported handlers ────────────────────────────────────────────────────
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Query handler for roadmap.get-phase.
|
|
279
|
+
*
|
|
280
|
+
* Port of cmdRoadmapGetPhase from roadmap.cjs lines 75-113.
|
|
281
|
+
*
|
|
282
|
+
* @param args - args[0] is phase number (required)
|
|
283
|
+
* @param projectDir - Project root directory
|
|
284
|
+
* @returns QueryResult with phase section info or { found: false }
|
|
285
|
+
*/
|
|
286
|
+
export const roadmapGetPhase: QueryHandler = async (args, projectDir) => {
|
|
287
|
+
const phaseNum = args[0];
|
|
288
|
+
if (!phaseNum) {
|
|
289
|
+
throw new GSDError(
|
|
290
|
+
'Usage: roadmap get-phase <phase-number>',
|
|
291
|
+
ErrorClassification.Validation,
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const roadmapPath = planningPaths(projectDir).roadmap;
|
|
296
|
+
|
|
297
|
+
let rawContent: string;
|
|
298
|
+
try {
|
|
299
|
+
rawContent = await readFile(roadmapPath, 'utf-8');
|
|
300
|
+
} catch {
|
|
301
|
+
return { data: { found: false, error: 'ROADMAP.md not found' } };
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const milestoneContent = await extractCurrentMilestone(rawContent, projectDir);
|
|
305
|
+
const escapedPhase = escapeRegex(phaseNum);
|
|
306
|
+
|
|
307
|
+
// Search the current milestone slice first, then fall back to full roadmap.
|
|
308
|
+
const fullContent = stripShippedMilestones(rawContent);
|
|
309
|
+
const milestoneResult = searchPhaseInContent(milestoneContent, escapedPhase, phaseNum);
|
|
310
|
+
const result = (milestoneResult && !milestoneResult.error)
|
|
311
|
+
? milestoneResult
|
|
312
|
+
: searchPhaseInContent(fullContent, escapedPhase, phaseNum) || milestoneResult;
|
|
313
|
+
|
|
314
|
+
if (!result) {
|
|
315
|
+
return { data: { found: false, phase_number: phaseNum } };
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return { data: result };
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Query handler for roadmap.analyze.
|
|
323
|
+
*
|
|
324
|
+
* Port of cmdRoadmapAnalyze from roadmap.cjs lines 115-248.
|
|
325
|
+
* Multi-pass regex parsing with disk status correlation.
|
|
326
|
+
*
|
|
327
|
+
* @param args - Unused
|
|
328
|
+
* @param projectDir - Project root directory
|
|
329
|
+
* @returns QueryResult with full roadmap analysis
|
|
330
|
+
*/
|
|
331
|
+
export const roadmapAnalyze: QueryHandler = async (_args, projectDir) => {
|
|
332
|
+
const roadmapPath = planningPaths(projectDir).roadmap;
|
|
333
|
+
|
|
334
|
+
let rawContent: string;
|
|
335
|
+
try {
|
|
336
|
+
rawContent = await readFile(roadmapPath, 'utf-8');
|
|
337
|
+
} catch {
|
|
338
|
+
return { data: { error: 'ROADMAP.md not found', milestones: [], phases: [], current_phase: null } };
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const content = await extractCurrentMilestone(rawContent, projectDir);
|
|
342
|
+
const phasesDir = planningPaths(projectDir).phases;
|
|
343
|
+
|
|
344
|
+
// IMPORTANT: Create regex INSIDE the function to avoid /g lastIndex persistence
|
|
345
|
+
const phasePattern = /#{2,4}\s*Phase\s+(\d+[A-Z]?(?:\.\d+)*)\s*:\s*([^\n]+)/gi;
|
|
346
|
+
const phases: Array<Record<string, unknown>> = [];
|
|
347
|
+
let match: RegExpExecArray | null;
|
|
348
|
+
|
|
349
|
+
while ((match = phasePattern.exec(content)) !== null) {
|
|
350
|
+
const phaseNum = match[1];
|
|
351
|
+
const phaseName = match[2].replace(/\(INSERTED\)/i, '').trim();
|
|
352
|
+
|
|
353
|
+
// Extract goal from the section
|
|
354
|
+
const sectionStart = match.index;
|
|
355
|
+
const restOfContent = content.slice(sectionStart);
|
|
356
|
+
const nextHeader = restOfContent.match(/\n#{2,4}\s+Phase\s+\d/i);
|
|
357
|
+
const sectionEnd = nextHeader ? sectionStart + nextHeader.index! : content.length;
|
|
358
|
+
const section = content.slice(sectionStart, sectionEnd);
|
|
359
|
+
|
|
360
|
+
const goalMatch = section.match(/\*\*Goal(?::\*\*|\*\*:)\s*([^\n]+)/i);
|
|
361
|
+
const goal = goalMatch ? goalMatch[1].trim() : null;
|
|
362
|
+
|
|
363
|
+
const dependsMatch = section.match(/\*\*Depends on(?::\*\*|\*\*:)\s*([^\n]+)/i);
|
|
364
|
+
const depends_on = dependsMatch ? dependsMatch[1].trim() : null;
|
|
365
|
+
|
|
366
|
+
// Check completion on disk
|
|
367
|
+
const normalized = normalizePhaseName(phaseNum);
|
|
368
|
+
let diskStatus = 'no_directory';
|
|
369
|
+
let planCount = 0;
|
|
370
|
+
let summaryCount = 0;
|
|
371
|
+
let hasContext = false;
|
|
372
|
+
let hasResearch = false;
|
|
373
|
+
|
|
374
|
+
try {
|
|
375
|
+
const entries = await readdir(phasesDir, { withFileTypes: true });
|
|
376
|
+
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name);
|
|
377
|
+
const dirMatch = dirs.find(d => phaseTokenMatches(d, normalized));
|
|
378
|
+
|
|
379
|
+
if (dirMatch) {
|
|
380
|
+
const phaseFiles = await readdir(join(phasesDir, dirMatch));
|
|
381
|
+
planCount = phaseFiles.filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md').length;
|
|
382
|
+
summaryCount = phaseFiles.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md').length;
|
|
383
|
+
hasContext = phaseFiles.some(f => f.endsWith('-CONTEXT.md') || f === 'CONTEXT.md');
|
|
384
|
+
hasResearch = phaseFiles.some(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
|
|
385
|
+
|
|
386
|
+
if (summaryCount >= planCount && planCount > 0) diskStatus = 'complete';
|
|
387
|
+
else if (summaryCount > 0) diskStatus = 'partial';
|
|
388
|
+
else if (planCount > 0) diskStatus = 'planned';
|
|
389
|
+
else if (hasResearch) diskStatus = 'researched';
|
|
390
|
+
else if (hasContext) diskStatus = 'discussed';
|
|
391
|
+
else diskStatus = 'empty';
|
|
392
|
+
}
|
|
393
|
+
} catch { /* intentionally empty */ }
|
|
394
|
+
|
|
395
|
+
// Check ROADMAP checkbox status
|
|
396
|
+
const checkboxPattern = new RegExp(`-\\s*\\[(x| )\\]\\s*.*Phase\\s+${escapeRegex(phaseNum)}[:\\s]`, 'i');
|
|
397
|
+
const checkboxMatch = content.match(checkboxPattern);
|
|
398
|
+
const roadmapComplete = checkboxMatch ? checkboxMatch[1] === 'x' : false;
|
|
399
|
+
|
|
400
|
+
// If roadmap marks phase complete, trust that over disk
|
|
401
|
+
if (roadmapComplete && diskStatus !== 'complete') {
|
|
402
|
+
diskStatus = 'complete';
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
phases.push({
|
|
406
|
+
number: phaseNum,
|
|
407
|
+
name: phaseName,
|
|
408
|
+
goal,
|
|
409
|
+
depends_on,
|
|
410
|
+
plan_count: planCount,
|
|
411
|
+
summary_count: summaryCount,
|
|
412
|
+
has_context: hasContext,
|
|
413
|
+
has_research: hasResearch,
|
|
414
|
+
disk_status: diskStatus,
|
|
415
|
+
roadmap_complete: roadmapComplete,
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Extract milestone info
|
|
420
|
+
const milestones: Array<{ heading: string; version: string }> = [];
|
|
421
|
+
const milestonePattern = /##\s*(.*v(\d+(?:\.\d+)+)[^(\n]*)/gi;
|
|
422
|
+
let mMatch: RegExpExecArray | null;
|
|
423
|
+
while ((mMatch = milestonePattern.exec(content)) !== null) {
|
|
424
|
+
milestones.push({
|
|
425
|
+
heading: mMatch[1].trim(),
|
|
426
|
+
version: 'v' + mMatch[2],
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// Find current and next phase
|
|
431
|
+
const currentPhase = phases.find(p => p.disk_status === 'planned' || p.disk_status === 'partial') || null;
|
|
432
|
+
const nextPhase = phases.find(p => p.disk_status === 'empty' || p.disk_status === 'no_directory' || p.disk_status === 'discussed' || p.disk_status === 'researched') || null;
|
|
433
|
+
|
|
434
|
+
// Aggregated stats
|
|
435
|
+
const totalPlans = phases.reduce((sum, p) => sum + (p.plan_count as number), 0);
|
|
436
|
+
const totalSummaries = phases.reduce((sum, p) => sum + (p.summary_count as number), 0);
|
|
437
|
+
const completedPhases = phases.filter(p => p.disk_status === 'complete').length;
|
|
438
|
+
|
|
439
|
+
// Detect phases in summary list without detail sections (malformed ROADMAP)
|
|
440
|
+
const checklistPattern = /-\s*\[[ x]\]\s*\*\*Phase\s+(\d+[A-Z]?(?:\.\d+)*)/gi;
|
|
441
|
+
const checklistPhases = new Set<string>();
|
|
442
|
+
let checklistMatch: RegExpExecArray | null;
|
|
443
|
+
while ((checklistMatch = checklistPattern.exec(content)) !== null) {
|
|
444
|
+
checklistPhases.add(checklistMatch[1]);
|
|
445
|
+
}
|
|
446
|
+
const detailPhases = new Set(phases.map(p => p.number as string));
|
|
447
|
+
const missingDetails = [...checklistPhases].filter(p => !detailPhases.has(p));
|
|
448
|
+
|
|
449
|
+
const result: Record<string, unknown> = {
|
|
450
|
+
milestones,
|
|
451
|
+
phases,
|
|
452
|
+
phase_count: phases.length,
|
|
453
|
+
completed_phases: completedPhases,
|
|
454
|
+
total_plans: totalPlans,
|
|
455
|
+
total_summaries: totalSummaries,
|
|
456
|
+
progress_percent: totalPlans > 0 ? Math.min(100, Math.round((totalSummaries / totalPlans) * 100)) : 0,
|
|
457
|
+
current_phase: currentPhase ? currentPhase.number : null,
|
|
458
|
+
next_phase: nextPhase ? nextPhase.number : null,
|
|
459
|
+
missing_phase_details: missingDetails.length > 0 ? missingDetails : null,
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
return { data: result };
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
// ─── roadmapAnnotateDependencies ─────────────────────────────────────────
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Annotate the ROADMAP.md plan list with wave dependency notes and
|
|
470
|
+
* cross-cutting constraints derived from PLAN frontmatter.
|
|
471
|
+
*
|
|
472
|
+
* Delegates to gsd-tools.cjs which holds the full annotation logic.
|
|
473
|
+
* Returns { updated, phase, waves, cross_cutting_constraints }.
|
|
474
|
+
*/
|
|
475
|
+
export const roadmapAnnotateDependencies: QueryHandler = async (args, projectDir) => {
|
|
476
|
+
const phase = args[0];
|
|
477
|
+
if (!phase) {
|
|
478
|
+
return { data: { updated: false, reason: 'phase argument required' } };
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
const { spawnSync } = await import('node:child_process');
|
|
482
|
+
const { fileURLToPath } = await import('node:url');
|
|
483
|
+
|
|
484
|
+
const toolsPath = fileURLToPath(
|
|
485
|
+
new URL('../../../get-shit-done/bin/gsd-tools.cjs', import.meta.url),
|
|
486
|
+
);
|
|
487
|
+
|
|
488
|
+
const result = spawnSync(process.execPath, [toolsPath, 'roadmap', 'annotate-dependencies', phase], {
|
|
489
|
+
cwd: projectDir,
|
|
490
|
+
encoding: 'utf-8',
|
|
491
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
492
|
+
timeout: 15000,
|
|
493
|
+
maxBuffer: 1024 * 1024,
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
if (result.error) {
|
|
497
|
+
return { data: { updated: false, reason: result.error.message || 'gsd-tools invocation failed' } };
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (result.status !== 0) {
|
|
501
|
+
return { data: { updated: false, reason: result.stderr?.trim() || 'gsd-tools error' } };
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
try {
|
|
505
|
+
return { data: JSON.parse(result.stdout.trim()) };
|
|
506
|
+
} catch {
|
|
507
|
+
return { data: { updated: false, reason: 'failed to parse gsd-tools output' } };
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
// ─── requirementsMarkComplete ─────────────────────────────────────────────
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Mark requirement IDs complete in REQUIREMENTS.md (checkbox + traceability table).
|
|
516
|
+
* Port of `cmdRequirementsMarkComplete` from milestone.cjs lines 11–87.
|
|
517
|
+
*/
|
|
518
|
+
export const requirementsMarkComplete: QueryHandler = async (args, projectDir) => {
|
|
519
|
+
if (args.length === 0) {
|
|
520
|
+
throw new GSDError(
|
|
521
|
+
'requirement IDs required. Usage: requirements mark-complete REQ-01,REQ-02 or REQ-01 REQ-02',
|
|
522
|
+
ErrorClassification.Validation,
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
const reqIds = args
|
|
527
|
+
.join(' ')
|
|
528
|
+
.replace(/[\[\]]/g, '')
|
|
529
|
+
.split(/[,\s]+/)
|
|
530
|
+
.map(r => r.trim())
|
|
531
|
+
.filter(Boolean);
|
|
532
|
+
|
|
533
|
+
if (reqIds.length === 0) {
|
|
534
|
+
throw new GSDError('no valid requirement IDs found', ErrorClassification.Validation);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
const paths = planningPaths(projectDir);
|
|
538
|
+
if (!existsSync(paths.requirements)) {
|
|
539
|
+
return { data: { updated: false, reason: 'REQUIREMENTS.md not found', ids: reqIds } };
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
let reqContent = (await readFile(paths.requirements, 'utf-8')).replace(/\r\n/g, '\n');
|
|
543
|
+
const updated: string[] = [];
|
|
544
|
+
const alreadyComplete: string[] = [];
|
|
545
|
+
const notFound: string[] = [];
|
|
546
|
+
|
|
547
|
+
for (const reqId of reqIds) {
|
|
548
|
+
let found = false;
|
|
549
|
+
const reqEscaped = escapeRegex(reqId);
|
|
550
|
+
|
|
551
|
+
const checkboxPattern = new RegExp(`(-\\s*\\[)[ ](\\]\\s*\\*\\*${reqEscaped}\\*\\*)`, 'gi');
|
|
552
|
+
const afterCheckbox = reqContent.replace(checkboxPattern, '$1x$2');
|
|
553
|
+
if (afterCheckbox !== reqContent) {
|
|
554
|
+
reqContent = afterCheckbox;
|
|
555
|
+
found = true;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
const tablePattern = new RegExp(`(\\|\\s*${reqEscaped}\\s*\\|[^|]+\\|)\\s*Pending\\s*(\\|)`, 'gi');
|
|
559
|
+
const afterTable = reqContent.replace(tablePattern, '$1 Complete $2');
|
|
560
|
+
if (afterTable !== reqContent) {
|
|
561
|
+
reqContent = afterTable;
|
|
562
|
+
found = true;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
if (found) {
|
|
566
|
+
updated.push(reqId);
|
|
567
|
+
} else {
|
|
568
|
+
const doneCheckbox = new RegExp(`-\\s*\\[x\\]\\s*\\*\\*${reqEscaped}\\*\\*`, 'i');
|
|
569
|
+
const doneTable = new RegExp(`\\|\\s*${reqEscaped}\\s*\\|[^|]+\\|\\s*Complete\\s*\\|`, 'i');
|
|
570
|
+
if (doneCheckbox.test(reqContent) || doneTable.test(reqContent)) {
|
|
571
|
+
alreadyComplete.push(reqId);
|
|
572
|
+
} else {
|
|
573
|
+
notFound.push(reqId);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
if (updated.length > 0) {
|
|
579
|
+
await writeFile(paths.requirements, reqContent, 'utf-8');
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
return {
|
|
583
|
+
data: {
|
|
584
|
+
updated: updated.length > 0,
|
|
585
|
+
marked_complete: updated,
|
|
586
|
+
already_complete: alreadyComplete,
|
|
587
|
+
not_found: notFound,
|
|
588
|
+
total: reqIds.length,
|
|
589
|
+
},
|
|
590
|
+
};
|
|
591
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { mkdtemp, mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { describe, it, expect } from 'vitest';
|
|
5
|
+
import { routeNextAction } from './route-next-action.js';
|
|
6
|
+
|
|
7
|
+
describe('routeNextAction', () => {
|
|
8
|
+
it('suggests new-project when STATE.md is missing', async () => {
|
|
9
|
+
const dir = await mkdtemp(join(tmpdir(), 'gsd-rna-'));
|
|
10
|
+
await mkdir(join(dir, '.planning'), { recursive: true });
|
|
11
|
+
const { data } = await routeNextAction([], dir);
|
|
12
|
+
expect(data).toMatchObject({
|
|
13
|
+
command: '/gsd-new-project',
|
|
14
|
+
reason: expect.stringContaining('STATE.md'),
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('routes to resume-work when paused', async () => {
|
|
19
|
+
const dir = await mkdtemp(join(tmpdir(), 'gsd-rna-'));
|
|
20
|
+
await mkdir(join(dir, '.planning'), { recursive: true });
|
|
21
|
+
await writeFile(
|
|
22
|
+
join(dir, '.planning', 'STATE.md'),
|
|
23
|
+
`---
|
|
24
|
+
milestone: v1.0
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
**Paused At:** Phase 2
|
|
28
|
+
|
|
29
|
+
`,
|
|
30
|
+
'utf-8',
|
|
31
|
+
);
|
|
32
|
+
await writeFile(join(dir, '.planning', 'ROADMAP.md'), '# Roadmap\n', 'utf-8');
|
|
33
|
+
const { data } = await routeNextAction([], dir);
|
|
34
|
+
expect(data).toMatchObject({
|
|
35
|
+
command: '/gsd-resume-work',
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('blocks when .continue-here.md exists', async () => {
|
|
40
|
+
const dir = await mkdtemp(join(tmpdir(), 'gsd-rna-'));
|
|
41
|
+
await mkdir(join(dir, '.planning'), { recursive: true });
|
|
42
|
+
await writeFile(join(dir, '.planning', '.continue-here.md'), 'checkpoint\n', 'utf-8');
|
|
43
|
+
await writeFile(
|
|
44
|
+
join(dir, '.planning', 'STATE.md'),
|
|
45
|
+
`---
|
|
46
|
+
milestone: v1.0
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
**Current Phase:** 3
|
|
50
|
+
|
|
51
|
+
`,
|
|
52
|
+
'utf-8',
|
|
53
|
+
);
|
|
54
|
+
await writeFile(join(dir, '.planning', 'ROADMAP.md'), '# Roadmap\n', 'utf-8');
|
|
55
|
+
const { data } = await routeNextAction([], dir);
|
|
56
|
+
expect(data).toMatchObject({
|
|
57
|
+
command: '',
|
|
58
|
+
gates: expect.objectContaining({ continue_here: true }),
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|