@bastani/atomic 0.9.41-alpha.3 → 0.9.42-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 (271) hide show
  1. package/CHANGELOG.md +122 -0
  2. package/dist/builtin/intercom/CHANGELOG.md +25 -0
  3. package/dist/builtin/intercom/README.md +7 -3
  4. package/dist/builtin/intercom/broker/broker-status.ts +48 -0
  5. package/dist/builtin/intercom/broker/broker.ts +90 -9
  6. package/dist/builtin/intercom/broker/client.ts +112 -12
  7. package/dist/builtin/intercom/broker/control.ts +225 -0
  8. package/dist/builtin/intercom/broker/multinode-router.ts +32 -39
  9. package/dist/builtin/intercom/broker/paths.ts +4 -0
  10. package/dist/builtin/intercom/broker/pending-send-registry.ts +27 -5
  11. package/dist/builtin/intercom/broker/shared-storage-setting.ts +60 -0
  12. package/dist/builtin/intercom/broker/spawn.ts +13 -4
  13. package/dist/builtin/intercom/broker/sql-lease-store.ts +23 -0
  14. package/dist/builtin/intercom/broker/watchdog.ts +105 -0
  15. package/dist/builtin/intercom/index.bundle.mjs +200 -22
  16. package/dist/builtin/intercom/package.json +1 -1
  17. package/dist/builtin/intercom/types.ts +34 -2
  18. package/dist/builtin/mcp/package.json +1 -1
  19. package/dist/builtin/subagents/CHANGELOG.md +14 -0
  20. package/dist/builtin/subagents/package.json +1 -1
  21. package/dist/builtin/subagents/src/extension/index.bundle.mjs +1 -0
  22. package/dist/builtin/web-access/package.json +1 -1
  23. package/dist/builtin/workflows/CHANGELOG.md +40 -0
  24. package/dist/builtin/workflows/README.md +10 -0
  25. package/dist/builtin/workflows/builtin/{chunk-txbc93t6.js → chunk-3s95f7ry.js} +1 -1
  26. package/dist/builtin/workflows/builtin/{chunk-n2gkzkty.js → chunk-edhf30ef.js} +1 -1
  27. package/dist/builtin/workflows/builtin/{chunk-8x61e0s7.js → chunk-frqxd4d1.js} +18 -9
  28. package/dist/builtin/workflows/builtin/goal.js +2 -2
  29. package/dist/builtin/workflows/builtin/index.js +3 -3
  30. package/dist/builtin/workflows/builtin/ralph.js +2 -2
  31. package/dist/builtin/workflows/package.json +6 -1
  32. package/dist/builtin/workflows/src/authoring.d.ts +3 -1
  33. package/dist/builtin/workflows/src/durable/journal/internal.d.ts +13 -0
  34. package/dist/builtin/workflows/src/durable/journal/resolution.d.ts +2 -0
  35. package/dist/builtin/workflows/src/durable/journal/sql-run-journal.d.ts +1 -0
  36. package/dist/builtin/workflows/src/extension/index.bundle.mjs +88554 -82820
  37. package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +72635 -0
  38. package/dist/builtin/workflows/src/index.js +53824 -5907
  39. package/dist/builtin/workflows/src/local-worker-entry.mjs +72635 -0
  40. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +7 -0
  41. package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +2 -0
  42. package/dist/builtin/workflows/src/workers/public-options.d.ts +31 -0
  43. package/dist/bun/app-host-modules.d.ts +9 -0
  44. package/dist/bun/app-host-modules.d.ts.map +1 -0
  45. package/dist/bun/app-host-modules.js +10 -0
  46. package/dist/bun/app-host-modules.js.map +1 -0
  47. package/dist/bun/cli.d.ts +3 -1
  48. package/dist/bun/cli.d.ts.map +1 -1
  49. package/dist/bun/cli.js +15 -1
  50. package/dist/bun/cli.js.map +1 -1
  51. package/dist/bun/internal-intercom-broker.d.ts +17 -0
  52. package/dist/bun/internal-intercom-broker.d.ts.map +1 -1
  53. package/dist/bun/internal-intercom-broker.js +29 -0
  54. package/dist/bun/internal-intercom-broker.js.map +1 -1
  55. package/dist/bun/internal-workflow-worker.d.ts +4 -0
  56. package/dist/bun/internal-workflow-worker.d.ts.map +1 -0
  57. package/dist/bun/internal-workflow-worker.js +37 -0
  58. package/dist/bun/internal-workflow-worker.js.map +1 -0
  59. package/dist/bun/split-loader.js +10 -2
  60. package/dist/bun/split-loader.js.map +1 -1
  61. package/dist/cli/args.d.ts.map +1 -1
  62. package/dist/cli/args.js +3 -1
  63. package/dist/cli/args.js.map +1 -1
  64. package/dist/cli/intercom-command.d.ts +15 -0
  65. package/dist/cli/intercom-command.d.ts.map +1 -0
  66. package/dist/cli/intercom-command.js +87 -0
  67. package/dist/cli/intercom-command.js.map +1 -0
  68. package/dist/cli/storage-command.d.ts +39 -0
  69. package/dist/cli/storage-command.d.ts.map +1 -0
  70. package/dist/cli/storage-command.js +367 -0
  71. package/dist/cli/storage-command.js.map +1 -0
  72. package/dist/core/agent-session-events.d.ts.map +1 -1
  73. package/dist/core/agent-session-events.js +5 -1
  74. package/dist/core/agent-session-events.js.map +1 -1
  75. package/dist/core/agent-session-methods.d.ts +1 -0
  76. package/dist/core/agent-session-methods.d.ts.map +1 -1
  77. package/dist/core/agent-session-methods.js.map +1 -1
  78. package/dist/core/agent-session-tasks.d.ts.map +1 -1
  79. package/dist/core/agent-session-tasks.js +1 -0
  80. package/dist/core/agent-session-tasks.js.map +1 -1
  81. package/dist/core/agent-session-types.d.ts +1 -0
  82. package/dist/core/agent-session-types.d.ts.map +1 -1
  83. package/dist/core/agent-session-types.js.map +1 -1
  84. package/dist/core/agent-session.d.ts +1 -0
  85. package/dist/core/agent-session.d.ts.map +1 -1
  86. package/dist/core/agent-session.js +2 -0
  87. package/dist/core/agent-session.js.map +1 -1
  88. package/dist/core/builtin-install-layout.d.ts +6 -0
  89. package/dist/core/builtin-install-layout.d.ts.map +1 -1
  90. package/dist/core/builtin-install-layout.js +9 -0
  91. package/dist/core/builtin-install-layout.js.map +1 -1
  92. package/dist/core/child-session-options.d.ts.map +1 -1
  93. package/dist/core/child-session-options.js +3 -0
  94. package/dist/core/child-session-options.js.map +1 -1
  95. package/dist/core/exec.js +2 -2
  96. package/dist/core/exec.js.map +1 -1
  97. package/dist/core/export-html/template.css +9 -0
  98. package/dist/core/export-html/template.js +165 -45
  99. package/dist/core/extensions/loader-host-modules.d.ts +6 -0
  100. package/dist/core/extensions/loader-host-modules.d.ts.map +1 -1
  101. package/dist/core/extensions/loader-host-modules.js +12 -1
  102. package/dist/core/extensions/loader-host-modules.js.map +1 -1
  103. package/dist/core/extensions/loader-virtual-modules.d.ts +6 -0
  104. package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
  105. package/dist/core/extensions/loader-virtual-modules.js +18 -0
  106. package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
  107. package/dist/core/extensions/message-types.d.ts +4 -0
  108. package/dist/core/extensions/message-types.d.ts.map +1 -1
  109. package/dist/core/extensions/message-types.js.map +1 -1
  110. package/dist/core/fast-model-routing-transport.d.ts.map +1 -1
  111. package/dist/core/fast-model-routing-transport.js +5 -1
  112. package/dist/core/fast-model-routing-transport.js.map +1 -1
  113. package/dist/core/intercom-broker-control.d.ts +67 -0
  114. package/dist/core/intercom-broker-control.d.ts.map +1 -0
  115. package/dist/core/intercom-broker-control.js +17 -0
  116. package/dist/core/intercom-broker-control.js.map +1 -0
  117. package/dist/core/model-runtime-streaming.d.ts.map +1 -1
  118. package/dist/core/model-runtime-streaming.js +38 -1
  119. package/dist/core/model-runtime-streaming.js.map +1 -1
  120. package/dist/core/package-manager-git.d.ts +2 -2
  121. package/dist/core/package-manager-git.d.ts.map +1 -1
  122. package/dist/core/package-manager-git.js.map +1 -1
  123. package/dist/core/package-manager-manifest.d.ts.map +1 -1
  124. package/dist/core/package-manager-manifest.js +9 -1
  125. package/dist/core/package-manager-manifest.js.map +1 -1
  126. package/dist/core/package-manager-npm.d.ts +2 -2
  127. package/dist/core/package-manager-npm.d.ts.map +1 -1
  128. package/dist/core/package-manager-npm.js.map +1 -1
  129. package/dist/core/package-manager-paths.d.ts +7 -7
  130. package/dist/core/package-manager-paths.d.ts.map +1 -1
  131. package/dist/core/package-manager-paths.js.map +1 -1
  132. package/dist/core/package-manager-storage-adapters.d.ts +7 -0
  133. package/dist/core/package-manager-storage-adapters.d.ts.map +1 -0
  134. package/dist/core/package-manager-storage-adapters.js +76 -0
  135. package/dist/core/package-manager-storage-adapters.js.map +1 -0
  136. package/dist/core/package-manager-types.d.ts +4 -0
  137. package/dist/core/package-manager-types.d.ts.map +1 -1
  138. package/dist/core/package-manager-types.js.map +1 -1
  139. package/dist/core/provider-rate-limits.d.ts +23 -0
  140. package/dist/core/provider-rate-limits.d.ts.map +1 -0
  141. package/dist/core/provider-rate-limits.js +113 -0
  142. package/dist/core/provider-rate-limits.js.map +1 -0
  143. package/dist/core/provider-request-admission.d.ts +7 -0
  144. package/dist/core/provider-request-admission.d.ts.map +1 -0
  145. package/dist/core/provider-request-admission.js +91 -0
  146. package/dist/core/provider-request-admission.js.map +1 -0
  147. package/dist/core/resource-admission-scope.d.ts +4 -0
  148. package/dist/core/resource-admission-scope.d.ts.map +1 -0
  149. package/dist/core/resource-admission-scope.js +9 -0
  150. package/dist/core/resource-admission-scope.js.map +1 -0
  151. package/dist/core/sdk-types.d.ts +16 -0
  152. package/dist/core/sdk-types.d.ts.map +1 -1
  153. package/dist/core/sdk-types.js.map +1 -1
  154. package/dist/core/sdk.d.ts +2 -1
  155. package/dist/core/sdk.d.ts.map +1 -1
  156. package/dist/core/sdk.js +18 -2
  157. package/dist/core/sdk.js.map +1 -1
  158. package/dist/core/session-lifecycle-work.d.ts +1 -0
  159. package/dist/core/session-lifecycle-work.d.ts.map +1 -1
  160. package/dist/core/session-lifecycle-work.js +1 -0
  161. package/dist/core/session-lifecycle-work.js.map +1 -1
  162. package/dist/core/settings-manager-basic-accessors.d.ts +3 -0
  163. package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
  164. package/dist/core/settings-manager-basic-accessors.js +6 -0
  165. package/dist/core/settings-manager-basic-accessors.js.map +1 -1
  166. package/dist/core/settings-schema.d.ts +22 -0
  167. package/dist/core/settings-schema.d.ts.map +1 -1
  168. package/dist/core/settings-schema.js +18 -1
  169. package/dist/core/settings-schema.js.map +1 -1
  170. package/dist/core/storage/index.d.ts +1 -0
  171. package/dist/core/storage/index.d.ts.map +1 -1
  172. package/dist/core/storage/index.js +1 -0
  173. package/dist/core/storage/index.js.map +1 -1
  174. package/dist/core/storage/node-sqlite.d.ts +2 -1
  175. package/dist/core/storage/node-sqlite.d.ts.map +1 -1
  176. package/dist/core/storage/node-sqlite.js +5 -4
  177. package/dist/core/storage/node-sqlite.js.map +1 -1
  178. package/dist/core/storage/provider.d.ts +6 -0
  179. package/dist/core/storage/provider.d.ts.map +1 -1
  180. package/dist/core/storage/provider.js +27 -7
  181. package/dist/core/storage/provider.js.map +1 -1
  182. package/dist/core/storage/sqlite-facade.d.ts +49 -0
  183. package/dist/core/storage/sqlite-facade.d.ts.map +1 -0
  184. package/dist/core/storage/sqlite-facade.js +180 -0
  185. package/dist/core/storage/sqlite-facade.js.map +1 -0
  186. package/dist/core/storage/storage-status.d.ts +81 -0
  187. package/dist/core/storage/storage-status.d.ts.map +1 -0
  188. package/dist/core/storage/storage-status.js +409 -0
  189. package/dist/core/storage/storage-status.js.map +1 -0
  190. package/dist/core/tasks/supervisor.d.ts +2 -1
  191. package/dist/core/tasks/supervisor.d.ts.map +1 -1
  192. package/dist/core/tasks/supervisor.js +105 -4
  193. package/dist/core/tasks/supervisor.js.map +1 -1
  194. package/dist/core/tools/bash-pty-native.d.ts.map +1 -1
  195. package/dist/core/tools/bash-pty-native.js +1 -1
  196. package/dist/core/tools/bash-pty-native.js.map +1 -1
  197. package/dist/index.d.ts +2 -1
  198. package/dist/index.d.ts.map +1 -1
  199. package/dist/index.js +2 -1
  200. package/dist/index.js.map +1 -1
  201. package/dist/main.d.ts.map +1 -1
  202. package/dist/main.js +28 -2
  203. package/dist/main.js.map +1 -1
  204. package/dist/modes/interactive/components/assistant-message.d.ts +3 -1
  205. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  206. package/dist/modes/interactive/components/assistant-message.js +7 -3
  207. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  208. package/dist/modes/interactive/components/chat-message-renderer.d.ts +9 -1
  209. package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
  210. package/dist/modes/interactive/components/chat-message-renderer.js +16 -8
  211. package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
  212. package/dist/modes/interactive/components/login-dialog.d.ts +5 -0
  213. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  214. package/dist/modes/interactive/components/login-dialog.js +69 -2
  215. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  216. package/dist/modes/interactive/components/markdown-transform.d.ts +1 -1
  217. package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -1
  218. package/dist/modes/interactive/components/markdown-transform.js +2 -2
  219. package/dist/modes/interactive/components/markdown-transform.js.map +1 -1
  220. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  221. package/dist/modes/interactive/components/session-selector-search.js +80 -22
  222. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  223. package/dist/modes/interactive/components/user-message.d.ts +3 -1
  224. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  225. package/dist/modes/interactive/components/user-message.js +6 -2
  226. package/dist/modes/interactive/components/user-message.js.map +1 -1
  227. package/dist/modes/interactive/interactive-mode-deps.d.ts +1 -1
  228. package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
  229. package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
  230. package/dist/modes/interactive/interactive-render-chat.js +6 -2
  231. package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
  232. package/dist/modes/interactive-engine/engine-health.d.ts +8 -4
  233. package/dist/modes/interactive-engine/engine-health.d.ts.map +1 -1
  234. package/dist/modes/interactive-engine/engine-health.js +41 -6
  235. package/dist/modes/interactive-engine/engine-health.js.map +1 -1
  236. package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
  237. package/dist/modes/interactive-engine/isolated-runtime.js +19 -17
  238. package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
  239. package/dist/modes/interactive-engine/remote-queue-pause.js +1 -1
  240. package/dist/modes/interactive-engine/remote-queue-pause.js.map +1 -1
  241. package/dist/modes/rpc/rpc-input-scheduler.d.ts +1 -0
  242. package/dist/modes/rpc/rpc-input-scheduler.d.ts.map +1 -1
  243. package/dist/modes/rpc/rpc-input-scheduler.js +4 -1
  244. package/dist/modes/rpc/rpc-input-scheduler.js.map +1 -1
  245. package/dist/modes/rpc/rpc-input.d.ts.map +1 -1
  246. package/dist/modes/rpc/rpc-input.js +29 -7
  247. package/dist/modes/rpc/rpc-input.js.map +1 -1
  248. package/dist/utils/shell.d.ts.map +1 -1
  249. package/dist/utils/shell.js +14 -0
  250. package/dist/utils/shell.js.map +1 -1
  251. package/docs/custom-provider/oauth.md +8 -1
  252. package/docs/extensions/api-reference.md +2 -0
  253. package/docs/intercom/operations.md +17 -8
  254. package/docs/intercom/reference.md +1 -1
  255. package/docs/keybindings.md +1 -1
  256. package/docs/packages/authoring.md +15 -0
  257. package/docs/packages.md +3 -2
  258. package/docs/providers.md +2 -0
  259. package/docs/reference/cli.md +17 -0
  260. package/docs/sdk.md +37 -0
  261. package/docs/settings.md +33 -2
  262. package/docs/storage.md +191 -219
  263. package/docs/usage.md +1 -1
  264. package/docs/workflows/api-reference.md +50 -0
  265. package/docs/workflows/operations.md +44 -1
  266. package/docs/workflows.md +25 -0
  267. package/examples/extensions/gondolin/package-lock.json +14 -24
  268. package/examples/extensions/gondolin/package.json +1 -1
  269. package/npm-shrinkwrap.json +35 -35
  270. package/package.json +4 -4
  271. package/schemas/settings.schema.json +87 -1
