gsd-pi 2.50.0-dev.d210a87 → 2.51.0-dev.7d435fe
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 +4 -4
- package/dist/headless-events.d.ts +18 -0
- package/dist/headless-events.js +36 -0
- 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/claude-code-cli/stream-adapter.js +18 -19
- package/dist/resources/extensions/gsd/auto-dispatch.js +18 -0
- 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 +21 -0
- package/dist/resources/extensions/gsd/auto.js +4 -2
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +95 -69
- 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 +1 -1
- package/dist/resources/extensions/gsd/detection.js +6 -6
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +3 -3
- package/dist/resources/extensions/gsd/error-classifier.js +105 -0
- package/dist/resources/extensions/gsd/gitignore.js +7 -7
- package/dist/resources/extensions/gsd/gsd-db.js +298 -45
- 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/memory-store.js +28 -13
- package/dist/resources/extensions/gsd/milestone-actions.js +19 -0
- package/dist/resources/extensions/gsd/preferences-models.js +1 -13
- 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 +21 -2
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -10
- package/dist/resources/extensions/gsd/tools/complete-slice.js +3 -17
- package/dist/resources/extensions/gsd/tools/complete-task.js +7 -18
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +26 -17
- package/dist/resources/extensions/gsd/tools/plan-slice.js +25 -14
- package/dist/resources/extensions/gsd/tools/plan-task.js +21 -11
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +47 -37
- package/dist/resources/extensions/gsd/tools/replan-slice.js +49 -38
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +23 -16
- 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/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +21 -21
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- 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_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 +2 -2
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- 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 +2 -2
- 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_client-reference-manifest.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_client-reference-manifest.js +1 -1
- 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_client-reference-manifest.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_client-reference-manifest.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_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route.js +1 -1
- 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_client-reference-manifest.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_client-reference-manifest.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_client-reference-manifest.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_client-reference-manifest.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_client-reference-manifest.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_client-reference-manifest.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_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +1 -1
- 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_client-reference-manifest.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_client-reference-manifest.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_client-reference-manifest.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_client-reference-manifest.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_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.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_client-reference-manifest.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_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 +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
- 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 +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +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 +21 -21
- package/dist/web/standalone/.next/server/chunks/2229.js +2 -2
- 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/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.21054f459af5cc78.js +9 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-cfc9a116e6450a6b.js → webpack-024d82be84800e52.js} +1 -1
- package/dist/web/standalone/.next/static/css/a58ef8a151aa0493.css +1 -0
- package/dist/wizard.js +4 -1
- package/package.json +2 -2
- 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/pkg/package.json +1 -1
- package/src/resources/extensions/async-jobs/async-bash-tool.ts +22 -11
- 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/gsd/auto-dispatch.ts +19 -0
- 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 +21 -0
- package/src/resources/extensions/gsd/auto.ts +5 -2
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +115 -72
- 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 +1 -1
- package/src/resources/extensions/gsd/detection.ts +6 -6
- package/src/resources/extensions/gsd/docs/preferences-reference.md +3 -3
- package/src/resources/extensions/gsd/error-classifier.ts +139 -0
- package/src/resources/extensions/gsd/gitignore.ts +7 -7
- package/src/resources/extensions/gsd/gsd-db.ts +355 -63
- 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/memory-store.ts +29 -18
- package/src/resources/extensions/gsd/milestone-actions.ts +17 -0
- package/src/resources/extensions/gsd/preferences-models.ts +1 -13
- 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 +22 -2
- package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +61 -0
- 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/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 +1 -1
- 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/none-mode-gates.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +91 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +77 -70
- 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/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/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 +3 -14
- package/src/resources/extensions/gsd/tools/complete-slice.ts +3 -21
- package/src/resources/extensions/gsd/tools/complete-task.ts +9 -22
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +28 -18
- package/src/resources/extensions/gsd/tools/plan-slice.ts +28 -16
- package/src/resources/extensions/gsd/tools/plan-task.ts +24 -12
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +54 -42
- package/src/resources/extensions/gsd/tools/replan-slice.ts +53 -40
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +26 -20
- 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/dist/web/standalone/.next/static/chunks/4024.9ad5def014d90ce4.js +0 -9
- 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/{yJIyd5cXPNpmXTv18ZlyC → RqOU-jOv9uZ1Q03P6L6nn}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{yJIyd5cXPNpmXTv18ZlyC → RqOU-jOv9uZ1Q03P6L6nn}/_ssgManifest.js +0 -0
- /package/src/resources/extensions/gsd/templates/{preferences.md → PREFERENCES.md} +0 -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.
|
|
@@ -319,6 +323,22 @@ export function syncGsdStateToWorktree(mainBasePath, worktreePath_) {
|
|
|
319
323
|
}
|
|
320
324
|
}
|
|
321
325
|
}
|
|
326
|
+
// Forward-sync preferences.md from project root to worktree (additive only).
|
|
327
|
+
// NOT in ROOT_STATE_FILES because syncWorktreeStateBack() must never overwrite
|
|
328
|
+
// the project root's preferences — the project root is authoritative (#2684).
|
|
329
|
+
{
|
|
330
|
+
const src = join(mainGsd, "preferences.md");
|
|
331
|
+
const dst = join(wtGsd, "preferences.md");
|
|
332
|
+
if (existsSync(src) && !existsSync(dst)) {
|
|
333
|
+
try {
|
|
334
|
+
cpSync(src, dst);
|
|
335
|
+
synced.push("preferences.md");
|
|
336
|
+
}
|
|
337
|
+
catch {
|
|
338
|
+
/* non-fatal */
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
322
342
|
// Sync milestones: copy entire milestone directories that are missing
|
|
323
343
|
const mainMilestonesDir = join(mainGsd, "milestones");
|
|
324
344
|
const wtMilestonesDir = join(wtGsd, "milestones");
|
|
@@ -801,6 +821,7 @@ function copyPlanningArtifacts(srcBase, wtPath) {
|
|
|
801
821
|
"STATE.md",
|
|
802
822
|
"KNOWLEDGE.md",
|
|
803
823
|
"OVERRIDES.md",
|
|
824
|
+
"preferences.md",
|
|
804
825
|
]) {
|
|
805
826
|
safeCopy(join(srcGsd, file), join(dstGsd, file), { force: true });
|
|
806
827
|
}
|
|
@@ -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);
|
|
@@ -815,6 +816,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
815
816
|
s.stepMode = requestedStepMode;
|
|
816
817
|
s.cmdCtx = ctx;
|
|
817
818
|
s.basePath = base;
|
|
819
|
+
setLogBasePath(base);
|
|
818
820
|
s.unitDispatchCount.clear();
|
|
819
821
|
s.unitLifetimeDispatches.clear();
|
|
820
822
|
if (!getLedger())
|
|
@@ -1,12 +1,33 @@
|
|
|
1
1
|
import { checkAutoStartAfterDiscuss } from "../guided-flow.js";
|
|
2
2
|
import { getAutoDashboardData, getAutoModeStartModel, isAutoActive, pauseAuto } from "../auto.js";
|
|
3
|
-
import { getNextFallbackModel,
|
|
4
|
-
import {
|
|
3
|
+
import { getNextFallbackModel, resolveModelWithFallbacksForUnit } from "../preferences.js";
|
|
4
|
+
import { pauseAutoForProviderError } from "../provider-error-pause.js";
|
|
5
5
|
import { isSessionSwitchInFlight, resolveAgentEnd } from "../auto-loop.js";
|
|
6
|
+
import { resolveModelId } from "../auto-model-selection.js";
|
|
6
7
|
import { clearDiscussionFlowState } from "./write-gate.js";
|
|
7
|
-
|
|
8
|
+
import { classifyError, createRetryState, resetRetryState, isTransient, } from "../error-classifier.js";
|
|
9
|
+
const retryState = createRetryState();
|
|
10
|
+
const MAX_NETWORK_RETRIES = 2;
|
|
8
11
|
const MAX_TRANSIENT_AUTO_RESUMES = 3;
|
|
9
|
-
|
|
12
|
+
async function pauseTransientWithBackoff(cls, pi, ctx, errorDetail, isRateLimit) {
|
|
13
|
+
retryState.consecutiveTransientCount += 1;
|
|
14
|
+
const baseRetryAfterMs = "retryAfterMs" in cls ? cls.retryAfterMs : 15_000;
|
|
15
|
+
const retryAfterMs = baseRetryAfterMs * 2 ** Math.max(0, retryState.consecutiveTransientCount - 1);
|
|
16
|
+
const allowAutoResume = retryState.consecutiveTransientCount <= MAX_TRANSIENT_AUTO_RESUMES;
|
|
17
|
+
if (!allowAutoResume) {
|
|
18
|
+
ctx.ui.notify(`Transient provider errors persisted after ${MAX_TRANSIENT_AUTO_RESUMES} auto-resume attempts. Pausing for manual review.`, "warning");
|
|
19
|
+
}
|
|
20
|
+
await pauseAutoForProviderError(ctx.ui, errorDetail, () => pauseAuto(ctx, pi), {
|
|
21
|
+
isRateLimit,
|
|
22
|
+
isTransient: allowAutoResume,
|
|
23
|
+
retryAfterMs,
|
|
24
|
+
resume: allowAutoResume
|
|
25
|
+
? () => {
|
|
26
|
+
pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution — provider error recovery delay elapsed.", display: false }, { triggerTurn: true });
|
|
27
|
+
}
|
|
28
|
+
: undefined,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
10
31
|
export async function handleAgentEnd(pi, event, ctx) {
|
|
11
32
|
if (checkAutoStartAfterDiscuss()) {
|
|
12
33
|
clearDiscussionFlowState();
|
|
@@ -24,93 +45,98 @@ export async function handleAgentEnd(pi, event, ctx) {
|
|
|
24
45
|
if (lastMsg && "stopReason" in lastMsg && lastMsg.stopReason === "error") {
|
|
25
46
|
const errorDetail = "errorMessage" in lastMsg && lastMsg.errorMessage ? `: ${lastMsg.errorMessage}` : "";
|
|
26
47
|
const errorMsg = ("errorMessage" in lastMsg && lastMsg.errorMessage) ? String(lastMsg.errorMessage) : "";
|
|
27
|
-
|
|
48
|
+
const explicitRetryAfterMs = ("retryAfterMs" in lastMsg && typeof lastMsg.retryAfterMs === "number") ? lastMsg.retryAfterMs : undefined;
|
|
49
|
+
// ── 1. Classify ──────────────────────────────────────────────────────
|
|
50
|
+
const cls = classifyError(errorMsg, explicitRetryAfterMs);
|
|
51
|
+
// ── 2. Decide & Act ──────────────────────────────────────────────────
|
|
52
|
+
// --- Network errors: same-model retry with backoff ---
|
|
53
|
+
if (cls.kind === "network") {
|
|
28
54
|
const currentModelId = ctx.model?.id ?? "unknown";
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
55
|
+
if (retryState.currentRetryModelId !== currentModelId) {
|
|
56
|
+
retryState.networkRetryCount = 0;
|
|
57
|
+
retryState.currentRetryModelId = currentModelId;
|
|
58
|
+
}
|
|
59
|
+
if (retryState.networkRetryCount < MAX_NETWORK_RETRIES) {
|
|
60
|
+
retryState.networkRetryCount += 1;
|
|
61
|
+
retryState.consecutiveTransientCount += 1;
|
|
62
|
+
const attempt = retryState.networkRetryCount;
|
|
63
|
+
const delayMs = attempt * cls.retryAfterMs;
|
|
64
|
+
ctx.ui.notify(`Network error on ${currentModelId}${errorDetail}. Retry ${attempt}/${MAX_NETWORK_RETRIES} in ${delayMs / 1000}s...`, "warning");
|
|
37
65
|
setTimeout(() => {
|
|
38
66
|
pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution — retrying after transient network error.", display: false }, { triggerTurn: true });
|
|
39
67
|
}, delayMs);
|
|
40
68
|
return;
|
|
41
69
|
}
|
|
42
|
-
|
|
70
|
+
// Network retries exhausted — fall through to model fallback
|
|
71
|
+
retryState.networkRetryCount = 0;
|
|
72
|
+
retryState.currentRetryModelId = undefined;
|
|
43
73
|
ctx.ui.notify(`Network retries exhausted for ${currentModelId}. Attempting model fallback.`, "warning");
|
|
44
74
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
75
|
+
// --- Rate limit: skip model fallback, go straight to pause ---
|
|
76
|
+
// Rate-limiting is a provider issue, not a model issue.
|
|
77
|
+
// Switching models won't help if the provider is throttling you.
|
|
78
|
+
if (cls.kind === "rate-limit") {
|
|
79
|
+
await pauseTransientWithBackoff(cls, pi, ctx, errorDetail, true);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
// --- Server/connection/stream errors: try model fallback first ---
|
|
83
|
+
if (cls.kind === "network" || cls.kind === "server" || cls.kind === "connection" || cls.kind === "stream") {
|
|
84
|
+
// Try model fallback
|
|
85
|
+
const dash = getAutoDashboardData();
|
|
86
|
+
if (dash.currentUnit) {
|
|
87
|
+
const modelConfig = resolveModelWithFallbacksForUnit(dash.currentUnit.type);
|
|
88
|
+
if (modelConfig && modelConfig.fallbacks.length > 0) {
|
|
89
|
+
const availableModels = ctx.modelRegistry.getAvailable();
|
|
90
|
+
const nextModelId = getNextFallbackModel(ctx.model?.id, modelConfig);
|
|
91
|
+
if (nextModelId) {
|
|
92
|
+
retryState.networkRetryCount = 0;
|
|
93
|
+
retryState.currentRetryModelId = undefined;
|
|
94
|
+
const modelToSet = resolveModelId(nextModelId, availableModels, ctx.model?.provider);
|
|
95
|
+
if (modelToSet) {
|
|
96
|
+
const ok = await pi.setModel(modelToSet, { persist: false });
|
|
97
|
+
if (ok) {
|
|
98
|
+
ctx.ui.notify(`Model error${errorDetail}. Switched to fallback: ${nextModelId} and resuming.`, "warning");
|
|
99
|
+
pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution.", display: false }, { triggerTurn: true });
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
63
102
|
}
|
|
64
103
|
}
|
|
65
104
|
}
|
|
66
105
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
106
|
+
// Try restoring session model
|
|
107
|
+
const sessionModel = getAutoModeStartModel();
|
|
108
|
+
if (sessionModel) {
|
|
109
|
+
if (ctx.model?.id !== sessionModel.id || ctx.model?.provider !== sessionModel.provider) {
|
|
110
|
+
const startModel = ctx.modelRegistry.getAvailable().find((m) => m.provider === sessionModel.provider && m.id === sessionModel.id);
|
|
111
|
+
if (startModel) {
|
|
112
|
+
const ok = await pi.setModel(startModel, { persist: false });
|
|
113
|
+
if (ok) {
|
|
114
|
+
retryState.networkRetryCount = 0;
|
|
115
|
+
retryState.currentRetryModelId = undefined;
|
|
116
|
+
ctx.ui.notify(`Model error${errorDetail}. Restored session model: ${sessionModel.provider}/${sessionModel.id} and resuming.`, "warning");
|
|
117
|
+
pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution.", display: false }, { triggerTurn: true });
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
79
120
|
}
|
|
80
121
|
}
|
|
81
122
|
}
|
|
82
123
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
consecutiveTransientErrors = 0;
|
|
90
|
-
}
|
|
91
|
-
const baseRetryAfterMs = explicitRetryAfterMs ?? classification.suggestedDelayMs;
|
|
92
|
-
const retryAfterMs = classification.isTransient
|
|
93
|
-
? baseRetryAfterMs * 2 ** Math.max(0, consecutiveTransientErrors - 1)
|
|
94
|
-
: baseRetryAfterMs;
|
|
95
|
-
const allowAutoResume = classification.isTransient && consecutiveTransientErrors <= MAX_TRANSIENT_AUTO_RESUMES;
|
|
96
|
-
if (classification.isTransient && !allowAutoResume) {
|
|
97
|
-
ctx.ui.notify(`Transient provider errors persisted after ${MAX_TRANSIENT_AUTO_RESUMES} auto-resume attempts. Pausing for manual review.`, "warning");
|
|
124
|
+
// --- Transient fallback: pause with auto-resume ---
|
|
125
|
+
if (isTransient(cls)) {
|
|
126
|
+
await pauseTransientWithBackoff(cls, pi, ctx, errorDetail, false);
|
|
127
|
+
return;
|
|
98
128
|
}
|
|
129
|
+
// --- Permanent / unknown: pause indefinitely ---
|
|
99
130
|
await pauseAutoForProviderError(ctx.ui, errorDetail, () => pauseAuto(ctx, pi), {
|
|
100
|
-
isRateLimit:
|
|
101
|
-
isTransient:
|
|
102
|
-
retryAfterMs,
|
|
103
|
-
resume: allowAutoResume
|
|
104
|
-
? () => {
|
|
105
|
-
pi.sendMessage({ customType: "gsd-auto-timeout-recovery", content: "Continue execution — provider error recovery delay elapsed.", display: false }, { triggerTurn: true });
|
|
106
|
-
}
|
|
107
|
-
: undefined,
|
|
131
|
+
isRateLimit: false,
|
|
132
|
+
isTransient: false,
|
|
133
|
+
retryAfterMs: 0,
|
|
108
134
|
});
|
|
109
135
|
return;
|
|
110
136
|
}
|
|
137
|
+
// ── Success path ─────────────────────────────────────────────────────────
|
|
111
138
|
try {
|
|
112
|
-
|
|
113
|
-
networkRetryCounters.clear();
|
|
139
|
+
resetRetryState(retryState);
|
|
114
140
|
resolveAgentEnd(event);
|
|
115
141
|
}
|
|
116
142
|
catch (err) {
|
|
@@ -2,6 +2,7 @@ import { existsSync } from "node:fs";
|
|
|
2
2
|
import { join, sep } from "node:path";
|
|
3
3
|
import { createBashTool, createEditTool, createReadTool, createWriteTool } from "@gsd/pi-coding-agent";
|
|
4
4
|
import { DEFAULT_BASH_TIMEOUT_SECS } from "../constants.js";
|
|
5
|
+
import { setLogBasePath } from "../workflow-logger.js";
|
|
5
6
|
/**
|
|
6
7
|
* Resolve the correct DB path for the current working directory.
|
|
7
8
|
* If `basePath` is inside a `.gsd/worktrees/<MID>/` directory, returns
|
|
@@ -35,9 +36,14 @@ export async function ensureDbOpen() {
|
|
|
35
36
|
const basePath = process.cwd();
|
|
36
37
|
const dbPath = resolveProjectRootDbPath(basePath);
|
|
37
38
|
const gsdDir = join(basePath, ".gsd");
|
|
39
|
+
// Derive the project root from the DB path (strip .gsd/gsd.db)
|
|
40
|
+
const projectRoot = join(dbPath, "..", "..");
|
|
38
41
|
// Open existing DB file (may be at project root for worktrees)
|
|
39
42
|
if (existsSync(dbPath)) {
|
|
40
|
-
|
|
43
|
+
const opened = db.openDatabase(dbPath);
|
|
44
|
+
if (opened)
|
|
45
|
+
setLogBasePath(projectRoot);
|
|
46
|
+
return opened;
|
|
41
47
|
}
|
|
42
48
|
// No DB file — create + migrate from Markdown if .gsd/ has content
|
|
43
49
|
if (existsSync(gsdDir)) {
|
|
@@ -47,6 +53,7 @@ export async function ensureDbOpen() {
|
|
|
47
53
|
if (hasDecisions || hasRequirements || hasMilestones) {
|
|
48
54
|
const opened = db.openDatabase(dbPath);
|
|
49
55
|
if (opened) {
|
|
56
|
+
setLogBasePath(projectRoot);
|
|
50
57
|
try {
|
|
51
58
|
const { migrateFromMarkdown } = await import("../md-importer.js");
|
|
52
59
|
migrateFromMarkdown(basePath);
|
|
@@ -58,7 +65,10 @@ export async function ensureDbOpen() {
|
|
|
58
65
|
return opened;
|
|
59
66
|
}
|
|
60
67
|
// .gsd/ exists but has no Markdown content (fresh project) — create empty DB
|
|
61
|
-
|
|
68
|
+
const opened = db.openDatabase(dbPath);
|
|
69
|
+
if (opened)
|
|
70
|
+
setLogBasePath(projectRoot);
|
|
71
|
+
return opened;
|
|
62
72
|
}
|
|
63
73
|
return false;
|
|
64
74
|
}
|
|
@@ -227,7 +227,7 @@ export function registerHooks(pi) {
|
|
|
227
227
|
pi.on("tool_execution_start", async (event) => {
|
|
228
228
|
if (!isAutoActive())
|
|
229
229
|
return;
|
|
230
|
-
markToolStart(event.toolCallId);
|
|
230
|
+
markToolStart(event.toolCallId, event.toolName);
|
|
231
231
|
});
|
|
232
232
|
pi.on("tool_execution_end", async (event) => {
|
|
233
233
|
markToolEnd(event.toolCallId);
|
|
@@ -79,16 +79,50 @@ function isMarketplacePath(pluginPath) {
|
|
|
79
79
|
}
|
|
80
80
|
/**
|
|
81
81
|
* Detect which plugin roots are marketplaces and which are legacy flat paths.
|
|
82
|
+
*
|
|
83
|
+
* Claude Code stores marketplace sources under ~/.claude/plugins/marketplaces/.
|
|
84
|
+
* Each subdirectory (e.g. marketplaces/confluent/) is a marketplace repo that
|
|
85
|
+
* contains .claude-plugin/marketplace.json. The parent directory itself does not
|
|
86
|
+
* have a marketplace.json, so we scan one level deeper when the root isn't
|
|
87
|
+
* directly a marketplace.
|
|
82
88
|
*/
|
|
83
|
-
function categorizePluginRoots(pluginRoots) {
|
|
89
|
+
export function categorizePluginRoots(pluginRoots) {
|
|
84
90
|
const marketplaces = [];
|
|
85
91
|
const flat = [];
|
|
92
|
+
const seen = new Set();
|
|
86
93
|
for (const root of pluginRoots) {
|
|
87
94
|
if (isMarketplacePath(root)) {
|
|
88
|
-
|
|
95
|
+
if (!seen.has(root)) {
|
|
96
|
+
marketplaces.push(root);
|
|
97
|
+
seen.add(root);
|
|
98
|
+
}
|
|
89
99
|
}
|
|
90
100
|
else {
|
|
91
|
-
|
|
101
|
+
// The root itself isn't a marketplace — check if it's a container of
|
|
102
|
+
// marketplaces (e.g. ~/.claude/plugins/marketplaces/ contains subdirs
|
|
103
|
+
// like confluent/, claude-hud/, each with their own marketplace.json).
|
|
104
|
+
let foundChild = false;
|
|
105
|
+
try {
|
|
106
|
+
const entries = readdirSync(root, { withFileTypes: true });
|
|
107
|
+
for (const entry of entries) {
|
|
108
|
+
if (!entry.isDirectory())
|
|
109
|
+
continue;
|
|
110
|
+
if (SKIP_DIRS.has(entry.name))
|
|
111
|
+
continue;
|
|
112
|
+
const childPath = join(root, entry.name);
|
|
113
|
+
if (isMarketplacePath(childPath) && !seen.has(childPath)) {
|
|
114
|
+
marketplaces.push(childPath);
|
|
115
|
+
seen.add(childPath);
|
|
116
|
+
foundChild = true;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
// Can't read directory — fall through to flat
|
|
122
|
+
}
|
|
123
|
+
if (!foundChild) {
|
|
124
|
+
flat.push(root);
|
|
125
|
+
}
|
|
92
126
|
}
|
|
93
127
|
}
|
|
94
128
|
return { marketplaces, flat };
|
|
@@ -145,20 +179,37 @@ export function discoverClaudePlugins(cwd) {
|
|
|
145
179
|
const seen = new Set();
|
|
146
180
|
for (const root of pluginRoots) {
|
|
147
181
|
walkDirs(root, (dir) => {
|
|
182
|
+
// Recognize both npm-style plugins (package.json) and Claude Code plugins
|
|
183
|
+
// (.claude-plugin/plugin.json). Claude marketplace-installed plugins use
|
|
184
|
+
// the latter format exclusively.
|
|
148
185
|
const pkgPath = join(dir, "package.json");
|
|
149
|
-
|
|
186
|
+
const claudePluginPath = join(dir, ".claude-plugin", "plugin.json");
|
|
187
|
+
const hasPkg = existsSync(pkgPath);
|
|
188
|
+
const hasClaudePlugin = existsSync(claudePluginPath);
|
|
189
|
+
if (!hasPkg && !hasClaudePlugin)
|
|
150
190
|
return;
|
|
151
191
|
const resolvedDir = resolve(dir);
|
|
152
192
|
if (seen.has(resolvedDir))
|
|
153
193
|
return;
|
|
154
194
|
seen.add(resolvedDir);
|
|
155
195
|
let packageName;
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
196
|
+
if (hasPkg) {
|
|
197
|
+
try {
|
|
198
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
199
|
+
packageName = pkg.name;
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
packageName = undefined;
|
|
203
|
+
}
|
|
159
204
|
}
|
|
160
|
-
|
|
161
|
-
|
|
205
|
+
else if (hasClaudePlugin) {
|
|
206
|
+
try {
|
|
207
|
+
const manifest = JSON.parse(readFileSync(claudePluginPath, "utf8"));
|
|
208
|
+
packageName = manifest.name;
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
packageName = undefined;
|
|
212
|
+
}
|
|
162
213
|
}
|
|
163
214
|
results.push({
|
|
164
215
|
type: "plugin",
|