gsd-pi 2.63.0-dev.026d309 → 2.63.0-dev.786f0ff
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 +9 -3
- package/dist/resources/extensions/gsd/auto-model-selection.js +32 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +124 -10
- 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-worktree.js +13 -7
- package/dist/resources/extensions/gsd/auto.js +19 -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/preferences-types.js +2 -0
- package/dist/resources/extensions/gsd/preferences.js +7 -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/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 +20 -20
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- 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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +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/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/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 +20 -20
- package/dist/web/standalone/.next/server/chunks/6897.js +12 -0
- 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/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/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/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 +11 -3
- package/src/resources/extensions/gsd/auto-model-selection.ts +36 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +141 -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-worktree.ts +14 -6
- package/src/resources/extensions/gsd/auto.ts +22 -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/preferences-types.ts +16 -0
- package/src/resources/extensions/gsd/preferences.ts +9 -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/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/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/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/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/{TTlAguZQ5vR9EOv6G8cel → SDB1T-4NqkMjYirjjqQhr}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{TTlAguZQ5vR9EOv6G8cel → SDB1T-4NqkMjYirjjqQhr}/_ssgManifest.js +0 -0
|
@@ -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
|
+
}
|
|
@@ -14,7 +14,7 @@ import { atomicWriteSync } from "./atomic-write.js";
|
|
|
14
14
|
import { execFileSync } from "node:child_process";
|
|
15
15
|
import { safeCopy, safeCopyRecursive } from "./safe-fs.js";
|
|
16
16
|
import { gsdRoot } from "./paths.js";
|
|
17
|
-
import { createWorktree, removeWorktree, resolveGitDir, worktreePath, } from "./worktree-manager.js";
|
|
17
|
+
import { createWorktree, removeWorktree, resolveGitDir, worktreePath, isInsideWorktreesDir, } from "./worktree-manager.js";
|
|
18
18
|
import { detectWorktreeName, nudgeGitBranchCache, } from "./worktree.js";
|
|
19
19
|
import { MergeConflictError, readIntegrationBranch, RUNTIME_EXCLUSION_PATHS } from "./git-service.js";
|
|
20
20
|
import { debugLog } from "./debug-logger.js";
|
|
@@ -1025,13 +1025,19 @@ export function teardownAutoWorktree(originalBasePath, milestoneId, opts = {}) {
|
|
|
1025
1025
|
logWarning("reconcile", `Worktree directory still exists after teardown: ${wtDir}. ` +
|
|
1026
1026
|
`This is likely an orphaned directory consuming disk space. ` +
|
|
1027
1027
|
`Remove it manually with: rm -rf "${wtDir.replaceAll("\\", "/")}"`, { worktree: milestoneId });
|
|
1028
|
-
// Attempt a direct filesystem removal as a fallback
|
|
1029
|
-
|
|
1030
|
-
|
|
1028
|
+
// Attempt a direct filesystem removal as a fallback — but ONLY if the
|
|
1029
|
+
// path is safely inside .gsd/worktrees/ to prevent #2365 data loss.
|
|
1030
|
+
if (isInsideWorktreesDir(originalBasePath, wtDir)) {
|
|
1031
|
+
try {
|
|
1032
|
+
rmSync(wtDir, { recursive: true, force: true });
|
|
1033
|
+
}
|
|
1034
|
+
catch (err) {
|
|
1035
|
+
// Non-fatal — the warning above tells the user how to clean up
|
|
1036
|
+
logWarning("worktree", `worktree directory removal failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1037
|
+
}
|
|
1031
1038
|
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
logWarning("worktree", `worktree directory removal failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1039
|
+
else {
|
|
1040
|
+
console.error(`[GSD] REFUSING fallback rmSync — path is outside .gsd/worktrees/: ${wtDir}`);
|
|
1035
1041
|
}
|
|
1036
1042
|
}
|
|
1037
1043
|
}
|
|
@@ -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, } from "./auto-tool-tracking.js";
|
|
26
|
+
import { markToolStart as _markToolStart, markToolEnd as _markToolEnd, getOldestInFlightToolAgeMs as _getOldestInFlightToolAgeMs, clearInFlightTools, isToolInvocationError, } 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";
|
|
@@ -57,7 +57,7 @@ import { clearCmuxSidebar, logCmuxEvent, syncCmuxSidebar } from "../cmux/index.j
|
|
|
57
57
|
import { startUnitSupervision } from "./auto-timers.js";
|
|
58
58
|
import { runPostUnitVerification } from "./auto-verification.js";
|
|
59
59
|
import { postUnitPreVerification, postUnitPostVerification, } from "./auto-post-unit.js";
|
|
60
|
-
import { bootstrapAutoSession } from "./auto-start.js";
|
|
60
|
+
import { bootstrapAutoSession, openProjectDbIfPresent } from "./auto-start.js";
|
|
61
61
|
import { autoLoop, resolveAgentEnd, resolveAgentEndCancelled, _resetPendingResolve, isSessionSwitchInFlight } from "./auto-loop.js";
|
|
62
62
|
import { WorktreeResolver, } from "./worktree-resolver.js";
|
|
63
63
|
import { reorderForCaching } from "./prompt-ordering.js";
|
|
@@ -192,6 +192,19 @@ export function markToolStart(toolCallId, toolName) {
|
|
|
192
192
|
export function markToolEnd(toolCallId) {
|
|
193
193
|
_markToolEnd(toolCallId);
|
|
194
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* Record a tool invocation error on the current session (#2883).
|
|
197
|
+
* Called from tool_execution_end when a GSD tool fails with isError.
|
|
198
|
+
* Only stores the error if it matches the tool-invocation-error pattern
|
|
199
|
+
* (malformed/truncated JSON), not normal business-logic errors.
|
|
200
|
+
*/
|
|
201
|
+
export function recordToolInvocationError(toolName, errorMsg) {
|
|
202
|
+
if (!s.active)
|
|
203
|
+
return;
|
|
204
|
+
if (isToolInvocationError(errorMsg)) {
|
|
205
|
+
s.lastToolInvocationError = `${toolName}: ${errorMsg}`;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
195
208
|
export function getOldestInFlightToolAgeMs() {
|
|
196
209
|
return _getOldestInFlightToolAgeMs();
|
|
197
210
|
}
|
|
@@ -909,6 +922,9 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
909
922
|
ctx.ui.setFooter(hideFooter);
|
|
910
923
|
ctx.ui.notify(s.stepMode ? "Step-mode resumed." : "Auto-mode resumed.", "info");
|
|
911
924
|
restoreHookState(s.basePath);
|
|
925
|
+
// Open the project DB before rebuild/derive so resume uses DB-backed
|
|
926
|
+
// state instead of falling back to stale markdown parsing (#2940).
|
|
927
|
+
await openProjectDbIfPresent(s.basePath);
|
|
912
928
|
try {
|
|
913
929
|
await rebuildState(s.basePath);
|
|
914
930
|
syncCmuxSidebar(loadEffectiveGSDPreferences()?.preferences, await deriveState(s.basePath));
|
|
@@ -1005,6 +1021,7 @@ const widgetStateAccessors = {
|
|
|
1005
1021
|
getBasePath: () => s.basePath,
|
|
1006
1022
|
isVerbose: () => s.verbose,
|
|
1007
1023
|
isSessionSwitching: isSessionSwitchInFlight,
|
|
1024
|
+
getCurrentDispatchedModelId: () => s.currentDispatchedModelId,
|
|
1008
1025
|
};
|
|
1009
1026
|
// ─── Preconditions ────────────────────────────────────────────────────────────
|
|
1010
1027
|
/**
|
|
@@ -486,28 +486,10 @@ export function registerDbTools(pi) {
|
|
|
486
486
|
"Use the canonical name gsd_plan_milestone; gsd_milestone_plan is only an alias.",
|
|
487
487
|
],
|
|
488
488
|
parameters: Type.Object({
|
|
489
|
+
// ── Core identification + content (required) ──────────────────────
|
|
489
490
|
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
490
491
|
title: Type.String({ description: "Milestone title" }),
|
|
491
|
-
status: Type.Optional(Type.String({ description: "Milestone status (defaults to active)" })),
|
|
492
|
-
dependsOn: Type.Optional(Type.Array(Type.String(), { description: "Milestone dependencies" })),
|
|
493
492
|
vision: Type.String({ description: "Milestone vision" }),
|
|
494
|
-
successCriteria: Type.Array(Type.String(), { description: "Top-level success criteria bullets" }),
|
|
495
|
-
keyRisks: Type.Array(Type.Object({
|
|
496
|
-
risk: Type.String({ description: "Risk statement" }),
|
|
497
|
-
whyItMatters: Type.String({ description: "Why the risk matters" }),
|
|
498
|
-
}), { description: "Structured risk entries" }),
|
|
499
|
-
proofStrategy: Type.Array(Type.Object({
|
|
500
|
-
riskOrUnknown: Type.String({ description: "Risk or unknown to retire" }),
|
|
501
|
-
retireIn: Type.String({ description: "Where it will be retired" }),
|
|
502
|
-
whatWillBeProven: Type.String({ description: "What proof will be produced" }),
|
|
503
|
-
}), { description: "Structured proof strategy entries" }),
|
|
504
|
-
verificationContract: Type.String({ description: "Verification contract text" }),
|
|
505
|
-
verificationIntegration: Type.String({ description: "Integration verification text" }),
|
|
506
|
-
verificationOperational: Type.String({ description: "Operational verification text" }),
|
|
507
|
-
verificationUat: Type.String({ description: "UAT verification text" }),
|
|
508
|
-
definitionOfDone: Type.Array(Type.String(), { description: "Definition of done bullets" }),
|
|
509
|
-
requirementCoverage: Type.String({ description: "Requirement coverage text" }),
|
|
510
|
-
boundaryMapMarkdown: Type.String({ description: "Boundary map markdown block" }),
|
|
511
493
|
slices: Type.Array(Type.Object({
|
|
512
494
|
sliceId: Type.String({ description: "Slice ID (e.g. S01)" }),
|
|
513
495
|
title: Type.String({ description: "Slice title" }),
|
|
@@ -520,6 +502,26 @@ export function registerDbTools(pi) {
|
|
|
520
502
|
integrationClosure: Type.String({ description: "Slice integration closure" }),
|
|
521
503
|
observabilityImpact: Type.String({ description: "Slice observability impact" }),
|
|
522
504
|
}), { description: "Planned slices for the milestone" }),
|
|
505
|
+
// ── Enrichment metadata (optional — defaults to empty) ────────────
|
|
506
|
+
status: Type.Optional(Type.String({ description: "Milestone status (defaults to active)" })),
|
|
507
|
+
dependsOn: Type.Optional(Type.Array(Type.String(), { description: "Milestone dependencies" })),
|
|
508
|
+
successCriteria: Type.Optional(Type.Array(Type.String(), { description: "Top-level success criteria bullets" })),
|
|
509
|
+
keyRisks: Type.Optional(Type.Array(Type.Object({
|
|
510
|
+
risk: Type.String({ description: "Risk statement" }),
|
|
511
|
+
whyItMatters: Type.String({ description: "Why the risk matters" }),
|
|
512
|
+
}), { description: "Structured risk entries" })),
|
|
513
|
+
proofStrategy: Type.Optional(Type.Array(Type.Object({
|
|
514
|
+
riskOrUnknown: Type.String({ description: "Risk or unknown to retire" }),
|
|
515
|
+
retireIn: Type.String({ description: "Where it will be retired" }),
|
|
516
|
+
whatWillBeProven: Type.String({ description: "What proof will be produced" }),
|
|
517
|
+
}), { description: "Structured proof strategy entries" })),
|
|
518
|
+
verificationContract: Type.Optional(Type.String({ description: "Verification contract text" })),
|
|
519
|
+
verificationIntegration: Type.Optional(Type.String({ description: "Integration verification text" })),
|
|
520
|
+
verificationOperational: Type.Optional(Type.String({ description: "Operational verification text" })),
|
|
521
|
+
verificationUat: Type.Optional(Type.String({ description: "UAT verification text" })),
|
|
522
|
+
definitionOfDone: Type.Optional(Type.Array(Type.String(), { description: "Definition of done bullets" })),
|
|
523
|
+
requirementCoverage: Type.Optional(Type.String({ description: "Requirement coverage text" })),
|
|
524
|
+
boundaryMapMarkdown: Type.Optional(Type.String({ description: "Boundary map markdown block" })),
|
|
523
525
|
}),
|
|
524
526
|
execute: planMilestoneExecute,
|
|
525
527
|
};
|
|
@@ -575,13 +577,10 @@ export function registerDbTools(pi) {
|
|
|
575
577
|
"Use the canonical name gsd_plan_slice; gsd_slice_plan is only an alias.",
|
|
576
578
|
],
|
|
577
579
|
parameters: Type.Object({
|
|
580
|
+
// ── Core identification + content (required) ──────────────────────
|
|
578
581
|
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
579
582
|
sliceId: Type.String({ description: "Slice ID (e.g. S01)" }),
|
|
580
583
|
goal: Type.String({ description: "Slice goal" }),
|
|
581
|
-
successCriteria: Type.String({ description: "Slice success criteria block" }),
|
|
582
|
-
proofLevel: Type.String({ description: "Slice proof level" }),
|
|
583
|
-
integrationClosure: Type.String({ description: "Slice integration closure" }),
|
|
584
|
-
observabilityImpact: Type.String({ description: "Slice observability impact" }),
|
|
585
584
|
tasks: Type.Array(Type.Object({
|
|
586
585
|
taskId: Type.String({ description: "Task ID (e.g. T01)" }),
|
|
587
586
|
title: Type.String({ description: "Task title" }),
|
|
@@ -593,6 +592,11 @@ export function registerDbTools(pi) {
|
|
|
593
592
|
expectedOutput: Type.Array(Type.String(), { description: "Expected output files or artifacts" }),
|
|
594
593
|
observabilityImpact: Type.Optional(Type.String({ description: "Task observability impact" })),
|
|
595
594
|
}), { description: "Planned tasks for the slice" }),
|
|
595
|
+
// ── Enrichment metadata (optional — defaults to empty) ────────────
|
|
596
|
+
successCriteria: Type.Optional(Type.String({ description: "Slice success criteria block" })),
|
|
597
|
+
proofLevel: Type.Optional(Type.String({ description: "Slice proof level" })),
|
|
598
|
+
integrationClosure: Type.Optional(Type.String({ description: "Slice integration closure" })),
|
|
599
|
+
observabilityImpact: Type.Optional(Type.String({ description: "Slice observability impact" })),
|
|
596
600
|
}),
|
|
597
601
|
execute: planSliceExecute,
|
|
598
602
|
};
|
|
@@ -674,8 +678,11 @@ export function registerDbTools(pi) {
|
|
|
674
678
|
};
|
|
675
679
|
}
|
|
676
680
|
try {
|
|
681
|
+
// Coerce string items to objects for verificationEvidence (#3541).
|
|
682
|
+
const coerced = { ...params };
|
|
683
|
+
coerced.verificationEvidence = (params.verificationEvidence ?? []).map((v) => typeof v === "string" ? { command: v, exitCode: -1, verdict: "unknown (coerced from string)", durationMs: 0 } : v);
|
|
677
684
|
const { handleCompleteTask } = await import("../tools/complete-task.js");
|
|
678
|
-
const result = await handleCompleteTask(
|
|
685
|
+
const result = await handleCompleteTask(coerced, process.cwd());
|
|
679
686
|
if ("error" in result) {
|
|
680
687
|
return {
|
|
681
688
|
content: [{ type: "text", text: `Error completing task: ${result.error}` }],
|
|
@@ -716,23 +723,28 @@ export function registerDbTools(pi) {
|
|
|
716
723
|
"Idempotent — calling with the same params twice will upsert (INSERT OR REPLACE) without error.",
|
|
717
724
|
],
|
|
718
725
|
parameters: Type.Object({
|
|
726
|
+
// ── Core identification + content (required) ──────────────────────
|
|
719
727
|
taskId: Type.String({ description: "Task ID (e.g. T01)" }),
|
|
720
728
|
sliceId: Type.String({ description: "Slice ID (e.g. S01)" }),
|
|
721
729
|
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
722
730
|
oneLiner: Type.String({ description: "One-line summary of what was accomplished" }),
|
|
723
731
|
narrative: Type.String({ description: "Detailed narrative of what happened during the task" }),
|
|
724
732
|
verification: Type.String({ description: "What was verified and how — commands run, tests passed, behavior confirmed" }),
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
733
|
+
// ── Enrichment metadata (optional — defaults to empty) ────────────
|
|
734
|
+
deviations: Type.Optional(Type.String({ description: "Deviations from the task plan, or 'None.'" })),
|
|
735
|
+
knownIssues: Type.Optional(Type.String({ description: "Known issues discovered but not fixed, or 'None.'" })),
|
|
736
|
+
keyFiles: Type.Optional(Type.Array(Type.String(), { description: "List of key files created or modified" })),
|
|
737
|
+
keyDecisions: Type.Optional(Type.Array(Type.String(), { description: "List of key decisions made during this task" })),
|
|
738
|
+
blockerDiscovered: Type.Optional(Type.Boolean({ description: "Whether a plan-invalidating blocker was discovered" })),
|
|
739
|
+
verificationEvidence: Type.Optional(Type.Array(Type.Union([
|
|
740
|
+
Type.Object({
|
|
741
|
+
command: Type.String({ description: "Verification command that was run" }),
|
|
742
|
+
exitCode: Type.Number({ description: "Exit code of the command" }),
|
|
743
|
+
verdict: Type.String({ description: "Pass/fail verdict (e.g. '✅ pass', '❌ fail')" }),
|
|
744
|
+
durationMs: Type.Number({ description: "Duration of the command in milliseconds" }),
|
|
745
|
+
}),
|
|
746
|
+
Type.String({ description: "Fallback: verification summary string" }),
|
|
747
|
+
]), { description: "Array of verification evidence entries" })),
|
|
736
748
|
}),
|
|
737
749
|
execute: taskCompleteExecute,
|
|
738
750
|
};
|
|
@@ -748,8 +760,46 @@ export function registerDbTools(pi) {
|
|
|
748
760
|
};
|
|
749
761
|
}
|
|
750
762
|
try {
|
|
763
|
+
// Coerce string items to objects for fields where LLMs sometimes pass
|
|
764
|
+
// plain strings instead of the expected { key, value } shape (#3541).
|
|
765
|
+
// Parses "key — value" or "key - value" format when possible.
|
|
766
|
+
const splitPair = (s) => {
|
|
767
|
+
const m = s.match(/^(.+?)\s*(?:—|-)\s+(.+)$/);
|
|
768
|
+
return m ? [m[1].trim(), m[2].trim()] : [s.trim(), ""];
|
|
769
|
+
};
|
|
770
|
+
const coerced = { ...params };
|
|
771
|
+
coerced.filesModified = (params.filesModified ?? []).map((f) => {
|
|
772
|
+
if (typeof f !== "string")
|
|
773
|
+
return f;
|
|
774
|
+
const [path, description] = splitPair(f);
|
|
775
|
+
return { path, description };
|
|
776
|
+
});
|
|
777
|
+
coerced.requires = (params.requires ?? []).map((r) => {
|
|
778
|
+
if (typeof r !== "string")
|
|
779
|
+
return r;
|
|
780
|
+
const [slice, provides] = splitPair(r);
|
|
781
|
+
return { slice, provides };
|
|
782
|
+
});
|
|
783
|
+
coerced.requirementsAdvanced = (params.requirementsAdvanced ?? []).map((r) => {
|
|
784
|
+
if (typeof r !== "string")
|
|
785
|
+
return r;
|
|
786
|
+
const [id, how] = splitPair(r);
|
|
787
|
+
return { id, how };
|
|
788
|
+
});
|
|
789
|
+
coerced.requirementsValidated = (params.requirementsValidated ?? []).map((r) => {
|
|
790
|
+
if (typeof r !== "string")
|
|
791
|
+
return r;
|
|
792
|
+
const [id, proof] = splitPair(r);
|
|
793
|
+
return { id, proof };
|
|
794
|
+
});
|
|
795
|
+
coerced.requirementsInvalidated = (params.requirementsInvalidated ?? []).map((r) => {
|
|
796
|
+
if (typeof r !== "string")
|
|
797
|
+
return r;
|
|
798
|
+
const [id, what] = splitPair(r);
|
|
799
|
+
return { id, what };
|
|
800
|
+
});
|
|
751
801
|
const { handleCompleteSlice } = await import("../tools/complete-slice.js");
|
|
752
|
-
const result = await handleCompleteSlice(
|
|
802
|
+
const result = await handleCompleteSlice(coerced, process.cwd());
|
|
753
803
|
if ("error" in result) {
|
|
754
804
|
return {
|
|
755
805
|
content: [{ type: "text", text: `Error completing slice: ${result.error}` }],
|
|
@@ -789,44 +839,61 @@ export function registerDbTools(pi) {
|
|
|
789
839
|
"Idempotent — calling with the same params twice will not crash.",
|
|
790
840
|
],
|
|
791
841
|
parameters: Type.Object({
|
|
842
|
+
// ── Core identification + content (required) ──────────────────────
|
|
792
843
|
sliceId: Type.String({ description: "Slice ID (e.g. S01)" }),
|
|
793
844
|
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
794
845
|
sliceTitle: Type.String({ description: "Title of the slice" }),
|
|
795
846
|
oneLiner: Type.String({ description: "One-line summary of what the slice accomplished" }),
|
|
796
847
|
narrative: Type.String({ description: "Detailed narrative of what happened across all tasks" }),
|
|
797
848
|
verification: Type.String({ description: "What was verified across all tasks" }),
|
|
798
|
-
deviations: Type.String({ description: "Deviations from the slice plan, or 'None.'" }),
|
|
799
|
-
knownLimitations: Type.String({ description: "Known limitations or gaps, or 'None.'" }),
|
|
800
|
-
followUps: Type.String({ description: "Follow-up work discovered during execution, or 'None.'" }),
|
|
801
|
-
keyFiles: Type.Array(Type.String(), { description: "Key files created or modified" }),
|
|
802
|
-
keyDecisions: Type.Array(Type.String(), { description: "Key decisions made during this slice" }),
|
|
803
|
-
patternsEstablished: Type.Array(Type.String(), { description: "Patterns established by this slice" }),
|
|
804
|
-
observabilitySurfaces: Type.Array(Type.String(), { description: "Observability surfaces added" }),
|
|
805
|
-
provides: Type.Array(Type.String(), { description: "What this slice provides to downstream slices" }),
|
|
806
|
-
requirementsSurfaced: Type.Array(Type.String(), { description: "New requirements surfaced" }),
|
|
807
|
-
drillDownPaths: Type.Array(Type.String(), { description: "Paths to task summaries for drill-down" }),
|
|
808
|
-
affects: Type.Array(Type.String(), { description: "Downstream slices affected" }),
|
|
809
|
-
requirementsAdvanced: Type.Array(Type.Object({
|
|
810
|
-
id: Type.String({ description: "Requirement ID" }),
|
|
811
|
-
how: Type.String({ description: "How it was advanced" }),
|
|
812
|
-
}), { description: "Requirements advanced by this slice" }),
|
|
813
|
-
requirementsValidated: Type.Array(Type.Object({
|
|
814
|
-
id: Type.String({ description: "Requirement ID" }),
|
|
815
|
-
proof: Type.String({ description: "What proof validates it" }),
|
|
816
|
-
}), { description: "Requirements validated by this slice" }),
|
|
817
|
-
requirementsInvalidated: Type.Array(Type.Object({
|
|
818
|
-
id: Type.String({ description: "Requirement ID" }),
|
|
819
|
-
what: Type.String({ description: "What changed" }),
|
|
820
|
-
}), { description: "Requirements invalidated or re-scoped" }),
|
|
821
|
-
filesModified: Type.Array(Type.Object({
|
|
822
|
-
path: Type.String({ description: "File path" }),
|
|
823
|
-
description: Type.String({ description: "What changed" }),
|
|
824
|
-
}), { description: "Files modified with descriptions" }),
|
|
825
|
-
requires: Type.Array(Type.Object({
|
|
826
|
-
slice: Type.String({ description: "Dependency slice ID" }),
|
|
827
|
-
provides: Type.String({ description: "What was consumed from it" }),
|
|
828
|
-
}), { description: "Upstream slice dependencies consumed" }),
|
|
829
849
|
uatContent: Type.String({ description: "UAT test content (markdown body)" }),
|
|
850
|
+
// ── Enrichment metadata (optional — defaults to empty) ────────────
|
|
851
|
+
deviations: Type.Optional(Type.String({ description: "Deviations from the slice plan, or 'None.'" })),
|
|
852
|
+
knownLimitations: Type.Optional(Type.String({ description: "Known limitations or gaps, or 'None.'" })),
|
|
853
|
+
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" })),
|
|
862
|
+
requirementsAdvanced: Type.Optional(Type.Array(Type.Union([
|
|
863
|
+
Type.Object({
|
|
864
|
+
id: Type.String({ description: "Requirement ID" }),
|
|
865
|
+
how: Type.String({ description: "How it was advanced" }),
|
|
866
|
+
}),
|
|
867
|
+
Type.String({ description: "Fallback: 'ID — how' string" }),
|
|
868
|
+
]), { description: "Requirements advanced by this slice" })),
|
|
869
|
+
requirementsValidated: Type.Optional(Type.Array(Type.Union([
|
|
870
|
+
Type.Object({
|
|
871
|
+
id: Type.String({ description: "Requirement ID" }),
|
|
872
|
+
proof: Type.String({ description: "What proof validates it" }),
|
|
873
|
+
}),
|
|
874
|
+
Type.String({ description: "Fallback: 'ID — proof' string" }),
|
|
875
|
+
]), { description: "Requirements validated by this slice" })),
|
|
876
|
+
requirementsInvalidated: Type.Optional(Type.Array(Type.Union([
|
|
877
|
+
Type.Object({
|
|
878
|
+
id: Type.String({ description: "Requirement ID" }),
|
|
879
|
+
what: Type.String({ description: "What changed" }),
|
|
880
|
+
}),
|
|
881
|
+
Type.String({ description: "Fallback: 'ID — what' string" }),
|
|
882
|
+
]), { description: "Requirements invalidated or re-scoped" })),
|
|
883
|
+
filesModified: Type.Optional(Type.Array(Type.Union([
|
|
884
|
+
Type.Object({
|
|
885
|
+
path: Type.String({ description: "File path" }),
|
|
886
|
+
description: Type.String({ description: "What changed" }),
|
|
887
|
+
}),
|
|
888
|
+
Type.String({ description: "Fallback: file path string" }),
|
|
889
|
+
]), { description: "Files modified with descriptions" })),
|
|
890
|
+
requires: Type.Optional(Type.Array(Type.Union([
|
|
891
|
+
Type.Object({
|
|
892
|
+
slice: Type.String({ description: "Dependency slice ID" }),
|
|
893
|
+
provides: Type.String({ description: "What was consumed from it" }),
|
|
894
|
+
}),
|
|
895
|
+
Type.String({ description: "Fallback: slice ID string" }),
|
|
896
|
+
]), { description: "Upstream slice dependencies consumed" })),
|
|
830
897
|
}),
|
|
831
898
|
execute: sliceCompleteExecute,
|
|
832
899
|
};
|
|
@@ -912,8 +979,11 @@ export function registerDbTools(pi) {
|
|
|
912
979
|
};
|
|
913
980
|
}
|
|
914
981
|
try {
|
|
982
|
+
// ── Input sanitization: normalize markdown parameters (#3013) ──────
|
|
983
|
+
const { sanitizeCompleteMilestoneParams } = await import("./sanitize-complete-milestone.js");
|
|
984
|
+
const sanitized = sanitizeCompleteMilestoneParams(params);
|
|
915
985
|
const { handleCompleteMilestone } = await import("../tools/complete-milestone.js");
|
|
916
|
-
const result = await handleCompleteMilestone(
|
|
986
|
+
const result = await handleCompleteMilestone(sanitized, process.cwd());
|
|
917
987
|
if ("error" in result) {
|
|
918
988
|
return {
|
|
919
989
|
content: [{ type: "text", text: `Error completing milestone: ${result.error}` }],
|
|
@@ -951,19 +1021,21 @@ export function registerDbTools(pi) {
|
|
|
951
1021
|
"On success, returns summaryPath where the MILESTONE-SUMMARY.md was written.",
|
|
952
1022
|
],
|
|
953
1023
|
parameters: Type.Object({
|
|
1024
|
+
// ── Core identification + content (required) ──────────────────────
|
|
954
1025
|
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
955
1026
|
title: Type.String({ description: "Milestone title" }),
|
|
956
1027
|
oneLiner: Type.String({ description: "One-sentence summary of what the milestone achieved" }),
|
|
957
1028
|
narrative: Type.String({ description: "Detailed narrative of what happened during the milestone" }),
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
1029
|
+
verificationPassed: Type.Boolean({ description: "Must be true — confirms that code change verification, success criteria, and definition of done checks all passed before completion" }),
|
|
1030
|
+
// ── Enrichment metadata (optional — defaults to empty) ────────────
|
|
1031
|
+
successCriteriaResults: Type.Optional(Type.String({ description: "Markdown detailing how each success criterion was met or not met" })),
|
|
1032
|
+
definitionOfDoneResults: Type.Optional(Type.String({ description: "Markdown detailing how each definition-of-done item was met" })),
|
|
1033
|
+
requirementOutcomes: Type.Optional(Type.String({ description: "Markdown detailing requirement status transitions with evidence" })),
|
|
1034
|
+
keyDecisions: Type.Optional(Type.Array(Type.String(), { description: "Key architectural/pattern decisions made during the milestone" })),
|
|
1035
|
+
keyFiles: Type.Optional(Type.Array(Type.String(), { description: "Key files created or modified during the milestone" })),
|
|
1036
|
+
lessonsLearned: Type.Optional(Type.Array(Type.String(), { description: "Lessons learned during the milestone" })),
|
|
964
1037
|
followUps: Type.Optional(Type.String({ description: "Follow-up items for future milestones" })),
|
|
965
1038
|
deviations: Type.Optional(Type.String({ description: "Deviations from the original plan" })),
|
|
966
|
-
verificationPassed: Type.Boolean({ description: "Must be true — confirms that code change verification, success criteria, and definition of done checks all passed before completion" }),
|
|
967
1039
|
}),
|
|
968
1040
|
execute: milestoneCompleteExecute,
|
|
969
1041
|
};
|
|
@@ -26,6 +26,19 @@ export function resolveProjectRootDbPath(basePath) {
|
|
|
26
26
|
const projectRoot = basePath.slice(0, fwdIdx);
|
|
27
27
|
return join(projectRoot, ".gsd", "gsd.db");
|
|
28
28
|
}
|
|
29
|
+
// External-state layout: ~/.gsd/projects/<hash>/worktrees/<MID>/...
|
|
30
|
+
// Resolve to ~/.gsd/projects/<hash>/gsd.db (the canonical project DB) (#2952).
|
|
31
|
+
// Must be checked before the generic symlink-resolved handler: both match
|
|
32
|
+
// /.gsd/projects/<hash>/worktrees/ but require different resolution targets.
|
|
33
|
+
const extRe = /[/\\]\.gsd[/\\]projects[/\\][a-f0-9]+[/\\]worktrees(?:[/\\]|$)/;
|
|
34
|
+
const extMatch = extRe.exec(basePath);
|
|
35
|
+
if (extMatch) {
|
|
36
|
+
const matchStr = extMatch[0];
|
|
37
|
+
// Find the "/worktrees" portion within the match and slice up to it
|
|
38
|
+
const wtIdx = matchStr.search(/[/\\]worktrees(?:[/\\]|$)/);
|
|
39
|
+
const projectStateRoot = basePath.slice(0, extMatch.index + wtIdx);
|
|
40
|
+
return join(projectStateRoot, "gsd.db");
|
|
41
|
+
}
|
|
29
42
|
// Symlink-resolved layout: /.gsd/projects/<hash>/worktrees/M001/...
|
|
30
43
|
// The project root is everything before /.gsd/projects/ (#2517)
|
|
31
44
|
const symlinkMarker = `${sep}.gsd${sep}projects${sep}`;
|