@poolzin/pool-bot 2026.2.21 → 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 (369) hide show
  1. package/CHANGELOG.md +17 -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-catalog.js +40 -9
  14. package/dist/agents/model-forward-compat.js +60 -23
  15. package/dist/agents/model-selection.js +134 -41
  16. package/dist/agents/pi-auth-json.js +2 -2
  17. package/dist/agents/pi-embedded-helpers/bootstrap.js +65 -15
  18. package/dist/agents/pi-embedded-helpers/errors.js +140 -15
  19. package/dist/agents/pi-embedded-helpers/images.js +22 -12
  20. package/dist/agents/pi-embedded-helpers.js +2 -2
  21. package/dist/agents/pi-embedded-runner/abort.js +10 -3
  22. package/dist/agents/pi-embedded-runner/compact.js +230 -32
  23. package/dist/agents/pi-embedded-runner/extra-params.js +203 -12
  24. package/dist/agents/pi-embedded-runner/google.js +109 -19
  25. package/dist/agents/pi-embedded-runner/history.js +35 -17
  26. package/dist/agents/pi-embedded-runner/run/attempt.js +386 -95
  27. package/dist/agents/pi-embedded-runner/run/images.js +81 -55
  28. package/dist/agents/pi-embedded-runner/run/payloads.js +89 -39
  29. package/dist/agents/pi-embedded-runner/run.js +193 -25
  30. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +2 -2
  31. package/dist/agents/pi-embedded-runner/runs.js +17 -8
  32. package/dist/agents/pi-embedded-runner/tool-result-context-guard.js +262 -0
  33. package/dist/agents/pi-embedded-runner.js +1 -1
  34. package/dist/agents/pi-embedded-subscribe.handlers.tools.js +180 -10
  35. package/dist/agents/pi-embedded-subscribe.js +37 -0
  36. package/dist/agents/pi-embedded-subscribe.tools.js +127 -30
  37. package/dist/agents/pi-model-discovery.js +9 -2
  38. package/dist/agents/pi-tool-definition-adapter.js +60 -8
  39. package/dist/agents/pi-tools.before-tool-call.js +1 -1
  40. package/dist/agents/pi-tools.js +113 -94
  41. package/dist/agents/pi-tools.read.js +337 -38
  42. package/dist/agents/poolbot-tools.js +14 -5
  43. package/dist/agents/sandbox/docker.js +10 -5
  44. package/dist/agents/sandbox/registry.js +96 -46
  45. package/dist/agents/sandbox/sanitize-env-vars.js +82 -0
  46. package/dist/agents/sandbox-paths.js +43 -10
  47. package/dist/agents/session-tool-result-guard-wrapper.js +23 -11
  48. package/dist/agents/session-tool-result-guard.js +39 -39
  49. package/dist/agents/session-transcript-repair.js +36 -33
  50. package/dist/agents/session-write-lock.js +62 -44
  51. package/dist/agents/skills/frontmatter.js +49 -88
  52. package/dist/agents/skills/workspace.js +335 -28
  53. package/dist/agents/subagent-announce.js +508 -174
  54. package/dist/agents/subagent-registry.js +45 -4
  55. package/dist/agents/subagent-spawn.js +16 -33
  56. package/dist/agents/system-prompt-report.js +27 -10
  57. package/dist/agents/system-prompt.js +26 -32
  58. package/dist/agents/tool-call-id.js +69 -17
  59. package/dist/agents/tool-display-common.js +1 -1
  60. package/dist/agents/tool-images.js +64 -31
  61. package/dist/agents/tools/canvas-tool.js +17 -11
  62. package/dist/agents/tools/common.js +37 -19
  63. package/dist/agents/tools/cron-tool.js +40 -38
  64. package/dist/agents/tools/gateway.js +70 -2
  65. package/dist/agents/tools/message-tool.js +181 -40
  66. package/dist/agents/tools/nodes-tool.js +128 -36
  67. package/dist/agents/tools/nodes-utils.js +12 -38
  68. package/dist/agents/tools/session-status-tool.js +24 -71
  69. package/dist/agents/tools/sessions-helpers.js +38 -210
  70. package/dist/agents/tools/sessions-spawn-tool.js +28 -198
  71. package/dist/agents/tools/telegram-actions.js +58 -7
  72. package/dist/agents/tools/web-fetch-utils.js +112 -7
  73. package/dist/agents/tools/web-fetch.js +279 -175
  74. package/dist/agents/tools/web-shared.js +71 -8
  75. package/dist/agents/usage.js +25 -16
  76. package/dist/auto-reply/commands-registry.data.js +85 -11
  77. package/dist/auto-reply/dispatch.js +40 -21
  78. package/dist/auto-reply/reply/abort.js +102 -33
  79. package/dist/auto-reply/reply/commands-core.js +82 -33
  80. package/dist/auto-reply/reply/commands-export-session.js +1 -1
  81. package/dist/auto-reply/reply/commands-info.js +41 -12
  82. package/dist/auto-reply/reply/commands-subagents.js +352 -100
  83. package/dist/auto-reply/reply/commands-system-prompt.js +2 -2
  84. package/dist/auto-reply/reply/dispatch-from-config.js +100 -29
  85. package/dist/auto-reply/reply/elevated-unavailable.js +1 -1
  86. package/dist/auto-reply/reply/inbound-meta.js +12 -1
  87. package/dist/auto-reply/reply/mentions.js +18 -11
  88. package/dist/auto-reply/reply/normalize-reply.js +17 -8
  89. package/dist/auto-reply/reply/reply-dispatcher.js +62 -10
  90. package/dist/auto-reply/reply/session.js +102 -21
  91. package/dist/auto-reply/reply/streaming-directives.js +16 -5
  92. package/dist/auto-reply/status.js +73 -50
  93. package/dist/browser/extension-relay.js +3 -3
  94. package/dist/browser/http-auth.js +1 -1
  95. package/dist/browser/paths.js +2 -2
  96. package/dist/build-info.json +3 -3
  97. package/dist/channels/allowlist-match.js +20 -0
  98. package/dist/channels/allowlists/resolve-utils.js +65 -2
  99. package/dist/channels/chat-type.js +8 -4
  100. package/dist/channels/dock.js +127 -35
  101. package/dist/channels/draft-stream-loop.js +6 -2
  102. package/dist/channels/plugins/actions/telegram.js +42 -18
  103. package/dist/channels/plugins/allowlist-match.js +1 -1
  104. package/dist/channels/plugins/group-mentions.js +51 -41
  105. package/dist/channels/plugins/message-action-names.js +2 -0
  106. package/dist/channels/plugins/message-actions.js +24 -5
  107. package/dist/channels/plugins/normalize/discord.js +26 -4
  108. package/dist/channels/plugins/normalize/signal.js +35 -22
  109. package/dist/channels/plugins/onboarding/helpers.js +8 -26
  110. package/dist/channels/plugins/outbound/imessage.js +15 -14
  111. package/dist/channels/registry.js +20 -7
  112. package/dist/cli/acp-cli.js +7 -5
  113. package/dist/cli/browser-cli-extension.js +25 -12
  114. package/dist/cli/browser-cli-state.cookies-storage.js +25 -6
  115. package/dist/cli/browser-cli-state.js +101 -145
  116. package/dist/cli/command-options.js +28 -0
  117. package/dist/cli/completion-cli.js +6 -6
  118. package/dist/cli/cron-cli/register.cron-add.js +25 -1
  119. package/dist/cli/cron-cli/register.cron-edit.js +44 -0
  120. package/dist/cli/cron-cli/shared.js +7 -1
  121. package/dist/cli/daemon-cli/lifecycle-core.js +23 -21
  122. package/dist/cli/daemon-cli/lifecycle.js +23 -247
  123. package/dist/cli/daemon-cli/register-service-commands.js +25 -4
  124. package/dist/cli/daemon-cli.js +1 -0
  125. package/dist/cli/devices-cli.js +33 -20
  126. package/dist/cli/gateway-cli/register.js +37 -105
  127. package/dist/cli/gateway-cli/run.js +49 -11
  128. package/dist/cli/nodes-camera.js +59 -4
  129. package/dist/cli/nodes-cli/register.camera.js +27 -24
  130. package/dist/cli/nodes-cli/rpc.js +21 -38
  131. package/dist/cli/qr-cli.js +2 -2
  132. package/dist/cli/skills-cli.format.js +2 -2
  133. package/dist/cli/update-cli/progress.js +2 -2
  134. package/dist/cli/update-cli/restart-helper.js +28 -7
  135. package/dist/cli/update-cli/shared.js +7 -7
  136. package/dist/cli/update-cli/status.js +1 -1
  137. package/dist/cli/update-cli/update-command.js +14 -8
  138. package/dist/cli/update-cli/wizard.js +2 -2
  139. package/dist/cli/update-cli.js +21 -1027
  140. package/dist/commands/auth-choice.apply.anthropic.js +10 -2
  141. package/dist/commands/channels/add-mutators.js +3 -35
  142. package/dist/commands/channels/add.js +39 -51
  143. package/dist/commands/config-validation.js +1 -1
  144. package/dist/commands/configure.gateway-auth.js +52 -15
  145. package/dist/commands/configure.gateway.js +84 -40
  146. package/dist/commands/doctor-completion.js +3 -3
  147. package/dist/commands/doctor-config-flow.js +536 -16
  148. package/dist/commands/doctor-gateway-services.js +103 -79
  149. package/dist/commands/doctor-memory-search.js +9 -9
  150. package/dist/commands/doctor-platform-notes.js +57 -30
  151. package/dist/commands/doctor-prompter.js +26 -15
  152. package/dist/commands/doctor-session-locks.js +1 -1
  153. package/dist/commands/doctor.js +21 -9
  154. package/dist/commands/model-picker.js +120 -95
  155. package/dist/commands/models/set.js +2 -21
  156. package/dist/commands/models/shared.js +65 -37
  157. package/dist/commands/onboard-helpers.js +81 -39
  158. package/dist/commands/openai-codex-oauth.js +1 -1
  159. package/dist/commands/sessions.js +52 -53
  160. package/dist/commands/status.summary.js +52 -34
  161. package/dist/commands/test-wizard-helpers.js +2 -2
  162. package/dist/config/defaults.js +79 -42
  163. package/dist/config/group-policy.js +50 -18
  164. package/dist/config/includes.js +37 -10
  165. package/dist/config/schema.help.js +5 -4
  166. package/dist/config/schema.hints.js +2 -2
  167. package/dist/config/schema.labels.js +1 -0
  168. package/dist/config/sessions/group.js +12 -11
  169. package/dist/config/sessions/paths.js +137 -11
  170. package/dist/config/sessions/store.js +185 -65
  171. package/dist/config/sessions/types.js +15 -1
  172. package/dist/config/sessions.js +1 -0
  173. package/dist/config/telegram-custom-commands.js +3 -2
  174. package/dist/config/types.js +2 -0
  175. package/dist/config/zod-schema.agent-defaults.js +6 -27
  176. package/dist/config/zod-schema.agent-runtime.js +171 -79
  177. package/dist/config/zod-schema.providers-core.js +138 -65
  178. package/dist/config/zod-schema.session.js +49 -22
  179. package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
  180. package/dist/cron/isolated-agent/run.js +224 -57
  181. package/dist/cron/normalize.js +48 -45
  182. package/dist/cron/run-log.js +14 -0
  183. package/dist/cron/service/jobs.js +190 -28
  184. package/dist/cron/service/normalize.js +29 -11
  185. package/dist/cron/service/store.js +30 -44
  186. package/dist/cron/service/timer.js +182 -96
  187. package/dist/cron/service.js +3 -0
  188. package/dist/cron/stagger.js +37 -0
  189. package/dist/daemon/inspect.js +132 -92
  190. package/dist/daemon/runtime-paths.js +25 -4
  191. package/dist/daemon/service-audit.js +47 -16
  192. package/dist/discord/accounts.js +23 -20
  193. package/dist/discord/monitor/agent-components.js +1115 -219
  194. package/dist/discord/monitor/allow-list.js +114 -34
  195. package/dist/discord/monitor/listeners.js +204 -97
  196. package/dist/discord/monitor/message-handler.js +21 -10
  197. package/dist/discord/monitor/message-handler.preflight.js +195 -101
  198. package/dist/discord/monitor/message-handler.process.js +384 -123
  199. package/dist/discord/monitor/message-utils.js +86 -23
  200. package/dist/discord/monitor/native-command.js +77 -57
  201. package/dist/discord/monitor/provider.js +122 -117
  202. package/dist/discord/monitor/reply-context.js +20 -16
  203. package/dist/discord/monitor/reply-delivery.js +40 -8
  204. package/dist/discord/monitor/rest-fetch.js +22 -0
  205. package/dist/discord/monitor/threading.js +117 -24
  206. package/dist/discord/send.js +2 -1
  207. package/dist/discord/send.outbound.js +124 -11
  208. package/dist/discord/send.shared.js +112 -72
  209. package/dist/discord/voice-message.js +3 -3
  210. package/dist/gateway/auth.js +119 -44
  211. package/dist/gateway/call.js +76 -34
  212. package/dist/gateway/channel-health-monitor.js +57 -50
  213. package/dist/gateway/client.js +63 -29
  214. package/dist/gateway/control-ui-contract.js +1 -1
  215. package/dist/gateway/gateway-config-prompts.shared.js +2 -2
  216. package/dist/gateway/net.js +109 -1
  217. package/dist/gateway/protocol/index.js +5 -8
  218. package/dist/gateway/protocol/schema/agent.js +19 -1
  219. package/dist/gateway/protocol/schema/channels.js +21 -0
  220. package/dist/gateway/protocol/schema/cron.js +43 -30
  221. package/dist/gateway/protocol/schema/protocol-schemas.js +6 -11
  222. package/dist/gateway/protocol/schema/sessions.js +5 -1
  223. package/dist/gateway/protocol/schema.js +0 -1
  224. package/dist/gateway/server/presence-events.js +12 -0
  225. package/dist/gateway/server/ws-connection/message-handler.js +203 -212
  226. package/dist/gateway/server/ws-connection.js +58 -21
  227. package/dist/gateway/server-broadcast.js +18 -13
  228. package/dist/gateway/server-cron.js +177 -10
  229. package/dist/gateway/server-methods/agent-job.js +131 -38
  230. package/dist/gateway/server-methods/send.js +60 -14
  231. package/dist/gateway/server-methods/sessions.js +160 -96
  232. package/dist/gateway/server-methods/system.js +5 -7
  233. package/dist/gateway/server-methods-list.js +8 -0
  234. package/dist/gateway/server-methods.js +24 -8
  235. package/dist/gateway/server-node-events.js +278 -68
  236. package/dist/gateway/session-utils.fs.js +316 -75
  237. package/dist/gateway/session-utils.js +224 -70
  238. package/dist/gateway/sessions-patch.js +63 -20
  239. package/dist/gateway/test-temp-config.js +1 -1
  240. package/dist/gateway/tools-invoke-http.js +118 -70
  241. package/dist/gateway/ws-log.js +135 -107
  242. package/dist/hooks/frontmatter.js +36 -82
  243. package/dist/hooks/install.js +149 -139
  244. package/dist/hooks/internal-hooks.js +29 -4
  245. package/dist/hooks/plugin-hooks.js +2 -1
  246. package/dist/imessage/monitor/deliver.js +10 -4
  247. package/dist/imessage/monitor/monitor-provider.js +138 -375
  248. package/dist/imessage/monitor/runtime.js +4 -8
  249. package/dist/imessage/send.js +65 -19
  250. package/dist/infra/exec-approvals-allowlist.js +7 -0
  251. package/dist/infra/exec-approvals.js +35 -920
  252. package/dist/infra/exec-safe-bin-trust.js +64 -0
  253. package/dist/infra/heartbeat-runner.js +207 -134
  254. package/dist/infra/heartbeat-wake.js +183 -22
  255. package/dist/infra/install-source-utils.js +47 -0
  256. package/dist/infra/net/ssrf.js +170 -36
  257. package/dist/infra/outbound/deliver.js +224 -58
  258. package/dist/infra/outbound/message-action-spec.js +12 -5
  259. package/dist/infra/outbound/outbound-session.js +27 -25
  260. package/dist/infra/poolbot-root.js +32 -22
  261. package/dist/infra/ports.js +14 -11
  262. package/dist/infra/skills-remote.js +48 -37
  263. package/dist/infra/system-events.js +25 -11
  264. package/dist/infra/system-presence.js +26 -33
  265. package/dist/infra/tmp-poolbot-dir.js +81 -2
  266. package/dist/infra/wsl.js +37 -1
  267. package/dist/line/bot-message-context.js +163 -191
  268. package/dist/logging/subsystem.js +59 -22
  269. package/dist/markdown/ir.js +124 -50
  270. package/dist/media/store.js +1 -1
  271. package/dist/media-understanding/runner.entries.js +42 -25
  272. package/dist/media-understanding/runner.js +53 -488
  273. package/dist/memory/embeddings-gemini.js +53 -38
  274. package/dist/memory/manager-embedding-ops.js +48 -69
  275. package/dist/pairing/pairing-store.js +178 -119
  276. package/dist/plugin-sdk/index.js +34 -6
  277. package/dist/plugins/hooks.js +135 -14
  278. package/dist/plugins/install.js +190 -152
  279. package/dist/polls.js +11 -0
  280. package/dist/routing/resolve-route.js +190 -56
  281. package/dist/routing/session-key.js +38 -22
  282. package/dist/runtime.js +35 -9
  283. package/dist/security/audit-channel.js +1 -1
  284. package/dist/sessions/session-key-utils.js +29 -11
  285. package/dist/shared/frontmatter.js +5 -5
  286. package/dist/shared/node-list-types.js +1 -0
  287. package/dist/shared/string-normalization.js +15 -0
  288. package/dist/signal/monitor/event-handler.js +68 -36
  289. package/dist/signal/send.js +29 -37
  290. package/dist/slack/monitor/allow-list.js +10 -11
  291. package/dist/slack/monitor/commands.js +14 -3
  292. package/dist/slack/monitor/events/interactions.js +4 -4
  293. package/dist/slack/monitor/media.js +224 -16
  294. package/dist/slack/monitor/message-handler/dispatch.js +247 -13
  295. package/dist/slack/monitor/message-handler/prepare.js +128 -45
  296. package/dist/slack/monitor/slash.js +357 -144
  297. package/dist/slack/streaming.js +77 -0
  298. package/dist/telegram/accounts.js +40 -13
  299. package/dist/telegram/allowed-updates.js +3 -0
  300. package/dist/telegram/bot/delivery.js +129 -66
  301. package/dist/telegram/bot/helpers.js +136 -122
  302. package/dist/telegram/bot-handlers.js +600 -339
  303. package/dist/telegram/bot-message-context.js +115 -73
  304. package/dist/telegram/bot-message-dispatch.js +235 -104
  305. package/dist/telegram/bot-native-command-menu.js +3 -1
  306. package/dist/telegram/bot-native-commands.js +213 -193
  307. package/dist/telegram/bot.js +24 -132
  308. package/dist/telegram/draft-stream.js +84 -75
  309. package/dist/telegram/format.js +150 -6
  310. package/dist/telegram/send.js +415 -255
  311. package/dist/telegram/targets.js +21 -2
  312. package/dist/telegram/update-offset-store.js +19 -3
  313. package/dist/terminal/restore.js +5 -2
  314. package/dist/test-utils/fetch-mock.js +5 -0
  315. package/dist/version.js +18 -5
  316. package/dist/web/auto-reply/monitor/broadcast.js +7 -3
  317. package/dist/web/auto-reply/monitor/on-message.js +6 -3
  318. package/dist/web/inbound/media.js +34 -8
  319. package/dist/web/inbound/monitor.js +34 -17
  320. package/dist/web/inbound/send-api.js +18 -17
  321. package/dist/web/outbound.js +12 -5
  322. package/dist/wizard/clack-prompter.js +40 -7
  323. package/extensions/bluebubbles/package.json +1 -1
  324. package/extensions/copilot-proxy/package.json +1 -1
  325. package/extensions/diagnostics-otel/package.json +1 -1
  326. package/extensions/discord/package.json +1 -1
  327. package/extensions/feishu/package.json +1 -1
  328. package/extensions/google-antigravity-auth/package.json +1 -1
  329. package/extensions/google-gemini-cli-auth/package.json +1 -1
  330. package/extensions/googlechat/package.json +1 -1
  331. package/extensions/imessage/package.json +1 -1
  332. package/extensions/irc/package.json +1 -1
  333. package/extensions/line/package.json +1 -1
  334. package/extensions/llm-task/package.json +1 -1
  335. package/extensions/lobster/package.json +1 -1
  336. package/extensions/matrix/CHANGELOG.md +5 -0
  337. package/extensions/matrix/package.json +1 -1
  338. package/extensions/mattermost/package.json +1 -1
  339. package/extensions/memory-core/package.json +1 -1
  340. package/extensions/memory-lancedb/package.json +1 -1
  341. package/extensions/minimax-portal-auth/package.json +1 -1
  342. package/extensions/msteams/CHANGELOG.md +5 -0
  343. package/extensions/msteams/package.json +1 -1
  344. package/extensions/nextcloud-talk/package.json +1 -1
  345. package/extensions/nostr/CHANGELOG.md +5 -0
  346. package/extensions/nostr/package.json +1 -1
  347. package/extensions/open-prose/package.json +1 -1
  348. package/extensions/openai-codex-auth/package.json +1 -1
  349. package/extensions/signal/package.json +1 -1
  350. package/extensions/slack/package.json +1 -1
  351. package/extensions/telegram/package.json +1 -1
  352. package/extensions/tlon/package.json +1 -1
  353. package/extensions/twitch/CHANGELOG.md +5 -0
  354. package/extensions/twitch/package.json +1 -1
  355. package/extensions/voice-call/CHANGELOG.md +5 -0
  356. package/extensions/voice-call/package.json +1 -1
  357. package/extensions/whatsapp/package.json +1 -1
  358. package/extensions/zalo/CHANGELOG.md +5 -0
  359. package/extensions/zalo/package.json +1 -1
  360. package/extensions/zalouser/CHANGELOG.md +5 -0
  361. package/extensions/zalouser/package.json +1 -1
  362. package/package.json +1 -1
  363. package/skills/apple-reminders/SKILL.md +100 -49
  364. package/skills/coding-agent/SKILL.md +34 -28
  365. package/skills/github/SKILL.md +131 -16
  366. package/skills/imsg/SKILL.md +112 -15
  367. package/skills/openhue/SKILL.md +101 -19
  368. package/skills/tmux/SKILL.md +111 -79
  369. package/skills/weather/SKILL.md +88 -25
