@openclaw/slack 2026.7.2-beta.7 → 2026.8.1-beta.3

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 (87) hide show
  1. package/dist/{account-inspect-DEKpg9Ip.js → account-inspect-YJvFBbCR.js} +1 -1
  2. package/dist/account-inspect-api.js +1 -1
  3. package/dist/{accounts-CHAeNZOX.js → accounts-BlzxuYle.js} +7 -3
  4. package/dist/{accounts.runtime-BHD4Ma2R.js → accounts.runtime-CbabBL8x.js} +1 -1
  5. package/dist/{action-runtime-DfuYoMjG.js → action-runtime-D6jg2CQd.js} +193 -125
  6. package/dist/action-runtime.runtime-JtoOK9l5.js +2 -0
  7. package/dist/{actions-D3NuJvva.js → actions-DFk0ANVB.js} +116 -235
  8. package/dist/actions.runtime-CYLsYRai.js +2 -0
  9. package/dist/api.js +17 -17
  10. package/dist/{approval-handler.runtime-BA05P0QT.js → approval-handler.runtime-BNvAoKdK.js} +53 -14
  11. package/dist/{channel-B9fVdW3s.js → channel-CA5w7qDF.js} +209 -110
  12. package/dist/channel-config-api.js +1 -1
  13. package/dist/channel-plugin-api.js +1 -1
  14. package/dist/{channel-type-DXyos1d2.js → channel-type-CZWv55Wu.js} +9 -12
  15. package/dist/{config-adapter-CxBQH8fq.js → channel.setup-CpyYsEXH.js} +83 -25
  16. package/dist/{config-schema-SgZT6nXV.js → config-schema-CN3XZRX5.js} +27 -17
  17. package/dist/conversation-binding-route-DFVLUdYF.js +115 -0
  18. package/dist/{directory-config-CnCIAktf.js → directory-config-BGYyuzWh.js} +3 -3
  19. package/dist/directory-contract-api.js +1 -1
  20. package/dist/{directory-live-DKunWh3A.js → directory-live-DjUJQLbq.js} +13 -22
  21. package/dist/{doctor-contract-CsGH1Dfc.js → doctor-contract-BAy7-EUQ.js} +30 -3
  22. package/dist/doctor-contract-api.js +1 -1
  23. package/dist/{group-policy-NQZti9t-.js → group-policy-DyfB_ZIE.js} +282 -183
  24. package/dist/index.js +4 -1
  25. package/dist/{message-tool-api-DkhFpMoy.js → message-tool-api-CqMr5Rmc.js} +14 -3
  26. package/dist/message-tool-api.js +1 -1
  27. package/dist/{monitor-CmKz0wtI.js → monitor-Chrecrb9.js} +3 -3
  28. package/dist/{outbound-adapter-BkuMp2Vs.js → outbound-adapter-DuRqAQXK.js} +35 -23
  29. package/dist/{pipeline.runtime-DgtmuYCP.js → pipeline.runtime-Bbfd5VFW.js} +1386 -929
  30. package/dist/{policy-PRysPn23.js → policy-BKXSxrIS.js} +18 -14
  31. package/dist/{probe-CgDsSops.js → probe-BVA65leh.js} +38 -18
  32. package/dist/{provider-DmRizMZt.js → provider-CUUiwsg2.js} +3454 -2601
  33. package/dist/{relay-source-Blxj8xb4.js → relay-source-mhpMMRG-.js} +11 -21
  34. package/dist/{replies-4s_Vq_z9.js → replies-SnWyXcsL.js} +84 -27
  35. package/dist/{resolve-channels-yEqmM-3I.js → resolve-channels-BSpqC8jU.js} +39 -12
  36. package/dist/{resolve-users-BOrt5K-5.js → resolve-users-Dvz9pDe0.js} +28 -5
  37. package/dist/{runtime-api-QMb-Q5Ko.js → runtime-api-DBi7xc_g.js} +3 -3
  38. package/dist/runtime-api.js +11 -11
  39. package/dist/{scopes-BJSrkAp6.js → scopes-BSk4GZvZ.js} +1 -1
  40. package/dist/security-contract-api.js +1 -1
  41. package/dist/{send-DsLeZpST.js → send-CtnOxKCc.js} +249 -163
  42. package/dist/{send.runtime-gUdK6V3h.js → send.runtime-kYctMHSd.js} +1 -1
  43. package/dist/setup-entry.js +1 -4
  44. package/dist/setup-plugin-api.js +1 -1
  45. package/dist/{setup-surface-BeNzrMrJ.js → setup-surface-BPFfp6So.js} +6 -6
  46. package/dist/{shared-DgIN3Dcr.js → shared-DJBaslN7.js} +45 -45
  47. package/dist/{block-text-DkHaoGem.js → slack-client-kind-BXyOOICI.js} +17 -2
  48. package/dist/{slash-dispatch.runtime-zPkyl7dB.js → slash-dispatch.runtime-Cf2FTrnf.js} +2 -2
  49. package/dist/{streaming-compat-3_X-21wW.js → streaming-compat-B-e0mqM0.js} +3 -8
  50. package/dist/{target-parsing-N6lHogYZ.js → target-parsing-BnMD2ZqZ.js} +40 -2
  51. package/dist/{targets-KmjP2E8s.js → targets-Cx5W_n3W.js} +1 -1
  52. package/node_modules/@slack/bolt/node_modules/@types/node/README.md +1 -1
  53. package/node_modules/@slack/bolt/node_modules/@types/node/crypto.d.ts +1 -1
  54. package/node_modules/@slack/bolt/node_modules/@types/node/package.json +2 -2
  55. package/node_modules/@slack/socket-mode/node_modules/@types/node/README.md +1 -1
  56. package/node_modules/@slack/socket-mode/node_modules/@types/node/crypto.d.ts +1 -1
  57. package/node_modules/@slack/socket-mode/node_modules/@types/node/package.json +2 -2
  58. package/node_modules/@slack/web-api/node_modules/@types/node/README.md +1 -1
  59. package/node_modules/@slack/web-api/node_modules/@types/node/crypto.d.ts +1 -1
  60. package/node_modules/@slack/web-api/node_modules/@types/node/package.json +2 -2
  61. package/node_modules/undici/lib/cache/memory-cache-store.js +54 -9
  62. package/node_modules/undici/lib/cache/sqlite-cache-store.js +7 -1
  63. package/node_modules/undici/lib/core/request.js +12 -1
  64. package/node_modules/undici/lib/dispatcher/client-h1.js +11 -2
  65. package/node_modules/undici/lib/handler/cache-handler.js +246 -64
  66. package/node_modules/undici/lib/handler/cache-revalidation-handler.js +3 -3
  67. package/node_modules/undici/lib/handler/retry-handler.js +24 -0
  68. package/node_modules/undici/lib/interceptor/cache.js +159 -52
  69. package/node_modules/undici/lib/util/cache.js +324 -62
  70. package/node_modules/undici/lib/util/date.js +23 -6
  71. package/node_modules/undici/lib/web/cookies/util.js +79 -9
  72. package/node_modules/undici/package.json +1 -1
  73. package/openclaw.plugin.json +280 -33
  74. package/package.json +9 -11
  75. package/skills/slack/SKILL.md +10 -68
  76. package/dist/account-reply-mode-DrUXogvO.js +0 -14
  77. package/dist/action-runtime.runtime-DQErZYpz.js +0 -2
  78. package/dist/actions.runtime-BIRU_G4M.js +0 -2
  79. package/dist/channel.setup-CLP5oTvh.js +0 -56
  80. package/dist/preflight-audio.runtime-D5Bgags0.js +0 -3
  81. package/dist/slash-plugin-commands.runtime-Dosfcx3X.js +0 -2
  82. package/node_modules/p-map/index.d.ts +0 -155
  83. package/node_modules/p-map/index.js +0 -285
  84. package/node_modules/p-map/license +0 -9
  85. package/node_modules/p-map/package.json +0 -57
  86. package/node_modules/p-map/readme.md +0 -190
  87. package/dist/{security-audit-DR097212.js → security-audit-B_yKr7MW.js} +1 -1
