gsd-pi 2.70.0 → 2.70.1-dev.366a872
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/dist/loader.js +4 -0
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +270 -23
- package/dist/resources/extensions/get-secrets-from-user.js +17 -1
- package/dist/resources/extensions/gsd/auto-model-selection.js +33 -19
- package/dist/resources/extensions/gsd/auto-prompts.js +7 -3
- package/dist/resources/extensions/gsd/auto-start.js +28 -12
- package/dist/resources/extensions/gsd/auto.js +12 -8
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +4 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +22 -8
- package/dist/resources/extensions/gsd/custom-workflow-engine.js +16 -12
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +12 -0
- package/dist/resources/extensions/gsd/doctor-format.js +2 -0
- package/dist/resources/extensions/gsd/file-lock.js +60 -0
- package/dist/resources/extensions/gsd/guided-flow.js +33 -20
- package/dist/resources/extensions/gsd/init-wizard.js +3 -11
- package/dist/resources/extensions/gsd/pre-execution-checks.js +5 -3
- package/dist/resources/extensions/gsd/prompts/discuss.md +31 -13
- package/dist/resources/extensions/gsd/state.js +234 -332
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +34 -0
- package/dist/resources/extensions/gsd/validate-directory.js +30 -12
- package/dist/resources/extensions/gsd/workflow-events.js +25 -13
- package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +56 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +12 -1
- package/dist/resources/extensions/slash-commands/audit.js +2 -1
- package/dist/resources/extensions/subagent/isolation.js +4 -2
- package/dist/update-check.d.ts +1 -0
- package/dist/update-check.js +30 -27
- package/dist/update-cmd.js +3 -11
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
- 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 +1 -1
- 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 +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_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/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_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/notifications/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/notifications/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 +2 -2
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_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 +1 -1
- 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 +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
- 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 +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
- package/dist/web/standalone/.next/server/chunks/63.js +3 -3
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- 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 +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/2826.dd3dc8bbd3025fa5.js +9 -0
- 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-f1e30ab6bb269149.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-6e4d7e9a4f57bed4.js → webpack-b868033a5834586d.js} +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/dist/web-mode.js +4 -0
- package/package.json +11 -11
- package/packages/mcp-server/dist/env-writer.d.ts +39 -0
- package/packages/mcp-server/dist/env-writer.d.ts.map +1 -0
- package/packages/mcp-server/dist/env-writer.js +158 -0
- package/packages/mcp-server/dist/env-writer.js.map +1 -0
- package/packages/mcp-server/dist/server.d.ts +11 -2
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +102 -2
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +2 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +35 -3
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/env-writer.test.ts +280 -0
- package/packages/mcp-server/src/env-writer.ts +183 -0
- package/packages/mcp-server/src/import-candidates.test.ts +48 -0
- package/packages/mcp-server/src/secure-env-collect.test.ts +265 -0
- package/packages/mcp-server/src/server.ts +137 -3
- package/packages/mcp-server/src/workflow-tools.ts +34 -1
- package/packages/pi-agent-core/dist/agent.d.ts +8 -0
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +3 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/src/agent.test.ts +82 -0
- package/packages/pi-agent-core/src/agent.ts +12 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +348 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/config.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/lsp/config.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/config.js +38 -15
- package/packages/pi-coding-agent/dist/core/lsp/config.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/dist/modes/interactive/components/dynamic-border.d.ts +19 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js +50 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.js +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.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 +158 -23
- 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-state.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +6 -0
- 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 +58 -2
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +3 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +418 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -0
- package/packages/pi-coding-agent/src/core/lsp/config.ts +43 -17
- package/packages/pi-coding-agent/src/core/sdk.ts +8 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.ts +58 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/extension-input.ts +2 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +189 -29
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +66 -2
- package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +7 -5
- package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +1 -1
- package/packages/pi-coding-agent/src/modes/rpc/rpc-types.ts +1 -0
- package/packages/pi-tui/dist/components/__tests__/input.test.js +9 -0
- package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.d.ts +2 -0
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +66 -0
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -0
- package/packages/pi-tui/dist/components/input.d.ts +2 -0
- package/packages/pi-tui/dist/components/input.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/input.js +7 -4
- package/packages/pi-tui/dist/components/input.js.map +1 -1
- package/packages/pi-tui/dist/components/markdown.d.ts +3 -0
- package/packages/pi-tui/dist/components/markdown.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/markdown.js +17 -1
- package/packages/pi-tui/dist/components/markdown.js.map +1 -1
- package/packages/pi-tui/src/components/__tests__/input.test.ts +11 -0
- package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +75 -0
- package/packages/pi-tui/src/components/input.ts +7 -4
- package/packages/pi-tui/src/components/markdown.ts +22 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +384 -24
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +317 -0
- package/src/resources/extensions/get-secrets-from-user.ts +24 -1
- package/src/resources/extensions/gsd/auto-model-selection.ts +39 -25
- package/src/resources/extensions/gsd/auto-prompts.ts +7 -3
- package/src/resources/extensions/gsd/auto-start.ts +37 -14
- package/src/resources/extensions/gsd/auto.ts +12 -8
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +4 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +22 -7
- package/src/resources/extensions/gsd/custom-workflow-engine.ts +19 -14
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +14 -0
- package/src/resources/extensions/gsd/doctor-format.ts +1 -0
- package/src/resources/extensions/gsd/doctor-types.ts +1 -0
- package/src/resources/extensions/gsd/file-lock.ts +59 -0
- package/src/resources/extensions/gsd/guided-flow.ts +36 -17
- package/src/resources/extensions/gsd/init-wizard.ts +3 -13
- package/src/resources/extensions/gsd/pre-execution-checks.ts +6 -3
- package/src/resources/extensions/gsd/prompts/discuss.md +31 -13
- package/src/resources/extensions/gsd/state.ts +274 -344
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +436 -0
- package/src/resources/extensions/gsd/tests/discuss-incremental-persistence.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/file-lock.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +207 -0
- package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +48 -1
- package/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts +8 -7
- package/src/resources/extensions/gsd/tests/secure-env-collect.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/validate-directory.test.ts +33 -1
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +87 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +76 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +180 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +22 -0
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +60 -25
- package/src/resources/extensions/gsd/validate-directory.ts +33 -11
- package/src/resources/extensions/gsd/workflow-events.ts +34 -25
- package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +76 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +16 -1
- package/src/resources/extensions/slash-commands/audit.ts +2 -1
- package/src/resources/extensions/subagent/isolation.ts +4 -3
- package/dist/web/standalone/.next/static/chunks/2826.821e01b07d92e948.js +0 -9
- package/dist/web/standalone/.next/static/chunks/app/page-7115e62689b5fd84.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/{Nl6lg7zP5dNgNBV1107v1 → eMly3KqfZihJJAHQGmxvO}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Nl6lg7zP5dNgNBV1107v1 → eMly3KqfZihJJAHQGmxvO}/_ssgManifest.js +0 -0
|
@@ -23,12 +23,14 @@ export async function executeSummarySave(params, basePath = process.cwd()) {
|
|
|
23
23
|
return {
|
|
24
24
|
content: [{ type: "text", text: "Error: GSD database is not available. Cannot save artifact." }],
|
|
25
25
|
details: { operation: "save_summary", error: "db_unavailable" },
|
|
26
|
+
isError: true,
|
|
26
27
|
};
|
|
27
28
|
}
|
|
28
29
|
if (!isSupportedSummaryArtifactType(params.artifact_type)) {
|
|
29
30
|
return {
|
|
30
31
|
content: [{ type: "text", text: `Error: Invalid artifact_type "${params.artifact_type}". Must be one of: ${SUPPORTED_SUMMARY_ARTIFACT_TYPES.join(", ")}` }],
|
|
31
32
|
details: { operation: "save_summary", error: "invalid_artifact_type" },
|
|
33
|
+
isError: true,
|
|
32
34
|
};
|
|
33
35
|
}
|
|
34
36
|
const contextGuard = shouldBlockContextArtifactSaveInSnapshot(loadWriteGateSnapshot(basePath), params.artifact_type, params.milestone_id ?? null, params.slice_id ?? null);
|
|
@@ -36,6 +38,7 @@ export async function executeSummarySave(params, basePath = process.cwd()) {
|
|
|
36
38
|
return {
|
|
37
39
|
content: [{ type: "text", text: `Error saving artifact: ${contextGuard.reason ?? "context write blocked"}` }],
|
|
38
40
|
details: { operation: "save_summary", error: "context_write_blocked" },
|
|
41
|
+
isError: true,
|
|
39
42
|
};
|
|
40
43
|
}
|
|
41
44
|
try {
|
|
@@ -68,6 +71,7 @@ export async function executeSummarySave(params, basePath = process.cwd()) {
|
|
|
68
71
|
return {
|
|
69
72
|
content: [{ type: "text", text: `Error saving artifact: ${msg}` }],
|
|
70
73
|
details: { operation: "save_summary", error: msg },
|
|
74
|
+
isError: true,
|
|
71
75
|
};
|
|
72
76
|
}
|
|
73
77
|
}
|
|
@@ -77,6 +81,7 @@ export async function executeTaskComplete(params, basePath = process.cwd()) {
|
|
|
77
81
|
return {
|
|
78
82
|
content: [{ type: "text", text: "Error: GSD database is not available. Cannot complete task." }],
|
|
79
83
|
details: { operation: "complete_task", error: "db_unavailable" },
|
|
84
|
+
isError: true,
|
|
80
85
|
};
|
|
81
86
|
}
|
|
82
87
|
try {
|
|
@@ -87,6 +92,7 @@ export async function executeTaskComplete(params, basePath = process.cwd()) {
|
|
|
87
92
|
return {
|
|
88
93
|
content: [{ type: "text", text: `Error completing task: ${result.error}` }],
|
|
89
94
|
details: { operation: "complete_task", error: result.error },
|
|
95
|
+
isError: true,
|
|
90
96
|
};
|
|
91
97
|
}
|
|
92
98
|
return {
|
|
@@ -106,6 +112,7 @@ export async function executeTaskComplete(params, basePath = process.cwd()) {
|
|
|
106
112
|
return {
|
|
107
113
|
content: [{ type: "text", text: `Error completing task: ${msg}` }],
|
|
108
114
|
details: { operation: "complete_task", error: msg },
|
|
115
|
+
isError: true,
|
|
109
116
|
};
|
|
110
117
|
}
|
|
111
118
|
}
|
|
@@ -115,6 +122,7 @@ export async function executeSliceComplete(params, basePath = process.cwd()) {
|
|
|
115
122
|
return {
|
|
116
123
|
content: [{ type: "text", text: "Error: GSD database is not available. Cannot complete slice." }],
|
|
117
124
|
details: { operation: "complete_slice", error: "db_unavailable" },
|
|
125
|
+
isError: true,
|
|
118
126
|
};
|
|
119
127
|
}
|
|
120
128
|
try {
|
|
@@ -167,6 +175,7 @@ export async function executeSliceComplete(params, basePath = process.cwd()) {
|
|
|
167
175
|
return {
|
|
168
176
|
content: [{ type: "text", text: `Error completing slice: ${result.error}` }],
|
|
169
177
|
details: { operation: "complete_slice", error: result.error },
|
|
178
|
+
isError: true,
|
|
170
179
|
};
|
|
171
180
|
}
|
|
172
181
|
return {
|
|
@@ -186,6 +195,7 @@ export async function executeSliceComplete(params, basePath = process.cwd()) {
|
|
|
186
195
|
return {
|
|
187
196
|
content: [{ type: "text", text: `Error completing slice: ${msg}` }],
|
|
188
197
|
details: { operation: "complete_slice", error: msg },
|
|
198
|
+
isError: true,
|
|
189
199
|
};
|
|
190
200
|
}
|
|
191
201
|
}
|
|
@@ -195,6 +205,7 @@ export async function executeCompleteMilestone(params, basePath = process.cwd())
|
|
|
195
205
|
return {
|
|
196
206
|
content: [{ type: "text", text: "Error: GSD database is not available. Cannot complete milestone." }],
|
|
197
207
|
details: { operation: "complete_milestone", error: "db_unavailable" },
|
|
208
|
+
isError: true,
|
|
198
209
|
};
|
|
199
210
|
}
|
|
200
211
|
try {
|
|
@@ -204,6 +215,7 @@ export async function executeCompleteMilestone(params, basePath = process.cwd())
|
|
|
204
215
|
return {
|
|
205
216
|
content: [{ type: "text", text: `Error completing milestone: ${result.error}` }],
|
|
206
217
|
details: { operation: "complete_milestone", error: result.error },
|
|
218
|
+
isError: true,
|
|
207
219
|
};
|
|
208
220
|
}
|
|
209
221
|
return {
|
|
@@ -221,6 +233,7 @@ export async function executeCompleteMilestone(params, basePath = process.cwd())
|
|
|
221
233
|
return {
|
|
222
234
|
content: [{ type: "text", text: `Error completing milestone: ${msg}` }],
|
|
223
235
|
details: { operation: "complete_milestone", error: msg },
|
|
236
|
+
isError: true,
|
|
224
237
|
};
|
|
225
238
|
}
|
|
226
239
|
}
|
|
@@ -230,6 +243,7 @@ export async function executeValidateMilestone(params, basePath = process.cwd())
|
|
|
230
243
|
return {
|
|
231
244
|
content: [{ type: "text", text: "Error: GSD database is not available. Cannot validate milestone." }],
|
|
232
245
|
details: { operation: "validate_milestone", error: "db_unavailable" },
|
|
246
|
+
isError: true,
|
|
233
247
|
};
|
|
234
248
|
}
|
|
235
249
|
try {
|
|
@@ -238,6 +252,7 @@ export async function executeValidateMilestone(params, basePath = process.cwd())
|
|
|
238
252
|
return {
|
|
239
253
|
content: [{ type: "text", text: `Error validating milestone: ${result.error}` }],
|
|
240
254
|
details: { operation: "validate_milestone", error: result.error },
|
|
255
|
+
isError: true,
|
|
241
256
|
};
|
|
242
257
|
}
|
|
243
258
|
return {
|
|
@@ -256,6 +271,7 @@ export async function executeValidateMilestone(params, basePath = process.cwd())
|
|
|
256
271
|
return {
|
|
257
272
|
content: [{ type: "text", text: `Error validating milestone: ${msg}` }],
|
|
258
273
|
details: { operation: "validate_milestone", error: msg },
|
|
274
|
+
isError: true,
|
|
259
275
|
};
|
|
260
276
|
}
|
|
261
277
|
}
|
|
@@ -265,6 +281,7 @@ export async function executeReassessRoadmap(params, basePath = process.cwd()) {
|
|
|
265
281
|
return {
|
|
266
282
|
content: [{ type: "text", text: "Error: GSD database is not available. Cannot reassess roadmap." }],
|
|
267
283
|
details: { operation: "reassess_roadmap", error: "db_unavailable" },
|
|
284
|
+
isError: true,
|
|
268
285
|
};
|
|
269
286
|
}
|
|
270
287
|
try {
|
|
@@ -273,6 +290,7 @@ export async function executeReassessRoadmap(params, basePath = process.cwd()) {
|
|
|
273
290
|
return {
|
|
274
291
|
content: [{ type: "text", text: `Error reassessing roadmap: ${result.error}` }],
|
|
275
292
|
details: { operation: "reassess_roadmap", error: result.error },
|
|
293
|
+
isError: true,
|
|
276
294
|
};
|
|
277
295
|
}
|
|
278
296
|
return {
|
|
@@ -292,6 +310,7 @@ export async function executeReassessRoadmap(params, basePath = process.cwd()) {
|
|
|
292
310
|
return {
|
|
293
311
|
content: [{ type: "text", text: `Error reassessing roadmap: ${msg}` }],
|
|
294
312
|
details: { operation: "reassess_roadmap", error: msg },
|
|
313
|
+
isError: true,
|
|
295
314
|
};
|
|
296
315
|
}
|
|
297
316
|
}
|
|
@@ -301,6 +320,7 @@ export async function executeSaveGateResult(params, basePath = process.cwd()) {
|
|
|
301
320
|
return {
|
|
302
321
|
content: [{ type: "text", text: "Error: GSD database is not available." }],
|
|
303
322
|
details: { operation: "save_gate_result", error: "db_unavailable" },
|
|
323
|
+
isError: true,
|
|
304
324
|
};
|
|
305
325
|
}
|
|
306
326
|
const validGates = ["Q3", "Q4", "Q5", "Q6", "Q7", "Q8"];
|
|
@@ -308,6 +328,7 @@ export async function executeSaveGateResult(params, basePath = process.cwd()) {
|
|
|
308
328
|
return {
|
|
309
329
|
content: [{ type: "text", text: `Error: Invalid gateId "${params.gateId}". Must be one of: ${validGates.join(", ")}` }],
|
|
310
330
|
details: { operation: "save_gate_result", error: "invalid_gate_id" },
|
|
331
|
+
isError: true,
|
|
311
332
|
};
|
|
312
333
|
}
|
|
313
334
|
const validVerdicts = ["pass", "flag", "omitted"];
|
|
@@ -315,6 +336,7 @@ export async function executeSaveGateResult(params, basePath = process.cwd()) {
|
|
|
315
336
|
return {
|
|
316
337
|
content: [{ type: "text", text: `Error: Invalid verdict "${params.verdict}". Must be one of: ${validVerdicts.join(", ")}` }],
|
|
317
338
|
details: { operation: "save_gate_result", error: "invalid_verdict" },
|
|
339
|
+
isError: true,
|
|
318
340
|
};
|
|
319
341
|
}
|
|
320
342
|
try {
|
|
@@ -339,6 +361,7 @@ export async function executeSaveGateResult(params, basePath = process.cwd()) {
|
|
|
339
361
|
return {
|
|
340
362
|
content: [{ type: "text", text: `Error saving gate result: ${msg}` }],
|
|
341
363
|
details: { operation: "save_gate_result", error: msg },
|
|
364
|
+
isError: true,
|
|
342
365
|
};
|
|
343
366
|
}
|
|
344
367
|
}
|
|
@@ -348,6 +371,7 @@ export async function executePlanMilestone(params, basePath = process.cwd()) {
|
|
|
348
371
|
return {
|
|
349
372
|
content: [{ type: "text", text: "Error: GSD database is not available. Cannot plan milestone." }],
|
|
350
373
|
details: { operation: "plan_milestone", error: "db_unavailable" },
|
|
374
|
+
isError: true,
|
|
351
375
|
};
|
|
352
376
|
}
|
|
353
377
|
try {
|
|
@@ -356,6 +380,7 @@ export async function executePlanMilestone(params, basePath = process.cwd()) {
|
|
|
356
380
|
return {
|
|
357
381
|
content: [{ type: "text", text: `Error planning milestone: ${result.error}` }],
|
|
358
382
|
details: { operation: "plan_milestone", error: result.error },
|
|
383
|
+
isError: true,
|
|
359
384
|
};
|
|
360
385
|
}
|
|
361
386
|
return {
|
|
@@ -373,6 +398,7 @@ export async function executePlanMilestone(params, basePath = process.cwd()) {
|
|
|
373
398
|
return {
|
|
374
399
|
content: [{ type: "text", text: `Error planning milestone: ${msg}` }],
|
|
375
400
|
details: { operation: "plan_milestone", error: msg },
|
|
401
|
+
isError: true,
|
|
376
402
|
};
|
|
377
403
|
}
|
|
378
404
|
}
|
|
@@ -382,6 +408,7 @@ export async function executePlanSlice(params, basePath = process.cwd()) {
|
|
|
382
408
|
return {
|
|
383
409
|
content: [{ type: "text", text: "Error: GSD database is not available. Cannot plan slice." }],
|
|
384
410
|
details: { operation: "plan_slice", error: "db_unavailable" },
|
|
411
|
+
isError: true,
|
|
385
412
|
};
|
|
386
413
|
}
|
|
387
414
|
try {
|
|
@@ -390,6 +417,7 @@ export async function executePlanSlice(params, basePath = process.cwd()) {
|
|
|
390
417
|
return {
|
|
391
418
|
content: [{ type: "text", text: `Error planning slice: ${result.error}` }],
|
|
392
419
|
details: { operation: "plan_slice", error: result.error },
|
|
420
|
+
isError: true,
|
|
393
421
|
};
|
|
394
422
|
}
|
|
395
423
|
return {
|
|
@@ -409,6 +437,7 @@ export async function executePlanSlice(params, basePath = process.cwd()) {
|
|
|
409
437
|
return {
|
|
410
438
|
content: [{ type: "text", text: `Error planning slice: ${msg}` }],
|
|
411
439
|
details: { operation: "plan_slice", error: msg },
|
|
440
|
+
isError: true,
|
|
412
441
|
};
|
|
413
442
|
}
|
|
414
443
|
}
|
|
@@ -418,6 +447,7 @@ export async function executeReplanSlice(params, basePath = process.cwd()) {
|
|
|
418
447
|
return {
|
|
419
448
|
content: [{ type: "text", text: "Error: GSD database is not available. Cannot replan slice." }],
|
|
420
449
|
details: { operation: "replan_slice", error: "db_unavailable" },
|
|
450
|
+
isError: true,
|
|
421
451
|
};
|
|
422
452
|
}
|
|
423
453
|
try {
|
|
@@ -426,6 +456,7 @@ export async function executeReplanSlice(params, basePath = process.cwd()) {
|
|
|
426
456
|
return {
|
|
427
457
|
content: [{ type: "text", text: `Error replanning slice: ${result.error}` }],
|
|
428
458
|
details: { operation: "replan_slice", error: result.error },
|
|
459
|
+
isError: true,
|
|
429
460
|
};
|
|
430
461
|
}
|
|
431
462
|
return {
|
|
@@ -445,6 +476,7 @@ export async function executeReplanSlice(params, basePath = process.cwd()) {
|
|
|
445
476
|
return {
|
|
446
477
|
content: [{ type: "text", text: `Error replanning slice: ${msg}` }],
|
|
447
478
|
details: { operation: "replan_slice", error: msg },
|
|
479
|
+
isError: true,
|
|
448
480
|
};
|
|
449
481
|
}
|
|
450
482
|
}
|
|
@@ -455,6 +487,7 @@ export async function executeMilestoneStatus(params, basePath = process.cwd()) {
|
|
|
455
487
|
return {
|
|
456
488
|
content: [{ type: "text", text: "Error: GSD database is not available." }],
|
|
457
489
|
details: { operation: "milestone_status", error: "db_unavailable" },
|
|
490
|
+
isError: true,
|
|
458
491
|
};
|
|
459
492
|
}
|
|
460
493
|
const adapter = _getAdapter();
|
|
@@ -503,6 +536,7 @@ export async function executeMilestoneStatus(params, basePath = process.cwd()) {
|
|
|
503
536
|
return {
|
|
504
537
|
content: [{ type: "text", text: `Error querying milestone status: ${msg}` }],
|
|
505
538
|
details: { operation: "milestone_status", error: msg },
|
|
539
|
+
isError: true,
|
|
506
540
|
};
|
|
507
541
|
}
|
|
508
542
|
}
|
|
@@ -45,6 +45,30 @@ const WINDOWS_BLOCKED_PATHS = new Set([
|
|
|
45
45
|
"C:\\Program Files",
|
|
46
46
|
"C:\\Program Files (x86)",
|
|
47
47
|
]);
|
|
48
|
+
const WINDOWS_BLOCKED_SUFFIXES = new Set([
|
|
49
|
+
"\\",
|
|
50
|
+
"\\windows",
|
|
51
|
+
"\\windows\\system32",
|
|
52
|
+
"\\program files",
|
|
53
|
+
"\\program files (x86)",
|
|
54
|
+
]);
|
|
55
|
+
function normalizePathForComparison(dirPath) {
|
|
56
|
+
let normalized = dirPath.replace(/[/\\]+$/, "");
|
|
57
|
+
if (normalized === "") {
|
|
58
|
+
normalized = "/";
|
|
59
|
+
}
|
|
60
|
+
else if (/^[A-Za-z]:$/.test(normalized)) {
|
|
61
|
+
normalized += "\\";
|
|
62
|
+
}
|
|
63
|
+
return platform() === "win32" ? normalized.toLowerCase() : normalized;
|
|
64
|
+
}
|
|
65
|
+
function isBlockedWindowsPath(normalized) {
|
|
66
|
+
if (!/^[a-z]:\\/.test(normalized)) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
const suffix = normalized.slice(2);
|
|
70
|
+
return WINDOWS_BLOCKED_SUFFIXES.has(suffix);
|
|
71
|
+
}
|
|
48
72
|
// ─── Core Validation ────────────────────────────────────────────────────────────
|
|
49
73
|
/**
|
|
50
74
|
* Validate whether a directory is safe for GSD to operate in.
|
|
@@ -67,16 +91,10 @@ export function validateDirectory(dirPath) {
|
|
|
67
91
|
}
|
|
68
92
|
// Normalize trailing slashes for consistent comparison.
|
|
69
93
|
// Special cases: "/" → "/" (not ""), "C:\" → "C:\" (not "C:")
|
|
70
|
-
|
|
71
|
-
if (normalized === "") {
|
|
72
|
-
normalized = "/";
|
|
73
|
-
}
|
|
74
|
-
else if (/^[A-Za-z]:$/.test(normalized)) {
|
|
75
|
-
normalized = normalized + "\\";
|
|
76
|
-
}
|
|
94
|
+
const normalized = normalizePathForComparison(resolved);
|
|
77
95
|
// ── Check 1: Blocked system paths ──────────────────────────────────────
|
|
78
96
|
const blockedPaths = platform() === "win32" ? WINDOWS_BLOCKED_PATHS : UNIX_BLOCKED_PATHS;
|
|
79
|
-
if (blockedPaths.has(normalized)) {
|
|
97
|
+
if (platform() === "win32" ? isBlockedWindowsPath(normalized) : blockedPaths.has(normalized)) {
|
|
80
98
|
return {
|
|
81
99
|
safe: false,
|
|
82
100
|
severity: "blocked",
|
|
@@ -86,10 +104,10 @@ export function validateDirectory(dirPath) {
|
|
|
86
104
|
// ── Check 2: Home directory itself (not subdirs) ───────────────────────
|
|
87
105
|
let resolvedHome;
|
|
88
106
|
try {
|
|
89
|
-
resolvedHome = realpathSync(resolve(homedir()))
|
|
107
|
+
resolvedHome = normalizePathForComparison(realpathSync(resolve(homedir())));
|
|
90
108
|
}
|
|
91
109
|
catch {
|
|
92
|
-
resolvedHome = resolve(homedir())
|
|
110
|
+
resolvedHome = normalizePathForComparison(resolve(homedir()));
|
|
93
111
|
}
|
|
94
112
|
if (normalized === resolvedHome) {
|
|
95
113
|
return {
|
|
@@ -101,10 +119,10 @@ export function validateDirectory(dirPath) {
|
|
|
101
119
|
// ── Check 3: Temp directory root ───────────────────────────────────────
|
|
102
120
|
let resolvedTmp;
|
|
103
121
|
try {
|
|
104
|
-
resolvedTmp = realpathSync(resolve(tmpdir()))
|
|
122
|
+
resolvedTmp = normalizePathForComparison(realpathSync(resolve(tmpdir())));
|
|
105
123
|
}
|
|
106
124
|
catch {
|
|
107
|
-
resolvedTmp = resolve(tmpdir())
|
|
125
|
+
resolvedTmp = normalizePathForComparison(resolve(tmpdir()));
|
|
108
126
|
}
|
|
109
127
|
if (normalized === resolvedTmp) {
|
|
110
128
|
return {
|
|
@@ -2,6 +2,7 @@ import { createHash, randomUUID } from "node:crypto";
|
|
|
2
2
|
import { appendFileSync, readFileSync, existsSync, mkdirSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
5
|
+
import { withFileLockSync } from "./file-lock.js";
|
|
5
6
|
import { logWarning } from "./workflow-logger.js";
|
|
6
7
|
// ─── Session ID ───────────────────────────────────────────────────────────
|
|
7
8
|
/**
|
|
@@ -88,17 +89,28 @@ export function findForkPoint(logA, logB) {
|
|
|
88
89
|
export function compactMilestoneEvents(basePath, milestoneId) {
|
|
89
90
|
const logPath = join(basePath, ".gsd", "event-log.jsonl");
|
|
90
91
|
const archivePath = join(basePath, ".gsd", `event-log-${milestoneId}.jsonl.archived`);
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
92
|
+
return withFileLockSync(logPath, () => {
|
|
93
|
+
const allEvents = readEvents(logPath);
|
|
94
|
+
// Single-pass partition to halve the work (per reviewer agent)
|
|
95
|
+
const toArchive = [];
|
|
96
|
+
const remaining = [];
|
|
97
|
+
for (const e of allEvents) {
|
|
98
|
+
if (e.params.milestoneId === milestoneId) {
|
|
99
|
+
toArchive.push(e);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
remaining.push(e);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (toArchive.length === 0) {
|
|
106
|
+
return { archived: 0 };
|
|
107
|
+
}
|
|
108
|
+
// Write archived events to .jsonl.archived file (crash-safe)
|
|
109
|
+
atomicWriteSync(archivePath, toArchive.map((e) => JSON.stringify(e)).join("\n") + "\n");
|
|
110
|
+
// Truncate active log to remaining events only
|
|
111
|
+
atomicWriteSync(logPath, remaining.length > 0
|
|
112
|
+
? remaining.map((e) => JSON.stringify(e)).join("\n") + "\n"
|
|
113
|
+
: "");
|
|
114
|
+
return { archived: toArchive.length };
|
|
115
|
+
});
|
|
104
116
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ensureProjectWorkflowMcpConfig, } from "./mcp-project-config.js";
|
|
2
|
+
import { usesWorkflowMcpTransport } from "./workflow-mcp.js";
|
|
3
|
+
function getAuthModeSafe(ctx, provider) {
|
|
4
|
+
if (!provider)
|
|
5
|
+
return undefined;
|
|
6
|
+
const getAuthMode = ctx.modelRegistry?.getProviderAuthMode;
|
|
7
|
+
if (typeof getAuthMode !== "function")
|
|
8
|
+
return undefined;
|
|
9
|
+
try {
|
|
10
|
+
return getAuthMode(provider);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function hasClaudeCodeProvider(ctx) {
|
|
17
|
+
return getAuthModeSafe(ctx, "claude-code") === "externalCli";
|
|
18
|
+
}
|
|
19
|
+
function isClaudeCodeProviderReady(ctx) {
|
|
20
|
+
const readyCheck = ctx.modelRegistry?.isProviderRequestReady;
|
|
21
|
+
if (typeof readyCheck !== "function")
|
|
22
|
+
return false;
|
|
23
|
+
try {
|
|
24
|
+
return readyCheck("claude-code");
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function shouldAutoPrepareWorkflowMcp(ctx) {
|
|
31
|
+
const provider = ctx.model?.provider;
|
|
32
|
+
const baseUrl = ctx.model?.baseUrl;
|
|
33
|
+
const authMode = getAuthModeSafe(ctx, provider);
|
|
34
|
+
if (usesWorkflowMcpTransport(authMode, baseUrl))
|
|
35
|
+
return true;
|
|
36
|
+
if (provider === "claude-code")
|
|
37
|
+
return true;
|
|
38
|
+
if (hasClaudeCodeProvider(ctx))
|
|
39
|
+
return true;
|
|
40
|
+
return isClaudeCodeProviderReady(ctx);
|
|
41
|
+
}
|
|
42
|
+
export function prepareWorkflowMcpForProject(ctx, projectRoot) {
|
|
43
|
+
if (!shouldAutoPrepareWorkflowMcp(ctx))
|
|
44
|
+
return null;
|
|
45
|
+
try {
|
|
46
|
+
const result = ensureProjectWorkflowMcpConfig(projectRoot);
|
|
47
|
+
if (result.status !== "unchanged") {
|
|
48
|
+
ctx.ui?.notify?.(`Claude Code MCP prepared at ${result.configPath}`, "info");
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
ctx.ui?.notify?.(`Claude Code MCP prep failed: ${err instanceof Error ? err.message : String(err)}. Detected Claude Code model but no workflow MCP. Please run /gsd mcp init . from your project root.`, "warning");
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -287,6 +287,17 @@ export function getRequiredWorkflowToolsForAutoUnit(unitType) {
|
|
|
287
287
|
export function usesWorkflowMcpTransport(authMode, baseUrl) {
|
|
288
288
|
return authMode === "externalCli" && typeof baseUrl === "string" && baseUrl.startsWith("local://");
|
|
289
289
|
}
|
|
290
|
+
export function supportsStructuredQuestions(activeTools, options = {}) {
|
|
291
|
+
if (!activeTools.includes("ask_user_questions"))
|
|
292
|
+
return false;
|
|
293
|
+
// Workflow MCP currently exposes ask_user_questions via MCP form elicitation.
|
|
294
|
+
// Local external CLI transports such as Claude Code can invoke the tool, but
|
|
295
|
+
// do not reliably complete that elicitation round-trip yet, so guided discuss
|
|
296
|
+
// prompts must fall back to plain-text questioning.
|
|
297
|
+
if (usesWorkflowMcpTransport(options.authMode, options.baseUrl))
|
|
298
|
+
return false;
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
290
301
|
export function getWorkflowTransportSupportError(provider, requiredTools, options = {}) {
|
|
291
302
|
if (!provider || requiredTools.length === 0)
|
|
292
303
|
return null;
|
|
@@ -299,7 +310,7 @@ export function getWorkflowTransportSupportError(provider, requiredTools, option
|
|
|
299
310
|
const unitLabel = options.unitType ? ` for ${options.unitType}` : "";
|
|
300
311
|
const providerLabel = `"${provider}"`;
|
|
301
312
|
if (!launch) {
|
|
302
|
-
return `Provider ${providerLabel} cannot run ${surface}${unitLabel}: the GSD workflow MCP server is not configured or discoverable.
|
|
313
|
+
return `Provider ${providerLabel} cannot run ${surface}${unitLabel}: the GSD workflow MCP server is not configured or discoverable. Detected Claude Code model but no workflow MCP. Please run /gsd mcp init . from your project root. You can also configure GSD_WORKFLOW_MCP_COMMAND, build packages/mcp-server/dist/cli.js, or install gsd-mcp-server on PATH.`;
|
|
303
314
|
}
|
|
304
315
|
const missing = [...new Set(requiredTools)].filter((tool) => !MCP_WORKFLOW_TOOL_SURFACE.has(tool));
|
|
305
316
|
if (missing.length === 0)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { mkdirSync } from "node:fs";
|
|
1
2
|
export default function auditCommand(pi) {
|
|
2
3
|
pi.registerCommand("audit", {
|
|
3
4
|
description: "Audit the current codebase against a specific goal and write a structured report to .gsd/audits/",
|
|
@@ -26,7 +27,7 @@ export default function auditCommand(pi) {
|
|
|
26
27
|
.slice(0, 40);
|
|
27
28
|
const outputPath = `.gsd/audits/${timestamp}-${slug}.md`;
|
|
28
29
|
// ── Step 3: Ensure the output directory exists ───────────────────────
|
|
29
|
-
|
|
30
|
+
mkdirSync(".gsd/audits", { recursive: true });
|
|
30
31
|
// ── Step 4: Send the audit prompt to the agent ───────────────────────
|
|
31
32
|
const prompt = `You are conducting a codebase audit. This is a **read-only recce** — you will explore the codebase deeply and produce a structured report. You must NOT edit any code or create any files other than the audit report itself.
|
|
32
33
|
|
|
@@ -14,8 +14,10 @@ const execFile = promisify(execFileCb);
|
|
|
14
14
|
// ============================================================================
|
|
15
15
|
// Directory helpers
|
|
16
16
|
// ============================================================================
|
|
17
|
-
function encodeCwd(cwd) {
|
|
18
|
-
|
|
17
|
+
export function encodeCwd(cwd) {
|
|
18
|
+
// Encode the entire cwd so Windows drive letters, separators, and UNC
|
|
19
|
+
// prefixes cannot leak into the isolation path.
|
|
20
|
+
return Buffer.from(cwd, "utf8").toString("base64url");
|
|
19
21
|
}
|
|
20
22
|
const gsdHome = process.env.GSD_HOME || path.join(os.homedir(), ".gsd");
|
|
21
23
|
function getIsolationBaseDir(cwd, taskId) {
|
package/dist/update-check.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ interface UpdateCheckCache {
|
|
|
8
8
|
export declare function compareSemver(a: string, b: string): number;
|
|
9
9
|
export declare function readUpdateCache(cachePath?: string): UpdateCheckCache | null;
|
|
10
10
|
export declare function writeUpdateCache(cache: UpdateCheckCache, cachePath?: string): void;
|
|
11
|
+
export declare function fetchLatestVersionFromRegistry(registryUrl?: string, fetchTimeoutMs?: number): Promise<string | null>;
|
|
11
12
|
export interface UpdateCheckOptions {
|
|
12
13
|
currentVersion?: string;
|
|
13
14
|
cachePath?: string;
|
package/dist/update-check.js
CHANGED
|
@@ -7,6 +7,7 @@ const CACHE_FILE = join(appRoot, '.update-check');
|
|
|
7
7
|
const NPM_PACKAGE_NAME = 'gsd-pi';
|
|
8
8
|
const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
9
9
|
const FETCH_TIMEOUT_MS = 5000;
|
|
10
|
+
const DEFAULT_REGISTRY_URL = `https://registry.npmjs.org/${NPM_PACKAGE_NAME}/latest`;
|
|
10
11
|
/**
|
|
11
12
|
* Compares two semver strings. Returns 1 if a > b, -1 if a < b, 0 if equal.
|
|
12
13
|
*/
|
|
@@ -42,6 +43,29 @@ export function writeUpdateCache(cache, cachePath = CACHE_FILE) {
|
|
|
42
43
|
// Non-fatal — don't block startup if cache write fails
|
|
43
44
|
}
|
|
44
45
|
}
|
|
46
|
+
function normalizeLatestVersion(version) {
|
|
47
|
+
if (typeof version !== 'string')
|
|
48
|
+
return null;
|
|
49
|
+
const trimmed = version.trim().replace(/^v/, '');
|
|
50
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
51
|
+
}
|
|
52
|
+
export async function fetchLatestVersionFromRegistry(registryUrl = DEFAULT_REGISTRY_URL, fetchTimeoutMs = FETCH_TIMEOUT_MS) {
|
|
53
|
+
const controller = new AbortController();
|
|
54
|
+
const timeout = setTimeout(() => controller.abort(), fetchTimeoutMs);
|
|
55
|
+
try {
|
|
56
|
+
const res = await fetch(registryUrl, { signal: controller.signal });
|
|
57
|
+
if (!res.ok)
|
|
58
|
+
return null;
|
|
59
|
+
const data = (await res.json());
|
|
60
|
+
return normalizeLatestVersion(data.version);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
clearTimeout(timeout);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
45
69
|
function printUpdateBanner(current, latest) {
|
|
46
70
|
process.stderr.write(` ${chalk.yellow('Update available:')} ${chalk.dim(`v${current}`)} → ${chalk.bold(`v${latest}`)}\n` +
|
|
47
71
|
` ${chalk.dim('Run')} npm update -g gsd-pi ${chalk.dim('or')} /gsd update ${chalk.dim('to upgrade')}\n\n`);
|
|
@@ -53,7 +77,7 @@ function printUpdateBanner(current, latest) {
|
|
|
53
77
|
export async function checkForUpdates(options = {}) {
|
|
54
78
|
const currentVersion = options.currentVersion || process.env.GSD_VERSION || '0.0.0';
|
|
55
79
|
const cachePath = options.cachePath || CACHE_FILE;
|
|
56
|
-
const registryUrl = options.registryUrl ||
|
|
80
|
+
const registryUrl = options.registryUrl || DEFAULT_REGISTRY_URL;
|
|
57
81
|
const checkIntervalMs = options.checkIntervalMs ?? CHECK_INTERVAL_MS;
|
|
58
82
|
const fetchTimeoutMs = options.fetchTimeoutMs ?? FETCH_TIMEOUT_MS;
|
|
59
83
|
const onUpdate = options.onUpdate || printUpdateBanner;
|
|
@@ -65,16 +89,8 @@ export async function checkForUpdates(options = {}) {
|
|
|
65
89
|
}
|
|
66
90
|
return;
|
|
67
91
|
}
|
|
68
|
-
// Fetch latest version from npm registry
|
|
69
|
-
const controller = new AbortController();
|
|
70
|
-
const timeout = setTimeout(() => controller.abort(), fetchTimeoutMs);
|
|
71
92
|
try {
|
|
72
|
-
const
|
|
73
|
-
clearTimeout(timeout);
|
|
74
|
-
if (!res.ok)
|
|
75
|
-
return;
|
|
76
|
-
const data = (await res.json());
|
|
77
|
-
const latestVersion = data.version;
|
|
93
|
+
const latestVersion = await fetchLatestVersionFromRegistry(registryUrl, fetchTimeoutMs);
|
|
78
94
|
if (!latestVersion)
|
|
79
95
|
return;
|
|
80
96
|
writeUpdateCache({ lastCheck: Date.now(), latestVersion }, cachePath);
|
|
@@ -85,9 +101,6 @@ export async function checkForUpdates(options = {}) {
|
|
|
85
101
|
catch {
|
|
86
102
|
// Network error or timeout — silently ignore, don't block startup
|
|
87
103
|
}
|
|
88
|
-
finally {
|
|
89
|
-
clearTimeout(timeout);
|
|
90
|
-
}
|
|
91
104
|
}
|
|
92
105
|
const PROMPT_TIMEOUT_MS = 30_000;
|
|
93
106
|
/**
|
|
@@ -101,7 +114,7 @@ const PROMPT_TIMEOUT_MS = 30_000;
|
|
|
101
114
|
export async function checkAndPromptForUpdates(options = {}) {
|
|
102
115
|
const currentVersion = options.currentVersion || process.env.GSD_VERSION || '0.0.0';
|
|
103
116
|
const cachePath = options.cachePath || CACHE_FILE;
|
|
104
|
-
const registryUrl = options.registryUrl ||
|
|
117
|
+
const registryUrl = options.registryUrl || DEFAULT_REGISTRY_URL;
|
|
105
118
|
const checkIntervalMs = options.checkIntervalMs ?? CHECK_INTERVAL_MS;
|
|
106
119
|
const fetchTimeoutMs = options.fetchTimeoutMs ?? FETCH_TIMEOUT_MS;
|
|
107
120
|
// Determine latest version (from cache or network)
|
|
@@ -111,25 +124,15 @@ export async function checkAndPromptForUpdates(options = {}) {
|
|
|
111
124
|
latestVersion = cache.latestVersion;
|
|
112
125
|
}
|
|
113
126
|
else {
|
|
114
|
-
const controller = new AbortController();
|
|
115
|
-
const timeout = setTimeout(() => controller.abort(), fetchTimeoutMs);
|
|
116
127
|
try {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const data = (await res.json());
|
|
121
|
-
if (data.version) {
|
|
122
|
-
latestVersion = data.version;
|
|
123
|
-
writeUpdateCache({ lastCheck: Date.now(), latestVersion }, cachePath);
|
|
124
|
-
}
|
|
128
|
+
latestVersion = await fetchLatestVersionFromRegistry(registryUrl, fetchTimeoutMs);
|
|
129
|
+
if (latestVersion) {
|
|
130
|
+
writeUpdateCache({ lastCheck: Date.now(), latestVersion }, cachePath);
|
|
125
131
|
}
|
|
126
132
|
}
|
|
127
133
|
catch {
|
|
128
134
|
// Network unavailable — silently skip
|
|
129
135
|
}
|
|
130
|
-
finally {
|
|
131
|
-
clearTimeout(timeout);
|
|
132
|
-
}
|
|
133
136
|
}
|
|
134
137
|
if (!latestVersion || compareSemver(latestVersion, currentVersion) <= 0) {
|
|
135
138
|
return false;
|
package/dist/update-cmd.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execSync } from 'node:child_process';
|
|
2
|
-
import { compareSemver } from './update-check.js';
|
|
2
|
+
import { compareSemver, fetchLatestVersionFromRegistry } from './update-check.js';
|
|
3
3
|
const NPM_PACKAGE = 'gsd-pi';
|
|
4
4
|
export async function runUpdate() {
|
|
5
5
|
const current = process.env.GSD_VERSION || '0.0.0';
|
|
@@ -10,16 +10,8 @@ export async function runUpdate() {
|
|
|
10
10
|
const reset = '\x1b[0m';
|
|
11
11
|
process.stdout.write(`${dim}Current version:${reset} v${current}\n`);
|
|
12
12
|
process.stdout.write(`${dim}Checking npm registry...${reset}\n`);
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
latest = execSync(`npm view ${NPM_PACKAGE} version --fetch-retry-mintimeout=3000`, {
|
|
17
|
-
encoding: 'utf-8',
|
|
18
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
19
|
-
env: { ...process.env, npm_config_cache: '' },
|
|
20
|
-
}).trim();
|
|
21
|
-
}
|
|
22
|
-
catch {
|
|
13
|
+
const latest = await fetchLatestVersionFromRegistry();
|
|
14
|
+
if (!latest) {
|
|
23
15
|
process.stderr.write(`${yellow}Failed to reach npm registry.${reset}\n`);
|
|
24
16
|
process.exit(1);
|
|
25
17
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
eMly3KqfZihJJAHQGmxvO
|