gsd-pi 2.71.0 → 2.72.0-dev.8f83716
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 +57 -17
- package/dist/cli.js +29 -3
- package/dist/headless-events.d.ts +2 -0
- package/dist/headless-events.js +7 -0
- package/dist/headless.js +16 -3
- package/dist/mcp-server.js +40 -17
- package/dist/provider-migrations.d.ts +10 -0
- package/dist/provider-migrations.js +12 -0
- package/dist/resource-loader.js +139 -13
- package/dist/resources/GSD-WORKFLOW.md +1 -1
- package/dist/resources/agents/debugger.md +58 -0
- package/dist/resources/agents/doc-writer.md +43 -0
- package/dist/resources/agents/git-ops.md +56 -0
- package/dist/resources/agents/javascript-pro.md +46 -271
- package/dist/resources/agents/planner.md +55 -0
- package/dist/resources/agents/refactorer.md +47 -0
- package/dist/resources/agents/reviewer.md +48 -0
- package/dist/resources/agents/security.md +59 -0
- package/dist/resources/agents/tester.md +50 -0
- package/dist/resources/agents/typescript-pro.md +41 -235
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +40 -12
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +133 -14
- package/dist/resources/extensions/gsd/auto/infra-errors.js +34 -0
- package/dist/resources/extensions/gsd/auto/loop.js +32 -1
- package/dist/resources/extensions/gsd/auto/phases.js +5 -1
- package/dist/resources/extensions/gsd/auto/session.js +11 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +22 -16
- package/dist/resources/extensions/gsd/auto-model-selection.js +10 -2
- package/dist/resources/extensions/gsd/auto-prompts.js +88 -33
- package/dist/resources/extensions/gsd/auto-start.js +34 -7
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +1 -1
- package/dist/resources/extensions/gsd/auto-worktree.js +1 -1
- package/dist/resources/extensions/gsd/auto.js +56 -0
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -3
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +63 -51
- 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/commands/handlers/auto.js +10 -33
- package/dist/resources/extensions/gsd/commands/handlers/core.js +56 -11
- package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +15 -6
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +4 -10
- package/dist/resources/extensions/gsd/dashboard-overlay.js +8 -3
- package/dist/resources/extensions/gsd/dispatch-guard.js +18 -1
- package/dist/resources/extensions/gsd/doctor-providers.js +23 -0
- package/dist/resources/extensions/gsd/error-classifier.js +5 -2
- package/dist/resources/extensions/gsd/forensics.js +19 -6
- package/dist/resources/extensions/gsd/gate-registry.js +208 -0
- package/dist/resources/extensions/gsd/gsd-db.js +41 -0
- package/dist/resources/extensions/gsd/guided-flow.js +5 -10
- package/dist/resources/extensions/gsd/metrics.js +1 -0
- package/dist/resources/extensions/gsd/milestone-actions.js +10 -4
- package/dist/resources/extensions/gsd/milestone-validation-gates.js +11 -12
- package/dist/resources/extensions/gsd/notification-overlay.js +42 -13
- package/dist/resources/extensions/gsd/notification-store.js +56 -5
- package/dist/resources/extensions/gsd/notification-widget.js +5 -13
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +8 -3
- package/dist/resources/extensions/gsd/pre-execution-checks.js +35 -2
- package/dist/resources/extensions/gsd/prompt-validation.js +126 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +5 -3
- package/dist/resources/extensions/gsd/prompts/discuss.md +2 -0
- package/dist/resources/extensions/gsd/prompts/execute-task.md +22 -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 +4 -1
- package/dist/resources/extensions/gsd/session-model-override.js +25 -0
- package/dist/resources/extensions/gsd/shortcut-defs.js +40 -0
- package/dist/resources/extensions/gsd/state.js +9 -2
- package/dist/resources/extensions/gsd/tools/complete-slice.js +52 -1
- package/dist/resources/extensions/gsd/tools/complete-task.js +51 -1
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +4 -1
- package/dist/resources/extensions/ollama/index.js +13 -5
- package/dist/resources/extensions/shared/gsd-phase-state.js +35 -0
- package/dist/resources/extensions/subagent/agents.js +8 -0
- package/dist/resources/extensions/subagent/index.js +17 -0
- package/dist/resources/skills/create-skill/SKILL.md +2 -0
- package/dist/startup-model-validation.d.ts +0 -1
- package/dist/startup-model-validation.js +6 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- 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 +13 -13
- 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.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/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/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/server.d.ts +12 -1
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +90 -42
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +22 -12
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/server.ts +110 -38
- package/packages/mcp-server/src/workflow-tools.test.ts +110 -0
- package/packages/mcp-server/src/workflow-tools.ts +32 -12
- 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-auth.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/anthropic-auth.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js +20 -0
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -0
- 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/anthropic.d.ts +2 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +7 -4
- package/packages/pi-ai/dist/providers/anthropic.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-auth.test.ts +32 -0
- 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/anthropic.ts +8 -4
- package/packages/pi-ai/src/providers/openai-completions.ts +14 -0
- package/packages/pi-coding-agent/dist/core/agent-session-renderable-tools.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session-renderable-tools.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session-renderable-tools.test.js +61 -0
- package/packages/pi-coding-agent/dist/core/agent-session-renderable-tools.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +2 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +10 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +27 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +85 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver-initial-model-auth.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/model-resolver-initial-model-auth.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver-initial-model-auth.test.js +64 -0
- package/packages/pi-coding-agent/dist/core/model-resolver-initial-model-auth.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +22 -18
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.test.d.ts +8 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.test.js +75 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts +5 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +55 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +57 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.d.ts +11 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +38 -5
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/sdk.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.test.js +71 -0
- package/packages/pi-coding-agent/dist/core/sdk.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/login-dialog.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/login-dialog.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/login-dialog.test.js +13 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/login-dialog.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +24 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +9 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +130 -12
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +7 -2
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js +6 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +4 -3
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +4 -2
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-renderable-tools.test.ts +70 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +2 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +108 -0
- package/packages/pi-coding-agent/src/core/auth-storage.ts +30 -0
- package/packages/pi-coding-agent/src/core/model-resolver-initial-model-auth.test.ts +78 -0
- package/packages/pi-coding-agent/src/core/model-resolver.test.ts +85 -0
- package/packages/pi-coding-agent/src/core/model-resolver.ts +22 -18
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +83 -0
- package/packages/pi-coding-agent/src/core/retry-handler.ts +60 -1
- package/packages/pi-coding-agent/src/core/sdk.test.ts +89 -0
- package/packages/pi-coding-agent/src/core/sdk.ts +45 -9
- package/packages/pi-coding-agent/src/index.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/login-dialog.test.ts +24 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +72 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/login-dialog.ts +30 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +15 -6
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +131 -12
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +7 -2
- package/packages/pi-coding-agent/src/modes/interactive/controllers/model-controller.ts +6 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +4 -3
- package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +4 -2
- package/pkg/package.json +1 -1
- package/src/resources/GSD-WORKFLOW.md +1 -1
- package/src/resources/agents/debugger.md +58 -0
- package/src/resources/agents/doc-writer.md +43 -0
- package/src/resources/agents/git-ops.md +56 -0
- package/src/resources/agents/javascript-pro.md +46 -271
- package/src/resources/agents/planner.md +55 -0
- package/src/resources/agents/refactorer.md +47 -0
- package/src/resources/agents/reviewer.md +48 -0
- package/src/resources/agents/security.md +59 -0
- package/src/resources/agents/tester.md +50 -0
- package/src/resources/agents/typescript-pro.md +41 -235
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +45 -12
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +143 -13
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +91 -2
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +281 -6
- package/src/resources/extensions/gsd/auto/infra-errors.ts +38 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -0
- package/src/resources/extensions/gsd/auto/loop.ts +45 -1
- package/src/resources/extensions/gsd/auto/phases.ts +6 -0
- package/src/resources/extensions/gsd/auto/session.ts +11 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +29 -18
- package/src/resources/extensions/gsd/auto-model-selection.ts +9 -1
- package/src/resources/extensions/gsd/auto-prompts.ts +111 -33
- package/src/resources/extensions/gsd/auto-start.ts +41 -7
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +1 -1
- package/src/resources/extensions/gsd/auto-worktree.ts +1 -1
- package/src/resources/extensions/gsd/auto.ts +72 -0
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -3
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +79 -60
- 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/commands/handlers/auto.ts +10 -36
- package/src/resources/extensions/gsd/commands/handlers/core.ts +58 -11
- package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +17 -7
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +4 -10
- package/src/resources/extensions/gsd/dashboard-overlay.ts +10 -3
- package/src/resources/extensions/gsd/dispatch-guard.ts +18 -1
- package/src/resources/extensions/gsd/doctor-providers.ts +24 -0
- package/src/resources/extensions/gsd/error-classifier.ts +5 -2
- package/src/resources/extensions/gsd/forensics.ts +23 -7
- package/src/resources/extensions/gsd/gate-registry.ts +251 -0
- package/src/resources/extensions/gsd/gsd-db.ts +51 -0
- package/src/resources/extensions/gsd/guided-flow.ts +5 -10
- package/src/resources/extensions/gsd/interrupted-session.ts +1 -0
- package/src/resources/extensions/gsd/metrics.ts +12 -1
- package/src/resources/extensions/gsd/milestone-actions.ts +10 -3
- package/src/resources/extensions/gsd/milestone-validation-gates.ts +11 -13
- package/src/resources/extensions/gsd/notification-overlay.ts +47 -14
- package/src/resources/extensions/gsd/notification-store.ts +54 -5
- package/src/resources/extensions/gsd/notification-widget.ts +5 -14
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +10 -3
- package/src/resources/extensions/gsd/pre-execution-checks.ts +39 -2
- package/src/resources/extensions/gsd/prompt-validation.ts +157 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +5 -3
- package/src/resources/extensions/gsd/prompts/discuss.md +2 -0
- package/src/resources/extensions/gsd/prompts/execute-task.md +22 -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 +4 -1
- package/src/resources/extensions/gsd/session-model-override.ts +36 -0
- package/src/resources/extensions/gsd/shortcut-defs.ts +56 -0
- package/src/resources/extensions/gsd/state.ts +13 -2
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +25 -9
- 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-gate-closure.test.ts +167 -0
- package/src/resources/extensions/gsd/tests/complete-slice-prompt-task-summary-layout.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/execute-task-prompt-existing-artifact-guard.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/forensics-stuck-loops.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/format-shortcut.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/gate-registry.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +73 -0
- package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +180 -0
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +66 -1
- package/src/resources/extensions/gsd/tests/model-isolation.test.ts +36 -51
- package/src/resources/extensions/gsd/tests/notification-store.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/notification-widget.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +18 -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/prompt-system-gate-coverage.test.ts +208 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/register-shortcuts.test.ts +63 -5
- package/src/resources/extensions/gsd/tests/session-model-override.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +90 -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/tools/complete-slice.ts +63 -0
- package/src/resources/extensions/gsd/tools/complete-task.ts +63 -0
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +4 -1
- package/src/resources/extensions/gsd/types.ts +26 -0
- package/src/resources/extensions/ollama/index.ts +13 -3
- package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +28 -0
- package/src/resources/extensions/shared/gsd-phase-state.ts +42 -0
- package/src/resources/extensions/shared/tests/gsd-phase-state.test.ts +48 -0
- package/src/resources/extensions/subagent/agents.ts +10 -0
- package/src/resources/extensions/subagent/index.ts +18 -0
- package/src/resources/extensions/subagent/tests/agents-conflicts.test.ts +33 -0
- package/src/resources/skills/create-skill/SKILL.md +2 -0
- 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/{nPky_WQC28aBD77eZsRAB → nCL1Ivw47iAAoKVgerXNi}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{nPky_WQC28aBD77eZsRAB → nCL1Ivw47iAAoKVgerXNi}/_ssgManifest.js +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, test } from "node:test";
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
|
-
import { PartialMessageBuilder } from "../partial-builder.ts";
|
|
4
|
-
import type { BetaRawMessageStreamEvent } from "../sdk-types.ts";
|
|
3
|
+
import { mapContentBlock, parseMcpToolName, PartialMessageBuilder } from "../partial-builder.ts";
|
|
4
|
+
import type { BetaContentBlock, BetaRawMessageStreamEvent } from "../sdk-types.ts";
|
|
5
5
|
|
|
6
6
|
describe("PartialMessageBuilder — malformed tool arguments (#2574)", () => {
|
|
7
7
|
/**
|
|
@@ -148,3 +148,92 @@ describe("PartialMessageBuilder — malformed tool arguments (#2574)", () => {
|
|
|
148
148
|
}
|
|
149
149
|
});
|
|
150
150
|
});
|
|
151
|
+
|
|
152
|
+
describe("parseMcpToolName", () => {
|
|
153
|
+
test("splits mcp__<server>__<tool> into parts", () => {
|
|
154
|
+
assert.deepEqual(
|
|
155
|
+
parseMcpToolName("mcp__gsd-workflow__gsd_plan_milestone"),
|
|
156
|
+
{ server: "gsd-workflow", tool: "gsd_plan_milestone" },
|
|
157
|
+
);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("preserves server names containing hyphens", () => {
|
|
161
|
+
assert.deepEqual(
|
|
162
|
+
parseMcpToolName("mcp__my-cool-server__do_thing"),
|
|
163
|
+
{ server: "my-cool-server", tool: "do_thing" },
|
|
164
|
+
);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test("preserves tool names containing underscores", () => {
|
|
168
|
+
assert.deepEqual(
|
|
169
|
+
parseMcpToolName("mcp__srv__a_b_c_d"),
|
|
170
|
+
{ server: "srv", tool: "a_b_c_d" },
|
|
171
|
+
);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test("returns null for non-prefixed names", () => {
|
|
175
|
+
assert.equal(parseMcpToolName("Bash"), null);
|
|
176
|
+
assert.equal(parseMcpToolName("gsd_plan_milestone"), null);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
test("returns null for malformed prefixes", () => {
|
|
180
|
+
assert.equal(parseMcpToolName("mcp__"), null);
|
|
181
|
+
assert.equal(parseMcpToolName("mcp__server"), null);
|
|
182
|
+
assert.equal(parseMcpToolName("mcp__server__"), null);
|
|
183
|
+
assert.equal(parseMcpToolName("mcp____tool"), null);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
describe("PartialMessageBuilder — MCP tool name normalization", () => {
|
|
188
|
+
test("strips mcp__<server>__ prefix on content_block_start", () => {
|
|
189
|
+
const builder = new PartialMessageBuilder("claude-sonnet-4-20250514");
|
|
190
|
+
const event = builder.handleEvent({
|
|
191
|
+
type: "content_block_start",
|
|
192
|
+
index: 0,
|
|
193
|
+
content_block: {
|
|
194
|
+
type: "tool_use",
|
|
195
|
+
id: "tool_1",
|
|
196
|
+
name: "mcp__gsd-workflow__gsd_plan_milestone",
|
|
197
|
+
input: {},
|
|
198
|
+
},
|
|
199
|
+
} as BetaRawMessageStreamEvent);
|
|
200
|
+
|
|
201
|
+
assert.ok(event, "event should not be null");
|
|
202
|
+
assert.equal(event!.type, "toolcall_start");
|
|
203
|
+
if (event!.type === "toolcall_start") {
|
|
204
|
+
const toolCall = (event.partial.content[event.contentIndex] as any);
|
|
205
|
+
assert.equal(toolCall.name, "gsd_plan_milestone");
|
|
206
|
+
assert.equal(toolCall.mcpServer, "gsd-workflow");
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
test("leaves non-MCP tool names untouched", () => {
|
|
211
|
+
const builder = new PartialMessageBuilder("claude-sonnet-4-20250514");
|
|
212
|
+
const event = builder.handleEvent({
|
|
213
|
+
type: "content_block_start",
|
|
214
|
+
index: 0,
|
|
215
|
+
content_block: { type: "tool_use", id: "tool_1", name: "Bash", input: {} },
|
|
216
|
+
} as BetaRawMessageStreamEvent);
|
|
217
|
+
|
|
218
|
+
assert.ok(event);
|
|
219
|
+
if (event!.type === "toolcall_start") {
|
|
220
|
+
const toolCall = (event.partial.content[event.contentIndex] as any);
|
|
221
|
+
assert.equal(toolCall.name, "Bash");
|
|
222
|
+
assert.equal(toolCall.mcpServer, undefined);
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test("mapContentBlock strips MCP prefix on full tool_use blocks", () => {
|
|
227
|
+
const block: BetaContentBlock = {
|
|
228
|
+
type: "tool_use",
|
|
229
|
+
id: "tool_2",
|
|
230
|
+
name: "mcp__gsd-workflow__gsd_task_complete",
|
|
231
|
+
input: { taskId: "T001" },
|
|
232
|
+
};
|
|
233
|
+
const mapped = mapContentBlock(block) as any;
|
|
234
|
+
assert.equal(mapped.type, "toolCall");
|
|
235
|
+
assert.equal(mapped.name, "gsd_task_complete");
|
|
236
|
+
assert.equal(mapped.mcpServer, "gsd-workflow");
|
|
237
|
+
assert.deepEqual(mapped.arguments, { taskId: "T001" });
|
|
238
|
+
});
|
|
239
|
+
});
|
|
@@ -5,6 +5,10 @@ import { join, resolve } from "node:path";
|
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
import {
|
|
7
7
|
makeStreamExhaustedErrorMessage,
|
|
8
|
+
getResultErrorMessage,
|
|
9
|
+
makeAbortedMessage,
|
|
10
|
+
mergePendingToolCalls,
|
|
11
|
+
resolveClaudePermissionMode,
|
|
8
12
|
buildPromptFromContext,
|
|
9
13
|
buildSdkOptions,
|
|
10
14
|
createClaudeCodeElicitationHandler,
|
|
@@ -15,7 +19,7 @@ import {
|
|
|
15
19
|
parseClaudeLookupOutput,
|
|
16
20
|
roundResultToElicitationContent,
|
|
17
21
|
} from "../stream-adapter.ts";
|
|
18
|
-
import type { Context, Message } from "@gsd/pi-ai";
|
|
22
|
+
import type { AssistantMessage, Context, Message } from "@gsd/pi-ai";
|
|
19
23
|
import type { SDKUserMessage } from "../sdk-types.ts";
|
|
20
24
|
|
|
21
25
|
// ---------------------------------------------------------------------------
|
|
@@ -40,6 +44,57 @@ describe("stream-adapter — exhausted stream fallback (#2575)", () => {
|
|
|
40
44
|
});
|
|
41
45
|
});
|
|
42
46
|
|
|
47
|
+
describe("stream-adapter — result error text (#3776)", () => {
|
|
48
|
+
test("prefers SDK result text when an error arrives with subtype success", () => {
|
|
49
|
+
const message = getResultErrorMessage({
|
|
50
|
+
type: "result",
|
|
51
|
+
subtype: "success",
|
|
52
|
+
uuid: "uuid-1",
|
|
53
|
+
session_id: "session-1",
|
|
54
|
+
duration_ms: 1,
|
|
55
|
+
duration_api_ms: 1,
|
|
56
|
+
is_error: true,
|
|
57
|
+
num_turns: 1,
|
|
58
|
+
result: 'API Error: 529 {"type":"error","error":{"type":"overloaded_error","message":"Overloaded"}}',
|
|
59
|
+
stop_reason: null,
|
|
60
|
+
total_cost_usd: 0,
|
|
61
|
+
usage: {
|
|
62
|
+
input_tokens: 0,
|
|
63
|
+
output_tokens: 0,
|
|
64
|
+
cache_read_input_tokens: 0,
|
|
65
|
+
cache_creation_input_tokens: 0,
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
assert.match(message, /API Error: 529/);
|
|
70
|
+
assert.doesNotMatch(message, /^success$/i);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("falls back to a stable classifier when success errors have no text", () => {
|
|
74
|
+
const message = getResultErrorMessage({
|
|
75
|
+
type: "result",
|
|
76
|
+
subtype: "success",
|
|
77
|
+
uuid: "uuid-2",
|
|
78
|
+
session_id: "session-2",
|
|
79
|
+
duration_ms: 1,
|
|
80
|
+
duration_api_ms: 1,
|
|
81
|
+
is_error: true,
|
|
82
|
+
num_turns: 1,
|
|
83
|
+
result: " ",
|
|
84
|
+
stop_reason: null,
|
|
85
|
+
total_cost_usd: 0,
|
|
86
|
+
usage: {
|
|
87
|
+
input_tokens: 0,
|
|
88
|
+
output_tokens: 0,
|
|
89
|
+
cache_read_input_tokens: 0,
|
|
90
|
+
cache_creation_input_tokens: 0,
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
assert.equal(message, "claude_code_request_failed");
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
43
98
|
// ---------------------------------------------------------------------------
|
|
44
99
|
// Bug #2859 — stateless provider regression tests
|
|
45
100
|
// ---------------------------------------------------------------------------
|
|
@@ -112,6 +167,98 @@ describe("stream-adapter — full context prompt (#2859)", () => {
|
|
|
112
167
|
});
|
|
113
168
|
});
|
|
114
169
|
|
|
170
|
+
// ---------------------------------------------------------------------------
|
|
171
|
+
// Bug #4102 — transcript fabrication regression tests
|
|
172
|
+
// ---------------------------------------------------------------------------
|
|
173
|
+
|
|
174
|
+
describe("stream-adapter — no transcript fabrication (#4102)", () => {
|
|
175
|
+
test("buildPromptFromContext never emits forbidden [User]/[Assistant] bracket headers", () => {
|
|
176
|
+
const context: Context = {
|
|
177
|
+
systemPrompt: "You are a helpful assistant.",
|
|
178
|
+
messages: [
|
|
179
|
+
{ role: "user", content: "First" } as Message,
|
|
180
|
+
{
|
|
181
|
+
role: "assistant",
|
|
182
|
+
content: [{ type: "text", text: "Second" }],
|
|
183
|
+
api: "anthropic-messages",
|
|
184
|
+
provider: "claude-code",
|
|
185
|
+
model: "claude-sonnet-4-20250514",
|
|
186
|
+
usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } },
|
|
187
|
+
stopReason: "stop",
|
|
188
|
+
timestamp: Date.now(),
|
|
189
|
+
} as Message,
|
|
190
|
+
{ role: "user", content: "Third" } as Message,
|
|
191
|
+
],
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const prompt = buildPromptFromContext(context);
|
|
195
|
+
|
|
196
|
+
assert.ok(!prompt.includes("[User]"), "prompt must not include literal [User] bracket header");
|
|
197
|
+
assert.ok(!prompt.includes("[Assistant]"), "prompt must not include literal [Assistant] bracket header");
|
|
198
|
+
assert.ok(!prompt.includes("[System]"), "prompt must not include literal [System] bracket header");
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
test("buildPromptFromContext wraps history in XML-tag structure", () => {
|
|
202
|
+
const context: Context = {
|
|
203
|
+
systemPrompt: "You are helpful.",
|
|
204
|
+
messages: [
|
|
205
|
+
{ role: "user", content: "Hello" } as Message,
|
|
206
|
+
{
|
|
207
|
+
role: "assistant",
|
|
208
|
+
content: [{ type: "text", text: "Hi there" }],
|
|
209
|
+
api: "anthropic-messages",
|
|
210
|
+
provider: "claude-code",
|
|
211
|
+
model: "claude-sonnet-4-20250514",
|
|
212
|
+
usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } },
|
|
213
|
+
stopReason: "stop",
|
|
214
|
+
timestamp: Date.now(),
|
|
215
|
+
} as Message,
|
|
216
|
+
],
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const prompt = buildPromptFromContext(context);
|
|
220
|
+
|
|
221
|
+
assert.ok(prompt.includes("<conversation_history>"), "prompt must wrap history in <conversation_history>");
|
|
222
|
+
assert.ok(prompt.includes("</conversation_history>"), "prompt must close <conversation_history>");
|
|
223
|
+
assert.ok(prompt.includes("<user_message>\nHello\n</user_message>"), "user turn must use <user_message> tags");
|
|
224
|
+
assert.ok(prompt.includes("<assistant_message>\nHi there\n</assistant_message>"), "assistant turn must use <assistant_message> tags");
|
|
225
|
+
assert.ok(prompt.includes("<prior_system_context>\nYou are helpful.\n</prior_system_context>"), "system prompt must use <prior_system_context> tags");
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
test("buildPromptFromContext includes a do-not-echo-tags directive as primary instruction", () => {
|
|
229
|
+
const context: Context = {
|
|
230
|
+
messages: [{ role: "user", content: "Anything" } as Message],
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const prompt = buildPromptFromContext(context);
|
|
234
|
+
|
|
235
|
+
assert.ok(
|
|
236
|
+
prompt.startsWith("Respond only to the final user message"),
|
|
237
|
+
"primary directive must lead the prompt",
|
|
238
|
+
);
|
|
239
|
+
assert.ok(prompt.includes("Do not emit <user_message>"), "directive must forbid emitting user_message tag");
|
|
240
|
+
assert.ok(prompt.includes("<assistant_message>"), "directive must mention assistant_message tag");
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
test("buildPromptFromContext omits <conversation_history> when there are no messages but a system prompt", () => {
|
|
244
|
+
const context: Context = {
|
|
245
|
+
systemPrompt: "Seed",
|
|
246
|
+
messages: [],
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
const prompt = buildPromptFromContext(context);
|
|
250
|
+
|
|
251
|
+
assert.ok(prompt.includes("<prior_system_context>"), "system prompt must still render");
|
|
252
|
+
assert.ok(!prompt.includes("<conversation_history>"), "no history wrapper when messages are empty");
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
test("buildPromptFromContext still returns empty string when context is entirely empty", () => {
|
|
256
|
+
const context: Context = { messages: [] };
|
|
257
|
+
const prompt = buildPromptFromContext(context);
|
|
258
|
+
assert.equal(prompt, "", "empty context must not emit a bare directive");
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
|
|
115
262
|
describe("stream-adapter — Claude Code external tool results", () => {
|
|
116
263
|
test("extractToolResultsFromSdkUserMessage maps tool_result content to tool payloads", () => {
|
|
117
264
|
const message: SDKUserMessage = {
|
|
@@ -362,7 +509,7 @@ describe("stream-adapter — session persistence (#2859)", () => {
|
|
|
362
509
|
delete process.env.GSD_WORKFLOW_MCP_ARGS;
|
|
363
510
|
delete process.env.GSD_WORKFLOW_MCP_ENV;
|
|
364
511
|
delete process.env.GSD_WORKFLOW_MCP_CWD;
|
|
365
|
-
const options = buildSdkOptions("claude-sonnet-4-20250514", "test", { onElicitation });
|
|
512
|
+
const options = buildSdkOptions("claude-sonnet-4-20250514", "test", undefined, { onElicitation });
|
|
366
513
|
assert.equal(options.onElicitation, onElicitation);
|
|
367
514
|
} finally {
|
|
368
515
|
process.env.GSD_WORKFLOW_MCP_COMMAND = prev.GSD_WORKFLOW_MCP_COMMAND;
|
|
@@ -598,9 +745,9 @@ describe("stream-adapter — MCP elicitation bridge", () => {
|
|
|
598
745
|
requestedSchema: {
|
|
599
746
|
type: "object" as const,
|
|
600
747
|
properties: {
|
|
601
|
-
|
|
748
|
+
TEST_SECURE_FIELD: {
|
|
602
749
|
type: "string",
|
|
603
|
-
title: "
|
|
750
|
+
title: "TEST_SECURE_FIELD",
|
|
604
751
|
description: "Format: Your secure testing password\nLeave empty to skip.",
|
|
605
752
|
},
|
|
606
753
|
},
|
|
@@ -611,7 +758,7 @@ describe("stream-adapter — MCP elicitation bridge", () => {
|
|
|
611
758
|
const handler = createClaudeCodeElicitationHandler({
|
|
612
759
|
input: async (_title: string, _placeholder?: string, opts?: { secure?: boolean }) => {
|
|
613
760
|
inputCalls.push({ opts });
|
|
614
|
-
return "
|
|
761
|
+
return "example-secure-input";
|
|
615
762
|
},
|
|
616
763
|
} as any);
|
|
617
764
|
assert.ok(handler);
|
|
@@ -620,7 +767,7 @@ describe("stream-adapter — MCP elicitation bridge", () => {
|
|
|
620
767
|
assert.deepEqual(result, {
|
|
621
768
|
action: "accept",
|
|
622
769
|
content: {
|
|
623
|
-
|
|
770
|
+
TEST_SECURE_FIELD: "example-secure-input",
|
|
624
771
|
},
|
|
625
772
|
});
|
|
626
773
|
assert.equal(inputCalls.length, 1);
|
|
@@ -628,6 +775,134 @@ describe("stream-adapter — MCP elicitation bridge", () => {
|
|
|
628
775
|
});
|
|
629
776
|
});
|
|
630
777
|
|
|
778
|
+
// ---------------------------------------------------------------------------
|
|
779
|
+
// F2 — abort vs stream-exhausted classification
|
|
780
|
+
// ---------------------------------------------------------------------------
|
|
781
|
+
|
|
782
|
+
describe("stream-adapter — abort classification (F2)", () => {
|
|
783
|
+
test("makeAbortedMessage sets stopReason to 'aborted', not 'error'", () => {
|
|
784
|
+
const message = makeAbortedMessage("claude-sonnet-4-6", "");
|
|
785
|
+
assert.equal(message.stopReason, "aborted");
|
|
786
|
+
assert.equal(message.errorMessage, undefined);
|
|
787
|
+
});
|
|
788
|
+
|
|
789
|
+
test("makeAbortedMessage preserves last-seen text content", () => {
|
|
790
|
+
const message = makeAbortedMessage("claude-sonnet-4-6", "partial mid-stream text");
|
|
791
|
+
assert.deepEqual(message.content, [{ type: "text", text: "partial mid-stream text" }]);
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
test("aborted message is distinguishable from stream-exhausted error", () => {
|
|
795
|
+
const aborted = makeAbortedMessage("claude-sonnet-4-6", "");
|
|
796
|
+
const exhausted = makeStreamExhaustedErrorMessage("claude-sonnet-4-6", "");
|
|
797
|
+
assert.notEqual(aborted.stopReason, exhausted.stopReason);
|
|
798
|
+
assert.equal(exhausted.errorMessage, "stream_exhausted_without_result");
|
|
799
|
+
});
|
|
800
|
+
});
|
|
801
|
+
|
|
802
|
+
// ---------------------------------------------------------------------------
|
|
803
|
+
// F3 — final-turn tool calls not dropped
|
|
804
|
+
// ---------------------------------------------------------------------------
|
|
805
|
+
|
|
806
|
+
describe("stream-adapter — final-turn tool-call merge (F3)", () => {
|
|
807
|
+
function toolCall(id: string, name = "bash"): AssistantMessage["content"][number] {
|
|
808
|
+
return { type: "toolCall", id, name, arguments: {} };
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
test("mergePendingToolCalls appends tool calls not already in intermediate", () => {
|
|
812
|
+
const intermediate: AssistantMessage["content"] = [toolCall("tool-1")];
|
|
813
|
+
const pending: AssistantMessage["content"] = [
|
|
814
|
+
toolCall("tool-2"),
|
|
815
|
+
{ type: "text", text: "trailing text" },
|
|
816
|
+
];
|
|
817
|
+
const merged = mergePendingToolCalls(intermediate, pending);
|
|
818
|
+
assert.equal(merged.length, 2);
|
|
819
|
+
assert.equal((merged[0] as any).id, "tool-1");
|
|
820
|
+
assert.equal((merged[1] as any).id, "tool-2");
|
|
821
|
+
});
|
|
822
|
+
|
|
823
|
+
test("mergePendingToolCalls is idempotent across duplicate ids", () => {
|
|
824
|
+
const intermediate: AssistantMessage["content"] = [toolCall("tool-1")];
|
|
825
|
+
const pending: AssistantMessage["content"] = [toolCall("tool-1"), toolCall("tool-2")];
|
|
826
|
+
const merged = mergePendingToolCalls(intermediate, pending);
|
|
827
|
+
assert.equal(merged.length, 2);
|
|
828
|
+
assert.deepEqual(
|
|
829
|
+
merged.map((b) => (b as any).id),
|
|
830
|
+
["tool-1", "tool-2"],
|
|
831
|
+
);
|
|
832
|
+
});
|
|
833
|
+
|
|
834
|
+
test("mergePendingToolCalls ignores non-toolCall blocks from pending", () => {
|
|
835
|
+
const intermediate: AssistantMessage["content"] = [];
|
|
836
|
+
const pending: AssistantMessage["content"] = [
|
|
837
|
+
{ type: "text", text: "hello" },
|
|
838
|
+
{ type: "thinking", thinking: "pondering" },
|
|
839
|
+
toolCall("tool-1"),
|
|
840
|
+
];
|
|
841
|
+
const merged = mergePendingToolCalls(intermediate, pending);
|
|
842
|
+
assert.equal(merged.length, 1);
|
|
843
|
+
assert.equal((merged[0] as any).id, "tool-1");
|
|
844
|
+
});
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
// ---------------------------------------------------------------------------
|
|
848
|
+
// F10 — permission mode is configurable
|
|
849
|
+
// ---------------------------------------------------------------------------
|
|
850
|
+
|
|
851
|
+
describe("stream-adapter — permission mode (F10)", () => {
|
|
852
|
+
// Earlier tests in this file set GSD_WORKFLOW_MCP_* env vars and restore
|
|
853
|
+
// them by reassigning from `prev.*`. When `prev.*` was undefined, node
|
|
854
|
+
// coerces the assignment to the literal string "undefined", which then
|
|
855
|
+
// fails JSON.parse inside buildWorkflowMcpServers. Clear the relevant
|
|
856
|
+
// slots before each permission-mode test so buildSdkOptions doesn't throw.
|
|
857
|
+
function clearWorkflowMcpEnv(): void {
|
|
858
|
+
for (const key of [
|
|
859
|
+
"GSD_WORKFLOW_MCP_COMMAND",
|
|
860
|
+
"GSD_WORKFLOW_MCP_NAME",
|
|
861
|
+
"GSD_WORKFLOW_MCP_ARGS",
|
|
862
|
+
"GSD_WORKFLOW_MCP_ENV",
|
|
863
|
+
"GSD_WORKFLOW_MCP_CWD",
|
|
864
|
+
]) {
|
|
865
|
+
if (process.env[key] === undefined || process.env[key] === "undefined") {
|
|
866
|
+
delete process.env[key];
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
test("buildSdkOptions defaults to bypassPermissions for backwards compatibility", () => {
|
|
872
|
+
clearWorkflowMcpEnv();
|
|
873
|
+
const opts = buildSdkOptions("claude-sonnet-4-6", "test");
|
|
874
|
+
assert.equal(opts.permissionMode, "bypassPermissions");
|
|
875
|
+
assert.equal(opts.allowDangerouslySkipPermissions, true);
|
|
876
|
+
});
|
|
877
|
+
|
|
878
|
+
test("buildSdkOptions respects explicit acceptEdits override", () => {
|
|
879
|
+
clearWorkflowMcpEnv();
|
|
880
|
+
const opts = buildSdkOptions("claude-sonnet-4-6", "test", { permissionMode: "acceptEdits" });
|
|
881
|
+
assert.equal(opts.permissionMode, "acceptEdits");
|
|
882
|
+
assert.equal(
|
|
883
|
+
opts.allowDangerouslySkipPermissions,
|
|
884
|
+
false,
|
|
885
|
+
"allowDangerouslySkipPermissions must be false for non-bypass modes",
|
|
886
|
+
);
|
|
887
|
+
});
|
|
888
|
+
|
|
889
|
+
test("resolveClaudePermissionMode honours the GSD_CLAUDE_CODE_PERMISSION_MODE env override", async () => {
|
|
890
|
+
const env = { GSD_CLAUDE_CODE_PERMISSION_MODE: "acceptEdits" } as NodeJS.ProcessEnv;
|
|
891
|
+
const mode = await resolveClaudePermissionMode(env);
|
|
892
|
+
assert.equal(mode, "acceptEdits");
|
|
893
|
+
});
|
|
894
|
+
|
|
895
|
+
test("resolveClaudePermissionMode rejects unknown override values (fallback path)", async () => {
|
|
896
|
+
const env = { GSD_CLAUDE_CODE_PERMISSION_MODE: "nonsense" } as NodeJS.ProcessEnv;
|
|
897
|
+
const mode = await resolveClaudePermissionMode(env);
|
|
898
|
+
// Unknown override falls back to auto-detect → either bypass or acceptEdits
|
|
899
|
+
assert.ok(
|
|
900
|
+
mode === "bypassPermissions" || mode === "acceptEdits",
|
|
901
|
+
`expected bypass or acceptEdits, got ${mode}`,
|
|
902
|
+
);
|
|
903
|
+
});
|
|
904
|
+
});
|
|
905
|
+
|
|
631
906
|
describe("stream-adapter — Windows Claude path lookup (#3770)", () => {
|
|
632
907
|
test("getClaudeLookupCommand uses where on Windows", () => {
|
|
633
908
|
assert.equal(getClaudeLookupCommand("win32"), "where claude");
|
|
@@ -46,3 +46,41 @@ export function isInfrastructureError(err: unknown): string | null {
|
|
|
46
46
|
if (msg.includes("database disk image is malformed")) return "SQLITE_CORRUPT";
|
|
47
47
|
return null;
|
|
48
48
|
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Default wait duration when a cooldown error is detected but no specific
|
|
52
|
+
* expiry is available from AuthStorage (e.g., error propagated across
|
|
53
|
+
* process boundary without structured backoff data).
|
|
54
|
+
*/
|
|
55
|
+
export const COOLDOWN_FALLBACK_WAIT_MS = 35_000; // 35s — slightly longer than the 30s rate-limit backoff
|
|
56
|
+
|
|
57
|
+
/** Maximum consecutive cooldown retries before the auto-loop gives up. */
|
|
58
|
+
export const MAX_COOLDOWN_RETRIES = 5;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Detect whether an error is a transient credential cooldown that should
|
|
62
|
+
* be waited out rather than counted as a consecutive failure.
|
|
63
|
+
*
|
|
64
|
+
* Prefers the structured `CredentialCooldownError` (code: AUTH_COOLDOWN)
|
|
65
|
+
* thrown by sdk.ts. Falls back to message matching for errors that
|
|
66
|
+
* propagated across process boundaries without the typed class.
|
|
67
|
+
*/
|
|
68
|
+
export function isTransientCooldownError(err: unknown): boolean {
|
|
69
|
+
if (err && typeof err === "object" && (err as Record<string, unknown>).code === "AUTH_COOLDOWN") {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
// Fallback: message match for cross-process error propagation
|
|
73
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
74
|
+
return /in a cooldown window/i.test(msg);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Extract retryAfterMs from a CredentialCooldownError, if available.
|
|
79
|
+
* Returns undefined for unstructured errors or when no retry hint exists.
|
|
80
|
+
*/
|
|
81
|
+
export function getCooldownRetryAfterMs(err: unknown): number | undefined {
|
|
82
|
+
if (err && typeof err === "object" && (err as Record<string, unknown>).code === "AUTH_COOLDOWN") {
|
|
83
|
+
return (err as Record<string, unknown>).retryAfterMs as number | undefined;
|
|
84
|
+
}
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
@@ -211,6 +211,8 @@ export interface LoopDeps {
|
|
|
211
211
|
verbose: boolean,
|
|
212
212
|
startModel: { provider: string; id: string } | null,
|
|
213
213
|
retryContext?: { isRetry: boolean; previousTier?: string },
|
|
214
|
+
isAutoMode?: boolean,
|
|
215
|
+
sessionModelOverride?: { provider: string; id: string } | null,
|
|
214
216
|
) => Promise<{
|
|
215
217
|
routing: { tier: string; modelDowngraded: boolean } | null;
|
|
216
218
|
appliedModel: { provider: string; id: string } | null;
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
runFinalize,
|
|
28
28
|
} from "./phases.js";
|
|
29
29
|
import { debugLog } from "../debug-logger.js";
|
|
30
|
-
import { isInfrastructureError } from "./infra-errors.js";
|
|
30
|
+
import { isInfrastructureError, isTransientCooldownError, getCooldownRetryAfterMs, COOLDOWN_FALLBACK_WAIT_MS, MAX_COOLDOWN_RETRIES } from "./infra-errors.js";
|
|
31
31
|
import { resolveEngine } from "../engine-resolver.js";
|
|
32
32
|
|
|
33
33
|
/**
|
|
@@ -48,6 +48,7 @@ export async function autoLoop(
|
|
|
48
48
|
let iteration = 0;
|
|
49
49
|
const loopState: LoopState = { recentUnits: [], stuckRecoveryAttempts: 0, consecutiveFinalizeTimeouts: 0 };
|
|
50
50
|
let consecutiveErrors = 0;
|
|
51
|
+
let consecutiveCooldowns = 0;
|
|
51
52
|
const recentErrorMessages: string[] = [];
|
|
52
53
|
|
|
53
54
|
while (s.active) {
|
|
@@ -203,6 +204,7 @@ export async function autoLoop(
|
|
|
203
204
|
|
|
204
205
|
deps.clearUnitTimeout();
|
|
205
206
|
consecutiveErrors = 0;
|
|
207
|
+
consecutiveCooldowns = 0;
|
|
206
208
|
recentErrorMessages.length = 0;
|
|
207
209
|
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId, seq: nextSeq(), eventType: "iteration-end", data: { iteration } });
|
|
208
210
|
debugLog("autoLoop", { phase: "iteration-complete", iteration });
|
|
@@ -265,6 +267,7 @@ export async function autoLoop(
|
|
|
265
267
|
if (finalizeResult.action === "continue") continue;
|
|
266
268
|
|
|
267
269
|
consecutiveErrors = 0; // Iteration completed successfully
|
|
270
|
+
consecutiveCooldowns = 0;
|
|
268
271
|
recentErrorMessages.length = 0;
|
|
269
272
|
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId, seq: nextSeq(), eventType: "iteration-end", data: { iteration } });
|
|
270
273
|
debugLog("autoLoop", { phase: "iteration-complete", iteration });
|
|
@@ -300,6 +303,47 @@ export async function autoLoop(
|
|
|
300
303
|
break;
|
|
301
304
|
}
|
|
302
305
|
|
|
306
|
+
// ── Credential cooldown: wait and retry with bounded budget ──
|
|
307
|
+
// A 429 triggers a 30s credential backoff in AuthStorage. If the SDK's
|
|
308
|
+
// getApiKey() retries couldn't outlast the window, the error surfaces
|
|
309
|
+
// here. Wait for the cooldown to clear rather than counting it as a
|
|
310
|
+
// consecutive failure — but cap retries so we don't spin for hours
|
|
311
|
+
// on persistent quota exhaustion.
|
|
312
|
+
if (isTransientCooldownError(loopErr)) {
|
|
313
|
+
consecutiveCooldowns++;
|
|
314
|
+
const retryAfterMs = getCooldownRetryAfterMs(loopErr);
|
|
315
|
+
debugLog("autoLoop", {
|
|
316
|
+
phase: "cooldown-wait",
|
|
317
|
+
iteration,
|
|
318
|
+
consecutiveCooldowns,
|
|
319
|
+
retryAfterMs,
|
|
320
|
+
error: msg,
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
if (consecutiveCooldowns > MAX_COOLDOWN_RETRIES) {
|
|
324
|
+
ctx.ui.notify(
|
|
325
|
+
`Auto-mode stopped: ${consecutiveCooldowns} consecutive credential cooldowns — rate limit or quota may be persistently exhausted.`,
|
|
326
|
+
"error",
|
|
327
|
+
);
|
|
328
|
+
await deps.stopAuto(
|
|
329
|
+
ctx,
|
|
330
|
+
pi,
|
|
331
|
+
`${consecutiveCooldowns} consecutive credential cooldowns exceeded retry budget`,
|
|
332
|
+
);
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const waitMs = (retryAfterMs !== undefined && retryAfterMs > 0 && retryAfterMs <= 60_000)
|
|
337
|
+
? retryAfterMs + 500 // Use structured hint + small buffer
|
|
338
|
+
: COOLDOWN_FALLBACK_WAIT_MS;
|
|
339
|
+
ctx.ui.notify(
|
|
340
|
+
`Credentials in cooldown (${consecutiveCooldowns}/${MAX_COOLDOWN_RETRIES}) — waiting ${Math.round(waitMs / 1000)}s before retrying.`,
|
|
341
|
+
"warning",
|
|
342
|
+
);
|
|
343
|
+
await new Promise(resolve => setTimeout(resolve, waitMs));
|
|
344
|
+
continue; // Retry iteration without incrementing consecutiveErrors
|
|
345
|
+
}
|
|
346
|
+
|
|
303
347
|
consecutiveErrors++;
|
|
304
348
|
recentErrorMessages.push(msg.length > 120 ? msg.slice(0, 120) + "..." : msg);
|
|
305
349
|
debugLog("autoLoop", {
|
|
@@ -27,6 +27,7 @@ import { runUnit } from "./run-unit.js";
|
|
|
27
27
|
import { debugLog } from "../debug-logger.js";
|
|
28
28
|
import { PROJECT_FILES } from "../detection.js";
|
|
29
29
|
import { MergeConflictError } from "../git-service.js";
|
|
30
|
+
import { setCurrentPhase, clearCurrentPhase } from "../../shared/gsd-phase-state.js";
|
|
30
31
|
import { join, basename, dirname, parse as parsePath } from "node:path";
|
|
31
32
|
import { existsSync, cpSync, readdirSync } from "node:fs";
|
|
32
33
|
import { logWarning, logError } from "../workflow-logger.js";
|
|
@@ -1068,6 +1069,7 @@ export async function runUnitPhase(
|
|
|
1068
1069
|
const previousTier = s.currentUnitRouting?.tier;
|
|
1069
1070
|
|
|
1070
1071
|
s.currentUnit = { type: unitType, id: unitId, startedAt: Date.now() };
|
|
1072
|
+
setCurrentPhase(unitType);
|
|
1071
1073
|
s.lastToolInvocationError = null; // #2883: clear stale error from previous unit
|
|
1072
1074
|
const unitStartSeq = ic.nextSeq();
|
|
1073
1075
|
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: unitStartSeq, eventType: "unit-start", data: { unitType, unitId } });
|
|
@@ -1183,6 +1185,8 @@ export async function runUnitPhase(
|
|
|
1183
1185
|
s.verbose,
|
|
1184
1186
|
s.autoModeStartModel,
|
|
1185
1187
|
sidecarItem ? undefined : { isRetry, previousTier },
|
|
1188
|
+
undefined,
|
|
1189
|
+
s.manualSessionModelOverride,
|
|
1186
1190
|
);
|
|
1187
1191
|
s.currentUnitRouting =
|
|
1188
1192
|
modelResult.routing as AutoSession["currentUnitRouting"];
|
|
@@ -1527,6 +1531,7 @@ export async function runFinalize(
|
|
|
1527
1531
|
// Detach session from the timed-out unit so late async completions
|
|
1528
1532
|
// cannot mutate state for the next unit (#3757).
|
|
1529
1533
|
s.currentUnit = null;
|
|
1534
|
+
clearCurrentPhase();
|
|
1530
1535
|
loopState.consecutiveFinalizeTimeouts++;
|
|
1531
1536
|
debugLog("autoLoop", {
|
|
1532
1537
|
phase: "pre-verification-timeout",
|
|
@@ -1624,6 +1629,7 @@ export async function runFinalize(
|
|
|
1624
1629
|
// Detach session from the timed-out unit so late async completions
|
|
1625
1630
|
// cannot mutate state for the next unit (#3757).
|
|
1626
1631
|
s.currentUnit = null;
|
|
1632
|
+
clearCurrentPhase();
|
|
1627
1633
|
loopState.consecutiveFinalizeTimeouts++;
|
|
1628
1634
|
debugLog("autoLoop", {
|
|
1629
1635
|
phase: "post-verification-timeout",
|
|
@@ -87,6 +87,10 @@ export class AutoSession {
|
|
|
87
87
|
previousProjectRootEnv: string | null = null;
|
|
88
88
|
hadProjectRootEnv = false;
|
|
89
89
|
projectRootEnvCaptured = false;
|
|
90
|
+
previousMilestoneLockEnv: string | null = null;
|
|
91
|
+
hadMilestoneLockEnv = false;
|
|
92
|
+
milestoneLockEnvCaptured = false;
|
|
93
|
+
sessionMilestoneLock: string | null = null;
|
|
90
94
|
gitService: GitServiceImpl | null = null;
|
|
91
95
|
|
|
92
96
|
// ── Dispatch counters ────────────────────────────────────────────────────
|
|
@@ -107,6 +111,8 @@ export class AutoSession {
|
|
|
107
111
|
|
|
108
112
|
// ── Model state ──────────────────────────────────────────────────────────
|
|
109
113
|
autoModeStartModel: StartModel | null = null;
|
|
114
|
+
/** Explicit /gsd model pin captured at bootstrap (session-scoped policy override). */
|
|
115
|
+
manualSessionModelOverride: StartModel | null = null;
|
|
110
116
|
currentUnitModel: Model<Api> | null = null;
|
|
111
117
|
/** Fully-qualified model ID (provider/id) set after selectAndApplyModel + hook overrides (#2899). */
|
|
112
118
|
currentDispatchedModelId: string | null = null;
|
|
@@ -200,6 +206,10 @@ export class AutoSession {
|
|
|
200
206
|
this.previousProjectRootEnv = null;
|
|
201
207
|
this.hadProjectRootEnv = false;
|
|
202
208
|
this.projectRootEnvCaptured = false;
|
|
209
|
+
this.previousMilestoneLockEnv = null;
|
|
210
|
+
this.hadMilestoneLockEnv = false;
|
|
211
|
+
this.milestoneLockEnvCaptured = false;
|
|
212
|
+
this.sessionMilestoneLock = null;
|
|
203
213
|
this.gitService = null;
|
|
204
214
|
|
|
205
215
|
// Dispatch
|
|
@@ -214,6 +224,7 @@ export class AutoSession {
|
|
|
214
224
|
|
|
215
225
|
// Model
|
|
216
226
|
this.autoModeStartModel = null;
|
|
227
|
+
this.manualSessionModelOverride = null;
|
|
217
228
|
this.currentUnitModel = null;
|
|
218
229
|
this.currentDispatchedModelId = null;
|
|
219
230
|
this.originalModelId = null;
|