@bastani/atomic 0.9.18 → 0.9.19-alpha.2

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 (698) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/dist/builtin/intercom/CHANGELOG.md +16 -0
  3. package/dist/builtin/intercom/README.md +21 -11
  4. package/dist/builtin/intercom/broker/broker.ts +73 -9
  5. package/dist/builtin/intercom/broker/client.ts +4 -0
  6. package/dist/builtin/intercom/broker/framing.ts +5 -2
  7. package/dist/builtin/intercom/broker/group-membership.ts +4 -2
  8. package/dist/builtin/intercom/broker/presence-handler.ts +14 -0
  9. package/dist/builtin/intercom/broker/send-handler.ts +34 -5
  10. package/dist/builtin/intercom/broker/terminal-questions.ts +29 -0
  11. package/dist/builtin/intercom/index.bundle.mjs +936 -740
  12. package/dist/builtin/intercom/package.json +2 -2
  13. package/dist/builtin/intercom/recipient-purpose.ts +9 -0
  14. package/dist/builtin/intercom/recoverable-disconnect.ts +2 -3
  15. package/dist/builtin/intercom/retry-policy.ts +4 -2
  16. package/dist/builtin/intercom/skills/intercom/SKILL.md +5 -4
  17. package/dist/builtin/intercom/types.ts +16 -2
  18. package/dist/builtin/mcp/CHANGELOG.md +6 -0
  19. package/dist/builtin/mcp/README.md +2 -0
  20. package/dist/builtin/mcp/index.bundle.mjs +2201 -12000
  21. package/dist/builtin/mcp/package.json +2 -2
  22. package/dist/builtin/subagents/CHANGELOG.md +27 -0
  23. package/dist/builtin/subagents/README.md +33 -12
  24. package/dist/builtin/subagents/agents/code-simplifier.md +1 -1
  25. package/dist/builtin/subagents/agents/codebase-analyzer.md +1 -1
  26. package/dist/builtin/subagents/agents/codebase-locator.md +2 -2
  27. package/dist/builtin/subagents/agents/codebase-online-researcher.md +1 -1
  28. package/dist/builtin/subagents/agents/codebase-pattern-finder.md +2 -2
  29. package/dist/builtin/subagents/agents/codebase-research-analyzer.md +1 -1
  30. package/dist/builtin/subagents/agents/codebase-research-locator.md +2 -2
  31. package/dist/builtin/subagents/agents/debugger.md +1 -1
  32. package/dist/builtin/subagents/agents/worker.md +1 -1
  33. package/dist/builtin/subagents/package.json +2 -2
  34. package/dist/builtin/subagents/skills/herdr/LICENSE +201 -0
  35. package/dist/builtin/subagents/skills/herdr/SKILL.md +202 -0
  36. package/dist/builtin/subagents/skills/subagent/SKILL.md +14 -10
  37. package/dist/builtin/subagents/skills/tmux/SKILL.md +1 -1
  38. package/dist/builtin/subagents/src/extension/index.bundle.mjs +1284 -609
  39. package/dist/builtin/web-access/index.bundle.mjs +26280 -26274
  40. package/dist/builtin/web-access/package.json +2 -2
  41. package/dist/builtin/workflows/CHANGELOG.md +48 -0
  42. package/dist/builtin/workflows/README.md +1 -1
  43. package/dist/builtin/workflows/builtin/adversarial-verification.js +5 -7
  44. package/dist/builtin/workflows/builtin/{chunk-reqr3sr3.js → chunk-1kx4aggw.js} +22 -22
  45. package/dist/builtin/workflows/builtin/{chunk-42s7sw0b.js → chunk-62v3gg9f.js} +9 -9
  46. package/dist/builtin/workflows/builtin/{chunk-wgccch41.js → chunk-6w6cvk6b.js} +16 -16
  47. package/dist/builtin/workflows/builtin/{chunk-zbekjqew.js → chunk-a2kdsqn8.js} +4 -4
  48. package/dist/builtin/workflows/builtin/{chunk-ze5x3d1r.js → chunk-fg9esgkj.js} +7 -7
  49. package/dist/builtin/workflows/builtin/{chunk-n8h4yyew.js → chunk-g0csgs7w.js} +11 -11
  50. package/dist/builtin/workflows/builtin/{chunk-79fjkcvh.js → chunk-hbnwv56f.js} +17 -17
  51. package/dist/builtin/workflows/builtin/{chunk-ed4jfn5t.js → chunk-mygmtz6e.js} +43 -43
  52. package/dist/builtin/workflows/builtin/{chunk-7430zyas.js → chunk-p8jjwfg6.js} +1 -1
  53. package/dist/builtin/workflows/builtin/{chunk-hqpe2cyx.js → chunk-r9qq7xfj.js} +49 -49
  54. package/dist/builtin/workflows/builtin/{chunk-k3w87x8y.js → chunk-t6x2d78s.js} +10 -10
  55. package/dist/builtin/workflows/builtin/{chunk-6fqs7c01.js → chunk-z0d03ktm.js} +1 -1
  56. package/dist/builtin/workflows/builtin/{chunk-b0v2xab1.js → chunk-zggjyg5z.js} +221 -23
  57. package/dist/builtin/workflows/builtin/classify-and-act.js +5 -6
  58. package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +3 -4
  59. package/dist/builtin/workflows/builtin/generate-and-filter.js +5 -6
  60. package/dist/builtin/workflows/builtin/goal.js +7 -8
  61. package/dist/builtin/workflows/builtin/index.js +20 -22
  62. package/dist/builtin/workflows/builtin/loop-until-done.js +5 -6
  63. package/dist/builtin/workflows/builtin/open-claude-design.js +3 -3
  64. package/dist/builtin/workflows/builtin/ralph.js +7 -8
  65. package/dist/builtin/workflows/builtin/steering-context.js +3 -3
  66. package/dist/builtin/workflows/builtin/tournament.js +5 -7
  67. package/dist/builtin/workflows/package.json +2 -2
  68. package/dist/builtin/workflows/src/extension/index.bundle.mjs +56236 -25199
  69. package/dist/builtin/workflows/src/index.js +1217 -547
  70. package/dist/cli/config-selector.js.map +1 -1
  71. package/dist/cli/startup-ui.d.ts +1 -1
  72. package/dist/cli/startup-ui.js.map +1 -1
  73. package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
  74. package/dist/core/agent-session-auto-compaction.js +5 -4
  75. package/dist/core/agent-session-auto-compaction.js.map +1 -1
  76. package/dist/core/agent-session-bash.d.ts +1 -1
  77. package/dist/core/agent-session-bash.d.ts.map +1 -1
  78. package/dist/core/agent-session-bash.js +5 -1
  79. package/dist/core/agent-session-bash.js.map +1 -1
  80. package/dist/core/agent-session-compaction.d.ts +1 -1
  81. package/dist/core/agent-session-compaction.js.map +1 -1
  82. package/dist/core/agent-session-custom-message-commit.d.ts +1 -1
  83. package/dist/core/agent-session-custom-message-commit.js.map +1 -1
  84. package/dist/core/agent-session-delivery-forwarding.d.ts +1 -1
  85. package/dist/core/agent-session-delivery-forwarding.js.map +1 -1
  86. package/dist/core/agent-session-events.d.ts.map +1 -1
  87. package/dist/core/agent-session-events.js +5 -0
  88. package/dist/core/agent-session-events.js.map +1 -1
  89. package/dist/core/agent-session-export.d.ts +1 -1
  90. package/dist/core/agent-session-export.js.map +1 -1
  91. package/dist/core/agent-session-extension-bindings.d.ts +8 -1
  92. package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
  93. package/dist/core/agent-session-extension-bindings.js +45 -3
  94. package/dist/core/agent-session-extension-bindings.js.map +1 -1
  95. package/dist/core/agent-session-message-queue.d.ts +1 -1
  96. package/dist/core/agent-session-message-queue.js.map +1 -1
  97. package/dist/core/agent-session-methods.d.ts +14 -7
  98. package/dist/core/agent-session-methods.d.ts.map +1 -1
  99. package/dist/core/agent-session-methods.js.map +1 -1
  100. package/dist/core/agent-session-prompt.d.ts +2 -2
  101. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  102. package/dist/core/agent-session-prompt.js +22 -18
  103. package/dist/core/agent-session-prompt.js.map +1 -1
  104. package/dist/core/agent-session-runtime-auth.d.ts +1 -1
  105. package/dist/core/agent-session-runtime-auth.js.map +1 -1
  106. package/dist/core/agent-session-runtime.d.ts +13 -4
  107. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  108. package/dist/core/agent-session-runtime.js +27 -4
  109. package/dist/core/agent-session-runtime.js.map +1 -1
  110. package/dist/core/agent-session-services.d.ts +5 -1
  111. package/dist/core/agent-session-services.d.ts.map +1 -1
  112. package/dist/core/agent-session-services.js +44 -34
  113. package/dist/core/agent-session-services.js.map +1 -1
  114. package/dist/core/agent-session-state.d.ts +1 -1
  115. package/dist/core/agent-session-state.js.map +1 -1
  116. package/dist/core/agent-session-tasks.d.ts +9 -0
  117. package/dist/core/agent-session-tasks.d.ts.map +1 -0
  118. package/dist/core/agent-session-tasks.js +113 -0
  119. package/dist/core/agent-session-tasks.js.map +1 -0
  120. package/dist/core/agent-session-tool-registry.d.ts +1 -0
  121. package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
  122. package/dist/core/agent-session-tool-registry.js +30 -5
  123. package/dist/core/agent-session-tool-registry.js.map +1 -1
  124. package/dist/core/agent-session-tree.d.ts.map +1 -1
  125. package/dist/core/agent-session-tree.js +3 -0
  126. package/dist/core/agent-session-tree.js.map +1 -1
  127. package/dist/core/agent-session-types.d.ts +2 -2
  128. package/dist/core/agent-session-types.js.map +1 -1
  129. package/dist/core/agent-session.d.ts +4 -1
  130. package/dist/core/agent-session.d.ts.map +1 -1
  131. package/dist/core/agent-session.js +7 -1
  132. package/dist/core/agent-session.js.map +1 -1
  133. package/dist/core/bash-executor.d.ts +1 -1
  134. package/dist/core/bash-executor.js.map +1 -1
  135. package/dist/core/export-html/index.js.map +1 -1
  136. package/dist/core/export-html/tool-renderer.d.ts +1 -1
  137. package/dist/core/export-html/tool-renderer.js.map +1 -1
  138. package/dist/core/extension-session-state.js.map +1 -1
  139. package/dist/core/extensions/agent-events.d.ts +4 -4
  140. package/dist/core/extensions/agent-events.d.ts.map +1 -1
  141. package/dist/core/extensions/agent-events.js.map +1 -1
  142. package/dist/core/extensions/api-types.d.ts +8 -2
  143. package/dist/core/extensions/api-types.d.ts.map +1 -1
  144. package/dist/core/extensions/api-types.js.map +1 -1
  145. package/dist/core/extensions/context-types.d.ts +9 -0
  146. package/dist/core/extensions/context-types.d.ts.map +1 -1
  147. package/dist/core/extensions/context-types.js.map +1 -1
  148. package/dist/core/extensions/event-results.d.ts +1 -1
  149. package/dist/core/extensions/event-results.js.map +1 -1
  150. package/dist/core/extensions/event-types.d.ts +2 -1
  151. package/dist/core/extensions/event-types.d.ts.map +1 -1
  152. package/dist/core/extensions/event-types.js.map +1 -1
  153. package/dist/core/extensions/index.d.ts +2 -1
  154. package/dist/core/extensions/index.d.ts.map +1 -1
  155. package/dist/core/extensions/index.js.map +1 -1
  156. package/dist/core/extensions/loader-api.d.ts +1 -1
  157. package/dist/core/extensions/loader-api.d.ts.map +1 -1
  158. package/dist/core/extensions/loader-api.js +7 -0
  159. package/dist/core/extensions/loader-api.js.map +1 -1
  160. package/dist/core/extensions/loader-core.d.ts +1 -1
  161. package/dist/core/extensions/loader-core.js.map +1 -1
  162. package/dist/core/extensions/loader-discovery.d.ts +1 -1
  163. package/dist/core/extensions/loader-discovery.js.map +1 -1
  164. package/dist/core/extensions/loader-runtime.d.ts.map +1 -1
  165. package/dist/core/extensions/loader-runtime.js +3 -0
  166. package/dist/core/extensions/loader-runtime.js.map +1 -1
  167. package/dist/core/extensions/loader.d.ts +1 -1
  168. package/dist/core/extensions/loader.js.map +1 -1
  169. package/dist/core/extensions/message-types.d.ts +1 -1
  170. package/dist/core/extensions/message-types.js.map +1 -1
  171. package/dist/core/extensions/runner-context.d.ts +11 -1
  172. package/dist/core/extensions/runner-context.d.ts.map +1 -1
  173. package/dist/core/extensions/runner-context.js +41 -2
  174. package/dist/core/extensions/runner-context.js.map +1 -1
  175. package/dist/core/extensions/runner-events.d.ts +1 -1
  176. package/dist/core/extensions/runner-events.d.ts.map +1 -1
  177. package/dist/core/extensions/runner-events.js +17 -2
  178. package/dist/core/extensions/runner-events.js.map +1 -1
  179. package/dist/core/extensions/runner-ui.js.map +1 -1
  180. package/dist/core/extensions/runner.d.ts +17 -2
  181. package/dist/core/extensions/runner.d.ts.map +1 -1
  182. package/dist/core/extensions/runner.js +68 -18
  183. package/dist/core/extensions/runner.js.map +1 -1
  184. package/dist/core/extensions/runtime-types.d.ts +4 -1
  185. package/dist/core/extensions/runtime-types.d.ts.map +1 -1
  186. package/dist/core/extensions/runtime-types.js.map +1 -1
  187. package/dist/core/extensions/tool-types.d.ts +1 -1
  188. package/dist/core/extensions/tool-types.js.map +1 -1
  189. package/dist/core/extensions/types.d.ts +1 -0
  190. package/dist/core/extensions/types.d.ts.map +1 -1
  191. package/dist/core/extensions/types.js.map +1 -1
  192. package/dist/core/extensions/ui-types.d.ts +5 -1
  193. package/dist/core/extensions/ui-types.d.ts.map +1 -1
  194. package/dist/core/extensions/ui-types.js.map +1 -1
  195. package/dist/core/extensions/workflow-activity-hub.d.ts +25 -0
  196. package/dist/core/extensions/workflow-activity-hub.d.ts.map +1 -0
  197. package/dist/core/extensions/workflow-activity-hub.js +183 -0
  198. package/dist/core/extensions/workflow-activity-hub.js.map +1 -0
  199. package/dist/core/extensions/workflow-events.d.ts +118 -0
  200. package/dist/core/extensions/workflow-events.d.ts.map +1 -0
  201. package/dist/core/extensions/workflow-events.js +2 -0
  202. package/dist/core/extensions/workflow-events.js.map +1 -0
  203. package/dist/core/footer-data-provider.d.ts +8 -4
  204. package/dist/core/footer-data-provider.d.ts.map +1 -1
  205. package/dist/core/footer-data-provider.js +97 -11
  206. package/dist/core/footer-data-provider.js.map +1 -1
  207. package/dist/core/index.d.ts +3 -3
  208. package/dist/core/index.js.map +1 -1
  209. package/dist/core/keybindings.d.ts +27 -2
  210. package/dist/core/keybindings.d.ts.map +1 -1
  211. package/dist/core/keybindings.js +7 -2
  212. package/dist/core/keybindings.js.map +1 -1
  213. package/dist/core/mandatory-runtime-tools.d.ts +1 -1
  214. package/dist/core/mandatory-runtime-tools.js.map +1 -1
  215. package/dist/core/model-fallback-failures.js +2 -2
  216. package/dist/core/model-fallback-failures.js.map +1 -1
  217. package/dist/core/model-registry.d.ts +5 -1
  218. package/dist/core/model-registry.d.ts.map +1 -1
  219. package/dist/core/model-registry.js +8 -0
  220. package/dist/core/model-registry.js.map +1 -1
  221. package/dist/core/model-resolver-defaults.js +1 -1
  222. package/dist/core/model-resolver-defaults.js.map +1 -1
  223. package/dist/core/resource-loader-assets.js.map +1 -1
  224. package/dist/core/resource-loader-core.d.ts +1 -1
  225. package/dist/core/resource-loader-core.js.map +1 -1
  226. package/dist/core/resource-loader-internals.d.ts +2 -2
  227. package/dist/core/resource-loader-internals.js.map +1 -1
  228. package/dist/core/resource-loader-reload.d.ts +2 -0
  229. package/dist/core/resource-loader-reload.d.ts.map +1 -1
  230. package/dist/core/resource-loader-reload.js +231 -191
  231. package/dist/core/resource-loader-reload.js.map +1 -1
  232. package/dist/core/resource-loader-types.d.ts +4 -2
  233. package/dist/core/resource-loader-types.d.ts.map +1 -1
  234. package/dist/core/resource-loader-types.js.map +1 -1
  235. package/dist/core/sdk-exports.d.ts +2 -2
  236. package/dist/core/sdk-exports.js.map +1 -1
  237. package/dist/core/sdk-types.d.ts +2 -2
  238. package/dist/core/sdk-types.js.map +1 -1
  239. package/dist/core/sdk.js.map +1 -1
  240. package/dist/core/settings-manager-core.d.ts.map +1 -1
  241. package/dist/core/settings-manager-core.js +10 -4
  242. package/dist/core/settings-manager-core.js.map +1 -1
  243. package/dist/core/settings-storage.d.ts +1 -0
  244. package/dist/core/settings-storage.d.ts.map +1 -1
  245. package/dist/core/settings-storage.js +18 -0
  246. package/dist/core/settings-storage.js.map +1 -1
  247. package/dist/core/settings-types.d.ts +11 -0
  248. package/dist/core/settings-types.d.ts.map +1 -1
  249. package/dist/core/settings-types.js.map +1 -1
  250. package/dist/core/slash-commands.d.ts.map +1 -1
  251. package/dist/core/slash-commands.js +2 -0
  252. package/dist/core/slash-commands.js.map +1 -1
  253. package/dist/core/system-prompt.d.ts.map +1 -1
  254. package/dist/core/system-prompt.js +5 -6
  255. package/dist/core/system-prompt.js.map +1 -1
  256. package/dist/core/tasks/agent-adapter.d.ts +32 -0
  257. package/dist/core/tasks/agent-adapter.d.ts.map +1 -0
  258. package/dist/core/tasks/agent-adapter.js +71 -0
  259. package/dist/core/tasks/agent-adapter.js.map +1 -0
  260. package/dist/core/tasks/command-output.d.ts +15 -0
  261. package/dist/core/tasks/command-output.d.ts.map +1 -0
  262. package/dist/core/tasks/command-output.js +29 -0
  263. package/dist/core/tasks/command-output.js.map +1 -0
  264. package/dist/core/tasks/completion-ordering.d.ts +11 -0
  265. package/dist/core/tasks/completion-ordering.d.ts.map +1 -0
  266. package/dist/core/tasks/completion-ordering.js +19 -0
  267. package/dist/core/tasks/completion-ordering.js.map +1 -0
  268. package/dist/core/tasks/completion.d.ts +36 -0
  269. package/dist/core/tasks/completion.d.ts.map +1 -0
  270. package/dist/core/tasks/completion.js +115 -0
  271. package/dist/core/tasks/completion.js.map +1 -0
  272. package/dist/core/tasks/contracts.d.ts +404 -0
  273. package/dist/core/tasks/contracts.d.ts.map +1 -0
  274. package/dist/core/tasks/contracts.js +2 -0
  275. package/dist/core/tasks/contracts.js.map +1 -0
  276. package/dist/core/tasks/execution-scope.d.ts +10 -0
  277. package/dist/core/tasks/execution-scope.d.ts.map +1 -0
  278. package/dist/core/tasks/execution-scope.js +27 -0
  279. package/dist/core/tasks/execution-scope.js.map +1 -0
  280. package/dist/core/tasks/owner-store.d.ts +53 -0
  281. package/dist/core/tasks/owner-store.d.ts.map +1 -0
  282. package/dist/core/tasks/owner-store.js +155 -0
  283. package/dist/core/tasks/owner-store.js.map +1 -0
  284. package/dist/core/tasks/supervisor.d.ts +121 -0
  285. package/dist/core/tasks/supervisor.d.ts.map +1 -0
  286. package/dist/core/tasks/supervisor.js +916 -0
  287. package/dist/core/tasks/supervisor.js.map +1 -0
  288. package/dist/core/tasks/transcript.d.ts +23 -0
  289. package/dist/core/tasks/transcript.d.ts.map +1 -0
  290. package/dist/core/tasks/transcript.js +74 -0
  291. package/dist/core/tasks/transcript.js.map +1 -0
  292. package/dist/core/tools/ask-user-question/ask-user-question.d.ts +2 -2
  293. package/dist/core/tools/ask-user-question/ask-user-question.d.ts.map +1 -1
  294. package/dist/core/tools/ask-user-question/ask-user-question.js +8 -4
  295. package/dist/core/tools/ask-user-question/ask-user-question.js.map +1 -1
  296. package/dist/core/tools/ask-user-question/state/build-questionnaire.d.ts +1 -1
  297. package/dist/core/tools/ask-user-question/state/build-questionnaire.js.map +1 -1
  298. package/dist/core/tools/ask-user-question/state/questionnaire-session.d.ts +1 -1
  299. package/dist/core/tools/ask-user-question/state/questionnaire-session.js.map +1 -1
  300. package/dist/core/tools/ask-user-question/view/components/multi-select-view.d.ts +1 -1
  301. package/dist/core/tools/ask-user-question/view/components/multi-select-view.js.map +1 -1
  302. package/dist/core/tools/ask-user-question/view/components/preview/markdown-content-cache.d.ts +1 -1
  303. package/dist/core/tools/ask-user-question/view/components/preview/markdown-content-cache.js.map +1 -1
  304. package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.d.ts +1 -1
  305. package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.js.map +1 -1
  306. package/dist/core/tools/ask-user-question/view/components/submit-picker.d.ts +1 -1
  307. package/dist/core/tools/ask-user-question/view/components/submit-picker.js.map +1 -1
  308. package/dist/core/tools/ask-user-question/view/components/tab-bar.d.ts +1 -1
  309. package/dist/core/tools/ask-user-question/view/components/tab-bar.js.map +1 -1
  310. package/dist/core/tools/ask-user-question/view/dialog-builder.d.ts +1 -1
  311. package/dist/core/tools/ask-user-question/view/dialog-builder.js.map +1 -1
  312. package/dist/core/tools/ask-user-question/view/tab-content-strategy.d.ts +1 -1
  313. package/dist/core/tools/ask-user-question/view/tab-content-strategy.js.map +1 -1
  314. package/dist/core/tools/bash-pty-native.d.ts +18 -3
  315. package/dist/core/tools/bash-pty-native.d.ts.map +1 -1
  316. package/dist/core/tools/bash-pty-native.js +116 -1
  317. package/dist/core/tools/bash-pty-native.js.map +1 -1
  318. package/dist/core/tools/bash.d.ts +11 -4
  319. package/dist/core/tools/bash.d.ts.map +1 -1
  320. package/dist/core/tools/bash.js +52 -8
  321. package/dist/core/tools/bash.js.map +1 -1
  322. package/dist/core/tools/edit.d.ts.map +1 -1
  323. package/dist/core/tools/edit.js +1 -2
  324. package/dist/core/tools/edit.js.map +1 -1
  325. package/dist/core/tools/find.js.map +1 -1
  326. package/dist/core/tools/grep.js.map +1 -1
  327. package/dist/core/tools/index.d.ts +2 -2
  328. package/dist/core/tools/index.js.map +1 -1
  329. package/dist/core/tools/ls.js.map +1 -1
  330. package/dist/core/tools/powershell.d.ts +20 -10
  331. package/dist/core/tools/powershell.d.ts.map +1 -1
  332. package/dist/core/tools/powershell.js +32 -7
  333. package/dist/core/tools/powershell.js.map +1 -1
  334. package/dist/core/tools/read.d.ts.map +1 -1
  335. package/dist/core/tools/read.js +1 -2
  336. package/dist/core/tools/read.js.map +1 -1
  337. package/dist/core/tools/render-utils.d.ts +1 -1
  338. package/dist/core/tools/render-utils.js.map +1 -1
  339. package/dist/core/tools/resource-selectors.d.ts.map +1 -1
  340. package/dist/core/tools/resource-selectors.js +15 -7
  341. package/dist/core/tools/resource-selectors.js.map +1 -1
  342. package/dist/core/tools/search.js.map +1 -1
  343. package/dist/core/tools/todos-render.d.ts +1 -1
  344. package/dist/core/tools/todos-render.js.map +1 -1
  345. package/dist/core/tools/write.d.ts.map +1 -1
  346. package/dist/core/tools/write.js +1 -2
  347. package/dist/core/tools/write.js.map +1 -1
  348. package/dist/core/workflow-stage-admission.d.ts +10 -0
  349. package/dist/core/workflow-stage-admission.d.ts.map +1 -1
  350. package/dist/core/workflow-stage-admission.js +24 -0
  351. package/dist/core/workflow-stage-admission.js.map +1 -1
  352. package/dist/extensions/herdr/activity.d.ts +15 -0
  353. package/dist/extensions/herdr/activity.d.ts.map +1 -0
  354. package/dist/extensions/herdr/activity.js +24 -0
  355. package/dist/extensions/herdr/activity.js.map +1 -0
  356. package/dist/extensions/herdr/environment.d.ts +7 -0
  357. package/dist/extensions/herdr/environment.d.ts.map +1 -0
  358. package/dist/extensions/herdr/environment.js +6 -0
  359. package/dist/extensions/herdr/environment.js.map +1 -0
  360. package/dist/extensions/herdr/index.d.ts +9 -0
  361. package/dist/extensions/herdr/index.d.ts.map +1 -0
  362. package/dist/extensions/herdr/index.js +225 -0
  363. package/dist/extensions/herdr/index.js.map +1 -0
  364. package/dist/extensions/herdr/pane-owner.d.ts +30 -0
  365. package/dist/extensions/herdr/pane-owner.d.ts.map +1 -0
  366. package/dist/extensions/herdr/pane-owner.js +111 -0
  367. package/dist/extensions/herdr/pane-owner.js.map +1 -0
  368. package/dist/extensions/herdr/transport.d.ts +8 -0
  369. package/dist/extensions/herdr/transport.d.ts.map +1 -0
  370. package/dist/extensions/herdr/transport.js +28 -0
  371. package/dist/extensions/herdr/transport.js.map +1 -0
  372. package/dist/extensions/index.d.ts.map +1 -1
  373. package/dist/extensions/index.js +2 -0
  374. package/dist/extensions/index.js.map +1 -1
  375. package/dist/extensions/llama/huggingface-ui.d.ts +1 -1
  376. package/dist/extensions/llama/huggingface-ui.js.map +1 -1
  377. package/dist/extensions/llama/ui.js.map +1 -1
  378. package/dist/index-extensions.d.ts +3 -2
  379. package/dist/index-extensions.d.ts.map +1 -1
  380. package/dist/index-extensions.js.map +1 -1
  381. package/dist/index.d.ts +11 -3
  382. package/dist/index.d.ts.map +1 -1
  383. package/dist/index.js +8 -0
  384. package/dist/index.js.map +1 -1
  385. package/dist/main-session.js.map +1 -1
  386. package/dist/main.d.ts.map +1 -1
  387. package/dist/main.js +149 -69
  388. package/dist/main.js.map +1 -1
  389. package/dist/modes/interactive/components/armin.js.map +1 -1
  390. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  391. package/dist/modes/interactive/components/atomic-banner.d.ts +1 -1
  392. package/dist/modes/interactive/components/atomic-banner.js.map +1 -1
  393. package/dist/modes/interactive/components/atomic-working-status.js.map +1 -1
  394. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  395. package/dist/modes/interactive/components/bordered-loader.d.ts +1 -1
  396. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  397. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  398. package/dist/modes/interactive/components/chat-message-renderer.d.ts +12 -0
  399. package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
  400. package/dist/modes/interactive/components/chat-message-renderer.js +44 -0
  401. package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
  402. package/dist/modes/interactive/components/chat-session-host-actions.d.ts +1 -1
  403. package/dist/modes/interactive/components/chat-session-host-actions.d.ts.map +1 -1
  404. package/dist/modes/interactive/components/chat-session-host-actions.js +43 -8
  405. package/dist/modes/interactive/components/chat-session-host-actions.js.map +1 -1
  406. package/dist/modes/interactive/components/chat-session-host-editor.d.ts +1 -1
  407. package/dist/modes/interactive/components/chat-session-host-editor.js.map +1 -1
  408. package/dist/modes/interactive/components/chat-session-host-events.d.ts +2 -2
  409. package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -1
  410. package/dist/modes/interactive/components/chat-session-host-rendering.d.ts +2 -2
  411. package/dist/modes/interactive/components/chat-session-host-rendering.d.ts.map +1 -1
  412. package/dist/modes/interactive/components/chat-session-host-rendering.js +12 -3
  413. package/dist/modes/interactive/components/chat-session-host-rendering.js.map +1 -1
  414. package/dist/modes/interactive/components/chat-session-host-runtime.d.ts +4 -5
  415. package/dist/modes/interactive/components/chat-session-host-runtime.d.ts.map +1 -1
  416. package/dist/modes/interactive/components/chat-session-host-runtime.js +8 -6
  417. package/dist/modes/interactive/components/chat-session-host-runtime.js.map +1 -1
  418. package/dist/modes/interactive/components/chat-session-host-state.d.ts +7 -2
  419. package/dist/modes/interactive/components/chat-session-host-state.d.ts.map +1 -1
  420. package/dist/modes/interactive/components/chat-session-host-state.js +1 -0
  421. package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
  422. package/dist/modes/interactive/components/chat-session-host-terminal-cleanup.d.ts +1 -1
  423. package/dist/modes/interactive/components/chat-session-host-terminal-cleanup.js.map +1 -1
  424. package/dist/modes/interactive/components/chat-session-host-types.d.ts +8 -3
  425. package/dist/modes/interactive/components/chat-session-host-types.d.ts.map +1 -1
  426. package/dist/modes/interactive/components/chat-session-host-types.js.map +1 -1
  427. package/dist/modes/interactive/components/chat-session-host-utils.d.ts +1 -1
  428. package/dist/modes/interactive/components/chat-session-host-utils.d.ts.map +1 -1
  429. package/dist/modes/interactive/components/chat-session-host-utils.js +2 -0
  430. package/dist/modes/interactive/components/chat-session-host-utils.js.map +1 -1
  431. package/dist/modes/interactive/components/chat-session-host.d.ts +17 -2
  432. package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
  433. package/dist/modes/interactive/components/chat-session-host.js +97 -1
  434. package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
  435. package/dist/modes/interactive/components/chat-transcript.d.ts +1 -0
  436. package/dist/modes/interactive/components/chat-transcript.d.ts.map +1 -1
  437. package/dist/modes/interactive/components/chat-transcript.js +1 -1
  438. package/dist/modes/interactive/components/chat-transcript.js.map +1 -1
  439. package/dist/modes/interactive/components/compaction-boundary-message.js.map +1 -1
  440. package/dist/modes/interactive/components/config-selector-list.js.map +1 -1
  441. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  442. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  443. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  444. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  445. package/dist/modes/interactive/components/custom-message.js +12 -0
  446. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  447. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  448. package/dist/modes/interactive/components/diff.js.map +1 -1
  449. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  450. package/dist/modes/interactive/components/earendil-announcement.js.map +1 -1
  451. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  452. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  453. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  454. package/dist/modes/interactive/components/first-time-setup.d.ts +1 -1
  455. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  456. package/dist/modes/interactive/components/footer.d.ts +7 -6
  457. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  458. package/dist/modes/interactive/components/footer.js +27 -9
  459. package/dist/modes/interactive/components/footer.js.map +1 -1
  460. package/dist/modes/interactive/components/host-input-form-mount.js.map +1 -1
  461. package/dist/modes/interactive/components/host-input-form.d.ts +1 -1
  462. package/dist/modes/interactive/components/host-input-form.js.map +1 -1
  463. package/dist/modes/interactive/components/index.d.ts +2 -2
  464. package/dist/modes/interactive/components/index.js.map +1 -1
  465. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  466. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  467. package/dist/modes/interactive/components/mermaid.d.ts +1 -1
  468. package/dist/modes/interactive/components/mermaid.js.map +1 -1
  469. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  470. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  471. package/dist/modes/interactive/components/reserved-bottom-overlay.js.map +1 -1
  472. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  473. package/dist/modes/interactive/components/session-selector-header.js.map +1 -1
  474. package/dist/modes/interactive/components/session-selector-list.js.map +1 -1
  475. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  476. package/dist/modes/interactive/components/settings-selector-items.js.map +1 -1
  477. package/dist/modes/interactive/components/settings-selector-submenus.d.ts +1 -1
  478. package/dist/modes/interactive/components/settings-selector-submenus.js.map +1 -1
  479. package/dist/modes/interactive/components/settings-selector-types.d.ts +1 -1
  480. package/dist/modes/interactive/components/settings-selector-types.js.map +1 -1
  481. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  482. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  483. package/dist/modes/interactive/components/skill-invocation-message.d.ts +1 -1
  484. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  485. package/dist/modes/interactive/components/task-completion-message.d.ts +13 -0
  486. package/dist/modes/interactive/components/task-completion-message.d.ts.map +1 -0
  487. package/dist/modes/interactive/components/task-completion-message.js +65 -0
  488. package/dist/modes/interactive/components/task-completion-message.js.map +1 -0
  489. package/dist/modes/interactive/components/task-detail.d.ts +27 -0
  490. package/dist/modes/interactive/components/task-detail.d.ts.map +1 -0
  491. package/dist/modes/interactive/components/task-detail.js +107 -0
  492. package/dist/modes/interactive/components/task-detail.js.map +1 -0
  493. package/dist/modes/interactive/components/task-inspector.d.ts +50 -0
  494. package/dist/modes/interactive/components/task-inspector.d.ts.map +1 -0
  495. package/dist/modes/interactive/components/task-inspector.js +599 -0
  496. package/dist/modes/interactive/components/task-inspector.js.map +1 -0
  497. package/dist/modes/interactive/components/task-list.d.ts +18 -0
  498. package/dist/modes/interactive/components/task-list.d.ts.map +1 -0
  499. package/dist/modes/interactive/components/task-list.js +59 -0
  500. package/dist/modes/interactive/components/task-list.js.map +1 -0
  501. package/dist/modes/interactive/components/task-live-transcript.d.ts +17 -0
  502. package/dist/modes/interactive/components/task-live-transcript.d.ts.map +1 -0
  503. package/dist/modes/interactive/components/task-live-transcript.js +33 -0
  504. package/dist/modes/interactive/components/task-live-transcript.js.map +1 -0
  505. package/dist/modes/interactive/components/task-navigation.d.ts +38 -0
  506. package/dist/modes/interactive/components/task-navigation.d.ts.map +1 -0
  507. package/dist/modes/interactive/components/task-navigation.js +93 -0
  508. package/dist/modes/interactive/components/task-navigation.js.map +1 -0
  509. package/dist/modes/interactive/components/task-row.d.ts +34 -0
  510. package/dist/modes/interactive/components/task-row.d.ts.map +1 -0
  511. package/dist/modes/interactive/components/task-row.js +158 -0
  512. package/dist/modes/interactive/components/task-row.js.map +1 -0
  513. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  514. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  515. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  516. package/dist/modes/interactive/components/transcript-follow-indicator.js.map +1 -1
  517. package/dist/modes/interactive/components/tree-selector-component.js.map +1 -1
  518. package/dist/modes/interactive/components/tree-selector-content.js.map +1 -1
  519. package/dist/modes/interactive/components/tree-selector-help.js.map +1 -1
  520. package/dist/modes/interactive/components/tree-selector-label-input.js.map +1 -1
  521. package/dist/modes/interactive/components/tree-selector-list.js.map +1 -1
  522. package/dist/modes/interactive/components/trust-selector.js.map +1 -1
  523. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  524. package/dist/modes/interactive/components/user-message.js.map +1 -1
  525. package/dist/modes/interactive/components/working-status.js.map +1 -1
  526. package/dist/modes/interactive/interactive-agent-events.js +8 -2
  527. package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
  528. package/dist/modes/interactive/interactive-auth-login.js +3 -1
  529. package/dist/modes/interactive/interactive-auth-login.js.map +1 -1
  530. package/dist/modes/interactive/interactive-autocomplete.js +9 -30
  531. package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
  532. package/dist/modes/interactive/interactive-deferred-startup.js +2 -1
  533. package/dist/modes/interactive/interactive-deferred-startup.js.map +1 -1
  534. package/dist/modes/interactive/interactive-extension-context.js +14 -4
  535. package/dist/modes/interactive/interactive-extension-context.js.map +1 -1
  536. package/dist/modes/interactive/interactive-extension-custom-ui.js +52 -4
  537. package/dist/modes/interactive/interactive-extension-custom-ui.js.map +1 -1
  538. package/dist/modes/interactive/interactive-extension-runtime.js +1 -0
  539. package/dist/modes/interactive/interactive-extension-runtime.js.map +1 -1
  540. package/dist/modes/interactive/interactive-extension-widgets.js +9 -1
  541. package/dist/modes/interactive/interactive-extension-widgets.js.map +1 -1
  542. package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
  543. package/dist/modes/interactive/interactive-input-handling.js +19 -0
  544. package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
  545. package/dist/modes/interactive/interactive-mode-base.d.ts +6 -1
  546. package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
  547. package/dist/modes/interactive/interactive-mode-base.js +4 -1
  548. package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
  549. package/dist/modes/interactive/interactive-mode-deps.d.ts +6 -6
  550. package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
  551. package/dist/modes/interactive/interactive-mode-surface.d.ts +2 -1
  552. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  553. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  554. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  555. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  556. package/dist/modes/interactive/interactive-mode.js +3 -0
  557. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  558. package/dist/modes/interactive/interactive-process-lifecycle.js +4 -1
  559. package/dist/modes/interactive/interactive-process-lifecycle.js.map +1 -1
  560. package/dist/modes/interactive/interactive-render-chat.js +2 -0
  561. package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
  562. package/dist/modes/interactive/interactive-session-routing.js +33 -23
  563. package/dist/modes/interactive/interactive-session-routing.js.map +1 -1
  564. package/dist/modes/interactive/interactive-session-runtime.js +1 -0
  565. package/dist/modes/interactive/interactive-session-runtime.js.map +1 -1
  566. package/dist/modes/interactive/interactive-slash-commands.js.map +1 -1
  567. package/dist/modes/interactive/interactive-summarization-retry-events.js +2 -2
  568. package/dist/modes/interactive/interactive-summarization-retry-events.js.map +1 -1
  569. package/dist/modes/interactive/interactive-task-projection.d.ts +13 -0
  570. package/dist/modes/interactive/interactive-task-projection.d.ts.map +1 -0
  571. package/dist/modes/interactive/interactive-task-projection.js +72 -0
  572. package/dist/modes/interactive/interactive-task-projection.js.map +1 -0
  573. package/dist/modes/interactive/interactive-tui.js.map +1 -1
  574. package/dist/modes/interactive/interactive-windows-subshell.d.ts +17 -0
  575. package/dist/modes/interactive/interactive-windows-subshell.d.ts.map +1 -0
  576. package/dist/modes/interactive/interactive-windows-subshell.js +92 -0
  577. package/dist/modes/interactive/interactive-windows-subshell.js.map +1 -0
  578. package/dist/modes/interactive/skill-command-autocomplete.d.ts +12 -0
  579. package/dist/modes/interactive/skill-command-autocomplete.d.ts.map +1 -0
  580. package/dist/modes/interactive/skill-command-autocomplete.js +69 -0
  581. package/dist/modes/interactive/skill-command-autocomplete.js.map +1 -0
  582. package/dist/modes/interactive/theme/theme-class.d.ts.map +1 -1
  583. package/dist/modes/interactive/theme/theme-class.js +4 -1
  584. package/dist/modes/interactive/theme/theme-class.js.map +1 -1
  585. package/dist/modes/interactive/theme/theme-controller.d.ts +1 -1
  586. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  587. package/dist/modes/interactive-engine/create-isolated-runtime.d.ts +1 -1
  588. package/dist/modes/interactive-engine/create-isolated-runtime.js.map +1 -1
  589. package/dist/modes/interactive-engine/engine-custom-ui.d.ts +5 -9
  590. package/dist/modes/interactive-engine/engine-custom-ui.d.ts.map +1 -1
  591. package/dist/modes/interactive-engine/engine-custom-ui.js +14 -5
  592. package/dist/modes/interactive-engine/engine-custom-ui.js.map +1 -1
  593. package/dist/modes/interactive-engine/engine-dialog-host.d.ts +2 -2
  594. package/dist/modes/interactive-engine/engine-dialog-host.js.map +1 -1
  595. package/dist/modes/interactive-engine/engine-project-trust.d.ts +10 -0
  596. package/dist/modes/interactive-engine/engine-project-trust.d.ts.map +1 -0
  597. package/dist/modes/interactive-engine/engine-project-trust.js +28 -0
  598. package/dist/modes/interactive-engine/engine-project-trust.js.map +1 -0
  599. package/dist/modes/interactive-engine/engine-render-service.d.ts +1 -1
  600. package/dist/modes/interactive-engine/engine-render-service.js.map +1 -1
  601. package/dist/modes/interactive-engine/extension-ui-bridge.d.ts +3 -1
  602. package/dist/modes/interactive-engine/extension-ui-bridge.d.ts.map +1 -1
  603. package/dist/modes/interactive-engine/extension-ui-bridge.js +6 -0
  604. package/dist/modes/interactive-engine/extension-ui-bridge.js.map +1 -1
  605. package/dist/modes/interactive-engine/input-form-host.d.ts +2 -2
  606. package/dist/modes/interactive-engine/input-form-host.js.map +1 -1
  607. package/dist/modes/interactive-engine/isolated-auth.d.ts +1 -1
  608. package/dist/modes/interactive-engine/isolated-auth.js.map +1 -1
  609. package/dist/modes/interactive-engine/isolated-runtime.d.ts +5 -2
  610. package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
  611. package/dist/modes/interactive-engine/isolated-runtime.js +40 -3
  612. package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
  613. package/dist/modes/interactive-engine/protocol.d.ts +9 -0
  614. package/dist/modes/interactive-engine/protocol.d.ts.map +1 -1
  615. package/dist/modes/interactive-engine/protocol.js +8 -0
  616. package/dist/modes/interactive-engine/protocol.js.map +1 -1
  617. package/dist/modes/interactive-engine/remote-component.d.ts +2 -2
  618. package/dist/modes/interactive-engine/remote-component.d.ts.map +1 -1
  619. package/dist/modes/interactive-engine/remote-component.js +3 -2
  620. package/dist/modes/interactive-engine/remote-component.js.map +1 -1
  621. package/dist/modes/interactive-engine/remote-model-catalog.d.ts +1 -1
  622. package/dist/modes/interactive-engine/remote-model-catalog.js.map +1 -1
  623. package/dist/modes/interactive-engine/remote-renderer.d.ts +1 -1
  624. package/dist/modes/interactive-engine/remote-renderer.js.map +1 -1
  625. package/dist/modes/interactive-engine/session-picker-host.d.ts +2 -2
  626. package/dist/modes/interactive-engine/session-picker-host.js.map +1 -1
  627. package/dist/modes/json-event.d.ts +1 -1
  628. package/dist/modes/json-event.js.map +1 -1
  629. package/dist/modes/print-mode.js.map +1 -1
  630. package/dist/modes/rpc/rpc-bash-request-owners.d.ts +2 -2
  631. package/dist/modes/rpc/rpc-bash-request-owners.js.map +1 -1
  632. package/dist/modes/rpc/rpc-client-api.d.ts +2 -2
  633. package/dist/modes/rpc/rpc-client-api.d.ts.map +1 -1
  634. package/dist/modes/rpc/rpc-client-api.js +2 -2
  635. package/dist/modes/rpc/rpc-client-api.js.map +1 -1
  636. package/dist/modes/rpc/rpc-client-waits.d.ts +1 -1
  637. package/dist/modes/rpc/rpc-client-waits.js.map +1 -1
  638. package/dist/modes/rpc/rpc-client.d.ts +3 -1
  639. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  640. package/dist/modes/rpc/rpc-client.js +20 -0
  641. package/dist/modes/rpc/rpc-client.js.map +1 -1
  642. package/dist/modes/rpc/rpc-command-handler.d.ts +4 -2
  643. package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
  644. package/dist/modes/rpc/rpc-command-handler.js +12 -4
  645. package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
  646. package/dist/modes/rpc/rpc-extension-ui.d.ts +1 -1
  647. package/dist/modes/rpc/rpc-extension-ui.js.map +1 -1
  648. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  649. package/dist/modes/rpc/rpc-mode.js +11 -2
  650. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  651. package/dist/modes/rpc/rpc-provider-auth.d.ts +1 -1
  652. package/dist/modes/rpc/rpc-provider-auth.js.map +1 -1
  653. package/dist/modes/rpc/rpc-session-binding.d.ts +4 -1
  654. package/dist/modes/rpc/rpc-session-binding.d.ts.map +1 -1
  655. package/dist/modes/rpc/rpc-session-binding.js +35 -1
  656. package/dist/modes/rpc/rpc-session-binding.js.map +1 -1
  657. package/dist/modes/rpc/rpc-types.d.ts +13 -1
  658. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  659. package/dist/modes/rpc/rpc-types.js.map +1 -1
  660. package/dist/modes/rpc/task-ui-bridge.d.ts +9 -0
  661. package/dist/modes/rpc/task-ui-bridge.d.ts.map +1 -0
  662. package/dist/modes/rpc/task-ui-bridge.js +146 -0
  663. package/dist/modes/rpc/task-ui-bridge.js.map +1 -0
  664. package/dist/self-update-plan.js.map +1 -1
  665. package/docs/background-tasks.md +199 -0
  666. package/docs/compaction.md +2 -0
  667. package/docs/development.md +3 -1
  668. package/docs/docs.json +2 -0
  669. package/docs/environment-variables.md +1 -1
  670. package/docs/extensions.md +108 -6
  671. package/docs/herdr.md +106 -0
  672. package/docs/intercom.md +38 -35
  673. package/docs/keybindings.md +19 -2
  674. package/docs/models/evals.md +222 -147
  675. package/docs/models/model-selection.md +20 -14
  676. package/docs/models/pareto-efficiency.md +2 -2
  677. package/docs/providers.md +48 -46
  678. package/docs/quickstart.md +2 -2
  679. package/docs/sdk.md +244 -0
  680. package/docs/settings.md +15 -3
  681. package/docs/skills.md +23 -1
  682. package/docs/subagents.md +71 -9
  683. package/docs/themes.md +4 -0
  684. package/docs/tools.md +25 -0
  685. package/docs/tui.md +29 -2
  686. package/docs/usage.md +4 -0
  687. package/docs/windows.md +4 -4
  688. package/docs/workflows/api-reference.md +13 -4
  689. package/docs/workflows/operations.md +59 -5
  690. package/docs/workflows/reliable-design.md +35 -4
  691. package/docs/workflows/verification.md +21 -4
  692. package/docs/workflows.md +3 -1
  693. package/npm-shrinkwrap.json +781 -661
  694. package/package.json +10 -10
  695. /package/dist/builtin/workflows/builtin/{chunk-cg9tmks0.js → chunk-n1910xc4.js} +0 -0
  696. /package/dist/builtin/workflows/builtin/{chunk-wpckd35c.js → chunk-rc5ec5xx.js} +0 -0
  697. /package/dist/builtin/workflows/builtin/{chunk-7at6dnkr.js → chunk-tgt0s5e5.js} +0 -0
  698. /package/dist/builtin/workflows/builtin/{chunk-bfkmzv9h.js → chunk-xtxcq5tj.js} +0 -0