@@ -1,14 +1,12 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
- import { a as resolveSlackAccount, l as resolveSlackOperationToken } from "./accounts-CHAeNZOX.js";
3
- import { s as normalizeAllowListLower } from "./group-policy-NQZti9t-.js";
4
- import { l as createSlackWebClient, o as createSlackReadClient } from "./probe-CgDsSops.js";
2
+ import { a as resolveSlackAccount, l as resolveSlackOperationToken } from "./accounts-BlzxuYle.js";
3
+ import { g as assertSlackDetachedTargetAllowed, u as normalizeAllowListLower } from "./group-policy-DyfB_ZIE.js";
4
+ import { a as createSlackReadClient, c as createSlackWebClient } from "./probe-BVA65leh.js";
5
5
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
6
6
  import { createHash } from "node:crypto";
7
7
  import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
8
8
  //#region extensions/slack/src/channel-type.ts
9
9
  var channel_type_exports = /* @__PURE__ */ __exportAll({
10
- __resetSlackChannelTypeCacheForTest: () => resetSlackChannelTypeCacheForTest,
11
- resetSlackChannelTypeCacheForTest: () => resetSlackChannelTypeCacheForTest,
12
10
  resolveSlackChannelType: () => resolveSlackChannelType,
13
11
  resolveSlackConversationInfo: () => resolveSlackConversationInfo
14
12
  });
@@ -47,12 +45,14 @@ async function resolveSlackConversationInfo(params) {
47
45
  cfg: params.cfg,
48
46
  accountId: params.accountId
49
47
  });
48
+ assertSlackDetachedTargetAllowed(account.accountId, params.teamId);
50
49
  const operation = params.operation ?? "read";
51
50
  const token = resolveSlackOperationToken(account, operation);
52
51
  const userToken = normalizeOptionalString(account.userToken);
53
52
  const credentialRole = token ? token === userToken ? "user" : "bot" : "none";
54
53
  const credentialFingerprint = token ? fingerprintSlackCredential(token) : "none";
