gsd-pi 2.71.0-dev.e17e0ce → 2.72.0-dev.3118184
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/README.md +46 -3
- package/dist/cli.js +76 -3
- package/dist/mcp-server.js +37 -14
- package/dist/onboarding.js +10 -0
- package/dist/resources/agents/debugger.md +58 -0
- package/dist/resources/agents/doc-writer.md +43 -0
- package/dist/resources/agents/git-ops.md +56 -0
- package/dist/resources/agents/javascript-pro.md +46 -271
- package/dist/resources/agents/planner.md +55 -0
- package/dist/resources/agents/refactorer.md +47 -0
- package/dist/resources/agents/reviewer.md +48 -0
- package/dist/resources/agents/security.md +59 -0
- package/dist/resources/agents/tester.md +50 -0
- package/dist/resources/agents/typescript-pro.md +41 -235
- package/dist/resources/extensions/async-jobs/await-tool.js +7 -4
- package/dist/resources/extensions/async-jobs/job-manager.js +28 -3
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +40 -12
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +132 -10
- package/dist/resources/extensions/gsd/auto/loop.js +84 -1
- package/dist/resources/extensions/gsd/auto/phases.js +4 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +6 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +88 -33
- package/dist/resources/extensions/gsd/auto-recovery.js +11 -0
- package/dist/resources/extensions/gsd/auto-start.js +24 -4
- package/dist/resources/extensions/gsd/auto.js +29 -19
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -3
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +9 -11
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +2 -5
- package/dist/resources/extensions/gsd/commands-handlers.js +4 -1
- package/dist/resources/extensions/gsd/context-injector.js +1 -1
- package/dist/resources/extensions/gsd/custom-workflow-engine.js +3 -7
- package/dist/resources/extensions/gsd/definition-io.js +15 -0
- package/dist/resources/extensions/gsd/dispatch-guard.js +4 -0
- package/dist/resources/extensions/gsd/doctor-providers.js +23 -0
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +6 -3
- package/dist/resources/extensions/gsd/error-classifier.js +4 -1
- package/dist/resources/extensions/gsd/gate-registry.js +208 -0
- package/dist/resources/extensions/gsd/git-service.js +11 -8
- package/dist/resources/extensions/gsd/gitignore.js +12 -6
- package/dist/resources/extensions/gsd/gsd-db.js +90 -6
- package/dist/resources/extensions/gsd/key-manager.js +2 -0
- package/dist/resources/extensions/gsd/milestone-validation-gates.js +11 -12
- package/dist/resources/extensions/gsd/notification-overlay.js +26 -12
- package/dist/resources/extensions/gsd/notification-store.js +5 -4
- package/dist/resources/extensions/gsd/preferences-skills.js +2 -34
- package/dist/resources/extensions/gsd/preferences-types.js +15 -0
- package/dist/resources/extensions/gsd/preferences.js +16 -3
- package/dist/resources/extensions/gsd/prompt-loader.js +4 -1
- package/dist/resources/extensions/gsd/prompt-validation.js +126 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +3 -1
- package/dist/resources/extensions/gsd/prompts/discuss.md +122 -13
- package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
- package/dist/resources/extensions/gsd/shortcut-defs.js +7 -1
- package/dist/resources/extensions/gsd/state.js +29 -2
- package/dist/resources/extensions/gsd/tools/complete-slice.js +52 -1
- package/dist/resources/extensions/gsd/tools/complete-task.js +51 -1
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +4 -1
- package/dist/resources/extensions/gsd/workflow-projections.js +7 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +30 -3
- package/dist/resources/extensions/gsd/write-intercept.js +10 -1
- package/dist/resources/extensions/ollama/index.js +17 -10
- package/dist/resources/extensions/ollama/ollama-client.js +35 -6
- package/dist/resources/extensions/ollama/ollama-discovery.js +32 -6
- package/dist/resources/extensions/shared/gsd-phase-state.js +35 -0
- package/dist/resources/extensions/subagent/agents.js +8 -0
- package/dist/resources/extensions/subagent/index.js +17 -0
- package/dist/startup-model-validation.d.ts +0 -1
- package/dist/startup-model-validation.js +6 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +3 -3
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +14 -14
- package/dist/web/standalone/.next/server/chunks/2331.js +16 -16
- package/dist/web/standalone/.next/server/chunks/4741.js +12 -12
- package/dist/web/standalone/.next/server/chunks/5822.js +2 -2
- package/dist/web/standalone/.next/server/chunks/63.js +8 -8
- package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
- package/dist/web/standalone/.next/server/edge-runtime-webpack.js +2 -0
- package/dist/web/standalone/.next/server/functions-config-manifest.json +0 -9
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +29 -2
- package/dist/web/standalone/.next/server/middleware.js +4 -12
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/server/webpack-runtime.js +1 -1
- package/package.json +1 -1
- package/packages/mcp-server/dist/server.d.ts +12 -1
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +90 -42
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +1 -1
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/server.ts +110 -38
- package/packages/mcp-server/src/workflow-tools.ts +1 -1
- package/packages/pi-ai/dist/env-api-keys.js +1 -0
- package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
- package/packages/pi-ai/dist/models.custom.d.ts +105 -0
- package/packages/pi-ai/dist/models.custom.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.custom.js +97 -0
- package/packages/pi-ai/dist/models.custom.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +648 -140
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +867 -370
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.test.d.ts +2 -0
- package/packages/pi-ai/dist/models.generated.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/models.generated.test.js +334 -0
- package/packages/pi-ai/dist/models.generated.test.js.map +1 -0
- package/packages/pi-ai/dist/models.test.js +105 -0
- package/packages/pi-ai/dist/models.test.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +1 -1
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js +5 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.test.d.ts +2 -0
- package/packages/pi-ai/dist/utils/oauth/github-copilot.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +57 -0
- package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -0
- package/packages/pi-ai/src/env-api-keys.ts +1 -0
- package/packages/pi-ai/src/models.custom.ts +98 -0
- package/packages/pi-ai/src/models.generated.test.ts +373 -0
- package/packages/pi-ai/src/models.generated.ts +867 -370
- package/packages/pi-ai/src/models.test.ts +135 -0
- package/packages/pi-ai/src/types.ts +1 -0
- package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +71 -0
- package/packages/pi-ai/src/utils/oauth/github-copilot.ts +4 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.test.d.ts +8 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.test.js +75 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts +5 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +55 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +57 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +9 -0
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +9 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +87 -12
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js +6 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/model-resolver.test.ts +85 -0
- package/packages/pi-coding-agent/src/core/model-resolver.ts +1 -0
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +83 -0
- package/packages/pi-coding-agent/src/core/retry-handler.ts +60 -1
- package/packages/pi-coding-agent/src/core/sdk.ts +10 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +72 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +15 -6
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +84 -12
- package/packages/pi-coding-agent/src/modes/interactive/controllers/model-controller.ts +6 -1
- package/packages/pi-tui/dist/components/__tests__/editor.test.js +12 -0
- package/packages/pi-tui/dist/components/__tests__/editor.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/input.test.js +12 -0
- package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
- package/packages/pi-tui/dist/keys.d.ts.map +1 -1
- package/packages/pi-tui/dist/keys.js +27 -0
- package/packages/pi-tui/dist/keys.js.map +1 -1
- package/packages/pi-tui/src/components/__tests__/editor.test.ts +18 -0
- package/packages/pi-tui/src/components/__tests__/input.test.ts +18 -0
- package/packages/pi-tui/src/keys.ts +32 -0
- package/pkg/package.json +1 -1
- package/src/resources/agents/debugger.md +58 -0
- package/src/resources/agents/doc-writer.md +43 -0
- package/src/resources/agents/git-ops.md +56 -0
- package/src/resources/agents/javascript-pro.md +46 -271
- package/src/resources/agents/planner.md +55 -0
- package/src/resources/agents/refactorer.md +47 -0
- package/src/resources/agents/reviewer.md +48 -0
- package/src/resources/agents/security.md +59 -0
- package/src/resources/agents/tester.md +50 -0
- package/src/resources/agents/typescript-pro.md +41 -235
- package/src/resources/extensions/async-jobs/await-tool.test.ts +40 -7
- package/src/resources/extensions/async-jobs/await-tool.ts +7 -4
- package/src/resources/extensions/async-jobs/job-manager.ts +33 -3
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +45 -12
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +139 -8
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +91 -2
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +245 -2
- package/src/resources/extensions/gsd/auto/loop.ts +89 -1
- package/src/resources/extensions/gsd/auto/phases.ts +4 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +7 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +111 -33
- package/src/resources/extensions/gsd/auto-recovery.ts +10 -0
- package/src/resources/extensions/gsd/auto-start.ts +31 -4
- package/src/resources/extensions/gsd/auto.ts +29 -20
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -3
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +8 -10
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +2 -5
- package/src/resources/extensions/gsd/commands-handlers.ts +5 -1
- package/src/resources/extensions/gsd/context-injector.ts +1 -1
- package/src/resources/extensions/gsd/custom-workflow-engine.ts +4 -8
- package/src/resources/extensions/gsd/definition-io.ts +18 -0
- package/src/resources/extensions/gsd/dispatch-guard.ts +5 -0
- package/src/resources/extensions/gsd/doctor-providers.ts +24 -0
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +6 -3
- package/src/resources/extensions/gsd/error-classifier.ts +4 -1
- package/src/resources/extensions/gsd/gate-registry.ts +251 -0
- package/src/resources/extensions/gsd/git-service.ts +11 -8
- package/src/resources/extensions/gsd/gitignore.ts +12 -6
- package/src/resources/extensions/gsd/gsd-db.ts +105 -6
- package/src/resources/extensions/gsd/key-manager.ts +2 -0
- package/src/resources/extensions/gsd/milestone-validation-gates.ts +11 -13
- package/src/resources/extensions/gsd/notification-overlay.ts +27 -11
- package/src/resources/extensions/gsd/notification-store.ts +5 -4
- package/src/resources/extensions/gsd/preferences-skills.ts +2 -36
- package/src/resources/extensions/gsd/preferences-types.ts +16 -0
- package/src/resources/extensions/gsd/preferences.ts +19 -6
- package/src/resources/extensions/gsd/prompt-loader.ts +6 -1
- package/src/resources/extensions/gsd/prompt-validation.ts +157 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +3 -1
- package/src/resources/extensions/gsd/prompts/discuss.md +122 -13
- package/src/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
- package/src/resources/extensions/gsd/shortcut-defs.ts +8 -1
- package/src/resources/extensions/gsd/state.ts +33 -2
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/block-db-writes.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/complete-slice-gate-closure.test.ts +167 -0
- package/src/resources/extensions/gsd/tests/definition-io.test.ts +57 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/doctor-heal-fixable-warnings.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/false-degraded-mode-warning.test.ts +104 -0
- package/src/resources/extensions/gsd/tests/format-shortcut.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/gate-registry.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +107 -5
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +8 -6
- package/src/resources/extensions/gsd/tests/key-manager.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/plan-milestone-artifact-verification.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/preferences-formatting.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/projection-regression.test.ts +96 -1
- package/src/resources/extensions/gsd/tests/prompt-loader-working-directory.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/prompt-system-gate-coverage.test.ts +208 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +97 -0
- package/src/resources/extensions/gsd/tests/register-shortcuts.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +41 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +63 -0
- package/src/resources/extensions/gsd/tools/complete-task.ts +63 -0
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +4 -1
- package/src/resources/extensions/gsd/types.ts +26 -0
- package/src/resources/extensions/gsd/workflow-projections.ts +8 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +29 -3
- package/src/resources/extensions/gsd/write-intercept.ts +10 -1
- package/src/resources/extensions/ollama/index.ts +17 -8
- package/src/resources/extensions/ollama/ollama-client.ts +35 -6
- package/src/resources/extensions/ollama/ollama-discovery.ts +37 -6
- package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +28 -0
- package/src/resources/extensions/ollama/tests/ollama-discovery.test.ts +54 -0
- package/src/resources/extensions/shared/gsd-phase-state.ts +42 -0
- package/src/resources/extensions/shared/tests/gsd-phase-state.test.ts +48 -0
- package/src/resources/extensions/subagent/agents.ts +10 -0
- package/src/resources/extensions/subagent/index.ts +18 -0
- package/src/resources/extensions/subagent/tests/agents-conflicts.test.ts +33 -0
- /package/dist/web/standalone/.next/static/{cYPZv_bAhZk2ms-Pz6vsY → NzO79SOz9jHX-VY5-0t2O}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{cYPZv_bAhZk2ms-Pz6vsY → NzO79SOz9jHX-VY5-0t2O}/_ssgManifest.js +0 -0
|
@@ -49,6 +49,8 @@ export const PROVIDER_REGISTRY: ProviderInfo[] = [
|
|
|
49
49
|
{ id: "custom-openai", label: "Custom (OpenAI-compat)", category: "llm", envVar: "CUSTOM_OPENAI_API_KEY" },
|
|
50
50
|
{ id: "cerebras", label: "Cerebras", category: "llm", envVar: "CEREBRAS_API_KEY" },
|
|
51
51
|
{ id: "azure-openai-responses", label: "Azure OpenAI", category: "llm", envVar: "AZURE_OPENAI_API_KEY" },
|
|
52
|
+
{ id: "alibaba-coding-plan", label: "Alibaba Coding Plan", category: "llm", envVar: "ALIBABA_API_KEY", dashboardUrl: "bailian.console.aliyun.com" },
|
|
53
|
+
{ id: "alibaba-dashscope", label: "Alibaba DashScope", category: "llm", envVar: "DASHSCOPE_API_KEY", dashboardUrl: "dashscope.console.aliyun.com" },
|
|
52
54
|
|
|
53
55
|
// Tool Keys
|
|
54
56
|
{ id: "context7", label: "Context7 Docs", category: "tool", envVar: "CONTEXT7_API_KEY", dashboardUrl: "context7.com/dashboard" },
|
|
@@ -6,19 +6,13 @@
|
|
|
6
6
|
* records in the DB. This module inserts milestone-level validation gates
|
|
7
7
|
* that correspond to the validation checks performed.
|
|
8
8
|
*
|
|
9
|
-
* Gate IDs for milestone validation
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* MV03 — Cross-slice integration
|
|
13
|
-
* MV04 — Requirement coverage
|
|
14
|
-
*
|
|
15
|
-
* These use the existing quality_gates table with scope "milestone".
|
|
9
|
+
* Gate IDs for milestone validation (MV01–MV04) are sourced from the
|
|
10
|
+
* gate registry so the definitions stay in lockstep with prompt builders,
|
|
11
|
+
* dispatch rules, and state derivation. See gate-registry.ts.
|
|
16
12
|
*/
|
|
17
13
|
|
|
18
14
|
import { _getAdapter } from "./gsd-db.js";
|
|
19
|
-
|
|
20
|
-
/** Milestone validation gate IDs. */
|
|
21
|
-
const MILESTONE_GATE_IDS = ["MV01", "MV02", "MV03", "MV04"] as const;
|
|
15
|
+
import { getGatesForTurn } from "./gate-registry.js";
|
|
22
16
|
|
|
23
17
|
/**
|
|
24
18
|
* Insert milestone-level quality_gates records for a validation run.
|
|
@@ -27,6 +21,9 @@ const MILESTONE_GATE_IDS = ["MV01", "MV02", "MV03", "MV04"] as const;
|
|
|
27
21
|
* from the overall milestone validation verdict. Individual gate-level
|
|
28
22
|
* verdicts are not available (the handler receives a single verdict),
|
|
29
23
|
* so all gates share the overall verdict.
|
|
24
|
+
*
|
|
25
|
+
* Gate IDs come from the registry — adding/removing an MV-scoped gate
|
|
26
|
+
* in gate-registry.ts automatically flows through here.
|
|
30
27
|
*/
|
|
31
28
|
export function insertMilestoneValidationGates(
|
|
32
29
|
milestoneId: string,
|
|
@@ -38,8 +35,9 @@ export function insertMilestoneValidationGates(
|
|
|
38
35
|
if (!db) return;
|
|
39
36
|
|
|
40
37
|
const gateVerdict = verdict === "pass" ? "pass" : "flag";
|
|
38
|
+
const milestoneGates = getGatesForTurn("validate-milestone");
|
|
41
39
|
|
|
42
|
-
for (const
|
|
40
|
+
for (const def of milestoneGates) {
|
|
43
41
|
db.prepare(
|
|
44
42
|
`INSERT OR REPLACE INTO quality_gates
|
|
45
43
|
(milestone_id, slice_id, gate_id, scope, task_id, status, verdict, rationale, findings, evaluated_at)
|
|
@@ -47,9 +45,9 @@ export function insertMilestoneValidationGates(
|
|
|
47
45
|
).run({
|
|
48
46
|
":mid": milestoneId,
|
|
49
47
|
":sid": sliceId,
|
|
50
|
-
":gid":
|
|
48
|
+
":gid": def.id,
|
|
51
49
|
":verdict": gateVerdict,
|
|
52
|
-
":rationale":
|
|
50
|
+
":rationale": `${def.promptSection} — milestone validation verdict: ${verdict}`,
|
|
53
51
|
":evaluated_at": evaluatedAt,
|
|
54
52
|
});
|
|
55
53
|
}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
readNotifications,
|
|
10
10
|
markAllRead,
|
|
11
11
|
clearNotifications,
|
|
12
|
+
onNotificationStoreChange,
|
|
12
13
|
type NotificationEntry,
|
|
13
14
|
type NotifySeverity,
|
|
14
15
|
} from "./notification-store.js";
|
|
@@ -82,6 +83,7 @@ export class GSDNotificationOverlay {
|
|
|
82
83
|
private refreshTimer: ReturnType<typeof setInterval>;
|
|
83
84
|
private disposed = false;
|
|
84
85
|
private resizeHandler: (() => void) | null = null;
|
|
86
|
+
private unsubscribeStore: (() => void) | null = null;
|
|
85
87
|
|
|
86
88
|
constructor(
|
|
87
89
|
tui: { requestRender: () => void },
|
|
@@ -105,19 +107,17 @@ export class GSDNotificationOverlay {
|
|
|
105
107
|
};
|
|
106
108
|
process.stdout.on("resize", this.resizeHandler);
|
|
107
109
|
|
|
108
|
-
//
|
|
110
|
+
// Subscribe to store mutations for immediate updates
|
|
111
|
+
this.unsubscribeStore = onNotificationStoreChange(() => {
|
|
112
|
+
if (this.disposed) return;
|
|
113
|
+
this._refreshFromDisk();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// 30s safety-net for cross-process edits (web subprocess, parallel workers)
|
|
109
117
|
this.refreshTimer = setInterval(() => {
|
|
110
118
|
if (this.disposed) return;
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (signature !== this.entriesSignature) {
|
|
114
|
-
markAllRead();
|
|
115
|
-
this.entries = readNotifications();
|
|
116
|
-
this.entriesSignature = notificationSignature(this.entries);
|
|
117
|
-
this.invalidate();
|
|
118
|
-
this.tui.requestRender();
|
|
119
|
-
}
|
|
120
|
-
}, 3000);
|
|
119
|
+
this._refreshFromDisk();
|
|
120
|
+
}, 30_000);
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
private get filter(): FilterMode {
|
|
@@ -215,12 +215,28 @@ export class GSDNotificationOverlay {
|
|
|
215
215
|
dispose(): void {
|
|
216
216
|
this.disposed = true;
|
|
217
217
|
clearInterval(this.refreshTimer);
|
|
218
|
+
if (this.unsubscribeStore) {
|
|
219
|
+
this.unsubscribeStore();
|
|
220
|
+
this.unsubscribeStore = null;
|
|
221
|
+
}
|
|
218
222
|
if (this.resizeHandler) {
|
|
219
223
|
process.stdout.removeListener("resize", this.resizeHandler);
|
|
220
224
|
this.resizeHandler = null;
|
|
221
225
|
}
|
|
222
226
|
}
|
|
223
227
|
|
|
228
|
+
private _refreshFromDisk(): void {
|
|
229
|
+
const fresh = readNotifications();
|
|
230
|
+
const signature = notificationSignature(fresh);
|
|
231
|
+
if (signature !== this.entriesSignature) {
|
|
232
|
+
markAllRead();
|
|
233
|
+
this.entries = readNotifications();
|
|
234
|
+
this.entriesSignature = notificationSignature(this.entries);
|
|
235
|
+
this.invalidate();
|
|
236
|
+
this.tui.requestRender();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
224
240
|
private wrapInBox(inner: string[], width: number): string[] {
|
|
225
241
|
const th = this.theme;
|
|
226
242
|
const border = (s: string) => th.fg("borderAccent", s);
|
|
@@ -323,10 +323,11 @@ function _withLock<T>(basePath: string, fn: () => T): T {
|
|
|
323
323
|
}
|
|
324
324
|
}
|
|
325
325
|
|
|
326
|
-
//
|
|
327
|
-
|
|
326
|
+
// Best-effort: mutation runs regardless of lock status (idempotent overwrites).
|
|
327
|
+
// createdLock gates cleanup only — never skip fn() on lock failure.
|
|
328
|
+
const createdLock = fd !== null;
|
|
328
329
|
try {
|
|
329
|
-
if (
|
|
330
|
+
if (createdLock && fd !== null) {
|
|
330
331
|
// Write our PID timestamp into the lock for stale detection
|
|
331
332
|
writeFileSync(lockPath, String(Date.now()), "utf-8");
|
|
332
333
|
closeSync(fd);
|
|
@@ -334,7 +335,7 @@ function _withLock<T>(basePath: string, fn: () => T): T {
|
|
|
334
335
|
return fn();
|
|
335
336
|
} finally {
|
|
336
337
|
// Only delete the lock if we created it — never remove another process's lock
|
|
337
|
-
if (
|
|
338
|
+
if (createdLock) {
|
|
338
339
|
try { unlinkSync(lockPath); } catch { /* best-effort cleanup */ }
|
|
339
340
|
}
|
|
340
341
|
}
|
|
@@ -17,7 +17,6 @@ import type {
|
|
|
17
17
|
SkillResolutionReport,
|
|
18
18
|
} from "./preferences-types.js";
|
|
19
19
|
import { validatePreferences } from "./preferences-validation.js";
|
|
20
|
-
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
21
20
|
|
|
22
21
|
// Re-export types so existing consumers of ./preferences-skills.js keep working
|
|
23
22
|
export type { GSDSkillRule, SkillDiscoveryMode, SkillResolution, SkillResolutionReport } from "./preferences-types.js";
|
|
@@ -143,38 +142,5 @@ export function resolveAllSkillReferences(preferences: GSDPreferences, cwd: stri
|
|
|
143
142
|
return { resolutions, warnings };
|
|
144
143
|
}
|
|
145
144
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
* If resolved, shows the path so the agent knows exactly where to read.
|
|
149
|
-
* If unresolved, marks it clearly.
|
|
150
|
-
*/
|
|
151
|
-
export function formatSkillRef(ref: string, resolutions: Map<string, SkillResolution>): string {
|
|
152
|
-
const resolution = resolutions.get(ref);
|
|
153
|
-
if (!resolution || resolution.method === "unresolved") {
|
|
154
|
-
return `${ref} (⚠ not found — check skill name or path)`;
|
|
155
|
-
}
|
|
156
|
-
// For absolute paths where SKILL.md is just appended, don't clutter the output
|
|
157
|
-
if (resolution.method === "absolute-path" || resolution.method === "absolute-dir") {
|
|
158
|
-
return ref;
|
|
159
|
-
}
|
|
160
|
-
// For bare names resolved from skill directories, show the resolved path
|
|
161
|
-
return `${ref} → \`${resolution.resolvedPath}\``;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Resolve the skill discovery mode from effective preferences.
|
|
166
|
-
* Defaults to "suggest" -- skills are identified during research but not installed automatically.
|
|
167
|
-
*/
|
|
168
|
-
export function resolveSkillDiscoveryMode(): SkillDiscoveryMode {
|
|
169
|
-
const prefs = loadEffectiveGSDPreferences();
|
|
170
|
-
return prefs?.preferences.skill_discovery ?? "suggest";
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Resolve the skill staleness threshold in days.
|
|
175
|
-
* Returns 0 if disabled, default 60 if not configured.
|
|
176
|
-
*/
|
|
177
|
-
export function resolveSkillStalenessDays(): number {
|
|
178
|
-
const prefs = loadEffectiveGSDPreferences();
|
|
179
|
-
return prefs?.preferences.skill_staleness_days ?? 60;
|
|
180
|
-
}
|
|
145
|
+
// resolveSkillDiscoveryMode and resolveSkillStalenessDays moved to
|
|
146
|
+
// preferences.ts to break circular dependency (they need loadEffectiveGSDPreferences).
|
|
@@ -384,3 +384,19 @@ export interface SkillResolutionReport {
|
|
|
384
384
|
/** References that could not be resolved. */
|
|
385
385
|
warnings: string[];
|
|
386
386
|
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Format a skill reference for the system prompt.
|
|
390
|
+
* If resolved, shows the path so the agent knows exactly where to read.
|
|
391
|
+
* If unresolved, marks it clearly.
|
|
392
|
+
*/
|
|
393
|
+
export function formatSkillRef(ref: string, resolutions: Map<string, SkillResolution>): string {
|
|
394
|
+
const resolution = resolutions.get(ref);
|
|
395
|
+
if (!resolution || resolution.method === "unresolved") {
|
|
396
|
+
return `${ref} (⚠ not found — check skill name or path)`;
|
|
397
|
+
}
|
|
398
|
+
if (resolution.method === "absolute-path" || resolution.method === "absolute-dir") {
|
|
399
|
+
return ref;
|
|
400
|
+
}
|
|
401
|
+
return `${ref} → \`${resolution.resolvedPath}\``;
|
|
402
|
+
}
|
|
@@ -29,9 +29,10 @@ import {
|
|
|
29
29
|
type GSDPreferences,
|
|
30
30
|
type LoadedGSDPreferences,
|
|
31
31
|
type SkillResolution,
|
|
32
|
+
type SkillDiscoveryMode,
|
|
33
|
+
formatSkillRef,
|
|
32
34
|
} from "./preferences-types.js";
|
|
33
35
|
import { validatePreferences } from "./preferences-validation.js";
|
|
34
|
-
import { formatSkillRef } from "./preferences-skills.js";
|
|
35
36
|
|
|
36
37
|
// ─── Re-exports: types ──────────────────────────────────────────────────────
|
|
37
38
|
// Every type/interface that was previously exported from this file is
|
|
@@ -60,11 +61,20 @@ export type {
|
|
|
60
61
|
export { validatePreferences } from "./preferences-validation.js";
|
|
61
62
|
|
|
62
63
|
// ─── Re-exports: skills ─────────────────────────────────────────────────────
|
|
63
|
-
export {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
export { resolveAllSkillReferences } from "./preferences-skills.js";
|
|
65
|
+
|
|
66
|
+
// These lived in preferences-skills.ts but imported loadEffectiveGSDPreferences
|
|
67
|
+
// back from this file, creating a circular dependency. Moved here since they
|
|
68
|
+
// are trivial wrappers over loadEffectiveGSDPreferences.
|
|
69
|
+
export function resolveSkillDiscoveryMode(): SkillDiscoveryMode {
|
|
70
|
+
const prefs = loadEffectiveGSDPreferences();
|
|
71
|
+
return prefs?.preferences.skill_discovery ?? "suggest";
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function resolveSkillStalenessDays(): number {
|
|
75
|
+
const prefs = loadEffectiveGSDPreferences();
|
|
76
|
+
return prefs?.preferences.skill_staleness_days ?? 60;
|
|
77
|
+
}
|
|
68
78
|
|
|
69
79
|
// ─── Re-exports: models ─────────────────────────────────────────────────────
|
|
70
80
|
export {
|
|
@@ -389,6 +399,9 @@ function mergePreferences(base: GSDPreferences, override: GSDPreferences): GSDPr
|
|
|
389
399
|
github: (base.github || override.github)
|
|
390
400
|
? { ...(base.github ?? {}), ...(override.github ?? {}) } as import("../github-sync/types.js").GitHubSyncConfig
|
|
391
401
|
: undefined,
|
|
402
|
+
experimental: (base.experimental || override.experimental)
|
|
403
|
+
? { ...(base.experimental ?? {}), ...(override.experimental ?? {}) }
|
|
404
|
+
: undefined,
|
|
392
405
|
service_tier: override.service_tier ?? base.service_tier,
|
|
393
406
|
forensics_dedup: override.forensics_dedup ?? base.forensics_dedup,
|
|
394
407
|
show_token_cost: override.show_token_cost ?? base.show_token_cost,
|
|
@@ -143,10 +143,15 @@ export function loadPrompt(name: string, vars: Record<string, string> = {}): str
|
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
for (const [key, value] of Object.entries(effectiveVars)) {
|
|
146
|
+
const safeValue =
|
|
147
|
+
key === "workingDirectory" && typeof value === "string"
|
|
148
|
+
? value.replaceAll("\\", "/")
|
|
149
|
+
: value;
|
|
150
|
+
|
|
146
151
|
// Use split/join instead of replaceAll to avoid JavaScript's special
|
|
147
152
|
// replacement patterns ($', $`, $&) being interpreted in the value.
|
|
148
153
|
// See: https://github.com/gsd-build/gsd-2/issues/2968
|
|
149
|
-
content = content.split(`{{${key}}}`).join(
|
|
154
|
+
content = content.split(`{{${key}}}`).join(safeValue);
|
|
150
155
|
}
|
|
151
156
|
|
|
152
157
|
return content.trim();
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GSD Prompt Validation — Validates enhanced context and turn output
|
|
3
|
+
* artifacts before writing.
|
|
4
|
+
*
|
|
5
|
+
* Implements R109 validation requirement: CONTEXT.md must have required
|
|
6
|
+
* sections before being written to disk. Additionally, per-turn validators
|
|
7
|
+
* check that artifacts produced by gate-owning turns contain the gate
|
|
8
|
+
* sections declared in gate-registry.ts, so a malformed summary/validation
|
|
9
|
+
* markdown file cannot silently drop a quality gate.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { getGatesForTurn, type OwnerTurn } from "./gate-registry.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Result of validating enhanced context output.
|
|
16
|
+
*/
|
|
17
|
+
export interface ValidationResult {
|
|
18
|
+
/** Whether all required sections are present. */
|
|
19
|
+
valid: boolean;
|
|
20
|
+
/** List of missing required sections. */
|
|
21
|
+
missing: string[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Validate that enhanced context content has all required sections.
|
|
26
|
+
*
|
|
27
|
+
* Required sections per R109:
|
|
28
|
+
* - Scope section (## Scope, ## Milestone Scope, or ## Why This Milestone)
|
|
29
|
+
* - Architectural Decisions section (## Architectural Decisions)
|
|
30
|
+
* - Acceptance Criteria section (## Acceptance Criteria or ## Final Integrated Acceptance)
|
|
31
|
+
*
|
|
32
|
+
* Additionally validates that the Architectural Decisions section contains
|
|
33
|
+
* at least one decision entry (### heading or **Decision marker).
|
|
34
|
+
*
|
|
35
|
+
* @param content - The enhanced context markdown content
|
|
36
|
+
* @returns ValidationResult with valid flag and list of missing sections
|
|
37
|
+
*/
|
|
38
|
+
export function validateEnhancedContext(content: string): ValidationResult {
|
|
39
|
+
const missing: string[] = [];
|
|
40
|
+
|
|
41
|
+
// Required section 1: Scope (multiple acceptable header variants)
|
|
42
|
+
const hasScopeSection =
|
|
43
|
+
/^## Scope\b/m.test(content) ||
|
|
44
|
+
/^## Milestone Scope\b/m.test(content) ||
|
|
45
|
+
/^## Why This Milestone\b/m.test(content);
|
|
46
|
+
|
|
47
|
+
if (!hasScopeSection) {
|
|
48
|
+
missing.push("Milestone Scope or Why This Milestone");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Required section 2: Architectural Decisions
|
|
52
|
+
const hasArchitecturalDecisions = /^## Architectural Decisions\b/m.test(content);
|
|
53
|
+
if (!hasArchitecturalDecisions) {
|
|
54
|
+
missing.push("Architectural Decisions");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Required section 3: Acceptance Criteria (multiple acceptable header variants)
|
|
58
|
+
const hasAcceptanceCriteria =
|
|
59
|
+
/^## Acceptance Criteria\b/m.test(content) ||
|
|
60
|
+
/^## Final Integrated Acceptance\b/m.test(content);
|
|
61
|
+
|
|
62
|
+
if (!hasAcceptanceCriteria) {
|
|
63
|
+
missing.push("Acceptance Criteria");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Additional validation: Architectural Decisions must have at least one entry
|
|
67
|
+
if (hasArchitecturalDecisions) {
|
|
68
|
+
// Extract the section content between ## Architectural Decisions and the next ## heading.
|
|
69
|
+
// Uses indexOf-based extraction instead of regex with \z (which is invalid in JavaScript
|
|
70
|
+
// regex — it's PCRE/Ruby syntax and JS treats it as literal 'z').
|
|
71
|
+
const sectionStart = content.indexOf("## Architectural Decisions");
|
|
72
|
+
if (sectionStart === -1) {
|
|
73
|
+
missing.push("Architectural Decisions");
|
|
74
|
+
} else {
|
|
75
|
+
const afterHeading = content.slice(sectionStart + "## Architectural Decisions".length);
|
|
76
|
+
const nextSection = afterHeading.search(/^## /m);
|
|
77
|
+
const sectionContent = nextSection === -1 ? afterHeading : afterHeading.slice(0, nextSection);
|
|
78
|
+
|
|
79
|
+
// Check for actual decision entries:
|
|
80
|
+
// - ### heading (subsection per decision)
|
|
81
|
+
// - **Decision marker (inline decision format)
|
|
82
|
+
const hasDecisionEntry = /^### /m.test(sectionContent) || /^\*\*Decision/m.test(sectionContent);
|
|
83
|
+
|
|
84
|
+
if (!hasDecisionEntry) {
|
|
85
|
+
missing.push("At least one architectural decision entry");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
valid: missing.length === 0,
|
|
92
|
+
missing,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ─── Per-Turn Gate Section Validators ─────────────────────────────────────
|
|
97
|
+
//
|
|
98
|
+
// Each validator checks that the artifact written by a turn contains a
|
|
99
|
+
// heading for every gate owned by that turn. The registry is the source
|
|
100
|
+
// of truth for which sections must exist; adding a new gate automatically
|
|
101
|
+
// flows through via `getGatesForTurn(turn)`.
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Escape a string so it can be embedded safely inside a regular expression.
|
|
105
|
+
*/
|
|
106
|
+
function escapeRegExp(value: string): string {
|
|
107
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Validate that an artifact contains an `## H2` heading for every gate the
|
|
112
|
+
* named turn owns. Returns the list of missing gate section headers.
|
|
113
|
+
*
|
|
114
|
+
* Soft rule: a section counts as "present" if it is declared (H2 heading
|
|
115
|
+
* exists) — empty-body sections are allowed and handled by the tool
|
|
116
|
+
* handler, which will record such gates as `omitted`.
|
|
117
|
+
*/
|
|
118
|
+
export function validateGateSections(
|
|
119
|
+
content: string,
|
|
120
|
+
turn: OwnerTurn,
|
|
121
|
+
): ValidationResult {
|
|
122
|
+
const missing: string[] = [];
|
|
123
|
+
for (const def of getGatesForTurn(turn)) {
|
|
124
|
+
const pattern = new RegExp(`^##\\s+${escapeRegExp(def.promptSection)}\\b`, "m");
|
|
125
|
+
if (!pattern.test(content)) {
|
|
126
|
+
missing.push(`${def.id} (## ${def.promptSection})`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return { valid: missing.length === 0, missing };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Validate a SUMMARY.md produced by the complete-slice turn. Requires
|
|
134
|
+
* an H2 heading for every gate owned by complete-slice (e.g. Q8 →
|
|
135
|
+
* "## Operational Readiness"). Intended for use in the tool handler's
|
|
136
|
+
* pre-write checks or in the post-unit validation sweep.
|
|
137
|
+
*/
|
|
138
|
+
export function validateSliceSummaryOutput(content: string): ValidationResult {
|
|
139
|
+
return validateGateSections(content, "complete-slice");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Validate a task SUMMARY.md produced by the execute-task turn. Only
|
|
144
|
+
* flags gates that are still pending for the task; skips the check
|
|
145
|
+
* when no rows are seeded (simple task).
|
|
146
|
+
*/
|
|
147
|
+
export function validateTaskSummaryOutput(content: string): ValidationResult {
|
|
148
|
+
return validateGateSections(content, "execute-task");
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Validate a VALIDATION.md produced by the validate-milestone turn.
|
|
153
|
+
* Requires an H2 heading for every MV gate declared in the registry.
|
|
154
|
+
*/
|
|
155
|
+
export function validateMilestoneValidationOutput(content: string): ValidationResult {
|
|
156
|
+
return validateGateSections(content, "validate-milestone");
|
|
157
|
+
}
|
|
@@ -16,6 +16,8 @@ All relevant context has been preloaded below — the slice plan, all task summa
|
|
|
16
16
|
|
|
17
17
|
{{inlinedContext}}
|
|
18
18
|
|
|
19
|
+
{{gatesToClose}}
|
|
20
|
+
|
|
19
21
|
**Match effort to complexity.** A simple slice with 1-2 tasks needs a brief summary and lightweight verification. A complex slice with 5 tasks across multiple subsystems needs thorough verification and a detailed summary. Scale the work below accordingly.
|
|
20
22
|
|
|
21
23
|
Then:
|
|
@@ -23,7 +25,7 @@ Then:
|
|
|
23
25
|
2. {{skillActivation}}
|
|
24
26
|
3. Run all slice-level verification checks defined in the slice plan. All must pass before marking the slice done. If any fail, fix them first. Task artifacts use a **flat file layout** directly inside `tasks/` (for example `T01-SUMMARY.md`, `T02-SUMMARY.md`) rather than per-task subdirectories. If you need to count or re-read task summaries during verification, use `find .gsd/milestones/{{milestoneId}}/slices/{{sliceId}}/tasks -name "*-SUMMARY.md"` or `ls .gsd/milestones/{{milestoneId}}/slices/{{sliceId}}/tasks/*-SUMMARY.md`. Never use `tasks/*/SUMMARY.md` — that glob expects subdirectories that do not exist.
|
|
25
27
|
4. If the slice plan includes observability/diagnostic surfaces, confirm they work. Skip this for simple slices that don't have observability sections.
|
|
26
|
-
5.
|
|
28
|
+
5. Address every gate listed in the **Gates to Close** section above — each gate maps to a specific slice-summary section the handler inspects (for example, Q8 maps to **Operational Readiness**: health signal, failure signal, recovery procedure, and monitoring gaps). Leaving a section empty records the gate as `omitted`.
|
|
27
29
|
6. If this slice produced evidence that a requirement changed status (Active → Validated, Active → Deferred, etc.), call `gsd_requirement_update` with the requirement ID, updated `status`, and `validation` evidence. Do NOT write `.gsd/REQUIREMENTS.md` directly — the engine renders it from the database.
|
|
28
30
|
7. Prepare the slice completion content you will pass to `gsd_complete_slice` using the camelCase fields `milestoneId`, `sliceId`, `sliceTitle`, `oneLiner`, `narrative`, `verification`, and `uatContent`. Do **not** manually write `{{sliceSummaryPath}}`. Do **not** manually write `{{sliceUatPath}}` — the DB-backed tool is the canonical write path for both artifacts.
|
|
29
31
|
8. Draft the UAT content you will pass as `uatContent` — a concrete UAT script with real test cases derived from the slice plan and task summaries. Include preconditions, numbered steps with expected outcomes, and edge cases. This must NOT be a placeholder or generic template — tailor every test case to what this slice actually built.
|
|
@@ -49,31 +49,132 @@ This happens ONCE, before the first round. The goal: your first questions should
|
|
|
49
49
|
|
|
50
50
|
For subsequent rounds, continue investigating between rounds — check docs, search, or scout as needed to make each round's questions smarter. But the first-round investigation is mandatory and explicit. Distribute searches across turns rather than clustering them in one turn.
|
|
51
51
|
|
|
52
|
-
## Question Rounds
|
|
52
|
+
## Layered Question Rounds
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
Questions are organized into four layers. Each layer targets a specific depth dimension. At each layer: ask 1-3 open questions per round, investigate between rounds as needed, and gate before advancing.
|
|
55
55
|
|
|
56
|
-
**
|
|
56
|
+
**Default to open questions.** Use `ask_user_questions` only when there are 2-3 genuinely distinct paths with clear tradeoffs (e.g., "REST vs GraphQL" or "Postgres vs SQLite"). For nuanced design questions, ask in plain text and let the user explain.
|
|
57
57
|
|
|
58
|
-
**If `{{structuredQuestionsAvailable}}` is `
|
|
58
|
+
**If `{{structuredQuestionsAvailable}}` is `true`:** use `ask_user_questions` for binary/ternary choices. Keep option labels short (3-5 words). Always include a freeform "Other / let me explain" option. When the user picks that option or writes a long freeform answer, switch to plain text follow-up for that thread before resuming structured questions. **IMPORTANT: Call `ask_user_questions` exactly once per turn. Never make multiple calls with the same or overlapping questions — wait for the user's response before asking the next round.**
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
**If `{{structuredQuestionsAvailable}}` is `false`:** ask questions in plain text. Keep each round to 1-3 focused questions. Wait for answers before asking the next round.
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
**Incremental persistence:** After every 2 question rounds (across any layer), silently save a `{{milestoneId}}-CONTEXT-DRAFT.md` using `gsd_summary_save` with `artifact_type: "CONTEXT-DRAFT"` and `milestone_id: "{{milestoneId}}"`. This protects confirmed work against session crashes. Do NOT mention this save to the user.
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
### Identify Work Type
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
Before starting Layer 1, identify the primary work type and state it:
|
|
67
|
+
|
|
68
|
+
"Based on your description and the codebase, this is primarily **[work type]** work."
|
|
69
|
+
|
|
70
|
+
Work types include: API/backend, UI/frontend, CLI/developer tool, data pipeline, ML/AI, infrastructure/platform, refactoring/migration, or a combination. The user can correct this. The classification shapes which questions deserve deep exploration at each layer.
|
|
71
|
+
|
|
72
|
+
### Layer 1 — Scope
|
|
73
|
+
|
|
74
|
+
Resolve what's in and what's out. Ask about:
|
|
75
|
+
- Feature boundaries — what exactly ships in this milestone vs later
|
|
76
|
+
- Ambiguities in the user's description — anything you're unsure about, ask
|
|
77
|
+
- Dependencies — what does this work depend on, what depends on it
|
|
78
|
+
- Priority — if scope needs trimming, what matters most
|
|
79
|
+
|
|
80
|
+
Adapt depth to work type:
|
|
81
|
+
- **CLI work:** Focus on user mental model, command grammar, what existing commands do
|
|
82
|
+
- **Refactoring:** Focus on what changes vs what must stay identical
|
|
83
|
+
|
|
84
|
+
**Depth-matching:** Simple, well-defined scope may need 1 round. Ambiguous or large scope may need 3-4 rounds. Don't pad rounds to hit a number.
|
|
85
|
+
|
|
86
|
+
#### Layer 1 Gate
|
|
87
|
+
|
|
88
|
+
Summarize scope decisions in the user's own terminology:
|
|
89
|
+
- What's included, what's excluded, what's deferred
|
|
90
|
+
- Key boundaries and constraints
|
|
91
|
+
|
|
92
|
+
Then ask: **"Does this capture the scope? Adjust anything before we move on."**
|
|
93
|
+
|
|
94
|
+
If the user adjusts, reflect the updated understanding and ask again. Do not advance until the user explicitly confirms. If the user says "looks good, let's move faster" at any gate, respect that and advance.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
### Layer 2 — Architecture
|
|
99
|
+
|
|
100
|
+
Resolve how it's built. Ask about:
|
|
101
|
+
- Per-slice technical decisions — what approach for each major piece
|
|
102
|
+
- Inter-slice contracts — how do the pieces connect
|
|
103
|
+
- Library/framework choices — with evidence from investigation, not assumptions
|
|
104
|
+
- Integration with existing code — what patterns to follow, what to change
|
|
105
|
+
|
|
106
|
+
Adapt depth to work type:
|
|
107
|
+
- **API work:** Contracts, versioning, backwards compatibility, auth boundaries
|
|
108
|
+
- **UI work:** Component boundaries, state management, data flow
|
|
109
|
+
- **Infrastructure:** Deployment topology, failure domains, rollback
|
|
110
|
+
|
|
111
|
+
Between rounds, use your available web search tools to research technologies from the Codebase Brief. Search for "[technology] [version] best practices [current year]" and "[technology] [version] known issues". Present findings alongside your questions.
|
|
112
|
+
|
|
113
|
+
#### Layer 2 Gate
|
|
114
|
+
|
|
115
|
+
Summarize architecture decisions, each with:
|
|
116
|
+
- The decision and rationale
|
|
117
|
+
- Evidence source (codebase patterns, library docs, web research)
|
|
118
|
+
- Alternatives considered
|
|
119
|
+
|
|
120
|
+
Then ask: **"Does this capture the architecture? Adjust anything before we move on."**
|
|
121
|
+
|
|
122
|
+
Same gate rules: reflect adjustments, wait for confirmation.
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
### Layer 3 — Error States
|
|
127
|
+
|
|
128
|
+
Resolve what happens when things fail. Present this layer with an option:
|
|
129
|
+
|
|
130
|
+
"We can go deep on error handling and failure modes, or I can apply sensible defaults based on the architecture decisions above. Which do you prefer?"
|
|
131
|
+
|
|
132
|
+
If the user chooses defaults, summarize what the defaults are and gate. If the user chooses to go deep, ask about:
|
|
133
|
+
- Failure modes for each major component
|
|
134
|
+
- Error propagation between layers (API → frontend, service → database)
|
|
135
|
+
- Timeout, retry, and circuit-breaker strategies
|
|
136
|
+
- What the user sees when something fails
|
|
137
|
+
|
|
138
|
+
Adapt depth to work type:
|
|
139
|
+
- **API work:** Rate limiting, timeout cascades, partial failure, status codes
|
|
140
|
+
- **UI work:** Loading states, optimistic updates, offline behavior, error boundaries
|
|
141
|
+
- **Data pipelines:** Data corruption, checkpoint recovery, idempotency
|
|
142
|
+
|
|
143
|
+
#### Layer 3 Gate
|
|
144
|
+
|
|
145
|
+
Summarize error handling strategy. Then ask: **"Does this capture how errors should be handled? Adjust anything before we move on."**
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
### Layer 4 — Quality Bar
|
|
150
|
+
|
|
151
|
+
Resolve what "done" means concretely. Ask about:
|
|
152
|
+
- Per-slice acceptance criteria — specific enough for automated verification
|
|
153
|
+
- Test strategy — what types of tests, what coverage expectations
|
|
154
|
+
- Definition of done — what must be true before the milestone ships
|
|
155
|
+
- Non-functional requirements — performance, accessibility, security if relevant
|
|
156
|
+
|
|
157
|
+
Adapt depth to work type:
|
|
158
|
+
- **CLI work:** Shell compatibility, error message clarity, exit code semantics
|
|
159
|
+
- **Refactoring:** Behavioral equivalence tests, not just code coverage
|
|
160
|
+
- **UI work:** Visual regression criteria, responsive breakpoints
|
|
161
|
+
|
|
162
|
+
#### Layer 4 Gate
|
|
163
|
+
|
|
164
|
+
Summarize quality bar: acceptance criteria, test strategy, definition of done. Then ask: **"Does this capture the quality bar? Adjust anything before we move on to requirements and roadmap?"**
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
### Layer cadence
|
|
169
|
+
|
|
170
|
+
- Do not count the reflection step as a question round. Rounds start at Layer 1 after reflection is confirmed.
|
|
171
|
+
- When all four layer gates have been confirmed (or skipped by the user), move to the Depth Verification step below. Do not ask a separate "ready to wrap up?" gate — the depth verification confirms the full picture.
|
|
71
172
|
|
|
72
173
|
## Questioning Philosophy
|
|
73
174
|
|
|
74
175
|
You are a thinking partner, not an interviewer.
|
|
75
176
|
|
|
76
|
-
**Turn-taking contract (non-bypassable).** Never fabricate, simulate, or role-play user responses. Never generate fake transcript markers like `[User]`, `[Human]`, or `User:` to invent input. Ask one question round (1-3 questions) per turn, then stop and wait for the user's actual response before continuing. If you use `ask_user_questions`, call it at most once per turn and treat its returned response as the only valid structured user input for that round.
|
|
177
|
+
**Turn-taking contract (non-bypassable).** Never fabricate, simulate, or role-play user responses. Never generate fake transcript markers like `[User]`, `[Human]`, or `User:` to invent input. Prior conversation context may be provided to you inside `<conversation_history>` with `<user_message>` / `<assistant_message>` XML tags — treat those as read-only context and never emit those tags in your response. Ask one question round (1-3 questions) per turn, then stop and wait for the user's actual response before continuing. If you use `ask_user_questions`, call it at most once per turn and treat its returned response as the only valid structured user input for that round.
|
|
77
178
|
|
|
78
179
|
**Start open, follow energy.** Let the user's enthusiasm guide where you dig deeper. If they light up about a particular aspect, explore it. If they're vague about something, that's where you probe.
|
|
79
180
|
|
|
@@ -225,6 +326,14 @@ Once the user is satisfied, in a single pass:
|
|
|
225
326
|
**Depth-Preservation Guidance for context.md:**
|
|
226
327
|
When writing context.md, preserve the user's exact terminology, emphasis, and specific framing from the discussion. Do not paraphrase user nuance into generic summaries. If the user said "craft feel," write "craft feel" — not "high-quality user experience." If they emphasized a specific constraint or negative requirement, carry that emphasis through verbatim. The context file is downstream agents' only window into this conversation — flattening specifics into generics loses the signal that shaped every decision.
|
|
227
328
|
|
|
329
|
+
**Structured sections from discussion layers:**
|
|
330
|
+
When writing CONTEXT.md, include structured sections that map to the discussion layers:
|
|
331
|
+
- **Scope** — what's in, what's out, what's deferred (from Layer 1 gate summary)
|
|
332
|
+
- **Architectural Decisions** — each with rationale, evidence source, alternatives considered (from Layer 2 gate summary)
|
|
333
|
+
- **Error Handling Strategy** — failure modes, propagation, user-facing error behavior (from Layer 3 gate summary)
|
|
334
|
+
- **Acceptance Criteria** — per-slice criteria specific enough for the planner to use directly (from Layer 4 gate summary)
|
|
335
|
+
These sections are in addition to whatever other context the discussion surfaced.
|
|
336
|
+
|
|
228
337
|
4. Write `{{contextPath}}` — use the **Context** output template below. Preserve key risks, unknowns, existing codebase constraints, integration points, and relevant requirements surfaced during discussion.
|
|
229
338
|
5. Call `gsd_plan_milestone` to create the roadmap. Decompose into demoable vertical slices with risk, depends, demo sentences, proof strategy, verification classes, milestone definition of done, requirement coverage, and a boundary map. If the milestone crosses multiple runtime boundaries, include an explicit final integration slice that proves the assembled system works end-to-end in a real environment. Use the **Roadmap** output template below to structure the tool call parameters.
|
|
230
339
|
6. For each architectural or pattern decision made during discussion, call `gsd_decision_save` — the tool auto-assigns IDs and regenerates `.gsd/DECISIONS.md` automatically.
|