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
|
@@ -12,7 +12,7 @@ import { parseUnitId } from "./unit-id.js";
|
|
|
12
12
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
13
13
|
import { clearParseCache } from "./files.js";
|
|
14
14
|
import { parseRoadmap as parseLegacyRoadmap, parsePlan as parseLegacyPlan } from "./parsers-legacy.js";
|
|
15
|
-
import { isDbAvailable, getTask, getSlice, getSliceTasks, updateTaskStatus } from "./gsd-db.js";
|
|
15
|
+
import { isDbAvailable, getTask, getSlice, getSliceTasks, updateTaskStatus, updateSliceStatus } from "./gsd-db.js";
|
|
16
16
|
import { isValidationTerminal } from "./state.js";
|
|
17
17
|
import { getErrorMessage } from "./error-utils.js";
|
|
18
18
|
import { logWarning, logError } from "./workflow-logger.js";
|
|
@@ -424,15 +424,16 @@ export function writeBlockerPlaceholder(
|
|
|
424
424
|
].join("\n");
|
|
425
425
|
writeFileSync(absPath, content, "utf-8");
|
|
426
426
|
|
|
427
|
-
// Mark the task as complete in the DB so verifyExpectedArtifact passes.
|
|
427
|
+
// Mark the task/slice as complete in the DB so verifyExpectedArtifact passes.
|
|
428
428
|
// Without this, the DB status stays "pending" and the dispatch loop
|
|
429
|
-
// re-derives the same
|
|
430
|
-
if (
|
|
429
|
+
// re-derives the same unit indefinitely (#2531, #2653).
|
|
430
|
+
if (isDbAvailable()) {
|
|
431
431
|
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
|
432
|
-
if (mid && sid && tid) {
|
|
433
|
-
try { updateTaskStatus(mid, sid, tid, "complete", new Date().toISOString()); } catch (
|
|
434
|
-
|
|
435
|
-
|
|
432
|
+
if (unitType === "execute-task" && mid && sid && tid) {
|
|
433
|
+
try { updateTaskStatus(mid, sid, tid, "complete", new Date().toISOString()); } catch (e) { logWarning("recovery", `updateTaskStatus failed during context exhaustion: ${e instanceof Error ? e.message : String(e)}`); }
|
|
434
|
+
}
|
|
435
|
+
if (unitType === "complete-slice" && mid && sid) {
|
|
436
|
+
try { updateSliceStatus(mid, sid, "complete", new Date().toISOString()); } catch (e) { logWarning("recovery", `updateSliceStatus failed during context exhaustion: ${e instanceof Error ? e.message : String(e)}`); }
|
|
436
437
|
}
|
|
437
438
|
}
|
|
438
439
|
|
|
@@ -58,7 +58,7 @@ import { initRoutingHistory } from "./routing-history.js";
|
|
|
58
58
|
import { restoreHookState, resetHookState } from "./post-unit-hooks.js";
|
|
59
59
|
import { resetProactiveHealing, setLevelChangeCallback } from "./doctor-proactive.js";
|
|
60
60
|
import { snapshotSkills } from "./skill-discovery.js";
|
|
61
|
-
import { isDbAvailable, getMilestone } from "./gsd-db.js";
|
|
61
|
+
import { isDbAvailable, getMilestone, openDatabase } from "./gsd-db.js";
|
|
62
62
|
import { hideFooter } from "./auto-dashboard.js";
|
|
63
63
|
import {
|
|
64
64
|
debugLog,
|
|
@@ -99,33 +99,24 @@ export interface BootstrapDeps {
|
|
|
99
99
|
* concurrent session detected). Returns true when ready to dispatch.
|
|
100
100
|
*/
|
|
101
101
|
|
|
102
|
-
/**
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
async function openProjectDbIfPresent(basePath: string): Promise<void> {
|
|
102
|
+
/** Guard: tracks consecutive bootstrap attempts that found phase === "complete".
|
|
103
|
+
* Prevents the recursive dialog loop described in #1348 where
|
|
104
|
+
* bootstrapAutoSession → showSmartEntry → checkAutoStartAfterDiscuss → startAuto
|
|
105
|
+
* cycles indefinitely when the discuss workflow doesn't produce a milestone. */
|
|
106
|
+
let _consecutiveCompleteBootstraps = 0;
|
|
107
|
+
const MAX_CONSECUTIVE_COMPLETE_BOOTSTRAPS = 2;
|
|
108
|
+
|
|
109
|
+
export async function openProjectDbIfPresent(basePath: string): Promise<void> {
|
|
110
110
|
const gsdDbPath = resolveProjectRootDbPath(basePath);
|
|
111
|
-
if (!existsSync(gsdDbPath)) return;
|
|
112
|
-
if (isDbAvailable()) return;
|
|
111
|
+
if (!existsSync(gsdDbPath) || isDbAvailable()) return;
|
|
113
112
|
|
|
114
113
|
try {
|
|
115
|
-
const { openDatabase } = await import("./gsd-db.js");
|
|
116
114
|
openDatabase(gsdDbPath);
|
|
117
115
|
} catch (err) {
|
|
118
|
-
|
|
119
|
-
logWarning("engine", `DB open failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
116
|
+
logWarning("engine", `gsd-db: failed to open existing database: ${err instanceof Error ? err.message : String(err)}`);
|
|
120
117
|
}
|
|
121
118
|
}
|
|
122
119
|
|
|
123
|
-
/** Guard: tracks consecutive bootstrap attempts that found phase === "complete".
|
|
124
|
-
* Prevents the recursive dialog loop described in #1348 where
|
|
125
|
-
* bootstrapAutoSession → showSmartEntry → checkAutoStartAfterDiscuss → startAuto
|
|
126
|
-
* cycles indefinitely when the discuss workflow doesn't produce a milestone. */
|
|
127
|
-
let _consecutiveCompleteBootstraps = 0;
|
|
128
|
-
const MAX_CONSECUTIVE_COMPLETE_BOOTSTRAPS = 2;
|
|
129
120
|
export async function bootstrapAutoSession(
|
|
130
121
|
s: AutoSession,
|
|
131
122
|
ctx: ExtensionCommandContext,
|
|
@@ -83,3 +83,22 @@ export function hasInteractiveToolInFlight(): boolean {
|
|
|
83
83
|
export function clearInFlightTools(): void {
|
|
84
84
|
inFlightTools.clear();
|
|
85
85
|
}
|
|
86
|
+
|
|
87
|
+
// ─── Tool invocation error classification (#2883) ────────────────────────
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Patterns that indicate a tool invocation failed due to malformed or truncated
|
|
91
|
+
* JSON arguments — as opposed to a normal business-logic error from the tool
|
|
92
|
+
* handler. When these errors occur, retrying the same unit will produce the same
|
|
93
|
+
* failure, so the retry loop must be broken.
|
|
94
|
+
*/
|
|
95
|
+
const TOOL_INVOCATION_ERROR_RE = /Validation failed for tool|Expected ',' or '\}' in JSON|Unexpected end of JSON|Unexpected token.*in JSON/i;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Returns true if the error message indicates a tool invocation failure due to
|
|
99
|
+
* malformed/truncated arguments (as opposed to a normal tool execution error).
|
|
100
|
+
*/
|
|
101
|
+
export function isToolInvocationError(errorMsg: string): boolean {
|
|
102
|
+
if (!errorMsg) return false;
|
|
103
|
+
return TOOL_INVOCATION_ERROR_RE.test(errorMsg);
|
|
104
|
+
}
|
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
removeWorktree,
|
|
37
37
|
resolveGitDir,
|
|
38
38
|
worktreePath,
|
|
39
|
+
isInsideWorktreesDir,
|
|
39
40
|
} from "./worktree-manager.js";
|
|
40
41
|
import {
|
|
41
42
|
detectWorktreeName,
|
|
@@ -1204,12 +1205,19 @@ export function teardownAutoWorktree(
|
|
|
1204
1205
|
`Remove it manually with: rm -rf "${wtDir.replaceAll("\\", "/")}"`,
|
|
1205
1206
|
{ worktree: milestoneId },
|
|
1206
1207
|
);
|
|
1207
|
-
// Attempt a direct filesystem removal as a fallback
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1208
|
+
// Attempt a direct filesystem removal as a fallback — but ONLY if the
|
|
1209
|
+
// path is safely inside .gsd/worktrees/ to prevent #2365 data loss.
|
|
1210
|
+
if (isInsideWorktreesDir(originalBasePath, wtDir)) {
|
|
1211
|
+
try {
|
|
1212
|
+
rmSync(wtDir, { recursive: true, force: true });
|
|
1213
|
+
} catch (err) {
|
|
1214
|
+
// Non-fatal — the warning above tells the user how to clean up
|
|
1215
|
+
logWarning("worktree", `worktree directory removal failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1216
|
+
}
|
|
1217
|
+
} else {
|
|
1218
|
+
console.error(
|
|
1219
|
+
`[GSD] REFUSING fallback rmSync — path is outside .gsd/worktrees/: ${wtDir}`,
|
|
1220
|
+
);
|
|
1213
1221
|
}
|
|
1214
1222
|
}
|
|
1215
1223
|
}
|
|
@@ -75,6 +75,7 @@ import {
|
|
|
75
75
|
getOldestInFlightToolStart,
|
|
76
76
|
hasInteractiveToolInFlight,
|
|
77
77
|
clearInFlightTools,
|
|
78
|
+
isToolInvocationError,
|
|
78
79
|
} from "./auto-tool-tracking.js";
|
|
79
80
|
import { closeoutUnit } from "./auto-unit-closeout.js";
|
|
80
81
|
import { recoverTimedOutUnit } from "./auto-timeout-recovery.js";
|
|
@@ -185,8 +186,11 @@ import {
|
|
|
185
186
|
postUnitPreVerification,
|
|
186
187
|
postUnitPostVerification,
|
|
187
188
|
} from "./auto-post-unit.js";
|
|
188
|
-
import { bootstrapAutoSession, type BootstrapDeps } from "./auto-start.js";
|
|
189
|
+
import { bootstrapAutoSession, openProjectDbIfPresent, type BootstrapDeps } from "./auto-start.js";
|
|
189
190
|
import { autoLoop, resolveAgentEnd, resolveAgentEndCancelled, _resetPendingResolve, isSessionSwitchInFlight, type LoopDeps, type ErrorContext } from "./auto-loop.js";
|
|
191
|
+
// Slice-level parallelism (#2340)
|
|
192
|
+
import { getEligibleSlices } from "./slice-parallel-eligibility.js";
|
|
193
|
+
import { startSliceParallel } from "./slice-parallel-orchestrator.js";
|
|
190
194
|
import {
|
|
191
195
|
WorktreeResolver,
|
|
192
196
|
type WorktreeResolverDeps,
|
|
@@ -385,6 +389,19 @@ export function markToolEnd(toolCallId: string): void {
|
|
|
385
389
|
_markToolEnd(toolCallId);
|
|
386
390
|
}
|
|
387
391
|
|
|
392
|
+
/**
|
|
393
|
+
* Record a tool invocation error on the current session (#2883).
|
|
394
|
+
* Called from tool_execution_end when a GSD tool fails with isError.
|
|
395
|
+
* Only stores the error if it matches the tool-invocation-error pattern
|
|
396
|
+
* (malformed/truncated JSON), not normal business-logic errors.
|
|
397
|
+
*/
|
|
398
|
+
export function recordToolInvocationError(toolName: string, errorMsg: string): void {
|
|
399
|
+
if (!s.active) return;
|
|
400
|
+
if (isToolInvocationError(errorMsg)) {
|
|
401
|
+
s.lastToolInvocationError = `${toolName}: ${errorMsg}`;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
388
405
|
export function getOldestInFlightToolAgeMs(): number {
|
|
389
406
|
return _getOldestInFlightToolAgeMs();
|
|
390
407
|
}
|
|
@@ -1205,6 +1222,9 @@ export async function startAuto(
|
|
|
1205
1222
|
"info",
|
|
1206
1223
|
);
|
|
1207
1224
|
restoreHookState(s.basePath);
|
|
1225
|
+
// Open the project DB before rebuild/derive so resume uses DB-backed
|
|
1226
|
+
// state instead of falling back to stale markdown parsing (#2940).
|
|
1227
|
+
await openProjectDbIfPresent(s.basePath);
|
|
1208
1228
|
try {
|
|
1209
1229
|
await rebuildState(s.basePath);
|
|
1210
1230
|
syncCmuxSidebar(loadEffectiveGSDPreferences()?.preferences, await deriveState(s.basePath));
|
|
@@ -1351,6 +1371,7 @@ const widgetStateAccessors: WidgetStateAccessors = {
|
|
|
1351
1371
|
getBasePath: () => s.basePath,
|
|
1352
1372
|
isVerbose: () => s.verbose,
|
|
1353
1373
|
isSessionSwitching: isSessionSwitchInFlight,
|
|
1374
|
+
getCurrentDispatchedModelId: () => s.currentDispatchedModelId,
|
|
1354
1375
|
};
|
|
1355
1376
|
|
|
1356
1377
|
// ─── Preconditions ────────────────────────────────────────────────────────────
|
|
@@ -501,28 +501,10 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
501
501
|
"Use the canonical name gsd_plan_milestone; gsd_milestone_plan is only an alias.",
|
|
502
502
|
],
|
|
503
503
|
parameters: Type.Object({
|
|
504
|
+
// ── Core identification + content (required) ──────────────────────
|
|
504
505
|
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
505
506
|
title: Type.String({ description: "Milestone title" }),
|
|
506
|
-
status: Type.Optional(Type.String({ description: "Milestone status (defaults to active)" })),
|
|
507
|
-
dependsOn: Type.Optional(Type.Array(Type.String(), { description: "Milestone dependencies" })),
|
|
508
507
|
vision: Type.String({ description: "Milestone vision" }),
|
|
509
|
-
successCriteria: Type.Array(Type.String(), { description: "Top-level success criteria bullets" }),
|
|
510
|
-
keyRisks: Type.Array(Type.Object({
|
|
511
|
-
risk: Type.String({ description: "Risk statement" }),
|
|
512
|
-
whyItMatters: Type.String({ description: "Why the risk matters" }),
|
|
513
|
-
}), { description: "Structured risk entries" }),
|
|
514
|
-
proofStrategy: Type.Array(Type.Object({
|
|
515
|
-
riskOrUnknown: Type.String({ description: "Risk or unknown to retire" }),
|
|
516
|
-
retireIn: Type.String({ description: "Where it will be retired" }),
|
|
517
|
-
whatWillBeProven: Type.String({ description: "What proof will be produced" }),
|
|
518
|
-
}), { description: "Structured proof strategy entries" }),
|
|
519
|
-
verificationContract: Type.String({ description: "Verification contract text" }),
|
|
520
|
-
verificationIntegration: Type.String({ description: "Integration verification text" }),
|
|
521
|
-
verificationOperational: Type.String({ description: "Operational verification text" }),
|
|
522
|
-
verificationUat: Type.String({ description: "UAT verification text" }),
|
|
523
|
-
definitionOfDone: Type.Array(Type.String(), { description: "Definition of done bullets" }),
|
|
524
|
-
requirementCoverage: Type.String({ description: "Requirement coverage text" }),
|
|
525
|
-
boundaryMapMarkdown: Type.String({ description: "Boundary map markdown block" }),
|
|
526
508
|
slices: Type.Array(Type.Object({
|
|
527
509
|
sliceId: Type.String({ description: "Slice ID (e.g. S01)" }),
|
|
528
510
|
title: Type.String({ description: "Slice title" }),
|
|
@@ -535,6 +517,26 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
535
517
|
integrationClosure: Type.String({ description: "Slice integration closure" }),
|
|
536
518
|
observabilityImpact: Type.String({ description: "Slice observability impact" }),
|
|
537
519
|
}), { description: "Planned slices for the milestone" }),
|
|
520
|
+
// ── Enrichment metadata (optional — defaults to empty) ────────────
|
|
521
|
+
status: Type.Optional(Type.String({ description: "Milestone status (defaults to active)" })),
|
|
522
|
+
dependsOn: Type.Optional(Type.Array(Type.String(), { description: "Milestone dependencies" })),
|
|
523
|
+
successCriteria: Type.Optional(Type.Array(Type.String(), { description: "Top-level success criteria bullets" })),
|
|
524
|
+
keyRisks: Type.Optional(Type.Array(Type.Object({
|
|
525
|
+
risk: Type.String({ description: "Risk statement" }),
|
|
526
|
+
whyItMatters: Type.String({ description: "Why the risk matters" }),
|
|
527
|
+
}), { description: "Structured risk entries" })),
|
|
528
|
+
proofStrategy: Type.Optional(Type.Array(Type.Object({
|
|
529
|
+
riskOrUnknown: Type.String({ description: "Risk or unknown to retire" }),
|
|
530
|
+
retireIn: Type.String({ description: "Where it will be retired" }),
|
|
531
|
+
whatWillBeProven: Type.String({ description: "What proof will be produced" }),
|
|
532
|
+
}), { description: "Structured proof strategy entries" })),
|
|
533
|
+
verificationContract: Type.Optional(Type.String({ description: "Verification contract text" })),
|
|
534
|
+
verificationIntegration: Type.Optional(Type.String({ description: "Integration verification text" })),
|
|
535
|
+
verificationOperational: Type.Optional(Type.String({ description: "Operational verification text" })),
|
|
536
|
+
verificationUat: Type.Optional(Type.String({ description: "UAT verification text" })),
|
|
537
|
+
definitionOfDone: Type.Optional(Type.Array(Type.String(), { description: "Definition of done bullets" })),
|
|
538
|
+
requirementCoverage: Type.Optional(Type.String({ description: "Requirement coverage text" })),
|
|
539
|
+
boundaryMapMarkdown: Type.Optional(Type.String({ description: "Boundary map markdown block" })),
|
|
538
540
|
}),
|
|
539
541
|
execute: planMilestoneExecute,
|
|
540
542
|
};
|
|
@@ -594,13 +596,10 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
594
596
|
"Use the canonical name gsd_plan_slice; gsd_slice_plan is only an alias.",
|
|
595
597
|
],
|
|
596
598
|
parameters: Type.Object({
|
|
599
|
+
// ── Core identification + content (required) ──────────────────────
|
|
597
600
|
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
598
601
|
sliceId: Type.String({ description: "Slice ID (e.g. S01)" }),
|
|
599
602
|
goal: Type.String({ description: "Slice goal" }),
|
|
600
|
-
successCriteria: Type.String({ description: "Slice success criteria block" }),
|
|
601
|
-
proofLevel: Type.String({ description: "Slice proof level" }),
|
|
602
|
-
integrationClosure: Type.String({ description: "Slice integration closure" }),
|
|
603
|
-
observabilityImpact: Type.String({ description: "Slice observability impact" }),
|
|
604
603
|
tasks: Type.Array(Type.Object({
|
|
605
604
|
taskId: Type.String({ description: "Task ID (e.g. T01)" }),
|
|
606
605
|
title: Type.String({ description: "Task title" }),
|
|
@@ -612,6 +611,11 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
612
611
|
expectedOutput: Type.Array(Type.String(), { description: "Expected output files or artifacts" }),
|
|
613
612
|
observabilityImpact: Type.Optional(Type.String({ description: "Task observability impact" })),
|
|
614
613
|
}), { description: "Planned tasks for the slice" }),
|
|
614
|
+
// ── Enrichment metadata (optional — defaults to empty) ────────────
|
|
615
|
+
successCriteria: Type.Optional(Type.String({ description: "Slice success criteria block" })),
|
|
616
|
+
proofLevel: Type.Optional(Type.String({ description: "Slice proof level" })),
|
|
617
|
+
integrationClosure: Type.Optional(Type.String({ description: "Slice integration closure" })),
|
|
618
|
+
observabilityImpact: Type.Optional(Type.String({ description: "Slice observability impact" })),
|
|
615
619
|
}),
|
|
616
620
|
execute: planSliceExecute,
|
|
617
621
|
};
|
|
@@ -743,18 +747,20 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
743
747
|
"Idempotent — calling with the same params twice will upsert (INSERT OR REPLACE) without error.",
|
|
744
748
|
],
|
|
745
749
|
parameters: Type.Object({
|
|
750
|
+
// ── Core identification + content (required) ──────────────────────
|
|
746
751
|
taskId: Type.String({ description: "Task ID (e.g. T01)" }),
|
|
747
752
|
sliceId: Type.String({ description: "Slice ID (e.g. S01)" }),
|
|
748
753
|
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
749
754
|
oneLiner: Type.String({ description: "One-line summary of what was accomplished" }),
|
|
750
755
|
narrative: Type.String({ description: "Detailed narrative of what happened during the task" }),
|
|
751
756
|
verification: Type.String({ description: "What was verified and how — commands run, tests passed, behavior confirmed" }),
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
757
|
+
// ── Enrichment metadata (optional — defaults to empty) ────────────
|
|
758
|
+
deviations: Type.Optional(Type.String({ description: "Deviations from the task plan, or 'None.'" })),
|
|
759
|
+
knownIssues: Type.Optional(Type.String({ description: "Known issues discovered but not fixed, or 'None.'" })),
|
|
760
|
+
keyFiles: Type.Optional(Type.Array(Type.String(), { description: "List of key files created or modified" })),
|
|
761
|
+
keyDecisions: Type.Optional(Type.Array(Type.String(), { description: "List of key decisions made during this task" })),
|
|
762
|
+
blockerDiscovered: Type.Optional(Type.Boolean({ description: "Whether a plan-invalidating blocker was discovered" })),
|
|
763
|
+
verificationEvidence: Type.Optional(Type.Array(
|
|
758
764
|
Type.Object({
|
|
759
765
|
command: Type.String({ description: "Verification command that was run" }),
|
|
760
766
|
exitCode: Type.Number({ description: "Exit code of the command" }),
|
|
@@ -762,7 +768,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
762
768
|
durationMs: Type.Number({ description: "Duration of the command in milliseconds" }),
|
|
763
769
|
}),
|
|
764
770
|
{ description: "Array of verification evidence entries" },
|
|
765
|
-
),
|
|
771
|
+
)),
|
|
766
772
|
}),
|
|
767
773
|
execute: taskCompleteExecute,
|
|
768
774
|
};
|
|
@@ -823,59 +829,61 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
823
829
|
"Idempotent — calling with the same params twice will not crash.",
|
|
824
830
|
],
|
|
825
831
|
parameters: Type.Object({
|
|
832
|
+
// ── Core identification + content (required) ──────────────────────
|
|
826
833
|
sliceId: Type.String({ description: "Slice ID (e.g. S01)" }),
|
|
827
834
|
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
828
835
|
sliceTitle: Type.String({ description: "Title of the slice" }),
|
|
829
836
|
oneLiner: Type.String({ description: "One-line summary of what the slice accomplished" }),
|
|
830
837
|
narrative: Type.String({ description: "Detailed narrative of what happened across all tasks" }),
|
|
831
838
|
verification: Type.String({ description: "What was verified across all tasks" }),
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
839
|
+
uatContent: Type.String({ description: "UAT test content (markdown body)" }),
|
|
840
|
+
// ── Enrichment metadata (optional — defaults to empty) ────────────
|
|
841
|
+
deviations: Type.Optional(Type.String({ description: "Deviations from the slice plan, or 'None.'" })),
|
|
842
|
+
knownLimitations: Type.Optional(Type.String({ description: "Known limitations or gaps, or 'None.'" })),
|
|
843
|
+
followUps: Type.Optional(Type.String({ description: "Follow-up work discovered during execution, or 'None.'" })),
|
|
844
|
+
keyFiles: Type.Optional(Type.Array(Type.String(), { description: "Key files created or modified" })),
|
|
845
|
+
keyDecisions: Type.Optional(Type.Array(Type.String(), { description: "Key decisions made during this slice" })),
|
|
846
|
+
patternsEstablished: Type.Optional(Type.Array(Type.String(), { description: "Patterns established by this slice" })),
|
|
847
|
+
observabilitySurfaces: Type.Optional(Type.Array(Type.String(), { description: "Observability surfaces added" })),
|
|
848
|
+
provides: Type.Optional(Type.Array(Type.String(), { description: "What this slice provides to downstream slices" })),
|
|
849
|
+
requirementsSurfaced: Type.Optional(Type.Array(Type.String(), { description: "New requirements surfaced" })),
|
|
850
|
+
drillDownPaths: Type.Optional(Type.Array(Type.String(), { description: "Paths to task summaries for drill-down" })),
|
|
851
|
+
affects: Type.Optional(Type.Array(Type.String(), { description: "Downstream slices affected" })),
|
|
852
|
+
requirementsAdvanced: Type.Optional(Type.Array(
|
|
844
853
|
Type.Object({
|
|
845
854
|
id: Type.String({ description: "Requirement ID" }),
|
|
846
855
|
how: Type.String({ description: "How it was advanced" }),
|
|
847
856
|
}),
|
|
848
857
|
{ description: "Requirements advanced by this slice" },
|
|
849
|
-
),
|
|
850
|
-
requirementsValidated: Type.Array(
|
|
858
|
+
)),
|
|
859
|
+
requirementsValidated: Type.Optional(Type.Array(
|
|
851
860
|
Type.Object({
|
|
852
861
|
id: Type.String({ description: "Requirement ID" }),
|
|
853
862
|
proof: Type.String({ description: "What proof validates it" }),
|
|
854
863
|
}),
|
|
855
864
|
{ description: "Requirements validated by this slice" },
|
|
856
|
-
),
|
|
857
|
-
requirementsInvalidated: Type.Array(
|
|
865
|
+
)),
|
|
866
|
+
requirementsInvalidated: Type.Optional(Type.Array(
|
|
858
867
|
Type.Object({
|
|
859
868
|
id: Type.String({ description: "Requirement ID" }),
|
|
860
869
|
what: Type.String({ description: "What changed" }),
|
|
861
870
|
}),
|
|
862
871
|
{ description: "Requirements invalidated or re-scoped" },
|
|
863
|
-
),
|
|
864
|
-
filesModified: Type.Array(
|
|
872
|
+
)),
|
|
873
|
+
filesModified: Type.Optional(Type.Array(
|
|
865
874
|
Type.Object({
|
|
866
875
|
path: Type.String({ description: "File path" }),
|
|
867
876
|
description: Type.String({ description: "What changed" }),
|
|
868
877
|
}),
|
|
869
878
|
{ description: "Files modified with descriptions" },
|
|
870
|
-
),
|
|
871
|
-
requires: Type.Array(
|
|
879
|
+
)),
|
|
880
|
+
requires: Type.Optional(Type.Array(
|
|
872
881
|
Type.Object({
|
|
873
882
|
slice: Type.String({ description: "Dependency slice ID" }),
|
|
874
883
|
provides: Type.String({ description: "What was consumed from it" }),
|
|
875
884
|
}),
|
|
876
885
|
{ description: "Upstream slice dependencies consumed" },
|
|
877
|
-
),
|
|
878
|
-
uatContent: Type.String({ description: "UAT test content (markdown body)" }),
|
|
886
|
+
)),
|
|
879
887
|
}),
|
|
880
888
|
execute: sliceCompleteExecute,
|
|
881
889
|
};
|
|
@@ -972,8 +980,12 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
972
980
|
};
|
|
973
981
|
}
|
|
974
982
|
try {
|
|
983
|
+
// ── Input sanitization: normalize markdown parameters (#3013) ──────
|
|
984
|
+
const { sanitizeCompleteMilestoneParams } = await import("./sanitize-complete-milestone.js");
|
|
985
|
+
const sanitized = sanitizeCompleteMilestoneParams(params);
|
|
986
|
+
|
|
975
987
|
const { handleCompleteMilestone } = await import("../tools/complete-milestone.js");
|
|
976
|
-
const result = await handleCompleteMilestone(
|
|
988
|
+
const result = await handleCompleteMilestone(sanitized, process.cwd());
|
|
977
989
|
if ("error" in result) {
|
|
978
990
|
return {
|
|
979
991
|
content: [{ type: "text" as const, text: `Error completing milestone: ${result.error}` }],
|
|
@@ -1012,19 +1024,21 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
1012
1024
|
"On success, returns summaryPath where the MILESTONE-SUMMARY.md was written.",
|
|
1013
1025
|
],
|
|
1014
1026
|
parameters: Type.Object({
|
|
1027
|
+
// ── Core identification + content (required) ──────────────────────
|
|
1015
1028
|
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
1016
1029
|
title: Type.String({ description: "Milestone title" }),
|
|
1017
1030
|
oneLiner: Type.String({ description: "One-sentence summary of what the milestone achieved" }),
|
|
1018
1031
|
narrative: Type.String({ description: "Detailed narrative of what happened during the milestone" }),
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1032
|
+
verificationPassed: Type.Boolean({ description: "Must be true — confirms that code change verification, success criteria, and definition of done checks all passed before completion" }),
|
|
1033
|
+
// ── Enrichment metadata (optional — defaults to empty) ────────────
|
|
1034
|
+
successCriteriaResults: Type.Optional(Type.String({ description: "Markdown detailing how each success criterion was met or not met" })),
|
|
1035
|
+
definitionOfDoneResults: Type.Optional(Type.String({ description: "Markdown detailing how each definition-of-done item was met" })),
|
|
1036
|
+
requirementOutcomes: Type.Optional(Type.String({ description: "Markdown detailing requirement status transitions with evidence" })),
|
|
1037
|
+
keyDecisions: Type.Optional(Type.Array(Type.String(), { description: "Key architectural/pattern decisions made during the milestone" })),
|
|
1038
|
+
keyFiles: Type.Optional(Type.Array(Type.String(), { description: "Key files created or modified during the milestone" })),
|
|
1039
|
+
lessonsLearned: Type.Optional(Type.Array(Type.String(), { description: "Lessons learned during the milestone" })),
|
|
1025
1040
|
followUps: Type.Optional(Type.String({ description: "Follow-up items for future milestones" })),
|
|
1026
1041
|
deviations: Type.Optional(Type.String({ description: "Deviations from the original plan" })),
|
|
1027
|
-
verificationPassed: Type.Boolean({ description: "Must be true — confirms that code change verification, success criteria, and definition of done checks all passed before completion" }),
|
|
1028
1042
|
}),
|
|
1029
1043
|
execute: milestoneCompleteExecute,
|
|
1030
1044
|
};
|
|
@@ -32,6 +32,20 @@ export function resolveProjectRootDbPath(basePath: string): string {
|
|
|
32
32
|
return join(projectRoot, ".gsd", "gsd.db");
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
// External-state layout: ~/.gsd/projects/<hash>/worktrees/<MID>/...
|
|
36
|
+
// Resolve to ~/.gsd/projects/<hash>/gsd.db (the canonical project DB) (#2952).
|
|
37
|
+
// Must be checked before the generic symlink-resolved handler: both match
|
|
38
|
+
// /.gsd/projects/<hash>/worktrees/ but require different resolution targets.
|
|
39
|
+
const extRe = /[/\\]\.gsd[/\\]projects[/\\][a-f0-9]+[/\\]worktrees(?:[/\\]|$)/;
|
|
40
|
+
const extMatch = extRe.exec(basePath);
|
|
41
|
+
if (extMatch) {
|
|
42
|
+
const matchStr = extMatch[0];
|
|
43
|
+
// Find the "/worktrees" portion within the match and slice up to it
|
|
44
|
+
const wtIdx = matchStr.search(/[/\\]worktrees(?:[/\\]|$)/);
|
|
45
|
+
const projectStateRoot = basePath.slice(0, extMatch.index + wtIdx);
|
|
46
|
+
return join(projectStateRoot, "gsd.db");
|
|
47
|
+
}
|
|
48
|
+
|
|
35
49
|
// Symlink-resolved layout: /.gsd/projects/<hash>/worktrees/M001/...
|
|
36
50
|
// The project root is everything before /.gsd/projects/ (#2517)
|
|
37
51
|
const symlinkMarker = `${sep}.gsd${sep}projects${sep}`;
|
|
@@ -57,6 +71,7 @@ export function resolveProjectRootDbPath(basePath: string): string {
|
|
|
57
71
|
}
|
|
58
72
|
}
|
|
59
73
|
|
|
74
|
+
|
|
60
75
|
return join(basePath, ".gsd", "gsd.db");
|
|
61
76
|
}
|
|
62
77
|
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// GSD2 — Read-only query tools exposing DB state to the LLM via the WAL connection
|
|
2
|
+
|
|
3
|
+
import { Type } from "@sinclair/typebox";
|
|
4
|
+
import type { ExtensionAPI } from "@gsd/pi-coding-agent";
|
|
5
|
+
|
|
6
|
+
import { logWarning } from "../workflow-logger.js";
|
|
7
|
+
|
|
8
|
+
export function registerQueryTools(pi: ExtensionAPI): void {
|
|
9
|
+
pi.registerTool({
|
|
10
|
+
name: "gsd_milestone_status",
|
|
11
|
+
label: "Milestone Status",
|
|
12
|
+
description:
|
|
13
|
+
"Read the current status of a milestone and all its slices from the GSD database. " +
|
|
14
|
+
"Returns milestone metadata, per-slice status, and task counts per slice. " +
|
|
15
|
+
"Use this instead of querying .gsd/gsd.db directly via sqlite3 or better-sqlite3.",
|
|
16
|
+
promptSnippet: "Get milestone status, slice statuses, and task counts for a given milestoneId",
|
|
17
|
+
promptGuidelines: [
|
|
18
|
+
"Use this tool — not sqlite3 or better-sqlite3 — to inspect milestone or slice state from the DB.",
|
|
19
|
+
],
|
|
20
|
+
parameters: Type.Object({
|
|
21
|
+
milestoneId: Type.String({ description: "Milestone ID to query (e.g. M001)" }),
|
|
22
|
+
}),
|
|
23
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
24
|
+
try {
|
|
25
|
+
// Strictly read-only: only use an already-open DB connection.
|
|
26
|
+
// Do NOT call ensureDbOpen() — it can create/migrate the DB as a side effect.
|
|
27
|
+
const {
|
|
28
|
+
isDbAvailable,
|
|
29
|
+
getMilestone,
|
|
30
|
+
getSliceStatusSummary,
|
|
31
|
+
getSliceTaskCounts,
|
|
32
|
+
_getAdapter,
|
|
33
|
+
} = await import("../gsd-db.js");
|
|
34
|
+
|
|
35
|
+
if (!isDbAvailable()) {
|
|
36
|
+
return {
|
|
37
|
+
content: [{ type: "text" as const, text: "Error: GSD database is not available." }],
|
|
38
|
+
details: { operation: "milestone_status", error: "db_unavailable" } as any,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Wrap all reads in a single transaction for snapshot consistency.
|
|
43
|
+
// SQLite WAL mode guarantees reads within a transaction see a single
|
|
44
|
+
// consistent snapshot, preventing torn reads from concurrent writes.
|
|
45
|
+
const adapter = _getAdapter()!;
|
|
46
|
+
adapter.exec("BEGIN"); // eslint-disable-line -- SQLite exec, not child_process
|
|
47
|
+
try {
|
|
48
|
+
const milestone = getMilestone(params.milestoneId);
|
|
49
|
+
if (!milestone) {
|
|
50
|
+
adapter.exec("COMMIT"); // eslint-disable-line
|
|
51
|
+
return {
|
|
52
|
+
content: [{ type: "text" as const, text: `Milestone ${params.milestoneId} not found in database.` }],
|
|
53
|
+
details: { operation: "milestone_status", milestoneId: params.milestoneId, found: false } as any,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const sliceStatuses = getSliceStatusSummary(params.milestoneId);
|
|
58
|
+
|
|
59
|
+
const slices = sliceStatuses.map((s) => {
|
|
60
|
+
const counts = getSliceTaskCounts(params.milestoneId, s.id);
|
|
61
|
+
return {
|
|
62
|
+
id: s.id,
|
|
63
|
+
status: s.status,
|
|
64
|
+
taskCounts: counts,
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
adapter.exec("COMMIT"); // eslint-disable-line
|
|
69
|
+
|
|
70
|
+
const result = {
|
|
71
|
+
milestoneId: milestone.id,
|
|
72
|
+
title: milestone.title,
|
|
73
|
+
status: milestone.status,
|
|
74
|
+
createdAt: milestone.created_at,
|
|
75
|
+
completedAt: milestone.completed_at,
|
|
76
|
+
sliceCount: slices.length,
|
|
77
|
+
slices,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
|
|
82
|
+
details: { operation: "milestone_status", milestoneId: milestone.id, sliceCount: slices.length } as any,
|
|
83
|
+
};
|
|
84
|
+
} catch (txErr) {
|
|
85
|
+
try { adapter.exec("ROLLBACK"); } catch { /* swallow */ } // eslint-disable-line
|
|
86
|
+
throw txErr;
|
|
87
|
+
}
|
|
88
|
+
} catch (err) {
|
|
89
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
90
|
+
logWarning("tool", `gsd_milestone_status tool failed: ${msg}`);
|
|
91
|
+
return {
|
|
92
|
+
content: [{ type: "text" as const, text: `Error querying milestone status: ${msg}` }],
|
|
93
|
+
details: { operation: "milestone_status", error: msg } as any,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// GSD2 — Extension registration: wires all GSD tools, commands, and hooks into pi
|
|
2
|
+
|
|
1
3
|
import type { ExtensionAPI, ExtensionCommandContext } from "@gsd/pi-coding-agent";
|
|
2
4
|
|
|
3
5
|
import { registerGSDCommand } from "../commands.js";
|
|
@@ -6,6 +8,7 @@ import { registerWorktreeCommand } from "../worktree-command.js";
|
|
|
6
8
|
import { registerDbTools } from "./db-tools.js";
|
|
7
9
|
import { registerDynamicTools } from "./dynamic-tools.js";
|
|
8
10
|
import { registerJournalTools } from "./journal-tools.js";
|
|
11
|
+
import { registerQueryTools } from "./query-tools.js";
|
|
9
12
|
import { registerHooks } from "./register-hooks.js";
|
|
10
13
|
import { registerShortcuts } from "./register-shortcuts.js";
|
|
11
14
|
|
|
@@ -56,6 +59,7 @@ export function registerGsdExtension(pi: ExtensionAPI): void {
|
|
|
56
59
|
registerDynamicTools(pi);
|
|
57
60
|
registerDbTools(pi);
|
|
58
61
|
registerJournalTools(pi);
|
|
62
|
+
registerQueryTools(pi);
|
|
59
63
|
registerShortcuts(pi);
|
|
60
64
|
registerHooks(pi);
|
|
61
65
|
}
|
|
@@ -13,7 +13,7 @@ import { getDiscussionMilestoneId } from "../guided-flow.js";
|
|
|
13
13
|
import { loadToolApiKeys } from "../commands-config.js";
|
|
14
14
|
import { loadFile, saveFile, formatContinue } from "../files.js";
|
|
15
15
|
import { deriveState } from "../state.js";
|
|
16
|
-
import { getAutoDashboardData, isAutoActive, isAutoPaused, markToolEnd, markToolStart } from "../auto.js";
|
|
16
|
+
import { getAutoDashboardData, isAutoActive, isAutoPaused, markToolEnd, markToolStart, recordToolInvocationError } from "../auto.js";
|
|
17
17
|
import { isParallelActive, shutdownParallel } from "../parallel-orchestrator.js";
|
|
18
18
|
import { checkToolCallLoop, resetToolCallLoopGuard } from "./tool-call-loop-guard.js";
|
|
19
19
|
import { saveActivityLog } from "../activity-log.js";
|
|
@@ -260,6 +260,14 @@ export function registerHooks(pi: ExtensionAPI): void {
|
|
|
260
260
|
|
|
261
261
|
pi.on("tool_execution_end", async (event) => {
|
|
262
262
|
markToolEnd(event.toolCallId);
|
|
263
|
+
// #2883: Capture tool invocation errors (malformed/truncated JSON arguments)
|
|
264
|
+
// so postUnitPreVerification can break the retry loop instead of re-dispatching.
|
|
265
|
+
if (event.isError && event.toolName.startsWith("gsd_")) {
|
|
266
|
+
const errorText = typeof event.result === "string"
|
|
267
|
+
? event.result
|
|
268
|
+
: (typeof event.result?.content?.[0]?.text === "string" ? event.result.content[0].text : String(event.result));
|
|
269
|
+
recordToolInvocationError(event.toolName, errorText);
|
|
270
|
+
}
|
|
263
271
|
});
|
|
264
272
|
|
|
265
273
|
pi.on("model_select", async (_event, ctx) => {
|