@opengsd/gsd-pi 1.2.0-dev.4c756166 → 1.2.0-dev.955e4da0

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 (246) hide show
  1. package/dist/resources/.managed-resources-content-hash +1 -1
  2. package/dist/resources/extensions/bg-shell/utilities.js +2 -2
  3. package/dist/resources/extensions/claude-code-cli/models.js +9 -0
  4. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +8 -2
  5. package/dist/resources/extensions/gsd/auto/orchestrator.js +33 -4
  6. package/dist/resources/extensions/gsd/auto/phases.js +6 -1
  7. package/dist/resources/extensions/gsd/auto-post-unit.js +8 -6
  8. package/dist/resources/extensions/gsd/auto-start.js +8 -13
  9. package/dist/resources/extensions/gsd/auto-worktree-repair.js +10 -2
  10. package/dist/resources/extensions/gsd/auto-worktree.js +13 -270
  11. package/dist/resources/extensions/gsd/auto.js +4 -7
  12. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +9 -6
  13. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +32 -3
  14. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +26 -4
  15. package/dist/resources/extensions/gsd/captures.js +5 -13
  16. package/dist/resources/extensions/gsd/closeout-recovery.js +3 -2
  17. package/dist/resources/extensions/gsd/commands/catalog.js +6 -62
  18. package/dist/resources/extensions/gsd/db/engine.js +755 -0
  19. package/dist/resources/extensions/gsd/db/queries.js +372 -0
  20. package/dist/resources/extensions/gsd/db/sql-constants.js +11 -0
  21. package/dist/resources/extensions/gsd/db/writers/cascades.js +194 -0
  22. package/dist/resources/extensions/gsd/db/writers/import-restore.js +182 -0
  23. package/dist/resources/extensions/gsd/db/writers/memory.js +149 -0
  24. package/dist/resources/extensions/gsd/db/writers/reconcile.js +458 -0
  25. package/dist/resources/extensions/gsd/db/writers/status.js +70 -0
  26. package/dist/resources/extensions/gsd/doctor-environment.js +8 -10
  27. package/dist/resources/extensions/gsd/doctor-git-checks.js +4 -3
  28. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +9 -2
  29. package/dist/resources/extensions/gsd/git-service.js +1 -0
  30. package/dist/resources/extensions/gsd/gitignore.js +3 -0
  31. package/dist/resources/extensions/gsd/gsd-db.js +171 -2048
  32. package/dist/resources/extensions/gsd/guided-flow.js +34 -3
  33. package/dist/resources/extensions/gsd/migrate/safety.js +17 -9
  34. package/dist/resources/extensions/gsd/migration-auto-check.js +24 -3
  35. package/dist/resources/extensions/gsd/model-cost-table.js +1 -0
  36. package/dist/resources/extensions/gsd/model-router.js +3 -0
  37. package/dist/resources/extensions/gsd/parallel-merge.js +14 -11
  38. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +7 -5
  39. package/dist/resources/extensions/gsd/paths.js +10 -24
  40. package/dist/resources/extensions/gsd/preferences.js +14 -0
  41. package/dist/resources/extensions/gsd/recovery-classification.js +12 -1
  42. package/dist/resources/extensions/gsd/safety/evidence-collector.js +37 -4
  43. package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +7 -2
  44. package/dist/resources/extensions/gsd/safety/file-change-validator.js +10 -0
  45. package/dist/resources/extensions/gsd/state-transition-matrix.js +38 -0
  46. package/dist/resources/extensions/gsd/status-guards.js +56 -8
  47. package/dist/resources/extensions/gsd/tools/complete-slice.js +24 -43
  48. package/dist/resources/extensions/gsd/tools/exec-tool.js +5 -5
  49. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +11 -29
  50. package/dist/resources/extensions/gsd/tools/reopen-slice.js +14 -33
  51. package/dist/resources/extensions/gsd/tools/skip-slice.js +18 -36
  52. package/dist/resources/extensions/gsd/undo.js +8 -7
  53. package/dist/resources/extensions/gsd/worktree-git-recovery.js +287 -0
  54. package/dist/resources/extensions/gsd/worktree-lifecycle.js +9 -1
  55. package/dist/resources/extensions/gsd/worktree-manager.js +45 -28
  56. package/dist/resources/extensions/gsd/worktree-placement.js +59 -0
  57. package/dist/resources/extensions/gsd/worktree-reentry.js +12 -8
  58. package/dist/resources/extensions/gsd/worktree-root.js +17 -6
  59. package/dist/resources/extensions/gsd/worktree-safety.js +8 -5
  60. package/dist/resources/extensions/gsd/worktree-session-state.js +12 -10
  61. package/dist/resources/skills/gsd-browser/SKILL.md +1 -1
  62. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  63. package/dist/web/standalone/.next/BUILD_ID +1 -1
  64. package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
  65. package/dist/web/standalone/.next/build-manifest.json +2 -2
  66. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  67. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  68. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  76. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  84. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  85. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  86. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  87. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  88. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  89. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  90. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  91. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  92. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  93. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  94. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  95. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  96. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  97. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  98. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  99. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  100. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  101. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  102. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  103. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  104. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  105. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  106. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  107. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  108. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  109. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  110. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  111. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  112. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  113. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  114. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  115. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  116. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  117. package/dist/web/standalone/.next/server/app/index.html +1 -1
  118. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
  125. package/dist/web/standalone/.next/server/chunks/{5047.js → 5942.js} +2 -2
  126. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  127. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  129. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  130. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  131. package/dist/worktree-status-banner.js +7 -3
  132. package/package.json +1 -1
  133. package/packages/cloud-mcp-gateway/package.json +2 -2
  134. package/packages/contracts/package.json +1 -1
  135. package/packages/daemon/package.json +4 -4
  136. package/packages/gsd-agent-core/package.json +5 -5
  137. package/packages/gsd-agent-modes/package.json +7 -7
  138. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  139. package/packages/mcp-server/dist/workflow-tools.js +30 -21
  140. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  141. package/packages/mcp-server/package.json +3 -3
  142. package/packages/native/package.json +1 -1
  143. package/packages/pi-agent-core/package.json +1 -1
  144. package/packages/pi-ai/dist/models.generated.d.ts +266 -35
  145. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  146. package/packages/pi-ai/dist/models.generated.js +235 -46
  147. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  148. package/packages/pi-ai/package.json +1 -1
  149. package/packages/pi-coding-agent/dist/core/capability-patches.d.ts.map +1 -1
  150. package/packages/pi-coding-agent/dist/core/capability-patches.js +3 -1
  151. package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
  152. package/packages/pi-coding-agent/package.json +7 -7
  153. package/packages/pi-tui/package.json +2 -2
  154. package/packages/rpc-client/package.json +2 -2
  155. package/pkg/package.json +1 -1
  156. package/src/resources/extensions/bg-shell/utilities.ts +2 -2
  157. package/src/resources/extensions/claude-code-cli/models.ts +9 -0
  158. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +6 -0
  159. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +28 -0
  160. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -1
  161. package/src/resources/extensions/gsd/auto/orchestrator.ts +39 -5
  162. package/src/resources/extensions/gsd/auto/phases.ts +10 -1
  163. package/src/resources/extensions/gsd/auto-post-unit.ts +12 -5
  164. package/src/resources/extensions/gsd/auto-start.ts +8 -14
  165. package/src/resources/extensions/gsd/auto-worktree-repair.ts +13 -2
  166. package/src/resources/extensions/gsd/auto-worktree.ts +20 -280
  167. package/src/resources/extensions/gsd/auto.ts +12 -9
  168. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +10 -6
  169. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +32 -3
  170. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +25 -3
  171. package/src/resources/extensions/gsd/captures.ts +5 -14
  172. package/src/resources/extensions/gsd/closeout-recovery.ts +2 -1
  173. package/src/resources/extensions/gsd/commands/catalog.ts +6 -68
  174. package/src/resources/extensions/gsd/db/engine.ts +809 -0
  175. package/src/resources/extensions/gsd/db/queries.ts +453 -0
  176. package/src/resources/extensions/gsd/db/sql-constants.ts +12 -0
  177. package/src/resources/extensions/gsd/db/writers/cascades.ts +237 -0
  178. package/src/resources/extensions/gsd/db/writers/import-restore.ts +310 -0
  179. package/src/resources/extensions/gsd/db/writers/memory.ts +220 -0
  180. package/src/resources/extensions/gsd/db/writers/reconcile.ts +500 -0
  181. package/src/resources/extensions/gsd/db/writers/status.ts +88 -0
  182. package/src/resources/extensions/gsd/doctor-environment.ts +8 -11
  183. package/src/resources/extensions/gsd/doctor-git-checks.ts +3 -3
  184. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +10 -3
  185. package/src/resources/extensions/gsd/git-service.ts +1 -0
  186. package/src/resources/extensions/gsd/gitignore.ts +3 -0
  187. package/src/resources/extensions/gsd/gsd-db.ts +173 -2373
  188. package/src/resources/extensions/gsd/guided-flow.ts +34 -3
  189. package/src/resources/extensions/gsd/migrate/safety.ts +15 -7
  190. package/src/resources/extensions/gsd/migration-auto-check.ts +28 -3
  191. package/src/resources/extensions/gsd/model-cost-table.ts +1 -0
  192. package/src/resources/extensions/gsd/model-router.ts +3 -0
  193. package/src/resources/extensions/gsd/parallel-merge.ts +12 -9
  194. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +6 -5
  195. package/src/resources/extensions/gsd/paths.ts +9 -22
  196. package/src/resources/extensions/gsd/preferences.ts +18 -0
  197. package/src/resources/extensions/gsd/recovery-classification.ts +14 -1
  198. package/src/resources/extensions/gsd/safety/evidence-collector.ts +36 -4
  199. package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +7 -2
  200. package/src/resources/extensions/gsd/safety/file-change-validator.ts +14 -0
  201. package/src/resources/extensions/gsd/state-transition-matrix.ts +42 -0
  202. package/src/resources/extensions/gsd/status-guards.ts +59 -8
  203. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +123 -0
  204. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +3 -1
  205. package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +46 -0
  206. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +2 -2
  207. package/src/resources/extensions/gsd/tests/auto-worktree-repair.test.ts +4 -2
  208. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +22 -0
  209. package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +157 -0
  210. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +33 -1
  211. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +5 -4
  212. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +1 -1
  213. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +3 -2
  214. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +85 -1
  215. package/src/resources/extensions/gsd/tests/recovery-classification-illegal-transition.test.ts +30 -0
  216. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +91 -1
  217. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +38 -0
  218. package/src/resources/extensions/gsd/tests/session-switch-clears-pending-autostart.test.ts +108 -0
  219. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +43 -6
  220. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +36 -0
  221. package/src/resources/extensions/gsd/tests/status-guards.test.ts +38 -0
  222. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +41 -4
  223. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +22 -1
  224. package/src/resources/extensions/gsd/tests/worktree-placement.test.ts +113 -0
  225. package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +1 -1
  226. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +3 -1
  227. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +12 -6
  228. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +2 -2
  229. package/src/resources/extensions/gsd/tests/write-gate.test.ts +42 -0
  230. package/src/resources/extensions/gsd/tools/complete-slice.ts +23 -58
  231. package/src/resources/extensions/gsd/tools/exec-tool.ts +5 -5
  232. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +11 -38
  233. package/src/resources/extensions/gsd/tools/reopen-slice.ts +14 -42
  234. package/src/resources/extensions/gsd/tools/skip-slice.ts +18 -44
  235. package/src/resources/extensions/gsd/undo.ts +9 -8
  236. package/src/resources/extensions/gsd/worktree-git-recovery.ts +308 -0
  237. package/src/resources/extensions/gsd/worktree-lifecycle.ts +10 -1
  238. package/src/resources/extensions/gsd/worktree-manager.ts +47 -28
  239. package/src/resources/extensions/gsd/worktree-placement.ts +63 -0
  240. package/src/resources/extensions/gsd/worktree-reentry.ts +10 -7
  241. package/src/resources/extensions/gsd/worktree-root.ts +17 -6
  242. package/src/resources/extensions/gsd/worktree-safety.ts +8 -5
  243. package/src/resources/extensions/gsd/worktree-session-state.ts +12 -10
  244. package/src/resources/skills/gsd-browser/SKILL.md +1 -1
  245. /package/dist/web/standalone/.next/static/{DUFWcMFRH3iXh7d2fbrOF → C24pqUd-aru-l0Dp0gLZP}/_buildManifest.js +0 -0
  246. /package/dist/web/standalone/.next/static/{DUFWcMFRH3iXh7d2fbrOF → C24pqUd-aru-l0Dp0gLZP}/_ssgManifest.js +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gsd/pi-ai",
