@bastani/atomic 0.9.39-alpha.2 → 0.9.40-alpha.1

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 (261) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/dist/builtin/intercom/CHANGELOG.md +20 -0
  3. package/dist/builtin/intercom/broker/broker.ts +523 -72
  4. package/dist/builtin/intercom/broker/client.ts +136 -5
  5. package/dist/builtin/intercom/broker/database-wake-up-bus.ts +274 -0
  6. package/dist/builtin/intercom/broker/group-membership.ts +2 -2
  7. package/dist/builtin/intercom/broker/multinode-router.ts +1500 -0
  8. package/dist/builtin/intercom/broker/multinode-state-store.ts +569 -0
  9. package/dist/builtin/intercom/broker/open-broker-state.ts +160 -0
  10. package/dist/builtin/intercom/broker/paths.ts +6 -0
  11. package/dist/builtin/intercom/broker/pending-send-registry.ts +14 -0
  12. package/dist/builtin/intercom/broker/recipient-receipts.ts +93 -0
  13. package/dist/builtin/intercom/broker/restoring-recipients.ts +263 -0
  14. package/dist/builtin/intercom/broker/send-handler.ts +241 -25
  15. package/dist/builtin/intercom/broker/session-id-reclaim.ts +41 -0
  16. package/dist/builtin/intercom/broker/socket-writes.ts +47 -0
  17. package/dist/builtin/intercom/broker/spawn.ts +10 -2
  18. package/dist/builtin/intercom/broker/sql-held-send-store.ts +96 -0
  19. package/dist/builtin/intercom/broker/sql-known-session-store.ts +129 -0
  20. package/dist/builtin/intercom/broker/sql-lease-store.ts +194 -0
  21. package/dist/builtin/intercom/broker/sql-outbox-store.ts +249 -0
  22. package/dist/builtin/intercom/broker/sql-pending-ask-store.ts +105 -0
  23. package/dist/builtin/intercom/broker/sql-restoring-reservation-store.ts +295 -0
  24. package/dist/builtin/intercom/broker/sql-sent-message-authority.ts +126 -0
  25. package/dist/builtin/intercom/broker/supervisor-channel.ts +10 -0
  26. package/dist/builtin/intercom/broker/wake-up-bus.ts +60 -0
  27. package/dist/builtin/intercom/index.bundle.mjs +793 -91
  28. package/dist/builtin/intercom/package.json +1 -1
  29. package/dist/builtin/intercom/retry-policy.ts +4 -0
  30. package/dist/builtin/intercom/session-target.ts +24 -0
  31. package/dist/builtin/intercom/types.ts +57 -3
  32. package/dist/builtin/mcp/package.json +1 -1
  33. package/dist/builtin/subagents/CHANGELOG.md +37 -0
  34. package/dist/builtin/subagents/README.md +18 -12
  35. package/dist/builtin/subagents/package.json +1 -1
  36. package/dist/builtin/subagents/skills/agent-browser/SKILL.md +1 -1
  37. package/dist/builtin/subagents/skills/cua-driver/BROWSER.md +55 -8
  38. package/dist/builtin/subagents/skills/cua-driver/EMBEDDING.md +7 -2
  39. package/dist/builtin/subagents/skills/cua-driver/LINUX.md +7 -1
  40. package/dist/builtin/subagents/skills/cua-driver/MACOS.md +151 -27
  41. package/dist/builtin/subagents/skills/cua-driver/RUNTIME.md +1 -1
  42. package/dist/builtin/subagents/skills/cua-driver/SKILL.md +33 -17
  43. package/dist/builtin/subagents/skills/cua-driver/WINDOWS.md +5 -0
  44. package/dist/builtin/subagents/skills/cua-driver/WORKFLOW.md +46 -8
  45. package/dist/builtin/subagents/skills/subagent/SKILL.md +18 -20
  46. package/dist/builtin/subagents/src/extension/index.bundle.mjs +8032 -6034
  47. package/dist/builtin/web-access/package.json +1 -1
  48. package/dist/builtin/workflows/CHANGELOG.md +32 -0
  49. package/dist/builtin/workflows/README.md +1 -1
  50. package/dist/builtin/workflows/package.json +1 -1
  51. package/dist/builtin/workflows/skills/impeccable/SKILL.md +8 -8
  52. package/dist/builtin/workflows/skills/impeccable/reference/adapt.md +3 -3
  53. package/dist/builtin/workflows/skills/impeccable/reference/adapt.native.md +1 -1
  54. package/dist/builtin/workflows/skills/impeccable/reference/audit.md +4 -2
  55. package/dist/builtin/workflows/skills/impeccable/reference/audit.native.md +2 -2
  56. package/dist/builtin/workflows/skills/impeccable/reference/craft-floor.md +1 -1
  57. package/dist/builtin/workflows/skills/impeccable/reference/critique.md +22 -9
  58. package/dist/builtin/workflows/skills/impeccable/reference/degraded/finish-reviewer.md +2 -2
  59. package/dist/builtin/workflows/skills/impeccable/reference/distill.md +3 -3
  60. package/dist/builtin/workflows/skills/impeccable/reference/extract.md +3 -3
  61. package/dist/builtin/workflows/skills/impeccable/reference/harden.md +2 -4
  62. package/dist/builtin/workflows/skills/impeccable/reference/hooks.md +4 -4
  63. package/dist/builtin/workflows/skills/impeccable/reference/live.md +1 -1
  64. package/dist/builtin/workflows/skills/impeccable/reference/new-work.md +6 -6
  65. package/dist/builtin/workflows/skills/impeccable/reference/onboard.md +3 -3
  66. package/dist/builtin/workflows/skills/impeccable/reference/optimize.md +3 -3
  67. package/dist/builtin/workflows/skills/impeccable/reference/overdrive.md +3 -3
  68. package/dist/builtin/workflows/skills/impeccable/reference/quieter.md +3 -3
  69. package/dist/builtin/workflows/skills/impeccable/reference/typeset.md +10 -0
  70. package/dist/builtin/workflows/skills/impeccable/reference/visualize.md +1 -1
  71. package/dist/builtin/workflows/skills/impeccable/scripts/VERSION +1 -1
  72. package/dist/builtin/workflows/skills/impeccable/scripts/impeccable +6 -0
  73. package/dist/builtin/workflows/skills/impeccable/scripts/impeccable.cmd +47 -22
  74. package/dist/builtin/workflows/skills/impeccable/scripts/live-browser-dom.js +34 -1
  75. package/dist/builtin/workflows/skills/impeccable/scripts/live-browser-session.js +25 -1
  76. package/dist/builtin/workflows/skills/impeccable/scripts/live-browser.js +33 -8
  77. package/dist/builtin/workflows/src/durable/journal/resolution.d.ts +7 -7
  78. package/dist/builtin/workflows/src/extension/index.bundle.mjs +22855 -22308
  79. package/dist/builtin/workflows/src/index.js +106 -35
  80. package/dist/cli/args.d.ts +2 -0
  81. package/dist/cli/args.d.ts.map +1 -1
  82. package/dist/cli/args.js +16 -0
  83. package/dist/cli/args.js.map +1 -1
  84. package/dist/core/agent-session-extension-bindings.d.ts +2 -0
  85. package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
  86. package/dist/core/agent-session-extension-bindings.js +6 -6
  87. package/dist/core/agent-session-extension-bindings.js.map +1 -1
  88. package/dist/core/agent-session-methods.d.ts +6 -3
  89. package/dist/core/agent-session-methods.d.ts.map +1 -1
  90. package/dist/core/agent-session-methods.js.map +1 -1
  91. package/dist/core/agent-session-persistent-custom-messages.d.ts +7 -2
  92. package/dist/core/agent-session-persistent-custom-messages.d.ts.map +1 -1
  93. package/dist/core/agent-session-persistent-custom-messages.js +29 -12
  94. package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
  95. package/dist/core/agent-session-recovery.d.ts +14 -0
  96. package/dist/core/agent-session-recovery.d.ts.map +1 -0
  97. package/dist/core/agent-session-recovery.js +83 -0
  98. package/dist/core/agent-session-recovery.js.map +1 -0
  99. package/dist/core/agent-session-tasks.d.ts.map +1 -1
  100. package/dist/core/agent-session-tasks.js +4 -6
  101. package/dist/core/agent-session-tasks.js.map +1 -1
  102. package/dist/core/agent-session-types.d.ts +13 -0
  103. package/dist/core/agent-session-types.d.ts.map +1 -1
  104. package/dist/core/agent-session-types.js.map +1 -1
  105. package/dist/core/agent-session.d.ts +2 -1
  106. package/dist/core/agent-session.d.ts.map +1 -1
  107. package/dist/core/agent-session.js +4 -1
  108. package/dist/core/agent-session.js.map +1 -1
  109. package/dist/core/extensions/api-types.d.ts +6 -2
  110. package/dist/core/extensions/api-types.d.ts.map +1 -1
  111. package/dist/core/extensions/api-types.js.map +1 -1
  112. package/dist/core/extensions/event-results.d.ts +21 -0
  113. package/dist/core/extensions/event-results.d.ts.map +1 -1
  114. package/dist/core/extensions/event-results.js.map +1 -1
  115. package/dist/core/extensions/index.d.ts +1 -1
  116. package/dist/core/extensions/index.d.ts.map +1 -1
  117. package/dist/core/extensions/index.js.map +1 -1
  118. package/dist/core/extensions/loader-api.d.ts.map +1 -1
  119. package/dist/core/extensions/loader-api.js +4 -0
  120. package/dist/core/extensions/loader-api.js.map +1 -1
  121. package/dist/core/extensions/runner-events.d.ts +9 -2
  122. package/dist/core/extensions/runner-events.d.ts.map +1 -1
  123. package/dist/core/extensions/runner-events.js +29 -0
  124. package/dist/core/extensions/runner-events.js.map +1 -1
  125. package/dist/core/extensions/runner.d.ts +5 -3
  126. package/dist/core/extensions/runner.d.ts.map +1 -1
  127. package/dist/core/extensions/runner.js +7 -2
  128. package/dist/core/extensions/runner.js.map +1 -1
  129. package/dist/core/extensions/runtime-types.d.ts +1 -0
  130. package/dist/core/extensions/runtime-types.d.ts.map +1 -1
  131. package/dist/core/extensions/runtime-types.js.map +1 -1
  132. package/dist/core/extensions/session-events.d.ts +30 -2
  133. package/dist/core/extensions/session-events.d.ts.map +1 -1
  134. package/dist/core/extensions/session-events.js.map +1 -1
  135. package/dist/core/sdk-types.d.ts +3 -2
  136. package/dist/core/sdk-types.d.ts.map +1 -1
  137. package/dist/core/sdk-types.js.map +1 -1
  138. package/dist/core/sdk.d.ts.map +1 -1
  139. package/dist/core/sdk.js +3 -0
  140. package/dist/core/sdk.js.map +1 -1
  141. package/dist/core/session-storage.d.ts.map +1 -1
  142. package/dist/core/session-storage.js +15 -9
  143. package/dist/core/session-storage.js.map +1 -1
  144. package/dist/core/storage/process-selection.d.ts +39 -0
  145. package/dist/core/storage/process-selection.d.ts.map +1 -0
  146. package/dist/core/storage/process-selection.js +154 -0
  147. package/dist/core/storage/process-selection.js.map +1 -0
  148. package/dist/core/storage/provider.d.ts +6 -1
  149. package/dist/core/storage/provider.d.ts.map +1 -1
  150. package/dist/core/storage/provider.js +3 -2
  151. package/dist/core/storage/provider.js.map +1 -1
  152. package/dist/core/storage/selection.d.ts +1 -1
  153. package/dist/core/storage/selection.d.ts.map +1 -1
  154. package/dist/core/storage/selection.js.map +1 -1
  155. package/dist/core/storage/session/jsonl-session-store.d.ts +2 -0
  156. package/dist/core/storage/session/jsonl-session-store.d.ts.map +1 -1
  157. package/dist/core/storage/session/jsonl-session-store.js +38 -2
  158. package/dist/core/storage/session/jsonl-session-store.js.map +1 -1
  159. package/dist/core/tasks/completion.d.ts +11 -2
  160. package/dist/core/tasks/completion.d.ts.map +1 -1
  161. package/dist/core/tasks/completion.js +40 -16
  162. package/dist/core/tasks/completion.js.map +1 -1
  163. package/dist/core/tasks/pause.d.ts +4 -1
  164. package/dist/core/tasks/pause.d.ts.map +1 -1
  165. package/dist/core/tasks/pause.js +8 -5
  166. package/dist/core/tasks/pause.js.map +1 -1
  167. package/dist/index-extensions.d.ts +1 -1
  168. package/dist/index-extensions.d.ts.map +1 -1
  169. package/dist/index-extensions.js.map +1 -1
  170. package/dist/index.d.ts +2 -1
  171. package/dist/index.d.ts.map +1 -1
  172. package/dist/index.js +2 -0
  173. package/dist/index.js.map +1 -1
  174. package/dist/main.d.ts.map +1 -1
  175. package/dist/main.js +7 -1
  176. package/dist/main.js.map +1 -1
  177. package/dist/modes/interactive/components/chat-session-host-rendering.d.ts.map +1 -1
  178. package/dist/modes/interactive/components/chat-session-host-rendering.js +11 -1
  179. package/dist/modes/interactive/components/chat-session-host-rendering.js.map +1 -1
  180. package/dist/modes/interactive/components/chat-session-host-state.d.ts +2 -0
  181. package/dist/modes/interactive/components/chat-session-host-state.d.ts.map +1 -1
  182. package/dist/modes/interactive/components/chat-session-host-state.js +2 -0
  183. package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
  184. package/dist/modes/interactive/interactive-deferred-startup.d.ts.map +1 -1
  185. package/dist/modes/interactive/interactive-deferred-startup.js +4 -0
  186. package/dist/modes/interactive/interactive-deferred-startup.js.map +1 -1
  187. package/dist/modes/interactive/interactive-mode-surface.d.ts +2 -1
  188. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  189. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  190. package/dist/modes/interactive/interactive-render-chat.js +3 -0
  191. package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
  192. package/dist/modes/interactive/interactive-session-routing.js +2 -0
  193. package/dist/modes/interactive/interactive-session-routing.js.map +1 -1
  194. package/dist/modes/interactive/interactive-session-runtime.d.ts +2 -1
  195. package/dist/modes/interactive/interactive-session-runtime.d.ts.map +1 -1
  196. package/dist/modes/interactive/interactive-session-runtime.js +29 -0
  197. package/dist/modes/interactive/interactive-session-runtime.js.map +1 -1
  198. package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
  199. package/dist/modes/interactive/interactive-startup.js +4 -1
  200. package/dist/modes/interactive/interactive-startup.js.map +1 -1
  201. package/dist/modes/interactive-engine/engine-args.d.ts.map +1 -1
  202. package/dist/modes/interactive-engine/engine-args.js +4 -0
  203. package/dist/modes/interactive-engine/engine-args.js.map +1 -1
  204. package/dist/modes/interactive-engine/engine-render-service.d.ts.map +1 -1
  205. package/dist/modes/interactive-engine/engine-render-service.js +4 -4
  206. package/dist/modes/interactive-engine/engine-render-service.js.map +1 -1
  207. package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
  208. package/dist/modes/interactive-engine/isolated-runtime.js +4 -0
  209. package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
  210. package/dist/modes/interactive-engine/remote-renderer.js +1 -1
  211. package/dist/modes/interactive-engine/remote-renderer.js.map +1 -1
  212. package/dist/modes/rpc/rpc-client-api.d.ts +4 -1
  213. package/dist/modes/rpc/rpc-client-api.d.ts.map +1 -1
  214. package/dist/modes/rpc/rpc-client-api.js +4 -0
  215. package/dist/modes/rpc/rpc-client-api.js.map +1 -1
  216. package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
  217. package/dist/modes/rpc/rpc-command-handler.js +3 -0
  218. package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
  219. package/dist/modes/rpc/rpc-command-timeouts.d.ts.map +1 -1
  220. package/dist/modes/rpc/rpc-command-timeouts.js +1 -0
  221. package/dist/modes/rpc/rpc-command-timeouts.js.map +1 -1
  222. package/dist/modes/rpc/rpc-input-scheduler.d.ts.map +1 -1
  223. package/dist/modes/rpc/rpc-input-scheduler.js +6 -1
  224. package/dist/modes/rpc/rpc-input-scheduler.js.map +1 -1
  225. package/dist/modes/rpc/rpc-types.d.ts +12 -1
  226. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  227. package/dist/modes/rpc/rpc-types.js.map +1 -1
  228. package/dist/utils/shell.d.ts.map +1 -1
  229. package/dist/utils/shell.js +44 -11
  230. package/dist/utils/shell.js.map +1 -1
  231. package/dist/utils/tools-manager.js +1 -1
  232. package/dist/utils/tools-manager.js.map +1 -1
  233. package/docs/background-tasks.md +5 -3
  234. package/docs/computer-use.md +2 -2
  235. package/docs/environment-variables.md +4 -1
  236. package/docs/extensions/events.md +29 -2
  237. package/docs/getting-started/first-session.md +1 -1
  238. package/docs/guides/intercom.md +1 -1
  239. package/docs/intercom/operations.md +103 -1
  240. package/docs/intercom/reference.md +10 -3
  241. package/docs/intercom.md +8 -6
  242. package/docs/keybindings.md +1 -1
  243. package/docs/models.md +1 -1
  244. package/docs/providers.md +4 -2
  245. package/docs/reference/cli.md +5 -0
  246. package/docs/rpc/protocol.md +19 -0
  247. package/docs/rpc.md +3 -0
  248. package/docs/sdk/web-server.md +1 -1
  249. package/docs/sdk.md +5 -2
  250. package/docs/sessions.md +17 -1
  251. package/docs/settings.md +5 -3
  252. package/docs/skills.md +1 -1
  253. package/docs/storage.md +54 -3
  254. package/docs/subagents.md +49 -9
  255. package/docs/usage.md +1 -1
  256. package/docs/windows.md +14 -4
  257. package/docs/workflows/api-reference.md +1 -1
  258. package/docs/workflows/authoring.md +1 -1
  259. package/docs/workflows/operations.md +10 -6
  260. package/npm-shrinkwrap.json +37 -37
  261. package/package.json +4 -4
