@opengsd/gsd-pi 1.5.0-dev.553dc518 → 1.5.0-dev.c4c8885f

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 (302) hide show
  1. package/dist/resources/.managed-resources-content-hash +1 -1
  2. package/dist/resources/extensions/ask-user-questions.js +1 -1
  3. package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +114 -36
  4. package/dist/resources/extensions/gsd/activity-log.js +1 -1
  5. package/dist/resources/extensions/gsd/auto/orchestrator.js +16 -10
  6. package/dist/resources/extensions/gsd/auto-artifact-paths.js +14 -5
  7. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +7 -2
  8. package/dist/resources/extensions/gsd/auto-dispatch.js +69 -17
  9. package/dist/resources/extensions/gsd/auto-model-selection.js +28 -1
  10. package/dist/resources/extensions/gsd/auto-post-unit.js +4 -3
  11. package/dist/resources/extensions/gsd/auto-prompts.js +29 -117
  12. package/dist/resources/extensions/gsd/auto-recovery.js +50 -6
  13. package/dist/resources/extensions/gsd/auto-start.js +54 -31
  14. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +12 -2
  15. package/dist/resources/extensions/gsd/auto-timers.js +9 -2
  16. package/dist/resources/extensions/gsd/auto.js +97 -31
  17. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +1 -1
  18. package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +67 -6
  19. package/dist/resources/extensions/gsd/codebase-generator.js +7 -1
  20. package/dist/resources/extensions/gsd/compat/compat-marker.js +44 -0
  21. package/dist/resources/extensions/gsd/config-overlay.js +7 -2
  22. package/dist/resources/extensions/gsd/db/engine.js +33 -0
  23. package/dist/resources/extensions/gsd/db/writers/cascades.js +20 -2
  24. package/dist/resources/extensions/gsd/db-adapter.js +30 -3
  25. package/dist/resources/extensions/gsd/docs/preferences-reference.md +3 -3
  26. package/dist/resources/extensions/gsd/flat-phase-migration.js +18 -0
  27. package/dist/resources/extensions/gsd/gsd-db.js +12 -11
  28. package/dist/resources/extensions/gsd/guided-flow.js +16 -7
  29. package/dist/resources/extensions/gsd/journal.js +1 -1
  30. package/dist/resources/extensions/gsd/markdown-renderer.js +34 -91
  31. package/dist/resources/extensions/gsd/md-importer.js +89 -23
  32. package/dist/resources/extensions/gsd/metrics.js +2 -2
  33. package/dist/resources/extensions/gsd/migration-auto-check.js +30 -3
  34. package/dist/resources/extensions/gsd/paths.js +87 -52
  35. package/dist/resources/extensions/gsd/post-unit-hooks.js +27 -0
  36. package/dist/resources/extensions/gsd/preferences-models.js +66 -15
  37. package/dist/resources/extensions/gsd/preferences-skills.js +10 -16
  38. package/dist/resources/extensions/gsd/preferences-validation.js +66 -10
  39. package/dist/resources/extensions/gsd/preferences.js +20 -0
  40. package/dist/resources/extensions/gsd/rule-registry.js +106 -10
  41. package/dist/resources/extensions/gsd/skill-discovery.js +36 -23
  42. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +1 -10
  43. package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +3 -24
  44. package/dist/resources/extensions/gsd/state-reconciliation/index.js +10 -0
  45. package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -5
  46. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +16 -10
  47. package/dist/resources/extensions/gsd/tools/reopen-slice.js +5 -0
  48. package/dist/resources/extensions/gsd/tools/reopen-task.js +13 -5
  49. package/dist/resources/extensions/gsd/tools/validate-milestone.js +3 -8
  50. package/dist/resources/extensions/gsd/uat-dispatch.js +94 -0
  51. package/dist/resources/extensions/gsd/uok/audit-toggle.js +31 -2
  52. package/dist/resources/extensions/gsd/uok/audit.js +3 -0
  53. package/dist/resources/extensions/gsd/uok/gate-runner.js +22 -30
  54. package/dist/resources/extensions/gsd/uok/gitops.js +18 -15
  55. package/dist/resources/extensions/gsd/uok/kernel.js +120 -46
  56. package/dist/resources/extensions/gsd/uok/model-policy.js +17 -14
  57. package/dist/resources/extensions/gsd/workflow-event-ledger.js +1 -1
  58. package/dist/resources/extensions/gsd/workflow-logger.js +1 -1
  59. package/dist/resources/extensions/gsd/workflow-projections.js +9 -26
  60. package/dist/resources/extensions/gsd/workspace.js +5 -14
  61. package/dist/resources/extensions/shared/gsd-browser-cli.js +29 -0
  62. package/dist/resources/extensions/shared/interview-ui.js +62 -9
  63. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  64. package/dist/web/standalone/.next/BUILD_ID +1 -1
  65. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  66. package/dist/web/standalone/.next/build-manifest.json +2 -2
  67. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  68. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  69. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  77. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  85. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  86. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  87. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  88. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  89. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  90. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  91. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  92. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  93. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  94. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  95. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  96. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  97. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  98. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  99. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  100. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  101. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  102. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  103. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  104. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  105. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  106. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  107. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  108. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  109. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  110. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  111. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  112. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  113. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  114. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  115. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  116. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  117. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  118. package/dist/web/standalone/.next/server/app/index.html +1 -1
  119. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  126. package/dist/web/standalone/.next/server/chunks/{1128.js → 1991.js} +1 -1
  127. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  128. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  130. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  131. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  132. package/dist/worktree-cli-create.d.ts +10 -0
  133. package/dist/worktree-cli-create.js +11 -0
  134. package/dist/worktree-cli-format.d.ts +12 -0
  135. package/dist/worktree-cli-format.js +38 -0
  136. package/dist/worktree-cli-plan.d.ts +16 -0
  137. package/dist/worktree-cli-plan.js +19 -0
  138. package/dist/worktree-cli-session.d.ts +13 -0
  139. package/dist/worktree-cli-session.js +18 -0
  140. package/dist/worktree-cli-status.d.ts +35 -0
  141. package/dist/worktree-cli-status.js +54 -0
  142. package/dist/worktree-cli.d.ts +1 -16
  143. package/dist/worktree-cli.js +28 -122
  144. package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
  145. package/integrations/hermes/pyproject.toml +1 -1
  146. package/package.json +1 -1
  147. package/packages/cloud-mcp-gateway/package.json +2 -2
  148. package/packages/contracts/package.json +1 -1
  149. package/packages/daemon/dist/orchestrator-agent.d.ts +21 -0
  150. package/packages/daemon/dist/orchestrator-agent.d.ts.map +1 -0
  151. package/packages/daemon/dist/orchestrator-agent.js +113 -0
  152. package/packages/daemon/dist/orchestrator-agent.js.map +1 -0
  153. package/packages/daemon/dist/orchestrator-tools.d.ts +12 -0
  154. package/packages/daemon/dist/orchestrator-tools.d.ts.map +1 -0
  155. package/packages/daemon/dist/orchestrator-tools.js +137 -0
  156. package/packages/daemon/dist/orchestrator-tools.js.map +1 -0
  157. package/packages/daemon/dist/orchestrator.d.ts +4 -56
  158. package/packages/daemon/dist/orchestrator.d.ts.map +1 -1
  159. package/packages/daemon/dist/orchestrator.js +13 -303
  160. package/packages/daemon/dist/orchestrator.js.map +1 -1
  161. package/packages/daemon/dist/orchestrator.test.js +11 -1
  162. package/packages/daemon/dist/orchestrator.test.js.map +1 -1
  163. package/packages/daemon/package.json +4 -4
  164. package/packages/gsd-agent-core/package.json +5 -5
  165. package/packages/gsd-agent-modes/package.json +7 -7
  166. package/packages/mcp-server/package.json +4 -4
  167. package/packages/native/package.json +1 -1
  168. package/packages/pi-agent-core/package.json +1 -1
  169. package/packages/pi-ai/package.json +1 -1
  170. package/packages/pi-coding-agent/dist/core/package-manager.d.ts +9 -0
  171. package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
  172. package/packages/pi-coding-agent/dist/core/package-manager.js +74 -53
  173. package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
  174. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +6 -0
  175. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
  176. package/packages/pi-coding-agent/dist/core/resource-loader.js +30 -2
  177. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  178. package/packages/pi-coding-agent/dist/core/skill-directories.d.ts +66 -0
  179. package/packages/pi-coding-agent/dist/core/skill-directories.d.ts.map +1 -0
  180. package/packages/pi-coding-agent/dist/core/skill-directories.js +138 -0
  181. package/packages/pi-coding-agent/dist/core/skill-directories.js.map +1 -0
  182. package/packages/pi-coding-agent/dist/core/skills.d.ts +4 -1
  183. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  184. package/packages/pi-coding-agent/dist/core/skills.js +4 -1
  185. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  186. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  187. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  188. package/packages/pi-coding-agent/dist/index.js +1 -0
  189. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  190. package/packages/pi-coding-agent/package.json +7 -7
  191. package/packages/pi-tui/package.json +2 -2
  192. package/packages/rpc-client/package.json +2 -2
  193. package/pkg/package.json +1 -1
  194. package/src/resources/extensions/ask-user-questions.ts +1 -1
  195. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +146 -33
  196. package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +25 -0
  197. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +93 -0
  198. package/src/resources/extensions/gsd/activity-log.ts +1 -1
  199. package/src/resources/extensions/gsd/auto/orchestrator.ts +17 -11
  200. package/src/resources/extensions/gsd/auto-artifact-paths.ts +14 -4
  201. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +9 -2
  202. package/src/resources/extensions/gsd/auto-dispatch.ts +77 -16
  203. package/src/resources/extensions/gsd/auto-model-selection.ts +33 -1
  204. package/src/resources/extensions/gsd/auto-post-unit.ts +4 -2
  205. package/src/resources/extensions/gsd/auto-prompts.ts +53 -113
  206. package/src/resources/extensions/gsd/auto-recovery.ts +50 -6
  207. package/src/resources/extensions/gsd/auto-start.ts +58 -29
  208. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +12 -2
  209. package/src/resources/extensions/gsd/auto-timers.ts +9 -2
  210. package/src/resources/extensions/gsd/auto.ts +103 -30
  211. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +1 -1
  212. package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +66 -6
  213. package/src/resources/extensions/gsd/codebase-generator.ts +7 -1
  214. package/src/resources/extensions/gsd/compat/compat-marker.ts +47 -0
  215. package/src/resources/extensions/gsd/config-overlay.ts +7 -1
  216. package/src/resources/extensions/gsd/db/engine.ts +36 -0
  217. package/src/resources/extensions/gsd/db/writers/cascades.ts +23 -1
  218. package/src/resources/extensions/gsd/db-adapter.ts +29 -3
  219. package/src/resources/extensions/gsd/docs/preferences-reference.md +3 -3
  220. package/src/resources/extensions/gsd/flat-phase-migration.ts +20 -0
  221. package/src/resources/extensions/gsd/gsd-db.ts +20 -11
  222. package/src/resources/extensions/gsd/guided-flow.ts +19 -7
  223. package/src/resources/extensions/gsd/journal.ts +1 -1
  224. package/src/resources/extensions/gsd/markdown-renderer.ts +52 -103
  225. package/src/resources/extensions/gsd/md-importer.ts +93 -22
  226. package/src/resources/extensions/gsd/metrics.ts +2 -2
  227. package/src/resources/extensions/gsd/migration-auto-check.ts +32 -3
  228. package/src/resources/extensions/gsd/paths.ts +108 -51
  229. package/src/resources/extensions/gsd/post-unit-hooks.ts +32 -0
  230. package/src/resources/extensions/gsd/preferences-models.ts +74 -20
  231. package/src/resources/extensions/gsd/preferences-skills.ts +10 -16
  232. package/src/resources/extensions/gsd/preferences-types.ts +24 -1
  233. package/src/resources/extensions/gsd/preferences-validation.ts +77 -9
  234. package/src/resources/extensions/gsd/preferences.ts +20 -0
  235. package/src/resources/extensions/gsd/rule-registry.ts +111 -9
  236. package/src/resources/extensions/gsd/skill-discovery.ts +47 -23
  237. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +1 -9
  238. package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +2 -22
  239. package/src/resources/extensions/gsd/state-reconciliation/index.ts +14 -0
  240. package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +169 -1
  241. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +41 -2
  242. package/src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts +48 -1
  243. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +57 -0
  244. package/src/resources/extensions/gsd/tests/auto-start-project-milestone-reconcile.test.ts +29 -1
  245. package/src/resources/extensions/gsd/tests/auto-timeout-recovery-supervisor-inflight-guard.test.ts +159 -0
  246. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
  247. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +3 -1
  248. package/src/resources/extensions/gsd/tests/compat-marker.test.ts +85 -0
  249. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +45 -0
  250. package/src/resources/extensions/gsd/tests/db-adapter.test.ts +39 -0
  251. package/src/resources/extensions/gsd/tests/db-writable-probe.test.ts +66 -0
  252. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +27 -0
  253. package/src/resources/extensions/gsd/tests/flat-phase-renderer.test.ts +22 -1
  254. package/src/resources/extensions/gsd/tests/flat-phase-validation-path.test.ts +72 -32
  255. package/src/resources/extensions/gsd/tests/import-completion-lost-update.test.ts +196 -0
  256. package/src/resources/extensions/gsd/tests/integration/paths.test.ts +88 -1
  257. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +16 -15
  258. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +91 -0
  259. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +2 -1
  260. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +0 -1
  261. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +269 -0
  262. package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +8 -1
  263. package/src/resources/extensions/gsd/tests/preferences.test.ts +19 -0
  264. package/src/resources/extensions/gsd/tests/read-uat-gate-verdict.test.ts +54 -0
  265. package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +49 -1
  266. package/src/resources/extensions/gsd/tests/reopen-slice.test.ts +52 -0
  267. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +95 -1
  268. package/src/resources/extensions/gsd/tests/sibling-model-fallbacks.test.ts +189 -0
  269. package/src/resources/extensions/gsd/tests/single-field-model-thinking.test.ts +156 -0
  270. package/src/resources/extensions/gsd/tests/skill-discovery.test.ts +46 -0
  271. package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +6 -1
  272. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +32 -0
  273. package/src/resources/extensions/gsd/tests/supervisor-model-swap-inflight-guard.test.ts +181 -0
  274. package/src/resources/extensions/gsd/tests/supervisor-model-swap-thinking-clamp.test.ts +122 -0
  275. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +93 -0
  276. package/src/resources/extensions/gsd/tests/uat-dispatch.test.ts +211 -0
  277. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +39 -0
  278. package/src/resources/extensions/gsd/tests/uok-kernel-path.test.ts +226 -2
  279. package/src/resources/extensions/gsd/tests/uok-model-policy.test.ts +6 -0
  280. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +213 -2
  281. package/src/resources/extensions/gsd/tools/complete-milestone.ts +9 -5
  282. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +19 -8
  283. package/src/resources/extensions/gsd/tools/reopen-slice.ts +5 -0
  284. package/src/resources/extensions/gsd/tools/reopen-task.ts +13 -5
  285. package/src/resources/extensions/gsd/tools/validate-milestone.ts +13 -9
  286. package/src/resources/extensions/gsd/types.ts +23 -4
  287. package/src/resources/extensions/gsd/uat-dispatch.ts +176 -0
  288. package/src/resources/extensions/gsd/uok/audit-toggle.ts +32 -2
  289. package/src/resources/extensions/gsd/uok/audit.ts +2 -0
  290. package/src/resources/extensions/gsd/uok/gate-runner.ts +26 -36
  291. package/src/resources/extensions/gsd/uok/gitops.ts +21 -18
  292. package/src/resources/extensions/gsd/uok/kernel.ts +169 -48
  293. package/src/resources/extensions/gsd/uok/model-policy.ts +20 -17
  294. package/src/resources/extensions/gsd/workflow-event-ledger.ts +1 -1
  295. package/src/resources/extensions/gsd/workflow-logger.ts +1 -1
  296. package/src/resources/extensions/gsd/workflow-projections.ts +9 -24
  297. package/src/resources/extensions/gsd/workspace.ts +5 -21
  298. package/src/resources/extensions/shared/gsd-browser-cli.ts +29 -0
  299. package/src/resources/extensions/shared/interview-ui.ts +58 -11
  300. package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +32 -0
  301. /package/dist/web/standalone/.next/static/{ZpFDazP-38PXBPiI_LdZf → NPMNi2HV8BuK3baQsEUhk}/_buildManifest.js +0 -0
  302. /package/dist/web/standalone/.next/static/{ZpFDazP-38PXBPiI_LdZf → NPMNi2HV8BuK3baQsEUhk}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- be3c5dc39486dc24