3
- "version": "1.2.0-dev.4c756166",
3
+ "version": "1.2.0-dev.955e4da0",
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.4c756166",
3
+ "version": "1.2.0-dev.955e4da0",
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.4c756166",
36
+ "@opengsd/contracts": "^1.2.0-dev.955e4da0",
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.4c756166",
57
- "@gsd/native": "^1.2.0-dev.4c756166",
58
- "@gsd/pi-agent-core": "^1.2.0-dev.4c756166",
59
- "@gsd/pi-ai": "^1.2.0-dev.4c756166",
60
- "@gsd/pi-tui": "^1.2.0-dev.4c756166",
56
+ "@gsd/agent-core": "^1.2.0-dev.955e4da0",
57
+ "@gsd/native": "^1.2.0-dev.955e4da0",
58
+ "@gsd/pi-agent-core": "^1.2.0-dev.955e4da0",
59
+ "@gsd/pi-ai": "^1.2.0-dev.955e4da0",
60
+ "@gsd/pi-tui": "^1.2.0-dev.955e4da0",
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.4c756166",
3
+ "version": "1.2.0-dev.955e4da0",
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.4c756166",
24
+ "@gsd/native": "^1.2.0-dev.955e4da0",
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.4c756166",
3
+ "version": "1.2.0-dev.955e4da0",
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.4c756166"
37
+ "@opengsd/contracts": "^1.2.0-dev.955e4da0"
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.4c756166",
3
+ "version": "1.2.0-dev.955e4da0",
4
4
  "piConfig": {
5
5
  "name": "gsd",
6
6
  "configDir": ".gsd"
@@ -45,7 +45,7 @@ export function formatTimeAgo(timestamp: number): string {
45
45
 
46
46
  function deriveProjectRootFromAutoWorktree(cachedCwd?: string): string | undefined {
47
47
  if (!cachedCwd) return undefined;
48
- const match = cachedCwd.match(/^(.*?)[\\/]\.gsd[\\/]worktrees[\\/][^\\/]+(?:[\\/].*)?$/);
48
+ const match = cachedCwd.match(/^(.*?)[\\/]\.gsd(?:-worktrees|[\\/]worktrees)[\\/][^\\/]+(?:[\\/].*)?$/);
49
49
  return match?.[1];
50
50
  }
51
51
 
@@ -84,7 +84,7 @@ export function resolveBgShellPersistenceCwd(
84
84
  pathExists: (path: string) => boolean = existsSync,
85
85
  ): string {
86
86
  const resolvedLiveCwd = liveCwd ?? getBgShellLiveCwd(cachedCwd, pathExists);
87
- const cachedIsAutoWorktree = /(?:^|[\\/])\.gsd[\\/]worktrees[\\/]/.test(cachedCwd);
87
+ const cachedIsAutoWorktree = /(?:^|[\\/])\.gsd(?:-worktrees|[\\/]worktrees)[\\/]/.test(cachedCwd);
88
88
  if (!cachedIsAutoWorktree) return cachedCwd;
89
89
  if (cachedCwd === resolvedLiveCwd && pathExists(cachedCwd)) return cachedCwd;
90
90
  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)",
@@ -1542,6 +1542,8 @@ function modelSupportsAdaptiveThinking(modelId: string): boolean {
1542
1542
  || modelId.includes("opus-4.7")
1543
1543
  || modelId.includes("opus-4-8")
1544
1544
  || modelId.includes("opus-4.8")
1545
+ || modelId.includes("fable-5")
1546
+ || modelId.includes("fable.5")
1545
1547
  || modelId.includes("sonnet-4-6")
1546
1548
  || modelId.includes("sonnet-4.6")
1547
1549
  || modelId.includes("sonnet-4-7")
@@ -1567,6 +1569,8 @@ function mapThinkingLevelToAnthropicEffort(level: ThinkingLevel | undefined, mod
1567
1569
  || modelId.includes("opus-4.7")
1568
1570
  || modelId.includes("opus-4-8")
1569
1571
  || modelId.includes("opus-4.8")
1572
+ || modelId.includes("fable-5")
1573
+ || modelId.includes("fable.5")
1570
1574
  ) return "xhigh";
1571
1575
  if (modelId.includes("opus-4-6") || modelId.includes("opus-4.6")) return "max";
1572
1576
  return "high";
@@ -1899,6 +1903,8 @@ export function buildSdkOptions(
1899
1903
  || modelId.includes("opus-4.7")
1900
1904
  || modelId.includes("opus-4-8")
1901
1905
  || modelId.includes("opus-4.8")
1906
+ || modelId.includes("fable-5")
1907
+ || modelId.includes("fable.5")
1902
1908
  ) ? ["context-1m-2025-08-07"] : [],
1903
1909
  ...(thinkingConfig ?? {}),
1904
1910
  ...(effort ? { effort } : {}),
@@ -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";
@@ -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");
@@ -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 {
@@ -96,7 +97,6 @@ import {
96
97
  rmSync,
97
98
  } from "node:fs";
98
99
  import { join } from "node:path";
99
- import { sep as pathSep } from "node:path";
100
100
 
101
101
  import { validateDirectory } from "./validate-directory.js";
102
102
  import {
@@ -601,7 +601,7 @@ export function auditOrphanedMilestoneBranches(
601
601
  warnings.push(`Failed to remove worktree directory for ${milestoneId}: ${err2 instanceof Error ? err2.message : String(err2)}`);
602
602
  }
603
603
  } else {
604
- warnings.push(`Orphaned worktree directory for ${milestoneId} is outside .gsd/worktrees/ — skipping removal for safety.`);
604
+ warnings.push(`Orphaned worktree directory for ${milestoneId} is outside the GSD worktrees containers — skipping removal for safety.`);
605
605
  }
606
606
  } else {
607
607
  pushAction({
@@ -717,7 +717,7 @@ export function auditOrphanedMilestoneBranches(
717
717
  if (!existsSync(wtDir)) continue;
718
718
  if (!isInsideWorktreesDir(basePath, wtDir)) {
719
719
  warnings.push(
720
- `Orphaned worktree directory for ${m.id} is outside .gsd/worktrees/ — skipping removal for safety.`,
720
+ `Orphaned worktree directory for ${m.id} is outside the GSD worktrees containers — skipping removal for safety.`,
721
721
  );
722
722
  continue;
723
723
  }
@@ -1325,7 +1325,7 @@ export async function bootstrapAutoSession(
1325
1325
  (state.phase === "pre-planning" || state.phase === "complete") &&
1326
1326
  survivorIsolationMode !== "none" &&
1327
1327
  !detectWorktreeName(base) &&
1328
- !base.includes(`${pathSep}.gsd${pathSep}worktrees${pathSep}`)
1328
+ !isGsdWorktreePath(base)
1329
1329
  ) {
1330
1330
  const milestoneBranch = `milestone/${survivorMilestoneId}`;
1331
1331
  const { nativeBranchExists } = await import("./native-git-bridge.js");
@@ -1610,16 +1610,10 @@ export async function bootstrapAutoSession(
1610
1610
  // live here is gone.
1611
1611
 
1612
1612
  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);
1613
+ const normalized = p.replaceAll("\\", "/");
1614
+ if (findWorktreeSegment(normalized) !== null) return true;
1615
+ // The container directory itself (no trailing worktree name).
1616
+ return normalized.endsWith("/.gsd/worktrees") || normalized.endsWith("/.gsd-worktrees");
1623
1617
  };
1624
1618
 
1625
1619
  if (
@@ -5,6 +5,7 @@ import { existsSync, lstatSync, readdirSync, type Stats } from "node:fs";
5
5
  import { join } from "node:path";
6
6
 
7
7
  import { worktreePath } from "./worktree-manager.js";
8
+ import { worktreesDirs } from "./worktree-placement.js";
8
9
  import { normalizeWorktreePathForCompare } from "./worktree-root.js";
9
10
  import type { WorktreeSafetyResult } from "./worktree-safety.js";
10
11
 
@@ -39,6 +40,16 @@ export function expectedAutoWorktreePath(
39
40
  return worktreePath(projectRoot, id);
40
41
  }
41
42
 
43
+ /** Every path the milestone worktree may legitimately live at (canonical + legacy). */
44
+ function candidateAutoWorktreePaths(
45
+ projectRoot: string,
46
+ milestoneId: string | null | undefined,
47
+ ): string[] {
48
+ const id = milestoneId?.trim();
49
+ if (!id || !isValidMilestoneId(id)) return [];
50
+ return worktreesDirs(projectRoot).map((dir) => join(dir, id));
51
+ }
52
+
42
53
  export function resolvePausedAutoWorktreePath(input: {
43
54
  basePath: string;
44
55
  originalBasePath?: string | null;
@@ -82,8 +93,8 @@ export function assessAutoWorktreeRepairTarget(input: {
82
93
  if (!expectedPath) {
83
94
  return { ok: false, reason: "missing expected worktree path" };
84
95
  }
85
- const computedExpectedPath = expectedAutoWorktreePath(input.projectRoot, input.milestoneId);
86
- if (!computedExpectedPath || !samePath(expectedPath, computedExpectedPath)) {
96
+ const candidatePaths = candidateAutoWorktreePaths(input.projectRoot, input.milestoneId);
97
+ if (candidatePaths.length === 0 || !candidatePaths.some((candidate) => samePath(expectedPath, candidate))) {
87
98
  return { ok: false, reason: "expected worktree path does not match milestone" };
88
99
  }
89
100
  if (!samePath(input.activeRoot, input.projectRoot) && !samePath(input.activeRoot, expectedPath)) {