gsd-pi 2.70.1 → 2.71.0-dev.06b86c6
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 +24 -17
- package/dist/cli.js +12 -3
- package/dist/mcp-server.js +6 -6
- package/dist/provider-migrations.d.ts +10 -0
- package/dist/provider-migrations.js +12 -0
- package/dist/resource-loader.js +136 -13
- package/dist/resources/GSD-WORKFLOW.md +1 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +129 -30
- package/dist/resources/extensions/get-secrets-from-user.js +17 -1
- package/dist/resources/extensions/gsd/auto-start.js +4 -12
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +1 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +6 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +6 -0
- package/dist/resources/extensions/gsd/commands/context.js +15 -6
- package/dist/resources/extensions/gsd/commands/dispatcher.js +12 -2
- package/dist/resources/extensions/gsd/custom-workflow-engine.js +16 -12
- package/dist/resources/extensions/gsd/dispatch-guard.js +18 -1
- package/dist/resources/extensions/gsd/error-classifier.js +1 -1
- package/dist/resources/extensions/gsd/file-lock.js +60 -0
- package/dist/resources/extensions/gsd/guided-flow.js +12 -10
- package/dist/resources/extensions/gsd/init-wizard.js +3 -11
- package/dist/resources/extensions/gsd/notification-store.js +21 -1
- package/dist/resources/extensions/gsd/notification-widget.js +1 -1
- package/dist/resources/extensions/gsd/pre-execution-checks.js +35 -2
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -2
- package/dist/resources/extensions/gsd/prompts/discuss.md +33 -13
- package/dist/resources/extensions/gsd/prompts/execute-task.md +20 -19
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +2 -0
- package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/queue.md +3 -2
- package/dist/resources/extensions/gsd/prompts/system.md +1 -0
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -1
- package/dist/resources/extensions/gsd/state.js +234 -332
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +34 -0
- package/dist/resources/extensions/gsd/workflow-events.js +25 -13
- package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +56 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +1 -1
- package/dist/resources/skills/create-skill/SKILL.md +2 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
- package/dist/web/standalone/.next/build-manifest.json +4 -4
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/required-server-files.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 +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- 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 +3 -3
- 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/boot/route_client-reference-manifest.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/input/route_client-reference-manifest.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/resize/route_client-reference-manifest.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/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.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/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.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/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.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/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.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/command/route_client-reference-manifest.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/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.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/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.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/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.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/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
- 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 +3 -3
- 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 +15 -15
- package/dist/web/standalone/.next/server/chunks/63.js +3 -3
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- 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/static/chunks/2826.dd3dc8bbd3025fa5.js +9 -0
- package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-f1e30ab6bb269149.js +1 -0
- package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-6e4d7e9a4f57bed4.js → webpack-b868033a5834586d.js} +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/package.json +1 -1
- package/packages/mcp-server/dist/env-writer.d.ts +39 -0
- package/packages/mcp-server/dist/env-writer.d.ts.map +1 -0
- package/packages/mcp-server/dist/env-writer.js +158 -0
- package/packages/mcp-server/dist/env-writer.js.map +1 -0
- package/packages/mcp-server/dist/server.d.ts +11 -2
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +102 -2
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +21 -11
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/env-writer.test.ts +280 -0
- package/packages/mcp-server/src/env-writer.ts +183 -0
- package/packages/mcp-server/src/secure-env-collect.test.ts +265 -0
- package/packages/mcp-server/src/server.ts +137 -3
- package/packages/mcp-server/src/workflow-tools.test.ts +110 -0
- package/packages/mcp-server/src/workflow-tools.ts +31 -11
- package/packages/pi-ai/dist/providers/amazon-bedrock.js +11 -2
- package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts +4 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +8 -3
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.test.js +44 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.test.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +11 -0
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/src/providers/amazon-bedrock.ts +13 -1
- package/packages/pi-ai/src/providers/anthropic-shared.test.ts +55 -1
- package/packages/pi-ai/src/providers/anthropic-shared.ts +14 -3
- package/packages/pi-ai/src/providers/openai-completions.ts +14 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +388 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts +19 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js +50 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.js +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +168 -23
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +6 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +58 -2
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +468 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.ts +58 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/extension-input.ts +2 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +198 -29
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +66 -2
- package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +1 -1
- package/packages/pi-coding-agent/src/modes/rpc/rpc-types.ts +1 -0
- package/packages/pi-tui/dist/components/__tests__/input.test.js +9 -0
- package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.d.ts +2 -0
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +66 -0
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -0
- package/packages/pi-tui/dist/components/input.d.ts +2 -0
- package/packages/pi-tui/dist/components/input.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/input.js +7 -4
- package/packages/pi-tui/dist/components/input.js.map +1 -1
- package/packages/pi-tui/dist/components/markdown.d.ts +3 -0
- package/packages/pi-tui/dist/components/markdown.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/markdown.js +17 -1
- package/packages/pi-tui/dist/components/markdown.js.map +1 -1
- package/packages/pi-tui/src/components/__tests__/input.test.ts +11 -0
- package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +75 -0
- package/packages/pi-tui/src/components/input.ts +7 -4
- package/packages/pi-tui/src/components/markdown.ts +22 -1
- package/pkg/package.json +1 -1
- package/src/resources/GSD-WORKFLOW.md +1 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +166 -31
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +145 -0
- package/src/resources/extensions/get-secrets-from-user.ts +24 -1
- package/src/resources/extensions/gsd/auto-start.ts +4 -14
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +1 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +6 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +7 -0
- package/src/resources/extensions/gsd/commands/context.ts +16 -5
- package/src/resources/extensions/gsd/commands/dispatcher.ts +14 -2
- package/src/resources/extensions/gsd/custom-workflow-engine.ts +19 -14
- package/src/resources/extensions/gsd/dispatch-guard.ts +18 -1
- package/src/resources/extensions/gsd/error-classifier.ts +1 -1
- package/src/resources/extensions/gsd/file-lock.ts +59 -0
- package/src/resources/extensions/gsd/guided-flow.ts +12 -9
- package/src/resources/extensions/gsd/init-wizard.ts +3 -13
- package/src/resources/extensions/gsd/notification-store.ts +19 -1
- package/src/resources/extensions/gsd/notification-widget.ts +1 -1
- package/src/resources/extensions/gsd/pre-execution-checks.ts +39 -2
- package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/discuss.md +33 -13
- package/src/resources/extensions/gsd/prompts/execute-task.md +20 -19
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +2 -0
- package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/queue.md +3 -2
- package/src/resources/extensions/gsd/prompts/system.md +1 -0
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -1
- package/src/resources/extensions/gsd/state.ts +274 -344
- package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/complete-slice-prompt-task-summary-layout.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +436 -0
- package/src/resources/extensions/gsd/tests/discuss-incremental-persistence.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/execute-task-prompt-existing-artifact-guard.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/file-lock.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +73 -0
- package/src/resources/extensions/gsd/tests/notification-store.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/notification-widget.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/secure-env-collect.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +76 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +155 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +22 -0
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +60 -25
- package/src/resources/extensions/gsd/workflow-events.ts +34 -25
- package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +76 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +1 -1
- package/src/resources/skills/create-skill/SKILL.md +2 -0
- package/dist/web/standalone/.next/static/chunks/2826.821e01b07d92e948.js +0 -9
- package/dist/web/standalone/.next/static/chunks/app/page-7115e62689b5fd84.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
- /package/dist/web/standalone/.next/static/{9pw9EXtXjdM7EFrCXUEPf → dYVdRaunb2ZSEA8fjkT-V}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{9pw9EXtXjdM7EFrCXUEPf → dYVdRaunb2ZSEA8fjkT-V}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
|
|
8
|
+
import { withFileLock, withFileLockSync } from "../file-lock.ts";
|
|
9
|
+
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
11
|
+
|
|
12
|
+
function hasProperLockfile(): boolean {
|
|
13
|
+
try {
|
|
14
|
+
require("proper-lockfile");
|
|
15
|
+
return true;
|
|
16
|
+
} catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
test("withFileLockSync: executes callback when file does not exist", () => {
|
|
22
|
+
const dir = mkdtempSync(join(tmpdir(), "gsd-file-lock-test-"));
|
|
23
|
+
try {
|
|
24
|
+
const missingPath = join(dir, "missing.txt");
|
|
25
|
+
let called = 0;
|
|
26
|
+
const result = withFileLockSync(missingPath, () => {
|
|
27
|
+
called++;
|
|
28
|
+
return "ok";
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
assert.equal(result, "ok");
|
|
32
|
+
assert.equal(called, 1, "callback should execute exactly once");
|
|
33
|
+
} finally {
|
|
34
|
+
rmSync(dir, { recursive: true, force: true });
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("withFileLock: executes callback when file does not exist", async () => {
|
|
39
|
+
const dir = mkdtempSync(join(tmpdir(), "gsd-file-lock-test-"));
|
|
40
|
+
try {
|
|
41
|
+
const missingPath = join(dir, "missing.txt");
|
|
42
|
+
let called = 0;
|
|
43
|
+
const result = await withFileLock(missingPath, async () => {
|
|
44
|
+
called++;
|
|
45
|
+
return "ok";
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
assert.equal(result, "ok");
|
|
49
|
+
assert.equal(called, 1, "callback should execute exactly once");
|
|
50
|
+
} finally {
|
|
51
|
+
rmSync(dir, { recursive: true, force: true });
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("withFileLockSync: falls back to unlocked callback on ELOCKED", () => {
|
|
56
|
+
if (!hasProperLockfile() || process.platform === "win32") {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const lockfile = require("proper-lockfile");
|
|
61
|
+
const dir = mkdtempSync(join(tmpdir(), "gsd-file-lock-test-"));
|
|
62
|
+
const filePath = join(dir, "locked.jsonl");
|
|
63
|
+
writeFileSync(filePath, "{}\n", "utf-8");
|
|
64
|
+
|
|
65
|
+
const release = lockfile.lockSync(filePath, { retries: 0, stale: 10000 });
|
|
66
|
+
try {
|
|
67
|
+
let called = 0;
|
|
68
|
+
const result = withFileLockSync(filePath, () => {
|
|
69
|
+
called++;
|
|
70
|
+
return "fallback-ok";
|
|
71
|
+
});
|
|
72
|
+
assert.equal(result, "fallback-ok");
|
|
73
|
+
assert.equal(called, 1, "callback should run even when lock acquisition fails");
|
|
74
|
+
} finally {
|
|
75
|
+
release();
|
|
76
|
+
rmSync(dir, { recursive: true, force: true });
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("withFileLock: falls back to unlocked callback on ELOCKED", async () => {
|
|
81
|
+
if (!hasProperLockfile() || process.platform === "win32") {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const lockfile = require("proper-lockfile");
|
|
86
|
+
const dir = mkdtempSync(join(tmpdir(), "gsd-file-lock-test-"));
|
|
87
|
+
const filePath = join(dir, "locked.jsonl");
|
|
88
|
+
writeFileSync(filePath, "{}\n", "utf-8");
|
|
89
|
+
|
|
90
|
+
const release = await lockfile.lock(filePath, { retries: 0, stale: 10000 });
|
|
91
|
+
try {
|
|
92
|
+
let called = 0;
|
|
93
|
+
const result = await withFileLock(filePath, async () => {
|
|
94
|
+
called++;
|
|
95
|
+
return "fallback-ok";
|
|
96
|
+
});
|
|
97
|
+
assert.equal(result, "fallback-ok");
|
|
98
|
+
assert.equal(called, 1, "callback should run even when lock acquisition fails");
|
|
99
|
+
} finally {
|
|
100
|
+
await release();
|
|
101
|
+
rmSync(dir, { recursive: true, force: true });
|
|
102
|
+
}
|
|
103
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GSDNoProjectError — tests for friendly home-directory error handling.
|
|
3
|
+
*
|
|
4
|
+
* Verifies that GSDNoProjectError is thrown for blocked directories and
|
|
5
|
+
* that the dispatcher catches it with a user-friendly message.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import test from "node:test";
|
|
9
|
+
import assert from "node:assert/strict";
|
|
10
|
+
import { readFileSync } from "node:fs";
|
|
11
|
+
import { join, dirname } from "node:path";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
|
|
14
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
|
|
16
|
+
const contextSrc = readFileSync(join(__dirname, "..", "commands", "context.ts"), "utf-8");
|
|
17
|
+
const dispatcherSrc = readFileSync(join(__dirname, "..", "commands", "dispatcher.ts"), "utf-8");
|
|
18
|
+
|
|
19
|
+
// ─── GSDNoProjectError class ──────────────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
test("GSDNoProjectError class is exported from context.ts", () => {
|
|
22
|
+
assert.ok(
|
|
23
|
+
contextSrc.includes("export class GSDNoProjectError extends Error"),
|
|
24
|
+
"GSDNoProjectError should be an exported Error subclass",
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("GSDNoProjectError sets name property", () => {
|
|
29
|
+
assert.ok(
|
|
30
|
+
contextSrc.includes('this.name = "GSDNoProjectError"'),
|
|
31
|
+
"GSDNoProjectError should set its name for instanceof checks",
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// ─── projectRoot blocked directory handling ───────────────────────────────
|
|
36
|
+
|
|
37
|
+
test("projectRoot uses validateDirectory and checks for blocked severity", () => {
|
|
38
|
+
assert.ok(
|
|
39
|
+
contextSrc.includes("validateDirectory(pathToCheck)"),
|
|
40
|
+
"projectRoot should call validateDirectory",
|
|
41
|
+
);
|
|
42
|
+
assert.ok(
|
|
43
|
+
contextSrc.includes('result.severity === "blocked"'),
|
|
44
|
+
"projectRoot should check for blocked severity",
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("projectRoot throws GSDNoProjectError on blocked directory", () => {
|
|
49
|
+
assert.ok(
|
|
50
|
+
contextSrc.includes("throw new GSDNoProjectError"),
|
|
51
|
+
"projectRoot should throw GSDNoProjectError when directory is blocked",
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// ─── Dispatcher catch ─────────────────────────────────────────────────────
|
|
56
|
+
|
|
57
|
+
test("dispatcher catches GSDNoProjectError with user-friendly message", () => {
|
|
58
|
+
assert.ok(
|
|
59
|
+
dispatcherSrc.includes("err instanceof GSDNoProjectError"),
|
|
60
|
+
"dispatcher should catch GSDNoProjectError specifically",
|
|
61
|
+
);
|
|
62
|
+
assert.ok(
|
|
63
|
+
dispatcherSrc.includes("cd"),
|
|
64
|
+
"error message should suggest cd-ing into a project directory",
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("dispatcher re-throws non-GSDNoProjectError exceptions", () => {
|
|
69
|
+
assert.ok(
|
|
70
|
+
dispatcherSrc.includes("throw err"),
|
|
71
|
+
"dispatcher should re-throw unexpected errors",
|
|
72
|
+
);
|
|
73
|
+
});
|
|
@@ -187,6 +187,23 @@ describe("notification-store", () => {
|
|
|
187
187
|
assert.ok(!entries.some((e) => e.message === "suppressed"));
|
|
188
188
|
});
|
|
189
189
|
|
|
190
|
+
test("appendNotification suppresses identical messages within the dedup window", (t) => {
|
|
191
|
+
initNotificationStore(tmp);
|
|
192
|
+
let now = 1_000;
|
|
193
|
+
t.mock.method(Date, "now", () => now);
|
|
194
|
+
|
|
195
|
+
appendNotification("same", "warning");
|
|
196
|
+
now += 1_000;
|
|
197
|
+
appendNotification("same", "warning");
|
|
198
|
+
now += 31_000;
|
|
199
|
+
appendNotification("same", "warning");
|
|
200
|
+
|
|
201
|
+
const entries = readNotifications();
|
|
202
|
+
assert.equal(entries.length, 2);
|
|
203
|
+
assert.equal(entries[0].message, "same");
|
|
204
|
+
assert.equal(entries[1].message, "same");
|
|
205
|
+
});
|
|
206
|
+
|
|
190
207
|
test("suppressPersistence is ref-counted", () => {
|
|
191
208
|
initNotificationStore(tmp);
|
|
192
209
|
suppressPersistence();
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdtempSync, mkdirSync, rmSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
|
|
7
|
+
import { initNotificationStore, appendNotification, _resetNotificationStore } from "../notification-store.js";
|
|
8
|
+
import { buildNotificationWidgetLines } from "../notification-widget.js";
|
|
9
|
+
|
|
10
|
+
test("buildNotificationWidgetLines includes slash-command fallback for unread notifications", () => {
|
|
11
|
+
const tmp = mkdtempSync(join(tmpdir(), "gsd-notification-widget-"));
|
|
12
|
+
try {
|
|
13
|
+
mkdirSync(join(tmp, ".gsd"), { recursive: true });
|
|
14
|
+
_resetNotificationStore();
|
|
15
|
+
initNotificationStore(tmp);
|
|
16
|
+
appendNotification("Need attention", "warning");
|
|
17
|
+
|
|
18
|
+
const lines = buildNotificationWidgetLines();
|
|
19
|
+
assert.equal(lines.length, 1);
|
|
20
|
+
assert.match(lines[0]!, /\/gsd notifications/);
|
|
21
|
+
} finally {
|
|
22
|
+
_resetNotificationStore();
|
|
23
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
24
|
+
}
|
|
25
|
+
});
|
|
@@ -1107,6 +1107,38 @@ describe("checkTaskOrdering false positive regression (#3677)", () => {
|
|
|
1107
1107
|
assert.equal(results[0].target, "`later.ts` — needed first");
|
|
1108
1108
|
assert.ok(results[0].message.includes("sequence violation"));
|
|
1109
1109
|
});
|
|
1110
|
+
|
|
1111
|
+
test("existing on-disk files do not trigger ordering violations just because a later task modifies them", () => {
|
|
1112
|
+
const tempDir = join(tmpdir(), `pre-exec-ordering-existing-file-${Date.now()}`);
|
|
1113
|
+
const existingFile = "frontend/src/__tests__/ProcurementPage29.test.tsx";
|
|
1114
|
+
|
|
1115
|
+
mkdirSync(join(tempDir, "frontend", "src", "__tests__"), { recursive: true });
|
|
1116
|
+
writeFileSync(join(tempDir, existingFile), "// existing file");
|
|
1117
|
+
|
|
1118
|
+
try {
|
|
1119
|
+
const tasks = [
|
|
1120
|
+
createTask({
|
|
1121
|
+
id: "T01",
|
|
1122
|
+
sequence: 0,
|
|
1123
|
+
files: [],
|
|
1124
|
+
inputs: ["`frontend/src/__tests__/ProcurementPage29.test.tsx` — contains matchMedia stub to remove"],
|
|
1125
|
+
expected_output: [],
|
|
1126
|
+
}),
|
|
1127
|
+
createTask({
|
|
1128
|
+
id: "T03",
|
|
1129
|
+
sequence: 2,
|
|
1130
|
+
files: [],
|
|
1131
|
+
inputs: [],
|
|
1132
|
+
expected_output: ["frontend/src/__tests__/ProcurementPage29.test.tsx"],
|
|
1133
|
+
}),
|
|
1134
|
+
];
|
|
1135
|
+
|
|
1136
|
+
const results = checkTaskOrdering(tasks, tempDir);
|
|
1137
|
+
assert.equal(results.length, 0, "Pre-existing files should not be treated as created by later tasks");
|
|
1138
|
+
} finally {
|
|
1139
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
1140
|
+
}
|
|
1141
|
+
});
|
|
1110
1142
|
});
|
|
1111
1143
|
|
|
1112
1144
|
// ─── checkFilePathConsistency additional edge cases ──────────────────────────
|
|
@@ -1175,6 +1207,23 @@ describe("checkFilePathConsistency additional edge cases", () => {
|
|
|
1175
1207
|
assert.equal(results![0].blocking, true);
|
|
1176
1208
|
});
|
|
1177
1209
|
|
|
1210
|
+
test("multi-word prose inputs are ignored by path consistency checks", () => {
|
|
1211
|
+
const tasks = [
|
|
1212
|
+
createTask({
|
|
1213
|
+
id: "T01",
|
|
1214
|
+
files: [],
|
|
1215
|
+
inputs: [
|
|
1216
|
+
"Current WIZARD_PRODUCTS enum",
|
|
1217
|
+
"Existing test patterns in wizard.test.ts",
|
|
1218
|
+
],
|
|
1219
|
+
expected_output: [],
|
|
1220
|
+
}),
|
|
1221
|
+
];
|
|
1222
|
+
|
|
1223
|
+
const results = checkFilePathConsistency(tasks, "/tmp");
|
|
1224
|
+
assert.equal(results.length, 0, "Prose planning hints should not be treated as missing file paths");
|
|
1225
|
+
});
|
|
1226
|
+
|
|
1178
1227
|
test("empty inputs array produces no results", () => {
|
|
1179
1228
|
// A task with no inputs and only files should produce zero results from
|
|
1180
1229
|
// consistency check — files are not checked (#3626).
|
|
@@ -42,9 +42,19 @@ test("system prompt references CODEBASE.md and /gsd codebase", () => {
|
|
|
42
42
|
assert.match(prompt, /auto-refreshes it when tracked files change/i);
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
+
test("system prompt hard rules forbid fabricating user responses", () => {
|
|
46
|
+
const prompt = readPrompt("system");
|
|
47
|
+
assert.match(prompt, /never fabricate, simulate, or role-play user responses/i);
|
|
48
|
+
assert.match(prompt, /never generate markers like `?\[User\]`?, `?\[Human\]`?, `?User:`?/i);
|
|
49
|
+
assert.match(prompt, /ask one question round \(1-3 questions\), then stop and wait for the user's actual response/i);
|
|
50
|
+
assert.match(prompt, /ask_user_questions.*only valid structured user input/i);
|
|
51
|
+
});
|
|
52
|
+
|
|
45
53
|
test("discuss prompt allows implementation questions when they materially matter", () => {
|
|
46
54
|
const prompt = readPrompt("discuss");
|
|
47
55
|
assert.match(prompt, /Lead with experience, but ask implementation when it materially matters/i);
|
|
56
|
+
assert.match(prompt, /Never fabricate, simulate, or role-play user responses/i);
|
|
57
|
+
assert.match(prompt, /Ask one question round \(1-3 questions\) per turn, then stop and wait for the user's actual response/i);
|
|
48
58
|
assert.match(prompt, /one gate, not two/i);
|
|
49
59
|
assert.doesNotMatch(prompt, /Questions must be about the experience, not the implementation/i);
|
|
50
60
|
});
|
|
@@ -56,6 +66,8 @@ test("guided discussion prompts avoid wrap-up prompts after every round", () =>
|
|
|
56
66
|
assert.match(slicePrompt, /Do \*\*not\*\* ask a meta "ready to wrap up\?" question after every round/i);
|
|
57
67
|
assert.doesNotMatch(milestonePrompt, /I think I have a solid picture of this milestone\. Ready to wrap up/i);
|
|
58
68
|
assert.doesNotMatch(slicePrompt, /I think I have a solid picture of this slice\. Ready to wrap up/i);
|
|
69
|
+
assert.match(milestonePrompt, /Never fabricate or simulate user input/i);
|
|
70
|
+
assert.match(slicePrompt, /Never fabricate or simulate user input/i);
|
|
59
71
|
});
|
|
60
72
|
|
|
61
73
|
test("guided milestone discussion scopes depth verification to the milestone id", () => {
|
|
@@ -64,6 +76,13 @@ test("guided milestone discussion scopes depth verification to the milestone id"
|
|
|
64
76
|
assert.doesNotMatch(prompt, /depth_verification_confirm" — this enables the write-gate downstream/i, "legacy global depth gate wording should be gone");
|
|
65
77
|
});
|
|
66
78
|
|
|
79
|
+
test("queue prompt requires waiting for user response between rounds", () => {
|
|
80
|
+
const prompt = readPrompt("queue");
|
|
81
|
+
assert.match(prompt, /Never fabricate or simulate user input during this discussion/i);
|
|
82
|
+
assert.match(prompt, /Ask 1-3 questions per round, then wait for the user's response before asking the next round\./i);
|
|
83
|
+
assert.doesNotMatch(prompt, /treat that as permission to continue/i);
|
|
84
|
+
});
|
|
85
|
+
|
|
67
86
|
test("guided-resume-task prompt preserves recovery state until work is superseded", () => {
|
|
68
87
|
const prompt = readPrompt("guided-resume-task");
|
|
69
88
|
assert.match(prompt, /Do \*\*not\*\* delete the continue file immediately/i);
|
|
@@ -101,6 +101,13 @@ test("classifyError detects quota exceeded as permanent", () => {
|
|
|
101
101
|
assert.ok(!isTransient(result));
|
|
102
102
|
});
|
|
103
103
|
|
|
104
|
+
test("classifyError treats plain 'Connection error.' as transient connection failure (#3594)", () => {
|
|
105
|
+
const result = classifyError("Connection error.");
|
|
106
|
+
assert.ok(isTransient(result));
|
|
107
|
+
assert.equal(result.kind, "connection");
|
|
108
|
+
assert.ok("retryAfterMs" in result && result.retryAfterMs === 15_000);
|
|
109
|
+
});
|
|
110
|
+
|
|
104
111
|
test("classifyError treats unknown error as not transient", () => {
|
|
105
112
|
const result = classifyError("something went wrong");
|
|
106
113
|
assert.ok(!isTransient(result));
|
|
@@ -317,3 +317,48 @@ test("secure_env_collect #2997: null from ctx.ui.custom() is still treated as sk
|
|
|
317
317
|
"Key returning null must NOT be in applied list",
|
|
318
318
|
);
|
|
319
319
|
});
|
|
320
|
+
|
|
321
|
+
test("secure_env_collect: falls back to secure input prompt when custom UI is unavailable", async (t) => {
|
|
322
|
+
const { collectSecretsFromManifest } = await loadOrchestrator();
|
|
323
|
+
|
|
324
|
+
const tmp = makeTempDir("sec-input-fallback-test");
|
|
325
|
+
t.after(() => {
|
|
326
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
const manifest = makeManifest([
|
|
330
|
+
{ key: "SECRET_FROM_INPUT_FALLBACK", status: "pending", formatHint: "starts with sk-" },
|
|
331
|
+
]);
|
|
332
|
+
await writeManifestFile(tmp, manifest);
|
|
333
|
+
|
|
334
|
+
let callIndex = 0;
|
|
335
|
+
const inputCalls: Array<{ title: string; placeholder?: string; opts?: { secure?: boolean } }> = [];
|
|
336
|
+
const mockCtx = {
|
|
337
|
+
cwd: tmp,
|
|
338
|
+
hasUI: true,
|
|
339
|
+
ui: {
|
|
340
|
+
custom: async (_factory: any) => {
|
|
341
|
+
callIndex++;
|
|
342
|
+
if (callIndex <= 1) return null; // summary screen dismiss
|
|
343
|
+
return undefined; // collect screen unavailable on this surface
|
|
344
|
+
},
|
|
345
|
+
input: async (title: string, placeholder?: string, opts?: { secure?: boolean }) => {
|
|
346
|
+
inputCalls.push({ title, placeholder, opts });
|
|
347
|
+
return " sk-test-fallback-value ";
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
const result = await collectSecretsFromManifest(tmp, "M001", mockCtx as any);
|
|
353
|
+
|
|
354
|
+
assert.ok(
|
|
355
|
+
result.applied.includes("SECRET_FROM_INPUT_FALLBACK"),
|
|
356
|
+
"Fallback input should collect and apply the key",
|
|
357
|
+
);
|
|
358
|
+
assert.ok(
|
|
359
|
+
!result.skipped.includes("SECRET_FROM_INPUT_FALLBACK"),
|
|
360
|
+
"Fallback input should not mark the key as skipped",
|
|
361
|
+
);
|
|
362
|
+
assert.equal(inputCalls.length, 1, "Fallback input should be requested once");
|
|
363
|
+
assert.equal(inputCalls[0]?.opts?.secure, true, "Fallback input should request secure entry when supported");
|
|
364
|
+
});
|
|
@@ -61,6 +61,13 @@ describe("#2883: isToolInvocationError classification", () => {
|
|
|
61
61
|
);
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
+
test("detects Node v18+ JSON parse variant with property-value text", () => {
|
|
65
|
+
assert.equal(
|
|
66
|
+
isToolInvocationError("Expected ',' or '}' after property value in JSON at position 4096"),
|
|
67
|
+
true,
|
|
68
|
+
);
|
|
69
|
+
});
|
|
70
|
+
|
|
64
71
|
test("detects Unexpected end of JSON input", () => {
|
|
65
72
|
assert.equal(
|
|
66
73
|
isToolInvocationError("Unexpected end of JSON input"),
|
package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
|
|
6
|
+
const promptPath = join(process.cwd(), "src/resources/extensions/gsd/prompts/validate-milestone.md");
|
|
7
|
+
const prompt = readFileSync(promptPath, "utf-8");
|
|
8
|
+
|
|
9
|
+
test("validate-milestone reviewer C requires canonical verification class names", () => {
|
|
10
|
+
assert.match(prompt, /\*\*Reviewer C[\s\S]*Verification Classes/i);
|
|
11
|
+
assert.match(prompt, /exact class names [`']?Contract[`']?, [`']?Integration[`']?, [`']?Operational[`']?, and [`']?UAT[`']?/i);
|
|
12
|
+
assert.match(prompt, /If no verification classes were planned, say that explicitly/i);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("validate-milestone prompt routes verification class analysis into verificationClasses", () => {
|
|
16
|
+
assert.match(prompt, /pass it in `verificationClasses`/i);
|
|
17
|
+
assert.match(prompt, /Extract the `Verification Classes` subsection from Reviewer C and pass it verbatim in `verificationClasses`/);
|
|
18
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
|
|
4
|
+
import { prepareWorkflowMcpForProject, shouldAutoPrepareWorkflowMcp } from "../workflow-mcp-auto-prep.ts";
|
|
5
|
+
|
|
6
|
+
test("shouldAutoPrepareWorkflowMcp enables prep for externalCli local transport", () => {
|
|
7
|
+
const result = shouldAutoPrepareWorkflowMcp({
|
|
8
|
+
model: { provider: "claude-code", baseUrl: "local://claude-code" },
|
|
9
|
+
modelRegistry: {
|
|
10
|
+
getProviderAuthMode: () => "externalCli",
|
|
11
|
+
isProviderRequestReady: () => false,
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
assert.equal(result, true);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("shouldAutoPrepareWorkflowMcp enables prep when claude-code provider is ready", () => {
|
|
19
|
+
const result = shouldAutoPrepareWorkflowMcp({
|
|
20
|
+
model: { provider: "openai", baseUrl: "https://api.openai.com" },
|
|
21
|
+
modelRegistry: {
|
|
22
|
+
getProviderAuthMode: () => "apiKey",
|
|
23
|
+
isProviderRequestReady: (provider: string) => provider === "claude-code",
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
assert.equal(result, true);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("shouldAutoPrepareWorkflowMcp enables prep when claude-code provider is registered", () => {
|
|
31
|
+
const result = shouldAutoPrepareWorkflowMcp({
|
|
32
|
+
model: { provider: "openai", baseUrl: "https://api.openai.com" },
|
|
33
|
+
modelRegistry: {
|
|
34
|
+
getProviderAuthMode: (provider: string) => provider === "claude-code" ? "externalCli" : "apiKey",
|
|
35
|
+
isProviderRequestReady: () => false,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
assert.equal(result, true);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("shouldAutoPrepareWorkflowMcp stays disabled when neither transport nor provider readiness match", () => {
|
|
43
|
+
const result = shouldAutoPrepareWorkflowMcp({
|
|
44
|
+
model: { provider: "openai", baseUrl: "https://api.openai.com" },
|
|
45
|
+
modelRegistry: {
|
|
46
|
+
getProviderAuthMode: () => "apiKey",
|
|
47
|
+
isProviderRequestReady: () => false,
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
assert.equal(result, false);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("prepareWorkflowMcpForProject warns with /gsd mcp init guidance when prep fails", () => {
|
|
55
|
+
const notifications: Array<{ message: string; level: "info" | "warning" | "error" | "success" }> = [];
|
|
56
|
+
const result = prepareWorkflowMcpForProject(
|
|
57
|
+
{
|
|
58
|
+
model: { provider: "claude-code", baseUrl: "local://claude-code" },
|
|
59
|
+
modelRegistry: {
|
|
60
|
+
getProviderAuthMode: () => "externalCli",
|
|
61
|
+
isProviderRequestReady: () => true,
|
|
62
|
+
},
|
|
63
|
+
ui: {
|
|
64
|
+
notify: (message: string, level?: "info" | "warning" | "error" | "success") => {
|
|
65
|
+
notifications.push({ message, level: level ?? "info" });
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
"/",
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
assert.equal(result, null);
|
|
73
|
+
assert.equal(notifications.length, 1);
|
|
74
|
+
assert.equal(notifications[0].level, "warning");
|
|
75
|
+
assert.match(notifications[0].message, /Please run \/gsd mcp init \./);
|
|
76
|
+
});
|