gsd-pi 2.72.0 → 2.73.0-dev.27730dc
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 +12 -2
- package/dist/cli.js +59 -50
- package/dist/help-text.js +1 -1
- package/dist/onboarding.js +10 -0
- package/dist/resources/extensions/async-jobs/await-tool.js +7 -4
- package/dist/resources/extensions/async-jobs/job-manager.js +28 -3
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +40 -12
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +48 -23
- package/dist/resources/extensions/gsd/auto/loop.js +84 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +5 -3
- package/dist/resources/extensions/gsd/auto-post-unit.js +6 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +9 -6
- package/dist/resources/extensions/gsd/auto-recovery.js +11 -0
- package/dist/resources/extensions/gsd/auto.js +30 -20
- package/dist/resources/extensions/gsd/bootstrap/crash-log.js +31 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +18 -7
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +9 -11
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +6 -1
- package/dist/resources/extensions/gsd/commands-handlers.js +4 -1
- package/dist/resources/extensions/gsd/context-injector.js +1 -1
- package/dist/resources/extensions/gsd/crash-recovery.js +51 -0
- package/dist/resources/extensions/gsd/custom-workflow-engine.js +3 -7
- package/dist/resources/extensions/gsd/definition-io.js +15 -0
- package/dist/resources/extensions/gsd/dispatch-guard.js +4 -0
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +6 -3
- package/dist/resources/extensions/gsd/git-service.js +11 -8
- package/dist/resources/extensions/gsd/gitignore.js +12 -6
- package/dist/resources/extensions/gsd/gsd-db.js +85 -8
- package/dist/resources/extensions/gsd/key-manager.js +2 -0
- package/dist/resources/extensions/gsd/milestone-actions.js +19 -1
- package/dist/resources/extensions/gsd/preferences-skills.js +2 -34
- package/dist/resources/extensions/gsd/preferences-types.js +15 -0
- package/dist/resources/extensions/gsd/preferences.js +16 -3
- package/dist/resources/extensions/gsd/prompt-loader.js +4 -1
- package/dist/resources/extensions/gsd/prompts/discuss.md +122 -13
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/state.js +21 -1
- package/dist/resources/extensions/gsd/workflow-projections.js +7 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +30 -3
- package/dist/resources/extensions/gsd/write-intercept.js +10 -1
- package/dist/resources/extensions/ollama/index.js +4 -5
- package/dist/resources/extensions/ollama/ollama-client.js +35 -6
- package/dist/resources/extensions/ollama/ollama-discovery.js +32 -6
- package/dist/startup-model-validation.js +8 -5
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
- 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/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 +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/notifications/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 +3 -3
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
- package/dist/web/standalone/.next/server/chunks/2331.js +16 -16
- package/dist/web/standalone/.next/server/chunks/4741.js +12 -12
- package/dist/web/standalone/.next/server/chunks/5822.js +2 -2
- package/dist/web/standalone/.next/server/chunks/63.js +8 -8
- package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
- package/dist/web/standalone/.next/server/edge-runtime-webpack.js +2 -0
- package/dist/web/standalone/.next/server/functions-config-manifest.json +0 -9
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +29 -2
- package/dist/web/standalone/.next/server/middleware.js +4 -12
- 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 +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/server/webpack-runtime.js +1 -1
- 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-f1e30ab6bb269149.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/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/package.json +1 -1
- package/packages/pi-ai/dist/env-api-keys.js +1 -0
- package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
- package/packages/pi-ai/dist/models.custom.d.ts +105 -0
- package/packages/pi-ai/dist/models.custom.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.custom.js +97 -0
- package/packages/pi-ai/dist/models.custom.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +648 -140
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +867 -370
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.test.d.ts +2 -0
- package/packages/pi-ai/dist/models.generated.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/models.generated.test.js +334 -0
- package/packages/pi-ai/dist/models.generated.test.js.map +1 -0
- package/packages/pi-ai/dist/models.test.js +105 -0
- package/packages/pi-ai/dist/models.test.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +1 -1
- 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/dist/utils/oauth/github-copilot.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js +5 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.test.d.ts +2 -0
- package/packages/pi-ai/dist/utils/oauth/github-copilot.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +57 -0
- package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -0
- package/packages/pi-ai/src/env-api-keys.ts +1 -0
- package/packages/pi-ai/src/models.custom.ts +98 -0
- package/packages/pi-ai/src/models.generated.test.ts +373 -0
- package/packages/pi-ai/src/models.generated.ts +867 -370
- package/packages/pi-ai/src/models.test.ts +135 -0
- package/packages/pi-ai/src/types.ts +1 -0
- package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +71 -0
- package/packages/pi-ai/src/utils/oauth/github-copilot.ts +4 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +27 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +25 -67
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +9 -0
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +87 -12
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts +1 -0
- 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 +22 -9
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +63 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +38 -0
- package/packages/pi-coding-agent/src/core/auth-storage.ts +1 -1
- package/packages/pi-coding-agent/src/core/model-resolver.ts +26 -69
- package/packages/pi-coding-agent/src/core/sdk.ts +10 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +72 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +84 -12
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +71 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +23 -9
- package/packages/pi-tui/dist/components/__tests__/editor.test.js +12 -0
- package/packages/pi-tui/dist/components/__tests__/editor.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/input.test.js +12 -0
- package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
- package/packages/pi-tui/dist/keys.d.ts.map +1 -1
- package/packages/pi-tui/dist/keys.js +27 -0
- package/packages/pi-tui/dist/keys.js.map +1 -1
- package/packages/pi-tui/src/components/__tests__/editor.test.ts +18 -0
- package/packages/pi-tui/src/components/__tests__/input.test.ts +18 -0
- package/packages/pi-tui/src/keys.ts +32 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/async-jobs/await-tool.test.ts +40 -7
- package/src/resources/extensions/async-jobs/await-tool.ts +7 -4
- package/src/resources/extensions/async-jobs/job-manager.ts +33 -3
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +45 -12
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +49 -24
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +91 -2
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +112 -0
- package/src/resources/extensions/gsd/auto/loop.ts +89 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +5 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +7 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +9 -3
- package/src/resources/extensions/gsd/auto-recovery.ts +10 -0
- package/src/resources/extensions/gsd/auto.ts +30 -20
- package/src/resources/extensions/gsd/bootstrap/crash-log.ts +32 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +19 -7
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +8 -10
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +8 -1
- package/src/resources/extensions/gsd/commands-handlers.ts +5 -1
- package/src/resources/extensions/gsd/context-injector.ts +1 -1
- package/src/resources/extensions/gsd/crash-recovery.ts +59 -0
- package/src/resources/extensions/gsd/custom-workflow-engine.ts +4 -8
- package/src/resources/extensions/gsd/definition-io.ts +18 -0
- package/src/resources/extensions/gsd/dispatch-guard.ts +5 -0
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +6 -3
- package/src/resources/extensions/gsd/git-service.ts +11 -8
- package/src/resources/extensions/gsd/gitignore.ts +12 -6
- package/src/resources/extensions/gsd/gsd-db.ts +106 -8
- package/src/resources/extensions/gsd/key-manager.ts +2 -0
- package/src/resources/extensions/gsd/milestone-actions.ts +19 -1
- package/src/resources/extensions/gsd/preferences-skills.ts +2 -36
- package/src/resources/extensions/gsd/preferences-types.ts +16 -0
- package/src/resources/extensions/gsd/preferences.ts +19 -6
- package/src/resources/extensions/gsd/prompt-loader.ts +6 -1
- package/src/resources/extensions/gsd/prompts/discuss.md +122 -13
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/state.ts +20 -0
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/block-db-writes.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +235 -0
- package/src/resources/extensions/gsd/tests/definition-io.test.ts +57 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/doctor-heal-fixable-warnings.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/false-degraded-mode-warning.test.ts +104 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +165 -5
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +8 -6
- package/src/resources/extensions/gsd/tests/key-manager.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/plan-milestone-artifact-verification.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/preferences-formatting.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/projection-regression.test.ts +96 -1
- package/src/resources/extensions/gsd/tests/prompt-loader-working-directory.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +97 -0
- package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +267 -0
- package/src/resources/extensions/gsd/workflow-projections.ts +8 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +29 -3
- package/src/resources/extensions/gsd/write-intercept.ts +10 -1
- package/src/resources/extensions/ollama/index.ts +4 -5
- package/src/resources/extensions/ollama/ollama-client.ts +35 -6
- package/src/resources/extensions/ollama/ollama-discovery.ts +37 -6
- package/src/resources/extensions/ollama/tests/ollama-discovery.test.ts +54 -0
- package/dist/resources/extensions/gsd/auto-observability.js +0 -54
- package/dist/resources/extensions/gsd/file-watcher.js +0 -80
- package/dist/resources/extensions/gsd/rtk-status.js +0 -43
- package/dist/web/standalone/.next/static/chunks/app/page-7115e62689b5fd84.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/src/resources/extensions/gsd/auto-observability.ts +0 -72
- package/src/resources/extensions/gsd/file-watcher.ts +0 -100
- package/src/resources/extensions/gsd/rtk-status.ts +0 -53
- /package/dist/web/standalone/.next/static/{Y0I7CjXJl-tWoV__KidV4 → jNiH700EcljeLnbQ2_RCv}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Y0I7CjXJl-tWoV__KidV4 → jNiH700EcljeLnbQ2_RCv}/_ssgManifest.js +0 -0
|
@@ -1712,7 +1712,7 @@ export async function buildReassessRoadmapPrompt(mid, midTitle, completedSliceId
|
|
|
1712
1712
|
});
|
|
1713
1713
|
}
|
|
1714
1714
|
// ─── Reactive Execute Prompt ──────────────────────────────────────────────
|
|
1715
|
-
export async function buildReactiveExecutePrompt(mid, midTitle, sid, sTitle, readyTaskIds, base) {
|
|
1715
|
+
export async function buildReactiveExecutePrompt(mid, midTitle, sid, sTitle, readyTaskIds, base, subagentModel) {
|
|
1716
1716
|
const { loadSliceTaskIO, deriveTaskGraph, graphMetrics } = await import("./reactive-graph.js");
|
|
1717
1717
|
// Build graph for context
|
|
1718
1718
|
const taskIO = await loadSliceTaskIO(base, mid, sid);
|
|
@@ -1744,10 +1744,11 @@ export async function buildReactiveExecutePrompt(mid, midTitle, sid, sTitle, rea
|
|
|
1744
1744
|
const depPaths = await getDependencyTaskSummaryPaths(mid, sid, tid, node?.dependsOn ?? [], base);
|
|
1745
1745
|
// Build a full execute-task prompt with dependency-based carry-forward
|
|
1746
1746
|
const taskPrompt = await buildExecuteTaskPrompt(mid, sid, sTitle, tid, tTitle, base, { carryForwardPaths: depPaths });
|
|
1747
|
+
const modelSuffix = subagentModel ? ` with model: "${subagentModel}"` : "";
|
|
1747
1748
|
subagentSections.push([
|
|
1748
1749
|
`### ${tid}: ${tTitle}`,
|
|
1749
1750
|
"",
|
|
1750
|
-
|
|
1751
|
+
`Use this as the prompt for a \`subagent\` call${modelSuffix}:`,
|
|
1751
1752
|
"",
|
|
1752
1753
|
"```",
|
|
1753
1754
|
taskPrompt,
|
|
@@ -1806,15 +1807,16 @@ function renderGatesToCloseBlock(gates, opts) {
|
|
|
1806
1807
|
}
|
|
1807
1808
|
return lines.join("\n").trimEnd();
|
|
1808
1809
|
}
|
|
1809
|
-
export async function buildParallelResearchSlicesPrompt(mid, midTitle, slices, basePath) {
|
|
1810
|
+
export async function buildParallelResearchSlicesPrompt(mid, midTitle, slices, basePath, subagentModel) {
|
|
1810
1811
|
// Build individual research-slice prompts for each slice
|
|
1811
1812
|
const subagentSections = [];
|
|
1813
|
+
const modelSuffix = subagentModel ? ` with model: "${subagentModel}"` : "";
|
|
1812
1814
|
for (const slice of slices) {
|
|
1813
1815
|
const slicePrompt = await buildResearchSlicePrompt(mid, midTitle, slice.id, slice.title, basePath);
|
|
1814
1816
|
subagentSections.push([
|
|
1815
1817
|
`### ${slice.id}: ${slice.title}`,
|
|
1816
1818
|
"",
|
|
1817
|
-
|
|
1819
|
+
`Use this as the prompt for a \`subagent\` call${modelSuffix} (agent: \`gsd-executor\` or the default agent):`,
|
|
1818
1820
|
"",
|
|
1819
1821
|
"```",
|
|
1820
1822
|
slicePrompt,
|
|
@@ -1829,7 +1831,7 @@ export async function buildParallelResearchSlicesPrompt(mid, midTitle, slices, b
|
|
|
1829
1831
|
subagentPrompts: subagentSections.join("\n\n---\n\n"),
|
|
1830
1832
|
});
|
|
1831
1833
|
}
|
|
1832
|
-
export async function buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, base) {
|
|
1834
|
+
export async function buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, base, subagentModel) {
|
|
1833
1835
|
// Pull only the gates this turn actually owns (Q3/Q4). Filter via the
|
|
1834
1836
|
// registry so that scope:"slice" gates owned by other turns (Q8) can't
|
|
1835
1837
|
// leak into this prompt and can't block dispatch via silent skip.
|
|
@@ -1873,10 +1875,11 @@ export async function buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, base)
|
|
|
1873
1875
|
"- `rationale`: one-sentence justification",
|
|
1874
1876
|
"- `findings`: detailed markdown findings (or empty if omitted)",
|
|
1875
1877
|
].join("\n");
|
|
1878
|
+
const modelSuffix = subagentModel ? ` with model: "${subagentModel}"` : "";
|
|
1876
1879
|
subagentSections.push([
|
|
1877
1880
|
`### ${def.id}: ${def.question}`,
|
|
1878
1881
|
"",
|
|
1879
|
-
|
|
1882
|
+
`Use this as the prompt for a \`subagent\` call${modelSuffix}:`,
|
|
1880
1883
|
"",
|
|
1881
1884
|
"```",
|
|
1882
1885
|
subPrompt,
|
|
@@ -224,6 +224,17 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
|
|
|
224
224
|
if (!isValidationTerminal(validationContent))
|
|
225
225
|
return false;
|
|
226
226
|
}
|
|
227
|
+
if (unitType === "plan-milestone") {
|
|
228
|
+
try {
|
|
229
|
+
const roadmap = parseLegacyRoadmap(readFileSync(absPath, "utf-8"));
|
|
230
|
+
if (roadmap.slices.length === 0)
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
logWarning("recovery", `plan-milestone roadmap verification failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
227
238
|
// plan-slice must produce a plan with actual task entries, not just a scaffold.
|
|
228
239
|
// The plan file may exist from a prior discussion/context step with only headings
|
|
229
240
|
// but no tasks. Without this check the artifact is considered "complete" and the
|
|
@@ -19,7 +19,7 @@ import { gsdRoot, resolveMilestoneFile, resolveMilestonePath, resolveDir, milest
|
|
|
19
19
|
import { invalidateAllCaches } from "./cache.js";
|
|
20
20
|
import { clearActivityLogState } from "./activity-log.js";
|
|
21
21
|
import { synthesizeCrashRecovery, getDeepDiagnostic, readActiveMilestoneId, } from "./session-forensics.js";
|
|
22
|
-
import { writeLock, clearLock, readCrashLock, isLockProcessAlive, formatCrashInfo, } from "./crash-recovery.js";
|
|
22
|
+
import { writeLock, clearLock, readCrashLock, isLockProcessAlive, formatCrashInfo, emitCrashRecoveredUnitEnd, } from "./crash-recovery.js";
|
|
23
23
|
import { acquireSessionLock, getSessionLockStatus, releaseSessionLock, updateSessionLock, } from "./session-lock.js";
|
|
24
24
|
import { resolveAutoSupervisorConfig, loadEffectiveGSDPreferences, getIsolationMode, } from "./preferences.js";
|
|
25
25
|
import { sendDesktopNotification } from "./notifications.js";
|
|
@@ -425,9 +425,13 @@ function cleanupAfterLoopExit(ctx) {
|
|
|
425
425
|
/* best-effort — mirror stopAuto cleanup */
|
|
426
426
|
logWarning("session", `lock cleanup failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
427
427
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
428
|
+
// A transient provider-error pause intentionally leaves the paused badge
|
|
429
|
+
// visible so the user still has a resumable auto-mode signal on screen.
|
|
430
|
+
if (!s.paused) {
|
|
431
|
+
ctx.ui.setStatus("gsd-auto", undefined);
|
|
432
|
+
ctx.ui.setWidget("gsd-progress", undefined);
|
|
433
|
+
ctx.ui.setFooter(undefined);
|
|
434
|
+
}
|
|
431
435
|
// Restore CWD out of worktree back to original project root
|
|
432
436
|
if (s.originalBasePath) {
|
|
433
437
|
s.basePath = s.originalBasePath;
|
|
@@ -529,7 +533,22 @@ export async function stopAuto(ctx, pi, reason) {
|
|
|
529
533
|
catch (e) {
|
|
530
534
|
debugLog("stop-cleanup-worktree", { error: e instanceof Error ? e.message : String(e) });
|
|
531
535
|
}
|
|
532
|
-
// ── Step 5: DB
|
|
536
|
+
// ── Step 5: Rebuild state while DB is still open (#3599) ──
|
|
537
|
+
// rebuildState() calls deriveState() which needs the DB for authoritative
|
|
538
|
+
// state. Previously this ran after closeDatabase(), forcing a filesystem
|
|
539
|
+
// fallback that could disagree with the DB-backed dispatch decisions —
|
|
540
|
+
// a split-brain where dispatch says "blocked" but STATE.md shows work.
|
|
541
|
+
if (s.basePath) {
|
|
542
|
+
try {
|
|
543
|
+
await rebuildState(s.basePath);
|
|
544
|
+
}
|
|
545
|
+
catch (e) {
|
|
546
|
+
debugLog("stop-rebuild-state-failed", {
|
|
547
|
+
error: e instanceof Error ? e.message : String(e),
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
// ── Step 6: DB cleanup ──
|
|
533
552
|
if (isDbAvailable()) {
|
|
534
553
|
try {
|
|
535
554
|
const { closeDatabase } = await import("./gsd-db.js");
|
|
@@ -541,7 +560,7 @@ export async function stopAuto(ctx, pi, reason) {
|
|
|
541
560
|
});
|
|
542
561
|
}
|
|
543
562
|
}
|
|
544
|
-
// ── Step
|
|
563
|
+
// ── Step 7: Restore basePath and chdir ──
|
|
545
564
|
try {
|
|
546
565
|
if (s.originalBasePath) {
|
|
547
566
|
s.basePath = s.originalBasePath;
|
|
@@ -557,7 +576,7 @@ export async function stopAuto(ctx, pi, reason) {
|
|
|
557
576
|
catch (e) {
|
|
558
577
|
debugLog("stop-cleanup-basepath", { error: e instanceof Error ? e.message : String(e) });
|
|
559
578
|
}
|
|
560
|
-
// ── Step
|
|
579
|
+
// ── Step 8: Ledger notification ──
|
|
561
580
|
try {
|
|
562
581
|
const ledger = getLedger();
|
|
563
582
|
if (ledger && ledger.units.length > 0) {
|
|
@@ -571,17 +590,6 @@ export async function stopAuto(ctx, pi, reason) {
|
|
|
571
590
|
catch (e) {
|
|
572
591
|
debugLog("stop-cleanup-ledger", { error: e instanceof Error ? e.message : String(e) });
|
|
573
592
|
}
|
|
574
|
-
// ── Step 8: Rebuild state ──
|
|
575
|
-
if (s.basePath) {
|
|
576
|
-
try {
|
|
577
|
-
await rebuildState(s.basePath);
|
|
578
|
-
}
|
|
579
|
-
catch (e) {
|
|
580
|
-
debugLog("stop-rebuild-state-failed", {
|
|
581
|
-
error: e instanceof Error ? e.message : String(e),
|
|
582
|
-
});
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
593
|
// ── Step 9: Cmux sidebar / event log ──
|
|
586
594
|
try {
|
|
587
595
|
clearCmuxSidebar(loadedPreferences);
|
|
@@ -1006,6 +1014,10 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1006
1014
|
s.stepMode = requestedStepMode;
|
|
1007
1015
|
}
|
|
1008
1016
|
if (freshStartAssessment.lock) {
|
|
1017
|
+
// Emit a synthetic unit-end for any unit-start that has no closing event.
|
|
1018
|
+
// This closes the journal gap reported in #3348 where the worker wrote side
|
|
1019
|
+
// effects (SUMMARY.md, DB updates) but died before emitting unit-end.
|
|
1020
|
+
emitCrashRecoveredUnitEnd(base, freshStartAssessment.lock);
|
|
1009
1021
|
clearLock(base);
|
|
1010
1022
|
}
|
|
1011
1023
|
if (!s.paused) {
|
|
@@ -1294,8 +1306,6 @@ export async function dispatchHookUnit(ctx, pi, hookName, triggerUnitType, trigg
|
|
|
1294
1306
|
pi.sendMessage({ customType: "gsd-auto", content: hookPrompt, display: true }, { triggerTurn: true });
|
|
1295
1307
|
return true;
|
|
1296
1308
|
}
|
|
1297
|
-
// Direct phase dispatch → auto-direct-dispatch.ts
|
|
1298
|
-
export { dispatchDirectPhase } from "./auto-direct-dispatch.js";
|
|
1299
1309
|
// Re-export recovery functions for external consumers
|
|
1300
1310
|
export { buildLoopRemediationSteps, } from "./auto-recovery.js";
|
|
1301
1311
|
export { resolveExpectedArtifactPath } from "./auto-artifact-paths.js";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* crash-log.ts — Write crash diagnostics to ~/.gsd/crash/<timestamp>.log
|
|
3
|
+
*
|
|
4
|
+
* Zero cross-dependencies: only uses Node.js built-ins so it can be imported
|
|
5
|
+
* safely from uncaughtException / unhandledRejection handlers and from tests
|
|
6
|
+
* without pulling in the full extension dependency tree.
|
|
7
|
+
*/
|
|
8
|
+
import { appendFileSync, mkdirSync } from "node:fs";
|
|
9
|
+
import { homedir } from "node:os";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
/**
|
|
12
|
+
* Write a crash log to ~/.gsd/crash/<timestamp>.log (or $GSD_HOME/crash/).
|
|
13
|
+
* Never throws — must be safe to call from any error handler.
|
|
14
|
+
*/
|
|
15
|
+
export function writeCrashLog(err, source) {
|
|
16
|
+
try {
|
|
17
|
+
const crashDir = join(process.env.GSD_HOME ?? join(homedir(), ".gsd"), "crash");
|
|
18
|
+
mkdirSync(crashDir, { recursive: true });
|
|
19
|
+
const ts = new Date().toISOString().replace(/[:.]/g, "-");
|
|
20
|
+
const logPath = join(crashDir, `${ts}.log`);
|
|
21
|
+
const lines = [
|
|
22
|
+
`[gsd] ${source}: ${err.message}`,
|
|
23
|
+
`timestamp: ${new Date().toISOString()}`,
|
|
24
|
+
`pid: ${process.pid}`,
|
|
25
|
+
err.stack ?? "(no stack trace available)",
|
|
26
|
+
"",
|
|
27
|
+
];
|
|
28
|
+
appendFileSync(logPath, lines.join("\n"));
|
|
29
|
+
}
|
|
30
|
+
catch { /* never throw from crash handler */ }
|
|
31
|
+
}
|
|
@@ -8,6 +8,8 @@ import { registerJournalTools } from "./journal-tools.js";
|
|
|
8
8
|
import { registerQueryTools } from "./query-tools.js";
|
|
9
9
|
import { registerHooks } from "./register-hooks.js";
|
|
10
10
|
import { registerShortcuts } from "./register-shortcuts.js";
|
|
11
|
+
import { writeCrashLog } from "./crash-log.js";
|
|
12
|
+
export { writeCrashLog } from "./crash-log.js";
|
|
11
13
|
export function handleRecoverableExtensionProcessError(err) {
|
|
12
14
|
if (err.code === "EPIPE") {
|
|
13
15
|
process.exit(0);
|
|
@@ -28,17 +30,26 @@ export function handleRecoverableExtensionProcessError(err) {
|
|
|
28
30
|
function installEpipeGuard() {
|
|
29
31
|
if (!process.listeners("uncaughtException").some((listener) => listener.name === "_gsdEpipeGuard")) {
|
|
30
32
|
const _gsdEpipeGuard = (err) => {
|
|
31
|
-
if (handleRecoverableExtensionProcessError(err))
|
|
33
|
+
if (handleRecoverableExtensionProcessError(err))
|
|
32
34
|
return;
|
|
33
|
-
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
process.stderr.write(`${err.stack}\n`);
|
|
35
|
+
// Write crash log and exit cleanly for unrecoverable errors.
|
|
36
|
+
// Logging and continuing was the original double-fault fix (#3163), but
|
|
37
|
+
// continuing in an indeterminate state is worse than a clean exit (#3348).
|
|
38
|
+
writeCrashLog(err, "uncaughtException");
|
|
39
|
+
process.exit(1);
|
|
39
40
|
};
|
|
40
41
|
process.on("uncaughtException", _gsdEpipeGuard);
|
|
41
42
|
}
|
|
43
|
+
if (!process.listeners("unhandledRejection").some((listener) => listener.name === "_gsdRejectionGuard")) {
|
|
44
|
+
const _gsdRejectionGuard = (reason, _promise) => {
|
|
45
|
+
const err = reason instanceof Error ? reason : new Error(String(reason));
|
|
46
|
+
if (handleRecoverableExtensionProcessError(err))
|
|
47
|
+
return;
|
|
48
|
+
writeCrashLog(err, "unhandledRejection");
|
|
49
|
+
process.exit(1);
|
|
50
|
+
};
|
|
51
|
+
process.on("unhandledRejection", _gsdRejectionGuard);
|
|
52
|
+
}
|
|
42
53
|
}
|
|
43
54
|
export function registerGsdExtension(pi) {
|
|
44
55
|
registerGSDCommand(pi);
|
|
@@ -172,14 +172,10 @@ export function registerHooks(pi) {
|
|
|
172
172
|
// Only gate-shaped ask_user_questions calls should block execution.
|
|
173
173
|
// The gate stays pending until the user selects the approval option.
|
|
174
174
|
if (event.toolName === "ask_user_questions") {
|
|
175
|
-
const
|
|
176
|
-
const
|
|
177
|
-
if (
|
|
178
|
-
|
|
179
|
-
const questionId = questions.find((question) => typeof question?.id === "string" && isGateQuestionId(question.id))?.id;
|
|
180
|
-
if (typeof questionId === "string") {
|
|
181
|
-
setPendingGate(questionId);
|
|
182
|
-
}
|
|
175
|
+
const questions = event.input?.questions ?? [];
|
|
176
|
+
const questionId = questions.find((question) => typeof question?.id === "string" && isGateQuestionId(question.id))?.id;
|
|
177
|
+
if (typeof questionId === "string") {
|
|
178
|
+
setPendingGate(questionId);
|
|
183
179
|
}
|
|
184
180
|
}
|
|
185
181
|
// ── Discussion gate enforcement: block tool calls while gate is pending ──
|
|
@@ -261,8 +257,6 @@ export function registerHooks(pi) {
|
|
|
261
257
|
return;
|
|
262
258
|
const milestoneId = getDiscussionMilestoneId(process.cwd());
|
|
263
259
|
const queueActive = isQueuePhaseActive();
|
|
264
|
-
if (!milestoneId && !queueActive)
|
|
265
|
-
return;
|
|
266
260
|
const details = event.details;
|
|
267
261
|
// ── Discussion gate enforcement: handle gate question responses ──
|
|
268
262
|
// If the result is cancelled or has no response, the pending gate stays active
|
|
@@ -293,12 +287,16 @@ export function registerHooks(pi) {
|
|
|
293
287
|
// Only unlock the gate if the user selected the first option (confirmation).
|
|
294
288
|
// Cross-references against the question's defined options to reject free-form "Other" text.
|
|
295
289
|
const answer = details.response?.answers?.[question.id];
|
|
290
|
+
const inferredMilestoneId = extractDepthVerificationMilestoneId(question.id) ?? milestoneId;
|
|
296
291
|
if (isDepthConfirmationAnswer(answer?.selected, question.options)) {
|
|
297
|
-
markDepthVerified(
|
|
292
|
+
markDepthVerified(inferredMilestoneId);
|
|
293
|
+
clearPendingGate();
|
|
298
294
|
}
|
|
299
295
|
break;
|
|
300
296
|
}
|
|
301
297
|
}
|
|
298
|
+
if (!milestoneId && !queueActive)
|
|
299
|
+
return;
|
|
302
300
|
if (!milestoneId)
|
|
303
301
|
return;
|
|
304
302
|
const basePath = process.cwd();
|
|
@@ -6,6 +6,7 @@ import { debugTime } from "../debug-logger.js";
|
|
|
6
6
|
import { loadPrompt, getTemplatesDir } from "../prompt-loader.js";
|
|
7
7
|
import { readForensicsMarker } from "../forensics.js";
|
|
8
8
|
import { resolveAllSkillReferences, renderPreferencesForSystemPrompt, loadEffectiveGSDPreferences } from "../preferences.js";
|
|
9
|
+
import { resolveModelWithFallbacksForUnit } from "../preferences-models.js";
|
|
9
10
|
import { resolveSkillReference } from "../preferences-skills.js";
|
|
10
11
|
import { resolveGsdRootFile, resolveSliceFile, resolveSlicePath, resolveTaskFile, resolveTaskFiles, resolveTasksDir, relSliceFile, relSlicePath, relTaskFile } from "../paths.js";
|
|
11
12
|
import { ensureCodebaseMapFresh, readCodebaseMap } from "../codebase-generator.js";
|
|
@@ -147,7 +148,11 @@ export async function buildBeforeAgentStartResult(event, ctx) {
|
|
|
147
148
|
// Re-inject forensics context on follow-up turns (#2941)
|
|
148
149
|
const forensicsInjection = !injection ? buildForensicsContextInjection(process.cwd(), event.prompt) : null;
|
|
149
150
|
const worktreeBlock = buildWorktreeContextBlock();
|
|
150
|
-
const
|
|
151
|
+
const subagentModelConfig = resolveModelWithFallbacksForUnit("subagent");
|
|
152
|
+
const subagentModelBlock = subagentModelConfig
|
|
153
|
+
? `\n\n## Subagent Model\n\nWhen spawning subagents via the \`subagent\` tool, always pass \`model: "${subagentModelConfig.primary}"\` in the tool call parameters. Never omit this — always specify it explicitly.`
|
|
154
|
+
: "";
|
|
155
|
+
const fullSystem = `${event.systemPrompt}\n\n[SYSTEM CONTEXT — GSD]\n\n${systemContent}${preferenceBlock}${knowledgeBlock}${codebaseBlock}${memoryBlock}${newSkillsBlock}${worktreeBlock}${subagentModelBlock}`;
|
|
151
156
|
stopContextTimer({
|
|
152
157
|
systemPromptSize: fullSystem.length,
|
|
153
158
|
injectionSize: injection?.length ?? forensicsInjection?.length ?? 0,
|
|
@@ -61,6 +61,9 @@ export function parseDoctorArgs(args) {
|
|
|
61
61
|
const requestedScope = mode === "doctor" ? parts[0] : parts[1];
|
|
62
62
|
return { jsonMode, dryRun, fixFlag, includeBuild, includeTests, mode, requestedScope };
|
|
63
63
|
}
|
|
64
|
+
export function isDoctorHealActionable(issue) {
|
|
65
|
+
return issue.fixable && issue.severity !== "info";
|
|
66
|
+
}
|
|
64
67
|
export async function handleDoctor(args, ctx, pi) {
|
|
65
68
|
const { jsonMode, dryRun, fixFlag, includeBuild, includeTests, mode, requestedScope } = parseDoctorArgs(args);
|
|
66
69
|
const scope = await selectDoctorScope(projectRoot(), requestedScope);
|
|
@@ -88,7 +91,7 @@ export async function handleDoctor(args, ctx, pi) {
|
|
|
88
91
|
scope: effectiveScope,
|
|
89
92
|
includeWarnings: true,
|
|
90
93
|
});
|
|
91
|
-
const actionable = unresolved.filter(
|
|
94
|
+
const actionable = unresolved.filter(isDoctorHealActionable);
|
|
92
95
|
if (actionable.length === 0) {
|
|
93
96
|
ctx.ui.notify("Doctor heal found nothing actionable to hand off to the LLM.", "info");
|
|
94
97
|
return;
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { readFileSync, existsSync } from "node:fs";
|
|
16
16
|
import { resolve, sep } from "node:path";
|
|
17
|
-
import { readFrozenDefinition } from "./
|
|
17
|
+
import { readFrozenDefinition } from "./definition-io.js";
|
|
18
18
|
/** Maximum characters per artifact to prevent context window blowout. */
|
|
19
19
|
const MAX_CONTEXT_CHARS = 10_000;
|
|
20
20
|
/**
|
|
@@ -14,6 +14,7 @@ import { join } from "node:path";
|
|
|
14
14
|
import { gsdRoot } from "./paths.js";
|
|
15
15
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
16
16
|
import { effectiveLockFile } from "./session-lock.js";
|
|
17
|
+
import { emitJournalEvent, queryJournal } from "./journal.js";
|
|
17
18
|
function lockPath(basePath) {
|
|
18
19
|
return join(gsdRoot(basePath), effectiveLockFile());
|
|
19
20
|
}
|
|
@@ -110,3 +111,53 @@ export function formatCrashInfo(lock) {
|
|
|
110
111
|
}
|
|
111
112
|
return lines.join("\n");
|
|
112
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Emit a synthetic unit-end event for a unit that crashed without emitting its own.
|
|
116
|
+
*
|
|
117
|
+
* Queries the journal to find the most recent unit-start for the crashed unit.
|
|
118
|
+
* If a matching unit-end already exists (e.g. the hard timeout fired), this is a
|
|
119
|
+
* no-op. Called during crash recovery, before clearing the stale lock.
|
|
120
|
+
*
|
|
121
|
+
* Addresses the gap reported in #3348 where `unit-start` was emitted but no
|
|
122
|
+
* `unit-end` followed — side effects landed but the worker died before closeout.
|
|
123
|
+
*/
|
|
124
|
+
export function emitCrashRecoveredUnitEnd(basePath, lock) {
|
|
125
|
+
// Skip bootstrap / starting pseudo-units — they have no meaningful unit-start event.
|
|
126
|
+
if (!lock.unitType || !lock.unitId || lock.unitType === "starting")
|
|
127
|
+
return;
|
|
128
|
+
try {
|
|
129
|
+
const all = queryJournal(basePath);
|
|
130
|
+
// Find the most recent unit-start for this unitId
|
|
131
|
+
const starts = all.filter((e) => e.eventType === "unit-start" && e.data?.unitId === lock.unitId);
|
|
132
|
+
if (starts.length === 0)
|
|
133
|
+
return;
|
|
134
|
+
const lastStart = starts[starts.length - 1];
|
|
135
|
+
// Check if a unit-end was already emitted (e.g. hard timeout fired after the crash)
|
|
136
|
+
const alreadyClosed = all.some((e) => e.eventType === "unit-end" &&
|
|
137
|
+
e.data?.unitId === lock.unitId &&
|
|
138
|
+
e.causedBy?.flowId === lastStart.flowId &&
|
|
139
|
+
e.causedBy?.seq === lastStart.seq);
|
|
140
|
+
if (alreadyClosed)
|
|
141
|
+
return;
|
|
142
|
+
// Find the highest seq in this flow for monotonic ordering
|
|
143
|
+
const maxSeq = all
|
|
144
|
+
.filter((e) => e.flowId === lastStart.flowId)
|
|
145
|
+
.reduce((max, e) => Math.max(max, e.seq), lastStart.seq);
|
|
146
|
+
emitJournalEvent(basePath, {
|
|
147
|
+
ts: new Date().toISOString(),
|
|
148
|
+
flowId: lastStart.flowId,
|
|
149
|
+
seq: maxSeq + 1,
|
|
150
|
+
eventType: "unit-end",
|
|
151
|
+
data: {
|
|
152
|
+
unitType: lock.unitType,
|
|
153
|
+
unitId: lock.unitId,
|
|
154
|
+
status: "crash-recovered",
|
|
155
|
+
artifactVerified: false,
|
|
156
|
+
},
|
|
157
|
+
causedBy: { flowId: lastStart.flowId, seq: lastStart.seq },
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
// Never throw from crash recovery path — journal failure must not block recovery
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -13,17 +13,13 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { readFileSync } from "node:fs";
|
|
15
15
|
import { join } from "node:path";
|
|
16
|
-
import { parse } from "yaml";
|
|
17
16
|
import { readGraph, writeGraph, getNextPendingStep, markStepComplete, expandIteration, } from "./graph.js";
|
|
18
17
|
import { injectContext } from "./context-injector.js";
|
|
18
|
+
import { readFrozenDefinition } from "./definition-io.js";
|
|
19
19
|
import { parseUnitId } from "./unit-id.js";
|
|
20
20
|
import { withFileLock } from "./file-lock.js";
|
|
21
|
-
|
|
22
|
-
export
|
|
23
|
-
const defPath = join(runDir, "DEFINITION.yaml");
|
|
24
|
-
const raw = readFileSync(defPath, "utf-8");
|
|
25
|
-
return parse(raw, { schema: "core" });
|
|
26
|
-
}
|
|
21
|
+
// Re-export for downstream consumers
|
|
22
|
+
export { readFrozenDefinition } from "./definition-io.js";
|
|
27
23
|
export class CustomWorkflowEngine {
|
|
28
24
|
engineId = "custom";
|
|
29
25
|
runDir;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* definition-io.ts — Read frozen DEFINITION.yaml from a run directory.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from custom-workflow-engine.ts to break the circular dependency
|
|
5
|
+
* between context-injector.ts and custom-workflow-engine.ts.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { parse } from "yaml";
|
|
10
|
+
/** Read and parse the frozen DEFINITION.yaml from a run directory. */
|
|
11
|
+
export function readFrozenDefinition(runDir) {
|
|
12
|
+
const defPath = join(runDir, "DEFINITION.yaml");
|
|
13
|
+
const raw = readFileSync(defPath, "utf-8");
|
|
14
|
+
return parse(raw, { schema: "core" });
|
|
15
|
+
}
|
|
@@ -102,6 +102,10 @@ export function getPriorSliceCompletionBlocker(base, _mainBranch, unitType, unit
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
else {
|
|
105
|
+
const milestoneUsesExplicitDeps = slices.some((slice) => slice.depends.length > 0);
|
|
106
|
+
if (milestoneUsesExplicitDeps) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
105
109
|
// Positional fallback is only a heuristic for legacy slices with no
|
|
106
110
|
// declared dependencies. Skip any earlier slice that depends on the
|
|
107
111
|
// target, directly or transitively, or we can deadlock a valid zero-dep
|
|
@@ -277,13 +277,16 @@ export async function checkRuntimeHealth(basePath, issues, fixesApplied, shouldF
|
|
|
277
277
|
if (existsSync(gitignorePath) && nativeIsRepo(basePath)) {
|
|
278
278
|
const content = readFileSync(gitignorePath, "utf-8");
|
|
279
279
|
const existingLines = new Set(content.split("\n").map(l => l.trim()).filter(l => l && !l.startsWith("#")));
|
|
280
|
-
// Check for critical runtime patterns that must be present
|
|
280
|
+
// Check for critical runtime patterns that must be present.
|
|
281
|
+
// NOTE: GSD_RUNTIME_PATTERNS in gitignore.ts is the canonical source of truth.
|
|
282
|
+
// This is a minimal subset for the doctor check.
|
|
281
283
|
const criticalPatterns = [
|
|
282
284
|
".gsd/activity/",
|
|
283
285
|
".gsd/runtime/",
|
|
284
286
|
".gsd/auto.lock",
|
|
285
|
-
".gsd/gsd.db",
|
|
286
|
-
".gsd/completed-units
|
|
287
|
+
".gsd/gsd.db*",
|
|
288
|
+
".gsd/completed-units*.json",
|
|
289
|
+
".gsd/event-log.jsonl",
|
|
287
290
|
];
|
|
288
291
|
// If blanket .gsd/ or .gsd is present, all patterns are covered
|
|
289
292
|
const hasBlanketIgnore = existingLines.has(".gsd/") || existingLines.has(".gsd");
|
|
@@ -78,22 +78,25 @@ export class MergeConflictError extends GSDError {
|
|
|
78
78
|
/**
|
|
79
79
|
* GSD runtime paths that should be excluded from smart staging.
|
|
80
80
|
* These are transient/generated artifacts that should never be committed.
|
|
81
|
-
*
|
|
82
|
-
*
|
|
81
|
+
*
|
|
82
|
+
* NOTE: GSD_RUNTIME_PATTERNS in gitignore.ts is the canonical source of truth.
|
|
83
|
+
* This array must stay synchronized with it.
|
|
83
84
|
*/
|
|
84
85
|
export const RUNTIME_EXCLUSION_PATHS = [
|
|
85
86
|
".gsd/activity/",
|
|
87
|
+
".gsd/forensics/",
|
|
86
88
|
".gsd/runtime/",
|
|
87
89
|
".gsd/worktrees/",
|
|
90
|
+
".gsd/parallel/",
|
|
88
91
|
".gsd/auto.lock",
|
|
89
92
|
".gsd/metrics.json",
|
|
90
|
-
".gsd/completed-units
|
|
93
|
+
".gsd/completed-units*.json", // covers completed-units.json and archived completed-units-{MID}.json
|
|
94
|
+
".gsd/state-manifest.json",
|
|
91
95
|
".gsd/STATE.md",
|
|
92
|
-
".gsd/gsd.db",
|
|
93
|
-
".gsd/
|
|
94
|
-
".gsd/
|
|
95
|
-
".gsd/
|
|
96
|
-
".gsd/doctor-history.jsonl", // doctor run history (#2296)
|
|
96
|
+
".gsd/gsd.db*",
|
|
97
|
+
".gsd/journal/",
|
|
98
|
+
".gsd/doctor-history.jsonl",
|
|
99
|
+
".gsd/event-log.jsonl",
|
|
97
100
|
".gsd/DISCUSSION-MANIFEST.json",
|
|
98
101
|
];
|
|
99
102
|
// ─── Integration Branch Metadata ───────────────────────────────────────────
|
|
@@ -13,6 +13,12 @@ import { gsdRoot } from "./paths.js";
|
|
|
13
13
|
import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
|
|
14
14
|
/**
|
|
15
15
|
* GSD runtime patterns for git index cleanup.
|
|
16
|
+
*
|
|
17
|
+
* CANONICAL SOURCE OF TRUTH: This array is the authoritative list of runtime
|
|
18
|
+
* ignore patterns. Other modules (RUNTIME_EXCLUSION_PATHS in git-service.ts,
|
|
19
|
+
* SKIP_* arrays in worktree-manager.ts, criticalPatterns in doctor-runtime-checks.ts)
|
|
20
|
+
* must stay synchronized with this list.
|
|
21
|
+
*
|
|
16
22
|
* With external state (symlink), these are a no-op in most cases,
|
|
17
23
|
* but retained for backwards compatibility during migration.
|
|
18
24
|
*/
|
|
@@ -24,13 +30,13 @@ const GSD_RUNTIME_PATTERNS = [
|
|
|
24
30
|
".gsd/parallel/",
|
|
25
31
|
".gsd/auto.lock",
|
|
26
32
|
".gsd/metrics.json",
|
|
27
|
-
".gsd/completed-units
|
|
33
|
+
".gsd/completed-units*.json", // covers completed-units.json and archived completed-units-{MID}.json
|
|
34
|
+
".gsd/state-manifest.json",
|
|
28
35
|
".gsd/STATE.md",
|
|
29
|
-
".gsd/gsd.db",
|
|
30
|
-
".gsd/
|
|
31
|
-
".gsd/
|
|
32
|
-
".gsd/
|
|
33
|
-
".gsd/doctor-history.jsonl", // doctor run history (#2296)
|
|
36
|
+
".gsd/gsd.db*",
|
|
37
|
+
".gsd/journal/",
|
|
38
|
+
".gsd/doctor-history.jsonl",
|
|
39
|
+
".gsd/event-log.jsonl",
|
|
34
40
|
".gsd/DISCUSSION-MANIFEST.json",
|
|
35
41
|
".gsd/milestones/**/*-CONTINUE.md",
|
|
36
42
|
".gsd/milestones/**/continue.md",
|