@@ -585,6 +585,32 @@ function createMessageReader(onMessage, onError) {
585
585
  };
586
586
  }
587
587
 
588
+ // dist/builtin/intercom/broker/broker-status.ts
589
+ function isObject(value) {
590
+ return typeof value === "object" && value !== null && !Array.isArray(value);
591
+ }
592
+ function isOptionalString(value) {
593
+ return value === undefined || typeof value === "string";
594
+ }
595
+ function isBrokerStatusReport(value) {
596
+ if (!isObject(value) || typeof value.pid !== "number" || typeof value.sessions !== "number")
597
+ return false;
598
+ const { storage, multiNode } = value;
599
+ if (storage !== undefined && (!isObject(storage) || typeof storage.digest !== "string" || storage.source !== "env" && storage.source !== "settings"))
600
+ return false;
601
+ return isObject(multiNode) && (multiNode.status === "off" || multiNode.status === "starting" || multiNode.status === "on" || multiNode.status === "unavailable") && isOptionalString(multiNode.reason) && isOptionalString(multiNode.adapter) && isOptionalString(multiNode.prefix) && (multiNode.peers === undefined || Array.isArray(multiNode.peers) && multiNode.peers.every((peer) => typeof peer === "string"));
602
+ }
603
+ function describeMultiNodeStatus(multiNode) {
604
+ const storage = multiNode.adapter === undefined ? "" : ` (adapter ${multiNode.adapter}, prefix ${multiNode.prefix ?? "none"})`;
605
+ if (multiNode.status === "off" || multiNode.status === "unavailable") {
606
+ return `${multiNode.status}${storage}${multiNode.reason === undefined ? "" : `: ${multiNode.reason}`}`;
607
+ }
608
+ if (multiNode.status === "starting" || multiNode.peers === undefined)
609
+ return `${multiNode.status}${storage}`;
610
+ const count = `${multiNode.peers.length} peer broker${multiNode.peers.length === 1 ? "" : "s"} live`;
611
+ return `on${storage}, ${count}${multiNode.peers.length === 0 ? "" : ` (${[...new Set(multiNode.peers)].join(", ")})`}`;
612
+ }
613
+
588
614
  // dist/builtin/intercom/broker/paths.ts
