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,75 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { test } from "node:test";
|
|
3
|
+
|
|
4
|
+
import { Markdown, type MarkdownTheme } from "../markdown.js";
|
|
5
|
+
|
|
6
|
+
function noopTheme(): MarkdownTheme {
|
|
7
|
+
const identity = (text: string) => text;
|
|
8
|
+
return {
|
|
9
|
+
heading: identity,
|
|
10
|
+
link: identity,
|
|
11
|
+
linkUrl: identity,
|
|
12
|
+
code: identity,
|
|
13
|
+
codeBlock: identity,
|
|
14
|
+
codeBlockBorder: identity,
|
|
15
|
+
quote: identity,
|
|
16
|
+
quoteBorder: identity,
|
|
17
|
+
hr: identity,
|
|
18
|
+
listBullet: identity,
|
|
19
|
+
bold: identity,
|
|
20
|
+
italic: identity,
|
|
21
|
+
strikethrough: identity,
|
|
22
|
+
underline: identity,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
test("Markdown renders all lines when maxLines is not set", () => {
|
|
27
|
+
const text = "Line 1\n\nLine 2\n\nLine 3\n\nLine 4\n\nLine 5";
|
|
28
|
+
const md = new Markdown(text, 0, 0, noopTheme());
|
|
29
|
+
const lines = md.render(80);
|
|
30
|
+
// Each paragraph produces a line + an inter-paragraph blank line
|
|
31
|
+
const contentLines = lines.filter((l) => l.trim().length > 0);
|
|
32
|
+
assert.ok(contentLines.length >= 5, `expected at least 5 content lines, got ${contentLines.length}`);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("Markdown truncates from the top when maxLines is exceeded", () => {
|
|
36
|
+
const text = "Line 1\n\nLine 2\n\nLine 3\n\nLine 4\n\nLine 5";
|
|
37
|
+
const md = new Markdown(text, 0, 0, noopTheme());
|
|
38
|
+
md.maxLines = 3;
|
|
39
|
+
const lines = md.render(80);
|
|
40
|
+
assert.ok(lines.length <= 3, `expected at most 3 lines, got ${lines.length}`);
|
|
41
|
+
// First line should be the ellipsis indicator
|
|
42
|
+
assert.ok(lines[0].includes("…"), "first line should contain ellipsis indicator");
|
|
43
|
+
assert.ok(lines[0].includes("above"), "first line should mention lines above");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("Markdown preserves most recent content when truncating", () => {
|
|
47
|
+
const text = "First paragraph\n\nSecond paragraph\n\nThird paragraph\n\nFourth paragraph\n\nFifth paragraph";
|
|
48
|
+
const md = new Markdown(text, 0, 0, noopTheme());
|
|
49
|
+
md.maxLines = 3;
|
|
50
|
+
const lines = md.render(80);
|
|
51
|
+
// The last rendered line should contain "Fifth paragraph" (the most recent content)
|
|
52
|
+
const lastContentLine = lines.filter((l) => !l.includes("…")).pop() ?? "";
|
|
53
|
+
assert.ok(
|
|
54
|
+
lastContentLine.includes("Fifth paragraph"),
|
|
55
|
+
`expected last content line to contain "Fifth paragraph", got "${lastContentLine}"`,
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("Markdown does not truncate when content fits within maxLines", () => {
|
|
60
|
+
const text = "Short text";
|
|
61
|
+
const md = new Markdown(text, 0, 0, noopTheme());
|
|
62
|
+
md.maxLines = 10;
|
|
63
|
+
const lines = md.render(80);
|
|
64
|
+
assert.ok(!lines.some((l) => l.includes("…")), "should not contain ellipsis when content fits");
|
|
65
|
+
assert.ok(lines.some((l) => l.includes("Short text")), "should contain the original text");
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("Markdown trims trailing empty lines", () => {
|
|
69
|
+
const text = "Some text\n\n";
|
|
70
|
+
const md = new Markdown(text, 0, 0, noopTheme());
|
|
71
|
+
const lines = md.render(80);
|
|
72
|
+
// Last line should not be empty (trailing empties are trimmed)
|
|
73
|
+
const lastLine = lines[lines.length - 1];
|
|
74
|
+
assert.ok(lastLine.trim().length > 0 || lines.length === 1, "trailing empty lines should be trimmed");
|
|
75
|
+
});
|
|
@@ -21,6 +21,8 @@ export class Input implements Component, Focusable {
|
|
|
21
21
|
public onSubmit?: (value: string) => void;
|
|
22
22
|
public onEscape?: () => void;
|
|
23
23
|
public placeholder: string = "";
|
|
24
|
+
/** When true, render obscured characters instead of the actual value. */
|
|
25
|
+
public secure: boolean = false;
|
|
24
26
|
|
|
25
27
|
/** Focusable interface - set by TUI when focus changes */
|
|
26
28
|
private _focused: boolean = false;
|
|
@@ -446,6 +448,7 @@ export class Input implements Component, Focusable {
|
|
|
446
448
|
// Calculate visible window
|
|
447
449
|
const prompt = "> ";
|
|
448
450
|
const availableWidth = width - prompt.length;
|
|
451
|
+
const renderValue = this.secure ? "*".repeat(this.value.length) : this.value;
|
|
449
452
|
|
|
450
453
|
if (availableWidth <= 0) {
|
|
451
454
|
return [prompt];
|
|
@@ -466,7 +469,7 @@ export class Input implements Component, Focusable {
|
|
|
466
469
|
|
|
467
470
|
if (this.value.length < availableWidth) {
|
|
468
471
|
// Everything fits (leave room for cursor at end)
|
|
469
|
-
visibleText =
|
|
472
|
+
visibleText = renderValue;
|
|
470
473
|
} else {
|
|
471
474
|
// Need horizontal scrolling
|
|
472
475
|
// Reserve one character for cursor if it's at the end
|
|
@@ -501,17 +504,17 @@ export class Input implements Component, Focusable {
|
|
|
501
504
|
|
|
502
505
|
if (this.cursor < halfWidth) {
|
|
503
506
|
// Cursor near start
|
|
504
|
-
visibleText =
|
|
507
|
+
visibleText = renderValue.slice(0, findValidEnd(scrollWidth));
|
|
505
508
|
cursorDisplay = this.cursor;
|
|
506
509
|
} else if (this.cursor > this.value.length - halfWidth) {
|
|
507
510
|
// Cursor near end
|
|
508
511
|
const start = findValidStart(this.value.length - scrollWidth);
|
|
509
|
-
visibleText =
|
|
512
|
+
visibleText = renderValue.slice(start);
|
|
510
513
|
cursorDisplay = this.cursor - start;
|
|
511
514
|
} else {
|
|
512
515
|
// Cursor in middle
|
|
513
516
|
const start = findValidStart(this.cursor - halfWidth);
|
|
514
|
-
visibleText =
|
|
517
|
+
visibleText = renderValue.slice(start, findValidEnd(start + scrollWidth));
|
|
515
518
|
cursorDisplay = halfWidth;
|
|
516
519
|
}
|
|
517
520
|
}
|
|
@@ -58,10 +58,13 @@ export class Markdown implements Component {
|
|
|
58
58
|
private defaultTextStyle?: DefaultTextStyle;
|
|
59
59
|
private theme: MarkdownTheme;
|
|
60
60
|
private defaultStylePrefix?: string;
|
|
61
|
+
/** Maximum rendered lines (excluding padding). When set, content is truncated from the top with an ellipsis indicator so the most recent output remains visible. */
|
|
62
|
+
maxLines?: number;
|
|
61
63
|
|
|
62
64
|
// Cache for rendered output
|
|
63
65
|
private cachedText?: string;
|
|
64
66
|
private cachedWidth?: number;
|
|
67
|
+
private cachedMaxLines?: number;
|
|
65
68
|
private cachedLines?: string[];
|
|
66
69
|
|
|
67
70
|
constructor(
|
|
@@ -86,12 +89,13 @@ export class Markdown implements Component {
|
|
|
86
89
|
invalidate(): void {
|
|
87
90
|
this.cachedText = undefined;
|
|
88
91
|
this.cachedWidth = undefined;
|
|
92
|
+
this.cachedMaxLines = undefined;
|
|
89
93
|
this.cachedLines = undefined;
|
|
90
94
|
}
|
|
91
95
|
|
|
92
96
|
render(width: number): string[] {
|
|
93
97
|
// Check cache
|
|
94
|
-
if (this.cachedLines && this.cachedText === this.text && this.cachedWidth === width) {
|
|
98
|
+
if (this.cachedLines && this.cachedText === this.text && this.cachedWidth === width && this.cachedMaxLines === this.maxLines) {
|
|
95
99
|
return this.cachedLines;
|
|
96
100
|
}
|
|
97
101
|
|
|
@@ -104,6 +108,7 @@ export class Markdown implements Component {
|
|
|
104
108
|
// Update cache
|
|
105
109
|
this.cachedText = this.text;
|
|
106
110
|
this.cachedWidth = width;
|
|
111
|
+
this.cachedMaxLines = this.maxLines;
|
|
107
112
|
this.cachedLines = result;
|
|
108
113
|
return result;
|
|
109
114
|
}
|
|
@@ -124,6 +129,12 @@ export class Markdown implements Component {
|
|
|
124
129
|
for (let j = 0; j < tokenLines.length; j++) renderedLines.push(tokenLines[j]);
|
|
125
130
|
}
|
|
126
131
|
|
|
132
|
+
// Trim trailing empty lines — inter-block spacing at the end just adds
|
|
133
|
+
// unwanted whitespace before whatever follows (e.g. pinned output border).
|
|
134
|
+
while (renderedLines.length > 0 && renderedLines[renderedLines.length - 1] === "") {
|
|
135
|
+
renderedLines.pop();
|
|
136
|
+
}
|
|
137
|
+
|
|
127
138
|
// Wrap lines (NO padding, NO background yet)
|
|
128
139
|
const wrappedLines: string[] = [];
|
|
129
140
|
for (const line of renderedLines) {
|
|
@@ -143,6 +154,15 @@ export class Markdown implements Component {
|
|
|
143
154
|
}
|
|
144
155
|
}
|
|
145
156
|
|
|
157
|
+
// Truncate from the top when maxLines is set so the most recent content
|
|
158
|
+
// stays visible. This prevents the pinned output zone from exceeding the
|
|
159
|
+
// terminal height and causing render flashing.
|
|
160
|
+
if (this.maxLines !== undefined && wrappedLines.length > this.maxLines) {
|
|
161
|
+
const keep = Math.max(1, this.maxLines - 1); // Reserve one line for the ellipsis indicator
|
|
162
|
+
const truncated = wrappedLines.length - keep;
|
|
163
|
+
wrappedLines.splice(0, truncated, `… ${truncated} line${truncated !== 1 ? "s" : ""} above`);
|
|
164
|
+
}
|
|
165
|
+
|
|
146
166
|
// Add margins and background to each wrapped line
|
|
147
167
|
const leftMargin = " ".repeat(this.paddingX);
|
|
148
168
|
const rightMargin = " ".repeat(this.paddingX);
|
|
@@ -181,6 +201,7 @@ export class Markdown implements Component {
|
|
|
181
201
|
// Update cache
|
|
182
202
|
this.cachedText = this.text;
|
|
183
203
|
this.cachedWidth = width;
|
|
204
|
+
this.cachedMaxLines = this.maxLines;
|
|
184
205
|
this.cachedLines = result;
|
|
185
206
|
|
|
186
207
|
return result.length > 0 ? result : [""];
|
package/pkg/package.json
CHANGED
|
@@ -275,7 +275,7 @@ Work flows through these phases. Each phase produces a file.
|
|
|
275
275
|
**How to do it manually:**
|
|
276
276
|
1. Read the roadmap to understand the scope.
|
|
277
277
|
2. Identify 3-5 gray areas — implementation decisions the user cares about.
|
|
278
|
-
3. Use `ask_user_questions` to discuss each area.
|
|
278
|
+
3. Use `ask_user_questions` to discuss each area, one round at a time. Never fabricate user input; wait for the user's actual response before the next round.
|
|
279
279
|
4. Write decisions to the appropriate context file (`M###-CONTEXT.md` or `S##-CONTEXT.md`).
|
|
280
280
|
5. Do NOT discuss how to implement — only what the user wants.
|
|
281
281
|
|
|
@@ -60,6 +60,8 @@ interface SdkElicitationFieldSchema {
|
|
|
60
60
|
type?: string;
|
|
61
61
|
title?: string;
|
|
62
62
|
description?: string;
|
|
63
|
+
format?: string;
|
|
64
|
+
writeOnly?: boolean;
|
|
63
65
|
oneOf?: SdkElicitationRequestOption[];
|
|
64
66
|
items?: {
|
|
65
67
|
anyOf?: SdkElicitationRequestOption[];
|
|
@@ -73,6 +75,7 @@ interface SdkElicitationRequest {
|
|
|
73
75
|
requestedSchema?: {
|
|
74
76
|
type?: string;
|
|
75
77
|
properties?: Record<string, SdkElicitationFieldSchema>;
|
|
78
|
+
required?: string[];
|
|
76
79
|
};
|
|
77
80
|
}
|
|
78
81
|
|
|
@@ -85,7 +88,16 @@ interface ParsedElicitationQuestion extends Question {
|
|
|
85
88
|
noteFieldId?: string;
|
|
86
89
|
}
|
|
87
90
|
|
|
91
|
+
interface ParsedTextInputField {
|
|
92
|
+
id: string;
|
|
93
|
+
title: string;
|
|
94
|
+
description: string;
|
|
95
|
+
required: boolean;
|
|
96
|
+
secure: boolean;
|
|
97
|
+
}
|
|
98
|
+
|
|
88
99
|
const OTHER_OPTION_LABEL = "None of the above";
|
|
100
|
+
const SENSITIVE_FIELD_PATTERN = /(password|passphrase|secret|token|api[_\s-]*key|private[_\s-]*key|credential)/i;
|
|
89
101
|
|
|
90
102
|
// ---------------------------------------------------------------------------
|
|
91
103
|
// Stream factory
|
|
@@ -274,6 +286,67 @@ export function parseAskUserQuestionsElicitation(
|
|
|
274
286
|
return questions.length > 0 ? questions : null;
|
|
275
287
|
}
|
|
276
288
|
|
|
289
|
+
function isSecureElicitationField(
|
|
290
|
+
requestMessage: string,
|
|
291
|
+
fieldId: string,
|
|
292
|
+
field: SdkElicitationFieldSchema,
|
|
293
|
+
): boolean {
|
|
294
|
+
if (field.format === "password") return true;
|
|
295
|
+
if (field.writeOnly === true) return true;
|
|
296
|
+
|
|
297
|
+
const rawField = field as Record<string, unknown>;
|
|
298
|
+
if (rawField.sensitive === true || rawField["x-sensitive"] === true) return true;
|
|
299
|
+
|
|
300
|
+
const haystack = [
|
|
301
|
+
requestMessage,
|
|
302
|
+
fieldId.replace(/[_-]+/g, " "),
|
|
303
|
+
typeof field.title === "string" ? field.title : "",
|
|
304
|
+
typeof field.description === "string" ? field.description : "",
|
|
305
|
+
]
|
|
306
|
+
.join(" ")
|
|
307
|
+
.toLowerCase();
|
|
308
|
+
|
|
309
|
+
return SENSITIVE_FIELD_PATTERN.test(haystack);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export function parseTextInputElicitation(
|
|
313
|
+
request: Pick<SdkElicitationRequest, "message" | "mode" | "requestedSchema">,
|
|
314
|
+
): ParsedTextInputField[] | null {
|
|
315
|
+
if (request.mode && request.mode !== "form") return null;
|
|
316
|
+
const schema = request.requestedSchema as
|
|
317
|
+
| ({ properties?: Record<string, SdkElicitationFieldSchema>; keys?: Record<string, SdkElicitationFieldSchema> } & Record<string, unknown>)
|
|
318
|
+
| undefined;
|
|
319
|
+
const fieldsSource = schema?.properties && typeof schema.properties === "object"
|
|
320
|
+
? schema.properties
|
|
321
|
+
: schema?.keys && typeof schema.keys === "object"
|
|
322
|
+
? schema.keys
|
|
323
|
+
: undefined;
|
|
324
|
+
if (!fieldsSource) return null;
|
|
325
|
+
|
|
326
|
+
const requiredSet = new Set(
|
|
327
|
+
Array.isArray(request.requestedSchema?.required)
|
|
328
|
+
? request.requestedSchema.required.filter((value): value is string => typeof value === "string")
|
|
329
|
+
: [],
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
const fields: ParsedTextInputField[] = [];
|
|
333
|
+
for (const [fieldId, field] of Object.entries(fieldsSource)) {
|
|
334
|
+
if (!field || typeof field !== "object") continue;
|
|
335
|
+
if (field.type !== "string") continue;
|
|
336
|
+
if (Array.isArray(field.oneOf) && field.oneOf.length > 0) continue;
|
|
337
|
+
|
|
338
|
+
fields.push({
|
|
339
|
+
id: fieldId,
|
|
340
|
+
title: typeof field.title === "string" && field.title.length > 0 ? field.title : fieldId,
|
|
341
|
+
description: typeof field.description === "string" ? field.description : "",
|
|
342
|
+
required: requiredSet.has(fieldId),
|
|
343
|
+
secure: isSecureElicitationField(request.message, fieldId, field),
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return fields.length > 0 ? fields : null;
|
|
348
|
+
}
|
|
349
|
+
|
|
277
350
|
export function roundResultToElicitationContent(
|
|
278
351
|
questions: ParsedElicitationQuestion[],
|
|
279
352
|
result: RoundResult,
|
|
@@ -355,6 +428,52 @@ async function promptElicitationWithDialogs(
|
|
|
355
428
|
return { action: "accept", content };
|
|
356
429
|
}
|
|
357
430
|
|
|
431
|
+
function buildTextInputPromptTitle(request: SdkElicitationRequest, field: ParsedTextInputField): string {
|
|
432
|
+
const parts = [
|
|
433
|
+
request.serverName ? `[${request.serverName}]` : "",
|
|
434
|
+
field.title,
|
|
435
|
+
field.description,
|
|
436
|
+
].filter((part) => typeof part === "string" && part.trim().length > 0);
|
|
437
|
+
return parts.join("\n\n");
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function buildTextInputPlaceholder(field: ParsedTextInputField): string | undefined {
|
|
441
|
+
const desc = field.description.trim();
|
|
442
|
+
if (!desc) return field.required ? "Required" : "Leave empty to skip";
|
|
443
|
+
|
|
444
|
+
const formatLine = desc
|
|
445
|
+
.split(/\r?\n/)
|
|
446
|
+
.map((line) => line.trim())
|
|
447
|
+
.find((line) => /^format:/i.test(line));
|
|
448
|
+
|
|
449
|
+
if (!formatLine) return field.required ? "Required" : "Leave empty to skip";
|
|
450
|
+
const hint = formatLine.replace(/^format:\s*/i, "").trim();
|
|
451
|
+
return hint.length > 0 ? hint : field.required ? "Required" : "Leave empty to skip";
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
async function promptTextInputElicitation(
|
|
455
|
+
request: SdkElicitationRequest,
|
|
456
|
+
fields: ParsedTextInputField[],
|
|
457
|
+
ui: ExtensionUIContext,
|
|
458
|
+
signal: AbortSignal,
|
|
459
|
+
): Promise<SdkElicitationResult> {
|
|
460
|
+
const content: Record<string, string | string[]> = {};
|
|
461
|
+
|
|
462
|
+
for (const field of fields) {
|
|
463
|
+
const value = await ui.input(
|
|
464
|
+
buildTextInputPromptTitle(request, field),
|
|
465
|
+
buildTextInputPlaceholder(field),
|
|
466
|
+
{ signal, ...(field.secure ? { secure: true } : {}) },
|
|
467
|
+
);
|
|
468
|
+
if (value === undefined) {
|
|
469
|
+
return { action: "cancel" };
|
|
470
|
+
}
|
|
471
|
+
content[field.id] = value;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return { action: "accept", content };
|
|
475
|
+
}
|
|
476
|
+
|
|
358
477
|
export function createClaudeCodeElicitationHandler(
|
|
359
478
|
ui: ExtensionUIContext | undefined,
|
|
360
479
|
): ((request: SdkElicitationRequest, options: { signal: AbortSignal }) => Promise<SdkElicitationResult>) | undefined {
|
|
@@ -366,19 +485,24 @@ export function createClaudeCodeElicitationHandler(
|
|
|
366
485
|
}
|
|
367
486
|
|
|
368
487
|
const questions = parseAskUserQuestionsElicitation(request);
|
|
369
|
-
if (
|
|
370
|
-
|
|
488
|
+
if (questions) {
|
|
489
|
+
const interviewResult = await showInterviewRound(questions, { signal }, { ui } as any).catch(() => undefined);
|
|
490
|
+
if (interviewResult && Object.keys(interviewResult.answers).length > 0) {
|
|
491
|
+
return {
|
|
492
|
+
action: "accept",
|
|
493
|
+
content: roundResultToElicitationContent(questions, interviewResult),
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
return promptElicitationWithDialogs(request, questions, ui, signal);
|
|
371
498
|
}
|
|
372
499
|
|
|
373
|
-
const
|
|
374
|
-
if (
|
|
375
|
-
return
|
|
376
|
-
action: "accept",
|
|
377
|
-
content: roundResultToElicitationContent(questions, interviewResult),
|
|
378
|
-
};
|
|
500
|
+
const textFields = parseTextInputElicitation(request);
|
|
501
|
+
if (textFields) {
|
|
502
|
+
return promptTextInputElicitation(request, textFields, ui, signal);
|
|
379
503
|
}
|
|
380
504
|
|
|
381
|
-
return
|
|
505
|
+
return { action: "decline" };
|
|
382
506
|
};
|
|
383
507
|
}
|
|
384
508
|
|
|
@@ -398,6 +522,7 @@ export function buildSdkOptions(
|
|
|
398
522
|
extraOptions: Record<string, unknown> = {},
|
|
399
523
|
): Record<string, unknown> {
|
|
400
524
|
const mcpServers = buildWorkflowMcpServers();
|
|
525
|
+
const disallowedTools = ["AskUserQuestion"];
|
|
401
526
|
return {
|
|
402
527
|
pathToClaudeCodeExecutable: getClaudePath(),
|
|
403
528
|
model: modelId,
|
|
@@ -408,6 +533,7 @@ export function buildSdkOptions(
|
|
|
408
533
|
allowDangerouslySkipPermissions: true,
|
|
409
534
|
settingSources: ["project"],
|
|
410
535
|
systemPrompt: { type: "preset", preset: "claude_code" },
|
|
536
|
+
disallowedTools,
|
|
411
537
|
...(mcpServers ? { mcpServers } : {}),
|
|
412
538
|
betas: modelId.includes("sonnet") ? ["context-1m-2025-08-07"] : [],
|
|
413
539
|
...extraOptions,
|
|
@@ -506,15 +632,15 @@ export function extractToolResultsFromSdkUserMessage(message: SDKUserMessage): A
|
|
|
506
632
|
return extracted;
|
|
507
633
|
}
|
|
508
634
|
|
|
509
|
-
function
|
|
510
|
-
|
|
635
|
+
function attachExternalResultsToToolBlocks(
|
|
636
|
+
toolBlocks: AssistantMessage["content"],
|
|
511
637
|
toolResultsById: ReadonlyMap<string, ExternalToolResultPayload>,
|
|
512
638
|
): void {
|
|
513
|
-
for (const block of
|
|
514
|
-
if (block.type !== "toolCall") continue;
|
|
639
|
+
for (const block of toolBlocks) {
|
|
640
|
+
if (block.type !== "toolCall" && block.type !== "serverToolUse") continue;
|
|
515
641
|
const externalResult = toolResultsById.get(block.id);
|
|
516
642
|
if (!externalResult) continue;
|
|
517
|
-
(block as ToolCallWithExternalResult).externalResult = externalResult;
|
|
643
|
+
(block as ToolCallWithExternalResult & { id: string }).externalResult = externalResult;
|
|
518
644
|
}
|
|
519
645
|
}
|
|
520
646
|
|
|
@@ -552,8 +678,8 @@ async function pumpSdkMessages(
|
|
|
552
678
|
/** Track the last text content seen across all assistant turns for the final message. */
|
|
553
679
|
let lastTextContent = "";
|
|
554
680
|
let lastThinkingContent = "";
|
|
555
|
-
/** Collect tool
|
|
556
|
-
const
|
|
681
|
+
/** Collect tool blocks from intermediate SDK turns for tool execution rendering. */
|
|
682
|
+
const intermediateToolBlocks: AssistantMessage["content"] = [];
|
|
557
683
|
/** Preserve real external tool results from Claude Code's synthetic user messages. */
|
|
558
684
|
const toolResultsById = new Map<string, ExternalToolResultPayload>();
|
|
559
685
|
|
|
@@ -664,9 +790,9 @@ async function pumpSdkMessages(
|
|
|
664
790
|
lastTextContent = block.text;
|
|
665
791
|
} else if (block.type === "thinking" && block.thinking) {
|
|
666
792
|
lastThinkingContent = block.thinking;
|
|
667
|
-
} else if (block.type === "toolCall") {
|
|
668
|
-
// Collect tool
|
|
669
|
-
|
|
793
|
+
} else if (block.type === "toolCall" || block.type === "serverToolUse") {
|
|
794
|
+
// Collect tool blocks for externalToolExecution rendering
|
|
795
|
+
intermediateToolBlocks.push(block);
|
|
670
796
|
}
|
|
671
797
|
}
|
|
672
798
|
}
|
|
@@ -676,24 +802,33 @@ async function pumpSdkMessages(
|
|
|
676
802
|
for (const { toolUseId, result } of extractToolResultsFromSdkUserMessage(msg as SDKUserMessage)) {
|
|
677
803
|
toolResultsById.set(toolUseId, result);
|
|
678
804
|
}
|
|
679
|
-
|
|
805
|
+
attachExternalResultsToToolBlocks(intermediateToolBlocks, toolResultsById);
|
|
680
806
|
|
|
681
807
|
// Push a synthetic toolcall_end for each tool call from this turn
|
|
682
808
|
// so the TUI can render tool results in real-time during the SDK
|
|
683
809
|
// session instead of waiting until the entire session completes.
|
|
684
810
|
if (builder) {
|
|
685
811
|
for (const block of builder.message.content) {
|
|
686
|
-
if (block.type !== "toolCall") continue;
|
|
687
812
|
const extResult = (block as ToolCallWithExternalResult).externalResult;
|
|
688
813
|
if (!extResult) continue;
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
814
|
+
const contentIndex = builder.message.content.indexOf(block);
|
|
815
|
+
if (contentIndex < 0) continue;
|
|
816
|
+
// Push synthetic completion events with result attached so the
|
|
817
|
+
// chat-controller can update pending ToolExecutionComponents.
|
|
818
|
+
if (block.type === "toolCall") {
|
|
819
|
+
stream.push({
|
|
820
|
+
type: "toolcall_end",
|
|
821
|
+
contentIndex,
|
|
822
|
+
toolCall: block,
|
|
823
|
+
partial: builder.message,
|
|
824
|
+
});
|
|
825
|
+
} else if (block.type === "serverToolUse") {
|
|
826
|
+
stream.push({
|
|
827
|
+
type: "server_tool_use",
|
|
828
|
+
contentIndex,
|
|
829
|
+
partial: builder.message,
|
|
830
|
+
});
|
|
831
|
+
}
|
|
697
832
|
}
|
|
698
833
|
}
|
|
699
834
|
|
|
@@ -711,8 +846,8 @@ async function pumpSdkMessages(
|
|
|
711
846
|
const finalContent: AssistantMessage["content"] = [];
|
|
712
847
|
|
|
713
848
|
// Add tool calls from intermediate turns first (renders above text)
|
|
714
|
-
|
|
715
|
-
finalContent.push(...
|
|
849
|
+
attachExternalResultsToToolBlocks(intermediateToolBlocks, toolResultsById);
|
|
850
|
+
finalContent.push(...intermediateToolBlocks);
|
|
716
851
|
|
|
717
852
|
// Add text/thinking from the last turn
|
|
718
853
|
if (builder && builder.message.content.length > 0) {
|