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,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase-aware prompt factory — assembles complete prompts for each phase type.
|
|
3
|
+
*
|
|
4
|
+
* Reads workflow .md + agent .md files from disk (D006), extracts structured
|
|
5
|
+
* blocks (<role>, <purpose>, <process>), and composes system prompts with
|
|
6
|
+
* injected context files per phase type.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { readFile } from 'node:fs/promises';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
import { fileURLToPath } from 'node:url';
|
|
12
|
+
import { homedir } from 'node:os';
|
|
13
|
+
|
|
14
|
+
import type { ContextFiles, ParsedPlan } from './types.js';
|
|
15
|
+
import { PhaseType } from './types.js';
|
|
16
|
+
import { buildExecutorPrompt, parseAgentRole } from './prompt-builder.js';
|
|
17
|
+
import { PHASE_AGENT_MAP } from './tool-scoping.js';
|
|
18
|
+
import { sanitizePrompt } from './prompt-sanitizer.js';
|
|
19
|
+
|
|
20
|
+
// ─── Workflow file mapping ───────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Maps phase types to their workflow file names.
|
|
24
|
+
*/
|
|
25
|
+
const PHASE_WORKFLOW_MAP: Record<PhaseType, string> = {
|
|
26
|
+
[PhaseType.Execute]: 'execute-plan.md',
|
|
27
|
+
[PhaseType.Research]: 'research-phase.md',
|
|
28
|
+
[PhaseType.Plan]: 'plan-phase.md',
|
|
29
|
+
[PhaseType.Verify]: 'verify-phase.md',
|
|
30
|
+
[PhaseType.Discuss]: 'discuss-phase.md',
|
|
31
|
+
[PhaseType.Repair]: 'execute-plan.md',
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// ─── XML block extraction ────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Extract content from an XML-style block (e.g., <purpose>...</purpose>).
|
|
38
|
+
* Returns the trimmed inner content, or empty string if not found.
|
|
39
|
+
*/
|
|
40
|
+
export function extractBlock(content: string, tagName: string): string {
|
|
41
|
+
const regex = new RegExp(`<${tagName}[^>]*>([\\s\\S]*?)<\\/${tagName}>`, 'i');
|
|
42
|
+
const match = content.match(regex);
|
|
43
|
+
return match ? match[1].trim() : '';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Extract all <step> blocks from a workflow's <process> section.
|
|
48
|
+
* Returns an array of step contents with their name attributes.
|
|
49
|
+
*/
|
|
50
|
+
export function extractSteps(processContent: string): Array<{ name: string; content: string }> {
|
|
51
|
+
const steps: Array<{ name: string; content: string }> = [];
|
|
52
|
+
const stepRegex = /<step\s+name="([^"]*)"[^>]*>([\s\S]*?)<\/step>/gi;
|
|
53
|
+
let match;
|
|
54
|
+
|
|
55
|
+
while ((match = stepRegex.exec(processContent)) !== null) {
|
|
56
|
+
steps.push({
|
|
57
|
+
name: match[1],
|
|
58
|
+
content: match[2].trim(),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return steps;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ─── PromptFactory class ─────────────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
export class PromptFactory {
|
|
68
|
+
private readonly workflowsDir: string;
|
|
69
|
+
private readonly agentsDir: string;
|
|
70
|
+
private readonly projectAgentsDir?: string;
|
|
71
|
+
private readonly sdkPromptsDir: string;
|
|
72
|
+
|
|
73
|
+
constructor(options?: {
|
|
74
|
+
gsdInstallDir?: string;
|
|
75
|
+
agentsDir?: string;
|
|
76
|
+
projectAgentsDir?: string;
|
|
77
|
+
sdkPromptsDir?: string;
|
|
78
|
+
}) {
|
|
79
|
+
const gsdInstallDir = options?.gsdInstallDir ?? join(homedir(), '.claude', 'get-shit-done');
|
|
80
|
+
this.workflowsDir = join(gsdInstallDir, 'workflows');
|
|
81
|
+
this.agentsDir = options?.agentsDir ?? join(homedir(), '.claude', 'agents');
|
|
82
|
+
this.projectAgentsDir = options?.projectAgentsDir;
|
|
83
|
+
// SDK prompts dir: explicit override → package-relative default via import.meta.url
|
|
84
|
+
this.sdkPromptsDir =
|
|
85
|
+
options?.sdkPromptsDir ??
|
|
86
|
+
join(fileURLToPath(new URL('.', import.meta.url)), '..', 'prompts');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Build a complete prompt for the given phase type.
|
|
91
|
+
*
|
|
92
|
+
* For execute phase with a plan, delegates to buildExecutorPrompt().
|
|
93
|
+
* For other phases, assembles: role + purpose + process steps + context.
|
|
94
|
+
*/
|
|
95
|
+
async buildPrompt(
|
|
96
|
+
phaseType: PhaseType,
|
|
97
|
+
plan: ParsedPlan | null,
|
|
98
|
+
contextFiles: ContextFiles,
|
|
99
|
+
): Promise<string> {
|
|
100
|
+
// Execute phase with a plan: delegate to existing buildExecutorPrompt
|
|
101
|
+
if (phaseType === PhaseType.Execute && plan) {
|
|
102
|
+
const agentDef = await this.loadAgentDef(phaseType);
|
|
103
|
+
return sanitizePrompt(buildExecutorPrompt(plan, agentDef));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Prompt assembly order is cache-optimized (#1614):
|
|
107
|
+
// Stable prefix (deterministic per phase type) → cached by Anthropic at 0.1x cost
|
|
108
|
+
// Variable suffix (.planning/ files) → uncached, changes per project/run
|
|
109
|
+
const sections: string[] = [];
|
|
110
|
+
|
|
111
|
+
// ── STABLE PREFIX (cacheable across runs for the same phase type) ──
|
|
112
|
+
|
|
113
|
+
// ── Agent role ──
|
|
114
|
+
const agentDef = await this.loadAgentDef(phaseType);
|
|
115
|
+
if (agentDef) {
|
|
116
|
+
const role = parseAgentRole(agentDef);
|
|
117
|
+
if (role) {
|
|
118
|
+
sections.push(`## Role\n\n${role}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ── Workflow purpose + process ──
|
|
123
|
+
const workflow = await this.loadWorkflowFile(phaseType);
|
|
124
|
+
if (workflow) {
|
|
125
|
+
const purpose = extractBlock(workflow, 'purpose');
|
|
126
|
+
if (purpose) {
|
|
127
|
+
sections.push(`## Purpose\n\n${purpose}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const process = extractBlock(workflow, 'process');
|
|
131
|
+
if (process) {
|
|
132
|
+
const steps = extractSteps(process);
|
|
133
|
+
if (steps.length > 0) {
|
|
134
|
+
const stepBlocks = steps.map((s) => `### ${s.name}\n\n${s.content}`).join('\n\n');
|
|
135
|
+
sections.push(`## Process\n\n${stepBlocks}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ── Phase-specific instructions (hardcoded per phase type — stable) ──
|
|
141
|
+
const phaseInstructions = this.getPhaseInstructions(phaseType);
|
|
142
|
+
if (phaseInstructions) {
|
|
143
|
+
sections.push(`## Phase Instructions\n\n${phaseInstructions}`);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ── VARIABLE SUFFIX (project-specific, changes per run) ──
|
|
147
|
+
|
|
148
|
+
// ── Context files ──
|
|
149
|
+
const contextSection = this.formatContextFiles(contextFiles);
|
|
150
|
+
if (contextSection) {
|
|
151
|
+
sections.push(contextSection);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return sanitizePrompt(sections.join('\n\n'));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Load the workflow file for a phase type.
|
|
159
|
+
* Tries sdk/prompts/workflows/ first (headless versions), then
|
|
160
|
+
* falls back to GSD-1 originals in workflowsDir.
|
|
161
|
+
* Returns the raw content, or undefined if not found.
|
|
162
|
+
*/
|
|
163
|
+
async loadWorkflowFile(phaseType: PhaseType): Promise<string | undefined> {
|
|
164
|
+
const filename = PHASE_WORKFLOW_MAP[phaseType];
|
|
165
|
+
|
|
166
|
+
// Try SDK prompts dir first (headless versions)
|
|
167
|
+
const sdkPath = join(this.sdkPromptsDir, 'workflows', filename);
|
|
168
|
+
try {
|
|
169
|
+
return await readFile(sdkPath, 'utf-8');
|
|
170
|
+
} catch {
|
|
171
|
+
// Not in sdk/prompts/, fall through to GSD-1 originals
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Fall back to GSD-1 originals
|
|
175
|
+
const filePath = join(this.workflowsDir, filename);
|
|
176
|
+
try {
|
|
177
|
+
return await readFile(filePath, 'utf-8');
|
|
178
|
+
} catch {
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Load the agent definition for a phase type.
|
|
185
|
+
* Tries sdk/prompts/agents/ first (headless versions), then
|
|
186
|
+
* user-level agents dir, then project-level.
|
|
187
|
+
* Returns undefined if no agent is mapped or file not found.
|
|
188
|
+
*/
|
|
189
|
+
async loadAgentDef(phaseType: PhaseType): Promise<string | undefined> {
|
|
190
|
+
const agentFilename = PHASE_AGENT_MAP[phaseType];
|
|
191
|
+
if (!agentFilename) return undefined;
|
|
192
|
+
|
|
193
|
+
// Try SDK prompts dir first (headless versions)
|
|
194
|
+
const paths = [
|
|
195
|
+
join(this.sdkPromptsDir, 'agents', agentFilename),
|
|
196
|
+
join(this.agentsDir, agentFilename),
|
|
197
|
+
];
|
|
198
|
+
|
|
199
|
+
// Then project-level if configured
|
|
200
|
+
if (this.projectAgentsDir) {
|
|
201
|
+
paths.push(join(this.projectAgentsDir, agentFilename));
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
for (const p of paths) {
|
|
205
|
+
try {
|
|
206
|
+
return await readFile(p, 'utf-8');
|
|
207
|
+
} catch {
|
|
208
|
+
// Not found at this path, try next
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return undefined;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Format context files into a prompt section.
|
|
217
|
+
*/
|
|
218
|
+
private formatContextFiles(contextFiles: ContextFiles): string | null {
|
|
219
|
+
const entries: string[] = [];
|
|
220
|
+
|
|
221
|
+
const fileLabels: Record<keyof ContextFiles, string> = {
|
|
222
|
+
state: 'Project State (STATE.md)',
|
|
223
|
+
roadmap: 'Roadmap (ROADMAP.md)',
|
|
224
|
+
context: 'Context (CONTEXT.md)',
|
|
225
|
+
research: 'Research (RESEARCH.md)',
|
|
226
|
+
requirements: 'Requirements (REQUIREMENTS.md)',
|
|
227
|
+
config: 'Config (config.json)',
|
|
228
|
+
plan: 'Plan (PLAN.md)',
|
|
229
|
+
summary: 'Summary (SUMMARY.md)',
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
for (const [key, label] of Object.entries(fileLabels)) {
|
|
233
|
+
const content = contextFiles[key as keyof ContextFiles];
|
|
234
|
+
if (content) {
|
|
235
|
+
entries.push(`### ${label}\n\n${content}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (entries.length === 0) return null;
|
|
240
|
+
return `## Context\n\n${entries.join('\n\n')}`;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Get phase-specific instructions that aren't covered by the workflow file.
|
|
245
|
+
*/
|
|
246
|
+
private getPhaseInstructions(phaseType: PhaseType): string | null {
|
|
247
|
+
switch (phaseType) {
|
|
248
|
+
case PhaseType.Research:
|
|
249
|
+
return 'Focus on technical investigation. Do not modify source files. Produce RESEARCH.md with findings organized by topic, confidence levels (HIGH/MEDIUM/LOW), and specific recommendations.';
|
|
250
|
+
case PhaseType.Plan:
|
|
251
|
+
return 'Create executable plans with task breakdown, dependency analysis, and verification criteria. Each task must have clear acceptance criteria and a done condition.';
|
|
252
|
+
case PhaseType.Verify:
|
|
253
|
+
return 'Verify goal achievement, not just task completion. Start from what the phase SHOULD deliver, then verify it actually exists and works. Produce VERIFICATION.md with pass/fail for each criterion.';
|
|
254
|
+
case PhaseType.Discuss:
|
|
255
|
+
return 'Extract implementation decisions that downstream agents need. Identify gray areas, capture decisions that guide research and planning.';
|
|
256
|
+
case PhaseType.Execute:
|
|
257
|
+
return null;
|
|
258
|
+
default:
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export { PHASE_WORKFLOW_MAP };
|
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { GSDTools, GSDToolsError } from './gsd-tools.js';
|
|
3
|
+
import {
|
|
4
|
+
PhaseStepType,
|
|
5
|
+
GSDEventType,
|
|
6
|
+
PhaseType,
|
|
7
|
+
type PhaseOpInfo,
|
|
8
|
+
type PhaseStepResult,
|
|
9
|
+
type PhaseRunnerResult,
|
|
10
|
+
type HumanGateCallbacks,
|
|
11
|
+
type PhaseRunnerOptions,
|
|
12
|
+
type GSDPhaseStartEvent,
|
|
13
|
+
type GSDPhaseStepStartEvent,
|
|
14
|
+
type GSDPhaseStepCompleteEvent,
|
|
15
|
+
type GSDPhaseCompleteEvent,
|
|
16
|
+
} from './types.js';
|
|
17
|
+
import { mkdir, writeFile, rm } from 'node:fs/promises';
|
|
18
|
+
import { join } from 'node:path';
|
|
19
|
+
import { tmpdir } from 'node:os';
|
|
20
|
+
|
|
21
|
+
describe('Phase lifecycle types', () => {
|
|
22
|
+
// ─── PhaseStepType enum ────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
describe('PhaseStepType', () => {
|
|
25
|
+
it('has all expected step values', () => {
|
|
26
|
+
expect(PhaseStepType.Discuss).toBe('discuss');
|
|
27
|
+
expect(PhaseStepType.Research).toBe('research');
|
|
28
|
+
expect(PhaseStepType.Plan).toBe('plan');
|
|
29
|
+
expect(PhaseStepType.Execute).toBe('execute');
|
|
30
|
+
expect(PhaseStepType.Verify).toBe('verify');
|
|
31
|
+
expect(PhaseStepType.Advance).toBe('advance');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('has exactly 7 members', () => {
|
|
35
|
+
const values = Object.values(PhaseStepType);
|
|
36
|
+
expect(values).toHaveLength(7);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// ─── GSDEventType phase lifecycle values ───────────────────────────────
|
|
41
|
+
|
|
42
|
+
describe('GSDEventType phase lifecycle events', () => {
|
|
43
|
+
it('includes PhaseStart', () => {
|
|
44
|
+
expect(GSDEventType.PhaseStart).toBe('phase_start');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('includes PhaseStepStart', () => {
|
|
48
|
+
expect(GSDEventType.PhaseStepStart).toBe('phase_step_start');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('includes PhaseStepComplete', () => {
|
|
52
|
+
expect(GSDEventType.PhaseStepComplete).toBe('phase_step_complete');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('includes PhaseComplete', () => {
|
|
56
|
+
expect(GSDEventType.PhaseComplete).toBe('phase_complete');
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// ─── PhaseOpInfo shape validation ──────────────────────────────────────
|
|
61
|
+
|
|
62
|
+
describe('PhaseOpInfo interface', () => {
|
|
63
|
+
it('accepts a valid phase-op output object', () => {
|
|
64
|
+
const info: PhaseOpInfo = {
|
|
65
|
+
phase_found: true,
|
|
66
|
+
phase_dir: '.planning/phases/05-Skill-Scaffolding',
|
|
67
|
+
phase_number: '5',
|
|
68
|
+
phase_name: 'Skill Scaffolding',
|
|
69
|
+
phase_slug: 'skill-scaffolding',
|
|
70
|
+
padded_phase: '05',
|
|
71
|
+
has_research: false,
|
|
72
|
+
has_context: false,
|
|
73
|
+
has_plans: false,
|
|
74
|
+
has_verification: false,
|
|
75
|
+
plan_count: 0,
|
|
76
|
+
roadmap_exists: true,
|
|
77
|
+
planning_exists: true,
|
|
78
|
+
commit_docs: true,
|
|
79
|
+
context_path: '.planning/phases/05-Skill-Scaffolding/CONTEXT.md',
|
|
80
|
+
research_path: '.planning/phases/05-Skill-Scaffolding/RESEARCH.md',
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
expect(info.phase_found).toBe(true);
|
|
84
|
+
expect(info.phase_number).toBe('5');
|
|
85
|
+
expect(info.plan_count).toBe(0);
|
|
86
|
+
expect(info.has_context).toBe(false);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('matches the documented init phase-op JSON shape', () => {
|
|
90
|
+
// Simulate parsing JSON from gsd-tools.cjs
|
|
91
|
+
const raw = JSON.parse(JSON.stringify({
|
|
92
|
+
phase_found: true,
|
|
93
|
+
phase_dir: '.planning/phases/03-Auth',
|
|
94
|
+
phase_number: '3',
|
|
95
|
+
phase_name: 'Auth',
|
|
96
|
+
phase_slug: 'auth',
|
|
97
|
+
padded_phase: '03',
|
|
98
|
+
has_research: true,
|
|
99
|
+
has_context: true,
|
|
100
|
+
has_plans: true,
|
|
101
|
+
has_verification: false,
|
|
102
|
+
plan_count: 2,
|
|
103
|
+
roadmap_exists: true,
|
|
104
|
+
planning_exists: true,
|
|
105
|
+
commit_docs: true,
|
|
106
|
+
context_path: '.planning/phases/03-Auth/CONTEXT.md',
|
|
107
|
+
research_path: '.planning/phases/03-Auth/RESEARCH.md',
|
|
108
|
+
}));
|
|
109
|
+
|
|
110
|
+
const info = raw as PhaseOpInfo;
|
|
111
|
+
expect(info.phase_found).toBe(true);
|
|
112
|
+
expect(info.has_plans).toBe(true);
|
|
113
|
+
expect(info.plan_count).toBe(2);
|
|
114
|
+
expect(typeof info.phase_dir).toBe('string');
|
|
115
|
+
expect(typeof info.padded_phase).toBe('string');
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// ─── Phase result types ────────────────────────────────────────────────
|
|
120
|
+
|
|
121
|
+
describe('PhaseStepResult', () => {
|
|
122
|
+
it('can represent a successful step', () => {
|
|
123
|
+
const result: PhaseStepResult = {
|
|
124
|
+
step: PhaseStepType.Research,
|
|
125
|
+
success: true,
|
|
126
|
+
durationMs: 5000,
|
|
127
|
+
};
|
|
128
|
+
expect(result.success).toBe(true);
|
|
129
|
+
expect(result.error).toBeUndefined();
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('can represent a failed step with error', () => {
|
|
133
|
+
const result: PhaseStepResult = {
|
|
134
|
+
step: PhaseStepType.Execute,
|
|
135
|
+
success: false,
|
|
136
|
+
durationMs: 12000,
|
|
137
|
+
error: 'Session timed out',
|
|
138
|
+
planResults: [],
|
|
139
|
+
};
|
|
140
|
+
expect(result.success).toBe(false);
|
|
141
|
+
expect(result.error).toBe('Session timed out');
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe('PhaseRunnerResult', () => {
|
|
146
|
+
it('can represent a complete phase run', () => {
|
|
147
|
+
const result: PhaseRunnerResult = {
|
|
148
|
+
phaseNumber: '3',
|
|
149
|
+
phaseName: 'Auth',
|
|
150
|
+
steps: [
|
|
151
|
+
{ step: PhaseStepType.Research, success: true, durationMs: 5000 },
|
|
152
|
+
{ step: PhaseStepType.Plan, success: true, durationMs: 3000 },
|
|
153
|
+
{ step: PhaseStepType.Execute, success: true, durationMs: 60000 },
|
|
154
|
+
],
|
|
155
|
+
success: true,
|
|
156
|
+
totalCostUsd: 1.5,
|
|
157
|
+
totalDurationMs: 68000,
|
|
158
|
+
};
|
|
159
|
+
expect(result.steps).toHaveLength(3);
|
|
160
|
+
expect(result.success).toBe(true);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
describe('HumanGateCallbacks', () => {
|
|
165
|
+
it('accepts an object with all optional callbacks', () => {
|
|
166
|
+
const callbacks: HumanGateCallbacks = {
|
|
167
|
+
onDiscussApproval: async () => 'approve',
|
|
168
|
+
onVerificationReview: async () => 'accept',
|
|
169
|
+
onBlockerDecision: async () => 'retry',
|
|
170
|
+
};
|
|
171
|
+
expect(callbacks.onDiscussApproval).toBeDefined();
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('accepts an empty object (all callbacks optional)', () => {
|
|
175
|
+
const callbacks: HumanGateCallbacks = {};
|
|
176
|
+
expect(callbacks.onDiscussApproval).toBeUndefined();
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
describe('PhaseRunnerOptions', () => {
|
|
181
|
+
it('accepts full options', () => {
|
|
182
|
+
const options: PhaseRunnerOptions = {
|
|
183
|
+
callbacks: {},
|
|
184
|
+
maxBudgetPerStep: 3.0,
|
|
185
|
+
maxTurnsPerStep: 30,
|
|
186
|
+
model: 'claude-sonnet-4-6',
|
|
187
|
+
};
|
|
188
|
+
expect(options.maxBudgetPerStep).toBe(3.0);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('accepts empty options (all fields optional)', () => {
|
|
192
|
+
const options: PhaseRunnerOptions = {};
|
|
193
|
+
expect(options.callbacks).toBeUndefined();
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// ─── Phase lifecycle event interfaces ──────────────────────────────────
|
|
198
|
+
|
|
199
|
+
describe('Phase lifecycle event interfaces', () => {
|
|
200
|
+
it('GSDPhaseStartEvent has correct shape', () => {
|
|
201
|
+
const event: GSDPhaseStartEvent = {
|
|
202
|
+
type: GSDEventType.PhaseStart,
|
|
203
|
+
timestamp: new Date().toISOString(),
|
|
204
|
+
sessionId: 'test-session',
|
|
205
|
+
phaseNumber: '3',
|
|
206
|
+
phaseName: 'Auth',
|
|
207
|
+
};
|
|
208
|
+
expect(event.type).toBe('phase_start');
|
|
209
|
+
expect(event.phaseNumber).toBe('3');
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('GSDPhaseStepStartEvent has correct shape', () => {
|
|
213
|
+
const event: GSDPhaseStepStartEvent = {
|
|
214
|
+
type: GSDEventType.PhaseStepStart,
|
|
215
|
+
timestamp: new Date().toISOString(),
|
|
216
|
+
sessionId: 'test-session',
|
|
217
|
+
phaseNumber: '3',
|
|
218
|
+
step: PhaseStepType.Research,
|
|
219
|
+
};
|
|
220
|
+
expect(event.type).toBe('phase_step_start');
|
|
221
|
+
expect(event.step).toBe('research');
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('GSDPhaseStepCompleteEvent has correct shape', () => {
|
|
225
|
+
const event: GSDPhaseStepCompleteEvent = {
|
|
226
|
+
type: GSDEventType.PhaseStepComplete,
|
|
227
|
+
timestamp: new Date().toISOString(),
|
|
228
|
+
sessionId: 'test-session',
|
|
229
|
+
phaseNumber: '3',
|
|
230
|
+
step: PhaseStepType.Execute,
|
|
231
|
+
success: true,
|
|
232
|
+
durationMs: 45000,
|
|
233
|
+
};
|
|
234
|
+
expect(event.type).toBe('phase_step_complete');
|
|
235
|
+
expect(event.success).toBe(true);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it('GSDPhaseStepCompleteEvent can include error', () => {
|
|
239
|
+
const event: GSDPhaseStepCompleteEvent = {
|
|
240
|
+
type: GSDEventType.PhaseStepComplete,
|
|
241
|
+
timestamp: new Date().toISOString(),
|
|
242
|
+
sessionId: 'test-session',
|
|
243
|
+
phaseNumber: '3',
|
|
244
|
+
step: PhaseStepType.Verify,
|
|
245
|
+
success: false,
|
|
246
|
+
durationMs: 2000,
|
|
247
|
+
error: 'Verification failed',
|
|
248
|
+
};
|
|
249
|
+
expect(event.error).toBe('Verification failed');
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it('GSDPhaseCompleteEvent has correct shape', () => {
|
|
253
|
+
const event: GSDPhaseCompleteEvent = {
|
|
254
|
+
type: GSDEventType.PhaseComplete,
|
|
255
|
+
timestamp: new Date().toISOString(),
|
|
256
|
+
sessionId: 'test-session',
|
|
257
|
+
phaseNumber: '3',
|
|
258
|
+
phaseName: 'Auth',
|
|
259
|
+
success: true,
|
|
260
|
+
totalCostUsd: 2.5,
|
|
261
|
+
totalDurationMs: 120000,
|
|
262
|
+
stepsCompleted: 5,
|
|
263
|
+
};
|
|
264
|
+
expect(event.type).toBe('phase_complete');
|
|
265
|
+
expect(event.stepsCompleted).toBe(5);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// ─── GSDTools typed methods ──────────────────────────────────────────────────
|
|
271
|
+
|
|
272
|
+
describe('GSDTools typed methods', () => {
|
|
273
|
+
let tmpDir: string;
|
|
274
|
+
let fixtureDir: string;
|
|
275
|
+
|
|
276
|
+
beforeEach(async () => {
|
|
277
|
+
tmpDir = join(tmpdir(), `gsd-tools-phase-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
278
|
+
fixtureDir = join(tmpDir, 'fixtures');
|
|
279
|
+
await mkdir(fixtureDir, { recursive: true });
|
|
280
|
+
await mkdir(join(tmpDir, '.planning'), { recursive: true });
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
afterEach(async () => {
|
|
284
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
async function createScript(name: string, code: string): Promise<string> {
|
|
288
|
+
const scriptPath = join(fixtureDir, name);
|
|
289
|
+
await writeFile(scriptPath, code, { mode: 0o755 });
|
|
290
|
+
return scriptPath;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
describe('initPhaseOp()', () => {
|
|
294
|
+
it('returns typed PhaseOpInfo from gsd-tools output', async () => {
|
|
295
|
+
const mockOutput: PhaseOpInfo = {
|
|
296
|
+
phase_found: true,
|
|
297
|
+
phase_dir: '.planning/phases/05-Skill-Scaffolding',
|
|
298
|
+
phase_number: '5',
|
|
299
|
+
phase_name: 'Skill Scaffolding',
|
|
300
|
+
phase_slug: 'skill-scaffolding',
|
|
301
|
+
padded_phase: '05',
|
|
302
|
+
has_research: false,
|
|
303
|
+
has_context: true,
|
|
304
|
+
has_plans: true,
|
|
305
|
+
has_verification: false,
|
|
306
|
+
plan_count: 3,
|
|
307
|
+
roadmap_exists: true,
|
|
308
|
+
planning_exists: true,
|
|
309
|
+
commit_docs: true,
|
|
310
|
+
context_path: '.planning/phases/05-Skill-Scaffolding/CONTEXT.md',
|
|
311
|
+
research_path: '.planning/phases/05-Skill-Scaffolding/RESEARCH.md',
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
const scriptPath = await createScript(
|
|
315
|
+
'init-phase-op.cjs',
|
|
316
|
+
`
|
|
317
|
+
const args = process.argv.slice(2);
|
|
318
|
+
// Script receives: init phase-op 5 --raw
|
|
319
|
+
if (args[0] === 'init' && args[1] === 'phase-op' && args[2] === '5') {
|
|
320
|
+
process.stdout.write(JSON.stringify(${JSON.stringify(mockOutput)}));
|
|
321
|
+
} else {
|
|
322
|
+
process.stderr.write('unexpected args: ' + args.join(' '));
|
|
323
|
+
process.exit(1);
|
|
324
|
+
}
|
|
325
|
+
`,
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
const tools = new GSDTools({ projectDir: tmpDir, gsdToolsPath: scriptPath, preferNativeQuery: false });
|
|
329
|
+
const result = await tools.initPhaseOp('5');
|
|
330
|
+
|
|
331
|
+
expect(result.phase_found).toBe(true);
|
|
332
|
+
expect(result.phase_number).toBe('5');
|
|
333
|
+
expect(result.phase_name).toBe('Skill Scaffolding');
|
|
334
|
+
expect(result.plan_count).toBe(3);
|
|
335
|
+
expect(result.has_context).toBe(true);
|
|
336
|
+
expect(result.has_plans).toBe(true);
|
|
337
|
+
expect(result.context_path).toContain('CONTEXT.md');
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
it('calls exec with correct args (init phase-op <N>)', async () => {
|
|
341
|
+
const scriptPath = await createScript(
|
|
342
|
+
'init-phase-op-args.cjs',
|
|
343
|
+
`
|
|
344
|
+
const args = process.argv.slice(2);
|
|
345
|
+
process.stdout.write(JSON.stringify({ received_args: args }));
|
|
346
|
+
`,
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
const tools = new GSDTools({ projectDir: tmpDir, gsdToolsPath: scriptPath, preferNativeQuery: false });
|
|
350
|
+
const result = await tools.initPhaseOp('7') as { received_args: string[] };
|
|
351
|
+
|
|
352
|
+
expect(result.received_args).toContain('init');
|
|
353
|
+
expect(result.received_args).toContain('phase-op');
|
|
354
|
+
expect(result.received_args).toContain('7');
|
|
355
|
+
// exec() no longer appends --raw (only execRaw does)
|
|
356
|
+
expect(result.received_args).not.toContain('--raw');
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
describe('configGet()', () => {
|
|
361
|
+
it('returns string value from gsd-tools config', async () => {
|
|
362
|
+
const scriptPath = await createScript(
|
|
363
|
+
'config-get.cjs',
|
|
364
|
+
`
|
|
365
|
+
const args = process.argv.slice(2);
|
|
366
|
+
if (args[0] === 'config-get' && args[1] === 'model_profile') {
|
|
367
|
+
process.stdout.write(JSON.stringify('balanced'));
|
|
368
|
+
} else {
|
|
369
|
+
process.exit(1);
|
|
370
|
+
}
|
|
371
|
+
`,
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
const tools = new GSDTools({ projectDir: tmpDir, gsdToolsPath: scriptPath, preferNativeQuery: false });
|
|
375
|
+
const result = await tools.configGet('model_profile');
|
|
376
|
+
|
|
377
|
+
expect(result).toBe('balanced');
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
it('returns null when key not found', async () => {
|
|
381
|
+
const scriptPath = await createScript(
|
|
382
|
+
'config-get-null.cjs',
|
|
383
|
+
`
|
|
384
|
+
const args = process.argv.slice(2);
|
|
385
|
+
if (args[0] === 'config-get' && args[1] === 'nonexistent_key') {
|
|
386
|
+
process.stdout.write('null');
|
|
387
|
+
} else {
|
|
388
|
+
process.exit(1);
|
|
389
|
+
}
|
|
390
|
+
`,
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
const tools = new GSDTools({ projectDir: tmpDir, gsdToolsPath: scriptPath, preferNativeQuery: false });
|
|
394
|
+
const result = await tools.configGet('nonexistent_key');
|
|
395
|
+
|
|
396
|
+
expect(result).toBeNull();
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
describe('stateBeginPhase()', () => {
|
|
401
|
+
it('calls state begin-phase with correct args', async () => {
|
|
402
|
+
const scriptPath = await createScript(
|
|
403
|
+
'state-begin-phase.cjs',
|
|
404
|
+
`
|
|
405
|
+
const args = process.argv.slice(2);
|
|
406
|
+
if (args[0] === 'state' && args[1] === 'begin-phase' && args[2] === '--phase' && args[3] === '3') {
|
|
407
|
+
process.stdout.write('ok');
|
|
408
|
+
} else {
|
|
409
|
+
process.stderr.write('unexpected args: ' + args.join(' '));
|
|
410
|
+
process.exit(1);
|
|
411
|
+
}
|
|
412
|
+
`,
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
const tools = new GSDTools({ projectDir: tmpDir, gsdToolsPath: scriptPath, preferNativeQuery: false });
|
|
416
|
+
const result = await tools.stateBeginPhase('3');
|
|
417
|
+
|
|
418
|
+
expect(result).toBe('ok');
|
|
419
|
+
});
|
|
420
|
+
});
|
|
421
|
+
});
|