@openclaw/slack 2026.5.12-beta.7

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 (88) hide show
  1. package/dist/account-inspect-D7AZNs8C.js +77 -0
  2. package/dist/account-inspect-api.js +10 -0
  3. package/dist/accounts-ClAPP5ry.js +139 -0
  4. package/dist/accounts.runtime-DDVcLJUI.js +2 -0
  5. package/dist/action-runtime-e2UhRsNx.js +350 -0
  6. package/dist/action-runtime.runtime-BFcqMbOm.js +2 -0
  7. package/dist/actions-CYLFK-Zy.js +292 -0
  8. package/dist/actions.runtime-CO3OaTLb.js +2 -0
  9. package/dist/allow-list-BPnnlRPL.js +82 -0
  10. package/dist/api.js +21 -0
  11. package/dist/approval-handler.runtime-CmeRr9qA.js +256 -0
  12. package/dist/blocks-input-CwTFVImV.js +29 -0
  13. package/dist/blocks-render-BIDw-Pom.js +161 -0
  14. package/dist/channel-DRjHBTDB.js +1020 -0
  15. package/dist/channel-api-B_nZwosg.js +20 -0
  16. package/dist/channel-config-api.js +2 -0
  17. package/dist/channel-entry.js +22 -0
  18. package/dist/channel-plugin-api.js +2 -0
  19. package/dist/channel.setup-Cayn7afd.js +73 -0
  20. package/dist/client-CPe4GmDR.js +103 -0
  21. package/dist/config-api-B_jq4NJW.js +2 -0
  22. package/dist/config-schema-D9B5LB_L.js +167 -0
  23. package/dist/configured-state.js +11 -0
  24. package/dist/contract-api.js +5 -0
  25. package/dist/directory-config-B3JiHeB7.js +54 -0
  26. package/dist/directory-contract-api.js +2 -0
  27. package/dist/directory-live-Bf16GwDh.js +133 -0
  28. package/dist/doctor-contract-KUjHnkQm.js +147 -0
  29. package/dist/doctor-contract-api.js +2 -0
  30. package/dist/errors-BYFHR24f.js +109 -0
  31. package/dist/exec-approvals-7xUNgLi9.js +58 -0
  32. package/dist/group-policy-CyLUK6My.js +41 -0
  33. package/dist/http-routes-api.js +2 -0
  34. package/dist/inbound-contract-test-api.js +3 -0
  35. package/dist/index.js +33 -0
  36. package/dist/interactive-replies-api.js +2 -0
  37. package/dist/interactive-replies-qAIfuBor.js +173 -0
  38. package/dist/magic-string.es-BMaGRRZ1.js +1011 -0
  39. package/dist/media-D1XCd1uP.js +469 -0
  40. package/dist/message-tool-api-6lowf9zE.js +104 -0
  41. package/dist/message-tool-api.js +2 -0
  42. package/dist/monitor-a97o17G6.js +13 -0
  43. package/dist/mrkdwn-Cax-eSfK.js +6 -0
  44. package/dist/outbound-adapter-B_5sEhCg.js +174 -0
  45. package/dist/outbound-payload-test-api.js +2 -0
  46. package/dist/outbound-payload.test-harness-CVCamg1x.js +13558 -0
  47. package/dist/pipeline.runtime-DT0hLnq2.js +1379 -0
  48. package/dist/plugin-routes-DtTPmga1.js +20 -0
  49. package/dist/prepare-D3YqV8jB.js +1482 -0
  50. package/dist/prepare.test-helpers-DVcjRhfG.js +49 -0
  51. package/dist/probe-3eZf1FjI.js +42 -0
  52. package/dist/provider-D7uAN3Fq.js +3235 -0
  53. package/dist/registry-CeaoNfoP.js +39 -0
  54. package/dist/replies-Xe_jMR6o.js +139 -0
  55. package/dist/reply-blocks-Z5l6_R6H.js +14 -0
  56. package/dist/resolve-allowlist-common-Bk3clYPK.js +43 -0
  57. package/dist/resolve-channels-BRYqyNVJ.js +81 -0
  58. package/dist/resolve-users-Bd_SdP8j.js +113 -0
  59. package/dist/rolldown-runtime-CiIaOW0V.js +13 -0
  60. package/dist/room-context-0vovmZPU.js +787 -0
  61. package/dist/runtime-Bo-KHM-F.js +8 -0
  62. package/dist/runtime-api-Dd1xIV5v.js +9 -0
  63. package/dist/runtime-api.js +14 -0
  64. package/dist/runtime-setter-api.js +2 -0
  65. package/dist/scopes-CDevO8jg.js +74 -0
  66. package/dist/secret-contract-Bo6lbSkh.js +141 -0
  67. package/dist/secret-contract-api.js +2 -0
  68. package/dist/security-audit-BtHGnD3d.js +51 -0
  69. package/dist/security-contract-api.js +2 -0
  70. package/dist/send-D_A9kL-C.js +721 -0
  71. package/dist/send.runtime-BRE_ncCU.js +2 -0
  72. package/dist/send.runtime-_l76lUuL.js +2 -0
  73. package/dist/setup-core-B9NetDkM.js +320 -0
  74. package/dist/setup-entry.js +15 -0
  75. package/dist/setup-plugin-api.js +2 -0
  76. package/dist/setup-surface-D88QBVOW.js +128 -0
  77. package/dist/shared-D8U42xFL.js +208 -0
  78. package/dist/slash-commands.runtime-22kgyst2.js +19 -0
  79. package/dist/slash-dispatch.runtime-BJgT0jwV.js +32 -0
  80. package/dist/slash-plugin-commands.runtime-CF-n3MeP.js +2 -0
  81. package/dist/slash-skill-commands.runtime-BMs0VjTe.js +7 -0
  82. package/dist/streaming-compat-RkZgTmQ2.js +43 -0
  83. package/dist/target-parsing-CQmv-iSm.js +55 -0
  84. package/dist/targets-B1tYCAr6.js +2 -0
  85. package/dist/test-api.js +8 -0
  86. package/dist/thread-ts-C2x7c5PP.js +24 -0
  87. package/openclaw.plugin.json +2405 -0
  88. package/package.json +84 -0
