@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
@@ -0,0 +1,358 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { resolveStateDir } from "../../config/paths.js";
4
+ import { loadJsonFile, saveJsonFile } from "../../infra/json-file.js";
5
+ import { normalizeAccountId, resolveAgentIdFromSessionKey } from "../../routing/session-key.js";
6
+ import { DEFAULT_THREAD_BINDING_TTL_MS, RECENT_UNBOUND_WEBHOOK_ECHO_TTL_MS, THREAD_BINDINGS_VERSION, } from "./thread-bindings.types.js";
7
+ // Plugin hooks can load this module via Jiti while core imports it via ESM.
8
+ // Store mutable state on globalThis so both loader paths share one registry.
9
+ const THREAD_BINDINGS_STATE_KEY = "__poolbotDiscordThreadBindingsState";
10
+ function createThreadBindingsGlobalState() {
11
+ return {
12
+ managersByAccountId: new Map(),
13
+ bindingsByThreadId: new Map(),
14
+ bindingsBySessionKey: new Map(),
15
+ tokensByAccountId: new Map(),
16
+ recentUnboundWebhookEchoesByBindingKey: new Map(),
17
+ reusableWebhooksByAccountChannel: new Map(),
18
+ persistByAccountId: new Map(),
19
+ loadedBindings: false,
20
+ };
21
+ }
22
+ function resolveThreadBindingsGlobalState() {
23
+ const runtimeGlobal = globalThis;
24
+ if (!runtimeGlobal[THREAD_BINDINGS_STATE_KEY]) {
25
+ runtimeGlobal[THREAD_BINDINGS_STATE_KEY] = createThreadBindingsGlobalState();
26
+ }
27
+ return runtimeGlobal[THREAD_BINDINGS_STATE_KEY];
28
+ }
29
+ const THREAD_BINDINGS_STATE = resolveThreadBindingsGlobalState();
30
+ export const MANAGERS_BY_ACCOUNT_ID = THREAD_BINDINGS_STATE.managersByAccountId;
31
+ export const BINDINGS_BY_THREAD_ID = THREAD_BINDINGS_STATE.bindingsByThreadId;
32
+ export const BINDINGS_BY_SESSION_KEY = THREAD_BINDINGS_STATE.bindingsBySessionKey;
33
+ export const TOKENS_BY_ACCOUNT_ID = THREAD_BINDINGS_STATE.tokensByAccountId;
34
+ export const RECENT_UNBOUND_WEBHOOK_ECHOES_BY_BINDING_KEY = THREAD_BINDINGS_STATE.recentUnboundWebhookEchoesByBindingKey;
35
+ export const REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL = THREAD_BINDINGS_STATE.reusableWebhooksByAccountChannel;
36
+ export const PERSIST_BY_ACCOUNT_ID = THREAD_BINDINGS_STATE.persistByAccountId;
37
+ export function rememberThreadBindingToken(params) {
38
+ const normalizedAccountId = normalizeAccountId(params.accountId);
39
+ const token = params.token?.trim();
40
+ if (!token) {
41
+ return;
42
+ }
43
+ TOKENS_BY_ACCOUNT_ID.set(normalizedAccountId, token);
44
+ }
45
+ export function forgetThreadBindingToken(accountId) {
46
+ TOKENS_BY_ACCOUNT_ID.delete(normalizeAccountId(accountId));
47
+ }
48
+ export function getThreadBindingToken(accountId) {
49
+ return TOKENS_BY_ACCOUNT_ID.get(normalizeAccountId(accountId));
50
+ }
51
+ export function shouldDefaultPersist() {
52
+ return !(process.env.VITEST || process.env.NODE_ENV === "test");
53
+ }
54
+ export function resolveThreadBindingsPath() {
55
+ return path.join(resolveStateDir(process.env), "discord", "thread-bindings.json");
56
+ }
57
+ export function normalizeTargetKind(raw, targetSessionKey) {
58
+ if (raw === "subagent" || raw === "acp") {
59
+ return raw;
60
+ }
61
+ return targetSessionKey.includes(":subagent:") ? "subagent" : "acp";
62
+ }
63
+ export function normalizeThreadId(raw) {
64
+ if (typeof raw === "number" && Number.isFinite(raw)) {
65
+ return String(Math.floor(raw));
66
+ }
67
+ if (typeof raw !== "string") {
68
+ return undefined;
69
+ }
70
+ const trimmed = raw.trim();
71
+ return trimmed ? trimmed : undefined;
72
+ }
73
+ export function toBindingRecordKey(params) {
74
+ return `${normalizeAccountId(params.accountId)}:${params.threadId.trim()}`;
75
+ }
76
+ export function resolveBindingRecordKey(params) {
77
+ const threadId = normalizeThreadId(params.threadId);
78
+ if (!threadId) {
79
+ return undefined;
80
+ }
81
+ return toBindingRecordKey({
82
+ accountId: normalizeAccountId(params.accountId),
83
+ threadId,
84
+ });
85
+ }
86
+ function normalizePersistedBinding(threadIdKey, raw) {
87
+ if (!raw || typeof raw !== "object") {
88
+ return null;
89
+ }
90
+ const value = raw;
91
+ const threadId = normalizeThreadId(value.threadId ?? threadIdKey);
92
+ const channelId = typeof value.channelId === "string" ? value.channelId.trim() : "";
93
+ const targetSessionKey = typeof value.targetSessionKey === "string"
94
+ ? value.targetSessionKey.trim()
95
+ : typeof value.sessionKey === "string"
96
+ ? value.sessionKey.trim()
97
+ : "";
98
+ if (!threadId || !channelId || !targetSessionKey) {
99
+ return null;
100
+ }
101
+ const accountId = normalizeAccountId(value.accountId);
102
+ const targetKind = normalizeTargetKind(value.targetKind, targetSessionKey);
103
+ const agentIdRaw = typeof value.agentId === "string" ? value.agentId.trim() : "";
104
+ const agentId = agentIdRaw || resolveAgentIdFromSessionKey(targetSessionKey);
105
+ const label = typeof value.label === "string" ? value.label.trim() || undefined : undefined;
106
+ const webhookId = typeof value.webhookId === "string" ? value.webhookId.trim() || undefined : undefined;
107
+ const webhookToken = typeof value.webhookToken === "string" ? value.webhookToken.trim() || undefined : undefined;
108
+ const boundBy = typeof value.boundBy === "string" ? value.boundBy.trim() || "system" : "system";
109
+ const boundAt = typeof value.boundAt === "number" && Number.isFinite(value.boundAt)
110
+ ? Math.floor(value.boundAt)
111
+ : Date.now();
112
+ const expiresAt = typeof value.expiresAt === "number" && Number.isFinite(value.expiresAt)
113
+ ? Math.max(0, Math.floor(value.expiresAt))
114
+ : undefined;
115
+ return {
116
+ accountId,
117
+ channelId,
118
+ threadId,
119
+ targetKind,
120
+ targetSessionKey,
121
+ agentId,
122
+ label,
123
+ webhookId,
124
+ webhookToken,
125
+ boundBy,
126
+ boundAt,
127
+ expiresAt,
128
+ };
129
+ }
130
+ export function normalizeThreadBindingTtlMs(raw) {
131
+ if (typeof raw !== "number" || !Number.isFinite(raw)) {
132
+ return DEFAULT_THREAD_BINDING_TTL_MS;
133
+ }
134
+ const ttlMs = Math.floor(raw);
135
+ if (ttlMs < 0) {
136
+ return DEFAULT_THREAD_BINDING_TTL_MS;
137
+ }
138
+ return ttlMs;
139
+ }
140
+ export function resolveThreadBindingExpiresAt(params) {
141
+ if (typeof params.record.expiresAt === "number" && Number.isFinite(params.record.expiresAt)) {
142
+ const explicitExpiresAt = Math.floor(params.record.expiresAt);
143
+ if (explicitExpiresAt <= 0) {
144
+ // 0 is an explicit per-binding TTL disable sentinel.
145
+ return undefined;
146
+ }
147
+ return explicitExpiresAt;
148
+ }
149
+ if (params.sessionTtlMs <= 0) {
150
+ return undefined;
151
+ }
152
+ const boundAt = Math.floor(params.record.boundAt);
153
+ if (!Number.isFinite(boundAt) || boundAt <= 0) {
154
+ return undefined;
155
+ }
156
+ return boundAt + params.sessionTtlMs;
157
+ }
158
+ function linkSessionBinding(targetSessionKey, bindingKey) {
159
+ const key = targetSessionKey.trim();
160
+ if (!key) {
161
+ return;
162
+ }
163
+ const threads = BINDINGS_BY_SESSION_KEY.get(key) ?? new Set();
164
+ threads.add(bindingKey);
165
+ BINDINGS_BY_SESSION_KEY.set(key, threads);
166
+ }
167
+ function unlinkSessionBinding(targetSessionKey, bindingKey) {
168
+ const key = targetSessionKey.trim();
169
+ if (!key) {
170
+ return;
171
+ }
172
+ const threads = BINDINGS_BY_SESSION_KEY.get(key);
173
+ if (!threads) {
174
+ return;
175
+ }
176
+ threads.delete(bindingKey);
177
+ if (threads.size === 0) {
178
+ BINDINGS_BY_SESSION_KEY.delete(key);
179
+ }
180
+ }
181
+ export function toReusableWebhookKey(params) {
182
+ return `${params.accountId.trim().toLowerCase()}:${params.channelId.trim()}`;
183
+ }
184
+ export function rememberReusableWebhook(record) {
185
+ const webhookId = record.webhookId?.trim();
186
+ const webhookToken = record.webhookToken?.trim();
187
+ if (!webhookId || !webhookToken) {
188
+ return;
189
+ }
190
+ const key = toReusableWebhookKey({
191
+ accountId: record.accountId,
192
+ channelId: record.channelId,
193
+ });
194
+ REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL.set(key, { webhookId, webhookToken });
195
+ }
196
+ export function rememberRecentUnboundWebhookEcho(record) {
197
+ const webhookId = record.webhookId?.trim();
198
+ if (!webhookId) {
199
+ return;
200
+ }
201
+ const bindingKey = resolveBindingRecordKey({
202
+ accountId: record.accountId,
203
+ threadId: record.threadId,
204
+ });
205
+ if (!bindingKey) {
206
+ return;
207
+ }
208
+ RECENT_UNBOUND_WEBHOOK_ECHOES_BY_BINDING_KEY.set(bindingKey, {
209
+ webhookId,
210
+ expiresAt: Date.now() + RECENT_UNBOUND_WEBHOOK_ECHO_TTL_MS,
211
+ });
212
+ }
213
+ function clearRecentUnboundWebhookEcho(bindingKeyRaw) {
214
+ const key = bindingKeyRaw.trim();
215
+ if (!key) {
216
+ return;
217
+ }
218
+ RECENT_UNBOUND_WEBHOOK_ECHOES_BY_BINDING_KEY.delete(key);
219
+ }
220
+ export function setBindingRecord(record) {
221
+ const bindingKey = toBindingRecordKey({
222
+ accountId: record.accountId,
223
+ threadId: record.threadId,
224
+ });
225
+ const existing = BINDINGS_BY_THREAD_ID.get(bindingKey);
226
+ if (existing) {
227
+ unlinkSessionBinding(existing.targetSessionKey, bindingKey);
228
+ }
229
+ BINDINGS_BY_THREAD_ID.set(bindingKey, record);
230
+ linkSessionBinding(record.targetSessionKey, bindingKey);
231
+ clearRecentUnboundWebhookEcho(bindingKey);
232
+ rememberReusableWebhook(record);
233
+ }
234
+ export function removeBindingRecord(bindingKeyRaw) {
235
+ const key = bindingKeyRaw.trim();
236
+ if (!key) {
237
+ return null;
238
+ }
239
+ const existing = BINDINGS_BY_THREAD_ID.get(key);
240
+ if (!existing) {
241
+ return null;
242
+ }
243
+ BINDINGS_BY_THREAD_ID.delete(key);
244
+ unlinkSessionBinding(existing.targetSessionKey, key);
245
+ return existing;
246
+ }
247
+ export function isRecentlyUnboundThreadWebhookMessage(params) {
248
+ const webhookId = params.webhookId?.trim() || "";
249
+ if (!webhookId) {
250
+ return false;
251
+ }
252
+ const bindingKey = resolveBindingRecordKey({
253
+ accountId: params.accountId,
254
+ threadId: params.threadId,
255
+ });
256
+ if (!bindingKey) {
257
+ return false;
258
+ }
259
+ const suppressed = RECENT_UNBOUND_WEBHOOK_ECHOES_BY_BINDING_KEY.get(bindingKey);
260
+ if (!suppressed) {
261
+ return false;
262
+ }
263
+ if (suppressed.expiresAt <= Date.now()) {
264
+ RECENT_UNBOUND_WEBHOOK_ECHOES_BY_BINDING_KEY.delete(bindingKey);
265
+ return false;
266
+ }
267
+ return suppressed.webhookId === webhookId;
268
+ }
269
+ function shouldPersistAnyBindingState() {
270
+ for (const value of PERSIST_BY_ACCOUNT_ID.values()) {
271
+ if (value) {
272
+ return true;
273
+ }
274
+ }
275
+ return false;
276
+ }
277
+ export function shouldPersistBindingMutations() {
278
+ if (shouldPersistAnyBindingState()) {
279
+ return true;
280
+ }
281
+ return fs.existsSync(resolveThreadBindingsPath());
282
+ }
283
+ export function saveBindingsToDisk(params = {}) {
284
+ if (!params.force && !shouldPersistAnyBindingState()) {
285
+ return;
286
+ }
287
+ const bindings = {};
288
+ for (const [bindingKey, record] of BINDINGS_BY_THREAD_ID.entries()) {
289
+ bindings[bindingKey] = { ...record };
290
+ }
291
+ const payload = {
292
+ version: THREAD_BINDINGS_VERSION,
293
+ bindings,
294
+ };
295
+ saveJsonFile(resolveThreadBindingsPath(), payload);
296
+ }
297
+ export function ensureBindingsLoaded() {
298
+ if (THREAD_BINDINGS_STATE.loadedBindings) {
299
+ return;
300
+ }
301
+ THREAD_BINDINGS_STATE.loadedBindings = true;
302
+ BINDINGS_BY_THREAD_ID.clear();
303
+ BINDINGS_BY_SESSION_KEY.clear();
304
+ REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL.clear();
305
+ const raw = loadJsonFile(resolveThreadBindingsPath());
306
+ if (!raw || typeof raw !== "object") {
307
+ return;
308
+ }
309
+ const payload = raw;
310
+ if (payload.version !== 1 || !payload.bindings || typeof payload.bindings !== "object") {
311
+ return;
312
+ }
313
+ for (const [threadId, entry] of Object.entries(payload.bindings)) {
314
+ const normalized = normalizePersistedBinding(threadId, entry);
315
+ if (!normalized) {
316
+ continue;
317
+ }
318
+ setBindingRecord(normalized);
319
+ }
320
+ }
321
+ export function resolveBindingIdsForSession(params) {
322
+ const key = params.targetSessionKey.trim();
323
+ if (!key) {
324
+ return [];
325
+ }
326
+ const ids = BINDINGS_BY_SESSION_KEY.get(key);
327
+ if (!ids) {
328
+ return [];
329
+ }
330
+ const out = [];
331
+ for (const bindingKey of ids.values()) {
332
+ const record = BINDINGS_BY_THREAD_ID.get(bindingKey);
333
+ if (!record) {
334
+ continue;
335
+ }
336
+ if (params.accountId && record.accountId !== params.accountId) {
337
+ continue;
338
+ }
339
+ if (params.targetKind && record.targetKind !== params.targetKind) {
340
+ continue;
341
+ }
342
+ out.push(bindingKey);
343
+ }
344
+ return out;
345
+ }
346
+ export function resetThreadBindingsForTests() {
347
+ for (const manager of MANAGERS_BY_ACCOUNT_ID.values()) {
348
+ manager.stop();
349
+ }
350
+ MANAGERS_BY_ACCOUNT_ID.clear();
351
+ BINDINGS_BY_THREAD_ID.clear();
352
+ BINDINGS_BY_SESSION_KEY.clear();
353
+ RECENT_UNBOUND_WEBHOOK_ECHOES_BY_BINDING_KEY.clear();
354
+ REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL.clear();
355
+ TOKENS_BY_ACCOUNT_ID.clear();
356
+ PERSIST_BY_ACCOUNT_ID.clear();
357
+ THREAD_BINDINGS_STATE.loadedBindings = false;
358
+ }
@@ -0,0 +1,6 @@
1
+ export const THREAD_BINDINGS_VERSION = 1;
2
+ export const THREAD_BINDINGS_SWEEP_INTERVAL_MS = 120_000;
3
+ export const DEFAULT_THREAD_BINDING_TTL_MS = 24 * 60 * 60 * 1000; // 24h
4
+ export const DEFAULT_FAREWELL_TEXT = "Session ended. Messages here will no longer be routed.";
5
+ export const DISCORD_UNKNOWN_CHANNEL_ERROR_CODE = 10_003;
6
+ export const RECENT_UNBOUND_WEBHOOK_ECHO_TTL_MS = 30_000;
@@ -1,34 +1,31 @@
1
1
  import { fetchDiscord } from "./api.js";
