@poolzin/pool-bot 2026.2.17 → 2026.2.18

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 (469) hide show
  1. package/CHANGELOG.md +17 -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/discord/src/channel.js +366 -0
  381. package/extensions/discord/src/runtime.js +10 -0
  382. package/extensions/feishu/index.ts +63 -0
  383. package/extensions/feishu/src/accounts.ts +114 -0
  384. package/extensions/feishu/src/bitable.ts +739 -0
  385. package/extensions/feishu/src/bot.ts +965 -0
  386. package/extensions/feishu/src/channel.ts +351 -0
  387. package/extensions/feishu/src/client.ts +118 -0
  388. package/extensions/feishu/src/config-schema.ts +206 -0
  389. package/extensions/feishu/src/dedup.ts +33 -0
  390. package/extensions/feishu/src/directory.ts +177 -0
  391. package/extensions/feishu/src/doc-schema.ts +47 -0
  392. package/extensions/feishu/src/docx.ts +536 -0
  393. package/extensions/feishu/src/drive-schema.ts +46 -0
  394. package/extensions/feishu/src/drive.ts +227 -0
  395. package/extensions/feishu/src/dynamic-agent.ts +131 -0
  396. package/extensions/feishu/src/media.ts +449 -0
  397. package/extensions/feishu/src/mention.ts +126 -0
  398. package/extensions/feishu/src/monitor.ts +330 -0
  399. package/extensions/feishu/src/onboarding.ts +359 -0
  400. package/extensions/feishu/src/outbound.ts +55 -0
  401. package/extensions/feishu/src/perm-schema.ts +52 -0
  402. package/extensions/feishu/src/perm.ts +173 -0
  403. package/extensions/feishu/src/policy.ts +84 -0
  404. package/extensions/feishu/src/probe.ts +44 -0
  405. package/extensions/feishu/src/reactions.ts +160 -0
  406. package/extensions/feishu/src/reply-dispatcher.ts +239 -0
  407. package/extensions/feishu/src/runtime.ts +14 -0
  408. package/extensions/feishu/src/send-result.ts +29 -0
  409. package/extensions/feishu/src/send.ts +335 -0
  410. package/extensions/feishu/src/streaming-card.ts +223 -0
  411. package/extensions/feishu/src/targets.ts +78 -0
  412. package/extensions/feishu/src/tools-config.ts +21 -0
  413. package/extensions/feishu/src/types.ts +81 -0
  414. package/extensions/feishu/src/typing.ts +80 -0
  415. package/extensions/feishu/src/wiki-schema.ts +55 -0
  416. package/extensions/feishu/src/wiki.ts +232 -0
  417. package/extensions/imessage/src/channel.js +253 -0
  418. package/extensions/imessage/src/runtime.js +10 -0
  419. package/extensions/irc/index.ts +17 -0
  420. package/extensions/irc/src/accounts.ts +268 -0
  421. package/extensions/irc/src/channel.ts +367 -0
  422. package/extensions/irc/src/client.ts +439 -0
  423. package/extensions/irc/src/config-schema.ts +97 -0
  424. package/extensions/irc/src/connect-options.ts +30 -0
  425. package/extensions/irc/src/control-chars.ts +22 -0
  426. package/extensions/irc/src/inbound.ts +334 -0
  427. package/extensions/irc/src/monitor.ts +147 -0
  428. package/extensions/irc/src/normalize.ts +117 -0
  429. package/extensions/irc/src/onboarding.ts +479 -0
  430. package/extensions/irc/src/policy.ts +157 -0
  431. package/extensions/irc/src/probe.ts +53 -0
  432. package/extensions/irc/src/protocol.ts +169 -0
  433. package/extensions/irc/src/runtime.ts +14 -0
  434. package/extensions/irc/src/send.ts +88 -0
  435. package/extensions/irc/src/types.ts +93 -0
  436. package/extensions/matrix/src/matrix/client-bootstrap.ts +39 -0
  437. package/extensions/mattermost/src/mattermost/monitor-onchar.ts +25 -0
  438. package/extensions/mattermost/src/mattermost/monitor-websocket.ts +221 -0
  439. package/extensions/mattermost/src/mattermost/reactions.ts +130 -0
  440. package/extensions/mattermost/src/mattermost/reconnect.ts +103 -0
  441. package/extensions/minimax-portal-auth/index.ts +161 -0
  442. package/extensions/minimax-portal-auth/oauth.ts +247 -0
  443. package/extensions/msteams/src/file-lock.ts +1 -0
  444. package/extensions/msteams/src/graph.ts +92 -0
  445. package/extensions/msteams/src/mentions.ts +114 -0
  446. package/extensions/msteams/src/test-runtime.ts +16 -0
  447. package/extensions/openai-codex-auth/index.ts +177 -0
  448. package/extensions/phone-control/index.ts +421 -0
  449. package/extensions/shared/resolve-target-test-helpers.ts +66 -0
  450. package/extensions/signal/src/channel.js +273 -0
  451. package/extensions/signal/src/runtime.js +10 -0
  452. package/extensions/slack/src/channel.js +489 -0
  453. package/extensions/slack/src/runtime.js +10 -0
  454. package/extensions/talk-voice/index.ts +150 -0
  455. package/extensions/telegram/src/channel.js +424 -0
  456. package/extensions/telegram/src/runtime.js +10 -0
  457. package/extensions/thread-ownership/index.ts +133 -0
  458. package/extensions/tlon/src/account-fields.ts +25 -0
  459. package/extensions/tlon/src/urbit/base-url.ts +57 -0
  460. package/extensions/tlon/src/urbit/channel-client.ts +157 -0
  461. package/extensions/tlon/src/urbit/channel-ops.ts +164 -0
  462. package/extensions/tlon/src/urbit/context.ts +47 -0
  463. package/extensions/tlon/src/urbit/errors.ts +51 -0
  464. package/extensions/tlon/src/urbit/fetch.ts +39 -0
  465. package/extensions/twitch/src/test-fixtures.ts +30 -0
  466. package/extensions/voice-call/src/allowlist.ts +19 -0
  467. package/extensions/whatsapp/src/channel.js +429 -0
  468. package/extensions/whatsapp/src/runtime.js +10 -0
  469. package/package.json +1 -1
