@poolzin/pool-bot 2026.2.20 → 2026.2.22

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 (388) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/agents/api-key-rotation.js +47 -0
  3. package/dist/agents/apply-patch-update.js +19 -9
  4. package/dist/agents/apply-patch.js +72 -47
  5. package/dist/agents/bash-tools.exec.js +141 -559
  6. package/dist/agents/cli-backends.js +49 -6
  7. package/dist/agents/cli-runner/helpers.js +69 -152
  8. package/dist/agents/cli-runner.js +70 -19
  9. package/dist/agents/identity.js +20 -1
  10. package/dist/agents/image-sanitization.js +9 -0
  11. package/dist/agents/live-auth-keys.js +123 -26
  12. package/dist/agents/live-model-filter.js +13 -4
  13. package/dist/agents/model-auth.js +12 -0
  14. package/dist/agents/model-catalog.js +40 -9
  15. package/dist/agents/model-fallback.js +24 -0
  16. package/dist/agents/model-forward-compat.js +60 -23
  17. package/dist/agents/model-selection.js +134 -41
  18. package/dist/agents/pi-auth-json.js +2 -2
  19. package/dist/agents/pi-embedded-helpers/bootstrap.js +65 -15
  20. package/dist/agents/pi-embedded-helpers/errors.js +140 -15
  21. package/dist/agents/pi-embedded-helpers/images.js +22 -12
  22. package/dist/agents/pi-embedded-helpers.js +2 -2
  23. package/dist/agents/pi-embedded-runner/abort.js +10 -3
  24. package/dist/agents/pi-embedded-runner/compact.js +230 -32
  25. package/dist/agents/pi-embedded-runner/extra-params.js +203 -12
  26. package/dist/agents/pi-embedded-runner/google.js +109 -19
  27. package/dist/agents/pi-embedded-runner/history.js +35 -17
  28. package/dist/agents/pi-embedded-runner/run/attempt.js +386 -80
  29. package/dist/agents/pi-embedded-runner/run/images.js +81 -55
  30. package/dist/agents/pi-embedded-runner/run/payloads.js +89 -39
  31. package/dist/agents/pi-embedded-runner/run.js +193 -25
  32. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +2 -2
  33. package/dist/agents/pi-embedded-runner/runs.js +17 -8
  34. package/dist/agents/pi-embedded-runner/tool-result-context-guard.js +262 -0
  35. package/dist/agents/pi-embedded-runner.js +1 -1
  36. package/dist/agents/pi-embedded-subscribe.handlers.tools.js +180 -10
  37. package/dist/agents/pi-embedded-subscribe.js +37 -0
  38. package/dist/agents/pi-embedded-subscribe.tools.js +127 -30
  39. package/dist/agents/pi-model-discovery.js +9 -2
  40. package/dist/agents/pi-tool-definition-adapter.js +60 -8
  41. package/dist/agents/pi-tools.before-tool-call.js +1 -1
  42. package/dist/agents/pi-tools.js +113 -94
  43. package/dist/agents/pi-tools.read.js +337 -38
  44. package/dist/agents/poolbot-tools.js +14 -5
  45. package/dist/agents/provider/config-loader.js +76 -0
  46. package/dist/agents/provider/index.js +15 -0
  47. package/dist/agents/provider/integration.js +136 -0
  48. package/dist/agents/provider/models-dev.js +129 -0
  49. package/dist/agents/provider/rate-limits.js +458 -0
  50. package/dist/agents/provider/request-monitor.js +449 -0
  51. package/dist/agents/provider/session-binding.js +376 -0
  52. package/dist/agents/provider/token-pool.js +541 -0
  53. package/dist/agents/sandbox/docker.js +10 -5
  54. package/dist/agents/sandbox/registry.js +96 -46
  55. package/dist/agents/sandbox/sanitize-env-vars.js +82 -0
  56. package/dist/agents/sandbox-paths.js +43 -10
  57. package/dist/agents/session-tool-result-guard-wrapper.js +23 -11
  58. package/dist/agents/session-tool-result-guard.js +39 -39
  59. package/dist/agents/session-transcript-repair.js +36 -33
  60. package/dist/agents/session-write-lock.js +62 -44
  61. package/dist/agents/skills/frontmatter.js +49 -88
  62. package/dist/agents/skills/workspace.js +335 -28
  63. package/dist/agents/subagent-announce.js +508 -174
  64. package/dist/agents/subagent-registry.js +45 -4
  65. package/dist/agents/subagent-spawn.js +16 -33
  66. package/dist/agents/system-prompt-report.js +27 -10
  67. package/dist/agents/system-prompt.js +26 -32
  68. package/dist/agents/tool-call-id.js +69 -17
  69. package/dist/agents/tool-display-common.js +1 -1
  70. package/dist/agents/tool-images.js +64 -31
  71. package/dist/agents/tools/canvas-tool.js +17 -11
  72. package/dist/agents/tools/common.js +37 -19
  73. package/dist/agents/tools/cron-tool.js +40 -38
  74. package/dist/agents/tools/gateway.js +70 -2
  75. package/dist/agents/tools/message-tool.js +181 -40
  76. package/dist/agents/tools/nodes-tool.js +128 -36
  77. package/dist/agents/tools/nodes-utils.js +12 -38
  78. package/dist/agents/tools/session-status-tool.js +24 -71
  79. package/dist/agents/tools/sessions-helpers.js +38 -210
  80. package/dist/agents/tools/sessions-spawn-tool.js +28 -198
  81. package/dist/agents/tools/telegram-actions.js +58 -7
  82. package/dist/agents/tools/web-fetch-utils.js +112 -7
  83. package/dist/agents/tools/web-fetch.js +279 -175
  84. package/dist/agents/tools/web-shared.js +71 -8
  85. package/dist/agents/usage.js +25 -16
  86. package/dist/auto-reply/commands-registry.data.js +85 -11
  87. package/dist/auto-reply/dispatch.js +40 -21
  88. package/dist/auto-reply/reply/abort.js +102 -33
  89. package/dist/auto-reply/reply/commands-core.js +82 -33
  90. package/dist/auto-reply/reply/commands-export-session.js +1 -1
  91. package/dist/auto-reply/reply/commands-info.js +41 -12
  92. package/dist/auto-reply/reply/commands-subagents.js +352 -100
  93. package/dist/auto-reply/reply/commands-system-prompt.js +2 -2
  94. package/dist/auto-reply/reply/dispatch-from-config.js +100 -29
  95. package/dist/auto-reply/reply/elevated-unavailable.js +1 -1
  96. package/dist/auto-reply/reply/inbound-meta.js +12 -1
  97. package/dist/auto-reply/reply/mentions.js +18 -11
  98. package/dist/auto-reply/reply/normalize-reply.js +17 -8
  99. package/dist/auto-reply/reply/reply-dispatcher.js +62 -10
  100. package/dist/auto-reply/reply/session.js +102 -21
  101. package/dist/auto-reply/reply/streaming-directives.js +16 -5
  102. package/dist/auto-reply/status.js +73 -50
  103. package/dist/browser/extension-relay.js +3 -3
  104. package/dist/browser/http-auth.js +1 -1
  105. package/dist/browser/paths.js +2 -2
  106. package/dist/build-info.json +3 -3
  107. package/dist/channels/allowlist-match.js +20 -0
  108. package/dist/channels/allowlists/resolve-utils.js +65 -2
  109. package/dist/channels/chat-type.js +8 -4
  110. package/dist/channels/dock.js +127 -35
  111. package/dist/channels/draft-stream-loop.js +6 -2
  112. package/dist/channels/plugins/actions/telegram.js +42 -18
  113. package/dist/channels/plugins/allowlist-match.js +1 -1
  114. package/dist/channels/plugins/group-mentions.js +51 -41
  115. package/dist/channels/plugins/message-action-names.js +2 -0
  116. package/dist/channels/plugins/message-actions.js +24 -5
  117. package/dist/channels/plugins/normalize/discord.js +26 -4
  118. package/dist/channels/plugins/normalize/signal.js +35 -22
  119. package/dist/channels/plugins/onboarding/helpers.js +8 -26
  120. package/dist/channels/plugins/outbound/imessage.js +15 -14
  121. package/dist/channels/registry.js +20 -7
  122. package/dist/cli/acp-cli.js +7 -5
  123. package/dist/cli/browser-cli-extension.js +25 -12
  124. package/dist/cli/browser-cli-state.cookies-storage.js +25 -6
  125. package/dist/cli/browser-cli-state.js +101 -145
  126. package/dist/cli/command-options.js +28 -0
  127. package/dist/cli/completion-cli.js +6 -6
  128. package/dist/cli/cron-cli/register.cron-add.js +25 -1
  129. package/dist/cli/cron-cli/register.cron-edit.js +44 -0
  130. package/dist/cli/cron-cli/shared.js +7 -1
  131. package/dist/cli/daemon-cli/lifecycle-core.js +23 -21
  132. package/dist/cli/daemon-cli/lifecycle.js +23 -247
  133. package/dist/cli/daemon-cli/register-service-commands.js +25 -4
  134. package/dist/cli/daemon-cli.js +1 -0
  135. package/dist/cli/devices-cli.js +33 -20
  136. package/dist/cli/gateway-cli/register.js +37 -105
  137. package/dist/cli/gateway-cli/run.js +49 -11
  138. package/dist/cli/nodes-camera.js +59 -4
  139. package/dist/cli/nodes-cli/register.camera.js +27 -24
  140. package/dist/cli/nodes-cli/rpc.js +21 -38
  141. package/dist/cli/qr-cli.js +2 -2
  142. package/dist/cli/skills-cli.format.js +2 -2
  143. package/dist/cli/update-cli/progress.js +2 -2
  144. package/dist/cli/update-cli/restart-helper.js +28 -7
  145. package/dist/cli/update-cli/shared.js +7 -7
  146. package/dist/cli/update-cli/status.js +1 -1
  147. package/dist/cli/update-cli/update-command.js +14 -8
  148. package/dist/cli/update-cli/wizard.js +2 -2
  149. package/dist/cli/update-cli.js +21 -1027
  150. package/dist/commands/auth-choice.apply.anthropic.js +10 -2
  151. package/dist/commands/channels/add-mutators.js +3 -35
  152. package/dist/commands/channels/add.js +39 -51
  153. package/dist/commands/config-validation.js +1 -1
  154. package/dist/commands/configure.gateway-auth.js +52 -15
  155. package/dist/commands/configure.gateway.js +84 -40
  156. package/dist/commands/doctor-completion.js +3 -3
  157. package/dist/commands/doctor-config-flow.js +536 -16
  158. package/dist/commands/doctor-gateway-services.js +103 -79
  159. package/dist/commands/doctor-memory-search.js +9 -9
  160. package/dist/commands/doctor-platform-notes.js +57 -30
  161. package/dist/commands/doctor-prompter.js +26 -15
  162. package/dist/commands/doctor-session-locks.js +1 -1
  163. package/dist/commands/doctor.js +21 -9
  164. package/dist/commands/model-picker.js +120 -95
  165. package/dist/commands/models/set.js +2 -21
  166. package/dist/commands/models/shared.js +65 -37
  167. package/dist/commands/onboard-helpers.js +81 -39
  168. package/dist/commands/openai-codex-oauth.js +1 -1
  169. package/dist/commands/sessions.js +52 -53
  170. package/dist/commands/status.summary.js +52 -34
  171. package/dist/commands/test-wizard-helpers.js +2 -2
  172. package/dist/config/defaults.js +79 -42
  173. package/dist/config/group-policy.js +50 -18
  174. package/dist/config/includes.js +37 -10
  175. package/dist/config/schema.help.js +5 -4
  176. package/dist/config/schema.hints.js +2 -2
  177. package/dist/config/schema.labels.js +1 -0
  178. package/dist/config/sessions/group.js +12 -11
  179. package/dist/config/sessions/paths.js +137 -11
  180. package/dist/config/sessions/store.js +185 -65
  181. package/dist/config/sessions/types.js +15 -1
  182. package/dist/config/sessions.js +1 -0
  183. package/dist/config/telegram-custom-commands.js +3 -2
  184. package/dist/config/types.js +2 -0
  185. package/dist/config/zod-schema.agent-defaults.js +6 -27
  186. package/dist/config/zod-schema.agent-runtime.js +171 -79
  187. package/dist/config/zod-schema.providers-core.js +138 -65
  188. package/dist/config/zod-schema.session.js +49 -22
  189. package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
  190. package/dist/cron/isolated-agent/run.js +224 -57
  191. package/dist/cron/normalize.js +48 -45
  192. package/dist/cron/run-log.js +14 -0
  193. package/dist/cron/service/jobs.js +190 -28
  194. package/dist/cron/service/normalize.js +29 -11
  195. package/dist/cron/service/store.js +30 -44
  196. package/dist/cron/service/timer.js +182 -96
  197. package/dist/cron/service.js +3 -0
  198. package/dist/cron/stagger.js +37 -0
  199. package/dist/daemon/inspect.js +132 -92
  200. package/dist/daemon/runtime-paths.js +25 -4
  201. package/dist/daemon/service-audit.js +47 -16
  202. package/dist/discord/accounts.js +23 -20
  203. package/dist/discord/monitor/agent-components.js +1115 -219
  204. package/dist/discord/monitor/allow-list.js +114 -34
  205. package/dist/discord/monitor/listeners.js +204 -97
  206. package/dist/discord/monitor/message-handler.js +21 -10
  207. package/dist/discord/monitor/message-handler.preflight.js +195 -101
  208. package/dist/discord/monitor/message-handler.process.js +384 -123
  209. package/dist/discord/monitor/message-utils.js +86 -23
  210. package/dist/discord/monitor/native-command.js +77 -57
  211. package/dist/discord/monitor/provider.js +122 -117
  212. package/dist/discord/monitor/reply-context.js +20 -16
  213. package/dist/discord/monitor/reply-delivery.js +40 -8
  214. package/dist/discord/monitor/rest-fetch.js +22 -0
  215. package/dist/discord/monitor/threading.js +117 -24
  216. package/dist/discord/send.js +2 -1
  217. package/dist/discord/send.outbound.js +124 -11
  218. package/dist/discord/send.shared.js +112 -72
  219. package/dist/discord/voice-message.js +3 -3
  220. package/dist/gateway/auth.js +119 -44
  221. package/dist/gateway/call.js +76 -34
  222. package/dist/gateway/channel-health-monitor.js +57 -50
  223. package/dist/gateway/client.js +63 -29
  224. package/dist/gateway/control-ui-contract.js +1 -1
  225. package/dist/gateway/gateway-config-prompts.shared.js +2 -2
  226. package/dist/gateway/net.js +109 -1
  227. package/dist/gateway/protocol/index.js +5 -8
  228. package/dist/gateway/protocol/schema/agent.js +19 -1
  229. package/dist/gateway/protocol/schema/channels.js +21 -0
  230. package/dist/gateway/protocol/schema/cron.js +43 -30
  231. package/dist/gateway/protocol/schema/protocol-schemas.js +6 -11
  232. package/dist/gateway/protocol/schema/sessions.js +5 -1
  233. package/dist/gateway/protocol/schema.js +0 -1
  234. package/dist/gateway/server/presence-events.js +12 -0
  235. package/dist/gateway/server/ws-connection/message-handler.js +203 -212
  236. package/dist/gateway/server/ws-connection.js +58 -21
  237. package/dist/gateway/server-broadcast.js +18 -13
  238. package/dist/gateway/server-cron.js +177 -10
  239. package/dist/gateway/server-methods/agent-job.js +131 -38
  240. package/dist/gateway/server-methods/send.js +60 -14
  241. package/dist/gateway/server-methods/sessions.js +160 -96
  242. package/dist/gateway/server-methods/system.js +5 -7
  243. package/dist/gateway/server-methods-list.js +8 -0
  244. package/dist/gateway/server-methods.js +24 -8
  245. package/dist/gateway/server-node-events.js +278 -68
  246. package/dist/gateway/session-utils.fs.js +316 -75
  247. package/dist/gateway/session-utils.js +224 -70
  248. package/dist/gateway/sessions-patch.js +63 -20
  249. package/dist/gateway/test-temp-config.js +1 -1
  250. package/dist/gateway/tools-invoke-http.js +118 -70
  251. package/dist/gateway/ws-log.js +135 -107
  252. package/dist/hooks/frontmatter.js +36 -82
  253. package/dist/hooks/install.js +149 -139
  254. package/dist/hooks/internal-hooks.js +29 -4
  255. package/dist/hooks/plugin-hooks.js +2 -1
  256. package/dist/imessage/monitor/deliver.js +10 -4
  257. package/dist/imessage/monitor/monitor-provider.js +138 -375
  258. package/dist/imessage/monitor/runtime.js +4 -8
  259. package/dist/imessage/send.js +65 -19
  260. package/dist/infra/exec-approvals-allowlist.js +7 -0
  261. package/dist/infra/exec-approvals.js +35 -920
  262. package/dist/infra/exec-safe-bin-trust.js +64 -0
  263. package/dist/infra/heartbeat-runner.js +207 -134
  264. package/dist/infra/heartbeat-wake.js +183 -22
  265. package/dist/infra/install-source-utils.js +47 -0
  266. package/dist/infra/net/ssrf.js +170 -36
  267. package/dist/infra/outbound/deliver.js +224 -58
  268. package/dist/infra/outbound/message-action-spec.js +12 -5
  269. package/dist/infra/outbound/outbound-session.js +27 -25
  270. package/dist/infra/poolbot-root.js +32 -22
  271. package/dist/infra/ports.js +14 -11
  272. package/dist/infra/skills-remote.js +48 -37
  273. package/dist/infra/system-events.js +25 -11
  274. package/dist/infra/system-presence.js +26 -33
  275. package/dist/infra/tmp-poolbot-dir.js +81 -2
  276. package/dist/infra/wsl.js +37 -1
  277. package/dist/line/bot-message-context.js +163 -191
  278. package/dist/logging/subsystem.js +59 -22
  279. package/dist/markdown/ir.js +124 -50
  280. package/dist/media/store.js +1 -1
  281. package/dist/media-understanding/runner.entries.js +42 -25
  282. package/dist/media-understanding/runner.js +53 -488
  283. package/dist/memory/embeddings-gemini.js +53 -38
  284. package/dist/memory/manager-embedding-ops.js +48 -69
  285. package/dist/pairing/pairing-store.js +178 -119
  286. package/dist/plugin-sdk/index.js +34 -6
  287. package/dist/plugins/hooks.js +135 -14
  288. package/dist/plugins/install.js +190 -152
  289. package/dist/polls.js +11 -0
  290. package/dist/routing/resolve-route.js +190 -56
  291. package/dist/routing/session-key.js +38 -22
  292. package/dist/runtime.js +35 -9
  293. package/dist/security/audit-channel.js +1 -1
  294. package/dist/sessions/session-key-utils.js +29 -11
  295. package/dist/shared/frontmatter.js +5 -5
  296. package/dist/shared/node-list-types.js +1 -0
  297. package/dist/shared/string-normalization.js +15 -0
  298. package/dist/signal/monitor/event-handler.js +68 -36
  299. package/dist/signal/send.js +29 -37
  300. package/dist/slack/monitor/allow-list.js +10 -11
  301. package/dist/slack/monitor/commands.js +14 -3
  302. package/dist/slack/monitor/events/interactions.js +4 -4
  303. package/dist/slack/monitor/media.js +224 -16
  304. package/dist/slack/monitor/message-handler/dispatch.js +247 -13
  305. package/dist/slack/monitor/message-handler/prepare.js +128 -45
  306. package/dist/slack/monitor/slash.js +357 -144
  307. package/dist/slack/streaming.js +77 -0
  308. package/dist/telegram/accounts.js +40 -13
  309. package/dist/telegram/allowed-updates.js +3 -0
  310. package/dist/telegram/bot/delivery.js +129 -66
  311. package/dist/telegram/bot/helpers.js +136 -122
  312. package/dist/telegram/bot-handlers.js +600 -339
  313. package/dist/telegram/bot-message-context.js +115 -73
  314. package/dist/telegram/bot-message-dispatch.js +235 -104
  315. package/dist/telegram/bot-native-command-menu.js +3 -1
  316. package/dist/telegram/bot-native-commands.js +213 -193
  317. package/dist/telegram/bot.js +24 -132
  318. package/dist/telegram/draft-stream.js +84 -75
  319. package/dist/telegram/format.js +150 -6
  320. package/dist/telegram/send.js +415 -255
  321. package/dist/telegram/targets.js +21 -2
  322. package/dist/telegram/update-offset-store.js +19 -3
  323. package/dist/terminal/restore.js +5 -2
  324. package/dist/test-utils/fetch-mock.js +5 -0
  325. package/dist/version.js +18 -5
  326. package/dist/web/auto-reply/monitor/broadcast.js +7 -3
  327. package/dist/web/auto-reply/monitor/on-message.js +6 -3
  328. package/dist/web/inbound/media.js +34 -8
  329. package/dist/web/inbound/monitor.js +34 -17
  330. package/dist/web/inbound/send-api.js +18 -17
  331. package/dist/web/outbound.js +12 -5
  332. package/dist/wizard/clack-prompter.js +40 -7
  333. package/extensions/bluebubbles/package.json +1 -1
  334. package/extensions/copilot-proxy/package.json +1 -1
  335. package/extensions/diagnostics-otel/package.json +1 -1
  336. package/extensions/discord/package.json +1 -1
  337. package/extensions/feishu/package.json +1 -1
  338. package/extensions/google-antigravity-auth/package.json +1 -1
  339. package/extensions/google-gemini-cli-auth/package.json +1 -1
  340. package/extensions/googlechat/package.json +1 -1
  341. package/extensions/imessage/package.json +1 -1
  342. package/extensions/irc/package.json +1 -1
  343. package/extensions/line/package.json +1 -1
  344. package/extensions/llm-task/package.json +1 -1
  345. package/extensions/lobster/package.json +1 -1
  346. package/extensions/matrix/CHANGELOG.md +5 -0
  347. package/extensions/matrix/package.json +1 -1
  348. package/extensions/mattermost/package.json +1 -1
  349. package/extensions/memory-core/package.json +1 -1
  350. package/extensions/memory-lancedb/package.json +1 -1
  351. package/extensions/minimax-portal-auth/package.json +1 -1
  352. package/extensions/msteams/CHANGELOG.md +5 -0
  353. package/extensions/msteams/package.json +1 -1
  354. package/extensions/nextcloud-talk/package.json +1 -1
  355. package/extensions/nostr/CHANGELOG.md +5 -0
  356. package/extensions/nostr/package.json +1 -1
  357. package/extensions/open-prose/package.json +1 -1
  358. package/extensions/openai-codex-auth/package.json +1 -1
  359. package/extensions/signal/package.json +1 -1
  360. package/extensions/slack/package.json +1 -1
  361. package/extensions/telegram/package.json +1 -1
  362. package/extensions/tlon/package.json +1 -1
  363. package/extensions/twitch/CHANGELOG.md +5 -0
  364. package/extensions/twitch/package.json +1 -1
  365. package/extensions/voice-call/CHANGELOG.md +5 -0
  366. package/extensions/voice-call/package.json +1 -1
  367. package/extensions/whatsapp/package.json +1 -1
  368. package/extensions/zalo/CHANGELOG.md +5 -0
  369. package/extensions/zalo/package.json +1 -1
  370. package/extensions/zalouser/CHANGELOG.md +5 -0
  371. package/extensions/zalouser/package.json +1 -1
  372. package/package.json +1 -1
  373. package/skills/apple-reminders/SKILL.md +100 -49
  374. package/skills/coding-agent/SKILL.md +34 -28
  375. package/skills/github/SKILL.md +131 -16
  376. package/skills/imsg/SKILL.md +112 -15
  377. package/skills/openhue/SKILL.md +101 -19
  378. package/skills/plcode-controller/SKILL.md +156 -0
  379. package/skills/plcode-controller/assets/operator-prompts.md +65 -0
  380. package/skills/plcode-controller/references/command-cheatsheet.md +53 -0
  381. package/skills/plcode-controller/references/failure-handling.md +60 -0
  382. package/skills/plcode-controller/references/model-selection.md +57 -0
  383. package/skills/plcode-controller/references/plan-vs-build.md +52 -0
  384. package/skills/plcode-controller/references/question-handling.md +40 -0
  385. package/skills/plcode-controller/references/session-management.md +63 -0
  386. package/skills/plcode-controller/references/workflow.md +35 -0
  387. package/skills/tmux/SKILL.md +111 -79
  388. package/skills/weather/SKILL.md +88 -25