1
+ d89940a8e727f2ea
@@ -209,7 +209,7 @@ export default function AskUserQuestions(pi) {
209
209
  "For single-select: each question must have 2-3 options. Put the recommended option first with '(Recommended)' suffix. Do not include an 'Other' or 'None of the above' option - the client adds one automatically.",
210
210
  "For multi-select: set allowMultiple: true. The user can pick any number of options. No 'None of the above' is added.",
211
211
  "When options involve code patterns, config choices, or architecture decisions, add a 'preview' field with markdown content (code blocks, lists, headers, etc.). The preview renders in a side-by-side panel when the option is highlighted.",
212
- "Preview content is rendered in a fixed-height panel (max ~20 lines visible). Keep previews concise — show the most relevant snippet, not exhaustive examples. Longer content is truncated with a '+N lines hidden' indicator.",
212
+ "Preview content is rendered in a fixed-height panel (max ~20 lines visible). Keep previews concise — show the most relevant snippet, not exhaustive examples. Longer content stays fully accessible: the user scrolls it with PgUp/PgDn, with '▲/▼ N more' indicators marking hidden rows.",
213
213
  ],
214
214
  parameters: AskUserQuestionsParams,
215
215
  async execute(_toolCallId, params, signal, _onUpdate, ctx) {
@@ -4,8 +4,6 @@ import { Type } from "@sinclair/typebox";
4
4
  import { BROWSER_CONTRACT_TOOL_NAMES } from "../../shared/browser-contract.js";
5
5
  import { resolveGsdBrowserMcpLaunchConfig } from "../../shared/gsd-browser-cli.js";
6
6
  import { buildMcpChildEnv } from "../../mcp-client/manager.js";
7
- const connections = new Map();
8
- const pendingConnections = new Map();
9
7
  const DEFAULT_MAX_LINES = 2_000;
10
8
  const DEFAULT_MAX_BYTES = 50 * 1024;
11
9
  const MCP_CALL_TIMEOUT_MS = 60_000;
@@ -297,6 +295,103 @@ function buildConnectionKey(launch) {
297
295
  env: launch.env ?? {},
298
296
  });