@@ -0,0 +1,147 @@
1
+ import { n as resolveSlackNativeStreaming, r as resolveSlackStreamingMode } from "./streaming-compat-RkZgTmQ2.js";
2
+ import { asObjectRecord, hasLegacyAccountStreamingAliases, hasLegacyStreamingAliases, normalizeLegacyChannelAliases } from "openclaw/plugin-sdk/runtime-doctor";
3
+ //#region extensions/slack/src/doctor-contract.ts
4
+ function hasLegacySlackStreamingAliases(value) {
5
+ return hasLegacyStreamingAliases(value, { includeNativeTransport: true });
6
+ }
7
+ function hasLegacySlackChannelAllowAlias(value) {
8
+ const channels = asObjectRecord(asObjectRecord(value)?.channels);
9
+ if (!channels) return false;
10
+ return Object.values(channels).some((channel) => Object.prototype.hasOwnProperty.call(asObjectRecord(channel) ?? {}, "allow"));
11
+ }
12
+ function normalizeSlackChannelAllowAliases(params) {
13
+ let changed = false;
14
+ const nextChannels = { ...params.channels };
15
+ for (const [channelId, channelValue] of Object.entries(params.channels)) {
16
+ const channel = asObjectRecord(channelValue);
17
+ if (!channel || !Object.prototype.hasOwnProperty.call(channel, "allow")) continue;
18
+ const nextChannel = { ...channel };
19
+ if (nextChannel.enabled === void 0) {
20
+ nextChannel.enabled = channel.allow;
21
+ params.changes.push(`Moved ${params.pathPrefix}.${channelId}.allow → ${params.pathPrefix}.${channelId}.enabled.`);
22
+ } else params.changes.push(`Removed ${params.pathPrefix}.${channelId}.allow (${params.pathPrefix}.${channelId}.enabled already set).`);
23
+ delete nextChannel.allow;
24
+ nextChannels[channelId] = nextChannel;
25
+ changed = true;
26
+ }
27
+ return {
28
+ channels: nextChannels,
29
+ changed
30
+ };
31
+ }
32
+ const legacyConfigRules = [
33
+ {
34
+ path: ["channels", "slack"],
35
+ message: "channels.slack.streamMode, channels.slack.streaming (scalar), chunkMode, blockStreaming, blockStreamingCoalesce, and nativeStreaming are legacy; use channels.slack.streaming.{mode,chunkMode,block.enabled,block.coalesce,nativeTransport}.",
36
+ match: hasLegacySlackStreamingAliases
37
+ },
38
+ {
39
+ path: [
40
+ "channels",
41
+ "slack",
42
+ "accounts"
43
+ ],
44
+ message: "channels.slack.accounts.<id>.streamMode, streaming (scalar), chunkMode, blockStreaming, blockStreamingCoalesce, and nativeStreaming are legacy; use channels.slack.accounts.<id>.streaming.{mode,chunkMode,block.enabled,block.coalesce,nativeTransport}.",
45
+ match: (value) => hasLegacyAccountStreamingAliases(value, hasLegacySlackStreamingAliases)
46
+ },
47
+ {
48
+ path: ["channels", "slack"],
49
+ message: "channels.slack.channels.<id>.allow is legacy; use channels.slack.channels.<id>.enabled instead. Run \"openclaw doctor --fix\".",
50
+ match: hasLegacySlackChannelAllowAlias
51
+ },
52
+ {
53
+ path: [
54
+ "channels",
55
+ "slack",
56
+ "accounts"
57
+ ],
58
+ message: "channels.slack.accounts.<id>.channels.<id>.allow is legacy; use channels.slack.accounts.<id>.channels.<id>.enabled instead. Run \"openclaw doctor --fix\".",
59
+ match: (value) => {
60
+ const accounts = asObjectRecord(value);
61
+ if (!accounts) return false;
62
+ return Object.values(accounts).some((account) => hasLegacySlackChannelAllowAlias(account));
63
+ }
64
+ }
65
+ ];
66
+ function normalizeCompatibilityConfig({ cfg }) {
67
+ const rawEntry = asObjectRecord(cfg.channels?.slack);
68
+ if (!rawEntry) return {
69
+ config: cfg,
70
+ changes: []
71
+ };
72
+ const changes = [];
73
+ let updated = rawEntry;
74
+ let changed = false;
75
+ const aliases = normalizeLegacyChannelAliases({
76
+ entry: rawEntry,
77
+ pathPrefix: "channels.slack",
78
+ changes,
79
+ normalizeDm: true,
80
+ normalizeAccountDm: true,
81
+ resolveStreamingOptions: (entry) => ({
82
+ resolvedMode: resolveSlackStreamingMode(entry),
83
+ resolvedNativeTransport: resolveSlackNativeStreaming(entry)
84
+ })
85
+ });
86
+ updated = aliases.entry;
87
+ changed = aliases.changed;
88
+ const channels = asObjectRecord(updated.channels);
89
+ if (channels) {
90
+ const normalized = normalizeSlackChannelAllowAliases({
91
+ channels,
92
+ pathPrefix: "channels.slack.channels",
93
+ changes
94
+ });
95
+ if (normalized.changed) {
96
+ updated = {
97
+ ...updated,
98
+ channels: normalized.channels
99
+ };
100
+ changed = true;
101
+ }
102
+ }
103
+ const accounts = asObjectRecord(updated.accounts);
104
+ if (accounts) {
105
+ let accountsChanged = false;
106
+ const nextAccounts = { ...accounts };
107
+ for (const [accountId, accountValue] of Object.entries(accounts)) {
108
+ const account = asObjectRecord(accountValue);
109
+ const channelEntries = asObjectRecord(account?.channels);
110
+ if (!account || !channelEntries) continue;
111
+ const normalized = normalizeSlackChannelAllowAliases({
112
+ channels: channelEntries,
113
+ pathPrefix: `channels.slack.accounts.${accountId}.channels`,
114
+ changes
115
+ });
116
+ if (!normalized.changed) continue;
117
+ nextAccounts[accountId] = {
118
+ ...account,
119
+ channels: normalized.channels
120
+ };
121
+ accountsChanged = true;
122
+ }
123
+ if (accountsChanged) {
124
+ updated = {
125
+ ...updated,
126
+ accounts: nextAccounts
127
+ };
128
+ changed = true;
129
+ }
130
+ }
131
+ if (!changed) return {
132
+ config: cfg,
133
+ changes: []
134
+ };
135
+ return {
136
+ config: {
137
+ ...cfg,
138
+ channels: {
139
+ ...cfg.channels,
140
+ slack: updated
141
+ }
142
+ },
143
+ changes
144
+ };
145
+ }
146
+ //#endregion
147
+ export { normalizeCompatibilityConfig as n, legacyConfigRules as t };
@@ -0,0 +1,2 @@
1
+ import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-KUjHnkQm.js";
2
+ export { legacyConfigRules, normalizeCompatibilityConfig };
@@ -0,0 +1,109 @@
1
+ import { redactSensitiveText } from "openclaw/plugin-sdk/logging-core";
2
+ //#region extensions/slack/src/errors.ts
3
+ const NO_ERROR_DETAIL = "no error detail";
4
+ function isRecord(value) {
5
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
6
+ }
7
+ function redact(value) {
8
+ return redactSensitiveText(value);
9
+ }
10
+ function addStringDetail(details, label, value) {
11
+ if (typeof value !== "string") return;
12
+ const trimmed = redact(value.trim());
13
+ if (trimmed) details.push(label ? `${label}: ${trimmed}` : trimmed);
14
+ }
15
+ function addScalarDetail(details, label, value) {
16
+ if (typeof value === "string") {
17
+ addStringDetail(details, label, value);
18
+ return;
19
+ }
20
+ if (typeof value === "number" || typeof value === "boolean") details.push(`${label}: ${String(value)}`);
21
+ }
22
+ function addStringListDetail(details, label, value) {
23
+ if (!Array.isArray(value)) return;
24
+ const entries = value.flatMap((entry) => {
25
+ if (typeof entry !== "string") return [];
26
+ const trimmed = redact(entry.trim());
27
+ return trimmed ? [trimmed] : [];
28
+ });
29
+ if (entries.length) details.push(`${label}: ${entries.join(", ")}`);
30
+ }
31
+ function safeStringify(value) {
32
+ const seen = /* @__PURE__ */ new WeakSet();
33
+ try {
34
+ const result = JSON.stringify(value, (_key, nested) => {
35
+ if (typeof nested !== "object" || nested === null) return nested;
36
+ if (seen.has(nested)) return "[Circular]";
37
+ seen.add(nested);
38
+ return nested;
39
+ });
40
+ return result ? redact(result) : void 0;
41
+ } catch {
42
+ return;
43
+ }
44
+ }
45
+ function addSlackResponseMetadata(details, value) {
46
+ if (!isRecord(value)) return;
47
+ addStringListDetail(details, "scopes", value.scopes);
48
+ addStringListDetail(details, "accepted", value.acceptedScopes);
49
+ const messages = value.messages;
50
+ if (Array.isArray(messages)) for (const message of messages) addStringDetail(details, "slack message", message);
51
+ const warnings = value.warnings;
52
+ if (Array.isArray(warnings)) for (const warning of warnings) addStringDetail(details, "slack warning", warning);
53
+ }
54
+ function addSlackDataDetails(details, value) {
55
+ if (!isRecord(value)) return;
56
+ addScalarDetail(details, "slack error", value.error);
57
+ addScalarDetail(details, "needed", value.needed);
58
+ addScalarDetail(details, "provided", value.provided);
59
+ addSlackResponseMetadata(details, value.response_metadata);
60
+ }
61
+ function addRecordDetails(details, value) {
62
+ addScalarDetail(details, "code", value.code);
63
+ addScalarDetail(details, "status", value.status);
64
+ addScalarDetail(details, "statusCode", value.statusCode);
65
+ addScalarDetail(details, "statusMessage", value.statusMessage);
66
+ addScalarDetail(details, "retryAfter", value.retryAfter);
67
+ addScalarDetail(details, "errno", value.errno);
68
+ addScalarDetail(details, "syscall", value.syscall);
69
+ addScalarDetail(details, "hostname", value.hostname);
70
+ addScalarDetail(details, "type", value.type);
71
+ addStringDetail(details, "statusText", value.statusText);
72
+ addStringDetail(details, "body", value.body);
73
+ addSlackDataDetails(details, value.data);
74
+ if (isRecord(value.response)) {
75
+ addScalarDetail(details, "response status", value.response.status);
76
+ addStringDetail(details, "response statusText", value.response.statusText);
77
+ addSlackDataDetails(details, value.response.data);
78
+ }
79
+ }
80
+ function collectSlackErrorDetails(error) {
81
+ const details = [];
82
+ if (error === void 0 || error === null) return details;
83
+ if (typeof error === "string") {
84
+ addStringDetail(details, "", error);
85
+ return details;
86
+ }
87
+ if (error instanceof Error) {
88
+ addStringDetail(details, "", error.message || error.name);
89
+ if (error.cause !== void 0) {
90
+ const cause = formatSlackError(error.cause, "");
91
+ if (cause) details.push(`cause: ${cause}`);
92
+ }
93
+ }
94
+ if (isRecord(error)) {
95
+ addRecordDetails(details, error);
96
+ const fallback = safeStringify(error);
97
+ if (details.length === 0 && fallback && fallback !== "{}") details.push(fallback);
98
+ }
99
+ return details;
100
+ }
101
+ function formatSlackError(error, fallback = NO_ERROR_DETAIL) {
102
+ const details = collectSlackErrorDetails(error);
103
+ if (details.length > 0) return details.join("; ");
104
+ if (error === void 0 || error === null) return fallback;
105
+ if (typeof error === "string" && !error.trim()) return fallback;
106
+ return safeStringify(error) ?? fallback;
107
+ }
108
+ //#endregion
109
+ export { formatSlackError as t };
@@ -0,0 +1,58 @@
1
+ import { a as resolveSlackAccount } from "./accounts-ClAPP5ry.js";
2
+ import { normalizeStringifiedOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
3
+ import { doesApprovalRequestMatchChannelAccount } from "openclaw/plugin-sdk/approval-native-runtime";
4
+ import { resolveApprovalApprovers } from "openclaw/plugin-sdk/approval-auth-runtime";
5
+ import { createChannelExecApprovalProfile, isChannelExecApprovalTargetRecipient } from "openclaw/plugin-sdk/approval-client-runtime";
6
+ //#region extensions/slack/src/exec-approvals.ts
7
+ function normalizeSlackApproverId(value) {
8
+ const trimmed = normalizeStringifiedOptionalString(value);
9
+ if (!trimmed) return;
10
+ const prefixed = trimmed.match(/^(?:slack|user):([A-Z0-9]+)$/i);
11
+ if (prefixed?.[1]) return prefixed[1];
12
+ const mention = trimmed.match(/^<@([A-Z0-9]+)>$/i);
13
+ if (mention?.[1]) return mention[1];
14
+ return /^[UW][A-Z0-9]+$/i.test(trimmed) ? trimmed : void 0;
15
+ }
16
+ function resolveSlackOwnerApprovers(cfg) {
17
+ const ownerAllowFrom = cfg.commands?.ownerAllowFrom;
18
+ if (!Array.isArray(ownerAllowFrom) || ownerAllowFrom.length === 0) return [];
19
+ return resolveApprovalApprovers({
20
+ explicit: ownerAllowFrom,
21
+ normalizeApprover: normalizeSlackApproverId
22
+ });
23
+ }
24
+ function getSlackExecApprovalApprovers(params) {
25
+ const account = resolveSlackAccount(params).config;
26
+ return resolveApprovalApprovers({
27
+ explicit: account.execApprovals?.approvers ?? resolveSlackOwnerApprovers(params.cfg),
28
+ normalizeApprover: normalizeSlackApproverId
29
+ });
30
+ }
31
+ function isSlackExecApprovalTargetRecipient(params) {
32
+ return isChannelExecApprovalTargetRecipient({
33
+ ...params,
34
+ channel: "slack",
35
+ normalizeSenderId: normalizeSlackApproverId,
36
+ matchTarget: ({ target, normalizedSenderId }) => normalizeSlackApproverId(target.to) === normalizedSenderId
37
+ });
38
+ }
39
+ const slackExecApprovalProfile = createChannelExecApprovalProfile({
40
+ resolveConfig: (params) => resolveSlackAccount(params).config.execApprovals,
41
+ resolveApprovers: getSlackExecApprovalApprovers,
42
+ normalizeSenderId: normalizeSlackApproverId,
43
+ isTargetRecipient: isSlackExecApprovalTargetRecipient,
44
+ matchesRequestAccount: (params) => doesApprovalRequestMatchChannelAccount({
45
+ cfg: params.cfg,
46
+ request: params.request,
47
+ channel: "slack",
48
+ accountId: params.accountId
49
+ })
50
+ });
51
+ const isSlackExecApprovalClientEnabled = slackExecApprovalProfile.isClientEnabled;
52
+ const isSlackExecApprovalApprover = slackExecApprovalProfile.isApprover;
53
+ const isSlackExecApprovalAuthorizedSender = slackExecApprovalProfile.isAuthorizedSender;
54
+ const resolveSlackExecApprovalTarget = slackExecApprovalProfile.resolveTarget;
55
+ const shouldHandleSlackExecApprovalRequest = slackExecApprovalProfile.shouldHandleRequest;
56
+ const shouldSuppressLocalSlackExecApprovalPrompt = slackExecApprovalProfile.shouldSuppressLocalPrompt;
57
+ //#endregion
58
+ export { normalizeSlackApproverId as a, shouldSuppressLocalSlackExecApprovalPrompt as c, isSlackExecApprovalClientEnabled as i, isSlackExecApprovalApprover as n, resolveSlackExecApprovalTarget as o, isSlackExecApprovalAuthorizedSender as r, shouldHandleSlackExecApprovalRequest as s, getSlackExecApprovalApprovers as t };
@@ -0,0 +1,41 @@
1
+ import { i as resolveDefaultSlackAccountId, r as mergeSlackAccountConfig } from "./accounts-ClAPP5ry.js";
2
+ import { normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
3
+ import { normalizeHyphenSlug } from "openclaw/plugin-sdk/string-normalization-runtime";
4
+ import { resolveToolsBySender } from "openclaw/plugin-sdk/channel-policy";
5
+ //#region extensions/slack/src/group-policy.ts
6
+ function resolveSlackChannelPolicyEntry(params) {
7
+ const accountId = normalizeAccountId(params.accountId ?? resolveDefaultSlackAccountId(params.cfg));
8
+ const channelMap = mergeSlackAccountConfig(params.cfg, accountId).channels ?? {};
9
+ if (Object.keys(channelMap).length === 0) return;
10
+ const channelId = params.groupId?.trim();
11
+ const channelName = params.groupChannel?.replace(/^#/, "");
12
+ const normalizedName = normalizeHyphenSlug(channelName);
13
+ const candidates = [
14
+ channelId ?? "",
15
+ channelName ? `#${channelName}` : "",
16
+ channelName ?? "",
17
+ normalizedName
18
+ ].filter(Boolean);
19
+ for (const candidate of candidates) if (candidate && channelMap[candidate]) return channelMap[candidate];
20
+ return channelMap["*"];
21
+ }
22
+ function resolveSenderToolsEntry(entry, params) {
23
+ if (!entry) return;
24
+ return resolveToolsBySender({
25
+ toolsBySender: entry.toolsBySender,
26
+ senderId: params.senderId,
27
+ senderName: params.senderName,
28
+ senderUsername: params.senderUsername,
29
+ senderE164: params.senderE164
30
+ }) ?? entry.tools;
31
+ }
32
+ function resolveSlackGroupRequireMention(params) {
33
+ const resolved = resolveSlackChannelPolicyEntry(params);
34
+ if (typeof resolved?.requireMention === "boolean") return resolved.requireMention;
35
+ return true;
36
+ }
37
+ function resolveSlackGroupToolPolicy(params) {
38
+ return resolveSenderToolsEntry(resolveSlackChannelPolicyEntry(params), params);
39
+ }
40
+ //#endregion
41
+ export { resolveSlackGroupToolPolicy as n, resolveSlackGroupRequireMention as t };
@@ -0,0 +1,2 @@
1
+ import { t as registerSlackPluginHttpRoutes } from "./plugin-routes-DtTPmga1.js";
2
+ export { registerSlackPluginHttpRoutes };
@@ -0,0 +1,3 @@
1
+ import { t as prepareSlackMessage } from "./prepare-D3YqV8jB.js";
2
+ import { t as createInboundSlackTestContext } from "./prepare.test-helpers-DVcjRhfG.js";
3
+ export { createInboundSlackTestContext, prepareSlackMessage };
package/dist/index.js ADDED
@@ -0,0 +1,33 @@
1
+ import { defineBundledChannelEntry, loadBundledEntryExportSync } from "openclaw/plugin-sdk/channel-entry-contract";
2
+ //#region extensions/slack/index.ts
3
+ function registerSlackPluginHttpRoutes(api) {
4
+ loadBundledEntryExportSync(import.meta.url, {
5
+ specifier: "./http-routes-api.js",
6
+ exportName: "registerSlackPluginHttpRoutes"
7
+ })(api);
8
+ }
9
+ var slack_default = defineBundledChannelEntry({
10
+ id: "slack",
11
+ name: "Slack",
12
+ description: "Slack channel plugin",
13
+ importMetaUrl: import.meta.url,
14
+ plugin: {
15
+ specifier: "./channel-plugin-api.js",
16
+ exportName: "slackPlugin"
17
+ },
18
+ secrets: {
19
+ specifier: "./secret-contract-api.js",
20
+ exportName: "channelSecrets"
21
+ },
22
+ runtime: {
23
+ specifier: "./runtime-setter-api.js",
24
+ exportName: "setSlackRuntime"
25
+ },
26
+ accountInspect: {
27
+ specifier: "./account-inspect-api.js",
28
+ exportName: "inspectSlackReadOnlyAccount"
29
+ },
30
+ registerFull: registerSlackPluginHttpRoutes
31
+ });
32
+ //#endregion
33
+ export { slack_default as default };
@@ -0,0 +1,2 @@
1
+ import { n as isSlackInteractiveRepliesEnabled, t as compileSlackInteractiveReplies } from "./interactive-replies-qAIfuBor.js";
2
+ export { compileSlackInteractiveReplies, isSlackInteractiveRepliesEnabled };
@@ -0,0 +1,173 @@
1
+ import { a as resolveSlackAccount, i as resolveDefaultSlackAccountId } from "./accounts-ClAPP5ry.js";
2
+ import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
3
+ //#region extensions/slack/src/interactive-replies.ts
4
+ const SLACK_BUTTON_MAX_ITEMS = 5;
5
+ const SLACK_SELECT_MAX_ITEMS = 100;
6
+ const SLACK_DIRECTIVE_RE = /\[\[(slack_buttons|slack_select):\s*([^\]]+)\]\]/gi;
7
+ const SLACK_OPTIONS_LINE_RE = /^\s*Options:\s*(.+?)\s*\.?\s*$/i;
8
+ const SLACK_AUTO_SELECT_MAX_ITEMS = 12;
9
+ const SLACK_SIMPLE_OPTION_RE = /^[a-z0-9][a-z0-9 _+/-]{0,31}$/i;
10
+ function parseChoice(raw, options) {
11
+ const trimmed = raw.trim();
12
+ if (!trimmed) return null;
13
+ const delimiter = trimmed.indexOf(":");
14
+ if (delimiter === -1) return {
15
+ label: trimmed,
16
+ value: trimmed
17
+ };
18
+ const label = trimmed.slice(0, delimiter).trim();
19
+ let value = trimmed.slice(delimiter + 1).trim();
20
+ if (!label || !value) return null;
21
+ let style;
22
+ if (options?.allowStyle) {
23
+ const styleDelimiter = value.lastIndexOf(":");
24
+ if (styleDelimiter !== -1) {
25
+ const maybeStyle = normalizeLowercaseStringOrEmpty(value.slice(styleDelimiter + 1));
26
+ if (maybeStyle === "primary" || maybeStyle === "secondary" || maybeStyle === "success" || maybeStyle === "danger") {
27
+ const unstyledValue = value.slice(0, styleDelimiter).trim();
28
+ if (unstyledValue) {
29
+ value = unstyledValue;
30
+ style = maybeStyle;
31
+ }
32
+ }
33
+ }
34
+ }
35
+ return style ? {
36
+ label,
37
+ value,
38
+ style
39
+ } : {
40
+ label,
41
+ value
42
+ };
43
+ }
44
+ function parseChoices(raw, maxItems, options) {
45
+ return raw.split(",").map((entry) => parseChoice(entry, options)).filter((entry) => Boolean(entry)).slice(0, maxItems);
46
+ }
47
+ function buildTextBlock(text) {
48
+ const trimmed = text.trim();
49
+ if (!trimmed) return null;
50
+ return {
51
+ type: "text",
52
+ text: trimmed
53
+ };
54
+ }
55
+ function buildButtonsBlock(raw) {
56
+ const choices = parseChoices(raw, SLACK_BUTTON_MAX_ITEMS, { allowStyle: true });
57
+ if (choices.length === 0) return null;
58
+ return {
59
+ type: "buttons",
60
+ buttons: choices.map((choice) => Object.assign({
61
+ label: choice.label,
62
+ value: choice.value
63
+ }, choice.style ? { style: choice.style } : {}))
64
+ };
65
+ }
66
+ function buildSelectBlock(raw) {
67
+ const parts = raw.split("|").map((entry) => entry.trim()).filter(Boolean);
68
+ if (parts.length === 0) return null;
69
+ const [first, second] = parts;
70
+ const placeholder = parts.length >= 2 ? first : "Choose an option";
71
+ const choices = parseChoices(parts.length >= 2 ? second : first, SLACK_SELECT_MAX_ITEMS);
72
+ if (choices.length === 0) return null;
73
+ return {
74
+ type: "select",
75
+ placeholder,
76
+ options: choices
77
+ };
78
+ }
79
+ function hasSlackBlocks(payload) {
80
+ const blocks = (payload.channelData?.slack)?.blocks;
81
+ if (typeof blocks === "string") return blocks.trim().length > 0;
82
+ return Array.isArray(blocks) && blocks.length > 0;
83
+ }
84
+ function parseSimpleSlackOptions(raw) {
85
+ const entries = raw.split(",").map((entry) => entry.trim()).filter(Boolean);
86
+ if (entries.length < 2 || entries.length > SLACK_AUTO_SELECT_MAX_ITEMS) return null;
87
+ if (!entries.every((entry) => SLACK_SIMPLE_OPTION_RE.test(entry))) return null;
88
+ if (new Set(entries.map((entry) => normalizeLowercaseStringOrEmpty(entry))).size !== entries.length) return null;
89
+ return entries.map((entry) => ({
90
+ label: entry,
91
+ value: entry
92
+ }));
93
+ }
94
+ function resolveInteractiveRepliesFromCapabilities(capabilities) {
95
+ if (!capabilities) return false;
96
+ if (Array.isArray(capabilities)) return capabilities.some((entry) => normalizeLowercaseStringOrEmpty(String(entry)) === "interactivereplies");
97
+ if (typeof capabilities === "object") return capabilities.interactiveReplies === true;
98
+ return false;
99
+ }
100
+ function isSlackInteractiveRepliesEnabled(params) {
101
+ return resolveInteractiveRepliesFromCapabilities(resolveSlackAccount({
102
+ cfg: params.cfg,
103
+ accountId: params.accountId ?? resolveDefaultSlackAccountId(params.cfg)
104
+ }).config.capabilities);
105
+ }
106
+ function compileSlackInteractiveReplies(payload) {
107
+ const text = payload.text;
108
+ if (!text) return payload;
109
+ const generatedBlocks = [];
110
+ const visibleTextParts = [];
111
+ let cursor = 0;
112
+ let matchedDirective = false;
113
+ let generatedInteractiveBlock = false;
114
+ SLACK_DIRECTIVE_RE.lastIndex = 0;
115
+ for (const match of text.matchAll(SLACK_DIRECTIVE_RE)) {
116
+ matchedDirective = true;
117
+ const matchText = match[0];
118
+ const directiveType = match[1];
119
+ const body = match[2];
120
+ const index = match.index ?? 0;
121
+ const precedingText = text.slice(cursor, index);
122
+ visibleTextParts.push(precedingText);
123
+ const section = buildTextBlock(precedingText);
124
+ if (section) generatedBlocks.push(section);
125
+ const block = normalizeLowercaseStringOrEmpty(directiveType) === "slack_buttons" ? buildButtonsBlock(body) : buildSelectBlock(body);
126
+ if (block) {
127
+ generatedInteractiveBlock = true;
128
+ generatedBlocks.push(block);
129
+ }
130
+ cursor = index + matchText.length;
131
+ }
132
+ const trailingText = text.slice(cursor);
133
+ visibleTextParts.push(trailingText);
134
+ const trailingSection = buildTextBlock(trailingText);
135
+ if (trailingSection) generatedBlocks.push(trailingSection);
136
+ const cleanedText = visibleTextParts.join("");
137
+ if (!matchedDirective || !generatedInteractiveBlock) return parseSlackOptionsLine(payload);
138
+ return {
139
+ ...payload,
140
+ text: cleanedText.trim() || void 0,
141
+ interactive: { blocks: [...payload.interactive?.blocks ?? [], ...generatedBlocks] }
142
+ };
143
+ }
144
+ function parseSlackOptionsLine(payload) {
145
+ const text = payload.text;
146
+ if (!text || payload.interactive?.blocks?.length || hasSlackBlocks(payload)) return payload;
147
+ const lines = text.split("\n");
148
+ const lastNonEmptyIndex = [...lines.keys()].toReversed().find((index) => lines[index]?.trim());
149
+ if (lastNonEmptyIndex == null) return payload;
150
+ const match = (lines[lastNonEmptyIndex] ?? "").match(SLACK_OPTIONS_LINE_RE);
151
+ if (!match) return payload;
152
+ const choices = parseSimpleSlackOptions(match[1] ?? "");
153
+ if (!choices) return payload;
154
+ const bodyText = lines.filter((_, index) => index !== lastNonEmptyIndex).join("\n").trim();
155
+ const generatedBlocks = [];
156
+ const bodyBlock = buildTextBlock(bodyText);
157
+ if (bodyBlock) generatedBlocks.push(bodyBlock);
158
+ generatedBlocks.push(choices.length <= SLACK_BUTTON_MAX_ITEMS ? {
159
+ type: "buttons",
160
+ buttons: choices
161
+ } : {
162
+ type: "select",
163
+ placeholder: "Choose an option",
164
+ options: choices
165
+ });
166
+ return {
167
+ ...payload,
168
+ text: bodyText || void 0,
169
+ interactive: { blocks: [...payload.interactive?.blocks ?? [], ...generatedBlocks] }
170
+ };
171
+ }
172
+ //#endregion
173
+ export { isSlackInteractiveRepliesEnabled as n, parseSlackOptionsLine as r, compileSlackInteractiveReplies as t };