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
@@ -181,3 +181,154 @@ export function formatSummaryComment(data: SummaryData): string {
181
181
 
182
182
  return lines.join("\n");
183
183
  }
184
+
185
+ // ─── Swarm Delivery Routines ───────────────────────────────────────────────
186
+
187
+ export type SwarmLaneId = "workflow" | "state" | "writer" | "uok" | "github";
188
+
189
+ export interface SwarmLaneData {
190
+ id: SwarmLaneId;
191
+ branch: string;
192
+ owner?: string;
193
+ latestCommit?: string;
194
+ summary?: string;
195
+ changedContracts?: string[];
196
+ testEvidence?: string[];
197
+ blockers?: string[];
198
+ }
199
+
200
+ export interface SwarmLanePRData {
201
+ lane: SwarmLaneData;
202
+ impactArea: string;
203
+ transitionRisks: string[];
204
+ rollbackPlan: string[];
205
+ linkedIssue?: number;
206
+ }
207
+
208
+ export interface SwarmReleaseChecklistData {
209
+ integrationBranch: string;
210
+ lanes: SwarmLaneData[];
211
+ parityReport?: string;
212
+ rollbackDrill?: string;
213
+ requiredChecks?: string[];
214
+ openRisks?: string[];
215
+ }
216
+
217
+ export const SWARM_LANE_LABELS: Record<SwarmLaneId, string> = {
218
+ workflow: "lane/workflow",
219
+ state: "lane/state",
220
+ writer: "lane/writer",
221
+ uok: "lane/uok",
222
+ github: "lane/github",
223
+ };
224
+
225
+ function checkedList(items: string[] | undefined, emptyLabel: string): string[] {
226
+ if (!items?.length) return [`- [ ] ${emptyLabel}`];
227
+ return items.map((item) => `- [ ] ${item}`);
228
+ }
229
+
230
+ export function formatSwarmLanePRBody(data: SwarmLanePRData): string {
231
+ const lines: string[] = [];
232
+ const laneLabel = SWARM_LANE_LABELS[data.lane.id];
233
+
234
+ lines.push("## Swarm lane");
235
+ lines.push("");
236
+ lines.push(`**Lane:** \`${laneLabel}\``);
237
+ lines.push(`**Branch:** \`${data.lane.branch}\``);
238
+ if (data.lane.owner) lines.push(`**Owner:** ${data.lane.owner}`);
239
+ if (data.lane.latestCommit) lines.push(`**Latest commit:** \`${data.lane.latestCommit}\``);
240
+ lines.push("");
241
+
242
+ lines.push("## Impact area");
243
+ lines.push("");
244
+ lines.push(data.impactArea);
245
+ lines.push("");
246
+
247
+ lines.push("## Changed contracts");
248
+ lines.push(...checkedList(data.lane.changedContracts, "No shared contracts changed"));
249
+ lines.push("");
250
+
251
+ lines.push("## Transition risks");
252
+ lines.push(...checkedList(data.transitionRisks, "No transition risks identified"));
253
+ lines.push("");
254
+
255
+ lines.push("## Rollback plan");
256
+ lines.push(...checkedList(data.rollbackPlan, "Revert this lane PR"));
257
+ lines.push("");
258
+
259
+ lines.push("## Test evidence");
260
+ lines.push(...checkedList(data.lane.testEvidence, "Test evidence pending"));
261
+ lines.push("");
262
+
263
+ if (data.lane.blockers?.length) {
264
+ lines.push("## Blockers");
265
+ for (const blocker of data.lane.blockers) lines.push(`- ${blocker}`);
266
+ lines.push("");
267
+ }
268
+
269
+ if (data.linkedIssue) {
270
+ lines.push(`Closes #${data.linkedIssue}`);
271
+ lines.push("");
272
+ }
273
+
274
+ lines.push("---");
275
+ lines.push("*Auto-generated by GSD GitHub Sync swarm routines*");
276
+
277
+ return lines.join("\n");
278
+ }
279
+
280
+ export function formatSwarmReleaseChecklistBody(data: SwarmReleaseChecklistData): string {
281
+ const lines: string[] = [];
282
+
283
+ lines.push(`# UOK Swarm Release Checklist`);
284
+ lines.push("");
285
+ lines.push(`**Integration branch:** \`${data.integrationBranch}\``);
286
+ lines.push("");
287
+
288
+ lines.push("## Lane summary");
289
+ lines.push("");
290
+ lines.push("| Lane | Branch | Owner | Commit | Status |");
291
+ lines.push("|------|--------|-------|--------|--------|");
292
+ for (const lane of data.lanes) {
293
+ const owner = lane.owner ?? "";
294
+ const commit = lane.latestCommit ? `\`${lane.latestCommit}\`` : "";
295
+ const status = lane.blockers?.length ? "blocked" : "ready";
296
+ lines.push(`| \`${SWARM_LANE_LABELS[lane.id]}\` | \`${lane.branch}\` | ${owner} | ${commit} | ${status} |`);
297
+ }
298
+ lines.push("");
299
+
300
+ lines.push("## Required evidence");
301
+ lines.push("- [ ] Changed contracts summarized");
302
+ lines.push("- [ ] Transition matrix diff attached or linked");
303
+ lines.push("- [ ] Writer sequence proof attached or linked");
304
+ lines.push("- [ ] UOK parity report attached or linked");
305
+ lines.push("- [ ] Rollback drill evidence attached or linked");
306
+ lines.push("");
307
+
308
+ if (data.requiredChecks?.length) {
309
+ lines.push("## Required checks");
310
+ for (const check of data.requiredChecks) lines.push(`- [ ] ${check}`);
311
+ lines.push("");
312
+ }
313
+
314
+ lines.push("## Parity report");
315
+ lines.push(data.parityReport ?? "Pending.");
316
+ lines.push("");
317
+
318
+ lines.push("## Rollback drill");
319
+ lines.push(data.rollbackDrill ?? "Pending.");
320
+ lines.push("");
321
+
322
+ lines.push("## Open risks");
323
+ if (data.openRisks?.length) {
324
+ for (const risk of data.openRisks) lines.push(`- ${risk}`);
325
+ } else {
326
+ lines.push("None.");
327
+ }
328
+ lines.push("");
329
+
330
+ lines.push("---");
331
+ lines.push("*Auto-generated by GSD GitHub Sync swarm routines*");
332
+
333
+ return lines.join("\n");
334
+ }
@@ -1,20 +1,89 @@
1
- import test, { describe, it, beforeEach } from "node:test";
1
+ import { describe, it, beforeEach, afterEach } from "node:test";
2
2
  import assert from "node:assert/strict";