55
- const cacheKey = `${account.accountId}:${operation}:${credentialRole}:${credentialFingerprint}:${channelId}`;
54
+ const teamId = normalizeLowercaseStringOrEmpty(params.teamId) || "no-team-id";
55
+ const cacheKey = `${account.accountId}:${teamId}:${operation}:${credentialRole}:${credentialFingerprint}:${channelId}`;
56
56
  if (!params.requireFreshName) {
57
57
  const cached = getCachedSlackConversationInfo(cacheKey);
58
58
  if (cached) return cached;
@@ -64,7 +64,7 @@ async function resolveSlackConversationInfo(params) {
64
64
  });
65
65
  if (token) try {
66
66
  if (isNativeImChannel && operation === "write") {
67
- const opened = await createSlackWebClient(token).conversations.open({
67
+ const opened = await createSlackWebClient(token, { teamId: params.teamId }).conversations.open({
68
68
  channel: channelId,
69
69
  prevent_creation: true,
70
70
  return_im: true
@@ -77,7 +77,7 @@ async function resolveSlackConversationInfo(params) {
77
77
  if (user) setCachedSlackConversationInfo(cacheKey, result);
78
78
  return result;
79
79
  }
80
- const channel = (await createSlackReadClient(token).conversations.info({ channel: channelId })).channel;
80
+ const channel = (await createSlackReadClient(token, { teamId: params.teamId }).conversations.info({ channel: channelId })).channel;
81
81
  const type = channel?.is_im ? "dm" : channel?.is_mpim ? "group" : "channel";
82
82
  const name = normalizeOptionalString(channel?.name);
83
83
  const user = normalizeOptionalString(channel?.user);
@@ -101,8 +101,5 @@ async function resolveSlackConversationInfo(params) {
101
101
  async function resolveSlackChannelType(params) {
102
102
  return (await resolveSlackConversationInfo(params)).type;
103
103
  }
104
- function resetSlackChannelTypeCacheForTest() {
105
- SLACK_CONVERSATION_INFO_CACHE.clear();
106
- }
107
104
  //#endregion
108
- export { resolveSlackConversationInfo as i, resetSlackChannelTypeCacheForTest as n, resolveSlackChannelType as r, channel_type_exports as t };
105
+ export { resolveSlackChannelType as n, resolveSlackConversationInfo as r, channel_type_exports as t };
@@ -1,6 +1,7 @@
1
- import { a as resolveSlackAccount, c as resolveSlackConfigAccessorAccount, i as resolveDefaultSlackAccountId, n as listSlackAccountIds } from "./accounts-CHAeNZOX.js";
2
- import { t as inspectSlackAccount } from "./account-inspect-DEKpg9Ip.js";
1
+ import { a as resolveSlackAccount, c as resolveSlackConfigAccessorAccount, i as resolveDefaultSlackAccountId, n as listSlackAccountIds } from "./accounts-BlzxuYle.js";
2
+ import { t as inspectSlackAccount } from "./account-inspect-YJvFBbCR.js";
3
3
  import { t as isSlackPluginAccountConfigured } from "./account-configured-BwfXBo_F.js";
4
+ import { t as SlackChannelConfigSchema } from "./config-schema-CN3XZRX5.js";
4
5
  import { hasConfiguredSecretInput, normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input";
5
6
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
6
7
  import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
@@ -247,7 +248,12 @@ const slackSetupAdapterBase = createPatchedAccountSetupAdapter({
247
248
  const identity = setupInput.identity ?? account.config.postAs ?? "bot";
248
249
  const mode = setupInput.mode ?? account.config.mode ?? "socket";
249
250
  if (identity === "user" && mode === "relay") return "Slack user identity setup supports mode \"socket\" or \"http\", not \"relay\".";
250
- if (setupInput.useEnv) return identity === "user" ? "Slack user identity setup does not support --use-env; configure userToken and the transport credential explicitly." : null;
251
+ if (setupInput.useEnv) {
252
+ if (identity === "user") return "Slack user identity setup does not support --use-env; configure userToken and the transport credential explicitly.";
253
+ if (mode === "socket" && !normalizeOptionalString(setupInput.appToken) && account.appTokenStatus === "missing") return "Slack Socket Mode requires SLACK_APP_TOKEN when using --use-env.";
254
+ if (mode === "http" && !normalizeOptionalString(setupInput.signingSecret) && account.signingSecretStatus === "missing") return "Slack HTTP mode requires a configured signing secret when using --use-env.";
255
+ return null;
256
+ }
251
257
  if (hasSlackSetupCredentials({
252
258
  input: setupInput,
253
259
  identity,
@@ -268,25 +274,6 @@ const slackSetupAdapterBase = createPatchedAccountSetupAdapter({
268
274
  };
269
275
  }
270
276
  });
271
- const slackSetupAdapter = {
272
- ...slackSetupAdapterBase,
273
- singleAccountKeysToMove: ["appToken"],
274
- applyAccountConfig: ({ cfg, accountId, input }) => {
275
- const setupInput = input;
276
- const identity = setupInput.identity ?? inspectSlackAccount({
277
- cfg,
278
- accountId
279
- }).config.postAs;
280
- return slackSetupAdapterBase.applyAccountConfig({
281
- cfg,
282
- accountId,
283
- input: identity === "user" ? {
284
- ...setupInput,
285
- identity
286
- } : setupInput
287
- });
288
- }
289
- };
290
277
  const slackSetupContract = defineChannelSetupContract({
291
278
  fields: {
292
279
  botToken: {
@@ -342,10 +329,29 @@ const slackSetupContract = defineChannelSetupContract({
342
329
  cli: {
343
330
  flags: "--use-env",
344
331
  description: "Use Slack environment credentials"
345
- }
332
+ },
333
+ envVars: ["SLACK_BOT_TOKEN"]
346
334
  }
347
335
  },
348
- legacyAdapter: slackSetupAdapter
336
+ legacyAdapter: {
337
+ ...slackSetupAdapterBase,
338
+ singleAccountKeysToMove: ["appToken"],
339
+ applyAccountConfig: ({ cfg, accountId, input }) => {
340
+ const setupInput = input;
341
+ const identity = setupInput.identity ?? inspectSlackAccount({
342
+ cfg,
343
+ accountId
344
+ }).config.postAs;
345
+ return slackSetupAdapterBase.applyAccountConfig({
346
+ cfg,
347
+ accountId,
348
+ input: identity === "user" ? {
349
+ ...setupInput,
350
+ identity
351
+ } : setupInput
352
+ });
353
+ }
354
+ }
349
355
  });
350
356
  function createSlackSetupWizardBase(handlers) {
351
357
  const slackDmPolicy = createChannelDmPolicy({
@@ -563,4 +569,56 @@ const slackBaseConfigAdapter = createScopedChannelConfigAdapter({
563
569
  resolveDefaultTo: (account) => account.defaultTo
564
570
  });
565
571
  //#endregion
566
- export { slackSetupContract as a, isSlackSetupAccountConfigured as c, slackSetupAdapter as i, createSlackSetupWizardBase as n, SLACK_CHANNEL as o, createSlackSetupWizardProxy as r, describeSlackSetupAccount as s, slackBaseConfigAdapter as t };
572
+ //#region extensions/slack/src/channel.setup.ts
573
+ const slackSetupWizard = createSlackSetupWizardProxy(async () => ({ slackSetupWizard: (await import("./setup-surface-BPFfp6So.js")).slackSetupWizard }));
574
+ const slackSetupPlugin = {
575
+ id: SLACK_CHANNEL,
576
+ meta: {
577
+ id: SLACK_CHANNEL,
578
+ label: "Slack",
579
+ selectionLabel: "Slack (Socket Mode)",
580
+ detailLabel: "Slack Bot",
581
+ docsPath: "/channels/slack",
582
+ docsLabel: "slack",
583
+ blurb: "supported (Socket Mode).",
584
+ systemImage: "number",
585
+ markdownCapable: true,
586
+ preferSessionLookupForAnnounceTarget: true
587
+ },
588
+ setupWizard: slackSetupWizard,
589
+ capabilities: {
590
+ chatTypes: [
591
+ "direct",
592
+ "channel",
593
+ "thread"
594
+ ],
595
+ reactions: true,
596
+ threads: true,
597
+ media: true,
598
+ nativeCommands: true
599
+ },
600
+ commands: {
601
+ nativeCommandsAutoEnabled: false,
602
+ nativeSkillsAutoEnabled: false,
603
+ resolveNativeCommandName: ({ commandKey, defaultName }) => commandKey === "status" ? "agentstatus" : defaultName
604
+ },
605
+ streaming: { blockStreamingCoalesceDefaults: {
606
+ minChars: 1500,
607
+ idleMs: 1e3
608
+ } },
609
+ reload: { configPrefixes: ["channels.slack"] },
610
+ configSchema: SlackChannelConfigSchema,
611
+ config: {
612
+ ...slackBaseConfigAdapter,
613
+ hasConfiguredState: ({ env }) => [
614
+ "SLACK_APP_TOKEN",
615
+ "SLACK_BOT_TOKEN",
616
+ "SLACK_USER_TOKEN"
617
+ ].some((key) => typeof env?.[key] === "string" && env[key]?.trim().length > 0),
618
+ isConfigured: (account) => isSlackSetupAccountConfigured(account),
619
+ describeAccount: (account) => describeSlackSetupAccount(account)
620
+ },
621
+ setupContract: slackSetupContract
622
+ };
623
+ //#endregion
624
+ export { slackSetupContract as a, createSlackSetupWizardProxy as i, slackBaseConfigAdapter as n, SLACK_CHANNEL as o, createSlackSetupWizardBase as r, slackSetupPlugin as t };
@@ -8,10 +8,6 @@ const slackChannelConfigUiHints = {
8
8
  label: "Slack",
9
9
  help: "Slack channel provider configuration for bot/app tokens, streaming behavior, and DM policy controls. Keep token handling and thread behavior explicit to avoid noisy workspace interactions."
10
10
  },
11
- enterpriseOrgInstall: {
12
- label: "Slack Enterprise Grid Org Install",
13
- help: "Enable only for an Enterprise Grid org-wide bot installation. OpenClaw verifies the token with Slack auth.test at startup; DMs must be disabled or use dmPolicy=\"open\" with allowFrom=[\"*\"]."
14
- },
15
11
  postAs: {
16
12
  label: "Slack Identity",
17
13
  help: "Select \"bot\" (default) for the classic Slack app/bot identity or \"user\" to post as the authorizing human through a user token while the app carries event transport."
@@ -28,16 +24,16 @@ const slackChannelConfigUiHints = {
28
24
  nativeCommands: true,
29
25
  implicitMentions: true,
30
26
  streaming: {
31
- "": "Unified Slack stream preview mode: \"off\" | \"partial\" | \"block\" | \"progress\". Legacy boolean/streamMode keys are auto-mapped.",
32
- mode: "Canonical Slack preview mode: \"off\" | \"partial\" | \"block\" | \"progress\".",
27
+ "": "Unified Slack stream preview mode: \"off\" | \"partial\" | \"block\" | \"progress\" (default). Legacy boolean/streamMode keys are auto-mapped.",
28
+ mode: "Canonical Slack preview mode: \"off\" | \"partial\" | \"block\" | \"progress\" (default).",
33
29
  chunkMode: "Chunking mode for outbound Slack text delivery: \"length\" (default) or \"newline\".",
34
30
  "block.enabled": "Enable chunked block-style Slack preview delivery when channels.slack.streaming.mode=\"block\".",
35
31
  "block.coalesce": "Merge streamed Slack block replies before final delivery.",
36
32
  nativeTransport: "Enable native Slack text streaming (chat.startStream/chat.appendStream/chat.stopStream) when channels.slack.streaming.mode is partial (default: true). Native streaming and Slack assistant thread status require a reply thread target; top-level DMs can still use draft post-and-edit preview streaming.",
37
33
  "preview.toolProgress": "Show tool/progress activity in the live draft preview message (default: true). Set false to hide interim tool updates while the draft preview stays active.",
38
- "preview.commandText": "Command/exec detail in preview tool-progress lines: \"raw\" preserves released behavior; \"status\" shows only the tool label.",
39
- "progress.render": "Progress draft renderer: \"text\" uses one portable text body; \"rich\" renders structured Slack Block Kit fields with the same text fallback.",
40
- "progress.nativeTaskCards": "Opt in to Slack native task-card progress updates when channels.slack.streaming.mode=\"progress\" and streaming.nativeTransport is enabled. Default: false."
34
+ "preview.commandText": "Command/exec detail in preview tool-progress lines: \"status\" is the safe default; \"raw\" opts into command text.",
35
+ "progress.style": "Slack progress presentation: \"card\" (default) uses structured task/session cards; \"compact\" keeps one editable text draft that the final answer replaces in place when Slack can safely edit it.",
36
+ "progress.nativeTaskCards": "Slack native task-card progress updates when channels.slack.streaming.mode=\"progress\", progress.style=\"card\", and streaming.nativeTransport is enabled. Set false to fall back to the Block Kit progress card. Default: true."
41
37
  },
42
38
  progress: { labels: "openclaw" }
43
39
  }),
@@ -99,7 +95,7 @@ const slackChannelConfigUiHints = {
99
95
  },
100
96
  execApprovals: {
101
97
  label: "Slack Exec Approvals",
102
- help: "Slack-native exec approval routing and approver authorization. When unset, OpenClaw auto-enables DM-first native approvals if approvers can be resolved for this workspace account."
98
+ help: "Slack-native exec approval routing and approver authorization. When unset, OpenClaw auto-enables DM-first native approvals if approvers can be resolved for this Slack account."
103
99
  },
104
100
  presenceEvents: {
105
101
  label: "Slack Presence Events",
@@ -109,10 +105,18 @@ const slackChannelConfigUiHints = {
109
105
  label: "Slack Presence Event Mode",
110
106
  help: "\"off\" disables polling; \"auto\" covers DMs, MPIMs, and recent threads with up to 8 observed people; \"on\" also covers larger threads and top-level channels."
111
107
  },
108
+ "presenceEvents.prompt": {
109
+ label: "Slack Presence Event Prompt",
110
+ help: "Replace the default greeting guidance appended after presence facts. Use an empty string to omit event-specific guidance and let workspace instructions such as AGENTS.md govern behavior. Maximum: 20,000 characters."
111
+ },
112
112
  "channels.*.presenceEvents.mode": {
113
113
  label: "Slack Channel Presence Event Mode",
114
114
  help: "Override presence events for one Slack channel. Use \"on\" to include large threads or top-level channel sessions."
115
115
  },
116
+ "channels.*.presenceEvents.prompt": {
117
+ label: "Slack Channel Presence Event Prompt",
118
+ help: "Override the account-level presence-event prompt for one Slack channel. Maximum: 20,000 characters."
119
+ },
116
120
  "execApprovals.enabled": {
117
121
  label: "Slack Exec Approvals Enabled",
118
122
  help: "Controls Slack native exec approvals for this account: unset or \"auto\" enables DM-first native approvals when approvers can be resolved, true forces native approvals on, and false disables them."
@@ -149,7 +153,11 @@ const slackChannelConfigUiHints = {
149
153
  //#endregion
150
154
  //#region extensions/slack/src/config-schema.ts
151
155
  const SecretInputSchema = buildSecretInputSchema();
152
- const SlackStreamingProgressSchema = ChannelStreamingProgressSchema.extend({ nativeTaskCards: z.boolean().optional() }).strict();
156
+ const SLACK_PRESENCE_EVENT_PROMPT_MAX_CHARS = 2e4;
157
+ const SlackStreamingProgressSchema = ChannelStreamingProgressSchema.extend({
158
+ style: z.enum(["card", "compact"]).optional(),
159
+ nativeTaskCards: z.boolean().optional()
160
+ }).strict();
153
161
  const SlackStreamingConfigSchema = ChannelPreviewStreamingConfigSchema.extend({
154
162
  nativeTransport: z.boolean().optional(),
155
163
  progress: SlackStreamingProgressSchema.optional()
@@ -159,11 +167,14 @@ const SlackDmSchema = z.object({
159
167
  groupEnabled: z.boolean().optional(),
160
168
  groupChannels: z.array(z.union([z.string(), z.number()])).optional()
161
169
  }).strict();
162
- const SlackPresenceEventsSchema = z.object({ mode: z.enum([
163
- "off",
164
- "auto",
165
- "on"
166
- ]).optional() }).strict();
170
+ const SlackPresenceEventsSchema = z.object({
171
+ mode: z.enum([
172
+ "off",
173
+ "auto",
174
+ "on"
175
+ ]).optional(),
176
+ prompt: z.string().max(SLACK_PRESENCE_EVENT_PROMPT_MAX_CHARS).optional()
177
+ }).strict();
167
178
  const SlackChannelSchema = buildGroupEntrySchema({
168
179
  ignoreOtherMentions: z.boolean().optional(),
169
180
  replyToMode: ReplyToModeSchema.optional(),
@@ -199,7 +210,6 @@ const SlackAccountSchema = z.object({
199
210
  "http",
200
211
  "relay"
201
212
  ]).optional(),
202
- enterpriseOrgInstall: z.boolean().optional(),
203
213
  relay: SlackRelaySchema.optional(),
204
214
  signingSecret: SecretInputSchema.optional(),
205
215
  webhookPath: z.string().optional(),
@@ -0,0 +1,115 @@
1
+ import { a as parseSlackTarget } from "./target-parsing-BnMD2ZqZ.js";
2
+ import "./targets-Cx5W_n3W.js";
3
+ import { resolveConfiguredBindingRoute, resolveRuntimeConversationBindingRoute } from "openclaw/plugin-sdk/conversation-runtime";
4
+ //#region extensions/slack/src/account-reply-mode.ts
5
+ function normalizeSlackChatType(raw) {
6
+ const value = raw?.trim().toLowerCase();
7
+ if (!value) return;
8
+ if (value === "direct" || value === "dm") return "direct";
9
+ if (value === "group" || value === "channel") return value;
10
+ }
11
+ function resolveSlackReplyToMode(account, chatType) {
12
+ const normalized = normalizeSlackChatType(chatType ?? void 0);
13
+ if (normalized && account.replyToModeByChatType?.[normalized] !== void 0) return account.replyToModeByChatType[normalized] ?? "off";
14
+ return account.replyToMode ?? "off";
15
+ }
16
+ //#endregion
17
+ //#region extensions/slack/src/conversation-binding-route.ts
18
+ const slackRouteBindingConfigCache = /* @__PURE__ */ new WeakMap();
19
+ function slackTargetDefaultKindForPeer(kind) {
20
+ return kind === "direct" ? "user" : "channel";
21
+ }
22
+ function slackTargetKindMatchesPeer(peerKind, targetKind) {
23
+ if (targetKind === "user") return peerKind === "direct";
24
+ return peerKind === "channel" || peerKind === "group";
25
+ }
26
+ function normalizeSlackRouteBindingPeer(peer) {
27
+ const rawId = peer.id.trim();
28
+ if (!rawId || rawId === "*") return peer;
29
+ const target = (() => {
30
+ try {
31
+ return parseSlackTarget(rawId, { defaultKind: slackTargetDefaultKindForPeer(peer.kind) });
32
+ } catch {
33
+ return;
34
+ }
35
+ })();
36
+ if (!target || !slackTargetKindMatchesPeer(peer.kind, target.kind)) return peer;
37
+ const normalizedId = target.teamId ? `team:${target.teamId}:${target.kind}:${target.id}` : target.id;
38
+ return normalizedId === peer.id ? peer : {
39
+ ...peer,
40
+ id: normalizedId
41
+ };
42
+ }
43
+ function normalizeSlackRouteBindingConfig(cfg) {
44
+ const bindings = cfg.bindings;
45
+ const cached = slackRouteBindingConfigCache.get(cfg);
46
+ if (cached && cached.bindingsRef === bindings) return cached.normalizedCfg;
47
+ if (!Array.isArray(bindings)) return cfg;
48
+ let changed = false;
49
+ const normalizedBindings = bindings.map((binding) => {
50
+ if (binding.type === "acp" || binding.match.channel.trim().toLowerCase() !== "slack") return binding;
51
+ const peer = binding.match.peer;
52
+ if (!peer) return binding;
53
+ const normalizedPeer = normalizeSlackRouteBindingPeer(peer);
54
+ if (normalizedPeer === peer) return binding;
55
+ changed = true;
56
+ return {
57
+ ...binding,
58
+ match: {
59
+ ...binding.match,
60
+ peer: normalizedPeer
61
+ }
62
+ };
63
+ });
64
+ const normalizedCfg = changed ? {
65
+ ...cfg,
66
+ bindings: normalizedBindings
67
+ } : cfg;
68
+ slackRouteBindingConfigCache.set(cfg, {
69
+ bindingsRef: bindings,
70
+ normalizedCfg
71
+ });
72
+ return normalizedCfg;
73
+ }
74
+ function resolveSlackConversationBindingRoute(params) {
75
+ const boundThreadRoute = params.bindingsEnabled && params.runtimeBindingThreadId ? resolveRuntimeConversationBindingRoute({
76
+ route: params.route,
77
+ touchBinding: params.touchBinding,
78
+ conversation: {
79
+ channel: "slack",
80
+ accountId: params.accountId,
81
+ conversationId: params.runtimeBindingThreadId,
82
+ parentConversationId: params.baseConversationId
83
+ }
84
+ }) : null;
85
+ const runtimeRoute = !params.bindingsEnabled ? {
86
+ bindingOwnerAvailable: true,
87
+ route: params.route,
88
+ bindingRecord: null,
89
+ boundSessionKey: void 0
90
+ } : boundThreadRoute?.boundSessionKey || boundThreadRoute?.bindingRecord ? boundThreadRoute : resolveRuntimeConversationBindingRoute({
91
+ route: params.route,
92
+ touchBinding: params.touchBinding,
93
+ conversation: {
94
+ channel: "slack",
95
+ accountId: params.accountId,
96
+ conversationId: params.baseConversationId
97
+ }
98
+ });
99
+ const configuredRoute = params.bindingsEnabled && !runtimeRoute.boundSessionKey && !runtimeRoute.bindingRecord ? resolveConfiguredBindingRoute({
100
+ cfg: params.cfg,
101
+ route: params.route,
102
+ conversation: {
103
+ channel: "slack",
104
+ accountId: params.accountId,
105
+ conversationId: params.baseConversationId
106
+ }
107
+ }) : null;
108
+ return {
109
+ runtimeRoute,
110
+ configuredRoute,
111
+ route: runtimeRoute.boundSessionKey ? runtimeRoute.route : configuredRoute?.route ?? params.route
112
+ };
113
+ }
114
+ //#endregion
115
+ export { resolveSlackConversationBindingRoute as n, resolveSlackReplyToMode as r, normalizeSlackRouteBindingConfig as t };
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
- import { i as resolveDefaultSlackAccountId, o as resolveSlackAccountAllowFrom, r as mergeSlackAccountConfig } from "./accounts-CHAeNZOX.js";
3
- import { i as parseSlackTarget } from "./target-parsing-N6lHogYZ.js";
4
- import "./targets-KmjP2E8s.js";
2
+ import { i as resolveDefaultSlackAccountId, o as resolveSlackAccountAllowFrom, r as mergeSlackAccountConfig } from "./accounts-BlzxuYle.js";
3
+ import { a as parseSlackTarget } from "./target-parsing-BnMD2ZqZ.js";
4
+ import "./targets-Cx5W_n3W.js";
5
5
  import { normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
6
6
  import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
7
7
  import { createResolvedDirectoryEntriesLister } from "openclaw/plugin-sdk/directory-config-runtime";
@@ -1,2 +1,2 @@
1
- import { n as listSlackDirectoryGroupsFromConfig, r as listSlackDirectoryPeersFromConfig } from "./directory-config-CnCIAktf.js";
1
+ import { n as listSlackDirectoryGroupsFromConfig, r as listSlackDirectoryPeersFromConfig } from "./directory-config-BGYyuzWh.js";
2
2
  export { listSlackDirectoryGroupsFromConfig, listSlackDirectoryPeersFromConfig };
@@ -1,6 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
- import { a as resolveSlackAccount } from "./accounts-CHAeNZOX.js";
3
- import { a as createSlackLookupClient } from "./probe-CgDsSops.js";
2
+ import { a as resolveSlackAccount } from "./accounts-BlzxuYle.js";
3
+ import { i as createSlackLookupClient } from "./probe-BVA65leh.js";
4
+ import { t as collectSlackCursorPages } from "./cursor-pages-eX7p8Wwt.js";
4
5
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
5
6
  //#region extensions/slack/src/directory-live.ts
6
7
  var directory_live_exports = /* @__PURE__ */ __exportAll({
@@ -67,18 +68,13 @@ async function listSlackDirectoryPeersLive(params) {
67
68
  const client = createSlackDirectoryClient(params);
68
69
  if (!client) return [];
69
70
  const query = normalizeQuery(params.query);
70
- const members = [];
71
- let cursor;
72
- do {
73
- const res = await client.users.list({
71
+ const rows = (await collectSlackCursorPages({
72
+ fetchPage: (cursor) => client.users.list({
74
73
  limit: 200,
75
74
  cursor
76
- });
77
- if (Array.isArray(res.members)) members.push(...res.members);
78
- const next = res.response_metadata?.next_cursor?.trim();
79
- cursor = next ? next : void 0;
80
- } while (cursor);
81
- const rows = members.filter((member) => {
75
+ }),
76
+ collectPageItems: (res) => Array.isArray(res.members) ? res.members : []
77
+ })).filter((member) => {
82
78
  const candidates = [
83
79
  member.profile?.display_name || member.profile?.real_name || member.real_name,
84
80
  member.name,
@@ -94,20 +90,15 @@ async function listSlackDirectoryGroupsLive(params) {
94
90
  const client = createSlackDirectoryClient(params);
95
91
  if (!client) return [];
96
92
  const query = normalizeQuery(params.query);
97
- const channels = [];
98
- let cursor;
99
- do {
100
- const res = await client.conversations.list({
93
+ const rows = (await collectSlackCursorPages({
94
+ fetchPage: (cursor) => client.conversations.list({
101
95
  types: "public_channel,private_channel",
102
96
  exclude_archived: false,
103
97
  limit: 1e3,
104
98
  cursor
105
- });
106
- if (Array.isArray(res.channels)) channels.push(...res.channels);
107
- const next = res.response_metadata?.next_cursor?.trim();
108
- cursor = next ? next : void 0;
109
- } while (cursor);
110
- const rows = channels.filter((channel) => {
99
+ }),
100
+ collectPageItems: (res) => Array.isArray(res.channels) ? res.channels : []
101
+ })).filter((channel) => {
111
102
  const name = normalizeOptionalLowercaseString(channel.name);
112
103
  if (!query) return true;
113
104
  return Boolean(name && name.includes(query));
@@ -1,5 +1,5 @@
1
- import { n as resolveSlackNativeStreaming, r as resolveSlackStreamingMode } from "./streaming-compat-3_X-21wW.js";
2
- import { asObjectRecord, defineChannelAliasMigration, defineKeyMoveMigration, hasLegacyAccountStreamingAliases, normalizeChannelConfigEntries } from "openclaw/plugin-sdk/runtime-doctor";
1
+ import { n as resolveSlackStreamingMode, t as resolveSlackNativeStreaming } from "./streaming-compat-B-e0mqM0.js";
2
+ import { asObjectRecord, defineChannelAliasMigration, defineKeyMoveMigration, hasLegacyAccountStreamingAliases, normalizeChannelConfigEntries, stripRetiredChannelKeys } from "openclaw/plugin-sdk/runtime-doctor-migrations";
3
3
  //#region extensions/slack/src/doctor-contract.ts
4
4
  const streamingAliasMigration = defineChannelAliasMigration({
5
5
  channelId: "slack",
@@ -35,6 +35,9 @@ function hasInteractiveRepliesCapability(value) {
35
35
  const capabilitiesRecord = asObjectRecord(capabilities);
36
36
  return Boolean(capabilitiesRecord && (Object.keys(capabilitiesRecord).length === 0 || Object.hasOwn(capabilitiesRecord, "interactiveReplies")));
37
37
  }
38
+ function hasEnterpriseOrgInstall(value) {
39
+ return Object.hasOwn(asObjectRecord(value) ?? {}, "enterpriseOrgInstall");
40
+ }
38
41
  function removeInteractiveRepliesCapability(params) {
39
42
  const capabilities = params.entry.capabilities;
40
43
  let nextCapabilities;
@@ -66,6 +69,23 @@ function removeInteractiveRepliesCapability(params) {
66
69
  }
67
70
  const legacyConfigRules = [
68
71
  ...streamingAliasMigration.legacyConfigRules,
72
+ {
73
+ path: [
74
+ "channels",
75
+ "slack",
76
+ "enterpriseOrgInstall"
77
+ ],
78
+ message: "channels.slack.enterpriseOrgInstall is retired; Slack now detects org-wide installations automatically. Run \"openclaw doctor --fix\"."
79
+ },
80
+ {
81
+ path: [
82
+ "channels",
83
+ "slack",
84
+ "accounts"
85
+ ],
86
+ message: "channels.slack.accounts.<id>.enterpriseOrgInstall is retired; Slack now detects org-wide installations automatically. Run \"openclaw doctor --fix\".",
87
+ match: (value) => hasLegacyAccountStreamingAliases(value, hasEnterpriseOrgInstall)
88
+ },
69
89
  {
70
90
  path: ["channels", "slack"],
71
91
  message: "channels.slack.capabilities.interactiveReplies is retired; use typed presentation actions instead. Run \"openclaw doctor --fix\".",
@@ -144,9 +164,16 @@ function normalizeSlackEntry(params) {
144
164
  }
145
165
  function normalizeCompatibilityConfig({ cfg }) {
146
166
  const changes = [];
167
+ const retired = stripRetiredChannelKeys({
168
+ cfg,
169
+ channelId: "slack",
170
+ keys: /* @__PURE__ */ new Set(["enterpriseOrgInstall"]),
171
+ scope: "root-and-accounts",
172
+ onRemove: ({ key, pathPrefix }) => changes.push(`Removed retired ${pathPrefix}.${key}; Slack detects org-wide installations automatically.`)
173
+ });
147
174
  return normalizeChannelConfigEntries({
148
175
  cfg: streamingAliasMigration.normalizeChannelConfig({
149
- cfg,
176
+ cfg: retired.config,
150
177
  changes
151
178
  }).config,
152
179
  channelId: "slack",
@@ -1,2 +1,2 @@
1
- import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-CsGH1Dfc.js";
1
+ import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-BAy7-EUQ.js";
2
2
  export { legacyConfigRules, normalizeCompatibilityConfig };