@poolzin/pool-bot 2026.2.25 → 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 (506) hide show
  1. package/dist/acp/event-mapper.js +87 -22
  2. package/dist/acp/meta.js +12 -6
  3. package/dist/agents/agent-paths.js +8 -9
  4. package/dist/agents/agent-scope.js +7 -5
  5. package/dist/agents/auth-profiles/oauth.js +148 -64
  6. package/dist/agents/auth-profiles/session-override.js +13 -7
  7. package/dist/agents/bash-tools.exec-host-gateway.js +14 -4
  8. package/dist/agents/bash-tools.exec-runtime.js +2 -25
  9. package/dist/agents/bedrock-discovery.js +3 -1
  10. package/dist/agents/byteplus-models.js +97 -0
  11. package/dist/agents/chutes-oauth.js +1 -0
  12. package/dist/agents/cli-runner/helpers.js +4 -0
  13. package/dist/agents/compaction.js +41 -14
  14. package/dist/agents/doubao-models.js +121 -0
  15. package/dist/agents/failover-error.js +2 -0
  16. package/dist/agents/huggingface-models.js +5 -3
  17. package/dist/agents/live-model-filter.js +5 -0
  18. package/dist/agents/minimax-vlm.js +10 -8
  19. package/dist/agents/model-auth.js +6 -0
  20. package/dist/agents/model-catalog.js +3 -1
  21. package/dist/agents/model-selection.js +7 -1
  22. package/dist/agents/models-config.providers.js +93 -11
  23. package/dist/agents/ollama-stream.js +117 -4
  24. package/dist/agents/opencode-zen-models.js +22 -11
  25. package/dist/agents/pi-embedded-helpers/errors.js +55 -33
  26. package/dist/agents/pi-embedded-helpers/messaging-dedupe.js +10 -5
  27. package/dist/agents/pi-embedded-helpers/thinking.js +10 -5
  28. package/dist/agents/pi-embedded-helpers.js +1 -1
  29. package/dist/agents/pi-embedded-runner/compact.js +29 -7
  30. package/dist/agents/pi-embedded-runner/extensions.js +28 -26
  31. package/dist/agents/pi-embedded-runner/google.js +20 -8
  32. package/dist/agents/pi-embedded-runner/run/attempt.js +95 -36
  33. package/dist/agents/pi-embedded-runner/run.js +71 -12
  34. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +11 -2
  35. package/dist/agents/pi-embedded-runner/session-manager-cache.js +11 -7
  36. package/dist/agents/pi-embedded-runner/system-prompt.js +2 -0
  37. package/dist/agents/pi-embedded-runner/thinking.js +42 -0
  38. package/dist/agents/pi-embedded-runner/tool-name-allowlist.js +19 -0
  39. package/dist/agents/pi-embedded-runner/utils.js +7 -10
  40. package/dist/agents/pi-embedded-subscribe.handlers.lifecycle.js +45 -56
  41. package/dist/agents/pi-embedded-subscribe.handlers.tools.js +2 -2
  42. package/dist/agents/pi-embedded-subscribe.js +9 -4
  43. package/dist/agents/pi-embedded-subscribe.tools.js +68 -14
  44. package/dist/agents/pi-embedded-utils.js +3 -0
  45. package/dist/agents/pi-extensions/compaction-safeguard-runtime.js +4 -20
  46. package/dist/agents/pi-extensions/compaction-safeguard.js +75 -33
  47. package/dist/agents/pi-settings.js +40 -0
  48. package/dist/agents/pi-tools.policy.js +2 -1
  49. package/dist/agents/provider/config-loader.js +1 -1
  50. package/dist/agents/sandbox/browser.js +170 -33
  51. package/dist/agents/sandbox/config-hash.js +14 -27
  52. package/dist/agents/sandbox/config.js +21 -2
  53. package/dist/agents/sandbox/constants.js +2 -0
  54. package/dist/agents/sandbox/docker.js +16 -2
  55. package/dist/agents/sandbox/novnc-auth.js +62 -0
  56. package/dist/agents/sandbox/sanitize-env-vars.js +1 -1
  57. package/dist/agents/sandbox/shared.js +10 -6
  58. package/dist/agents/sandbox-paths.js +24 -11
  59. package/dist/agents/schema/clean-for-gemini.js +132 -85
  60. package/dist/agents/session-slug.js +10 -5
  61. package/dist/agents/session-tool-result-guard-wrapper.js +1 -0
  62. package/dist/agents/session-tool-result-guard.js +3 -1
  63. package/dist/agents/session-transcript-repair.js +40 -6
  64. package/dist/agents/skills/bundled-dir.js +19 -5
  65. package/dist/agents/skills/env-overrides.js +124 -43
  66. package/dist/agents/skills/frontmatter.js +6 -6
  67. package/dist/agents/skills/plugin-skills.js +14 -7
  68. package/dist/agents/skills/workspace.js +1 -0
  69. package/dist/agents/subagent-announce.js +251 -49
  70. package/dist/agents/subagent-lifecycle-events.js +19 -0
  71. package/dist/agents/subagent-registry-cleanup.js +31 -0
  72. package/dist/agents/subagent-registry-completion.js +68 -0
  73. package/dist/agents/subagent-registry-queries.js +117 -0
  74. package/dist/agents/subagent-registry-state.js +46 -0
  75. package/dist/agents/subagent-registry.js +252 -221
  76. package/dist/agents/subagent-registry.store.js +1 -0
  77. package/dist/agents/subagent-registry.types.js +1 -0
  78. package/dist/agents/subagent-spawn.js +195 -7
  79. package/dist/agents/system-prompt.js +22 -6
  80. package/dist/agents/test-helpers/fast-coding-tools.js +1 -18
  81. package/dist/agents/test-helpers/fast-core-tools.js +1 -17
  82. package/dist/agents/timeout.js +18 -6
  83. package/dist/agents/tool-call-id.js +1 -1
  84. package/dist/agents/tool-display-common.js +162 -29
  85. package/dist/agents/tool-images.js +82 -9
  86. package/dist/agents/tool-policy.js +51 -26
  87. package/dist/agents/tools/browser-tool.js +2 -2
  88. package/dist/agents/tools/canvas-tool.js +27 -1
  89. package/dist/agents/tools/common.js +45 -0
  90. package/dist/agents/tools/discord-actions-guild.js +4 -1
  91. package/dist/agents/tools/gateway-tool.js +3 -1
  92. package/dist/agents/tools/nodes-utils.js +1 -10
  93. package/dist/agents/tools/sessions-send-helpers.js +12 -6
  94. package/dist/agents/tools/sessions-spawn-tool.js +8 -2
  95. package/dist/agents/tools/subagents-tool.js +2 -1
  96. package/dist/agents/tools/whatsapp-actions.js +10 -2
  97. package/dist/agents/tools/whatsapp-target-auth.js +18 -0
  98. package/dist/agents/transcript-policy.js +22 -8
  99. package/dist/agents/venice-models.js +11 -3
  100. package/dist/auto-reply/commands-registry.data.js +51 -0
  101. package/dist/auto-reply/commands-registry.js +4 -3
  102. package/dist/auto-reply/group-activation.js +10 -5
  103. package/dist/auto-reply/inbound-debounce.js +10 -5
  104. package/dist/auto-reply/reply/abort.js +1 -1
  105. package/dist/auto-reply/reply/agent-runner-execution.js +4 -1
  106. package/dist/auto-reply/reply/bash-command.js +41 -39
  107. package/dist/auto-reply/reply/command-gates.js +25 -0
  108. package/dist/auto-reply/reply/commands-allowlist.js +111 -72
  109. package/dist/auto-reply/reply/commands-bash.js +6 -5
  110. package/dist/auto-reply/reply/commands-config.js +30 -28
  111. package/dist/auto-reply/reply/commands-core.js +2 -1
  112. package/dist/auto-reply/reply/commands-info.js +1 -0
  113. package/dist/auto-reply/reply/commands-models.js +65 -14
  114. package/dist/auto-reply/reply/commands-session.js +237 -82
  115. package/dist/auto-reply/reply/commands-setunset.js +45 -0
  116. package/dist/auto-reply/reply/commands-subagents/action-agents.js +44 -0
  117. package/dist/auto-reply/reply/commands-subagents/action-focus.js +64 -0
  118. package/dist/auto-reply/reply/commands-subagents/action-help.js +4 -0
  119. package/dist/auto-reply/reply/commands-subagents/action-info.js +45 -0
  120. package/dist/auto-reply/reply/commands-subagents/action-kill.js +60 -0
  121. package/dist/auto-reply/reply/commands-subagents/action-list.js +44 -0
  122. package/dist/auto-reply/reply/commands-subagents/action-log.js +29 -0
  123. package/dist/auto-reply/reply/commands-subagents/action-send.js +119 -0
  124. package/dist/auto-reply/reply/commands-subagents/action-spawn.js +52 -0
  125. package/dist/auto-reply/reply/commands-subagents/action-unfocus.js +30 -0
  126. package/dist/auto-reply/reply/commands-subagents/shared.js +303 -0
  127. package/dist/auto-reply/reply/commands-subagents.js +51 -587
  128. package/dist/auto-reply/reply/commands-tts.js +10 -5
  129. package/dist/auto-reply/reply/config-value.js +10 -5
  130. package/dist/auto-reply/reply/directive-handling.model-picker.js +12 -6
  131. package/dist/auto-reply/reply/directive-handling.persist.js +9 -21
  132. package/dist/auto-reply/reply/directive-handling.shared.js +24 -4
  133. package/dist/auto-reply/reply/followup-runner.js +1 -0
  134. package/dist/auto-reply/reply/get-reply-directives-utils.js +23 -14
  135. package/dist/auto-reply/reply/get-reply-directives.js +17 -28
  136. package/dist/auto-reply/reply/get-reply-inline-actions.js +1 -0
  137. package/dist/auto-reply/reply/get-reply.js +71 -12
  138. package/dist/auto-reply/reply/model-selection.js +80 -39
  139. package/dist/auto-reply/reply/queue/enqueue.js +10 -5
  140. package/dist/auto-reply/reply/queue/state.js +13 -12
  141. package/dist/auto-reply/reply/reply-payloads.js +67 -36
  142. package/dist/auto-reply/reply/reply-reference.js +9 -8
  143. package/dist/auto-reply/reply/route-reply.js +15 -8
  144. package/dist/auto-reply/reply/session-reset-prompt.js +1 -1
  145. package/dist/auto-reply/reply/session.js +22 -6
  146. package/dist/auto-reply/reply/strip-inbound-meta.js +147 -0
  147. package/dist/auto-reply/reply/subagents-utils.js +56 -30
  148. package/dist/auto-reply/reply/typing.js +46 -21
  149. package/dist/auto-reply/send-policy.js +14 -7
  150. package/dist/auto-reply/status.js +140 -16
  151. package/dist/auto-reply/templating.js +10 -5
  152. package/dist/auto-reply/thinking.js +7 -16
  153. package/dist/auto-reply/tokens.js +21 -5
  154. package/dist/browser/bridge-server.js +36 -20
  155. package/dist/browser/cdp.helpers.js +7 -14
  156. package/dist/browser/cdp.js +35 -15
  157. package/dist/browser/chrome.profile-decoration.js +7 -4
  158. package/dist/browser/config.js +4 -0
  159. package/dist/browser/extension-relay-auth.js +55 -0
  160. package/dist/browser/extension-relay.js +74 -29
  161. package/dist/browser/navigation-guard.js +9 -1
  162. package/dist/browser/paths.js +77 -0
  163. package/dist/browser/profiles.js +13 -8
  164. package/dist/browser/pw-ai-module.js +10 -5
  165. package/dist/browser/pw-session.js +76 -39
  166. package/dist/browser/pw-tools-core.interactions.js +14 -7
  167. package/dist/browser/pw-tools-core.state.js +12 -6
  168. package/dist/browser/routes/agent.act.js +2 -2
  169. package/dist/browser/server-context.js +7 -0
  170. package/dist/build-info.json +3 -3
  171. package/dist/channels/allow-from.js +2 -1
  172. package/dist/channels/allowlists/resolve-utils.js +43 -19
  173. package/dist/channels/channel-config.js +14 -7
  174. package/dist/channels/draft-stream-loop.js +7 -0
  175. package/dist/channels/model-overrides.js +82 -0
  176. package/dist/channels/plugins/normalize/imessage.js +14 -7
  177. package/dist/channels/plugins/normalize/slack.js +10 -5
  178. package/dist/channels/plugins/normalize/telegram.js +14 -7
  179. package/dist/channels/plugins/outbound/discord.js +80 -8
  180. package/dist/channels/plugins/outbound/signal.js +11 -11
  181. package/dist/channels/plugins/setup-helpers.js +10 -5
  182. package/dist/channels/sender-label.js +14 -7
  183. package/dist/channels/session.js +4 -2
  184. package/dist/channels/status-reactions.js +297 -0
  185. package/dist/cli/banner.js +1 -1
  186. package/dist/cli/browser-cli-actions-input/register.files-downloads.js +65 -56
  187. package/dist/cli/cli-name.js +11 -11
  188. package/dist/cli/cli-utils.js +13 -3
  189. package/dist/cli/command-format.js +1 -1
  190. package/dist/cli/config-cli.js +1 -1
  191. package/dist/cli/daemon-cli/lifecycle-core.js +31 -19
  192. package/dist/cli/daemon-cli/lifecycle.js +64 -2
  193. package/dist/cli/daemon-cli/restart-health.js +126 -0
  194. package/dist/cli/daemon-cli/status.gather.js +9 -13
  195. package/dist/cli/daemon-cli/status.print.js +2 -10
  196. package/dist/cli/deps.js +27 -22
  197. package/dist/cli/gateway-cli/run-loop.js +23 -5
  198. package/dist/cli/node-cli/register.js +14 -5
  199. package/dist/cli/nodes-media-utils.js +7 -2
  200. package/dist/cli/outbound-send-deps.js +2 -9
  201. package/dist/cli/outbound-send-mapping.js +11 -0
  202. package/dist/cli/pairing-cli.js +40 -14
  203. package/dist/cli/plugins-cli.js +34 -41
  204. package/dist/cli/ports.js +11 -10
  205. package/dist/cli/program/command-registry.js +2 -11
  206. package/dist/cli/program/command-tree.js +16 -0
  207. package/dist/cli/program/preaction.js +13 -9
  208. package/dist/cli/program/register.configure.js +3 -18
  209. package/dist/cli/program/register.maintenance.js +2 -2
  210. package/dist/cli/program/register.onboard.js +2 -0
  211. package/dist/cli/program/register.status-health-sessions.js +16 -17
  212. package/dist/cli/program/register.subclis.js +93 -52
  213. package/dist/cli/route.js +11 -7
  214. package/dist/cli/system-cli.js +36 -46
  215. package/dist/cli/update-cli/shared.js +22 -9
  216. package/dist/cli/update-cli/update-command.js +89 -14
  217. package/dist/cli/update-cli/wizard.js +6 -12
  218. package/dist/commands/agent/run-context.js +18 -5
  219. package/dist/commands/agent/session-store.js +17 -4
  220. package/dist/commands/agent.js +22 -2
  221. package/dist/commands/agents.bindings.js +14 -7
  222. package/dist/commands/agents.commands.add.js +13 -9
  223. package/dist/commands/agents.commands.identity.js +12 -6
  224. package/dist/commands/agents.commands.list.js +11 -6
  225. package/dist/commands/agents.config.js +8 -10
  226. package/dist/commands/agents.providers.js +12 -6
  227. package/dist/commands/auth-choice-options.js +103 -75
  228. package/dist/commands/auth-choice.apply.byteplus.js +55 -0
  229. package/dist/commands/auth-choice.apply.js +4 -0
  230. package/dist/commands/auth-choice.apply.minimax.js +61 -13
  231. package/dist/commands/auth-choice.apply.openai.js +3 -1
  232. package/dist/commands/auth-choice.apply.volcengine.js +55 -0
  233. package/dist/commands/auth-choice.preferred-provider.js +2 -0
  234. package/dist/commands/channels/remove.js +13 -6
  235. package/dist/commands/channels/shared.js +4 -14
  236. package/dist/commands/configure.commands.js +14 -0
  237. package/dist/commands/configure.gateway.js +2 -4
  238. package/dist/commands/configure.js +1 -1
  239. package/dist/commands/configure.shared.js +11 -0
  240. package/dist/commands/daemon-install-helpers.js +2 -2
  241. package/dist/commands/dashboard.js +12 -10
  242. package/dist/commands/docs.js +14 -8
  243. package/dist/commands/doctor-config-flow.js +11 -9
  244. package/dist/commands/doctor-legacy-config.js +281 -0
  245. package/dist/commands/doctor-state-integrity.js +99 -23
  246. package/dist/commands/doctor-update.js +12 -9
  247. package/dist/commands/models/list.list-command.js +7 -5
  248. package/dist/commands/models/set-image.js +2 -21
  249. package/dist/commands/node-daemon-install-helpers.js +10 -8
  250. package/dist/commands/onboard-auth.config-minimax.js +54 -80
  251. package/dist/commands/onboard-auth.config-opencode.js +2 -18
  252. package/dist/commands/onboard-auth.credentials.js +90 -13
  253. package/dist/commands/onboard-auth.js +1 -1
  254. package/dist/commands/onboard-auth.models.js +6 -5
  255. package/dist/commands/onboard-hooks.js +1 -1
  256. package/dist/commands/onboard-non-interactive/api-keys.js +14 -7
  257. package/dist/commands/onboard-non-interactive/local/auth-choice.js +64 -49
  258. package/dist/commands/onboard-provider-auth-flags.js +14 -0
  259. package/dist/commands/onboard-remote.js +14 -7
  260. package/dist/commands/onboard.js +11 -13
  261. package/dist/commands/sandbox-display.js +6 -5
  262. package/dist/commands/status-all/diagnosis.js +14 -10
  263. package/dist/commands/status-all/format.js +1 -0
  264. package/dist/commands/status.gateway-probe.js +1 -16
  265. package/dist/commands/systemd-linger.js +12 -6
  266. package/dist/config/agent-limits.js +2 -0
  267. package/dist/config/commands.js +30 -16
  268. package/dist/config/config-paths.js +9 -11
  269. package/dist/config/defaults.js +22 -2
  270. package/dist/config/discord-preview-streaming.js +104 -0
  271. package/dist/config/env-vars.js +37 -8
  272. package/dist/config/includes.js +4 -0
  273. package/dist/config/io.js +97 -12
  274. package/dist/config/legacy.migrations.part-1.js +189 -78
  275. package/dist/config/legacy.shared.js +3 -1
  276. package/dist/config/merge-patch.js +4 -0
  277. package/dist/config/prototype-keys.js +4 -0
  278. package/dist/config/schema.help.js +44 -7
  279. package/dist/config/schema.labels.js +38 -6
  280. package/dist/config/sessions/delivery-info.js +10 -3
  281. package/dist/config/sessions/main-session.js +10 -5
  282. package/dist/config/sessions/session-file.js +33 -0
  283. package/dist/config/sessions/session-key.js +10 -5
  284. package/dist/config/sessions/store.js +1 -1
  285. package/dist/config/sessions.js +1 -0
  286. package/dist/config/zod-schema.agent-runtime.js +11 -0
  287. package/dist/config/zod-schema.js +148 -13
  288. package/dist/config/zod-schema.providers-core.js +78 -4
  289. package/dist/config/zod-schema.providers.js +6 -1
  290. package/dist/config/zod-schema.session.js +41 -2
  291. package/dist/cron/run-log.js +3 -0
  292. package/dist/cron/schedule.js +21 -10
  293. package/dist/cron/service/ops.js +35 -21
  294. package/dist/cron/service/timer.js +116 -16
  295. package/dist/cron/stagger.js +3 -1
  296. package/dist/discord/api.js +12 -6
  297. package/dist/discord/draft-chunking.js +22 -0
  298. package/dist/discord/draft-stream.js +124 -0
  299. package/dist/discord/monitor/agent-components.js +1 -1
  300. package/dist/discord/monitor/commands.js +5 -0
  301. package/dist/discord/monitor/gateway-plugin.js +2 -1
  302. package/dist/discord/monitor/listeners.js +37 -27
  303. package/dist/discord/monitor/message-handler.js +4 -1
  304. package/dist/discord/monitor/message-handler.preflight.js +65 -8
  305. package/dist/discord/monitor/message-handler.process.js +246 -217
  306. package/dist/discord/monitor/message-utils.js +143 -6
  307. package/dist/discord/monitor/model-picker-preferences.js +143 -0
  308. package/dist/discord/monitor/model-picker.js +651 -0
  309. package/dist/discord/monitor/native-command.js +573 -16
  310. package/dist/discord/monitor/provider.allowlist.js +223 -0
  311. package/dist/discord/monitor/provider.js +275 -347
  312. package/dist/discord/monitor/provider.lifecycle.js +100 -0
  313. package/dist/discord/monitor/reply-delivery.js +123 -16
  314. package/dist/discord/monitor/thread-bindings.discord-api.js +215 -0
  315. package/dist/discord/monitor/thread-bindings.js +4 -0
  316. package/dist/discord/monitor/thread-bindings.lifecycle.js +177 -0
  317. package/dist/discord/monitor/thread-bindings.manager.js +423 -0
  318. package/dist/discord/monitor/thread-bindings.messages.js +55 -0
  319. package/dist/discord/monitor/thread-bindings.state.js +358 -0
  320. package/dist/discord/monitor/thread-bindings.types.js +6 -0
  321. package/dist/discord/resolve-users.js +33 -21
  322. package/dist/discord/send.channels.js +15 -0
  323. package/dist/discord/send.js +3 -2
  324. package/dist/discord/send.outbound.js +82 -26
  325. package/dist/discord/send.permissions.js +83 -30
  326. package/dist/discord/send.reactions.js +8 -4
  327. package/dist/discord/token.js +10 -5
  328. package/dist/discord/voice/command.js +263 -0
  329. package/dist/discord/voice/manager.js +531 -0
  330. package/dist/gateway/auth.js +34 -10
  331. package/dist/gateway/call.js +4 -16
  332. package/dist/gateway/client.js +28 -4
  333. package/dist/gateway/config-reload.js +3 -4
  334. package/dist/gateway/control-ui.js +219 -96
  335. package/dist/gateway/hooks-mapping.js +88 -38
  336. package/dist/gateway/http-auth-helpers.js +3 -2
  337. package/dist/gateway/http-endpoint-helpers.js +1 -0
  338. package/dist/gateway/net.js +54 -12
  339. package/dist/gateway/node-invoke-system-run-approval.js +14 -35
  340. package/dist/gateway/node-registry.js +10 -5
  341. package/dist/gateway/openai-http.js +1 -0
  342. package/dist/gateway/openresponses-http.js +1 -0
  343. package/dist/gateway/origin-check.js +1 -18
  344. package/dist/gateway/protocol/index.js +4 -3
  345. package/dist/gateway/protocol/schema/cron.js +1 -0
  346. package/dist/gateway/protocol/schema/devices.js +1 -0
  347. package/dist/gateway/protocol/schema/protocol-schemas.js +2 -1
  348. package/dist/gateway/protocol/schema/sessions.js +6 -0
  349. package/dist/gateway/role-policy.js +17 -0
  350. package/dist/gateway/server/ws-connection/connect-policy.js +37 -0
  351. package/dist/gateway/server/ws-connection/message-handler.js +175 -148
  352. package/dist/gateway/server-chat.js +83 -25
  353. package/dist/gateway/server-constants.js +10 -9
  354. package/dist/gateway/server-cron.js +1 -0
  355. package/dist/gateway/server-http.js +16 -7
  356. package/dist/gateway/server-maintenance.js +20 -5
  357. package/dist/gateway/server-methods/chat.js +10 -6
  358. package/dist/gateway/server-methods/config.js +12 -14
  359. package/dist/gateway/server-methods/devices.js +17 -3
  360. package/dist/gateway/server-methods/models.js +11 -1
  361. package/dist/gateway/server-methods/sessions.js +64 -8
  362. package/dist/gateway/server-methods/usage.js +162 -75
  363. package/dist/gateway/server-node-events.js +29 -0
  364. package/dist/gateway/server-runtime-config.js +34 -13
  365. package/dist/gateway/server-startup-memory.js +17 -11
  366. package/dist/gateway/session-utils.fs.js +32 -34
  367. package/dist/gateway/sessions-resolve.js +17 -5
  368. package/dist/gateway/test-helpers.openai-mock.js +14 -7
  369. package/dist/gateway/tools-invoke-http.js +21 -10
  370. package/dist/hooks/bundled/bootstrap-extra-files/handler.js +3 -1
  371. package/dist/hooks/bundled/command-logger/handler.js +7 -2
  372. package/dist/hooks/bundled/session-memory/handler.js +6 -5
  373. package/dist/hooks/frontmatter.js +6 -6
  374. package/dist/hooks/gmail-watcher.js +11 -6
  375. package/dist/hooks/internal-hooks.js +11 -1
  376. package/dist/hooks/llm-slug-generator.js +4 -1
  377. package/dist/hooks/workspace.js +47 -17
  378. package/dist/imessage/accounts.js +9 -20
  379. package/dist/imessage/monitor/inbound-processing.js +2 -1
  380. package/dist/infra/archive.js +174 -73
  381. package/dist/infra/control-ui-assets.js +14 -6
  382. package/dist/infra/device-pairing.js +108 -29
  383. package/dist/infra/env.js +10 -5
  384. package/dist/infra/exec-approvals-allowlist.js +122 -0
  385. package/dist/infra/exec-approvals-analysis.js +34 -3
  386. package/dist/infra/exec-approvals.js +5 -17
  387. package/dist/infra/exec-safe-bin-policy.js +53 -45
  388. package/dist/infra/fs-safe.js +71 -39
  389. package/dist/infra/gateway-lock.js +6 -2
  390. package/dist/infra/heartbeat-wake.js +6 -12
  391. package/dist/infra/host-env-security-policy.json +19 -0
  392. package/dist/infra/host-env-security.js +66 -0
  393. package/dist/infra/net/ssrf.js +131 -38
  394. package/dist/infra/outbound/bound-delivery-router.js +88 -0
  395. package/dist/infra/outbound/channel-selection.js +12 -6
  396. package/dist/infra/outbound/envelope.js +1 -1
  397. package/dist/infra/outbound/format.js +12 -6
  398. package/dist/infra/outbound/payloads.js +14 -7
  399. package/dist/infra/outbound/session-binding-service.js +123 -0
  400. package/dist/infra/path-guards.js +25 -0
  401. package/dist/infra/provider-usage.fetch.codex.js +7 -15
  402. package/dist/infra/provider-usage.fetch.gemini.js +14 -11
  403. package/dist/infra/provider-usage.fetch.shared.js +30 -1
  404. package/dist/infra/provider-usage.fetch.zai.js +10 -9
  405. package/dist/infra/retry-policy.js +4 -2
  406. package/dist/infra/retry.js +9 -5
  407. package/dist/infra/session-cost-usage.js +107 -59
  408. package/dist/infra/session-maintenance-warning.js +3 -1
  409. package/dist/infra/shell-env.js +98 -34
  410. package/dist/infra/ssh-config.js +12 -6
  411. package/dist/infra/system-run-command.js +49 -4
  412. package/dist/infra/update-channels.js +10 -5
  413. package/dist/line/accounts.js +5 -7
  414. package/dist/line/bot-access.js +8 -20
  415. package/dist/line/bot-handlers.js +3 -1
  416. package/dist/link-understanding/detect.js +15 -7
  417. package/dist/media/constants.js +15 -6
  418. package/dist/media/image-ops.js +7 -0
  419. package/dist/media/local-roots.js +3 -2
  420. package/dist/media-understanding/apply.js +4 -1
  421. package/dist/media-understanding/concurrency.js +8 -20
  422. package/dist/memory/backend-config.js +45 -6
  423. package/dist/memory/embeddings.js +10 -4
  424. package/dist/memory/fs-utils.js +23 -0
  425. package/dist/memory/manager-search.js +12 -6
  426. package/dist/memory/manager-sync-ops.js +12 -2
  427. package/dist/memory/qmd-manager.js +466 -53
  428. package/dist/memory/query-expansion.js +167 -3
  429. package/dist/memory/status-format.js +10 -5
  430. package/dist/memory/sync-memory-files.js +1 -1
  431. package/dist/node-host/invoke-system-run.js +281 -0
  432. package/dist/node-host/invoke.js +55 -337
  433. package/dist/pairing/pairing-store.js +22 -0
  434. package/dist/plugin-sdk/allow-from.js +1 -1
  435. package/dist/plugin-sdk/command-auth.js +3 -1
  436. package/dist/plugin-sdk/index.js +6 -3
  437. package/dist/plugin-sdk/webhook-targets.js +32 -0
  438. package/dist/plugins/bundled-dir.js +9 -6
  439. package/dist/plugins/hooks.js +50 -0
  440. package/dist/plugins/install.js +28 -16
  441. package/dist/plugins/runtime.js +3 -17
  442. package/dist/plugins/update.js +78 -12
  443. package/dist/process/spawn-utils.js +14 -7
  444. package/dist/providers/github-copilot-token.js +11 -6
  445. package/dist/providers/qwen-portal-oauth.js +14 -6
  446. package/dist/routing/account-id.js +30 -0
  447. package/dist/routing/resolve-route.js +3 -7
  448. package/dist/routing/session-key.js +2 -16
  449. package/dist/security/audit-channel.js +93 -2
  450. package/dist/security/audit-extra.async.js +159 -5
  451. package/dist/security/audit-extra.js +1 -1
  452. package/dist/security/audit-extra.sync.js +85 -6
  453. package/dist/security/audit.js +40 -4
  454. package/dist/security/dm-policy-shared.js +44 -0
  455. package/dist/security/external-content.js +26 -6
  456. package/dist/shared/entry-status.js +6 -0
  457. package/dist/shared/frontmatter.js +5 -5
  458. package/dist/shared/node-match.js +11 -4
  459. package/dist/shared/operator-scope-compat.js +8 -3
  460. package/dist/signal/accounts.js +7 -20
  461. package/dist/signal/monitor/event-handler.js +3 -1
  462. package/dist/slack/accounts.js +6 -19
  463. package/dist/slack/actions.js +11 -3
  464. package/dist/slack/monitor/auth.js +1 -1
  465. package/dist/slack/monitor/message-handler/dispatch.js +50 -29
  466. package/dist/slack/monitor/replies.js +15 -7
  467. package/dist/slack/monitor/slash.js +22 -13
  468. package/dist/slack/resolve-channels.js +10 -5
  469. package/dist/slack/send.js +102 -12
  470. package/dist/slack/stream-mode.js +10 -0
  471. package/dist/slack/streaming.js +4 -2
  472. package/dist/telegram/accounts.js +19 -14
  473. package/dist/telegram/bot/helpers.js +3 -5
  474. package/dist/telegram/bot-access.js +35 -36
  475. package/dist/telegram/bot-handlers.js +120 -148
  476. package/dist/telegram/bot-message-context.js +68 -9
  477. package/dist/telegram/bot-message-dispatch.js +155 -90
  478. package/dist/telegram/bot-native-commands.js +16 -0
  479. package/dist/telegram/draft-stream.js +14 -1
  480. package/dist/telegram/inline-buttons.js +5 -15
  481. package/dist/telegram/monitor.js +11 -7
  482. package/dist/telegram/network-config.js +19 -7
  483. package/dist/telegram/send.js +3 -2
  484. package/dist/telegram/sent-message-cache.js +5 -6
  485. package/dist/telegram/status-reaction-variants.js +208 -0
  486. package/dist/telegram/sticker-cache.js +11 -9
  487. package/dist/terminal/theme.js +12 -12
  488. package/dist/tts/tts.js +80 -567
  489. package/dist/tui/components/chat-log.js +41 -8
  490. package/dist/tui/theme/theme.js +10 -12
  491. package/dist/tui/tui-local-shell.js +16 -6
  492. package/dist/tui/tui.js +58 -6
  493. package/dist/utils/account-id.js +2 -4
  494. package/dist/utils/boolean.js +10 -5
  495. package/dist/utils/directive-tags.js +11 -0
  496. package/dist/utils/queue-helpers.js +67 -12
  497. package/dist/web/auto-reply/deliver-reply.js +8 -4
  498. package/dist/web/auto-reply/mentions.js +10 -5
  499. package/dist/web/auto-reply/monitor/group-members.js +14 -7
  500. package/dist/web/auto-reply/monitor/process-message.js +45 -24
  501. package/dist/web/inbound/access-control.js +5 -2
  502. package/dist/web/login-qr.js +12 -6
  503. package/dist/web/media.js +123 -16
  504. package/extensions/bluebubbles/src/monitor-processing.ts +580 -139
  505. package/extensions/bluebubbles/src/monitor.ts +208 -1950
  506. package/package.json +1 -1
