@poolzin/pool-bot 2026.2.11 → 2026.2.18

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 (535) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/agents/agent-scope.js +4 -0
  3. package/dist/agents/announce-idempotency.js +14 -0
  4. package/dist/agents/auth-profiles/usage.js +22 -0
  5. package/dist/agents/auth-profiles.js +1 -1
  6. package/dist/agents/auth-profiles.resolve-auth-profile-order.fixtures.js +23 -0
  7. package/dist/agents/bash-tools.exec-runtime.js +438 -0
  8. package/dist/agents/bash-tools.shared.js +6 -0
  9. package/dist/agents/cli-runner/reliability.js +61 -0
  10. package/dist/agents/cli-watchdog-defaults.js +11 -0
  11. package/dist/agents/command-poll-backoff.js +63 -0
  12. package/dist/agents/current-time.js +16 -0
  13. package/dist/agents/glob-pattern.js +42 -0
  14. package/dist/agents/memory-search.js +33 -0
  15. package/dist/agents/model-alias-lines.js +18 -0
  16. package/dist/agents/model-auth-label.js +61 -0
  17. package/dist/agents/model-fallback.js +59 -8
  18. package/dist/agents/models-config.e2e-harness.js +115 -0
  19. package/dist/agents/ollama-stream.js +11 -3
  20. package/dist/agents/openclaw-tools.js +135 -0
  21. package/dist/agents/pi-auth-json.js +118 -0
  22. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +147 -0
  23. package/dist/agents/pi-embedded-subscribe.e2e-harness.js +90 -0
  24. package/dist/agents/pi-embedded-subscribe.handlers.compaction.js +63 -0
  25. package/dist/agents/pi-embedded-subscribe.handlers.tools.media.test-helpers.js +30 -0
  26. package/dist/agents/pi-extensions/session-manager-runtime-registry.js +23 -0
  27. package/dist/agents/pi-tools.before-tool-call.js +145 -4
  28. package/dist/agents/pi-tools.js +29 -9
  29. package/dist/agents/pi-tools.policy.js +85 -92
  30. package/dist/agents/pi-tools.schema.js +54 -27
  31. package/dist/agents/queued-file-writer.js +22 -0
  32. package/dist/agents/sandbox/docker.js +133 -40
  33. package/dist/agents/sandbox/fs-bridge.js +146 -0
  34. package/dist/agents/sandbox/fs-paths.js +205 -0
  35. package/dist/agents/sandbox/hash.js +4 -0
  36. package/dist/agents/sandbox/validate-sandbox-security.js +157 -0
  37. package/dist/agents/sandbox-paths.js +3 -0
  38. package/dist/agents/sandbox-tool-policy.js +26 -0
  39. package/dist/agents/sanitize-for-prompt.js +18 -0
  40. package/dist/agents/session-dirs.js +20 -0
  41. package/dist/agents/session-write-lock.js +203 -39
  42. package/dist/agents/skills/filter.js +24 -0
  43. package/dist/agents/skills/tools-dir.js +9 -0
  44. package/dist/agents/skills-install-download.js +290 -0
  45. package/dist/agents/skills-install-output.js +30 -0
  46. package/dist/agents/skills-install.download-test-utils.js +36 -0
  47. package/dist/agents/skills.e2e-test-helpers.js +13 -0
  48. package/dist/agents/subagent-announce-queue.js +59 -15
  49. package/dist/agents/subagent-depth.js +137 -0
  50. package/dist/agents/subagent-registry.js +448 -96
  51. package/dist/agents/subagent-spawn.js +262 -0
  52. package/dist/agents/system-prompt.js +52 -10
  53. package/dist/agents/test-helpers/fast-tool-stubs.js +18 -0
  54. package/dist/agents/test-helpers/host-sandbox-fs-bridge.js +74 -0
  55. package/dist/agents/tool-display-common.js +782 -0
  56. package/dist/agents/tool-loop-detection.js +466 -0
  57. package/dist/agents/tool-policy.js +6 -0
  58. package/dist/agents/tools/image-tool.js +1 -1
  59. package/dist/agents/tools/sessions-access.js +178 -0
  60. package/dist/agents/tools/sessions-resolution.js +206 -0
  61. package/dist/agents/tools/subagents-tool.js +616 -0
  62. package/dist/agents/workspace-dir.js +18 -0
  63. package/dist/agents/workspace-dirs.js +14 -0
  64. package/dist/agents/workspace.js +70 -0
  65. package/dist/auto-reply/heartbeat-reply-payload.js +18 -0
  66. package/dist/auto-reply/reply/commands-export-session.js +163 -0
  67. package/dist/auto-reply/reply/commands-mesh.js +245 -0
  68. package/dist/auto-reply/reply/commands-setunset.js +28 -0
  69. package/dist/auto-reply/reply/commands-slash-parse.js +31 -0
  70. package/dist/auto-reply/reply/commands-system-prompt.js +117 -0
  71. package/dist/auto-reply/reply/directive-handling.levels.js +17 -0
  72. package/dist/auto-reply/reply/directive-handling.params.js +1 -0
  73. package/dist/auto-reply/reply/directive-parsing.js +36 -0
  74. package/dist/auto-reply/reply/dispatcher-registry.js +43 -0
  75. package/dist/auto-reply/reply/elevated-unavailable.js +20 -0
  76. package/dist/auto-reply/reply/post-compaction-audit.js +96 -0
  77. package/dist/auto-reply/reply/post-compaction-context.js +98 -0
  78. package/dist/auto-reply/reply/reply-delivery.js +92 -0
  79. package/dist/auto-reply/reply/session-reset-prompt.js +1 -0
  80. package/dist/auto-reply/reply/session-run-accounting.js +33 -0
  81. package/dist/auto-reply/reply.directive.directive-behavior.e2e-harness.js +115 -0
  82. package/dist/auto-reply/reply.directive.directive-behavior.e2e-mocks.js +12 -0
  83. package/dist/browser/bridge-auth-registry.js +26 -0
  84. package/dist/browser/client-actions-url.js +10 -0
  85. package/dist/browser/control-auth.js +73 -0
  86. package/dist/browser/csrf.js +64 -0
  87. package/dist/browser/http-auth.js +52 -0
  88. package/dist/browser/paths.js +37 -0
  89. package/dist/browser/proxy-files.js +32 -0
  90. package/dist/browser/pw-ai-state.js +7 -0
  91. package/dist/browser/resolved-config-refresh.js +42 -0
  92. package/dist/browser/routes/path-output.js +1 -0
  93. package/dist/browser/server-context.chrome-test-harness.js +20 -0
  94. package/dist/browser/server-middleware.js +31 -0
  95. package/dist/browser/test-port.js +16 -0
  96. package/dist/build-info.json +3 -3
  97. package/dist/canvas-host/file-resolver.js +43 -0
  98. package/dist/channels/account-summary.js +19 -0
  99. package/dist/channels/draft-stream-loop.js +77 -0
  100. package/dist/channels/plugins/account-helpers.js +26 -0
  101. package/dist/channels/telegram/allow-from.js +10 -0
  102. package/dist/cli/browser-cli-resize.js +22 -0
  103. package/dist/cli/browser-cli-shared.js +8 -0
  104. package/dist/cli/clawbot-cli.js +5 -0
  105. package/dist/cli/completion-cli.js +566 -0
  106. package/dist/cli/config-cli.js +63 -5
  107. package/dist/cli/daemon-cli/lifecycle-core.js +256 -0
  108. package/dist/cli/daemon-cli/register-service-commands.js +60 -0
  109. package/dist/cli/daemon-cli-compat.js +80 -0
  110. package/dist/cli/nodes-cli/pairing-render.js +26 -0
  111. package/dist/cli/program/action-reparse.js +17 -0
  112. package/dist/cli/program/command-registry.js +17 -0
  113. package/dist/cli/program/program-context.js +8 -0
  114. package/dist/cli/program/register.subclis.js +7 -0
  115. package/dist/cli/program/routes.js +233 -0
  116. package/dist/cli/qr-cli.js +132 -0
  117. package/dist/cli/requirements-test-fixtures.js +17 -0
  118. package/dist/cli/respawn-policy.js +4 -0
  119. package/dist/cli/shared/parse-port.js +18 -0
  120. package/dist/cli/skills-cli.format.js +241 -0
  121. package/dist/cli/update-cli/progress.js +121 -0
  122. package/dist/cli/update-cli/restart-helper.js +108 -0
  123. package/dist/cli/update-cli/shared.js +196 -0
  124. package/dist/cli/update-cli/status.js +97 -0
  125. package/dist/cli/update-cli/suppress-deprecations.js +17 -0
  126. package/dist/cli/update-cli/update-command.js +506 -0
  127. package/dist/cli/update-cli/wizard.js +130 -0
  128. package/dist/cli/update-cli.js +3 -9
  129. package/dist/cli/windows-argv.js +69 -0
  130. package/dist/commands/auth-choice-legacy.js +20 -0
  131. package/dist/commands/auth-choice.apply-helpers.js +8 -0
  132. package/dist/commands/channel-test-helpers.js +19 -0
  133. package/dist/commands/cleanup-plan.js +10 -0
  134. package/dist/commands/cleanup-utils.js +7 -0
  135. package/dist/commands/config-validation.js +15 -0
  136. package/dist/commands/doctor-completion.js +112 -0
  137. package/dist/commands/doctor-memory-search.js +119 -0
  138. package/dist/commands/doctor-session-locks.js +73 -0
  139. package/dist/commands/doctor.e2e-harness.js +364 -0
  140. package/dist/commands/gateway-presence.js +19 -0
  141. package/dist/commands/model-default.js +35 -0
  142. package/dist/commands/models/fallbacks-shared.js +102 -0
  143. package/dist/commands/models/shared.js +24 -0
  144. package/dist/commands/onboard-auth.config-gateways.js +64 -0
  145. package/dist/commands/onboard-auth.config-litellm.js +45 -0
  146. package/dist/commands/onboard-auth.config-shared.js +116 -0
  147. package/dist/commands/onboard-config.js +16 -0
  148. package/dist/commands/onboard-non-interactive.test-helpers.js +31 -0
  149. package/dist/commands/onboard-provider-auth-flags.js +136 -0
  150. package/dist/commands/openai-codex-oauth.js +40 -0
  151. package/dist/commands/test-runtime-config-helpers.js +21 -0
  152. package/dist/commands/test-wizard-helpers.js +68 -0
  153. package/dist/commands/vllm-setup.js +66 -0
  154. package/dist/compat/legacy-names.js +2 -0
  155. package/dist/config/backup-rotation.js +19 -0
  156. package/dist/config/env-preserve.js +122 -0
  157. package/dist/config/includes-scan.js +78 -0
  158. package/dist/config/plugins-allowlist.js +13 -0
  159. package/dist/config/schema.help.js +256 -0
  160. package/dist/config/schema.hints.js +189 -0
  161. package/dist/config/schema.irc.js +20 -0
  162. package/dist/config/schema.labels.js +317 -0
  163. package/dist/config/sessions/delivery-info.js +40 -0
  164. package/dist/config/types.irc.js +1 -0
  165. package/dist/config/zod-schema.agent-defaults.js +14 -0
  166. package/dist/config/zod-schema.agent-model.js +10 -0
  167. package/dist/config/zod-schema.agent-runtime.js +14 -0
  168. package/dist/config/zod-schema.allowdeny.js +35 -0
  169. package/dist/config/zod-schema.sensitive.js +4 -0
  170. package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
  171. package/dist/cron/isolated-agent/skills-snapshot.js +26 -0
  172. package/dist/cron/isolated-agent/subagent-followup.js +127 -0
  173. package/dist/cron/isolated-agent.mocks.js +12 -0
  174. package/dist/cron/isolated-agent.test-setup.js +22 -0
  175. package/dist/cron/legacy-delivery.js +43 -0
  176. package/dist/cron/webhook-url.js +22 -0
  177. package/dist/daemon/arg-split.js +40 -0
  178. package/dist/daemon/exec-file.js +23 -0
  179. package/dist/daemon/output.js +6 -0
  180. package/dist/daemon/runtime-format.js +31 -0
  181. package/dist/daemon/schtasks-exec.js +4 -0
  182. package/dist/daemon/service-audit.js +22 -0
  183. package/dist/discord/client.js +41 -0
  184. package/dist/discord/components-registry.js +57 -0
  185. package/dist/discord/components.js +816 -0
  186. package/dist/discord/guilds.js +12 -0
  187. package/dist/discord/monitor/gateway-plugin.js +48 -0
  188. package/dist/discord/monitor/presence.js +30 -0
  189. package/dist/discord/send.components.js +115 -0
  190. package/dist/discord/send.shared.js +4 -0
  191. package/dist/discord/ui.js +26 -0
  192. package/dist/discord/voice-message.js +254 -0
  193. package/dist/gateway/agent-event-assistant-text.js +5 -0
  194. package/dist/gateway/agent-prompt.js +33 -0
  195. package/dist/gateway/auth-rate-limit.js +136 -0
  196. package/dist/gateway/channel-health-monitor.js +114 -0
  197. package/dist/gateway/control-ui-contract.js +1 -0
  198. package/dist/gateway/control-ui-csp.js +15 -0
  199. package/dist/gateway/gateway-config-prompts.shared.js +25 -0
  200. package/dist/gateway/http-auth-helpers.js +18 -0
  201. package/dist/gateway/http-common.js +18 -0
  202. package/dist/gateway/http-endpoint-helpers.js +27 -0
  203. package/dist/gateway/node-invoke-sanitize.js +11 -0
  204. package/dist/gateway/node-invoke-system-run-approval.js +205 -0
  205. package/dist/gateway/probe-auth.js +21 -0
  206. package/dist/gateway/protocol/index.js +7 -2
  207. package/dist/gateway/protocol/schema/mesh.js +54 -0
  208. package/dist/gateway/protocol/schema/protocol-schemas.js +7 -0
  209. package/dist/gateway/protocol/schema.js +1 -0
  210. package/dist/gateway/server/ws-connection/auth-messages.js +54 -0
  211. package/dist/gateway/server-channels.js +11 -0
  212. package/dist/gateway/server-methods/attachment-normalize.js +16 -0
  213. package/dist/gateway/server-methods/base-hash.js +8 -0
  214. package/dist/gateway/server-methods/mesh.js +700 -0
  215. package/dist/gateway/server-methods/nodes.handlers.invoke-result.js +55 -0
  216. package/dist/gateway/server-methods/restart-request.js +13 -0
  217. package/dist/gateway/server-methods/validation.js +8 -0
  218. package/dist/gateway/server.agent.gateway-server-agent.mocks.js +35 -0
  219. package/dist/gateway/server.e2e-registry-helpers.js +1 -0
  220. package/dist/gateway/server.e2e-ws-harness.js +20 -0
  221. package/dist/gateway/test-helpers.js +2 -0
  222. package/dist/gateway/test-helpers.server.js +3 -1
  223. package/dist/gateway/test-http-response.js +12 -0
  224. package/dist/gateway/test-openai-responses-model.js +20 -0
  225. package/dist/gateway/test-temp-config.js +30 -0
  226. package/dist/gateway/test-with-server.js +32 -0
  227. package/dist/hooks/bundled/bootstrap-extra-files/handler.js +46 -0
  228. package/dist/imessage/monitor/abort-handler.js +23 -0
  229. package/dist/imessage/monitor/inbound-processing.js +346 -0
  230. package/dist/imessage/monitor/parse-notification.js +64 -0
  231. package/dist/imessage/target-parsing-helpers.js +92 -0
  232. package/dist/infra/archive.js +244 -20
  233. package/dist/infra/detect-package-manager.js +26 -0
  234. package/dist/infra/exec-approvals-allowlist.js +257 -0
  235. package/dist/infra/exec-approvals-analysis.js +770 -0
  236. package/dist/infra/exec-approvals.js +13 -0
  237. package/dist/infra/file-lock.js +1 -0
  238. package/dist/infra/gemini-auth.js +39 -0
  239. package/dist/infra/heartbeat-active-hours.js +85 -0
  240. package/dist/infra/heartbeat-events-filter.js +50 -0
  241. package/dist/infra/heartbeat-runner.test-utils.js +39 -0
  242. package/dist/infra/http-body.js +265 -0
  243. package/dist/infra/install-package-dir.js +50 -0
  244. package/dist/infra/install-safe-path.js +49 -0
  245. package/dist/infra/json-files.js +49 -0
  246. package/dist/infra/jsonl-socket.js +52 -0
  247. package/dist/infra/map-size.js +14 -0
  248. package/dist/infra/net/hostname.js +7 -0
  249. package/dist/infra/npm-registry-spec.js +39 -0
  250. package/dist/infra/openclaw-root.js +109 -0
  251. package/dist/infra/outbound/delivery-queue.js +214 -0
  252. package/dist/infra/outbound/identity.js +23 -0
  253. package/dist/infra/outbound/message-action-params.js +307 -0
  254. package/dist/infra/outbound/tool-payload.js +21 -0
  255. package/dist/infra/package-json.js +23 -0
  256. package/dist/infra/pairing-files.js +19 -0
  257. package/dist/infra/pairing-token.js +9 -0
  258. package/dist/infra/path-prepend.js +51 -0
  259. package/dist/infra/path-safety.js +16 -0
  260. package/dist/infra/process-respawn.js +49 -0
  261. package/dist/infra/runtime-status.js +16 -0
  262. package/dist/infra/session-cost-usage.types.js +1 -0
  263. package/dist/infra/session-maintenance-warning.js +89 -0
  264. package/dist/infra/system-run-command.js +78 -0
  265. package/dist/infra/tmp-openclaw-dir.js +81 -0
  266. package/dist/infra/tmp-poolbot-dir.js +2 -0
  267. package/dist/infra/update-channels.js +19 -0
  268. package/dist/line/actions.js +45 -0
  269. package/dist/line/channel-access-token.js +9 -0
  270. package/dist/line/flex-templates/basic-cards.js +332 -0
  271. package/dist/line/flex-templates/common.js +18 -0
  272. package/dist/line/flex-templates/media-control-cards.js +453 -0
  273. package/dist/line/flex-templates/message.js +10 -0
  274. package/dist/line/flex-templates/schedule-cards.js +399 -0
  275. package/dist/line/flex-templates/types.js +1 -0
  276. package/dist/line/webhook-node.js +100 -0
  277. package/dist/line/webhook-utils.js +11 -0
  278. package/dist/logging/diagnostic-session-state.js +73 -0
  279. package/dist/logging/diagnostic.js +22 -0
  280. package/dist/logging/timestamps.js +14 -0
  281. package/dist/markdown/whatsapp.js +62 -0
  282. package/dist/media/base64.js +34 -0
  283. package/dist/media/local-roots.js +32 -0
  284. package/dist/media/outbound-attachment.js +10 -0
  285. package/dist/media/read-response-with-limit.js +41 -0
  286. package/dist/media/sniff-mime-from-base64.js +19 -0
  287. package/dist/media-understanding/audio-preflight.js +67 -0
  288. package/dist/media-understanding/fs.js +13 -0
  289. package/dist/media-understanding/output-extract.js +26 -0
  290. package/dist/media-understanding/providers/audio.test-helpers.js +34 -0
  291. package/dist/media-understanding/providers/google/inline-data.js +64 -0
  292. package/dist/media-understanding/providers/shared.js +7 -0
  293. package/dist/media-understanding/runner.entries.js +459 -0
  294. package/dist/memory/batch-error-utils.js +11 -0
  295. package/dist/memory/batch-http.js +27 -0
  296. package/dist/memory/batch-output.js +29 -0
  297. package/dist/memory/batch-runner.js +22 -0
  298. package/dist/memory/batch-upload.js +23 -0
  299. package/dist/memory/batch-utils.js +26 -0
  300. package/dist/memory/embeddings-debug.js +11 -0
  301. package/dist/memory/embeddings-remote-client.js +22 -0
  302. package/dist/memory/embeddings-remote-fetch.js +14 -0
  303. package/dist/memory/embeddings.js +36 -9
  304. package/dist/memory/hybrid.js +24 -5
  305. package/dist/memory/manager-embedding-ops.js +616 -0
  306. package/dist/memory/manager-sync-ops.js +953 -0
  307. package/dist/memory/manager.js +76 -28
  308. package/dist/memory/mmr.js +164 -0
  309. package/dist/memory/qmd-manager.js +1061 -0
  310. package/dist/memory/qmd-query-parser.js +107 -0
  311. package/dist/memory/qmd-scope.js +93 -0
  312. package/dist/memory/query-expansion.js +331 -0
  313. package/dist/memory/search-manager.js +0 -1
  314. package/dist/memory/sync-index.js +21 -0
  315. package/dist/memory/sync-progress.js +22 -0
  316. package/dist/memory/sync-stale.js +30 -0
  317. package/dist/memory/temporal-decay.js +119 -0
  318. package/dist/memory/test-embeddings-mock.js +16 -0
  319. package/dist/memory/test-manager-helpers.js +14 -0
  320. package/dist/memory/test-runtime-mocks.js +11 -0
  321. package/dist/node-host/invoke-browser.js +177 -0
  322. package/dist/node-host/invoke.js +685 -0
  323. package/dist/pairing/setup-code.js +285 -0
  324. package/dist/plugin-sdk/account-id.js +1 -0
  325. package/dist/plugin-sdk/agent-media-payload.js +13 -0
  326. package/dist/plugin-sdk/allow-from.js +47 -0
  327. package/dist/plugin-sdk/command-auth.js +23 -0
  328. package/dist/plugin-sdk/config-paths.js +9 -0
  329. package/dist/plugin-sdk/file-lock.js +116 -0
  330. package/dist/plugin-sdk/json-store.js +31 -0
  331. package/dist/plugin-sdk/onboarding.js +28 -0
  332. package/dist/plugin-sdk/provider-auth-result.js +29 -0
  333. package/dist/plugin-sdk/slack-message-actions.js +133 -0
  334. package/dist/plugin-sdk/status-helpers.js +35 -0
  335. package/dist/plugin-sdk/text-chunking.js +31 -0
  336. package/dist/plugin-sdk/tool-send.js +12 -0
  337. package/dist/plugin-sdk/webhook-path.js +27 -0
  338. package/dist/plugin-sdk/webhook-targets.js +34 -0
  339. package/dist/plugins/hooks.test-helpers.js +21 -0
  340. package/dist/plugins/uninstall.js +171 -0
  341. package/dist/process/kill-tree.js +98 -0
  342. package/dist/process/supervisor/adapters/child.js +143 -0
  343. package/dist/process/supervisor/adapters/env.js +13 -0
  344. package/dist/process/supervisor/adapters/pty.js +148 -0
  345. package/dist/process/supervisor/index.js +10 -0
  346. package/dist/process/supervisor/registry.js +117 -0
  347. package/dist/process/supervisor/supervisor.js +244 -0
  348. package/dist/process/supervisor/types.js +1 -0
  349. package/dist/providers/google-shared.test-helpers.js +75 -0
  350. package/dist/security/audit-channel.js +419 -0
  351. package/dist/security/audit-tool-policy.js +1 -0
  352. package/dist/security/scan-paths.js +12 -0
  353. package/dist/sessions/input-provenance.js +55 -0
  354. package/dist/sessions/session-key-utils.js +7 -0
  355. package/dist/shared/chat-content.js +31 -0
  356. package/dist/shared/chat-envelope.js +45 -0
  357. package/dist/shared/config-eval.js +117 -0
  358. package/dist/shared/device-auth.js +16 -0
  359. package/dist/shared/entry-metadata.js +9 -0
  360. package/dist/shared/entry-status.js +25 -0
  361. package/dist/shared/frontmatter.js +98 -0
  362. package/dist/shared/model-param-b.js +19 -0
  363. package/dist/shared/net/ipv4.js +17 -0
  364. package/dist/shared/node-match.js +53 -0
  365. package/dist/shared/pid-alive.js +12 -0
  366. package/dist/shared/process-scoped-map.js +10 -0
  367. package/dist/shared/requirements.js +128 -0
  368. package/dist/shared/subagents-format.js +84 -0
  369. package/dist/shared/usage-aggregates.js +28 -0
  370. package/dist/signal/monitor/mentions.js +45 -0
  371. package/dist/signal/rpc-context.js +19 -0
  372. package/dist/slack/blocks-fallback.js +76 -0
  373. package/dist/slack/blocks-input.js +40 -0
  374. package/dist/slack/draft-stream.js +106 -0
  375. package/dist/slack/message-actions.js +51 -0
  376. package/dist/slack/modal-metadata.js +32 -0
  377. package/dist/slack/monitor/events/interactions.js +462 -0
  378. package/dist/slack/monitor/room-context.js +17 -0
  379. package/dist/slack/stream-mode.js +41 -0
  380. package/dist/telegram/bot-native-command-menu.js +64 -0
  381. package/dist/telegram/bot.media.e2e-harness.js +81 -0
  382. package/dist/telegram/button-types.js +1 -0
  383. package/dist/telegram/group-access.js +65 -0
  384. package/dist/telegram/outbound-params.js +21 -0
  385. package/dist/telegram/poll-vote-cache.js +21 -0
  386. package/dist/terminal/health-style.js +36 -0
  387. package/dist/test-utils/chunk-test-helpers.js +21 -0
  388. package/dist/test-utils/env.js +72 -0
  389. package/dist/test-utils/exec-assertions.js +12 -0
  390. package/dist/test-utils/imessage-test-plugin.js +54 -0
  391. package/dist/test-utils/mock-http-response.js +17 -0
  392. package/dist/test-utils/vitest-mock-fn.js +1 -0
  393. package/dist/tts/tts-core.js +550 -0
  394. package/dist/utils/chunk-items.js +10 -0
  395. package/dist/utils/reaction-level.js +52 -0
  396. package/dist/utils/safe-json.js +22 -0
  397. package/dist/utils/with-timeout.js +14 -0
  398. package/dist/web/media.js +17 -5
  399. package/dist/whatsapp/resolve-outbound-target.js +42 -0
  400. package/dist/wizard/onboarding.completion.js +74 -0
  401. package/extensions/bluebubbles/package.json +1 -1
  402. package/extensions/bluebubbles/src/account-resolve.ts +29 -0
  403. package/extensions/bluebubbles/src/monitor-normalize.ts +796 -0
  404. package/extensions/bluebubbles/src/monitor-processing.ts +1007 -0
  405. package/extensions/bluebubbles/src/monitor-reply-cache.ts +185 -0
  406. package/extensions/bluebubbles/src/monitor-shared.ts +51 -0
  407. package/extensions/bluebubbles/src/multipart.ts +32 -0
  408. package/extensions/bluebubbles/src/send-helpers.ts +53 -0
  409. package/extensions/bluebubbles/src/test-harness.ts +50 -0
  410. package/extensions/bluebubbles/src/test-mocks.ts +11 -0
  411. package/extensions/copilot-proxy/package.json +1 -1
  412. package/extensions/device-pair/index.ts +554 -0
  413. package/extensions/diagnostics-otel/package.json +1 -1
  414. package/extensions/discord/package.json +1 -1
  415. package/extensions/discord/src/channel.js +366 -0
  416. package/extensions/discord/src/runtime.js +10 -0
  417. package/extensions/feishu/index.ts +63 -0
  418. package/extensions/feishu/src/accounts.ts +114 -0
  419. package/extensions/feishu/src/bitable.ts +739 -0
  420. package/extensions/feishu/src/bot.ts +965 -0
  421. package/extensions/feishu/src/channel.ts +351 -0
  422. package/extensions/feishu/src/client.ts +118 -0
  423. package/extensions/feishu/src/config-schema.ts +206 -0
  424. package/extensions/feishu/src/dedup.ts +33 -0
  425. package/extensions/feishu/src/directory.ts +177 -0
  426. package/extensions/feishu/src/doc-schema.ts +47 -0
  427. package/extensions/feishu/src/docx.ts +536 -0
  428. package/extensions/feishu/src/drive-schema.ts +46 -0
  429. package/extensions/feishu/src/drive.ts +227 -0
  430. package/extensions/feishu/src/dynamic-agent.ts +131 -0
  431. package/extensions/feishu/src/media.ts +449 -0
  432. package/extensions/feishu/src/mention.ts +126 -0
  433. package/extensions/feishu/src/monitor.ts +330 -0
  434. package/extensions/feishu/src/onboarding.ts +359 -0
  435. package/extensions/feishu/src/outbound.ts +55 -0
  436. package/extensions/feishu/src/perm-schema.ts +52 -0
  437. package/extensions/feishu/src/perm.ts +173 -0
  438. package/extensions/feishu/src/policy.ts +84 -0
  439. package/extensions/feishu/src/probe.ts +44 -0
  440. package/extensions/feishu/src/reactions.ts +160 -0
  441. package/extensions/feishu/src/reply-dispatcher.ts +239 -0
  442. package/extensions/feishu/src/runtime.ts +14 -0
  443. package/extensions/feishu/src/send-result.ts +29 -0
  444. package/extensions/feishu/src/send.ts +335 -0
  445. package/extensions/feishu/src/streaming-card.ts +223 -0
  446. package/extensions/feishu/src/targets.ts +78 -0
  447. package/extensions/feishu/src/tools-config.ts +21 -0
  448. package/extensions/feishu/src/types.ts +81 -0
  449. package/extensions/feishu/src/typing.ts +80 -0
  450. package/extensions/feishu/src/wiki-schema.ts +55 -0
  451. package/extensions/feishu/src/wiki.ts +232 -0
  452. package/extensions/google-antigravity-auth/package.json +1 -1
  453. package/extensions/google-gemini-cli-auth/package.json +1 -1
  454. package/extensions/googlechat/package.json +1 -1
  455. package/extensions/imessage/package.json +1 -1
  456. package/extensions/imessage/src/channel.js +253 -0
  457. package/extensions/imessage/src/runtime.js +10 -0
  458. package/extensions/irc/index.ts +17 -0
  459. package/extensions/irc/src/accounts.ts +268 -0
  460. package/extensions/irc/src/channel.ts +367 -0
  461. package/extensions/irc/src/client.ts +439 -0
  462. package/extensions/irc/src/config-schema.ts +97 -0
  463. package/extensions/irc/src/connect-options.ts +30 -0
  464. package/extensions/irc/src/control-chars.ts +22 -0
  465. package/extensions/irc/src/inbound.ts +334 -0
  466. package/extensions/irc/src/monitor.ts +147 -0
  467. package/extensions/irc/src/normalize.ts +117 -0
  468. package/extensions/irc/src/onboarding.ts +479 -0
  469. package/extensions/irc/src/policy.ts +157 -0
  470. package/extensions/irc/src/probe.ts +53 -0
  471. package/extensions/irc/src/protocol.ts +169 -0
  472. package/extensions/irc/src/runtime.ts +14 -0
  473. package/extensions/irc/src/send.ts +88 -0
  474. package/extensions/irc/src/types.ts +93 -0
  475. package/extensions/line/package.json +1 -1
  476. package/extensions/llm-task/package.json +1 -1
  477. package/extensions/lobster/package.json +1 -1
  478. package/extensions/matrix/CHANGELOG.md +5 -0
  479. package/extensions/matrix/package.json +1 -1
  480. package/extensions/matrix/src/matrix/client-bootstrap.ts +39 -0
  481. package/extensions/mattermost/package.json +1 -1
  482. package/extensions/mattermost/src/mattermost/monitor-onchar.ts +25 -0
  483. package/extensions/mattermost/src/mattermost/monitor-websocket.ts +221 -0
  484. package/extensions/mattermost/src/mattermost/reactions.ts +130 -0
  485. package/extensions/mattermost/src/mattermost/reconnect.ts +103 -0
  486. package/extensions/memory-core/package.json +1 -1
  487. package/extensions/memory-lancedb/package.json +1 -1
  488. package/extensions/minimax-portal-auth/index.ts +161 -0
  489. package/extensions/minimax-portal-auth/oauth.ts +247 -0
  490. package/extensions/msteams/CHANGELOG.md +5 -0
  491. package/extensions/msteams/package.json +1 -1
  492. package/extensions/msteams/src/file-lock.ts +1 -0
  493. package/extensions/msteams/src/graph.ts +92 -0
  494. package/extensions/msteams/src/mentions.ts +114 -0
  495. package/extensions/msteams/src/test-runtime.ts +16 -0
  496. package/extensions/nextcloud-talk/package.json +1 -1
  497. package/extensions/nostr/CHANGELOG.md +5 -0
  498. package/extensions/nostr/package.json +1 -1
  499. package/extensions/open-prose/package.json +1 -1
  500. package/extensions/openai-codex-auth/index.ts +177 -0
  501. package/extensions/phone-control/index.ts +421 -0
  502. package/extensions/shared/resolve-target-test-helpers.ts +66 -0
  503. package/extensions/signal/package.json +1 -1
  504. package/extensions/signal/src/channel.js +273 -0
  505. package/extensions/signal/src/runtime.js +10 -0
  506. package/extensions/slack/package.json +1 -1
  507. package/extensions/slack/src/channel.js +489 -0
  508. package/extensions/slack/src/runtime.js +10 -0
  509. package/extensions/talk-voice/index.ts +150 -0
  510. package/extensions/telegram/package.json +1 -1
  511. package/extensions/telegram/src/channel.js +424 -0
  512. package/extensions/telegram/src/runtime.js +10 -0
  513. package/extensions/thread-ownership/index.ts +133 -0
  514. package/extensions/tlon/package.json +1 -1
  515. package/extensions/tlon/src/account-fields.ts +25 -0
  516. package/extensions/tlon/src/urbit/base-url.ts +57 -0
  517. package/extensions/tlon/src/urbit/channel-client.ts +157 -0
  518. package/extensions/tlon/src/urbit/channel-ops.ts +164 -0
  519. package/extensions/tlon/src/urbit/context.ts +47 -0
  520. package/extensions/tlon/src/urbit/errors.ts +51 -0
  521. package/extensions/tlon/src/urbit/fetch.ts +39 -0
  522. package/extensions/twitch/CHANGELOG.md +5 -0
  523. package/extensions/twitch/package.json +1 -1
  524. package/extensions/twitch/src/test-fixtures.ts +30 -0
  525. package/extensions/voice-call/CHANGELOG.md +5 -0
  526. package/extensions/voice-call/package.json +1 -1
  527. package/extensions/voice-call/src/allowlist.ts +19 -0
  528. package/extensions/whatsapp/package.json +1 -1
  529. package/extensions/whatsapp/src/channel.js +429 -0
  530. package/extensions/whatsapp/src/runtime.js +10 -0
  531. package/extensions/zalo/CHANGELOG.md +5 -0
  532. package/extensions/zalo/package.json +1 -1
  533. package/extensions/zalouser/CHANGELOG.md +5 -0
  534. package/extensions/zalouser/package.json +1 -1
  535. package/package.json +1 -1
