@bastani/atomic 0.8.25 → 0.8.26-alpha.10

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 (332) hide show
  1. package/CHANGELOG.md +84 -0
  2. package/README.md +5 -5
  3. package/dist/builtin/intercom/CHANGELOG.md +60 -0
  4. package/dist/builtin/intercom/index-heavy.ts +1754 -0
  5. package/dist/builtin/intercom/index.ts +374 -1746
  6. package/dist/builtin/intercom/package.json +2 -2
  7. package/dist/builtin/intercom/result-renderers.ts +77 -0
  8. package/dist/builtin/mcp/CHANGELOG.md +64 -0
  9. package/dist/builtin/mcp/index.ts +151 -57
  10. package/dist/builtin/mcp/package.json +3 -3
  11. package/dist/builtin/subagents/CHANGELOG.md +61 -0
  12. package/dist/builtin/subagents/agents/codebase-online-researcher.md +9 -9
  13. package/dist/builtin/subagents/agents/debugger.md +6 -6
  14. package/dist/builtin/subagents/package.json +4 -4
  15. package/dist/builtin/subagents/prompts/parallel-handoff-plan.md +1 -1
  16. package/dist/builtin/subagents/skills/browser/EXAMPLES.md +151 -0
  17. package/dist/builtin/subagents/skills/browser/LICENSE.txt +21 -0
  18. package/dist/builtin/subagents/skills/browser/REFERENCE.md +451 -0
  19. package/dist/builtin/subagents/skills/browser/SKILL.md +170 -0
  20. package/dist/builtin/subagents/skills/subagent/SKILL.md +4 -4
  21. package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +55 -12
  22. package/dist/builtin/subagents/src/runs/foreground/execution.ts +71 -12
  23. package/dist/builtin/subagents/src/runs/shared/acceptance.ts +2 -1
  24. package/dist/builtin/subagents/src/runs/shared/final-drain.ts +34 -0
  25. package/dist/builtin/subagents/src/runs/shared/model-fallback.ts +416 -7
  26. package/dist/builtin/subagents/src/runs/shared/worktree.ts +2 -2
  27. package/dist/builtin/web-access/CHANGELOG.md +60 -0
  28. package/dist/builtin/web-access/index-heavy.ts +2060 -0
  29. package/dist/builtin/web-access/index.ts +182 -2274
  30. package/dist/builtin/web-access/package.json +2 -2
  31. package/dist/builtin/web-access/result-renderers.ts +364 -0
  32. package/dist/builtin/workflows/CHANGELOG.md +75 -0
  33. package/dist/builtin/workflows/README.md +10 -8
  34. package/dist/builtin/workflows/builtin/deep-research-codebase.ts +11 -8
  35. package/dist/builtin/workflows/builtin/goal.ts +137 -109
  36. package/dist/builtin/workflows/builtin/index.d.ts +2 -0
  37. package/dist/builtin/workflows/builtin/open-claude-design.ts +228 -151
  38. package/dist/builtin/workflows/builtin/ralph.d.ts +2 -0
  39. package/dist/builtin/workflows/builtin/ralph.ts +452 -279
  40. package/dist/builtin/workflows/package.json +2 -2
  41. package/dist/builtin/workflows/skills/create-spec/SKILL.md +14 -0
  42. package/dist/builtin/workflows/skills/research-codebase/SKILL.md +29 -10
  43. package/dist/builtin/workflows/src/extension/index.ts +23 -5
  44. package/dist/builtin/workflows/src/extension/runtime.ts +35 -3
  45. package/dist/builtin/workflows/src/extension/wiring.ts +13 -1
  46. package/dist/builtin/workflows/src/runs/background/status.ts +52 -6
  47. package/dist/builtin/workflows/src/runs/foreground/executor.ts +453 -21
  48. package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +130 -13
  49. package/dist/builtin/workflows/src/runs/shared/model-fallback.ts +402 -8
  50. package/dist/builtin/workflows/src/runs/shared/worktree.ts +2 -2
  51. package/dist/builtin/workflows/src/shared/authoring-contract.d.ts +2 -2
  52. package/dist/builtin/workflows/src/shared/persistence-restore.ts +182 -6
  53. package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +76 -6
  54. package/dist/builtin/workflows/src/shared/stage-prompt.ts +33 -2
  55. package/dist/builtin/workflows/src/shared/store-types.ts +31 -0
  56. package/dist/builtin/workflows/src/shared/store.ts +160 -18
  57. package/dist/builtin/workflows/src/shared/types.ts +3 -3
  58. package/dist/builtin/workflows/src/shared/workflow-failures.ts +758 -132
  59. package/dist/builtin/workflows/src/tui/inline-form-overlay.ts +12 -3
  60. package/dist/builtin/workflows/src/tui/inline-form-store.ts +17 -6
  61. package/dist/builtin/workflows/src/tui/stage-chat-view.ts +39 -3
  62. package/dist/builtin/workflows/src/tui/store-widget-installer.ts +74 -74
  63. package/dist/core/agent-session-services.d.ts.map +1 -1
  64. package/dist/core/agent-session-services.js +13 -0
  65. package/dist/core/agent-session-services.js.map +1 -1
  66. package/dist/core/agent-session.d.ts +33 -6
  67. package/dist/core/agent-session.d.ts.map +1 -1
  68. package/dist/core/agent-session.js +157 -182
  69. package/dist/core/agent-session.js.map +1 -1
  70. package/dist/core/atomic-guide-command.d.ts.map +1 -1
  71. package/dist/core/atomic-guide-command.js +11 -9
  72. package/dist/core/atomic-guide-command.js.map +1 -1
  73. package/dist/core/compaction/branch-summarization.d.ts +1 -1
  74. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  75. package/dist/core/compaction/branch-summarization.js +6 -3
  76. package/dist/core/compaction/branch-summarization.js.map +1 -1
  77. package/dist/core/compaction/compaction.d.ts.map +1 -1
  78. package/dist/core/compaction/compaction.js +23 -10
  79. package/dist/core/compaction/compaction.js.map +1 -1
  80. package/dist/core/compaction/context-compaction.d.ts +175 -0
  81. package/dist/core/compaction/context-compaction.d.ts.map +1 -0
  82. package/dist/core/compaction/context-compaction.js +1636 -0
  83. package/dist/core/compaction/context-compaction.js.map +1 -0
  84. package/dist/core/compaction/index.d.ts +1 -0
  85. package/dist/core/compaction/index.d.ts.map +1 -1
  86. package/dist/core/compaction/index.js +1 -0
  87. package/dist/core/compaction/index.js.map +1 -1
  88. package/dist/core/extensions/loader.d.ts.map +1 -1
  89. package/dist/core/extensions/loader.js +7 -0
  90. package/dist/core/extensions/loader.js.map +1 -1
  91. package/dist/core/extensions/types.d.ts +16 -3
  92. package/dist/core/extensions/types.d.ts.map +1 -1
  93. package/dist/core/extensions/types.js.map +1 -1
  94. package/dist/core/footer-data-provider.d.ts.map +1 -1
  95. package/dist/core/footer-data-provider.js +3 -0
  96. package/dist/core/footer-data-provider.js.map +1 -1
  97. package/dist/core/index.d.ts +1 -1
  98. package/dist/core/index.d.ts.map +1 -1
  99. package/dist/core/index.js.map +1 -1
  100. package/dist/core/package-manager.d.ts.map +1 -1
  101. package/dist/core/package-manager.js +14 -7
  102. package/dist/core/package-manager.js.map +1 -1
  103. package/dist/core/resource-loader.d.ts.map +1 -1
  104. package/dist/core/resource-loader.js +17 -0
  105. package/dist/core/resource-loader.js.map +1 -1
  106. package/dist/core/session-manager.d.ts +41 -1
  107. package/dist/core/session-manager.d.ts.map +1 -1
  108. package/dist/core/session-manager.js +146 -7
  109. package/dist/core/session-manager.js.map +1 -1
  110. package/dist/core/slash-commands.d.ts.map +1 -1
  111. package/dist/core/slash-commands.js +1 -1
  112. package/dist/core/slash-commands.js.map +1 -1
  113. package/dist/core/timings.d.ts +9 -0
  114. package/dist/core/timings.d.ts.map +1 -1
  115. package/dist/core/timings.js +28 -1
  116. package/dist/core/timings.js.map +1 -1
  117. package/dist/core/tools/ask-user-question/tool/format-answer.d.ts +5 -5
  118. package/dist/core/tools/ask-user-question/tool/format-answer.d.ts.map +1 -1
  119. package/dist/core/tools/ask-user-question/tool/format-answer.js +5 -5
  120. package/dist/core/tools/ask-user-question/tool/format-answer.js.map +1 -1
  121. package/dist/core/tools/ask-user-question/tool/response-envelope.d.ts +16 -3
  122. package/dist/core/tools/ask-user-question/tool/response-envelope.d.ts.map +1 -1
  123. package/dist/core/tools/ask-user-question/tool/response-envelope.js +21 -3
  124. package/dist/core/tools/ask-user-question/tool/response-envelope.js.map +1 -1
  125. package/dist/index.d.ts +4 -3
  126. package/dist/index.d.ts.map +1 -1
  127. package/dist/index.js +3 -2
  128. package/dist/index.js.map +1 -1
  129. package/dist/main.d.ts.map +1 -1
  130. package/dist/main.js +4 -2
  131. package/dist/main.js.map +1 -1
  132. package/dist/modes/index.d.ts +1 -1
  133. package/dist/modes/index.d.ts.map +1 -1
  134. package/dist/modes/index.js.map +1 -1
  135. package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
  136. package/dist/modes/interactive/components/chat-session-host.js +17 -0
  137. package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
  138. package/dist/modes/interactive/components/context-compaction-summary-message.d.ts +17 -0
  139. package/dist/modes/interactive/components/context-compaction-summary-message.d.ts.map +1 -0
  140. package/dist/modes/interactive/components/context-compaction-summary-message.js +83 -0
  141. package/dist/modes/interactive/components/context-compaction-summary-message.js.map +1 -0
  142. package/dist/modes/interactive/components/custom-message.d.ts +1 -0
  143. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  144. package/dist/modes/interactive/components/custom-message.js +36 -4
  145. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  146. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  147. package/dist/modes/interactive/components/footer.js +4 -1
  148. package/dist/modes/interactive/components/footer.js.map +1 -1
  149. package/dist/modes/interactive/components/index.d.ts +1 -0
  150. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  151. package/dist/modes/interactive/components/index.js +1 -0
  152. package/dist/modes/interactive/components/index.js.map +1 -1
  153. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  154. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  155. package/dist/modes/interactive/interactive-mode.js +94 -17
  156. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  157. package/dist/modes/rpc/rpc-client.d.ts +13 -8
  158. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  159. package/dist/modes/rpc/rpc-client.js +8 -1
  160. package/dist/modes/rpc/rpc-client.js.map +1 -1
  161. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  162. package/dist/modes/rpc/rpc-mode.js +4 -0
  163. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  164. package/dist/modes/rpc/rpc-types.d.ts +14 -3
  165. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  166. package/dist/modes/rpc/rpc-types.js.map +1 -1
  167. package/dist/utils/git-env.d.ts +10 -0
  168. package/dist/utils/git-env.d.ts.map +1 -0
  169. package/dist/utils/git-env.js +33 -0
  170. package/dist/utils/git-env.js.map +1 -0
  171. package/docs/compaction.md +185 -50
  172. package/docs/custom-provider.md +11 -9
  173. package/docs/extensions.md +46 -42
  174. package/docs/index.md +13 -6
  175. package/docs/json.md +15 -12
  176. package/docs/packages.md +2 -0
  177. package/docs/providers.md +4 -1
  178. package/docs/quickstart.md +18 -11
  179. package/docs/rpc.md +38 -23
  180. package/docs/sdk.md +17 -8
  181. package/docs/session-format.md +26 -13
  182. package/docs/sessions.md +3 -3
  183. package/docs/settings.md +2 -2
  184. package/docs/skills.md +1 -15
  185. package/docs/termux.md +9 -10
  186. package/docs/themes.md +2 -2
  187. package/docs/tmux.md +3 -3
  188. package/docs/tui.md +19 -32
  189. package/docs/usage.md +2 -2
  190. package/docs/workflows.md +60 -16
  191. package/package.json +6 -12
  192. package/dist/builtin/subagents/skills/browser-use/SKILL.md +0 -234
  193. package/dist/builtin/subagents/skills/browser-use/references/cdp-python.md +0 -76
  194. package/dist/builtin/subagents/skills/browser-use/references/multi-session.md +0 -92
  195. package/node_modules/@earendil-works/pi-tui/README.md +0 -779
  196. package/node_modules/@earendil-works/pi-tui/dist/autocomplete.d.ts +0 -54
  197. package/node_modules/@earendil-works/pi-tui/dist/autocomplete.d.ts.map +0 -1
  198. package/node_modules/@earendil-works/pi-tui/dist/autocomplete.js +0 -632
  199. package/node_modules/@earendil-works/pi-tui/dist/autocomplete.js.map +0 -1
  200. package/node_modules/@earendil-works/pi-tui/dist/components/box.d.ts +0 -22
  201. package/node_modules/@earendil-works/pi-tui/dist/components/box.d.ts.map +0 -1
  202. package/node_modules/@earendil-works/pi-tui/dist/components/box.js +0 -104
  203. package/node_modules/@earendil-works/pi-tui/dist/components/box.js.map +0 -1
  204. package/node_modules/@earendil-works/pi-tui/dist/components/cancellable-loader.d.ts +0 -22
  205. package/node_modules/@earendil-works/pi-tui/dist/components/cancellable-loader.d.ts.map +0 -1
  206. package/node_modules/@earendil-works/pi-tui/dist/components/cancellable-loader.js +0 -35
  207. package/node_modules/@earendil-works/pi-tui/dist/components/cancellable-loader.js.map +0 -1
  208. package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts +0 -249
  209. package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +0 -1
  210. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +0 -1857
  211. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +0 -1
  212. package/node_modules/@earendil-works/pi-tui/dist/components/image.d.ts +0 -28
  213. package/node_modules/@earendil-works/pi-tui/dist/components/image.d.ts.map +0 -1
  214. package/node_modules/@earendil-works/pi-tui/dist/components/image.js +0 -89
  215. package/node_modules/@earendil-works/pi-tui/dist/components/image.js.map +0 -1
  216. package/node_modules/@earendil-works/pi-tui/dist/components/input.d.ts +0 -37
  217. package/node_modules/@earendil-works/pi-tui/dist/components/input.d.ts.map +0 -1
  218. package/node_modules/@earendil-works/pi-tui/dist/components/input.js +0 -378
  219. package/node_modules/@earendil-works/pi-tui/dist/components/input.js.map +0 -1
  220. package/node_modules/@earendil-works/pi-tui/dist/components/loader.d.ts +0 -31
  221. package/node_modules/@earendil-works/pi-tui/dist/components/loader.d.ts.map +0 -1
  222. package/node_modules/@earendil-works/pi-tui/dist/components/loader.js +0 -69
  223. package/node_modules/@earendil-works/pi-tui/dist/components/loader.js.map +0 -1
  224. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.d.ts +0 -96
  225. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.d.ts.map +0 -1
  226. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js +0 -644
  227. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js.map +0 -1
  228. package/node_modules/@earendil-works/pi-tui/dist/components/select-list.d.ts +0 -50
  229. package/node_modules/@earendil-works/pi-tui/dist/components/select-list.d.ts.map +0 -1
  230. package/node_modules/@earendil-works/pi-tui/dist/components/select-list.js +0 -159
  231. package/node_modules/@earendil-works/pi-tui/dist/components/select-list.js.map +0 -1
  232. package/node_modules/@earendil-works/pi-tui/dist/components/settings-list.d.ts +0 -50
  233. package/node_modules/@earendil-works/pi-tui/dist/components/settings-list.d.ts.map +0 -1
  234. package/node_modules/@earendil-works/pi-tui/dist/components/settings-list.js +0 -185
  235. package/node_modules/@earendil-works/pi-tui/dist/components/settings-list.js.map +0 -1
  236. package/node_modules/@earendil-works/pi-tui/dist/components/spacer.d.ts +0 -12
  237. package/node_modules/@earendil-works/pi-tui/dist/components/spacer.d.ts.map +0 -1
  238. package/node_modules/@earendil-works/pi-tui/dist/components/spacer.js +0 -23
  239. package/node_modules/@earendil-works/pi-tui/dist/components/spacer.js.map +0 -1
  240. package/node_modules/@earendil-works/pi-tui/dist/components/text.d.ts +0 -19
  241. package/node_modules/@earendil-works/pi-tui/dist/components/text.d.ts.map +0 -1
  242. package/node_modules/@earendil-works/pi-tui/dist/components/text.js +0 -89
  243. package/node_modules/@earendil-works/pi-tui/dist/components/text.js.map +0 -1
  244. package/node_modules/@earendil-works/pi-tui/dist/components/truncated-text.d.ts +0 -13
  245. package/node_modules/@earendil-works/pi-tui/dist/components/truncated-text.d.ts.map +0 -1
  246. package/node_modules/@earendil-works/pi-tui/dist/components/truncated-text.js +0 -51
  247. package/node_modules/@earendil-works/pi-tui/dist/components/truncated-text.js.map +0 -1
  248. package/node_modules/@earendil-works/pi-tui/dist/editor-component.d.ts +0 -39
  249. package/node_modules/@earendil-works/pi-tui/dist/editor-component.d.ts.map +0 -1
  250. package/node_modules/@earendil-works/pi-tui/dist/editor-component.js +0 -2
  251. package/node_modules/@earendil-works/pi-tui/dist/editor-component.js.map +0 -1
  252. package/node_modules/@earendil-works/pi-tui/dist/fuzzy.d.ts +0 -16
  253. package/node_modules/@earendil-works/pi-tui/dist/fuzzy.d.ts.map +0 -1
  254. package/node_modules/@earendil-works/pi-tui/dist/fuzzy.js +0 -110
  255. package/node_modules/@earendil-works/pi-tui/dist/fuzzy.js.map +0 -1
  256. package/node_modules/@earendil-works/pi-tui/dist/index.d.ts +0 -23
  257. package/node_modules/@earendil-works/pi-tui/dist/index.d.ts.map +0 -1
  258. package/node_modules/@earendil-works/pi-tui/dist/index.js +0 -32
  259. package/node_modules/@earendil-works/pi-tui/dist/index.js.map +0 -1
  260. package/node_modules/@earendil-works/pi-tui/dist/keybindings.d.ts +0 -193
  261. package/node_modules/@earendil-works/pi-tui/dist/keybindings.d.ts.map +0 -1
  262. package/node_modules/@earendil-works/pi-tui/dist/keybindings.js +0 -174
  263. package/node_modules/@earendil-works/pi-tui/dist/keybindings.js.map +0 -1
  264. package/node_modules/@earendil-works/pi-tui/dist/keys.d.ts +0 -184
  265. package/node_modules/@earendil-works/pi-tui/dist/keys.d.ts.map +0 -1
  266. package/node_modules/@earendil-works/pi-tui/dist/keys.js +0 -1173
  267. package/node_modules/@earendil-works/pi-tui/dist/keys.js.map +0 -1
  268. package/node_modules/@earendil-works/pi-tui/dist/kill-ring.d.ts +0 -28
  269. package/node_modules/@earendil-works/pi-tui/dist/kill-ring.d.ts.map +0 -1
  270. package/node_modules/@earendil-works/pi-tui/dist/kill-ring.js +0 -44
  271. package/node_modules/@earendil-works/pi-tui/dist/kill-ring.js.map +0 -1
  272. package/node_modules/@earendil-works/pi-tui/dist/native-modifiers.d.ts +0 -3
  273. package/node_modules/@earendil-works/pi-tui/dist/native-modifiers.d.ts.map +0 -1
  274. package/node_modules/@earendil-works/pi-tui/dist/native-modifiers.js +0 -53
  275. package/node_modules/@earendil-works/pi-tui/dist/native-modifiers.js.map +0 -1
  276. package/node_modules/@earendil-works/pi-tui/dist/stdin-buffer.d.ts +0 -50
  277. package/node_modules/@earendil-works/pi-tui/dist/stdin-buffer.d.ts.map +0 -1
  278. package/node_modules/@earendil-works/pi-tui/dist/stdin-buffer.js +0 -361
  279. package/node_modules/@earendil-works/pi-tui/dist/stdin-buffer.js.map +0 -1
  280. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.d.ts +0 -90
  281. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.d.ts.map +0 -1
  282. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js +0 -366
  283. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js.map +0 -1
  284. package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts +0 -113
  285. package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts.map +0 -1
  286. package/node_modules/@earendil-works/pi-tui/dist/terminal.js +0 -472
  287. package/node_modules/@earendil-works/pi-tui/dist/terminal.js.map +0 -1
  288. package/node_modules/@earendil-works/pi-tui/dist/tui.d.ts +0 -227
  289. package/node_modules/@earendil-works/pi-tui/dist/tui.d.ts.map +0 -1
  290. package/node_modules/@earendil-works/pi-tui/dist/tui.js +0 -1106
  291. package/node_modules/@earendil-works/pi-tui/dist/tui.js.map +0 -1
  292. package/node_modules/@earendil-works/pi-tui/dist/undo-stack.d.ts +0 -17
  293. package/node_modules/@earendil-works/pi-tui/dist/undo-stack.d.ts.map +0 -1
  294. package/node_modules/@earendil-works/pi-tui/dist/undo-stack.js +0 -25
  295. package/node_modules/@earendil-works/pi-tui/dist/undo-stack.js.map +0 -1
  296. package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts +0 -84
  297. package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts.map +0 -1
  298. package/node_modules/@earendil-works/pi-tui/dist/utils.js +0 -1029
  299. package/node_modules/@earendil-works/pi-tui/dist/utils.js.map +0 -1
  300. package/node_modules/@earendil-works/pi-tui/dist/word-navigation.d.ts +0 -25
  301. package/node_modules/@earendil-works/pi-tui/dist/word-navigation.d.ts.map +0 -1
  302. package/node_modules/@earendil-works/pi-tui/dist/word-navigation.js +0 -96
  303. package/node_modules/@earendil-works/pi-tui/dist/word-navigation.js.map +0 -1
  304. package/node_modules/@earendil-works/pi-tui/native/darwin/prebuilds/darwin-arm64/darwin-modifiers.node +0 -0
  305. package/node_modules/@earendil-works/pi-tui/native/darwin/prebuilds/darwin-x64/darwin-modifiers.node +0 -0
  306. package/node_modules/@earendil-works/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
  307. package/node_modules/@earendil-works/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  308. package/node_modules/@earendil-works/pi-tui/package.json +0 -47
  309. package/node_modules/get-east-asian-width/index.d.ts +0 -60
  310. package/node_modules/get-east-asian-width/index.js +0 -30
  311. package/node_modules/get-east-asian-width/license +0 -9
  312. package/node_modules/get-east-asian-width/lookup-data.js +0 -21
  313. package/node_modules/get-east-asian-width/lookup.js +0 -138
  314. package/node_modules/get-east-asian-width/package.json +0 -71
  315. package/node_modules/get-east-asian-width/readme.md +0 -65
  316. package/node_modules/get-east-asian-width/utilities.js +0 -24
  317. package/node_modules/marked/LICENSE.md +0 -44
  318. package/node_modules/marked/README.md +0 -106
  319. package/node_modules/marked/bin/main.js +0 -282
  320. package/node_modules/marked/bin/marked.js +0 -15
  321. package/node_modules/marked/lib/marked.cjs +0 -2211
  322. package/node_modules/marked/lib/marked.cjs.map +0 -7
  323. package/node_modules/marked/lib/marked.d.cts +0 -728
  324. package/node_modules/marked/lib/marked.d.ts +0 -728
  325. package/node_modules/marked/lib/marked.esm.js +0 -2189
  326. package/node_modules/marked/lib/marked.esm.js.map +0 -7
  327. package/node_modules/marked/lib/marked.umd.js +0 -2213
  328. package/node_modules/marked/lib/marked.umd.js.map +0 -7
  329. package/node_modules/marked/man/marked.1 +0 -111
  330. package/node_modules/marked/man/marked.1.md +0 -92
  331. package/node_modules/marked/marked.min.js +0 -69
  332. package/node_modules/marked/package.json +0 -111