@@ -164,7 +164,7 @@ var init_recoverable_disconnect = __esm(() => {
164
164
  });
165
165
 
166
166
  // dist/builtin/intercom/retry-policy.ts
167
- var ASK_REPLY_TIMEOUT_MS, RETRY_IDENTITY_RETRY_OPPORTUNITY_MS, RETRY_IDENTITY_TTL_MS, DELIVERED_MESSAGE_TTL_MS, RECONNECT_DELAYS_MS;
167
+ var ASK_REPLY_TIMEOUT_MS, RETRY_IDENTITY_RETRY_OPPORTUNITY_MS, RETRY_IDENTITY_TTL_MS, DELIVERED_MESSAGE_TTL_MS, RECONNECT_DELAYS_MS, SEND_RESPONSE_TIMEOUT_MS = 1e4;
168
168
  var init_retry_policy = __esm(() => {
169
169
  ASK_REPLY_TIMEOUT_MS = 10 * 60 * 1000;
170
170
  RETRY_IDENTITY_RETRY_OPPORTUNITY_MS = 60 * 1000;
@@ -182,6 +182,298 @@ var init_reconnect_backoff = __esm(() => {
182
182
  BACKOFF_MS = [1000, 2000, 5000, 1e4, 30000];
183
183
  });
184
184
 
185
+ // dist/builtin/intercom/session-recovery.ts
186
+ async function awaitRestoredIntercomPeers(events, ownerSessionId) {
187
+ const request = { ownerSessionId };
188
+ try {
189
+ events.emit(SUBAGENT_RESTORED_INTERCOM_PEERS_EVENT, request);
190
+ return request.completion ? await request.completion : [];
191
+ } catch {
192
+ return [];
193
+ }
194
+ }
195
+ function isReserveRestoringChildRequest(value) {
196
+ if (!value || typeof value !== "object")
197
+ return false;
198
+ const request = value;
199
+ return typeof request.capability === "string" && request.capability.length > 0 && (request.group === undefined || typeof request.group === "string") && (request.dormant === undefined || typeof request.dormant === "boolean") && Array.isArray(request.aliases) && request.aliases.every((alias) => typeof alias === "string");
200
+ }
201
+ function isReleaseRestoringChildRequest(value) {
202
+ if (!value || typeof value !== "object")
203
+ return false;
204
+ const request = value;
205
+ return typeof request.capability === "string" && request.capability.length > 0 && (request.gone === undefined || typeof request.gone === "string") && (request.refusal === undefined || typeof request.refusal === "string");
206
+ }
207
+ async function awaitSubagentChildRestoration(events, ownerSessionId, target) {
208
+ const request = { ownerSessionId, target, timeoutMs: CHILD_RESTORATION_WAIT_MS };
209
+ try {
210
+ events.emit(SUBAGENT_AWAIT_CHILD_RESTORATION_EVENT, request);
211
+ return request.completion ? await request.completion : undefined;
212
+ } catch {
213
+ return;
214
+ }
215
+ }
216
+ function isAwaitIntercomPeerRequest(value) {
217
+ const request = value;
218
+ return typeof request.name === "string" && request.name.trim().length > 0 && typeof request.timeoutMs === "number" && (request.group === undefined || typeof request.group === "string");
219
+ }
220
+ function hasIntercomHistory(entries) {
221
+ return entries.some((entry) => entry.type === "custom_message" && entry.customType === "intercom_message" || entry.type === "custom" && entry.customType === "intercom_inbox" || entry.type === "custom" && entry.customType === "subagent-child" || entry.type === "message" && entry.message.role === "toolResult" && (entry.message.toolName === "intercom" || entry.message.toolName === "contact_supervisor"));
222
+ }
223
+ async function waitForIntercomPeer(client, request) {
224
+ const name = request.name.trim().toLowerCase();
225
+ const deadline = Date.now() + request.timeoutMs;
226
+ for (;; ) {
227
+ const sessions = await client.listSessions(request.group);
228
+ if (sessions.some((session) => session.name?.trim().toLowerCase() === name))
229
+ return true;
230
+ if (Date.now() + PEER_POLL_INTERVAL_MS > deadline)
231
+ return false;
232
+ await new Promise((resolve) => setTimeout(resolve, PEER_POLL_INTERVAL_MS));
233
+ }
234
+ }
235
+ function inboundEntry(delivery) {
236
+ if (delivery.customType !== "intercom_message")
237
+ return;
238
+ const details = delivery.details;
239
+ return typeof details?.from?.id === "string" && typeof details.message?.id === "string" ? details : undefined;
240
+ }
241
+ function peerLabel(from) {
242
+ return from.name ? `\`${from.name}\`` : `\`${from.id}\``;
243
+ }
244
+ function isLivePeer(from, peers) {
245
+ const name = from.name?.trim().toLowerCase();
246
+ return peers.some((peer) => peer.id === from.id || name !== undefined && peer.name?.trim().toLowerCase() === name);
247
+ }
248
+ function isRestoredPeer(from, restored) {
249
+ const name = from.name?.trim().toLowerCase();
250
+ return restored.some((peer) => peer.ids.includes(from.id) || name !== undefined && peer.name.trim().toLowerCase() === name);
251
+ }
252
+ function boundedBody(text) {
253
+ return text.length > RECOVERED_BODY_MAX_CHARS ? `${text.slice(0, RECOVERED_BODY_MAX_CHARS)}…` : text;
254
+ }
255
+ function planIntercomRecoveryReplay(pending, peers, restored = []) {
256
+ const decisions = [];
257
+ const gone = new Map;
258
+ const deferred = new Map;
259
+ const reconnecting = new Map;
260
+ const tally = (counts, key, from) => {
261
+ const sender = counts.get(key) ?? { from, count: 0 };
262
+ sender.count += 1;
263
+ counts.set(key, sender);
264
+ };
265
+ for (const delivery of pending) {
266
+ const entry = inboundEntry(delivery);
267
+ if (!entry || LOCAL_RELAY_SENDERS.has(entry.from.id))
268
+ continue;
269
+ const key = entry.from.name?.trim().toLowerCase() ?? entry.from.id;
270
+ if (peers === undefined) {
271
+ decisions.push({ entryId: delivery.entryId, action: "defer" });
272
+ tally(deferred, key, entry.from);
273
+ continue;
274
+ }
275
+ if (isLivePeer(entry.from, peers)) {
276
+ decisions.push({ entryId: delivery.entryId, action: "replay" });
277
+ continue;
278
+ }
279
+ if (isRestoredPeer(entry.from, restored)) {
280
+ decisions.push({ entryId: delivery.entryId, action: "defer" });
281
+ tally(reconnecting, key, entry.from);
282
+ continue;
283
+ }
284
+ decisions.push({ entryId: delivery.entryId, action: "drop" });
285
+ const group = gone.get(key) ?? { from: entry.from, entries: [] };
286
+ group.entries.push(entry);
287
+ gone.set(key, group);
288
+ }
289
+ const notices = [...gone.values()].map(({ from, entries }) => {
290
+ const history = entries.map((entry) => `- Sent ${new Date(entry.message.timestamp).toISOString()}: ${boundedBody(entry.bodyText)}`).join(`
291
+ `);
292
+ return `Intercom peer ${peerLabel(from)} is gone: it is no longer connected after the restart. ${entries.length} message(s) it sent before the restart were not replayed as new turns; they are shown here as history only. Do not reply to it or send it new messages; launch a fresh subagent if its work is still needed.
293
+ ${history}`;
294
+ });
295
+ for (const { from, count } of reconnecting.values()) {
296
+ notices.push(`Intercom peer ${peerLabel(from)} was relaunched after the restart but has not reconnected to Intercom yet, so ${count === 1 ? "1 interrupted delivery" : `${count} interrupted deliveries`} from it ${count === 1 ? "was" : "were"} deferred: not replayed now and not discarded. It is not gone; treat it as unreachable until it reconnects. The next resume of this session tries them again.`);
297
+ }
298
+ if (deferred.size > 0) {
299
+ const count = [...deferred.values()].reduce((total, sender) => total + sender.count, 0);
300
+ const senders = [...deferred.values()].map(({ from }) => peerLabel(from)).join(", ");
301
+ notices.push(`Intercom could not be reached after the restart, so ${count === 1 ? "1 interrupted Intercom delivery" : `${count} interrupted Intercom deliveries`} from ${senders} ${count === 1 ? "was" : "were"} deferred: not replayed now and not discarded. Whether their senders are still connected is unknown. The next resume of this session tries them again.`);
302
+ }
303
+ return { decisions, ...notices.length > 0 ? { notices } : {} };
304
+ }
305
+ var SUBAGENT_AWAIT_INTERCOM_PEER_EVENT = "subagent:await-intercom-peer", SUBAGENT_AWAIT_CHILD_RESTORATION_EVENT = "subagent:await-child-restoration", CHILD_RESTORATION_WAIT_MS = 20000, SUBAGENT_RESERVE_RESTORING_CHILD_EVENT = "subagent:reserve-restoring-child", SUBAGENT_RELEASE_RESTORING_CHILD_EVENT = "subagent:release-restoring-child", SUBAGENT_RESTORED_INTERCOM_PEERS_EVENT = "subagent:restored-intercom-peers", INTERCOM_RECOVERY_PEERS_EVENT = "intercom:recovery-peers", PEER_POLL_INTERVAL_MS = 200, RECOVERED_BODY_MAX_CHARS = 2000, LOCAL_RELAY_SENDERS;
306
+ var init_session_recovery = __esm(() => {
307
+ LOCAL_RELAY_SENDERS = new Set(["subagent-control", "subagent-result"]);
308
+ });
309
+
310
+ // dist/builtin/intercom/broker/client-message-validation.ts
311
+ function isAttachment(value) {
312
+ if (typeof value !== "object" || value === null)
313
+ return false;
314
+ const attachment = value;
315
+ if (attachment.type !== "file" && attachment.type !== "snippet" && attachment.type !== "context")
316
+ return false;
317
+ if (typeof attachment.name !== "string" || typeof attachment.content !== "string")
318
+ return false;
319
+ return attachment.language === undefined || typeof attachment.language === "string";
320
+ }
321
+ function isMessageSource(value) {
322
+ if (typeof value !== "object" || value === null || Array.isArray(value))
323
+ return false;
324
+ const source = value;
325
+ return typeof source.subagentRunId === "string" && (source.subagentAgent === undefined || typeof source.subagentAgent === "string") && (source.subagentIndex === undefined || typeof source.subagentIndex === "number");
326
+ }
327
+ function isMessage(value) {
328
+ if (typeof value !== "object" || value === null)
329
+ return false;
330
+ const message = value;
331
+ if (typeof message.id !== "string" || typeof message.timestamp !== "number")
332
+ return false;
333
+ if (message.replyTo !== undefined && typeof message.replyTo !== "string")
334
+ return false;
335
+ if (message.expectsReply !== undefined && typeof message.expectsReply !== "boolean")
336
+ return false;
337
+ if (message.replyError !== undefined && typeof message.replyError !== "string")
338
+ return false;
339
+ if (message.source !== undefined && !isMessageSource(message.source))
340
+ return false;
341
+ if (typeof message.content !== "object" || message.content === null)
342
+ return false;
343
+ const content = message.content;
344
+ if (typeof content.text !== "string")
345
+ return false;
346
+ return content.attachments === undefined || Array.isArray(content.attachments) && content.attachments.every(isAttachment);
347
+ }
348
+ function isSessionInfo(value) {
349
+ if (typeof value !== "object" || value === null)
350
+ return false;
351
+ const session = value;
352
+ if (typeof session.id !== "string" || typeof session.cwd !== "string" || typeof session.model !== "string" || typeof session.pid !== "number" || typeof session.startedAt !== "number" || typeof session.lastActivity !== "number")
353
+ return false;
354
+ if (session.name !== undefined && typeof session.name !== "string")
355
+ return false;
356
+ if (session.group !== undefined && typeof session.group !== "string")
357
+ return false;
358
+ return session.status === undefined || typeof session.status === "string";
359
+ }
360
+
361
+ // dist/builtin/intercom/durable-inbox.ts
362
+ function inboxRecord(entry) {
363
+ if (entry.type !== "custom" || entry.customType !== INTERCOM_INBOX_ENTRY)
364
+ return;
365
+ const data = entry.data;
366
+ if (!isMessage(data?.message) || !isSessionInfo(data.from) || typeof data.receivedAt !== "number")
367
+ return;
368
+ return {
369
+ message: data.message,
370
+ from: data.from,
371
+ receivedAt: data.receivedAt,
372
+ ...data.channel === "supervisor" ? { channel: "supervisor" } : {}
373
+ };
374
+ }
375
+ function consumedIntercomMessageIds(entries) {
376
+ const ids = new Set;
377
+ for (const entry of entries) {
378
+ if (entry.type !== "custom_message" || entry.customType !== "intercom_message")
379
+ continue;
380
+ const id = entry.details?.message?.id;
381
+ if (typeof id === "string")
382
+ ids.add(id);
383
+ }
384
+ return ids;
385
+ }
386
+ function handledIntercomMessageIds(entries) {
387
+ const ids = new Set;
388
+ for (const entry of entries) {
389
+ if (entry.type !== "custom")
390
+ continue;
391
+ if (entry.customType !== "intercom_received" && entry.customType !== INTERCOM_INBOX_HANDLED_ENTRY)
392
+ continue;
393
+ const id = entry.data?.messageId;
394
+ if (typeof id === "string")
395
+ ids.add(id);
396
+ }
397
+ return ids;
398
+ }
399
+ function savedIntercomMessageIds(entries) {
400
+ const ids = new Set;
401
+ for (const entry of entries) {
402
+ const record = inboxRecord(entry);
403
+ if (record !== undefined)
404
+ ids.add(record.message.id);
405
+ }
406
+ return ids;
407
+ }
408
+ function unconsumedIntercomInbox(entries) {
409
+ const branch = [...entries];
410
+ const consumed = consumedIntercomMessageIds(branch);
411
+ for (const id of handledIntercomMessageIds(branch))
412
+ consumed.add(id);
413
+ const records = new Map;
414
+ for (const entry of branch) {
415
+ const record = inboxRecord(entry);
416
+ if (record === undefined || consumed.has(record.message.id) || records.has(record.message.id))
417
+ continue;
418
+ records.set(record.message.id, record);
419
+ }
420
+ return [...records.values()].sort((left, right) => left.receivedAt - right.receivedAt);
421
+ }
422
+
423
+ class DurableInbox {
424
+ options;
425
+ saved = new Set;
426
+ tail = Promise.resolve();
427
+ constructor(options) {
428
+ this.options = options;
429
+ }
430
+ receive(from, message, channel, acknowledge) {
431
+ const arrival = this.tail.then(() => this.save(from, message, channel, acknowledge));
432
+ this.tail = arrival.then(() => {}, () => {});
433
+ return arrival;
434
+ }
435
+ async handledWithoutCard(messageId) {
436
+ if (!this.options.durable())
437
+ return;
438
+ if (!this.saved.has(messageId) && !savedIntercomMessageIds(this.options.entries()).has(messageId))
439
+ return;
440
+ try {
441
+ await this.options.appendHandled(messageId);
442
+ } catch {}
443
+ }
444
+ async save(from, message, channel, acknowledge) {
445
+ const confirm = () => {
446
+ try {
447
+ acknowledge();
448
+ } catch {}
449
+ };
450
+ if (!this.options.durable()) {
451
+ confirm();
452
+ return "fresh";
453
+ }
454
+ if (this.saved.has(message.id) || savedIntercomMessageIds(this.options.entries()).has(message.id)) {
455
+ this.saved.add(message.id);
456
+ confirm();
457
+ return "redelivered";
458
+ }
459
+ try {
460
+ await this.options.append({
461
+ message,
462
+ from,
463
+ receivedAt: this.options.now?.() ?? Date.now(),
464
+ ...channel === undefined ? {} : { channel }
465
+ });
466
+ } catch {
467
+ return "unsaved";
468
+ }
469
+ this.saved.add(message.id);
470
+ confirm();
471
+ return "fresh";
472
+ }
473
+ }
474
+ var INTERCOM_INBOX_ENTRY = "intercom_inbox", INTERCOM_INBOX_HANDLED_ENTRY = "intercom_inbox_handled", INTERCOM_INBOX_REPLAY_EVENT = "intercom:inbox-replay";
475
+ var init_durable_inbox = () => {};
476
+
185
477
  // dist/builtin/intercom/subagent-reply-capability.ts
186
478
  function registerSubagentReplyCapability(pi, client) {
187
479
  let signal;
@@ -213,6 +505,20 @@ function registerSubagentReplyCapability(pi, client) {
213
505
  return capability;
214
506
  }
215
507
 
508
+ // dist/builtin/intercom/session-identity.ts
509
+ function readIntercomSessionIdentity(entries, sessionId) {
510
+ for (let index = entries.length - 1;index >= 0; index -= 1) {
511
+ const entry = entries[index];
512
+ if (entry?.type !== "custom" || entry.customType !== INTERCOM_SESSION_IDENTITY_ENTRY)
513
+ continue;
514
+ const data = entry.data;
515
+ if (data?.sessionId === sessionId && typeof data.intercomSessionId === "string" && data.intercomSessionId)
516
+ return data.intercomSessionId;
517
+ }
518
+ return;
519
+ }
520
+ var INTERCOM_SESSION_IDENTITY_ENTRY = "intercom_session_identity";
521
+
216
522
  // dist/builtin/intercom/broker/framing.ts
217
523
  function writeMessage(socket, msg, callback) {
218
524
  const json = JSON.stringify(msg);
@@ -308,6 +614,7 @@ function getBrokerSocketPath(platform = process.platform, agentDir = getAgentDir
308
614
  }
309
615
  return join(getIntercomDirPath(agentDir), "broker.sock");
310
616
  }
617
+ var BROKER_STORAGE_ENV = "ATOMIC_STORAGE";
311
618
  var init_paths = () => {};
312
619
 
313
620
  // dist/builtin/intercom/broker/send-signature.ts
@@ -415,6 +722,17 @@ class PendingSendRegistry {
415
722
  attempt.resolve(result);
416
723
  return true;
417
724
  }
725
+ extend(messageId, attemptId, timeoutMs) {
726
+ const attempt = this.attempts.get(messageId);
727
+ if (!attempt || (attemptId === undefined ? !attempt.legacyEligible : attempt.attemptId !== attemptId))
728
+ return false;
729
+ if (attempt.timer)
730
+ clearTimeout(attempt.timer);
731
+ attempt.timer = setTimeout(() => {
732
+ this.reject(attempt, new Error("Send timeout"));
733
+ }, timeoutMs);
734
+ return true;
735
+ }
418
736
  resolveLegacy(messageId, result) {
419
737
  const attempt = this.attempts.get(messageId);
420
738
  if (!attempt?.legacyEligible)
@@ -454,57 +772,6 @@ function readSubagentMessageSource(policy) {
454
772
  };
455
773
  }
456
774
 
457
- // dist/builtin/intercom/broker/client-message-validation.ts
458
- function isAttachment(value) {
459
- if (typeof value !== "object" || value === null)
460
- return false;
461
- const attachment = value;
462
- if (attachment.type !== "file" && attachment.type !== "snippet" && attachment.type !== "context")
463
- return false;
464
- if (typeof attachment.name !== "string" || typeof attachment.content !== "string")
465
- return false;
466
- return attachment.language === undefined || typeof attachment.language === "string";
467
- }
468
- function isMessageSource(value) {
469
- if (typeof value !== "object" || value === null || Array.isArray(value))
470
- return false;
471
- const source = value;
472
- return typeof source.subagentRunId === "string" && (source.subagentAgent === undefined || typeof source.subagentAgent === "string") && (source.subagentIndex === undefined || typeof source.subagentIndex === "number");
473
- }
474
- function isMessage(value) {
475
- if (typeof value !== "object" || value === null)
476
- return false;
477
- const message = value;
478
- if (typeof message.id !== "string" || typeof message.timestamp !== "number")
479
- return false;
480
- if (message.replyTo !== undefined && typeof message.replyTo !== "string")
481
- return false;
482
- if (message.expectsReply !== undefined && typeof message.expectsReply !== "boolean")
483
- return false;
484
- if (message.replyError !== undefined && typeof message.replyError !== "string")
485
- return false;
486
- if (message.source !== undefined && !isMessageSource(message.source))
487
- return false;
488
- if (typeof message.content !== "object" || message.content === null)
489
- return false;
490
- const content = message.content;
491
- if (typeof content.text !== "string")
492
- return false;
493
- return content.attachments === undefined || Array.isArray(content.attachments) && content.attachments.every(isAttachment);
494
- }
495
- function isSessionInfo(value) {
496
- if (typeof value !== "object" || value === null)
497
- return false;
498
- const session = value;
499
- if (typeof session.id !== "string" || typeof session.cwd !== "string" || typeof session.model !== "string" || typeof session.pid !== "number" || typeof session.startedAt !== "number" || typeof session.lastActivity !== "number")
500
- return false;
501
- if (session.name !== undefined && typeof session.name !== "string")
502
- return false;
503
- if (session.group !== undefined && typeof session.group !== "string")
504
- return false;
505
- return session.status === undefined || typeof session.status === "string";
506
- }
507
-
508
775
  // dist/builtin/intercom/group.ts
509
776
  function intercomGroupFromEnv() {
510
777
  return process.env.ATOMIC_INTERCOM_GROUP ?? process.env.PI_INTERCOM_GROUP;
@@ -571,16 +838,20 @@ function isWorkflowFutureStageRosterEntries(value) {
571
838
  function isWorkflowStageRosterEntries(value) {
572
839
  return Array.isArray(value) && value.every((entry) => typeof entry === "object" && entry !== null && entry.kind === "workflow-stage" && typeof entry.runId === "string" && typeof entry.stageId === "string" && typeof entry.stageName === "string" && typeof entry.target === "string" && (entry.lifecycle === "pending" || entry.lifecycle === "running") && typeof entry.group === "string" && (entry.sessionId === undefined || typeof entry.sessionId === "string"));
573
840
  }
574
- var BROKER_SOCKET, GROUP_REQUEST_TIMEOUT_MS = 5000, PRESENCE_ACK_TIMEOUT_MS = 5000, IntercomClient;
841
+ var BROKER_SOCKET, GROUP_REQUEST_TIMEOUT_MS = 5000, PRESENCE_ACK_TIMEOUT_MS = 5000, RESTORING_RECIPIENT_REQUEST_TIMEOUT_MS = 5000, HELD_SEND_GRACE_MS = 5000, IntercomClient;
575
842
  var init_client = __esm(() => {
576
843
  init_paths();
577
844
  init_pending_send_registry();
578
845
  init_group();
579
846
  init_recoverable_disconnect();
580
847
  init_live_route_refusal();
848
+ init_retry_policy();
581
849
  BROKER_SOCKET = getBrokerSocketPath();
582
850
  IntercomClient = class IntercomClient extends EventEmitter {
583
851
  returnAddress;
852
+ preferredSessionId;
853
+ acknowledgesReceipt;
854
+ brokerAcknowledgesReceipt = false;
584
855
  socket = null;
585
856
  _sessionId = null;
586
857
  _supervisorSessionId = null;
@@ -594,13 +865,16 @@ var init_client = __esm(() => {
594
865
  _groups = normalizeGroups();
595
866
  pendingLiveWorkflowStageRoutes = new Map;
596
867
  pendingSupervisorAuthorizations = new Map;
868
+ pendingRestoringRecipientRequests = new Map;
597
869
  disconnecting = false;
598
870
  disconnectError = null;
599
- constructor(returnAddress = randomUUID2()) {
871
+ constructor(returnAddress = randomUUID2(), options = {}) {
600
872
  super();
601
873
  if (returnAddress.length === 0)
602
874
  throw new Error("Intercom return address must not be empty");
603
875
  this.returnAddress = returnAddress;
876
+ this.preferredSessionId = options.preferredSessionId;
877
+ this.acknowledgesReceipt = options.acknowledgesReceipt === true;
604
878
  }
605
879
  failPending(error) {
606
880
  this.pendingSends.rejectAll(error);
@@ -610,6 +884,8 @@ var init_client = __esm(() => {
610
884
  pending.reject(error);
611
885
  for (const pending of this.pendingSupervisorAuthorizations.values())
612
886
  pending.reject(error);
887
+ for (const pending of this.pendingRestoringRecipientRequests.values())
888
+ pending.reject(error);
613
889
  for (const pending of this.pendingPresence.values())
614
890
  pending.reject(error);
615
891
  for (const pending of this.pendingMemberships.values())
@@ -619,6 +895,7 @@ var init_client = __esm(() => {
619
895
  this.pendingLists.clear();
620
896
  this.pendingGroupLists.clear();
621
897
  this.pendingSupervisorAuthorizations.clear();
898
+ this.pendingRestoringRecipientRequests.clear();
622
899
  this.pendingPresence.clear();
623
900
  this.pendingMemberships.clear();
624
901
  this.pendingLiveWorkflowStageRoutes.clear();
@@ -702,6 +979,7 @@ var init_client = __esm(() => {
702
979
  }
703
980
  this._sessionId = null;
704
981
  this._supervisorSessionId = null;
982
+ this.brokerAcknowledgesReceipt = false;
705
983
  this._messageSource = undefined;
706
984
  this.disconnectError = null;
707
985
  if (connectionEstablished && !wasDisconnecting) {
@@ -753,6 +1031,8 @@ var init_client = __esm(() => {
753
1031
  session,
754
1032
  ...registrationGroup !== undefined ? { registrationGroup } : {},
755
1033
  returnAddress: this.returnAddress,
1034
+ ...this.preferredSessionId === undefined ? {} : { preferredSessionId: this.preferredSessionId },
1035
+ ...this.acknowledgesReceipt ? { acknowledgesReceipt: true } : {},
756
1036
  ...supervisor ? { supervisor } : {},
757
1037
  ...supervisorOwnerToken ? { supervisorOwnerToken } : {}
758
1038
  });
@@ -777,7 +1057,7 @@ var init_client = __esm(() => {
777
1057
  }
778
1058
  switch (brokerMessage.type) {
779
1059
  case "registered": {
780
- if (typeof brokerMessage.sessionId !== "string" || brokerMessage.supervisorSessionId !== undefined && typeof brokerMessage.supervisorSessionId !== "string") {
1060
+ if (typeof brokerMessage.sessionId !== "string" || brokerMessage.supervisorSessionId !== undefined && typeof brokerMessage.supervisorSessionId !== "string" || brokerMessage.acknowledgesReceipt !== undefined && brokerMessage.acknowledgesReceipt !== true) {
781
1061
  throw new Error("Invalid registered message");
782
1062
  }
783
1063
  if (this._sessionId !== null) {
@@ -785,6 +1065,7 @@ var init_client = __esm(() => {
785
1065
  }
786
1066
  this._sessionId = brokerMessage.sessionId;
787
1067
  this._supervisorSessionId = typeof brokerMessage.supervisorSessionId === "string" ? brokerMessage.supervisorSessionId : null;
1068
+ this.brokerAcknowledgesReceipt = this.acknowledgesReceipt && brokerMessage.acknowledgesReceipt === true;
788
1069
  this.emit("_registered", { type: "registered", sessionId: brokerMessage.sessionId });
789
1070
  break;
790
1071
  }
@@ -901,6 +1182,13 @@ var init_client = __esm(() => {
901
1182
  });
902
1183
  break;
903
1184
  }
1185
+ case "pending_stage_route_revoked": {
1186
+ const { runId } = brokerMessage;
1187
+ if (typeof runId !== "string")
1188
+ throw new Error("Invalid pending-stage route revocation");
1189
+ this.emit("pending_stage_route_revoked", { runId });
1190
+ break;
1191
+ }
904
1192
  case "live_workflow_stage_route_registered": {
905
1193
  const { requestId } = brokerMessage;
906
1194
  if (typeof requestId !== "string")
@@ -931,6 +1219,29 @@ var init_client = __esm(() => {
931
1219
  this.pendingSends.resolve(messageId, attemptId, result);
932
1220
  break;
933
1221
  }
1222
+ case "send_held": {
1223
+ const { messageId, attemptId, timeoutMs } = brokerMessage;
1224
+ if (typeof messageId !== "string" || attemptId !== undefined && typeof attemptId !== "string" || typeof timeoutMs !== "number" || !Number.isFinite(timeoutMs) || timeoutMs <= 0) {
1225
+ throw new Error("Invalid send_held message");
1226
+ }
1227
+ this.pendingSends.extend(messageId, attemptId, timeoutMs + HELD_SEND_GRACE_MS);
1228
+ break;
1229
+ }
1230
+ case "restoring_recipient_ack": {
1231
+ const { requestId, error } = brokerMessage;
1232
+ if (typeof requestId !== "string" || error !== undefined && typeof error !== "string") {
1233
+ throw new Error("Invalid restoring_recipient_ack message");
1234
+ }
1235
+ const pending = this.pendingRestoringRecipientRequests.get(requestId);
1236
+ if (!pending)
1237
+ return;
1238
+ this.pendingRestoringRecipientRequests.delete(requestId);
1239
+ if (error === undefined)
1240
+ pending.resolve();
1241
+ else
1242
+ pending.reject(new Error(error));
1243
+ break;
1244
+ }
934
1245
  case "delivered": {
935
1246
  const { messageId, attemptId } = brokerMessage;
936
1247
  if (typeof messageId !== "string" || attemptId !== undefined && typeof attemptId !== "string") {
@@ -1228,7 +1539,58 @@ var init_client = __esm(() => {
1228
1539
  }
1229
1540
  });
1230
1541
  }
1231
- registerPendingStageRoute(runId, group, capability, stages, possibleStages, parent) {
1542
+ reserveRestoringRecipient(capability, options = {}) {
1543
+ return this.restoringRecipientRequest({
1544
+ type: "reserve_restoring_recipient",
1545
+ capability,
1546
+ ...options.group === undefined ? {} : { group: options.group },
1547
+ ...options.aliases === undefined ? {} : { aliases: [...options.aliases] },
1548
+ ...options.dormant === true ? { dormant: true } : {}
1549
+ });
1550
+ }
1551
+ releaseRestoringRecipient(capability, outcome) {
1552
+ const { gone, refusal } = typeof outcome === "string" ? { gone: outcome, refusal: undefined } : outcome ?? {};
1553
+ return this.restoringRecipientRequest({
1554
+ type: "release_restoring_recipient",
1555
+ capability,
1556
+ ...gone === undefined ? {} : { gone },
1557
+ ...refusal === undefined ? {} : { refusal }
1558
+ });
1559
+ }
1560
+ restoringRecipientRequest(frame) {
1561
+ let socket;
1562
+ try {
1563
+ socket = this.requireActiveSocket();
1564
+ } catch (error) {
1565
+ return Promise.reject(toError(error));
1566
+ }
1567
+ const requestId = randomUUID2();
1568
+ return new Promise((resolve, reject) => {
1569
+ const timeout = setTimeout(() => {
1570
+ if (!this.pendingRestoringRecipientRequests.delete(requestId))
1571
+ return;
1572
+ reject(new Error("Restoring-recipient request timeout"));
1573
+ }, RESTORING_RECIPIENT_REQUEST_TIMEOUT_MS);
1574
+ this.pendingRestoringRecipientRequests.set(requestId, {
1575
+ resolve: () => {
1576
+ clearTimeout(timeout);
1577
+ resolve();
1578
+ },
1579
+ reject: (error) => {
1580
+ clearTimeout(timeout);
1581
+ reject(error);
1582
+ }
1583
+ });
1584
+ try {
1585
+ writeMessage(socket, { ...frame, requestId });
1586
+ } catch (error) {
1587
+ clearTimeout(timeout);
1588
+ this.pendingRestoringRecipientRequests.delete(requestId);
1589
+ reject(toError(error));
1590
+ }
1591
+ });
1592
+ }
1593
+ registerPendingStageRoute(runId, group, capability, stages, possibleStages, parent, dormant) {
1232
1594
  writeMessage(this.requireActiveSocket(), {
1233
1595
  type: "register_pending_stage_route",
1234
1596
  runId,
@@ -1236,7 +1598,8 @@ var init_client = __esm(() => {
1236
1598
  capability,
1237
1599
  stages,
1238
1600
  possibleStages,
1239
- ...parent === undefined ? {} : { parent }
1601
+ ...parent === undefined ? {} : { parent },
1602
+ ...dormant === true ? { dormant: true } : {}
1240
1603
  });
1241
1604
  }
1242
1605
  registerLiveWorkflowStageRoute(runId, stageKeys, capability) {
@@ -1286,6 +1649,11 @@ var init_client = __esm(() => {
1286
1649
  send(to, options) {
1287
1650
  return this.sendFrame("send", to, options);
1288
1651
  }
1652
+ acknowledgeReceived(messageId) {
1653
+ if (!this.brokerAcknowledgesReceipt)
1654
+ return;
1655
+ writeMessage(this.requireActiveSocket(), { type: "received", messageId });
1656
+ }
1289
1657
  sendPendingStageNotification(runId, capability, to, senderRegistrationName, options, senderReturnAddress) {
1290
1658
  return this.sendFrame("send_pending_stage_notification", to, options, {
1291
1659
  runId,
@@ -1313,7 +1681,7 @@ var init_client = __esm(() => {
1313
1681
  requirePendingReply: options.requirePendingReply ?? false,
1314
1682
  ...options.expectedRecipientId === undefined ? {} : { expectedRecipientId: options.expectedRecipientId }
1315
1683
  });
1316
- acquired = this.pendingSends.acquire(messageId, pendingSignature, 1e4);
1684
+ acquired = this.pendingSends.acquire(messageId, pendingSignature, SEND_RESPONSE_TIMEOUT_MS);
1317
1685
  } catch (error) {
1318
1686
  return Promise.reject(toError(error));
1319
1687
  }
@@ -1339,6 +1707,7 @@ var init_client = __esm(() => {
1339
1707
  ...options.requirePendingReply === undefined ? {} : { requirePendingReply: options.requirePendingReply },
1340
1708
  ...options.expectedRecipientId === undefined ? {} : { expectedRecipientId: options.expectedRecipientId },
1341
1709
  ...options.onReplyTarget === undefined ? {} : { resolveReplyTarget: true },
1710
+ ...type === "send" ? { awaitRestoringRecipient: true } : {},
1342
1711
  message,
1343
1712
  attemptId: acquired.attempt.attemptId,
1344
1713
  ...extra
@@ -1443,7 +1812,7 @@ import { appendFileSync, chmodSync, closeSync, existsSync, mkdirSync, openSync,
1443
1812
  import { join as join2, dirname } from "path";
1444
1813
  import { fileURLToPath } from "url";
1445
1814
  import { createRequire } from "module";
1446
- import { createChildProcessEnvironment, isBunBinary } from "@bastani/atomic";
1815
+ import { createChildProcessEnvironment, isBunBinary, processSharedStorageSelection } from "@bastani/atomic";
1447
1816
  function isIntercomPackageRoot(dir) {
1448
1817
  return existsSync(join2(dir, "package.json")) && existsSync(join2(dir, "broker"));
1449
1818
  }
@@ -1557,11 +1926,15 @@ function getBrokerLaunchSpec(brokerPath, brokerCommand, brokerArgs, extensionDir
1557
1926
  };
1558
1927
  }
1559
1928
  function getBrokerSpawnOptions(extensionDir = EXTENSION_DIR, stderr = "ignore") {
1929
+ const storage = processSharedStorageSelection();
1560
1930
  return {
1561
1931
  detached: true,
1562
1932
  stdio: ["ignore", "ignore", stderr],
1563
1933
  cwd: extensionDir,
1564
- env: createChildProcessEnvironment({ NODE_NO_WARNINGS: "1" }),
1934
+ env: createChildProcessEnvironment({
1935
+ NODE_NO_WARNINGS: "1",
1936
+ ...storage === undefined ? {} : { [BROKER_STORAGE_ENV]: storage }
1937
+ }),
1565
1938
  windowsHide: true
1566
1939
  };
1567
1940
  }
@@ -2081,6 +2454,9 @@ function sessionTargetFailureReason(target, resolution) {
2081
2454
  if (resolution.kind === "ambiguous_id_prefix") {
2082
2455
  return `Session ID prefix "${target}" is ambiguous; matches: ${resolution.matches.map((session) => `${session.name ?? "unnamed"} (${session.id})`).join(", ")}. Use the full UUID.`;
2083
2456
  }
2457
+ if (resolution.kind === "ambiguous_session_id") {
2458
+ return `Session ID "${target}" is registered by more than one Intercom session: ${resolution.matches.map((session) => `${session.name ?? "unnamed"} (${session.id})`).join(", ")}. Use the Intercom session ID shown by intercom list.`;
2459
+ }
2084
2460
  return "Session not found";
2085
2461
  }
2086
2462
  async function resolveSessionTargetId(client, nameOrId) {
@@ -2268,6 +2644,12 @@ var init_parent_ask_handoff = __esm(() => {
2268
2644
  });
2269
2645
 
2270
2646
  // dist/builtin/intercom/intercom-utils.ts
2647
+ function mayStartTurn(entry) {
2648
+ return entry.historyOnly !== true;
2649
+ }
2650
+ function maySupplyReplyContext(entry) {
2651
+ return entry.historyOnly !== true;
2652
+ }
2271
2653
  function getErrorMessage(error) {
2272
2654
  return error instanceof Error ? error.message : String(error);
2273
2655
  }
@@ -3698,6 +4080,16 @@ ${message}${attachmentText}`);
3698
4080
  replyTo,
3699
4081
  expectsReply: false
3700
4082
  }, retryToken);
4083
+ const goneChild = await awaitSubagentChildRestoration(pi.events, toolSessionId, to);
4084
+ if (goneChild !== undefined) {
4085
+ retryIdentities.release(retryIdentity);
4086
+ retryIdentity = undefined;
4087
+ return {
4088
+ content: [{ type: "text", text: goneChild }],
4089
+ isError: true,
4090
+ details: { error: true, delivered: false, reason: goneChild }
4091
+ };
4092
+ }
3701
4093
  const sendTo = await resolveTarget(connectedClient, to) ?? to;
3702
4094
  if (_signal?.aborted) {
3703
4095
  const retained = retainInconclusiveRetry(retryIdentities, retryIdentity);
@@ -3861,7 +4253,18 @@ ${message}${attachmentText}`);
3861
4253
  details: { yielded: true }
3862
4254
  };
3863
4255
  }
3864
- const sendTo = await resolveTarget(connectedClient, to) ?? to;
4256
+ const goneChild = await awaitSubagentChildRestoration(pi.events, toolSessionId, to);
4257
+ if (goneChild !== undefined) {
4258
+ retryIdentities.release(retryIdentity);
4259
+ retryIdentity = undefined;
4260
+ return {
4261
+ content: [{ type: "text", text: goneChild }],
4262
+ isError: true,
4263
+ details: { error: true, delivered: false, reason: goneChild }
4264
+ };
4265
+ }
4266
+ const listedTarget = await resolveTarget(connectedClient, to);
4267
+ const sendTo = listedTarget ?? to;
3865
4268
  if (_signal?.aborted) {
3866
4269
  const retained = retryIdentity === undefined ? undefined : retainInconclusiveRetry(retryIdentities, retryIdentity);
3867
4270
  retryIdentity = undefined;
@@ -3946,7 +4349,7 @@ ${message}${attachmentText}`);
3946
4349
  attachments,
3947
4350
  replyTo,
3948
4351
  expectsReply: true,
3949
- ...parseWorkflowStageTarget(to)?.kind === "path" ? { onReplyTarget: wait.bindSender } : {}
4352
+ onReplyTarget: wait.bindSender
3950
4353
  });
3951
4354
  if (sendResult.queued === true) {
3952
4355
  retryIdentities.release(retryIdentity);
@@ -4308,6 +4711,7 @@ var init_intercom_tool = __esm(() => {
4308
4711
  init_parent_ask_handoff();
4309
4712
  init_result_renderers();
4310
4713
  init_intercom_utils();
4714
+ init_session_recovery();
4311
4715
  init_session_target();
4312
4716
  init_group();
4313
4717
  init_workflow_stage_target();
@@ -5919,11 +6323,12 @@ function routePeerDisconnect(waiters, notice) {
5919
6323
 
5920
6324
  // dist/builtin/intercom/incoming-message-delivery.ts
5921
6325
  function createIncomingMessageSender(input) {
5922
- return (entry, delivery, generation = input.currentGeneration(), trackReplyContext = true, turnContext, stageAdmissionBarrier) => {
6326
+ return (entry, requested, generation = input.currentGeneration(), trackReplyContext = true, turnContext, stageAdmissionBarrier) => {
5923
6327
  if (!input.canDeliver(generation)) {
5924
6328
  return Promise.reject(new Error("Intercom session retired before inbound delivery"));
5925
6329
  }
5926
- if ((delivery === "trigger" || delivery === "interrupt") && trackReplyContext) {
6330
+ const delivery = (requested === "trigger" || requested === "interrupt") && !mayStartTurn(entry) ? "prelude" : requested;
6331
+ if ((delivery === "trigger" || delivery === "interrupt") && trackReplyContext && maySupplyReplyContext(entry)) {
5927
6332
  input.queueTurnContext(turnContext ?? { from: entry.from, message: entry.message, receivedAt: Date.now() });
5928
6333
  }
5929
6334
  const baseOptions = {
@@ -5991,16 +6396,39 @@ ${entry.bodyText}`,
5991
6396
  details: entry
5992
6397
  };
5993
6398
  }
6399
+ var init_incoming_message_delivery = __esm(() => {
6400
+ init_intercom_utils();
6401
+ });
5994
6402
 
5995
6403
  // dist/builtin/intercom/inbound-idle-queue.ts
6404
+ function planIdleBatch(entries) {
6405
+ const starter = entries.findIndex(mayStartTurn);
6406
+ return {
6407
+ triggerTurn: starter >= 0,
6408
+ replyContext: starter >= 0 ? entries.find(maySupplyReplyContext) : undefined,
6409
+ sendOptions: entries.map((_, index) => starter < 0 || index < starter ? { triggerTurn: false } : index === starter ? { triggerTurn: true } : { deliverAs: "followUp" })
6410
+ };
6411
+ }
6412
+
5996
6413
  class InboundIdleQueue {
6414
+ consumedIds;
5997
6415
  entries = [];
5998
6416
  generation = 0;
6417
+ constructor(consumedIds = () => NONE_CONSUMED) {
6418
+ this.consumedIds = consumedIds;
6419
+ }
6420
+ dropConsumed() {
6421
+ const consumed = this.consumedIds();
6422
+ this.entries = this.entries.filter((entry) => !consumed.has(entry.message.id));
6423
+ }
5999
6424
  get size() {
6000
6425
  return this.entries.length;
6001
6426
  }
6002
6427
  enqueue(entry) {
6428
+ if (this.consumedIds().has(entry.message.id) || this.entries.some((queued) => queued.message.id === entry.message.id))
6429
+ return false;
6003
6430
  this.entries.push(entry);
6431
+ return true;
6004
6432
  }
6005
6433
  has(entry) {
6006
6434
  return this.entries.includes(entry);
@@ -6010,14 +6438,16 @@ class InboundIdleQueue {
6010
6438
  if (index < 0)
6011
6439
  return false;
6012
6440
  this.entries.splice(index, 1);
6013
- return true;
6441
+ return !this.consumedIds().has(entry.message.id);
6014
6442
  }
6015
6443
  drain() {
6444
+ this.dropConsumed();
6016
6445
  const entries = this.entries;
6017
6446
  this.entries = [];
6018
6447
  return entries;
6019
6448
  }
6020
6449
  claimOrdinarySourceTargets(runId, sourceSessionTargets, terminalAt = Number.POSITIVE_INFINITY) {
6450
+ this.dropConsumed();
6021
6451
  const targets = new Set(sourceSessionTargets);
6022
6452
  const generation = this.generation;
6023
6453
  const original = this.entries;
@@ -6065,6 +6495,11 @@ class InboundIdleQueue {
6065
6495
  this.entries = [];
6066
6496
  }
6067
6497
  }
6498
+ var NONE_CONSUMED;
6499
+ var init_inbound_idle_queue = __esm(() => {
6500
+ init_intercom_utils();
6501
+ NONE_CONSUMED = new Set;
6502
+ });
6068
6503
 
6069
6504
  // dist/builtin/intercom/inbound-message-admission.ts
6070
6505
  class InboundMessageAdmission {
@@ -6175,6 +6610,10 @@ function registerLateStageMessageRouter(pi, admission, getReplyTracker, getOwner
6175
6610
  const entry = message.details;
6176
6611
  if (!entry?.from || !entry.message)
6177
6612
  continue;
6613
+ if (!maySupplyReplyContext(entry)) {
6614
+ accepted.push(message);
6615
+ continue;
6616
+ }
6178
6617
  if (entry.channel !== "supervisor" && !isSubagentRelayHandoff(entry) && normalizeGroup(entry.from.group) !== normalizeGroup(getOwnerGroup()))
6179
6618
  continue;
6180
6619
  const result = admission.admit(entry.from, entry.message);
@@ -6193,11 +6632,18 @@ function registerLateStageMessageRouter(pi, admission, getReplyTracker, getOwner
6193
6632
  accepted.push(message);
6194
6633
  }
6195
6634
  event.handled = true;
6196
- const ownedCompletion = event.batch && typeof pi.sendMessages === "function" ? deliverAtomicBatch(pi, accepted, event, reservations, admission, tracker) : deliverSequentially(pi, accepted, event, reservations, admission, tracker);
6635
+ const delivery = accepted.some((message) => !isHistoryCard(message)) || event.options?.triggerTurn !== true ? event : { ...event, options: { ...event.options, triggerTurn: false } };
6636
+ const ownedCompletion = event.batch && typeof pi.sendMessages === "function" ? deliverAtomicBatch(pi, accepted, delivery, reservations, admission, tracker) : deliverSequentially(pi, accepted, delivery, reservations, admission, tracker);
6197
6637
  event.completion = Promise.all([ownedCompletion, ...joined]).then(() => {});
6198
6638
  return event.completion;
6199
6639
  });
6200
6640
  }
6641
+ function isHistoryCard(message) {
6642
+ if (message.customType !== "intercom_message")
6643
+ return false;
6644
+ const entry = message.details;
6645
+ return entry !== undefined && !mayStartTurn(entry);
6646
+ }
6201
6647
  function isCompletedStageAskRoute(event) {
6202
6648
  return typeof event.workflowRunId === "string" && typeof event.workflowStageId === "string" && event.messages?.length !== 0 && event.messages?.every((message) => {
6203
6649
  if (message.customType !== "intercom_message")
@@ -6229,13 +6675,14 @@ function deliverAtomicBatch(pi, accepted, event, reservations, admission, tracke
6229
6675
  }
6230
6676
  async function deliverSequentially(pi, accepted, event, reservations, admission, tracker) {
6231
6677
  const pending = new Map(reservations.map((owned) => [owned.message, owned]));
6678
+ const starter = accepted.findIndex((message) => !isHistoryCard(message));
6232
6679
  for (let index = 0;index < accepted.length; index += 1) {
6233
6680
  const message = accepted[index];
6234
6681
  const owned = pending.get(message);
6235
6682
  if (owned)
6236
6683
  admission.beginDelivery(owned.reservation);
6237
6684
  try {
6238
- await pi.sendMessage(message, index === 0 ? event.options : { deliverAs: "followUp" });
6685
+ await pi.sendMessage(message, index === starter ? event.options : starter < 0 || index < starter ? { ...event.options, triggerTurn: false } : { deliverAs: "followUp" });
6239
6686
  } catch (error) {
6240
6687
  if (owned)
6241
6688
  admission.endDelivery(owned.reservation);
@@ -6258,6 +6705,7 @@ function releaseReservations(reservations, admission, tracker, error) {
6258
6705
  }
6259
6706
  var LATE_STAGE_MESSAGE_EVENT = "atomic:workflow-stage-late-message";
6260
6707
  var init_late_stage_message_router = __esm(() => {
6708
+ init_intercom_utils();
6261
6709
  init_group();
6262
6710
  });
6263
6711
 
@@ -6406,10 +6854,12 @@ async function settleOpenStageDeliveryFailure(input, error) {
6406
6854
  }
6407
6855
 
6408
6856
  // dist/builtin/intercom/closed-workflow-stage-message.ts
6409
- function routeClosedWorkflowStageMessage(entry, admission, tracker, waiter, deliver, currentClient, isCurrent, ownsSubagentRun) {
6857
+ function routeClosedWorkflowStageMessage(entry, admission, tracker, waiter, deliver, currentClient, isCurrent, ownsSubagentRun, handledWithoutCard = () => {}) {
6410
6858
  const sourceRunId = entry.message.source?.subagentRunId;
6411
- if (sourceRunId !== undefined && ownsSubagentRun(sourceRunId))
6859
+ if (sourceRunId !== undefined && ownsSubagentRun(sourceRunId)) {
6860
+ handledWithoutCard();
6412
6861
  return;
6862
+ }
6413
6863
  if (entry.message.expectsReply !== true && !isDeliveryFeedback(entry.message)) {
6414
6864
  retryStableDelivery({ deliver, isCurrent }).catch(() => {});
6415
6865
  return;
@@ -6438,6 +6888,7 @@ function routeClosedWorkflowStageMessage(entry, admission, tracker, waiter, deli
6438
6888
  const failure = error instanceof Error ? error : new Error(String(error));
6439
6889
  tracker.forgetIncomingMessage(replyContext);
6440
6890
  if (entry.message.expectsReply === true && await sendWorkflowStageDeliveryFailure(entry, failure, tracker, currentClient, isCurrent, "Completed workflow stage could not process intercom ask")) {
6891
+ handledWithoutCard();
6441
6892
  admission.commit(admitted.reservation);
6442
6893
  return;
6443
6894
  }
@@ -6451,7 +6902,9 @@ function invoke(deliver) {
6451
6902
  return Promise.reject(error);
6452
6903
  }
6453
6904
  }
6454
- var init_closed_workflow_stage_message = () => {};
6905
+ var init_closed_workflow_stage_message = __esm(() => {
6906
+ init_incoming_message_delivery();
6907
+ });
6455
6908
 
6456
6909
  // dist/builtin/intercom/runtime-group.ts
6457
6910
  import { runtimeIntercomGroupEnvKey } from "@bastani/atomic";
@@ -6731,7 +7184,26 @@ function piIntercomExtension(pi, testOverrides = {}) {
6731
7184
  let replyTracker = new ReplyTracker;
6732
7185
  const replyWaiters = new ReplyWaiterRegistry(DEFAULT_REPLY_TIMEOUT_MS, config.maxPendingAsks);
6733
7186
  const foregroundDetachHandoff = new ForegroundDetachHandoff(pi);
6734
- const pendingIdleMessages = new InboundIdleQueue;
7187
+ function sessionBranch() {
7188
+ try {
7189
+ return runtimeContext?.sessionManager.getBranch() ?? [];
7190
+ } catch {
7191
+ return [];
7192
+ }
7193
+ }
7194
+ const pendingIdleMessages = new InboundIdleQueue(() => consumedIntercomMessageIds(sessionBranch()));
7195
+ const durableInbox = new DurableInbox({
7196
+ durable: () => {
7197
+ try {
7198
+ return runtimeContext?.sessionManager.getSessionStore?.().descriptor.adapter !== "memory";
7199
+ } catch {
7200
+ return true;
7201
+ }
7202
+ },
7203
+ entries: sessionBranch,
7204
+ append: (record) => pi.appendEntry(INTERCOM_INBOX_ENTRY, record),
7205
+ appendHandled: (messageId) => pi.appendEntry(INTERCOM_INBOX_HANDLED_ENTRY, { messageId })
7206
+ });
6735
7207
  const inboundDeliveries = new InboundMessageAdmission;
6736
7208
  const pendingStageRoutes = new Map;
6737
7209
  const pendingStageRouteClients = new Map;
@@ -6912,16 +7384,79 @@ function piIntercomExtension(pi, testOverrides = {}) {
6912
7384
  return;
6913
7385
  }
6914
7386
  const entries = pendingIdleMessages.drain();
6915
- const first = entries[0];
6916
- if (first)
6917
- replyTracker.queueTurnContext({ from: first.from, message: first.message, receivedAt: Date.now() });
7387
+ const batch = planIdleBatch(entries);
7388
+ if (batch.replyContext)
7389
+ replyTracker.queueTurnContext({ from: batch.replyContext.from, message: batch.replyContext.message, receivedAt: Date.now() });
6918
7390
  const messages = entries.map(buildIncomingCustomMessage);
6919
7391
  retryStableDelivery({
6920
- deliver: () => typeof pi.sendMessages === "function" ? Promise.resolve(pi.sendMessages(messages, { triggerTurn: true })) : Promise.all(messages.map((message, index) => pi.sendMessage(message, index === 0 ? { triggerTurn: true } : { deliverAs: "followUp" }))).then(() => {}),
7392
+ deliver: () => typeof pi.sendMessages === "function" ? Promise.resolve(pi.sendMessages(messages, { triggerTurn: batch.triggerTurn })) : Promise.all(messages.map((message, index) => pi.sendMessage(message, batch.sendOptions[index]))).then(() => {}),
6921
7393
  isCurrent: () => Boolean(getLiveContext(ctx, generation))
6922
7394
  }).catch(() => {});
6923
7395
  }
6924
7396
  testOverrides.captureInboundHandler?.(handleIncomingMessage);
7397
+ function buildInboundEntry(from, message, channel) {
7398
+ const attachmentText = message.content.attachments?.length ? formatAttachments(message.content.attachments) : "";
7399
+ const bodyText = `${message.content.text}${attachmentText}`;
7400
+ const replyCommand = config.replyHint && message.expectsReply ? `intercom({ action: "reply", message: "..." })` : undefined;
7401
+ const rawEntry = { from, message, replyCommand, bodyText, ...channel ? { channel } : {} };
7402
+ return isDeliveryFeedback(message) ? frameDeliveryFeedback(rawEntry) : frameHistoricalSupervisorUpdate(rawEntry);
7403
+ }
7404
+ function receiveIncomingMessage(receiver, from, message, channel) {
7405
+ const generation = runtimeGeneration;
7406
+ durableInbox.receive(from, message, channel, () => receiver.acknowledgeReceived(message.id)).then((arrival) => {
7407
+ if (arrival !== "fresh")
7408
+ return;
7409
+ const liveContext = getLiveContext(runtimeContext, generation);
7410
+ if (liveContext)
7411
+ handleIncomingMessage(liveContext, from, message, channel);
7412
+ });
7413
+ }
7414
+ async function replayDurableInbox(request) {
7415
+ const liveContext = getLiveContext();
7416
+ if (!liveContext)
7417
+ return [];
7418
+ replyTracker = bindWorkflowReplyTracker(liveContext, replyTracker);
7419
+ const records = unconsumedIntercomInbox(sessionBranch()).map((record) => ({
7420
+ record,
7421
+ entry: buildInboundEntry(record.from, record.message, record.channel)
7422
+ }));
7423
+ const plan = planIntercomRecoveryReplay(records.map(({ record, entry }) => ({
7424
+ entryId: record.message.id,
7425
+ customType: "intercom_message",
7426
+ content: entry.bodyText,
7427
+ details: entry,
7428
+ timestamp: new Date(record.receivedAt).toISOString(),
7429
+ delivery: "followUp"
7430
+ })), request.peers, request.restored);
7431
+ const actions = new Map((plan.decisions ?? []).map((decision) => [decision.entryId, decision.action]));
7432
+ let queued = 0;
7433
+ for (const { record, entry } of records) {
7434
+ const action = actions.get(record.message.id) ?? "replay";
7435
+ if (action === "defer")
7436
+ continue;
7437
+ if (action === "drop") {
7438
+ const historyEntry = { ...entry, replyCommand: undefined, historyOnly: true };
7439
+ if (queued > 0) {
7440
+ pendingIdleMessages.enqueue(historyEntry);
7441
+ continue;
7442
+ }
7443
+ try {
7444
+ await pi.sendMessage(buildIncomingCustomMessage(historyEntry), { triggerTurn: false });
7445
+ } catch {}
7446
+ continue;
7447
+ }
7448
+ const admission = inboundDeliveries.admit(record.from, record.message);
7449
+ if (admission.kind !== "reserved")
7450
+ continue;
7451
+ replyTracker.recordIncomingMessage(record.from, record.message);
7452
+ if (pendingIdleMessages.enqueue(entry))
7453
+ queued += 1;
7454
+ inboundDeliveries.commit(admission.reservation);
7455
+ }
7456
+ if (queued > 0)
7457
+ scheduleInboundFlush();
7458
+ return plan.notices ?? [];
7459
+ }
6925
7460
  function handleIncomingMessage(ctx, from, message, channel, receivedBeforeStageStart = false) {
6926
7461
  const messageGeneration = runtimeGeneration;
6927
7462
  const liveContext = getLiveContext(ctx, messageGeneration);
@@ -6931,11 +7466,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
6931
7466
  return;
6932
7467
  }
6933
7468
  replyTracker = bindWorkflowReplyTracker(liveContext, replyTracker);
6934
- const attachmentText = message.content.attachments?.length ? formatAttachments(message.content.attachments) : "";
6935
- const bodyText = `${message.content.text}${attachmentText}`;
6936
- const replyCommand = config.replyHint && message.expectsReply ? `intercom({ action: "reply", message: "..." })` : undefined;
6937
- const rawEntry = { from, message, replyCommand, bodyText, ...channel ? { channel } : {} };
6938
- const framedEntry = isDeliveryFeedback(message) ? frameDeliveryFeedback(rawEntry) : frameHistoricalSupervisorUpdate(rawEntry);
7469
+ const framedEntry = buildInboundEntry(from, message, channel);
6939
7470
  const entry = receivedBeforeStageStart ? framePreStartPendingStageMessage(framedEntry) : framedEntry;
6940
7471
  if (receivedBeforeStageStart) {
6941
7472
  return sendIncomingMessage(entry, "prelude", messageGeneration, false);
@@ -6948,7 +7479,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
6948
7479
  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.");
6949
7480
  }
6950
7481
  return sendIncomingMessage(entry, isDeliveryFeedback(message) ? "prelude" : "trigger", messageGeneration, false);
6951
- }, () => client, () => Boolean(getLiveContext(liveContext, messageGeneration)), (runId) => stageAdmission.boundary.ownsSubagentRun(runId));
7482
+ }, () => client, () => Boolean(getLiveContext(liveContext, messageGeneration)), (runId) => stageAdmission.boundary.ownsSubagentRun(runId), () => durableInbox.handledWithoutCard(message.id));
6952
7483
  return;
6953
7484
  }
6954
7485
  const admission = inboundDeliveries.admit(from, message);
@@ -6976,7 +7507,10 @@ function piIntercomExtension(pi, testOverrides = {}) {
6976
7507
  tracker: replyTracker,
6977
7508
  replyContext,
6978
7509
  currentClient: () => client,
6979
- commit,
7510
+ commit: () => {
7511
+ durableInbox.handledWithoutCard(message.id);
7512
+ commit();
7513
+ },
6980
7514
  failurePrefix: liveContext.subagentPolicy?.executionEnded === undefined ? undefined : "Subagent could not admit intercom ask"
6981
7515
  });
6982
7516
  const activeDelivery = admitActiveSessionInbound(liveContext, (admissionBarrier) => {
@@ -7013,6 +7547,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
7013
7547
  }
7014
7548
  } catch {}
7015
7549
  }
7550
+ await durableInbox.handledWithoutCard(message.id);
7016
7551
  commit();
7017
7552
  return;
7018
7553
  }
@@ -7164,11 +7699,10 @@ function piIntercomExtension(pi, testOverrides = {}) {
7164
7699
  }
7165
7700
  function attachClientHandlers(nextClient) {
7166
7701
  nextClient.on("message", (from, message, channel) => {
7167
- const liveContext = getLiveContext();
7168
- if (client !== nextClient || !liveContext) {
7702
+ if (client !== nextClient || !getLiveContext()) {
7169
7703
  return;
7170
7704
  }
7171
- handleIncomingMessage(liveContext, from, message, channel);
7705
+ receiveIncomingMessage(nextClient, from, message, channel);
7172
7706
  });
7173
7707
  nextClient.on("pending_stage_message", (request) => {
7174
7708
  handlePendingStageMessage(nextClient, request, () => client === nextClient);
@@ -7249,6 +7783,20 @@ function piIntercomExtension(pi, testOverrides = {}) {
7249
7783
  if (state.client === nextClient)
7250
7784
  relayStickyLiveDelivered(notice);
7251
7785
  });
7786
+ nextClient.on("pending_stage_route_revoked", (notice) => {
7787
+ if (notice.runId !== runId || state.client !== nextClient)
7788
+ return;
7789
+ state.client = null;
7790
+ if (state.reconnectTimer)
7791
+ clearTimeout(state.reconnectTimer);
7792
+ state.reconnectTimer = null;
7793
+ if (pendingStageRouteClients.get(runId) === state)
7794
+ pendingStageRouteClients.delete(runId);
7795
+ if (samePendingStageRoute(pendingStageRoutes.get(runId), state.route))
7796
+ pendingStageRoutes.delete(runId);
7797
+ nextClient.disconnect().catch(() => {});
7798
+ pi.events.emit(PENDING_STAGE_ROUTE_REVOKED_EVENT, { runId, capability: state.route.capability });
7799
+ });
7252
7800
  }
7253
7801
  async function ensurePendingStageRouteClient(runId, route) {
7254
7802
  const contextAtStart = getLiveContext();
@@ -7281,7 +7829,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
7281
7829
  pendingStageRouteClients.set(runId, state);
7282
7830
  if (state.client?.isConnected()) {
7283
7831
  state.route = route;
7284
- state.client.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages, route.parent);
7832
+ state.client.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages, route.parent, route.dormant === true);
7285
7833
  await state.client.listSessions();
7286
7834
  return;
7287
7835
  }
@@ -7299,7 +7847,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
7299
7847
  await nextClient.disconnect();
7300
7848
  throw new Error("Intercom runtime no longer active");
7301
7849
  }
7302
- nextClient.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages, route.parent);
7850
+ nextClient.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages, route.parent, route.dormant === true);
7303
7851
  await nextClient.listSessions();
7304
7852
  if (!pendingStageRouteClientIsCurrent(runId, state, contextAtStart, generationAtStart)) {
7305
7853
  await nextClient.disconnect();
@@ -7346,13 +7894,28 @@ function piIntercomExtension(pi, testOverrides = {}) {
7346
7894
  }
7347
7895
  async function registerPendingStageRoute(activeClient, runId, route) {
7348
7896
  const routeGroup = normalizeGroup(route.group);
7349
- if (clientRegistrationGroup === routeGroup) {
7897
+ if (clientRegistrationGroup === routeGroup && route.dormant !== true) {
7350
7898
  activeClient.registerPendingStageRoute(runId, routeGroup, route.capability, route.stages, route.possibleStages, route.parent);
7351
7899
  await activeClient.listSessions();
7352
7900
  return;
7353
7901
  }
7354
7902
  await ensurePendingStageRouteClient(runId, { ...route, group: routeGroup });
7355
7903
  }
7904
+ function persistedIntercomSessionId(ctx, sessionId) {
7905
+ try {
7906
+ return readIntercomSessionIdentity(ctx.sessionManager.getEntries(), sessionId);
7907
+ } catch {
7908
+ return;
7909
+ }
7910
+ }
7911
+ async function recordIntercomSessionIdentity(sessionId, intercomSessionId) {
7912
+ try {
7913
+ await pi.appendEntry(INTERCOM_SESSION_IDENTITY_ENTRY, {
7914
+ sessionId,
7915
+ intercomSessionId
7916
+ });
7917
+ } catch {}
7918
+ }
7356
7919
  async function ensureConnected(reason) {
7357
7920
  if (disposed || shuttingDown) {
7358
7921
  throw new Error("Intercom shutting down");
@@ -7370,10 +7933,12 @@ function piIntercomExtension(pi, testOverrides = {}) {
7370
7933
  return reconnectPromise;
7371
7934
  }
7372
7935
  const ownershipRecorded = Promise.withResolvers();
7936
+ const sessionIdAtStart = currentSessionId;
7937
+ const preferredSessionId = persistedIntercomSessionId(contextAtStart, sessionIdAtStart);
7373
7938
  const nextReconnectPromise = (async () => {
7374
7939
  let connectFailed = false;
7375
7940
  await ownershipRecorded.promise;
7376
- const nextClient = new IntercomClient(currentSessionId);
7941
+ const nextClient = new IntercomClient(sessionIdAtStart, { preferredSessionId, acknowledgesReceipt: true });
7377
7942
  client = nextClient;
7378
7943
  attachClientHandlers(nextClient);
7379
7944
  try {
@@ -7404,6 +7969,9 @@ function piIntercomExtension(pi, testOverrides = {}) {
7404
7969
  process.env[INTERCOM_SESSION_ID_ENV] = nextClient.sessionId;
7405
7970
  }
7406
7971
  reconnectAttempt = 0;
7972
+ if (nextClient.sessionId && nextClient.sessionId !== preferredSessionId) {
7973
+ await recordIntercomSessionIdentity(sessionIdAtStart, nextClient.sessionId);
7974
+ }
7407
7975
  return nextClient;
7408
7976
  } catch (error) {
7409
7977
  if (client === nextClient) {
@@ -7438,7 +8006,8 @@ function piIntercomExtension(pi, testOverrides = {}) {
7438
8006
  capability: payload.capability,
7439
8007
  ...payload.stages === undefined ? {} : { stages: payload.stages },
7440
8008
  ...payload.possibleStages === undefined ? {} : { possibleStages: payload.possibleStages },
7441
- ...payload.parent === undefined ? {} : { parent: payload.parent }
8009
+ ...payload.parent === undefined ? {} : { parent: payload.parent },
8010
+ ...payload.dormant === true ? { dormant: true } : {}
7442
8011
  });
7443
8012
  const completion = ensureConnected("background").then((activeClient) => registerPendingStageRoute(activeClient, payload.runId, payload));
7444
8013
  payload.completion = completion;
@@ -7508,6 +8077,48 @@ function piIntercomExtension(pi, testOverrides = {}) {
7508
8077
  resolveSessionTarget: resolveSessionTargetId,
7509
8078
  homeGroup: currentIntercomGroup
7510
8079
  });
8080
+ pi.events.on(SUBAGENT_AWAIT_INTERCOM_PEER_EVENT, (payload) => {
8081
+ if (!payload || typeof payload !== "object" || !isAwaitIntercomPeerRequest(payload) || payload.completion)
8082
+ return;
8083
+ const request = payload;
8084
+ request.completion = ensureConnected("background").then((activeClient) => waitForIntercomPeer(activeClient, request));
8085
+ });
8086
+ pi.events.on(INTERCOM_INBOX_REPLAY_EVENT, (payload) => {
8087
+ if (!payload || typeof payload !== "object")
8088
+ return;
8089
+ const request = payload;
8090
+ if (request.completion || !Array.isArray(request.restored))
8091
+ return;
8092
+ request.completion = replayDurableInbox(request);
8093
+ });
8094
+ pi.events.on(INTERCOM_RECOVERY_PEERS_EVENT, (payload) => {
8095
+ if (!payload || typeof payload !== "object")
8096
+ return;
8097
+ const request = payload;
8098
+ if (request.completion)
8099
+ return;
8100
+ request.completion = ensureConnected("background").then((activeClient) => activeClient.listSessions());
8101
+ });
8102
+ pi.events.on(SUBAGENT_RESERVE_RESTORING_CHILD_EVENT, (payload) => {
8103
+ if (!isReserveRestoringChildRequest(payload) || payload.completion)
8104
+ return;
8105
+ const request = payload;
8106
+ request.completion = ensureConnected("background").then((activeClient) => activeClient.reserveRestoringRecipient(request.capability, {
8107
+ ...request.group === undefined ? {} : { group: request.group },
8108
+ aliases: request.aliases,
8109
+ ...request.dormant === true ? { dormant: true } : {}
8110
+ }));
8111
+ });
8112
+ pi.events.on(SUBAGENT_RELEASE_RESTORING_CHILD_EVENT, (payload) => {
8113
+ if (!isReleaseRestoringChildRequest(payload) || payload.completion)
8114
+ return;
8115
+ const request = payload;
8116
+ const activeClient = client;
8117
+ request.completion = activeClient?.isConnected() ? activeClient.releaseRestoringRecipient(request.capability, {
8118
+ ...request.gone === undefined ? {} : { gone: request.gone },
8119
+ ...request.refusal === undefined ? {} : { refusal: request.refusal }
8120
+ }) : Promise.resolve();
8121
+ });
7511
8122
  pi.on("session_shutdown", (event) => {
7512
8123
  if (event.reason !== "reload" && currentSessionId)
7513
8124
  sessionMemberships.delete(currentSessionId);
@@ -7635,8 +8246,9 @@ function piIntercomExtension(pi, testOverrides = {}) {
7635
8246
  syncPresenceIdentity
7636
8247
  });
7637
8248
  }
7638
- var INTERCOM_SESSION_ID_ENV, PENDING_STAGE_ROUTE_EVENT = "atomic:workflow-pending-stage-route", PENDING_STAGE_MESSAGE_EVENT = "atomic:workflow-pending-stage-message", PENDING_STAGE_UNDELIVERABLE_EVENT = "atomic:workflow-pending-stage-undeliverable", STICKY_LIVE_DELIVERED_EVENT = "atomic:workflow-sticky-live-delivered";
8249
+ var INTERCOM_SESSION_ID_ENV, PENDING_STAGE_ROUTE_EVENT = "atomic:workflow-pending-stage-route", PENDING_STAGE_MESSAGE_EVENT = "atomic:workflow-pending-stage-message", PENDING_STAGE_UNDELIVERABLE_EVENT = "atomic:workflow-pending-stage-undeliverable", STICKY_LIVE_DELIVERED_EVENT = "atomic:workflow-sticky-live-delivered", PENDING_STAGE_ROUTE_REVOKED_EVENT = "atomic:workflow-pending-stage-route-revoked";
7639
8250
  var init_index_heavy = __esm(() => {
8251
+ init_session_recovery();
7640
8252
  init_client();
7641
8253
  init_spawn();
7642
8254
  init_inline_message();
@@ -7650,6 +8262,9 @@ var init_index_heavy = __esm(() => {
7650
8262
  init_subagent_relay();
7651
8263
  init_foreground_detach_handoff();
7652
8264
  init_intercom_utils();
8265
+ init_incoming_message_delivery();
8266
+ init_inbound_idle_queue();
8267
+ init_durable_inbox();
7653
8268
  init_terminal_ordering_barrier();
7654
8269
  init_session_target();
7655
8270
  init_inbound_message_admission();
@@ -7818,6 +8433,8 @@ class IntercomWarmUpExhaustedError extends Error {
7818
8433
 
7819
8434
  // dist/builtin/intercom/index.ts
7820
8435
  init_reconnect_backoff();
8436
+ init_session_recovery();
8437
+ init_durable_inbox();
7821
8438
 
7822
8439
  // dist/builtin/intercom/lazy-heavy-proxy.ts
7823
8440
  var LIVE_EVENT_SUBSCRIPTIONS = new Set(["pi-intercom:detach-response"]);
@@ -8404,6 +9021,91 @@ function intercom(pi, options = {}) {
8404
9021
  throw error;
8405
9022
  });
8406
9023
  });
9024
+ pi.events.on(SUBAGENT_AWAIT_INTERCOM_PEER_EVENT, (payload) => {
9025
+ if (!payload || typeof payload !== "object" || !isAwaitIntercomPeerRequest(payload) || payload.completion)
9026
+ return;
9027
+ const forwarded = {
9028
+ name: payload.name,
9029
+ timeoutMs: payload.timeoutMs,
9030
+ ...payload.group === undefined ? {} : { group: payload.group }
9031
+ };
9032
+ payload.completion = loadHeavy(latestLifecycleContext()).then(async (handle) => {
9033
+ handle.assertCurrent();
9034
+ await dispatchEventHandlers(handle.heavy, SUBAGENT_AWAIT_INTERCOM_PEER_EVENT, forwarded);
9035
+ return forwarded.completion ? await forwarded.completion : false;
9036
+ }).catch(() => false);
9037
+ });
9038
+ pi.events.on(SUBAGENT_RESERVE_RESTORING_CHILD_EVENT, (payload) => {
9039
+ if (!isReserveRestoringChildRequest(payload) || payload.completion)
9040
+ return;
9041
+ const forwarded = {
9042
+ capability: payload.capability,
9043
+ aliases: [...payload.aliases],
9044
+ ...payload.group === undefined ? {} : { group: payload.group },
9045
+ ...payload.dormant === true ? { dormant: true } : {}
9046
+ };
9047
+ payload.completion = loadHeavy(latestLifecycleContext()).then(async (handle) => {
9048
+ handle.assertCurrent();
9049
+ await dispatchEventHandlers(handle.heavy, SUBAGENT_RESERVE_RESTORING_CHILD_EVENT, forwarded);
9050
+ if (!forwarded.completion)
9051
+ throw new Error("Intercom cannot hold sends for a restoring subagent");
9052
+ await forwarded.completion;
9053
+ });
9054
+ });
9055
+ pi.events.on(SUBAGENT_RELEASE_RESTORING_CHILD_EVENT, (payload) => {
9056
+ if (!isReleaseRestoringChildRequest(payload) || payload.completion)
9057
+ return;
9058
+ const forwarded = {
9059
+ capability: payload.capability,
9060
+ ...payload.gone === undefined ? {} : { gone: payload.gone },
9061
+ ...payload.refusal === undefined ? {} : { refusal: payload.refusal }
9062
+ };
9063
+ const handle = loadedHeavy;
9064
+ payload.completion = !handle ? Promise.resolve() : (async () => {
9065
+ try {
9066
+ handle.assertCurrent();
9067
+ await dispatchEventHandlers(handle.heavy, SUBAGENT_RELEASE_RESTORING_CHILD_EVENT, forwarded);
9068
+ await forwarded.completion;
9069
+ } catch {}
9070
+ })();
9071
+ });
9072
+ async function recoveryPeers(ctx) {
9073
+ try {
9074
+ const handle = await loadHeavy(ctx);
9075
+ handle.assertCurrent();
9076
+ const forwarded = {};
9077
+ await dispatchEventHandlers(handle.heavy, INTERCOM_RECOVERY_PEERS_EVENT, forwarded);
9078
+ return forwarded.completion ? await forwarded.completion : undefined;
9079
+ } catch {
9080
+ return;
9081
+ }
9082
+ }
9083
+ async function replayIntercomInbox(ctx, peers) {
9084
+ try {
9085
+ const restored = await awaitRestoredIntercomPeers(pi.events, ctx.sessionManager.getSessionId());
9086
+ const handle = await loadHeavy(ctx);
9087
+ handle.assertCurrent();
9088
+ const forwarded = { peers, restored };
9089
+ await dispatchEventHandlers(handle.heavy, INTERCOM_INBOX_REPLAY_EVENT, forwarded);
9090
+ return await forwarded.completion ?? [];
9091
+ } catch {
9092
+ return [];
9093
+ }
9094
+ }
9095
+ pi.on("session_recovery_restore", async (_event, ctx) => {
9096
+ const peers = hasIntercomHistory(ctx.sessionManager.getEntries()) ? await recoveryPeers(ctx) : undefined;
9097
+ if (unconsumedIntercomInbox(ctx.sessionManager.getBranch()).length === 0)
9098
+ return;
9099
+ const notices = await replayIntercomInbox(ctx, peers);
9100
+ return notices.length > 0 ? { notices: [...notices] } : undefined;
9101
+ });
9102
+ pi.on("session_recovery_replay", async (event, ctx) => {
9103
+ if (!event.pending.some((delivery) => delivery.customType === "intercom_message"))
9104
+ return;
9105
+ const peers = await recoveryPeers(ctx);
9106
+ const restored = await awaitRestoredIntercomPeers(pi.events, ctx.sessionManager.getSessionId());
9107
+ return planIntercomRecoveryReplay(event.pending, peers, restored);
9108
+ });
8407
9109
  pi.events.on(PENDING_STAGE_UNDELIVERABLE_EVENT2, (payload) => {
8408
9110
  if (!isPendingStageUndeliverableRelay(payload) || payload.handled === true)
8409
9111
  return;