@poolzin/pool-bot 2026.2.17 → 2026.2.19

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 (488) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/agents/agent-scope.js +4 -0
  3. package/dist/agents/announce-idempotency.js +14 -0
  4. package/dist/agents/auth-profiles.resolve-auth-profile-order.fixtures.js +23 -0
  5. package/dist/agents/bash-tools.exec-runtime.js +438 -0
  6. package/dist/agents/bash-tools.shared.js +6 -0
  7. package/dist/agents/cli-runner/reliability.js +61 -0
  8. package/dist/agents/cli-watchdog-defaults.js +11 -0
  9. package/dist/agents/command-poll-backoff.js +63 -0
  10. package/dist/agents/current-time.js +16 -0
  11. package/dist/agents/model-alias-lines.js +18 -0
  12. package/dist/agents/model-auth-label.js +61 -0
  13. package/dist/agents/models-config.e2e-harness.js +115 -0
  14. package/dist/agents/ollama-stream.js +11 -3
  15. package/dist/agents/openclaw-tools.js +135 -0
  16. package/dist/agents/pi-auth-json.js +118 -0
  17. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +147 -0
  18. package/dist/agents/pi-embedded-subscribe.e2e-harness.js +90 -0
  19. package/dist/agents/pi-embedded-subscribe.handlers.compaction.js +63 -0
  20. package/dist/agents/pi-embedded-subscribe.handlers.tools.media.test-helpers.js +30 -0
  21. package/dist/agents/pi-extensions/session-manager-runtime-registry.js +23 -0
  22. package/dist/agents/pi-tools.js +2 -0
  23. package/dist/agents/queued-file-writer.js +22 -0
  24. package/dist/agents/sandbox/docker.js +133 -40
  25. package/dist/agents/sandbox/fs-bridge.js +146 -0
  26. package/dist/agents/sandbox/fs-paths.js +205 -0
  27. package/dist/agents/sandbox/hash.js +4 -0
  28. package/dist/agents/sandbox-paths.js +3 -0
  29. package/dist/agents/session-dirs.js +20 -0
  30. package/dist/agents/skills/filter.js +24 -0
  31. package/dist/agents/skills/tools-dir.js +9 -0
  32. package/dist/agents/skills-install-download.js +290 -0
  33. package/dist/agents/skills-install-output.js +30 -0
  34. package/dist/agents/skills-install.download-test-utils.js +36 -0
  35. package/dist/agents/skills.e2e-test-helpers.js +13 -0
  36. package/dist/agents/subagent-announce-queue.js +59 -15
  37. package/dist/agents/subagent-depth.js +137 -0
  38. package/dist/agents/subagent-registry.js +448 -96
  39. package/dist/agents/subagent-spawn.js +262 -0
  40. package/dist/agents/test-helpers/fast-tool-stubs.js +18 -0
  41. package/dist/agents/test-helpers/host-sandbox-fs-bridge.js +74 -0
  42. package/dist/agents/tool-display-common.js +782 -0
  43. package/dist/agents/tools/image-tool.js +1 -1
  44. package/dist/agents/tools/sessions-access.js +178 -0
  45. package/dist/agents/tools/sessions-resolution.js +206 -0
  46. package/dist/agents/tools/subagents-tool.js +616 -0
  47. package/dist/agents/workspace-dir.js +18 -0
  48. package/dist/agents/workspace-dirs.js +14 -0
  49. package/dist/agents/workspace.js +70 -0
  50. package/dist/auto-reply/heartbeat-reply-payload.js +18 -0
  51. package/dist/auto-reply/reply/commands-export-session.js +163 -0
  52. package/dist/auto-reply/reply/commands-mesh.js +245 -0
  53. package/dist/auto-reply/reply/commands-setunset.js +28 -0
  54. package/dist/auto-reply/reply/commands-slash-parse.js +31 -0
  55. package/dist/auto-reply/reply/commands-system-prompt.js +117 -0
  56. package/dist/auto-reply/reply/directive-handling.levels.js +17 -0
  57. package/dist/auto-reply/reply/directive-handling.params.js +1 -0
  58. package/dist/auto-reply/reply/directive-parsing.js +36 -0
  59. package/dist/auto-reply/reply/dispatcher-registry.js +43 -0
  60. package/dist/auto-reply/reply/elevated-unavailable.js +20 -0
  61. package/dist/auto-reply/reply/reply-delivery.js +92 -0
  62. package/dist/auto-reply/reply/session-reset-prompt.js +1 -0
  63. package/dist/auto-reply/reply/session-run-accounting.js +33 -0
  64. package/dist/auto-reply/reply.directive.directive-behavior.e2e-harness.js +115 -0
  65. package/dist/auto-reply/reply.directive.directive-behavior.e2e-mocks.js +12 -0
  66. package/dist/browser/bridge-auth-registry.js +26 -0
  67. package/dist/browser/client-actions-url.js +10 -0
  68. package/dist/browser/control-auth.js +73 -0
  69. package/dist/browser/csrf.js +64 -0
  70. package/dist/browser/http-auth.js +52 -0
  71. package/dist/browser/paths.js +37 -0
  72. package/dist/browser/proxy-files.js +32 -0
  73. package/dist/browser/pw-ai-state.js +7 -0
  74. package/dist/browser/resolved-config-refresh.js +42 -0
  75. package/dist/browser/routes/path-output.js +1 -0
  76. package/dist/browser/server-context.chrome-test-harness.js +20 -0
  77. package/dist/browser/server-middleware.js +31 -0
  78. package/dist/browser/test-port.js +16 -0
  79. package/dist/build-info.json +3 -3
  80. package/dist/canvas-host/file-resolver.js +43 -0
  81. package/dist/channels/account-summary.js +19 -0
  82. package/dist/channels/draft-stream-loop.js +77 -0
  83. package/dist/channels/plugins/account-helpers.js +26 -0
  84. package/dist/channels/telegram/allow-from.js +10 -0
  85. package/dist/cli/browser-cli-resize.js +22 -0
  86. package/dist/cli/browser-cli-shared.js +8 -0
  87. package/dist/cli/clawbot-cli.js +5 -0
  88. package/dist/cli/completion-cli.js +566 -0
  89. package/dist/cli/config-cli.js +63 -5
  90. package/dist/cli/daemon-cli/lifecycle-core.js +256 -0
  91. package/dist/cli/daemon-cli/register-service-commands.js +60 -0
  92. package/dist/cli/daemon-cli-compat.js +80 -0
  93. package/dist/cli/nodes-cli/pairing-render.js +26 -0
  94. package/dist/cli/program/action-reparse.js +17 -0
  95. package/dist/cli/program/command-registry.js +17 -0
  96. package/dist/cli/program/program-context.js +8 -0
  97. package/dist/cli/program/register.subclis.js +7 -0
  98. package/dist/cli/program/routes.js +233 -0
  99. package/dist/cli/qr-cli.js +132 -0
  100. package/dist/cli/requirements-test-fixtures.js +17 -0
  101. package/dist/cli/respawn-policy.js +4 -0
  102. package/dist/cli/shared/parse-port.js +18 -0
  103. package/dist/cli/skills-cli.format.js +241 -0
  104. package/dist/cli/update-cli/progress.js +121 -0
  105. package/dist/cli/update-cli/restart-helper.js +108 -0
  106. package/dist/cli/update-cli/shared.js +196 -0
  107. package/dist/cli/update-cli/status.js +97 -0
  108. package/dist/cli/update-cli/suppress-deprecations.js +17 -0
  109. package/dist/cli/update-cli/update-command.js +506 -0
  110. package/dist/cli/update-cli/wizard.js +130 -0
  111. package/dist/cli/update-cli.js +3 -9
  112. package/dist/cli/windows-argv.js +69 -0
  113. package/dist/commands/auth-choice-legacy.js +20 -0
  114. package/dist/commands/auth-choice.apply-helpers.js +8 -0
  115. package/dist/commands/channel-test-helpers.js +19 -0
  116. package/dist/commands/cleanup-plan.js +10 -0
  117. package/dist/commands/cleanup-utils.js +7 -0
  118. package/dist/commands/config-validation.js +15 -0
  119. package/dist/commands/doctor-completion.js +112 -0
  120. package/dist/commands/doctor-memory-search.js +119 -0
  121. package/dist/commands/doctor-session-locks.js +73 -0
  122. package/dist/commands/doctor.e2e-harness.js +364 -0
  123. package/dist/commands/gateway-presence.js +19 -0
  124. package/dist/commands/model-default.js +35 -0
  125. package/dist/commands/models/fallbacks-shared.js +102 -0
  126. package/dist/commands/models/shared.js +24 -0
  127. package/dist/commands/onboard-auth.config-gateways.js +64 -0
  128. package/dist/commands/onboard-auth.config-litellm.js +45 -0
  129. package/dist/commands/onboard-auth.config-shared.js +116 -0
  130. package/dist/commands/onboard-config.js +16 -0
  131. package/dist/commands/onboard-non-interactive.test-helpers.js +31 -0
  132. package/dist/commands/onboard-provider-auth-flags.js +136 -0
  133. package/dist/commands/openai-codex-oauth.js +40 -0
  134. package/dist/commands/test-runtime-config-helpers.js +21 -0
  135. package/dist/commands/test-wizard-helpers.js +68 -0
  136. package/dist/commands/vllm-setup.js +66 -0
  137. package/dist/compat/legacy-names.js +2 -0
  138. package/dist/config/backup-rotation.js +19 -0
  139. package/dist/config/env-preserve.js +122 -0
  140. package/dist/config/includes-scan.js +78 -0
  141. package/dist/config/plugins-allowlist.js +13 -0
  142. package/dist/config/schema.help.js +256 -0
  143. package/dist/config/schema.hints.js +189 -0
  144. package/dist/config/schema.irc.js +20 -0
  145. package/dist/config/schema.labels.js +317 -0
  146. package/dist/config/sessions/delivery-info.js +40 -0
  147. package/dist/config/types.irc.js +1 -0
  148. package/dist/config/zod-schema.agent-model.js +10 -0
  149. package/dist/config/zod-schema.allowdeny.js +35 -0
  150. package/dist/config/zod-schema.sensitive.js +4 -0
  151. package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
  152. package/dist/cron/isolated-agent/skills-snapshot.js +26 -0
  153. package/dist/cron/isolated-agent/subagent-followup.js +127 -0
  154. package/dist/cron/isolated-agent.mocks.js +12 -0
  155. package/dist/cron/isolated-agent.test-setup.js +22 -0
  156. package/dist/cron/legacy-delivery.js +43 -0
  157. package/dist/cron/webhook-url.js +22 -0
  158. package/dist/daemon/arg-split.js +40 -0
  159. package/dist/daemon/exec-file.js +23 -0
  160. package/dist/daemon/output.js +6 -0
  161. package/dist/daemon/runtime-format.js +31 -0
  162. package/dist/daemon/schtasks-exec.js +4 -0
  163. package/dist/daemon/service-audit.js +22 -0
  164. package/dist/discord/client.js +41 -0
  165. package/dist/discord/components-registry.js +57 -0
  166. package/dist/discord/components.js +816 -0
  167. package/dist/discord/guilds.js +12 -0
  168. package/dist/discord/monitor/gateway-plugin.js +48 -0
  169. package/dist/discord/monitor/presence.js +30 -0
  170. package/dist/discord/send.components.js +115 -0
  171. package/dist/discord/send.shared.js +4 -0
  172. package/dist/discord/ui.js +26 -0
  173. package/dist/discord/voice-message.js +254 -0
  174. package/dist/gateway/agent-event-assistant-text.js +5 -0
  175. package/dist/gateway/agent-prompt.js +33 -0
  176. package/dist/gateway/auth-rate-limit.js +136 -0
  177. package/dist/gateway/channel-health-monitor.js +114 -0
  178. package/dist/gateway/control-ui-contract.js +1 -0
  179. package/dist/gateway/control-ui-csp.js +15 -0
  180. package/dist/gateway/gateway-config-prompts.shared.js +25 -0
  181. package/dist/gateway/http-auth-helpers.js +18 -0
  182. package/dist/gateway/http-common.js +18 -0
  183. package/dist/gateway/http-endpoint-helpers.js +27 -0
  184. package/dist/gateway/node-invoke-sanitize.js +11 -0
  185. package/dist/gateway/node-invoke-system-run-approval.js +205 -0
  186. package/dist/gateway/probe-auth.js +21 -0
  187. package/dist/gateway/protocol/index.js +7 -2
  188. package/dist/gateway/protocol/schema/mesh.js +54 -0
  189. package/dist/gateway/protocol/schema/protocol-schemas.js +7 -0
  190. package/dist/gateway/protocol/schema.js +1 -0
  191. package/dist/gateway/server/ws-connection/auth-messages.js +54 -0
  192. package/dist/gateway/server-channels.js +11 -0
  193. package/dist/gateway/server-methods/attachment-normalize.js +16 -0
  194. package/dist/gateway/server-methods/base-hash.js +8 -0
  195. package/dist/gateway/server-methods/mesh.js +700 -0
  196. package/dist/gateway/server-methods/nodes.handlers.invoke-result.js +55 -0
  197. package/dist/gateway/server-methods/restart-request.js +13 -0
  198. package/dist/gateway/server-methods/validation.js +8 -0
  199. package/dist/gateway/server.agent.gateway-server-agent.mocks.js +35 -0
  200. package/dist/gateway/server.e2e-registry-helpers.js +1 -0
  201. package/dist/gateway/server.e2e-ws-harness.js +20 -0
  202. package/dist/gateway/test-helpers.js +2 -0
  203. package/dist/gateway/test-helpers.server.js +3 -1
  204. package/dist/gateway/test-http-response.js +12 -0
  205. package/dist/gateway/test-openai-responses-model.js +20 -0
  206. package/dist/gateway/test-temp-config.js +30 -0
  207. package/dist/gateway/test-with-server.js +32 -0
  208. package/dist/hooks/bundled/bootstrap-extra-files/handler.js +46 -0
  209. package/dist/imessage/monitor/abort-handler.js +23 -0
  210. package/dist/imessage/monitor/inbound-processing.js +346 -0
  211. package/dist/imessage/monitor/parse-notification.js +64 -0
  212. package/dist/imessage/target-parsing-helpers.js +92 -0
  213. package/dist/infra/archive.js +244 -20
  214. package/dist/infra/detect-package-manager.js +26 -0
  215. package/dist/infra/exec-approvals-allowlist.js +257 -0
  216. package/dist/infra/exec-approvals-analysis.js +770 -0
  217. package/dist/infra/exec-approvals.js +13 -0
  218. package/dist/infra/file-lock.js +1 -0
  219. package/dist/infra/gemini-auth.js +39 -0
  220. package/dist/infra/heartbeat-active-hours.js +85 -0
  221. package/dist/infra/heartbeat-events-filter.js +50 -0
  222. package/dist/infra/heartbeat-runner.test-utils.js +39 -0
  223. package/dist/infra/http-body.js +265 -0
  224. package/dist/infra/install-package-dir.js +50 -0
  225. package/dist/infra/install-safe-path.js +49 -0
  226. package/dist/infra/json-files.js +49 -0
  227. package/dist/infra/jsonl-socket.js +52 -0
  228. package/dist/infra/map-size.js +14 -0
  229. package/dist/infra/net/hostname.js +7 -0
  230. package/dist/infra/npm-registry-spec.js +39 -0
  231. package/dist/infra/openclaw-root.js +109 -0
  232. package/dist/infra/outbound/delivery-queue.js +214 -0
  233. package/dist/infra/outbound/identity.js +23 -0
  234. package/dist/infra/outbound/message-action-params.js +307 -0
  235. package/dist/infra/outbound/tool-payload.js +21 -0
  236. package/dist/infra/package-json.js +23 -0
  237. package/dist/infra/pairing-files.js +19 -0
  238. package/dist/infra/pairing-token.js +9 -0
  239. package/dist/infra/path-prepend.js +51 -0
  240. package/dist/infra/process-respawn.js +49 -0
  241. package/dist/infra/runtime-status.js +16 -0
  242. package/dist/infra/session-cost-usage.types.js +1 -0
  243. package/dist/infra/session-maintenance-warning.js +89 -0
  244. package/dist/infra/system-run-command.js +78 -0
  245. package/dist/infra/tmp-openclaw-dir.js +81 -0
  246. package/dist/infra/tmp-poolbot-dir.js +2 -0
  247. package/dist/infra/update-channels.js +19 -0
  248. package/dist/line/actions.js +45 -0
  249. package/dist/line/channel-access-token.js +9 -0
  250. package/dist/line/flex-templates/basic-cards.js +332 -0
  251. package/dist/line/flex-templates/common.js +18 -0
  252. package/dist/line/flex-templates/media-control-cards.js +453 -0
  253. package/dist/line/flex-templates/message.js +10 -0
  254. package/dist/line/flex-templates/schedule-cards.js +399 -0
  255. package/dist/line/flex-templates/types.js +1 -0
  256. package/dist/line/webhook-node.js +100 -0
  257. package/dist/line/webhook-utils.js +11 -0
  258. package/dist/logging/timestamps.js +14 -0
  259. package/dist/markdown/whatsapp.js +62 -0
  260. package/dist/media/base64.js +34 -0
  261. package/dist/media/local-roots.js +32 -0
  262. package/dist/media/outbound-attachment.js +10 -0
  263. package/dist/media/read-response-with-limit.js +41 -0
  264. package/dist/media/sniff-mime-from-base64.js +19 -0
  265. package/dist/media-understanding/audio-preflight.js +67 -0
  266. package/dist/media-understanding/fs.js +13 -0
  267. package/dist/media-understanding/output-extract.js +26 -0
  268. package/dist/media-understanding/providers/audio.test-helpers.js +34 -0
  269. package/dist/media-understanding/providers/google/inline-data.js +64 -0
  270. package/dist/media-understanding/providers/shared.js +7 -0
  271. package/dist/media-understanding/runner.entries.js +459 -0
  272. package/dist/memory/batch-error-utils.js +11 -0
  273. package/dist/memory/batch-http.js +27 -0
  274. package/dist/memory/batch-output.js +29 -0
  275. package/dist/memory/batch-runner.js +22 -0
  276. package/dist/memory/batch-upload.js +23 -0
  277. package/dist/memory/batch-utils.js +26 -0
  278. package/dist/memory/embeddings-debug.js +11 -0
  279. package/dist/memory/embeddings-remote-client.js +22 -0
  280. package/dist/memory/embeddings-remote-fetch.js +14 -0
  281. package/dist/memory/manager-embedding-ops.js +616 -0
  282. package/dist/memory/manager-sync-ops.js +953 -0
  283. package/dist/memory/qmd-manager.js +1061 -0
  284. package/dist/memory/qmd-query-parser.js +107 -0
  285. package/dist/memory/qmd-scope.js +93 -0
  286. package/dist/memory/search-manager.js +0 -1
  287. package/dist/memory/sync-index.js +21 -0
  288. package/dist/memory/sync-progress.js +22 -0
  289. package/dist/memory/sync-stale.js +30 -0
  290. package/dist/memory/test-embeddings-mock.js +16 -0
  291. package/dist/memory/test-manager-helpers.js +14 -0
  292. package/dist/memory/test-runtime-mocks.js +11 -0
  293. package/dist/node-host/invoke-browser.js +177 -0
  294. package/dist/node-host/invoke.js +685 -0
  295. package/dist/pairing/setup-code.js +285 -0
  296. package/dist/plugin-sdk/account-id.js +1 -0
  297. package/dist/plugin-sdk/agent-media-payload.js +13 -0
  298. package/dist/plugin-sdk/allow-from.js +47 -0
  299. package/dist/plugin-sdk/command-auth.js +23 -0
  300. package/dist/plugin-sdk/config-paths.js +9 -0
  301. package/dist/plugin-sdk/file-lock.js +116 -0
  302. package/dist/plugin-sdk/json-store.js +31 -0
  303. package/dist/plugin-sdk/onboarding.js +28 -0
  304. package/dist/plugin-sdk/provider-auth-result.js +29 -0
  305. package/dist/plugin-sdk/slack-message-actions.js +133 -0
  306. package/dist/plugin-sdk/status-helpers.js +35 -0
  307. package/dist/plugin-sdk/text-chunking.js +31 -0
  308. package/dist/plugin-sdk/tool-send.js +12 -0
  309. package/dist/plugin-sdk/webhook-path.js +27 -0
  310. package/dist/plugin-sdk/webhook-targets.js +34 -0
  311. package/dist/plugins/hooks.test-helpers.js +21 -0
  312. package/dist/plugins/uninstall.js +171 -0
  313. package/dist/process/supervisor/adapters/child.js +143 -0
  314. package/dist/process/supervisor/adapters/env.js +13 -0
  315. package/dist/process/supervisor/adapters/pty.js +148 -0
  316. package/dist/process/supervisor/index.js +10 -0
  317. package/dist/process/supervisor/registry.js +117 -0
  318. package/dist/process/supervisor/supervisor.js +244 -0
  319. package/dist/process/supervisor/types.js +1 -0
  320. package/dist/providers/google-shared.test-helpers.js +75 -0
  321. package/dist/security/audit-channel.js +419 -0
  322. package/dist/security/audit-tool-policy.js +1 -0
  323. package/dist/security/scan-paths.js +12 -0
  324. package/dist/sessions/input-provenance.js +55 -0
  325. package/dist/sessions/session-key-utils.js +7 -0
  326. package/dist/shared/chat-content.js +31 -0
  327. package/dist/shared/chat-envelope.js +45 -0
  328. package/dist/shared/config-eval.js +117 -0
  329. package/dist/shared/device-auth.js +16 -0
  330. package/dist/shared/entry-metadata.js +9 -0
  331. package/dist/shared/entry-status.js +25 -0
  332. package/dist/shared/frontmatter.js +98 -0
  333. package/dist/shared/model-param-b.js +19 -0
  334. package/dist/shared/net/ipv4.js +17 -0
  335. package/dist/shared/node-match.js +53 -0
  336. package/dist/shared/requirements.js +128 -0
  337. package/dist/shared/subagents-format.js +84 -0
  338. package/dist/shared/usage-aggregates.js +28 -0
  339. package/dist/signal/monitor/mentions.js +45 -0
  340. package/dist/signal/rpc-context.js +19 -0
  341. package/dist/slack/blocks-fallback.js +76 -0
  342. package/dist/slack/blocks-input.js +40 -0
  343. package/dist/slack/draft-stream.js +106 -0
  344. package/dist/slack/message-actions.js +51 -0
  345. package/dist/slack/modal-metadata.js +32 -0
  346. package/dist/slack/monitor/events/interactions.js +462 -0
  347. package/dist/slack/monitor/room-context.js +17 -0
  348. package/dist/slack/stream-mode.js +41 -0
  349. package/dist/telegram/bot-native-command-menu.js +64 -0
  350. package/dist/telegram/bot.media.e2e-harness.js +81 -0
  351. package/dist/telegram/button-types.js +1 -0
  352. package/dist/telegram/group-access.js +65 -0
  353. package/dist/telegram/outbound-params.js +21 -0
  354. package/dist/telegram/poll-vote-cache.js +21 -0
  355. package/dist/terminal/health-style.js +36 -0
  356. package/dist/test-utils/chunk-test-helpers.js +21 -0
  357. package/dist/test-utils/env.js +72 -0
  358. package/dist/test-utils/exec-assertions.js +12 -0
  359. package/dist/test-utils/imessage-test-plugin.js +54 -0
  360. package/dist/test-utils/mock-http-response.js +17 -0
  361. package/dist/test-utils/vitest-mock-fn.js +1 -0
  362. package/dist/tts/tts-core.js +550 -0
  363. package/dist/utils/chunk-items.js +10 -0
  364. package/dist/utils/reaction-level.js +52 -0
  365. package/dist/utils/safe-json.js +22 -0
  366. package/dist/utils/with-timeout.js +14 -0
  367. package/dist/web/media.js +17 -5
  368. package/dist/whatsapp/resolve-outbound-target.js +42 -0
  369. package/dist/wizard/onboarding.completion.js +74 -0
  370. package/extensions/bluebubbles/src/account-resolve.ts +29 -0
  371. package/extensions/bluebubbles/src/monitor-normalize.ts +796 -0
  372. package/extensions/bluebubbles/src/monitor-processing.ts +1007 -0
  373. package/extensions/bluebubbles/src/monitor-reply-cache.ts +185 -0
  374. package/extensions/bluebubbles/src/monitor-shared.ts +51 -0
  375. package/extensions/bluebubbles/src/multipart.ts +32 -0
  376. package/extensions/bluebubbles/src/send-helpers.ts +53 -0
  377. package/extensions/bluebubbles/src/test-harness.ts +50 -0
  378. package/extensions/bluebubbles/src/test-mocks.ts +11 -0
  379. package/extensions/device-pair/index.ts +554 -0
  380. package/extensions/device-pair/poolbot.plugin.json +20 -0
  381. package/extensions/discord/src/channel.js +366 -0
  382. package/extensions/discord/src/runtime.js +10 -0
  383. package/extensions/feishu/index.ts +63 -0
  384. package/extensions/feishu/package.json +37 -0
  385. package/extensions/feishu/poolbot.plugin.json +10 -0
  386. package/extensions/feishu/skills/feishu-doc/SKILL.md +105 -0
  387. package/extensions/feishu/skills/feishu-doc/references/block-types.md +103 -0
  388. package/extensions/feishu/skills/feishu-drive/SKILL.md +97 -0
  389. package/extensions/feishu/skills/feishu-perm/SKILL.md +119 -0
  390. package/extensions/feishu/skills/feishu-wiki/SKILL.md +111 -0
  391. package/extensions/feishu/src/accounts.ts +114 -0
  392. package/extensions/feishu/src/bitable.ts +739 -0
  393. package/extensions/feishu/src/bot.ts +965 -0
  394. package/extensions/feishu/src/channel.ts +351 -0
  395. package/extensions/feishu/src/client.ts +118 -0
  396. package/extensions/feishu/src/config-schema.ts +206 -0
  397. package/extensions/feishu/src/dedup.ts +33 -0
  398. package/extensions/feishu/src/directory.ts +177 -0
  399. package/extensions/feishu/src/doc-schema.ts +47 -0
  400. package/extensions/feishu/src/docx.ts +536 -0
  401. package/extensions/feishu/src/drive-schema.ts +46 -0
  402. package/extensions/feishu/src/drive.ts +227 -0
  403. package/extensions/feishu/src/dynamic-agent.ts +131 -0
  404. package/extensions/feishu/src/media.ts +449 -0
  405. package/extensions/feishu/src/mention.ts +126 -0
  406. package/extensions/feishu/src/monitor.ts +330 -0
  407. package/extensions/feishu/src/onboarding.ts +359 -0
  408. package/extensions/feishu/src/outbound.ts +55 -0
  409. package/extensions/feishu/src/perm-schema.ts +52 -0
  410. package/extensions/feishu/src/perm.ts +173 -0
  411. package/extensions/feishu/src/policy.ts +84 -0
  412. package/extensions/feishu/src/probe.ts +44 -0
  413. package/extensions/feishu/src/reactions.ts +160 -0
  414. package/extensions/feishu/src/reply-dispatcher.ts +239 -0
  415. package/extensions/feishu/src/runtime.ts +14 -0
  416. package/extensions/feishu/src/send-result.ts +29 -0
  417. package/extensions/feishu/src/send.ts +335 -0
  418. package/extensions/feishu/src/streaming-card.ts +223 -0
  419. package/extensions/feishu/src/targets.ts +78 -0
  420. package/extensions/feishu/src/tools-config.ts +21 -0
  421. package/extensions/feishu/src/types.ts +81 -0
  422. package/extensions/feishu/src/typing.ts +80 -0
  423. package/extensions/feishu/src/wiki-schema.ts +55 -0
  424. package/extensions/feishu/src/wiki.ts +232 -0
  425. package/extensions/imessage/src/channel.js +253 -0
  426. package/extensions/imessage/src/runtime.js +10 -0
  427. package/extensions/irc/index.ts +17 -0
  428. package/extensions/irc/package.json +14 -0
  429. package/extensions/irc/poolbot.plugin.json +9 -0
  430. package/extensions/irc/src/accounts.ts +268 -0
  431. package/extensions/irc/src/channel.ts +367 -0
  432. package/extensions/irc/src/client.ts +439 -0
  433. package/extensions/irc/src/config-schema.ts +97 -0
  434. package/extensions/irc/src/connect-options.ts +30 -0
  435. package/extensions/irc/src/control-chars.ts +22 -0
  436. package/extensions/irc/src/inbound.ts +334 -0
  437. package/extensions/irc/src/monitor.ts +147 -0
  438. package/extensions/irc/src/normalize.ts +117 -0
  439. package/extensions/irc/src/onboarding.ts +479 -0
  440. package/extensions/irc/src/policy.ts +157 -0
  441. package/extensions/irc/src/probe.ts +53 -0
  442. package/extensions/irc/src/protocol.ts +169 -0
  443. package/extensions/irc/src/runtime.ts +14 -0
  444. package/extensions/irc/src/send.ts +88 -0
  445. package/extensions/irc/src/types.ts +93 -0
  446. package/extensions/matrix/src/matrix/client-bootstrap.ts +39 -0
  447. package/extensions/mattermost/src/mattermost/monitor-onchar.ts +25 -0
  448. package/extensions/mattermost/src/mattermost/monitor-websocket.ts +221 -0
  449. package/extensions/mattermost/src/mattermost/reactions.ts +130 -0
  450. package/extensions/mattermost/src/mattermost/reconnect.ts +103 -0
  451. package/extensions/minimax-portal-auth/README.md +33 -0
  452. package/extensions/minimax-portal-auth/index.ts +161 -0
  453. package/extensions/minimax-portal-auth/oauth.ts +247 -0
  454. package/extensions/minimax-portal-auth/package.json +15 -0
  455. package/extensions/minimax-portal-auth/poolbot.plugin.json +9 -0
  456. package/extensions/msteams/src/file-lock.ts +1 -0
  457. package/extensions/msteams/src/graph.ts +92 -0
  458. package/extensions/msteams/src/mentions.ts +114 -0
  459. package/extensions/msteams/src/test-runtime.ts +16 -0
  460. package/extensions/openai-codex-auth/README.md +82 -0
  461. package/extensions/openai-codex-auth/index.ts +177 -0
  462. package/extensions/openai-codex-auth/package.json +15 -0
  463. package/extensions/openai-codex-auth/poolbot.plugin.json +9 -0
  464. package/extensions/phone-control/index.ts +421 -0
  465. package/extensions/phone-control/poolbot.plugin.json +10 -0
  466. package/extensions/shared/resolve-target-test-helpers.ts +66 -0
  467. package/extensions/signal/src/channel.js +273 -0
  468. package/extensions/signal/src/runtime.js +10 -0
  469. package/extensions/slack/src/channel.js +489 -0
  470. package/extensions/slack/src/runtime.js +10 -0
  471. package/extensions/talk-voice/index.ts +150 -0
  472. package/extensions/talk-voice/poolbot.plugin.json +10 -0
  473. package/extensions/telegram/src/channel.js +424 -0
  474. package/extensions/telegram/src/runtime.js +10 -0
  475. package/extensions/thread-ownership/index.ts +133 -0
  476. package/extensions/thread-ownership/poolbot.plugin.json +28 -0
  477. package/extensions/tlon/src/account-fields.ts +25 -0
  478. package/extensions/tlon/src/urbit/base-url.ts +57 -0
  479. package/extensions/tlon/src/urbit/channel-client.ts +157 -0
  480. package/extensions/tlon/src/urbit/channel-ops.ts +164 -0
  481. package/extensions/tlon/src/urbit/context.ts +47 -0
  482. package/extensions/tlon/src/urbit/errors.ts +51 -0
  483. package/extensions/tlon/src/urbit/fetch.ts +39 -0
  484. package/extensions/twitch/src/test-fixtures.ts +30 -0
  485. package/extensions/voice-call/src/allowlist.ts +19 -0
  486. package/extensions/whatsapp/src/channel.js +429 -0
  487. package/extensions/whatsapp/src/runtime.js +10 -0
  488. package/package.json +1 -1
