@opengsd/gsd-pi 1.2.0-dev.4813ead6 → 1.2.0-dev.5457a158

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 (342) hide show
  1. package/dist/cli-style.d.ts +17 -0
  2. package/dist/cli-style.js +28 -0
  3. package/dist/cli.js +1 -1
  4. package/dist/headless-events.d.ts +4 -2
  5. package/dist/headless-events.js +7 -29
  6. package/dist/models-resolver.d.ts +3 -13
  7. package/dist/models-resolver.js +3 -22
  8. package/dist/resource-loader.js +2 -14
  9. package/dist/resources/.managed-resources-content-hash +1 -1
  10. package/dist/resources/extensions/bg-shell/utilities.js +5 -2
  11. package/dist/resources/extensions/claude-code-cli/models.js +9 -0
  12. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +35 -4
  13. package/dist/resources/extensions/gsd/auto/orchestrator.js +33 -4
  14. package/dist/resources/extensions/gsd/auto/phases.js +6 -1
  15. package/dist/resources/extensions/gsd/auto-post-unit.js +19 -8
  16. package/dist/resources/extensions/gsd/auto-prompts.js +3 -0
  17. package/dist/resources/extensions/gsd/auto-start.js +12 -14
  18. package/dist/resources/extensions/gsd/auto-tool-tracking.js +18 -0
  19. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +7 -16
  20. package/dist/resources/extensions/gsd/auto-worktree-repair.js +10 -2
  21. package/dist/resources/extensions/gsd/auto-worktree.js +35 -352
  22. package/dist/resources/extensions/gsd/auto.js +8 -20
  23. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +3 -2
  24. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +9 -6
  25. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +86 -6
  26. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +30 -4
  27. package/dist/resources/extensions/gsd/branch-patterns.js +2 -0
  28. package/dist/resources/extensions/gsd/captures.js +5 -15
  29. package/dist/resources/extensions/gsd/closeout-recovery.js +3 -2
  30. package/dist/resources/extensions/gsd/commands/catalog.js +6 -62
  31. package/dist/resources/extensions/gsd/crash-recovery.js +4 -12
  32. package/dist/resources/extensions/gsd/db/engine.js +755 -0
  33. package/dist/resources/extensions/gsd/db/queries.js +372 -0
  34. package/dist/resources/extensions/gsd/db/sql-constants.js +11 -0
  35. package/dist/resources/extensions/gsd/db/writers/cascades.js +194 -0
  36. package/dist/resources/extensions/gsd/db/writers/import-restore.js +182 -0
  37. package/dist/resources/extensions/gsd/db/writers/memory.js +149 -0
  38. package/dist/resources/extensions/gsd/db/writers/reconcile.js +458 -0
  39. package/dist/resources/extensions/gsd/db/writers/status.js +70 -0
  40. package/dist/resources/extensions/gsd/doctor-environment.js +5 -11
  41. package/dist/resources/extensions/gsd/doctor-format.js +9 -6
  42. package/dist/resources/extensions/gsd/doctor-git-checks.js +4 -3
  43. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +21 -16
  44. package/dist/resources/extensions/gsd/error-classifier.js +9 -0
  45. package/dist/resources/extensions/gsd/git-service.js +1 -0
  46. package/dist/resources/extensions/gsd/gitignore.js +3 -0
  47. package/dist/resources/extensions/gsd/gsd-db.js +171 -2048
  48. package/dist/resources/extensions/gsd/guidance.js +98 -0
  49. package/dist/resources/extensions/gsd/guided-flow.js +51 -5
  50. package/dist/resources/extensions/gsd/mcp-tool-name.js +5 -13
  51. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +1 -1
  52. package/dist/resources/extensions/gsd/migrate/safety.js +20 -9
  53. package/dist/resources/extensions/gsd/migration-auto-check.js +24 -3
  54. package/dist/resources/extensions/gsd/model-cost-table.js +1 -0
  55. package/dist/resources/extensions/gsd/model-router.js +3 -0
  56. package/dist/resources/extensions/gsd/notification-store.js +11 -4
  57. package/dist/resources/extensions/gsd/parallel-merge.js +14 -11
  58. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +11 -7
  59. package/dist/resources/extensions/gsd/paths.js +37 -24
  60. package/dist/resources/extensions/gsd/pre-execution-checks.js +91 -3
  61. package/dist/resources/extensions/gsd/preferences-models.js +12 -46
  62. package/dist/resources/extensions/gsd/preferences.js +14 -0
  63. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  64. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  65. package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  66. package/dist/resources/extensions/gsd/provider-error-guidance.js +1 -5
  67. package/dist/resources/extensions/gsd/provider-switch-observer.js +1 -1
  68. package/dist/resources/extensions/gsd/publication.js +87 -0
  69. package/dist/resources/extensions/gsd/recovery-classification.js +41 -87
  70. package/dist/resources/extensions/gsd/safety/evidence-collector.js +37 -4
  71. package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +7 -2
  72. package/dist/resources/extensions/gsd/safety/file-change-validator.js +10 -0
  73. package/dist/resources/extensions/gsd/state-transition-matrix.js +38 -0
  74. package/dist/resources/extensions/gsd/state.js +1 -20
  75. package/dist/resources/extensions/gsd/status-guards.js +56 -8
  76. package/dist/resources/extensions/gsd/stop-notice.js +57 -0
  77. package/dist/resources/extensions/gsd/tool-surface-readiness.js +56 -0
  78. package/dist/resources/extensions/gsd/tools/complete-slice.js +24 -43
  79. package/dist/resources/extensions/gsd/tools/exec-tool.js +5 -8
  80. package/dist/resources/extensions/gsd/tools/plan-slice.js +12 -6
  81. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +11 -29
  82. package/dist/resources/extensions/gsd/tools/reopen-slice.js +14 -33
  83. package/dist/resources/extensions/gsd/tools/skip-slice.js +18 -36
  84. package/dist/resources/extensions/gsd/undo.js +8 -7
  85. package/dist/resources/extensions/gsd/unit-closeout.js +138 -0
  86. package/dist/resources/extensions/gsd/unit-context-composer.js +9 -1
  87. package/dist/resources/extensions/gsd/unit-context-manifest.js +4 -27
  88. package/dist/resources/extensions/gsd/unit-registry.js +350 -0
  89. package/dist/resources/extensions/gsd/unit-tool-contracts.js +9 -182
  90. package/dist/resources/extensions/gsd/workflow-tool-surface.js +1 -1
  91. package/dist/resources/extensions/gsd/worktree-git-recovery.js +293 -0
  92. package/dist/resources/extensions/gsd/worktree-lifecycle.js +9 -1
  93. package/dist/resources/extensions/gsd/worktree-manager.js +45 -28
  94. package/dist/resources/extensions/gsd/worktree-placement.js +59 -0
  95. package/dist/resources/extensions/gsd/worktree-reentry.js +12 -8
  96. package/dist/resources/extensions/gsd/worktree-root.js +28 -6
  97. package/dist/resources/extensions/gsd/worktree-safety.js +8 -5
  98. package/dist/resources/extensions/gsd/worktree-session-state.js +12 -11
  99. package/dist/resources/skills/gsd-browser/SKILL.md +1 -1
  100. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  101. package/dist/web/standalone/.next/BUILD_ID +1 -1
  102. package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
  103. package/dist/web/standalone/.next/build-manifest.json +2 -2
  104. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  105. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  106. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  122. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  123. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  124. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  125. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  126. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  127. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  128. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  129. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  130. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  131. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  132. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  133. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  134. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  135. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  136. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  137. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  138. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  139. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  140. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  141. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  142. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  143. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  144. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  145. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  146. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  147. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  148. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  149. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  150. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  151. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  152. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  153. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  154. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  155. package/dist/web/standalone/.next/server/app/index.html +1 -1
  156. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  157. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  158. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  159. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  160. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  161. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  162. package/dist/web/standalone/.next/server/app-paths-manifest.json +6 -6
  163. package/dist/web/standalone/.next/server/chunks/5124.js +1 -1
  164. package/dist/web/standalone/.next/server/chunks/{5047.js → 5942.js} +2 -2
  165. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  166. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  168. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  169. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  170. package/dist/worktree-cli.js +3 -6
  171. package/dist/worktree-status-banner.js +7 -11
  172. package/package.json +1 -1
  173. package/packages/cloud-mcp-gateway/package.json +2 -2
  174. package/packages/contracts/dist/workflow.d.ts +4 -0
  175. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  176. package/packages/contracts/dist/workflow.js.map +1 -1
  177. package/packages/contracts/package.json +1 -1
  178. package/packages/daemon/package.json +4 -4
  179. package/packages/gsd-agent-core/package.json +5 -5
  180. package/packages/gsd-agent-modes/package.json +7 -7
  181. package/packages/mcp-server/dist/cli.js +6 -3
  182. package/packages/mcp-server/dist/cli.js.map +1 -1
  183. package/packages/mcp-server/dist/workflow-tools.d.ts +8 -0
  184. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  185. package/packages/mcp-server/dist/workflow-tools.js +46 -21
  186. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  187. package/packages/mcp-server/package.json +3 -3
  188. package/packages/native/package.json +1 -1
  189. package/packages/pi-agent-core/package.json +1 -1
  190. package/packages/pi-ai/dist/image-models.generated.d.ts +0 -30
  191. package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  192. package/packages/pi-ai/dist/image-models.generated.js +0 -30
  193. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  194. package/packages/pi-ai/dist/models.generated.d.ts +361 -255
  195. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  196. package/packages/pi-ai/dist/models.generated.js +311 -256
  197. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  198. package/packages/pi-ai/package.json +1 -1
  199. package/packages/pi-coding-agent/dist/core/capability-patches.d.ts.map +1 -1
  200. package/packages/pi-coding-agent/dist/core/capability-patches.js +3 -1
  201. package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
  202. package/packages/pi-coding-agent/package.json +7 -7
  203. package/packages/pi-tui/package.json +2 -2
  204. package/packages/rpc-client/package.json +2 -2
  205. package/pkg/package.json +1 -1
  206. package/src/resources/extensions/bg-shell/utilities.ts +5 -2
  207. package/src/resources/extensions/claude-code-cli/models.ts +9 -0
  208. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +37 -2
  209. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +28 -0
  210. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -1
  211. package/src/resources/extensions/gsd/auto/orchestrator.ts +39 -5
  212. package/src/resources/extensions/gsd/auto/phases.ts +10 -1
  213. package/src/resources/extensions/gsd/auto-post-unit.ts +25 -7
  214. package/src/resources/extensions/gsd/auto-prompts.ts +3 -0
  215. package/src/resources/extensions/gsd/auto-start.ts +12 -15
  216. package/src/resources/extensions/gsd/auto-tool-tracking.ts +19 -0
  217. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +10 -17
  218. package/src/resources/extensions/gsd/auto-worktree-repair.ts +13 -2
  219. package/src/resources/extensions/gsd/auto-worktree.ts +41 -364
  220. package/src/resources/extensions/gsd/auto.ts +20 -24
  221. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +3 -5
  222. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +10 -6
  223. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +87 -6
  224. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +29 -3
  225. package/src/resources/extensions/gsd/branch-patterns.ts +3 -0
  226. package/src/resources/extensions/gsd/captures.ts +5 -16
  227. package/src/resources/extensions/gsd/closeout-recovery.ts +2 -1
  228. package/src/resources/extensions/gsd/commands/catalog.ts +6 -68
  229. package/src/resources/extensions/gsd/crash-recovery.ts +3 -9
  230. package/src/resources/extensions/gsd/db/engine.ts +809 -0
  231. package/src/resources/extensions/gsd/db/queries.ts +453 -0
  232. package/src/resources/extensions/gsd/db/sql-constants.ts +12 -0
  233. package/src/resources/extensions/gsd/db/writers/cascades.ts +237 -0
  234. package/src/resources/extensions/gsd/db/writers/import-restore.ts +310 -0
  235. package/src/resources/extensions/gsd/db/writers/memory.ts +220 -0
  236. package/src/resources/extensions/gsd/db/writers/reconcile.ts +500 -0
  237. package/src/resources/extensions/gsd/db/writers/status.ts +88 -0
  238. package/src/resources/extensions/gsd/doctor-environment.ts +5 -13
  239. package/src/resources/extensions/gsd/doctor-format.ts +12 -7
  240. package/src/resources/extensions/gsd/doctor-git-checks.ts +3 -3
  241. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +22 -17
  242. package/src/resources/extensions/gsd/error-classifier.ts +11 -0
  243. package/src/resources/extensions/gsd/git-service.ts +1 -0
  244. package/src/resources/extensions/gsd/gitignore.ts +3 -0
  245. package/src/resources/extensions/gsd/gsd-db.ts +173 -2373
  246. package/src/resources/extensions/gsd/guidance.ts +139 -0
  247. package/src/resources/extensions/gsd/guided-flow.ts +50 -5
  248. package/src/resources/extensions/gsd/mcp-tool-name.ts +6 -11
  249. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +1 -1
  250. package/src/resources/extensions/gsd/migrate/safety.ts +18 -7
  251. package/src/resources/extensions/gsd/migration-auto-check.ts +28 -3
  252. package/src/resources/extensions/gsd/model-cost-table.ts +1 -0
  253. package/src/resources/extensions/gsd/model-router.ts +3 -0
  254. package/src/resources/extensions/gsd/notification-store.ts +26 -3
  255. package/src/resources/extensions/gsd/parallel-merge.ts +12 -9
  256. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +10 -7
  257. package/src/resources/extensions/gsd/paths.ts +42 -22
  258. package/src/resources/extensions/gsd/pre-execution-checks.ts +109 -3
  259. package/src/resources/extensions/gsd/preferences-models.ts +10 -46
  260. package/src/resources/extensions/gsd/preferences.ts +18 -0
  261. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  262. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  263. package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  264. package/src/resources/extensions/gsd/provider-error-guidance.ts +4 -9
  265. package/src/resources/extensions/gsd/provider-switch-observer.ts +1 -1
  266. package/src/resources/extensions/gsd/publication.ts +122 -0
  267. package/src/resources/extensions/gsd/recovery-classification.ts +47 -88
  268. package/src/resources/extensions/gsd/safety/evidence-collector.ts +36 -4
  269. package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +7 -2
  270. package/src/resources/extensions/gsd/safety/file-change-validator.ts +14 -0
  271. package/src/resources/extensions/gsd/state-transition-matrix.ts +42 -0
  272. package/src/resources/extensions/gsd/state.ts +4 -21
  273. package/src/resources/extensions/gsd/status-guards.ts +59 -8
  274. package/src/resources/extensions/gsd/stop-notice.ts +75 -0
  275. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +123 -0
  276. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +3 -1
  277. package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +46 -0
  278. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +2 -2
  279. package/src/resources/extensions/gsd/tests/auto-worktree-repair.test.ts +4 -2
  280. package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +66 -1
  281. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +44 -0
  282. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +8 -7
  283. package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +157 -0
  284. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +33 -1
  285. package/src/resources/extensions/gsd/tests/guidance.test.ts +125 -0
  286. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +51 -4
  287. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +54 -1
  288. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +3 -2
  289. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +85 -1
  290. package/src/resources/extensions/gsd/tests/notification-store.test.ts +32 -0
  291. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +193 -1
  292. package/src/resources/extensions/gsd/tests/provider-error-guidance.test.ts +3 -3
  293. package/src/resources/extensions/gsd/tests/publication.test.ts +120 -0
  294. package/src/resources/extensions/gsd/tests/recovery-classification-illegal-transition.test.ts +30 -0
  295. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +248 -1
  296. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +1 -0
  297. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +38 -0
  298. package/src/resources/extensions/gsd/tests/session-switch-clears-pending-autostart.test.ts +108 -0
  299. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +43 -6
  300. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +36 -0
  301. package/src/resources/extensions/gsd/tests/status-guards.test.ts +38 -0
  302. package/src/resources/extensions/gsd/tests/stop-notice.test.ts +70 -0
  303. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +8 -0
  304. package/src/resources/extensions/gsd/tests/tool-surface-readiness.test.ts +155 -0
  305. package/src/resources/extensions/gsd/tests/unit-closeout.test.ts +209 -0
  306. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +23 -2
  307. package/src/resources/extensions/gsd/tests/unit-registry.test.ts +163 -0
  308. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -2
  309. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +2 -2
  310. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +41 -4
  311. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +22 -1
  312. package/src/resources/extensions/gsd/tests/worktree-placement.test.ts +113 -0
  313. package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +1 -1
  314. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +3 -1
  315. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +12 -6
  316. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +2 -2
  317. package/src/resources/extensions/gsd/tests/write-gate.test.ts +42 -0
  318. package/src/resources/extensions/gsd/tool-surface-readiness.ts +76 -0
  319. package/src/resources/extensions/gsd/tools/complete-slice.ts +23 -58
  320. package/src/resources/extensions/gsd/tools/exec-tool.ts +5 -8
  321. package/src/resources/extensions/gsd/tools/plan-slice.ts +12 -6
  322. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +11 -38
  323. package/src/resources/extensions/gsd/tools/reopen-slice.ts +14 -42
  324. package/src/resources/extensions/gsd/tools/skip-slice.ts +18 -44
  325. package/src/resources/extensions/gsd/undo.ts +9 -8
  326. package/src/resources/extensions/gsd/unit-closeout.ts +201 -0
  327. package/src/resources/extensions/gsd/unit-context-composer.ts +12 -1
  328. package/src/resources/extensions/gsd/unit-context-manifest.ts +4 -28
  329. package/src/resources/extensions/gsd/unit-registry.ts +425 -0
  330. package/src/resources/extensions/gsd/unit-tool-contracts.ts +27 -192
  331. package/src/resources/extensions/gsd/workflow-tool-surface.ts +4 -1
  332. package/src/resources/extensions/gsd/worktree-git-recovery.ts +314 -0
  333. package/src/resources/extensions/gsd/worktree-lifecycle.ts +10 -1
  334. package/src/resources/extensions/gsd/worktree-manager.ts +47 -28
  335. package/src/resources/extensions/gsd/worktree-placement.ts +63 -0
  336. package/src/resources/extensions/gsd/worktree-reentry.ts +10 -7
  337. package/src/resources/extensions/gsd/worktree-root.ts +29 -6
  338. package/src/resources/extensions/gsd/worktree-safety.ts +8 -5
  339. package/src/resources/extensions/gsd/worktree-session-state.ts +11 -11
  340. package/src/resources/skills/gsd-browser/SKILL.md +1 -1
  341. /package/dist/web/standalone/.next/static/{tkLHUSzPA2kMmWz4DmGwI → 2p9Rv9pQflAxCBbGVI2vb}/_buildManifest.js +0 -0
  342. /package/dist/web/standalone/.next/static/{tkLHUSzPA2kMmWz4DmGwI → 2p9Rv9pQflAxCBbGVI2vb}/_ssgManifest.js +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gsd/pi-ai",