3
3
  import { ghIsAvailable, _resetGhCache } from "../cli.ts";
4
4
 
5
- describe("cli", () => {
5
+ describe("github-sync/cli.ghIsAvailable", () => {
6
+ let originalPath: string | undefined;
7
+
6
8
  beforeEach(() => {
7
9
  _resetGhCache();
10
+ originalPath = process.env.PATH;
11
+ });
12
+
13
+ afterEach(() => {
14
+ if (originalPath !== undefined) {
15
+ process.env.PATH = originalPath;
16
+ } else {
17
+ delete process.env.PATH;
18
+ }
19
+ _resetGhCache();
8
20
  });
9
21
 
10
- it("ghIsAvailable returns boolean", () => {
11
- const result = ghIsAvailable();
12
- assert.equal(typeof result, "boolean");
22
+ it("returns true when gh is on PATH, false otherwise", () => {
23
+ // Force gh to be unavailable by setting PATH to an empty-ish string
24
+ // that contains no gh. This is more robust than asserting a raw
25
+ // `typeof === 'boolean'` (which the previous test did — a tautology,
26
+ // since the function's TypeScript signature already guarantees it).
27
+ process.env.PATH = "/nonexistent-path-for-test";
28
+ assert.equal(
29
+ ghIsAvailable(),
30
+ false,
31
+ "with gh not on PATH, ghIsAvailable must return false",
32
+ );
13
33
  });
14
34
 
15
- it("ghIsAvailable caches result", () => {
35
+ it("caches the availability result — PATH changes after first call are ignored", () => {
36
+ // With the original PATH, gh may or may not be present (depends on
37
+ // the dev machine / CI runner). Either way, capture the first
38
+ // result, then mutate PATH so a fresh subprocess spawn would yield
39
+ // a different result. If the function is genuinely caching, the
40
+ // second call returns the same value despite the PATH change.
41
+
42
+ // Prime the cache with whatever the current PATH says.
16
43
  const first = ghIsAvailable();
44
+
45
+ // Change PATH so the `gh` binary is no longer findable — any
46
+ // subsequent subprocess spawn would yield false.
47
+ process.env.PATH = "/nonexistent-path-for-test";
48
+
17
49
  const second = ghIsAvailable();
18
- assert.equal(first, second);
50
+
51
+ assert.equal(
52
+ second,
53
+ first,
54
+ "cached result must not change when PATH changes after the first call. " +
55
+ "Without caching, mutating PATH away from gh would flip the result.",
56
+ );
57
+ });
58
+
59
+ it("re-evaluates after _resetGhCache — cache is the thing being tested", () => {
60
+ // This locks in that `_resetGhCache` actually clears the cache:
61
+ // with it absent, the second assertion wouldn't observe the PATH change.
62
+ process.env.PATH = "/nonexistent-path-for-test";
63
+ const beforeReset = ghIsAvailable(); // false — gh not on PATH
64
+ assert.equal(beforeReset, false);
65
+
66
+ _resetGhCache();
67
+ // Restore PATH so that if a real gh is available, the cached
68
+ // "false" from before-reset must not persist.
69
+ if (originalPath !== undefined) {
70
+ process.env.PATH = originalPath;
71
+ }
72
+
73
+ // After reset, another call re-probes. We don't know whether the
74
+ // real machine has gh, but we know the re-probe happened because
75
+ // before-reset with an empty PATH was false AND if the machine
76
+ // has gh, the post-reset result would be true (i.e. different).
77
+ const afterReset = ghIsAvailable();
78
+ // Invariant: either the dev machine has gh (afterReset=true, differs
79
+ // from beforeReset) or it doesn't (afterReset=false, unchanged).
80
+ // Both are fine — what matters is that _resetGhCache cleared the
81
+ // memoized value so the re-probe ran. That's observable by the
82
+ // fact that with gh present, afterReset=true even though the
83
+ // cached pre-reset value was false.
84
+ assert.ok(
85
+ typeof afterReset === "boolean",
86
+ "re-probe must return a boolean",
87
+ );
19
88
  });
20
89
  });
@@ -5,6 +5,9 @@ import {
5
5
  formatSlicePRBody,
6
6
  formatTaskIssueBody,
7
7
  formatSummaryComment,
8
+ formatSwarmLanePRBody,
9
+ formatSwarmReleaseChecklistBody,
10
+ SWARM_LANE_LABELS,
8
11
  } from "../templates.ts";
9
12
 
10
13
  describe("templates", () => {
@@ -102,9 +105,97 @@ describe("templates", () => {
102
105
  assert.ok(comment.includes("duration:"));
103
106
  });
104
107
 
105
- it("handles empty data gracefully", () => {
108
+ it("handles empty data gracefully — no debug-artifact output", () => {
109
+ // Previous version only asserted `typeof === 'string'`, which the
110
+ // function signature already guarantees (tautology).
111
+ //
112
+ // The real invariant is: empty input must produce a string that
113
+ // is safe to post (or skip) without leaking a debug-stringified
114
+ // object. An empty string IS allowed here — callers are expected
115
+ // to gate on truthiness before posting ("skip if empty"). What
116
+ // must NOT happen is leaking 'undefined', '[object Object]',
117
+ // 'null', or a template-placeholder tell like '{{' / '}}'.
106
118
  const comment = formatSummaryComment({});
107
119
  assert.equal(typeof comment, "string");
120
+ assert.doesNotMatch(
121
+ comment,
122
+ /^undefined$|^\[object Object\]$|^null$/,
123
+ "empty-data comment must not be a debug-style stringified artifact",
124
+ );
125
+ assert.doesNotMatch(
126
+ comment,
127
+ /\{\{\s*\w+\s*\}\}/,
128
+ "empty-data comment must not leak unsubstituted {{placeholders}}",
129
+ );
130
+ });
131
+
132
+ it("empty input produces empty comment — callers gate on truthiness", () => {
133
+ // Sister to the previous test: this locks in the current behaviour
134
+ // that empty input returns empty string, so a regression that
135
+ // unexpectedly starts emitting a non-empty default (which would
136
+ // then post spam comments for every bare-data milestone) fails.
137
+ const comment = formatSummaryComment({});
138
+ assert.equal(
139
+ comment,
140
+ "",
141
+ "empty data must return exactly '' so callers can `if (comment)` gate",
142
+ );
143
+ });
144
+ });
145
+
146
+ describe("swarm delivery routines", () => {
147
+ it("formats lane PR bodies with impact, risks, rollback, and evidence", () => {
148
+ const body = formatSwarmLanePRBody({
149
+ lane: {
150
+ id: "writer",
151
+ branch: "lane/single-writer",
152
+ owner: "@owner",
153
+ latestCommit: "abc1234",
154
+ changedContracts: ["WriterToken"],
155
+ testEvidence: ["npm run typecheck:extensions"],
156
+ },
157
+ impactArea: "Single-writer UOK metadata.",
158
+ transitionRisks: ["Writer token lifecycle regression"],
159
+ rollbackPlan: ["Disable writer sequence enrichment"],
160
+ linkedIssue: 123,
161
+ });
162
+
163
+ assert.ok(body.includes("`lane/writer`"));
164
+ assert.ok(body.includes("Single-writer UOK metadata."));
165
+ assert.ok(body.includes("- [ ] Writer token lifecycle regression"));
166
+ assert.ok(body.includes("- [ ] Disable writer sequence enrichment"));
167
+ assert.ok(body.includes("- [ ] npm run typecheck:extensions"));
168
+ assert.ok(body.includes("Closes #123"));
169
+ });
170
+
171
+ it("formats release checklist bodies from lane state", () => {
172
+ const body = formatSwarmReleaseChecklistBody({
173
+ integrationBranch: "integration/uok-swarm",
174
+ lanes: [
175
+ { id: "workflow", branch: "lane/workflow-engine", owner: "@a", latestCommit: "1111111" },
176
+ { id: "state", branch: "lane/state-machine", blockers: ["matrix gap"] },
177
+ ],
178
+ parityReport: "No critical mismatches.",
179
+ rollbackDrill: "Passed fallback drill.",
180
+ requiredChecks: ["unit", "integration"],
181
+ });
182
+
183
+ assert.ok(body.includes("`integration/uok-swarm`"));
184
+ assert.ok(body.includes("| `lane/workflow` | `lane/workflow-engine` | @a | `1111111` | ready |"));
185
+ assert.ok(body.includes("| `lane/state` | `lane/state-machine` | | | blocked |"));
186
+ assert.ok(body.includes("- [ ] UOK parity report attached or linked"));
187
+ assert.ok(body.includes("- [ ] unit"));
188
+ assert.ok(body.includes("Passed fallback drill."));
189
+ });
190
+
191
+ it("declares expected swarm lane labels for generated GitHub routines", () => {
192
+ assert.deepEqual(Object.values(SWARM_LANE_LABELS), [
193
+ "lane/workflow",
194
+ "lane/state",
195
+ "lane/writer",
196
+ "lane/uok",
197
+ "lane/github",
198
+ ]);
108
199
  });
109
200
  });
110
201
  });
@@ -4,8 +4,9 @@ import type { ExtensionAPI } from "@gsd/pi-coding-agent";
4
4
  export default function (pi: ExtensionAPI) {
5
5
  pi.on("session_start", async (_event, ctx) => {
6
6
  ctx.ui.notify(
7
- "google_search has moved to @gsd-extensions/google-search. " +
8
- "Install: gsd extensions install @gsd-extensions/google-search",
7
+ "google_search is being extracted to @gsd-extensions/google-search " +
8
+ "(not yet published to npm). This stub will be replaced once the " +
9
+ "package is available. No action needed for now.",
9
10
  "warning",
10
11
  );
11
12
  });
@@ -29,14 +29,16 @@ import {
29
29
  } from "./phases.js";
30
30
  import { debugLog } from "../debug-logger.js";
31
31
  import { isInfrastructureError, isTransientCooldownError, getCooldownRetryAfterMs, COOLDOWN_FALLBACK_WAIT_MS, MAX_COOLDOWN_RETRIES } from "./infra-errors.js";
32
+ import { ModelPolicyDispatchBlockedError } from "../auto-model-selection.js";
32
33
  import { resolveEngine } from "../engine-resolver.js";
33
34
  import { logWarning } from "../workflow-logger.js";
34
35
  import { gsdRoot } from "../paths.js";
36
+ import { atomicWriteSync } from "../atomic-write.js";
35
37
  import { resolveUokFlags } from "../uok/flags.js";
36
38
  import { scheduleSidecarQueue } from "../uok/execution-graph.js";
37
39
  import { ExecutionGraphScheduler } from "../uok/execution-graph.js";
38
40
  import type { UokGraphNode } from "../uok/contracts.js";
39
- import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
41
+ import { readFileSync, writeFileSync, mkdirSync, unlinkSync } from "node:fs";
40
42
  import { join } from "node:path";
41
43
 
42
44
  // ── Stuck detection persistence (#3704) ──────────────────────────────────
@@ -82,12 +84,69 @@ function saveStuckState(basePath: string, state: LoopState): void {
82
84
  }
83
85
  }
84
86
 
87
+ // ── Custom workflow verification retry persistence ───────────────────────
88
+ // Custom workflows can request verification retries after a step runs. The
89
+ // retry budget must survive an auto-mode restart or a failing verifier can
90
+ // consume a fresh retry budget every session.
91
+ function customVerifyRetryStateDir(s: Pick<AutoSession, "activeRunDir" | "basePath">): string {
92
+ return s.activeRunDir ? join(s.activeRunDir, "runtime") : join(gsdRoot(s.basePath), "runtime");
93
+ }
94
+
95
+ function customVerifyRetryStatePath(s: Pick<AutoSession, "activeRunDir" | "basePath">): string {
96
+ return join(customVerifyRetryStateDir(s), "custom-verify-retries.json");
97
+ }
98
+
99
+ function hydrateCustomVerifyRetryCounts(s: AutoSession): Map<string, number> {
100
+ if (s.verificationRetryCount.size > 0) {
101
+ return s.verificationRetryCount;
102
+ }
103
+
104
+ try {
105
+ const raw = JSON.parse(readFileSync(customVerifyRetryStatePath(s), "utf-8"));
106
+ const counts = raw && typeof raw === "object" && raw.counts && typeof raw.counts === "object"
107
+ ? raw.counts as Record<string, unknown>
108
+ : {};
109
+ for (const [key, value] of Object.entries(counts)) {
110
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) {
111
+ s.verificationRetryCount.set(key, Math.floor(value));
112
+ }
113
+ }
114
+ } catch (err) {
115
+ debugLog("autoLoop", { phase: "load-custom-verify-retries-failed", error: err instanceof Error ? err.message : String(err) });
116
+ }
117
+
118
+ return s.verificationRetryCount;
119
+ }
120
+
121
+ function saveCustomVerifyRetryCounts(s: AutoSession): void {
122
+ const retryCounts = s.verificationRetryCount;
123
+ const filePath = customVerifyRetryStatePath(s);
124
+
125
+ try {
126
+ if (!retryCounts || retryCounts.size === 0) {
127
+ unlinkSync(filePath);
128
+ return;
129
+ }
130
+ mkdirSync(customVerifyRetryStateDir(s), { recursive: true });
131
+ atomicWriteSync(filePath, JSON.stringify({
132
+ counts: Object.fromEntries(retryCounts),
133
+ updatedAt: new Date().toISOString(),
134
+ }) + "\n");
135
+ } catch (err) {
136
+ const code = err && typeof err === "object" && "code" in err ? (err as { code?: string }).code : undefined;
137
+ if (code !== "ENOENT") {
138
+ debugLog("autoLoop", { phase: "save-custom-verify-retries-failed", error: err instanceof Error ? err.message : String(err) });
139
+ }
140
+ }
141
+ }
142
+
85
143
  // ── Memory pressure monitoring (#3331) ──────────────────────────────────
86
144
  // Check heap usage every N iterations and trigger graceful shutdown before
87
145
  // the OS OOM killer sends SIGKILL. The threshold is 90% of the V8 heap
88
146
  // limit (--max-old-space-size or default ~1.5-4GB depending on platform).
89
147
  const MEMORY_CHECK_INTERVAL = 5; // check every 5 iterations
90
148
  const MEMORY_PRESSURE_THRESHOLD = 0.85; // 85% of heap limit
149
+ const MAX_CUSTOM_ENGINE_VERIFY_RETRIES = 3;
91
150
 
92
151
  type DispatchContract = "legacy-direct" | "uok-scheduler";
93
152
 
@@ -437,16 +496,51 @@ export async function autoLoop(
437
496
  break;
438
497
  }
439
498
  if (verifyResult === "retry") {
440
- debugLog("autoLoop", { phase: "custom-engine-verify-retry", iteration, unitId: iterData.unitId });
499
+ const recoveryKey = `${iterData.unitType}/${iterData.unitId}`;
500
+ const retryCounts = hydrateCustomVerifyRetryCounts(s);
501
+ const attempts = (retryCounts.get(recoveryKey) ?? 0) + 1;
502
+ retryCounts.set(recoveryKey, attempts);
503
+ saveCustomVerifyRetryCounts(s);
504
+ debugLog("autoLoop", { phase: "custom-engine-verify-retry", iteration, unitId: iterData.unitId, attempts });
441
505
  deps.uokObserver?.onPhaseResult("custom-engine", "retry", {
442
506
  unitType: iterData.unitType,
443
507
  unitId: iterData.unitId,
508
+ attempts,
444
509
  });
510
+ if (attempts > MAX_CUSTOM_ENGINE_VERIFY_RETRIES) {
511
+ const recovery = await policy.recover(iterData.unitType, iterData.unitId, { basePath: s.basePath });
512
+ if (recovery.outcome === "pause") {
513
+ await deps.pauseAuto(ctx, pi);
514
+ finishTurn("paused", "manual-attention", recovery.reason ?? "custom-engine-verify-retry-exhausted");
515
+ break;
516
+ }
517
+ if (recovery.outcome === "skip") {
518
+ await deps.stopAuto(
519
+ ctx,
520
+ pi,
521
+ recovery.reason ??
522
+ `Custom workflow verification for ${iterData.unitId} requested skip after retry exhaustion, but the custom engine cannot reconcile skipped steps.`,
523
+ );
524
+ finishTurn("stopped", "manual-attention", "custom-engine-verify-retry-exhausted");
525
+ break;
526
+ }
527
+ const exhaustedReason =
528
+ `Custom workflow verification for ${iterData.unitId} requested retry ${attempts} times without passing.`;
529
+ await deps.stopAuto(
530
+ ctx,
531
+ pi,
532
+ recovery.outcome === "stop" && recovery.reason ? recovery.reason : exhaustedReason,
533
+ );
534
+ finishTurn("stopped", "manual-attention", "custom-engine-verify-retry-exhausted");
535
+ break;
536
+ }
445
537
  finishTurn("retry");
446
538
  continue;
447
539
  }
448
540
 
449
541
  // Verification passed — mark step complete
542
+ s.verificationRetryCount?.delete(`${iterData.unitType}/${iterData.unitId}`);
543
+ saveCustomVerifyRetryCounts(s);
450
544
  debugLog("autoLoop", { phase: "custom-engine-reconcile", iteration, unitId: iterData.unitId });
451
545
  const reconcileResult = await engine.reconcile(engineState, {
452
546
  unitType: iterData.unitType,
@@ -610,6 +704,52 @@ export async function autoLoop(
610
704
  // runFinalize leave the journal incomplete, making diagnosis harder.
611
705
  deps.emitJournalEvent({ ts: new Date().toISOString(), flowId, seq: nextSeq(), eventType: "iteration-end", data: { iteration, error: msg } });
612
706
 
707
+ // ── Pre-send model-policy block: not a retryable error (#4959 / #4850) ──
708
+ // The model-policy gate runs before the prompt is sent. When every
709
+ // candidate model is denied (cross-provider disabled + flat-rate
710
+ // baseline + tool-policy denial), retrying the same unit produces the
711
+ // same denial — burning the consecutive-error budget toward a 3-strike
712
+ // hard stop and corrupting auto-mode state. Pause for user attention
713
+ // instead, with the per-model deny reasons surfaced from the typed
714
+ // error.
715
+ if (loopErr instanceof ModelPolicyDispatchBlockedError) {
716
+ debugLog("autoLoop", {
717
+ phase: "model-policy-blocked",
718
+ iteration,
719
+ unitType: loopErr.unitType,
720
+ unitId: loopErr.unitId,
721
+ reasons: loopErr.reasons,
722
+ });
723
+ ctx.ui.notify(
724
+ `Auto-mode paused: model-policy denied dispatch for ${loopErr.unitType}/${loopErr.unitId}. ${msg}`,
725
+ "error",
726
+ );
727
+ deps.emitJournalEvent({
728
+ ts: new Date().toISOString(),
729
+ flowId,
730
+ seq: nextSeq(),
731
+ eventType: "unit-end",
732
+ data: {
733
+ unitType: loopErr.unitType,
734
+ unitId: loopErr.unitId,
735
+ status: "blocked",
736
+ reason: "model-policy-dispatch-blocked",
737
+ reasons: loopErr.reasons,
738
+ },
739
+ });
740
+ // Carry the blocked unit identity into the turn-result observer:
741
+ // the throw originated inside dispatch, so observedUnitType/Id were
742
+ // not assigned by the success path at lines 453/631/647 — but the
743
+ // typed error already names the unit (#4959 / CodeRabbit).
744
+ observedUnitType = loopErr.unitType;
745
+ observedUnitId = loopErr.unitId;
746
+ await deps.pauseAuto(ctx, pi);
747
+ finishTurn("paused", "manual-attention", msg);
748
+ // Do NOT increment consecutiveErrors — the failure is configuration,
749
+ // not a transient runtime fault.
750
+ break;
751
+ }
752
+
613
753
  // ── Infrastructure errors: immediate stop, no retry ──
614
754
  // These are unrecoverable (disk full, OOM, etc.). Retrying just burns
615
755
  // LLM budget on guaranteed failures.