gsd-pi 2.66.1-dev.ed243f2 → 2.67.0
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/claude-cli-check.d.ts +8 -0
- package/dist/claude-cli-check.js +36 -0
- package/dist/cli.js +40 -0
- package/dist/onboarding.js +19 -2
- package/dist/resources/extensions/ask-user-questions.js +79 -11
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +4 -3
- package/dist/resources/extensions/claude-code-cli/readiness.js +63 -12
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +10 -3
- package/dist/resources/extensions/gsd/auto/loop.js +13 -1
- package/dist/resources/extensions/gsd/auto/phases.js +22 -3
- package/dist/resources/extensions/gsd/auto/run-unit.js +10 -2
- package/dist/resources/extensions/gsd/auto/session.js +1 -1
- package/dist/resources/extensions/gsd/auto-dashboard.js +65 -15
- package/dist/resources/extensions/gsd/auto-dispatch.js +30 -28
- package/dist/resources/extensions/gsd/auto-model-selection.js +12 -3
- package/dist/resources/extensions/gsd/auto-prompts.js +173 -25
- package/dist/resources/extensions/gsd/auto-recovery.js +11 -12
- package/dist/resources/extensions/gsd/auto.js +13 -1
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +32 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +18 -6
- package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +5 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +59 -5
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +8 -5
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +186 -14
- package/dist/resources/extensions/gsd/codebase-generator.js +4 -0
- package/dist/resources/extensions/gsd/commands/handlers/core.js +3 -3
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +10 -4
- package/dist/resources/extensions/gsd/context-store.js +134 -2
- package/dist/resources/extensions/gsd/custom-workflow-engine.js +3 -1
- package/dist/resources/extensions/gsd/detection.js +6 -0
- package/dist/resources/extensions/gsd/files.js +19 -2
- package/dist/resources/extensions/gsd/guided-flow.js +12 -8
- package/dist/resources/extensions/gsd/index.js +1 -1
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +2 -0
- package/dist/resources/extensions/gsd/parsers-legacy.js +3 -1
- package/dist/resources/extensions/gsd/preferences.js +6 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +7 -7
- package/dist/resources/extensions/gsd/prompts/discuss.md +3 -3
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -3
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +3 -1
- package/dist/resources/extensions/gsd/prompts/rethink.md +6 -2
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +4 -4
- package/dist/resources/extensions/gsd/prompts/worktree-merge.md +3 -1
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +2 -1
- package/dist/resources/extensions/gsd/state.js +2 -1
- package/dist/resources/extensions/gsd/visualizer-overlay.js +27 -26
- package/dist/resources/extensions/gsd/workflow-reconcile.js +46 -7
- package/dist/resources/extensions/remote-questions/manager.js +8 -0
- package/dist/resources/extensions/shared/interview-ui.js +10 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- 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 +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 +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 +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 +14 -14
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- package/dist/web/standalone/.next/server/chunks/7471.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-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/app/_not-found/{page-f2a7482d42a5614b.js → page-2f24283c162b6ab3.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/{layout-a16c7a7ecdf0c2cf.js → layout-9ecfd95f343793f0.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-62be3b5fa91e4c8f.js +1 -0
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +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/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +4 -3
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/utils/json-parse.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/json-parse.js +11 -1
- package/packages/pi-ai/dist/utils/json-parse.js.map +1 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.js +60 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.js.map +1 -1
- package/packages/pi-ai/dist/utils/tests/json-parse.test.d.ts +2 -0
- package/packages/pi-ai/dist/utils/tests/json-parse.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/tests/json-parse.test.js +14 -0
- package/packages/pi-ai/dist/utils/tests/json-parse.test.js.map +1 -0
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js +10 -0
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js.map +1 -1
- package/packages/pi-ai/src/providers/anthropic-shared.ts +4 -3
- package/packages/pi-ai/src/utils/json-parse.ts +11 -1
- package/packages/pi-ai/src/utils/repair-tool-json.ts +69 -1
- package/packages/pi-ai/src/utils/tests/json-parse.test.ts +17 -0
- package/packages/pi-ai/src/utils/tests/repair-tool-json.test.ts +13 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts +16 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +58 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +58 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js +17 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +9 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +2 -2
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +4 -0
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +69 -0
- package/packages/pi-coding-agent/src/core/retry-handler.ts +66 -1
- package/packages/pi-coding-agent/src/core/sdk.ts +5 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/provider-display-name.test.ts +18 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +2 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +11 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +2 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/scoped-models-selector.ts +2 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +2 -2
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js +13 -0
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +35 -0
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -0
- package/packages/pi-tui/dist/__tests__/tui.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/tui.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/tui.test.js +43 -0
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -0
- package/packages/pi-tui/dist/autocomplete.d.ts.map +1 -1
- package/packages/pi-tui/dist/autocomplete.js +9 -7
- package/packages/pi-tui/dist/autocomplete.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/editor.test.d.ts +2 -0
- package/packages/pi-tui/dist/components/__tests__/editor.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/components/__tests__/editor.test.js +54 -0
- package/packages/pi-tui/dist/components/__tests__/editor.test.js.map +1 -0
- package/packages/pi-tui/dist/components/editor.d.ts +3 -1
- package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/editor.js +14 -3
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.js +6 -0
- package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +8 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/__tests__/autocomplete.test.ts +15 -0
- package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +43 -0
- package/packages/pi-tui/src/__tests__/tui.test.ts +50 -0
- package/packages/pi-tui/src/autocomplete.ts +9 -7
- package/packages/pi-tui/src/components/__tests__/editor.test.ts +64 -0
- package/packages/pi-tui/src/components/editor.ts +14 -3
- package/packages/pi-tui/src/stdin-buffer.ts +7 -0
- package/packages/pi-tui/src/tui.ts +9 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/ask-user-questions.ts +103 -11
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +4 -3
- package/src/resources/extensions/claude-code-cli/readiness.ts +67 -12
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +12 -3
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +17 -0
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +18 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -1
- package/src/resources/extensions/gsd/auto/loop.ts +14 -1
- package/src/resources/extensions/gsd/auto/phases.ts +27 -4
- package/src/resources/extensions/gsd/auto/run-unit.ts +14 -2
- package/src/resources/extensions/gsd/auto/session.ts +1 -1
- package/src/resources/extensions/gsd/auto-dashboard.ts +76 -16
- package/src/resources/extensions/gsd/auto-dispatch.ts +36 -35
- package/src/resources/extensions/gsd/auto-model-selection.ts +12 -3
- package/src/resources/extensions/gsd/auto-prompts.ts +195 -25
- package/src/resources/extensions/gsd/auto-recovery.ts +15 -15
- package/src/resources/extensions/gsd/auto.ts +12 -1
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +34 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +27 -6
- package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +6 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +67 -6
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +11 -8
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +209 -16
- package/src/resources/extensions/gsd/codebase-generator.ts +4 -0
- package/src/resources/extensions/gsd/commands/handlers/core.ts +6 -6
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +11 -4
- package/src/resources/extensions/gsd/context-store.ts +167 -2
- package/src/resources/extensions/gsd/custom-workflow-engine.ts +3 -1
- package/src/resources/extensions/gsd/detection.ts +6 -0
- package/src/resources/extensions/gsd/files.ts +21 -2
- package/src/resources/extensions/gsd/guided-flow.ts +15 -8
- package/src/resources/extensions/gsd/index.ts +6 -0
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +2 -0
- package/src/resources/extensions/gsd/parsers-legacy.ts +3 -1
- package/src/resources/extensions/gsd/preferences.ts +6 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss-prepared.md +7 -7
- package/src/resources/extensions/gsd/prompts/discuss.md +3 -3
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -3
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +3 -1
- package/src/resources/extensions/gsd/prompts/rethink.md +6 -2
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +4 -4
- package/src/resources/extensions/gsd/prompts/worktree-merge.md +3 -1
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +4 -1
- package/src/resources/extensions/gsd/state.ts +2 -1
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +52 -1
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +50 -2
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +21 -7
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/context-store.test.ts +176 -0
- package/src/resources/extensions/gsd/tests/core-overlay-fallback.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/decision-scope-cascade.test.ts +370 -0
- package/src/resources/extensions/gsd/tests/detection.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +53 -13
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/measurement.test.ts +531 -0
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +3 -4
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +71 -2
- package/src/resources/extensions/gsd/tests/parsers.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +60 -0
- package/src/resources/extensions/gsd/tests/queue-execution-guard.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/reactive-graph.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/register-shortcuts.test.ts +73 -0
- package/src/resources/extensions/gsd/tests/remote-questions.test.ts +98 -0
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/workflow-reconcile.test.ts +91 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +210 -35
- package/src/resources/extensions/gsd/visualizer-overlay.ts +31 -27
- package/src/resources/extensions/gsd/workflow-reconcile.ts +59 -8
- package/src/resources/extensions/remote-questions/manager.ts +9 -0
- package/src/resources/extensions/shared/interview-ui.ts +13 -0
- package/dist/web/standalone/.next/static/chunks/app/page-0c485498795110d6.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +0 -1
- /package/dist/web/standalone/.next/static/{HAq0VE4k68rhRvJbQL1VW → DFZllMYDbO0OwyS6FSvm5}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{HAq0VE4k68rhRvJbQL1VW → DFZllMYDbO0OwyS6FSvm5}/_ssgManifest.js +0 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
const MILESTONE_CONTEXT_RE = /M\d+(?:-[a-z0-9]{6})?-CONTEXT\.md$/;
|
|
2
|
+
const CONTEXT_MILESTONE_RE = /(?:^|[/\\])(M\d+(?:-[a-z0-9]{6})?)-CONTEXT\.md$/i;
|
|
3
|
+
const DEPTH_VERIFICATION_MILESTONE_RE = /depth_verification[_-](M\d+(?:-[a-z0-9]{6})?)/i;
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
6
|
* Path segment that identifies .gsd/ planning artifacts.
|
|
@@ -26,11 +28,53 @@ const QUEUE_SAFE_TOOLS = new Set([
|
|
|
26
28
|
*/
|
|
27
29
|
const BASH_READ_ONLY_RE = /^\s*(cat|head|tail|less|more|wc|file|stat|du|df|which|type|echo|printf|ls|find|grep|rg|awk|sed\b(?!.*-i)|sort|uniq|diff|comm|tr|cut|tee\s+-a\s+\/dev\/null|git\s+(log|show|diff|status|branch|tag|remote|rev-parse|ls-files|blame|shortlog|describe|stash\s+list|config\s+--get|cat-file)|gh\s+(issue|pr|api|repo|release)\s+(view|list|diff|status|checks)|mkdir\s+-p\s+\.gsd|rtk\s)/;
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
const verifiedDepthMilestones = new Set<string>();
|
|
30
32
|
let activeQueuePhase = false;
|
|
31
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Discussion gate enforcement state.
|
|
36
|
+
*
|
|
37
|
+
* When ask_user_questions is called with a recognized gate question ID,
|
|
38
|
+
* we track the pending gate. Until the gate is confirmed (user selects the
|
|
39
|
+
* first/recommended option), all non-read-only tool calls are blocked.
|
|
40
|
+
* This mechanically prevents the model from rationalizing past failed or
|
|
41
|
+
* cancelled gate questions.
|
|
42
|
+
*/
|
|
43
|
+
let pendingGateId: string | null = null;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Recognized gate question ID patterns.
|
|
47
|
+
* These appear in both discuss-prepared.md (4-layer) and discuss.md (depth/requirements/roadmap).
|
|
48
|
+
*/
|
|
49
|
+
const GATE_QUESTION_PATTERNS = [
|
|
50
|
+
"layer1_scope_gate",
|
|
51
|
+
"layer2_architecture_gate",
|
|
52
|
+
"layer3_error_gate",
|
|
53
|
+
"layer4_quality_gate",
|
|
54
|
+
"depth_verification",
|
|
55
|
+
] as const;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Tools that are safe to call while a gate is pending.
|
|
59
|
+
* Includes read-only tools and ask_user_questions itself (so the model can re-ask).
|
|
60
|
+
*/
|
|
61
|
+
const GATE_SAFE_TOOLS = new Set([
|
|
62
|
+
"ask_user_questions",
|
|
63
|
+
"read", "grep", "find", "ls", "glob",
|
|
64
|
+
"search-the-web", "resolve_library", "get_library_docs", "fetch_page",
|
|
65
|
+
"search_and_read",
|
|
66
|
+
]);
|
|
67
|
+
|
|
32
68
|
export function isDepthVerified(): boolean {
|
|
33
|
-
return
|
|
69
|
+
return verifiedDepthMilestones.size > 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Check whether a specific milestone has passed depth verification.
|
|
74
|
+
*/
|
|
75
|
+
export function isMilestoneDepthVerified(milestoneId: string | null | undefined): boolean {
|
|
76
|
+
if (!milestoneId) return false;
|
|
77
|
+
return verifiedDepthMilestones.has(milestoneId);
|
|
34
78
|
}
|
|
35
79
|
|
|
36
80
|
export function isQueuePhaseActive(): boolean {
|
|
@@ -42,16 +86,120 @@ export function setQueuePhaseActive(active: boolean): void {
|
|
|
42
86
|
}
|
|
43
87
|
|
|
44
88
|
export function resetWriteGateState(): void {
|
|
45
|
-
|
|
89
|
+
verifiedDepthMilestones.clear();
|
|
90
|
+
pendingGateId = null;
|
|
46
91
|
}
|
|
47
92
|
|
|
48
93
|
export function clearDiscussionFlowState(): void {
|
|
49
|
-
|
|
94
|
+
verifiedDepthMilestones.clear();
|
|
50
95
|
activeQueuePhase = false;
|
|
96
|
+
pendingGateId = null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function markDepthVerified(milestoneId?: string | null): void {
|
|
100
|
+
if (!milestoneId) return;
|
|
101
|
+
verifiedDepthMilestones.add(milestoneId);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Check whether a question ID matches a recognized gate pattern.
|
|
106
|
+
*/
|
|
107
|
+
export function isGateQuestionId(questionId: string): boolean {
|
|
108
|
+
return GATE_QUESTION_PATTERNS.some(pattern => questionId.includes(pattern));
|
|
51
109
|
}
|
|
52
110
|
|
|
53
|
-
|
|
54
|
-
|
|
111
|
+
/**
|
|
112
|
+
* Extract the milestone ID embedded in a depth-verification question id.
|
|
113
|
+
* Prompts are expected to use ids like `depth_verification_M001_confirm`.
|
|
114
|
+
*/
|
|
115
|
+
export function extractDepthVerificationMilestoneId(questionId: string): string | null {
|
|
116
|
+
const match = questionId.match(DEPTH_VERIFICATION_MILESTONE_RE);
|
|
117
|
+
return match?.[1] ?? null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Extract the milestone ID from a milestone CONTEXT file path.
|
|
122
|
+
*/
|
|
123
|
+
function extractContextMilestoneId(inputPath: string): string | null {
|
|
124
|
+
const match = inputPath.match(CONTEXT_MILESTONE_RE);
|
|
125
|
+
return match?.[1] ?? null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Mark a gate as pending (called when ask_user_questions is invoked with a gate ID).
|
|
130
|
+
*/
|
|
131
|
+
export function setPendingGate(gateId: string): void {
|
|
132
|
+
pendingGateId = gateId;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Clear the pending gate (called when the user confirms).
|
|
137
|
+
*/
|
|
138
|
+
export function clearPendingGate(): void {
|
|
139
|
+
pendingGateId = null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Get the currently pending gate, if any.
|
|
144
|
+
*/
|
|
145
|
+
export function getPendingGate(): string | null {
|
|
146
|
+
return pendingGateId;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Check whether a tool call should be blocked because a discussion gate
|
|
151
|
+
* is pending (ask_user_questions was called but not confirmed).
|
|
152
|
+
*
|
|
153
|
+
* Returns { block: true, reason } if the tool should be blocked.
|
|
154
|
+
* Read-only tools and ask_user_questions itself are always allowed.
|
|
155
|
+
*/
|
|
156
|
+
export function shouldBlockPendingGate(
|
|
157
|
+
toolName: string,
|
|
158
|
+
_milestoneId: string | null,
|
|
159
|
+
_queuePhaseActive?: boolean,
|
|
160
|
+
): { block: boolean; reason?: string } {
|
|
161
|
+
if (!pendingGateId) return { block: false };
|
|
162
|
+
|
|
163
|
+
if (GATE_SAFE_TOOLS.has(toolName)) return { block: false };
|
|
164
|
+
|
|
165
|
+
// Bash read-only commands are also safe
|
|
166
|
+
if (toolName === "bash") return { block: false }; // bash is checked separately below
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
block: true,
|
|
170
|
+
reason: [
|
|
171
|
+
`HARD BLOCK: Discussion gate "${pendingGateId}" has not been confirmed by the user.`,
|
|
172
|
+
`You MUST re-call ask_user_questions with the gate question before making any other tool calls.`,
|
|
173
|
+
`If the previous ask_user_questions call failed, errored, was cancelled, or the user's response`,
|
|
174
|
+
`did not match a provided option, you MUST re-ask — never rationalize past the block.`,
|
|
175
|
+
`Do NOT proceed, do NOT use alternative approaches, do NOT skip the gate.`,
|
|
176
|
+
].join(" "),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Check whether a bash command should be blocked because a discussion gate is pending.
|
|
182
|
+
* Read-only bash commands are allowed; mutating commands are blocked.
|
|
183
|
+
*/
|
|
184
|
+
export function shouldBlockPendingGateBash(
|
|
185
|
+
command: string,
|
|
186
|
+
_milestoneId: string | null,
|
|
187
|
+
_queuePhaseActive?: boolean,
|
|
188
|
+
): { block: boolean; reason?: string } {
|
|
189
|
+
if (!pendingGateId) return { block: false };
|
|
190
|
+
|
|
191
|
+
// Allow read-only bash commands
|
|
192
|
+
if (BASH_READ_ONLY_RE.test(command)) return { block: false };
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
block: true,
|
|
196
|
+
reason: [
|
|
197
|
+
`HARD BLOCK: Discussion gate "${pendingGateId}" has not been confirmed by the user.`,
|
|
198
|
+
`You MUST re-call ask_user_questions with the gate question before running mutating commands.`,
|
|
199
|
+
`If the previous ask_user_questions call failed, errored, was cancelled, or the user's response`,
|
|
200
|
+
`did not match a provided option, you MUST re-ask — never rationalize past the block.`,
|
|
201
|
+
].join(" "),
|
|
202
|
+
};
|
|
55
203
|
}
|
|
56
204
|
|
|
57
205
|
/**
|
|
@@ -87,16 +235,24 @@ export function shouldBlockContextWrite(
|
|
|
87
235
|
toolName: string,
|
|
88
236
|
inputPath: string,
|
|
89
237
|
milestoneId: string | null,
|
|
90
|
-
|
|
91
|
-
queuePhaseActive?: boolean,
|
|
238
|
+
_queuePhaseActive?: boolean,
|
|
92
239
|
): { block: boolean; reason?: string } {
|
|
93
240
|
if (toolName !== "write") return { block: false };
|
|
94
|
-
|
|
95
|
-
const inDiscussion = milestoneId !== null;
|
|
96
|
-
const inQueue = queuePhaseActive ?? false;
|
|
97
|
-
if (!inDiscussion && !inQueue) return { block: false };
|
|
98
241
|
if (!MILESTONE_CONTEXT_RE.test(inputPath)) return { block: false };
|
|
99
|
-
|
|
242
|
+
|
|
243
|
+
const targetMilestoneId = extractContextMilestoneId(inputPath) ?? milestoneId;
|
|
244
|
+
if (!targetMilestoneId) {
|
|
245
|
+
return {
|
|
246
|
+
block: true,
|
|
247
|
+
reason: [
|
|
248
|
+
`HARD BLOCK: Cannot write milestone CONTEXT.md without knowing which milestone it belongs to.`,
|
|
249
|
+
`This is a mechanical gate — you MUST NOT proceed, retry, or rationalize past this block.`,
|
|
250
|
+
`Required action: call ask_user_questions with question id containing "depth_verification" and the milestone id.`,
|
|
251
|
+
].join(" "),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (isMilestoneDepthVerified(targetMilestoneId)) return { block: false };
|
|
100
256
|
|
|
101
257
|
return {
|
|
102
258
|
block: true,
|
|
@@ -110,6 +266,40 @@ export function shouldBlockContextWrite(
|
|
|
110
266
|
};
|
|
111
267
|
}
|
|
112
268
|
|
|
269
|
+
/**
|
|
270
|
+
* Check whether a gsd_summary_save CONTEXT artifact should be blocked.
|
|
271
|
+
* Slice-level CONTEXT artifacts are allowed; milestone-level CONTEXT writes
|
|
272
|
+
* require the milestone to be depth-verified first.
|
|
273
|
+
*/
|
|
274
|
+
export function shouldBlockContextArtifactSave(
|
|
275
|
+
artifactType: string,
|
|
276
|
+
milestoneId: string | null,
|
|
277
|
+
sliceId?: string | null,
|
|
278
|
+
): { block: boolean; reason?: string } {
|
|
279
|
+
if (artifactType !== "CONTEXT") return { block: false };
|
|
280
|
+
if (sliceId) return { block: false };
|
|
281
|
+
if (!milestoneId) {
|
|
282
|
+
return {
|
|
283
|
+
block: true,
|
|
284
|
+
reason: [
|
|
285
|
+
`HARD BLOCK: Cannot save milestone CONTEXT without a milestone_id.`,
|
|
286
|
+
`This is a mechanical gate — you MUST NOT proceed, retry, or rationalize past this block.`,
|
|
287
|
+
].join(" "),
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
if (isMilestoneDepthVerified(milestoneId)) return { block: false };
|
|
291
|
+
|
|
292
|
+
return {
|
|
293
|
+
block: true,
|
|
294
|
+
reason: [
|
|
295
|
+
`HARD BLOCK: Cannot save milestone CONTEXT without depth verification for ${milestoneId}.`,
|
|
296
|
+
`This is a mechanical gate — you MUST NOT proceed, retry, or rationalize past this block.`,
|
|
297
|
+
`Required action: call ask_user_questions with question id containing "depth_verification_${milestoneId}".`,
|
|
298
|
+
`The user MUST select the "(Recommended)" confirmation option to unlock this gate.`,
|
|
299
|
+
].join(" "),
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
113
303
|
/**
|
|
114
304
|
* Queue-mode execution guard (#2545).
|
|
115
305
|
*
|
|
@@ -155,7 +345,10 @@ export function shouldBlockQueueExecution(
|
|
|
155
345
|
};
|
|
156
346
|
}
|
|
157
347
|
|
|
158
|
-
// Unknown tools —
|
|
159
|
-
|
|
348
|
+
// Unknown tools — block by default in queue mode so custom tools cannot
|
|
349
|
+
// bypass execution restrictions.
|
|
350
|
+
return {
|
|
351
|
+
block: true,
|
|
352
|
+
reason: `Blocked: /gsd queue is a planning tool — it creates milestones, not executes work. Unknown tools are not permitted during queue mode.`,
|
|
353
|
+
};
|
|
160
354
|
}
|
|
161
|
-
|
|
@@ -84,8 +84,8 @@ export async function handleStatus(ctx: ExtensionCommandContext): Promise<void>
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
const { GSDDashboardOverlay } = await import("../../dashboard-overlay.js");
|
|
87
|
-
const result = await ctx.ui.custom<
|
|
88
|
-
(tui, theme, _kb, done) => new GSDDashboardOverlay(tui, theme, () => done()),
|
|
87
|
+
const result = await ctx.ui.custom<boolean>(
|
|
88
|
+
(tui, theme, _kb, done) => new GSDDashboardOverlay(tui, theme, () => done(true)),
|
|
89
89
|
{
|
|
90
90
|
overlay: true,
|
|
91
91
|
overlayOptions: {
|
|
@@ -113,8 +113,8 @@ export async function handleVisualize(ctx: ExtensionCommandContext): Promise<voi
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
const { GSDVisualizerOverlay } = await import("../../visualizer-overlay.js");
|
|
116
|
-
const result = await ctx.ui.custom<
|
|
117
|
-
(tui, theme, _kb, done) => new GSDVisualizerOverlay(tui, theme, () => done()),
|
|
116
|
+
const result = await ctx.ui.custom<boolean>(
|
|
117
|
+
(tui, theme, _kb, done) => new GSDVisualizerOverlay(tui, theme, () => done(true)),
|
|
118
118
|
{
|
|
119
119
|
overlay: true,
|
|
120
120
|
overlayOptions: {
|
|
@@ -221,8 +221,8 @@ export async function handleCoreCommand(trimmed: string, ctx: ExtensionCommandCo
|
|
|
221
221
|
}
|
|
222
222
|
if (trimmed === "show-config") {
|
|
223
223
|
const { GSDConfigOverlay, formatConfigText } = await import("../../config-overlay.js");
|
|
224
|
-
const result = await ctx.ui.custom<
|
|
225
|
-
(tui, theme, _kb, done) => new GSDConfigOverlay(tui, theme, () => done()),
|
|
224
|
+
const result = await ctx.ui.custom<boolean>(
|
|
225
|
+
(tui, theme, _kb, done) => new GSDConfigOverlay(tui, theme, () => done(true)),
|
|
226
226
|
{
|
|
227
227
|
overlay: true,
|
|
228
228
|
overlayOptions: {
|
|
@@ -277,10 +277,17 @@ async function configureModels(ctx: ExtensionCommandContext, prefs: Record<strin
|
|
|
277
277
|
group.sort((a, b) => a.id.localeCompare(b.id));
|
|
278
278
|
}
|
|
279
279
|
|
|
280
|
-
//
|
|
280
|
+
// Display names for providers in the preferences wizard UI.
|
|
281
|
+
const PROVIDER_DISPLAY_NAMES: Record<string, string> = { anthropic: "anthropic-api" };
|
|
282
|
+
const displayName = (p: string) => PROVIDER_DISPLAY_NAMES[p] ?? p;
|
|
283
|
+
|
|
284
|
+
// Build provider menu with model counts (display name → real name lookup)
|
|
285
|
+
const displayToReal = new Map<string, string>();
|
|
281
286
|
const providerOptions = providers.map(p => {
|
|
282
287
|
const count = byProvider.get(p)!.length;
|
|
283
|
-
|
|
288
|
+
const label = `${displayName(p)} (${count} models)`;
|
|
289
|
+
displayToReal.set(label, p);
|
|
290
|
+
return label;
|
|
284
291
|
});
|
|
285
292
|
providerOptions.push("(keep current)", "(clear)", "(type manually)");
|
|
286
293
|
|
|
@@ -310,14 +317,14 @@ async function configureModels(ctx: ExtensionCommandContext, prefs: Record<strin
|
|
|
310
317
|
}
|
|
311
318
|
|
|
312
319
|
// Step 2: pick model within provider
|
|
313
|
-
const providerName = providerChoice.replace(/ \(\d+ models?\)$/, "");
|
|
320
|
+
const providerName = displayToReal.get(providerChoice) ?? providerChoice.replace(/ \(\d+ models?\)$/, "");
|
|
314
321
|
const group = byProvider.get(providerName);
|
|
315
322
|
if (!group) continue;
|
|
316
323
|
|
|
317
324
|
const modelOptions = group.map(m => m.id);
|
|
318
325
|
modelOptions.push("(keep current)", "(clear)");
|
|
319
326
|
|
|
320
|
-
const modelChoice = await ctx.ui.select(`${phaseLabel} — ${providerName}:`, modelOptions);
|
|
327
|
+
const modelChoice = await ctx.ui.select(`${phaseLabel} — ${displayName(providerName)}:`, modelOptions);
|
|
321
328
|
if (modelChoice && typeof modelChoice === "string" && modelChoice !== "(keep current)") {
|
|
322
329
|
if (modelChoice === "(clear)") {
|
|
323
330
|
delete models[phase];
|
|
@@ -15,6 +15,7 @@ export interface DecisionQueryOpts {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export interface RequirementQueryOpts {
|
|
18
|
+
milestoneId?: string;
|
|
18
19
|
sliceId?: string;
|
|
19
20
|
status?: string;
|
|
20
21
|
}
|
|
@@ -67,7 +68,8 @@ export function queryDecisions(opts?: DecisionQueryOpts): Decision[] {
|
|
|
67
68
|
|
|
68
69
|
/**
|
|
69
70
|
* Query active (non-superseded) requirements with optional filters.
|
|
70
|
-
* -
|
|
71
|
+
* - milestoneId: combined with sliceId for precise filtering (e.g. %M005/S01%)
|
|
72
|
+
* - sliceId: filters where primary_owner LIKE '%pattern%' OR supporting_slices LIKE '%pattern%'
|
|
71
73
|
* - status: filters where status = :status (exact match)
|
|
72
74
|
*
|
|
73
75
|
* Returns [] if DB is not available. Never throws.
|
|
@@ -81,9 +83,19 @@ export function queryRequirements(opts?: RequirementQueryOpts): Requirement[] {
|
|
|
81
83
|
const clauses: string[] = ['superseded_by IS NULL'];
|
|
82
84
|
const params: Record<string, unknown> = {};
|
|
83
85
|
|
|
84
|
-
|
|
86
|
+
// Combined milestone+slice filtering for precise scoping
|
|
87
|
+
if (opts?.milestoneId && opts?.sliceId) {
|
|
88
|
+
// Use combined pattern like %M005/S01% to avoid cross-milestone contamination
|
|
89
|
+
clauses.push('(primary_owner LIKE :combined_pattern OR supporting_slices LIKE :combined_pattern)');
|
|
90
|
+
params[':combined_pattern'] = `%${opts.milestoneId}/${opts.sliceId}%`;
|
|
91
|
+
} else if (opts?.sliceId) {
|
|
92
|
+
// Slice-only filtering (legacy behavior)
|
|
85
93
|
clauses.push('(primary_owner LIKE :slice_pattern OR supporting_slices LIKE :slice_pattern)');
|
|
86
94
|
params[':slice_pattern'] = `%${opts.sliceId}%`;
|
|
95
|
+
} else if (opts?.milestoneId) {
|
|
96
|
+
// Milestone-only filtering
|
|
97
|
+
clauses.push('(primary_owner LIKE :milestone_pattern OR supporting_slices LIKE :milestone_pattern)');
|
|
98
|
+
params[':milestone_pattern'] = `%${opts.milestoneId}%`;
|
|
87
99
|
}
|
|
88
100
|
|
|
89
101
|
if (opts?.status) {
|
|
@@ -194,3 +206,156 @@ export function queryArtifact(path: string): string | null {
|
|
|
194
206
|
export function queryProject(): string | null {
|
|
195
207
|
return queryArtifact('PROJECT.md');
|
|
196
208
|
}
|
|
209
|
+
|
|
210
|
+
// ─── Knowledge Query ───────────────────────────────────────────────────────
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Filter KNOWLEDGE.md sections by keyword matching.
|
|
214
|
+
* Uses H2 sections, matches keywords case-insensitively against:
|
|
215
|
+
* 1. Section header text
|
|
216
|
+
* 2. First paragraph of section content (up to first blank line or next heading)
|
|
217
|
+
*
|
|
218
|
+
* Per D020, returns empty string (not null) when no matches found.
|
|
219
|
+
* This signals "no relevant knowledge" vs "file not found".
|
|
220
|
+
*
|
|
221
|
+
* @param content - Full KNOWLEDGE.md content
|
|
222
|
+
* @param keywords - Keywords to match (case-insensitive)
|
|
223
|
+
* @returns Concatenated matching sections with H2 headers, or empty string
|
|
224
|
+
*/
|
|
225
|
+
export async function queryKnowledge(content: string, keywords: string[]): Promise<string> {
|
|
226
|
+
if (!content || keywords.length === 0) return '';
|
|
227
|
+
|
|
228
|
+
// Lazy import to avoid circular dependency
|
|
229
|
+
const { extractAllSections } = await import('./files.js');
|
|
230
|
+
|
|
231
|
+
const sections = extractAllSections(content, 2);
|
|
232
|
+
if (sections.size === 0) return '';
|
|
233
|
+
|
|
234
|
+
// Normalize keywords for case-insensitive matching
|
|
235
|
+
const normalizedKeywords = keywords.map(k => k.toLowerCase());
|
|
236
|
+
|
|
237
|
+
const matchingSections: string[] = [];
|
|
238
|
+
|
|
239
|
+
for (const [header, body] of sections) {
|
|
240
|
+
// Extract first paragraph: everything up to first blank line or next heading
|
|
241
|
+
const firstParagraph = body.split(/\n\s*\n|\n#/)[0] || '';
|
|
242
|
+
|
|
243
|
+
// Check if any keyword matches header or first paragraph
|
|
244
|
+
const headerLower = header.toLowerCase();
|
|
245
|
+
const paragraphLower = firstParagraph.toLowerCase();
|
|
246
|
+
|
|
247
|
+
const matches = normalizedKeywords.some(kw =>
|
|
248
|
+
headerLower.includes(kw) || paragraphLower.includes(kw)
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
if (matches) {
|
|
252
|
+
matchingSections.push(`## ${header}\n\n${body}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return matchingSections.join('\n\n');
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// ─── Roadmap Excerpt Formatter ─────────────────────────────────────────────
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Format a minimal roadmap excerpt for prompt injection.
|
|
263
|
+
* Parses the slice table from roadmap content, extracts:
|
|
264
|
+
* 1. Header row + separator
|
|
265
|
+
* 2. Predecessor row (if sliceId depends on one via the Depends column)
|
|
266
|
+
* 3. Target slice row
|
|
267
|
+
* 4. Reference directive pointing to full roadmap path
|
|
268
|
+
*
|
|
269
|
+
* Per D021, this minimizes injected content while preserving dependency awareness.
|
|
270
|
+
* Returns empty string if sliceId is not found in the table.
|
|
271
|
+
* Never throws.
|
|
272
|
+
*
|
|
273
|
+
* @param roadmapContent - Full content of the M###-ROADMAP.md file
|
|
274
|
+
* @param sliceId - Target slice ID (e.g. 'S02')
|
|
275
|
+
* @param roadmapPath - Optional path for reference directive (defaults to generic)
|
|
276
|
+
*/
|
|
277
|
+
export function formatRoadmapExcerpt(
|
|
278
|
+
roadmapContent: string,
|
|
279
|
+
sliceId: string,
|
|
280
|
+
roadmapPath = 'ROADMAP.md',
|
|
281
|
+
): string {
|
|
282
|
+
if (!roadmapContent || !sliceId) return '';
|
|
283
|
+
|
|
284
|
+
const lines = roadmapContent.split('\n');
|
|
285
|
+
|
|
286
|
+
// Find the slice table header: | ID | Slice | ... (case insensitive)
|
|
287
|
+
let headerIndex = -1;
|
|
288
|
+
for (let i = 0; i < lines.length; i++) {
|
|
289
|
+
const line = lines[i];
|
|
290
|
+
if (line && /^\s*\|\s*ID\s*\|\s*Slice\s*\|/i.test(line)) {
|
|
291
|
+
headerIndex = i;
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (headerIndex === -1) return '';
|
|
297
|
+
|
|
298
|
+
// The separator should be the next line (|---|---|...)
|
|
299
|
+
const separatorIndex = headerIndex + 1;
|
|
300
|
+
if (separatorIndex >= lines.length) return '';
|
|
301
|
+
|
|
302
|
+
const headerLine = lines[headerIndex];
|
|
303
|
+
const separatorLine = lines[separatorIndex];
|
|
304
|
+
|
|
305
|
+
// Validate separator line looks like |---|---|... (may include : for alignment)
|
|
306
|
+
if (!separatorLine || !/^\s*\|[\s:\-|]+\|/.test(separatorLine)) return '';
|
|
307
|
+
|
|
308
|
+
// Parse table rows after separator
|
|
309
|
+
interface SliceRow {
|
|
310
|
+
line: string;
|
|
311
|
+
id: string;
|
|
312
|
+
depends: string;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const sliceRows: SliceRow[] = [];
|
|
316
|
+
for (let i = separatorIndex + 1; i < lines.length; i++) {
|
|
317
|
+
const line = lines[i];
|
|
318
|
+
if (!line || !line.trim().startsWith('|')) break; // End of table
|
|
319
|
+
|
|
320
|
+
// Parse row: | ID | Slice | Risk | Depends | Done | After this |
|
|
321
|
+
const cells = line.split('|').map(c => c.trim());
|
|
322
|
+
// cells[0] is empty (before first |), cells[1] is ID, etc.
|
|
323
|
+
if (cells.length < 5) continue;
|
|
324
|
+
|
|
325
|
+
const id = cells[1] || '';
|
|
326
|
+
const depends = cells[4] || ''; // Depends column (0-indexed: empty, ID, Slice, Risk, Depends, ...)
|
|
327
|
+
|
|
328
|
+
sliceRows.push({ line, id, depends });
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Find target slice row
|
|
332
|
+
const targetRow = sliceRows.find(r => r.id === sliceId);
|
|
333
|
+
if (!targetRow) return '';
|
|
334
|
+
|
|
335
|
+
// Find predecessor if target depends on one
|
|
336
|
+
// Depends column may contain: '—', 'S01', 'S01, S02', etc.
|
|
337
|
+
let predecessorRow: SliceRow | undefined;
|
|
338
|
+
const dependsRaw = targetRow.depends;
|
|
339
|
+
if (dependsRaw && dependsRaw !== '—' && dependsRaw !== '-') {
|
|
340
|
+
// Extract first dependency (e.g. 'S01' from 'S01, S02')
|
|
341
|
+
const depMatch = dependsRaw.match(/S\d+/);
|
|
342
|
+
if (depMatch) {
|
|
343
|
+
predecessorRow = sliceRows.find(r => r.id === depMatch[0]);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Build excerpt
|
|
348
|
+
const excerptLines: string[] = [headerLine!, separatorLine!];
|
|
349
|
+
|
|
350
|
+
if (predecessorRow) {
|
|
351
|
+
excerptLines.push(predecessorRow.line);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
excerptLines.push(targetRow.line);
|
|
355
|
+
|
|
356
|
+
// Add reference directive
|
|
357
|
+
excerptLines.push('');
|
|
358
|
+
excerptLines.push(`> See full roadmap: ${roadmapPath}`);
|
|
359
|
+
|
|
360
|
+
return excerptLines.join('\n');
|
|
361
|
+
}
|
|
@@ -179,7 +179,9 @@ export class CustomWorkflowEngine implements WorkflowEngine {
|
|
|
179
179
|
state: EngineState,
|
|
180
180
|
completedStep: CompletedStep,
|
|
181
181
|
): Promise<ReconcileResult> {
|
|
182
|
-
|
|
182
|
+
// Re-read the graph from disk so we do not overwrite concurrent
|
|
183
|
+
// workflow edits with a stale in-memory snapshot from deriveState().
|
|
184
|
+
const graph = readGraph(this.runDir);
|
|
183
185
|
|
|
184
186
|
// Extract stepId from "<workflowName>/<stepId>"
|
|
185
187
|
const { milestone, slice, task } = parseUnitId(completedStep.unitId);
|
|
@@ -242,6 +242,12 @@ const TEST_MARKERS = [
|
|
|
242
242
|
/** Directories skipped during bounded recursive project scans. */
|
|
243
243
|
const RECURSIVE_SCAN_IGNORED_DIRS = new Set([
|
|
244
244
|
".git",
|
|
245
|
+
".gsd",
|
|
246
|
+
".planning",
|
|
247
|
+
".plans",
|
|
248
|
+
".claude",
|
|
249
|
+
".cursor",
|
|
250
|
+
".vscode",
|
|
245
251
|
"node_modules",
|
|
246
252
|
".venv",
|
|
247
253
|
"venv",
|
|
@@ -132,6 +132,25 @@ function escapeRegex(s: string): string {
|
|
|
132
132
|
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Normalize a task-plan file reference that may include inline description text
|
|
137
|
+
* after the path, for example:
|
|
138
|
+
* "docs/file.md — explanation"
|
|
139
|
+
* "docs/file.md - explanation"
|
|
140
|
+
*/
|
|
141
|
+
export function normalizePlannedFileReference(value: string): string {
|
|
142
|
+
const trimmed = value.trim().replace(/`/g, "");
|
|
143
|
+
const match = /^(.*?)(?:\s+(?:—|-)\s+)(.+)$/.exec(trimmed);
|
|
144
|
+
if (!match) return trimmed;
|
|
145
|
+
|
|
146
|
+
const pathCandidate = match[1].trim();
|
|
147
|
+
if (pathCandidate.includes("/") || pathCandidate.includes("\\") || pathCandidate.includes(".")) {
|
|
148
|
+
return pathCandidate;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return trimmed;
|
|
152
|
+
}
|
|
153
|
+
|
|
135
154
|
/** Parse bullet list items from a text block. */
|
|
136
155
|
export function parseBullets(text: string): string[] {
|
|
137
156
|
return text.split('\n')
|
|
@@ -622,11 +641,11 @@ export function parseTaskPlanIO(content: string): { inputFiles: string[]; output
|
|
|
622
641
|
let match: RegExpExecArray | null;
|
|
623
642
|
backtickPathRegex.lastIndex = 0;
|
|
624
643
|
while ((match = backtickPathRegex.exec(trimmed)) !== null) {
|
|
625
|
-
const candidate = match[1];
|
|
644
|
+
const candidate = normalizePlannedFileReference(match[1]);
|
|
626
645
|
// Filter out things that look like code tokens rather than file paths
|
|
627
646
|
// (e.g. `true`, `false`, `npm run test`). A file path has at least one
|
|
628
647
|
// dot or slash.
|
|
629
|
-
if (candidate.includes("/") || candidate.includes(".")) {
|
|
648
|
+
if (candidate.includes("/") || candidate.includes("\\") || candidate.includes(".")) {
|
|
630
649
|
paths.push(candidate);
|
|
631
650
|
}
|
|
632
651
|
}
|
|
@@ -186,12 +186,13 @@ export function checkAutoStartAfterDiscuss(): boolean {
|
|
|
186
186
|
// Parse PROJECT.md for milestone sequence, warn if any are missing context.
|
|
187
187
|
// Don't block — milestones can be intentionally queued without context.
|
|
188
188
|
const projectFile = resolveGsdRootFile(basePath, "PROJECT");
|
|
189
|
+
let projectIds: string[] = [];
|
|
189
190
|
if (projectFile) {
|
|
190
191
|
try {
|
|
191
192
|
const projectContent = readFileSync(projectFile, "utf-8");
|
|
192
|
-
|
|
193
|
-
if (
|
|
194
|
-
const missing =
|
|
193
|
+
projectIds = parseMilestoneSequenceFromProject(projectContent);
|
|
194
|
+
if (projectIds.length > 1) {
|
|
195
|
+
const missing = projectIds.filter(id => {
|
|
195
196
|
const hasContext = !!resolveMilestoneFile(basePath, id, "CONTEXT");
|
|
196
197
|
const hasDraft = !!resolveMilestoneFile(basePath, id, "CONTEXT-DRAFT");
|
|
197
198
|
const hasDir = existsSync(join(gsdRoot(basePath), "milestones", id));
|
|
@@ -210,9 +211,17 @@ export function checkAutoStartAfterDiscuss(): boolean {
|
|
|
210
211
|
|
|
211
212
|
// Gate 4: Discussion manifest process verification (multi-milestone only)
|
|
212
213
|
// The LLM writes DISCUSSION-MANIFEST.json after each Phase 3 gate decision.
|
|
213
|
-
// If the
|
|
214
|
-
//
|
|
214
|
+
// If the project is multi-milestone, the manifest is required. When it is
|
|
215
|
+
// missing, fail closed instead of assuming the discussion finished.
|
|
215
216
|
const manifestPath = join(gsdRoot(basePath), "DISCUSSION-MANIFEST.json");
|
|
217
|
+
const requiresManifest = projectIds.length > 1 || findMilestoneIds(basePath).length > 1;
|
|
218
|
+
if (requiresManifest && !existsSync(manifestPath)) {
|
|
219
|
+
ctx.ui.notify(
|
|
220
|
+
"Multi-milestone discussion manifest is missing. Auto-start will remain paused until the manifest is written.",
|
|
221
|
+
"warning",
|
|
222
|
+
);
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
216
225
|
if (existsSync(manifestPath)) {
|
|
217
226
|
try {
|
|
218
227
|
const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
@@ -225,9 +234,7 @@ export function checkAutoStartAfterDiscuss(): boolean {
|
|
|
225
234
|
}
|
|
226
235
|
|
|
227
236
|
// Cross-check manifest milestones against PROJECT.md if available
|
|
228
|
-
if (
|
|
229
|
-
const projectContent = readFileSync(projectFile, "utf-8");
|
|
230
|
-
const projectIds = parseMilestoneSequenceFromProject(projectContent);
|
|
237
|
+
if (projectIds.length > 0) {
|
|
231
238
|
const manifestIds = Object.keys(manifest.milestones ?? {});
|
|
232
239
|
const untracked = projectIds.filter(id => !manifestIds.includes(id));
|
|
233
240
|
if (untracked.length > 0) {
|
|
@@ -3,10 +3,16 @@ import type { ExtensionAPI } from "@gsd/pi-coding-agent";
|
|
|
3
3
|
export {
|
|
4
4
|
isDepthConfirmationAnswer,
|
|
5
5
|
isDepthVerified,
|
|
6
|
+
isGateQuestionId,
|
|
6
7
|
isQueuePhaseActive,
|
|
7
8
|
setQueuePhaseActive,
|
|
8
9
|
shouldBlockContextWrite,
|
|
10
|
+
shouldBlockPendingGate,
|
|
11
|
+
shouldBlockPendingGateBash,
|
|
9
12
|
shouldBlockQueueExecution,
|
|
13
|
+
setPendingGate,
|
|
14
|
+
clearPendingGate,
|
|
15
|
+
getPendingGate,
|
|
10
16
|
} from "./bootstrap/write-gate.js";
|
|
11
17
|
|
|
12
18
|
export default async function registerExtension(pi: ExtensionAPI) {
|