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
package/dist/cli.js
CHANGED
|
@@ -103,19 +103,6 @@ const cliFlags = parseCliArgs(process.argv);
|
|
|
103
103
|
const isPrintMode = cliFlags.print || cliFlags.mode !== undefined;
|
|
104
104
|
// Early resource-skew check — must run before TTY gate so version mismatch
|
|
105
105
|
// errors surface even in non-TTY environments.
|
|
106
|
-
exitIfManagedResourcesAreNewer(agentDir);
|
|
107
|
-
// Early TTY check — must come before heavy initialization to avoid dangling
|
|
108
|
-
// handles that prevent process.exit() from completing promptly.
|
|
109
|
-
const hasSubcommand = cliFlags.messages.length > 0;
|
|
110
|
-
if (!process.stdin.isTTY && !isPrintMode && !hasSubcommand && !cliFlags.listModels && !cliFlags.web) {
|
|
111
|
-
process.stderr.write('[gsd] Error: Interactive mode requires a terminal (TTY).\n');
|
|
112
|
-
process.stderr.write('[gsd] Non-interactive alternatives:\n');
|
|
113
|
-
process.stderr.write('[gsd] gsd --print "your message" Single-shot prompt\n');
|
|
114
|
-
process.stderr.write('[gsd] gsd --mode rpc JSON-RPC over stdin/stdout\n');
|
|
115
|
-
process.stderr.write('[gsd] gsd --mode mcp MCP server over stdin/stdout\n');
|
|
116
|
-
process.stderr.write('[gsd] gsd --mode text "message" Text output mode\n');
|
|
117
|
-
process.exit(1);
|
|
118
|
-
}
|
|
119
106
|
async function ensureRtkBootstrap() {
|
|
120
107
|
if (ensureRtkBootstrap._done)
|
|
121
108
|
return;
|
|
@@ -136,6 +123,25 @@ async function ensureRtkBootstrap() {
|
|
|
136
123
|
process.stderr.write(`[gsd] Warning: RTK unavailable — continuing without shell-command compression (${rtkStatus.reason}).\n`);
|
|
137
124
|
}
|
|
138
125
|
}
|
|
126
|
+
// `gsd update` — update to the latest version via npm
|
|
127
|
+
if (cliFlags.messages[0] === 'update') {
|
|
128
|
+
const { runUpdate } = await import('./update-cmd.js');
|
|
129
|
+
await runUpdate();
|
|
130
|
+
process.exit(0);
|
|
131
|
+
}
|
|
132
|
+
exitIfManagedResourcesAreNewer(agentDir);
|
|
133
|
+
// Early TTY check — must come before heavy initialization to avoid dangling
|
|
134
|
+
// handles that prevent process.exit() from completing promptly.
|
|
135
|
+
const hasSubcommand = cliFlags.messages.length > 0;
|
|
136
|
+
if (!process.stdin.isTTY && !isPrintMode && !hasSubcommand && !cliFlags.listModels && !cliFlags.web) {
|
|
137
|
+
process.stderr.write('[gsd] Error: Interactive mode requires a terminal (TTY).\n');
|
|
138
|
+
process.stderr.write('[gsd] Non-interactive alternatives:\n');
|
|
139
|
+
process.stderr.write('[gsd] gsd --print "your message" Single-shot prompt\n');
|
|
140
|
+
process.stderr.write('[gsd] gsd --mode rpc JSON-RPC over stdin/stdout\n');
|
|
141
|
+
process.stderr.write('[gsd] gsd --mode mcp MCP server over stdin/stdout\n');
|
|
142
|
+
process.stderr.write('[gsd] gsd --mode text "message" Text output mode\n');
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
139
145
|
// `gsd <subcommand> --help` — show subcommand-specific help
|
|
140
146
|
const subcommand = cliFlags.messages[0];
|
|
141
147
|
if (subcommand && process.argv.includes('--help')) {
|
|
@@ -162,12 +168,6 @@ if (cliFlags.messages[0] === 'config') {
|
|
|
162
168
|
await runOnboarding(authStorage);
|
|
163
169
|
process.exit(0);
|
|
164
170
|
}
|
|
165
|
-
// `gsd update` — update to the latest version via npm
|
|
166
|
-
if (cliFlags.messages[0] === 'update') {
|
|
167
|
-
const { runUpdate } = await import('./update-cmd.js');
|
|
168
|
-
await runUpdate();
|
|
169
|
-
process.exit(0);
|
|
170
|
-
}
|
|
171
171
|
// `gsd web stop [path|all]` — stop web server before anything else
|
|
172
172
|
if (cliFlags.messages[0] === 'web' && cliFlags.messages[1] === 'stop') {
|
|
173
173
|
const webFlags = parseWebCliArgs(process.argv);
|
package/dist/headless-ui.d.ts
CHANGED
|
@@ -18,6 +18,32 @@ interface ExtensionUIRequest {
|
|
|
18
18
|
[key: string]: unknown;
|
|
19
19
|
}
|
|
20
20
|
export type { ExtensionUIRequest };
|
|
21
|
+
/** Context passed alongside an event for richer formatting. */
|
|
22
|
+
export interface ProgressContext {
|
|
23
|
+
verbose: boolean;
|
|
24
|
+
toolDuration?: number;
|
|
25
|
+
lastCost?: {
|
|
26
|
+
costUsd: number;
|
|
27
|
+
inputTokens: number;
|
|
28
|
+
outputTokens: number;
|
|
29
|
+
};
|
|
30
|
+
thinkingPreview?: string;
|
|
31
|
+
isError?: boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Produce a short human-readable summary of tool arguments.
|
|
35
|
+
* Returns a string like "path/to/file.ts" or "grep pattern *.ts" — never the
|
|
36
|
+
* full JSON blob.
|
|
37
|
+
*/
|
|
38
|
+
export declare function summarizeToolArgs(toolName: unknown, toolInput: unknown): string;
|
|
21
39
|
export declare function handleExtensionUIRequest(event: ExtensionUIRequest, client: RpcClient): void;
|
|
22
|
-
export declare function formatProgress(event: Record<string, unknown>,
|
|
40
|
+
export declare function formatProgress(event: Record<string, unknown>, ctx: ProgressContext): string | null;
|
|
41
|
+
/**
|
|
42
|
+
* Format a thinking preview line from accumulated LLM text deltas.
|
|
43
|
+
*/
|
|
44
|
+
export declare function formatThinkingLine(text: string): string;
|
|
45
|
+
/**
|
|
46
|
+
* Format a cost line (used for periodic cost updates in verbose mode).
|
|
47
|
+
*/
|
|
48
|
+
export declare function formatCostLine(costUsd: number, inputTokens: number, outputTokens: number): string;
|
|
23
49
|
export declare function startSupervisedStdinReader(client: RpcClient, onResponse: (id: string) => void): () => void;
|
package/dist/headless-ui.js
CHANGED
|
@@ -7,6 +7,101 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { attachJsonlLineReader } from '@gsd/pi-coding-agent';
|
|
9
9
|
// ---------------------------------------------------------------------------
|
|
10
|
+
// ANSI Color Helpers
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
const _c = {
|
|
13
|
+
reset: '\x1b[0m',
|
|
14
|
+
bold: '\x1b[1m',
|
|
15
|
+
dim: '\x1b[2m',
|
|
16
|
+
italic: '\x1b[3m',
|
|
17
|
+
red: '\x1b[31m',
|
|
18
|
+
green: '\x1b[32m',
|
|
19
|
+
yellow: '\x1b[33m',
|
|
20
|
+
cyan: '\x1b[36m',
|
|
21
|
+
gray: '\x1b[90m',
|
|
22
|
+
};
|
|
23
|
+
/** Build a no-op color map (all codes empty). */
|
|
24
|
+
function noColor() {
|
|
25
|
+
const nc = {};
|
|
26
|
+
for (const k of Object.keys(_c))
|
|
27
|
+
nc[k] = '';
|
|
28
|
+
return nc;
|
|
29
|
+
}
|
|
30
|
+
const colorsDisabled = !!process.env['NO_COLOR'] || !process.stderr.isTTY;
|
|
31
|
+
const c = colorsDisabled ? noColor() : _c;
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Tool-Arg Summarizer
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
/**
|
|
36
|
+
* Produce a short human-readable summary of tool arguments.
|
|
37
|
+
* Returns a string like "path/to/file.ts" or "grep pattern *.ts" — never the
|
|
38
|
+
* full JSON blob.
|
|
39
|
+
*/
|
|
40
|
+
export function summarizeToolArgs(toolName, toolInput) {
|
|
41
|
+
const name = String(toolName ?? '');
|
|
42
|
+
const input = (toolInput && typeof toolInput === 'object') ? toolInput : {};
|
|
43
|
+
switch (name) {
|
|
44
|
+
case 'Read':
|
|
45
|
+
case 'read':
|
|
46
|
+
return shortPath(input.file_path) || '';
|
|
47
|
+
case 'Write':
|
|
48
|
+
case 'write':
|
|
49
|
+
return shortPath(input.file_path) || '';
|
|
50
|
+
case 'Edit':
|
|
51
|
+
case 'edit':
|
|
52
|
+
return shortPath(input.file_path) || '';
|
|
53
|
+
case 'Bash':
|
|
54
|
+
case 'bash': {
|
|
55
|
+
const cmd = String(input.command ?? '');
|
|
56
|
+
return cmd.length > 80 ? cmd.slice(0, 77) + '...' : cmd;
|
|
57
|
+
}
|
|
58
|
+
case 'Glob':
|
|
59
|
+
case 'glob':
|
|
60
|
+
return String(input.pattern ?? '');
|
|
61
|
+
case 'Grep':
|
|
62
|
+
case 'grep':
|
|
63
|
+
case 'Search':
|
|
64
|
+
case 'search': {
|
|
65
|
+
const pat = String(input.pattern ?? '');
|
|
66
|
+
const g = input.glob ? ` ${input.glob}` : '';
|
|
67
|
+
return `${pat}${g}`;
|
|
68
|
+
}
|
|
69
|
+
case 'Task':
|
|
70
|
+
case 'task': {
|
|
71
|
+
const desc = String(input.description ?? input.prompt ?? '');
|
|
72
|
+
return desc.length > 60 ? desc.slice(0, 57) + '...' : desc;
|
|
73
|
+
}
|
|
74
|
+
default: {
|
|
75
|
+
// Fallback: show first string-valued key up to 60 chars
|
|
76
|
+
for (const v of Object.values(input)) {
|
|
77
|
+
if (typeof v === 'string' && v.length > 0) {
|
|
78
|
+
return v.length > 60 ? v.slice(0, 57) + '...' : v;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return '';
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function shortPath(p) {
|
|
86
|
+
if (typeof p !== 'string')
|
|
87
|
+
return '';
|
|
88
|
+
// Strip common CWD prefix to save space
|
|
89
|
+
const cwd = process.cwd();
|
|
90
|
+
if (p.startsWith(cwd + '/'))
|
|
91
|
+
return p.slice(cwd.length + 1);
|
|
92
|
+
// Strip /Users/*/Developer/ prefix
|
|
93
|
+
return p.replace(/^\/Users\/[^/]+\/Developer\//, '');
|
|
94
|
+
}
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
// Format Duration
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
function formatDuration(ms) {
|
|
99
|
+
if (ms < 1000)
|
|
100
|
+
return `${ms}ms`;
|
|
101
|
+
const s = (ms / 1000).toFixed(1);
|
|
102
|
+
return `${s}s`;
|
|
103
|
+
}
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
10
105
|
// Extension UI Auto-Responder
|
|
11
106
|
// ---------------------------------------------------------------------------
|
|
12
107
|
export function handleExtensionUIRequest(event, client) {
|
|
@@ -50,29 +145,124 @@ export function handleExtensionUIRequest(event, client) {
|
|
|
50
145
|
// ---------------------------------------------------------------------------
|
|
51
146
|
// Progress Formatter
|
|
52
147
|
// ---------------------------------------------------------------------------
|
|
53
|
-
export function formatProgress(event,
|
|
148
|
+
export function formatProgress(event, ctx) {
|
|
54
149
|
const type = String(event.type ?? '');
|
|
150
|
+
// Emit accumulated thinking preview before tool calls
|
|
151
|
+
if (ctx.thinkingPreview) {
|
|
152
|
+
// thinkingPreview is handled by the caller in headless.ts — it prepends
|
|
153
|
+
// the thinking line before the current event's line. We return the thinking
|
|
154
|
+
// line as a prefix joined with newline.
|
|
155
|
+
}
|
|
55
156
|
switch (type) {
|
|
56
|
-
case 'tool_execution_start':
|
|
57
|
-
if (verbose)
|
|
58
|
-
return
|
|
59
|
-
|
|
157
|
+
case 'tool_execution_start': {
|
|
158
|
+
if (!ctx.verbose)
|
|
159
|
+
return null;
|
|
160
|
+
const name = String(event.toolName ?? 'unknown');
|
|
161
|
+
const args = summarizeToolArgs(event.toolName, event.args);
|
|
162
|
+
const argStr = args ? ` ${c.dim}${args}${c.reset}` : '';
|
|
163
|
+
return ` ${c.dim}[tool]${c.reset} ${name}${argStr}`;
|
|
164
|
+
}
|
|
165
|
+
case 'tool_execution_end': {
|
|
166
|
+
if (!ctx.verbose)
|
|
167
|
+
return null;
|
|
168
|
+
const name = String(event.toolName ?? 'unknown');
|
|
169
|
+
const durationStr = ctx.toolDuration != null ? ` ${c.dim}${formatDuration(ctx.toolDuration)}${c.reset}` : '';
|
|
170
|
+
if (ctx.isError) {
|
|
171
|
+
return ` ${c.red}[tool] ${name} error${c.reset}${durationStr}`;
|
|
172
|
+
}
|
|
173
|
+
return ` ${c.dim}[tool] ${name} done${c.reset}${durationStr}`;
|
|
174
|
+
}
|
|
60
175
|
case 'agent_start':
|
|
61
|
-
return
|
|
62
|
-
case 'agent_end':
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
176
|
+
return `${c.dim}[agent] Session started${c.reset}`;
|
|
177
|
+
case 'agent_end': {
|
|
178
|
+
let line = `${c.dim}[agent] Session ended${c.reset}`;
|
|
179
|
+
if (ctx.lastCost) {
|
|
180
|
+
const cost = `$${ctx.lastCost.costUsd.toFixed(4)}`;
|
|
181
|
+
const tokens = `${ctx.lastCost.inputTokens + ctx.lastCost.outputTokens} tokens`;
|
|
182
|
+
line += ` ${c.dim}(${cost}, ${tokens})${c.reset}`;
|
|
67
183
|
}
|
|
68
|
-
|
|
69
|
-
|
|
184
|
+
return line;
|
|
185
|
+
}
|
|
186
|
+
case 'extension_ui_request': {
|
|
187
|
+
const method = String(event.method ?? '');
|
|
188
|
+
if (method === 'notify') {
|
|
189
|
+
const msg = String(event.message ?? '');
|
|
190
|
+
if (!msg)
|
|
191
|
+
return null;
|
|
192
|
+
// Bold important notifications
|
|
193
|
+
const isImportant = /^(committed:|verification gate:|milestone|blocked:)/i.test(msg);
|
|
194
|
+
return isImportant
|
|
195
|
+
? `${c.bold}[gsd] ${msg}${c.reset}`
|
|
196
|
+
: `[gsd] ${msg}`;
|
|
197
|
+
}
|
|
198
|
+
if (method === 'setStatus') {
|
|
199
|
+
// Parse statusKey for phase transitions
|
|
200
|
+
const statusKey = String(event.statusKey ?? '');
|
|
201
|
+
const msg = String(event.message ?? '');
|
|
202
|
+
if (!statusKey && !msg)
|
|
203
|
+
return null; // suppress empty status lines
|
|
204
|
+
// Show meaningful phase transitions
|
|
205
|
+
if (statusKey) {
|
|
206
|
+
const label = parsePhaseLabel(statusKey, msg);
|
|
207
|
+
if (label)
|
|
208
|
+
return `${c.cyan}[phase] ${label}${c.reset}`;
|
|
209
|
+
}
|
|
210
|
+
// Fallback: show message if non-empty
|
|
211
|
+
if (msg)
|
|
212
|
+
return `${c.cyan}[phase] ${msg}${c.reset}`;
|
|
213
|
+
return null;
|
|
70
214
|
}
|
|
71
215
|
return null;
|
|
216
|
+
}
|
|
72
217
|
default:
|
|
73
218
|
return null;
|
|
74
219
|
}
|
|
75
220
|
}
|
|
221
|
+
/**
|
|
222
|
+
* Format a thinking preview line from accumulated LLM text deltas.
|
|
223
|
+
*/
|
|
224
|
+
export function formatThinkingLine(text) {
|
|
225
|
+
const trimmed = text.replace(/\s+/g, ' ').trim();
|
|
226
|
+
const truncated = trimmed.length > 120 ? trimmed.slice(0, 117) + '...' : trimmed;
|
|
227
|
+
return `${c.dim}${c.italic}[thinking] ${truncated}${c.reset}`;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Format a cost line (used for periodic cost updates in verbose mode).
|
|
231
|
+
*/
|
|
232
|
+
export function formatCostLine(costUsd, inputTokens, outputTokens) {
|
|
233
|
+
return `${c.dim}[cost] $${costUsd.toFixed(4)} (${inputTokens + outputTokens} tokens)${c.reset}`;
|
|
234
|
+
}
|
|
235
|
+
// ---------------------------------------------------------------------------
|
|
236
|
+
// Phase Label Parser
|
|
237
|
+
// ---------------------------------------------------------------------------
|
|
238
|
+
/**
|
|
239
|
+
* Parse a statusKey into a human-readable phase label.
|
|
240
|
+
* statusKey format varies but common patterns:
|
|
241
|
+
* "milestone:M1", "slice:S1.1", "task:T1.1.1", "phase:discuss", etc.
|
|
242
|
+
*/
|
|
243
|
+
function parsePhaseLabel(statusKey, message) {
|
|
244
|
+
// Direct phase/milestone/slice/task keys
|
|
245
|
+
const parts = statusKey.split(':');
|
|
246
|
+
if (parts.length >= 2) {
|
|
247
|
+
const [kind, value] = parts;
|
|
248
|
+
switch (kind.toLowerCase()) {
|
|
249
|
+
case 'milestone':
|
|
250
|
+
return `Milestone ${value}${message ? ' -- ' + message : ''}`;
|
|
251
|
+
case 'slice':
|
|
252
|
+
return `Slice ${value}${message ? ' -- ' + message : ''}`;
|
|
253
|
+
case 'task':
|
|
254
|
+
return `Task ${value}${message ? ' -- ' + message : ''}`;
|
|
255
|
+
case 'phase':
|
|
256
|
+
return `Phase: ${value}${message ? ' -- ' + message : ''}`;
|
|
257
|
+
default:
|
|
258
|
+
return `${kind}: ${value}${message ? ' -- ' + message : ''}`;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
// Single-word status keys with a message
|
|
262
|
+
if (message)
|
|
263
|
+
return `${statusKey}: ${message}`;
|
|
264
|
+
return statusKey || null;
|
|
265
|
+
}
|
|
76
266
|
// ---------------------------------------------------------------------------
|
|
77
267
|
// Supervised Stdin Reader
|
|
78
268
|
// ---------------------------------------------------------------------------
|
package/dist/headless.js
CHANGED
|
@@ -19,7 +19,7 @@ import { getProjectSessionsDir } from './project-sessions.js';
|
|
|
19
19
|
import { loadAndValidateAnswerFile, AnswerInjector } from './headless-answers.js';
|
|
20
20
|
import { isTerminalNotification, isBlockedNotification, isMilestoneReadyNotification, isQuickCommand, FIRE_AND_FORGET_METHODS, IDLE_TIMEOUT_MS, NEW_MILESTONE_IDLE_TIMEOUT_MS, EXIT_SUCCESS, EXIT_ERROR, EXIT_BLOCKED, EXIT_CANCELLED, mapStatusToExitCode, } from './headless-events.js';
|
|
21
21
|
import { VALID_OUTPUT_FORMATS } from './headless-types.js';
|
|
22
|
-
import { handleExtensionUIRequest, formatProgress, startSupervisedStdinReader, } from './headless-ui.js';
|
|
22
|
+
import { handleExtensionUIRequest, formatProgress, formatThinkingLine, startSupervisedStdinReader, } from './headless-ui.js';
|
|
23
23
|
import { loadContext, bootstrapGsdProject, } from './headless-context.js';
|
|
24
24
|
/**
|
|
25
25
|
* Resolve a session prefix to a single session.
|
|
@@ -266,6 +266,8 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
266
266
|
if (injector) {
|
|
267
267
|
clientOptions.env = injector.getSecretEnvVars();
|
|
268
268
|
}
|
|
269
|
+
// Signal headless mode to the GSD extension (skips UAT human pause, etc.)
|
|
270
|
+
clientOptions.env = { ...(clientOptions.env || {}), GSD_HEADLESS: '1' };
|
|
269
271
|
// Propagate --bare to the child process
|
|
270
272
|
if (options.bare) {
|
|
271
273
|
clientOptions.args = [...(clientOptions.args || []), '--bare'];
|
|
@@ -286,6 +288,10 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
286
288
|
let cumulativeCacheReadTokens = 0;
|
|
287
289
|
let cumulativeCacheWriteTokens = 0;
|
|
288
290
|
let lastSessionId;
|
|
291
|
+
// Verbose text-mode state
|
|
292
|
+
const toolStartTimes = new Map();
|
|
293
|
+
let lastCostData;
|
|
294
|
+
let thinkingBuffer = '';
|
|
289
295
|
// Emit HeadlessJsonResult to stdout for --output-format json batch mode
|
|
290
296
|
function emitBatchJsonResult() {
|
|
291
297
|
if (options.outputFormat !== 'json')
|
|
@@ -410,8 +416,59 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
410
416
|
}
|
|
411
417
|
}
|
|
412
418
|
else if (!options.json) {
|
|
413
|
-
// Progress output to stderr
|
|
414
|
-
const
|
|
419
|
+
// Progress output to stderr with verbose state tracking
|
|
420
|
+
const eventType = String(eventObj.type ?? '');
|
|
421
|
+
// Track cost_update events for agent_end summary
|
|
422
|
+
if (eventType === 'cost_update') {
|
|
423
|
+
const data = eventObj;
|
|
424
|
+
const cumCost = data.cumulativeCost;
|
|
425
|
+
if (cumCost) {
|
|
426
|
+
const tokens = data.tokens;
|
|
427
|
+
lastCostData = {
|
|
428
|
+
costUsd: Number(cumCost.costUsd ?? 0),
|
|
429
|
+
inputTokens: tokens?.input ?? 0,
|
|
430
|
+
outputTokens: tokens?.output ?? 0,
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
// Accumulate thinking text from message_update text_delta events
|
|
435
|
+
if (eventType === 'message_update') {
|
|
436
|
+
const ame = eventObj.assistantMessageEvent;
|
|
437
|
+
if (ame?.type === 'text_delta') {
|
|
438
|
+
thinkingBuffer += String(ame.text ?? '');
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
// Track tool execution start timestamps
|
|
442
|
+
if (eventType === 'tool_execution_start') {
|
|
443
|
+
const toolCallId = String(eventObj.toolCallId ?? eventObj.id ?? '');
|
|
444
|
+
if (toolCallId)
|
|
445
|
+
toolStartTimes.set(toolCallId, Date.now());
|
|
446
|
+
}
|
|
447
|
+
// Flush thinking buffer before tool calls or message end
|
|
448
|
+
if (options.verbose && thinkingBuffer.trim() &&
|
|
449
|
+
(eventType === 'tool_execution_start' || eventType === 'message_end')) {
|
|
450
|
+
process.stderr.write(formatThinkingLine(thinkingBuffer) + '\n');
|
|
451
|
+
thinkingBuffer = '';
|
|
452
|
+
}
|
|
453
|
+
// Compute tool duration for tool_execution_end
|
|
454
|
+
let toolDuration;
|
|
455
|
+
let isToolError = false;
|
|
456
|
+
if (eventType === 'tool_execution_end') {
|
|
457
|
+
const toolCallId = String(eventObj.toolCallId ?? eventObj.id ?? '');
|
|
458
|
+
const startTime = toolStartTimes.get(toolCallId);
|
|
459
|
+
if (startTime) {
|
|
460
|
+
toolDuration = Date.now() - startTime;
|
|
461
|
+
toolStartTimes.delete(toolCallId);
|
|
462
|
+
}
|
|
463
|
+
isToolError = eventObj.isError === true || eventObj.error != null;
|
|
464
|
+
}
|
|
465
|
+
const ctx = {
|
|
466
|
+
verbose: !!options.verbose,
|
|
467
|
+
toolDuration,
|
|
468
|
+
isError: isToolError,
|
|
469
|
+
lastCost: eventType === 'agent_end' ? lastCostData : undefined,
|
|
470
|
+
};
|
|
471
|
+
const line = formatProgress(eventObj, ctx);
|
|
415
472
|
if (line)
|
|
416
473
|
process.stderr.write(line + '\n');
|
|
417
474
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { truncateToWidth, visibleWidth, } from "@gsd/pi-tui";
|
|
6
6
|
import { processes, pendingAlerts, cleanupAll, cleanupSessionProcesses, persistManifest, loadManifest, pruneDeadProcesses, } from "./process-manager.js";
|
|
7
|
-
import { formatUptime, resolveBgShellPersistenceCwd } from "./utilities.js";
|
|
7
|
+
import { formatUptime, getBgShellLiveCwd, resolveBgShellPersistenceCwd } from "./utilities.js";
|
|
8
8
|
import { formatTokenCount } from "../shared/format-utils.js";
|
|
9
9
|
export function registerBgShellLifecycle(pi, state) {
|
|
10
10
|
function syncLatestCtxCwd() {
|
|
@@ -161,7 +161,7 @@ export function registerBgShellLifecycle(pi, state) {
|
|
|
161
161
|
return {
|
|
162
162
|
render(width) {
|
|
163
163
|
// ── Line 1: pwd (branch) [session] ... bg status ──
|
|
164
|
-
let pwd =
|
|
164
|
+
let pwd = getBgShellLiveCwd(state.latestCtx?.cwd);
|
|
165
165
|
const home = process.env.HOME || process.env.USERPROFILE;
|
|
166
166
|
if (home && pwd.startsWith(home)) {
|
|
167
167
|
pwd = `~${pwd.slice(home.length)}`;
|
|
@@ -36,15 +36,44 @@ export const formatUptime = formatDuration;
|
|
|
36
36
|
export function formatTimeAgo(timestamp) {
|
|
37
37
|
return formatDuration(Date.now() - timestamp) + " ago";
|
|
38
38
|
}
|
|
39
|
-
|
|
39
|
+
function deriveProjectRootFromAutoWorktree(cachedCwd) {
|
|
40
|
+
if (!cachedCwd)
|
|
41
|
+
return undefined;
|
|
42
|
+
const match = cachedCwd.match(/^(.*?)[\\/]\.gsd[\\/]worktrees[\\/][^\\/]+(?:[\\/].*)?$/);
|
|
43
|
+
return match?.[1];
|
|
44
|
+
}
|
|
45
|
+
export function getBgShellLiveCwd(cachedCwd, pathExists = existsSync, getCwd = () => process.cwd(), chdir = (path) => process.chdir(path)) {
|
|
46
|
+
try {
|
|
47
|
+
return getCwd();
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
const projectRoot = deriveProjectRootFromAutoWorktree(cachedCwd);
|
|
51
|
+
const home = process.env.HOME || process.env.USERPROFILE;
|
|
52
|
+
const fallbacks = [projectRoot, cachedCwd, home, "/"].filter((candidate) => Boolean(candidate));
|
|
53
|
+
for (const candidate of fallbacks) {
|
|
54
|
+
if (candidate !== "/" && !pathExists(candidate))
|
|
55
|
+
continue;
|
|
56
|
+
try {
|
|
57
|
+
chdir(candidate);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Best-effort only. Returning a known-good fallback is enough to avoid crashes.
|
|
61
|
+
}
|
|
62
|
+
return candidate;
|
|
63
|
+
}
|
|
64
|
+
return "/";
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export function resolveBgShellPersistenceCwd(cachedCwd, liveCwd = undefined, pathExists = existsSync) {
|
|
68
|
+
const resolvedLiveCwd = liveCwd ?? getBgShellLiveCwd(cachedCwd, pathExists);
|
|
40
69
|
const cachedIsAutoWorktree = /(?:^|[\\/])\.gsd[\\/]worktrees[\\/]/.test(cachedCwd);
|
|
41
70
|
if (!cachedIsAutoWorktree)
|
|
42
71
|
return cachedCwd;
|
|
43
|
-
if (cachedCwd ===
|
|
72
|
+
if (cachedCwd === resolvedLiveCwd && pathExists(cachedCwd))
|
|
44
73
|
return cachedCwd;
|
|
45
74
|
if (!pathExists(cachedCwd))
|
|
46
|
-
return
|
|
47
|
-
if (
|
|
48
|
-
return
|
|
75
|
+
return resolvedLiveCwd;
|
|
76
|
+
if (resolvedLiveCwd !== cachedCwd)
|
|
77
|
+
return resolvedLiveCwd;
|
|
49
78
|
return cachedCwd;
|
|
50
79
|
}
|
|
@@ -29,6 +29,14 @@ import { writeUnitRuntimeRecord } from "../unit-runtime.js";
|
|
|
29
29
|
export function _resolveReportBasePath(s) {
|
|
30
30
|
return s.originalBasePath || s.basePath;
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Resolve the authoritative project base for dispatch guards.
|
|
34
|
+
* Prior-milestone completion lives at the project root, even when the active
|
|
35
|
+
* unit is running inside an auto worktree.
|
|
36
|
+
*/
|
|
37
|
+
export function _resolveDispatchGuardBasePath(s) {
|
|
38
|
+
return s.originalBasePath || s.basePath;
|
|
39
|
+
}
|
|
32
40
|
/**
|
|
33
41
|
* Generate and write an HTML milestone report snapshot.
|
|
34
42
|
* Extracted from the milestone-transition block in autoLoop.
|
|
@@ -459,7 +467,8 @@ export async function runDispatch(ic, preData, loopState) {
|
|
|
459
467
|
else if (preDispatchResult.prompt) {
|
|
460
468
|
prompt = preDispatchResult.prompt;
|
|
461
469
|
}
|
|
462
|
-
const
|
|
470
|
+
const guardBasePath = _resolveDispatchGuardBasePath(s);
|
|
471
|
+
const priorSliceBlocker = deps.getPriorSliceCompletionBlocker(guardBasePath, deps.getMainBranch(guardBasePath), unitType, unitId);
|
|
463
472
|
if (priorSliceBlocker) {
|
|
464
473
|
await deps.stopAuto(ctx, pi, priorSliceBlocker);
|
|
465
474
|
debugLog("autoLoop", { phase: "exit", reason: "prior-slice-blocker" });
|
|
@@ -487,8 +496,15 @@ export async function runGuards(ic, mid) {
|
|
|
487
496
|
const budgetCeiling = prefs?.budget_ceiling;
|
|
488
497
|
if (budgetCeiling !== undefined && budgetCeiling > 0) {
|
|
489
498
|
const currentLedger = deps.getLedger();
|
|
490
|
-
|
|
491
|
-
|
|
499
|
+
// In parallel worker mode, only count cost from the current auto-mode session
|
|
500
|
+
// to avoid hitting the ceiling due to historical project-wide spend (#2184).
|
|
501
|
+
let costUnits = currentLedger?.units;
|
|
502
|
+
if (process.env.GSD_PARALLEL_WORKER && s.autoStartTime && Array.isArray(costUnits)) {
|
|
503
|
+
const sessionStartISO = new Date(s.autoStartTime).toISOString();
|
|
504
|
+
costUnits = costUnits.filter((u) => u.startedAt != null && u.startedAt >= sessionStartISO);
|
|
505
|
+
}
|
|
506
|
+
const totalCost = costUnits
|
|
507
|
+
? deps.getProjectTotals(costUnits).cost
|
|
492
508
|
: 0;
|
|
493
509
|
const budgetPct = totalCost / budgetCeiling;
|
|
494
510
|
const budgetAlertLevel = deps.getBudgetAlertLevel(budgetPct);
|
|
@@ -115,7 +115,7 @@ export const DISPATCH_RULES = [
|
|
|
115
115
|
unitType: "run-uat",
|
|
116
116
|
unitId: `${mid}/${sliceId}`,
|
|
117
117
|
prompt: await buildRunUatPrompt(mid, sliceId, relSliceFile(basePath, mid, sliceId, "UAT"), uatContent ?? "", basePath),
|
|
118
|
-
pauseAfterDispatch: uatType !== "artifact-driven" && uatType !== "browser-executable" && uatType !== "runtime-executable",
|
|
118
|
+
pauseAfterDispatch: !process.env.GSD_HEADLESS && uatType !== "artifact-driven" && uatType !== "browser-executable" && uatType !== "runtime-executable",
|
|
119
119
|
};
|
|
120
120
|
},
|
|
121
121
|
},
|
|
@@ -8,6 +8,22 @@ import { classifyUnitComplexity, tierLabel } from "./complexity-classifier.js";
|
|
|
8
8
|
import { resolveModelForComplexity, escalateTier } from "./model-router.js";
|
|
9
9
|
import { getLedger, getProjectTotals } from "./metrics.js";
|
|
10
10
|
import { unitPhaseLabel } from "./auto-dashboard.js";
|
|
11
|
+
export function resolvePreferredModelConfig(unitType, autoModeStartModel) {
|
|
12
|
+
const explicitConfig = resolveModelWithFallbacksForUnit(unitType);
|
|
13
|
+
if (explicitConfig)
|
|
14
|
+
return explicitConfig;
|
|
15
|
+
const routingConfig = resolveDynamicRoutingConfig();
|
|
16
|
+
if (!routingConfig.enabled || !routingConfig.tier_models)
|
|
17
|
+
return undefined;
|
|
18
|
+
const ceilingModel = routingConfig.tier_models.heavy
|
|
19
|
+
?? (autoModeStartModel ? `${autoModeStartModel.provider}/${autoModeStartModel.id}` : undefined);
|
|
20
|
+
if (!ceilingModel)
|
|
21
|
+
return undefined;
|
|
22
|
+
return {
|
|
23
|
+
primary: ceilingModel,
|
|
24
|
+
fallbacks: [],
|
|
25
|
+
};
|
|
26
|
+
}
|
|
11
27
|
/**
|
|
12
28
|
* Select and apply the appropriate model for a unit dispatch.
|
|
13
29
|
* Handles: per-unit-type model preferences, dynamic complexity routing,
|
|
@@ -16,7 +32,7 @@ import { unitPhaseLabel } from "./auto-dashboard.js";
|
|
|
16
32
|
* Returns routing metadata for metrics tracking.
|
|
17
33
|
*/
|
|
18
34
|
export async function selectAndApplyModel(ctx, pi, unitType, unitId, basePath, prefs, verbose, autoModeStartModel, retryContext) {
|
|
19
|
-
const modelConfig =
|
|
35
|
+
const modelConfig = resolvePreferredModelConfig(unitType, autoModeStartModel);
|
|
20
36
|
let routing = null;
|
|
21
37
|
if (modelConfig) {
|
|
22
38
|
const availableModels = ctx.modelRegistry.getAvailable();
|
|
@@ -66,6 +66,10 @@ function buildSourceFilePaths(base, mid, sid) {
|
|
|
66
66
|
if (existsSync(decisionsPath)) {
|
|
67
67
|
paths.push(`- **Decisions**: \`${relGsdRootFile("DECISIONS")}\``);
|
|
68
68
|
}
|
|
69
|
+
const queuePath = resolveGsdRootFile(base, "QUEUE");
|
|
70
|
+
if (existsSync(queuePath)) {
|
|
71
|
+
paths.push(`- **Queue**: \`${relGsdRootFile("QUEUE")}\``);
|
|
72
|
+
}
|
|
69
73
|
const contextPath = resolveMilestoneFile(base, mid, "CONTEXT");
|
|
70
74
|
if (contextPath) {
|
|
71
75
|
paths.push(`- **Milestone Context**: \`${relMilestoneFile(base, mid, "CONTEXT")}\``);
|
|
@@ -812,6 +816,11 @@ export async function buildPlanMilestonePrompt(mid, midTitle, base, level) {
|
|
|
812
816
|
if (decisionsInline)
|
|
813
817
|
inlined.push(decisionsInline);
|
|
814
818
|
}
|
|
819
|
+
const queuePath = resolveGsdRootFile(base, "QUEUE");
|
|
820
|
+
if (existsSync(queuePath)) {
|
|
821
|
+
const queueInline = await inlineFileSmart(queuePath, relGsdRootFile("QUEUE"), "Project Queue", `${mid} ${midTitle}`);
|
|
822
|
+
inlined.push(queueInline);
|
|
823
|
+
}
|
|
815
824
|
const knowledgeInlinePM = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
|
|
816
825
|
if (knowledgeInlinePM)
|
|
817
826
|
inlined.push(knowledgeInlinePM);
|
|
@@ -64,6 +64,14 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
64
64
|
clearLock(base);
|
|
65
65
|
return false;
|
|
66
66
|
}
|
|
67
|
+
// Capture the user's session model before guided-flow dispatch can apply a
|
|
68
|
+
// phase-specific planning model for a discuss turn (#2829).
|
|
69
|
+
const startModelSnapshot = ctx.model
|
|
70
|
+
? {
|
|
71
|
+
provider: ctx.model.provider,
|
|
72
|
+
id: ctx.model.id,
|
|
73
|
+
}
|
|
74
|
+
: null;
|
|
67
75
|
try {
|
|
68
76
|
// Validate GSD_PROJECT_ID early so the user gets immediate feedback
|
|
69
77
|
const customProjectId = process.env.GSD_PROJECT_ID;
|
|
@@ -410,12 +418,11 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
410
418
|
initMetrics(s.basePath);
|
|
411
419
|
// Initialize routing history
|
|
412
420
|
initRoutingHistory(s.basePath);
|
|
413
|
-
//
|
|
414
|
-
|
|
415
|
-
if (currentModel) {
|
|
421
|
+
// Restore the model that was active when auto bootstrap began (#650, #2829).
|
|
422
|
+
if (startModelSnapshot) {
|
|
416
423
|
s.autoModeStartModel = {
|
|
417
|
-
provider:
|
|
418
|
-
id:
|
|
424
|
+
provider: startModelSnapshot.provider,
|
|
425
|
+
id: startModelSnapshot.id,
|
|
419
426
|
};
|
|
420
427
|
}
|
|
421
428
|
// Snapshot installed skills
|