@opengsd/gsd-pi 1.1.1-dev.a5a2de8 → 1.1.1-dev.b2556262

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 (325) hide show
  1. package/dist/headless-recover.js +56 -1
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +18 -2
  4. package/dist/resources/extensions/browser-tools/engine/selection.js +1 -1
  5. package/dist/resources/extensions/browser-tools/extension-manifest.json +1 -1
  6. package/dist/resources/extensions/browser-tools/index.js +68 -24
  7. package/dist/resources/extensions/browser-tools/state.js +12 -0
  8. package/dist/resources/extensions/browser-tools/tools/session.js +3 -2
  9. package/dist/resources/extensions/browser-tools/utils.js +3 -3
  10. package/dist/resources/extensions/browser-tools/web-app-detect.js +52 -0
  11. package/dist/resources/extensions/gsd/auto/loop.js +4 -2
  12. package/dist/resources/extensions/gsd/auto/phases.js +87 -12
  13. package/dist/resources/extensions/gsd/auto/session.js +22 -1
  14. package/dist/resources/extensions/gsd/auto/workflow-kernel.js +1 -0
  15. package/dist/resources/extensions/gsd/auto-dispatch.js +81 -13
  16. package/dist/resources/extensions/gsd/auto-model-selection.js +154 -9
  17. package/dist/resources/extensions/gsd/auto-post-unit.js +19 -2
  18. package/dist/resources/extensions/gsd/auto-prompts.js +26 -21
  19. package/dist/resources/extensions/gsd/auto-recovery.js +4 -2
  20. package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
  21. package/dist/resources/extensions/gsd/auto-start.js +1 -1
  22. package/dist/resources/extensions/gsd/auto-timers.js +24 -10
  23. package/dist/resources/extensions/gsd/auto.js +40 -15
  24. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -3
  25. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +192 -77
  26. package/dist/resources/extensions/gsd/bootstrap/system-context.js +1 -1
  27. package/dist/resources/extensions/gsd/closeout-wizard.js +32 -9
  28. package/dist/resources/extensions/gsd/commands/handlers/auto.js +10 -0
  29. package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -9
  30. package/dist/resources/extensions/gsd/commands-maintenance.js +93 -15
  31. package/dist/resources/extensions/gsd/commands-mcp-status.js +1 -1
  32. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +2 -2
  33. package/dist/resources/extensions/gsd/config-overlay.js +1 -0
  34. package/dist/resources/extensions/gsd/context-masker.js +129 -5
  35. package/dist/resources/extensions/gsd/db-writer.js +35 -0
  36. package/dist/resources/extensions/gsd/docs/preferences-reference.md +50 -1
  37. package/dist/resources/extensions/gsd/gsd-db.js +480 -172
  38. package/dist/resources/extensions/gsd/guided-flow.js +4 -1
  39. package/dist/resources/extensions/gsd/markdown-renderer.js +37 -53
  40. package/dist/resources/extensions/gsd/md-importer.js +38 -3
  41. package/dist/resources/extensions/gsd/migration-auto-check.js +126 -31
  42. package/dist/resources/extensions/gsd/parsers-legacy.js +23 -0
  43. package/dist/resources/extensions/gsd/planner-handoff.js +98 -0
  44. package/dist/resources/extensions/gsd/planning-path-scope.js +22 -4
  45. package/dist/resources/extensions/gsd/pre-execution-checks.js +10 -2
  46. package/dist/resources/extensions/gsd/preferences-models.js +111 -43
  47. package/dist/resources/extensions/gsd/preferences-types.js +13 -0
  48. package/dist/resources/extensions/gsd/preferences-validation.js +68 -3
  49. package/dist/resources/extensions/gsd/preferences.js +4 -1
  50. package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
  51. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  52. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  53. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  54. package/dist/resources/extensions/gsd/prompts/run-uat.md +2 -2
  55. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  56. package/dist/resources/extensions/gsd/roadmap-slices.js +5 -1
  57. package/dist/resources/extensions/gsd/safety/content-validator.js +6 -4
  58. package/dist/resources/extensions/gsd/skill-manifest.js +12 -0
  59. package/dist/resources/extensions/gsd/source-observations.js +306 -0
  60. package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +15 -8
  61. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +33 -5
  62. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +34 -13
  63. package/dist/resources/extensions/gsd/state-reconciliation/index.js +39 -14
  64. package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +4 -4
  65. package/dist/resources/extensions/gsd/state.js +7 -3
  66. package/dist/resources/extensions/gsd/tool-contract.js +15 -1
  67. package/dist/resources/extensions/gsd/tool-presentation-plan.js +24 -2
  68. package/dist/resources/extensions/gsd/tools/complete-slice.js +28 -0
  69. package/dist/resources/extensions/gsd/tools/plan-slice.js +42 -11
  70. package/dist/resources/extensions/gsd/tools/plan-task.js +7 -1
  71. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +62 -406
  72. package/dist/resources/extensions/gsd/uat-policy.js +130 -0
  73. package/dist/resources/extensions/gsd/uat-run.js +414 -0
  74. package/dist/resources/extensions/gsd/unit-context-manifest.js +3 -4
  75. package/dist/resources/extensions/gsd/unit-tool-contracts.js +38 -14
  76. package/dist/resources/extensions/gsd/verdict-parser.js +3 -8
  77. package/dist/resources/extensions/gsd/workflow-manifest.js +132 -5
  78. package/dist/resources/extensions/gsd/workflow-mcp.js +2 -3
  79. package/dist/resources/extensions/gsd/workflow-projections.js +8 -0
  80. package/dist/resources/extensions/gsd/worktree-manager.js +26 -0
  81. package/dist/resources/extensions/gsd/worktree-reentry.js +96 -0
  82. package/dist/resources/extensions/gsd/worktree-state-projection.js +18 -17
  83. package/dist/resources/extensions/shared/gsd-browser-cli.js +6 -0
  84. package/dist/resources/extensions/subagent/agents.js +1 -0
  85. package/dist/resources/extensions/subagent/index.js +27 -12
  86. package/dist/resources/extensions/subagent/launch.js +7 -2
  87. package/dist/web/standalone/.next/BUILD_ID +1 -1
  88. package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
  89. package/dist/web/standalone/.next/build-manifest.json +2 -2
  90. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  91. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/index.html +1 -1
  108. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app-paths-manifest.json +6 -6
  115. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  116. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  118. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  119. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  120. package/dist/web/standalone/node_modules/@gsd/native/dist/native.js +22 -0
  121. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  122. package/package.json +4 -4
  123. package/packages/cloud-mcp-gateway/package.json +2 -2
  124. package/packages/contracts/package.json +1 -1
  125. package/packages/daemon/package.json +4 -4
  126. package/packages/gsd-agent-core/package.json +5 -5
  127. package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  128. package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js +21 -23
  129. package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js.map +1 -1
  130. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +3 -0
  131. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  132. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +25 -0
  133. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  134. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts +1 -0
  135. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
  136. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +66 -12
  137. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
  138. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  139. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +18 -11
  140. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  141. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
  142. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +16 -0
  143. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
  144. package/packages/gsd-agent-modes/package.json +7 -7
  145. package/packages/mcp-server/dist/workflow-tools.js +1 -1
  146. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  147. package/packages/mcp-server/package.json +3 -3
  148. package/packages/native/dist/native.js +22 -0
  149. package/packages/native/package.json +1 -1
  150. package/packages/pi-agent-core/package.json +1 -1
  151. package/packages/pi-ai/dist/image-models.generated.d.ts +30 -0
  152. package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  153. package/packages/pi-ai/dist/image-models.generated.js +30 -0
  154. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  155. package/packages/pi-ai/dist/models.generated.d.ts +174 -29
  156. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  157. package/packages/pi-ai/dist/models.generated.js +178 -54
  158. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  159. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  160. package/packages/pi-ai/dist/providers/transform-messages.js +8 -1
  161. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  162. package/packages/pi-ai/package.json +1 -1
  163. package/packages/pi-coding-agent/dist/core/settings-manager.js +1 -1
  164. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  165. package/packages/pi-coding-agent/dist/theme/themes.js +1 -1
  166. package/packages/pi-coding-agent/dist/theme/themes.js.map +1 -1
  167. package/packages/pi-coding-agent/package.json +7 -7
  168. package/packages/pi-tui/dist/utils.d.ts +11 -0
  169. package/packages/pi-tui/dist/utils.d.ts.map +1 -1
  170. package/packages/pi-tui/dist/utils.js +119 -6
  171. package/packages/pi-tui/dist/utils.js.map +1 -1
  172. package/packages/pi-tui/package.json +2 -1
  173. package/packages/rpc-client/package.json +2 -2
  174. package/pkg/dist/theme/themes.js +1 -1
  175. package/pkg/dist/theme/themes.js.map +1 -1
  176. package/pkg/package.json +1 -1
  177. package/scripts/install/handoff.js +16 -3
  178. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +21 -2
  179. package/src/resources/extensions/browser-tools/engine/selection.ts +1 -1
  180. package/src/resources/extensions/browser-tools/extension-manifest.json +1 -1
  181. package/src/resources/extensions/browser-tools/index.ts +75 -27
  182. package/src/resources/extensions/browser-tools/state.ts +13 -0
  183. package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +2 -2
  184. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +57 -0
  185. package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +37 -0
  186. package/src/resources/extensions/browser-tools/tests/web-app-detect.test.mjs +68 -0
  187. package/src/resources/extensions/browser-tools/tools/session.ts +4 -2
  188. package/src/resources/extensions/browser-tools/utils.ts +3 -3
  189. package/src/resources/extensions/browser-tools/web-app-detect.ts +63 -0
  190. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
  191. package/src/resources/extensions/gsd/auto/loop.ts +4 -2
  192. package/src/resources/extensions/gsd/auto/phases.ts +89 -15
  193. package/src/resources/extensions/gsd/auto/session.ts +24 -1
  194. package/src/resources/extensions/gsd/auto/workflow-kernel.ts +1 -0
  195. package/src/resources/extensions/gsd/auto-dispatch.ts +117 -12
  196. package/src/resources/extensions/gsd/auto-model-selection.ts +190 -12
  197. package/src/resources/extensions/gsd/auto-post-unit.ts +20 -2
  198. package/src/resources/extensions/gsd/auto-prompts.ts +25 -22
  199. package/src/resources/extensions/gsd/auto-recovery.ts +22 -3
  200. package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
  201. package/src/resources/extensions/gsd/auto-start.ts +1 -1
  202. package/src/resources/extensions/gsd/auto-timers.ts +25 -9
  203. package/src/resources/extensions/gsd/auto.ts +41 -14
  204. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -3
  205. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +250 -78
  206. package/src/resources/extensions/gsd/bootstrap/system-context.ts +1 -1
  207. package/src/resources/extensions/gsd/closeout-wizard.ts +47 -13
  208. package/src/resources/extensions/gsd/commands/handlers/auto.ts +9 -0
  209. package/src/resources/extensions/gsd/commands/handlers/ops.ts +2 -17
  210. package/src/resources/extensions/gsd/commands-maintenance.ts +124 -13
  211. package/src/resources/extensions/gsd/commands-mcp-status.ts +1 -1
  212. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +2 -2
  213. package/src/resources/extensions/gsd/config-overlay.ts +1 -0
  214. package/src/resources/extensions/gsd/context-masker.ts +152 -5
  215. package/src/resources/extensions/gsd/db-writer.ts +38 -0
  216. package/src/resources/extensions/gsd/docs/preferences-reference.md +50 -1
  217. package/src/resources/extensions/gsd/gsd-db.ts +564 -186
  218. package/src/resources/extensions/gsd/guided-flow.ts +4 -1
  219. package/src/resources/extensions/gsd/markdown-renderer.ts +44 -66
  220. package/src/resources/extensions/gsd/md-importer.ts +49 -2
  221. package/src/resources/extensions/gsd/migration-auto-check.ts +154 -34
  222. package/src/resources/extensions/gsd/parsers-legacy.ts +20 -0
  223. package/src/resources/extensions/gsd/planner-handoff.ts +149 -0
  224. package/src/resources/extensions/gsd/planning-path-scope.ts +22 -4
  225. package/src/resources/extensions/gsd/pre-execution-checks.ts +9 -2
  226. package/src/resources/extensions/gsd/preferences-models.ts +113 -43
  227. package/src/resources/extensions/gsd/preferences-types.ts +47 -0
  228. package/src/resources/extensions/gsd/preferences-validation.ts +76 -2
  229. package/src/resources/extensions/gsd/preferences.ts +5 -0
  230. package/src/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
  231. package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  232. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  233. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  234. package/src/resources/extensions/gsd/prompts/run-uat.md +2 -2
  235. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  236. package/src/resources/extensions/gsd/roadmap-slices.ts +6 -1
  237. package/src/resources/extensions/gsd/safety/content-validator.ts +8 -5
  238. package/src/resources/extensions/gsd/skill-manifest.ts +12 -0
  239. package/src/resources/extensions/gsd/source-observations.ts +402 -0
  240. package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +20 -8
  241. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +44 -5
  242. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +39 -11
  243. package/src/resources/extensions/gsd/state-reconciliation/index.ts +45 -15
  244. package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +4 -4
  245. package/src/resources/extensions/gsd/state.ts +7 -4
  246. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +114 -0
  247. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +66 -4
  248. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +299 -1
  249. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +32 -0
  250. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +75 -3
  251. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +22 -1
  252. package/src/resources/extensions/gsd/tests/auto-supervisor.test.mjs +4 -0
  253. package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +145 -0
  254. package/src/resources/extensions/gsd/tests/bundled-skill-triggers.test.ts +9 -0
  255. package/src/resources/extensions/gsd/tests/closeout-wizard.test.ts +44 -0
  256. package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +26 -1
  257. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +118 -0
  258. package/src/resources/extensions/gsd/tests/content-validator.test.ts +74 -0
  259. package/src/resources/extensions/gsd/tests/context-masker.test.ts +56 -1
  260. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +17 -2
  261. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +24 -0
  262. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +1 -11
  263. package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +64 -0
  264. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +15 -0
  265. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +62 -1
  266. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +4 -1
  267. package/src/resources/extensions/gsd/tests/interrupted-session-auto.test.ts +27 -0
  268. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +16 -0
  269. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +42 -0
  270. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +7 -1
  271. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +1 -1
  272. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +99 -0
  273. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +99 -2
  274. package/src/resources/extensions/gsd/tests/plan-task.test.ts +19 -0
  275. package/src/resources/extensions/gsd/tests/planner-handoff.test.ts +100 -0
  276. package/src/resources/extensions/gsd/tests/preferences.test.ts +14 -0
  277. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +1 -0
  278. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +133 -0
  279. package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +55 -0
  280. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +101 -1
  281. package/src/resources/extensions/gsd/tests/repository-registry.test.ts +2 -2
  282. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +28 -0
  283. package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +5 -3
  284. package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +162 -18
  285. package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +4 -3
  286. package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +8 -0
  287. package/src/resources/extensions/gsd/tests/source-observations.test.ts +275 -0
  288. package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +43 -0
  289. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +76 -21
  290. package/src/resources/extensions/gsd/tests/thinking-level-resolution.test.ts +203 -0
  291. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +170 -0
  292. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +7 -1
  293. package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +7 -0
  294. package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +306 -1
  295. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +77 -10
  296. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +260 -5
  297. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +511 -1
  298. package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +102 -0
  299. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +44 -0
  300. package/src/resources/extensions/gsd/tool-contract.ts +29 -1
  301. package/src/resources/extensions/gsd/tool-presentation-plan.ts +41 -6
  302. package/src/resources/extensions/gsd/tools/complete-slice.ts +29 -0
  303. package/src/resources/extensions/gsd/tools/plan-slice.ts +54 -12
  304. package/src/resources/extensions/gsd/tools/plan-task.ts +8 -1
  305. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +71 -489
  306. package/src/resources/extensions/gsd/types.ts +1 -0
  307. package/src/resources/extensions/gsd/uat-policy.ts +191 -0
  308. package/src/resources/extensions/gsd/uat-run.ts +550 -0
  309. package/src/resources/extensions/gsd/unit-context-manifest.ts +3 -4
  310. package/src/resources/extensions/gsd/unit-tool-contracts.ts +38 -14
  311. package/src/resources/extensions/gsd/verdict-parser.ts +3 -10
  312. package/src/resources/extensions/gsd/workflow-manifest.ts +193 -7
  313. package/src/resources/extensions/gsd/workflow-mcp.ts +2 -3
  314. package/src/resources/extensions/gsd/workflow-projections.ts +9 -0
  315. package/src/resources/extensions/gsd/worktree-manager.ts +32 -0
  316. package/src/resources/extensions/gsd/worktree-reentry.ts +103 -0
  317. package/src/resources/extensions/gsd/worktree-state-projection.ts +22 -22
  318. package/src/resources/extensions/shared/gsd-browser-cli.ts +6 -0
  319. package/src/resources/extensions/shared/tests/format-utils.test.ts +8 -3
  320. package/src/resources/extensions/subagent/agents.ts +4 -0
  321. package/src/resources/extensions/subagent/index.ts +28 -3
  322. package/src/resources/extensions/subagent/launch.ts +8 -0
  323. package/src/resources/extensions/subagent/tests/model-override.test.ts +31 -0
  324. /package/dist/web/standalone/.next/static/{9y3LeeR2uGr2yRj9RjY3D → tJOKQbQRO-9MiFDO8DIDS}/_buildManifest.js +0 -0
  325. /package/dist/web/standalone/.next/static/{9y3LeeR2uGr2yRj9RjY3D → tJOKQbQRO-9MiFDO8DIDS}/_ssgManifest.js +0 -0
