@poolzin/pool-bot 2026.3.25 → 2026.3.27

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 (271) hide show
  1. package/dist/agents/model-fallback.js +5 -4
  2. package/dist/agents/tools/common.js +16 -201
  3. package/dist/auto-reply/auto-reply/reply/agent-runner-execution.js +502 -0
  4. package/dist/auto-reply/auto-reply/reply/agent-runner-helpers.js +65 -0
  5. package/dist/auto-reply/auto-reply/reply/agent-runner-memory.js +160 -0
  6. package/dist/auto-reply/auto-reply/reply/agent-runner-payloads.js +85 -0
  7. package/dist/auto-reply/auto-reply/reply/agent-runner-utils.js +101 -0
  8. package/dist/auto-reply/auto-reply/reply/bash-command.js +338 -0
  9. package/dist/auto-reply/auto-reply/reply/block-streaming.js +91 -0
  10. package/dist/auto-reply/auto-reply/reply/commands-approve.js +88 -0
  11. package/dist/auto-reply/auto-reply/reply/commands-bash.js +26 -0
  12. package/dist/auto-reply/auto-reply/reply/commands-compact.js +107 -0
  13. package/dist/auto-reply/auto-reply/reply/commands-config.js +241 -0
  14. package/dist/auto-reply/auto-reply/reply/commands-context-report.js +295 -0
  15. package/dist/auto-reply/auto-reply/reply/commands-context.js +30 -0
  16. package/dist/auto-reply/auto-reply/reply/commands-core.js +151 -0
  17. package/dist/auto-reply/auto-reply/reply/commands-export-session.js +163 -0
  18. package/dist/auto-reply/auto-reply/reply/commands-info.js +184 -0
  19. package/dist/auto-reply/auto-reply/reply/commands-models.js +299 -0
  20. package/dist/auto-reply/auto-reply/reply/commands-plugin.js +35 -0
  21. package/dist/auto-reply/auto-reply/reply/commands-ptt.js +171 -0
  22. package/dist/auto-reply/auto-reply/reply/commands-setunset-standard.js +13 -0
  23. package/dist/auto-reply/auto-reply/reply/commands-setunset.js +73 -0
  24. package/dist/auto-reply/auto-reply/reply/commands-slash-parse.js +31 -0
  25. package/dist/auto-reply/auto-reply/reply/commands-status.js +178 -0
  26. package/dist/auto-reply/auto-reply/reply/commands-subagents.js +73 -0
  27. package/dist/auto-reply/auto-reply/reply/commands-system-prompt.js +117 -0
  28. package/dist/auto-reply/auto-reply/reply/commands-tts.js +231 -0
  29. package/dist/auto-reply/auto-reply/reply/directive-handling.impl.js +380 -0
  30. package/dist/auto-reply/auto-reply/reply/followup-runner.js +227 -0
  31. package/dist/auto-reply/auto-reply/reply/get-reply-directives-apply.js +201 -0
  32. package/dist/auto-reply/auto-reply/reply/get-reply-directives-utils.js +54 -0
  33. package/dist/auto-reply/auto-reply/reply/get-reply-directives.js +332 -0
  34. package/dist/auto-reply/auto-reply/reply/get-reply-inline-actions.js +258 -0
  35. package/dist/auto-reply/auto-reply/reply/get-reply-run.js +297 -0
  36. package/dist/auto-reply/auto-reply/reply/groups.js +102 -0
  37. package/dist/auto-reply/auto-reply/reply/mentions.js +129 -0
  38. package/dist/auto-reply/auto-reply/reply/reply-delivery.js +92 -0
  39. package/dist/auto-reply/auto-reply/reply/reply-directives.js +30 -0
  40. package/dist/auto-reply/auto-reply/reply/reply-dispatcher.js +152 -0
  41. package/dist/auto-reply/auto-reply/reply/reply-elevated.js +166 -0
  42. package/dist/auto-reply/auto-reply/reply/reply-inline.js +28 -0
  43. package/dist/auto-reply/auto-reply/reply/reply-payloads.js +114 -0
  44. package/dist/auto-reply/auto-reply/reply/reply-reference.js +36 -0
  45. package/dist/auto-reply/auto-reply/reply/reply-tags.js +13 -0
  46. package/dist/auto-reply/auto-reply/reply/reply-threading.js +41 -0
  47. package/dist/auto-reply/auto-reply/reply/session-updates.js +233 -0
  48. package/dist/auto-reply/auto-reply/reply/stage-sandbox-media.js +146 -0
  49. package/dist/build-info.json +3 -3
  50. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  51. package/dist/canvas-host/a2ui/a2ui.bundle.js +2 -17772
  52. package/dist/canvas-host/a2ui/index.html +1 -307
  53. package/dist/channels/channels/directory-config.js +185 -0
  54. package/dist/channels/channels/discord/handle-action.guild-admin.js +332 -0
  55. package/dist/channels/channels/discord/handle-action.js +165 -0
  56. package/dist/channels/channels/discord.js +413 -0
  57. package/dist/channels/channels/dock.js +436 -0
  58. package/dist/channels/channels/index.js +51 -0
  59. package/dist/channels/channels/plugins/outbound/discord.js +101 -0
  60. package/dist/channels/channels/whatsapp.js +17 -0
  61. package/dist/channels/plugins/types.js +1 -1
  62. package/dist/channels/run-state-machine.js +7 -0
  63. package/dist/commands/models/auth.js +47 -1
  64. package/dist/commands-subagents/action-agents.js +44 -0
  65. package/dist/commands-subagents/action-focus.js +64 -0
  66. package/dist/commands-subagents/action-help.js +4 -0
  67. package/dist/commands-subagents/action-info.js +45 -0
  68. package/dist/commands-subagents/action-kill.js +60 -0
  69. package/dist/commands-subagents/action-list.js +44 -0
  70. package/dist/commands-subagents/action-log.js +29 -0
  71. package/dist/commands-subagents/action-send.js +119 -0
  72. package/dist/commands-subagents/action-spawn.js +52 -0
  73. package/dist/commands-subagents/action-unfocus.js +30 -0
  74. package/dist/commands-subagents/shared.js +303 -0
  75. package/dist/config/config.js +1 -8
  76. package/dist/config/types.secrets.js +61 -0
  77. package/dist/control-ui/assets/{index-D7shnQwQ.js → index-umCsvrWy.js} +884 -741
  78. package/dist/control-ui/assets/index-umCsvrWy.js.map +1 -0
  79. package/dist/control-ui/assets/pt-BR-DedEVAvY.js +2 -0
  80. package/dist/control-ui/assets/pt-BR-DedEVAvY.js.map +1 -0
  81. package/dist/control-ui/assets/zh-CN-CDzeklK-.js +2 -0
  82. package/dist/control-ui/assets/zh-CN-CDzeklK-.js.map +1 -0
  83. package/dist/control-ui/assets/zh-TW-BJCRYNWH.js +2 -0
  84. package/dist/control-ui/assets/zh-TW-BJCRYNWH.js.map +1 -0
  85. package/dist/control-ui/index.html +1 -1
  86. package/dist/gateway/method-scopes.js +9 -1
  87. package/dist/gateway/node-pending-work.js +142 -0
  88. package/dist/gateway/protocol/index.js +5 -1
  89. package/dist/gateway/protocol/schema/nodes.js +18 -0
  90. package/dist/gateway/server-methods/nodes-pending.js +96 -0
  91. package/dist/gateway/server-methods-list.js +4 -0
  92. package/dist/gateway/server-methods.js +2 -0
  93. package/dist/imessage/channel.js +253 -0
  94. package/dist/imessage/monitor/echo-cache.js +70 -0
  95. package/dist/imessage/monitor/loop-rate-limiter.js +51 -0
  96. package/dist/imessage/monitor/reflection-guard.js +50 -0
  97. package/dist/imessage/monitor/sanitize-outbound.js +25 -0
  98. package/dist/imessage/monitor/self-chat-cache.js +75 -0
  99. package/dist/imessage/runtime.js +3 -0
  100. package/dist/infra/exec-approval-reply.js +7 -0
  101. package/dist/infra/tmp-openclaw-dir.js +84 -0
  102. package/dist/pairing/pairing-challenge.js +15 -0
  103. package/dist/plugin-sdk/account-id.d.ts +1 -0
  104. package/dist/plugin-sdk/agent-media-payload.d.ts +12 -0
  105. package/dist/plugin-sdk/allow-from.d.ts +27 -0
  106. package/dist/plugin-sdk/command-auth.d.ts +25 -0
  107. package/dist/plugin-sdk/command-auth.js +3 -1
  108. package/dist/plugin-sdk/config-paths.d.ts +6 -0
  109. package/dist/plugin-sdk/file-lock.d.ts +16 -0
  110. package/dist/plugin-sdk/index.d.ts +428 -0
  111. package/dist/plugin-sdk/index.js +237 -103
  112. package/dist/plugin-sdk/json-store.d.ts +5 -0
  113. package/dist/plugin-sdk/keyed-async-queue.d.ts +12 -0
  114. package/dist/plugin-sdk/onboarding.d.ts +11 -0
  115. package/dist/plugin-sdk/provider-auth-result.d.ts +14 -0
  116. package/dist/plugin-sdk/slack-message-actions.d.ts +11 -0
  117. package/dist/plugin-sdk/status-helpers.d.ts +25 -0
  118. package/dist/plugin-sdk/temp-path.d.ts +12 -0
  119. package/dist/plugin-sdk/text-chunking.d.ts +1 -0
  120. package/dist/plugin-sdk/tool-send.d.ts +4 -0
  121. package/dist/plugin-sdk/webhook-path.d.ts +6 -0
  122. package/dist/plugin-sdk/webhook-targets.d.ts +23 -0
  123. package/dist/plugin-sdk/windows-spawn.d.ts +39 -0
  124. package/dist/plugin-sdk-internal/accounts.js +6 -0
  125. package/dist/plugin-sdk-internal/discord.js +23 -0
  126. package/dist/plugin-sdk-internal/imessage.js +13 -0
  127. package/dist/plugin-sdk-internal/setup.js +9 -0
  128. package/dist/plugin-sdk-internal/signal.js +13 -0
  129. package/dist/plugin-sdk-internal/slack.js +22 -0
  130. package/dist/plugin-sdk-internal/telegram.js +32 -0
  131. package/dist/plugin-sdk-internal/whatsapp.js +29 -0
  132. package/dist/routing/session-key.js +4 -185
  133. package/dist/shared/pid-alive.js +2 -61
  134. package/dist/shared/process-scoped-map.js +5 -7
  135. package/dist/signal/channel.js +264 -0
  136. package/dist/signal/monitor/access-policy.js +60 -0
  137. package/dist/signal/runtime.js +3 -0
  138. package/dist/slack/account-inspect.js +135 -0
  139. package/dist/slack/blocks-input.js +7 -38
  140. package/dist/slack/channel.js +394 -0
  141. package/dist/slack/interactive-replies.js +28 -0
  142. package/dist/slack/monitor/channel-type.js +31 -0
  143. package/dist/slack/monitor/dm-auth.js +49 -0
  144. package/dist/slack/monitor/events/interactions.modal.js +137 -0
  145. package/dist/slack/monitor/events/message-subtype-handlers.js +68 -0
  146. package/dist/slack/monitor/events/system-event-context.js +29 -0
  147. package/dist/slack/monitor/events/system-event-test-harness.js +41 -0
  148. package/dist/slack/monitor/external-arg-menu-store.js +46 -0
  149. package/dist/slack/monitor/message-handler/prepare-content.js +69 -0
  150. package/dist/slack/monitor/message-handler/prepare-thread-context.js +91 -0
  151. package/dist/slack/monitor/message-handler/prepare.test-helpers.js +55 -0
  152. package/dist/slack/monitor/reconnect-policy.js +78 -0
  153. package/dist/slack/monitor/slash-commands.runtime.js +1 -0
  154. package/dist/slack/monitor/slash-dispatch.runtime.js +9 -0
  155. package/dist/slack/monitor/slash-skill-commands.runtime.js +1 -0
  156. package/dist/slack/resolve-allowlist-common.js +36 -0
  157. package/dist/slack/runtime.js +3 -0
  158. package/dist/slack/sent-thread-cache.js +61 -0
  159. package/dist/slack/truncate.js +10 -0
  160. package/dist/telegram/account-inspect.js +175 -0
  161. package/dist/telegram/allow-from.js +10 -0
  162. package/dist/telegram/api-fetch.js +18 -0
  163. package/dist/telegram/approval-buttons.js +30 -0
  164. package/dist/telegram/audit-membership-runtime.js +61 -0
  165. package/dist/telegram/bot/delivery.replies.js +508 -0
  166. package/dist/telegram/bot/delivery.resolve-media.js +227 -0
  167. package/dist/telegram/bot/delivery.send.js +132 -0
  168. package/dist/telegram/bot/reply-threading.js +46 -0
  169. package/dist/telegram/bot-message-context.body.js +186 -0
  170. package/dist/telegram/bot-message-context.session.js +207 -0
  171. package/dist/telegram/bot-message-context.types.js +1 -0
  172. package/dist/telegram/bot-native-commands.test-helpers.js +117 -0
  173. package/dist/telegram/bot.media.e2e-harness.js +81 -0
  174. package/dist/telegram/bot.media.test-utils.js +81 -0
  175. package/dist/telegram/channel-actions.js +225 -0
  176. package/dist/telegram/channel.js +515 -0
  177. package/dist/telegram/conversation-route.js +107 -0
  178. package/dist/telegram/delivery.js +2 -0
  179. package/dist/telegram/delivery.replies.js +508 -0
  180. package/dist/telegram/dm-access.js +86 -0
  181. package/dist/telegram/draft-stream.test-helpers.js +62 -0
  182. package/dist/telegram/exec-approvals-handler.js +281 -0
  183. package/dist/telegram/exec-approvals.js +62 -0
  184. package/dist/telegram/forum-service-message.js +22 -0
  185. package/dist/telegram/group-config-helpers.js +10 -0
  186. package/dist/telegram/lane-delivery-state.js +19 -0
  187. package/dist/telegram/lane-delivery-text-deliverer.js +357 -0
  188. package/dist/telegram/lane-delivery.js +2 -0
  189. package/dist/telegram/normalize.js +37 -0
  190. package/dist/telegram/onboarding.js +192 -0
  191. package/dist/telegram/outbound-adapter.js +100 -0
  192. package/dist/telegram/polling-session.js +275 -0
  193. package/dist/telegram/runtime.js +3 -0
  194. package/dist/telegram/sendchataction-401-backoff.js +71 -0
  195. package/dist/telegram/sequential-key.js +46 -0
  196. package/dist/telegram/status-issues.js +105 -0
  197. package/dist/telegram/target-writeback.js +165 -0
  198. package/dist/telegram/thread-bindings.js +560 -0
  199. package/dist/utils.js +32 -257
  200. package/dist/wizard/prompts.js +5 -5
  201. package/extensions/feishu/src/policy.ts +1 -1
  202. package/extensions/firecrawl/index.test.ts +82 -0
  203. package/extensions/firecrawl/index.ts +20 -0
  204. package/extensions/firecrawl/openclaw.plugin.json +8 -0
  205. package/extensions/firecrawl/package.json +12 -0
  206. package/extensions/firecrawl/src/config.ts +159 -0
  207. package/extensions/firecrawl/src/firecrawl-client.ts +446 -0
  208. package/extensions/firecrawl/src/firecrawl-scrape-tool.ts +89 -0
  209. package/extensions/firecrawl/src/firecrawl-search-provider.ts +63 -0
  210. package/extensions/firecrawl/src/firecrawl-search-tool.ts +76 -0
  211. package/package.json +1 -1
  212. package/dist/.buildstamp +0 -1
  213. package/dist/acp/bindings-store.js +0 -209
  214. package/dist/acp/control-plane/runtime-cache.js +0 -54
  215. package/dist/acp/control-plane/runtime-options.js +0 -215
  216. package/dist/acp/control-plane/session-actor-queue.js +0 -36
  217. package/dist/acp/index.js +0 -2
  218. package/dist/acp/runtime/errors.js +0 -47
  219. package/dist/acp/runtime/registry.js +0 -86
  220. package/dist/acp/secret-file.js +0 -22
  221. package/dist/agents/auth-profiles.resolve-auth-profile-order.fixtures.js +0 -23
  222. package/dist/agents/bash-process-registry.test-helpers.js +0 -29
  223. package/dist/agents/bash-tools.exec-approval-request.js +0 -20
  224. package/dist/agents/bash-tools.exec-host-gateway.js +0 -240
  225. package/dist/agents/bash-tools.exec-host-node.js +0 -235
  226. package/dist/agents/checkpoint-manager.js +0 -290
  227. package/dist/agents/claude-cli-runner.js +0 -3
  228. package/dist/agents/error-classifier.js +0 -251
  229. package/dist/agents/live-model-filter.js +0 -84
  230. package/dist/agents/nvidia-models.js +0 -228
  231. package/dist/agents/pi-embedded-runner/run.overflow-compaction.fixture.js +0 -34
  232. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +0 -156
  233. package/dist/agents/pi-embedded-subscribe.handlers.tools.media.test-helpers.js +0 -30
  234. package/dist/agents/provider/config-loader.js +0 -76
  235. package/dist/agents/provider/index.js +0 -15
  236. package/dist/agents/provider/models-dev.js +0 -129
  237. package/dist/agents/provider/session-binding.js +0 -376
  238. package/dist/agents/queued-file-writer.js +0 -22
  239. package/dist/agents/skills/bundled-context.js +0 -23
  240. package/dist/agents/skills/security.js +0 -211
  241. package/dist/agents/skills/tools-dir.js +0 -9
  242. package/dist/agents/skills-install-download.js +0 -290
  243. package/dist/agents/skills-install-output.js +0 -30
  244. package/dist/agents/skills-install.download-test-utils.js +0 -36
  245. package/dist/agents/skills.test-helpers.js +0 -13
  246. package/dist/agents/subagent-announce-reliability.js +0 -160
  247. package/dist/agents/subagent-registry.mocks.shared.js +0 -12
  248. package/dist/agents/test-helpers/assistant-message-fixtures.js +0 -29
  249. package/dist/agents/test-helpers/fast-coding-tools.js +0 -1
  250. package/dist/agents/test-helpers/fast-core-tools.js +0 -8
  251. package/dist/agents/test-helpers/fast-tool-stubs.js +0 -18
  252. package/dist/agents/test-helpers/host-sandbox-fs-bridge.js +0 -74
  253. package/dist/agents/test-helpers/pi-tools-sandbox-context.js +0 -27
  254. package/dist/agents/tool-display-common.js +0 -915
  255. package/dist/agents/tool-policy-shared.js +0 -108
  256. package/dist/agents/tool-policy.conformance.js +0 -14
  257. package/dist/agents/tool-result-truncation.js +0 -299
  258. package/dist/agents/tools/cron-tool.test-helpers.js +0 -12
  259. package/dist/agents/tools/discord-actions-moderation-shared.js +0 -27
  260. package/dist/agents/tools/discord-actions-presence.js +0 -78
  261. package/dist/control-ui/assets/index-D7shnQwQ.js.map +0 -1
  262. package/dist/discord/discord-improvements.js +0 -167
  263. package/dist/discord/index.js +0 -2
  264. package/dist/hooks/bundled/boot-md/HOOK.md +0 -19
  265. package/dist/hooks/bundled/command-logger/HOOK.md +0 -122
  266. package/dist/hooks/bundled/session-memory/HOOK.md +0 -86
  267. package/dist/hooks/bundled/soul-evil/HOOK.md +0 -71
  268. package/dist/whatsapp/normalize.js +0 -66
  269. package/dist/whatsapp/resolve-outbound-target.js +0 -42
  270. /package/dist/{acp/runtime/types.js → auto-reply/auto-reply/reply/commands-types.js} +0 -0
  271. /package/dist/{agents/pi-embedded-payloads.js → slack/account-surface-fields.js} +0 -0
