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.
Files changed (503) hide show
  1. package/README.md +60 -30
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/browser-tools/tools/screenshot.js +1 -0
  4. package/dist/resources/extensions/browser-tools/tools/zoom.js +1 -0
  5. package/dist/resources/extensions/gsd/auto/loop.js +111 -8
  6. package/dist/resources/extensions/gsd/auto/orchestrator.js +113 -6
  7. package/dist/resources/extensions/gsd/auto/phases.js +199 -97
  8. package/dist/resources/extensions/gsd/auto/run-unit.js +66 -3
  9. package/dist/resources/extensions/gsd/auto/session.js +9 -0
  10. package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +43 -0
  11. package/dist/resources/extensions/gsd/auto-dashboard.js +182 -178
  12. package/dist/resources/extensions/gsd/auto-dispatch.js +14 -11
  13. package/dist/resources/extensions/gsd/auto-post-unit.js +7 -1
  14. package/dist/resources/extensions/gsd/auto-prompts.js +11 -3
  15. package/dist/resources/extensions/gsd/auto-recovery.js +6 -181
  16. package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -0
  17. package/dist/resources/extensions/gsd/auto-start.js +20 -23
  18. package/dist/resources/extensions/gsd/auto-unit-closeout.js +33 -5
  19. package/dist/resources/extensions/gsd/auto-verification.js +12 -6
  20. package/dist/resources/extensions/gsd/auto-worktree.js +8 -0
  21. package/dist/resources/extensions/gsd/auto.js +386 -106
  22. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +13 -6
  23. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +13 -2
  24. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +4 -8
  25. package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
  26. package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -1
  27. package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +4 -10
  28. package/dist/resources/extensions/gsd/commands/handlers/parallel.js +9 -0
  29. package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
  30. package/dist/resources/extensions/gsd/context-store.js +112 -0
  31. package/dist/resources/extensions/gsd/db-writer.js +150 -84
  32. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  33. package/dist/resources/extensions/gsd/doctor-git-checks.js +41 -6
  34. package/dist/resources/extensions/gsd/git-service.js +2 -1
  35. package/dist/resources/extensions/gsd/gsd-db.js +7 -23
  36. package/dist/resources/extensions/gsd/health-widget-core.js +1 -1
  37. package/dist/resources/extensions/gsd/health-widget.js +4 -10
  38. package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
  39. package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
  40. package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
  41. package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
  42. package/dist/resources/extensions/gsd/markdown-renderer.js +6 -96
  43. package/dist/resources/extensions/gsd/md-importer.js +1 -1
  44. package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
  45. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
  46. package/dist/resources/extensions/gsd/migrate/command.js +5 -0
  47. package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
  48. package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
  49. package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
  50. package/dist/resources/extensions/gsd/native-git-bridge.js +14 -14
  51. package/dist/resources/extensions/gsd/notification-overlay.js +35 -40
  52. package/dist/resources/extensions/gsd/parallel-merge.js +53 -30
  53. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +25 -33
  54. package/dist/resources/extensions/gsd/prompts/complete-slice.md +14 -12
  55. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
  56. package/dist/resources/extensions/gsd/prompts/discuss.md +20 -2
  57. package/dist/resources/extensions/gsd/prompts/system.md +2 -2
  58. package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
  59. package/dist/resources/extensions/gsd/recovery-classification.js +15 -1
  60. package/dist/resources/extensions/gsd/session-lock.js +40 -0
  61. package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +131 -0
  62. package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +247 -0
  63. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +50 -0
  64. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +87 -0
  65. package/dist/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.js +50 -0
  66. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +124 -0
  67. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +32 -0
  68. package/dist/resources/extensions/gsd/state-reconciliation/errors.js +41 -0
  69. package/dist/resources/extensions/gsd/state-reconciliation/index.js +99 -0
  70. package/dist/resources/extensions/gsd/state-reconciliation/registry.js +24 -0
  71. package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +43 -0
  72. package/dist/resources/extensions/gsd/state-reconciliation/types.js +3 -0
  73. package/dist/resources/extensions/gsd/state-reconciliation.js +5 -26
  74. package/dist/resources/extensions/gsd/templates/knowledge.md +2 -2
  75. package/dist/resources/extensions/gsd/tui/render-kit.js +74 -0
  76. package/dist/resources/extensions/gsd/watch/header-renderer.js +92 -69
  77. package/dist/resources/extensions/gsd/watch/splash-palette.js +10 -0
  78. package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
  79. package/dist/resources/extensions/gsd/worktree-lifecycle.js +722 -316
  80. package/dist/resources/extensions/gsd/worktree-telemetry.js +3 -1
  81. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  82. package/dist/web/standalone/.next/BUILD_ID +1 -1
  83. package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
  84. package/dist/web/standalone/.next/build-manifest.json +3 -3
  85. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  86. package/dist/web/standalone/.next/required-server-files.json +3 -3
  87. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  88. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  90. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  98. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  114. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  126. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  146. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  156. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  162. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  178. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
  182. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  190. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  191. package/dist/web/standalone/.next/server/app/index.html +1 -1
  192. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  193. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  194. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  195. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  196. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  197. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  198. package/dist/web/standalone/.next/server/app/page.js +2 -2
  199. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/app-paths-manifest.json +6 -6
  201. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  202. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  203. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  204. package/dist/web/standalone/.next/server/middleware.js +2 -2
  205. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  206. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  207. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  208. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  209. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  210. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  211. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  212. package/dist/web/standalone/.next/static/chunks/app/page-752f1e2ebdaa3e45.js +1 -0
  213. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  214. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  215. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  216. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  217. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  218. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  219. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  220. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  221. package/dist/web/standalone/server.js +1 -1
  222. package/dist/welcome-screen.d.ts +0 -7
  223. package/dist/welcome-screen.js +60 -69
  224. package/package.json +3 -2
  225. package/packages/daemon/package.json +2 -2
  226. package/packages/mcp-server/README.md +2 -0
  227. package/packages/mcp-server/package.json +2 -2
  228. package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
  229. package/packages/native/package.json +1 -1
  230. package/packages/pi-agent-core/package.json +1 -1
  231. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  232. package/packages/pi-ai/dist/index.d.ts +2 -2
  233. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  234. package/packages/pi-ai/dist/index.js +1 -1
  235. package/packages/pi-ai/dist/index.js.map +1 -1
  236. package/packages/pi-ai/dist/providers/transform-messages.d.ts +11 -0
  237. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  238. package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
  239. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  240. package/packages/pi-ai/package.json +1 -1
  241. package/packages/pi-ai/src/index.ts +7 -2
  242. package/packages/pi-ai/src/providers/transform-messages.ts +24 -0
  243. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  244. package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
  245. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  246. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts +2 -0
  247. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts.map +1 -0
  248. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js +47 -0
  249. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js.map +1 -0
  250. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +76 -9
  251. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  252. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts +2 -0
  253. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts.map +1 -0
  254. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js +40 -0
  255. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js.map +1 -0
  256. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +0 -1
  257. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -1
  258. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +30 -29
  259. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -1
  260. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +10 -3
  261. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -1
  262. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  263. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +13 -13
  264. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  265. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -3
  266. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  267. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +58 -3
  268. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
  269. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +2 -2
  270. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
  271. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +12 -6
  272. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
  273. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  274. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -41
  275. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  276. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +0 -1
  277. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  278. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +86 -82
  279. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  280. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts +35 -0
  281. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts.map +1 -0
  282. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js +152 -0
  283. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js.map +1 -0
  284. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts +16 -0
  285. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts.map +1 -0
  286. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js +73 -0
  287. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js.map +1 -0
  288. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +1 -1
  289. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  290. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +12 -8
  291. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  292. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  293. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  294. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  295. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  296. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  297. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +105 -1
  298. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  299. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  300. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +27 -26
  301. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  302. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +9 -6
  303. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -1
  304. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
  305. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
  306. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
  307. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
  308. package/packages/pi-coding-agent/package.json +1 -1
  309. package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
  310. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/assistant-message-design.test.ts +56 -0
  311. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +113 -9
  312. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/user-message-design.test.ts +48 -0
  313. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +10 -3
  314. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +43 -42
  315. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +14 -14
  316. package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +64 -3
  317. package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +13 -7
  318. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +15 -42
  319. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +84 -104
  320. package/packages/pi-coding-agent/src/modes/interactive/components/transcript-design.ts +196 -0
  321. package/packages/pi-coding-agent/src/modes/interactive/components/tui-style-kit.ts +94 -0
  322. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +14 -9
  323. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-highlight.test.ts +23 -0
  324. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +106 -1
  325. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +27 -26
  326. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +9 -6
  327. package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
  328. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  329. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +14 -1
  330. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  331. package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
  332. package/packages/pi-tui/dist/overlay-layout.js +9 -6
  333. package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
  334. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  335. package/packages/pi-tui/dist/tui.js +5 -0
  336. package/packages/pi-tui/dist/tui.js.map +1 -1
  337. package/packages/pi-tui/package.json +1 -1
  338. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +20 -1
  339. package/packages/pi-tui/src/overlay-layout.ts +10 -7
  340. package/packages/pi-tui/src/tui.ts +6 -0
  341. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  342. package/packages/rpc-client/package.json +1 -1
  343. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  344. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  345. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  346. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  347. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  348. package/pkg/dist/modes/interactive/theme/theme.js +105 -1
  349. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  350. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  351. package/pkg/dist/modes/interactive/theme/themes.js +27 -26
  352. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  353. package/pkg/package.json +1 -1
  354. package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
  355. package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
  356. package/src/resources/extensions/gsd/auto/contracts.ts +46 -11
  357. package/src/resources/extensions/gsd/auto/loop-deps.ts +9 -5
  358. package/src/resources/extensions/gsd/auto/loop.ts +113 -9
  359. package/src/resources/extensions/gsd/auto/orchestrator.ts +118 -6
  360. package/src/resources/extensions/gsd/auto/phases.ts +158 -19
  361. package/src/resources/extensions/gsd/auto/run-unit.ts +69 -4
  362. package/src/resources/extensions/gsd/auto/session.ts +10 -0
  363. package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +82 -0
  364. package/src/resources/extensions/gsd/auto-dashboard.ts +230 -183
  365. package/src/resources/extensions/gsd/auto-dispatch.ts +15 -1
  366. package/src/resources/extensions/gsd/auto-post-unit.ts +7 -1
  367. package/src/resources/extensions/gsd/auto-prompts.ts +11 -3
  368. package/src/resources/extensions/gsd/auto-recovery.ts +7 -209
  369. package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
  370. package/src/resources/extensions/gsd/auto-start.ts +22 -22
  371. package/src/resources/extensions/gsd/auto-unit-closeout.ts +51 -0
  372. package/src/resources/extensions/gsd/auto-verification.ts +12 -6
  373. package/src/resources/extensions/gsd/auto-worktree.ts +8 -0
  374. package/src/resources/extensions/gsd/auto.ts +424 -106
  375. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +21 -6
  376. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +12 -2
  377. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +5 -8
  378. package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
  379. package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -1
  380. package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +4 -10
  381. package/src/resources/extensions/gsd/commands/handlers/parallel.ts +12 -0
  382. package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
  383. package/src/resources/extensions/gsd/context-store.ts +120 -1
  384. package/src/resources/extensions/gsd/db-writer.ts +167 -84
  385. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  386. package/src/resources/extensions/gsd/doctor-git-checks.ts +44 -6
  387. package/src/resources/extensions/gsd/doctor-types.ts +2 -0
  388. package/src/resources/extensions/gsd/git-service.ts +2 -0
  389. package/src/resources/extensions/gsd/gsd-db.ts +7 -23
  390. package/src/resources/extensions/gsd/health-widget-core.ts +1 -1
  391. package/src/resources/extensions/gsd/health-widget.ts +6 -10
  392. package/src/resources/extensions/gsd/journal.ts +2 -0
  393. package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
  394. package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
  395. package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
  396. package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
  397. package/src/resources/extensions/gsd/markdown-renderer.ts +10 -96
  398. package/src/resources/extensions/gsd/md-importer.ts +1 -1
  399. package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
  400. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
  401. package/src/resources/extensions/gsd/migrate/command.ts +5 -0
  402. package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
  403. package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
  404. package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
  405. package/src/resources/extensions/gsd/native-git-bridge.ts +14 -13
  406. package/src/resources/extensions/gsd/notification-overlay.ts +50 -46
  407. package/src/resources/extensions/gsd/parallel-merge.ts +61 -34
  408. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +33 -35
  409. package/src/resources/extensions/gsd/prompts/complete-slice.md +14 -12
  410. package/src/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
  411. package/src/resources/extensions/gsd/prompts/discuss.md +20 -2
  412. package/src/resources/extensions/gsd/prompts/system.md +2 -2
  413. package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
  414. package/src/resources/extensions/gsd/recovery-classification.ts +18 -1
  415. package/src/resources/extensions/gsd/session-lock.ts +41 -0
  416. package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +172 -0
  417. package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +337 -0
  418. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +69 -0
  419. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +109 -0
  420. package/src/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.ts +68 -0
  421. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +185 -0
  422. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +46 -0
  423. package/src/resources/extensions/gsd/state-reconciliation/errors.ts +67 -0
  424. package/src/resources/extensions/gsd/state-reconciliation/index.ts +142 -0
  425. package/src/resources/extensions/gsd/state-reconciliation/registry.ts +27 -0
  426. package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +60 -0
  427. package/src/resources/extensions/gsd/state-reconciliation/types.ts +83 -0
  428. package/src/resources/extensions/gsd/state-reconciliation.ts +21 -53
  429. package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
  430. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +1 -1
  431. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +99 -0
  432. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +729 -176
  433. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +408 -4
  434. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +291 -4
  435. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +20 -5
  436. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +18 -0
  437. package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +68 -0
  438. package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
  439. package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
  440. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +28 -1
  441. package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
  442. package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
  443. package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
  444. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +20 -2
  445. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +44 -0
  446. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
  447. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
  448. package/src/resources/extensions/gsd/tests/header-renderer.test.ts +40 -0
  449. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +10 -0
  450. package/src/resources/extensions/gsd/tests/health-widget.test.ts +14 -4
  451. package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +44 -0
  452. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +26 -0
  453. package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
  454. package/src/resources/extensions/gsd/tests/integration/integration-proof.test.ts +1 -1
  455. package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
  456. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +116 -24
  457. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -1
  458. package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
  459. package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
  460. package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
  461. package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
  462. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +1 -1
  463. package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
  464. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +46 -11
  465. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
  466. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
  467. package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +78 -41
  468. package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +44 -0
  469. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +12 -217
  470. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +38 -6
  471. package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
  472. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +2 -2
  473. package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +1 -1
  474. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +32 -1
  475. package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
  476. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +7 -3
  477. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +6 -3
  478. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
  479. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +24 -0
  480. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +65 -58
  481. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +952 -0
  482. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -0
  483. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +121 -1
  484. package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +66 -0
  485. package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +83 -0
  486. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +6 -0
  487. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +158 -58
  488. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +572 -118
  489. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +59 -2
  490. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +18 -0
  491. package/src/resources/extensions/gsd/tui/render-kit.ts +109 -0
  492. package/src/resources/extensions/gsd/watch/header-renderer.ts +121 -79
  493. package/src/resources/extensions/gsd/watch/splash-palette.ts +11 -0
  494. package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
  495. package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
  496. package/src/resources/extensions/gsd/worktree-lifecycle.ts +1151 -524
  497. package/src/resources/extensions/gsd/worktree-telemetry.ts +7 -2
  498. package/dist/web/standalone/.next/static/chunks/app/page-200592a7f3baf579.js +0 -1
  499. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  500. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  501. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +0 -1544
  502. /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → YEvjuT-fsFfYQhDSWtueS}/_buildManifest.js +0 -0
  503. /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<WorktreeLifecycleDeps>,
