gsd-pi 2.80.0-dev.fbe7c8c6f → 2.81.0-dev.3cddbbba2

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 (814) hide show
  1. package/README.md +47 -59
  2. package/dist/claude-cli-check.d.ts +30 -0
  3. package/dist/claude-cli-check.js +18 -7
  4. package/dist/cli.js +0 -19
  5. package/dist/headless-query.d.ts +10 -0
  6. package/dist/headless-query.js +6 -4
  7. package/dist/loader-entrypoint.d.ts +8 -0
  8. package/dist/loader-entrypoint.js +27 -0
  9. package/dist/loader.js +2 -11
  10. package/dist/mcp-server.d.ts +1 -0
  11. package/dist/mcp-server.js +6 -3
  12. package/dist/resources/.managed-resources-content-hash +1 -1
  13. package/dist/resources/extensions/claude-code-cli/readiness.js +18 -7
  14. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +40 -3
  15. package/dist/resources/extensions/github-sync/sync.js +4 -1
  16. package/dist/resources/extensions/gsd/auto/contracts.js +2 -0
  17. package/dist/resources/extensions/gsd/auto/loop.js +214 -17
  18. package/dist/resources/extensions/gsd/auto/orchestrator.js +48 -4
  19. package/dist/resources/extensions/gsd/auto/phases.js +372 -134
  20. package/dist/resources/extensions/gsd/auto/resolve.js +29 -0
  21. package/dist/resources/extensions/gsd/auto/run-unit.js +88 -33
  22. package/dist/resources/extensions/gsd/auto/session.js +18 -1
  23. package/dist/resources/extensions/gsd/auto/unit-runner-events.js +7 -0
  24. package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +43 -0
  25. package/dist/resources/extensions/gsd/auto/workflow-dispatch-claim.js +33 -1
  26. package/dist/resources/extensions/gsd/auto/workflow-worker-heartbeat.js +9 -1
  27. package/dist/resources/extensions/gsd/auto-dashboard.js +199 -177
  28. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +5 -32
  29. package/dist/resources/extensions/gsd/auto-dispatch.js +30 -11
  30. package/dist/resources/extensions/gsd/auto-post-unit.js +119 -79
  31. package/dist/resources/extensions/gsd/auto-prompts.js +103 -16
  32. package/dist/resources/extensions/gsd/auto-recovery.js +43 -1
  33. package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -0
  34. package/dist/resources/extensions/gsd/auto-start.js +251 -16
  35. package/dist/resources/extensions/gsd/auto-supervisor.js +8 -1
  36. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +2 -2
  37. package/dist/resources/extensions/gsd/auto-unit-closeout.js +33 -5
  38. package/dist/resources/extensions/gsd/auto-verification.js +12 -6
  39. package/dist/resources/extensions/gsd/auto-worktree.js +237 -336
  40. package/dist/resources/extensions/gsd/auto.js +493 -129
  41. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +133 -12
  42. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +44 -37
  43. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +37 -10
  44. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +30 -20
  45. package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +4 -1
  46. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +6 -4
  47. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +5 -3
  48. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +1 -1
  49. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +337 -55
  50. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +4 -8
  51. package/dist/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.js +4 -0
  52. package/dist/resources/extensions/gsd/bootstrap/system-context.js +82 -23
  53. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +19 -2
  54. package/dist/resources/extensions/gsd/clean-root-preflight.js +24 -6
  55. package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +4 -10
  56. package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -2
  57. package/dist/resources/extensions/gsd/commands-config.js +1 -1
  58. package/dist/resources/extensions/gsd/commands-eval-review.js +2 -2
  59. package/dist/resources/extensions/gsd/commands-handlers.js +23 -9
  60. package/dist/resources/extensions/gsd/context-budget.js +37 -2
  61. package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
  62. package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -1
  63. package/dist/resources/extensions/gsd/db/unit-dispatches.js +92 -0
  64. package/dist/resources/extensions/gsd/db-base-schema.js +4 -2
  65. package/dist/resources/extensions/gsd/db-migration-steps.js +6 -0
  66. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +2 -0
  67. package/dist/resources/extensions/gsd/git-service.js +75 -6
  68. package/dist/resources/extensions/gsd/gsd-db.js +46 -13
  69. package/dist/resources/extensions/gsd/guided-flow.js +119 -42
  70. package/dist/resources/extensions/gsd/health-widget-core.js +1 -1
  71. package/dist/resources/extensions/gsd/health-widget.js +6 -9
  72. package/dist/resources/extensions/gsd/init-wizard.js +4 -1
  73. package/dist/resources/extensions/gsd/memory-store.js +69 -12
  74. package/dist/resources/extensions/gsd/migrate/command.js +40 -1
  75. package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
  76. package/dist/resources/extensions/gsd/native-git-bridge.js +46 -22
  77. package/dist/resources/extensions/gsd/notification-overlay.js +35 -40
  78. package/dist/resources/extensions/gsd/orphan-stash-audit.js +101 -0
  79. package/dist/resources/extensions/gsd/parallel-merge.js +53 -30
  80. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +25 -33
  81. package/dist/resources/extensions/gsd/parallel-orchestrator.js +13 -3
  82. package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
  83. package/dist/resources/extensions/gsd/pre-execution-checks.js +22 -0
  84. package/dist/resources/extensions/gsd/prompt-loader.js +28 -2
  85. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +22 -17
  86. package/dist/resources/extensions/gsd/prompts/complete-slice.md +14 -12
  87. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
  88. package/dist/resources/extensions/gsd/prompts/discuss.md +20 -2
  89. package/dist/resources/extensions/gsd/prompts/execute-task.md +4 -2
  90. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  91. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  92. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
  93. package/dist/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  94. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  95. package/dist/resources/extensions/gsd/quick.js +34 -2
  96. package/dist/resources/extensions/gsd/recovery-classification.js +94 -0
  97. package/dist/resources/extensions/gsd/slice-cadence.js +45 -2
  98. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +15 -9
  99. package/dist/resources/extensions/gsd/state-reconciliation.js +27 -0
  100. package/dist/resources/extensions/gsd/tool-contract.js +50 -0
  101. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -7
  102. package/dist/resources/extensions/gsd/tools/complete-task.js +1 -1
  103. package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
  104. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
  105. package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
  106. package/dist/resources/extensions/gsd/tools/memory-tools.js +1 -0
  107. package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
  108. package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
  109. package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
  110. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +1 -1
  111. package/dist/resources/extensions/gsd/tui/render-kit.js +74 -0
  112. package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
  113. package/dist/resources/extensions/gsd/unit-runtime.js +22 -0
  114. package/dist/resources/extensions/gsd/watch/header-renderer.js +92 -69
  115. package/dist/resources/extensions/gsd/watch/splash-palette.js +10 -0
  116. package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
  117. package/dist/resources/extensions/gsd/workflow-protocol.js +131 -0
  118. package/dist/resources/extensions/gsd/worktree-lifecycle.js +1364 -0
  119. package/dist/resources/extensions/gsd/worktree-safety.js +119 -0
  120. package/dist/resources/extensions/gsd/worktree-state-projection.js +317 -0
  121. package/dist/resources/extensions/gsd/worktree-telemetry.js +3 -1
  122. package/dist/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
  123. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  124. package/dist/web/standalone/.next/BUILD_ID +1 -1
  125. package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
  126. package/dist/web/standalone/.next/build-manifest.json +3 -3
  127. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  128. package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
  129. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  131. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  132. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  134. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  135. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  136. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  137. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  140. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  141. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  142. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  143. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  144. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  145. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  146. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  147. package/dist/web/standalone/.next/server/app/index.html +1 -1
  148. package/dist/web/standalone/.next/server/app/index.rsc +2 -2
  149. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  150. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  151. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  152. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  153. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  154. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
  156. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/middleware.js +3 -3
  159. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  160. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  161. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  162. package/dist/web/standalone/.next/static/chunks/8359.e059d86b255fce1c.js +10 -0
  163. package/dist/web/standalone/.next/static/chunks/app/{page-fab3ebb85b006001.js → page-752f1e2ebdaa3e45.js} +1 -1
  164. package/dist/web/standalone/.next/static/chunks/{webpack-0481f1221120a7c6.js → webpack-de742b64187e13fe.js} +1 -1
  165. package/dist/welcome-screen.d.ts +2 -7
  166. package/dist/welcome-screen.js +68 -75
  167. package/package.json +3 -3
  168. package/packages/daemon/package.json +2 -2
  169. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  170. package/packages/mcp-server/dist/workflow-tools.js +22 -17
  171. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  172. package/packages/mcp-server/package.json +2 -2
  173. package/packages/mcp-server/src/workflow-tools.test.ts +75 -2
  174. package/packages/mcp-server/src/workflow-tools.ts +30 -16
  175. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  176. package/packages/native/package.json +1 -1
  177. package/packages/native/tsconfig.tsbuildinfo +1 -1
  178. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  179. package/packages/pi-agent-core/dist/agent-loop.js +4 -1
  180. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  181. package/packages/pi-agent-core/dist/agent.d.ts +9 -2
  182. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  183. package/packages/pi-agent-core/dist/agent.js +43 -11
  184. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  185. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  186. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  187. package/packages/pi-agent-core/dist/index.js +2 -0
  188. package/packages/pi-agent-core/dist/index.js.map +1 -1
  189. package/packages/pi-agent-core/dist/token-audit.d.ts +47 -0
  190. package/packages/pi-agent-core/dist/token-audit.d.ts.map +1 -0
  191. package/packages/pi-agent-core/dist/token-audit.js +221 -0
  192. package/packages/pi-agent-core/dist/token-audit.js.map +1 -0
  193. package/packages/pi-agent-core/dist/types.d.ts +31 -0
  194. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  195. package/packages/pi-agent-core/dist/types.js.map +1 -1
  196. package/packages/pi-agent-core/package.json +1 -1
  197. package/packages/pi-agent-core/src/agent-loop.test.ts +128 -0
  198. package/packages/pi-agent-core/src/agent-loop.ts +4 -1
  199. package/packages/pi-agent-core/src/agent.ts +52 -11
  200. package/packages/pi-agent-core/src/index.ts +2 -0
  201. package/packages/pi-agent-core/src/token-audit.test.ts +189 -0
  202. package/packages/pi-agent-core/src/token-audit.ts +287 -0
  203. package/packages/pi-agent-core/src/types.ts +26 -10
  204. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  205. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +35 -13
  206. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  207. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +21 -11
  208. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -1
  209. package/packages/pi-ai/dist/providers/anthropic.d.ts +7 -0
  210. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  211. package/packages/pi-ai/dist/providers/anthropic.js +9 -7
  212. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  213. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +23 -14
  214. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -1
  215. package/packages/pi-ai/dist/types.d.ts +2 -0
  216. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  217. package/packages/pi-ai/dist/types.js.map +1 -1
  218. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +48 -21
  219. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
  220. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +22 -21
  221. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -1
  222. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +22 -21
  223. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -1
  224. package/packages/pi-ai/package.json +1 -1
  225. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +39 -25
  226. package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -22
  227. package/packages/pi-ai/src/providers/anthropic.ts +22 -9
  228. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +34 -21
  229. package/packages/pi-ai/src/types.ts +3 -0
  230. package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +56 -22
  231. package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +24 -28
  232. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +24 -28
  233. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  234. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +36 -1
  235. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  236. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +30 -1
  237. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  238. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +21 -2
  239. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  240. package/packages/pi-coding-agent/dist/core/agent-session.js +94 -16
  241. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  242. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +6 -2
  243. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  244. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
  245. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  246. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
  247. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  248. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
  249. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
  250. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
  251. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
  252. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
  253. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
  254. package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
  255. package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
  256. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
  257. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
  258. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
  259. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
  260. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  261. package/packages/pi-coding-agent/dist/core/extensions/loader.js +8 -0
  262. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  263. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +3 -0
  264. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  265. package/packages/pi-coding-agent/dist/core/extensions/runner.js +6 -6
  266. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  267. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +5 -3
  268. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  269. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +60 -4
  270. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  271. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  272. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +2 -0
  273. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -1
  274. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts +2 -0
  275. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts.map +1 -0
  276. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js +46 -0
  277. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js.map +1 -0
  278. package/packages/pi-coding-agent/dist/core/sdk.d.ts +10 -2
  279. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  280. package/packages/pi-coding-agent/dist/core/sdk.js +81 -4
  281. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  282. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
  283. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  284. package/packages/pi-coding-agent/dist/core/settings-manager.js +25 -0
  285. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  286. package/packages/pi-coding-agent/dist/core/skill-tool.test.js +22 -0
  287. package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -1
  288. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +6 -7
  289. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  290. package/packages/pi-coding-agent/dist/core/system-prompt.js +2 -3
  291. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  292. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js +22 -56
  293. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js.map +1 -1
  294. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +1 -0
  295. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  296. package/packages/pi-coding-agent/dist/core/tools/bash.js +3 -1
  297. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  298. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts +2 -0
  299. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  300. package/packages/pi-coding-agent/dist/core/tools/edit.js +12 -1
  301. package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  302. package/packages/pi-coding-agent/dist/core/tools/find.d.ts +2 -0
  303. package/packages/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
  304. package/packages/pi-coding-agent/dist/core/tools/find.js +14 -6
  305. package/packages/pi-coding-agent/dist/core/tools/find.js.map +1 -1
  306. package/packages/pi-coding-agent/dist/core/tools/grep.d.ts +2 -0
  307. package/packages/pi-coding-agent/dist/core/tools/grep.d.ts.map +1 -1
  308. package/packages/pi-coding-agent/dist/core/tools/grep.js +12 -3
  309. package/packages/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
  310. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts +2 -0
  311. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts.map +1 -1
  312. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js +3 -1
  313. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js.map +1 -1
  314. package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -1
  315. package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
  316. package/packages/pi-coding-agent/dist/core/tools/index.js +1 -0
  317. package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
  318. package/packages/pi-coding-agent/dist/core/tools/ls.d.ts +2 -0
  319. package/packages/pi-coding-agent/dist/core/tools/ls.d.ts.map +1 -1
  320. package/packages/pi-coding-agent/dist/core/tools/ls.js +10 -3
  321. package/packages/pi-coding-agent/dist/core/tools/ls.js.map +1 -1
  322. package/packages/pi-coding-agent/dist/core/tools/read.d.ts +2 -0
  323. package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
  324. package/packages/pi-coding-agent/dist/core/tools/read.js +3 -1
  325. package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
  326. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js +7 -62
  327. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js.map +1 -1
  328. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts +2 -0
  329. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts.map +1 -0
  330. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js +115 -0
  331. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js.map +1 -0
  332. package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts +19 -0
  333. package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts.map +1 -0
  334. package/packages/pi-coding-agent/dist/core/tools/tool-target.js +20 -0
  335. package/packages/pi-coding-agent/dist/core/tools/tool-target.js.map +1 -0
  336. package/packages/pi-coding-agent/dist/core/tools/write.d.ts +4 -0
  337. package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  338. package/packages/pi-coding-agent/dist/core/tools/write.js +9 -1
  339. package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  340. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts +2 -0
  341. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts.map +1 -0
  342. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js +47 -0
  343. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js.map +1 -0
  344. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +161 -7
  345. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  346. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts +2 -0
  347. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts.map +1 -0
  348. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js +40 -0
  349. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js.map +1 -0
  350. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +0 -1
  351. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -1
  352. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +30 -29
  353. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -1
  354. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +10 -3
  355. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -1
  356. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  357. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +13 -13
  358. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  359. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -3
  360. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  361. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +58 -3
  362. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
  363. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +2 -2
  364. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
  365. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +12 -6
  366. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
  367. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  368. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -41
  369. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  370. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +25 -1
  371. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
  372. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +6 -1
  373. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  374. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +225 -73
  375. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  376. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts +35 -0
  377. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts.map +1 -0
  378. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js +152 -0
  379. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js.map +1 -0
  380. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts +16 -0
  381. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts.map +1 -0
  382. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js +73 -0
  383. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js.map +1 -0
  384. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +1 -1
  385. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  386. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +12 -8
  387. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  388. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  389. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +31 -6
  390. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  391. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +71 -0
  392. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  393. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +2 -0
  394. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  395. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +25 -3
  396. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  397. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  398. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  399. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  400. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  401. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  402. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +105 -1
  403. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  404. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  405. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +27 -26
  406. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  407. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +9 -6
  408. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -1
  409. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +1 -1
  410. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  411. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
  412. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
  413. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +28 -0
  414. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
  415. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
  416. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
  417. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
  418. package/packages/pi-coding-agent/package.json +1 -1
  419. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +40 -1
  420. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +40 -1
  421. package/packages/pi-coding-agent/src/core/agent-session.ts +102 -16
  422. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +6 -2
  423. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
  424. package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
  425. package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
  426. package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
  427. package/packages/pi-coding-agent/src/core/extensions/loader.ts +10 -0
  428. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +5 -3
  429. package/packages/pi-coding-agent/src/core/extensions/runner.ts +8 -5
  430. package/packages/pi-coding-agent/src/core/extensions/types.ts +63 -2
  431. package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +2 -0
  432. package/packages/pi-coding-agent/src/core/sdk-tool-filter.test.ts +60 -0
  433. package/packages/pi-coding-agent/src/core/sdk.ts +92 -4
  434. package/packages/pi-coding-agent/src/core/settings-manager.ts +39 -1
  435. package/packages/pi-coding-agent/src/core/skill-tool.test.ts +28 -0
  436. package/packages/pi-coding-agent/src/core/system-prompt.ts +8 -10
  437. package/packages/pi-coding-agent/src/core/tools/bash-spawn-windows.test.ts +22 -66
  438. package/packages/pi-coding-agent/src/core/tools/bash.ts +4 -1
  439. package/packages/pi-coding-agent/src/core/tools/edit.ts +13 -1
  440. package/packages/pi-coding-agent/src/core/tools/find.ts +15 -6
  441. package/packages/pi-coding-agent/src/core/tools/grep.ts +13 -3
  442. package/packages/pi-coding-agent/src/core/tools/hashline-read.ts +4 -1
  443. package/packages/pi-coding-agent/src/core/tools/index.ts +8 -0
  444. package/packages/pi-coding-agent/src/core/tools/ls.ts +11 -3
  445. package/packages/pi-coding-agent/src/core/tools/read.ts +4 -1
  446. package/packages/pi-coding-agent/src/core/tools/spawn-shell-windows.test.ts +11 -72
  447. package/packages/pi-coding-agent/src/core/tools/tool-target-metadata.test.ts +127 -0
  448. package/packages/pi-coding-agent/src/core/tools/tool-target.ts +48 -0
  449. package/packages/pi-coding-agent/src/core/tools/write.ts +14 -2
  450. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/assistant-message-design.test.ts +56 -0
  451. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +228 -7
  452. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/user-message-design.test.ts +48 -0
  453. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +10 -3
  454. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +43 -42
  455. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +14 -14
  456. package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +64 -3
  457. package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +13 -7
  458. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +15 -42
  459. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +31 -1
  460. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +247 -94
  461. package/packages/pi-coding-agent/src/modes/interactive/components/transcript-design.ts +196 -0
  462. package/packages/pi-coding-agent/src/modes/interactive/components/tui-style-kit.ts +94 -0
  463. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +14 -9
  464. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +75 -0
  465. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +39 -8
  466. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +27 -3
  467. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-highlight.test.ts +23 -0
  468. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +106 -1
  469. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +27 -26
  470. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +9 -6
  471. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +1 -1
  472. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +31 -0
  473. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
  474. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  475. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +14 -1
  476. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  477. package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
  478. package/packages/pi-tui/dist/overlay-layout.js +9 -6
  479. package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
  480. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  481. package/packages/pi-tui/dist/tui.js +18 -8
  482. package/packages/pi-tui/dist/tui.js.map +1 -1
  483. package/packages/pi-tui/package.json +1 -1
  484. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +20 -1
  485. package/packages/pi-tui/src/overlay-layout.ts +10 -7
  486. package/packages/pi-tui/src/tui.ts +20 -8
  487. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  488. package/packages/rpc-client/README.md +7 -0
  489. package/packages/rpc-client/package.json +1 -1
  490. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  491. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  492. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  493. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  494. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  495. package/pkg/dist/modes/interactive/theme/theme.js +105 -1
  496. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  497. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  498. package/pkg/dist/modes/interactive/theme/themes.js +27 -26
  499. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  500. package/pkg/package.json +1 -1
  501. package/src/resources/extensions/claude-code-cli/readiness.ts +25 -7
  502. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +42 -3
  503. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +67 -0
  504. package/src/resources/extensions/github-sync/sync.ts +8 -1
  505. package/src/resources/extensions/github-sync/tests/sync-source.test.ts +6 -18
  506. package/src/resources/extensions/gsd/auto/contracts.ts +19 -2
  507. package/src/resources/extensions/gsd/auto/loop-deps.ts +19 -16
  508. package/src/resources/extensions/gsd/auto/loop.ts +247 -25
  509. package/src/resources/extensions/gsd/auto/orchestrator.ts +52 -4
  510. package/src/resources/extensions/gsd/auto/phases.ts +512 -202
  511. package/src/resources/extensions/gsd/auto/resolve.ts +42 -1
  512. package/src/resources/extensions/gsd/auto/run-unit.ts +97 -34
  513. package/src/resources/extensions/gsd/auto/session.ts +19 -1
  514. package/src/resources/extensions/gsd/auto/types.ts +3 -0
  515. package/src/resources/extensions/gsd/auto/unit-runner-events.ts +15 -0
  516. package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +82 -0
  517. package/src/resources/extensions/gsd/auto/workflow-dispatch-claim.ts +63 -1
  518. package/src/resources/extensions/gsd/auto/workflow-worker-heartbeat.ts +14 -1
  519. package/src/resources/extensions/gsd/auto-dashboard.ts +249 -182
  520. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +8 -34
  521. package/src/resources/extensions/gsd/auto-dispatch.ts +31 -1
  522. package/src/resources/extensions/gsd/auto-post-unit.ts +131 -81
  523. package/src/resources/extensions/gsd/auto-prompts.ts +112 -15
  524. package/src/resources/extensions/gsd/auto-recovery.ts +54 -0
  525. package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
  526. package/src/resources/extensions/gsd/auto-start.ts +321 -21
  527. package/src/resources/extensions/gsd/auto-supervisor.ts +7 -0
  528. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +2 -2
  529. package/src/resources/extensions/gsd/auto-unit-closeout.ts +51 -0
  530. package/src/resources/extensions/gsd/auto-verification.ts +12 -6
  531. package/src/resources/extensions/gsd/auto-worktree.ts +267 -360
  532. package/src/resources/extensions/gsd/auto.ts +578 -126
  533. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +166 -12
  534. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +45 -37
  535. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +36 -10
  536. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +32 -19
  537. package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +5 -1
  538. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +7 -4
  539. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +6 -3
  540. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +1 -1
  541. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +384 -55
  542. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +5 -8
  543. package/src/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.ts +4 -0
  544. package/src/resources/extensions/gsd/bootstrap/system-context.ts +90 -22
  545. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +19 -2
  546. package/src/resources/extensions/gsd/clean-root-preflight.ts +32 -7
  547. package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +4 -10
  548. package/src/resources/extensions/gsd/commands/handlers/ops.ts +4 -2
  549. package/src/resources/extensions/gsd/commands-config.ts +1 -1
  550. package/src/resources/extensions/gsd/commands-eval-review.ts +2 -2
  551. package/src/resources/extensions/gsd/commands-handlers.ts +34 -15
  552. package/src/resources/extensions/gsd/context-budget.ts +44 -2
  553. package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
  554. package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -1
  555. package/src/resources/extensions/gsd/db/unit-dispatches.ts +107 -0
  556. package/src/resources/extensions/gsd/db-base-schema.ts +4 -2
  557. package/src/resources/extensions/gsd/db-migration-steps.ts +8 -0
  558. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +3 -0
  559. package/src/resources/extensions/gsd/git-service.ts +89 -10
  560. package/src/resources/extensions/gsd/gsd-db.ts +50 -13
  561. package/src/resources/extensions/gsd/guided-flow.ts +148 -49
  562. package/src/resources/extensions/gsd/health-widget-core.ts +1 -1
  563. package/src/resources/extensions/gsd/health-widget.ts +8 -9
  564. package/src/resources/extensions/gsd/init-wizard.ts +5 -1
  565. package/src/resources/extensions/gsd/journal.ts +2 -0
  566. package/src/resources/extensions/gsd/memory-store.ts +77 -12
  567. package/src/resources/extensions/gsd/migrate/command.ts +47 -1
  568. package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
  569. package/src/resources/extensions/gsd/native-git-bridge.ts +53 -19
  570. package/src/resources/extensions/gsd/notification-overlay.ts +50 -46
  571. package/src/resources/extensions/gsd/orphan-stash-audit.ts +117 -0
  572. package/src/resources/extensions/gsd/parallel-merge.ts +61 -34
  573. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +33 -35
  574. package/src/resources/extensions/gsd/parallel-orchestrator.ts +13 -3
  575. package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
  576. package/src/resources/extensions/gsd/pre-execution-checks.ts +23 -0
  577. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  578. package/src/resources/extensions/gsd/prompt-loader.ts +27 -2
  579. package/src/resources/extensions/gsd/prompts/complete-milestone.md +22 -17
  580. package/src/resources/extensions/gsd/prompts/complete-slice.md +14 -12
  581. package/src/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
  582. package/src/resources/extensions/gsd/prompts/discuss.md +20 -2
  583. package/src/resources/extensions/gsd/prompts/execute-task.md +4 -2
  584. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  585. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  586. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
  587. package/src/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  588. package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  589. package/src/resources/extensions/gsd/quick.ts +37 -2
  590. package/src/resources/extensions/gsd/recovery-classification.ts +122 -0
  591. package/src/resources/extensions/gsd/slice-cadence.ts +49 -2
  592. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +23 -9
  593. package/src/resources/extensions/gsd/state-reconciliation.ts +57 -0
  594. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +59 -89
  595. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +47 -172
  596. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +0 -35
  597. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +134 -9
  598. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +1125 -215
  599. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +80 -59
  600. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +119 -2
  601. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +3 -47
  602. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +363 -18
  603. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +175 -11
  604. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +54 -95
  605. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +67 -26
  606. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +14 -1
  607. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +32 -30
  608. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +16 -1
  609. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +32 -128
  610. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +20 -54
  611. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +20 -30
  612. package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +17 -29
  613. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +160 -0
  614. package/src/resources/extensions/gsd/tests/auto-start-time-persistence.test.ts +21 -39
  615. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +15 -24
  616. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +44 -29
  617. package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +68 -0
  618. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +39 -51
  619. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +159 -213
  620. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +15 -32
  621. package/src/resources/extensions/gsd/tests/browser-teardown.test.ts +0 -41
  622. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +15 -6
  623. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +34 -27
  624. package/src/resources/extensions/gsd/tests/cmux.test.ts +51 -53
  625. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +39 -61
  626. package/src/resources/extensions/gsd/tests/commands-config.test.ts +26 -19
  627. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +14 -1
  628. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +31 -0
  629. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +140 -0
  630. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +3 -2
  631. package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +29 -33
  632. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +45 -108
  633. package/src/resources/extensions/gsd/tests/context-budget.test.ts +10 -1
  634. package/src/resources/extensions/gsd/tests/context-store.test.ts +7 -1
  635. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +90 -31
  636. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
  637. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +46 -11
  638. package/src/resources/extensions/gsd/tests/cwd-fallback-hardening.test.ts +138 -0
  639. package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +4 -68
  640. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +24 -11
  641. package/src/resources/extensions/gsd/tests/deferred-milestone-dir-4996.test.ts +14 -65
  642. package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +44 -37
  643. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +100 -38
  644. package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +25 -15
  645. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +313 -0
  646. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +35 -17
  647. package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +16 -21
  648. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +15 -82
  649. package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
  650. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
  651. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +5 -2
  652. package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +219 -0
  653. package/src/resources/extensions/gsd/tests/finalize-survivor-branch.test.ts +151 -0
  654. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +2 -20
  655. package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +18 -26
  656. package/src/resources/extensions/gsd/tests/header-renderer.test.ts +40 -0
  657. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +10 -0
  658. package/src/resources/extensions/gsd/tests/health-widget.test.ts +14 -4
  659. package/src/resources/extensions/gsd/tests/init-skip-git.test.ts +9 -12
  660. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +40 -0
  661. package/src/resources/extensions/gsd/tests/integration/commands-eval-review.integration.test.ts +4 -2
  662. package/src/resources/extensions/gsd/tests/integration/git-locale.test.ts +31 -20
  663. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +92 -0
  664. package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +0 -47
  665. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +116 -24
  666. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +60 -202
  667. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +13 -56
  668. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +248 -11
  669. package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +32 -0
  670. package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -0
  671. package/src/resources/extensions/gsd/tests/lazy-pi-tui-import.test.ts +44 -6
  672. package/src/resources/extensions/gsd/tests/memory-decay-factor.test.ts +90 -0
  673. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +21 -35
  674. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +77 -12
  675. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
  676. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
  677. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +267 -0
  678. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +88 -98
  679. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +70 -278
  680. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +34 -2
  681. package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +37 -30
  682. package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +32 -28
  683. package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +78 -41
  684. package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +44 -0
  685. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +12 -182
  686. package/src/resources/extensions/gsd/tests/orphan-merge-bootstrap.test.ts +144 -0
  687. package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +201 -0
  688. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +38 -6
  689. package/src/resources/extensions/gsd/tests/parallel-orchestrator-fast-forward.test.ts +113 -0
  690. package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +24 -37
  691. package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +9 -24
  692. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +95 -75
  693. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
  694. package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
  695. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +2 -2
  696. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +36 -22
  697. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +36 -30
  698. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +45 -5
  699. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +74 -4
  700. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +20 -22
  701. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +130 -32
  702. package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +18 -36
  703. package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +35 -73
  704. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +76 -138
  705. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +24 -1
  706. package/src/resources/extensions/gsd/tests/prompt-duplication-cuts.test.ts +230 -0
  707. package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
  708. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +70 -106
  709. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +59 -161
  710. package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +33 -29
  711. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +22 -196
  712. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +23 -93
  713. package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
  714. package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +50 -79
  715. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +27 -13
  716. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +151 -251
  717. package/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts +41 -29
  718. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +58 -69
  719. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +36 -164
  720. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +57 -41
  721. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +91 -0
  722. package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
  723. package/src/resources/extensions/gsd/tests/select-resumable-milestone.test.ts +96 -0
  724. package/src/resources/extensions/gsd/tests/session-model-override.test.ts +14 -9
  725. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +77 -0
  726. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +222 -0
  727. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +44 -42
  728. package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
  729. package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +56 -24
  730. package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +51 -11
  731. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +23 -0
  732. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +66 -50
  733. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +68 -107
  734. package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +115 -42
  735. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +21 -77
  736. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +25 -116
  737. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +21 -57
  738. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +29 -76
  739. package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +33 -24
  740. package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +39 -30
  741. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -1
  742. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +55 -0
  743. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +65 -56
  744. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +35 -40
  745. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +48 -46
  746. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +14 -102
  747. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +78 -232
  748. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +32 -35
  749. package/src/resources/extensions/gsd/tests/system-context-memory.test.ts +112 -0
  750. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +7 -9
  751. package/src/resources/extensions/gsd/tests/token-profile.test.ts +84 -309
  752. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +295 -0
  753. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +134 -341
  754. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +330 -0
  755. package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +66 -0
  756. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +136 -4
  757. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +8 -25
  758. package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +80 -1
  759. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +37 -0
  760. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -99
  761. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +43 -36
  762. package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +83 -0
  763. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -444
  764. package/src/resources/extensions/gsd/tests/workflow-dispatch-claim.test.ts +142 -0
  765. package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +44 -189
  766. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +8 -57
  767. package/src/resources/extensions/gsd/tests/workflow-protocol-excerpt.test.ts +99 -0
  768. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +3 -0
  769. package/src/resources/extensions/gsd/tests/workflow-worker-heartbeat.test.ts +32 -1
  770. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +21 -44
  771. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +27 -26
  772. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +14 -13
  773. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +197 -78
  774. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +888 -0
  775. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -18
  776. package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +22 -19
  777. package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +66 -0
  778. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +327 -0
  779. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +120 -0
  780. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +59 -2
  781. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +18 -0
  782. package/src/resources/extensions/gsd/tests/write-gate.test.ts +40 -1
  783. package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -13
  784. package/src/resources/extensions/gsd/tool-contract.ts +82 -0
  785. package/src/resources/extensions/gsd/tools/complete-milestone.ts +14 -15
  786. package/src/resources/extensions/gsd/tools/complete-task.ts +1 -1
  787. package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
  788. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
  789. package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
  790. package/src/resources/extensions/gsd/tools/memory-tools.ts +1 -0
  791. package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
  792. package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
  793. package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
  794. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +1 -1
  795. package/src/resources/extensions/gsd/tui/render-kit.ts +109 -0
  796. package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
  797. package/src/resources/extensions/gsd/unit-runtime.ts +25 -0
  798. package/src/resources/extensions/gsd/watch/header-renderer.ts +121 -79
  799. package/src/resources/extensions/gsd/watch/splash-palette.ts +11 -0
  800. package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
  801. package/src/resources/extensions/gsd/workflow-protocol.ts +160 -0
  802. package/src/resources/extensions/gsd/worktree-lifecycle.ts +1882 -0
  803. package/src/resources/extensions/gsd/worktree-safety.ts +282 -0
  804. package/src/resources/extensions/gsd/worktree-state-projection.ts +404 -0
  805. package/src/resources/extensions/gsd/worktree-telemetry.ts +7 -2
  806. package/src/resources/skills/create-gsd-extension/templates/templates.test.ts +86 -40
  807. package/src/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
  808. package/dist/resources/extensions/gsd/worktree-resolver.js +0 -733
  809. package/dist/web/standalone/.next/static/chunks/8336.631939fb583761fa.js +0 -10
  810. package/src/resources/extensions/gsd/tests/sync-layer-scope.test.ts +0 -434
  811. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +0 -1247
  812. package/src/resources/extensions/gsd/worktree-resolver.ts +0 -909
  813. /package/dist/web/standalone/.next/static/{yTuahMMuJzVnsov5PreWl → F5x9E6H9k_52fjqyql93y}/_buildManifest.js +0 -0
  814. /package/dist/web/standalone/.next/static/{yTuahMMuJzVnsov5PreWl → F5x9E6H9k_52fjqyql93y}/_ssgManifest.js +0 -0
