gsd-pi 2.78.0 → 2.78.1-dev.8a893322c
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 +60 -23
- package/dist/bundled-resource-path.d.ts +7 -0
- package/dist/bundled-resource-path.js +34 -2
- package/dist/claude-cli-check.js +104 -33
- 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 +43 -8
- package/dist/headless.d.ts +10 -0
- package/dist/headless.js +16 -1
- package/dist/loader.js +9 -13
- 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 +30 -13
- package/dist/resources/.managed-resources-content-hash +1 -0
- package/dist/resources/extensions/claude-code-cli/readiness.js +128 -32
- package/dist/resources/extensions/google-search/index.js +2 -6
- package/dist/resources/extensions/gsd/auto/loop.js +23 -0
- package/dist/resources/extensions/gsd/auto/phases.js +5 -13
- package/dist/resources/extensions/gsd/auto/run-unit.js +3 -1
- package/dist/resources/extensions/gsd/auto/session.js +5 -6
- package/dist/resources/extensions/gsd/auto-dashboard.js +3 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +18 -6
- package/dist/resources/extensions/gsd/auto-prompts.js +63 -2
- 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 +60 -13
- 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 +112 -31
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +11 -6
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +22 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +45 -8
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +121 -3
- package/dist/resources/extensions/gsd/commands/catalog.js +76 -5
- package/dist/resources/extensions/gsd/commands/handlers/core.js +23 -1
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +8 -0
- package/dist/resources/extensions/gsd/commands-config.js +3 -2
- package/dist/resources/extensions/gsd/commands-extensions.js +46 -3
- package/dist/resources/extensions/gsd/commands-handlers.js +3 -2
- 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/commands-worktree.js +309 -0
- package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +10 -0
- package/dist/resources/extensions/gsd/doctor-providers.js +2 -1
- 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 +10 -8
- 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 +25 -24
- package/dist/resources/extensions/gsd/home-dir.js +16 -0
- package/dist/resources/extensions/gsd/key-manager.js +2 -1
- package/dist/resources/extensions/gsd/memory-store.js +66 -31
- package/dist/resources/extensions/gsd/migrate/command.js +3 -2
- 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/prompts/complete-milestone.md +10 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +10 -0
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +10 -0
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +10 -0
- 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/unit-context-manifest.js +29 -4
- 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-manager.js +20 -1
- package/dist/resources/extensions/gsd/worktree-resolver.js +4 -13
- package/dist/resources/extensions/gsd/worktree-root.js +124 -0
- package/dist/resources/extensions/gsd/worktree-session-state.js +33 -0
- package/dist/resources/extensions/gsd/worktree.js +4 -115
- package/dist/resources/extensions/mcp-client/index.js +6 -9
- package/dist/resources/extensions/ollama/index.js +15 -2
- package/dist/resources/extensions/ollama/model-capabilities.js +31 -0
- package/dist/resources/extensions/ollama/ollama-client.js +40 -4
- package/dist/resources/extensions/slash-commands/create-extension.js +36 -22
- package/dist/resources/extensions/subagent/index.js +324 -178
- 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 +15 -15
- 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 +15 -15
- 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/welcome-screen.js +27 -1
- package/dist/worktree-cli.d.ts +1 -0
- package/dist/worktree-cli.js +9 -3
- package/dist/worktree-status-banner.d.ts +1 -0
- package/dist/worktree-status-banner.js +132 -0
- package/package.json +1 -3
- 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 +78 -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/native/tsconfig.tsbuildinfo +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 +130 -30
- package/src/resources/extensions/google-search/index.ts +2 -9
- package/src/resources/extensions/gsd/auto/loop.ts +24 -2
- package/src/resources/extensions/gsd/auto/phases.ts +6 -14
- package/src/resources/extensions/gsd/auto/run-unit.ts +3 -1
- package/src/resources/extensions/gsd/auto/session.ts +5 -6
- package/src/resources/extensions/gsd/auto/types.ts +1 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +3 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +18 -6
- package/src/resources/extensions/gsd/auto-prompts.ts +60 -2
- 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 +82 -12
- 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 +121 -31
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +12 -6
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +20 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +50 -8
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +141 -11
- package/src/resources/extensions/gsd/commands/catalog.ts +82 -5
- package/src/resources/extensions/gsd/commands/handlers/core.ts +23 -1
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +10 -0
- package/src/resources/extensions/gsd/commands-config.ts +3 -2
- package/src/resources/extensions/gsd/commands-extensions.ts +43 -3
- package/src/resources/extensions/gsd/commands-handlers.ts +3 -2
- 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/commands-worktree.ts +383 -0
- package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +10 -0
- package/src/resources/extensions/gsd/doctor-providers.ts +2 -1
- 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 +12 -7
- 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 +27 -26
- package/src/resources/extensions/gsd/home-dir.ts +19 -0
- package/src/resources/extensions/gsd/journal.ts +4 -1
- package/src/resources/extensions/gsd/key-manager.ts +2 -1
- package/src/resources/extensions/gsd/memory-store.ts +81 -28
- package/src/resources/extensions/gsd/migrate/command.ts +3 -2
- 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/prompts/complete-milestone.md +10 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +10 -0
- package/src/resources/extensions/gsd/prompts/plan-slice.md +10 -0
- package/src/resources/extensions/gsd/prompts/refine-slice.md +10 -0
- 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 +24 -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/bundled-skill-triggers.test.ts +50 -27
- package/src/resources/extensions/gsd/tests/commands-extensions-version-compare.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/commands-worktree-clean.test.ts +48 -0
- 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/google-search-stub.test.ts +25 -65
- 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/home-dir.test.ts +52 -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 +72 -1
- 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/milestone-report-path.test.ts +18 -1
- 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/safety-harness-false-positives.test.ts +34 -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/steer-worktree-path.test.ts +17 -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/unit-context-manifest.test.ts +38 -3
- 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/worktree-symlink-removal.test.ts +34 -33
- package/src/resources/extensions/gsd/tests/worktree.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +131 -1
- package/src/resources/extensions/gsd/tools/memory-tools.ts +17 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +44 -12
- 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-manager.ts +40 -1
- package/src/resources/extensions/gsd/worktree-resolver.ts +4 -14
- package/src/resources/extensions/gsd/worktree-root.ts +144 -0
- package/src/resources/extensions/gsd/worktree-session-state.ts +35 -0
- package/src/resources/extensions/gsd/worktree.ts +8 -119
- package/src/resources/extensions/mcp-client/index.ts +6 -10
- package/src/resources/extensions/mcp-client/tests/global-config.test.ts +91 -0
- package/src/resources/extensions/ollama/index.ts +16 -2
- package/src/resources/extensions/ollama/model-capabilities.ts +34 -0
- package/src/resources/extensions/ollama/ollama-client.ts +41 -4
- package/src/resources/extensions/ollama/tests/model-capabilities.test.ts +96 -0
- package/src/resources/extensions/ollama/tests/ollama-client-timeout-env.test.ts +147 -0
- package/src/resources/extensions/slash-commands/create-extension.ts +38 -24
- package/src/resources/extensions/subagent/index.ts +165 -7
- 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 → QK8fABiGPmonfTgboN0Y9}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{C1zT2kEfoLhDdbWPWKrXd → QK8fABiGPmonfTgboN0Y9}/_ssgManifest.js +0 -0
|
@@ -18,28 +18,13 @@ import { createWorktree, listWorktrees, removeWorktree, mergeWorktreeToMain, dif
|
|
|
18
18
|
import { inferCommitType } from "./git-service.js";
|
|
19
19
|
import { existsSync, realpathSync, readdirSync, rmSync, unlinkSync } from "node:fs";
|
|
20
20
|
import { nativeMergeAbort } from "./native-git-bridge.js";
|
|
21
|
-
import { join
|
|
21
|
+
import { join } from "node:path";
|
|
22
|
+
import { clearWorktreeOriginalCwd, ensureWorktreeOriginalCwdFromPath, getActiveWorktreeName, getWorktreeOriginalCwd, setWorktreeOriginalCwd, } from "./worktree-session-state.js";
|
|
23
|
+
export { getActiveWorktreeName, getWorktreeOriginalCwd } from "./worktree-session-state.js";
|
|
22
24
|
/**
|
|
23
25
|
* Tracks the original project root so we can switch back.
|
|
24
26
|
* Set when we first chdir into a worktree, cleared on return.
|
|
25
27
|
*/
|
|
26
|
-
let originalCwd = null;
|
|
27
|
-
/** Get the original project root if currently in a worktree, or null. */
|
|
28
|
-
export function getWorktreeOriginalCwd() {
|
|
29
|
-
return originalCwd;
|
|
30
|
-
}
|
|
31
|
-
/** Get the name of the active worktree, or null if not in one. */
|
|
32
|
-
export function getActiveWorktreeName() {
|
|
33
|
-
if (!originalCwd)
|
|
34
|
-
return null;
|
|
35
|
-
const cwd = process.cwd();
|
|
36
|
-
const wtDir = join(originalCwd, ".gsd", "worktrees");
|
|
37
|
-
if (!cwd.startsWith(wtDir))
|
|
38
|
-
return null;
|
|
39
|
-
const rel = cwd.slice(wtDir.length + 1);
|
|
40
|
-
const name = rel.split("/")[0] ?? rel.split("\\")[0];
|
|
41
|
-
return name || null;
|
|
42
|
-
}
|
|
43
28
|
// ─── Shared completions and handler (used by both /worktree and /wt) ────────
|
|
44
29
|
function worktreeCompletions(prefix) {
|
|
45
30
|
const parts = prefix.trim().split(/\s+/);
|
|
@@ -111,7 +96,7 @@ async function worktreeHandler(args, ctx, pi, alias) {
|
|
|
111
96
|
return;
|
|
112
97
|
}
|
|
113
98
|
// create and switch both do the same thing: switch if exists, create if not
|
|
114
|
-
const mainBase =
|
|
99
|
+
const mainBase = getWorktreeOriginalCwd() ?? basePath;
|
|
115
100
|
const existing = listWorktrees(mainBase);
|
|
116
101
|
if (existing.some(wt => wt.name === name)) {
|
|
117
102
|
await handleSwitch(basePath, name, ctx);
|
|
@@ -123,7 +108,7 @@ async function worktreeHandler(args, ctx, pi, alias) {
|
|
|
123
108
|
}
|
|
124
109
|
if (trimmed === "merge" || trimmed.startsWith("merge ")) {
|
|
125
110
|
const mergeArgs = trimmed.replace(/^merge\s*/, "").trim().split(/\s+/).filter(Boolean);
|
|
126
|
-
const mainBase =
|
|
111
|
+
const mainBase = getWorktreeOriginalCwd() ?? basePath;
|
|
127
112
|
const activeWt = getActiveWorktreeName();
|
|
128
113
|
if (mergeArgs.length === 0) {
|
|
129
114
|
// Bare "/worktree merge" — only valid when inside a worktree
|
|
@@ -154,7 +139,7 @@ async function worktreeHandler(args, ctx, pi, alias) {
|
|
|
154
139
|
}
|
|
155
140
|
if (trimmed === "remove" || trimmed.startsWith("remove ")) {
|
|
156
141
|
const name = trimmed.replace(/^remove\s*/, "").trim();
|
|
157
|
-
const mainBase =
|
|
142
|
+
const mainBase = getWorktreeOriginalCwd() ?? basePath;
|
|
158
143
|
if (name === "all") {
|
|
159
144
|
await handleRemoveAll(mainBase, ctx);
|
|
160
145
|
return;
|
|
@@ -171,7 +156,7 @@ async function worktreeHandler(args, ctx, pi, alias) {
|
|
|
171
156
|
ctx.ui.notify(`Usage: /${alias} ${trimmed}${trimmed === "list" || trimmed === "return" ? "" : " <name>"}`, "warning");
|
|
172
157
|
return;
|
|
173
158
|
}
|
|
174
|
-
const mainBase =
|
|
159
|
+
const mainBase = getWorktreeOriginalCwd() ?? basePath;
|
|
175
160
|
const nameOnly = trimmed.split(/\s+/)[0];
|
|
176
161
|
if (trimmed !== nameOnly) {
|
|
177
162
|
ctx.ui.notify(`Unknown command. Did you mean /${alias} switch ${nameOnly}?`, "warning");
|
|
@@ -192,14 +177,7 @@ export function registerWorktreeCommand(pi) {
|
|
|
192
177
|
// Restore worktree state after /reload.
|
|
193
178
|
// The module-level originalCwd resets to null when extensions are re-loaded,
|
|
194
179
|
// but process.cwd() is still inside the worktree. Detect this and recover.
|
|
195
|
-
|
|
196
|
-
const cwd = process.cwd();
|
|
197
|
-
const marker = `${sep}.gsd${sep}worktrees${sep}`;
|
|
198
|
-
const markerIdx = cwd.indexOf(marker);
|
|
199
|
-
if (markerIdx !== -1) {
|
|
200
|
-
originalCwd = cwd.slice(0, markerIdx);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
180
|
+
ensureWorktreeOriginalCwdFromPath();
|
|
203
181
|
pi.registerCommand("worktree", {
|
|
204
182
|
description: "Git worktrees (also /wt): /worktree <name> | list | merge | remove",
|
|
205
183
|
getArgumentCompletions: worktreeCompletions,
|
|
@@ -260,7 +238,7 @@ async function handleCreate(basePath, name, ctx) {
|
|
|
260
238
|
// before createWorktree so the new worktree forks from committed HEAD)
|
|
261
239
|
const commitMsg = autoCommitCurrentBranch(basePath, "worktree-switch", name);
|
|
262
240
|
// Create from the main tree, not from inside another worktree
|
|
263
|
-
const mainBase =
|
|
241
|
+
const mainBase = getWorktreeOriginalCwd() ?? basePath;
|
|
264
242
|
const info = createWorktree(mainBase, name);
|
|
265
243
|
// Run user-configured post-create hook (#597) — e.g. copy .env, symlink assets
|
|
266
244
|
const hookError = runWorktreePostCreateHook(mainBase, info.path);
|
|
@@ -268,8 +246,8 @@ async function handleCreate(basePath, name, ctx) {
|
|
|
268
246
|
ctx.ui.notify(hookError, "warning");
|
|
269
247
|
}
|
|
270
248
|
// Track original cwd before switching
|
|
271
|
-
if (!
|
|
272
|
-
|
|
249
|
+
if (!getWorktreeOriginalCwd())
|
|
250
|
+
setWorktreeOriginalCwd(basePath);
|
|
273
251
|
const prevCwd = process.cwd();
|
|
274
252
|
process.chdir(info.path);
|
|
275
253
|
nudgeGitBranchCache(prevCwd);
|
|
@@ -319,7 +297,7 @@ async function handleCreate(basePath, name, ctx) {
|
|
|
319
297
|
}
|
|
320
298
|
async function handleSwitch(basePath, name, ctx) {
|
|
321
299
|
try {
|
|
322
|
-
const mainBase =
|
|
300
|
+
const mainBase = getWorktreeOriginalCwd() ?? basePath;
|
|
323
301
|
const wtPath = worktreePath(mainBase, name);
|
|
324
302
|
if (!existsSync(wtPath)) {
|
|
325
303
|
ctx.ui.notify(`Worktree "${name}" not found. Run /worktree list to see available worktrees.`, "warning");
|
|
@@ -328,8 +306,8 @@ async function handleSwitch(basePath, name, ctx) {
|
|
|
328
306
|
// Auto-commit dirty files before leaving current workspace
|
|
329
307
|
const commitMsg = autoCommitCurrentBranch(basePath, "worktree-switch", name);
|
|
330
308
|
// Track original cwd before switching
|
|
331
|
-
if (!
|
|
332
|
-
|
|
309
|
+
if (!getWorktreeOriginalCwd())
|
|
310
|
+
setWorktreeOriginalCwd(basePath);
|
|
333
311
|
const prevCwd = process.cwd();
|
|
334
312
|
process.chdir(wtPath);
|
|
335
313
|
nudgeGitBranchCache(prevCwd);
|
|
@@ -352,6 +330,7 @@ async function handleSwitch(basePath, name, ctx) {
|
|
|
352
330
|
}
|
|
353
331
|
}
|
|
354
332
|
async function handleReturn(ctx) {
|
|
333
|
+
const originalCwd = getWorktreeOriginalCwd();
|
|
355
334
|
if (!originalCwd) {
|
|
356
335
|
ctx.ui.notify("Already in the main project tree.", "info");
|
|
357
336
|
return;
|
|
@@ -359,7 +338,7 @@ async function handleReturn(ctx) {
|
|
|
359
338
|
// Auto-commit dirty files before leaving worktree
|
|
360
339
|
const commitMsg = autoCommitCurrentBranch(process.cwd(), "worktree-return", "worktree");
|
|
361
340
|
const returnTo = originalCwd;
|
|
362
|
-
|
|
341
|
+
clearWorktreeOriginalCwd();
|
|
363
342
|
const prevCwd = process.cwd();
|
|
364
343
|
process.chdir(returnTo);
|
|
365
344
|
nudgeGitBranchCache(prevCwd);
|
|
@@ -409,7 +388,7 @@ const CLR = {
|
|
|
409
388
|
};
|
|
410
389
|
async function handleList(basePath, ctx) {
|
|
411
390
|
try {
|
|
412
|
-
const mainBase =
|
|
391
|
+
const mainBase = getWorktreeOriginalCwd() ?? basePath;
|
|
413
392
|
const worktrees = listWorktrees(mainBase);
|
|
414
393
|
if (worktrees.length === 0) {
|
|
415
394
|
ctx.ui.notify("No GSD worktrees found. Create one with /worktree <name>.", "info");
|
|
@@ -452,6 +431,7 @@ async function handleList(basePath, ctx) {
|
|
|
452
431
|
}
|
|
453
432
|
lines.push("");
|
|
454
433
|
}
|
|
434
|
+
const originalCwd = getWorktreeOriginalCwd();
|
|
455
435
|
if (originalCwd) {
|
|
456
436
|
lines.push(` ${CLR.label("main tree")} ${CLR.path(originalCwd)}`);
|
|
457
437
|
}
|
|
@@ -539,11 +519,11 @@ async function handleMerge(basePath, name, ctx, pi, targetBranch) {
|
|
|
539
519
|
}
|
|
540
520
|
// Switch to the main tree before merging.
|
|
541
521
|
// Must be on the main branch to run git merge --squash.
|
|
542
|
-
if (
|
|
522
|
+
if (getWorktreeOriginalCwd()) {
|
|
543
523
|
const prevCwd = process.cwd();
|
|
544
524
|
process.chdir(basePath);
|
|
545
525
|
nudgeGitBranchCache(prevCwd);
|
|
546
|
-
|
|
526
|
+
clearWorktreeOriginalCwd();
|
|
547
527
|
}
|
|
548
528
|
// --- Deterministic merge path (preferred) ---
|
|
549
529
|
// Try a direct squash-merge first. Only fall back to LLM on conflict.
|
|
@@ -620,7 +600,7 @@ async function handleMerge(basePath, name, ctx, pi, targetBranch) {
|
|
|
620
600
|
}
|
|
621
601
|
async function handleRemove(basePath, name, ctx) {
|
|
622
602
|
try {
|
|
623
|
-
const mainBase =
|
|
603
|
+
const mainBase = getWorktreeOriginalCwd() ?? basePath;
|
|
624
604
|
// Validate the worktree exists before attempting removal
|
|
625
605
|
const worktrees = listWorktrees(mainBase);
|
|
626
606
|
const wt = worktrees.find(w => w.name === name);
|
|
@@ -641,9 +621,9 @@ async function handleRemove(basePath, name, ctx) {
|
|
|
641
621
|
const prevCwd = process.cwd();
|
|
642
622
|
removeWorktree(mainBase, name, { deleteBranch: true });
|
|
643
623
|
// If we were in that worktree, removeWorktree chdir'd us out — clear tracking
|
|
644
|
-
if (
|
|
624
|
+
if (getWorktreeOriginalCwd() && process.cwd() !== prevCwd) {
|
|
645
625
|
nudgeGitBranchCache(prevCwd);
|
|
646
|
-
|
|
626
|
+
clearWorktreeOriginalCwd();
|
|
647
627
|
}
|
|
648
628
|
ctx.ui.notify(`${CLR.ok("✓")} Worktree ${CLR.name(name)} removed ${CLR.muted("(branch deleted)")}.`, "info");
|
|
649
629
|
}
|
|
@@ -654,7 +634,7 @@ async function handleRemove(basePath, name, ctx) {
|
|
|
654
634
|
}
|
|
655
635
|
async function handleRemoveAll(basePath, ctx) {
|
|
656
636
|
try {
|
|
657
|
-
const mainBase =
|
|
637
|
+
const mainBase = getWorktreeOriginalCwd() ?? basePath;
|
|
658
638
|
const worktrees = listWorktrees(mainBase);
|
|
659
639
|
if (worktrees.length === 0) {
|
|
660
640
|
ctx.ui.notify("No worktrees to remove.", "info");
|
|
@@ -684,9 +664,9 @@ async function handleRemoveAll(basePath, ctx) {
|
|
|
684
664
|
}
|
|
685
665
|
}
|
|
686
666
|
// If we were in a worktree that got removed, clear tracking
|
|
687
|
-
if (
|
|
667
|
+
if (getWorktreeOriginalCwd() && process.cwd() !== prevCwd) {
|
|
688
668
|
nudgeGitBranchCache(prevCwd);
|
|
689
|
-
|
|
669
|
+
clearWorktreeOriginalCwd();
|
|
690
670
|
}
|
|
691
671
|
const lines = [];
|
|
692
672
|
if (removed.length > 0)
|
|
@@ -21,6 +21,7 @@ import { GSDError, GSD_PARSE_ERROR, GSD_STALE_STATE, GSD_LOCK_HELD, GSD_GIT_ERRO
|
|
|
21
21
|
import { logWarning } from "./workflow-logger.js";
|
|
22
22
|
import { nativeBranchDelete, nativeBranchExists, nativeBranchForceReset, nativeCommit, nativeDetectMainBranch, nativeDiffContent, nativeDiffNameStatus, nativeDiffNumstat, nativeGetCurrentBranch, nativeIsAncestor, nativeLogOneline, nativeMergeSquash, nativeWorktreeAdd, nativeWorktreeList, nativeWorktreePrune, nativeWorktreeRemove, } from "./native-git-bridge.js";
|
|
23
23
|
import { emitCanonicalRootRedirect } from "./worktree-telemetry.js";
|
|
24
|
+
import { isGsdWorktreePath, normalizeWorktreePathForCompare, resolveWorktreeProjectRoot, } from "./worktree-root.js";
|
|
24
25
|
// ─── Path Helpers ──────────────────────────────────────────────────────────
|
|
25
26
|
function normalizePathForComparison(path) {
|
|
26
27
|
const normalized = path
|
|
@@ -29,6 +30,14 @@ function normalizePathForComparison(path) {
|
|
|
29
30
|
.replace(/\/+$/, "");
|
|
30
31
|
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
31
32
|
}
|
|
33
|
+
function normalizeBasePathForWorktreeOps(basePath) {
|
|
34
|
+
const resolved = resolveWorktreeProjectRoot(basePath);
|
|
35
|
+
if (isGsdWorktreePath(basePath) &&
|
|
36
|
+
normalizeWorktreePathForCompare(resolved) === normalizeWorktreePathForCompare(basePath)) {
|
|
37
|
+
throw new GSDError(GSD_GIT_ERROR, `Cannot resolve project root from worktree path: ${basePath}. Run the command from the project root or set GSD_PROJECT_ROOT.`);
|
|
38
|
+
}
|
|
39
|
+
return resolved;
|
|
40
|
+
}
|
|
32
41
|
// ─── resolveGitDir ─────────────────────────────────────────────────────────
|
|
33
42
|
/**
|
|
34
43
|
* Resolve the actual git directory for a given repository path.
|
|
@@ -61,7 +70,7 @@ export function resolveGitDir(basePath) {
|
|
|
61
70
|
return gitPath;
|
|
62
71
|
}
|
|
63
72
|
export function worktreesDir(basePath) {
|
|
64
|
-
return join(basePath, ".gsd", "worktrees");
|
|
73
|
+
return join(resolveWorktreeProjectRoot(basePath), ".gsd", "worktrees");
|
|
65
74
|
}
|
|
66
75
|
export function worktreePath(basePath, name) {
|
|
67
76
|
return join(worktreesDir(basePath), name);
|
|
@@ -143,6 +152,7 @@ export function resolveCanonicalMilestoneRoot(basePath, milestoneId) {
|
|
|
143
152
|
* @param opts.branch — override the default `worktree/<name>` branch name
|
|
144
153
|
*/
|
|
145
154
|
export function createWorktree(basePath, name, opts = {}) {
|
|
155
|
+
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
146
156
|
// Validate name: alphanumeric, hyphens, underscores only
|
|
147
157
|
if (!/^[a-zA-Z0-9_-]+$/.test(name)) {
|
|
148
158
|
throw new GSDError(GSD_PARSE_ERROR, `Invalid worktree name "${name}". Use only letters, numbers, hyphens, and underscores.`);
|
|
@@ -227,6 +237,7 @@ export function createWorktree(basePath, name, opts = {}) {
|
|
|
227
237
|
* Uses native worktree list and filters to those under .gsd/worktrees/.
|
|
228
238
|
*/
|
|
229
239
|
export function listWorktrees(basePath) {
|
|
240
|
+
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
230
241
|
const baseVariants = [resolve(basePath)];
|
|
231
242
|
if (existsSync(basePath)) {
|
|
232
243
|
baseVariants.push(realpathSync(basePath));
|
|
@@ -366,6 +377,7 @@ export function findNestedGitDirs(rootPath) {
|
|
|
366
377
|
* If the process is currently inside the worktree, chdir out first.
|
|
367
378
|
*/
|
|
368
379
|
export function removeWorktree(basePath, name, opts = {}) {
|
|
380
|
+
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
369
381
|
let wtPath = worktreePath(basePath, name);
|
|
370
382
|
const branch = opts.branch ?? worktreeBranchName(name);
|
|
371
383
|
const { deleteBranch = true, force = true } = opts;
|
|
@@ -614,6 +626,7 @@ function parseDiffNameStatus(entries) {
|
|
|
614
626
|
* Returns a summary of added, modified, and removed GSD artifacts.
|
|
615
627
|
*/
|
|
616
628
|
export function diffWorktreeGSD(basePath, name) {
|
|
629
|
+
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
617
630
|
const branch = worktreeBranchName(name);
|
|
618
631
|
const mainBranch = nativeDetectMainBranch(basePath);
|
|
619
632
|
const entries = nativeDiffNameStatus(basePath, mainBranch, branch, ".gsd/", true);
|
|
@@ -626,6 +639,7 @@ export function diffWorktreeGSD(basePath, name) {
|
|
|
626
639
|
* content, this correctly returns an empty diff.
|
|
627
640
|
*/
|
|
628
641
|
export function diffWorktreeAll(basePath, name) {
|
|
642
|
+
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
629
643
|
const branch = worktreeBranchName(name);
|
|
630
644
|
const mainBranch = nativeDetectMainBranch(basePath);
|
|
631
645
|
const entries = nativeDiffNameStatus(basePath, mainBranch, branch);
|
|
@@ -636,6 +650,7 @@ export function diffWorktreeAll(basePath, name) {
|
|
|
636
650
|
* Uses direct diff (not merge-base) so the preview matches the actual merge outcome.
|
|
637
651
|
*/
|
|
638
652
|
export function diffWorktreeNumstat(basePath, name) {
|
|
653
|
+
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
639
654
|
const branch = worktreeBranchName(name);
|
|
640
655
|
const mainBranch = nativeDetectMainBranch(basePath);
|
|
641
656
|
const rawStats = nativeDiffNumstat(basePath, mainBranch, branch);
|
|
@@ -652,6 +667,7 @@ export function diffWorktreeNumstat(basePath, name) {
|
|
|
652
667
|
* Returns the raw unified diff for LLM consumption.
|
|
653
668
|
*/
|
|
654
669
|
export function getWorktreeGSDDiff(basePath, name) {
|
|
670
|
+
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
655
671
|
const branch = worktreeBranchName(name);
|
|
656
672
|
const mainBranch = nativeDetectMainBranch(basePath);
|
|
657
673
|
return nativeDiffContent(basePath, mainBranch, branch, ".gsd/", undefined, true);
|
|
@@ -661,6 +677,7 @@ export function getWorktreeGSDDiff(basePath, name) {
|
|
|
661
677
|
* Returns the raw unified diff for LLM consumption.
|
|
662
678
|
*/
|
|
663
679
|
export function getWorktreeCodeDiff(basePath, name) {
|
|
680
|
+
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
664
681
|
const branch = worktreeBranchName(name);
|
|
665
682
|
const mainBranch = nativeDetectMainBranch(basePath);
|
|
666
683
|
return nativeDiffContent(basePath, mainBranch, branch, undefined, ".gsd/", true);
|
|
@@ -669,6 +686,7 @@ export function getWorktreeCodeDiff(basePath, name) {
|
|
|
669
686
|
* Get commit log for the worktree branch since it diverged from main.
|
|
670
687
|
*/
|
|
671
688
|
export function getWorktreeLog(basePath, name) {
|
|
689
|
+
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
672
690
|
const branch = worktreeBranchName(name);
|
|
673
691
|
const mainBranch = nativeDetectMainBranch(basePath);
|
|
674
692
|
const entries = nativeLogOneline(basePath, mainBranch, branch);
|
|
@@ -680,6 +698,7 @@ export function getWorktreeLog(basePath, name) {
|
|
|
680
698
|
* Returns the merge commit message.
|
|
681
699
|
*/
|
|
682
700
|
export function mergeWorktreeToMain(basePath, name, commitMessage) {
|
|
701
|
+
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
683
702
|
const branch = worktreeBranchName(name);
|
|
684
703
|
const mainBranch = nativeDetectMainBranch(basePath);
|
|
685
704
|
const current = nativeGetCurrentBranch(basePath);
|
|
@@ -20,28 +20,19 @@ import { emitJournalEvent } from "./journal.js";
|
|
|
20
20
|
import { emitWorktreeCreated, emitWorktreeMerged } from "./worktree-telemetry.js";
|
|
21
21
|
import { getCollapseCadence, getMilestoneResquash, resquashMilestoneOnMain } from "./slice-cadence.js";
|
|
22
22
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
23
|
+
import { resolveWorktreeProjectRoot } from "./worktree-root.js";
|
|
23
24
|
// ─── Path Helpers ──────────────────────────────────────────────────────────
|
|
24
|
-
/**
|
|
25
|
-
* Worktree marker segment — present in any path produced by worktreePath().
|
|
26
|
-
* Used to strip the worktree suffix and recover the project root (#3729).
|
|
27
|
-
*/
|
|
28
|
-
const WORKTREE_MARKER = "/.gsd/worktrees/";
|
|
29
25
|
/**
|
|
30
26
|
* Resolve the project root from session path state.
|
|
31
27
|
*
|
|
32
28
|
* Prefers `originalBasePath` (always the project root when set), but falls
|
|
33
29
|
* back to `basePath` when `originalBasePath` is falsy (e.g. fresh AutoSession
|
|
34
30
|
* with default empty string). If `basePath` itself is inside a worktree
|
|
35
|
-
* directory (
|
|
36
|
-
* actual project root
|
|
31
|
+
* directory (including symlink-resolved ~/.gsd/projects/<hash>/worktrees
|
|
32
|
+
* paths), recover the actual project root to prevent double nesting (#3729).
|
|
37
33
|
*/
|
|
38
34
|
export function resolveProjectRoot(originalBasePath, basePath) {
|
|
39
|
-
|
|
40
|
-
const markerIdx = resolved.indexOf(WORKTREE_MARKER);
|
|
41
|
-
if (markerIdx !== -1) {
|
|
42
|
-
resolved = resolved.slice(0, markerIdx);
|
|
43
|
-
}
|
|
44
|
-
return resolved;
|
|
35
|
+
return resolveWorktreeProjectRoot(basePath, originalBasePath);
|
|
45
36
|
}
|
|
46
37
|
// ─── WorktreeResolver ──────────────────────────────────────────────────────
|
|
47
38
|
export class WorktreeResolver {
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
export function normalizeWorktreePathForCompare(path) {
|
|
5
|
+
let normalized;
|
|
6
|
+
try {
|
|
7
|
+
normalized = realpathSync(path);
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
normalized = resolve(path);
|
|
11
|
+
}
|
|
12
|
+
const slashed = normalized.replaceAll("\\", "/");
|
|
13
|
+
const trimmed = slashed.replace(/\/+$/, "");
|
|
14
|
+
return process.platform === "win32" ? (trimmed || "/").toLowerCase() : (trimmed || "/");
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Find the GSD worktree segment in both direct project layout and the
|
|
18
|
+
* symlink-resolved external-state layout used by ~/.gsd/projects/<hash>.
|
|
19
|
+
*/
|
|
20
|
+
export function findWorktreeSegment(normalizedPath) {
|
|
21
|
+
const directMarker = "/.gsd/worktrees/";
|
|
22
|
+
const directIdx = normalizedPath.indexOf(directMarker);
|
|
23
|
+
if (directIdx !== -1) {
|
|
24
|
+
return { gsdIdx: directIdx, afterWorktrees: directIdx + directMarker.length };
|
|
25
|
+
}
|
|
26
|
+
const externalRe = /\/\.gsd\/projects\/[^/]+\/worktrees\//;
|
|
27
|
+
const externalMatch = normalizedPath.match(externalRe);
|
|
28
|
+
if (externalMatch && externalMatch.index !== undefined) {
|
|
29
|
+
return {
|
|
30
|
+
gsdIdx: externalMatch.index,
|
|
31
|
+
afterWorktrees: externalMatch.index + externalMatch[0].length,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
export function isGsdWorktreePath(path) {
|
|
37
|
+
return findWorktreeSegment(path.replaceAll("\\", "/")) !== null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the canonical project root for worktree operations.
|
|
41
|
+
*
|
|
42
|
+
* `originalBasePath` wins when available because session state already knows the
|
|
43
|
+
* root. `GSD_PROJECT_ROOT` is the next strongest signal for worker processes.
|
|
44
|
+
* Otherwise, derive the root from direct `.gsd/worktrees` paths, or recover it
|
|
45
|
+
* from the worktree `.git` file for symlink-resolved ~/.gsd/project paths.
|
|
46
|
+
*/
|
|
47
|
+
export function resolveWorktreeProjectRoot(basePath, originalBasePath) {
|
|
48
|
+
const preferred = originalBasePath?.trim() ||
|
|
49
|
+
process.env.GSD_PROJECT_ROOT?.trim() ||
|
|
50
|
+
basePath;
|
|
51
|
+
return resolveProjectRootFromPath(preferred);
|
|
52
|
+
}
|
|
53
|
+
function resolveProjectRootFromPath(path) {
|
|
54
|
+
const normalizedPath = path.replaceAll("\\", "/");
|
|
55
|
+
const segment = findWorktreeSegment(normalizedPath);
|
|
56
|
+
if (!segment)
|
|
57
|
+
return resolveGitWorkingTreeRoot(path) ?? path;
|
|
58
|
+
const sepChar = path.includes("\\") ? "\\" : "/";
|
|
59
|
+
const gsdMarker = `${sepChar}.gsd${sepChar}`;
|
|
60
|
+
const markerIdx = path.indexOf(gsdMarker);
|
|
61
|
+
const candidate = markerIdx !== -1
|
|
62
|
+
? path.slice(0, markerIdx)
|
|
63
|
+
: path.slice(0, segment.gsdIdx);
|
|
64
|
+
const gsdHome = normalizeWorktreePathForCompare(process.env.GSD_HOME || join(homedir(), ".gsd"));
|
|
65
|
+
const candidateGsdPath = normalizeWorktreePathForCompare(join(candidate, ".gsd"));
|
|
66
|
+
if (candidateGsdPath === gsdHome || candidateGsdPath.startsWith(`${gsdHome}/`)) {
|
|
67
|
+
const realRoot = resolveProjectRootFromGitFile(path);
|
|
68
|
+
return realRoot ?? path;
|
|
69
|
+
}
|
|
70
|
+
return candidate;
|
|
71
|
+
}
|
|
72
|
+
function resolveGitWorkingTreeRoot(path) {
|
|
73
|
+
try {
|
|
74
|
+
let dir = existsSync(path) && !statSync(path).isDirectory()
|
|
75
|
+
? resolve(path, "..")
|
|
76
|
+
: path;
|
|
77
|
+
for (let i = 0; i < 30; i++) {
|
|
78
|
+
const gitPath = join(dir, ".git");
|
|
79
|
+
if (existsSync(gitPath))
|
|
80
|
+
return dir;
|
|
81
|
+
const parent = resolve(dir, "..");
|
|
82
|
+
if (parent === dir)
|
|
83
|
+
break;
|
|
84
|
+
dir = parent;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// Non-fatal: callers either keep the original path or fail closed.
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
function resolveProjectRootFromGitFile(worktreePath) {
|
|
93
|
+
try {
|
|
94
|
+
let dir = worktreePath;
|
|
95
|
+
for (let i = 0; i < 30; i++) {
|
|
96
|
+
const gitPath = join(dir, ".git");
|
|
97
|
+
if (existsSync(gitPath)) {
|
|
98
|
+
const content = readFileSync(gitPath, "utf8").trim();
|
|
99
|
+
if (content.startsWith("gitdir: ")) {
|
|
100
|
+
const gitDir = resolve(dir, content.slice(8));
|
|
101
|
+
const dotGitDir = resolve(gitDir, "..", "..");
|
|
102
|
+
if (dotGitDir.endsWith(".git") || dotGitDir.endsWith(".git/") || dotGitDir.endsWith(".git\\")) {
|
|
103
|
+
return resolve(dotGitDir, "..");
|
|
104
|
+
}
|
|
105
|
+
const commonDirPath = join(gitDir, "commondir");
|
|
106
|
+
if (existsSync(commonDirPath)) {
|
|
107
|
+
const commonDir = readFileSync(commonDirPath, "utf8").trim();
|
|
108
|
+
const resolvedCommonDir = resolve(gitDir, commonDir);
|
|
109
|
+
return resolve(resolvedCommonDir, "..");
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
const parent = resolve(dir, "..");
|
|
115
|
+
if (parent === dir)
|
|
116
|
+
break;
|
|
117
|
+
dir = parent;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
// Non-fatal: callers either keep the original path or fail closed.
|
|
122
|
+
}
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// GSD worktree session state
|
|
2
|
+
let originalCwd = null;
|
|
3
|
+
export function getWorktreeOriginalCwd() {
|
|
4
|
+
return originalCwd;
|
|
5
|
+
}
|
|
6
|
+
export function setWorktreeOriginalCwd(cwd) {
|
|
7
|
+
originalCwd = cwd;
|
|
8
|
+
}
|
|
9
|
+
export function clearWorktreeOriginalCwd() {
|
|
10
|
+
originalCwd = null;
|
|
11
|
+
}
|
|
12
|
+
export function ensureWorktreeOriginalCwdFromPath(cwd = process.cwd()) {
|
|
13
|
+
if (originalCwd)
|
|
14
|
+
return originalCwd;
|
|
15
|
+
const marker = `${/\\/.test(cwd) ? "\\" : "/"}.gsd${/\\/.test(cwd) ? "\\" : "/"}worktrees${/\\/.test(cwd) ? "\\" : "/"}`;
|
|
16
|
+
const markerIdx = cwd.indexOf(marker);
|
|
17
|
+
if (markerIdx !== -1) {
|
|
18
|
+
originalCwd = cwd.slice(0, markerIdx);
|
|
19
|
+
}
|
|
20
|
+
return originalCwd;
|
|
21
|
+
}
|
|
22
|
+
export function getActiveWorktreeName() {
|
|
23
|
+
if (!originalCwd)
|
|
24
|
+
return null;
|
|
25
|
+
const cwd = process.cwd();
|
|
26
|
+
const wtDir = `${originalCwd.replace(/[\\/]+$/, "")}/.gsd/worktrees`.replaceAll("\\", "/");
|
|
27
|
+
const normalizedCwd = cwd.replaceAll("\\", "/");
|
|
28
|
+
if (!normalizedCwd.startsWith(`${wtDir}/`))
|
|
29
|
+
return null;
|
|
30
|
+
const rel = normalizedCwd.slice(wtDir.length + 1);
|
|
31
|
+
const name = rel.split("/")[0];
|
|
32
|
+
return name || null;
|
|
33
|
+
}
|
|
@@ -11,11 +11,12 @@
|
|
|
11
11
|
* Pure utility functions (detectWorktreeName, getSliceBranchName, parseSliceBranch,
|
|
12
12
|
* SLICE_BRANCH_RE) remain for backwards compatibility with legacy branches.
|
|
13
13
|
*/
|
|
14
|
-
import { existsSync, readFileSync,
|
|
14
|
+
import { existsSync, readFileSync, utimesSync } from "node:fs";
|
|
15
15
|
import { join, resolve } from "node:path";
|
|
16
|
-
import { homedir } from "node:os";
|
|
17
16
|
import { GitServiceImpl, writeIntegrationBranch } from "./git-service.js";
|
|
18
17
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
18
|
+
import { findWorktreeSegment, resolveWorktreeProjectRoot, } from "./worktree-root.js";
|
|
19
|
+
export { resolveWorktreeProjectRoot } from "./worktree-root.js";
|
|
19
20
|
export { MergeConflictError } from "./git-service.js";
|
|
20
21
|
// ─── Lazy GitServiceImpl Cache ─────────────────────────────────────────────
|
|
21
22
|
let cachedService = null;
|
|
@@ -67,28 +68,6 @@ export function captureIntegrationBranch(basePath, milestoneId) {
|
|
|
67
68
|
writeIntegrationBranch(basePath, milestoneId, current);
|
|
68
69
|
}
|
|
69
70
|
// ─── Pure Utility Functions (unchanged) ────────────────────────────────────
|
|
70
|
-
/**
|
|
71
|
-
* Find the worktrees segment in a path, supporting both direct
|
|
72
|
-
* (`/.gsd/worktrees/`) and symlink-resolved (`/.gsd/projects/<hash>/worktrees/`)
|
|
73
|
-
* layouts. When `.gsd` is a symlink to `~/.gsd/projects/<hash>`, resolved
|
|
74
|
-
* paths contain the intermediate `projects/<hash>/` segment that the old
|
|
75
|
-
* single-marker check missed.
|
|
76
|
-
*/
|
|
77
|
-
function findWorktreeSegment(normalizedPath) {
|
|
78
|
-
// Direct layout: /.gsd/worktrees/<name>
|
|
79
|
-
const directMarker = "/.gsd/worktrees/";
|
|
80
|
-
const idx = normalizedPath.indexOf(directMarker);
|
|
81
|
-
if (idx !== -1) {
|
|
82
|
-
return { gsdIdx: idx, afterWorktrees: idx + directMarker.length };
|
|
83
|
-
}
|
|
84
|
-
// Symlink-resolved layout: /.gsd/projects/<hash>/worktrees/<name>
|
|
85
|
-
const symlinkRe = /\/\.gsd\/projects\/[a-f0-9]+\/worktrees\//;
|
|
86
|
-
const match = normalizedPath.match(symlinkRe);
|
|
87
|
-
if (match && match.index !== undefined) {
|
|
88
|
-
return { gsdIdx: match.index, afterWorktrees: match.index + match[0].length };
|
|
89
|
-
}
|
|
90
|
-
return null;
|
|
91
|
-
}
|
|
92
71
|
/**
|
|
93
72
|
* Detect the active worktree name from the current working directory.
|
|
94
73
|
* Returns null if not inside a GSD worktree (.gsd/worktrees/<name>/).
|
|
@@ -121,97 +100,7 @@ export function detectWorktreeName(basePath) {
|
|
|
121
100
|
* operate against the real project root, not a worktree subdirectory.
|
|
122
101
|
*/
|
|
123
102
|
export function resolveProjectRoot(basePath) {
|
|
124
|
-
|
|
125
|
-
if (process.env.GSD_PROJECT_ROOT) {
|
|
126
|
-
return process.env.GSD_PROJECT_ROOT;
|
|
127
|
-
}
|
|
128
|
-
const normalizedPath = basePath.replaceAll("\\", "/");
|
|
129
|
-
const seg = findWorktreeSegment(normalizedPath);
|
|
130
|
-
if (!seg)
|
|
131
|
-
return basePath;
|
|
132
|
-
// Candidate root via the string-slice heuristic
|
|
133
|
-
const sepChar = basePath.includes("\\") ? "\\" : "/";
|
|
134
|
-
const gsdMarker = `${sepChar}.gsd${sepChar}`;
|
|
135
|
-
const gsdIdx = basePath.indexOf(gsdMarker);
|
|
136
|
-
const candidate = gsdIdx !== -1
|
|
137
|
-
? basePath.slice(0, gsdIdx)
|
|
138
|
-
: basePath.slice(0, seg.gsdIdx);
|
|
139
|
-
// Layer 2: Guard against resolving to the user's home directory.
|
|
140
|
-
// When .gsd is a symlink into ~/.gsd/projects/<hash>, the resolved path
|
|
141
|
-
// contains /.gsd/ at the user-level boundary. Slicing there yields ~ — wrong.
|
|
142
|
-
const gsdHome = normalizePathForCompare(process.env.GSD_HOME || join(homedir(), ".gsd"));
|
|
143
|
-
const candidateGsdPath = normalizePathForCompare(join(candidate, ".gsd"));
|
|
144
|
-
if (candidateGsdPath === gsdHome || candidateGsdPath.startsWith(gsdHome + "/")) {
|
|
145
|
-
// The candidate is the home directory (or within it in a way that .gsd
|
|
146
|
-
// maps to the user-level GSD dir). Try to recover the real project root
|
|
147
|
-
// from the worktree's .git file.
|
|
148
|
-
const realRoot = resolveProjectRootFromGitFile(basePath);
|
|
149
|
-
if (realRoot)
|
|
150
|
-
return realRoot;
|
|
151
|
-
// If git file resolution failed, return basePath unchanged rather than ~
|
|
152
|
-
return basePath;
|
|
153
|
-
}
|
|
154
|
-
return candidate;
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* Recover the real project root from a worktree's .git file.
|
|
158
|
-
*
|
|
159
|
-
* Each git worktree has a `.git` file (not directory) containing:
|
|
160
|
-
* gitdir: /real/project/.git/worktrees/<name>
|
|
161
|
-
*
|
|
162
|
-
* Walking up from that gitdir gives us `/real/project/.git`, and its
|
|
163
|
-
* parent is the real project root.
|
|
164
|
-
*/
|
|
165
|
-
function resolveProjectRootFromGitFile(worktreePath) {
|
|
166
|
-
try {
|
|
167
|
-
// Walk up from the worktree path to find the .git file
|
|
168
|
-
let dir = worktreePath;
|
|
169
|
-
for (let i = 0; i < 30; i++) {
|
|
170
|
-
const gitPath = join(dir, ".git");
|
|
171
|
-
if (existsSync(gitPath)) {
|
|
172
|
-
const content = readFileSync(gitPath, "utf8").trim();
|
|
173
|
-
if (content.startsWith("gitdir: ")) {
|
|
174
|
-
// gitdir points to: <real-project>/.git/worktrees/<name>
|
|
175
|
-
const gitDir = resolve(dir, content.slice(8));
|
|
176
|
-
// Walk up: .git/worktrees/<name> → .git/worktrees → .git → project root
|
|
177
|
-
const dotGitDir = resolve(gitDir, "..", "..");
|
|
178
|
-
// Verify this looks like a .git directory
|
|
179
|
-
if (dotGitDir.endsWith(".git") || dotGitDir.endsWith(".git/") || dotGitDir.endsWith(".git\\")) {
|
|
180
|
-
return resolve(dotGitDir, "..");
|
|
181
|
-
}
|
|
182
|
-
// Alternative: the commondir file inside the worktree gitdir
|
|
183
|
-
// points to the main .git directory
|
|
184
|
-
const commonDirPath = join(gitDir, "commondir");
|
|
185
|
-
if (existsSync(commonDirPath)) {
|
|
186
|
-
const commonDir = readFileSync(commonDirPath, "utf8").trim();
|
|
187
|
-
const resolvedCommonDir = resolve(gitDir, commonDir);
|
|
188
|
-
return resolve(resolvedCommonDir, "..");
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
193
|
-
const parent = resolve(dir, "..");
|
|
194
|
-
if (parent === dir)
|
|
195
|
-
break;
|
|
196
|
-
dir = parent;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
catch {
|
|
200
|
-
// Non-fatal — caller will use fallback
|
|
201
|
-
}
|
|
202
|
-
return null;
|
|
203
|
-
}
|
|
204
|
-
function normalizePathForCompare(path) {
|
|
205
|
-
let normalized;
|
|
206
|
-
try {
|
|
207
|
-
normalized = realpathSync(path);
|
|
208
|
-
}
|
|
209
|
-
catch {
|
|
210
|
-
normalized = resolve(path);
|
|
211
|
-
}
|
|
212
|
-
const slashed = normalized.replaceAll("\\", "/");
|
|
213
|
-
const trimmed = slashed.replace(/\/+$/, "");
|
|
214
|
-
return trimmed || "/";
|
|
103
|
+
return resolveWorktreeProjectRoot(basePath);
|
|
215
104
|
}
|
|
216
105
|
/**
|
|
217
106
|
* Get the slice branch name, namespaced by worktree when inside one.
|