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,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* E2E lifecycle integration test — proves GSD.runPhase() drives
|
|
3
|
+
* the full phase lifecycle: discuss → research → plan → execute → verify → advance
|
|
4
|
+
* after bootstrapping a real project via InitRunner.
|
|
5
|
+
*
|
|
6
|
+
* This is the capstone proof that `gsd-remix-sdk auto` works end-to-end
|
|
7
|
+
* without human intervention. InitRunner bootstraps the project,
|
|
8
|
+
* then GSD.runPhase() drives Phase 1 through the complete lifecycle.
|
|
9
|
+
*
|
|
10
|
+
* Requires Claude Code CLI (`claude`) installed and authenticated.
|
|
11
|
+
* Skips gracefully if CLI is unavailable.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
15
|
+
import { execSync } from 'node:child_process';
|
|
16
|
+
import { mkdtemp, rm, readFile, stat, readdir } from 'node:fs/promises';
|
|
17
|
+
import { existsSync } from 'node:fs';
|
|
18
|
+
import { join } from 'node:path';
|
|
19
|
+
import { tmpdir } from 'node:os';
|
|
20
|
+
import { fileURLToPath } from 'node:url';
|
|
21
|
+
|
|
22
|
+
import { GSD } from './index.js';
|
|
23
|
+
import { InitRunner } from './init-runner.js';
|
|
24
|
+
import { GSDTools, resolveGsdToolsPath } from './gsd-tools.js';
|
|
25
|
+
import { GSDEventStream } from './event-stream.js';
|
|
26
|
+
import { GSDEventType, PhaseStepType } from './types.js';
|
|
27
|
+
import type { GSDEvent, PhaseRunnerResult, RoadmapAnalysis } from './types.js';
|
|
28
|
+
|
|
29
|
+
// ─── CLI availability check ─────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
let cliAvailable = false;
|
|
32
|
+
try {
|
|
33
|
+
execSync('which claude', { stdio: 'ignore' });
|
|
34
|
+
cliAvailable = true;
|
|
35
|
+
} catch {
|
|
36
|
+
cliAvailable = false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
40
|
+
const sdkPromptsDir = join(__dirname, '..', 'prompts');
|
|
41
|
+
const GSD_TOOLS_PATH = resolveGsdToolsPath(process.cwd());
|
|
42
|
+
const gsdToolsAvailable = existsSync(GSD_TOOLS_PATH);
|
|
43
|
+
|
|
44
|
+
// ─── Lifecycle step ordering for monotonicity check ──────────────────────────
|
|
45
|
+
|
|
46
|
+
const STEP_ORDER: Record<string, number> = {
|
|
47
|
+
[PhaseStepType.Discuss]: 0,
|
|
48
|
+
[PhaseStepType.Research]: 1,
|
|
49
|
+
[PhaseStepType.Plan]: 2,
|
|
50
|
+
[PhaseStepType.PlanCheck]: 3,
|
|
51
|
+
[PhaseStepType.Execute]: 4,
|
|
52
|
+
[PhaseStepType.Verify]: 5,
|
|
53
|
+
[PhaseStepType.Advance]: 6,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// ─── Test suite ──────────────────────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
describe.skipIf(!cliAvailable || !gsdToolsAvailable)('E2E Lifecycle: InitRunner → GSD.runPhase() full lifecycle', () => {
|
|
59
|
+
let tmpDir: string;
|
|
60
|
+
let initSuccess: boolean = false;
|
|
61
|
+
let phase1Number: string | null = null;
|
|
62
|
+
let tools: GSDTools;
|
|
63
|
+
|
|
64
|
+
// ── Bootstrap: create temp dir, git init, run InitRunner ──────────────
|
|
65
|
+
beforeAll(async () => {
|
|
66
|
+
tmpDir = await mkdtemp(join(tmpdir(), 'gsd-remix-sdk-lifecycle-e2e-'));
|
|
67
|
+
|
|
68
|
+
// Git init (required by InitRunner and phase lifecycle)
|
|
69
|
+
execSync('git init', { cwd: tmpDir, stdio: 'ignore' });
|
|
70
|
+
execSync('git config user.email "test@test.com"', { cwd: tmpDir, stdio: 'ignore' });
|
|
71
|
+
execSync('git config user.name "Test"', { cwd: tmpDir, stdio: 'ignore' });
|
|
72
|
+
|
|
73
|
+
tools = new GSDTools({
|
|
74
|
+
projectDir: tmpDir,
|
|
75
|
+
gsdToolsPath: GSD_TOOLS_PATH,
|
|
76
|
+
timeoutMs: 30_000,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Run InitRunner to bootstrap the project
|
|
80
|
+
const initEventStream = new GSDEventStream();
|
|
81
|
+
const initRunner = new InitRunner({
|
|
82
|
+
projectDir: tmpDir,
|
|
83
|
+
tools,
|
|
84
|
+
eventStream: initEventStream,
|
|
85
|
+
config: {
|
|
86
|
+
maxBudgetPerSession: 1.0,
|
|
87
|
+
maxTurnsPerSession: 15,
|
|
88
|
+
},
|
|
89
|
+
sdkPromptsDir,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const initResult = await initRunner.run('Build a CLI tool that converts Celsius to Fahrenheit');
|
|
93
|
+
|
|
94
|
+
// Mark init as successful if the pipeline progressed enough
|
|
95
|
+
const completedSteps = initResult.steps.filter(s => s.success);
|
|
96
|
+
initSuccess = initResult.success || completedSteps.length >= 3;
|
|
97
|
+
|
|
98
|
+
// Discover the first phase number via roadmapAnalyze
|
|
99
|
+
if (initSuccess) {
|
|
100
|
+
try {
|
|
101
|
+
const analysis: RoadmapAnalysis = await tools.roadmapAnalyze();
|
|
102
|
+
if (analysis.phases && analysis.phases.length > 0) {
|
|
103
|
+
// Sort by phase number and take the first
|
|
104
|
+
const sorted = [...analysis.phases].sort(
|
|
105
|
+
(a, b) => parseFloat(a.number) - parseFloat(b.number),
|
|
106
|
+
);
|
|
107
|
+
phase1Number = sorted[0]!.number;
|
|
108
|
+
}
|
|
109
|
+
} catch {
|
|
110
|
+
// If roadmap analyze fails, try scanning the phases dir directly
|
|
111
|
+
try {
|
|
112
|
+
const phasesDir = join(tmpDir, '.planning', 'phases');
|
|
113
|
+
const entries = await readdir(phasesDir);
|
|
114
|
+
const phaseEntries = entries
|
|
115
|
+
.filter(e => /^\d+/.test(e))
|
|
116
|
+
.sort();
|
|
117
|
+
if (phaseEntries.length > 0) {
|
|
118
|
+
// Extract the phase number (everything before the first dash)
|
|
119
|
+
const match = phaseEntries[0]!.match(/^(\d+)/);
|
|
120
|
+
if (match) {
|
|
121
|
+
phase1Number = match[1]!;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
} catch {
|
|
125
|
+
// No phases dir — init didn't create one
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}, 600_000); // 10 min for init
|
|
130
|
+
|
|
131
|
+
afterAll(async () => {
|
|
132
|
+
if (tmpDir) {
|
|
133
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// ── Main lifecycle test ───────────────────────────────────────────────
|
|
138
|
+
|
|
139
|
+
it('GSD.runPhase() drives Phase 1 through the full lifecycle without human intervention', async () => {
|
|
140
|
+
// If init failed, skip — can't test lifecycle without a bootstrapped project
|
|
141
|
+
if (!initSuccess) {
|
|
142
|
+
console.warn('Skipping lifecycle test: InitRunner did not bootstrap successfully');
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Verify ROADMAP.md exists and contains at least one phase
|
|
147
|
+
const roadmapPath = join(tmpDir, '.planning', 'ROADMAP.md');
|
|
148
|
+
const roadmapStat = await stat(roadmapPath).catch(() => null);
|
|
149
|
+
expect(roadmapStat).not.toBeNull();
|
|
150
|
+
|
|
151
|
+
const roadmapContent = await readFile(roadmapPath, 'utf-8');
|
|
152
|
+
expect(roadmapContent.length).toBeGreaterThan(0);
|
|
153
|
+
|
|
154
|
+
// Verify we discovered a phase number
|
|
155
|
+
expect(phase1Number).not.toBeNull();
|
|
156
|
+
|
|
157
|
+
// Verify the phase exists via initPhaseOp
|
|
158
|
+
const phaseOp = await tools.initPhaseOp(phase1Number!);
|
|
159
|
+
expect(phaseOp.phase_found).toBe(true);
|
|
160
|
+
|
|
161
|
+
// Collect all events during the phase lifecycle
|
|
162
|
+
const events: GSDEvent[] = [];
|
|
163
|
+
|
|
164
|
+
// Construct GSD with autoMode: true
|
|
165
|
+
const gsd = new GSD({
|
|
166
|
+
projectDir: tmpDir,
|
|
167
|
+
autoMode: true,
|
|
168
|
+
});
|
|
169
|
+
gsd.onEvent((e: GSDEvent) => events.push(e));
|
|
170
|
+
|
|
171
|
+
// Run the discovered first phase with tight budget to minimize cost
|
|
172
|
+
const result: PhaseRunnerResult = await gsd.runPhase(phase1Number!, {
|
|
173
|
+
maxTurnsPerStep: 10,
|
|
174
|
+
maxBudgetPerStep: 0.50,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// ── Assert: result.phaseNumber matches the discovered phase ──
|
|
178
|
+
expect(result.phaseNumber).toBe(phase1Number);
|
|
179
|
+
|
|
180
|
+
// ── Assert: result.phaseName is non-empty ──
|
|
181
|
+
expect(result.phaseName).toBeTruthy();
|
|
182
|
+
expect(result.phaseName.length).toBeGreaterThan(0);
|
|
183
|
+
|
|
184
|
+
// ── Assert: at least one lifecycle step was attempted ──
|
|
185
|
+
expect(result.steps.length).toBeGreaterThanOrEqual(1);
|
|
186
|
+
|
|
187
|
+
// ── Assert: events include PhaseStart ──
|
|
188
|
+
const phaseStartEvents = events.filter(e => e.type === GSDEventType.PhaseStart);
|
|
189
|
+
expect(phaseStartEvents.length).toBe(1);
|
|
190
|
+
const phaseStart = phaseStartEvents[0]!;
|
|
191
|
+
if (phaseStart.type === GSDEventType.PhaseStart) {
|
|
192
|
+
expect(phaseStart.phaseNumber).toBe(phase1Number);
|
|
193
|
+
expect(phaseStart.phaseName).toBeTruthy();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ── Assert: events include PhaseComplete ──
|
|
197
|
+
const phaseCompleteEvents = events.filter(e => e.type === GSDEventType.PhaseComplete);
|
|
198
|
+
expect(phaseCompleteEvents.length).toBe(1);
|
|
199
|
+
const phaseComplete = phaseCompleteEvents[0]!;
|
|
200
|
+
if (phaseComplete.type === GSDEventType.PhaseComplete) {
|
|
201
|
+
expect(phaseComplete.phaseNumber).toBe(phase1Number);
|
|
202
|
+
expect(typeof phaseComplete.totalCostUsd).toBe('number');
|
|
203
|
+
expect(typeof phaseComplete.totalDurationMs).toBe('number');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ── Assert: PhaseStepStart events show step progression ──
|
|
207
|
+
const stepStartEvents = events.filter(
|
|
208
|
+
(e): e is Extract<GSDEvent, { type: GSDEventType.PhaseStepStart }> =>
|
|
209
|
+
e.type === GSDEventType.PhaseStepStart,
|
|
210
|
+
);
|
|
211
|
+
expect(stepStartEvents.length).toBeGreaterThanOrEqual(1);
|
|
212
|
+
|
|
213
|
+
// Extract the step types in order
|
|
214
|
+
const stepTypesInOrder = stepStartEvents.map(e => e.step);
|
|
215
|
+
|
|
216
|
+
// Verify monotonic ordering: each step type should have an index >= previous
|
|
217
|
+
// Note: gap-closure can re-run plan+execute after verify, so we allow
|
|
218
|
+
// monotonicity to break only when verify triggers gap closure.
|
|
219
|
+
// For this tight-budget test, full gap closure is unlikely — check basic ordering.
|
|
220
|
+
let lastMaxOrder = -1;
|
|
221
|
+
for (const stepType of stepTypesInOrder) {
|
|
222
|
+
const order = STEP_ORDER[stepType] ?? -1;
|
|
223
|
+
// Track the high-water mark — steps should generally progress forward
|
|
224
|
+
if (order >= lastMaxOrder) {
|
|
225
|
+
lastMaxOrder = order;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// At least progressed past discuss (order 0) into real work
|
|
229
|
+
expect(lastMaxOrder).toBeGreaterThanOrEqual(1);
|
|
230
|
+
|
|
231
|
+
// ── Assert: at least one step has planResults with cost > 0 (real Agent SDK work) ──
|
|
232
|
+
const stepsWithCost = result.steps.filter(s => {
|
|
233
|
+
if (!s.planResults) return false;
|
|
234
|
+
return s.planResults.some(pr => pr.totalCostUsd > 0);
|
|
235
|
+
});
|
|
236
|
+
// At least one step should have incurred real cost (proves Agent SDK was invoked)
|
|
237
|
+
expect(stepsWithCost.length).toBeGreaterThanOrEqual(1);
|
|
238
|
+
|
|
239
|
+
// ── Assert: result cost and duration are tracked ──
|
|
240
|
+
expect(typeof result.totalCostUsd).toBe('number');
|
|
241
|
+
expect(result.totalDurationMs).toBeGreaterThan(0);
|
|
242
|
+
|
|
243
|
+
// ── Assert: each step result is properly structured ──
|
|
244
|
+
for (const step of result.steps) {
|
|
245
|
+
expect(Object.values(PhaseStepType)).toContain(step.step);
|
|
246
|
+
expect(typeof step.success).toBe('boolean');
|
|
247
|
+
expect(typeof step.durationMs).toBe('number');
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ── Assert: PhaseStepComplete events match step results ──
|
|
251
|
+
const stepCompleteEvents = events.filter(
|
|
252
|
+
(e): e is Extract<GSDEvent, { type: GSDEventType.PhaseStepComplete }> =>
|
|
253
|
+
e.type === GSDEventType.PhaseStepComplete,
|
|
254
|
+
);
|
|
255
|
+
// At least as many complete events as step results
|
|
256
|
+
expect(stepCompleteEvents.length).toBeGreaterThanOrEqual(result.steps.length);
|
|
257
|
+
}, 900_000); // 15 minute timeout: init (~4 min) + phase lifecycle (~10 min)
|
|
258
|
+
});
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { Writable } from 'node:stream';
|
|
3
|
+
import { GSDLogger } from './logger.js';
|
|
4
|
+
import type { LogEntry } from './logger.js';
|
|
5
|
+
import { PhaseType } from './types.js';
|
|
6
|
+
|
|
7
|
+
// ─── Test output capture ─────────────────────────────────────────────────────
|
|
8
|
+
|
|
9
|
+
class BufferStream extends Writable {
|
|
10
|
+
lines: string[] = [];
|
|
11
|
+
_write(chunk: Buffer, _encoding: string, callback: () => void): void {
|
|
12
|
+
const str = chunk.toString();
|
|
13
|
+
this.lines.push(...str.split('\n').filter(l => l.length > 0));
|
|
14
|
+
callback();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function parseLogEntry(line: string): LogEntry {
|
|
19
|
+
return JSON.parse(line) as LogEntry;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// ─── Tests ───────────────────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
describe('GSDLogger', () => {
|
|
25
|
+
let output: BufferStream;
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
output = new BufferStream();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('outputs valid JSON on each log call', () => {
|
|
32
|
+
const logger = new GSDLogger({ output, level: 'debug' });
|
|
33
|
+
logger.info('test message');
|
|
34
|
+
|
|
35
|
+
expect(output.lines).toHaveLength(1);
|
|
36
|
+
expect(() => JSON.parse(output.lines[0]!)).not.toThrow();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('includes required fields: timestamp, level, message', () => {
|
|
40
|
+
const logger = new GSDLogger({ output, level: 'debug' });
|
|
41
|
+
logger.info('hello world');
|
|
42
|
+
|
|
43
|
+
const entry = parseLogEntry(output.lines[0]!);
|
|
44
|
+
expect(entry.timestamp).toMatch(/^\d{4}-\d{2}-\d{2}T/);
|
|
45
|
+
expect(entry.level).toBe('info');
|
|
46
|
+
expect(entry.message).toBe('hello world');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('filters messages below minimum log level', () => {
|
|
50
|
+
const logger = new GSDLogger({ output, level: 'warn' });
|
|
51
|
+
|
|
52
|
+
logger.debug('should be dropped');
|
|
53
|
+
logger.info('should be dropped');
|
|
54
|
+
logger.warn('should appear');
|
|
55
|
+
logger.error('should appear');
|
|
56
|
+
|
|
57
|
+
expect(output.lines).toHaveLength(2);
|
|
58
|
+
expect(parseLogEntry(output.lines[0]!).level).toBe('warn');
|
|
59
|
+
expect(parseLogEntry(output.lines[1]!).level).toBe('error');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('defaults to info level filtering', () => {
|
|
63
|
+
const logger = new GSDLogger({ output });
|
|
64
|
+
|
|
65
|
+
logger.debug('dropped');
|
|
66
|
+
logger.info('kept');
|
|
67
|
+
|
|
68
|
+
expect(output.lines).toHaveLength(1);
|
|
69
|
+
expect(parseLogEntry(output.lines[0]!).level).toBe('info');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('writes to custom output stream', () => {
|
|
73
|
+
const customOutput = new BufferStream();
|
|
74
|
+
const logger = new GSDLogger({ output: customOutput, level: 'debug' });
|
|
75
|
+
logger.info('custom');
|
|
76
|
+
|
|
77
|
+
expect(customOutput.lines).toHaveLength(1);
|
|
78
|
+
expect(output.lines).toHaveLength(0);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('includes phase, plan, and sessionId context when set', () => {
|
|
82
|
+
const logger = new GSDLogger({
|
|
83
|
+
output,
|
|
84
|
+
level: 'debug',
|
|
85
|
+
phase: PhaseType.Execute,
|
|
86
|
+
plan: 'test-plan',
|
|
87
|
+
sessionId: 'sess-123',
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
logger.info('context test');
|
|
91
|
+
|
|
92
|
+
const entry = parseLogEntry(output.lines[0]!);
|
|
93
|
+
expect(entry.phase).toBe('execute');
|
|
94
|
+
expect(entry.plan).toBe('test-plan');
|
|
95
|
+
expect(entry.sessionId).toBe('sess-123');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('includes extra data when provided', () => {
|
|
99
|
+
const logger = new GSDLogger({ output, level: 'debug' });
|
|
100
|
+
logger.info('with data', { count: 42, tool: 'Bash' });
|
|
101
|
+
|
|
102
|
+
const entry = parseLogEntry(output.lines[0]!);
|
|
103
|
+
expect(entry.data).toEqual({ count: 42, tool: 'Bash' });
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('omits optional fields when not set', () => {
|
|
107
|
+
const logger = new GSDLogger({ output, level: 'debug' });
|
|
108
|
+
logger.info('minimal');
|
|
109
|
+
|
|
110
|
+
const entry = parseLogEntry(output.lines[0]!);
|
|
111
|
+
expect(entry.phase).toBeUndefined();
|
|
112
|
+
expect(entry.plan).toBeUndefined();
|
|
113
|
+
expect(entry.sessionId).toBeUndefined();
|
|
114
|
+
expect(entry.data).toBeUndefined();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('supports runtime context updates via setters', () => {
|
|
118
|
+
const logger = new GSDLogger({ output, level: 'debug' });
|
|
119
|
+
|
|
120
|
+
logger.info('before');
|
|
121
|
+
logger.setPhase(PhaseType.Research);
|
|
122
|
+
logger.setPlan('my-plan');
|
|
123
|
+
logger.setSessionId('sess-456');
|
|
124
|
+
logger.info('after');
|
|
125
|
+
|
|
126
|
+
const before = parseLogEntry(output.lines[0]!);
|
|
127
|
+
const after = parseLogEntry(output.lines[1]!);
|
|
128
|
+
|
|
129
|
+
expect(before.phase).toBeUndefined();
|
|
130
|
+
expect(after.phase).toBe('research');
|
|
131
|
+
expect(after.plan).toBe('my-plan');
|
|
132
|
+
expect(after.sessionId).toBe('sess-456');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('emits all four log levels correctly', () => {
|
|
136
|
+
const logger = new GSDLogger({ output, level: 'debug' });
|
|
137
|
+
|
|
138
|
+
logger.debug('d');
|
|
139
|
+
logger.info('i');
|
|
140
|
+
logger.warn('w');
|
|
141
|
+
logger.error('e');
|
|
142
|
+
|
|
143
|
+
expect(output.lines).toHaveLength(4);
|
|
144
|
+
expect(parseLogEntry(output.lines[0]!).level).toBe('debug');
|
|
145
|
+
expect(parseLogEntry(output.lines[1]!).level).toBe('info');
|
|
146
|
+
expect(parseLogEntry(output.lines[2]!).level).toBe('warn');
|
|
147
|
+
expect(parseLogEntry(output.lines[3]!).level).toBe('error');
|
|
148
|
+
});
|
|
149
|
+
});
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured JSON logger for GSD debugging.
|
|
3
|
+
*
|
|
4
|
+
* Writes structured log entries to stderr (or configurable writable stream).
|
|
5
|
+
* This is a debugging facility (R019), separate from the event stream.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Writable } from 'node:stream';
|
|
9
|
+
import type { PhaseType } from './types.js';
|
|
10
|
+
|
|
11
|
+
// ─── Log levels ──────────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
14
|
+
|
|
15
|
+
const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {
|
|
16
|
+
debug: 0,
|
|
17
|
+
info: 1,
|
|
18
|
+
warn: 2,
|
|
19
|
+
error: 3,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// ─── Log entry ───────────────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
export interface LogEntry {
|
|
25
|
+
timestamp: string;
|
|
26
|
+
level: LogLevel;
|
|
27
|
+
phase?: PhaseType;
|
|
28
|
+
plan?: string;
|
|
29
|
+
sessionId?: string;
|
|
30
|
+
message: string;
|
|
31
|
+
data?: Record<string, unknown>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ─── Logger options ──────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
export interface GSDLoggerOptions {
|
|
37
|
+
/** Minimum log level to output. Default: 'info'. */
|
|
38
|
+
level?: LogLevel;
|
|
39
|
+
/** Output stream. Default: process.stderr. */
|
|
40
|
+
output?: Writable;
|
|
41
|
+
/** Phase context for all log entries. */
|
|
42
|
+
phase?: PhaseType;
|
|
43
|
+
/** Plan name context for all log entries. */
|
|
44
|
+
plan?: string;
|
|
45
|
+
/** Session ID context for all log entries. */
|
|
46
|
+
sessionId?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ─── Logger class ────────────────────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
export class GSDLogger {
|
|
52
|
+
private readonly minLevel: number;
|
|
53
|
+
private readonly output: Writable;
|
|
54
|
+
private phase?: PhaseType;
|
|
55
|
+
private plan?: string;
|
|
56
|
+
private sessionId?: string;
|
|
57
|
+
|
|
58
|
+
constructor(options: GSDLoggerOptions = {}) {
|
|
59
|
+
this.minLevel = LOG_LEVEL_PRIORITY[options.level ?? 'info'];
|
|
60
|
+
this.output = options.output ?? process.stderr;
|
|
61
|
+
this.phase = options.phase;
|
|
62
|
+
this.plan = options.plan;
|
|
63
|
+
this.sessionId = options.sessionId;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Set phase context for subsequent log entries. */
|
|
67
|
+
setPhase(phase: PhaseType | undefined): void {
|
|
68
|
+
this.phase = phase;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Set plan context for subsequent log entries. */
|
|
72
|
+
setPlan(plan: string | undefined): void {
|
|
73
|
+
this.plan = plan;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Set session ID context for subsequent log entries. */
|
|
77
|
+
setSessionId(sessionId: string | undefined): void {
|
|
78
|
+
this.sessionId = sessionId;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
debug(message: string, data?: Record<string, unknown>): void {
|
|
82
|
+
this.log('debug', message, data);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
info(message: string, data?: Record<string, unknown>): void {
|
|
86
|
+
this.log('info', message, data);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
warn(message: string, data?: Record<string, unknown>): void {
|
|
90
|
+
this.log('warn', message, data);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
error(message: string, data?: Record<string, unknown>): void {
|
|
94
|
+
this.log('error', message, data);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private log(level: LogLevel, message: string, data?: Record<string, unknown>): void {
|
|
98
|
+
if (LOG_LEVEL_PRIORITY[level] < this.minLevel) return;
|
|
99
|
+
|
|
100
|
+
const entry: LogEntry = {
|
|
101
|
+
timestamp: new Date().toISOString(),
|
|
102
|
+
level,
|
|
103
|
+
message,
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
if (this.phase !== undefined) entry.phase = this.phase;
|
|
107
|
+
if (this.plan !== undefined) entry.plan = this.plan;
|
|
108
|
+
if (this.sessionId !== undefined) entry.sessionId = this.sessionId;
|
|
109
|
+
if (data !== undefined) entry.data = data;
|
|
110
|
+
|
|
111
|
+
this.output.write(JSON.stringify(entry) + '\n');
|
|
112
|
+
}
|
|
113
|
+
}
|