@bastani/atomic 0.9.18 → 0.9.19-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (876) hide show
  1. package/CHANGELOG.md +206 -0
  2. package/README.md +2 -2
  3. package/dist/builtin/intercom/CHANGELOG.md +51 -0
  4. package/dist/builtin/intercom/README.md +28 -18
  5. package/dist/builtin/intercom/broker/broker.ts +81 -9
  6. package/dist/builtin/intercom/broker/client.ts +45 -1
  7. package/dist/builtin/intercom/broker/framing.ts +5 -2
  8. package/dist/builtin/intercom/broker/group-membership.ts +4 -2
  9. package/dist/builtin/intercom/broker/presence-handler.ts +14 -0
  10. package/dist/builtin/intercom/broker/send-handler.ts +61 -6
  11. package/dist/builtin/intercom/broker/terminal-questions.ts +29 -0
  12. package/dist/builtin/intercom/index.bundle.mjs +1120 -783
  13. package/dist/builtin/intercom/package.json +2 -2
  14. package/dist/builtin/intercom/recipient-purpose.ts +9 -0
  15. package/dist/builtin/intercom/recoverable-disconnect.ts +2 -3
  16. package/dist/builtin/intercom/retry-policy.ts +4 -2
  17. package/dist/builtin/intercom/skills/intercom/SKILL.md +8 -7
  18. package/dist/builtin/intercom/types.ts +18 -3
  19. package/dist/builtin/mcp/CHANGELOG.md +6 -0
  20. package/dist/builtin/mcp/README.md +2 -0
  21. package/dist/builtin/mcp/index.bundle.mjs +2201 -12000
  22. package/dist/builtin/mcp/package.json +2 -2
  23. package/dist/builtin/subagents/CHANGELOG.md +57 -0
  24. package/dist/builtin/subagents/README.md +46 -23
  25. package/dist/builtin/subagents/agents/code-simplifier.md +1 -1
  26. package/dist/builtin/subagents/agents/codebase-analyzer.md +1 -1
  27. package/dist/builtin/subagents/agents/codebase-locator.md +2 -2
  28. package/dist/builtin/subagents/agents/codebase-online-researcher.md +8 -8
  29. package/dist/builtin/subagents/agents/codebase-pattern-finder.md +2 -2
  30. package/dist/builtin/subagents/agents/codebase-research-analyzer.md +1 -1
  31. package/dist/builtin/subagents/agents/codebase-research-locator.md +2 -2
  32. package/dist/builtin/subagents/agents/debugger.md +2 -2
  33. package/dist/builtin/subagents/agents/worker.md +1 -1
  34. package/dist/builtin/subagents/package.json +2 -2
  35. package/dist/builtin/subagents/skills/herdr/LICENSE +201 -0
  36. package/dist/builtin/subagents/skills/herdr/SKILL.md +202 -0
  37. package/dist/builtin/subagents/skills/subagent/SKILL.md +41 -35
  38. package/dist/builtin/subagents/skills/tmux/SKILL.md +1 -1
  39. package/dist/builtin/subagents/src/extension/index.bundle.mjs +1414 -656
  40. package/dist/builtin/web-access/CHANGELOG.md +19 -0
  41. package/dist/builtin/web-access/README.md +31 -24
  42. package/dist/builtin/web-access/index.bundle.mjs +42723 -26674
  43. package/dist/builtin/web-access/package.json +3 -2
  44. package/dist/builtin/workflows/CHANGELOG.md +131 -0
  45. package/dist/builtin/workflows/README.md +15 -16
  46. package/dist/builtin/workflows/builtin/adversarial-verification.js +5 -7
  47. package/dist/builtin/workflows/builtin/{chunk-hqpe2cyx.js → chunk-1jth021m.js} +85 -85
  48. package/dist/builtin/workflows/builtin/{chunk-7430zyas.js → chunk-2377r57g.js} +5 -3
  49. package/dist/builtin/workflows/builtin/{chunk-79fjkcvh.js → chunk-31j2gs7h.js} +18 -18
  50. package/dist/builtin/workflows/builtin/{chunk-wgccch41.js → chunk-6w6cvk6b.js} +16 -16
  51. package/dist/builtin/workflows/builtin/{chunk-zbekjqew.js → chunk-a2kdsqn8.js} +4 -4
  52. package/dist/builtin/workflows/builtin/{chunk-ze5x3d1r.js → chunk-fg9esgkj.js} +7 -7
  53. package/dist/builtin/workflows/builtin/{chunk-n8h4yyew.js → chunk-g0csgs7w.js} +11 -11
  54. package/dist/builtin/workflows/builtin/{chunk-b0v2xab1.js → chunk-ngkqkzej.js} +221 -23
  55. package/dist/builtin/workflows/builtin/{chunk-ed4jfn5t.js → chunk-nkrafh9s.js} +61 -61
  56. package/dist/builtin/workflows/builtin/{chunk-reqr3sr3.js → chunk-wf741bv3.js} +22 -22
  57. package/dist/builtin/workflows/builtin/{chunk-42s7sw0b.js → chunk-yeee2jrc.js} +19 -19
  58. package/dist/builtin/workflows/builtin/{chunk-6fqs7c01.js → chunk-z0d03ktm.js} +1 -1
  59. package/dist/builtin/workflows/builtin/{chunk-k3w87x8y.js → chunk-z29qbehr.js} +10 -10
  60. package/dist/builtin/workflows/builtin/classify-and-act.js +5 -6
  61. package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +3 -4
  62. package/dist/builtin/workflows/builtin/generate-and-filter.js +5 -6
  63. package/dist/builtin/workflows/builtin/goal.js +7 -8
  64. package/dist/builtin/workflows/builtin/index.js +20 -22
  65. package/dist/builtin/workflows/builtin/loop-until-done.js +5 -6
  66. package/dist/builtin/workflows/builtin/open-claude-design.js +3 -3
  67. package/dist/builtin/workflows/builtin/ralph.js +7 -8
  68. package/dist/builtin/workflows/builtin/steering-context.js +3 -3
  69. package/dist/builtin/workflows/builtin/tournament.js +5 -7
  70. package/dist/builtin/workflows/package.json +6 -6
  71. package/dist/builtin/workflows/src/extension/index.bundle.mjs +57318 -25709
  72. package/dist/builtin/workflows/src/index.js +1413 -589
  73. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +4 -1
  74. package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +1 -1
  75. package/dist/cli/config-selector.js.map +1 -1
  76. package/dist/cli/startup-ui.d.ts +1 -1
  77. package/dist/cli/startup-ui.js.map +1 -1
  78. package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
  79. package/dist/core/agent-session-auto-compaction.js +6 -5
  80. package/dist/core/agent-session-auto-compaction.js.map +1 -1
  81. package/dist/core/agent-session-bash.d.ts +1 -1
  82. package/dist/core/agent-session-bash.d.ts.map +1 -1
  83. package/dist/core/agent-session-bash.js +5 -1
  84. package/dist/core/agent-session-bash.js.map +1 -1
  85. package/dist/core/agent-session-compaction.d.ts +1 -1
  86. package/dist/core/agent-session-compaction.js +1 -1
  87. package/dist/core/agent-session-compaction.js.map +1 -1
  88. package/dist/core/agent-session-custom-message-commit.d.ts +1 -1
  89. package/dist/core/agent-session-custom-message-commit.d.ts.map +1 -1
  90. package/dist/core/agent-session-custom-message-commit.js +33 -2
  91. package/dist/core/agent-session-custom-message-commit.js.map +1 -1
  92. package/dist/core/agent-session-delivery-forwarding.d.ts +1 -1
  93. package/dist/core/agent-session-delivery-forwarding.js.map +1 -1
  94. package/dist/core/agent-session-events.d.ts.map +1 -1
  95. package/dist/core/agent-session-events.js +5 -0
  96. package/dist/core/agent-session-events.js.map +1 -1
  97. package/dist/core/agent-session-export.d.ts +1 -1
  98. package/dist/core/agent-session-export.js.map +1 -1
  99. package/dist/core/agent-session-extension-bindings.d.ts +8 -1
  100. package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
  101. package/dist/core/agent-session-extension-bindings.js +45 -3
  102. package/dist/core/agent-session-extension-bindings.js.map +1 -1
  103. package/dist/core/agent-session-message-queue.d.ts +2 -2
  104. package/dist/core/agent-session-message-queue.d.ts.map +1 -1
  105. package/dist/core/agent-session-message-queue.js +22 -8
  106. package/dist/core/agent-session-message-queue.js.map +1 -1
  107. package/dist/core/agent-session-methods.d.ts +21 -8
  108. package/dist/core/agent-session-methods.d.ts.map +1 -1
  109. package/dist/core/agent-session-methods.js.map +1 -1
  110. package/dist/core/agent-session-persistent-custom-messages.d.ts +1 -1
  111. package/dist/core/agent-session-persistent-custom-messages.d.ts.map +1 -1
  112. package/dist/core/agent-session-persistent-custom-messages.js +13 -3
  113. package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
  114. package/dist/core/agent-session-post-tool-compaction.js +1 -1
  115. package/dist/core/agent-session-post-tool-compaction.js.map +1 -1
  116. package/dist/core/agent-session-prompt.d.ts +2 -2
  117. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  118. package/dist/core/agent-session-prompt.js +105 -18
  119. package/dist/core/agent-session-prompt.js.map +1 -1
  120. package/dist/core/agent-session-queue-pause.d.ts.map +1 -1
  121. package/dist/core/agent-session-queue-pause.js +11 -0
  122. package/dist/core/agent-session-queue-pause.js.map +1 -1
  123. package/dist/core/agent-session-runtime-auth.d.ts +1 -1
  124. package/dist/core/agent-session-runtime-auth.js.map +1 -1
  125. package/dist/core/agent-session-runtime.d.ts +13 -4
  126. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  127. package/dist/core/agent-session-runtime.js +27 -4
  128. package/dist/core/agent-session-runtime.js.map +1 -1
  129. package/dist/core/agent-session-services.d.ts +5 -1
  130. package/dist/core/agent-session-services.d.ts.map +1 -1
  131. package/dist/core/agent-session-services.js +44 -34
  132. package/dist/core/agent-session-services.js.map +1 -1
  133. package/dist/core/agent-session-state.d.ts +1 -1
  134. package/dist/core/agent-session-state.js.map +1 -1
  135. package/dist/core/agent-session-tasks.d.ts +14 -0
  136. package/dist/core/agent-session-tasks.d.ts.map +1 -0
  137. package/dist/core/agent-session-tasks.js +120 -0
  138. package/dist/core/agent-session-tasks.js.map +1 -0
  139. package/dist/core/agent-session-tool-hooks.d.ts.map +1 -1
  140. package/dist/core/agent-session-tool-hooks.js +2 -0
  141. package/dist/core/agent-session-tool-hooks.js.map +1 -1
  142. package/dist/core/agent-session-tool-registry.d.ts +1 -0
  143. package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
  144. package/dist/core/agent-session-tool-registry.js +52 -5
  145. package/dist/core/agent-session-tool-registry.js.map +1 -1
  146. package/dist/core/agent-session-transfer.d.ts.map +1 -1
  147. package/dist/core/agent-session-transfer.js +7 -0
  148. package/dist/core/agent-session-transfer.js.map +1 -1
  149. package/dist/core/agent-session-tree.d.ts.map +1 -1
  150. package/dist/core/agent-session-tree.js +3 -0
  151. package/dist/core/agent-session-tree.js.map +1 -1
  152. package/dist/core/agent-session-types.d.ts +4 -2
  153. package/dist/core/agent-session-types.d.ts.map +1 -1
  154. package/dist/core/agent-session-types.js +2 -0
  155. package/dist/core/agent-session-types.js.map +1 -1
  156. package/dist/core/agent-session.d.ts +8 -1
  157. package/dist/core/agent-session.d.ts.map +1 -1
  158. package/dist/core/agent-session.js +29 -1
  159. package/dist/core/agent-session.js.map +1 -1
  160. package/dist/core/bash-executor.d.ts +1 -1
  161. package/dist/core/bash-executor.js.map +1 -1
  162. package/dist/core/export-html/index.js.map +1 -1
  163. package/dist/core/export-html/tool-renderer.d.ts +1 -1
  164. package/dist/core/export-html/tool-renderer.js.map +1 -1
  165. package/dist/core/extension-session-state.js.map +1 -1
  166. package/dist/core/extensions/agent-events.d.ts +4 -4
  167. package/dist/core/extensions/agent-events.d.ts.map +1 -1
  168. package/dist/core/extensions/agent-events.js.map +1 -1
  169. package/dist/core/extensions/api-types.d.ts +10 -2
  170. package/dist/core/extensions/api-types.d.ts.map +1 -1
  171. package/dist/core/extensions/api-types.js.map +1 -1
  172. package/dist/core/extensions/context-types.d.ts +15 -0
  173. package/dist/core/extensions/context-types.d.ts.map +1 -1
  174. package/dist/core/extensions/context-types.js.map +1 -1
  175. package/dist/core/extensions/event-results.d.ts +1 -1
  176. package/dist/core/extensions/event-results.js.map +1 -1
  177. package/dist/core/extensions/event-types.d.ts +2 -1
  178. package/dist/core/extensions/event-types.d.ts.map +1 -1
  179. package/dist/core/extensions/event-types.js.map +1 -1
  180. package/dist/core/extensions/index.d.ts +3 -2
  181. package/dist/core/extensions/index.d.ts.map +1 -1
  182. package/dist/core/extensions/index.js.map +1 -1
  183. package/dist/core/extensions/loader-api.d.ts +1 -1
  184. package/dist/core/extensions/loader-api.d.ts.map +1 -1
  185. package/dist/core/extensions/loader-api.js +10 -0
  186. package/dist/core/extensions/loader-api.js.map +1 -1
  187. package/dist/core/extensions/loader-core.d.ts +1 -1
  188. package/dist/core/extensions/loader-core.js.map +1 -1
  189. package/dist/core/extensions/loader-discovery.d.ts +1 -1
  190. package/dist/core/extensions/loader-discovery.js.map +1 -1
  191. package/dist/core/extensions/loader-host-modules.d.ts +1 -1
  192. package/dist/core/extensions/loader-host-modules.d.ts.map +1 -1
  193. package/dist/core/extensions/loader-host-modules.js +5 -2
  194. package/dist/core/extensions/loader-host-modules.js.map +1 -1
  195. package/dist/core/extensions/loader-runtime.d.ts.map +1 -1
  196. package/dist/core/extensions/loader-runtime.js +3 -0
  197. package/dist/core/extensions/loader-runtime.js.map +1 -1
  198. package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
  199. package/dist/core/extensions/loader-virtual-modules.js +6 -1
  200. package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
  201. package/dist/core/extensions/loader.d.ts +1 -1
  202. package/dist/core/extensions/loader.js.map +1 -1
  203. package/dist/core/extensions/message-types.d.ts +1 -1
  204. package/dist/core/extensions/message-types.js.map +1 -1
  205. package/dist/core/extensions/reactive-widget.d.ts +6 -0
  206. package/dist/core/extensions/reactive-widget.d.ts.map +1 -1
  207. package/dist/core/extensions/reactive-widget.js +7 -1
  208. package/dist/core/extensions/reactive-widget.js.map +1 -1
  209. package/dist/core/extensions/runner-context.d.ts +12 -2
  210. package/dist/core/extensions/runner-context.d.ts.map +1 -1
  211. package/dist/core/extensions/runner-context.js +49 -4
  212. package/dist/core/extensions/runner-context.js.map +1 -1
  213. package/dist/core/extensions/runner-events.d.ts +1 -1
  214. package/dist/core/extensions/runner-events.d.ts.map +1 -1
  215. package/dist/core/extensions/runner-events.js +17 -2
  216. package/dist/core/extensions/runner-events.js.map +1 -1
  217. package/dist/core/extensions/runner-shortcuts.d.ts.map +1 -1
  218. package/dist/core/extensions/runner-shortcuts.js +32 -3
  219. package/dist/core/extensions/runner-shortcuts.js.map +1 -1
  220. package/dist/core/extensions/runner-ui.js.map +1 -1
  221. package/dist/core/extensions/runner.d.ts +17 -2
  222. package/dist/core/extensions/runner.d.ts.map +1 -1
  223. package/dist/core/extensions/runner.js +69 -19
  224. package/dist/core/extensions/runner.js.map +1 -1
  225. package/dist/core/extensions/runtime-types.d.ts +8 -1
  226. package/dist/core/extensions/runtime-types.d.ts.map +1 -1
  227. package/dist/core/extensions/runtime-types.js.map +1 -1
  228. package/dist/core/extensions/tool-types.d.ts +1 -1
  229. package/dist/core/extensions/tool-types.js.map +1 -1
  230. package/dist/core/extensions/types.d.ts +1 -0
  231. package/dist/core/extensions/types.d.ts.map +1 -1
  232. package/dist/core/extensions/types.js.map +1 -1
  233. package/dist/core/extensions/ui-types.d.ts +25 -1
  234. package/dist/core/extensions/ui-types.d.ts.map +1 -1
  235. package/dist/core/extensions/ui-types.js.map +1 -1
  236. package/dist/core/extensions/workflow-activity-hub.d.ts +25 -0
  237. package/dist/core/extensions/workflow-activity-hub.d.ts.map +1 -0
  238. package/dist/core/extensions/workflow-activity-hub.js +183 -0
  239. package/dist/core/extensions/workflow-activity-hub.js.map +1 -0
  240. package/dist/core/extensions/workflow-events.d.ts +118 -0
  241. package/dist/core/extensions/workflow-events.d.ts.map +1 -0
  242. package/dist/core/extensions/workflow-events.js +2 -0
  243. package/dist/core/extensions/workflow-events.js.map +1 -0
  244. package/dist/core/footer-data-provider.d.ts +8 -4
  245. package/dist/core/footer-data-provider.d.ts.map +1 -1
  246. package/dist/core/footer-data-provider.js +97 -11
  247. package/dist/core/footer-data-provider.js.map +1 -1
  248. package/dist/core/index.d.ts +3 -3
  249. package/dist/core/index.js.map +1 -1
  250. package/dist/core/keybinding-identity.d.ts +4 -0
  251. package/dist/core/keybinding-identity.d.ts.map +1 -0
  252. package/dist/core/keybinding-identity.js +10 -0
  253. package/dist/core/keybinding-identity.js.map +1 -0
  254. package/dist/core/keybindings.d.ts +37 -2
  255. package/dist/core/keybindings.d.ts.map +1 -1
  256. package/dist/core/keybindings.js +9 -2
  257. package/dist/core/keybindings.js.map +1 -1
  258. package/dist/core/mandatory-runtime-tools.d.ts +1 -1
  259. package/dist/core/mandatory-runtime-tools.js.map +1 -1
  260. package/dist/core/model-fallback-failures.js +2 -2
  261. package/dist/core/model-fallback-failures.js.map +1 -1
  262. package/dist/core/model-registry.d.ts +5 -1
  263. package/dist/core/model-registry.d.ts.map +1 -1
  264. package/dist/core/model-registry.js +8 -0
  265. package/dist/core/model-registry.js.map +1 -1
  266. package/dist/core/model-resolver-defaults.js +1 -1
  267. package/dist/core/model-resolver-defaults.js.map +1 -1
  268. package/dist/core/resource-loader-assets.js.map +1 -1
  269. package/dist/core/resource-loader-core.d.ts +1 -1
  270. package/dist/core/resource-loader-core.js.map +1 -1
  271. package/dist/core/resource-loader-internals.d.ts +2 -2
  272. package/dist/core/resource-loader-internals.js.map +1 -1
  273. package/dist/core/resource-loader-reload.d.ts +2 -0
  274. package/dist/core/resource-loader-reload.d.ts.map +1 -1
  275. package/dist/core/resource-loader-reload.js +231 -191
  276. package/dist/core/resource-loader-reload.js.map +1 -1
  277. package/dist/core/resource-loader-types.d.ts +4 -2
  278. package/dist/core/resource-loader-types.d.ts.map +1 -1
  279. package/dist/core/resource-loader-types.js.map +1 -1
  280. package/dist/core/retry-policy.d.ts +1 -0
  281. package/dist/core/retry-policy.d.ts.map +1 -1
  282. package/dist/core/retry-policy.js +2 -1
  283. package/dist/core/retry-policy.js.map +1 -1
  284. package/dist/core/sdk-exports.d.ts +3 -3
  285. package/dist/core/sdk-exports.d.ts.map +1 -1
  286. package/dist/core/sdk-exports.js +1 -1
  287. package/dist/core/sdk-exports.js.map +1 -1
  288. package/dist/core/sdk-types.d.ts +2 -2
  289. package/dist/core/sdk-types.js.map +1 -1
  290. package/dist/core/sdk.js.map +1 -1
  291. package/dist/core/settings-manager-basic-accessors.d.ts +6 -3
  292. package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
  293. package/dist/core/settings-manager-basic-accessors.js +25 -8
  294. package/dist/core/settings-manager-basic-accessors.js.map +1 -1
  295. package/dist/core/settings-manager-core.d.ts.map +1 -1
  296. package/dist/core/settings-manager-core.js +10 -4
  297. package/dist/core/settings-manager-core.js.map +1 -1
  298. package/dist/core/settings-manager.d.ts +1 -1
  299. package/dist/core/settings-manager.d.ts.map +1 -1
  300. package/dist/core/settings-manager.js.map +1 -1
  301. package/dist/core/settings-storage.d.ts +1 -0
  302. package/dist/core/settings-storage.d.ts.map +1 -1
  303. package/dist/core/settings-storage.js +18 -0
  304. package/dist/core/settings-storage.js.map +1 -1
  305. package/dist/core/settings-types.d.ts +17 -0
  306. package/dist/core/settings-types.d.ts.map +1 -1
  307. package/dist/core/settings-types.js.map +1 -1
  308. package/dist/core/slash-commands.d.ts.map +1 -1
  309. package/dist/core/slash-commands.js +6 -5
  310. package/dist/core/slash-commands.js.map +1 -1
  311. package/dist/core/system-prompt.d.ts.map +1 -1
  312. package/dist/core/system-prompt.js +5 -6
  313. package/dist/core/system-prompt.js.map +1 -1
  314. package/dist/core/tasks/agent-adapter.d.ts +44 -0
  315. package/dist/core/tasks/agent-adapter.d.ts.map +1 -0
  316. package/dist/core/tasks/agent-adapter.js +112 -0
  317. package/dist/core/tasks/agent-adapter.js.map +1 -0
  318. package/dist/core/tasks/command-output.d.ts +15 -0
  319. package/dist/core/tasks/command-output.d.ts.map +1 -0
  320. package/dist/core/tasks/command-output.js +29 -0
  321. package/dist/core/tasks/command-output.js.map +1 -0
  322. package/dist/core/tasks/completion-ordering.d.ts +11 -0
  323. package/dist/core/tasks/completion-ordering.d.ts.map +1 -0
  324. package/dist/core/tasks/completion-ordering.js +19 -0
  325. package/dist/core/tasks/completion-ordering.js.map +1 -0
  326. package/dist/core/tasks/completion.d.ts +36 -0
  327. package/dist/core/tasks/completion.d.ts.map +1 -0
  328. package/dist/core/tasks/completion.js +119 -0
  329. package/dist/core/tasks/completion.js.map +1 -0
  330. package/dist/core/tasks/contracts.d.ts +404 -0
  331. package/dist/core/tasks/contracts.d.ts.map +1 -0
  332. package/dist/core/tasks/contracts.js +2 -0
  333. package/dist/core/tasks/contracts.js.map +1 -0
  334. package/dist/core/tasks/execution-scope.d.ts +10 -0
  335. package/dist/core/tasks/execution-scope.d.ts.map +1 -0
  336. package/dist/core/tasks/execution-scope.js +27 -0
  337. package/dist/core/tasks/execution-scope.js.map +1 -0
  338. package/dist/core/tasks/owner-store.d.ts +53 -0
  339. package/dist/core/tasks/owner-store.d.ts.map +1 -0
  340. package/dist/core/tasks/owner-store.js +155 -0
  341. package/dist/core/tasks/owner-store.js.map +1 -0
  342. package/dist/core/tasks/pause.d.ts +4 -0
  343. package/dist/core/tasks/pause.d.ts.map +1 -0
  344. package/dist/core/tasks/pause.js +49 -0
  345. package/dist/core/tasks/pause.js.map +1 -0
  346. package/dist/core/tasks/supervisor.d.ts +123 -0
  347. package/dist/core/tasks/supervisor.d.ts.map +1 -0
  348. package/dist/core/tasks/supervisor.js +942 -0
  349. package/dist/core/tasks/supervisor.js.map +1 -0
  350. package/dist/core/tasks/transcript.d.ts +23 -0
  351. package/dist/core/tasks/transcript.d.ts.map +1 -0
  352. package/dist/core/tasks/transcript.js +74 -0
  353. package/dist/core/tasks/transcript.js.map +1 -0
  354. package/dist/core/tools/ask-user-question/ask-user-question.d.ts +2 -2
  355. package/dist/core/tools/ask-user-question/ask-user-question.d.ts.map +1 -1
  356. package/dist/core/tools/ask-user-question/ask-user-question.js +8 -4
  357. package/dist/core/tools/ask-user-question/ask-user-question.js.map +1 -1
  358. package/dist/core/tools/ask-user-question/state/build-questionnaire.d.ts +1 -1
  359. package/dist/core/tools/ask-user-question/state/build-questionnaire.js.map +1 -1
  360. package/dist/core/tools/ask-user-question/state/questionnaire-session.d.ts +1 -1
  361. package/dist/core/tools/ask-user-question/state/questionnaire-session.js.map +1 -1
  362. package/dist/core/tools/ask-user-question/view/components/multi-select-view.d.ts +1 -1
  363. package/dist/core/tools/ask-user-question/view/components/multi-select-view.js.map +1 -1
  364. package/dist/core/tools/ask-user-question/view/components/preview/markdown-content-cache.d.ts +1 -1
  365. package/dist/core/tools/ask-user-question/view/components/preview/markdown-content-cache.js.map +1 -1
  366. package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.d.ts +1 -1
  367. package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.js.map +1 -1
  368. package/dist/core/tools/ask-user-question/view/components/submit-picker.d.ts +1 -1
  369. package/dist/core/tools/ask-user-question/view/components/submit-picker.js.map +1 -1
  370. package/dist/core/tools/ask-user-question/view/components/tab-bar.d.ts +1 -1
  371. package/dist/core/tools/ask-user-question/view/components/tab-bar.js.map +1 -1
  372. package/dist/core/tools/ask-user-question/view/dialog-builder.d.ts +1 -1
  373. package/dist/core/tools/ask-user-question/view/dialog-builder.js.map +1 -1
  374. package/dist/core/tools/ask-user-question/view/tab-content-strategy.d.ts +1 -1
  375. package/dist/core/tools/ask-user-question/view/tab-content-strategy.js.map +1 -1
  376. package/dist/core/tools/bash-pty-native.d.ts +32 -3
  377. package/dist/core/tools/bash-pty-native.d.ts.map +1 -1
  378. package/dist/core/tools/bash-pty-native.js +198 -1
  379. package/dist/core/tools/bash-pty-native.js.map +1 -1
  380. package/dist/core/tools/bash.d.ts +25 -5
  381. package/dist/core/tools/bash.d.ts.map +1 -1
  382. package/dist/core/tools/bash.js +100 -10
  383. package/dist/core/tools/bash.js.map +1 -1
  384. package/dist/core/tools/edit.d.ts +3 -0
  385. package/dist/core/tools/edit.d.ts.map +1 -1
  386. package/dist/core/tools/edit.js +92 -14
  387. package/dist/core/tools/edit.js.map +1 -1
  388. package/dist/core/tools/file-mutation-coordinator.d.ts +255 -0
  389. package/dist/core/tools/file-mutation-coordinator.d.ts.map +1 -0
  390. package/dist/core/tools/file-mutation-coordinator.js +300 -0
  391. package/dist/core/tools/file-mutation-coordinator.js.map +1 -0
  392. package/dist/core/tools/file-mutation-queue.d.ts +14 -1
  393. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  394. package/dist/core/tools/file-mutation-queue.js +15 -3
  395. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  396. package/dist/core/tools/find.js.map +1 -1
  397. package/dist/core/tools/grep.js.map +1 -1
  398. package/dist/core/tools/hashline.d.ts +9 -0
  399. package/dist/core/tools/hashline.d.ts.map +1 -1
  400. package/dist/core/tools/hashline.js +12 -1
  401. package/dist/core/tools/hashline.js.map +1 -1
  402. package/dist/core/tools/index.d.ts +15 -4
  403. package/dist/core/tools/index.d.ts.map +1 -1
  404. package/dist/core/tools/index.js +79 -12
  405. package/dist/core/tools/index.js.map +1 -1
  406. package/dist/core/tools/kill.d.ts +17 -0
  407. package/dist/core/tools/kill.d.ts.map +1 -0
  408. package/dist/core/tools/kill.js +49 -0
  409. package/dist/core/tools/kill.js.map +1 -0
  410. package/dist/core/tools/ls.js.map +1 -1
  411. package/dist/core/tools/non-minting-snapshot-store.d.ts +49 -0
  412. package/dist/core/tools/non-minting-snapshot-store.d.ts.map +1 -0
  413. package/dist/core/tools/non-minting-snapshot-store.js +64 -0
  414. package/dist/core/tools/non-minting-snapshot-store.js.map +1 -0
  415. package/dist/core/tools/powershell.d.ts +100 -34
  416. package/dist/core/tools/powershell.d.ts.map +1 -1
  417. package/dist/core/tools/powershell.js +41 -11
  418. package/dist/core/tools/powershell.js.map +1 -1
  419. package/dist/core/tools/read-document-extract.js.map +1 -1
  420. package/dist/core/tools/read.d.ts.map +1 -1
  421. package/dist/core/tools/read.js +1 -2
  422. package/dist/core/tools/read.js.map +1 -1
  423. package/dist/core/tools/render-utils.d.ts +1 -1
  424. package/dist/core/tools/render-utils.js.map +1 -1
  425. package/dist/core/tools/resource-selectors.d.ts +1 -1
  426. package/dist/core/tools/resource-selectors.d.ts.map +1 -1
  427. package/dist/core/tools/resource-selectors.js +21 -10
  428. package/dist/core/tools/resource-selectors.js.map +1 -1
  429. package/dist/core/tools/search.js.map +1 -1
  430. package/dist/core/tools/todos-render.d.ts +1 -1
  431. package/dist/core/tools/todos-render.js.map +1 -1
  432. package/dist/core/tools/write.d.ts +30 -1
  433. package/dist/core/tools/write.d.ts.map +1 -1
  434. package/dist/core/tools/write.js +98 -10
  435. package/dist/core/tools/write.js.map +1 -1
  436. package/dist/core/workflow-stage-admission.d.ts +24 -0
  437. package/dist/core/workflow-stage-admission.d.ts.map +1 -1
  438. package/dist/core/workflow-stage-admission.js +87 -3
  439. package/dist/core/workflow-stage-admission.js.map +1 -1
  440. package/dist/extensions/herdr/activity.d.ts +15 -0
  441. package/dist/extensions/herdr/activity.d.ts.map +1 -0
  442. package/dist/extensions/herdr/activity.js +24 -0
  443. package/dist/extensions/herdr/activity.js.map +1 -0
  444. package/dist/extensions/herdr/environment.d.ts +7 -0
  445. package/dist/extensions/herdr/environment.d.ts.map +1 -0
  446. package/dist/extensions/herdr/environment.js +6 -0
  447. package/dist/extensions/herdr/environment.js.map +1 -0
  448. package/dist/extensions/herdr/index.d.ts +9 -0
  449. package/dist/extensions/herdr/index.d.ts.map +1 -0
  450. package/dist/extensions/herdr/index.js +225 -0
  451. package/dist/extensions/herdr/index.js.map +1 -0
  452. package/dist/extensions/herdr/pane-owner.d.ts +30 -0
  453. package/dist/extensions/herdr/pane-owner.d.ts.map +1 -0
  454. package/dist/extensions/herdr/pane-owner.js +111 -0
  455. package/dist/extensions/herdr/pane-owner.js.map +1 -0
  456. package/dist/extensions/herdr/transport.d.ts +8 -0
  457. package/dist/extensions/herdr/transport.d.ts.map +1 -0
  458. package/dist/extensions/herdr/transport.js +28 -0
  459. package/dist/extensions/herdr/transport.js.map +1 -0
  460. package/dist/extensions/index.d.ts.map +1 -1
  461. package/dist/extensions/index.js +2 -0
  462. package/dist/extensions/index.js.map +1 -1
  463. package/dist/extensions/llama/huggingface-ui.d.ts +1 -1
  464. package/dist/extensions/llama/huggingface-ui.js.map +1 -1
  465. package/dist/extensions/llama/ui.js.map +1 -1
  466. package/dist/index-extensions.d.ts +3 -2
  467. package/dist/index-extensions.d.ts.map +1 -1
  468. package/dist/index-extensions.js.map +1 -1
  469. package/dist/index.d.ts +14 -5
  470. package/dist/index.d.ts.map +1 -1
  471. package/dist/index.js +10 -1
  472. package/dist/index.js.map +1 -1
  473. package/dist/main-session.js.map +1 -1
  474. package/dist/main.d.ts.map +1 -1
  475. package/dist/main.js +149 -69
  476. package/dist/main.js.map +1 -1
  477. package/dist/modes/interactive/components/armin.js.map +1 -1
  478. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  479. package/dist/modes/interactive/components/atomic-banner.d.ts +1 -1
  480. package/dist/modes/interactive/components/atomic-banner.js.map +1 -1
  481. package/dist/modes/interactive/components/atomic-working-status.js.map +1 -1
  482. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  483. package/dist/modes/interactive/components/bordered-loader.d.ts +1 -1
  484. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  485. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  486. package/dist/modes/interactive/components/chat-message-renderer.d.ts +12 -0
  487. package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
  488. package/dist/modes/interactive/components/chat-message-renderer.js +44 -0
  489. package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
  490. package/dist/modes/interactive/components/chat-session-host-actions.d.ts +1 -1
  491. package/dist/modes/interactive/components/chat-session-host-actions.d.ts.map +1 -1
  492. package/dist/modes/interactive/components/chat-session-host-actions.js +43 -8
  493. package/dist/modes/interactive/components/chat-session-host-actions.js.map +1 -1
  494. package/dist/modes/interactive/components/chat-session-host-editor.d.ts +1 -1
  495. package/dist/modes/interactive/components/chat-session-host-editor.js.map +1 -1
  496. package/dist/modes/interactive/components/chat-session-host-events.d.ts +2 -2
  497. package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -1
  498. package/dist/modes/interactive/components/chat-session-host-rendering.d.ts +2 -2
  499. package/dist/modes/interactive/components/chat-session-host-rendering.d.ts.map +1 -1
  500. package/dist/modes/interactive/components/chat-session-host-rendering.js +12 -3
  501. package/dist/modes/interactive/components/chat-session-host-rendering.js.map +1 -1
  502. package/dist/modes/interactive/components/chat-session-host-runtime.d.ts +4 -5
  503. package/dist/modes/interactive/components/chat-session-host-runtime.d.ts.map +1 -1
  504. package/dist/modes/interactive/components/chat-session-host-runtime.js +8 -6
  505. package/dist/modes/interactive/components/chat-session-host-runtime.js.map +1 -1
  506. package/dist/modes/interactive/components/chat-session-host-state.d.ts +7 -2
  507. package/dist/modes/interactive/components/chat-session-host-state.d.ts.map +1 -1
  508. package/dist/modes/interactive/components/chat-session-host-state.js +1 -0
  509. package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
  510. package/dist/modes/interactive/components/chat-session-host-terminal-cleanup.d.ts +1 -1
  511. package/dist/modes/interactive/components/chat-session-host-terminal-cleanup.js.map +1 -1
  512. package/dist/modes/interactive/components/chat-session-host-types.d.ts +8 -3
  513. package/dist/modes/interactive/components/chat-session-host-types.d.ts.map +1 -1
  514. package/dist/modes/interactive/components/chat-session-host-types.js.map +1 -1
  515. package/dist/modes/interactive/components/chat-session-host-utils.d.ts +1 -1
  516. package/dist/modes/interactive/components/chat-session-host-utils.d.ts.map +1 -1
  517. package/dist/modes/interactive/components/chat-session-host-utils.js +2 -0
  518. package/dist/modes/interactive/components/chat-session-host-utils.js.map +1 -1
  519. package/dist/modes/interactive/components/chat-session-host.d.ts +17 -2
  520. package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
  521. package/dist/modes/interactive/components/chat-session-host.js +100 -3
  522. package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
  523. package/dist/modes/interactive/components/chat-transcript.d.ts +1 -0
  524. package/dist/modes/interactive/components/chat-transcript.d.ts.map +1 -1
  525. package/dist/modes/interactive/components/chat-transcript.js +1 -1
  526. package/dist/modes/interactive/components/chat-transcript.js.map +1 -1
  527. package/dist/modes/interactive/components/compaction-boundary-message.js.map +1 -1
  528. package/dist/modes/interactive/components/config-selector-list.js.map +1 -1
  529. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  530. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  531. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  532. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  533. package/dist/modes/interactive/components/custom-message.js +12 -0
  534. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  535. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  536. package/dist/modes/interactive/components/diff.js.map +1 -1
  537. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  538. package/dist/modes/interactive/components/earendil-announcement.js.map +1 -1
  539. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  540. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  541. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  542. package/dist/modes/interactive/components/first-time-setup.d.ts +1 -1
  543. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  544. package/dist/modes/interactive/components/footer.d.ts +7 -6
  545. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  546. package/dist/modes/interactive/components/footer.js +27 -9
  547. package/dist/modes/interactive/components/footer.js.map +1 -1
  548. package/dist/modes/interactive/components/host-input-form-mount.js.map +1 -1
  549. package/dist/modes/interactive/components/host-input-form.d.ts +1 -1
  550. package/dist/modes/interactive/components/host-input-form.js.map +1 -1
  551. package/dist/modes/interactive/components/index.d.ts +2 -2
  552. package/dist/modes/interactive/components/index.js.map +1 -1
  553. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  554. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  555. package/dist/modes/interactive/components/mermaid.d.ts +1 -1
  556. package/dist/modes/interactive/components/mermaid.js.map +1 -1
  557. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  558. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  559. package/dist/modes/interactive/components/reserved-bottom-overlay.js.map +1 -1
  560. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  561. package/dist/modes/interactive/components/scroll-widget.d.ts +23 -0
  562. package/dist/modes/interactive/components/scroll-widget.d.ts.map +1 -0
  563. package/dist/modes/interactive/components/scroll-widget.js +61 -0
  564. package/dist/modes/interactive/components/scroll-widget.js.map +1 -0
  565. package/dist/modes/interactive/components/session-selector-header.js.map +1 -1
  566. package/dist/modes/interactive/components/session-selector-list.js.map +1 -1
  567. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  568. package/dist/modes/interactive/components/settings-selector-items.js.map +1 -1
  569. package/dist/modes/interactive/components/settings-selector-submenus.d.ts +1 -1
  570. package/dist/modes/interactive/components/settings-selector-submenus.js.map +1 -1
  571. package/dist/modes/interactive/components/settings-selector-types.d.ts +1 -1
  572. package/dist/modes/interactive/components/settings-selector-types.js.map +1 -1
  573. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  574. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  575. package/dist/modes/interactive/components/skill-invocation-message.d.ts +1 -1
  576. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  577. package/dist/modes/interactive/components/task-completion-message.d.ts +13 -0
  578. package/dist/modes/interactive/components/task-completion-message.d.ts.map +1 -0
  579. package/dist/modes/interactive/components/task-completion-message.js +65 -0
  580. package/dist/modes/interactive/components/task-completion-message.js.map +1 -0
  581. package/dist/modes/interactive/components/task-detail.d.ts +27 -0
  582. package/dist/modes/interactive/components/task-detail.d.ts.map +1 -0
  583. package/dist/modes/interactive/components/task-detail.js +107 -0
  584. package/dist/modes/interactive/components/task-detail.js.map +1 -0
  585. package/dist/modes/interactive/components/task-inspector.d.ts +50 -0
  586. package/dist/modes/interactive/components/task-inspector.d.ts.map +1 -0
  587. package/dist/modes/interactive/components/task-inspector.js +599 -0
  588. package/dist/modes/interactive/components/task-inspector.js.map +1 -0
  589. package/dist/modes/interactive/components/task-list.d.ts +18 -0
  590. package/dist/modes/interactive/components/task-list.d.ts.map +1 -0
  591. package/dist/modes/interactive/components/task-list.js +59 -0
  592. package/dist/modes/interactive/components/task-list.js.map +1 -0
  593. package/dist/modes/interactive/components/task-live-transcript.d.ts +17 -0
  594. package/dist/modes/interactive/components/task-live-transcript.d.ts.map +1 -0
  595. package/dist/modes/interactive/components/task-live-transcript.js +41 -0
  596. package/dist/modes/interactive/components/task-live-transcript.js.map +1 -0
  597. package/dist/modes/interactive/components/task-navigation.d.ts +38 -0
  598. package/dist/modes/interactive/components/task-navigation.d.ts.map +1 -0
  599. package/dist/modes/interactive/components/task-navigation.js +93 -0
  600. package/dist/modes/interactive/components/task-navigation.js.map +1 -0
  601. package/dist/modes/interactive/components/task-row.d.ts +34 -0
  602. package/dist/modes/interactive/components/task-row.d.ts.map +1 -0
  603. package/dist/modes/interactive/components/task-row.js +165 -0
  604. package/dist/modes/interactive/components/task-row.js.map +1 -0
  605. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  606. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  607. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  608. package/dist/modes/interactive/components/transcript-follow-indicator.js.map +1 -1
  609. package/dist/modes/interactive/components/tree-selector-component.js.map +1 -1
  610. package/dist/modes/interactive/components/tree-selector-content.js.map +1 -1
  611. package/dist/modes/interactive/components/tree-selector-help.js.map +1 -1
  612. package/dist/modes/interactive/components/tree-selector-label-input.js.map +1 -1
  613. package/dist/modes/interactive/components/tree-selector-list.js.map +1 -1
  614. package/dist/modes/interactive/components/trust-selector.js.map +1 -1
  615. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  616. package/dist/modes/interactive/components/user-message.js.map +1 -1
  617. package/dist/modes/interactive/components/working-status.js.map +1 -1
  618. package/dist/modes/interactive/interactive-agent-events.js +8 -2
  619. package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
  620. package/dist/modes/interactive/interactive-auth-login.js +3 -1
  621. package/dist/modes/interactive/interactive-auth-login.js.map +1 -1
  622. package/dist/modes/interactive/interactive-autocomplete.js +9 -30
  623. package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
  624. package/dist/modes/interactive/interactive-deferred-startup.js +2 -1
  625. package/dist/modes/interactive/interactive-deferred-startup.js.map +1 -1
  626. package/dist/modes/interactive/interactive-extension-context.js +14 -4
  627. package/dist/modes/interactive/interactive-extension-context.js.map +1 -1
  628. package/dist/modes/interactive/interactive-extension-custom-ui.js +52 -4
  629. package/dist/modes/interactive/interactive-extension-custom-ui.js.map +1 -1
  630. package/dist/modes/interactive/interactive-extension-runtime.js +11 -3
  631. package/dist/modes/interactive/interactive-extension-runtime.js.map +1 -1
  632. package/dist/modes/interactive/interactive-extension-widgets.js +9 -1
  633. package/dist/modes/interactive/interactive-extension-widgets.js.map +1 -1
  634. package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
  635. package/dist/modes/interactive/interactive-input-handling.js +19 -0
  636. package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
  637. package/dist/modes/interactive/interactive-mode-base.d.ts +7 -1
  638. package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
  639. package/dist/modes/interactive/interactive-mode-base.js +10 -4
  640. package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
  641. package/dist/modes/interactive/interactive-mode-deps.d.ts +6 -6
  642. package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
  643. package/dist/modes/interactive/interactive-mode-surface.d.ts +3 -2
  644. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  645. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  646. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  647. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  648. package/dist/modes/interactive/interactive-mode.js +3 -0
  649. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  650. package/dist/modes/interactive/interactive-process-lifecycle.js +4 -1
  651. package/dist/modes/interactive/interactive-process-lifecycle.js.map +1 -1
  652. package/dist/modes/interactive/interactive-render-chat.js +30 -4
  653. package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
  654. package/dist/modes/interactive/interactive-session-routing.js +33 -23
  655. package/dist/modes/interactive/interactive-session-routing.js.map +1 -1
  656. package/dist/modes/interactive/interactive-session-runtime.js +1 -0
  657. package/dist/modes/interactive/interactive-session-runtime.js.map +1 -1
  658. package/dist/modes/interactive/interactive-slash-commands.js.map +1 -1
  659. package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
  660. package/dist/modes/interactive/interactive-startup.js +3 -0
  661. package/dist/modes/interactive/interactive-startup.js.map +1 -1
  662. package/dist/modes/interactive/interactive-summarization-retry-events.js +2 -2
  663. package/dist/modes/interactive/interactive-summarization-retry-events.js.map +1 -1
  664. package/dist/modes/interactive/interactive-task-projection.d.ts +13 -0
  665. package/dist/modes/interactive/interactive-task-projection.d.ts.map +1 -0
  666. package/dist/modes/interactive/interactive-task-projection.js +72 -0
  667. package/dist/modes/interactive/interactive-task-projection.js.map +1 -0
  668. package/dist/modes/interactive/interactive-tui.js.map +1 -1
  669. package/dist/modes/interactive/interactive-windows-subshell.d.ts +17 -0
  670. package/dist/modes/interactive/interactive-windows-subshell.d.ts.map +1 -0
  671. package/dist/modes/interactive/interactive-windows-subshell.js +92 -0
  672. package/dist/modes/interactive/interactive-windows-subshell.js.map +1 -0
  673. package/dist/modes/interactive/skill-command-autocomplete.d.ts +12 -0
  674. package/dist/modes/interactive/skill-command-autocomplete.d.ts.map +1 -0
  675. package/dist/modes/interactive/skill-command-autocomplete.js +69 -0
  676. package/dist/modes/interactive/skill-command-autocomplete.js.map +1 -0
  677. package/dist/modes/interactive/theme/theme-class.d.ts.map +1 -1
  678. package/dist/modes/interactive/theme/theme-class.js +4 -1
  679. package/dist/modes/interactive/theme/theme-class.js.map +1 -1
  680. package/dist/modes/interactive/theme/theme-controller.d.ts +1 -1
  681. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  682. package/dist/modes/interactive-engine/activity-watchdog.d.ts +2 -2
  683. package/dist/modes/interactive-engine/activity-watchdog.d.ts.map +1 -1
  684. package/dist/modes/interactive-engine/activity-watchdog.js.map +1 -1
  685. package/dist/modes/interactive-engine/create-isolated-runtime.d.ts +1 -1
  686. package/dist/modes/interactive-engine/create-isolated-runtime.js.map +1 -1
  687. package/dist/modes/interactive-engine/engine-custom-ui.d.ts +9 -10
  688. package/dist/modes/interactive-engine/engine-custom-ui.d.ts.map +1 -1
  689. package/dist/modes/interactive-engine/engine-custom-ui.js +29 -12
  690. package/dist/modes/interactive-engine/engine-custom-ui.js.map +1 -1
  691. package/dist/modes/interactive-engine/engine-diagnostic-view.d.ts +3 -1
  692. package/dist/modes/interactive-engine/engine-diagnostic-view.d.ts.map +1 -1
  693. package/dist/modes/interactive-engine/engine-diagnostic-view.js +11 -0
  694. package/dist/modes/interactive-engine/engine-diagnostic-view.js.map +1 -1
  695. package/dist/modes/interactive-engine/engine-dialog-host.d.ts +2 -2
  696. package/dist/modes/interactive-engine/engine-dialog-host.d.ts.map +1 -1
  697. package/dist/modes/interactive-engine/engine-dialog-host.js +4 -1
  698. package/dist/modes/interactive-engine/engine-dialog-host.js.map +1 -1
  699. package/dist/modes/interactive-engine/engine-project-trust.d.ts +10 -0
  700. package/dist/modes/interactive-engine/engine-project-trust.d.ts.map +1 -0
  701. package/dist/modes/interactive-engine/engine-project-trust.js +28 -0
  702. package/dist/modes/interactive-engine/engine-project-trust.js.map +1 -0
  703. package/dist/modes/interactive-engine/engine-render-service.d.ts +1 -1
  704. package/dist/modes/interactive-engine/engine-render-service.js.map +1 -1
  705. package/dist/modes/interactive-engine/extension-ui-bridge.d.ts +3 -1
  706. package/dist/modes/interactive-engine/extension-ui-bridge.d.ts.map +1 -1
  707. package/dist/modes/interactive-engine/extension-ui-bridge.js +7 -1
  708. package/dist/modes/interactive-engine/extension-ui-bridge.js.map +1 -1
  709. package/dist/modes/interactive-engine/input-form-host.d.ts +2 -2
  710. package/dist/modes/interactive-engine/input-form-host.js.map +1 -1
  711. package/dist/modes/interactive-engine/isolated-auth.d.ts +1 -1
  712. package/dist/modes/interactive-engine/isolated-auth.js.map +1 -1
  713. package/dist/modes/interactive-engine/isolated-runtime.d.ts +5 -2
  714. package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
  715. package/dist/modes/interactive-engine/isolated-runtime.js +42 -4
  716. package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
  717. package/dist/modes/interactive-engine/protocol.d.ts +21 -1
  718. package/dist/modes/interactive-engine/protocol.d.ts.map +1 -1
  719. package/dist/modes/interactive-engine/protocol.js +53 -2
  720. package/dist/modes/interactive-engine/protocol.js.map +1 -1
  721. package/dist/modes/interactive-engine/remote-component.d.ts +2 -2
  722. package/dist/modes/interactive-engine/remote-component.d.ts.map +1 -1
  723. package/dist/modes/interactive-engine/remote-component.js +19 -8
  724. package/dist/modes/interactive-engine/remote-component.js.map +1 -1
  725. package/dist/modes/interactive-engine/remote-model-catalog.d.ts +1 -1
  726. package/dist/modes/interactive-engine/remote-model-catalog.js.map +1 -1
  727. package/dist/modes/interactive-engine/remote-renderer.d.ts +1 -1
  728. package/dist/modes/interactive-engine/remote-renderer.js.map +1 -1
  729. package/dist/modes/interactive-engine/session-picker-host.d.ts +2 -2
  730. package/dist/modes/interactive-engine/session-picker-host.js.map +1 -1
  731. package/dist/modes/json-event.d.ts +1 -1
  732. package/dist/modes/json-event.js.map +1 -1
  733. package/dist/modes/print-mode.js.map +1 -1
  734. package/dist/modes/rpc/rpc-bash-request-owners.d.ts +2 -2
  735. package/dist/modes/rpc/rpc-bash-request-owners.js.map +1 -1
  736. package/dist/modes/rpc/rpc-client-api.d.ts +2 -2
  737. package/dist/modes/rpc/rpc-client-api.d.ts.map +1 -1
  738. package/dist/modes/rpc/rpc-client-api.js +2 -2
  739. package/dist/modes/rpc/rpc-client-api.js.map +1 -1
  740. package/dist/modes/rpc/rpc-client-process.d.ts +2 -0
  741. package/dist/modes/rpc/rpc-client-process.d.ts.map +1 -1
  742. package/dist/modes/rpc/rpc-client-process.js +23 -1
  743. package/dist/modes/rpc/rpc-client-process.js.map +1 -1
  744. package/dist/modes/rpc/rpc-client-waits.d.ts +1 -1
  745. package/dist/modes/rpc/rpc-client-waits.js.map +1 -1
  746. package/dist/modes/rpc/rpc-client.d.ts +3 -1
  747. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  748. package/dist/modes/rpc/rpc-client.js +40 -3
  749. package/dist/modes/rpc/rpc-client.js.map +1 -1
  750. package/dist/modes/rpc/rpc-command-handler.d.ts +4 -2
  751. package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
  752. package/dist/modes/rpc/rpc-command-handler.js +12 -4
  753. package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
  754. package/dist/modes/rpc/rpc-extension-ui.d.ts +1 -1
  755. package/dist/modes/rpc/rpc-extension-ui.d.ts.map +1 -1
  756. package/dist/modes/rpc/rpc-extension-ui.js +2 -1
  757. package/dist/modes/rpc/rpc-extension-ui.js.map +1 -1
  758. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  759. package/dist/modes/rpc/rpc-mode.js +12 -2
  760. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  761. package/dist/modes/rpc/rpc-provider-auth.d.ts +1 -1
  762. package/dist/modes/rpc/rpc-provider-auth.js.map +1 -1
  763. package/dist/modes/rpc/rpc-session-binding.d.ts +4 -1
  764. package/dist/modes/rpc/rpc-session-binding.d.ts.map +1 -1
  765. package/dist/modes/rpc/rpc-session-binding.js +35 -1
  766. package/dist/modes/rpc/rpc-session-binding.js.map +1 -1
  767. package/dist/modes/rpc/rpc-types.d.ts +17 -1
  768. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  769. package/dist/modes/rpc/rpc-types.js.map +1 -1
  770. package/dist/modes/rpc/task-ui-bridge.d.ts +9 -0
  771. package/dist/modes/rpc/task-ui-bridge.d.ts.map +1 -0
  772. package/dist/modes/rpc/task-ui-bridge.js +146 -0
  773. package/dist/modes/rpc/task-ui-bridge.js.map +1 -0
  774. package/dist/self-update-plan.js.map +1 -1
  775. package/dist/utils/markit.d.ts +2 -0
  776. package/dist/utils/markit.d.ts.map +1 -1
  777. package/dist/utils/markit.js +65 -5
  778. package/dist/utils/markit.js.map +1 -1
  779. package/docs/background-tasks.md +232 -0
  780. package/docs/build.md +51 -0
  781. package/docs/changelog.mdx +8 -8
  782. package/docs/compaction/reference.md +267 -0
  783. package/docs/compaction.md +39 -200
  784. package/docs/computer-use.md +425 -0
  785. package/docs/containerization.md +9 -5
  786. package/docs/custom-provider/api-reference.md +145 -0
  787. package/docs/custom-provider/oauth.md +131 -0
  788. package/docs/custom-provider/override.md +34 -0
  789. package/docs/custom-provider/registration.md +163 -0
  790. package/docs/custom-provider/streaming.md +214 -0
  791. package/docs/custom-provider.md +43 -607
  792. package/docs/development.md +68 -30
  793. package/docs/docs.json +199 -73
  794. package/docs/environment-variables.md +2 -2
  795. package/docs/extensions/api-reference.md +1003 -0
  796. package/docs/extensions/authoring.md +676 -0
  797. package/docs/extensions/events.md +793 -0
  798. package/docs/extensions/examples.md +94 -0
  799. package/docs/extensions/ui.md +470 -0
  800. package/docs/extensions.md +241 -2623
  801. package/docs/getting-started/authentication.md +55 -0
  802. package/docs/getting-started/first-session.md +172 -0
  803. package/docs/getting-started/installation.md +154 -0
  804. package/docs/getting-started/project-instructions.md +43 -0
  805. package/docs/guides/configuration.md +65 -0
  806. package/docs/guides/intercom.md +24 -0
  807. package/docs/guides/non-interactive.md +33 -0
  808. package/docs/guides/subagents.md +24 -0
  809. package/docs/guides/workflows.md +27 -0
  810. package/docs/guides.md +41 -0
  811. package/docs/herdr.md +55 -0
  812. package/docs/index.md +13 -44
  813. package/docs/intercom/operations.md +178 -0
  814. package/docs/intercom/reference.md +150 -0
  815. package/docs/intercom.md +61 -251
  816. package/docs/json.md +17 -0
  817. package/docs/keybindings.md +36 -2
  818. package/docs/llama-cpp.md +5 -0
  819. package/docs/models/artificial-analysis-index.md +89 -0
  820. package/docs/models/evals.md +225 -148
  821. package/docs/models/model-selection.md +30 -21
  822. package/docs/models/pareto-efficiency.md +4 -4
  823. package/docs/models/reference.md +601 -0
  824. package/docs/models.md +45 -550
  825. package/docs/packages/authoring.md +88 -0
  826. package/docs/packages/reference.md +43 -0
  827. package/docs/packages.md +28 -107
  828. package/docs/programmatic.md +29 -0
  829. package/docs/prompt-templates.md +11 -0
  830. package/docs/providers/reference.md +23 -0
  831. package/docs/providers.md +59 -62
  832. package/docs/quickstart.md +45 -239
  833. package/docs/reference/cli.md +252 -0
  834. package/docs/reference.md +52 -0
  835. package/docs/rpc/examples.md +64 -0
  836. package/docs/rpc/extension-ui.md +198 -0
  837. package/docs/rpc/protocol.md +1341 -0
  838. package/docs/rpc.md +109 -1346
  839. package/docs/sdk/reference.md +1090 -0
  840. package/docs/sdk.md +64 -756
  841. package/docs/session-format.md +2 -0
  842. package/docs/sessions.md +6 -10
  843. package/docs/settings.md +45 -48
  844. package/docs/skills/authoring.md +95 -0
  845. package/docs/skills/reference.md +60 -0
  846. package/docs/skills.md +37 -117
  847. package/docs/subagents/authoring.md +37 -0
  848. package/docs/subagents/reference.md +60 -0
  849. package/docs/subagents.md +90 -78
  850. package/docs/terminal-setup.md +1 -1
  851. package/docs/themes/reference.md +176 -0
  852. package/docs/themes.md +25 -135
  853. package/docs/tmux.md +7 -0
  854. package/docs/tools/edit.md +5 -0
  855. package/docs/tools.md +67 -1
  856. package/docs/tui/reference.md +343 -0
  857. package/docs/tui.md +83 -285
  858. package/docs/usage.md +31 -210
  859. package/docs/web-access.md +50 -0
  860. package/docs/windows.md +6 -5
  861. package/docs/workflows/api-reference.md +31 -12
  862. package/docs/workflows/authoring.md +7 -5
  863. package/docs/workflows/builtins.md +11 -8
  864. package/docs/workflows/operations.md +117 -39
  865. package/docs/workflows/reliable-design.md +59 -10
  866. package/docs/workflows/verification.md +116 -32
  867. package/docs/workflows.md +7 -3
  868. package/examples/extensions/gondolin/index.ts +116 -148
  869. package/examples/extensions/gondolin/package.json +1 -1
  870. package/examples/extensions/ssh.ts +56 -34
  871. package/npm-shrinkwrap.json +798 -678
  872. package/package.json +11 -11
  873. /package/dist/builtin/workflows/builtin/{chunk-cg9tmks0.js → chunk-n1910xc4.js} +0 -0
  874. /package/dist/builtin/workflows/builtin/{chunk-wpckd35c.js → chunk-rc5ec5xx.js} +0 -0
  875. /package/dist/builtin/workflows/builtin/{chunk-7at6dnkr.js → chunk-tgt0s5e5.js} +0 -0
  876. /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);