@@ -0,0 +1,60 @@
1
+ import { issuePairingChallenge } from "../../../../src/pairing/pairing-challenge.js";
2
+ import { upsertChannelPairingRequest } from "../../../../src/pairing/pairing-store.js";
3
+ import { readStoreAllowFromForDmPolicy, resolveDmGroupAccessWithLists, } from "../../../../src/security/dm-policy-shared.js";
4
+ import { isSignalSenderAllowed } from "../identity.js";
5
+ export async function resolveSignalAccessState(params) {
6
+ const storeAllowFrom = await readStoreAllowFromForDmPolicy({
7
+ provider: "signal",
8
+ accountId: params.accountId,
9
+ dmPolicy: params.dmPolicy,
10
+ });
11
+ const resolveAccessDecision = (isGroup) => resolveDmGroupAccessWithLists({
12
+ isGroup,
13
+ dmPolicy: params.dmPolicy,
14
+ groupPolicy: params.groupPolicy,
15
+ allowFrom: params.allowFrom,
16
+ groupAllowFrom: params.groupAllowFrom,
17
+ storeAllowFrom,
18
+ isSenderAllowed: (allowEntries) => isSignalSenderAllowed(params.sender, allowEntries),
19
+ });
20
+ const dmAccess = resolveAccessDecision(false);
21
+ return {
22
+ resolveAccessDecision,
23
+ dmAccess,
24
+ effectiveDmAllow: dmAccess.effectiveAllowFrom,
25
+ effectiveGroupAllow: dmAccess.effectiveGroupAllowFrom,
26
+ };
27
+ }
28
+ export async function handleSignalDirectMessageAccess(params) {
29
+ if (params.dmAccessDecision === "allow") {
30
+ return true;
31
+ }
32
+ if (params.dmAccessDecision === "block") {
33
+ if (params.dmPolicy !== "disabled") {
34
+ params.log(`Blocked signal sender ${params.senderDisplay} (dmPolicy=${params.dmPolicy})`);
35
+ }
36
+ return false;
37
+ }
38
+ if (params.dmPolicy === "pairing") {
39
+ await issuePairingChallenge({
40
+ channel: "signal",
41
+ senderId: params.senderId,
42
+ senderIdLine: params.senderIdLine,
43
+ meta: { name: params.senderName },
44
+ upsertPairingRequest: async ({ id, meta }) => await upsertChannelPairingRequest({
45
+ channel: "signal",
46
+ id,
47
+ accountId: params.accountId,
48
+ meta,
49
+ }),
50
+ sendPairingReply: params.sendPairingReply,
51
+ onCreated: () => {
52
+ params.log(`signal pairing request sender=${params.senderId}`);
53
+ },
54
+ onReplyError: (err) => {
55
+ params.log(`signal pairing reply failed for ${params.senderId}: ${String(err)}`);
56
+ },
57
+ });
58
+ }
59
+ return false;
60
+ }
@@ -0,0 +1,3 @@
1
+ import { createPluginRuntimeStore } from "openclaw/plugin-sdk/compat";
2
+ const { setRuntime: setSignalRuntime, getRuntime: getSignalRuntime } = createPluginRuntimeStore("Signal runtime not initialized");
3
+ export { getSignalRuntime, setSignalRuntime };
@@ -0,0 +1,135 @@
1
+ import { hasConfiguredSecretInput, normalizeSecretInputString, } from "../../../src/config/types.secrets.js";
2
+ import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../../src/routing/session-key.js";
3
+ import { mergeSlackAccountConfig, resolveDefaultSlackAccountId, } from "./accounts.js";
4
+ function inspectSlackToken(value) {
5
+ const token = normalizeSecretInputString(value);
6
+ if (token) {
7
+ return {
8
+ token,
9
+ source: "config",
10
+ status: "available",
11
+ };
12
+ }
13
+ if (hasConfiguredSecretInput(value)) {
14
+ return {
15
+ source: "config",
16
+ status: "configured_unavailable",
17
+ };
18
+ }
19
+ return {
20
+ source: "none",
21
+ status: "missing",
22
+ };
23
+ }
24
+ export function inspectSlackAccount(params) {
25
+ const accountId = normalizeAccountId(params.accountId ?? resolveDefaultSlackAccountId(params.cfg));
26
+ const merged = mergeSlackAccountConfig(params.cfg, accountId);
27
+ const enabled = params.cfg.channels?.slack?.enabled !== false && merged.enabled !== false;
28
+ const allowEnv = accountId === DEFAULT_ACCOUNT_ID;
29
+ const mode = merged.mode ?? "socket";
30
+ const isHttpMode = mode === "http";
31
+ const configBot = inspectSlackToken(merged.botToken);
32
+ const configApp = inspectSlackToken(merged.appToken);
33
+ const configSigningSecret = inspectSlackToken(merged.signingSecret);
34
+ const configUser = inspectSlackToken(merged.userToken);
35
+ const envBot = allowEnv
36
+ ? normalizeSecretInputString(params.envBotToken ?? process.env.SLACK_BOT_TOKEN)
37
+ : undefined;
38
+ const envApp = allowEnv
39
+ ? normalizeSecretInputString(params.envAppToken ?? process.env.SLACK_APP_TOKEN)
40
+ : undefined;
41
+ const envUser = allowEnv
42
+ ? normalizeSecretInputString(params.envUserToken ?? process.env.SLACK_USER_TOKEN)
43
+ : undefined;
44
+ const botToken = configBot.token ?? envBot;
45
+ const appToken = configApp.token ?? envApp;
46
+ const signingSecret = configSigningSecret.token;
47
+ const userToken = configUser.token ?? envUser;
48
+ const botTokenSource = configBot.token
49
+ ? "config"
50
+ : configBot.status === "configured_unavailable"
51
+ ? "config"
52
+ : envBot
53
+ ? "env"
54
+ : "none";
55
+ const appTokenSource = configApp.token
56
+ ? "config"
57
+ : configApp.status === "configured_unavailable"
58
+ ? "config"
59
+ : envApp
60
+ ? "env"
61
+ : "none";
62
+ const signingSecretSource = configSigningSecret.token
63
+ ? "config"
64
+ : configSigningSecret.status === "configured_unavailable"
65
+ ? "config"
66
+ : "none";
67
+ const userTokenSource = configUser.token
68
+ ? "config"
69
+ : configUser.status === "configured_unavailable"
70
+ ? "config"
71
+ : envUser
72
+ ? "env"
73
+ : "none";
74
+ return {
75
+ accountId,
76
+ enabled,
77
+ name: merged.name?.trim() || undefined,
78
+ mode,
79
+ botToken,
80
+ appToken,
81
+ ...(isHttpMode ? { signingSecret } : {}),
82
+ userToken,
83
+ botTokenSource,
84
+ appTokenSource,
85
+ ...(isHttpMode ? { signingSecretSource } : {}),
86
+ userTokenSource,
87
+ botTokenStatus: configBot.token
88
+ ? "available"
89
+ : configBot.status === "configured_unavailable"
90
+ ? "configured_unavailable"
91
+ : envBot
92
+ ? "available"
93
+ : "missing",
94
+ appTokenStatus: configApp.token
95
+ ? "available"
96
+ : configApp.status === "configured_unavailable"
97
+ ? "configured_unavailable"
98
+ : envApp
99
+ ? "available"
100
+ : "missing",
101
+ ...(isHttpMode
102
+ ? {
103
+ signingSecretStatus: configSigningSecret.token
104
+ ? "available"
105
+ : configSigningSecret.status === "configured_unavailable"
106
+ ? "configured_unavailable"
107
+ : "missing",
108
+ }
109
+ : {}),
110
+ userTokenStatus: configUser.token
111
+ ? "available"
112
+ : configUser.status === "configured_unavailable"
113
+ ? "configured_unavailable"
114
+ : envUser
115
+ ? "available"
116
+ : "missing",
117
+ configured: isHttpMode
118
+ ? (configBot.status !== "missing" || Boolean(envBot)) &&
119
+ configSigningSecret.status !== "missing"
120
+ : (configBot.status !== "missing" || Boolean(envBot)) &&
121
+ (configApp.status !== "missing" || Boolean(envApp)),
122
+ config: merged,
123
+ groupPolicy: merged.groupPolicy,
124
+ textChunkLimit: merged.textChunkLimit,
125
+ mediaMaxMb: merged.mediaMaxMb,
126
+ reactionNotifications: merged.reactionNotifications,
127
+ reactionAllowlist: merged.reactionAllowlist,
128
+ replyToMode: merged.replyToMode,
129
+ replyToModeByChatType: merged.replyToModeByChatType,
130
+ actions: merged.actions,
131
+ slashCommand: merged.slashCommand,
132
+ dm: merged.dm,
133
+ channels: merged.channels,
134
+ };
135
+ }
@@ -1,40 +1,9 @@
1
- const SLACK_MAX_BLOCKS = 50;
2
- function parseBlocksJson(raw) {
3
- try {
4
- return JSON.parse(raw);
5
- }
6
- catch {
7
- throw new Error("blocks must be valid JSON");
8
- }
9
- }
10
- function assertBlocksArray(raw) {
11
- if (!Array.isArray(raw)) {
12
- throw new Error("blocks must be an array");
13
- }
14
- if (raw.length === 0) {
15
- throw new Error("blocks must contain at least one block");
16
- }
17
- if (raw.length > SLACK_MAX_BLOCKS) {
18
- throw new Error(`blocks cannot exceed ${SLACK_MAX_BLOCKS} items`);
19
- }
20
- for (const block of raw) {
21
- if (!block || typeof block !== "object" || Array.isArray(block)) {
22
- throw new Error("each block must be an object");
23
- }
24
- const type = block.type;
25
- if (typeof type !== "string" || type.trim().length === 0) {
26
- throw new Error("each block must include a non-empty string type");
27
- }
28
- }
29
- }
30
- export function validateSlackBlocksArray(raw) {
31
- assertBlocksArray(raw);
32
- return raw;
33
- }
34
- export function parseSlackBlocksInput(raw) {
35
- if (raw == null) {
1
+ // Stub for slack/blocks-input.js
2
+ export function parseSlackBlocksInput(blocks) {
3
+ if (!Array.isArray(blocks))
36
4
  return undefined;
37
- }
38
- const parsed = typeof raw === "string" ? parseBlocksJson(raw) : raw;
39
- return validateSlackBlocksArray(parsed);
5
+ return blocks;
6
+ }
7
+ export function extractSlackToolSend(_blocks) {
8
+ return null;
40
9
  }
@@ -0,0 +1,394 @@
1
+ import { createScopedChannelConfigBase } from "openclaw/plugin-sdk/compat";
2
+ import { buildAccountScopedDmSecurityPolicy, collectOpenProviderGroupPolicyWarnings, collectOpenGroupPolicyConfiguredRouteWarnings, createScopedAccountConfigAccessors, formatAllowFromLowercase, } from "openclaw/plugin-sdk/compat";
3
+ import { applyAccountNameToChannelSection, buildComputedAccountStatusSnapshot, buildChannelConfigSchema, DEFAULT_ACCOUNT_ID, extractSlackToolSend, getChatChannelMeta, handleSlackMessageAction, inspectSlackAccount, listSlackMessageActions, listSlackAccountIds, listSlackDirectoryGroupsFromConfig, listSlackDirectoryPeersFromConfig, looksLikeSlackTargetId, migrateBaseNameToDefaultAccount, normalizeAccountId, normalizeSlackMessagingTarget, PAIRING_APPROVED_MESSAGE, projectCredentialSnapshotFields, resolveConfiguredFromRequiredCredentialStatuses, resolveDefaultSlackAccountId, resolveSlackAccount, resolveSlackReplyToMode, isSlackInteractiveRepliesEnabled, resolveSlackGroupRequireMention, resolveSlackGroupToolPolicy, buildSlackThreadingToolContext, slackOnboardingAdapter, SlackConfigSchema, } from "openclaw/plugin-sdk/slack";
4
+ import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js";
5
+ import { buildPassiveProbedChannelStatusSummary } from "../../shared/channel-status-summary.js";
6
+ import { getSlackRuntime } from "./runtime.js";
7
+ const meta = getChatChannelMeta("slack");
8
+ // Select the appropriate Slack token for read/write operations.
9
+ function getTokenForOperation(account, operation) {
10
+ const userToken = account.config.userToken?.trim() || undefined;
11
+ const botToken = account.botToken?.trim();
12
+ const allowUserWrites = account.config.userTokenReadOnly === false;
13
+ if (operation === "read") {
14
+ return userToken ?? botToken;
15
+ }
16
+ if (!allowUserWrites) {
17
+ return botToken;
18
+ }
19
+ return botToken ?? userToken;
20
+ }
21
+ function isSlackAccountConfigured(account) {
22
+ const mode = account.config.mode ?? "socket";
23
+ const hasBotToken = Boolean(account.botToken?.trim());
24
+ if (!hasBotToken) {
25
+ return false;
26
+ }
27
+ if (mode === "http") {
28
+ return Boolean(account.config.signingSecret?.trim());
29
+ }
30
+ return Boolean(account.appToken?.trim());
31
+ }
32
+ function resolveSlackSendContext(params) {
33
+ const send = resolveOutboundSendDep(params.deps, "slack") ??
34
+ getSlackRuntime().channel.slack.sendMessageSlack;
35
+ const account = resolveSlackAccount({ cfg: params.cfg, accountId: params.accountId });
36
+ const token = getTokenForOperation(account, "write");
37
+ const botToken = account.botToken?.trim();
38
+ const tokenOverride = token && token !== botToken ? token : undefined;
39
+ const threadTsValue = params.replyToId ?? params.threadId;
40
+ return { send, threadTsValue, tokenOverride };
41
+ }
42
+ const slackConfigAccessors = createScopedAccountConfigAccessors({
43
+ resolveAccount: ({ cfg, accountId }) => resolveSlackAccount({ cfg, accountId }),
44
+ resolveAllowFrom: (account) => account.dm?.allowFrom,
45
+ formatAllowFrom: (allowFrom) => formatAllowFromLowercase({ allowFrom }),
46
+ resolveDefaultTo: (account) => account.config.defaultTo,
47
+ });
48
+ const slackConfigBase = createScopedChannelConfigBase({
49
+ sectionKey: "slack",
50
+ listAccountIds: listSlackAccountIds,
51
+ resolveAccount: (cfg, accountId) => resolveSlackAccount({ cfg, accountId }),
52
+ inspectAccount: (cfg, accountId) => inspectSlackAccount({ cfg, accountId }),
53
+ defaultAccountId: resolveDefaultSlackAccountId,
54
+ clearBaseFields: ["botToken", "appToken", "name"],
55
+ });
56
+ export const slackPlugin = {
57
+ id: "slack",
58
+ meta: {
59
+ ...meta,
60
+ preferSessionLookupForAnnounceTarget: true,
61
+ },
62
+ onboarding: slackOnboardingAdapter,
63
+ pairing: {
64
+ idLabel: "slackUserId",
65
+ normalizeAllowEntry: (entry) => entry.replace(/^(slack|user):/i, ""),
66
+ notifyApproval: async ({ id }) => {
67
+ const cfg = getSlackRuntime().config.loadConfig();
68
+ const account = resolveSlackAccount({
69
+ cfg,
70
+ accountId: DEFAULT_ACCOUNT_ID,
71
+ });
72
+ const token = getTokenForOperation(account, "write");
73
+ const botToken = account.botToken?.trim();
74
+ const tokenOverride = token && token !== botToken ? token : undefined;
75
+ if (tokenOverride) {
76
+ await getSlackRuntime().channel.slack.sendMessageSlack(`user:${id}`, PAIRING_APPROVED_MESSAGE, {
77
+ token: tokenOverride,
78
+ });
79
+ }
80
+ else {
81
+ await getSlackRuntime().channel.slack.sendMessageSlack(`user:${id}`, PAIRING_APPROVED_MESSAGE);
82
+ }
83
+ },
84
+ },
85
+ capabilities: {
86
+ chatTypes: ["direct", "channel", "thread"],
87
+ reactions: true,
88
+ threads: true,
89
+ media: true,
90
+ nativeCommands: true,
91
+ },
92
+ agentPrompt: {
93
+ messageToolHints: ({ cfg, accountId }) => isSlackInteractiveRepliesEnabled({ cfg, accountId })
94
+ ? [
95
+ "- Slack interactive replies: use `[[slack_buttons: Label:value, Other:other]]` to add action buttons that route clicks back as Slack interaction system events.",
96
+ "- Slack selects: use `[[slack_select: Placeholder | Label:value, Other:other]]` to add a static select menu that routes the chosen value back as a Slack interaction system event.",
97
+ ]
98
+ : [
99
+ "- Slack interactive replies are disabled. If needed, ask to set `channels.slack.capabilities.interactiveReplies=true` (or the same under `channels.slack.accounts.<account>.capabilities`).",
100
+ ],
101
+ },
102
+ streaming: {
103
+ blockStreamingCoalesceDefaults: { minChars: 1500, idleMs: 1000 },
104
+ },
105
+ reload: { configPrefixes: ["channels.slack"] },
106
+ configSchema: buildChannelConfigSchema(SlackConfigSchema),
107
+ config: {
108
+ ...slackConfigBase,
109
+ isConfigured: (account) => isSlackAccountConfigured(account),
110
+ describeAccount: (account) => ({
111
+ accountId: account.accountId,
112
+ name: account.name,
113
+ enabled: account.enabled,
114
+ configured: isSlackAccountConfigured(account),
115
+ botTokenSource: account.botTokenSource,
116
+ appTokenSource: account.appTokenSource,
117
+ }),
118
+ ...slackConfigAccessors,
119
+ },
120
+ security: {
121
+ resolveDmPolicy: ({ cfg, accountId, account }) => {
122
+ return buildAccountScopedDmSecurityPolicy({
123
+ cfg,
124
+ channelKey: "slack",
125
+ accountId,
126
+ fallbackAccountId: account.accountId ?? DEFAULT_ACCOUNT_ID,
127
+ policy: account.dm?.policy,
128
+ allowFrom: account.dm?.allowFrom ?? [],
129
+ allowFromPathSuffix: "dm.",
130
+ normalizeEntry: (raw) => raw.replace(/^(slack|user):/i, ""),
131
+ });
132
+ },
133
+ collectWarnings: ({ account, cfg }) => {
134
+ const channelAllowlistConfigured = Boolean(account.config.channels) && Object.keys(account.config.channels ?? {}).length > 0;
135
+ return collectOpenProviderGroupPolicyWarnings({
136
+ cfg,
137
+ providerConfigPresent: cfg.channels?.slack !== undefined,
138
+ configuredGroupPolicy: account.config.groupPolicy,
139
+ collect: (groupPolicy) => collectOpenGroupPolicyConfiguredRouteWarnings({
140
+ groupPolicy,
141
+ routeAllowlistConfigured: channelAllowlistConfigured,
142
+ configureRouteAllowlist: {
143
+ surface: "Slack channels",
144
+ openScope: "any channel not explicitly denied",
145
+ groupPolicyPath: "channels.slack.groupPolicy",
146
+ routeAllowlistPath: "channels.slack.channels",
147
+ },
148
+ missingRouteAllowlist: {
149
+ surface: "Slack channels",
150
+ openBehavior: "with no channel allowlist; any channel can trigger (mention-gated)",
151
+ remediation: 'Set channels.slack.groupPolicy="allowlist" and configure channels.slack.channels',
152
+ },
153
+ }),
154
+ });
155
+ },
156
+ },
157
+ groups: {
158
+ resolveRequireMention: resolveSlackGroupRequireMention,
159
+ resolveToolPolicy: resolveSlackGroupToolPolicy,
160
+ },
161
+ threading: {
162
+ resolveReplyToMode: ({ cfg, accountId, chatType }) => resolveSlackReplyToMode(resolveSlackAccount({ cfg, accountId }), chatType),
163
+ allowExplicitReplyTagsWhenOff: false,
164
+ buildToolContext: (params) => buildSlackThreadingToolContext(params),
165
+ },
166
+ messaging: {
167
+ normalizeTarget: normalizeSlackMessagingTarget,
168
+ targetResolver: {
169
+ looksLikeId: looksLikeSlackTargetId,
170
+ hint: "<channelId|user:ID|channel:ID>",
171
+ },
172
+ },
173
+ directory: {
174
+ self: async () => null,
175
+ listPeers: async (params) => listSlackDirectoryPeersFromConfig(params),
176
+ listGroups: async (params) => listSlackDirectoryGroupsFromConfig(params),
177
+ listPeersLive: async (params) => getSlackRuntime().channel.slack.listDirectoryPeersLive(params),
178
+ listGroupsLive: async (params) => getSlackRuntime().channel.slack.listDirectoryGroupsLive(params),
179
+ },
180
+ resolver: {
181
+ resolveTargets: async ({ cfg, accountId, inputs, kind }) => {
182
+ const toResolvedTarget = (entry, note) => ({
183
+ input: entry.input,
184
+ resolved: entry.resolved,
185
+ id: entry.id,
186
+ name: entry.name,
187
+ note,
188
+ });
189
+ const account = resolveSlackAccount({ cfg, accountId });
190
+ const token = account.config.userToken?.trim() || account.botToken?.trim();
191
+ if (!token) {
192
+ return inputs.map((input) => ({
193
+ input,
194
+ resolved: false,
195
+ note: "missing Slack token",
196
+ }));
197
+ }
198
+ if (kind === "group") {
199
+ const resolved = await getSlackRuntime().channel.slack.resolveChannelAllowlist({
200
+ token,
201
+ entries: inputs,
202
+ });
203
+ return resolved.map((entry) => toResolvedTarget(entry, entry.archived ? "archived" : undefined));
204
+ }
205
+ const resolved = await getSlackRuntime().channel.slack.resolveUserAllowlist({
206
+ token,
207
+ entries: inputs,
208
+ });
209
+ return resolved.map((entry) => toResolvedTarget(entry, entry.note));
210
+ },
211
+ },
212
+ actions: {
213
+ listActions: ({ cfg }) => listSlackMessageActions(cfg),
214
+ extractToolSend: ({ args }) => extractSlackToolSend(args),
215
+ handleAction: async (ctx) => await handleSlackMessageAction({
216
+ providerId: meta.id,
217
+ ctx,
218
+ includeReadThreadId: true,
219
+ invoke: async (action, cfg, toolContext) => await getSlackRuntime().channel.slack.handleSlackAction(action, cfg, toolContext),
220
+ }),
221
+ },
222
+ setup: {
223
+ resolveAccountId: ({ accountId }) => normalizeAccountId(accountId),
224
+ applyAccountName: ({ cfg, accountId, name }) => applyAccountNameToChannelSection({
225
+ cfg,
226
+ channelKey: "slack",
227
+ accountId,
228
+ name,
229
+ }),
230
+ validateInput: ({ accountId, input }) => {
231
+ if (input.useEnv && accountId !== DEFAULT_ACCOUNT_ID) {
232
+ return "Slack env tokens can only be used for the default account.";
233
+ }
234
+ if (!input.useEnv && (!input.botToken || !input.appToken)) {
235
+ return "Slack requires --bot-token and --app-token (or --use-env).";
236
+ }
237
+ return null;
238
+ },
239
+ applyAccountConfig: ({ cfg, accountId, input }) => {
240
+ const namedConfig = applyAccountNameToChannelSection({
241
+ cfg,
242
+ channelKey: "slack",
243
+ accountId,
244
+ name: input.name,
245
+ });
246
+ const next = accountId !== DEFAULT_ACCOUNT_ID
247
+ ? migrateBaseNameToDefaultAccount({
248
+ cfg: namedConfig,
249
+ channelKey: "slack",
250
+ })
251
+ : namedConfig;
252
+ if (accountId === DEFAULT_ACCOUNT_ID) {
253
+ return {
254
+ ...next,
255
+ channels: {
256
+ ...next.channels,
257
+ slack: {
258
+ ...next.channels?.slack,
259
+ enabled: true,
260
+ ...(input.useEnv
261
+ ? {}
262
+ : {
263
+ ...(input.botToken ? { botToken: input.botToken } : {}),
264
+ ...(input.appToken ? { appToken: input.appToken } : {}),
265
+ }),
266
+ },
267
+ },
268
+ };
269
+ }
270
+ return {
271
+ ...next,
272
+ channels: {
273
+ ...next.channels,
274
+ slack: {
275
+ ...next.channels?.slack,
276
+ enabled: true,
277
+ accounts: {
278
+ ...next.channels?.slack?.accounts,
279
+ [accountId]: {
280
+ ...next.channels?.slack?.accounts?.[accountId],
281
+ enabled: true,
282
+ ...(input.botToken ? { botToken: input.botToken } : {}),
283
+ ...(input.appToken ? { appToken: input.appToken } : {}),
284
+ },
285
+ },
286
+ },
287
+ },
288
+ };
289
+ },
290
+ },
291
+ outbound: {
292
+ deliveryMode: "direct",
293
+ chunker: null,
294
+ textChunkLimit: 4000,
295
+ sendText: async ({ to, text, accountId, deps, replyToId, threadId, cfg }) => {
296
+ const { send, threadTsValue, tokenOverride } = resolveSlackSendContext({
297
+ cfg,
298
+ accountId: accountId ?? undefined,
299
+ deps,
300
+ replyToId,
301
+ threadId,
302
+ });
303
+ const result = await send(to, text, {
304
+ cfg,
305
+ threadTs: threadTsValue != null ? String(threadTsValue) : undefined,
306
+ accountId: accountId ?? undefined,
307
+ ...(tokenOverride ? { token: tokenOverride } : {}),
308
+ });
309
+ return { channel: "slack", ...result };
310
+ },
311
+ sendMedia: async ({ to, text, mediaUrl, mediaLocalRoots, accountId, deps, replyToId, threadId, cfg, }) => {
312
+ const { send, threadTsValue, tokenOverride } = resolveSlackSendContext({
313
+ cfg,
314
+ accountId: accountId ?? undefined,
315
+ deps,
316
+ replyToId,
317
+ threadId,
318
+ });
319
+ const result = await send(to, text, {
320
+ cfg,
321
+ mediaUrl,
322
+ mediaLocalRoots,
323
+ threadTs: threadTsValue != null ? String(threadTsValue) : undefined,
324
+ accountId: accountId ?? undefined,
325
+ ...(tokenOverride ? { token: tokenOverride } : {}),
326
+ });
327
+ return { channel: "slack", ...result };
328
+ },
329
+ },
330
+ status: {
331
+ defaultRuntime: {
332
+ accountId: DEFAULT_ACCOUNT_ID,
333
+ running: false,
334
+ lastStartAt: null,
335
+ lastStopAt: null,
336
+ lastError: null,
337
+ },
338
+ buildChannelSummary: ({ snapshot }) => buildPassiveProbedChannelStatusSummary(snapshot, {
339
+ botTokenSource: snapshot.botTokenSource ?? "none",
340
+ appTokenSource: snapshot.appTokenSource ?? "none",
341
+ }),
342
+ probeAccount: async ({ account, timeoutMs }) => {
343
+ const token = account.botToken?.trim();
344
+ if (!token) {
345
+ return { ok: false, error: "missing token" };
346
+ }
347
+ return await getSlackRuntime().channel.slack.probeSlack(token, timeoutMs);
348
+ },
349
+ buildAccountSnapshot: ({ account, runtime, probe }) => {
350
+ const mode = account.config.mode ?? "socket";
351
+ const configured = (mode === "http"
352
+ ? resolveConfiguredFromRequiredCredentialStatuses(account, [
353
+ "botTokenStatus",
354
+ "signingSecretStatus",
355
+ ])
356
+ : resolveConfiguredFromRequiredCredentialStatuses(account, [
357
+ "botTokenStatus",
358
+ "appTokenStatus",
359
+ ])) ?? isSlackAccountConfigured(account);
360
+ const base = buildComputedAccountStatusSnapshot({
361
+ accountId: account.accountId,
362
+ name: account.name,
363
+ enabled: account.enabled,
364
+ configured,
365
+ runtime,
366
+ probe,
367
+ });
368
+ return {
369
+ ...base,
370
+ ...projectCredentialSnapshotFields(account),
371
+ };
372
+ },
373
+ },
374
+ gateway: {
375
+ startAccount: async (ctx) => {
376
+ const account = ctx.account;
377
+ const botToken = account.botToken?.trim();
378
+ const appToken = account.appToken?.trim();
379
+ ctx.log?.info(`[${account.accountId}] starting provider`);
380
+ return getSlackRuntime().channel.slack.monitorSlackProvider({
381
+ botToken: botToken ?? "",
382
+ appToken: appToken ?? "",
383
+ accountId: account.accountId,
384
+ config: ctx.cfg,
385
+ runtime: ctx.runtime,
386
+ abortSignal: ctx.abortSignal,
387
+ mediaMaxMb: account.config.mediaMaxMb,
388
+ slashCommand: account.config.slashCommand,
389
+ setStatus: ctx.setStatus,
390
+ getStatus: ctx.getStatus,
391
+ });
392
+ },
393
+ },
394
+ };
@@ -0,0 +1,28 @@
1
+ import { listSlackAccountIds, resolveSlackAccount } from "./accounts.js";
2
+ function resolveInteractiveRepliesFromCapabilities(capabilities) {
3
+ if (!capabilities) {
4
+ return false;
5
+ }
6
+ if (Array.isArray(capabilities)) {
7
+ return capabilities.some((entry) => String(entry).trim().toLowerCase() === "interactivereplies");
8
+ }
9
+ if (typeof capabilities === "object") {
10
+ return capabilities.interactiveReplies === true;
11
+ }
12
+ return false;
13
+ }
14
+ export function isSlackInteractiveRepliesEnabled(params) {
15
+ if (params.accountId) {
16
+ const account = resolveSlackAccount({ cfg: params.cfg, accountId: params.accountId });
17
+ return resolveInteractiveRepliesFromCapabilities(account.config.capabilities);
18
+ }
19
+ const accountIds = listSlackAccountIds(params.cfg);
20
+ if (accountIds.length === 0) {
21
+ return resolveInteractiveRepliesFromCapabilities(params.cfg.channels?.slack?.capabilities);
22
+ }
23
+ if (accountIds.length > 1) {
24
+ return false;
25
+ }
26
+ const account = resolveSlackAccount({ cfg: params.cfg, accountId: accountIds[0] });
27
+ return resolveInteractiveRepliesFromCapabilities(account.config.capabilities);
28
+ }