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
|
@@ -4,15 +4,27 @@
|
|
|
4
4
|
* can distinguish "waiting for tool completion" from "truly idle".
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
interface InFlightTool {
|
|
8
|
+
startedAt: number;
|
|
9
|
+
toolName: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const inFlightTools = new Map<string, InFlightTool>();
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Tools that block waiting for human input by design.
|
|
16
|
+
* The idle watchdog must not treat these as stalled.
|
|
17
|
+
*/
|
|
18
|
+
const INTERACTIVE_TOOLS = new Set(["ask_user_questions", "secure_env_collect"]);
|
|
8
19
|
|
|
9
20
|
/**
|
|
10
21
|
* Mark a tool execution as in-flight.
|
|
11
|
-
* Records start time so the idle watchdog can detect tools
|
|
22
|
+
* Records start time and tool name so the idle watchdog can detect tools
|
|
23
|
+
* hung longer than the idle timeout while exempting interactive tools.
|
|
12
24
|
*/
|
|
13
|
-
export function markToolStart(toolCallId: string, isActive: boolean): void {
|
|
25
|
+
export function markToolStart(toolCallId: string, isActive: boolean, toolName?: string): void {
|
|
14
26
|
if (!isActive) return;
|
|
15
|
-
inFlightTools.set(toolCallId, Date.now());
|
|
27
|
+
inFlightTools.set(toolCallId, { startedAt: Date.now(), toolName: toolName ?? "unknown" });
|
|
16
28
|
}
|
|
17
29
|
|
|
18
30
|
/**
|
|
@@ -29,7 +41,7 @@ export function getOldestInFlightToolAgeMs(): number {
|
|
|
29
41
|
if (inFlightTools.size === 0) return 0;
|
|
30
42
|
let oldestStart = Infinity;
|
|
31
43
|
for (const t of inFlightTools.values()) {
|
|
32
|
-
if (t < oldestStart) oldestStart = t;
|
|
44
|
+
if (t.startedAt < oldestStart) oldestStart = t.startedAt;
|
|
33
45
|
}
|
|
34
46
|
return Date.now() - oldestStart;
|
|
35
47
|
}
|
|
@@ -48,11 +60,23 @@ export function getOldestInFlightToolStart(): number | undefined {
|
|
|
48
60
|
if (inFlightTools.size === 0) return undefined;
|
|
49
61
|
let oldest = Infinity;
|
|
50
62
|
for (const t of inFlightTools.values()) {
|
|
51
|
-
if (t < oldest) oldest = t;
|
|
63
|
+
if (t.startedAt < oldest) oldest = t.startedAt;
|
|
52
64
|
}
|
|
53
65
|
return oldest;
|
|
54
66
|
}
|
|
55
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Returns true if any currently in-flight tool is a user-interactive tool
|
|
70
|
+
* (e.g. ask_user_questions, secure_env_collect) that blocks waiting for
|
|
71
|
+
* human input. These must be exempt from idle stall detection.
|
|
72
|
+
*/
|
|
73
|
+
export function hasInteractiveToolInFlight(): boolean {
|
|
74
|
+
for (const { toolName } of inFlightTools.values()) {
|
|
75
|
+
if (INTERACTIVE_TOOLS.has(toolName)) return true;
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
|
|
56
80
|
/**
|
|
57
81
|
* Clear all in-flight tool tracking state.
|
|
58
82
|
*/
|
|
@@ -82,6 +82,10 @@ const ROOT_STATE_FILES = [
|
|
|
82
82
|
"QUEUE.md",
|
|
83
83
|
"completed-units.json",
|
|
84
84
|
"metrics.json",
|
|
85
|
+
// NOTE: preferences.md is intentionally NOT in ROOT_STATE_FILES.
|
|
86
|
+
// Forward-sync (main → worktree) is handled explicitly in syncGsdStateToWorktree().
|
|
87
|
+
// Back-sync (worktree → main) must NEVER overwrite the project root's copy
|
|
88
|
+
// because the project root is authoritative for preferences (#2684).
|
|
85
89
|
] as const;
|
|
86
90
|
|
|
87
91
|
/**
|
|
@@ -153,6 +157,25 @@ function clearProjectRootStateFiles(basePath: string, milestoneId: string): void
|
|
|
153
157
|
}
|
|
154
158
|
}
|
|
155
159
|
|
|
160
|
+
// ─── Build Artifact Auto-Resolve ─────────────────────────────────────────────
|
|
161
|
+
|
|
162
|
+
/** Patterns for machine-generated build artifacts that can be safely
|
|
163
|
+
* auto-resolved by accepting --theirs during merge. These files are
|
|
164
|
+
* regenerable and never contain meaningful manual edits. */
|
|
165
|
+
export const SAFE_AUTO_RESOLVE_PATTERNS: RegExp[] = [
|
|
166
|
+
/\.tsbuildinfo$/,
|
|
167
|
+
/\.pyc$/,
|
|
168
|
+
/\/__pycache__\//,
|
|
169
|
+
/\.DS_Store$/,
|
|
170
|
+
/\.map$/,
|
|
171
|
+
];
|
|
172
|
+
|
|
173
|
+
/** Returns true if the file path is safe to auto-resolve during merge.
|
|
174
|
+
* Covers `.gsd/` state files and common build artifacts. */
|
|
175
|
+
export const isSafeToAutoResolve = (filePath: string): boolean =>
|
|
176
|
+
filePath.startsWith(".gsd/") ||
|
|
177
|
+
SAFE_AUTO_RESOLVE_PATTERNS.some((re) => re.test(filePath));
|
|
178
|
+
|
|
156
179
|
// ─── Dispatch-Level Sync (project root ↔ worktree) ──────────────────────────
|
|
157
180
|
|
|
158
181
|
/**
|
|
@@ -416,6 +439,22 @@ export function syncGsdStateToWorktree(
|
|
|
416
439
|
}
|
|
417
440
|
}
|
|
418
441
|
|
|
442
|
+
// Forward-sync preferences.md from project root to worktree (additive only).
|
|
443
|
+
// NOT in ROOT_STATE_FILES because syncWorktreeStateBack() must never overwrite
|
|
444
|
+
// the project root's preferences — the project root is authoritative (#2684).
|
|
445
|
+
{
|
|
446
|
+
const src = join(mainGsd, "preferences.md");
|
|
447
|
+
const dst = join(wtGsd, "preferences.md");
|
|
448
|
+
if (existsSync(src) && !existsSync(dst)) {
|
|
449
|
+
try {
|
|
450
|
+
cpSync(src, dst);
|
|
451
|
+
synced.push("preferences.md");
|
|
452
|
+
} catch {
|
|
453
|
+
/* non-fatal */
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
419
458
|
// Sync milestones: copy entire milestone directories that are missing
|
|
420
459
|
const mainMilestonesDir = join(mainGsd, "milestones");
|
|
421
460
|
const wtMilestonesDir = join(wtGsd, "milestones");
|
|
@@ -946,6 +985,7 @@ function copyPlanningArtifacts(srcBase: string, wtPath: string): void {
|
|
|
946
985
|
"STATE.md",
|
|
947
986
|
"KNOWLEDGE.md",
|
|
948
987
|
"OVERRIDES.md",
|
|
988
|
+
"preferences.md",
|
|
949
989
|
]) {
|
|
950
990
|
safeCopy(join(srcGsd, file), join(dstGsd, file), { force: true });
|
|
951
991
|
}
|
|
@@ -1387,30 +1427,30 @@ export function mergeMilestoneToMain(
|
|
|
1387
1427
|
: nativeConflictFiles(originalBasePath_);
|
|
1388
1428
|
|
|
1389
1429
|
if (conflictedFiles.length > 0) {
|
|
1390
|
-
// Separate
|
|
1391
|
-
// GSD state files
|
|
1392
|
-
//
|
|
1393
|
-
//
|
|
1394
|
-
const
|
|
1430
|
+
// Separate auto-resolvable conflicts (GSD state files + build artifacts)
|
|
1431
|
+
// from real code conflicts. GSD state files diverge between branches
|
|
1432
|
+
// during normal operation. Build artifacts are machine-generated and
|
|
1433
|
+
// regenerable. Both are safe to accept from the milestone branch.
|
|
1434
|
+
const autoResolvable = conflictedFiles.filter(isSafeToAutoResolve);
|
|
1395
1435
|
const codeConflicts = conflictedFiles.filter(
|
|
1396
|
-
(f) => !f
|
|
1436
|
+
(f) => !isSafeToAutoResolve(f),
|
|
1397
1437
|
);
|
|
1398
1438
|
|
|
1399
|
-
// Auto-resolve
|
|
1400
|
-
if (
|
|
1401
|
-
for (const
|
|
1439
|
+
// Auto-resolve safe conflicts by accepting the milestone branch version
|
|
1440
|
+
if (autoResolvable.length > 0) {
|
|
1441
|
+
for (const safeFile of autoResolvable) {
|
|
1402
1442
|
try {
|
|
1403
|
-
nativeCheckoutTheirs(originalBasePath_, [
|
|
1404
|
-
nativeAddPaths(originalBasePath_, [
|
|
1443
|
+
nativeCheckoutTheirs(originalBasePath_, [safeFile]);
|
|
1444
|
+
nativeAddPaths(originalBasePath_, [safeFile]);
|
|
1405
1445
|
} catch {
|
|
1406
1446
|
// If checkout --theirs fails, try removing the file from the merge
|
|
1407
1447
|
// (it's a runtime file that shouldn't be committed anyway)
|
|
1408
|
-
nativeRmForce(originalBasePath_, [
|
|
1448
|
+
nativeRmForce(originalBasePath_, [safeFile]);
|
|
1409
1449
|
}
|
|
1410
1450
|
}
|
|
1411
1451
|
}
|
|
1412
1452
|
|
|
1413
|
-
// If there are still
|
|
1453
|
+
// If there are still real code conflicts, escalate
|
|
1414
1454
|
if (codeConflicts.length > 0) {
|
|
1415
1455
|
// Pop stash before throwing so local work is not lost (#2151).
|
|
1416
1456
|
if (stashed) {
|
|
@@ -1459,7 +1499,47 @@ export function mergeMilestoneToMain(
|
|
|
1459
1499
|
encoding: "utf-8",
|
|
1460
1500
|
});
|
|
1461
1501
|
} catch {
|
|
1462
|
-
// Stash pop
|
|
1502
|
+
// Stash pop after squash merge can conflict on .gsd/ state files that
|
|
1503
|
+
// diverged between branches. Left unresolved, these UU entries block
|
|
1504
|
+
// every subsequent merge. Auto-resolve them the same way we handle
|
|
1505
|
+
// .gsd/ conflicts during the merge itself: accept HEAD (the just-committed
|
|
1506
|
+
// version) and drop the now-applied stash.
|
|
1507
|
+
const uu = nativeConflictFiles(originalBasePath_);
|
|
1508
|
+
const gsdUU = uu.filter((f) => f.startsWith(".gsd/"));
|
|
1509
|
+
const nonGsdUU = uu.filter((f) => !f.startsWith(".gsd/"));
|
|
1510
|
+
|
|
1511
|
+
if (gsdUU.length > 0) {
|
|
1512
|
+
for (const f of gsdUU) {
|
|
1513
|
+
try {
|
|
1514
|
+
// Accept the committed (HEAD) version of the state file
|
|
1515
|
+
execFileSync("git", ["checkout", "HEAD", "--", f], {
|
|
1516
|
+
cwd: originalBasePath_,
|
|
1517
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1518
|
+
encoding: "utf-8",
|
|
1519
|
+
});
|
|
1520
|
+
nativeAddPaths(originalBasePath_, [f]);
|
|
1521
|
+
} catch {
|
|
1522
|
+
// Last resort: remove the conflicted state file
|
|
1523
|
+
nativeRmForce(originalBasePath_, [f]);
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
if (nonGsdUU.length === 0) {
|
|
1529
|
+
// All conflicts were .gsd/ files — safe to drop the stash
|
|
1530
|
+
try {
|
|
1531
|
+
execFileSync("git", ["stash", "drop"], {
|
|
1532
|
+
cwd: originalBasePath_,
|
|
1533
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1534
|
+
encoding: "utf-8",
|
|
1535
|
+
});
|
|
1536
|
+
} catch { /* stash may already be consumed */ }
|
|
1537
|
+
} else {
|
|
1538
|
+
// Non-.gsd conflicts remain — leave stash for manual resolution
|
|
1539
|
+
logWarning("reconcile", "Stash pop conflict on non-.gsd files after merge", {
|
|
1540
|
+
files: nonGsdUU.join(", "),
|
|
1541
|
+
});
|
|
1542
|
+
}
|
|
1463
1543
|
}
|
|
1464
1544
|
}
|
|
1465
1545
|
|
|
@@ -73,6 +73,7 @@ import {
|
|
|
73
73
|
getOldestInFlightToolAgeMs as _getOldestInFlightToolAgeMs,
|
|
74
74
|
getInFlightToolCount,
|
|
75
75
|
getOldestInFlightToolStart,
|
|
76
|
+
hasInteractiveToolInFlight,
|
|
76
77
|
clearInFlightTools,
|
|
77
78
|
} from "./auto-tool-tracking.js";
|
|
78
79
|
import { closeoutUnit } from "./auto-unit-closeout.js";
|
|
@@ -114,6 +115,7 @@ import {
|
|
|
114
115
|
formatCost,
|
|
115
116
|
formatTokenCount,
|
|
116
117
|
} from "./metrics.js";
|
|
118
|
+
import { setLogBasePath } from "./workflow-logger.js";
|
|
117
119
|
import { join } from "node:path";
|
|
118
120
|
import { readFileSync, existsSync, mkdirSync, writeFileSync, unlinkSync } from "node:fs";
|
|
119
121
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
@@ -184,7 +186,7 @@ import {
|
|
|
184
186
|
postUnitPostVerification,
|
|
185
187
|
} from "./auto-post-unit.js";
|
|
186
188
|
import { bootstrapAutoSession, type BootstrapDeps } from "./auto-start.js";
|
|
187
|
-
import { autoLoop, resolveAgentEnd, resolveAgentEndCancelled, _resetPendingResolve, isSessionSwitchInFlight, type LoopDeps } from "./auto-loop.js";
|
|
189
|
+
import { autoLoop, resolveAgentEnd, resolveAgentEndCancelled, _resetPendingResolve, isSessionSwitchInFlight, type LoopDeps, type ErrorContext } from "./auto-loop.js";
|
|
188
190
|
import {
|
|
189
191
|
WorktreeResolver,
|
|
190
192
|
type WorktreeResolverDeps,
|
|
@@ -374,8 +376,8 @@ export function getAutoModeStartModel(): {
|
|
|
374
376
|
}
|
|
375
377
|
|
|
376
378
|
// Tool tracking — delegates to auto-tool-tracking.ts
|
|
377
|
-
export function markToolStart(toolCallId: string): void {
|
|
378
|
-
_markToolStart(toolCallId, s.active);
|
|
379
|
+
export function markToolStart(toolCallId: string, toolName?: string): void {
|
|
380
|
+
_markToolStart(toolCallId, s.active, toolName);
|
|
379
381
|
}
|
|
380
382
|
|
|
381
383
|
export function markToolEnd(toolCallId: string): void {
|
|
@@ -412,6 +414,13 @@ export function stopAutoRemote(projectRoot: string): {
|
|
|
412
414
|
const lock = readCrashLock(projectRoot);
|
|
413
415
|
if (!lock) return { found: false };
|
|
414
416
|
|
|
417
|
+
// Never SIGTERM ourselves — a stale lock with our own PID is not a remote
|
|
418
|
+
// session, it is leftover from a prior loop exit in this process. (#2730)
|
|
419
|
+
if (lock.pid === process.pid) {
|
|
420
|
+
clearLock(projectRoot);
|
|
421
|
+
return { found: false };
|
|
422
|
+
}
|
|
423
|
+
|
|
415
424
|
if (!isLockProcessAlive(lock)) {
|
|
416
425
|
// Stale lock — clean it up
|
|
417
426
|
clearLock(projectRoot);
|
|
@@ -443,6 +452,10 @@ export function checkRemoteAutoSession(projectRoot: string): {
|
|
|
443
452
|
const lock = readCrashLock(projectRoot);
|
|
444
453
|
if (!lock) return { running: false };
|
|
445
454
|
|
|
455
|
+
// Our own PID is not a "remote" session — it is a stale lock left by this
|
|
456
|
+
// process (e.g. after step-mode exit without full cleanup). (#2730)
|
|
457
|
+
if (lock.pid === process.pid) return { running: false };
|
|
458
|
+
|
|
446
459
|
if (!isLockProcessAlive(lock)) {
|
|
447
460
|
// Stale lock from a dead process — not a live remote session
|
|
448
461
|
return { running: false };
|
|
@@ -546,6 +559,16 @@ function cleanupAfterLoopExit(ctx: ExtensionContext): void {
|
|
|
546
559
|
s.active = false;
|
|
547
560
|
clearUnitTimeout();
|
|
548
561
|
|
|
562
|
+
// Clear crash lock and release session lock so the next `/gsd next` does
|
|
563
|
+
// not see a stale lock with the current PID and treat it as a "remote"
|
|
564
|
+
// session (which would cause it to SIGTERM itself). (#2730)
|
|
565
|
+
try {
|
|
566
|
+
if (lockBase()) clearLock(lockBase());
|
|
567
|
+
if (lockBase()) releaseSessionLock(lockBase());
|
|
568
|
+
} catch {
|
|
569
|
+
/* best-effort — mirror stopAuto cleanup */
|
|
570
|
+
}
|
|
571
|
+
|
|
549
572
|
ctx.ui.setStatus("gsd-auto", undefined);
|
|
550
573
|
ctx.ui.setWidget("gsd-progress", undefined);
|
|
551
574
|
ctx.ui.setFooter(undefined);
|
|
@@ -798,11 +821,14 @@ export async function stopAuto(
|
|
|
798
821
|
export async function pauseAuto(
|
|
799
822
|
ctx?: ExtensionContext,
|
|
800
823
|
_pi?: ExtensionAPI,
|
|
824
|
+
_errorContext?: ErrorContext,
|
|
801
825
|
): Promise<void> {
|
|
802
826
|
if (!s.active) return;
|
|
803
827
|
clearUnitTimeout();
|
|
804
828
|
// Unblock any pending unit promise so the auto-loop is not orphaned.
|
|
805
|
-
|
|
829
|
+
// Pass errorContext so runUnitPhase can distinguish user-initiated pause
|
|
830
|
+
// from provider-error pause and avoid hard-stopping (#2762).
|
|
831
|
+
resolveAgentEndCancelled(_errorContext);
|
|
806
832
|
|
|
807
833
|
s.pausedSessionFile = ctx?.sessionManager?.getSessionFile() ?? null;
|
|
808
834
|
|
|
@@ -1102,6 +1128,7 @@ export async function startAuto(
|
|
|
1102
1128
|
s.stepMode = requestedStepMode;
|
|
1103
1129
|
s.cmdCtx = ctx;
|
|
1104
1130
|
s.basePath = base;
|
|
1131
|
+
setLogBasePath(base);
|
|
1105
1132
|
s.unitDispatchCount.clear();
|
|
1106
1133
|
s.unitLifetimeDispatches.clear();
|
|
1107
1134
|
if (!getLedger()) initMetrics(base);
|
|
@@ -2,14 +2,56 @@ import type { ExtensionAPI, ExtensionContext } from "@gsd/pi-coding-agent";
|
|
|
2
2
|
|
|
3
3
|
import { checkAutoStartAfterDiscuss } from "../guided-flow.js";
|
|
4
4
|
import { getAutoDashboardData, getAutoModeStartModel, isAutoActive, pauseAuto } from "../auto.js";
|
|
5
|
-
import { getNextFallbackModel,
|
|
6
|
-
import {
|
|
5
|
+
import { getNextFallbackModel, resolveModelWithFallbacksForUnit } from "../preferences.js";
|
|
6
|
+
import { pauseAutoForProviderError } from "../provider-error-pause.js";
|
|
7
7
|
import { isSessionSwitchInFlight, resolveAgentEnd } from "../auto-loop.js";
|
|
8
|
+
import { resolveModelId } from "../auto-model-selection.js";
|
|
8
9
|
import { clearDiscussionFlowState } from "./write-gate.js";
|
|
10
|
+
import {
|
|
11
|
+
classifyError,
|
|
12
|
+
createRetryState,
|
|
13
|
+
resetRetryState,
|
|
14
|
+
isTransient,
|
|
15
|
+
type ErrorClass,
|
|
16
|
+
} from "../error-classifier.js";
|
|
9
17
|
|
|
10
|
-
const
|
|
18
|
+
const retryState = createRetryState();
|
|
19
|
+
const MAX_NETWORK_RETRIES = 2;
|
|
11
20
|
const MAX_TRANSIENT_AUTO_RESUMES = 3;
|
|
12
|
-
|
|
21
|
+
|
|
22
|
+
async function pauseTransientWithBackoff(
|
|
23
|
+
cls: ErrorClass,
|
|
24
|
+
pi: ExtensionAPI,
|
|
25
|
+
ctx: ExtensionContext,
|
|
26
|
+
errorDetail: string,
|
|
27
|
+
isRateLimit: boolean,
|
|
28
|
+
): Promise<void> {
|
|
29
|
+
retryState.consecutiveTransientCount += 1;
|
|
30
|
+
const baseRetryAfterMs = "retryAfterMs" in cls ? cls.retryAfterMs : 15_000;
|
|
31
|
+
const retryAfterMs = baseRetryAfterMs * 2 ** Math.max(0, retryState.consecutiveTransientCount - 1);
|
|
32
|
+
const allowAutoResume = retryState.consecutiveTransientCount <= MAX_TRANSIENT_AUTO_RESUMES;
|
|
33
|
+
if (!allowAutoResume) {
|
|
34
|
+
ctx.ui.notify(`Transient provider errors persisted after ${MAX_TRANSIENT_AUTO_RESUMES} auto-resume attempts. Pausing for manual review.`, "warning");
|
|
35
|
+
}
|
|
36
|
+
await pauseAutoForProviderError(ctx.ui, errorDetail, () => pauseAuto(ctx, pi, {
|
|
37
|
+
message: `Provider error: ${errorDetail}`,
|
|
38
|
+
category: "provider",
|
|
39
|
+
isTransient: allowAutoResume,
|
|
40
|
+
retryAfterMs,
|
|
41
|
+
}), {
|
|
42
|
+
isRateLimit,
|
|
43
|
+
isTransient: allowAutoResume,
|
|
44
|
+
retryAfterMs,
|
|
45
|
+
resume: allowAutoResume
|
|
46
|
+
? () => {
|
|
47
|
+
pi.sendMessage(
|
|
48
|
+
{ customType: "gsd-auto-timeout-recovery", content: "Continue execution — provider error recovery delay elapsed.", display: false },
|
|
49
|
+
{ triggerTurn: true },
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
: undefined,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
13
55
|
|
|
14
56
|
export async function handleAgentEnd(
|
|
15
57
|
pi: ExtensionAPI,
|
|
@@ -31,17 +73,26 @@ export async function handleAgentEnd(
|
|
|
31
73
|
if (lastMsg && "stopReason" in lastMsg && lastMsg.stopReason === "error") {
|
|
32
74
|
const errorDetail = "errorMessage" in lastMsg && lastMsg.errorMessage ? `: ${lastMsg.errorMessage}` : "";
|
|
33
75
|
const errorMsg = ("errorMessage" in lastMsg && lastMsg.errorMessage) ? String(lastMsg.errorMessage) : "";
|
|
76
|
+
const explicitRetryAfterMs = ("retryAfterMs" in lastMsg && typeof lastMsg.retryAfterMs === "number") ? lastMsg.retryAfterMs : undefined;
|
|
77
|
+
|
|
78
|
+
// ── 1. Classify ──────────────────────────────────────────────────────
|
|
79
|
+
const cls = classifyError(errorMsg, explicitRetryAfterMs);
|
|
34
80
|
|
|
35
|
-
|
|
81
|
+
// ── 2. Decide & Act ──────────────────────────────────────────────────
|
|
82
|
+
|
|
83
|
+
// --- Network errors: same-model retry with backoff ---
|
|
84
|
+
if (cls.kind === "network") {
|
|
36
85
|
const currentModelId = ctx.model?.id ?? "unknown";
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
86
|
+
if (retryState.currentRetryModelId !== currentModelId) {
|
|
87
|
+
retryState.networkRetryCount = 0;
|
|
88
|
+
retryState.currentRetryModelId = currentModelId;
|
|
89
|
+
}
|
|
90
|
+
if (retryState.networkRetryCount < MAX_NETWORK_RETRIES) {
|
|
91
|
+
retryState.networkRetryCount += 1;
|
|
92
|
+
retryState.consecutiveTransientCount += 1;
|
|
93
|
+
const attempt = retryState.networkRetryCount;
|
|
94
|
+
const delayMs = attempt * cls.retryAfterMs;
|
|
95
|
+
ctx.ui.notify(`Network error on ${currentModelId}${errorDetail}. Retry ${attempt}/${MAX_NETWORK_RETRIES} in ${delayMs / 1000}s...`, "warning");
|
|
45
96
|
setTimeout(() => {
|
|
46
97
|
pi.sendMessage(
|
|
47
98
|
{ customType: "gsd-auto-timeout-recovery", content: "Continue execution — retrying after transient network error.", display: false },
|
|
@@ -50,84 +101,79 @@ export async function handleAgentEnd(
|
|
|
50
101
|
}, delayMs);
|
|
51
102
|
return;
|
|
52
103
|
}
|
|
53
|
-
|
|
104
|
+
// Network retries exhausted — fall through to model fallback
|
|
105
|
+
retryState.networkRetryCount = 0;
|
|
106
|
+
retryState.currentRetryModelId = undefined;
|
|
54
107
|
ctx.ui.notify(`Network retries exhausted for ${currentModelId}. Attempting model fallback.`, "warning");
|
|
55
108
|
}
|
|
56
109
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
if (
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
110
|
+
// --- Transient errors: try model fallback first, then pause ---
|
|
111
|
+
// Rate limits are often per-model, so switching models can bypass them.
|
|
112
|
+
if (cls.kind === "rate-limit" || cls.kind === "network" || cls.kind === "server" || cls.kind === "connection" || cls.kind === "stream") {
|
|
113
|
+
// Try model fallback
|
|
114
|
+
const dash = getAutoDashboardData();
|
|
115
|
+
if (dash.currentUnit) {
|
|
116
|
+
const modelConfig = resolveModelWithFallbacksForUnit(dash.currentUnit.type);
|
|
117
|
+
if (modelConfig && modelConfig.fallbacks.length > 0) {
|
|
118
|
+
const availableModels = ctx.modelRegistry.getAvailable();
|
|
119
|
+
const nextModelId = getNextFallbackModel(ctx.model?.id, modelConfig);
|
|
120
|
+
if (nextModelId) {
|
|
121
|
+
retryState.networkRetryCount = 0;
|
|
122
|
+
retryState.currentRetryModelId = undefined;
|
|
123
|
+
const modelToSet = resolveModelId(nextModelId, availableModels, ctx.model?.provider);
|
|
124
|
+
if (modelToSet) {
|
|
125
|
+
const ok = await pi.setModel(modelToSet, { persist: false });
|
|
126
|
+
if (ok) {
|
|
127
|
+
ctx.ui.notify(`Model error${errorDetail}. Switched to fallback: ${nextModelId} and resuming.`, "warning");
|
|
128
|
+
pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution.", display: false }, { triggerTurn: true });
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
75
131
|
}
|
|
76
132
|
}
|
|
77
133
|
}
|
|
78
134
|
}
|
|
79
|
-
}
|
|
80
135
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
136
|
+
// Try restoring session model
|
|
137
|
+
const sessionModel = getAutoModeStartModel();
|
|
138
|
+
if (sessionModel) {
|
|
139
|
+
if (ctx.model?.id !== sessionModel.id || ctx.model?.provider !== sessionModel.provider) {
|
|
140
|
+
const startModel = ctx.modelRegistry.getAvailable().find((m) => m.provider === sessionModel.provider && m.id === sessionModel.id);
|
|
141
|
+
if (startModel) {
|
|
142
|
+
const ok = await pi.setModel(startModel, { persist: false });
|
|
143
|
+
if (ok) {
|
|
144
|
+
retryState.networkRetryCount = 0;
|
|
145
|
+
retryState.currentRetryModelId = undefined;
|
|
146
|
+
ctx.ui.notify(`Model error${errorDetail}. Restored session model: ${sessionModel.provider}/${sessionModel.id} and resuming.`, "warning");
|
|
147
|
+
pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution.", display: false }, { triggerTurn: true });
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
92
150
|
}
|
|
93
151
|
}
|
|
94
152
|
}
|
|
95
153
|
}
|
|
96
154
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
} else {
|
|
102
|
-
consecutiveTransientErrors = 0;
|
|
103
|
-
}
|
|
104
|
-
const baseRetryAfterMs = explicitRetryAfterMs ?? classification.suggestedDelayMs;
|
|
105
|
-
const retryAfterMs = classification.isTransient
|
|
106
|
-
? baseRetryAfterMs * 2 ** Math.max(0, consecutiveTransientErrors - 1)
|
|
107
|
-
: baseRetryAfterMs;
|
|
108
|
-
const allowAutoResume = classification.isTransient && consecutiveTransientErrors <= MAX_TRANSIENT_AUTO_RESUMES;
|
|
109
|
-
if (classification.isTransient && !allowAutoResume) {
|
|
110
|
-
ctx.ui.notify(`Transient provider errors persisted after ${MAX_TRANSIENT_AUTO_RESUMES} auto-resume attempts. Pausing for manual review.`, "warning");
|
|
155
|
+
// --- Transient fallback: pause with auto-resume ---
|
|
156
|
+
if (isTransient(cls)) {
|
|
157
|
+
await pauseTransientWithBackoff(cls, pi, ctx, errorDetail, cls.kind === "rate-limit");
|
|
158
|
+
return;
|
|
111
159
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
: undefined,
|
|
160
|
+
|
|
161
|
+
// --- Permanent / unknown: pause indefinitely ---
|
|
162
|
+
await pauseAutoForProviderError(ctx.ui, errorDetail, () => pauseAuto(ctx, pi, {
|
|
163
|
+
message: `Provider error: ${errorDetail}`,
|
|
164
|
+
category: "provider",
|
|
165
|
+
isTransient: false,
|
|
166
|
+
}), {
|
|
167
|
+
isRateLimit: false,
|
|
168
|
+
isTransient: false,
|
|
169
|
+
retryAfterMs: 0,
|
|
124
170
|
});
|
|
125
171
|
return;
|
|
126
172
|
}
|
|
127
173
|
|
|
174
|
+
// ── Success path ─────────────────────────────────────────────────────────
|
|
128
175
|
try {
|
|
129
|
-
|
|
130
|
-
networkRetryCounters.clear();
|
|
176
|
+
resetRetryState(retryState);
|
|
131
177
|
resolveAgentEnd(event);
|
|
132
178
|
} catch (err) {
|
|
133
179
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -139,4 +185,3 @@ export async function handleAgentEnd(
|
|
|
139
185
|
}
|
|
140
186
|
}
|
|
141
187
|
}
|
|
142
|
-
|
|
@@ -5,6 +5,7 @@ import type { ExtensionAPI } from "@gsd/pi-coding-agent";
|
|
|
5
5
|
import { createBashTool, createEditTool, createReadTool, createWriteTool } from "@gsd/pi-coding-agent";
|
|
6
6
|
|
|
7
7
|
import { DEFAULT_BASH_TIMEOUT_SECS } from "../constants.js";
|
|
8
|
+
import { setLogBasePath } from "../workflow-logger.js";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Resolve the correct DB path for the current working directory.
|
|
@@ -43,9 +44,14 @@ export async function ensureDbOpen(): Promise<boolean> {
|
|
|
43
44
|
const dbPath = resolveProjectRootDbPath(basePath);
|
|
44
45
|
const gsdDir = join(basePath, ".gsd");
|
|
45
46
|
|
|
47
|
+
// Derive the project root from the DB path (strip .gsd/gsd.db)
|
|
48
|
+
const projectRoot = join(dbPath, "..", "..");
|
|
49
|
+
|
|
46
50
|
// Open existing DB file (may be at project root for worktrees)
|
|
47
51
|
if (existsSync(dbPath)) {
|
|
48
|
-
|
|
52
|
+
const opened = db.openDatabase(dbPath);
|
|
53
|
+
if (opened) setLogBasePath(projectRoot);
|
|
54
|
+
return opened;
|
|
49
55
|
}
|
|
50
56
|
|
|
51
57
|
// No DB file — create + migrate from Markdown if .gsd/ has content
|
|
@@ -56,6 +62,7 @@ export async function ensureDbOpen(): Promise<boolean> {
|
|
|
56
62
|
if (hasDecisions || hasRequirements || hasMilestones) {
|
|
57
63
|
const opened = db.openDatabase(dbPath);
|
|
58
64
|
if (opened) {
|
|
65
|
+
setLogBasePath(projectRoot);
|
|
59
66
|
try {
|
|
60
67
|
const { migrateFromMarkdown } = await import("../md-importer.js");
|
|
61
68
|
migrateFromMarkdown(basePath);
|
|
@@ -69,7 +76,9 @@ export async function ensureDbOpen(): Promise<boolean> {
|
|
|
69
76
|
}
|
|
70
77
|
|
|
71
78
|
// .gsd/ exists but has no Markdown content (fresh project) — create empty DB
|
|
72
|
-
|
|
79
|
+
const opened = db.openDatabase(dbPath);
|
|
80
|
+
if (opened) setLogBasePath(projectRoot);
|
|
81
|
+
return opened;
|
|
73
82
|
}
|
|
74
83
|
|
|
75
84
|
return false;
|
|
@@ -245,7 +245,7 @@ export function registerHooks(pi: ExtensionAPI): void {
|
|
|
245
245
|
|
|
246
246
|
pi.on("tool_execution_start", async (event) => {
|
|
247
247
|
if (!isAutoActive()) return;
|
|
248
|
-
markToolStart(event.toolCallId);
|
|
248
|
+
markToolStart(event.toolCallId, event.toolName);
|
|
249
249
|
});
|
|
250
250
|
|
|
251
251
|
pi.on("tool_execution_end", async (event) => {
|