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,482 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared query helpers — cross-cutting utility functions used across query modules.
|
|
3
|
+
*
|
|
4
|
+
* Ported from get-shit-done/bin/lib/core.cjs and state.cjs.
|
|
5
|
+
* Provides phase name normalization, path handling, regex escaping,
|
|
6
|
+
* and STATE.md field extraction.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { normalizePhaseName, planningPaths } from './helpers.js';
|
|
11
|
+
*
|
|
12
|
+
* normalizePhaseName('9'); // '09'
|
|
13
|
+
* normalizePhaseName('CK-01'); // '01'
|
|
14
|
+
*
|
|
15
|
+
* const paths = planningPaths('/project');
|
|
16
|
+
* // { planning: '/project/.planning', state: '/project/.planning/STATE.md', ... }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { join, dirname, relative, resolve, isAbsolute, normalize } from 'node:path';
|
|
21
|
+
import { realpath } from 'node:fs/promises';
|
|
22
|
+
import { homedir } from 'node:os';
|
|
23
|
+
import { GSDError, ErrorClassification } from '../errors.js';
|
|
24
|
+
|
|
25
|
+
// ─── Runtime-aware agents directory resolution ─────────────────────────────
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Supported GSD runtimes. Kept in sync with `bin/install.js:getGlobalDir()`.
|
|
29
|
+
*/
|
|
30
|
+
export const SUPPORTED_RUNTIMES = [
|
|
31
|
+
'claude', 'opencode', 'kilo', 'gemini', 'codex', 'copilot', 'antigravity',
|
|
32
|
+
'cursor', 'windsurf', 'augment', 'trae', 'qwen', 'codebuddy', 'cline',
|
|
33
|
+
] as const;
|
|
34
|
+
|
|
35
|
+
export type Runtime = (typeof SUPPORTED_RUNTIMES)[number];
|
|
36
|
+
|
|
37
|
+
function expandTilde(p: string): string {
|
|
38
|
+
return p.startsWith('~/') || p === '~' ? join(homedir(), p.slice(1)) : p;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Resolve the per-runtime config directory, mirroring
|
|
43
|
+
* `bin/install.js:getGlobalDir()`. Agents live at `<configDir>/agents`.
|
|
44
|
+
*/
|
|
45
|
+
export function getRuntimeConfigDir(runtime: Runtime): string {
|
|
46
|
+
switch (runtime) {
|
|
47
|
+
case 'claude':
|
|
48
|
+
return process.env.CLAUDE_CONFIG_DIR
|
|
49
|
+
? expandTilde(process.env.CLAUDE_CONFIG_DIR)
|
|
50
|
+
: join(homedir(), '.claude');
|
|
51
|
+
case 'opencode':
|
|
52
|
+
if (process.env.OPENCODE_CONFIG_DIR) return expandTilde(process.env.OPENCODE_CONFIG_DIR);
|
|
53
|
+
if (process.env.OPENCODE_CONFIG) return dirname(expandTilde(process.env.OPENCODE_CONFIG));
|
|
54
|
+
if (process.env.XDG_CONFIG_HOME) return join(expandTilde(process.env.XDG_CONFIG_HOME), 'opencode');
|
|
55
|
+
return join(homedir(), '.config', 'opencode');
|
|
56
|
+
case 'kilo':
|
|
57
|
+
if (process.env.KILO_CONFIG_DIR) return expandTilde(process.env.KILO_CONFIG_DIR);
|
|
58
|
+
if (process.env.KILO_CONFIG) return dirname(expandTilde(process.env.KILO_CONFIG));
|
|
59
|
+
if (process.env.XDG_CONFIG_HOME) return join(expandTilde(process.env.XDG_CONFIG_HOME), 'kilo');
|
|
60
|
+
return join(homedir(), '.config', 'kilo');
|
|
61
|
+
case 'gemini':
|
|
62
|
+
return process.env.GEMINI_CONFIG_DIR ? expandTilde(process.env.GEMINI_CONFIG_DIR) : join(homedir(), '.gemini');
|
|
63
|
+
case 'codex':
|
|
64
|
+
return process.env.CODEX_HOME ? expandTilde(process.env.CODEX_HOME) : join(homedir(), '.codex');
|
|
65
|
+
case 'copilot':
|
|
66
|
+
return process.env.COPILOT_CONFIG_DIR ? expandTilde(process.env.COPILOT_CONFIG_DIR) : join(homedir(), '.copilot');
|
|
67
|
+
case 'antigravity':
|
|
68
|
+
return process.env.ANTIGRAVITY_CONFIG_DIR ? expandTilde(process.env.ANTIGRAVITY_CONFIG_DIR) : join(homedir(), '.gemini', 'antigravity');
|
|
69
|
+
case 'cursor':
|
|
70
|
+
return process.env.CURSOR_CONFIG_DIR ? expandTilde(process.env.CURSOR_CONFIG_DIR) : join(homedir(), '.cursor');
|
|
71
|
+
case 'windsurf':
|
|
72
|
+
return process.env.WINDSURF_CONFIG_DIR ? expandTilde(process.env.WINDSURF_CONFIG_DIR) : join(homedir(), '.codeium', 'windsurf');
|
|
73
|
+
case 'augment':
|
|
74
|
+
return process.env.AUGMENT_CONFIG_DIR ? expandTilde(process.env.AUGMENT_CONFIG_DIR) : join(homedir(), '.augment');
|
|
75
|
+
case 'trae':
|
|
76
|
+
return process.env.TRAE_CONFIG_DIR ? expandTilde(process.env.TRAE_CONFIG_DIR) : join(homedir(), '.trae');
|
|
77
|
+
case 'qwen':
|
|
78
|
+
return process.env.QWEN_CONFIG_DIR ? expandTilde(process.env.QWEN_CONFIG_DIR) : join(homedir(), '.qwen');
|
|
79
|
+
case 'codebuddy':
|
|
80
|
+
return process.env.CODEBUDDY_CONFIG_DIR ? expandTilde(process.env.CODEBUDDY_CONFIG_DIR) : join(homedir(), '.codebuddy');
|
|
81
|
+
case 'cline':
|
|
82
|
+
return process.env.CLINE_CONFIG_DIR ? expandTilde(process.env.CLINE_CONFIG_DIR) : join(homedir(), '.cline');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Detect the invoking runtime using issue #2402 precedence:
|
|
88
|
+
* 1. `GSD_RUNTIME` env var
|
|
89
|
+
* 2. `config.runtime` field (from `.planning/config.json` when loaded)
|
|
90
|
+
* 3. Fallback to `'claude'`
|
|
91
|
+
*
|
|
92
|
+
* Unknown values fall through to the next tier rather than throwing, so
|
|
93
|
+
* stale env values don't hard-block workflows.
|
|
94
|
+
*/
|
|
95
|
+
export function detectRuntime(config?: { runtime?: unknown }): Runtime {
|
|
96
|
+
const envValue = process.env.GSD_RUNTIME;
|
|
97
|
+
if (envValue && (SUPPORTED_RUNTIMES as readonly string[]).includes(envValue)) {
|
|
98
|
+
return envValue as Runtime;
|
|
99
|
+
}
|
|
100
|
+
const configValue = config?.runtime;
|
|
101
|
+
if (typeof configValue === 'string' && (SUPPORTED_RUNTIMES as readonly string[]).includes(configValue)) {
|
|
102
|
+
return configValue as Runtime;
|
|
103
|
+
}
|
|
104
|
+
return 'claude';
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Resolve the GSD agents directory for a given runtime.
|
|
109
|
+
*
|
|
110
|
+
* Precedence:
|
|
111
|
+
* 1. `GSD_AGENTS_DIR` — explicit SDK override (wins over runtime selection)
|
|
112
|
+
* 2. `<getRuntimeConfigDir(runtime)>/agents` — installer-parity default
|
|
113
|
+
*
|
|
114
|
+
* Defaults to Claude when no runtime is passed, matching prior behavior
|
|
115
|
+
* (see `init-runner.ts`, which is Claude-only by design).
|
|
116
|
+
*/
|
|
117
|
+
export function resolveAgentsDir(runtime: Runtime = 'claude'): string {
|
|
118
|
+
if (process.env.GSD_AGENTS_DIR) return process.env.GSD_AGENTS_DIR;
|
|
119
|
+
return join(getRuntimeConfigDir(runtime), 'agents');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ─── Types ──────────────────────────────────────────────────────────────────
|
|
123
|
+
|
|
124
|
+
/** Paths to common .planning files. */
|
|
125
|
+
export interface PlanningPaths {
|
|
126
|
+
planning: string;
|
|
127
|
+
state: string;
|
|
128
|
+
roadmap: string;
|
|
129
|
+
project: string;
|
|
130
|
+
config: string;
|
|
131
|
+
phases: string;
|
|
132
|
+
requirements: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ─── escapeRegex ────────────────────────────────────────────────────────────
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Escape regex special characters in a string.
|
|
139
|
+
*
|
|
140
|
+
* @param value - String to escape
|
|
141
|
+
* @returns String with regex special characters escaped
|
|
142
|
+
*/
|
|
143
|
+
export function escapeRegex(value: string): string {
|
|
144
|
+
return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ─── normalizePhaseName ─────────────────────────────────────────────────────
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Normalize a phase identifier to a canonical form.
|
|
151
|
+
*
|
|
152
|
+
* Strips optional project code prefix (e.g., 'CK-01' -> '01'),
|
|
153
|
+
* pads numeric part to 2 digits, preserves letter suffix and decimal parts.
|
|
154
|
+
*
|
|
155
|
+
* @param phase - Phase identifier string
|
|
156
|
+
* @returns Normalized phase name
|
|
157
|
+
*/
|
|
158
|
+
export function normalizePhaseName(phase: string): string {
|
|
159
|
+
const str = String(phase);
|
|
160
|
+
// Strip optional project_code prefix (e.g., 'CK-01' -> '01')
|
|
161
|
+
const stripped = str.replace(/^[A-Z]{1,6}-(?=\d)/, '');
|
|
162
|
+
// Standard numeric phases: 1, 01, 12A, 12.1
|
|
163
|
+
const match = stripped.match(/^(\d+)([A-Z])?((?:\.\d+)*)/i);
|
|
164
|
+
if (match) {
|
|
165
|
+
const padded = match[1].padStart(2, '0');
|
|
166
|
+
const letter = match[2] ? match[2].toUpperCase() : '';
|
|
167
|
+
const decimal = match[3] || '';
|
|
168
|
+
return padded + letter + decimal;
|
|
169
|
+
}
|
|
170
|
+
// Custom phase IDs (e.g. PROJ-42, AUTH-101): return as-is
|
|
171
|
+
return str;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ─── comparePhaseNum ────────────────────────────────────────────────────────
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Compare two phase directory names for sorting.
|
|
178
|
+
*
|
|
179
|
+
* Handles numeric, letter-suffixed, and decimal phases.
|
|
180
|
+
* Falls back to string comparison for custom IDs.
|
|
181
|
+
*
|
|
182
|
+
* @param a - First phase directory name
|
|
183
|
+
* @param b - Second phase directory name
|
|
184
|
+
* @returns Negative if a < b, positive if a > b, 0 if equal
|
|
185
|
+
*/
|
|
186
|
+
export function comparePhaseNum(a: string, b: string): number {
|
|
187
|
+
// Strip optional project_code prefix before comparing
|
|
188
|
+
const sa = String(a).replace(/^[A-Z]{1,6}-/, '');
|
|
189
|
+
const sb = String(b).replace(/^[A-Z]{1,6}-/, '');
|
|
190
|
+
const pa = sa.match(/^(\d+)([A-Z])?((?:\.\d+)*)/i);
|
|
191
|
+
const pb = sb.match(/^(\d+)([A-Z])?((?:\.\d+)*)/i);
|
|
192
|
+
// If either is non-numeric (custom ID), fall back to string comparison
|
|
193
|
+
if (!pa || !pb) return String(a).localeCompare(String(b));
|
|
194
|
+
const intDiff = parseInt(pa[1], 10) - parseInt(pb[1], 10);
|
|
195
|
+
if (intDiff !== 0) return intDiff;
|
|
196
|
+
// No letter sorts before letter: 12 < 12A < 12B
|
|
197
|
+
const la = (pa[2] || '').toUpperCase();
|
|
198
|
+
const lb = (pb[2] || '').toUpperCase();
|
|
199
|
+
if (la !== lb) {
|
|
200
|
+
if (!la) return -1;
|
|
201
|
+
if (!lb) return 1;
|
|
202
|
+
return la < lb ? -1 : 1;
|
|
203
|
+
}
|
|
204
|
+
// Segment-by-segment decimal comparison: 12A < 12A.1 < 12A.1.2 < 12A.2
|
|
205
|
+
const aDecParts = pa[3] ? pa[3].slice(1).split('.').map(p => parseInt(p, 10)) : [];
|
|
206
|
+
const bDecParts = pb[3] ? pb[3].slice(1).split('.').map(p => parseInt(p, 10)) : [];
|
|
207
|
+
const maxLen = Math.max(aDecParts.length, bDecParts.length);
|
|
208
|
+
if (aDecParts.length === 0 && bDecParts.length > 0) return -1;
|
|
209
|
+
if (bDecParts.length === 0 && aDecParts.length > 0) return 1;
|
|
210
|
+
for (let i = 0; i < maxLen; i++) {
|
|
211
|
+
const av = Number.isFinite(aDecParts[i]) ? aDecParts[i] : 0;
|
|
212
|
+
const bv = Number.isFinite(bDecParts[i]) ? bDecParts[i] : 0;
|
|
213
|
+
if (av !== bv) return av - bv;
|
|
214
|
+
}
|
|
215
|
+
return 0;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// ─── extractPhaseToken ──────────────────────────────────────────────────────
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Extract the phase token from a directory name.
|
|
222
|
+
*
|
|
223
|
+
* Supports: '01-name', '1009A-name', '999.6-name', 'CK-01-name', 'PROJ-42-name'.
|
|
224
|
+
*
|
|
225
|
+
* @param dirName - Directory name to extract token from
|
|
226
|
+
* @returns The token portion (e.g. '01', '1009A', '999.6', 'PROJ-42')
|
|
227
|
+
*/
|
|
228
|
+
export function extractPhaseToken(dirName: string): string {
|
|
229
|
+
// Try project-code-prefixed numeric: CK-01-name -> CK-01
|
|
230
|
+
const codePrefixed = dirName.match(/^([A-Z]{1,6}-\d+[A-Z]?(?:\.\d+)*)(?:-|$)/i);
|
|
231
|
+
if (codePrefixed) return codePrefixed[1];
|
|
232
|
+
// Try plain numeric: 01-name, 1009A-name, 999.6-name
|
|
233
|
+
const numeric = dirName.match(/^(\d+[A-Z]?(?:\.\d+)*)(?:-|$)/i);
|
|
234
|
+
if (numeric) return numeric[1];
|
|
235
|
+
// Custom IDs: PROJ-42-name -> everything before the last segment that looks like a name
|
|
236
|
+
const custom = dirName.match(/^([A-Z][A-Z0-9]*(?:-[A-Z0-9]+)*)(?:-[a-z]|$)/i);
|
|
237
|
+
if (custom) return custom[1];
|
|
238
|
+
return dirName;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// ─── phaseTokenMatches ──────────────────────────────────────────────────────
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Check if a directory name's phase token matches the normalized phase exactly.
|
|
245
|
+
*
|
|
246
|
+
* Case-insensitive comparison for the token portion.
|
|
247
|
+
*
|
|
248
|
+
* @param dirName - Directory name to check
|
|
249
|
+
* @param normalized - Normalized phase name to match against
|
|
250
|
+
* @returns True if the directory matches the phase
|
|
251
|
+
*/
|
|
252
|
+
export function phaseTokenMatches(dirName: string, normalized: string): boolean {
|
|
253
|
+
const token = extractPhaseToken(dirName);
|
|
254
|
+
if (token.toUpperCase() === normalized.toUpperCase()) return true;
|
|
255
|
+
// Strip optional project_code prefix from dir and retry
|
|
256
|
+
const stripped = dirName.replace(/^[A-Z]{1,6}-(?=\d)/i, '');
|
|
257
|
+
if (stripped !== dirName) {
|
|
258
|
+
const strippedToken = extractPhaseToken(stripped);
|
|
259
|
+
if (strippedToken.toUpperCase() === normalized.toUpperCase()) return true;
|
|
260
|
+
}
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// ─── toPosixPath ────────────────────────────────────────────────────────────
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Convert a path to POSIX format (forward slashes).
|
|
268
|
+
*
|
|
269
|
+
* @param p - Path to convert
|
|
270
|
+
* @returns Path with all separators as forward slashes
|
|
271
|
+
*/
|
|
272
|
+
export function toPosixPath(p: string): string {
|
|
273
|
+
return p.split('\\').join('/');
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// ─── stateExtractField ──────────────────────────────────────────────────────
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Extract a field value from STATE.md content.
|
|
280
|
+
*
|
|
281
|
+
* Supports both **bold:** and plain: formats, case-insensitive.
|
|
282
|
+
*
|
|
283
|
+
* @param content - STATE.md content string
|
|
284
|
+
* @param fieldName - Field name to extract
|
|
285
|
+
* @returns The field value, or null if not found
|
|
286
|
+
*/
|
|
287
|
+
export function stateExtractField(content: string, fieldName: string): string | null {
|
|
288
|
+
const escaped = escapeRegex(fieldName);
|
|
289
|
+
// Horizontal whitespace only after ':' so YAML blocks like `progress:\n total:` do not
|
|
290
|
+
// match as `Progress:` with a multi-line "value" (parity with STATE.md body fields).
|
|
291
|
+
const boldPattern = new RegExp(`\\*\\*${escaped}:\\*\\*[ \\t]*(.+)`, 'i');
|
|
292
|
+
const boldMatch = content.match(boldPattern);
|
|
293
|
+
if (boldMatch) return boldMatch[1].trim();
|
|
294
|
+
const plainPattern = new RegExp(`^${escaped}:[ \\t]*(.+)`, 'im');
|
|
295
|
+
const plainMatch = content.match(plainPattern);
|
|
296
|
+
return plainMatch ? plainMatch[1].trim() : null;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// ─── normalizeMd ───────────────────────────────────────────────────────────
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Normalize markdown content for consistent formatting.
|
|
303
|
+
*
|
|
304
|
+
* Port of `normalizeMd` from core.cjs lines 434-529.
|
|
305
|
+
* Applies: CRLF normalization, blank lines around headings/fences/lists,
|
|
306
|
+
* blank line collapsing (3+ to 2), terminal newline.
|
|
307
|
+
*
|
|
308
|
+
* @param content - Markdown content to normalize
|
|
309
|
+
* @returns Normalized markdown string
|
|
310
|
+
*/
|
|
311
|
+
export function normalizeMd(content: string): string {
|
|
312
|
+
if (!content || typeof content !== 'string') return content;
|
|
313
|
+
|
|
314
|
+
// Normalize line endings to LF
|
|
315
|
+
let text = content.replace(/\r\n/g, '\n');
|
|
316
|
+
|
|
317
|
+
const lines = text.split('\n');
|
|
318
|
+
const result: string[] = [];
|
|
319
|
+
|
|
320
|
+
// Pre-compute fence state in a single O(n) pass
|
|
321
|
+
const fenceRegex = /^```/;
|
|
322
|
+
const insideFence = new Array<boolean>(lines.length);
|
|
323
|
+
let fenceOpen = false;
|
|
324
|
+
for (let i = 0; i < lines.length; i++) {
|
|
325
|
+
if (fenceRegex.test(lines[i].trimEnd())) {
|
|
326
|
+
if (fenceOpen) {
|
|
327
|
+
insideFence[i] = false;
|
|
328
|
+
fenceOpen = false;
|
|
329
|
+
} else {
|
|
330
|
+
insideFence[i] = false;
|
|
331
|
+
fenceOpen = true;
|
|
332
|
+
}
|
|
333
|
+
} else {
|
|
334
|
+
insideFence[i] = fenceOpen;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
for (let i = 0; i < lines.length; i++) {
|
|
339
|
+
const line = lines[i];
|
|
340
|
+
const prev = i > 0 ? lines[i - 1] : '';
|
|
341
|
+
const prevTrimmed = prev.trimEnd();
|
|
342
|
+
const trimmed = line.trimEnd();
|
|
343
|
+
const isFenceLine = fenceRegex.test(trimmed);
|
|
344
|
+
|
|
345
|
+
// MD022: Blank line before headings (skip first line and frontmatter delimiters)
|
|
346
|
+
if (/^#{1,6}\s/.test(trimmed) && i > 0 && prevTrimmed !== '' && prevTrimmed !== '---') {
|
|
347
|
+
result.push('');
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// MD031: Blank line before fenced code blocks (opening fences only)
|
|
351
|
+
if (isFenceLine && i > 0 && prevTrimmed !== '' && !insideFence[i] && (i === 0 || !insideFence[i - 1] || isFenceLine)) {
|
|
352
|
+
if (i === 0 || !insideFence[i - 1]) {
|
|
353
|
+
result.push('');
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// MD032: Blank line before lists
|
|
358
|
+
if (/^(\s*[-*+]\s|\s*\d+\.\s)/.test(line) && i > 0 &&
|
|
359
|
+
prevTrimmed !== '' && !/^(\s*[-*+]\s|\s*\d+\.\s)/.test(prev) &&
|
|
360
|
+
prevTrimmed !== '---') {
|
|
361
|
+
result.push('');
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
result.push(line);
|
|
365
|
+
|
|
366
|
+
// MD022: Blank line after headings
|
|
367
|
+
if (/^#{1,6}\s/.test(trimmed) && i < lines.length - 1) {
|
|
368
|
+
const next = lines[i + 1];
|
|
369
|
+
if (next !== undefined && next.trimEnd() !== '') {
|
|
370
|
+
result.push('');
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// MD031: Blank line after closing fenced code blocks
|
|
375
|
+
if (/^```\s*$/.test(trimmed) && i > 0 && insideFence[i - 1] && i < lines.length - 1) {
|
|
376
|
+
const next = lines[i + 1];
|
|
377
|
+
if (next !== undefined && next.trimEnd() !== '') {
|
|
378
|
+
result.push('');
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// MD032: Blank line after last list item in a block
|
|
383
|
+
if (/^(\s*[-*+]\s|\s*\d+\.\s)/.test(line) && i < lines.length - 1) {
|
|
384
|
+
const next = lines[i + 1];
|
|
385
|
+
if (next !== undefined && next.trimEnd() !== '' &&
|
|
386
|
+
!/^(\s*[-*+]\s|\s*\d+\.\s)/.test(next) &&
|
|
387
|
+
!/^\s/.test(next)) {
|
|
388
|
+
result.push('');
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
text = result.join('\n');
|
|
394
|
+
|
|
395
|
+
// MD012: Collapse 3+ consecutive blank lines to 2
|
|
396
|
+
text = text.replace(/\n{3,}/g, '\n\n');
|
|
397
|
+
|
|
398
|
+
// MD047: Ensure file ends with exactly one newline
|
|
399
|
+
text = text.replace(/\n*$/, '\n');
|
|
400
|
+
|
|
401
|
+
return text;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// ─── planningPaths ──────────────────────────────────────────────────────────
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Get common .planning file paths for a project directory.
|
|
408
|
+
*
|
|
409
|
+
* Simplified version (no workstream/project env vars).
|
|
410
|
+
* All paths returned in POSIX format.
|
|
411
|
+
*
|
|
412
|
+
* @param projectDir - Root project directory
|
|
413
|
+
* @returns Object with paths to common .planning files
|
|
414
|
+
*/
|
|
415
|
+
export function planningPaths(projectDir: string): PlanningPaths {
|
|
416
|
+
const base = join(projectDir, '.planning');
|
|
417
|
+
return {
|
|
418
|
+
planning: toPosixPath(base),
|
|
419
|
+
state: toPosixPath(join(base, 'STATE.md')),
|
|
420
|
+
roadmap: toPosixPath(join(base, 'ROADMAP.md')),
|
|
421
|
+
project: toPosixPath(join(base, 'PROJECT.md')),
|
|
422
|
+
config: toPosixPath(join(base, 'config.json')),
|
|
423
|
+
phases: toPosixPath(join(base, 'phases')),
|
|
424
|
+
requirements: toPosixPath(join(base, 'REQUIREMENTS.md')),
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// ─── resolvePathUnderProject ───────────────────────────────────────────────
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Resolve a user-supplied path against the project and ensure it cannot escape
|
|
432
|
+
* the real project root (prefix checks are insufficient; symlinks are handled
|
|
433
|
+
* via realpath).
|
|
434
|
+
*
|
|
435
|
+
* @param projectDir - Project root directory
|
|
436
|
+
* @param userPath - Relative or absolute path from user input
|
|
437
|
+
* @returns Canonical resolved path within the project
|
|
438
|
+
*/
|
|
439
|
+
export async function resolvePathUnderProject(projectDir: string, userPath: string): Promise<string> {
|
|
440
|
+
const projectReal = await realpath(projectDir);
|
|
441
|
+
const candidate = isAbsolute(userPath) ? normalize(userPath) : resolve(projectReal, userPath);
|
|
442
|
+
let realCandidate: string;
|
|
443
|
+
try {
|
|
444
|
+
realCandidate = await realpath(candidate);
|
|
445
|
+
} catch {
|
|
446
|
+
realCandidate = candidate;
|
|
447
|
+
}
|
|
448
|
+
const rel = relative(projectReal, realCandidate);
|
|
449
|
+
if (rel.startsWith('..') || (isAbsolute(rel) && rel.length > 0)) {
|
|
450
|
+
throw new GSDError('path escapes project directory', ErrorClassification.Validation);
|
|
451
|
+
}
|
|
452
|
+
return realCandidate;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// ─── sanitizeForDisplay (security.cjs) ───────────────────────────────────────
|
|
456
|
+
|
|
457
|
+
/** Port of `sanitizeForPrompt` from `security.cjs`. */
|
|
458
|
+
export function sanitizeForPrompt(text: string): string {
|
|
459
|
+
let sanitized = text;
|
|
460
|
+
sanitized = sanitized.replace(/[\u200B-\u200F\u2028-\u202F\uFEFF\u00AD]/g, '');
|
|
461
|
+
sanitized = sanitized.replace(
|
|
462
|
+
/<(\/?)(?:system|assistant|human)>/gi,
|
|
463
|
+
(_, slash: string) => `<${slash || ''}system-text>`,
|
|
464
|
+
);
|
|
465
|
+
sanitized = sanitized.replace(/\[(SYSTEM|INST)\]/gi, '[$1-TEXT]');
|
|
466
|
+
sanitized = sanitized.replace(/<<\s*SYS\s*>>/gi, '«SYS-TEXT»');
|
|
467
|
+
return sanitized;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/** Port of `sanitizeForDisplay` from `security.cjs` (matches CLI JSON). */
|
|
471
|
+
export function sanitizeForDisplay(text: string): string {
|
|
472
|
+
let sanitized = sanitizeForPrompt(text);
|
|
473
|
+
const protocolLeakPatterns = [
|
|
474
|
+
/^\s*(?:assistant|user|system)\s+to=[^:\s]+:[^\n]+$/i,
|
|
475
|
+
/^\s*<\|(?:assistant|user|system)[^|]*\|>\s*$/i,
|
|
476
|
+
];
|
|
477
|
+
sanitized = sanitized
|
|
478
|
+
.split('\n')
|
|
479
|
+
.filter(line => !protocolLeakPatterns.some(pattern => pattern.test(line)))
|
|
480
|
+
.join('\n');
|
|
481
|
+
return sanitized;
|
|
482
|
+
}
|