@@ -1,10 +1,11 @@
1
1
  import { inspect } from "node:util";
2
2
  import { Client, ReadyListener, } from "@buape/carbon";
3
+ import { GatewayCloseCodes } from "@buape/carbon/gateway";
4
+ import { VoicePlugin } from "@buape/carbon/voice";
3
5
  import { Routes } from "discord-api-types/v10";
4
6
  import { resolveTextChunkLimit } from "../../auto-reply/chunk.js";
5
7
  import { listNativeCommandSpecsForConfig } from "../../auto-reply/commands-registry.js";
6
8
  import { listSkillCommandsForAgents } from "../../auto-reply/skill-commands.js";
7
- import { addAllowlistUserEntriesFromConfigEntry, buildAllowlistResolutionSummary, mergeAllowlist, resolveAllowlistIdAdditions, patchAllowlistUsersInConfigEntries, summarizeMapping, } from "../../channels/allowlists/resolve-utils.js";
8
9
  import { isNativeCommandsExplicitlyDisabled, resolveNativeCommandsEnabled, resolveNativeSkillsEnabled, } from "../../config/commands.js";
9
10
  import { loadConfig } from "../../config/config.js";
10
11
  import { danger, logVerbose, shouldLogVerbose, warn } from "../../globals.js";
@@ -13,21 +14,22 @@ import { createDiscordRetryRunner } from "../../infra/retry-policy.js";
13
14
  import { createSubsystemLogger } from "../../logging/subsystem.js";
