@bastani/atomic 0.9.39 → 0.9.40-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (280) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/builtin/intercom/CHANGELOG.md +14 -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 +31 -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/CHANGELOG.md +6 -0
  48. package/dist/builtin/web-access/README.md +1 -1
  49. package/dist/builtin/web-access/index.bundle.mjs +2 -5
  50. package/dist/builtin/web-access/package.json +1 -1
  51. package/dist/builtin/workflows/CHANGELOG.md +24 -0
  52. package/dist/builtin/workflows/README.md +1 -1
  53. package/dist/builtin/workflows/package.json +1 -1
  54. package/dist/builtin/workflows/skills/impeccable/SKILL.md +8 -8
  55. package/dist/builtin/workflows/skills/impeccable/reference/adapt.md +3 -3
  56. package/dist/builtin/workflows/skills/impeccable/reference/adapt.native.md +1 -1
  57. package/dist/builtin/workflows/skills/impeccable/reference/audit.md +4 -2
  58. package/dist/builtin/workflows/skills/impeccable/reference/audit.native.md +2 -2
  59. package/dist/builtin/workflows/skills/impeccable/reference/craft-floor.md +1 -1
  60. package/dist/builtin/workflows/skills/impeccable/reference/critique.md +22 -9
  61. package/dist/builtin/workflows/skills/impeccable/reference/degraded/finish-reviewer.md +2 -2
  62. package/dist/builtin/workflows/skills/impeccable/reference/distill.md +3 -3
  63. package/dist/builtin/workflows/skills/impeccable/reference/extract.md +3 -3
  64. package/dist/builtin/workflows/skills/impeccable/reference/harden.md +2 -4
  65. package/dist/builtin/workflows/skills/impeccable/reference/hooks.md +4 -4
  66. package/dist/builtin/workflows/skills/impeccable/reference/live.md +1 -1
  67. package/dist/builtin/workflows/skills/impeccable/reference/new-work.md +6 -6
  68. package/dist/builtin/workflows/skills/impeccable/reference/onboard.md +3 -3
  69. package/dist/builtin/workflows/skills/impeccable/reference/optimize.md +3 -3
  70. package/dist/builtin/workflows/skills/impeccable/reference/overdrive.md +3 -3
  71. package/dist/builtin/workflows/skills/impeccable/reference/quieter.md +3 -3
  72. package/dist/builtin/workflows/skills/impeccable/reference/typeset.md +10 -0
  73. package/dist/builtin/workflows/skills/impeccable/reference/visualize.md +1 -1
  74. package/dist/builtin/workflows/skills/impeccable/scripts/VERSION +1 -1
  75. package/dist/builtin/workflows/skills/impeccable/scripts/impeccable +6 -0
  76. package/dist/builtin/workflows/skills/impeccable/scripts/impeccable.cmd +47 -22
  77. package/dist/builtin/workflows/skills/impeccable/scripts/live-browser-dom.js +34 -1
  78. package/dist/builtin/workflows/skills/impeccable/scripts/live-browser-session.js +25 -1
  79. package/dist/builtin/workflows/skills/impeccable/scripts/live-browser.js +33 -8
  80. package/dist/builtin/workflows/src/durable/journal/resolution.d.ts +7 -7
  81. package/dist/builtin/workflows/src/extension/index.bundle.mjs +22715 -22159
  82. package/dist/builtin/workflows/src/index.js +106 -35
  83. package/dist/cli/args.d.ts +2 -0
  84. package/dist/cli/args.d.ts.map +1 -1
  85. package/dist/cli/args.js +17 -1
  86. package/dist/cli/args.js.map +1 -1
  87. package/dist/core/agent-session-extension-bindings.d.ts +2 -0
  88. package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
  89. package/dist/core/agent-session-extension-bindings.js +6 -6
  90. package/dist/core/agent-session-extension-bindings.js.map +1 -1
  91. package/dist/core/agent-session-methods.d.ts +6 -3
  92. package/dist/core/agent-session-methods.d.ts.map +1 -1
  93. package/dist/core/agent-session-methods.js.map +1 -1
  94. package/dist/core/agent-session-persistent-custom-messages.d.ts +7 -2
  95. package/dist/core/agent-session-persistent-custom-messages.d.ts.map +1 -1
  96. package/dist/core/agent-session-persistent-custom-messages.js +29 -12
  97. package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
  98. package/dist/core/agent-session-recovery.d.ts +14 -0
  99. package/dist/core/agent-session-recovery.d.ts.map +1 -0
  100. package/dist/core/agent-session-recovery.js +83 -0
  101. package/dist/core/agent-session-recovery.js.map +1 -0
  102. package/dist/core/agent-session-tasks.d.ts.map +1 -1
  103. package/dist/core/agent-session-tasks.js +4 -6
  104. package/dist/core/agent-session-tasks.js.map +1 -1
  105. package/dist/core/agent-session-types.d.ts +13 -0
  106. package/dist/core/agent-session-types.d.ts.map +1 -1
  107. package/dist/core/agent-session-types.js.map +1 -1
  108. package/dist/core/agent-session.d.ts +2 -1
  109. package/dist/core/agent-session.d.ts.map +1 -1
  110. package/dist/core/agent-session.js +4 -1
  111. package/dist/core/agent-session.js.map +1 -1
  112. package/dist/core/export-html/index.d.ts.map +1 -1
  113. package/dist/core/export-html/index.js +3 -2
  114. package/dist/core/export-html/index.js.map +1 -1
  115. package/dist/core/export-html/template.html +1 -0
  116. package/dist/core/export-html/template.js +37 -20
  117. package/dist/core/export-html/vendor/marked-cjk-friendly.min.js +6 -0
  118. package/dist/core/export-html/vendor/marked.min.js +76 -3
  119. package/dist/core/extensions/api-types.d.ts +6 -2
  120. package/dist/core/extensions/api-types.d.ts.map +1 -1
  121. package/dist/core/extensions/api-types.js.map +1 -1
  122. package/dist/core/extensions/event-results.d.ts +21 -0
  123. package/dist/core/extensions/event-results.d.ts.map +1 -1
  124. package/dist/core/extensions/event-results.js.map +1 -1
  125. package/dist/core/extensions/index.d.ts +1 -1
  126. package/dist/core/extensions/index.d.ts.map +1 -1
  127. package/dist/core/extensions/index.js.map +1 -1
  128. package/dist/core/extensions/loader-api.d.ts.map +1 -1
  129. package/dist/core/extensions/loader-api.js +4 -0
  130. package/dist/core/extensions/loader-api.js.map +1 -1
  131. package/dist/core/extensions/runner-events.d.ts +9 -2
  132. package/dist/core/extensions/runner-events.d.ts.map +1 -1
  133. package/dist/core/extensions/runner-events.js +29 -0
  134. package/dist/core/extensions/runner-events.js.map +1 -1
  135. package/dist/core/extensions/runner.d.ts +5 -3
  136. package/dist/core/extensions/runner.d.ts.map +1 -1
  137. package/dist/core/extensions/runner.js +7 -2
  138. package/dist/core/extensions/runner.js.map +1 -1
  139. package/dist/core/extensions/runtime-types.d.ts +1 -0
  140. package/dist/core/extensions/runtime-types.d.ts.map +1 -1
  141. package/dist/core/extensions/runtime-types.js.map +1 -1
  142. package/dist/core/extensions/session-events.d.ts +30 -2
  143. package/dist/core/extensions/session-events.d.ts.map +1 -1
  144. package/dist/core/extensions/session-events.js.map +1 -1
  145. package/dist/core/sdk-types.d.ts +3 -2
  146. package/dist/core/sdk-types.d.ts.map +1 -1
  147. package/dist/core/sdk-types.js.map +1 -1
  148. package/dist/core/sdk.d.ts.map +1 -1
  149. package/dist/core/sdk.js +3 -0
  150. package/dist/core/sdk.js.map +1 -1
  151. package/dist/core/session-storage.d.ts.map +1 -1
  152. package/dist/core/session-storage.js +15 -9
  153. package/dist/core/session-storage.js.map +1 -1
  154. package/dist/core/storage/process-selection.d.ts +39 -0
  155. package/dist/core/storage/process-selection.d.ts.map +1 -0
  156. package/dist/core/storage/process-selection.js +154 -0
  157. package/dist/core/storage/process-selection.js.map +1 -0
  158. package/dist/core/storage/provider.d.ts +6 -1
  159. package/dist/core/storage/provider.d.ts.map +1 -1
  160. package/dist/core/storage/provider.js +3 -2
  161. package/dist/core/storage/provider.js.map +1 -1
  162. package/dist/core/storage/selection.d.ts +1 -1
  163. package/dist/core/storage/selection.d.ts.map +1 -1
  164. package/dist/core/storage/selection.js.map +1 -1
  165. package/dist/core/storage/session/jsonl-session-store.d.ts +2 -0
  166. package/dist/core/storage/session/jsonl-session-store.d.ts.map +1 -1
  167. package/dist/core/storage/session/jsonl-session-store.js +38 -2
  168. package/dist/core/storage/session/jsonl-session-store.js.map +1 -1
  169. package/dist/core/tasks/completion.d.ts +11 -2
  170. package/dist/core/tasks/completion.d.ts.map +1 -1
  171. package/dist/core/tasks/completion.js +40 -16
  172. package/dist/core/tasks/completion.js.map +1 -1
  173. package/dist/core/tasks/pause.d.ts +4 -1
  174. package/dist/core/tasks/pause.d.ts.map +1 -1
  175. package/dist/core/tasks/pause.js +8 -5
  176. package/dist/core/tasks/pause.js.map +1 -1
  177. package/dist/index-extensions.d.ts +1 -1
  178. package/dist/index-extensions.d.ts.map +1 -1
  179. package/dist/index-extensions.js.map +1 -1
  180. package/dist/index.d.ts +2 -1
  181. package/dist/index.d.ts.map +1 -1
  182. package/dist/index.js +2 -0
  183. package/dist/index.js.map +1 -1
  184. package/dist/main.d.ts.map +1 -1
  185. package/dist/main.js +7 -1
  186. package/dist/main.js.map +1 -1
  187. package/dist/modes/interactive/components/chat-session-host-rendering.d.ts.map +1 -1
  188. package/dist/modes/interactive/components/chat-session-host-rendering.js +11 -1
  189. package/dist/modes/interactive/components/chat-session-host-rendering.js.map +1 -1
  190. package/dist/modes/interactive/components/chat-session-host-state.d.ts +2 -0
  191. package/dist/modes/interactive/components/chat-session-host-state.d.ts.map +1 -1
  192. package/dist/modes/interactive/components/chat-session-host-state.js +2 -0
  193. package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
  194. package/dist/modes/interactive/interactive-deferred-startup.d.ts.map +1 -1
  195. package/dist/modes/interactive/interactive-deferred-startup.js +4 -0
  196. package/dist/modes/interactive/interactive-deferred-startup.js.map +1 -1
  197. package/dist/modes/interactive/interactive-mode-surface.d.ts +2 -1
  198. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  199. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  200. package/dist/modes/interactive/interactive-render-chat.js +3 -0
  201. package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
  202. package/dist/modes/interactive/interactive-session-routing.js +2 -0
  203. package/dist/modes/interactive/interactive-session-routing.js.map +1 -1
  204. package/dist/modes/interactive/interactive-session-runtime.d.ts +2 -1
  205. package/dist/modes/interactive/interactive-session-runtime.d.ts.map +1 -1
  206. package/dist/modes/interactive/interactive-session-runtime.js +29 -0
  207. package/dist/modes/interactive/interactive-session-runtime.js.map +1 -1
  208. package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
  209. package/dist/modes/interactive/interactive-startup.js +4 -1
  210. package/dist/modes/interactive/interactive-startup.js.map +1 -1
  211. package/dist/modes/interactive-engine/engine-args.d.ts.map +1 -1
  212. package/dist/modes/interactive-engine/engine-args.js +4 -0
  213. package/dist/modes/interactive-engine/engine-args.js.map +1 -1
  214. package/dist/modes/interactive-engine/engine-render-service.d.ts.map +1 -1
  215. package/dist/modes/interactive-engine/engine-render-service.js +4 -4
  216. package/dist/modes/interactive-engine/engine-render-service.js.map +1 -1
  217. package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
  218. package/dist/modes/interactive-engine/isolated-runtime.js +4 -0
  219. package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
  220. package/dist/modes/interactive-engine/remote-renderer.js +1 -1
  221. package/dist/modes/interactive-engine/remote-renderer.js.map +1 -1
  222. package/dist/modes/rpc/rpc-client-api.d.ts +4 -1
  223. package/dist/modes/rpc/rpc-client-api.d.ts.map +1 -1
  224. package/dist/modes/rpc/rpc-client-api.js +4 -0
  225. package/dist/modes/rpc/rpc-client-api.js.map +1 -1
  226. package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
  227. package/dist/modes/rpc/rpc-command-handler.js +3 -0
  228. package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
  229. package/dist/modes/rpc/rpc-command-timeouts.d.ts.map +1 -1
  230. package/dist/modes/rpc/rpc-command-timeouts.js +1 -0
  231. package/dist/modes/rpc/rpc-command-timeouts.js.map +1 -1
  232. package/dist/modes/rpc/rpc-input-scheduler.d.ts.map +1 -1
  233. package/dist/modes/rpc/rpc-input-scheduler.js +6 -1
  234. package/dist/modes/rpc/rpc-input-scheduler.js.map +1 -1
  235. package/dist/modes/rpc/rpc-types.d.ts +12 -1
  236. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  237. package/dist/modes/rpc/rpc-types.js.map +1 -1
  238. package/dist/utils/shell.d.ts.map +1 -1
  239. package/dist/utils/shell.js +44 -11
  240. package/dist/utils/shell.js.map +1 -1
  241. package/dist/utils/tools-manager.js +1 -1
  242. package/dist/utils/tools-manager.js.map +1 -1
  243. package/docs/background-tasks.md +5 -3
  244. package/docs/computer-use.md +2 -2
  245. package/docs/environment-variables.md +4 -1
  246. package/docs/extensions/events.md +29 -2
  247. package/docs/getting-started/first-session.md +1 -1
  248. package/docs/guides/intercom.md +1 -1
  249. package/docs/intercom/operations.md +103 -1
  250. package/docs/intercom/reference.md +10 -3
  251. package/docs/intercom.md +8 -6
  252. package/docs/keybindings.md +1 -1
  253. package/docs/models.md +1 -1
  254. package/docs/providers.md +5 -3
  255. package/docs/reference/cli.md +5 -0
  256. package/docs/rpc/protocol.md +19 -0
  257. package/docs/rpc.md +3 -0
  258. package/docs/sdk/web-server.md +1 -1
  259. package/docs/sdk.md +5 -2
  260. package/docs/sessions.md +17 -1
  261. package/docs/settings.md +6 -4
  262. package/docs/skills.md +1 -1
  263. package/docs/storage.md +54 -3
  264. package/docs/subagents.md +49 -9
  265. package/docs/usage.md +1 -1
  266. package/docs/windows.md +14 -4
  267. package/docs/workflows/api-reference.md +1 -1
  268. package/docs/workflows/authoring.md +1 -1
  269. package/docs/workflows/operations.md +10 -6
  270. package/npm-shrinkwrap.json +40 -40
  271. package/package.json +6 -6
  272. package/dist/core/export-html/template-js/data-tree.js +0 -287
  273. package/dist/core/export-html/template-js/entries-navigation.js +0 -434
  274. package/dist/core/export-html/template-js/initialization.js +0 -335
  275. package/dist/core/export-html/template-js/message-tools.js +0 -428
  276. package/dist/core/export-html/template-js/tree-filter-render.js +0 -419
  277. package/dist/core/export-html/template-script.d.ts +0 -3
  278. package/dist/core/export-html/template-script.d.ts.map +0 -1
  279. package/dist/core/export-html/template-script.js +0 -13
  280. package/dist/core/export-html/template-script.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/intercom",
