gsd-pi 2.51.0 → 2.52.0-dev.655ad8a
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 +59 -36
- package/dist/headless-events.d.ts +18 -0
- package/dist/headless-events.js +36 -0
- package/dist/headless-query.js +1 -1
- package/dist/headless-types.d.ts +28 -0
- package/dist/headless-types.js +7 -0
- package/dist/headless.d.ts +8 -3
- package/dist/headless.js +47 -16
- package/dist/help-text.js +16 -5
- package/dist/onboarding.js +5 -4
- package/dist/remote-questions-config.js +1 -1
- package/dist/resources/extensions/async-jobs/async-bash-tool.js +29 -17
- package/dist/resources/extensions/async-jobs/job-manager.js +4 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +18 -19
- package/dist/resources/extensions/get-secrets-from-user.js +7 -0
- package/dist/resources/extensions/gsd/auto/phases.js +34 -8
- package/dist/resources/extensions/gsd/auto-dispatch.js +23 -1
- package/dist/resources/extensions/gsd/auto-start.js +2 -0
- package/dist/resources/extensions/gsd/auto-timers.js +24 -2
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +25 -7
- package/dist/resources/extensions/gsd/auto-worktree.js +91 -14
- package/dist/resources/extensions/gsd/auto.js +30 -4
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +99 -70
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +12 -2
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +1 -1
- package/dist/resources/extensions/gsd/claude-import.js +60 -9
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +69 -6
- package/dist/resources/extensions/gsd/commands-config.js +10 -5
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +4 -4
- package/dist/resources/extensions/gsd/detection.js +6 -6
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +5 -5
- package/dist/resources/extensions/gsd/error-classifier.js +105 -0
- package/dist/resources/extensions/gsd/git-service.js +4 -3
- package/dist/resources/extensions/gsd/gitignore.js +7 -7
- package/dist/resources/extensions/gsd/gsd-db.js +298 -45
- package/dist/resources/extensions/gsd/guided-flow.js +4 -3
- package/dist/resources/extensions/gsd/init-wizard.js +2 -2
- package/dist/resources/extensions/gsd/key-manager.js +7 -16
- package/dist/resources/extensions/gsd/markdown-renderer.js +5 -4
- package/dist/resources/extensions/gsd/memory-store.js +28 -13
- package/dist/resources/extensions/gsd/milestone-actions.js +19 -0
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +18 -2
- package/dist/resources/extensions/gsd/preferences-models.js +1 -13
- package/dist/resources/extensions/gsd/preferences-types.js +1 -1
- package/dist/resources/extensions/gsd/preferences.js +13 -13
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/provider-error-pause.js +0 -44
- package/dist/resources/extensions/gsd/rule-registry.js +1 -1
- package/dist/resources/extensions/gsd/service-tier.js +13 -2
- package/dist/resources/extensions/gsd/state.js +38 -30
- package/dist/resources/extensions/gsd/status-guards.js +12 -0
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +7 -13
- package/dist/resources/extensions/gsd/tools/complete-slice.js +7 -20
- package/dist/resources/extensions/gsd/tools/complete-task.js +11 -21
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +28 -29
- package/dist/resources/extensions/gsd/tools/plan-slice.js +27 -26
- package/dist/resources/extensions/gsd/tools/plan-task.js +23 -23
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +50 -41
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +4 -3
- package/dist/resources/extensions/gsd/tools/reopen-task.js +5 -4
- package/dist/resources/extensions/gsd/tools/replan-slice.js +51 -41
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +23 -16
- package/dist/resources/extensions/gsd/validation.js +21 -0
- package/dist/resources/extensions/gsd/workflow-logger.js +0 -1
- package/dist/resources/extensions/remote-questions/config.js +1 -1
- package/dist/resources/extensions/remote-questions/remote-command.js +1 -1
- package/dist/resources/extensions/search-the-web/native-search.js +1 -1
- package/dist/resources/extensions/search-the-web/provider.js +1 -1
- package/dist/resources/extensions/shared/rtk.js +14 -4
- package/dist/rtk.js +3 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
- 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 +2 -2
- 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 +4 -4
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
- 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 +4 -4
- 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 +2 -2
- 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/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 +2 -2
- 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 +2 -2
- 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 +4 -4
- 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 +5 -5
- 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 +5 -5
- 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 +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- 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 +11 -11
- package/dist/web/standalone/.next/server/chunks/2229.js +3 -3
- package/dist/web/standalone/.next/server/chunks/7471.js +3 -3
- 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 +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/4024.87fd909ae0110f50.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-b950e4e384cc62b3.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-cfc9a116e6450a6b.js → webpack-bca0e732db0dcec3.js} +1 -1
- package/dist/web/standalone/.next/static/css/a58ef8a151aa0493.css +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/dist/wizard.js +4 -1
- package/package.json +2 -2
- package/packages/mcp-server/README.md +202 -0
- package/packages/mcp-server/package.json +36 -0
- package/packages/mcp-server/src/cli.ts +68 -0
- package/packages/mcp-server/src/index.ts +14 -0
- package/packages/mcp-server/src/mcp-server.test.ts +628 -0
- package/packages/mcp-server/src/server.ts +278 -0
- package/packages/mcp-server/src/session-manager.ts +328 -0
- package/packages/mcp-server/src/types.ts +107 -0
- package/packages/mcp-server/tsconfig.json +24 -0
- package/packages/pi-ai/dist/models.d.ts +14 -3
- package/packages/pi-ai/dist/models.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.js +53 -10
- package/packages/pi-ai/dist/models.js.map +1 -1
- package/packages/pi-ai/dist/models.test.js +102 -1
- package/packages/pi-ai/dist/models.test.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +30 -0
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/src/models.test.ts +114 -1
- package/packages/pi-ai/src/models.ts +70 -13
- package/packages/pi-ai/src/types.ts +31 -0
- package/packages/pi-coding-agent/dist/cli/args.d.ts +2 -0
- package/packages/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/cli/args.js +3 -0
- package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/bash-executor.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/bash-executor.js +5 -1
- package/packages/pi-coding-agent/dist/core/bash-executor.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +9 -4
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.d.ts +19 -0
- package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js +83 -0
- package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js +5 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
- 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.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +5 -3
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/index.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 +0 -2
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts +28 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js +49 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +114 -6
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.d.ts +9 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.js +831 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts +66 -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/dist/utils/shell.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/utils/shell.js +0 -1
- package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/cli/args.ts +4 -0
- package/packages/pi-coding-agent/src/core/bash-executor.ts +5 -1
- package/packages/pi-coding-agent/src/core/model-registry.ts +10 -3
- package/packages/pi-coding-agent/src/core/tools/bash-spawn-windows.test.ts +101 -0
- package/packages/pi-coding-agent/src/core/tools/bash.ts +5 -1
- package/packages/pi-coding-agent/src/index.ts +3 -0
- package/packages/pi-coding-agent/src/main.ts +5 -3
- package/packages/pi-coding-agent/src/modes/index.ts +8 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +0 -2
- package/packages/pi-coding-agent/src/modes/rpc/rpc-client.ts +54 -1
- package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +124 -6
- package/packages/pi-coding-agent/src/modes/rpc/rpc-protocol-v2.test.ts +971 -0
- package/packages/pi-coding-agent/src/modes/rpc/rpc-types.ts +61 -4
- package/packages/pi-coding-agent/src/utils/shell.ts +0 -1
- package/packages/rpc-client/package.json +20 -0
- package/pkg/package.json +1 -1
- package/scripts/ensure-workspace-builds.cjs +36 -8
- package/src/resources/extensions/async-jobs/async-bash-tool.ts +22 -11
- package/src/resources/extensions/async-jobs/job-manager.ts +4 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +19 -20
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +21 -0
- package/src/resources/extensions/get-secrets-from-user.ts +8 -0
- package/src/resources/extensions/gsd/auto/phases.ts +44 -7
- package/src/resources/extensions/gsd/auto-dispatch.ts +25 -1
- package/src/resources/extensions/gsd/auto-start.ts +2 -0
- package/src/resources/extensions/gsd/auto-timers.ts +25 -1
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +30 -6
- package/src/resources/extensions/gsd/auto-worktree.ts +94 -14
- package/src/resources/extensions/gsd/auto.ts +31 -4
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +118 -73
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +11 -2
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +1 -1
- package/src/resources/extensions/gsd/claude-import.ts +58 -9
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +73 -6
- package/src/resources/extensions/gsd/commands-config.ts +11 -5
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +4 -4
- package/src/resources/extensions/gsd/detection.ts +6 -6
- package/src/resources/extensions/gsd/docs/preferences-reference.md +5 -5
- package/src/resources/extensions/gsd/error-classifier.ts +139 -0
- package/src/resources/extensions/gsd/git-service.ts +4 -3
- package/src/resources/extensions/gsd/gitignore.ts +7 -7
- package/src/resources/extensions/gsd/gsd-db.ts +355 -63
- package/src/resources/extensions/gsd/guided-flow.ts +4 -3
- package/src/resources/extensions/gsd/init-wizard.ts +2 -2
- package/src/resources/extensions/gsd/key-manager.ts +7 -16
- package/src/resources/extensions/gsd/markdown-renderer.ts +5 -4
- package/src/resources/extensions/gsd/memory-store.ts +29 -18
- package/src/resources/extensions/gsd/milestone-actions.ts +17 -0
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +23 -1
- package/src/resources/extensions/gsd/preferences-models.ts +1 -13
- package/src/resources/extensions/gsd/preferences-types.ts +1 -1
- package/src/resources/extensions/gsd/preferences.ts +12 -13
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/provider-error-pause.ts +0 -57
- package/src/resources/extensions/gsd/rule-registry.ts +1 -1
- package/src/resources/extensions/gsd/service-tier.ts +14 -2
- package/src/resources/extensions/gsd/state.ts +39 -30
- package/src/resources/extensions/gsd/status-guards.ts +13 -0
- package/src/resources/extensions/gsd/tests/active-milestone-id-guard.test.ts +91 -0
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +61 -0
- package/src/resources/extensions/gsd/tests/auto-stale-lock-self-kill.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-auto-resolve.test.ts +80 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/claude-import-marketplace-discovery.test.ts +191 -0
- package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/commands-config.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +106 -0
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +35 -7
- package/src/resources/extensions/gsd/tests/detection.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/empty-db-reconciliation.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/git-service.test.ts +65 -31
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/interactive-tool-idle-exemption.test.ts +119 -0
- package/src/resources/extensions/gsd/tests/key-manager.test.ts +16 -1
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/milestone-report-path.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/parallel-orchestrator-zombie-cleanup.test.ts +277 -0
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +91 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +77 -70
- package/src/resources/extensions/gsd/tests/rate-limit-model-fallback.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +110 -0
- package/src/resources/extensions/gsd/tests/remote-questions.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/session-lock-transient-read.test.ts +9 -8
- package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/status-guards.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +42 -31
- package/src/resources/extensions/gsd/tests/token-cost-display.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/vacuous-truth-slices.test.ts +115 -0
- package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +12 -2
- package/src/resources/extensions/gsd/tests/validation-gate-patterns.test.ts +124 -0
- package/src/resources/extensions/gsd/tests/validation.test.ts +72 -0
- package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +81 -1
- package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +130 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +7 -17
- package/src/resources/extensions/gsd/tools/complete-slice.ts +7 -24
- package/src/resources/extensions/gsd/tools/complete-task.ts +13 -25
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +30 -32
- package/src/resources/extensions/gsd/tools/plan-slice.ts +30 -30
- package/src/resources/extensions/gsd/tools/plan-task.ts +26 -26
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +57 -46
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +4 -3
- package/src/resources/extensions/gsd/tools/reopen-task.ts +5 -4
- package/src/resources/extensions/gsd/tools/replan-slice.ts +55 -44
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +26 -20
- package/src/resources/extensions/gsd/validation.ts +23 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +0 -1
- package/src/resources/extensions/remote-questions/config.ts +1 -1
- package/src/resources/extensions/remote-questions/remote-command.ts +1 -1
- package/src/resources/extensions/search-the-web/native-search.ts +1 -1
- package/src/resources/extensions/search-the-web/provider.ts +1 -1
- package/src/resources/extensions/shared/rtk.ts +22 -4
- package/dist/web/standalone/.next/static/chunks/4024.9ad5def014d90ce4.js +0 -9
- package/dist/web/standalone/.next/static/chunks/app/page-fbecd1237e2d6d1f.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/css/de141508b083f922.css +0 -1
- /package/dist/resources/extensions/gsd/templates/{preferences.md → PREFERENCES.md} +0 -0
- /package/dist/web/standalone/.next/static/{vkr67v-utm1dgZnbrBWQh → zpvUPKoW5jRAMB_fWHlPi}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{vkr67v-utm1dgZnbrBWQh → zpvUPKoW5jRAMB_fWHlPi}/_ssgManifest.js +0 -0
- /package/src/resources/extensions/gsd/templates/{preferences.md → PREFERENCES.md} +0 -0
|
@@ -11,6 +11,13 @@ import type { SessionStats } from "../../core/agent-session.js";
|
|
|
11
11
|
import type { BashResult } from "../../core/bash-executor.js";
|
|
12
12
|
import type { CompactionResult } from "../../core/compaction/index.js";
|
|
13
13
|
|
|
14
|
+
// ============================================================================
|
|
15
|
+
// RPC Protocol Versioning
|
|
16
|
+
// ============================================================================
|
|
17
|
+
|
|
18
|
+
/** Supported protocol versions. v1 is the implicit default; v2 requires an init handshake. */
|
|
19
|
+
export type RpcProtocolVersion = 1 | 2;
|
|
20
|
+
|
|
14
21
|
// ============================================================================
|
|
15
22
|
// RPC Commands (stdin)
|
|
16
23
|
// ============================================================================
|
|
@@ -69,7 +76,12 @@ export type RpcCommand =
|
|
|
69
76
|
// Bridge-hosted native terminal
|
|
70
77
|
| { id?: string; type: "terminal_input"; data: string }
|
|
71
78
|
| { id?: string; type: "terminal_resize"; cols: number; rows: number }
|
|
72
|
-
| { id?: string; type: "terminal_redraw" }
|
|
79
|
+
| { id?: string; type: "terminal_redraw" }
|
|
80
|
+
|
|
81
|
+
// v2 Protocol
|
|
82
|
+
| { id?: string; type: "init"; protocolVersion: 2; clientId?: string }
|
|
83
|
+
| { id?: string; type: "shutdown"; graceful?: boolean }
|
|
84
|
+
| { id?: string; type: "subscribe"; events: string[] };
|
|
73
85
|
|
|
74
86
|
// ============================================================================
|
|
75
87
|
// RPC Slash Command (for get_commands response)
|
|
@@ -120,9 +132,9 @@ export interface RpcSessionState {
|
|
|
120
132
|
// Success responses with data
|
|
121
133
|
export type RpcResponse =
|
|
122
134
|
// Prompting (async - events follow)
|
|
123
|
-
| { id?: string; type: "response"; command: "prompt"; success: true }
|
|
124
|
-
| { id?: string; type: "response"; command: "steer"; success: true }
|
|
125
|
-
| { id?: string; type: "response"; command: "follow_up"; success: true }
|
|
135
|
+
| { id?: string; type: "response"; command: "prompt"; success: true; runId?: string }
|
|
136
|
+
| { id?: string; type: "response"; command: "steer"; success: true; runId?: string }
|
|
137
|
+
| { id?: string; type: "response"; command: "follow_up"; success: true; runId?: string }
|
|
126
138
|
| { id?: string; type: "response"; command: "abort"; success: true }
|
|
127
139
|
| { id?: string; type: "response"; command: "new_session"; success: true; data: { cancelled: boolean } }
|
|
128
140
|
|
|
@@ -216,9 +228,54 @@ export type RpcResponse =
|
|
|
216
228
|
| { id?: string; type: "response"; command: "terminal_resize"; success: true }
|
|
217
229
|
| { id?: string; type: "response"; command: "terminal_redraw"; success: true }
|
|
218
230
|
|
|
231
|
+
// v2 Protocol
|
|
232
|
+
| { id?: string; type: "response"; command: "init"; success: true; data: RpcInitResult }
|
|
233
|
+
| { id?: string; type: "response"; command: "shutdown"; success: true }
|
|
234
|
+
| { id?: string; type: "response"; command: "subscribe"; success: true }
|
|
235
|
+
|
|
219
236
|
// Error response (any command can fail)
|
|
220
237
|
| { id?: string; type: "response"; command: string; success: false; error: string };
|
|
221
238
|
|
|
239
|
+
// ============================================================================
|
|
240
|
+
// v2 Protocol Types
|
|
241
|
+
// ============================================================================
|
|
242
|
+
|
|
243
|
+
/** Result of the init handshake (v2 only) */
|
|
244
|
+
export interface RpcInitResult {
|
|
245
|
+
protocolVersion: 2;
|
|
246
|
+
sessionId: string;
|
|
247
|
+
capabilities: {
|
|
248
|
+
events: string[];
|
|
249
|
+
commands: string[];
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** v2 execution_complete event — emitted when a prompt/steer/follow_up finishes */
|
|
254
|
+
export interface RpcExecutionCompleteEvent {
|
|
255
|
+
type: "execution_complete";
|
|
256
|
+
runId: string;
|
|
257
|
+
status: "completed" | "error" | "cancelled";
|
|
258
|
+
reason?: string;
|
|
259
|
+
stats: SessionStats;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** v2 cost_update event — emitted per-turn with running cost data */
|
|
263
|
+
export interface RpcCostUpdateEvent {
|
|
264
|
+
type: "cost_update";
|
|
265
|
+
runId: string;
|
|
266
|
+
turnCost: number;
|
|
267
|
+
cumulativeCost: number;
|
|
268
|
+
tokens: {
|
|
269
|
+
input: number;
|
|
270
|
+
output: number;
|
|
271
|
+
cacheRead: number;
|
|
272
|
+
cacheWrite: number;
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** Discriminated union of all v2-only event types */
|
|
277
|
+
export type RpcV2Event = RpcExecutionCompleteEvent | RpcCostUpdateEvent;
|
|
278
|
+
|
|
222
279
|
// ============================================================================
|
|
223
280
|
// Extension UI Events (stdout)
|
|
224
281
|
// ============================================================================
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gsd/rpc-client",
|
|
3
|
+
"version": "2.51.0",
|
|
4
|
+
"description": "Standalone RPC client SDK for GSD — zero internal dependencies",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=22.0.0"
|
|
19
|
+
}
|
|
20
|
+
}
|
package/pkg/package.json
CHANGED
|
@@ -3,15 +3,18 @@
|
|
|
3
3
|
* ensure-workspace-builds.cjs
|
|
4
4
|
*
|
|
5
5
|
* Checks whether workspace packages have been compiled (dist/ exists with
|
|
6
|
-
* index.js)
|
|
6
|
+
* index.js) and that the build is not stale (no src/ file newer than dist/).
|
|
7
|
+
* If any are missing or stale, runs the build for those packages.
|
|
7
8
|
*
|
|
8
9
|
* Designed for the postinstall hook so that `npm install` in a fresh clone
|
|
9
|
-
* produces a working runtime without a manual `npm run build` step.
|
|
10
|
+
* produces a working runtime without a manual `npm run build` step. Also
|
|
11
|
+
* catches the common case where `git pull` updates package sources but the
|
|
12
|
+
* old dist/ remains, causing TypeScript type errors.
|
|
10
13
|
*
|
|
11
14
|
* Skipped in CI (where the full build pipeline handles this) and when
|
|
12
15
|
* installing as an end-user dependency (no packages/ directory).
|
|
13
16
|
*/
|
|
14
|
-
const { existsSync } = require('fs')
|
|
17
|
+
const { existsSync, statSync, readdirSync } = require('fs')
|
|
15
18
|
const { resolve, join } = require('path')
|
|
16
19
|
const { execSync } = require('child_process')
|
|
17
20
|
|
|
@@ -34,19 +37,44 @@ const WORKSPACE_PACKAGES = [
|
|
|
34
37
|
'pi-coding-agent',
|
|
35
38
|
]
|
|
36
39
|
|
|
37
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Returns the most recent mtime (ms) of any .ts file under dir, recursively.
|
|
42
|
+
* Returns 0 if no .ts files found.
|
|
43
|
+
*/
|
|
44
|
+
function newestSrcMtime(dir) {
|
|
45
|
+
if (!existsSync(dir)) return 0
|
|
46
|
+
let newest = 0
|
|
47
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
48
|
+
if (entry.name === 'node_modules') continue
|
|
49
|
+
const full = join(dir, entry.name)
|
|
50
|
+
if (entry.isDirectory()) {
|
|
51
|
+
newest = Math.max(newest, newestSrcMtime(full))
|
|
52
|
+
} else if (entry.isFile() && entry.name.endsWith('.ts')) {
|
|
53
|
+
newest = Math.max(newest, statSync(full).mtimeMs)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return newest
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const stale = []
|
|
38
60
|
for (const pkg of WORKSPACE_PACKAGES) {
|
|
39
61
|
const distIndex = join(packagesDir, pkg, 'dist', 'index.js')
|
|
40
62
|
if (!existsSync(distIndex)) {
|
|
41
|
-
|
|
63
|
+
stale.push(pkg)
|
|
64
|
+
continue
|
|
65
|
+
}
|
|
66
|
+
const distMtime = statSync(distIndex).mtimeMs
|
|
67
|
+
const srcMtime = newestSrcMtime(join(packagesDir, pkg, 'src'))
|
|
68
|
+
if (srcMtime > distMtime) {
|
|
69
|
+
stale.push(pkg)
|
|
42
70
|
}
|
|
43
71
|
}
|
|
44
72
|
|
|
45
|
-
if (
|
|
73
|
+
if (stale.length === 0) process.exit(0)
|
|
46
74
|
|
|
47
|
-
process.stderr.write(` Building ${
|
|
75
|
+
process.stderr.write(` Building ${stale.length} workspace package(s) with stale or missing dist/: ${stale.join(', ')}\n`)
|
|
48
76
|
|
|
49
|
-
for (const pkg of
|
|
77
|
+
for (const pkg of stale) {
|
|
50
78
|
const pkgDir = join(packagesDir, pkg)
|
|
51
79
|
try {
|
|
52
80
|
execSync('npm run build', { cwd: pkgDir, stdio: 'pipe' })
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
DEFAULT_MAX_LINES,
|
|
15
15
|
} from "@gsd/pi-coding-agent";
|
|
16
16
|
import { Type } from "@sinclair/typebox";
|
|
17
|
-
import { spawn } from "node:child_process";
|
|
17
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
18
18
|
import { createWriteStream } from "node:fs";
|
|
19
19
|
import { tmpdir } from "node:os";
|
|
20
20
|
import { join } from "node:path";
|
|
@@ -38,17 +38,24 @@ function getTempFilePath(): string {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
|
-
* Kill a process and its children
|
|
41
|
+
* Kill a process and its children (cross-platform).
|
|
42
|
+
* Uses process group kill on Unix; taskkill /F /T on Windows.
|
|
42
43
|
*/
|
|
43
44
|
function killTree(pid: number): void {
|
|
44
|
-
|
|
45
|
-
// Kill the process group (negative PID)
|
|
46
|
-
process.kill(-pid, "SIGTERM");
|
|
47
|
-
} catch {
|
|
45
|
+
if (process.platform === "win32") {
|
|
48
46
|
try {
|
|
49
|
-
|
|
47
|
+
spawnSync("taskkill", ["/F", "/T", "/PID", String(pid)], {
|
|
48
|
+
timeout: 5_000,
|
|
49
|
+
stdio: "ignore",
|
|
50
|
+
});
|
|
51
|
+
} catch {
|
|
52
|
+
try { process.kill(pid, "SIGTERM"); } catch { /* already exited */ }
|
|
53
|
+
}
|
|
54
|
+
} else {
|
|
55
|
+
try {
|
|
56
|
+
process.kill(-pid, "SIGTERM");
|
|
50
57
|
} catch {
|
|
51
|
-
|
|
58
|
+
try { process.kill(pid, "SIGTERM"); } catch { /* already exited */ }
|
|
52
59
|
}
|
|
53
60
|
}
|
|
54
61
|
}
|
|
@@ -118,9 +125,13 @@ function executeBashInBackground(
|
|
|
118
125
|
const rewrittenCommand = rewriteCommandWithRtk(command);
|
|
119
126
|
const resolvedCommand = sanitizeCommand(rewrittenCommand);
|
|
120
127
|
|
|
128
|
+
// On Windows, detached: true sets CREATE_NEW_PROCESS_GROUP which can
|
|
129
|
+
// cause EINVAL in VSCode/ConPTY terminal contexts. The bg-shell
|
|
130
|
+
// extension already guards this (process-manager.ts); align here.
|
|
131
|
+
// Process-tree cleanup uses taskkill /F /T on Windows regardless.
|
|
121
132
|
const child = spawn(shell, [...args, resolvedCommand], {
|
|
122
133
|
cwd,
|
|
123
|
-
detached:
|
|
134
|
+
detached: process.platform !== "win32",
|
|
124
135
|
env: { ...process.env },
|
|
125
136
|
stdio: ["ignore", "pipe", "pipe"],
|
|
126
137
|
});
|
|
@@ -143,8 +154,8 @@ function executeBashInBackground(
|
|
|
143
154
|
// If the process ignores SIGTERM, escalate to SIGKILL
|
|
144
155
|
sigkillHandle = setTimeout(() => {
|
|
145
156
|
if (child.pid) {
|
|
146
|
-
|
|
147
|
-
|
|
157
|
+
// killTree already uses taskkill /F /T on Windows
|
|
158
|
+
killTree(child.pid);
|
|
148
159
|
}
|
|
149
160
|
|
|
150
161
|
// Hard deadline: if even SIGKILL doesn't trigger 'close',
|
|
@@ -172,7 +172,10 @@ export class AsyncJobManager {
|
|
|
172
172
|
|
|
173
173
|
private deliverResult(job: Job): void {
|
|
174
174
|
if (!this.onJobComplete) return;
|
|
175
|
-
|
|
175
|
+
// Defer delivery by one microtask so await_job's .then() chain runs first
|
|
176
|
+
// and can set job.awaited = true before onJobComplete checks it (#2762).
|
|
177
|
+
const cb = this.onJobComplete;
|
|
178
|
+
queueMicrotask(() => cb(job));
|
|
176
179
|
}
|
|
177
180
|
|
|
178
181
|
private scheduleEviction(id: string): void {
|
|
@@ -113,6 +113,20 @@ function makeErrorMessage(model: string, errorMsg: string): AssistantMessage {
|
|
|
113
113
|
};
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Generator exhaustion without a terminal result means the SDK stream was
|
|
118
|
+
* interrupted mid-turn. Surface it as an error so downstream recovery logic
|
|
119
|
+
* can classify and retry it instead of treating it as a clean completion.
|
|
120
|
+
*/
|
|
121
|
+
export function makeStreamExhaustedErrorMessage(model: string, lastTextContent: string): AssistantMessage {
|
|
122
|
+
const errorMsg = "stream_exhausted_without_result";
|
|
123
|
+
const message = makeErrorMessage(model, errorMsg);
|
|
124
|
+
if (lastTextContent) {
|
|
125
|
+
message.content = [{ type: "text", text: lastTextContent }];
|
|
126
|
+
}
|
|
127
|
+
return message;
|
|
128
|
+
}
|
|
129
|
+
|
|
116
130
|
// ---------------------------------------------------------------------------
|
|
117
131
|
// streamSimple implementation
|
|
118
132
|
// ---------------------------------------------------------------------------
|
|
@@ -339,26 +353,11 @@ async function pumpSdkMessages(
|
|
|
339
353
|
}
|
|
340
354
|
}
|
|
341
355
|
|
|
342
|
-
// Generator
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
}
|
|
347
|
-
if (fallbackContent.length === 0) {
|
|
348
|
-
fallbackContent.push({ type: "text", text: "(Claude Code session ended without a response)" });
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
const fallback: AssistantMessage = {
|
|
352
|
-
role: "assistant",
|
|
353
|
-
content: fallbackContent,
|
|
354
|
-
api: "anthropic-messages",
|
|
355
|
-
provider: "claude-code",
|
|
356
|
-
model: modelId,
|
|
357
|
-
usage: { ...ZERO_USAGE },
|
|
358
|
-
stopReason: "stop",
|
|
359
|
-
timestamp: Date.now(),
|
|
360
|
-
};
|
|
361
|
-
stream.push({ type: "done", reason: "stop", message: fallback });
|
|
356
|
+
// Generator exhaustion without a terminal result is a stream interruption,
|
|
357
|
+
// not a successful completion. Emitting an error lets GSD classify it as a
|
|
358
|
+
// transient provider failure instead of advancing auto-mode state.
|
|
359
|
+
const fallback = makeStreamExhaustedErrorMessage(modelId, lastTextContent);
|
|
360
|
+
stream.push({ type: "error", reason: "error", error: fallback });
|
|
362
361
|
} catch (err) {
|
|
363
362
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
364
363
|
stream.push({
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { describe, test } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { makeStreamExhaustedErrorMessage } from "../stream-adapter.ts";
|
|
4
|
+
|
|
5
|
+
describe("stream-adapter — exhausted stream fallback (#2575)", () => {
|
|
6
|
+
test("generator exhaustion becomes an error message instead of clean completion", () => {
|
|
7
|
+
const message = makeStreamExhaustedErrorMessage("claude-sonnet-4-20250514", "partial answer");
|
|
8
|
+
|
|
9
|
+
assert.equal(message.stopReason, "error");
|
|
10
|
+
assert.equal(message.errorMessage, "stream_exhausted_without_result");
|
|
11
|
+
assert.deepEqual(message.content, [{ type: "text", text: "partial answer" }]);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test("generator exhaustion without prior text still exposes a classifiable error", () => {
|
|
15
|
+
const message = makeStreamExhaustedErrorMessage("claude-sonnet-4-20250514", "");
|
|
16
|
+
|
|
17
|
+
assert.equal(message.stopReason, "error");
|
|
18
|
+
assert.equal(message.errorMessage, "stream_exhausted_without_result");
|
|
19
|
+
assert.match(String((message.content[0] as any)?.text ?? ""), /Claude Code error: stream_exhausted_without_result/);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -47,6 +47,12 @@ function shellEscapeSingle(value: string): string {
|
|
|
47
47
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
function hydrateProcessEnv(key: string, value: string): void {
|
|
51
|
+
// Make newly collected secrets immediately visible to the current session.
|
|
52
|
+
// Some extensions read process.env directly and do not reload .env on every call.
|
|
53
|
+
process.env[key] = value;
|
|
54
|
+
}
|
|
55
|
+
|
|
50
56
|
async function writeEnvKey(filePath: string, key: string, value: string): Promise<void> {
|
|
51
57
|
let content = "";
|
|
52
58
|
try {
|
|
@@ -312,6 +318,7 @@ async function applySecrets(
|
|
|
312
318
|
try {
|
|
313
319
|
await writeEnvKey(opts.envFilePath, key, value);
|
|
314
320
|
applied.push(key);
|
|
321
|
+
hydrateProcessEnv(key, value);
|
|
315
322
|
} catch (err: any) {
|
|
316
323
|
errors.push(`${key}: ${err.message}`);
|
|
317
324
|
}
|
|
@@ -330,6 +337,7 @@ async function applySecrets(
|
|
|
330
337
|
errors.push(`${key}: ${result.stderr.slice(0, 200)}`);
|
|
331
338
|
} else {
|
|
332
339
|
applied.push(key);
|
|
340
|
+
hydrateProcessEnv(key, value);
|
|
333
341
|
}
|
|
334
342
|
} catch (err: any) {
|
|
335
343
|
errors.push(`${key}: ${err.message}`);
|
|
@@ -36,6 +36,15 @@ import { writeUnitRuntimeRecord } from "../unit-runtime.js";
|
|
|
36
36
|
|
|
37
37
|
// ─── generateMilestoneReport ──────────────────────────────────────────────────
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the base path for milestone reports.
|
|
41
|
+
* Prefers originalBasePath (project root) over basePath (which may be a worktree).
|
|
42
|
+
* Exported for testing as _resolveReportBasePath.
|
|
43
|
+
*/
|
|
44
|
+
export function _resolveReportBasePath(s: Pick<AutoSession, "originalBasePath" | "basePath">): string {
|
|
45
|
+
return s.originalBasePath || s.basePath;
|
|
46
|
+
}
|
|
47
|
+
|
|
39
48
|
/**
|
|
40
49
|
* Generate and write an HTML milestone report snapshot.
|
|
41
50
|
* Extracted from the milestone-transition block in autoLoop.
|
|
@@ -50,13 +59,15 @@ async function generateMilestoneReport(
|
|
|
50
59
|
const { writeReportSnapshot } = await importExtensionModule<typeof import("../reports.js")>(import.meta.url, "../reports.js");
|
|
51
60
|
const { basename } = await import("node:path");
|
|
52
61
|
|
|
53
|
-
const
|
|
62
|
+
const reportBasePath = _resolveReportBasePath(s);
|
|
63
|
+
|
|
64
|
+
const snapData = await loadVisualizerData(reportBasePath);
|
|
54
65
|
const completedMs = snapData.milestones.find(
|
|
55
66
|
(m: { id: string }) => m.id === milestoneId,
|
|
56
67
|
);
|
|
57
68
|
const msTitle = completedMs?.title ?? milestoneId;
|
|
58
69
|
const gsdVersion = process.env.GSD_VERSION ?? "0.0.0";
|
|
59
|
-
const projName = basename(
|
|
70
|
+
const projName = basename(reportBasePath);
|
|
60
71
|
const doneSlices = snapData.milestones.reduce(
|
|
61
72
|
(acc: number, m: { slices: { done: boolean }[] }) =>
|
|
62
73
|
acc + m.slices.filter((sl: { done: boolean }) => sl.done).length,
|
|
@@ -67,10 +78,10 @@ async function generateMilestoneReport(
|
|
|
67
78
|
0,
|
|
68
79
|
);
|
|
69
80
|
const outPath = writeReportSnapshot({
|
|
70
|
-
basePath:
|
|
81
|
+
basePath: reportBasePath,
|
|
71
82
|
html: generateHtmlReport(snapData, {
|
|
72
83
|
projectName: projName,
|
|
73
|
-
projectPath:
|
|
84
|
+
projectPath: reportBasePath,
|
|
74
85
|
gsdVersion,
|
|
75
86
|
milestoneId,
|
|
76
87
|
indexRelPath: "index.html",
|
|
@@ -79,7 +90,7 @@ async function generateMilestoneReport(
|
|
|
79
90
|
milestoneTitle: msTitle,
|
|
80
91
|
kind: "milestone",
|
|
81
92
|
projectName: projName,
|
|
82
|
-
projectPath:
|
|
93
|
+
projectPath: reportBasePath,
|
|
83
94
|
gsdVersion,
|
|
84
95
|
totalCost: snapData.totals?.cost ?? 0,
|
|
85
96
|
totalTokens: snapData.totals?.tokens.total ?? 0,
|
|
@@ -250,8 +261,14 @@ export async function runPreDispatch(
|
|
|
250
261
|
await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
|
|
251
262
|
return { action: "break", reason: "merge-conflict" };
|
|
252
263
|
}
|
|
253
|
-
// Non-conflict merge errors —
|
|
254
|
-
|
|
264
|
+
// Non-conflict merge errors — stop auto to avoid advancing with unmerged work
|
|
265
|
+
logError("engine", "Milestone merge failed with non-conflict error", { milestone: s.currentMilestoneId!, error: String(mergeErr) });
|
|
266
|
+
ctx.ui.notify(
|
|
267
|
+
`Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /gsd auto to resume.`,
|
|
268
|
+
"error",
|
|
269
|
+
);
|
|
270
|
+
await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
|
|
271
|
+
return { action: "break", reason: "merge-failed" };
|
|
255
272
|
}
|
|
256
273
|
|
|
257
274
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
@@ -344,6 +361,13 @@ export async function runPreDispatch(
|
|
|
344
361
|
await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
|
|
345
362
|
return { action: "break", reason: "merge-conflict" };
|
|
346
363
|
}
|
|
364
|
+
logError("engine", "Milestone merge failed with non-conflict error", { milestone: s.currentMilestoneId!, error: String(mergeErr) });
|
|
365
|
+
ctx.ui.notify(
|
|
366
|
+
`Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /gsd auto to resume.`,
|
|
367
|
+
"error",
|
|
368
|
+
);
|
|
369
|
+
await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
|
|
370
|
+
return { action: "break", reason: "merge-failed" };
|
|
347
371
|
}
|
|
348
372
|
|
|
349
373
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
@@ -441,6 +465,13 @@ export async function runPreDispatch(
|
|
|
441
465
|
await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
|
|
442
466
|
return { action: "break", reason: "merge-conflict" };
|
|
443
467
|
}
|
|
468
|
+
logError("engine", "Milestone merge failed with non-conflict error", { milestone: s.currentMilestoneId!, error: String(mergeErr) });
|
|
469
|
+
ctx.ui.notify(
|
|
470
|
+
`Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /gsd auto to resume.`,
|
|
471
|
+
"error",
|
|
472
|
+
);
|
|
473
|
+
await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
|
|
474
|
+
return { action: "break", reason: "merge-failed" };
|
|
444
475
|
}
|
|
445
476
|
|
|
446
477
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
@@ -1069,6 +1100,12 @@ export async function runUnitPhase(
|
|
|
1069
1100
|
}
|
|
1070
1101
|
|
|
1071
1102
|
if (unitResult.status === "cancelled") {
|
|
1103
|
+
// Provider-error pause: pauseAuto already handled cleanup and scheduled
|
|
1104
|
+
// recovery. Don't hard-stop — just break out of the loop (#2762).
|
|
1105
|
+
if (unitResult.errorContext?.category === "provider") {
|
|
1106
|
+
debugLog("autoLoop", { phase: "exit", reason: "provider-pause", isTransient: unitResult.errorContext.isTransient });
|
|
1107
|
+
return { action: "break", reason: "provider-pause" };
|
|
1108
|
+
}
|
|
1072
1109
|
ctx.ui.notify(
|
|
1073
1110
|
`Session creation timed out or was cancelled for ${unitType} ${unitId}. Will retry.`,
|
|
1074
1111
|
"warning",
|
|
@@ -626,6 +626,25 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
626
626
|
match: async ({ state, mid, midTitle, basePath }) => {
|
|
627
627
|
if (state.phase !== "completing-milestone") return null;
|
|
628
628
|
|
|
629
|
+
// Safety guard (#2675): block completion when VALIDATION verdict is
|
|
630
|
+
// needs-remediation. The state machine treats needs-remediation as
|
|
631
|
+
// terminal (to prevent validate-milestone loops per #832), but
|
|
632
|
+
// completing-milestone should NOT proceed — remediation work is needed.
|
|
633
|
+
const validationFile = resolveMilestoneFile(basePath, mid, "VALIDATION");
|
|
634
|
+
if (validationFile) {
|
|
635
|
+
const validationContent = await loadFile(validationFile);
|
|
636
|
+
if (validationContent) {
|
|
637
|
+
const verdict = extractVerdict(validationContent);
|
|
638
|
+
if (verdict === "needs-remediation") {
|
|
639
|
+
return {
|
|
640
|
+
action: "stop",
|
|
641
|
+
reason: `Cannot complete milestone ${mid}: VALIDATION verdict is "needs-remediation". Address the remediation findings and re-run validation, or update the verdict manually.`,
|
|
642
|
+
level: "warning",
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
|
|
629
648
|
// Safety guard (#1368): verify all roadmap slices have SUMMARY files.
|
|
630
649
|
const missingSlices = findMissingSummaries(basePath, mid);
|
|
631
650
|
if (missingSlices.length > 0) {
|
|
@@ -658,9 +677,14 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
658
677
|
if (validationPath) {
|
|
659
678
|
const validationContent = await loadFile(validationPath);
|
|
660
679
|
if (validationContent) {
|
|
661
|
-
|
|
680
|
+
// Accept either the structured template format (table with MET/N/A)
|
|
681
|
+
// or prose evidence patterns the validation agent may emit.
|
|
682
|
+
const structuredMatch =
|
|
662
683
|
validationContent.includes("Operational") &&
|
|
663
684
|
(validationContent.includes("MET") || validationContent.includes("N/A"));
|
|
685
|
+
const proseMatch =
|
|
686
|
+
/[Oo]perational[\s:][^\n]*(?:pass|verified|confirmed|met|complete|true|yes|addressed|covered|n\/a|not\s+applicable)/i.test(validationContent);
|
|
687
|
+
const hasOperationalCheck = structuredMatch || proseMatch;
|
|
664
688
|
if (!hasOperationalCheck) {
|
|
665
689
|
return {
|
|
666
690
|
action: "stop" as const,
|
|
@@ -67,6 +67,7 @@ import {
|
|
|
67
67
|
getDebugLogPath,
|
|
68
68
|
} from "./debug-logger.js";
|
|
69
69
|
import { parseUnitId } from "./unit-id.js";
|
|
70
|
+
import { setLogBasePath } from "./workflow-logger.js";
|
|
70
71
|
import type { AutoSession } from "./auto/session.js";
|
|
71
72
|
import {
|
|
72
73
|
existsSync,
|
|
@@ -461,6 +462,7 @@ export async function bootstrapAutoSession(
|
|
|
461
462
|
s.verbose = verboseMode;
|
|
462
463
|
s.cmdCtx = ctx;
|
|
463
464
|
s.basePath = base;
|
|
465
|
+
setLogBasePath(base);
|
|
464
466
|
s.unitDispatchCount.clear();
|
|
465
467
|
s.unitRecoveryCount.clear();
|
|
466
468
|
s.lastBudgetAlertLevel = 0;
|
|
@@ -15,6 +15,8 @@ import { computeBudgets, resolveExecutorContextWindow } from "./context-budget.j
|
|
|
15
15
|
import {
|
|
16
16
|
getInFlightToolCount,
|
|
17
17
|
getOldestInFlightToolStart,
|
|
18
|
+
clearInFlightTools,
|
|
19
|
+
hasInteractiveToolInFlight,
|
|
18
20
|
} from "./auto-tool-tracking.js";
|
|
19
21
|
import { detectWorkingTreeActivity } from "./auto-supervisor.js";
|
|
20
22
|
import { closeoutUnit, type CloseoutOptions } from "./auto-unit-closeout.js";
|
|
@@ -146,7 +148,17 @@ export function startUnitSupervision(sctx: SupervisionContext): void {
|
|
|
146
148
|
|
|
147
149
|
// Agent has tool calls currently executing — not idle, just waiting.
|
|
148
150
|
// But only suppress recovery if the tool started recently.
|
|
151
|
+
let stalledToolDetected = false;
|
|
149
152
|
if (getInFlightToolCount() > 0) {
|
|
153
|
+
// User-interactive tools (ask_user_questions, secure_env_collect) block
|
|
154
|
+
// waiting for human input by design — never treat them as stalled (#2676).
|
|
155
|
+
if (hasInteractiveToolInFlight()) {
|
|
156
|
+
writeUnitRuntimeRecord(s.basePath, unitType, unitId, s.currentUnit.startedAt, {
|
|
157
|
+
lastProgressAt: Date.now(),
|
|
158
|
+
lastProgressKind: "interactive-tool-waiting",
|
|
159
|
+
});
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
150
162
|
const oldestStart = getOldestInFlightToolStart()!;
|
|
151
163
|
const toolAgeMs = Date.now() - oldestStart;
|
|
152
164
|
if (toolAgeMs < idleTimeoutMs) {
|
|
@@ -156,6 +168,12 @@ export function startUnitSupervision(sctx: SupervisionContext): void {
|
|
|
156
168
|
});
|
|
157
169
|
return;
|
|
158
170
|
}
|
|
171
|
+
// Tool has been in-flight longer than idle timeout — treat as hung.
|
|
172
|
+
// Clear the stale entries so subsequent ticks don't re-detect them,
|
|
173
|
+
// and set the flag so the filesystem-activity check below does not
|
|
174
|
+
// override the stall verdict (#2527).
|
|
175
|
+
stalledToolDetected = true;
|
|
176
|
+
clearInFlightTools();
|
|
159
177
|
ctx.ui.notify(
|
|
160
178
|
`Stalled tool detected: a tool has been in-flight for ${Math.round(toolAgeMs / 60000)}min. Treating as hung — attempting idle recovery.`,
|
|
161
179
|
"warning",
|
|
@@ -163,7 +181,9 @@ export function startUnitSupervision(sctx: SupervisionContext): void {
|
|
|
163
181
|
}
|
|
164
182
|
|
|
165
183
|
// Check if the agent is producing work on disk.
|
|
166
|
-
|
|
184
|
+
// Skip this when a stalled tool was just detected — filesystem changes
|
|
185
|
+
// from earlier in the task should not override the stall verdict (#2527).
|
|
186
|
+
if (!stalledToolDetected && detectWorkingTreeActivity(s.basePath)) {
|
|
167
187
|
writeUnitRuntimeRecord(s.basePath, unitType, unitId, s.currentUnit.startedAt, {
|
|
168
188
|
lastProgressAt: Date.now(),
|
|
169
189
|
lastProgressKind: "filesystem-activity",
|
|
@@ -180,6 +200,10 @@ export function startUnitSupervision(sctx: SupervisionContext): void {
|
|
|
180
200
|
const recovery = await recoverTimedOutUnit(ctx, pi, unitType, unitId, "idle", buildRecoveryContext());
|
|
181
201
|
if (recovery === "recovered") return;
|
|
182
202
|
|
|
203
|
+
// Guard: recoverTimedOutUnit is async — pauseAuto/stopAuto may have
|
|
204
|
+
// set s.currentUnit = null during the await (#2527).
|
|
205
|
+
if (!s.currentUnit) return;
|
|
206
|
+
|
|
183
207
|
writeUnitRuntimeRecord(s.basePath, unitType, unitId, s.currentUnit.startedAt, {
|
|
184
208
|
phase: "paused",
|
|
185
209
|
});
|