gsd-pi 2.77.0-dev.eaa4973bc → 2.78.0-dev.aeeb2ca00

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 (545) hide show
  1. package/README.md +53 -17
  2. package/dist/claude-cli-check.js +46 -10
  3. package/dist/headless.js +49 -4
  4. package/dist/resource-loader.d.ts +40 -0
  5. package/dist/resource-loader.js +32 -13
  6. package/dist/resources/extensions/browser-tools/capture.js +9 -0
  7. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  8. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  9. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  10. package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
  11. package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
  12. package/dist/resources/extensions/claude-code-cli/readiness.js +72 -16
  13. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +481 -17
  14. package/dist/resources/extensions/github-sync/templates.js +103 -0
  15. package/dist/resources/extensions/google-search/index.js +3 -2
  16. package/dist/resources/extensions/gsd/auto/loop.js +124 -2
  17. package/dist/resources/extensions/gsd/auto/phases.js +57 -39
  18. package/dist/resources/extensions/gsd/auto/session.js +6 -2
  19. package/dist/resources/extensions/gsd/auto-dispatch.js +142 -29
  20. package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
  21. package/dist/resources/extensions/gsd/auto-post-unit.js +150 -64
  22. package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
  23. package/dist/resources/extensions/gsd/auto-recovery.js +197 -48
  24. package/dist/resources/extensions/gsd/auto-start.js +107 -29
  25. package/dist/resources/extensions/gsd/auto-tool-tracking.js +47 -7
  26. package/dist/resources/extensions/gsd/auto-worktree.js +122 -26
  27. package/dist/resources/extensions/gsd/auto.js +76 -21
  28. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +19 -1
  29. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +209 -0
  30. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +3 -6
  31. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -3
  32. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +127 -9
  33. package/dist/resources/extensions/gsd/component-loader.js +447 -0
  34. package/dist/resources/extensions/gsd/component-types.js +69 -0
  35. package/dist/resources/extensions/gsd/context-store.js +23 -7
  36. package/dist/resources/extensions/gsd/detection.js +49 -1
  37. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -17
  38. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  39. package/dist/resources/extensions/gsd/forensics.js +106 -0
  40. package/dist/resources/extensions/gsd/gate-registry.js +2 -2
  41. package/dist/resources/extensions/gsd/git-constants.js +28 -1
  42. package/dist/resources/extensions/gsd/git-self-heal.js +27 -0
  43. package/dist/resources/extensions/gsd/git-service.js +126 -2
  44. package/dist/resources/extensions/gsd/gsd-db.js +6 -3
  45. package/dist/resources/extensions/gsd/guided-flow.js +39 -13
  46. package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
  47. package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
  48. package/dist/resources/extensions/gsd/milestone-summary-classifier.js +37 -0
  49. package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
  50. package/dist/resources/extensions/gsd/model-router.js +6 -0
  51. package/dist/resources/extensions/gsd/native-git-bridge.js +34 -4
  52. package/dist/resources/extensions/gsd/preferences-validation.js +23 -0
  53. package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +4 -0
  54. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  55. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
  56. package/dist/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  57. package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  58. package/dist/resources/extensions/gsd/safety/git-checkpoint.js +11 -0
  59. package/dist/resources/extensions/gsd/service-tier.js +5 -2
  60. package/dist/resources/extensions/gsd/session-lock.js +19 -10
  61. package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
  62. package/dist/resources/extensions/gsd/slice-cadence.js +238 -0
  63. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
  64. package/dist/resources/extensions/gsd/state-transition-matrix.js +118 -0
  65. package/dist/resources/extensions/gsd/state.js +69 -58
  66. package/dist/resources/extensions/gsd/sync-lock.js +98 -42
  67. package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -2
  68. package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
  69. package/dist/resources/extensions/gsd/unit-context-manifest.js +370 -0
  70. package/dist/resources/extensions/gsd/uok/dispatch-envelope.js +33 -0
  71. package/dist/resources/extensions/gsd/uok/execution-graph.js +10 -0
  72. package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
  73. package/dist/resources/extensions/gsd/uok/gitops.js +2 -1
  74. package/dist/resources/extensions/gsd/uok/loop-adapter.js +37 -10
  75. package/dist/resources/extensions/gsd/uok/parity-report.js +58 -0
  76. package/dist/resources/extensions/gsd/uok/plan-v2.js +10 -4
  77. package/dist/resources/extensions/gsd/uok/writer.js +82 -0
  78. package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
  79. package/dist/resources/extensions/gsd/worktree-manager.js +85 -8
  80. package/dist/resources/extensions/gsd/worktree-resolver.js +86 -7
  81. package/dist/resources/extensions/gsd/worktree-telemetry.js +198 -0
  82. package/dist/resources/extensions/mcp-client/index.js +3 -1
  83. package/dist/resources/extensions/ollama/index.js +5 -1
  84. package/dist/resources/extensions/remote-questions/manager.js +11 -5
  85. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  86. package/dist/web/standalone/.next/BUILD_ID +1 -1
  87. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  88. package/dist/web/standalone/.next/build-manifest.json +2 -2
  89. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  90. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/api/git/route.js +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 +11 -11
  115. package/dist/web/standalone/.next/server/chunks/1926.js +1 -1
  116. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  117. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  119. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  120. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  121. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  122. package/package.json +2 -3
  123. package/packages/daemon/package.json +2 -2
  124. package/packages/daemon/src/logger.ts +4 -3
  125. package/packages/mcp-server/dist/server.d.ts +24 -0
  126. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  127. package/packages/mcp-server/dist/server.js +88 -87
  128. package/packages/mcp-server/dist/server.js.map +1 -1
  129. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  130. package/packages/mcp-server/dist/workflow-tools.js +15 -6
  131. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  132. package/packages/mcp-server/package.json +2 -2
  133. package/packages/mcp-server/src/mcp-server.test.ts +25 -3
  134. package/packages/mcp-server/src/readers/graph.test.ts +87 -15
  135. package/packages/mcp-server/src/secure-env-collect.test.ts +232 -237
  136. package/packages/mcp-server/src/server.ts +131 -105
  137. package/packages/mcp-server/src/workflow-tools.test.ts +85 -0
  138. package/packages/mcp-server/src/workflow-tools.ts +19 -6
  139. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  140. package/packages/native/package.json +2 -2
  141. package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
  142. package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
  143. package/packages/native/src/__tests__/ps.test.mjs +14 -8
  144. package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
  145. package/packages/native/src/__tests__/truncate.test.mjs +17 -2
  146. package/packages/pi-agent-core/package.json +1 -1
  147. package/packages/pi-agent-core/src/agent-loop.test.ts +5 -15
  148. package/packages/pi-agent-core/src/agent.test.ts +96 -102
  149. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  150. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -1
  151. package/packages/pi-ai/dist/models/capability-patches.js +9 -2
  152. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -1
  153. package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
  154. package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
  155. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
  156. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
  157. package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
  158. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
  159. package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
  160. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
  161. package/packages/pi-ai/dist/models/generated/openai.js +17 -0
  162. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
  163. package/packages/pi-ai/dist/models.generated.test.js +43 -70
  164. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  165. package/packages/pi-ai/dist/models.test.js +36 -11
  166. package/packages/pi-ai/dist/models.test.js.map +1 -1
  167. package/packages/pi-ai/package.json +1 -1
  168. package/packages/pi-ai/scripts/generate-models.ts +44 -0
  169. package/packages/pi-ai/src/models/capability-patches.ts +10 -2
  170. package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
  171. package/packages/pi-ai/src/models/generated/openai.ts +17 -0
  172. package/packages/pi-ai/src/models.generated.test.ts +46 -73
  173. package/packages/pi-ai/src/models.test.ts +48 -11
  174. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  175. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
  176. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  177. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
  178. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
  179. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
  180. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  181. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -0
  182. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  183. package/packages/pi-coding-agent/dist/core/extensions/loader.js +61 -0
  184. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  185. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +30 -4
  186. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
  187. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +17 -0
  188. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  189. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
  190. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
  191. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  192. package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
  193. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  194. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
  195. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  196. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
  197. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
  198. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
  199. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
  200. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
  201. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  202. package/packages/pi-coding-agent/dist/core/system-prompt.js +16 -2
  203. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  204. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  205. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  206. package/packages/pi-coding-agent/dist/index.js +1 -0
  207. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  208. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -5
  209. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  210. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
  211. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
  212. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  213. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +30 -12
  214. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  215. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  216. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +18 -3
  217. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  218. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +125 -0
  219. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  220. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +2 -0
  221. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  222. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  223. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
  224. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  225. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +105 -13
  226. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  227. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
  228. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
  229. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
  230. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
  231. package/packages/pi-coding-agent/package.json +1 -1
  232. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
  233. package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
  234. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
  235. package/packages/pi-coding-agent/src/core/extensions/loader.ts +58 -0
  236. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +35 -4
  237. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +20 -0
  238. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
  239. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
  240. package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
  241. package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
  242. package/packages/pi-coding-agent/src/core/system-prompt.ts +35 -1
  243. package/packages/pi-coding-agent/src/index.ts +1 -0
  244. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +49 -3
  245. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
  246. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +48 -9
  247. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +146 -1
  248. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +20 -3
  249. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +2 -0
  250. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +119 -13
  251. package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
  252. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  253. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +18 -8
  254. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  255. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
  256. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  257. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +37 -11
  258. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  259. package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
  260. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  261. package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
  262. package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
  263. package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
  264. package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
  265. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
  266. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
  267. package/packages/pi-tui/dist/components/editor.d.ts +14 -0
  268. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  269. package/packages/pi-tui/dist/components/editor.js +19 -0
  270. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  271. package/packages/pi-tui/dist/components/image.test.js +6 -5
  272. package/packages/pi-tui/dist/components/image.test.js.map +1 -1
  273. package/packages/pi-tui/dist/editor-component.d.ts +2 -0
  274. package/packages/pi-tui/dist/editor-component.d.ts.map +1 -1
  275. package/packages/pi-tui/dist/editor-component.js.map +1 -1
  276. package/packages/pi-tui/package.json +1 -1
  277. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +24 -8
  278. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
  279. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +42 -11
  280. package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
  281. package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
  282. package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
  283. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
  284. package/packages/pi-tui/src/components/editor.ts +22 -0
  285. package/packages/pi-tui/src/components/image.test.ts +10 -5
  286. package/packages/pi-tui/src/editor-component.ts +3 -0
  287. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  288. package/packages/rpc-client/dist/rpc-client.test.js +101 -51
  289. package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
  290. package/packages/rpc-client/package.json +1 -1
  291. package/packages/rpc-client/src/rpc-client.test.ts +109 -52
  292. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  293. package/pkg/package.json +1 -1
  294. package/scripts/install.js +15 -1
  295. package/src/resources/extensions/browser-tools/capture.ts +12 -0
  296. package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  297. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  298. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  299. package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
  300. package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
  301. package/src/resources/extensions/claude-code-cli/readiness.ts +75 -16
  302. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +518 -19
  303. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +919 -75
  304. package/src/resources/extensions/github-sync/templates.ts +151 -0
  305. package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
  306. package/src/resources/extensions/github-sync/tests/templates.test.ts +92 -1
  307. package/src/resources/extensions/google-search/index.ts +3 -2
  308. package/src/resources/extensions/gsd/auto/loop.ts +142 -2
  309. package/src/resources/extensions/gsd/auto/phases.ts +62 -38
  310. package/src/resources/extensions/gsd/auto/session.ts +7 -2
  311. package/src/resources/extensions/gsd/auto-dispatch.ts +156 -29
  312. package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
  313. package/src/resources/extensions/gsd/auto-post-unit.ts +163 -73
  314. package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
  315. package/src/resources/extensions/gsd/auto-recovery.ts +230 -51
  316. package/src/resources/extensions/gsd/auto-start.ts +127 -9
  317. package/src/resources/extensions/gsd/auto-tool-tracking.ts +51 -7
  318. package/src/resources/extensions/gsd/auto-worktree.ts +130 -26
  319. package/src/resources/extensions/gsd/auto.ts +90 -23
  320. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +20 -1
  321. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +221 -0
  322. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +3 -7
  323. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -3
  324. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +158 -9
  325. package/src/resources/extensions/gsd/component-loader.ts +598 -0
  326. package/src/resources/extensions/gsd/component-types.ts +362 -0
  327. package/src/resources/extensions/gsd/context-store.ts +25 -8
  328. package/src/resources/extensions/gsd/detection.ts +58 -1
  329. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -20
  330. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  331. package/src/resources/extensions/gsd/forensics.ts +118 -1
  332. package/src/resources/extensions/gsd/gate-registry.ts +2 -2
  333. package/src/resources/extensions/gsd/git-constants.ts +30 -1
  334. package/src/resources/extensions/gsd/git-self-heal.ts +31 -0
  335. package/src/resources/extensions/gsd/git-service.ts +149 -2
  336. package/src/resources/extensions/gsd/gsd-db.ts +6 -3
  337. package/src/resources/extensions/gsd/guided-flow.ts +57 -14
  338. package/src/resources/extensions/gsd/journal.ts +11 -1
  339. package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
  340. package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
  341. package/src/resources/extensions/gsd/milestone-summary-classifier.ts +42 -0
  342. package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
  343. package/src/resources/extensions/gsd/model-router.ts +6 -0
  344. package/src/resources/extensions/gsd/native-git-bridge.ts +34 -4
  345. package/src/resources/extensions/gsd/preferences-validation.ts +21 -0
  346. package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +4 -0
  347. package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  348. package/src/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
  349. package/src/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  350. package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  351. package/src/resources/extensions/gsd/safety/git-checkpoint.ts +15 -0
  352. package/src/resources/extensions/gsd/service-tier.ts +5 -2
  353. package/src/resources/extensions/gsd/session-lock.ts +20 -10
  354. package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
  355. package/src/resources/extensions/gsd/slice-cadence.ts +299 -0
  356. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
  357. package/src/resources/extensions/gsd/state-transition-matrix.ts +152 -0
  358. package/src/resources/extensions/gsd/state.ts +76 -66
  359. package/src/resources/extensions/gsd/sync-lock.ts +97 -39
  360. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +270 -0
  361. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
  362. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +341 -0
  363. package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +264 -0
  364. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +133 -292
  365. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
  366. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +78 -0
  367. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +61 -0
  368. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +93 -0
  369. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +4 -1
  370. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -194
  371. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +3 -2
  372. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +2 -2
  373. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
  374. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +2 -2
  375. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +3 -2
  376. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +3 -2
  377. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -1
  378. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
  379. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
  380. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
  381. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +25 -0
  382. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
  383. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +2 -1
  384. package/src/resources/extensions/gsd/tests/complete-task.test.ts +16 -8
  385. package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
  386. package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
  387. package/src/resources/extensions/gsd/tests/context-store.test.ts +79 -0
  388. package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +2 -1
  389. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
  390. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +159 -0
  391. package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +1 -0
  392. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -3
  393. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +40 -0
  394. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +91 -3
  395. package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -4
  396. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +2 -1
  397. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +2 -1
  398. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +5 -0
  399. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +25 -0
  400. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +14 -0
  401. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
  402. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +4 -3
  403. package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +4 -3
  404. package/src/resources/extensions/gsd/tests/execution-entry-missing-context-4671.test.ts +173 -0
  405. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
  406. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +8 -104
  407. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
  408. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +1 -1
  409. package/src/resources/extensions/gsd/tests/google-search-stub.test.ts +14 -4
  410. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +117 -0
  411. package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
  412. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -56
  413. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +20 -0
  414. package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
  415. package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
  416. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +144 -7
  417. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +4 -0
  418. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -16
  419. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +9 -3
  420. package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
  421. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +64 -0
  422. package/src/resources/extensions/gsd/tests/knowledge.test.ts +93 -1
  423. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +8 -37
  424. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
  425. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -55
  426. package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
  427. package/src/resources/extensions/gsd/tests/milestone-summary-classifier.test.ts +30 -0
  428. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  429. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  430. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -48
  431. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
  432. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +59 -2
  433. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -130
  434. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
  435. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +32 -1
  436. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +2 -1
  437. package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +12 -0
  438. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +15 -4
  439. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +23 -24
  440. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +32 -0
  441. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +3 -2
  442. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +4 -5
  443. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +75 -2
  444. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
  445. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
  446. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
  447. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
  448. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +6 -3
  449. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
  450. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  451. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +29 -0
  452. package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +3 -2
  453. package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
  454. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
  455. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
  456. package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
  457. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +242 -0
  458. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +3 -2
  459. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
  460. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +2 -1
  461. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +112 -0
  462. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +29 -5
  463. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +44 -0
  464. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +3 -3
  465. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
  466. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +7 -6
  467. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
  468. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +31 -0
  469. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +4 -3
  470. package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
  471. package/src/resources/extensions/gsd/tests/test-helpers.ts +153 -0
  472. package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
  473. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +61 -1
  474. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -1
  475. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
  476. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +258 -0
  477. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +51 -0
  478. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +16 -0
  479. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +75 -0
  480. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
  481. package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +65 -0
  482. package/src/resources/extensions/gsd/tests/uok-parity-report.test.ts +42 -0
  483. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +19 -2
  484. package/src/resources/extensions/gsd/tests/uok-writer.test.ts +75 -0
  485. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +12 -0
  486. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -80
  487. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
  488. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
  489. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
  490. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
  491. package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
  492. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
  493. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
  494. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
  495. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +210 -0
  496. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +262 -0
  497. package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +186 -0
  498. package/src/resources/extensions/gsd/tests/write-gate.test.ts +7 -5
  499. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
  500. package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
  501. package/src/resources/extensions/gsd/types.ts +3 -3
  502. package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
  503. package/src/resources/extensions/gsd/unit-context-manifest.ts +574 -0
  504. package/src/resources/extensions/gsd/uok/contracts.ts +65 -0
  505. package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +56 -0
  506. package/src/resources/extensions/gsd/uok/execution-graph.ts +22 -0
  507. package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
  508. package/src/resources/extensions/gsd/uok/gitops.ts +6 -1
  509. package/src/resources/extensions/gsd/uok/loop-adapter.ts +45 -10
  510. package/src/resources/extensions/gsd/uok/parity-report.ts +84 -0
  511. package/src/resources/extensions/gsd/uok/plan-v2.ts +13 -5
  512. package/src/resources/extensions/gsd/uok/writer.ts +113 -0
  513. package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
  514. package/src/resources/extensions/gsd/worktree-manager.ts +108 -7
  515. package/src/resources/extensions/gsd/worktree-resolver.ts +96 -9
  516. package/src/resources/extensions/gsd/worktree-telemetry.ts +322 -0
  517. package/src/resources/extensions/mcp-client/index.ts +3 -1
  518. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
  519. package/src/resources/extensions/ollama/index.ts +5 -1
  520. package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
  521. package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
  522. package/src/resources/extensions/remote-questions/manager.ts +36 -4
  523. package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
  524. package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
  525. package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
  526. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
  527. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
  528. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
  529. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
  530. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
  531. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -143
  532. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -157
  533. package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
  534. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
  535. package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
  536. package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
  537. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
  538. package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -74
  539. package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
  540. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
  541. package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
  542. package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -125
  543. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -42
  544. /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_buildManifest.js +0 -0
  545. /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_ssgManifest.js +0 -0
