@opengsd/gsd-pi 1.5.0 → 1.6.0

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 (499) hide show
  1. package/README.md +10 -10
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/ask-user-questions.js +1 -1
  4. package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +114 -36
  5. package/dist/resources/extensions/gsd/activity-log.js +1 -1
  6. package/dist/resources/extensions/gsd/auto/closeout.js +97 -5
  7. package/dist/resources/extensions/gsd/auto/orchestrator.js +20 -13
  8. package/dist/resources/extensions/gsd/auto/pre-dispatch.js +6 -3
  9. package/dist/resources/extensions/gsd/auto/unit-phase.js +5 -9
  10. package/dist/resources/extensions/gsd/auto-artifact-paths.js +14 -5
  11. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +11 -7
  12. package/dist/resources/extensions/gsd/auto-dispatch.js +69 -17
  13. package/dist/resources/extensions/gsd/auto-model-selection.js +28 -1
  14. package/dist/resources/extensions/gsd/auto-post-unit.js +4 -3
  15. package/dist/resources/extensions/gsd/auto-prompts.js +29 -117
  16. package/dist/resources/extensions/gsd/auto-recovery.js +50 -6
  17. package/dist/resources/extensions/gsd/auto-start.js +57 -33
  18. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +12 -2
  19. package/dist/resources/extensions/gsd/auto-timers.js +9 -2
  20. package/dist/resources/extensions/gsd/auto-worktree-branch-lifecycle.js +189 -0
  21. package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +133 -0
  22. package/dist/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.js +35 -0
  23. package/dist/resources/extensions/gsd/auto-worktree-creation.js +130 -0
  24. package/dist/resources/extensions/gsd/auto-worktree-entry.js +118 -0
  25. package/dist/resources/extensions/gsd/auto-worktree-merge-already-merged.js +98 -0
  26. package/dist/resources/extensions/gsd/auto-worktree-merge-branch-head.js +52 -0
  27. package/dist/resources/extensions/gsd/auto-worktree-merge-cleanup.js +87 -0
  28. package/dist/resources/extensions/gsd/auto-worktree-merge-code-changes.js +46 -0
  29. package/dist/resources/extensions/gsd/auto-worktree-merge-db-ready.js +68 -0
  30. package/dist/resources/extensions/gsd/auto-worktree-merge-integration-branch.js +51 -0
  31. package/dist/resources/extensions/gsd/auto-worktree-merge-message.js +106 -0
  32. package/dist/resources/extensions/gsd/auto-worktree-merge-pre-teardown.js +64 -0
  33. package/dist/resources/extensions/gsd/auto-worktree-merge-stash.js +168 -0
  34. package/dist/resources/extensions/gsd/auto-worktree-merge.js +302 -0
  35. package/dist/resources/extensions/gsd/auto-worktree-milestone-shelter.js +119 -0
  36. package/dist/resources/extensions/gsd/auto-worktree-path-resolution.js +5 -0
  37. package/dist/resources/extensions/gsd/auto-worktree-path-utils.js +5 -0
  38. package/dist/resources/extensions/gsd/auto-worktree-resource-version.js +41 -0
  39. package/dist/resources/extensions/gsd/auto-worktree-runtime-cleanup.js +99 -0
  40. package/dist/resources/extensions/gsd/auto-worktree-session-registry.js +57 -0
  41. package/dist/resources/extensions/gsd/auto-worktree-sync.js +249 -0
  42. package/dist/resources/extensions/gsd/auto-worktree-teardown.js +120 -0
  43. package/dist/resources/extensions/gsd/auto-worktree.js +20 -2073
  44. package/dist/resources/extensions/gsd/auto.js +106 -34
  45. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +1 -1
  46. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +20 -2
  47. package/dist/resources/extensions/gsd/bootstrap/system-context.js +1 -1
  48. package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +185 -27
  49. package/dist/resources/extensions/gsd/codebase-generator.js +7 -1
  50. package/dist/resources/extensions/gsd/commands-handlers.js +1 -1
  51. package/dist/resources/extensions/gsd/commands-workflow-templates.js +3 -3
  52. package/dist/resources/extensions/gsd/compat/compat-marker.js +44 -0
  53. package/dist/resources/extensions/gsd/config-overlay.js +7 -2
  54. package/dist/resources/extensions/gsd/db/engine.js +33 -0
  55. package/dist/resources/extensions/gsd/db/queries.js +9 -9
  56. package/dist/resources/extensions/gsd/db/writers/cascades.js +20 -2
  57. package/dist/resources/extensions/gsd/db-adapter.js +30 -3
  58. package/dist/resources/extensions/gsd/docs/preferences-reference.md +3 -3
  59. package/dist/resources/extensions/gsd/doctor-engine-checks.js +93 -11
  60. package/dist/resources/extensions/gsd/flat-phase-migration.js +32 -3
  61. package/dist/resources/extensions/gsd/forensics.js +1 -1
  62. package/dist/resources/extensions/gsd/git-conflict-resolve.js +2 -2
  63. package/dist/resources/extensions/gsd/git-service.js +45 -0
  64. package/dist/resources/extensions/gsd/gsd-db.js +23 -11
  65. package/dist/resources/extensions/gsd/guided-flow.js +22 -17
  66. package/dist/resources/extensions/gsd/journal.js +1 -1
  67. package/dist/resources/extensions/gsd/markdown-renderer.js +34 -79
  68. package/dist/resources/extensions/gsd/md-importer.js +89 -23
  69. package/dist/resources/extensions/gsd/metrics.js +2 -2
  70. package/dist/resources/extensions/gsd/migration-auto-check.js +30 -3
  71. package/dist/resources/extensions/gsd/milestone-merge-transaction.js +11 -0
  72. package/dist/resources/extensions/gsd/milestone-settlement.js +1 -1
  73. package/dist/resources/extensions/gsd/parallel-merge.js +1 -1
  74. package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -1
  75. package/dist/resources/extensions/gsd/paths.js +87 -52
  76. package/dist/resources/extensions/gsd/post-unit-hooks.js +27 -0
  77. package/dist/resources/extensions/gsd/preferences-models.js +66 -15
  78. package/dist/resources/extensions/gsd/preferences-skills.js +10 -16
  79. package/dist/resources/extensions/gsd/preferences-types.js +1 -0
  80. package/dist/resources/extensions/gsd/preferences-validation.js +148 -10
  81. package/dist/resources/extensions/gsd/preferences.js +20 -0
  82. package/dist/resources/extensions/gsd/prompts/system.md +6 -6
  83. package/dist/resources/extensions/gsd/quick.js +12 -3
  84. package/dist/resources/extensions/gsd/rule-registry.js +106 -10
  85. package/dist/resources/extensions/gsd/skill-discovery.js +36 -23
  86. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +2 -1
  87. package/dist/resources/extensions/gsd/state/derive/from-db.js +88 -153
  88. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +1 -10
  89. package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +3 -24
  90. package/dist/resources/extensions/gsd/state-reconciliation/index.js +10 -0
  91. package/dist/resources/extensions/gsd/tool-contract.js +14 -0
  92. package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -5
  93. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +16 -10
  94. package/dist/resources/extensions/gsd/tools/reopen-slice.js +5 -0
  95. package/dist/resources/extensions/gsd/tools/reopen-task.js +13 -5
  96. package/dist/resources/extensions/gsd/tools/validate-milestone.js +3 -8
  97. package/dist/resources/extensions/gsd/uat-dispatch.js +94 -0
  98. package/dist/resources/extensions/gsd/unit-registry.js +12 -2
  99. package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +1 -1
  100. package/dist/resources/extensions/gsd/uok/audit-toggle.js +31 -2
  101. package/dist/resources/extensions/gsd/uok/audit.js +3 -0
  102. package/dist/resources/extensions/gsd/uok/gate-runner.js +22 -30
  103. package/dist/resources/extensions/gsd/uok/gitops.js +18 -15
  104. package/dist/resources/extensions/gsd/uok/kernel.js +120 -46
  105. package/dist/resources/extensions/gsd/uok/model-policy.js +17 -14
  106. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -1
  107. package/dist/resources/extensions/gsd/workflow-event-ledger.js +1 -1
  108. package/dist/resources/extensions/gsd/workflow-logger.js +1 -1
  109. package/dist/resources/extensions/gsd/workflow-projections.js +9 -26
  110. package/dist/resources/extensions/gsd/workspace-git-preflight.js +2 -2
  111. package/dist/resources/extensions/gsd/workspace.js +5 -14
  112. package/dist/resources/extensions/gsd/worktree-command.js +1 -1
  113. package/dist/resources/extensions/gsd/worktree-lifecycle.js +14 -9
  114. package/dist/resources/extensions/gsd/worktree-reentry.js +2 -1
  115. package/dist/resources/extensions/shared/gsd-browser-cli.js +29 -0
  116. package/dist/resources/extensions/shared/interview-ui.js +62 -9
  117. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  118. package/dist/web/standalone/.next/BUILD_ID +1 -1
  119. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  120. package/dist/web/standalone/.next/build-manifest.json +2 -2
  121. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  122. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  123. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  129. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  130. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  131. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  132. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  134. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  135. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  136. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  137. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  139. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  140. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  141. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  142. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  143. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  144. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  145. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  146. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  147. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  148. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  149. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  150. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  151. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  152. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  153. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  154. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  155. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  156. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  157. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  158. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  159. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  160. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  161. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  162. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  163. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  164. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  165. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  166. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  167. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  168. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  169. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  170. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  171. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  172. package/dist/web/standalone/.next/server/app/index.html +1 -1
  173. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  174. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  175. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  176. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  177. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  178. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  179. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  180. package/dist/web/standalone/.next/server/chunks/{1128.js → 1991.js} +1 -1
  181. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  182. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  183. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  184. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  185. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  186. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  187. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  188. package/dist/worktree-cli-create.d.ts +10 -0
  189. package/dist/worktree-cli-create.js +11 -0
  190. package/dist/worktree-cli-format.d.ts +12 -0
  191. package/dist/worktree-cli-format.js +38 -0
  192. package/dist/worktree-cli-plan.d.ts +16 -0
  193. package/dist/worktree-cli-plan.js +19 -0
  194. package/dist/worktree-cli-session.d.ts +13 -0
  195. package/dist/worktree-cli-session.js +18 -0
  196. package/dist/worktree-cli-status.d.ts +35 -0
  197. package/dist/worktree-cli-status.js +54 -0
  198. package/dist/worktree-cli.d.ts +1 -16
  199. package/dist/worktree-cli.js +28 -122
  200. package/integrations/hermes/open_gsd_hermes/gsd_client.py +25 -36
  201. package/integrations/hermes/pyproject.toml +1 -1
  202. package/integrations/hermes/tests/test_gsd_client_timeout.py +4 -4
  203. package/package.json +6 -6
  204. package/packages/cloud-mcp-gateway/package.json +2 -2
  205. package/packages/contracts/package.json +1 -1
  206. package/packages/daemon/dist/orchestrator-agent.d.ts +21 -0
  207. package/packages/daemon/dist/orchestrator-agent.d.ts.map +1 -0
  208. package/packages/daemon/dist/orchestrator-agent.js +113 -0
  209. package/packages/daemon/dist/orchestrator-agent.js.map +1 -0
  210. package/packages/daemon/dist/orchestrator-tools.d.ts +12 -0
  211. package/packages/daemon/dist/orchestrator-tools.d.ts.map +1 -0
  212. package/packages/daemon/dist/orchestrator-tools.js +137 -0
  213. package/packages/daemon/dist/orchestrator-tools.js.map +1 -0
  214. package/packages/daemon/dist/orchestrator.d.ts +4 -56
  215. package/packages/daemon/dist/orchestrator.d.ts.map +1 -1
  216. package/packages/daemon/dist/orchestrator.js +13 -303
  217. package/packages/daemon/dist/orchestrator.js.map +1 -1
  218. package/packages/daemon/dist/orchestrator.test.js +11 -1
  219. package/packages/daemon/dist/orchestrator.test.js.map +1 -1
  220. package/packages/daemon/package.json +4 -4
  221. package/packages/gsd-agent-core/dist/export-html/template.js +53 -4
  222. package/packages/gsd-agent-core/package.json +5 -5
  223. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  224. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +3 -2
  225. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  226. package/packages/gsd-agent-modes/package.json +7 -7
  227. package/packages/mcp-server/package.json +4 -4
  228. package/packages/native/package.json +1 -1
  229. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  230. package/packages/pi-agent-core/dist/agent-loop.js +14 -9
  231. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  232. package/packages/pi-agent-core/package.json +1 -1
  233. package/packages/pi-ai/dist/index.d.ts +1 -0
  234. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  235. package/packages/pi-ai/dist/index.js +1 -0
  236. package/packages/pi-ai/dist/index.js.map +1 -1
  237. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  238. package/packages/pi-ai/dist/providers/transform-messages.js +7 -3
  239. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  240. package/packages/pi-ai/dist/tool-result-content.d.ts +3 -0
  241. package/packages/pi-ai/dist/tool-result-content.d.ts.map +1 -0
  242. package/packages/pi-ai/dist/tool-result-content.js +62 -0
  243. package/packages/pi-ai/dist/tool-result-content.js.map +1 -0
  244. package/packages/pi-ai/dist/types.d.ts +8 -20
  245. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  246. package/packages/pi-ai/dist/types.js.map +1 -1
  247. package/packages/pi-ai/package.json +1 -1
  248. package/packages/pi-coding-agent/dist/core/package-manager.d.ts +9 -0
  249. package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
  250. package/packages/pi-coding-agent/dist/core/package-manager.js +74 -53
  251. package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
  252. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +6 -0
  253. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
  254. package/packages/pi-coding-agent/dist/core/resource-loader.js +30 -2
  255. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  256. package/packages/pi-coding-agent/dist/core/skill-directories.d.ts +66 -0
  257. package/packages/pi-coding-agent/dist/core/skill-directories.d.ts.map +1 -0
  258. package/packages/pi-coding-agent/dist/core/skill-directories.js +138 -0
  259. package/packages/pi-coding-agent/dist/core/skill-directories.js.map +1 -0
  260. package/packages/pi-coding-agent/dist/core/skills.d.ts +4 -1
  261. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  262. package/packages/pi-coding-agent/dist/core/skills.js +4 -1
  263. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  264. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  265. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  266. package/packages/pi-coding-agent/dist/index.js +1 -0
  267. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  268. package/packages/pi-coding-agent/package.json +7 -7
  269. package/packages/pi-tui/package.json +2 -2
  270. package/packages/rpc-client/package.json +2 -2
  271. package/pkg/dist/core/export-html/template.js +53 -4
  272. package/pkg/package.json +1 -1
  273. package/src/resources/extensions/ask-user-questions.ts +1 -1
  274. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +146 -33
  275. package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +25 -0
  276. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +93 -0
  277. package/src/resources/extensions/gsd/activity-log.ts +1 -1
  278. package/src/resources/extensions/gsd/auto/closeout.ts +114 -7
  279. package/src/resources/extensions/gsd/auto/orchestrator.ts +21 -14
  280. package/src/resources/extensions/gsd/auto/pre-dispatch.ts +6 -3
  281. package/src/resources/extensions/gsd/auto/unit-phase.ts +5 -9
  282. package/src/resources/extensions/gsd/auto-artifact-paths.ts +14 -4
  283. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +13 -7
  284. package/src/resources/extensions/gsd/auto-dispatch.ts +77 -16
  285. package/src/resources/extensions/gsd/auto-model-selection.ts +33 -1
  286. package/src/resources/extensions/gsd/auto-post-unit.ts +4 -2
  287. package/src/resources/extensions/gsd/auto-prompts.ts +53 -113
  288. package/src/resources/extensions/gsd/auto-recovery.ts +50 -6
  289. package/src/resources/extensions/gsd/auto-start.ts +62 -31
  290. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +12 -2
  291. package/src/resources/extensions/gsd/auto-timers.ts +9 -2
  292. package/src/resources/extensions/gsd/auto-worktree-branch-lifecycle.ts +237 -0
  293. package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +166 -0
  294. package/src/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.ts +37 -0
  295. package/src/resources/extensions/gsd/auto-worktree-creation.ts +171 -0
  296. package/src/resources/extensions/gsd/auto-worktree-entry.ts +154 -0
  297. package/src/resources/extensions/gsd/auto-worktree-merge-already-merged.ts +161 -0
  298. package/src/resources/extensions/gsd/auto-worktree-merge-branch-head.ts +83 -0
  299. package/src/resources/extensions/gsd/auto-worktree-merge-cleanup.ts +132 -0
  300. package/src/resources/extensions/gsd/auto-worktree-merge-code-changes.ts +71 -0
  301. package/src/resources/extensions/gsd/auto-worktree-merge-db-ready.ts +112 -0
  302. package/src/resources/extensions/gsd/auto-worktree-merge-integration-branch.ts +99 -0
  303. package/src/resources/extensions/gsd/auto-worktree-merge-message.ts +166 -0
  304. package/src/resources/extensions/gsd/auto-worktree-merge-pre-teardown.ts +93 -0
  305. package/src/resources/extensions/gsd/auto-worktree-merge-stash.ts +213 -0
  306. package/src/resources/extensions/gsd/auto-worktree-merge.ts +391 -0
  307. package/src/resources/extensions/gsd/auto-worktree-milestone-shelter.ts +159 -0
  308. package/src/resources/extensions/gsd/auto-worktree-path-resolution.ts +6 -0
  309. package/src/resources/extensions/gsd/auto-worktree-path-utils.ts +10 -0
  310. package/src/resources/extensions/gsd/auto-worktree-resource-version.ts +44 -0
  311. package/src/resources/extensions/gsd/auto-worktree-runtime-cleanup.ts +119 -0
  312. package/src/resources/extensions/gsd/auto-worktree-session-registry.ts +71 -0
  313. package/src/resources/extensions/gsd/auto-worktree-sync.ts +370 -0
  314. package/src/resources/extensions/gsd/auto-worktree-teardown.ts +161 -0
  315. package/src/resources/extensions/gsd/auto-worktree.ts +69 -2429
  316. package/src/resources/extensions/gsd/auto.ts +114 -47
  317. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +1 -1
  318. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +20 -2
  319. package/src/resources/extensions/gsd/bootstrap/system-context.ts +1 -1
  320. package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +218 -27
  321. package/src/resources/extensions/gsd/codebase-generator.ts +7 -1
  322. package/src/resources/extensions/gsd/commands-handlers.ts +1 -1
  323. package/src/resources/extensions/gsd/commands-workflow-templates.ts +3 -3
  324. package/src/resources/extensions/gsd/compat/compat-marker.ts +47 -0
  325. package/src/resources/extensions/gsd/config-overlay.ts +7 -1
  326. package/src/resources/extensions/gsd/db/engine.ts +36 -0
  327. package/src/resources/extensions/gsd/db/queries.ts +9 -9
  328. package/src/resources/extensions/gsd/db/writers/cascades.ts +23 -1
  329. package/src/resources/extensions/gsd/db-adapter.ts +29 -3
  330. package/src/resources/extensions/gsd/docs/preferences-reference.md +3 -3
  331. package/src/resources/extensions/gsd/doctor-engine-checks.ts +109 -10
  332. package/src/resources/extensions/gsd/flat-phase-migration.ts +34 -3
  333. package/src/resources/extensions/gsd/forensics.ts +1 -1
  334. package/src/resources/extensions/gsd/git-conflict-resolve.ts +2 -2
  335. package/src/resources/extensions/gsd/git-service.ts +53 -0
  336. package/src/resources/extensions/gsd/gsd-db.ts +33 -11
  337. package/src/resources/extensions/gsd/guided-flow.ts +26 -18
  338. package/src/resources/extensions/gsd/journal.ts +1 -1
  339. package/src/resources/extensions/gsd/markdown-renderer.ts +52 -91
  340. package/src/resources/extensions/gsd/md-importer.ts +93 -22
  341. package/src/resources/extensions/gsd/metrics.ts +2 -2
  342. package/src/resources/extensions/gsd/migration-auto-check.ts +32 -3
  343. package/src/resources/extensions/gsd/milestone-merge-transaction.ts +15 -0
  344. package/src/resources/extensions/gsd/milestone-settlement.ts +1 -1
  345. package/src/resources/extensions/gsd/parallel-merge.ts +1 -1
  346. package/src/resources/extensions/gsd/parallel-orchestrator.ts +3 -1
  347. package/src/resources/extensions/gsd/paths.ts +108 -51
  348. package/src/resources/extensions/gsd/post-unit-hooks.ts +32 -0
  349. package/src/resources/extensions/gsd/preferences-models.ts +74 -20
  350. package/src/resources/extensions/gsd/preferences-skills.ts +10 -16
  351. package/src/resources/extensions/gsd/preferences-types.ts +54 -1
  352. package/src/resources/extensions/gsd/preferences-validation.ts +146 -9
  353. package/src/resources/extensions/gsd/preferences.ts +20 -0
  354. package/src/resources/extensions/gsd/prompts/system.md +6 -6
  355. package/src/resources/extensions/gsd/quick.ts +11 -3
  356. package/src/resources/extensions/gsd/rule-registry.ts +111 -9
  357. package/src/resources/extensions/gsd/skill-discovery.ts +47 -23
  358. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +3 -1
  359. package/src/resources/extensions/gsd/state/derive/from-db.ts +201 -157
  360. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +1 -9
  361. package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +2 -22
  362. package/src/resources/extensions/gsd/state-reconciliation/index.ts +14 -0
  363. package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +169 -1
  364. package/src/resources/extensions/gsd/tests/auto-loop-no-copy-artifacts.test.ts +2 -1
  365. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +41 -2
  366. package/src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts +48 -1
  367. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +57 -0
  368. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +1 -1
  369. package/src/resources/extensions/gsd/tests/auto-start-project-milestone-reconcile.test.ts +29 -1
  370. package/src/resources/extensions/gsd/tests/auto-timeout-recovery-supervisor-inflight-guard.test.ts +159 -0
  371. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +2 -1
  372. package/src/resources/extensions/gsd/tests/auto-worktree-auto-resolve.test.ts +1 -1
  373. package/src/resources/extensions/gsd/tests/auto-worktree-merge-already-merged.test.ts +177 -0
  374. package/src/resources/extensions/gsd/tests/auto-worktree-merge-branch-head.test.ts +118 -0
  375. package/src/resources/extensions/gsd/tests/auto-worktree-merge-cleanup.test.ts +115 -0
  376. package/src/resources/extensions/gsd/tests/auto-worktree-merge-code-changes.test.ts +76 -0
  377. package/src/resources/extensions/gsd/tests/auto-worktree-merge-db-ready.test.ts +140 -0
  378. package/src/resources/extensions/gsd/tests/auto-worktree-merge-integration-branch.test.ts +123 -0
  379. package/src/resources/extensions/gsd/tests/auto-worktree-merge-message.test.ts +114 -0
  380. package/src/resources/extensions/gsd/tests/auto-worktree-merge-pre-teardown.test.ts +84 -0
  381. package/src/resources/extensions/gsd/tests/auto-worktree-merge-stash.test.ts +70 -0
  382. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-shelter.test.ts +52 -0
  383. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +6 -6
  384. package/src/resources/extensions/gsd/tests/auto-worktree-resource-version.test.ts +59 -0
  385. package/src/resources/extensions/gsd/tests/auto-worktree-untracked-content.test.ts +3 -1
  386. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
  387. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +3 -1
  388. package/src/resources/extensions/gsd/tests/compat-marker.test.ts +85 -0
  389. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +45 -0
  390. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +1 -1
  391. package/src/resources/extensions/gsd/tests/db-adapter.test.ts +39 -0
  392. package/src/resources/extensions/gsd/tests/db-writable-probe.test.ts +66 -0
  393. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -0
  394. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +174 -0
  395. package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +1 -1
  396. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +71 -1
  397. package/src/resources/extensions/gsd/tests/flat-phase-renderer.test.ts +46 -1
  398. package/src/resources/extensions/gsd/tests/flat-phase-validation-path.test.ts +72 -32
  399. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +40 -0
  400. package/src/resources/extensions/gsd/tests/import-completion-lost-update.test.ts +196 -0
  401. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +4 -6
  402. package/src/resources/extensions/gsd/tests/integration/auto-stash-merge.test.ts +2 -1
  403. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +3 -3
  404. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +7 -8
  405. package/src/resources/extensions/gsd/tests/integration/feature-branch-lifecycle-integration.test.ts +2 -5
  406. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +76 -0
  407. package/src/resources/extensions/gsd/tests/integration/merge-cwd-restore.test.ts +1 -1
  408. package/src/resources/extensions/gsd/tests/integration/merge-preserve-worktree-on-preteardown-error.test.ts +1 -1
  409. package/src/resources/extensions/gsd/tests/integration/merge-strategy-regular.test.ts +2 -1
  410. package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +5 -7
  411. package/src/resources/extensions/gsd/tests/integration/paths.test.ts +88 -1
  412. package/src/resources/extensions/gsd/tests/integration/workspace-collapse-integration.test.ts +2 -4
  413. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +16 -15
  414. package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +1 -1
  415. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +1 -1
  416. package/src/resources/extensions/gsd/tests/merge-self-branch-guard.test.ts +1 -1
  417. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +91 -0
  418. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +2 -1
  419. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +439 -0
  420. package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +24 -0
  421. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +1 -1
  422. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +3 -3
  423. package/src/resources/extensions/gsd/tests/parallel-worker-lock-contention.test.ts +1 -1
  424. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +0 -1
  425. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +269 -0
  426. package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +8 -1
  427. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +1 -4
  428. package/src/resources/extensions/gsd/tests/preferences.test.ts +19 -0
  429. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +5 -0
  430. package/src/resources/extensions/gsd/tests/read-uat-gate-verdict.test.ts +54 -0
  431. package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +49 -1
  432. package/src/resources/extensions/gsd/tests/reopen-slice.test.ts +52 -0
  433. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +95 -1
  434. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +20 -0
  435. package/src/resources/extensions/gsd/tests/sibling-model-fallbacks.test.ts +189 -0
  436. package/src/resources/extensions/gsd/tests/single-field-model-thinking.test.ts +156 -0
  437. package/src/resources/extensions/gsd/tests/skill-discovery.test.ts +46 -0
  438. package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +6 -1
  439. package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +3 -5
  440. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +32 -0
  441. package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +2 -1
  442. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +2 -1
  443. package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +1 -1
  444. package/src/resources/extensions/gsd/tests/supervisor-model-swap-inflight-guard.test.ts +181 -0
  445. package/src/resources/extensions/gsd/tests/supervisor-model-swap-thinking-clamp.test.ts +122 -0
  446. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +1 -1
  447. package/src/resources/extensions/gsd/tests/system-flat-phase-layout.test.ts +33 -0
  448. package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +4 -4
  449. package/src/resources/extensions/gsd/tests/teardown-cleanup-parity.test.ts +2 -1
  450. package/src/resources/extensions/gsd/tests/teardown-failure-clears-registry.test.ts +4 -4
  451. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +196 -0
  452. package/src/resources/extensions/gsd/tests/uat-dispatch.test.ts +211 -0
  453. package/src/resources/extensions/gsd/tests/uat-stuck-loop-orphaned-worktree.test.ts +1 -1
  454. package/src/resources/extensions/gsd/tests/unit-registry.test.ts +26 -1
  455. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +39 -0
  456. package/src/resources/extensions/gsd/tests/uok-kernel-path.test.ts +226 -2
  457. package/src/resources/extensions/gsd/tests/uok-model-policy.test.ts +6 -0
  458. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +213 -2
  459. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +1 -1
  460. package/src/resources/extensions/gsd/tests/worktree-db-respawn-truncation.test.ts +1 -1
  461. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +1 -3
  462. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +1 -1
  463. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +1 -1
  464. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +1 -1
  465. package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +1 -1
  466. package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +2 -1
  467. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +5 -2
  468. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +1 -1
  469. package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +1 -1
  470. package/src/resources/extensions/gsd/tool-contract.ts +29 -0
  471. package/src/resources/extensions/gsd/tools/complete-milestone.ts +9 -5
  472. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +19 -8
  473. package/src/resources/extensions/gsd/tools/reopen-slice.ts +5 -0
  474. package/src/resources/extensions/gsd/tools/reopen-task.ts +13 -5
  475. package/src/resources/extensions/gsd/tools/validate-milestone.ts +13 -9
  476. package/src/resources/extensions/gsd/types.ts +23 -4
  477. package/src/resources/extensions/gsd/uat-dispatch.ts +176 -0
  478. package/src/resources/extensions/gsd/unit-registry.ts +16 -2
  479. package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +1 -1
  480. package/src/resources/extensions/gsd/uok/audit-toggle.ts +32 -2
  481. package/src/resources/extensions/gsd/uok/audit.ts +2 -0
  482. package/src/resources/extensions/gsd/uok/gate-runner.ts +26 -36
  483. package/src/resources/extensions/gsd/uok/gitops.ts +21 -18
  484. package/src/resources/extensions/gsd/uok/kernel.ts +169 -48
  485. package/src/resources/extensions/gsd/uok/model-policy.ts +20 -17
  486. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -1
  487. package/src/resources/extensions/gsd/workflow-event-ledger.ts +1 -1
  488. package/src/resources/extensions/gsd/workflow-logger.ts +1 -1
  489. package/src/resources/extensions/gsd/workflow-projections.ts +9 -24
  490. package/src/resources/extensions/gsd/workspace-git-preflight.ts +2 -2
  491. package/src/resources/extensions/gsd/workspace.ts +5 -21
  492. package/src/resources/extensions/gsd/worktree-command.ts +1 -1
  493. package/src/resources/extensions/gsd/worktree-lifecycle.ts +19 -15
  494. package/src/resources/extensions/gsd/worktree-reentry.ts +2 -1
  495. package/src/resources/extensions/shared/gsd-browser-cli.ts +29 -0
  496. package/src/resources/extensions/shared/interview-ui.ts +58 -11
  497. package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +32 -0
  498. /package/dist/web/standalone/.next/static/{bCg3aYrFN1DKZr2dqgE7L → 6xYMOzxVhsQgryneJ5KRc}/_buildManifest.js +0 -0
  499. /package/dist/web/standalone/.next/static/{bCg3aYrFN1DKZr2dqgE7L → 6xYMOzxVhsQgryneJ5KRc}/_ssgManifest.js +0 -0