3
- "version": "0.9.39",
3
+ "version": "0.9.40-alpha.2",
4
4
  "private": true,
5
5
  "description": "Atomic extension providing a private coordination channel between parent and child agent sessions. Fork of: https://github.com/nicobailon/pi-intercom",
6
6
  "contributors": [
@@ -8,3 +8,7 @@ export const RETRY_IDENTITY_TTL_MS = ASK_REPLY_TIMEOUT_MS + RETRY_IDENTITY_RETRY
8
8
  export const DELIVERED_MESSAGE_TTL_MS = RETRY_IDENTITY_TTL_MS + RETRY_IDENTITY_RETRY_OPPORTUNITY_MS;
9
9
  /** Three reconnect attempts, used independently before initialization and during delivery. */
10
10
  export const RECONNECT_DELAYS_MS = [1_000, 2_000, 5_000] as const;
11
+ /** How long a sender waits for one send's outcome before its client gives up. */
12
+ export const SEND_RESPONSE_TIMEOUT_MS = 10_000;
13
+ /** The broker answers an unconfirmed save before the sender's own wait ends, so the sender learns the outcome is uncertain. */
14
+ export const RECIPIENT_RECEIPT_TIMEOUT_MS = 8_000;
@@ -4,6 +4,7 @@ export type SessionTargetResolution<T extends Pick<SessionInfo, "id" | "name"> =
4
4
  | { kind: "resolved"; session: T }
5
5
  | { kind: "ambiguous_name"; matches: readonly T[] }
6
6
  | { kind: "ambiguous_id_prefix"; matches: readonly T[] }
7
+ | { kind: "ambiguous_session_id"; matches: readonly T[] }
7
8
  | { kind: "not_found" };
8
9
 
9
10
  const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -42,6 +43,24 @@ export function resolveSessionTarget<T extends Pick<SessionInfo, "id" | "name">>
42
43
  return { kind: "not_found" };
43
44
  }