@@ -0,0 +1,63 @@
1
+ /**
2
+ * web-app-detect — lightweight, synchronous heuristic for deciding whether the
3
+ * project under development is a web app. Used only when the optional managed
4
+ * gsd-browser engine is selected and can be warmed before first use.
5
+ */
6
+ import { existsSync, readFileSync } from "node:fs";
7
+ import { resolve } from "node:path";
8
+
9
+ // Frontend frameworks / bundlers whose presence in dependencies indicates a
10
+ // browser-facing web app worth warming the optional managed engine for.
11
+ const WEB_DEPENDENCY_RE =
12
+ /^(react|react-dom|next|nuxt|vue|@vue\/|svelte|@sveltejs\/|solid-js|astro|@remix-run\/|gatsby|preact|@angular\/core|vite|@vitejs\/|@builder\.io\/qwik|@web\/dev-server|@11ty\/eleventy)/;
13
+
14
+ // package.json scripts that imply a dev server / browser-facing build.
15
+ const WEB_SCRIPT_RE = /\b(vite|next|nuxt|astro|remix|webpack(-dev-server)?|parcel|ng serve|serve\b|http-server|live-server|gatsby)\b/;
16
+
17
+ interface MinimalPackageJson {
18
+ dependencies?: Record<string, unknown>;
19
+ devDependencies?: Record<string, unknown>;
20
+ peerDependencies?: Record<string, unknown>;
21
+ scripts?: Record<string, unknown>;
22
+ }
23
+
24
+ function readPackageJson(projectRoot: string): MinimalPackageJson | null {
25
+ const packageJsonPath = resolve(projectRoot, "package.json");
26
+ if (!existsSync(packageJsonPath)) return null;
27
+ try {
28
+ const parsed = JSON.parse(readFileSync(packageJsonPath, "utf-8")) as unknown;
29
+ return parsed && typeof parsed === "object" ? (parsed as MinimalPackageJson) : null;
30
+ } catch {
31
+ return null;
32
+ }
33
+ }
34
+
35
+ function dependencyNames(pkg: MinimalPackageJson): string[] {
36
+ return [
37
+ ...Object.keys(pkg.dependencies ?? {}),
38
+ ...Object.keys(pkg.devDependencies ?? {}),
39
+ ...Object.keys(pkg.peerDependencies ?? {}),
40
+ ];
41
+ }
42
+
43
+ /**
44
+ * Returns true when the project looks like a browser-facing web app. Conservative
45
+ * and dependency-free: a false negative just means lazy connection (the prior
46
+ * behavior); a false positive only warms an idle engine connection.
47
+ */
48
+ export function detectWebApp(projectRoot: string): boolean {
49
+ const pkg = readPackageJson(projectRoot);
50
+ if (pkg) {
51
+ if (dependencyNames(pkg).some((name) => WEB_DEPENDENCY_RE.test(name))) return true;
52
+ const scriptValues = Object.values(pkg.scripts ?? {}).filter(
53
+ (value): value is string => typeof value === "string",
54
+ );
55
+ if (scriptValues.some((script) => WEB_SCRIPT_RE.test(script))) return true;
56
+ }
57
+
58
+ // No package.json signal — fall back to a top-level index.html (static sites).
59
+ if (existsSync(resolve(projectRoot, "index.html"))) return true;
60
+ if (existsSync(resolve(projectRoot, "public", "index.html"))) return true;
61
+
62
+ return false;
63
+ }
@@ -259,6 +259,7 @@ export interface LoopDeps {
259
259
  ) => Promise<{
260
260
  routing: { tier: string; modelDowngraded: boolean } | null;
261
261
  appliedModel: { provider: string; id: string } | null;
262
+ appliedThinkingLevel?: ReturnType<ExtensionAPI["getThinkingLevel"]> | null;
262
263
  }>;
