@poolzin/pool-bot 2026.2.24 → 2026.2.26

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 (646) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/acp/client.js +207 -18
  3. package/dist/acp/event-mapper.js +87 -22
  4. package/dist/acp/meta.js +12 -6
  5. package/dist/acp/secret-file.js +22 -0
  6. package/dist/agents/agent-paths.js +8 -9
  7. package/dist/agents/agent-scope.js +17 -5
  8. package/dist/agents/auth-profiles/oauth.js +148 -64
  9. package/dist/agents/auth-profiles/session-override.js +13 -7
  10. package/dist/agents/bash-process-registry.test-helpers.js +29 -0
  11. package/dist/agents/bash-tools.exec-approval-request.js +20 -0
  12. package/dist/agents/bash-tools.exec-host-gateway.js +240 -0
  13. package/dist/agents/bash-tools.exec-host-node.js +235 -0
  14. package/dist/agents/bash-tools.exec-runtime.js +2 -25
  15. package/dist/agents/bash-tools.exec-types.js +1 -0
  16. package/dist/agents/bash-tools.process.js +224 -218
  17. package/dist/agents/bedrock-discovery.js +3 -1
  18. package/dist/agents/byteplus-models.js +97 -0
  19. package/dist/agents/chutes-oauth.js +1 -0
  20. package/dist/agents/cli-runner/helpers.js +4 -0
  21. package/dist/agents/compaction.js +41 -14
  22. package/dist/agents/content-blocks.js +16 -0
  23. package/dist/agents/doubao-models.js +121 -0
  24. package/dist/agents/failover-error.js +2 -0
  25. package/dist/agents/huggingface-models.js +5 -3
  26. package/dist/agents/live-model-filter.js +5 -0
  27. package/dist/agents/minimax-vlm.js +10 -8
  28. package/dist/agents/model-auth.js +6 -0
  29. package/dist/agents/model-catalog.js +3 -1
  30. package/dist/agents/model-fallback.js +96 -101
  31. package/dist/agents/model-selection.js +7 -1
  32. package/dist/agents/models-config.providers.js +364 -165
  33. package/dist/agents/ollama-stream.js +117 -4
  34. package/dist/agents/opencode-zen-models.js +22 -11
  35. package/dist/agents/pi-embedded-helpers/errors.js +55 -33
  36. package/dist/agents/pi-embedded-helpers/messaging-dedupe.js +10 -5
  37. package/dist/agents/pi-embedded-helpers/thinking.js +10 -5
  38. package/dist/agents/pi-embedded-helpers.js +1 -1
  39. package/dist/agents/pi-embedded-payloads.js +1 -0
  40. package/dist/agents/pi-embedded-runner/compact.js +29 -7
  41. package/dist/agents/pi-embedded-runner/extensions.js +28 -26
  42. package/dist/agents/pi-embedded-runner/google.js +20 -8
  43. package/dist/agents/pi-embedded-runner/run/attempt.js +95 -36
  44. package/dist/agents/pi-embedded-runner/run.js +71 -12
  45. package/dist/agents/pi-embedded-runner/run.overflow-compaction.fixture.js +34 -0
  46. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +11 -2
  47. package/dist/agents/pi-embedded-runner/session-manager-cache.js +11 -7
  48. package/dist/agents/pi-embedded-runner/system-prompt.js +2 -0
  49. package/dist/agents/pi-embedded-runner/thinking.js +42 -0
  50. package/dist/agents/pi-embedded-runner/tool-name-allowlist.js +19 -0
  51. package/dist/agents/pi-embedded-runner/utils.js +7 -10
  52. package/dist/agents/pi-embedded-subscribe.handlers.lifecycle.js +45 -56
  53. package/dist/agents/pi-embedded-subscribe.handlers.tools.js +2 -2
  54. package/dist/agents/pi-embedded-subscribe.js +9 -4
  55. package/dist/agents/pi-embedded-subscribe.tools.js +68 -14
  56. package/dist/agents/pi-embedded-utils.js +3 -0
  57. package/dist/agents/pi-extensions/compaction-safeguard-runtime.js +4 -20
  58. package/dist/agents/pi-extensions/compaction-safeguard.js +75 -33
  59. package/dist/agents/pi-settings.js +40 -0
  60. package/dist/agents/pi-tools.policy.js +2 -1
  61. package/dist/agents/provider/config-loader.js +1 -1
  62. package/dist/agents/sandbox/browser.js +170 -33
  63. package/dist/agents/sandbox/config-hash.js +14 -27
  64. package/dist/agents/sandbox/config.js +21 -2
  65. package/dist/agents/sandbox/constants.js +2 -0
  66. package/dist/agents/sandbox/docker.js +16 -2
  67. package/dist/agents/sandbox/novnc-auth.js +62 -0
  68. package/dist/agents/sandbox/sanitize-env-vars.js +1 -1
  69. package/dist/agents/sandbox/shared.js +10 -6
  70. package/dist/agents/sandbox-paths.js +24 -11
  71. package/dist/agents/schema/clean-for-gemini.js +132 -85
  72. package/dist/agents/session-slug.js +10 -5
  73. package/dist/agents/session-tool-result-guard-wrapper.js +1 -0
  74. package/dist/agents/session-tool-result-guard.js +3 -1
  75. package/dist/agents/session-transcript-repair.js +40 -6
  76. package/dist/agents/skills/bundled-dir.js +19 -5
  77. package/dist/agents/skills/env-overrides.js +124 -43
  78. package/dist/agents/skills/frontmatter.js +6 -6
  79. package/dist/agents/skills/plugin-skills.js +14 -7
  80. package/dist/agents/skills/workspace.js +1 -0
  81. package/dist/agents/skills.test-helpers.js +13 -0
  82. package/dist/agents/stable-stringify.js +12 -0
  83. package/dist/agents/subagent-announce.js +251 -49
  84. package/dist/agents/subagent-lifecycle-events.js +19 -0
  85. package/dist/agents/subagent-registry-cleanup.js +31 -0
  86. package/dist/agents/subagent-registry-completion.js +68 -0
  87. package/dist/agents/subagent-registry-queries.js +117 -0
  88. package/dist/agents/subagent-registry-state.js +46 -0
  89. package/dist/agents/subagent-registry.js +252 -221
  90. package/dist/agents/subagent-registry.mocks.shared.js +12 -0
  91. package/dist/agents/subagent-registry.store.js +1 -0
  92. package/dist/agents/subagent-registry.types.js +1 -0
  93. package/dist/agents/subagent-spawn.js +195 -7
  94. package/dist/agents/system-prompt.js +22 -6
  95. package/dist/agents/test-helpers/assistant-message-fixtures.js +29 -0
  96. package/dist/agents/test-helpers/fast-coding-tools.js +1 -18
  97. package/dist/agents/test-helpers/fast-core-tools.js +1 -17
  98. package/dist/agents/test-helpers/pi-tools-sandbox-context.js +27 -0
  99. package/dist/agents/timeout.js +18 -6
  100. package/dist/agents/tool-call-id.js +1 -1
  101. package/dist/agents/tool-display-common.js +162 -29
  102. package/dist/agents/tool-images.js +82 -9
  103. package/dist/agents/tool-policy-shared.js +108 -0
  104. package/dist/agents/tool-policy.js +51 -26
  105. package/dist/agents/tools/browser-tool.js +160 -54
  106. package/dist/agents/tools/canvas-tool.js +27 -1
  107. package/dist/agents/tools/common.js +45 -0
  108. package/dist/agents/tools/cron-tool.test-helpers.js +12 -0
  109. package/dist/agents/tools/discord-actions-guild.js +4 -1
  110. package/dist/agents/tools/discord-actions-moderation-shared.js +27 -0
  111. package/dist/agents/tools/gateway-tool.js +3 -1
  112. package/dist/agents/tools/image-tool.js +214 -99
  113. package/dist/agents/tools/nodes-utils.js +1 -10
  114. package/dist/agents/tools/sessions-history-tool.js +140 -108
  115. package/dist/agents/tools/sessions-send-helpers.js +12 -6
  116. package/dist/agents/tools/sessions-spawn-tool.js +8 -2
  117. package/dist/agents/tools/subagents-tool.js +2 -1
  118. package/dist/agents/tools/whatsapp-actions.js +10 -2
  119. package/dist/agents/tools/whatsapp-target-auth.js +18 -0
  120. package/dist/agents/transcript-policy.js +22 -8
  121. package/dist/agents/venice-models.js +11 -3
  122. package/dist/agents/workspace.js +222 -46
  123. package/dist/auto-reply/commands-registry.data.js +51 -0
  124. package/dist/auto-reply/commands-registry.js +19 -21
  125. package/dist/auto-reply/fallback-state.js +114 -0
  126. package/dist/auto-reply/group-activation.js +10 -5
  127. package/dist/auto-reply/inbound-debounce.js +10 -5
  128. package/dist/auto-reply/model-runtime.js +68 -0
  129. package/dist/auto-reply/reply/abort.js +1 -1
  130. package/dist/auto-reply/reply/agent-runner-execution.js +40 -5
  131. package/dist/auto-reply/reply/agent-runner.js +165 -39
  132. package/dist/auto-reply/reply/bash-command.js +41 -39
  133. package/dist/auto-reply/reply/command-gates.js +25 -0
  134. package/dist/auto-reply/reply/commands-allowlist.js +111 -72
  135. package/dist/auto-reply/reply/commands-bash.js +6 -5
  136. package/dist/auto-reply/reply/commands-config.js +30 -28
  137. package/dist/auto-reply/reply/commands-core.js +2 -1
  138. package/dist/auto-reply/reply/commands-info.js +1 -0
  139. package/dist/auto-reply/reply/commands-models.js +65 -14
  140. package/dist/auto-reply/reply/commands-session.js +237 -82
  141. package/dist/auto-reply/reply/commands-setunset-standard.js +13 -0
  142. package/dist/auto-reply/reply/commands-setunset.js +45 -0
  143. package/dist/auto-reply/reply/commands-subagents/action-agents.js +44 -0
  144. package/dist/auto-reply/reply/commands-subagents/action-focus.js +64 -0
  145. package/dist/auto-reply/reply/commands-subagents/action-help.js +4 -0
  146. package/dist/auto-reply/reply/commands-subagents/action-info.js +45 -0
  147. package/dist/auto-reply/reply/commands-subagents/action-kill.js +60 -0
  148. package/dist/auto-reply/reply/commands-subagents/action-list.js +44 -0
  149. package/dist/auto-reply/reply/commands-subagents/action-log.js +29 -0
  150. package/dist/auto-reply/reply/commands-subagents/action-send.js +119 -0
  151. package/dist/auto-reply/reply/commands-subagents/action-spawn.js +52 -0
  152. package/dist/auto-reply/reply/commands-subagents/action-unfocus.js +30 -0
  153. package/dist/auto-reply/reply/commands-subagents/shared.js +303 -0
  154. package/dist/auto-reply/reply/commands-subagents.js +51 -587
  155. package/dist/auto-reply/reply/commands-tts.js +10 -5
  156. package/dist/auto-reply/reply/config-value.js +10 -5
  157. package/dist/auto-reply/reply/directive-handling.model-picker.js +12 -6
  158. package/dist/auto-reply/reply/directive-handling.persist.js +9 -21
  159. package/dist/auto-reply/reply/directive-handling.shared.js +24 -4
  160. package/dist/auto-reply/reply/followup-runner.js +1 -0
  161. package/dist/auto-reply/reply/get-reply-directives-utils.js +23 -14
  162. package/dist/auto-reply/reply/get-reply-directives.js +17 -28
  163. package/dist/auto-reply/reply/get-reply-inline-actions.js +1 -0
  164. package/dist/auto-reply/reply/get-reply.js +71 -12
  165. package/dist/auto-reply/reply/model-selection.js +80 -39
  166. package/dist/auto-reply/reply/queue/enqueue.js +10 -5
  167. package/dist/auto-reply/reply/queue/state.js +13 -12
  168. package/dist/auto-reply/reply/reply-payloads.js +67 -36
  169. package/dist/auto-reply/reply/reply-reference.js +9 -8
  170. package/dist/auto-reply/reply/route-reply.js +15 -8
  171. package/dist/auto-reply/reply/session-reset-prompt.js +1 -1
  172. package/dist/auto-reply/reply/session.js +22 -6
  173. package/dist/auto-reply/reply/strip-inbound-meta.js +147 -0
  174. package/dist/auto-reply/reply/subagents-utils.js +56 -30
  175. package/dist/auto-reply/reply/typing.js +46 -21
  176. package/dist/auto-reply/send-policy.js +14 -7
  177. package/dist/auto-reply/status.js +140 -16
  178. package/dist/auto-reply/templating.js +10 -5
  179. package/dist/auto-reply/thinking.js +7 -16
  180. package/dist/auto-reply/tokens.js +21 -5
  181. package/dist/browser/bridge-server.js +36 -20
  182. package/dist/browser/cdp.helpers.js +7 -14
  183. package/dist/browser/cdp.js +35 -15
  184. package/dist/browser/chrome.profile-decoration.js +7 -4
  185. package/dist/browser/config.js +30 -0
  186. package/dist/browser/extension-relay-auth.js +55 -0
  187. package/dist/browser/extension-relay.js +74 -29
  188. package/dist/browser/navigation-guard.js +39 -0
  189. package/dist/browser/paths.js +77 -0
  190. package/dist/browser/profiles.js +13 -8
  191. package/dist/browser/pw-ai-module.js +10 -5
  192. package/dist/browser/pw-session.js +76 -39
  193. package/dist/browser/pw-tools-core.interactions.js +14 -7
  194. package/dist/browser/pw-tools-core.state.js +12 -6
  195. package/dist/browser/routes/agent.act.js +431 -424
  196. package/dist/browser/routes/agent.shared.js +47 -3
  197. package/dist/browser/routes/agent.snapshot.js +122 -116
  198. package/dist/browser/routes/agent.storage.js +303 -297
  199. package/dist/browser/routes/tabs.js +154 -100
  200. package/dist/browser/server-context.js +7 -0
  201. package/dist/browser/server-lifecycle.js +37 -0
  202. package/dist/build-info.json +3 -3
  203. package/dist/channels/allow-from.js +26 -0
  204. package/dist/channels/allowlists/resolve-utils.js +43 -19
  205. package/dist/channels/channel-config.js +14 -7
  206. package/dist/channels/draft-stream-loop.js +7 -0
  207. package/dist/channels/model-overrides.js +82 -0
  208. package/dist/channels/plugins/account-action-gate.js +13 -0
  209. package/dist/channels/plugins/message-actions.js +10 -0
  210. package/dist/channels/plugins/normalize/imessage.js +14 -7
  211. package/dist/channels/plugins/normalize/slack.js +10 -5
  212. package/dist/channels/plugins/normalize/telegram.js +14 -7
  213. package/dist/channels/plugins/outbound/discord.js +80 -8
  214. package/dist/channels/plugins/outbound/signal.js +11 -11
  215. package/dist/channels/plugins/setup-helpers.js +10 -5
  216. package/dist/channels/sender-label.js +14 -7
  217. package/dist/channels/session.js +4 -2
  218. package/dist/channels/status-reactions.js +297 -0
  219. package/dist/channels/telegram/api.js +18 -0
  220. package/dist/cli/argv.js +84 -21
  221. package/dist/cli/banner.js +3 -2
  222. package/dist/cli/browser-cli-actions-input/register.files-downloads.js +65 -56
  223. package/dist/cli/cli-name.js +11 -11
  224. package/dist/cli/cli-utils.js +13 -3
  225. package/dist/cli/command-format.js +1 -1
  226. package/dist/cli/config-cli.js +1 -1
  227. package/dist/cli/daemon-cli/lifecycle-core.js +31 -19
  228. package/dist/cli/daemon-cli/lifecycle.js +64 -2
  229. package/dist/cli/daemon-cli/restart-health.js +126 -0
  230. package/dist/cli/daemon-cli/status.gather.js +9 -13
  231. package/dist/cli/daemon-cli/status.print.js +2 -10
  232. package/dist/cli/deps.js +27 -22
  233. package/dist/cli/exec-approvals-cli.js +92 -124
  234. package/dist/cli/gateway-cli/run-loop.js +23 -5
  235. package/dist/cli/memory-cli.js +158 -61
  236. package/dist/cli/node-cli/register.js +14 -5
  237. package/dist/cli/nodes-cli/register.push.js +63 -0
  238. package/dist/cli/nodes-media-utils.js +26 -0
  239. package/dist/cli/outbound-send-deps.js +2 -9
  240. package/dist/cli/outbound-send-mapping.js +11 -0
  241. package/dist/cli/pairing-cli.js +40 -14
  242. package/dist/cli/plugins-cli.js +250 -73
  243. package/dist/cli/ports.js +11 -10
  244. package/dist/cli/program/build-program.js +3 -1
  245. package/dist/cli/program/command-registry.js +214 -136
  246. package/dist/cli/program/command-tree.js +16 -0
  247. package/dist/cli/program/help.js +43 -12
  248. package/dist/cli/program/preaction.js +13 -9
  249. package/dist/cli/program/register.configure.js +3 -18
  250. package/dist/cli/program/register.maintenance.js +2 -2
  251. package/dist/cli/program/register.onboard.js +2 -0
  252. package/dist/cli/program/register.status-health-sessions.js +16 -17
  253. package/dist/cli/program/register.subclis.js +93 -52
  254. package/dist/cli/route.js +12 -8
  255. package/dist/cli/system-cli.js +36 -46
  256. package/dist/cli/test-runtime-capture.js +24 -0
  257. package/dist/cli/update-cli/shared.js +22 -9
  258. package/dist/cli/update-cli/update-command.js +89 -14
  259. package/dist/cli/update-cli/wizard.js +6 -12
  260. package/dist/commands/agent/run-context.js +18 -5
  261. package/dist/commands/agent/session-store.js +17 -4
  262. package/dist/commands/agent.js +185 -89
  263. package/dist/commands/agents.bindings.js +14 -7
  264. package/dist/commands/agents.commands.add.js +13 -9
  265. package/dist/commands/agents.commands.identity.js +12 -6
  266. package/dist/commands/agents.commands.list.js +11 -6
  267. package/dist/commands/agents.config.js +8 -10
  268. package/dist/commands/agents.providers.js +12 -6
  269. package/dist/commands/auth-choice-options.js +103 -75
  270. package/dist/commands/auth-choice.apply.byteplus.js +55 -0
  271. package/dist/commands/auth-choice.apply.js +4 -0
  272. package/dist/commands/auth-choice.apply.minimax.js +61 -13
  273. package/dist/commands/auth-choice.apply.openai.js +3 -1
  274. package/dist/commands/auth-choice.apply.volcengine.js +55 -0
  275. package/dist/commands/auth-choice.preferred-provider.js +2 -0
  276. package/dist/commands/channels/remove.js +13 -6
  277. package/dist/commands/channels/shared.js +4 -14
  278. package/dist/commands/channels.mock-harness.js +23 -0
  279. package/dist/commands/configure.commands.js +14 -0
  280. package/dist/commands/configure.gateway.js +2 -4
  281. package/dist/commands/configure.js +1 -1
  282. package/dist/commands/configure.shared.js +11 -0
  283. package/dist/commands/daemon-install-helpers.js +2 -2
  284. package/dist/commands/daemon-install-runtime-warning.js +11 -0
  285. package/dist/commands/dashboard.js +12 -10
  286. package/dist/commands/docs.js +14 -8
  287. package/dist/commands/doctor-config-flow.js +11 -9
  288. package/dist/commands/doctor-legacy-config.js +281 -0
  289. package/dist/commands/doctor-state-integrity.js +99 -23
  290. package/dist/commands/doctor-update.js +12 -9
  291. package/dist/commands/models/list.list-command.js +7 -5
  292. package/dist/commands/models/set-image.js +2 -21
  293. package/dist/commands/node-daemon-install-helpers.js +10 -8
  294. package/dist/commands/onboard-auth.config-minimax.js +54 -80
  295. package/dist/commands/onboard-auth.config-opencode.js +2 -18
  296. package/dist/commands/onboard-auth.credentials.js +90 -13
  297. package/dist/commands/onboard-auth.js +1 -1
  298. package/dist/commands/onboard-auth.models.js +6 -5
  299. package/dist/commands/onboard-hooks.js +1 -1
  300. package/dist/commands/onboard-non-interactive/api-keys.js +14 -7
  301. package/dist/commands/onboard-non-interactive/local/auth-choice.js +64 -49
  302. package/dist/commands/onboard-provider-auth-flags.js +14 -0
  303. package/dist/commands/onboard-remote.js +14 -7
  304. package/dist/commands/onboard.js +11 -13
  305. package/dist/commands/sandbox-display.js +6 -5
  306. package/dist/commands/sessions.test-helpers.js +61 -0
  307. package/dist/commands/status-all/diagnosis.js +14 -10
  308. package/dist/commands/status-all/format.js +1 -0
  309. package/dist/commands/status.gateway-probe.js +1 -16
  310. package/dist/commands/systemd-linger.js +12 -6
  311. package/dist/config/agent-limits.js +2 -0
  312. package/dist/config/commands.js +32 -15
  313. package/dist/config/config-paths.js +9 -11
  314. package/dist/config/config.js +1 -1
  315. package/dist/config/defaults.js +22 -2
  316. package/dist/config/discord-preview-streaming.js +104 -0
  317. package/dist/config/env-substitution.js +62 -34
  318. package/dist/config/env-vars.js +45 -7
  319. package/dist/config/includes.js +4 -0
  320. package/dist/config/io.js +656 -171
  321. package/dist/config/legacy.migrations.part-1.js +189 -78
  322. package/dist/config/legacy.shared.js +3 -1
  323. package/dist/config/merge-patch.js +54 -4
  324. package/dist/config/prototype-keys.js +4 -0
  325. package/dist/config/redact-snapshot.js +404 -76
  326. package/dist/config/schema.help.js +44 -7
  327. package/dist/config/schema.js +58 -570
  328. package/dist/config/schema.labels.js +38 -6
  329. package/dist/config/sessions/delivery-info.js +10 -3
  330. package/dist/config/sessions/main-session.js +10 -5
  331. package/dist/config/sessions/session-file.js +33 -0
  332. package/dist/config/sessions/session-key.js +10 -5
  333. package/dist/config/sessions/store.js +1 -1
  334. package/dist/config/sessions.js +1 -0
  335. package/dist/config/validation.js +140 -85
  336. package/dist/config/zod-schema.agent-runtime.js +11 -0
  337. package/dist/config/zod-schema.hooks.js +40 -11
  338. package/dist/config/zod-schema.installs.js +20 -0
  339. package/dist/config/zod-schema.js +156 -20
  340. package/dist/config/zod-schema.providers-core.js +78 -4
  341. package/dist/config/zod-schema.providers.js +6 -1
  342. package/dist/config/zod-schema.session.js +41 -2
  343. package/dist/cron/run-log.js +3 -0
  344. package/dist/cron/schedule.js +21 -10
  345. package/dist/cron/service/ops.js +35 -21
  346. package/dist/cron/service/timer.js +116 -16
  347. package/dist/cron/stagger.js +3 -1
  348. package/dist/daemon/cmd-argv.js +21 -0
  349. package/dist/daemon/cmd-set.js +58 -0
  350. package/dist/daemon/service-types.js +1 -0
  351. package/dist/discord/api.js +12 -6
  352. package/dist/discord/draft-chunking.js +22 -0
  353. package/dist/discord/draft-stream.js +124 -0
  354. package/dist/discord/monitor/agent-components.js +1 -1
  355. package/dist/discord/monitor/commands.js +5 -0
  356. package/dist/discord/monitor/exec-approvals.js +357 -162
  357. package/dist/discord/monitor/gateway-plugin.js +2 -1
  358. package/dist/discord/monitor/listeners.js +37 -27
  359. package/dist/discord/monitor/message-handler.js +4 -1
  360. package/dist/discord/monitor/message-handler.preflight.js +65 -8
  361. package/dist/discord/monitor/message-handler.process.js +246 -217
  362. package/dist/discord/monitor/message-utils.js +143 -6
  363. package/dist/discord/monitor/model-picker-preferences.js +143 -0
  364. package/dist/discord/monitor/model-picker.js +651 -0
  365. package/dist/discord/monitor/native-command.js +573 -16
  366. package/dist/discord/monitor/provider.allowlist.js +223 -0
  367. package/dist/discord/monitor/provider.js +275 -347
  368. package/dist/discord/monitor/provider.lifecycle.js +100 -0
  369. package/dist/discord/monitor/reply-delivery.js +123 -16
  370. package/dist/discord/monitor/thread-bindings.discord-api.js +215 -0
  371. package/dist/discord/monitor/thread-bindings.js +4 -0
  372. package/dist/discord/monitor/thread-bindings.lifecycle.js +177 -0
  373. package/dist/discord/monitor/thread-bindings.manager.js +423 -0
  374. package/dist/discord/monitor/thread-bindings.messages.js +55 -0
  375. package/dist/discord/monitor/thread-bindings.state.js +358 -0
  376. package/dist/discord/monitor/thread-bindings.types.js +6 -0
  377. package/dist/discord/resolve-users.js +33 -21
  378. package/dist/discord/send.channels.js +15 -0
  379. package/dist/discord/send.js +3 -2
  380. package/dist/discord/send.outbound.js +82 -26
  381. package/dist/discord/send.permissions.js +83 -30
  382. package/dist/discord/send.reactions.js +8 -4
  383. package/dist/discord/token.js +10 -5
  384. package/dist/discord/voice/command.js +263 -0
  385. package/dist/discord/voice/manager.js +531 -0
  386. package/dist/gateway/auth.js +72 -13
  387. package/dist/gateway/call.js +152 -83
  388. package/dist/gateway/canvas-capability.js +75 -0
  389. package/dist/gateway/client.js +28 -4
  390. package/dist/gateway/config-reload.js +3 -4
  391. package/dist/gateway/control-plane-audit.js +28 -0
  392. package/dist/gateway/control-plane-rate-limit.js +53 -0
  393. package/dist/gateway/control-ui.js +219 -96
  394. package/dist/gateway/events.js +1 -0
  395. package/dist/gateway/hooks-mapping.js +88 -38
  396. package/dist/gateway/hooks.js +109 -54
  397. package/dist/gateway/http-auth-helpers.js +3 -2
  398. package/dist/gateway/http-common.js +22 -0
  399. package/dist/gateway/http-endpoint-helpers.js +1 -0
  400. package/dist/gateway/method-scopes.js +169 -0
  401. package/dist/gateway/net.js +74 -9
  402. package/dist/gateway/node-invoke-system-run-approval.js +14 -35
  403. package/dist/gateway/node-registry.js +10 -5
  404. package/dist/gateway/openai-http.js +1 -0
  405. package/dist/gateway/openresponses-http.js +121 -110
  406. package/dist/gateway/origin-check.js +1 -18
  407. package/dist/gateway/probe-auth.js +2 -0
  408. package/dist/gateway/protocol/index.js +4 -2
  409. package/dist/gateway/protocol/schema/cron.js +1 -0
  410. package/dist/gateway/protocol/schema/devices.js +1 -0
  411. package/dist/gateway/protocol/schema/protocol-schemas.js +4 -1
  412. package/dist/gateway/protocol/schema/push.js +18 -0
  413. package/dist/gateway/protocol/schema/sessions.js +6 -0
  414. package/dist/gateway/protocol/schema.js +1 -0
  415. package/dist/gateway/role-policy.js +17 -0
  416. package/dist/gateway/server/ws-connection/connect-policy.js +37 -0
  417. package/dist/gateway/server/ws-connection/message-handler.js +175 -148
  418. package/dist/gateway/server-chat.js +83 -25
  419. package/dist/gateway/server-constants.js +10 -9
  420. package/dist/gateway/server-cron.js +1 -0
  421. package/dist/gateway/server-http.js +247 -54
  422. package/dist/gateway/server-maintenance.js +20 -5
  423. package/dist/gateway/server-methods/agent.js +162 -24
  424. package/dist/gateway/server-methods/chat.js +465 -130
  425. package/dist/gateway/server-methods/config.js +193 -152
  426. package/dist/gateway/server-methods/devices.js +17 -3
  427. package/dist/gateway/server-methods/models.js +11 -1
  428. package/dist/gateway/server-methods/nodes.helpers.js +12 -0
  429. package/dist/gateway/server-methods/nodes.js +251 -69
  430. package/dist/gateway/server-methods/push.js +53 -0
  431. package/dist/gateway/server-methods/sessions.js +64 -8
  432. package/dist/gateway/server-methods/usage.js +162 -75
  433. package/dist/gateway/server-node-events.js +29 -0
  434. package/dist/gateway/server-reload-handlers.js +2 -3
  435. package/dist/gateway/server-runtime-config.js +39 -13
  436. package/dist/gateway/server-runtime-state.js +2 -0
  437. package/dist/gateway/server-startup-memory.js +17 -11
  438. package/dist/gateway/server-ws-runtime.js +1 -0
  439. package/dist/gateway/server.impl.js +296 -139
  440. package/dist/gateway/session-preview.test-helpers.js +11 -0
  441. package/dist/gateway/session-utils.fs.js +32 -34
  442. package/dist/gateway/sessions-resolve.js +17 -5
  443. package/dist/gateway/startup-auth.js +126 -0
  444. package/dist/gateway/test-helpers.agent-results.js +15 -0
  445. package/dist/gateway/test-helpers.mocks.js +37 -14
  446. package/dist/gateway/test-helpers.openai-mock.js +14 -7
  447. package/dist/gateway/test-helpers.server.js +161 -77
  448. package/dist/gateway/tools-invoke-http.js +21 -10
  449. package/dist/hooks/bundled/bootstrap-extra-files/handler.js +3 -1
  450. package/dist/hooks/bundled/command-logger/handler.js +7 -2
  451. package/dist/hooks/bundled/session-memory/handler.js +170 -38
  452. package/dist/hooks/frontmatter.js +6 -6
  453. package/dist/hooks/gmail-watcher-lifecycle.js +23 -0
  454. package/dist/hooks/gmail-watcher.js +11 -6
  455. package/dist/hooks/internal-hooks.js +11 -1
  456. package/dist/hooks/llm-slug-generator.js +4 -1
  457. package/dist/hooks/workspace.js +47 -17
  458. package/dist/imessage/accounts.js +9 -20
  459. package/dist/imessage/monitor/inbound-processing.js +2 -1
  460. package/dist/infra/archive-path.js +49 -0
  461. package/dist/infra/archive.js +174 -73
  462. package/dist/infra/control-ui-assets.js +14 -6
  463. package/dist/infra/device-pairing.js +204 -144
  464. package/dist/infra/env.js +10 -5
  465. package/dist/infra/exec-approvals-allowlist.js +141 -70
  466. package/dist/infra/exec-approvals-analysis.js +78 -20
  467. package/dist/infra/exec-approvals.js +5 -17
  468. package/dist/infra/exec-safe-bin-policy.js +277 -0
  469. package/dist/infra/fixed-window-rate-limit.js +33 -0
  470. package/dist/infra/fs-safe.js +71 -39
  471. package/dist/infra/gateway-lock.js +6 -2
  472. package/dist/infra/git-root.js +61 -0
  473. package/dist/infra/heartbeat-active-hours.js +2 -2
  474. package/dist/infra/heartbeat-reason.js +40 -0
  475. package/dist/infra/heartbeat-runner.js +72 -32
  476. package/dist/infra/heartbeat-wake.js +6 -12
  477. package/dist/infra/host-env-security-policy.json +19 -0
  478. package/dist/infra/host-env-security.js +66 -0
  479. package/dist/infra/install-source-utils.js +91 -7
  480. package/dist/infra/net/ssrf.js +131 -38
  481. package/dist/infra/node-pairing.js +50 -105
  482. package/dist/infra/npm-integrity.js +45 -0
  483. package/dist/infra/npm-pack-install.js +40 -0
  484. package/dist/infra/outbound/bound-delivery-router.js +88 -0
  485. package/dist/infra/outbound/channel-adapters.js +20 -7
  486. package/dist/infra/outbound/channel-selection.js +12 -6
  487. package/dist/infra/outbound/envelope.js +1 -1
  488. package/dist/infra/outbound/format.js +12 -6
  489. package/dist/infra/outbound/message-action-runner.js +107 -327
  490. package/dist/infra/outbound/message.js +59 -36
  491. package/dist/infra/outbound/outbound-policy.js +52 -25
  492. package/dist/infra/outbound/outbound-send-service.js +58 -71
  493. package/dist/infra/outbound/payloads.js +14 -7
  494. package/dist/infra/outbound/session-binding-service.js +123 -0
  495. package/dist/infra/pairing-files.js +10 -0
  496. package/dist/infra/path-guards.js +25 -0
  497. package/dist/infra/plain-object.js +9 -0
  498. package/dist/infra/provider-usage.fetch.codex.js +7 -15
  499. package/dist/infra/provider-usage.fetch.gemini.js +14 -11
  500. package/dist/infra/provider-usage.fetch.shared.js +30 -1
  501. package/dist/infra/provider-usage.fetch.zai.js +10 -9
  502. package/dist/infra/push-apns.js +365 -0
  503. package/dist/infra/restart-sentinel.js +16 -1
  504. package/dist/infra/restart.js +229 -26
  505. package/dist/infra/retry-policy.js +4 -2
  506. package/dist/infra/retry.js +9 -5
  507. package/dist/infra/scp-host.js +54 -0
  508. package/dist/infra/session-cost-usage.js +107 -59
  509. package/dist/infra/session-maintenance-warning.js +3 -1
  510. package/dist/infra/shell-env.js +98 -34
  511. package/dist/infra/ssh-config.js +12 -6
  512. package/dist/infra/system-run-command.js +49 -4
  513. package/dist/infra/update-channels.js +10 -5
  514. package/dist/infra/update-startup.js +86 -9
  515. package/dist/line/accounts.js +5 -7
  516. package/dist/line/bot-access.js +8 -20
  517. package/dist/line/bot-handlers.js +3 -1
  518. package/dist/link-understanding/detect.js +15 -7
  519. package/dist/media/constants.js +15 -6
  520. package/dist/media/image-ops.js +7 -0
  521. package/dist/media/inbound-path-policy.js +114 -0
  522. package/dist/media/input-files.js +16 -0
  523. package/dist/media/local-roots.js +3 -2
  524. package/dist/media-understanding/apply.js +4 -1
  525. package/dist/media-understanding/concurrency.js +8 -20
  526. package/dist/memory/backend-config.js +45 -6
  527. package/dist/memory/embeddings.js +10 -4
  528. package/dist/memory/fs-utils.js +23 -0
  529. package/dist/memory/manager-search.js +12 -6
  530. package/dist/memory/manager-sync-ops.js +12 -2
  531. package/dist/memory/qmd-manager.js +466 -53
  532. package/dist/memory/query-expansion.js +167 -3
  533. package/dist/memory/status-format.js +10 -5
  534. package/dist/memory/sync-memory-files.js +1 -1
  535. package/dist/memory/test-manager.js +8 -0
  536. package/dist/node-host/invoke-system-run.js +281 -0
  537. package/dist/node-host/invoke.js +55 -337
  538. package/dist/pairing/pairing-store.js +22 -0
  539. package/dist/plugin-sdk/allow-from.js +1 -1
  540. package/dist/plugin-sdk/command-auth.js +3 -1
  541. package/dist/plugin-sdk/index.js +6 -3
  542. package/dist/plugin-sdk/temp-path.js +47 -0
  543. package/dist/plugin-sdk/webhook-targets.js +32 -0
  544. package/dist/plugins/bundled-dir.js +9 -6
  545. package/dist/plugins/discovery.js +217 -23
  546. package/dist/plugins/hook-runner-global.js +16 -0
  547. package/dist/plugins/hooks.js +50 -0
  548. package/dist/plugins/install.js +28 -16
  549. package/dist/plugins/loader.js +192 -26
  550. package/dist/plugins/logger.js +8 -0
  551. package/dist/plugins/manifest-registry.js +3 -0
  552. package/dist/plugins/path-safety.js +34 -0
  553. package/dist/plugins/registry.js +5 -2
  554. package/dist/plugins/runtime/index.js +271 -206
  555. package/dist/plugins/runtime.js +3 -17
  556. package/dist/plugins/update.js +78 -12
  557. package/dist/process/spawn-utils.js +14 -7
  558. package/dist/providers/github-copilot-models.js +4 -1
  559. package/dist/providers/github-copilot-token.js +11 -6
  560. package/dist/providers/qwen-portal-oauth.js +14 -6
  561. package/dist/routing/account-id.js +30 -0
  562. package/dist/routing/resolve-route.js +3 -7
  563. package/dist/routing/session-key.js +2 -16
  564. package/dist/security/audit-channel.js +100 -20
  565. package/dist/security/audit-extra.async.js +505 -179
  566. package/dist/security/audit-extra.js +12 -2
  567. package/dist/security/audit-extra.sync.js +421 -35
  568. package/dist/security/audit-fs.js +31 -13
  569. package/dist/security/audit.js +180 -370
  570. package/dist/security/dm-policy-shared.js +68 -0
  571. package/dist/security/external-content.js +46 -14
  572. package/dist/security/fix.js +49 -85
  573. package/dist/security/scan-paths.js +20 -0
  574. package/dist/security/secret-equal.js +3 -7
  575. package/dist/security/windows-acl.js +30 -15
  576. package/dist/shared/entry-status.js +6 -0
  577. package/dist/shared/frontmatter.js +5 -5
  578. package/dist/shared/node-list-parse.js +13 -0
  579. package/dist/shared/node-match.js +11 -4
  580. package/dist/shared/operator-scope-compat.js +42 -0
  581. package/dist/shared/text-chunking.js +29 -0
  582. package/dist/signal/accounts.js +7 -20
  583. package/dist/signal/monitor/event-handler.js +3 -1
  584. package/dist/slack/accounts.js +6 -19
  585. package/dist/slack/actions.js +11 -3
  586. package/dist/slack/blocks.test-helpers.js +31 -0
  587. package/dist/slack/monitor/auth.js +1 -1
  588. package/dist/slack/monitor/message-handler/dispatch.js +50 -29
  589. package/dist/slack/monitor/mrkdwn.js +8 -0
  590. package/dist/slack/monitor/replies.js +15 -7
  591. package/dist/slack/monitor/slash.js +22 -13
  592. package/dist/slack/resolve-channels.js +10 -5
  593. package/dist/slack/send.js +102 -12
  594. package/dist/slack/stream-mode.js +10 -0
  595. package/dist/slack/streaming.js +4 -2
  596. package/dist/telegram/accounts.js +19 -14
  597. package/dist/telegram/bot/helpers.js +3 -5
  598. package/dist/telegram/bot-access.js +35 -36
  599. package/dist/telegram/bot-handlers.js +120 -148
  600. package/dist/telegram/bot-message-context.js +68 -9
  601. package/dist/telegram/bot-message-dispatch.js +477 -210
  602. package/dist/telegram/bot-native-commands.js +16 -0
  603. package/dist/telegram/draft-stream.js +44 -8
  604. package/dist/telegram/inline-buttons.js +5 -15
  605. package/dist/telegram/monitor.js +11 -7
  606. package/dist/telegram/network-config.js +19 -7
  607. package/dist/telegram/reasoning-lane-coordinator.js +128 -0
  608. package/dist/telegram/send.js +3 -2
  609. package/dist/telegram/sent-message-cache.js +5 -6
  610. package/dist/telegram/status-reaction-variants.js +208 -0
  611. package/dist/telegram/sticker-cache.js +11 -9
  612. package/dist/terminal/prompt-select-styled.js +9 -0
  613. package/dist/terminal/theme.js +12 -12
  614. package/dist/test-utils/command-runner.js +6 -0
  615. package/dist/test-utils/internal-hook-event-payload.js +10 -0
  616. package/dist/test-utils/model-auth-mock.js +12 -0
  617. package/dist/test-utils/provider-usage-fetch.js +14 -0
  618. package/dist/test-utils/temp-home.js +33 -0
  619. package/dist/tts/tts.js +80 -567
  620. package/dist/tui/components/chat-log.js +50 -8
  621. package/dist/tui/theme/theme.js +10 -12
  622. package/dist/tui/tui-command-handlers.js +36 -27
  623. package/dist/tui/tui-event-handlers.js +122 -32
  624. package/dist/tui/tui-local-shell.js +16 -6
  625. package/dist/tui/tui.js +236 -48
  626. package/dist/utils/account-id.js +2 -4
  627. package/dist/utils/boolean.js +10 -5
  628. package/dist/utils/directive-tags.js +11 -0
  629. package/dist/utils/mask-api-key.js +10 -0
  630. package/dist/utils/queue-helpers.js +67 -12
  631. package/dist/utils/run-with-concurrency.js +39 -0
  632. package/dist/web/auto-reply/deliver-reply.js +8 -4
  633. package/dist/web/auto-reply/mentions.js +10 -5
  634. package/dist/web/auto-reply/monitor/group-members.js +14 -7
  635. package/dist/web/auto-reply/monitor/process-message.js +45 -24
  636. package/dist/web/inbound/access-control.js +5 -2
  637. package/dist/web/login-qr.js +12 -6
  638. package/dist/web/media.js +126 -15
  639. package/docs/tools/slash-commands.md +5 -1
  640. package/extensions/bluebubbles/src/monitor-processing.ts +580 -139
  641. package/extensions/bluebubbles/src/monitor.ts +208 -1950
  642. package/extensions/feishu/src/external-keys.ts +19 -0
  643. package/extensions/lobster/src/windows-spawn.ts +193 -0
  644. package/extensions/matrix/src/matrix/actions/limits.ts +6 -0
  645. package/extensions/mattermost/src/mattermost/reactions.test-helpers.ts +83 -0
  646. package/package.json +1 -1
