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
|
@@ -1926,6 +1926,7 @@ export async function buildReassessRoadmapPrompt(
|
|
|
1926
1926
|
export async function buildReactiveExecutePrompt(
|
|
1927
1927
|
mid: string, midTitle: string, sid: string, sTitle: string,
|
|
1928
1928
|
readyTaskIds: string[], base: string,
|
|
1929
|
+
subagentModel?: string,
|
|
1929
1930
|
): Promise<string> {
|
|
1930
1931
|
const { loadSliceTaskIO, deriveTaskGraph, graphMetrics } = await import("./reactive-graph.js");
|
|
1931
1932
|
|
|
@@ -1970,10 +1971,11 @@ export async function buildReactiveExecutePrompt(
|
|
|
1970
1971
|
{ carryForwardPaths: depPaths },
|
|
1971
1972
|
);
|
|
1972
1973
|
|
|
1974
|
+
const modelSuffix = subagentModel ? ` with model: "${subagentModel}"` : "";
|
|
1973
1975
|
subagentSections.push([
|
|
1974
1976
|
`### ${tid}: ${tTitle}`,
|
|
1975
1977
|
"",
|
|
1976
|
-
|
|
1978
|
+
`Use this as the prompt for a \`subagent\` call${modelSuffix}:`,
|
|
1977
1979
|
"",
|
|
1978
1980
|
"```",
|
|
1979
1981
|
taskPrompt,
|
|
@@ -2049,15 +2051,17 @@ export async function buildParallelResearchSlicesPrompt(
|
|
|
2049
2051
|
midTitle: string,
|
|
2050
2052
|
slices: Array<{ id: string; title: string }>,
|
|
2051
2053
|
basePath: string,
|
|
2054
|
+
subagentModel?: string,
|
|
2052
2055
|
): Promise<string> {
|
|
2053
2056
|
// Build individual research-slice prompts for each slice
|
|
2054
2057
|
const subagentSections: string[] = [];
|
|
2058
|
+
const modelSuffix = subagentModel ? ` with model: "${subagentModel}"` : "";
|
|
2055
2059
|
for (const slice of slices) {
|
|
2056
2060
|
const slicePrompt = await buildResearchSlicePrompt(mid, midTitle, slice.id, slice.title, basePath);
|
|
2057
2061
|
subagentSections.push([
|
|
2058
2062
|
`### ${slice.id}: ${slice.title}`,
|
|
2059
2063
|
"",
|
|
2060
|
-
|
|
2064
|
+
`Use this as the prompt for a \`subagent\` call${modelSuffix} (agent: \`gsd-executor\` or the default agent):`,
|
|
2061
2065
|
"",
|
|
2062
2066
|
"```",
|
|
2063
2067
|
slicePrompt,
|
|
@@ -2077,6 +2081,7 @@ export async function buildParallelResearchSlicesPrompt(
|
|
|
2077
2081
|
export async function buildGateEvaluatePrompt(
|
|
2078
2082
|
mid: string, midTitle: string, sid: string, sTitle: string,
|
|
2079
2083
|
base: string,
|
|
2084
|
+
subagentModel?: string,
|
|
2080
2085
|
): Promise<string> {
|
|
2081
2086
|
// Pull only the gates this turn actually owns (Q3/Q4). Filter via the
|
|
2082
2087
|
// registry so that scope:"slice" gates owned by other turns (Q8) can't
|
|
@@ -2128,10 +2133,11 @@ export async function buildGateEvaluatePrompt(
|
|
|
2128
2133
|
"- `findings`: detailed markdown findings (or empty if omitted)",
|
|
2129
2134
|
].join("\n");
|
|
2130
2135
|
|
|
2136
|
+
const modelSuffix = subagentModel ? ` with model: "${subagentModel}"` : "";
|
|
2131
2137
|
subagentSections.push([
|
|
2132
2138
|
`### ${def.id}: ${def.question}`,
|
|
2133
2139
|
"",
|
|
2134
|
-
|
|
2140
|
+
`Use this as the prompt for a \`subagent\` call${modelSuffix}:`,
|
|
2135
2141
|
"",
|
|
2136
2142
|
"```",
|
|
2137
2143
|
subPrompt,
|
|
@@ -272,6 +272,16 @@ export function verifyExpectedArtifact(
|
|
|
272
272
|
if (!isValidationTerminal(validationContent)) return false;
|
|
273
273
|
}
|
|
274
274
|
|
|
275
|
+
if (unitType === "plan-milestone") {
|
|
276
|
+
try {
|
|
277
|
+
const roadmap = parseLegacyRoadmap(readFileSync(absPath, "utf-8"));
|
|
278
|
+
if (roadmap.slices.length === 0) return false;
|
|
279
|
+
} catch (err) {
|
|
280
|
+
logWarning("recovery", `plan-milestone roadmap verification failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
275
285
|
// plan-slice must produce a plan with actual task entries, not just a scaffold.
|
|
276
286
|
// The plan file may exist from a prior discussion/context step with only headings
|
|
277
287
|
// but no tasks. Without this check the artifact is considered "complete" and the
|
|
@@ -52,6 +52,7 @@ import {
|
|
|
52
52
|
readCrashLock,
|
|
53
53
|
isLockProcessAlive,
|
|
54
54
|
formatCrashInfo,
|
|
55
|
+
emitCrashRecoveredUnitEnd,
|
|
55
56
|
} from "./crash-recovery.js";
|
|
56
57
|
import {
|
|
57
58
|
acquireSessionLock,
|
|
@@ -677,9 +678,13 @@ function cleanupAfterLoopExit(ctx: ExtensionContext): void {
|
|
|
677
678
|
logWarning("session", `lock cleanup failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
678
679
|
}
|
|
679
680
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
681
|
+
// A transient provider-error pause intentionally leaves the paused badge
|
|
682
|
+
// visible so the user still has a resumable auto-mode signal on screen.
|
|
683
|
+
if (!s.paused) {
|
|
684
|
+
ctx.ui.setStatus("gsd-auto", undefined);
|
|
685
|
+
ctx.ui.setWidget("gsd-progress", undefined);
|
|
686
|
+
ctx.ui.setFooter(undefined);
|
|
687
|
+
}
|
|
683
688
|
|
|
684
689
|
// Restore CWD out of worktree back to original project root
|
|
685
690
|
if (s.originalBasePath) {
|
|
@@ -791,7 +796,22 @@ export async function stopAuto(
|
|
|
791
796
|
debugLog("stop-cleanup-worktree", { error: e instanceof Error ? e.message : String(e) });
|
|
792
797
|
}
|
|
793
798
|
|
|
794
|
-
// ── Step 5: DB
|
|
799
|
+
// ── Step 5: Rebuild state while DB is still open (#3599) ──
|
|
800
|
+
// rebuildState() calls deriveState() which needs the DB for authoritative
|
|
801
|
+
// state. Previously this ran after closeDatabase(), forcing a filesystem
|
|
802
|
+
// fallback that could disagree with the DB-backed dispatch decisions —
|
|
803
|
+
// a split-brain where dispatch says "blocked" but STATE.md shows work.
|
|
804
|
+
if (s.basePath) {
|
|
805
|
+
try {
|
|
806
|
+
await rebuildState(s.basePath);
|
|
807
|
+
} catch (e) {
|
|
808
|
+
debugLog("stop-rebuild-state-failed", {
|
|
809
|
+
error: e instanceof Error ? e.message : String(e),
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
// ── Step 6: DB cleanup ──
|
|
795
815
|
if (isDbAvailable()) {
|
|
796
816
|
try {
|
|
797
817
|
const { closeDatabase } = await import("./gsd-db.js");
|
|
@@ -803,7 +823,7 @@ export async function stopAuto(
|
|
|
803
823
|
}
|
|
804
824
|
}
|
|
805
825
|
|
|
806
|
-
// ── Step
|
|
826
|
+
// ── Step 7: Restore basePath and chdir ──
|
|
807
827
|
try {
|
|
808
828
|
if (s.originalBasePath) {
|
|
809
829
|
s.basePath = s.originalBasePath;
|
|
@@ -818,7 +838,7 @@ export async function stopAuto(
|
|
|
818
838
|
debugLog("stop-cleanup-basepath", { error: e instanceof Error ? e.message : String(e) });
|
|
819
839
|
}
|
|
820
840
|
|
|
821
|
-
// ── Step
|
|
841
|
+
// ── Step 8: Ledger notification ──
|
|
822
842
|
try {
|
|
823
843
|
const ledger = getLedger();
|
|
824
844
|
if (ledger && ledger.units.length > 0) {
|
|
@@ -834,17 +854,6 @@ export async function stopAuto(
|
|
|
834
854
|
debugLog("stop-cleanup-ledger", { error: e instanceof Error ? e.message : String(e) });
|
|
835
855
|
}
|
|
836
856
|
|
|
837
|
-
// ── Step 8: Rebuild state ──
|
|
838
|
-
if (s.basePath) {
|
|
839
|
-
try {
|
|
840
|
-
await rebuildState(s.basePath);
|
|
841
|
-
} catch (e) {
|
|
842
|
-
debugLog("stop-rebuild-state-failed", {
|
|
843
|
-
error: e instanceof Error ? e.message : String(e),
|
|
844
|
-
});
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
|
|
848
857
|
// ── Step 9: Cmux sidebar / event log ──
|
|
849
858
|
try {
|
|
850
859
|
clearCmuxSidebar(loadedPreferences);
|
|
@@ -1324,6 +1333,10 @@ export async function startAuto(
|
|
|
1324
1333
|
}
|
|
1325
1334
|
|
|
1326
1335
|
if (freshStartAssessment.lock) {
|
|
1336
|
+
// Emit a synthetic unit-end for any unit-start that has no closing event.
|
|
1337
|
+
// This closes the journal gap reported in #3348 where the worker wrote side
|
|
1338
|
+
// effects (SUMMARY.md, DB updates) but died before emitting unit-end.
|
|
1339
|
+
emitCrashRecoveredUnitEnd(base, freshStartAssessment.lock);
|
|
1327
1340
|
clearLock(base);
|
|
1328
1341
|
}
|
|
1329
1342
|
|
|
@@ -1713,9 +1726,6 @@ export async function dispatchHookUnit(
|
|
|
1713
1726
|
return true;
|
|
1714
1727
|
}
|
|
1715
1728
|
|
|
1716
|
-
// Direct phase dispatch → auto-direct-dispatch.ts
|
|
1717
|
-
export { dispatchDirectPhase } from "./auto-direct-dispatch.js";
|
|
1718
|
-
|
|
1719
1729
|
// Re-export recovery functions for external consumers
|
|
1720
1730
|
export {
|
|
1721
1731
|
buildLoopRemediationSteps,
|
|
@@ -0,0 +1,32 @@
|
|
|
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
|
+
|
|
9
|
+
import { appendFileSync, mkdirSync } from "node:fs";
|
|
10
|
+
import { homedir } from "node:os";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Write a crash log to ~/.gsd/crash/<timestamp>.log (or $GSD_HOME/crash/).
|
|
15
|
+
* Never throws — must be safe to call from any error handler.
|
|
16
|
+
*/
|
|
17
|
+
export function writeCrashLog(err: Error, source: string): void {
|
|
18
|
+
try {
|
|
19
|
+
const crashDir = join(process.env.GSD_HOME ?? join(homedir(), ".gsd"), "crash");
|
|
20
|
+
mkdirSync(crashDir, { recursive: true });
|
|
21
|
+
const ts = new Date().toISOString().replace(/[:.]/g, "-");
|
|
22
|
+
const logPath = join(crashDir, `${ts}.log`);
|
|
23
|
+
const lines = [
|
|
24
|
+
`[gsd] ${source}: ${err.message}`,
|
|
25
|
+
`timestamp: ${new Date().toISOString()}`,
|
|
26
|
+
`pid: ${process.pid}`,
|
|
27
|
+
err.stack ?? "(no stack trace available)",
|
|
28
|
+
"",
|
|
29
|
+
];
|
|
30
|
+
appendFileSync(logPath, lines.join("\n"));
|
|
31
|
+
} catch { /* never throw from crash handler */ }
|
|
32
|
+
}
|
|
@@ -11,6 +11,9 @@ import { registerJournalTools } from "./journal-tools.js";
|
|
|
11
11
|
import { registerQueryTools } from "./query-tools.js";
|
|
12
12
|
import { registerHooks } from "./register-hooks.js";
|
|
13
13
|
import { registerShortcuts } from "./register-shortcuts.js";
|
|
14
|
+
import { writeCrashLog } from "./crash-log.js";
|
|
15
|
+
|
|
16
|
+
export { writeCrashLog } from "./crash-log.js";
|
|
14
17
|
|
|
15
18
|
export function handleRecoverableExtensionProcessError(err: Error): boolean {
|
|
16
19
|
if ((err as NodeJS.ErrnoException).code === "EPIPE") {
|
|
@@ -33,16 +36,25 @@ export function handleRecoverableExtensionProcessError(err: Error): boolean {
|
|
|
33
36
|
function installEpipeGuard(): void {
|
|
34
37
|
if (!process.listeners("uncaughtException").some((listener) => listener.name === "_gsdEpipeGuard")) {
|
|
35
38
|
const _gsdEpipeGuard = (err: Error): void => {
|
|
36
|
-
if (handleRecoverableExtensionProcessError(err))
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
//
|
|
40
|
-
|
|
41
|
-
process.
|
|
42
|
-
if (err.stack) process.stderr.write(`${err.stack}\n`);
|
|
39
|
+
if (handleRecoverableExtensionProcessError(err)) return;
|
|
40
|
+
// Write crash log and exit cleanly for unrecoverable errors.
|
|
41
|
+
// Logging and continuing was the original double-fault fix (#3163), but
|
|
42
|
+
// continuing in an indeterminate state is worse than a clean exit (#3348).
|
|
43
|
+
writeCrashLog(err, "uncaughtException");
|
|
44
|
+
process.exit(1);
|
|
43
45
|
};
|
|
44
46
|
process.on("uncaughtException", _gsdEpipeGuard);
|
|
45
47
|
}
|
|
48
|
+
|
|
49
|
+
if (!process.listeners("unhandledRejection").some((listener) => listener.name === "_gsdRejectionGuard")) {
|
|
50
|
+
const _gsdRejectionGuard = (reason: unknown, _promise: Promise<unknown>): void => {
|
|
51
|
+
const err = reason instanceof Error ? reason : new Error(String(reason));
|
|
52
|
+
if (handleRecoverableExtensionProcessError(err)) return;
|
|
53
|
+
writeCrashLog(err, "unhandledRejection");
|
|
54
|
+
process.exit(1);
|
|
55
|
+
};
|
|
56
|
+
process.on("unhandledRejection", _gsdRejectionGuard);
|
|
57
|
+
}
|
|
46
58
|
}
|
|
47
59
|
|
|
48
60
|
export function registerGsdExtension(pi: ExtensionAPI): void {
|
|
@@ -181,14 +181,10 @@ export function registerHooks(pi: ExtensionAPI): void {
|
|
|
181
181
|
// Only gate-shaped ask_user_questions calls should block execution.
|
|
182
182
|
// The gate stays pending until the user selects the approval option.
|
|
183
183
|
if (event.toolName === "ask_user_questions") {
|
|
184
|
-
const
|
|
185
|
-
const
|
|
186
|
-
if (
|
|
187
|
-
|
|
188
|
-
const questionId = questions.find((question) => typeof question?.id === "string" && isGateQuestionId(question.id))?.id;
|
|
189
|
-
if (typeof questionId === "string") {
|
|
190
|
-
setPendingGate(questionId);
|
|
191
|
-
}
|
|
184
|
+
const questions: any[] = (event.input as any)?.questions ?? [];
|
|
185
|
+
const questionId = questions.find((question) => typeof question?.id === "string" && isGateQuestionId(question.id))?.id;
|
|
186
|
+
if (typeof questionId === "string") {
|
|
187
|
+
setPendingGate(questionId);
|
|
192
188
|
}
|
|
193
189
|
}
|
|
194
190
|
|
|
@@ -286,7 +282,6 @@ export function registerHooks(pi: ExtensionAPI): void {
|
|
|
286
282
|
if (event.toolName !== "ask_user_questions") return;
|
|
287
283
|
const milestoneId = getDiscussionMilestoneId(process.cwd());
|
|
288
284
|
const queueActive = isQueuePhaseActive();
|
|
289
|
-
if (!milestoneId && !queueActive) return;
|
|
290
285
|
|
|
291
286
|
const details = event.details as any;
|
|
292
287
|
|
|
@@ -319,13 +314,16 @@ export function registerHooks(pi: ExtensionAPI): void {
|
|
|
319
314
|
// Only unlock the gate if the user selected the first option (confirmation).
|
|
320
315
|
// Cross-references against the question's defined options to reject free-form "Other" text.
|
|
321
316
|
const answer = details.response?.answers?.[question.id];
|
|
317
|
+
const inferredMilestoneId = extractDepthVerificationMilestoneId(question.id) ?? milestoneId;
|
|
322
318
|
if (isDepthConfirmationAnswer(answer?.selected, question.options)) {
|
|
323
|
-
markDepthVerified(
|
|
319
|
+
markDepthVerified(inferredMilestoneId);
|
|
320
|
+
clearPendingGate();
|
|
324
321
|
}
|
|
325
322
|
break;
|
|
326
323
|
}
|
|
327
324
|
}
|
|
328
325
|
|
|
326
|
+
if (!milestoneId && !queueActive) return;
|
|
329
327
|
if (!milestoneId) return;
|
|
330
328
|
|
|
331
329
|
const basePath = process.cwd();
|
|
@@ -9,6 +9,7 @@ import { debugTime } from "../debug-logger.js";
|
|
|
9
9
|
import { loadPrompt, getTemplatesDir } from "../prompt-loader.js";
|
|
10
10
|
import { readForensicsMarker } from "../forensics.js";
|
|
11
11
|
import { resolveAllSkillReferences, renderPreferencesForSystemPrompt, loadEffectiveGSDPreferences } from "../preferences.js";
|
|
12
|
+
import { resolveModelWithFallbacksForUnit } from "../preferences-models.js";
|
|
12
13
|
import { resolveSkillReference } from "../preferences-skills.js";
|
|
13
14
|
import { resolveGsdRootFile, resolveSliceFile, resolveSlicePath, resolveTaskFile, resolveTaskFiles, resolveTasksDir, relSliceFile, relSlicePath, relTaskFile } from "../paths.js";
|
|
14
15
|
import { ensureCodebaseMapFresh, readCodebaseMap } from "../codebase-generator.js";
|
|
@@ -175,7 +176,13 @@ export async function buildBeforeAgentStartResult(
|
|
|
175
176
|
const forensicsInjection = !injection ? buildForensicsContextInjection(process.cwd(), event.prompt) : null;
|
|
176
177
|
|
|
177
178
|
const worktreeBlock = buildWorktreeContextBlock();
|
|
178
|
-
|
|
179
|
+
|
|
180
|
+
const subagentModelConfig = resolveModelWithFallbacksForUnit("subagent");
|
|
181
|
+
const subagentModelBlock = subagentModelConfig
|
|
182
|
+
? `\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.`
|
|
183
|
+
: "";
|
|
184
|
+
|
|
185
|
+
const fullSystem = `${event.systemPrompt}\n\n[SYSTEM CONTEXT — GSD]\n\n${systemContent}${preferenceBlock}${knowledgeBlock}${codebaseBlock}${memoryBlock}${newSkillsBlock}${worktreeBlock}${subagentModelBlock}`;
|
|
179
186
|
|
|
180
187
|
stopContextTimer({
|
|
181
188
|
systemPromptSize: fullSystem.length,
|
|
@@ -78,6 +78,10 @@ export function parseDoctorArgs(args: string) {
|
|
|
78
78
|
return { jsonMode, dryRun, fixFlag, includeBuild, includeTests, mode, requestedScope };
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
export function isDoctorHealActionable(issue: { fixable: boolean; severity: string }): boolean {
|
|
82
|
+
return issue.fixable && issue.severity !== "info";
|
|
83
|
+
}
|
|
84
|
+
|
|
81
85
|
export async function handleDoctor(args: string, ctx: ExtensionCommandContext, pi: ExtensionAPI): Promise<void> {
|
|
82
86
|
const { jsonMode, dryRun, fixFlag, includeBuild, includeTests, mode, requestedScope } = parseDoctorArgs(args);
|
|
83
87
|
const scope = await selectDoctorScope(projectRoot(), requestedScope);
|
|
@@ -109,7 +113,7 @@ export async function handleDoctor(args: string, ctx: ExtensionCommandContext, p
|
|
|
109
113
|
scope: effectiveScope,
|
|
110
114
|
includeWarnings: true,
|
|
111
115
|
});
|
|
112
|
-
const actionable = unresolved.filter(
|
|
116
|
+
const actionable = unresolved.filter(isDoctorHealActionable);
|
|
113
117
|
if (actionable.length === 0) {
|
|
114
118
|
ctx.ui.notify("Doctor heal found nothing actionable to hand off to the LLM.", "info");
|
|
115
119
|
return;
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import { readFileSync, existsSync } from "node:fs";
|
|
17
17
|
import { join, resolve, sep } from "node:path";
|
|
18
18
|
import type { StepDefinition } from "./definition-loader.js";
|
|
19
|
-
import { readFrozenDefinition } from "./
|
|
19
|
+
import { readFrozenDefinition } from "./definition-io.js";
|
|
20
20
|
|
|
21
21
|
/** Maximum characters per artifact to prevent context window blowout. */
|
|
22
22
|
const MAX_CONTEXT_CHARS = 10_000;
|
|
@@ -15,6 +15,7 @@ import { join } from "node:path";
|
|
|
15
15
|
import { gsdRoot } from "./paths.js";
|
|
16
16
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
17
17
|
import { effectiveLockFile } from "./session-lock.js";
|
|
18
|
+
import { emitJournalEvent, queryJournal } from "./journal.js";
|
|
18
19
|
|
|
19
20
|
export interface LockData {
|
|
20
21
|
pid: number;
|
|
@@ -118,3 +119,61 @@ export function formatCrashInfo(lock: LockData): string {
|
|
|
118
119
|
|
|
119
120
|
return lines.join("\n");
|
|
120
121
|
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Emit a synthetic unit-end event for a unit that crashed without emitting its own.
|
|
125
|
+
*
|
|
126
|
+
* Queries the journal to find the most recent unit-start for the crashed unit.
|
|
127
|
+
* If a matching unit-end already exists (e.g. the hard timeout fired), this is a
|
|
128
|
+
* no-op. Called during crash recovery, before clearing the stale lock.
|
|
129
|
+
*
|
|
130
|
+
* Addresses the gap reported in #3348 where `unit-start` was emitted but no
|
|
131
|
+
* `unit-end` followed — side effects landed but the worker died before closeout.
|
|
132
|
+
*/
|
|
133
|
+
export function emitCrashRecoveredUnitEnd(basePath: string, lock: LockData): void {
|
|
134
|
+
// Skip bootstrap / starting pseudo-units — they have no meaningful unit-start event.
|
|
135
|
+
if (!lock.unitType || !lock.unitId || lock.unitType === "starting") return;
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
const all = queryJournal(basePath);
|
|
139
|
+
|
|
140
|
+
// Find the most recent unit-start for this unitId
|
|
141
|
+
const starts = all.filter(
|
|
142
|
+
(e) => e.eventType === "unit-start" && e.data?.unitId === lock.unitId,
|
|
143
|
+
);
|
|
144
|
+
if (starts.length === 0) return;
|
|
145
|
+
|
|
146
|
+
const lastStart = starts[starts.length - 1];
|
|
147
|
+
|
|
148
|
+
// Check if a unit-end was already emitted (e.g. hard timeout fired after the crash)
|
|
149
|
+
const alreadyClosed = all.some(
|
|
150
|
+
(e) =>
|
|
151
|
+
e.eventType === "unit-end" &&
|
|
152
|
+
e.data?.unitId === lock.unitId &&
|
|
153
|
+
e.causedBy?.flowId === lastStart.flowId &&
|
|
154
|
+
e.causedBy?.seq === lastStart.seq,
|
|
155
|
+
);
|
|
156
|
+
if (alreadyClosed) return;
|
|
157
|
+
|
|
158
|
+
// Find the highest seq in this flow for monotonic ordering
|
|
159
|
+
const maxSeq = all
|
|
160
|
+
.filter((e) => e.flowId === lastStart.flowId)
|
|
161
|
+
.reduce((max, e) => Math.max(max, e.seq), lastStart.seq);
|
|
162
|
+
|
|
163
|
+
emitJournalEvent(basePath, {
|
|
164
|
+
ts: new Date().toISOString(),
|
|
165
|
+
flowId: lastStart.flowId,
|
|
166
|
+
seq: maxSeq + 1,
|
|
167
|
+
eventType: "unit-end",
|
|
168
|
+
data: {
|
|
169
|
+
unitType: lock.unitType,
|
|
170
|
+
unitId: lock.unitId,
|
|
171
|
+
status: "crash-recovered",
|
|
172
|
+
artifactVerified: false,
|
|
173
|
+
},
|
|
174
|
+
causedBy: { flowId: lastStart.flowId, seq: lastStart.seq },
|
|
175
|
+
});
|
|
176
|
+
} catch {
|
|
177
|
+
// Never throw from crash recovery path — journal failure must not block recovery
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -22,7 +22,6 @@ import type {
|
|
|
22
22
|
} from "./engine-types.js";
|
|
23
23
|
import { readFileSync } from "node:fs";
|
|
24
24
|
import { join } from "node:path";
|
|
25
|
-
import { parse } from "yaml";
|
|
26
25
|
import {
|
|
27
26
|
readGraph,
|
|
28
27
|
writeGraph,
|
|
@@ -32,16 +31,13 @@ import {
|
|
|
32
31
|
type WorkflowGraph,
|
|
33
32
|
} from "./graph.js";
|
|
34
33
|
import { injectContext } from "./context-injector.js";
|
|
35
|
-
import type {
|
|
34
|
+
import type { StepDefinition } from "./definition-loader.js";
|
|
35
|
+
import { readFrozenDefinition } from "./definition-io.js";
|
|
36
36
|
import { parseUnitId } from "./unit-id.js";
|
|
37
37
|
import { withFileLock } from "./file-lock.js";
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
export
|
|
41
|
-
const defPath = join(runDir, "DEFINITION.yaml");
|
|
42
|
-
const raw = readFileSync(defPath, "utf-8");
|
|
43
|
-
return parse(raw, { schema: "core" }) as WorkflowDefinition;
|
|
44
|
-
}
|
|
39
|
+
// Re-export for downstream consumers
|
|
40
|
+
export { readFrozenDefinition } from "./definition-io.js";
|
|
45
41
|
|
|
46
42
|
export class CustomWorkflowEngine implements WorkflowEngine {
|
|
47
43
|
readonly engineId = "custom";
|
|
@@ -0,0 +1,18 @@
|
|
|
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
|
+
|
|
8
|
+
import { readFileSync } from "node:fs";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { parse } from "yaml";
|
|
11
|
+
import type { WorkflowDefinition } from "./definition-loader.js";
|
|
12
|
+
|
|
13
|
+
/** Read and parse the frozen DEFINITION.yaml from a run directory. */
|
|
14
|
+
export function readFrozenDefinition(runDir: string): WorkflowDefinition {
|
|
15
|
+
const defPath = join(runDir, "DEFINITION.yaml");
|
|
16
|
+
const raw = readFileSync(defPath, "utf-8");
|
|
17
|
+
return parse(raw, { schema: "core" }) as WorkflowDefinition;
|
|
18
|
+
}
|
|
@@ -107,6 +107,11 @@ export function getPriorSliceCompletionBlocker(
|
|
|
107
107
|
// it may be a cross-milestone reference handled elsewhere.
|
|
108
108
|
}
|
|
109
109
|
} else {
|
|
110
|
+
const milestoneUsesExplicitDeps = slices.some((slice) => slice.depends.length > 0);
|
|
111
|
+
if (milestoneUsesExplicitDeps) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
|
|
110
115
|
// Positional fallback is only a heuristic for legacy slices with no
|
|
111
116
|
// declared dependencies. Skip any earlier slice that depends on the
|
|
112
117
|
// target, directly or transitively, or we can deadlock a valid zero-dep
|
|
@@ -303,13 +303,16 @@ export async function checkRuntimeHealth(
|
|
|
303
303
|
content.split("\n").map(l => l.trim()).filter(l => l && !l.startsWith("#")),
|
|
304
304
|
);
|
|
305
305
|
|
|
306
|
-
// Check for critical runtime patterns that must be present
|
|
306
|
+
// Check for critical runtime patterns that must be present.
|
|
307
|
+
// NOTE: GSD_RUNTIME_PATTERNS in gitignore.ts is the canonical source of truth.
|
|
308
|
+
// This is a minimal subset for the doctor check.
|
|
307
309
|
const criticalPatterns = [
|
|
308
310
|
".gsd/activity/",
|
|
309
311
|
".gsd/runtime/",
|
|
310
312
|
".gsd/auto.lock",
|
|
311
|
-
".gsd/gsd.db",
|
|
312
|
-
".gsd/completed-units
|
|
313
|
+
".gsd/gsd.db*",
|
|
314
|
+
".gsd/completed-units*.json",
|
|
315
|
+
".gsd/event-log.jsonl",
|
|
313
316
|
];
|
|
314
317
|
|
|
315
318
|
// If blanket .gsd/ or .gsd is present, all patterns are covered
|
|
@@ -192,22 +192,25 @@ export interface PreMergeCheckResult {
|
|
|
192
192
|
/**
|
|
193
193
|
* GSD runtime paths that should be excluded from smart staging.
|
|
194
194
|
* These are transient/generated artifacts that should never be committed.
|
|
195
|
-
*
|
|
196
|
-
*
|
|
195
|
+
*
|
|
196
|
+
* NOTE: GSD_RUNTIME_PATTERNS in gitignore.ts is the canonical source of truth.
|
|
197
|
+
* This array must stay synchronized with it.
|
|
197
198
|
*/
|
|
198
199
|
export const RUNTIME_EXCLUSION_PATHS: readonly string[] = [
|
|
199
200
|
".gsd/activity/",
|
|
201
|
+
".gsd/forensics/",
|
|
200
202
|
".gsd/runtime/",
|
|
201
203
|
".gsd/worktrees/",
|
|
204
|
+
".gsd/parallel/",
|
|
202
205
|
".gsd/auto.lock",
|
|
203
206
|
".gsd/metrics.json",
|
|
204
|
-
".gsd/completed-units
|
|
207
|
+
".gsd/completed-units*.json", // covers completed-units.json and archived completed-units-{MID}.json
|
|
208
|
+
".gsd/state-manifest.json",
|
|
205
209
|
".gsd/STATE.md",
|
|
206
|
-
".gsd/gsd.db",
|
|
207
|
-
".gsd/
|
|
208
|
-
".gsd/
|
|
209
|
-
".gsd/
|
|
210
|
-
".gsd/doctor-history.jsonl", // doctor run history (#2296)
|
|
210
|
+
".gsd/gsd.db*",
|
|
211
|
+
".gsd/journal/",
|
|
212
|
+
".gsd/doctor-history.jsonl",
|
|
213
|
+
".gsd/event-log.jsonl",
|
|
211
214
|
".gsd/DISCUSSION-MANIFEST.json",
|
|
212
215
|
];
|
|
213
216
|
|
|
@@ -15,6 +15,12 @@ import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
|
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* GSD runtime patterns for git index cleanup.
|
|
18
|
+
*
|
|
19
|
+
* CANONICAL SOURCE OF TRUTH: This array is the authoritative list of runtime
|
|
20
|
+
* ignore patterns. Other modules (RUNTIME_EXCLUSION_PATHS in git-service.ts,
|
|
21
|
+
* SKIP_* arrays in worktree-manager.ts, criticalPatterns in doctor-runtime-checks.ts)
|
|
22
|
+
* must stay synchronized with this list.
|
|
23
|
+
*
|
|
18
24
|
* With external state (symlink), these are a no-op in most cases,
|
|
19
25
|
* but retained for backwards compatibility during migration.
|
|
20
26
|
*/
|
|
@@ -26,13 +32,13 @@ const GSD_RUNTIME_PATTERNS = [
|
|
|
26
32
|
".gsd/parallel/",
|
|
27
33
|
".gsd/auto.lock",
|
|
28
34
|
".gsd/metrics.json",
|
|
29
|
-
".gsd/completed-units
|
|
35
|
+
".gsd/completed-units*.json", // covers completed-units.json and archived completed-units-{MID}.json
|
|
36
|
+
".gsd/state-manifest.json",
|
|
30
37
|
".gsd/STATE.md",
|
|
31
|
-
".gsd/gsd.db",
|
|
32
|
-
".gsd/
|
|
33
|
-
".gsd/
|
|
34
|
-
".gsd/
|
|
35
|
-
".gsd/doctor-history.jsonl", // doctor run history (#2296)
|
|
38
|
+
".gsd/gsd.db*",
|
|
39
|
+
".gsd/journal/",
|
|
40
|
+
".gsd/doctor-history.jsonl",
|
|
41
|
+
".gsd/event-log.jsonl",
|
|
36
42
|
".gsd/DISCUSSION-MANIFEST.json",
|
|
37
43
|
".gsd/milestones/**/*-CONTINUE.md",
|
|
38
44
|
".gsd/milestones/**/continue.md",
|