@@ -1,5 +1,30 @@
1
1
  import { formatLocationText } from "../../channels/location.js";
2
+ import { readChannelAllowFromStore } from "../../pairing/pairing-store.js";
3
+ import { firstDefined, normalizeAllowFromWithStore, } from "../bot-access.js";
2
4
  const TELEGRAM_GENERAL_TOPIC_ID = 1;
5
+ export async function resolveTelegramGroupAllowFromContext(params) {
6
+ const resolvedThreadId = resolveTelegramForumThreadId({
7
+ isForum: params.isForum,
8
+ messageThreadId: params.messageThreadId,
9
+ });
10
+ const storeAllowFrom = await readChannelAllowFromStore("telegram", process.env, params.accountId).catch(() => []);
11
+ const { groupConfig, topicConfig } = params.resolveTelegramGroupConfig(params.chatId, resolvedThreadId);
12
+ const groupAllowOverride = firstDefined(topicConfig?.allowFrom, groupConfig?.allowFrom);
13
+ const effectiveGroupAllow = normalizeAllowFromWithStore({
14
+ allowFrom: groupAllowOverride ?? params.groupAllowFrom,
15
+ storeAllowFrom,
16
+ });
17
+ const hasGroupAllowOverride = typeof groupAllowOverride !== "undefined";
18
+ return {
19
+ resolvedThreadId,
20
+ storeAllowFrom,
21
+ groupConfig,
22
+ topicConfig,
23
+ groupAllowOverride,
24
+ effectiveGroupAllow,
25
+ hasGroupAllowOverride,
26
+ };
27
+ }
3
28
  /**
4
29
  * Resolve the thread ID for Telegram forum topics.
5
30
  * For non-forum groups, returns undefined even if messageThreadId is present
@@ -38,30 +63,28 @@ export function resolveTelegramThreadSpec(params) {
38
63
  }
39
64
  /**
40
65
  * Build thread params for Telegram API calls (messages, media).
66
+ *
67
+ * IMPORTANT: Thread IDs behave differently based on chat type:
68
+ * - DMs (private chats): Include message_thread_id when present (DM topics)
69
+ * - Forum topics: Skip thread_id=1 (General topic), include others
70
+ * - Regular groups: Thread IDs are ignored by Telegram
71
+ *
41
72
  * General forum topic (id=1) must be treated like a regular supergroup send:
42
73
  * Telegram rejects sendMessage/sendMedia with message_thread_id=1 ("thread not found").
43
74
  *
44
- * Accepts either a TelegramThreadSpec (preferred) or a raw messageThreadId number
45
- * for backward compatibility with callers that haven't migrated yet.
75
+ * @param thread - Thread specification with ID and scope
76
+ * @returns API params object or undefined if thread_id should be omitted
46
77
  */
