gsd-pi 2.64.0-dev.f8aad9b → 2.65.0-dev.16e10d7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/headless.js +3 -1
- package/dist/mcp-server.js +6 -2
- package/dist/resources/extensions/bg-shell/bg-shell-lifecycle.js +22 -7
- package/dist/resources/extensions/bg-shell/process-manager.js +6 -1
- package/dist/resources/extensions/browser-tools/capture.js +20 -1
- package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +93 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +13 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +94 -8
- package/dist/resources/extensions/gsd/auto-model-selection.js +7 -5
- package/dist/resources/extensions/gsd/auto-post-unit.js +115 -7
- package/dist/resources/extensions/gsd/auto-prompts.js +24 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +12 -8
- package/dist/resources/extensions/gsd/auto-start.js +35 -1
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +10 -0
- package/dist/resources/extensions/gsd/auto-verification.js +138 -1
- package/dist/resources/extensions/gsd/auto-worktree.js +29 -7
- package/dist/resources/extensions/gsd/auto.js +2 -2
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +17 -4
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +34 -13
- package/dist/resources/extensions/gsd/bootstrap/notify-interceptor.js +28 -0
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +6 -4
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +5 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +12 -1
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +16 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +20 -0
- package/dist/resources/extensions/gsd/commands/catalog.js +7 -1
- package/dist/resources/extensions/gsd/commands/context.js +8 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +21 -0
- package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +104 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
- package/dist/resources/extensions/gsd/commands-extensions.js +1 -1
- package/dist/resources/extensions/gsd/config-overlay.js +312 -0
- package/dist/resources/extensions/gsd/detection.js +1 -1
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -0
- package/dist/resources/extensions/gsd/doctor.js +2 -1
- package/dist/resources/extensions/gsd/gitignore.js +1 -0
- package/dist/resources/extensions/gsd/gsd-db.js +11 -2
- package/dist/resources/extensions/gsd/guided-flow.js +220 -29
- package/dist/resources/extensions/gsd/md-importer.js +14 -7
- package/dist/resources/extensions/gsd/notification-overlay.js +256 -0
- package/dist/resources/extensions/gsd/notification-store.js +273 -0
- package/dist/resources/extensions/gsd/notification-widget.js +56 -0
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +17 -11
- package/dist/resources/extensions/gsd/post-execution-checks.js +407 -0
- package/dist/resources/extensions/gsd/pre-execution-checks.js +471 -0
- package/dist/resources/extensions/gsd/preferences-types.js +7 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +78 -1
- package/dist/resources/extensions/gsd/preferences.js +13 -2
- package/dist/resources/extensions/gsd/preparation.js +1092 -0
- package/dist/resources/extensions/gsd/prompt-validation.js +67 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +3 -3
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +4 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -4
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +23 -0
- package/dist/resources/extensions/gsd/prompts/rethink.md +2 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +56 -23
- package/dist/resources/extensions/gsd/quick.js +19 -15
- package/dist/resources/extensions/gsd/reactive-graph.js +12 -0
- package/dist/resources/extensions/gsd/roadmap-slices.js +24 -5
- package/dist/resources/extensions/gsd/safety/content-validator.js +3 -3
- package/dist/resources/extensions/gsd/session-lock.js +23 -1
- package/dist/resources/extensions/gsd/state.js +100 -12
- package/dist/resources/extensions/gsd/templates/context-enhanced.md +138 -0
- package/dist/resources/extensions/gsd/tools/complete-slice.js +12 -3
- package/dist/resources/extensions/gsd/tools/complete-task.js +16 -4
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -5
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +5 -2
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +119 -0
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +30 -0
- package/dist/resources/extensions/gsd/tools/reopen-task.js +18 -0
- package/dist/resources/extensions/gsd/triage-resolution.js +25 -9
- package/dist/resources/extensions/gsd/verification-evidence.js +18 -0
- package/dist/resources/extensions/gsd/workflow-logger.js +8 -0
- package/dist/resources/extensions/gsd/workflow-projections.js +4 -7
- package/dist/resources/extensions/gsd/workflow-reconcile.js +2 -4
- package/dist/resources/extensions/gsd/workflow-templates.js +11 -2
- package/dist/resources/extensions/gsd/worktree-manager.js +5 -2
- package/dist/resources/extensions/gsd/worktree.js +9 -0
- package/dist/resources/extensions/shared/interview-ui.js +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -17
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/routes-manifest.json +6 -0
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- 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 +1 -1
- 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/notifications/route.js +3 -0
- package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -0
- package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -0
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- 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 +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -17
- package/dist/web/standalone/.next/server/functions-config-manifest.json +1 -0
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/Z3TgDP0c7kG9j8CVQVGcl/_buildManifest.js +1 -0
- package/dist/web/standalone/.next/static/chunks/6502.8874bcae249c02e1.js +9 -0
- package/dist/web/standalone/.next/static/chunks/app/_global-error/page-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/boot/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/input/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/resize/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/stream/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/browse-directories/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/captures/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/cleanup/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/dev-mode/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/doctor/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/experimental/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/export-data/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/files/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/forensics/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/git/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/history/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/hooks/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/inspect/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/knowledge/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/live-state/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/notifications/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/onboarding/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/preferences/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/projects/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/recovery/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/remote-questions/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/session/browser/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/session/command/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/session/events/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/session/manage/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/settings-data/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/shutdown/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/skill-health/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/steer/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/switch-root/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/input/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/resize/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/sessions/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/stream/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/upload/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/undo/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/update/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/visualizer/route-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-8805a20e15762c3c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-a1c1e452c6b32d04.js → webpack-9fed74684e1c5bb1.js} +1 -1
- package/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +26 -9
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.test.ts +100 -4
- package/packages/pi-agent-core/src/agent-loop.ts +43 -12
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +38 -0
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +11 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +24 -0
- package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.js +4 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +30 -19
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +51 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +9 -9
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +10 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +2 -0
- 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 +28 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +15 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +18 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +6 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +40 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +64 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +10 -0
- package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +42 -0
- package/packages/pi-coding-agent/src/core/resource-loader.ts +5 -1
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +80 -0
- package/packages/pi-coding-agent/src/core/retry-handler.ts +37 -25
- package/packages/pi-coding-agent/src/core/sdk.ts +9 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +10 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +29 -4
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +27 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +16 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +38 -0
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +66 -0
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -0
- package/packages/pi-tui/dist/components/image.d.ts +2 -0
- package/packages/pi-tui/dist/components/image.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/image.js +4 -0
- package/packages/pi-tui/dist/components/image.js.map +1 -1
- package/packages/pi-tui/dist/components/image.test.d.ts +6 -0
- package/packages/pi-tui/dist/components/image.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/components/image.test.js +32 -0
- package/packages/pi-tui/dist/components/image.test.js.map +1 -0
- package/packages/pi-tui/dist/components/loader.d.ts +4 -2
- package/packages/pi-tui/dist/components/loader.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/loader.js +27 -9
- package/packages/pi-tui/dist/components/loader.js.map +1 -1
- package/packages/pi-tui/dist/components/text.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/text.js +2 -0
- package/packages/pi-tui/dist/components/text.js.map +1 -1
- package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
- package/packages/pi-tui/dist/overlay-layout.js +12 -1
- package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts +4 -0
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +35 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +82 -0
- package/packages/pi-tui/src/components/image.test.ts +36 -0
- package/packages/pi-tui/src/components/image.ts +5 -0
- package/packages/pi-tui/src/components/loader.ts +27 -10
- package/packages/pi-tui/src/components/text.ts +1 -0
- package/packages/pi-tui/src/overlay-layout.ts +13 -1
- package/packages/pi-tui/src/tui.ts +34 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/bg-shell/bg-shell-lifecycle.ts +19 -7
- package/src/resources/extensions/bg-shell/process-manager.ts +8 -2
- package/src/resources/extensions/browser-tools/capture.ts +19 -1
- package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +93 -0
- package/src/resources/extensions/gsd/auto/run-unit.ts +12 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +105 -8
- package/src/resources/extensions/gsd/auto-model-selection.ts +7 -5
- package/src/resources/extensions/gsd/auto-post-unit.ts +138 -6
- package/src/resources/extensions/gsd/auto-prompts.ts +31 -0
- package/src/resources/extensions/gsd/auto-recovery.ts +10 -8
- package/src/resources/extensions/gsd/auto-start.ts +38 -0
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +10 -0
- package/src/resources/extensions/gsd/auto-verification.ts +190 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +28 -7
- package/src/resources/extensions/gsd/auto.ts +2 -1
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +16 -4
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +35 -13
- package/src/resources/extensions/gsd/bootstrap/notify-interceptor.ts +34 -0
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +5 -4
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +4 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +12 -1
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +20 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +28 -0
- package/src/resources/extensions/gsd/commands/catalog.ts +7 -1
- package/src/resources/extensions/gsd/commands/context.ts +7 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +24 -0
- package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +140 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
- package/src/resources/extensions/gsd/commands-extensions.ts +1 -1
- package/src/resources/extensions/gsd/config-overlay.ts +331 -0
- package/src/resources/extensions/gsd/detection.ts +1 -1
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -0
- package/src/resources/extensions/gsd/doctor.ts +2 -1
- package/src/resources/extensions/gsd/gitignore.ts +1 -0
- package/src/resources/extensions/gsd/gsd-db.ts +13 -2
- package/src/resources/extensions/gsd/guided-flow.ts +254 -30
- package/src/resources/extensions/gsd/md-importer.ts +13 -6
- package/src/resources/extensions/gsd/notification-overlay.ts +295 -0
- package/src/resources/extensions/gsd/notification-store.ts +293 -0
- package/src/resources/extensions/gsd/notification-widget.ts +68 -0
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +19 -11
- package/src/resources/extensions/gsd/post-execution-checks.ts +539 -0
- package/src/resources/extensions/gsd/pre-execution-checks.ts +581 -0
- package/src/resources/extensions/gsd/preferences-types.ts +53 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +78 -1
- package/src/resources/extensions/gsd/preferences.ts +13 -2
- package/src/resources/extensions/gsd/preparation.ts +1419 -0
- package/src/resources/extensions/gsd/prompt-validation.ts +88 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +3 -3
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +4 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -4
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +23 -0
- package/src/resources/extensions/gsd/prompts/rethink.md +2 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +56 -23
- package/src/resources/extensions/gsd/quick.ts +20 -15
- package/src/resources/extensions/gsd/reactive-graph.ts +18 -0
- package/src/resources/extensions/gsd/roadmap-slices.ts +21 -5
- package/src/resources/extensions/gsd/safety/content-validator.ts +3 -3
- package/src/resources/extensions/gsd/session-lock.ts +17 -1
- package/src/resources/extensions/gsd/state.ts +101 -11
- package/src/resources/extensions/gsd/templates/context-enhanced.md +138 -0
- package/src/resources/extensions/gsd/tests/adversarial-review-fixes.test.ts +223 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +33 -2
- package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/complete-slice-string-coercion.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +72 -0
- package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/defer-milestone-stamp.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/discuss-incremental-persistence.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +76 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/enhanced-verification-integration.test.ts +526 -0
- package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +28 -30
- package/src/resources/extensions/gsd/tests/integration/test-isolation.ts +53 -0
- package/src/resources/extensions/gsd/tests/integration-prepared-discussion.test.ts +525 -0
- package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +73 -0
- package/src/resources/extensions/gsd/tests/notification-store.test.ts +282 -0
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +77 -0
- package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +312 -0
- package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +813 -0
- package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +1197 -0
- package/src/resources/extensions/gsd/tests/pre-execution-fail-closed.test.ts +266 -0
- package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +457 -0
- package/src/resources/extensions/gsd/tests/preparation.test.ts +1211 -0
- package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/prompt-builder.test.ts +669 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +7 -4
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/reactive-graph.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +4 -5
- package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/show-config-command.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/skipped-validation-completion.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +147 -0
- package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +13 -0
- package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +6 -7
- package/src/resources/extensions/gsd/tests/status-db-open.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/symlink-extension-discovery.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +29 -1
- package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +163 -0
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +3 -4
- package/src/resources/extensions/gsd/tests/verification-operational-gate.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +16 -17
- package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +13 -9
- package/src/resources/extensions/gsd/tests/worktree.test.ts +26 -9
- package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +13 -3
- package/src/resources/extensions/gsd/tools/complete-task.ts +16 -4
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +11 -9
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +5 -2
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +152 -0
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +27 -0
- package/src/resources/extensions/gsd/tools/reopen-task.ts +17 -0
- package/src/resources/extensions/gsd/triage-resolution.ts +29 -10
- package/src/resources/extensions/gsd/types.ts +4 -0
- package/src/resources/extensions/gsd/verification-evidence.ts +68 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +13 -0
- package/src/resources/extensions/gsd/workflow-projections.ts +4 -6
- package/src/resources/extensions/gsd/workflow-reconcile.ts +2 -3
- package/src/resources/extensions/gsd/workflow-templates.ts +11 -2
- package/src/resources/extensions/gsd/worktree-manager.ts +4 -2
- package/src/resources/extensions/gsd/worktree.ts +10 -0
- package/src/resources/extensions/shared/interview-ui.ts +1 -1
- package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +8 -10
- package/dist/web/standalone/.next/static/F1mOwzgCW9R8N3Pt1Et87/_buildManifest.js +0 -1
- package/dist/web/standalone/.next/static/chunks/6502.7593d7797a4b3999.js +0 -9
- package/dist/web/standalone/.next/static/chunks/app/_global-error/page-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/boot/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/input/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/resize/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/stream/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/browse-directories/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/captures/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/cleanup/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/dev-mode/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/doctor/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/experimental/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/export-data/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/files/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/forensics/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/git/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/history/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/hooks/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/inspect/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/knowledge/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/live-state/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/onboarding/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/preferences/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/projects/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/recovery/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/remote-questions/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/session/browser/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/session/command/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/session/events/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/session/manage/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/settings-data/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/shutdown/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/skill-health/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/steer/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/switch-root/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/input/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/resize/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/sessions/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/stream/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/upload/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/undo/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/update/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/visualizer/route-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-c4cc189e7b117ea2.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-c4cc189e7b117ea2.js +0 -1
- /package/dist/web/standalone/.next/static/{F1mOwzgCW9R8N3Pt1Et87 → Z3TgDP0c7kG9j8CVQVGcl}/_ssgManifest.js +0 -0
|
@@ -754,6 +754,7 @@ export async function buildDiscussMilestonePrompt(mid, midTitle, base) {
|
|
|
754
754
|
inlinedTemplates: discussTemplates,
|
|
755
755
|
structuredQuestionsAvailable: "true",
|
|
756
756
|
commitInstruction: "Do not commit planning artifacts — .gsd/ is managed externally.",
|
|
757
|
+
fastPathInstruction: "",
|
|
757
758
|
});
|
|
758
759
|
// If a CONTEXT-DRAFT.md exists, append it as seed material
|
|
759
760
|
const draftPath = resolveMilestoneFile(base, mid, "CONTEXT-DRAFT");
|
|
@@ -1607,6 +1608,29 @@ const GATE_QUESTIONS = {
|
|
|
1607
1608
|
].join("\n"),
|
|
1608
1609
|
},
|
|
1609
1610
|
};
|
|
1611
|
+
export async function buildParallelResearchSlicesPrompt(mid, midTitle, slices, basePath) {
|
|
1612
|
+
// Build individual research-slice prompts for each slice
|
|
1613
|
+
const subagentSections = [];
|
|
1614
|
+
for (const slice of slices) {
|
|
1615
|
+
const slicePrompt = await buildResearchSlicePrompt(mid, midTitle, slice.id, slice.title, basePath);
|
|
1616
|
+
subagentSections.push([
|
|
1617
|
+
`### ${slice.id}: ${slice.title}`,
|
|
1618
|
+
"",
|
|
1619
|
+
"Use this as the prompt for a `subagent` call (agent: `gsd-executor` or the default agent):",
|
|
1620
|
+
"",
|
|
1621
|
+
"```",
|
|
1622
|
+
slicePrompt,
|
|
1623
|
+
"```",
|
|
1624
|
+
].join("\n"));
|
|
1625
|
+
}
|
|
1626
|
+
return loadPrompt("parallel-research-slices", {
|
|
1627
|
+
mid,
|
|
1628
|
+
midTitle,
|
|
1629
|
+
sliceCount: String(slices.length),
|
|
1630
|
+
sliceList: slices.map((s) => `- **${s.id}**: ${s.title}`).join("\n"),
|
|
1631
|
+
subagentPrompts: subagentSections.join("\n\n---\n\n"),
|
|
1632
|
+
});
|
|
1633
|
+
}
|
|
1610
1634
|
export async function buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, base) {
|
|
1611
1635
|
const pending = getPendingGates(mid, sid, "slice");
|
|
1612
1636
|
// Load the slice plan for context
|
|
@@ -238,7 +238,7 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
|
|
|
238
238
|
if (!hasCheckboxTask && !hasHeadingTask)
|
|
239
239
|
return false;
|
|
240
240
|
}
|
|
241
|
-
// execute-task: DB status is authoritative. Fall back to
|
|
241
|
+
// execute-task: DB status is authoritative. Fall back to checked-checkbox
|
|
242
242
|
// detection when the DB is unavailable (unmigrated projects).
|
|
243
243
|
if (unitType === "execute-task") {
|
|
244
244
|
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
|
@@ -251,21 +251,25 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
|
|
|
251
251
|
}
|
|
252
252
|
else if (!isDbAvailable()) {
|
|
253
253
|
// LEGACY: Pre-migration fallback for projects without DB.
|
|
254
|
-
//
|
|
255
|
-
//
|
|
256
|
-
//
|
|
254
|
+
// Require a CHECKED checkbox — a bare heading or unchecked checkbox
|
|
255
|
+
// does not prove gsd_complete_task ran. Summary file on disk alone
|
|
256
|
+
// is not sufficient evidence (could be a rogue write) (#3607).
|
|
257
257
|
const planAbs = resolveSliceFile(base, mid, sid, "PLAN");
|
|
258
258
|
if (planAbs && existsSync(planAbs)) {
|
|
259
259
|
const planContent = readFileSync(planAbs, "utf-8");
|
|
260
260
|
const escapedTid = tid.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
261
|
-
const hdRe = new RegExp(`^#{2,4}\\s+${escapedTid}\\s*(?:--|—|:)`, "m");
|
|
262
261
|
const cbRe = new RegExp(`^- \\[[xX]\\] \\*\\*${escapedTid}:`, "m");
|
|
263
|
-
if (!
|
|
262
|
+
if (!cbRe.test(planContent))
|
|
264
263
|
return false;
|
|
265
264
|
}
|
|
265
|
+
else {
|
|
266
|
+
return false; // no plan file → cannot verify
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
// DB available but task row not found — completion tool never ran (#3607)
|
|
271
|
+
return false;
|
|
266
272
|
}
|
|
267
|
-
// else: DB available but task not found — summary file exists (checked above),
|
|
268
|
-
// so treat as verified (task may not be imported yet)
|
|
269
273
|
}
|
|
270
274
|
}
|
|
271
275
|
// plan-slice must also produce individual task plan files for every task listed
|
|
@@ -20,7 +20,7 @@ import { synthesizeCrashRecovery } from "./session-forensics.js";
|
|
|
20
20
|
import { writeLock, clearLock, readCrashLock, formatCrashInfo, isLockProcessAlive, } from "./crash-recovery.js";
|
|
21
21
|
import { acquireSessionLock, releaseSessionLock, updateSessionLock, } from "./session-lock.js";
|
|
22
22
|
import { ensureGitignore, untrackRuntimeFiles } from "./gitignore.js";
|
|
23
|
-
import { nativeInit, nativeAddAll, nativeCommit, } from "./native-git-bridge.js";
|
|
23
|
+
import { nativeIsRepo, nativeInit, nativeAddAll, nativeCommit, nativeGetCurrentBranch, nativeDetectMainBranch, nativeCheckoutBranch, } from "./native-git-bridge.js";
|
|
24
24
|
import { GitServiceImpl } from "./git-service.js";
|
|
25
25
|
import { captureIntegrationBranch, detectWorktreeName, setActiveMilestoneId, } from "./worktree.js";
|
|
26
26
|
import { getAutoWorktreePath } from "./auto-worktree.js";
|
|
@@ -373,6 +373,22 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
373
373
|
}
|
|
374
374
|
setActiveMilestoneId(base, s.currentMilestoneId);
|
|
375
375
|
}
|
|
376
|
+
// Guard against stale milestone branch when isolation:none (#3613).
|
|
377
|
+
// A prior session with isolation:branch/worktree may have left HEAD on
|
|
378
|
+
// milestone/<MID>. Auto-checkout back to the integration branch.
|
|
379
|
+
if (getIsolationMode() === "none" && nativeIsRepo(base)) {
|
|
380
|
+
try {
|
|
381
|
+
const currentBranch = nativeGetCurrentBranch(base);
|
|
382
|
+
if (currentBranch.startsWith("milestone/")) {
|
|
383
|
+
const integrationBranch = nativeDetectMainBranch(base);
|
|
384
|
+
nativeCheckoutBranch(base, integrationBranch);
|
|
385
|
+
logWarning("bootstrap", `Returned to "${integrationBranch}" — HEAD was on stale milestone branch "${currentBranch}" (isolation: none does not use milestone branches).`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
catch (err) {
|
|
389
|
+
logWarning("bootstrap", `Could not auto-checkout from stale milestone branch: ${err instanceof Error ? err.message : String(err)}`);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
376
392
|
// ── Auto-worktree setup ──
|
|
377
393
|
s.originalBasePath = base;
|
|
378
394
|
const isUnderGsdWorktrees = (p) => {
|
|
@@ -448,6 +464,24 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
448
464
|
id: startModelSnapshot.id,
|
|
449
465
|
};
|
|
450
466
|
}
|
|
467
|
+
// Apply worker model override from parallel orchestrator (#worker-model).
|
|
468
|
+
// GSD_WORKER_MODEL is injected by the coordinator when parallel.worker_model
|
|
469
|
+
// is configured, so parallel milestone workers use a cheaper model than the
|
|
470
|
+
// coordinator session (e.g. Haiku for execution, Sonnet for planning).
|
|
471
|
+
const workerModelOverride = process.env.GSD_WORKER_MODEL;
|
|
472
|
+
if (workerModelOverride && process.env.GSD_PARALLEL_WORKER === "1") {
|
|
473
|
+
const availableModels = ctx.modelRegistry.getAvailable();
|
|
474
|
+
const { resolveModelId } = await import("./auto-model-selection.js");
|
|
475
|
+
const overrideModel = resolveModelId(workerModelOverride, availableModels, ctx.model?.provider);
|
|
476
|
+
if (overrideModel) {
|
|
477
|
+
const ok = await pi.setModel(overrideModel, { persist: false });
|
|
478
|
+
if (ok) {
|
|
479
|
+
// Update start model so all subsequent units use this as the baseline
|
|
480
|
+
s.autoModeStartModel = { provider: overrideModel.provider, id: overrideModel.id };
|
|
481
|
+
ctx.ui.notify(`Worker model override: ${overrideModel.provider}/${overrideModel.id}`, "info");
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
451
485
|
// Snapshot installed skills
|
|
452
486
|
if (resolveSkillDiscoveryMode() !== "off") {
|
|
453
487
|
snapshotSkills();
|
|
@@ -92,3 +92,13 @@ export function isToolInvocationError(errorMsg) {
|
|
|
92
92
|
return false;
|
|
93
93
|
return TOOL_INVOCATION_ERROR_RE.test(errorMsg);
|
|
94
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Returns true if the error message indicates the tool was skipped because
|
|
97
|
+
* a queued user message interrupted the turn (#3595). Retrying will produce
|
|
98
|
+
* the same skip, so the unit should be paused rather than retried.
|
|
99
|
+
*/
|
|
100
|
+
export function isQueuedUserMessageSkip(errorMsg) {
|
|
101
|
+
if (!errorMsg)
|
|
102
|
+
return false;
|
|
103
|
+
return /^Skipped due to queued user message\.?$/i.test(errorMsg.trim());
|
|
104
|
+
}
|
|
@@ -9,13 +9,15 @@
|
|
|
9
9
|
* value instead of calling return/pauseAuto directly — the caller
|
|
10
10
|
* checks the result and handles control flow.
|
|
11
11
|
*/
|
|
12
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
12
13
|
import { resolveSlicePath } from "./paths.js";
|
|
13
14
|
import { parseUnitId } from "./unit-id.js";
|
|
14
|
-
import { isDbAvailable, getTask } from "./gsd-db.js";
|
|
15
|
+
import { isDbAvailable, getTask, getSliceTasks } from "./gsd-db.js";
|
|
15
16
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
16
17
|
import { runVerificationGate, formatFailureContext, captureRuntimeErrors, runDependencyAudit, } from "./verification-gate.js";
|
|
17
18
|
import { writeVerificationJSON } from "./verification-evidence.js";
|
|
18
19
|
import { logWarning } from "./workflow-logger.js";
|
|
20
|
+
import { runPostExecutionChecks } from "./post-execution-checks.js";
|
|
19
21
|
import { join } from "node:path";
|
|
20
22
|
function isInfraVerificationFailure(stderr) {
|
|
21
23
|
return /\b(ENOENT|ENOTFOUND|ETIMEDOUT|ECONNRESET|EAI_AGAIN|spawn\s+\S+\s+ENOENT|command not found)\b/i.test(stderr);
|
|
@@ -128,12 +130,104 @@ export async function runPostUnitVerification(vctx, pauseAuto) {
|
|
|
128
130
|
: "Verification failed due to infrastructure/runtime environment issues — treating as advisory.", "warning");
|
|
129
131
|
return "continue";
|
|
130
132
|
}
|
|
133
|
+
// ── Post-execution checks (run after main verification passes for execute-task units) ──
|
|
134
|
+
let postExecChecks;
|
|
135
|
+
let postExecBlockingFailure = false;
|
|
136
|
+
if (result.passed && mid && sid && tid) {
|
|
137
|
+
// Check preferences — respect enhanced_verification and enhanced_verification_post
|
|
138
|
+
const enhancedEnabled = prefs?.enhanced_verification !== false; // default true
|
|
139
|
+
const postEnabled = prefs?.enhanced_verification_post !== false; // default true
|
|
140
|
+
if (enhancedEnabled && postEnabled && isDbAvailable()) {
|
|
141
|
+
try {
|
|
142
|
+
// Get the completed task from DB
|
|
143
|
+
const taskRow = getTask(mid, sid, tid);
|
|
144
|
+
if (taskRow && taskRow.key_files && taskRow.key_files.length > 0) {
|
|
145
|
+
// Get all tasks in the slice
|
|
146
|
+
const allTasks = getSliceTasks(mid, sid);
|
|
147
|
+
// Filter to prior completed tasks (status = 'complete' or 'done', before current task)
|
|
148
|
+
const priorTasks = allTasks.filter((t) => (t.status === "complete" || t.status === "done") &&
|
|
149
|
+
t.id !== tid &&
|
|
150
|
+
t.sequence < taskRow.sequence);
|
|
151
|
+
// Run post-execution checks
|
|
152
|
+
const postExecResult = runPostExecutionChecks(taskRow, priorTasks, s.basePath);
|
|
153
|
+
// Store checks for evidence JSON
|
|
154
|
+
postExecChecks = postExecResult.checks;
|
|
155
|
+
// Log summary to stderr with gsd-post-exec: prefix
|
|
156
|
+
const emoji = postExecResult.status === "pass"
|
|
157
|
+
? "✅"
|
|
158
|
+
: postExecResult.status === "warn"
|
|
159
|
+
? "⚠️"
|
|
160
|
+
: "❌";
|
|
161
|
+
process.stderr.write(`gsd-post-exec: ${emoji} Post-execution checks ${postExecResult.status} for ${mid}/${sid}/${tid} (${postExecResult.durationMs}ms)\n`);
|
|
162
|
+
// Log individual check results
|
|
163
|
+
for (const check of postExecResult.checks) {
|
|
164
|
+
const checkEmoji = check.passed
|
|
165
|
+
? "✓"
|
|
166
|
+
: check.blocking
|
|
167
|
+
? "✗"
|
|
168
|
+
: "⚠";
|
|
169
|
+
process.stderr.write(`gsd-post-exec: ${checkEmoji} [${check.category}] ${check.target}: ${check.message}\n`);
|
|
170
|
+
}
|
|
171
|
+
// Check for blocking failures
|
|
172
|
+
if (postExecResult.status === "fail") {
|
|
173
|
+
postExecBlockingFailure = true;
|
|
174
|
+
const blockingCount = postExecResult.checks.filter((c) => !c.passed && c.blocking).length;
|
|
175
|
+
ctx.ui.notify(`Post-execution checks failed: ${blockingCount} blocking issue${blockingCount === 1 ? "" : "s"} found`, "error");
|
|
176
|
+
}
|
|
177
|
+
else if (postExecResult.status === "warn") {
|
|
178
|
+
ctx.ui.notify(`Post-execution checks passed with warnings`, "warning");
|
|
179
|
+
// Strict mode: treat warnings as blocking
|
|
180
|
+
if (prefs?.enhanced_verification_strict === true) {
|
|
181
|
+
postExecBlockingFailure = true;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
catch (postExecErr) {
|
|
187
|
+
// Post-execution check errors are non-fatal — log and continue
|
|
188
|
+
logWarning("engine", `gsd-post-exec: error — ${postExecErr.message}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// Re-write verification evidence JSON with post-execution checks
|
|
193
|
+
if (postExecChecks && postExecChecks.length > 0 && mid && sid && tid) {
|
|
194
|
+
try {
|
|
195
|
+
const sDir = resolveSlicePath(s.basePath, mid, sid);
|
|
196
|
+
if (sDir) {
|
|
197
|
+
const tasksDir = join(sDir, "tasks");
|
|
198
|
+
// Add postExecutionChecks to the result for the JSON write
|
|
199
|
+
const resultWithPostExec = {
|
|
200
|
+
...result,
|
|
201
|
+
// Mark as failed if there was a blocking post-exec failure
|
|
202
|
+
passed: result.passed && !postExecBlockingFailure,
|
|
203
|
+
};
|
|
204
|
+
// Manually write with postExecutionChecks field
|
|
205
|
+
writeVerificationJSONWithPostExec(resultWithPostExec, tasksDir, tid, s.currentUnit.id, postExecChecks, postExecBlockingFailure ? attempt + 1 : undefined, postExecBlockingFailure ? maxRetries : undefined);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
catch (evidenceErr) {
|
|
209
|
+
logWarning("engine", `verification-evidence: post-exec write error — ${evidenceErr.message}`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// Update result.passed based on post-execution checks
|
|
213
|
+
if (postExecBlockingFailure) {
|
|
214
|
+
result.passed = false;
|
|
215
|
+
}
|
|
131
216
|
// ── Auto-fix retry logic ──
|
|
132
217
|
if (result.passed) {
|
|
133
218
|
s.verificationRetryCount.delete(s.currentUnit.id);
|
|
134
219
|
s.pendingVerificationRetry = null;
|
|
135
220
|
return "continue";
|
|
136
221
|
}
|
|
222
|
+
else if (postExecBlockingFailure) {
|
|
223
|
+
// Post-execution failures are cross-task consistency issues — retrying the same task won't fix them.
|
|
224
|
+
// Skip retry and pause immediately for human review.
|
|
225
|
+
s.verificationRetryCount.delete(s.currentUnit.id);
|
|
226
|
+
s.pendingVerificationRetry = null;
|
|
227
|
+
ctx.ui.notify(`Post-execution checks failed — cross-task consistency issue detected, pausing for human review`, "error");
|
|
228
|
+
await pauseAuto(ctx, pi);
|
|
229
|
+
return "pause";
|
|
230
|
+
}
|
|
137
231
|
else if (autoFixEnabled && attempt + 1 <= maxRetries) {
|
|
138
232
|
const nextAttempt = attempt + 1;
|
|
139
233
|
s.verificationRetryCount.set(s.currentUnit.id, nextAttempt);
|
|
@@ -173,3 +267,46 @@ export async function runPostUnitVerification(vctx, pauseAuto) {
|
|
|
173
267
|
return "continue";
|
|
174
268
|
}
|
|
175
269
|
}
|
|
270
|
+
/**
|
|
271
|
+
* Write verification evidence JSON with post-execution checks included.
|
|
272
|
+
* This is a variant of writeVerificationJSON that adds the postExecutionChecks field.
|
|
273
|
+
*/
|
|
274
|
+
function writeVerificationJSONWithPostExec(result, tasksDir, taskId, unitId, postExecutionChecks, retryAttempt, maxRetries) {
|
|
275
|
+
mkdirSync(tasksDir, { recursive: true });
|
|
276
|
+
const evidence = {
|
|
277
|
+
schemaVersion: 1,
|
|
278
|
+
taskId,
|
|
279
|
+
unitId: unitId ?? taskId,
|
|
280
|
+
timestamp: result.timestamp,
|
|
281
|
+
passed: result.passed,
|
|
282
|
+
discoverySource: result.discoverySource,
|
|
283
|
+
checks: result.checks.map((check) => ({
|
|
284
|
+
command: check.command,
|
|
285
|
+
exitCode: check.exitCode,
|
|
286
|
+
durationMs: check.durationMs,
|
|
287
|
+
verdict: check.exitCode === 0 ? "pass" : "fail",
|
|
288
|
+
})),
|
|
289
|
+
...(retryAttempt !== undefined ? { retryAttempt } : {}),
|
|
290
|
+
...(maxRetries !== undefined ? { maxRetries } : {}),
|
|
291
|
+
postExecutionChecks,
|
|
292
|
+
};
|
|
293
|
+
if (result.runtimeErrors && result.runtimeErrors.length > 0) {
|
|
294
|
+
evidence.runtimeErrors = result.runtimeErrors.map(e => ({
|
|
295
|
+
source: e.source,
|
|
296
|
+
severity: e.severity,
|
|
297
|
+
message: e.message,
|
|
298
|
+
blocking: e.blocking,
|
|
299
|
+
}));
|
|
300
|
+
}
|
|
301
|
+
if (result.auditWarnings && result.auditWarnings.length > 0) {
|
|
302
|
+
evidence.auditWarnings = result.auditWarnings.map(w => ({
|
|
303
|
+
name: w.name,
|
|
304
|
+
severity: w.severity,
|
|
305
|
+
title: w.title,
|
|
306
|
+
url: w.url,
|
|
307
|
+
fixAvailable: w.fixAvailable,
|
|
308
|
+
}));
|
|
309
|
+
}
|
|
310
|
+
const filePath = join(tasksDir, `${taskId}-VERIFY.json`);
|
|
311
|
+
writeFileSync(filePath, JSON.stringify(evidence, null, 2) + "\n", "utf-8");
|
|
312
|
+
}
|
|
@@ -135,8 +135,10 @@ function clearProjectRootStateFiles(basePath, milestoneId) {
|
|
|
135
135
|
unlinkSync(file);
|
|
136
136
|
}
|
|
137
137
|
catch (err) {
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
// ENOENT is expected — file may not exist (#3597)
|
|
139
|
+
if (err.code !== "ENOENT") {
|
|
140
|
+
logWarning("worktree", `file unlink failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
141
|
+
}
|
|
140
142
|
}
|
|
141
143
|
}
|
|
142
144
|
// Clean up entire synced milestone directory and runtime/units.
|
|
@@ -160,8 +162,11 @@ function clearProjectRootStateFiles(basePath, milestoneId) {
|
|
|
160
162
|
unlinkSync(join(basePath, f));
|
|
161
163
|
}
|
|
162
164
|
catch (err) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
+
// ENOENT/EISDIR are expected for already-removed or directory entries (#3597)
|
|
166
|
+
const code = err.code;
|
|
167
|
+
if (code !== "ENOENT" && code !== "EISDIR") {
|
|
168
|
+
logWarning("worktree", `untracked file unlink failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
169
|
+
}
|
|
165
170
|
}
|
|
166
171
|
}
|
|
167
172
|
}
|
|
@@ -656,6 +661,10 @@ export function syncWorktreeStateBack(mainBasePath, worktreePath, milestoneId) {
|
|
|
656
661
|
.filter((d) => d.isDirectory())
|
|
657
662
|
.map((d) => d.name);
|
|
658
663
|
for (const mid of wtMilestones) {
|
|
664
|
+
// Skip the current milestone being merged — its files are already in the
|
|
665
|
+
// milestone branch and would conflict with the squash merge (#3641).
|
|
666
|
+
if (mid === milestoneId)
|
|
667
|
+
continue;
|
|
659
668
|
syncMilestoneDir(wtGsd, mainGsd, mid, synced);
|
|
660
669
|
}
|
|
661
670
|
}
|
|
@@ -901,11 +910,19 @@ export function createAutoWorktree(basePath, milestoneId) {
|
|
|
901
910
|
});
|
|
902
911
|
}
|
|
903
912
|
else {
|
|
904
|
-
// Fresh start — create branch from integration branch
|
|
913
|
+
// Fresh start — create branch from integration branch.
|
|
914
|
+
// Use the same 3-tier fallback as mergeMilestoneToMain (#3461):
|
|
915
|
+
// 1. META.json integration branch (explicit per-milestone override)
|
|
916
|
+
// 2. git.main_branch preference (user's configured working branch)
|
|
917
|
+
// 3. nativeDetectMainBranch (origin/HEAD auto-detection)
|
|
918
|
+
// Without tier 2, projects with main_branch=dev but origin/HEAD→master
|
|
919
|
+
// would fork worktrees from the wrong (stale) branch.
|
|
905
920
|
const integrationBranch = readIntegrationBranch(basePath, milestoneId) ?? undefined;
|
|
921
|
+
const gitPrefs = loadEffectiveGSDPreferences()?.preferences?.git;
|
|
922
|
+
const startPoint = integrationBranch ?? gitPrefs?.main_branch ?? undefined;
|
|
906
923
|
info = createWorktree(basePath, milestoneId, {
|
|
907
924
|
branch,
|
|
908
|
-
startPoint
|
|
925
|
+
startPoint,
|
|
909
926
|
});
|
|
910
927
|
}
|
|
911
928
|
// Copy .gsd/ planning artifacts from the source repo into the new worktree.
|
|
@@ -1235,7 +1252,12 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1235
1252
|
// checkout and leave the user with a broken merge state (#1668).
|
|
1236
1253
|
const prefs = loadEffectiveGSDPreferences()?.preferences?.git ?? {};
|
|
1237
1254
|
const integrationBranch = readIntegrationBranch(originalBasePath_, milestoneId);
|
|
1238
|
-
|
|
1255
|
+
// Validate prefs.main_branch exists before using it — a stale preference
|
|
1256
|
+
// (e.g. "master" when repo uses "main") causes merge failure (#3589).
|
|
1257
|
+
const validatedPrefBranch = prefs.main_branch && nativeBranchExists(originalBasePath_, prefs.main_branch)
|
|
1258
|
+
? prefs.main_branch
|
|
1259
|
+
: undefined;
|
|
1260
|
+
const mainBranch = integrationBranch ?? validatedPrefBranch ?? nativeDetectMainBranch(originalBasePath_);
|
|
1239
1261
|
// Remove transient project-root state files before any branch or merge
|
|
1240
1262
|
// operation. Untracked milestone metadata can otherwise block squash merges.
|
|
1241
1263
|
clearProjectRootStateFiles(originalBasePath_, milestoneId);
|
|
@@ -23,7 +23,7 @@ import { acquireSessionLock, getSessionLockStatus, releaseSessionLock, updateSes
|
|
|
23
23
|
import { resolveAutoSupervisorConfig, loadEffectiveGSDPreferences, getIsolationMode, } from "./preferences.js";
|
|
24
24
|
import { sendDesktopNotification } from "./notifications.js";
|
|
25
25
|
import { getBudgetAlertLevel, getNewBudgetAlertLevel, getBudgetEnforcementAction, } from "./auto-budget.js";
|
|
26
|
-
import { markToolStart as _markToolStart, markToolEnd as _markToolEnd, getOldestInFlightToolAgeMs as _getOldestInFlightToolAgeMs, clearInFlightTools, isToolInvocationError, } from "./auto-tool-tracking.js";
|
|
26
|
+
import { markToolStart as _markToolStart, markToolEnd as _markToolEnd, getOldestInFlightToolAgeMs as _getOldestInFlightToolAgeMs, clearInFlightTools, isToolInvocationError, isQueuedUserMessageSkip, } from "./auto-tool-tracking.js";
|
|
27
27
|
import { closeoutUnit } from "./auto-unit-closeout.js";
|
|
28
28
|
import { selectAndApplyModel, resolveModelId } from "./auto-model-selection.js";
|
|
29
29
|
import { resetRoutingHistory, recordOutcome } from "./routing-history.js";
|
|
@@ -201,7 +201,7 @@ export function markToolEnd(toolCallId) {
|
|
|
201
201
|
export function recordToolInvocationError(toolName, errorMsg) {
|
|
202
202
|
if (!s.active)
|
|
203
203
|
return;
|
|
204
|
-
if (isToolInvocationError(errorMsg)) {
|
|
204
|
+
if (isToolInvocationError(errorMsg) || isQueuedUserMessageSkip(errorMsg)) {
|
|
205
205
|
s.lastToolInvocationError = `${toolName}: ${errorMsg}`;
|
|
206
206
|
}
|
|
207
207
|
}
|
|
@@ -79,11 +79,24 @@ export async function handleAgentEnd(pi, event, ctx) {
|
|
|
79
79
|
return;
|
|
80
80
|
}
|
|
81
81
|
if (lastMsg && "stopReason" in lastMsg && lastMsg.stopReason === "error") {
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
// #3588: errorMessage can be useless (e.g. "success") while the real error
|
|
83
|
+
// is in the assistant message text content. Fall back to content when
|
|
84
|
+
// errorMessage looks uninformative.
|
|
85
|
+
const rawErrorMsg = ("errorMessage" in lastMsg && lastMsg.errorMessage) ? String(lastMsg.errorMessage) : "";
|
|
86
|
+
const isUseless = !rawErrorMsg || /^(success|ok|true|error|unknown)$/i.test(rawErrorMsg.trim());
|
|
87
|
+
// #3588: When errorMessage is uninformative, extract the real error from
|
|
88
|
+
// the assistant message text content for display purposes only.
|
|
89
|
+
// Classification still uses rawErrorMsg to avoid false positives from prose.
|
|
90
|
+
let displayMsg = rawErrorMsg;
|
|
91
|
+
if (isUseless && "content" in lastMsg && Array.isArray(lastMsg.content)) {
|
|
92
|
+
const textBlock = lastMsg.content.find((b) => b.type === "text" && b.text);
|
|
93
|
+
if (textBlock)
|
|
94
|
+
displayMsg = textBlock.text.slice(0, 300);
|
|
95
|
+
}
|
|
96
|
+
const errorDetail = displayMsg ? `: ${displayMsg}` : "";
|
|
84
97
|
const explicitRetryAfterMs = ("retryAfterMs" in lastMsg && typeof lastMsg.retryAfterMs === "number") ? lastMsg.retryAfterMs : undefined;
|
|
85
|
-
// ── 1. Classify
|
|
86
|
-
const cls = classifyError(
|
|
98
|
+
// ── 1. Classify using rawErrorMsg to avoid prose false-positives ────
|
|
99
|
+
const cls = classifyError(rawErrorMsg, explicitRetryAfterMs);
|
|
87
100
|
// Cap rate-limit backoff for CLI-style providers (openai-codex, google-gemini-cli)
|
|
88
101
|
// which use per-user quotas with shorter windows (#2922).
|
|
89
102
|
if (cls.kind === "rate-limit") {
|
|
@@ -768,31 +768,42 @@ export function registerDbTools(pi) {
|
|
|
768
768
|
return m ? [m[1].trim(), m[2].trim()] : [s.trim(), ""];
|
|
769
769
|
};
|
|
770
770
|
const coerced = { ...params };
|
|
771
|
-
|
|
771
|
+
// Coerce simple string-array fields: LLMs sometimes pass a plain string
|
|
772
|
+
// instead of a single-element array (#3585).
|
|
773
|
+
const wrapArray = (v) => v == null ? [] : Array.isArray(v) ? v : [v];
|
|
774
|
+
coerced.provides = wrapArray(params.provides);
|
|
775
|
+
coerced.keyFiles = wrapArray(params.keyFiles);
|
|
776
|
+
coerced.keyDecisions = wrapArray(params.keyDecisions);
|
|
777
|
+
coerced.patternsEstablished = wrapArray(params.patternsEstablished);
|
|
778
|
+
coerced.observabilitySurfaces = wrapArray(params.observabilitySurfaces);
|
|
779
|
+
coerced.requirementsSurfaced = wrapArray(params.requirementsSurfaced);
|
|
780
|
+
coerced.drillDownPaths = wrapArray(params.drillDownPaths);
|
|
781
|
+
coerced.affects = wrapArray(params.affects);
|
|
782
|
+
coerced.filesModified = wrapArray(params.filesModified).map((f) => {
|
|
772
783
|
if (typeof f !== "string")
|
|
773
784
|
return f;
|
|
774
785
|
const [path, description] = splitPair(f);
|
|
775
786
|
return { path, description };
|
|
776
787
|
});
|
|
777
|
-
coerced.requires = (params.requires
|
|
788
|
+
coerced.requires = wrapArray(params.requires).map((r) => {
|
|
778
789
|
if (typeof r !== "string")
|
|
779
790
|
return r;
|
|
780
791
|
const [slice, provides] = splitPair(r);
|
|
781
792
|
return { slice, provides };
|
|
782
793
|
});
|
|
783
|
-
coerced.requirementsAdvanced = (params.requirementsAdvanced
|
|
794
|
+
coerced.requirementsAdvanced = wrapArray(params.requirementsAdvanced).map((r) => {
|
|
784
795
|
if (typeof r !== "string")
|
|
785
796
|
return r;
|
|
786
797
|
const [id, how] = splitPair(r);
|
|
787
798
|
return { id, how };
|
|
788
799
|
});
|
|
789
|
-
coerced.requirementsValidated = (params.requirementsValidated
|
|
800
|
+
coerced.requirementsValidated = wrapArray(params.requirementsValidated).map((r) => {
|
|
790
801
|
if (typeof r !== "string")
|
|
791
802
|
return r;
|
|
792
803
|
const [id, proof] = splitPair(r);
|
|
793
804
|
return { id, proof };
|
|
794
805
|
});
|
|
795
|
-
coerced.requirementsInvalidated = (params.requirementsInvalidated
|
|
806
|
+
coerced.requirementsInvalidated = wrapArray(params.requirementsInvalidated).map((r) => {
|
|
796
807
|
if (typeof r !== "string")
|
|
797
808
|
return r;
|
|
798
809
|
const [id, what] = splitPair(r);
|
|
@@ -851,14 +862,14 @@ export function registerDbTools(pi) {
|
|
|
851
862
|
deviations: Type.Optional(Type.String({ description: "Deviations from the slice plan, or 'None.'" })),
|
|
852
863
|
knownLimitations: Type.Optional(Type.String({ description: "Known limitations or gaps, or 'None.'" })),
|
|
853
864
|
followUps: Type.Optional(Type.String({ description: "Follow-up work discovered during execution, or 'None.'" })),
|
|
854
|
-
keyFiles: Type.Optional(Type.Array(Type.String(), { description: "Key files created or modified" })),
|
|
855
|
-
keyDecisions: Type.Optional(Type.Array(Type.String(), { description: "Key decisions made during this slice" })),
|
|
856
|
-
patternsEstablished: Type.Optional(Type.Array(Type.String(), { description: "Patterns established by this slice" })),
|
|
857
|
-
observabilitySurfaces: Type.Optional(Type.Array(Type.String(), { description: "Observability surfaces added" })),
|
|
858
|
-
provides: Type.Optional(Type.Array(Type.String(), { description: "What this slice provides to downstream slices" })),
|
|
859
|
-
requirementsSurfaced: Type.Optional(Type.Array(Type.String(), { description: "New requirements surfaced" })),
|
|
860
|
-
drillDownPaths: Type.Optional(Type.Array(Type.String(), { description: "Paths to task summaries for drill-down" })),
|
|
861
|
-
affects: Type.Optional(Type.Array(Type.String(), { description: "Downstream slices affected" })),
|
|
865
|
+
keyFiles: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "Key files created or modified" })),
|
|
866
|
+
keyDecisions: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "Key decisions made during this slice" })),
|
|
867
|
+
patternsEstablished: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "Patterns established by this slice" })),
|
|
868
|
+
observabilitySurfaces: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "Observability surfaces added" })),
|
|
869
|
+
provides: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "What this slice provides to downstream slices" })),
|
|
870
|
+
requirementsSurfaced: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "New requirements surfaced" })),
|
|
871
|
+
drillDownPaths: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "Paths to task summaries for drill-down" })),
|
|
872
|
+
affects: Type.Optional(Type.Union([Type.Array(Type.String()), Type.String()], { description: "Downstream slices affected" })),
|
|
862
873
|
requirementsAdvanced: Type.Optional(Type.Array(Type.Union([
|
|
863
874
|
Type.Object({
|
|
864
875
|
id: Type.String({ description: "Requirement ID" }),
|
|
@@ -932,6 +943,16 @@ export function registerDbTools(pi) {
|
|
|
932
943
|
}
|
|
933
944
|
updateSliceStatus(params.milestoneId, params.sliceId, "skipped");
|
|
934
945
|
invalidateStateCache();
|
|
946
|
+
// Rebuild STATE.md so it reflects the skip immediately (#3477).
|
|
947
|
+
// Without this, /gsd auto reads stale STATE.md and resumes the skipped slice.
|
|
948
|
+
try {
|
|
949
|
+
const basePath = process.cwd();
|
|
950
|
+
const { rebuildState } = await import("../doctor.js");
|
|
951
|
+
await rebuildState(basePath);
|
|
952
|
+
}
|
|
953
|
+
catch (err) {
|
|
954
|
+
logError("tool", `skip_slice rebuildState failed: ${err.message}`, { tool: "gsd_skip_slice" });
|
|
955
|
+
}
|
|
935
956
|
return {
|
|
936
957
|
content: [{ type: "text", text: `Skipped slice ${params.sliceId} (${params.milestoneId}). Reason: ${params.reason ?? "User-directed skip"}. Auto-mode will advance past this slice.` }],
|
|
937
958
|
details: {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// GSD Extension — Notify Interceptor
|
|
2
|
+
// Wraps ctx.ui.notify() in-place to persist every notification through the
|
|
3
|
+
// notification store. Uses a WeakSet to prevent double-wrapping and handle
|
|
4
|
+
// UI context replacement on /reload gracefully.
|
|
5
|
+
import { appendNotification } from "../notification-store.js";
|
|
6
|
+
// Track which ui context objects have been wrapped to prevent double-install.
|
|
7
|
+
// WeakSet allows GC to collect replaced uiContext instances after /reload.
|
|
8
|
+
const _wrappedContexts = new WeakSet();
|
|
9
|
+
/**
|
|
10
|
+
* Install the notify interceptor on a context's UI object.
|
|
11
|
+
* Mutates ctx.ui.notify in place — the original is called after persistence.
|
|
12
|
+
* Safe to call multiple times; no-ops if already installed on the same ui object.
|
|
13
|
+
*/
|
|
14
|
+
export function installNotifyInterceptor(ctx) {
|
|
15
|
+
if (_wrappedContexts.has(ctx.ui))
|
|
16
|
+
return;
|
|
17
|
+
const originalNotify = ctx.ui.notify.bind(ctx.ui);
|
|
18
|
+
ctx.ui.notify = (message, type) => {
|
|
19
|
+
try {
|
|
20
|
+
appendNotification(message, (type ?? "info"), "notify");
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// Non-fatal — never let persistence break the UI
|
|
24
|
+
}
|
|
25
|
+
originalNotify(message, type);
|
|
26
|
+
};
|
|
27
|
+
_wrappedContexts.add(ctx.ui);
|
|
28
|
+
}
|
|
@@ -17,10 +17,12 @@ export function registerQueryTools(pi) {
|
|
|
17
17
|
}),
|
|
18
18
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
19
19
|
try {
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
const {
|
|
23
|
-
|
|
20
|
+
// Open the DB if not already open — safe for read-only use since
|
|
21
|
+
// ensureDbOpen() only creates/migrates when .gsd/ has content (#3644).
|
|
22
|
+
const { ensureDbOpen } = await import("./dynamic-tools.js");
|
|
23
|
+
const dbAvailable = await ensureDbOpen();
|
|
24
|
+
const { getMilestone, getSliceStatusSummary, getSliceTaskCounts, _getAdapter, } = await import("../gsd-db.js");
|
|
25
|
+
if (!dbAvailable) {
|
|
24
26
|
return {
|
|
25
27
|
content: [{ type: "text", text: "Error: GSD database is not available." }],
|
|
26
28
|
details: { operation: "milestone_status", error: "db_unavailable" },
|
|
@@ -31,7 +31,11 @@ function installEpipeGuard() {
|
|
|
31
31
|
if (handleRecoverableExtensionProcessError(err)) {
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
// Log unhandled errors instead of re-throwing — throwing inside an
|
|
35
|
+
// uncaughtException handler is a fatal double-fault in Node.js (#3163).
|
|
36
|
+
process.stderr.write(`[gsd] uncaught extension error (non-fatal): ${err.message}\n`);
|
|
37
|
+
if (err.stack)
|
|
38
|
+
process.stderr.write(`${err.stack}\n`);
|
|
35
39
|
};
|
|
36
40
|
process.on("uncaughtException", _gsdEpipeGuard);
|
|
37
41
|
}
|
|
@@ -18,6 +18,9 @@ import { resetAskUserQuestionsCache } from "../../ask-user-questions.js";
|
|
|
18
18
|
import { recordToolCall as safetyRecordToolCall, recordToolResult as safetyRecordToolResult } from "../safety/evidence-collector.js";
|
|
19
19
|
import { classifyCommand } from "../safety/destructive-guard.js";
|
|
20
20
|
import { logWarning as safetyLogWarning } from "../workflow-logger.js";
|
|
21
|
+
import { installNotifyInterceptor } from "./notify-interceptor.js";
|
|
22
|
+
import { initNotificationStore } from "../notification-store.js";
|
|
23
|
+
import { initNotificationWidget } from "../notification-widget.js";
|
|
21
24
|
// Skip the welcome screen on the very first session_start — cli.ts already
|
|
22
25
|
// printed it before the TUI launched. Only re-print on /clear (subsequent sessions).
|
|
23
26
|
let isFirstSession = true;
|
|
@@ -27,6 +30,9 @@ async function syncServiceTierStatus(ctx) {
|
|
|
27
30
|
}
|
|
28
31
|
export function registerHooks(pi) {
|
|
29
32
|
pi.on("session_start", async (_event, ctx) => {
|
|
33
|
+
initNotificationStore(process.cwd());
|
|
34
|
+
installNotifyInterceptor(ctx);
|
|
35
|
+
initNotificationWidget(ctx);
|
|
30
36
|
resetWriteGateState();
|
|
31
37
|
resetToolCallLoopGuard();
|
|
32
38
|
resetAskUserQuestionsCache();
|
|
@@ -63,6 +69,8 @@ export function registerHooks(pi) {
|
|
|
63
69
|
loadToolApiKeys();
|
|
64
70
|
});
|
|
65
71
|
pi.on("session_switch", async (_event, ctx) => {
|
|
72
|
+
initNotificationStore(process.cwd());
|
|
73
|
+
installNotifyInterceptor(ctx);
|
|
66
74
|
resetWriteGateState();
|
|
67
75
|
resetToolCallLoopGuard();
|
|
68
76
|
resetAskUserQuestionsCache();
|
|
@@ -90,7 +98,10 @@ export function registerHooks(pi) {
|
|
|
90
98
|
}
|
|
91
99
|
});
|
|
92
100
|
pi.on("session_before_compact", async () => {
|
|
93
|
-
|
|
101
|
+
// Only cancel compaction while auto-mode is actively running.
|
|
102
|
+
// Paused auto-mode should allow compaction — the user may be doing
|
|
103
|
+
// interactive work (#3165).
|
|
104
|
+
if (isAutoActive()) {
|
|
94
105
|
return { cancel: true };
|
|
95
106
|
}
|
|
96
107
|
const basePath = process.cwd();
|