14
15
  import { createNonExitingRuntime } from "../../runtime.js";
15
16
  import { resolveDiscordAccount } from "../accounts.js";
16
- import { attachDiscordGatewayLogging } from "../gateway-logging.js";
17
- import { getDiscordGatewayEmitter, waitForDiscordGatewayStop } from "../monitor.gateway.js";
18
17
  import { fetchDiscordApplicationId } from "../probe.js";
19
- import { resolveDiscordChannelAllowlist } from "../resolve-channels.js";
20
- import { resolveDiscordUserAllowlist } from "../resolve-users.js";
21
18
  import { normalizeDiscordToken } from "../token.js";
19
+ import { createDiscordVoiceCommand } from "../voice/command.js";
20
+ import { DiscordVoiceManager, DiscordVoiceReadyListener } from "../voice/manager.js";
22
21
  import { createAgentComponentButton, createAgentSelectMenu, createDiscordComponentButton, createDiscordComponentChannelSelect, createDiscordComponentMentionableSelect, createDiscordComponentModal, createDiscordComponentRoleSelect, createDiscordComponentStringSelect, createDiscordComponentUserSelect, } from "./agent-components.js";
22
+ import { resolveDiscordSlashCommandConfig } from "./commands.js";
23
23
  import { createExecApprovalButton, DiscordExecApprovalHandler } from "./exec-approvals.js";