44
45
 
46
+ /**
47
+ * #3760: a host (Atomic) session id addresses the one candidate registered for it. Only the broker knows
48
+ * which host session registered each Intercom session, so it supplies the lookup; this applies only after
49
+ * Intercom ids, names and id prefixes found nothing, so it never shadows them.
50
+ */
51
+ export function resolveSessionTargetByHostSessionId<T extends Pick<SessionInfo, "id" | "name">>(
52
+ sessions: readonly T[],
53
+ target: string,
54
+ hostSessionIdOf: (session: T) => string | undefined,
55
+ ): SessionTargetResolution<T> {
56
+ const hostSessionId = target.trim();
57
+ if (!hostSessionId) return { kind: "not_found" };
58
+ const matches = sessions.filter((session) => hostSessionIdOf(session) === hostSessionId);
59
+ if (matches.length === 1) return { kind: "resolved", session: matches[0]! };
60
+ if (matches.length > 1) return { kind: "ambiguous_session_id", matches };
61
+ return { kind: "not_found" };
62
+ }
63
+
45
64
  export function sessionTargetFailureReason(
46
65
  target: string,
47
66
  resolution: Exclude<SessionTargetResolution<Pick<SessionInfo, "id" | "name">>, { kind: "resolved" }>,
@@ -54,6 +73,11 @@ export function sessionTargetFailureReason(
54
73
  .map((session) => `${session.name ?? "unnamed"} (${session.id})`)
55
74
  .join(", ")}. Use the full UUID.`;
56
75
  }
76
+ if (resolution.kind === "ambiguous_session_id") {
77
+ return `Session ID "${target}" is registered by more than one Intercom session: ${resolution.matches
78
+ .map((session) => `${session.name ?? "unnamed"} (${session.id})`)
79
+ .join(", ")}. Use the Intercom session ID shown by intercom list.`;
80
+ }
57
81
  return "Session not found";
58
82
  }
59
83
 
@@ -128,18 +128,51 @@ export type ClientMessage =
128
128
  session: Omit<SessionInfo, "id">;
129
129
  /** Internal host-owned identity retained across broker reconnects. */
130
130
  returnAddress?: string;
131
+ /**
132
+ * The Intercom session id this session held before a restart or reconnect (#3760). The broker grants it
133
+ * only when no live session holds it and it was not last held under another return address.
134
+ */
135
+ preferredSessionId?: string;
131
136
  /** Immutable session origin; separate from mutable group memberships. Legacy clients use session.group. */
132
137
  registrationGroup?: string;
133
138
  supervisor?: SupervisorRegistration;
134
139
  supervisorOwnerToken?: string;
140
+ /** #3761: this recipient sends `received` once it has saved each message; `delivered` waits for it. */
141
+ acknowledgesReceipt?: true;
135
142
  }
136
143
  | { type: "unregister" }
144
+ /** #3761: the recipient saved this message; it ignores a copy of it sent again. */
145
+ | { type: "received"; messageId: string }
137
146
  | { type: "list"; requestId: string; group?: string }
138
147
  | { type: "list_groups"; requestId: string }
139
148
  | { type: "join_group"; requestId: string; group: string }
140
149
  | { type: "leave_group"; requestId: string; group?: string }
141
150
  | { type: "authorize_supervisor"; requestId: string; childName: string; capability?: string }
142
- | { type: "send" | "supervisor_send"; to: string; logicalTarget?: string; requirePendingReply?: true; expectedRecipientId?: string; resolveReplyTarget?: true; message: Message; attemptId?: string }
151
+ /**
152
+ * #3760: the supervisor that holds `capability` for a child it is restoring, or is about to restore, holds sends to
153
+ * that child's name and `aliases` (its Atomic session id and pre-restart Intercom id) until the child registers
154
+ * with the capability. A `dormant` hold only keeps the child addressable until the supervisor that restores it
155
+ * reserves the same child and group, which takes the hold over together with the sends held so far.
156
+ */
157
+ | { type: "reserve_restoring_recipient"; requestId: string; capability: string; group?: string; aliases?: string[]; dormant?: boolean }
158
+ /**
159
+ * #3760: end that hold. With `gone` (the reason), held and later senders are told the child is gone. With `refusal`,
160
+ * the senders held now are told that reason instead and later ones are routed normally. Otherwise held sends are
161
+ * routed normally.
162
+ */
163
+ | { type: "release_restoring_recipient"; requestId: string; capability: string; gone?: string; refusal?: string }
164
+ | {
165
+ type: "send" | "supervisor_send";
166
+ to: string;
167
+ logicalTarget?: string;
168
+ requirePendingReply?: true;
169
+ expectedRecipientId?: string;
170
+ resolveReplyTarget?: true;
171
+ /** The sender understands `send_held` and may wait past its usual acknowledgement timeout (#3760). */
172
+ awaitRestoringRecipient?: true;
173
+ message: Message;
174
+ attemptId?: string;
175
+ }
143
176
  | {
144
177
  type: "send_pending_stage_notification";
145
178
  runId: string;
@@ -151,7 +184,17 @@ export type ClientMessage =
151
184
  attemptId?: string;
152
185
  }
153
186
  | { type: "pending_stage_notification_result"; requestId: string; delivered: boolean }
154
- | { type: "register_pending_stage_route"; runId: string; group: string; capability: string; stages?: WorkflowStageRosterAnnouncement[]; possibleStages?: WorkflowPossibleStageAnnouncement[]; parent?: WorkflowRunParentAnnouncement }
187
+ | {
188
+ type: "register_pending_stage_route";
189
+ runId: string;
190
+ group: string;
191
+ capability: string;
192
+ stages?: WorkflowStageRosterAnnouncement[];
193
+ possibleStages?: WorkflowPossibleStageAnnouncement[];
194
+ parent?: WorkflowRunParentAnnouncement;
195
+ /** Interrupted run queued by its restarted owner before resume; yields to the process that resumes it (#3760). */
196
+ dormant?: true;
197
+ }
155
198
  | {
156
199
  type: "register_live_workflow_stage_route";
157
200
  requestId: string;
@@ -181,7 +224,13 @@ export type ClientMessage =
181
224
  };
182
225
 
183
226
  export type BrokerMessage =
184
- | { type: "registered"; sessionId: string; supervisorSessionId?: string }
227
+ | {
228
+ type: "registered";
229
+ sessionId: string;
230
+ supervisorSessionId?: string;
231
+ /** #3761: echoed only to a client that advertised it; that client may now send `received`. */
232
+ acknowledgesReceipt?: true;
233
+ }
185
234
  | { type: "registration_failed"; reason: string; code?: LiveWorkflowStageRouteRefusalCode }
186
235
  | { type: "question_target"; messageId: string; attemptId: string; sessionId: string }
187
236
  | { type: "sessions"; requestId: string; sessions: SessionInfo[]; workflowStages?: WorkflowStageRosterEntry[]; workflowFutureStages?: WorkflowFutureStageRosterEntry[] }
@@ -202,6 +251,8 @@ export type BrokerMessage =
202
251
  live?: boolean;
203
252
  }
204
253
  | { type: "live_workflow_stage_route_registered"; requestId: string }
254
+ /** A dormant route's run was resumed by another process, which now owns the run's routes (#3760). */
255
+ | { type: "pending_stage_route_revoked"; runId: string }
205
256
  | { type: "presence_update"; session: SessionInfo }
206
257
  | { type: "session_joined"; session: SessionInfo }
207
258
  | { type: "session_left"; sessionId: string }
@@ -211,4 +262,7 @@ export type BrokerMessage =
211
262
  | { type: "error"; error: string }
212
263
  | { type: "delivered"; messageId: string; attemptId?: string }
213
264
  | { type: "queued"; messageId: string; attemptId?: string; target: string; position: number }
265
+ /** #3760: the send is held for a subagent that is being restored; wait up to `timeoutMs` for its outcome. */
266
+ | { type: "send_held"; messageId: string; attemptId?: string; timeoutMs: number }
267
+ | { type: "restoring_recipient_ack"; requestId: string; error?: string }
214
268
  | { type: "delivery_failed"; messageId: string; reason: string; reasonCode?: "message_id_conflict" | "session_not_found"; attemptId?: string };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/mcp",
3
- "version": "0.9.39",
3
+ "version": "0.9.40-alpha.2",
4
4
  "private": true,
5
5
  "description": "Atomic's pi-compatible MCP integration for server connections, OAuth, tools, resources, and terminal management.",
6
6
  "contributors": [
@@ -2,6 +2,37 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.9.40-alpha.1] - 2026-10-20
6
+
7
+ ### Breaking Changes
8
+
9
+ - Removed the `kill` action from the `subagent` tool. Replace `subagent({ action: "kill", id })` with `subagent({ action: "quit", id })`, which stops the child gracefully and keeps it resumable. Calls with `action: "kill"` or the earlier `action: "interrupt"` are rejected with an error that names `quit` as the replacement ([#3760](https://github.com/bastani-inc/atomic/issues/3760)).
10
+
11
+ ### Added
12
+
13
+ - Added workflow-style run control to the `subagent` tool: `pause` stops a child and holds its queued messages until resume, `quit` stops it gracefully, and `resume` continues it from its own saved session under the same child id, Intercom name, and group. `pause` and `quit` accept `all: true` and also reach parallel children still queued behind their concurrency limit, which then start only when resumed, and `resume` accepts an optional `message`: a paused, quit, or interrupted child receives it once as its next prompt and then continues where it left off, and a completed or failed child receives it as one fresh prompt. Without `message`, the child is asked to continue where it left off, including a completed or failed child. A resumed child of a parallel run waits for a slot under that run's concurrency limit, and keeps its `worktree: true` worktree until it finishes; a paused or quit child holds no slot, and its worktree is kept only while it has uncommitted or untracked changes or commits that are not in the run's base. Resume continues in a kept worktree, or recreates a removed one from the run's base; a resume that fails keeps the worktree, its changes, and its branch. Steering and follow-up messages a child had queued when it was paused or quit are delivered once, in order, when it resumes, before the resume `message`. An SDK session without a task host records its subagents the same way, so `pause`, `resume` and `quit` work there too, also after the session is reopened; a child it resumes runs in the background and reports through a completion notice. A child paused or quit before it read its task or the resume message keeps them, and resume delivers them. `id` accepts the child id, task id, Intercom name, or a single-child run id ([#3760](https://github.com/bastani-inc/atomic/issues/3760)).
14
+ - Paused, quit, interrupted, completed, and failed children can be resumed, including children of a session you closed or switched away from (Atomic exit or crash, `/new`, `/resume` to another session, `/fork`). Children cancelled for good (owner or batch cancellation, a `/tasks` stop, the removed `kill` action) or reported gone after a restart are terminal, and `resume` on them returns an error that says why ([#3760](https://github.com/bastani-inc/atomic/issues/3760)).
15
+ - Background subagent launch cards now show the child's latest state, also after you reopen the session (`/resume` or `atomic --session <id>`) or view a workflow stage's transcript: running, paused, paused with its workflow stage, quit, or interrupted (resumable), completed, failed, or terminal (killed, gone after a restart, or its workflow stage ended). Expanding a card shows the end of the child's saved transcript. A resumed child continues in its original card, marked resumed, and replayed `pause`, `resume`, and `quit` calls render as their results, or as errors when they were rejected ([#3760](https://github.com/bastani-inc/atomic/issues/3760)).
16
+
17
+ ### Changed
18
+
19
+ - Updated the bundled Cua Driver skill to upstream `cua-driver-rs-v0.36.0`. It now starts with an efficient loop: targeted `get_window_state` reads with `query`, acting by `element_token`, batching actions with `run_steps` or `run_script`, re-reading only changes with `since:"latest"`, and verifying at checkpoints instead of after every action. It also covers opening local files with `launch_app`, browser fallbacks when browser tools refuse in the background, and macOS editor recipes.
20
+ - When a workflow stage closes for good (the stage finished, or its run ended or was cancelled), every subagent it launched becomes terminal, whether running, paused, quit, completed, or failed, and `resume` on them returns an error that says their workflow stage ended. A quit child stays resumable only while the session or stage that launched it can still resume it. `quit` also accepts a child paused with its workflow stage, and `pause` reports such a child as already paused. Pausing or quitting a workflow run, Atomic exiting, switching sessions, and an interrupted stage leave the stage's children resumable: `resume` continues them, and resuming the run after Atomic restarts restores them with the stage ([#3760](https://github.com/bastani-inc/atomic/issues/3760)). A stage blocked by a recoverable failure, such as a rate limit or provider outage that leaves its run resumable, keeps its paused and quit subagents resumable until the run is killed, cancelled, or ends without staying resumable; then they end with the stage.
21
+
22
+ ### Fixed
23
+
24
+ - Background subagents that were still running when Atomic exited are now relaunched from their own sessions when you resume the session (`atomic --session <id>` or `/resume`) or resume a workflow stage that launched them. They keep their original Intercom name and group and get fresh supervisor authorization, and Intercom messages sent to it by any session in its group wait for it from the moment the resumed session starts (or, for a stage's subagent, from the moment the interrupted run becomes addressable) until it has been restored. Only the session that launched a child restores it: a fork of that session (`/fork`, `atomic --fork`, or a branched session) copies the child's record but never relaunches, waits for, or reports the child. If a child cannot be restored, the resumed agent is told explicitly that it is gone, once: the child is then recorded as gone, so later resumes neither retry it nor repeat the notice ([#3760](https://github.com/bastani-inc/atomic/issues/3760)).
25
+ - On Windows, removing a `worktree: true` worktree now removes its directory. Its `node_modules` junction is unlinked first, so Git for Windows no longer leaves the directory behind, and older Git versions no longer delete the main checkout's `node_modules` through the junction.
26
+ - A `worktree: true` child resumed after an Atomic restart saves its tracked and untracked edits as a patch in its run's `worktree-diffs` directory before its worktree is removed, as a child of a fresh run does.
27
+ - Resuming a `worktree: true` child whose worktree was already removed, such as a completed child, now restores the edits it saved as a patch before it continues, so its earlier work is not lost. Each run saves its patches in its own `worktree-diffs/<run id>` directory, and each execution of a resumed child writes its own patch (`task-<n>-<agent>.<execution>.patch`) instead of overwriting the earlier one. Patches now include binary changes.
28
+ - A subagent that an SDK session without a task host resumed now stops when that session closes, as the original launch does. Reopening the session relaunches it automatically, as it does a task-host child, and the steering and follow-up messages it had queued and not read are delivered once, in order. A task-host child whose session or workflow stage closes now keeps its unread steering and follow-up messages the same way, and restoring or resuming it delivers them once, in order, instead of losing them.
29
+ - Opening a fork no longer changes the original session's subagent launch cards back to an older state copied into the fork, such as showing a completed child as running.
30
+ - `pause` or `quit` of a subagent that completes just before the stop takes effect now reports that it completed instead of "Paused", and Intercom messages sent to it are no longer held until a resume ([#3784](https://github.com/bastani-inc/atomic/pull/3784)).
31
+ - A parallel subagent paused or quit while it still waited for a free slot can now be resumed after Atomic restarts, and one still waiting when Atomic exited starts when its session reopens, instead of being reported unrestorable or gone. It starts as a new launch under the same child id, Intercom name, and group, with its original agent definition, task, working directory or worktree, model, and skills, and a `context: "fork"` child starts on the parent conversation its launch branched; if that branch can no longer be reopened, the child is reported gone rather than started without it. This holds in task-host and SDK sessions alike ([#3784](https://github.com/bastani-inc/atomic/pull/3784)).
32
+ - Subagents of a workflow stage whose run is killed while it waits, after Atomic restarts, for `/workflow resume` now end with the run: `resume` returns "its workflow stage ended", their cards no longer show them as resumable, and reopening the stage's session no longer restores them ([#3784](https://github.com/bastani-inc/atomic/pull/3784)).
33
+ - A subagent relaunched from its own session after Atomic restarts, or resumed with `resume`, now runs on the agent definition it was launched with: a user agent is no longer replaced by a project agent of the same name. A child launched with `context: "fork"` also keeps its Intercom bridge instructions under `intercomBridge.mode: "fork-only"`. Children recorded by an earlier version keep the previous lookup ([#3784](https://github.com/bastani-inc/atomic/pull/3784)).
34
+ - A queued parallel subagent that inherited its parent's model and thinking level now keeps them when it starts after Atomic restarts, instead of taking whatever model and thinking level the parent switched to meanwhile. If that model is no longer available, resume reports the child as gone instead of starting it on the parent's current model. A child restored or resumed from its own session also falls back to the model it was launched with, not the parent's current one, and a child launched outside any Intercom group no longer joins a group the parent joined later ([#3784](https://github.com/bastani-inc/atomic/pull/3784)).
35
+
5
36
  ## [0.9.39] - 2026-10-19
6
37
 
7
38
  ### Fixed
@@ -183,7 +183,9 @@ subagent({ agent: "codebase-analyzer", task: "Trace authentication.", wait: { ki
183
183
  subagent({ agent: "codebase-analyzer", task: "Trace authentication.", wait: { kind: "foreground", budgetMs: 30000 } })
184
184
  subagent({ action: "wait", id: taskId })
185
185
  subagent({ action: "status", id: taskId })
186
- subagent({ action: "kill", id: taskId })
186
+ subagent({ action: "pause", id: taskId })
187
+ subagent({ action: "resume", id: taskId, message: "Focus on the failing test." })
188
+ subagent({ action: "quit", id: taskId })
187
189
  ```
188
190
 
189
191
  In owner-bound sessions, omitted `wait` means background. Explicit foreground waits use the owner's agent observation budget, normally 30 seconds, unless overridden. Expiry releases the caller, not the execution. Wait or inspect the returned task ID instead of launching a duplicate. Existing SDK callers without an owner retain their original execution path.
@@ -202,7 +204,7 @@ clarify → gather context → worker → fresh reviewers → worker
202
204
 
203
205
  Packaged `worker` defaults to forked context when a launch omits `context`; every other builtin runs fresh. Pass `context: "fresh"` when you intentionally want a fresh `worker` run.
204
206
 
205
- Child-safety boundaries are enforced at runtime by typed admission policy. In-process child sessions load bundled extensions through normal discovery. The `subagent` tool may therefore be registered when the child's active tool selection permits it, including the default no-allowlist case; an explicit allowlist may omit it. Tool presence does not grant fanout: fanout is authorized only when the resolved builtin `tools` list includes `subagent`. Typed admission policy lets a non-fanout child use only `list`, `get`, and `status`; delegation and `kill` receive the fanout refusal. A management-restricted child is also refused `create`, `update`, and `delete`. The bundled `pi-subagents` skill remains parent-only and is stripped from child prompts, including fanout-authorized children. No admitted child may delegate or control another child: launches and `kill` are refused for every child regardless of its fanout authorization. Children receive boundary instructions that they are not the parent orchestrator and must complete their assigned task directly. Forked child context filtering also removes parent-only subagent artifacts (including old hidden orchestration-instruction messages, slash/status/control messages, and prior parent `subagent` tool-call/tool-result history) while preserving ordinary prose and unrelated tool calls/results.
207
+ Child-safety boundaries are enforced at runtime by typed admission policy. In-process child sessions load bundled extensions through normal discovery. The `subagent` tool may therefore be registered when the child's active tool selection permits it, including the default no-allowlist case; an explicit allowlist may omit it. Tool presence does not grant fanout: fanout is authorized only when the resolved builtin `tools` list includes `subagent`. Typed admission policy lets a non-fanout child use only `list`, `get`, `status`, and `wait`; delegation and run control (`pause`, `resume`, `quit`) receive the fanout refusal. A management-restricted child is also refused `create`, `update`, and `delete`. The bundled `pi-subagents` skill remains parent-only and is stripped from child prompts, including fanout-authorized children. No admitted child may delegate or control another child: launches and run control are refused for every child regardless of its fanout authorization. Children receive boundary instructions that they are not the parent orchestrator and must complete their assigned task directly. Forked child context filtering also removes parent-only subagent artifacts (including old hidden orchestration-instruction messages, slash/status/control messages, and prior parent `subagent` tool-call/tool-result history) while preserving ordinary prose and unrelated tool calls/results.
206
208
 
207
209
 
208
210
 
@@ -234,13 +236,13 @@ Child-side routine completion handoffs are still not expected. In parallel runs,
234
236
 
235
237
  Children can also talk to each other. Children launched in one parallel set (or with the same explicit `group`) share an Intercom group, and children launched from a workflow stage inherit that stage's invocation group. `intercom({ action: "list" })` shows live siblings, and ordinary `send`/`ask` reaches them directly: a locator hands paths to an analyzer, writers agree on file ownership or who runs a shared suite, a debugger reuses a sibling's reproduction, or one reviewer challenges another's finding before each returns its own verdict. `contact_supervisor` stays reserved for the supervisor. Peers do not coordinate spontaneously, so name the peers and the expected, bounded exchange in each task prompt. Peer asks and one blocking supervisor request may wait concurrently in the same child.
236
238
 
237
- An exact-child probe/commit handshake may release parallel foreground observations, including queued slots, so the parent can respond. It does not end any execution or spend a running concurrency slot. Active siblings keep working, queued siblings start once capacity becomes available, and worktrees remain until their owners finish. Do not relaunch children to answer an ask. Targeted kill, explicit batch cancellation, and owner closure remain separate controls.
239
+ An exact-child probe/commit handshake may release parallel foreground observations, including queued slots, so the parent can respond. It does not end any execution or spend a running concurrency slot. Active siblings keep working, queued siblings start once capacity becomes available, and worktrees remain until their owners finish. Do not relaunch children to answer an ask. Targeted `pause`/`quit`, explicit batch cancellation, and owner closure remain separate controls.
238
240
 
239
241
  Single-child launches retain their existing terminal parent-ask handoff: the exact live child ends before broker send or waiter admission and the parent receives the verbatim question, ordered attachments, identity, and `[TASK_CONTEXT]` for a fresh child. The bridge still obtains each child's capability during admission; the child connects only when it uses Intercom.
240
242
 
241
243
  Parent-side Atomic sends grouped completion results through Intercom: one grouped message per foreground parent `subagent` run and one per detached child completion while its owning session remains live. When a workflow stage completes, Atomic cancels its still-running detached children and suppresses their late findings and completion notifications instead of forwarding them to the parent/main chat. Intercom-confirmed delivery returns a compact receipt with artifact/session paths; without that confirmation, the normal full output is preserved. Grouped messages include child Intercom targets and full child summaries.
242
244
 
243
- If a child appears stalled, needs-attention notices can show up in the parent session with useful next actions, such as checking `subagent({ action: "status" })`, killing the run, or nudging the child.
245
+ If a child appears stalled, needs-attention notices can show up in the parent session with useful next actions, such as checking `subagent({ action: "status" })`, quitting the child, or nudging it.
244
246
 
245
247
  If messages do not show up, check the bridge from the intercom side with `intercom({ action: "status" })`.
246
248
 
@@ -438,7 +440,7 @@ What the bundled skill covers:
438
440
  - **Role-agent prompting guidance**: compact contract prompts instead of long scripts, what to include in role-specific meta prompts, and retrieval budgets for researchers
439
441
  - **Safety boundaries**: child agents must not run subagents, must not invent intercom targets, and must escalate unapproved decisions
440
442
  - **Intercom conventions**: when to ask vs send, and how parent-side result delivery works with `pi-intercom`
441
- - **Control signals**: attention signals, terminal kills, and status
443
+ - **Control signals**: attention signals, pause/resume/quit run control, and status
442
444
 
443
445
  If you are writing an agent that orchestrates subagents, the bundled skill helps it behave correctly without guessing the patterns. If you are a human user, you do not need to read it directly; the README and prompt shortcuts encode the same workflows in user-facing form.
444
446
 
@@ -528,11 +530,11 @@ Agent definitions are not loaded into context by default. Management actions let
528
530
  |-------|------|---------|-------------|
529
531
  | `agent` | string | - | Agent name for single mode, or target for management actions. |
530
532
  | `task` | string | - | Task string for single mode. |
531
- | `action` | string | - | `list`, `get`, `create`, `update`, `delete`, `status`, `wait`, or `kill`. |
533
+ | `action` | string | - | `list`, `get`, `create`, `update`, `delete`, `status`, `wait`, `pause`, `resume`, or `quit`. `kill` and `interrupt` were removed and are rejected with an error naming `quit`. |
532
534
  | `config` | object/string | - | Agent config for create/update. |
533
535
  | `wait` | object | background in owner-bound sessions | `{ kind: "background" }` yields after admission; `{ kind: "foreground", budgetMs?: number }` waits before automatically yielding. |
534
536
  | `budgetMs` | number | owner wait policy | Observation budget for `action: "wait"`; not a child execution deadline. |
535
- | `id` | string | - | Task ID returned by an owner-bound launch for `wait`, `status`, or `kill`. |
537
+ | `id` | string | - | Task ID returned by an owner-bound launch for `wait` or `status`; for `pause`, `resume`, and `quit` also the child id (`<runId>:<index>`), Intercom name, or a single-child run id. |
536
538
  | `output` | `string \| false` | agent default | Override single-agent output file. |
537
539
  | `outputMode` | `"inline" \| "file-only"` | `inline` | Return saved output inline or as a concise saved-file reference. `file-only` requires an `output` path. |
538
540
  | `reads` | `string[] \| false` | - | Single-agent files to read before execution, or `false` to disable. Relative paths resolve against the effective child `cwd`; absolute paths pass through. |
@@ -561,10 +563,14 @@ Status and control actions:
561
563
  ```ts
562
564
  subagent({ action: "status" })
563
565
  subagent({ action: "status", id: "<run-id>" })
564
- subagent({ action: "kill", id: "<run-id>" })
566
+ subagent({ action: "pause", id: "<child-id>" })
567
+ subagent({ action: "pause", all: true })
568
+ subagent({ action: "resume", id: "<child-id>", message: "optional steer" })
569
+ subagent({ action: "quit", id: "<child-id>" })
570
+ subagent({ action: "quit", all: true })
565
571
  ```
566
572
 
567
- Completed, killed, interrupted, and single-child terminal-handoff children cannot be revived by a prior run ID; follow-up work requires a fresh launch with explicit context. A parallel child waiting for a reply is not terminal and continues in its original execution. Parent cancellation of a still-running child uses the interrupted/abort state: receipts and progress present it as cancelled rather than failed, persisted metadata keeps the abort cause, and bounded partial findings remain available. Migrate old subagent calls from `action: "interrupt"` to `action: "kill"`; the old action is rejected. Kill is terminal and cannot be resumed. Workflow controls use `pause`; host interrupt APIs are unchanged.
573
+ `pause` stops a child and holds its queued messages until `resume`; `quit` stops it gracefully, including a child already paused by you or with its workflow stage. Both stay resumable while the session or workflow stage that launched the child can still resume it, as do children stopped because their workflow stage was paused or quit, including by Atomic exiting or a session switch. `resume` reopens the child's own session under the same id and Intercom name. A paused, quit, or interrupted child receives `message` once as its next prompt and then continues where it left off; a completed or failed child receives `message` as one fresh prompt. Without `message`, every resumable child, including a completed or failed one, is asked to continue where it left off. Children cancelled for good (owner or batch cancellation, including a `/tasks` stop, and the removed `kill` action), children whose workflow stage ended (the stage finished, or its run ended or was cancelled; this covers all of that stage's children, including ones you paused or quit), and children reported gone after a restart cannot be resumed: `resume` returns an error that says why, and follow-up work requires a fresh launch with explicit context. A parallel child waiting for a reply is not terminal and continues in its original execution. Parent cancellation of a still-running child uses the interrupted/abort state: receipts and progress present it as cancelled rather than failed, persisted metadata keeps the abort cause, and bounded partial findings remain available. Migrate old subagent calls from `action: "kill"` or `action: "interrupt"` to `action: "quit"`; the old actions are rejected with `The subagent action "kill" was removed. Use { action: "quit", id } to stop a child gracefully; it stays resumable with { action: "resume", id, message? }.` (naming the action that was used). Host interrupt APIs are unchanged.
568
574
 