@@ -5,7 +5,11 @@ import { defaultRuntime } from "../runtime.js";
5
5
  import { normalizeDeliveryContext } from "../utils/delivery-context.js";
6
6
  import { resetAnnounceQueuesForTests } from "./subagent-announce-queue.js";
7
7
  import { runSubagentAnnounceFlow } from "./subagent-announce.js";
8
- import { loadSubagentRegistryFromDisk, saveSubagentRegistryToDisk, } from "./subagent-registry.store.js";
8
+ import { SUBAGENT_ENDED_OUTCOME_KILLED, SUBAGENT_ENDED_REASON_COMPLETE, SUBAGENT_ENDED_REASON_ERROR, SUBAGENT_ENDED_REASON_KILLED, } from "./subagent-lifecycle-events.js";
9
+ import { resolveCleanupCompletionReason, resolveDeferredCleanupDecision, } from "./subagent-registry-cleanup.js";
10
+ import { emitSubagentEndedHookOnce, resolveLifecycleOutcomeFromRunOutcome, runOutcomesEqual, } from "./subagent-registry-completion.js";
11
+ import { countActiveDescendantRunsFromRuns, countActiveRunsForSessionFromRuns, findRunIdsByChildSessionKeyFromRuns, listDescendantRunsForRequesterFromRuns, listRunsForRequesterFromRuns, resolveRequesterForChildSessionFromRuns, } from "./subagent-registry-queries.js";
12
+ import { getSubagentRunsSnapshotForRead, persistSubagentRunsToDisk, restoreSubagentRunsFromDisk, } from "./subagent-registry-state.js";
9
13
  import { resolveAgentTimeoutMs } from "./timeout.js";