589
615
  import { homedir } from "os";
590
616
  import { join } from "path";
@@ -730,14 +756,14 @@ class PendingSendRegistry {
730
756
  generation
731
757
  };
732
758
  attempt.timer = setTimeout(() => {
733
- this.reject(attempt, new Error("Send timeout"));
759
+ this.expire(attempt);
734
760
  }, timeoutMs);
735
761
  this.attempts.set(messageId, attempt);
736
762
  return { attempt, owner: true };
737
763
  }
738
764
  resolve(messageId, attemptId, result) {
739
765
  const attempt = this.attempts.get(messageId);
740
- if (!attempt || attempt.attemptId !== attemptId)
766
+ if (!attempt || attempt.timedOut || attempt.attemptId !== attemptId)
741
767
  return false;
742
768
  this.attempts.delete(messageId);
743
769
  if (attempt.timer)
@@ -748,21 +774,36 @@ class PendingSendRegistry {
748
774
  }
749
775
  extend(messageId, attemptId, timeoutMs) {
750
776
  const attempt = this.attempts.get(messageId);
751
- if (!attempt || (attemptId === undefined ? !attempt.legacyEligible : attempt.attemptId !== attemptId))
777
+ if (!attempt || attempt.timedOut || (attemptId === undefined ? !attempt.legacyEligible : attempt.attemptId !== attemptId))
752
778
  return false;
753
779
  if (attempt.timer)
754
780
  clearTimeout(attempt.timer);
755
781
  attempt.timer = setTimeout(() => {
756
- this.reject(attempt, new Error("Send timeout"));
782
+ this.expire(attempt);
757
783
  }, timeoutMs);
758
784
  return true;
759
785
  }
760
786
  resolveLegacy(messageId, result) {
761
787
  const attempt = this.attempts.get(messageId);
762
- if (!attempt?.legacyEligible)
788
+ if (!attempt?.legacyEligible || attempt.timedOut)
763
789
  return false;
764
790
  return this.resolve(messageId, attempt.attemptId, result);
765
791
  }
792
+ expire(attempt) {
793
+ if (this.attempts.get(attempt.messageId) !== attempt)
794
+ return;
795
+ attempt.timedOut = true;
796
+ attempt.timer = undefined;
797
+ attempt.reject(new PendingSendTimeoutError);
798
+ }
799
+ release(attempt) {
800
+ const current = this.attempts.get(attempt.messageId);
801
+ if (current !== attempt || !current.timedOut)
802
+ return false;
803
+ this.attempts.delete(attempt.messageId);
804
+ this.touchGeneration(current);
805
+ return true;
806
+ }
766
807
  reject(attempt, error) {
767
808
  const current = this.attempts.get(attempt.messageId);
768
809
  if (current !== attempt)
@@ -779,9 +820,14 @@ class PendingSendRegistry {
779
820
  this.reject(attempt, error);
780
821
  }
781
822
  }
782
- var DEFAULT_GENERATION_TTL_MS, DEFAULT_MAX_GENERATIONS = 1e4;
823
+ var DEFAULT_GENERATION_TTL_MS, DEFAULT_MAX_GENERATIONS = 1e4, PendingSendTimeoutError;
783
824
  var init_pending_send_registry = __esm(() => {
784
825
  DEFAULT_GENERATION_TTL_MS = 10 * 60 * 1000;
826
+ PendingSendTimeoutError = class PendingSendTimeoutError extends Error {
827
+ constructor() {
828
+ super("Send timeout");
829
+ }
830
+ };
785
831
  });
786
832
 
787
833
  // dist/builtin/intercom/source-ownership.ts
@@ -878,16 +924,19 @@ var init_client = __esm(() => {
878
924
  connectTimeoutMs;
879
925
  brokerAcknowledgesReceipt = false;
880
926
  brokerAcknowledgesPendingStageRoutes = false;
927
+ brokerAnswersStatus = false;
881
928
  socket = null;
882
929
  _sessionId = null;
883
930
  _supervisorSessionId = null;
884
931
  _messageSource;
885
932
  pendingSends = new PendingSendRegistry;
933
+ sendResults = new WeakMap;
886
934
  pendingReplyTargets = new Map;
887
935
  pendingGroupLists = new Map;
888
936
  pendingLists = new Map;
889
937
  pendingPresence = new Map;
890
938
  pendingMemberships = new Map;
939
+ pendingBrokerStatus = new Map;
891
940
  _groups = normalizeGroups();
892
941
  pendingLiveWorkflowStageRoutes = new Map;
893
942
  pendingStageRouteRegistrations = new Map;
@@ -895,6 +944,43 @@ var init_client = __esm(() => {
895
944
  pendingRestoringRecipientRequests = new Map;
896
945
  disconnecting = false;
897
946
  disconnectError = null;
947
+ healthCheck;
948
+ async requestTimeout(socket, error) {
949
+ if (this.socket !== socket || socket.destroyed)
950
+ return this.disconnectError ?? new IntercomClientDisconnectedError;
951
+ if (this.healthCheck?.socket !== socket) {
952
+ const requestId = randomUUID2();
953
+ const result = new Promise((resolve) => {
954
+ const finish = (failure) => {
955
+ clearTimeout(timer);
956
+ this.pendingGroupLists.delete(requestId);
957
+ resolve(failure);
958
+ };
959
+ const timer = setTimeout(() => finish(new IntercomBrokerTimeoutError("Broker health check timed out")), GROUP_REQUEST_TIMEOUT_MS);
960
+ this.pendingGroupLists.set(requestId, { resolve: () => finish(), reject: finish });
961
+ try {
962
+ writeMessage(socket, { type: "list_groups", requestId });
963
+ } catch (cause) {
964
+ finish(new IntercomClientDisconnectedError({ cause }));
965
+ }
966
+ });
967
+ this.healthCheck = { socket, result };
968
+ }
969
+ const check = this.healthCheck;
970
+ const failure = await check.result;
971
+ if (this.healthCheck === check)
972
+ this.healthCheck = undefined;
973
+ if (failure === undefined)
974
+ return error;
975
+ const reported = failure instanceof IntercomBrokerTimeoutError ? new IntercomBrokerTimeoutError(error.message, { cause: failure }) : failure;
976
+ if (this.socket === socket && !this.disconnecting) {
977
+ this.disconnectError ??= reported;
978
+ this.failPending(this.disconnectError);
979
+ socket.destroy();
980
+ return this.disconnectError;
981
+ }
982
+ return reported;
983
+ }
898
984
  constructor(returnAddress = randomUUID2(), options = {}) {
899
985
  super();
900
986
  if (returnAddress.length === 0)
@@ -922,6 +1008,8 @@ var init_client = __esm(() => {
922
1008
  pending.reject(error);
923
1009
  for (const pending of this.pendingStageRouteRegistrations.values())
924
1010
  pending.reject(error);
1011
+ for (const pending of this.pendingBrokerStatus.values())
1012
+ pending.reject(error);
925
1013
  this.pendingLists.clear();
926
1014
  this.pendingGroupLists.clear();
927
1015
  this.pendingSupervisorAuthorizations.clear();
@@ -930,6 +1018,7 @@ var init_client = __esm(() => {
930
1018
  this.pendingMemberships.clear();
931
1019
  this.pendingLiveWorkflowStageRoutes.clear();
932
1020
  this.pendingStageRouteRegistrations.clear();
1021
+ this.pendingBrokerStatus.clear();
933
1022
  }
934
1023
  get sessionId() {
935
1024
  return this._sessionId;
@@ -1012,6 +1101,7 @@ var init_client = __esm(() => {
1012
1101
  this._supervisorSessionId = null;
1013
1102
  this.brokerAcknowledgesReceipt = false;
1014
1103
  this.brokerAcknowledgesPendingStageRoutes = false;
1104
+ this.brokerAnswersStatus = false;
1015
1105
  this._messageSource = undefined;
1016
1106
  this.disconnectError = null;
1017
1107
  if (connectionEstablished && !wasDisconnecting) {
@@ -1089,7 +1179,7 @@ var init_client = __esm(() => {
1089
1179
  }
1090
1180
  switch (brokerMessage.type) {
1091
1181
  case "registered": {
1092
- if (typeof brokerMessage.sessionId !== "string" || brokerMessage.supervisorSessionId !== undefined && typeof brokerMessage.supervisorSessionId !== "string" || brokerMessage.acknowledgesReceipt !== undefined && brokerMessage.acknowledgesReceipt !== true || brokerMessage.acknowledgesPendingStageRoutes !== undefined && brokerMessage.acknowledgesPendingStageRoutes !== true) {
1182
+ if (typeof brokerMessage.sessionId !== "string" || brokerMessage.supervisorSessionId !== undefined && typeof brokerMessage.supervisorSessionId !== "string" || brokerMessage.acknowledgesReceipt !== undefined && brokerMessage.acknowledgesReceipt !== true || brokerMessage.acknowledgesPendingStageRoutes !== undefined && brokerMessage.acknowledgesPendingStageRoutes !== true || brokerMessage.brokerStatus !== undefined && brokerMessage.brokerStatus !== true) {
1093
1183
  throw new Error("Invalid registered message");
1094
1184
  }
1095
1185
  if (this._sessionId !== null) {
@@ -1099,6 +1189,7 @@ var init_client = __esm(() => {
1099
1189
  this._supervisorSessionId = typeof brokerMessage.supervisorSessionId === "string" ? brokerMessage.supervisorSessionId : null;
1100
1190
  this.brokerAcknowledgesReceipt = this.acknowledgesReceipt && brokerMessage.acknowledgesReceipt === true;
1101
1191
  this.brokerAcknowledgesPendingStageRoutes = brokerMessage.acknowledgesPendingStageRoutes === true;
1192
+ this.brokerAnswersStatus = brokerMessage.brokerStatus === true;
1102
1193
  this.emit("_registered", { type: "registered", sessionId: brokerMessage.sessionId });
1103
1194
  break;
1104
1195
  }
@@ -1154,6 +1245,18 @@ var init_client = __esm(() => {
1154
1245
  pending.resolve(groups);
1155
1246
  break;
1156
1247
  }
1248
+ case "broker_status": {
1249
+ const { requestId } = brokerMessage;
1250
+ const report = brokerMessage.report;
1251
+ if (typeof requestId !== "string" || !isBrokerStatusReport(report))
1252
+ throw new Error("Invalid broker_status message");
1253
+ const pending = this.pendingBrokerStatus.get(requestId);
1254
+ if (!pending)
1255
+ return;
1256
+ this.pendingBrokerStatus.delete(requestId);
1257
+ pending.resolve(report);
1258
+ break;
1259
+ }
1157
1260
  case "supervisor_authorized": {
1158
1261
  const { requestId, capability, supervisorSessionId, childName } = brokerMessage;
1159
1262
  if (typeof requestId !== "string" || typeof capability !== "string" || typeof supervisorSessionId !== "string" || typeof childName !== "string") {
@@ -1455,7 +1558,7 @@ var init_client = __esm(() => {
1455
1558
  const timeout = setTimeout(() => {
1456
1559
  if (!this.pendingLists.delete(requestId))
1457
1560
  return;
1458
- reject(new Error("List sessions timeout"));
1561
+ this.requestTimeout(socket, new Error("List sessions timeout")).then(reject);
1459
1562
  }, 5000);
1460
1563
  this.pendingLists.set(requestId, {
1461
1564
  resolve: (directory) => {
@@ -1488,7 +1591,7 @@ var init_client = __esm(() => {
1488
1591
  const timeout = setTimeout(() => {
1489
1592
  if (!this.pendingGroupLists.delete(requestId))
1490
1593
  return;
1491
- reject(new Error("List groups timeout"));
1594
+ this.requestTimeout(socket, new Error("List groups timeout")).then(reject);
1492
1595
  }, GROUP_REQUEST_TIMEOUT_MS);
1493
1596
  this.pendingGroupLists.set(requestId, {
1494
1597
  resolve: (groups) => {
@@ -1509,6 +1612,41 @@ var init_client = __esm(() => {
1509
1612
  }
1510
1613
  });
1511
1614
  }
1615
+ brokerStatus() {
1616
+ let socket;
1617
+ try {
1618
+ socket = this.requireActiveSocket();
1619
+ } catch (error) {
1620
+ return Promise.reject(toError(error));
1621
+ }
1622
+ if (!this.brokerAnswersStatus)
1623
+ return Promise.resolve(undefined);
1624
+ const requestId = randomUUID2();
1625
+ return new Promise((resolve, reject) => {
1626
+ const timeout = setTimeout(() => {
1627
+ if (!this.pendingBrokerStatus.delete(requestId))
1628
+ return;
1629
+ reject(new Error("Broker status timeout"));
1630
+ }, GROUP_REQUEST_TIMEOUT_MS);
1631
+ this.pendingBrokerStatus.set(requestId, {
1632
+ resolve: (report) => {
1633
+ clearTimeout(timeout);
1634
+ resolve(report);
1635
+ },
1636
+ reject: (error) => {
1637
+ clearTimeout(timeout);
1638
+ reject(error);
1639
+ }
1640
+ });
1641
+ try {
1642
+ writeMessage(socket, { type: "broker_status", requestId });
1643
+ } catch (error) {
1644
+ clearTimeout(timeout);
1645
+ this.pendingBrokerStatus.delete(requestId);
1646
+ reject(toError(error));
1647
+ }
1648
+ });
1649
+ }
1512
1650
  joinGroup(group) {
1513
1651
  return this.updateMembership("join_group", group);
1514
1652
  }
@@ -1527,7 +1665,7 @@ var init_client = __esm(() => {
1527
1665
  const timeout = setTimeout(() => {
1528
1666
  if (!this.pendingMemberships.delete(requestId))
1529
1667
  return;
1530
- reject(new Error("Membership update timeout"));
1668
+ this.requestTimeout(socket, new Error("Membership update timeout")).then(reject);
1531
1669
  }, GROUP_REQUEST_TIMEOUT_MS);
1532
1670
  this.pendingMemberships.set(requestId, {
1533
1671
  resolve: (groups) => {
@@ -1563,7 +1701,7 @@ var init_client = __esm(() => {
1563
1701
  const timeout = setTimeout(() => {
1564
1702
  if (!this.pendingSupervisorAuthorizations.delete(requestId))
1565
1703
  return;
1566
- reject(new Error("Supervisor authorization timeout"));
1704
+ this.requestTimeout(socket, new Error("Supervisor authorization timeout")).then(reject);
1567
1705
  }, 5000);
1568
1706
  this.pendingSupervisorAuthorizations.set(requestId, {
1569
1707
  resolve: (authorization) => {
@@ -1614,7 +1752,7 @@ var init_client = __esm(() => {
1614
1752
  const timeout = setTimeout(() => {
1615
1753
  if (!this.pendingRestoringRecipientRequests.delete(requestId))
1616
1754
  return;
1617
- reject(new Error("Restoring-recipient request timeout"));
1755
+ this.requestTimeout(socket, new Error("Restoring-recipient request timeout")).then(reject);
1618
1756
  }, RESTORING_RECIPIENT_REQUEST_TIMEOUT_MS);
1619
1757
  this.pendingRestoringRecipientRequests.set(requestId, {
1620
1758
  resolve: () => {
@@ -1669,7 +1807,7 @@ var init_client = __esm(() => {
1669
1807
  const timeout = setTimeout(() => {
1670
1808
  if (!this.pendingStageRouteRegistrations.delete(requestId))
1671
1809
  return;
1672
- reject(new IntercomBrokerTimeoutError("Pending-stage route registration timeout"));
1810
+ this.requestTimeout(socket, new IntercomBrokerTimeoutError("Pending-stage route registration timeout")).then(reject);
1673
1811
  }, PENDING_STAGE_ROUTE_ACK_TIMEOUT_MS);
1674
1812
  this.pendingStageRouteRegistrations.set(requestId, {
1675
1813
  resolve: () => {
@@ -1783,8 +1921,22 @@ var init_client = __esm(() => {
1783
1921
  } catch (error) {
1784
1922
  return Promise.reject(toError(error));
1785
1923
  }
1924
+ let result = this.sendResults.get(acquired.attempt.promise);
1925
+ if (result === undefined) {
1926
+ result = acquired.attempt.promise.catch(async (error) => {
1927
+ if (error instanceof PendingSendTimeoutError) {
1928
+ try {
1929
+ throw await this.requestTimeout(socket, error);
1930
+ } finally {
1931
+ this.pendingSends.release(acquired.attempt);
1932
+ }
1933
+ }
1934
+ throw error;
1935
+ });
1936
+ this.sendResults.set(acquired.attempt.promise, result);
1937
+ }
1786
1938
  if (!acquired.owner)
1787
- return acquired.attempt.promise;
1939
+ return result;
1788
1940
  const message = {
1789
1941
  id: messageId,
1790
1942
  timestamp: Date.now(),
@@ -1817,7 +1969,7 @@ var init_client = __esm(() => {
1817
1969
  this.pendingReplyTargets.delete(acquired.attempt.attemptId);
1818
1970
  };
1819
1971
  acquired.attempt.promise.then(clearReplyTarget, clearReplyTarget);
1820
- return acquired.attempt.promise;
1972
+ return result;
1821
1973
  }
1822
1974
  updatePresence(updates) {
1823
1975
  if (this.disconnecting) {
@@ -1854,7 +2006,7 @@ var init_client = __esm(() => {
1854
2006
  const timeout = setTimeout(() => {
1855
2007
  if (!this.pendingPresence.delete(requestId))
1856
2008
  return;
1857
- reject(new Error("Presence update timeout"));
2009
+ this.requestTimeout(socket, new Error("Presence update timeout")).then(reject);
1858
2010
  }, PRESENCE_ACK_TIMEOUT_MS);
1859
2011
  this.pendingPresence.set(requestId, {
1860
2012
  resolve: wrappedResolve,
@@ -2039,7 +2191,16 @@ function getBrokerSpawnOptions(extensionDir = EXTENSION_DIR, stderr = "ignore")
2039
2191
  function resetBrokerLog(logPath = BROKER_LOG) {
2040
2192
  ensurePrivateDirectory(dirname(logPath));
2041
2193
  try {
2194
+ const previous = readBrokerLogTail(logPath);
2042
2195
  closeSync(openSync(logPath, "w"));
2196
+ if (previous.length > 0) {
2197
+ try {
2198
+ const previousPath = `${logPath}.previous`;
2199
+ writeFileSync(previousPath, Buffer.from(previous).subarray(-BROKER_LOG_TAIL_BYTES), { mode: 384 });
2200
+ if (process.platform !== "win32")
2201
+ chmodSync(previousPath, 384);
2202
+ } catch {}
2203
+ }
2043
2204
  return true;
2044
2205
  } catch (error) {
2045
2206
  const code = error.code;
@@ -2080,7 +2241,7 @@ ${tail}`;
2080
2241
  function toError2(error) {
2081
2242
  return error instanceof Error ? error : new Error(String(error));
2082
2243
  }
2083
- async function spawnBrokerIfNeeded(brokerCommand, brokerArgs, readyTimeoutMs = BROKER_READY_TIMEOUT_MS) {
2244
+ async function spawnBrokerIfNeeded(brokerCommand, brokerArgs, readyTimeoutMs = BROKER_READY_TIMEOUT_MS, extensionDir = EXTENSION_DIR) {
2084
2245
  ensurePrivateDirectory(INTERCOM_DIR);
2085
2246
  if (await isBrokerRunning()) {
2086
2247
  return;
@@ -2095,8 +2256,8 @@ async function spawnBrokerIfNeeded(brokerCommand, brokerArgs, readyTimeoutMs = B
2095
2256
  if (await isBrokerRunning()) {
2096
2257
  return;
2097
2258
  }
2098
- const brokerPath = resolveBrokerEntrypoint(EXTENSION_DIR);
2099
- const launch = getBrokerLaunchSpec(brokerPath, brokerCommand, brokerArgs);
2259
+ const brokerPath = resolveBrokerEntrypoint(extensionDir);
2260
+ const launch = getBrokerLaunchSpec(brokerPath, brokerCommand, brokerArgs, extensionDir);
2100
2261
  if (launch.kind === "windows-launcher") {
2101
2262
  writeWindowsHiddenLauncher(launch.launcherCommandLine, launch.launcherPath);
2102
2263
  }
@@ -2107,7 +2268,7 @@ async function spawnBrokerIfNeeded(brokerCommand, brokerArgs, readyTimeoutMs = B
2107
2268
  const logFd = launch.kind === "direct" ? openSync(BROKER_LOG, "a") : undefined;
2108
2269
  let child;
2109
2270
  try {
2110
- child = spawn(launch.command, launch.args, getBrokerSpawnOptions(EXTENSION_DIR, logFd ?? "ignore"));
2271
+ child = spawn(launch.command, launch.args, getBrokerSpawnOptions(extensionDir, logFd ?? "ignore"));
2111
2272
  } finally {
2112
2273
  if (logFd !== undefined)
2113
2274
  closeSync(logFd);
@@ -3753,6 +3914,19 @@ function retainInconclusiveRetry(reservations, attempt) {
3753
3914
  remainingRetries: reservations.remainingRetries(attempt)
3754
3915
  };
3755
3916
  }
3917
+ async function multiNodeStatus(client) {
3918
+ if (typeof client.brokerStatus !== "function")
3919
+ return;
3920
+ try {
3921
+ const report = await client.brokerStatus();
3922
+ if (report === undefined) {
3923
+ return { line: "unknown (the running broker predates status reporting; `atomic intercom restart` replaces it)" };
3924
+ }
3925
+ return { line: describeMultiNodeStatus(report.multiNode), multiNode: report.multiNode };
3926
+ } catch (error) {
3927
+ return { line: `unknown (${getErrorMessage(error)})` };
3928
+ }
3929
+ }
3756
3930
  async function listDirectory(client, group) {
3757
3931
  if (typeof client.listDirectory === "function")
3758
3932
  return client.listDirectory(group);
@@ -4750,6 +4924,9 @@ ${lines.join(`
4750
4924
  const selectedGroupSessions = selectedGroup === undefined ? undefined : await connectedClient.listSessions(selectedGroup);
4751
4925
  const selectedSection = selectedGroupSessions === undefined ? "" : `
4752
4926
  Selected group [${selectedGroup}]: ${selectedGroupSessions.length} session(s)`;
4927
+ const multiNode = await multiNodeStatus(connectedClient);
4928
+ const multiNodeSection = multiNode === undefined ? "" : `
4929
+ Multi-node routing: ${multiNode.line}`;
4753
4930
  return {
4754
4931
  content: [{
4755
4932
  type: "text",
@@ -4757,13 +4934,14 @@ Selected group [${selectedGroup}]: ${selectedGroupSessions.length} session(s)`;
4757
4934
  Connected: Yes
4758
4935
  Session ID: ${mySessionId}
4759
4936
  Groups: ${ownGroups.join(", ")}
4760
- Active visible sessions: ${sessions.length}${selectedSection}`
4937
+ Active visible sessions: ${sessions.length}${selectedSection}${multiNodeSection}`
4761
4938
  }],
4762
4939
  isError: false,
4763
4940
  details: {
4764
4941
  group: ownGroups.at(-1),
4765
4942
  groups: ownGroups,
4766
- ...selectedGroup === undefined ? {} : { selectedGroup, selectedGroupSessionCount: selectedGroupSessions?.length ?? 0 }
4943
+ ...selectedGroup === undefined ? {} : { selectedGroup, selectedGroupSessionCount: selectedGroupSessions?.length ?? 0 },
4944
+ ...multiNode?.multiNode === undefined ? {} : { multiNode: multiNode.multiNode }
4767
4945
  }
4768
4946
  };
4769
4947
  } catch (error) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/intercom",
3
- "version": "0.9.41-alpha.3",
3
+ "version": "0.9.42-alpha.1",
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": [
@@ -93,6 +93,28 @@ export interface GroupSummary {
93
93
  member: boolean;
94
94
  }
95
95
 
96
+ /** A broker's multi-node routing state, as `broker_status` reports it. */
97
+ export interface BrokerMultiNodeStatus {
98
+ status: "off" | "starting" | "on" | "unavailable";
99
+ /** Why routing is off or unavailable. */
100
+ reason?: string;
101
+ /** The shared selection's adapter module, or `sqlite` for a `path` selection. */
102
+ adapter?: string;
103
+ prefix?: string;
104
+ /** Host names of the other brokers whose membership lease is live, while routing is on. */
105
+ peers?: string[];
106
+ }
107
+
108
+ /** What a broker reports about itself; read before registering by `atomic intercom restart` and `atomic storage status`. */
109
+ export interface BrokerStatusReport {
110
+ pid: number;
111
+ /** Sessions connected to this broker. */
112
+ sessions: number;
113
+ /** The shared storage selection the broker read, as a digest of its JSON, and where it read it; absent without one. */
114
+ storage?: { digest: string; source: "env" | "settings" };
115
+ multiNode: BrokerMultiNodeStatus;
116
+ }
117
+
96
118
  export interface Message {
97
119
  id: string;
98
120
  timestamp: number;
@@ -125,6 +147,7 @@ export interface SupervisorRegistration {
125
147
 
126
148
 
127
149
  export type ClientMessage =
150
+ | { type: "health"; requestId: string }
128
151
  | {
129
152
  type: "register";
130
153
  session: Omit<SessionInfo, "id">;
@@ -225,9 +248,14 @@ export type ClientMessage =
225
248
  /** Legacy single-group membership; accepted alongside `groups` for compatibility. */
226
249
  group?: string;
227
250
  requestId?: string;
228
- };
251
+ }
252
+ /** Allowed before `register`: the broker's own status. */
253
+ | { type: "broker_status"; requestId: string }
254
+ /** Allowed before `register`: shut the broker down; its sessions reconnect to a new broker. */
255
+ | { type: "shutdown"; requestId: string };
229
256
 
230
257
  export type BrokerMessage =
258
+ | { type: "health"; requestId: string; instanceId: string }
231
259
  | {
232
260
  type: "registered";
233
261
  sessionId: string;
@@ -236,6 +264,8 @@ export type BrokerMessage =
236
264
  acknowledgesReceipt?: true;
237
265
  /** This broker acknowledges a `register_pending_stage_route` that carries a `requestId`; absent on older brokers. */
238
266
  acknowledgesPendingStageRoutes?: true;
267
+ /** This broker answers `broker_status`; absent on older brokers, which drop a client that sends it. */
268
+ brokerStatus?: true;
239
269
  }
240
270
  | { type: "registration_failed"; reason: string; code?: LiveWorkflowStageRouteRefusalCode }
241
271
  | { type: "question_target"; messageId: string; attemptId: string; sessionId: string }
@@ -272,4 +302,6 @@ export type BrokerMessage =
272
302
  /** #3760: the send is held for a subagent that is being restored; wait up to `timeoutMs` for its outcome. */
273
303
  | { type: "send_held"; messageId: string; attemptId?: string; timeoutMs: number }
274
304
  | { type: "restoring_recipient_ack"; requestId: string; error?: string }
275
- | { type: "delivery_failed"; messageId: string; reason: string; reasonCode?: "message_id_conflict" | "session_not_found"; attemptId?: string };
305
+ | { type: "delivery_failed"; messageId: string; reason: string; reasonCode?: "message_id_conflict" | "session_not_found"; attemptId?: string }
306
+ | { type: "broker_status"; requestId: string; report: BrokerStatusReport }
307
+ | { type: "shutdown_ack"; requestId: string };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/mcp",
3
- "version": "0.9.41-alpha.3",
3
+ "version": "0.9.42-alpha.1",
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,20 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.9.41] - 2026-10-22
6
+
7
+ ### Added
8
+
9
+ - Added a `resumeInFlight` subagent setting (`"never"`, `"ask"`, or `"auto"`, default `"never"`) for recovery of paused and quit subagents that are awaiting resume. `ask` confirms once, listing each subagent, and `auto` resumes each from its own session, with its completion reaching the session that launched it; `never` leaves them for a manual `resume`. It applies when Atomic starts or a session is resumed, to that session's own subagents, never to workflow-stage children, and an invalid value is reported and treated as `never` ([#3827](https://github.com/bastani-inc/atomic/issues/3827)).
10
+
11
+ ### Changed
12
+
13
+ - Quitting a subagent now behaves like quitting a workflow. The `quit` and `pause` results say the child is paused · awaiting resume and name `{ action: "resume", id: "<child-id>" }`; the parent's completion notice says the same, with the typed `quit` or `pause` stop reason instead of `parent-handoff` and without "This execution has ended". `{ action: "status", id }` reports a paused or quit child as paused · awaiting resume with its resume call, and `{ action: "status" }` lists every such child, including after Atomic restarts. Launch cards of such children show `‖ Paused · awaiting resume` (or `‖ Quit · paused · awaiting resume`) instead of `(resumable)`.
14
+
15
+ ### Fixed
16
+
17
+ - A subagent with `model: "auto"` no longer waits indefinitely on a slow routing model. Each routing inference now stops after the `httpIdleTimeoutMs` deadline (10 minutes by default), and the subagent runs on the current chat model when it satisfies the routing constraints ([#3806](https://github.com/bastani-inc/atomic/issues/3806))
18
+
5
19
  ## [0.9.41-alpha.1] - 2026-10-21
6
20
 
7
21
  ### Added
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/subagents",
3
- "version": "0.9.41-alpha.3",
3
+ "version": "0.9.42-alpha.1",
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": [
@@ -13205,6 +13205,7 @@ class SubagentControlRuntime {
13205
13205
  ...inherited,
13206
13206
  customTools: admitted.policy.customTools ?? inherited.customTools,
13207
13207
  resourceLoader,
13208
+ resourceAdmissionSignal: AbortSignal.any([signals.abort, signals.interrupt]),
13208
13209
  subagentPolicy: {
13209
13210
  ...admitted.policy,
13210
13211
  executionEnded: executionEnded.signal,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/web-access",
3
- "version": "0.9.41-alpha.3",
3
+ "version": "0.9.42-alpha.1",
4
4
  "private": true,
5
5
  "description": "Atomic extension for web search, URL fetching, GitHub repo cloning, PDF/video extraction. Fork of: https://github.com/nicobailon/pi-web-access",
6
6
  "contributors": [
@@ -6,6 +6,46 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.9.42-alpha.1] - 2026-10-23
10
+
11
+ ### Added
12
+
13
+ - Local workflow pools can be enabled per run through SDK options or workflow settings, with root and optional user-wide admission limits. A root stays local while registered child workflow subtrees run in local worker processes; unsupported process containment and incompatible worker definitions fail closed ([#3869](https://github.com/bastani-inc/atomic/issues/3869)).
14
+
15
+ ### Fixed
16
+
17
+ - Workflow model chains now share provider-account cooldowns after rate limits, honor `Retry-After`, and wait for the earliest eligible account instead of exhausting a cooling chain. Retries remain bounded, including retries within each session; waits can be paused or cancelled, and workflow status and task results report provider counts and cooldown deadlines. Retrying a follow-up on the same model preserves its conversation history. Follow-ups keep each model's retry allowance across account switches and can return to an earlier account when its cooldown expires ([#3864](https://github.com/bastani-inc/atomic/issues/3864)).
18
+ - Workflow stages now reload resources up to four at a time per Atomic process instead of one at a time, so a slow reload no longer blocks every other stage at startup. Cancelling a stage waiting for a reload slot removes it from the queue immediately; an active reload retains its slot until it finishes ([#3861](https://github.com/bastani-inc/atomic/issues/3861)).
19
+ - Standalone `run()` now owns Intercom routes for eligible workflow stages until the run settles, so stages can use Intercom without an interactive workflow host. An installed SDK reuses an Intercom owner the extension bundle already registered for the store instead of starting a second one. When a route-update acknowledgement times out, the update retries without disconnecting a healthy owner ([#3863](https://github.com/bastani-inc/atomic/issues/3863))
20
+
21
+ ## [0.9.41] - 2026-10-22
22
+
23
+ ### Added
24
+
25
+ - Added `schemaTimeoutMs` to workflow stage, task, chain, and parallel options: the wall-clock limit in milliseconds for each `structured_output` decision of a schema-backed item, covering its repair attempts, retries, and model fallbacks together. It defaults to the `httpIdleTimeoutMs` setting ([#3806](https://github.com/bastani-inc/atomic/issues/3806))
26
+
27
+ ### Changed
28
+
29
+ - Reopening `/workflow resume` is faster: the run list is kept between opens and rereads only the runs whose journal changed since the last open, including changes made by other Atomic processes. Whether another session still owns a run is checked when you select it.
30
+ - `/workflow connect` and `/workflow status` now list runs the way `/tasks` does. Active runs come before ended ones, with runs waiting for your input or blocked first, then running, then paused; ended runs follow with failed, cancelled, then completed. Within each group the newest run comes first, where before the `/workflow connect` list showed the oldest running run first ([#3824](https://github.com/bastani-inc/atomic/issues/3824)).
31
+
32
+ ### Fixed
33
+
34
+ - A rejection that workflow code leaves unhandled no longer ends the whole Atomic process. This covers a rejected `ctx.tool`, `ctx.task`, `ctx.chain`, `ctx.parallel`, `ctx.workflow`, `ctx.ui` prompt (`input`, `confirm`, `select`, `editor` or `custom`) or stage method call (`prompt`, `complete`, `steer`, `sendUserMessage`, `setModel`, `compact` and the other promise-returning stage methods), including one that is started and never awaited (`void ctx.task(...)` used to leave the run `completed` with no sign of the failure), a `ctx.tool` call made after its run has stopped (`ctx.tool admission is closed for this run`), a string, number or `undefined` thrown from a `ctx.tool` callback, and an error the workflow file throws or receives from `fs` itself, for example in a rolling pool that keeps `branch.finally(...)` as a separate promise. It also covers `ctx.exit()` called inside such a branch, which ends the run as exited with the status and outputs it asked for (on Bun the process used to end right after the run reported `completed`), and a child workflow's own branch that uses `ctx` after its parent exited. Stopping a run no longer ends the process either: a branch that keeps running after `/workflow quit`, a kill, or an abort signal from the code that started the run, and then calls `ctx.stage`, `ctx.task`, `ctx.workflow` or `ctx.exit()`, or that was waiting on a `ctx.ui` prompt when the run was killed, could end it with `workflow killed` (a kill), the quit error (`/workflow quit`), an `AbortError` or `atomic-workflows: HIL aborted` right after the run reported `killed` or `paused`, and the run keeps that status. `ctx.exit()` called in such a branch while the run is paused ends the run as exited once the run resumes, and a kill of the paused run still ends it as `killed` (on Node it used to end as `failed` with `Workflow exit is waiting for explicit resume`, and on Bun the process ended). The rejection fails its own run when it surfaces before that run decides its final status, so other runs, stages, and the interactive engine keep going; a `ctx.task`, `ctx.chain`, `ctx.parallel`, `ctx.workflow`, `ctx.ui` or stage method rejection that the workflow awaits or catches reaches that code unchanged and does not fail the run. Once the run has ended, an error that a `ctx` call rejected with, what `ctx.exit()` threw and the reason the run was stopped with are ignored (the reason of a kill is the string `workflow killed`, which is ignored by value for the rest of the process, so a branch that wakes up long after the run ended is covered too), and so is an error thrown by the workflow file for the next 30 seconds, so the remaining branches of a failing pool cannot end the process; a later one ends it as before. On Node the owning run is identified exactly; on Bun a `ctx` call's rejection, what `ctx.exit()` threw and the reason the run was stopped with are matched by identity (a `ctx` call's string, number or `undefined` only within the event-loop turn in which the call rejected, and the string a kill uses by value), and an error thrown by the workflow file itself is matched through its stack to the run of the file that calls `workflow()`, but only when no other run of that file is running or has run at the same time (a child workflow defined in the same file does not count), so a primitive thrown outside a `ctx` call on Bun is still fatal, and an error that either of two overlapping runs of one file could have thrown ends the process as before instead of failing a run that may be healthy. This works the same in the bundled install as in a source checkout. A rejection that belongs to no workflow run, including one raised by Atomic's own code, ends the process as before, with its original error and stack, and `--unhandled-rejections=warn|none|warn-with-error-code` are honored ([#3846](https://github.com/bastani-inc/atomic/issues/3846))
35
+ - A workflow that omits `name` is now named after the file that defines it when Atomic runs from the bundled install, as it already was in a source checkout, instead of after the bundled extension file (`index.bundle`) ([#3846](https://github.com/bastani-inc/atomic/issues/3846))
36
+ - `/workflow status <runId>` no longer reports `durable checkpoint topology is malformed or incomplete` for a running or crashed run whose child `ctx.workflow` calls have started but not yet recorded a stage or tool of their own, such as a pool of concurrent children when the process was killed. The children now show as running, and a crashed run can be inspected and resumed. A run that fails while such children are still starting now cancels them first, so its status can be inspected as well ([#3846](https://github.com/bastani-inc/atomic/issues/3846))
37
+ - A workflow stage no longer stays stuck selecting its model when many workflows run at once. A stage with `model: "auto"` now waits at most five minutes for model selection, counting any wait for one of eight routing slots shared by every stage, so a burst of stages queues instead of overloading the router provider. When the wait ends, the stage runs on the current chat model if that model satisfies every routing constraint; otherwise it fails with an error that names the stage and the `model-resolution` startup phase, and its startup status reads `failed` instead of staying active. A failed selection is no longer remembered, so the next prompt on the same stage selects a model again, without launching a replacement workflow.
38
+ - After a blocked workflow run is resumed, Intercom sends to `workflow:<rootRunId>/**`, to stage patterns, and to stages that have not started yet are accepted and delivered again instead of failing with `Workflow execution for <runId> is retired`.
39
+ - In a long-running session, starting a workflow from a turn that an Intercom message started no longer fails with `Workflow execution for <runId> is retired; startup cleanup failed: …` after an earlier workflow run in the session has ended or been quit. The session's Intercom connection is now opened outside the workflow run that first needed it. The `is retired` error now names the run whose execution actually ended, not the run being started.
40
+ - A workflow stage whose fallback session fails to start because an extension's `session_start` failed under load, for example Intercom's `Broker failed to start within timeout` or `connect ECONNREFUSED`, now retries that session with the same-model retry budget and then moves on to its next fallback model, instead of failing the stage and letting fail-fast skip its sibling stages. Any other extension startup error still fails the stage at once. The stage error, model attempts, and fallback warnings now name each failing extension and its error rather than only `Extension startup failed`.
41
+ - When a workflow stage falls back to another model and that fallback session cannot start, the stage now closes the session it was replacing. Before, that session kept its session database open after the stage failed, and on Windows the file could not be deleted until the process exited.
42
+ - Workflow stage sessions now provide `ctx.ui.theme` and the other default UI members, so extensions that read `ctx.ui.theme.fg(...)` in `session_start`, such as `examples/extensions/status-line.ts`, no longer fail stage startup with `Extension startup failed` ([#3801](https://github.com/bastani-inc/atomic/issues/3801))
43
+ - Workflow inputs now reject integer and number values outside the `minimum`/`maximum` declared in the input schema, such as `count: 0` for `Type.Integer({ minimum: 1, maximum: 8 })`, when the run is started, instead of passing them to the workflow body. The error names the input and the violated bound ([#3812](https://github.com/bastani-inc/atomic/issues/3812)).
44
+ - A `ctx.parallel(..., { failFast: false })` call that has a failing step no longer loses the results of the steps that succeeded. The `AggregateError` it rejects with now carries `partialResults`, one entry per step in step order, holding each completed step's result and `undefined` for a step that failed. The `WorkflowParallelFailure` type describes it ([#3809](https://github.com/bastani-inc/atomic/issues/3809))
45
+ - A workflow stage's corrective prompt after a rejected `structured_output` result now names the failing paths and expected types, or reports that the tool arguments were not valid JSON, instead of only saying the response does not match the decision schema ([#3802](https://github.com/bastani-inc/atomic/issues/3802))
46
+ - Disposing a session right after a workflow run reports that it ended no longer leaves the run `running` in the workflow journal, with its lease released, for readers to report as crashed. `session.dispose()` now waits up to 10 seconds for runs that have ended but are still recording their ending, before it closes the journal, and it rejects naming the run when that ending still cannot be recorded. A run whose journal rejects the write of its `completed` status now retries it once, and reports it with an error notice and a rejected `waitForSettled` when it still fails, instead of failing in silence ([#3811](https://github.com/bastani-inc/atomic/issues/3811))
47
+ - A schema-backed workflow stage no longer stays `running` for hours inside one `structured_output` call when a slow model keeps generating without calling the tool. The decision now stops after the `httpIdleTimeoutMs` deadline (10 minutes by default) or the stage's `schemaTimeoutMs`, and the error that names the deadline and each attempt's duration reaches the model and the failed stage unchanged instead of being treated as a structured-output contract failure ([#3806](https://github.com/bastani-inc/atomic/issues/3806))
48
+
9
49
  ## [0.9.41-alpha.2] - 2026-10-22
10
50
 
11
51
  ### Fixed