@@ -0,0 +1,399 @@
1
+ import { attachFooterText } from "./common.js";
2
+ function buildTitleSubtitleHeader(params) {
3
+ const { title, subtitle } = params;
4
+ const headerContents = [
5
+ {
6
+ type: "text",
7
+ text: title,
8
+ weight: "bold",
9
+ size: "xl",
10
+ color: "#111111",
11
+ wrap: true,
12
+ },
13
+ ];
14
+ if (subtitle) {
15
+ headerContents.push({
16
+ type: "text",
17
+ text: subtitle,
18
+ size: "sm",
19
+ color: "#888888",
20
+ margin: "sm",
21
+ wrap: true,
22
+ });
23
+ }
24
+ return headerContents;
25
+ }
26
+ function buildCardHeaderSections(headerContents) {
27
+ return [
28
+ {
29
+ type: "box",
30
+ layout: "vertical",
31
+ contents: headerContents,
32
+ paddingBottom: "lg",
33
+ },
34
+ {
35
+ type: "separator",
36
+ color: "#EEEEEE",
37
+ },
38
+ ];
39
+ }
40
+ function createMegaBubbleWithFooter(params) {
41
+ const bubble = {
42
+ type: "bubble",
43
+ size: "mega",
44
+ body: {
45
+ type: "box",
46
+ layout: "vertical",
47
+ contents: params.bodyContents,
48
+ paddingAll: "xl",
49
+ backgroundColor: "#FFFFFF",
50
+ },
51
+ };
52
+ if (params.footer) {
53
+ attachFooterText(bubble, params.footer);
54
+ }
55
+ return bubble;
56
+ }
57
+ /**
58
+ * Create a receipt/summary card (for orders, transactions, data tables)
59
+ *
60
+ * Editorial design: Clean table layout with alternating row backgrounds,
61
+ * prominent total section, and clear visual hierarchy.
62
+ */
63
+ export function createReceiptCard(params) {
64
+ const { title, subtitle, items, total, footer } = params;
65
+ const itemRows = items.slice(0, 12).map((item, index) => ({
66
+ type: "box",
67
+ layout: "horizontal",
68
+ contents: [
69
+ {
70
+ type: "text",
71
+ text: item.name,
72
+ size: "sm",
73
+ color: item.highlight ? "#111111" : "#666666",
74
+ weight: item.highlight ? "bold" : "regular",
75
+ flex: 3,
76
+ wrap: true,
77
+ },
78
+ {
79
+ type: "text",
80
+ text: item.value,
81
+ size: "sm",
82
+ color: item.highlight ? "#06C755" : "#333333",
83
+ weight: item.highlight ? "bold" : "regular",
84
+ flex: 2,
85
+ align: "end",
86
+ wrap: true,
87
+ },
88
+ ],
89
+ paddingAll: "md",
90
+ backgroundColor: index % 2 === 0 ? "#FFFFFF" : "#FAFAFA",
91
+ }));
92
+ // Header section
93
+ const headerContents = buildTitleSubtitleHeader({ title, subtitle });
94
+ const bodyContents = [
95
+ ...buildCardHeaderSections(headerContents),
96
+ {
97
+ type: "box",
98
+ layout: "vertical",
99
+ contents: itemRows,
100
+ margin: "md",
101
+ cornerRadius: "md",
102
+ borderWidth: "light",
103
+ borderColor: "#EEEEEE",
104
+ },
105
+ ];
106
+ // Total section with emphasis
107
+ if (total) {
108
+ bodyContents.push({
109
+ type: "box",
110
+ layout: "horizontal",
111
+ contents: [
112
+ {
113
+ type: "text",
114
+ text: total.label,
115
+ size: "lg",
116
+ weight: "bold",
117
+ color: "#111111",
118
+ flex: 2,
119
+ },
120
+ {
121
+ type: "text",
122
+ text: total.value,
123
+ size: "xl",
124
+ weight: "bold",
125
+ color: "#06C755",
126
+ flex: 2,
127
+ align: "end",
128
+ },
129
+ ],
130
+ margin: "xl",
131
+ paddingAll: "lg",
132
+ backgroundColor: "#F0FDF4",
133
+ cornerRadius: "lg",
134
+ });
135
+ }
136
+ return createMegaBubbleWithFooter({ bodyContents, footer });
137
+ }
138
+ /**
139
+ * Create a calendar event card (for meetings, appointments, reminders)
140
+ *
141
+ * Editorial design: Date as hero, strong typographic hierarchy,
142
+ * color-blocked zones, full text wrapping for readability.
143
+ */
144
+ export function createEventCard(params) {
145
+ const { title, date, time, location, description, calendar, isAllDay, action } = params;
146
+ // Hero date block - the most important information
147
+ const dateBlock = {
148
+ type: "box",
149
+ layout: "vertical",
150
+ contents: [
151
+ {
152
+ type: "text",
153
+ text: date.toUpperCase(),
154
+ size: "sm",
155
+ weight: "bold",
156
+ color: "#06C755",
157
+ wrap: true,
158
+ },
159
+ {
160
+ type: "text",
161
+ text: isAllDay ? "ALL DAY" : (time ?? ""),
162
+ size: "xxl",
163
+ weight: "bold",
164
+ color: "#111111",
165
+ wrap: true,
166
+ margin: "xs",
167
+ },
168
+ ],
169
+ paddingBottom: "lg",
170
+ borderWidth: "none",
171
+ };
172
+ // If no time and not all day, hide the time display
173
+ if (!time && !isAllDay) {
174
+ dateBlock.contents = [
175
+ {
176
+ type: "text",
177
+ text: date,
178
+ size: "xl",
179
+ weight: "bold",
180
+ color: "#111111",
181
+ wrap: true,
182
+ },
183
+ ];
184
+ }
185
+ // Event title with accent bar
186
+ const titleBlock = {
187
+ type: "box",
188
+ layout: "horizontal",
189
+ contents: [
190
+ {
191
+ type: "box",
192
+ layout: "vertical",
193
+ contents: [],
194
+ width: "4px",
195
+ backgroundColor: "#06C755",
196
+ cornerRadius: "2px",
197
+ },
198
+ {
199
+ type: "box",
200
+ layout: "vertical",
201
+ contents: [
202
+ {
203
+ type: "text",
204
+ text: title,
205
+ size: "lg",
206
+ weight: "bold",
207
+ color: "#1a1a1a",
208
+ wrap: true,
209
+ },
210
+ ...(calendar
211
+ ? [
212
+ {
213
+ type: "text",
214
+ text: calendar,
215
+ size: "xs",
216
+ color: "#888888",
217
+ margin: "sm",
218
+ wrap: true,
219
+ },
220
+ ]
221
+ : []),
222
+ ],
223
+ flex: 1,
224
+ paddingStart: "lg",
225
+ },
226
+ ],
227
+ paddingTop: "lg",
228
+ paddingBottom: "lg",
229
+ borderWidth: "light",
230
+ borderColor: "#EEEEEE",
231
+ };
232
+ const bodyContents = [dateBlock, titleBlock];
233
+ // Details section (location + description) in subtle background
234
+ const hasDetails = location || description;
235
+ if (hasDetails) {
236
+ const detailItems = [];
237
+ if (location) {
238
+ detailItems.push({
239
+ type: "box",
240
+ layout: "horizontal",
241
+ contents: [
242
+ {
243
+ type: "text",
244
+ text: "📍",
245
+ size: "sm",
246
+ flex: 0,
247
+ },
248
+ {
249
+ type: "text",
250
+ text: location,
251
+ size: "sm",
252
+ color: "#444444",
253
+ margin: "md",
254
+ flex: 1,
255
+ wrap: true,
256
+ },
257
+ ],
258
+ alignItems: "flex-start",
259
+ });
260
+ }
261
+ if (description) {
262
+ detailItems.push({
263
+ type: "text",
264
+ text: description,
265
+ size: "sm",
266
+ color: "#666666",
267
+ wrap: true,
268
+ margin: location ? "lg" : "none",
269
+ });
270
+ }
271
+ bodyContents.push({
272
+ type: "box",
273
+ layout: "vertical",
274
+ contents: detailItems,
275
+ margin: "lg",
276
+ paddingAll: "lg",
277
+ backgroundColor: "#F8F9FA",
278
+ cornerRadius: "lg",
279
+ });
280
+ }
281
+ return {
282
+ type: "bubble",
283
+ size: "mega",
284
+ body: {
285
+ type: "box",
286
+ layout: "vertical",
287
+ contents: bodyContents,
288
+ paddingAll: "xl",
289
+ backgroundColor: "#FFFFFF",
290
+ action,
291
+ },
292
+ };
293
+ }
294
+ /**
295
+ * Create a calendar agenda card showing multiple events
296
+ *
297
+ * Editorial timeline design: Time-focused left column with event details
298
+ * on the right. Visual accent bars indicate event priority/recency.
299
+ */
300
+ export function createAgendaCard(params) {
301
+ const { title, subtitle, events, footer } = params;
302
+ // Header with title and optional subtitle
303
+ const headerContents = buildTitleSubtitleHeader({ title, subtitle });
304
+ // Event timeline items
305
+ const eventItems = events.slice(0, 6).map((event, index) => {
306
+ const isActive = event.isNow || index === 0;
307
+ const accentColor = isActive ? "#06C755" : "#E5E5E5";
308
+ // Time column (fixed width)
309
+ const timeColumn = {
310
+ type: "box",
311
+ layout: "vertical",
312
+ contents: [
313
+ {
314
+ type: "text",
315
+ text: event.time ?? "—",
316
+ size: "sm",
317
+ weight: isActive ? "bold" : "regular",
318
+ color: isActive ? "#06C755" : "#666666",
319
+ align: "end",
320
+ wrap: true,
321
+ },
322
+ ],
323
+ width: "65px",
324
+ justifyContent: "flex-start",
325
+ };
326
+ // Accent dot
327
+ const dotColumn = {
328
+ type: "box",
329
+ layout: "vertical",
330
+ contents: [
331
+ {
332
+ type: "box",
333
+ layout: "vertical",
334
+ contents: [],
335
+ width: "10px",
336
+ height: "10px",
337
+ backgroundColor: accentColor,
338
+ cornerRadius: "5px",
339
+ },
340
+ ],
341
+ width: "24px",
342
+ alignItems: "center",
343
+ justifyContent: "flex-start",
344
+ paddingTop: "xs",
345
+ };
346
+ // Event details column
347
+ const detailContents = [
348
+ {
349
+ type: "text",
350
+ text: event.title,
351
+ size: "md",
352
+ weight: "bold",
353
+ color: "#1a1a1a",
354
+ wrap: true,
355
+ },
356
+ ];
357
+ // Secondary info line
358
+ const secondaryParts = [];
359
+ if (event.location) {
360
+ secondaryParts.push(event.location);
361
+ }
362
+ if (event.calendar) {
363
+ secondaryParts.push(event.calendar);
364
+ }
365
+ if (secondaryParts.length > 0) {
366
+ detailContents.push({
367
+ type: "text",
368
+ text: secondaryParts.join(" · "),
369
+ size: "xs",
370
+ color: "#888888",
371
+ wrap: true,
372
+ margin: "xs",
373
+ });
374
+ }
375
+ const detailColumn = {
376
+ type: "box",
377
+ layout: "vertical",
378
+ contents: detailContents,
379
+ flex: 1,
380
+ };
381
+ return {
382
+ type: "box",
383
+ layout: "horizontal",
384
+ contents: [timeColumn, dotColumn, detailColumn],
385
+ margin: index > 0 ? "xl" : undefined,
386
+ alignItems: "flex-start",
387
+ };
388
+ });
389
+ const bodyContents = [
390
+ ...buildCardHeaderSections(headerContents),
391
+ {
392
+ type: "box",
393
+ layout: "vertical",
394
+ contents: eventItems,
395
+ paddingTop: "xl",
396
+ },
397
+ ];
398
+ return createMegaBubbleWithFooter({ bodyContents, footer });
399
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,100 @@
1
+ import { danger, logVerbose } from "../globals.js";
2
+ import { isRequestBodyLimitError, readRequestBodyWithLimit, requestBodyErrorToText, } from "../infra/http-body.js";
3
+ import { validateLineSignature } from "./signature.js";
4
+ import { isLineWebhookVerificationRequest, parseLineWebhookBody } from "./webhook-utils.js";
5
+ const LINE_WEBHOOK_MAX_BODY_BYTES = 1024 * 1024;
6
+ const LINE_WEBHOOK_BODY_TIMEOUT_MS = 30_000;
7
+ export async function readLineWebhookRequestBody(req, maxBytes = LINE_WEBHOOK_MAX_BODY_BYTES) {
8
+ return await readRequestBodyWithLimit(req, {
9
+ maxBytes,
10
+ timeoutMs: LINE_WEBHOOK_BODY_TIMEOUT_MS,
11
+ });
12
+ }
13
+ export function createLineNodeWebhookHandler(params) {
14
+ const maxBodyBytes = params.maxBodyBytes ?? LINE_WEBHOOK_MAX_BODY_BYTES;
15
+ const readBody = params.readBody ?? readLineWebhookRequestBody;
16
+ return async (req, res) => {
17
+ // Handle GET requests for webhook verification
18
+ if (req.method === "GET") {
19
+ res.statusCode = 200;
20
+ res.setHeader("Content-Type", "text/plain");
21
+ res.end("OK");
22
+ return;
23
+ }
24
+ // Only accept POST requests
25
+ if (req.method !== "POST") {
26
+ res.statusCode = 405;
27
+ res.setHeader("Allow", "GET, POST");
28
+ res.setHeader("Content-Type", "application/json");
29
+ res.end(JSON.stringify({ error: "Method Not Allowed" }));
30
+ return;
31
+ }
32
+ try {
33
+ const rawBody = await readBody(req, maxBodyBytes);
34
+ const signature = req.headers["x-line-signature"];
35
+ // Parse once; we may need it for verification requests and for event processing.
36
+ const body = parseLineWebhookBody(rawBody);
37
+ // LINE webhook verification sends POST {"events":[]} without a
38
+ // signature header. Return 200 so the LINE Developers Console
39
+ // "Verify" button succeeds.
40
+ if (!signature || typeof signature !== "string") {
41
+ if (isLineWebhookVerificationRequest(body)) {
42
+ logVerbose("line: webhook verification request (empty events, no signature) - 200 OK");
43
+ res.statusCode = 200;
44
+ res.setHeader("Content-Type", "application/json");
45
+ res.end(JSON.stringify({ status: "ok" }));
46
+ return;
47
+ }
48
+ logVerbose("line: webhook missing X-Line-Signature header");
49
+ res.statusCode = 400;
50
+ res.setHeader("Content-Type", "application/json");
51
+ res.end(JSON.stringify({ error: "Missing X-Line-Signature header" }));
52
+ return;
53
+ }
54
+ if (!validateLineSignature(rawBody, signature, params.channelSecret)) {
55
+ logVerbose("line: webhook signature validation failed");
56
+ res.statusCode = 401;
57
+ res.setHeader("Content-Type", "application/json");
58
+ res.end(JSON.stringify({ error: "Invalid signature" }));
59
+ return;
60
+ }
61
+ if (!body) {
62
+ res.statusCode = 400;
63
+ res.setHeader("Content-Type", "application/json");
64
+ res.end(JSON.stringify({ error: "Invalid webhook payload" }));
65
+ return;
66
+ }
67
+ // Respond immediately with 200 to avoid LINE timeout
68
+ res.statusCode = 200;
69
+ res.setHeader("Content-Type", "application/json");
70
+ res.end(JSON.stringify({ status: "ok" }));
71
+ // Process events asynchronously
72
+ if (body.events && body.events.length > 0) {
73
+ logVerbose(`line: received ${body.events.length} webhook events`);
74
+ await params.bot.handleWebhook(body).catch((err) => {
75
+ params.runtime.error?.(danger(`line webhook handler failed: ${String(err)}`));
76
+ });
77
+ }
78
+ }
79
+ catch (err) {
80
+ if (isRequestBodyLimitError(err, "PAYLOAD_TOO_LARGE")) {
81
+ res.statusCode = 413;
82
+ res.setHeader("Content-Type", "application/json");
83
+ res.end(JSON.stringify({ error: "Payload too large" }));
84
+ return;
85
+ }
86
+ if (isRequestBodyLimitError(err, "REQUEST_BODY_TIMEOUT")) {
87
+ res.statusCode = 408;
88
+ res.setHeader("Content-Type", "application/json");
89
+ res.end(JSON.stringify({ error: requestBodyErrorToText("REQUEST_BODY_TIMEOUT") }));
90
+ return;
91
+ }
92
+ params.runtime.error?.(danger(`line webhook error: ${String(err)}`));
93
+ if (!res.headersSent) {
94
+ res.statusCode = 500;
95
+ res.setHeader("Content-Type", "application/json");
96
+ res.end(JSON.stringify({ error: "Internal server error" }));
97
+ }
98
+ }
99
+ };
100
+ }
@@ -0,0 +1,11 @@
1
+ export function parseLineWebhookBody(rawBody) {
2
+ try {
3
+ return JSON.parse(rawBody);
4
+ }
5
+ catch {
6
+ return null;
7
+ }
8
+ }
9
+ export function isLineWebhookVerificationRequest(body) {
10
+ return !!body && Array.isArray(body.events) && body.events.length === 0;
11
+ }
@@ -0,0 +1,14 @@
1
+ export function formatLocalIsoWithOffset(now) {
2
+ const year = now.getFullYear();
3
+ const month = String(now.getMonth() + 1).padStart(2, "0");
4
+ const day = String(now.getDate()).padStart(2, "0");
5
+ const h = String(now.getHours()).padStart(2, "0");
6
+ const m = String(now.getMinutes()).padStart(2, "0");
7
+ const s = String(now.getSeconds()).padStart(2, "0");
8
+ const ms = String(now.getMilliseconds()).padStart(3, "0");
9
+ const tzOffset = now.getTimezoneOffset();
10
+ const tzSign = tzOffset <= 0 ? "+" : "-";
11
+ const tzHours = String(Math.floor(Math.abs(tzOffset) / 60)).padStart(2, "0");
12
+ const tzMinutes = String(Math.abs(tzOffset) % 60).padStart(2, "0");
13
+ return `${year}-${month}-${day}T${h}:${m}:${s}.${ms}${tzSign}${tzHours}:${tzMinutes}`;
14
+ }
@@ -0,0 +1,62 @@
1
+ import { escapeRegExp } from "../utils.js";
2
+ /**
3
+ * Convert standard Markdown formatting to WhatsApp-compatible markup.
4
+ *
5
+ * WhatsApp uses its own formatting syntax:
6
+ * bold: *text*
7
+ * italic: _text_
8
+ * strikethrough: ~text~
9
+ * monospace: ```text```
10
+ *
11
+ * Standard Markdown uses:
12
+ * bold: **text** or __text__
13
+ * italic: *text* or _text_
14
+ * strikethrough: ~~text~~
15
+ * code: `text` (inline) or ```text``` (block)
16
+ *
17
+ * The conversion preserves fenced code blocks and inline code,
18
+ * then converts bold and strikethrough markers.
19
+ */
20
+ /** Placeholder tokens used during conversion to protect code spans. */
21
+ const FENCE_PLACEHOLDER = "\x00FENCE";
22
+ const INLINE_CODE_PLACEHOLDER = "\x00CODE";
23
+ /**
24
+ * Convert standard Markdown bold/italic/strikethrough to WhatsApp formatting.
25
+ *
26
+ * Order of operations matters:
27
+ * 1. Protect fenced code blocks (```...```) — already WhatsApp-compatible
28
+ * 2. Protect inline code (`...`) — leave as-is
29
+ * 3. Convert **bold** → *bold* and __bold__ → *bold*
30
+ * 4. Convert ~~strike~~ → ~strike~
31
+ * 5. Restore protected spans
32
+ *
33
+ * Italic *text* and _text_ are left alone since WhatsApp uses _text_ for italic
34
+ * and single * is already WhatsApp bold — no conversion needed for single markers.
35
+ */
36
+ export function markdownToWhatsApp(text) {
37
+ if (!text) {
38
+ return text;
39
+ }
40
+ // 1. Extract and protect fenced code blocks
41
+ const fences = [];
42
+ let result = text.replace(/```[\s\S]*?```/g, (match) => {
43
+ fences.push(match);
44
+ return `${FENCE_PLACEHOLDER}${fences.length - 1}`;
45
+ });
46
+ // 2. Extract and protect inline code
47
+ const inlineCodes = [];
48
+ result = result.replace(/`[^`\n]+`/g, (match) => {
49
+ inlineCodes.push(match);
50
+ return `${INLINE_CODE_PLACEHOLDER}${inlineCodes.length - 1}`;
51
+ });
52
+ // 3. Convert **bold** → *bold* and __bold__ → *bold*
53
+ result = result.replace(/\*\*(.+?)\*\*/g, "*$1*");
54
+ result = result.replace(/__(.+?)__/g, "*$1*");
55
+ // 4. Convert ~~strikethrough~~ → ~strikethrough~
56
+ result = result.replace(/~~(.+?)~~/g, "~$1~");
57
+ // 5. Restore inline code
58
+ result = result.replace(new RegExp(`${escapeRegExp(INLINE_CODE_PLACEHOLDER)}(\\d+)`, "g"), (_, idx) => inlineCodes[Number(idx)] ?? "");
59
+ // 6. Restore fenced code blocks
60
+ result = result.replace(new RegExp(`${escapeRegExp(FENCE_PLACEHOLDER)}(\\d+)`, "g"), (_, idx) => fences[Number(idx)] ?? "");
61
+ return result;
62
+ }
@@ -0,0 +1,34 @@
1
+ export function estimateBase64DecodedBytes(base64) {
2
+ // Avoid `trim()`/`replace()` here: they allocate a second (potentially huge) string.
3
+ // We only need a conservative decoded-size estimate to enforce budgets before Buffer.from(..., "base64").
4
+ let effectiveLen = 0;
5
+ for (let i = 0; i < base64.length; i += 1) {
6
+ const code = base64.charCodeAt(i);
7
+ // Treat ASCII control + space as whitespace; base64 decoders commonly ignore these.
8
+ if (code <= 0x20) {
9
+ continue;
10
+ }
11
+ effectiveLen += 1;
12
+ }
13
+ if (effectiveLen === 0) {
14
+ return 0;
15
+ }
16
+ let padding = 0;
17
+ // Find last non-whitespace char(s) to detect '=' padding without allocating/copying.
18
+ let end = base64.length - 1;
19
+ while (end >= 0 && base64.charCodeAt(end) <= 0x20) {
20
+ end -= 1;
21
+ }
22
+ if (end >= 0 && base64[end] === "=") {
23
+ padding = 1;
24
+ end -= 1;
25
+ while (end >= 0 && base64.charCodeAt(end) <= 0x20) {
26
+ end -= 1;
27
+ }
28
+ if (end >= 0 && base64[end] === "=") {
29
+ padding = 2;
30
+ }
31
+ }
32
+ const estimated = Math.floor((effectiveLen * 3) / 4) - padding;
33
+ return Math.max(0, estimated);
34
+ }
@@ -0,0 +1,32 @@
1
+ import os from "node:os";
2
+ import path from "node:path";
3
+ import { resolveAgentWorkspaceDir } from "../agents/agent-scope.js";
4
+ import { resolveStateDir } from "../config/paths.js";
5
+ function buildMediaLocalRoots(stateDir) {
6
+ const resolvedStateDir = path.resolve(stateDir);
7
+ return [
8
+ os.tmpdir(),
9
+ path.join(resolvedStateDir, "media"),
10
+ path.join(resolvedStateDir, "agents"),
11
+ path.join(resolvedStateDir, "workspace"),
12
+ path.join(resolvedStateDir, "sandboxes"),
13
+ ];
14
+ }
15
+ export function getDefaultMediaLocalRoots() {
16
+ return buildMediaLocalRoots(resolveStateDir());
17
+ }
18
+ export function getAgentScopedMediaLocalRoots(cfg, agentId) {
19
+ const roots = buildMediaLocalRoots(resolveStateDir());
20
+ if (!agentId?.trim()) {
21
+ return roots;
22
+ }
23
+ const workspaceDir = resolveAgentWorkspaceDir(cfg, agentId);
24
+ if (!workspaceDir) {
25
+ return roots;
26
+ }
27
+ const normalizedWorkspaceDir = path.resolve(workspaceDir);
28
+ if (!roots.includes(normalizedWorkspaceDir)) {
29
+ roots.push(normalizedWorkspaceDir);
30
+ }
31
+ return roots;
32
+ }
@@ -0,0 +1,10 @@
1
+ import { loadWebMedia } from "../web/media.js";
2
+ import { saveMediaBuffer } from "./store.js";
3
+ export async function resolveOutboundAttachmentFromUrl(mediaUrl, maxBytes, options) {
4
+ const media = await loadWebMedia(mediaUrl, {
5
+ maxBytes,
6
+ localRoots: options?.localRoots,
7
+ });
8
+ const saved = await saveMediaBuffer(media.buffer, media.contentType ?? undefined, "outbound", maxBytes);
9
+ return { path: saved.path, contentType: saved.contentType };
10
+ }