gsd-pi 2.63.0 → 2.64.0-dev.9c14bd0
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 +46 -134
- package/dist/cli.js +48 -6
- package/dist/headless-query.js +11 -1
- package/dist/help-text.js +4 -1
- package/dist/onboarding.js +15 -8
- package/dist/resource-loader.js +18 -3
- package/dist/resources/extensions/cmux/index.js +21 -12
- package/dist/resources/extensions/gsd/auto/detect-stuck.js +27 -0
- package/dist/resources/extensions/gsd/auto/finalize-timeout.js +40 -0
- package/dist/resources/extensions/gsd/auto/loop.js +4 -0
- package/dist/resources/extensions/gsd/auto/phases.js +157 -22
- package/dist/resources/extensions/gsd/auto/session.js +12 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +14 -8
- package/dist/resources/extensions/gsd/auto-model-selection.js +32 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +222 -11
- package/dist/resources/extensions/gsd/auto-prompts.js +25 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +15 -7
- package/dist/resources/extensions/gsd/auto-start.js +10 -21
- package/dist/resources/extensions/gsd/auto-timers.js +2 -1
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +17 -0
- package/dist/resources/extensions/gsd/auto-verification.js +138 -1
- package/dist/resources/extensions/gsd/auto-worktree.js +13 -7
- package/dist/resources/extensions/gsd/auto.js +24 -2
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +147 -75
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +13 -0
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +85 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +3 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +32 -1
- package/dist/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.js +54 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +30 -2
- package/dist/resources/extensions/gsd/commands-handlers.js +9 -4
- package/dist/resources/extensions/gsd/constants.js +42 -0
- package/dist/resources/extensions/gsd/db-writer.js +72 -4
- package/dist/resources/extensions/gsd/forensics.js +20 -4
- package/dist/resources/extensions/gsd/gsd-db.js +64 -17
- package/dist/resources/extensions/gsd/guided-flow.js +19 -0
- package/dist/resources/extensions/gsd/metrics.js +27 -1
- package/dist/resources/extensions/gsd/native-git-bridge.js +5 -3
- package/dist/resources/extensions/gsd/post-execution-checks.js +407 -0
- package/dist/resources/extensions/gsd/pre-execution-checks.js +464 -0
- package/dist/resources/extensions/gsd/preferences-types.js +6 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +33 -0
- package/dist/resources/extensions/gsd/preferences.js +11 -2
- package/dist/resources/extensions/gsd/prompt-loader.js +7 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -0
- package/dist/resources/extensions/gsd/prompts/doctor-heal.md +1 -0
- package/dist/resources/extensions/gsd/prompts/forensics.md +2 -0
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +2 -0
- package/dist/resources/extensions/gsd/prompts/system.md +4 -7
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
- package/dist/resources/extensions/gsd/roadmap-mutations.js +1 -1
- package/dist/resources/extensions/gsd/roadmap-slices.js +9 -5
- package/dist/resources/extensions/gsd/safety/content-validator.js +73 -0
- package/dist/resources/extensions/gsd/safety/destructive-guard.js +34 -0
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +109 -0
- package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +83 -0
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +71 -0
- package/dist/resources/extensions/gsd/safety/git-checkpoint.js +91 -0
- package/dist/resources/extensions/gsd/safety/safety-harness.js +64 -0
- package/dist/resources/extensions/gsd/slice-parallel-conflict.js +67 -0
- package/dist/resources/extensions/gsd/slice-parallel-eligibility.js +51 -0
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +378 -0
- package/dist/resources/extensions/gsd/state.js +74 -14
- package/dist/resources/extensions/gsd/status-guards.js +11 -0
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +17 -12
- package/dist/resources/extensions/gsd/tools/complete-slice.js +40 -26
- package/dist/resources/extensions/gsd/tools/complete-task.js +12 -12
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +33 -25
- package/dist/resources/extensions/gsd/tools/plan-slice.js +5 -8
- package/dist/resources/extensions/gsd/verification-evidence.js +18 -0
- package/dist/resources/extensions/gsd/workflow-projections.js +21 -5
- package/dist/resources/extensions/gsd/worktree-manager.js +82 -29
- package/dist/resources/extensions/gsd/worktree-resolver.js +4 -3
- package/dist/resources/extensions/mcp-client/auth.js +101 -0
- package/dist/resources/extensions/mcp-client/index.js +10 -1
- package/dist/resources/extensions/ollama/index.js +28 -22
- package/dist/resources/extensions/ollama/model-capabilities.js +37 -34
- package/dist/resources/extensions/ollama/ndjson-stream.js +54 -0
- package/dist/resources/extensions/ollama/ollama-chat-provider.js +380 -0
- package/dist/resources/extensions/ollama/ollama-client.js +23 -32
- package/dist/resources/extensions/ollama/ollama-discovery.js +2 -7
- package/dist/resources/extensions/ollama/ollama-tool.js +62 -0
- package/dist/resources/extensions/ollama/thinking-parser.js +104 -0
- package/dist/update-cmd.js +4 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
- 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 +4 -4
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.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.js.nft.json +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.js.nft.json +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 +15 -15
- package/dist/web/standalone/.next/server/chunks/6897.js +12 -0
- package/dist/web/standalone/.next/server/chunks/7471.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/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-0c485498795110d6.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/dist/welcome-screen.js +1 -1
- package/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.d.ts +8 -0
- package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +50 -0
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.test.ts +221 -5
- package/packages/pi-agent-core/src/agent-loop.ts +53 -0
- package/packages/pi-ai/dist/types.d.ts +16 -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/src/types.ts +18 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +50 -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 +41 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +7 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +31 -4
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.test.js +28 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/provider-registration.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/provider-registration.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/provider-registration.test.js +46 -0
- package/packages/pi-coding-agent/dist/core/extensions/provider-registration.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +12 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +3 -3
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +23 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.js +80 -56
- package/packages/pi-coding-agent/dist/core/resource-loader.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/package.json +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +53 -0
- package/packages/pi-coding-agent/src/core/auth-storage.ts +66 -1
- package/packages/pi-coding-agent/src/core/extensions/loader.test.ts +39 -1
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +34 -4
- package/packages/pi-coding-agent/src/core/extensions/provider-registration.test.ts +81 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +14 -0
- package/packages/pi-coding-agent/src/core/model-resolver.ts +3 -3
- package/packages/pi-coding-agent/src/core/resource-loader.ts +89 -56
- package/packages/pi-coding-agent/src/core/sdk.ts +10 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/cmux/index.ts +18 -12
- package/src/resources/extensions/gsd/auto/detect-stuck.ts +27 -0
- package/src/resources/extensions/gsd/auto/finalize-timeout.ts +46 -0
- package/src/resources/extensions/gsd/auto/loop.ts +5 -0
- package/src/resources/extensions/gsd/auto/phases.ts +194 -33
- package/src/resources/extensions/gsd/auto/session.ts +14 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +16 -7
- package/src/resources/extensions/gsd/auto-model-selection.ts +36 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +263 -12
- package/src/resources/extensions/gsd/auto-prompts.ts +21 -0
- package/src/resources/extensions/gsd/auto-recovery.ts +9 -8
- package/src/resources/extensions/gsd/auto-start.ts +11 -20
- package/src/resources/extensions/gsd/auto-timers.ts +2 -1
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +19 -0
- package/src/resources/extensions/gsd/auto-verification.ts +190 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +14 -6
- package/src/resources/extensions/gsd/auto.ts +26 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +160 -88
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +15 -0
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +98 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +4 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +36 -1
- package/src/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.ts +57 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +31 -2
- package/src/resources/extensions/gsd/commands-handlers.ts +10 -4
- package/src/resources/extensions/gsd/constants.ts +44 -0
- package/src/resources/extensions/gsd/db-writer.ts +78 -4
- package/src/resources/extensions/gsd/forensics.ts +21 -5
- package/src/resources/extensions/gsd/gsd-db.ts +64 -17
- package/src/resources/extensions/gsd/guided-flow.ts +22 -0
- package/src/resources/extensions/gsd/metrics.ts +28 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +5 -3
- package/src/resources/extensions/gsd/post-execution-checks.ts +539 -0
- package/src/resources/extensions/gsd/pre-execution-checks.ts +573 -0
- package/src/resources/extensions/gsd/preferences-types.ts +44 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +33 -0
- package/src/resources/extensions/gsd/preferences.ts +13 -2
- package/src/resources/extensions/gsd/prompt-loader.ts +8 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -0
- package/src/resources/extensions/gsd/prompts/doctor-heal.md +1 -0
- package/src/resources/extensions/gsd/prompts/forensics.md +2 -0
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +2 -0
- package/src/resources/extensions/gsd/prompts/system.md +4 -7
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
- package/src/resources/extensions/gsd/roadmap-mutations.ts +1 -1
- package/src/resources/extensions/gsd/roadmap-slices.ts +10 -5
- package/src/resources/extensions/gsd/safety/content-validator.ts +98 -0
- package/src/resources/extensions/gsd/safety/destructive-guard.ts +49 -0
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +151 -0
- package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +120 -0
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +108 -0
- package/src/resources/extensions/gsd/safety/git-checkpoint.ts +106 -0
- package/src/resources/extensions/gsd/safety/safety-harness.ts +105 -0
- package/src/resources/extensions/gsd/slice-parallel-conflict.ts +86 -0
- package/src/resources/extensions/gsd/slice-parallel-eligibility.ts +73 -0
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +477 -0
- package/src/resources/extensions/gsd/state.ts +67 -12
- package/src/resources/extensions/gsd/status-guards.ts +13 -0
- package/src/resources/extensions/gsd/tests/artifact-corruption-2630.test.ts +288 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +34 -13
- package/src/resources/extensions/gsd/tests/auto-start-time-persistence.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/cmux.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/complete-slice-string-coercion.test.ts +211 -0
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +109 -0
- package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +13 -9
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +134 -0
- package/src/resources/extensions/gsd/tests/deferred-slice-dispatch.test.ts +203 -0
- package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +130 -0
- package/src/resources/extensions/gsd/tests/doctor-fix-flag.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/enhanced-verification-integration.test.ts +526 -0
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/forensics-stuck-loops.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/git-checkpoint.test.ts +94 -0
- package/src/resources/extensions/gsd/tests/insert-slice-no-wipe.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +27 -7
- package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/metrics.test.ts +116 -1
- package/src/resources/extensions/gsd/tests/milestone-status-tool.test.ts +201 -0
- package/src/resources/extensions/gsd/tests/plan-milestone-title.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +82 -18
- 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-execution-checks.test.ts +999 -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/preferences.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/shared-wal.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/slice-parallel-conflict.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/slice-parallel-eligibility.test.ts +95 -0
- package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +349 -0
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +35 -2
- package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +73 -0
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +148 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +34 -20
- package/src/resources/extensions/gsd/tools/complete-slice.ts +41 -26
- package/src/resources/extensions/gsd/tools/complete-task.ts +12 -12
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +55 -30
- package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -8
- package/src/resources/extensions/gsd/types.ts +44 -22
- package/src/resources/extensions/gsd/verification-evidence.ts +68 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +2 -1
- package/src/resources/extensions/gsd/workflow-projections.ts +23 -5
- package/src/resources/extensions/gsd/worktree-manager.ts +76 -28
- package/src/resources/extensions/gsd/worktree-resolver.ts +4 -3
- package/src/resources/extensions/mcp-client/auth.ts +149 -0
- package/src/resources/extensions/mcp-client/index.ts +16 -1
- package/src/resources/extensions/ollama/index.ts +26 -25
- package/src/resources/extensions/ollama/model-capabilities.ts +41 -34
- package/src/resources/extensions/ollama/ndjson-stream.ts +63 -0
- package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +20 -0
- package/src/resources/extensions/ollama/ollama-chat-provider.ts +459 -0
- package/src/resources/extensions/ollama/ollama-client.ts +30 -30
- package/src/resources/extensions/ollama/ollama-discovery.ts +5 -8
- package/src/resources/extensions/ollama/ollama-tool.ts +69 -0
- package/src/resources/extensions/ollama/tests/ollama-chat-provider-stream.test.ts +82 -0
- package/src/resources/extensions/ollama/tests/ollama-discovery.test.ts +0 -27
- package/src/resources/extensions/ollama/thinking-parser.ts +116 -0
- package/src/resources/extensions/ollama/types.ts +23 -0
- package/dist/web/standalone/.next/server/chunks/2229.js +0 -12
- package/dist/web/standalone/.next/static/chunks/app/page-62be3b5fa91e4c8f.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
- /package/dist/web/standalone/.next/static/{5FLUBNdqolRyyehCyChPd → SoxM61WC_ia7R2gk4VMpJ}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{5FLUBNdqolRyyehCyChPd → SoxM61WC_ia7R2gk4VMpJ}/_ssgManifest.js +0 -0
|
@@ -14,12 +14,12 @@ import { deriveState } from "./state.js";
|
|
|
14
14
|
import { logWarning, logError } from "./workflow-logger.js";
|
|
15
15
|
import { loadFile, parseSummary, resolveAllOverrides } from "./files.js";
|
|
16
16
|
import { loadPrompt } from "./prompt-loader.js";
|
|
17
|
-
import { resolveSliceFile, resolveTaskFile, resolveMilestoneFile, resolveTasksDir, buildTaskFileName, } from "./paths.js";
|
|
17
|
+
import { resolveSliceFile, resolveSlicePath, resolveTaskFile, resolveMilestoneFile, resolveTasksDir, buildTaskFileName, } from "./paths.js";
|
|
18
18
|
import { invalidateAllCaches } from "./cache.js";
|
|
19
19
|
import { parseUnitId } from "./unit-id.js";
|
|
20
20
|
import { closeoutUnit } from "./auto-unit-closeout.js";
|
|
21
21
|
import { autoCommitCurrentBranch, } from "./worktree.js";
|
|
22
|
-
import { verifyExpectedArtifact, resolveExpectedArtifactPath, diagnoseExpectedArtifact, } from "./auto-recovery.js";
|
|
22
|
+
import { verifyExpectedArtifact, resolveExpectedArtifactPath, writeBlockerPlaceholder, diagnoseExpectedArtifact, } from "./auto-recovery.js";
|
|
23
23
|
import { regenerateIfMissing } from "./workflow-projections.js";
|
|
24
24
|
import { syncStateToProjectRoot } from "./auto-worktree.js";
|
|
25
25
|
import { isDbAvailable, getTask, getSlice, getMilestone, updateTaskStatus, _getAdapter } from "./gsd-db.js";
|
|
@@ -29,6 +29,19 @@ import { checkPostUnitHooks, isRetryPending, consumeRetryTrigger, persistHookSta
|
|
|
29
29
|
import { hasPendingCaptures, loadPendingCaptures, revertExecutorResolvedCaptures } from "./captures.js";
|
|
30
30
|
import { debugLog } from "./debug-logger.js";
|
|
31
31
|
import { runSafely } from "./auto-utils.js";
|
|
32
|
+
import { getEvidence } from "./safety/evidence-collector.js";
|
|
33
|
+
import { validateFileChanges } from "./safety/file-change-validator.js";
|
|
34
|
+
// crossReferenceEvidence available for future use when verification_evidence is stored in DB
|
|
35
|
+
// import { crossReferenceEvidence, type ClaimedEvidence } from "./safety/evidence-cross-ref.js";
|
|
36
|
+
import { validateContent } from "./safety/content-validator.js";
|
|
37
|
+
import { resolveSafetyHarnessConfig } from "./safety/safety-harness.js";
|
|
38
|
+
import { resolveExpectedArtifactPath as resolveArtifactForContent } from "./auto-artifact-paths.js";
|
|
39
|
+
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
40
|
+
import { getSliceTasks } from "./gsd-db.js";
|
|
41
|
+
import { runPreExecutionChecks } from "./pre-execution-checks.js";
|
|
42
|
+
import { writePreExecutionEvidence } from "./verification-evidence.js";
|
|
43
|
+
/** Maximum verification retry attempts before escalating to blocker placeholder (#2653). */
|
|
44
|
+
const MAX_VERIFICATION_RETRIES = 3;
|
|
32
45
|
/** Enqueue a sidecar item (hook, triage, or quick-task) for the main loop to
|
|
33
46
|
* drain via runUnit. Logs the enqueue event and notifies the UI. */
|
|
34
47
|
function enqueueSidecar(s, ctx, entry, debugExtra, notification) {
|
|
@@ -339,6 +352,78 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
339
352
|
catch (e) {
|
|
340
353
|
debugLog("postUnit", { phase: "rogue-detection", error: String(e) });
|
|
341
354
|
}
|
|
355
|
+
// ── Safety harness: post-unit validation ──
|
|
356
|
+
try {
|
|
357
|
+
const { loadEffectiveGSDPreferences } = await import("./preferences.js");
|
|
358
|
+
const prefs = loadEffectiveGSDPreferences()?.preferences;
|
|
359
|
+
const safetyConfig = resolveSafetyHarnessConfig(prefs?.safety_harness);
|
|
360
|
+
if (safetyConfig.enabled) {
|
|
361
|
+
const { milestone: sMid, slice: sSid, task: sTid } = parseUnitId(s.currentUnit.id);
|
|
362
|
+
// File change validation (execute-task only, after auto-commit)
|
|
363
|
+
if (safetyConfig.file_change_validation && s.currentUnit.type === "execute-task" && sMid && sSid && sTid && isDbAvailable()) {
|
|
364
|
+
try {
|
|
365
|
+
const taskRow = getTask(sMid, sSid, sTid);
|
|
366
|
+
if (taskRow) {
|
|
367
|
+
const expectedOutput = taskRow.expected_output ?? [];
|
|
368
|
+
const plannedFiles = taskRow.files ?? [];
|
|
369
|
+
const audit = validateFileChanges(s.basePath, expectedOutput, plannedFiles);
|
|
370
|
+
if (audit && audit.violations.length > 0) {
|
|
371
|
+
const warnings = audit.violations.filter(v => v.severity === "warning");
|
|
372
|
+
for (const v of warnings) {
|
|
373
|
+
logWarning("safety", `file-change: ${v.file} — ${v.reason}`);
|
|
374
|
+
}
|
|
375
|
+
if (warnings.length > 0) {
|
|
376
|
+
ctx.ui.notify(`Safety: ${warnings.length} unexpected file change(s) outside task plan`, "warning");
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
catch (e) {
|
|
382
|
+
debugLog("postUnit", { phase: "safety-file-change", error: String(e) });
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
// Evidence cross-reference (execute-task only)
|
|
386
|
+
// Verification evidence is passed via the complete-task tool call and
|
|
387
|
+
// stored in the SUMMARY.md on disk — not available as structured data
|
|
388
|
+
// in the DB. The evidence collector tracks actual bash tool calls, so
|
|
389
|
+
// we can still detect units that claimed success but ran no commands.
|
|
390
|
+
if (safetyConfig.evidence_cross_reference && s.currentUnit.type === "execute-task") {
|
|
391
|
+
try {
|
|
392
|
+
const actual = getEvidence();
|
|
393
|
+
const bashCalls = actual.filter(e => e.kind === "bash");
|
|
394
|
+
// If the task is marked complete but zero bash commands were run,
|
|
395
|
+
// it's suspicious — the LLM may have fabricated results.
|
|
396
|
+
if (sMid && sSid && sTid && isDbAvailable()) {
|
|
397
|
+
const taskRow = getTask(sMid, sSid, sTid);
|
|
398
|
+
if (taskRow?.status === "complete" && taskRow.verify && bashCalls.length === 0) {
|
|
399
|
+
logWarning("safety", "task marked complete with verification commands but no bash calls were executed");
|
|
400
|
+
ctx.ui.notify(`Safety: task ${sTid} has verification commands but no bash calls were recorded`, "warning");
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
catch (e) {
|
|
405
|
+
debugLog("postUnit", { phase: "safety-evidence-xref", error: String(e) });
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
// Content validation (plan-slice, plan-milestone)
|
|
409
|
+
if (safetyConfig.content_validation) {
|
|
410
|
+
try {
|
|
411
|
+
const artifactPath = resolveArtifactForContent(s.currentUnit.type, s.currentUnit.id, s.basePath);
|
|
412
|
+
const contentViolations = validateContent(s.currentUnit.type, artifactPath);
|
|
413
|
+
for (const v of contentViolations) {
|
|
414
|
+
logWarning("safety", `content: ${v.reason}`);
|
|
415
|
+
ctx.ui.notify(`Content validation: ${v.reason}`, "warning");
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
catch (e) {
|
|
419
|
+
debugLog("postUnit", { phase: "safety-content-validation", error: String(e) });
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
catch (e) {
|
|
425
|
+
debugLog("postUnit", { phase: "safety-harness", error: String(e) });
|
|
426
|
+
}
|
|
342
427
|
// Artifact verification
|
|
343
428
|
let triggerArtifactVerified = false;
|
|
344
429
|
if (!s.currentUnit.type.startsWith("hook/")) {
|
|
@@ -374,6 +459,8 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
374
459
|
// When artifact verification fails for a unit type that has a known expected
|
|
375
460
|
// artifact, return "retry" so the caller re-dispatches with failure context
|
|
376
461
|
// instead of blindly re-dispatching the same unit (#1571).
|
|
462
|
+
// After MAX_VERIFICATION_RETRIES, escalate to writeBlockerPlaceholder so the
|
|
463
|
+
// pipeline can advance instead of looping forever (#2653).
|
|
377
464
|
//
|
|
378
465
|
// HOWEVER, if the DB is unavailable (db_unavailable), the artifact was never
|
|
379
466
|
// written because the completion tool failed at the infra level. Retrying
|
|
@@ -387,20 +474,51 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
387
474
|
ctx.ui.notify(`Artifact missing for ${s.currentUnit.type} ${s.currentUnit.id} — DB unavailable, skipping retry.${dbSkipDiag ? ` Expected: ${dbSkipDiag}` : ""}`, "error");
|
|
388
475
|
}
|
|
389
476
|
else if (!triggerArtifactVerified) {
|
|
477
|
+
// #2883: If the artifact is missing because the tool invocation itself
|
|
478
|
+
// failed (malformed/truncated JSON arguments), retrying will produce the
|
|
479
|
+
// same failure. Pause auto-mode instead of entering a stuck retry loop.
|
|
480
|
+
if (s.lastToolInvocationError) {
|
|
481
|
+
const errMsg = `Tool invocation failed for ${s.currentUnit.type}: ${s.lastToolInvocationError}. Structured argument generation failed — pausing auto-mode.`;
|
|
482
|
+
debugLog("postUnit", { phase: "tool-invocation-error-pause", unitType: s.currentUnit.type, unitId: s.currentUnit.id, error: s.lastToolInvocationError });
|
|
483
|
+
ctx.ui.notify(errMsg, "error");
|
|
484
|
+
s.lastToolInvocationError = null;
|
|
485
|
+
await pauseAuto(ctx, pi);
|
|
486
|
+
return "dispatched";
|
|
487
|
+
}
|
|
390
488
|
const hasExpectedArtifact = resolveExpectedArtifactPath(s.currentUnit.type, s.currentUnit.id, s.basePath) !== null;
|
|
391
489
|
if (hasExpectedArtifact) {
|
|
392
490
|
const retryKey = `${s.currentUnit.type}:${s.currentUnit.id}`;
|
|
393
491
|
const attempt = (s.verificationRetryCount.get(retryKey) ?? 0) + 1;
|
|
394
492
|
s.verificationRetryCount.set(retryKey, attempt);
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
493
|
+
if (attempt > MAX_VERIFICATION_RETRIES) {
|
|
494
|
+
// Retries exhausted — write a blocker placeholder so the pipeline
|
|
495
|
+
// can advance past this stuck unit (#2653).
|
|
496
|
+
debugLog("postUnit", {
|
|
497
|
+
phase: "artifact-verify-escalate",
|
|
498
|
+
unitType: s.currentUnit.type,
|
|
499
|
+
unitId: s.currentUnit.id,
|
|
500
|
+
attempt,
|
|
501
|
+
maxRetries: MAX_VERIFICATION_RETRIES,
|
|
502
|
+
});
|
|
503
|
+
const reason = `Artifact verification failed after ${MAX_VERIFICATION_RETRIES} retries for ${s.currentUnit.type} "${s.currentUnit.id}".`;
|
|
504
|
+
writeBlockerPlaceholder(s.currentUnit.type, s.currentUnit.id, s.basePath, reason);
|
|
505
|
+
ctx.ui.notify(`${s.currentUnit.type} ${s.currentUnit.id} — verification retries exhausted (${MAX_VERIFICATION_RETRIES}), wrote blocker placeholder to advance pipeline`, "warning");
|
|
506
|
+
// Reset retry count and fall through to "continue" so the loop
|
|
507
|
+
// re-derives state with the placeholder in place.
|
|
508
|
+
s.verificationRetryCount.delete(retryKey);
|
|
509
|
+
s.pendingVerificationRetry = null;
|
|
510
|
+
// Do NOT return "retry" — fall through to "continue" below.
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
513
|
+
s.pendingVerificationRetry = {
|
|
514
|
+
unitId: s.currentUnit.id,
|
|
515
|
+
failureContext: `Artifact verification failed: expected artifact for ${s.currentUnit.type} "${s.currentUnit.id}" was not found on disk after unit execution (attempt ${attempt}).`,
|
|
516
|
+
attempt,
|
|
517
|
+
};
|
|
518
|
+
debugLog("postUnit", { phase: "artifact-verify-retry", unitType: s.currentUnit.type, unitId: s.currentUnit.id, attempt });
|
|
519
|
+
ctx.ui.notify(`Artifact missing for ${s.currentUnit.type} ${s.currentUnit.id} — retrying (attempt ${attempt})`, "warning");
|
|
520
|
+
return "retry";
|
|
521
|
+
}
|
|
404
522
|
}
|
|
405
523
|
}
|
|
406
524
|
}
|
|
@@ -520,6 +638,99 @@ export async function postUnitPostVerification(pctx) {
|
|
|
520
638
|
debugLog("postUnit", { phase: "capture-protection-error", error: String(e) });
|
|
521
639
|
}
|
|
522
640
|
}
|
|
641
|
+
// ── Pre-execution checks (after plan-slice completes) ──
|
|
642
|
+
if (s.currentUnit &&
|
|
643
|
+
s.currentUnit.type === "plan-slice") {
|
|
644
|
+
let preExecPauseNeeded = false;
|
|
645
|
+
await runSafely("postUnitPostVerification", "pre-execution-checks", async () => {
|
|
646
|
+
try {
|
|
647
|
+
// Check preferences — respect enhanced_verification and enhanced_verification_pre
|
|
648
|
+
const prefs = loadEffectiveGSDPreferences()?.preferences;
|
|
649
|
+
const enhancedEnabled = prefs?.enhanced_verification !== false; // default true
|
|
650
|
+
const preEnabled = prefs?.enhanced_verification_pre !== false; // default true
|
|
651
|
+
if (!enhancedEnabled || !preEnabled) {
|
|
652
|
+
debugLog("postUnitPostVerification", {
|
|
653
|
+
phase: "pre-execution-checks",
|
|
654
|
+
skipped: true,
|
|
655
|
+
reason: "disabled by preferences",
|
|
656
|
+
});
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
// Parse the unit ID to get milestone/slice IDs
|
|
660
|
+
const { milestone: mid, slice: sid } = parseUnitId(s.currentUnit.id);
|
|
661
|
+
if (!mid || !sid) {
|
|
662
|
+
debugLog("postUnitPostVerification", {
|
|
663
|
+
phase: "pre-execution-checks",
|
|
664
|
+
skipped: true,
|
|
665
|
+
reason: "could not parse milestone/slice from unit ID",
|
|
666
|
+
});
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
// Get tasks for this slice from DB
|
|
670
|
+
const tasks = getSliceTasks(mid, sid);
|
|
671
|
+
if (tasks.length === 0) {
|
|
672
|
+
debugLog("postUnitPostVerification", {
|
|
673
|
+
phase: "pre-execution-checks",
|
|
674
|
+
skipped: true,
|
|
675
|
+
reason: "no tasks found for slice",
|
|
676
|
+
});
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
// Run pre-execution checks
|
|
680
|
+
const result = await runPreExecutionChecks(tasks, s.basePath);
|
|
681
|
+
// Log summary to stderr in existing verification output format
|
|
682
|
+
const emoji = result.status === "pass" ? "✅" : result.status === "warn" ? "⚠️" : "❌";
|
|
683
|
+
process.stderr.write(`gsd-pre-exec: ${emoji} Pre-execution checks ${result.status} for ${mid}/${sid} (${result.durationMs}ms)\n`);
|
|
684
|
+
// Log individual check results
|
|
685
|
+
for (const check of result.checks) {
|
|
686
|
+
const checkEmoji = check.passed ? "✓" : check.blocking ? "✗" : "⚠";
|
|
687
|
+
process.stderr.write(`gsd-pre-exec: ${checkEmoji} [${check.category}] ${check.target}: ${check.message}\n`);
|
|
688
|
+
}
|
|
689
|
+
// Write evidence JSON to slice artifacts directory
|
|
690
|
+
const slicePath = resolveSlicePath(s.basePath, mid, sid);
|
|
691
|
+
if (slicePath) {
|
|
692
|
+
writePreExecutionEvidence(result, slicePath, mid, sid);
|
|
693
|
+
}
|
|
694
|
+
// Notify UI
|
|
695
|
+
if (result.status === "fail") {
|
|
696
|
+
const blockingCount = result.checks.filter(c => !c.passed && c.blocking).length;
|
|
697
|
+
ctx.ui.notify(`Pre-execution checks failed: ${blockingCount} blocking issue${blockingCount === 1 ? "" : "s"} found`, "error");
|
|
698
|
+
preExecPauseNeeded = true;
|
|
699
|
+
}
|
|
700
|
+
else if (result.status === "warn") {
|
|
701
|
+
ctx.ui.notify(`Pre-execution checks passed with warnings`, "warning");
|
|
702
|
+
// Strict mode: treat warnings as blocking
|
|
703
|
+
if (prefs?.enhanced_verification_strict === true) {
|
|
704
|
+
preExecPauseNeeded = true;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
debugLog("postUnitPostVerification", {
|
|
708
|
+
phase: "pre-execution-checks",
|
|
709
|
+
status: result.status,
|
|
710
|
+
checkCount: result.checks.length,
|
|
711
|
+
durationMs: result.durationMs,
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
catch (preExecError) {
|
|
715
|
+
// Fail-closed: if runPreExecutionChecks throws, pause auto-mode instead of silently continuing
|
|
716
|
+
const errorMessage = preExecError instanceof Error ? preExecError.message : String(preExecError);
|
|
717
|
+
debugLog("postUnitPostVerification", {
|
|
718
|
+
phase: "pre-execution-checks",
|
|
719
|
+
error: errorMessage,
|
|
720
|
+
failClosed: true,
|
|
721
|
+
});
|
|
722
|
+
logError("engine", `gsd-pre-exec: Pre-execution checks threw an error: ${errorMessage}`);
|
|
723
|
+
ctx.ui.notify(`Pre-execution checks error: ${errorMessage} — pausing for human review`, "error");
|
|
724
|
+
preExecPauseNeeded = true;
|
|
725
|
+
}
|
|
726
|
+
});
|
|
727
|
+
// Check for blocking failures after runSafely completes
|
|
728
|
+
if (preExecPauseNeeded) {
|
|
729
|
+
debugLog("postUnitPostVerification", { phase: "pre-execution-checks", pausing: true, reason: "blocking failures detected" });
|
|
730
|
+
await pauseAuto(ctx, pi);
|
|
731
|
+
return "stopped";
|
|
732
|
+
}
|
|
733
|
+
}
|
|
523
734
|
// ── Triage check ──
|
|
524
735
|
if (!s.stepMode &&
|
|
525
736
|
s.currentUnit &&
|
|
@@ -880,11 +880,16 @@ export async function buildResearchSlicePrompt(mid, _midTitle, sid, sTitle, base
|
|
|
880
880
|
const contextRel = relMilestoneFile(base, mid, "CONTEXT");
|
|
881
881
|
const milestoneResearchPath = resolveMilestoneFile(base, mid, "RESEARCH");
|
|
882
882
|
const milestoneResearchRel = relMilestoneFile(base, mid, "RESEARCH");
|
|
883
|
+
const sliceContextPath = resolveSliceFile(base, mid, sid, "CONTEXT");
|
|
884
|
+
const sliceContextRel = relSliceFile(base, mid, sid, "CONTEXT");
|
|
883
885
|
const inlined = [];
|
|
884
886
|
inlined.push(await inlineFile(roadmapPath, roadmapRel, "Milestone Roadmap"));
|
|
885
887
|
const contextInline = await inlineFileOptional(contextPath, contextRel, "Milestone Context");
|
|
886
888
|
if (contextInline)
|
|
887
889
|
inlined.push(contextInline);
|
|
890
|
+
const sliceCtxInline = await inlineFileOptional(sliceContextPath, sliceContextRel, "Slice Context (from discussion)");
|
|
891
|
+
if (sliceCtxInline)
|
|
892
|
+
inlined.push(sliceCtxInline);
|
|
888
893
|
const researchInline = await inlineFileOptional(milestoneResearchPath, milestoneResearchRel, "Milestone Research");
|
|
889
894
|
if (researchInline)
|
|
890
895
|
inlined.push(researchInline);
|
|
@@ -931,12 +936,17 @@ export async function buildPlanSlicePrompt(mid, _midTitle, sid, sTitle, base, le
|
|
|
931
936
|
const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
|
|
932
937
|
const researchPath = resolveSliceFile(base, mid, sid, "RESEARCH");
|
|
933
938
|
const researchRel = relSliceFile(base, mid, sid, "RESEARCH");
|
|
939
|
+
const sliceContextPath = resolveSliceFile(base, mid, sid, "CONTEXT");
|
|
940
|
+
const sliceContextRel = relSliceFile(base, mid, sid, "CONTEXT");
|
|
934
941
|
const inlined = [];
|
|
935
942
|
// Inject phase handoff anchor from research phase (if available)
|
|
936
943
|
const researchSliceAnchor = readPhaseAnchor(base, mid, "research-slice");
|
|
937
944
|
if (researchSliceAnchor)
|
|
938
945
|
inlined.push(formatAnchorForPrompt(researchSliceAnchor));
|
|
939
946
|
inlined.push(await inlineFile(roadmapPath, roadmapRel, "Milestone Roadmap"));
|
|
947
|
+
const sliceCtxInline = await inlineFileOptional(sliceContextPath, sliceContextRel, "Slice Context (from discussion)");
|
|
948
|
+
if (sliceCtxInline)
|
|
949
|
+
inlined.push(sliceCtxInline);
|
|
940
950
|
const researchInline = await inlineFileOptional(researchPath, researchRel, "Slice Research");
|
|
941
951
|
if (researchInline)
|
|
942
952
|
inlined.push(researchInline);
|
|
@@ -1097,8 +1107,13 @@ export async function buildCompleteSlicePrompt(mid, _midTitle, sid, sTitle, base
|
|
|
1097
1107
|
const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
|
|
1098
1108
|
const slicePlanPath = resolveSliceFile(base, mid, sid, "PLAN");
|
|
1099
1109
|
const slicePlanRel = relSliceFile(base, mid, sid, "PLAN");
|
|
1110
|
+
const sliceContextPath = resolveSliceFile(base, mid, sid, "CONTEXT");
|
|
1111
|
+
const sliceContextRel = relSliceFile(base, mid, sid, "CONTEXT");
|
|
1100
1112
|
const inlined = [];
|
|
1101
1113
|
inlined.push(await inlineFile(roadmapPath, roadmapRel, "Milestone Roadmap"));
|
|
1114
|
+
const sliceCtxInline = await inlineFileOptional(sliceContextPath, sliceContextRel, "Slice Context (from discussion)");
|
|
1115
|
+
if (sliceCtxInline)
|
|
1116
|
+
inlined.push(sliceCtxInline);
|
|
1102
1117
|
inlined.push(await inlineFile(slicePlanPath, slicePlanRel, "Slice Plan"));
|
|
1103
1118
|
if (inlineLevel !== "minimal") {
|
|
1104
1119
|
const requirementsInline = await inlineRequirementsFromDb(base, sid, inlineLevel);
|
|
@@ -1351,8 +1366,13 @@ export async function buildReplanSlicePrompt(mid, midTitle, sid, sTitle, base) {
|
|
|
1351
1366
|
const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
|
|
1352
1367
|
const slicePlanPath = resolveSliceFile(base, mid, sid, "PLAN");
|
|
1353
1368
|
const slicePlanRel = relSliceFile(base, mid, sid, "PLAN");
|
|
1369
|
+
const sliceContextPath = resolveSliceFile(base, mid, sid, "CONTEXT");
|
|
1370
|
+
const sliceContextRel = relSliceFile(base, mid, sid, "CONTEXT");
|
|
1354
1371
|
const inlined = [];
|
|
1355
1372
|
inlined.push(await inlineFile(roadmapPath, roadmapRel, "Milestone Roadmap"));
|
|
1373
|
+
const sliceCtxInline = await inlineFileOptional(sliceContextPath, sliceContextRel, "Slice Context (from discussion)");
|
|
1374
|
+
if (sliceCtxInline)
|
|
1375
|
+
inlined.push(sliceCtxInline);
|
|
1356
1376
|
inlined.push(await inlineFile(slicePlanPath, slicePlanRel, "Current Slice Plan"));
|
|
1357
1377
|
// Find the blocker task summary — the completed task with blocker_discovered: true
|
|
1358
1378
|
let blockerTaskId = "";
|
|
@@ -1454,8 +1474,13 @@ export async function buildReassessRoadmapPrompt(mid, midTitle, completedSliceId
|
|
|
1454
1474
|
const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
|
|
1455
1475
|
const summaryPath = resolveSliceFile(base, mid, completedSliceId, "SUMMARY");
|
|
1456
1476
|
const summaryRel = relSliceFile(base, mid, completedSliceId, "SUMMARY");
|
|
1477
|
+
const sliceContextPath = resolveSliceFile(base, mid, completedSliceId, "CONTEXT");
|
|
1478
|
+
const sliceContextRel = relSliceFile(base, mid, completedSliceId, "CONTEXT");
|
|
1457
1479
|
const inlined = [];
|
|
1458
1480
|
inlined.push(await inlineFile(roadmapPath, roadmapRel, "Current Roadmap"));
|
|
1481
|
+
const sliceCtxInline = await inlineFileOptional(sliceContextPath, sliceContextRel, "Slice Context (from discussion)");
|
|
1482
|
+
if (sliceCtxInline)
|
|
1483
|
+
inlined.push(sliceCtxInline);
|
|
1459
1484
|
inlined.push(await inlineFile(summaryPath, summaryRel, `${completedSliceId} Summary`));
|
|
1460
1485
|
if (inlineLevel !== "minimal") {
|
|
1461
1486
|
const projectInline = await inlineProjectFromDb(base);
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { parseUnitId } from "./unit-id.js";
|
|
10
10
|
import { clearParseCache } from "./files.js";
|
|
11
11
|
import { parseRoadmap as parseLegacyRoadmap, parsePlan as parseLegacyPlan } from "./parsers-legacy.js";
|
|
12
|
-
import { isDbAvailable, getTask, getSlice, getSliceTasks, updateTaskStatus } from "./gsd-db.js";
|
|
12
|
+
import { isDbAvailable, getTask, getSlice, getSliceTasks, updateTaskStatus, updateSliceStatus } from "./gsd-db.js";
|
|
13
13
|
import { isValidationTerminal } from "./state.js";
|
|
14
14
|
import { getErrorMessage } from "./error-utils.js";
|
|
15
15
|
import { logWarning, logError } from "./workflow-logger.js";
|
|
@@ -377,17 +377,25 @@ export function writeBlockerPlaceholder(unitType, unitId, base, reason) {
|
|
|
377
377
|
`Review and replace this file before relying on downstream artifacts.`,
|
|
378
378
|
].join("\n");
|
|
379
379
|
writeFileSync(absPath, content, "utf-8");
|
|
380
|
-
// Mark the task as complete in the DB so verifyExpectedArtifact passes.
|
|
380
|
+
// Mark the task/slice as complete in the DB so verifyExpectedArtifact passes.
|
|
381
381
|
// Without this, the DB status stays "pending" and the dispatch loop
|
|
382
|
-
// re-derives the same
|
|
383
|
-
if (
|
|
382
|
+
// re-derives the same unit indefinitely (#2531, #2653).
|
|
383
|
+
if (isDbAvailable()) {
|
|
384
384
|
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
|
385
|
-
if (mid && sid && tid) {
|
|
385
|
+
if (unitType === "execute-task" && mid && sid && tid) {
|
|
386
386
|
try {
|
|
387
387
|
updateTaskStatus(mid, sid, tid, "complete", new Date().toISOString());
|
|
388
388
|
}
|
|
389
|
-
catch (
|
|
390
|
-
|
|
389
|
+
catch (e) {
|
|
390
|
+
logWarning("recovery", `updateTaskStatus failed during context exhaustion: ${e instanceof Error ? e.message : String(e)}`);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (unitType === "complete-slice" && mid && sid) {
|
|
394
|
+
try {
|
|
395
|
+
updateSliceStatus(mid, sid, "complete", new Date().toISOString());
|
|
396
|
+
}
|
|
397
|
+
catch (e) {
|
|
398
|
+
logWarning("recovery", `updateSliceStatus failed during context exhaustion: ${e instanceof Error ? e.message : String(e)}`);
|
|
391
399
|
}
|
|
392
400
|
}
|
|
393
401
|
}
|
|
@@ -30,7 +30,7 @@ import { initRoutingHistory } from "./routing-history.js";
|
|
|
30
30
|
import { restoreHookState, resetHookState } from "./post-unit-hooks.js";
|
|
31
31
|
import { resetProactiveHealing, setLevelChangeCallback } from "./doctor-proactive.js";
|
|
32
32
|
import { snapshotSkills } from "./skill-discovery.js";
|
|
33
|
-
import { isDbAvailable, getMilestone } from "./gsd-db.js";
|
|
33
|
+
import { isDbAvailable, getMilestone, openDatabase } from "./gsd-db.js";
|
|
34
34
|
import { hideFooter } from "./auto-dashboard.js";
|
|
35
35
|
import { debugLog, enableDebug, isDebugEnabled, getDebugLogPath, } from "./debug-logger.js";
|
|
36
36
|
import { logWarning, logError } from "./workflow-logger.js";
|
|
@@ -48,34 +48,23 @@ import { resolveDefaultSessionModel } from "./preferences-models.js";
|
|
|
48
48
|
* Returns false if the bootstrap aborted (e.g., guided flow returned,
|
|
49
49
|
* concurrent session detected). Returns true when ready to dispatch.
|
|
50
50
|
*/
|
|
51
|
-
/**
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
async function openProjectDbIfPresent(basePath) {
|
|
51
|
+
/** Guard: tracks consecutive bootstrap attempts that found phase === "complete".
|
|
52
|
+
* Prevents the recursive dialog loop described in #1348 where
|
|
53
|
+
* bootstrapAutoSession → showSmartEntry → checkAutoStartAfterDiscuss → startAuto
|
|
54
|
+
* cycles indefinitely when the discuss workflow doesn't produce a milestone. */
|
|
55
|
+
let _consecutiveCompleteBootstraps = 0;
|
|
56
|
+
const MAX_CONSECUTIVE_COMPLETE_BOOTSTRAPS = 2;
|
|
57
|
+
export async function openProjectDbIfPresent(basePath) {
|
|
59
58
|
const gsdDbPath = resolveProjectRootDbPath(basePath);
|
|
60
|
-
if (!existsSync(gsdDbPath))
|
|
61
|
-
return;
|
|
62
|
-
if (isDbAvailable())
|
|
59
|
+
if (!existsSync(gsdDbPath) || isDbAvailable())
|
|
63
60
|
return;
|
|
64
61
|
try {
|
|
65
|
-
const { openDatabase } = await import("./gsd-db.js");
|
|
66
62
|
openDatabase(gsdDbPath);
|
|
67
63
|
}
|
|
68
64
|
catch (err) {
|
|
69
|
-
|
|
70
|
-
logWarning("engine", `DB open failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
65
|
+
logWarning("engine", `gsd-db: failed to open existing database: ${err instanceof Error ? err.message : String(err)}`);
|
|
71
66
|
}
|
|
72
67
|
}
|
|
73
|
-
/** Guard: tracks consecutive bootstrap attempts that found phase === "complete".
|
|
74
|
-
* Prevents the recursive dialog loop described in #1348 where
|
|
75
|
-
* bootstrapAutoSession → showSmartEntry → checkAutoStartAfterDiscuss → startAuto
|
|
76
|
-
* cycles indefinitely when the discuss workflow doesn't produce a milestone. */
|
|
77
|
-
let _consecutiveCompleteBootstraps = 0;
|
|
78
|
-
const MAX_CONSECUTIVE_COMPLETE_BOOTSTRAPS = 2;
|
|
79
68
|
export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, requestedStepMode, deps) {
|
|
80
69
|
const { shouldUseWorktreeIsolation, registerSigtermHandler, lockBase, buildResolver, } = deps;
|
|
81
70
|
const lockResult = acquireSessionLock(base);
|
|
@@ -77,8 +77,9 @@ export function startUnitSupervision(sctx) {
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
const estimateMinutes = taskEstimate ? parseEstimateMinutes(taskEstimate) : null;
|
|
80
|
+
const MAX_TIMEOUT_SCALE = 6; // Cap at 6x (60min task). Prevents 2h+ tasks from creating 120min+ timeout windows.
|
|
80
81
|
const timeoutScale = estimateMinutes && estimateMinutes > 0
|
|
81
|
-
? Math.max(1, estimateMinutes / 10)
|
|
82
|
+
? Math.min(MAX_TIMEOUT_SCALE, Math.max(1, estimateMinutes / 10))
|
|
82
83
|
: 1;
|
|
83
84
|
const softTimeoutMs = (supervisor.soft_timeout_minutes ?? 0) * 60 * 1000 * timeoutScale;
|
|
84
85
|
const idleTimeoutMs = (supervisor.idle_timeout_minutes ?? 0) * 60 * 1000; // idle not scaled — idle is idle
|
|
@@ -75,3 +75,20 @@ export function hasInteractiveToolInFlight() {
|
|
|
75
75
|
export function clearInFlightTools() {
|
|
76
76
|
inFlightTools.clear();
|
|
77
77
|
}
|
|
78
|
+
// ─── Tool invocation error classification (#2883) ────────────────────────
|
|
79
|
+
/**
|
|
80
|
+
* Patterns that indicate a tool invocation failed due to malformed or truncated
|
|
81
|
+
* JSON arguments — as opposed to a normal business-logic error from the tool
|
|
82
|
+
* handler. When these errors occur, retrying the same unit will produce the same
|
|
83
|
+
* failure, so the retry loop must be broken.
|
|
84
|
+
*/
|
|
85
|
+
const TOOL_INVOCATION_ERROR_RE = /Validation failed for tool|Expected ',' or '\}' in JSON|Unexpected end of JSON|Unexpected token.*in JSON/i;
|
|
86
|
+
/**
|
|
87
|
+
* Returns true if the error message indicates a tool invocation failure due to
|
|
88
|
+
* malformed/truncated arguments (as opposed to a normal tool execution error).
|
|
89
|
+
*/
|
|
90
|
+
export function isToolInvocationError(errorMsg) {
|
|
91
|
+
if (!errorMsg)
|
|
92
|
+
return false;
|
|
93
|
+
return TOOL_INVOCATION_ERROR_RE.test(errorMsg);
|
|
94
|
+
}
|