@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
@@ -0,0 +1,100 @@
1
+ import { danger } from "../../globals.js";
2
+ import { attachDiscordGatewayLogging } from "../gateway-logging.js";
3
+ import { getDiscordGatewayEmitter, waitForDiscordGatewayStop } from "../monitor.gateway.js";
4
+ import { registerGateway, unregisterGateway } from "./gateway-registry.js";
5
+ export async function runDiscordGatewayLifecycle(params) {
6
+ const gateway = params.client.getPlugin("gateway");
7
+ if (gateway) {
8
+ registerGateway(params.accountId, gateway);
9
+ }
10
+ const gatewayEmitter = getDiscordGatewayEmitter(gateway);
11
+ const stopGatewayLogging = attachDiscordGatewayLogging({
12
+ emitter: gatewayEmitter,
13
+ runtime: params.runtime,
14
+ });
15
+ const onAbort = () => {
16
+ if (!gateway) {
17
+ return;
18
+ }
19
+ gatewayEmitter?.once("error", () => { });
20
+ gateway.options.reconnect = { maxAttempts: 0 };
21
+ gateway.disconnect();
22
+ };
23
+ if (params.abortSignal?.aborted) {
24
+ onAbort();
25
+ }
26
+ else {
27
+ params.abortSignal?.addEventListener("abort", onAbort, { once: true });
28
+ }
29
+ const HELLO_TIMEOUT_MS = 30000;
30
+ let helloTimeoutId;
31
+ const onGatewayDebug = (msg) => {
32
+ const message = String(msg);
33
+ if (!message.includes("WebSocket connection opened")) {
34
+ return;
35
+ }
36
+ if (helloTimeoutId) {
37
+ clearTimeout(helloTimeoutId);
38
+ }
39
+ helloTimeoutId = setTimeout(() => {
40
+ if (!gateway?.isConnected) {
41
+ params.runtime.log?.(danger(`connection stalled: no HELLO received within ${HELLO_TIMEOUT_MS}ms, forcing reconnect`));
42
+ gateway?.disconnect();
43
+ gateway?.connect(false);
44
+ }
45
+ helloTimeoutId = undefined;
46
+ }, HELLO_TIMEOUT_MS);
47
+ };
48
+ gatewayEmitter?.on("debug", onGatewayDebug);
49
+ let sawDisallowedIntents = false;
50
+ try {
51
+ if (params.execApprovalsHandler) {
52
+ await params.execApprovalsHandler.start();
53
+ }
54
+ await waitForDiscordGatewayStop({
55
+ gateway: gateway
56
+ ? {
57
+ emitter: gatewayEmitter,
58
+ disconnect: () => gateway.disconnect(),
59
+ }
60
+ : undefined,
61
+ abortSignal: params.abortSignal,
62
+ onGatewayError: (err) => {
63
+ if (params.isDisallowedIntentsError(err)) {
64
+ sawDisallowedIntents = true;
65
+ params.runtime.error?.(danger("discord: gateway closed with code 4014 (missing privileged gateway intents). Enable the required intents in the Discord Developer Portal or disable them in config."));
66
+ return;
67
+ }
68
+ params.runtime.error?.(danger(`discord gateway error: ${String(err)}`));
69
+ },
70
+ shouldStopOnError: (err) => {
71
+ const message = String(err);
72
+ return (message.includes("Max reconnect attempts") ||
73
+ message.includes("Fatal Gateway error") ||
74
+ params.isDisallowedIntentsError(err));
75
+ },
76
+ });
77
+ }
78
+ catch (err) {
79
+ if (!sawDisallowedIntents && !params.isDisallowedIntentsError(err)) {
80
+ throw err;
81
+ }
82
+ }
83
+ finally {
84
+ unregisterGateway(params.accountId);
85
+ stopGatewayLogging();
86
+ if (helloTimeoutId) {
87
+ clearTimeout(helloTimeoutId);
88
+ }
89
+ gatewayEmitter?.removeListener("debug", onGatewayDebug);
90
+ params.abortSignal?.removeEventListener("abort", onAbort);
91
+ if (params.voiceManager) {
92
+ await params.voiceManager.destroy();
93
+ params.voiceManagerRef.current = null;
94
+ }
95
+ if (params.execApprovalsHandler) {
96
+ await params.execApprovalsHandler.stop();
97
+ }
98
+ params.threadBindings.stop();
99
+ }
100
+ }
@@ -1,8 +1,104 @@
1
+ import { resolveAgentAvatar } from "../../agents/identity-avatar.js";
2
+ import { loadConfig } from "../../config/config.js";
1
3
  import { convertMarkdownTables } from "../../markdown/tables.js";