569
575
  ## Worktree isolation
570
576
 
@@ -690,7 +696,7 @@ Foreground runs persist their session and user-facing artifacts beside the paren
690
696
  run-history.jsonl
691
697
  ```
692
698
 
693
- Task-ID status, wait, and kill resolve the same owner as launch. Run-ID status uses the existing Rust subagent registry. Owner-bound completion delivery uses persisted intent and acknowledgement records in session history; no second PID registry or execution is created for the UI.
699
+ Task-ID status, wait, pause, resume, and quit resolve the same owner as launch. Run-ID status uses the existing Rust subagent registry. Owner-bound completion delivery uses persisted intent and acknowledgement records in session history; no second PID registry or execution is created for the UI.
694
700
 
695
701
  ## Completion and output
696
702
 
@@ -725,7 +731,7 @@ This is disabled by default. Session data may contain source code, paths, enviro
725
731
 
726
732
  ## Delegation boundary
727
733
 
728
- Delegation is exactly one level deep, and nothing configures it. A top-level session, main chat or a workflow stage, may call `subagent`. A session that was itself admitted as a subagent child may not: every launch and `kill` it attempts is refused with guidance to complete its assigned task directly. The observing actions `list`, `get`, and `status` stay available to a child. Child sessions retain bundled workflow definitions as resources but do not load the workflows extension or expose its `workflow` tool; orchestration stays owned by the parent session.
734
+ Delegation is exactly one level deep, and nothing configures it. A top-level session, main chat or a workflow stage, may call `subagent`. A session that was itself admitted as a subagent child may not: every launch and run control (`pause`, `resume`, `quit`) it attempts is refused with guidance to complete its assigned task directly. The observing actions `list`, `get`, `status`, and `wait` stay available to a child. Child sessions retain bundled workflow definitions as resources but do not load the workflows extension or expose its `workflow` tool; orchestration stays owned by the parent session.
729
735
 
730
736
  There is no configuration option, agent frontmatter field, or tool parameter for the delegation level. The rule is enforced twice: the subagent executor refuses a child before any run starts, and the Rust `SubagentControl` admission door refuses a child deeper than the single permitted level. Admitted depth is typed admission state and is not inherited through an environment variable.
731
737
 
@@ -782,7 +788,7 @@ The main runtime files are:
782
788
  |------|---------|
783
789
  | `src/extension/index.ts` | Extension registration, tool registration, message/render wiring. |
784
790
  | `src/agents/agents.ts` | Agent discovery and frontmatter parsing. |
785
- | `src/runs/foreground/subagent-executor.ts` | Main execution routing for single, parallel, management, status, and kill actions. |
791
+ | `src/runs/foreground/subagent-executor.ts` | Main execution routing for single, parallel, management, status, and run-control actions. |
786
792
  | `src/runs/foreground/execution.ts` | Core foreground `runSync` handling. |
787
793
  | `src/runs/foreground/notify.ts` | Completion-notification delivery for a detached Intercom child. |
788
794
  | `src/runs/foreground/completion-notification.ts` | Local completion acknowledgement and ordering barrier for detached children. |
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/subagents",
3
- "version": "0.9.39",
3
+ "version": "0.9.40-alpha.2",
4
4
  "private": true,
5
5
  "description": "Atomic extension for delegating tasks to subagents with parallel execution. Fork of: https://github.com/nicobailon/pi-subagents",
6
6
  "contributors": [
@@ -4,7 +4,7 @@ description: Browser automation CLI for AI agents. Use when the user needs to in
4
4
  hidden: true
5
5
  metadata:
6
6
  github-path: skills/agent-browser
7
- github-ref: refs/tags/v0.38.2
7
+ github-ref: refs/tags/v0.39.1
8
8
  github-repo: https://github.com/vercel-labs/agent-browser
9
9
  github-tree-sha: 82def67855a0d2aad7794207951820fa5422fdb0
10
10
  name: agent-browser
@@ -109,7 +109,13 @@ title looks close.
109
109
  `get_browser_state` is strictly read-only. It never launches a browser,
110
110
  changes a profile, enables remote debugging, or accepts a consent prompt. If
111
111
  it returns `browser_requires_setup` or `browser_consent_required`, choose one
112
- explicit preparation flow. A standalone consumer browser cannot bind through
112
+ explicit preparation flow. For the user's running Chrome, Edge or Brave the
113
+ refusal's `detail.next_call` is the exact `browser_prepare` call to make next
114
+ (`pid`, `window_id`, `session`, `strategy:{"kind":"existing_profile"}`). It is
115
+ the driver's own setup step, not a question for the user: make the call, and it
116
+ attaches or refuses with nothing changed and says why. Do not fall back to
117
+ desktop-target pointer tools for the page; they move the user's real pointer,
118
+ and over a background window they refuse. A standalone consumer browser cannot bind through
113
119
  a DevTools listener merely because the listener belongs to that process.
114
120
 
115
121
  ### Driver-owned isolated profile
@@ -153,6 +159,18 @@ or terminates an existing personal profile. The result returns a
153
159
  `prepared_pid`; list that process's windows and bind the new `(pid,
154
160
  window_id)`.
155
161
 
162
+ The result's optional `lifecycle` object describes how long the browser
163
+ process lives: `owner` is `session`, `idle_expires_in_seconds` is how long the
164
+ session may stay idle after this call before it and the browser end,
165
+ `process_ends_with_session` is `true`, and
166
+ `profile_persists_after_session` is `true` only for `isolated_named`. The
167
+ value is advisory, not a lease. `get_session` reports the remaining time later
168
+ but does not keep the browser alive, and explicit `end_session`, disconnect,
169
+ revocation, or shutdown ends the browser earlier. A named profile keeps its
170
+ files, not the process or its open pages. Attachments to an existing profile
171
+ or endpoint the driver did not launch, and sessions already ending, have no
172
+ `lifecycle`.
173
+
156
174
  ### Existing profile
157
175
 
158
176
  Attaching to an authenticated profile requires explicit trusted launch or host
@@ -199,6 +217,31 @@ transition on that same control. Unsupported appearance, scale, zoom,
199
217
  window-size, or toolbar geometry refuses without a click; the fallback does not
200
218
  authorize generic pixel interaction.
201
219
 
220
+ On macOS this attachment cannot stay in the background. Chrome brings itself
221
+ to the front to show its "Allow remote debugging?" prompt for every new
222
+ DevTools connection, and turning remote debugging on needs Chrome in front.
223
+ Chrome does not prompt again for tabs or targets reached over a connection it
224
+ already allowed, so the driver keeps one approved connection per running
225
+ Chrome and every session for that Chrome shares it: a second session, or a new
226
+ session after the previous one ended, attaches without another prompt. Each
227
+ session still needs its own `browser_prepare` approval from the driver, and
228
+ only sees the targets it bound. The shared connection closes after 30 minutes
229
+ without a session, 8 hours after the prompt that opened it, when the daemon
230
+ restarts, on `cua-driver revoke --all`, or when the driver turns remote
231
+ debugging back off; the next session after that prompts once again.
232
+ When the Chrome window is on another Space than the user's, the attach runs in
233
+ the background: the driver turns remote debugging on without bringing Chrome
234
+ forward, and reverts Chrome's own brief activations (its consent window opens
235
+ on Chrome's Space, out of the user's sight) within milliseconds, giving the
236
+ user's window front and key status back. On the user's Space, while another
237
+ app is in front, `browser_prepare` with `strategy.kind:"existing_profile"`
238
+ refuses with `background_unavailable` before it opens a tab or connects. Keep
239
+ or put Chrome on another Space, or pass `delivery_mode:"foreground"` only when
240
+ nobody is using the screen or the user agreed to Chrome coming forward; the
241
+ driver then brings the previous app back and reports
242
+ `side_effects.restored_frontmost_app`. If the user is working in another app,
243
+ read the Chrome window with `get_window_state` instead.
244
+
202
245
  Chrome 144 and later can expose its agent auto-connect bridge from the running
203
246
  profile. After approval, Cua reads the exact port and browser WebSocket path
204
247
  from that process's `DevToolsActivePort` file, cross-checks the loopback socket
@@ -348,11 +391,12 @@ browser_click
348
391
  Before dispatch, the driver refreshes the element box and hit-tests the point.
349
392
  It refuses stale, covered, or ambiguous targets.
350
393
 
351
- Standalone Chromium on macOS and Linux can activate its native window when
352
- trusted CDP pointer input is used. CUA Driver detects that limitation and
353
- returns `browser_input_trust_unavailable` before dispatch instead of claiming
354
- background delivery. Windows Chrome and Edge have validated trusted
355
- background delivery.
394
+ Standalone Chromium on Linux can activate its native window when trusted CDP
395
+ pointer input is used. CUA Driver detects that limitation and returns
396
+ `browser_input_trust_unavailable` before dispatch instead of claiming
397
+ background delivery. Chrome and Edge on Windows, and Chrome on macOS, deliver
398
+ trusted input in the background, including to an inactive (hidden) tab,
399
+ without activating or raising the browser window.
356
400
 
357
401
  When the application semantics allow a synthetic JavaScript click, request it
358
402
  explicitly with a current ref:
@@ -363,8 +407,11 @@ browser_click
363
407
  "input_route":"dom_event","session":"browser-run-1"}'
364
408
  ```
