gsd-pi 2.63.0-dev.026d309 → 2.63.0-dev.351157b
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 +44 -6
- 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/finalize-timeout.js +40 -0
- package/dist/resources/extensions/gsd/auto/loop.js +4 -0
- package/dist/resources/extensions/gsd/auto/phases.js +123 -22
- package/dist/resources/extensions/gsd/auto/session.js +8 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +9 -3
- package/dist/resources/extensions/gsd/auto-post-unit.js +45 -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-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 +73 -60
- 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 +9 -1
- package/dist/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.js +54 -0
- 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 +1 -0
- package/dist/resources/extensions/gsd/preferences.js +7 -2
- 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 +1 -0
- 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/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 +6 -12
- 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/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
- 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 +14 -14
- 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/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 +1 -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 +10 -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/types.ts +2 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +2 -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 +11 -0
- package/src/resources/extensions/cmux/index.ts +18 -12
- 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 +156 -34
- package/src/resources/extensions/gsd/auto/session.ts +9 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +11 -3
- package/src/resources/extensions/gsd/auto-post-unit.ts +53 -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-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 +74 -60
- 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 +9 -1
- package/src/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.ts +57 -0
- 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 +3 -0
- package/src/resources/extensions/gsd/preferences.ts +9 -2
- 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 +1 -0
- 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/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-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/forensics-stuck-loops.test.ts +103 -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/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-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 +6 -14
- 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-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-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 → QmuF-eAbuU_2MQ03t38qr}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{TTlAguZQ5vR9EOv6G8cel → QmuF-eAbuU_2MQ03t38qr}/_ssgManifest.js +0 -0
|
@@ -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
|
};
|
|
@@ -716,23 +720,25 @@ export function registerDbTools(pi) {
|
|
|
716
720
|
"Idempotent — calling with the same params twice will upsert (INSERT OR REPLACE) without error.",
|
|
717
721
|
],
|
|
718
722
|
parameters: Type.Object({
|
|
723
|
+
// ── Core identification + content (required) ──────────────────────
|
|
719
724
|
taskId: Type.String({ description: "Task ID (e.g. T01)" }),
|
|
720
725
|
sliceId: Type.String({ description: "Slice ID (e.g. S01)" }),
|
|
721
726
|
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
722
727
|
oneLiner: Type.String({ description: "One-line summary of what was accomplished" }),
|
|
723
728
|
narrative: Type.String({ description: "Detailed narrative of what happened during the task" }),
|
|
724
729
|
verification: Type.String({ description: "What was verified and how — commands run, tests passed, behavior confirmed" }),
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
730
|
+
// ── Enrichment metadata (optional — defaults to empty) ────────────
|
|
731
|
+
deviations: Type.Optional(Type.String({ description: "Deviations from the task plan, or 'None.'" })),
|
|
732
|
+
knownIssues: Type.Optional(Type.String({ description: "Known issues discovered but not fixed, or 'None.'" })),
|
|
733
|
+
keyFiles: Type.Optional(Type.Array(Type.String(), { description: "List of key files created or modified" })),
|
|
734
|
+
keyDecisions: Type.Optional(Type.Array(Type.String(), { description: "List of key decisions made during this task" })),
|
|
735
|
+
blockerDiscovered: Type.Optional(Type.Boolean({ description: "Whether a plan-invalidating blocker was discovered" })),
|
|
736
|
+
verificationEvidence: Type.Optional(Type.Array(Type.Object({
|
|
731
737
|
command: Type.String({ description: "Verification command that was run" }),
|
|
732
738
|
exitCode: Type.Number({ description: "Exit code of the command" }),
|
|
733
739
|
verdict: Type.String({ description: "Pass/fail verdict (e.g. '✅ pass', '❌ fail')" }),
|
|
734
740
|
durationMs: Type.Number({ description: "Duration of the command in milliseconds" }),
|
|
735
|
-
}), { description: "Array of verification evidence entries" }),
|
|
741
|
+
}), { description: "Array of verification evidence entries" })),
|
|
736
742
|
}),
|
|
737
743
|
execute: taskCompleteExecute,
|
|
738
744
|
};
|
|
@@ -789,44 +795,46 @@ export function registerDbTools(pi) {
|
|
|
789
795
|
"Idempotent — calling with the same params twice will not crash.",
|
|
790
796
|
],
|
|
791
797
|
parameters: Type.Object({
|
|
798
|
+
// ── Core identification + content (required) ──────────────────────
|
|
792
799
|
sliceId: Type.String({ description: "Slice ID (e.g. S01)" }),
|
|
793
800
|
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
794
801
|
sliceTitle: Type.String({ description: "Title of the slice" }),
|
|
795
802
|
oneLiner: Type.String({ description: "One-line summary of what the slice accomplished" }),
|
|
796
803
|
narrative: Type.String({ description: "Detailed narrative of what happened across all tasks" }),
|
|
797
804
|
verification: Type.String({ description: "What was verified across all tasks" }),
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
805
|
+
uatContent: Type.String({ description: "UAT test content (markdown body)" }),
|
|
806
|
+
// ── Enrichment metadata (optional — defaults to empty) ────────────
|
|
807
|
+
deviations: Type.Optional(Type.String({ description: "Deviations from the slice plan, or 'None.'" })),
|
|
808
|
+
knownLimitations: Type.Optional(Type.String({ description: "Known limitations or gaps, or 'None.'" })),
|
|
809
|
+
followUps: Type.Optional(Type.String({ description: "Follow-up work discovered during execution, or 'None.'" })),
|
|
810
|
+
keyFiles: Type.Optional(Type.Array(Type.String(), { description: "Key files created or modified" })),
|
|
811
|
+
keyDecisions: Type.Optional(Type.Array(Type.String(), { description: "Key decisions made during this slice" })),
|
|
812
|
+
patternsEstablished: Type.Optional(Type.Array(Type.String(), { description: "Patterns established by this slice" })),
|
|
813
|
+
observabilitySurfaces: Type.Optional(Type.Array(Type.String(), { description: "Observability surfaces added" })),
|
|
814
|
+
provides: Type.Optional(Type.Array(Type.String(), { description: "What this slice provides to downstream slices" })),
|
|
815
|
+
requirementsSurfaced: Type.Optional(Type.Array(Type.String(), { description: "New requirements surfaced" })),
|
|
816
|
+
drillDownPaths: Type.Optional(Type.Array(Type.String(), { description: "Paths to task summaries for drill-down" })),
|
|
817
|
+
affects: Type.Optional(Type.Array(Type.String(), { description: "Downstream slices affected" })),
|
|
818
|
+
requirementsAdvanced: Type.Optional(Type.Array(Type.Object({
|
|
810
819
|
id: Type.String({ description: "Requirement ID" }),
|
|
811
820
|
how: Type.String({ description: "How it was advanced" }),
|
|
812
|
-
}), { description: "Requirements advanced by this slice" }),
|
|
813
|
-
requirementsValidated: Type.Array(Type.Object({
|
|
821
|
+
}), { description: "Requirements advanced by this slice" })),
|
|
822
|
+
requirementsValidated: Type.Optional(Type.Array(Type.Object({
|
|
814
823
|
id: Type.String({ description: "Requirement ID" }),
|
|
815
824
|
proof: Type.String({ description: "What proof validates it" }),
|
|
816
|
-
}), { description: "Requirements validated by this slice" }),
|
|
817
|
-
requirementsInvalidated: Type.Array(Type.Object({
|
|
825
|
+
}), { description: "Requirements validated by this slice" })),
|
|
826
|
+
requirementsInvalidated: Type.Optional(Type.Array(Type.Object({
|
|
818
827
|
id: Type.String({ description: "Requirement ID" }),
|
|
819
828
|
what: Type.String({ description: "What changed" }),
|
|
820
|
-
}), { description: "Requirements invalidated or re-scoped" }),
|
|
821
|
-
filesModified: Type.Array(Type.Object({
|
|
829
|
+
}), { description: "Requirements invalidated or re-scoped" })),
|
|
830
|
+
filesModified: Type.Optional(Type.Array(Type.Object({
|
|
822
831
|
path: Type.String({ description: "File path" }),
|
|
823
832
|
description: Type.String({ description: "What changed" }),
|
|
824
|
-
}), { description: "Files modified with descriptions" }),
|
|
825
|
-
requires: Type.Array(Type.Object({
|
|
833
|
+
}), { description: "Files modified with descriptions" })),
|
|
834
|
+
requires: Type.Optional(Type.Array(Type.Object({
|
|
826
835
|
slice: Type.String({ description: "Dependency slice ID" }),
|
|
827
836
|
provides: Type.String({ description: "What was consumed from it" }),
|
|
828
|
-
}), { description: "Upstream slice dependencies consumed" }),
|
|
829
|
-
uatContent: Type.String({ description: "UAT test content (markdown body)" }),
|
|
837
|
+
}), { description: "Upstream slice dependencies consumed" })),
|
|
830
838
|
}),
|
|
831
839
|
execute: sliceCompleteExecute,
|
|
832
840
|
};
|
|
@@ -912,8 +920,11 @@ export function registerDbTools(pi) {
|
|
|
912
920
|
};
|
|
913
921
|
}
|
|
914
922
|
try {
|
|
923
|
+
// ── Input sanitization: normalize markdown parameters (#3013) ──────
|
|
924
|
+
const { sanitizeCompleteMilestoneParams } = await import("./sanitize-complete-milestone.js");
|
|
925
|
+
const sanitized = sanitizeCompleteMilestoneParams(params);
|
|
915
926
|
const { handleCompleteMilestone } = await import("../tools/complete-milestone.js");
|
|
916
|
-
const result = await handleCompleteMilestone(
|
|
927
|
+
const result = await handleCompleteMilestone(sanitized, process.cwd());
|
|
917
928
|
if ("error" in result) {
|
|
918
929
|
return {
|
|
919
930
|
content: [{ type: "text", text: `Error completing milestone: ${result.error}` }],
|
|
@@ -951,19 +962,21 @@ export function registerDbTools(pi) {
|
|
|
951
962
|
"On success, returns summaryPath where the MILESTONE-SUMMARY.md was written.",
|
|
952
963
|
],
|
|
953
964
|
parameters: Type.Object({
|
|
965
|
+
// ── Core identification + content (required) ──────────────────────
|
|
954
966
|
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
955
967
|
title: Type.String({ description: "Milestone title" }),
|
|
956
968
|
oneLiner: Type.String({ description: "One-sentence summary of what the milestone achieved" }),
|
|
957
969
|
narrative: Type.String({ description: "Detailed narrative of what happened during the milestone" }),
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
970
|
+
verificationPassed: Type.Boolean({ description: "Must be true — confirms that code change verification, success criteria, and definition of done checks all passed before completion" }),
|
|
971
|
+
// ── Enrichment metadata (optional — defaults to empty) ────────────
|
|
972
|
+
successCriteriaResults: Type.Optional(Type.String({ description: "Markdown detailing how each success criterion was met or not met" })),
|
|
973
|
+
definitionOfDoneResults: Type.Optional(Type.String({ description: "Markdown detailing how each definition-of-done item was met" })),
|
|
974
|
+
requirementOutcomes: Type.Optional(Type.String({ description: "Markdown detailing requirement status transitions with evidence" })),
|
|
975
|
+
keyDecisions: Type.Optional(Type.Array(Type.String(), { description: "Key architectural/pattern decisions made during the milestone" })),
|
|
976
|
+
keyFiles: Type.Optional(Type.Array(Type.String(), { description: "Key files created or modified during the milestone" })),
|
|
977
|
+
lessonsLearned: Type.Optional(Type.Array(Type.String(), { description: "Lessons learned during the milestone" })),
|
|
964
978
|
followUps: Type.Optional(Type.String({ description: "Follow-up items for future milestones" })),
|
|
965
979
|
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
980
|
}),
|
|
968
981
|
execute: milestoneCompleteExecute,
|
|
969
982
|
};
|
|
@@ -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}`;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// GSD2 — Read-only query tools exposing DB state to the LLM via the WAL connection
|
|
2
|
+
import { Type } from "@sinclair/typebox";
|
|
3
|
+
import { logWarning } from "../workflow-logger.js";
|
|
4
|
+
export function registerQueryTools(pi) {
|
|
5
|
+
pi.registerTool({
|
|
6
|
+
name: "gsd_milestone_status",
|
|
7
|
+
label: "Milestone Status",
|
|
8
|
+
description: "Read the current status of a milestone and all its slices from the GSD database. " +
|
|
9
|
+
"Returns milestone metadata, per-slice status, and task counts per slice. " +
|
|
10
|
+
"Use this instead of querying .gsd/gsd.db directly via sqlite3 or better-sqlite3.",
|
|
11
|
+
promptSnippet: "Get milestone status, slice statuses, and task counts for a given milestoneId",
|
|
12
|
+
promptGuidelines: [
|
|
13
|
+
"Use this tool — not sqlite3 or better-sqlite3 — to inspect milestone or slice state from the DB.",
|
|
14
|
+
],
|
|
15
|
+
parameters: Type.Object({
|
|
16
|
+
milestoneId: Type.String({ description: "Milestone ID to query (e.g. M001)" }),
|
|
17
|
+
}),
|
|
18
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
19
|
+
try {
|
|
20
|
+
// Strictly read-only: only use an already-open DB connection.
|
|
21
|
+
// Do NOT call ensureDbOpen() — it can create/migrate the DB as a side effect.
|
|
22
|
+
const { isDbAvailable, getMilestone, getSliceStatusSummary, getSliceTaskCounts, _getAdapter, } = await import("../gsd-db.js");
|
|
23
|
+
if (!isDbAvailable()) {
|
|
24
|
+
return {
|
|
25
|
+
content: [{ type: "text", text: "Error: GSD database is not available." }],
|
|
26
|
+
details: { operation: "milestone_status", error: "db_unavailable" },
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
// Wrap all reads in a single transaction for snapshot consistency.
|
|
30
|
+
// SQLite WAL mode guarantees reads within a transaction see a single
|
|
31
|
+
// consistent snapshot, preventing torn reads from concurrent writes.
|
|
32
|
+
const adapter = _getAdapter();
|
|
33
|
+
adapter.exec("BEGIN"); // eslint-disable-line -- SQLite exec, not child_process
|
|
34
|
+
try {
|
|
35
|
+
const milestone = getMilestone(params.milestoneId);
|
|
36
|
+
if (!milestone) {
|
|
37
|
+
adapter.exec("COMMIT"); // eslint-disable-line
|
|
38
|
+
return {
|
|
39
|
+
content: [{ type: "text", text: `Milestone ${params.milestoneId} not found in database.` }],
|
|
40
|
+
details: { operation: "milestone_status", milestoneId: params.milestoneId, found: false },
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const sliceStatuses = getSliceStatusSummary(params.milestoneId);
|
|
44
|
+
const slices = sliceStatuses.map((s) => {
|
|
45
|
+
const counts = getSliceTaskCounts(params.milestoneId, s.id);
|
|
46
|
+
return {
|
|
47
|
+
id: s.id,
|
|
48
|
+
status: s.status,
|
|
49
|
+
taskCounts: counts,
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
adapter.exec("COMMIT"); // eslint-disable-line
|
|
53
|
+
const result = {
|
|
54
|
+
milestoneId: milestone.id,
|
|
55
|
+
title: milestone.title,
|
|
56
|
+
status: milestone.status,
|
|
57
|
+
createdAt: milestone.created_at,
|
|
58
|
+
completedAt: milestone.completed_at,
|
|
59
|
+
sliceCount: slices.length,
|
|
60
|
+
slices,
|
|
61
|
+
};
|
|
62
|
+
return {
|
|
63
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
64
|
+
details: { operation: "milestone_status", milestoneId: milestone.id, sliceCount: slices.length },
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
catch (txErr) {
|
|
68
|
+
try {
|
|
69
|
+
adapter.exec("ROLLBACK");
|
|
70
|
+
}
|
|
71
|
+
catch { /* swallow */ } // eslint-disable-line
|
|
72
|
+
throw txErr;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
77
|
+
logWarning("tool", `gsd_milestone_status tool failed: ${msg}`);
|
|
78
|
+
return {
|
|
79
|
+
content: [{ type: "text", text: `Error querying milestone status: ${msg}` }],
|
|
80
|
+
details: { operation: "milestone_status", error: msg },
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
// GSD2 — Extension registration: wires all GSD tools, commands, and hooks into pi
|
|
1
2
|
import { registerGSDCommand } from "../commands.js";
|
|
2
3
|
import { registerExitCommand } from "../exit-command.js";
|
|
3
4
|
import { registerWorktreeCommand } from "../worktree-command.js";
|
|
4
5
|
import { registerDbTools } from "./db-tools.js";
|
|
5
6
|
import { registerDynamicTools } from "./dynamic-tools.js";
|
|
6
7
|
import { registerJournalTools } from "./journal-tools.js";
|
|
8
|
+
import { registerQueryTools } from "./query-tools.js";
|
|
7
9
|
import { registerHooks } from "./register-hooks.js";
|
|
8
10
|
import { registerShortcuts } from "./register-shortcuts.js";
|
|
9
11
|
export function handleRecoverableExtensionProcessError(err) {
|
|
@@ -48,6 +50,7 @@ export function registerGsdExtension(pi) {
|
|
|
48
50
|
registerDynamicTools(pi);
|
|
49
51
|
registerDbTools(pi);
|
|
50
52
|
registerJournalTools(pi);
|
|
53
|
+
registerQueryTools(pi);
|
|
51
54
|
registerShortcuts(pi);
|
|
52
55
|
registerHooks(pi);
|
|
53
56
|
}
|
|
@@ -10,7 +10,7 @@ import { getDiscussionMilestoneId } from "../guided-flow.js";
|
|
|
10
10
|
import { loadToolApiKeys } from "../commands-config.js";
|
|
11
11
|
import { loadFile, saveFile, formatContinue } from "../files.js";
|
|
12
12
|
import { deriveState } from "../state.js";
|
|
13
|
-
import { getAutoDashboardData, isAutoActive, isAutoPaused, markToolEnd, markToolStart } from "../auto.js";
|
|
13
|
+
import { getAutoDashboardData, isAutoActive, isAutoPaused, markToolEnd, markToolStart, recordToolInvocationError } from "../auto.js";
|
|
14
14
|
import { isParallelActive, shutdownParallel } from "../parallel-orchestrator.js";
|
|
15
15
|
import { checkToolCallLoop, resetToolCallLoopGuard } from "./tool-call-loop-guard.js";
|
|
16
16
|
import { saveActivityLog } from "../activity-log.js";
|
|
@@ -243,6 +243,14 @@ export function registerHooks(pi) {
|
|
|
243
243
|
});
|
|
244
244
|
pi.on("tool_execution_end", async (event) => {
|
|
245
245
|
markToolEnd(event.toolCallId);
|
|
246
|
+
// #2883: Capture tool invocation errors (malformed/truncated JSON arguments)
|
|
247
|
+
// so postUnitPreVerification can break the retry loop instead of re-dispatching.
|
|
248
|
+
if (event.isError && event.toolName.startsWith("gsd_")) {
|
|
249
|
+
const errorText = typeof event.result === "string"
|
|
250
|
+
? event.result
|
|
251
|
+
: (typeof event.result?.content?.[0]?.text === "string" ? event.result.content[0].text : String(event.result));
|
|
252
|
+
recordToolInvocationError(event.toolName, errorText);
|
|
253
|
+
}
|
|
246
254
|
});
|
|
247
255
|
pi.on("model_select", async (_event, ctx) => {
|
|
248
256
|
await syncServiceTierStatus(ctx);
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input sanitization for gsd_complete_milestone parameters.
|
|
3
|
+
*
|
|
4
|
+
* The Claude SDK deserializes tool-call JSON before the handler runs.
|
|
5
|
+
* When an LLM (especially smaller models like haiku) generates large markdown
|
|
6
|
+
* parameters, the JSON can arrive with subtly wrong types — numbers where
|
|
7
|
+
* strings are expected, null where arrays belong, string "true" instead of
|
|
8
|
+
* boolean true, etc. This sanitizer normalizes all fields so
|
|
9
|
+
* handleCompleteMilestone never crashes on type mismatches.
|
|
10
|
+
*
|
|
11
|
+
* See: https://github.com/gsd-build/gsd-2/issues/3013
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Coerce an unknown value to a trimmed string.
|
|
15
|
+
* Returns "" for null / undefined.
|
|
16
|
+
*/
|
|
17
|
+
function toStr(v) {
|
|
18
|
+
if (v == null)
|
|
19
|
+
return "";
|
|
20
|
+
return String(v).trim();
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Coerce an unknown value to an array of trimmed, non-empty strings.
|
|
24
|
+
* - If already an array, filter/trim each element.
|
|
25
|
+
* - Otherwise return [].
|
|
26
|
+
*/
|
|
27
|
+
function toStrArray(v) {
|
|
28
|
+
if (!Array.isArray(v))
|
|
29
|
+
return [];
|
|
30
|
+
return v
|
|
31
|
+
.map((item) => (item == null ? "" : String(item).trim()))
|
|
32
|
+
.filter((s) => s.length > 0);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Sanitize raw params from the tool-call framework into well-typed
|
|
36
|
+
* CompleteMilestoneParams, tolerating type mismatches from LLM JSON quirks.
|
|
37
|
+
*/
|
|
38
|
+
export function sanitizeCompleteMilestoneParams(raw) {
|
|
39
|
+
return {
|
|
40
|
+
milestoneId: toStr(raw.milestoneId),
|
|
41
|
+
title: toStr(raw.title),
|
|
42
|
+
oneLiner: toStr(raw.oneLiner),
|
|
43
|
+
narrative: toStr(raw.narrative),
|
|
44
|
+
successCriteriaResults: toStr(raw.successCriteriaResults),
|
|
45
|
+
definitionOfDoneResults: toStr(raw.definitionOfDoneResults),
|
|
46
|
+
requirementOutcomes: toStr(raw.requirementOutcomes),
|
|
47
|
+
keyDecisions: toStrArray(raw.keyDecisions),
|
|
48
|
+
keyFiles: toStrArray(raw.keyFiles),
|
|
49
|
+
lessonsLearned: toStrArray(raw.lessonsLearned),
|
|
50
|
+
followUps: toStr(raw.followUps),
|
|
51
|
+
deviations: toStr(raw.deviations),
|
|
52
|
+
verificationPassed: raw.verificationPassed === true || raw.verificationPassed === "true",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -27,21 +27,26 @@ export function dispatchDoctorHeal(pi, scope, reportText, structuredIssues) {
|
|
|
27
27
|
const content = `Read the following GSD workflow protocol and execute exactly.\n\n${workflow}\n\n## Your Task\n\n${prompt}`;
|
|
28
28
|
pi.sendMessage({ customType: "gsd-doctor-heal", content, display: false }, { triggerTurn: true });
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
/** Parse doctor command args into structured flags and positionals (pure, no I/O). */
|
|
31
|
+
export function parseDoctorArgs(args) {
|
|
31
32
|
const trimmed = args.trim();
|
|
32
|
-
// Extract flags before positional parsing
|
|
33
33
|
const jsonMode = trimmed.includes("--json");
|
|
34
34
|
const dryRun = trimmed.includes("--dry-run");
|
|
35
|
+
const fixFlag = trimmed.includes("--fix");
|
|
35
36
|
const includeBuild = trimmed.includes("--build");
|
|
36
37
|
const includeTests = trimmed.includes("--test");
|
|
37
|
-
const stripped = trimmed.replace(/--json|--dry-run|--build|--test/g, "").trim();
|
|
38
|
+
const stripped = trimmed.replace(/--json|--dry-run|--build|--test|--fix/g, "").trim();
|
|
38
39
|
const parts = stripped ? stripped.split(/\s+/) : [];
|
|
39
40
|
const mode = parts[0] === "fix" || parts[0] === "heal" || parts[0] === "audit" ? parts[0] : "doctor";
|
|
40
41
|
const requestedScope = mode === "doctor" ? parts[0] : parts[1];
|
|
42
|
+
return { jsonMode, dryRun, fixFlag, includeBuild, includeTests, mode, requestedScope };
|
|
43
|
+
}
|
|
44
|
+
export async function handleDoctor(args, ctx, pi) {
|
|
45
|
+
const { jsonMode, dryRun, fixFlag, includeBuild, includeTests, mode, requestedScope } = parseDoctorArgs(args);
|
|
41
46
|
const scope = await selectDoctorScope(projectRoot(), requestedScope);
|
|
42
47
|
const effectiveScope = mode === "audit" ? requestedScope : scope;
|
|
43
48
|
const report = await runGSDDoctor(projectRoot(), {
|
|
44
|
-
fix: mode === "fix" || mode === "heal" || dryRun,
|
|
49
|
+
fix: mode === "fix" || mode === "heal" || dryRun || fixFlag,
|
|
45
50
|
dryRun,
|
|
46
51
|
scope: effectiveScope,
|
|
47
52
|
includeBuild,
|
|
@@ -13,3 +13,45 @@ export const DEFAULT_BASH_TIMEOUT_SECS = 120;
|
|
|
13
13
|
export const DIR_CACHE_MAX = 200;
|
|
14
14
|
/** Max parse-cache entries before eviction. */
|
|
15
15
|
export const CACHE_MAX = 50;
|
|
16
|
+
// ─── Tool Scoping ─────────────────────────────────────────────────────────────
|
|
17
|
+
/**
|
|
18
|
+
* GSD tools allowed during discuss flows (#2949).
|
|
19
|
+
*
|
|
20
|
+
* xAI/Grok (and potentially other providers with grammar-based constrained
|
|
21
|
+
* decoding) return "Grammar is too complex" (HTTP 400) when the combined
|
|
22
|
+
* tool schemas exceed their internal grammar limit. The full GSD tool set
|
|
23
|
+
* registers ~33 tools with deeply nested schemas; discuss flows only need
|
|
24
|
+
* a small subset.
|
|
25
|
+
*
|
|
26
|
+
* By scoping tools to this allowlist during discuss dispatches, the grammar
|
|
27
|
+
* sent to the provider stays well under provider limits.
|
|
28
|
+
*
|
|
29
|
+
* Included tools and why:
|
|
30
|
+
* - gsd_summary_save: writes CONTEXT.md artifacts (all discuss prompts)
|
|
31
|
+
* - gsd_save_summary: alias for above
|
|
32
|
+
* - gsd_decision_save: records decisions (discuss.md output phase)
|
|
33
|
+
* - gsd_save_decision: alias for above
|
|
34
|
+
* - gsd_plan_milestone: writes roadmap (discuss.md single/multi milestone)
|
|
35
|
+
* - gsd_milestone_plan: alias for above
|
|
36
|
+
* - gsd_milestone_generate_id: generates milestone IDs (discuss.md multi-milestone)
|
|
37
|
+
* - gsd_generate_milestone_id: alias for above
|
|
38
|
+
* - gsd_requirement_update: updates requirements during discuss
|
|
39
|
+
* - gsd_update_requirement: alias for above
|
|
40
|
+
*/
|
|
41
|
+
export const DISCUSS_TOOLS_ALLOWLIST = [
|
|
42
|
+
// Context / summary writing
|
|
43
|
+
"gsd_summary_save",
|
|
44
|
+
"gsd_save_summary",
|
|
45
|
+
// Decision recording
|
|
46
|
+
"gsd_decision_save",
|
|
47
|
+
"gsd_save_decision",
|
|
48
|
+
// Milestone planning (needed for discuss.md output phase)
|
|
49
|
+
"gsd_plan_milestone",
|
|
50
|
+
"gsd_milestone_plan",
|
|
51
|
+
// Milestone ID generation (multi-milestone flow)
|
|
52
|
+
"gsd_milestone_generate_id",
|
|
53
|
+
"gsd_generate_milestone_id",
|
|
54
|
+
// Requirement updates
|
|
55
|
+
"gsd_requirement_update",
|
|
56
|
+
"gsd_update_requirement",
|
|
57
|
+
];
|