47
- export function buildTelegramThreadParams(threadOrId) {
48
- if (threadOrId == null) {
78
+ export function buildTelegramThreadParams(thread) {
79
+ if (thread?.id == null) {
49
80
  return undefined;
50
81
  }
51
- // Legacy call: raw number
52
- if (typeof threadOrId === "number") {
53
- const normalized = Math.trunc(threadOrId);
54
- if (normalized === TELEGRAM_GENERAL_TOPIC_ID) {
55
- return undefined;
56
- }
57
- return { message_thread_id: normalized };
58
- }
59
- // New call: TelegramThreadSpec
60
- if (!threadOrId.id) {
61
- return undefined;
82
+ const normalized = Math.trunc(thread.id);
83
+ if (thread.scope === "dm") {
84
+ return normalized > 0 ? { message_thread_id: normalized } : undefined;
62
85
  }
63
- const normalized = Math.trunc(threadOrId.id);
64
- if (normalized === TELEGRAM_GENERAL_TOPIC_ID && threadOrId.scope === "forum") {
86
+ // Telegram rejects message_thread_id=1 for General forum topic
87
+ if (normalized === TELEGRAM_GENERAL_TOPIC_ID) {
65
88
  return undefined;
66
89
  }
67
90
  return { message_thread_id: normalized };
@@ -78,8 +101,9 @@ export function buildTypingThreadParams(messageThreadId) {
78
101
  }
79
102
  export function resolveTelegramStreamMode(telegramCfg) {
80
103
  const raw = telegramCfg?.streamMode?.trim().toLowerCase();
81
- if (raw === "off" || raw === "partial" || raw === "block")
104
+ if (raw === "off" || raw === "partial" || raw === "block") {
82
105
  return raw;
106
+ }
83
107
  return "partial";
84
108
  }
85
109
  export function buildTelegramGroupPeerId(chatId, messageThreadId) {
@@ -106,6 +130,27 @@ export function buildSenderName(msg) {
106
130
  msg.from?.username;
107
131
  return name || undefined;
108
132
  }
133
+ export function resolveTelegramMediaPlaceholder(msg) {
134
+ if (!msg) {
135
+ return undefined;
136
+ }
137
+ if (msg.photo) {
138
+ return "<media:image>";
139
+ }
140
+ if (msg.video || msg.video_note) {
141
+ return "<media:video>";
142
+ }
143
+ if (msg.audio || msg.voice) {
144
+ return "<media:audio>";
145
+ }
146
+ if (msg.document) {
147
+ return "<media:document>";
148
+ }
149
+ if (msg.sticker) {
150
+ return "<media:sticker>";
151
+ }
152
+ return undefined;
153
+ }
109
154
  export function buildSenderLabel(msg, senderId) {
110
155
  const name = buildSenderName(msg);
111
156
  const username = msg.from?.username ? `@${msg.from.username}` : undefined;
@@ -119,41 +164,49 @@ export function buildSenderLabel(msg, senderId) {
119
164
  const normalizedSenderId = senderId != null && `${senderId}`.trim() ? `${senderId}`.trim() : undefined;
120
165
  const fallbackId = normalizedSenderId ?? (msg.from?.id != null ? String(msg.from.id) : undefined);
121
166
  const idPart = fallbackId ? `id:${fallbackId}` : undefined;
122
- if (label && idPart)
167
+ if (label && idPart) {
123
168
  return `${label} ${idPart}`;
124
- if (label)
169
+ }
170
+ if (label) {
125
171
  return label;
172
+ }
126
173
  return idPart ?? "id:unknown";
127
174
  }
128
175
  export function buildGroupLabel(msg, chatId, messageThreadId) {
129
176
  const title = msg.chat?.title;
130
177
  const topicSuffix = messageThreadId != null ? ` topic:${messageThreadId}` : "";
131
- if (title)
178
+ if (title) {
132
179
  return `${title} id:${chatId}${topicSuffix}`;
180
+ }
133
181
  return `group:${chatId}${topicSuffix}`;
134
182
  }
135
183
  export function hasBotMention(msg, botUsername) {
136
184
  const text = (msg.text ?? msg.caption ?? "").toLowerCase();
137
- if (text.includes(`@${botUsername}`))
185
+ if (text.includes(`@${botUsername}`)) {
138
186
  return true;
187
+ }
139
188
  const entities = msg.entities ?? msg.caption_entities ?? [];
140
189
  for (const ent of entities) {
141
- if (ent.type !== "mention")
190
+ if (ent.type !== "mention") {
142
191
  continue;
192
+ }
143
193
  const slice = (msg.text ?? msg.caption ?? "").slice(ent.offset, ent.offset + ent.length);
144
- if (slice.toLowerCase() === `@${botUsername}`)
194
+ if (slice.toLowerCase() === `@${botUsername}`) {
145
195
  return true;
196
+ }
146
197
  }
147
198
  return false;
148
199
  }
149
200
  export function expandTextLinks(text, entities) {
150
- if (!text || !entities?.length)
201
+ if (!text || !entities?.length) {
151
202
  return text;
203
+ }
152
204
  const textLinks = entities
153
205
  .filter((entity) => entity.type === "text_link" && Boolean(entity.url))
154
206
  .toSorted((a, b) => b.offset - a.offset);
155
- if (textLinks.length === 0)
207
+ if (textLinks.length === 0) {
156
208
  return text;
209
+ }
157
210
  let result = text;
158
211
  for (const entity of textLinks) {
159
212
  const linkText = text.slice(entity.offset, entity.offset + entity.length);
@@ -164,17 +217,18 @@ export function expandTextLinks(text, entities) {
164
217
  return result;
165
218
  }
166
219
  export function resolveTelegramReplyId(raw) {
167
- if (!raw)
220
+ if (!raw) {
168
221
  return undefined;
222
+ }
169
223
  const parsed = Number(raw);
170
- if (!Number.isFinite(parsed))
224
+ if (!Number.isFinite(parsed)) {
171
225
  return undefined;
226
+ }
172
227
  return parsed;
173
228
  }
174
229
  export function describeReplyTarget(msg) {
175
230
  const reply = msg.reply_to_message;
176
- const externalReply = msg
177
- .external_reply;
231
+ const externalReply = msg.external_reply;
178
232
  const quoteText = msg.quote?.text ??
179
233
  externalReply?.quote?.text;
180
234
  let body = "";
@@ -190,19 +244,8 @@ export function describeReplyTarget(msg) {
190
244
  const replyBody = (replyLike.text ?? replyLike.caption ?? "").trim();
191
245
  body = replyBody;
192
246
  if (!body) {
193
- if (replyLike.photo) {
194
- body = "<media:image>";
195
- }
196
- else if (replyLike.video) {
197
- body = "<media:video>";
198
- }
199
- else if (replyLike.audio || replyLike.voice) {
200
- body = "<media:audio>";
201
- }
202
- else if (replyLike.document) {
203
- body = "<media:document>";
204
- }
205
- else {
247
+ body = resolveTelegramMediaPlaceholder(replyLike) ?? "";
248
+ if (!body) {
206
249
  const locationData = extractTelegramLocation(replyLike);
207
250
  if (locationData) {
208
251
  body = formatLocationText(locationData);
@@ -225,23 +268,24 @@ export function describeReplyTarget(msg) {
225
268
  function normalizeForwardedUserLabel(user) {
226
269
  const name = [user.first_name, user.last_name].filter(Boolean).join(" ").trim();
227
270
  const username = user.username?.trim() || undefined;
228
- const id = user.id != null ? String(user.id) : undefined;
271
+ const id = String(user.id);
229
272
  const display = (name && username
230
273
  ? `${name} (@${username})`
231
- : name || (username ? `@${username}` : undefined)) || (id ? `user:${id}` : undefined);
274
+ : name || (username ? `@${username}` : undefined)) || `user:${id}`;
232
275
  return { display, name: name || undefined, username, id };
233
276
  }
234
277
  function normalizeForwardedChatLabel(chat, fallbackKind) {
235
278
  const title = chat.title?.trim() || undefined;
236
279
  const username = chat.username?.trim() || undefined;
237
- const id = chat.id != null ? String(chat.id) : undefined;
238
- const display = title || (username ? `@${username}` : undefined) || (id ? `${fallbackKind}:${id}` : undefined);
280
+ const id = String(chat.id);
281
+ const display = title || (username ? `@${username}` : undefined) || `${fallbackKind}:${id}`;
239
282
  return { display, title, username, id };
240
283
  }
241
284
  function buildForwardedContextFromUser(params) {
242
285
  const { display, name, username, id } = normalizeForwardedUserLabel(params.user);
243
- if (!display)
286
+ if (!display) {
244
287
  return null;
288
+ }
245
289
  return {
246
290
  from: display,
247
291
  date: params.date,
@@ -253,8 +297,9 @@ function buildForwardedContextFromUser(params) {
253
297
  }
254
298
  function buildForwardedContextFromHiddenName(params) {
255
299
  const trimmed = params.name?.trim();
256
- if (!trimmed)
300
+ if (!trimmed) {
257
301
  return null;
302
+ }
258
303
  return {
259
304
  from: trimmed,
260
305
  date: params.date,
@@ -263,10 +308,11 @@ function buildForwardedContextFromHiddenName(params) {
263
308
  };
264
309
  }
265
310
  function buildForwardedContextFromChat(params) {
266
- const fallbackKind = params.type === "channel" || params.type === "legacy_channel" ? "channel" : "chat";
311
+ const fallbackKind = params.type === "channel" ? "channel" : "chat";
267
312
  const { display, title, username, id } = normalizeForwardedChatLabel(params.chat, fallbackKind);
268
- if (!display)
313
+ if (!display) {
269
314
  return null;
315
+ }
270
316
  const signature = params.signature?.trim() || undefined;
271
317
  const from = signature ? `${display} (${signature})` : display;
272
318
  const chatType = (params.chat.type?.trim() || undefined);
@@ -282,83 +328,51 @@ function buildForwardedContextFromChat(params) {
282
328
  fromMessageId: params.messageId,
283
329
  };
284
330
  }
285
- function resolveForwardOrigin(origin, signature) {
286
- if (origin.type === "user" && origin.sender_user) {
287
- return buildForwardedContextFromUser({
288
- user: origin.sender_user,
289
- date: origin.date,
290
- type: "user",
291
- });
292
- }
293
- if (origin.type === "hidden_user") {
294
- return buildForwardedContextFromHiddenName({
295
- name: origin.sender_user_name,
296
- date: origin.date,
297
- type: "hidden_user",
298
- });
331
+ function resolveForwardOrigin(origin) {
332
+ switch (origin.type) {
333
+ case "user":
334
+ return buildForwardedContextFromUser({
335
+ user: origin.sender_user,
336
+ date: origin.date,
337
+ type: "user",
338
+ });
339
+ case "hidden_user":
340
+ return buildForwardedContextFromHiddenName({
341
+ name: origin.sender_user_name,
342
+ date: origin.date,
343
+ type: "hidden_user",
344
+ });
345
+ case "chat":
346
+ return buildForwardedContextFromChat({
347
+ chat: origin.sender_chat,
348
+ date: origin.date,
349
+ type: "chat",
350
+ signature: origin.author_signature,
351
+ });
352
+ case "channel":
353
+ return buildForwardedContextFromChat({
354
+ chat: origin.chat,
355
+ date: origin.date,
356
+ type: "channel",
357
+ signature: origin.author_signature,
358
+ messageId: origin.message_id,
359
+ });
360
+ default:
361
+ // Exhaustiveness guard: if Grammy adds a new MessageOrigin variant,
362
+ // TypeScript will flag this assignment as an error.
363
+ origin;
364
+ return null;
299
365
  }
300
- if (origin.type === "chat" && origin.sender_chat) {
301
- return buildForwardedContextFromChat({
302
- chat: origin.sender_chat,
303
- date: origin.date,
304
- type: "chat",
305
- signature,
306
- });
307
- }
308
- if (origin.type === "channel" && origin.chat) {
309
- return buildForwardedContextFromChat({
310
- chat: origin.chat,
311
- date: origin.date,
312
- type: "channel",
313
- signature,
314
- });
315
- }
316
- return null;
317
366
  }
318
- /**
319
- * Extract forwarded message origin info from Telegram message.
320
- * Supports both new forward_origin API and legacy forward_from/forward_from_chat fields.
321
- */
367
+ /** Extract forwarded message origin info from Telegram message. */
322
368
  export function normalizeForwardedContext(msg) {
323
- const forwardMsg = msg;
324
- const signature = forwardMsg.forward_signature?.trim() || undefined;
325
- if (forwardMsg.forward_origin) {
326
- const originContext = resolveForwardOrigin(forwardMsg.forward_origin, signature);
327
- if (originContext)
328
- return originContext;
329
- }
330
- if (forwardMsg.forward_from_chat) {
331
- const legacyType = forwardMsg.forward_from_chat.type === "channel" ? "legacy_channel" : "legacy_chat";
332
- const legacyContext = buildForwardedContextFromChat({
333
- chat: forwardMsg.forward_from_chat,
334
- date: forwardMsg.forward_date,
335
- type: legacyType,
336
- signature,
337
- });
338
- if (legacyContext)
339
- return legacyContext;
340
- }
341
- if (forwardMsg.forward_from) {
342
- const legacyContext = buildForwardedContextFromUser({
343
- user: forwardMsg.forward_from,
344
- date: forwardMsg.forward_date,
345
- type: "legacy_user",
346
- });
347
- if (legacyContext)
348
- return legacyContext;
369
+ if (!msg.forward_origin) {
370
+ return null;
349
371
  }
350
- const hiddenContext = buildForwardedContextFromHiddenName({
351
- name: forwardMsg.forward_sender_name,
352
- date: forwardMsg.forward_date,
353
- type: "legacy_hidden_user",
354
- });
355
- if (hiddenContext)
356
- return hiddenContext;
357
- return null;
372
+ return resolveForwardOrigin(msg.forward_origin);
358
373
  }
359
374
  export function extractTelegramLocation(msg) {
360
- const msgWithLocation = msg;
361
- const { venue, location } = msgWithLocation;
375
+ const { venue, location } = msg;
362
376
  if (venue) {
363
377
  return {
364
378
  latitude: venue.location.latitude,