299
297
  }
298
+ function combineAbortSignals(poolSignal, callerSignal) {
299
+ if (!callerSignal)
300
+ return poolSignal;
301
+ if (typeof AbortSignal.any === "function") {
302
+ return AbortSignal.any([poolSignal, callerSignal]);
303
+ }
304
+ const controller = new AbortController();
305
+ const abort = () => {
306
+ if (!controller.signal.aborted)
307
+ controller.abort();
308
+ };
309
+ if (poolSignal.aborted || callerSignal.aborted) {
310
+ abort();
311
+ }
312
+ else {
313
+ poolSignal.addEventListener("abort", abort, { once: true });
314
+ callerSignal.addEventListener("abort", abort, { once: true });
315
+ }
316
+ return controller.signal;
317
+ }
318
+ export class ManagedGsdBrowserConnectionPool {
319
+ connections = new Map();
320
+ pendingConnections = new Map();
321
+ connect;
322
+ closeConnection;
323
+ generation = 0;
324
+ closing = false;
325
+ constructor(connect, closeConnection) {
326
+ this.connect = connect;
327
+ this.closeConnection = closeConnection;
328
+ }
329
+ get activeCount() {
330
+ return this.connections.size;
331
+ }
332
+ get pendingCount() {
333
+ return this.pendingConnections.size;
334
+ }
335
+ getOrConnect(launch, signal) {
336
+ if (this.closing) {
337
+ return Promise.reject(new Error("gsd-browser connection pool is closing"));
338
+ }
339
+ const key = buildConnectionKey(launch);
340
+ const existing = this.connections.get(key);
341
+ if (existing)
342
+ return Promise.resolve(existing);
343
+ const pending = this.pendingConnections.get(key);
344
+ if (pending)
345
+ return pending.promise;
346
+ const generation = this.generation;
347
+ const abortController = new AbortController();
348
+ const connectionSignal = combineAbortSignals(abortController.signal, signal);
349
+ const connectionPromise = this.connect(launch, connectionSignal)
350
+ .then(async (connection) => {
351
+ if (this.closing || this.generation !== generation) {
352
+ await this.closeConnection(connection);
353
+ throw new Error("gsd-browser connection closed during startup");
354
+ }
355
+ this.connections.set(key, connection);
356
+ return connection;
357
+ })
358
+ .finally(() => {
359
+ if (this.pendingConnections.get(key)?.promise === connectionPromise) {
360
+ this.pendingConnections.delete(key);
361
+ }
362
+ });
363
+ this.pendingConnections.set(key, { promise: connectionPromise, abortController });
364
+ return connectionPromise;
365
+ }
366
+ async closeAll() {
367
+ this.closing = true;
368
+ this.generation += 1;
369
+ const activeConnections = Array.from(this.connections.values());
370
+ const pendingConnections = Array.from(this.pendingConnections.values());
371
+ this.connections.clear();
372
+ this.pendingConnections.clear();
373
+ for (const pending of pendingConnections) {
374
+ pending.abortController.abort();
375
+ }
376
+ const closingActive = activeConnections.map((connection) => this.closeConnection(connection));
377
+ const closingPending = pendingConnections.map(async (pending) => {
378
+ try {
379
+ const connection = await pending.promise;
380
+ await this.closeConnection(connection);
381
+ }
382
+ catch {
383
+ // Failed or invalidated connection attempts have already cleaned up.
384
+ }
385
+ });
386
+ try {
387
+ await Promise.allSettled([...closingActive, ...closingPending]);
388
+ }
389
+ finally {
390
+ this.closing = false;
391
+ this.generation += 1;
392
+ }
393
+ }
394
+ }
300
395
  async function connectManagedGsdBrowser(launch, signal) {
301
396
  const client = new Client({ name: "gsd-pi-browser-tools", version: "1.0.0" });
302
397
  const transport = new StdioClientTransport({
@@ -326,27 +421,26 @@ async function connectManagedGsdBrowser(launch, signal) {
326
421
  throw error;
327
422
  }
328
423
  }
424
+ async function closeManagedGsdBrowserConnection(connection) {
425
+ try {
426
+ await connection.client.close();
427
+ }
428
+ catch {
429
+ // Best-effort cleanup.
430
+ }
431
+ try {
432
+ await connection.transport.close();
433
+ }
434
+ catch {
435
+ // Best-effort cleanup.
436
+ }
437
+ }
438
+ const connectionPool = new ManagedGsdBrowserConnectionPool(connectManagedGsdBrowser, closeManagedGsdBrowserConnection);
329
439
  async function getOrConnectManagedGsdBrowser(ctx, signal) {
330
440
  const launch = resolveGsdBrowserMcpLaunchConfig(resolveProjectRoot(ctx), process.env, {
331
441
  sessionSuffix: resolveManagedSessionSuffix(ctx),
332
442
  });
333
- const key = buildConnectionKey(launch);
334
- const existing = connections.get(key);
335
- if (existing)
336
- return existing;
337
- const pending = pendingConnections.get(key);
338
- if (pending)
339
- return pending;
340
- const connectionPromise = connectManagedGsdBrowser(launch, signal);
341
- pendingConnections.set(key, connectionPromise);
342
- try {
343
- const connection = await connectionPromise;
344
- connections.set(key, connection);
345
- return connection;
346
- }
347
- finally {
348
- pendingConnections.delete(key);
349
- }
443
+ return connectionPool.getOrConnect(launch, signal);
350
444
  }
351
445
  function isUnknownMcpToolError(error) {
352
446
  const message = error instanceof Error ? error.message : String(error);
@@ -609,23 +703,7 @@ export function registerManagedGsdBrowserTools(pi) {
609
703
  }
610
704
  }
611
705
  export async function closeManagedGsdBrowser() {
612
- const closing = Array.from(connections.entries()).map(async ([key, connection]) => {
613
- try {
614
- await connection.client.close();
615
- }
616
- catch {
617
- // Best-effort cleanup.
618
- }
619
- try {
620
- await connection.transport.close();
621
- }
622
- catch {
623
- // Best-effort cleanup.
624
- }
625
- connections.delete(key);
626
- });
627
- await Promise.allSettled(closing);
628
- pendingConnections.clear();
706
+ await connectionPool.closeAll();
629
707
  }
630
708
  export async function _resetManagedGsdBrowserForTest() {
631
709
  await closeManagedGsdBrowser();
@@ -115,7 +115,7 @@ export function saveActivityLog(ctx, basePath, unitType, unitId) {
115
115
  }
116
116
  state.nextSeq += 1;
117
117
  state.lastSnapshotKeyByUnit.set(unitKey, key);
118
- if (isUnifiedAuditEnabled()) {
118
+ if (isUnifiedAuditEnabled(basePath)) {
119
119
  emitUokAuditEvent(basePath, buildAuditEnvelope({
120
120
  traceId: `activity:${unitType}:${unitId}`,
121
121
  turnId: unitId,
@@ -999,16 +999,22 @@ export class AutoOrchestrator {
999
999
  this.postAdvanceRecord(skipped);
1000
1000
  return skipped;
1001
1001
  }
1002
- // Stuck-loop detection: when the window is saturated with copies of
1003
- // `nextKey` (count >= STUCK_WINDOW_SIZE), consult the Dispatch History
1004
- // module's full detect-stuck rule set for the verdict instead of the old
1005
- // bare saturation count. This keeps the saturation threshold (the window
1006
- // deliberately records benign idempotent repeats, so earlier-firing
1007
- // rules would false-positive on pause/resume re-advances) while gaining
1008
- // retry-budget suppression and diagnosable rule reasons. A saturated
1009
- // window with no verdict means the dispatch ledger says we are inside
1010
- // the unit's retry-backoff budget let the retry proceed.
1011
- const stuckVerdict = matchingCount >= STUCK_WINDOW_SIZE ? this.dispatchHistory.detectStuck() : null;
1002
+ // Stuck-loop detection: consult the Dispatch History module's full
1003
+ // detect-stuck rule set once the window is *full* — not only when a
1004
+ // single key saturates it. Gating on a single key's saturation count
1005
+ // (matchingCount >= STUCK_WINDOW_SIZE) let two-unit oscillations slip
1006
+ // through forever: an execute-task complete-slice loop (a slice gate
1007
+ // that keeps reopening the same task, #1225) fills the window with two
1008
+ // alternating keys, so neither key ever reaches the saturation count and
1009
+ // detect-stuck's oscillation/repeat rules were never even invoked. Firing
1010
+ // on window saturation instead covers both shapes. Consecutive same-key
1011
+ // re-advances (the benign pause/resume churn the old count gate guarded
1012
+ // against) are already short-circuited above by the idempotency skip, and
1013
+ // legitimate retry backoff is still suppressed inside detect-stuck via the
1014
+ // dispatch ledger — a saturated window with no verdict means we are inside
1015
+ // the unit's retry-backoff budget, so let the retry proceed.
1016
+ const windowSaturated = this.dispatchHistory.getRecentWindow().length >= STUCK_WINDOW_SIZE;
1017
+ const stuckVerdict = windowSaturated ? this.dispatchHistory.detectStuck() : null;
1012
1018
  if (stuckVerdict) {
1013
1019
  // #442: before declaring a stuck loop, verify the unit didn't actually
1014
1020
  // complete on disk (stale DB) and recover if so — legacy graduated
@@ -5,10 +5,10 @@
5
5
  // resolveExpectedArtifactPath and diagnoseExpectedArtifact moved here from
6
6
  // auto-recovery.ts (Phase 5 dead-code cleanup). The artifact verification
7
7
  // function was removed entirely — callers now query WorkflowEngine directly.
8
- import { gsdRoot, resolveDir, resolveFile, resolveMilestonePath, resolveMilestoneFile, resolveSliceFile, relMilestoneFile, relSliceFile, buildTaskFileName, resolveSlicePath, resolveTasksDir, dirIsMetaOnlyLegacyMilestone, } from "./paths.js";
8
+ import { gsdRoot, resolveDir, resolveFile, resolveMilestonePath, resolveMilestoneFile, resolveSliceFile, relMilestoneFile, relSliceFile, buildTaskFileName, resolveSlicePath, resolveTasksDir, dirIsMetaOnlyLegacyMilestone, normalizeRealPath, } from "./paths.js";
9
9
  import { milestoneIdToPhaseNum } from "./layout-policy.js";
10
10
  import { parseUnitId } from "./unit-id.js";
11
- import { dirname, join, relative } from "node:path";
11
+ import { basename, dirname, join, relative } from "node:path";
12
12
  import { existsSync } from "node:fs";
13
13
  function resolveMilestoneArtifactPath(base, mid, suffix) {
14
14
  const existing = resolveProjectedMilestoneFile(base, mid, suffix) ?? resolveProjectMilestoneFile(base, mid, suffix);
@@ -193,8 +193,17 @@ export function resolveExpectedArtifactPath(unitType, unitId, base) {
193
193
  ?? resolveSlicePath(base, mid, sid);
194
194
  if (!slicePath || !tid)
195
195
  return null;
196
- const tasksDir = resolveTasksDir(base, mid, sid) ?? slicePath;
197
- return join(tasksDir, buildTaskFileName(tid, "SUMMARY"));
196
+ // Legacy layout: slice dirs live under slices/<SID>/ and task summaries
197
+ // live in a tasks/ subdir. Flat-phase layout: slicePath IS the phase dir
198
+ // and task summaries live beside the plan files at the phase root. A
199
+ // tasks/ subdir may still exist in flat-phase for auxiliary task-scoped
200
+ // artifacts (e.g. T01-VERIFY.json gate outputs) — its mere existence must
201
+ // NOT redirect summary resolution into tasks/ (#1208).
202
+ const isLegacySlice = basename(dirname(slicePath)) === "slices";
203
+ const summaryDir = isLegacySlice
204
+ ? (resolveTasksDir(base, mid, sid) ?? slicePath)
205
+ : slicePath;
206
+ return join(summaryDir, buildTaskFileName(tid, "SUMMARY"));
198
207
  }
199
208
  case "complete-slice": {
200
209
  return resolveSliceArtifactPath(base, mid, sid, "SUMMARY");
@@ -299,7 +308,7 @@ export function resolveSliceResearchLocation(basePath, mid, sid) {
299
308
  if (canonicalPath && existsSync(canonicalPath)) {
300
309
  return {
301
310
  absolutePath: canonicalPath,
302
- relativePath: relative(basePath, canonicalPath),
311
+ relativePath: relative(normalizeRealPath(basePath), canonicalPath),
303
312
  };
304
313
  }
305
314
  return { absolutePath: null, relativePath: null };
@@ -7,7 +7,7 @@ import { loadFile } from "./files.js";
7
7
  import { isDbAvailable, getClosedSliceIds } from "./gsd-db.js";
8
8
  import { resolveSliceFile, relSliceFile, } from "./paths.js";
9
9
  import { buildResearchSlicePrompt, buildResearchMilestonePrompt, buildPlanSlicePrompt, buildPlanMilestonePrompt, buildExecuteTaskPrompt, buildCompleteSlicePrompt, buildCompleteMilestonePrompt, buildValidateMilestonePrompt, buildReassessRoadmapPrompt, buildRunUatPrompt, buildReplanSlicePrompt, } from "./auto-prompts.js";
10
- import { loadEffectiveGSDPreferences } from "./preferences.js";
10
+ import { loadEffectiveGSDPreferences, renderLanguageDirectiveForPrompt } from "./preferences.js";
11
11
  import { pauseAuto } from "./auto.js";
12
12
  import { resolveCanonicalMilestoneRoot } from "./worktree-manager.js";
13
13
  import { getUnitWorkflowDispatchReadinessErrorForModel } from "./tool-contract.js";
@@ -231,5 +231,10 @@ export async function dispatchDirectPhase(ctx, pi, phase, base, opts = {}) {
231
231
  ctx.ui.notify("Session creation cancelled.", "warning");
232
232
  return;
233
233
  }
234
- pi.sendMessage({ customType: "gsd-dispatch", content: prompt, display: false }, { triggerTurn: true });
234
+ // Inject the configured response language into the dispatched prompt content
235
+ // — the new session's system prompt does not carry the preferences block, so
236
+ // the language setting would otherwise never reach the unit (#1210).
237
+ const languageDirective = renderLanguageDirectiveForPrompt(loadEffectiveGSDPreferences(dispatchBase)?.preferences);
238
+ const dispatchContent = languageDirective ? `${languageDirective}\n\n${prompt}` : prompt;
239
+ pi.sendMessage({ customType: "gsd-dispatch", content: dispatchContent, display: false }, { triggerTurn: true });
235
240
  }
@@ -1,5 +1,6 @@
1
1
  // Project/App: gsd-pi
2
2
  // File Purpose: Declarative auto-mode dispatch rules and dispatch resolver.
3
+ import { renderLanguageDirectiveForPrompt } from "./preferences.js";
3
4
  import { loadFile, extractUatType, loadActiveOverrides } from "./files.js";
4
5
  import { getUatBrowserToolSupportError } from "./uat-policy.js";
5
6
  import { isDbAvailable, getMilestoneSlices, getMilestoneSliceSummaries, getClosedSliceIds, getPendingGatesForTurn, markPendingGatesOmittedForTurn, getMilestone, insertArtifact, insertAssessment, setSliceSketchFlag, transaction, getAssessment, getSliceRunUatAssessment, } from "./gsd-db.js";
@@ -11,8 +12,9 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, readdir
11
12
  import { logWarning, logError } from "./workflow-logger.js";
12
13
  import { dirname, join, sep } from "node:path";
13
14
  import { hasImplementationArtifacts } from "./milestone-implementation-evidence.js";
14
- import { buildDiscussMilestonePrompt, buildDiscussProjectPrompt, buildDiscussRequirementsPrompt, buildResearchDecisionPrompt, buildResearchProjectPrompt, buildResearchMilestonePrompt, buildPlanMilestonePrompt, buildResearchSlicePrompt, buildPlanSlicePrompt, buildRefineSlicePrompt, buildExecuteTaskPrompt, buildCompleteSlicePrompt, buildCompleteMilestonePrompt, buildValidateMilestonePrompt, buildReplanSlicePrompt, buildRunUatPrompt, buildReassessRoadmapPrompt, buildRewriteDocsPrompt, buildReactiveExecutePrompt, buildGateEvaluatePrompt, buildParallelResearchSlicesPrompt, checkNeedsReassessment, checkNeedsRunUat, } from "./auto-prompts.js";
15
- import { resolveModelWithFallbacksForUnit, resolveThinkingLevelForUnit } from "./preferences-models.js";
15
+ import { buildDiscussMilestonePrompt, buildDiscussProjectPrompt, buildDiscussRequirementsPrompt, buildResearchDecisionPrompt, buildResearchProjectPrompt, buildResearchMilestonePrompt, buildPlanMilestonePrompt, buildResearchSlicePrompt, buildPlanSlicePrompt, buildRefineSlicePrompt, buildExecuteTaskPrompt, buildCompleteSlicePrompt, buildCompleteMilestonePrompt, buildValidateMilestonePrompt, buildReplanSlicePrompt, buildRunUatPrompt, buildReassessRoadmapPrompt, buildRewriteDocsPrompt, buildReactiveExecutePrompt, buildGateEvaluatePrompt, buildParallelResearchSlicesPrompt, checkNeedsReassessment, loadRoadmapCompletedSliceCandidates, } from "./auto-prompts.js";
16
+ import { checkNeedsRunUat } from "./uat-dispatch.js";
17
+ import { normalizeModelFieldConfig, resolveModelWithFallbacksForUnit, resolveThinkingLevelForUnit } from "./preferences-models.js";
16
18
  import { resolveUokFlags } from "./uok/flags.js";
17
19
  import { selectReactiveDispatchBatch } from "./uok/execution-graph.js";
18
20
  import { getMilestonePipelineVariant } from "./milestone-scope-classifier.js";
@@ -141,12 +143,21 @@ export async function readUatGateVerdict(basePath, mid, sliceId) {
141
143
  if (assessmentScope === "roadmap") {
142
144
  return null;
143
145
  }
144
- const assessmentVerdict = extractVerdict(assessmentContent);
145
- if (assessmentVerdict) {
146
- return {
147
- verdict: assessmentVerdict,
148
- uatType: uatType ?? extractUatType(assessmentContent),
149
- };
146
+ // Backfilled assessments (#1258) are placeholders created during milestone
147
+ // validation for completed slices that never produced a real UAT ASSESSMENT
148
+ // (e.g. artifact-driven UAT that was never dispatched). Their fabricated
149
+ // verdict must not be treated as a genuine UAT sign-off — otherwise "never
150
+ // checked" is silently read as "passed". Skip the placeholder and fall
151
+ // through to the authoritative run-uat DB row (which stays null unless a
152
+ // real UAT was actually recorded).
153
+ if (assessmentScope !== BACKFILL_ASSESSMENT_SCOPE) {
154
+ const assessmentVerdict = extractVerdict(assessmentContent);
155
+ if (assessmentVerdict) {
156
+ return {
157
+ verdict: assessmentVerdict,
158
+ uatType: uatType ?? extractUatType(assessmentContent),
159
+ };
160
+ }
150
161
  }
151
162
  }
152
163
  if (uatContent) {
@@ -290,11 +301,20 @@ function stringField(row, key) {
290
301
  function stripGsdPrefix(path) {
291
302
  return path.startsWith(".gsd/") ? path.slice(".gsd/".length) : path;
292
303
  }
293
- function persistSliceAssessmentBackfill(assessmentRelPath, mid, sliceId, content) {
304
+ // Scope marker for assessments fabricated by the milestone-validation backfill
305
+ // (#1258). It keeps these placeholders distinguishable from genuine `run-uat`
306
+ // sign-offs so `readUatGateVerdict` never mistakes "never checked" for "passed".
307
+ const BACKFILL_ASSESSMENT_SCOPE = "backfill";
308
+ function persistSliceAssessmentBackfill(assessmentRelPath, mid, sliceId, content, fabricated) {
294
309
  const artifactPath = stripGsdPrefix(assessmentRelPath);
295
310
  const existingAssessment = getAssessment(assessmentRelPath) ??
296
311
  getAssessment(artifactPath);
297
- const scope = stringField(existingAssessment, "scope") ?? "run-uat";
312
+ // A newly fabricated placeholder is filed under a distinct scope; a pre-existing
313
+ // on-disk ASSESSMENT keeps its real scope (default `run-uat`) so genuine
314
+ // sign-offs are still honored.
315
+ const scope = fabricated
316
+ ? BACKFILL_ASSESSMENT_SCOPE
317
+ : stringField(existingAssessment, "scope") ?? "run-uat";
298
318
  const status = stringField(existingAssessment, "status") ??
299
319
  extractVerdict(content)?.toLowerCase() ??
300
320
  "unknown";
@@ -342,18 +362,24 @@ function backfillMissingAssessmentsFromSummaries(basePath, mid) {
342
362
  "---",
343
363
  `sliceId: ${sliceId}`,
344
364
  "verdict: PASS",
365
+ // Distinguishing marker (#1258): this ASSESSMENT was fabricated to satisfy
366
+ // the per-slice artifact requirement, NOT produced by a real UAT run. It
367
+ // must not be read as a genuine UAT sign-off.
368
+ "backfilled: true",
369
+ "verified: false",
345
370
  `date: ${now}`,
346
371
  "---",
347
372
  "",
348
373
  `# Assessment — ${sliceId}`,
349
374
  "",
350
375
  "Auto-created during milestone validation because this completed slice had a SUMMARY but no ASSESSMENT artifact.",
376
+ "This is a placeholder: no UAT was executed for this slice, so its verdict is not an independent sign-off.",
351
377
  "No additional reassessment changes were detected in this backfill step.",
352
378
  "",
353
379
  ].join("\n") : readFileSync(assessmentPath, "utf-8");
354
380
  if (isDbAvailable()) {
355
381
  try {
356
- persistSliceAssessmentBackfill(assessmentRelPath, mid, sliceId, content);
382
+ persistSliceAssessmentBackfill(assessmentRelPath, mid, sliceId, content, didCreateAssessment);
357
383
  }
358
384
  catch (err) {
359
385
  logWarning("dispatch", `failed to backfill assessment DB rows for ${mid}/${sliceId}: ${err.message}`);
@@ -533,7 +559,7 @@ export const DISPATCH_RULES = [
533
559
  {
534
560
  name: "run-uat (post-completion)",
535
561
  match: async ({ state, mid, basePath, prefs, sessionProvider, sessionAuthMode, activeTools, registeredTools, sessionBaseUrl, }) => {
536
- const needsRunUat = await checkNeedsRunUat(basePath, mid, state, prefs);
562
+ const needsRunUat = await checkNeedsRunUat(basePath, mid, prefs, await loadRoadmapCompletedSliceCandidates(basePath, mid));
537
563
  if (!needsRunUat)
538
564
  return null;
539
565
  const { sliceId, uatType } = needsRunUat;
@@ -1167,8 +1193,15 @@ export const DISPATCH_RULES = [
1167
1193
  if (resolveSliceFile(basePath, mid, sid, "REACTIVE-BLOCKER"))
1168
1194
  return null;
1169
1195
  const maxParallel = reactiveConfig?.max_parallel ?? 2;
1170
- const subagentModel = reactiveConfig?.subagent_model ?? resolveModelWithFallbacksForUnit("subagent")?.primary;
1171
- const subagentThinking = resolveThinkingLevelForUnit("subagent");
1196
+ // `subagent_model` accepts the phase-bucket object form (#1229); honor the
1197
+ // full primary→fallbacks chain in the dispatch prompt (the reactive
1198
+ // subagent model is embedded there rather than set as the session model).
1199
+ const subagentModelConfig = normalizeModelFieldConfig(reactiveConfig?.subagent_model)
1200
+ ?? resolveModelWithFallbacksForUnit("subagent");
1201
+ const subagentModel = subagentModelConfig?.primary;
1202
+ // Prefer the per-field `thinking` carried on `reactive_execution.subagent_model`'s
1203
+ // object form over the phase-bucket `subagent` level (#1269).
1204
+ const subagentThinking = subagentModelConfig?.thinking ?? resolveThinkingLevelForUnit("subagent");
1172
1205
  // Default-on safety threshold: only activate reactive dispatch when at
1173
1206
  // least N tasks are ready. Users who explicitly enabled reactive_execution
1174
1207
  // keep the legacy threshold of 2 (matches the prior "any parallelism is
@@ -1228,7 +1261,13 @@ export const DISPATCH_RULES = [
1228
1261
  action: "dispatch",
1229
1262
  unitType: "reactive-execute",
1230
1263
  unitId: `${mid}/${sid}/reactive+${batchSuffix}`,
1231
- prompt: await buildReactiveExecutePrompt(mid, midTitle, sid, sTitle, selected, basePath, subagentModel, { sessionContextWindow, modelRegistry, sessionProvider, subagentThinking }),
1264
+ prompt: await buildReactiveExecutePrompt(mid, midTitle, sid, sTitle, selected, basePath, subagentModel, {
1265
+ sessionContextWindow,
1266
+ modelRegistry,
1267
+ sessionProvider,
1268
+ subagentThinking,
1269
+ subagentModelFallbacks: subagentModelConfig?.fallbacks,
1270
+ }),
1232
1271
  };
1233
1272
  }
1234
1273
  catch (err) {
@@ -1500,6 +1539,19 @@ export const DISPATCH_RULES = [
1500
1539
  },
1501
1540
  ];
1502
1541
  import { getRegistry } from "./rule-registry.js";
1542
+ /**
1543
+ * Prepend the configured response-language directive to a dispatched unit
1544
+ * prompt so auto-execution units respond in the language set in PREFERENCES.md
1545
+ * (#1210). No-op for non-dispatch actions or when no language is configured.
1546
+ */
1547
+ function applyLanguageDirectiveToDispatch(action, prefs) {
1548
+ if (action.action !== "dispatch" || !action.prompt)
1549
+ return action;
1550
+ const directive = renderLanguageDirectiveForPrompt(prefs);
1551
+ if (!directive)
1552
+ return action;
1553
+ return { ...action, prompt: `${directive}\n\n${action.prompt}` };
1554
+ }
1503
1555
  // ─── Resolver ─────────────────────────────────────────────────────────────
1504
1556
  /**
1505
1557
  * Evaluate dispatch rules in order. Returns the first matching action,
@@ -1551,7 +1603,7 @@ export async function resolveDispatch(ctx) {
1551
1603
  level: "error",
1552
1604
  };
1553
1605
  }
1554
- return action;
1606
+ return applyLanguageDirectiveToDispatch(action, ctx.prefs);
1555
1607
  }
1556
1608
  catch (err) {
1557
1609
  // Registry not initialized — fall back to inline loop
@@ -1572,7 +1624,7 @@ export async function resolveDispatch(ctx) {
1572
1624
  matchedRule: rule.name,
1573
1625
  };
1574
1626
  }
1575
- return action;
1627
+ return applyLanguageDirectiveToDispatch(action, ctx.prefs);
1576
1628
  }
1577
1629
  }
1578
1630
  // No rule matched — unhandled phase.
@@ -219,10 +219,37 @@ function buildModelPolicyBlockReasons(policyDenyReasons, availableModels, routin
219
219
  reason: `configured model(s) did not resolve against policy-eligible registry [${eligibleSummary}]`,
220
220
  }];
221
221
  }
222
- function isModelUnavailable(basePath, provider, id) {
222
+ export function isModelUnavailable(basePath, provider, id) {
223
223
  return isModelBlocked(basePath, provider, id) ||
224
224
  isModelTemporarilyUnavailable(basePath, provider, id);
225
225
  }
226
+ /** Apply `auto_supervisor.model`, walking configured fallbacks on unavailability (#1229). */
227
+ export async function applySupervisorModelIfConfigured(ctx, pi, basePath) {
228
+ const modelConfig = resolveModelWithFallbacksForUnit("supervisor", basePath);
229
+ if (!modelConfig)
230
+ return;
231
+ const availableModels = ctx.modelRegistry.getAvailable();
232
+ for (const candidate of [modelConfig.primary, ...modelConfig.fallbacks]) {
233
+ const match = resolveModelId(candidate, availableModels, ctx.model?.provider);
234
+ if (!match)
235
+ continue;
236
+ if (isModelUnavailable(basePath, match.provider, match.id))
237
+ continue;
238
+ try {
239
+ if (await pi.setModel(match, { persist: false })) {
240
+ // Prefer the per-field `thinking` from `auto_supervisor.model`'s object
241
+ // form over the session level so a configured supervisor level actually
242
+ // applies (#1269).
243
+ applyThinkingLevelForModel(pi, modelConfig.thinking ?? pi.getThinkingLevel(), match, ctx);
244
+ return;
245
+ }
246
+ }
247
+ catch (err) {
248
+ // Non-fatal — try the next fallback.
249
+ logWarning("dispatch", `supervisor model set failed for ${candidate}: ${err instanceof Error ? err.message : String(err)}`);
250
+ }
251
+ }
252
+ }
226
253
  function restoreToolBaseline(pi) {
227
254
  const key = pi;
228
255
  const baseline = TOOL_BASELINE.get(key);
@@ -17,7 +17,7 @@ import { logWarning, logError } from "./workflow-logger.js";
17
17
  import { loadFile, parseSummary, resolveAllOverrides } from "./files.js";
18
18
  import { loadPrompt } from "./prompt-loader.js";
19
19
  import { isAwaitingUserInput } from "./consent-question.js";
20
- import { resolveSliceFile, resolveSlicePath, relSlicePath, resolveTaskFile, resolveMilestoneFile, resolveTasksDir, resolveFile, relMilestoneFile, relSliceFile, relTaskFile, } from "./paths.js";
20
+ import { resolveSliceFile, resolveSlicePath, relSlicePath, resolveTaskFile, resolveMilestoneFile, resolveTasksDir, resolveFile, relMilestoneFile, relSliceFile, relTaskFile, normalizeRealPath, } from "./paths.js";
21
21
  import { invalidateAllCaches } from "./cache.js";
22
22
  import { rebuildState } from "./doctor.js";
23
23
  import { parseUnitId } from "./unit-id.js";
@@ -770,7 +770,7 @@ function describeArtifactVerificationFailure(unitType, unitId, basePath, agentEn
770
770
  if (!artifactPath) {
771
771
  return `Artifact verification failed: ${unitType} "${unitId}" has no resolvable artifact path.`;
772
772
  }
773
- const relPath = relative(basePath, artifactPath);
773
+ const relPath = relative(normalizeRealPath(basePath), artifactPath);
774
774
  if (!existsSync(artifactPath)) {
775
775
  const completionToolHint = unitType === "execute-task" && !hasTaskCompletionToolCall(agentEndMessages)
776
776
  ? " No completion tool call detected (`gsd_task_complete`/alias)."
@@ -1987,7 +1987,8 @@ export async function postUnitPostVerification(pctx) {
1987
1987
  persistHookState(s.basePath);
1988
1988
  const verdict = gateBlock.verdict ? ` verdict=${gateBlock.verdict};` : "";
1989
1989
  const artifact = gateBlock.artifact ? ` artifact=${gateBlock.artifact};` : "";
1990
- const message = `Post-unit gate "${gateBlock.hookName}" blocked ${gateBlock.triggerUnitType} ${gateBlock.triggerUnitId}:` +
1990
+ const message = `Post-unit gate "${gateBlock.hookName}" blocked ${gateBlock.triggerUnitType} ${gateBlock.triggerUnitId} ` +
1991
+ `(detected on completion of ${s.currentUnit.type} ${s.currentUnit.id}):` +
1991
1992
  `${verdict}${artifact} ${gateBlock.reason}. Run /gsd status to inspect, then /gsd auto after recovery.`;
1992
1993
  ctx.ui.notify(message, "warning");
1993
1994
  await pauseAuto(ctx, pi);