gsd-pi 2.54.0 → 2.55.0-dev.9ec7cdf
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/dist/cli.js +19 -19
- package/dist/headless-ui.d.ts +27 -1
- package/dist/headless-ui.js +203 -13
- package/dist/headless.js +60 -3
- package/dist/resources/extensions/bg-shell/bg-shell-lifecycle.js +2 -2
- package/dist/resources/extensions/bg-shell/utilities.js +34 -5
- package/dist/resources/extensions/gsd/auto/phases.js +19 -3
- package/dist/resources/extensions/gsd/auto-dispatch.js +1 -1
- package/dist/resources/extensions/gsd/auto-model-selection.js +17 -1
- package/dist/resources/extensions/gsd/auto-prompts.js +9 -0
- package/dist/resources/extensions/gsd/auto-start.js +12 -5
- package/dist/resources/extensions/gsd/auto-worktree.js +39 -14
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +5 -1
- package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +18 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +18 -5
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +20 -0
- package/dist/resources/extensions/gsd/commands/catalog.js +2 -1
- package/dist/resources/extensions/gsd/commands/handlers/parallel.js +15 -1
- package/dist/resources/extensions/gsd/crash-recovery.js +2 -2
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +413 -0
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +5 -1
- package/dist/resources/extensions/gsd/session-lock.js +46 -12
- package/dist/resources/extensions/gsd/skill-health.js +2 -2
- package/dist/resources/extensions/gsd/visualizer-overlay.js +3 -3
- package/dist/resources/extensions/shared/format-utils.js +1 -1
- package/dist/resources/extensions/subagent/worker-registry.js +2 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
- 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 +2 -2
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/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 +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
- package/dist/web/standalone/.next/server/chunks/2229.js +2 -2
- 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/6502.2305d0afd2385711.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-0c485498795110d6.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-bca0e732db0dcec3.js → webpack-4332cbd5dd1be584.js} +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/package.json +6 -4
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +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.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +14 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/model-registry.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +16 -2
- package/pkg/package.json +1 -1
- package/scripts/ensure-workspace-builds.cjs +45 -41
- package/src/resources/extensions/bg-shell/bg-shell-lifecycle.ts +2 -2
- package/src/resources/extensions/bg-shell/utilities.ts +39 -4
- package/src/resources/extensions/gsd/auto/phases.ts +25 -4
- package/src/resources/extensions/gsd/auto-dispatch.ts +1 -1
- package/src/resources/extensions/gsd/auto-model-selection.ts +21 -1
- package/src/resources/extensions/gsd/auto-prompts.ts +15 -0
- package/src/resources/extensions/gsd/auto-start.ts +13 -5
- package/src/resources/extensions/gsd/auto-worktree.ts +46 -13
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +5 -4
- package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +53 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +19 -6
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +24 -0
- package/src/resources/extensions/gsd/commands/catalog.ts +2 -1
- package/src/resources/extensions/gsd/commands/handlers/parallel.ts +19 -1
- package/src/resources/extensions/gsd/crash-recovery.ts +2 -3
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +497 -0
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +6 -1
- package/src/resources/extensions/gsd/session-lock.ts +46 -12
- package/src/resources/extensions/gsd/skill-health.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +139 -0
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/{all-milestones-complete-merge.test.ts → integration/all-milestones-complete-merge.test.ts} +3 -3
- package/src/resources/extensions/gsd/tests/{atomic-task-closeout.test.ts → integration/atomic-task-closeout.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{auto-preflight.test.ts → integration/auto-preflight.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{auto-recovery.test.ts → integration/auto-recovery.test.ts} +7 -7
- package/src/resources/extensions/gsd/tests/{auto-secrets-gate.test.ts → integration/auto-secrets-gate.test.ts} +2 -2
- package/src/resources/extensions/gsd/tests/{auto-stash-merge.test.ts → integration/auto-stash-merge.test.ts} +3 -3
- package/src/resources/extensions/gsd/tests/{auto-worktree-milestone-merge.test.ts → integration/auto-worktree-milestone-merge.test.ts} +4 -4
- package/src/resources/extensions/gsd/tests/{auto-worktree.test.ts → integration/auto-worktree.test.ts} +5 -5
- package/src/resources/extensions/gsd/tests/{continue-here.test.ts → integration/continue-here.test.ts} +3 -3
- package/src/resources/extensions/gsd/tests/{doctor-completion-deferral.test.ts → integration/doctor-completion-deferral.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{doctor-delimiter-fix.test.ts → integration/doctor-delimiter-fix.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{doctor-enhancements.test.ts → integration/doctor-enhancements.test.ts} +3 -3
- package/src/resources/extensions/gsd/tests/{doctor-environment-worktree.test.ts → integration/doctor-environment-worktree.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{doctor-environment.test.ts → integration/doctor-environment.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{doctor-fixlevel.test.ts → integration/doctor-fixlevel.test.ts} +2 -2
- package/src/resources/extensions/gsd/tests/{doctor-git.test.ts → integration/doctor-git.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{doctor-proactive.test.ts → integration/doctor-proactive.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{doctor-roadmap-summary-atomicity.test.ts → integration/doctor-roadmap-summary-atomicity.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{doctor-runtime.test.ts → integration/doctor-runtime.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{doctor.test.ts → integration/doctor.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{e2e-workflow-pipeline-integration.test.ts → integration/e2e-workflow-pipeline-integration.test.ts} +5 -5
- package/src/resources/extensions/gsd/tests/{feature-branch-lifecycle-integration.test.ts → integration/feature-branch-lifecycle-integration.test.ts} +4 -4
- package/src/resources/extensions/gsd/tests/{git-locale.test.ts → integration/git-locale.test.ts} +4 -4
- package/src/resources/extensions/gsd/tests/{git-self-heal.test.ts → integration/git-self-heal.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{git-service.test.ts → integration/git-service.test.ts} +4 -4
- package/src/resources/extensions/gsd/tests/{gitignore-tracked-gsd.test.ts → integration/gitignore-tracked-gsd.test.ts} +2 -2
- package/src/resources/extensions/gsd/tests/{idle-recovery.test.ts → integration/idle-recovery.test.ts} +3 -3
- package/src/resources/extensions/gsd/tests/{inherited-repo-home-dir.test.ts → integration/inherited-repo-home-dir.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{integration-lifecycle.test.ts → integration/integration-lifecycle.test.ts} +4 -4
- package/src/resources/extensions/gsd/tests/{integration-mixed-milestones.test.ts → integration/integration-mixed-milestones.test.ts} +6 -6
- package/src/resources/extensions/gsd/tests/{integration-proof.test.ts → integration/integration-proof.test.ts} +12 -12
- package/src/resources/extensions/gsd/tests/{migrate-command.test.ts → integration/migrate-command.test.ts} +2 -2
- package/src/resources/extensions/gsd/tests/{milestone-transition-worktree.test.ts → integration/milestone-transition-worktree.test.ts} +3 -3
- package/src/resources/extensions/gsd/tests/{parallel-merge.test.ts → integration/parallel-merge.test.ts} +3 -3
- package/src/resources/extensions/gsd/tests/{parallel-workers-multi-milestone-e2e.test.ts → integration/parallel-workers-multi-milestone-e2e.test.ts} +3 -3
- package/src/resources/extensions/gsd/tests/{paths.test.ts → integration/paths.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{plugin-importer-live.test.ts → integration/plugin-importer-live.test.ts} +2 -2
- package/src/resources/extensions/gsd/tests/{queue-completed-milestone-perf.test.ts → integration/queue-completed-milestone-perf.test.ts} +3 -3
- package/src/resources/extensions/gsd/tests/{queue-reorder-e2e.test.ts → integration/queue-reorder-e2e.test.ts} +5 -5
- package/src/resources/extensions/gsd/tests/{quick-branch-lifecycle.test.ts → integration/quick-branch-lifecycle.test.ts} +5 -5
- package/src/resources/extensions/gsd/tests/{run-uat.test.ts → integration/run-uat.test.ts} +4 -4
- package/src/resources/extensions/gsd/tests/{token-savings.test.ts → integration/token-savings.test.ts} +3 -3
- package/src/resources/extensions/gsd/tests/{worktree-e2e.test.ts → integration/worktree-e2e.test.ts} +4 -4
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +60 -0
- package/src/resources/extensions/gsd/tests/parallel-worker-lock-contention.test.ts +226 -0
- package/src/resources/extensions/gsd/tests/plan-milestone-queue-context.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +61 -19
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +98 -0
- package/src/resources/extensions/gsd/tests/register-extension-guard.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +49 -24
- package/src/resources/extensions/gsd/visualizer-overlay.ts +3 -3
- package/src/resources/extensions/shared/format-utils.ts +1 -1
- package/src/resources/extensions/subagent/worker-registry.ts +2 -1
- package/dist/web/standalone/.next/static/chunks/4024.87fd909ae0110f50.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/{KixbEdSRlU9zzYdZdrJ7A → k92jvAf8IfV4dZE3nnrAr}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{KixbEdSRlU9zzYdZdrJ7A → k92jvAf8IfV4dZE3nnrAr}/_ssgManifest.js +0 -0
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
loadManifest,
|
|
23
23
|
pruneDeadProcesses,
|
|
24
24
|
} from "./process-manager.js";
|
|
25
|
-
import { formatUptime, resolveBgShellPersistenceCwd } from "./utilities.js";
|
|
25
|
+
import { formatUptime, getBgShellLiveCwd, resolveBgShellPersistenceCwd } from "./utilities.js";
|
|
26
26
|
import { formatTokenCount } from "../shared/format-utils.js";
|
|
27
27
|
|
|
28
28
|
import type { BgShellSharedState } from "./index.js";
|
|
@@ -213,7 +213,7 @@ export function registerBgShellLifecycle(pi: ExtensionAPI, state: BgShellSharedS
|
|
|
213
213
|
return {
|
|
214
214
|
render(width: number): string[] {
|
|
215
215
|
// ── Line 1: pwd (branch) [session] ... bg status ──
|
|
216
|
-
let pwd =
|
|
216
|
+
let pwd = getBgShellLiveCwd(state.latestCtx?.cwd);
|
|
217
217
|
const home = process.env.HOME || process.env.USERPROFILE;
|
|
218
218
|
if (home && pwd.startsWith(home)) {
|
|
219
219
|
pwd = `~${pwd.slice(home.length)}`;
|
|
@@ -42,16 +42,51 @@ export function formatTimeAgo(timestamp: number): string {
|
|
|
42
42
|
return formatDuration(Date.now() - timestamp) + " ago";
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
function deriveProjectRootFromAutoWorktree(cachedCwd?: string): string | undefined {
|
|
46
|
+
if (!cachedCwd) return undefined;
|
|
47
|
+
const match = cachedCwd.match(/^(.*?)[\\/]\.gsd[\\/]worktrees[\\/][^\\/]+(?:[\\/].*)?$/);
|
|
48
|
+
return match?.[1];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function getBgShellLiveCwd(
|
|
52
|
+
cachedCwd?: string,
|
|
53
|
+
pathExists: (path: string) => boolean = existsSync,
|
|
54
|
+
getCwd: () => string = () => process.cwd(),
|
|
55
|
+
chdir: (path: string) => void = (path) => process.chdir(path),
|
|
56
|
+
): string {
|
|
57
|
+
try {
|
|
58
|
+
return getCwd();
|
|
59
|
+
} catch {
|
|
60
|
+
const projectRoot = deriveProjectRootFromAutoWorktree(cachedCwd);
|
|
61
|
+
const home = process.env.HOME || process.env.USERPROFILE;
|
|
62
|
+
const fallbacks = [projectRoot, cachedCwd, home, "/"].filter(
|
|
63
|
+
(candidate): candidate is string => Boolean(candidate),
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
for (const candidate of fallbacks) {
|
|
67
|
+
if (candidate !== "/" && !pathExists(candidate)) continue;
|
|
68
|
+
try {
|
|
69
|
+
chdir(candidate);
|
|
70
|
+
} catch {
|
|
71
|
+
// Best-effort only. Returning a known-good fallback is enough to avoid crashes.
|
|
72
|
+
}
|
|
73
|
+
return candidate;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return "/";
|
|
77
|
+
}
|
|
78
|
+
}
|
|
45
79
|
|
|
46
80
|
export function resolveBgShellPersistenceCwd(
|
|
47
81
|
cachedCwd: string,
|
|
48
|
-
liveCwd =
|
|
82
|
+
liveCwd: string | undefined = undefined,
|
|
49
83
|
pathExists: (path: string) => boolean = existsSync,
|
|
50
84
|
): string {
|
|
85
|
+
const resolvedLiveCwd = liveCwd ?? getBgShellLiveCwd(cachedCwd, pathExists);
|
|
51
86
|
const cachedIsAutoWorktree = /(?:^|[\\/])\.gsd[\\/]worktrees[\\/]/.test(cachedCwd);
|
|
52
87
|
if (!cachedIsAutoWorktree) return cachedCwd;
|
|
53
|
-
if (cachedCwd ===
|
|
54
|
-
if (!pathExists(cachedCwd)) return
|
|
55
|
-
if (
|
|
88
|
+
if (cachedCwd === resolvedLiveCwd && pathExists(cachedCwd)) return cachedCwd;
|
|
89
|
+
if (!pathExists(cachedCwd)) return resolvedLiveCwd;
|
|
90
|
+
if (resolvedLiveCwd !== cachedCwd) return resolvedLiveCwd;
|
|
56
91
|
return cachedCwd;
|
|
57
92
|
}
|
|
@@ -45,6 +45,17 @@ export function _resolveReportBasePath(s: Pick<AutoSession, "originalBasePath" |
|
|
|
45
45
|
return s.originalBasePath || s.basePath;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Resolve the authoritative project base for dispatch guards.
|
|
50
|
+
* Prior-milestone completion lives at the project root, even when the active
|
|
51
|
+
* unit is running inside an auto worktree.
|
|
52
|
+
*/
|
|
53
|
+
export function _resolveDispatchGuardBasePath(
|
|
54
|
+
s: Pick<AutoSession, "originalBasePath" | "basePath">,
|
|
55
|
+
): string {
|
|
56
|
+
return s.originalBasePath || s.basePath;
|
|
57
|
+
}
|
|
58
|
+
|
|
48
59
|
/**
|
|
49
60
|
* Generate and write an HTML milestone report snapshot.
|
|
50
61
|
* Extracted from the milestone-transition block in autoLoop.
|
|
@@ -667,9 +678,10 @@ export async function runDispatch(
|
|
|
667
678
|
prompt = preDispatchResult.prompt;
|
|
668
679
|
}
|
|
669
680
|
|
|
681
|
+
const guardBasePath = _resolveDispatchGuardBasePath(s);
|
|
670
682
|
const priorSliceBlocker = deps.getPriorSliceCompletionBlocker(
|
|
671
|
-
|
|
672
|
-
deps.getMainBranch(
|
|
683
|
+
guardBasePath,
|
|
684
|
+
deps.getMainBranch(guardBasePath),
|
|
673
685
|
unitType,
|
|
674
686
|
unitId,
|
|
675
687
|
);
|
|
@@ -707,8 +719,17 @@ export async function runGuards(
|
|
|
707
719
|
const budgetCeiling = prefs?.budget_ceiling;
|
|
708
720
|
if (budgetCeiling !== undefined && budgetCeiling > 0) {
|
|
709
721
|
const currentLedger = deps.getLedger() as { units: unknown } | null;
|
|
710
|
-
|
|
711
|
-
|
|
722
|
+
// In parallel worker mode, only count cost from the current auto-mode session
|
|
723
|
+
// to avoid hitting the ceiling due to historical project-wide spend (#2184).
|
|
724
|
+
let costUnits = currentLedger?.units;
|
|
725
|
+
if (process.env.GSD_PARALLEL_WORKER && s.autoStartTime && Array.isArray(costUnits)) {
|
|
726
|
+
const sessionStartISO = new Date(s.autoStartTime).toISOString();
|
|
727
|
+
costUnits = costUnits.filter(
|
|
728
|
+
(u: { startedAt?: string }) => u.startedAt != null && u.startedAt >= sessionStartISO,
|
|
729
|
+
);
|
|
730
|
+
}
|
|
731
|
+
const totalCost = costUnits
|
|
732
|
+
? deps.getProjectTotals(costUnits).cost
|
|
712
733
|
: 0;
|
|
713
734
|
const budgetPct = totalCost / budgetCeiling;
|
|
714
735
|
const budgetAlertLevel = deps.getBudgetAlertLevel(budgetPct);
|
|
@@ -200,7 +200,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
200
200
|
uatContent ?? "",
|
|
201
201
|
basePath,
|
|
202
202
|
),
|
|
203
|
-
pauseAfterDispatch: uatType !== "artifact-driven" && uatType !== "browser-executable" && uatType !== "runtime-executable",
|
|
203
|
+
pauseAfterDispatch: !process.env.GSD_HEADLESS && uatType !== "artifact-driven" && uatType !== "browser-executable" && uatType !== "runtime-executable",
|
|
204
204
|
};
|
|
205
205
|
},
|
|
206
206
|
},
|
|
@@ -18,6 +18,26 @@ export interface ModelSelectionResult {
|
|
|
18
18
|
routing: { tier: string; modelDowngraded: boolean } | null;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
export function resolvePreferredModelConfig(
|
|
22
|
+
unitType: string,
|
|
23
|
+
autoModeStartModel: { provider: string; id: string } | null,
|
|
24
|
+
) {
|
|
25
|
+
const explicitConfig = resolveModelWithFallbacksForUnit(unitType);
|
|
26
|
+
if (explicitConfig) return explicitConfig;
|
|
27
|
+
|
|
28
|
+
const routingConfig = resolveDynamicRoutingConfig();
|
|
29
|
+
if (!routingConfig.enabled || !routingConfig.tier_models) return undefined;
|
|
30
|
+
|
|
31
|
+
const ceilingModel = routingConfig.tier_models.heavy
|
|
32
|
+
?? (autoModeStartModel ? `${autoModeStartModel.provider}/${autoModeStartModel.id}` : undefined);
|
|
33
|
+
if (!ceilingModel) return undefined;
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
primary: ceilingModel,
|
|
37
|
+
fallbacks: [],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
21
41
|
/**
|
|
22
42
|
* Select and apply the appropriate model for a unit dispatch.
|
|
23
43
|
* Handles: per-unit-type model preferences, dynamic complexity routing,
|
|
@@ -36,7 +56,7 @@ export async function selectAndApplyModel(
|
|
|
36
56
|
autoModeStartModel: { provider: string; id: string } | null,
|
|
37
57
|
retryContext?: { isRetry: boolean; previousTier?: string },
|
|
38
58
|
): Promise<ModelSelectionResult> {
|
|
39
|
-
const modelConfig =
|
|
59
|
+
const modelConfig = resolvePreferredModelConfig(unitType, autoModeStartModel);
|
|
40
60
|
let routing: { tier: string; modelDowngraded: boolean } | null = null;
|
|
41
61
|
|
|
42
62
|
if (modelConfig) {
|
|
@@ -87,6 +87,11 @@ function buildSourceFilePaths(
|
|
|
87
87
|
paths.push(`- **Decisions**: \`${relGsdRootFile("DECISIONS")}\``);
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
const queuePath = resolveGsdRootFile(base, "QUEUE");
|
|
91
|
+
if (existsSync(queuePath)) {
|
|
92
|
+
paths.push(`- **Queue**: \`${relGsdRootFile("QUEUE")}\``);
|
|
93
|
+
}
|
|
94
|
+
|
|
90
95
|
const contextPath = resolveMilestoneFile(base, mid, "CONTEXT");
|
|
91
96
|
if (contextPath) {
|
|
92
97
|
paths.push(`- **Milestone Context**: \`${relMilestoneFile(base, mid, "CONTEXT")}\``);
|
|
@@ -915,6 +920,16 @@ export async function buildPlanMilestonePrompt(mid: string, midTitle: string, ba
|
|
|
915
920
|
const decisionsInline = await inlineDecisionsFromDb(base, mid, undefined, inlineLevel);
|
|
916
921
|
if (decisionsInline) inlined.push(decisionsInline);
|
|
917
922
|
}
|
|
923
|
+
const queuePath = resolveGsdRootFile(base, "QUEUE");
|
|
924
|
+
if (existsSync(queuePath)) {
|
|
925
|
+
const queueInline = await inlineFileSmart(
|
|
926
|
+
queuePath,
|
|
927
|
+
relGsdRootFile("QUEUE"),
|
|
928
|
+
"Project Queue",
|
|
929
|
+
`${mid} ${midTitle}`,
|
|
930
|
+
);
|
|
931
|
+
inlined.push(queueInline);
|
|
932
|
+
}
|
|
918
933
|
const knowledgeInlinePM = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
|
|
919
934
|
if (knowledgeInlinePM) inlined.push(knowledgeInlinePM);
|
|
920
935
|
inlined.push(inlineTemplate("roadmap", "Roadmap"));
|
|
@@ -131,6 +131,15 @@ export async function bootstrapAutoSession(
|
|
|
131
131
|
return false;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
// Capture the user's session model before guided-flow dispatch can apply a
|
|
135
|
+
// phase-specific planning model for a discuss turn (#2829).
|
|
136
|
+
const startModelSnapshot = ctx.model
|
|
137
|
+
? {
|
|
138
|
+
provider: ctx.model.provider,
|
|
139
|
+
id: ctx.model.id,
|
|
140
|
+
}
|
|
141
|
+
: null;
|
|
142
|
+
|
|
134
143
|
try {
|
|
135
144
|
// Validate GSD_PROJECT_ID early so the user gets immediate feedback
|
|
136
145
|
const customProjectId = process.env.GSD_PROJECT_ID;
|
|
@@ -576,12 +585,11 @@ export async function bootstrapAutoSession(
|
|
|
576
585
|
// Initialize routing history
|
|
577
586
|
initRoutingHistory(s.basePath);
|
|
578
587
|
|
|
579
|
-
//
|
|
580
|
-
|
|
581
|
-
if (currentModel) {
|
|
588
|
+
// Restore the model that was active when auto bootstrap began (#650, #2829).
|
|
589
|
+
if (startModelSnapshot) {
|
|
582
590
|
s.autoModeStartModel = {
|
|
583
|
-
provider:
|
|
584
|
-
id:
|
|
591
|
+
provider: startModelSnapshot.provider,
|
|
592
|
+
id: startModelSnapshot.id,
|
|
585
593
|
};
|
|
586
594
|
}
|
|
587
595
|
|
|
@@ -65,6 +65,8 @@ import {
|
|
|
65
65
|
} from "./native-git-bridge.js";
|
|
66
66
|
|
|
67
67
|
const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
68
|
+
const PROJECT_PREFERENCES_FILE = "PREFERENCES.md";
|
|
69
|
+
const LEGACY_PROJECT_PREFERENCES_FILE = "preferences.md";
|
|
68
70
|
|
|
69
71
|
// ─── Shared Constants & Helpers ─────────────────────────────────────────────
|
|
70
72
|
|
|
@@ -82,7 +84,7 @@ const ROOT_STATE_FILES = [
|
|
|
82
84
|
"QUEUE.md",
|
|
83
85
|
"completed-units.json",
|
|
84
86
|
"metrics.json",
|
|
85
|
-
// NOTE: preferences
|
|
87
|
+
// NOTE: project preferences are intentionally NOT in ROOT_STATE_FILES.
|
|
86
88
|
// Forward-sync (main → worktree) is handled explicitly in syncGsdStateToWorktree().
|
|
87
89
|
// Back-sync (worktree → main) must NEVER overwrite the project root's copy
|
|
88
90
|
// because the project root is authoritative for preferences (#2684).
|
|
@@ -196,6 +198,11 @@ export function syncProjectRootToWorktree(
|
|
|
196
198
|
const prGsd = join(projectRoot, ".gsd");
|
|
197
199
|
const wtGsd = join(worktreePath_, ".gsd");
|
|
198
200
|
|
|
201
|
+
// When .gsd is a symlink to the same external directory in both locations,
|
|
202
|
+
// cpSync rejects the copy because source === destination (ERR_FS_CP_EINVAL).
|
|
203
|
+
// Compare realpaths and skip when they resolve to the same physical path (#2184).
|
|
204
|
+
if (isSamePath(prGsd, wtGsd)) return;
|
|
205
|
+
|
|
199
206
|
// Copy milestone directory from project root to worktree — additive only.
|
|
200
207
|
// force:false prevents cpSync from overwriting existing worktree files.
|
|
201
208
|
// Without this, worktree-authoritative files (e.g. VALIDATION.md written
|
|
@@ -245,6 +252,11 @@ export function syncStateToProjectRoot(
|
|
|
245
252
|
const wtGsd = join(worktreePath_, ".gsd");
|
|
246
253
|
const prGsd = join(projectRoot, ".gsd");
|
|
247
254
|
|
|
255
|
+
// When .gsd is a symlink to the same external directory in both locations,
|
|
256
|
+
// cpSync rejects the copy because source === destination (ERR_FS_CP_EINVAL).
|
|
257
|
+
// Compare realpaths and skip when they resolve to the same physical path (#2184).
|
|
258
|
+
if (isSamePath(wtGsd, prGsd)) return;
|
|
259
|
+
|
|
248
260
|
// 1. STATE.md — the quick-glance status used by initial deriveState()
|
|
249
261
|
safeCopy(join(wtGsd, "STATE.md"), join(prGsd, "STATE.md"), { force: true });
|
|
250
262
|
|
|
@@ -439,18 +451,25 @@ export function syncGsdStateToWorktree(
|
|
|
439
451
|
}
|
|
440
452
|
}
|
|
441
453
|
|
|
442
|
-
// Forward-sync preferences
|
|
443
|
-
//
|
|
444
|
-
//
|
|
454
|
+
// Forward-sync project preferences from project root to worktree (additive only).
|
|
455
|
+
// Prefer the canonical uppercase file name, but keep the legacy lowercase
|
|
456
|
+
// fallback so older repos still work on case-sensitive filesystems.
|
|
445
457
|
{
|
|
446
|
-
const
|
|
447
|
-
|
|
448
|
-
if (
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
458
|
+
const worktreeHasPreferences = existsSync(join(wtGsd, PROJECT_PREFERENCES_FILE))
|
|
459
|
+
|| existsSync(join(wtGsd, LEGACY_PROJECT_PREFERENCES_FILE));
|
|
460
|
+
if (!worktreeHasPreferences) {
|
|
461
|
+
for (const file of [PROJECT_PREFERENCES_FILE, LEGACY_PROJECT_PREFERENCES_FILE] as const) {
|
|
462
|
+
const src = join(mainGsd, file);
|
|
463
|
+
const dst = join(wtGsd, file);
|
|
464
|
+
if (existsSync(src)) {
|
|
465
|
+
try {
|
|
466
|
+
cpSync(src, dst);
|
|
467
|
+
synced.push(file);
|
|
468
|
+
} catch {
|
|
469
|
+
/* non-fatal */
|
|
470
|
+
}
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
454
473
|
}
|
|
455
474
|
}
|
|
456
475
|
}
|
|
@@ -985,11 +1004,25 @@ function copyPlanningArtifacts(srcBase: string, wtPath: string): void {
|
|
|
985
1004
|
"STATE.md",
|
|
986
1005
|
"KNOWLEDGE.md",
|
|
987
1006
|
"OVERRIDES.md",
|
|
988
|
-
"preferences.md",
|
|
989
1007
|
]) {
|
|
990
1008
|
safeCopy(join(srcGsd, file), join(dstGsd, file), { force: true });
|
|
991
1009
|
}
|
|
992
1010
|
|
|
1011
|
+
// Seed canonical PREFERENCES.md when available; fall back to legacy lowercase.
|
|
1012
|
+
if (existsSync(join(srcGsd, PROJECT_PREFERENCES_FILE))) {
|
|
1013
|
+
safeCopy(
|
|
1014
|
+
join(srcGsd, PROJECT_PREFERENCES_FILE),
|
|
1015
|
+
join(dstGsd, PROJECT_PREFERENCES_FILE),
|
|
1016
|
+
{ force: true },
|
|
1017
|
+
);
|
|
1018
|
+
} else if (existsSync(join(srcGsd, LEGACY_PROJECT_PREFERENCES_FILE))) {
|
|
1019
|
+
safeCopy(
|
|
1020
|
+
join(srcGsd, LEGACY_PROJECT_PREFERENCES_FILE),
|
|
1021
|
+
join(dstGsd, LEGACY_PROJECT_PREFERENCES_FILE),
|
|
1022
|
+
{ force: true },
|
|
1023
|
+
);
|
|
1024
|
+
}
|
|
1025
|
+
|
|
993
1026
|
// Shared WAL (R012): worktrees use the project root's DB directly.
|
|
994
1027
|
// No longer copy gsd.db into the worktree — the DB path resolver in
|
|
995
1028
|
// ensureDbOpen() detects the worktree location and opens the root DB.
|
|
@@ -7,6 +7,7 @@ import { pauseAutoForProviderError } from "../provider-error-pause.js";
|
|
|
7
7
|
import { isSessionSwitchInFlight, resolveAgentEnd } from "../auto-loop.js";
|
|
8
8
|
import { resolveModelId } from "../auto-model-selection.js";
|
|
9
9
|
import { clearDiscussionFlowState } from "./write-gate.js";
|
|
10
|
+
import { resumeAutoAfterProviderDelay } from "./provider-error-resume.js";
|
|
10
11
|
import {
|
|
11
12
|
classifyError,
|
|
12
13
|
createRetryState,
|
|
@@ -44,10 +45,10 @@ async function pauseTransientWithBackoff(
|
|
|
44
45
|
retryAfterMs,
|
|
45
46
|
resume: allowAutoResume
|
|
46
47
|
? () => {
|
|
47
|
-
pi.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
);
|
|
48
|
+
void resumeAutoAfterProviderDelay(pi, ctx).catch((err) => {
|
|
49
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
50
|
+
ctx.ui.notify(`Provider error recovery delay elapsed, but auto-mode failed to resume: ${message}`, "error");
|
|
51
|
+
});
|
|
51
52
|
}
|
|
52
53
|
: undefined,
|
|
53
54
|
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExtensionAPI,
|
|
3
|
+
ExtensionCommandContext,
|
|
4
|
+
ExtensionContext,
|
|
5
|
+
} from "@gsd/pi-coding-agent";
|
|
6
|
+
|
|
7
|
+
import { getAutoDashboardData, startAuto, type AutoDashboardData } from "../auto.js";
|
|
8
|
+
|
|
9
|
+
type AutoResumeSnapshot = Pick<AutoDashboardData, "active" | "paused" | "stepMode" | "basePath">;
|
|
10
|
+
|
|
11
|
+
export interface ProviderErrorResumeDeps {
|
|
12
|
+
getSnapshot(): AutoResumeSnapshot;
|
|
13
|
+
startAuto(
|
|
14
|
+
ctx: ExtensionCommandContext,
|
|
15
|
+
pi: ExtensionAPI,
|
|
16
|
+
base: string,
|
|
17
|
+
verboseMode: boolean,
|
|
18
|
+
options?: { step?: boolean },
|
|
19
|
+
): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const defaultDeps: ProviderErrorResumeDeps = {
|
|
23
|
+
getSnapshot: () => getAutoDashboardData(),
|
|
24
|
+
startAuto,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export async function resumeAutoAfterProviderDelay(
|
|
28
|
+
pi: ExtensionAPI,
|
|
29
|
+
ctx: ExtensionContext,
|
|
30
|
+
deps: ProviderErrorResumeDeps = defaultDeps,
|
|
31
|
+
): Promise<"resumed" | "already-active" | "not-paused" | "missing-base"> {
|
|
32
|
+
const snapshot = deps.getSnapshot();
|
|
33
|
+
|
|
34
|
+
if (snapshot.active) return "already-active";
|
|
35
|
+
if (!snapshot.paused) return "not-paused";
|
|
36
|
+
|
|
37
|
+
if (!snapshot.basePath) {
|
|
38
|
+
ctx.ui.notify(
|
|
39
|
+
"Provider error recovery delay elapsed, but no paused auto-mode base path was available. Leaving auto-mode paused.",
|
|
40
|
+
"warning",
|
|
41
|
+
);
|
|
42
|
+
return "missing-base";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
await deps.startAuto(
|
|
46
|
+
ctx as ExtensionCommandContext,
|
|
47
|
+
pi,
|
|
48
|
+
snapshot.basePath,
|
|
49
|
+
false,
|
|
50
|
+
{ step: snapshot.stepMode },
|
|
51
|
+
);
|
|
52
|
+
return "resumed";
|
|
53
|
+
}
|
|
@@ -9,14 +9,28 @@ import { registerJournalTools } from "./journal-tools.js";
|
|
|
9
9
|
import { registerHooks } from "./register-hooks.js";
|
|
10
10
|
import { registerShortcuts } from "./register-shortcuts.js";
|
|
11
11
|
|
|
12
|
+
export function handleRecoverableExtensionProcessError(err: Error): boolean {
|
|
13
|
+
if ((err as NodeJS.ErrnoException).code === "EPIPE") {
|
|
14
|
+
process.exit(0);
|
|
15
|
+
}
|
|
16
|
+
if ((err as NodeJS.ErrnoException).code === "ENOENT") {
|
|
17
|
+
const syscall = (err as NodeJS.ErrnoException).syscall;
|
|
18
|
+
if (syscall?.startsWith("spawn")) {
|
|
19
|
+
process.stderr.write(`[gsd] spawn ENOENT: ${(err as any).path ?? "unknown"} — command not found\n`);
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
if (syscall === "uv_cwd") {
|
|
23
|
+
process.stderr.write(`[gsd] ENOENT (${syscall}): ${err.message}\n`);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
12
30
|
function installEpipeGuard(): void {
|
|
13
31
|
if (!process.listeners("uncaughtException").some((listener) => listener.name === "_gsdEpipeGuard")) {
|
|
14
32
|
const _gsdEpipeGuard = (err: Error): void => {
|
|
15
|
-
if ((err
|
|
16
|
-
process.exit(0);
|
|
17
|
-
}
|
|
18
|
-
if ((err as NodeJS.ErrnoException).code === "ENOENT" && (err as any).syscall?.startsWith("spawn")) {
|
|
19
|
-
process.stderr.write(`[gsd] spawn ENOENT: ${(err as any).path ?? "unknown"} — command not found\n`);
|
|
33
|
+
if (handleRecoverableExtensionProcessError(err)) {
|
|
20
34
|
return;
|
|
21
35
|
}
|
|
22
36
|
throw err;
|
|
@@ -45,4 +59,3 @@ export function registerGsdExtension(pi: ExtensionAPI): void {
|
|
|
45
59
|
registerShortcuts(pi);
|
|
46
60
|
registerHooks(pi);
|
|
47
61
|
}
|
|
48
|
-
|
|
@@ -5,6 +5,7 @@ import type { ExtensionAPI } from "@gsd/pi-coding-agent";
|
|
|
5
5
|
import { Key } from "@gsd/pi-tui";
|
|
6
6
|
|
|
7
7
|
import { GSDDashboardOverlay } from "../dashboard-overlay.js";
|
|
8
|
+
import { ParallelMonitorOverlay } from "../parallel-monitor-overlay.js";
|
|
8
9
|
import { shortcutDesc } from "../../shared/mod.js";
|
|
9
10
|
|
|
10
11
|
export function registerShortcuts(pi: ExtensionAPI): void {
|
|
@@ -29,4 +30,27 @@ export function registerShortcuts(pi: ExtensionAPI): void {
|
|
|
29
30
|
);
|
|
30
31
|
},
|
|
31
32
|
});
|
|
33
|
+
|
|
34
|
+
pi.registerShortcut(Key.ctrlAlt("p"), {
|
|
35
|
+
description: shortcutDesc("Open parallel worker monitor", "/gsd parallel watch"),
|
|
36
|
+
handler: async (ctx) => {
|
|
37
|
+
const parallelDir = join(process.cwd(), ".gsd", "parallel");
|
|
38
|
+
if (!existsSync(parallelDir)) {
|
|
39
|
+
ctx.ui.notify("No parallel workers found. Run /gsd parallel start first.", "info");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
await ctx.ui.custom<void>(
|
|
43
|
+
(tui, theme, _kb, done) => new ParallelMonitorOverlay(tui, theme, () => done()),
|
|
44
|
+
{
|
|
45
|
+
overlay: true,
|
|
46
|
+
overlayOptions: {
|
|
47
|
+
width: "90%",
|
|
48
|
+
minWidth: 80,
|
|
49
|
+
maxHeight: "92%",
|
|
50
|
+
anchor: "center",
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
);
|
|
54
|
+
},
|
|
55
|
+
});
|
|
32
56
|
}
|
|
@@ -59,7 +59,7 @@ export const TOP_LEVEL_SUBCOMMANDS: readonly GsdCommandDefinition[] = [
|
|
|
59
59
|
{ cmd: "inspect", desc: "Show SQLite DB diagnostics" },
|
|
60
60
|
{ cmd: "knowledge", desc: "Add persistent project knowledge (rule, pattern, or lesson)" },
|
|
61
61
|
{ cmd: "new-milestone", desc: "Create a milestone from a specification document (headless)" },
|
|
62
|
-
{ cmd: "parallel", desc: "Parallel milestone orchestration (start, status, stop, merge)" },
|
|
62
|
+
{ cmd: "parallel", desc: "Parallel milestone orchestration (start, status, stop, merge, watch)" },
|
|
63
63
|
{ cmd: "cmux", desc: "Manage cmux integration (status, sidebar, notifications, splits)" },
|
|
64
64
|
{ cmd: "park", desc: "Park a milestone — skip without deleting" },
|
|
65
65
|
{ cmd: "unpark", desc: "Reactivate a parked milestone" },
|
|
@@ -100,6 +100,7 @@ const NESTED_COMPLETIONS: CompletionMap = {
|
|
|
100
100
|
{ cmd: "pause", desc: "Pause a specific worker" },
|
|
101
101
|
{ cmd: "resume", desc: "Resume a paused worker" },
|
|
102
102
|
{ cmd: "merge", desc: "Merge completed milestone branches" },
|
|
103
|
+
{ cmd: "watch", desc: "Live TUI dashboard monitoring all workers" },
|
|
103
104
|
],
|
|
104
105
|
setup: [
|
|
105
106
|
{ cmd: "llm", desc: "Configure LLM provider settings" },
|
|
@@ -111,7 +111,25 @@ export async function handleParallelCommand(trimmed: string, _ctx: ExtensionComm
|
|
|
111
111
|
return true;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
if (subcommand === "watch") {
|
|
115
|
+
const root = projectRoot();
|
|
116
|
+
const { ParallelMonitorOverlay } = await import("../../parallel-monitor-overlay.js");
|
|
117
|
+
await _ctx.ui.custom<void>(
|
|
118
|
+
(tui, theme, _kb, done) => new ParallelMonitorOverlay(tui, theme, () => done(), root),
|
|
119
|
+
{
|
|
120
|
+
overlay: true,
|
|
121
|
+
overlayOptions: {
|
|
122
|
+
width: "90%",
|
|
123
|
+
minWidth: 80,
|
|
124
|
+
maxHeight: "92%",
|
|
125
|
+
anchor: "center",
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
);
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
emitParallelMessage(pi, `Unknown parallel subcommand "${subcommand}". Usage: /gsd parallel [start|status|stop|pause|resume|merge|watch]`);
|
|
115
133
|
return true;
|
|
116
134
|
}
|
|
117
135
|
|
|
@@ -14,8 +14,7 @@ import { readFileSync, unlinkSync, existsSync } from "node:fs";
|
|
|
14
14
|
import { join } from "node:path";
|
|
15
15
|
import { gsdRoot } from "./paths.js";
|
|
16
16
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
17
|
-
|
|
18
|
-
const LOCK_FILE = "auto.lock";
|
|
17
|
+
import { effectiveLockFile } from "./session-lock.js";
|
|
19
18
|
|
|
20
19
|
export interface LockData {
|
|
21
20
|
pid: number;
|
|
@@ -28,7 +27,7 @@ export interface LockData {
|
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
function lockPath(basePath: string): string {
|
|
31
|
-
return join(gsdRoot(basePath),
|
|
30
|
+
return join(gsdRoot(basePath), effectiveLockFile());
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
/** Write or update the lock file with current auto-mode state. */
|