263
264
  resolveModelId: <T extends { id: string; provider: string }>(
264
265
  modelId: string,
@@ -1284,7 +1284,7 @@ export async function autoLoop(
1284
1284
  unitId: iterData.unitId,
1285
1285
  });
1286
1286
  const finalizeReason = finalizeResult.action === "break" ? finalizeResult.reason : undefined;
1287
- const finalizeStatus = finalizeReason === "step-wizard"
1287
+ const finalizeStatus = (finalizeReason === "step-wizard" || finalizeReason === "milestone-complete")
1288
1288
  ? "completed"
1289
1289
  : finalizeResult.action === "next"
1290
1290
  ? "completed"
@@ -1353,7 +1353,9 @@ export async function autoLoop(
1353
1353
  stuckStatePersistedThisIteration = true;
1354
1354
  finishTurn("completed");
1355
1355
  if (finalizeDecision.action === "complete-and-break") {
1356
- s.preserveStepSurfaceAfterLoopExit = true;
1356
+ if (!s.completionStopInProgress) {
1357
+ s.preserveStepSurfaceAfterLoopExit = true;
1358
+ }
1357
1359
  break;
1358
1360
  }
1359
1361
  } catch (loopErr) {
@@ -35,6 +35,8 @@ import { detectStuck } from "./detect-stuck.js";
35
35
  import { runUnit } from "./run-unit.js";
36
36
  import { debugLog } from "../debug-logger.js";
37
37
  import { resolveWorktreeProjectRoot, normalizeWorktreePathForCompare } from "../worktree-root.js";
38
+ import { buildManualValidationGuidance } from "../worktree-manager.js";
39
+ import { relSliceFile } from "../paths.js";
38
40
  import { classifyProject } from "../detection.js";
39
41
  import { MergeConflictError } from "../git-service.js";
40
42
  import { setCurrentPhase, clearCurrentPhase } from "../../shared/gsd-phase-state.js";
@@ -83,6 +85,7 @@ import {
83
85
  supportsStructuredQuestions,
84
86
  } from "../workflow-mcp.js";
85
87
  import { prepareWorkflowMcpForProject } from "../workflow-mcp-auto-prep.js";
88
+ import { getToolBaselineSnapshot, applyThinkingLevelForModel, floorThinkingLevelForUnit } from "../auto-model-selection.js";
86
89
  import type { DispatchAction } from "../auto-dispatch.js";
87
90
  import { resolveManifest } from "../unit-context-manifest.js";
88
91
  import { createWorktreeSafetyModule, type WorktreeSafetyResult } from "../worktree-safety.js";
@@ -397,6 +400,8 @@ async function validateSourceWriteWorktreeSafety(
397
400
 
398
401
  let consecutiveSessionTimeouts = 0;
399
402
  const MAX_SESSION_TIMEOUT_AUTO_RESUMES = 3;
403
+ /** Maximum zero-tool-call retries before pausing — context exhaustion is deterministic. */
404
+ const MAX_ZERO_TOOL_RETRIES = 1;
400
405
 
401
406
  export function resetSessionTimeoutState(): void {
402
407
  consecutiveSessionTimeouts = 0;
@@ -534,7 +539,7 @@ async function closeoutAndStop(
534
539
  s.currentUnit.startedAt,
535
540
  deps.buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id),
536
541
  );
537
- s.currentUnit = null;
542
+ s.clearCurrentUnit();
538
543
  }
539
544
  await deps.stopAuto(ctx, pi, reason);
540
545
  }
