gsd-pi 2.44.0 → 2.45.0-dev.6b9da3e
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 +30 -12
- package/dist/resources/extensions/gsd/activity-log.js +7 -0
- package/dist/resources/extensions/gsd/auto/infra-errors.js +3 -0
- package/dist/resources/extensions/gsd/auto/phases.js +37 -36
- package/dist/resources/extensions/gsd/auto-prompts.js +24 -1
- package/dist/resources/extensions/gsd/auto-start.js +31 -2
- package/dist/resources/extensions/gsd/auto-timers.js +57 -3
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +4 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +9 -6
- package/dist/resources/extensions/gsd/auto.js +30 -3
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +156 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -12
- package/dist/resources/extensions/gsd/commands/catalog.js +7 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +2 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +10 -0
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
- package/dist/resources/extensions/gsd/commands-mcp-status.js +187 -0
- package/dist/resources/extensions/gsd/db-writer.js +34 -16
- package/dist/resources/extensions/gsd/doctor.js +8 -0
- package/dist/resources/extensions/gsd/git-service.js +8 -3
- package/dist/resources/extensions/gsd/gsd-db.js +12 -1
- package/dist/resources/extensions/gsd/markdown-renderer.js +1 -1
- package/dist/resources/extensions/gsd/preferences.js +9 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +3 -14
- package/dist/resources/extensions/gsd/prompts/rethink.md +78 -0
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
- package/dist/resources/extensions/gsd/provider-error-pause.js +7 -0
- package/dist/resources/extensions/gsd/repo-identity.js +45 -7
- package/dist/resources/extensions/gsd/rethink.js +115 -0
- package/dist/resources/extensions/gsd/state.js +41 -3
- package/dist/resources/extensions/gsd/tools/plan-slice.js +1 -0
- package/dist/resources/extensions/gsd/tools/plan-task.js +1 -0
- package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -0
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +88 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +32 -2
- package/dist/resources/extensions/gsd/worktree-resolver.js +6 -0
- package/dist/resources/extensions/mcp-client/index.js +14 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
- package/dist/web/standalone/.next/build-manifest.json +4 -4
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
- package/dist/web/standalone/.next/required-server-files.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +5 -5
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +5 -5
- 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 +4 -4
- 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 +2 -2
- package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +6 -6
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +6 -6
- 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 +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +8 -8
- package/dist/web/standalone/.next/server/chunks/229.js +1 -1
- package/dist/web/standalone/.next/server/chunks/471.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/4024.11ca5c01938e5948.js +9 -0
- package/dist/web/standalone/.next/static/chunks/{3721.bf31263de6d5fa46.js → 485.243af25f0cdf50d6.js} +2 -2
- package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-6654a8cca61a3d1c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
- package/dist/web/standalone/.next/static/chunks/webpack-0a4cd455ec4197d2.js +1 -0
- package/dist/web/standalone/.next/static/css/dd4ae3f58ac9b600.css +1 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/package.json +1 -1
- package/packages/native/dist/stream-process/index.js +2 -2
- package/packages/native/src/__tests__/stream-process.test.mjs +34 -0
- package/packages/native/src/stream-process/index.ts +2 -2
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +3 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +15 -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 +6 -8
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/local-model-check.d.ts +15 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.js +41 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +11 -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 +20 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.js +30 -34
- package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +6 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +17 -0
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js +32 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +8 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts +15 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js +40 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +4 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +5 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +13 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +17 -8
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -3
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
- package/packages/pi-coding-agent/src/core/auth-storage.ts +15 -1
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
- package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
- package/packages/pi-coding-agent/src/core/local-model-check.ts +45 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +21 -1
- package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
- package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
- package/packages/pi-coding-agent/src/core/settings-manager.ts +9 -0
- package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
- package/packages/pi-coding-agent/src/main.ts +19 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +38 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +10 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +48 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +3 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +18 -3
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +16 -7
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +8 -1
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/activity-log.ts +1 -0
- package/src/resources/extensions/gsd/auto/infra-errors.ts +3 -0
- package/src/resources/extensions/gsd/auto/phases.ts +46 -48
- package/src/resources/extensions/gsd/auto-prompts.ts +24 -1
- package/src/resources/extensions/gsd/auto-start.ts +39 -2
- package/src/resources/extensions/gsd/auto-timers.ts +64 -3
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +5 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +9 -6
- package/src/resources/extensions/gsd/auto.ts +37 -3
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +148 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +48 -11
- package/src/resources/extensions/gsd/commands/catalog.ts +7 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +2 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +10 -0
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
- package/src/resources/extensions/gsd/commands-mcp-status.ts +247 -0
- package/src/resources/extensions/gsd/db-writer.ts +39 -17
- package/src/resources/extensions/gsd/doctor.ts +7 -1
- package/src/resources/extensions/gsd/git-service.ts +6 -2
- package/src/resources/extensions/gsd/gsd-db.ts +16 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +1 -1
- package/src/resources/extensions/gsd/preferences.ts +11 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
- package/src/resources/extensions/gsd/prompts/replan-slice.md +3 -14
- package/src/resources/extensions/gsd/prompts/rethink.md +78 -0
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
- package/src/resources/extensions/gsd/provider-error-pause.ts +9 -0
- package/src/resources/extensions/gsd/repo-identity.ts +46 -7
- package/src/resources/extensions/gsd/rethink.ts +154 -0
- package/src/resources/extensions/gsd/state.ts +41 -1
- package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
- package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +14 -16
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
- package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +465 -523
- package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +533 -656
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
- package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
- package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
- package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
- package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +38 -59
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +228 -263
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +250 -302
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +114 -0
- package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
- package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
- package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
- package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +465 -416
- package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +68 -83
- package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +121 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +210 -181
- package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
- package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
- package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +164 -180
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
- package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
- package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +27 -29
- package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
- package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +54 -75
- package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +21 -32
- package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
- package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +38 -44
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
- package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +54 -60
- package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
- package/src/resources/extensions/gsd/tests/doctor.test.ts +104 -134
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
- package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
- package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
- package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +30 -42
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +198 -206
- package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
- package/src/resources/extensions/gsd/tests/git-service.test.ts +285 -388
- package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
- package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
- package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +81 -103
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
- package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
- package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -102
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +20 -2
- package/src/resources/extensions/gsd/tests/inherited-repo-home-dir.test.ts +121 -0
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
- package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
- package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
- package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
- package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +150 -194
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +80 -93
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
- package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +83 -93
- package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +87 -96
- package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +125 -164
- package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +35 -36
- package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
- package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
- package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
- package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
- package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
- package/src/resources/extensions/gsd/tests/parsers.test.ts +546 -611
- package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
- package/src/resources/extensions/gsd/tests/preferences.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +11 -7
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
- package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
- package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
- package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
- package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
- package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
- package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +176 -0
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
- package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
- package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
- package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
- package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
- package/src/resources/extensions/gsd/tests/shared-wal.test.ts +19 -26
- package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
- package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +108 -0
- package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +10 -11
- package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
- package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
- package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
- package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
- package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
- package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
- package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
- package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
- package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
- package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +2 -0
- package/src/resources/extensions/gsd/tools/replan-slice.ts +3 -0
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +127 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +43 -2
- package/src/resources/extensions/gsd/worktree-resolver.ts +7 -0
- package/src/resources/extensions/mcp-client/index.ts +20 -0
- package/dist/web/standalone/.next/static/chunks/4024.0de81b543b28b9fe.js +0 -9
- package/dist/web/standalone/.next/static/chunks/app/page-7e9530a7122506c5.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
- package/dist/web/standalone/.next/static/chunks/webpack-9014b5adb127a98a.js +0 -1
- package/dist/web/standalone/.next/static/css/8a727f372cf53002.css +0 -1
- /package/dist/web/standalone/.next/static/{mgkxN0mGP6gSUmGPEzbk_ → rzO54ZboyINyEt7cVM_uS}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{mgkxN0mGP6gSUmGPEzbk_ → rzO54ZboyINyEt7cVM_uS}/_ssgManifest.js +0 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { Text } from "@gsd/pi-tui";
|
|
2
3
|
import { findMilestoneIds, nextMilestoneId, claimReservedId, getReservedMilestoneIds } from "../guided-flow.js";
|
|
3
4
|
import { loadEffectiveGSDPreferences } from "../preferences.js";
|
|
4
5
|
import { ensureDbOpen } from "./dynamic-tools.js";
|
|
6
|
+
import { StringEnum } from "@gsd/pi-ai";
|
|
5
7
|
/**
|
|
6
8
|
* Register an alias tool that shares the same execute function as its canonical counterpart.
|
|
7
9
|
* The alias description and promptGuidelines direct the LLM to prefer the canonical name.
|
|
@@ -77,6 +79,26 @@ export function registerDbTools(pi) {
|
|
|
77
79
|
], { description: "Who made this decision: 'human' (user directed), 'agent' (LLM decided autonomously), or 'collaborative' (discussed and agreed). Default: 'agent'" })),
|
|
78
80
|
}),
|
|
79
81
|
execute: decisionSaveExecute,
|
|
82
|
+
renderCall(args, theme) {
|
|
83
|
+
let text = theme.fg("toolTitle", theme.bold("decision_save "));
|
|
84
|
+
if (args.scope)
|
|
85
|
+
text += theme.fg("accent", `[${args.scope}] `);
|
|
86
|
+
if (args.decision)
|
|
87
|
+
text += theme.fg("muted", args.decision);
|
|
88
|
+
if (args.choice)
|
|
89
|
+
text += theme.fg("dim", ` — ${args.choice}`);
|
|
90
|
+
return new Text(text, 0, 0);
|
|
91
|
+
},
|
|
92
|
+
renderResult(result, _options, theme) {
|
|
93
|
+
const d = result.details;
|
|
94
|
+
if (result.isError || d?.error) {
|
|
95
|
+
return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
|
|
96
|
+
}
|
|
97
|
+
let text = theme.fg("success", `Decision ${d?.id ?? ""} saved`);
|
|
98
|
+
if (d?.id)
|
|
99
|
+
text += theme.fg("dim", ` → DECISIONS.md`);
|
|
100
|
+
return new Text(text, 0, 0);
|
|
101
|
+
},
|
|
80
102
|
};
|
|
81
103
|
pi.registerTool(decisionSaveTool);
|
|
82
104
|
registerAlias(pi, decisionSaveTool, "gsd_save_decision", "gsd_decision_save");
|
|
@@ -149,6 +171,24 @@ export function registerDbTools(pi) {
|
|
|
149
171
|
supporting_slices: Type.Optional(Type.String({ description: "Supporting slices" })),
|
|
150
172
|
}),
|
|
151
173
|
execute: requirementUpdateExecute,
|
|
174
|
+
renderCall(args, theme) {
|
|
175
|
+
let text = theme.fg("toolTitle", theme.bold("requirement_update "));
|
|
176
|
+
if (args.id)
|
|
177
|
+
text += theme.fg("accent", args.id);
|
|
178
|
+
const fields = ["status", "validation", "notes", "description"].filter((f) => args[f]);
|
|
179
|
+
if (fields.length > 0)
|
|
180
|
+
text += theme.fg("dim", ` (${fields.join(", ")})`);
|
|
181
|
+
return new Text(text, 0, 0);
|
|
182
|
+
},
|
|
183
|
+
renderResult(result, _options, theme) {
|
|
184
|
+
const d = result.details;
|
|
185
|
+
if (result.isError || d?.error) {
|
|
186
|
+
return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
|
|
187
|
+
}
|
|
188
|
+
let text = theme.fg("success", `Requirement ${d?.id ?? ""} updated`);
|
|
189
|
+
text += theme.fg("dim", ` → REQUIREMENTS.md`);
|
|
190
|
+
return new Text(text, 0, 0);
|
|
191
|
+
},
|
|
152
192
|
};
|
|
153
193
|
pi.registerTool(requirementUpdateTool);
|
|
154
194
|
registerAlias(pi, requirementUpdateTool, "gsd_update_requirement", "gsd_requirement_update");
|
|
@@ -222,6 +262,25 @@ export function registerDbTools(pi) {
|
|
|
222
262
|
content: Type.String({ description: "The full markdown content of the artifact" }),
|
|
223
263
|
}),
|
|
224
264
|
execute: summarySaveExecute,
|
|
265
|
+
renderCall(args, theme) {
|
|
266
|
+
let text = theme.fg("toolTitle", theme.bold("summary_save "));
|
|
267
|
+
if (args.artifact_type)
|
|
268
|
+
text += theme.fg("accent", args.artifact_type);
|
|
269
|
+
const path = [args.milestone_id, args.slice_id, args.task_id].filter(Boolean).join("/");
|
|
270
|
+
if (path)
|
|
271
|
+
text += theme.fg("dim", ` ${path}`);
|
|
272
|
+
return new Text(text, 0, 0);
|
|
273
|
+
},
|
|
274
|
+
renderResult(result, _options, theme) {
|
|
275
|
+
const d = result.details;
|
|
276
|
+
if (result.isError || d?.error) {
|
|
277
|
+
return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
|
|
278
|
+
}
|
|
279
|
+
let text = theme.fg("success", `${d?.artifact_type ?? "Artifact"} saved`);
|
|
280
|
+
if (d?.path)
|
|
281
|
+
text += theme.fg("dim", ` → ${d.path}`);
|
|
282
|
+
return new Text(text, 0, 0);
|
|
283
|
+
},
|
|
225
284
|
};
|
|
226
285
|
pi.registerTool(summarySaveTool);
|
|
227
286
|
registerAlias(pi, summarySaveTool, "gsd_save_summary", "gsd_summary_save");
|
|
@@ -232,6 +291,7 @@ export function registerDbTools(pi) {
|
|
|
232
291
|
// This guarantees the ID shown in the UI matches the one materialised on disk.
|
|
233
292
|
const reserved = claimReservedId();
|
|
234
293
|
if (reserved) {
|
|
294
|
+
await ensureMilestoneDbRow(reserved);
|
|
235
295
|
return {
|
|
236
296
|
content: [{ type: "text", text: reserved }],
|
|
237
297
|
details: { operation: "generate_milestone_id", id: reserved, source: "reserved" },
|
|
@@ -242,6 +302,7 @@ export function registerDbTools(pi) {
|
|
|
242
302
|
const uniqueEnabled = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
|
|
243
303
|
const allIds = [...new Set([...existingIds, ...getReservedMilestoneIds()])];
|
|
244
304
|
const newId = nextMilestoneId(allIds, uniqueEnabled);
|
|
305
|
+
await ensureMilestoneDbRow(newId);
|
|
245
306
|
return {
|
|
246
307
|
content: [{ type: "text", text: newId }],
|
|
247
308
|
details: { operation: "generate_milestone_id", id: newId, existingCount: existingIds.length, uniqueEnabled },
|
|
@@ -255,6 +316,24 @@ export function registerDbTools(pi) {
|
|
|
255
316
|
};
|
|
256
317
|
}
|
|
257
318
|
};
|
|
319
|
+
/**
|
|
320
|
+
* Insert a minimal DB row for a milestone ID so it's visible to the state
|
|
321
|
+
* machine. Uses INSERT OR IGNORE — safe to call even if gsd_plan_milestone
|
|
322
|
+
* later writes the full row. Silently skips if the DB isn't available yet
|
|
323
|
+
* (pre-migration).
|
|
324
|
+
*/
|
|
325
|
+
async function ensureMilestoneDbRow(milestoneId) {
|
|
326
|
+
const dbAvailable = await ensureDbOpen();
|
|
327
|
+
if (!dbAvailable)
|
|
328
|
+
return;
|
|
329
|
+
try {
|
|
330
|
+
const { insertMilestone } = await import("../gsd-db.js");
|
|
331
|
+
insertMilestone({ id: milestoneId, status: "queued" });
|
|
332
|
+
}
|
|
333
|
+
catch {
|
|
334
|
+
// Non-fatal — the safety-net in deriveStateFromDb will catch this
|
|
335
|
+
}
|
|
336
|
+
}
|
|
258
337
|
const milestoneGenerateIdTool = {
|
|
259
338
|
name: "gsd_milestone_generate_id",
|
|
260
339
|
label: "Generate Milestone ID",
|
|
@@ -270,6 +349,19 @@ export function registerDbTools(pi) {
|
|
|
270
349
|
],
|
|
271
350
|
parameters: Type.Object({}),
|
|
272
351
|
execute: milestoneGenerateIdExecute,
|
|
352
|
+
renderCall(_args, theme) {
|
|
353
|
+
return new Text(theme.fg("toolTitle", theme.bold("milestone_generate_id")), 0, 0);
|
|
354
|
+
},
|
|
355
|
+
renderResult(result, _options, theme) {
|
|
356
|
+
const d = result.details;
|
|
357
|
+
if (result.isError || d?.error) {
|
|
358
|
+
return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
|
|
359
|
+
}
|
|
360
|
+
let text = theme.fg("success", `Generated ${d?.id ?? "ID"}`);
|
|
361
|
+
if (d?.source === "reserved")
|
|
362
|
+
text += theme.fg("dim", " (reserved)");
|
|
363
|
+
return new Text(text, 0, 0);
|
|
364
|
+
},
|
|
273
365
|
};
|
|
274
366
|
pi.registerTool(milestoneGenerateIdTool);
|
|
275
367
|
registerAlias(pi, milestoneGenerateIdTool, "gsd_generate_milestone_id", "gsd_milestone_generate_id");
|
|
@@ -732,6 +824,70 @@ export function registerDbTools(pi) {
|
|
|
732
824
|
};
|
|
733
825
|
pi.registerTool(milestoneCompleteTool);
|
|
734
826
|
registerAlias(pi, milestoneCompleteTool, "gsd_milestone_complete", "gsd_complete_milestone");
|
|
827
|
+
// ─── gsd_validate_milestone (gsd_milestone_validate alias) ─────────────
|
|
828
|
+
const milestoneValidateExecute = async (_toolCallId, params, _signal, _onUpdate, _ctx) => {
|
|
829
|
+
const dbAvailable = await ensureDbOpen();
|
|
830
|
+
if (!dbAvailable) {
|
|
831
|
+
return {
|
|
832
|
+
content: [{ type: "text", text: "Error: GSD database is not available. Cannot validate milestone." }],
|
|
833
|
+
details: { operation: "validate_milestone", error: "db_unavailable" },
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
try {
|
|
837
|
+
const { handleValidateMilestone } = await import("../tools/validate-milestone.js");
|
|
838
|
+
const result = await handleValidateMilestone(params, process.cwd());
|
|
839
|
+
if ("error" in result) {
|
|
840
|
+
return {
|
|
841
|
+
content: [{ type: "text", text: `Error validating milestone: ${result.error}` }],
|
|
842
|
+
details: { operation: "validate_milestone", error: result.error },
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
return {
|
|
846
|
+
content: [{ type: "text", text: `Validated milestone ${result.milestoneId} — verdict: ${result.verdict}. Written to ${result.validationPath}` }],
|
|
847
|
+
details: {
|
|
848
|
+
operation: "validate_milestone",
|
|
849
|
+
milestoneId: result.milestoneId,
|
|
850
|
+
verdict: result.verdict,
|
|
851
|
+
validationPath: result.validationPath,
|
|
852
|
+
},
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
catch (err) {
|
|
856
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
857
|
+
process.stderr.write(`gsd-db: validate_milestone tool failed: ${msg}\n`);
|
|
858
|
+
return {
|
|
859
|
+
content: [{ type: "text", text: `Error validating milestone: ${msg}` }],
|
|
860
|
+
details: { operation: "validate_milestone", error: msg },
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
};
|
|
864
|
+
const milestoneValidateTool = {
|
|
865
|
+
name: "gsd_validate_milestone",
|
|
866
|
+
label: "Validate Milestone",
|
|
867
|
+
description: "Validate a milestone before completion — persist validation results to the DB, render VALIDATION.md to disk. " +
|
|
868
|
+
"Records verdict (pass/needs-attention/needs-remediation) and rationale.",
|
|
869
|
+
promptSnippet: "Validate a GSD milestone (DB write + VALIDATION.md render)",
|
|
870
|
+
promptGuidelines: [
|
|
871
|
+
"Use gsd_validate_milestone when all slices are done and the milestone needs validation before completion.",
|
|
872
|
+
"Parameters: milestoneId, verdict, remediationRound, successCriteriaChecklist, sliceDeliveryAudit, crossSliceIntegration, requirementCoverage, verdictRationale, remediationPlan (optional).",
|
|
873
|
+
"If verdict is 'needs-remediation', also provide remediationPlan and use gsd_reassess_roadmap to add remediation slices to the roadmap.",
|
|
874
|
+
"On success, returns validationPath where VALIDATION.md was written.",
|
|
875
|
+
],
|
|
876
|
+
parameters: Type.Object({
|
|
877
|
+
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
878
|
+
verdict: StringEnum(["pass", "needs-attention", "needs-remediation"], { description: "Validation verdict" }),
|
|
879
|
+
remediationRound: Type.Number({ description: "Remediation round (0 for first validation)" }),
|
|
880
|
+
successCriteriaChecklist: Type.String({ description: "Markdown checklist of success criteria with pass/fail and evidence" }),
|
|
881
|
+
sliceDeliveryAudit: Type.String({ description: "Markdown table auditing each slice's claimed vs delivered output" }),
|
|
882
|
+
crossSliceIntegration: Type.String({ description: "Markdown describing any cross-slice boundary mismatches" }),
|
|
883
|
+
requirementCoverage: Type.String({ description: "Markdown describing any unaddressed requirements" }),
|
|
884
|
+
verdictRationale: Type.String({ description: "Why this verdict was chosen" }),
|
|
885
|
+
remediationPlan: Type.Optional(Type.String({ description: "Remediation plan (required if verdict is needs-remediation)" })),
|
|
886
|
+
}),
|
|
887
|
+
execute: milestoneValidateExecute,
|
|
888
|
+
};
|
|
889
|
+
pi.registerTool(milestoneValidateTool);
|
|
890
|
+
registerAlias(pi, milestoneValidateTool, "gsd_milestone_validate", "gsd_validate_milestone");
|
|
735
891
|
// ─── gsd_replan_slice (gsd_slice_replan alias) ─────────────────────────
|
|
736
892
|
const replanSliceExecute = async (_toolCallId, params, _signal, _onUpdate, _ctx) => {
|
|
737
893
|
const dbAvailable = await ensureDbOpen();
|
|
@@ -45,18 +45,9 @@ export async function buildBeforeAgentStartResult(event, ctx) {
|
|
|
45
45
|
ctx.ui.notify(`GSD skill preferences: ${report.warnings.length} unresolved skill${report.warnings.length === 1 ? "" : "s"}: ${report.warnings.join(", ")}`, "warning");
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
const content = readFileSync(knowledgePath, "utf-8").trim();
|
|
53
|
-
if (content) {
|
|
54
|
-
knowledgeBlock = `\n\n[PROJECT KNOWLEDGE — Rules, patterns, and lessons learned]\n\n${content}`;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
// skip
|
|
59
|
-
}
|
|
48
|
+
const { block: knowledgeBlock, globalSizeKb } = loadKnowledgeBlock(gsdHome, process.cwd());
|
|
49
|
+
if (globalSizeKb > 4) {
|
|
50
|
+
ctx.ui.notify(`GSD: ~/.gsd/agent/KNOWLEDGE.md is ${globalSizeKb.toFixed(1)}KB — consider trimming to keep system prompt lean.`, "warning");
|
|
60
51
|
}
|
|
61
52
|
let memoryBlock = "";
|
|
62
53
|
try {
|
|
@@ -102,6 +93,49 @@ export async function buildBeforeAgentStartResult(event, ctx) {
|
|
|
102
93
|
: {}),
|
|
103
94
|
};
|
|
104
95
|
}
|
|
96
|
+
export function loadKnowledgeBlock(gsdHomeDir, cwd) {
|
|
97
|
+
// 1. Global knowledge (~/.gsd/agent/KNOWLEDGE.md) — cross-project, user-maintained
|
|
98
|
+
let globalKnowledge = "";
|
|
99
|
+
let globalSizeKb = 0;
|
|
100
|
+
const globalKnowledgePath = join(gsdHomeDir, "agent", "KNOWLEDGE.md");
|
|
101
|
+
if (existsSync(globalKnowledgePath)) {
|
|
102
|
+
try {
|
|
103
|
+
const content = readFileSync(globalKnowledgePath, "utf-8").trim();
|
|
104
|
+
if (content) {
|
|
105
|
+
globalSizeKb = Buffer.byteLength(content, "utf-8") / 1024;
|
|
106
|
+
globalKnowledge = content;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// skip
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// 2. Project knowledge (.gsd/KNOWLEDGE.md) — project-specific
|
|
114
|
+
let projectKnowledge = "";
|
|
115
|
+
const knowledgePath = resolveGsdRootFile(cwd, "KNOWLEDGE");
|
|
116
|
+
if (existsSync(knowledgePath)) {
|
|
117
|
+
try {
|
|
118
|
+
const content = readFileSync(knowledgePath, "utf-8").trim();
|
|
119
|
+
if (content)
|
|
120
|
+
projectKnowledge = content;
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// skip
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (!globalKnowledge && !projectKnowledge) {
|
|
127
|
+
return { block: "", globalSizeKb: 0 };
|
|
128
|
+
}
|
|
129
|
+
const parts = [];
|
|
130
|
+
if (globalKnowledge)
|
|
131
|
+
parts.push(`## Global Knowledge\n\n${globalKnowledge}`);
|
|
132
|
+
if (projectKnowledge)
|
|
133
|
+
parts.push(`## Project Knowledge\n\n${projectKnowledge}`);
|
|
134
|
+
return {
|
|
135
|
+
block: `\n\n[KNOWLEDGE — Rules, patterns, and lessons learned]\n\n${parts.join("\n\n")}`,
|
|
136
|
+
globalSizeKb,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
105
139
|
function buildWorktreeContextBlock() {
|
|
106
140
|
const worktreeName = getActiveWorktreeName();
|
|
107
141
|
const worktreeMainCwd = getWorktreeOriginalCwd();
|
|
@@ -4,7 +4,7 @@ import { join } from "node:path";
|
|
|
4
4
|
import { loadRegistry } from "../workflow-templates.js";
|
|
5
5
|
import { resolveProjectRoot } from "../worktree.js";
|
|
6
6
|
const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
7
|
-
export const GSD_COMMAND_DESCRIPTION = "GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|queue|quick|discuss|capture|triage|dispatch|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|logs|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|parallel|cmux|park|unpark|init|setup|inspect|extensions|update|fast";
|
|
7
|
+
export const GSD_COMMAND_DESCRIPTION = "GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|queue|quick|discuss|capture|triage|dispatch|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|logs|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|parallel|cmux|park|unpark|init|setup|inspect|extensions|update|fast|mcp|rethink";
|
|
8
8
|
export const TOP_LEVEL_SUBCOMMANDS = [
|
|
9
9
|
{ cmd: "help", desc: "Categorized command reference with descriptions" },
|
|
10
10
|
{ cmd: "next", desc: "Explicit step mode (same as /gsd)" },
|
|
@@ -56,6 +56,8 @@ export const TOP_LEVEL_SUBCOMMANDS = [
|
|
|
56
56
|
{ cmd: "templates", desc: "List available workflow templates" },
|
|
57
57
|
{ cmd: "extensions", desc: "Manage extensions (list, enable, disable, info)" },
|
|
58
58
|
{ cmd: "fast", desc: "Toggle OpenAI service tier (on/off/flex/status)" },
|
|
59
|
+
{ cmd: "mcp", desc: "MCP server status and connectivity check (status, check <server>)" },
|
|
60
|
+
{ cmd: "rethink", desc: "Conversational project reorganization — reorder, park, discard, add milestones" },
|
|
59
61
|
{ cmd: "workflow", desc: "Custom workflow lifecycle (new, run, list, validate, pause, resume)" },
|
|
60
62
|
];
|
|
61
63
|
const NESTED_COMPLETIONS = {
|
|
@@ -174,6 +176,10 @@ const NESTED_COMPLETIONS = {
|
|
|
174
176
|
{ cmd: "flex", desc: "Flex tier (0.5x cost, slower)" },
|
|
175
177
|
{ cmd: "status", desc: "Show current service tier setting" },
|
|
176
178
|
],
|
|
179
|
+
mcp: [
|
|
180
|
+
{ cmd: "status", desc: "Show all MCP server statuses (default)" },
|
|
181
|
+
{ cmd: "check", desc: "Detailed status for a specific server" },
|
|
182
|
+
],
|
|
177
183
|
doctor: [
|
|
178
184
|
{ cmd: "fix", desc: "Auto-fix detected issues" },
|
|
179
185
|
{ cmd: "heal", desc: "AI-driven deep healing" },
|
|
@@ -32,6 +32,7 @@ export function showHelp(ctx) {
|
|
|
32
32
|
" /gsd triage Classify and route pending captures",
|
|
33
33
|
" /gsd skip <unit> Prevent a unit from auto-mode dispatch",
|
|
34
34
|
" /gsd undo Revert last completed unit [--force]",
|
|
35
|
+
" /gsd rethink Conversational project reorganization — reorder, park, discard, add milestones",
|
|
35
36
|
" /gsd park [id] Park a milestone — skip without deleting [reason]",
|
|
36
37
|
" /gsd unpark [id] Reactivate a parked milestone",
|
|
37
38
|
"",
|
|
@@ -49,6 +50,7 @@ export function showHelp(ctx) {
|
|
|
49
50
|
" /gsd hooks Show post-unit hook configuration",
|
|
50
51
|
" /gsd extensions Manage extensions [list|enable|disable|info]",
|
|
51
52
|
" /gsd fast Toggle OpenAI service tier [on|off|flex|status]",
|
|
53
|
+
" /gsd mcp MCP server status and connectivity [status|check <server>]",
|
|
52
54
|
"",
|
|
53
55
|
"MAINTENANCE",
|
|
54
56
|
" /gsd doctor Diagnose and repair .gsd/ state [audit|fix|heal] [scope]",
|
|
@@ -188,10 +188,20 @@ Examples:
|
|
|
188
188
|
await handleFast(trimmed.replace(/^fast\s*/, "").trim(), ctx);
|
|
189
189
|
return true;
|
|
190
190
|
}
|
|
191
|
+
if (trimmed === "mcp" || trimmed.startsWith("mcp ")) {
|
|
192
|
+
const { handleMcpStatus } = await import("../../commands-mcp-status.js");
|
|
193
|
+
await handleMcpStatus(trimmed.replace(/^mcp\s*/, "").trim(), ctx);
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
191
196
|
if (trimmed === "extensions" || trimmed.startsWith("extensions ")) {
|
|
192
197
|
const { handleExtensions } = await import("../../commands-extensions.js");
|
|
193
198
|
await handleExtensions(trimmed.replace(/^extensions\s*/, "").trim(), ctx);
|
|
194
199
|
return true;
|
|
195
200
|
}
|
|
201
|
+
if (trimmed === "rethink") {
|
|
202
|
+
const { handleRethink } = await import("../../rethink.js");
|
|
203
|
+
await handleRethink(trimmed, ctx, pi);
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
196
206
|
return false;
|
|
197
207
|
}
|
|
@@ -166,6 +166,11 @@ export async function handleWorkflowCommand(trimmed, ctx, pi) {
|
|
|
166
166
|
return true;
|
|
167
167
|
}
|
|
168
168
|
if (trimmed === "quick" || trimmed.startsWith("quick ")) {
|
|
169
|
+
if (isAutoActive()) {
|
|
170
|
+
ctx.ui.notify("/gsd quick cannot run while auto-mode is active.\n" +
|
|
171
|
+
"Stop auto-mode first with /gsd stop, then run /gsd quick.", "error");
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
169
174
|
await handleQuick(trimmed.replace(/^quick\s*/, "").trim(), ctx, pi);
|
|
170
175
|
return true;
|
|
171
176
|
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Status — `/gsd mcp` command handler.
|
|
3
|
+
*
|
|
4
|
+
* Shows configured MCP servers, their connection status, and available tools.
|
|
5
|
+
*
|
|
6
|
+
* Subcommands:
|
|
7
|
+
* /gsd mcp — Overview of all servers (alias: /gsd mcp status)
|
|
8
|
+
* /gsd mcp status — Same as bare /gsd mcp
|
|
9
|
+
* /gsd mcp check <srv> — Detailed status for a specific server
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
function readMcpConfigs() {
|
|
14
|
+
const servers = [];
|
|
15
|
+
const seen = new Set();
|
|
16
|
+
const configPaths = [
|
|
17
|
+
join(process.cwd(), ".mcp.json"),
|
|
18
|
+
join(process.cwd(), ".gsd", "mcp.json"),
|
|
19
|
+
];
|
|
20
|
+
for (const configPath of configPaths) {
|
|
21
|
+
try {
|
|
22
|
+
if (!existsSync(configPath))
|
|
23
|
+
continue;
|
|
24
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
25
|
+
const data = JSON.parse(raw);
|
|
26
|
+
const mcpServers = (data.mcpServers ?? data.servers);
|
|
27
|
+
if (!mcpServers || typeof mcpServers !== "object")
|
|
28
|
+
continue;
|
|
29
|
+
for (const [name, config] of Object.entries(mcpServers)) {
|
|
30
|
+
if (seen.has(name))
|
|
31
|
+
continue;
|
|
32
|
+
seen.add(name);
|
|
33
|
+
const hasCommand = typeof config.command === "string";
|
|
34
|
+
const hasUrl = typeof config.url === "string";
|
|
35
|
+
const transport = hasCommand
|
|
36
|
+
? "stdio"
|
|
37
|
+
: hasUrl
|
|
38
|
+
? "http"
|
|
39
|
+
: "unknown";
|
|
40
|
+
servers.push({
|
|
41
|
+
name,
|
|
42
|
+
transport,
|
|
43
|
+
...(hasCommand && {
|
|
44
|
+
command: config.command,
|
|
45
|
+
args: Array.isArray(config.args) ? config.args : undefined,
|
|
46
|
+
}),
|
|
47
|
+
...(hasUrl && { url: config.url }),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// Non-fatal — config file may not exist or be malformed
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return servers;
|
|
56
|
+
}
|
|
57
|
+
// ─── Formatters (exported for testing) ──────────────────────────────────────
|
|
58
|
+
export function formatMcpStatusReport(servers) {
|
|
59
|
+
if (servers.length === 0) {
|
|
60
|
+
return [
|
|
61
|
+
"No MCP servers configured.",
|
|
62
|
+
"",
|
|
63
|
+
"Add servers to .mcp.json or .gsd/mcp.json to enable MCP integrations.",
|
|
64
|
+
"See: https://modelcontextprotocol.io/quickstart",
|
|
65
|
+
].join("\n");
|
|
66
|
+
}
|
|
67
|
+
const lines = [`MCP Server Status — ${servers.length} server(s)\n`];
|
|
68
|
+
for (const s of servers) {
|
|
69
|
+
const icon = s.error ? "✗" : s.connected ? "✓" : "○";
|
|
70
|
+
const status = s.error
|
|
71
|
+
? `error: ${s.error}`
|
|
72
|
+
: s.connected
|
|
73
|
+
? `connected — ${s.toolCount} tools`
|
|
74
|
+
: "disconnected";
|
|
75
|
+
lines.push(` ${icon} ${s.name} (${s.transport}) — ${status}`);
|
|
76
|
+
}
|
|
77
|
+
lines.push("");
|
|
78
|
+
lines.push("Use /gsd mcp check <server> for details on a specific server.");
|
|
79
|
+
lines.push("Use mcp_discover to connect and list tools for a server.");
|
|
80
|
+
return lines.join("\n");
|
|
81
|
+
}
|
|
82
|
+
export function formatMcpServerDetail(server) {
|
|
83
|
+
const lines = [`MCP Server: ${server.name}\n`];
|
|
84
|
+
lines.push(` Transport: ${server.transport}`);
|
|
85
|
+
if (server.error) {
|
|
86
|
+
lines.push(` Status: error`);
|
|
87
|
+
lines.push(` Error: ${server.error}`);
|
|
88
|
+
}
|
|
89
|
+
else if (server.connected) {
|
|
90
|
+
lines.push(` Status: connected`);
|
|
91
|
+
lines.push(` Tools: ${server.toolCount}`);
|
|
92
|
+
if (server.tools.length > 0) {
|
|
93
|
+
lines.push("");
|
|
94
|
+
lines.push(" Available tools:");
|
|
95
|
+
for (const tool of server.tools) {
|
|
96
|
+
lines.push(` - ${tool}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
lines.push(` Status: disconnected`);
|
|
102
|
+
lines.push("");
|
|
103
|
+
lines.push(` Run mcp_discover("${server.name}") to connect and list tools.`);
|
|
104
|
+
}
|
|
105
|
+
return lines.join("\n");
|
|
106
|
+
}
|
|
107
|
+
// ─── Command handler ────────────────────────────────────────────────────────
|
|
108
|
+
/**
|
|
109
|
+
* Handle `/gsd mcp [status|check <server>]`.
|
|
110
|
+
*/
|
|
111
|
+
export async function handleMcpStatus(args, ctx) {
|
|
112
|
+
const trimmed = args.trim().toLowerCase();
|
|
113
|
+
const configs = readMcpConfigs();
|
|
114
|
+
// /gsd mcp check <server>
|
|
115
|
+
if (trimmed.startsWith("check ")) {
|
|
116
|
+
const serverName = args.trim().slice("check ".length).trim();
|
|
117
|
+
const config = configs.find((c) => c.name === serverName);
|
|
118
|
+
if (!config) {
|
|
119
|
+
const available = configs.map((c) => c.name).join(", ") || "(none)";
|
|
120
|
+
ctx.ui.notify(`Unknown MCP server: "${serverName}"\n\nAvailable: ${available}`, "warning");
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
// Try to get connection/tool info from the mcp-client module if available
|
|
124
|
+
let connected = false;
|
|
125
|
+
let toolNames = [];
|
|
126
|
+
let error;
|
|
127
|
+
try {
|
|
128
|
+
const mcpClient = await import("../mcp-client/index.js");
|
|
129
|
+
// Access the module's connection state if exported; fall back gracefully
|
|
130
|
+
const mod = mcpClient;
|
|
131
|
+
if (typeof mod.getConnectionStatus === "function") {
|
|
132
|
+
const status = mod.getConnectionStatus(serverName);
|
|
133
|
+
connected = status.connected;
|
|
134
|
+
toolNames = status.tools;
|
|
135
|
+
error = status.error;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// mcp-client may not expose status helpers — that's fine
|
|
140
|
+
}
|
|
141
|
+
ctx.ui.notify(formatMcpServerDetail({
|
|
142
|
+
name: config.name,
|
|
143
|
+
transport: config.transport,
|
|
144
|
+
connected,
|
|
145
|
+
toolCount: toolNames.length,
|
|
146
|
+
tools: toolNames,
|
|
147
|
+
error,
|
|
148
|
+
}), "info");
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
// /gsd mcp or /gsd mcp status
|
|
152
|
+
if (!trimmed || trimmed === "status") {
|
|
153
|
+
// Build status for each server
|
|
154
|
+
const statuses = [];
|
|
155
|
+
for (const config of configs) {
|
|
156
|
+
let connected = false;
|
|
157
|
+
let toolCount = 0;
|
|
158
|
+
let error;
|
|
159
|
+
try {
|
|
160
|
+
const mcpClient = await import("../mcp-client/index.js");
|
|
161
|
+
const mod = mcpClient;
|
|
162
|
+
if (typeof mod.getConnectionStatus === "function") {
|
|
163
|
+
const status = mod.getConnectionStatus(config.name);
|
|
164
|
+
connected = status.connected;
|
|
165
|
+
toolCount = status.tools.length;
|
|
166
|
+
error = status.error;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
// Fall back to unknown state
|
|
171
|
+
}
|
|
172
|
+
statuses.push({
|
|
173
|
+
name: config.name,
|
|
174
|
+
transport: config.transport,
|
|
175
|
+
connected,
|
|
176
|
+
toolCount,
|
|
177
|
+
error,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
ctx.ui.notify(formatMcpStatusReport(statuses), "info");
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
// Unknown subcommand
|
|
184
|
+
ctx.ui.notify("Usage: /gsd mcp [status|check <server>]\n\n" +
|
|
185
|
+
" status Show all MCP server statuses (default)\n" +
|
|
186
|
+
" check <server> Detailed status for a specific server", "warning");
|
|
187
|
+
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// Critical invariant: generated markdown must round-trip through
|
|
9
9
|
// parseDecisionsTable() and parseRequirementsSections() with field fidelity.
|
|
10
10
|
import { resolve } from 'node:path';
|
|
11
|
-
import { readFileSync, existsSync } from 'node:fs';
|
|
11
|
+
import { readFileSync, existsSync, statSync } from 'node:fs';
|
|
12
12
|
import { resolveGsdRootFile } from './paths.js';
|
|
13
13
|
import { saveFile } from './files.js';
|
|
14
14
|
import { GSDError, GSD_STALE_STATE, GSD_IO_ERROR } from './errors.js';
|
|
@@ -356,28 +356,46 @@ export async function updateRequirementInDb(id, updates, basePath) {
|
|
|
356
356
|
export async function saveArtifactToDb(opts, basePath) {
|
|
357
357
|
try {
|
|
358
358
|
const db = await import('./gsd-db.js');
|
|
359
|
+
// Guard against path traversal before any reads/writes
|
|
360
|
+
const gsdDir = resolve(basePath, '.gsd');
|
|
361
|
+
const fullPath = resolve(basePath, '.gsd', opts.path);
|
|
362
|
+
if (!fullPath.startsWith(gsdDir)) {
|
|
363
|
+
throw new GSDError(GSD_IO_ERROR, `saveArtifactToDb: path escapes .gsd/ directory: ${opts.path}`);
|
|
364
|
+
}
|
|
365
|
+
// Shrinkage guard: if the file already exists and the new content is
|
|
366
|
+
// significantly smaller (<50%), preserve the richer file on disk and
|
|
367
|
+
// store its content in the DB instead of the abbreviated version.
|
|
368
|
+
let dbContent = opts.content;
|
|
369
|
+
let skipDiskWrite = false;
|
|
370
|
+
if (existsSync(fullPath)) {
|
|
371
|
+
const existingSize = statSync(fullPath).size;
|
|
372
|
+
const newSize = Buffer.byteLength(opts.content, 'utf-8');
|
|
373
|
+
if (existingSize > 0 && newSize < existingSize * 0.5) {
|
|
374
|
+
process.stderr.write(`gsd-db: saveArtifactToDb — new content (${newSize}B) is <50% of existing file ` +
|
|
375
|
+
`(${existingSize}B) at ${opts.path}. Preserving disk file to prevent data loss.\n`);
|
|
376
|
+
dbContent = readFileSync(fullPath, 'utf-8');
|
|
377
|
+
skipDiskWrite = true;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
359
380
|
db.insertArtifact({
|
|
360
381
|
path: opts.path,
|
|
361
382
|
artifact_type: opts.artifact_type,
|
|
362
383
|
milestone_id: opts.milestone_id ?? null,
|
|
363
384
|
slice_id: opts.slice_id ?? null,
|
|
364
385
|
task_id: opts.task_id ?? null,
|
|
365
|
-
full_content:
|
|
386
|
+
full_content: dbContent,
|
|
366
387
|
});
|
|
367
|
-
// Write the file to disk (
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
const rollbackAdapter = db._getAdapter();
|
|
379
|
-
rollbackAdapter?.prepare('DELETE FROM artifacts WHERE path = :path').run({ ':path': opts.path });
|
|
380
|
-
throw diskErr;
|
|
388
|
+
// Write the file to disk (only if we're not preserving a richer existing file)
|
|
389
|
+
if (!skipDiskWrite) {
|
|
390
|
+
try {
|
|
391
|
+
await saveFile(fullPath, opts.content);
|
|
392
|
+
}
|
|
393
|
+
catch (diskErr) {
|
|
394
|
+
process.stderr.write(`gsd-db: saveArtifactToDb — disk write failed, rolling back DB row: ${diskErr.message}\n`);
|
|
395
|
+
const rollbackAdapter = db._getAdapter();
|
|
396
|
+
rollbackAdapter?.prepare('DELETE FROM artifacts WHERE path = :path').run({ ':path': opts.path });
|
|
397
|
+
throw diskErr;
|
|
398
|
+
}
|
|
381
399
|
}
|
|
382
400
|
// Invalidate file-read caches so deriveState() sees the updated markdown.
|
|
383
401
|
// Do NOT clear the artifacts table — we just wrote to it intentionally.
|
|
@@ -441,6 +441,7 @@ export async function runGSDDoctor(basePath, options) {
|
|
|
441
441
|
id: s.id,
|
|
442
442
|
title: s.title,
|
|
443
443
|
done: s.status === "complete",
|
|
444
|
+
pending: s.status === "pending",
|
|
444
445
|
risk: (s.risk || "medium"),
|
|
445
446
|
depends: s.depends,
|
|
446
447
|
demo: s.demo,
|
|
@@ -528,6 +529,10 @@ export async function runGSDDoctor(basePath, options) {
|
|
|
528
529
|
}
|
|
529
530
|
const slicePath = resolveSlicePath(basePath, milestoneId, slice.id);
|
|
530
531
|
if (!slicePath) {
|
|
532
|
+
// Pending slices haven't been planned yet — directories are created
|
|
533
|
+
// lazily by ensurePreconditions() at dispatch time. Skip them.
|
|
534
|
+
if (slice.pending)
|
|
535
|
+
continue;
|
|
531
536
|
const expectedPath = relSlicePath(basePath, milestoneId, slice.id);
|
|
532
537
|
issues.push({
|
|
533
538
|
severity: slice.done ? "warning" : "error",
|
|
@@ -549,6 +554,9 @@ export async function runGSDDoctor(basePath, options) {
|
|
|
549
554
|
}
|
|
550
555
|
const tasksDir = resolveTasksDir(basePath, milestoneId, slice.id);
|
|
551
556
|
if (!tasksDir) {
|
|
557
|
+
// Pending slices haven't been planned yet — tasks/ is created on demand.
|
|
558
|
+
if (slice.pending)
|
|
559
|
+
continue;
|
|
552
560
|
issues.push({
|
|
553
561
|
severity: slice.done ? "warning" : "error",
|
|
554
562
|
code: "missing_tasks_dir",
|