@@ -10,6 +10,7 @@ import {
10
10
  compileUnitContextContract,
11
11
  compileUnitToolContract,
12
12
  getUnitWorkflowDispatchReadinessError,
13
+ getUnitWorkflowDispatchReadinessErrorForModel,
13
14
  } from "../tool-contract.js";
14
15
  import { shouldBlockAutoUnitToolCall } from "../auto-unit-tool-scope.js";
15
16
  import type { GSDState } from "../types.js";
@@ -111,6 +112,25 @@ test("Tool Contract derives dispatch readiness from Unit workflow tools", () =>
111
112
  assert.equal(error, null);
112
113
  });
113
114
 
115
+ test("Tool Contract derives dispatch readiness from selected model context", () => {
116
+ const authLookups: string[] = [];
117
+ const error = getUnitWorkflowDispatchReadinessErrorForModel({
118
+ model: { provider: "claude-code" },
119
+ fallbackModel: { provider: "openai-codex", baseUrl: "local://claude-code" },
120
+ getProviderAuthMode(provider) {
121
+ authLookups.push(provider);
122
+ return provider === "claude-code" ? "externalCli" : "oauth";
123
+ },
124
+ unitType: "plan-slice",
125
+ projectRoot: "/tmp/project",
126
+ env: { GSD_WORKFLOW_MCP_COMMAND: "node" },
127
+ surface: "auto-mode",
128
+ });
129
+
130
+ assert.equal(error, null);
131
+ assert.deepEqual(authLookups, ["claude-code"]);
132
+ });
133
+
114
134
  test("Unit Context Contract exposes prompt context without workflow tool surface", () => {
115
135
  const result = compileUnitContextContract("execute-task");
116
136
 
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Sibling single-model fields honor `fallbacks[]` (#1229).
3
+ *
4
+ * `post_unit_hooks[].model`, `auto_supervisor.model`, and
5
+ * `reactive_execution.subagent_model` accept the same
6
+ * `{ model, provider?, fallbacks? }` object form as `models.<phase>` so a
7
+ * transient provider trip falls back to the next entry instead of hard-failing
8
+ * (and, for a blocking hook, pausing the whole auto-mode run).
9
+ */
10
+
11
+ import test from "node:test";
12
+ import assert from "node:assert/strict";
13
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
14
+ import { join } from "node:path";
15
+ import { tmpdir } from "node:os";
16
+
17
+ import {
18
+ normalizeModelFieldConfig,
19
+ resolveModelWithFallbacksForUnit,
20
+ resolveAutoSupervisorConfig,
21
+ } from "../preferences-models.ts";
22
+ import { validatePreferences } from "../preferences-validation.ts";
23
+
24
+ function withPreferences<T>(frontmatter: string[], fn: () => T): T {
25
+ const oldHome = process.env.GSD_HOME;
26
+ const home = mkdtempSync(join(tmpdir(), "gsd-sibling-models-"));
27
+ try {
28
+ process.env.GSD_HOME = home;
29
+ writeFileSync(join(home, "preferences.md"), ["---", ...frontmatter, "---", ""].join("\n"));
30
+ return fn();
31
+ } finally {
32
+ if (oldHome === undefined) delete process.env.GSD_HOME;
33
+ else process.env.GSD_HOME = oldHome;
34
+ rmSync(home, { recursive: true, force: true });
35
+ }
36
+ }
37
+
38
+ // ─── normalizeModelFieldConfig ───────────────────────────────────────────────
39
+
40
+ test("normalizeModelFieldConfig: bare string → primary with empty fallbacks", () => {
41
+ assert.deepEqual(normalizeModelFieldConfig("my-model"), { primary: "my-model", fallbacks: [] });
42
+ });
43
+
44
+ test("normalizeModelFieldConfig: object form carries fallbacks", () => {
45
+ assert.deepEqual(
46
+ normalizeModelFieldConfig({ model: "primary", fallbacks: ["fb-1", "fb-2"] }),
47
+ { primary: "primary", fallbacks: ["fb-1", "fb-2"] },
48
+ );
49
+ });
50
+
51
+ test("normalizeModelFieldConfig: provider prefix is prepended to bare model", () => {
52
+ assert.deepEqual(
53
+ normalizeModelFieldConfig({ model: "gpt-5.4", provider: "openai-codex" }),
54
+ { primary: "openai-codex/gpt-5.4", fallbacks: [] },
55
+ );
56
+ });
57
+
58
+ test("normalizeModelFieldConfig: unset / blank / model-less → undefined", () => {
59
+ assert.equal(normalizeModelFieldConfig(undefined), undefined);
60
+ assert.equal(normalizeModelFieldConfig(" "), undefined);
61
+ assert.equal(normalizeModelFieldConfig({ model: "" }), undefined);
62
+ });
63
+
64
+ // ─── post_unit_hooks[].model fallback resolution ─────────────────────────────
65
+
66
+ test("hook/<name> resolves the hook's object-form model with fallbacks", () => {
67
+ withPreferences(
68
+ [
69
+ "post_unit_hooks:",
70
+ " - name: plan-review",
71
+ " after: [plan-slice]",
72
+ " prompt: review the plan",
73
+ " model:",
74
+ " model: primary-model",
75
+ " fallbacks:",
76
+ " - fallback-a",
77
+ " - fallback-b",
78
+ ],
79
+ () => {
80
+ const resolved = resolveModelWithFallbacksForUnit("hook/plan-review");
81
+ assert.deepEqual(resolved, { primary: "primary-model", fallbacks: ["fallback-a", "fallback-b"] });
82
+ },
83
+ );
84
+ });
85
+
86
+ test("hook/<name> still resolves the legacy bare-string model form", () => {
87
+ withPreferences(
88
+ [
89
+ "post_unit_hooks:",
90
+ " - name: plan-review",
91
+ " after: [plan-slice]",
92
+ " prompt: review the plan",
93
+ " model: solo-model",
94
+ ],
95
+ () => {
96
+ assert.deepEqual(
97
+ resolveModelWithFallbacksForUnit("hook/plan-review"),
98
+ { primary: "solo-model", fallbacks: [] },
99
+ );
100
+ },
101
+ );
102
+ });
103
+
104
+ test("hook/<name> resolves undefined when the hook has no model", () => {
105
+ withPreferences(
106
+ [
107
+ "post_unit_hooks:",
108
+ " - name: plan-review",
109
+ " after: [plan-slice]",
110
+ " prompt: review the plan",
111
+ ],
112
+ () => {
113
+ assert.equal(resolveModelWithFallbacksForUnit("hook/plan-review"), undefined);
114
+ assert.equal(resolveModelWithFallbacksForUnit("hook/unknown-hook"), undefined);
115
+ },
116
+ );
117
+ });
118
+
119
+ // ─── auto_supervisor.model ───────────────────────────────────────────────────
120
+
121
+ test("auto_supervisor.model object form resolves with fallbacks", () => {
122
+ withPreferences(
123
+ [
124
+ "auto_supervisor:",
125
+ " model:",
126
+ " model: supervisor-primary",
127
+ " fallbacks: [supervisor-fb]",
128
+ ],
129
+ () => {
130
+ assert.deepEqual(resolveModelWithFallbacksForUnit("supervisor"), {
131
+ primary: "supervisor-primary",
132
+ fallbacks: ["supervisor-fb"],
133
+ });
134
+ const supervisor = resolveAutoSupervisorConfig();
135
+ assert.equal(supervisor.model, "supervisor-primary");
136
+ assert.deepEqual(supervisor.modelFallbacks, ["supervisor-fb"]);
137
+ },
138
+ );
139
+ });
140
+
141
+ // ─── validation accepts the object form ──────────────────────────────────────
142
+
143
+ test("validatePreferences accepts object-form hook and subagent models", () => {
144
+ const { preferences: validated, errors } = validatePreferences({
145
+ post_unit_hooks: [
146
+ {
147
+ name: "plan-review",
148
+ after: ["plan-slice"],
149
+ prompt: "review",
150
+ model: { model: "primary", fallbacks: ["fb-1"] },
151
+ },
152
+ ],
153
+ reactive_execution: {
154
+ enabled: true,
155
+ subagent_model: { model: "sub-primary", fallbacks: ["sub-fb"] },
156
+ },
157
+ } as never);
158
+
159
+ assert.deepEqual(errors, []);
160
+ assert.deepEqual(validated.post_unit_hooks?.[0].model, { model: "primary", fallbacks: ["fb-1"] });
161
+ assert.deepEqual(validated.reactive_execution?.subagent_model, { model: "sub-primary", fallbacks: ["sub-fb"] });
162
+ });
163
+
164
+ test("validatePreferences rejects a model-less object form", () => {
165
+ const { errors } = validatePreferences({
166
+ post_unit_hooks: [
167
+ { name: "plan-review", after: ["plan-slice"], prompt: "review", model: { fallbacks: ["fb"] } },
168
+ ],
169
+ } as never);
170
+ assert.ok(errors.some((e) => e.includes('requires a non-empty "model"')));
171
+ });
172
+
173
+ test("validatePreferences accepts object-form auto_supervisor.model", () => {
174
+ const { preferences: validated, errors } = validatePreferences({
175
+ auto_supervisor: { model: { model: "sup-primary", fallbacks: ["sup-fb"] } },
176
+ } as never);
177
+ assert.deepEqual(errors, []);
178
+ assert.deepEqual(validated.auto_supervisor?.model, { model: "sup-primary", fallbacks: ["sup-fb"] });
179
+ });
180
+
181
+ test("validatePreferences rejects a model-less auto_supervisor.model object", () => {
182
+ const { errors } = validatePreferences({
183
+ auto_supervisor: { model: { fallbacks: ["sup-fb"] } },
184
+ } as never);
185
+ assert.ok(
186
+ errors.some((e) => e.includes("auto_supervisor.model") && e.includes('requires a non-empty "model"')),
187
+ `expected supervisor model error, got: ${JSON.stringify(errors)}`,
188
+ );
189
+ });
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Regression tests for #1269 — the object model form's `thinking` sub-field on
3
+ * the three single-model fields (`post_unit_hooks[].model`,
4
+ * `auto_supervisor.model`, and `reactive_execution.subagent_model`) was
5
+ * silently dropped after validation/normalization, so a configured
6
+ * hook/supervisor/subagent reasoning level never applied.
7
+ *
8
+ * These exercise the real preference pipeline through the exported runtime APIs:
9
+ * sanitize → validatePreferences
10
+ * normalize → normalizeModelFieldConfig
11
+ * resolve → resolveThinkingLevelForUnit (supervisor + hook/* early path)
12
+ *
13
+ * The `supervisor` and `hook/*` unit types have no phase-bucket chain, so the
14
+ * pre-#1269 resolver walk never covered them and returned `undefined`.
15
+ */
16
+
17
+ import test from "node:test";
18
+ import assert from "node:assert/strict";
19
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
20
+ import { join } from "node:path";
21
+ import { tmpdir } from "node:os";
22
+
23
+ import { validatePreferences } from "../preferences-validation.ts";
24
+ import { normalizeModelFieldConfig, resolveThinkingLevelForUnit } from "../preferences-models.ts";
25
+ import { invalidateAllCaches } from "../cache.ts";
26
+
27
+ /** Read the per-field `thinking` off a validated/normalized model config. */
28
+ function thinkingOf(model: unknown): string | undefined {
29
+ return (model as { thinking?: string } | undefined)?.thinking;
30
+ }
31
+
32
+ /** Write a project-level `.gsd/PREFERENCES.md` and run `fn` with its basePath. */
33
+ function withProjectPreferences<T>(frontmatter: string, fn: (basePath: string) => T): T {
34
+ const base = mkdtempSync(join(tmpdir(), "gsd-1269-thinking-"));
35
+ mkdirSync(join(base, ".gsd"), { recursive: true });
36
+ writeFileSync(join(base, ".gsd", "PREFERENCES.md"), `---\n${frontmatter}\n---\n`, "utf-8");
37
+ invalidateAllCaches();
38
+ try {
39
+ return fn(base);
40
+ } finally {
41
+ invalidateAllCaches();
42
+ rmSync(base, { recursive: true, force: true });
43
+ }
44
+ }
45
+
46
+ // ── sanitize: validatePreferences preserves a valid object-form thinking ──────
47
+
48
+ test("validatePreferences preserves auto_supervisor.model object-form thinking", () => {
49
+ const { preferences, errors } = validatePreferences({
50
+ auto_supervisor: { model: { model: "supervisor-model", thinking: "high" } },
51
+ });
52
+ assert.equal(errors.length, 0);
53
+ assert.equal(thinkingOf(preferences.auto_supervisor?.model), "high");
54
+ });
55
+
56
+ test("validatePreferences preserves post_unit_hooks[].model object-form thinking", () => {
57
+ const { preferences, errors } = validatePreferences({
58
+ post_unit_hooks: [
59
+ {
60
+ name: "code-review",
61
+ after: ["execute-task"],
62
+ prompt: "Review the diff",
63
+ model: { model: "hook-model", thinking: "low" },
64
+ },
65
+ ],
66
+ });
67
+ assert.equal(errors.length, 0);
68
+ assert.equal(thinkingOf(preferences.post_unit_hooks?.[0]?.model), "low");
69
+ });
70
+
71
+ test("validatePreferences preserves reactive_execution.subagent_model object-form thinking", () => {
72
+ const { preferences, errors } = validatePreferences({
73
+ reactive_execution: {
74
+ enabled: true,
75
+ max_parallel: 2,
76
+ isolation_mode: "same-tree",
77
+ subagent_model: { model: "subagent-model", thinking: "medium" },
78
+ },
79
+ });
80
+ assert.equal(errors.length, 0);
81
+ assert.equal(thinkingOf(preferences.reactive_execution?.subagent_model), "medium");
82
+ });
83
+
84
+ // ── sanitize: an invalid thinking level is warned and stripped ────────────────
85
+
86
+ test("validatePreferences warns and strips an invalid object-form thinking level", () => {
87
+ const { preferences, errors, warnings } = validatePreferences({
88
+ auto_supervisor: { model: { model: "supervisor-model", thinking: "ludicrous" } },
89
+ } as never);
90
+ // The model survives; only the bogus thinking is dropped, so a typo can never
91
+ // reach the resolver and masquerade as explicit configuration.
92
+ assert.equal(errors.length, 0);
93
+ assert.equal(thinkingOf(preferences.auto_supervisor?.model), undefined);
94
+ assert.ok(
95
+ warnings.some((w) => w.includes("auto_supervisor.model") && w.includes("thinking")),
96
+ `expected a thinking warning, got: ${JSON.stringify(warnings)}`,
97
+ );
98
+ });
99
+
100
+ // ── normalize: normalizeModelFieldConfig carries thinking through ─────────────
101
+
102
+ test("normalizeModelFieldConfig carries object-form thinking through", () => {
103
+ const config = normalizeModelFieldConfig({ model: "hook-model", thinking: "xhigh" });
104
+ assert.equal(config?.primary, "hook-model");
105
+ assert.equal(config?.thinking, "xhigh");
106
+ });
107
+
108
+ test("normalizeModelFieldConfig leaves thinking absent when omitted", () => {
109
+ const fromObject = normalizeModelFieldConfig({ model: "hook-model" });
110
+ assert.equal(fromObject?.primary, "hook-model");
111
+ assert.equal(fromObject?.thinking, undefined);
112
+
113
+ const fromString = normalizeModelFieldConfig("hook-model");
114
+ assert.equal(fromString?.primary, "hook-model");
115
+ assert.equal(fromString?.thinking, undefined);
116
+ });
117
+
118
+ // ── resolve: the single-field unit types surface their per-field thinking ──────
119
+
120
+ test("resolveThinkingLevelForUnit('supervisor') returns auto_supervisor.model thinking", () => {
121
+ withProjectPreferences(
122
+ ["auto_supervisor:", " model:", " model: supervisor-model", " thinking: high"].join("\n"),
123
+ (base) => {
124
+ assert.equal(resolveThinkingLevelForUnit("supervisor", base), "high");
125
+ },
126
+ );
127
+ });
128
+
129
+ test("resolveThinkingLevelForUnit('hook/<name>') returns the matching hook model thinking", () => {
130
+ withProjectPreferences(
131
+ [
132
+ "post_unit_hooks:",
133
+ " - name: code-review",
134
+ " after:",
135
+ " - execute-task",
136
+ " prompt: Review the diff",
137
+ " model:",
138
+ " model: hook-model",
139
+ " thinking: low",
140
+ ].join("\n"),
141
+ (base) => {
142
+ assert.equal(resolveThinkingLevelForUnit("hook/code-review", base), "low");
143
+ },
144
+ );
145
+ });
146
+
147
+ test("resolveThinkingLevelForUnit('supervisor') stays undefined when thinking is omitted", () => {
148
+ // Bare-string model form carries no thinking → dispatch falls back to the
149
+ // session/floor level, unchanged from pre-#1269 behavior.
150
+ withProjectPreferences(
151
+ ["auto_supervisor:", " model: supervisor-model"].join("\n"),
152
+ (base) => {
153
+ assert.equal(resolveThinkingLevelForUnit("supervisor", base), undefined);
154
+ },
155
+ );
156
+ });
@@ -109,3 +109,49 @@ test("appendDiscoveredSkillsFallback does not duplicate skills already in the pr
109
109
  location: "/tmp/already-loaded/SKILL.md",
110
110
  }]), prompt);
111
111
  });