@@ -0,0 +1,816 @@
1
+ import crypto from "node:crypto";
2
+ import { Button, ChannelSelectMenu, CheckboxGroup, Container, File, Label, LinkButton, MediaGallery, MentionableSelectMenu, Modal, RadioGroup, RoleSelectMenu, Row, Section, Separator, StringSelectMenu, TextDisplay, TextInput, Thumbnail, UserSelectMenu, parseCustomId, } from "@buape/carbon";
3
+ import { ButtonStyle, MessageFlags, TextInputStyle } from "discord-api-types/v10";
4
+ export const DISCORD_COMPONENT_CUSTOM_ID_KEY = "occomp";
5
+ export const DISCORD_MODAL_CUSTOM_ID_KEY = "ocmodal";
6
+ export const DISCORD_COMPONENT_ATTACHMENT_PREFIX = "attachment://";
7
+ const BLOCK_ALIASES = new Map([
8
+ ["row", "actions"],
9
+ ["action-row", "actions"],
10
+ ]);
11
+ function createShortId(prefix) {
12
+ return `${prefix}${crypto.randomBytes(6).toString("base64url")}`;
13
+ }
14
+ function requireObject(value, label) {
15
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
16
+ throw new Error(`${label} must be an object`);
17
+ }
18
+ return value;
19
+ }
20
+ function readString(value, label, opts) {
21
+ if (typeof value !== "string") {
22
+ throw new Error(`${label} must be a string`);
23
+ }
24
+ const trimmed = value.trim();
25
+ if (!opts?.allowEmpty && !trimmed) {
26
+ throw new Error(`${label} cannot be empty`);
27
+ }
28
+ return opts?.allowEmpty ? value : trimmed;
29
+ }
30
+ function readOptionalString(value) {
31
+ if (typeof value !== "string") {
32
+ return undefined;
33
+ }
34
+ const trimmed = value.trim();
35
+ return trimmed ? trimmed : undefined;
36
+ }
37
+ function readOptionalStringArray(value, label) {
38
+ if (value === undefined) {
39
+ return undefined;
40
+ }
41
+ if (!Array.isArray(value)) {
42
+ throw new Error(`${label} must be an array`);
43
+ }
44
+ if (value.length === 0) {
45
+ return undefined;
46
+ }
47
+ return value.map((entry, index) => readString(entry, `${label}[${index}]`));
48
+ }
49
+ function readOptionalNumber(value) {
50
+ if (typeof value !== "number" || !Number.isFinite(value)) {
51
+ return undefined;
52
+ }
53
+ return value;
54
+ }
55
+ function normalizeModalFieldName(value, index) {
56
+ const trimmed = value?.trim();
57
+ if (trimmed) {
58
+ return trimmed;
59
+ }
60
+ return `field_${index + 1}`;
61
+ }
62
+ function normalizeAttachmentRef(value, label) {
63
+ const trimmed = value.trim();
64
+ if (!trimmed.startsWith(DISCORD_COMPONENT_ATTACHMENT_PREFIX)) {
65
+ throw new Error(`${label} must start with "${DISCORD_COMPONENT_ATTACHMENT_PREFIX}"`);
66
+ }
67
+ const attachmentName = trimmed.slice(DISCORD_COMPONENT_ATTACHMENT_PREFIX.length).trim();
68
+ if (!attachmentName) {
69
+ throw new Error(`${label} must include an attachment filename`);
70
+ }
71
+ return `${DISCORD_COMPONENT_ATTACHMENT_PREFIX}${attachmentName}`;
72
+ }
73
+ export function resolveDiscordComponentAttachmentName(value) {
74
+ const trimmed = value.trim();
75
+ if (!trimmed.startsWith(DISCORD_COMPONENT_ATTACHMENT_PREFIX)) {
76
+ throw new Error(`Attachment reference must start with "${DISCORD_COMPONENT_ATTACHMENT_PREFIX}"`);
77
+ }
78
+ const attachmentName = trimmed.slice(DISCORD_COMPONENT_ATTACHMENT_PREFIX.length).trim();
79
+ if (!attachmentName) {
80
+ throw new Error("Attachment reference must include a filename");
81
+ }
82
+ return attachmentName;
83
+ }
84
+ function mapButtonStyle(style) {
85
+ switch ((style ?? "primary").toLowerCase()) {
86
+ case "secondary":
87
+ return ButtonStyle.Secondary;
88
+ case "success":
89
+ return ButtonStyle.Success;
90
+ case "danger":
91
+ return ButtonStyle.Danger;
92
+ case "link":
93
+ return ButtonStyle.Link;
94
+ case "primary":
95
+ default:
96
+ return ButtonStyle.Primary;
97
+ }
98
+ }
99
+ function mapTextInputStyle(style) {
100
+ return style === "paragraph" ? TextInputStyle.Paragraph : TextInputStyle.Short;
101
+ }
102
+ function normalizeBlockType(raw) {
103
+ const lowered = raw.trim().toLowerCase();
104
+ return BLOCK_ALIASES.get(lowered) ?? lowered;
105
+ }
106
+ function parseSelectOptions(raw, label) {
107
+ if (raw === undefined) {
108
+ return undefined;
109
+ }
110
+ if (!Array.isArray(raw)) {
111
+ throw new Error(`${label} must be an array`);
112
+ }
113
+ return raw.map((entry, index) => {
114
+ const obj = requireObject(entry, `${label}[${index}]`);
115
+ return {
116
+ label: readString(obj.label, `${label}[${index}].label`),
117
+ value: readString(obj.value, `${label}[${index}].value`),
118
+ description: readOptionalString(obj.description),
119
+ emoji: typeof obj.emoji === "object" && obj.emoji && !Array.isArray(obj.emoji)
120
+ ? {
121
+ name: readString(obj.emoji.name, `${label}[${index}].emoji.name`),
122
+ id: readOptionalString(obj.emoji.id),
123
+ animated: typeof obj.emoji.animated === "boolean"
124
+ ? obj.emoji.animated
125
+ : undefined,
126
+ }
127
+ : undefined,
128
+ default: typeof obj.default === "boolean" ? obj.default : undefined,
129
+ };
130
+ });
131
+ }
132
+ function parseButtonSpec(raw, label) {
133
+ const obj = requireObject(raw, label);
134
+ const style = readOptionalString(obj.style);
135
+ const url = readOptionalString(obj.url);
136
+ if ((style === "link" || url) && !url) {
137
+ throw new Error(`${label}.url is required for link buttons`);
138
+ }
139
+ return {
140
+ label: readString(obj.label, `${label}.label`),
141
+ style,
142
+ url,
143
+ emoji: typeof obj.emoji === "object" && obj.emoji && !Array.isArray(obj.emoji)
144
+ ? {
145
+ name: readString(obj.emoji.name, `${label}.emoji.name`),
146
+ id: readOptionalString(obj.emoji.id),
147
+ animated: typeof obj.emoji.animated === "boolean"
148
+ ? obj.emoji.animated
149
+ : undefined,
150
+ }
151
+ : undefined,
152
+ disabled: typeof obj.disabled === "boolean" ? obj.disabled : undefined,
153
+ allowedUsers: readOptionalStringArray(obj.allowedUsers, `${label}.allowedUsers`),
154
+ };
155
+ }
156
+ function parseSelectSpec(raw, label) {
157
+ const obj = requireObject(raw, label);
158
+ const type = readOptionalString(obj.type);
159
+ const allowedTypes = [
160
+ "string",
161
+ "user",
162
+ "role",
163
+ "mentionable",
164
+ "channel",
165
+ ];
166
+ if (type && !allowedTypes.includes(type)) {
167
+ throw new Error(`${label}.type must be one of ${allowedTypes.join(", ")}`);
168
+ }
169
+ return {
170
+ type,
171
+ placeholder: readOptionalString(obj.placeholder),
172
+ minValues: readOptionalNumber(obj.minValues),
173
+ maxValues: readOptionalNumber(obj.maxValues),
174
+ options: parseSelectOptions(obj.options, `${label}.options`),
175
+ };
176
+ }
177
+ function parseModalField(raw, label, index) {
178
+ const obj = requireObject(raw, label);
179
+ const type = readString(obj.type, `${label}.type`).toLowerCase();
180
+ const supported = [
181
+ "text",
182
+ "checkbox",
183
+ "radio",
184
+ "select",
185
+ "role-select",
186
+ "user-select",
187
+ ];
188
+ if (!supported.includes(type)) {
189
+ throw new Error(`${label}.type must be one of ${supported.join(", ")}`);
190
+ }
191
+ const options = parseSelectOptions(obj.options, `${label}.options`);
192
+ if (["checkbox", "radio", "select"].includes(type) && (!options || options.length === 0)) {
193
+ throw new Error(`${label}.options is required for ${type} fields`);
194
+ }
195
+ return {
196
+ type,
197
+ name: normalizeModalFieldName(readOptionalString(obj.name), index),
198
+ label: readString(obj.label, `${label}.label`),
199
+ description: readOptionalString(obj.description),
200
+ placeholder: readOptionalString(obj.placeholder),
201
+ required: typeof obj.required === "boolean" ? obj.required : undefined,
202
+ options,
203
+ minValues: readOptionalNumber(obj.minValues),
204
+ maxValues: readOptionalNumber(obj.maxValues),
205
+ minLength: readOptionalNumber(obj.minLength),
206
+ maxLength: readOptionalNumber(obj.maxLength),
207
+ style: readOptionalString(obj.style),
208
+ };
209
+ }
210
+ function parseComponentBlock(raw, label) {
211
+ const obj = requireObject(raw, label);
212
+ const typeRaw = readString(obj.type, `${label}.type`).toLowerCase();
213
+ const type = normalizeBlockType(typeRaw);
214
+ switch (type) {
215
+ case "text":
216
+ return {
217
+ type: "text",
218
+ text: readString(obj.text, `${label}.text`),
219
+ };
220
+ case "section": {
221
+ const text = readOptionalString(obj.text);
222
+ const textsRaw = obj.texts;
223
+ const texts = Array.isArray(textsRaw)
224
+ ? textsRaw.map((entry, idx) => readString(entry, `${label}.texts[${idx}]`))
225
+ : undefined;
226
+ if (!text && (!texts || texts.length === 0)) {
227
+ throw new Error(`${label}.text or ${label}.texts is required for section blocks`);
228
+ }
229
+ let accessory;
230
+ if (obj.accessory !== undefined) {
231
+ const accessoryObj = requireObject(obj.accessory, `${label}.accessory`);
232
+ const accessoryType = readString(accessoryObj.type, `${label}.accessory.type`).toLowerCase();
233
+ if (accessoryType === "thumbnail") {
234
+ accessory = {
235
+ type: "thumbnail",
236
+ url: readString(accessoryObj.url, `${label}.accessory.url`),
237
+ };
238
+ }
239
+ else if (accessoryType === "button") {
240
+ accessory = {
241
+ type: "button",
242
+ button: parseButtonSpec(accessoryObj.button, `${label}.accessory.button`),
243
+ };
244
+ }
245
+ else {
246
+ throw new Error(`${label}.accessory.type must be "thumbnail" or "button"`);
247
+ }
248
+ }
249
+ return {
250
+ type: "section",
251
+ text,
252
+ texts,
253
+ accessory,
254
+ };
255
+ }
256
+ case "separator": {
257
+ const spacingRaw = obj.spacing;
258
+ let spacing;
259
+ if (spacingRaw === "small" || spacingRaw === "large") {
260
+ spacing = spacingRaw;
261
+ }
262
+ else if (spacingRaw === 1 || spacingRaw === 2) {
263
+ spacing = spacingRaw;
264
+ }
265
+ else if (spacingRaw !== undefined) {
266
+ throw new Error(`${label}.spacing must be "small", "large", 1, or 2`);
267
+ }
268
+ const divider = typeof obj.divider === "boolean" ? obj.divider : undefined;
269
+ return {
270
+ type: "separator",
271
+ spacing,
272
+ divider,
273
+ };
274
+ }
275
+ case "actions": {
276
+ const buttonsRaw = obj.buttons;
277
+ const buttons = Array.isArray(buttonsRaw)
278
+ ? buttonsRaw.map((entry, idx) => parseButtonSpec(entry, `${label}.buttons[${idx}]`))
279
+ : undefined;
280
+ const select = obj.select ? parseSelectSpec(obj.select, `${label}.select`) : undefined;
281
+ if ((!buttons || buttons.length === 0) && !select) {
282
+ throw new Error(`${label} requires buttons or select`);
283
+ }
284
+ if (buttons && select) {
285
+ throw new Error(`${label} cannot include both buttons and select`);
286
+ }
287
+ return {
288
+ type: "actions",
289
+ buttons,
290
+ select,
291
+ };
292
+ }
293
+ case "media-gallery": {
294
+ const itemsRaw = obj.items;
295
+ if (!Array.isArray(itemsRaw) || itemsRaw.length === 0) {
296
+ throw new Error(`${label}.items must be a non-empty array`);
297
+ }
298
+ const items = itemsRaw.map((entry, idx) => {
299
+ const itemObj = requireObject(entry, `${label}.items[${idx}]`);
300
+ return {
301
+ url: readString(itemObj.url, `${label}.items[${idx}].url`),
302
+ description: readOptionalString(itemObj.description),
303
+ spoiler: typeof itemObj.spoiler === "boolean" ? itemObj.spoiler : undefined,
304
+ };
305
+ });
306
+ return {
307
+ type: "media-gallery",
308
+ items,
309
+ };
310
+ }
311
+ case "file": {
312
+ const file = readString(obj.file, `${label}.file`);
313
+ return {
314
+ type: "file",
315
+ file: normalizeAttachmentRef(file, `${label}.file`),
316
+ spoiler: typeof obj.spoiler === "boolean" ? obj.spoiler : undefined,
317
+ };
318
+ }
319
+ default:
320
+ throw new Error(`${label}.type must be a supported component block`);
321
+ }
322
+ }
323
+ export function readDiscordComponentSpec(raw) {
324
+ if (raw === undefined || raw === null) {
325
+ return null;
326
+ }
327
+ const obj = requireObject(raw, "components");
328
+ const blocksRaw = obj.blocks;
329
+ const blocks = Array.isArray(blocksRaw)
330
+ ? blocksRaw.map((entry, idx) => parseComponentBlock(entry, `components.blocks[${idx}]`))
331
+ : undefined;
332
+ const modalRaw = obj.modal;
333
+ const reusable = typeof obj.reusable === "boolean" ? obj.reusable : undefined;
334
+ let modal;
335
+ if (modalRaw !== undefined) {
336
+ const modalObj = requireObject(modalRaw, "components.modal");
337
+ const fieldsRaw = modalObj.fields;
338
+ if (!Array.isArray(fieldsRaw) || fieldsRaw.length === 0) {
339
+ throw new Error("components.modal.fields must be a non-empty array");
340
+ }
341
+ if (fieldsRaw.length > 5) {
342
+ throw new Error("components.modal.fields supports up to 5 inputs");
343
+ }
344
+ const fields = fieldsRaw.map((entry, idx) => parseModalField(entry, `components.modal.fields[${idx}]`, idx));
345
+ modal = {
346
+ title: readString(modalObj.title, "components.modal.title"),
347
+ triggerLabel: readOptionalString(modalObj.triggerLabel),
348
+ triggerStyle: readOptionalString(modalObj.triggerStyle),
349
+ fields,
350
+ };
351
+ }
352
+ return {
353
+ text: readOptionalString(obj.text),
354
+ reusable,
355
+ container: typeof obj.container === "object" && obj.container && !Array.isArray(obj.container)
356
+ ? {
357
+ accentColor: obj.container.accentColor,
358
+ spoiler: typeof obj.container.spoiler === "boolean"
359
+ ? obj.container.spoiler
360
+ : undefined,
361
+ }
362
+ : undefined,
363
+ blocks,
364
+ modal,
365
+ };
366
+ }
367
+ export function buildDiscordComponentCustomId(params) {
368
+ const base = `${DISCORD_COMPONENT_CUSTOM_ID_KEY}:cid=${params.componentId}`;
369
+ return params.modalId ? `${base};mid=${params.modalId}` : base;
370
+ }
371
+ export function buildDiscordModalCustomId(modalId) {
372
+ return `${DISCORD_MODAL_CUSTOM_ID_KEY}:mid=${modalId}`;
373
+ }
374
+ export function parseDiscordComponentCustomId(id) {
375
+ const parsed = parseCustomId(id);
376
+ if (parsed.key !== DISCORD_COMPONENT_CUSTOM_ID_KEY) {
377
+ return null;
378
+ }
379
+ const componentId = parsed.data.cid;
380
+ if (typeof componentId !== "string" || !componentId.trim()) {
381
+ return null;
382
+ }
383
+ const modalId = parsed.data.mid;
384
+ return {
385
+ componentId,
386
+ modalId: typeof modalId === "string" && modalId.trim() ? modalId : undefined,
387
+ };
388
+ }
389
+ export function parseDiscordModalCustomId(id) {
390
+ const parsed = parseCustomId(id);
391
+ if (parsed.key !== DISCORD_MODAL_CUSTOM_ID_KEY) {
392
+ return null;
393
+ }
394
+ const modalId = parsed.data.mid;
395
+ if (typeof modalId !== "string" || !modalId.trim()) {
396
+ return null;
397
+ }
398
+ return modalId;
399
+ }
400
+ export function parseDiscordComponentCustomIdForCarbon(id) {
401
+ if (id === "*") {
402
+ return { key: "*", data: {} };
403
+ }
404
+ const parsed = parseCustomId(id);
405
+ if (parsed.key !== DISCORD_COMPONENT_CUSTOM_ID_KEY) {
406
+ return parsed;
407
+ }
408
+ return { key: "*", data: parsed.data };
409
+ }
410
+ export function parseDiscordModalCustomIdForCarbon(id) {
411
+ if (id === "*") {
412
+ return { key: "*", data: {} };
413
+ }
414
+ const parsed = parseCustomId(id);
415
+ if (parsed.key !== DISCORD_MODAL_CUSTOM_ID_KEY) {
416
+ return parsed;
417
+ }
418
+ return { key: "*", data: parsed.data };
419
+ }
420
+ function buildTextDisplays(text, texts) {
421
+ if (texts && texts.length > 0) {
422
+ return texts.map((entry) => new TextDisplay(entry));
423
+ }
424
+ if (text) {
425
+ return [new TextDisplay(text)];
426
+ }
427
+ return [];
428
+ }
429
+ function createButtonComponent(params) {
430
+ const style = mapButtonStyle(params.spec.style);
431
+ const isLink = style === ButtonStyle.Link || Boolean(params.spec.url);
432
+ if (isLink) {
433
+ if (!params.spec.url) {
434
+ throw new Error("Link buttons require a url");
435
+ }
436
+ const linkUrl = params.spec.url;
437
+ class DynamicLinkButton extends LinkButton {
438
+ label = params.spec.label;
439
+ url = linkUrl;
440
+ }
441
+ return { component: new DynamicLinkButton() };
442
+ }
443
+ const componentId = params.componentId ?? createShortId("btn_");
444
+ const customId = buildDiscordComponentCustomId({
445
+ componentId,
446
+ modalId: params.modalId,
447
+ });
448
+ class DynamicButton extends Button {
449
+ label = params.spec.label;
450
+ customId = customId;
451
+ style = style;
452
+ emoji = params.spec.emoji;
453
+ disabled = params.spec.disabled ?? false;
454
+ }
455
+ return {
456
+ component: new DynamicButton(),
457
+ entry: {
458
+ id: componentId,
459
+ kind: params.modalId ? "modal-trigger" : "button",
460
+ label: params.spec.label,
461
+ modalId: params.modalId,
462
+ allowedUsers: params.spec.allowedUsers,
463
+ },
464
+ };
465
+ }
466
+ function createSelectComponent(params) {
467
+ const type = (params.spec.type ?? "string").toLowerCase();
468
+ const componentId = params.componentId ?? createShortId("sel_");
469
+ const customId = buildDiscordComponentCustomId({ componentId });
470
+ if (type === "string") {
471
+ const options = params.spec.options ?? [];
472
+ if (options.length === 0) {
473
+ throw new Error("String select menus require options");
474
+ }
475
+ class DynamicStringSelect extends StringSelectMenu {
476
+ customId = customId;
477
+ options = options;
478
+ minValues = params.spec.minValues;
479
+ maxValues = params.spec.maxValues;
480
+ placeholder = params.spec.placeholder;
481
+ disabled = false;
482
+ }
483
+ return {
484
+ component: new DynamicStringSelect(),
485
+ entry: {
486
+ id: componentId,
487
+ kind: "select",
488
+ label: params.spec.placeholder ?? "select",
489
+ selectType: "string",
490
+ options: options.map((option) => ({ value: option.value, label: option.label })),
491
+ },
492
+ };
493
+ }
494
+ if (type === "user") {
495
+ class DynamicUserSelect extends UserSelectMenu {
496
+ customId = customId;
497
+ minValues = params.spec.minValues;
498
+ maxValues = params.spec.maxValues;
499
+ placeholder = params.spec.placeholder;
500
+ disabled = false;
501
+ }
502
+ return {
503
+ component: new DynamicUserSelect(),
504
+ entry: {
505
+ id: componentId,
506
+ kind: "select",
507
+ label: params.spec.placeholder ?? "user select",
508
+ selectType: "user",
509
+ },
510
+ };
511
+ }
512
+ if (type === "role") {
513
+ class DynamicRoleSelect extends RoleSelectMenu {
514
+ customId = customId;
515
+ minValues = params.spec.minValues;
516
+ maxValues = params.spec.maxValues;
517
+ placeholder = params.spec.placeholder;
518
+ disabled = false;
519
+ }
520
+ return {
521
+ component: new DynamicRoleSelect(),
522
+ entry: {
523
+ id: componentId,
524
+ kind: "select",
525
+ label: params.spec.placeholder ?? "role select",
526
+ selectType: "role",
527
+ },
528
+ };
529
+ }
530
+ if (type === "mentionable") {
531
+ class DynamicMentionableSelect extends MentionableSelectMenu {
532
+ customId = customId;
533
+ minValues = params.spec.minValues;
534
+ maxValues = params.spec.maxValues;
535
+ placeholder = params.spec.placeholder;
536
+ disabled = false;
537
+ }
538
+ return {
539
+ component: new DynamicMentionableSelect(),
540
+ entry: {
541
+ id: componentId,
542
+ kind: "select",
543
+ label: params.spec.placeholder ?? "mentionable select",
544
+ selectType: "mentionable",
545
+ },
546
+ };
547
+ }
548
+ class DynamicChannelSelect extends ChannelSelectMenu {
549
+ customId = customId;
550
+ minValues = params.spec.minValues;
551
+ maxValues = params.spec.maxValues;
552
+ placeholder = params.spec.placeholder;
553
+ disabled = false;
554
+ }
555
+ return {
556
+ component: new DynamicChannelSelect(),
557
+ entry: {
558
+ id: componentId,
559
+ kind: "select",
560
+ label: params.spec.placeholder ?? "channel select",
561
+ selectType: "channel",
562
+ },
563
+ };
564
+ }
565
+ function isSelectComponent(component) {
566
+ return (component instanceof StringSelectMenu ||
567
+ component instanceof UserSelectMenu ||
568
+ component instanceof RoleSelectMenu ||
569
+ component instanceof MentionableSelectMenu ||
570
+ component instanceof ChannelSelectMenu);
571
+ }
572
+ function createModalFieldComponent(field) {
573
+ if (field.type === "text") {
574
+ class DynamicTextInput extends TextInput {
575
+ customId = field.id;
576
+ style = mapTextInputStyle(field.style);
577
+ placeholder = field.placeholder;
578
+ required = field.required;
579
+ minLength = field.minLength;
580
+ maxLength = field.maxLength;
581
+ }
582
+ return new DynamicTextInput();
583
+ }
584
+ if (field.type === "select") {
585
+ const options = field.options ?? [];
586
+ class DynamicModalSelect extends StringSelectMenu {
587
+ customId = field.id;
588
+ options = options;
589
+ required = field.required;
590
+ minValues = field.minValues;
591
+ maxValues = field.maxValues;
592
+ placeholder = field.placeholder;
593
+ }
594
+ return new DynamicModalSelect();
595
+ }
596
+ if (field.type === "role-select") {
597
+ class DynamicModalRoleSelect extends RoleSelectMenu {
598
+ customId = field.id;
599
+ required = field.required;
600
+ minValues = field.minValues;
601
+ maxValues = field.maxValues;
602
+ placeholder = field.placeholder;
603
+ }
604
+ return new DynamicModalRoleSelect();
605
+ }
606
+ if (field.type === "user-select") {
607
+ class DynamicModalUserSelect extends UserSelectMenu {
608
+ customId = field.id;
609
+ required = field.required;
610
+ minValues = field.minValues;
611
+ maxValues = field.maxValues;
612
+ placeholder = field.placeholder;
613
+ }
614
+ return new DynamicModalUserSelect();
615
+ }
616
+ if (field.type === "checkbox") {
617
+ const options = field.options ?? [];
618
+ class DynamicCheckboxGroup extends CheckboxGroup {
619
+ customId = field.id;
620
+ options = options;
621
+ required = field.required;
622
+ minValues = field.minValues;
623
+ maxValues = field.maxValues;
624
+ }
625
+ return new DynamicCheckboxGroup();
626
+ }
627
+ const options = field.options ?? [];
628
+ class DynamicRadioGroup extends RadioGroup {
629
+ customId = field.id;
630
+ options = options;
631
+ required = field.required;
632
+ minValues = field.minValues;
633
+ maxValues = field.maxValues;
634
+ }
635
+ return new DynamicRadioGroup();
636
+ }
637
+ export function buildDiscordComponentMessage(params) {
638
+ const entries = [];
639
+ const modals = [];
640
+ const components = [];
641
+ const containerChildren = [];
642
+ const addEntry = (entry) => {
643
+ entries.push({
644
+ ...entry,
645
+ sessionKey: params.sessionKey,
646
+ agentId: params.agentId,
647
+ accountId: params.accountId,
648
+ reusable: entry.reusable ?? params.spec.reusable,
649
+ });
650
+ };
651
+ const text = params.spec.text ?? params.fallbackText;
652
+ if (text) {
653
+ containerChildren.push(new TextDisplay(text));
654
+ }
655
+ for (const block of params.spec.blocks ?? []) {
656
+ if (block.type === "text") {
657
+ containerChildren.push(new TextDisplay(block.text));
658
+ continue;
659
+ }
660
+ if (block.type === "section") {
661
+ const displays = buildTextDisplays(block.text, block.texts);
662
+ if (displays.length > 3) {
663
+ throw new Error("Section blocks support up to 3 text displays");
664
+ }
665
+ let accessory;
666
+ if (block.accessory?.type === "thumbnail") {
667
+ accessory = new Thumbnail(block.accessory.url);
668
+ }
669
+ else if (block.accessory?.type === "button") {
670
+ const { component, entry } = createButtonComponent({ spec: block.accessory.button });
671
+ accessory = component;
672
+ if (entry) {
673
+ addEntry(entry);
674
+ }
675
+ }
676
+ containerChildren.push(new Section(displays, accessory));
677
+ continue;
678
+ }
679
+ if (block.type === "separator") {
680
+ containerChildren.push(new Separator({ spacing: block.spacing, divider: block.divider }));
681
+ continue;
682
+ }
683
+ if (block.type === "media-gallery") {
684
+ containerChildren.push(new MediaGallery(block.items));
685
+ continue;
686
+ }
687
+ if (block.type === "file") {
688
+ containerChildren.push(new File(block.file, block.spoiler));
689
+ continue;
690
+ }
691
+ if (block.type === "actions") {
692
+ const rowComponents = [];
693
+ if (block.buttons) {
694
+ if (block.buttons.length > 5) {
695
+ throw new Error("Action rows support up to 5 buttons");
696
+ }
697
+ for (const button of block.buttons) {
698
+ const { component, entry } = createButtonComponent({ spec: button });
699
+ rowComponents.push(component);
700
+ if (entry) {
701
+ addEntry(entry);
702
+ }
703
+ }
704
+ }
705
+ else if (block.select) {
706
+ const { component, entry } = createSelectComponent({ spec: block.select });
707
+ rowComponents.push(component);
708
+ addEntry(entry);
709
+ }
710
+ containerChildren.push(new Row(rowComponents));
711
+ }
712
+ }
713
+ if (params.spec.modal) {
714
+ const modalId = createShortId("mdl_");
715
+ const fields = params.spec.modal.fields.map((field, index) => ({
716
+ id: createShortId("fld_"),
717
+ name: normalizeModalFieldName(field.name, index),
718
+ label: field.label,
719
+ type: field.type,
720
+ description: field.description,
721
+ placeholder: field.placeholder,
722
+ required: field.required,
723
+ options: field.options,
724
+ minValues: field.minValues,
725
+ maxValues: field.maxValues,
726
+ minLength: field.minLength,
727
+ maxLength: field.maxLength,
728
+ style: field.style,
729
+ }));
730
+ modals.push({
731
+ id: modalId,
732
+ title: params.spec.modal.title,
733
+ fields,
734
+ sessionKey: params.sessionKey,
735
+ agentId: params.agentId,
736
+ accountId: params.accountId,
737
+ reusable: params.spec.reusable,
738
+ });
739
+ const triggerSpec = {
740
+ label: params.spec.modal.triggerLabel ?? "Open form",
741
+ style: params.spec.modal.triggerStyle ?? "primary",
742
+ };
743
+ const { component, entry } = createButtonComponent({
744
+ spec: triggerSpec,
745
+ modalId,
746
+ });
747
+ if (entry) {
748
+ addEntry(entry);
749
+ }
750
+ const lastChild = containerChildren.at(-1);
751
+ if (lastChild instanceof Row) {
752
+ const row = lastChild;
753
+ const hasSelect = row.components.some((entry) => isSelectComponent(entry));
754
+ if (row.components.length < 5 && !hasSelect) {
755
+ row.addComponent(component);
756
+ }
757
+ else {
758
+ containerChildren.push(new Row([component]));
759
+ }
760
+ }
761
+ else {
762
+ containerChildren.push(new Row([component]));
763
+ }
764
+ }
765
+ if (containerChildren.length === 0) {
766
+ throw new Error("components must include at least one block, text, or modal trigger");
767
+ }
768
+ const container = new Container(containerChildren, params.spec.container);
769
+ components.push(container);
770
+ return { components, entries, modals };
771
+ }
772
+ export function buildDiscordComponentMessageFlags(components) {
773
+ const hasV2 = components.some((component) => component.isV2);
774
+ return hasV2 ? MessageFlags.IsComponentsV2 : undefined;
775
+ }
776
+ export class DiscordFormModal extends Modal {
777
+ title;
778
+ customId;
779
+ components;
780
+ customIdParser = parseDiscordModalCustomIdForCarbon;
781
+ constructor(params) {
782
+ super();
783
+ this.title = params.title;
784
+ this.customId = buildDiscordModalCustomId(params.modalId);
785
+ this.components = params.fields.map((field) => {
786
+ const component = createModalFieldComponent(field);
787
+ class DynamicLabel extends Label {
788
+ label = field.label;
789
+ description = field.description;
790
+ component = component;
791
+ customId = field.id;
792
+ }
793
+ return new DynamicLabel(component);
794
+ });
795
+ }
796
+ async run() {
797
+ throw new Error("Modal handler is not registered for dynamic forms");
798
+ }
799
+ }
800
+ export function createDiscordFormModal(entry) {
801
+ return new DiscordFormModal({
802
+ modalId: entry.id,
803
+ title: entry.title,
804
+ fields: entry.fields,
805
+ });
806
+ }
807
+ export function formatDiscordComponentEventText(params) {
808
+ if (params.kind === "button") {
809
+ return `Clicked "${params.label}".`;
810
+ }
811
+ const values = params.values ?? [];
812
+ if (values.length === 0) {
813
+ return `Updated "${params.label}".`;
814
+ }
815
+ return `Selected ${values.join(", ")} from "${params.label}".`;
816
+ }