36
- ): WorktreeLifecycleDeps & { calls: CallLog[] } {
44
+ overrides?: Partial<LegacyTestDeps>,
45
+ ): LegacyTestDeps & { calls: CallLog[] } {
37
46
  const calls: CallLog[] = [];
38
- const deps: WorktreeLifecycleDeps & { calls: CallLog[] } = {
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
- enterAutoWorktree: (basePath, milestoneId) => {
41
- calls.push({ fn: "enterAutoWorktree", args: [basePath, milestoneId] });
42
- return `/project/.gsd/worktrees/${milestoneId}`;
43
- },
44
- createAutoWorktree: (basePath, milestoneId) => {
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
- const s = makeSession();
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.equal(result.path, "/project/.gsd/worktrees/M001");
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.equal(s.basePath, "/project/.gsd/worktrees/M001");
134
- assert.equal(
135
- deps.calls.filter((c) => c.fn === "invalidateAllCaches").length,
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
- const s = makeSession();
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, "/project");
192
+ assert.equal(result.path, base);
152
193
  }
153
194
  // Branch mode does not mutate s.basePath
154
- assert.equal(s.basePath, "/project");
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
- // No worktree primitives invoked
186
- assert.equal(deps.calls.filter((c) => c.fn === "createAutoWorktree").length, 0);
187
- assert.equal(deps.calls.filter((c) => c.fn === "enterAutoWorktree").length, 0);
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
- const s = makeSession();
192
- const deps = makeDeps({
193
- createAutoWorktree: () => {
194
- throw new Error("boom");
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, "/project");
253
+ assert.equal(s.basePath, base);
210
254
  });
211
255
 
212
- test("enterMilestone returns ok:false reason:creation-failed when branch mode throws", () => {
213
- const s = makeSession();
214
- const deps = makeDeps({
215
- getIsolationMode: () => "branch",
216
- enterBranchModeForMilestone: () => {
217
- throw new Error("branch checkout failed");
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
- const s = makeSession();
234
- const deps = makeDeps({
235
- getAutoWorktreePath: () => "/project/.gsd/worktrees/M001",
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
- assert.equal(deps.calls.filter((c) => c.fn === "enterAutoWorktree").length, 1);
244
- assert.equal(deps.calls.filter((c) => c.fn === "createAutoWorktree").length, 0);
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(deps.calls.filter((c) => c.fn === "createAutoWorktree").length, 0);
270
- assert.equal(deps.calls.filter((c) => c.fn === "enterAutoWorktree").length, 0);
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: "/project/.gsd/worktrees/M001",
276
- originalBasePath: "/project",
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, "/project/.gsd/worktrees/M001");
367
+ assert.equal(result.path, wt);
289
368
  }
290
- assert.equal(s.basePath, "/project/.gsd/worktrees/M001");
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 invokes branch-mode helper", () => {
357
- const s = makeSession();
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
- assert.equal(
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
- assert.equal(
382
- deps.calls.filter((c) => c.fn === "enterBranchModeForMilestone").length,
383
- 0,
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
- assert.equal(deps.calls.filter((c) => c.fn === "GitServiceImpl").length, 1);
420
- assert.equal(deps.calls.filter((c) => c.fn === "invalidateAllCaches").length, 1);
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 === "GitServiceImpl").length, 0);
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
  });