@@ -241,6 +241,59 @@ function lastAssistantTextFromMessages(messages: AgentSession["messages"]): stri
241
241
  return undefined;
242
242
  }
243
243
 
244
+ function messageStopReason(message: AgentSession["messages"][number]): string | undefined {
245
+ const record = message as { readonly stopReason?: unknown };
246
+ return typeof record.stopReason === "string" ? record.stopReason : undefined;
247
+ }
248
+
249
+ function normalizedStopReason(stopReason: string | undefined): string | undefined {
250
+ return stopReason?.toLowerCase().replace(/[_-]+/g, "");
251
+ }
252
+
253
+ function isTerminalAssistantFailureStopReason(stopReason: string | undefined): boolean {
254
+ const normalized = normalizedStopReason(stopReason);
255
+ return normalized === "error" || normalized === "aborted";
256
+ }
257
+
258
+ function isCleanAssistantStopReason(stopReason: string | undefined): boolean {
259
+ const normalized = normalizedStopReason(stopReason);
260
+ return normalized === "stop" || normalized === "tooluse" || normalized === "length";
261
+ }
262
+
263
+ function assistantErrorMessage(message: AgentSession["messages"][number]): string | undefined {
264
+ const record = message as { readonly errorMessage?: unknown };
265
+ return typeof record.errorMessage === "string" && record.errorMessage.trim().length > 0
266
+ ? record.errorMessage
267
+ : undefined;
268
+ }
269
+
270
+ function latestTerminalAssistantFailureSince(
271
+ messages: AgentSession["messages"],
272
+ startIndex: number,
273
+ ): AgentSession["messages"][number] | undefined {
274
+ for (let index = messages.length - 1; index >= startIndex; index -= 1) {
275
+ const message = messages[index];
276
+ if (!message || message.role !== "assistant") continue;
277
+ const stopReason = messageStopReason(message);
278
+ if (isTerminalAssistantFailureStopReason(stopReason)) return message;
279
+ if (isCleanAssistantStopReason(stopReason)) return undefined;
280
+ if (assistantErrorMessage(message) === undefined && extractMessageText(message).trim().length > 0) {
281
+ return undefined;
282
+ }
283
+ }
284
+ return undefined;
285
+ }
286
+
287
+ class WorkflowPromptModelFailure extends Error {
288
+ override readonly cause: unknown;
289
+
290
+ constructor(cause: unknown) {
291
+ super(errorMessage(cause));
292
+ this.name = "WorkflowPromptModelFailure";
293
+ this.cause = cause;
294
+ }
295
+ }
296
+
244
297
  /**
245
298
  * When an agent turn ends on a tool that returned `terminate: true`, control
246
299
  * returns with the tool result as the final conversational message and no
@@ -285,6 +338,57 @@ function terminatingToolResultText(
285
338
  return undefined;
286
339
  }
287
340
 
341
+ /**
342
+ * A stage session backed by a real Atomic `AgentSession` exposes its
343
+ * `extensionRunner`. When workflow wiring binds extensions to a stage session it
344
+ * replays the `session_start` lifecycle (see wiring.ts `bindExtensions`), so
345
+ * extensions such as MCP begin per-session initialization. Tearing that session
346
+ * down with `dispose()` alone invalidates the extension runtime WITHOUT emitting
347
+ * `session_shutdown`, so those extensions never receive a graceful teardown
348
+ * signal: MCP, for example, logs a spurious stale-context "initialization
349
+ * failed" error when its deferred init races with disposal, and leaves any child
350
+ * MCP servers running.
351
+ *
352
+ * The test stub session (createTestAgentSession) has no `extensionRunner`, so the
353
+ * capability is optional and feature-detected at runtime.
354
+ */
355
+ type StageSessionExtensionRunner = {
356
+ hasHandlers(eventType: string): boolean;
357
+ emit(event: { readonly type: "session_shutdown"; readonly reason: "quit" }): Promise<unknown>;
358
+ };
359
+
360
+ function stageSessionExtensionRunner(
361
+ current: StageSessionRuntime,
362
+ ): StageSessionExtensionRunner | undefined {
363
+ const runner = (current as StageSessionRuntime & { extensionRunner?: StageSessionExtensionRunner })
364
+ .extensionRunner;
365
+ if (runner && typeof runner.hasHandlers === "function" && typeof runner.emit === "function") {
366
+ return runner;
367
+ }
368
+ return undefined;
369
+ }
370
+
371
+ /**
372
+ * Dispose a stage session, mirroring the host `AgentSessionRuntime` teardown:
373
+ * emit `session_shutdown` before `dispose()` whenever the session exposes a
374
+ * compatible extension runner, so extensions tear down per-session resources
375
+ * (and bump their lifecycle generation) instead of being silently invalidated.
376
+ * A throwing shutdown handler must never strand the session, so disposal always
377
+ * runs.
378
+ */
379
+ async function disposeStageSession(current: StageSessionRuntime | undefined): Promise<void> {
380
+ if (!current) return;
381
+ const runner = stageSessionExtensionRunner(current);
382
+ if (runner?.hasHandlers("session_shutdown")) {
383
+ try {
384
+ await runner.emit({ type: "session_shutdown", reason: "quit" });
385
+ } catch (error) {
386
+ console.error("atomic-workflows: stage session_shutdown handler failed", error);
387
+ }
388
+ }
389
+ await current.dispose();
390
+ }
391
+
288
392
  function asAgentSession(activeSession: StageSessionRuntime | undefined): AgentSession | undefined {
289
393
  if (!activeSession) return undefined;
290
394
  const candidate = activeSession as StageSessionRuntime & Partial<Pick<AgentSession, "state" | "sessionManager" | "modelRegistry" | "getContextUsage">>;
@@ -535,6 +639,7 @@ export function createStageContext(opts: StageRunnerOpts): InternalStageContext
535
639
  let selectedModel: string | undefined;
536
640
  const modelAttempts: WorkflowModelAttempt[] = [];
537
641
  const modelWarnings: string[] = [];
642
+ const pendingFallbackWarnings: string[] = [];
538
643
  const modelCatalog = opts.models === undefined
539
644
  ? undefined
540
645
  : {
@@ -675,14 +780,14 @@ export function createStageContext(opts: StageRunnerOpts): InternalStageContext
675
780
  unsubscribeTerminateWatcher?.();
676
781
  unsubscribeTerminateWatcher = undefined;
677
782
  terminatingToolCallIds.clear();
678
- await current?.dispose();
783
+ await disposeStageSession(current);
679
784
  }
680
785
 
681
786
  async function promptWithPauseResume(
682
787
  activeSession: StageSessionRuntime,
683
788
  initialText: string,
684
789
  sdkOptions: PromptOptions | undefined,
685
- ): Promise<void> {
790
+ ): Promise<{ readonly terminalScanStartIndex: number }> {
686
791
  // Pause/resume loop: when a controlled pause aborts the SDK call,
687
792
  // swallow the resulting abort, suspend on `pauseRequest.deferred`,
688
793
  // and either re-issue with the user's resume message or return the
@@ -693,28 +798,32 @@ export function createStageContext(opts: StageRunnerOpts): InternalStageContext
693
798
  if (pendingPauseBeforePrompt) {
694
799
  const { message } = await pendingPauseBeforePrompt.deferred.promise;
695
800
  nextText = message;
696
- if (nextText === undefined) return;
801
+ if (nextText === undefined) return { terminalScanStartIndex: activeSession.messages.length };
697
802
  continue;
698
803
  }
804
+ const promptStartIndex = activeSession.messages.length;
699
805
  try {
700
806
  await activeSession.prompt(nextText, sdkOptions);
701
807
  const pendingPauseAfterPrompt = pauseRequest;
702
808
  if (pendingPauseAfterPrompt) {
703
809
  const { message } = await pendingPauseAfterPrompt.deferred.promise;
704
810
  nextText = message;
705
- if (nextText === undefined) return;
811
+ if (nextText === undefined) return { terminalScanStartIndex: activeSession.messages.length };
706
812
  continue;
707
813
  }
708
- nextText = undefined;
814
+ return { terminalScanStartIndex: promptStartIndex };
709
815
  } catch (err) {
710
- if (pauseRequest) {
711
- const { message } = await pauseRequest.deferred.promise;
816
+ const pendingPauseAfterThrow = pauseRequest;
817
+ if (pendingPauseAfterThrow) {
818
+ const { message } = await pendingPauseAfterThrow.deferred.promise;
712
819
  nextText = message;
820
+ if (nextText === undefined) return { terminalScanStartIndex: activeSession.messages.length };
713
821
  continue;
714
822
  }
715
823
  throw err;
716
824
  }
717
825
  }
826
+ return { terminalScanStartIndex: activeSession.messages.length };
718
827
  }
719
828
 
720
829
  async function promptWithFallback(
@@ -743,17 +852,25 @@ export function createStageContext(opts: StageRunnerOpts): InternalStageContext
743
852
  selectedModel = candidate.id;
744
853
  notifyModelFallbackMetaChange();
745
854
  try {
746
- await promptWithPauseResume(activeSession, text, sdkOptions);
855
+ const { terminalScanStartIndex } = await promptWithPauseResume(activeSession, text, sdkOptions);
856
+ const terminalFailure = latestTerminalAssistantFailureSince(activeSession.messages, terminalScanStartIndex);
857
+ if (terminalFailure !== undefined) {
858
+ throw new WorkflowPromptModelFailure(terminalFailure);
859
+ }
747
860
  modelAttempts.push({ model: candidate.id, success: true, ...modelAttemptReasoning(candidate) });
861
+ pendingFallbackWarnings.length = 0;
748
862
  return;
749
863
  } catch (err) {
750
864
  const message = errorMessage(err);
751
865
  modelAttempts.push({ model: candidate.id, success: false, ...modelAttemptReasoning(candidate), error: message });
752
- if (signal?.aborted || !isRetryableModelFailure(message) || index === candidates.length - 1) {
866
+ if (signal?.aborted || !isRetryableModelFailure(err) || index === candidates.length - 1) {
867
+ modelWarnings.push(...pendingFallbackWarnings);
868
+ pendingFallbackWarnings.length = 0;
869
+ notifyModelFallbackMetaChange();
753
870
  throw err;
754
871
  }
755
872
  const nextCandidate = candidates[index + 1]!;
756
- modelWarnings.push(`[fallback] ${candidateLabel(candidate)} failed: ${message}. Retrying with ${candidateLabel(nextCandidate)}.`);
873
+ pendingFallbackWarnings.push(`[fallback] ${candidateLabel(candidate)} failed: ${message}. Retrying with ${candidateLabel(nextCandidate)}.`);
757
874
  await disposeCurrentSession();
758
875
  index += 1;
759
876
  }
@@ -875,8 +992,8 @@ export function createStageContext(opts: StageRunnerOpts): InternalStageContext
875
992
  return (await ensureSession()).navigateTree(targetId, options);
876
993
  },
877
994
 
878
- async compact(customInstructions) {
879
- return (await ensureSession()).compact(customInstructions);
995
+ async compact() {
996
+ return (await ensureSession()).compact();
880
997
  },
881
998
 
882
999
  abortCompaction() {
@@ -895,7 +1012,7 @@ export function createStageContext(opts: StageRunnerOpts): InternalStageContext
895
1012
  unsubscribeTerminateWatcher?.();
896
1013
  unsubscribeTerminateWatcher = undefined;
897
1014
  terminatingToolCallIds.clear();
898
- await session?.dispose();
1015
+ await disposeStageSession(session);
899
1016
  },
900
1017
 
901
1018
  __getLastAssistantText() {
@@ -313,9 +313,12 @@ const RETRYABLE_MODEL_FAILURE_PATTERNS: readonly RegExp[] = [
313
313
  /billing/i,
314
314
  /credit/i,
315
315
  /auth(?:entication|orization)?/i,
316
+ /unauthori[sz]ed/i,
317
+ /\b40[13]\b/,
316
318
  /api\s*key/i,
317
319
  /token\s*expired/i,
318
320
  /forbidden/i,
321
+ /invalid\s*key/i,
319
322
  /model.*(?:unavailable|disabled|not\s*found|unknown)/i,
320
323
  /(?:unavailable|disabled|not\s*found|unknown).*model/i,
321
324
  /overloaded/i,
@@ -324,10 +327,11 @@ const RETRYABLE_MODEL_FAILURE_PATTERNS: readonly RegExp[] = [
324
327
  /network/i,
325
328
  /fetch/i,
326
329
  /socket/i,
330
+ /connection\s*refused/i,
327
331
  /upstream/i,
328
332
  /timeout/i,
329
333
  /timed\s*out/i,
330
- /\b50[234]\b/,
334
+ /\b50[0-4]\b/,
331
335
  ];
332
336
 
333
337
  const NON_RETRYABLE_FAILURE_PATTERNS: readonly RegExp[] = [
@@ -342,15 +346,405 @@ const NON_RETRYABLE_FAILURE_PATTERNS: readonly RegExp[] = [
342
346
  /interrupted/i,
343
347
  ];
344
348
 
349
+ const CANCELLED_FAILURE_PATTERNS: readonly RegExp[] = [
350
+ /cancel/i,
351
+ /abort/i,
352
+ /interrupted/i,
353
+ ];
354
+
355
+ export type ModelFallbackFailureKind =
356
+ | "auth_on_candidate_provider"
357
+ | "rate_limit"
358
+ | "provider_unavailable"
359
+ | "network_timeout"
360
+ | "model_unavailable"
361
+ | "cancelled"
362
+ | "task_failure"
363
+ | "unknown";
364
+
365
+ export type ModelFallbackFailureSource =
366
+ | "assistant_message"
367
+ | "diagnostic"
368
+ | "throw"
369
+ | "structured"
370
+ | "string_fallback";
371
+
372
+ export interface ModelFallbackFailureSignal {
373
+ readonly kind: ModelFallbackFailureKind;
374
+ readonly message: string;
375
+ readonly source: ModelFallbackFailureSource;
376
+ readonly stopReason?: string;
377
+ readonly status?: number;
378
+ readonly code?: string | number;
379
+ readonly name?: string;
380
+ }
381
+
382
+ const FALLBACKABLE_FAILURE_KINDS: ReadonlySet<ModelFallbackFailureKind> = new Set([
383
+ "auth_on_candidate_provider",
384
+ "rate_limit",
385
+ "provider_unavailable",
386
+ "network_timeout",
387
+ "model_unavailable",
388
+ ]);
389
+
390
+ function asRecord(value: unknown): Record<string, unknown> | undefined {
391
+ return value !== null && typeof value === "object" ? value as Record<string, unknown> : undefined;
392
+ }
393
+
394
+ function field(value: unknown, key: string): unknown {
395
+ return asRecord(value)?.[key];
396
+ }
397
+
398
+ function stringField(value: unknown, key: string): string | undefined {
399
+ const raw = field(value, key);
400
+ return typeof raw === "string" && raw.trim().length > 0 ? raw : undefined;
401
+ }
402
+
403
+ function errorName(value: unknown): string | undefined {
404
+ return value instanceof Error ? value.name : stringField(value, "name");
405
+ }
406
+
407
+ function directMessageFrom(value: unknown): string | undefined {
408
+ return stringField(value, "errorMessage")
409
+ ?? stringField(value, "message")
410
+ ?? stringField(value, "statusText");
411
+ }
412
+
413
+ function integerFrom(value: unknown): number | undefined {
414
+ if (typeof value === "number" && Number.isInteger(value)) return value;
415
+ if (typeof value !== "string" || value.trim().length === 0) return undefined;
416
+ const parsed = Number(value.trim());
417
+ return Number.isInteger(parsed) ? parsed : undefined;
418
+ }
419
+
420
+ function statusFrom(value: unknown): number | undefined {
421
+ return integerFrom(field(value, "status"))
422
+ ?? integerFrom(field(value, "statusCode"))
423
+ ?? integerFrom(field(value, "httpStatus"));
424
+ }
425
+
426
+ function codeFrom(value: unknown): string | number | undefined {
427
+ const rawCode = field(value, "code");
428
+ return typeof rawCode === "string" || typeof rawCode === "number" ? rawCode : undefined;
429
+ }
430
+
431
+ function stopReasonFrom(value: unknown): string | undefined {
432
+ return stringField(value, "stopReason");
433
+ }
434
+
435
+ function finishReasonFrom(value: unknown): string | undefined {
436
+ return stringField(value, "finish_reason") ?? stringField(value, "finishReason");
437
+ }
438
+
439
+ function causeOf(value: unknown): unknown {
440
+ return value instanceof Error ? value.cause : field(value, "cause");
441
+ }
442
+
443
+ function diagnosticErrors(value: unknown): readonly unknown[] {
444
+ const diagnostics = field(value, "diagnostics");
445
+ if (!Array.isArray(diagnostics)) return [];
446
+ const errors: unknown[] = [];
447
+ for (const diagnostic of diagnostics) {
448
+ const diagnosticError = field(diagnostic, "error");
449
+ errors.push(diagnosticError ?? diagnostic);
450
+ }
451
+ return errors;
452
+ }
453
+
454
+ function normalizeCode(value: string | number | undefined): string | undefined {
455
+ if (value === undefined) return undefined;
456
+ const normalized = String(value)
457
+ .trim()
458
+ .toLowerCase()
459
+ .replace(/[^a-z0-9]+/g, "_")
460
+ .replace(/^_+|_+$/g, "");
461
+ return normalized.length > 0 ? normalized : undefined;
462
+ }
463
+
464
+ function kindFromStatus(status: number | undefined): ModelFallbackFailureKind | undefined {
465
+ switch (status) {
466
+ case 401:
467
+ case 403:
468
+ return "auth_on_candidate_provider";
469
+ case 408:
470
+ return "network_timeout";
471
+ case 404:
472
+ return "model_unavailable";
473
+ case 429:
474
+ return "rate_limit";
475
+ default:
476
+ if (status !== undefined && status >= 500 && status <= 599) return "provider_unavailable";
477
+ return undefined;
478
+ }
479
+ }
480
+
481
+ function refusalKindFromCode(code: string | number | undefined): ModelFallbackFailureKind | undefined {
482
+ const normalizedCode = normalizeCode(code);
483
+ if (normalizedCode === undefined) return undefined;
484
+ if (normalizedCode.includes("content_filter") || normalizedCode.includes("contentfilter")) return "task_failure";
485
+ if (normalizedCode.includes("safety") || normalizedCode.includes("policy")) return "task_failure";
486
+ switch (normalizedCode) {
487
+ case "blocked":
488
+ case "blocked_by_provider":
489
+ case "blocked_by_safety":
490
+ case "blocked_by_policy":
491
+ case "provider_refusal":
492
+ case "refusal":
493
+ case "tool_refusal":
494
+ case "tool_call_refusal":
495
+ case "tool_use_refusal":
496
+ return "task_failure";
497
+ default:
498
+ return undefined;
499
+ }
500
+ }
501
+
502
+ function kindFromCode(code: string | number | undefined): ModelFallbackFailureKind | undefined {
503
+ const normalizedCode = normalizeCode(code);
504
+ if (normalizedCode === undefined) return undefined;
505
+ const refusalKind = refusalKindFromCode(code);
506
+ if (refusalKind !== undefined) return refusalKind;
507
+ const httpStatusKind = kindFromStatus(integerFrom(code));
508
+ if (httpStatusKind !== undefined) return httpStatusKind;
509
+
510
+ switch (normalizedCode) {
511
+ case "auth":
512
+ case "auth_required":
513
+ case "authentication_required":
514
+ case "unauthorized":
515
+ case "forbidden":
516
+ case "invalid_api_key":
517
+ case "missing_api_key":
518
+ case "invalid_key":
519
+ return "auth_on_candidate_provider";
520
+ case "etimedout":
521
+ case "econnreset":
522
+ case "econnrefused":
523
+ case "enotfound":
524
+ case "eai_again":
525
+ case "fetch_failed":
526
+ case "network_error":
527
+ case "timeout":
528
+ case "timeout_error":
529
+ case "und_err_connect_timeout":
530
+ return "network_timeout";
531
+ case "rate_limit":
532
+ case "rate_limit_exceeded":
533
+ case "too_many_requests":
534
+ case "quota_exceeded":
535
+ return "rate_limit";
536
+ case "aborterror":
537
+ case "aborted":
538
+ case "cancelled":
539
+ case "canceled":
540
+ return "cancelled";
541
+ case "model_not_found":
542
+ case "model_unavailable":
543
+ case "model_disabled":
544
+ case "unknown_model":
545
+ return "model_unavailable";
546
+ case "provider_error":
547
+ case "api_error":
548
+ case "service_unavailable":
549
+ case "temporarily_unavailable":
550
+ case "overloaded":
551
+ return "provider_unavailable";
552
+ default:
553
+ return undefined;
554
+ }
555
+ }
556
+
557
+ const PROVIDER_REFUSAL_FAILURE_PATTERNS: readonly RegExp[] = [
558
+ /\bfinish[_\s-]?reason\b[^\n]*\bcontent[_\s-]?filter\b/i,
559
+ /\bcontent[_\s-]?filter(?:ed|ing)?\b/i,
560
+ /\b(?:safety|policy)\b[^\n]*\b(?:refus(?:e|al|ed|es|ing)?|block(?:ed|ing)?|filter(?:ed|ing)?|violat(?:e|ion|ed|ing)?|disallow(?:ed|ing)?|reject(?:ed|ion|ing)?)\b/i,
561
+ /\b(?:refus(?:e|al|ed|es|ing)?|block(?:ed|ing)?|filter(?:ed|ing)?|violat(?:e|ion|ed|ing)?|disallow(?:ed|ing)?|reject(?:ed|ion|ing)?)\b[^\n]*\b(?:safety|policy)\b/i,
562
+ /\btool[_\s-]?(?:call|use)?[_\s-]?refus(?:e|al|ed|es|ing)?\b/i,
563
+ /\btool(?:\s+call|\s+use)?\b[^\n]*\brefus(?:e|al|ed|es|ing)?\b/i,
564
+ /\brefus(?:e|al|ed|es|ing)?\b[^\n]*\btool(?:\s+call|\s+use)?\b/i,
565
+ /\bprovider[_\s-]?refus(?:e|al|ed|es|ing)?\b/i,
566
+ /\bprovider\b[^\n]*\brefus(?:e|al|ed|es|ing)?\b[^\n]*\b(?:prompt|request|content|policy|safety)\b/i,
567
+ ];
568
+
569
+ function refusalKindFromMessage(message: string): ModelFallbackFailureKind | undefined {
570
+ if (CANCELLED_FAILURE_PATTERNS.some((pattern) => pattern.test(message))) return "cancelled";
571
+ if (NON_RETRYABLE_FAILURE_PATTERNS.some((pattern) => pattern.test(message))) return "task_failure";
572
+ if (PROVIDER_REFUSAL_FAILURE_PATTERNS.some((pattern) => pattern.test(message))) return "task_failure";
573
+ return undefined;
574
+ }
575
+
576
+ function fallbackKindFromMessage(message: string, name: string | undefined): ModelFallbackFailureKind | undefined {
577
+ const refusalKind = refusalKindFromMessage(message);
578
+ if (refusalKind !== undefined) return refusalKind;
579
+ const nameKind = kindFromCode(name);
580
+ if (nameKind !== undefined) return nameKind;
581
+ if (!RETRYABLE_MODEL_FAILURE_PATTERNS.some((pattern) => pattern.test(message))) return undefined;
582
+ if (/rate\s*limit|too\s*many\s*requests|\b429\b|quota|billing|credit/i.test(message)) return "rate_limit";
583
+ if (/auth|unauthori[sz]ed|\b40[13]\b|api\s*key|token\s*expired|forbidden|invalid\s*key/i.test(message)) return "auth_on_candidate_provider";
584
+ if (/model.*(?:unavailable|disabled|not\s*found|unknown)|(?:unavailable|disabled|not\s*found|unknown).*model/i.test(message)) return "model_unavailable";
585
+ if (/network|fetch|socket|connection\s*refused|timeout|timed\s*out/i.test(message)) return "network_timeout";
586
+ return "provider_unavailable";
587
+ }
588
+
589
+ function signalSource(value: unknown, fallback: ModelFallbackFailureSource | undefined): ModelFallbackFailureSource {
590
+ if (fallback !== undefined) return fallback;
591
+ if (stopReasonFrom(value) !== undefined || diagnosticErrors(value).length > 0) return "assistant_message";
592
+ if (value instanceof Error) return "throw";
593
+ return "structured";
594
+ }
595
+
596
+ function makeSignal(
597
+ kind: ModelFallbackFailureKind,
598
+ value: unknown,
599
+ source: ModelFallbackFailureSource | undefined,
600
+ ): ModelFallbackFailureSignal {
601
+ const status = statusFrom(value);
602
+ const code = codeFrom(value);
603
+ const name = errorName(value);
604
+ const stopReason = stopReasonFrom(value);
605
+ return {
606
+ kind,
607
+ message: errorMessage(value),
608
+ source: signalSource(value, source),
609
+ ...(stopReason !== undefined ? { stopReason } : {}),
610
+ ...(status !== undefined ? { status } : {}),
611
+ ...(code !== undefined ? { code } : {}),
612
+ ...(name !== undefined ? { name } : {}),
613
+ };
614
+ }
615
+
616
+ function fallbackSignalFromMessage(
617
+ value: unknown,
618
+ source: ModelFallbackFailureSource | undefined,
619
+ ): ModelFallbackFailureSignal | undefined {
620
+ const message = errorMessage(value);
621
+ if (!message.trim()) return undefined;
622
+ const kind = fallbackKindFromMessage(message, errorName(value));
623
+ return kind === undefined ? undefined : makeSignal(kind, value, source);
624
+ }
625
+
626
+ function classifyAssistantRefusalSignal(
627
+ value: unknown,
628
+ source: ModelFallbackFailureSource | undefined,
629
+ ): ModelFallbackFailureSignal | undefined {
630
+ const codeRefusalKind = refusalKindFromCode(codeFrom(value))
631
+ ?? refusalKindFromCode(errorName(value))
632
+ ?? refusalKindFromCode(finishReasonFrom(value));
633
+ if (codeRefusalKind !== undefined) return makeSignal(codeRefusalKind, value, source);
634
+
635
+ const messageRefusalKind = refusalKindFromMessage(directMessageFrom(value) ?? "");
636
+ return messageRefusalKind === undefined ? undefined : makeSignal(messageRefusalKind, value, source);
637
+ }
638
+
639
+ function isRefusalSignal(signal: ModelFallbackFailureSignal): boolean {
640
+ return signal.kind === "cancelled" || signal.kind === "task_failure";
641
+ }
642
+
643
+ function structuredSignal(
644
+ value: unknown,
645
+ seen: Set<unknown>,
646
+ source?: ModelFallbackFailureSource,
647
+ ): ModelFallbackFailureSignal | undefined {
648
+ if (value === undefined || value === null || seen.has(value)) return undefined;
649
+ if (typeof value === "object") seen.add(value);
650
+
651
+ const stopReason = stopReasonFrom(value)?.toLowerCase();
652
+ if (stopReason === "aborted") return makeSignal("cancelled", value, source);
653
+
654
+ const directRefusalSignal = classifyAssistantRefusalSignal(value, source);
655
+ if (directRefusalSignal !== undefined) return directRefusalSignal;
656
+
657
+ const codeKind = kindFromCode(codeFrom(value));
658
+ const nameKind = kindFromCode(errorName(value));
659
+ if (codeKind === "cancelled" || nameKind === "cancelled") return makeSignal("cancelled", value, source);
660
+
661
+ let firstNestedFallbackSignal: ModelFallbackFailureSignal | undefined;
662
+ const nestedSeen = new Set(seen);
663
+ for (const diagnosticError of diagnosticErrors(value)) {
664
+ const diagnosticSignal = structuredSignal(diagnosticError, nestedSeen, "diagnostic")
665
+ ?? fallbackSignalFromMessage(diagnosticError, "diagnostic");
666
+ if (diagnosticSignal === undefined) continue;
667
+ if (isRefusalSignal(diagnosticSignal)) return diagnosticSignal;
668
+ firstNestedFallbackSignal ??= diagnosticSignal;
669
+ }
670
+
671
+ const cause = causeOf(value);
672
+ const causeSignal = structuredSignal(cause, nestedSeen, source)
673
+ ?? fallbackSignalFromMessage(cause, source);
674
+ if (causeSignal !== undefined) {
675
+ if (isRefusalSignal(causeSignal)) return causeSignal;
676
+ firstNestedFallbackSignal ??= causeSignal;
677
+ }
678
+
679
+ const statusKind = kindFromStatus(statusFrom(value));
680
+ if (statusKind !== undefined) return makeSignal(statusKind, value, source);
681
+ if (codeKind !== undefined) return makeSignal(codeKind, value, source);
682
+ if (nameKind !== undefined) return makeSignal(nameKind, value, source);
683
+
684
+ if (firstNestedFallbackSignal !== undefined) return firstNestedFallbackSignal;
685
+
686
+ if (stopReason === "error") return makeSignal("provider_unavailable", value, source);
687
+
688
+ return undefined;
689
+ }
690
+
691
+ function messageFromUnknown(value: unknown, seen: Set<unknown>): string | undefined {
692
+ if (value === undefined || value === null || seen.has(value)) return undefined;
693
+ if (typeof value === "string") return value.trim().length > 0 ? value : undefined;
694
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
695
+ if (typeof value === "symbol" || typeof value === "function") return undefined;
696
+ seen.add(value);
697
+
698
+ if (value instanceof Error && value.message.trim().length > 0) return value.message;
699
+ const directMessage = directMessageFrom(value);
700
+ if (directMessage !== undefined) return directMessage;
701
+
702
+ for (const diagnosticError of diagnosticErrors(value)) {
703
+ const diagnosticMessage = messageFromUnknown(diagnosticError, seen);
704
+ if (diagnosticMessage !== undefined) return diagnosticMessage;
705
+ }
706
+
707
+ const causeMessage = messageFromUnknown(causeOf(value), seen);
708
+ if (causeMessage !== undefined) return causeMessage;
709
+
710
+ const stopReason = stopReasonFrom(value);
711
+ if (stopReason !== undefined) return `Assistant message ended with stopReason:${stopReason}`;
712
+ const finishReason = finishReasonFrom(value);
713
+ if (finishReason !== undefined) return `Model request finished with finish_reason:${finishReason}`;
714
+ const status = statusFrom(value);
715
+ if (status !== undefined) return `Model request failed with status ${status}`;
716
+ const code = codeFrom(value);
717
+ if (code !== undefined) return `Model request failed with code ${String(code)}`;
718
+
719
+ return undefined;
720
+ }
721
+
345
722
  export function errorMessage(error: unknown): string {
346
- if (error instanceof Error) return error.message;
347
- return String(error);
723
+ const structuredMessage = messageFromUnknown(error, new Set());
724
+ if (structuredMessage !== undefined) return structuredMessage;
725
+ const rendered = String(error);
726
+ return rendered === "[object Object]" ? "Model request failed" : rendered;
727
+ }
728
+
729
+ export function normalizeModelFailureSignal(error: unknown): ModelFallbackFailureSignal {
730
+ const structured = structuredSignal(error, new Set());
731
+ if (structured !== undefined) return structured;
732
+
733
+ const message = errorMessage(error);
734
+ const name = errorName(error);
735
+ const fallbackKind = message.trim().length > 0
736
+ ? fallbackKindFromMessage(message, name)
737
+ : undefined;
738
+ return {
739
+ kind: fallbackKind ?? "unknown",
740
+ message,
741
+ source: "string_fallback",
742
+ ...(name !== undefined ? { name } : {}),
743
+ };
348
744
  }
349
745
 
350
- export function isRetryableModelFailure(error: string | Error | undefined): boolean {
746
+ export function isRetryableModelFailure(error: unknown): boolean {
351
747
  if (error === undefined) return false;
352
- const message = typeof error === "string" ? error : error.message;
353
- if (!message.trim()) return false;
354
- if (NON_RETRYABLE_FAILURE_PATTERNS.some((pattern) => pattern.test(message))) return false;
355
- return RETRYABLE_MODEL_FAILURE_PATTERNS.some((pattern) => pattern.test(message));
748
+ const signal = normalizeModelFailureSignal(error);
749
+ return FALLBACKABLE_FAILURE_KINDS.has(signal.kind);
356
750
  }
@@ -2,7 +2,7 @@ import { spawnSync } from "node:child_process";
2
2
  import * as fs from "node:fs";
3
3
  import * as os from "node:os";
4
4
  import * as path from "node:path";
5
- import { APP_NAME } from "@bastani/atomic";
5
+ import { APP_NAME, createGitEnvironment } from "@bastani/atomic";
6
6
 
7
7
  export interface WorktreeSetup {
8
8
  cwd: string;
@@ -110,7 +110,7 @@ function runGit(cwd: string, args: string[]): GitResult {
110
110
  ], {
111
111
  cwd,
112
112
  encoding: "utf-8",
113
- env: { ...process.env, GIT_OPTIONAL_LOCKS: "0" },
113
+ env: createGitEnvironment({ GIT_OPTIONAL_LOCKS: "0" }),
114
114
  timeout: 5000,
115
115
  });
116
116
  return {