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
|
@@ -88,6 +88,19 @@ function makeErrorMessage(model, errorMsg) {
|
|
|
88
88
|
timestamp: Date.now(),
|
|
89
89
|
};
|
|
90
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Generator exhaustion without a terminal result means the SDK stream was
|
|
93
|
+
* interrupted mid-turn. Surface it as an error so downstream recovery logic
|
|
94
|
+
* can classify and retry it instead of treating it as a clean completion.
|
|
95
|
+
*/
|
|
96
|
+
export function makeStreamExhaustedErrorMessage(model, lastTextContent) {
|
|
97
|
+
const errorMsg = "stream_exhausted_without_result";
|
|
98
|
+
const message = makeErrorMessage(model, errorMsg);
|
|
99
|
+
if (lastTextContent) {
|
|
100
|
+
message.content = [{ type: "text", text: lastTextContent }];
|
|
101
|
+
}
|
|
102
|
+
return message;
|
|
103
|
+
}
|
|
91
104
|
// ---------------------------------------------------------------------------
|
|
92
105
|
// streamSimple implementation
|
|
93
106
|
// ---------------------------------------------------------------------------
|
|
@@ -278,25 +291,11 @@ async function pumpSdkMessages(model, context, options, stream) {
|
|
|
278
291
|
break;
|
|
279
292
|
}
|
|
280
293
|
}
|
|
281
|
-
// Generator
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
if (fallbackContent.length === 0) {
|
|
287
|
-
fallbackContent.push({ type: "text", text: "(Claude Code session ended without a response)" });
|
|
288
|
-
}
|
|
289
|
-
const fallback = {
|
|
290
|
-
role: "assistant",
|
|
291
|
-
content: fallbackContent,
|
|
292
|
-
api: "anthropic-messages",
|
|
293
|
-
provider: "claude-code",
|
|
294
|
-
model: modelId,
|
|
295
|
-
usage: { ...ZERO_USAGE },
|
|
296
|
-
stopReason: "stop",
|
|
297
|
-
timestamp: Date.now(),
|
|
298
|
-
};
|
|
299
|
-
stream.push({ type: "done", reason: "stop", message: fallback });
|
|
294
|
+
// Generator exhaustion without a terminal result is a stream interruption,
|
|
295
|
+
// not a successful completion. Emitting an error lets GSD classify it as a
|
|
296
|
+
// transient provider failure instead of advancing auto-mode state.
|
|
297
|
+
const fallback = makeStreamExhaustedErrorMessage(modelId, lastTextContent);
|
|
298
|
+
stream.push({ type: "error", reason: "error", error: fallback });
|
|
300
299
|
}
|
|
301
300
|
catch (err) {
|
|
302
301
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -25,6 +25,11 @@ function maskPreview(value) {
|
|
|
25
25
|
function shellEscapeSingle(value) {
|
|
26
26
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
27
27
|
}
|
|
28
|
+
function hydrateProcessEnv(key, value) {
|
|
29
|
+
// Make newly collected secrets immediately visible to the current session.
|
|
30
|
+
// Some extensions read process.env directly and do not reload .env on every call.
|
|
31
|
+
process.env[key] = value;
|
|
32
|
+
}
|
|
28
33
|
async function writeEnvKey(filePath, key, value) {
|
|
29
34
|
let content = "";
|
|
30
35
|
try {
|
|
@@ -246,6 +251,7 @@ async function applySecrets(provided, destination, opts) {
|
|
|
246
251
|
try {
|
|
247
252
|
await writeEnvKey(opts.envFilePath, key, value);
|
|
248
253
|
applied.push(key);
|
|
254
|
+
hydrateProcessEnv(key, value);
|
|
249
255
|
}
|
|
250
256
|
catch (err) {
|
|
251
257
|
errors.push(`${key}: ${err.message}`);
|
|
@@ -265,6 +271,7 @@ async function applySecrets(provided, destination, opts) {
|
|
|
265
271
|
}
|
|
266
272
|
else {
|
|
267
273
|
applied.push(key);
|
|
274
|
+
hydrateProcessEnv(key, value);
|
|
268
275
|
}
|
|
269
276
|
}
|
|
270
277
|
catch (err) {
|
|
@@ -15,12 +15,20 @@ import { PROJECT_FILES } from "../detection.js";
|
|
|
15
15
|
import { MergeConflictError } from "../git-service.js";
|
|
16
16
|
import { join } from "node:path";
|
|
17
17
|
import { existsSync, cpSync } from "node:fs";
|
|
18
|
-
import { logWarning } from "../workflow-logger.js";
|
|
18
|
+
import { logWarning, logError } from "../workflow-logger.js";
|
|
19
19
|
import { gsdRoot } from "../paths.js";
|
|
20
20
|
import { atomicWriteSync } from "../atomic-write.js";
|
|
21
21
|
import { verifyExpectedArtifact } from "../auto-recovery.js";
|
|
22
22
|
import { writeUnitRuntimeRecord } from "../unit-runtime.js";
|
|
23
23
|
// ─── generateMilestoneReport ──────────────────────────────────────────────────
|
|
24
|
+
/**
|
|
25
|
+
* Resolve the base path for milestone reports.
|
|
26
|
+
* Prefers originalBasePath (project root) over basePath (which may be a worktree).
|
|
27
|
+
* Exported for testing as _resolveReportBasePath.
|
|
28
|
+
*/
|
|
29
|
+
export function _resolveReportBasePath(s) {
|
|
30
|
+
return s.originalBasePath || s.basePath;
|
|
31
|
+
}
|
|
24
32
|
/**
|
|
25
33
|
* Generate and write an HTML milestone report snapshot.
|
|
26
34
|
* Extracted from the milestone-transition block in autoLoop.
|
|
@@ -30,18 +38,19 @@ async function generateMilestoneReport(s, ctx, milestoneId) {
|
|
|
30
38
|
const { generateHtmlReport } = await importExtensionModule(import.meta.url, "../export-html.js");
|
|
31
39
|
const { writeReportSnapshot } = await importExtensionModule(import.meta.url, "../reports.js");
|
|
32
40
|
const { basename } = await import("node:path");
|
|
33
|
-
const
|
|
41
|
+
const reportBasePath = _resolveReportBasePath(s);
|
|
42
|
+
const snapData = await loadVisualizerData(reportBasePath);
|
|
34
43
|
const completedMs = snapData.milestones.find((m) => m.id === milestoneId);
|
|
35
44
|
const msTitle = completedMs?.title ?? milestoneId;
|
|
36
45
|
const gsdVersion = process.env.GSD_VERSION ?? "0.0.0";
|
|
37
|
-
const projName = basename(
|
|
46
|
+
const projName = basename(reportBasePath);
|
|
38
47
|
const doneSlices = snapData.milestones.reduce((acc, m) => acc + m.slices.filter((sl) => sl.done).length, 0);
|
|
39
48
|
const totalSlices = snapData.milestones.reduce((acc, m) => acc + m.slices.length, 0);
|
|
40
49
|
const outPath = writeReportSnapshot({
|
|
41
|
-
basePath:
|
|
50
|
+
basePath: reportBasePath,
|
|
42
51
|
html: generateHtmlReport(snapData, {
|
|
43
52
|
projectName: projName,
|
|
44
|
-
projectPath:
|
|
53
|
+
projectPath: reportBasePath,
|
|
45
54
|
gsdVersion,
|
|
46
55
|
milestoneId,
|
|
47
56
|
indexRelPath: "index.html",
|
|
@@ -50,7 +59,7 @@ async function generateMilestoneReport(s, ctx, milestoneId) {
|
|
|
50
59
|
milestoneTitle: msTitle,
|
|
51
60
|
kind: "milestone",
|
|
52
61
|
projectName: projName,
|
|
53
|
-
projectPath:
|
|
62
|
+
projectPath: reportBasePath,
|
|
54
63
|
gsdVersion,
|
|
55
64
|
totalCost: snapData.totals?.cost ?? 0,
|
|
56
65
|
totalTokens: snapData.totals?.tokens.total ?? 0,
|
|
@@ -160,8 +169,11 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
160
169
|
await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
|
|
161
170
|
return { action: "break", reason: "merge-conflict" };
|
|
162
171
|
}
|
|
163
|
-
// Non-conflict merge errors —
|
|
164
|
-
|
|
172
|
+
// Non-conflict merge errors — stop auto to avoid advancing with unmerged work
|
|
173
|
+
logError("engine", "Milestone merge failed with non-conflict error", { milestone: s.currentMilestoneId, error: String(mergeErr) });
|
|
174
|
+
ctx.ui.notify(`Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /gsd auto to resume.`, "error");
|
|
175
|
+
await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
|
|
176
|
+
return { action: "break", reason: "merge-failed" };
|
|
165
177
|
}
|
|
166
178
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
167
179
|
deps.invalidateAllCaches();
|
|
@@ -228,6 +240,10 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
228
240
|
await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
|
|
229
241
|
return { action: "break", reason: "merge-conflict" };
|
|
230
242
|
}
|
|
243
|
+
logError("engine", "Milestone merge failed with non-conflict error", { milestone: s.currentMilestoneId, error: String(mergeErr) });
|
|
244
|
+
ctx.ui.notify(`Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /gsd auto to resume.`, "error");
|
|
245
|
+
await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
|
|
246
|
+
return { action: "break", reason: "merge-failed" };
|
|
231
247
|
}
|
|
232
248
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
233
249
|
}
|
|
@@ -295,6 +311,10 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
295
311
|
await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
|
|
296
312
|
return { action: "break", reason: "merge-conflict" };
|
|
297
313
|
}
|
|
314
|
+
logError("engine", "Milestone merge failed with non-conflict error", { milestone: s.currentMilestoneId, error: String(mergeErr) });
|
|
315
|
+
ctx.ui.notify(`Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /gsd auto to resume.`, "error");
|
|
316
|
+
await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
|
|
317
|
+
return { action: "break", reason: "merge-failed" };
|
|
298
318
|
}
|
|
299
319
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
300
320
|
}
|
|
@@ -753,6 +773,12 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
753
773
|
}
|
|
754
774
|
}
|
|
755
775
|
if (unitResult.status === "cancelled") {
|
|
776
|
+
// Provider-error pause: pauseAuto already handled cleanup and scheduled
|
|
777
|
+
// recovery. Don't hard-stop — just break out of the loop (#2762).
|
|
778
|
+
if (unitResult.errorContext?.category === "provider") {
|
|
779
|
+
debugLog("autoLoop", { phase: "exit", reason: "provider-pause", isTransient: unitResult.errorContext.isTransient });
|
|
780
|
+
return { action: "break", reason: "provider-pause" };
|
|
781
|
+
}
|
|
756
782
|
ctx.ui.notify(`Session creation timed out or was cancelled for ${unitType} ${unitId}. Will retry.`, "warning");
|
|
757
783
|
await deps.stopAuto(ctx, pi, "Session creation failed");
|
|
758
784
|
debugLog("autoLoop", { phase: "exit", reason: "session-failed" });
|
|
@@ -483,6 +483,24 @@ export const DISPATCH_RULES = [
|
|
|
483
483
|
match: async ({ state, mid, midTitle, basePath }) => {
|
|
484
484
|
if (state.phase !== "completing-milestone")
|
|
485
485
|
return null;
|
|
486
|
+
// Safety guard (#2675): block completion when VALIDATION verdict is
|
|
487
|
+
// needs-remediation. The state machine treats needs-remediation as
|
|
488
|
+
// terminal (to prevent validate-milestone loops per #832), but
|
|
489
|
+
// completing-milestone should NOT proceed — remediation work is needed.
|
|
490
|
+
const validationFile = resolveMilestoneFile(basePath, mid, "VALIDATION");
|
|
491
|
+
if (validationFile) {
|
|
492
|
+
const validationContent = await loadFile(validationFile);
|
|
493
|
+
if (validationContent) {
|
|
494
|
+
const verdict = extractVerdict(validationContent);
|
|
495
|
+
if (verdict === "needs-remediation") {
|
|
496
|
+
return {
|
|
497
|
+
action: "stop",
|
|
498
|
+
reason: `Cannot complete milestone ${mid}: VALIDATION verdict is "needs-remediation". Address the remediation findings and re-run validation, or update the verdict manually.`,
|
|
499
|
+
level: "warning",
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
486
504
|
// Safety guard (#1368): verify all roadmap slices have SUMMARY files.
|
|
487
505
|
const missingSlices = findMissingSummaries(basePath, mid);
|
|
488
506
|
if (missingSlices.length > 0) {
|
|
@@ -513,8 +531,12 @@ export const DISPATCH_RULES = [
|
|
|
513
531
|
if (validationPath) {
|
|
514
532
|
const validationContent = await loadFile(validationPath);
|
|
515
533
|
if (validationContent) {
|
|
516
|
-
|
|
534
|
+
// Accept either the structured template format (table with MET/N/A)
|
|
535
|
+
// or prose evidence patterns the validation agent may emit.
|
|
536
|
+
const structuredMatch = validationContent.includes("Operational") &&
|
|
517
537
|
(validationContent.includes("MET") || validationContent.includes("N/A"));
|
|
538
|
+
const proseMatch = /[Oo]perational[\s:][^\n]*(?:pass|verified|confirmed|met|complete|true|yes|addressed|covered|n\/a|not\s+applicable)/i.test(validationContent);
|
|
539
|
+
const hasOperationalCheck = structuredMatch || proseMatch;
|
|
518
540
|
if (!hasOperationalCheck) {
|
|
519
541
|
return {
|
|
520
542
|
action: "stop",
|
|
@@ -34,6 +34,7 @@ import { isDbAvailable, getMilestone } from "./gsd-db.js";
|
|
|
34
34
|
import { hideFooter } from "./auto-dashboard.js";
|
|
35
35
|
import { debugLog, enableDebug, isDebugEnabled, getDebugLogPath, } from "./debug-logger.js";
|
|
36
36
|
import { parseUnitId } from "./unit-id.js";
|
|
37
|
+
import { setLogBasePath } from "./workflow-logger.js";
|
|
37
38
|
import { existsSync, mkdirSync, readdirSync, statSync, unlinkSync, } from "node:fs";
|
|
38
39
|
import { join } from "node:path";
|
|
39
40
|
import { sep as pathSep } from "node:path";
|
|
@@ -312,6 +313,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
312
313
|
s.verbose = verboseMode;
|
|
313
314
|
s.cmdCtx = ctx;
|
|
314
315
|
s.basePath = base;
|
|
316
|
+
setLogBasePath(base);
|
|
315
317
|
s.unitDispatchCount.clear();
|
|
316
318
|
s.unitRecoveryCount.clear();
|
|
317
319
|
s.lastBudgetAlertLevel = 0;
|
|
@@ -9,7 +9,7 @@ import { readUnitRuntimeRecord, writeUnitRuntimeRecord } from "./unit-runtime.js
|
|
|
9
9
|
import { isDbAvailable, getMilestoneSlices, getSliceTasks } from "./gsd-db.js";
|
|
10
10
|
import { resolveAutoSupervisorConfig } from "./preferences.js";
|
|
11
11
|
import { computeBudgets, resolveExecutorContextWindow } from "./context-budget.js";
|
|
12
|
-
import { getInFlightToolCount, getOldestInFlightToolStart, } from "./auto-tool-tracking.js";
|
|
12
|
+
import { getInFlightToolCount, getOldestInFlightToolStart, clearInFlightTools, hasInteractiveToolInFlight, } from "./auto-tool-tracking.js";
|
|
13
13
|
import { detectWorkingTreeActivity } from "./auto-supervisor.js";
|
|
14
14
|
import { closeoutUnit } from "./auto-unit-closeout.js";
|
|
15
15
|
import { saveActivityLog } from "./activity-log.js";
|
|
@@ -116,7 +116,17 @@ export function startUnitSupervision(sctx) {
|
|
|
116
116
|
return;
|
|
117
117
|
// Agent has tool calls currently executing — not idle, just waiting.
|
|
118
118
|
// But only suppress recovery if the tool started recently.
|
|
119
|
+
let stalledToolDetected = false;
|
|
119
120
|
if (getInFlightToolCount() > 0) {
|
|
121
|
+
// User-interactive tools (ask_user_questions, secure_env_collect) block
|
|
122
|
+
// waiting for human input by design — never treat them as stalled (#2676).
|
|
123
|
+
if (hasInteractiveToolInFlight()) {
|
|
124
|
+
writeUnitRuntimeRecord(s.basePath, unitType, unitId, s.currentUnit.startedAt, {
|
|
125
|
+
lastProgressAt: Date.now(),
|
|
126
|
+
lastProgressKind: "interactive-tool-waiting",
|
|
127
|
+
});
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
120
130
|
const oldestStart = getOldestInFlightToolStart();
|
|
121
131
|
const toolAgeMs = Date.now() - oldestStart;
|
|
122
132
|
if (toolAgeMs < idleTimeoutMs) {
|
|
@@ -126,10 +136,18 @@ export function startUnitSupervision(sctx) {
|
|
|
126
136
|
});
|
|
127
137
|
return;
|
|
128
138
|
}
|
|
139
|
+
// Tool has been in-flight longer than idle timeout — treat as hung.
|
|
140
|
+
// Clear the stale entries so subsequent ticks don't re-detect them,
|
|
141
|
+
// and set the flag so the filesystem-activity check below does not
|
|
142
|
+
// override the stall verdict (#2527).
|
|
143
|
+
stalledToolDetected = true;
|
|
144
|
+
clearInFlightTools();
|
|
129
145
|
ctx.ui.notify(`Stalled tool detected: a tool has been in-flight for ${Math.round(toolAgeMs / 60000)}min. Treating as hung — attempting idle recovery.`, "warning");
|
|
130
146
|
}
|
|
131
147
|
// Check if the agent is producing work on disk.
|
|
132
|
-
|
|
148
|
+
// Skip this when a stalled tool was just detected — filesystem changes
|
|
149
|
+
// from earlier in the task should not override the stall verdict (#2527).
|
|
150
|
+
if (!stalledToolDetected && detectWorkingTreeActivity(s.basePath)) {
|
|
133
151
|
writeUnitRuntimeRecord(s.basePath, unitType, unitId, s.currentUnit.startedAt, {
|
|
134
152
|
lastProgressAt: Date.now(),
|
|
135
153
|
lastProgressKind: "filesystem-activity",
|
|
@@ -145,6 +163,10 @@ export function startUnitSupervision(sctx) {
|
|
|
145
163
|
const recovery = await recoverTimedOutUnit(ctx, pi, unitType, unitId, "idle", buildRecoveryContext());
|
|
146
164
|
if (recovery === "recovered")
|
|
147
165
|
return;
|
|
166
|
+
// Guard: recoverTimedOutUnit is async — pauseAuto/stopAuto may have
|
|
167
|
+
// set s.currentUnit = null during the await (#2527).
|
|
168
|
+
if (!s.currentUnit)
|
|
169
|
+
return;
|
|
148
170
|
writeUnitRuntimeRecord(s.basePath, unitType, unitId, s.currentUnit.startedAt, {
|
|
149
171
|
phase: "paused",
|
|
150
172
|
});
|
|
@@ -4,14 +4,20 @@
|
|
|
4
4
|
* can distinguish "waiting for tool completion" from "truly idle".
|
|
5
5
|
*/
|
|
6
6
|
const inFlightTools = new Map();
|
|
7
|
+
/**
|
|
8
|
+
* Tools that block waiting for human input by design.
|
|
9
|
+
* The idle watchdog must not treat these as stalled.
|
|
10
|
+
*/
|
|
11
|
+
const INTERACTIVE_TOOLS = new Set(["ask_user_questions", "secure_env_collect"]);
|
|
7
12
|
/**
|
|
8
13
|
* Mark a tool execution as in-flight.
|
|
9
|
-
* Records start time so the idle watchdog can detect tools
|
|
14
|
+
* Records start time and tool name so the idle watchdog can detect tools
|
|
15
|
+
* hung longer than the idle timeout while exempting interactive tools.
|
|
10
16
|
*/
|
|
11
|
-
export function markToolStart(toolCallId, isActive) {
|
|
17
|
+
export function markToolStart(toolCallId, isActive, toolName) {
|
|
12
18
|
if (!isActive)
|
|
13
19
|
return;
|
|
14
|
-
inFlightTools.set(toolCallId, Date.now());
|
|
20
|
+
inFlightTools.set(toolCallId, { startedAt: Date.now(), toolName: toolName ?? "unknown" });
|
|
15
21
|
}
|
|
16
22
|
/**
|
|
17
23
|
* Mark a tool execution as completed.
|
|
@@ -27,8 +33,8 @@ export function getOldestInFlightToolAgeMs() {
|
|
|
27
33
|
return 0;
|
|
28
34
|
let oldestStart = Infinity;
|
|
29
35
|
for (const t of inFlightTools.values()) {
|
|
30
|
-
if (t < oldestStart)
|
|
31
|
-
oldestStart = t;
|
|
36
|
+
if (t.startedAt < oldestStart)
|
|
37
|
+
oldestStart = t.startedAt;
|
|
32
38
|
}
|
|
33
39
|
return Date.now() - oldestStart;
|
|
34
40
|
}
|
|
@@ -46,11 +52,23 @@ export function getOldestInFlightToolStart() {
|
|
|
46
52
|
return undefined;
|
|
47
53
|
let oldest = Infinity;
|
|
48
54
|
for (const t of inFlightTools.values()) {
|
|
49
|
-
if (t < oldest)
|
|
50
|
-
oldest = t;
|
|
55
|
+
if (t.startedAt < oldest)
|
|
56
|
+
oldest = t.startedAt;
|
|
51
57
|
}
|
|
52
58
|
return oldest;
|
|
53
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Returns true if any currently in-flight tool is a user-interactive tool
|
|
62
|
+
* (e.g. ask_user_questions, secure_env_collect) that blocks waiting for
|
|
63
|
+
* human input. These must be exempt from idle stall detection.
|
|
64
|
+
*/
|
|
65
|
+
export function hasInteractiveToolInFlight() {
|
|
66
|
+
for (const { toolName } of inFlightTools.values()) {
|
|
67
|
+
if (INTERACTIVE_TOOLS.has(toolName))
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
54
72
|
/**
|
|
55
73
|
* Clear all in-flight tool tracking state.
|
|
56
74
|
*/
|
|
@@ -37,6 +37,10 @@ const ROOT_STATE_FILES = [
|
|
|
37
37
|
"QUEUE.md",
|
|
38
38
|
"completed-units.json",
|
|
39
39
|
"metrics.json",
|
|
40
|
+
// NOTE: preferences.md is intentionally NOT in ROOT_STATE_FILES.
|
|
41
|
+
// Forward-sync (main → worktree) is handled explicitly in syncGsdStateToWorktree().
|
|
42
|
+
// Back-sync (worktree → main) must NEVER overwrite the project root's copy
|
|
43
|
+
// because the project root is authoritative for preferences (#2684).
|
|
40
44
|
];
|
|
41
45
|
/**
|
|
42
46
|
* Check if two filesystem paths resolve to the same real location.
|
|
@@ -100,6 +104,21 @@ function clearProjectRootStateFiles(basePath, milestoneId) {
|
|
|
100
104
|
}
|
|
101
105
|
}
|
|
102
106
|
}
|
|
107
|
+
// ─── Build Artifact Auto-Resolve ─────────────────────────────────────────────
|
|
108
|
+
/** Patterns for machine-generated build artifacts that can be safely
|
|
109
|
+
* auto-resolved by accepting --theirs during merge. These files are
|
|
110
|
+
* regenerable and never contain meaningful manual edits. */
|
|
111
|
+
export const SAFE_AUTO_RESOLVE_PATTERNS = [
|
|
112
|
+
/\.tsbuildinfo$/,
|
|
113
|
+
/\.pyc$/,
|
|
114
|
+
/\/__pycache__\//,
|
|
115
|
+
/\.DS_Store$/,
|
|
116
|
+
/\.map$/,
|
|
117
|
+
];
|
|
118
|
+
/** Returns true if the file path is safe to auto-resolve during merge.
|
|
119
|
+
* Covers `.gsd/` state files and common build artifacts. */
|
|
120
|
+
export const isSafeToAutoResolve = (filePath) => filePath.startsWith(".gsd/") ||
|
|
121
|
+
SAFE_AUTO_RESOLVE_PATTERNS.some((re) => re.test(filePath));
|
|
103
122
|
// ─── Dispatch-Level Sync (project root ↔ worktree) ──────────────────────────
|
|
104
123
|
/**
|
|
105
124
|
* Sync milestone artifacts from project root INTO worktree before deriveState.
|
|
@@ -319,6 +338,22 @@ export function syncGsdStateToWorktree(mainBasePath, worktreePath_) {
|
|
|
319
338
|
}
|
|
320
339
|
}
|
|
321
340
|
}
|
|
341
|
+
// Forward-sync preferences.md from project root to worktree (additive only).
|
|
342
|
+
// NOT in ROOT_STATE_FILES because syncWorktreeStateBack() must never overwrite
|
|
343
|
+
// the project root's preferences — the project root is authoritative (#2684).
|
|
344
|
+
{
|
|
345
|
+
const src = join(mainGsd, "preferences.md");
|
|
346
|
+
const dst = join(wtGsd, "preferences.md");
|
|
347
|
+
if (existsSync(src) && !existsSync(dst)) {
|
|
348
|
+
try {
|
|
349
|
+
cpSync(src, dst);
|
|
350
|
+
synced.push("preferences.md");
|
|
351
|
+
}
|
|
352
|
+
catch {
|
|
353
|
+
/* non-fatal */
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
322
357
|
// Sync milestones: copy entire milestone directories that are missing
|
|
323
358
|
const mainMilestonesDir = join(mainGsd, "milestones");
|
|
324
359
|
const wtMilestonesDir = join(wtGsd, "milestones");
|
|
@@ -801,6 +836,7 @@ function copyPlanningArtifacts(srcBase, wtPath) {
|
|
|
801
836
|
"STATE.md",
|
|
802
837
|
"KNOWLEDGE.md",
|
|
803
838
|
"OVERRIDES.md",
|
|
839
|
+
"preferences.md",
|
|
804
840
|
]) {
|
|
805
841
|
safeCopy(join(srcGsd, file), join(dstGsd, file), { force: true });
|
|
806
842
|
}
|
|
@@ -1170,27 +1206,27 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1170
1206
|
? mergeResult.conflicts
|
|
1171
1207
|
: nativeConflictFiles(originalBasePath_);
|
|
1172
1208
|
if (conflictedFiles.length > 0) {
|
|
1173
|
-
// Separate
|
|
1174
|
-
// GSD state files
|
|
1175
|
-
//
|
|
1176
|
-
//
|
|
1177
|
-
const
|
|
1178
|
-
const codeConflicts = conflictedFiles.filter((f) => !f
|
|
1179
|
-
// Auto-resolve
|
|
1180
|
-
if (
|
|
1181
|
-
for (const
|
|
1209
|
+
// Separate auto-resolvable conflicts (GSD state files + build artifacts)
|
|
1210
|
+
// from real code conflicts. GSD state files diverge between branches
|
|
1211
|
+
// during normal operation. Build artifacts are machine-generated and
|
|
1212
|
+
// regenerable. Both are safe to accept from the milestone branch.
|
|
1213
|
+
const autoResolvable = conflictedFiles.filter(isSafeToAutoResolve);
|
|
1214
|
+
const codeConflicts = conflictedFiles.filter((f) => !isSafeToAutoResolve(f));
|
|
1215
|
+
// Auto-resolve safe conflicts by accepting the milestone branch version
|
|
1216
|
+
if (autoResolvable.length > 0) {
|
|
1217
|
+
for (const safeFile of autoResolvable) {
|
|
1182
1218
|
try {
|
|
1183
|
-
nativeCheckoutTheirs(originalBasePath_, [
|
|
1184
|
-
nativeAddPaths(originalBasePath_, [
|
|
1219
|
+
nativeCheckoutTheirs(originalBasePath_, [safeFile]);
|
|
1220
|
+
nativeAddPaths(originalBasePath_, [safeFile]);
|
|
1185
1221
|
}
|
|
1186
1222
|
catch {
|
|
1187
1223
|
// If checkout --theirs fails, try removing the file from the merge
|
|
1188
1224
|
// (it's a runtime file that shouldn't be committed anyway)
|
|
1189
|
-
nativeRmForce(originalBasePath_, [
|
|
1225
|
+
nativeRmForce(originalBasePath_, [safeFile]);
|
|
1190
1226
|
}
|
|
1191
1227
|
}
|
|
1192
1228
|
}
|
|
1193
|
-
// If there are still
|
|
1229
|
+
// If there are still real code conflicts, escalate
|
|
1194
1230
|
if (codeConflicts.length > 0) {
|
|
1195
1231
|
// Pop stash before throwing so local work is not lost (#2151).
|
|
1196
1232
|
if (stashed) {
|
|
@@ -1235,7 +1271,48 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1235
1271
|
});
|
|
1236
1272
|
}
|
|
1237
1273
|
catch {
|
|
1238
|
-
// Stash pop
|
|
1274
|
+
// Stash pop after squash merge can conflict on .gsd/ state files that
|
|
1275
|
+
// diverged between branches. Left unresolved, these UU entries block
|
|
1276
|
+
// every subsequent merge. Auto-resolve them the same way we handle
|
|
1277
|
+
// .gsd/ conflicts during the merge itself: accept HEAD (the just-committed
|
|
1278
|
+
// version) and drop the now-applied stash.
|
|
1279
|
+
const uu = nativeConflictFiles(originalBasePath_);
|
|
1280
|
+
const gsdUU = uu.filter((f) => f.startsWith(".gsd/"));
|
|
1281
|
+
const nonGsdUU = uu.filter((f) => !f.startsWith(".gsd/"));
|
|
1282
|
+
if (gsdUU.length > 0) {
|
|
1283
|
+
for (const f of gsdUU) {
|
|
1284
|
+
try {
|
|
1285
|
+
// Accept the committed (HEAD) version of the state file
|
|
1286
|
+
execFileSync("git", ["checkout", "HEAD", "--", f], {
|
|
1287
|
+
cwd: originalBasePath_,
|
|
1288
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1289
|
+
encoding: "utf-8",
|
|
1290
|
+
});
|
|
1291
|
+
nativeAddPaths(originalBasePath_, [f]);
|
|
1292
|
+
}
|
|
1293
|
+
catch {
|
|
1294
|
+
// Last resort: remove the conflicted state file
|
|
1295
|
+
nativeRmForce(originalBasePath_, [f]);
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
if (nonGsdUU.length === 0) {
|
|
1300
|
+
// All conflicts were .gsd/ files — safe to drop the stash
|
|
1301
|
+
try {
|
|
1302
|
+
execFileSync("git", ["stash", "drop"], {
|
|
1303
|
+
cwd: originalBasePath_,
|
|
1304
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1305
|
+
encoding: "utf-8",
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
catch { /* stash may already be consumed */ }
|
|
1309
|
+
}
|
|
1310
|
+
else {
|
|
1311
|
+
// Non-.gsd conflicts remain — leave stash for manual resolution
|
|
1312
|
+
logWarning("reconcile", "Stash pop conflict on non-.gsd files after merge", {
|
|
1313
|
+
files: nonGsdUU.join(", "),
|
|
1314
|
+
});
|
|
1315
|
+
}
|
|
1239
1316
|
}
|
|
1240
1317
|
}
|
|
1241
1318
|
// 9b. Safety check (#1792): if nothing was committed, verify the milestone
|
|
@@ -34,6 +34,7 @@ import { clearSkillSnapshot } from "./skill-discovery.js";
|
|
|
34
34
|
import { captureAvailableSkills, resetSkillTelemetry, } from "./skill-telemetry.js";
|
|
35
35
|
import { getRtkSessionSavings } from "../shared/rtk-session-stats.js";
|
|
36
36
|
import { initMetrics, resetMetrics, getLedger, getProjectTotals, formatCost, formatTokenCount, } from "./metrics.js";
|
|
37
|
+
import { setLogBasePath } from "./workflow-logger.js";
|
|
37
38
|
import { join } from "node:path";
|
|
38
39
|
import { readFileSync, existsSync, mkdirSync, writeFileSync, unlinkSync } from "node:fs";
|
|
39
40
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
@@ -184,8 +185,8 @@ export function getAutoModeStartModel() {
|
|
|
184
185
|
return s.autoModeStartModel;
|
|
185
186
|
}
|
|
186
187
|
// Tool tracking — delegates to auto-tool-tracking.ts
|
|
187
|
-
export function markToolStart(toolCallId) {
|
|
188
|
-
_markToolStart(toolCallId, s.active);
|
|
188
|
+
export function markToolStart(toolCallId, toolName) {
|
|
189
|
+
_markToolStart(toolCallId, s.active, toolName);
|
|
189
190
|
}
|
|
190
191
|
export function markToolEnd(toolCallId) {
|
|
191
192
|
_markToolEnd(toolCallId);
|
|
@@ -214,6 +215,12 @@ export function stopAutoRemote(projectRoot) {
|
|
|
214
215
|
const lock = readCrashLock(projectRoot);
|
|
215
216
|
if (!lock)
|
|
216
217
|
return { found: false };
|
|
218
|
+
// Never SIGTERM ourselves — a stale lock with our own PID is not a remote
|
|
219
|
+
// session, it is leftover from a prior loop exit in this process. (#2730)
|
|
220
|
+
if (lock.pid === process.pid) {
|
|
221
|
+
clearLock(projectRoot);
|
|
222
|
+
return { found: false };
|
|
223
|
+
}
|
|
217
224
|
if (!isLockProcessAlive(lock)) {
|
|
218
225
|
// Stale lock — clean it up
|
|
219
226
|
clearLock(projectRoot);
|
|
@@ -238,6 +245,10 @@ export function checkRemoteAutoSession(projectRoot) {
|
|
|
238
245
|
const lock = readCrashLock(projectRoot);
|
|
239
246
|
if (!lock)
|
|
240
247
|
return { running: false };
|
|
248
|
+
// Our own PID is not a "remote" session — it is a stale lock left by this
|
|
249
|
+
// process (e.g. after step-mode exit without full cleanup). (#2730)
|
|
250
|
+
if (lock.pid === process.pid)
|
|
251
|
+
return { running: false };
|
|
241
252
|
if (!isLockProcessAlive(lock)) {
|
|
242
253
|
// Stale lock from a dead process — not a live remote session
|
|
243
254
|
return { running: false };
|
|
@@ -320,6 +331,18 @@ function cleanupAfterLoopExit(ctx) {
|
|
|
320
331
|
s.currentUnit = null;
|
|
321
332
|
s.active = false;
|
|
322
333
|
clearUnitTimeout();
|
|
334
|
+
// Clear crash lock and release session lock so the next `/gsd next` does
|
|
335
|
+
// not see a stale lock with the current PID and treat it as a "remote"
|
|
336
|
+
// session (which would cause it to SIGTERM itself). (#2730)
|
|
337
|
+
try {
|
|
338
|
+
if (lockBase())
|
|
339
|
+
clearLock(lockBase());
|
|
340
|
+
if (lockBase())
|
|
341
|
+
releaseSessionLock(lockBase());
|
|
342
|
+
}
|
|
343
|
+
catch {
|
|
344
|
+
/* best-effort — mirror stopAuto cleanup */
|
|
345
|
+
}
|
|
323
346
|
ctx.ui.setStatus("gsd-auto", undefined);
|
|
324
347
|
ctx.ui.setWidget("gsd-progress", undefined);
|
|
325
348
|
ctx.ui.setFooter(undefined);
|
|
@@ -553,12 +576,14 @@ export async function stopAuto(ctx, pi, reason) {
|
|
|
553
576
|
* The user can interact with the agent, then `/gsd auto` resumes
|
|
554
577
|
* from disk state. Called when the user presses Escape during auto-mode.
|
|
555
578
|
*/
|
|
556
|
-
export async function pauseAuto(ctx, _pi) {
|
|
579
|
+
export async function pauseAuto(ctx, _pi, _errorContext) {
|
|
557
580
|
if (!s.active)
|
|
558
581
|
return;
|
|
559
582
|
clearUnitTimeout();
|
|
560
583
|
// Unblock any pending unit promise so the auto-loop is not orphaned.
|
|
561
|
-
|
|
584
|
+
// Pass errorContext so runUnitPhase can distinguish user-initiated pause
|
|
585
|
+
// from provider-error pause and avoid hard-stopping (#2762).
|
|
586
|
+
resolveAgentEndCancelled(_errorContext);
|
|
562
587
|
s.pausedSessionFile = ctx?.sessionManager?.getSessionFile() ?? null;
|
|
563
588
|
// Persist paused-session metadata so resume survives /exit (#1383).
|
|
564
589
|
// The fresh-start bootstrap checks for this file and restores worktree context.
|
|
@@ -815,6 +840,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
815
840
|
s.stepMode = requestedStepMode;
|
|
816
841
|
s.cmdCtx = ctx;
|
|
817
842
|
s.basePath = base;
|
|
843
|
+
setLogBasePath(base);
|
|
818
844
|
s.unitDispatchCount.clear();
|
|
819
845
|
s.unitLifetimeDispatches.clear();
|
|
820
846
|
if (!getLedger())
|