@@ -19,6 +19,38 @@ import { logWarning } from "./workflow-logger.js";
19
19
  import { resolveUokFlags } from "./uok/flags.js";
20
20
  import { applyModelPolicyFilter } from "./uok/model-policy.js";
21
21
  import { isModelBlocked } from "./blocked-models.js";
22
+ import { getRequiredWorkflowToolsForAutoUnit } from "./workflow-mcp.js";
23
+
24
+ /**
25
+ * Thrown when the model-policy gate rejects every candidate model for a unit
26
+ * dispatch (#4959 / #4681 / #4850). The auto-loop catches this specifically
27
+ * to classify the unit as `blocked` rather than counting it as a retryable
28
+ * iteration error — pre-send policy denial is a configuration problem, not a
29
+ * transient runtime failure, so retrying just burns the consecutive-error
30
+ * budget toward a hard stop.
31
+ */
32
+ export class ModelPolicyDispatchBlockedError extends Error {
33
+ readonly unitType: string;
34
+ readonly unitId: string;
35
+ readonly reasons: ReadonlyArray<{ provider: string; modelId: string; reason: string }>;
36
+ constructor(
37
+ unitType: string,
38
+ unitId: string,
39
+ reasons: ReadonlyArray<{ provider: string; modelId: string; reason: string }>,
40
+ ) {
41
+ const summary = reasons.length === 0
42
+ ? "no candidate models"
43
+ : reasons
44
+ .slice(0, 4)
45
+ .map((r) => `${r.provider}/${r.modelId} (${r.reason})`)
46
+ .join("; ");
47
+ super(`Model policy denied dispatch for ${unitType}/${unitId} before prompt send. Rejected: ${summary}`);
48
+ this.name = "ModelPolicyDispatchBlockedError";
49
+ this.unitType = unitType;
50
+ this.unitId = unitId;
51
+ this.reasons = reasons;
52
+ }
53
+ }
22
54
 