2
4
  import { chunkDiscordTextWithMode } from "../chunk.js";
3
- import { sendMessageDiscord, sendVoiceMessageDiscord } from "../send.js";
5
+ import { sendMessageDiscord, sendVoiceMessageDiscord, sendWebhookMessageDiscord } from "../send.js";
6
+ function resolveTargetChannelId(target) {
7
+ if (!target.startsWith("channel:")) {
8
+ return undefined;
9
+ }
10
+ const channelId = target.slice("channel:".length).trim();
11
+ return channelId || undefined;
12
+ }
13
+ function resolveBoundThreadBinding(params) {
14
+ const sessionKey = params.sessionKey?.trim();
15
+ if (!params.threadBindings || !sessionKey) {
16
+ return undefined;
17
+ }
18
+ const bindings = params.threadBindings.listBySessionKey(sessionKey);
19
+ if (bindings.length === 0) {
20
+ return undefined;
21
+ }
22
+ const targetChannelId = resolveTargetChannelId(params.target);
23
+ if (!targetChannelId) {
24
+ return undefined;
25
+ }
26
+ return bindings.find((entry) => entry.threadId === targetChannelId);
27
+ }
28
+ function resolveBindingPersona(binding) {
29
+ if (!binding) {
30
+ return {};
31
+ }
32
+ const baseLabel = binding.label?.trim() || binding.agentId;
33
+ const username = (`🤖 ${baseLabel}`.trim() || "🤖 agent").slice(0, 80);
34
+ let avatarUrl;
35
+ try {
36
+ const avatar = resolveAgentAvatar(loadConfig(), binding.agentId);
37
+ if (avatar.kind === "remote") {
38
+ avatarUrl = avatar.url;
39
+ }
40
+ }
41
+ catch {
42
+ avatarUrl = undefined;
43
+ }
44
+ return { username, avatarUrl };
45
+ }
46
+ async function sendDiscordChunkWithFallback(params) {
47
+ const text = params.text.trim();
48
+ if (!text) {
49
+ return;
50
+ }
51
+ const binding = params.binding;
52
+ if (binding?.webhookId && binding?.webhookToken) {
53
+ try {
54
+ await sendWebhookMessageDiscord(text, {
55
+ webhookId: binding.webhookId,
56
+ webhookToken: binding.webhookToken,
57
+ accountId: binding.accountId,
58
+ threadId: binding.threadId,
59
+ replyTo: params.replyTo,
60
+ username: params.username,
61
+ avatarUrl: params.avatarUrl,
62
+ });
63
+ return;
64
+ }
65
+ catch {
66
+ // Fall through to the standard bot sender path.
67
+ }
68
+ }
69
+ await sendMessageDiscord(params.target, text, {
70
+ token: params.token,
71
+ rest: params.rest,
72
+ accountId: params.accountId,
73
+ replyTo: params.replyTo,
74
+ });
75
+ }
4
76
  export async function deliverDiscordReply(params) {
5
77
  const chunkLimit = Math.min(params.textLimit, 2000);
78
+ const replyTo = params.replyToId?.trim() || undefined;
79
+ const replyToMode = params.replyToMode ?? "all";
80
+ // replyToMode=first should only apply to the first physical send.
81
+ const replyOnce = replyToMode === "first";
82
+ let replyUsed = false;
83
+ const resolveReplyTo = () => {
84
+ if (!replyTo) {
85
+ return undefined;
86
+ }
87
+ if (!replyOnce) {
88
+ return replyTo;
89
+ }
90
+ if (replyUsed) {
91
+ return undefined;
92
+ }
93
+ replyUsed = true;
94
+ return replyTo;
95
+ };
96
+ const binding = resolveBoundThreadBinding({
97
+ threadBindings: params.threadBindings,
98
+ sessionKey: params.sessionKey,
99
+ target: params.target,
100
+ });
101
+ const persona = resolveBindingPersona(binding);
6
102
  for (const payload of params.replies) {
7
103
  const mediaList = payload.mediaUrls ?? (payload.mediaUrl ? [payload.mediaUrl] : []);
8
104
  const rawText = payload.text ?? "";
@@ -11,7 +107,6 @@ export async function deliverDiscordReply(params) {
11
107
  if (!text && mediaList.length === 0) {
12
108
  continue;
13
109
  }
14
- const replyTo = params.replyToId?.trim() || undefined;
15
110
  if (mediaList.length === 0) {
16
111
  const mode = params.chunkMode ?? "length";
17
112
  const chunks = chunkDiscordTextWithMode(text, {
@@ -23,15 +118,20 @@ export async function deliverDiscordReply(params) {
23
118
  chunks.push(text);
24
119
  }
25
120
  for (const chunk of chunks) {
26
- const trimmed = chunk.trim();
27
- if (!trimmed) {
121
+ if (!chunk.trim()) {
28
122
  continue;
29
123
  }
30
- await sendMessageDiscord(params.target, trimmed, {
124
+ const replyTo = resolveReplyTo();
125
+ await sendDiscordChunkWithFallback({
126
+ target: params.target,
127
+ text: chunk,
31
128
  token: params.token,
32
129
  rest: params.rest,
33
130
  accountId: params.accountId,
34
131
  replyTo,
132
+ binding,
133
+ username: persona.username,
134
+ avatarUrl: persona.avatarUrl,
35
135
  });
36
136
  }
37
137
  continue;
@@ -40,25 +140,30 @@ export async function deliverDiscordReply(params) {
40
140
  if (!firstMedia) {
41
141
  continue;
42
142
  }
43
- // Voice message path: audioAsVoice flag routes through sendVoiceMessageDiscord
143
+ // Voice message path: audioAsVoice flag routes through sendVoiceMessageDiscord.
44
144
  if (payload.audioAsVoice) {
145
+ const replyTo = resolveReplyTo();
45
146
  await sendVoiceMessageDiscord(params.target, firstMedia, {
46
147
  token: params.token,
47
148
  rest: params.rest,
48
149
  accountId: params.accountId,
49
150
  replyTo,
50
151
  });
51
- // Voice messages cannot include text; send remaining text separately if present
52
- if (text.trim()) {
53
- await sendMessageDiscord(params.target, text, {
54
- token: params.token,
55
- rest: params.rest,
56
- accountId: params.accountId,
57
- replyTo,
58
- });
59
- }
60
- // Additional media items are sent as regular attachments (voice is single-file only)
152
+ // Voice messages cannot include text; send remaining text separately if present.
153
+ await sendDiscordChunkWithFallback({
154
+ target: params.target,
155
+ text,
156
+ token: params.token,
157
+ rest: params.rest,
158
+ accountId: params.accountId,
159
+ replyTo: resolveReplyTo(),
160
+ binding,
161
+ username: persona.username,
162
+ avatarUrl: persona.avatarUrl,
163
+ });
164
+ // Additional media items are sent as regular attachments (voice is single-file only).
61
165
  for (const extra of mediaList.slice(1)) {
166
+ const replyTo = resolveReplyTo();
62
167
  await sendMessageDiscord(params.target, "", {
63
168
  token: params.token,
64
169
  rest: params.rest,
@@ -69,6 +174,7 @@ export async function deliverDiscordReply(params) {
69
174
  }
70
175
  continue;
71
176
  }
177
+ const replyTo = resolveReplyTo();
72
178
  await sendMessageDiscord(params.target, text, {
73
179
  token: params.token,
74
180
  rest: params.rest,
@@ -77,6 +183,7 @@ export async function deliverDiscordReply(params) {
77
183
  replyTo,
78
184
  });
79
185
  for (const extra of mediaList.slice(1)) {
186
+ const replyTo = resolveReplyTo();
80
187
  await sendMessageDiscord(params.target, "", {
81
188
  token: params.token,
82
189
  rest: params.rest,
@@ -0,0 +1,215 @@
1
+ import { ChannelType, Routes } from "discord-api-types/v10";
2
+ import { logVerbose } from "../../globals.js";
3
+ import { createDiscordRestClient } from "../client.js";
4
+ import { sendMessageDiscord, sendWebhookMessageDiscord } from "../send.js";
5
+ import { createThreadDiscord } from "../send.messages.js";
6
+ import { summarizeBindingPersona } from "./thread-bindings.messages.js";
7
+ import { BINDINGS_BY_THREAD_ID, REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL, rememberReusableWebhook, toReusableWebhookKey, } from "./thread-bindings.state.js";
8
+ import { DISCORD_UNKNOWN_CHANNEL_ERROR_CODE, } from "./thread-bindings.types.js";
9
+ function buildThreadTarget(threadId) {
10
+ return `channel:${threadId}`;
11
+ }
12
+ export function isThreadArchived(raw) {
13
+ if (!raw || typeof raw !== "object") {
14
+ return false;
15
+ }
16
+ const asRecord = raw;
17
+ if (asRecord.archived === true) {
18
+ return true;
19
+ }
20
+ if (asRecord.thread_metadata?.archived === true) {
21
+ return true;
22
+ }
23
+ if (asRecord.threadMetadata?.archived === true) {
24
+ return true;
25
+ }
26
+ return false;
27
+ }
28
+ function isThreadChannelType(type) {
29
+ return (type === ChannelType.PublicThread ||
30
+ type === ChannelType.PrivateThread ||
31
+ type === ChannelType.AnnouncementThread);
32
+ }
33
+ export function summarizeDiscordError(err) {
34
+ if (err instanceof Error) {
35
+ return err.message;
36
+ }
37
+ if (typeof err === "string") {
38
+ return err;
39
+ }
40
+ if (typeof err === "number" ||
41
+ typeof err === "boolean" ||
42
+ typeof err === "bigint" ||
43
+ typeof err === "symbol") {
44
+ return String(err);
45
+ }
46
+ return "error";
47
+ }
48
+ function extractNumericDiscordErrorValue(value) {
49
+ if (typeof value === "number" && Number.isFinite(value)) {
50
+ return Math.trunc(value);
51
+ }
52
+ if (typeof value === "string" && /^\d+$/.test(value.trim())) {
53
+ return Number(value);
54
+ }
55
+ return undefined;
56
+ }
57
+ function extractDiscordErrorStatus(err) {
58
+ if (!err || typeof err !== "object") {
59
+ return undefined;
60
+ }
61
+ const candidate = err;
62
+ return (extractNumericDiscordErrorValue(candidate.status) ??
63
+ extractNumericDiscordErrorValue(candidate.statusCode) ??
64
+ extractNumericDiscordErrorValue(candidate.response?.status));
65
+ }
66
+ function extractDiscordErrorCode(err) {
67
+ if (!err || typeof err !== "object") {
68
+ return undefined;
69
+ }
70
+ const candidate = err;
71
+ return (extractNumericDiscordErrorValue(candidate.code) ??
72
+ extractNumericDiscordErrorValue(candidate.rawError?.code) ??
73
+ extractNumericDiscordErrorValue(candidate.body?.code) ??
74
+ extractNumericDiscordErrorValue(candidate.response?.body?.code) ??
75
+ extractNumericDiscordErrorValue(candidate.response?.data?.code));
76
+ }
77
+ export function isDiscordThreadGoneError(err) {
78
+ const code = extractDiscordErrorCode(err);
79
+ if (code === DISCORD_UNKNOWN_CHANNEL_ERROR_CODE) {
80
+ return true;
81
+ }
82
+ const status = extractDiscordErrorStatus(err);
83
+ // 404: deleted/unknown channel. 403: bot no longer has access.
84
+ return status === 404 || status === 403;
85
+ }
86
+ export async function maybeSendBindingMessage(params) {
87
+ const text = params.text.trim();
88
+ if (!text) {
89
+ return;
90
+ }
91
+ const record = params.record;
92
+ if (params.preferWebhook !== false && record.webhookId && record.webhookToken) {
93
+ try {
94
+ await sendWebhookMessageDiscord(text, {
95
+ webhookId: record.webhookId,
96
+ webhookToken: record.webhookToken,
97
+ accountId: record.accountId,
98
+ threadId: record.threadId,
99
+ username: summarizeBindingPersona(record),
100
+ });
101
+ return;
102
+ }
103
+ catch (err) {
104
+ logVerbose(`discord thread binding webhook send failed: ${summarizeDiscordError(err)}`);
105
+ }
106
+ }
107
+ try {
108
+ await sendMessageDiscord(buildThreadTarget(record.threadId), text, {
109
+ accountId: record.accountId,
110
+ });
111
+ }
112
+ catch (err) {
113
+ logVerbose(`discord thread binding fallback send failed: ${summarizeDiscordError(err)}`);
114
+ }
115
+ }
116
+ export async function createWebhookForChannel(params) {
117
+ try {
118
+ const rest = createDiscordRestClient({
119
+ accountId: params.accountId,
120
+ token: params.token,
121
+ }).rest;
122
+ const created = (await rest.post(Routes.channelWebhooks(params.channelId), {
123
+ body: {
124
+ name: "Pool Bot Agents",
125
+ },
126
+ }));
127
+ const webhookId = typeof created?.id === "string" ? created.id.trim() : "";
128
+ const webhookToken = typeof created?.token === "string" ? created.token.trim() : "";
129
+ if (!webhookId || !webhookToken) {
130
+ return {};
131
+ }
132
+ return { webhookId, webhookToken };
133
+ }
134
+ catch (err) {
135
+ logVerbose(`discord thread binding webhook create failed for ${params.channelId}: ${summarizeDiscordError(err)}`);
136
+ return {};
137
+ }
138
+ }
139
+ export function findReusableWebhook(params) {
140
+ const reusableKey = toReusableWebhookKey({
141
+ accountId: params.accountId,
142
+ channelId: params.channelId,
143
+ });
144
+ const cached = REUSABLE_WEBHOOKS_BY_ACCOUNT_CHANNEL.get(reusableKey);
145
+ if (cached) {
146
+ return {
147
+ webhookId: cached.webhookId,
148
+ webhookToken: cached.webhookToken,
149
+ };
150
+ }
151
+ for (const record of BINDINGS_BY_THREAD_ID.values()) {
152
+ if (record.accountId !== params.accountId) {
153
+ continue;
154
+ }
155
+ if (record.channelId !== params.channelId) {
156
+ continue;
157
+ }
158
+ if (!record.webhookId || !record.webhookToken) {
159
+ continue;
160
+ }
161
+ rememberReusableWebhook(record);
162
+ return {
163
+ webhookId: record.webhookId,
164
+ webhookToken: record.webhookToken,
165
+ };
166
+ }
167
+ return {};
168
+ }
169
+ export async function resolveChannelIdForBinding(params) {
170
+ const explicit = params.channelId?.trim();
171
+ if (explicit) {
172
+ return explicit;
173
+ }
174
+ try {
175
+ const rest = createDiscordRestClient({
176
+ accountId: params.accountId,
177
+ token: params.token,
178
+ }).rest;
179
+ const channel = (await rest.get(Routes.channel(params.threadId)));
180
+ const channelId = typeof channel?.id === "string" ? channel.id.trim() : "";
181
+ const type = channel?.type;
182
+ const parentId = typeof channel?.parent_id === "string"
183
+ ? channel.parent_id.trim()
184
+ : typeof channel?.parentId === "string"
185
+ ? channel.parentId.trim()
186
+ : "";
187
+ // Only thread channels should resolve to their parent channel.
188
+ // Non-thread channels (text/forum/media) must keep their own ID.
189
+ if (parentId && isThreadChannelType(type)) {
190
+ return parentId;
191
+ }
192
+ return channelId || null;
193
+ }
194
+ catch (err) {
195
+ logVerbose(`discord thread binding channel resolve failed for ${params.threadId}: ${summarizeDiscordError(err)}`);
196
+ return null;
197
+ }
198
+ }
199
+ export async function createThreadForBinding(params) {
200
+ try {
201
+ const created = (await createThreadDiscord(params.channelId, {
202
+ name: params.threadName,
203
+ autoArchiveMinutes: 60,
204
+ }, {
205
+ accountId: params.accountId,
206
+ token: params.token,
207
+ }));
208
+ const createdId = typeof created?.id === "string" ? created.id.trim() : "";
209
+ return createdId || null;
210
+ }
211
+ catch (err) {
212
+ logVerbose(`discord thread binding auto-thread create failed for ${params.channelId}: ${summarizeDiscordError(err)}`);
213
+ return null;
214
+ }
215
+ }
@@ -0,0 +1,4 @@
1
+ export { formatThreadBindingTtlLabel, resolveThreadBindingIntroText, resolveThreadBindingThreadName, } from "./thread-bindings.messages.js";
2
+ export { isRecentlyUnboundThreadWebhookMessage } from "./thread-bindings.state.js";
3
+ export { autoBindSpawnedDiscordSubagent, listThreadBindingsBySessionKey, listThreadBindingsForAccount, setThreadBindingTtlBySessionKey, unbindThreadBindingsBySessionKey, } from "./thread-bindings.lifecycle.js";
4
+ export { __testing, createNoopThreadBindingManager, createThreadBindingManager, getThreadBindingManager, } from "./thread-bindings.manager.js";
@@ -0,0 +1,177 @@
1
+ import { normalizeAccountId } from "../../routing/session-key.js";
2
+ import { parseDiscordTarget } from "../targets.js";
3
+ import { resolveChannelIdForBinding } from "./thread-bindings.discord-api.js";
4
+ import { getThreadBindingManager } from "./thread-bindings.manager.js";
5
+ import { resolveThreadBindingIntroText, resolveThreadBindingThreadName, } from "./thread-bindings.messages.js";
6
+ import { BINDINGS_BY_THREAD_ID, MANAGERS_BY_ACCOUNT_ID, ensureBindingsLoaded, getThreadBindingToken, normalizeThreadBindingTtlMs, normalizeThreadId, rememberRecentUnboundWebhookEcho, removeBindingRecord, resolveBindingIdsForSession, saveBindingsToDisk, setBindingRecord, shouldPersistBindingMutations, } from "./thread-bindings.state.js";
7
+ export function listThreadBindingsForAccount(accountId) {
8
+ const manager = getThreadBindingManager(accountId);
9
+ if (!manager) {
10
+ return [];
11
+ }
12
+ return manager.listBindings();
13
+ }
14
+ export function listThreadBindingsBySessionKey(params) {
15
+ ensureBindingsLoaded();
16
+ const targetSessionKey = params.targetSessionKey.trim();
17
+ if (!targetSessionKey) {
18
+ return [];
19
+ }
20
+ const accountId = params.accountId ? normalizeAccountId(params.accountId) : undefined;
21
+ const ids = resolveBindingIdsForSession({
22
+ targetSessionKey,
23
+ accountId,
24
+ targetKind: params.targetKind,
25
+ });
26
+ return ids
27
+ .map((bindingKey) => BINDINGS_BY_THREAD_ID.get(bindingKey))
28
+ .filter((entry) => Boolean(entry));
29
+ }
30
+ export async function autoBindSpawnedDiscordSubagent(params) {
31
+ const channel = params.channel?.trim().toLowerCase();
32
+ if (channel !== "discord") {
33
+ return null;
34
+ }
35
+ const manager = getThreadBindingManager(params.accountId);
36
+ if (!manager) {
37
+ return null;
38
+ }
39
+ const managerToken = getThreadBindingToken(manager.accountId);
40
+ const requesterThreadId = normalizeThreadId(params.threadId);
41
+ let channelId = "";
42
+ if (requesterThreadId) {
43
+ const existing = manager.getByThreadId(requesterThreadId);
44
+ if (existing?.channelId?.trim()) {
45
+ channelId = existing.channelId.trim();
46
+ }
47
+ else {
48
+ channelId =
49
+ (await resolveChannelIdForBinding({
50
+ accountId: manager.accountId,
51
+ token: managerToken,
52
+ threadId: requesterThreadId,
53
+ })) ?? "";
54
+ }
55
+ }
56
+ if (!channelId) {
57
+ const to = params.to?.trim() || "";
58
+ if (!to) {
59
+ return null;
60
+ }
61
+ try {
62
+ const target = parseDiscordTarget(to, { defaultKind: "channel" });
63
+ if (!target || target.kind !== "channel") {
64
+ return null;
65
+ }
66
+ channelId =
67
+ (await resolveChannelIdForBinding({
68
+ accountId: manager.accountId,
69
+ token: managerToken,
70
+ threadId: target.id,
71
+ })) ?? "";
72
+ }
73
+ catch {
74
+ return null;
75
+ }
76
+ }
77
+ return await manager.bindTarget({
78
+ threadId: undefined,
79
+ channelId,
80
+ createThread: true,
81
+ threadName: resolveThreadBindingThreadName({
82
+ agentId: params.agentId,
83
+ label: params.label,
84
+ }),
85
+ targetKind: "subagent",
86
+ targetSessionKey: params.childSessionKey,
87
+ agentId: params.agentId,
88
+ label: params.label,
89
+ boundBy: params.boundBy ?? "system",
90
+ introText: resolveThreadBindingIntroText({
91
+ agentId: params.agentId,
92
+ label: params.label,
93
+ sessionTtlMs: manager.getSessionTtlMs(),
94
+ }),
95
+ });
96
+ }
97
+ export function unbindThreadBindingsBySessionKey(params) {
98
+ ensureBindingsLoaded();
99
+ const targetSessionKey = params.targetSessionKey.trim();
100
+ if (!targetSessionKey) {
101
+ return [];
102
+ }
103
+ const accountId = params.accountId ? normalizeAccountId(params.accountId) : undefined;
104
+ const ids = resolveBindingIdsForSession({
105
+ targetSessionKey,
106
+ accountId,
107
+ targetKind: params.targetKind,
108
+ });
109
+ if (ids.length === 0) {
110
+ return [];
111
+ }
112
+ const removed = [];
113
+ for (const bindingKey of ids) {
114
+ const record = BINDINGS_BY_THREAD_ID.get(bindingKey);
115
+ if (!record) {
116
+ continue;
117
+ }
118
+ const manager = MANAGERS_BY_ACCOUNT_ID.get(record.accountId);
119
+ if (manager) {
120
+ const unbound = manager.unbindThread({
121
+ threadId: record.threadId,
122
+ reason: params.reason,
123
+ sendFarewell: params.sendFarewell,
124
+ farewellText: params.farewellText,
125
+ });
126
+ if (unbound) {
127
+ removed.push(unbound);
128
+ }
129
+ continue;
130
+ }
131
+ const unbound = removeBindingRecord(bindingKey);
132
+ if (unbound) {
133
+ rememberRecentUnboundWebhookEcho(unbound);
134
+ removed.push(unbound);
135
+ }
136
+ }
137
+ if (removed.length > 0 && shouldPersistBindingMutations()) {
138
+ saveBindingsToDisk({ force: true });
139
+ }
140
+ return removed;
141
+ }
142
+ export function setThreadBindingTtlBySessionKey(params) {
143
+ ensureBindingsLoaded();
144
+ const targetSessionKey = params.targetSessionKey.trim();
145
+ if (!targetSessionKey) {
146
+ return [];
147
+ }
148
+ const accountId = params.accountId ? normalizeAccountId(params.accountId) : undefined;
149
+ const ids = resolveBindingIdsForSession({
150
+ targetSessionKey,
151
+ accountId,
152
+ });
153
+ if (ids.length === 0) {
154
+ return [];
155
+ }
156
+ const ttlMs = normalizeThreadBindingTtlMs(params.ttlMs);
157
+ const now = Date.now();
158
+ const expiresAt = ttlMs > 0 ? now + ttlMs : 0;
159
+ const updated = [];
160
+ for (const bindingKey of ids) {
161
+ const existing = BINDINGS_BY_THREAD_ID.get(bindingKey);
162
+ if (!existing) {
163
+ continue;
164
+ }
165
+ const nextRecord = {
166
+ ...existing,
167
+ boundAt: now,
168
+ expiresAt,
169
+ };
170
+ setBindingRecord(nextRecord);
171
+ updated.push(nextRecord);
172
+ }
173
+ if (updated.length > 0 && shouldPersistBindingMutations()) {
174
+ saveBindingsToDisk({ force: true });
175
+ }
176
+ return updated;
177
+ }