10
14
  const subagentRuns = new Map();
11
15
  let sweeper = null;
@@ -41,17 +45,85 @@ function logAnnounceGiveUp(entry, reason) {
41
45
  defaultRuntime.log(`[warn] Subagent announce give up (${reason}) run=${entry.runId} child=${entry.childSessionKey} requester=${entry.requesterSessionKey} retries=${retryCount} endedAgo=${endedAgoLabel}`);
42
46
  }
43
47
  function persistSubagentRuns() {
44
- try {
45
- saveSubagentRegistryToDisk(subagentRuns);
46
- }
47
- catch {
48
- // ignore persistence failures
49
- }
48
+ persistSubagentRunsToDisk(subagentRuns);
50
49
  }
51
50
  const resumedRuns = new Set();
51
+ const endedHookInFlightRunIds = new Set();
52
52
  function suppressAnnounceForSteerRestart(entry) {
53
53
  return entry?.suppressAnnounceReason === "steer-restart";
54
54
  }
55
+ function shouldKeepThreadBindingAfterRun(params) {
56
+ if (params.reason === SUBAGENT_ENDED_REASON_KILLED) {
57
+ return false;
58
+ }
59
+ return params.entry.spawnMode === "session";
60
+ }
61
+ function shouldEmitEndedHookForRun(params) {
62
+ return !shouldKeepThreadBindingAfterRun(params);
63
+ }
64
+ async function emitSubagentEndedHookForRun(params) {
65
+ const reason = params.reason ?? params.entry.endedReason ?? SUBAGENT_ENDED_REASON_COMPLETE;
66
+ const outcome = resolveLifecycleOutcomeFromRunOutcome(params.entry.outcome);
67
+ const error = params.entry.outcome?.status === "error" ? params.entry.outcome.error : undefined;
68
+ await emitSubagentEndedHookOnce({
69
+ entry: params.entry,
70
+ reason,
71
+ sendFarewell: params.sendFarewell,
72
+ accountId: params.accountId ?? params.entry.requesterOrigin?.accountId,
73
+ outcome,
74
+ error,
75
+ inFlightRunIds: endedHookInFlightRunIds,
76
+ persist: persistSubagentRuns,
77
+ });
78
+ }
79
+ async function completeSubagentRun(params) {
80
+ const entry = subagentRuns.get(params.runId);
81
+ if (!entry) {
82
+ return;
83
+ }
84
+ let mutated = false;
85
+ const endedAt = typeof params.endedAt === "number" ? params.endedAt : Date.now();
86
+ if (entry.endedAt !== endedAt) {
87
+ entry.endedAt = endedAt;
88
+ mutated = true;
89
+ }
90
+ if (!runOutcomesEqual(entry.outcome, params.outcome)) {
91
+ entry.outcome = params.outcome;
92
+ mutated = true;
93
+ }
94
+ if (entry.endedReason !== params.reason) {
95
+ entry.endedReason = params.reason;
96
+ mutated = true;
97
+ }
98
+ if (mutated) {
99
+ persistSubagentRuns();
100
+ }
101
+ const suppressedForSteerRestart = suppressAnnounceForSteerRestart(entry);
102
+ const shouldEmitEndedHook = !suppressedForSteerRestart &&
103
+ shouldEmitEndedHookForRun({
104
+ entry,
105
+ reason: params.reason,
106
+ });
107
+ const shouldDeferEndedHook = shouldEmitEndedHook &&
108
+ params.triggerCleanup &&
109
+ entry.expectsCompletionMessage === true &&
110
+ !suppressedForSteerRestart;
111
+ if (!shouldDeferEndedHook && shouldEmitEndedHook) {
112
+ await emitSubagentEndedHookForRun({
113
+ entry,
114
+ reason: params.reason,
115
+ sendFarewell: params.sendFarewell,
116
+ accountId: params.accountId,
117
+ });
118
+ }
119
+ if (!params.triggerCleanup) {
120
+ return;
121
+ }
122
+ if (suppressedForSteerRestart) {
123
+ return;
124
+ }
125
+ startSubagentAnnounceCleanupFlow(params.runId, entry);
126
+ }
55
127
  function startSubagentAnnounceCleanupFlow(runId, entry) {
56
128
  if (!beginSubagentCleanup(runId)) {
57
129
  return false;
@@ -64,7 +136,6 @@ function startSubagentAnnounceCleanupFlow(runId, entry) {
64
136
  requesterOrigin,
65
137
  requesterDisplayKey: entry.requesterDisplayKey,
66
138
  task: entry.task,
67
- expectsCompletionMessage: entry.expectsCompletionMessage,
68
139
  timeoutMs: SUBAGENT_ANNOUNCE_TIMEOUT_MS,
69
140
  cleanup: entry.cleanup,
70
141
  waitForCompletion: false,
@@ -72,8 +143,10 @@ function startSubagentAnnounceCleanupFlow(runId, entry) {
72
143
  endedAt: entry.endedAt,
73
144
  label: entry.label,
74
145
  outcome: entry.outcome,
146
+ spawnMode: entry.spawnMode,
147
+ expectsCompletionMessage: entry.expectsCompletionMessage,
75
148
  }).then((didAnnounce) => {
76
- finalizeSubagentCleanup(runId, entry.cleanup, didAnnounce);
149
+ void finalizeSubagentCleanup(runId, entry.cleanup, didAnnounce);
77
150
  });
78
151
  return true;
79
152
  }
@@ -137,19 +210,13 @@ function restoreSubagentRunsOnce() {
137
210
  }
138
211
  restoreAttempted = true;
139
212
  try {
140
- const restored = loadSubagentRegistryFromDisk();
141
- if (restored.size === 0) {
213
+ const restoredCount = restoreSubagentRunsFromDisk({
214
+ runs: subagentRuns,
215
+ mergeOnly: true,
216
+ });
217
+ if (restoredCount === 0) {
142
218
  return;
143
219
  }
144
- for (const [runId, entry] of restored.entries()) {
145
- if (!runId || !entry) {
146
- continue;
147
- }
148
- // Keep any newer in-memory entries.
149
- if (!subagentRuns.has(runId)) {
150
- subagentRuns.set(runId, entry);
151
- }
152
- }
153
220
  // Resume pending work.
154
221
  ensureListener();
155
222
  if ([...subagentRuns.values()].some((entry) => entry.archiveAtMs)) {
@@ -202,7 +269,11 @@ async function sweepSubagentRuns() {
202
269
  try {
203
270
  await callGateway({
204
271
  method: "sessions.delete",
205
- params: { key: entry.childSessionKey, deleteTranscript: true },
272
+ params: {
273
+ key: entry.childSessionKey,
274
+ deleteTranscript: true,
275
+ emitLifecycleHooks: false,
276
+ },
206
277
  timeoutMs: 10_000,
207
278
  });
208
279
  }
@@ -223,87 +294,131 @@ function ensureListener() {
223
294
  }
224
295
  listenerStarted = true;
225
296
  listenerStop = onAgentEvent((evt) => {
226
- if (!evt || evt.stream !== "lifecycle") {
227
- return;
228
- }
229
- const entry = subagentRuns.get(evt.runId);
230
- if (!entry) {
231
- return;
232
- }
233
- const phase = evt.data?.phase;
234
- if (phase === "start") {
235
- const startedAt = typeof evt.data?.startedAt === "number" ? evt.data.startedAt : undefined;
236
- if (startedAt) {
237
- entry.startedAt = startedAt;
238
- persistSubagentRuns();
297
+ void (async () => {
298
+ if (!evt || evt.stream !== "lifecycle") {
299
+ return;
239
300
  }
240
- return;
241
- }
242
- if (phase !== "end" && phase !== "error") {
243
- return;
244
- }
245
- const endedAt = typeof evt.data?.endedAt === "number" ? evt.data.endedAt : Date.now();
246
- entry.endedAt = endedAt;
247
- if (phase === "error") {
301
+ const entry = subagentRuns.get(evt.runId);
302
+ if (!entry) {
303
+ return;
304
+ }
305
+ const phase = evt.data?.phase;
306
+ if (phase === "start") {
307
+ const startedAt = typeof evt.data?.startedAt === "number" ? evt.data.startedAt : undefined;
308
+ if (startedAt) {
309
+ entry.startedAt = startedAt;
310
+ persistSubagentRuns();
311
+ }
312
+ return;
313
+ }
314
+ if (phase !== "end" && phase !== "error") {
315
+ return;
316
+ }
317
+ const endedAt = typeof evt.data?.endedAt === "number" ? evt.data.endedAt : Date.now();
248
318
  const error = typeof evt.data?.error === "string" ? evt.data.error : undefined;
249
- entry.outcome = { status: "error", error };
250
- }
251
- else if (evt.data?.aborted) {
252
- entry.outcome = { status: "timeout" };
253
- }
254
- else {
255
- entry.outcome = { status: "ok" };
256
- }
257
- persistSubagentRuns();
258
- if (suppressAnnounceForSteerRestart(entry)) {
259
- return;
260
- }
261
- if (!startSubagentAnnounceCleanupFlow(evt.runId, entry)) {
262
- return;
263
- }
319
+ const outcome = phase === "error"
320
+ ? { status: "error", error }
321
+ : evt.data?.aborted
322
+ ? { status: "timeout" }
323
+ : { status: "ok" };
324
+ await completeSubagentRun({
325
+ runId: evt.runId,
326
+ endedAt,
327
+ outcome,
328
+ reason: phase === "error" ? SUBAGENT_ENDED_REASON_ERROR : SUBAGENT_ENDED_REASON_COMPLETE,
329
+ sendFarewell: true,
330
+ accountId: entry.requesterOrigin?.accountId,
331
+ triggerCleanup: true,
332
+ });
333
+ })();
264
334
  });
265
335
  }
266
- function finalizeSubagentCleanup(runId, cleanup, didAnnounce) {
336
+ async function finalizeSubagentCleanup(runId, cleanup, didAnnounce) {
267
337
  const entry = subagentRuns.get(runId);
268
338
  if (!entry) {
269
339
  return;
270
340
  }
271
- if (!didAnnounce) {
272
- const now = Date.now();
273
- const retryCount = (entry.announceRetryCount ?? 0) + 1;
274
- entry.announceRetryCount = retryCount;
341
+ if (didAnnounce) {
342
+ const completionReason = resolveCleanupCompletionReason(entry);
343
+ await emitCompletionEndedHookIfNeeded(entry, completionReason);
344
+ completeCleanupBookkeeping({
345
+ runId,
346
+ entry,
347
+ cleanup,
348
+ completedAt: Date.now(),
349
+ });
350
+ return;
351
+ }
352
+ const now = Date.now();
353
+ const deferredDecision = resolveDeferredCleanupDecision({
354
+ entry,
355
+ now,
356
+ activeDescendantRuns: Math.max(0, countActiveDescendantRuns(entry.childSessionKey)),
357
+ announceExpiryMs: ANNOUNCE_EXPIRY_MS,
358
+ maxAnnounceRetryCount: MAX_ANNOUNCE_RETRY_COUNT,
359
+ deferDescendantDelayMs: MIN_ANNOUNCE_RETRY_DELAY_MS,
360
+ resolveAnnounceRetryDelayMs,
361
+ });
362
+ if (deferredDecision.kind === "defer-descendants") {
275
363
  entry.lastAnnounceRetryAt = now;
276
- // Check if the announce has exceeded retry limits or expired (#18264).
277
- const endedAgo = typeof entry.endedAt === "number" ? now - entry.endedAt : 0;
278
- if (retryCount >= MAX_ANNOUNCE_RETRY_COUNT || endedAgo > ANNOUNCE_EXPIRY_MS) {
279
- // Give up: mark as completed to break the infinite retry loop.
280
- logAnnounceGiveUp(entry, retryCount >= MAX_ANNOUNCE_RETRY_COUNT ? "retry-limit" : "expiry");
281
- entry.cleanupCompletedAt = now;
282
- persistSubagentRuns();
283
- retryDeferredCompletedAnnounces(runId);
284
- return;
285
- }
286
- // Allow retry on the next wake if announce was deferred or failed.
287
364
  entry.cleanupHandled = false;
288
365
  resumedRuns.delete(runId);
289
366
  persistSubagentRuns();
290
- if (entry.expectsCompletionMessage !== true) {
291
- return;
292
- }
293
367
  setTimeout(() => {
294
368
  resumeSubagentRun(runId);
295
- }, resolveAnnounceRetryDelayMs(entry.announceRetryCount ?? 0)).unref?.();
369
+ }, deferredDecision.delayMs).unref?.();
296
370
  return;
297
371
  }
298
- if (cleanup === "delete") {
299
- subagentRuns.delete(runId);
372
+ if (deferredDecision.retryCount != null) {
373
+ entry.announceRetryCount = deferredDecision.retryCount;
374
+ entry.lastAnnounceRetryAt = now;
375
+ }
376
+ if (deferredDecision.kind === "give-up") {
377
+ const completionReason = resolveCleanupCompletionReason(entry);
378
+ await emitCompletionEndedHookIfNeeded(entry, completionReason);
379
+ logAnnounceGiveUp(entry, deferredDecision.reason);
380
+ completeCleanupBookkeeping({
381
+ runId,
382
+ entry,
383
+ cleanup: "keep",
384
+ completedAt: now,
385
+ });
386
+ return;
387
+ }
388
+ // Allow retry on the next wake if announce was deferred or failed.
389
+ entry.cleanupHandled = false;
390
+ resumedRuns.delete(runId);
391
+ persistSubagentRuns();
392
+ if (deferredDecision.resumeDelayMs == null) {
393
+ return;
394
+ }
395
+ setTimeout(() => {
396
+ resumeSubagentRun(runId);
397
+ }, deferredDecision.resumeDelayMs).unref?.();
398
+ }
399
+ async function emitCompletionEndedHookIfNeeded(entry, reason) {
400
+ if (entry.expectsCompletionMessage === true &&
401
+ shouldEmitEndedHookForRun({
402
+ entry,
403
+ reason,
404
+ })) {
405
+ await emitSubagentEndedHookForRun({
406
+ entry,
407
+ reason,
408
+ sendFarewell: true,
409
+ });
410
+ }
411
+ }
412
+ function completeCleanupBookkeeping(params) {
413
+ if (params.cleanup === "delete") {
414
+ subagentRuns.delete(params.runId);
300
415
  persistSubagentRuns();
301
- retryDeferredCompletedAnnounces(runId);
416
+ retryDeferredCompletedAnnounces(params.runId);
302
417
  return;
303
418
  }
304
- entry.cleanupCompletedAt = Date.now();
419
+ params.entry.cleanupCompletedAt = params.completedAt;
305
420
  persistSubagentRuns();
306
- retryDeferredCompletedAnnounces(runId);
421
+ retryDeferredCompletedAnnounces(params.runId);
307
422
  }
308
423
  function retryDeferredCompletedAnnounces(excludeRunId) {
309
424
  const now = Date.now();
@@ -403,7 +518,8 @@ export function replaceSubagentRunAfterSteer(params) {
403
518
  const now = Date.now();
404
519
  const cfg = loadConfig();
405
520
  const archiveAfterMs = resolveArchiveAfterMs(cfg);
406
- const archiveAtMs = archiveAfterMs ? now + archiveAfterMs : undefined;
521
+ const spawnMode = source.spawnMode === "session" ? "session" : "run";
522
+ const archiveAtMs = spawnMode === "session" ? undefined : archiveAfterMs ? now + archiveAfterMs : undefined;
407
523
  const runTimeoutSeconds = params.runTimeoutSeconds ?? source.runTimeoutSeconds ?? 0;
408
524
  const waitTimeoutMs = resolveSubagentWaitTimeoutMs(cfg, runTimeoutSeconds);
409
525
  const next = {
@@ -411,12 +527,15 @@ export function replaceSubagentRunAfterSteer(params) {
411
527
  runId: nextRunId,
412
528
  startedAt: now,
413
529
  endedAt: undefined,
530
+ endedReason: undefined,
531
+ endedHookEmittedAt: undefined,
414
532
  outcome: undefined,
415
533
  cleanupCompletedAt: undefined,
416
534
  cleanupHandled: false,
417
535
  suppressAnnounceReason: undefined,
418
536
  announceRetryCount: undefined,
419
537
  lastAnnounceRetryAt: undefined,
538
+ spawnMode,
420
539
  archiveAtMs,
421
540
  runTimeoutSeconds,
422
541
  };
@@ -433,7 +552,8 @@ export function registerSubagentRun(params) {
433
552
  const now = Date.now();
434
553
  const cfg = loadConfig();
435
554
  const archiveAfterMs = resolveArchiveAfterMs(cfg);
436
- const archiveAtMs = archiveAfterMs ? now + archiveAfterMs : undefined;
555
+ const spawnMode = params.spawnMode === "session" ? "session" : "run";
556
+ const archiveAtMs = spawnMode === "session" ? undefined : archiveAfterMs ? now + archiveAfterMs : undefined;
437
557
  const runTimeoutSeconds = params.runTimeoutSeconds ?? 0;
438
558
  const waitTimeoutMs = resolveSubagentWaitTimeoutMs(cfg, runTimeoutSeconds);
439
559
  const requesterOrigin = normalizeDeliveryContext(params.requesterOrigin);
@@ -446,6 +566,7 @@ export function registerSubagentRun(params) {
446
566
  task: params.task,
447
567
  cleanup: params.cleanup,
448
568
  expectsCompletionMessage: params.expectsCompletionMessage,
569
+ spawnMode,
449
570
  label: params.label,
450
571
  model: params.model,
451
572
  runTimeoutSeconds,
@@ -456,7 +577,7 @@ export function registerSubagentRun(params) {
456
577
  });
457
578
  ensureListener();
458
579
  persistSubagentRuns();
459
- if (archiveAfterMs) {
580
+ if (archiveAtMs) {
460
581
  startSweeper();
461
582
  }
462
583
  // Wait for subagent completion via gateway RPC (cross-process).
@@ -495,22 +616,27 @@ async function waitForSubagentCompletion(runId, waitTimeoutMs) {
495
616
  mutated = true;
496
617
  }
497
618
  const waitError = typeof wait.error === "string" ? wait.error : undefined;
498
- entry.outcome =
499
- wait.status === "error"
500
- ? { status: "error", error: waitError }
501
- : wait.status === "timeout"
502
- ? { status: "timeout" }
503
- : { status: "ok" };
504
- mutated = true;
619
+ const outcome = wait.status === "error"
620
+ ? { status: "error", error: waitError }
621
+ : wait.status === "timeout"
622
+ ? { status: "timeout" }
623
+ : { status: "ok" };
624
+ if (!runOutcomesEqual(entry.outcome, outcome)) {
625
+ entry.outcome = outcome;
626
+ mutated = true;
627
+ }
505
628
  if (mutated) {
506
629
  persistSubagentRuns();
507
630
  }
508
- if (suppressAnnounceForSteerRestart(entry)) {
509
- return;
510
- }
511
- if (!startSubagentAnnounceCleanupFlow(runId, entry)) {
512
- return;
513
- }
631
+ await completeSubagentRun({
632
+ runId,
633
+ endedAt: entry.endedAt,
634
+ outcome,
635
+ reason: wait.status === "error" ? SUBAGENT_ENDED_REASON_ERROR : SUBAGENT_ENDED_REASON_COMPLETE,
636
+ sendFarewell: true,
637
+ accountId: entry.requesterOrigin?.accountId,
638
+ triggerCleanup: true,
639
+ });
514
640
  }
515
641
  catch {
516
642
  // ignore
@@ -519,6 +645,7 @@ async function waitForSubagentCompletion(runId, waitTimeoutMs) {
519
645
  export function resetSubagentRegistryForTests(opts) {
520
646
  subagentRuns.clear();
521
647
  resumedRuns.clear();
648
+ endedHookInFlightRunIds.clear();
522
649
  resetAnnounceQueuesForTests();
523
650
  stopSweeper();
524
651
  restoreAttempted = false;
@@ -544,58 +671,16 @@ export function releaseSubagentRun(runId) {
544
671
  }
545
672
  }
546
673
  function findRunIdsByChildSessionKey(childSessionKey) {
547
- const key = childSessionKey.trim();
548
- if (!key) {
549
- return [];
550
- }
551
- const runIds = [];
552
- for (const [runId, entry] of subagentRuns.entries()) {
553
- if (entry.childSessionKey === key) {
554
- runIds.push(runId);
555
- }
556
- }
557
- return runIds;
558
- }
559
- function getRunsSnapshotForRead() {
560
- const merged = new Map();
561
- const shouldReadDisk = !(process.env.VITEST || process.env.NODE_ENV === "test");
562
- if (shouldReadDisk) {
563
- try {
564
- // Registry state is persisted to disk so other worker processes (for
565
- // example cron runners) can observe active children spawned elsewhere.
566
- for (const [runId, entry] of loadSubagentRegistryFromDisk().entries()) {
567
- merged.set(runId, entry);
568
- }
569
- }
570
- catch {
571
- // Ignore disk read failures and fall back to local memory state.
572
- }
573
- }
574
- for (const [runId, entry] of subagentRuns.entries()) {
575
- merged.set(runId, entry);
576
- }
577
- return merged;
674
+ return findRunIdsByChildSessionKeyFromRuns(subagentRuns, childSessionKey);
578
675
  }
579
676
  export function resolveRequesterForChildSession(childSessionKey) {
580
- const key = childSessionKey.trim();
581
- if (!key) {
582
- return null;
583
- }
584
- let best;
585
- for (const entry of getRunsSnapshotForRead().values()) {
586
- if (entry.childSessionKey !== key) {
587
- continue;
588
- }
589
- if (!best || entry.createdAt > best.createdAt) {
590
- best = entry;
591
- }
592
- }
593
- if (!best) {
677
+ const resolved = resolveRequesterForChildSessionFromRuns(getSubagentRunsSnapshotForRead(subagentRuns), childSessionKey);
678
+ if (!resolved) {
594
679
  return null;
595
680
  }
596
681
  return {
597
- requesterSessionKey: best.requesterSessionKey,
598
- requesterOrigin: normalizeDeliveryContext(best.requesterOrigin),
682
+ requesterSessionKey: resolved.requesterSessionKey,
683
+ requesterOrigin: normalizeDeliveryContext(resolved.requesterOrigin),
599
684
  };
600
685
  }
601
686
  export function isSubagentSessionRunActive(childSessionKey) {
@@ -627,6 +712,7 @@ export function markSubagentRunTerminated(params) {
627
712
  const now = Date.now();
628
713
  const reason = params.reason?.trim() || "killed";
629
714
  let updated = 0;
715
+ const entriesByChildSessionKey = new Map();
630
716
  for (const runId of runIds) {
631
717
  const entry = subagentRuns.get(runId);
632
718
  if (!entry) {
@@ -637,99 +723,44 @@ export function markSubagentRunTerminated(params) {
637
723
  }
638
724
  entry.endedAt = now;
639
725
  entry.outcome = { status: "error", error: reason };
726
+ entry.endedReason = SUBAGENT_ENDED_REASON_KILLED;
640
727
  entry.cleanupHandled = true;
641
728
  entry.cleanupCompletedAt = now;
642
729
  entry.suppressAnnounceReason = "killed";
730
+ if (!entriesByChildSessionKey.has(entry.childSessionKey)) {
731
+ entriesByChildSessionKey.set(entry.childSessionKey, entry);
732
+ }
643
733
  updated += 1;
644
734
  }
645
735
  if (updated > 0) {
646
736
  persistSubagentRuns();
737
+ for (const entry of entriesByChildSessionKey.values()) {
738
+ void emitSubagentEndedHookOnce({
739
+ entry,
740
+ reason: SUBAGENT_ENDED_REASON_KILLED,
741
+ sendFarewell: true,
742
+ outcome: SUBAGENT_ENDED_OUTCOME_KILLED,
743
+ error: reason,
744
+ inFlightRunIds: endedHookInFlightRunIds,
745
+ persist: persistSubagentRuns,
746
+ }).catch(() => {
747
+ // Hook failures should not break termination flow.
748
+ });
749
+ }
647
750
  }
648
751
  return updated;
649
752
  }
650
753
  export function listSubagentRunsForRequester(requesterSessionKey) {
651
- const key = requesterSessionKey.trim();
652
- if (!key) {
653
- return [];
654
- }
655
- return [...subagentRuns.values()].filter((entry) => entry.requesterSessionKey === key);
754
+ return listRunsForRequesterFromRuns(subagentRuns, requesterSessionKey);
656
755
  }
657
756
  export function countActiveRunsForSession(requesterSessionKey) {
658
- const key = requesterSessionKey.trim();
659
- if (!key) {
660
- return 0;
661
- }
662
- let count = 0;
663
- for (const entry of getRunsSnapshotForRead().values()) {
664
- if (entry.requesterSessionKey !== key) {
665
- continue;
666
- }
667
- if (typeof entry.endedAt === "number") {
668
- continue;
669
- }
670
- count += 1;
671
- }
672
- return count;
757
+ return countActiveRunsForSessionFromRuns(getSubagentRunsSnapshotForRead(subagentRuns), requesterSessionKey);
673
758
  }
674
759
  export function countActiveDescendantRuns(rootSessionKey) {
675
- const root = rootSessionKey.trim();
676
- if (!root) {
677
- return 0;
678
- }
679
- const runs = getRunsSnapshotForRead();
680
- const pending = [root];
681
- const visited = new Set([root]);
682
- let count = 0;
683
- while (pending.length > 0) {
684
- const requester = pending.shift();
685
- if (!requester) {
686
- continue;
687
- }
688
- for (const entry of runs.values()) {
689
- if (entry.requesterSessionKey !== requester) {
690
- continue;
691
- }
692
- if (typeof entry.endedAt !== "number") {
693
- count += 1;
694
- }
695
- const childKey = entry.childSessionKey.trim();
696
- if (!childKey || visited.has(childKey)) {
697
- continue;
698
- }
699
- visited.add(childKey);
700
- pending.push(childKey);
701
- }
702
- }
703
- return count;
760
+ return countActiveDescendantRunsFromRuns(getSubagentRunsSnapshotForRead(subagentRuns), rootSessionKey);
704
761
  }
705
762
  export function listDescendantRunsForRequester(rootSessionKey) {
706
- const root = rootSessionKey.trim();
707
- if (!root) {
708
- return [];
709
- }
710
- const runs = getRunsSnapshotForRead();
711
- const pending = [root];
712
- const visited = new Set([root]);
713
- const descendants = [];
714
- while (pending.length > 0) {
715
- const requester = pending.shift();
716
- if (!requester) {
717
- continue;
718
- }
719
- for (const entry of runs.values()) {
720
- if (entry.requesterSessionKey !== requester) {
721
- continue;
722
- }
723
- descendants.push(entry);
724
- const childKey = entry.childSessionKey.trim();
725
- if (!childKey || visited.has(childKey)) {
726
- continue;
727
- }
728
- visited.add(childKey);
729
- pending.push(childKey);
730
- }
731
- }
732
- return descendants;
763
+ return listDescendantRunsForRequesterFromRuns(getSubagentRunsSnapshotForRead(subagentRuns), rootSessionKey);
733
764
  }
734
765
  export function initSubagentRegistry() {
735
766
  restoreSubagentRunsOnce();
@@ -0,0 +1,12 @@
1
+ import { vi } from "vitest";
2
+ const noop = () => { };
3
+ vi.mock("../gateway/call.js", () => ({
4
+ callGateway: vi.fn(async () => ({
5
+ status: "ok",
6
+ startedAt: 111,
7
+ endedAt: 222,
8
+ })),
9
+ }));
10
+ vi.mock("../infra/agent-events.js", () => ({
11
+ onAgentEvent: vi.fn(() => noop),
12
+ }));
@@ -45,6 +45,7 @@ export function loadSubagentRegistryFromDisk() {
45
45
  requesterOrigin,
46
46
  cleanupCompletedAt,
47
47
  cleanupHandled,
48
+ spawnMode: typed.spawnMode === "session" ? "session" : "run",
48
49
  });
49
50
  if (isLegacy)
50
51
  migrated = true;
@@ -0,0 +1 @@
1
+ export {};