gsd-pi 2.51.0 → 2.52.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/headless-events.d.ts +18 -0
- package/dist/headless-events.js +36 -0
- package/dist/headless-types.d.ts +28 -0
- package/dist/headless-types.js +7 -0
- package/dist/headless.d.ts +8 -3
- package/dist/headless.js +47 -16
- package/dist/help-text.js +16 -5
- package/dist/onboarding.js +5 -4
- package/dist/remote-questions-config.js +1 -1
- package/dist/resources/extensions/async-jobs/async-bash-tool.js +29 -17
- package/dist/resources/extensions/async-jobs/job-manager.js +4 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +18 -19
- package/dist/resources/extensions/gsd/auto/phases.js +6 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +18 -0
- package/dist/resources/extensions/gsd/auto-start.js +2 -0
- package/dist/resources/extensions/gsd/auto-timers.js +24 -2
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +25 -7
- package/dist/resources/extensions/gsd/auto-worktree.js +21 -0
- package/dist/resources/extensions/gsd/auto.js +8 -4
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +105 -70
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +12 -2
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +1 -1
- package/dist/resources/extensions/gsd/claude-import.js +60 -9
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +69 -6
- package/dist/resources/extensions/gsd/commands-config.js +10 -5
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
- package/dist/resources/extensions/gsd/detection.js +6 -6
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +3 -3
- package/dist/resources/extensions/gsd/error-classifier.js +105 -0
- package/dist/resources/extensions/gsd/gitignore.js +7 -7
- package/dist/resources/extensions/gsd/gsd-db.js +298 -45
- package/dist/resources/extensions/gsd/init-wizard.js +2 -2
- package/dist/resources/extensions/gsd/key-manager.js +7 -16
- package/dist/resources/extensions/gsd/memory-store.js +28 -13
- package/dist/resources/extensions/gsd/milestone-actions.js +19 -0
- package/dist/resources/extensions/gsd/preferences-models.js +1 -13
- package/dist/resources/extensions/gsd/preferences.js +13 -13
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/provider-error-pause.js +0 -44
- package/dist/resources/extensions/gsd/rule-registry.js +1 -1
- package/dist/resources/extensions/gsd/service-tier.js +13 -2
- package/dist/resources/extensions/gsd/state.js +21 -2
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -10
- package/dist/resources/extensions/gsd/tools/complete-slice.js +3 -17
- package/dist/resources/extensions/gsd/tools/complete-task.js +7 -18
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +26 -17
- package/dist/resources/extensions/gsd/tools/plan-slice.js +25 -14
- package/dist/resources/extensions/gsd/tools/plan-task.js +21 -11
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +47 -37
- package/dist/resources/extensions/gsd/tools/replan-slice.js +49 -38
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +23 -16
- package/dist/resources/extensions/gsd/workflow-logger.js +0 -1
- package/dist/resources/extensions/remote-questions/config.js +1 -1
- package/dist/resources/extensions/remote-questions/remote-command.js +1 -1
- package/dist/resources/extensions/search-the-web/native-search.js +1 -1
- package/dist/resources/extensions/search-the-web/provider.js +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -18
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +2 -2
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -18
- package/dist/web/standalone/.next/server/chunks/2229.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/4024.21054f459af5cc78.js +9 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-cfc9a116e6450a6b.js → webpack-024d82be84800e52.js} +1 -1
- package/dist/web/standalone/.next/static/css/a58ef8a151aa0493.css +1 -0
- package/dist/wizard.js +4 -1
- package/package.json +2 -2
- package/packages/mcp-server/README.md +202 -0
- package/packages/mcp-server/package.json +36 -0
- package/packages/mcp-server/src/cli.ts +68 -0
- package/packages/mcp-server/src/index.ts +14 -0
- package/packages/mcp-server/src/mcp-server.test.ts +628 -0
- package/packages/mcp-server/src/server.ts +278 -0
- package/packages/mcp-server/src/session-manager.ts +328 -0
- package/packages/mcp-server/src/types.ts +107 -0
- package/packages/mcp-server/tsconfig.json +24 -0
- package/packages/pi-ai/dist/models.d.ts +14 -3
- package/packages/pi-ai/dist/models.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.js +53 -10
- package/packages/pi-ai/dist/models.js.map +1 -1
- package/packages/pi-ai/dist/models.test.js +102 -1
- package/packages/pi-ai/dist/models.test.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +30 -0
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/src/models.test.ts +114 -1
- package/packages/pi-ai/src/models.ts +70 -13
- package/packages/pi-ai/src/types.ts +31 -0
- package/packages/pi-coding-agent/dist/cli/args.d.ts +2 -0
- package/packages/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/cli/args.js +3 -0
- package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/bash-executor.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/bash-executor.js +5 -1
- package/packages/pi-coding-agent/dist/core/bash-executor.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +9 -4
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.d.ts +19 -0
- package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js +83 -0
- package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js +5 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +5 -3
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +0 -2
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts +28 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js +49 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +114 -6
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.d.ts +9 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.js +831 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts +66 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.js.map +1 -1
- package/packages/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/utils/shell.js +0 -1
- package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/cli/args.ts +4 -0
- package/packages/pi-coding-agent/src/core/bash-executor.ts +5 -1
- package/packages/pi-coding-agent/src/core/model-registry.ts +10 -3
- package/packages/pi-coding-agent/src/core/tools/bash-spawn-windows.test.ts +101 -0
- package/packages/pi-coding-agent/src/core/tools/bash.ts +5 -1
- package/packages/pi-coding-agent/src/index.ts +3 -0
- package/packages/pi-coding-agent/src/main.ts +5 -3
- package/packages/pi-coding-agent/src/modes/index.ts +8 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +0 -2
- package/packages/pi-coding-agent/src/modes/rpc/rpc-client.ts +54 -1
- package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +124 -6
- package/packages/pi-coding-agent/src/modes/rpc/rpc-protocol-v2.test.ts +971 -0
- package/packages/pi-coding-agent/src/modes/rpc/rpc-types.ts +61 -4
- package/packages/pi-coding-agent/src/utils/shell.ts +0 -1
- package/packages/rpc-client/package.json +20 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/async-jobs/async-bash-tool.ts +22 -11
- package/src/resources/extensions/async-jobs/job-manager.ts +4 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +19 -20
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +21 -0
- package/src/resources/extensions/gsd/auto/phases.ts +6 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +19 -0
- package/src/resources/extensions/gsd/auto-start.ts +2 -0
- package/src/resources/extensions/gsd/auto-timers.ts +25 -1
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +30 -6
- package/src/resources/extensions/gsd/auto-worktree.ts +21 -0
- package/src/resources/extensions/gsd/auto.ts +10 -4
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +125 -73
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +11 -2
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +1 -1
- package/src/resources/extensions/gsd/claude-import.ts +58 -9
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +73 -6
- package/src/resources/extensions/gsd/commands-config.ts +11 -5
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
- package/src/resources/extensions/gsd/detection.ts +6 -6
- package/src/resources/extensions/gsd/docs/preferences-reference.md +3 -3
- package/src/resources/extensions/gsd/error-classifier.ts +139 -0
- package/src/resources/extensions/gsd/gitignore.ts +7 -7
- package/src/resources/extensions/gsd/gsd-db.ts +355 -63
- package/src/resources/extensions/gsd/init-wizard.ts +2 -2
- package/src/resources/extensions/gsd/key-manager.ts +7 -16
- package/src/resources/extensions/gsd/memory-store.ts +29 -18
- package/src/resources/extensions/gsd/milestone-actions.ts +17 -0
- package/src/resources/extensions/gsd/preferences-models.ts +1 -13
- package/src/resources/extensions/gsd/preferences.ts +12 -13
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/provider-error-pause.ts +0 -57
- package/src/resources/extensions/gsd/rule-registry.ts +1 -1
- package/src/resources/extensions/gsd/service-tier.ts +14 -2
- package/src/resources/extensions/gsd/state.ts +22 -2
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +61 -0
- package/src/resources/extensions/gsd/tests/claude-import-marketplace-discovery.test.ts +191 -0
- package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/commands-config.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +106 -0
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +35 -7
- package/src/resources/extensions/gsd/tests/detection.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/empty-db-reconciliation.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/git-service.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/interactive-tool-idle-exemption.test.ts +119 -0
- package/src/resources/extensions/gsd/tests/key-manager.test.ts +16 -1
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +91 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +77 -70
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +110 -0
- package/src/resources/extensions/gsd/tests/remote-questions.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +42 -31
- package/src/resources/extensions/gsd/tests/token-cost-display.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/vacuous-truth-slices.test.ts +115 -0
- package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +81 -1
- package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +130 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -14
- package/src/resources/extensions/gsd/tools/complete-slice.ts +3 -21
- package/src/resources/extensions/gsd/tools/complete-task.ts +9 -22
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +28 -18
- package/src/resources/extensions/gsd/tools/plan-slice.ts +28 -16
- package/src/resources/extensions/gsd/tools/plan-task.ts +24 -12
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +54 -42
- package/src/resources/extensions/gsd/tools/replan-slice.ts +53 -40
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +26 -20
- package/src/resources/extensions/gsd/workflow-logger.ts +0 -1
- package/src/resources/extensions/remote-questions/config.ts +1 -1
- package/src/resources/extensions/remote-questions/remote-command.ts +1 -1
- package/src/resources/extensions/search-the-web/native-search.ts +1 -1
- package/src/resources/extensions/search-the-web/provider.ts +1 -1
- package/dist/web/standalone/.next/static/chunks/4024.9ad5def014d90ce4.js +0 -9
- package/dist/web/standalone/.next/static/css/de141508b083f922.css +0 -1
- /package/dist/resources/extensions/gsd/templates/{preferences.md → PREFERENCES.md} +0 -0
- /package/dist/web/standalone/.next/static/{vkr67v-utm1dgZnbrBWQh → vlgS2rkXjxeKhgXhdp4lh}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{vkr67v-utm1dgZnbrBWQh → vlgS2rkXjxeKhgXhdp4lh}/_ssgManifest.js +0 -0
- /package/src/resources/extensions/gsd/templates/{preferences.md → PREFERENCES.md} +0 -0
package/README.md
CHANGED
|
@@ -521,7 +521,7 @@ An auto-generated `index.html` shows all reports with progression metrics across
|
|
|
521
521
|
|
|
522
522
|
### Preferences
|
|
523
523
|
|
|
524
|
-
GSD preferences live in `~/.gsd/
|
|
524
|
+
GSD preferences live in `~/.gsd/PREFERENCES.md` (global) or `.gsd/PREFERENCES.md` (project). Manage with `/gsd prefs`.
|
|
525
525
|
|
|
526
526
|
```yaml
|
|
527
527
|
---
|
|
@@ -672,7 +672,7 @@ The best practice for working in teams is to ensure unique milestone names acros
|
|
|
672
672
|
|
|
673
673
|
### Unique Milestone Names
|
|
674
674
|
|
|
675
|
-
Create or amend your `.gsd/
|
|
675
|
+
Create or amend your `.gsd/PREFERENCES.md` file within the repo to include `unique_milestone_ids: true` e.g.
|
|
676
676
|
|
|
677
677
|
```markdown
|
|
678
678
|
---
|
|
@@ -681,7 +681,7 @@ unique_milestone_ids: true
|
|
|
681
681
|
---
|
|
682
682
|
```
|
|
683
683
|
|
|
684
|
-
With the above `.gitignore` set up, the `.gsd/
|
|
684
|
+
With the above `.gitignore` set up, the `.gsd/PREFERENCES.md` file is checked into the repo ensuring all teammates use unique milestone names to avoid collisions.
|
|
685
685
|
|
|
686
686
|
Milestone names will now be generated with a 6 char random string appended e.g. instead of `M001` you'll get something like `M001-ush8s3`
|
|
687
687
|
|
|
@@ -689,7 +689,7 @@ Milestone names will now be generated with a 6 char random string appended e.g.
|
|
|
689
689
|
|
|
690
690
|
1. Ensure you are not in the middle of any milestones (clean state)
|
|
691
691
|
2. Update the `.gsd/` related entries in your `.gitignore` to follow the `Suggested .gitignore setup` section under `Working in teams` (ensure you are no longer blanket ignoring the whole `.gsd/` directory)
|
|
692
|
-
3. Update your `.gsd/
|
|
692
|
+
3. Update your `.gsd/PREFERENCES.md` file within the repo as per section `Unique Milestone Names`
|
|
693
693
|
4. If you want to update all your existing milestones use this prompt in GSD: `I have turned on unique milestone ids, please update all old milestone ids to use this new format e.g. M001-abc123 where abc123 is a random 6 char lowercase alpha numeric string. Update all references in all .gsd file contents, file names and directory names. Validate your work once done to ensure referential integrity.`
|
|
694
694
|
5. Commit to git
|
|
695
695
|
|
|
@@ -3,7 +3,25 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Detects terminal notifications, blocked notifications, milestone-ready signals,
|
|
5
5
|
* and classifies commands as quick (single-turn) vs long-running.
|
|
6
|
+
*
|
|
7
|
+
* Also defines exit code constants and the status→exit-code mapping function.
|
|
8
|
+
*/
|
|
9
|
+
export declare const EXIT_SUCCESS = 0;
|
|
10
|
+
export declare const EXIT_ERROR = 1;
|
|
11
|
+
export declare const EXIT_BLOCKED = 10;
|
|
12
|
+
export declare const EXIT_CANCELLED = 11;
|
|
13
|
+
/**
|
|
14
|
+
* Map a headless session status string to its standardized exit code.
|
|
15
|
+
*
|
|
16
|
+
* success → 0
|
|
17
|
+
* error → 1
|
|
18
|
+
* timeout → 1
|
|
19
|
+
* blocked → 10
|
|
20
|
+
* cancelled → 11
|
|
21
|
+
*
|
|
22
|
+
* Unknown statuses default to EXIT_ERROR (1).
|
|
6
23
|
*/
|
|
24
|
+
export declare function mapStatusToExitCode(status: string): number;
|
|
7
25
|
/**
|
|
8
26
|
* Detect genuine auto-mode termination notifications.
|
|
9
27
|
*
|
package/dist/headless-events.js
CHANGED
|
@@ -3,7 +3,43 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Detects terminal notifications, blocked notifications, milestone-ready signals,
|
|
5
5
|
* and classifies commands as quick (single-turn) vs long-running.
|
|
6
|
+
*
|
|
7
|
+
* Also defines exit code constants and the status→exit-code mapping function.
|
|
8
|
+
*/
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Exit Code Constants
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
export const EXIT_SUCCESS = 0;
|
|
13
|
+
export const EXIT_ERROR = 1;
|
|
14
|
+
export const EXIT_BLOCKED = 10;
|
|
15
|
+
export const EXIT_CANCELLED = 11;
|
|
16
|
+
/**
|
|
17
|
+
* Map a headless session status string to its standardized exit code.
|
|
18
|
+
*
|
|
19
|
+
* success → 0
|
|
20
|
+
* error → 1
|
|
21
|
+
* timeout → 1
|
|
22
|
+
* blocked → 10
|
|
23
|
+
* cancelled → 11
|
|
24
|
+
*
|
|
25
|
+
* Unknown statuses default to EXIT_ERROR (1).
|
|
6
26
|
*/
|
|
27
|
+
export function mapStatusToExitCode(status) {
|
|
28
|
+
switch (status) {
|
|
29
|
+
case 'success':
|
|
30
|
+
case 'complete':
|
|
31
|
+
return EXIT_SUCCESS;
|
|
32
|
+
case 'error':
|
|
33
|
+
case 'timeout':
|
|
34
|
+
return EXIT_ERROR;
|
|
35
|
+
case 'blocked':
|
|
36
|
+
return EXIT_BLOCKED;
|
|
37
|
+
case 'cancelled':
|
|
38
|
+
return EXIT_CANCELLED;
|
|
39
|
+
default:
|
|
40
|
+
return EXIT_ERROR;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
7
43
|
// ---------------------------------------------------------------------------
|
|
8
44
|
// Completion Detection
|
|
9
45
|
// ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Headless Types — shared types for the headless orchestrator surface.
|
|
3
|
+
*
|
|
4
|
+
* Contains the structured result type emitted in --output-format json mode
|
|
5
|
+
* and the output format discriminator.
|
|
6
|
+
*/
|
|
7
|
+
export type OutputFormat = 'text' | 'json' | 'stream-json';
|
|
8
|
+
export declare const VALID_OUTPUT_FORMATS: ReadonlySet<string>;
|
|
9
|
+
export interface HeadlessJsonResult {
|
|
10
|
+
status: 'success' | 'error' | 'blocked' | 'cancelled' | 'timeout';
|
|
11
|
+
exitCode: number;
|
|
12
|
+
sessionId?: string;
|
|
13
|
+
duration: number;
|
|
14
|
+
cost: {
|
|
15
|
+
total: number;
|
|
16
|
+
input_tokens: number;
|
|
17
|
+
output_tokens: number;
|
|
18
|
+
cache_read_tokens: number;
|
|
19
|
+
cache_write_tokens: number;
|
|
20
|
+
};
|
|
21
|
+
toolCalls: number;
|
|
22
|
+
events: number;
|
|
23
|
+
milestone?: string;
|
|
24
|
+
phase?: string;
|
|
25
|
+
nextAction?: string;
|
|
26
|
+
artifacts?: string[];
|
|
27
|
+
commits?: string[];
|
|
28
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Headless Types — shared types for the headless orchestrator surface.
|
|
3
|
+
*
|
|
4
|
+
* Contains the structured result type emitted in --output-format json mode
|
|
5
|
+
* and the output format discriminator.
|
|
6
|
+
*/
|
|
7
|
+
export const VALID_OUTPUT_FORMATS = new Set(['text', 'json', 'stream-json']);
|
package/dist/headless.d.ts
CHANGED
|
@@ -6,13 +6,16 @@
|
|
|
6
6
|
* progress to stderr.
|
|
7
7
|
*
|
|
8
8
|
* Exit codes:
|
|
9
|
-
* 0
|
|
10
|
-
* 1
|
|
11
|
-
*
|
|
9
|
+
* 0 — complete (command finished successfully)
|
|
10
|
+
* 1 — error or timeout
|
|
11
|
+
* 10 — blocked (command reported a blocker)
|
|
12
|
+
* 11 — cancelled (SIGINT/SIGTERM received)
|
|
12
13
|
*/
|
|
14
|
+
import type { OutputFormat } from './headless-types.js';
|
|
13
15
|
export interface HeadlessOptions {
|
|
14
16
|
timeout: number;
|
|
15
17
|
json: boolean;
|
|
18
|
+
outputFormat: OutputFormat;
|
|
16
19
|
model?: string;
|
|
17
20
|
command: string;
|
|
18
21
|
commandArgs: string[];
|
|
@@ -25,6 +28,8 @@ export interface HeadlessOptions {
|
|
|
25
28
|
responseTimeout?: number;
|
|
26
29
|
answers?: string;
|
|
27
30
|
eventFilter?: Set<string>;
|
|
31
|
+
resumeSession?: string;
|
|
32
|
+
bare?: boolean;
|
|
28
33
|
}
|
|
29
34
|
export declare function parseHeadlessArgs(argv: string[]): HeadlessOptions;
|
|
30
35
|
export declare function runHeadless(options: HeadlessOptions): Promise<void>;
|
package/dist/headless.js
CHANGED
|
@@ -6,16 +6,18 @@
|
|
|
6
6
|
* progress to stderr.
|
|
7
7
|
*
|
|
8
8
|
* Exit codes:
|
|
9
|
-
* 0
|
|
10
|
-
* 1
|
|
11
|
-
*
|
|
9
|
+
* 0 — complete (command finished successfully)
|
|
10
|
+
* 1 — error or timeout
|
|
11
|
+
* 10 — blocked (command reported a blocker)
|
|
12
|
+
* 11 — cancelled (SIGINT/SIGTERM received)
|
|
12
13
|
*/
|
|
13
14
|
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
14
15
|
import { join } from 'node:path';
|
|
15
16
|
import { resolve } from 'node:path';
|
|
16
17
|
import { RpcClient } from '@gsd/pi-coding-agent';
|
|
17
18
|
import { loadAndValidateAnswerFile, AnswerInjector } from './headless-answers.js';
|
|
18
|
-
import { isTerminalNotification, isBlockedNotification, isMilestoneReadyNotification, isQuickCommand, FIRE_AND_FORGET_METHODS, IDLE_TIMEOUT_MS, NEW_MILESTONE_IDLE_TIMEOUT_MS, } from './headless-events.js';
|
|
19
|
+
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, } from './headless-events.js';
|
|
20
|
+
import { VALID_OUTPUT_FORMATS } from './headless-types.js';
|
|
19
21
|
import { handleExtensionUIRequest, formatProgress, startSupervisedStdinReader, } from './headless-ui.js';
|
|
20
22
|
import { loadContext, bootstrapGsdProject, } from './headless-context.js';
|
|
21
23
|
// ---------------------------------------------------------------------------
|
|
@@ -25,6 +27,7 @@ export function parseHeadlessArgs(argv) {
|
|
|
25
27
|
const options = {
|
|
26
28
|
timeout: 300_000,
|
|
27
29
|
json: false,
|
|
30
|
+
outputFormat: 'text',
|
|
28
31
|
command: 'auto',
|
|
29
32
|
commandArgs: [],
|
|
30
33
|
};
|
|
@@ -44,6 +47,18 @@ export function parseHeadlessArgs(argv) {
|
|
|
44
47
|
}
|
|
45
48
|
else if (arg === '--json') {
|
|
46
49
|
options.json = true;
|
|
50
|
+
options.outputFormat = 'stream-json';
|
|
51
|
+
}
|
|
52
|
+
else if (arg === '--output-format' && i + 1 < args.length) {
|
|
53
|
+
const fmt = args[++i];
|
|
54
|
+
if (!VALID_OUTPUT_FORMATS.has(fmt)) {
|
|
55
|
+
process.stderr.write(`[headless] Error: --output-format must be one of: text, json, stream-json (got '${fmt}')\n`);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
options.outputFormat = fmt;
|
|
59
|
+
if (fmt === 'stream-json' || fmt === 'json') {
|
|
60
|
+
options.json = true;
|
|
61
|
+
}
|
|
47
62
|
}
|
|
48
63
|
else if (arg === '--model' && i + 1 < args.length) {
|
|
49
64
|
// --model can also be passed from the main CLI; headless-specific takes precedence
|
|
@@ -74,10 +89,16 @@ export function parseHeadlessArgs(argv) {
|
|
|
74
89
|
else if (arg === '--events' && i + 1 < args.length) {
|
|
75
90
|
options.eventFilter = new Set(args[++i].split(','));
|
|
76
91
|
options.json = true; // --events implies --json
|
|
92
|
+
if (options.outputFormat === 'text') {
|
|
93
|
+
options.outputFormat = 'stream-json';
|
|
94
|
+
}
|
|
77
95
|
}
|
|
78
96
|
else if (arg === '--supervised') {
|
|
79
97
|
options.supervised = true;
|
|
80
98
|
options.json = true; // supervised implies json
|
|
99
|
+
if (options.outputFormat === 'text') {
|
|
100
|
+
options.outputFormat = 'stream-json';
|
|
101
|
+
}
|
|
81
102
|
}
|
|
82
103
|
else if (arg === '--response-timeout' && i + 1 < args.length) {
|
|
83
104
|
options.responseTimeout = parseInt(args[++i], 10);
|
|
@@ -86,6 +107,12 @@ export function parseHeadlessArgs(argv) {
|
|
|
86
107
|
process.exit(1);
|
|
87
108
|
}
|
|
88
109
|
}
|
|
110
|
+
else if (arg === '--resume' && i + 1 < args.length) {
|
|
111
|
+
options.resumeSession = args[++i];
|
|
112
|
+
}
|
|
113
|
+
else if (arg === '--bare') {
|
|
114
|
+
options.bare = true;
|
|
115
|
+
}
|
|
89
116
|
}
|
|
90
117
|
else if (!positionalStarted) {
|
|
91
118
|
positionalStarted = true;
|
|
@@ -106,7 +133,7 @@ export async function runHeadless(options) {
|
|
|
106
133
|
while (true) {
|
|
107
134
|
const result = await runHeadlessOnce(options, restartCount);
|
|
108
135
|
// Success or blocked — exit normally
|
|
109
|
-
if (result.exitCode ===
|
|
136
|
+
if (result.exitCode === EXIT_SUCCESS || result.exitCode === EXIT_BLOCKED) {
|
|
110
137
|
process.exit(result.exitCode);
|
|
111
138
|
}
|
|
112
139
|
// Crash/error — check if we should restart
|
|
@@ -216,6 +243,10 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
216
243
|
if (injector) {
|
|
217
244
|
clientOptions.env = injector.getSecretEnvVars();
|
|
218
245
|
}
|
|
246
|
+
// Propagate --bare to the child process
|
|
247
|
+
if (options.bare) {
|
|
248
|
+
clientOptions.args = [...(clientOptions.args || []), '--bare'];
|
|
249
|
+
}
|
|
219
250
|
const client = new RpcClient(clientOptions);
|
|
220
251
|
// Event tracking
|
|
221
252
|
let totalEvents = 0;
|
|
@@ -278,7 +309,7 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
278
309
|
const timeoutTimer = options.timeout > 0
|
|
279
310
|
? setTimeout(() => {
|
|
280
311
|
process.stderr.write(`[headless] Timeout after ${options.timeout / 1000}s\n`);
|
|
281
|
-
exitCode =
|
|
312
|
+
exitCode = EXIT_ERROR;
|
|
282
313
|
resolveCompletion();
|
|
283
314
|
}, options.timeout)
|
|
284
315
|
: null;
|
|
@@ -319,7 +350,7 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
319
350
|
if (injector && !FIRE_AND_FORGET_METHODS.has(String(eventObj.method ?? ''))) {
|
|
320
351
|
if (injector.tryHandle(eventObj, stdinWriter)) {
|
|
321
352
|
if (completed) {
|
|
322
|
-
exitCode = blocked ?
|
|
353
|
+
exitCode = blocked ? EXIT_BLOCKED : EXIT_SUCCESS;
|
|
323
354
|
resolveCompletion();
|
|
324
355
|
}
|
|
325
356
|
return;
|
|
@@ -343,7 +374,7 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
343
374
|
}
|
|
344
375
|
// If we detected a terminal notification, resolve after responding
|
|
345
376
|
if (completed) {
|
|
346
|
-
exitCode = blocked ?
|
|
377
|
+
exitCode = blocked ? EXIT_BLOCKED : EXIT_SUCCESS;
|
|
347
378
|
resolveCompletion();
|
|
348
379
|
return;
|
|
349
380
|
}
|
|
@@ -361,7 +392,7 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
361
392
|
const signalHandler = () => {
|
|
362
393
|
process.stderr.write('\n[headless] Interrupted, stopping child process...\n');
|
|
363
394
|
interrupted = true;
|
|
364
|
-
exitCode =
|
|
395
|
+
exitCode = EXIT_CANCELLED;
|
|
365
396
|
client.stop().finally(() => {
|
|
366
397
|
if (timeoutTimer)
|
|
367
398
|
clearTimeout(timeoutTimer);
|
|
@@ -411,7 +442,7 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
411
442
|
if (!completed) {
|
|
412
443
|
const msg = `[headless] Child process exited unexpectedly with code ${code ?? 'null'}\n`;
|
|
413
444
|
process.stderr.write(msg);
|
|
414
|
-
exitCode =
|
|
445
|
+
exitCode = EXIT_ERROR;
|
|
415
446
|
resolveCompletion();
|
|
416
447
|
}
|
|
417
448
|
});
|
|
@@ -425,14 +456,14 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
425
456
|
}
|
|
426
457
|
catch (err) {
|
|
427
458
|
process.stderr.write(`[headless] Error: Failed to send prompt: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
428
|
-
exitCode =
|
|
459
|
+
exitCode = EXIT_ERROR;
|
|
429
460
|
}
|
|
430
461
|
// Wait for completion
|
|
431
|
-
if (exitCode ===
|
|
462
|
+
if (exitCode === EXIT_SUCCESS || exitCode === EXIT_BLOCKED) {
|
|
432
463
|
await completionPromise;
|
|
433
464
|
}
|
|
434
465
|
// Auto-mode chaining: if --auto and milestone creation succeeded, send /gsd auto
|
|
435
|
-
if (isNewMilestone && options.auto && milestoneReady && !blocked && exitCode ===
|
|
466
|
+
if (isNewMilestone && options.auto && milestoneReady && !blocked && exitCode === EXIT_SUCCESS) {
|
|
436
467
|
if (!options.json) {
|
|
437
468
|
process.stderr.write('[headless] Milestone ready — chaining into auto-mode...\n');
|
|
438
469
|
}
|
|
@@ -451,9 +482,9 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
451
482
|
}
|
|
452
483
|
catch (err) {
|
|
453
484
|
process.stderr.write(`[headless] Error: Failed to start auto-mode: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
454
|
-
exitCode =
|
|
485
|
+
exitCode = EXIT_ERROR;
|
|
455
486
|
}
|
|
456
|
-
if (exitCode ===
|
|
487
|
+
if (exitCode === EXIT_SUCCESS || exitCode === EXIT_BLOCKED) {
|
|
457
488
|
await autoCompletionPromise;
|
|
458
489
|
}
|
|
459
490
|
}
|
|
@@ -471,7 +502,7 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
471
502
|
await client.stop();
|
|
472
503
|
// Summary
|
|
473
504
|
const duration = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
474
|
-
const status = blocked ? 'blocked' : exitCode ===
|
|
505
|
+
const status = blocked ? 'blocked' : exitCode === EXIT_CANCELLED ? 'cancelled' : exitCode === EXIT_ERROR ? (totalEvents === 0 ? 'error' : 'timeout') : 'complete';
|
|
475
506
|
process.stderr.write(`[headless] Status: ${status}\n`);
|
|
476
507
|
process.stderr.write(`[headless] Duration: ${duration}s\n`);
|
|
477
508
|
process.stderr.write(`[headless] Events: ${totalEvents} total, ${toolCallCount} tool calls\n`);
|
package/dist/help-text.js
CHANGED
|
@@ -87,9 +87,12 @@ const SUBCOMMAND_HELP = {
|
|
|
87
87
|
'Run /gsd commands without the TUI. Default command: auto',
|
|
88
88
|
'',
|
|
89
89
|
'Flags:',
|
|
90
|
-
' --timeout N
|
|
91
|
-
' --json
|
|
92
|
-
' --
|
|
90
|
+
' --timeout N Overall timeout in ms (default: 300000)',
|
|
91
|
+
' --json JSONL event stream to stdout (alias for --output-format stream-json)',
|
|
92
|
+
' --output-format <fmt> Output format: text (default), json (structured result), stream-json (JSONL events)',
|
|
93
|
+
' --bare Minimal context: skip CLAUDE.md, AGENTS.md, user settings, user skills',
|
|
94
|
+
' --resume <id> Resume a prior headless session by ID',
|
|
95
|
+
' --model ID Override model',
|
|
93
96
|
' --supervised Forward interactive UI requests to orchestrator via stdout/stdin',
|
|
94
97
|
' --response-timeout N Timeout (ms) for orchestrator response (default: 30000)',
|
|
95
98
|
' --answers <path> Pre-supply answers and secrets (JSON file)',
|
|
@@ -108,11 +111,19 @@ const SUBCOMMAND_HELP = {
|
|
|
108
111
|
' --auto Start auto-mode after milestone creation',
|
|
109
112
|
' --verbose Show tool calls in progress output',
|
|
110
113
|
'',
|
|
114
|
+
'Output formats:',
|
|
115
|
+
' text Human-readable progress on stderr (default)',
|
|
116
|
+
' json Collect events silently, emit structured HeadlessJsonResult on stdout at exit',
|
|
117
|
+
' stream-json Stream JSONL events to stdout in real time (same as --json)',
|
|
118
|
+
'',
|
|
111
119
|
'Examples:',
|
|
112
120
|
' gsd headless Run /gsd auto',
|
|
113
121
|
' gsd headless next Run one unit',
|
|
114
|
-
' gsd headless --json
|
|
122
|
+
' gsd headless --output-format json auto Structured JSON result on stdout',
|
|
123
|
+
' gsd headless --json status Machine-readable JSONL stream',
|
|
115
124
|
' gsd headless --timeout 60000 With 1-minute timeout',
|
|
125
|
+
' gsd headless --bare auto Minimal context (CI/ecosystem use)',
|
|
126
|
+
' gsd headless --resume abc123 auto Resume a prior session',
|
|
116
127
|
' gsd headless new-milestone --context spec.md Create milestone from file',
|
|
117
128
|
' cat spec.md | gsd headless new-milestone --context - From stdin',
|
|
118
129
|
' gsd headless new-milestone --context spec.md --auto Create + auto-execute',
|
|
@@ -121,7 +132,7 @@ const SUBCOMMAND_HELP = {
|
|
|
121
132
|
' gsd headless --events agent_end,extension_ui_request auto Filtered event stream',
|
|
122
133
|
' gsd headless query Instant JSON state snapshot',
|
|
123
134
|
'',
|
|
124
|
-
'Exit codes: 0 =
|
|
135
|
+
'Exit codes: 0 = success, 1 = error/timeout, 10 = blocked, 11 = cancelled',
|
|
125
136
|
].join('\n'),
|
|
126
137
|
};
|
|
127
138
|
// Alias: `gsd wt --help` → same as `gsd worktree --help`
|
package/dist/onboarding.js
CHANGED
|
@@ -568,10 +568,11 @@ async function runToolKeysStep(p, pc, authStorage) {
|
|
|
568
568
|
}
|
|
569
569
|
// ─── Remote Questions Step ────────────────────────────────────────────────────
|
|
570
570
|
async function runRemoteQuestionsStep(p, pc, authStorage) {
|
|
571
|
-
// Check existing config
|
|
572
|
-
const
|
|
573
|
-
const
|
|
574
|
-
const
|
|
571
|
+
// Check existing config — use getCredentialsForProvider to skip empty-key entries
|
|
572
|
+
const hasValidKey = (provider) => authStorage.getCredentialsForProvider(provider).some((c) => c.type === 'api_key' && c.key);
|
|
573
|
+
const hasDiscord = hasValidKey('discord_bot');
|
|
574
|
+
const hasSlack = hasValidKey('slack_bot');
|
|
575
|
+
const hasTelegram = hasValidKey('telegram_bot');
|
|
575
576
|
const existingChannel = hasDiscord ? 'Discord' : hasSlack ? 'Slack' : hasTelegram ? 'Telegram' : null;
|
|
576
577
|
const options = [];
|
|
577
578
|
if (existingChannel) {
|
|
@@ -14,7 +14,7 @@ import { appRoot } from "./app-paths.js";
|
|
|
14
14
|
// boundary — this file is compiled by tsc, but preferences.ts is loaded
|
|
15
15
|
// via jiti at runtime. Importing it as .js fails because no .js exists
|
|
16
16
|
// in dist/. See #592, #1110.
|
|
17
|
-
const GLOBAL_PREFERENCES_PATH = join(appRoot, "
|
|
17
|
+
const GLOBAL_PREFERENCES_PATH = join(appRoot, "PREFERENCES.md");
|
|
18
18
|
export function saveRemoteQuestionsConfig(channel, channelId) {
|
|
19
19
|
const prefsPath = GLOBAL_PREFERENCES_PATH;
|
|
20
20
|
const block = [
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { getShellConfig, sanitizeCommand, DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, } from "@gsd/pi-coding-agent";
|
|
9
9
|
import { Type } from "@sinclair/typebox";
|
|
10
|
-
import { spawn } from "node:child_process";
|
|
10
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
11
11
|
import { createWriteStream } from "node:fs";
|
|
12
12
|
import { tmpdir } from "node:os";
|
|
13
13
|
import { join } from "node:path";
|
|
@@ -23,19 +23,33 @@ function getTempFilePath() {
|
|
|
23
23
|
return join(tmpdir(), `pi-async-bash-${id}.log`);
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
|
-
* Kill a process and its children
|
|
26
|
+
* Kill a process and its children (cross-platform).
|
|
27
|
+
* Uses process group kill on Unix; taskkill /F /T on Windows.
|
|
27
28
|
*/
|
|
28
29
|
function killTree(pid) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
if (process.platform === "win32") {
|
|
31
|
+
try {
|
|
32
|
+
spawnSync("taskkill", ["/F", "/T", "/PID", String(pid)], {
|
|
33
|
+
timeout: 5_000,
|
|
34
|
+
stdio: "ignore",
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
try {
|
|
39
|
+
process.kill(pid, "SIGTERM");
|
|
40
|
+
}
|
|
41
|
+
catch { /* already exited */ }
|
|
42
|
+
}
|
|
32
43
|
}
|
|
33
|
-
|
|
44
|
+
else {
|
|
34
45
|
try {
|
|
35
|
-
process.kill(pid, "SIGTERM");
|
|
46
|
+
process.kill(-pid, "SIGTERM");
|
|
36
47
|
}
|
|
37
48
|
catch {
|
|
38
|
-
|
|
49
|
+
try {
|
|
50
|
+
process.kill(pid, "SIGTERM");
|
|
51
|
+
}
|
|
52
|
+
catch { /* already exited */ }
|
|
39
53
|
}
|
|
40
54
|
}
|
|
41
55
|
}
|
|
@@ -96,9 +110,13 @@ function executeBashInBackground(command, cwd, signal, timeout) {
|
|
|
96
110
|
const { shell, args } = getShellConfig();
|
|
97
111
|
const rewrittenCommand = rewriteCommandWithRtk(command);
|
|
98
112
|
const resolvedCommand = sanitizeCommand(rewrittenCommand);
|
|
113
|
+
// On Windows, detached: true sets CREATE_NEW_PROCESS_GROUP which can
|
|
114
|
+
// cause EINVAL in VSCode/ConPTY terminal contexts. The bg-shell
|
|
115
|
+
// extension already guards this (process-manager.ts); align here.
|
|
116
|
+
// Process-tree cleanup uses taskkill /F /T on Windows regardless.
|
|
99
117
|
const child = spawn(shell, [...args, resolvedCommand], {
|
|
100
118
|
cwd,
|
|
101
|
-
detached:
|
|
119
|
+
detached: process.platform !== "win32",
|
|
102
120
|
env: { ...process.env },
|
|
103
121
|
stdio: ["ignore", "pipe", "pipe"],
|
|
104
122
|
});
|
|
@@ -118,14 +136,8 @@ function executeBashInBackground(command, cwd, signal, timeout) {
|
|
|
118
136
|
// If the process ignores SIGTERM, escalate to SIGKILL
|
|
119
137
|
sigkillHandle = setTimeout(() => {
|
|
120
138
|
if (child.pid) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
catch { /* ignore */ }
|
|
125
|
-
try {
|
|
126
|
-
process.kill(child.pid, "SIGKILL");
|
|
127
|
-
}
|
|
128
|
-
catch { /* ignore */ }
|
|
139
|
+
// killTree already uses taskkill /F /T on Windows
|
|
140
|
+
killTree(child.pid);
|
|
129
141
|
}
|
|
130
142
|
// Hard deadline: if even SIGKILL doesn't trigger 'close',
|
|
131
143
|
// force-resolve so the job doesn't hang forever (#2186).
|
|
@@ -121,7 +121,10 @@ export class AsyncJobManager {
|
|
|
121
121
|
deliverResult(job) {
|
|
122
122
|
if (!this.onJobComplete)
|
|
123
123
|
return;
|
|
124
|
-
|
|
124
|
+
// Defer delivery by one microtask so await_job's .then() chain runs first
|
|
125
|
+
// and can set job.awaited = true before onJobComplete checks it (#2762).
|
|
126
|
+
const cb = this.onJobComplete;
|
|
127
|
+
queueMicrotask(() => cb(job));
|
|
125
128
|
}
|
|
126
129
|
scheduleEviction(id) {
|
|
127
130
|
const existing = this.evictionTimers.get(id);
|
|
@@ -88,6 +88,19 @@ function makeErrorMessage(model, errorMsg) {
|
|
|
88
88
|
timestamp: Date.now(),
|
|
89
89
|
};
|
|
90
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Generator exhaustion without a terminal result means the SDK stream was
|
|
93
|
+
* interrupted mid-turn. Surface it as an error so downstream recovery logic
|
|
94
|
+
* can classify and retry it instead of treating it as a clean completion.
|
|
95
|
+
*/
|
|
96
|
+
export function makeStreamExhaustedErrorMessage(model, lastTextContent) {
|
|
97
|
+
const errorMsg = "stream_exhausted_without_result";
|
|
98
|
+
const message = makeErrorMessage(model, errorMsg);
|
|
99
|
+
if (lastTextContent) {
|
|
100
|
+
message.content = [{ type: "text", text: lastTextContent }];
|
|
101
|
+
}
|
|
102
|
+
return message;
|
|
103
|
+
}
|
|
91
104
|
// ---------------------------------------------------------------------------
|
|
92
105
|
// streamSimple implementation
|
|
93
106
|
// ---------------------------------------------------------------------------
|
|
@@ -278,25 +291,11 @@ async function pumpSdkMessages(model, context, options, stream) {
|
|
|
278
291
|
break;
|
|
279
292
|
}
|
|
280
293
|
}
|
|
281
|
-
// Generator
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
if (fallbackContent.length === 0) {
|
|
287
|
-
fallbackContent.push({ type: "text", text: "(Claude Code session ended without a response)" });
|
|
288
|
-
}
|
|
289
|
-
const fallback = {
|
|
290
|
-
role: "assistant",
|
|
291
|
-
content: fallbackContent,
|
|
292
|
-
api: "anthropic-messages",
|
|
293
|
-
provider: "claude-code",
|
|
294
|
-
model: modelId,
|
|
295
|
-
usage: { ...ZERO_USAGE },
|
|
296
|
-
stopReason: "stop",
|
|
297
|
-
timestamp: Date.now(),
|
|
298
|
-
};
|
|
299
|
-
stream.push({ type: "done", reason: "stop", message: fallback });
|
|
294
|
+
// Generator exhaustion without a terminal result is a stream interruption,
|
|
295
|
+
// not a successful completion. Emitting an error lets GSD classify it as a
|
|
296
|
+
// transient provider failure instead of advancing auto-mode state.
|
|
297
|
+
const fallback = makeStreamExhaustedErrorMessage(modelId, lastTextContent);
|
|
298
|
+
stream.push({ type: "error", reason: "error", error: fallback });
|
|
300
299
|
}
|
|
301
300
|
catch (err) {
|
|
302
301
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -753,6 +753,12 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
753
753
|
}
|
|
754
754
|
}
|
|
755
755
|
if (unitResult.status === "cancelled") {
|
|
756
|
+
// Provider-error pause: pauseAuto already handled cleanup and scheduled
|
|
757
|
+
// recovery. Don't hard-stop — just break out of the loop (#2762).
|
|
758
|
+
if (unitResult.errorContext?.category === "provider") {
|
|
759
|
+
debugLog("autoLoop", { phase: "exit", reason: "provider-pause", isTransient: unitResult.errorContext.isTransient });
|
|
760
|
+
return { action: "break", reason: "provider-pause" };
|
|
761
|
+
}
|
|
756
762
|
ctx.ui.notify(`Session creation timed out or was cancelled for ${unitType} ${unitId}. Will retry.`, "warning");
|
|
757
763
|
await deps.stopAuto(ctx, pi, "Session creation failed");
|
|
758
764
|
debugLog("autoLoop", { phase: "exit", reason: "session-failed" });
|
|
@@ -483,6 +483,24 @@ export const DISPATCH_RULES = [
|
|
|
483
483
|
match: async ({ state, mid, midTitle, basePath }) => {
|
|
484
484
|
if (state.phase !== "completing-milestone")
|
|
485
485
|
return null;
|
|
486
|
+
// Safety guard (#2675): block completion when VALIDATION verdict is
|
|
487
|
+
// needs-remediation. The state machine treats needs-remediation as
|
|
488
|
+
// terminal (to prevent validate-milestone loops per #832), but
|
|
489
|
+
// completing-milestone should NOT proceed — remediation work is needed.
|
|
490
|
+
const validationFile = resolveMilestoneFile(basePath, mid, "VALIDATION");
|
|
491
|
+
if (validationFile) {
|
|
492
|
+
const validationContent = await loadFile(validationFile);
|
|
493
|
+
if (validationContent) {
|
|
494
|
+
const verdict = extractVerdict(validationContent);
|
|
495
|
+
if (verdict === "needs-remediation") {
|
|
496
|
+
return {
|
|
497
|
+
action: "stop",
|
|
498
|
+
reason: `Cannot complete milestone ${mid}: VALIDATION verdict is "needs-remediation". Address the remediation findings and re-run validation, or update the verdict manually.`,
|
|
499
|
+
level: "warning",
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
486
504
|
// Safety guard (#1368): verify all roadmap slices have SUMMARY files.
|
|
487
505
|
const missingSlices = findMissingSummaries(basePath, mid);
|
|
488
506
|
if (missingSlices.length > 0) {
|
|
@@ -34,6 +34,7 @@ import { isDbAvailable, getMilestone } from "./gsd-db.js";
|
|
|
34
34
|
import { hideFooter } from "./auto-dashboard.js";
|
|
35
35
|
import { debugLog, enableDebug, isDebugEnabled, getDebugLogPath, } from "./debug-logger.js";
|
|
36
36
|
import { parseUnitId } from "./unit-id.js";
|
|
37
|
+
import { setLogBasePath } from "./workflow-logger.js";
|
|
37
38
|
import { existsSync, mkdirSync, readdirSync, statSync, unlinkSync, } from "node:fs";
|
|
38
39
|
import { join } from "node:path";
|
|
39
40
|
import { sep as pathSep } from "node:path";
|
|
@@ -312,6 +313,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
312
313
|
s.verbose = verboseMode;
|
|
313
314
|
s.cmdCtx = ctx;
|
|
314
315
|
s.basePath = base;
|
|
316
|
+
setLogBasePath(base);
|
|
315
317
|
s.unitDispatchCount.clear();
|
|
316
318
|
s.unitRecoveryCount.clear();
|
|
317
319
|
s.lastBudgetAlertLevel = 0;
|