@@ -13,8 +13,9 @@ export function stripTelegramInternalPrefixes(to) {
13
13
  }
14
14
  return trimmed;
15
15
  })();
16
- if (next === trimmed)
16
+ if (next === trimmed) {
17
17
  return trimmed;
18
+ }
18
19
  trimmed = next;
19
20
  }
20
21
  }
@@ -26,6 +27,16 @@ export function stripTelegramInternalPrefixes(to) {
26
27
  * - `chatId:topicId` (numeric topic/thread ID)
27
28
  * - `chatId:topic:topicId` (explicit topic marker; preferred)
28
29
  */
30
+ function resolveTelegramChatType(chatId) {
31
+ const trimmed = chatId.trim();
32
+ if (!trimmed) {
33
+ return "unknown";
34
+ }
35
+ if (/^-?\d+$/.test(trimmed)) {
36
+ return trimmed.startsWith("-") ? "group" : "direct";
37
+ }
38
+ return "unknown";
39
+ }
29
40
  export function parseTelegramTarget(to) {
30
41
  const normalized = stripTelegramInternalPrefixes(to);
31
42
  const topicMatch = /^(.+?):topic:(\d+)$/.exec(normalized);
@@ -33,6 +44,7 @@ export function parseTelegramTarget(to) {
33
44
  return {
34
45
  chatId: topicMatch[1],
35
46
  messageThreadId: Number.parseInt(topicMatch[2], 10),
47
+ chatType: resolveTelegramChatType(topicMatch[1]),
36
48
  };
37
49
  }
38
50
  const colonMatch = /^(.+):(\d+)$/.exec(normalized);
@@ -40,7 +52,14 @@ export function parseTelegramTarget(to) {
40
52
  return {
41
53
  chatId: colonMatch[1],
42
54
  messageThreadId: Number.parseInt(colonMatch[2], 10),
55
+ chatType: resolveTelegramChatType(colonMatch[1]),
43
56
  };
44
57
  }
45
- return { chatId: normalized };
58
+ return {
59
+ chatId: normalized,
60
+ chatType: resolveTelegramChatType(normalized),
61
+ };
62
+ }
63
+ export function resolveTelegramTargetChatType(target) {
64
+ return parseTelegramTarget(target).chatType;
46
65
  }
@@ -6,8 +6,9 @@ import { resolveStateDir } from "../config/paths.js";
6
6
  const STORE_VERSION = 1;
7
7
  function normalizeAccountId(accountId) {
8
8
  const trimmed = accountId?.trim();
9
- if (!trimmed)
9
+ if (!trimmed) {
10
10
  return "default";
11
+ }
11
12
  return trimmed.replace(/[^a-z0-9._-]+/gi, "_");
12
13
  }
13
14
  function resolveTelegramUpdateOffsetPath(accountId, env = process.env) {
@@ -18,8 +19,9 @@ function resolveTelegramUpdateOffsetPath(accountId, env = process.env) {
18
19
  function safeParseState(raw) {
19
20
  try {
20
21
  const parsed = JSON.parse(raw);
21
- if (parsed?.version !== STORE_VERSION)
22
+ if (parsed?.version !== STORE_VERSION) {
22
23
  return null;
24
+ }
23
25
  if (parsed.lastUpdateId !== null && typeof parsed.lastUpdateId !== "number") {
24
26
  return null;
25
27
  }
@@ -38,8 +40,9 @@ export async function readTelegramUpdateOffset(params) {
38
40
  }
39
41
  catch (err) {
40
42
  const code = err.code;
41
- if (code === "ENOENT")
43
+ if (code === "ENOENT") {
42
44
  return null;
45
+ }
43
46
  return null;
44
47
  }
45
48
  }
@@ -58,3 +61,16 @@ export async function writeTelegramUpdateOffset(params) {
58
61
  await fs.chmod(tmp, 0o600);
59
62
  await fs.rename(tmp, filePath);
60
63
  }
64
+ export async function deleteTelegramUpdateOffset(params) {
65
+ const filePath = resolveTelegramUpdateOffsetPath(params.accountId, params.env);
66
+ try {
67
+ await fs.unlink(filePath);
68
+ }
69
+ catch (err) {
70
+ const code = err.code;
71
+ if (code === "ENOENT") {
72
+ return;
73
+ }
74
+ throw err;
75
+ }
76
+ }
@@ -10,7 +10,10 @@ function reportRestoreFailure(scope, err, reason) {
10
10
  console.error(`[terminal] restore reporting failed${suffix}: ${String(writeErr)}`);
11
11
  }
12
12
  }
13
- export function restoreTerminalState(reason) {
13
+ export function restoreTerminalState(reason, options = {}) {
14
+ // Docker TTY note: resuming stdin can keep a container process alive even
15
+ // after the wizard is "done" (stdin_open: true), making installers appear hung.
16
+ const resumeStdin = options.resumeStdinIfPaused ?? options.resumeStdin ?? false;
14
17
  try {
15
18
  clearActiveProgressLine();
16
19
  }
@@ -25,7 +28,7 @@ export function restoreTerminalState(reason) {
25
28
  catch (err) {
26
29
  reportRestoreFailure("raw mode", err, reason);
27
30
  }
28
- if (typeof stdin.isPaused === "function" && stdin.isPaused()) {
31
+ if (resumeStdin && typeof stdin.isPaused === "function" && stdin.isPaused()) {
29
32
  try {
30
33
  stdin.resume();
31
34
  }
@@ -0,0 +1,5 @@
1
+ export function withFetchPreconnect(fn) {
2
+ return Object.assign(fn, {
3
+ preconnect: (_url, _options) => { },
4
+ });
5
+ }
package/dist/version.js CHANGED
@@ -18,10 +18,12 @@ function readVersionFromJsonCandidates(moduleUrl, candidates, opts = {}) {
18
18
  try {
19
19
  const parsed = require(candidate);
20
20
  const version = parsed.version?.trim();
21
- if (!version)
21
+ if (!version) {
22
22
  continue;
23
- if (opts.requirePackageName && parsed.name !== CORE_PACKAGE_NAME)
23
+ }
24
+ if (opts.requirePackageName && parsed.name !== CORE_PACKAGE_NAME) {
24
25
  continue;
26
+ }
25
27
  return version;
26
28
  }
27
29
  catch {
@@ -34,6 +36,15 @@ function readVersionFromJsonCandidates(moduleUrl, candidates, opts = {}) {
34
36
  return null;
35
37
  }
36
38
  }
39
+ function firstNonEmpty(...values) {
40
+ for (const value of values) {
41
+ const trimmed = value?.trim();
42
+ if (trimmed) {
43
+ return trimmed;
44
+ }
45
+ }
46
+ return undefined;
47
+ }
37
48
  export function readVersionFromPackageJsonForModuleUrl(moduleUrl) {
38
49
  return readVersionFromJsonCandidates(moduleUrl, PACKAGE_JSON_CANDIDATES, {
39
50
  requirePackageName: true,
@@ -46,11 +57,13 @@ export function resolveVersionFromModuleUrl(moduleUrl) {
46
57
  return (readVersionFromPackageJsonForModuleUrl(moduleUrl) ||
47
58
  readVersionFromBuildInfoForModuleUrl(moduleUrl));
48
59
  }
49
- // Single source of truth for the current poolbot version.
60
+ export function resolveRuntimeServiceVersion(env = process.env, fallback = "dev") {
61
+ return (firstNonEmpty(env["POOLBOT_VERSION"], env["POOLBOT_SERVICE_VERSION"], env["npm_package_version"]) ?? fallback);
62
+ }
63
+ // Single source of truth for the current Pool Bot version.
50
64
  // - Embedded/bundled builds: injected define or env var.
51
65
  // - Dev/npm builds: package.json.
52
- export const VERSION = (typeof __CLAWDBOT_VERSION__ === "string" && __CLAWDBOT_VERSION__) ||
66
+ export const VERSION = (typeof __POOLBOT_VERSION__ === "string" && __POOLBOT_VERSION__) ||
53
67
  process.env.POOLBOT_BUNDLED_VERSION ||
54
- process.env.CLAWDBOT_BUNDLED_VERSION ||
55
68
  resolveVersionFromModuleUrl(import.meta.url) ||
56
69
  "0.0.0";
@@ -4,10 +4,12 @@ import { formatError } from "../../session.js";
4
4
  import { whatsappInboundLog } from "../loggers.js";
5
5
  export async function maybeBroadcastMessage(params) {
6
6
  const broadcastAgents = params.cfg.broadcast?.[params.peerId];
7
- if (!broadcastAgents || !Array.isArray(broadcastAgents))
7
+ if (!broadcastAgents || !Array.isArray(broadcastAgents)) {
8
8
  return false;
9
- if (broadcastAgents.length === 0)
9
+ }
10
+ if (broadcastAgents.length === 0) {
10
11
  return false;
12
+ }
11
13
  const strategy = params.cfg.broadcast?.strategy || "parallel";
12
14
  whatsappInboundLog.info(`Broadcasting message to ${broadcastAgents.length} agents (${strategy})`);
13
15
  const agentIds = params.cfg.agents?.list?.map((agent) => normalizeAgentId(agent.id));
@@ -27,11 +29,13 @@ export async function maybeBroadcastMessage(params) {
27
29
  sessionKey: buildAgentSessionKey({
28
30
  agentId: normalizedAgentId,
29
31
  channel: "whatsapp",
32
+ accountId: params.route.accountId,
30
33
  peer: {
31
- kind: params.msg.chatType === "group" ? "group" : "dm",
34
+ kind: params.msg.chatType === "group" ? "group" : "direct",
32
35
  id: params.peerId,
33
36
  },
34
37
  dmScope: params.cfg.session?.dmScope,
38
+ identityLinks: params.cfg.session?.identityLinks,
35
39
  }),
36
40
  mainSessionKey: buildAgentMainSessionKey({
37
41
  agentId: normalizedAgentId,
@@ -1,3 +1,4 @@
1
+ import { loadConfig } from "../../../config/config.js";
1
2
  import { logVerbose } from "../../../globals.js";
2
3
  import { resolveAgentRoute } from "../../../routing/resolve-route.js";
3
4
  import { buildGroupHistoryKey } from "../../../routing/session-key.js";
@@ -31,12 +32,13 @@ export function createWebOnMessageHandler(params) {
31
32
  return async (msg) => {
32
33
  const conversationId = msg.conversationId ?? msg.from;
33
34
  const peerId = resolvePeerId(msg);
35
+ // Fresh config for bindings lookup; other routing inputs are payload-derived.
34
36
  const route = resolveAgentRoute({
35
- cfg: params.cfg,
37
+ cfg: loadConfig(),
36
38
  channel: "whatsapp",
37
39
  accountId: msg.accountId,
38
40
  peer: {
39
- kind: msg.chatType === "group" ? "group" : "dm",
41
+ kind: msg.chatType === "group" ? "group" : "direct",
40
42
  id: peerId,
41
43
  },
42
44
  });
@@ -101,8 +103,9 @@ export function createWebOnMessageHandler(params) {
101
103
  logVerbose,
102
104
  replyLogger: params.replyLogger,
103
105
  });
104
- if (!gating.shouldProcess)
106
+ if (!gating.shouldProcess) {
105
107
  return;
108
+ }
106
109
  }
107
110
  else {
108
111
  // Ensure `peerId` for DMs is stable and stored as E.164 when possible.
@@ -4,16 +4,42 @@ function unwrapMessage(message) {
4
4
  const normalized = normalizeMessageContent(message);
5
5
  return normalized;
6
6
  }
7
- export async function downloadInboundMedia(msg, sock) {
8
- const message = unwrapMessage(msg.message);
9
- if (!message)
10
- return undefined;
11
- const mimetype = message.imageMessage?.mimetype ??
7
+ /**
8
+ * Resolve the MIME type for an inbound media message.
9
+ * Falls back to WhatsApp's standard formats when Baileys omits the MIME.
10
+ */
11
+ function resolveMediaMimetype(message) {
12
+ const explicit = message.imageMessage?.mimetype ??
12
13
  message.videoMessage?.mimetype ??
13
14
  message.documentMessage?.mimetype ??
14
15
  message.audioMessage?.mimetype ??
15
16
  message.stickerMessage?.mimetype ??
16
17
  undefined;
18
+ if (explicit) {
19
+ return explicit;
20
+ }
21
+ // WhatsApp voice messages (PTT) and audio use OGG Opus by default
22
+ if (message.audioMessage) {
23
+ return "audio/ogg; codecs=opus";
24
+ }
25
+ if (message.imageMessage) {
26
+ return "image/jpeg";
27
+ }
28
+ if (message.videoMessage) {
29
+ return "video/mp4";
30
+ }
31
+ if (message.stickerMessage) {
32
+ return "image/webp";
33
+ }
34
+ return undefined;
35
+ }
36
+ export async function downloadInboundMedia(msg, sock) {
37
+ const message = unwrapMessage(msg.message);
38
+ if (!message) {
39
+ return undefined;
40
+ }
41
+ const mimetype = resolveMediaMimetype(message);
42
+ const fileName = message.documentMessage?.fileName ?? undefined;
17
43
  if (!message.imageMessage &&
18
44
  !message.videoMessage &&
19
45
  !message.documentMessage &&
@@ -22,11 +48,11 @@ export async function downloadInboundMedia(msg, sock) {
22
48
  return undefined;
23
49
  }
24
50
  try {
25
- const buffer = (await downloadMediaMessage(msg, "buffer", {}, {
51
+ const buffer = await downloadMediaMessage(msg, "buffer", {}, {
26
52
  reuploadRequest: sock.updateMediaMessage,
27
53
  logger: sock.logger,
28
- }));
29
- return { buffer, mimetype };
54
+ });
55
+ return { buffer, mimetype, fileName };
30
56
  }
31
57
  catch (err) {
32
58
  logVerbose(`downloadMediaMessage failed: ${String(err)}`);
@@ -1,11 +1,11 @@
1
1
  import { DisconnectReason, isJidGroup } from "@whiskeysockets/baileys";
2
+ import { createInboundDebouncer } from "../../auto-reply/inbound-debounce.js";
2
3
  import { formatLocationText } from "../../channels/location.js";
3
4
  import { logVerbose, shouldLogVerbose } from "../../globals.js";
4
5
  import { recordChannelActivity } from "../../infra/channel-activity.js";
5
6
  import { getChildLogger } from "../../logging/logger.js";
6
7
  import { createSubsystemLogger } from "../../logging/subsystem.js";
7
8
  import { saveMediaBuffer } from "../../media/store.js";
8
- import { createInboundDebouncer } from "../../auto-reply/inbound-debounce.js";
9
9
  import { jidToE164, resolveJidToE164 } from "../../utils.js";
10
10
  import { createWaSocket, getStatusCode, waitForWaConnection } from "../session.js";
11
11
  import { checkInboundAccessControl } from "./access-control.js";
@@ -26,16 +26,18 @@ export async function monitorWebInbox(options) {
26
26
  onCloseResolve = resolve;
27
27
  });
28
28
  const resolveClose = (reason) => {
29
- if (!onCloseResolve)
29
+ if (!onCloseResolve) {
30
30
  return;
31
+ }
31
32
  const resolver = onCloseResolve;
32
33
  onCloseResolve = null;
33
34
  resolver(reason);
34
35
  };
35
36
  try {
36
37
  await sock.sendPresenceUpdate("available");
37
- if (shouldLogVerbose())
38
+ if (shouldLogVerbose()) {
38
39
  logVerbose("Sent global 'available' presence on connect");
40
+ }
39
41
  }
40
42
  catch (err) {
41
43
  logVerbose(`Failed to send 'available' presence on connect: ${String(err)}`);
@@ -48,24 +50,27 @@ export async function monitorWebInbox(options) {
48
50
  const senderKey = msg.chatType === "group"
49
51
  ? (msg.senderJid ?? msg.senderE164 ?? msg.senderName ?? msg.from)
50
52
  : msg.from;
51
- if (!senderKey)
53
+ if (!senderKey) {
52
54
  return null;
55
+ }
53
56
  const conversationKey = msg.chatType === "group" ? msg.chatId : msg.from;
54
57
  return `${msg.accountId}:${conversationKey}:${senderKey}`;
55
58
  },
56
59
  shouldDebounce: options.shouldDebounce,
57
60
  onFlush: async (entries) => {
58
61
  const last = entries.at(-1);
59
- if (!last)
62
+ if (!last) {
60
63
  return;
64
+ }
61
65
  if (entries.length === 1) {
62
66
  await options.onMessage(last);
63
67
  return;
64
68
  }
65
69
  const mentioned = new Set();
66
70
  for (const entry of entries) {
67
- for (const jid of entry.mentionedJids ?? [])
71
+ for (const jid of entry.mentionedJids ?? []) {
68
72
  mentioned.add(jid);
73
+ }
69
74
  }
70
75
  const combinedBody = entries
71
76
  .map((entry) => entry.body)
@@ -89,8 +94,9 @@ export async function monitorWebInbox(options) {
89
94
  const resolveInboundJid = async (jid) => resolveJidToE164(jid, { authDir: options.authDir, lidLookup });
90
95
  const getGroupMeta = async (jid) => {
91
96
  const cached = groupMetaCache.get(jid);
92
- if (cached && cached.expires > Date.now())
97
+ if (cached && cached.expires > Date.now()) {
93
98
  return cached;
99
+ }
94
100
  try {
95
101
  const meta = await sock.groupMetadata(jid);
96
102
  const participants = (await Promise.all(meta.participants?.map(async (p) => {
@@ -111,8 +117,9 @@ export async function monitorWebInbox(options) {
111
117
  }
112
118
  };
113
119
  const handleMessagesUpsert = async (upsert) => {
114
- if (upsert.type !== "notify" && upsert.type !== "append")
120
+ if (upsert.type !== "notify" && upsert.type !== "append") {
115
121
  return;
122
+ }
116
123
  for (const msg of upsert.messages ?? []) {
117
124
  recordChannelActivity({
118
125
  channel: "whatsapp",
@@ -121,20 +128,24 @@ export async function monitorWebInbox(options) {
121
128
  });
122
129
  const id = msg.key?.id ?? undefined;
123
130
  const remoteJid = msg.key?.remoteJid;
124
- if (!remoteJid)
131
+ if (!remoteJid) {
125
132
  continue;
126
- if (remoteJid.endsWith("@status") || remoteJid.endsWith("@broadcast"))
133
+ }
134
+ if (remoteJid.endsWith("@status") || remoteJid.endsWith("@broadcast")) {
127
135
  continue;
136
+ }
128
137
  const group = isJidGroup(remoteJid) === true;
129
138
  if (id) {
130
139
  const dedupeKey = `${options.accountId}:${remoteJid}:${id}`;
131
- if (isRecentInboundMessage(dedupeKey))
140
+ if (isRecentInboundMessage(dedupeKey)) {
132
141
  continue;
142
+ }
133
143
  }
134
144
  const participantJid = msg.key?.participant ?? undefined;
135
145
  const from = group ? remoteJid : await resolveInboundJid(remoteJid);
136
- if (!from)
146
+ if (!from) {
137
147
  continue;
148
+ }
138
149
  const senderE164 = group
139
150
  ? participantJid
140
151
  ? await resolveInboundJid(participantJid)
@@ -163,8 +174,9 @@ export async function monitorWebInbox(options) {
163
174
  sock: { sendMessage: (jid, content) => sock.sendMessage(jid, content) },
164
175
  remoteJid,
165
176
  });
166
- if (!access.allowed)
177
+ if (!access.allowed) {
167
178
  continue;
179
+ }
168
180
  if (id && !access.isSelfChat && options.sendReadReceipts !== false) {
169
181
  const participant = msg.key?.participant;
170
182
  try {
@@ -183,8 +195,9 @@ export async function monitorWebInbox(options) {
183
195
  logVerbose(`Self-chat mode: skipping read receipt for ${id}`);
184
196
  }
185
197
  // If this is history/offline catch-up, mark read above but skip auto-reply.
186
- if (upsert.type === "append")
198
+ if (upsert.type === "append") {
187
199
  continue;
200
+ }
188
201
  const location = extractLocationData(msg.message ?? undefined);
189
202
  const locationText = location ? formatLocationText(location) : undefined;
190
203
  let body = extractText(msg.message ?? undefined);
@@ -193,12 +206,14 @@ export async function monitorWebInbox(options) {
193
206
  }
194
207
  if (!body) {
195
208
  body = extractMediaPlaceholder(msg.message ?? undefined);
196
- if (!body)
209
+ if (!body) {
197
210
  continue;
211
+ }
198
212
  }
199
213
  const replyContext = describeReplyContext(msg.message);
200
214
  let mediaPath;
201
215
  let mediaType;
216
+ let mediaFileName;
202
217
  try {
203
218
  const inboundMedia = await downloadInboundMedia(msg, sock);
204
219
  if (inboundMedia) {
@@ -206,9 +221,10 @@ export async function monitorWebInbox(options) {
206
221
  ? options.mediaMaxMb
207
222
  : 50;
208
223
  const maxBytes = maxMb * 1024 * 1024;
209
- const saved = await saveMediaBuffer(inboundMedia.buffer, inboundMedia.mimetype, "inbound", maxBytes);
224
+ const saved = await saveMediaBuffer(inboundMedia.buffer, inboundMedia.mimetype, "inbound", maxBytes, inboundMedia.fileName);
210
225
  mediaPath = saved.path;
211
226
  mediaType = inboundMedia.mimetype;
227
+ mediaFileName = inboundMedia.fileName;
212
228
  }
213
229
  }
214
230
  catch (err) {
@@ -232,7 +248,7 @@ export async function monitorWebInbox(options) {
232
248
  const timestamp = messageTimestampMs;
233
249
  const mentionedJids = extractMentionedJids(msg.message);
234
250
  const senderName = msg.pushName ?? undefined;
235
- inboundLogger.info({ from, to: selfE164 ?? "me", body, mediaPath, mediaType, timestamp }, "inbound message");
251
+ inboundLogger.info({ from, to: selfE164 ?? "me", body, mediaPath, mediaType, mediaFileName, timestamp }, "inbound message");
236
252
  const inboundMessage = {
237
253
  id,
238
254
  from,
@@ -263,6 +279,7 @@ export async function monitorWebInbox(options) {
263
279
  sendMedia,
264
280
  mediaPath,
265
281
  mediaType,
282
+ mediaFileName,
266
283
  };
267
284
  try {
268
285
  const task = Promise.resolve(debouncer.enqueue(inboundMessage));
@@ -1,5 +1,17 @@
1
1
  import { recordChannelActivity } from "../../infra/channel-activity.js";
2
2
  import { toWhatsappJid } from "../../utils.js";
3
+ function recordWhatsAppOutbound(accountId) {
4
+ recordChannelActivity({
5
+ channel: "whatsapp",
6
+ accountId,
7
+ direction: "outbound",
8
+ });
9
+ }
10
+ function resolveOutboundMessageId(result) {
11
+ return typeof result === "object" && result && "key" in result
12
+ ? String(result.key?.id ?? "unknown")
13
+ : "unknown";
14
+ }
3
15
  export function createWebSendApi(params) {
4
16
  return {
5
17
  sendMessage: async (to, text, mediaBuffer, mediaType, sendOptions) => {
@@ -26,9 +38,10 @@ export function createWebSendApi(params) {
26
38
  };
27
39
  }
28
40
  else {
41
+ const fileName = sendOptions?.fileName?.trim() || "file";
29
42
  payload = {
30
43
  document: mediaBuffer,
31
- fileName: "file",
44
+ fileName,
32
45
  caption: text || undefined,
33
46
  mimetype: mediaType,
34
47
  };
@@ -39,14 +52,8 @@ export function createWebSendApi(params) {
39
52
  }
40
53
  const result = await params.sock.sendMessage(jid, payload);
41
54
  const accountId = sendOptions?.accountId ?? params.defaultAccountId;
42
- recordChannelActivity({
43
- channel: "whatsapp",
44
- accountId,
45
- direction: "outbound",
46
- });
47
- const messageId = typeof result === "object" && result && "key" in result
48
- ? String(result.key?.id ?? "unknown")
49
- : "unknown";
55
+ recordWhatsAppOutbound(accountId);
56
+ const messageId = resolveOutboundMessageId(result);
50
57
  return { messageId };
51
58
  },
52
59
  sendPoll: async (to, poll) => {
@@ -58,14 +65,8 @@ export function createWebSendApi(params) {
58
65
  selectableCount: poll.maxSelections ?? 1,
59
66
  },
60
67
  });
61
- recordChannelActivity({
62
- channel: "whatsapp",
63
- accountId: params.defaultAccountId,
64
- direction: "outbound",
65
- });
66
- const messageId = typeof result === "object" && result && "key" in result
67
- ? String(result.key?.id ?? "unknown")
68
- : "unknown";
68
+ recordWhatsAppOutbound(params.defaultAccountId);
69
+ const messageId = resolveOutboundMessageId(result);
69
70
  return { messageId };
70
71
  },
71
72
  sendReaction: async (chatJid, messageId, emoji, fromMe, participant) => {
@@ -1,11 +1,12 @@
1
1
  import { randomUUID } from "node:crypto";
2
+ import { loadConfig } from "../config/config.js";
3
+ import { resolveMarkdownTableMode } from "../config/markdown-tables.js";
2
4
  import { getChildLogger } from "../logging/logger.js";
3
5
  import { createSubsystemLogger } from "../logging/subsystem.js";
6
+ import { convertMarkdownTables } from "../markdown/tables.js";
7
+ import { markdownToWhatsApp } from "../markdown/whatsapp.js";
4
8
  import { normalizePollInput } from "../polls.js";
5
9
  import { toWhatsappJid } from "../utils.js";
6
- import { loadConfig } from "../config/config.js";
7
- import { resolveMarkdownTableMode } from "../config/markdown-tables.js";
8
- import { convertMarkdownTables } from "../markdown/tables.js";
9
10
  import { requireActiveWebListener } from "./active-listener.js";
10
11
  import { loadWebMedia } from "./media.js";
11
12
  const outboundLog = createSubsystemLogger("gateway/channels/whatsapp").child("outbound");
@@ -21,6 +22,7 @@ export async function sendMessageWhatsApp(to, body, options) {
21
22
  accountId: resolvedAccountId ?? options.accountId,
22
23
  });
23
24
  text = convertMarkdownTables(text ?? "", tableMode);
25
+ text = markdownToWhatsApp(text);
24
26
  const logger = getChildLogger({
25
27
  module: "web-outbound",
26
28
  correlationId,
@@ -30,8 +32,11 @@ export async function sendMessageWhatsApp(to, body, options) {
30
32
  const jid = toWhatsappJid(to);
31
33
  let mediaBuffer;
32
34
  let mediaType;
35
+ let documentFileName;
33
36
  if (options.mediaUrl) {
34
- const media = await loadWebMedia(options.mediaUrl);
37
+ const media = await loadWebMedia(options.mediaUrl, {
38
+ localRoots: options.mediaLocalRoots,
39
+ });
35
40
  const caption = text || undefined;
36
41
  mediaBuffer = media.buffer;
37
42
  mediaType = media.contentType;
@@ -50,6 +55,7 @@ export async function sendMessageWhatsApp(to, body, options) {
50
55
  }
51
56
  else {
52
57
  text = caption ?? "";
58
+ documentFileName = media.fileName;
53
59
  }
54
60
  }
55
61
  outboundLog.info(`Sending message -> ${jid}${options.mediaUrl ? " (media)" : ""}`);
@@ -57,9 +63,10 @@ export async function sendMessageWhatsApp(to, body, options) {
57
63
  await active.sendComposingTo(to);
58
64
  const hasExplicitAccountId = Boolean(options.accountId?.trim());
59
65
  const accountId = hasExplicitAccountId ? resolvedAccountId : undefined;
60
- const sendOptions = options.gifPlayback || accountId
66
+ const sendOptions = options.gifPlayback || accountId || documentFileName
61
67
  ? {
62
68
  ...(options.gifPlayback ? { gifPlayback: true } : {}),
69
+ ...(documentFileName ? { fileName: documentFileName } : {}),
63
70
  accountId,
64
71
  }
65
72
  : undefined;
@@ -1,5 +1,6 @@
1
- import { cancel, confirm, intro, isCancel, multiselect, outro, select, spinner, text, } from "@clack/prompts";
1
+ import { autocompleteMultiselect, cancel, confirm, intro, isCancel, multiselect, outro, select, spinner, text, } from "@clack/prompts";
2
2
  import { createCliProgress } from "../cli/progress.js";
3
+ import { stripAnsi } from "../terminal/ansi.js";
3
4
  import { note as emitNote } from "../terminal/note.js";
4
5
  import { stylePromptHint, stylePromptMessage, stylePromptTitle } from "../terminal/prompt-style.js";
5
6
  import { theme } from "../terminal/theme.js";
@@ -11,6 +12,27 @@ function guardCancel(value) {
11
12
  }
12
13
  return value;
13
14
  }
15
+ function normalizeSearchTokens(search) {
16
+ return search
17
+ .toLowerCase()
18
+ .split(/\s+/)
19
+ .map((token) => token.trim())
20
+ .filter((token) => token.length > 0);
21
+ }
22
+ function buildOptionSearchText(option) {
23
+ const label = stripAnsi(option.label ?? "");
24
+ const hint = stripAnsi(option.hint ?? "");
25
+ const value = String(option.value ?? "");
26
+ return `${label} ${hint} ${value}`.toLowerCase();
27
+ }
28
+ export function tokenizedOptionFilter(search, option) {
29
+ const tokens = normalizeSearchTokens(search);
30
+ if (tokens.length === 0) {
31
+ return true;
32
+ }
33
+ const haystack = buildOptionSearchText(option);
34
+ return tokens.every((token) => haystack.includes(token));
35
+ }
14
36
  export function createClackPrompter() {
15
37
  return {
16
38
  intro: async (title) => {
@@ -30,14 +52,25 @@ export function createClackPrompter() {
30
52
  }),
31
53
  initialValue: params.initialValue,
32
54
  })),
33
- multiselect: async (params) => guardCancel(await multiselect({
34
- message: stylePromptMessage(params.message),
35
- options: params.options.map((opt) => {
55
+ multiselect: async (params) => {
56
+ const options = params.options.map((opt) => {
36
57
  const base = { value: opt.value, label: opt.label };
37
58
  return opt.hint === undefined ? base : { ...base, hint: stylePromptHint(opt.hint) };
38
- }),
39
- initialValues: params.initialValues,
40
- })),
59
+ });
60
+ if (params.searchable) {
61
+ return guardCancel(await autocompleteMultiselect({
62
+ message: stylePromptMessage(params.message),
63
+ options,
64
+ initialValues: params.initialValues,
65
+ filter: tokenizedOptionFilter,
66
+ }));
67
+ }
68
+ return guardCancel(await multiselect({
69
+ message: stylePromptMessage(params.message),
70
+ options,
71
+ initialValues: params.initialValues,
72
+ }));
73
+ },
41
74
  text: async (params) => {
42
75
  const validate = params.validate;
43
76
  return guardCancel(await text({