gsd-pi 2.78.0 → 2.78.1-dev.84a383f51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -23
- package/dist/claude-cli-check.js +91 -32
- package/dist/cli-policy.d.ts +13 -0
- package/dist/cli-policy.js +17 -0
- package/dist/cli.js +95 -55
- package/dist/headless-query.d.ts +22 -0
- package/dist/headless-query.js +24 -4
- package/dist/headless.d.ts +10 -0
- package/dist/headless.js +16 -1
- package/dist/loader.js +7 -10
- package/dist/onboarding.d.ts +10 -0
- package/dist/onboarding.js +2 -2
- package/dist/provider-migrations.d.ts +2 -2
- package/dist/provider-migrations.js +5 -2
- package/dist/resource-loader.d.ts +5 -2
- package/dist/resource-loader.js +28 -5
- package/dist/resources/.managed-resources-content-hash +1 -0
- package/dist/resources/extensions/claude-code-cli/readiness.js +115 -31
- package/dist/resources/extensions/gsd/auto/loop.js +23 -0
- package/dist/resources/extensions/gsd/auto/phases.js +2 -2
- package/dist/resources/extensions/gsd/auto/run-unit.js +3 -1
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +43 -4
- package/dist/resources/extensions/gsd/auto-runtime-state.js +31 -0
- package/dist/resources/extensions/gsd/auto-start.js +1 -1
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +2 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +30 -0
- package/dist/resources/extensions/gsd/auto.js +14 -5
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +14 -2
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +7 -5
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +5 -4
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +94 -31
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +11 -6
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +34 -8
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +38 -2
- package/dist/resources/extensions/gsd/commands/catalog.js +69 -5
- package/dist/resources/extensions/gsd/commands/handlers/core.js +22 -1
- package/dist/resources/extensions/gsd/commands-mcp-status.js +3 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +10 -1
- package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +4 -0
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +39 -1
- package/dist/resources/extensions/gsd/error-classifier.js +1 -1
- package/dist/resources/extensions/gsd/forensics.js +2 -2
- package/dist/resources/extensions/gsd/git-service.js +12 -5
- package/dist/resources/extensions/gsd/gsd-db.js +11 -2
- package/dist/resources/extensions/gsd/guided-flow.js +23 -23
- package/dist/resources/extensions/gsd/memory-store.js +66 -31
- package/dist/resources/extensions/gsd/milestone-id-reservation.js +36 -0
- package/dist/resources/extensions/gsd/model-router.js +114 -9
- package/dist/resources/extensions/gsd/native-git-bridge.js +7 -1
- package/dist/resources/extensions/gsd/preferences-models.js +91 -15
- package/dist/resources/extensions/gsd/preferences-types.js +2 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +32 -0
- package/dist/resources/extensions/gsd/preferences.js +5 -3
- package/dist/resources/extensions/gsd/prompt-loader.js +23 -12
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +9 -3
- package/dist/resources/extensions/gsd/state.js +42 -0
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +1 -0
- package/dist/resources/extensions/gsd/tools/memory-tools.js +18 -1
- package/dist/resources/extensions/gsd/visualizer-overlay.js +1 -1
- package/dist/resources/extensions/gsd/watch/header-renderer.js +3 -1
- package/dist/resources/extensions/gsd/worktree-command.js +26 -46
- package/dist/resources/extensions/gsd/worktree-session-state.js +33 -0
- package/dist/resources/extensions/mcp-client/index.js +6 -3
- package/dist/resources/extensions/slash-commands/create-extension.js +36 -22
- package/dist/resources/skills/create-gsd-extension/SKILL.md +9 -5
- package/dist/resources/skills/create-gsd-extension/references/custom-commands.md +1 -1
- package/dist/resources/skills/create-gsd-extension/references/custom-rendering.md +5 -5
- package/dist/resources/skills/create-gsd-extension/references/custom-tools.md +4 -4
- package/dist/resources/skills/create-gsd-extension/references/custom-ui.md +6 -6
- package/dist/resources/skills/create-gsd-extension/references/events-reference.md +3 -3
- package/dist/resources/skills/create-gsd-extension/references/packaging-distribution.md +1 -1
- package/dist/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +3 -3
- package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +32 -12
- package/dist/rtk-shared.d.ts +3 -0
- package/dist/rtk-shared.js +17 -0
- package/dist/rtk.d.ts +2 -5
- package/dist/rtk.js +3 -20
- package/dist/runtime-checks.d.ts +27 -0
- package/dist/runtime-checks.js +38 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
- 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 +44 -4
- 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 +4 -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 +13 -13
- 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-manifest.json +5 -5
- 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/server/webpack-runtime.js +1 -1
- package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +1 -0
- package/dist/web/standalone/.next/static/chunks/2824.08296bc2f9654698.js +1 -0
- package/dist/web/standalone/.next/static/chunks/3026.3af53b279375f082.js +1 -0
- package/dist/web/standalone/.next/static/chunks/315.6f68ae79b67d25cf.js +1 -0
- package/dist/web/standalone/.next/static/chunks/3497.4bfc60a3b3dea717.js +1 -0
- package/dist/web/standalone/.next/static/chunks/5516.4a07c872b5c3a663.js +1 -0
- package/dist/web/standalone/.next/static/chunks/8336.31b019697882acfb.js +10 -0
- package/dist/web/standalone/.next/static/chunks/8845.c9702695e8c5a9c5.js +2 -0
- package/dist/web/standalone/.next/static/chunks/9058.01ef3a463bda88f1.js +20 -0
- package/dist/web/standalone/.next/static/chunks/9441.1081da1125d1764f.js +1 -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-9bf2e0c50fb2ca05.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-f9f0dc45e4f3ac10.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/package.json +2 -1
- package/dist/web/standalone/server.js +1 -1
- package/dist/worktree-status-banner.d.ts +1 -0
- package/dist/worktree-status-banner.js +132 -0
- package/package.json +1 -1
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/dist/alias-telemetry.d.ts +8 -0
- package/packages/mcp-server/dist/alias-telemetry.d.ts.map +1 -0
- package/packages/mcp-server/dist/alias-telemetry.js +30 -0
- package/packages/mcp-server/dist/alias-telemetry.js.map +1 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +74 -46
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/alias-telemetry.test.ts +78 -0
- package/packages/mcp-server/src/alias-telemetry.ts +30 -0
- package/packages/mcp-server/src/workflow-tools.test.ts +26 -0
- package/packages/mcp-server/src/workflow-tools.ts +93 -58
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.js +231 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +48 -19
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +13 -0
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.js +24 -3
- package/packages/pi-ai/dist/utils/repair-tool-json.js.map +1 -1
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js +26 -0
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/src/providers/anthropic-shared.cache-breakpoint.test.ts +289 -0
- package/packages/pi-ai/src/providers/anthropic-shared.ts +52 -20
- package/packages/pi-ai/src/types.ts +13 -0
- package/packages/pi-ai/src/utils/repair-tool-json.ts +24 -3
- package/packages/pi-ai/src/utils/tests/repair-tool-json.test.ts +32 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +6 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/messages.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/messages.js +4 -0
- package/packages/pi-coding-agent/dist/core/messages.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +19 -2
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +10 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +18 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +13 -0
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +20 -16
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/token-telemetry.d.ts +37 -0
- package/packages/pi-coding-agent/dist/core/token-telemetry.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/token-telemetry.js +49 -0
- package/packages/pi-coding-agent/dist/core/token-telemetry.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +133 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +14 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.js +78 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/tests/token-telemetry.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/token-telemetry.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/token-telemetry.test.js +181 -0
- package/packages/pi-coding-agent/dist/tests/token-telemetry.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +7 -0
- package/packages/pi-coding-agent/src/core/messages.ts +4 -0
- package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +32 -2
- package/packages/pi-coding-agent/src/core/model-registry.ts +21 -0
- package/packages/pi-coding-agent/src/core/system-prompt.ts +33 -15
- package/packages/pi-coding-agent/src/core/token-telemetry.ts +77 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +212 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +17 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +1 -1
- package/packages/pi-coding-agent/src/tests/system-prompt-cache-stability.test.ts +102 -0
- package/packages/pi-coding-agent/src/tests/token-telemetry.test.ts +200 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js +17 -3
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.d.ts +2 -0
- package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.js +161 -0
- package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.js.map +1 -0
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/__tests__/autocomplete.test.ts +20 -3
- package/packages/pi-tui/src/components/__tests__/leak-fixes-runtime.test.ts +219 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/claude-code-cli/readiness.ts +116 -29
- package/src/resources/extensions/gsd/auto/loop.ts +24 -2
- package/src/resources/extensions/gsd/auto/phases.ts +3 -3
- package/src/resources/extensions/gsd/auto/run-unit.ts +3 -1
- package/src/resources/extensions/gsd/auto/session.ts +3 -0
- package/src/resources/extensions/gsd/auto/types.ts +1 -0
- package/src/resources/extensions/gsd/auto-recovery.ts +46 -8
- package/src/resources/extensions/gsd/auto-runtime-state.ts +51 -0
- package/src/resources/extensions/gsd/auto-start.ts +1 -1
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +2 -4
- package/src/resources/extensions/gsd/auto-worktree.ts +38 -0
- package/src/resources/extensions/gsd/auto.ts +14 -4
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +15 -13
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +8 -7
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +10 -9
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +102 -31
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +12 -6
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +39 -8
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +39 -11
- package/src/resources/extensions/gsd/commands/catalog.ts +75 -5
- package/src/resources/extensions/gsd/commands/handlers/core.ts +22 -1
- package/src/resources/extensions/gsd/commands-mcp-status.ts +3 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +15 -1
- package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +4 -0
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +39 -1
- package/src/resources/extensions/gsd/doctor-types.ts +3 -1
- package/src/resources/extensions/gsd/error-classifier.ts +1 -1
- package/src/resources/extensions/gsd/forensics.ts +2 -2
- package/src/resources/extensions/gsd/git-service.ts +13 -5
- package/src/resources/extensions/gsd/gsd-db.ts +12 -2
- package/src/resources/extensions/gsd/guided-flow.ts +25 -25
- package/src/resources/extensions/gsd/memory-store.ts +81 -28
- package/src/resources/extensions/gsd/milestone-id-reservation.ts +47 -0
- package/src/resources/extensions/gsd/model-router.ts +172 -9
- package/src/resources/extensions/gsd/native-git-bridge.ts +7 -1
- package/src/resources/extensions/gsd/preferences-models.ts +101 -15
- package/src/resources/extensions/gsd/preferences-types.ts +6 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +35 -0
- package/src/resources/extensions/gsd/preferences.ts +16 -2
- package/src/resources/extensions/gsd/prompt-loader.ts +26 -12
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +9 -3
- package/src/resources/extensions/gsd/state.ts +42 -0
- package/src/resources/extensions/gsd/templates/PREFERENCES.md +1 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +178 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +9 -5
- package/src/resources/extensions/gsd/tests/auto-supervisor.test.mjs +21 -4
- package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/budget-prediction.test.ts +138 -211
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +142 -59
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +7 -4
- package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +89 -32
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +41 -23
- package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +3 -43
- package/src/resources/extensions/gsd/tests/debug-logger.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/deferred-milestone-dir-4996.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/discuss-empty-db-fallback.test.ts +22 -87
- package/src/resources/extensions/gsd/tests/discuss-queued-milestones.test.ts +7 -118
- package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +18 -60
- package/src/resources/extensions/gsd/tests/doctor-orphan-milestone-4996.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +14 -76
- package/src/resources/extensions/gsd/tests/ensure-preconditions-guard-4996.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/false-degraded-mode-warning.test.ts +22 -83
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +1 -63
- package/src/resources/extensions/gsd/tests/find-missing-summaries-closed-runtime.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/forensics-stuck-loops.test.ts +26 -1
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell-runtime.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/gsd-no-project-error-runtime.test.ts +81 -0
- package/src/resources/extensions/gsd/tests/headless-answers.test.ts +14 -4
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +22 -12
- package/src/resources/extensions/gsd/tests/help-menu-coverage.test.ts +57 -0
- package/src/resources/extensions/gsd/tests/import-done-milestones-runtime.test.ts +145 -0
- package/src/resources/extensions/gsd/tests/init-prefs-routing.test.ts +64 -1
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/integration/token-savings.test.ts +0 -23
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +128 -0
- package/src/resources/extensions/gsd/tests/memory-tools.test.ts +33 -1
- package/src/resources/extensions/gsd/tests/merge-self-branch-guard.test.ts +124 -0
- package/src/resources/extensions/gsd/tests/milestone-id-gap-reuse-4996.test.ts +152 -0
- package/src/resources/extensions/gsd/tests/model-router.test.ts +169 -8
- package/src/resources/extensions/gsd/tests/native-git-infra-errors.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +32 -43
- package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +4 -10
- package/src/resources/extensions/gsd/tests/preferences.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/register-hooks-compaction-checkpoint.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +168 -19
- package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +23 -1
- package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +101 -0
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +51 -4
- package/src/resources/extensions/gsd/tests/turn-epoch.test.ts +7 -16
- package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +15 -1
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +15 -0
- package/src/resources/extensions/gsd/tools/memory-tools.ts +17 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +8 -8
- package/src/resources/extensions/gsd/visualizer-overlay.ts +1 -1
- package/src/resources/extensions/gsd/watch/header-renderer.ts +3 -1
- package/src/resources/extensions/gsd/workflow-logger.ts +1 -0
- package/src/resources/extensions/gsd/worktree-command.ts +31 -44
- package/src/resources/extensions/gsd/worktree-session-state.ts +35 -0
- package/src/resources/extensions/mcp-client/index.ts +6 -3
- package/src/resources/extensions/mcp-client/tests/global-config.test.ts +91 -0
- package/src/resources/extensions/slash-commands/create-extension.ts +38 -24
- package/src/resources/skills/create-gsd-extension/SKILL.md +9 -5
- package/src/resources/skills/create-gsd-extension/references/custom-commands.md +1 -1
- package/src/resources/skills/create-gsd-extension/references/custom-rendering.md +5 -5
- package/src/resources/skills/create-gsd-extension/references/custom-tools.md +4 -4
- package/src/resources/skills/create-gsd-extension/references/custom-ui.md +6 -6
- package/src/resources/skills/create-gsd-extension/references/events-reference.md +3 -3
- package/src/resources/skills/create-gsd-extension/references/packaging-distribution.md +1 -1
- package/src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +3 -3
- package/src/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +2 -2
- package/src/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +3 -3
- package/src/resources/skills/create-gsd-extension/templates/templates.test.ts +58 -0
- package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +32 -12
- package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +0 -601
- package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +0 -651
- package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +0 -91
- package/dist/resources/extensions/gsd/tests/auto-supervisor.test.mjs +0 -53
- package/dist/resources/extensions/gsd/tests/dist-redirect.mjs +0 -112
- package/dist/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +0 -23
- package/dist/resources/extensions/gsd/tests/resolve-ts.mjs +0 -5
- package/dist/resources/skills/github-workflows/references/gh/tests/__init__.py +0 -0
- package/dist/resources/skills/github-workflows/references/gh/tests/test_github_project_setup.py +0 -608
- package/dist/web/standalone/.next/static/chunks/2826.e9f5195e91f9cad2.js +0 -11
- package/dist/web/standalone/.next/static/chunks/3621.fc7480022c972438.js +0 -20
- package/dist/web/standalone/.next/static/chunks/app/page-151349214571e2b6.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
- package/dist/web/standalone/.next/static/chunks/webpack-2e68521d7c82f7c2.js +0 -1
- package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +0 -22
- package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +0 -47
- package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +0 -75
- /package/dist/web/standalone/.next/static/{C1zT2kEfoLhDdbWPWKrXd → UF5VF4F1tB0miEtJS7LyX}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{C1zT2kEfoLhDdbWPWKrXd → UF5VF4F1tB0miEtJS7LyX}/_ssgManifest.js +0 -0
|
@@ -1,22 +1,14 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { isToolCallEventType } from "@gsd/pi-coding-agent";
|
|
3
3
|
import { updateSnapshot } from "../ecosystem/gsd-extension-api.js";
|
|
4
|
-
import { getEcosystemReadyPromise } from "../ecosystem/loader.js";
|
|
5
4
|
import { buildMilestoneFileName, resolveMilestonePath, resolveSliceFile, resolveSlicePath } from "../paths.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { clearDiscussionFlowState, isDepthConfirmationAnswer, isQueuePhaseActive, markDepthVerified, resetWriteGateState, shouldBlockContextWrite, shouldBlockQueueExecution, isGateQuestionId, setPendingGate, clearPendingGate, getPendingGate, shouldBlockPendingGate, shouldBlockPendingGateBash, extractDepthVerificationMilestoneId } from "./write-gate.js";
|
|
5
|
+
import { clearDiscussionFlowState, isDepthConfirmationAnswer, isQueuePhaseActive, markDepthVerified, resetWriteGateState, shouldBlockContextWrite, shouldBlockPlanningUnit, shouldBlockQueueExecution, isGateQuestionId, setPendingGate, clearPendingGate, getPendingGate, shouldBlockPendingGate, shouldBlockPendingGateBash, extractDepthVerificationMilestoneId } from "./write-gate.js";
|
|
6
|
+
import { resolveManifest } from "../unit-context-manifest.js";
|
|
9
7
|
import { isBlockedStateFile, isBashWriteToStateFile, BLOCKED_WRITE_ERROR } from "../write-intercept.js";
|
|
10
|
-
import { cleanupQuickBranch } from "../quick.js";
|
|
11
|
-
import { getDiscussionMilestoneId } from "../guided-flow.js";
|
|
12
|
-
import { loadToolApiKeys } from "../commands-config.js";
|
|
13
8
|
import { loadFile, saveFile, formatContinue } from "../files.js";
|
|
14
|
-
import {
|
|
15
|
-
import { getAutoDashboardData, isAutoActive, isAutoPaused, markToolEnd, markToolStart, recordToolInvocationError } from "../auto.js";
|
|
16
|
-
import { isParallelActive, shutdownParallel } from "../parallel-orchestrator.js";
|
|
9
|
+
import { getAutoRuntimeSnapshot, isAutoActive, isAutoPaused, markToolEnd, markToolStart, recordToolInvocationError } from "../auto-runtime-state.js";
|
|
17
10
|
import { checkToolCallLoop, resetToolCallLoopGuard } from "./tool-call-loop-guard.js";
|
|
18
11
|
import { saveActivityLog } from "../activity-log.js";
|
|
19
|
-
import { resetAskUserQuestionsCache } from "../../ask-user-questions.js";
|
|
20
12
|
import { recordToolCall as safetyRecordToolCall, recordToolResult as safetyRecordToolResult, saveEvidenceToDisk } from "../safety/evidence-collector.js";
|
|
21
13
|
import { parseUnitId } from "../unit-id.js";
|
|
22
14
|
import { classifyCommand } from "../safety/destructive-guard.js";
|
|
@@ -24,26 +16,52 @@ import { logWarning as safetyLogWarning } from "../workflow-logger.js";
|
|
|
24
16
|
import { installNotifyInterceptor } from "./notify-interceptor.js";
|
|
25
17
|
import { initNotificationStore } from "../notification-store.js";
|
|
26
18
|
import { initNotificationWidget } from "../notification-widget.js";
|
|
27
|
-
import { initHealthWidget } from "../health-widget.js";
|
|
28
19
|
// Skip the welcome screen on the very first session_start — cli.ts already
|
|
29
20
|
// printed it before the TUI launched. Only re-print on /clear (subsequent sessions).
|
|
30
21
|
let isFirstSession = true;
|
|
22
|
+
async function deriveGsdState(basePath) {
|
|
23
|
+
const { deriveState } = await import("../state.js");
|
|
24
|
+
return deriveState(basePath);
|
|
25
|
+
}
|
|
26
|
+
async function getDiscussionMilestoneIdFor(basePath) {
|
|
27
|
+
const { getDiscussionMilestoneId } = await import("../guided-flow.js");
|
|
28
|
+
return getDiscussionMilestoneId(basePath);
|
|
29
|
+
}
|
|
30
|
+
async function loadToolApiKeysForSession() {
|
|
31
|
+
const { loadToolApiKeys } = await import("../commands-config.js");
|
|
32
|
+
loadToolApiKeys();
|
|
33
|
+
}
|
|
34
|
+
async function resetAskUserQuestionsTurnCache() {
|
|
35
|
+
const { resetAskUserQuestionsCache } = await import("../../ask-user-questions.js");
|
|
36
|
+
resetAskUserQuestionsCache();
|
|
37
|
+
}
|
|
31
38
|
async function syncServiceTierStatus(ctx) {
|
|
32
39
|
const { getEffectiveServiceTier, formatServiceTierFooterStatus } = await import("../service-tier.js");
|
|
33
40
|
ctx.ui.setStatus("gsd-fast", formatServiceTierFooterStatus(getEffectiveServiceTier(), ctx.model?.id));
|
|
34
41
|
}
|
|
42
|
+
async function applyDisabledModelProviderPolicy(ctx) {
|
|
43
|
+
try {
|
|
44
|
+
const { resolveDisabledModelProvidersFromPreferences } = await import("../preferences.js");
|
|
45
|
+
ctx.modelRegistry.setDisabledModelProviders(resolveDisabledModelProvidersFromPreferences());
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Non-fatal: keep default provider visibility if preferences cannot be loaded.
|
|
49
|
+
}
|
|
50
|
+
}
|
|
35
51
|
export function registerHooks(pi, ecosystemHandlers) {
|
|
36
52
|
pi.on("session_start", async (_event, ctx) => {
|
|
37
53
|
initNotificationStore(process.cwd());
|
|
38
54
|
installNotifyInterceptor(ctx);
|
|
39
55
|
initNotificationWidget(ctx);
|
|
40
56
|
if (!isAutoActive()) {
|
|
57
|
+
const { initHealthWidget } = await import("../health-widget.js");
|
|
41
58
|
initHealthWidget(ctx);
|
|
42
59
|
}
|
|
43
60
|
resetWriteGateState();
|
|
44
61
|
resetToolCallLoopGuard();
|
|
45
|
-
|
|
62
|
+
await resetAskUserQuestionsTurnCache();
|
|
46
63
|
await syncServiceTierStatus(ctx);
|
|
64
|
+
await applyDisabledModelProviderPolicy(ctx);
|
|
47
65
|
// Skip MCP auto-prep when running inside an auto-worktree (see session_switch below).
|
|
48
66
|
const { isInAutoWorktree } = await import("../auto-worktree.js");
|
|
49
67
|
if (!isInAutoWorktree(process.cwd())) {
|
|
@@ -79,7 +97,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
79
97
|
}
|
|
80
98
|
catch { /* non-fatal */ }
|
|
81
99
|
}
|
|
82
|
-
|
|
100
|
+
await loadToolApiKeysForSession();
|
|
83
101
|
if (isAutoActive()) {
|
|
84
102
|
ctx.ui.setWidget("gsd-health", undefined);
|
|
85
103
|
}
|
|
@@ -89,9 +107,10 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
89
107
|
installNotifyInterceptor(ctx);
|
|
90
108
|
resetWriteGateState();
|
|
91
109
|
resetToolCallLoopGuard();
|
|
92
|
-
|
|
110
|
+
await resetAskUserQuestionsTurnCache();
|
|
93
111
|
clearDiscussionFlowState();
|
|
94
112
|
await syncServiceTierStatus(ctx);
|
|
113
|
+
await applyDisabledModelProviderPolicy(ctx);
|
|
95
114
|
// Skip MCP auto-prep when running inside an auto-worktree. The worktree
|
|
96
115
|
// already has .mcp.json from createAutoWorktree, and re-running the writer
|
|
97
116
|
// post-chdir rewrites the file mid-run (non-idempotent due to cwd-relative
|
|
@@ -101,20 +120,26 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
101
120
|
const { prepareWorkflowMcpForProject } = await import("../workflow-mcp-auto-prep.js");
|
|
102
121
|
prepareWorkflowMcpForProject(ctx, process.cwd());
|
|
103
122
|
}
|
|
104
|
-
|
|
105
|
-
if (isAutoActive()) {
|
|
123
|
+
await loadToolApiKeysForSession();
|
|
124
|
+
if (!isAutoActive()) {
|
|
125
|
+
const { initHealthWidget } = await import("../health-widget.js");
|
|
126
|
+
initHealthWidget(ctx);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
106
129
|
ctx.ui.setWidget("gsd-health", undefined);
|
|
107
130
|
}
|
|
108
131
|
});
|
|
109
132
|
pi.on("before_agent_start", async (event, ctx) => {
|
|
110
133
|
// Wait for ecosystem loader to finish (no-op after first turn).
|
|
134
|
+
const { getEcosystemReadyPromise } = await import("../ecosystem/loader.js");
|
|
111
135
|
await getEcosystemReadyPromise();
|
|
112
136
|
// GSD's own context injection (existing behavior — unchanged).
|
|
137
|
+
const { buildBeforeAgentStartResult } = await import("./system-context.js");
|
|
113
138
|
const gsdResult = await buildBeforeAgentStartResult(event, ctx);
|
|
114
139
|
// Refresh the snapshot used by ecosystem getPhase()/getActiveUnit().
|
|
115
140
|
// deriveState has its own ~100ms cache so this is cheap on repeat calls.
|
|
116
141
|
try {
|
|
117
|
-
const state = await
|
|
142
|
+
const state = await deriveGsdState(process.cwd());
|
|
118
143
|
updateSnapshot(state);
|
|
119
144
|
}
|
|
120
145
|
catch {
|
|
@@ -148,7 +173,8 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
148
173
|
});
|
|
149
174
|
pi.on("agent_end", async (event, ctx) => {
|
|
150
175
|
resetToolCallLoopGuard();
|
|
151
|
-
|
|
176
|
+
await resetAskUserQuestionsTurnCache();
|
|
177
|
+
const { handleAgentEnd } = await import("./agent-end-recovery.js");
|
|
152
178
|
await handleAgentEnd(pi, event, ctx);
|
|
153
179
|
});
|
|
154
180
|
// Squash-merge quick-task branch back to the original branch after the
|
|
@@ -156,6 +182,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
156
182
|
// quick-return state is pending, so this is safe to call on every turn.
|
|
157
183
|
pi.on("turn_end", async () => {
|
|
158
184
|
try {
|
|
185
|
+
const { cleanupQuickBranch } = await import("../quick.js");
|
|
159
186
|
cleanupQuickBranch();
|
|
160
187
|
}
|
|
161
188
|
catch {
|
|
@@ -172,8 +199,8 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
172
199
|
const basePath = process.cwd();
|
|
173
200
|
const { ensureDbOpen } = await import("./dynamic-tools.js");
|
|
174
201
|
await ensureDbOpen();
|
|
175
|
-
const state = await
|
|
176
|
-
if (!state.activeMilestone || !state.activeSlice
|
|
202
|
+
const state = await deriveGsdState(basePath);
|
|
203
|
+
if (!state.activeMilestone || !state.activeSlice)
|
|
177
204
|
return;
|
|
178
205
|
// Write checkpoint for ALL phases, not just "executing" — discuss, research,
|
|
179
206
|
// and planning also carry in-memory state (user answers, gate verification)
|
|
@@ -189,21 +216,30 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
189
216
|
if (await loadFile(legacyContinue))
|
|
190
217
|
return;
|
|
191
218
|
const continuePath = join(sliceDir, `${state.activeSlice.id}-CONTINUE.md`);
|
|
219
|
+
const taskId = state.activeTask?.id ?? "none";
|
|
220
|
+
const taskTitle = state.activeTask?.title ?? "";
|
|
221
|
+
const phaseLabel = state.phase.replace(/-/g, " ");
|
|
192
222
|
await saveFile(continuePath, formatContinue({
|
|
193
223
|
frontmatter: {
|
|
194
224
|
milestone: state.activeMilestone.id,
|
|
195
225
|
slice: state.activeSlice.id,
|
|
196
|
-
task:
|
|
226
|
+
task: taskId,
|
|
197
227
|
step: 0,
|
|
198
228
|
totalSteps: 0,
|
|
199
229
|
status: "compacted",
|
|
200
230
|
savedAt: new Date().toISOString(),
|
|
201
231
|
},
|
|
202
|
-
completedWork:
|
|
203
|
-
|
|
232
|
+
completedWork: state.activeTask
|
|
233
|
+
? `Task ${taskId} (${taskTitle}) was in progress when compaction occurred.`
|
|
234
|
+
: `Slice ${state.activeSlice.id} was in ${phaseLabel} phase when compaction occurred.`,
|
|
235
|
+
remainingWork: state.activeTask
|
|
236
|
+
? "Check the task plan for remaining steps."
|
|
237
|
+
: "Continue this slice from the latest planning/research/discussion artifacts.",
|
|
204
238
|
decisions: "Check task summary files for prior decisions.",
|
|
205
239
|
context: "Session was auto-compacted by Pi. Resume with /gsd.",
|
|
206
|
-
nextAction:
|
|
240
|
+
nextAction: state.activeTask
|
|
241
|
+
? `Resume task ${taskId}: ${taskTitle}.`
|
|
242
|
+
: `Resume ${phaseLabel} work for slice ${state.activeSlice.id}.`,
|
|
207
243
|
}));
|
|
208
244
|
});
|
|
209
245
|
// Context-mode snapshot: write .gsd/last-snapshot.md before compaction so
|
|
@@ -225,7 +261,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
225
261
|
const basePath = process.cwd();
|
|
226
262
|
let activeContext = null;
|
|
227
263
|
try {
|
|
228
|
-
const state = await
|
|
264
|
+
const state = await deriveGsdState(basePath);
|
|
229
265
|
if (state.activeMilestone && state.activeSlice && state.activeTask) {
|
|
230
266
|
activeContext =
|
|
231
267
|
`Active: ${state.activeMilestone.id} / ${state.activeSlice.id} / ${state.activeTask.id}` +
|
|
@@ -242,6 +278,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
242
278
|
}
|
|
243
279
|
});
|
|
244
280
|
pi.on("session_shutdown", async (_event, ctx) => {
|
|
281
|
+
const { isParallelActive, shutdownParallel } = await import("../parallel-orchestrator.js");
|
|
245
282
|
if (isParallelActive()) {
|
|
246
283
|
try {
|
|
247
284
|
await shutdownParallel(process.cwd());
|
|
@@ -252,7 +289,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
252
289
|
}
|
|
253
290
|
if (!isAutoActive() && !isAutoPaused())
|
|
254
291
|
return;
|
|
255
|
-
const dash =
|
|
292
|
+
const dash = getAutoRuntimeSnapshot();
|
|
256
293
|
if (dash.currentUnit) {
|
|
257
294
|
saveActivityLog(ctx, dash.basePath, dash.currentUnit.type, dash.currentUnit.id);
|
|
258
295
|
}
|
|
@@ -278,7 +315,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
278
315
|
// If ask_user_questions was called with a gate ID but hasn't been confirmed,
|
|
279
316
|
// block all non-read-only tool calls to prevent the model from skipping gates.
|
|
280
317
|
if (getPendingGate()) {
|
|
281
|
-
const milestoneId =
|
|
318
|
+
const milestoneId = await getDiscussionMilestoneIdFor(discussionBasePath);
|
|
282
319
|
if (isToolCallEventType("bash", event)) {
|
|
283
320
|
const bashGuard = shouldBlockPendingGateBash(event.input.command, milestoneId, isQueuePhaseActive());
|
|
284
321
|
if (bashGuard.block)
|
|
@@ -309,6 +346,32 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
309
346
|
if (queueGuard.block)
|
|
310
347
|
return queueGuard;
|
|
311
348
|
}
|
|
349
|
+
// ── Planning-unit tools-policy enforcement (#4934): runtime half ─────
|
|
350
|
+
// The active auto-mode unit's manifest declares a ToolsPolicy. For
|
|
351
|
+
// planning/docs/read-only modes, deny writes outside .gsd/ (or the
|
|
352
|
+
// manifest's allowedPathGlobs), bash that isn't read-only, and
|
|
353
|
+
// subagent dispatch. Closes the b23 bug class where a discuss-milestone
|
|
354
|
+
// turn used the host Edit tool to modify user source files.
|
|
355
|
+
const dash = getAutoRuntimeSnapshot();
|
|
356
|
+
const activeUnitType = dash.currentUnit?.type;
|
|
357
|
+
if (activeUnitType) {
|
|
358
|
+
const manifest = resolveManifest(activeUnitType);
|
|
359
|
+
if (manifest) {
|
|
360
|
+
let planningInput = "";
|
|
361
|
+
if (isToolCallEventType("write", event)) {
|
|
362
|
+
planningInput = event.input.path;
|
|
363
|
+
}
|
|
364
|
+
else if (isToolCallEventType("edit", event)) {
|
|
365
|
+
planningInput = event.input.path;
|
|
366
|
+
}
|
|
367
|
+
else if (isToolCallEventType("bash", event)) {
|
|
368
|
+
planningInput = event.input.command;
|
|
369
|
+
}
|
|
370
|
+
const planningGuard = shouldBlockPlanningUnit(event.toolName, planningInput, dash.basePath || discussionBasePath, activeUnitType, manifest.tools);
|
|
371
|
+
if (planningGuard.block)
|
|
372
|
+
return planningGuard;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
312
375
|
// ── Single-writer engine: block direct writes to STATE.md ──────────
|
|
313
376
|
// Covers write, edit, and bash tools to prevent bypass vectors.
|
|
314
377
|
if (isToolCallEventType("write", event)) {
|
|
@@ -328,7 +391,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
328
391
|
}
|
|
329
392
|
if (!isToolCallEventType("write", event))
|
|
330
393
|
return;
|
|
331
|
-
const result = shouldBlockContextWrite(event.toolName, event.input.path,
|
|
394
|
+
const result = shouldBlockContextWrite(event.toolName, event.input.path, await getDiscussionMilestoneIdFor(discussionBasePath), isQueuePhaseActive());
|
|
332
395
|
if (result.block)
|
|
333
396
|
return result;
|
|
334
397
|
});
|
|
@@ -368,7 +431,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
368
431
|
}
|
|
369
432
|
if (event.toolName !== "ask_user_questions")
|
|
370
433
|
return;
|
|
371
|
-
const milestoneId =
|
|
434
|
+
const milestoneId = await getDiscussionMilestoneIdFor(process.cwd());
|
|
372
435
|
const queueActive = isQueuePhaseActive();
|
|
373
436
|
const details = event.details;
|
|
374
437
|
// ── Discussion gate enforcement: handle gate question responses ──
|
|
@@ -464,7 +527,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
464
527
|
safetyRecordToolResult(event.toolCallId, event.toolName, event.result, event.isError);
|
|
465
528
|
// Persist evidence to disk after each tool result so it survives a session
|
|
466
529
|
// restart mid-unit (Bug #4385 — non-persisted evidence false positives).
|
|
467
|
-
const dash =
|
|
530
|
+
const dash = getAutoRuntimeSnapshot();
|
|
468
531
|
if (dash.basePath && dash.currentUnit?.type === "execute-task") {
|
|
469
532
|
const { milestone: pMid, slice: pSid, task: pTid } = parseUnitId(dash.currentUnit.id);
|
|
470
533
|
if (pMid && pSid && pTid) {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { Key } from "@gsd/pi-tui";
|
|
4
|
-
import { GSDDashboardOverlay } from "../dashboard-overlay.js";
|
|
5
|
-
import { GSDNotificationOverlay } from "../notification-overlay.js";
|
|
6
|
-
import { ParallelMonitorOverlay } from "../parallel-monitor-overlay.js";
|
|
7
4
|
import { GSD_SHORTCUTS } from "../shortcut-defs.js";
|
|
8
|
-
import { projectRoot } from "../commands/context.js";
|
|
9
5
|
import { shortcutDesc } from "../../shared/mod.js";
|
|
6
|
+
async function getProjectRoot() {
|
|
7
|
+
const { projectRoot } = await import("../commands/context.js");
|
|
8
|
+
return projectRoot();
|
|
9
|
+
}
|
|
10
10
|
export function registerShortcuts(pi) {
|
|
11
11
|
const overlayOptions = {
|
|
12
12
|
width: "90%",
|
|
@@ -15,7 +15,10 @@ export function registerShortcuts(pi) {
|
|
|
15
15
|
anchor: "center",
|
|
16
16
|
};
|
|
17
17
|
const openDashboardOverlay = async (ctx) => {
|
|
18
|
-
const basePath =
|
|
18
|
+
const [{ GSDDashboardOverlay }, basePath] = await Promise.all([
|
|
19
|
+
import("../dashboard-overlay.js"),
|
|
20
|
+
getProjectRoot(),
|
|
21
|
+
]);
|
|
19
22
|
if (!existsSync(join(basePath, ".gsd"))) {
|
|
20
23
|
ctx.ui.notify("No .gsd/ directory found. Run /gsd to start.", "info");
|
|
21
24
|
return;
|
|
@@ -26,6 +29,7 @@ export function registerShortcuts(pi) {
|
|
|
26
29
|
});
|
|
27
30
|
};
|
|
28
31
|
const openNotificationsOverlay = async (ctx) => {
|
|
32
|
+
const { GSDNotificationOverlay } = await import("../notification-overlay.js");
|
|
29
33
|
await ctx.ui.custom((tui, theme, _kb, done) => new GSDNotificationOverlay(tui, theme, () => done(true)), {
|
|
30
34
|
overlay: true,
|
|
31
35
|
overlayOptions: {
|
|
@@ -38,12 +42,13 @@ export function registerShortcuts(pi) {
|
|
|
38
42
|
});
|
|
39
43
|
};
|
|
40
44
|
const openParallelOverlay = async (ctx) => {
|
|
41
|
-
const basePath =
|
|
45
|
+
const basePath = await getProjectRoot();
|
|
42
46
|
const parallelDir = join(basePath, ".gsd", "parallel");
|
|
43
47
|
if (!existsSync(parallelDir)) {
|
|
44
48
|
ctx.ui.notify("No parallel workers found. Run /gsd parallel start first.", "info");
|
|
45
49
|
return;
|
|
46
50
|
}
|
|
51
|
+
const { ParallelMonitorOverlay } = await import("../parallel-monitor-overlay.js");
|
|
47
52
|
await ctx.ui.custom((tui, theme, _kb, done) => new ParallelMonitorOverlay(tui, theme, () => done(true), basePath), {
|
|
48
53
|
overlay: true,
|
|
49
54
|
overlayOptions,
|
|
@@ -12,7 +12,7 @@ import { resolveGsdRootFile, resolveSliceFile, resolveSlicePath, resolveTaskFile
|
|
|
12
12
|
import { ensureCodebaseMapFresh, readCodebaseMap } from "../codebase-generator.js";
|
|
13
13
|
import { hasSkillSnapshot, detectNewSkills, formatSkillsXml } from "../skill-discovery.js";
|
|
14
14
|
import { getActiveAutoWorktreeContext } from "../auto-worktree.js";
|
|
15
|
-
import { getActiveWorktreeName, getWorktreeOriginalCwd } from "../worktree-
|
|
15
|
+
import { getActiveWorktreeName, getWorktreeOriginalCwd } from "../worktree-session-state.js";
|
|
16
16
|
import { deriveState } from "../state.js";
|
|
17
17
|
import { formatOverridesSection, formatShortcut, loadActiveOverrides, loadFile, parseContinue, parseSummary } from "../files.js";
|
|
18
18
|
import { toPosixPath } from "../../shared/mod.js";
|
|
@@ -177,24 +177,50 @@ export async function buildBeforeAgentStartResult(event, ctx) {
|
|
|
177
177
|
const subagentModelBlock = subagentModelConfig
|
|
178
178
|
? `\n\n## Subagent Model\n\nWhen spawning subagents via the \`subagent\` tool, always pass \`model: "${subagentModelConfig.primary}"\` in the tool call parameters. Never omit this — always specify it explicitly.`
|
|
179
179
|
: "";
|
|
180
|
-
|
|
180
|
+
// memoryBlock is FTS-queried against the user prompt and changes per call.
|
|
181
|
+
// Removing it from `fullSystem` keeps the system-prompt cache breakpoint
|
|
182
|
+
// stable across calls — the only scoped goal of this fix. The pi-ai
|
|
183
|
+
// Anthropic adapter additionally cache-marks the last user turn, so the
|
|
184
|
+
// memoryBlock injected via the context message may itself be cached up to
|
|
185
|
+
// that boundary; that's orthogonal and unchanged from prior behavior. The
|
|
186
|
+
// load-bearing win here is preserving the system+tools cache hit. (#5019)
|
|
187
|
+
const fullSystem = `${event.systemPrompt}\n\n[SYSTEM CONTEXT — GSD]\n\n${systemContent}${preferenceBlock}${knowledgeBlock}${codebaseBlock}${newSkillsBlock}${worktreeBlock}${subagentModelBlock}`;
|
|
181
188
|
stopContextTimer({
|
|
182
189
|
systemPromptSize: fullSystem.length,
|
|
183
190
|
injectionSize: injection?.length ?? forensicsInjection?.length ?? 0,
|
|
184
191
|
hasPreferences: preferenceBlock.length > 0,
|
|
185
192
|
hasNewSkills: newSkillsBlock.length > 0,
|
|
186
193
|
});
|
|
187
|
-
|
|
188
|
-
const contextMessage = injection
|
|
189
|
-
? { customType: "gsd-guided-context", content: injection, display: false }
|
|
190
|
-
: forensicsInjection
|
|
191
|
-
? { customType: "gsd-forensics", content: forensicsInjection, display: false }
|
|
192
|
-
: null;
|
|
194
|
+
const contextMessage = buildContextMessage({ memoryBlock, injection, forensicsInjection });
|
|
193
195
|
return {
|
|
194
196
|
systemPrompt: fullSystem,
|
|
195
197
|
...(contextMessage ? { message: contextMessage } : {}),
|
|
196
198
|
};
|
|
197
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* Route the per-call dynamic blocks (memory, guided-execute, forensics) into a
|
|
202
|
+
* single user-message context payload so they ride the volatile suffix instead
|
|
203
|
+
* of the cached system prefix. Priority when both memory and an injection are
|
|
204
|
+
* present: guided > forensics > memory-only. (#5019)
|
|
205
|
+
*
|
|
206
|
+
* Exported for direct unit testing — the surrounding bootstrap has too many
|
|
207
|
+
* filesystem and DB dependencies to exercise this routing logic in-place.
|
|
208
|
+
*/
|
|
209
|
+
export function buildContextMessage(opts) {
|
|
210
|
+
const memoryContent = opts.memoryBlock.trim();
|
|
211
|
+
if (opts.injection) {
|
|
212
|
+
const content = memoryContent ? `${memoryContent}\n\n${opts.injection}` : opts.injection;
|
|
213
|
+
return { customType: "gsd-guided-context", content, display: false };
|
|
214
|
+
}
|
|
215
|
+
if (opts.forensicsInjection) {
|
|
216
|
+
const content = memoryContent ? `${memoryContent}\n\n${opts.forensicsInjection}` : opts.forensicsInjection;
|
|
217
|
+
return { customType: "gsd-forensics", content, display: false };
|
|
218
|
+
}
|
|
219
|
+
if (memoryContent) {
|
|
220
|
+
return { customType: "gsd-memory", content: memoryContent, display: false };
|
|
221
|
+
}
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
198
224
|
/**
|
|
199
225
|
* ADR-013 step 4 — auto-injection parity for the memories table.
|
|
200
226
|
*
|
|
@@ -441,8 +441,31 @@ export function shouldBlockQueueExecutionInSnapshot(snapshot, toolName, input, q
|
|
|
441
441
|
};
|
|
442
442
|
}
|
|
443
443
|
// ─── Planning-unit tools-policy enforcement (#4934) ───────────────────────
|
|
444
|
+
//
|
|
445
|
+
// Runtime half of the declarative ToolsPolicy on UnitContextManifest. The
|
|
446
|
+
// manifest assigns each unit type a tools mode; this predicate is what
|
|
447
|
+
// actually rejects a tool call that violates it.
|
|
448
|
+
//
|
|
449
|
+
// Forensics: a discuss-milestone LLM turn used the host Edit tool to modify
|
|
450
|
+
// index.html in test app b23 (~/Github/test-apps/b23). With this predicate
|
|
451
|
+
// wired into the tool_call hook, the same call returns block=true with a
|
|
452
|
+
// HARD BLOCK reason that the model cannot rationalize past.
|
|
453
|
+
//
|
|
454
|
+
// Activation: the hook supplies the policy resolved from the active unit's
|
|
455
|
+
// manifest. When no unit is active (interactive sessions, unknown unit
|
|
456
|
+
// types), the hook passes null and this predicate is a no-op — falling
|
|
457
|
+
// through to the existing pendingGate / queue-execution / context-write
|
|
458
|
+
// guards.
|
|
444
459
|
const PLANNING_WRITE_TOOLS = new Set(["write", "edit", "multi_edit", "notebook_edit"]);
|
|
445
460
|
const PLANNING_SUBAGENT_TOOLS = new Set(["subagent", "task"]);
|
|
461
|
+
/**
|
|
462
|
+
* Read-only / planning-safe tools that any non-"all" mode allows. Mirrors
|
|
463
|
+
* QUEUE_SAFE_TOOLS / GATE_SAFE_TOOLS but is the inclusive default for
|
|
464
|
+
* planning units (which need their full discussion + research surface).
|
|
465
|
+
*
|
|
466
|
+
* gsd_* MCP tools are passed through unconditionally — they have their own
|
|
467
|
+
* domain validation (e.g. depth-verification gate, single-writer DB).
|
|
468
|
+
*/
|
|
446
469
|
const PLANNING_SAFE_TOOLS = new Set([
|
|
447
470
|
"read", "grep", "find", "ls", "glob",
|
|
448
471
|
"ask_user_questions",
|
|
@@ -458,6 +481,7 @@ function matchesAllowedGlob(absPath, basePath, globs) {
|
|
|
458
481
|
const rel = relative(basePath, absPath);
|
|
459
482
|
if (rel.startsWith("..") || isAbsolute(rel))
|
|
460
483
|
return false;
|
|
484
|
+
// Normalize Windows separators for minimatch.
|
|
461
485
|
const posix = rel.split(sep).join("/");
|
|
462
486
|
return globs.some(g => minimatch(posix, g, { dot: false, nocase: false }));
|
|
463
487
|
}
|
|
@@ -480,7 +504,12 @@ function blockReason(unitType, mode, what) {
|
|
|
480
504
|
* - "docs" → like "planning" but also allows writes to paths
|
|
481
505
|
* matching `allowedPathGlobs` relative to basePath.
|
|
482
506
|
*
|
|
483
|
-
* `
|
|
507
|
+
* `pathOrCommand` is the file path for write/edit-shaped tools and the
|
|
508
|
+
* shell command for bash. Other tools ignore this argument.
|
|
509
|
+
*
|
|
510
|
+
* `policy` of null means "no manifest resolved" — pass-through. Callers
|
|
511
|
+
* that have no active unit (interactive sessions) pass null and this
|
|
512
|
+
* predicate is a no-op.
|
|
484
513
|
*/
|
|
485
514
|
export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitType, policy) {
|
|
486
515
|
if (!policy)
|
|
@@ -488,6 +517,7 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
|
|
|
488
517
|
if (policy.mode === "all")
|
|
489
518
|
return { block: false };
|
|
490
519
|
const tool = toolName;
|
|
520
|
+
// Read-only mode: only Read-class tools are permitted.
|
|
491
521
|
if (policy.mode === "read-only") {
|
|
492
522
|
if (PLANNING_SAFE_TOOLS.has(tool))
|
|
493
523
|
return { block: false };
|
|
@@ -496,9 +526,10 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
|
|
|
496
526
|
if (PLANNING_WRITE_TOOLS.has(tool) || tool === "bash" || PLANNING_SUBAGENT_TOOLS.has(tool)) {
|
|
497
527
|
return { block: true, reason: blockReason(unitType, policy.mode, `${tool} is not permitted (read-only)`) };
|
|
498
528
|
}
|
|
529
|
+
// Unknown tool in read-only mode — block by default.
|
|
499
530
|
return { block: true, reason: blockReason(unitType, policy.mode, `tool "${tool}" is not on the read-only allowlist`) };
|
|
500
531
|
}
|
|
501
|
-
// planning / docs modes
|
|
532
|
+
// planning / docs modes share the same surface for safe tools, bash, and subagent.
|
|
502
533
|
if (PLANNING_SAFE_TOOLS.has(tool))
|
|
503
534
|
return { block: false };
|
|
504
535
|
if (tool.startsWith("gsd_"))
|
|
@@ -519,8 +550,10 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
|
|
|
519
550
|
return { block: true, reason: blockReason(unitType, policy.mode, `${tool} called with empty path`) };
|
|
520
551
|
}
|
|
521
552
|
const absPath = isAbsolute(pathOrCommand) ? pathOrCommand : resolve(basePath, pathOrCommand);
|
|
553
|
+
// Always allow .gsd/ writes — that's where planning artifacts live.
|
|
522
554
|
if (isPathUnderGsd(absPath, basePath))
|
|
523
555
|
return { block: false };
|
|
556
|
+
// docs mode additionally allows the manifest's allowedPathGlobs.
|
|
524
557
|
if (policy.mode === "docs" && matchesAllowedGlob(absPath, basePath, policy.allowedPathGlobs)) {
|
|
525
558
|
return { block: false };
|
|
526
559
|
}
|
|
@@ -529,5 +562,8 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
|
|
|
529
562
|
reason: blockReason(unitType, policy.mode, `cannot ${tool} "${pathOrCommand}" — writes are restricted to .gsd/${policy.mode === "docs" ? " and " + policy.allowedPathGlobs.join(", ") : ""}`),
|
|
530
563
|
};
|
|
531
564
|
}
|
|
565
|
+
// Unknown tool name — pass through. Other layers (queue, pending-gate,
|
|
566
|
+
// CONTEXT.md write) catch known mutating shapes; defaulting to allow here
|
|
567
|
+
// avoids breaking gsd_* MCP tools or future safe additions.
|
|
532
568
|
return { block: false };
|
|
533
569
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
4
|
import { loadRegistry } from "../workflow-templates.js";
|
|
5
|
-
import { resolveProjectRoot } from "../worktree.js";
|
|
6
5
|
const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
7
|
-
export const GSD_COMMAND_DESCRIPTION = "GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|queue|quick|discuss|capture|triage|dispatch|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|model|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|debug|logs|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|parallel|cmux|park|unpark|init|setup|onboarding|inspect|extensions|update|fast|mcp|rethink|codebase|notifications|ship|do|session-report|backlog|pr-branch|add-tests|scan|language";
|
|
6
|
+
export const GSD_COMMAND_DESCRIPTION = "GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|queue|quick|discuss|capture|triage|dispatch|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|model|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|debug|logs|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|parallel|cmux|park|unpark|init|setup|onboarding|inspect|extensions|update|fast|mcp|rethink|workflow|codebase|notifications|ship|do|session-report|backlog|pr-branch|add-tests|scan|language";
|
|
8
7
|
export const TOP_LEVEL_SUBCOMMANDS = [
|
|
9
8
|
{ cmd: "help", desc: "Categorized command reference with descriptions" },
|
|
10
9
|
{ cmd: "next", desc: "Explicit step mode (same as /gsd)" },
|
|
@@ -330,6 +329,71 @@ function getExtensionCompletions(prefix, action) {
|
|
|
330
329
|
return [];
|
|
331
330
|
}
|
|
332
331
|
}
|
|
332
|
+
function normalizePathForCompare(path) {
|
|
333
|
+
return path.replaceAll("\\", "/").replace(/\/+$/, "");
|
|
334
|
+
}
|
|
335
|
+
function findWorktreeSegment(normalizedPath) {
|
|
336
|
+
const directMarker = "/.gsd/worktrees/";
|
|
337
|
+
const directIdx = normalizedPath.indexOf(directMarker);
|
|
338
|
+
if (directIdx !== -1) {
|
|
339
|
+
return { gsdIdx: directIdx, afterWorktrees: directIdx + directMarker.length };
|
|
340
|
+
}
|
|
341
|
+
const symlinkMatch = normalizedPath.match(/\/\.gsd\/projects\/[a-f0-9]+\/worktrees\//);
|
|
342
|
+
if (symlinkMatch?.index !== undefined) {
|
|
343
|
+
return { gsdIdx: symlinkMatch.index, afterWorktrees: symlinkMatch.index + symlinkMatch[0].length };
|
|
344
|
+
}
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
function resolveProjectRootFromGitFile(worktreePath) {
|
|
348
|
+
try {
|
|
349
|
+
let dir = worktreePath;
|
|
350
|
+
for (let i = 0; i < 30; i++) {
|
|
351
|
+
const gitPath = join(dir, ".git");
|
|
352
|
+
if (existsSync(gitPath)) {
|
|
353
|
+
const content = readFileSync(gitPath, "utf8").trim();
|
|
354
|
+
if (content.startsWith("gitdir: ")) {
|
|
355
|
+
const gitDir = resolve(dir, content.slice(8));
|
|
356
|
+
const dotGitDir = resolve(gitDir, "..", "..");
|
|
357
|
+
if (dotGitDir.endsWith(".git") || dotGitDir.endsWith(".git/") || dotGitDir.endsWith(".git\\")) {
|
|
358
|
+
return resolve(dotGitDir, "..");
|
|
359
|
+
}
|
|
360
|
+
const commonDirPath = join(gitDir, "commondir");
|
|
361
|
+
if (existsSync(commonDirPath)) {
|
|
362
|
+
const commonDir = readFileSync(commonDirPath, "utf8").trim();
|
|
363
|
+
return resolve(resolve(gitDir, commonDir), "..");
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
break;
|
|
367
|
+
}
|
|
368
|
+
const parent = resolve(dir, "..");
|
|
369
|
+
if (parent === dir)
|
|
370
|
+
break;
|
|
371
|
+
dir = parent;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
catch {
|
|
375
|
+
// Completion must stay best-effort.
|
|
376
|
+
}
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
379
|
+
function resolveProjectRootForCompletion(basePath) {
|
|
380
|
+
if (process.env.GSD_PROJECT_ROOT)
|
|
381
|
+
return process.env.GSD_PROJECT_ROOT;
|
|
382
|
+
const normalizedPath = normalizePathForCompare(basePath);
|
|
383
|
+
const segment = findWorktreeSegment(normalizedPath);
|
|
384
|
+
if (!segment)
|
|
385
|
+
return basePath;
|
|
386
|
+
const separator = basePath.includes("\\") ? "\\" : "/";
|
|
387
|
+
const gsdMarker = `${separator}.gsd${separator}`;
|
|
388
|
+
const gsdIdx = basePath.indexOf(gsdMarker);
|
|
389
|
+
const candidate = gsdIdx !== -1 ? basePath.slice(0, gsdIdx) : basePath.slice(0, segment.gsdIdx);
|
|
390
|
+
const normalizedGsdHome = normalizePathForCompare(gsdHome);
|
|
391
|
+
const candidateGsdPath = normalizePathForCompare(join(candidate, ".gsd"));
|
|
392
|
+
if (candidateGsdPath === normalizedGsdHome || candidateGsdPath.startsWith(`${normalizedGsdHome}/`)) {
|
|
393
|
+
return resolveProjectRootFromGitFile(basePath) ?? basePath;
|
|
394
|
+
}
|
|
395
|
+
return candidate;
|
|
396
|
+
}
|
|
333
397
|
export function getGsdArgumentCompletions(prefix) {
|
|
334
398
|
const hasTrailingSpace = prefix.endsWith(" ");
|
|
335
399
|
const parts = prefix.trim().split(/\s+/);
|
|
@@ -384,7 +448,7 @@ export function getGsdArgumentCompletions(prefix) {
|
|
|
384
448
|
// Workflow definition-name completion for `workflow run <name>` and `workflow validate <name>`
|
|
385
449
|
if (command === "workflow" && (subcommand === "run" || subcommand === "validate") && parts.length <= 3) {
|
|
386
450
|
try {
|
|
387
|
-
const defsDir = join(
|
|
451
|
+
const defsDir = join(resolveProjectRootForCompletion(process.cwd()), ".gsd", "workflow-defs");
|
|
388
452
|
if (existsSync(defsDir)) {
|
|
389
453
|
return readdirSync(defsDir)
|
|
390
454
|
.filter((f) => f.endsWith(".yaml") && f.startsWith(third))
|
|
@@ -426,7 +490,7 @@ export function getGsdArgumentCompletions(prefix) {
|
|
|
426
490
|
catch { /* ignore */ }
|
|
427
491
|
};
|
|
428
492
|
try {
|
|
429
|
-
const base =
|
|
493
|
+
const base = resolveProjectRootForCompletion(process.cwd());
|
|
430
494
|
scanDir(join(base, ".gsd", "workflows"), "project");
|
|
431
495
|
scanDir(join(base, ".gsd", "workflow-defs"), "project-legacy");
|
|
432
496
|
scanDir(join(gsdHome, "workflows"), "global");
|