23
55
  export interface ModelSelectionResult {
24
56
  /** Routing metadata for metrics recording */
@@ -33,6 +65,51 @@ export interface PreferredModelConfig {
33
65
  source: "explicit" | "synthesized";
34
66
  }
35
67
 
68
+ // Baseline active-tool set per-`pi` instance, captured the first time
69
+ // `selectAndApplyModel` runs against that instance during an auto session
70
+ // and re-applied before each subsequent dispatch. WeakMap so that test
71
+ // fakes / disposed sessions are garbage-collected normally. See
72
+ // #4959 / #4681 cross-unit poisoning notes at the call site below.
73
+ //
74
+ // LIFECYCLE: the baseline is tied to a single auto session, NOT to the
75
+ // lifetime of the `pi` instance (which can outlive many auto runs and have
76
+ // the user mutate tools between them). `clearToolBaseline` MUST be called
77
+ // at auto start AND auto stop so that a second `/gsd auto` run on the same
78
+ // `pi` does not silently restore a stale snapshot from the prior run and
79
+ // undo any tool changes the user made between sessions.
80
+ const TOOL_BASELINE = new WeakMap<object, string[]>();
81
+
82
+ /**
83
+ * Drop the captured tool baseline for `pi` so the next `selectAndApplyModel`
84
+ * call re-captures from the live active set. Wired into `startAuto` and
85
+ * `stopAuto` in `auto.ts` to bound the baseline to a single auto session.
86
+ *
87
+ * Safe to call when no baseline is recorded (no-op).
88
+ */
89
+ export function clearToolBaseline(pi: ExtensionAPI | object): void {
90
+ TOOL_BASELINE.delete(pi as unknown as object);
91
+ }
92
+
93
+ function restoreToolBaseline(pi: ExtensionAPI): void {
94
+ const key = pi as unknown as object;
95
+ const baseline = TOOL_BASELINE.get(key);
96
+ if (baseline === undefined) {
97
+ // First call: capture the canonical pre-dispatch tool set. At auto-mode
98
+ // start the active set has not yet been narrowed for any provider.
99
+ // Guarded against test fakes that omit getActiveTools — record an empty
100
+ // baseline so subsequent calls don't keep re-probing.
101
+ const initial = typeof pi.getActiveTools === "function" ? pi.getActiveTools() : [];
102
+ TOOL_BASELINE.set(key, [...initial]);
103
+ return;
104
+ }
105
+ // Restore baseline before the next unit reads getActiveTools / applies
106
+ // post-selection adjustToolSet. Older fakes that omit setActiveTools are
107
+ // tolerated — the test asserts call order on real fakes.
108
+ if (typeof pi.setActiveTools === "function") {
109
+ pi.setActiveTools([...baseline]);
110
+ }
111
+ }
112
+
36
113
  function reapplyThinkingLevel(
37
114
  pi: ExtensionAPI,
38
115
  level: ReturnType<ExtensionAPI["getThinkingLevel"]> | null | undefined,
@@ -129,6 +206,29 @@ export async function selectAndApplyModel(
129
206
  let routing: { tier: string; modelDowngraded: boolean } | null = null;
130
207
  let appliedModel: Model<Api> | null = null;
131
208
 
209
+ // ── Restore active-tool baseline before policy evaluation (#4959, #4681, #4850) ──
210
+ // Per-unit narrowing at the bottom of this function (line ~417) calls
211
+ // `pi.setActiveTools(finalToolNames)` and monotonically narrows the active
212
+ // set across units. Without restoration, a previously-dispatched unit on a
213
+ // narrow-API provider (e.g. openai-completions) leaves the active set
214
+ // missing tools that the next unit's selected model fully supports, but
215
+ // `pi.getActiveTools()` snapshot-as-hard-gate (the old behaviour) blocked
216
+ // dispatch with "tool policy denied" anyway.
217
+ //
218
+ // The baseline is captured once per `pi` instance via a WeakMap and
219
+ // re-applied here so each unit starts from a clean slate. Soft adaptation
220
+ // (adjustToolSet at the bottom of this function) still trims for the
221
+ // selected model.
222
+ //
223
+ // Auto-mode only (#4965): `guided-flow.ts:dispatchWorkflow` also calls
224
+ // `selectAndApplyModel` with `isAutoMode=false`. Guided-flow has its own
225
+ // narrow/restore via discuss-tool-scoping (guided-flow.ts:587-622) and no
226
+ // baseline-clear hook of its own, so an unconditional restore here would
227
+ // resurrect an auto-era baseline on guided-flow dispatches — silently
228
+ // overwriting any tool changes made interactively between auto sessions.
229
+ // The baseline is structurally an auto-mode concept; gate it accordingly.
230
+ if (isAutoMode) restoreToolBaseline(pi);
231
+
132
232
  if (modelConfig) {
133
233
  const availableModels = ctx.modelRegistry.getAvailable();
134
234
  const modelPolicyTraceId = `model:${ctx.sessionManager.getSessionId()}:${Date.now()}`;
@@ -160,7 +260,16 @@ export async function selectAndApplyModel(
160
260
  ? extractTaskMetadata(unitId, basePath)
161
261
  : undefined;
162
262
 
263
+ let policyDenyReasons: Array<{ provider: string; modelId: string; reason: string }> = [];
163
264
  if (uokFlags.modelPolicy) {
265
+ // Use the workflow-spec required-tool subset for the unit type rather
266
+ // than the live `pi.getActiveTools()` snapshot (#4959). The active set
267
+ // is poisoned by per-unit narrowing for narrow-API providers — using it
268
+ // as a hard gate promotes soft adaptation (adjustToolSet at line ~417)
269
+ // into a layering violation that throws before dispatch. The smaller
270
+ // workflow-required subset reflects what the unit actually needs; soft
271
+ // adaptation post-selection still trims provider-incompatible tools.
272
+ const requiredTools = getRequiredWorkflowToolsForAutoUnit(unitType);
164
273
  const policy = applyModelPolicyFilter(
165
274
  availableModels,
166
275
  {
@@ -171,15 +280,18 @@ export async function selectAndApplyModel(
171
280
  taskMetadata: taskMetadataForPolicy,
172
281
  currentProvider: ctx.model?.provider,
173
282
  allowCrossProvider: routingConfig.cross_provider !== false,
174
- requiredTools: pi.getActiveTools(),
283
+ requiredTools,
175
284
  },
176
285
  );
177
286
  routingEligibleModels = policy.eligible;
178
287
  policyAllowedModelKeys = new Set(
179
288
  policy.eligible.map((m) => `${m.provider.toLowerCase()}/${m.id.toLowerCase()}`),
180
289
  );
290
+ policyDenyReasons = policy.decisions
291
+ .filter((d) => !d.allowed)
292
+ .map((d) => ({ provider: d.provider, modelId: d.modelId, reason: d.reason }));
181
293
  if (routingEligibleModels.length === 0) {
182
- throw new Error(`Model policy denied all candidate models for ${unitType}/${unitId}`);
294
+ throw new ModelPolicyDispatchBlockedError(unitType, unitId, policyDenyReasons);
183
295
  }
184
296
  }
185
297
 
@@ -235,7 +347,11 @@ export async function selectAndApplyModel(
235
347
  );
236
348
  const availableModelIds = routingEligibleModels.map(m => `${m.provider}/${m.id}`);
237
349
 
238
- // Escalate tier on retry when escalate_on_failure is enabled (default: true)
350
+ // Escalate tier on retry when escalate_on_failure is enabled (default: true).
351
+ // #4973: Deterministic policy errors are short-circuited at the postUnit
352
+ // level (auto-post-unit.ts writes a placeholder and returns "continue"),
353
+ // so this code path only runs for legitimate model-quality retries where
354
+ // tier escalation is the right response.
239
355
  if (
240
356
  retryContext?.isRetry &&
241
357
  retryContext.previousTier &&
@@ -249,6 +365,17 @@ export async function selectAndApplyModel(
249
365
  `Tier escalation: ${retryContext.previousTier} → ${escalated} (retry after failure)`,
250
366
  "info",
251
367
  );
368
+ } else {
369
+ // #4973: Already at max tier — keep previousTier rather than letting
370
+ // fresh classification silently downgrade the model back to a lower tier.
371
+ // Without this, a light-start unit on retry 3 would revert to the light
372
+ // model after escalating to heavy on retries 1 and 2.
373
+ const tierOrder: Record<string, number> = { light: 0, standard: 1, heavy: 2 };
374
+ const prevOrder = tierOrder[retryContext.previousTier] ?? 0;
375
+ const freshOrder = tierOrder[classification.tier] ?? 0;
376
+ if (prevOrder > freshOrder) {
377
+ classification = { ...classification, tier: retryContext.previousTier as ComplexityTier, reason: "retained escalated tier from retry" };
378
+ }
252
379
  }
253
380
  }
254
381
 
@@ -443,7 +570,7 @@ export async function selectAndApplyModel(
443
570
  }
444
571
 
445
572
  if (uokFlags.modelPolicy && policyAllowedModelKeys && !attemptedPolicyEligible) {
446
- throw new Error(`Model policy denied dispatch for ${unitType}/${unitId} before prompt send`);
573
+ throw new ModelPolicyDispatchBlockedError(unitType, unitId, policyDenyReasons);
447
574
  }
448
575
  } else if (autoModeStartModel) {
449
576
  // No model preference for this unit type — re-apply the model captured
@@ -65,16 +65,28 @@ import { resolveExpectedArtifactPath as resolveArtifactForContent } from "./auto
65
65
  import { loadEffectiveGSDPreferences } from "./preferences.js";
66
66
  import { getSliceTasks } from "./gsd-db.js";
67
67
  import { runPreExecutionChecks, type PreExecutionResult } from "./pre-execution-checks.js";
68
- import { writePreExecutionEvidence } from "./verification-evidence.js";
68
+ import { writePreExecutionEvidence, type PreExecutionCheckJSON } from "./verification-evidence.js";
69
69
  import { ensureCodebaseMapFresh } from "./codebase-generator.js";
70
70
  import { resolveUokFlags } from "./uok/flags.js";
71
71
  import { UokGateRunner } from "./uok/gate-runner.js";
72
72
  import { writeTurnGitTransaction } from "./uok/gitops.js";
73
73
  import { isClosedStatus } from "./status-guards.js";
74
74
  import { detectAbandonMilestone } from "./abandon-detect.js";
75
+ import { isDeterministicPolicyError } from "./auto-tool-tracking.js";
75
76
 
76
77
  /** Maximum verification retry attempts before escalating to blocker placeholder (#2653). */
77
78
  const MAX_VERIFICATION_RETRIES = 3;
79
+ /** Keep failure toasts short while still showing concrete examples. */
80
+ const MAX_NOTIFICATION_DETAILS = 3;
81
+ const NOTIFICATION_BULLET = "•";
82
+
83
+ function formatPreExecutionCheckDetail(check: PreExecutionCheckJSON): string {
84
+ const category = check.category?.trim() || "unknown category";
85
+ const target = check.target?.trim() || "unknown target";
86
+ const message = check.message.split(/\r?\n/, 1)[0]?.trim() || "No details provided";
87
+ return ` ${NOTIFICATION_BULLET} [${category}] ${target}: ${message}`;
88
+ }
89
+
78
90
  const COMPLETE_MILESTONE_DB_SETTLE_MS = 1500;
79
91
  const COMPLETE_MILESTONE_DB_SETTLE_POLL_MS = 100;
80
92
 
@@ -125,7 +137,7 @@ import {
125
137
  describeNextUnit,
126
138
  } from "./auto-dashboard.js";
127
139
  import { existsSync, unlinkSync } from "node:fs";
128
- import { join } from "node:path";
140
+ import { join, relative } from "node:path";
129
141
  import { _resetHasChangesCache } from "./native-git-bridge.js";
130
142
  import { autoCommitCurrentBranch } from "./worktree.js";
131
143
 
@@ -253,6 +265,14 @@ export function detectRogueFileWrites(
253
265
  return rogues;
254
266
  }
255
267
 
268
+ /**
269
+ * Maximum number of times to retry a unit whose expected artifact is missing
270
+ * after execution. Matches the bounded pattern used by runPostUnitVerification
271
+ * in auto-verification.ts. Exceeding this limit pauses auto-mode instead of
272
+ * looping indefinitely (#2007).
273
+ */
274
+ const MAX_ARTIFACT_VERIFICATION_RETRIES = 3;
275
+
256
276
  export const STEP_COMPLETE_FALLBACK_MESSAGE =
257
277
  "Step complete. Run /clear, then /gsd to continue (or /gsd auto to run continuously).";
258
278
 
@@ -618,6 +638,87 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
618
638
  clearReactiveState(s.basePath, mid, sid);
619
639
  }
620
640
  });
641
+
642
+ // #4765 — slice-cadence collapse. When `git.collapse_cadence: "slice"`
643
+ // is set, squash-merge the slice's commits from the milestone branch
644
+ // onto main right here, so orphan risk shrinks from milestone-size to
645
+ // slice-size. Only runs in worktree isolation mode — the feature needs
646
+ // a milestone branch to squash from.
647
+ let sliceMergeStopped = false;
648
+ await runSafely("postUnit", "slice-cadence-merge", async () => {
649
+ const prefsResult = loadEffectiveGSDPreferences(s.basePath);
650
+ const prefs = prefsResult?.preferences;
651
+ const { getCollapseCadence, mergeSliceToMain } = await import("./slice-cadence.js");
652
+ if (getCollapseCadence(prefs) !== "slice") return;
653
+ if (prefs?.git?.isolation !== "worktree") return;
654
+ if (s.isolationDegraded) return;
655
+
656
+ const projectRoot = s.originalBasePath || s.basePath;
657
+ const { milestone: mid, slice: sid } = parseUnitId(unit.id);
658
+ if (!mid || !sid) return;
659
+
660
+ // Record the milestone start SHA before the first slice merge, so
661
+ // resquashMilestoneOnMain has a target at milestone completion.
662
+ // Resolve main branch dynamically — hard-coding "main" breaks repos
663
+ // that use "master" or a custom default branch.
664
+ if (!s.milestoneStartShas.has(mid)) {
665
+ try {
666
+ const { nativeDetectMainBranch } = await import("./native-git-bridge.js");
667
+ const mainBranch = nativeDetectMainBranch(projectRoot);
668
+ const { execFileSync } = await import("node:child_process");
669
+ const sha = execFileSync("git", ["rev-parse", mainBranch], {
670
+ cwd: projectRoot, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8",
671
+ }).trim();
672
+ if (sha) s.milestoneStartShas.set(mid, sha);
673
+ } catch (err) {
674
+ logWarning("engine", `slice-cadence: failed to record milestone start SHA: ${err instanceof Error ? err.message : String(err)}`);
675
+ }
676
+ }
677
+
678
+ try {
679
+ const result = mergeSliceToMain(projectRoot, mid, sid);
680
+ if (result.skipped) {
681
+ logWarning("engine", `slice-cadence: merge skipped for ${sid} — ${result.skippedReason}`);
682
+ return;
683
+ }
684
+ ctx.ui.notify(
685
+ `slice-cadence: ${sid} merged to main (${result.durationMs}ms).`,
686
+ "info",
687
+ );
688
+ } catch (err) {
689
+ const { MergeConflictError } = await import("./git-service.js");
690
+ if (err instanceof MergeConflictError) {
691
+ ctx.ui.notify(
692
+ `slice-cadence merge conflict in ${sid}: ${err.conflictedFiles.join(", ")}. ` +
693
+ `Resolve manually on main and run \`/gsd auto\` to resume.`,
694
+ "error",
695
+ );
696
+ // Stop auto AND signal the outer postUnit flow to exit early.
697
+ // Without the flag, subsequent hooks (triage, rogue detection,
698
+ // DB writes) would keep running against a conflicted main
699
+ // checkout after the loop was already told to stop.
700
+ const { stopAuto } = await import("./auto.js");
701
+ await stopAuto(ctx, undefined, `slice-merge-conflict on ${sid}`);
702
+ sliceMergeStopped = true;
703
+ return;
704
+ }
705
+ logError("engine", `slice-cadence merge failed for ${sid}`, {
706
+ error: err instanceof Error ? err.message : String(err),
707
+ });
708
+ // Non-conflict failures (dirty main, rev-walk error, etc.) can
709
+ // leave the checkout in an unexpected state. Stop auto-mode so
710
+ // the next slice doesn't dispatch on top of it.
711
+ const { stopAuto } = await import("./auto.js");
712
+ await stopAuto(ctx, undefined, `slice-merge-error on ${sid}`);
713
+ sliceMergeStopped = true;
714
+ }
715
+ });
716
+ // Exit early after stopAuto so the rest of post-unit processing
717
+ // (triage, rogue detection, hook dispatch, DB writes) doesn't run
718
+ // against a conflicted main checkout. Return "dispatched" to match
719
+ // the convention used by other stop/pauseAuto paths in this function
720
+ // (see signal handling earlier: stop/pause also return "dispatched").
721
+ if (sliceMergeStopped) return "dispatched";
621
722
  }
622
723
 
623
724
  // Post-triage: execute actionable resolutions
@@ -824,16 +925,35 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
824
925
  // When artifact verification fails for a unit type that has a known expected
825
926
  // artifact, return "retry" so the caller re-dispatches with failure context
826
927
  // instead of blindly re-dispatching the same unit (#1571).
827
- // After MAX_VERIFICATION_RETRIES, escalate to writeBlockerPlaceholder so the
828
- // pipeline can advance instead of looping forever (#2653).
928
+ // Retries are capped at MAX_ARTIFACT_VERIFICATION_RETRIES to prevent
929
+ // unbounded loops (#2007).
930
+ //
931
+ // Pre-checks short-circuit retry for known-unrecoverable failures:
932
+ // - Deterministic policy rejection (#4973): structural write-gate failure
933
+ // that will recur on every retry, so write a blocker placeholder.
934
+ // - DB infra failure (#2517): completion tool returned db_unavailable, so
935
+ // the artifact was never written. Retrying can never succeed.
936
+ // - Tool invocation error (#2883/#3595): malformed JSON args or queued
937
+ // user message — retry will produce the same failure.
829
938
  //
830
- // HOWEVER, if the DB is unavailable (db_unavailable), the artifact was never
831
- // written because the completion tool failed at the infra level. Retrying
832
- // can never succeed and produces a costly re-dispatch loop (#2517).
833
- if (!triggerArtifactVerified && !isDbAvailable()) {
834
- // DB infra failure do NOT retry; the completion tool returned
835
- // db_unavailable so the artifact was never written. Retrying would
836
- // produce an infinite re-dispatch loop (#2517).
939
+ // #4973: Deterministic policy rejections (e.g. context_write_blocked from the
940
+ // write-gate) are checked FIRST before the DB-availability check — because
941
+ // they are structural gates that will fire on every retry regardless of DB or
942
+ // model tier. Short-circuit immediately by writing a blocker placeholder.
943
+ if (!triggerArtifactVerified && s.lastToolInvocationError && isDeterministicPolicyError(s.lastToolInvocationError)) {
944
+ const retryKey = `${s.currentUnit.type}:${s.currentUnit.id}`;
945
+ debugLog("postUnit", { phase: "deterministic-policy-error-placeholder", unitType: s.currentUnit.type, unitId: s.currentUnit.id, error: s.lastToolInvocationError });
946
+ const reason = `Deterministic policy rejection for ${s.currentUnit.type} "${s.currentUnit.id}": ${s.lastToolInvocationError}. Retrying cannot resolve this gate — writing blocker placeholder to advance pipeline.`;
947
+ s.lastToolInvocationError = null;
948
+ s.pendingVerificationRetry = null;
949
+ s.verificationRetryCount.delete(retryKey);
950
+ writeBlockerPlaceholder(s.currentUnit.type, s.currentUnit.id, s.basePath, reason);
951
+ ctx.ui.notify(
952
+ `${s.currentUnit.type} ${s.currentUnit.id} — deterministic policy rejection, wrote blocker placeholder (no retries) (#4973)`,
953
+ "warning",
954
+ );
955
+ // Fall through to "continue" — do NOT enter the retry or db-unavailable paths.
956
+ } else if (!triggerArtifactVerified && !isDbAvailable()) {
837
957
  debugLog("postUnit", { phase: "artifact-verify-skip-db-unavailable", unitType: s.currentUnit.type, unitId: s.currentUnit.id });
838
958
  const dbSkipDiag = diagnoseExpectedArtifact(s.currentUnit.type, s.currentUnit.id, s.basePath);
839
959
  ctx.ui.notify(
@@ -841,9 +961,6 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
841
961
  "error",
842
962
  );
843
963
  } else if (!triggerArtifactVerified) {
844
- // #2883/#3595: If the artifact is missing because the tool invocation
845
- // failed (malformed JSON) or was skipped (queued user message), retrying
846
- // will produce the same failure. Pause auto-mode instead of looping.
847
964
  if (s.lastToolInvocationError) {
848
965
  const isUserSkip = /queued user message/i.test(s.lastToolInvocationError);
849
966
  const errMsg = isUserSkip
@@ -860,68 +977,36 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
860
977
  if (hasExpectedArtifact) {
861
978
  const retryKey = `${s.currentUnit.type}:${s.currentUnit.id}`;
862
979
  const attempt = (s.verificationRetryCount.get(retryKey) ?? 0) + 1;
863
- s.verificationRetryCount.set(retryKey, attempt);
864
-
865
- if (attempt > MAX_VERIFICATION_RETRIES) {
866
- // #4175: For complete-milestone, a blocker placeholder is harmful —
867
- // the stub SUMMARY has no recovery value (milestone is terminal),
868
- // it does not update DB status (so deriveState never advances),
869
- // and it fools stopAuto's presence check into merging a milestone
870
- // that was never legitimately completed. Pause auto-mode with a
871
- // clear single failure signal and preserve the worktree branch.
872
- if (s.currentUnit.type === "complete-milestone") {
873
- debugLog("postUnit", {
874
- phase: "artifact-verify-pause-complete-milestone",
875
- unitType: s.currentUnit.type,
876
- unitId: s.currentUnit.id,
877
- attempt,
878
- maxRetries: MAX_VERIFICATION_RETRIES,
879
- });
880
- s.verificationRetryCount.delete(retryKey);
881
- s.pendingVerificationRetry = null;
882
- ctx.ui.notify(
883
- `Milestone ${s.currentUnit.id} verification failed after ${MAX_VERIFICATION_RETRIES} retries — worktree branch preserved. Re-run /gsd auto once blockers are resolved.`,
884
- "error",
885
- );
886
- await pauseAuto(ctx, pi);
887
- return "dispatched";
888
- }
889
-
890
- // Retries exhausted — write a blocker placeholder so the pipeline
891
- // can advance past this stuck unit (#2653).
892
- debugLog("postUnit", {
893
- phase: "artifact-verify-escalate",
894
- unitType: s.currentUnit.type,
895
- unitId: s.currentUnit.id,
896
- attempt,
897
- maxRetries: MAX_VERIFICATION_RETRIES,
898
- });
899
- const reason = `Artifact verification failed after ${MAX_VERIFICATION_RETRIES} retries for ${s.currentUnit.type} "${s.currentUnit.id}".`;
900
- writeBlockerPlaceholder(s.currentUnit.type, s.currentUnit.id, s.basePath, reason);
901
- ctx.ui.notify(
902
- `${s.currentUnit.type} ${s.currentUnit.id} — verification retries exhausted (${MAX_VERIFICATION_RETRIES}), wrote blocker placeholder to advance pipeline`,
903
- "warning",
904
- );
905
- // Reset retry count and fall through to "continue" so the loop
906
- // re-derives state with the placeholder in place.
980
+ if (attempt > MAX_ARTIFACT_VERIFICATION_RETRIES) {
907
981
  s.verificationRetryCount.delete(retryKey);
908
- s.pendingVerificationRetry = null;
909
- // Do NOT return "retry" — fall through to "continue" below.
910
- } else {
911
- s.pendingVerificationRetry = {
912
- unitId: s.currentUnit.id,
913
- failureContext: `Artifact verification failed: expected artifact for ${s.currentUnit.type} "${s.currentUnit.id}" was not found on disk after unit execution (attempt ${attempt}).`,
914
- attempt,
915
- };
916
- debugLog("postUnit", { phase: "artifact-verify-retry", unitType: s.currentUnit.type, unitId: s.currentUnit.id, attempt });
982
+ debugLog("postUnit", { phase: "artifact-verify-exhausted", unitType: s.currentUnit.type, unitId: s.currentUnit.id, attempt });
917
983
  ctx.ui.notify(
918
- `Artifact missing for ${s.currentUnit.type} ${s.currentUnit.id} retrying (attempt ${attempt})`,
919
- "warning",
984
+ `Artifact still missing for ${s.currentUnit.type} ${s.currentUnit.id} after ${MAX_ARTIFACT_VERIFICATION_RETRIES} retries — pausing auto-mode`,
985
+ "error",
920
986
  );
921
- return "retry";
987
+ await pauseAuto(ctx, pi);
988
+ return "dispatched";
922
989
  }
990
+ s.verificationRetryCount.set(retryKey, attempt);
991
+ s.pendingVerificationRetry = {
992
+ unitId: s.currentUnit.id,
993
+ failureContext: `Artifact verification failed: expected artifact for ${s.currentUnit.type} "${s.currentUnit.id}" was not found on disk after unit execution (attempt ${attempt}/${MAX_ARTIFACT_VERIFICATION_RETRIES}).`,
994
+ attempt,
995
+ };
996
+ debugLog("postUnit", { phase: "artifact-verify-retry", unitType: s.currentUnit.type, unitId: s.currentUnit.id, attempt });
997
+ ctx.ui.notify(
998
+ `Artifact missing for ${s.currentUnit.type} ${s.currentUnit.id} — retrying (attempt ${attempt}/${MAX_ARTIFACT_VERIFICATION_RETRIES})`,
999
+ "warning",
1000
+ );
1001
+ return "retry";
923
1002
  }
924
1003
  }
1004
+
1005
+ // Verification succeeded — clear the retry counter so a future failure
1006
+ // of the same unit gets a full retry budget instead of the stale count.
1007
+ if (triggerArtifactVerified) {
1008
+ s.verificationRetryCount.delete(`${s.currentUnit.type}:${s.currentUnit.id}`);
1009
+ }
925
1010
  } else {
926
1011
  // Hook unit completed — no additional processing needed
927
1012
  }
@@ -1161,8 +1246,11 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
1161
1246
 
1162
1247
  // Write evidence JSON to slice artifacts directory
1163
1248
  const slicePath = resolveSlicePath(s.basePath, mid, sid);
1249
+ const evidenceFileName = `${sid}-PRE-EXEC-VERIFY.json`;
1250
+ let evidencePath = join(".gsd", "milestones", mid, "slices", sid, evidenceFileName);
1164
1251
  if (slicePath) {
1165
1252
  writePreExecutionEvidence(result, slicePath, mid, sid);
1253
+ evidencePath = relative(s.basePath, join(slicePath, evidenceFileName)) || evidenceFileName;
1166
1254
  }
1167
1255
 
1168
1256
  if (uokFlags.gates) {
@@ -1199,9 +1287,11 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
1199
1287
  if (result.status === "fail") {
1200
1288
  const blockingChecks = result.checks.filter(c => !c.passed && c.blocking);
1201
1289
  const blockingCount = blockingChecks.length;
1202
- const details = blockingChecks.slice(0, 3).map(c => ` \u2022 ${c.message}`).join("\n");
1203
- const suffix = blockingChecks.length > 3 ? `\n \u2022 ...and ${blockingChecks.length - 3} more` : "";
1204
- const evidenceNote = `\nSee ${sid}-PRE-EXEC-VERIFY.json for full details.`;
1290
+ const details = blockingChecks.slice(0, MAX_NOTIFICATION_DETAILS).map(formatPreExecutionCheckDetail).join("\n");
1291
+ const suffix = blockingChecks.length > MAX_NOTIFICATION_DETAILS
1292
+ ? `\n ${NOTIFICATION_BULLET} ...and ${blockingChecks.length - MAX_NOTIFICATION_DETAILS} more`
1293
+ : "";
1294
+ const evidenceNote = `\nSee ${evidencePath} for full details.`;
1205
1295
  ctx.ui.notify(
1206
1296
  `Pre-execution checks failed: ${blockingCount} blocking issue${blockingCount === 1 ? "" : "s"} found\n${details}${suffix}${evidenceNote}`,
1207
1297
  "error",