3
- "version": "1.2.0-dev.4813ead6",
3
+ "version": "1.2.0-dev.5457a158",
4
4
  "description": "Unified LLM API with automatic model discovery and provider configuration",
5
5
  "type": "module",
6
6
  "gsd": {
@@ -1 +1 @@
1
- {"version":3,"file":"capability-patches.d.ts","sourceRoot":"","sources":["../../src/core/capability-patches.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAE7C,mEAAmE;AACnE,MAAM,WAAW,iBAAiB;IACjC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,KAAK,eAAe,GAAG;IAAE,KAAK,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC;IAAC,IAAI,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAEtF,eAAO,MAAM,kBAAkB,EAAE,eAAe,EAuB/C,CAAC;AAEF,kEAAkE;AAClE,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAe7E"}
1
+ {"version":3,"file":"capability-patches.d.ts","sourceRoot":"","sources":["../../src/core/capability-patches.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAE7C,mEAAmE;AACnE,MAAM,WAAW,iBAAiB;IACjC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,KAAK,eAAe,GAAG;IAAE,KAAK,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC;IAAC,IAAI,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAEtF,eAAO,MAAM,kBAAkB,EAAE,eAAe,EAyB/C,CAAC;AAEF,kEAAkE;AAClE,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAe7E"}
@@ -16,7 +16,9 @@ export const CAPABILITY_PATCHES = [
16
16
  m.id.includes("opus-4-7") ||
17
17
  m.id.includes("opus-4.7") ||
18
18
  m.id.includes("opus-4-8") ||
19
- m.id.includes("opus-4.8")),
19
+ m.id.includes("opus-4.8") ||
20
+ m.id.includes("fable-5") ||
21
+ m.id.includes("fable.5")),
20
22
  caps: { supportsXhigh: true },
21
23
  },
22
24
  ];