@@ -2,6 +2,7 @@ import { loadConfig } from "../config/config.js";
2
2
  import { callGateway } from "../gateway/call.js";
3
3
  import { onAgentEvent } from "../infra/agent-events.js";
4
4
  import { normalizeDeliveryContext } from "../utils/delivery-context.js";
5
+ import { resetAnnounceQueuesForTests } from "./subagent-announce-queue.js";
5
6
  import { runSubagentAnnounceFlow } from "./subagent-announce.js";
6
7
  import { loadSubagentRegistryFromDisk, saveSubagentRegistryToDisk, } from "./subagent-registry.store.js";
7
8
  import { resolveAgentTimeoutMs } from "./timeout.js";
@@ -11,6 +12,19 @@ let listenerStarted = false;
11
12
  let listenerStop = null;
12
13
  // Use var to avoid TDZ when init runs across circular imports during bootstrap.
13
14
  var restoreAttempted = false;
15
+ const SUBAGENT_ANNOUNCE_TIMEOUT_MS = 120_000;
16
+ /**
17
+ * Maximum number of announce delivery attempts before giving up.
18
+ * Prevents infinite retry loops when `runSubagentAnnounceFlow` repeatedly
19
+ * returns `false` due to stale state or transient conditions (#18264).
20
+ */
21
+ const MAX_ANNOUNCE_RETRY_COUNT = 3;
22
+ /**
23
+ * Announce entries older than this are force-expired even if delivery never
24
+ * succeeded. Guards against stale registry entries surviving gateway restarts.
25
+ */
26
+ const ANNOUNCE_EXPIRY_MS = 5 * 60_000; // 5 minutes
27
+ // (Backoff constant removed — max-retry + expiry guards are sufficient.)
14
28
  function persistSubagentRuns() {
15
29
  try {
16
30
  saveSubagentRegistryToDisk(subagentRuns);
@@ -20,55 +34,86 @@ function persistSubagentRuns() {
20
34
  }
21
35
  }
22
36
  const resumedRuns = new Set();
37
+ function suppressAnnounceForSteerRestart(entry) {
38
+ return entry?.suppressAnnounceReason === "steer-restart";
39
+ }
40
+ function startSubagentAnnounceCleanupFlow(runId, entry) {
41
+ if (!beginSubagentCleanup(runId)) {
42
+ return false;
43
+ }
44
+ const requesterOrigin = normalizeDeliveryContext(entry.requesterOrigin);
45
+ void runSubagentAnnounceFlow({
46
+ childSessionKey: entry.childSessionKey,
47
+ childRunId: entry.runId,
48
+ requesterSessionKey: entry.requesterSessionKey,
49
+ requesterOrigin,
50
+ requesterDisplayKey: entry.requesterDisplayKey,
51
+ task: entry.task,
52
+ timeoutMs: SUBAGENT_ANNOUNCE_TIMEOUT_MS,
53
+ cleanup: entry.cleanup,
54
+ waitForCompletion: false,
55
+ startedAt: entry.startedAt,
56
+ endedAt: entry.endedAt,
57
+ label: entry.label,
58
+ outcome: entry.outcome,
59
+ }).then((didAnnounce) => {
60
+ finalizeSubagentCleanup(runId, entry.cleanup, didAnnounce);
61
+ });
62
+ return true;
63
+ }
23
64
  function resumeSubagentRun(runId) {
24
- if (!runId || resumedRuns.has(runId))
65
+ if (!runId || resumedRuns.has(runId)) {
25
66
  return;
67
+ }
26
68
  const entry = subagentRuns.get(runId);
27
- if (!entry)
69
+ if (!entry) {
70
+ return;
71
+ }
72
+ if (entry.cleanupCompletedAt) {
73
+ return;
74
+ }
75
+ // Skip entries that have exhausted their retry budget or expired (#18264).
76
+ if ((entry.announceRetryCount ?? 0) >= MAX_ANNOUNCE_RETRY_COUNT) {
77
+ entry.cleanupCompletedAt = Date.now();
78
+ persistSubagentRuns();
28
79
  return;
29
- if (entry.cleanupCompletedAt)
80
+ }
81
+ if (typeof entry.endedAt === "number" && Date.now() - entry.endedAt > ANNOUNCE_EXPIRY_MS) {
82
+ entry.cleanupCompletedAt = Date.now();
83
+ persistSubagentRuns();
30
84
  return;
85
+ }
31
86
  if (typeof entry.endedAt === "number" && entry.endedAt > 0) {
32
- if (!beginSubagentCleanup(runId))
87
+ if (suppressAnnounceForSteerRestart(entry)) {
88
+ resumedRuns.add(runId);
33
89
  return;
34
- const requesterOrigin = normalizeDeliveryContext(entry.requesterOrigin);
35
- void runSubagentAnnounceFlow({
36
- childSessionKey: entry.childSessionKey,
37
- childRunId: entry.runId,
38
- requesterSessionKey: entry.requesterSessionKey,
39
- requesterOrigin,
40
- requesterDisplayKey: entry.requesterDisplayKey,
41
- task: entry.task,
42
- timeoutMs: 30_000,
43
- cleanup: entry.cleanup,
44
- waitForCompletion: false,
45
- startedAt: entry.startedAt,
46
- endedAt: entry.endedAt,
47
- label: entry.label,
48
- outcome: entry.outcome,
49
- }).then((didAnnounce) => {
50
- finalizeSubagentCleanup(runId, entry.cleanup, didAnnounce);
51
- });
90
+ }
91
+ if (!startSubagentAnnounceCleanupFlow(runId, entry)) {
92
+ return;
93
+ }
52
94
  resumedRuns.add(runId);
53
95
  return;
54
96
  }
55
97
  // Wait for completion again after restart.
56
98
  const cfg = loadConfig();
57
- const waitTimeoutMs = resolveSubagentWaitTimeoutMs(cfg, undefined);
99
+ const waitTimeoutMs = resolveSubagentWaitTimeoutMs(cfg, entry.runTimeoutSeconds);
58
100
  void waitForSubagentCompletion(runId, waitTimeoutMs);
59
101
  resumedRuns.add(runId);
60
102
  }
61
103
  function restoreSubagentRunsOnce() {
62
- if (restoreAttempted)
104
+ if (restoreAttempted) {
63
105
  return;
106
+ }
64
107
  restoreAttempted = true;
65
108
  try {
66
109
  const restored = loadSubagentRegistryFromDisk();
67
- if (restored.size === 0)
110
+ if (restored.size === 0) {
68
111
  return;
112
+ }
69
113
  for (const [runId, entry] of restored.entries()) {
70
- if (!runId || !entry)
114
+ if (!runId || !entry) {
71
115
  continue;
116
+ }
72
117
  // Keep any newer in-memory entries.
73
118
  if (!subagentRuns.has(runId)) {
74
119
  subagentRuns.set(runId, entry);
@@ -90,24 +135,27 @@ function restoreSubagentRunsOnce() {
90
135
  function resolveArchiveAfterMs(cfg) {
91
136
  const config = cfg ?? loadConfig();
92
137
  const minutes = config.agents?.defaults?.subagents?.archiveAfterMinutes ?? 60;
93
- if (!Number.isFinite(minutes) || minutes <= 0)
138
+ if (!Number.isFinite(minutes) || minutes <= 0) {
94
139
  return undefined;
140
+ }
95
141
  return Math.max(1, Math.floor(minutes)) * 60_000;
96
142
  }
97
143
  function resolveSubagentWaitTimeoutMs(cfg, runTimeoutSeconds) {
98
- return resolveAgentTimeoutMs({ cfg, overrideSeconds: runTimeoutSeconds });
144
+ return resolveAgentTimeoutMs({ cfg, overrideSeconds: runTimeoutSeconds ?? 0 });
99
145
  }
100
146
  function startSweeper() {
101
- if (sweeper)
147
+ if (sweeper) {
102
148
  return;
149
+ }
103
150
  sweeper = setInterval(() => {
104
151
  void sweepSubagentRuns();
105
152
  }, 60_000);
106
153
  sweeper.unref?.();
107
154
  }
108
155
  function stopSweeper() {
109
- if (!sweeper)
156
+ if (!sweeper) {
110
157
  return;
158
+ }
111
159
  clearInterval(sweeper);
112
160
  sweeper = null;
113
161
  }
@@ -115,8 +163,9 @@ async function sweepSubagentRuns() {
115
163
  const now = Date.now();
116
164
  let mutated = false;
117
165
  for (const [runId, entry] of subagentRuns.entries()) {
118
- if (!entry.archiveAtMs || entry.archiveAtMs > now)
166
+ if (!entry.archiveAtMs || entry.archiveAtMs > now) {
119
167
  continue;
168
+ }
120
169
  subagentRuns.delete(runId);
121
170
  mutated = true;
122
171
  try {
@@ -130,10 +179,12 @@ async function sweepSubagentRuns() {
130
179
  // ignore
131
180
  }
132
181
  }
133
- if (mutated)
182
+ if (mutated) {
134
183
  persistSubagentRuns();
135
- if (subagentRuns.size === 0)
184
+ }
185
+ if (subagentRuns.size === 0) {
136
186
  stopSweeper();
187
+ }
137
188
  }
138
189
  function ensureListener() {
139
190
  if (listenerStarted) {
@@ -141,8 +192,9 @@ function ensureListener() {
141
192
  }
142
193
  listenerStarted = true;
143
194
  listenerStop = onAgentEvent((evt) => {
144
- if (!evt || evt.stream !== "lifecycle")
195
+ if (!evt || evt.stream !== "lifecycle") {
145
196
  return;
197
+ }
146
198
  const entry = subagentRuns.get(evt.runId);
147
199
  if (!entry) {
148
200
  return;
@@ -156,77 +208,194 @@ function ensureListener() {
156
208
  }
157
209
  return;
158
210
  }
159
- if (phase !== "end" && phase !== "error")
211
+ if (phase !== "end" && phase !== "error") {
160
212
  return;
213
+ }
161
214
  const endedAt = typeof evt.data?.endedAt === "number" ? evt.data.endedAt : Date.now();
162
215
  entry.endedAt = endedAt;
163
216
  if (phase === "error") {
164
217
  const error = typeof evt.data?.error === "string" ? evt.data.error : undefined;
165
218
  entry.outcome = { status: "error", error };
166
219
  }
220
+ else if (evt.data?.aborted) {
221
+ entry.outcome = { status: "timeout" };
222
+ }
167
223
  else {
168
224
  entry.outcome = { status: "ok" };
169
225
  }
170
226
  persistSubagentRuns();
171
- if (!beginSubagentCleanup(evt.runId)) {
227
+ if (suppressAnnounceForSteerRestart(entry)) {
228
+ return;
229
+ }
230
+ if (!startSubagentAnnounceCleanupFlow(evt.runId, entry)) {
172
231
  return;
173
232
  }
174
- const requesterOrigin = normalizeDeliveryContext(entry.requesterOrigin);
175
- void runSubagentAnnounceFlow({
176
- childSessionKey: entry.childSessionKey,
177
- childRunId: entry.runId,
178
- requesterSessionKey: entry.requesterSessionKey,
179
- requesterOrigin,
180
- requesterDisplayKey: entry.requesterDisplayKey,
181
- task: entry.task,
182
- timeoutMs: 30_000,
183
- cleanup: entry.cleanup,
184
- waitForCompletion: false,
185
- startedAt: entry.startedAt,
186
- endedAt: entry.endedAt,
187
- label: entry.label,
188
- outcome: entry.outcome,
189
- }).then((didAnnounce) => {
190
- finalizeSubagentCleanup(evt.runId, entry.cleanup, didAnnounce);
191
- });
192
233
  });
193
234
  }
194
235
  function finalizeSubagentCleanup(runId, cleanup, didAnnounce) {
195
236
  const entry = subagentRuns.get(runId);
196
- if (!entry)
197
- return;
198
- if (cleanup === "delete") {
199
- subagentRuns.delete(runId);
200
- persistSubagentRuns();
237
+ if (!entry) {
201
238
  return;
202
239
  }
203
240
  if (!didAnnounce) {
204
- // Allow retry on the next wake if the announce failed.
241
+ const retryCount = (entry.announceRetryCount ?? 0) + 1;
242
+ entry.announceRetryCount = retryCount;
243
+ entry.lastAnnounceRetryAt = Date.now();
244
+ // Check if the announce has exceeded retry limits or expired (#18264).
245
+ const endedAgo = typeof entry.endedAt === "number" ? Date.now() - entry.endedAt : 0;
246
+ if (retryCount >= MAX_ANNOUNCE_RETRY_COUNT || endedAgo > ANNOUNCE_EXPIRY_MS) {
247
+ // Give up: mark as completed to break the infinite retry loop.
248
+ entry.cleanupCompletedAt = Date.now();
249
+ persistSubagentRuns();
250
+ retryDeferredCompletedAnnounces(runId);
251
+ return;
252
+ }
253
+ // Allow retry on the next wake if announce was deferred or failed.
205
254
  entry.cleanupHandled = false;
255
+ resumedRuns.delete(runId);
206
256
  persistSubagentRuns();
207
257
  return;
208
258
  }
259
+ if (cleanup === "delete") {
260
+ subagentRuns.delete(runId);
261
+ persistSubagentRuns();
262
+ retryDeferredCompletedAnnounces(runId);
263
+ return;
264
+ }
209
265
  entry.cleanupCompletedAt = Date.now();
210
266
  persistSubagentRuns();
267
+ retryDeferredCompletedAnnounces(runId);
268
+ }
269
+ function retryDeferredCompletedAnnounces(excludeRunId) {
270
+ const now = Date.now();
271
+ for (const [runId, entry] of subagentRuns.entries()) {
272
+ if (excludeRunId && runId === excludeRunId) {
273
+ continue;
274
+ }
275
+ if (typeof entry.endedAt !== "number") {
276
+ continue;
277
+ }
278
+ if (entry.cleanupCompletedAt || entry.cleanupHandled) {
279
+ continue;
280
+ }
281
+ if (suppressAnnounceForSteerRestart(entry)) {
282
+ continue;
283
+ }
284
+ // Force-expire announces that have been pending too long (#18264).
285
+ const endedAgo = now - (entry.endedAt ?? now);
286
+ if (endedAgo > ANNOUNCE_EXPIRY_MS) {
287
+ entry.cleanupCompletedAt = now;
288
+ persistSubagentRuns();
289
+ continue;
290
+ }
291
+ resumedRuns.delete(runId);
292
+ resumeSubagentRun(runId);
293
+ }
211
294
  }
212
295
  function beginSubagentCleanup(runId) {
213
296
  const entry = subagentRuns.get(runId);
214
- if (!entry)
297
+ if (!entry) {
215
298
  return false;
216
- if (entry.cleanupCompletedAt)
299
+ }
300
+ if (entry.cleanupCompletedAt) {
217
301
  return false;
218
- if (entry.cleanupHandled)
302
+ }
303
+ if (entry.cleanupHandled) {
219
304
  return false;
305
+ }
220
306
  entry.cleanupHandled = true;
221
307
  persistSubagentRuns();
222
308
  return true;
223
309
  }
310
+ export function markSubagentRunForSteerRestart(runId) {
311
+ const key = runId.trim();
312
+ if (!key) {
313
+ return false;
314
+ }
315
+ const entry = subagentRuns.get(key);
316
+ if (!entry) {
317
+ return false;
318
+ }
319
+ if (entry.suppressAnnounceReason === "steer-restart") {
320
+ return true;
321
+ }
322
+ entry.suppressAnnounceReason = "steer-restart";
323
+ persistSubagentRuns();
324
+ return true;
325
+ }
326
+ export function clearSubagentRunSteerRestart(runId) {
327
+ const key = runId.trim();
328
+ if (!key) {
329
+ return false;
330
+ }
331
+ const entry = subagentRuns.get(key);
332
+ if (!entry) {
333
+ return false;
334
+ }
335
+ if (entry.suppressAnnounceReason !== "steer-restart") {
336
+ return true;
337
+ }
338
+ entry.suppressAnnounceReason = undefined;
339
+ persistSubagentRuns();
340
+ // If the interrupted run already finished while suppression was active, retry
341
+ // cleanup now so completion output is not lost when restart dispatch fails.
342
+ resumedRuns.delete(key);
343
+ if (typeof entry.endedAt === "number" && !entry.cleanupCompletedAt) {
344
+ resumeSubagentRun(key);
345
+ }
346
+ return true;
347
+ }
348
+ export function replaceSubagentRunAfterSteer(params) {
349
+ const previousRunId = params.previousRunId.trim();
350
+ const nextRunId = params.nextRunId.trim();
351
+ if (!previousRunId || !nextRunId) {
352
+ return false;
353
+ }
354
+ const previous = subagentRuns.get(previousRunId);
355
+ const source = previous ?? params.fallback;
356
+ if (!source) {
357
+ return false;
358
+ }
359
+ if (previousRunId !== nextRunId) {
360
+ subagentRuns.delete(previousRunId);
361
+ resumedRuns.delete(previousRunId);
362
+ }
363
+ const now = Date.now();
364
+ const cfg = loadConfig();
365
+ const archiveAfterMs = resolveArchiveAfterMs(cfg);
366
+ const archiveAtMs = archiveAfterMs ? now + archiveAfterMs : undefined;
367
+ const runTimeoutSeconds = params.runTimeoutSeconds ?? source.runTimeoutSeconds ?? 0;
368
+ const waitTimeoutMs = resolveSubagentWaitTimeoutMs(cfg, runTimeoutSeconds);
369
+ const next = {
370
+ ...source,
371
+ runId: nextRunId,
372
+ startedAt: now,
373
+ endedAt: undefined,
374
+ outcome: undefined,
375
+ cleanupCompletedAt: undefined,
376
+ cleanupHandled: false,
377
+ suppressAnnounceReason: undefined,
378
+ announceRetryCount: undefined,
379
+ lastAnnounceRetryAt: undefined,
380
+ archiveAtMs,
381
+ runTimeoutSeconds,
382
+ };
383
+ subagentRuns.set(nextRunId, next);
384
+ ensureListener();
385
+ persistSubagentRuns();
386
+ if (archiveAtMs) {
387
+ startSweeper();
388
+ }
389
+ void waitForSubagentCompletion(nextRunId, waitTimeoutMs);
390
+ return true;
391
+ }
224
392
  export function registerSubagentRun(params) {
225
393
  const now = Date.now();
226
394
  const cfg = loadConfig();
227
395
  const archiveAfterMs = resolveArchiveAfterMs(cfg);
228
396
  const archiveAtMs = archiveAfterMs ? now + archiveAfterMs : undefined;
229
- const waitTimeoutMs = resolveSubagentWaitTimeoutMs(cfg, params.runTimeoutSeconds);
397
+ const runTimeoutSeconds = params.runTimeoutSeconds ?? 0;
398
+ const waitTimeoutMs = resolveSubagentWaitTimeoutMs(cfg, runTimeoutSeconds);
230
399
  const requesterOrigin = normalizeDeliveryContext(params.requesterOrigin);
231
400
  subagentRuns.set(params.runId, {
232
401
  runId: params.runId,
@@ -237,6 +406,8 @@ export function registerSubagentRun(params) {
237
406
  task: params.task,
238
407
  cleanup: params.cleanup,
239
408
  label: params.label,
409
+ model: params.model,
410
+ runTimeoutSeconds,
240
411
  createdAt: now,
241
412
  startedAt: now,
242
413
  archiveAtMs,
@@ -244,8 +415,9 @@ export function registerSubagentRun(params) {
244
415
  });
245
416
  ensureListener();
246
417
  persistSubagentRuns();
247
- if (archiveAfterMs)
418
+ if (archiveAfterMs) {
248
419
  startSweeper();
420
+ }
249
421
  // Wait for subagent completion via gateway RPC (cross-process).
250
422
  // The in-process lifecycle listener is a fallback for embedded runs.
251
423
  void waitForSubagentCompletion(params.runId, waitTimeoutMs);
@@ -253,19 +425,21 @@ export function registerSubagentRun(params) {
253
425
  async function waitForSubagentCompletion(runId, waitTimeoutMs) {
254
426
  try {
255
427
  const timeoutMs = Math.max(1, Math.floor(waitTimeoutMs));
256
- const wait = (await callGateway({
428
+ const wait = await callGateway({
257
429
  method: "agent.wait",
258
430
  params: {
259
431
  runId,
260
432
  timeoutMs,
261
433
  },
262
434
  timeoutMs: timeoutMs + 10_000,
263
- }));
264
- if (wait?.status !== "ok" && wait?.status !== "error")
435
+ });
436
+ if (wait?.status !== "ok" && wait?.status !== "error" && wait?.status !== "timeout") {
265
437
  return;
438
+ }
266
439
  const entry = subagentRuns.get(runId);
267
- if (!entry)
440
+ if (!entry) {
268
441
  return;
442
+ }
269
443
  let mutated = false;
270
444
  if (typeof wait.startedAt === "number") {
271
445
  entry.startedAt = wait.startedAt;
@@ -279,39 +453,32 @@ async function waitForSubagentCompletion(runId, waitTimeoutMs) {
279
453
  entry.endedAt = Date.now();
280
454
  mutated = true;
281
455
  }
456
+ const waitError = typeof wait.error === "string" ? wait.error : undefined;
282
457
  entry.outcome =
283
- wait.status === "error" ? { status: "error", error: wait.error } : { status: "ok" };
458
+ wait.status === "error"
459
+ ? { status: "error", error: waitError }
460
+ : wait.status === "timeout"
461
+ ? { status: "timeout" }
462
+ : { status: "ok" };
284
463
  mutated = true;
285
- if (mutated)
464
+ if (mutated) {
286
465
  persistSubagentRuns();
287
- if (!beginSubagentCleanup(runId))
466
+ }
467
+ if (suppressAnnounceForSteerRestart(entry)) {
288
468
  return;
289
- const requesterOrigin = normalizeDeliveryContext(entry.requesterOrigin);
290
- void runSubagentAnnounceFlow({
291
- childSessionKey: entry.childSessionKey,
292
- childRunId: entry.runId,
293
- requesterSessionKey: entry.requesterSessionKey,
294
- requesterOrigin,
295
- requesterDisplayKey: entry.requesterDisplayKey,
296
- task: entry.task,
297
- timeoutMs: 30_000,
298
- cleanup: entry.cleanup,
299
- waitForCompletion: false,
300
- startedAt: entry.startedAt,
301
- endedAt: entry.endedAt,
302
- label: entry.label,
303
- outcome: entry.outcome,
304
- }).then((didAnnounce) => {
305
- finalizeSubagentCleanup(runId, entry.cleanup, didAnnounce);
306
- });
469
+ }
470
+ if (!startSubagentAnnounceCleanupFlow(runId, entry)) {
471
+ return;
472
+ }
307
473
  }
308
474
  catch {
309
475
  // ignore
310
476
  }
311
477
  }
312
- export function resetSubagentRegistryForTests() {
478
+ export function resetSubagentRegistryForTests(opts) {
313
479
  subagentRuns.clear();
314
480
  resumedRuns.clear();
481
+ resetAnnounceQueuesForTests();
315
482
  stopSweeper();
316
483
  restoreAttempted = false;
317
484
  if (listenerStop) {
@@ -319,25 +486,210 @@ export function resetSubagentRegistryForTests() {
319
486
  listenerStop = null;
320
487
  }
321
488
  listenerStarted = false;
322
- persistSubagentRuns();
489
+ if (opts?.persist !== false) {
490
+ persistSubagentRuns();
491
+ }
323
492
  }
324
493
  export function addSubagentRunForTests(entry) {
325
494
  subagentRuns.set(entry.runId, entry);
326
- persistSubagentRuns();
327
495
  }
328
496
  export function releaseSubagentRun(runId) {
329
497
  const didDelete = subagentRuns.delete(runId);
330
- if (didDelete)
498
+ if (didDelete) {
331
499
  persistSubagentRuns();
332
- if (subagentRuns.size === 0)
500
+ }
501
+ if (subagentRuns.size === 0) {
333
502
  stopSweeper();
503
+ }
504
+ }
505
+ function findRunIdsByChildSessionKey(childSessionKey) {
506
+ const key = childSessionKey.trim();
507
+ if (!key) {
508
+ return [];
509
+ }
510
+ const runIds = [];
511
+ for (const [runId, entry] of subagentRuns.entries()) {
512
+ if (entry.childSessionKey === key) {
513
+ runIds.push(runId);
514
+ }
515
+ }
516
+ return runIds;
517
+ }
518
+ function getRunsSnapshotForRead() {
519
+ const merged = new Map();
520
+ const shouldReadDisk = !(process.env.VITEST || process.env.NODE_ENV === "test");
521
+ if (shouldReadDisk) {
522
+ try {
523
+ // Registry state is persisted to disk so other worker processes (for
524
+ // example cron runners) can observe active children spawned elsewhere.
525
+ for (const [runId, entry] of loadSubagentRegistryFromDisk().entries()) {
526
+ merged.set(runId, entry);
527
+ }
528
+ }
529
+ catch {
530
+ // Ignore disk read failures and fall back to local memory state.
531
+ }
532
+ }
533
+ for (const [runId, entry] of subagentRuns.entries()) {
534
+ merged.set(runId, entry);
535
+ }
536
+ return merged;
537
+ }
538
+ export function resolveRequesterForChildSession(childSessionKey) {
539
+ const key = childSessionKey.trim();
540
+ if (!key) {
541
+ return null;
542
+ }
543
+ let best;
544
+ for (const entry of getRunsSnapshotForRead().values()) {
545
+ if (entry.childSessionKey !== key) {
546
+ continue;
547
+ }
548
+ if (!best || entry.createdAt > best.createdAt) {
549
+ best = entry;
550
+ }
551
+ }
552
+ if (!best) {
553
+ return null;
554
+ }
555
+ return {
556
+ requesterSessionKey: best.requesterSessionKey,
557
+ requesterOrigin: normalizeDeliveryContext(best.requesterOrigin),
558
+ };
559
+ }
560
+ export function isSubagentSessionRunActive(childSessionKey) {
561
+ const runIds = findRunIdsByChildSessionKey(childSessionKey);
562
+ for (const runId of runIds) {
563
+ const entry = subagentRuns.get(runId);
564
+ if (!entry) {
565
+ continue;
566
+ }
567
+ if (typeof entry.endedAt !== "number") {
568
+ return true;
569
+ }
570
+ }
571
+ return false;
572
+ }
573
+ export function markSubagentRunTerminated(params) {
574
+ const runIds = new Set();
575
+ if (typeof params.runId === "string" && params.runId.trim()) {
576
+ runIds.add(params.runId.trim());
577
+ }
578
+ if (typeof params.childSessionKey === "string" && params.childSessionKey.trim()) {
579
+ for (const runId of findRunIdsByChildSessionKey(params.childSessionKey)) {
580
+ runIds.add(runId);
581
+ }
582
+ }
583
+ if (runIds.size === 0) {
584
+ return 0;
585
+ }
586
+ const now = Date.now();
587
+ const reason = params.reason?.trim() || "killed";
588
+ let updated = 0;
589
+ for (const runId of runIds) {
590
+ const entry = subagentRuns.get(runId);
591
+ if (!entry) {
592
+ continue;
593
+ }
594
+ if (typeof entry.endedAt === "number") {
595
+ continue;
596
+ }
597
+ entry.endedAt = now;
598
+ entry.outcome = { status: "error", error: reason };
599
+ entry.cleanupHandled = true;
600
+ entry.cleanupCompletedAt = now;
601
+ entry.suppressAnnounceReason = "killed";
602
+ updated += 1;
603
+ }
604
+ if (updated > 0) {
605
+ persistSubagentRuns();
606
+ }
607
+ return updated;
334
608
  }
335
609
  export function listSubagentRunsForRequester(requesterSessionKey) {
336
610
  const key = requesterSessionKey.trim();
337
- if (!key)
611
+ if (!key) {
338
612
  return [];
613
+ }
339
614
  return [...subagentRuns.values()].filter((entry) => entry.requesterSessionKey === key);
340
615
  }
616
+ export function countActiveRunsForSession(requesterSessionKey) {
617
+ const key = requesterSessionKey.trim();
618
+ if (!key) {
619
+ return 0;
620
+ }
621
+ let count = 0;
622
+ for (const entry of getRunsSnapshotForRead().values()) {
623
+ if (entry.requesterSessionKey !== key) {
624
+ continue;
625
+ }
626
+ if (typeof entry.endedAt === "number") {
627
+ continue;
628
+ }
629
+ count += 1;
630
+ }
631
+ return count;
632
+ }
633
+ export function countActiveDescendantRuns(rootSessionKey) {
634
+ const root = rootSessionKey.trim();
635
+ if (!root) {
636
+ return 0;
637
+ }
638
+ const runs = getRunsSnapshotForRead();
639
+ const pending = [root];
640
+ const visited = new Set([root]);
641
+ let count = 0;
642
+ while (pending.length > 0) {
643
+ const requester = pending.shift();
644
+ if (!requester) {
645
+ continue;
646
+ }
647
+ for (const entry of runs.values()) {
648
+ if (entry.requesterSessionKey !== requester) {
649
+ continue;
650
+ }
651
+ if (typeof entry.endedAt !== "number") {
652
+ count += 1;
653
+ }
654
+ const childKey = entry.childSessionKey.trim();
655
+ if (!childKey || visited.has(childKey)) {
656
+ continue;
657
+ }
658
+ visited.add(childKey);
659
+ pending.push(childKey);
660
+ }
661
+ }
662
+ return count;
663
+ }
664
+ export function listDescendantRunsForRequester(rootSessionKey) {
665
+ const root = rootSessionKey.trim();
666
+ if (!root) {
667
+ return [];
668
+ }
669
+ const runs = getRunsSnapshotForRead();
670
+ const pending = [root];
671
+ const visited = new Set([root]);
672
+ const descendants = [];
673
+ while (pending.length > 0) {
674
+ const requester = pending.shift();
675
+ if (!requester) {
676
+ continue;
677
+ }
678
+ for (const entry of runs.values()) {
679
+ if (entry.requesterSessionKey !== requester) {
680
+ continue;
681
+ }
682
+ descendants.push(entry);
683
+ const childKey = entry.childSessionKey.trim();
684
+ if (!childKey || visited.has(childKey)) {
685
+ continue;
686
+ }
687
+ visited.add(childKey);
688
+ pending.push(childKey);
689
+ }
690
+ }
691
+ return descendants;
692
+ }
341
693
  export function initSubagentRegistry() {
342
694
  restoreSubagentRunsOnce();
343
695
  }