@@ -12,7 +12,17 @@ var __export = (target, all) => {
12
12
  set: __exportSetter.bind(all, name)
13
13
  });
14
14
  };
15
- var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
15
+ var __esm = (fn, res, err) => () => {
16
+ if (fn)
17
+ try {
18
+ res = fn(fn = 0);
19
+ } catch (e) {
20
+ err = [e];
21
+ }
22
+ if (err)
23
+ throw err[0];
24
+ return res;
25
+ };
16
26
 
17
27
  // dist/builtin/intercom/result-renderers.ts
18
28
  import { Text } from "@earendil-works/pi-tui";
@@ -80,7 +90,7 @@ function isRecoverableIntercomDisconnect(error) {
80
90
  }
81
91
  return false;
82
92
  }
83
- var RECOVERABLE_DISCONNECT_MESSAGE = "Client disconnected. Retry the same Intercom call up to three times to reconnect.", MAX_CAUSE_DEPTH = 8, IntercomClientDisconnectedError;
93
+ var RECOVERABLE_DISCONNECT_MESSAGE = "Client disconnected", MAX_CAUSE_DEPTH = 8, IntercomClientDisconnectedError;
84
94
  var init_recoverable_disconnect = __esm(() => {
85
95
  IntercomClientDisconnectedError = class IntercomClientDisconnectedError extends Error {
86
96
  intercomRecoverableDisconnect = true;
@@ -91,6 +101,16 @@ var init_recoverable_disconnect = __esm(() => {
91
101
  };
92
102
  });
93
103
 
104
+ // dist/builtin/intercom/retry-policy.ts
105
+ var ASK_REPLY_TIMEOUT_MS, RETRY_IDENTITY_RETRY_OPPORTUNITY_MS, RETRY_IDENTITY_TTL_MS, DELIVERED_MESSAGE_TTL_MS, RECONNECT_DELAYS_MS;
106
+ var init_retry_policy = __esm(() => {
107
+ ASK_REPLY_TIMEOUT_MS = 10 * 60 * 1000;
108
+ RETRY_IDENTITY_RETRY_OPPORTUNITY_MS = 60 * 1000;
109
+ RETRY_IDENTITY_TTL_MS = ASK_REPLY_TIMEOUT_MS + RETRY_IDENTITY_RETRY_OPPORTUNITY_MS;
110
+ DELIVERED_MESSAGE_TTL_MS = RETRY_IDENTITY_TTL_MS + RETRY_IDENTITY_RETRY_OPPORTUNITY_MS;
111
+ RECONNECT_DELAYS_MS = [1000, 2000, 5000];
112
+ });
113
+
94
114
  // dist/builtin/intercom/reconnect-backoff.ts
95
115
  function reconnectDelayMs(attempt) {
96
116
  return BACKOFF_MS[Math.min(attempt, BACKOFF_MS.length - 1)];
@@ -100,6 +120,37 @@ var init_reconnect_backoff = __esm(() => {
100
120
  BACKOFF_MS = [1000, 2000, 5000, 1e4, 30000];
101
121
  });
102
122
 
123
+ // dist/builtin/intercom/subagent-reply-capability.ts
124
+ function registerSubagentReplyCapability(pi, client) {
125
+ let signal;
126
+ let unbind;
127
+ const capability = () => {
128
+ if (!signal)
129
+ return;
130
+ return signal.aborted ? "terminal" : "live";
131
+ };
132
+ pi.on("session_start", (_event, ctx) => {
133
+ unbind?.();
134
+ signal = ctx.subagentPolicy?.executionEnded;
135
+ const current = signal;
136
+ const terminal = () => {
137
+ if (signal !== current)
138
+ return;
139
+ client()?.updatePresence({ replyCapability: "terminal" });
140
+ };
141
+ current?.addEventListener("abort", terminal, { once: true });
142
+ unbind = () => current?.removeEventListener("abort", terminal);
143
+ if (current?.aborted)
144
+ terminal();
145
+ });
146
+ pi.on("session_shutdown", () => {
147
+ unbind?.();
148
+ unbind = undefined;
149
+ signal = undefined;
150
+ });
151
+ return capability;
152
+ }
153
+
103
154
  // dist/builtin/intercom/broker/framing.ts
104
155
  function writeMessage(socket, msg, callback) {
105
156
  const json = JSON.stringify(msg);
@@ -1096,14 +1147,15 @@ var init_client = __esm(() => {
1096
1147
  }
1097
1148
  });
1098
1149
  }
1099
- registerPendingStageRoute(runId, group, capability, stages, possibleStages) {
1150
+ registerPendingStageRoute(runId, group, capability, stages, possibleStages, parent) {
1100
1151
  writeMessage(this.requireActiveSocket(), {
1101
1152
  type: "register_pending_stage_route",
1102
1153
  runId,
1103
1154
  group,
1104
1155
  capability,
1105
1156
  stages,
1106
- possibleStages
1157
+ possibleStages,
1158
+ ...parent === undefined ? {} : { parent }
1107
1159
  });
1108
1160
  }
1109
1161
  registerLiveWorkflowStageRoute(runId, stageKeys, capability) {
@@ -1676,15 +1728,6 @@ class InlineMessageComponent {
1676
1728
  }
1677
1729
  var init_inline_message = () => {};
1678
1730
 
1679
- // dist/builtin/intercom/retry-policy.ts
1680
- var ASK_REPLY_TIMEOUT_MS, RETRY_IDENTITY_RETRY_OPPORTUNITY_MS, RETRY_IDENTITY_TTL_MS, DELIVERED_MESSAGE_TTL_MS;
1681
- var init_retry_policy = __esm(() => {
1682
- ASK_REPLY_TIMEOUT_MS = 10 * 60 * 1000;
1683
- RETRY_IDENTITY_RETRY_OPPORTUNITY_MS = 60 * 1000;
1684
- RETRY_IDENTITY_TTL_MS = ASK_REPLY_TIMEOUT_MS + RETRY_IDENTITY_RETRY_OPPORTUNITY_MS;
1685
- DELIVERED_MESSAGE_TTL_MS = RETRY_IDENTITY_TTL_MS + RETRY_IDENTITY_RETRY_OPPORTUNITY_MS;
1686
- });
1687
-
1688
1731
  // dist/builtin/intercom/reply-waiter.ts
1689
1732
  class ReplyWaiterRegistry {
1690
1733
  timeoutMs;
@@ -2264,32 +2307,32 @@ function validateSupervisorInterviewReply(value, interview) {
2264
2307
  if (!Object.hasOwn(raw, "value")) {
2265
2308
  throw new Error(`responses[${index}].value is required`);
2266
2309
  }
2267
- const value2 = raw.value;
2310
+ const value = raw.value;
2268
2311
  if (question.type === "single") {
2269
- if (typeof value2 !== "string")
2312
+ if (typeof value !== "string")
2270
2313
  throw new Error(`responses[${index}].value must be a string for single questions`);
2271
2314
  const optionLabels = new Set(question.options?.map(interviewOptionLabel));
2272
- if (!optionLabels.has(value2.trim()))
2315
+ if (!optionLabels.has(value.trim()))
2273
2316
  throw new Error(`responses[${index}].value must match one of the question options`);
2274
- responses.push({ id, value: value2.trim() });
2317
+ responses.push({ id, value: value.trim() });
2275
2318
  continue;
2276
2319
  }
2277
2320
  if (question.type === "multi") {
2278
- if (!Array.isArray(value2) || value2.some((item) => typeof item !== "string")) {
2321
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
2279
2322
  throw new Error(`responses[${index}].value must be an array of strings for multi questions`);
2280
2323
  }
2281
2324
  const optionLabels = new Set(question.options?.map(interviewOptionLabel));
2282
- const selected = value2.map((item) => item.trim());
2325
+ const selected = value.map((item) => item.trim());
2283
2326
  const invalid = selected.find((item) => !optionLabels.has(item));
2284
2327
  if (invalid)
2285
2328
  throw new Error(`responses[${index}].value contains an option that is not in the question options: ${invalid}`);
2286
2329
  responses.push({ id, value: selected });
2287
2330
  continue;
2288
2331
  }
2289
- if (typeof value2 !== "string") {
2332
+ if (typeof value !== "string") {
2290
2333
  throw new Error(`responses[${index}].value must be a string for ${question.type} questions`);
2291
2334
  }
2292
- responses.push({ id, value: value2 });
2335
+ responses.push({ id, value });
2293
2336
  }
2294
2337
  return { responses };
2295
2338
  }
@@ -2395,7 +2438,7 @@ import { randomUUID as randomUUID3 } from "crypto";
2395
2438
  import { Type } from "typebox";
2396
2439
  import { Text as Text2 } from "@earendil-works/pi-tui";
2397
2440
  function registerContactSupervisorTool(pi, deps) {
2398
- const { childOrchestratorMetadata, ensureConnected, syncPresenceIdentity, resolveSessionTarget: resolveSessionTarget2, beginReplyWait } = deps;
2441
+ const { childOrchestratorMetadata, ensureConnected, syncPresenceIdentity, resolveSessionTarget, beginReplyWait } = deps;
2399
2442
  const getMetadata = typeof childOrchestratorMetadata === "function" ? childOrchestratorMetadata : () => childOrchestratorMetadata;
2400
2443
  let supervisorWaitActive = false;
2401
2444
  let supervisorHandoffClaimed = false;
@@ -2508,13 +2551,6 @@ function registerContactSupervisorTool(pi, deps) {
2508
2551
  details: { yielded: true }
2509
2552
  };
2510
2553
  }
2511
- if (reason === "need_decision" && typeof params.message !== "string") {
2512
- return {
2513
- content: [{ type: "text", text: `Missing 'message' parameter for reason '${reason}'.` }],
2514
- isError: true,
2515
- details: { error: true }
2516
- };
2517
- }
2518
2554
  let connectedClient;
2519
2555
  try {
2520
2556
  connectedClient = await ensureConnected("tool");
@@ -2538,7 +2574,7 @@ function registerContactSupervisorTool(pi, deps) {
2538
2574
  sendTo = connectedClient.supervisorSessionId ?? metadata.supervisor.supervisorSessionId;
2539
2575
  } else {
2540
2576
  try {
2541
- sendTo = await resolveSessionTarget2(connectedClient, metadata.orchestratorTarget) ?? metadata.orchestratorTarget;
2577
+ sendTo = await resolveSessionTarget(connectedClient, metadata.orchestratorTarget) ?? metadata.orchestratorTarget;
2542
2578
  } catch (error) {
2543
2579
  return {
2544
2580
  content: [{ type: "text", text: `Failed to resolve supervisor target: ${getErrorMessage(error)}` }],
@@ -2607,7 +2643,7 @@ function registerContactSupervisorTool(pi, deps) {
2607
2643
  };
2608
2644
  }
2609
2645
  wait = admission.wait;
2610
- const requestText = reason === "interview_request" ? formatChildOrchestratorMessage("interview", metadata, formatSupervisorInterviewRequest(supervisorInterview, typeof params.message === "string" ? params.message : undefined)) : formatChildOrchestratorMessage("ask", metadata, params.message);
2646
+ const requestText = reason === "interview_request" ? formatChildOrchestratorMessage("interview", metadata, formatSupervisorInterviewRequest(supervisorInterview, typeof params.message === "string" ? params.message : undefined)) : formatChildOrchestratorMessage("ask", metadata, typeof params.message === "string" ? params.message : "");
2611
2647
  const sendResult = await connectedClient.sendToSupervisor(sendTo, {
2612
2648
  messageId: questionId,
2613
2649
  text: requestText,
@@ -2808,6 +2844,11 @@ class RetryIdentityReservations {
2808
2844
  }
2809
2845
  this.finishRetained(reservation, "settled");
2810
2846
  }
2847
+ discard(retryToken) {
2848
+ const reservation = this.tokenReservations.get(retryToken);
2849
+ if (reservation !== undefined)
2850
+ this.expire(reservation);
2851
+ }
2811
2852
  remainingRetries(attempt) {
2812
2853
  const reservation = this.currentReservation(attempt);
2813
2854
  return reservation === undefined ? 0 : Math.max(0, this.maxReuses - reservation.reuseCount);
@@ -2961,14 +3002,73 @@ var init_retry_identity = __esm(() => {
2961
3002
  };
2962
3003
  });
2963
3004
 
3005
+ // dist/builtin/intercom/tool-retry.ts
3006
+ import { setTimeout as delay2 } from "node:timers/promises";
3007
+ async function runIntercomOperation(attempt, release, signal) {
3008
+ const deadline = new AbortController;
3009
+ const timer = setTimeout(() => deadline.abort(), RETRY_IDENTITY_TTL_MS);
3010
+ const operationSignal = signal === undefined ? deadline.signal : AbortSignal.any([signal, deadline.signal]);
3011
+ let token;
3012
+ let recovering = false;
3013
+ let retries = 0;
3014
+ let last = {
3015
+ content: [{ type: "text", text: "Cancelled" }],
3016
+ isError: true,
3017
+ details: { error: true }
3018
+ };
3019
+ try {
3020
+ for (;; ) {
3021
+ if (operationSignal.aborted)
3022
+ break;
3023
+ last = await attempt(token, operationSignal);
3024
+ const { retryToken, retryable, deliveryUncertain, ...details } = last.details;
3025
+ last = { ...last, details };
3026
+ if (!last.isError)
3027
+ return last;
3028
+ recovering ||= deliveryUncertain === true || retryable === true;
3029
+ const nextToken = typeof retryToken === "string" ? retryToken : undefined;
3030
+ const canRetry = nextToken !== undefined || token === undefined && retryable === true;
3031
+ token = nextToken ?? token;
3032
+ if (!canRetry) {
3033
+ if (!recovering && retryable !== true)
3034
+ return last;
3035
+ break;
3036
+ }
3037
+ recovering = true;
3038
+ if (retries >= RETRY_IDENTITY_MAX_REUSES || operationSignal.aborted)
3039
+ break;
3040
+ try {
3041
+ await delay2(RECONNECT_DELAYS_MS[retries], undefined, { signal: operationSignal });
3042
+ } catch {
3043
+ break;
3044
+ }
3045
+ retries += 1;
3046
+ }
3047
+ const reason = operationSignal.aborted ? "Cancelled" : last.content.map(({ text }) => text).join(`
3048
+ `);
3049
+ return {
3050
+ content: [{
3051
+ type: "text",
3052
+ text: recovering ? `${reason}
3053
+ Intercom recovery stopped after ${retries} automatic retries. Delivery may already have occurred. Do not repeat this operation automatically; check with the recipient before intentionally sending a new message.` : reason
3054
+ }],
3055
+ isError: true,
3056
+ details: { error: true, terminal: true, automaticRetries: retries, ...recovering ? { outcome: "unknown" } : {} }
3057
+ };
3058
+ } finally {
3059
+ clearTimeout(timer);
3060
+ if (token !== undefined)
3061
+ release(token);
3062
+ }
3063
+ }
3064
+ var init_tool_retry = __esm(() => {
3065
+ init_retry_identity();
3066
+ init_retry_policy();
3067
+ });
3068
+
2964
3069
  // dist/builtin/intercom/intercom-tool.ts
2965
3070
  import { Type as Type2 } from "typebox";
2966
3071
  import { Text as Text3 } from "@earendil-works/pi-tui";
2967
- function retryTokenGuidance(retryToken, remainingRetries) {
2968
- if (retryToken === undefined)
2969
- return "";
2970
- return ` Retry this exact operation with retryToken \`${retryToken}\` (${remainingRetries} claimed ${remainingRetries === 1 ? "attempt" : "attempts"} remain; the original deadline is unchanged).`;
2971
- }
2972
3072
  function retryErrorDetails(retryToken) {
2973
3073
  return retryToken === undefined ? { error: true } : { error: true, retryToken };
2974
3074
  }
@@ -3086,7 +3186,7 @@ A valid target outside the known set queues speculatively with a \`notInKnownSet
3086
3186
  undeliverable at terminal only if never delivered. Use \`ask\` only for a live, reply-capable target.
3087
3187
  Stage paths win over same-named owned subgroups for send/ask; \`list\` with \`group\` continues to
3088
3188
  select the group.
3089
- If a \`send\`, \`ask\`, or \`reply\` fails with \`Client disconnected\`, retry that exact operation with the returned \`retryToken\`, up to three claimed attempts; a call without the token is always a distinct operation.
3189
+ For send/ask/reply, Intercom retries recoverable disconnects internally up to three times with the same operation identity. Each new tool call is a new operation. If recovery ends with an unknown delivery outcome, do not repeat it automatically.
3090
3190
 
3091
3191
  Usage:
3092
3192
  intercom({ action: "list" }) → List sessions visible through your groups
@@ -3098,14 +3198,13 @@ Usage:
3098
3198
  intercom({ action: "send", to: "session-name", message: "..." }) → Send message (shared group only)
3099
3199
  intercom({ action: "ask", to: "session-name", message: "..." }) → Ask and wait for reply
3100
3200
  intercom({ action: "reply", message: "..." }) → Reply to the active or exact pending ask
3101
- intercom({ action: "send", to: "session-name", message: "...", retryToken: "..." }) → Claim the exact retry returned by a retryable failure
3102
3201
  intercom({ action: "pending" }) → List unresolved inbound asks
3103
3202
  intercom({ action: "status" }) → Show connection status and all your groups
3104
3203
 
3105
3204
  The "join" action is additive. "default" is the shared default group; "true" and
3106
3205
  "auto" are reserved for subagent auto-groups. Ordinary delivery requires at least
3107
3206
  one shared membership; contact_supervisor remains the only cross-group path.`,
3108
- promptSnippet: "Use to coordinate with other local agent sessions that share an intercom group. For a retryable send/ask/reply failure, repeat the exact operation with its returned retryToken; omit retryToken for fresh operations.",
3207
+ promptSnippet: "Use to coordinate with other local agent sessions that share an intercom group. Send/ask/reply retry reconnects internally; do not automatically repeat an unknown delivery outcome.",
3109
3208
  parameters: Type2.Object({
3110
3209
  action: Type2.String({
3111
3210
  description: "Action: 'list', 'groups', 'join', 'leave', 'send', 'ask', 'reply', 'pending', or 'status'"
@@ -3125,78 +3224,25 @@ one shared membership; contact_supervisor remains the only cross-group path.`,
3125
3224
  replyTo: Type2.Optional(Type2.String({
3126
3225
  description: "Exact pending-ask message ID; disambiguates concurrent asks, including asks from one sender"
3127
3226
  })),
3128
- retryToken: Type2.Optional(Type2.String({
3129
- minLength: 1,
3130
- maxLength: 128,
3131
- description: "Opaque token returned after a retryable send/ask/reply failure. Repeat the exact same action and arguments with this token; omit it for every fresh operation."
3132
- })),
3133
3227
  group: Type2.Optional(Type2.String({
3134
3228
  description: "Group name for 'join' or optional targeted 'leave'; read-only group filter for 'list'/'status'. 'send'/'ask' use shared memberships."
3135
3229
  }))
3136
3230
  }),
3137
- async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
3138
- const toolSessionId = ctx.sessionManager.getSessionId();
3139
- const { action, to, message, attachments, replyTo, retryToken, group } = params;
3140
- let retryPreflightRemaining;
3141
- if (retryToken !== undefined) {
3142
- if (action !== "send" && action !== "ask" && action !== "reply") {
3143
- const error = new RetryTokenError("mismatch");
3144
- return {
3145
- content: [{ type: "text", text: getErrorMessage(error) }],
3146
- isError: true,
3147
- details: { error: true }
3148
- };
3149
- }
3150
- try {
3151
- retryPreflightRemaining = retryIdentities.validateRetryToken(retryToken, toolSessionId, action);
3152
- } catch (error) {
3153
- return {
3154
- content: [{ type: "text", text: getErrorMessage(error) }],
3155
- isError: true,
3156
- details: { error: true }
3157
- };
3158
- }
3159
- }
3160
- let connectedClient;
3161
- try {
3162
- connectedClient = await ensureConnected("tool");
3163
- } catch (error) {
3164
- const retainedToken = retryToken !== undefined && isRecoverableIntercomDisconnect(error) ? retryToken : undefined;
3231
+ async execute(_toolCallId, params, signal, _onUpdate, ctx) {
3232
+ if ("retryToken" in params) {
3165
3233
  return {
3166
- content: [{
3167
- type: "text",
3168
- text: `Intercom not connected: ${getErrorMessage(error)}${retryTokenGuidance(retainedToken, retryPreflightRemaining ?? 0)}`
3169
- }],
3234
+ content: [{ type: "text", text: "Intercom manages retries internally. Caller-supplied retry tokens are not supported; this call was not sent." }],
3170
3235
  isError: true,
3171
- details: retryErrorDetails(retainedToken)
3236
+ details: { error: true }
3172
3237
  };
3173
3238
  }
3174
- syncPresenceIdentity(toolSessionId);
3175
- const resolveOwnGroups = (sessions) => {
3176
- if (Array.isArray(connectedClient.groups)) {
3177
- return connectedClient.groups.map((membership) => normalizeGroup(membership));
3178
- }
3179
- const self = sessions?.find((session) => session.id === connectedClient.sessionId);
3180
- return [...normalizeGroups(self?.groups, self?.group)];
3181
- };
3182
- const isOnlyOwnGroup = (candidate, ownGroups) => candidate !== undefined && ownGroups.length === 1 && ownGroups[0] === candidate;
3183
- const requestedGroup = typeof group === "string" && group.trim() ? normalizeGroup(group) : undefined;
3184
- if ((action === "send" || action === "ask") && requestedGroup) {
3185
- const ownGroups = resolveOwnGroups();
3186
- if (!ownGroups.includes(requestedGroup)) {
3187
- return {
3188
- content: [{ type: "text", text: `The 'group' parameter is read-only for 'list'/'status'. '${action}' is always locked to your groups (${ownGroups.join(", ")}); it cannot target group "${requestedGroup}".` }],
3189
- isError: true,
3190
- details: { error: true }
3191
- };
3192
- }
3193
- }
3194
- switch (action) {
3195
- case "join": {
3196
- let targetGroup;
3197
- try {
3198
- targetGroup = validateRuntimeGroup(group);
3199
- } catch (error) {
3239
+ const toolSessionId = ctx.sessionManager.getSessionId();
3240
+ const { action, to, message, replyTo, group } = params;
3241
+ const attachments = params.attachments?.map((attachment) => ({ ...attachment }));
3242
+ const executeAttempt = async (retryToken, _signal) => {
3243
+ if (retryToken !== undefined) {
3244
+ if (action !== "send" && action !== "ask" && action !== "reply") {
3245
+ const error = new RetryTokenError("mismatch");
3200
3246
  return {
3201
3247
  content: [{ type: "text", text: getErrorMessage(error) }],
3202
3248
  isError: true,
@@ -3204,174 +3250,256 @@ one shared membership; contact_supervisor remains the only cross-group path.`,
3204
3250
  };
3205
3251
  }
3206
3252
  try {
3207
- const groups = await connectedClient.joinGroup(targetGroup);
3208
- deps.setJoinedGroups(groups);
3209
- return {
3210
- content: [{ type: "text", text: `Joined intercom group "${targetGroup}". Memberships: ${groups.join(", ")}.` }],
3211
- isError: false,
3212
- details: { group: targetGroup, groups }
3213
- };
3253
+ retryIdentities.validateRetryToken(retryToken, toolSessionId, action);
3214
3254
  } catch (error) {
3215
3255
  return {
3216
- content: [{ type: "text", text: `Failed to join group: ${getErrorMessage(error)}` }],
3256
+ content: [{ type: "text", text: getErrorMessage(error) }],
3217
3257
  isError: true,
3218
3258
  details: { error: true }
3219
3259
  };
3220
3260
  }
3221
3261
  }
3222
- case "leave": {
3223
- let targetGroup;
3224
- let homeGroup;
3225
- try {
3226
- targetGroup = typeof group === "string" && group.trim().length > 0 ? validateRuntimeGroup(group) : undefined;
3227
- if (targetGroup === undefined)
3228
- homeGroup = validateRuntimeGroup(deps.homeGroup());
3229
- } catch (error) {
3262
+ let connectedClient;
3263
+ try {
3264
+ connectedClient = await ensureConnected("tool");
3265
+ } catch (error) {
3266
+ const retainedToken = retryToken !== undefined && isRecoverableIntercomDisconnect(error) ? retryToken : undefined;
3267
+ return {
3268
+ content: [{
3269
+ type: "text",
3270
+ text: `Intercom not connected: ${getErrorMessage(error)}`
3271
+ }],
3272
+ isError: true,
3273
+ details: { ...retryErrorDetails(retainedToken), retryable: isRecoverableIntercomDisconnect(error) }
3274
+ };
3275
+ }
3276
+ syncPresenceIdentity(toolSessionId);
3277
+ const resolveOwnGroups = (sessions) => {
3278
+ if (Array.isArray(connectedClient.groups)) {
3279
+ return connectedClient.groups.map((membership) => normalizeGroup(membership));
3280
+ }
3281
+ const self = sessions?.find((session) => session.id === connectedClient.sessionId);
3282
+ return [...normalizeGroups(self?.groups, self?.group)];
3283
+ };
3284
+ const isOnlyOwnGroup = (candidate, ownGroups) => candidate !== undefined && ownGroups.length === 1 && ownGroups[0] === candidate;
3285
+ const requestedGroup = typeof group === "string" && group.trim() ? normalizeGroup(group) : undefined;
3286
+ if ((action === "send" || action === "ask") && requestedGroup) {
3287
+ const ownGroups = resolveOwnGroups();
3288
+ if (!ownGroups.includes(requestedGroup)) {
3230
3289
  return {
3231
- content: [{ type: "text", text: `Cannot leave intercom group: ${getErrorMessage(error)}` }],
3290
+ content: [{ type: "text", text: `The 'group' parameter is read-only for 'list'/'status'. '${action}' is always locked to your groups (${ownGroups.join(", ")}); it cannot target group "${requestedGroup}".` }],
3232
3291
  isError: true,
3233
3292
  details: { error: true }
3234
3293
  };
3235
3294
  }
3236
- try {
3237
- let groups;
3238
- if (targetGroup === undefined) {
3239
- if (homeGroup === undefined)
3240
- throw new Error("Intercom home group is unavailable");
3241
- await connectedClient.updatePresenceAcked({ groups: [homeGroup] });
3242
- groups = connectedClient.groups;
3243
- deps.clearJoinedGroups();
3244
- } else {
3245
- groups = await connectedClient.leaveGroup(targetGroup);
3295
+ }
3296
+ switch (action) {
3297
+ case "join": {
3298
+ let targetGroup;
3299
+ try {
3300
+ targetGroup = validateRuntimeGroup(group);
3301
+ } catch (error) {
3302
+ return {
3303
+ content: [{ type: "text", text: getErrorMessage(error) }],
3304
+ isError: true,
3305
+ details: { error: true }
3306
+ };
3307
+ }
3308
+ try {
3309
+ const groups = await connectedClient.joinGroup(targetGroup);
3246
3310
  deps.setJoinedGroups(groups);
3311
+ return {
3312
+ content: [{ type: "text", text: `Joined intercom group "${targetGroup}". Memberships: ${groups.join(", ")}.` }],
3313
+ isError: false,
3314
+ details: { group: targetGroup, groups }
3315
+ };
3316
+ } catch (error) {
3317
+ return {
3318
+ content: [{ type: "text", text: `Failed to join group: ${getErrorMessage(error)}` }],
3319
+ isError: true,
3320
+ details: { error: true }
3321
+ };
3247
3322
  }
3248
- const text = targetGroup === undefined ? `Returned to home intercom membership. Memberships: ${groups.join(", ")}.` : `Left intercom group "${targetGroup}". Memberships: ${groups.join(", ")}.`;
3249
- return {
3250
- content: [{ type: "text", text }],
3251
- isError: false,
3252
- details: targetGroup === undefined ? { group: homeGroup, groups } : { groups }
3253
- };
3254
- } catch (error) {
3255
- return {
3256
- content: [{ type: "text", text: `Failed to leave group: ${getErrorMessage(error)}` }],
3257
- isError: true,
3258
- details: { error: true }
3259
- };
3260
3323
  }
3261
- }
3262
- case "groups": {
3263
- try {
3264
- const groups = await connectedClient.listGroups();
3265
- const lines = groups.map(({ group: groupName, sessionCount, member }) => `- ${groupName} — ${sessionCount} session${sessionCount === 1 ? "" : "s"}${member ? " [member]" : ""}`);
3266
- return {
3267
- content: [{ type: "text", text: `**Intercom groups:**
3324
+ case "leave": {
3325
+ let targetGroup;
3326
+ let homeGroup;
3327
+ try {
3328
+ targetGroup = typeof group === "string" && group.trim().length > 0 ? validateRuntimeGroup(group) : undefined;
3329
+ if (targetGroup === undefined)
3330
+ homeGroup = validateRuntimeGroup(deps.homeGroup());
3331
+ } catch (error) {
3332
+ return {
3333
+ content: [{ type: "text", text: `Cannot leave intercom group: ${getErrorMessage(error)}` }],
3334
+ isError: true,
3335
+ details: { error: true }
3336
+ };
3337
+ }
3338
+ try {
3339
+ let groups;
3340
+ if (targetGroup === undefined) {
3341
+ if (homeGroup === undefined)
3342
+ throw new Error("Intercom home group is unavailable");
3343
+ await connectedClient.updatePresenceAcked({ groups: [homeGroup] });
3344
+ groups = connectedClient.groups;
3345
+ deps.clearJoinedGroups();
3346
+ } else {
3347
+ groups = await connectedClient.leaveGroup(targetGroup);
3348
+ deps.setJoinedGroups(groups);
3349
+ }
3350
+ const text = targetGroup === undefined ? `Returned to home intercom membership. Memberships: ${groups.join(", ")}.` : `Left intercom group "${targetGroup}". Memberships: ${groups.join(", ")}.`;
3351
+ return {
3352
+ content: [{ type: "text", text }],
3353
+ isError: false,
3354
+ details: targetGroup === undefined ? { group: homeGroup, groups } : { groups }
3355
+ };
3356
+ } catch (error) {
3357
+ return {
3358
+ content: [{ type: "text", text: `Failed to leave group: ${getErrorMessage(error)}` }],
3359
+ isError: true,
3360
+ details: { error: true }
3361
+ };
3362
+ }
3363
+ }
3364
+ case "groups": {
3365
+ try {
3366
+ const groups = await connectedClient.listGroups();
3367
+ const lines = groups.map(({ group: groupName, sessionCount, member }) => `- ${groupName} — ${sessionCount} session${sessionCount === 1 ? "" : "s"}${member ? " [member]" : ""}`);
3368
+ return {
3369
+ content: [{ type: "text", text: `**Intercom groups:**
3268
3370
  ${lines.join(`
3269
3371
  `)}` }],
3270
- isError: false,
3271
- details: { groups }
3272
- };
3273
- } catch (error) {
3274
- return {
3275
- content: [{ type: "text", text: `Failed to list groups: ${getErrorMessage(error)}` }],
3276
- isError: true,
3277
- details: { error: true }
3278
- };
3279
- }
3280
- }
3281
- case "list": {
3282
- try {
3283
- const mySessionId = connectedClient.sessionId;
3284
- const ownDirectory = await listDirectory(connectedClient);
3285
- const ownSessions = ownDirectory.sessions;
3286
- const currentSession = ownSessions.find((session) => session.id === mySessionId);
3287
- if (!currentSession) {
3372
+ isError: false,
3373
+ details: { groups }
3374
+ };
3375
+ } catch (error) {
3288
3376
  return {
3289
- content: [{ type: "text", text: "Current session is missing from intercom session list." }],
3377
+ content: [{ type: "text", text: `Failed to list groups: ${getErrorMessage(error)}` }],
3290
3378
  isError: true,
3291
3379
  details: { error: true }
3292
3380
  };
3293
3381
  }
3294
- const ownGroups = resolveOwnGroups(ownSessions);
3295
- if (requestedGroup && !isOnlyOwnGroup(requestedGroup, ownGroups)) {
3296
- const peeked = await listDirectory(connectedClient, requestedGroup);
3297
- const rows = [
3298
- ...peeked.sessions.map((session) => formatSessionListRow(session, currentSession.cwd, session.id === mySessionId)),
3299
- ...peeked.workflowStages.map(formatWorkflowStageRow),
3300
- ...(peeked.workflowFutureStages ?? []).map(formatWorkflowFutureStageRow)
3301
- ];
3302
- const section = rows.length === 0 ? `**Group [${requestedGroup}] (read-only peek):**
3382
+ }
3383
+ case "list": {
3384
+ try {
3385
+ const mySessionId = connectedClient.sessionId;
3386
+ const ownDirectory = await listDirectory(connectedClient);
3387
+ const ownSessions = ownDirectory.sessions;
3388
+ const currentSession = ownSessions.find((session) => session.id === mySessionId);
3389
+ if (!currentSession) {
3390
+ return {
3391
+ content: [{ type: "text", text: "Current session is missing from intercom session list." }],
3392
+ isError: true,
3393
+ details: { error: true }
3394
+ };
3395
+ }
3396
+ const ownGroups = resolveOwnGroups(ownSessions);
3397
+ if (requestedGroup && !isOnlyOwnGroup(requestedGroup, ownGroups)) {
3398
+ const peeked = await listDirectory(connectedClient, requestedGroup);
3399
+ const rows = [
3400
+ ...peeked.sessions.map((session) => formatSessionListRow(session, currentSession.cwd, session.id === mySessionId)),
3401
+ ...peeked.workflowStages.map(formatWorkflowStageRow),
3402
+ ...(peeked.workflowFutureStages ?? []).map(formatWorkflowFutureStageRow)
3403
+ ];
3404
+ const section = rows.length === 0 ? `**Group [${requestedGroup}] (read-only peek):**
3303
3405
  No sessions or workflow stages in this group.` : `**Group [${requestedGroup}] (read-only peek):**
3304
3406
  ${rows.join(`
3305
3407
  `)}`;
3306
- return {
3307
- content: [{ type: "text", text: `Your groups: ${ownGroups.join(", ")}
3408
+ return {
3409
+ content: [{ type: "text", text: `Your groups: ${ownGroups.join(", ")}
3308
3410
 
3309
3411
  ${section}` }],
3412
+ isError: false,
3413
+ details: {
3414
+ group: ownGroups.at(-1),
3415
+ groups: ownGroups,
3416
+ peekGroup: requestedGroup,
3417
+ workflowStages: peeked.workflowStages,
3418
+ ...(peeked.workflowFutureStages?.length ?? 0) === 0 ? {} : { workflowFutureStages: peeked.workflowFutureStages }
3419
+ }
3420
+ };
3421
+ }
3422
+ const otherSessions = ownSessions.filter((session) => session.id !== mySessionId);
3423
+ const currentSection = `**Current session** (groups: ${ownGroups.join(", ")}):
3424
+ ${formatSessionListRow(currentSession, currentSession.cwd, true)}`;
3425
+ const visibleRows = [
3426
+ ...otherSessions.map((session) => formatSessionListRow(session, currentSession.cwd, false)),
3427
+ ...ownDirectory.workflowStages.map(formatWorkflowStageRow),
3428
+ ...(ownDirectory.workflowFutureStages ?? []).map(formatWorkflowFutureStageRow)
3429
+ ];
3430
+ const otherSection = visibleRows.length === 0 ? `**Other sessions and workflow stages:**
3431
+ No other sessions or workflow stages share any of your groups.` : `**Other visible sessions and workflow stages:**
3432
+ ${visibleRows.join(`
3433
+ `)}`;
3434
+ return {
3435
+ content: [{ type: "text", text: `${currentSection}
3436
+
3437
+ ${otherSection}` }],
3310
3438
  isError: false,
3311
3439
  details: {
3312
3440
  group: ownGroups.at(-1),
3313
3441
  groups: ownGroups,
3314
- peekGroup: requestedGroup,
3315
- workflowStages: peeked.workflowStages,
3316
- ...(peeked.workflowFutureStages?.length ?? 0) === 0 ? {} : { workflowFutureStages: peeked.workflowFutureStages }
3442
+ ...ownDirectory.workflowStages.length === 0 ? {} : { workflowStages: ownDirectory.workflowStages },
3443
+ ...(ownDirectory.workflowFutureStages?.length ?? 0) === 0 ? {} : { workflowFutureStages: ownDirectory.workflowFutureStages }
3317
3444
  }
3318
3445
  };
3446
+ } catch (error) {
3447
+ return {
3448
+ content: [{ type: "text", text: `Failed to list sessions: ${getErrorMessage(error)}` }],
3449
+ isError: true,
3450
+ details: { error: true }
3451
+ };
3319
3452
  }
3320
- const otherSessions = ownSessions.filter((session) => session.id !== mySessionId);
3321
- const currentSection = `**Current session** (groups: ${ownGroups.join(", ")}):
3322
- ${formatSessionListRow(currentSession, currentSession.cwd, true)}`;
3323
- const visibleRows = [
3324
- ...otherSessions.map((session) => formatSessionListRow(session, currentSession.cwd, false)),
3325
- ...ownDirectory.workflowStages.map(formatWorkflowStageRow),
3326
- ...(ownDirectory.workflowFutureStages ?? []).map(formatWorkflowFutureStageRow)
3327
- ];
3328
- const otherSection = visibleRows.length === 0 ? `**Other sessions and workflow stages:**
3329
- No other sessions or workflow stages share any of your groups.` : `**Other visible sessions and workflow stages:**
3330
- ${visibleRows.join(`
3331
- `)}`;
3332
- return {
3333
- content: [{ type: "text", text: `${currentSection}
3453
+ }
3454
+ case "send": {
3455
+ if (!to || !message) {
3456
+ const errorText = retryToken === undefined ? "Missing 'to' or 'message' parameter" : getErrorMessage(new RetryTokenError("mismatch"));
3457
+ return {
3458
+ content: [{ type: "text", text: errorText }],
3459
+ isError: true,
3460
+ details: { error: true }
3461
+ };
3462
+ }
3463
+ if (_signal?.aborted) {
3464
+ return {
3465
+ content: [{
3466
+ type: "text",
3467
+ text: "Cancelled"
3468
+ }],
3469
+ isError: true,
3470
+ details: retryErrorDetails(retryToken)
3471
+ };
3472
+ }
3473
+ let retryIdentity;
3474
+ try {
3475
+ if (retryToken === undefined) {
3476
+ retryIdentity = retryIdentities.begin({
3477
+ sessionId: toolSessionId,
3478
+ action: "send",
3479
+ target: to,
3480
+ text: message,
3481
+ attachments,
3482
+ replyTo,
3483
+ expectsReply: false
3484
+ });
3485
+ }
3486
+ if (retryToken === undefined && !replyTo && deps.confirmSend && ctx.hasUI) {
3487
+ const attachmentText = attachments?.length ? formatAttachments(attachments) : "";
3488
+ const confirmed = await ctx.ui.confirm("Send Message", `Send to "${to}":
3334
3489
 
3335
- ${otherSection}` }],
3336
- isError: false,
3337
- details: {
3338
- group: ownGroups.at(-1),
3339
- groups: ownGroups,
3340
- ...ownDirectory.workflowStages.length === 0 ? {} : { workflowStages: ownDirectory.workflowStages },
3341
- ...(ownDirectory.workflowFutureStages?.length ?? 0) === 0 ? {} : { workflowFutureStages: ownDirectory.workflowFutureStages }
3490
+ ${message}${attachmentText}`);
3491
+ if (!confirmed) {
3492
+ if (retryIdentity !== undefined)
3493
+ retryIdentities.release(retryIdentity);
3494
+ retryIdentity = undefined;
3495
+ return {
3496
+ content: [{ type: "text", text: "Message cancelled by user" }],
3497
+ isError: false,
3498
+ details: {}
3499
+ };
3500
+ }
3342
3501
  }
3343
- };
3344
- } catch (error) {
3345
- return {
3346
- content: [{ type: "text", text: `Failed to list sessions: ${getErrorMessage(error)}` }],
3347
- isError: true,
3348
- details: { error: true }
3349
- };
3350
- }
3351
- }
3352
- case "send": {
3353
- if (!to || !message) {
3354
- const errorText = retryToken === undefined ? "Missing 'to' or 'message' parameter" : getErrorMessage(new RetryTokenError("mismatch"));
3355
- return {
3356
- content: [{ type: "text", text: errorText }],
3357
- isError: true,
3358
- details: { error: true }
3359
- };
3360
- }
3361
- if (_signal?.aborted) {
3362
- return {
3363
- content: [{
3364
- type: "text",
3365
- text: `Cancelled${retryTokenGuidance(retryToken, retryPreflightRemaining ?? 0)}`
3366
- }],
3367
- isError: true,
3368
- details: retryErrorDetails(retryToken)
3369
- };
3370
- }
3371
- let retryIdentity;
3372
- try {
3373
- if (retryToken === undefined) {
3374
- retryIdentity = retryIdentities.begin({
3502
+ retryIdentity ??= retryIdentities.begin({
3375
3503
  sessionId: toolSessionId,
3376
3504
  action: "send",
3377
3505
  target: to,
@@ -3379,63 +3507,79 @@ ${otherSection}` }],
3379
3507
  attachments,
3380
3508
  replyTo,
3381
3509
  expectsReply: false
3510
+ }, retryToken);
3511
+ const sendTo = await resolveTarget(connectedClient, to) ?? to;
3512
+ if (_signal?.aborted) {
3513
+ const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3514
+ retryIdentity = undefined;
3515
+ return {
3516
+ content: [{ type: "text", text: "Cancelled" }],
3517
+ isError: true,
3518
+ details: retryErrorDetails(retained.retryToken)
3519
+ };
3520
+ }
3521
+ if (sendTo === connectedClient.sessionId) {
3522
+ const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3523
+ retryIdentity = undefined;
3524
+ return {
3525
+ content: [{
3526
+ type: "text",
3527
+ text: "Cannot message the current session"
3528
+ }],
3529
+ isError: true,
3530
+ details: retryErrorDetails(retained.retryToken)
3531
+ };
3532
+ }
3533
+ const result = await connectedClient.send(sendTo, {
3534
+ messageId: retryIdentity.messageId,
3535
+ logicalTarget: to,
3536
+ text: message,
3537
+ attachments,
3538
+ replyTo
3382
3539
  });
3383
- }
3384
- if (!replyTo && deps.confirmSend && ctx.hasUI) {
3385
- const attachmentText = attachments?.length ? formatAttachments(attachments) : "";
3386
- const confirmed = await ctx.ui.confirm("Send Message", `Send to "${to}":
3387
-
3388
- ${message}${attachmentText}`);
3389
- if (!confirmed) {
3390
- if (retryIdentity !== undefined)
3391
- retryIdentities.release(retryIdentity);
3540
+ if (result.queued === true) {
3541
+ retryIdentities.release(retryIdentity);
3392
3542
  retryIdentity = undefined;
3543
+ pi.appendEntry("intercom_sent", {
3544
+ to,
3545
+ message: { text: message, attachments, replyTo },
3546
+ messageId: result.id,
3547
+ timestamp: Date.now()
3548
+ });
3549
+ const notInKnownSet = result.notInKnownSet === true;
3393
3550
  return {
3394
- content: [{ type: "text", text: "Message cancelled by user" }],
3551
+ content: [{
3552
+ type: "text",
3553
+ text: notInKnownSet ? `Message queued for ${to} (not in the workflow's known stage set; it will be delivered to every matching stage that starts before the run terminates)` : `Message queued for ${to}`
3554
+ }],
3395
3555
  isError: false,
3396
- details: {}
3556
+ details: {
3557
+ messageId: result.id,
3558
+ delivered: false,
3559
+ queued: true,
3560
+ target: result.target,
3561
+ position: result.position,
3562
+ ...notInKnownSet ? { notInKnownSet: true } : {}
3563
+ }
3564
+ };
3565
+ }
3566
+ if (!result.delivered) {
3567
+ const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3568
+ retryIdentity = undefined;
3569
+ const errorText = result.reason ?? "Session may not exist or has disconnected.";
3570
+ return {
3571
+ content: [{
3572
+ type: "text",
3573
+ text: `Message to "${to}" was not delivered: ${errorText}`
3574
+ }],
3575
+ isError: true,
3576
+ details: retryToken === undefined ? { messageId: result.id, delivered: false, reason: result.reason } : {
3577
+ delivered: false,
3578
+ reason: result.reason,
3579
+ ...retained.retryToken === undefined ? {} : { retryToken: retained.retryToken }
3580
+ }
3397
3581
  };
3398
3582
  }
3399
- }
3400
- retryIdentity ??= retryIdentities.begin({
3401
- sessionId: toolSessionId,
3402
- action: "send",
3403
- target: to,
3404
- text: message,
3405
- attachments,
3406
- replyTo,
3407
- expectsReply: false
3408
- }, retryToken);
3409
- const sendTo = await resolveTarget(connectedClient, to) ?? to;
3410
- if (_signal?.aborted) {
3411
- const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3412
- retryIdentity = undefined;
3413
- return {
3414
- content: [{ type: "text", text: `Cancelled${retryTokenGuidance(retained.retryToken, retained.remainingRetries)}` }],
3415
- isError: true,
3416
- details: retryErrorDetails(retained.retryToken)
3417
- };
3418
- }
3419
- if (sendTo === connectedClient.sessionId) {
3420
- const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3421
- retryIdentity = undefined;
3422
- return {
3423
- content: [{
3424
- type: "text",
3425
- text: `Cannot message the current session${retryTokenGuidance(retained.retryToken, retained.remainingRetries)}`
3426
- }],
3427
- isError: true,
3428
- details: retryErrorDetails(retained.retryToken)
3429
- };
3430
- }
3431
- const result = await connectedClient.send(sendTo, {
3432
- messageId: retryIdentity.messageId,
3433
- logicalTarget: to,
3434
- text: message,
3435
- attachments,
3436
- replyTo
3437
- });
3438
- if (result.queued === true) {
3439
3583
  retryIdentities.release(retryIdentity);
3440
3584
  retryIdentity = undefined;
3441
3585
  pi.appendEntry("intercom_sent", {
@@ -3444,376 +3588,378 @@ ${message}${attachmentText}`);
3444
3588
  messageId: result.id,
3445
3589
  timestamp: Date.now()
3446
3590
  });
3447
- const notInKnownSet = result.notInKnownSet === true;
3591
+ if (replyTo)
3592
+ activeReplyTracker().markReplied(replyTo);
3448
3593
  return {
3449
- content: [{
3450
- type: "text",
3451
- text: notInKnownSet ? `Message queued for ${to} (not in the workflow's known stage set; it will be delivered to every matching stage that starts before the run terminates)` : `Message queued for ${to}`
3452
- }],
3594
+ content: [{ type: "text", text: `Message sent to ${to}` }],
3453
3595
  isError: false,
3454
- details: {
3455
- messageId: result.id,
3456
- delivered: false,
3457
- queued: true,
3458
- target: result.target,
3459
- position: result.position,
3460
- ...notInKnownSet ? { notInKnownSet: true } : {}
3461
- }
3596
+ details: { messageId: result.id, delivered: true }
3462
3597
  };
3463
- }
3464
- if (!result.delivered) {
3465
- const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3466
- retryIdentity = undefined;
3467
- const errorText = result.reason ?? "Session may not exist or has disconnected.";
3598
+ } catch (error) {
3599
+ let failure = error;
3600
+ let retained;
3601
+ if (retryIdentity !== undefined) {
3602
+ if (isRecoverableIntercomDisconnect(error)) {
3603
+ try {
3604
+ retained = retainRecoverableRetry(retryIdentities, retryIdentity);
3605
+ } catch (retentionError) {
3606
+ failure = retentionError;
3607
+ }
3608
+ } else {
3609
+ retryIdentities.release(retryIdentity);
3610
+ }
3611
+ }
3468
3612
  return {
3469
3613
  content: [{
3470
3614
  type: "text",
3471
- text: `Message to "${to}" was not delivered: ${errorText}${retryTokenGuidance(retained.retryToken, retained.remainingRetries)}`
3615
+ text: `Failed to send: ${getErrorMessage(failure)}`
3472
3616
  }],
3473
3617
  isError: true,
3474
- details: retryToken === undefined ? { messageId: result.id, delivered: false, reason: result.reason } : {
3475
- delivered: false,
3476
- reason: result.reason,
3477
- ...retained.retryToken === undefined ? {} : { retryToken: retained.retryToken }
3478
- }
3618
+ details: { ...retryErrorDetails(retained?.retryToken), retryable: isRecoverableIntercomDisconnect(error) }
3479
3619
  };
3480
3620
  }
3481
- retryIdentities.release(retryIdentity);
3482
- retryIdentity = undefined;
3483
- pi.appendEntry("intercom_sent", {
3484
- to,
3485
- message: { text: message, attachments, replyTo },
3486
- messageId: result.id,
3487
- timestamp: Date.now()
3488
- });
3489
- if (replyTo)
3490
- activeReplyTracker().markReplied(replyTo);
3491
- return {
3492
- content: [{ type: "text", text: `Message sent to ${to}` }],
3493
- isError: false,
3494
- details: { messageId: result.id, delivered: true }
3495
- };
3496
- } catch (error) {
3497
- let failure = error;
3498
- let retained;
3499
- if (retryIdentity !== undefined) {
3500
- if (isRecoverableIntercomDisconnect(error)) {
3501
- try {
3502
- retained = retainRecoverableRetry(retryIdentities, retryIdentity);
3503
- } catch (retentionError) {
3504
- failure = retentionError;
3505
- }
3506
- } else {
3507
- retryIdentities.release(retryIdentity);
3508
- }
3509
- }
3510
- return {
3511
- content: [{
3512
- type: "text",
3513
- text: `Failed to send: ${getErrorMessage(failure)}${retryTokenGuidance(retained?.retryToken, retained?.remainingRetries ?? 0)}`
3514
- }],
3515
- isError: true,
3516
- details: retryErrorDetails(retained?.retryToken)
3517
- };
3518
- }
3519
- }
3520
- case "ask": {
3521
- if (!to) {
3522
- const errorText = retryToken === undefined ? "Missing 'to' or 'message' parameter" : getErrorMessage(new RetryTokenError("mismatch"));
3523
- return {
3524
- content: [{ type: "text", text: errorText }],
3525
- isError: true,
3526
- details: { error: true }
3527
- };
3528
3621
  }
3529
- if (_signal?.aborted) {
3530
- return {
3531
- content: [{
3532
- type: "text",
3533
- text: `Cancelled${retryTokenGuidance(retryToken, retryPreflightRemaining ?? 0)}`
3534
- }],
3535
- isError: true,
3536
- details: retryErrorDetails(retryToken)
3537
- };
3538
- }
3539
- let wait = null;
3540
- let retryIdentity;
3541
- try {
3542
- if (retryToken !== undefined && !message)
3543
- throw new RetryTokenError("mismatch");
3544
- retryIdentity = retryIdentities.begin({
3545
- sessionId: toolSessionId,
3546
- action: "ask",
3547
- target: to,
3548
- text: message ?? "",
3549
- attachments,
3550
- replyTo,
3551
- expectsReply: true
3552
- }, retryToken);
3553
- const metadata = getMetadata();
3554
- const currentSupervisorId = connectedClient.supervisorSessionId ?? undefined;
3555
- const metadataSupervisorId = metadata?.supervisor?.supervisorSessionId;
3556
- const directParentTarget = Boolean(metadata && (to === metadata.orchestratorTarget || to === currentSupervisorId || to === metadataSupervisorId));
3557
- const claimParentAsk = (resolvedTargetId) => Boolean(metadata && requestParentAskHandoff(pi.events, metadata, {
3558
- kind: "intercom",
3559
- question: typeof message === "string" ? message : "",
3560
- attachments,
3561
- resolvedTargetId
3562
- }));
3563
- if (retryToken === undefined && directParentTarget && claimParentAsk(currentSupervisorId ?? metadataSupervisorId ?? to)) {
3564
- retryIdentities.release(retryIdentity);
3565
- retryIdentity = undefined;
3566
- return {
3567
- content: [{ type: "text", text: "Parent ask claimed; this child is ending for a fresh subagent start." }],
3568
- isError: false,
3569
- details: { yielded: true }
3570
- };
3571
- }
3572
- const sendTo = await resolveTarget(connectedClient, to) ?? to;
3573
- if (_signal?.aborted) {
3574
- const retained = retryIdentity === undefined ? undefined : retainInconclusiveRetry(retryIdentities, retryIdentity);
3575
- retryIdentity = undefined;
3622
+ case "ask": {
3623
+ if (!to) {
3624
+ const errorText = retryToken === undefined ? "Missing 'to' or 'message' parameter" : getErrorMessage(new RetryTokenError("mismatch"));
3576
3625
  return {
3577
- content: [{
3578
- type: "text",
3579
- text: `Cancelled${retryTokenGuidance(retained?.retryToken, retained?.remainingRetries ?? 0)}`
3580
- }],
3626
+ content: [{ type: "text", text: errorText }],
3581
3627
  isError: true,
3582
- details: retryErrorDetails(retained?.retryToken)
3628
+ details: { error: true }
3583
3629
  };
3584
3630
  }
3585
- if (sendTo === connectedClient.sessionId) {
3586
- const retained = retryIdentity === undefined ? undefined : retainInconclusiveRetry(retryIdentities, retryIdentity);
3587
- retryIdentity = undefined;
3631
+ if (_signal?.aborted) {
3588
3632
  return {
3589
3633
  content: [{
3590
3634
  type: "text",
3591
- text: `Cannot message the current session${retryTokenGuidance(retained?.retryToken, retained?.remainingRetries ?? 0)}`
3635
+ text: "Cancelled"
3592
3636
  }],
3593
3637
  isError: true,
3594
- details: retryErrorDetails(retained?.retryToken)
3638
+ details: retryErrorDetails(retryToken)
3595
3639
  };
3596
3640
  }
3597
- if (retryToken === undefined && metadata && !directParentTarget) {
3598
- const authoritativeParent = [currentSupervisorId, metadataSupervisorId].find((candidate) => candidate === sendTo);
3599
- const resolvedParent = authoritativeParent ?? await resolveTarget(connectedClient, metadata.orchestratorTarget);
3600
- if (resolvedParent !== null && resolvedParent === sendTo && claimParentAsk(sendTo)) {
3641
+ let wait = null;
3642
+ let retryIdentity;
3643
+ let askDelivered = false;
3644
+ try {
3645
+ retryIdentity = retryIdentities.begin({
3646
+ sessionId: toolSessionId,
3647
+ action: "ask",
3648
+ target: to,
3649
+ text: message ?? "",
3650
+ attachments,
3651
+ replyTo,
3652
+ expectsReply: true
3653
+ }, retryToken);
3654
+ const metadata = getMetadata();
3655
+ const currentSupervisorId = connectedClient.supervisorSessionId ?? undefined;
3656
+ const metadataSupervisorId = metadata?.supervisor?.supervisorSessionId;
3657
+ const directParentTarget = Boolean(metadata && (to === metadata.orchestratorTarget || to === currentSupervisorId || to === metadataSupervisorId));
3658
+ let parentTarget = directParentTarget;
3659
+ const claimParentAsk = (resolvedTargetId) => Boolean(metadata && requestParentAskHandoff(pi.events, metadata, {
3660
+ kind: "intercom",
3661
+ question: typeof message === "string" ? message : "",
3662
+ attachments: params.attachments,
3663
+ resolvedTargetId
3664
+ }));
3665
+ if (retryToken === undefined && directParentTarget && claimParentAsk(currentSupervisorId ?? metadataSupervisorId ?? to)) {
3666
+ retryIdentities.release(retryIdentity);
3667
+ retryIdentity = undefined;
3668
+ return {
3669
+ content: [{ type: "text", text: "Parent ask claimed; this child is ending for a fresh subagent start." }],
3670
+ isError: false,
3671
+ details: { yielded: true }
3672
+ };
3673
+ }
3674
+ const sendTo = await resolveTarget(connectedClient, to) ?? to;
3675
+ if (_signal?.aborted) {
3676
+ const retained = retryIdentity === undefined ? undefined : retainInconclusiveRetry(retryIdentities, retryIdentity);
3677
+ retryIdentity = undefined;
3678
+ return {
3679
+ content: [{
3680
+ type: "text",
3681
+ text: "Cancelled"
3682
+ }],
3683
+ isError: true,
3684
+ details: retryErrorDetails(retained?.retryToken)
3685
+ };
3686
+ }
3687
+ if (sendTo === connectedClient.sessionId) {
3688
+ const retained = retryIdentity === undefined ? undefined : retainInconclusiveRetry(retryIdentities, retryIdentity);
3689
+ retryIdentity = undefined;
3690
+ return {
3691
+ content: [{
3692
+ type: "text",
3693
+ text: "Cannot message the current session"
3694
+ }],
3695
+ isError: true,
3696
+ details: retryErrorDetails(retained?.retryToken)
3697
+ };
3698
+ }
3699
+ if (metadata && !directParentTarget) {
3700
+ const authoritativeParent = [currentSupervisorId, metadataSupervisorId].find((candidate) => candidate === sendTo);
3701
+ const resolvedParent = authoritativeParent ?? await resolveTarget(connectedClient, metadata.orchestratorTarget);
3702
+ parentTarget = resolvedParent !== null && resolvedParent === sendTo;
3703
+ if (retryToken === undefined && parentTarget && claimParentAsk(sendTo)) {
3704
+ retryIdentities.release(retryIdentity);
3705
+ retryIdentity = undefined;
3706
+ return {
3707
+ content: [{ type: "text", text: "Parent ask claimed; this child is ending for a fresh subagent start." }],
3708
+ isError: false,
3709
+ details: { yielded: true }
3710
+ };
3711
+ }
3712
+ }
3713
+ if (!message && !parentTarget) {
3714
+ retryIdentities.release(retryIdentity);
3715
+ retryIdentity = undefined;
3716
+ return {
3717
+ content: [{ type: "text", text: "Missing 'to' or 'message' parameter" }],
3718
+ isError: true,
3719
+ details: { error: true }
3720
+ };
3721
+ }
3722
+ const replySender = await resolveReplySender(connectedClient, to, sendTo);
3723
+ if (replySender.kind === "ambiguous") {
3724
+ const retained = retryIdentity === undefined ? undefined : retainInconclusiveRetry(retryIdentities, retryIdentity);
3725
+ retryIdentity = undefined;
3726
+ return {
3727
+ content: [{
3728
+ type: "text",
3729
+ text: `Message to "${to}" is ambiguous: ${replySender.reason}. Use the exact target shown by intercom list.`
3730
+ }],
3731
+ isError: true,
3732
+ details: retryErrorDetails(retained?.retryToken)
3733
+ };
3734
+ }
3735
+ const questionId = retryIdentity.messageId;
3736
+ const replyFrom = replySender.kind === "resolved" ? replySender.sessionId : sendTo;
3737
+ const admission = beginReplyWait(replyFrom, questionId, _signal);
3738
+ if (!admission.ok) {
3739
+ const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3740
+ retryIdentity = undefined;
3741
+ const text = admission.reason === "busy" ? `Too many pending asks (${admission.limit}); reply-wait slots are full` : "Cancelled";
3742
+ return {
3743
+ content: [{
3744
+ type: "text",
3745
+ text
3746
+ }],
3747
+ isError: true,
3748
+ details: retryErrorDetails(retained.retryToken)
3749
+ };
3750
+ }
3751
+ wait = admission.wait;
3752
+ const sendResult = await connectedClient.send(sendTo, {
3753
+ messageId: questionId,
3754
+ logicalTarget: to,
3755
+ text: message ?? "",
3756
+ attachments,
3757
+ replyTo,
3758
+ expectsReply: true
3759
+ });
3760
+ if (sendResult.queued === true) {
3601
3761
  retryIdentities.release(retryIdentity);
3602
3762
  retryIdentity = undefined;
3763
+ wait.cancel(new Error(`Message queued for ${to}`));
3764
+ pi.appendEntry("intercom_sent", {
3765
+ to,
3766
+ message: { text: message, attachments, replyTo },
3767
+ messageId: sendResult.id,
3768
+ timestamp: Date.now()
3769
+ });
3603
3770
  return {
3604
- content: [{ type: "text", text: "Parent ask claimed; this child is ending for a fresh subagent start." }],
3771
+ content: [{ type: "text", text: `Message queued for ${to}` }],
3605
3772
  isError: false,
3606
- details: { yielded: true }
3773
+ details: {
3774
+ messageId: sendResult.id,
3775
+ delivered: false,
3776
+ queued: true,
3777
+ target: sendResult.target,
3778
+ position: sendResult.position
3779
+ }
3607
3780
  };
3608
3781
  }
3609
- }
3610
- if (!message) {
3611
- retryIdentities.release(retryIdentity);
3612
- retryIdentity = undefined;
3613
- return {
3614
- content: [{ type: "text", text: "Missing 'to' or 'message' parameter" }],
3615
- isError: true,
3616
- details: { error: true }
3617
- };
3618
- }
3619
- const replySender = await resolveReplySender(connectedClient, to, sendTo);
3620
- if (replySender.kind === "ambiguous") {
3621
- const retained = retryIdentity === undefined ? undefined : retainInconclusiveRetry(retryIdentities, retryIdentity);
3622
- retryIdentity = undefined;
3623
- return {
3624
- content: [{
3625
- type: "text",
3626
- text: `Message to "${to}" is ambiguous: ${replySender.reason}. Use the exact target shown by intercom list.${retryTokenGuidance(retained?.retryToken, retained?.remainingRetries ?? 0)}`
3627
- }],
3628
- isError: true,
3629
- details: retryErrorDetails(retained?.retryToken)
3630
- };
3631
- }
3632
- const questionId = retryIdentity.messageId;
3633
- const replyFrom = replySender.kind === "resolved" ? replySender.sessionId : sendTo;
3634
- const admission = beginReplyWait(replyFrom, questionId, _signal);
3635
- if (!admission.ok) {
3636
- const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3637
- retryIdentity = undefined;
3638
- const text = admission.reason === "busy" ? `Too many pending asks (${admission.limit}); reply-wait slots are full` : "Cancelled";
3639
- return {
3640
- content: [{
3641
- type: "text",
3642
- text: `${text}${retryTokenGuidance(retained.retryToken, retained.remainingRetries)}`
3643
- }],
3644
- isError: true,
3645
- details: retryErrorDetails(retained.retryToken)
3646
- };
3647
- }
3648
- wait = admission.wait;
3649
- const sendResult = await connectedClient.send(sendTo, {
3650
- messageId: questionId,
3651
- logicalTarget: to,
3652
- text: message,
3653
- attachments,
3654
- replyTo,
3655
- expectsReply: true
3656
- });
3657
- if (sendResult.queued === true) {
3658
- retryIdentities.release(retryIdentity);
3659
- retryIdentity = undefined;
3660
- wait.cancel(new Error(`Message queued for ${to}`));
3782
+ if (!sendResult.delivered) {
3783
+ const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3784
+ retryIdentity = undefined;
3785
+ const errorText = sendResult.reason ?? "Session may not exist or has disconnected.";
3786
+ wait.cancel(new Error(`Message to "${to}" was not delivered: ${errorText}`));
3787
+ const pendingStageAskRefusal = errorText.startsWith("Cannot ask a workflow stage whose session has not initialized.");
3788
+ return {
3789
+ content: [{
3790
+ type: "text",
3791
+ text: `Message to "${to}" was not delivered: ${errorText}`
3792
+ }],
3793
+ isError: true,
3794
+ details: {
3795
+ ...pendingStageAskRefusal ? {
3796
+ refusal: "pending_stage_ask_unsupported",
3797
+ recommendedAction: "send",
3798
+ reason: errorText
3799
+ } : {},
3800
+ ...retryErrorDetails(retained.retryToken)
3801
+ }
3802
+ };
3803
+ }
3804
+ askDelivered = true;
3661
3805
  pi.appendEntry("intercom_sent", {
3662
3806
  to,
3663
3807
  message: { text: message, attachments, replyTo },
3664
3808
  messageId: sendResult.id,
3665
3809
  timestamp: Date.now()
3666
3810
  });
3811
+ const replyMessage = await wait.promise;
3812
+ retryIdentities.release(retryIdentity);
3813
+ retryIdentity = undefined;
3814
+ const replyText = replyMessage.content.text;
3815
+ const replyAttachments = replyMessage.content.attachments?.length ? formatAttachments(replyMessage.content.attachments) : "";
3816
+ pi.appendEntry("intercom_received", {
3817
+ from: to,
3818
+ message: { text: replyText, attachments: replyMessage.content.attachments },
3819
+ messageId: replyMessage.id,
3820
+ timestamp: replyMessage.timestamp
3821
+ });
3822
+ if (replyMessage.replyError !== undefined) {
3823
+ return {
3824
+ content: [{ type: "text", text: `Failed: ${replyMessage.replyError}` }],
3825
+ isError: true,
3826
+ details: { error: true, replyTo: replyMessage.replyTo }
3827
+ };
3828
+ }
3667
3829
  return {
3668
- content: [{ type: "text", text: `Message queued for ${to}` }],
3830
+ content: [{ type: "text", text: `**Reply from ${to}:**
3831
+ ${replyText}${replyAttachments}` }],
3669
3832
  isError: false,
3670
- details: {
3671
- messageId: sendResult.id,
3672
- delivered: false,
3673
- queued: true,
3674
- target: sendResult.target,
3675
- position: sendResult.position
3676
- }
3833
+ details: {}
3677
3834
  };
3678
- }
3679
- if (!sendResult.delivered) {
3680
- const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3681
- retryIdentity = undefined;
3682
- const errorText = sendResult.reason ?? "Session may not exist or has disconnected.";
3683
- wait.cancel(new Error(`Message to "${to}" was not delivered: ${errorText}`));
3684
- const pendingStageAskRefusal = errorText.startsWith("Cannot ask a workflow stage whose session has not initialized.");
3835
+ } catch (error) {
3836
+ wait?.cancel(toError3(error));
3837
+ let failure = error;
3838
+ let retained;
3839
+ if (retryIdentity !== undefined) {
3840
+ if (isRecoverableIntercomDisconnect(error)) {
3841
+ try {
3842
+ retained = retainRecoverableRetry(retryIdentities, retryIdentity);
3843
+ } catch (retentionError) {
3844
+ failure = retentionError;
3845
+ }
3846
+ } else {
3847
+ retryIdentities.release(retryIdentity);
3848
+ }
3849
+ }
3685
3850
  return {
3686
3851
  content: [{
3687
3852
  type: "text",
3688
- text: `Message to "${to}" was not delivered: ${errorText}${retryTokenGuidance(retained.retryToken, retained.remainingRetries)}`
3853
+ text: `Failed: ${getErrorMessage(failure)}`
3689
3854
  }],
3690
3855
  isError: true,
3691
- details: {
3692
- ...pendingStageAskRefusal ? {
3693
- refusal: "pending_stage_ask_unsupported",
3694
- recommendedAction: "send",
3695
- reason: errorText
3696
- } : {},
3697
- ...retryErrorDetails(retained.retryToken)
3698
- }
3699
- };
3700
- }
3701
- pi.appendEntry("intercom_sent", {
3702
- to,
3703
- message: { text: message, attachments, replyTo },
3704
- messageId: sendResult.id,
3705
- timestamp: Date.now()
3706
- });
3707
- const replyMessage = await wait.promise;
3708
- retryIdentities.release(retryIdentity);
3709
- retryIdentity = undefined;
3710
- const replyText = replyMessage.content.text;
3711
- const replyAttachments = replyMessage.content.attachments?.length ? formatAttachments(replyMessage.content.attachments) : "";
3712
- pi.appendEntry("intercom_received", {
3713
- from: to,
3714
- message: { text: replyText, attachments: replyMessage.content.attachments },
3715
- messageId: replyMessage.id,
3716
- timestamp: replyMessage.timestamp
3717
- });
3718
- if (replyMessage.replyError !== undefined) {
3719
- return {
3720
- content: [{ type: "text", text: `Failed: ${replyMessage.replyError}` }],
3721
- isError: true,
3722
- details: { error: true, replyTo: replyMessage.replyTo }
3856
+ details: { ...retryErrorDetails(retained?.retryToken), retryable: isRecoverableIntercomDisconnect(error), deliveryUncertain: askDelivered }
3723
3857
  };
3724
3858
  }
3725
- return {
3726
- content: [{ type: "text", text: `**Reply from ${to}:**
3727
- ${replyText}${replyAttachments}` }],
3728
- isError: false,
3729
- details: {}
3730
- };
3731
- } catch (error) {
3732
- wait?.cancel(toError3(error));
3733
- let failure = error;
3734
- let retained;
3735
- if (retryIdentity !== undefined) {
3736
- if (isRecoverableIntercomDisconnect(error)) {
3737
- try {
3738
- retained = retainRecoverableRetry(retryIdentities, retryIdentity);
3739
- } catch (retentionError) {
3740
- failure = retentionError;
3741
- }
3742
- } else {
3743
- retryIdentities.release(retryIdentity);
3744
- }
3745
- }
3746
- return {
3747
- content: [{
3748
- type: "text",
3749
- text: `Failed: ${getErrorMessage(failure)}${retryTokenGuidance(retained?.retryToken, retained?.remainingRetries ?? 0)}`
3750
- }],
3751
- isError: true,
3752
- details: retryErrorDetails(retained?.retryToken)
3753
- };
3754
- }
3755
- }
3756
- case "reply": {
3757
- if (!message) {
3758
- const errorText = retryToken === undefined ? "Missing 'message' parameter" : getErrorMessage(new RetryTokenError("mismatch"));
3759
- return {
3760
- content: [{ type: "text", text: errorText }],
3761
- isError: true,
3762
- details: { error: true }
3763
- };
3764
3859
  }
3765
- let retryIdentity;
3766
- try {
3767
- retryIdentity = retryIdentities.begin({
3768
- sessionId: toolSessionId,
3769
- action: "reply",
3770
- target: to,
3771
- text: message,
3772
- attachments,
3773
- replyTo,
3774
- expectsReply: false
3775
- }, retryToken);
3776
- if (retryToken === undefined) {
3777
- const target = activeReplyTracker().resolveReplyTarget({ to, replyTo });
3778
- retryIdentities.bindReplyRoute(retryIdentity, {
3779
- senderId: target.from.id,
3780
- ...target.from.name === undefined ? {} : { senderName: target.from.name },
3781
- messageId: target.message.id,
3782
- expectsReply: target.message.expectsReply === true
3783
- });
3784
- }
3785
- const route = retryIdentities.replyRoute(retryIdentity);
3786
- if (route === undefined)
3787
- throw new RetryTokenError("invalid");
3788
- const replySendTo = to ?? route.senderId;
3789
- const replyLogicalTarget = to ?? route.senderId;
3790
- const displayTarget = route.senderName || route.senderId;
3791
- if (route.senderId === connectedClient.sessionId) {
3792
- const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3793
- retryIdentity = undefined;
3860
+ case "reply": {
3861
+ if (!message) {
3862
+ const errorText = retryToken === undefined ? "Missing 'message' parameter" : getErrorMessage(new RetryTokenError("mismatch"));
3794
3863
  return {
3795
- content: [{
3796
- type: "text",
3797
- text: `Cannot message the current session${retryTokenGuidance(retained.retryToken, retained.remainingRetries)}`
3798
- }],
3864
+ content: [{ type: "text", text: errorText }],
3799
3865
  isError: true,
3800
- details: retryErrorDetails(retained.retryToken)
3866
+ details: { error: true }
3801
3867
  };
3802
3868
  }
3803
- const replyMessageId = retryIdentity.messageId;
3804
- const sendReply = (targetId) => connectedClient.send(targetId, {
3805
- messageId: replyMessageId,
3806
- logicalTarget: replyLogicalTarget,
3807
- ...route.expectsReply ? { requirePendingReply: true } : {},
3808
- text: message,
3809
- attachments,
3810
- replyTo: route.messageId
3811
- });
3812
- let result = await sendReply(replySendTo);
3813
- if (to === undefined && result.delivered === false && result.reasonCode === "session_not_found" && route.senderName !== undefined) {
3814
- result = await sendReply(route.senderName);
3869
+ if (_signal?.aborted) {
3870
+ return { content: [{ type: "text", text: "Cancelled" }], isError: true, details: retryErrorDetails(retryToken) };
3815
3871
  }
3816
- if (result.queued === true) {
3872
+ let retryIdentity;
3873
+ try {
3874
+ retryIdentity = retryIdentities.begin({
3875
+ sessionId: toolSessionId,
3876
+ action: "reply",
3877
+ target: to,
3878
+ text: message,
3879
+ attachments,
3880
+ replyTo,
3881
+ expectsReply: false
3882
+ }, retryToken);
3883
+ if (retryToken === undefined) {
3884
+ const target = activeReplyTracker().resolveReplyTarget({ to, replyTo });
3885
+ retryIdentities.bindReplyRoute(retryIdentity, {
3886
+ senderId: target.from.id,
3887
+ ...target.from.name === undefined ? {} : { senderName: target.from.name },
3888
+ messageId: target.message.id,
3889
+ expectsReply: target.message.expectsReply === true
3890
+ });
3891
+ }
3892
+ const route = retryIdentities.replyRoute(retryIdentity);
3893
+ if (route === undefined)
3894
+ throw new RetryTokenError("invalid");
3895
+ const replySendTo = to ?? route.senderId;
3896
+ const replyLogicalTarget = to ?? route.senderId;
3897
+ const displayTarget = route.senderName || route.senderId;
3898
+ if (route.senderId === connectedClient.sessionId) {
3899
+ const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3900
+ retryIdentity = undefined;
3901
+ return {
3902
+ content: [{
3903
+ type: "text",
3904
+ text: "Cannot message the current session"
3905
+ }],
3906
+ isError: true,
3907
+ details: retryErrorDetails(retained.retryToken)
3908
+ };
3909
+ }
3910
+ const replyMessageId = retryIdentity.messageId;
3911
+ const sendReply = (targetId) => connectedClient.send(targetId, {
3912
+ messageId: replyMessageId,
3913
+ logicalTarget: replyLogicalTarget,
3914
+ ...route.expectsReply ? { requirePendingReply: true } : {},
3915
+ text: message,
3916
+ attachments,
3917
+ replyTo: route.messageId
3918
+ });
3919
+ let result = await sendReply(replySendTo);
3920
+ if (to === undefined && result.delivered === false && result.reasonCode === "session_not_found" && route.senderName !== undefined) {
3921
+ result = await sendReply(route.senderName);
3922
+ }
3923
+ if (result.queued === true) {
3924
+ retryIdentities.release(retryIdentity);
3925
+ retryIdentity = undefined;
3926
+ activeReplyTracker().markReplied(route.messageId);
3927
+ pi.appendEntry("intercom_sent", {
3928
+ to: displayTarget,
3929
+ message: { text: message, attachments, replyTo: route.messageId },
3930
+ messageId: result.id,
3931
+ timestamp: Date.now()
3932
+ });
3933
+ return {
3934
+ content: [{ type: "text", text: `Reply queued for ${displayTarget}` }],
3935
+ isError: false,
3936
+ details: {
3937
+ messageId: result.id,
3938
+ delivered: false,
3939
+ queued: true,
3940
+ replyTo: route.messageId,
3941
+ target: result.target,
3942
+ position: result.position
3943
+ }
3944
+ };
3945
+ }
3946
+ if (!result.delivered) {
3947
+ const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3948
+ retryIdentity = undefined;
3949
+ const errorText = result.reason ?? "Session may not exist or has disconnected.";
3950
+ return {
3951
+ content: [{
3952
+ type: "text",
3953
+ text: `Reply to "${displayTarget}" was not delivered: ${errorText}`
3954
+ }],
3955
+ isError: true,
3956
+ details: retryToken === undefined ? { messageId: result.id, delivered: false, reason: result.reason } : {
3957
+ delivered: false,
3958
+ reason: result.reason,
3959
+ ...retained.retryToken === undefined ? {} : { retryToken: retained.retryToken }
3960
+ }
3961
+ };
3962
+ }
3817
3963
  retryIdentities.release(retryIdentity);
3818
3964
  retryIdentity = undefined;
3819
3965
  activeReplyTracker().markReplied(route.messageId);
@@ -3824,136 +3970,101 @@ ${replyText}${replyAttachments}` }],
3824
3970
  timestamp: Date.now()
3825
3971
  });
3826
3972
  return {
3827
- content: [{ type: "text", text: `Reply queued for ${displayTarget}` }],
3973
+ content: [{ type: "text", text: `Reply sent to ${displayTarget}` }],
3828
3974
  isError: false,
3829
- details: {
3830
- messageId: result.id,
3831
- delivered: false,
3832
- queued: true,
3833
- replyTo: route.messageId,
3834
- target: result.target,
3835
- position: result.position
3836
- }
3975
+ details: { messageId: result.id, delivered: true, replyTo: route.messageId }
3837
3976
  };
3838
- }
3839
- if (!result.delivered) {
3840
- const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3841
- retryIdentity = undefined;
3842
- const errorText = result.reason ?? "Session may not exist or has disconnected.";
3977
+ } catch (error) {
3978
+ let failure = error;
3979
+ let retained;
3980
+ if (retryIdentity !== undefined) {
3981
+ if (isRecoverableIntercomDisconnect(error)) {
3982
+ try {
3983
+ retained = retainRecoverableRetry(retryIdentities, retryIdentity);
3984
+ } catch (retentionError) {
3985
+ failure = retentionError;
3986
+ }
3987
+ } else {
3988
+ retryIdentities.release(retryIdentity);
3989
+ }
3990
+ }
3843
3991
  return {
3844
3992
  content: [{
3845
3993
  type: "text",
3846
- text: `Reply to "${displayTarget}" was not delivered: ${errorText}${retryTokenGuidance(retained.retryToken, retained.remainingRetries)}`
3994
+ text: `Failed to reply: ${getErrorMessage(failure)}`
3847
3995
  }],
3848
3996
  isError: true,
3849
- details: retryToken === undefined ? { messageId: result.id, delivered: false, reason: result.reason } : {
3850
- delivered: false,
3851
- reason: result.reason,
3852
- ...retained.retryToken === undefined ? {} : { retryToken: retained.retryToken }
3853
- }
3997
+ details: { ...retryErrorDetails(retained?.retryToken), retryable: isRecoverableIntercomDisconnect(error) }
3854
3998
  };
3855
3999
  }
3856
- retryIdentities.release(retryIdentity);
3857
- retryIdentity = undefined;
3858
- activeReplyTracker().markReplied(route.messageId);
3859
- pi.appendEntry("intercom_sent", {
3860
- to: displayTarget,
3861
- message: { text: message, attachments, replyTo: route.messageId },
3862
- messageId: result.id,
3863
- timestamp: Date.now()
3864
- });
3865
- return {
3866
- content: [{ type: "text", text: `Reply sent to ${displayTarget}` }],
3867
- isError: false,
3868
- details: { messageId: result.id, delivered: true, replyTo: route.messageId }
3869
- };
3870
- } catch (error) {
3871
- let failure = error;
3872
- let retained;
3873
- if (retryIdentity !== undefined) {
3874
- if (isRecoverableIntercomDisconnect(error)) {
3875
- try {
3876
- retained = retainRecoverableRetry(retryIdentities, retryIdentity);
3877
- } catch (retentionError) {
3878
- failure = retentionError;
3879
- }
3880
- } else {
3881
- retryIdentities.release(retryIdentity);
3882
- }
3883
- }
3884
- return {
3885
- content: [{
3886
- type: "text",
3887
- text: `Failed to reply: ${getErrorMessage(failure)}${retryTokenGuidance(retained?.retryToken, retained?.remainingRetries ?? 0)}`
3888
- }],
3889
- isError: true,
3890
- details: retryErrorDetails(retained?.retryToken)
3891
- };
3892
4000
  }
3893
- }
3894
- case "pending": {
3895
- const pendingAsks = activeReplyTracker().listPending();
3896
- if (pendingAsks.length === 0) {
4001
+ case "pending": {
4002
+ const pendingAsks = activeReplyTracker().listPending();
4003
+ if (pendingAsks.length === 0) {
4004
+ return {
4005
+ content: [{ type: "text", text: "No unresolved inbound asks." }],
4006
+ isError: false,
4007
+ details: {}
4008
+ };
4009
+ }
4010
+ const now = Date.now();
4011
+ const lines = pendingAsks.map(({ from, message, receivedAt }) => {
4012
+ const preview = message.content.text.replace(/\s+/g, " ").slice(0, 80);
4013
+ const elapsedSeconds = Math.max(0, Math.floor((now - receivedAt) / 1000));
4014
+ return `- ${from.name || from.id} · ${message.id} · ${elapsedSeconds}s ago · ${preview}`;
4015
+ });
3897
4016
  return {
3898
- content: [{ type: "text", text: "No unresolved inbound asks." }],
4017
+ content: [{ type: "text", text: `**Pending asks:**
4018
+ ${lines.join(`
4019
+ `)}` }],
3899
4020
  isError: false,
3900
4021
  details: {}
3901
4022
  };
3902
4023
  }
3903
- const now = Date.now();
3904
- const lines = pendingAsks.map(({ from, message: message2, receivedAt }) => {
3905
- const preview = message2.content.text.replace(/\s+/g, " ").slice(0, 80);
3906
- const elapsedSeconds = Math.max(0, Math.floor((now - receivedAt) / 1000));
3907
- return `- ${from.name || from.id} · ${message2.id} · ${elapsedSeconds}s ago · ${preview}`;
3908
- });
3909
- return {
3910
- content: [{ type: "text", text: `**Pending asks:**
3911
- ${lines.join(`
3912
- `)}` }],
3913
- isError: false,
3914
- details: {}
3915
- };
3916
- }
3917
- case "status": {
3918
- try {
3919
- const mySessionId = connectedClient.sessionId;
3920
- const sessions = await connectedClient.listSessions();
3921
- const ownGroups = resolveOwnGroups(sessions);
3922
- const selectedGroup = isOnlyOwnGroup(requestedGroup, ownGroups) ? undefined : requestedGroup;
3923
- const selectedGroupSessions = selectedGroup === undefined ? undefined : await connectedClient.listSessions(selectedGroup);
3924
- const selectedSection = selectedGroupSessions === undefined ? "" : `
4024
+ case "status": {
4025
+ try {
4026
+ const mySessionId = connectedClient.sessionId;
4027
+ const sessions = await connectedClient.listSessions();
4028
+ const ownGroups = resolveOwnGroups(sessions);
4029
+ const selectedGroup = isOnlyOwnGroup(requestedGroup, ownGroups) ? undefined : requestedGroup;
4030
+ const selectedGroupSessions = selectedGroup === undefined ? undefined : await connectedClient.listSessions(selectedGroup);
4031
+ const selectedSection = selectedGroupSessions === undefined ? "" : `
3925
4032
  Selected group [${selectedGroup}]: ${selectedGroupSessions.length} session(s)`;
3926
- return {
3927
- content: [{
3928
- type: "text",
3929
- text: `**Intercom Status:**
4033
+ return {
4034
+ content: [{
4035
+ type: "text",
4036
+ text: `**Intercom Status:**
3930
4037
  Connected: Yes
3931
4038
  Session ID: ${mySessionId}
3932
4039
  Groups: ${ownGroups.join(", ")}
3933
4040
  Active visible sessions: ${sessions.length}${selectedSection}`
3934
- }],
3935
- isError: false,
3936
- details: {
3937
- group: ownGroups.at(-1),
3938
- groups: ownGroups,
3939
- ...selectedGroup === undefined ? {} : { selectedGroup, selectedGroupSessionCount: selectedGroupSessions?.length ?? 0 }
3940
- }
3941
- };
3942
- } catch (error) {
4041
+ }],
4042
+ isError: false,
4043
+ details: {
4044
+ group: ownGroups.at(-1),
4045
+ groups: ownGroups,
4046
+ ...selectedGroup === undefined ? {} : { selectedGroup, selectedGroupSessionCount: selectedGroupSessions?.length ?? 0 }
4047
+ }
4048
+ };
4049
+ } catch (error) {
4050
+ return {
4051
+ content: [{ type: "text", text: `Failed to get status: ${getErrorMessage(error)}` }],
4052
+ isError: true,
4053
+ details: { error: true }
4054
+ };
4055
+ }
4056
+ }
4057
+ default:
3943
4058
  return {
3944
- content: [{ type: "text", text: `Failed to get status: ${getErrorMessage(error)}` }],
4059
+ content: [{ type: "text", text: `Unknown action: ${action}` }],
3945
4060
  isError: true,
3946
4061
  details: { error: true }
3947
4062
  };
3948
- }
3949
4063
  }
3950
- default:
3951
- return {
3952
- content: [{ type: "text", text: `Unknown action: ${action}` }],
3953
- isError: true,
3954
- details: { error: true }
3955
- };
3956
- }
4064
+ };
4065
+ if (action !== "send" && action !== "ask" && action !== "reply")
4066
+ return executeAttempt(undefined, signal);
4067
+ return runIntercomOperation(executeAttempt, (token) => retryIdentities.discard(token), signal);
3957
4068
  },
3958
4069
  renderCall(args, theme) {
3959
4070
  const action = typeof args.action === "string" ? args.action : "intercom";
@@ -3985,6 +4096,7 @@ var init_intercom_tool = __esm(() => {
3985
4096
  init_workflow_stage_target();
3986
4097
  init_recoverable_disconnect();
3987
4098
  init_retry_identity();
4099
+ init_tool_retry();
3988
4100
  });
3989
4101
 
3990
4102
  // dist/builtin/intercom/ui/compose.ts
@@ -4564,12 +4676,12 @@ function prepareDurableAuthority(storagePath) {
4564
4676
  if (databaseExists !== keyExists)
4565
4677
  return;
4566
4678
  if (!databaseExists) {
4567
- const key2 = randomBytes(AUTHORITY_KEY_BYTES);
4568
- writeFileSync2(keyPath, key2, { flag: "wx", mode: 384 });
4679
+ const key = randomBytes(AUTHORITY_KEY_BYTES);
4680
+ writeFileSync2(keyPath, key, { flag: "wx", mode: 384 });
4569
4681
  const databaseDescriptor = openSync2(storagePath, "wx", 384);
4570
4682
  closeSync2(databaseDescriptor);
4571
4683
  restrictExistingAuthorityArtifacts(storagePath, keyPath);
4572
- return key2;
4684
+ return key;
4573
4685
  }
4574
4686
  const key = readFileSync3(keyPath);
4575
4687
  if (key.length !== AUTHORITY_KEY_BYTES)
@@ -4878,7 +4990,7 @@ function parseBarrier(value) {
4878
4990
  return null;
4879
4991
  if (typeof record.terminalAt !== "number" || !Number.isFinite(record.terminalAt))
4880
4992
  return null;
4881
- if (record.source !== "detached-notify" && record.source !== "result-relay")
4993
+ if (record.source !== "detached-notify" && record.source !== "result-relay" && record.source !== "owner-task")
4882
4994
  return null;
4883
4995
  if (!Array.isArray(record.sourceSessionTargets))
4884
4996
  return null;
@@ -4954,11 +5066,17 @@ function registerTerminalOrderingBarrier(pi, options) {
4954
5066
  envelope.completion = currentOwner;
4955
5067
  return;
4956
5068
  }
4957
- const drainedTargets = drainedTargetsByTerminal.get(terminalKey) ?? new Set;
5069
+ const drainedTargets = barrier.source === "owner-task" ? new Set : drainedTargetsByTerminal.get(terminalKey) ?? new Set;
4958
5070
  const pendingTargets = barrier.sourceSessionTargets.filter((target) => !drainedTargets.has(target));
4959
5071
  if (pendingTargets.length === 0)
4960
5072
  return;
4961
5073
  const claim = options.queue.claimOrdinarySourceTargets(barrier.runId, pendingTargets, barrier.terminalAt);
5074
+ const deliverPrelude = (entry) => {
5075
+ if (!claim.isCurrent() || options.isCurrent?.() === false) {
5076
+ throw new Error("Intercom terminal delivery owner retired");
5077
+ }
5078
+ return options.deliver(entry, "prelude");
5079
+ };
4962
5080
  const ownership = Promise.withResolvers();
4963
5081
  ownership.promise.catch(() => {});
4964
5082
  inFlightByTerminal.set(terminalKey, ownership.promise);
@@ -4968,7 +5086,7 @@ function registerTerminalOrderingBarrier(pi, options) {
4968
5086
  ownership.reject(error);
4969
5087
  };
4970
5088
  const finish = () => {
4971
- if (barrier.dispatch && options.toMessage || claim.entries.length > 0) {
5089
+ if (barrier.source !== "owner-task" && (barrier.dispatch && options.toMessage || claim.entries.length > 0)) {
4972
5090
  for (const target of pendingTargets)
4973
5091
  drainedTargets.add(target);
4974
5092
  drainedTargetsByTerminal.set(terminalKey, drainedTargets);
@@ -5019,7 +5137,7 @@ function registerTerminalOrderingBarrier(pi, options) {
5019
5137
  let delivered;
5020
5138
  let deliveredAsync;
5021
5139
  try {
5022
- delivered = options.deliver(claim.entries[index], "prelude");
5140
+ delivered = deliverPrelude(claim.entries[index]);
5023
5141
  deliveredAsync = isPromiseLike(delivered);
5024
5142
  } catch (error) {
5025
5143
  if (barrier.owner)
@@ -5035,7 +5153,7 @@ function registerTerminalOrderingBarrier(pi, options) {
5035
5153
  try {
5036
5154
  await delivered;
5037
5155
  for (current = index + 1;current < claim.entries.length; current++) {
5038
- await options.deliver(claim.entries[current], "prelude");
5156
+ await deliverPrelude(claim.entries[current]);
5039
5157
  }
5040
5158
  finish();
5041
5159
  } catch (error) {
@@ -5111,7 +5229,7 @@ async function dispatchRelayFallback(pi, prefix, terminalMessage, stageAdmission
5111
5229
  }
5112
5230
  }
5113
5231
  function registerSubagentRelay(pi, deps) {
5114
- const { getLiveContext, currentSessionTargetMatches, sendIncomingMessage, ensureConnected, resolveSessionTarget: resolveSessionTarget2 } = deps;
5232
+ const { getLiveContext, currentSessionTargetMatches, sendIncomingMessage, ensureConnected, resolveSessionTarget } = deps;
5115
5233
  const localDeliveries = deps.localDeliveryAuthority ?? new DeliveredMessageCache;
5116
5234
  function deliverLocalSubagentRelayMessage(sender, status, messageText, terminalBarrier, requestId) {
5117
5235
  const now = Date.now();
@@ -5268,7 +5386,7 @@ ${messageText}`,
5268
5386
  let target;
5269
5387
  try {
5270
5388
  activeClient = await ensureConnected("background");
5271
- target = await resolveSessionTarget2(activeClient, parsed.to) ?? parsed.to;
5389
+ target = await resolveSessionTarget(activeClient, parsed.to) ?? parsed.to;
5272
5390
  } catch (error) {
5273
5391
  if (!relayStillLive()) {
5274
5392
  acknowledgeResult(options, parsed.requestId, false, error);
@@ -5545,6 +5663,20 @@ function framePreStartPendingStageMessage(entry) {
5545
5663
 
5546
5664
  Sent: ${framePendingStageTimestamp(entry.message.timestamp)}
5547
5665
 
5666
+ ${entry.bodyText}`
5667
+ };
5668
+ }
5669
+ function isDeliveryFeedback(message) {
5670
+ return Boolean(message.replyTo) && message.replyError !== undefined;
5671
+ }
5672
+ function frameDeliveryFeedback(entry) {
5673
+ return {
5674
+ ...entry,
5675
+ replyCommand: undefined,
5676
+ bodyText: `**Intercom delivery failed**
5677
+
5678
+ Sent: ${framePendingStageTimestamp(entry.message.timestamp)}
5679
+
5548
5680
  ${entry.bodyText}`
5549
5681
  };
5550
5682
  }
@@ -5566,6 +5698,7 @@ ${entry.bodyText}`,
5566
5698
  // dist/builtin/intercom/inbound-idle-queue.ts
5567
5699
  class InboundIdleQueue {
5568
5700
  entries = [];
5701
+ generation = 0;
5569
5702
  get size() {
5570
5703
  return this.entries.length;
5571
5704
  }
@@ -5589,6 +5722,7 @@ class InboundIdleQueue {
5589
5722
  }
5590
5723
  claimOrdinarySourceTargets(runId, sourceSessionTargets, terminalAt = Number.POSITIVE_INFINITY) {
5591
5724
  const targets = new Set(sourceSessionTargets);
5725
+ const generation = this.generation;
5592
5726
  const original = this.entries;
5593
5727
  const legacyIdsByName = new Map;
5594
5728
  for (const entry of original) {
@@ -5618,8 +5752,9 @@ class InboundIdleQueue {
5618
5752
  let settled = false;
5619
5753
  return {
5620
5754
  entries: selected,
5755
+ isCurrent: () => generation === this.generation,
5621
5756
  rollbackFrom: (index) => {
5622
- if (settled)
5757
+ if (settled || generation !== this.generation)
5623
5758
  return;
5624
5759
  settled = true;
5625
5760
  const undelivered = new Set(selected.slice(index));
@@ -5629,6 +5764,7 @@ class InboundIdleQueue {
5629
5764
  };
5630
5765
  }
5631
5766
  clear() {
5767
+ this.generation++;
5632
5768
  this.entries = [];
5633
5769
  }
5634
5770
  }
@@ -5954,7 +6090,7 @@ function routeClosedWorkflowStageMessage(entry, admission, tracker, waiter, deli
5954
6090
  const sourceRunId = entry.message.source?.subagentRunId;
5955
6091
  if (sourceRunId !== undefined && ownsSubagentRun(sourceRunId))
5956
6092
  return;
5957
- if (entry.message.expectsReply !== true) {
6093
+ if (entry.message.expectsReply !== true && !isDeliveryFeedback(entry.message)) {
5958
6094
  retryStableDelivery({ deliver, isCurrent }).catch(() => {});
5959
6095
  return;
5960
6096
  }
@@ -5965,6 +6101,14 @@ function routeClosedWorkflowStageMessage(entry, admission, tracker, waiter, deli
5965
6101
  admission.commit(admitted.reservation);
5966
6102
  return;
5967
6103
  }
6104
+ if (isDeliveryFeedback(entry.message)) {
6105
+ retryStableDelivery({ deliver, isCurrent }).then(() => {
6106
+ admission.commit(admitted.reservation);
6107
+ }, (error) => {
6108
+ admission.release(admitted.reservation, error instanceof Error ? error : new Error(String(error)));
6109
+ });
6110
+ return;
6111
+ }
5968
6112
  const replyContext = tracker.recordIncomingMessage(entry.from, entry.message);
5969
6113
  tracker.queueTurnContext(replyContext);
5970
6114
  const delivery = invoke(deliver);
@@ -6050,6 +6194,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
6050
6194
  };
6051
6195
  let client = null;
6052
6196
  let clientRegistrationGroup = null;
6197
+ const replyCapability = registerSubagentReplyCapability(pi, () => client);
6053
6198
  const config = loadConfig();
6054
6199
  const legacyChildOrchestratorMetadata = readChildOrchestratorMetadata();
6055
6200
  let runtimeContext = null;
@@ -6156,6 +6301,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
6156
6301
  startedAt: sessionStartedAt,
6157
6302
  lastActivity: Date.now(),
6158
6303
  status: currentStatus(),
6304
+ replyCapability: replyCapability(),
6159
6305
  groups: [...currentIntercomGroups()],
6160
6306
  group: currentIntercomGroup()
6161
6307
  };
@@ -6257,14 +6403,15 @@ function piIntercomExtension(pi, testOverrides = {}) {
6257
6403
  const bodyText = `${message.content.text}${attachmentText}`;
6258
6404
  const replyCommand = config.replyHint && message.expectsReply ? `intercom({ action: "reply", message: "..." })` : undefined;
6259
6405
  const rawEntry = { from, message, replyCommand, bodyText, ...channel ? { channel } : {} };
6260
- const entry = receivedBeforeStageStart ? framePreStartPendingStageMessage(rawEntry) : rawEntry;
6406
+ const framedEntry = isDeliveryFeedback(message) ? frameDeliveryFeedback(rawEntry) : rawEntry;
6407
+ const entry = receivedBeforeStageStart ? framePreStartPendingStageMessage(framedEntry) : framedEntry;
6261
6408
  if (receivedBeforeStageStart) {
6262
6409
  return sendIncomingMessage(entry, "prelude", messageGeneration, false);
6263
6410
  }
6264
6411
  const stageAdmission = liveContext.orchestrationContext?.kind === "workflow-stage" ? liveContext.orchestrationContext.messageAdmission : undefined;
6265
6412
  const stageClosed = stageAdmission?.isOpen() === false;
6266
6413
  if (stageClosed) {
6267
- routeClosedWorkflowStageMessage(entry, inboundDeliveries, replyTracker, replyWaiters.pending(), () => sendIncomingMessage(entry, "trigger", messageGeneration, false), () => client, () => Boolean(getLiveContext(liveContext, messageGeneration)), (runId) => stageAdmission.boundary.ownsSubagentRun(runId));
6414
+ routeClosedWorkflowStageMessage(entry, inboundDeliveries, replyTracker, replyWaiters.pending(), () => sendIncomingMessage(entry, isDeliveryFeedback(message) ? "prelude" : "trigger", messageGeneration, false), () => client, () => Boolean(getLiveContext(liveContext, messageGeneration)), (runId) => stageAdmission.boundary.ownsSubagentRun(runId));
6268
6415
  return;
6269
6416
  }
6270
6417
  const admission = inboundDeliveries.admit(from, message);
@@ -6275,6 +6422,12 @@ function piIntercomExtension(pi, testOverrides = {}) {
6275
6422
  inboundDeliveries.commit(reservation);
6276
6423
  return;
6277
6424
  }
6425
+ if (isDeliveryFeedback(message)) {
6426
+ return retryStableDelivery({
6427
+ deliver: () => sendIncomingMessage(entry, "prelude", messageGeneration, false),
6428
+ isCurrent: () => Boolean(getLiveContext(liveContext, messageGeneration))
6429
+ }).then(() => inboundDeliveries.commit(reservation), (error) => inboundDeliveries.release(reservation, toError3(error)));
6430
+ }
6278
6431
  const replyContext = replyTracker.recordIncomingMessage(from, message);
6279
6432
  const commit = () => {
6280
6433
  inboundDeliveries.commit(reservation);
@@ -6311,9 +6464,11 @@ function piIntercomExtension(pi, testOverrides = {}) {
6311
6464
  const activeClient = client;
6312
6465
  if (!message.replyTo && activeClient?.isConnected()) {
6313
6466
  try {
6467
+ const refusal = "Message not accepted: recipient was busy in non-interactive mode. Its task was not interrupted.";
6314
6468
  const result = await activeClient.send(from.id, {
6315
- text: "This agent is running in non-interactive mode and cannot respond to intercom messages while it is working. It will continue its current task and exit when done.",
6316
- replyTo: message.id
6469
+ text: refusal,
6470
+ replyTo: message.id,
6471
+ replyError: refusal
6317
6472
  });
6318
6473
  if (result.delivered && getLiveContext(liveContext, messageGeneration)) {
6319
6474
  replyTracker.markReplied(message.id);
@@ -6581,7 +6736,8 @@ function piIntercomExtension(pi, testOverrides = {}) {
6581
6736
  pendingStageRouteClients.set(runId, state);
6582
6737
  if (state.client?.isConnected()) {
6583
6738
  state.route = route;
6584
- state.client.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages);
6739
+ state.client.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages, route.parent);
6740
+ await state.client.listSessions();
6585
6741
  return;
6586
6742
  }
6587
6743
  if (state.promise) {
@@ -6593,12 +6749,12 @@ function piIntercomExtension(pi, testOverrides = {}) {
6593
6749
  const nextClient = new IntercomClient(`${currentSessionId}:pending-stage-route:${runId}`);
6594
6750
  state.client = nextClient;
6595
6751
  attachPendingStageRouteClientHandlers(runId, state, nextClient);
6596
- await nextClient.connect({ ...buildRegistration(), name: undefined, groups: [normalizeGroup(route.group)], group: normalizeGroup(route.group) }, undefined, undefined, readSubagentMessageSource(runtimeContext?.subagentPolicy));
6752
+ await nextClient.connect({ ...buildRegistration(), recipientPurpose: "control", name: undefined, groups: [normalizeGroup(route.group)], group: normalizeGroup(route.group) }, undefined, undefined, readSubagentMessageSource(runtimeContext?.subagentPolicy));
6597
6753
  if (!pendingStageRouteClientIsCurrent(runId, state, contextAtStart, generationAtStart)) {
6598
6754
  await nextClient.disconnect();
6599
6755
  throw new Error("Intercom runtime no longer active");
6600
6756
  }
6601
- nextClient.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages);
6757
+ nextClient.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages, route.parent);
6602
6758
  await nextClient.listSessions();
6603
6759
  if (!pendingStageRouteClientIsCurrent(runId, state, contextAtStart, generationAtStart)) {
6604
6760
  await nextClient.disconnect();
@@ -6646,7 +6802,8 @@ function piIntercomExtension(pi, testOverrides = {}) {
6646
6802
  async function registerPendingStageRoute(activeClient, runId, route) {
6647
6803
  const routeGroup = normalizeGroup(route.group);
6648
6804
  if (clientRegistrationGroup === routeGroup) {
6649
- activeClient.registerPendingStageRoute(runId, routeGroup, route.capability, route.stages, route.possibleStages);
6805
+ activeClient.registerPendingStageRoute(runId, routeGroup, route.capability, route.stages, route.possibleStages, route.parent);
6806
+ await activeClient.listSessions();
6650
6807
  return;
6651
6808
  }
6652
6809
  await ensurePendingStageRouteClient(runId, { ...route, group: routeGroup });
@@ -6672,15 +6829,16 @@ function piIntercomExtension(pi, testOverrides = {}) {
6672
6829
  let connectFailed = false;
6673
6830
  await ownershipRecorded.promise;
6674
6831
  const nextClient = new IntercomClient(currentSessionId);
6675
- const registration = buildRegistration();
6676
6832
  client = nextClient;
6677
6833
  attachClientHandlers(nextClient);
6678
6834
  try {
6679
6835
  await testOverrides.beforeConnectAttempt?.(reason);
6680
6836
  await spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs);
6681
6837
  const childMetadata = currentChildOrchestratorMetadata();
6682
- await nextClient.connect(registration, childMetadata?.supervisor, supervisorAuthorizations.ownerToken, readSubagentMessageSource(runtimeContext?.subagentPolicy), resolveSessionHomeGroup());
6838
+ await nextClient.connect(buildRegistration(), childMetadata?.supervisor, supervisorAuthorizations.ownerToken, readSubagentMessageSource(runtimeContext?.subagentPolicy), resolveSessionHomeGroup());
6683
6839
  clientRegistrationGroup = resolveSessionHomeGroup();
6840
+ if (replyCapability() === "terminal")
6841
+ nextClient.updatePresence({ replyCapability: "terminal" });
6684
6842
  await supervisorAuthorizations.restore(nextClient);
6685
6843
  for (const [runId, route] of pendingStageRoutes) {
6686
6844
  await registerPendingStageRoute(nextClient, runId, route);
@@ -6734,7 +6892,8 @@ function piIntercomExtension(pi, testOverrides = {}) {
6734
6892
  group: payload.group,
6735
6893
  capability: payload.capability,
6736
6894
  ...payload.stages === undefined ? {} : { stages: payload.stages },
6737
- ...payload.possibleStages === undefined ? {} : { possibleStages: payload.possibleStages }
6895
+ ...payload.possibleStages === undefined ? {} : { possibleStages: payload.possibleStages },
6896
+ ...payload.parent === undefined ? {} : { parent: payload.parent }
6738
6897
  });
6739
6898
  const completion = ensureConnected("background").then((activeClient) => registerPendingStageRoute(activeClient, payload.runId, payload));
6740
6899
  payload.completion = completion;
@@ -6942,8 +7101,34 @@ import { Text as Text4 } from "@earendil-works/pi-tui";
6942
7101
  import { Type as Type3 } from "typebox";
6943
7102
 
6944
7103
  // dist/builtin/intercom/lazy-tool-execution.ts
7104
+ init_recoverable_disconnect();
7105
+ init_retry_policy();
7106
+ import { setTimeout as delay } from "node:timers/promises";
6945
7107
  async function executeHeavyTool(loadHeavy, name, args) {
6946
- const handle = await loadHeavy(args[4]);
7108
+ const params = args[1];
7109
+ const recoverInitialization = name === "intercom" && ["send", "ask", "reply"].includes(params.action ?? "");
7110
+ let handle;
7111
+ let retries = 0;
7112
+ for (;; ) {
7113
+ if (recoverInitialization && args[2]?.aborted)
7114
+ return initializationFailure("Cancelled", retries);
7115
+ try {
7116
+ handle = await loadHeavy(args[4]);
7117
+ break;
7118
+ } catch (error) {
7119
+ if (!recoverInitialization || !isRecoverableIntercomDisconnect(error))
7120
+ throw error;
7121
+ const delayMs = RECONNECT_DELAYS_MS[retries];
7122
+ if (delayMs === undefined)
7123
+ return initializationFailure("Client disconnected", retries);
7124
+ try {
7125
+ await delay(delayMs, undefined, { signal: args[2] });
7126
+ } catch {
7127
+ return initializationFailure("Cancelled", retries);
7128
+ }
7129
+ retries += 1;
7130
+ }
7131
+ }
6947
7132
  handle.assertCurrent();
6948
7133
  const tool = handle.heavy.tools.get(name);
6949
7134
  if (!tool?.execute)
@@ -6952,6 +7137,13 @@ async function executeHeavyTool(loadHeavy, name, args) {
6952
7137
  handle.assertCurrent();
6953
7138
  return result;
6954
7139
  }
7140
+ function initializationFailure(reason, retries) {
7141
+ return {
7142
+ content: [{ type: "text", text: `${reason}. Intercom initialization stopped after ${retries} automatic retries. This operation was not sent.` }],
7143
+ isError: true,
7144
+ details: { error: true, terminal: true, automaticRetries: retries, outcome: "not_sent" }
7145
+ };
7146
+ }
6955
7147
  async function runHeavyCommand(loadHeavy, args, ctx) {
6956
7148
  const handle = await loadHeavy(ctx);
6957
7149
  handle.assertCurrent();
@@ -7634,7 +7826,7 @@ function intercom(pi, options = {}) {
7634
7826
  Use this to communicate findings, request help, or coordinate work with other sessions.
7635
7827
  Sessions belong to an intercom group and can ONLY message sessions in the same group; cross-group sends are rejected by the broker. Ungrouped sessions share the "default" group.
7636
7828
  For send, live session names and exact full session IDs remain supported. Workflow-stage targets use \`workflow:<rootRunId>/<segment>[/<segment>...]\`; \`*\` matches one segment and \`**\` any depth. Use \`intercom list\` inside the invocation group to see live, pending, and possible future targets with queued counts. \`workflow:<rootRunId>/**\` reaches live stages now and remains sticky for every future stage until root termination; valid targets outside the known set queue with a \`notInKnownSet\` warning and settle undeliverable at terminal only if never delivered. Use \`ask\` only on live targets.
7637
- If a \`send\`, \`ask\`, or \`reply\` fails with \`Client disconnected\`, retry that exact operation with the returned \`retryToken\`, up to three claimed attempts; omit the token for every fresh operation.
7829
+ For send/ask/reply, Intercom retries recoverable disconnects internally up to three times with the same operation identity. Each new tool call is a new operation. If recovery ends with an unknown delivery outcome, do not repeat it automatically.
7638
7830
  Usage:
7639
7831
  intercom({ action: "list" }) → List sessions in your group
7640
7832
  intercom({ action: "list", group: "name" }) → Read-only peek at another group's sessions
@@ -7643,12 +7835,11 @@ Usage:
7643
7835
  intercom({ action: "send", to: "session-name", message: "..." }) → Send message (own group only)
7644
7836
  intercom({ action: "ask", to: "session-name", message: "..." }) → Ask and wait for reply
7645
7837
  intercom({ action: "reply", message: "..." }) → Reply to the active or exact pending ask
7646
- intercom({ action: "send", to: "session-name", message: "...", retryToken: "..." }) → Claim the exact retry returned by a retryable failure
7647
7838
  intercom({ action: "pending" }) → List unresolved inbound asks
7648
7839
  intercom({ action: "status" }) → Show connection status and your group
7649
7840
 
7650
7841
  "default" is the shared group; "true" and "auto" are reserved for subagent auto-groups. Joining does not grant cross-group access; contact_supervisor remains the only cross-group path.`,
7651
- promptSnippet: "Use to coordinate with other local agent sessions in your intercom group. For a retryable send/ask/reply failure, repeat the exact operation with its returned retryToken; omit retryToken for fresh operations.",
7842
+ promptSnippet: "Use to coordinate with other local agent sessions in your intercom group. Send/ask/reply retry reconnects internally; do not automatically repeat an unknown delivery outcome.",
7652
7843
  parameters: Type3.Object({
7653
7844
  action: Type3.String({ description: "Action: 'list', 'join', 'leave', 'send', 'ask', 'reply', 'pending', or 'status'" }),
7654
7845
  to: Type3.Optional(Type3.String({ description: "Live session name, exact full session ID, or `workflow:<rootRunId>/<segment>[/<segment>...]` path; `*` matches one segment and `**` any depth. Send queues sticky pending/future delivery and `workflow:<rootRunId>/**` broadcasts to live and future stages; use `ask` only on live targets (for 'send', 'ask', or targeted 'reply')" })),
@@ -7660,10 +7851,15 @@ Usage:
7660
7851
  language: Type3.Optional(Type3.String())
7661
7852
  }))),
7662
7853
  replyTo: Type3.Optional(Type3.String({ description: "Exact pending-ask message ID; disambiguates concurrent asks, including asks from one sender" })),
7663
- retryToken: Type3.Optional(Type3.String({ minLength: 1, maxLength: 128, description: "Opaque token returned after a retryable send/ask/reply failure. Repeat the exact same action and arguments with it; omit it for fresh operations." })),
7664
7854
  group: Type3.Optional(Type3.String({ description: "Group name for 'join'; read-only group filter for 'list'/'status'. 'send'/'ask' are locked to your own group." }))
7665
7855
  }),
7666
- execute: (...args) => executeHeavyTool(loadHeavy, "intercom", args),
7856
+ execute: (...args) => {
7857
+ const invocationLease = activeLease;
7858
+ return executeHeavyTool((ctx) => {
7859
+ assertLease(invocationLease);
7860
+ return loadHeavy(ctx);
7861
+ }, "intercom", args);
7862
+ },
7667
7863
  renderResult: (...args) => renderHeavyToolResult(loadedHeavy?.heavy ?? null, "intercom", args),
7668
7864
  renderCall(args, theme) {
7669
7865
  const input = args;