@@ -1,1247 +0,0 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
- import { mkdtempSync, rmSync, mkdirSync, realpathSync } from "node:fs";
4
- import { tmpdir } from "node:os";
5
- import { join } from "node:path";
6
- import {
7
- WorktreeResolver,
8
- type WorktreeResolverDeps,
9
- type NotifyCtx,
10
- } from "../worktree-resolver.js";
11
- import { AutoSession } from "../auto/session.js";
12
-
13
- // ─── Helpers ─────────────────────────────────────────────────────────────────
14
-
15
- /** Track calls to mock deps for assertion. */
16
- interface CallLog {
17
- fn: string;
18
- args: unknown[];
19
- }
20
-
21
- function makeSession(
22
- overrides?: Partial<{ basePath: string; originalBasePath: string }>,
23
- ): AutoSession {
24
- const s = new AutoSession();
25
- s.basePath = overrides?.basePath ?? "/project";
26
- s.originalBasePath = overrides?.originalBasePath ?? "/project";
27
- return s;
28
- }
29
-
30
- function makeDeps(
31
- overrides?: Partial<WorktreeResolverDeps>,
32
- ): WorktreeResolverDeps & { calls: CallLog[] } {
33
- const calls: CallLog[] = [];
34
-
35
- const deps: WorktreeResolverDeps & { calls: CallLog[] } = {
36
- calls,
37
- isInAutoWorktree: (basePath: string) => {
38
- calls.push({ fn: "isInAutoWorktree", args: [basePath] });
39
- return false;
40
- },
41
- shouldUseWorktreeIsolation: () => {
42
- calls.push({ fn: "shouldUseWorktreeIsolation", args: [] });
43
- return true;
44
- },
45
- getIsolationMode: () => {
46
- calls.push({ fn: "getIsolationMode", args: [] });
47
- return "worktree";
48
- },
49
- mergeMilestoneToMain: (
50
- basePath: string,
51
- milestoneId: string,
52
- roadmapContent: string,
53
- ) => {
54
- calls.push({
55
- fn: "mergeMilestoneToMain",
56
- args: [basePath, milestoneId, roadmapContent],
57
- });
58
- return { pushed: false, codeFilesChanged: true };
59
- },
60
- syncWorktreeStateBack: (
61
- mainBasePath: string,
62
- worktreePath: string,
63
- milestoneId: string,
64
- ) => {
65
- calls.push({
66
- fn: "syncWorktreeStateBack",
67
- args: [mainBasePath, worktreePath, milestoneId],
68
- });
69
- return { synced: [] };
70
- },
71
- teardownAutoWorktree: (
72
- basePath: string,
73
- milestoneId: string,
74
- opts?: { preserveBranch?: boolean },
75
- ) => {
76
- calls.push({
77
- fn: "teardownAutoWorktree",
78
- args: [basePath, milestoneId, opts],
79
- });
80
- },
81
- createAutoWorktree: (basePath: string, milestoneId: string) => {
82
- calls.push({ fn: "createAutoWorktree", args: [basePath, milestoneId] });
83
- return `/project/.gsd/worktrees/${milestoneId}`;
84
- },
85
- enterAutoWorktree: (basePath: string, milestoneId: string) => {
86
- calls.push({ fn: "enterAutoWorktree", args: [basePath, milestoneId] });
87
- return `/project/.gsd/worktrees/${milestoneId}`;
88
- },
89
- getAutoWorktreePath: (basePath: string, milestoneId: string) => {
90
- calls.push({ fn: "getAutoWorktreePath", args: [basePath, milestoneId] });
91
- return null;
92
- },
93
- autoCommitCurrentBranch: (
94
- basePath: string,
95
- reason: string,
96
- milestoneId: string,
97
- ) => {
98
- calls.push({
99
- fn: "autoCommitCurrentBranch",
100
- args: [basePath, reason, milestoneId],
101
- });
102
- },
103
- getCurrentBranch: (basePath: string) => {
104
- calls.push({ fn: "getCurrentBranch", args: [basePath] });
105
- return "main";
106
- },
107
- autoWorktreeBranch: (milestoneId: string) => {
108
- calls.push({ fn: "autoWorktreeBranch", args: [milestoneId] });
109
- return `milestone/${milestoneId}`;
110
- },
111
- resolveMilestoneFile: (
112
- basePath: string,
113
- milestoneId: string,
114
- fileType: string,
115
- ) => {
116
- calls.push({
117
- fn: "resolveMilestoneFile",
118
- args: [basePath, milestoneId, fileType],
119
- });
120
- return `/project/.gsd/milestones/${milestoneId}/${milestoneId}-ROADMAP.md`;
121
- },
122
- readFileSync: (path: string, _encoding: string) => {
123
- calls.push({ fn: "readFileSync", args: [path] });
124
- return "# Roadmap\n- [x] S01: Slice one\n";
125
- },
126
- GitServiceImpl: class MockGitServiceImpl {
127
- basePath: string;
128
- gitConfig: unknown;
129
- constructor(basePath: string, gitConfig: unknown) {
130
- calls.push({ fn: "GitServiceImpl", args: [basePath, gitConfig] });
131
- this.basePath = basePath;
132
- this.gitConfig = gitConfig;
133
- }
134
- } as unknown as WorktreeResolverDeps["GitServiceImpl"],
135
- loadEffectiveGSDPreferences: () => {
136
- calls.push({ fn: "loadEffectiveGSDPreferences", args: [] });
137
- return { preferences: { git: {} } };
138
- },
139
- invalidateAllCaches: () => {
140
- calls.push({ fn: "invalidateAllCaches", args: [] });
141
- },
142
- captureIntegrationBranch: (
143
- basePath: string,
144
- mid: string | undefined,
145
- ) => {
146
- calls.push({
147
- fn: "captureIntegrationBranch",
148
- args: [basePath, mid],
149
- });
150
- },
151
- enterBranchModeForMilestone: (basePath: string, milestoneId: string) => {
152
- calls.push({ fn: "enterBranchModeForMilestone", args: [basePath, milestoneId] });
153
- },
154
- ...overrides,
155
- };
156
-
157
- // Re-apply overrides that add the call tracking
158
- if (overrides) {
159
- for (const [key, val] of Object.entries(overrides)) {
160
- if (key !== "calls") {
161
- (deps as unknown as Record<string, unknown>)[key] = val;
162
- }
163
- }
164
- }
165
-
166
- return deps;
167
- }
168
-
169
- function makeNotifyCtx(): NotifyCtx & {
170
- messages: Array<{ msg: string; level?: string }>;
171
- } {
172
- const messages: Array<{ msg: string; level?: string }> = [];
173
- return {
174
- messages,
175
- notify: (msg: string, level?: "info" | "warning" | "error" | "success") => {
176
- messages.push({ msg, level });
177
- },
178
- };
179
- }
180
-
181
- function findCalls(calls: CallLog[], fn: string): CallLog[] {
182
- return calls.filter((c) => c.fn === fn);
183
- }
184
-
185
- // ─── Getter Tests ────────────────────────────────────────────────────────────
186
-
187
- test("workPath returns s.basePath", () => {
188
- const s = makeSession({ basePath: "/project/.gsd/worktrees/M001" });
189
- const resolver = new WorktreeResolver(s, makeDeps());
190
- assert.equal(resolver.workPath, "/project/.gsd/worktrees/M001");
191
- });
192
-
193
- test("projectRoot returns originalBasePath when set", () => {
194
- const s = makeSession({
195
- basePath: "/project/.gsd/worktrees/M001",
196
- originalBasePath: "/project",
197
- });
198
- const resolver = new WorktreeResolver(s, makeDeps());
199
- assert.equal(resolver.projectRoot, "/project");
200
- });
201
-
202
- test("projectRoot falls back to basePath when originalBasePath is empty", () => {
203
- const s = makeSession({ basePath: "/project", originalBasePath: "" });
204
- const resolver = new WorktreeResolver(s, makeDeps());
205
- assert.equal(resolver.projectRoot, "/project");
206
- });
207
-
208
- test("lockPath returns originalBasePath when set (same as lockBase)", () => {
209
- const s = makeSession({
210
- basePath: "/project/.gsd/worktrees/M001",
211
- originalBasePath: "/project",
212
- });
213
- const resolver = new WorktreeResolver(s, makeDeps());
214
- assert.equal(resolver.lockPath, "/project");
215
- });
216
-
217
- test("lockPath falls back to basePath when originalBasePath is empty", () => {
218
- const s = makeSession({ basePath: "/project", originalBasePath: "" });
219
- const resolver = new WorktreeResolver(s, makeDeps());
220
- assert.equal(resolver.lockPath, "/project");
221
- });
222
-
223
- // ─── enterMilestone Tests ────────────────────────────────────────────────────
224
-
225
- test("enterMilestone creates new worktree when none exists", () => {
226
- const s = makeSession();
227
- const deps = makeDeps({
228
- getAutoWorktreePath: () => null,
229
- });
230
- const ctx = makeNotifyCtx();
231
- const resolver = new WorktreeResolver(s, deps);
232
-
233
- resolver.enterMilestone("M001", ctx);
234
-
235
- assert.equal(s.basePath, "/project/.gsd/worktrees/M001");
236
- assert.equal(findCalls(deps.calls, "createAutoWorktree").length, 1);
237
- assert.equal(findCalls(deps.calls, "enterAutoWorktree").length, 0);
238
- assert.equal(findCalls(deps.calls, "GitServiceImpl").length, 1);
239
- assert.ok(
240
- ctx.messages.some(
241
- (m) => m.level === "info" && m.msg.includes("Entered worktree"),
242
- ),
243
- );
244
- });
245
-
246
- test("enterMilestone enters existing worktree instead of creating", () => {
247
- const s = makeSession();
248
- const deps = makeDeps({
249
- getAutoWorktreePath: () => "/project/.gsd/worktrees/M001",
250
- });
251
- const ctx = makeNotifyCtx();
252
- const resolver = new WorktreeResolver(s, deps);
253
-
254
- resolver.enterMilestone("M001", ctx);
255
-
256
- assert.equal(s.basePath, "/project/.gsd/worktrees/M001");
257
- assert.equal(findCalls(deps.calls, "enterAutoWorktree").length, 1);
258
- assert.equal(findCalls(deps.calls, "createAutoWorktree").length, 0);
259
- });
260
-
261
- test("enterMilestone is no-op when isolation mode is none", () => {
262
- const s = makeSession();
263
- const deps = makeDeps({
264
- getIsolationMode: () => "none",
265
- });
266
- const ctx = makeNotifyCtx();
267
- const resolver = new WorktreeResolver(s, deps);
268
-
269
- resolver.enterMilestone("M001", ctx);
270
-
271
- assert.equal(s.basePath, "/project"); // unchanged
272
- assert.equal(findCalls(deps.calls, "createAutoWorktree").length, 0);
273
- assert.equal(findCalls(deps.calls, "enterAutoWorktree").length, 0);
274
- assert.equal(findCalls(deps.calls, "enterBranchModeForMilestone").length, 0);
275
- });
276
-
277
- test("enterMilestone passes project root to isolation mode guard", () => {
278
- const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
279
- let checkedBasePath: string | undefined;
280
- const deps = makeDeps({
281
- getIsolationMode: (basePath?: string) => {
282
- checkedBasePath = basePath;
283
- return "none";
284
- },
285
- });
286
- const ctx = makeNotifyCtx();
287
- const resolver = new WorktreeResolver(s, deps);
288
-
289
- resolver.enterMilestone("M001", ctx);
290
-
291
- assert.equal(checkedBasePath, "/project");
292
- assert.equal(findCalls(deps.calls, "createAutoWorktree").length, 0);
293
- });
294
-
295
- test("enterMilestone does NOT update basePath on creation failure", () => {
296
- const s = makeSession();
297
- const deps = makeDeps({
298
- getAutoWorktreePath: () => null,
299
- createAutoWorktree: () => {
300
- throw new Error("disk full");
301
- },
302
- });
303
- const ctx = makeNotifyCtx();
304
- const resolver = new WorktreeResolver(s, deps);
305
-
306
- resolver.enterMilestone("M001", ctx);
307
-
308
- assert.equal(s.basePath, "/project"); // unchanged — error recovery
309
- assert.ok(
310
- ctx.messages.some(
311
- (m) => m.level === "warning" && m.msg.includes("disk full"),
312
- ),
313
- );
314
- });
315
-
316
- test("enterMilestone uses originalBasePath as base for worktree ops", () => {
317
- const s = makeSession({
318
- basePath: "/project/.gsd/worktrees/M001",
319
- originalBasePath: "/project",
320
- });
321
- let createdFrom = "";
322
- const deps = makeDeps({
323
- getAutoWorktreePath: () => null,
324
- createAutoWorktree: (basePath: string, _mid: string) => {
325
- createdFrom = basePath;
326
- return "/project/.gsd/worktrees/M002";
327
- },
328
- });
329
- const ctx = makeNotifyCtx();
330
- const resolver = new WorktreeResolver(s, deps);
331
-
332
- resolver.enterMilestone("M002", ctx);
333
-
334
- assert.equal(createdFrom, "/project"); // uses originalBasePath, not current basePath
335
- });
336
-
337
- test("enterMilestone does not create double-nested worktree when originalBasePath is empty and basePath is a worktree path", () => {
338
- // Regression test for #3729: when s.originalBasePath is "" (falsy) and
339
- // s.basePath is already a worktree path, the expression
340
- // `this.s.originalBasePath || this.s.basePath` evaluates to the worktree
341
- // path. Passing that to createAutoWorktree produces a doubly-nested path
342
- // like /project/.gsd/worktrees/M001/.gsd/worktrees/M002.
343
- const wtPath = "/project/.gsd/worktrees/M001";
344
- const s = makeSession({
345
- basePath: wtPath,
346
- originalBasePath: "/project", // will be overwritten below to simulate the bug
347
- });
348
- // Simulate the real bug: originalBasePath is "" (falsy) as it is when AutoSession
349
- // is constructed fresh or reset() is called without auto-start re-setting it.
350
- s.originalBasePath = "";
351
-
352
- let createdFromPath = "";
353
- const deps = makeDeps({
354
- getAutoWorktreePath: () => null,
355
- createAutoWorktree: (basePath: string, _mid: string) => {
356
- createdFromPath = basePath;
357
- return `/project/.gsd/worktrees/M002`;
358
- },
359
- });
360
- const ctx = makeNotifyCtx();
361
- const resolver = new WorktreeResolver(s, deps);
362
-
363
- resolver.enterMilestone("M002", ctx);
364
-
365
- // The path passed to createAutoWorktree must be the project root, NOT the
366
- // worktree path. If it equals wtPath the worktree would be created at
367
- // /project/.gsd/worktrees/M001/.gsd/worktrees/M002 (double-nesting).
368
- assert.ok(
369
- !createdFromPath.includes("/.gsd/worktrees/"),
370
- `createAutoWorktree must be called with project root, got: "${createdFromPath}"`,
371
- );
372
- });
373
-
374
- // ─── enterMilestone Tests (branch mode) ──────────────────────────────────────
375
-
376
- test("enterMilestone in branch mode calls enterBranchModeForMilestone and rebuilds GitService", () => {
377
- const s = makeSession();
378
- const deps = makeDeps({
379
- getIsolationMode: () => "branch",
380
- });
381
- const ctx = makeNotifyCtx();
382
- const resolver = new WorktreeResolver(s, deps);
383
-
384
- resolver.enterMilestone("M001", ctx);
385
-
386
- // Branch mode: no worktree created, basePath unchanged
387
- assert.equal(s.basePath, "/project");
388
- assert.equal(findCalls(deps.calls, "enterBranchModeForMilestone").length, 1);
389
- assert.equal(findCalls(deps.calls, "createAutoWorktree").length, 0);
390
- assert.equal(findCalls(deps.calls, "enterAutoWorktree").length, 0);
391
- assert.equal(findCalls(deps.calls, "GitServiceImpl").length, 1);
392
- assert.ok(ctx.messages.some((m) => m.level === "info" && m.msg.includes("milestone/M001")));
393
- });
394
-
395
- test("enterMilestone in branch mode uses originalBasePath as base", () => {
396
- const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
397
- let calledWith = "";
398
- const deps = makeDeps({
399
- getIsolationMode: () => "branch",
400
- enterBranchModeForMilestone: (basePath: string, _mid: string) => {
401
- calledWith = basePath;
402
- },
403
- });
404
- const ctx = makeNotifyCtx();
405
- const resolver = new WorktreeResolver(s, deps);
406
-
407
- resolver.enterMilestone("M001", ctx);
408
-
409
- assert.equal(calledWith, "/project");
410
- });
411
-
412
- test("enterMilestone in branch mode degrades isolation on failure", () => {
413
- const s = makeSession();
414
- const deps = makeDeps({
415
- getIsolationMode: () => "branch",
416
- enterBranchModeForMilestone: () => {
417
- throw new Error("checkout failed");
418
- },
419
- });
420
- const ctx = makeNotifyCtx();
421
- const resolver = new WorktreeResolver(s, deps);
422
-
423
- resolver.enterMilestone("M001", ctx);
424
-
425
- assert.equal(s.basePath, "/project"); // unchanged
426
- assert.ok(s.isolationDegraded);
427
- assert.ok(ctx.messages.some((m) => m.level === "warning" && m.msg.includes("checkout failed")));
428
- });
429
-
430
- test("enterMilestone branch mode is skipped when isolationDegraded", () => {
431
- const s = makeSession();
432
- s.isolationDegraded = true;
433
- const deps = makeDeps({
434
- getIsolationMode: () => "branch",
435
- });
436
- const ctx = makeNotifyCtx();
437
- const resolver = new WorktreeResolver(s, deps);
438
-
439
- resolver.enterMilestone("M001", ctx);
440
-
441
- assert.equal(findCalls(deps.calls, "enterBranchModeForMilestone").length, 0);
442
- assert.equal(findCalls(deps.calls, "createAutoWorktree").length, 0);
443
- });
444
-
445
- // ─── exitMilestone Tests ─────────────────────────────────────────────────────
446
-
447
- test("exitMilestone commits, tears down, and resets basePath", () => {
448
- const s = makeSession({
449
- basePath: "/project/.gsd/worktrees/M001",
450
- originalBasePath: "/project",
451
- });
452
- const deps = makeDeps({
453
- isInAutoWorktree: () => true,
454
- });
455
- const ctx = makeNotifyCtx();
456
- const resolver = new WorktreeResolver(s, deps);
457
-
458
- resolver.exitMilestone("M001", ctx);
459
-
460
- assert.equal(s.basePath, "/project"); // reset to originalBasePath
461
- assert.equal(findCalls(deps.calls, "autoCommitCurrentBranch").length, 1);
462
- assert.equal(findCalls(deps.calls, "teardownAutoWorktree").length, 1);
463
- assert.equal(findCalls(deps.calls, "GitServiceImpl").length, 1); // rebuilt
464
- assert.equal(findCalls(deps.calls, "invalidateAllCaches").length, 1);
465
- });
466
-
467
- test("exitMilestone is no-op when not in worktree", () => {
468
- const s = makeSession();
469
- const deps = makeDeps({
470
- isInAutoWorktree: () => false,
471
- });
472
- const ctx = makeNotifyCtx();
473
- const resolver = new WorktreeResolver(s, deps);
474
-
475
- resolver.exitMilestone("M001", ctx);
476
-
477
- assert.equal(s.basePath, "/project"); // unchanged
478
- assert.equal(findCalls(deps.calls, "autoCommitCurrentBranch").length, 0);
479
- assert.equal(findCalls(deps.calls, "teardownAutoWorktree").length, 0);
480
- });
481
-
482
- test("exitMilestone passes preserveBranch option", () => {
483
- const s = makeSession({
484
- basePath: "/project/.gsd/worktrees/M001",
485
- originalBasePath: "/project",
486
- });
487
- let preserveOpts: unknown = null;
488
- const deps = makeDeps({
489
- isInAutoWorktree: () => true,
490
- teardownAutoWorktree: (
491
- _basePath: string,
492
- _mid: string,
493
- opts?: { preserveBranch?: boolean },
494
- ) => {
495
- preserveOpts = opts;
496
- },
497
- });
498
- const ctx = makeNotifyCtx();
499
- const resolver = new WorktreeResolver(s, deps);
500
-
501
- resolver.exitMilestone("M001", ctx, { preserveBranch: true });
502
-
503
- assert.deepEqual(preserveOpts, { preserveBranch: true });
504
- });
505
-
506
- test("exitMilestone still resets basePath even if auto-commit fails", () => {
507
- const s = makeSession({
508
- basePath: "/project/.gsd/worktrees/M001",
509
- originalBasePath: "/project",
510
- });
511
- const deps = makeDeps({
512
- isInAutoWorktree: () => true,
513
- autoCommitCurrentBranch: () => {
514
- throw new Error("commit error");
515
- },
516
- });
517
- const ctx = makeNotifyCtx();
518
- const resolver = new WorktreeResolver(s, deps);
519
-
520
- resolver.exitMilestone("M001", ctx);
521
-
522
- // Should still complete: reset basePath, rebuild git service
523
- assert.equal(s.basePath, "/project");
524
- assert.equal(findCalls(deps.calls, "GitServiceImpl").length, 1);
525
- });
526
-
527
- // ─── mergeAndExit Tests (worktree mode) ──────────────────────────────────────
528
-
529
- test("mergeAndExit in worktree mode reads roadmap and merges", () => {
530
- const s = makeSession({
531
- basePath: "/project/.gsd/worktrees/M001",
532
- originalBasePath: "/project",
533
- });
534
- const deps = makeDeps({
535
- isInAutoWorktree: () => true,
536
- getIsolationMode: () => "worktree",
537
- });
538
- const ctx = makeNotifyCtx();
539
- const resolver = new WorktreeResolver(s, deps);
540
-
541
- resolver.mergeAndExit("M001", ctx);
542
-
543
- assert.equal(findCalls(deps.calls, "syncWorktreeStateBack").length, 1);
544
- assert.equal(findCalls(deps.calls, "resolveMilestoneFile").length, 1);
545
- assert.equal(findCalls(deps.calls, "readFileSync").length, 1);
546
- assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 1);
547
- assert.equal(s.basePath, "/project"); // restored
548
- assert.ok(ctx.messages.some((m) => m.msg.includes("merged to main")));
549
- });
550
-
551
- test("mergeAndExit in worktree mode shows pushed status", () => {
552
- const s = makeSession({
553
- basePath: "/project/.gsd/worktrees/M001",
554
- originalBasePath: "/project",
555
- });
556
- const deps = makeDeps({
557
- isInAutoWorktree: () => true,
558
- getIsolationMode: () => "worktree",
559
- mergeMilestoneToMain: () => ({ pushed: true, codeFilesChanged: true }),
560
- });
561
- const ctx = makeNotifyCtx();
562
- const resolver = new WorktreeResolver(s, deps);
563
-
564
- resolver.mergeAndExit("M001", ctx);
565
-
566
- assert.ok(ctx.messages.some((m) => m.msg.includes("Pushed to remote")));
567
- });
568
-
569
- test("mergeAndExit falls back to teardown with preserveBranch when roadmap is missing (#1573)", () => {
570
- const s = makeSession({
571
- basePath: "/project/.gsd/worktrees/M001",
572
- originalBasePath: "/project",
573
- });
574
- const deps = makeDeps({
575
- isInAutoWorktree: () => true,
576
- getIsolationMode: () => "worktree",
577
- resolveMilestoneFile: () => null,
578
- });
579
- const ctx = makeNotifyCtx();
580
- const resolver = new WorktreeResolver(s, deps);
581
-
582
- resolver.mergeAndExit("M001", ctx);
583
-
584
- const teardownCalls = findCalls(deps.calls, "teardownAutoWorktree");
585
- assert.equal(teardownCalls.length, 1);
586
- // Branch must be preserved so commits are not orphaned (#1573)
587
- assert.deepEqual(teardownCalls[0].args[2], { preserveBranch: true });
588
- assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 0);
589
- assert.equal(s.basePath, "/project"); // restored
590
- assert.ok(ctx.messages.some((m) => m.msg.includes("branch preserved")));
591
- });
592
-
593
- test("mergeAndExit resolves roadmap from worktree when missing at project root (#1573)", () => {
594
- const s = makeSession({
595
- basePath: "/project/.gsd/worktrees/M001",
596
- originalBasePath: "/project",
597
- });
598
- // resolveMilestoneFile returns null for project root, returns path for worktree
599
- const deps = makeDeps({
600
- isInAutoWorktree: () => true,
601
- getIsolationMode: () => "worktree",
602
- resolveMilestoneFile: (basePath: string) => {
603
- if (basePath === "/project") return null; // missing at project root
604
- if (basePath === "/project/.gsd/worktrees/M001") {
605
- return "/project/.gsd/worktrees/M001/.gsd/milestones/M001/M001-ROADMAP.md";
606
- }
607
- return null;
608
- },
609
- });
610
- const ctx = makeNotifyCtx();
611
- const resolver = new WorktreeResolver(s, deps);
612
-
613
- resolver.mergeAndExit("M001", ctx);
614
-
615
- // Should have called mergeMilestoneToMain, not bare teardown
616
- assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 1);
617
- // #2945 Bug 3: secondary teardown is now called after merge for cleanup
618
- assert.equal(findCalls(deps.calls, "teardownAutoWorktree").length, 1);
619
- assert.equal(s.basePath, "/project"); // restored
620
- assert.ok(ctx.messages.some((m) => m.msg.includes("merged to main")));
621
- });
622
-
623
- test("mergeAndExit in worktree mode restores to project root on merge failure", () => {
624
- const s = makeSession({
625
- basePath: "/project/.gsd/worktrees/M001",
626
- originalBasePath: "/project",
627
- });
628
- const deps = makeDeps({
629
- isInAutoWorktree: () => true,
630
- getIsolationMode: () => "worktree",
631
- mergeMilestoneToMain: () => {
632
- throw new Error("conflict in main");
633
- },
634
- });
635
- const ctx = makeNotifyCtx();
636
- const resolver = new WorktreeResolver(s, deps);
637
-
638
- // Error propagates (#4380) — callers handle recovery. restoreToProjectRoot()
639
- // still runs before re-throw so state is consistent for the caller.
640
- assert.throws(() => resolver.mergeAndExit("M001", ctx), /conflict in main/);
641
-
642
- assert.equal(s.basePath, "/project"); // error recovery — restored before re-throw
643
- assert.ok(
644
- ctx.messages.some(
645
- (m) => m.level === "warning" && m.msg.includes("conflict in main"),
646
- ),
647
- );
648
- assert.equal(findCalls(deps.calls, "GitServiceImpl").length, 1); // rebuilt after recovery
649
- });
650
-
651
- test("mergeAndExit failure message tells user worktree and branch are preserved (#1668)", () => {
652
- // Regression test: before the fix, the failure message was a bare
653
- // "Milestone merge failed: <reason>" with no recovery guidance. Users were
654
- // left confused about whether their code had been deleted. The new message
655
- // explicitly states that the worktree and branch are preserved and what to do.
656
- const s = makeSession({
657
- basePath: "/project/.gsd/worktrees/M001",
658
- originalBasePath: "/project",
659
- });
660
- const deps = makeDeps({
661
- isInAutoWorktree: () => true,
662
- getIsolationMode: () => "worktree",
663
- mergeMilestoneToMain: () => {
664
- throw new Error("pathspec 'main' did not match any file(s) known to git");
665
- },
666
- });
667
- const ctx = makeNotifyCtx();
668
- const resolver = new WorktreeResolver(s, deps);
669
-
670
- // Error propagates (#4380) — notification is still emitted before re-throw
671
- assert.throws(() => resolver.mergeAndExit("M001", ctx), /pathspec 'main' did not match/);
672
-
673
- const warning = ctx.messages.find((m) => m.level === "warning");
674
- assert.ok(warning, "a warning message is emitted");
675
- // Must contain the original error
676
- assert.ok(warning!.msg.includes("pathspec 'main' did not match"), "warning includes the original error");
677
- // Must tell the user their work is safe
678
- assert.ok(
679
- warning!.msg.includes("preserved"),
680
- "warning tells user the worktree and branch are preserved",
681
- );
682
- // Must suggest a recovery action
683
- assert.ok(
684
- warning!.msg.includes("retry") || warning!.msg.includes("manually"),
685
- "warning suggests a recovery action",
686
- );
687
- });
688
-
689
- test("mergeAndExit failure message references /gsd dispatch complete-milestone, not /complete-milestone (#1891)", () => {
690
- // Regression test: the failure notification previously told users to
691
- // "retry /complete-milestone" — a command that does not exist. The correct
692
- // recovery command is "/gsd dispatch complete-milestone".
693
- const s = makeSession({
694
- basePath: "/project/.gsd/worktrees/M001",
695
- originalBasePath: "/project",
696
- });
697
- const deps = makeDeps({
698
- isInAutoWorktree: () => true,
699
- getIsolationMode: () => "worktree",
700
- mergeMilestoneToMain: () => {
701
- throw new Error("dirty working tree");
702
- },
703
- });
704
- const ctx = makeNotifyCtx();
705
- const resolver = new WorktreeResolver(s, deps);
706
-
707
- // Error propagates (#4380) — notification is still emitted before re-throw
708
- assert.throws(() => resolver.mergeAndExit("M001", ctx), /dirty working tree/);
709
-
710
- const warning = ctx.messages.find((m) => m.level === "warning");
711
- assert.ok(warning, "a warning message is emitted");
712
- // Must reference the correct dispatch command
713
- assert.ok(
714
- warning!.msg.includes("/gsd dispatch complete-milestone"),
715
- "warning references /gsd dispatch complete-milestone, not bare /complete-milestone",
716
- );
717
- // Must NOT contain the bare (incorrect) command without the dispatch prefix
718
- assert.ok(
719
- !warning!.msg.match(/retry\s+\/complete-milestone(?!\S)/),
720
- "warning must not reference the non-existent /complete-milestone command",
721
- );
722
- });
723
-
724
- // ─── mergeAndExit Tests (branch mode) ────────────────────────────────────────
725
-
726
- test("mergeAndExit in branch mode merges when on milestone branch", () => {
727
- const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
728
- const deps = makeDeps({
729
- isInAutoWorktree: () => false,
730
- getIsolationMode: () => "branch",
731
- getCurrentBranch: () => "milestone/M001",
732
- autoWorktreeBranch: () => "milestone/M001",
733
- });
734
- const ctx = makeNotifyCtx();
735
- const resolver = new WorktreeResolver(s, deps);
736
-
737
- resolver.mergeAndExit("M001", ctx);
738
-
739
- assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 1);
740
- assert.ok(ctx.messages.some((m) => m.msg.includes("branch mode")));
741
- });
742
-
743
- test("mergeAndExit in branch mode skips when not on milestone branch", () => {
744
- const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
745
- const deps = makeDeps({
746
- isInAutoWorktree: () => false,
747
- getIsolationMode: () => "branch",
748
- getCurrentBranch: () => "main",
749
- autoWorktreeBranch: () => "milestone/M001",
750
- });
751
- const ctx = makeNotifyCtx();
752
- const resolver = new WorktreeResolver(s, deps);
753
-
754
- resolver.mergeAndExit("M001", ctx);
755
-
756
- assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 0);
757
- assert.equal(ctx.messages.length, 0);
758
- });
759
-
760
- test("mergeAndExit in branch mode handles merge failure gracefully", () => {
761
- const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
762
- const deps = makeDeps({
763
- isInAutoWorktree: () => false,
764
- getIsolationMode: () => "branch",
765
- getCurrentBranch: () => "milestone/M001",
766
- autoWorktreeBranch: () => "milestone/M001",
767
- mergeMilestoneToMain: () => {
768
- throw new Error("branch merge conflict");
769
- },
770
- });
771
- const ctx = makeNotifyCtx();
772
- const resolver = new WorktreeResolver(s, deps);
773
-
774
- // Error propagates (#4380) — notification is still emitted before re-throw
775
- assert.throws(() => resolver.mergeAndExit("M001", ctx), /branch merge conflict/);
776
-
777
- assert.ok(
778
- ctx.messages.some(
779
- (m) => m.level === "warning" && m.msg.includes("branch merge conflict"),
780
- ),
781
- );
782
- });
783
-
784
- test("mergeAndExit in branch mode skips when no roadmap", () => {
785
- const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
786
- const deps = makeDeps({
787
- isInAutoWorktree: () => false,
788
- getIsolationMode: () => "branch",
789
- getCurrentBranch: () => "milestone/M001",
790
- autoWorktreeBranch: () => "milestone/M001",
791
- resolveMilestoneFile: () => null,
792
- });
793
- const ctx = makeNotifyCtx();
794
- const resolver = new WorktreeResolver(s, deps);
795
-
796
- resolver.mergeAndExit("M001", ctx);
797
-
798
- assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 0);
799
- });
800
-
801
- test("mergeAndExit in branch mode rebuilds GitService after merge", () => {
802
- const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
803
- const deps = makeDeps({
804
- isInAutoWorktree: () => false,
805
- getIsolationMode: () => "branch",
806
- getCurrentBranch: () => "milestone/M001",
807
- autoWorktreeBranch: () => "milestone/M001",
808
- });
809
- const ctx = makeNotifyCtx();
810
- const resolver = new WorktreeResolver(s, deps);
811
-
812
- resolver.mergeAndExit("M001", ctx);
813
-
814
- assert.equal(findCalls(deps.calls, "GitServiceImpl").length, 1);
815
- });
816
-
817
- // ─── mergeAndExit Tests (none mode) ──────────────────────────────────────────
818
-
819
- test("mergeAndExit in none mode is a no-op", () => {
820
- const s = makeSession();
821
- const deps = makeDeps({
822
- getIsolationMode: () => "none",
823
- });
824
- const ctx = makeNotifyCtx();
825
- const resolver = new WorktreeResolver(s, deps);
826
-
827
- resolver.mergeAndExit("M001", ctx);
828
-
829
- assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 0);
830
- assert.equal(findCalls(deps.calls, "teardownAutoWorktree").length, 0);
831
- assert.equal(ctx.messages.length, 0);
832
- });
833
-
834
- // ─── #1906 — metadata-only merge warning ────────────────────────────────────
835
-
836
- test("mergeAndExit warns when merge contains no code changes (#1906)", () => {
837
- const s = makeSession({
838
- basePath: "/project/.gsd/worktrees/M001",
839
- originalBasePath: "/project",
840
- });
841
- const deps = makeDeps({
842
- isInAutoWorktree: () => true,
843
- getIsolationMode: () => "worktree",
844
- mergeMilestoneToMain: () => ({ pushed: false, codeFilesChanged: false }),
845
- });
846
- const ctx = makeNotifyCtx();
847
- const resolver = new WorktreeResolver(s, deps);
848
-
849
- resolver.mergeAndExit("M001", ctx);
850
-
851
- assert.ok(
852
- ctx.messages.some((m) => m.msg.includes("NO code changes") && m.level === "warning"),
853
- "must emit warning when only .gsd/ metadata was merged",
854
- );
855
- assert.ok(
856
- !ctx.messages.some((m) => m.msg.includes("merged to main") && m.level === "info"),
857
- "must NOT emit success-style info notification for metadata-only merge",
858
- );
859
- });
860
-
861
- test("mergeAndExit emits info when merge contains code changes (#1906)", () => {
862
- const s = makeSession({
863
- basePath: "/project/.gsd/worktrees/M001",
864
- originalBasePath: "/project",
865
- });
866
- const deps = makeDeps({
867
- isInAutoWorktree: () => true,
868
- getIsolationMode: () => "worktree",
869
- mergeMilestoneToMain: () => ({ pushed: false, codeFilesChanged: true }),
870
- });
871
- const ctx = makeNotifyCtx();
872
- const resolver = new WorktreeResolver(s, deps);
873
-
874
- resolver.mergeAndExit("M001", ctx);
875
-
876
- assert.ok(
877
- ctx.messages.some((m) => m.msg.includes("merged to main") && m.level === "info"),
878
- "must emit info notification when code files were merged",
879
- );
880
- assert.ok(
881
- !ctx.messages.some((m) => m.msg.includes("NO code changes")),
882
- "must NOT emit metadata-only warning when code files were merged",
883
- );
884
- });
885
-
886
- test("mergeAndExit branch mode warns when merge contains no code changes (#1906)", () => {
887
- const s = makeSession({
888
- basePath: "/project",
889
- originalBasePath: "/project",
890
- });
891
- const deps = makeDeps({
892
- isInAutoWorktree: () => false,
893
- getIsolationMode: () => "branch",
894
- getCurrentBranch: () => "milestone/M001",
895
- autoWorktreeBranch: () => "milestone/M001",
896
- mergeMilestoneToMain: () => ({ pushed: false, codeFilesChanged: false }),
897
- });
898
- const ctx = makeNotifyCtx();
899
- const resolver = new WorktreeResolver(s, deps);
900
-
901
- resolver.mergeAndExit("M001", ctx);
902
-
903
- assert.ok(
904
- ctx.messages.some((m) => m.msg.includes("NO code changes") && m.level === "warning"),
905
- "branch mode must emit warning when only .gsd/ metadata was merged",
906
- );
907
- });
908
-
909
- // ─── mergeAndEnterNext Tests ─────────────────────────────────────────────────
910
-
911
- test("mergeAndEnterNext calls mergeAndExit then enterMilestone", () => {
912
- const s = makeSession({
913
- basePath: "/project/.gsd/worktrees/M001",
914
- originalBasePath: "/project",
915
- });
916
- const callOrder: string[] = [];
917
- const deps = makeDeps({
918
- isInAutoWorktree: () => true,
919
- getIsolationMode: () => "worktree",
920
- shouldUseWorktreeIsolation: () => true,
921
- mergeMilestoneToMain: (
922
- basePath: string,
923
- milestoneId: string,
924
- _roadmap: string,
925
- ) => {
926
- callOrder.push(`merge:${milestoneId}`);
927
- return { pushed: false, codeFilesChanged: true };
928
- },
929
- getAutoWorktreePath: () => null,
930
- createAutoWorktree: (basePath: string, milestoneId: string) => {
931
- callOrder.push(`create:${milestoneId}`);
932
- return `/project/.gsd/worktrees/${milestoneId}`;
933
- },
934
- });
935
- const ctx = makeNotifyCtx();
936
- const resolver = new WorktreeResolver(s, deps);
937
-
938
- resolver.mergeAndEnterNext("M001", "M002", ctx);
939
-
940
- assert.deepEqual(callOrder, ["merge:M001", "create:M002"]);
941
- assert.equal(s.basePath, "/project/.gsd/worktrees/M002");
942
- });
943
-
944
- test("mergeAndEnterNext enters next milestone even if merge fails", () => {
945
- const s = makeSession({
946
- basePath: "/project/.gsd/worktrees/M001",
947
- originalBasePath: "/project",
948
- });
949
- const deps = makeDeps({
950
- isInAutoWorktree: (basePath: string) => basePath.includes("worktrees"),
951
- getIsolationMode: () => "worktree",
952
- shouldUseWorktreeIsolation: () => true,
953
- mergeMilestoneToMain: () => {
954
- throw new Error("merge failed");
955
- },
956
- getAutoWorktreePath: () => null,
957
- createAutoWorktree: (_basePath: string, milestoneId: string) => {
958
- return `/project/.gsd/worktrees/${milestoneId}`;
959
- },
960
- });
961
- const ctx = makeNotifyCtx();
962
- const resolver = new WorktreeResolver(s, deps);
963
-
964
- resolver.mergeAndEnterNext("M001", "M002", ctx);
965
-
966
- // Merge failed but enter should still happen
967
- assert.equal(s.basePath, "/project/.gsd/worktrees/M002");
968
- assert.ok(
969
- ctx.messages.some(
970
- (m) => m.level === "warning" && m.msg.includes("merge failed"),
971
- ),
972
- );
973
- assert.ok(
974
- ctx.messages.some(
975
- (m) => m.level === "info" && m.msg.includes("Entered worktree"),
976
- ),
977
- );
978
- });
979
-
980
- // ─── GitService Rebuild Atomicity ────────────────────────────────────────────
981
-
982
- test("GitService is rebuilt with the NEW basePath after enterMilestone", () => {
983
- const s = makeSession();
984
- let gitServiceBasePath = "";
985
- const deps = makeDeps({
986
- getAutoWorktreePath: () => null,
987
- GitServiceImpl: class {
988
- constructor(basePath: string, _config: unknown) {
989
- gitServiceBasePath = basePath;
990
- }
991
- } as unknown as WorktreeResolverDeps["GitServiceImpl"],
992
- });
993
- const ctx = makeNotifyCtx();
994
- const resolver = new WorktreeResolver(s, deps);
995
-
996
- resolver.enterMilestone("M001", ctx);
997
-
998
- assert.equal(gitServiceBasePath, "/project/.gsd/worktrees/M001"); // new path, not old
999
- });
1000
-
1001
- test("GitService is rebuilt with originalBasePath after exitMilestone", () => {
1002
- const s = makeSession({
1003
- basePath: "/project/.gsd/worktrees/M001",
1004
- originalBasePath: "/project",
1005
- });
1006
- let gitServiceBasePath = "";
1007
- const deps = makeDeps({
1008
- isInAutoWorktree: () => true,
1009
- GitServiceImpl: class {
1010
- constructor(basePath: string, _config: unknown) {
1011
- gitServiceBasePath = basePath;
1012
- }
1013
- } as unknown as WorktreeResolverDeps["GitServiceImpl"],
1014
- });
1015
- const ctx = makeNotifyCtx();
1016
- const resolver = new WorktreeResolver(s, deps);
1017
-
1018
- resolver.exitMilestone("M001", ctx);
1019
-
1020
- assert.equal(gitServiceBasePath, "/project"); // project root, not worktree
1021
- });
1022
-
1023
- // ─── Isolation Degradation Tests (#2483) ──────────────────────────────────
1024
-
1025
- test("enterMilestone sets isolationDegraded when worktree creation throws (#2483)", () => {
1026
- const s = makeSession();
1027
- const deps = makeDeps({
1028
- getAutoWorktreePath: () => null,
1029
- createAutoWorktree: () => {
1030
- throw new Error("empty repo");
1031
- },
1032
- });
1033
- const ctx = makeNotifyCtx();
1034
- const resolver = new WorktreeResolver(s, deps);
1035
-
1036
- resolver.enterMilestone("M001", ctx);
1037
-
1038
- assert.equal(s.isolationDegraded, true);
1039
- assert.equal(s.basePath, "/project"); // unchanged — error recovery
1040
- });
1041
-
1042
- test("enterMilestone is no-op when isolationDegraded is true (#2483)", () => {
1043
- const s = makeSession();
1044
- s.isolationDegraded = true;
1045
- const deps = makeDeps();
1046
- const ctx = makeNotifyCtx();
1047
- const resolver = new WorktreeResolver(s, deps);
1048
-
1049
- resolver.enterMilestone("M001", ctx);
1050
-
1051
- assert.equal(s.basePath, "/project"); // unchanged
1052
- assert.equal(findCalls(deps.calls, "createAutoWorktree").length, 0);
1053
- assert.equal(findCalls(deps.calls, "enterAutoWorktree").length, 0);
1054
- assert.equal(findCalls(deps.calls, "shouldUseWorktreeIsolation").length, 0);
1055
- });
1056
-
1057
- test("mergeAndExit is no-op when isolationDegraded is true (#2483)", () => {
1058
- const s = makeSession({
1059
- basePath: "/project",
1060
- originalBasePath: "/project",
1061
- });
1062
- s.isolationDegraded = true;
1063
- const deps = makeDeps({
1064
- getIsolationMode: () => "worktree",
1065
- });
1066
- const ctx = makeNotifyCtx();
1067
- const resolver = new WorktreeResolver(s, deps);
1068
-
1069
- resolver.mergeAndExit("M001", ctx);
1070
-
1071
- assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 0);
1072
- assert.equal(findCalls(deps.calls, "teardownAutoWorktree").length, 0);
1073
- assert.equal(findCalls(deps.calls, "getIsolationMode").length, 0);
1074
- assert.ok(
1075
- ctx.messages.some(
1076
- (m) => m.level === "info" && m.msg.includes("isolation was degraded"),
1077
- ),
1078
- );
1079
- });
1080
-
1081
- test("isolationDegraded is reset by session.reset() (#2483)", () => {
1082
- const s = new AutoSession();
1083
- s.isolationDegraded = true;
1084
-
1085
- s.reset();
1086
-
1087
- assert.equal(s.isolationDegraded, false);
1088
- });
1089
-
1090
- // ─── #2625 — Default isolation mode change must not orphan worktree commits ──
1091
-
1092
- test("mergeAndExit still merges when mode is 'none' but session is in a worktree (#2625)", () => {
1093
- // Scenario: user upgraded from a version where default was "worktree" to one
1094
- // where default is "none". They have an active worktree with committed work.
1095
- // mergeAndExit must detect the active worktree and merge regardless of config.
1096
- const s = makeSession({
1097
- basePath: "/project/.gsd/worktrees/M001",
1098
- originalBasePath: "/project",
1099
- });
1100
- const deps = makeDeps({
1101
- isInAutoWorktree: () => true,
1102
- getIsolationMode: () => "none", // config says "none" — but we ARE in a worktree
1103
- });
1104
- const ctx = makeNotifyCtx();
1105
- const resolver = new WorktreeResolver(s, deps);
1106
-
1107
- resolver.mergeAndExit("M001", ctx);
1108
-
1109
- // Must still merge — not skip silently
1110
- assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 1,
1111
- "must call mergeMilestoneToMain even when isolation mode is 'none' but we are in a worktree");
1112
- assert.equal(s.basePath, "/project", "basePath must be restored to project root");
1113
- assert.ok(ctx.messages.some((m) => m.msg.includes("merged to main")),
1114
- "must notify about the merge");
1115
- });
1116
-
1117
- test("mergeAndExit in none mode remains a no-op when NOT in a worktree (#2625)", () => {
1118
- // When mode is "none" and we are genuinely not in a worktree, it should still be a no-op.
1119
- const s = makeSession({
1120
- basePath: "/project",
1121
- originalBasePath: "/project",
1122
- });
1123
- const deps = makeDeps({
1124
- isInAutoWorktree: () => false,
1125
- getIsolationMode: () => "none",
1126
- });
1127
- const ctx = makeNotifyCtx();
1128
- const resolver = new WorktreeResolver(s, deps);
1129
-
1130
- resolver.mergeAndExit("M001", ctx);
1131
-
1132
- assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 0,
1133
- "must NOT merge when not in a worktree and mode is none");
1134
- });
1135
-
1136
- // ─── #4380 — Non-MergeConflictError must not be swallowed ────────────────────
1137
-
1138
- test("mergeAndExit propagates non-MergeConflictError to caller (#4380)", () => {
1139
- // Regression test: previously the catch block in _mergeWorktreeMode only
1140
- // re-threw MergeConflictError. Permission errors, filesystem errors, and other
1141
- // non-conflict failures were swallowed silently, making broken states impossible
1142
- // to diagnose and preventing callers (phases.ts) from applying their own
1143
- // error-recovery logic.
1144
- const permissionError = new Error("EACCES: permission denied, open '/project/.git/SQUASH_MSG'");
1145
- const s = makeSession({
1146
- basePath: "/project/.gsd/worktrees/M001",
1147
- originalBasePath: "/project",
1148
- });
1149
- const deps = makeDeps({
1150
- isInAutoWorktree: () => true,
1151
- getIsolationMode: () => "worktree",
1152
- mergeMilestoneToMain: () => {
1153
- throw permissionError;
1154
- },
1155
- });
1156
- const ctx = makeNotifyCtx();
1157
- const resolver = new WorktreeResolver(s, deps);
1158
-
1159
- // The error must propagate — callers need it to apply their own recovery logic
1160
- assert.throws(
1161
- () => resolver.mergeAndExit("M001", ctx),
1162
- (err: unknown) => err === permissionError,
1163
- "non-MergeConflictError must propagate to the caller, not be swallowed",
1164
- );
1165
- });
1166
-
1167
- // ─── Regression: mergeAndExit anchors cwd at project root before merge work ─
1168
- // (de73fb43d headless `gsd auto` exits-on-task regression)
1169
- //
1170
- // Background: the auto loop runs tasks inside the milestone worktree
1171
- // (process.cwd() === worktreePath). When the milestone completes, the
1172
- // worktree dir is torn down. If cwd was still inside it at that moment,
1173
- // every subsequent process.cwd() throws ENOENT — and after de73fb43d
1174
- // auto/run-unit.ts:50 turns that ENOENT into a session-failed cancel,
1175
- // which in headless mode bubbles up to a "Auto-mode stopped" notify
1176
- // and process.exit(0). mergeAndExit must therefore guarantee cwd is
1177
- // anchored at the project root regardless of which merge path runs.
1178
-
1179
- test("mergeAndExit chdirs to project root before merge work (regression: headless gsd auto exit)", () => {
1180
- // Set up real dirs so process.chdir actually succeeds. realpathSync
1181
- // canonicalizes the macOS /var → /private/var symlink so equality holds.
1182
- const projectRoot = realpathSync(mkdtempSync(join(tmpdir(), "gsd-resolver-cwd-")));
1183
- const worktreePath = join(projectRoot, ".gsd/worktrees/M001");
1184
- mkdirSync(worktreePath, { recursive: true });
1185
- const previousCwd = process.cwd();
1186
-
1187
- try {
1188
- process.chdir(worktreePath);
1189
- assert.equal(process.cwd(), worktreePath, "precondition: cwd is in worktree");
1190
-
1191
- const s = makeSession({
1192
- basePath: worktreePath,
1193
- originalBasePath: projectRoot,
1194
- });
1195
- const deps = makeDeps({
1196
- isInAutoWorktree: () => true,
1197
- getIsolationMode: () => "worktree",
1198
- });
1199
- const ctx = makeNotifyCtx();
1200
- const resolver = new WorktreeResolver(s, deps);
1201
-
1202
- resolver.mergeAndExit("M001", ctx);
1203
-
1204
- assert.equal(
1205
- process.cwd(),
1206
- projectRoot,
1207
- "mergeAndExit must leave cwd at the project root, not the (about-to-be-removed) worktree",
1208
- );
1209
- } finally {
1210
- try { process.chdir(previousCwd); } catch { /* best-effort */ }
1211
- rmSync(projectRoot, { recursive: true, force: true });
1212
- }
1213
- });
1214
-
1215
- test("mergeAndExit anchors cwd even on isolation-degraded skip path", () => {
1216
- // The skip paths (isolation-degraded, mode-none, missing-original-base)
1217
- // bypass the per-mode merge helpers entirely. They must still leave cwd
1218
- // at the project root so a subsequent worktree teardown elsewhere does
1219
- // not strand cwd in a deleted dir.
1220
- const projectRoot = realpathSync(mkdtempSync(join(tmpdir(), "gsd-resolver-cwd-degraded-")));
1221
- const worktreePath = join(projectRoot, ".gsd/worktrees/M001");
1222
- mkdirSync(worktreePath, { recursive: true });
1223
- const previousCwd = process.cwd();
1224
-
1225
- try {
1226
- process.chdir(worktreePath);
1227
- const s = makeSession({
1228
- basePath: worktreePath,
1229
- originalBasePath: projectRoot,
1230
- });
1231
- s.isolationDegraded = true;
1232
- const deps = makeDeps({ getIsolationMode: () => "worktree" });
1233
- const ctx = makeNotifyCtx();
1234
- const resolver = new WorktreeResolver(s, deps);
1235
-
1236
- resolver.mergeAndExit("M001", ctx);
1237
-
1238
- assert.equal(
1239
- process.cwd(),
1240
- projectRoot,
1241
- "isolation-degraded skip must still anchor cwd at project root",
1242
- );
1243
- } finally {
1244
- try { process.chdir(previousCwd); } catch { /* best-effort */ }
1245
- rmSync(projectRoot, { recursive: true, force: true });
1246
- }
1247
- });