365
409
 
366
- `dom_event` calls the page element's click behavior without pretending that a
367
- trusted pointer event occurred. It requires a ref and is the full-background
410
+ `dom_event` replays a primary-button click as synthetic DOM events at the
411
+ element's center: pointer and mouse over, move, down, up, then `click`. Apps
412
+ that open rows or menus from pointer or mouse down/up, as many React tables
413
+ do, respond to it; it does not pretend that a trusted pointer event occurred.
414
+ Controls that check `event.isTrusted` still need the trusted route. It requires a ref and is the full-background
368
415
  alternative where supported. Dispatch is not proof that the control activated:
369
416
  trust-gated controls can ignore synthetic events, so refresh page state and
370
417
  verify the expected postcondition. Never silently change trust class or
@@ -204,8 +204,13 @@ daemon child.
204
204
 
205
205
  After an input action, the driver watches the window list for a short time so
206
206
  it can report a menu, dialog, or new window that the action opened. On macOS,
207
- that watch lasts up to 1000 ms for an action that opens nothing, which makes it
208
- the largest part of a background click's latency. A host that already observes
207
+ the watch lasts up to 1000 ms. The action's result waits for at most the first
208
+ 300 ms of it; when nothing has changed by then, the result returns and the rest
209
+ of the watch runs detached, still holding the focus-steal lease. A window that
210
+ opens during that remainder is reported on the next action's result as
211
+ `After the previous action returned, it opened new window(s): …`. The next
212
+ action, or any activation the driver performs, ends the detached remainder
213
+ first. On Linux X11 the result waits for the whole watch. A host that already observes
209
214
  its target continuously can shorten it through two variables set at trusted