@@ -1 +1 @@
1
- {"version":3,"file":"capability-patches.js","sourceRoot":"","sources":["../../src/core/capability-patches.ts"],"names":[],"mappings":"AAYA,MAAM,CAAC,MAAM,kBAAkB,GAAsB;IACpD;QACC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CACZ,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;YACxB,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;YACxB,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;QACzB,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE;KACxD;IACD;QACC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;QACtC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE;KAC7B;IACD;QACC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CACZ,CAAC,CAAC,GAAG,KAAK,oBAAoB;YAC9B,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC;gBACzB,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC;gBACzB,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC;gBACzB,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC;gBACzB,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC;gBACzB,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC5B,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE;KAC7B;CACD,CAAC;AAEF,kEAAkE;AAClE,MAAM,UAAU,sBAAsB,CAAuB,MAAW;IACvE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QAC3B,KAAK,MAAM,KAAK,IAAI,kBAAkB,EAAE,CAAC;YACxC,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO;oBACN,GAAG,KAAK;oBACR,YAAY,EAAE;wBACb,GAAG,KAAK,CAAC,IAAI;wBACb,GAAI,KAAwD,CAAC,YAAY;qBACzE;iBACI,CAAC;YACR,CAAC;QACF,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import type { Api, Model } from \"@gsd/pi-ai\";\n\n/** GSD extension: provider-agnostic capability flags on models. */\nexport interface ModelCapabilities {\n\tsupportsXhigh?: boolean;\n\trequiresToolCallId?: boolean;\n\tsupportsServiceTier?: boolean;\n\tcharsPerToken?: number;\n}\n\ntype CapabilityPatch = { match: (m: Model<Api>) => boolean; caps: ModelCapabilities };\n\nexport const CAPABILITY_PATCHES: CapabilityPatch[] = [\n\t{\n\t\tmatch: (m) =>\n\t\t\tm.id.includes(\"gpt-5.2\") ||\n\t\t\tm.id.includes(\"gpt-5.3\") ||\n\t\t\tm.id.includes(\"gpt-5.4\"),\n\t\tcaps: { supportsXhigh: true, supportsServiceTier: true },\n\t},\n\t{\n\t\tmatch: (m) => m.id.includes(\"gpt-5.5\"),\n\t\tcaps: { supportsXhigh: true },\n\t},\n\t{\n\t\tmatch: (m) =>\n\t\t\tm.api === \"anthropic-messages\" &&\n\t\t\t(m.id.includes(\"opus-4-6\") ||\n\t\t\t\tm.id.includes(\"opus-4.6\") ||\n\t\t\t\tm.id.includes(\"opus-4-7\") ||\n\t\t\t\tm.id.includes(\"opus-4.7\") ||\n\t\t\t\tm.id.includes(\"opus-4-8\") ||\n\t\t\t\tm.id.includes(\"opus-4.8\")),\n\t\tcaps: { supportsXhigh: true },\n\t},\n];\n\n/** Apply GSD capability patches after assembling a model list. */\nexport function applyCapabilityPatches<T extends Model<Api>>(models: T[]): T[] {\n\treturn models.map((model) => {\n\t\tfor (const patch of CAPABILITY_PATCHES) {\n\t\t\tif (patch.match(model)) {\n\t\t\t\treturn {\n\t\t\t\t\t...model,\n\t\t\t\t\tcapabilities: {\n\t\t\t\t\t\t...patch.caps,\n\t\t\t\t\t\t...(model as T & { capabilities?: Record<string, boolean> }).capabilities,\n\t\t\t\t\t},\n\t\t\t\t} as T;\n\t\t\t}\n\t\t}\n\t\treturn model;\n\t});\n}\n"]}
1
+ {"version":3,"file":"capability-patches.js","sourceRoot":"","sources":["../../src/core/capability-patches.ts"],"names":[],"mappings":"AAYA,MAAM,CAAC,MAAM,kBAAkB,GAAsB;IACpD;QACC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CACZ,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;YACxB,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;YACxB,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;QACzB,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE;KACxD;IACD;QACC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;QACtC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE;KAC7B;IACD;QACC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CACZ,CAAC,CAAC,GAAG,KAAK,oBAAoB;YAC9B,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC;gBACzB,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC;gBACzB,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC;gBACzB,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC;gBACzB,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC;gBACzB,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC;gBACzB,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;gBACxB,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC3B,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE;KAC7B;CACD,CAAC;AAEF,kEAAkE;AAClE,MAAM,UAAU,sBAAsB,CAAuB,MAAW;IACvE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QAC3B,KAAK,MAAM,KAAK,IAAI,kBAAkB,EAAE,CAAC;YACxC,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO;oBACN,GAAG,KAAK;oBACR,YAAY,EAAE;wBACb,GAAG,KAAK,CAAC,IAAI;wBACb,GAAI,KAAwD,CAAC,YAAY;qBACzE;iBACI,CAAC;YACR,CAAC;QACF,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import type { Api, Model } from \"@gsd/pi-ai\";\n\n/** GSD extension: provider-agnostic capability flags on models. */\nexport interface ModelCapabilities {\n\tsupportsXhigh?: boolean;\n\trequiresToolCallId?: boolean;\n\tsupportsServiceTier?: boolean;\n\tcharsPerToken?: number;\n}\n\ntype CapabilityPatch = { match: (m: Model<Api>) => boolean; caps: ModelCapabilities };\n\nexport const CAPABILITY_PATCHES: CapabilityPatch[] = [\n\t{\n\t\tmatch: (m) =>\n\t\t\tm.id.includes(\"gpt-5.2\") ||\n\t\t\tm.id.includes(\"gpt-5.3\") ||\n\t\t\tm.id.includes(\"gpt-5.4\"),\n\t\tcaps: { supportsXhigh: true, supportsServiceTier: true },\n\t},\n\t{\n\t\tmatch: (m) => m.id.includes(\"gpt-5.5\"),\n\t\tcaps: { supportsXhigh: true },\n\t},\n\t{\n\t\tmatch: (m) =>\n\t\t\tm.api === \"anthropic-messages\" &&\n\t\t\t(m.id.includes(\"opus-4-6\") ||\n\t\t\t\tm.id.includes(\"opus-4.6\") ||\n\t\t\t\tm.id.includes(\"opus-4-7\") ||\n\t\t\t\tm.id.includes(\"opus-4.7\") ||\n\t\t\t\tm.id.includes(\"opus-4-8\") ||\n\t\t\t\tm.id.includes(\"opus-4.8\") ||\n\t\t\t\tm.id.includes(\"fable-5\") ||\n\t\t\t\tm.id.includes(\"fable.5\")),\n\t\tcaps: { supportsXhigh: true },\n\t},\n];\n\n/** Apply GSD capability patches after assembling a model list. */\nexport function applyCapabilityPatches<T extends Model<Api>>(models: T[]): T[] {\n\treturn models.map((model) => {\n\t\tfor (const patch of CAPABILITY_PATCHES) {\n\t\t\tif (patch.match(model)) {\n\t\t\t\treturn {\n\t\t\t\t\t...model,\n\t\t\t\t\tcapabilities: {\n\t\t\t\t\t\t...patch.caps,\n\t\t\t\t\t\t...(model as T & { capabilities?: Record<string, boolean> }).capabilities,\n\t\t\t\t\t},\n\t\t\t\t} as T;\n\t\t\t}\n\t\t}\n\t\treturn model;\n\t});\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gsd/pi-coding-agent",
3
- "version": "1.2.0-dev.4813ead6",
3
+ "version": "1.2.0-dev.5457a158",
4
4
  "description": "Coding agent CLI (vendored from earendil-works/pi)",
5
5
  "type": "module",
6
6
  "gsd": {
@@ -33,7 +33,7 @@
33
33
  "copy-assets": "node scripts/copy-assets.cjs"
34
34
  },
35
35
  "dependencies": {
36
- "@opengsd/contracts": "^1.2.0-dev.4813ead6",
36
+ "@opengsd/contracts": "^1.2.0-dev.5457a158",
37
37
  "@mariozechner/jiti": "^2.6.2",
38
38
  "@silvia-odwyer/photon-node": "0.3.4",
39
39
  "chalk": "5.6.2",
@@ -53,11 +53,11 @@
53
53
  "typebox": "1.1.38",
54
54
  "undici": "7.26.0",
55
55
  "yaml": "2.9.0",
56
- "@gsd/agent-core": "^1.2.0-dev.4813ead6",
57
- "@gsd/native": "^1.2.0-dev.4813ead6",
58
- "@gsd/pi-agent-core": "^1.2.0-dev.4813ead6",
59
- "@gsd/pi-ai": "^1.2.0-dev.4813ead6",
60
- "@gsd/pi-tui": "^1.2.0-dev.4813ead6",
56
+ "@gsd/agent-core": "^1.2.0-dev.5457a158",
57
+ "@gsd/native": "^1.2.0-dev.5457a158",
58
+ "@gsd/pi-agent-core": "^1.2.0-dev.5457a158",
59
+ "@gsd/pi-ai": "^1.2.0-dev.5457a158",
60
+ "@gsd/pi-tui": "^1.2.0-dev.5457a158",
61
61
  "@sinclair/typebox": "^0.34.41"
62
62
  },
63
63
  "devDependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gsd/pi-tui",
3
- "version": "1.2.0-dev.4813ead6",
3
+ "version": "1.2.0-dev.5457a158",
4
4
  "description": "Terminal UI library (vendored from earendil-works/pi)",
5
5
  "type": "module",
6
6
  "gsd": {
@@ -21,7 +21,7 @@
21
21
  "build": "node ../../scripts/clean-package-dist.cjs && tsc -p tsconfig.json --incremental false"
22
22
  },
23
23
  "dependencies": {
24
- "@gsd/native": "^1.2.0-dev.4813ead6",
24
+ "@gsd/native": "^1.2.0-dev.5457a158",
25
25
  "get-east-asian-width": "1.6.0",
26
26
  "marked": "15.0.12",
27
27
  "@sinclair/typebox": "^0.34.41"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengsd/rpc-client",
3
- "version": "1.2.0-dev.4813ead6",
3
+ "version": "1.2.0-dev.5457a158",
4
4
  "description": "Standalone RPC client SDK for GSD — zero internal dependencies",
5
5
  "license": "MIT",
6
6
  "gsd": {
@@ -34,7 +34,7 @@
34
34
  "test": "node --test dist/rpc-client.test.js"
35
35
  },
36
36
  "dependencies": {
37
- "@opengsd/contracts": "^1.2.0-dev.4813ead6"
37
+ "@opengsd/contracts": "^1.2.0-dev.5457a158"
38
38
  },
39
39
  "engines": {
40
40
  "node": ">=22.0.0"
package/pkg/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glittercowboy/gsd",
3
- "version": "1.2.0-dev.4813ead6",
3
+ "version": "1.2.0-dev.5457a158",
4
4
  "piConfig": {
5
5
  "name": "gsd",
6
6
  "configDir": ".gsd"
@@ -43,9 +43,12 @@ export function formatTimeAgo(timestamp: number): string {
43
43
  return formatDuration(Date.now() - timestamp) + " ago";
44
44
  }
45
45
 
46
+ // NOTE: these worktree-layout regexes mirror findWorktreeSegment in
47
+ // src/resources/extensions/gsd/worktree-root.ts (bg-shell does not import the
48
+ // gsd extension). Keep them synchronized when a layout changes.
46
49
  function deriveProjectRootFromAutoWorktree(cachedCwd?: string): string | undefined {
47
50
  if (!cachedCwd) return undefined;
48
- const match = cachedCwd.match(/^(.*?)[\\/]\.gsd[\\/]worktrees[\\/][^\\/]+(?:[\\/].*)?$/);
51
+ const match = cachedCwd.match(/^(.*?)[\\/]\.gsd(?:-worktrees|[\\/]worktrees)[\\/][^\\/]+(?:[\\/].*)?$/);
49
52
  return match?.[1];
50
53
  }
51
54
 
@@ -84,7 +87,7 @@ export function resolveBgShellPersistenceCwd(
84
87
  pathExists: (path: string) => boolean = existsSync,
85
88
  ): string {
86
89
  const resolvedLiveCwd = liveCwd ?? getBgShellLiveCwd(cachedCwd, pathExists);
87
- const cachedIsAutoWorktree = /(?:^|[\\/])\.gsd[\\/]worktrees[\\/]/.test(cachedCwd);
90
+ const cachedIsAutoWorktree = /(?:^|[\\/])\.gsd(?:-worktrees|[\\/]worktrees)[\\/]/.test(cachedCwd);
88
91
  if (!cachedIsAutoWorktree) return cachedCwd;
89
92
  if (cachedCwd === resolvedLiveCwd && pathExists(cachedCwd)) return cachedCwd;
90
93
  if (!pathExists(cachedCwd)) return resolvedLiveCwd;
@@ -39,6 +39,15 @@ export const CLAUDE_CODE_MODELS = [
39
39
  contextWindow: 1_000_000,
40
40
  maxTokens: 128_000,
41
41
  },
42
+ {
43
+ id: "claude-fable-5",
44
+ name: "Claude Fable 5 (via Claude Code)",
45
+ reasoning: true,
46
+ input: ["text", "image"] as ("text" | "image")[],
47
+ cost: ZERO_COST,
48
+ contextWindow: 1_000_000,
49
+ maxTokens: 128_000,
50
+ },
42
51
  {
43
52
  id: "claude-sonnet-4-6",
44
53
  name: "Claude Sonnet 4.6 (via Claude Code)",
@@ -59,6 +59,7 @@ import {
59
59
  computeMcpDisallowedTools,
60
60
  } from "../gsd/mcp-filter.js";
61
61
  import { RUN_UAT_CLAUDE_NATIVE_TOOL_NAMES, RUN_UAT_FORBIDDEN_TOOL_NAMES, RUN_UAT_WORKFLOW_TOOL_NAMES, resolveToolPresentationPlan } from "../gsd/tool-presentation-plan.js";
62
+ import { getToolSurfaceReadinessError } from "../gsd/tool-surface-readiness.js";
62
63
  import { showInterviewRound, type Question, type RoundResult } from "../shared/tui.js";
63
64
  import type {
64
65
  SDKAssistantMessage,
@@ -1542,6 +1543,8 @@ function modelSupportsAdaptiveThinking(modelId: string): boolean {
1542
1543
  || modelId.includes("opus-4.7")
1543
1544
  || modelId.includes("opus-4-8")
1544
1545
  || modelId.includes("opus-4.8")
1546
+ || modelId.includes("fable-5")
1547
+ || modelId.includes("fable.5")
1545
1548
  || modelId.includes("sonnet-4-6")
1546
1549
  || modelId.includes("sonnet-4.6")
1547
1550
  || modelId.includes("sonnet-4-7")
@@ -1567,6 +1570,8 @@ function mapThinkingLevelToAnthropicEffort(level: ThinkingLevel | undefined, mod
1567
1570
  || modelId.includes("opus-4.7")
1568
1571
  || modelId.includes("opus-4-8")
1569
1572
  || modelId.includes("opus-4.8")
1573
+ || modelId.includes("fable-5")
1574
+ || modelId.includes("fable.5")
1570
1575
  ) return "xhigh";
1571
1576
  if (modelId.includes("opus-4-6") || modelId.includes("opus-4.6")) return "max";
1572
1577
  return "high";
@@ -1899,6 +1904,8 @@ export function buildSdkOptions(
1899
1904
  || modelId.includes("opus-4.7")
1900
1905
  || modelId.includes("opus-4-8")
1901
1906
  || modelId.includes("opus-4.8")
1907
+ || modelId.includes("fable-5")
1908
+ || modelId.includes("fable.5")
1902
1909
  ) ? ["context-1m-2025-08-07"] : [],
1903
1910
  ...(thinkingConfig ?? {}),
1904
1911
  ...(effort ? { effort } : {}),
@@ -1992,8 +1999,9 @@ async function pumpSdkMessages(
1992
1999
  : {}),
1993
2000
  },
1994
2001
  );
2002
+ const workflowMcpServerName = workflowMcpServerNameFromAllowedTools(sdkOpts.allowedTools);
1995
2003
  const prompt = buildPromptFromContext(context, {
1996
- workflowMcpServerName: workflowMcpServerNameFromAllowedTools(sdkOpts.allowedTools),
2004
+ workflowMcpServerName,
1997
2005
  browserMcpServerName: browserMcpServerNameFromAllowedTools(sdkOpts.allowedTools),
1998
2006
  });
1999
2007
  const queryPrompt = buildSdkQueryPrompt(context, prompt);
@@ -2035,7 +2043,34 @@ async function pumpSdkMessages(
2035
2043
  switch (msg.type) {
2036
2044
  // -- Init --
2037
2045
  case "system": {
2038
- // Nothing to emit the stream is already started.
2046
+ // Tool Surface Readiness gate: the init message is the first (and
2047
+ // only) point where the session reports its live tool surface and
2048
+ // MCP server statuses. If the workflow server failed or has not
2049
+ // registered this Unit's required tools, abort before the first
2050
+ // model turn with a transient, recovery-classifiable error
2051
+ // (tool-unavailable → retry) instead of letting the model hit
2052
+ // "No such tool available" mid-Unit and improvise around it.
2053
+ const init = msg as unknown as {
2054
+ subtype?: string;
2055
+ tools?: string[];
2056
+ mcp_servers?: { name: string; status: string }[];
2057
+ };
2058
+ if (init.subtype === "init") {
2059
+ const readinessError = getToolSurfaceReadinessError({
2060
+ unitType: gsdPhase,
2061
+ workflowServerName: workflowMcpServerName,
2062
+ observation: { tools: init.tools ?? [], mcpServers: init.mcp_servers ?? [] },
2063
+ });
2064
+ if (readinessError) {
2065
+ controller.abort();
2066
+ stream.push({
2067
+ type: "error",
2068
+ reason: "error",
2069
+ error: makeErrorMessage(modelId, readinessError),
2070
+ });
2071
+ return;
2072
+ }
2073
+ }
2039
2074
  break;
2040
2075
  }
2041
2076
 
@@ -36,6 +36,7 @@ import {
36
36
  autoInitClaudeCodeWorkflowMcp,
37
37
  inferGsdPhaseFromContext,
38
38
  } from "../stream-adapter.ts";
39
+ import { CLAUDE_CODE_MODELS } from "../models.ts";
39
40
  import type { AssistantMessage, Context, Message } from "@gsd/pi-ai";
40
41
  import type { SDKUserMessage } from "../sdk-types.ts";
41
42
  import { _setAutoActiveForTest } from "../../gsd/auto.ts";
@@ -793,6 +794,33 @@ describe("stream-adapter — Claude Code external tool results", () => {
793
794
  });
794
795
  });
795
796
 
797
+ describe("claude-code-cli — Claude Fable 5 Opus-tier support", () => {
798
+ test("Fable 5 is exposed in the Claude Code model picker list", () => {
799
+ const fable = CLAUDE_CODE_MODELS.find((m) => m.id === "claude-fable-5");
800
+ assert.ok(fable, "claude-fable-5 must appear in CLAUDE_CODE_MODELS");
801
+ assert.equal(fable!.reasoning, true);
802
+ assert.equal(fable!.contextWindow, 1_000_000);
803
+ assert.equal(fable!.maxTokens, 128_000);
804
+ });
805
+
806
+ test("Fable 5 gets Opus-tier gates: xhigh effort, adaptive thinking, 1M-context beta", () => {
807
+ const options = buildSdkOptions("claude-fable-5", "test prompt", undefined, { reasoning: "xhigh" });
808
+ assert.equal(options.effort, "xhigh", "xhigh must pass through natively for Fable 5");
809
+ assert.deepEqual(options.thinking, { type: "adaptive" }, "Fable 5 must use adaptive thinking");
810
+ assert.ok(
811
+ Array.isArray(options.betas) && (options.betas as string[]).includes("context-1m-2025-08-07"),
812
+ "Fable 5 must enable the 1M-context beta",
813
+ );
814
+ });
815
+
816
+ test("non-Opus models do not receive Fable 5's Opus-tier gates", () => {
817
+ // Failure/contrast path: Haiku supports adaptive thinking but is not xhigh/1M-tier.
818
+ const options = buildSdkOptions("claude-haiku-4-5", "test prompt", undefined, { reasoning: "xhigh" });
819
+ assert.equal(options.effort, "high", "xhigh must clamp to high for non-Opus-tier models");
820
+ assert.deepEqual(options.betas, [], "Haiku must not enable the 1M-context beta");
821
+ });
822
+ });
823
+
796
824
  describe("stream-adapter — session persistence (#2859)", () => {
797
825
  test("buildSdkOptions enables persistSession by default", () => {
798
826
  const options = buildSdkOptions("claude-sonnet-4-20250514", "test prompt");
@@ -143,7 +143,7 @@ export interface LoopDeps {
143
143
  basePath: string,
144
144
  mid: string,
145
145
  ) => void;
146
- getIsolationMode: (basePath?: string) => string;
146
+ getIsolationMode: (basePath?: string) => "none" | "worktree" | "branch";
147
147
  getCurrentBranch: (basePath: string) => string;
148
148
  autoWorktreeBranch: (milestoneId: string) => string;
149
149
  resolveMilestoneFile: (
@@ -14,13 +14,14 @@ import type { ExtensionAPI, ExtensionContext } from "@gsd/pi-coding-agent";
14
14
 
15
15
  import type { AutoAdvanceResult, AutoOrchestrationModule, AutoSessionContext, AutoStatus, AutoTerminalOutcome } from "./contracts.js";
16
16
  import type { AutoSession, PendingOrchestrationDispatch } from "./session.js";
17
- import type { GSDState } from "../types.js";
17
+ import type { GSDState, Phase } from "../types.js";
18
18
  import type { MinimalModelRegistry } from "../context-budget.js";
19
19
 
20
20
  type BlockedAdvanceResult = Extract<AutoAdvanceResult, { kind: "blocked" }>;
21
21
 
22
- import { debugCount, debugTime } from "../debug-logger.js";
22
+ import { debugCount, debugLog, debugTime } from "../debug-logger.js";
23
23
  import { reconcileBeforeDispatch } from "../state-reconciliation.js";
24
+ import { isLegalEdge, IllegalPhaseTransitionError } from "../state-transition-matrix.js";
24
25
  import { resolveDispatch } from "../auto-dispatch.js";
25
26
  import { classifyFailure } from "../recovery-classification.js";
26
27
  import { verifyExpectedArtifact, refreshRecoveryDbForArtifact } from "../auto-recovery.js";
@@ -37,7 +38,7 @@ import { checkResourcesStale, autoWorktreeBranch, mergeMilestoneToMain } from ".
37
38
  import { getSessionLockStatus } from "../session-lock.js";
38
39
  import { resolveUokFlags } from "../uok/flags.js";
39
40
  import { emitJournalEvent as _emitJournalEvent } from "../journal.js";
40
- import { loadEffectiveGSDPreferences, getIsolationMode } from "../preferences.js";
41
+ import { loadEffectiveGSDPreferences, getIsolationMode, resolveEffectiveUnitIsolationMode } from "../preferences.js";
41
42
  import {
42
43
  detectWorktreeName,
43
44
  getMainBranch,
@@ -330,6 +331,10 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
330
331
  private lastAdvanceKey: string | null = null;
331
332
  private lastFinalizedUnitKey: string | null = null;
332
333
  private dispatchKeyWindow: string[] = [];
334
+ // ADR-030 Phase Transition Invariant: the prior advance's reconciled Phase,
335
+ // the "from" endpoint of the edge check. In-memory; reset on start/resume/stop
336
+ // so the first advance of a session has no edge to assert.
337
+ private lastDerivedPhase: Phase | null = null;
333
338
  // #442: the unit key we last attempted graduated stuck-recovery for. Bounds
334
339
  // recovery to one attempt per stuck episode per run (reset on start/resume/
335
340
  // stop), mirroring the legacy Level-1-then-Level-2 escalation in phases.ts.
@@ -612,8 +617,11 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
612
617
  // ── WorktreeAdapter (folded) ─────────────────────────────────────────────
613
618
 
614
619
  private getEffectiveUnitIsolationMode(basePath: string): ReturnType<typeof getIsolationMode> {
615
- const configuredMode = getIsolationMode(basePath);
616
- return configuredMode === "worktree" && this.s.isolationDegraded ? "branch" : configuredMode;
620
+ return resolveEffectiveUnitIsolationMode(
621
+ getIsolationMode(basePath),
622
+ this.s.isolationDegraded,
623
+ this.s.strandedRecoveryIsolationMode,
624
+ );
617
625
  }
618
626
 
619
627
  private buildLifecycle(): WorktreeLifecycle {
@@ -724,6 +732,21 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
724
732
  return { action: recovery.action, reason: recovery.reason };
725
733
  }
726
734
 
735
+ /**
736
+ * ADR-030 Phase Transition Invariant (advisory mode). The matrix is an
737
+ * assertion, not a decision-maker — deriveState already chose the phase; we
738
+ * only observe illegal *derived* edges that survived reconciliation. The
739
+ * matrix is still a sparse hardening spec, so this is telemetry-only (no
740
+ * block) until it is expanded into a validated legal-edge graph. To enforce:
741
+ * `throw violation;` instead of logging — recovery-classification maps
742
+ * IllegalPhaseTransitionError to kind "illegal-transition" (escalate).
743
+ */
744
+ private observePhaseTransition(from: Phase, to: Phase): void {
745
+ if (isLegalEdge(from, to)) return;
746
+ const violation = new IllegalPhaseTransitionError(from, to);
747
+ debugLog("phase-transition-advisory", { from, to, message: violation.message });
748
+ }
749
+
727
750
  // ── Lifecycle verbs ──────────────────────────────────────────────────────
728
751
 
729
752
  /**
@@ -787,6 +810,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
787
810
  this.lastFinalizedUnitKey = null;
788
811
  this.dispatchKeyWindow = [];
789
812
  this.lastStuckRecoveryKey = null;
813
+ this.lastDerivedPhase = null;
790
814
  this.status.phase = "running";
791
815
  this.bumpTransition();
792
816
  this.journalTransition({ name: "start" });
@@ -876,6 +900,12 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
876
900
  return blocked;
877
901
  }
878
902
 
903
+ const reconciledPhase = reconciliation.stateSnapshot.phase;
904
+ if (this.lastDerivedPhase !== null) {
905
+ this.observePhaseTransition(this.lastDerivedPhase, reconciledPhase);
906
+ }
907
+ this.lastDerivedPhase = reconciledPhase;
908
+
879
909
  const decision = await this.decideNextUnit({ stateSnapshot: reconciliation.stateSnapshot });
880
910
  if (!decision) {
881
911
  const settlementBlock = this.evaluateNoRemainingUnitsSettlement(reconciliation.stateSnapshot);
@@ -1146,6 +1176,9 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
1146
1176
  // Preserve dispatchKeyWindow across resume so stuck-loop detection
1147
1177
  // accumulates across pause/resume cycles rather than resetting each time.
1148
1178
  this.lastStuckRecoveryKey = null;
1179
+ // ADR-030: drop the prior "from" — the first advance after resume has no
1180
+ // edge to assert (avoids a false illegal-edge across the pause boundary).
1181
+ this.lastDerivedPhase = null;
1149
1182
  this.status.phase = "running";
1150
1183
  this.bumpTransition();
1151
1184
  this.journalTransition({ name: "resume" });
@@ -1162,6 +1195,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
1162
1195
  this.status.activeUnit = undefined;
1163
1196
  this.lastAdvanceKey = null;
1164
1197
  this.lastFinalizedUnitKey = null;
1198
+ this.lastDerivedPhase = null;
1165
1199
  // Preserve dispatchKeyWindow on pause so stuck-loop detection accumulates
1166
1200
  // across pause/resume cycles. Only clear on a hard stop.
1167
1201
  if (reason !== "pause") {
@@ -20,6 +20,7 @@ import {
20
20
  type PreVerificationOpts,
21
21
  } from "../auto-post-unit.js";
22
22
  import { lastAssistantText } from "../user-input-boundary.js";
23
+ import { resolveEffectiveUnitIsolationMode } from "../preferences.js";
23
24
  import type { Phase } from "../types.js";
24
25
  import {
25
26
  MAX_RECOVERY_CHARS,
@@ -362,7 +363,15 @@ async function validateSourceWriteWorktreeSafety(
362
363
  if (!writesSource) return null;
363
364
 
364
365
  const projectRoot = s.canonicalProjectRoot ?? resolveWorktreeProjectRoot(s.basePath, s.originalBasePath);
365
- const isolationMode = deps.getIsolationMode(projectRoot);
366
+ // A degraded session already fell back to the milestone branch in the
367
+ // project root — validating against the canonical worktree root there
368
+ // would fail every dispatch with a false invalid-root. The same applies
369
+ // to a stranded-recovery session that adopted the milestone branch.
370
+ const isolationMode = resolveEffectiveUnitIsolationMode(
371
+ deps.getIsolationMode(projectRoot),
372
+ s.isolationDegraded,
373
+ s.strandedRecoveryIsolationMode,
374
+ );
366
375
  if (isolationMode !== "worktree") return null;
367
376
 
368
377
  const safety = createWorktreeSafetyModule();
@@ -72,7 +72,7 @@ import {
72
72
  } from "./milestone-closeout.js";
73
73
  import type { AutoSession, SidecarItem } from "./auto/session.js";
74
74
  import { getEvidence, clearEvidenceFromDisk, isExecutionToolName } from "./safety/evidence-collector.js";
75
- import { validateFileChanges } from "./safety/file-change-validator.js";
75
+ import { validateFileChanges, effectiveFileChangeAllowlist } from "./safety/file-change-validator.js";
76
76
  import { crossReferenceEvidence, type ClaimedEvidence } from "./safety/evidence-cross-ref.js";
77
77
  import { validateContent } from "./safety/content-validator.js";
78
78
  import { resolveSafetyHarnessConfig } from "./safety/safety-harness.js";
@@ -88,7 +88,7 @@ import { writeTurnGitTransaction } from "./uok/gitops.js";
88
88
  import { isClosedStatus } from "./status-guards.js";
89
89
  import { detectAbandonMilestone } from "./abandon-detect.js";
90
90
  import { getPendingGate } from "./bootstrap/write-gate.js";
91
- import { isDeterministicPolicyError } from "./auto-tool-tracking.js";
91
+ import { isDeterministicPolicyError, isToolUnavailableError } from "./auto-tool-tracking.js";
92
92
  import { formatConnectedStepStack, formatPostUnitStatusCard } from "./auto-status-message.js";
93
93
  import {
94
94
  clearProjectResearchInflightMarker,
@@ -619,8 +619,10 @@ export function _hasExecutionToolCallsInSessionForTest(entries: readonly unknown
619
619
  return true;
620
620
  }
621
621
 
622
- if (e?.type !== "message") continue;
623
- const msg = e?.message;
622
+ // Accept both session-manager entries ({type: "message", message}) and
623
+ // bare agent-end messages ({role, content}) — the auto loop passes the
624
+ // latter via opts.agentEndMessages.
625
+ const msg = e?.type === "message" ? e?.message : e;
624
626
  if (!msg || msg.role !== "assistant" || !Array.isArray(msg.content)) continue;
625
627
  for (const block of msg.content) {
626
628
  if (block?.type !== "toolCall") continue;
@@ -1535,6 +1537,11 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
1535
1537
  if (safetyConfig.enabled) {
1536
1538
  const { milestone: sMid, slice: sSid, task: sTid } = parseUnitId(s.currentUnit.id);
1537
1539
 
1540
+ const fileChangeAllowlist = effectiveFileChangeAllowlist(
1541
+ safetyConfig.file_change_allowlist,
1542
+ (prefs?.git as { manage_gitignore?: boolean } | undefined)?.manage_gitignore,
1543
+ );
1544
+
1538
1545
  // File change validation (execute-task only, after unit execution)
1539
1546
  if (safetyConfig.file_change_validation && s.currentUnit.type === "execute-task" && sMid && sSid && sTid) {
1540
1547
  try {
@@ -1554,7 +1561,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
1554
1561
  files: taskRow.files,
1555
1562
  })),
1556
1563
  );
1557
- const audit = validateFileChanges(s.basePath, expectedOutput, plannedFiles, safetyConfig.file_change_allowlist);
1564
+ const audit = validateFileChanges(s.basePath, expectedOutput, plannedFiles, fileChangeAllowlist);
1558
1565
  if (audit && audit.violations.length > 0) {
1559
1566
  const warnings = audit.violations.filter(v => v.severity === "warning");
1560
1567
  for (const v of warnings) {
@@ -1576,7 +1583,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
1576
1583
  s.basePath,
1577
1584
  expectedOutput,
1578
1585
  plannedFiles,
1579
- safetyConfig.file_change_allowlist,
1586
+ fileChangeAllowlist,
1580
1587
  );
1581
1588
  if (audit && audit.violations.length > 0) {
1582
1589
  const warnings = audit.violations.filter(v => v.severity === "warning");
@@ -2015,7 +2022,18 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
2015
2022
  "error",
2016
2023
  );
2017
2024
  } else if (!triggerArtifactVerified) {
2018
- if (s.lastToolInvocationError) {
2025
+ if (s.lastToolInvocationError && isToolUnavailableError(s.lastToolInvocationError)) {
2026
+ // Tool-unavailable is the one transient invocation error: the
2027
+ // workflow MCP server registers its surface asynchronously, so a
2028
+ // Unit's first call can race the registration. Fall through to the
2029
+ // bounded verification retry instead of pausing.
2030
+ debugLog("postUnit", { phase: "tool-unavailable-retry", unitType: s.currentUnit.type, unitId: s.currentUnit.id, error: s.lastToolInvocationError });
2031
+ ctx.ui.notify(
2032
+ `Tool unavailable for ${s.currentUnit.type}: ${s.lastToolInvocationError}. The tool surface may still be registering — retrying.`,
2033
+ "warning",
2034
+ );
2035
+ s.lastToolInvocationError = null;
2036
+ } else if (s.lastToolInvocationError) {
2019
2037
  const isUserSkip = /queued user message/i.test(s.lastToolInvocationError);
2020
2038
  const errMsg = isUserSkip
2021
2039
  ? `Tool skipped for ${s.currentUnit.type}: ${s.lastToolInvocationError}. Queued user message interrupted the turn — pausing auto-mode.`
@@ -2470,6 +2470,9 @@ export async function buildPlanSlicePrompt(
2470
2470
  `Either (a) add an earlier task that creates X on disk before the task that needs it, ` +
2471
2471
  `or (b) if this task IS the one that creates X, move X from inputs to expected_output. ` +
2472
2472
  `Do NOT put X in a task's expected_output if that task only reads or verifies X — only tasks that actually write X to disk should list it in expected_output.\n` +
2473
+ `- **"[file] X: ... GSD planning artifacts are projections preloaded as context / written by workflow tools"**: ` +
2474
+ `Remove X from the task's inputs, files, and expectedOutput entirely. Planning artifacts (anything under .gsd/, .planning/, or .audits/, or names like M001-CONTEXT.md / S01-PLAN.md) are preloaded as context and written by workflow tools — ` +
2475
+ `do NOT add a task that creates X and do NOT move X to expectedOutput.\n` +
2473
2476
  `- **"[file] X: Task T_early reads X but it's created by task T_late (sequence violation)"**: ` +
2474
2477
  `Either (a) reorder tasks so T_late (the creator) runs before T_early (the reader), ` +
2475
2478
  `or (b) if T_late doesn't actually create X (it only reads/tests it), remove X from T_late's expected_output entirely.\n` +
@@ -16,6 +16,7 @@ import type {
16
16
  ExtensionCommandContext,
17
17
  } from "@gsd/pi-coding-agent";
18
18
  import { deriveState } from "./state.js";
19
+ import { findWorktreeSegment, isGsdWorktreePath } from "./worktree-root.js";
19
20
  import { loadFile, getManifestStatus } from "./files.js";
20
21
  import type { InterruptedSessionAssessment } from "./interrupted-session.js";
21
22
  import {
@@ -56,7 +57,8 @@ import {
56
57
  detectWorktreeName,
57
58
  setActiveMilestoneId,
58
59
  } from "./worktree.js";
59
- import { getAutoWorktreePath, isInAutoWorktree, checkoutBranchWithStashGuard } from "./auto-worktree.js";
60
+ import { getAutoWorktreePath, isInAutoWorktree } from "./auto-worktree.js";
61
+ import { checkoutBranchWithStashGuard } from "./worktree-git-recovery.js";
60
62
  import { readResourceVersion, cleanStaleRuntimeUnits } from "./auto-worktree.js";
61
63
  import { worktreePath as getWorktreeDir, isInsideWorktreesDir } from "./worktree-manager.js";
62
64
  import { emitWorktreeOrphaned } from "./worktree-telemetry.js";
@@ -96,7 +98,6 @@ import {
96
98
  rmSync,
97
99
  } from "node:fs";
98
100
  import { join } from "node:path";
99
- import { sep as pathSep } from "node:path";
100
101
 
101
102
  import { validateDirectory } from "./validate-directory.js";
102
103
  import {
@@ -601,7 +602,7 @@ export function auditOrphanedMilestoneBranches(
601
602
  warnings.push(`Failed to remove worktree directory for ${milestoneId}: ${err2 instanceof Error ? err2.message : String(err2)}`);
602
603
  }
603
604
  } else {
604
- warnings.push(`Orphaned worktree directory for ${milestoneId} is outside .gsd/worktrees/ — skipping removal for safety.`);
605
+ warnings.push(`Orphaned worktree directory for ${milestoneId} is outside the GSD worktrees containers — skipping removal for safety.`);
605
606
  }
606
607
  } else {
607
608
  pushAction({
@@ -717,7 +718,7 @@ export function auditOrphanedMilestoneBranches(
717
718
  if (!existsSync(wtDir)) continue;
718
719
  if (!isInsideWorktreesDir(basePath, wtDir)) {
719
720
  warnings.push(
720
- `Orphaned worktree directory for ${m.id} is outside .gsd/worktrees/ — skipping removal for safety.`,
721
+ `Orphaned worktree directory for ${m.id} is outside the GSD worktrees containers — skipping removal for safety.`,
721
722
  );
722
723
  continue;
723
724
  }
@@ -1325,7 +1326,7 @@ export async function bootstrapAutoSession(
1325
1326
  (state.phase === "pre-planning" || state.phase === "complete") &&
1326
1327
  survivorIsolationMode !== "none" &&
1327
1328
  !detectWorktreeName(base) &&
1328
- !base.includes(`${pathSep}.gsd${pathSep}worktrees${pathSep}`)
1329
+ !isGsdWorktreePath(base)
1329
1330
  ) {
1330
1331
  const milestoneBranch = `milestone/${survivorMilestoneId}`;
1331
1332
  const { nativeBranchExists } = await import("./native-git-bridge.js");
@@ -1610,16 +1611,12 @@ export async function bootstrapAutoSession(
1610
1611
  // live here is gone.
1611
1612
 
1612
1613
  const isUnderGsdWorktrees = (p: string): boolean => {
1613
- // Direct layout: /.gsd/worktrees/
1614
- const marker = `${pathSep}.gsd${pathSep}worktrees${pathSep}`;
1615
- if (p.includes(marker)) return true;
1616
- const worktreesSuffix = `${pathSep}.gsd${pathSep}worktrees`;
1617
- if (p.endsWith(worktreesSuffix)) return true;
1618
- // Symlink-resolved layout: /.gsd/projects/<hash>/worktrees/
1619
- const symlinkRe = new RegExp(
1620
- `\\${pathSep}\\.gsd\\${pathSep}projects\\${pathSep}[a-f0-9]+\\${pathSep}worktrees(?:\\${pathSep}|$)`,
1621
- );
1622
- return symlinkRe.test(p);
1614
+ const normalized = p.replaceAll("\\", "/");
1615
+ if (findWorktreeSegment(normalized) !== null) return true;
1616
+ // The container directory itself (no trailing worktree name), in any layout.
1617
+ return normalized.endsWith("/.gsd/worktrees")
1618
+ || normalized.endsWith("/.gsd-worktrees")
1619
+ || /\/\.gsd\/projects\/[^/]+\/worktrees$/.test(normalized);
1623
1620
  };
1624
1621
 
1625
1622
  if (
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import { stripMcpToolPrefix } from "@gsd/pi-ai";
8
+ import { TOOL_SURFACE_NOT_READY } from "./tool-surface-readiness.js";
8
9
 
9
10
  interface InFlightTool {
10
11
  startedAt: number;
@@ -132,6 +133,15 @@ export function clearInFlightTools(): void {
132
133
  const TOOL_INVOCATION_ERROR_RE = /Validation failed for tool|Input validation error|Invalid arguments for tool|MCP error -32602|No such tool available|Expected ',' or '\}'(?: after property value)?(?: in JSON)?|Unexpected end of JSON|Unexpected token.*in JSON|does not provide an export named|Named export .* not found|Cannot find module|ERR_MODULE_NOT_FOUND|ERR_MODULE_NOT_EXPORTED|ERR_PACKAGE_PATH_NOT_EXPORTED/i;
133
134
  const DETERMINISTIC_POLICY_ERROR_RE = /(?:^|\b)(?:HARD BLOCK:|Blocked: \/gsd queue is a planning tool|Direct writes to \.gsd\/STATE\.md and \.gsd\/gsd\.db are blocked|This is a mechanical gate)/i;
134
135
 
136
+ /**
137
+ * Matches the runtime's "tool not registered" error. Unlike the deterministic
138
+ * invocation failures above, this one is usually transient: the workflow MCP
139
+ * server registers its tool surface asynchronously after session start, so a
140
+ * Unit's first tool call can race the registration. Callers should retry
141
+ * (bounded) instead of breaking the loop.
142
+ */
143
+ const TOOL_UNAVAILABLE_ERROR_RE = new RegExp(`No such tool available|${TOOL_SURFACE_NOT_READY}`, "i");
144
+
135
145
  /**
136
146
  * Returns true if the error message indicates a deterministic invocation or
137
147
  * policy failure (as opposed to a normal tool execution error).
@@ -141,6 +151,15 @@ export function isToolInvocationError(errorMsg: string): boolean {
141
151
  return TOOL_INVOCATION_ERROR_RE.test(errorMsg) || isDeterministicPolicyError(errorMsg);
142
152
  }
143
153
 
154
+ /**
155
+ * Returns true if the error message indicates the called tool was not on the
156
+ * session's tool surface (MCP startup race — see TOOL_UNAVAILABLE_ERROR_RE).
157
+ */
158
+ export function isToolUnavailableError(errorMsg: string): boolean {
159
+ if (!errorMsg) return false;
160
+ return TOOL_UNAVAILABLE_ERROR_RE.test(errorMsg);
161
+ }
162
+
144
163
  /**
145
164
  * Returns true if the error message indicates the tool was skipped because
146
165
  * a queued user message interrupted the turn (#3595). Retrying will produce