2
+ import { listGuilds } from "./guilds.js";
2
3
  import { normalizeDiscordSlug } from "./monitor/allow-list.js";
3
4
  import { normalizeDiscordToken } from "./token.js";
4
5
  function parseDiscordUserInput(raw) {
5
6
  const trimmed = raw.trim();
6
- if (!trimmed)
7
+ if (!trimmed) {
7
8
  return {};
9
+ }
8
10
  const mention = trimmed.match(/^<@!?(\d+)>$/);
9
- if (mention)
11
+ if (mention) {
10
12
  return { userId: mention[1] };
13
+ }
11
14
  const prefixed = trimmed.match(/^(?:user:|discord:)?(\d+)$/i);
12
- if (prefixed)
15
+ if (prefixed) {
13
16
  return { userId: prefixed[1] };
17
+ }
14
18
  const split = trimmed.includes("/") ? trimmed.split("/") : trimmed.split("#");
15
19
  if (split.length >= 2) {
16
20
  const guild = split[0]?.trim();
17
21
  const user = split.slice(1).join("#").trim();
18
- if (guild && /^\d+$/.test(guild))
22
+ if (guild && /^\d+$/.test(guild)) {
19
23
  return { guildId: guild, userName: user };
24
+ }
20
25
  return { guildName: guild, userName: user };
21
26
  }
22
27
  return { userName: trimmed.replace(/^@/, "") };
23
28
  }
