gsd-pi 2.51.0 → 2.52.0-dev.655ad8a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -36
- package/dist/headless-events.d.ts +18 -0
- package/dist/headless-events.js +36 -0
- package/dist/headless-query.js +1 -1
- package/dist/headless-types.d.ts +28 -0
- package/dist/headless-types.js +7 -0
- package/dist/headless.d.ts +8 -3
- package/dist/headless.js +47 -16
- package/dist/help-text.js +16 -5
- package/dist/onboarding.js +5 -4
- package/dist/remote-questions-config.js +1 -1
- package/dist/resources/extensions/async-jobs/async-bash-tool.js +29 -17
- package/dist/resources/extensions/async-jobs/job-manager.js +4 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +18 -19
- package/dist/resources/extensions/get-secrets-from-user.js +7 -0
- package/dist/resources/extensions/gsd/auto/phases.js +34 -8
- package/dist/resources/extensions/gsd/auto-dispatch.js +23 -1
- package/dist/resources/extensions/gsd/auto-start.js +2 -0
- package/dist/resources/extensions/gsd/auto-timers.js +24 -2
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +25 -7
- package/dist/resources/extensions/gsd/auto-worktree.js +91 -14
- package/dist/resources/extensions/gsd/auto.js +30 -4
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +99 -70
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +12 -2
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +1 -1
- package/dist/resources/extensions/gsd/claude-import.js +60 -9
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +69 -6
- package/dist/resources/extensions/gsd/commands-config.js +10 -5
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +4 -4
- package/dist/resources/extensions/gsd/detection.js +6 -6
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +5 -5
- package/dist/resources/extensions/gsd/error-classifier.js +105 -0
- package/dist/resources/extensions/gsd/git-service.js +4 -3
- package/dist/resources/extensions/gsd/gitignore.js +7 -7
- package/dist/resources/extensions/gsd/gsd-db.js +298 -45
- package/dist/resources/extensions/gsd/guided-flow.js +4 -3
- package/dist/resources/extensions/gsd/init-wizard.js +2 -2
- package/dist/resources/extensions/gsd/key-manager.js +7 -16
- package/dist/resources/extensions/gsd/markdown-renderer.js +5 -4
- package/dist/resources/extensions/gsd/memory-store.js +28 -13
- package/dist/resources/extensions/gsd/milestone-actions.js +19 -0
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +18 -2
- package/dist/resources/extensions/gsd/preferences-models.js +1 -13
- package/dist/resources/extensions/gsd/preferences-types.js +1 -1
- package/dist/resources/extensions/gsd/preferences.js +13 -13
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/provider-error-pause.js +0 -44
- package/dist/resources/extensions/gsd/rule-registry.js +1 -1
- package/dist/resources/extensions/gsd/service-tier.js +13 -2
- package/dist/resources/extensions/gsd/state.js +38 -30
- package/dist/resources/extensions/gsd/status-guards.js +12 -0
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +7 -13
- package/dist/resources/extensions/gsd/tools/complete-slice.js +7 -20
- package/dist/resources/extensions/gsd/tools/complete-task.js +11 -21
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +28 -29
- package/dist/resources/extensions/gsd/tools/plan-slice.js +27 -26
- package/dist/resources/extensions/gsd/tools/plan-task.js +23 -23
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +50 -41
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +4 -3
- package/dist/resources/extensions/gsd/tools/reopen-task.js +5 -4
- package/dist/resources/extensions/gsd/tools/replan-slice.js +51 -41
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +23 -16
- package/dist/resources/extensions/gsd/validation.js +21 -0
- package/dist/resources/extensions/gsd/workflow-logger.js +0 -1
- package/dist/resources/extensions/remote-questions/config.js +1 -1
- package/dist/resources/extensions/remote-questions/remote-command.js +1 -1
- package/dist/resources/extensions/search-the-web/native-search.js +1 -1
- package/dist/resources/extensions/search-the-web/provider.js +1 -1
- package/dist/resources/extensions/shared/rtk.js +14 -4
- package/dist/rtk.js +3 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
- package/dist/web/standalone/.next/build-manifest.json +4 -4
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/required-server-files.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -4
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +5 -5
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +5 -5
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
- package/dist/web/standalone/.next/server/chunks/2229.js +3 -3
- package/dist/web/standalone/.next/server/chunks/7471.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/4024.87fd909ae0110f50.js +9 -0
- package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-b950e4e384cc62b3.js +1 -0
- package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-cfc9a116e6450a6b.js → webpack-bca0e732db0dcec3.js} +1 -1
- package/dist/web/standalone/.next/static/css/a58ef8a151aa0493.css +1 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/dist/wizard.js +4 -1
- package/package.json +2 -2
- package/packages/mcp-server/README.md +202 -0
- package/packages/mcp-server/package.json +36 -0
- package/packages/mcp-server/src/cli.ts +68 -0
- package/packages/mcp-server/src/index.ts +14 -0
- package/packages/mcp-server/src/mcp-server.test.ts +628 -0
- package/packages/mcp-server/src/server.ts +278 -0
- package/packages/mcp-server/src/session-manager.ts +328 -0
- package/packages/mcp-server/src/types.ts +107 -0
- package/packages/mcp-server/tsconfig.json +24 -0
- package/packages/pi-ai/dist/models.d.ts +14 -3
- package/packages/pi-ai/dist/models.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.js +53 -10
- package/packages/pi-ai/dist/models.js.map +1 -1
- package/packages/pi-ai/dist/models.test.js +102 -1
- package/packages/pi-ai/dist/models.test.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +30 -0
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/src/models.test.ts +114 -1
- package/packages/pi-ai/src/models.ts +70 -13
- package/packages/pi-ai/src/types.ts +31 -0
- package/packages/pi-coding-agent/dist/cli/args.d.ts +2 -0
- package/packages/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/cli/args.js +3 -0
- package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/bash-executor.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/bash-executor.js +5 -1
- package/packages/pi-coding-agent/dist/core/bash-executor.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +9 -4
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.d.ts +19 -0
- package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js +83 -0
- package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js +5 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +5 -3
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +0 -2
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts +28 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js +49 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +114 -6
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.d.ts +9 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.js +831 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts +66 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.js.map +1 -1
- package/packages/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/utils/shell.js +0 -1
- package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/cli/args.ts +4 -0
- package/packages/pi-coding-agent/src/core/bash-executor.ts +5 -1
- package/packages/pi-coding-agent/src/core/model-registry.ts +10 -3
- package/packages/pi-coding-agent/src/core/tools/bash-spawn-windows.test.ts +101 -0
- package/packages/pi-coding-agent/src/core/tools/bash.ts +5 -1
- package/packages/pi-coding-agent/src/index.ts +3 -0
- package/packages/pi-coding-agent/src/main.ts +5 -3
- package/packages/pi-coding-agent/src/modes/index.ts +8 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +0 -2
- package/packages/pi-coding-agent/src/modes/rpc/rpc-client.ts +54 -1
- package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +124 -6
- package/packages/pi-coding-agent/src/modes/rpc/rpc-protocol-v2.test.ts +971 -0
- package/packages/pi-coding-agent/src/modes/rpc/rpc-types.ts +61 -4
- package/packages/pi-coding-agent/src/utils/shell.ts +0 -1
- package/packages/rpc-client/package.json +20 -0
- package/pkg/package.json +1 -1
- package/scripts/ensure-workspace-builds.cjs +36 -8
- package/src/resources/extensions/async-jobs/async-bash-tool.ts +22 -11
- package/src/resources/extensions/async-jobs/job-manager.ts +4 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +19 -20
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +21 -0
- package/src/resources/extensions/get-secrets-from-user.ts +8 -0
- package/src/resources/extensions/gsd/auto/phases.ts +44 -7
- package/src/resources/extensions/gsd/auto-dispatch.ts +25 -1
- package/src/resources/extensions/gsd/auto-start.ts +2 -0
- package/src/resources/extensions/gsd/auto-timers.ts +25 -1
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +30 -6
- package/src/resources/extensions/gsd/auto-worktree.ts +94 -14
- package/src/resources/extensions/gsd/auto.ts +31 -4
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +118 -73
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +11 -2
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +1 -1
- package/src/resources/extensions/gsd/claude-import.ts +58 -9
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +73 -6
- package/src/resources/extensions/gsd/commands-config.ts +11 -5
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +4 -4
- package/src/resources/extensions/gsd/detection.ts +6 -6
- package/src/resources/extensions/gsd/docs/preferences-reference.md +5 -5
- package/src/resources/extensions/gsd/error-classifier.ts +139 -0
- package/src/resources/extensions/gsd/git-service.ts +4 -3
- package/src/resources/extensions/gsd/gitignore.ts +7 -7
- package/src/resources/extensions/gsd/gsd-db.ts +355 -63
- package/src/resources/extensions/gsd/guided-flow.ts +4 -3
- package/src/resources/extensions/gsd/init-wizard.ts +2 -2
- package/src/resources/extensions/gsd/key-manager.ts +7 -16
- package/src/resources/extensions/gsd/markdown-renderer.ts +5 -4
- package/src/resources/extensions/gsd/memory-store.ts +29 -18
- package/src/resources/extensions/gsd/milestone-actions.ts +17 -0
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +23 -1
- package/src/resources/extensions/gsd/preferences-models.ts +1 -13
- package/src/resources/extensions/gsd/preferences-types.ts +1 -1
- package/src/resources/extensions/gsd/preferences.ts +12 -13
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/provider-error-pause.ts +0 -57
- package/src/resources/extensions/gsd/rule-registry.ts +1 -1
- package/src/resources/extensions/gsd/service-tier.ts +14 -2
- package/src/resources/extensions/gsd/state.ts +39 -30
- package/src/resources/extensions/gsd/status-guards.ts +13 -0
- package/src/resources/extensions/gsd/tests/active-milestone-id-guard.test.ts +91 -0
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +61 -0
- package/src/resources/extensions/gsd/tests/auto-stale-lock-self-kill.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-auto-resolve.test.ts +80 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/claude-import-marketplace-discovery.test.ts +191 -0
- package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/commands-config.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +106 -0
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +35 -7
- package/src/resources/extensions/gsd/tests/detection.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/empty-db-reconciliation.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/git-service.test.ts +65 -31
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/interactive-tool-idle-exemption.test.ts +119 -0
- package/src/resources/extensions/gsd/tests/key-manager.test.ts +16 -1
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/milestone-report-path.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/parallel-orchestrator-zombie-cleanup.test.ts +277 -0
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +91 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +77 -70
- package/src/resources/extensions/gsd/tests/rate-limit-model-fallback.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +110 -0
- package/src/resources/extensions/gsd/tests/remote-questions.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/session-lock-transient-read.test.ts +9 -8
- package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/status-guards.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +42 -31
- package/src/resources/extensions/gsd/tests/token-cost-display.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/vacuous-truth-slices.test.ts +115 -0
- package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +12 -2
- package/src/resources/extensions/gsd/tests/validation-gate-patterns.test.ts +124 -0
- package/src/resources/extensions/gsd/tests/validation.test.ts +72 -0
- package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +81 -1
- package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +130 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +7 -17
- package/src/resources/extensions/gsd/tools/complete-slice.ts +7 -24
- package/src/resources/extensions/gsd/tools/complete-task.ts +13 -25
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +30 -32
- package/src/resources/extensions/gsd/tools/plan-slice.ts +30 -30
- package/src/resources/extensions/gsd/tools/plan-task.ts +26 -26
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +57 -46
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +4 -3
- package/src/resources/extensions/gsd/tools/reopen-task.ts +5 -4
- package/src/resources/extensions/gsd/tools/replan-slice.ts +55 -44
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +26 -20
- package/src/resources/extensions/gsd/validation.ts +23 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +0 -1
- package/src/resources/extensions/remote-questions/config.ts +1 -1
- package/src/resources/extensions/remote-questions/remote-command.ts +1 -1
- package/src/resources/extensions/search-the-web/native-search.ts +1 -1
- package/src/resources/extensions/search-the-web/provider.ts +1 -1
- package/src/resources/extensions/shared/rtk.ts +22 -4
- package/dist/web/standalone/.next/static/chunks/4024.9ad5def014d90ce4.js +0 -9
- package/dist/web/standalone/.next/static/chunks/app/page-fbecd1237e2d6d1f.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
- package/dist/web/standalone/.next/static/css/de141508b083f922.css +0 -1
- /package/dist/resources/extensions/gsd/templates/{preferences.md → PREFERENCES.md} +0 -0
- /package/dist/web/standalone/.next/static/{vkr67v-utm1dgZnbrBWQh → zpvUPKoW5jRAMB_fWHlPi}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{vkr67v-utm1dgZnbrBWQh → zpvUPKoW5jRAMB_fWHlPi}/_ssgManifest.js +0 -0
- /package/src/resources/extensions/gsd/templates/{preferences.md → PREFERENCES.md} +0 -0
|
@@ -408,8 +408,9 @@ export async function showDiscuss(ctx, pi, basePath) {
|
|
|
408
408
|
// Invalidate caches to pick up artifacts written by a just-completed discuss/plan
|
|
409
409
|
invalidateAllCaches();
|
|
410
410
|
const state = await deriveState(basePath);
|
|
411
|
-
// No active milestone
|
|
412
|
-
|
|
411
|
+
// No active milestone (or corrupted milestone with undefined id) —
|
|
412
|
+
// check for pending milestones to discuss instead
|
|
413
|
+
if (!state.activeMilestone?.id) {
|
|
413
414
|
const pendingMilestones = state.registry.filter(m => m.status === "pending");
|
|
414
415
|
if (pendingMilestones.length === 0) {
|
|
415
416
|
ctx.ui.notify("No active milestone. Run /gsd to create one first.", "warning");
|
|
@@ -864,7 +865,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
864
865
|
}
|
|
865
866
|
}
|
|
866
867
|
const state = await deriveState(basePath);
|
|
867
|
-
if (!state.activeMilestone) {
|
|
868
|
+
if (!state.activeMilestone?.id) {
|
|
868
869
|
// Guard: if a discuss session is already in flight, don't re-inject the prompt.
|
|
869
870
|
// Both /gsd and /gsd auto reach this branch when no milestone exists yet.
|
|
870
871
|
// Without this guard, every subsequent /gsd call overwrites pendingAutoStart
|
|
@@ -336,9 +336,9 @@ function bootstrapGsdDirectory(basePath, prefs, signals) {
|
|
|
336
336
|
assertSafeDirectory(basePath);
|
|
337
337
|
const gsd = gsdRoot(basePath);
|
|
338
338
|
mkdirSync(join(gsd, "milestones"), { recursive: true });
|
|
339
|
-
// Write
|
|
339
|
+
// Write PREFERENCES.md from wizard answers
|
|
340
340
|
const preferencesContent = buildPreferencesFile(prefs);
|
|
341
|
-
writeFileSync(join(gsd, "
|
|
341
|
+
writeFileSync(join(gsd, "PREFERENCES.md"), preferencesContent, "utf-8");
|
|
342
342
|
// Seed CONTEXT.md with detected project signals
|
|
343
343
|
const contextContent = buildContextSeed(signals);
|
|
344
344
|
if (contextContent) {
|
|
@@ -110,21 +110,12 @@ export function findProvider(idOrLabel) {
|
|
|
110
110
|
*/
|
|
111
111
|
export function getAllKeyStatuses(auth) {
|
|
112
112
|
return PROVIDER_REGISTRY.map((provider) => {
|
|
113
|
-
const
|
|
113
|
+
const rawCreds = auth.getCredentialsForProvider(provider.id);
|
|
114
|
+
// Filter out empty-key entries (left by legacy removeProviderToken or skipped onboarding)
|
|
115
|
+
const creds = rawCreds.filter((c) => !(c.type === "api_key" && !c.key));
|
|
114
116
|
const envKey = provider.envVar ? process.env[provider.envVar] : undefined;
|
|
115
117
|
if (creds.length > 0) {
|
|
116
118
|
const firstCred = creds[0];
|
|
117
|
-
// Skip empty keys (from skipped onboarding)
|
|
118
|
-
if (firstCred.type === "api_key" && !firstCred.key) {
|
|
119
|
-
return {
|
|
120
|
-
provider,
|
|
121
|
-
configured: false,
|
|
122
|
-
source: "none",
|
|
123
|
-
credentialCount: 0,
|
|
124
|
-
description: "empty key (skipped setup)",
|
|
125
|
-
backedOff: false,
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
119
|
const desc = creds.length > 1
|
|
129
120
|
? `${creds.length} keys (round-robin)`
|
|
130
121
|
: describeCredential(firstCred);
|
|
@@ -222,7 +213,7 @@ export async function handleAddKey(providerArg, ctx, auth) {
|
|
|
222
213
|
else {
|
|
223
214
|
// Interactive provider picker
|
|
224
215
|
const options = PROVIDER_REGISTRY.map((p) => {
|
|
225
|
-
const creds = auth.getCredentialsForProvider(p.id);
|
|
216
|
+
const creds = auth.getCredentialsForProvider(p.id).filter((c) => !(c.type === "api_key" && !c.key));
|
|
226
217
|
const existing = creds.length > 0 ? " (configured)" : "";
|
|
227
218
|
return `[${p.category}] ${p.label}${existing}`;
|
|
228
219
|
});
|
|
@@ -285,7 +276,7 @@ export async function handleRemoveKey(providerArg, ctx, auth) {
|
|
|
285
276
|
else {
|
|
286
277
|
// Show only configured providers
|
|
287
278
|
const configured = PROVIDER_REGISTRY.filter((p) => {
|
|
288
|
-
const creds = auth.getCredentialsForProvider(p.id);
|
|
279
|
+
const creds = auth.getCredentialsForProvider(p.id).filter((c) => !(c.type === "api_key" && !c.key));
|
|
289
280
|
return creds.length > 0;
|
|
290
281
|
});
|
|
291
282
|
if (configured.length === 0) {
|
|
@@ -508,7 +499,7 @@ export async function handleRotateKey(providerArg, ctx, auth) {
|
|
|
508
499
|
// Show only configured API key providers
|
|
509
500
|
const configured = PROVIDER_REGISTRY.filter((p) => {
|
|
510
501
|
const creds = auth.getCredentialsForProvider(p.id);
|
|
511
|
-
return creds.some((c) => c.type === "api_key");
|
|
502
|
+
return creds.some((c) => c.type === "api_key" && c.key);
|
|
512
503
|
});
|
|
513
504
|
if (configured.length === 0) {
|
|
514
505
|
ctx.ui.notify("No API keys configured to rotate.", "info");
|
|
@@ -646,7 +637,7 @@ export function runKeyDoctor(auth) {
|
|
|
646
637
|
if (!envValue)
|
|
647
638
|
continue;
|
|
648
639
|
const creds = auth.getCredentialsForProvider(provider.id);
|
|
649
|
-
const apiKey = creds.find((c) => c.type === "api_key");
|
|
640
|
+
const apiKey = creds.find((c) => c.type === "api_key" && c.key);
|
|
650
641
|
if (apiKey?.key && apiKey.key !== envValue) {
|
|
651
642
|
findings.push({
|
|
652
643
|
severity: "warning",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
// Critical invariant: rendered markdown must round-trip through
|
|
9
9
|
// parseRoadmap(), parsePlan(), parseSummary() in files.ts.
|
|
10
10
|
import { readFileSync, existsSync, mkdirSync } from "node:fs";
|
|
11
|
+
import { isClosedStatus } from "./status-guards.js";
|
|
11
12
|
import { join, relative } from "node:path";
|
|
12
13
|
import { createRequire } from "node:module";
|
|
13
14
|
import { getAllMilestones, getMilestone, getMilestoneSlices, getSliceTasks, getTask, getSlice, getArtifact, insertArtifact, getGateResults, } from "./gsd-db.js";
|
|
@@ -262,7 +263,7 @@ function renderSlicePlanMarkdown(slice, tasks, gates = []) {
|
|
|
262
263
|
lines.push("## Tasks");
|
|
263
264
|
lines.push("");
|
|
264
265
|
for (const task of tasks) {
|
|
265
|
-
const done = task.status
|
|
266
|
+
const done = isClosedStatus(task.status) ? "x" : " ";
|
|
266
267
|
const estimate = task.estimate.trim() ? ` \`est:${task.estimate.trim()}\`` : "";
|
|
267
268
|
lines.push(`- [${done}] **${task.id}: ${task.title || task.id}**${estimate}`);
|
|
268
269
|
if (task.description.trim()) {
|
|
@@ -435,7 +436,7 @@ export async function renderPlanCheckboxes(basePath, milestoneId, sliceId) {
|
|
|
435
436
|
// Apply checkbox patches for each task
|
|
436
437
|
let updated = content;
|
|
437
438
|
for (const task of tasks) {
|
|
438
|
-
const isDone = task.status
|
|
439
|
+
const isDone = isClosedStatus(task.status);
|
|
439
440
|
const tid = task.id;
|
|
440
441
|
if (isDone) {
|
|
441
442
|
// Set [x]
|
|
@@ -660,7 +661,7 @@ export function detectStaleRenders(basePath) {
|
|
|
660
661
|
const content = readFileSync(planPath, "utf-8");
|
|
661
662
|
const parsed = parsePlan(content);
|
|
662
663
|
for (const task of tasks) {
|
|
663
|
-
const isDoneInDb = task.status
|
|
664
|
+
const isDoneInDb = isClosedStatus(task.status);
|
|
664
665
|
const planTask = parsed.tasks.find((t) => t.id === task.id);
|
|
665
666
|
if (!planTask)
|
|
666
667
|
continue;
|
|
@@ -684,7 +685,7 @@ export function detectStaleRenders(basePath) {
|
|
|
684
685
|
}
|
|
685
686
|
// Check missing task summary files
|
|
686
687
|
for (const task of tasks) {
|
|
687
|
-
if ((task.status
|
|
688
|
+
if (isClosedStatus(task.status) && task.full_summary_md) {
|
|
688
689
|
const slicePath = resolveSlicePath(basePath, milestone.id, slice.id);
|
|
689
690
|
if (slicePath) {
|
|
690
691
|
const tasksDir = join(slicePath, "tasks");
|
|
@@ -71,6 +71,9 @@ export function getActiveMemoriesRanked(limit = 30) {
|
|
|
71
71
|
/**
|
|
72
72
|
* Generate the next memory ID: MEM + zero-padded 3-digit from MAX(seq).
|
|
73
73
|
* Returns MEM001 if no memories exist.
|
|
74
|
+
*
|
|
75
|
+
* NOTE: For race-safe creation, prefer createMemory() which inserts with a
|
|
76
|
+
* placeholder ID then updates to the seq-derived ID atomically.
|
|
74
77
|
*/
|
|
75
78
|
export function nextMemoryId() {
|
|
76
79
|
if (!isDbAvailable())
|
|
@@ -94,7 +97,9 @@ export function nextMemoryId() {
|
|
|
94
97
|
}
|
|
95
98
|
// ─── Mutation Functions ─────────────────────────────────────────────────────
|
|
96
99
|
/**
|
|
97
|
-
* Insert a new memory with auto-assigned ID.
|
|
100
|
+
* Insert a new memory with a race-safe auto-assigned ID.
|
|
101
|
+
* Uses AUTOINCREMENT seq to derive the ID after insert, avoiding
|
|
102
|
+
* the read-then-write race in concurrent scenarios (e.g. worktrees).
|
|
98
103
|
* Returns the assigned ID, or null on failure.
|
|
99
104
|
*/
|
|
100
105
|
export function createMemory(fields) {
|
|
@@ -104,11 +109,12 @@ export function createMemory(fields) {
|
|
|
104
109
|
if (!adapter)
|
|
105
110
|
return null;
|
|
106
111
|
try {
|
|
107
|
-
const id = nextMemoryId();
|
|
108
112
|
const now = new Date().toISOString();
|
|
113
|
+
// Insert with a temporary placeholder ID — seq is auto-assigned
|
|
114
|
+
const placeholder = `_TMP_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
109
115
|
adapter.prepare(`INSERT INTO memories (id, category, content, confidence, source_unit_type, source_unit_id, created_at, updated_at)
|
|
110
116
|
VALUES (:id, :category, :content, :confidence, :source_unit_type, :source_unit_id, :created_at, :updated_at)`).run({
|
|
111
|
-
':id':
|
|
117
|
+
':id': placeholder,
|
|
112
118
|
':category': fields.category,
|
|
113
119
|
':content': fields.content,
|
|
114
120
|
':confidence': fields.confidence ?? 0.8,
|
|
@@ -117,7 +123,17 @@ export function createMemory(fields) {
|
|
|
117
123
|
':created_at': now,
|
|
118
124
|
':updated_at': now,
|
|
119
125
|
});
|
|
120
|
-
|
|
126
|
+
// Derive the real ID from the assigned seq
|
|
127
|
+
const row = adapter.prepare('SELECT seq FROM memories WHERE id = :id').get({ ':id': placeholder });
|
|
128
|
+
if (!row)
|
|
129
|
+
return placeholder; // fallback — should not happen
|
|
130
|
+
const seq = row['seq'];
|
|
131
|
+
const realId = `MEM${String(seq).padStart(3, '0')}`;
|
|
132
|
+
adapter.prepare('UPDATE memories SET id = :real_id WHERE id = :placeholder').run({
|
|
133
|
+
':real_id': realId,
|
|
134
|
+
':placeholder': placeholder,
|
|
135
|
+
});
|
|
136
|
+
return realId;
|
|
121
137
|
}
|
|
122
138
|
catch {
|
|
123
139
|
return null;
|
|
@@ -258,15 +274,14 @@ export function enforceMemoryCap(max = 50) {
|
|
|
258
274
|
if (count <= max)
|
|
259
275
|
return;
|
|
260
276
|
const excess = count - max;
|
|
261
|
-
//
|
|
262
|
-
|
|
263
|
-
WHERE
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
}
|
|
277
|
+
// Batch update: supersede lowest-ranked active memories in a single statement
|
|
278
|
+
adapter.prepare(`UPDATE memories SET superseded_by = 'CAP_EXCEEDED', updated_at = :now
|
|
279
|
+
WHERE id IN (
|
|
280
|
+
SELECT id FROM memories
|
|
281
|
+
WHERE superseded_by IS NULL
|
|
282
|
+
ORDER BY (confidence * (1.0 + hit_count * 0.1)) ASC
|
|
283
|
+
LIMIT :limit
|
|
284
|
+
)`).run({ ':now': new Date().toISOString(), ':limit': excess });
|
|
270
285
|
}
|
|
271
286
|
catch {
|
|
272
287
|
// non-fatal
|
|
@@ -15,6 +15,7 @@ import { join } from "node:path";
|
|
|
15
15
|
import { resolveMilestonePath, resolveMilestoneFile, buildMilestoneFileName, } from "./paths.js";
|
|
16
16
|
import { invalidateAllCaches } from "./cache.js";
|
|
17
17
|
import { loadQueueOrder, saveQueueOrder } from "./queue-order.js";
|
|
18
|
+
import { isDbAvailable, updateMilestoneStatus } from "./gsd-db.js";
|
|
18
19
|
// ─── Park ──────────────────────────────────────────────────────────────────
|
|
19
20
|
/**
|
|
20
21
|
* Park a milestone — creates a PARKED.md marker file with reason and timestamp.
|
|
@@ -44,6 +45,15 @@ export function parkMilestone(basePath, milestoneId, reason) {
|
|
|
44
45
|
"",
|
|
45
46
|
].join("\n");
|
|
46
47
|
writeFileSync(parkedPath, content, "utf-8");
|
|
48
|
+
// Sync DB status so deriveStateFromDb also skips this milestone (#2694)
|
|
49
|
+
if (isDbAvailable()) {
|
|
50
|
+
try {
|
|
51
|
+
updateMilestoneStatus(milestoneId, "parked");
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
process.stderr.write(`gsd: parkMilestone DB sync failed for ${milestoneId}: ${err.message}\n`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
47
57
|
invalidateAllCaches();
|
|
48
58
|
return true;
|
|
49
59
|
}
|
|
@@ -60,6 +70,15 @@ export function unparkMilestone(basePath, milestoneId) {
|
|
|
60
70
|
if (!existsSync(parkedPath))
|
|
61
71
|
return false; // not parked
|
|
62
72
|
unlinkSync(parkedPath);
|
|
73
|
+
// Sync DB status so deriveStateFromDb picks up the unparked milestone (#2694)
|
|
74
|
+
if (isDbAvailable()) {
|
|
75
|
+
try {
|
|
76
|
+
updateMilestoneStatus(milestoneId, "active");
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
process.stderr.write(`gsd: unparkMilestone DB sync failed for ${milestoneId}: ${err.message}\n`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
63
82
|
invalidateAllCaches();
|
|
64
83
|
return true;
|
|
65
84
|
}
|
|
@@ -131,8 +131,15 @@ function appendWorkerLog(basePath, milestoneId, chunk) {
|
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
function restoreRuntimeState(basePath) {
|
|
134
|
-
if (state?.active)
|
|
135
|
-
|
|
134
|
+
if (state?.active) {
|
|
135
|
+
// Verify at least one worker is alive — if all are in terminal states,
|
|
136
|
+
// the cached state is stale and we should fall through to cleanup.
|
|
137
|
+
const hasLiveWorker = [...state.workers.values()].some((w) => w.state !== "error" && w.state !== "stopped");
|
|
138
|
+
if (hasLiveWorker)
|
|
139
|
+
return true;
|
|
140
|
+
// All workers dead — clear stale state so restoreState() can clean up.
|
|
141
|
+
state = null;
|
|
142
|
+
}
|
|
136
143
|
const restored = restoreState(basePath);
|
|
137
144
|
if (restored && restored.workers.length > 0) {
|
|
138
145
|
const config = resolveParallelConfig(undefined);
|
|
@@ -778,6 +785,15 @@ export function refreshWorkerStatuses(basePath, options = {}) {
|
|
|
778
785
|
for (const worker of state.workers.values()) {
|
|
779
786
|
state.totalCost += worker.cost;
|
|
780
787
|
}
|
|
788
|
+
// If all workers are in a terminal state (error/stopped), the orchestration
|
|
789
|
+
// is finished — deactivate and clean up so zombie workers don't persist.
|
|
790
|
+
const allDead = [...state.workers.values()].every((w) => w.state === "error" || w.state === "stopped");
|
|
791
|
+
if (allDead) {
|
|
792
|
+
state.active = false;
|
|
793
|
+
removeStateFile(basePath);
|
|
794
|
+
state = null;
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
781
797
|
// Persist updated state for crash recovery
|
|
782
798
|
persistState(basePath);
|
|
783
799
|
}
|
|
@@ -98,18 +98,6 @@ export function getNextFallbackModel(currentModelId, modelConfig) {
|
|
|
98
98
|
return modelsToTry[0];
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
|
-
/**
|
|
102
|
-
* Detect whether an error message indicates a transient network error
|
|
103
|
-
* (worth retrying the same model) vs a permanent provider error
|
|
104
|
-
* (auth failure, quota exceeded, etc. -- should fall back immediately).
|
|
105
|
-
*/
|
|
106
|
-
export function isTransientNetworkError(errorMsg) {
|
|
107
|
-
if (!errorMsg)
|
|
108
|
-
return false;
|
|
109
|
-
const hasNetworkSignal = /network|ECONNRESET|ETIMEDOUT|ECONNREFUSED|socket hang up|fetch failed|connection.*reset|dns/i.test(errorMsg);
|
|
110
|
-
const hasPermanentSignal = /auth|unauthorized|forbidden|invalid.*key|quota|billing/i.test(errorMsg);
|
|
111
|
-
return hasNetworkSignal && !hasPermanentSignal;
|
|
112
|
-
}
|
|
113
101
|
/**
|
|
114
102
|
* Validate a model ID string.
|
|
115
103
|
* Returns true if the ID looks like a valid model identifier.
|
|
@@ -273,7 +261,7 @@ export function resolveContextSelection() {
|
|
|
273
261
|
return profile === "budget" ? "smart" : "full";
|
|
274
262
|
}
|
|
275
263
|
/**
|
|
276
|
-
* Resolve the search provider preference from
|
|
264
|
+
* Resolve the search provider preference from PREFERENCES.md.
|
|
277
265
|
* Returns undefined if not configured (caller falls back to existing behavior).
|
|
278
266
|
*/
|
|
279
267
|
export function resolveSearchProviderFromPreferences() {
|
|
@@ -24,27 +24,27 @@ export { validatePreferences } from "./preferences-validation.js";
|
|
|
24
24
|
// ─── Re-exports: skills ─────────────────────────────────────────────────────
|
|
25
25
|
export { resolveAllSkillReferences, resolveSkillDiscoveryMode, resolveSkillStalenessDays, } from "./preferences-skills.js";
|
|
26
26
|
// ─── Re-exports: models ─────────────────────────────────────────────────────
|
|
27
|
-
export { resolveModelForUnit, resolveModelWithFallbacksForUnit, getNextFallbackModel,
|
|
27
|
+
export { resolveModelForUnit, resolveModelWithFallbacksForUnit, getNextFallbackModel, validateModelId, updatePreferencesModels, resolveDynamicRoutingConfig, resolveAutoSupervisorConfig, resolveProfileDefaults, resolveEffectiveProfile, resolveInlineLevel, resolveContextSelection, resolveSearchProviderFromPreferences, } from "./preferences-models.js";
|
|
28
28
|
// ─── Path Constants & Getters ───────────────────────────────────────────────
|
|
29
29
|
function gsdHome() {
|
|
30
30
|
return process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
31
31
|
}
|
|
32
32
|
function globalPreferencesPath() {
|
|
33
|
-
return join(gsdHome(), "
|
|
33
|
+
return join(gsdHome(), "PREFERENCES.md");
|
|
34
34
|
}
|
|
35
35
|
function legacyGlobalPreferencesPath() {
|
|
36
36
|
return join(homedir(), ".pi", "agent", "gsd-preferences.md");
|
|
37
37
|
}
|
|
38
38
|
function projectPreferencesPath() {
|
|
39
|
-
return join(gsdRoot(process.cwd()), "
|
|
39
|
+
return join(gsdRoot(process.cwd()), "PREFERENCES.md");
|
|
40
40
|
}
|
|
41
|
-
//
|
|
42
|
-
// Check
|
|
43
|
-
function
|
|
44
|
-
return join(gsdHome(), "
|
|
41
|
+
// Legacy: older versions used lowercase preferences.md.
|
|
42
|
+
// Check lowercase as a fallback so those files aren't silently ignored.
|
|
43
|
+
function globalPreferencesPathLegacy() {
|
|
44
|
+
return join(gsdHome(), "preferences.md");
|
|
45
45
|
}
|
|
46
|
-
function
|
|
47
|
-
return join(gsdRoot(process.cwd()), "
|
|
46
|
+
function projectPreferencesPathLegacy() {
|
|
47
|
+
return join(gsdRoot(process.cwd()), "preferences.md");
|
|
48
48
|
}
|
|
49
49
|
export function getGlobalGSDPreferencesPath() {
|
|
50
50
|
return globalPreferencesPath();
|
|
@@ -58,12 +58,12 @@ export function getProjectGSDPreferencesPath() {
|
|
|
58
58
|
// ─── Loading ────────────────────────────────────────────────────────────────
|
|
59
59
|
export function loadGlobalGSDPreferences() {
|
|
60
60
|
return loadPreferencesFile(globalPreferencesPath(), "global")
|
|
61
|
-
?? loadPreferencesFile(
|
|
61
|
+
?? loadPreferencesFile(globalPreferencesPathLegacy(), "global")
|
|
62
62
|
?? loadPreferencesFile(legacyGlobalPreferencesPath(), "global");
|
|
63
63
|
}
|
|
64
64
|
export function loadProjectGSDPreferences() {
|
|
65
65
|
return loadPreferencesFile(projectPreferencesPath(), "project")
|
|
66
|
-
?? loadPreferencesFile(
|
|
66
|
+
?? loadPreferencesFile(projectPreferencesPathLegacy(), "project");
|
|
67
67
|
}
|
|
68
68
|
export function loadEffectiveGSDPreferences() {
|
|
69
69
|
const globalPreferences = loadGlobalGSDPreferences();
|
|
@@ -149,7 +149,7 @@ export function parsePreferencesMarkdown(content) {
|
|
|
149
149
|
}
|
|
150
150
|
if (!_warnedUnrecognizedFormat) {
|
|
151
151
|
_warnedUnrecognizedFormat = true;
|
|
152
|
-
console.warn("[parsePreferencesMarkdown]
|
|
152
|
+
console.warn("[parsePreferencesMarkdown] PREFERENCES.md exists but uses an unrecognized format — skipping.");
|
|
153
153
|
}
|
|
154
154
|
return null;
|
|
155
155
|
}
|
|
@@ -398,7 +398,7 @@ export function resolvePreDispatchHooks() {
|
|
|
398
398
|
* Resolve the effective git isolation mode from preferences.
|
|
399
399
|
* Returns "none" (default), "worktree", or "branch".
|
|
400
400
|
*
|
|
401
|
-
* Default is "none" so GSD works out of the box without
|
|
401
|
+
* Default is "none" so GSD works out of the box without PREFERENCES.md.
|
|
402
402
|
* Worktree isolation requires explicit opt-in because it depends on git
|
|
403
403
|
* branch infrastructure that must be set up before use.
|
|
404
404
|
*/
|
|
@@ -92,7 +92,7 @@ Titles live inside file content (headings, frontmatter), not in file or director
|
|
|
92
92
|
|
|
93
93
|
### Isolation Model
|
|
94
94
|
|
|
95
|
-
Auto-mode supports three isolation modes (configured in `.gsd/
|
|
95
|
+
Auto-mode supports three isolation modes (configured in `.gsd/PREFERENCES.md` under `taskIsolation.mode`):
|
|
96
96
|
|
|
97
97
|
- **worktree** (default): Work happens in `.gsd/worktrees/<MID>/`, a full git worktree on the `milestone/<MID>` branch. Each worktree has its own working copy and `.gsd/` directory. Squash-merged back to the integration branch on milestone completion.
|
|
98
98
|
- **branch**: Work happens in the project root on a `milestone/<MID>` branch. No worktree directory — files are checked out in-place.
|
|
@@ -1,47 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Classify a provider error as transient (auto-resume) or permanent (manual resume).
|
|
3
|
-
*
|
|
4
|
-
* Transient: rate limits, server errors (500/502/503), overloaded, internal errors.
|
|
5
|
-
* These are expected to self-resolve and should auto-resume after a delay.
|
|
6
|
-
*
|
|
7
|
-
* Permanent: auth errors, invalid API key, billing issues.
|
|
8
|
-
* These require user intervention and should pause indefinitely.
|
|
9
|
-
*/
|
|
10
|
-
export function classifyProviderError(errorMsg) {
|
|
11
|
-
const isRateLimit = /rate.?limit|too many requests|429/i.test(errorMsg);
|
|
12
|
-
const isServerError = /internal server error|500|502|503|overloaded|server_error|api_error|service.?unavailable/i.test(errorMsg);
|
|
13
|
-
// Connection/process errors — transient, auto-resume after brief backoff (#2309).
|
|
14
|
-
// These indicate the process was killed, the connection was reset, or a network
|
|
15
|
-
// blip occurred. They are NOT permanent failures.
|
|
16
|
-
const isConnectionError = /terminated|connection.?reset|connection.?refused|other side closed|fetch failed|network.?(?:is\s+)?unavailable|ECONNREFUSED|ECONNRESET|EPIPE/i.test(errorMsg);
|
|
17
|
-
// Permanent errors — never auto-resume
|
|
18
|
-
const isPermanent = /auth|unauthorized|forbidden|invalid.*key|invalid.*api|billing|quota exceeded|account/i.test(errorMsg);
|
|
19
|
-
if (isPermanent && !isRateLimit) {
|
|
20
|
-
return { isTransient: false, isRateLimit: false, suggestedDelayMs: 0 };
|
|
21
|
-
}
|
|
22
|
-
if (isRateLimit) {
|
|
23
|
-
// Try to extract retry-after from the message
|
|
24
|
-
const resetMatch = errorMsg.match(/reset in (\d+)s/i);
|
|
25
|
-
const delayMs = resetMatch ? Number(resetMatch[1]) * 1000 : 60_000; // default 60s for rate limits
|
|
26
|
-
return { isTransient: true, isRateLimit: true, suggestedDelayMs: delayMs };
|
|
27
|
-
}
|
|
28
|
-
if (isServerError) {
|
|
29
|
-
return { isTransient: true, isRateLimit: false, suggestedDelayMs: 30_000 }; // 30s for server errors
|
|
30
|
-
}
|
|
31
|
-
if (isConnectionError) {
|
|
32
|
-
return { isTransient: true, isRateLimit: false, suggestedDelayMs: 15_000 }; // 15s for connection errors
|
|
33
|
-
}
|
|
34
|
-
// Stream-truncation JSON parse errors — transient (#2572).
|
|
35
|
-
// When the API stream is cut mid-chunk, pi tries to reassemble the partial
|
|
36
|
-
// tool-call JSON and gets a SyntaxError. This is the downstream symptom of
|
|
37
|
-
// a connection drop — same root cause as ECONNRESET, one layer up.
|
|
38
|
-
const isMalformedStream = /Unexpected end of JSON|Unexpected token.*JSON|Expected double-quoted property name|SyntaxError.*JSON/i.test(errorMsg);
|
|
39
|
-
if (isMalformedStream) {
|
|
40
|
-
return { isTransient: true, isRateLimit: false, suggestedDelayMs: 15_000 }; // 15s, same as connection errors
|
|
41
|
-
}
|
|
42
|
-
// Unknown error — treat as permanent (user reviews)
|
|
43
|
-
return { isTransient: false, isRateLimit: false, suggestedDelayMs: 0 };
|
|
44
|
-
}
|
|
45
1
|
/**
|
|
46
2
|
* Pause auto-mode due to a provider error.
|
|
47
3
|
*
|
|
@@ -426,7 +426,7 @@ export class RuleRegistry {
|
|
|
426
426
|
formatHookStatus() {
|
|
427
427
|
const entries = this.getHookStatus();
|
|
428
428
|
if (entries.length === 0) {
|
|
429
|
-
return "No hooks configured. Add post_unit_hooks or pre_dispatch_hooks to .gsd/
|
|
429
|
+
return "No hooks configured. Add post_unit_hooks or pre_dispatch_hooks to .gsd/PREFERENCES.md";
|
|
430
430
|
}
|
|
431
431
|
const lines = ["Configured Hooks:", ""];
|
|
432
432
|
const postHooks = entries.filter(e => e.type === "post");
|
|
@@ -13,16 +13,27 @@ import { getGlobalGSDPreferencesPath, loadEffectiveGSDPreferences, loadGlobalGSD
|
|
|
13
13
|
import { ensurePreferencesFile, serializePreferencesToFrontmatter } from "./commands-prefs-wizard.js";
|
|
14
14
|
const SERVICE_TIER_SCOPE_NOTE = "Only affects gpt-5.4 models, regardless of provider.";
|
|
15
15
|
// ─── Gating ──────────────────────────────────────────────────────────────────
|
|
16
|
+
/**
|
|
17
|
+
* Model ID prefixes (bare, without provider) that support OpenAI service tiers.
|
|
18
|
+
*
|
|
19
|
+
* This list is the fallback for callers that only have a model ID string.
|
|
20
|
+
* The authoritative source of truth is `model.capabilities.supportsServiceTier`
|
|
21
|
+
* (set via CAPABILITY_PATCHES in packages/pi-ai/src/models.ts). When callers
|
|
22
|
+
* have access to the full Model object, prefer reading capabilities directly.
|
|
23
|
+
*
|
|
24
|
+
* See: https://github.com/gsd-build/gsd-2/issues/2546
|
|
25
|
+
*/
|
|
26
|
+
const SERVICE_TIER_MODEL_PREFIXES = ["gpt-5.4"];
|
|
16
27
|
/**
|
|
17
28
|
* Returns true when the given model ID supports OpenAI service tiers.
|
|
18
|
-
*
|
|
29
|
+
* Reads from SERVICE_TIER_MODEL_PREFIXES — update that list, not this function.
|
|
19
30
|
*/
|
|
20
31
|
export function supportsServiceTier(modelId) {
|
|
21
32
|
if (!modelId)
|
|
22
33
|
return false;
|
|
23
34
|
// Strip provider prefix if present (e.g. "openai/gpt-5.4" → "gpt-5.4")
|
|
24
35
|
const bare = modelId.includes("/") ? modelId.split("/").pop() : modelId;
|
|
25
|
-
return bare.startsWith(
|
|
36
|
+
return SERVICE_TIER_MODEL_PREFIXES.some((prefix) => bare.startsWith(prefix));
|
|
26
37
|
}
|
|
27
38
|
// ─── Status Formatting ───────────────────────────────────────────────────────
|
|
28
39
|
/**
|