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,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Research gate — validates RESEARCH.md for unresolved open questions
|
|
3
|
+
* before allowing plan-phase to proceed (#1602).
|
|
4
|
+
*
|
|
5
|
+
* Pure functions: no I/O, no side effects. The caller reads the file
|
|
6
|
+
* and passes the content string.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// ─── Types ──────────────────────────────────────────────────────────────────
|
|
10
|
+
|
|
11
|
+
export interface ResearchGateResult {
|
|
12
|
+
/** Whether research is clear to proceed to planning */
|
|
13
|
+
pass: boolean;
|
|
14
|
+
/** Unresolved questions found (empty if pass=true) */
|
|
15
|
+
unresolvedQuestions: string[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// ─── Open questions detection ───────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Check RESEARCH.md content for unresolved open questions.
|
|
22
|
+
*
|
|
23
|
+
* Rules:
|
|
24
|
+
* - If no "## Open Questions" section exists → pass
|
|
25
|
+
* - If section header has "(RESOLVED)" suffix → pass
|
|
26
|
+
* - If section exists but is empty (only whitespace before next heading) → pass
|
|
27
|
+
* - Otherwise → fail with list of unresolved questions
|
|
28
|
+
*/
|
|
29
|
+
export function checkResearchGate(researchContent: string): ResearchGateResult {
|
|
30
|
+
// Find "## Open Questions" section (case-insensitive)
|
|
31
|
+
const sectionMatch = researchContent.match(
|
|
32
|
+
/^##\s+Open\s+Questions\b([^\n]*)/im,
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
if (!sectionMatch) {
|
|
36
|
+
return { pass: true, unresolvedQuestions: [] };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Check for (RESOLVED) suffix on the heading
|
|
40
|
+
const headingSuffix = sectionMatch[1].trim();
|
|
41
|
+
if (/\(resolved\)/i.test(headingSuffix)) {
|
|
42
|
+
return { pass: true, unresolvedQuestions: [] };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Extract section content until next heading or EOF
|
|
46
|
+
const headingIndex = researchContent.indexOf(sectionMatch[0]);
|
|
47
|
+
const afterHeading = researchContent.slice(headingIndex + sectionMatch[0].length);
|
|
48
|
+
|
|
49
|
+
// Find next heading at same or higher level
|
|
50
|
+
const nextHeadingMatch = afterHeading.match(/\n##\s+[^\n]/);
|
|
51
|
+
const sectionBody = nextHeadingMatch
|
|
52
|
+
? afterHeading.slice(0, nextHeadingMatch.index)
|
|
53
|
+
: afterHeading;
|
|
54
|
+
|
|
55
|
+
// Extract question items (numbered list or bullet points)
|
|
56
|
+
const unresolvedQuestions: string[] = [];
|
|
57
|
+
let totalQuestionLines = 0;
|
|
58
|
+
const lines = sectionBody.split('\n');
|
|
59
|
+
|
|
60
|
+
for (const line of lines) {
|
|
61
|
+
const trimmed = line.trim();
|
|
62
|
+
// Match: "1. **Question**", "- **Question**", "* **Question**", "1. Question"
|
|
63
|
+
const questionMatch = trimmed.match(
|
|
64
|
+
/^(?:\d+[.)]\s*|\*\s+|-\s+)\*{0,2}([^*\n]+)\*{0,2}/,
|
|
65
|
+
);
|
|
66
|
+
if (questionMatch) {
|
|
67
|
+
totalQuestionLines++;
|
|
68
|
+
const questionText = questionMatch[1].trim();
|
|
69
|
+
// Skip questions marked as resolved inline (handles — RESOLVED, - RESOLVED, RESOLVED:, etc.)
|
|
70
|
+
if (!/\bresolved\b/i.test(trimmed)) {
|
|
71
|
+
unresolvedQuestions.push(questionText);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Empty section body → pass
|
|
77
|
+
if (sectionBody.trim() === '') {
|
|
78
|
+
return { pass: true, unresolvedQuestions: [] };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// All question lines were resolved → pass
|
|
82
|
+
if (totalQuestionLines > 0 && unresolvedQuestions.length === 0) {
|
|
83
|
+
return { pass: true, unresolvedQuestions: [] };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Unresolved questions found → fail
|
|
87
|
+
if (unresolvedQuestions.length > 0) {
|
|
88
|
+
return { pass: false, unresolvedQuestions };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Section has content but no parseable question lines → fail conservatively
|
|
92
|
+
// (e.g., prose-style questions without list formatting)
|
|
93
|
+
return { pass: false, unresolvedQuestions: ['(unstructured open questions detected — review ## Open Questions section)'] };
|
|
94
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
|
|
6
|
+
import { runRuntimeHealth } from './runtime-health.js';
|
|
7
|
+
|
|
8
|
+
async function createProject(): Promise<{ projectDir: string; cleanup: () => Promise<void> }> {
|
|
9
|
+
const projectDir = await mkdtemp(join(tmpdir(), 'gsd-runtime-health-'));
|
|
10
|
+
return {
|
|
11
|
+
projectDir,
|
|
12
|
+
cleanup: () => rm(projectDir, { recursive: true, force: true }),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function createNodeScript(projectDir: string, name: string, body: string): Promise<string> {
|
|
17
|
+
const filePath = join(projectDir, name);
|
|
18
|
+
await writeFile(filePath, body, 'utf-8');
|
|
19
|
+
return filePath;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function createIdentity(dir: string, extra: Record<string, unknown> = {}): Promise<string> {
|
|
23
|
+
await mkdir(dir, { recursive: true });
|
|
24
|
+
const filePath = join(dir, 'IDENTITY.json');
|
|
25
|
+
await writeFile(filePath, JSON.stringify({
|
|
26
|
+
distribution: 'gsd-remix',
|
|
27
|
+
package_name: 'gsd-remix',
|
|
28
|
+
version: '1.37.1',
|
|
29
|
+
display_name: 'GSD Remix',
|
|
30
|
+
...extra,
|
|
31
|
+
}), 'utf-8');
|
|
32
|
+
return filePath;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe('runtime-health', () => {
|
|
36
|
+
const cleanups: Array<() => Promise<void>> = [];
|
|
37
|
+
|
|
38
|
+
afterEach(async () => {
|
|
39
|
+
await Promise.all(cleanups.splice(0).map(fn => fn()));
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('passes when node version is supported and the legacy bridge probe succeeds', async () => {
|
|
43
|
+
const { projectDir, cleanup } = await createProject();
|
|
44
|
+
cleanups.push(cleanup);
|
|
45
|
+
|
|
46
|
+
const bridgePath = await createNodeScript(
|
|
47
|
+
projectDir,
|
|
48
|
+
'gsd-tools-ok.cjs',
|
|
49
|
+
`process.stdout.write('/tmp/config.json\\n');`,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const result = await runRuntimeHealth(projectDir, {
|
|
53
|
+
nodeVersion: 'v22.4.1',
|
|
54
|
+
requiredNodeRange: '>=22.0.0',
|
|
55
|
+
gsdToolsCandidates: [{ path: bridgePath, source: 'custom' }],
|
|
56
|
+
runtimeIdentityPath: await createIdentity(projectDir),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
expect(result.passed).toBe(true);
|
|
60
|
+
expect(result.blockers).toHaveLength(0);
|
|
61
|
+
expect(result.warnings).toHaveLength(0);
|
|
62
|
+
expect(result.runtime_identity?.package_name).toBe('gsd-remix');
|
|
63
|
+
expect(result.legacy_bridge_available).toBe(true);
|
|
64
|
+
expect(result.gsd_tools_source).toBe('custom');
|
|
65
|
+
expect(result.checks.map(check => check.code)).toEqual([
|
|
66
|
+
'node_version_supported',
|
|
67
|
+
'legacy_bridge_ready',
|
|
68
|
+
'runtime_identity_verified',
|
|
69
|
+
]);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('warns when no legacy bridge candidate is available', async () => {
|
|
73
|
+
const { projectDir, cleanup } = await createProject();
|
|
74
|
+
cleanups.push(cleanup);
|
|
75
|
+
|
|
76
|
+
const result = await runRuntimeHealth(projectDir, {
|
|
77
|
+
nodeVersion: 'v22.4.1',
|
|
78
|
+
requiredNodeRange: '>=22.0.0',
|
|
79
|
+
gsdToolsCandidates: [{ path: join(projectDir, 'missing-gsd-tools.cjs'), source: 'custom' }],
|
|
80
|
+
runtimeIdentityPath: await createIdentity(projectDir),
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
expect(result.passed).toBe(true);
|
|
84
|
+
expect(result.legacy_bridge_available).toBe(false);
|
|
85
|
+
expect(result.warnings).toHaveLength(1);
|
|
86
|
+
expect(result.warnings[0]?.code).toBe('legacy_bridge_missing');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('warns when the legacy bridge probe fails', async () => {
|
|
90
|
+
const { projectDir, cleanup } = await createProject();
|
|
91
|
+
cleanups.push(cleanup);
|
|
92
|
+
|
|
93
|
+
const bridgePath = await createNodeScript(
|
|
94
|
+
projectDir,
|
|
95
|
+
'gsd-tools-fail.cjs',
|
|
96
|
+
`process.stderr.write('bridge probe failed\\n'); process.exit(1);`,
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const result = await runRuntimeHealth(projectDir, {
|
|
100
|
+
nodeVersion: 'v22.4.1',
|
|
101
|
+
requiredNodeRange: '>=22.0.0',
|
|
102
|
+
gsdToolsCandidates: [{ path: bridgePath, source: 'custom' }],
|
|
103
|
+
runtimeIdentityPath: await createIdentity(projectDir),
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
expect(result.passed).toBe(true);
|
|
107
|
+
expect(result.legacy_bridge_available).toBe(false);
|
|
108
|
+
expect(result.warnings).toHaveLength(1);
|
|
109
|
+
expect(result.warnings[0]?.code).toBe('legacy_bridge_probe_failed');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('blocks when the current node version is below the required runtime', async () => {
|
|
113
|
+
const { projectDir, cleanup } = await createProject();
|
|
114
|
+
cleanups.push(cleanup);
|
|
115
|
+
|
|
116
|
+
const bridgePath = await createNodeScript(
|
|
117
|
+
projectDir,
|
|
118
|
+
'gsd-tools-ok.cjs',
|
|
119
|
+
`process.stdout.write('/tmp/config.json\\n');`,
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
const result = await runRuntimeHealth(projectDir, {
|
|
123
|
+
nodeVersion: 'v20.11.1',
|
|
124
|
+
requiredNodeRange: '>=22.0.0',
|
|
125
|
+
gsdToolsCandidates: [{ path: bridgePath, source: 'custom' }],
|
|
126
|
+
runtimeIdentityPath: await createIdentity(projectDir),
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
expect(result.passed).toBe(false);
|
|
130
|
+
expect(result.blockers).toHaveLength(1);
|
|
131
|
+
expect(result.blockers[0]?.code).toBe('node_version_unsupported');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('warns when the remix identity marker is missing', async () => {
|
|
135
|
+
const { projectDir, cleanup } = await createProject();
|
|
136
|
+
cleanups.push(cleanup);
|
|
137
|
+
|
|
138
|
+
const bridgePath = await createNodeScript(
|
|
139
|
+
projectDir,
|
|
140
|
+
'gsd-tools-ok.cjs',
|
|
141
|
+
`process.stdout.write('/tmp/config.json\\n');`,
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const result = await runRuntimeHealth(projectDir, {
|
|
145
|
+
nodeVersion: 'v22.4.1',
|
|
146
|
+
requiredNodeRange: '>=22.0.0',
|
|
147
|
+
gsdToolsCandidates: [{ path: bridgePath, source: 'custom' }],
|
|
148
|
+
runtimeIdentityPath: join(projectDir, 'missing-IDENTITY.json'),
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
expect(result.passed).toBe(true);
|
|
152
|
+
expect(result.runtime_identity).toBeNull();
|
|
153
|
+
expect(result.warnings.some(warning => warning.code === 'runtime_identity_missing')).toBe(true);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('resolves project-local runtime assets for non-Claude runtimes', async () => {
|
|
157
|
+
const { projectDir, cleanup } = await createProject();
|
|
158
|
+
cleanups.push(cleanup);
|
|
159
|
+
|
|
160
|
+
const runtimeRoot = join(projectDir, '.codex', 'get-shit-done');
|
|
161
|
+
const bridgeDir = join(runtimeRoot, 'bin');
|
|
162
|
+
await mkdir(bridgeDir, { recursive: true });
|
|
163
|
+
await writeFile(join(bridgeDir, 'gsd-tools.cjs'), `process.stdout.write('/tmp/config.json\\n');`, 'utf-8');
|
|
164
|
+
await createIdentity(runtimeRoot, { runtime: 'codex', install_scope: 'local' });
|
|
165
|
+
|
|
166
|
+
const result = await runRuntimeHealth(projectDir, {
|
|
167
|
+
nodeVersion: 'v22.4.1',
|
|
168
|
+
requiredNodeRange: '>=22.0.0',
|
|
169
|
+
runtime: 'codex',
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
expect(result.gsd_tools_source).toBe('project');
|
|
173
|
+
expect(result.runtime_identity?.runtime).toBe('codex');
|
|
174
|
+
expect(result.checks.some(check => check.code === 'runtime_identity_verified')).toBe(true);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { promisify } from 'node:util';
|
|
7
|
+
|
|
8
|
+
import { detectRuntime, getRuntimeConfigDir, type Runtime } from './query/helpers.js';
|
|
9
|
+
|
|
10
|
+
const execFileAsync = promisify(execFile);
|
|
11
|
+
|
|
12
|
+
const SDK_PACKAGE_JSON_PATH = fileURLToPath(new URL('../package.json', import.meta.url));
|
|
13
|
+
const ROOT_PACKAGE_JSON_PATH = fileURLToPath(new URL('../../package.json', import.meta.url));
|
|
14
|
+
const BUNDLED_GSD_TOOLS_PATH = fileURLToPath(
|
|
15
|
+
new URL('../../get-shit-done/bin/gsd-tools.cjs', import.meta.url),
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
export type RuntimeHealthLevel = 'pass' | 'warn' | 'block';
|
|
19
|
+
export type RuntimeHealthSource = 'bundled' | 'project' | 'user' | 'custom' | 'missing';
|
|
20
|
+
|
|
21
|
+
export interface RuntimeHealthCheck {
|
|
22
|
+
code: string;
|
|
23
|
+
level: RuntimeHealthLevel;
|
|
24
|
+
message: string;
|
|
25
|
+
detail?: string;
|
|
26
|
+
fix?: string;
|
|
27
|
+
path?: string;
|
|
28
|
+
source?: RuntimeHealthSource;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface RuntimeHealthCandidate {
|
|
32
|
+
path: string;
|
|
33
|
+
source: Exclude<RuntimeHealthSource, 'missing'>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface RuntimeHealthResult {
|
|
37
|
+
passed: boolean;
|
|
38
|
+
node_version: string;
|
|
39
|
+
required_node_range: string | null;
|
|
40
|
+
runtime_identity: RuntimeIdentity | null;
|
|
41
|
+
runtime_identity_path: string | null;
|
|
42
|
+
gsd_tools_path: string | null;
|
|
43
|
+
gsd_tools_source: RuntimeHealthSource;
|
|
44
|
+
legacy_bridge_available: boolean;
|
|
45
|
+
checks: RuntimeHealthCheck[];
|
|
46
|
+
blockers: RuntimeHealthCheck[];
|
|
47
|
+
warnings: RuntimeHealthCheck[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface RuntimeHealthOptions {
|
|
51
|
+
nodeVersion?: string;
|
|
52
|
+
requiredNodeRange?: string | null;
|
|
53
|
+
gsdToolsCandidates?: RuntimeHealthCandidate[];
|
|
54
|
+
runtimeIdentityPath?: string | null;
|
|
55
|
+
runtime?: Runtime;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface PackageMeta {
|
|
59
|
+
engines?: {
|
|
60
|
+
node?: string;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
interface VersionTuple {
|
|
65
|
+
major: number;
|
|
66
|
+
minor: number;
|
|
67
|
+
patch: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface RuntimeIdentity {
|
|
71
|
+
distribution?: string;
|
|
72
|
+
package_name?: string;
|
|
73
|
+
version?: string;
|
|
74
|
+
display_name?: string;
|
|
75
|
+
sdk_binary?: string;
|
|
76
|
+
sdk_package?: string;
|
|
77
|
+
runtime?: string;
|
|
78
|
+
install_scope?: string;
|
|
79
|
+
installed_at?: string;
|
|
80
|
+
identity_path: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function parseVersionTuple(input: string): VersionTuple | null {
|
|
84
|
+
const match = input.trim().match(/^v?(\d+)(?:\.(\d+))?(?:\.(\d+))?/);
|
|
85
|
+
if (!match) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
major: Number(match[1] ?? 0),
|
|
91
|
+
minor: Number(match[2] ?? 0),
|
|
92
|
+
patch: Number(match[3] ?? 0),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function compareVersionTuple(left: VersionTuple, right: VersionTuple): number {
|
|
97
|
+
if (left.major !== right.major) {
|
|
98
|
+
return left.major - right.major;
|
|
99
|
+
}
|
|
100
|
+
if (left.minor !== right.minor) {
|
|
101
|
+
return left.minor - right.minor;
|
|
102
|
+
}
|
|
103
|
+
return left.patch - right.patch;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function parseMinimumNodeRange(range: string): VersionTuple | null {
|
|
107
|
+
const match = range.trim().match(/^>=\s*(\d+)(?:\.(\d+))?(?:\.(\d+))?/);
|
|
108
|
+
if (!match) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
major: Number(match[1] ?? 0),
|
|
114
|
+
minor: Number(match[2] ?? 0),
|
|
115
|
+
patch: Number(match[3] ?? 0),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function loadRequiredNodeRange(): Promise<string | null> {
|
|
120
|
+
for (const packagePath of [SDK_PACKAGE_JSON_PATH, ROOT_PACKAGE_JSON_PATH]) {
|
|
121
|
+
try {
|
|
122
|
+
const parsed = JSON.parse(await readFile(packagePath, 'utf-8')) as PackageMeta;
|
|
123
|
+
if (parsed.engines?.node) {
|
|
124
|
+
return parsed.engines.node;
|
|
125
|
+
}
|
|
126
|
+
} catch {
|
|
127
|
+
// Ignore missing package metadata and continue probing.
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function loadProjectRuntimeConfig(projectDir: string): Promise<{ runtime?: unknown } | undefined> {
|
|
135
|
+
try {
|
|
136
|
+
const parsed = JSON.parse(await readFile(join(projectDir, '.planning', 'config.json'), 'utf-8')) as {
|
|
137
|
+
runtime?: unknown;
|
|
138
|
+
};
|
|
139
|
+
return parsed;
|
|
140
|
+
} catch {
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function getLocalRuntimeDirName(runtime: Runtime): string {
|
|
146
|
+
switch (runtime) {
|
|
147
|
+
case 'copilot':
|
|
148
|
+
return '.github';
|
|
149
|
+
case 'opencode':
|
|
150
|
+
return '.opencode';
|
|
151
|
+
case 'kilo':
|
|
152
|
+
return '.kilo';
|
|
153
|
+
case 'codex':
|
|
154
|
+
return '.codex';
|
|
155
|
+
case 'antigravity':
|
|
156
|
+
return '.agent';
|
|
157
|
+
case 'cursor':
|
|
158
|
+
return '.cursor';
|
|
159
|
+
case 'windsurf':
|
|
160
|
+
return '.windsurf';
|
|
161
|
+
case 'augment':
|
|
162
|
+
return '.augment';
|
|
163
|
+
case 'trae':
|
|
164
|
+
return '.trae';
|
|
165
|
+
case 'qwen':
|
|
166
|
+
return '.qwen';
|
|
167
|
+
case 'codebuddy':
|
|
168
|
+
return '.codebuddy';
|
|
169
|
+
case 'cline':
|
|
170
|
+
return '.cline';
|
|
171
|
+
case 'gemini':
|
|
172
|
+
return '.gemini';
|
|
173
|
+
case 'claude':
|
|
174
|
+
return '.claude';
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function defaultGsdToolsCandidates(projectDir: string, runtime: Runtime): RuntimeHealthCandidate[] {
|
|
179
|
+
return [
|
|
180
|
+
{ path: join(projectDir, getLocalRuntimeDirName(runtime), 'get-shit-done', 'bin', 'gsd-tools.cjs'), source: 'project' },
|
|
181
|
+
{ path: join(getRuntimeConfigDir(runtime), 'get-shit-done', 'bin', 'gsd-tools.cjs'), source: 'user' },
|
|
182
|
+
{ path: BUNDLED_GSD_TOOLS_PATH, source: 'bundled' },
|
|
183
|
+
];
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function evaluateNodeVersion(nodeVersion: string, requiredNodeRange: string | null): RuntimeHealthCheck {
|
|
187
|
+
if (!requiredNodeRange) {
|
|
188
|
+
return {
|
|
189
|
+
code: 'node_requirement_missing',
|
|
190
|
+
level: 'warn',
|
|
191
|
+
message: `No Node engine requirement declared for the installed GSD runtime.`,
|
|
192
|
+
fix: 'Declare engines.node in package.json so runtime-health can enforce it.',
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const actual = parseVersionTuple(nodeVersion);
|
|
197
|
+
const minimum = parseMinimumNodeRange(requiredNodeRange);
|
|
198
|
+
|
|
199
|
+
if (!actual || !minimum) {
|
|
200
|
+
return {
|
|
201
|
+
code: 'node_requirement_unparsed',
|
|
202
|
+
level: 'warn',
|
|
203
|
+
message: `Unable to validate Node ${nodeVersion} against required range ${requiredNodeRange}.`,
|
|
204
|
+
fix: 'Use a simple >=x.y.z engines.node constraint so runtime-health can enforce it.',
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (compareVersionTuple(actual, minimum) < 0) {
|
|
209
|
+
return {
|
|
210
|
+
code: 'node_version_unsupported',
|
|
211
|
+
level: 'block',
|
|
212
|
+
message: `Current Node ${nodeVersion} does not satisfy the required runtime ${requiredNodeRange}.`,
|
|
213
|
+
fix: `Use Node ${requiredNodeRange} or newer, then rerun the workflow.`,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
code: 'node_version_supported',
|
|
219
|
+
level: 'pass',
|
|
220
|
+
message: `Current Node ${nodeVersion} satisfies the required runtime ${requiredNodeRange}.`,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
async function probeLegacyBridge(
|
|
225
|
+
projectDir: string,
|
|
226
|
+
candidates: RuntimeHealthCandidate[],
|
|
227
|
+
): Promise<{ check: RuntimeHealthCheck; path: string | null; source: RuntimeHealthSource; available: boolean }> {
|
|
228
|
+
const candidate = candidates.find(item => existsSync(item.path));
|
|
229
|
+
|
|
230
|
+
if (!candidate) {
|
|
231
|
+
return {
|
|
232
|
+
check: {
|
|
233
|
+
code: 'legacy_bridge_missing',
|
|
234
|
+
level: 'warn',
|
|
235
|
+
message: 'No gsd-tools.cjs bridge could be found for CJS fallback commands.',
|
|
236
|
+
fix: 'Run /gsd-update to restore the bundled bridge. Use /gsd-health --runtime --repair only for SDK CLI repair.',
|
|
237
|
+
},
|
|
238
|
+
path: null,
|
|
239
|
+
source: 'missing',
|
|
240
|
+
available: false,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
try {
|
|
245
|
+
const { stdout } = await execFileAsync(process.execPath, [candidate.path, 'config-path', '--raw'], {
|
|
246
|
+
cwd: projectDir,
|
|
247
|
+
timeout: 4_000,
|
|
248
|
+
env: process.env,
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
const output = String(stdout).trim();
|
|
252
|
+
if (!output) {
|
|
253
|
+
return {
|
|
254
|
+
check: {
|
|
255
|
+
code: 'legacy_bridge_probe_empty',
|
|
256
|
+
level: 'warn',
|
|
257
|
+
message: `Legacy bridge probe returned no output from ${candidate.source} gsd-tools.cjs.`,
|
|
258
|
+
fix: 'Run /gsd-update to refresh the bridge assets before relying on fallback commands.',
|
|
259
|
+
path: candidate.path,
|
|
260
|
+
source: candidate.source,
|
|
261
|
+
},
|
|
262
|
+
path: candidate.path,
|
|
263
|
+
source: candidate.source,
|
|
264
|
+
available: false,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return {
|
|
269
|
+
check: {
|
|
270
|
+
code: 'legacy_bridge_ready',
|
|
271
|
+
level: 'pass',
|
|
272
|
+
message: `Legacy bridge is available from the ${candidate.source} runtime assets.`,
|
|
273
|
+
path: candidate.path,
|
|
274
|
+
source: candidate.source,
|
|
275
|
+
},
|
|
276
|
+
path: candidate.path,
|
|
277
|
+
source: candidate.source,
|
|
278
|
+
available: true,
|
|
279
|
+
};
|
|
280
|
+
} catch (error) {
|
|
281
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
282
|
+
return {
|
|
283
|
+
check: {
|
|
284
|
+
code: 'legacy_bridge_probe_failed',
|
|
285
|
+
level: 'warn',
|
|
286
|
+
message: `Legacy bridge probe failed for the ${candidate.source} gsd-tools.cjs.`,
|
|
287
|
+
detail,
|
|
288
|
+
fix: 'Run /gsd-update to refresh bundled assets, then retry the workflow.',
|
|
289
|
+
path: candidate.path,
|
|
290
|
+
source: candidate.source,
|
|
291
|
+
},
|
|
292
|
+
path: candidate.path,
|
|
293
|
+
source: candidate.source,
|
|
294
|
+
available: false,
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function identityPathForBridgePath(gsdToolsPath: string | null): string | null {
|
|
300
|
+
if (!gsdToolsPath) {
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return join(dirname(dirname(gsdToolsPath)), 'IDENTITY.json');
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
async function loadRuntimeIdentity(identityPath: string | null): Promise<RuntimeIdentity | null> {
|
|
308
|
+
if (!identityPath) {
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
try {
|
|
313
|
+
const parsed = JSON.parse(await readFile(identityPath, 'utf-8')) as Omit<RuntimeIdentity, 'identity_path'>;
|
|
314
|
+
return {
|
|
315
|
+
...parsed,
|
|
316
|
+
identity_path: identityPath,
|
|
317
|
+
};
|
|
318
|
+
} catch {
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function evaluateRuntimeIdentity(identity: RuntimeIdentity | null, identityPath: string | null): RuntimeHealthCheck {
|
|
324
|
+
if (!identity) {
|
|
325
|
+
return {
|
|
326
|
+
code: 'runtime_identity_missing',
|
|
327
|
+
level: 'warn',
|
|
328
|
+
message: 'No GSD Remix identity marker was found next to the resolved runtime assets.',
|
|
329
|
+
detail: identityPath ? `Expected identity marker at ${identityPath}.` : undefined,
|
|
330
|
+
fix: 'Run npx gsd-remix@latest for this runtime, then rerun /gsd-health --runtime.',
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (identity.distribution !== 'gsd-remix' || identity.package_name !== 'gsd-remix') {
|
|
335
|
+
return {
|
|
336
|
+
code: 'runtime_identity_unexpected',
|
|
337
|
+
level: 'warn',
|
|
338
|
+
message: `Resolved runtime identity is ${identity.display_name ?? identity.distribution ?? 'unknown'}, not GSD Remix.`,
|
|
339
|
+
detail: `Identity file: ${identity.identity_path}`,
|
|
340
|
+
fix: 'Reinstall with npx gsd-remix@latest for the selected runtime, then rerun /gsd-health --runtime.',
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return {
|
|
345
|
+
code: 'runtime_identity_verified',
|
|
346
|
+
level: 'pass',
|
|
347
|
+
message: `Resolved runtime identity is GSD Remix ${identity.version ?? 'unknown version'}.`,
|
|
348
|
+
path: identity.identity_path,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export async function runRuntimeHealth(
|
|
353
|
+
projectDir: string,
|
|
354
|
+
options: RuntimeHealthOptions = {},
|
|
355
|
+
): Promise<RuntimeHealthResult> {
|
|
356
|
+
const nodeVersion = options.nodeVersion ?? process.version;
|
|
357
|
+
const requiredNodeRange = options.requiredNodeRange !== undefined
|
|
358
|
+
? options.requiredNodeRange
|
|
359
|
+
: await loadRequiredNodeRange();
|
|
360
|
+
const runtime = options.runtime ?? detectRuntime(await loadProjectRuntimeConfig(projectDir));
|
|
361
|
+
const gsdToolsCandidates = options.gsdToolsCandidates ?? defaultGsdToolsCandidates(projectDir, runtime);
|
|
362
|
+
|
|
363
|
+
const nodeCheck = evaluateNodeVersion(nodeVersion, requiredNodeRange);
|
|
364
|
+
const legacyBridge = await probeLegacyBridge(projectDir, gsdToolsCandidates);
|
|
365
|
+
const identityPath = options.runtimeIdentityPath !== undefined
|
|
366
|
+
? options.runtimeIdentityPath
|
|
367
|
+
: identityPathForBridgePath(legacyBridge.path);
|
|
368
|
+
const runtimeIdentity = await loadRuntimeIdentity(identityPath);
|
|
369
|
+
const identityCheck = evaluateRuntimeIdentity(runtimeIdentity, identityPath);
|
|
370
|
+
const checks = [nodeCheck, legacyBridge.check, identityCheck];
|
|
371
|
+
const blockers = checks.filter(check => check.level === 'block');
|
|
372
|
+
const warnings = checks.filter(check => check.level === 'warn');
|
|
373
|
+
|
|
374
|
+
return {
|
|
375
|
+
passed: blockers.length === 0,
|
|
376
|
+
node_version: nodeVersion,
|
|
377
|
+
required_node_range: requiredNodeRange,
|
|
378
|
+
runtime_identity: runtimeIdentity,
|
|
379
|
+
runtime_identity_path: identityPath,
|
|
380
|
+
gsd_tools_path: legacyBridge.path,
|
|
381
|
+
gsd_tools_source: legacyBridge.source,
|
|
382
|
+
legacy_bridge_available: legacyBridge.available,
|
|
383
|
+
checks,
|
|
384
|
+
blockers,
|
|
385
|
+
warnings,
|
|
386
|
+
};
|
|
387
|
+
}
|