210
215
  launch, in the environment of the `serve --embedded` child (or of the host
211
216
  process when you use the same-process runtime). `EmbeddedCuaDriverHost` starts
@@ -77,7 +77,7 @@ sentence naming the call that targets each one
77
77
  (`get_window_state(pid, window_id=<that id>)`). When one overlaps the window
78
78
  the screenshot is taken from the screen (`screenshot_composited:true`) so the
79
79
  menu or dialog is visible; the window's own drawable never shows them. The
80
- payload states its frame (`coordinate_frame:"window"`, `frame_note`): `x`/`y`
80
+ payload states its frame (`coordinate_frame:"window"`, plus `frame_note` with `verbose:true`): `x`/`y`
81
81
  of the pointer tools are pixels of THIS screenshot. Closed menus are listed
82
82
  with a `description` ("closed menu with N items…") and are not walked;
83
83
  click the menu (a real press) and read the popup by its window_id.
@@ -212,6 +212,12 @@ doctor` now probes `org.a11y.Bus` for real (not just "is there a bus?")
212
212
  daemon as root against a user session is the Linux analogue of the Windows
213
213
  "Session 0" isolation problem.
214
214
 
215
+ `get_window_state` returns one compact markdown tree capped at 250 actionable
216
+ nodes by default (`full_output:true` restores 5 000 nodes and both forms), and
217
+ `since:<snapshot_id>` returns only added/changed/removed rows. The focused
218
+ element is not reported on Linux yet, so an unchanged read says only
219
+ `no change since …`.
220
+
215
221
  An empty AT-SPI walk is now surfaced honestly: `get_window_state` sets
216
222
  `degraded: true` + a `degraded_reason` (instead of a bare `elements: []`) so a
217
223
  caller can tell "this window genuinely has no controls" apart from "the a11y