112
+
113
+ test("snapshotSkills({cwd}) detects skills added to the project .agents/skills/ mid-session", async () => {
114
+ await withTempSkillHome(async (home) => {
115
+ // Use a project dir under the temp home so cwd is isolated.
116
+ const projectDir = join(home, "myproject");
117
+ const projectSkills = join(projectDir, ".agents", "skills");
118
+ snapshotSkills({ cwd: projectDir });
119
+
120
+ // Add a skill to the project skills dir after the snapshot.
121
+ writeDiskSkill(projectSkills, "project-disk-skill", "Project skill added mid-session.");
122
+ const detected = detectNewSkills();
123
+
124
+ assert.deepEqual(detected.map(skill => skill.name), ["project-disk-skill"]);
125
+ assert.equal(detected[0].location, join(projectSkills, "project-disk-skill", "SKILL.md"));
126
+ });
127
+ });
128
+
129
+ test("snapshotSkills({cwd}) detects skills added to the project .claude/skills/ mid-session", async () => {
130
+ await withTempSkillHome(async (home) => {
131
+ const projectDir = join(home, "claude-project");
132
+ const claudeSkills = join(projectDir, ".claude", "skills");
133
+ snapshotSkills({ cwd: projectDir });
134
+
135
+ writeDiskSkill(claudeSkills, "claude-project-skill", "Claude-format skill added mid-session.");
136
+ const detected = detectNewSkills();
137
+
138
+ assert.deepEqual(detected.map(skill => skill.name), ["claude-project-skill"]);
139
+ });
140
+ });
141
+
142
+ test("snapshotSkills({cwd}) treats skills already in the project dir as baseline, not newly discovered", async () => {
143
+ await withTempSkillHome(async (home) => {
144
+ // projectDir is intentionally NOT process.cwd(): mirrors auto-mode passing a
145
+ // base path that differs from cwd (e.g. after chdir into a worktree). The
146
+ // baseline must scan the passed cwd's dirs, so a skill present *before* the
147
+ // snapshot is part of the baseline and is never reported as newly discovered.
148
+ // Regresses the fix where snapshotCurrentSkillNames fell back to process.cwd().
149
+ const projectDir = join(home, "preexisting-project");
150
+ const projectSkills = join(projectDir, ".agents", "skills");
151
+ writeDiskSkill(projectSkills, "preexisting-project-skill");
152
+
153
+ snapshotSkills({ cwd: projectDir });
154
+
155
+ assert.deepEqual(detectNewSkills(), []);
156
+ });
157
+ });
@@ -52,7 +52,12 @@ test("skipped validation dispatch persists the validation file and DB assessment
52
52
  const artifactPath = "milestones/M001/slices/S01/S01-ASSESSMENT.md";
53
53
  const assessmentPath = `.gsd/${artifactPath}`;
54
54
  assert.equal(getArtifact(artifactPath)?.artifact_type, "ASSESSMENT");
55
- assert.equal(getAssessment(assessmentPath)?.scope, "run-uat");
55
+ // #1258: the per-slice ASSESSMENT fabricated by the pre-validation backfill
56
+ // is a placeholder (no UAT ever ran for this slice), so it is filed under the
57
+ // `backfill` scope — never `run-uat` — so `readUatGateVerdict` cannot mistake
58
+ // it for a genuine UAT sign-off. Its verdict body stays PASS to satisfy the
59
+ // MV02 artifact-existence requirement.
60
+ assert.equal(getAssessment(assessmentPath)?.scope, "backfill");
56
61
  assert.equal(getAssessment(assessmentPath)?.status, "pass");
57
62
  assert.equal(
58
63
  getLatestAssessmentByScope("M001", "milestone-validation")?.status,
@@ -12,11 +12,9 @@ import { join, sep } from "node:path";
12
12
  import { tmpdir } from "node:os";
13
13
  import { execSync } from "node:child_process";
14
14
 
15
- import {
16
- createAutoWorktree,
17
- teardownAutoWorktree,
18
- mergeMilestoneToMain,
19
- } from "../auto-worktree.ts";
15
+ import { createAutoWorktree } from "../auto-worktree-creation.ts";
16
+ import { mergeMilestoneToMain } from "../auto-worktree-merge.ts";
17
+ import { teardownAutoWorktree } from "../auto-worktree-teardown.ts";
20
18
  import { _resetServiceCache } from "../worktree.ts";
21
19
  import { _clearGsdRootCache } from "../paths.ts";
22
20
 
@@ -208,6 +208,38 @@ test("startAutoDetached reports failures asynchronously (#3733)", () => {
208
208
  );
209
209
  });
210
210
 
211
+ test("failed auto-start always clears leaked s.active so later /gsd auto is not bricked (#1235)", () => {
212
+ const autoSrc = readGsdFile("auto.ts");
213
+
214
+ // 1. startAutoDetached is the single funnel for any exception thrown out of
215
+ // startAuto — including a bootstrap throw that escapes before the loop's
216
+ // try/finally could run cleanupAfterLoopExit. The failure handler must
217
+ // clear leaked activation, or s.active + the on-disk auto lock persist and
218
+ // the re-entry guard silently no-ops every later /gsd auto until restart.
219
+ const detachedIdx = autoSrc.indexOf("export function startAutoDetached");
220
+ assert.ok(detachedIdx > -1, "startAutoDetached should exist");
221
+ const detachedBody = autoSrc.slice(detachedIdx, autoSrc.indexOf("\n}", detachedIdx));
222
+ assert.ok(
223
+ detachedBody.includes("if (s.active)") &&
224
+ detachedBody.includes("cleanupAfterLoopExit(ctx)"),
225
+ "startAutoDetached failure handler must run cleanupAfterLoopExit when auto-mode is still active",
226
+ );
227
+
228
+ // 2. bootstrapAutoSession sets s.active = true before some bail-outs return
229
+ // false (e.g. the SQLite-unavailable gate), so the fresh-start !ready path
230
+ // must clear the leaked activation before returning.
231
+ const startAutoIdx = autoSrc.indexOf("export async function startAuto(");
232
+ assert.ok(startAutoIdx > -1, "startAuto should exist");
233
+ const startAutoBody = autoSrc.slice(startAutoIdx);
234
+ const notReadyIdx = startAutoBody.indexOf("if (!ready) {");
235
+ assert.ok(notReadyIdx > -1, "fresh start should guard on bootstrap readiness with a block body");
236
+ const notReadyBlock = startAutoBody.slice(notReadyIdx, notReadyIdx + 600);
237
+ assert.ok(
238
+ notReadyBlock.includes("if (s.active) await cleanupAfterLoopExit(ctx)"),
239
+ "fresh-start !ready bail-out must clear leaked auto activation before returning",
240
+ );
241
+ });
242
+
211
243
  test("detached auto-start keeps a ref'ed handle until the run settles", async () => {
212
244
  const originalSetInterval = globalThis.setInterval;
213
245
  const originalClearInterval = globalThis.clearInterval;
@@ -14,7 +14,8 @@ import { join } from "node:path";
14
14
  import { tmpdir } from "node:os";
15
15
  import { execSync } from "node:child_process";
16
16
 
17
- import { createAutoWorktree, mergeMilestoneToMain } from "../auto-worktree.ts";
17
+ import { createAutoWorktree } from "../auto-worktree-creation.ts";
18
+ import { mergeMilestoneToMain } from "../auto-worktree-merge.ts";
18
19
  import { _resetServiceCache } from "../worktree.ts";
19
20
  import { _clearGsdRootCache } from "../paths.ts";
20
21
 
@@ -28,7 +28,8 @@ import { join } from "node:path";
28
28
  import { tmpdir } from "node:os";
29
29
  import { execSync } from "node:child_process";
30
30
 
31
- import { createAutoWorktree, mergeMilestoneToMain } from "../auto-worktree.ts";
31
+ import { createAutoWorktree } from "../auto-worktree-creation.ts";
32
+ import { mergeMilestoneToMain } from "../auto-worktree-merge.ts";
32
33
  import { _resetServiceCache } from "../worktree.ts";
33
34
  import { _clearGsdRootCache } from "../paths.ts";
34
35
 
@@ -8,7 +8,7 @@ import { mkdtempSync, mkdirSync, existsSync, readFileSync, rmSync, writeFileSync
8
8
  import { join } from "node:path";
9
9
  import { tmpdir } from "node:os";
10
10
  import { appendOverride, loadActiveOverrides } from "../files.ts";
11
- import { getAutoWorktreePath } from "../auto-worktree.ts";
11
+ import { getAutoWorktreePath } from "../auto-worktree-path-resolution.ts";
12
12
 
13
13
  describe("steer worktree path resolution (#3476)", () => {
14
14
  let projectRoot: string;