24
24
  import { createDiscordGatewayPlugin } from "./gateway-plugin.js";
25
- import { registerGateway, unregisterGateway } from "./gateway-registry.js";
26
25
  import { DiscordMessageListener, DiscordPresenceListener, DiscordReactionListener, DiscordReactionRemoveListener, registerDiscordListener, } from "./listeners.js";
27
26
  import { createDiscordMessageHandler } from "./message-handler.js";
28
- import { createDiscordCommandArgFallbackButton, createDiscordNativeCommand, } from "./native-command.js";
27
+ import { createDiscordCommandArgFallbackButton, createDiscordModelPickerFallbackButton, createDiscordModelPickerFallbackSelect, createDiscordNativeCommand, } from "./native-command.js";
29
28
  import { resolveDiscordPresenceUpdate } from "./presence.js";
29
+ import { resolveDiscordAllowlistConfig } from "./provider.allowlist.js";
30
+ import { runDiscordGatewayLifecycle } from "./provider.lifecycle.js";
30
31
  import { resolveDiscordRestFetch } from "./rest-fetch.js";
32
+ import { createNoopThreadBindingManager, createThreadBindingManager } from "./thread-bindings.js";
31
33
  function summarizeAllowList(list) {
32
34
  if (!list || list.length === 0) {
33
35
  return "any";
@@ -45,6 +47,46 @@ function summarizeGuilds(entries) {
45
47
  const suffix = keys.length > sample.length ? ` (+${keys.length - sample.length})` : "";
46
48
  return `${sample.join(", ")}${suffix}`;
47
49
  }
50
+ const DEFAULT_THREAD_BINDING_TTL_HOURS = 24;
51
+ function normalizeThreadBindingTtlHours(raw) {
52
+ if (typeof raw !== "number" || !Number.isFinite(raw)) {
53
+ return undefined;
54
+ }
55
+ if (raw < 0) {
56
+ return undefined;
57
+ }
58
+ return raw;
59
+ }
60
+ function resolveThreadBindingSessionTtlMs(params) {
61
+ const ttlHours = normalizeThreadBindingTtlHours(params.channelTtlHoursRaw) ??
62
+ normalizeThreadBindingTtlHours(params.sessionTtlHoursRaw) ??
63
+ DEFAULT_THREAD_BINDING_TTL_HOURS;
64
+ return Math.floor(ttlHours * 60 * 60 * 1000);
65
+ }
66
+ function normalizeThreadBindingsEnabled(raw) {
67
+ if (typeof raw !== "boolean") {
68
+ return undefined;
69
+ }
70
+ return raw;
71
+ }
72
+ function resolveThreadBindingsEnabled(params) {
73
+ return (normalizeThreadBindingsEnabled(params.channelEnabledRaw) ??
74
+ normalizeThreadBindingsEnabled(params.sessionEnabledRaw) ??
75
+ true);
76
+ }
77
+ function formatThreadBindingSessionTtlLabel(ttlMs) {
78
+ if (ttlMs <= 0) {
79
+ return "off";
80
+ }
81
+ if (ttlMs < 60_000) {
82
+ return "<1m";
83
+ }
84
+ const totalMinutes = Math.floor(ttlMs / 60_000);
85
+ if (totalMinutes % 60 === 0) {
86
+ return `${Math.floor(totalMinutes / 60)}h`;
87
+ }
88
+ return `${totalMinutes}m`;
89
+ }
48
90
  function dedupeSkillCommandsForDiscord(skillCommands) {
49
91
  const seen = new Set();
50
92
  const deduped = [];
@@ -106,6 +148,14 @@ function formatDiscordDeployErrorDetails(err) {
106
148
  }
107
149
  return details.length > 0 ? ` (${details.join(", ")})` : "";
108
150
  }
151
+ const DISCORD_DISALLOWED_INTENTS_CODE = GatewayCloseCodes.DisallowedIntents;
152
+ function isDiscordDisallowedIntentsError(err) {
153
+ if (!err) {
154
+ return false;
155
+ }
156
+ const message = formatErrorMessage(err);
157
+ return message.includes(String(DISCORD_DISALLOWED_INTENTS_CODE));
158
+ }
109
159
  export async function monitorDiscordProvider(opts = {}) {
110
160
  const cfg = opts.config ?? loadConfig();
111
161
  const account = resolveDiscordAccount({
@@ -118,6 +168,8 @@ export async function monitorDiscordProvider(opts = {}) {
118
168
  }
119
169
  const runtime = opts.runtime ?? createNonExitingRuntime();
120
170
  const discordCfg = account.config;
171
+ const discordRootThreadBindings = cfg.channels?.discord?.threadBindings;
172
+ const discordAccountThreadBindings = cfg.channels?.discord?.accounts?.[account.accountId]?.threadBindings;
121
173
  const discordRestFetch = resolveDiscordRestFetch(discordCfg.proxy, runtime);
122
174
  const dmConfig = discordCfg.dm;
123
175
  let guildEntries = discordCfg.guilds;
@@ -138,6 +190,14 @@ export async function monitorDiscordProvider(opts = {}) {
138
190
  const replyToMode = opts.replyToMode ?? discordCfg.replyToMode ?? "off";
139
191
  const dmEnabled = dmConfig?.enabled ?? true;
140
192
  const dmPolicy = discordCfg.dmPolicy ?? dmConfig?.policy ?? "pairing";
193
+ const threadBindingSessionTtlMs = resolveThreadBindingSessionTtlMs({
194
+ channelTtlHoursRaw: discordAccountThreadBindings?.ttlHours ?? discordRootThreadBindings?.ttlHours,
195
+ sessionTtlHoursRaw: cfg.session?.threadBindings?.ttlHours,
196
+ });
197
+ const threadBindingsEnabled = resolveThreadBindingsEnabled({
198
+ channelEnabledRaw: discordAccountThreadBindings?.enabled ?? discordRootThreadBindings?.enabled,
199
+ sessionEnabledRaw: cfg.session?.threadBindings?.enabled,
200
+ });
141
201
  const groupDmEnabled = dmConfig?.groupEnabled ?? false;
142
202
  const groupDmChannels = dmConfig?.groupChannels;
143
203
  const nativeEnabled = resolveNativeCommandsEnabled({
@@ -155,148 +215,21 @@ export async function monitorDiscordProvider(opts = {}) {
155
215
  globalSetting: cfg.commands?.native,
156
216
  });
157
217
  const useAccessGroups = cfg.commands?.useAccessGroups !== false;
218
+ const slashCommand = resolveDiscordSlashCommandConfig(discordCfg.slashCommand);
158
219
  const sessionPrefix = "discord:slash";
159
- const ephemeralDefault = true;
160
- if (token) {
161
- if (guildEntries && Object.keys(guildEntries).length > 0) {
162
- try {
163
- const entries = [];
164
- for (const [guildKey, guildCfg] of Object.entries(guildEntries)) {
165
- if (guildKey === "*") {
166
- continue;
167
- }
168
- const channels = guildCfg?.channels ?? {};
169
- const channelKeys = Object.keys(channels).filter((key) => key !== "*");
170
- if (channelKeys.length === 0) {
171
- const input = /^\d+$/.test(guildKey) ? `guild:${guildKey}` : guildKey;
172
- entries.push({ input, guildKey });
173
- continue;
174
- }
175
- for (const channelKey of channelKeys) {
176
- entries.push({
177
- input: `${guildKey}/${channelKey}`,
178
- guildKey,
179
- channelKey,
180
- });
181
- }
182
- }
183
- if (entries.length > 0) {
184
- const resolved = await resolveDiscordChannelAllowlist({
185
- token,
186
- entries: entries.map((entry) => entry.input),
187
- fetcher: discordRestFetch,
188
- });
189
- const nextGuilds = { ...guildEntries };
190
- const mapping = [];
191
- const unresolved = [];
192
- for (const entry of resolved) {
193
- const source = entries.find((item) => item.input === entry.input);
194
- if (!source) {
195
- continue;
196
- }
197
- const sourceGuild = guildEntries?.[source.guildKey] ?? {};
198
- if (!entry.resolved || !entry.guildId) {
199
- unresolved.push(entry.input);
200
- continue;
201
- }
202
- mapping.push(entry.channelId
203
- ? `${entry.input}→${entry.guildId}/${entry.channelId}`
204
- : `${entry.input}→${entry.guildId}`);
205
- const existing = nextGuilds[entry.guildId] ?? {};
206
- const mergedChannels = { ...sourceGuild.channels, ...existing.channels };
207
- const mergedGuild = { ...sourceGuild, ...existing, channels: mergedChannels };
208
- nextGuilds[entry.guildId] = mergedGuild;
209
- if (source.channelKey && entry.channelId) {
210
- const sourceChannel = sourceGuild.channels?.[source.channelKey];
211
- if (sourceChannel) {
212
- nextGuilds[entry.guildId] = {
213
- ...mergedGuild,
214
- channels: {
215
- ...mergedChannels,
216
- [entry.channelId]: {
217
- ...sourceChannel,
218
- ...mergedChannels?.[entry.channelId],
219
- },
220
- },
221
- };
222
- }
223
- }
224
- }
225
- guildEntries = nextGuilds;
226
- summarizeMapping("discord channels", mapping, unresolved, runtime);
227
- }
228
- }
229
- catch (err) {
230
- runtime.log?.(`discord channel resolve failed; using config entries. ${formatErrorMessage(err)}`);
231
- }
232
- }
233
- const allowEntries = allowFrom?.filter((entry) => String(entry).trim() && String(entry).trim() !== "*") ?? [];
234
- if (allowEntries.length > 0) {
235
- try {
236
- const resolvedUsers = await resolveDiscordUserAllowlist({
237
- token,
238
- entries: allowEntries.map((entry) => String(entry)),
239
- fetcher: discordRestFetch,
240
- });
241
- const { mapping, unresolved, additions } = buildAllowlistResolutionSummary(resolvedUsers);
242
- allowFrom = mergeAllowlist({ existing: allowFrom, additions });
243
- summarizeMapping("discord users", mapping, unresolved, runtime);
244
- }
245
- catch (err) {
246
- runtime.log?.(`discord user resolve failed; using config entries. ${formatErrorMessage(err)}`);
247
- }
248
- }
249
- if (guildEntries && Object.keys(guildEntries).length > 0) {
250
- const userEntries = new Set();
251
- for (const guild of Object.values(guildEntries)) {
252
- if (!guild || typeof guild !== "object") {
253
- continue;
254
- }
255
- addAllowlistUserEntriesFromConfigEntry(userEntries, guild);
256
- const channels = guild.channels ?? {};
257
- for (const channel of Object.values(channels)) {
258
- addAllowlistUserEntriesFromConfigEntry(userEntries, channel);
259
- }
260
- }
261
- if (userEntries.size > 0) {
262
- try {
263
- const resolvedUsers = await resolveDiscordUserAllowlist({
264
- token,
265
- entries: Array.from(userEntries),
266
- fetcher: discordRestFetch,
267
- });
268
- const { resolvedMap, mapping, unresolved } = buildAllowlistResolutionSummary(resolvedUsers);
269
- const nextGuilds = { ...guildEntries };
270
- for (const [guildKey, guildConfig] of Object.entries(guildEntries ?? {})) {
271
- if (!guildConfig || typeof guildConfig !== "object") {
272
- continue;
273
- }
274
- const nextGuild = { ...guildConfig };
275
- const users = guildConfig.users;
276
- if (Array.isArray(users) && users.length > 0) {
277
- const additions = resolveAllowlistIdAdditions({ existing: users, resolvedMap });
278
- nextGuild.users = mergeAllowlist({ existing: users, additions });
279
- }
280
- const channels = guildConfig.channels ?? {};
281
- if (channels && typeof channels === "object") {
282
- nextGuild.channels = patchAllowlistUsersInConfigEntries({
283
- entries: channels,
284
- resolvedMap,
285
- });
286
- }
287
- nextGuilds[guildKey] = nextGuild;
288
- }
289
- guildEntries = nextGuilds;
290
- summarizeMapping("discord channel users", mapping, unresolved, runtime);
291
- }
292
- catch (err) {
293
- runtime.log?.(`discord channel user resolve failed; using config entries. ${formatErrorMessage(err)}`);
294
- }
295
- }
296
- }
297
- }
220
+ const ephemeralDefault = slashCommand.ephemeral;
221
+ const voiceEnabled = discordCfg.voice?.enabled !== false;
222
+ const allowlistResolved = await resolveDiscordAllowlistConfig({
223
+ token,
224
+ guildEntries,
225
+ allowFrom,
226
+ fetcher: discordRestFetch,
227
+ runtime,
228
+ });
229
+ guildEntries = allowlistResolved.guildEntries;
230
+ allowFrom = allowlistResolved.allowFrom;
298
231
  if (shouldLogVerbose()) {
299
- logVerbose(`discord: config dm=${dmEnabled ? "on" : "off"} dmPolicy=${dmPolicy} allowFrom=${summarizeAllowList(allowFrom)} groupDm=${groupDmEnabled ? "on" : "off"} groupDmChannels=${summarizeAllowList(groupDmChannels)} groupPolicy=${groupPolicy} guilds=${summarizeGuilds(guildEntries)} historyLimit=${historyLimit} mediaMaxMb=${Math.round(mediaMaxBytes / (1024 * 1024))} native=${nativeEnabled ? "on" : "off"} nativeSkills=${nativeSkillsEnabled ? "on" : "off"} accessGroups=${useAccessGroups ? "on" : "off"}`);
232
+ logVerbose(`discord: config dm=${dmEnabled ? "on" : "off"} dmPolicy=${dmPolicy} allowFrom=${summarizeAllowList(allowFrom)} groupDm=${groupDmEnabled ? "on" : "off"} groupDmChannels=${summarizeAllowList(groupDmChannels)} groupPolicy=${groupPolicy} guilds=${summarizeGuilds(guildEntries)} historyLimit=${historyLimit} mediaMaxMb=${Math.round(mediaMaxBytes / (1024 * 1024))} native=${nativeEnabled ? "on" : "off"} nativeSkills=${nativeSkillsEnabled ? "on" : "off"} accessGroups=${useAccessGroups ? "on" : "off"} threadBindings=${threadBindingsEnabled ? "on" : "off"} threadSessionTtl=${formatThreadBindingSessionTtlLabel(threadBindingSessionTtlMs)}`);
300
233
  }
301
234
  const applicationId = await fetchDiscordApplicationId(token, 4000, discordRestFetch);
302
235
  if (!applicationId) {
@@ -318,223 +251,217 @@ export async function monitorDiscordProvider(opts = {}) {
318
251
  if (nativeEnabled && commandSpecs.length > maxDiscordCommands) {
319
252
  runtime.log?.(warn(`discord: ${commandSpecs.length} commands exceeds limit; some commands may fail to deploy.`));
320
253
  }
321
- const commands = commandSpecs.map((spec) => createDiscordNativeCommand({
322
- command: spec,
323
- cfg,
324
- discordConfig: discordCfg,
325
- accountId: account.accountId,
326
- sessionPrefix,
327
- ephemeralDefault,
328
- }));
329
- // Initialize exec approvals handler if enabled
330
- const execApprovalsConfig = discordCfg.execApprovals ?? {};
331
- const execApprovalsHandler = execApprovalsConfig.enabled
332
- ? new DiscordExecApprovalHandler({
333
- token,
254
+ const voiceManagerRef = { current: null };
255
+ const threadBindings = threadBindingsEnabled
256
+ ? createThreadBindingManager({
334
257
  accountId: account.accountId,
335
- config: execApprovalsConfig,
336
- cfg,
337
- runtime,
258
+ token,
259
+ sessionTtlMs: threadBindingSessionTtlMs,
338
260
  })
339
- : null;
340
- const agentComponentsConfig = discordCfg.agentComponents ?? {};
341
- const agentComponentsEnabled = agentComponentsConfig.enabled ?? true;
342
- const components = [
343
- createDiscordCommandArgFallbackButton({
261
+ : createNoopThreadBindingManager(account.accountId);
262
+ let lifecycleStarted = false;
263
+ try {
264
+ const commands = commandSpecs.map((spec) => createDiscordNativeCommand({
265
+ command: spec,
344
266
  cfg,
345
267
  discordConfig: discordCfg,
346
268
  accountId: account.accountId,
347
269
  sessionPrefix,
348
- }),
349
- ];
350
- const modals = [];
351
- if (execApprovalsHandler) {
352
- components.push(createExecApprovalButton({ handler: execApprovalsHandler }));
353
- }
354
- if (agentComponentsEnabled) {
355
- const componentContext = {
270
+ ephemeralDefault,
271
+ threadBindings,
272
+ }));
273
+ if (nativeEnabled && voiceEnabled) {
274
+ commands.push(createDiscordVoiceCommand({
275
+ cfg,
276
+ discordConfig: discordCfg,
277
+ accountId: account.accountId,
278
+ groupPolicy,
279
+ useAccessGroups,
280
+ getManager: () => voiceManagerRef.current,
281
+ ephemeralDefault,
282
+ }));
283
+ }
284
+ // Initialize exec approvals handler if enabled
285
+ const execApprovalsConfig = discordCfg.execApprovals ?? {};
286
+ const execApprovalsHandler = execApprovalsConfig.enabled
287
+ ? new DiscordExecApprovalHandler({
288
+ token,
289
+ accountId: account.accountId,
290
+ config: execApprovalsConfig,
291
+ cfg,
292
+ runtime,
293
+ })
294
+ : null;
295
+ const agentComponentsConfig = discordCfg.agentComponents ?? {};
296
+ const agentComponentsEnabled = agentComponentsConfig.enabled ?? true;
297
+ const components = [
298
+ createDiscordCommandArgFallbackButton({
299
+ cfg,
300
+ discordConfig: discordCfg,
301
+ accountId: account.accountId,
302
+ sessionPrefix,
303
+ threadBindings,
304
+ }),
305
+ createDiscordModelPickerFallbackButton({
306
+ cfg,
307
+ discordConfig: discordCfg,
308
+ accountId: account.accountId,
309
+ sessionPrefix,
310
+ threadBindings,
311
+ }),
312
+ createDiscordModelPickerFallbackSelect({
313
+ cfg,
314
+ discordConfig: discordCfg,
315
+ accountId: account.accountId,
316
+ sessionPrefix,
317
+ threadBindings,
318
+ }),
319
+ ];
320
+ const modals = [];
321
+ if (execApprovalsHandler) {
322
+ components.push(createExecApprovalButton({ handler: execApprovalsHandler }));
323
+ }
324
+ if (agentComponentsEnabled) {
325
+ const componentContext = {
326
+ cfg,
327
+ discordConfig: discordCfg,
328
+ accountId: account.accountId,
329
+ guildEntries,
330
+ allowFrom,
331
+ dmPolicy,
332
+ runtime,
333
+ token,
334
+ };
335
+ components.push(createAgentComponentButton(componentContext));
336
+ components.push(createAgentSelectMenu(componentContext));
337
+ components.push(createDiscordComponentButton(componentContext));
338
+ components.push(createDiscordComponentStringSelect(componentContext));
339
+ components.push(createDiscordComponentUserSelect(componentContext));
340
+ components.push(createDiscordComponentRoleSelect(componentContext));
341
+ components.push(createDiscordComponentMentionableSelect(componentContext));
342
+ components.push(createDiscordComponentChannelSelect(componentContext));
343
+ modals.push(createDiscordComponentModal(componentContext));
344
+ }
345
+ class DiscordStatusReadyListener extends ReadyListener {
346
+ async handle(_data, client) {
347
+ const gateway = client.getPlugin("gateway");
348
+ if (!gateway) {
349
+ return;
350
+ }
351
+ const presence = resolveDiscordPresenceUpdate(discordCfg);
352
+ if (!presence) {
353
+ return;
354
+ }
355
+ gateway.updatePresence(presence);
356
+ }
357
+ }
358
+ const clientPlugins = [
359
+ createDiscordGatewayPlugin({ discordConfig: discordCfg, runtime }),
360
+ ];
361
+ if (voiceEnabled) {
362
+ clientPlugins.push(new VoicePlugin());
363
+ }
364
+ const client = new Client({
365
+ baseUrl: "http://localhost",
366
+ deploySecret: "a",
367
+ clientId: applicationId,
368
+ publicKey: "a",
369
+ token,
370
+ autoDeploy: false,
371
+ }, {
372
+ commands,
373
+ listeners: [new DiscordStatusReadyListener()],
374
+ components,
375
+ modals,
376
+ }, clientPlugins);
377
+ await deployDiscordCommands({ client, runtime, enabled: nativeEnabled });
378
+ const logger = createSubsystemLogger("discord/monitor");
379
+ const guildHistories = new Map();
380
+ let botUserId;
381
+ let voiceManager = null;
382
+ if (nativeDisabledExplicit) {
383
+ await clearDiscordNativeCommands({
384
+ client,
385
+ applicationId,
386
+ runtime,
387
+ });
388
+ }
389
+ try {
390
+ const botUser = await client.fetchUser("@me");
391
+ botUserId = botUser?.id;
392
+ }
393
+ catch (err) {
394
+ runtime.error?.(danger(`discord: failed to fetch bot identity: ${String(err)}`));
395
+ }
396
+ if (voiceEnabled) {
397
+ voiceManager = new DiscordVoiceManager({
398
+ client,
399
+ cfg,
400
+ discordConfig: discordCfg,
401
+ accountId: account.accountId,
402
+ runtime,
403
+ botUserId,
404
+ });
405
+ voiceManagerRef.current = voiceManager;
406
+ registerDiscordListener(client.listeners, new DiscordVoiceReadyListener(voiceManager));
407
+ }
408
+ const messageHandler = createDiscordMessageHandler({
356
409
  cfg,
357
410
  discordConfig: discordCfg,
358
411
  accountId: account.accountId,
359
- guildEntries,
412
+ token,
413
+ runtime,
414
+ botUserId,
415
+ guildHistories,
416
+ historyLimit,
417
+ mediaMaxBytes,
418
+ textLimit,
419
+ replyToMode,
420
+ dmEnabled,
421
+ groupDmEnabled,
422
+ groupDmChannels,
360
423
  allowFrom,
361
- dmPolicy,
424
+ guildEntries,
425
+ threadBindings,
426
+ });
427
+ registerDiscordListener(client.listeners, new DiscordMessageListener(messageHandler, logger));
428
+ registerDiscordListener(client.listeners, new DiscordReactionListener({
429
+ cfg,
430
+ accountId: account.accountId,
362
431
  runtime,
363
- token,
364
- };
365
- components.push(createAgentComponentButton(componentContext));
366
- components.push(createAgentSelectMenu(componentContext));
367
- components.push(createDiscordComponentButton(componentContext));
368
- components.push(createDiscordComponentStringSelect(componentContext));
369
- components.push(createDiscordComponentUserSelect(componentContext));
370
- components.push(createDiscordComponentRoleSelect(componentContext));
371
- components.push(createDiscordComponentMentionableSelect(componentContext));
372
- components.push(createDiscordComponentChannelSelect(componentContext));
373
- modals.push(createDiscordComponentModal(componentContext));
374
- }
375
- class DiscordStatusReadyListener extends ReadyListener {
376
- async handle(_data, client) {
377
- const gateway = client.getPlugin("gateway");
378
- if (!gateway) {
379
- return;
380
- }
381
- const presence = resolveDiscordPresenceUpdate(discordCfg);
382
- if (!presence) {
383
- return;
384
- }
385
- gateway.updatePresence(presence);
432
+ botUserId,
433
+ guildEntries,
434
+ logger,
435
+ }));
436
+ registerDiscordListener(client.listeners, new DiscordReactionRemoveListener({
437
+ cfg,
438
+ accountId: account.accountId,
439
+ runtime,
440
+ botUserId,
441
+ guildEntries,
442
+ logger,
443
+ }));
444
+ if (discordCfg.intents?.presence) {
445
+ registerDiscordListener(client.listeners, new DiscordPresenceListener({ logger, accountId: account.accountId }));
446
+ runtime.log?.("discord: GuildPresences intent enabled — presence listener registered");
386
447
  }
387
- }
388
- const client = new Client({
389
- baseUrl: "http://localhost",
390
- deploySecret: "a",
391
- clientId: applicationId,
392
- publicKey: "a",
393
- token,
394
- autoDeploy: false,
395
- }, {
396
- commands,
397
- listeners: [new DiscordStatusReadyListener()],
398
- components,
399
- modals,
400
- }, [createDiscordGatewayPlugin({ discordConfig: discordCfg, runtime })]);
401
- await deployDiscordCommands({ client, runtime, enabled: nativeEnabled });
402
- const logger = createSubsystemLogger("discord/monitor");
403
- const guildHistories = new Map();
404
- let botUserId;
405
- if (nativeDisabledExplicit) {
406
- await clearDiscordNativeCommands({
448
+ runtime.log?.(`logged in to discord${botUserId ? ` as ${botUserId}` : ""}`);
449
+ lifecycleStarted = true;
450
+ await runDiscordGatewayLifecycle({
451
+ accountId: account.accountId,
407
452
  client,
408
- applicationId,
409
453
  runtime,
410
- });
411
- }
412
- try {
413
- const botUser = await client.fetchUser("@me");
414
- botUserId = botUser?.id;
415
- }
416
- catch (err) {
417
- runtime.error?.(danger(`discord: failed to fetch bot identity: ${String(err)}`));
418
- }
419
- const messageHandler = createDiscordMessageHandler({
420
- cfg,
421
- discordConfig: discordCfg,
422
- accountId: account.accountId,
423
- token,
424
- runtime,
425
- botUserId,
426
- guildHistories,
427
- historyLimit,
428
- mediaMaxBytes,
429
- textLimit,
430
- replyToMode,
431
- dmEnabled,
432
- groupDmEnabled,
433
- groupDmChannels,
434
- allowFrom,
435
- guildEntries,
436
- });
437
- registerDiscordListener(client.listeners, new DiscordMessageListener(messageHandler, logger));
438
- registerDiscordListener(client.listeners, new DiscordReactionListener({
439
- cfg,
440
- accountId: account.accountId,
441
- runtime,
442
- botUserId,
443
- guildEntries,
444
- logger,
445
- }));
446
- registerDiscordListener(client.listeners, new DiscordReactionRemoveListener({
447
- cfg,
448
- accountId: account.accountId,
449
- runtime,
450
- botUserId,
451
- guildEntries,
452
- logger,
453
- }));
454
- if (discordCfg.intents?.presence) {
455
- registerDiscordListener(client.listeners, new DiscordPresenceListener({ logger, accountId: account.accountId }));
456
- runtime.log?.("discord: GuildPresences intent enabled — presence listener registered");
457
- }
458
- runtime.log?.(`logged in to discord${botUserId ? ` as ${botUserId}` : ""}`);
459
- // Start exec approvals handler after client is ready
460
- if (execApprovalsHandler) {
461
- await execApprovalsHandler.start();
462
- }
463
- const gateway = client.getPlugin("gateway");
464
- if (gateway) {
465
- registerGateway(account.accountId, gateway);
466
- }
467
- const gatewayEmitter = getDiscordGatewayEmitter(gateway);
468
- const stopGatewayLogging = attachDiscordGatewayLogging({
469
- emitter: gatewayEmitter,
470
- runtime,
471
- });
472
- const abortSignal = opts.abortSignal;
473
- const onAbort = () => {
474
- if (!gateway) {
475
- return;
476
- }
477
- // Carbon emits an error when maxAttempts is 0; keep a one-shot listener to avoid
478
- // an unhandled error after we tear down listeners during abort.
479
- gatewayEmitter?.once("error", () => { });
480
- gateway.options.reconnect = { maxAttempts: 0 };
481
- gateway.disconnect();
482
- };
483
- if (abortSignal?.aborted) {
484
- onAbort();
485
- }
486
- else {
487
- abortSignal?.addEventListener("abort", onAbort, { once: true });
488
- }
489
- // Timeout to detect zombie connections where HELLO is never received.
490
- const HELLO_TIMEOUT_MS = 30000;
491
- let helloTimeoutId;
492
- const onGatewayDebug = (msg) => {
493
- const message = String(msg);
494
- if (!message.includes("WebSocket connection opened")) {
495
- return;
496
- }
497
- if (helloTimeoutId) {
498
- clearTimeout(helloTimeoutId);
499
- }
500
- helloTimeoutId = setTimeout(() => {
501
- if (!gateway?.isConnected) {
502
- runtime.log?.(danger(`connection stalled: no HELLO received within ${HELLO_TIMEOUT_MS}ms, forcing reconnect`));
503
- gateway?.disconnect();
504
- gateway?.connect(false);
505
- }
506
- helloTimeoutId = undefined;
507
- }, HELLO_TIMEOUT_MS);
508
- };
509
- gatewayEmitter?.on("debug", onGatewayDebug);
510
- try {
511
- await waitForDiscordGatewayStop({
512
- gateway: gateway
513
- ? {
514
- emitter: gatewayEmitter,
515
- disconnect: () => gateway.disconnect(),
516
- }
517
- : undefined,
518
- abortSignal,
519
- onGatewayError: (err) => {
520
- runtime.error?.(danger(`discord gateway error: ${String(err)}`));
521
- },
522
- shouldStopOnError: (err) => {
523
- const message = String(err);
524
- return (message.includes("Max reconnect attempts") || message.includes("Fatal Gateway error"));
525
- },
454
+ abortSignal: opts.abortSignal,
455
+ isDisallowedIntentsError: isDiscordDisallowedIntentsError,
456
+ voiceManager,
457
+ voiceManagerRef,
458
+ execApprovalsHandler,
459
+ threadBindings,
526
460
  });
527
461
  }
528
462
  finally {
529
- unregisterGateway(account.accountId);
530
- stopGatewayLogging();
531
- if (helloTimeoutId) {
532
- clearTimeout(helloTimeoutId);
533
- }
534
- gatewayEmitter?.removeListener("debug", onGatewayDebug);
535
- abortSignal?.removeEventListener("abort", onAbort);
536
- if (execApprovalsHandler) {
537
- await execApprovalsHandler.stop();
463
+ if (!lifecycleStarted) {
464
+ threadBindings.stop();
538
465
  }
539
466
  }
540
467
  }
@@ -553,4 +480,5 @@ export const __testing = {
553
480
  createDiscordGatewayPlugin,
554
481
  dedupeSkillCommandsForDiscord,
555
482
  resolveDiscordRestFetch,
483
+ resolveThreadBindingsEnabled,
556
484
  };