@@ -802,7 +807,7 @@ async function failClosedOnFinalizeTimeout(
802
807
  );
803
808
 
804
809
  await deps.pauseAuto(ctx, pi);
805
- s.currentUnit = null;
810
+ s.clearCurrentUnit();
806
811
  clearCurrentPhase();
807
812
  drainLogs();
808
813
  return { action: "break", reason: progressKind };
@@ -1384,7 +1389,7 @@ export async function runPreDispatch(
1384
1389
  s.currentUnit.startedAt,
1385
1390
  deps.buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id),
1386
1391
  );
1387
- s.currentUnit = null;
1392
+ s.clearCurrentUnit();
1388
1393
  }
1389
1394
  await deps.stopAuto(ctx, pi, `Milestone ${mid} complete`, {
1390
1395
  completionWidget: {
@@ -1446,7 +1451,13 @@ export async function runDispatch(
1446
1451
  const authMode = provider && typeof ctx.modelRegistry?.getProviderAuthMode === "function"
1447
1452
  ? ctx.modelRegistry.getProviderAuthMode(provider)
1448
1453
  : undefined;
1449
- const activeTools = typeof pi.getActiveTools === "function" ? pi.getActiveTools() : [];
1454
+ // Use the baseline snapshot rather than the live active-tool set: a prior
1455
+ // unit's per-provider narrowing (hook overrides, Groq 128-tool cap, etc.)
1456
+ // can strip required MCP tools from the live set even though
1457
+ // selectAndApplyModel will restore them before the unit is dispatched.
1458
+ // Checking a stale-narrowed set causes false transport-preflight warnings
1459
+ // that repeat on every /gsd auto resume (#477 follow-up).
1460
+ const activeTools = getToolBaselineSnapshot(pi);
1450
1461
  // Deep planning intentionally keeps human checkpoints in plain chat. In
1451
1462
  // Claude Code/local MCP transports, structured question requests can be
1452
1463
  // cancelled outside the normal chat flow, which made approval gates easy to
@@ -1470,6 +1481,9 @@ export async function runDispatch(
1470
1481
  sessionContextWindow: ctx.model?.contextWindow,
1471
1482
  sessionProvider: ctx.model?.provider,
1472
1483
  modelRegistry: ctx.modelRegistry as MinimalModelRegistry | undefined,
1484
+ activeTools,
1485
+ sessionBaseUrl: ctx.model?.baseUrl,
1486
+ sessionAuthMode: authMode,
1473
1487
  });
1474
1488
  if (isUnhandledPhaseWarning(dispatchResult)) {
1475
1489
  deps.invalidateAllCaches();
@@ -1493,6 +1507,9 @@ export async function runDispatch(
1493
1507
  sessionContextWindow: ctx.model?.contextWindow,
1494
1508
  sessionProvider: ctx.model?.provider,
1495
1509
  modelRegistry: ctx.modelRegistry as MinimalModelRegistry | undefined,
1510
+ activeTools,
1511
+ sessionBaseUrl: ctx.model?.baseUrl,
1512
+ sessionAuthMode: authMode,
1496
1513
  });
1497
1514
  }
1498
1515
 
@@ -2233,9 +2250,16 @@ export async function runUnitPhase(
2233
2250
  if (match) {
2234
2251
  const ok = await pi.setModel(match, { persist: false });
2235
2252
  if (ok) {
2236
- if (s.autoModeStartThinkingLevel) {
2237
- pi.setThinkingLevel(s.autoModeStartThinkingLevel);
2238
- }
2253
+ // Apply the per-phase reasoning effort selectAndApplyModel resolved for
2254
+ // this unit — not the auto-start session snapshot — but route it through
2255
+ // the same floor + capability-clamp pipeline against the *hook* model
2256
+ // (ADR-026). The hook override can pick a different model family than the
2257
+ // one selectAndApplyModel clamped against, so re-clamping here prevents
2258
+ // sending an unsupported level; the floor fills in when no phase level
2259
+ // resolved so a hook-overridden execute-task still meets the floor.
2260
+ const hookThinkingBase = modelResult.appliedThinkingLevel
2261
+ ?? floorThinkingLevelForUnit(unitType, s.autoModeStartThinkingLevel);
2262
+ applyThinkingLevelForModel(pi, hookThinkingBase, match, ctx);
2239
2263
  s.currentUnitModel = match as AutoSession["currentUnitModel"];
2240
2264
  ctx.ui.notify(`Hook model override: ${match.provider}/${match.id}`, "info");
2241
2265
  } else {
@@ -2318,7 +2342,19 @@ export async function runUnitPhase(
2318
2342
  _resetLogs();
2319
2343
  const unitStartedAt = Date.now();
2320
2344
  s.unitDispatchCount.set(dispatchKey, nextDispatchCount);
2321
- s.currentUnit = { type: unitType, id: unitId, startedAt: unitStartedAt, workspaceRoot: s.basePath };
2345
+ s.setCurrentUnit({ type: unitType, id: unitId, startedAt: unitStartedAt, workspaceRoot: s.basePath });
2346
+ if (unitType === "execute-task") {
2347
+ const { milestone, slice, task } = parseUnitId(unitId);
2348
+ if (milestone && slice && task && isDbAvailable()) {
2349
+ try {
2350
+ const taskRow = getTask(milestone, slice, task);
2351
+ if (taskRow) s.sourceObservations.observePlanTask(taskRow);
2352
+ } catch (err) {
2353
+ const message = err instanceof Error ? err.message : String(err);
2354
+ logWarning("prompt", `failed to preload source observations for ${unitId}: ${message}`);
2355
+ }
2356
+ }
2357
+ }
2322
2358
  s.rootWriteBaseline = isIsolatedWorktreeSession(s)
2323
2359
  ? captureRootDirtySnapshot(s.originalBasePath)
2324
2360
  : null;
@@ -2429,7 +2465,7 @@ export async function runUnitPhase(
2429
2465
  category: "unknown",
2430
2466
  isTransient: true,
2431
2467
  });
2432
- s.currentUnit = null;
2468
+ s.clearCurrentUnit();
2433
2469
  await deps.pauseAuto(ctx, pi);
2434
2470
  return { action: "break", reason: "ghost-completion" };
2435
2471
  }
@@ -2711,14 +2747,27 @@ export async function runUnitPhase(
2711
2747
  unitId,
2712
2748
  });
2713
2749
  } else {
2750
+ const zeroToolKey = `${unitType}/${unitId}`;
2751
+ const attempt = (s.zeroToolRetryCount.get(zeroToolKey) ?? 0) + 1;
2714
2752
  debugLog("runUnitPhase", {
2715
2753
  phase: "zero-tool-calls",
2716
2754
  unitType,
2717
2755
  unitId,
2756
+ attempt,
2718
2757
  warning: "Unit completed with 0 tool calls — likely context exhaustion, marking as failed",
2719
2758
  });
2759
+ if (attempt > MAX_ZERO_TOOL_RETRIES) {
2760
+ s.zeroToolRetryCount.delete(zeroToolKey);
2761
+ ctx.ui.notify(
2762
+ `${unitType} ${unitId} completed with 0 tool calls — context exhaustion, pausing auto-mode after ${MAX_ZERO_TOOL_RETRIES} retry.`,
2763
+ "error",
2764
+ );
2765
+ await deps.pauseAuto(ctx, pi);
2766
+ return { action: "break", reason: "zero-tool-calls-exhausted" };
2767
+ }
2768
+ s.zeroToolRetryCount.set(zeroToolKey, attempt);
2720
2769
  ctx.ui.notify(
2721
- `${unitType} ${unitId} completed with 0 tool calls — context exhaustion, will retry`,
2770
+ `${unitType} ${unitId} completed with 0 tool calls — context exhaustion, will retry (attempt ${attempt}/${MAX_ZERO_TOOL_RETRIES})`,
2722
2771
  "warning",
2723
2772
  );
2724
2773
  return {
@@ -2748,6 +2797,7 @@ export async function runUnitPhase(
2748
2797
  if (artifactVerified) {
2749
2798
  s.unitDispatchCount.delete(dispatchKey);
2750
2799
  s.unitRecoveryCount.delete(`${unitType}/${unitId}`);
2800
+ s.zeroToolRetryCount.delete(dispatchKey);
2751
2801
  }
2752
2802
 
2753
2803
  // Write phase handoff anchor after successful research/planning completion
@@ -2855,7 +2905,7 @@ export async function runFinalize(
2855
2905
  s.currentUnit?.id === preUnitSnapshot.id &&
2856
2906
  s.currentUnit?.startedAt === preUnitSnapshot.startedAt
2857
2907
  ) {
2858
- s.currentUnit = null;
2908
+ s.clearCurrentUnit();
2859
2909
  }
2860
2910
  s.rootWriteBaseline = null;
2861
2911
  };
@@ -2927,10 +2977,21 @@ export async function runFinalize(
2927
2977
  }
2928
2978
 
2929
2979
  if (pauseAfterUatDispatch) {
2930
- ctx.ui.notify(
2931
- "UAT requires human execution. Auto-mode will pause after this unit writes the result file.",
2932
- "info",
2933
- );
2980
+ const pauseMid = iterData.mid;
2981
+ const pauseSliceId = pauseMid && iterData.unitId.startsWith(`${pauseMid}/`)
2982
+ ? iterData.unitId.slice(pauseMid.length + 1)
2983
+ : undefined;
2984
+ const guidance = pauseMid
2985
+ ? buildManualValidationGuidance(s.basePath, pauseMid, {
2986
+ uatPath: pauseSliceId
2987
+ ? relSliceFile(s.basePath, pauseMid, pauseSliceId, "UAT")
2988
+ : undefined,
2989
+ })
2990
+ : null;
2991
+ const pauseMessage = guidance
2992
+ ? `UAT requires human execution. Auto-mode will pause after this unit writes the result file.\n\n${guidance}`
2993
+ : "UAT requires human execution. Auto-mode will pause after this unit writes the result file.";
2994
+ ctx.ui.notify(pauseMessage, "info");
2934
2995
  await deps.pauseAuto(ctx, pi);
2935
2996
  debugLog("autoLoop", { phase: "exit", reason: "uat-pause" });
2936
2997
  clearFinalizingUnit();
@@ -3128,5 +3189,18 @@ export async function runFinalize(
3128
3189
  }
3129
3190
  }
3130
3191
 
3192
+ if (preUnitSnapshot?.type === "complete-milestone" && s.currentMilestoneId) {
3193
+ // cleanupAfterLoopExit skips gsd-progress when preserveCompletionSurface is true, so clear stale controls here.
3194
+ ctx.ui.setStatus?.("gsd-step", undefined);
3195
+ ctx.ui.setWidget?.("gsd-progress", undefined);
3196
+ await deps.stopAuto(ctx, pi, `Milestone ${s.currentMilestoneId} complete`, {
3197
+ completionWidget: {
3198
+ milestoneId: s.currentMilestoneId,
3199
+ milestoneTitle: iterData.midTitle,
3200
+ },
3201
+ });
3202
+ return { action: "break", reason: "milestone-complete" };
3203
+ }
3204
+
3131
3205
  return { action: "next", data: undefined as void };
3132
3206
  }
@@ -22,6 +22,7 @@ import type { Api, Model } from "@gsd/pi-ai";
22
22
  import type { ExtensionAPI, ExtensionCommandContext } from "@gsd/pi-coding-agent";
23
23
  import type { GitServiceImpl } from "../git-service.js";
24
24
  import type { CaptureEntry } from "../captures.js";
25
+ import { SourceObservationStore, supportsSourceObservationsForUnit } from "../source-observations.js";
25
26
  import type { BudgetAlertLevel } from "../auto-budget.js";
26
27
  import type { AutoOrchestrationModule } from "./contracts.js";
27
28
  import { resolveWorktreeProjectRoot } from "../worktree-root.js";
@@ -156,6 +157,7 @@ export class AutoSession {
156
157
  currentTurnId: string | null = null;
157
158
  currentUnitRouting: UnitRouting | null = null;
158
159
  currentMilestoneId: string | null = null;
160
+ readonly sourceObservations = new SourceObservationStore();
159
161
 
160
162
  // ── Model state ──────────────────────────────────────────────────────────
161
163
  autoModeStartModel: StartModel | null = null;
@@ -176,6 +178,7 @@ export class AutoSession {
176
178
  readonly verificationRetryCount = new Map<string, number>();
177
179
  readonly verificationRetryFailureHashes = new Map<string, string>();
178
180
  readonly exhaustedVerificationUnits = new Set<string>();
181
+ readonly zeroToolRetryCount = new Map<string, number>();
179
182
  pausedSessionFile: string | null = null;
180
183
  pausedUnitType: string | null = null;
181
184
  pausedUnitId: string | null = null;
@@ -282,6 +285,25 @@ export class AutoSession {
282
285
  this.unitLifetimeDispatches.clear();
283
286
  }
284
287
 
288
+ setCurrentUnit(unit: CurrentUnit): void {
289
+ this.currentUnit = unit;
290
+ if (!supportsSourceObservationsForUnit(unit.type)) {
291
+ this.sourceObservations.clear();
292
+ return;
293
+ }
294
+ this.sourceObservations.beginUnit({
295
+ unitType: unit.type,
296
+ unitId: unit.id,
297
+ startedAt: unit.startedAt,
298
+ basePath: unit.workspaceRoot ?? this.basePath,
299
+ });
300
+ }
301
+
302
+ clearCurrentUnit(): void {
303
+ this.currentUnit = null;
304
+ this.sourceObservations.clear();
305
+ }
306
+
285
307
  get lockBasePath(): string {
286
308
  return resolveWorktreeProjectRoot(this.basePath, this.originalBasePath);
287
309
  }
@@ -339,7 +361,7 @@ export class AutoSession {
339
361
  this.unitRecoveryCount.clear();
340
362
 
341
363
  // Unit
342
- this.currentUnit = null;
364
+ this.clearCurrentUnit();
343
365
  this.currentTraceId = null;
344
366
  this.currentTurnId = null;
345
367
  this.currentUnitRouting = null;
@@ -362,6 +384,7 @@ export class AutoSession {
362
384
  this.verificationRetryCount.clear();
363
385
  this.verificationRetryFailureHashes.clear();
364
386
  this.exhaustedVerificationUnits.clear();
387
+ this.zeroToolRetryCount.clear();
365
388
  this.pausedSessionFile = null;
366
389
  this.pausedUnitType = null;
367
390
  this.pausedUnitId = null;
@@ -284,6 +284,7 @@ const COMPLETE_AND_BREAK_REASONS = [
284
284
  "verification-pause",
285
285
  "finalize-pre-timeout",
286
286
  "finalize-post-timeout",
287
+ "milestone-complete",
287
288
  ] as const;
288
289
 
289
290
  function isCompleteAndBreakReason(
@@ -14,10 +14,21 @@
14
14
 
15
15
  import type { GSDState } from "./types.js";
16
16
  import type { GSDPreferences } from "./preferences.js";
17
- import type { UatType } from "./files.js";
18
17
  import type { MinimalModelRegistry } from "./context-budget.js";
19
18
  import { loadFile, extractUatType, loadActiveOverrides } from "./files.js";
20
- import { isDbAvailable, getMilestoneSlices, getPendingGates, markAllGatesOmitted, getMilestone, insertAssessment, setSliceSketchFlag, transaction, getAssessment } from "./gsd-db.js";
19
+ import { getUatBrowserToolSupportError, type UatType } from "./uat-policy.js";
20
+ import {
21
+ isDbAvailable,
22
+ getMilestoneSlices,
23
+ getPendingGatesForTurn,
24
+ markPendingGatesOmittedForTurn,
25
+ getMilestone,
26
+ insertArtifact,
27
+ insertAssessment,
28
+ setSliceSketchFlag,
29
+ transaction,
30
+ getAssessment,
31
+ } from "./gsd-db.js";
21
32
  import { isClosedStatus } from "./status-guards.js";
22
33
  import { extractVerdict, isAcceptableUatVerdict } from "./verdict-parser.js";
23
34
 
@@ -67,7 +78,7 @@ import {
67
78
  checkNeedsReassessment,
68
79
  checkNeedsRunUat,
69
80
  } from "./auto-prompts.js";
70
- import { resolveModelWithFallbacksForUnit } from "./preferences-models.js";
81
+ import { resolveModelWithFallbacksForUnit, resolveThinkingLevelForUnit } from "./preferences-models.js";
71
82
  import { resolveUokFlags } from "./uok/flags.js";
72
83
  import { selectReactiveDispatchBatch } from "./uok/execution-graph.js";
73
84
  import { getMilestonePipelineVariant } from "./milestone-scope-classifier.js";
@@ -76,6 +87,10 @@ import { isAutoActive } from "./auto.js";
76
87
  import { markDepthVerified } from "./bootstrap/write-gate.js";
77
88
  import { ensureWorkflowPreferencesCaptured } from "./planning-depth.js";
78
89
  import { MILESTONE_ID_RE } from "./milestone-ids.js";
90
+ import {
91
+ getWorkflowTransportSupportError,
92
+ getRequiredWorkflowToolsForAutoUnit,
93
+ } from "./workflow-mcp.js";
79
94
  import {
80
95
  PROJECT_RESEARCH_INFLIGHT_MARKER,
81
96
  } from "./project-research-policy.js";
@@ -136,6 +151,12 @@ export interface DispatchContext {
136
151
  modelRegistry?: MinimalModelRegistry;
137
152
  /** Session model provider, used for provider-specific effective context windows. */
138
153
  sessionProvider?: string;
154
+ /** Active tools in the current session, used for transport preflight checks. */
155
+ activeTools?: string[];
156
+ /** Session model base URL, used for transport preflight checks. */
157
+ sessionBaseUrl?: string;
158
+ /** Session model auth mode, used for transport preflight checks. */
159
+ sessionAuthMode?: "apiKey" | "oauth" | "externalCli" | "none";
139
160
  }
140
161
 
141
162
  function resolveExistingExpectedArtifact(
@@ -419,6 +440,53 @@ export function findMissingSummaries(basePath: string, mid: string): string[] {
419
440
  .map(s => s.id);
420
441
  }
421
442
 
443
+ function stringField(row: Record<string, unknown> | null, key: string): string | null {
444
+ const value = row?.[key];
445
+ return typeof value === "string" ? value : null;
446
+ }
447
+
448
+ function stripGsdPrefix(path: string): string {
449
+ return path.startsWith(".gsd/") ? path.slice(".gsd/".length) : path;
450
+ }
451
+
452
+ function persistSliceAssessmentBackfill(
453
+ assessmentRelPath: string,
454
+ mid: string,
455
+ sliceId: string,
456
+ content: string,
457
+ ): void {
458
+ const artifactPath = stripGsdPrefix(assessmentRelPath);
459
+ const existingAssessment =
460
+ getAssessment(assessmentRelPath) ??
461
+ getAssessment(artifactPath);
462
+ const scope = stringField(existingAssessment, "scope") ?? "run-uat";
463
+ const status = stringField(existingAssessment, "status") ??
464
+ extractVerdict(content)?.toLowerCase() ??
465
+ "unknown";
466
+
467
+ transaction(() => {
468
+ insertArtifact({
469
+ path: artifactPath,
470
+ artifact_type: "ASSESSMENT",
471
+ milestone_id: mid,
472
+ slice_id: sliceId,
473
+ task_id: null,
474
+ full_content: content,
475
+ });
476
+ if (!getAssessment(assessmentRelPath)) {
477
+ insertAssessment({
478
+ path: assessmentRelPath,
479
+ milestoneId: mid,
480
+ sliceId,
481
+ taskId: null,
482
+ status,
483
+ scope,
484
+ fullContent: content,
485
+ });
486
+ }
487
+ });
488
+ }
489
+
422
490
  function backfillMissingAssessmentsFromSummaries(basePath: string, mid: string): void {
423
491
  const completedSliceIds = new Set<string>();
424
492
  if (isDbAvailable()) {
@@ -447,11 +515,12 @@ function backfillMissingAssessmentsFromSummaries(basePath: string, mid: string):
447
515
  const slicePath = resolveSlicePath(basePath, mid, sliceId);
448
516
  const assessmentPath = resolveSliceFile(basePath, mid, sliceId, "ASSESSMENT")
449
517
  ?? (slicePath ? join(slicePath, buildSliceFileName(sliceId, "ASSESSMENT")) : null);
450
- if (!assessmentPath || existsSync(assessmentPath)) continue;
518
+ if (!assessmentPath) continue;
451
519
 
452
- mkdirSync(dirname(assessmentPath), { recursive: true });
520
+ const assessmentRelPath = relSliceFile(basePath, mid, sliceId, "ASSESSMENT");
453
521
  const now = new Date().toISOString();
454
- const content = [
522
+ const didCreateAssessment = !existsSync(assessmentPath);
523
+ const content = didCreateAssessment ? [
455
524
  "---",
456
525
  `sliceId: ${sliceId}`,
457
526
  "verdict: PASS",
@@ -463,8 +532,20 @@ function backfillMissingAssessmentsFromSummaries(basePath: string, mid: string):
463
532
  "Auto-created during milestone validation because this completed slice had a SUMMARY but no ASSESSMENT artifact.",
464
533
  "No additional reassessment changes were detected in this backfill step.",
465
534
  "",
466
- ].join("\n");
467
- writeFileSync(assessmentPath, content, "utf-8");
535
+ ].join("\n") : readFileSync(assessmentPath, "utf-8");
536
+
537
+ if (isDbAvailable()) {
538
+ try {
539
+ persistSliceAssessmentBackfill(assessmentRelPath, mid, sliceId, content);
540
+ } catch (err) {
541
+ logWarning("dispatch", `failed to backfill assessment DB rows for ${mid}/${sliceId}: ${(err as Error).message}`);
542
+ }
543
+ }
544
+
545
+ if (didCreateAssessment) {
546
+ mkdirSync(dirname(assessmentPath), { recursive: true });
547
+ writeFileSync(assessmentPath, content, "utf-8");
548
+ }
468
549
  }
469
550
  }
470
551
 
@@ -653,11 +734,32 @@ export const DISPATCH_RULES: DispatchRule[] = [
653
734
  },
654
735
  {
655
736
  name: "run-uat (post-completion)",
656
- match: async ({ state, mid, basePath, prefs }) => {
737
+ match: async ({ state, mid, basePath, prefs, sessionProvider, sessionAuthMode, activeTools, sessionBaseUrl }) => {
657
738
  const needsRunUat = await checkNeedsRunUat(basePath, mid, state, prefs);
658
739
  if (!needsRunUat) return null;
659
740
  const { sliceId, uatType } = needsRunUat;
660
741
 
742
+ // Transport preflight: verify required MCP tools are actually connected
743
+ // before consuming a retry attempt. Fixes tool-starved sessions burning
744
+ // all MAX_UAT_ATTEMPTS before stopping (#477).
745
+ const transportError = getWorkflowTransportSupportError(
746
+ sessionProvider,
747
+ getRequiredWorkflowToolsForAutoUnit("run-uat"),
748
+ { projectRoot: basePath, surface: "auto-mode", unitType: "run-uat", authMode: sessionAuthMode, baseUrl: sessionBaseUrl, activeTools },
749
+ );
750
+ if (transportError) {
751
+ return { action: "stop" as const, reason: transportError, level: "warning" as const };
752
+ }
753
+ const browserToolError = getUatBrowserToolSupportError({
754
+ uatType,
755
+ activeTools,
756
+ milestoneId: mid,
757
+ sliceId,
758
+ });
759
+ if (browserToolError) {
760
+ return { action: "stop" as const, reason: browserToolError, level: "warning" as const };
761
+ }
762
+
661
763
  // Cap run-uat dispatch attempts to prevent infinite replay (#3624).
662
764
  // Check before incrementing so an exhausted counter cannot create a
663
765
  // no-progress skip loop that starves later dispatch rules.
@@ -1063,6 +1165,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
1063
1165
  researchReadySlices,
1064
1166
  basePath,
1065
1167
  resolveModelWithFallbacksForUnit("subagent")?.primary,
1168
+ resolveThinkingLevelForUnit("subagent"),
1066
1169
  ),
1067
1170
  };
1068
1171
  },
@@ -1232,11 +1335,11 @@ export const DISPATCH_RULES: DispatchRule[] = [
1232
1335
  // Gate evaluation is opt-in via preferences
1233
1336
  const gateConfig = prefs?.gate_evaluation;
1234
1337
  if (!gateConfig?.enabled) {
1235
- markAllGatesOmitted(mid, sid);
1338
+ markPendingGatesOmittedForTurn(mid, sid, "gate-evaluate");
1236
1339
  return { action: "skip" };
1237
1340
  }
1238
1341
 
1239
- const pending = getPendingGates(mid, sid, "slice");
1342
+ const pending = getPendingGatesForTurn(mid, sid, "gate-evaluate");
1240
1343
  if (pending.length === 0) return { action: "skip" };
1241
1344
 
1242
1345
  return {
@@ -1250,6 +1353,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
1250
1353
  sTitle,
1251
1354
  basePath,
1252
1355
  resolveModelWithFallbacksForUnit("subagent")?.primary,
1356
+ resolveThinkingLevelForUnit("subagent"),
1253
1357
  ),
1254
1358
  };
1255
1359
  },
@@ -1295,6 +1399,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
1295
1399
  if (resolveSliceFile(basePath, mid, sid, "REACTIVE-BLOCKER")) return null;
1296
1400
  const maxParallel = reactiveConfig?.max_parallel ?? 2;
1297
1401
  const subagentModel = reactiveConfig?.subagent_model ?? resolveModelWithFallbacksForUnit("subagent")?.primary;
1402
+ const subagentThinking = resolveThinkingLevelForUnit("subagent");
1298
1403
  // Default-on safety threshold: only activate reactive dispatch when at
1299
1404
  // least N tasks are ready. Users who explicitly enabled reactive_execution
1300
1405
  // keep the legacy threshold of 2 (matches the prior "any parallelism is
@@ -1381,7 +1486,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
1381
1486
  selected,
1382
1487
  basePath,
1383
1488
  subagentModel,
1384
- { sessionContextWindow, modelRegistry, sessionProvider },
1489
+ { sessionContextWindow, modelRegistry, sessionProvider, subagentThinking },
1385
1490
  ),
1386
1491
  };
1387
1492
  } catch (err) {