gsd-pi 2.81.0 → 2.82.0-dev.ed17d078d
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 -30
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/browser-tools/tools/screenshot.js +1 -0
- package/dist/resources/extensions/browser-tools/tools/zoom.js +1 -0
- package/dist/resources/extensions/gsd/auto/loop.js +111 -8
- package/dist/resources/extensions/gsd/auto/orchestrator.js +113 -6
- package/dist/resources/extensions/gsd/auto/phases.js +199 -97
- package/dist/resources/extensions/gsd/auto/run-unit.js +66 -3
- package/dist/resources/extensions/gsd/auto/session.js +9 -0
- package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +43 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +182 -178
- package/dist/resources/extensions/gsd/auto-dispatch.js +14 -11
- package/dist/resources/extensions/gsd/auto-post-unit.js +7 -1
- package/dist/resources/extensions/gsd/auto-prompts.js +11 -3
- package/dist/resources/extensions/gsd/auto-recovery.js +6 -181
- package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -0
- package/dist/resources/extensions/gsd/auto-start.js +20 -23
- package/dist/resources/extensions/gsd/auto-unit-closeout.js +33 -5
- package/dist/resources/extensions/gsd/auto-verification.js +12 -6
- package/dist/resources/extensions/gsd/auto-worktree.js +8 -0
- package/dist/resources/extensions/gsd/auto.js +386 -106
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +13 -6
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +13 -2
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +4 -8
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
- package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -1
- package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +4 -10
- package/dist/resources/extensions/gsd/commands/handlers/parallel.js +9 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
- package/dist/resources/extensions/gsd/context-store.js +112 -0
- package/dist/resources/extensions/gsd/db-writer.js +150 -84
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/doctor-git-checks.js +41 -6
- package/dist/resources/extensions/gsd/git-service.js +2 -1
- package/dist/resources/extensions/gsd/gsd-db.js +7 -23
- package/dist/resources/extensions/gsd/health-widget-core.js +1 -1
- package/dist/resources/extensions/gsd/health-widget.js +4 -10
- package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
- package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
- package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
- package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +6 -96
- package/dist/resources/extensions/gsd/md-importer.js +1 -1
- package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
- package/dist/resources/extensions/gsd/migrate/command.js +5 -0
- package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
- package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
- package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
- package/dist/resources/extensions/gsd/native-git-bridge.js +14 -14
- package/dist/resources/extensions/gsd/notification-overlay.js +35 -40
- package/dist/resources/extensions/gsd/parallel-merge.js +53 -30
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +25 -33
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +14 -12
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
- package/dist/resources/extensions/gsd/prompts/discuss.md +20 -2
- package/dist/resources/extensions/gsd/prompts/system.md +2 -2
- package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
- package/dist/resources/extensions/gsd/recovery-classification.js +15 -1
- package/dist/resources/extensions/gsd/session-lock.js +40 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +131 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +247 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +50 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +87 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.js +50 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +124 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +32 -0
- package/dist/resources/extensions/gsd/state-reconciliation/errors.js +41 -0
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +99 -0
- package/dist/resources/extensions/gsd/state-reconciliation/registry.js +24 -0
- package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +43 -0
- package/dist/resources/extensions/gsd/state-reconciliation/types.js +3 -0
- package/dist/resources/extensions/gsd/state-reconciliation.js +5 -26
- package/dist/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/dist/resources/extensions/gsd/tui/render-kit.js +74 -0
- package/dist/resources/extensions/gsd/watch/header-renderer.js +92 -69
- package/dist/resources/extensions/gsd/watch/splash-palette.js +10 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +722 -316
- package/dist/resources/extensions/gsd/worktree-telemetry.js +3 -1
- 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 +6 -6
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/required-server-files.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +6 -6
- 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.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/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-752f1e2ebdaa3e45.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/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/dist/welcome-screen.d.ts +0 -7
- package/dist/welcome-screen.js +60 -69
- package/package.json +3 -2
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/README.md +2 -0
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
- 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/index.d.ts +2 -2
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -1
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.d.ts +11 -0
- package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/src/index.ts +7 -2
- package/packages/pi-ai/src/providers/transform-messages.ts +24 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js +47 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +76 -9
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js +40 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +30 -29
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +10 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +13 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +58 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +2 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +12 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -41
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +86 -82
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts +35 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js +152 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts +16 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js +73 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +12 -8
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +105 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +27 -26
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +9 -6
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/assistant-message-design.test.ts +56 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +113 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/user-message-design.test.ts +48 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +10 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +43 -42
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +14 -14
- package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +64 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +13 -7
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +15 -42
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +84 -104
- package/packages/pi-coding-agent/src/modes/interactive/components/transcript-design.ts +196 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tui-style-kit.ts +94 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +14 -9
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme-highlight.test.ts +23 -0
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +106 -1
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +27 -26
- package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +9 -6
- package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +14 -1
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
- package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
- package/packages/pi-tui/dist/overlay-layout.js +9 -6
- package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +5 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +20 -1
- package/packages/pi-tui/src/overlay-layout.ts +10 -7
- package/packages/pi-tui/src/tui.ts +6 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.js +105 -1
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.js +27 -26
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
- package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +46 -11
- package/src/resources/extensions/gsd/auto/loop-deps.ts +9 -5
- package/src/resources/extensions/gsd/auto/loop.ts +113 -9
- package/src/resources/extensions/gsd/auto/orchestrator.ts +118 -6
- package/src/resources/extensions/gsd/auto/phases.ts +158 -19
- package/src/resources/extensions/gsd/auto/run-unit.ts +69 -4
- package/src/resources/extensions/gsd/auto/session.ts +10 -0
- package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +82 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +230 -183
- package/src/resources/extensions/gsd/auto-dispatch.ts +15 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +7 -1
- package/src/resources/extensions/gsd/auto-prompts.ts +11 -3
- package/src/resources/extensions/gsd/auto-recovery.ts +7 -209
- package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
- package/src/resources/extensions/gsd/auto-start.ts +22 -22
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +51 -0
- package/src/resources/extensions/gsd/auto-verification.ts +12 -6
- package/src/resources/extensions/gsd/auto-worktree.ts +8 -0
- package/src/resources/extensions/gsd/auto.ts +424 -106
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +21 -6
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +12 -2
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +5 -8
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
- package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -1
- package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +4 -10
- package/src/resources/extensions/gsd/commands/handlers/parallel.ts +12 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
- package/src/resources/extensions/gsd/context-store.ts +120 -1
- package/src/resources/extensions/gsd/db-writer.ts +167 -84
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/doctor-git-checks.ts +44 -6
- package/src/resources/extensions/gsd/doctor-types.ts +2 -0
- package/src/resources/extensions/gsd/git-service.ts +2 -0
- package/src/resources/extensions/gsd/gsd-db.ts +7 -23
- package/src/resources/extensions/gsd/health-widget-core.ts +1 -1
- package/src/resources/extensions/gsd/health-widget.ts +6 -10
- package/src/resources/extensions/gsd/journal.ts +2 -0
- package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
- package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
- package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
- package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +10 -96
- package/src/resources/extensions/gsd/md-importer.ts +1 -1
- package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
- package/src/resources/extensions/gsd/migrate/command.ts +5 -0
- package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
- package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
- package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +14 -13
- package/src/resources/extensions/gsd/notification-overlay.ts +50 -46
- package/src/resources/extensions/gsd/parallel-merge.ts +61 -34
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +33 -35
- package/src/resources/extensions/gsd/prompts/complete-slice.md +14 -12
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
- package/src/resources/extensions/gsd/prompts/discuss.md +20 -2
- package/src/resources/extensions/gsd/prompts/system.md +2 -2
- package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
- package/src/resources/extensions/gsd/recovery-classification.ts +18 -1
- package/src/resources/extensions/gsd/session-lock.ts +41 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +172 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +337 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +69 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +109 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.ts +68 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +185 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +46 -0
- package/src/resources/extensions/gsd/state-reconciliation/errors.ts +67 -0
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +142 -0
- package/src/resources/extensions/gsd/state-reconciliation/registry.ts +27 -0
- package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +60 -0
- package/src/resources/extensions/gsd/state-reconciliation/types.ts +83 -0
- package/src/resources/extensions/gsd/state-reconciliation.ts +21 -53
- package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +729 -176
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +408 -4
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +291 -4
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +20 -5
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +28 -1
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
- package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
- package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +20 -2
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
- package/src/resources/extensions/gsd/tests/header-renderer.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +14 -4
- package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
- package/src/resources/extensions/gsd/tests/integration/integration-proof.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +116 -24
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
- package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
- package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +46 -11
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +78 -41
- package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +12 -217
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +38 -6
- package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +32 -1
- package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
- package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +65 -58
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +952 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +158 -58
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +572 -118
- package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +18 -0
- package/src/resources/extensions/gsd/tui/render-kit.ts +109 -0
- package/src/resources/extensions/gsd/watch/header-renderer.ts +121 -79
- package/src/resources/extensions/gsd/watch/splash-palette.ts +11 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +1151 -524
- package/src/resources/extensions/gsd/worktree-telemetry.ts +7 -2
- package/dist/web/standalone/.next/static/chunks/app/page-200592a7f3baf579.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/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +0 -1544
- /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → YEvjuT-fsFfYQhDSWtueS}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → YEvjuT-fsFfYQhDSWtueS}/_ssgManifest.js +0 -0
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
// File Purpose: Worktree Lifecycle Module — typed-result contract tests for enterMilestone (ADR-016).
|
|
3
3
|
import test from "node:test";
|
|
4
4
|
import assert from "node:assert/strict";
|
|
5
|
-
import { mkdtempSync, mkdirSync, rmSync } from "node:fs";
|
|
5
|
+
import { mkdtempSync, mkdirSync, rmSync, writeFileSync, realpathSync } from "node:fs";
|
|
6
6
|
import { tmpdir } from "node:os";
|
|
7
7
|
import { join } from "node:path";
|
|
8
|
+
import { execFileSync } from "node:child_process";
|
|
8
9
|
import {
|
|
9
10
|
WorktreeLifecycle,
|
|
11
|
+
resolvePausedResumeBasePath,
|
|
10
12
|
type WorktreeLifecycleDeps,
|
|
13
|
+
type WorktreeLifecycleTestOverrides,
|
|
11
14
|
type NotifyCtx,
|
|
12
15
|
} from "../worktree-lifecycle.js";
|
|
13
16
|
import { WorktreeStateProjection } from "../worktree-state-projection.js";
|
|
@@ -23,6 +26,12 @@ interface CallLog {
|
|
|
23
26
|
args: unknown[];
|
|
24
27
|
}
|
|
25
28
|
|
|
29
|
+
// The C1-C4-inlined primitive overrides come from
|
|
30
|
+
// `WorktreeLifecycleTestOverrides`, the test seam exported by the Module.
|
|
31
|
+
// Lifecycle reads these through `primitiveOverrides()` when present and
|
|
32
|
+
// falls back to direct imports otherwise.
|
|
33
|
+
type LegacyTestDeps = WorktreeLifecycleDeps & WorktreeLifecycleTestOverrides;
|
|
34
|
+
|
|
26
35
|
function makeSession(overrides?: Partial<AutoSession>): AutoSession {
|
|
27
36
|
const s = new AutoSession();
|
|
28
37
|
s.basePath = overrides?.basePath ?? "/project";
|
|
@@ -32,66 +41,80 @@ function makeSession(overrides?: Partial<AutoSession>): AutoSession {
|
|
|
32
41
|
}
|
|
33
42
|
|
|
34
43
|
function makeDeps(
|
|
35
|
-
overrides?: Partial<
|
|
36
|
-
):
|
|
44
|
+
overrides?: Partial<LegacyTestDeps>,
|
|
45
|
+
): LegacyTestDeps & { calls: CallLog[] } {
|
|
37
46
|
const calls: CallLog[] = [];
|
|
38
|
-
|
|
47
|
+
// ADR-016 phase 2 / C-track close-out: WorktreeLifecycleDeps is now a
|
|
48
|
+
// 3-field bag (gitServiceFactory, worktreeProjection, mergeMilestoneToMain).
|
|
49
|
+
// Tests still pass legacy override hooks via `LegacyTestDeps` — Lifecycle
|
|
50
|
+
// ignores the extras structurally and reads them through the C1-healing
|
|
51
|
+
// primitive-override pattern when stubs are needed.
|
|
52
|
+
const deps: LegacyTestDeps & { calls: CallLog[] } = {
|
|
39
53
|
calls,
|
|
40
|
-
|
|
41
|
-
calls.push({ fn: "
|
|
42
|
-
return
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
calls.push({ fn: "createAutoWorktree", args: [basePath, milestoneId] });
|
|
46
|
-
return `/project/.gsd/worktrees/${milestoneId}`;
|
|
47
|
-
},
|
|
48
|
-
enterBranchModeForMilestone: (basePath, milestoneId) => {
|
|
49
|
-
calls.push({
|
|
50
|
-
fn: "enterBranchModeForMilestone",
|
|
51
|
-
args: [basePath, milestoneId],
|
|
52
|
-
});
|
|
53
|
-
},
|
|
54
|
-
getAutoWorktreePath: (basePath, milestoneId) => {
|
|
55
|
-
calls.push({ fn: "getAutoWorktreePath", args: [basePath, milestoneId] });
|
|
56
|
-
return null;
|
|
57
|
-
},
|
|
58
|
-
getIsolationMode: () => {
|
|
59
|
-
calls.push({ fn: "getIsolationMode", args: [] });
|
|
60
|
-
return "worktree";
|
|
61
|
-
},
|
|
62
|
-
invalidateAllCaches: () => {
|
|
63
|
-
calls.push({ fn: "invalidateAllCaches", args: [] });
|
|
54
|
+
gitServiceFactory: (basePath: string) => {
|
|
55
|
+
calls.push({ fn: "gitServiceFactory", args: [basePath] });
|
|
56
|
+
return { basePath } as unknown as ReturnType<
|
|
57
|
+
WorktreeLifecycleDeps["gitServiceFactory"]
|
|
58
|
+
>;
|
|
64
59
|
},
|
|
65
|
-
GitServiceImpl: class MockGitService {
|
|
66
|
-
basePath: string;
|
|
67
|
-
gitConfig: unknown;
|
|
68
|
-
constructor(basePath: string, gitConfig: unknown) {
|
|
69
|
-
calls.push({ fn: "GitServiceImpl", args: [basePath, gitConfig] });
|
|
70
|
-
this.basePath = basePath;
|
|
71
|
-
this.gitConfig = gitConfig;
|
|
72
|
-
}
|
|
73
|
-
} as unknown as WorktreeLifecycleDeps["GitServiceImpl"],
|
|
74
|
-
loadEffectiveGSDPreferences: () => {
|
|
75
|
-
calls.push({ fn: "loadEffectiveGSDPreferences", args: [] });
|
|
76
|
-
return { preferences: { git: {} } };
|
|
77
|
-
},
|
|
78
|
-
// Slice 7 widened WorktreeLifecycleDeps with merge/exit-side fields.
|
|
79
|
-
// These tests focus on enter; merge-side helpers are no-op stubs.
|
|
80
60
|
worktreeProjection: new WorktreeStateProjection(),
|
|
61
|
+
// Legacy stubs — Lifecycle no longer reads these post-C2; preserved as
|
|
62
|
+
// no-ops so existing test fixtures keep type-checking.
|
|
81
63
|
isInAutoWorktree: () => false,
|
|
82
|
-
autoCommitCurrentBranch: (
|
|
64
|
+
autoCommitCurrentBranch: (
|
|
65
|
+
basePath: string,
|
|
66
|
+
unitType: string,
|
|
67
|
+
unitId: string,
|
|
68
|
+
taskContext?: unknown,
|
|
69
|
+
) => {
|
|
70
|
+
calls.push({ fn: "autoCommitCurrentBranch", args: [basePath, unitType, unitId, taskContext] });
|
|
71
|
+
return null;
|
|
72
|
+
},
|
|
83
73
|
autoWorktreeBranch: (mid: string) => `milestone/${mid}`,
|
|
84
74
|
teardownAutoWorktree: () => {},
|
|
85
75
|
mergeMilestoneToMain: () => ({ pushed: false, codeFilesChanged: true }),
|
|
86
|
-
getCurrentBranch: () => "main",
|
|
87
|
-
checkoutBranch: () => {},
|
|
88
|
-
resolveMilestoneFile: () => null,
|
|
89
|
-
readFileSync: () => "",
|
|
90
76
|
...overrides,
|
|
91
77
|
};
|
|
92
78
|
return deps;
|
|
93
79
|
}
|
|
94
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Create a real temporary git repo for tests that exercise the inlined
|
|
83
|
+
* worktree-manager primitives (post-C2). Returns the realpath of the new
|
|
84
|
+
* repo. Tests that previously relied on `deps.createAutoWorktree`,
|
|
85
|
+
* `deps.enterAutoWorktree`, etc. now drive Lifecycle through these
|
|
86
|
+
* fixtures.
|
|
87
|
+
*/
|
|
88
|
+
function makeGitRepoBase(opts?: {
|
|
89
|
+
isolation?: "worktree" | "branch" | "none";
|
|
90
|
+
}): string {
|
|
91
|
+
const base = realpathSync(mkdtempSync(join(tmpdir(), "gsd-lifecycle-git-")));
|
|
92
|
+
const git = (args: string[]): void => {
|
|
93
|
+
execFileSync("git", args, { cwd: base, stdio: "pipe" });
|
|
94
|
+
};
|
|
95
|
+
git(["init", "-b", "main"]);
|
|
96
|
+
git(["config", "user.email", "test@test.com"]);
|
|
97
|
+
git(["config", "user.name", "Test"]);
|
|
98
|
+
writeFileSync(join(base, "README.md"), "# test\n");
|
|
99
|
+
writeFileSync(join(base, ".gitignore"), ".gsd/worktrees/\n");
|
|
100
|
+
mkdirSync(join(base, ".gsd"), { recursive: true });
|
|
101
|
+
if (opts?.isolation && opts.isolation !== "none") {
|
|
102
|
+
writeFileSync(
|
|
103
|
+
join(base, ".gsd", "preferences.md"),
|
|
104
|
+
`## Git\n- isolation: ${opts.isolation}\n`,
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
git(["add", "."]);
|
|
108
|
+
git(["commit", "-m", "init"]);
|
|
109
|
+
return base;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function cleanupRepoBase(base: string, previousCwd?: string): void {
|
|
113
|
+
try { closeDatabase(); } catch { /* noop */ }
|
|
114
|
+
try { if (previousCwd) process.chdir(previousCwd); } catch { /* noop */ }
|
|
115
|
+
try { rmSync(base, { recursive: true, force: true }); } catch { /* noop */ }
|
|
116
|
+
}
|
|
117
|
+
|
|
95
118
|
function makeCtx(): NotifyCtx & {
|
|
96
119
|
messages: Array<{ msg: string; level?: string }>;
|
|
97
120
|
} {
|
|
@@ -117,41 +140,59 @@ function cleanupDbBase(base: string): void {
|
|
|
117
140
|
|
|
118
141
|
// ─── enterMilestone — typed-result contract ──────────────────────────────────
|
|
119
142
|
|
|
120
|
-
test("enterMilestone returns ok:true mode:worktree on successful create", () => {
|
|
121
|
-
|
|
143
|
+
test("enterMilestone returns ok:true mode:worktree on successful create", (t) => {
|
|
144
|
+
// ADR-016 phase 2 / C2 (#5625): the worktree-manager primitives are
|
|
145
|
+
// inlined, so the success path needs a real git repo. The test exercises
|
|
146
|
+
// Lifecycle.enterMilestone end-to-end against `createAutoWorktree`'s
|
|
147
|
+
// real implementation in `auto-worktree.ts`.
|
|
148
|
+
const previousCwd = process.cwd();
|
|
149
|
+
const base = makeGitRepoBase({ isolation: "worktree" });
|
|
150
|
+
t.after(() => cleanupRepoBase(base, previousCwd));
|
|
151
|
+
|
|
152
|
+
const s = makeSession({ basePath: base, originalBasePath: base });
|
|
122
153
|
const deps = makeDeps();
|
|
123
154
|
const ctx = makeCtx();
|
|
124
155
|
const lifecycle = new WorktreeLifecycle(s, deps);
|
|
125
156
|
|
|
126
157
|
const result = lifecycle.enterMilestone("M001", ctx);
|
|
127
158
|
|
|
128
|
-
assert.equal(result.ok, true);
|
|
159
|
+
assert.equal(result.ok, true, `expected ok:true, got: ${JSON.stringify(result)}`);
|
|
129
160
|
if (result.ok) {
|
|
130
161
|
assert.equal(result.mode, "worktree");
|
|
131
|
-
assert.
|
|
162
|
+
assert.ok(
|
|
163
|
+
result.path.endsWith("/.gsd/worktrees/M001"),
|
|
164
|
+
`expected path to end with /.gsd/worktrees/M001, got ${result.path}`,
|
|
165
|
+
);
|
|
132
166
|
}
|
|
133
|
-
assert.
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
1,
|
|
167
|
+
assert.ok(
|
|
168
|
+
s.basePath.endsWith("/.gsd/worktrees/M001"),
|
|
169
|
+
`expected s.basePath to end with /.gsd/worktrees/M001, got ${s.basePath}`,
|
|
137
170
|
);
|
|
171
|
+
// After C3 (#5626) `invalidateAllCaches` is inlined; assertion against
|
|
172
|
+
// `deps.calls` for cache invalidation is no longer possible.
|
|
138
173
|
});
|
|
139
174
|
|
|
140
|
-
test("enterMilestone returns ok:true mode:branch on successful branch fallback", () => {
|
|
141
|
-
|
|
175
|
+
test("enterMilestone returns ok:true mode:branch on successful branch fallback", (t) => {
|
|
176
|
+
// Real fixture with isolation:branch — `enterBranchModeForMilestone`'s
|
|
177
|
+
// real implementation runs against the temp repo.
|
|
178
|
+
const previousCwd = process.cwd();
|
|
179
|
+
const base = makeGitRepoBase({ isolation: "branch" });
|
|
180
|
+
t.after(() => cleanupRepoBase(base, previousCwd));
|
|
181
|
+
|
|
182
|
+
const s = makeSession({ basePath: base, originalBasePath: base });
|
|
142
183
|
const deps = makeDeps({ getIsolationMode: () => "branch" });
|
|
143
184
|
const ctx = makeCtx();
|
|
144
185
|
const lifecycle = new WorktreeLifecycle(s, deps);
|
|
145
186
|
|
|
146
187
|
const result = lifecycle.enterMilestone("M001", ctx);
|
|
147
188
|
|
|
148
|
-
assert.equal(result.ok, true);
|
|
189
|
+
assert.equal(result.ok, true, `expected ok:true, got: ${JSON.stringify(result)}`);
|
|
149
190
|
if (result.ok) {
|
|
150
191
|
assert.equal(result.mode, "branch");
|
|
151
|
-
assert.equal(result.path,
|
|
192
|
+
assert.equal(result.path, base);
|
|
152
193
|
}
|
|
153
194
|
// Branch mode does not mutate s.basePath
|
|
154
|
-
assert.equal(s.basePath,
|
|
195
|
+
assert.equal(s.basePath, base);
|
|
155
196
|
});
|
|
156
197
|
|
|
157
198
|
test("enterMilestone returns ok:true mode:none when isolation disabled", () => {
|
|
@@ -182,66 +223,92 @@ test("enterMilestone returns ok:false reason:isolation-degraded when session deg
|
|
|
182
223
|
if (!result.ok) {
|
|
183
224
|
assert.equal(result.reason, "isolation-degraded");
|
|
184
225
|
}
|
|
185
|
-
|
|
186
|
-
assert.equal(
|
|
187
|
-
assert.equal(deps.calls.filter((c) => c.fn === "
|
|
226
|
+
assert.equal(s.basePath, "/project");
|
|
227
|
+
assert.equal(s.milestoneLeaseToken, null);
|
|
228
|
+
assert.equal(deps.calls.filter((c) => c.fn === "getIsolationMode").length, 0);
|
|
188
229
|
});
|
|
189
230
|
|
|
190
|
-
test("enterMilestone returns ok:false reason:creation-failed and degrades session on worktree throw", () => {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
});
|
|
231
|
+
test("enterMilestone returns ok:false reason:creation-failed and degrades session on worktree throw", (t) => {
|
|
232
|
+
// After C2 the worktree-manager primitives are inlined. Use a real
|
|
233
|
+
// fixture and break the repo by deleting `.git` so any git op throws.
|
|
234
|
+
const previousCwd = process.cwd();
|
|
235
|
+
const base = makeGitRepoBase({ isolation: "worktree" });
|
|
236
|
+
t.after(() => cleanupRepoBase(base, previousCwd));
|
|
237
|
+
rmSync(join(base, ".git"), { recursive: true, force: true });
|
|
238
|
+
|
|
239
|
+
const s = makeSession({ basePath: base, originalBasePath: base });
|
|
240
|
+
const deps = makeDeps();
|
|
197
241
|
const ctx = makeCtx();
|
|
198
242
|
const lifecycle = new WorktreeLifecycle(s, deps);
|
|
199
243
|
|
|
200
244
|
const result = lifecycle.enterMilestone("M001", ctx);
|
|
201
245
|
|
|
202
|
-
assert.equal(result.ok, false);
|
|
246
|
+
assert.equal(result.ok, false, `expected ok:false, got: ${JSON.stringify(result)}`);
|
|
203
247
|
if (!result.ok) {
|
|
204
248
|
assert.equal(result.reason, "creation-failed");
|
|
205
249
|
assert.ok(result.cause instanceof Error);
|
|
206
250
|
}
|
|
207
251
|
assert.equal(s.isolationDegraded, true);
|
|
208
252
|
// s.basePath unchanged on failure
|
|
209
|
-
assert.equal(s.basePath,
|
|
253
|
+
assert.equal(s.basePath, base);
|
|
210
254
|
});
|
|
211
255
|
|
|
212
|
-
test("enterMilestone returns ok:false reason:creation-failed when branch mode throws", () => {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
256
|
+
test("enterMilestone returns ok:false reason:creation-failed when branch mode throws", (t) => {
|
|
257
|
+
// Branch-mode failure scenario: real fixture with isolation:branch, but
|
|
258
|
+
// delete the `.git` directory so any branch operation throws.
|
|
259
|
+
const previousCwd = process.cwd();
|
|
260
|
+
const base = makeGitRepoBase({ isolation: "branch" });
|
|
261
|
+
t.after(() => cleanupRepoBase(base, previousCwd));
|
|
262
|
+
rmSync(join(base, ".git"), { recursive: true, force: true });
|
|
263
|
+
|
|
264
|
+
const s = makeSession({ basePath: base, originalBasePath: base });
|
|
265
|
+
const deps = makeDeps({ getIsolationMode: () => "branch" });
|
|
220
266
|
const ctx = makeCtx();
|
|
221
267
|
const lifecycle = new WorktreeLifecycle(s, deps);
|
|
222
268
|
|
|
223
269
|
const result = lifecycle.enterMilestone("M001", ctx);
|
|
224
270
|
|
|
225
|
-
assert.equal(result.ok, false);
|
|
271
|
+
assert.equal(result.ok, false, `expected ok:false, got: ${JSON.stringify(result)}`);
|
|
226
272
|
if (!result.ok) {
|
|
227
273
|
assert.equal(result.reason, "creation-failed");
|
|
228
274
|
}
|
|
229
275
|
assert.equal(s.isolationDegraded, true);
|
|
230
276
|
});
|
|
231
277
|
|
|
232
|
-
test("enterMilestone enters existing worktree when path resolves", () => {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
278
|
+
test("enterMilestone enters existing worktree when path resolves", (t) => {
|
|
279
|
+
// After C2, `getAutoWorktreePath` runs against real git. To exercise the
|
|
280
|
+
// "existing worktree" branch we pre-create the worktree on disk so
|
|
281
|
+
// git's worktree list includes it.
|
|
282
|
+
const previousCwd = process.cwd();
|
|
283
|
+
const base = makeGitRepoBase({ isolation: "worktree" });
|
|
284
|
+
t.after(() => cleanupRepoBase(base, previousCwd));
|
|
285
|
+
const wt = join(base, ".gsd", "worktrees", "M001");
|
|
286
|
+
execFileSync("git", ["checkout", "-b", "milestone/M001"], {
|
|
287
|
+
cwd: base,
|
|
288
|
+
stdio: "pipe",
|
|
236
289
|
});
|
|
290
|
+
execFileSync("git", ["checkout", "main"], { cwd: base, stdio: "pipe" });
|
|
291
|
+
execFileSync(
|
|
292
|
+
"git",
|
|
293
|
+
["worktree", "add", wt, "milestone/M001"],
|
|
294
|
+
{ cwd: base, stdio: "pipe" },
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
const s = makeSession({ basePath: base, originalBasePath: base });
|
|
298
|
+
const deps = makeDeps();
|
|
237
299
|
const ctx = makeCtx();
|
|
238
300
|
const lifecycle = new WorktreeLifecycle(s, deps);
|
|
239
301
|
|
|
240
302
|
const result = lifecycle.enterMilestone("M001", ctx);
|
|
241
303
|
|
|
242
|
-
assert.equal(result.ok, true);
|
|
243
|
-
|
|
244
|
-
|
|
304
|
+
assert.equal(result.ok, true, `expected ok:true, got: ${JSON.stringify(result)}`);
|
|
305
|
+
if (result.ok) {
|
|
306
|
+
assert.equal(result.mode, "worktree");
|
|
307
|
+
assert.ok(
|
|
308
|
+
result.path.endsWith("/.gsd/worktrees/M001"),
|
|
309
|
+
`expected path to end with /.gsd/worktrees/M001, got ${result.path}`,
|
|
310
|
+
);
|
|
311
|
+
}
|
|
245
312
|
});
|
|
246
313
|
|
|
247
314
|
test("enterMilestone returns ok:false reason:lease-conflict when another worker holds the lease", (t) => {
|
|
@@ -266,14 +333,26 @@ test("enterMilestone returns ok:false reason:lease-conflict when another worker
|
|
|
266
333
|
assert.equal(result.reason, "lease-conflict");
|
|
267
334
|
}
|
|
268
335
|
assert.equal(s.isolationDegraded, false);
|
|
269
|
-
assert.equal(
|
|
270
|
-
assert.equal(
|
|
336
|
+
assert.equal(s.basePath, base);
|
|
337
|
+
assert.equal(s.milestoneLeaseToken, null);
|
|
338
|
+
assert.equal(deps.calls.filter((c) => c.fn === "getIsolationMode").length, 0);
|
|
339
|
+
assert.equal(ctx.messages.length, 1);
|
|
340
|
+
assert.equal(ctx.messages[0]?.level, "error");
|
|
271
341
|
});
|
|
272
342
|
|
|
273
|
-
test("enterMilestone is idempotent when already in the milestone worktree", () => {
|
|
343
|
+
test("enterMilestone is idempotent when already in the milestone worktree", (t) => {
|
|
344
|
+
// Real-fixture variant after C2/C3. The session is already pointing at
|
|
345
|
+
// the worktree path with currentMilestoneId set, so the idempotency
|
|
346
|
+
// early-return inside `_enterMilestoneCore` fires without invoking the
|
|
347
|
+
// inlined worktree primitives.
|
|
348
|
+
const previousCwd = process.cwd();
|
|
349
|
+
const base = makeGitRepoBase({ isolation: "worktree" });
|
|
350
|
+
t.after(() => cleanupRepoBase(base, previousCwd));
|
|
351
|
+
const wt = join(base, ".gsd", "worktrees", "M001");
|
|
352
|
+
|
|
274
353
|
const s = makeSession({
|
|
275
|
-
basePath:
|
|
276
|
-
originalBasePath:
|
|
354
|
+
basePath: wt,
|
|
355
|
+
originalBasePath: base,
|
|
277
356
|
currentMilestoneId: "M001",
|
|
278
357
|
});
|
|
279
358
|
const deps = makeDeps();
|
|
@@ -282,14 +361,12 @@ test("enterMilestone is idempotent when already in the milestone worktree", () =
|
|
|
282
361
|
|
|
283
362
|
const result = lifecycle.enterMilestone("M001", ctx);
|
|
284
363
|
|
|
285
|
-
assert.equal(result.ok, true);
|
|
364
|
+
assert.equal(result.ok, true, `expected ok:true, got: ${JSON.stringify(result)}`);
|
|
286
365
|
if (result.ok) {
|
|
287
366
|
assert.equal(result.mode, "worktree");
|
|
288
|
-
assert.equal(result.path,
|
|
367
|
+
assert.equal(result.path, wt);
|
|
289
368
|
}
|
|
290
|
-
assert.equal(s.basePath,
|
|
291
|
-
assert.equal(deps.calls.filter((c) => c.fn === "createAutoWorktree").length, 0);
|
|
292
|
-
assert.equal(deps.calls.filter((c) => c.fn === "enterAutoWorktree").length, 0);
|
|
369
|
+
assert.equal(s.basePath, wt);
|
|
293
370
|
});
|
|
294
371
|
|
|
295
372
|
test("enterMilestone returns ok:false reason:invalid-milestone-id on path traversal", () => {
|
|
@@ -353,8 +430,15 @@ test("getCurrentMilestoneIfAny returns the active milestone id or null", () => {
|
|
|
353
430
|
|
|
354
431
|
// ─── degradeToBranchMode (issue #5587) ────────────────────────────────────────
|
|
355
432
|
|
|
356
|
-
test("degradeToBranchMode sets isolationDegraded and
|
|
357
|
-
|
|
433
|
+
test("degradeToBranchMode sets isolationDegraded and runs branch-mode setup", (t) => {
|
|
434
|
+
// After C2, `enterBranchModeForMilestone` runs against real git. Use a
|
|
435
|
+
// real fixture so the branch checkout succeeds and we can observe the
|
|
436
|
+
// session's isolationDegraded flag flip.
|
|
437
|
+
const previousCwd = process.cwd();
|
|
438
|
+
const base = makeGitRepoBase({ isolation: "branch" });
|
|
439
|
+
t.after(() => cleanupRepoBase(base, previousCwd));
|
|
440
|
+
|
|
441
|
+
const s = makeSession({ basePath: base, originalBasePath: base });
|
|
358
442
|
const deps = makeDeps();
|
|
359
443
|
const ctx = makeCtx();
|
|
360
444
|
const lifecycle = new WorktreeLifecycle(s, deps);
|
|
@@ -362,11 +446,7 @@ test("degradeToBranchMode sets isolationDegraded and invokes branch-mode helper"
|
|
|
362
446
|
lifecycle.degradeToBranchMode("M001", ctx);
|
|
363
447
|
|
|
364
448
|
assert.equal(s.isolationDegraded, true);
|
|
365
|
-
|
|
366
|
-
deps.calls.filter((c) => c.fn === "enterBranchModeForMilestone").length,
|
|
367
|
-
1,
|
|
368
|
-
);
|
|
369
|
-
assert.equal(deps.calls.filter((c) => c.fn === "invalidateAllCaches").length, 1);
|
|
449
|
+
// After C3 (#5626) `invalidateAllCaches` is inlined.
|
|
370
450
|
});
|
|
371
451
|
|
|
372
452
|
test("degradeToBranchMode is no-op when isolationDegraded is already true", () => {
|
|
@@ -378,19 +458,20 @@ test("degradeToBranchMode is no-op when isolationDegraded is already true", () =
|
|
|
378
458
|
|
|
379
459
|
lifecycle.degradeToBranchMode("M001", ctx);
|
|
380
460
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
461
|
+
// Pre-check returns early before any side effect. After C3 the
|
|
462
|
+
// `invalidateAllCaches` mock is gone; we assert the observable
|
|
463
|
+
// contract: `s.isolationDegraded` stays true and no notify message
|
|
464
|
+
// is emitted.
|
|
465
|
+
assert.equal(s.isolationDegraded, true);
|
|
466
|
+
assert.equal(ctx.messages.length, 0);
|
|
385
467
|
});
|
|
386
468
|
|
|
387
469
|
test("degradeToBranchMode marks degraded and notifies on branch-mode failure", () => {
|
|
470
|
+
// Synthetic /project causes the real `enterBranchModeForMilestone` to
|
|
471
|
+
// throw — same shape as the original mock-throws test but exercises the
|
|
472
|
+
// production error path against the inlined helper.
|
|
388
473
|
const s = makeSession();
|
|
389
|
-
const deps = makeDeps({
|
|
390
|
-
enterBranchModeForMilestone: () => {
|
|
391
|
-
throw new Error("checkout failed");
|
|
392
|
-
},
|
|
393
|
-
});
|
|
474
|
+
const deps = makeDeps({});
|
|
394
475
|
const ctx = makeCtx();
|
|
395
476
|
const lifecycle = new WorktreeLifecycle(s, deps);
|
|
396
477
|
|
|
@@ -416,8 +497,32 @@ test("restoreToProjectRoot restores basePath to originalBasePath and rebuilds gi
|
|
|
416
497
|
lifecycle.restoreToProjectRoot();
|
|
417
498
|
|
|
418
499
|
assert.equal(s.basePath, "/project");
|
|
419
|
-
|
|
420
|
-
|
|
500
|
+
// After C4 (#5627) the rebuild goes through `gitServiceFactory`
|
|
501
|
+
// instead of `new GitServiceImpl(...)`. `invalidateAllCaches` is
|
|
502
|
+
// inlined post-C3 and no longer routes through deps.
|
|
503
|
+
assert.equal(
|
|
504
|
+
deps.calls.filter((c) => c.fn === "gitServiceFactory").length,
|
|
505
|
+
1,
|
|
506
|
+
);
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
test("restoreToProjectRoot rebuilds git service via gitServiceFactory at the restored base path", () => {
|
|
510
|
+
// ADR-016 phase 2 / C4 (#5627): the gitConfig load + GitServiceImpl
|
|
511
|
+
// construction now live behind the `gitServiceFactory` seam. Lifecycle
|
|
512
|
+
// is no longer responsible for either; the test asserts only that the
|
|
513
|
+
// factory is invoked with the restored basePath.
|
|
514
|
+
const s = makeSession();
|
|
515
|
+
s.originalBasePath = "/project";
|
|
516
|
+
s.basePath = "/project/.gsd/worktrees/M001";
|
|
517
|
+
const deps = makeDeps();
|
|
518
|
+
const lifecycle = new WorktreeLifecycle(s, deps);
|
|
519
|
+
|
|
520
|
+
lifecycle.restoreToProjectRoot();
|
|
521
|
+
|
|
522
|
+
assert.deepEqual(
|
|
523
|
+
deps.calls.find((c) => c.fn === "gitServiceFactory")?.args,
|
|
524
|
+
["/project"],
|
|
525
|
+
);
|
|
421
526
|
});
|
|
422
527
|
|
|
423
528
|
test("restoreToProjectRoot is no-op when originalBasePath is empty", () => {
|
|
@@ -430,5 +535,354 @@ test("restoreToProjectRoot is no-op when originalBasePath is empty", () => {
|
|
|
430
535
|
lifecycle.restoreToProjectRoot();
|
|
431
536
|
|
|
432
537
|
assert.equal(s.basePath, "/some/path"); // unchanged
|
|
433
|
-
assert.equal(deps.calls.filter((c) => c.fn === "
|
|
538
|
+
assert.equal(deps.calls.filter((c) => c.fn === "gitServiceFactory").length, 0);
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
// ─── adoptSessionRoot (ADR-016 phase 2 / B2, issue #5620) ─────────────────────
|
|
542
|
+
|
|
543
|
+
test("adoptSessionRoot sets basePath and seeds originalBasePath on a fresh session", () => {
|
|
544
|
+
const s = makeSession();
|
|
545
|
+
s.basePath = "";
|
|
546
|
+
s.originalBasePath = "";
|
|
547
|
+
const lifecycle = new WorktreeLifecycle(s, makeDeps());
|
|
548
|
+
|
|
549
|
+
lifecycle.adoptSessionRoot("/project");
|
|
550
|
+
|
|
551
|
+
assert.equal(s.basePath, "/project");
|
|
552
|
+
assert.equal(s.originalBasePath, "/project");
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
test("adoptSessionRoot preserves a pre-existing originalBasePath when no override is passed", () => {
|
|
556
|
+
// Resume-from-paused path (auto.ts:2148 after meta-restore at 2003/2055):
|
|
557
|
+
// s.originalBasePath was already restored from paused metadata; the verb
|
|
558
|
+
// must NOT overwrite that value.
|
|
559
|
+
const s = makeSession();
|
|
560
|
+
s.basePath = "";
|
|
561
|
+
s.originalBasePath = "/persisted/project-root";
|
|
562
|
+
const lifecycle = new WorktreeLifecycle(s, makeDeps());
|
|
563
|
+
|
|
564
|
+
lifecycle.adoptSessionRoot("/project");
|
|
565
|
+
|
|
566
|
+
assert.equal(s.basePath, "/project");
|
|
567
|
+
assert.equal(s.originalBasePath, "/persisted/project-root");
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
test("adoptSessionRoot honors an explicit originalBase override", () => {
|
|
571
|
+
const s = makeSession();
|
|
572
|
+
s.basePath = "";
|
|
573
|
+
s.originalBasePath = "/old-root";
|
|
574
|
+
const lifecycle = new WorktreeLifecycle(s, makeDeps());
|
|
575
|
+
|
|
576
|
+
lifecycle.adoptSessionRoot("/project", "/explicit-original");
|
|
577
|
+
|
|
578
|
+
assert.equal(s.basePath, "/project");
|
|
579
|
+
assert.equal(s.originalBasePath, "/explicit-original");
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
test("adoptSessionRoot does not chdir, rebuild git service, or invalidate caches", () => {
|
|
583
|
+
// The verb is a pure session-state mutation. Side effects (chdir, git
|
|
584
|
+
// service rebuild, cache invalidation) belong to other Lifecycle verbs
|
|
585
|
+
// (`enterMilestone`, `restoreToProjectRoot`).
|
|
586
|
+
const s = makeSession();
|
|
587
|
+
s.basePath = "";
|
|
588
|
+
s.originalBasePath = "";
|
|
589
|
+
const deps = makeDeps();
|
|
590
|
+
const lifecycle = new WorktreeLifecycle(s, deps);
|
|
591
|
+
|
|
592
|
+
lifecycle.adoptSessionRoot("/project");
|
|
593
|
+
|
|
594
|
+
assert.equal(deps.calls.filter((c) => c.fn === "gitServiceFactory").length, 0);
|
|
595
|
+
assert.equal(deps.calls.filter((c) => c.fn === "invalidateAllCaches").length, 0);
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
// ─── resumeFromPausedSession (ADR-016 phase 2 / B3, issue #5621) ──────────────
|
|
599
|
+
|
|
600
|
+
test("resumeFromPausedSession adopts the persisted worktree path when it exists", (t) => {
|
|
601
|
+
// Use a real temp directory so the existsSync check inside the verb
|
|
602
|
+
// succeeds. Earlier `process.cwd()` ran into ENOENT after sibling tests
|
|
603
|
+
// deleted their basePaths and left cwd dangling.
|
|
604
|
+
const wtDir = realpathSync(mkdtempSync(join(tmpdir(), "gsd-resume-test-")));
|
|
605
|
+
t.after(() => { try { rmSync(wtDir, { recursive: true, force: true }); } catch { /* */ } });
|
|
606
|
+
|
|
607
|
+
const s = makeSession();
|
|
608
|
+
s.basePath = "/some/old/path";
|
|
609
|
+
const lifecycle = new WorktreeLifecycle(s, makeDeps());
|
|
610
|
+
|
|
611
|
+
// Verify the pure helper's contract first (folded in from the legacy
|
|
612
|
+
// _resolvePausedResumeBasePathForTest)
|
|
613
|
+
assert.equal(
|
|
614
|
+
resolvePausedResumeBasePath("/project", "/persisted/worktree/M001", () => true),
|
|
615
|
+
"/persisted/worktree/M001",
|
|
616
|
+
);
|
|
617
|
+
|
|
618
|
+
// Exercise the verb with a real path that exists.
|
|
619
|
+
lifecycle.resumeFromPausedSession("/project", wtDir);
|
|
620
|
+
assert.equal(s.basePath, wtDir);
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
test("resumeFromPausedSession falls back to base when persisted worktree is null", () => {
|
|
624
|
+
const s = makeSession();
|
|
625
|
+
s.basePath = "/old";
|
|
626
|
+
const lifecycle = new WorktreeLifecycle(s, makeDeps());
|
|
627
|
+
|
|
628
|
+
lifecycle.resumeFromPausedSession("/project", null);
|
|
629
|
+
assert.equal(s.basePath, "/project");
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
test("resumeFromPausedSession falls back to base when persisted worktree does not exist", () => {
|
|
633
|
+
const s = makeSession();
|
|
634
|
+
s.basePath = "/old";
|
|
635
|
+
const lifecycle = new WorktreeLifecycle(s, makeDeps());
|
|
636
|
+
|
|
637
|
+
lifecycle.resumeFromPausedSession(
|
|
638
|
+
"/project",
|
|
639
|
+
"/this/path/does/not/exist/abc/xyz",
|
|
640
|
+
);
|
|
641
|
+
assert.equal(s.basePath, "/project");
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
test("resumeFromPausedSession does not chdir, rebuild git service, or invalidate caches", () => {
|
|
645
|
+
const s = makeSession();
|
|
646
|
+
const deps = makeDeps();
|
|
647
|
+
const lifecycle = new WorktreeLifecycle(s, deps);
|
|
648
|
+
|
|
649
|
+
lifecycle.resumeFromPausedSession("/project", null);
|
|
650
|
+
|
|
651
|
+
assert.equal(deps.calls.filter((c) => c.fn === "gitServiceFactory").length, 0);
|
|
652
|
+
assert.equal(deps.calls.filter((c) => c.fn === "invalidateAllCaches").length, 0);
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
// ─── adoptOrphanWorktree (ADR-016 phase 2 / B4, issue #5622) ──────────────────
|
|
656
|
+
|
|
657
|
+
// After C2 (#5625) the `getAutoWorktreePath` primitive is inlined, so these
|
|
658
|
+
// tests use a real-git fixture with a pre-created worktree to exercise the
|
|
659
|
+
// swap-run-revert protocol. The "fall back when getAutoWorktreePath returns
|
|
660
|
+
// null" test uses a fixture WITHOUT a worktree so the real call returns null.
|
|
661
|
+
|
|
662
|
+
test("adoptOrphanWorktree swaps to worktree path and reverts to base on !merged", (t) => {
|
|
663
|
+
const previousCwd = process.cwd();
|
|
664
|
+
const base = makeGitRepoBase({ isolation: "worktree" });
|
|
665
|
+
t.after(() => cleanupRepoBase(base, previousCwd));
|
|
666
|
+
const wt = join(base, ".gsd", "worktrees", "M001");
|
|
667
|
+
execFileSync("git", ["checkout", "-b", "milestone/M001"], { cwd: base, stdio: "pipe" });
|
|
668
|
+
execFileSync("git", ["checkout", "main"], { cwd: base, stdio: "pipe" });
|
|
669
|
+
execFileSync("git", ["worktree", "add", wt, "milestone/M001"], { cwd: base, stdio: "pipe" });
|
|
670
|
+
|
|
671
|
+
const s = makeSession();
|
|
672
|
+
s.basePath = "/old";
|
|
673
|
+
s.originalBasePath = "/old";
|
|
674
|
+
s.active = true;
|
|
675
|
+
const lifecycle = new WorktreeLifecycle(s, makeDeps());
|
|
676
|
+
|
|
677
|
+
let basePathInsideCallback = "";
|
|
678
|
+
const result = lifecycle.adoptOrphanWorktree("M001", base, () => {
|
|
679
|
+
basePathInsideCallback = s.basePath;
|
|
680
|
+
return { merged: false as const, reason: "synthetic" };
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
assert.equal(basePathInsideCallback, wt);
|
|
684
|
+
assert.equal(s.basePath, base);
|
|
685
|
+
assert.equal(s.originalBasePath, base);
|
|
686
|
+
assert.equal(result.merged, false);
|
|
687
|
+
});
|
|
688
|
+
|
|
689
|
+
test("adoptOrphanWorktree holds the swap on merged && active", (t) => {
|
|
690
|
+
const previousCwd = process.cwd();
|
|
691
|
+
const base = makeGitRepoBase({ isolation: "worktree" });
|
|
692
|
+
t.after(() => cleanupRepoBase(base, previousCwd));
|
|
693
|
+
const wt = join(base, ".gsd", "worktrees", "M001");
|
|
694
|
+
execFileSync("git", ["checkout", "-b", "milestone/M001"], { cwd: base, stdio: "pipe" });
|
|
695
|
+
execFileSync("git", ["checkout", "main"], { cwd: base, stdio: "pipe" });
|
|
696
|
+
execFileSync("git", ["worktree", "add", wt, "milestone/M001"], { cwd: base, stdio: "pipe" });
|
|
697
|
+
|
|
698
|
+
const s = makeSession();
|
|
699
|
+
s.basePath = "/old";
|
|
700
|
+
s.originalBasePath = "/old";
|
|
701
|
+
s.active = true;
|
|
702
|
+
const lifecycle = new WorktreeLifecycle(s, makeDeps());
|
|
703
|
+
|
|
704
|
+
lifecycle.adoptOrphanWorktree("M001", base, () => ({
|
|
705
|
+
merged: true as const,
|
|
706
|
+
}));
|
|
707
|
+
|
|
708
|
+
assert.equal(s.basePath, wt);
|
|
709
|
+
assert.equal(s.originalBasePath, base);
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
test("adoptOrphanWorktree restores prior paths on merged && !active", (t) => {
|
|
713
|
+
const previousCwd = process.cwd();
|
|
714
|
+
const base = makeGitRepoBase({ isolation: "worktree" });
|
|
715
|
+
t.after(() => cleanupRepoBase(base, previousCwd));
|
|
716
|
+
const wt = join(base, ".gsd", "worktrees", "M001");
|
|
717
|
+
execFileSync("git", ["checkout", "-b", "milestone/M001"], { cwd: base, stdio: "pipe" });
|
|
718
|
+
execFileSync("git", ["checkout", "main"], { cwd: base, stdio: "pipe" });
|
|
719
|
+
execFileSync("git", ["worktree", "add", wt, "milestone/M001"], { cwd: base, stdio: "pipe" });
|
|
720
|
+
|
|
721
|
+
const s = makeSession();
|
|
722
|
+
s.basePath = "/prior";
|
|
723
|
+
s.originalBasePath = "/prior-original";
|
|
724
|
+
s.active = false;
|
|
725
|
+
const lifecycle = new WorktreeLifecycle(s, makeDeps());
|
|
726
|
+
|
|
727
|
+
lifecycle.adoptOrphanWorktree("M001", base, () => ({
|
|
728
|
+
merged: true as const,
|
|
729
|
+
}));
|
|
730
|
+
|
|
731
|
+
assert.equal(s.basePath, "/prior");
|
|
732
|
+
assert.equal(s.originalBasePath, "/prior-original");
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
test("adoptOrphanWorktree falls back to base when getAutoWorktreePath returns null", (t) => {
|
|
736
|
+
// Real fixture with isolation:worktree but NO worktree pre-created — the
|
|
737
|
+
// real `getAutoWorktreePath` returns null so the verb falls back to base.
|
|
738
|
+
const previousCwd = process.cwd();
|
|
739
|
+
const base = makeGitRepoBase({ isolation: "worktree" });
|
|
740
|
+
t.after(() => cleanupRepoBase(base, previousCwd));
|
|
741
|
+
|
|
742
|
+
const s = makeSession();
|
|
743
|
+
s.basePath = "/old";
|
|
744
|
+
s.active = true;
|
|
745
|
+
const lifecycle = new WorktreeLifecycle(s, makeDeps());
|
|
746
|
+
|
|
747
|
+
let basePathInsideCallback = "";
|
|
748
|
+
lifecycle.adoptOrphanWorktree("M001", base, () => {
|
|
749
|
+
basePathInsideCallback = s.basePath;
|
|
750
|
+
return { merged: true as const };
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
assert.equal(basePathInsideCallback, base);
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
test("adoptOrphanWorktree restores prior paths and cwd when the callback throws", () => {
|
|
757
|
+
const originalCwd = process.cwd();
|
|
758
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-orphan-rollback-base-"));
|
|
759
|
+
const worktree = mkdtempSync(join(tmpdir(), "gsd-orphan-rollback-wt-"));
|
|
760
|
+
const s = makeSession({
|
|
761
|
+
basePath: "/prior",
|
|
762
|
+
originalBasePath: originalCwd,
|
|
763
|
+
active: true,
|
|
764
|
+
});
|
|
765
|
+
const deps = makeDeps({
|
|
766
|
+
getAutoWorktreePath: () => worktree,
|
|
767
|
+
});
|
|
768
|
+
const lifecycle = new WorktreeLifecycle(s, deps);
|
|
769
|
+
const thrown = new Error("synthetic callback failure");
|
|
770
|
+
|
|
771
|
+
try {
|
|
772
|
+
assert.throws(
|
|
773
|
+
() =>
|
|
774
|
+
lifecycle.adoptOrphanWorktree<{ merged: boolean }>("M001", base, () => {
|
|
775
|
+
assert.equal(s.basePath, worktree);
|
|
776
|
+
assert.equal(s.originalBasePath, base);
|
|
777
|
+
throw thrown;
|
|
778
|
+
}),
|
|
779
|
+
thrown,
|
|
780
|
+
);
|
|
781
|
+
|
|
782
|
+
assert.equal(s.basePath, "/prior");
|
|
783
|
+
assert.equal(s.originalBasePath, originalCwd);
|
|
784
|
+
assert.equal(process.cwd(), originalCwd);
|
|
785
|
+
} finally {
|
|
786
|
+
process.chdir(originalCwd);
|
|
787
|
+
rmSync(base, { recursive: true, force: true });
|
|
788
|
+
rmSync(worktree, { recursive: true, force: true });
|
|
789
|
+
}
|
|
790
|
+
});
|
|
791
|
+
|
|
792
|
+
test("adoptOrphanWorktree rejects traversal-style milestone ids before path resolution", () => {
|
|
793
|
+
const s = makeSession({
|
|
794
|
+
basePath: "/prior",
|
|
795
|
+
originalBasePath: "/prior-original",
|
|
796
|
+
active: true,
|
|
797
|
+
});
|
|
798
|
+
const deps = makeDeps({
|
|
799
|
+
getAutoWorktreePath: () => {
|
|
800
|
+
throw new Error("getAutoWorktreePath should not be called");
|
|
801
|
+
},
|
|
802
|
+
});
|
|
803
|
+
const lifecycle = new WorktreeLifecycle(s, deps);
|
|
804
|
+
|
|
805
|
+
assert.throws(
|
|
806
|
+
() =>
|
|
807
|
+
lifecycle.adoptOrphanWorktree("../M001", "/project", () => ({
|
|
808
|
+
merged: true as const,
|
|
809
|
+
})),
|
|
810
|
+
/Invalid milestoneId: \.\.\/M001/,
|
|
811
|
+
);
|
|
812
|
+
|
|
813
|
+
assert.equal(s.basePath, "/prior");
|
|
814
|
+
assert.equal(s.originalBasePath, "/prior-original");
|
|
815
|
+
assert.equal(
|
|
816
|
+
deps.calls.filter((c) => c.fn === "getAutoWorktreePath").length,
|
|
817
|
+
0,
|
|
818
|
+
);
|
|
819
|
+
});
|
|
820
|
+
|
|
821
|
+
test("adoptOrphanWorktree forwards the callback's return value", (t) => {
|
|
822
|
+
const previousCwd = process.cwd();
|
|
823
|
+
const base = makeGitRepoBase({ isolation: "worktree" });
|
|
824
|
+
t.after(() => cleanupRepoBase(base, previousCwd));
|
|
825
|
+
|
|
826
|
+
|
|
827
|
+
const s = makeSession();
|
|
828
|
+
s.active = true;
|
|
829
|
+
const lifecycle = new WorktreeLifecycle(s, makeDeps());
|
|
830
|
+
|
|
831
|
+
const result = lifecycle.adoptOrphanWorktree("M001", base, () => ({
|
|
832
|
+
merged: true as const,
|
|
833
|
+
customField: "preserved",
|
|
834
|
+
}));
|
|
835
|
+
|
|
836
|
+
assert.equal(result.merged, true);
|
|
837
|
+
assert.equal(result.customField, "preserved");
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
test("adoptOrphanWorktree leaves session unchanged when getAutoWorktreePath throws", () => {
|
|
841
|
+
const s = makeSession();
|
|
842
|
+
s.basePath = "/prior";
|
|
843
|
+
s.originalBasePath = "/prior-original";
|
|
844
|
+
s.active = true;
|
|
845
|
+
const lifecycle = new WorktreeLifecycle(
|
|
846
|
+
s,
|
|
847
|
+
makeDeps({
|
|
848
|
+
getAutoWorktreePath: () => {
|
|
849
|
+
throw new Error("git state unavailable");
|
|
850
|
+
},
|
|
851
|
+
}),
|
|
852
|
+
);
|
|
853
|
+
|
|
854
|
+
assert.throws(
|
|
855
|
+
() =>
|
|
856
|
+
lifecycle.adoptOrphanWorktree("M001", "/project", () => ({
|
|
857
|
+
merged: true as const,
|
|
858
|
+
})),
|
|
859
|
+
/git state unavailable/,
|
|
860
|
+
);
|
|
861
|
+
assert.equal(s.basePath, "/prior");
|
|
862
|
+
assert.equal(s.originalBasePath, "/prior-original");
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
test("adoptOrphanWorktree restores prior paths when callback throws", () => {
|
|
866
|
+
const s = makeSession();
|
|
867
|
+
s.basePath = "/prior";
|
|
868
|
+
s.originalBasePath = "/prior-original";
|
|
869
|
+
s.active = true;
|
|
870
|
+
const lifecycle = new WorktreeLifecycle(
|
|
871
|
+
s,
|
|
872
|
+
makeDeps({
|
|
873
|
+
getAutoWorktreePath: () => "/project/.gsd/worktrees/M001",
|
|
874
|
+
}),
|
|
875
|
+
);
|
|
876
|
+
|
|
877
|
+
assert.throws(
|
|
878
|
+
() =>
|
|
879
|
+
lifecycle.adoptOrphanWorktree("M001", "/project", () => {
|
|
880
|
+
assert.equal(s.basePath, "/project/.gsd/worktrees/M001");
|
|
881
|
+
assert.equal(s.originalBasePath, "/project");
|
|
882
|
+
throw new Error("merge exploded");
|
|
883
|
+
}),
|
|
884
|
+
/merge exploded/,
|
|
885
|
+
);
|
|
886
|
+
assert.equal(s.basePath, "/prior");
|
|
887
|
+
assert.equal(s.originalBasePath, "/prior-original");
|
|
434
888
|
});
|