24
- async function listGuilds(token, fetcher) {
25
- const raw = await fetchDiscord("/users/@me/guilds", token, fetcher);
26
- return raw.map((guild) => ({
27
- id: guild.id,
28
- name: guild.name,
29
- slug: normalizeDiscordSlug(guild.name),
30
- }));
31
- }
32
29
  function scoreDiscordMember(member, query) {
33
30
  const q = query.toLowerCase();
34
31
  const user = member.user;
@@ -36,23 +33,36 @@ function scoreDiscordMember(member, query) {
36
33
  .map((value) => value?.toLowerCase())
37
34
  .filter(Boolean);
38
35
  let score = 0;
39
- if (candidates.some((value) => value === q))
36
+ if (candidates.some((value) => value === q)) {
40
37
  score += 3;
41
- if (candidates.some((value) => value?.includes(q)))
38
+ }
39
+ if (candidates.some((value) => value?.includes(q))) {
42
40
  score += 1;
43
- if (!user.bot)
41
+ }
42
+ if (!user.bot) {
44
43
  score += 1;
44
+ }
45
45
  return score;
46
46
  }
47
47
  export async function resolveDiscordUserAllowlist(params) {
48
48
  const token = normalizeDiscordToken(params.token);
49
- if (!token)
49
+ if (!token) {
50
50
  return params.entries.map((input) => ({
51
51
  input,
52
52
  resolved: false,
53
53
  }));
54
+ }
54
55
  const fetcher = params.fetcher ?? fetch;
55
- const guilds = await listGuilds(token, fetcher);
56
+ // Lazy-load guilds: only fetch when an entry actually needs username search.
57
+ // This prevents listGuilds() failures (permissions, network) from blocking
58
+ // resolution of plain user-id entries that don't need guild data at all.
59
+ let guilds = null;
60
+ const getGuilds = async () => {
61
+ if (!guilds) {
62
+ guilds = await listGuilds(token, fetcher);
63
+ }
64
+ return guilds;
65
+ };
56
66
  const results = [];
57
67
  for (const input of params.entries) {
58
68
  const parsed = parseDiscordUserInput(input);
@@ -70,11 +80,12 @@ export async function resolveDiscordUserAllowlist(params) {
70
80
  continue;
71
81
  }
72
82
  const guildName = parsed.guildName?.trim();
83
+ const allGuilds = await getGuilds();
73
84
  const guildList = parsed.guildId
74
- ? guilds.filter((g) => g.id === parsed.guildId)
85
+ ? allGuilds.filter((g) => g.id === parsed.guildId)
75
86
  : guildName
76
- ? guilds.filter((g) => g.slug === normalizeDiscordSlug(guildName))
77
- : guilds;
87
+ ? allGuilds.filter((g) => g.slug === normalizeDiscordSlug(guildName))
88
+ : allGuilds;
78
89
  let best = null;
79
90
  let matches = 0;
80
91
  for (const guild of guildList) {
@@ -85,8 +96,9 @@ export async function resolveDiscordUserAllowlist(params) {
85
96
  const members = await fetchDiscord(`/guilds/${guild.id}/members/search?${paramsObj.toString()}`, token, fetcher);
86
97
  for (const member of members) {
87
98
  const score = scoreDiscordMember(member, query);
88
- if (score === 0)
99
+ if (score === 0) {
89
100
  continue;
101
+ }
90
102
  matches += 1;
91
103
  if (!best || score > best.score) {
92
104
  best = { member, guild, score };
@@ -34,6 +34,21 @@ export async function editChannelDiscord(payload, opts = {}) {
34
34
  body.nsfw = payload.nsfw;
35
35
  if (payload.rateLimitPerUser !== undefined)
36
36
  body.rate_limit_per_user = payload.rateLimitPerUser;
37
+ if (payload.archived !== undefined)
38
+ body.archived = payload.archived;
39
+ if (payload.locked !== undefined)
40
+ body.locked = payload.locked;
41
+ if (payload.autoArchiveDuration !== undefined)
42
+ body.auto_archive_duration = payload.autoArchiveDuration;
43
+ if (payload.availableTags !== undefined) {
44
+ body.available_tags = payload.availableTags.map((t) => ({
45
+ ...(t.id !== undefined && { id: t.id }),
46
+ name: t.name,
47
+ ...(t.moderated !== undefined && { moderated: t.moderated }),
48
+ ...(t.emoji_id !== undefined && { emoji_id: t.emoji_id }),
49
+ ...(t.emoji_name !== undefined && { emoji_name: t.emoji_name }),
50
+ }));
51
+ }
37
52
  return (await rest.patch(Routes.channel(payload.channelId), {
38
53
  body,
39
54
  }));
@@ -2,7 +2,8 @@ export { createChannelDiscord, deleteChannelDiscord, editChannelDiscord, moveCha
2
2
  export { listGuildEmojisDiscord, uploadEmojiDiscord, uploadStickerDiscord, } from "./send.emojis-stickers.js";
3
3
  export { addRoleDiscord, banMemberDiscord, createScheduledEventDiscord, fetchChannelInfoDiscord, fetchMemberInfoDiscord, fetchRoleInfoDiscord, fetchVoiceStatusDiscord, kickMemberDiscord, listGuildChannelsDiscord, listScheduledEventsDiscord, removeRoleDiscord, timeoutMemberDiscord, } from "./send.guild.js";
4
4
  export { createThreadDiscord, deleteMessageDiscord, editMessageDiscord, fetchMessageDiscord, listPinsDiscord, listThreadsDiscord, pinMessageDiscord, readMessagesDiscord, searchMessagesDiscord, unpinMessageDiscord, } from "./send.messages.js";
5
- export { sendMessageDiscord, sendPollDiscord, sendStickerDiscord, sendVoiceMessageDiscord, } from "./send.outbound.js";
5
+ export { sendMessageDiscord, sendPollDiscord, sendStickerDiscord, sendWebhookMessageDiscord, sendVoiceMessageDiscord, } from "./send.outbound.js";
6
6
  export { sendDiscordComponentMessage } from "./send.components.js";
7
- export { fetchChannelPermissionsDiscord, fetchReactionsDiscord, reactMessageDiscord, removeOwnReactionsDiscord, removeReactionDiscord, } from "./send.reactions.js";
7
+ export { fetchChannelPermissionsDiscord, hasAllGuildPermissionsDiscord, hasAnyGuildPermissionDiscord, fetchMemberGuildPermissionsDiscord, } from "./send.permissions.js";
8
+ export { fetchReactionsDiscord, reactMessageDiscord, removeOwnReactionsDiscord, removeReactionDiscord, } from "./send.reactions.js";
8
9
  export { DiscordSendError } from "./send.types.js";
@@ -29,6 +29,19 @@ function deriveForumThreadName(text) {
29
29
  function isForumLikeType(channelType) {
30
30
  return channelType === ChannelType.GuildForum || channelType === ChannelType.GuildMedia;
31
31
  }
32
+ function toDiscordSendResult(result, fallbackChannelId) {
33
+ return {
34
+ messageId: result.id ? String(result.id) : "unknown",
35
+ channelId: String(result.channel_id ?? fallbackChannelId),
36
+ };
37
+ }
38
+ async function resolveDiscordSendTarget(to, opts) {
39
+ const cfg = loadConfig();
40
+ const { rest, request } = createDiscordClient(opts, cfg);
41
+ const recipient = await parseAndResolveRecipient(to, opts.accountId);
42
+ const { channelId } = await resolveChannelId(rest, recipient, request);
43
+ return { rest, request, channelId };
44
+ }
32
45
  export async function sendMessageDiscord(to, text, opts = {}) {
33
46
  const cfg = loadConfig();
34
47
  const accountInfo = resolveDiscordAccount({
@@ -122,10 +135,10 @@ export async function sendMessageDiscord(to, text, opts = {}) {
122
135
  accountId: accountInfo.accountId,
123
136
  direction: "outbound",
124
137
  });
125
- return {
126
- messageId: messageId ? String(messageId) : "unknown",
127
- channelId: String(resultChannelId ?? channelId),
128
- };
138
+ return toDiscordSendResult({
139
+ id: messageId,
140
+ channel_id: resultChannelId,
141
+ }, channelId);
129
142
  }
130
143
  let result;
131
144
  try {
@@ -149,16 +162,71 @@ export async function sendMessageDiscord(to, text, opts = {}) {
149
162
  accountId: accountInfo.accountId,
150
163
  direction: "outbound",
151
164
  });
165
+ return toDiscordSendResult(result, channelId);
166
+ }
167
+ function resolveWebhookExecutionUrl(params) {
168
+ const baseUrl = new URL(`https://discord.com/api/v10/webhooks/${encodeURIComponent(params.webhookId)}/${encodeURIComponent(params.webhookToken)}`);
169
+ baseUrl.searchParams.set("wait", params.wait === false ? "false" : "true");
170
+ if (params.threadId !== undefined && params.threadId !== null && params.threadId !== "") {
171
+ baseUrl.searchParams.set("thread_id", String(params.threadId));
172
+ }
173
+ return baseUrl.toString();
174
+ }
175
+ export async function sendWebhookMessageDiscord(text, opts) {
176
+ const webhookId = opts.webhookId.trim();
177
+ const webhookToken = opts.webhookToken.trim();
178
+ if (!webhookId || !webhookToken) {
179
+ throw new Error("Discord webhook id/token are required");
180
+ }
181
+ const replyTo = typeof opts.replyTo === "string" ? opts.replyTo.trim() : "";
182
+ const messageReference = replyTo ? { message_id: replyTo, fail_if_not_exists: false } : undefined;
183
+ const response = await fetch(resolveWebhookExecutionUrl({
184
+ webhookId,
185
+ webhookToken,
186
+ threadId: opts.threadId,
187
+ wait: opts.wait,
188
+ }), {
189
+ method: "POST",
190
+ headers: {
191
+ "content-type": "application/json",
192
+ },
193
+ body: JSON.stringify({
194
+ content: text,
195
+ username: opts.username?.trim() || undefined,
196
+ avatar_url: opts.avatarUrl?.trim() || undefined,
197
+ ...(messageReference ? { message_reference: messageReference } : {}),
198
+ }),
199
+ });
200
+ if (!response.ok) {
201
+ const raw = await response.text().catch(() => "");
202
+ throw new Error(`Discord webhook send failed (${response.status}${raw ? `: ${raw.slice(0, 200)}` : ""})`);
203
+ }
204
+ const payload = (await response.json().catch(() => ({})));
205
+ try {
206
+ const account = resolveDiscordAccount({
207
+ cfg: loadConfig(),
208
+ accountId: opts.accountId,
209
+ });
210
+ recordChannelActivity({
211
+ channel: "discord",
212
+ accountId: account.accountId,
213
+ direction: "outbound",
214
+ });
215
+ }
216
+ catch {
217
+ // Best-effort telemetry only.
218
+ }
152
219
  return {
153
- messageId: result.id ? String(result.id) : "unknown",
154
- channelId: String(result.channel_id ?? channelId),
220
+ messageId: payload.id ? String(payload.id) : "unknown",
221
+ channelId: payload.channel_id
222
+ ? String(payload.channel_id)
223
+ : opts.threadId
224
+ ? String(opts.threadId)
225
+ : "",
155
226
  };
156
227
  }
157
228
  export async function sendStickerDiscord(to, stickerIds, opts = {}) {
158
- const cfg = loadConfig();
159
- const { rest, request } = createDiscordClient(opts, cfg);
160
- const recipient = await parseAndResolveRecipient(to, opts.accountId);
161
- const { channelId } = await resolveChannelId(rest, recipient, request);
229
+ const { rest, request, channelId } = await resolveDiscordSendTarget(to, opts);
162
230
  const content = opts.content?.trim();
163
231
  const stickers = normalizeStickerIds(stickerIds);
164
232
  const res = (await request(() => rest.post(Routes.channelMessages(channelId), {
@@ -167,16 +235,10 @@ export async function sendStickerDiscord(to, stickerIds, opts = {}) {
167
235
  sticker_ids: stickers,
168
236
  },
169
237
  }), "sticker"));
170
- return {
171
- messageId: res.id ? String(res.id) : "unknown",
172
- channelId: String(res.channel_id ?? channelId),
173
- };
238
+ return toDiscordSendResult(res, channelId);
174
239
  }
175
240
  export async function sendPollDiscord(to, poll, opts = {}) {
176
- const cfg = loadConfig();
177
- const { rest, request } = createDiscordClient(opts, cfg);
178
- const recipient = await parseAndResolveRecipient(to, opts.accountId);
179
- const { channelId } = await resolveChannelId(rest, recipient, request);
241
+ const { rest, request, channelId } = await resolveDiscordSendTarget(to, opts);
180
242
  const content = opts.content?.trim();
181
243
  if (poll.durationSeconds !== undefined) {
182
244
  throw new Error("Discord polls do not support durationSeconds; use durationHours");
@@ -190,10 +252,7 @@ export async function sendPollDiscord(to, poll, opts = {}) {
190
252
  ...(flags ? { flags } : {}),
191
253
  },
192
254
  }), "poll"));
193
- return {
194
- messageId: res.id ? String(res.id) : "unknown",
195
- channelId: String(res.channel_id ?? channelId),
196
- };
255
+ return toDiscordSendResult(res, channelId);
197
256
  }
198
257
  async function materializeVoiceMessageInput(mediaUrl) {
199
258
  // Security: reuse the standard media loader so we apply SSRF guards + allowed-local-root checks.
@@ -251,10 +310,7 @@ export async function sendVoiceMessageDiscord(to, audioPath, opts = {}) {
251
310
  accountId: accountInfo.accountId,
252
311
  direction: "outbound",
253
312
  });
254
- return {
255
- messageId: result.id ? String(result.id) : "unknown",
256
- channelId: String(result.channel_id ?? channelId),
257
- };
313
+ return toDiscordSendResult(result, channelId);
258
314
  }
259
315
  catch (err) {
260
316
  if (channelId && rest && token) {