@@ -472,6 +523,7 @@ var init_client = __esm(() => {
472
523
  _supervisorSessionId = null;
473
524
  _messageSource;
474
525
  pendingSends = new PendingSendRegistry;
526
+ pendingReplyTargets = new Map;
475
527
  pendingGroupLists = new Map;
476
528
  pendingLists = new Map;
477
529
  pendingPresence = new Map;
@@ -676,7 +728,24 @@ var init_client = __esm(() => {
676
728
  case "registration_failed": {
677
729
  if (typeof brokerMessage.reason !== "string")
678
730
  throw new Error("Invalid registration_failed message");
679
- this.emit("_registration_failed", new Error(brokerMessage.reason));
731
+ const refusal = new Error(brokerMessage.reason);
732
+ if (this._sessionId === null) {
733
+ this.emit("_registration_failed", refusal);
734
+ break;
735
+ }
736
+ this.disconnectError ??= refusal;
737
+ this.failPending(this.disconnectError);
738
+ this.socket?.destroy();
739
+ break;
740
+ }
741
+ case "question_target": {
742
+ const { messageId, attemptId, sessionId } = brokerMessage;
743
+ if (typeof messageId !== "string" || typeof attemptId !== "string" || typeof sessionId !== "string") {
744
+ throw new Error("Invalid question_target message");
745
+ }
746
+ const pending = this.pendingReplyTargets.get(attemptId);
747
+ if (pending?.messageId === messageId)
748
+ pending.bind(sessionId);
680
749
  break;
681
750
  }
682
751
  case "sessions": {
@@ -1096,14 +1165,15 @@ var init_client = __esm(() => {
1096
1165
  }
1097
1166
  });
1098
1167
  }
1099
- registerPendingStageRoute(runId, group, capability, stages, possibleStages) {
1168
+ registerPendingStageRoute(runId, group, capability, stages, possibleStages, parent) {
1100
1169
  writeMessage(this.requireActiveSocket(), {
1101
1170
  type: "register_pending_stage_route",
1102
1171
  runId,
1103
1172
  group,
1104
1173
  capability,
1105
1174
  stages,
1106
- possibleStages
1175
+ possibleStages,
1176
+ ...parent === undefined ? {} : { parent }
1107
1177
  });
1108
1178
  }
1109
1179
  registerLiveWorkflowStageRoute(runId, stageKeys, capability) {
@@ -1177,7 +1247,8 @@ var init_client = __esm(() => {
1177
1247
  const pendingSignature = JSON.stringify({
1178
1248
  transportTarget: to,
1179
1249
  logicalSignature: buildSendSignature(options.logicalTarget ?? to, options),
1180
- requirePendingReply: options.requirePendingReply ?? false
1250
+ requirePendingReply: options.requirePendingReply ?? false,
1251
+ ...options.expectedRecipientId === undefined ? {} : { expectedRecipientId: options.expectedRecipientId }
1181
1252
  });
1182
1253
  acquired = this.pendingSends.acquire(messageId, pendingSignature, 1e4);
1183
1254
  } catch (error) {
@@ -1194,12 +1265,17 @@ var init_client = __esm(() => {
1194
1265
  source: this._messageSource,
1195
1266
  content: { text: options.text, attachments: options.attachments }
1196
1267
  };
1268
+ if (options.onReplyTarget !== undefined) {
1269
+ this.pendingReplyTargets.set(acquired.attempt.attemptId, { messageId, bind: options.onReplyTarget });
1270
+ }
1197
1271
  try {
1198
1272
  writeMessage(socket, {
1199
1273
  type,
1200
1274
  to,
1201
1275
  ...options.logicalTarget === undefined ? {} : { logicalTarget: options.logicalTarget },
1202
1276
  ...options.requirePendingReply === undefined ? {} : { requirePendingReply: options.requirePendingReply },
1277
+ ...options.expectedRecipientId === undefined ? {} : { expectedRecipientId: options.expectedRecipientId },
1278
+ ...options.onReplyTarget === undefined ? {} : { resolveReplyTarget: true },
1203
1279
  message,
1204
1280
  attemptId: acquired.attempt.attemptId,
1205
1281
  ...extra
@@ -1207,6 +1283,10 @@ var init_client = __esm(() => {
1207
1283
  } catch (error) {
1208
1284
  this.pendingSends.reject(acquired.attempt, toError(error));
1209
1285
  }
1286
+ const clearReplyTarget = () => {
1287
+ this.pendingReplyTargets.delete(acquired.attempt.attemptId);
1288
+ };
1289
+ acquired.attempt.promise.then(clearReplyTarget, clearReplyTarget);
1210
1290
  return acquired.attempt.promise;
1211
1291
  }
1212
1292
  updatePresence(updates) {
@@ -1676,15 +1756,6 @@ class InlineMessageComponent {
1676
1756
  }
1677
1757
  var init_inline_message = () => {};
1678
1758
 
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
1759
  // dist/builtin/intercom/reply-waiter.ts
1689
1760
  class ReplyWaiterRegistry {
1690
1761
  timeoutMs;
@@ -1756,6 +1827,10 @@ class ReplyWaiterRegistry {
1756
1827
  ok: true,
1757
1828
  wait: {
1758
1829
  promise,
1830
+ bindSender: (sender) => {
1831
+ if (this.waiters.get(replyTo) === record)
1832
+ record.from = sender;
1833
+ },
1759
1834
  cancel: (error) => record.reject(error)
1760
1835
  }
1761
1836
  };
@@ -1923,6 +1998,11 @@ class ReplyTracker {
1923
1998
  endTurn() {
1924
1999
  this.currentTurnContext = null;
1925
2000
  }
2001
+ restoreTurnContext() {
2002
+ if (this.currentTurnContext)
2003
+ this.pendingTurnContexts.unshift(this.currentTurnContext);
2004
+ this.currentTurnContext = null;
2005
+ }
1926
2006
  reset() {
1927
2007
  this.pendingAsks.clear();
1928
2008
  this.pendingTurnContexts.length = 0;
@@ -1930,22 +2010,22 @@ class ReplyTracker {
1930
2010
  }
1931
2011
  resolveReplyTarget(options, now = Date.now()) {
1932
2012
  this.pruneExpired(now);
1933
- if (options.replyTo) {
1934
- const exact = this.pendingAsks.get(options.replyTo);
1935
- if (exact) {
1936
- if (options.to) {
1937
- const resolution = resolveSessionTarget([exact.from], options.to);
1938
- if (resolution.kind !== "resolved")
1939
- throw new Error(`Pending ask "${options.replyTo}" is not from "${options.to}"`);
1940
- }
1941
- return exact;
2013
+ if (options.replyTo !== undefined) {
2014
+ const exact = this.pendingAsks.get(options.replyTo) ?? (this.currentTurnContext?.message.id === options.replyTo && !this.currentTurnContext.message.expectsReply ? this.currentTurnContext : undefined);
2015
+ if (!exact)
2016
+ throw new Error(`No reply context for "${options.replyTo}"`);
2017
+ if (options.to !== undefined) {
2018
+ const resolution = resolveSessionTarget([exact.from], options.to);
2019
+ if (resolution.kind !== "resolved")
2020
+ throw new Error(`Reply context "${options.replyTo}" is not from "${options.to}"`);
1942
2021
  }
2022
+ return exact;
1943
2023
  }
1944
- if (this.currentTurnContext) {
2024
+ if (options.to === undefined && this.currentTurnContext) {
1945
2025
  return this.currentTurnContext;
1946
2026
  }
1947
2027
  const pending = Array.from(this.pendingAsks.values());
1948
- if (options.to) {
2028
+ if (options.to !== undefined) {
1949
2029
  const senders = [...new Map(pending.map((context) => [context.from.id, context.from])).values()];
1950
2030
  const resolution = resolveSessionTarget(senders, options.to);
1951
2031
  if (resolution.kind !== "resolved") {
@@ -2264,32 +2344,32 @@ function validateSupervisorInterviewReply(value, interview) {
2264
2344
  if (!Object.hasOwn(raw, "value")) {
2265
2345
  throw new Error(`responses[${index}].value is required`);
2266
2346
  }
2267
- const value2 = raw.value;
2347
+ const value = raw.value;
2268
2348
  if (question.type === "single") {
2269
- if (typeof value2 !== "string")
2349
+ if (typeof value !== "string")
2270
2350
  throw new Error(`responses[${index}].value must be a string for single questions`);
2271
2351
  const optionLabels = new Set(question.options?.map(interviewOptionLabel));
2272
- if (!optionLabels.has(value2.trim()))
2352
+ if (!optionLabels.has(value.trim()))
2273
2353
  throw new Error(`responses[${index}].value must match one of the question options`);
2274
- responses.push({ id, value: value2.trim() });
2354
+ responses.push({ id, value: value.trim() });
2275
2355
  continue;
2276
2356
  }
2277
2357
  if (question.type === "multi") {
2278
- if (!Array.isArray(value2) || value2.some((item) => typeof item !== "string")) {
2358
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
2279
2359
  throw new Error(`responses[${index}].value must be an array of strings for multi questions`);
2280
2360
  }
2281
2361
  const optionLabels = new Set(question.options?.map(interviewOptionLabel));
2282
- const selected = value2.map((item) => item.trim());
2362
+ const selected = value.map((item) => item.trim());
2283
2363
  const invalid = selected.find((item) => !optionLabels.has(item));
2284
2364
  if (invalid)
2285
2365
  throw new Error(`responses[${index}].value contains an option that is not in the question options: ${invalid}`);
2286
2366
  responses.push({ id, value: selected });
2287
2367
  continue;
2288
2368
  }
2289
- if (typeof value2 !== "string") {
2369
+ if (typeof value !== "string") {
2290
2370
  throw new Error(`responses[${index}].value must be a string for ${question.type} questions`);
2291
2371
  }
2292
- responses.push({ id, value: value2 });
2372
+ responses.push({ id, value });
2293
2373
  }
2294
2374
  return { responses };
2295
2375
  }
@@ -2368,12 +2448,13 @@ function formatSessionLabel(session, duplicates) {
2368
2448
  return duplicates.has(session.name.toLowerCase()) ? `${session.name} (${session.id})` : session.name;
2369
2449
  }
2370
2450
  function formatSessionListRow(session, currentCwd, isSelf) {
2371
- const name = session.name || "Unnamed session";
2451
+ const name = session.name && session.name !== session.id && session.name !== resolveIntercomPresenceName(undefined, session.id) ? ` name: ${session.name}` : "";
2372
2452
  const normalizedGroup = normalizeGroup(session.group);
2373
2453
  const groupTag = normalizedGroup !== DEFAULT_GROUP ? `group: ${normalizedGroup}` : undefined;
2374
- const tags = [isSelf ? "self" : session.cwd === currentCwd ? "same cwd" : undefined, session.status, groupTag].filter((tag) => Boolean(tag));
2454
+ const capabilityTag = session.replyCapability === undefined ? undefined : `replyCapability: ${session.replyCapability}`;
2455
+ const tags = [isSelf ? "self" : session.cwd === currentCwd ? "same cwd" : undefined, session.status, capabilityTag, groupTag].filter((tag) => Boolean(tag));
2375
2456
  const suffix = tags.length ? ` [${tags.join(", ")}]` : "";
2376
- return `• ${name} (${session.id}) ${session.cwd} (${session.model})${suffix}`;
2457
+ return `- \`${session.id}\`${suffix} ${session.cwd} (${session.model})${name}`;
2377
2458
  }
2378
2459
  function previewText(value, maxLength = 72) {
2379
2460
  if (typeof value !== "string") {
@@ -2395,7 +2476,7 @@ import { randomUUID as randomUUID3 } from "crypto";
2395
2476
  import { Type } from "typebox";
2396
2477
  import { Text as Text2 } from "@earendil-works/pi-tui";
2397
2478
  function registerContactSupervisorTool(pi, deps) {
2398
- const { childOrchestratorMetadata, ensureConnected, syncPresenceIdentity, resolveSessionTarget: resolveSessionTarget2, beginReplyWait } = deps;
2479
+ const { childOrchestratorMetadata, ensureConnected, syncPresenceIdentity, resolveSessionTarget, beginReplyWait } = deps;
2399
2480
  const getMetadata = typeof childOrchestratorMetadata === "function" ? childOrchestratorMetadata : () => childOrchestratorMetadata;
2400
2481
  let supervisorWaitActive = false;
2401
2482
  let supervisorHandoffClaimed = false;
@@ -2508,13 +2589,6 @@ function registerContactSupervisorTool(pi, deps) {
2508
2589
  details: { yielded: true }
2509
2590
  };
2510
2591
  }
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
2592
  let connectedClient;
2519
2593
  try {
2520
2594
  connectedClient = await ensureConnected("tool");
@@ -2538,7 +2612,7 @@ function registerContactSupervisorTool(pi, deps) {
2538
2612
  sendTo = connectedClient.supervisorSessionId ?? metadata.supervisor.supervisorSessionId;
2539
2613
  } else {
2540
2614
  try {
2541
- sendTo = await resolveSessionTarget2(connectedClient, metadata.orchestratorTarget) ?? metadata.orchestratorTarget;
2615
+ sendTo = await resolveSessionTarget(connectedClient, metadata.orchestratorTarget) ?? metadata.orchestratorTarget;
2542
2616
  } catch (error) {
2543
2617
  return {
2544
2618
  content: [{ type: "text", text: `Failed to resolve supervisor target: ${getErrorMessage(error)}` }],
@@ -2607,7 +2681,7 @@ function registerContactSupervisorTool(pi, deps) {
2607
2681
  };
2608
2682
  }
2609
2683
  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);
2684
+ 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
2685
  const sendResult = await connectedClient.sendToSupervisor(sendTo, {
2612
2686
  messageId: questionId,
2613
2687
  text: requestText,
@@ -2808,6 +2882,11 @@ class RetryIdentityReservations {
2808
2882
  }
2809
2883
  this.finishRetained(reservation, "settled");
2810
2884
  }
2885
+ discard(retryToken) {
2886
+ const reservation = this.tokenReservations.get(retryToken);
2887
+ if (reservation !== undefined)
2888
+ this.expire(reservation);
2889
+ }
2811
2890
  remainingRetries(attempt) {
2812
2891
  const reservation = this.currentReservation(attempt);
2813
2892
  return reservation === undefined ? 0 : Math.max(0, this.maxReuses - reservation.reuseCount);
@@ -2961,14 +3040,73 @@ var init_retry_identity = __esm(() => {
2961
3040
  };
2962
3041
  });
2963
3042
 
3043
+ // dist/builtin/intercom/tool-retry.ts
3044
+ import { setTimeout as delay2 } from "node:timers/promises";
3045
+ async function runIntercomOperation(attempt, release, signal) {
3046
+ const deadline = new AbortController;
3047
+ const timer = setTimeout(() => deadline.abort(), RETRY_IDENTITY_TTL_MS);
3048
+ const operationSignal = signal === undefined ? deadline.signal : AbortSignal.any([signal, deadline.signal]);
3049
+ let token;
3050
+ let recovering = false;
3051
+ let retries = 0;
3052
+ let last = {
3053
+ content: [{ type: "text", text: "Cancelled" }],
3054
+ isError: true,
3055
+ details: { error: true }
3056
+ };
3057
+ try {
3058
+ for (;; ) {
3059
+ if (operationSignal.aborted)
3060
+ break;
3061
+ last = await attempt(token, operationSignal);
3062
+ const { retryToken, retryable, deliveryUncertain, ...details } = last.details;
3063
+ last = { ...last, details };
3064
+ if (!last.isError)
3065
+ return last;
3066
+ recovering ||= deliveryUncertain === true || retryable === true;
3067
+ const nextToken = typeof retryToken === "string" ? retryToken : undefined;
3068
+ const canRetry = nextToken !== undefined || token === undefined && retryable === true;
3069
+ token = nextToken ?? token;
3070
+ if (!canRetry) {
3071
+ if (!recovering && retryable !== true)
3072
+ return last;
3073
+ break;
3074
+ }
3075
+ recovering = true;
3076
+ if (retries >= RETRY_IDENTITY_MAX_REUSES || operationSignal.aborted)
3077
+ break;
3078
+ try {
3079
+ await delay2(RECONNECT_DELAYS_MS[retries], undefined, { signal: operationSignal });
3080
+ } catch {
3081
+ break;
3082
+ }
3083
+ retries += 1;
3084
+ }
3085
+ const reason = operationSignal.aborted ? "Cancelled" : last.content.map(({ text }) => text).join(`
3086
+ `);
3087
+ return {
3088
+ content: [{
3089
+ type: "text",
3090
+ text: recovering ? `${reason}
3091
+ 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
3092
+ }],
3093
+ isError: true,
3094
+ details: { error: true, terminal: true, automaticRetries: retries, ...recovering ? { outcome: "unknown" } : {} }
3095
+ };
3096
+ } finally {
3097
+ clearTimeout(timer);
3098
+ if (token !== undefined)
3099
+ release(token);
3100
+ }
3101
+ }
3102
+ var init_tool_retry = __esm(() => {
3103
+ init_retry_identity();
3104
+ init_retry_policy();
3105
+ });
3106
+
2964
3107
  // dist/builtin/intercom/intercom-tool.ts
2965
3108
  import { Type as Type2 } from "typebox";
2966
3109
  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
3110
  function retryErrorDetails(retryToken) {
2973
3111
  return retryToken === undefined ? { error: true } : { error: true, retryToken };
2974
3112
  }
@@ -3056,10 +3194,10 @@ async function resolveReplySender(client, logicalTarget, sendTarget) {
3056
3194
  return { kind: "unresolved" };
3057
3195
  }
3058
3196
  function formatWorkflowStageRow(stage) {
3059
- return `- **${stage.stageName}** — workflow stage [${stage.lifecycle.toUpperCase()}] target: \`${stage.target}\`${stage.sessionId === undefined ? "" : ` — intercom session: ${stage.sessionId}`}`;
3197
+ return `- \`${stage.target}\` [${stage.lifecycle.toUpperCase()}] workflow stage: ${stage.stageName}${stage.sessionId === undefined ? "" : ` session: \`${stage.sessionId}\``}`;
3060
3198
  }
3061
3199
  function formatWorkflowFutureStageRow(stage) {
3062
- return `- future workflow stage \`${stage.target}\` ${stage.queuedCount} queued message${stage.queuedCount === 1 ? "" : "s"}`;
3200
+ return `- \`${stage.target}\` [future] ${stage.queuedCount} queued message${stage.queuedCount === 1 ? "" : "s"}`;
3063
3201
  }
3064
3202
  function registerIntercomTool(pi, deps) {
3065
3203
  const retryIdentities = new RetryIdentityReservations({ maxEntries: deps.retryIdentityMaxEntries });
@@ -3086,7 +3224,7 @@ A valid target outside the known set queues speculatively with a \`notInKnownSet
3086
3224
  undeliverable at terminal only if never delivered. Use \`ask\` only for a live, reply-capable target.
3087
3225
  Stage paths win over same-named owned subgroups for send/ask; \`list\` with \`group\` continues to
3088
3226
  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.
3227
+ 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
3228
 
3091
3229
  Usage:
3092
3230
  intercom({ action: "list" }) → List sessions visible through your groups
@@ -3098,14 +3236,13 @@ Usage:
3098
3236
  intercom({ action: "send", to: "session-name", message: "..." }) → Send message (shared group only)
3099
3237
  intercom({ action: "ask", to: "session-name", message: "..." }) → Ask and wait for reply
3100
3238
  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
3239
  intercom({ action: "pending" }) → List unresolved inbound asks
3103
3240
  intercom({ action: "status" }) → Show connection status and all your groups
3104
3241
 
3105
3242
  The "join" action is additive. "default" is the shared default group; "true" and
3106
3243
  "auto" are reserved for subagent auto-groups. Ordinary delivery requires at least
3107
3244
  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.",
3245
+ 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
3246
  parameters: Type2.Object({
3110
3247
  action: Type2.String({
3111
3248
  description: "Action: 'list', 'groups', 'join', 'leave', 'send', 'ask', 'reply', 'pending', or 'status'"
@@ -3125,78 +3262,25 @@ one shared membership; contact_supervisor remains the only cross-group path.`,
3125
3262
  replyTo: Type2.Optional(Type2.String({
3126
3263
  description: "Exact pending-ask message ID; disambiguates concurrent asks, including asks from one sender"
3127
3264
  })),
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
3265
  group: Type2.Optional(Type2.String({
3134
3266
  description: "Group name for 'join' or optional targeted 'leave'; read-only group filter for 'list'/'status'. 'send'/'ask' use shared memberships."
3135
3267
  }))
3136
3268
  }),
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;
3269
+ async execute(_toolCallId, params, signal, _onUpdate, ctx) {
3270
+ if ("retryToken" in params) {
3165
3271
  return {
3166
- content: [{
3167
- type: "text",
3168
- text: `Intercom not connected: ${getErrorMessage(error)}${retryTokenGuidance(retainedToken, retryPreflightRemaining ?? 0)}`
3169
- }],
3272
+ content: [{ type: "text", text: "Intercom manages retries internally. Caller-supplied retry tokens are not supported; this call was not sent." }],
3170
3273
  isError: true,
3171
- details: retryErrorDetails(retainedToken)
3274
+ details: { error: true }
3172
3275
  };
3173
3276
  }
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) {
3277
+ const toolSessionId = ctx.sessionManager.getSessionId();
3278
+ const { action, to, message, replyTo, group } = params;
3279
+ const attachments = params.attachments?.map((attachment) => ({ ...attachment }));
3280
+ const executeAttempt = async (retryToken, _signal) => {
3281
+ if (retryToken !== undefined) {
3282
+ if (action !== "send" && action !== "ask" && action !== "reply") {
3283
+ const error = new RetryTokenError("mismatch");
3200
3284
  return {
3201
3285
  content: [{ type: "text", text: getErrorMessage(error) }],
3202
3286
  isError: true,
@@ -3204,174 +3288,256 @@ one shared membership; contact_supervisor remains the only cross-group path.`,
3204
3288
  };
3205
3289
  }
3206
3290
  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
- };
3291
+ retryIdentities.validateRetryToken(retryToken, toolSessionId, action);
3214
3292
  } catch (error) {
3215
3293
  return {
3216
- content: [{ type: "text", text: `Failed to join group: ${getErrorMessage(error)}` }],
3294
+ content: [{ type: "text", text: getErrorMessage(error) }],
3217
3295
  isError: true,
3218
3296
  details: { error: true }
3219
3297
  };
3220
3298
  }
3221
3299
  }
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) {
3300
+ let connectedClient;
3301
+ try {
3302
+ connectedClient = await ensureConnected("tool");
3303
+ } catch (error) {
3304
+ const retainedToken = retryToken !== undefined && isRecoverableIntercomDisconnect(error) ? retryToken : undefined;
3305
+ return {
3306
+ content: [{
3307
+ type: "text",
3308
+ text: `Intercom not connected: ${getErrorMessage(error)}`
3309
+ }],
3310
+ isError: true,
3311
+ details: { ...retryErrorDetails(retainedToken), retryable: isRecoverableIntercomDisconnect(error) }
3312
+ };
3313
+ }
3314
+ syncPresenceIdentity(toolSessionId);
3315
+ const resolveOwnGroups = (sessions) => {
3316
+ if (Array.isArray(connectedClient.groups)) {
3317
+ return connectedClient.groups.map((membership) => normalizeGroup(membership));
3318
+ }
3319
+ const self = sessions?.find((session) => session.id === connectedClient.sessionId);
3320
+ return [...normalizeGroups(self?.groups, self?.group)];
3321
+ };
3322
+ const isOnlyOwnGroup = (candidate, ownGroups) => candidate !== undefined && ownGroups.length === 1 && ownGroups[0] === candidate;
3323
+ const requestedGroup = typeof group === "string" && group.trim() ? normalizeGroup(group) : undefined;
3324
+ if ((action === "send" || action === "ask") && requestedGroup) {
3325
+ const ownGroups = resolveOwnGroups();
3326
+ if (!ownGroups.includes(requestedGroup)) {
3230
3327
  return {
3231
- content: [{ type: "text", text: `Cannot leave intercom group: ${getErrorMessage(error)}` }],
3328
+ 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
3329
  isError: true,
3233
3330
  details: { error: true }
3234
3331
  };
3235
3332
  }
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);
3333
+ }
3334
+ switch (action) {
3335
+ case "join": {
3336
+ let targetGroup;
3337
+ try {
3338
+ targetGroup = validateRuntimeGroup(group);
3339
+ } catch (error) {
3340
+ return {
3341
+ content: [{ type: "text", text: getErrorMessage(error) }],
3342
+ isError: true,
3343
+ details: { error: true }
3344
+ };
3345
+ }
3346
+ try {
3347
+ const groups = await connectedClient.joinGroup(targetGroup);
3246
3348
  deps.setJoinedGroups(groups);
3349
+ return {
3350
+ content: [{ type: "text", text: `Joined intercom group "${targetGroup}". Memberships: ${groups.join(", ")}.` }],
3351
+ isError: false,
3352
+ details: { group: targetGroup, groups }
3353
+ };
3354
+ } catch (error) {
3355
+ return {
3356
+ content: [{ type: "text", text: `Failed to join group: ${getErrorMessage(error)}` }],
3357
+ isError: true,
3358
+ details: { error: true }
3359
+ };
3247
3360
  }
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
3361
  }
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:**
3362
+ case "leave": {
3363
+ let targetGroup;
3364
+ let homeGroup;
3365
+ try {
3366
+ targetGroup = typeof group === "string" && group.trim().length > 0 ? validateRuntimeGroup(group) : undefined;
3367
+ if (targetGroup === undefined)
3368
+ homeGroup = validateRuntimeGroup(deps.homeGroup());
3369
+ } catch (error) {
3370
+ return {
3371
+ content: [{ type: "text", text: `Cannot leave intercom group: ${getErrorMessage(error)}` }],
3372
+ isError: true,
3373
+ details: { error: true }
3374
+ };
3375
+ }
3376
+ try {
3377
+ let groups;
3378
+ if (targetGroup === undefined) {
3379
+ if (homeGroup === undefined)
3380
+ throw new Error("Intercom home group is unavailable");
3381
+ await connectedClient.updatePresenceAcked({ groups: [homeGroup] });
3382
+ groups = connectedClient.groups;
3383
+ deps.clearJoinedGroups();
3384
+ } else {
3385
+ groups = await connectedClient.leaveGroup(targetGroup);
3386
+ deps.setJoinedGroups(groups);
3387
+ }
3388
+ const text = targetGroup === undefined ? `Returned to home intercom membership. Memberships: ${groups.join(", ")}.` : `Left intercom group "${targetGroup}". Memberships: ${groups.join(", ")}.`;
3389
+ return {
3390
+ content: [{ type: "text", text }],
3391
+ isError: false,
3392
+ details: targetGroup === undefined ? { group: homeGroup, groups } : { groups }
3393
+ };
3394
+ } catch (error) {
3395
+ return {
3396
+ content: [{ type: "text", text: `Failed to leave group: ${getErrorMessage(error)}` }],
3397
+ isError: true,
3398
+ details: { error: true }
3399
+ };
3400
+ }
3401
+ }
3402
+ case "groups": {
3403
+ try {
3404
+ const groups = await connectedClient.listGroups();
3405
+ const lines = groups.map(({ group: groupName, sessionCount, member }) => `- ${groupName} — ${sessionCount} session${sessionCount === 1 ? "" : "s"}${member ? " [member]" : ""}`);
3406
+ return {
3407
+ content: [{ type: "text", text: `**Intercom groups:**
3268
3408
  ${lines.join(`
3269
3409
  `)}` }],
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) {
3410
+ isError: false,
3411
+ details: { groups }
3412
+ };
3413
+ } catch (error) {
3288
3414
  return {
3289
- content: [{ type: "text", text: "Current session is missing from intercom session list." }],
3415
+ content: [{ type: "text", text: `Failed to list groups: ${getErrorMessage(error)}` }],
3290
3416
  isError: true,
3291
3417
  details: { error: true }
3292
3418
  };
3293
3419
  }
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):**
3420
+ }
3421
+ case "list": {
3422
+ try {
3423
+ const mySessionId = connectedClient.sessionId;
3424
+ const ownDirectory = await listDirectory(connectedClient);
3425
+ const ownSessions = ownDirectory.sessions;
3426
+ const currentSession = ownSessions.find((session) => session.id === mySessionId);
3427
+ if (!currentSession) {
3428
+ return {
3429
+ content: [{ type: "text", text: "Current session is missing from intercom session list." }],
3430
+ isError: true,
3431
+ details: { error: true }
3432
+ };
3433
+ }
3434
+ const ownGroups = resolveOwnGroups(ownSessions);
3435
+ if (requestedGroup && !isOnlyOwnGroup(requestedGroup, ownGroups)) {
3436
+ const peeked = await listDirectory(connectedClient, requestedGroup);
3437
+ const rows = [
3438
+ ...peeked.sessions.map((session) => formatSessionListRow(session, currentSession.cwd, session.id === mySessionId)),
3439
+ ...peeked.workflowStages.map(formatWorkflowStageRow),
3440
+ ...(peeked.workflowFutureStages ?? []).map(formatWorkflowFutureStageRow)
3441
+ ];
3442
+ const section = rows.length === 0 ? `**Group [${requestedGroup}] (read-only peek):**
3303
3443
  No sessions or workflow stages in this group.` : `**Group [${requestedGroup}] (read-only peek):**
3304
3444
  ${rows.join(`
3305
3445
  `)}`;
3306
- return {
3307
- content: [{ type: "text", text: `Your groups: ${ownGroups.join(", ")}
3446
+ return {
3447
+ content: [{ type: "text", text: `Your groups: ${ownGroups.join(", ")}
3308
3448
 
3309
3449
  ${section}` }],
3450
+ isError: false,
3451
+ details: {
3452
+ group: ownGroups.at(-1),
3453
+ groups: ownGroups,
3454
+ peekGroup: requestedGroup,
3455
+ workflowStages: peeked.workflowStages,
3456
+ ...(peeked.workflowFutureStages?.length ?? 0) === 0 ? {} : { workflowFutureStages: peeked.workflowFutureStages }
3457
+ }
3458
+ };
3459
+ }
3460
+ const otherSessions = ownSessions.filter((session) => session.id !== mySessionId);
3461
+ const currentSection = `**Current session** (groups: ${ownGroups.join(", ")}):
3462
+ ${formatSessionListRow(currentSession, currentSession.cwd, true)}`;
3463
+ const visibleRows = [
3464
+ ...otherSessions.map((session) => formatSessionListRow(session, currentSession.cwd, false)),
3465
+ ...ownDirectory.workflowStages.map(formatWorkflowStageRow),
3466
+ ...(ownDirectory.workflowFutureStages ?? []).map(formatWorkflowFutureStageRow)
3467
+ ];
3468
+ const otherSection = visibleRows.length === 0 ? `**Other sessions and workflow stages:**
3469
+ No other sessions or workflow stages share any of your groups.` : `**Other visible sessions and workflow stages:**
3470
+ ${visibleRows.join(`
3471
+ `)}`;
3472
+ return {
3473
+ content: [{ type: "text", text: `${currentSection}
3474
+
3475
+ ${otherSection}` }],
3310
3476
  isError: false,
3311
3477
  details: {
3312
3478
  group: ownGroups.at(-1),
3313
3479
  groups: ownGroups,
3314
- peekGroup: requestedGroup,
3315
- workflowStages: peeked.workflowStages,
3316
- ...(peeked.workflowFutureStages?.length ?? 0) === 0 ? {} : { workflowFutureStages: peeked.workflowFutureStages }
3480
+ ...ownDirectory.workflowStages.length === 0 ? {} : { workflowStages: ownDirectory.workflowStages },
3481
+ ...(ownDirectory.workflowFutureStages?.length ?? 0) === 0 ? {} : { workflowFutureStages: ownDirectory.workflowFutureStages }
3317
3482
  }
3318
3483
  };
3484
+ } catch (error) {
3485
+ return {
3486
+ content: [{ type: "text", text: `Failed to list sessions: ${getErrorMessage(error)}` }],
3487
+ isError: true,
3488
+ details: { error: true }
3489
+ };
3319
3490
  }
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}
3491
+ }
3492
+ case "send": {
3493
+ if (!to || !message) {
3494
+ const errorText = retryToken === undefined ? "Missing 'to' or 'message' parameter" : getErrorMessage(new RetryTokenError("mismatch"));
3495
+ return {
3496
+ content: [{ type: "text", text: errorText }],
3497
+ isError: true,
3498
+ details: { error: true }
3499
+ };
3500
+ }
3501
+ if (_signal?.aborted) {
3502
+ return {
3503
+ content: [{
3504
+ type: "text",
3505
+ text: "Cancelled"
3506
+ }],
3507
+ isError: true,
3508
+ details: retryErrorDetails(retryToken)
3509
+ };
3510
+ }
3511
+ let retryIdentity;
3512
+ try {
3513
+ if (retryToken === undefined) {
3514
+ retryIdentity = retryIdentities.begin({
3515
+ sessionId: toolSessionId,
3516
+ action: "send",
3517
+ target: to,
3518
+ text: message,
3519
+ attachments,
3520
+ replyTo,
3521
+ expectsReply: false
3522
+ });
3523
+ }
3524
+ if (retryToken === undefined && !replyTo && deps.confirmSend && ctx.hasUI) {
3525
+ const attachmentText = attachments?.length ? formatAttachments(attachments) : "";
3526
+ const confirmed = await ctx.ui.confirm("Send Message", `Send to "${to}":
3334
3527
 
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 }
3528
+ ${message}${attachmentText}`);
3529
+ if (!confirmed) {
3530
+ if (retryIdentity !== undefined)
3531
+ retryIdentities.release(retryIdentity);
3532
+ retryIdentity = undefined;
3533
+ return {
3534
+ content: [{ type: "text", text: "Message cancelled by user" }],
3535
+ isError: false,
3536
+ details: {}
3537
+ };
3538
+ }
3342
3539
  }
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({
3540
+ retryIdentity ??= retryIdentities.begin({
3375
3541
  sessionId: toolSessionId,
3376
3542
  action: "send",
3377
3543
  target: to,
@@ -3379,63 +3545,79 @@ ${otherSection}` }],
3379
3545
  attachments,
3380
3546
  replyTo,
3381
3547
  expectsReply: false
3548
+ }, retryToken);
3549
+ const sendTo = await resolveTarget(connectedClient, to) ?? to;
3550
+ if (_signal?.aborted) {
3551
+ const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3552
+ retryIdentity = undefined;
3553
+ return {
3554
+ content: [{ type: "text", text: "Cancelled" }],
3555
+ isError: true,
3556
+ details: retryErrorDetails(retained.retryToken)
3557
+ };
3558
+ }
3559
+ if (sendTo === connectedClient.sessionId) {
3560
+ const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3561
+ retryIdentity = undefined;
3562
+ return {
3563
+ content: [{
3564
+ type: "text",
3565
+ text: "Cannot message the current session"
3566
+ }],
3567
+ isError: true,
3568
+ details: retryErrorDetails(retained.retryToken)
3569
+ };
3570
+ }
3571
+ const result = await connectedClient.send(sendTo, {
3572
+ messageId: retryIdentity.messageId,
3573
+ logicalTarget: to,
3574
+ text: message,
3575
+ attachments,
3576
+ replyTo
3382
3577
  });
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);
3578
+ if (result.queued === true) {
3579
+ retryIdentities.release(retryIdentity);
3392
3580
  retryIdentity = undefined;
3581
+ pi.appendEntry("intercom_sent", {
3582
+ to,
3583
+ message: { text: message, attachments, replyTo },
3584
+ messageId: result.id,
3585
+ timestamp: Date.now()
3586
+ });
3587
+ const notInKnownSet = result.notInKnownSet === true;
3393
3588
  return {
3394
- content: [{ type: "text", text: "Message cancelled by user" }],
3589
+ content: [{
3590
+ type: "text",
3591
+ 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}`
3592
+ }],
3395
3593
  isError: false,
3396
- details: {}
3594
+ details: {
3595
+ messageId: result.id,
3596
+ delivered: false,
3597
+ queued: true,
3598
+ target: result.target,
3599
+ position: result.position,
3600
+ ...notInKnownSet ? { notInKnownSet: true } : {}
3601
+ }
3602
+ };
3603
+ }
3604
+ if (!result.delivered) {
3605
+ const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3606
+ retryIdentity = undefined;
3607
+ const errorText = result.reason ?? "Session may not exist or has disconnected.";
3608
+ return {
3609
+ content: [{
3610
+ type: "text",
3611
+ text: `Message to "${to}" was not delivered: ${errorText}`
3612
+ }],
3613
+ isError: true,
3614
+ details: retryToken === undefined ? { messageId: result.id, delivered: false, reason: result.reason } : {
3615
+ delivered: false,
3616
+ reason: result.reason,
3617
+ ...retained.retryToken === undefined ? {} : { retryToken: retained.retryToken }
3618
+ }
3397
3619
  };
3398
3620
  }
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
3621
  retryIdentities.release(retryIdentity);
3440
3622
  retryIdentity = undefined;
3441
3623
  pi.appendEntry("intercom_sent", {
@@ -3444,160 +3626,81 @@ ${message}${attachmentText}`);
3444
3626
  messageId: result.id,
3445
3627
  timestamp: Date.now()
3446
3628
  });
3447
- const notInKnownSet = result.notInKnownSet === true;
3629
+ if (replyTo)
3630
+ activeReplyTracker().markReplied(replyTo);
3448
3631
  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
- }],
3632
+ content: [{ type: "text", text: `Message sent to ${to}` }],
3453
3633
  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
- }
3634
+ details: { messageId: result.id, delivered: true }
3462
3635
  };
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.";
3636
+ } catch (error) {
3637
+ let failure = error;
3638
+ let retained;
3639
+ if (retryIdentity !== undefined) {
3640
+ if (isRecoverableIntercomDisconnect(error)) {
3641
+ try {
3642
+ retained = retainRecoverableRetry(retryIdentities, retryIdentity);
3643
+ } catch (retentionError) {
3644
+ failure = retentionError;
3645
+ }
3646
+ } else {
3647
+ retryIdentities.release(retryIdentity);
3648
+ }
3649
+ }
3468
3650
  return {
3469
3651
  content: [{
3470
3652
  type: "text",
3471
- text: `Message to "${to}" was not delivered: ${errorText}${retryTokenGuidance(retained.retryToken, retained.remainingRetries)}`
3653
+ text: `Failed to send: ${getErrorMessage(failure)}`
3472
3654
  }],
3473
3655
  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
- }
3656
+ details: { ...retryErrorDetails(retained?.retryToken), retryable: isRecoverableIntercomDisconnect(error) }
3479
3657
  };
3480
3658
  }
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
- }
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
3659
  }
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;
3660
+ case "ask": {
3661
+ if (!to) {
3662
+ const errorText = retryToken === undefined ? "Missing 'to' or 'message' parameter" : getErrorMessage(new RetryTokenError("mismatch"));
3566
3663
  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;
3576
- return {
3577
- content: [{
3578
- type: "text",
3579
- text: `Cancelled${retryTokenGuidance(retained?.retryToken, retained?.remainingRetries ?? 0)}`
3580
- }],
3664
+ content: [{ type: "text", text: errorText }],
3581
3665
  isError: true,
3582
- details: retryErrorDetails(retained?.retryToken)
3666
+ details: { error: true }
3583
3667
  };
3584
3668
  }
3585
- if (sendTo === connectedClient.sessionId) {
3586
- const retained = retryIdentity === undefined ? undefined : retainInconclusiveRetry(retryIdentities, retryIdentity);
3587
- retryIdentity = undefined;
3669
+ if (_signal?.aborted) {
3588
3670
  return {
3589
3671
  content: [{
3590
3672
  type: "text",
3591
- text: `Cannot message the current session${retryTokenGuidance(retained?.retryToken, retained?.remainingRetries ?? 0)}`
3673
+ text: "Cancelled"
3592
3674
  }],
3593
3675
  isError: true,
3594
- details: retryErrorDetails(retained?.retryToken)
3676
+ details: retryErrorDetails(retryToken)
3595
3677
  };
3596
3678
  }
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)) {
3679
+ let wait = null;
3680
+ let retryIdentity;
3681
+ let askDelivered = false;
3682
+ try {
3683
+ retryIdentity = retryIdentities.begin({
3684
+ sessionId: toolSessionId,
3685
+ action: "ask",
3686
+ target: to,
3687
+ text: message ?? "",
3688
+ attachments,
3689
+ replyTo,
3690
+ expectsReply: true
3691
+ }, retryToken);
3692
+ const metadata = getMetadata();
3693
+ const currentSupervisorId = connectedClient.supervisorSessionId ?? undefined;
3694
+ const metadataSupervisorId = metadata?.supervisor?.supervisorSessionId;
3695
+ const directParentTarget = Boolean(metadata && (to === metadata.orchestratorTarget || to === currentSupervisorId || to === metadataSupervisorId));
3696
+ let parentTarget = directParentTarget;
3697
+ const claimParentAsk = (resolvedTargetId) => Boolean(metadata && requestParentAskHandoff(pi.events, metadata, {
3698
+ kind: "intercom",
3699
+ question: typeof message === "string" ? message : "",
3700
+ attachments: params.attachments,
3701
+ resolvedTargetId
3702
+ }));
3703
+ if (retryToken === undefined && directParentTarget && claimParentAsk(currentSupervisorId ?? metadataSupervisorId ?? to)) {
3601
3704
  retryIdentities.release(retryIdentity);
3602
3705
  retryIdentity = undefined;
3603
3706
  return {
@@ -3606,214 +3709,297 @@ ${message}${attachmentText}`);
3606
3709
  details: { yielded: true }
3607
3710
  };
3608
3711
  }
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}`));
3712
+ const sendTo = await resolveTarget(connectedClient, to) ?? to;
3713
+ if (_signal?.aborted) {
3714
+ const retained = retryIdentity === undefined ? undefined : retainInconclusiveRetry(retryIdentities, retryIdentity);
3715
+ retryIdentity = undefined;
3716
+ return {
3717
+ content: [{
3718
+ type: "text",
3719
+ text: "Cancelled"
3720
+ }],
3721
+ isError: true,
3722
+ details: retryErrorDetails(retained?.retryToken)
3723
+ };
3724
+ }
3725
+ if (sendTo === connectedClient.sessionId) {
3726
+ const retained = retryIdentity === undefined ? undefined : retainInconclusiveRetry(retryIdentities, retryIdentity);
3727
+ retryIdentity = undefined;
3728
+ return {
3729
+ content: [{
3730
+ type: "text",
3731
+ text: "Cannot message the current session"
3732
+ }],
3733
+ isError: true,
3734
+ details: retryErrorDetails(retained?.retryToken)
3735
+ };
3736
+ }
3737
+ if (metadata && !directParentTarget) {
3738
+ const authoritativeParent = [currentSupervisorId, metadataSupervisorId].find((candidate) => candidate === sendTo);
3739
+ const resolvedParent = authoritativeParent ?? await resolveTarget(connectedClient, metadata.orchestratorTarget);
3740
+ parentTarget = resolvedParent !== null && resolvedParent === sendTo;
3741
+ if (retryToken === undefined && parentTarget && claimParentAsk(sendTo)) {
3742
+ retryIdentities.release(retryIdentity);
3743
+ retryIdentity = undefined;
3744
+ return {
3745
+ content: [{ type: "text", text: "Parent ask claimed; this child is ending for a fresh subagent start." }],
3746
+ isError: false,
3747
+ details: { yielded: true }
3748
+ };
3749
+ }
3750
+ }
3751
+ if (!message && !parentTarget) {
3752
+ retryIdentities.release(retryIdentity);
3753
+ retryIdentity = undefined;
3754
+ return {
3755
+ content: [{ type: "text", text: "Missing 'to' or 'message' parameter" }],
3756
+ isError: true,
3757
+ details: { error: true }
3758
+ };
3759
+ }
3760
+ const replySender = await resolveReplySender(connectedClient, to, sendTo);
3761
+ if (replySender.kind === "ambiguous") {
3762
+ const retained = retryIdentity === undefined ? undefined : retainInconclusiveRetry(retryIdentities, retryIdentity);
3763
+ retryIdentity = undefined;
3764
+ return {
3765
+ content: [{
3766
+ type: "text",
3767
+ text: `Message to "${to}" is ambiguous: ${replySender.reason}. Use the exact target shown by intercom list.`
3768
+ }],
3769
+ isError: true,
3770
+ details: retryErrorDetails(retained?.retryToken)
3771
+ };
3772
+ }
3773
+ const questionId = retryIdentity.messageId;
3774
+ const replyFrom = replySender.kind === "resolved" ? replySender.sessionId : sendTo;
3775
+ const admission = beginReplyWait(replyFrom, questionId, _signal);
3776
+ if (!admission.ok) {
3777
+ const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3778
+ retryIdentity = undefined;
3779
+ const text = admission.reason === "busy" ? `Too many pending asks (${admission.limit}); reply-wait slots are full` : "Cancelled";
3780
+ return {
3781
+ content: [{
3782
+ type: "text",
3783
+ text
3784
+ }],
3785
+ isError: true,
3786
+ details: retryErrorDetails(retained.retryToken)
3787
+ };
3788
+ }
3789
+ wait = admission.wait;
3790
+ const sendResult = await connectedClient.send(sendTo, {
3791
+ messageId: questionId,
3792
+ logicalTarget: to,
3793
+ text: message ?? "",
3794
+ attachments,
3795
+ replyTo,
3796
+ expectsReply: true,
3797
+ ...parseWorkflowStageTarget(to)?.kind === "path" ? { onReplyTarget: wait.bindSender } : {}
3798
+ });
3799
+ if (sendResult.queued === true) {
3800
+ retryIdentities.release(retryIdentity);
3801
+ retryIdentity = undefined;
3802
+ wait.cancel(new Error(`Message queued for ${to}`));
3803
+ pi.appendEntry("intercom_sent", {
3804
+ to,
3805
+ message: { text: message, attachments, replyTo },
3806
+ messageId: sendResult.id,
3807
+ timestamp: Date.now()
3808
+ });
3809
+ return {
3810
+ content: [{ type: "text", text: `Message queued for ${to}` }],
3811
+ isError: false,
3812
+ details: {
3813
+ messageId: sendResult.id,
3814
+ delivered: false,
3815
+ queued: true,
3816
+ target: sendResult.target,
3817
+ position: sendResult.position
3818
+ }
3819
+ };
3820
+ }
3821
+ if (!sendResult.delivered) {
3822
+ const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3823
+ retryIdentity = undefined;
3824
+ const errorText = sendResult.reason ?? "Session may not exist or has disconnected.";
3825
+ wait.cancel(new Error(`Message to "${to}" was not delivered: ${errorText}`));
3826
+ const pendingStageAskRefusal = errorText.startsWith("Cannot ask a workflow stage whose session has not initialized.");
3827
+ return {
3828
+ content: [{
3829
+ type: "text",
3830
+ text: `Message to "${to}" was not delivered: ${errorText}`
3831
+ }],
3832
+ isError: true,
3833
+ details: {
3834
+ ...pendingStageAskRefusal ? {
3835
+ refusal: "pending_stage_ask_unsupported",
3836
+ recommendedAction: "send",
3837
+ reason: errorText
3838
+ } : {},
3839
+ ...retryErrorDetails(retained.retryToken)
3840
+ }
3841
+ };
3842
+ }
3843
+ askDelivered = true;
3661
3844
  pi.appendEntry("intercom_sent", {
3662
3845
  to,
3663
3846
  message: { text: message, attachments, replyTo },
3664
3847
  messageId: sendResult.id,
3665
3848
  timestamp: Date.now()
3666
3849
  });
3850
+ const replyMessage = await wait.promise;
3851
+ retryIdentities.release(retryIdentity);
3852
+ retryIdentity = undefined;
3853
+ const replyText = replyMessage.content.text;
3854
+ const replyAttachments = replyMessage.content.attachments?.length ? formatAttachments(replyMessage.content.attachments) : "";
3855
+ pi.appendEntry("intercom_received", {
3856
+ from: to,
3857
+ message: { text: replyText, attachments: replyMessage.content.attachments },
3858
+ messageId: replyMessage.id,
3859
+ timestamp: replyMessage.timestamp
3860
+ });
3861
+ if (replyMessage.replyError !== undefined) {
3862
+ return {
3863
+ content: [{ type: "text", text: `Failed: ${replyMessage.replyError}` }],
3864
+ isError: true,
3865
+ details: { error: true, replyTo: replyMessage.replyTo }
3866
+ };
3867
+ }
3667
3868
  return {
3668
- content: [{ type: "text", text: `Message queued for ${to}` }],
3869
+ content: [{ type: "text", text: `**Reply from ${to}:**
3870
+ ${replyText}${replyAttachments}` }],
3669
3871
  isError: false,
3670
- details: {
3671
- messageId: sendResult.id,
3672
- delivered: false,
3673
- queued: true,
3674
- target: sendResult.target,
3675
- position: sendResult.position
3676
- }
3872
+ details: {}
3677
3873
  };
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.");
3874
+ } catch (error) {
3875
+ wait?.cancel(toError3(error));
3876
+ let failure = error;
3877
+ let retained;
3878
+ if (retryIdentity !== undefined) {
3879
+ if (isRecoverableIntercomDisconnect(error)) {
3880
+ try {
3881
+ retained = retainRecoverableRetry(retryIdentities, retryIdentity);
3882
+ } catch (retentionError) {
3883
+ failure = retentionError;
3884
+ }
3885
+ } else {
3886
+ retryIdentities.release(retryIdentity);
3887
+ }
3888
+ }
3685
3889
  return {
3686
3890
  content: [{
3687
3891
  type: "text",
3688
- text: `Message to "${to}" was not delivered: ${errorText}${retryTokenGuidance(retained.retryToken, retained.remainingRetries)}`
3892
+ text: `Failed: ${getErrorMessage(failure)}`
3689
3893
  }],
3690
3894
  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 }
3895
+ details: { ...retryErrorDetails(retained?.retryToken), retryable: isRecoverableIntercomDisconnect(error), deliveryUncertain: askDelivered }
3723
3896
  };
3724
3897
  }
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
3898
  }
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;
3899
+ case "reply": {
3900
+ if (!message) {
3901
+ const errorText = retryToken === undefined ? "Missing 'message' parameter" : getErrorMessage(new RetryTokenError("mismatch"));
3794
3902
  return {
3795
- content: [{
3796
- type: "text",
3797
- text: `Cannot message the current session${retryTokenGuidance(retained.retryToken, retained.remainingRetries)}`
3798
- }],
3903
+ content: [{ type: "text", text: errorText }],
3799
3904
  isError: true,
3800
- details: retryErrorDetails(retained.retryToken)
3905
+ details: { error: true }
3801
3906
  };
3802
3907
  }
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);
3908
+ if (_signal?.aborted) {
3909
+ return { content: [{ type: "text", text: "Cancelled" }], isError: true, details: retryErrorDetails(retryToken) };
3815
3910
  }
3816
- if (result.queued === true) {
3911
+ let retryIdentity;
3912
+ try {
3913
+ retryIdentity = retryIdentities.begin({
3914
+ sessionId: toolSessionId,
3915
+ action: "reply",
3916
+ target: to,
3917
+ text: message,
3918
+ attachments,
3919
+ replyTo,
3920
+ expectsReply: false
3921
+ }, retryToken);
3922
+ if (retryToken === undefined) {
3923
+ const target = activeReplyTracker().resolveReplyTarget({ to, replyTo });
3924
+ retryIdentities.bindReplyRoute(retryIdentity, {
3925
+ senderId: target.from.id,
3926
+ ...target.from.name === undefined ? {} : { senderName: target.from.name },
3927
+ messageId: target.message.id,
3928
+ expectsReply: target.message.expectsReply === true
3929
+ });
3930
+ }
3931
+ const route = retryIdentities.replyRoute(retryIdentity);
3932
+ if (route === undefined)
3933
+ throw new RetryTokenError("invalid");
3934
+ const replySendTo = to ?? route.senderId;
3935
+ const replyLogicalTarget = to ?? route.senderId;
3936
+ const displayTarget = route.senderName || route.senderId;
3937
+ if (route.senderId === connectedClient.sessionId) {
3938
+ const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3939
+ retryIdentity = undefined;
3940
+ return {
3941
+ content: [{
3942
+ type: "text",
3943
+ text: "Cannot message the current session"
3944
+ }],
3945
+ isError: true,
3946
+ details: retryErrorDetails(retained.retryToken)
3947
+ };
3948
+ }
3949
+ const replyMessageId = retryIdentity.messageId;
3950
+ const sendReply = (targetId) => connectedClient.send(targetId, {
3951
+ messageId: replyMessageId,
3952
+ logicalTarget: replyLogicalTarget,
3953
+ ...route.expectsReply ? { requirePendingReply: true } : {},
3954
+ ...to === undefined && replyTo === undefined ? {} : { expectedRecipientId: route.senderId },
3955
+ text: message,
3956
+ attachments,
3957
+ replyTo: route.messageId
3958
+ });
3959
+ let result = await sendReply(replySendTo);
3960
+ if (to === undefined && replyTo === undefined && result.delivered === false && result.reasonCode === "session_not_found" && route.senderName !== undefined) {
3961
+ result = await sendReply(route.senderName);
3962
+ }
3963
+ if (result.queued === true) {
3964
+ retryIdentities.release(retryIdentity);
3965
+ retryIdentity = undefined;
3966
+ activeReplyTracker().markReplied(route.messageId);
3967
+ pi.appendEntry("intercom_sent", {
3968
+ to: displayTarget,
3969
+ message: { text: message, attachments, replyTo: route.messageId },
3970
+ messageId: result.id,
3971
+ timestamp: Date.now()
3972
+ });
3973
+ return {
3974
+ content: [{ type: "text", text: `Reply queued for ${displayTarget}` }],
3975
+ isError: false,
3976
+ details: {
3977
+ messageId: result.id,
3978
+ delivered: false,
3979
+ queued: true,
3980
+ replyTo: route.messageId,
3981
+ target: result.target,
3982
+ position: result.position
3983
+ }
3984
+ };
3985
+ }
3986
+ if (!result.delivered) {
3987
+ const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
3988
+ retryIdentity = undefined;
3989
+ const errorText = result.reason ?? "Session may not exist or has disconnected.";
3990
+ return {
3991
+ content: [{
3992
+ type: "text",
3993
+ text: `Reply to "${displayTarget}" was not delivered: ${errorText}`
3994
+ }],
3995
+ isError: true,
3996
+ details: retryToken === undefined ? { messageId: result.id, delivered: false, reason: result.reason } : {
3997
+ delivered: false,
3998
+ reason: result.reason,
3999
+ ...retained.retryToken === undefined ? {} : { retryToken: retained.retryToken }
4000
+ }
4001
+ };
4002
+ }
3817
4003
  retryIdentities.release(retryIdentity);
3818
4004
  retryIdentity = undefined;
3819
4005
  activeReplyTracker().markReplied(route.messageId);
@@ -3824,136 +4010,101 @@ ${replyText}${replyAttachments}` }],
3824
4010
  timestamp: Date.now()
3825
4011
  });
3826
4012
  return {
3827
- content: [{ type: "text", text: `Reply queued for ${displayTarget}` }],
4013
+ content: [{ type: "text", text: `Reply sent to ${displayTarget}` }],
3828
4014
  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
- }
4015
+ details: { messageId: result.id, delivered: true, replyTo: route.messageId }
3837
4016
  };
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.";
4017
+ } catch (error) {
4018
+ let failure = error;
4019
+ let retained;
4020
+ if (retryIdentity !== undefined) {
4021
+ if (isRecoverableIntercomDisconnect(error)) {
4022
+ try {
4023
+ retained = retainRecoverableRetry(retryIdentities, retryIdentity);
4024
+ } catch (retentionError) {
4025
+ failure = retentionError;
4026
+ }
4027
+ } else {
4028
+ retryIdentities.release(retryIdentity);
4029
+ }
4030
+ }
3843
4031
  return {
3844
4032
  content: [{
3845
4033
  type: "text",
3846
- text: `Reply to "${displayTarget}" was not delivered: ${errorText}${retryTokenGuidance(retained.retryToken, retained.remainingRetries)}`
4034
+ text: `Failed to reply: ${getErrorMessage(failure)}`
3847
4035
  }],
3848
4036
  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
- }
4037
+ details: { ...retryErrorDetails(retained?.retryToken), retryable: isRecoverableIntercomDisconnect(error) }
3854
4038
  };
3855
4039
  }
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
4040
  }
3893
- }
3894
- case "pending": {
3895
- const pendingAsks = activeReplyTracker().listPending();
3896
- if (pendingAsks.length === 0) {
4041
+ case "pending": {
4042
+ const pendingAsks = activeReplyTracker().listPending();
4043
+ if (pendingAsks.length === 0) {
4044
+ return {
4045
+ content: [{ type: "text", text: "No unresolved inbound asks." }],
4046
+ isError: false,
4047
+ details: {}
4048
+ };
4049
+ }
4050
+ const now = Date.now();
4051
+ const lines = pendingAsks.map(({ from, message, receivedAt }) => {
4052
+ const preview = message.content.text.replace(/\s+/g, " ").slice(0, 80);
4053
+ const elapsedSeconds = Math.max(0, Math.floor((now - receivedAt) / 1000));
4054
+ return `- ${from.name || from.id} · ${message.id} · ${elapsedSeconds}s ago · ${preview}`;
4055
+ });
3897
4056
  return {
3898
- content: [{ type: "text", text: "No unresolved inbound asks." }],
4057
+ content: [{ type: "text", text: `**Pending asks:**
4058
+ ${lines.join(`
4059
+ `)}` }],
3899
4060
  isError: false,
3900
4061
  details: {}
3901
4062
  };
3902
4063
  }
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 ? "" : `
4064
+ case "status": {
4065
+ try {
4066
+ const mySessionId = connectedClient.sessionId;
4067
+ const sessions = await connectedClient.listSessions();
4068
+ const ownGroups = resolveOwnGroups(sessions);
4069
+ const selectedGroup = isOnlyOwnGroup(requestedGroup, ownGroups) ? undefined : requestedGroup;
4070
+ const selectedGroupSessions = selectedGroup === undefined ? undefined : await connectedClient.listSessions(selectedGroup);
4071
+ const selectedSection = selectedGroupSessions === undefined ? "" : `
3925
4072
  Selected group [${selectedGroup}]: ${selectedGroupSessions.length} session(s)`;
3926
- return {
3927
- content: [{
3928
- type: "text",
3929
- text: `**Intercom Status:**
4073
+ return {
4074
+ content: [{
4075
+ type: "text",
4076
+ text: `**Intercom Status:**
3930
4077
  Connected: Yes
3931
4078
  Session ID: ${mySessionId}
3932
4079
  Groups: ${ownGroups.join(", ")}
3933
4080
  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) {
4081
+ }],
4082
+ isError: false,
4083
+ details: {
4084
+ group: ownGroups.at(-1),
4085
+ groups: ownGroups,
4086
+ ...selectedGroup === undefined ? {} : { selectedGroup, selectedGroupSessionCount: selectedGroupSessions?.length ?? 0 }
4087
+ }
4088
+ };
4089
+ } catch (error) {
4090
+ return {
4091
+ content: [{ type: "text", text: `Failed to get status: ${getErrorMessage(error)}` }],
4092
+ isError: true,
4093
+ details: { error: true }
4094
+ };
4095
+ }
4096
+ }
4097
+ default:
3943
4098
  return {
3944
- content: [{ type: "text", text: `Failed to get status: ${getErrorMessage(error)}` }],
4099
+ content: [{ type: "text", text: `Unknown action: ${action}` }],
3945
4100
  isError: true,
3946
4101
  details: { error: true }
3947
4102
  };
3948
- }
3949
4103
  }
3950
- default:
3951
- return {
3952
- content: [{ type: "text", text: `Unknown action: ${action}` }],
3953
- isError: true,
3954
- details: { error: true }
3955
- };
3956
- }
4104
+ };
4105
+ if (action !== "send" && action !== "ask" && action !== "reply")
4106
+ return executeAttempt(undefined, signal);
4107
+ return runIntercomOperation(executeAttempt, (token) => retryIdentities.discard(token), signal);
3957
4108
  },
3958
4109
  renderCall(args, theme) {
3959
4110
  const action = typeof args.action === "string" ? args.action : "intercom";
@@ -3985,6 +4136,7 @@ var init_intercom_tool = __esm(() => {
3985
4136
  init_workflow_stage_target();
3986
4137
  init_recoverable_disconnect();
3987
4138
  init_retry_identity();
4139
+ init_tool_retry();
3988
4140
  });
3989
4141
 
3990
4142
  // dist/builtin/intercom/ui/compose.ts
@@ -4375,7 +4527,10 @@ var init_overlay = __esm(() => {
4375
4527
  function registerIntercomLifecycle(pi, deps) {
4376
4528
  const activeReplyTracker = () => typeof deps.replyTracker === "function" ? deps.replyTracker() : deps.replyTracker;
4377
4529
  let hasActiveSession = false;
4530
+ let unbindStageClose;
4378
4531
  async function cleanupRuntime(reason) {
4532
+ unbindStageClose?.();
4533
+ unbindStageClose = undefined;
4379
4534
  deps.setRuntimeStarted(false);
4380
4535
  deps.setShuttingDown(true);
4381
4536
  deps.setDisposed(true);
@@ -4426,6 +4581,12 @@ function registerIntercomLifecycle(pi, deps) {
4426
4581
  deps.setSessionStartedAt(Date.now());
4427
4582
  deps.setAgentRunning(false);
4428
4583
  deps.activeTools.clear();
4584
+ const stage = ctx.orchestrationContext;
4585
+ const closeSignal = stage?.kind === "workflow-stage" ? stage.messageAdmission?.boundary?.closeSignal : undefined;
4586
+ closeSignal?.addEventListener("abort", deps.syncPresenceStatus, { once: true });
4587
+ unbindStageClose = () => closeSignal?.removeEventListener("abort", deps.syncPresenceStatus);
4588
+ if (closeSignal?.aborted)
4589
+ deps.syncPresenceStatus();
4429
4590
  });
4430
4591
  pi.on("session_shutdown", async () => {
4431
4592
  if (!hasActiveSession)
@@ -4433,10 +4594,15 @@ function registerIntercomLifecycle(pi, deps) {
4433
4594
  hasActiveSession = false;
4434
4595
  await cleanupRuntime("Session shutting down");
4435
4596
  });
4436
- pi.on("turn_end", () => {
4597
+ pi.on("turn_end", (event) => {
4437
4598
  if (!deps.getLiveContext())
4438
4599
  return;
4439
- activeReplyTracker().endTurn();
4600
+ const message = event.message;
4601
+ const cancelledBeforeReply = message?.role === "assistant" && message.stopReason === "aborted" && message.content?.length === 0;
4602
+ if (cancelledBeforeReply)
4603
+ activeReplyTracker().restoreTurnContext();
4604
+ else
4605
+ activeReplyTracker().endTurn();
4440
4606
  deps.scheduleInboundFlush();
4441
4607
  });
4442
4608
  pi.on("agent_start", () => {
@@ -4564,12 +4730,12 @@ function prepareDurableAuthority(storagePath) {
4564
4730
  if (databaseExists !== keyExists)
4565
4731
  return;
4566
4732
  if (!databaseExists) {
4567
- const key2 = randomBytes(AUTHORITY_KEY_BYTES);
4568
- writeFileSync2(keyPath, key2, { flag: "wx", mode: 384 });
4733
+ const key = randomBytes(AUTHORITY_KEY_BYTES);
4734
+ writeFileSync2(keyPath, key, { flag: "wx", mode: 384 });
4569
4735
  const databaseDescriptor = openSync2(storagePath, "wx", 384);
4570
4736
  closeSync2(databaseDescriptor);
4571
4737
  restrictExistingAuthorityArtifacts(storagePath, keyPath);
4572
- return key2;
4738
+ return key;
4573
4739
  }
4574
4740
  const key = readFileSync3(keyPath);
4575
4741
  if (key.length !== AUTHORITY_KEY_BYTES)
@@ -4878,7 +5044,7 @@ function parseBarrier(value) {
4878
5044
  return null;
4879
5045
  if (typeof record.terminalAt !== "number" || !Number.isFinite(record.terminalAt))
4880
5046
  return null;
4881
- if (record.source !== "detached-notify" && record.source !== "result-relay")
5047
+ if (record.source !== "detached-notify" && record.source !== "result-relay" && record.source !== "owner-task")
4882
5048
  return null;
4883
5049
  if (!Array.isArray(record.sourceSessionTargets))
4884
5050
  return null;
@@ -4954,11 +5120,17 @@ function registerTerminalOrderingBarrier(pi, options) {
4954
5120
  envelope.completion = currentOwner;
4955
5121
  return;
4956
5122
  }
4957
- const drainedTargets = drainedTargetsByTerminal.get(terminalKey) ?? new Set;
5123
+ const drainedTargets = barrier.source === "owner-task" ? new Set : drainedTargetsByTerminal.get(terminalKey) ?? new Set;
4958
5124
  const pendingTargets = barrier.sourceSessionTargets.filter((target) => !drainedTargets.has(target));
4959
5125
  if (pendingTargets.length === 0)
4960
5126
  return;
4961
5127
  const claim = options.queue.claimOrdinarySourceTargets(barrier.runId, pendingTargets, barrier.terminalAt);
5128
+ const deliverPrelude = (entry) => {
5129
+ if (!claim.isCurrent() || options.isCurrent?.() === false) {
5130
+ throw new Error("Intercom terminal delivery owner retired");
5131
+ }
5132
+ return options.deliver(entry, "prelude");
5133
+ };
4962
5134
  const ownership = Promise.withResolvers();
4963
5135
  ownership.promise.catch(() => {});
4964
5136
  inFlightByTerminal.set(terminalKey, ownership.promise);
@@ -4968,7 +5140,7 @@ function registerTerminalOrderingBarrier(pi, options) {
4968
5140
  ownership.reject(error);
4969
5141
  };
4970
5142
  const finish = () => {
4971
- if (barrier.dispatch && options.toMessage || claim.entries.length > 0) {
5143
+ if (barrier.source !== "owner-task" && (barrier.dispatch && options.toMessage || claim.entries.length > 0)) {
4972
5144
  for (const target of pendingTargets)
4973
5145
  drainedTargets.add(target);
4974
5146
  drainedTargetsByTerminal.set(terminalKey, drainedTargets);
@@ -5019,7 +5191,7 @@ function registerTerminalOrderingBarrier(pi, options) {
5019
5191
  let delivered;
5020
5192
  let deliveredAsync;
5021
5193
  try {
5022
- delivered = options.deliver(claim.entries[index], "prelude");
5194
+ delivered = deliverPrelude(claim.entries[index]);
5023
5195
  deliveredAsync = isPromiseLike(delivered);
5024
5196
  } catch (error) {
5025
5197
  if (barrier.owner)
@@ -5035,7 +5207,7 @@ function registerTerminalOrderingBarrier(pi, options) {
5035
5207
  try {
5036
5208
  await delivered;
5037
5209
  for (current = index + 1;current < claim.entries.length; current++) {
5038
- await options.deliver(claim.entries[current], "prelude");
5210
+ await deliverPrelude(claim.entries[current]);
5039
5211
  }
5040
5212
  finish();
5041
5213
  } catch (error) {
@@ -5111,7 +5283,7 @@ async function dispatchRelayFallback(pi, prefix, terminalMessage, stageAdmission
5111
5283
  }
5112
5284
  }
5113
5285
  function registerSubagentRelay(pi, deps) {
5114
- const { getLiveContext, currentSessionTargetMatches, sendIncomingMessage, ensureConnected, resolveSessionTarget: resolveSessionTarget2 } = deps;
5286
+ const { getLiveContext, currentSessionTargetMatches, sendIncomingMessage, ensureConnected, resolveSessionTarget } = deps;
5115
5287
  const localDeliveries = deps.localDeliveryAuthority ?? new DeliveredMessageCache;
5116
5288
  function deliverLocalSubagentRelayMessage(sender, status, messageText, terminalBarrier, requestId) {
5117
5289
  const now = Date.now();
@@ -5268,7 +5440,7 @@ ${messageText}`,
5268
5440
  let target;
5269
5441
  try {
5270
5442
  activeClient = await ensureConnected("background");
5271
- target = await resolveSessionTarget2(activeClient, parsed.to) ?? parsed.to;
5443
+ target = await resolveSessionTarget(activeClient, parsed.to) ?? parsed.to;
5272
5444
  } catch (error) {
5273
5445
  if (!relayStillLive()) {
5274
5446
  acknowledgeResult(options, parsed.requestId, false, error);
@@ -5522,7 +5694,7 @@ function createIncomingMessageSender(input) {
5522
5694
  if (!input.canDeliver(generation)) {
5523
5695
  return Promise.reject(new Error("Intercom session retired before inbound delivery"));
5524
5696
  }
5525
- if (delivery === "trigger" && trackReplyContext) {
5697
+ if ((delivery === "trigger" || delivery === "interrupt") && trackReplyContext) {
5526
5698
  input.queueTurnContext(turnContext ?? { from: entry.from, message: entry.message, receivedAt: Date.now() });
5527
5699
  }
5528
5700
  const baseOptions = {
@@ -5530,7 +5702,7 @@ function createIncomingMessageSender(input) {
5530
5702
  persistWhenStreaming: true,
5531
5703
  ...stageAdmissionBarrier ? { stageAdmissionBarrier } : {}
5532
5704
  };
5533
- const options = delivery === "trigger" ? { ...baseOptions, triggerTurn: true } : delivery === "followUp" ? { ...baseOptions, deliverAs: "followUp" } : baseOptions;
5705
+ const options = delivery === "interrupt" ? { ...baseOptions, triggerTurn: true, deliverAs: "interrupt" } : delivery === "trigger" ? { ...baseOptions, triggerTurn: true } : delivery === "followUp" ? { ...baseOptions, deliverAs: "followUp" } : baseOptions;
5534
5706
  return Promise.resolve(input.pi.sendMessage(buildIncomingCustomMessage(entry), options));
5535
5707
  };
5536
5708
  }
@@ -5545,6 +5717,20 @@ function framePreStartPendingStageMessage(entry) {
5545
5717
 
5546
5718
  Sent: ${framePendingStageTimestamp(entry.message.timestamp)}
5547
5719
 
5720
+ ${entry.bodyText}`
5721
+ };
5722
+ }
5723
+ function isDeliveryFeedback(message) {
5724
+ return Boolean(message.replyTo) && message.replyError !== undefined;
5725
+ }
5726
+ function frameDeliveryFeedback(entry) {
5727
+ return {
5728
+ ...entry,
5729
+ replyCommand: undefined,
5730
+ bodyText: `**Intercom delivery failed**
5731
+
5732
+ Sent: ${framePendingStageTimestamp(entry.message.timestamp)}
5733
+
5548
5734
  ${entry.bodyText}`
5549
5735
  };
5550
5736
  }
@@ -5566,6 +5752,7 @@ ${entry.bodyText}`,
5566
5752
  // dist/builtin/intercom/inbound-idle-queue.ts
5567
5753
  class InboundIdleQueue {
5568
5754
  entries = [];
5755
+ generation = 0;
5569
5756
  get size() {
5570
5757
  return this.entries.length;
5571
5758
  }
@@ -5589,6 +5776,7 @@ class InboundIdleQueue {
5589
5776
  }
5590
5777
  claimOrdinarySourceTargets(runId, sourceSessionTargets, terminalAt = Number.POSITIVE_INFINITY) {
5591
5778
  const targets = new Set(sourceSessionTargets);
5779
+ const generation = this.generation;
5592
5780
  const original = this.entries;
5593
5781
  const legacyIdsByName = new Map;
5594
5782
  for (const entry of original) {
@@ -5618,8 +5806,9 @@ class InboundIdleQueue {
5618
5806
  let settled = false;
5619
5807
  return {
5620
5808
  entries: selected,
5809
+ isCurrent: () => generation === this.generation,
5621
5810
  rollbackFrom: (index) => {
5622
- if (settled)
5811
+ if (settled || generation !== this.generation)
5623
5812
  return;
5624
5813
  settled = true;
5625
5814
  const undelivered = new Set(selected.slice(index));
@@ -5629,6 +5818,7 @@ class InboundIdleQueue {
5629
5818
  };
5630
5819
  }
5631
5820
  clear() {
5821
+ this.generation++;
5632
5822
  this.entries = [];
5633
5823
  }
5634
5824
  }
@@ -5864,13 +6054,15 @@ function retryStableDelivery(options) {
5864
6054
  function admitWorkflowStageInbound(ctx, deliver, firstRefusal, onAdmissionFailure) {
5865
6055
  if (ctx.orchestrationContext?.kind !== "workflow-stage")
5866
6056
  return false;
6057
+ const boundary = ctx.orchestrationContext.messageAdmission?.boundary;
6058
+ const run = (barrier) => boundary?.runMessageDelivery(() => deliver(barrier), () => deliver(), true) ?? Promise.resolve(deliver(barrier));
5867
6059
  try {
5868
6060
  let busy = false;
5869
6061
  try {
5870
6062
  busy = ctx.isIdle?.() === false;
5871
6063
  } catch {}
5872
6064
  if (!busy || !firstRefusal)
5873
- return Promise.resolve(deliver());
6065
+ return run();
5874
6066
  let firstRefusalPromise;
5875
6067
  const admissionBarrier = () => {
5876
6068
  firstRefusalPromise ??= (async () => {
@@ -5883,12 +6075,29 @@ function admitWorkflowStageInbound(ctx, deliver, firstRefusal, onAdmissionFailur
5883
6075
  })();
5884
6076
  return firstRefusalPromise;
5885
6077
  };
5886
- return Promise.resolve(deliver(admissionBarrier));
6078
+ return run(admissionBarrier);
5887
6079
  } catch (error) {
5888
6080
  return Promise.reject(error);
5889
6081
  }
5890
6082
  }
5891
6083
 
6084
+ // dist/builtin/intercom/active-session-admission.ts
6085
+ function admitActiveSessionInbound(ctx, deliver, firstRefusal, onAdmissionFailure) {
6086
+ const executionEnded = ctx.subagentPolicy?.executionEnded;
6087
+ if (executionEnded !== undefined) {
6088
+ if (executionEnded.aborted || ctx.subagentPolicy?.messageAdmission?.isOpen() === false) {
6089
+ return Promise.reject(new Error("Subagent execution is terminal and cannot accept messages"));
6090
+ }
6091
+ try {
6092
+ return ctx.subagentPolicy?.messageAdmission?.run(deliver) ?? Promise.resolve(deliver());
6093
+ } catch (error) {
6094
+ return Promise.reject(error);
6095
+ }
6096
+ }
6097
+ return admitWorkflowStageInbound(ctx, deliver, firstRefusal, onAdmissionFailure);
6098
+ }
6099
+ var init_active_session_admission = () => {};
6100
+
5892
6101
  // dist/builtin/intercom/workflow-reply-tracker.ts
5893
6102
  function bindWorkflowReplyTracker(ctx, current) {
5894
6103
  const state = ctx.orchestrationContext?.messageAdmission?.extensionState;
@@ -5942,7 +6151,7 @@ async function settleOpenStageDeliveryFailure(input, error) {
5942
6151
  input.admission.release(input.reservation, failure);
5943
6152
  return;
5944
6153
  }
5945
- const delivered = await sendWorkflowStageDeliveryFailure(input.entry, failure, input.tracker, input.currentClient, () => input.currentClient()?.isConnected() === true, "Running workflow stage could not admit intercom ask");
6154
+ const delivered = await sendWorkflowStageDeliveryFailure(input.entry, failure, input.tracker, input.currentClient, () => input.currentClient()?.isConnected() === true, input.failurePrefix ?? "Running workflow stage could not admit intercom ask");
5946
6155
  if (delivered)
5947
6156
  input.commit();
5948
6157
  else
@@ -5954,7 +6163,7 @@ function routeClosedWorkflowStageMessage(entry, admission, tracker, waiter, deli
5954
6163
  const sourceRunId = entry.message.source?.subagentRunId;
5955
6164
  if (sourceRunId !== undefined && ownsSubagentRun(sourceRunId))
5956
6165
  return;
5957
- if (entry.message.expectsReply !== true) {
6166
+ if (entry.message.expectsReply !== true && !isDeliveryFeedback(entry.message)) {
5958
6167
  retryStableDelivery({ deliver, isCurrent }).catch(() => {});
5959
6168
  return;
5960
6169
  }
@@ -5965,6 +6174,14 @@ function routeClosedWorkflowStageMessage(entry, admission, tracker, waiter, deli
5965
6174
  admission.commit(admitted.reservation);
5966
6175
  return;
5967
6176
  }
6177
+ if (isDeliveryFeedback(entry.message)) {
6178
+ retryStableDelivery({ deliver, isCurrent }).then(() => {
6179
+ admission.commit(admitted.reservation);
6180
+ }, (error) => {
6181
+ admission.release(admitted.reservation, error instanceof Error ? error : new Error(String(error)));
6182
+ });
6183
+ return;
6184
+ }
5968
6185
  const replyContext = tracker.recordIncomingMessage(entry.from, entry.message);
5969
6186
  tracker.queueTurnContext(replyContext);
5970
6187
  const delivery = invoke(deliver);
@@ -6050,6 +6267,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
6050
6267
  };
6051
6268
  let client = null;
6052
6269
  let clientRegistrationGroup = null;
6270
+ const replyCapability = registerSubagentReplyCapability(pi, () => client);
6053
6271
  const config = loadConfig();
6054
6272
  const legacyChildOrchestratorMetadata = readChildOrchestratorMetadata();
6055
6273
  let runtimeContext = null;
@@ -6118,7 +6336,8 @@ function piIntercomExtension(pi, testOverrides = {}) {
6118
6336
  }
6119
6337
  function currentStatus() {
6120
6338
  const activeToolName = activeTools.values().next().value;
6121
- const lifecycleStatus = activeToolName ? `tool:${activeToolName}` : agentRunning ? "thinking" : "idle";
6339
+ const stage = getLiveContext()?.orchestrationContext;
6340
+ const lifecycleStatus = stage?.kind === "workflow-stage" && stage.messageAdmission?.isOpen() === false ? `closed · reply: ${stage.lateMessageRouter === undefined ? "unavailable" : "post-mortem only"}` : activeToolName ? `tool:${activeToolName}` : agentRunning ? "thinking" : "idle";
6122
6341
  return config.status ? `${lifecycleStatus} · ${config.status}` : lifecycleStatus;
6123
6342
  }
6124
6343
  function resolveSessionHomeGroup() {
@@ -6156,6 +6375,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
6156
6375
  startedAt: sessionStartedAt,
6157
6376
  lastActivity: Date.now(),
6158
6377
  status: currentStatus(),
6378
+ replyCapability: replyCapability(),
6159
6379
  groups: [...currentIntercomGroups()],
6160
6380
  group: currentIntercomGroup()
6161
6381
  };
@@ -6257,14 +6477,20 @@ function piIntercomExtension(pi, testOverrides = {}) {
6257
6477
  const bodyText = `${message.content.text}${attachmentText}`;
6258
6478
  const replyCommand = config.replyHint && message.expectsReply ? `intercom({ action: "reply", message: "..." })` : undefined;
6259
6479
  const rawEntry = { from, message, replyCommand, bodyText, ...channel ? { channel } : {} };
6260
- const entry = receivedBeforeStageStart ? framePreStartPendingStageMessage(rawEntry) : rawEntry;
6480
+ const framedEntry = isDeliveryFeedback(message) ? frameDeliveryFeedback(rawEntry) : rawEntry;
6481
+ const entry = receivedBeforeStageStart ? framePreStartPendingStageMessage(framedEntry) : framedEntry;
6261
6482
  if (receivedBeforeStageStart) {
6262
6483
  return sendIncomingMessage(entry, "prelude", messageGeneration, false);
6263
6484
  }
6264
6485
  const stageAdmission = liveContext.orchestrationContext?.kind === "workflow-stage" ? liveContext.orchestrationContext.messageAdmission : undefined;
6265
6486
  const stageClosed = stageAdmission?.isOpen() === false;
6266
6487
  if (stageClosed) {
6267
- routeClosedWorkflowStageMessage(entry, inboundDeliveries, replyTracker, replyWaiters.pending(), () => sendIncomingMessage(entry, "trigger", messageGeneration, false), () => client, () => Boolean(getLiveContext(liveContext, messageGeneration)), (runId) => stageAdmission.boundary.ownsSubagentRun(runId));
6488
+ routeClosedWorkflowStageMessage(entry, inboundDeliveries, replyTracker, replyWaiters.pending(), () => {
6489
+ if (message.expectsReply === true && liveContext.orchestrationContext?.lateMessageRouter === undefined) {
6490
+ throw new Error("Workflow stage is closed and cannot reply because post-mortem routing is unavailable. Contact a live stage or start new work with explicit context.");
6491
+ }
6492
+ return sendIncomingMessage(entry, isDeliveryFeedback(message) ? "prelude" : "trigger", messageGeneration, false);
6493
+ }, () => client, () => Boolean(getLiveContext(liveContext, messageGeneration)), (runId) => stageAdmission.boundary.ownsSubagentRun(runId));
6268
6494
  return;
6269
6495
  }
6270
6496
  const admission = inboundDeliveries.admit(from, message);
@@ -6275,6 +6501,12 @@ function piIntercomExtension(pi, testOverrides = {}) {
6275
6501
  inboundDeliveries.commit(reservation);
6276
6502
  return;
6277
6503
  }
6504
+ if (isDeliveryFeedback(message)) {
6505
+ return retryStableDelivery({
6506
+ deliver: () => sendIncomingMessage(entry, "prelude", messageGeneration, false),
6507
+ isCurrent: () => Boolean(getLiveContext(liveContext, messageGeneration))
6508
+ }).then(() => inboundDeliveries.commit(reservation), (error) => inboundDeliveries.release(reservation, toError3(error)));
6509
+ }
6278
6510
  const replyContext = replyTracker.recordIncomingMessage(from, message);
6279
6511
  const commit = () => {
6280
6512
  inboundDeliveries.commit(reservation);
@@ -6286,17 +6518,18 @@ function piIntercomExtension(pi, testOverrides = {}) {
6286
6518
  tracker: replyTracker,
6287
6519
  replyContext,
6288
6520
  currentClient: () => client,
6289
- commit
6521
+ commit,
6522
+ failurePrefix: liveContext.subagentPolicy?.executionEnded === undefined ? undefined : "Subagent could not admit intercom ask"
6290
6523
  });
6291
- const stageDelivery = admitWorkflowStageInbound(liveContext, (admissionBarrier) => {
6524
+ const activeDelivery = admitActiveSessionInbound(liveContext, (admissionBarrier) => {
6292
6525
  replyTracker.queueTurnContext(replyContext);
6293
6526
  return retryStableDelivery({
6294
- deliver: () => sendIncomingMessage(entry, "trigger", messageGeneration, false, undefined, admissionBarrier),
6295
- isCurrent: () => Boolean(getLiveContext(liveContext, messageGeneration))
6527
+ deliver: () => sendIncomingMessage(entry, "interrupt", messageGeneration, false, undefined, admissionBarrier),
6528
+ isCurrent: () => Boolean(getLiveContext(liveContext, messageGeneration)) && liveContext.subagentPolicy?.executionEnded?.aborted !== true && liveContext.subagentPolicy?.messageAdmission?.isOpen() !== false
6296
6529
  });
6297
6530
  }, () => foregroundDetachHandoff.claim(from, message, messageGeneration, () => Boolean(getLiveContext(liveContext, messageGeneration))), release);
6298
- if (stageDelivery !== false) {
6299
- stageDelivery.then(commit, release);
6531
+ if (activeDelivery !== false) {
6532
+ activeDelivery.then(commit, release);
6300
6533
  return;
6301
6534
  }
6302
6535
  return (async () => {
@@ -6306,14 +6539,16 @@ function piIntercomExtension(pi, testOverrides = {}) {
6306
6539
  release(new Error("Intercom session retired before inbound delivery"));
6307
6540
  return;
6308
6541
  }
6309
- if (!activeContext.isIdle()) {
6542
+ if (!activeContext.isIdle() && !activeContext.getAgentTaskHost?.().hasActiveTaskWaits) {
6310
6543
  if (!activeContext.hasUI) {
6311
6544
  const activeClient = client;
6312
6545
  if (!message.replyTo && activeClient?.isConnected()) {
6313
6546
  try {
6547
+ const refusal = "Message not accepted: recipient was busy in non-interactive mode. Its task was not interrupted.";
6314
6548
  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
6549
+ text: refusal,
6550
+ replyTo: message.id,
6551
+ replyError: refusal
6317
6552
  });
6318
6553
  if (result.delivered && getLiveContext(liveContext, messageGeneration)) {
6319
6554
  replyTracker.markReplied(message.id);
@@ -6347,6 +6582,13 @@ function piIntercomExtension(pi, testOverrides = {}) {
6347
6582
  });
6348
6583
  return;
6349
6584
  }
6585
+ if (!activeContext.isIdle()) {
6586
+ const disposition = await foregroundDetachHandoff.claim(from, message, messageGeneration, () => Boolean(getLiveContext(liveContext, messageGeneration)));
6587
+ if (disposition === "abandoned") {
6588
+ release(new Error("Intercom session retired during foreground-owner admission"));
6589
+ return;
6590
+ }
6591
+ }
6350
6592
  replyTracker.queueTurnContext(replyContext);
6351
6593
  await retryStableDelivery({ deliver: () => sendIncomingMessage(entry, "trigger", messageGeneration, false), isCurrent: () => Boolean(getLiveContext(liveContext, messageGeneration)) });
6352
6594
  commit();
@@ -6581,7 +6823,8 @@ function piIntercomExtension(pi, testOverrides = {}) {
6581
6823
  pendingStageRouteClients.set(runId, state);
6582
6824
  if (state.client?.isConnected()) {
6583
6825
  state.route = route;
6584
- state.client.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages);
6826
+ state.client.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages, route.parent);
6827
+ await state.client.listSessions();
6585
6828
  return;
6586
6829
  }
6587
6830
  if (state.promise) {
@@ -6593,12 +6836,12 @@ function piIntercomExtension(pi, testOverrides = {}) {
6593
6836
  const nextClient = new IntercomClient(`${currentSessionId}:pending-stage-route:${runId}`);
6594
6837
  state.client = nextClient;
6595
6838
  attachPendingStageRouteClientHandlers(runId, state, nextClient);
6596
- await nextClient.connect({ ...buildRegistration(), name: undefined, groups: [normalizeGroup(route.group)], group: normalizeGroup(route.group) }, undefined, undefined, readSubagentMessageSource(runtimeContext?.subagentPolicy));
6839
+ await nextClient.connect({ ...buildRegistration(), recipientPurpose: "control", name: undefined, groups: [normalizeGroup(route.group)], group: normalizeGroup(route.group) }, undefined, undefined, readSubagentMessageSource(runtimeContext?.subagentPolicy));
6597
6840
  if (!pendingStageRouteClientIsCurrent(runId, state, contextAtStart, generationAtStart)) {
6598
6841
  await nextClient.disconnect();
6599
6842
  throw new Error("Intercom runtime no longer active");
6600
6843
  }
6601
- nextClient.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages);
6844
+ nextClient.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages, route.parent);
6602
6845
  await nextClient.listSessions();
6603
6846
  if (!pendingStageRouteClientIsCurrent(runId, state, contextAtStart, generationAtStart)) {
6604
6847
  await nextClient.disconnect();
@@ -6646,7 +6889,8 @@ function piIntercomExtension(pi, testOverrides = {}) {
6646
6889
  async function registerPendingStageRoute(activeClient, runId, route) {
6647
6890
  const routeGroup = normalizeGroup(route.group);
6648
6891
  if (clientRegistrationGroup === routeGroup) {
6649
- activeClient.registerPendingStageRoute(runId, routeGroup, route.capability, route.stages, route.possibleStages);
6892
+ activeClient.registerPendingStageRoute(runId, routeGroup, route.capability, route.stages, route.possibleStages, route.parent);
6893
+ await activeClient.listSessions();
6650
6894
  return;
6651
6895
  }
6652
6896
  await ensurePendingStageRouteClient(runId, { ...route, group: routeGroup });
@@ -6672,15 +6916,16 @@ function piIntercomExtension(pi, testOverrides = {}) {
6672
6916
  let connectFailed = false;
6673
6917
  await ownershipRecorded.promise;
6674
6918
  const nextClient = new IntercomClient(currentSessionId);
6675
- const registration = buildRegistration();
6676
6919
  client = nextClient;
6677
6920
  attachClientHandlers(nextClient);
6678
6921
  try {
6679
6922
  await testOverrides.beforeConnectAttempt?.(reason);
6680
6923
  await spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs);
6681
6924
  const childMetadata = currentChildOrchestratorMetadata();
6682
- await nextClient.connect(registration, childMetadata?.supervisor, supervisorAuthorizations.ownerToken, readSubagentMessageSource(runtimeContext?.subagentPolicy), resolveSessionHomeGroup());
6925
+ await nextClient.connect(buildRegistration(), childMetadata?.supervisor, supervisorAuthorizations.ownerToken, readSubagentMessageSource(runtimeContext?.subagentPolicy), resolveSessionHomeGroup());
6683
6926
  clientRegistrationGroup = resolveSessionHomeGroup();
6927
+ if (replyCapability() === "terminal")
6928
+ nextClient.updatePresence({ replyCapability: "terminal" });
6684
6929
  await supervisorAuthorizations.restore(nextClient);
6685
6930
  for (const [runId, route] of pendingStageRoutes) {
6686
6931
  await registerPendingStageRoute(nextClient, runId, route);
@@ -6734,7 +6979,8 @@ function piIntercomExtension(pi, testOverrides = {}) {
6734
6979
  group: payload.group,
6735
6980
  capability: payload.capability,
6736
6981
  ...payload.stages === undefined ? {} : { stages: payload.stages },
6737
- ...payload.possibleStages === undefined ? {} : { possibleStages: payload.possibleStages }
6982
+ ...payload.possibleStages === undefined ? {} : { possibleStages: payload.possibleStages },
6983
+ ...payload.parent === undefined ? {} : { parent: payload.parent }
6738
6984
  });
6739
6985
  const completion = ensureConnected("background").then((activeClient) => registerPendingStageRoute(activeClient, payload.runId, payload));
6740
6986
  payload.completion = completion;
@@ -6919,6 +7165,7 @@ var init_index_heavy = __esm(() => {
6919
7165
  init_terminal_ordering_barrier();
6920
7166
  init_inbound_message_admission();
6921
7167
  init_late_stage_message_router();
7168
+ init_active_session_admission();
6922
7169
  init_workflow_reply_tracker();
6923
7170
  init_closed_workflow_stage_message();
6924
7171
  init_group();
@@ -6936,14 +7183,49 @@ var init_index_heavy = __esm(() => {
6936
7183
  });
6937
7184
 
6938
7185
  // dist/builtin/intercom/index.ts
6939
- init_result_renderers();
6940
7186
  import { APP_NAME as APP_NAME2, getEnvValue } from "@bastani/atomic";
6941
7187
  import { Text as Text4 } from "@earendil-works/pi-tui";
6942
7188
  import { Type as Type3 } from "typebox";
6943
7189
 
7190
+ // dist/builtin/intercom/context-owner.ts
7191
+ var CONTEXT_OWNERS_KEY = Symbol.for("atomic-coding-agent/extension-context-owners@1");
7192
+ function getExtensionContextOwner(context) {
7193
+ const owners = globalThis[CONTEXT_OWNERS_KEY];
7194
+ return owners?.get(context) ?? context;
7195
+ }
7196
+
7197
+ // dist/builtin/intercom/index.ts
7198
+ init_result_renderers();
7199
+
6944
7200
  // dist/builtin/intercom/lazy-tool-execution.ts
7201
+ init_recoverable_disconnect();
7202
+ init_retry_policy();
7203
+ import { setTimeout as delay } from "node:timers/promises";
6945
7204
  async function executeHeavyTool(loadHeavy, name, args) {
6946
- const handle = await loadHeavy(args[4]);
7205
+ const params = args[1];
7206
+ const recoverInitialization = name === "intercom" && ["send", "ask", "reply"].includes(params.action ?? "");
7207
+ let handle;
7208
+ let retries = 0;
7209
+ for (;; ) {
7210
+ if (recoverInitialization && args[2]?.aborted)
7211
+ return initializationFailure("Cancelled", retries);
7212
+ try {
7213
+ handle = await loadHeavy(args[4]);
7214
+ break;
7215
+ } catch (error) {
7216
+ if (!recoverInitialization || !isRecoverableIntercomDisconnect(error))
7217
+ throw error;
7218
+ const delayMs = RECONNECT_DELAYS_MS[retries];
7219
+ if (delayMs === undefined)
7220
+ return initializationFailure("Client disconnected", retries);
7221
+ try {
7222
+ await delay(delayMs, undefined, { signal: args[2] });
7223
+ } catch {
7224
+ return initializationFailure("Cancelled", retries);
7225
+ }
7226
+ retries += 1;
7227
+ }
7228
+ }
6947
7229
  handle.assertCurrent();
6948
7230
  const tool = handle.heavy.tools.get(name);
6949
7231
  if (!tool?.execute)
@@ -6952,6 +7234,13 @@ async function executeHeavyTool(loadHeavy, name, args) {
6952
7234
  handle.assertCurrent();
6953
7235
  return result;
6954
7236
  }
7237
+ function initializationFailure(reason, retries) {
7238
+ return {
7239
+ content: [{ type: "text", text: `${reason}. Intercom initialization stopped after ${retries} automatic retries. This operation was not sent.` }],
7240
+ isError: true,
7241
+ details: { error: true, terminal: true, automaticRetries: retries, outcome: "not_sent" }
7242
+ };
7243
+ }
6955
7244
  async function runHeavyCommand(loadHeavy, args, ctx) {
6956
7245
  const handle = await loadHeavy(ctx);
6957
7246
  handle.assertCurrent();
@@ -7169,10 +7458,37 @@ function renderHeavyToolResult(loadedHeavy, name, args) {
7169
7458
  return renderer(...args);
7170
7459
  return renderIntercomToolResult(name, args);
7171
7460
  }
7172
- function reportRelayFailure(eventName, error) {
7461
+ function diagnosticDetail(error) {
7462
+ try {
7463
+ return String(error instanceof Error ? error.message : error);
7464
+ } catch {
7465
+ return "Unprintable error";
7466
+ }
7467
+ }
7468
+ function captureDiagnosticRoute(ctx) {
7469
+ try {
7470
+ return ctx?.hasUI && ctx.mode === "tui" ? ctx : "console";
7471
+ } catch {
7472
+ return "silent";
7473
+ }
7474
+ }
7475
+ function reportDiagnostic(route, message, error, level, consoleMessage = message) {
7476
+ if (route === "console") {
7477
+ console.error(consoleMessage, error);
7478
+ return;
7479
+ }
7480
+ if (route === "silent")
7481
+ return;
7482
+ try {
7483
+ route.ui.notify(message, level);
7484
+ } catch {}
7485
+ }
7486
+ function reportRelayFailure(route, eventName, error) {
7173
7487
  if (isRecoverableIntercomDisconnect(error))
7174
7488
  return;
7175
- console.error(`Intercom event relay failed (${eventName}):`, error);
7489
+ const prefix = `Intercom event relay failed (${eventName}):`;
7490
+ const detail = diagnosticDetail(error);
7491
+ reportDiagnostic(route, `${prefix} ${detail}`, error, "error", prefix);
7176
7492
  }
7177
7493
  var WARM_UP_RETRY_ATTEMPTS = 5;
7178
7494
  function intercom(pi, options = {}) {
@@ -7180,6 +7496,7 @@ function intercom(pi, options = {}) {
7180
7496
  let heavyAttempt = null;
7181
7497
  let loadedHeavy = null;
7182
7498
  let sessionSnapshot = null;
7499
+ let shutdownDiagnosticRoute;
7183
7500
  let lifecycleGeneration = 0;
7184
7501
  let nextLeaseId = 1;
7185
7502
  let activeLease = createLifecycleLease(nextLeaseId++);
@@ -7263,6 +7580,8 @@ function intercom(pi, options = {}) {
7263
7580
  await promise;
7264
7581
  }
7265
7582
  async function loadHeavy(ctx) {
7583
+ let diagnosticRoute = captureDiagnosticRoute(ctx);
7584
+ let diagnosticOwner = ctx && getExtensionContextOwner(ctx);
7266
7585
  const lease = activeLease;
7267
7586
  if (lease.retired)
7268
7587
  throw new Error("Intercom initialization unavailable: no active session");
@@ -7279,6 +7598,7 @@ function intercom(pi, options = {}) {
7279
7598
  return handle;
7280
7599
  }
7281
7600
  let promise;
7601
+ let replayCtx = null;
7282
7602
  promise = (async () => {
7283
7603
  const captured = {
7284
7604
  tools: new Map,
@@ -7287,7 +7607,6 @@ function intercom(pi, options = {}) {
7287
7607
  shortcuts: new Map,
7288
7608
  eventHandlers: new Map
7289
7609
  };
7290
- let replayCtx = null;
7291
7610
  let cleaned = false;
7292
7611
  const cleanupCandidate = async () => {
7293
7612
  const shutdown = lease.shutdown;
@@ -7299,7 +7618,9 @@ function intercom(pi, options = {}) {
7299
7618
  try {
7300
7619
  await dispatchHandlers(captured, "session_shutdown", event, cleanupCtx);
7301
7620
  } catch (cleanupError) {
7302
- console.error("Intercom failed to clean rejected lazy candidate:", cleanupError);
7621
+ const prefix = "Intercom failed to clean rejected lazy candidate:";
7622
+ const detail = diagnosticDetail(cleanupError);
7623
+ reportDiagnostic(shutdown?.diagnosticRoute ?? diagnosticRoute, `${prefix} ${detail}`, cleanupError, "error", prefix);
7303
7624
  }
7304
7625
  };
7305
7626
  try {
@@ -7311,6 +7632,11 @@ function intercom(pi, options = {}) {
7311
7632
  sessionSnapshot = { event: createSyntheticSessionStartEvent(), ctx, generation: ++lifecycleGeneration, lease };
7312
7633
  }
7313
7634
  await ensureSessionStartReplayed(captured, lease, (replayContext) => {
7635
+ const owner = getExtensionContextOwner(replayContext);
7636
+ if (owner !== diagnosticOwner) {
7637
+ diagnosticRoute = captureDiagnosticRoute(replayContext);
7638
+ diagnosticOwner = owner;
7639
+ }
7314
7640
  replayCtx = replayContext;
7315
7641
  });
7316
7642
  assertLease(lease);
@@ -7329,8 +7655,8 @@ function intercom(pi, options = {}) {
7329
7655
  if (heavyAttempt?.promise === promise)
7330
7656
  heavyAttempt = null;
7331
7657
  if (!isRecoverableIntercomDisconnect(error)) {
7332
- const message = error instanceof Error ? error.message : String(error);
7333
- console.error(`Intercom heavy initialization failed; a later call will retry: ${message}`, error);
7658
+ const message = diagnosticDetail(error);
7659
+ reportDiagnostic(diagnosticRoute, `Intercom heavy initialization failed; a later call will retry: ${message}`, error, "warning");
7334
7660
  }
7335
7661
  });
7336
7662
  return promise;
@@ -7441,6 +7767,7 @@ function intercom(pi, options = {}) {
7441
7767
  }
7442
7768
  const generation = ++lifecycleGeneration;
7443
7769
  sessionSnapshot = { event, ctx, generation, lease };
7770
+ shutdownDiagnosticRoute = undefined;
7444
7771
  cancelWarmUpRetry();
7445
7772
  if (ctx.orchestrationContext?.kind === "workflow-stage" && ctx.orchestrationContext.pendingStageDelivery !== undefined) {
7446
7773
  const pendingStageDelivery = ctx.orchestrationContext.pendingStageDelivery;
@@ -7458,7 +7785,9 @@ function intercom(pi, options = {}) {
7458
7785
  pi.on("session_shutdown", async (event, ctx) => {
7459
7786
  const lease = activeLease;
7460
7787
  const generation = ++lifecycleGeneration;
7461
- retireLifecycleLease(lease, { event, ctx, generation });
7788
+ const diagnosticRoute = captureDiagnosticRoute(ctx);
7789
+ retireLifecycleLease(lease, { event, ctx, generation, diagnosticRoute });
7790
+ shutdownDiagnosticRoute = diagnosticRoute;
7462
7791
  cancelWarmUpRetry();
7463
7792
  const retiredHeavy = loadedHeavy?.heavy ?? null;
7464
7793
  const retiredAttempt = heavyAttempt?.lease === lease ? heavyAttempt.promise : null;
@@ -7579,13 +7908,15 @@ function intercom(pi, options = {}) {
7579
7908
  return;
7580
7909
  payload.handled = true;
7581
7910
  const forwarded = { ...payload, handled: false, completion: undefined };
7582
- payload.completion = loadHeavy(latestLifecycleContext()).then(async (handle) => {
7911
+ const ctx = latestLifecycleContext();
7912
+ const diagnosticRoute = ctx ? captureDiagnosticRoute(ctx) : shutdownDiagnosticRoute ?? "console";
7913
+ payload.completion = loadHeavy(ctx).then(async (handle) => {
7583
7914
  handle.assertCurrent();
7584
7915
  await dispatchEventHandlers(handle.heavy, PENDING_STAGE_UNDELIVERABLE_EVENT2, forwarded);
7585
7916
  handle.assertCurrent();
7586
7917
  return forwarded.handled === true && forwarded.completion !== undefined ? await forwarded.completion : false;
7587
7918
  }).catch((error) => {
7588
- reportRelayFailure(PENDING_STAGE_UNDELIVERABLE_EVENT2, error);
7919
+ reportRelayFailure(diagnosticRoute, PENDING_STAGE_UNDELIVERABLE_EVENT2, error);
7589
7920
  return false;
7590
7921
  });
7591
7922
  });
@@ -7595,7 +7926,9 @@ function intercom(pi, options = {}) {
7595
7926
  PENDING_STAGE_ROUTE_EVENT2
7596
7927
  ]) {
7597
7928
  pi.events.on(eventName, (payload) => {
7598
- const completion = loadHeavy(latestLifecycleContext()).then(async (handle) => {
7929
+ const ctx = latestLifecycleContext();
7930
+ const diagnosticRoute = ctx ? captureDiagnosticRoute(ctx) : shutdownDiagnosticRoute ?? "console";
7931
+ const completion = loadHeavy(ctx).then(async (handle) => {
7599
7932
  handle.assertCurrent();
7600
7933
  await dispatchEventHandlers(handle.heavy, eventName, payload);
7601
7934
  handle.assertCurrent();
@@ -7610,7 +7943,7 @@ function intercom(pi, options = {}) {
7610
7943
  }
7611
7944
  completion.catch((error) => {
7612
7945
  rejectLazyResultRelay(pi, eventName, payload, error);
7613
- reportRelayFailure(eventName, error);
7946
+ reportRelayFailure(diagnosticRoute, eventName, error);
7614
7947
  });
7615
7948
  });
7616
7949
  }
@@ -7634,7 +7967,7 @@ function intercom(pi, options = {}) {
7634
7967
  Use this to communicate findings, request help, or coordinate work with other sessions.
7635
7968
  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
7969
  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.
7970
+ 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
7971
  Usage:
7639
7972
  intercom({ action: "list" }) → List sessions in your group
7640
7973
  intercom({ action: "list", group: "name" }) → Read-only peek at another group's sessions
@@ -7643,12 +7976,11 @@ Usage:
7643
7976
  intercom({ action: "send", to: "session-name", message: "..." }) → Send message (own group only)
7644
7977
  intercom({ action: "ask", to: "session-name", message: "..." }) → Ask and wait for reply
7645
7978
  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
7979
  intercom({ action: "pending" }) → List unresolved inbound asks
7648
7980
  intercom({ action: "status" }) → Show connection status and your group
7649
7981
 
7650
7982
  "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.",
7983
+ 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
7984
  parameters: Type3.Object({
7653
7985
  action: Type3.String({ description: "Action: 'list', 'join', 'leave', 'send', 'ask', 'reply', 'pending', or 'status'" }),
7654
7986
  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 +7992,15 @@ Usage:
7660
7992
  language: Type3.Optional(Type3.String())
7661
7993
  }))),
7662
7994
  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
7995
  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
7996
  }),
7666
- execute: (...args) => executeHeavyTool(loadHeavy, "intercom", args),
7997
+ execute: (...args) => {
7998
+ const invocationLease = activeLease;
7999
+ return executeHeavyTool((ctx) => {
8000
+ assertLease(invocationLease);
8001
+ return loadHeavy(ctx);
8002
+ }, "intercom", args);
8003
+ },
7667
8004
  renderResult: (...args) => renderHeavyToolResult(loadedHeavy?.heavy ?? null, "intercom", args),
7668
8005
  renderCall(args, theme) {
7669
8006
  const input = args;