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
|
@@ -82,3 +82,19 @@ test("shortcut-defs: formats shortcut pair using platform symbols", () => {
|
|
|
82
82
|
assert.equal(pair, "Ctrl+Alt+N / Ctrl+Shift+N");
|
|
83
83
|
}
|
|
84
84
|
});
|
|
85
|
+
|
|
86
|
+
test("shortcut-defs: parallel shortcut omits fallback (hasFallback: false)", () => {
|
|
87
|
+
const pair = formattedShortcutPair("parallel");
|
|
88
|
+
if (process.platform === "darwin") {
|
|
89
|
+
assert.equal(pair, "⌃⌥P", "parallel should only show primary combo");
|
|
90
|
+
} else {
|
|
91
|
+
assert.equal(pair, "Ctrl+Alt+P", "parallel should only show primary combo");
|
|
92
|
+
}
|
|
93
|
+
// Verify it does NOT contain the fallback separator
|
|
94
|
+
assert.ok(!pair.includes("/"), "parallel pair should not contain fallback separator");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("shortcut-defs: dashboard shortcut includes fallback (hasFallback: true)", () => {
|
|
98
|
+
const pair = formattedShortcutPair("dashboard");
|
|
99
|
+
assert.ok(pair.includes("/"), "dashboard pair should contain fallback separator");
|
|
100
|
+
});
|
|
@@ -186,4 +186,31 @@ describe("evaluating-gates phase", () => {
|
|
|
186
186
|
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q5", scope: "task", taskId: "T01" });
|
|
187
187
|
assert.equal(getPendingSliceGateCount("M001", "S01"), 1);
|
|
188
188
|
});
|
|
189
|
+
|
|
190
|
+
test("Q8 (owned by complete-slice) does not block evaluating-gates phase", async () => {
|
|
191
|
+
// Regression: Q8 is stored with scope:"slice" but owned by the
|
|
192
|
+
// complete-slice turn. Before the gate registry landed, deriveState
|
|
193
|
+
// counted Q8 as a blocker for evaluating-gates while the gate-evaluate
|
|
194
|
+
// prompt silently dropped Q8 — an unrecoverable stall. After the
|
|
195
|
+
// registry change, deriveState filters by owner turn, so Q8 never
|
|
196
|
+
// blocks evaluating-gates.
|
|
197
|
+
planSlice(tmpDir);
|
|
198
|
+
await renderPlanFromDb(tmpDir, "M001", "S01");
|
|
199
|
+
|
|
200
|
+
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", scope: "slice" });
|
|
201
|
+
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q4", scope: "slice" });
|
|
202
|
+
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q8", scope: "slice" });
|
|
203
|
+
|
|
204
|
+
saveGateResult({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", verdict: "pass", rationale: "OK", findings: "" });
|
|
205
|
+
saveGateResult({ milestoneId: "M001", sliceId: "S01", gateId: "Q4", verdict: "omitted", rationale: "N/A", findings: "" });
|
|
206
|
+
// Q8 deliberately left pending — it's complete-slice's problem.
|
|
207
|
+
|
|
208
|
+
invalidateStateCache();
|
|
209
|
+
const state = await deriveState(tmpDir);
|
|
210
|
+
assert.equal(
|
|
211
|
+
state.phase,
|
|
212
|
+
"executing",
|
|
213
|
+
`pending Q8 must not stall evaluating-gates — got phase=${state.phase}`,
|
|
214
|
+
);
|
|
215
|
+
});
|
|
189
216
|
});
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gate registry tests — enforce that every declared GateId has a registry
|
|
3
|
+
* entry, that every owner-turn bucket is non-empty, and that coverage
|
|
4
|
+
* assertions fail loudly instead of silently skipping unknown gates.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, test } from "node:test";
|
|
8
|
+
import assert from "node:assert/strict";
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
GATE_REGISTRY,
|
|
12
|
+
assertGateCoverage,
|
|
13
|
+
getGateDefinition,
|
|
14
|
+
getGateIdsForTurn,
|
|
15
|
+
getGatesForTurn,
|
|
16
|
+
getOwnerTurn,
|
|
17
|
+
type OwnerTurn,
|
|
18
|
+
} from "../gate-registry.ts";
|
|
19
|
+
import type { GateId } from "../types.ts";
|
|
20
|
+
|
|
21
|
+
/** Authoritative list of GateIds as declared in types.ts. */
|
|
22
|
+
const ALL_GATE_IDS: readonly GateId[] = [
|
|
23
|
+
"Q3", "Q4", "Q5", "Q6", "Q7", "Q8",
|
|
24
|
+
"MV01", "MV02", "MV03", "MV04",
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
const ALL_OWNER_TURNS: readonly OwnerTurn[] = [
|
|
28
|
+
"gate-evaluate",
|
|
29
|
+
"execute-task",
|
|
30
|
+
"complete-slice",
|
|
31
|
+
"validate-milestone",
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
describe("gate-registry", () => {
|
|
35
|
+
test("every declared GateId has a registry entry", () => {
|
|
36
|
+
for (const id of ALL_GATE_IDS) {
|
|
37
|
+
const def = GATE_REGISTRY[id];
|
|
38
|
+
assert.ok(def, `missing registry entry for gate ${id}`);
|
|
39
|
+
assert.equal(def.id, id);
|
|
40
|
+
assert.ok(def.question.length > 0, `${id} missing question`);
|
|
41
|
+
assert.ok(def.guidance.length > 0, `${id} missing guidance`);
|
|
42
|
+
assert.ok(def.promptSection.length > 0, `${id} missing promptSection`);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("registry contains no extra gate entries", () => {
|
|
47
|
+
const registryIds = new Set(Object.keys(GATE_REGISTRY));
|
|
48
|
+
const declaredIds = new Set<string>(ALL_GATE_IDS);
|
|
49
|
+
for (const id of registryIds) {
|
|
50
|
+
assert.ok(declaredIds.has(id), `registry has unknown gate ${id}`);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("every owner turn owns at least one gate", () => {
|
|
55
|
+
for (const turn of ALL_OWNER_TURNS) {
|
|
56
|
+
const gates = getGatesForTurn(turn);
|
|
57
|
+
assert.ok(
|
|
58
|
+
gates.length > 0,
|
|
59
|
+
`owner turn "${turn}" has no gates — likely a registry mistake`,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("owner turn buckets are disjoint", () => {
|
|
65
|
+
const seen = new Set<string>();
|
|
66
|
+
for (const turn of ALL_OWNER_TURNS) {
|
|
67
|
+
for (const def of getGatesForTurn(turn)) {
|
|
68
|
+
assert.ok(!seen.has(def.id), `gate ${def.id} claimed by two turns`);
|
|
69
|
+
seen.add(def.id);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Every gate should appear in exactly one bucket.
|
|
73
|
+
assert.equal(seen.size, ALL_GATE_IDS.length);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("getOwnerTurn round-trips against GATE_REGISTRY", () => {
|
|
77
|
+
for (const id of ALL_GATE_IDS) {
|
|
78
|
+
const turn = getOwnerTurn(id);
|
|
79
|
+
const idsForTurn = getGateIdsForTurn(turn);
|
|
80
|
+
assert.ok(idsForTurn.has(id), `${id} not in ${turn} bucket`);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("getGateDefinition returns undefined for unknown ids", () => {
|
|
85
|
+
assert.equal(getGateDefinition("Q99"), undefined);
|
|
86
|
+
assert.equal(getGateDefinition("not-a-gate"), undefined);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe("assertGateCoverage", () => {
|
|
91
|
+
test("throws when a row is owned by a different turn", () => {
|
|
92
|
+
// Q8 is owned by complete-slice, not gate-evaluate — this used to be
|
|
93
|
+
// silently dropped by the old `if (!meta) continue;` filter, causing
|
|
94
|
+
// the evaluating-gates phase to stall.
|
|
95
|
+
assert.throws(
|
|
96
|
+
() => assertGateCoverage([{ gate_id: "Q8" }], "gate-evaluate"),
|
|
97
|
+
(err: Error) =>
|
|
98
|
+
err.message.includes("Q8") && err.message.includes("gate-evaluate"),
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("throws when a row has an unknown gate id", () => {
|
|
103
|
+
assert.throws(
|
|
104
|
+
() => assertGateCoverage([{ gate_id: "Q999" as GateId }], "gate-evaluate", { requireAll: false }),
|
|
105
|
+
(err: Error) => err.message.includes("Q999"),
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("throws when requireAll is true and an owned gate is missing", () => {
|
|
110
|
+
// gate-evaluate owns Q3 and Q4. Passing only Q3 should fail.
|
|
111
|
+
assert.throws(
|
|
112
|
+
() => assertGateCoverage([{ gate_id: "Q3" }], "gate-evaluate", { requireAll: true }),
|
|
113
|
+
(err: Error) => err.message.includes("Q4"),
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("passes when requireAll is false and only a subset is pending", () => {
|
|
118
|
+
// execute-task owns Q5/Q6/Q7, but a task with no external dependencies
|
|
119
|
+
// may only have Q7 seeded. That's still valid coverage.
|
|
120
|
+
assert.doesNotThrow(() =>
|
|
121
|
+
assertGateCoverage([{ gate_id: "Q7" }], "execute-task", { requireAll: false }),
|
|
122
|
+
);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("passes when requireAll is true and every owned gate is pending", () => {
|
|
126
|
+
assert.doesNotThrow(() =>
|
|
127
|
+
assertGateCoverage(
|
|
128
|
+
[{ gate_id: "Q3" }, { gate_id: "Q4" }],
|
|
129
|
+
"gate-evaluate",
|
|
130
|
+
{ requireAll: true },
|
|
131
|
+
),
|
|
132
|
+
);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("empty pending list passes when requireAll is false", () => {
|
|
136
|
+
assert.doesNotThrow(() =>
|
|
137
|
+
assertGateCoverage([], "complete-slice", { requireAll: false }),
|
|
138
|
+
);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
getRequirementById,
|
|
16
16
|
getActiveDecisions,
|
|
17
17
|
getActiveRequirements,
|
|
18
|
+
getTask,
|
|
18
19
|
transaction,
|
|
19
20
|
_getAdapter,
|
|
20
21
|
_resetProvider,
|
|
@@ -43,6 +44,16 @@ function cleanup(dbPath: string): void {
|
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
function withPlatform<T>(platform: NodeJS.Platform, fn: () => T): T {
|
|
48
|
+
const original = process.platform;
|
|
49
|
+
Object.defineProperty(process, 'platform', { value: platform });
|
|
50
|
+
try {
|
|
51
|
+
return fn();
|
|
52
|
+
} finally {
|
|
53
|
+
Object.defineProperty(process, 'platform', { value: original });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
46
57
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
47
58
|
// gsd-db tests
|
|
48
59
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -279,6 +290,26 @@ describe('gsd-db', () => {
|
|
|
279
290
|
cleanup(dbPath);
|
|
280
291
|
});
|
|
281
292
|
|
|
293
|
+
test('gsd-db: mmap stays disabled on darwin file-backed DBs', () => {
|
|
294
|
+
const darwinDbPath = tempDbPath();
|
|
295
|
+
withPlatform('darwin', () => {
|
|
296
|
+
openDatabase(darwinDbPath);
|
|
297
|
+
const adapter = _getAdapter()!;
|
|
298
|
+
const mmap = adapter.prepare('PRAGMA mmap_size').get();
|
|
299
|
+
assert.deepStrictEqual(mmap?.['mmap_size'], 0, 'darwin should leave mmap_size disabled');
|
|
300
|
+
cleanup(darwinDbPath);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
const linuxDbPath = tempDbPath();
|
|
304
|
+
withPlatform('linux', () => {
|
|
305
|
+
openDatabase(linuxDbPath);
|
|
306
|
+
const adapter = _getAdapter()!;
|
|
307
|
+
const mmap = adapter.prepare('PRAGMA mmap_size').get();
|
|
308
|
+
assert.deepStrictEqual(mmap?.['mmap_size'], 67108864, 'non-darwin should still enable mmap_size');
|
|
309
|
+
cleanup(linuxDbPath);
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
|
|
282
313
|
test('gsd-db: transaction rollback on error', () => {
|
|
283
314
|
openDatabase(':memory:');
|
|
284
315
|
|
|
@@ -329,6 +360,79 @@ describe('gsd-db', () => {
|
|
|
329
360
|
closeDatabase();
|
|
330
361
|
});
|
|
331
362
|
|
|
363
|
+
test('gsd-db: recreates missing verification evidence dedup index after removing duplicate rows', () => {
|
|
364
|
+
const dbPath = tempDbPath();
|
|
365
|
+
openDatabase(dbPath);
|
|
366
|
+
|
|
367
|
+
let adapter = _getAdapter()!;
|
|
368
|
+
adapter.prepare("INSERT INTO milestones (id, created_at) VALUES (?, '')").run('M001');
|
|
369
|
+
adapter.prepare("INSERT INTO slices (milestone_id, id, created_at) VALUES (?, ?, '')").run('M001', 'S01');
|
|
370
|
+
adapter.prepare("INSERT INTO tasks (milestone_id, slice_id, id) VALUES (?, ?, ?)").run('M001', 'S01', 'T01');
|
|
371
|
+
adapter.exec('DROP INDEX IF EXISTS idx_verification_evidence_dedup');
|
|
372
|
+
|
|
373
|
+
const insertEvidence = adapter.prepare(
|
|
374
|
+
`INSERT INTO verification_evidence (
|
|
375
|
+
task_id, slice_id, milestone_id, command, exit_code, verdict, duration_ms, created_at
|
|
376
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
377
|
+
);
|
|
378
|
+
insertEvidence.run('T01', 'S01', 'M001', 'npm test', 1, 'fail', 125, '2026-04-12T00:00:00.000Z');
|
|
379
|
+
insertEvidence.run('T01', 'S01', 'M001', 'npm test', 1, 'fail', 125, '2026-04-12T00:00:01.000Z');
|
|
380
|
+
insertEvidence.run('T01', 'S01', 'M001', 'npm run lint', 0, 'pass', 90, '2026-04-12T00:00:02.000Z');
|
|
381
|
+
|
|
382
|
+
closeDatabase();
|
|
383
|
+
|
|
384
|
+
assert.equal(openDatabase(dbPath), true, 'openDatabase should repair legacy duplicate evidence rows');
|
|
385
|
+
|
|
386
|
+
adapter = _getAdapter()!;
|
|
387
|
+
const countRow = adapter.prepare(
|
|
388
|
+
`SELECT count(*) as cnt
|
|
389
|
+
FROM verification_evidence
|
|
390
|
+
WHERE task_id = ? AND slice_id = ? AND milestone_id = ? AND command = ? AND verdict = ?`,
|
|
391
|
+
).get('T01', 'S01', 'M001', 'npm test', 'fail');
|
|
392
|
+
assert.equal(countRow?.['cnt'], 1, 'duplicate verification evidence rows should be deduplicated before index creation');
|
|
393
|
+
|
|
394
|
+
const indexRow = adapter.prepare(
|
|
395
|
+
"SELECT name FROM sqlite_master WHERE type = 'index' AND name = 'idx_verification_evidence_dedup'",
|
|
396
|
+
).get();
|
|
397
|
+
assert.equal(indexRow?.['name'], 'idx_verification_evidence_dedup', 'dedup index should be recreated on reopen');
|
|
398
|
+
|
|
399
|
+
cleanup(dbPath);
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
test('gsd-db: rowToTask tolerates legacy comma-separated task arrays', () => {
|
|
403
|
+
openDatabase(':memory:');
|
|
404
|
+
|
|
405
|
+
const adapter = _getAdapter()!;
|
|
406
|
+
adapter.prepare("INSERT INTO milestones (id, created_at) VALUES (?, '')").run('M001');
|
|
407
|
+
adapter.prepare("INSERT INTO slices (milestone_id, id, created_at) VALUES (?, ?, '')").run('M001', 'S01');
|
|
408
|
+
adapter.prepare(
|
|
409
|
+
`INSERT INTO tasks (
|
|
410
|
+
milestone_id, slice_id, id, key_files, key_decisions, files, inputs, expected_output
|
|
411
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
412
|
+
).run(
|
|
413
|
+
'M001',
|
|
414
|
+
'S01',
|
|
415
|
+
'T01',
|
|
416
|
+
'[]',
|
|
417
|
+
'[]',
|
|
418
|
+
'tests/test_verify.py, config.yaml, configs/roster_2026-05-11.yaml',
|
|
419
|
+
'tests/test_verify.py',
|
|
420
|
+
'reports/summary.md, artifacts/output.json',
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
const task = getTask('M001', 'S01', 'T01');
|
|
424
|
+
assert.ok(task, 'task should load successfully from DB');
|
|
425
|
+
assert.deepEqual(task?.files, [
|
|
426
|
+
'tests/test_verify.py',
|
|
427
|
+
'config.yaml',
|
|
428
|
+
'configs/roster_2026-05-11.yaml',
|
|
429
|
+
]);
|
|
430
|
+
assert.deepEqual(task?.inputs, ['tests/test_verify.py']);
|
|
431
|
+
assert.deepEqual(task?.expected_output, ['reports/summary.md', 'artifacts/output.json']);
|
|
432
|
+
|
|
433
|
+
closeDatabase();
|
|
434
|
+
});
|
|
435
|
+
|
|
332
436
|
test('gsd-db: query wrappers return null/empty when DB unavailable', () => {
|
|
333
437
|
// Ensure DB is closed
|
|
334
438
|
closeDatabase();
|
|
@@ -347,15 +451,13 @@ describe('gsd-db', () => {
|
|
|
347
451
|
assert.deepStrictEqual(ar, [], 'getActiveRequirements returns [] when DB closed');
|
|
348
452
|
});
|
|
349
453
|
|
|
350
|
-
test('gsd-db: wasDbOpenAttempted
|
|
351
|
-
|
|
352
|
-
// (previous tests in this suite already called openDatabase, so the flag is set)
|
|
454
|
+
test('gsd-db: closeDatabase resets wasDbOpenAttempted after an intentional close', () => {
|
|
455
|
+
openDatabase(':memory:');
|
|
353
456
|
assert.ok(wasDbOpenAttempted(), 'wasDbOpenAttempted should be true after openDatabase was called');
|
|
354
457
|
|
|
355
|
-
// Verify the flag persists even after closeDatabase
|
|
356
458
|
closeDatabase();
|
|
357
459
|
assert.ok(!isDbAvailable(), 'DB should not be available after close');
|
|
358
|
-
assert.ok(wasDbOpenAttempted(), 'wasDbOpenAttempted should
|
|
460
|
+
assert.ok(!wasDbOpenAttempted(), 'wasDbOpenAttempted should reset after closeDatabase');
|
|
359
461
|
});
|
|
360
462
|
|
|
361
463
|
// ─── Final Report ──────────────────────────────────────────────────────────
|
|
@@ -248,23 +248,25 @@ describe('git-service', async () => {
|
|
|
248
248
|
|
|
249
249
|
assert.deepStrictEqual(
|
|
250
250
|
RUNTIME_EXCLUSION_PATHS.length,
|
|
251
|
-
|
|
252
|
-
"exactly
|
|
251
|
+
15,
|
|
252
|
+
"exactly 15 runtime exclusion paths"
|
|
253
253
|
);
|
|
254
254
|
|
|
255
255
|
const expectedPaths = [
|
|
256
256
|
".gsd/activity/",
|
|
257
|
+
".gsd/forensics/",
|
|
257
258
|
".gsd/runtime/",
|
|
258
259
|
".gsd/worktrees/",
|
|
260
|
+
".gsd/parallel/",
|
|
259
261
|
".gsd/auto.lock",
|
|
260
262
|
".gsd/metrics.json",
|
|
261
|
-
".gsd/completed-units
|
|
263
|
+
".gsd/completed-units*.json",
|
|
264
|
+
".gsd/state-manifest.json",
|
|
262
265
|
".gsd/STATE.md",
|
|
263
|
-
".gsd/gsd.db",
|
|
264
|
-
".gsd/gsd.db-shm",
|
|
265
|
-
".gsd/gsd.db-wal",
|
|
266
|
+
".gsd/gsd.db*",
|
|
266
267
|
".gsd/journal/",
|
|
267
268
|
".gsd/doctor-history.jsonl",
|
|
269
|
+
".gsd/event-log.jsonl",
|
|
268
270
|
".gsd/DISCUSSION-MANIFEST.json",
|
|
269
271
|
];
|
|
270
272
|
|
|
@@ -427,3 +427,66 @@ test("formatDoctorFindings shows findings with appropriate icons", () => {
|
|
|
427
427
|
assert.ok(output.includes("1 warning"));
|
|
428
428
|
assert.ok(output.includes("1 fixed"));
|
|
429
429
|
});
|
|
430
|
+
|
|
431
|
+
// ─── Regression #3891 — alibaba-coding-plan missing from PROVIDER_REGISTRY ───────
|
|
432
|
+
//
|
|
433
|
+
// Before this fix, `alibaba-coding-plan` was not in PROVIDER_REGISTRY, causing
|
|
434
|
+
// `/gsd keys add alibaba-coding-plan` to silently fail (provider not found).
|
|
435
|
+
// alibaba-dashscope is the new standalone provider added in the same PR.
|
|
436
|
+
|
|
437
|
+
test("regression #3891 — alibaba-coding-plan is in PROVIDER_REGISTRY", () => {
|
|
438
|
+
const provider = findProvider("alibaba-coding-plan");
|
|
439
|
+
assert.ok(provider, "alibaba-coding-plan must be in PROVIDER_REGISTRY for /gsd keys add to work");
|
|
440
|
+
assert.equal(provider.id, "alibaba-coding-plan");
|
|
441
|
+
assert.equal(provider.category, "llm");
|
|
442
|
+
assert.equal(provider.envVar, "ALIBABA_API_KEY");
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
test("alibaba-dashscope is in PROVIDER_REGISTRY", () => {
|
|
446
|
+
const provider = findProvider("alibaba-dashscope");
|
|
447
|
+
assert.ok(provider, "alibaba-dashscope must be in PROVIDER_REGISTRY for /gsd keys add to work");
|
|
448
|
+
assert.equal(provider.id, "alibaba-dashscope");
|
|
449
|
+
assert.equal(provider.category, "llm");
|
|
450
|
+
assert.equal(provider.envVar, "DASHSCOPE_API_KEY");
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
test("alibaba-coding-plan and alibaba-dashscope are separate providers (different env vars)", () => {
|
|
454
|
+
const codingPlan = findProvider("alibaba-coding-plan");
|
|
455
|
+
const dashscope = findProvider("alibaba-dashscope");
|
|
456
|
+
assert.ok(codingPlan, "alibaba-coding-plan must exist");
|
|
457
|
+
assert.ok(dashscope, "alibaba-dashscope must exist");
|
|
458
|
+
assert.notEqual(
|
|
459
|
+
codingPlan.envVar,
|
|
460
|
+
dashscope.envVar,
|
|
461
|
+
"alibaba-coding-plan and alibaba-dashscope must use different env vars",
|
|
462
|
+
);
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
test("getAllKeyStatuses includes alibaba-coding-plan", () => {
|
|
466
|
+
const auth = makeAuth();
|
|
467
|
+
const statuses = getAllKeyStatuses(auth);
|
|
468
|
+
const found = statuses.find((s) => s.provider.id === "alibaba-coding-plan");
|
|
469
|
+
assert.ok(found, "getAllKeyStatuses must include alibaba-coding-plan");
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
test("getAllKeyStatuses includes alibaba-dashscope", () => {
|
|
473
|
+
const auth = makeAuth();
|
|
474
|
+
const statuses = getAllKeyStatuses(auth);
|
|
475
|
+
const found = statuses.find((s) => s.provider.id === "alibaba-dashscope");
|
|
476
|
+
assert.ok(found, "getAllKeyStatuses must include alibaba-dashscope");
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
test("getAllKeyStatuses detects DASHSCOPE_API_KEY for alibaba-dashscope (failure path: missing key shows not configured)", () => {
|
|
480
|
+
const saved = process.env.DASHSCOPE_API_KEY;
|
|
481
|
+
delete process.env.DASHSCOPE_API_KEY;
|
|
482
|
+
try {
|
|
483
|
+
const auth = makeAuth();
|
|
484
|
+
const statuses = getAllKeyStatuses(auth);
|
|
485
|
+
const found = statuses.find((s) => s.provider.id === "alibaba-dashscope");
|
|
486
|
+
assert.ok(found);
|
|
487
|
+
assert.equal(found.configured, false);
|
|
488
|
+
assert.equal(found.source, "none");
|
|
489
|
+
} finally {
|
|
490
|
+
if (saved !== undefined) process.env.DASHSCOPE_API_KEY = saved;
|
|
491
|
+
}
|
|
492
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression tests for memory pressure monitoring (#3331) and
|
|
3
|
+
* stuck detection persistence (#3704) in auto/loop.ts.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, test } from "node:test";
|
|
7
|
+
import assert from "node:assert/strict";
|
|
8
|
+
import { readFileSync } from "node:fs";
|
|
9
|
+
import { join, dirname } from "node:path";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
11
|
+
|
|
12
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const loopSource = readFileSync(join(__dirname, "..", "auto", "loop.ts"), "utf-8");
|
|
14
|
+
|
|
15
|
+
describe("memory pressure monitoring (#3331)", () => {
|
|
16
|
+
test("checkMemoryPressure function exists", () => {
|
|
17
|
+
assert.match(loopSource, /function checkMemoryPressure/);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("MEMORY_PRESSURE_THRESHOLD constant is defined", () => {
|
|
21
|
+
assert.match(loopSource, /MEMORY_PRESSURE_THRESHOLD\s*=\s*0\.\d+/);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("memory check runs every MEMORY_CHECK_INTERVAL iterations", () => {
|
|
25
|
+
assert.match(loopSource, /iteration\s*%\s*MEMORY_CHECK_INTERVAL\s*===\s*0/);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("memory pressure triggers graceful stopAuto", () => {
|
|
29
|
+
assert.match(loopSource, /mem\.pressured/);
|
|
30
|
+
assert.match(loopSource, /Stopping gracefully to prevent OOM/);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe("stuck detection persistence (#3704)", () => {
|
|
35
|
+
test("loadStuckState function exists", () => {
|
|
36
|
+
assert.match(loopSource, /function loadStuckState/);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("saveStuckState function exists", () => {
|
|
40
|
+
assert.match(loopSource, /function saveStuckState/);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("loopState initialized from persisted state", () => {
|
|
44
|
+
assert.match(loopSource, /loadStuckState\(s\.basePath\)/);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("stuck state saved after each iteration", () => {
|
|
48
|
+
assert.match(loopSource, /saveStuckState\(s\.basePath,\s*loopState\)/);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("stuck state file path uses runtime directory", () => {
|
|
52
|
+
assert.match(loopSource, /stuck-state\.json/);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
|
|
7
|
+
import { verifyExpectedArtifact } from "../auto-recovery.ts";
|
|
8
|
+
|
|
9
|
+
function createFixtureBase(): string {
|
|
10
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-plan-milestone-artifact-"));
|
|
11
|
+
mkdirSync(join(base, ".gsd", "milestones"), { recursive: true });
|
|
12
|
+
return base;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function writeRoadmap(base: string, milestoneId: string, content: string): void {
|
|
16
|
+
const milestoneDir = join(base, ".gsd", "milestones", milestoneId);
|
|
17
|
+
mkdirSync(milestoneDir, { recursive: true });
|
|
18
|
+
writeFileSync(join(milestoneDir, `${milestoneId}-ROADMAP.md`), content, "utf-8");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
test("#3405: plan-milestone roadmap stub does not count as a verified artifact", () => {
|
|
22
|
+
const base = createFixtureBase();
|
|
23
|
+
try {
|
|
24
|
+
writeRoadmap(base, "M001", [
|
|
25
|
+
"# M001: Placeholder",
|
|
26
|
+
"",
|
|
27
|
+
"**Vision:** Stub only.",
|
|
28
|
+
"",
|
|
29
|
+
"## Slices",
|
|
30
|
+
"",
|
|
31
|
+
"_TBD_",
|
|
32
|
+
"",
|
|
33
|
+
].join("\n"));
|
|
34
|
+
|
|
35
|
+
const result = verifyExpectedArtifact("plan-milestone", "M001", base);
|
|
36
|
+
assert.equal(result, false, "zero-slice roadmap stubs must fail verification");
|
|
37
|
+
} finally {
|
|
38
|
+
rmSync(base, { recursive: true, force: true });
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("#3405: plan-milestone roadmap with real slices still passes artifact verification", () => {
|
|
43
|
+
const base = createFixtureBase();
|
|
44
|
+
try {
|
|
45
|
+
writeRoadmap(base, "M001", [
|
|
46
|
+
"# M001: Real roadmap",
|
|
47
|
+
"",
|
|
48
|
+
"**Vision:** Real work.",
|
|
49
|
+
"",
|
|
50
|
+
"## Slices",
|
|
51
|
+
"",
|
|
52
|
+
"- [ ] **S01: First slice** `risk:low` `depends:[]`",
|
|
53
|
+
" > After this: a real slice exists.",
|
|
54
|
+
"",
|
|
55
|
+
].join("\n"));
|
|
56
|
+
|
|
57
|
+
const result = verifyExpectedArtifact("plan-milestone", "M001", base);
|
|
58
|
+
assert.equal(result, true, "real roadmap slices should keep passing verification");
|
|
59
|
+
} finally {
|
|
60
|
+
rmSync(base, { recursive: true, force: true });
|
|
61
|
+
}
|
|
62
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression test for #3869: normal post-unit flow should rebuild STATE.md
|
|
3
|
+
* before syncing worktree state back to the project root.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import test from "node:test";
|
|
7
|
+
import assert from "node:assert/strict";
|
|
8
|
+
import { readFileSync } from "node:fs";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
|
|
11
|
+
const source = readFileSync(join(import.meta.dirname, "..", "auto-post-unit.ts"), "utf-8");
|
|
12
|
+
|
|
13
|
+
test("auto-post-unit imports rebuildState", () => {
|
|
14
|
+
assert.ok(
|
|
15
|
+
source.includes('import { rebuildState } from "./doctor.js";'),
|
|
16
|
+
"auto-post-unit.ts should import rebuildState from doctor.ts",
|
|
17
|
+
);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("postUnitPreVerification rebuilds STATE.md before worktree sync", () => {
|
|
21
|
+
const fnStart = source.indexOf("export async function postUnitPreVerification");
|
|
22
|
+
assert.ok(fnStart > 0, "postUnitPreVerification should exist");
|
|
23
|
+
|
|
24
|
+
const section = source.slice(fnStart, fnStart + 8000);
|
|
25
|
+
const rebuildIdx = section.indexOf('await runSafely("postUnit", "state-rebuild"');
|
|
26
|
+
const syncIdx = section.indexOf('await runSafely("postUnit", "worktree-sync"');
|
|
27
|
+
|
|
28
|
+
assert.ok(rebuildIdx > 0, "postUnitPreVerification should rebuild STATE.md after unit completion");
|
|
29
|
+
assert.ok(syncIdx > 0, "postUnitPreVerification should sync worktree state back to the project root");
|
|
30
|
+
assert.ok(
|
|
31
|
+
rebuildIdx < syncIdx,
|
|
32
|
+
"STATE.md rebuild should happen before worktree sync so synced state is fresh",
|
|
33
|
+
);
|
|
34
|
+
});
|