@openclaw/slack 2026.8.1-beta.2 → 2026.8.1
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.
- package/dist/account-configured-sUohAxZr.js +33 -0
- package/dist/account-inspect-CN2hBsim.js +87 -0
- package/dist/account-inspect-api.js +1 -1
- package/dist/{accounts-CK4AVI2_.js → accounts-Dm_H77gH.js} +12 -11
- package/dist/{accounts.runtime-Cb7QwWBz.js → accounts.runtime-DRuEK6mL.js} +1 -1
- package/dist/{action-runtime-BkGe7ny_.js → action-runtime-044ldvNL.js} +80 -79
- package/dist/action-runtime.runtime-BL3KzX13.js +2 -0
- package/dist/{actions-BTDXwwE3.js → actions-BI7JkfVm.js} +273 -263
- package/dist/api.js +14 -14
- package/dist/{approval-handler.runtime-CJaNzAq2.js → approval-handler.runtime-DYv0UIZS.js} +53 -174
- package/dist/{channel-D_tovcUL.js → channel-1vIJOzPx.js} +134 -160
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel-type-B9MSdoGN.js → channel-type-DlFSKeIZ.js} +3 -7
- package/dist/{channel.setup-Bch9dYmA.js → channel.setup-ofDi3_Pu.js} +34 -49
- package/dist/{config-schema-xto5jFIx.js → config-schema-BVIMyiDN.js} +42 -19
- package/dist/configured-state.js +34 -0
- package/dist/conversation-binding-route-DFVLUdYF.js +115 -0
- package/dist/{directory-config-CNBz8lJa.js → directory-config-DqfQ42OV.js} +1 -1
- package/dist/directory-contract-api.js +1 -1
- package/dist/{directory-live-CFKUtW9E.js → directory-live-BPaNHjmP.js} +2 -2
- package/dist/{group-policy-c4RP9bjc.js → group-policy-BdwszjYn.js} +625 -773
- package/dist/{message-tool-api-BykQB4AU.js → message-tool-api-CJ0kjcg5.js} +23 -5
- package/dist/message-tool-api.js +1 -1
- package/dist/{monitor-1nF1NtqT.js → monitor-Dq5Cmrvp.js} +3 -3
- package/dist/{outbound-adapter-S81tsswN.js → outbound-adapter-DYaI8ThX.js} +101 -66
- package/dist/{pipeline.runtime-BvYsM5JO.js → pipeline.runtime-Bd22U0ga.js} +494 -474
- package/dist/{policy-TapwbeaT.js → policy-CtQVbde1.js} +2 -1
- package/dist/{probe-HoEg_WxB.js → probe-0usmAb0i.js} +209 -22
- package/dist/{provider-CDNvBXUi.js → provider-CN_8hFv2.js} +296 -178
- package/dist/{relay-source-C9leF11u.js → relay-source-BNGpsdwV.js} +1 -1
- package/dist/{replies-CeOfv82I.js → replies-BSiRQOJ1.js} +48 -27
- package/dist/{resolve-channels-CNPrxaXY.js → resolve-channels-Czheznc8.js} +1 -1
- package/dist/{resolve-users-Dzomuwnr.js → resolve-users-BAOlNimr.js} +1 -1
- package/dist/runtime-api.js +11 -11
- package/dist/{scopes-cYXKkrRD.js → scopes-COSlmhnH.js} +1 -1
- package/dist/security-contract-api.js +1 -1
- package/dist/{send-Nor0iBwY.js → send-DS9ICrBI.js} +88 -100
- package/dist/send-results-eeOu_HYm.js +23 -0
- package/dist/{send.runtime-BmgNe6S9.js → send.runtime-D_Bb6IuH.js} +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{setup-surface-CbX1-Knh.js → setup-surface-BGnd2pSe.js} +6 -6
- package/dist/{shared-zdT5AMp-.js → shared-D5B-5hBg.js} +35 -9
- package/dist/{slash-dispatch.runtime-Bnr9GR1S.js → slash-dispatch.runtime-CilDmI0c.js} +2 -2
- package/node_modules/@slack/bolt/node_modules/@types/node/README.md +1 -1
- package/node_modules/@slack/bolt/node_modules/@types/node/child_process.d.ts +0 -1
- package/node_modules/@slack/bolt/node_modules/@types/node/crypto.d.ts +6 -6
- package/node_modules/@slack/bolt/node_modules/@types/node/dns/promises.d.ts +5 -5
- package/node_modules/@slack/bolt/node_modules/@types/node/dns.d.ts +5 -5
- package/node_modules/@slack/bolt/node_modules/@types/node/fs.d.ts +7 -0
- package/node_modules/@slack/bolt/node_modules/@types/node/http.d.ts +30 -0
- package/node_modules/@slack/bolt/node_modules/@types/node/http2.d.ts +4 -4
- package/node_modules/@slack/bolt/node_modules/@types/node/os.d.ts +30 -30
- package/node_modules/@slack/bolt/node_modules/@types/node/package.json +2 -2
- package/node_modules/@slack/bolt/node_modules/@types/node/perf_hooks.d.ts +2 -1
- package/node_modules/@slack/bolt/node_modules/@types/node/process.d.ts +42 -43
- package/node_modules/@slack/bolt/node_modules/@types/node/quic.d.ts +1049 -84
- package/node_modules/@slack/bolt/node_modules/@types/node/sqlite.d.ts +14 -1
- package/node_modules/@slack/bolt/node_modules/@types/node/stream/iter.d.ts +3 -2
- package/node_modules/@slack/bolt/node_modules/@types/node/test.d.ts +61 -0
- package/node_modules/@slack/bolt/node_modules/@types/node/v8.d.ts +20 -23
- package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/README.md +2 -0
- package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/dist/index.d.ts +20 -0
- package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/dist/index.js +20 -14
- package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/dist/index.js.map +1 -1
- package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/package.json +1 -1
- package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/README.md +2 -0
- package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.d.ts +20 -0
- package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.js +20 -14
- package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.js.map +1 -1
- package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/package.json +1 -1
- package/node_modules/@slack/socket-mode/node_modules/@types/node/README.md +1 -1
- package/node_modules/@slack/socket-mode/node_modules/@types/node/child_process.d.ts +0 -1
- package/node_modules/@slack/socket-mode/node_modules/@types/node/crypto.d.ts +6 -6
- package/node_modules/@slack/socket-mode/node_modules/@types/node/dns/promises.d.ts +5 -5
- package/node_modules/@slack/socket-mode/node_modules/@types/node/dns.d.ts +5 -5
- package/node_modules/@slack/socket-mode/node_modules/@types/node/fs.d.ts +7 -0
- package/node_modules/@slack/socket-mode/node_modules/@types/node/http.d.ts +30 -0
- package/node_modules/@slack/socket-mode/node_modules/@types/node/http2.d.ts +4 -4
- package/node_modules/@slack/socket-mode/node_modules/@types/node/os.d.ts +30 -30
- package/node_modules/@slack/socket-mode/node_modules/@types/node/package.json +2 -2
- package/node_modules/@slack/socket-mode/node_modules/@types/node/perf_hooks.d.ts +2 -1
- package/node_modules/@slack/socket-mode/node_modules/@types/node/process.d.ts +42 -43
- package/node_modules/@slack/socket-mode/node_modules/@types/node/quic.d.ts +1049 -84
- package/node_modules/@slack/socket-mode/node_modules/@types/node/sqlite.d.ts +14 -1
- package/node_modules/@slack/socket-mode/node_modules/@types/node/stream/iter.d.ts +3 -2
- package/node_modules/@slack/socket-mode/node_modules/@types/node/test.d.ts +61 -0
- package/node_modules/@slack/socket-mode/node_modules/@types/node/v8.d.ts +20 -23
- package/node_modules/@slack/web-api/node_modules/@types/node/README.md +1 -1
- package/node_modules/@slack/web-api/node_modules/@types/node/child_process.d.ts +0 -1
- package/node_modules/@slack/web-api/node_modules/@types/node/crypto.d.ts +6 -6
- package/node_modules/@slack/web-api/node_modules/@types/node/dns/promises.d.ts +5 -5
- package/node_modules/@slack/web-api/node_modules/@types/node/dns.d.ts +5 -5
- package/node_modules/@slack/web-api/node_modules/@types/node/fs.d.ts +7 -0
- package/node_modules/@slack/web-api/node_modules/@types/node/http.d.ts +30 -0
- package/node_modules/@slack/web-api/node_modules/@types/node/http2.d.ts +4 -4
- package/node_modules/@slack/web-api/node_modules/@types/node/os.d.ts +30 -30
- package/node_modules/@slack/web-api/node_modules/@types/node/package.json +2 -2
- package/node_modules/@slack/web-api/node_modules/@types/node/perf_hooks.d.ts +2 -1
- package/node_modules/@slack/web-api/node_modules/@types/node/process.d.ts +42 -43
- package/node_modules/@slack/web-api/node_modules/@types/node/quic.d.ts +1049 -84
- package/node_modules/@slack/web-api/node_modules/@types/node/sqlite.d.ts +14 -1
- package/node_modules/@slack/web-api/node_modules/@types/node/stream/iter.d.ts +3 -2
- package/node_modules/@slack/web-api/node_modules/@types/node/test.d.ts +61 -0
- package/node_modules/@slack/web-api/node_modules/@types/node/v8.d.ts +20 -23
- package/node_modules/typebox/build/format/date.d.mts +1 -1
- package/node_modules/typebox/build/format/date.mjs +1 -1
- package/node_modules/typebox/build/format/date_time.d.mts +2 -2
- package/node_modules/typebox/build/format/date_time.mjs +3 -3
- package/node_modules/typebox/build/format/email.d.mts +1 -1
- package/node_modules/typebox/build/format/email.mjs +2 -2
- package/node_modules/typebox/build/format/hostname.mjs +2 -10
- package/node_modules/typebox/build/format/idn_email.d.mts +1 -1
- package/node_modules/typebox/build/format/idn_email.mjs +3 -3
- package/node_modules/typebox/build/format/idn_hostname.d.mts +1 -0
- package/node_modules/typebox/build/format/idn_hostname.mjs +3 -11
- package/node_modules/typebox/build/format/idna/format/bidi.d.mts +3 -0
- package/node_modules/typebox/build/format/idna/format/bidi.mjs +98 -0
- package/node_modules/typebox/build/format/idna/format/puny.d.mts +3 -0
- package/node_modules/typebox/build/format/idna/format/puny.mjs +144 -0
- package/node_modules/typebox/build/format/idna/hostname.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/hostname.mjs +16 -0
- package/node_modules/typebox/build/format/idna/idn-hostname.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/idn-hostname.mjs +23 -0
- package/node_modules/typebox/build/format/idna/index.d.mts +2 -0
- package/node_modules/typebox/build/format/idna/index.mjs +2 -0
- package/node_modules/typebox/build/format/idna/label/ascii.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/label/ascii.mjs +9 -0
- package/node_modules/typebox/build/format/idna/label/puny.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/label/puny.mjs +28 -0
- package/node_modules/typebox/build/format/idna/label/unicode.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/label/unicode.mjs +106 -0
- package/node_modules/typebox/build/format/idna/pattern/pattern.d.mts +30 -0
- package/node_modules/typebox/build/format/idna/pattern/pattern.mjs +70 -0
- package/node_modules/typebox/build/format/ipv4.d.mts +0 -1
- package/node_modules/typebox/build/format/ipv4.mjs +2 -32
- package/node_modules/typebox/build/format/ipv6.mjs +2 -61
- package/node_modules/typebox/build/format/iri.d.mts +2 -2
- package/node_modules/typebox/build/format/iri.mjs +26 -8
- package/node_modules/typebox/build/format/iri_reference.d.mts +2 -2
- package/node_modules/typebox/build/format/iri_reference.mjs +9 -55
- package/node_modules/typebox/build/format/regex.d.mts +1 -2
- package/node_modules/typebox/build/format/regex.mjs +2 -6
- package/node_modules/typebox/build/format/time.d.mts +2 -2
- package/node_modules/typebox/build/format/time.mjs +19 -14
- package/node_modules/typebox/build/format/uri.d.mts +1 -1
- package/node_modules/typebox/build/format/uri.mjs +3 -130
- package/node_modules/typebox/build/format/uri_reference.d.mts +1 -1
- package/node_modules/typebox/build/format/uri_reference.mjs +2 -3
- package/node_modules/typebox/build/format/uri_template.d.mts +2 -3
- package/node_modules/typebox/build/format/uri_template.mjs +4 -5
- package/node_modules/typebox/build/format/url.d.mts +3 -3
- package/node_modules/typebox/build/format/url.mjs +4 -5
- package/node_modules/typebox/build/guard/emit.d.mts +3 -1
- package/node_modules/typebox/build/guard/emit.mjs +12 -5
- package/node_modules/typebox/build/guard/guard.d.mts +8 -2
- package/node_modules/typebox/build/guard/guard.mjs +25 -4
- package/node_modules/typebox/build/guard/string.d.mts +2 -2
- package/node_modules/typebox/build/guard/string.mjs +7 -7
- package/node_modules/typebox/build/schema/engine/_context.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/_functions.mjs +1 -2
- package/node_modules/typebox/build/schema/engine/_regexp.d.mts +2 -0
- package/node_modules/typebox/build/schema/engine/_regexp.mjs +4 -0
- package/node_modules/typebox/build/schema/engine/_stack.mjs +12 -13
- package/node_modules/typebox/build/schema/engine/additionalItems.mjs +17 -7
- package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +4 -3
- package/node_modules/typebox/build/schema/engine/contains.mjs +18 -6
- package/node_modules/typebox/build/schema/engine/enum.mjs +1 -1
- package/node_modules/typebox/build/schema/engine/items.mjs +26 -6
- package/node_modules/typebox/build/schema/engine/maxContains.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/minContains.mjs +14 -4
- package/node_modules/typebox/build/schema/engine/not.mjs +4 -2
- package/node_modules/typebox/build/schema/engine/oneOf.mjs +7 -6
- package/node_modules/typebox/build/schema/engine/pattern.mjs +3 -2
- package/node_modules/typebox/build/schema/engine/patternProperties.mjs +4 -3
- package/node_modules/typebox/build/schema/engine/ref.mjs +1 -7
- package/node_modules/typebox/build/schema/engine/schema.mjs +13 -4
- package/node_modules/typebox/build/schema/engine/type.mjs +1 -1
- package/node_modules/typebox/build/schema/resolve/resolve.d.mts +4 -1
- package/node_modules/typebox/build/schema/resolve/resolve.mjs +202 -1
- package/node_modules/typebox/build/schema/static/propertyNames.d.mts +5 -0
- package/node_modules/typebox/build/schema/static/propertyNames.mjs +3 -0
- package/node_modules/typebox/build/schema/static/schema.d.mts +3 -0
- package/node_modules/typebox/build/schema/types/index.d.mts +0 -2
- package/node_modules/typebox/build/schema/types/index.mjs +0 -2
- package/node_modules/typebox/build/system/memory/clone.mjs +14 -11
- package/node_modules/typebox/build/system/memory/discard.mjs +6 -5
- package/node_modules/typebox/build/system/settings/settings.d.mts +9 -0
- package/node_modules/typebox/build/system/settings/settings.mjs +2 -0
- package/node_modules/typebox/build/type/engine/call/distribute_arguments.d.mts +6 -1
- package/node_modules/typebox/build/type/engine/call/distribute_arguments.mjs +16 -3
- package/node_modules/typebox/build/type/engine/call/instantiate.mjs +34 -4
- package/node_modules/typebox/build/type/engine/evaluate/broaden.d.mts +5 -5
- package/node_modules/typebox/build/type/engine/evaluate/broaden.mjs +20 -26
- package/node_modules/typebox/build/type/engine/evaluate/compare.d.mts +6 -10
- package/node_modules/typebox/build/type/engine/evaluate/compare.mjs +9 -13
- package/node_modules/typebox/build/type/engine/evaluate/composite.d.mts +7 -4
- package/node_modules/typebox/build/type/engine/evaluate/composite.mjs +12 -19
- package/node_modules/typebox/build/type/engine/evaluate/distribute.d.mts +4 -20
- package/node_modules/typebox/build/type/engine/evaluate/distribute.mjs +8 -20
- package/node_modules/typebox/build/type/engine/evaluate/evaluate.d.mts +4 -4
- package/node_modules/typebox/build/type/engine/evaluate/evaluate.mjs +11 -8
- package/node_modules/typebox/build/type/engine/evaluate/flatten.d.mts +1 -1
- package/node_modules/typebox/build/type/engine/evaluate/flatten.mjs +3 -4
- package/node_modules/typebox/build/type/engine/evaluate/narrow.d.mts +17 -2
- package/node_modules/typebox/build/type/engine/evaluate/narrow.mjs +26 -6
- package/node_modules/typebox/build/type/engine/exclude/operation.mjs +3 -4
- package/node_modules/typebox/build/type/engine/extract/operation.d.mts +1 -1
- package/node_modules/typebox/build/type/engine/extract/operation.mjs +3 -4
- package/node_modules/typebox/build/type/engine/priority/priority.d.mts +2 -2
- package/node_modules/typebox/build/type/engine/priority/priority.mjs +3 -4
- package/node_modules/typebox/build/type/script/mapping.d.mts +32 -29
- package/node_modules/typebox/build/type/script/mapping.mjs +18 -25
- package/node_modules/typebox/build/type/script/parser.d.mts +19 -25
- package/node_modules/typebox/build/type/script/parser.mjs +27 -23
- package/node_modules/typebox/build/value/errors/errors.d.mts +2 -2
- package/node_modules/typebox/build/value/errors/errors.mjs +1 -1
- package/node_modules/typebox/package.json +27 -27
- package/node_modules/typebox/readme.md +79 -82
- package/node_modules/ws/lib/permessage-deflate.js +3 -1
- package/node_modules/ws/package.json +1 -1
- package/openclaw.plugin.json +57 -7
- package/package.json +9 -9
- package/dist/account-configured-BwfXBo_F.js +0 -14
- package/dist/account-inspect-Drw2gAiN.js +0 -89
- package/dist/account-reply-mode-DrUXogvO.js +0 -14
- package/dist/action-runtime.runtime-D9I6uc0Q.js +0 -2
- package/dist/actions.runtime-DLFyUkvg.js +0 -2
- package/dist/block-text-YtiNkqmx.js +0 -79
- package/dist/runtime-api-Cj9nxBNv.js +0 -10
- package/node_modules/p-map/index.d.ts +0 -155
- package/node_modules/p-map/index.js +0 -285
- package/node_modules/p-map/license +0 -9
- package/node_modules/p-map/package.json +0 -57
- package/node_modules/p-map/readme.md +0 -190
- package/node_modules/typebox/build/format/_idna.d.mts +0 -2
- package/node_modules/typebox/build/format/_idna.mjs +0 -246
- package/node_modules/typebox/build/format/_puny.d.mts +0 -1
- package/node_modules/typebox/build/format/_puny.mjs +0 -77
- package/node_modules/typebox/build/schema/resolve/ref.d.mts +0 -3
- package/node_modules/typebox/build/schema/resolve/ref.mjs +0 -146
- package/node_modules/typebox/build/schema/types/contentEncoding.d.mts +0 -9
- package/node_modules/typebox/build/schema/types/contentEncoding.mjs +0 -13
- package/node_modules/typebox/build/schema/types/contentMediaType.d.mts +0 -9
- package/node_modules/typebox/build/schema/types/contentMediaType.mjs +0 -13
- package/dist/{security-audit-DR097212.js → security-audit-B_yKr7MW.js} +1 -1
|
@@ -1,26 +1,43 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as isSlackPluginAccountConfigured } from "./account-configured-sUohAxZr.js";
|
|
2
|
+
import { a as resolveSlackAccount, i as resolveDefaultSlackAccountId, n as listSlackAccountIds, o as resolveSlackAccountAllowFrom, r as mergeSlackAccountConfig } from "./accounts-Dm_H77gH.js";
|
|
2
3
|
import { a as parseSlackTarget, n as formatSlackTarget, t as canonicalizeSlackApiTargetId } from "./target-parsing-BnMD2ZqZ.js";
|
|
3
|
-
import { t as
|
|
4
|
+
import { t as slackContextTargetsMatch } from "./targets-Cx5W_n3W.js";
|
|
4
5
|
import { normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
|
|
5
|
-
import { asOptionalRecord, normalizeLowercaseStringOrEmpty,
|
|
6
|
+
import { asOptionalRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeStringifiedOptionalString, readNonBlankString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
6
7
|
import { normalizeMessageChannel } from "openclaw/plugin-sdk/routing";
|
|
7
8
|
import { FormatCapabilityProfile, chunkTextForOutbound, markdownToIR, renderMarkdownIRChunksWithinLimit, renderMarkdownWithMarkers } from "openclaw/plugin-sdk/text-chunking";
|
|
9
|
+
import { isSingleUseReplyToMode } from "openclaw/plugin-sdk/reply-reference";
|
|
8
10
|
import { buildChannelKeyCandidates } from "openclaw/plugin-sdk/channel-targets";
|
|
9
|
-
import { createNativeApprovalChannelRouteGates, doesApprovalRequestSelectChannelAccount, resolveApprovalRequestSessionConversation } from "openclaw/plugin-sdk/approval-native-runtime";
|
|
11
|
+
import { createNativeApprovalChannelRouteGates, doesApprovalRequestSelectChannelAccount, resolveApprovalKind, resolveApprovalRequestSessionConversation } from "openclaw/plugin-sdk/approval-native-runtime";
|
|
10
12
|
import { createChannelApprovalAuth, resolveApprovalApprovers } from "openclaw/plugin-sdk/approval-auth-runtime";
|
|
11
13
|
import { createChannelExecApprovalProfile, isChannelExecApprovalClientEnabledFromConfig, isChannelExecApprovalTargetRecipient, matchesApprovalRequestFilters } from "openclaw/plugin-sdk/approval-client-runtime";
|
|
12
14
|
import { channelRouteTargetsMatchExact, stringifyRouteThreadId } from "openclaw/plugin-sdk/channel-route";
|
|
13
15
|
import { resolveGlobalMap } from "openclaw/plugin-sdk/global-singleton";
|
|
14
|
-
import {
|
|
16
|
+
import { legacyInteractiveReplyToPresentation, normalizeMessagePresentation, renderMessagePresentationChartFallbackText, renderMessagePresentationFallbackText, renderMessagePresentationTableFallbackText, resolveMessagePresentationButtonAction, resolveMessagePresentationOptionAction } from "openclaw/plugin-sdk/interactive-runtime";
|
|
15
17
|
import { parseExecApprovalCommandText } from "openclaw/plugin-sdk/approval-reply-runtime";
|
|
18
|
+
import { resolveAskUserQuestionOptionIndex, resolveAskUserQuestionOptionIndices } from "openclaw/plugin-sdk/reply-payload";
|
|
16
19
|
import { buildApprovalResolutionRef } from "openclaw/plugin-sdk/approval-reference-runtime";
|
|
20
|
+
import { eastAsianWidthType } from "get-east-asian-width";
|
|
17
21
|
import { questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
|
|
18
22
|
import { sliceUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
19
|
-
import { eastAsianWidthType } from "get-east-asian-width";
|
|
20
23
|
import { readResponseTextLimited } from "openclaw/plugin-sdk/provider-http";
|
|
21
|
-
import {
|
|
22
|
-
import { normalizeHyphenSlug, normalizeStringEntries as normalizeStringEntries$1, normalizeStringEntriesLower } from "openclaw/plugin-sdk/string-normalization-runtime";
|
|
24
|
+
import { normalizeHyphenSlug } from "openclaw/plugin-sdk/string-normalization-runtime";
|
|
23
25
|
import { resolveScopeRequireMention, resolveScopeToolsPolicy } from "openclaw/plugin-sdk/channel-policy";
|
|
26
|
+
//#region extensions/slack/src/action-threading.ts
|
|
27
|
+
const SLACK_PRIVATE_ACTION_DELIVERY_RESULT = Symbol("slack.action.delivery-result");
|
|
28
|
+
function resolveSlackAutoThreadId(params) {
|
|
29
|
+
const context = params.toolContext;
|
|
30
|
+
if (!context?.currentChannelId && !context?.currentMessagingTarget) return;
|
|
31
|
+
if (!slackContextTargetsMatch(params.to, context)) return;
|
|
32
|
+
if (!context.currentThreadTs) {
|
|
33
|
+
if (context.sameChannelThreadRequired) throw new Error("Slack thread context is required for same-channel replies from a threaded Slack turn. Set topLevel=true or threadId=null to post at the channel root.");
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (context.replyToMode !== "all" && !isSingleUseReplyToMode(context.replyToMode ?? "off")) return;
|
|
37
|
+
if (isSingleUseReplyToMode(context.replyToMode ?? "off") && context.hasRepliedRef?.value) return;
|
|
38
|
+
return context.currentThreadTs;
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
24
41
|
//#region extensions/slack/src/exec-approvals.ts
|
|
25
42
|
function normalizeSlackUserLikeId(value) {
|
|
26
43
|
const upper = value.toUpperCase();
|
|
@@ -124,11 +141,6 @@ function isSlackWorkspaceInstallation(accountId) {
|
|
|
124
141
|
const DEFAULT_APPROVAL_FORWARDING_MODE = "session";
|
|
125
142
|
const SLACK_DM_CHANNEL_ID_RE = /^D[A-Z0-9]{8,}$/i;
|
|
126
143
|
const SLACK_USER_ID_RE = /^[UW][A-Z0-9]{8,}$/i;
|
|
127
|
-
function resolveSlackApprovalKind(request) {
|
|
128
|
-
const isExec = "command" in request.request;
|
|
129
|
-
if (isExec === ("title" in request.request && "description" in request.request)) throw new Error("Slack approval request payload does not identify exactly one owner");
|
|
130
|
-
return isExec ? "exec" : "plugin";
|
|
131
|
-
}
|
|
132
144
|
function isSlackApprovalTransportEnabled(params) {
|
|
133
145
|
return isSlackPluginAccountConfigured(resolveSlackAccount(params));
|
|
134
146
|
}
|
|
@@ -343,7 +355,7 @@ function isSlackAnyNativeApprovalClientEnabled(params) {
|
|
|
343
355
|
}
|
|
344
356
|
function shouldHandleSlackNativeApprovalRequest(params) {
|
|
345
357
|
if (getSlackInstallationKind(resolveSlackAccount(params).accountId) === "enterprise" && !resolveEnterpriseApprovalTeamId(params.request)) return false;
|
|
346
|
-
if ((params.
|
|
358
|
+
if (resolveApprovalKind(params.request, params.approvalKind) === "plugin") return shouldHandleSlackPluginViaNativeClientConfig(params) || shouldHandleSlackPluginViaForwarding(params);
|
|
347
359
|
const turnSourceChannel = normalizeMessageChannel(params.request.request.turnSourceChannel);
|
|
348
360
|
if (turnSourceChannel && turnSourceChannel !== "slack") return false;
|
|
349
361
|
if (!doesApprovalRequestSelectChannelAccount({
|
|
@@ -426,6 +438,7 @@ const SLACK_PRESENTATION_CAPABILITIES = {
|
|
|
426
438
|
//#endregion
|
|
427
439
|
//#region extensions/slack/src/approval-actions.ts
|
|
428
440
|
const SLACK_APPROVAL_VALUE_PREFIX = "openclaw:approval:v1:";
|
|
441
|
+
const SLACK_APPROVAL_HEADER_BLOCK_ID = "openclaw_approval_header";
|
|
429
442
|
function isApprovalDecision(value) {
|
|
430
443
|
return value === "allow-once" || value === "allow-always" || value === "deny";
|
|
431
444
|
}
|
|
@@ -911,133 +924,487 @@ function renderSlackDataVisualizationMrkdwnFallbackText(value) {
|
|
|
911
924
|
return typeof block.title === "string" && block.title.trim() ? escapeSlackMrkdwn(block.title.trim()) : void 0;
|
|
912
925
|
}
|
|
913
926
|
//#endregion
|
|
914
|
-
//#region extensions/slack/src/
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
function encodeSlackQuestionAction(action) {
|
|
918
|
-
if (!QUESTION_RECORD_ID_PATTERN.test(action.questionId) || !Number.isInteger(action.optionIndex) || action.optionIndex < 0 || action.optionIndex > 3) return;
|
|
919
|
-
const value = `${SLACK_QUESTION_VALUE_PREFIX}${action.questionId}:${action.optionIndex}`;
|
|
920
|
-
return value.length <= 2e3 ? value : void 0;
|
|
927
|
+
//#region extensions/slack/src/format.ts
|
|
928
|
+
function escapeSlackMrkdwnSegment(text) {
|
|
929
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
921
930
|
}
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
optionIndex: Number(match[2])
|
|
928
|
-
} : null;
|
|
931
|
+
const SLACK_ANGLE_TOKEN_RE = /<[^>\n]+>/g;
|
|
932
|
+
function isAllowedSlackAngleToken(token) {
|
|
933
|
+
if (!token.startsWith("<") || !token.endsWith(">")) return false;
|
|
934
|
+
const inner = token.slice(1, -1);
|
|
935
|
+
return inner.startsWith("@") || inner.startsWith("#") || inner.startsWith("!") || inner.startsWith("mailto:") || inner.startsWith("tel:") || inner.startsWith("http://") || inner.startsWith("https://") || inner.startsWith("slack://");
|
|
929
936
|
}
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
return;
|
|
937
|
+
function escapeSlackMrkdwnContent(text) {
|
|
938
|
+
if (!text) return "";
|
|
939
|
+
if (!text.includes("&") && !text.includes("<") && !text.includes(">")) return text;
|
|
940
|
+
SLACK_ANGLE_TOKEN_RE.lastIndex = 0;
|
|
941
|
+
const out = [];
|
|
942
|
+
let lastIndex = 0;
|
|
943
|
+
for (let match = SLACK_ANGLE_TOKEN_RE.exec(text); match; match = SLACK_ANGLE_TOKEN_RE.exec(text)) {
|
|
944
|
+
const matchIndex = match.index ?? 0;
|
|
945
|
+
out.push(escapeSlackMrkdwnSegment(text.slice(lastIndex, matchIndex)));
|
|
946
|
+
const token = match[0] ?? "";
|
|
947
|
+
out.push(isAllowedSlackAngleToken(token) ? token : escapeSlackMrkdwnSegment(token));
|
|
948
|
+
lastIndex = matchIndex + token.length;
|
|
943
949
|
}
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
//#endregion
|
|
947
|
-
//#region extensions/slack/src/reply-action-ids.ts
|
|
948
|
-
const SLACK_REPLY_BUTTON_ACTION_ID = "openclaw:reply_button";
|
|
949
|
-
const SLACK_REPLY_LINK_ACTION_ID = "openclaw:reply_link";
|
|
950
|
-
const SLACK_SESSION_LINK_ACTION_ID = "openclaw:session_link";
|
|
951
|
-
const SLACK_REPLY_SELECT_ACTION_ID = "openclaw:reply_select";
|
|
952
|
-
const SLACK_CALLBACK_BUTTON_ACTION_ID = "openclaw:callback_button";
|
|
953
|
-
const SLACK_CALLBACK_SELECT_ACTION_ID = "openclaw:callback_select";
|
|
954
|
-
const SLACK_APPROVAL_BUTTON_ACTION_ID = "openclaw:approval_button";
|
|
955
|
-
const SLACK_APPROVAL_SELECT_ACTION_ID = "openclaw:approval_select";
|
|
956
|
-
const SLACK_QUESTION_BUTTON_ACTION_ID = "openclaw:question_button";
|
|
957
|
-
const SLACK_QUESTION_FINALIZATION_BLOCKS = Symbol("slackQuestionFinalizationBlocks");
|
|
958
|
-
function isSlackQuestionActionId(actionId) {
|
|
959
|
-
return actionId === "openclaw:question_button" || actionId.startsWith(`openclaw:question_button:`);
|
|
960
|
-
}
|
|
961
|
-
/** Read only question control identities from the blocks actually sent to Slack. */
|
|
962
|
-
function resolveSlackQuestionActionIds(blocks) {
|
|
963
|
-
return (blocks ?? []).flatMap((block) => {
|
|
964
|
-
if (block.type !== "actions") return [];
|
|
965
|
-
return (block.elements ?? []).flatMap(({ action_id }) => action_id && isSlackQuestionActionId(action_id) ? [action_id] : []);
|
|
966
|
-
});
|
|
967
|
-
}
|
|
968
|
-
function isSlackApprovalActionId(actionId) {
|
|
969
|
-
return actionId === "openclaw:approval_button" || actionId === "openclaw:approval_select" || actionId.startsWith(`openclaw:approval_button:`) || actionId.startsWith(`openclaw:approval_select:`);
|
|
970
|
-
}
|
|
971
|
-
function isSlackCallbackActionId(actionId) {
|
|
972
|
-
return actionId === "openclaw:callback_button" || actionId === "openclaw:callback_select" || actionId.startsWith(`openclaw:callback_button:`) || actionId.startsWith(`openclaw:callback_select:`);
|
|
950
|
+
out.push(escapeSlackMrkdwnSegment(text.slice(lastIndex)));
|
|
951
|
+
return out.join("");
|
|
973
952
|
}
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
953
|
+
function escapeSlackMrkdwnText(text) {
|
|
954
|
+
if (!text) return "";
|
|
955
|
+
if (!text.includes("&") && !text.includes("<") && !text.includes(">")) return text;
|
|
956
|
+
return text.split("\n").map((line) => {
|
|
957
|
+
if (line.startsWith("> ")) return `> ${escapeSlackMrkdwnContent(line.slice(2))}`;
|
|
958
|
+
return escapeSlackMrkdwnContent(line);
|
|
959
|
+
}).join("\n");
|
|
981
960
|
}
|
|
982
|
-
function
|
|
983
|
-
|
|
961
|
+
function buildSlackLink(link, text) {
|
|
962
|
+
const href = link.href.trim();
|
|
963
|
+
if (!href) return null;
|
|
964
|
+
const trimmedLabel = text.slice(link.start, link.end).trim();
|
|
965
|
+
const comparableHref = href.startsWith("mailto:") ? href.slice(7) : href;
|
|
966
|
+
if (!(trimmedLabel.length > 0 && trimmedLabel !== href && trimmedLabel !== comparableHref)) return null;
|
|
967
|
+
const safeHref = escapeSlackMrkdwnSegment(href);
|
|
968
|
+
return {
|
|
969
|
+
start: link.start,
|
|
970
|
+
end: link.end,
|
|
971
|
+
open: `<${safeHref}|`,
|
|
972
|
+
close: ">"
|
|
973
|
+
};
|
|
984
974
|
}
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
const
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
const characterBytes = countSlackTextUtf8Bytes(character);
|
|
997
|
-
if (prefixBytes + characterBytes > prefixBudget) break;
|
|
998
|
-
prefix += character;
|
|
999
|
-
prefixBytes += characterBytes;
|
|
975
|
+
const SLACK_MRKDWN_WORD_CHARACTER_RE = /[\p{L}\p{M}\p{N}_]/u;
|
|
976
|
+
const SLACK_MRKDWN_PUNCTUATION_RE = /\p{P}/u;
|
|
977
|
+
const SLACK_MRKDWN_SYMBOL_RE = /\p{S}/u;
|
|
978
|
+
const SLACK_MRKDWN_CJK_SCRIPT_RE = /[\p{Script_Extensions=Han}\p{Script_Extensions=Hiragana}\p{Script_Extensions=Katakana}\p{Script_Extensions=Hangul}]/u;
|
|
979
|
+
const SLACK_MRKDWN_EMOJI_PRESENTATION_RE = /\p{Emoji_Presentation}/u;
|
|
980
|
+
function getCodePointBefore(text, index) {
|
|
981
|
+
if (index <= 0) return "";
|
|
982
|
+
const lastCodeUnit = text.charCodeAt(index - 1);
|
|
983
|
+
if (lastCodeUnit >= 56320 && lastCodeUnit <= 57343 && index > 1) {
|
|
984
|
+
const previousCodeUnit = text.charCodeAt(index - 2);
|
|
985
|
+
if (previousCodeUnit >= 55296 && previousCodeUnit <= 56319) return text.slice(index - 2, index);
|
|
1000
986
|
}
|
|
1001
|
-
return
|
|
1002
|
-
}
|
|
1003
|
-
//#endregion
|
|
1004
|
-
//#region extensions/slack/src/blocks-render.ts
|
|
1005
|
-
const SLACK_BUTTON_URL_MAX = 3e3;
|
|
1006
|
-
function buildSlackReplyButtonActionId(buttonIndex, choiceIndex) {
|
|
1007
|
-
return `${SLACK_REPLY_BUTTON_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
|
|
987
|
+
return text[index - 1] ?? "";
|
|
1008
988
|
}
|
|
1009
|
-
function
|
|
1010
|
-
|
|
989
|
+
function getCodePointAt(text, index) {
|
|
990
|
+
const codePoint = text.codePointAt(index);
|
|
991
|
+
return codePoint === void 0 ? "" : String.fromCodePoint(codePoint);
|
|
1011
992
|
}
|
|
1012
|
-
function
|
|
1013
|
-
|
|
993
|
+
function isSlackCjkPunctuation(character) {
|
|
994
|
+
if (!SLACK_MRKDWN_PUNCTUATION_RE.test(character)) return false;
|
|
995
|
+
if (SLACK_MRKDWN_CJK_SCRIPT_RE.test(character)) return true;
|
|
996
|
+
const codePoint = character.codePointAt(0);
|
|
997
|
+
if (codePoint === void 0) return false;
|
|
998
|
+
const width = eastAsianWidthType(codePoint);
|
|
999
|
+
return width === "fullwidth" || width === "halfwidth" || width === "wide" && !SLACK_MRKDWN_EMOJI_PRESENTATION_RE.test(character);
|
|
1014
1000
|
}
|
|
1015
|
-
function
|
|
1016
|
-
|
|
1001
|
+
function isUnsafeSlackEmphasisBoundary(character) {
|
|
1002
|
+
if (SLACK_MRKDWN_WORD_CHARACTER_RE.test(character)) return true;
|
|
1003
|
+
const codePoint = character.codePointAt(0);
|
|
1004
|
+
if (codePoint === void 0 || codePoint <= 127) return false;
|
|
1005
|
+
return SLACK_MRKDWN_SYMBOL_RE.test(character) || isSlackCjkPunctuation(character);
|
|
1017
1006
|
}
|
|
1018
|
-
function
|
|
1019
|
-
|
|
1007
|
+
function makeSlackEmphasisStylesSafe(ir) {
|
|
1008
|
+
const styles = ir.styles.filter((span) => {
|
|
1009
|
+
if (span.style !== "italic" && span.style !== "bold") return true;
|
|
1010
|
+
return !isUnsafeSlackEmphasisBoundary(getCodePointBefore(ir.text, span.start)) && !isUnsafeSlackEmphasisBoundary(getCodePointAt(ir.text, span.end));
|
|
1011
|
+
});
|
|
1012
|
+
return styles.length === ir.styles.length ? ir : {
|
|
1013
|
+
...ir,
|
|
1014
|
+
styles
|
|
1015
|
+
};
|
|
1020
1016
|
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1017
|
+
const SLACK_FORMAT_PROFILE = FormatCapabilityProfile.define({
|
|
1018
|
+
mechanism: "markdown",
|
|
1019
|
+
constructs: {
|
|
1020
|
+
underline: "strip",
|
|
1021
|
+
spoiler: "fallback",
|
|
1022
|
+
codeLanguage: "fallback",
|
|
1023
|
+
heading: "fallback",
|
|
1024
|
+
bulletList: "fallback",
|
|
1025
|
+
orderedList: "fallback",
|
|
1026
|
+
taskList: "fallback",
|
|
1027
|
+
table: "fallback",
|
|
1028
|
+
image: "fallback"
|
|
1029
|
+
},
|
|
1030
|
+
chunk: {
|
|
1031
|
+
limit: 4e3,
|
|
1032
|
+
unit: "chars",
|
|
1033
|
+
hardCap: 4e4
|
|
1034
|
+
}
|
|
1035
|
+
});
|
|
1036
|
+
const SLACK_ASSISTANT_TRANSCRIPT_PREFIX = "`Assistant:` ";
|
|
1037
|
+
function tokenizeSlackMrkdwn(text) {
|
|
1038
|
+
const tokens = [];
|
|
1039
|
+
for (let index = 0; index < text.length;) {
|
|
1040
|
+
if (text.startsWith("```", index)) {
|
|
1041
|
+
tokens.push("```");
|
|
1042
|
+
index += 3;
|
|
1043
|
+
continue;
|
|
1044
|
+
}
|
|
1045
|
+
const entity = [
|
|
1046
|
+
"&",
|
|
1047
|
+
"<",
|
|
1048
|
+
">"
|
|
1049
|
+
].find((candidate) => text.startsWith(candidate, index));
|
|
1050
|
+
if (entity) {
|
|
1051
|
+
tokens.push(entity);
|
|
1052
|
+
index += entity.length;
|
|
1053
|
+
continue;
|
|
1054
|
+
}
|
|
1055
|
+
if (text[index] === "<") {
|
|
1056
|
+
const end = text.indexOf(">", index + 1);
|
|
1057
|
+
const angleToken = end >= 0 ? text.slice(index, end + 1) : void 0;
|
|
1058
|
+
if (angleToken && !angleToken.includes("\n") && isAllowedSlackAngleToken(angleToken)) {
|
|
1059
|
+
tokens.push(angleToken);
|
|
1060
|
+
index += angleToken.length;
|
|
1061
|
+
continue;
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
const codePoint = text.codePointAt(index);
|
|
1065
|
+
if (codePoint === void 0) break;
|
|
1066
|
+
const character = String.fromCodePoint(codePoint);
|
|
1067
|
+
index += character.length;
|
|
1068
|
+
if (character === "\\" && index < text.length) {
|
|
1069
|
+
const escapedCodePoint = text.codePointAt(index);
|
|
1070
|
+
if (escapedCodePoint !== void 0) {
|
|
1071
|
+
const escapedCharacter = String.fromCodePoint(escapedCodePoint);
|
|
1072
|
+
tokens.push(character + escapedCharacter);
|
|
1073
|
+
index += escapedCharacter.length;
|
|
1074
|
+
continue;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
tokens.push(character);
|
|
1078
|
+
}
|
|
1079
|
+
return tokens;
|
|
1023
1080
|
}
|
|
1024
|
-
function
|
|
1025
|
-
|
|
1081
|
+
function resolveSlackCodeMarkerTransition(active, token) {
|
|
1082
|
+
if (token === "```" && active !== "`") return active === "```" ? void 0 : "```";
|
|
1083
|
+
if (token === "`" && active !== "```") return active === "`" ? void 0 : "`";
|
|
1084
|
+
return null;
|
|
1026
1085
|
}
|
|
1027
|
-
function
|
|
1028
|
-
return
|
|
1086
|
+
function maskSlackExcludedText(text) {
|
|
1087
|
+
return text.split("\n").map((line) => line.trim() ? `x${" ".repeat(Math.max(0, line.length - 1))}` : " ".repeat(line.length)).join("\n");
|
|
1029
1088
|
}
|
|
1030
|
-
function
|
|
1089
|
+
function maskSlackExcludedRanges(projection) {
|
|
1090
|
+
let masked = "";
|
|
1091
|
+
let cursor = 0;
|
|
1092
|
+
for (const range of projection.excludedRanges) {
|
|
1093
|
+
masked += projection.text.slice(cursor, range.start);
|
|
1094
|
+
masked += maskSlackExcludedText(projection.text.slice(range.start, range.end));
|
|
1095
|
+
cursor = range.end;
|
|
1096
|
+
}
|
|
1097
|
+
return masked + projection.text.slice(cursor);
|
|
1098
|
+
}
|
|
1099
|
+
function slackProjectionHasRoleHeader(projection) {
|
|
1100
|
+
return Boolean(markdownToIR(maskSlackExcludedRanges(projection), {
|
|
1101
|
+
assistantTranscriptRoleHeaders: true,
|
|
1102
|
+
autolink: false,
|
|
1103
|
+
blockquotePrefix: "",
|
|
1104
|
+
headingStyle: "none",
|
|
1105
|
+
linkify: false,
|
|
1106
|
+
tableMode: "off"
|
|
1107
|
+
}).annotations?.some((annotation) => annotation.type === "assistant_transcript_role"));
|
|
1108
|
+
}
|
|
1109
|
+
function decodeSlackMrkdwnEntities(text) {
|
|
1110
|
+
return text.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
1111
|
+
}
|
|
1112
|
+
function projectSlackAngleToken(token, dateDisplay) {
|
|
1113
|
+
const inner = token.slice(1, -1);
|
|
1114
|
+
if (inner.startsWith("!date^")) {
|
|
1115
|
+
const fallbackSeparator = inner.indexOf("|");
|
|
1116
|
+
const tokenString = (fallbackSeparator === -1 ? inner : inner.slice(0, fallbackSeparator)).split("^")[2] ?? "";
|
|
1117
|
+
const fallback = fallbackSeparator === -1 ? "" : inner.slice(fallbackSeparator + 1);
|
|
1118
|
+
return decodeSlackMrkdwnEntities(dateDisplay === "fallback" ? fallback || tokenString : tokenString || fallback);
|
|
1119
|
+
}
|
|
1120
|
+
const labelSeparator = inner.indexOf("|");
|
|
1121
|
+
if (labelSeparator >= 0) return decodeSlackMrkdwnEntities(inner.slice(labelSeparator + 1));
|
|
1122
|
+
if (inner.startsWith("@")) return "@";
|
|
1123
|
+
if (inner.startsWith("#")) return "#";
|
|
1124
|
+
if (inner.startsWith("!")) return "!";
|
|
1125
|
+
return decodeSlackMrkdwnEntities(inner);
|
|
1126
|
+
}
|
|
1127
|
+
function appendSlackVisibleProjection(projection, visible, excluded) {
|
|
1128
|
+
if (!visible) return;
|
|
1129
|
+
const start = projection.text.length;
|
|
1130
|
+
projection.text += visible;
|
|
1131
|
+
if (!excluded) return;
|
|
1132
|
+
const previous = projection.excludedRanges.at(-1);
|
|
1133
|
+
if (previous?.end === start) previous.end = projection.text.length;
|
|
1134
|
+
else projection.excludedRanges.push({
|
|
1135
|
+
start,
|
|
1136
|
+
end: projection.text.length
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
function projectSlackMrkdwnVisibleText(text, dateDisplay) {
|
|
1140
|
+
const projection = {
|
|
1141
|
+
text: "",
|
|
1142
|
+
excludedRanges: []
|
|
1143
|
+
};
|
|
1144
|
+
let activeMarker;
|
|
1145
|
+
let lineHasVisibleContent = false;
|
|
1146
|
+
for (const token of tokenizeSlackMrkdwn(text)) {
|
|
1147
|
+
const transition = resolveSlackCodeMarkerTransition(activeMarker, token);
|
|
1148
|
+
if (transition !== null) {
|
|
1149
|
+
activeMarker = transition;
|
|
1150
|
+
continue;
|
|
1151
|
+
}
|
|
1152
|
+
let visible = token;
|
|
1153
|
+
if (isAllowedSlackAngleToken(token)) visible = activeMarker ? token : projectSlackAngleToken(token, dateDisplay);
|
|
1154
|
+
else if (token === "&" || token === "<" || token === ">") visible = decodeSlackMrkdwnEntities(token);
|
|
1155
|
+
else if (!activeMarker && (token === "*" || token === "_" || token === "~")) visible = "";
|
|
1156
|
+
else if (!activeMarker && token === ">" && !lineHasVisibleContent) visible = "";
|
|
1157
|
+
else if (token.startsWith("\\") && token.length > 1) visible = token.slice(1);
|
|
1158
|
+
appendSlackVisibleProjection(projection, visible, activeMarker !== void 0);
|
|
1159
|
+
for (const character of visible) if (character === "\n") lineHasVisibleContent = false;
|
|
1160
|
+
else if (character !== " " && character !== " " && character !== "\r") lineHasVisibleContent = true;
|
|
1161
|
+
}
|
|
1162
|
+
return projection;
|
|
1163
|
+
}
|
|
1164
|
+
function protectSlackAssistantTranscriptRoleHeaders(text) {
|
|
1165
|
+
if (text.startsWith(SLACK_ASSISTANT_TRANSCRIPT_PREFIX)) return text;
|
|
1166
|
+
const tokenProjection = projectSlackMrkdwnVisibleText(text, "token");
|
|
1167
|
+
const fallbackProjection = projectSlackMrkdwnVisibleText(text, "fallback");
|
|
1168
|
+
if (!slackProjectionHasRoleHeader(tokenProjection) && !slackProjectionHasRoleHeader(fallbackProjection)) return text;
|
|
1169
|
+
return `${SLACK_ASSISTANT_TRANSCRIPT_PREFIX}${text}`;
|
|
1170
|
+
}
|
|
1171
|
+
function buildSlackRenderOptions() {
|
|
1172
|
+
return {
|
|
1173
|
+
annotationMarkers: { assistant_transcript_role: {
|
|
1174
|
+
open: "`",
|
|
1175
|
+
close: "`",
|
|
1176
|
+
suppressNestedFormatting: true
|
|
1177
|
+
} },
|
|
1178
|
+
styleMarkers: {
|
|
1179
|
+
bold: {
|
|
1180
|
+
open: "*",
|
|
1181
|
+
close: "*"
|
|
1182
|
+
},
|
|
1183
|
+
italic: {
|
|
1184
|
+
open: "_",
|
|
1185
|
+
close: "_"
|
|
1186
|
+
},
|
|
1187
|
+
strikethrough: {
|
|
1188
|
+
open: "~",
|
|
1189
|
+
close: "~"
|
|
1190
|
+
},
|
|
1191
|
+
code: {
|
|
1192
|
+
open: "`",
|
|
1193
|
+
close: "`"
|
|
1194
|
+
},
|
|
1195
|
+
code_block: {
|
|
1196
|
+
open: "```\n",
|
|
1197
|
+
close: "```"
|
|
1198
|
+
}
|
|
1199
|
+
},
|
|
1200
|
+
escapeText: escapeSlackMrkdwnText,
|
|
1201
|
+
buildLink: buildSlackLink
|
|
1202
|
+
};
|
|
1203
|
+
}
|
|
1204
|
+
function normalizeSlackOutboundText(markdown, options = {}) {
|
|
1205
|
+
return protectSlackAssistantTranscriptRoleHeaders(renderMarkdownWithMarkers(makeSlackEmphasisStylesSafe(markdownToIR(markdown ?? "", {
|
|
1206
|
+
assistantTranscriptRoleHeaders: true,
|
|
1207
|
+
linkify: false,
|
|
1208
|
+
autolink: false,
|
|
1209
|
+
headingStyle: "rich",
|
|
1210
|
+
blockquotePrefix: "> ",
|
|
1211
|
+
tableMode: options.tableMode
|
|
1212
|
+
})), buildSlackRenderOptions(), SLACK_FORMAT_PROFILE));
|
|
1213
|
+
}
|
|
1214
|
+
/** Chunk already-rendered Slack mrkdwn without splitting entities or code markers. */
|
|
1215
|
+
function chunkSlackMrkdwnText(text, limit) {
|
|
1216
|
+
if (text.length <= limit) return [text];
|
|
1217
|
+
if (!(text.includes("`") || text.includes("&") || text.includes("<") || text.includes(">") || (text.match(/<[^>\n]+>/gu)?.some(isAllowedSlackAngleToken) ?? false) || /\\[\s\S]/u.test(text))) return chunkTextForOutbound(text, limit, { preserveWhitespace: true });
|
|
1218
|
+
const chunks = [];
|
|
1219
|
+
let activeMarker;
|
|
1220
|
+
let content = "";
|
|
1221
|
+
const wrapper = (marker) => marker && limit > marker.length * 2 ? marker : void 0;
|
|
1222
|
+
const capacity = (marker) => limit - (wrapper(marker)?.length ?? 0);
|
|
1223
|
+
const flush = () => {
|
|
1224
|
+
const marker = wrapper(activeMarker);
|
|
1225
|
+
if (content && content !== marker) chunks.push(marker ? `${content}${marker}` : content);
|
|
1226
|
+
content = "";
|
|
1227
|
+
};
|
|
1228
|
+
for (const token of tokenizeSlackMrkdwn(text)) {
|
|
1229
|
+
const transition = resolveSlackCodeMarkerTransition(activeMarker, token);
|
|
1230
|
+
const nextMarker = transition === null ? activeMarker : transition;
|
|
1231
|
+
const sourceMarker = token === "`" || token === "```" ? token : void 0;
|
|
1232
|
+
if (transition !== null && sourceMarker && !wrapper(sourceMarker)) {
|
|
1233
|
+
activeMarker = nextMarker;
|
|
1234
|
+
continue;
|
|
1235
|
+
}
|
|
1236
|
+
if (content && content.length + token.length > capacity(nextMarker)) flush();
|
|
1237
|
+
activeMarker = nextMarker;
|
|
1238
|
+
if (!content && transition === void 0) continue;
|
|
1239
|
+
content ||= transition === null ? wrapper(activeMarker) ?? "" : "";
|
|
1240
|
+
const contentLimit = capacity(activeMarker) - (wrapper(activeMarker)?.length ?? 0);
|
|
1241
|
+
if (token.length > contentLimit) {
|
|
1242
|
+
flush();
|
|
1243
|
+
const marker = wrapper(activeMarker);
|
|
1244
|
+
if (activeMarker && isAllowedSlackAngleToken(token)) {
|
|
1245
|
+
if (marker) chunks.push(...chunkTextForOutbound(token, Math.max(1, Math.floor(contentLimit)), { preserveWhitespace: true }).map((fragment) => `${marker}${fragment}${marker}`));
|
|
1246
|
+
else chunks.push(...chunkTextForOutbound(escapeSlackMrkdwnSegment(token), Math.max(1, Math.floor(limit)), { preserveWhitespace: true }));
|
|
1247
|
+
continue;
|
|
1248
|
+
}
|
|
1249
|
+
chunks.push(...token.length <= limit ? [token] : chunkTextForOutbound(token, limit));
|
|
1250
|
+
continue;
|
|
1251
|
+
}
|
|
1252
|
+
content += token;
|
|
1253
|
+
}
|
|
1254
|
+
flush();
|
|
1255
|
+
return chunks;
|
|
1256
|
+
}
|
|
1257
|
+
function markdownToSlackMrkdwnChunks(markdown, limit, options = {}) {
|
|
1258
|
+
const ir = makeSlackEmphasisStylesSafe(markdownToIR(markdown ?? "", {
|
|
1259
|
+
assistantTranscriptRoleHeaders: true,
|
|
1260
|
+
linkify: false,
|
|
1261
|
+
autolink: false,
|
|
1262
|
+
headingStyle: "rich",
|
|
1263
|
+
blockquotePrefix: "> ",
|
|
1264
|
+
tableMode: options.tableMode
|
|
1265
|
+
}));
|
|
1266
|
+
const renderOptions = buildSlackRenderOptions();
|
|
1267
|
+
return renderMarkdownIRChunksWithinLimit({
|
|
1268
|
+
ir,
|
|
1269
|
+
limit,
|
|
1270
|
+
renderChunk: (chunk) => protectSlackAssistantTranscriptRoleHeaders(renderMarkdownWithMarkers(chunk, renderOptions, SLACK_FORMAT_PROFILE)),
|
|
1271
|
+
measureRendered: (rendered) => rendered.length
|
|
1272
|
+
}).map(({ rendered }) => rendered);
|
|
1273
|
+
}
|
|
1274
|
+
//#endregion
|
|
1275
|
+
//#region extensions/slack/src/question-actions.ts
|
|
1276
|
+
const SLACK_QUESTION_VALUE_PREFIX = "slq1:";
|
|
1277
|
+
const QUESTION_RECORD_ID_PATTERN = /^ask_[a-f0-9]{32}$/u;
|
|
1278
|
+
function encodeSlackQuestionAction(action) {
|
|
1279
|
+
if (!QUESTION_RECORD_ID_PATTERN.test(action.questionId) || !Number.isInteger(action.optionIndex) || action.optionIndex < 0 || action.optionIndex > 3) return;
|
|
1280
|
+
const value = `${SLACK_QUESTION_VALUE_PREFIX}${action.questionId}:${action.optionIndex}`;
|
|
1281
|
+
return value.length <= 2e3 ? value : void 0;
|
|
1282
|
+
}
|
|
1283
|
+
function decodeSlackQuestionAction(value) {
|
|
1284
|
+
if (typeof value !== "string" || value.length > 2e3) return null;
|
|
1285
|
+
const match = /^slq1:(ask_[a-f0-9]{32}):([0-3])$/u.exec(value);
|
|
1286
|
+
return match?.[1] && match[2] ? {
|
|
1287
|
+
questionId: match[1],
|
|
1288
|
+
optionIndex: Number(match[2])
|
|
1289
|
+
} : null;
|
|
1290
|
+
}
|
|
1291
|
+
async function resolveSlackQuestionAction(params) {
|
|
1292
|
+
let result;
|
|
1293
|
+
try {
|
|
1294
|
+
result = await (params.resolveQuestion ?? questionGatewayRuntime.resolveOption)({
|
|
1295
|
+
cfg: params.cfg,
|
|
1296
|
+
questionId: params.action.questionId,
|
|
1297
|
+
optionIndex: params.action.optionIndex,
|
|
1298
|
+
senderId: params.userId,
|
|
1299
|
+
clientDisplayName: `Slack question (${params.accountId})`
|
|
1300
|
+
});
|
|
1301
|
+
} catch {
|
|
1302
|
+
await params.respond("Could not submit this answer.").catch(() => {});
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
await params.respond(result.status === "answered" ? "Answer submitted." : "This question was already answered.").catch(() => {});
|
|
1306
|
+
}
|
|
1307
|
+
//#endregion
|
|
1308
|
+
//#region extensions/slack/src/reply-action-ids.ts
|
|
1309
|
+
const SLACK_REPLY_BUTTON_ACTION_ID = "openclaw:reply_button";
|
|
1310
|
+
const SLACK_REPLY_LINK_ACTION_ID = "openclaw:reply_link";
|
|
1311
|
+
const SLACK_SESSION_LINK_ACTION_ID = "openclaw:session_link";
|
|
1312
|
+
const SLACK_REPLY_SELECT_ACTION_ID = "openclaw:reply_select";
|
|
1313
|
+
const SLACK_CALLBACK_BUTTON_ACTION_ID = "openclaw:callback_button";
|
|
1314
|
+
const SLACK_CALLBACK_SELECT_ACTION_ID = "openclaw:callback_select";
|
|
1315
|
+
const SLACK_APPROVAL_BUTTON_ACTION_ID = "openclaw:approval_button";
|
|
1316
|
+
const SLACK_APPROVAL_SELECT_ACTION_ID = "openclaw:approval_select";
|
|
1317
|
+
const SLACK_QUESTION_BUTTON_ACTION_ID = "openclaw:question_button";
|
|
1318
|
+
const SLACK_QUESTION_FINALIZATION_BLOCKS = Symbol("slackQuestionFinalizationBlocks");
|
|
1319
|
+
function isSlackQuestionActionId(actionId) {
|
|
1320
|
+
return actionId === "openclaw:question_button" || actionId.startsWith(`openclaw:question_button:`);
|
|
1321
|
+
}
|
|
1322
|
+
/** Read only question control identities from the blocks actually sent to Slack. */
|
|
1323
|
+
function resolveSlackQuestionActionIds(blocks) {
|
|
1324
|
+
return (blocks ?? []).flatMap((block) => {
|
|
1325
|
+
if (block.type !== "actions") return [];
|
|
1326
|
+
return (block.elements ?? []).flatMap(({ action_id }) => action_id && isSlackQuestionActionId(action_id) ? [action_id] : []);
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1329
|
+
function isSlackApprovalActionId(actionId) {
|
|
1330
|
+
return actionId === "openclaw:approval_button" || actionId === "openclaw:approval_select" || actionId.startsWith(`openclaw:approval_button:`) || actionId.startsWith(`openclaw:approval_select:`);
|
|
1331
|
+
}
|
|
1332
|
+
function isSlackCallbackActionId(actionId) {
|
|
1333
|
+
return actionId === "openclaw:callback_button" || actionId === "openclaw:callback_select" || actionId.startsWith(`openclaw:callback_button:`) || actionId.startsWith(`openclaw:callback_select:`);
|
|
1334
|
+
}
|
|
1335
|
+
//#endregion
|
|
1336
|
+
//#region extensions/slack/src/truncate.ts
|
|
1337
|
+
function truncateSlackText(value, max) {
|
|
1338
|
+
const trimmed = value.trim();
|
|
1339
|
+
if (trimmed.length <= max) return trimmed;
|
|
1340
|
+
if (max <= 1) return sliceUtf16Safe(trimmed, 0, max);
|
|
1341
|
+
return `${sliceUtf16Safe(trimmed, 0, max - 1)}…`;
|
|
1342
|
+
}
|
|
1343
|
+
function countSlackTextUtf8Bytes(value) {
|
|
1344
|
+
return Buffer.byteLength(value, "utf8");
|
|
1345
|
+
}
|
|
1346
|
+
/** Truncate Slack text without splitting a code point or exceeding a UTF-8 byte limit. */
|
|
1347
|
+
function truncateSlackTextByUtf8Bytes(value, maxBytes) {
|
|
1348
|
+
const trimmed = value.trim();
|
|
1349
|
+
if (maxBytes <= 0) return "";
|
|
1350
|
+
if (countSlackTextUtf8Bytes(trimmed) <= maxBytes) return trimmed;
|
|
1351
|
+
const suffix = "…";
|
|
1352
|
+
const suffixBytes = countSlackTextUtf8Bytes(suffix);
|
|
1353
|
+
const prefixBudget = maxBytes >= suffixBytes ? maxBytes - suffixBytes : maxBytes;
|
|
1354
|
+
let prefix = "";
|
|
1355
|
+
let prefixBytes = 0;
|
|
1356
|
+
for (const character of trimmed) {
|
|
1357
|
+
const characterBytes = countSlackTextUtf8Bytes(character);
|
|
1358
|
+
if (prefixBytes + characterBytes > prefixBudget) break;
|
|
1359
|
+
prefix += character;
|
|
1360
|
+
prefixBytes += characterBytes;
|
|
1361
|
+
}
|
|
1362
|
+
return maxBytes >= suffixBytes ? `${prefix}${suffix}` : prefix;
|
|
1363
|
+
}
|
|
1364
|
+
//#endregion
|
|
1365
|
+
//#region extensions/slack/src/blocks-render.ts
|
|
1366
|
+
const SLACK_BUTTON_URL_MAX = 3e3;
|
|
1367
|
+
function buildSlackReplyButtonActionId(buttonIndex, choiceIndex) {
|
|
1368
|
+
return `${SLACK_REPLY_BUTTON_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
|
|
1369
|
+
}
|
|
1370
|
+
function buildSlackReplyLinkActionId(buttonIndex, choiceIndex) {
|
|
1371
|
+
return `${SLACK_REPLY_LINK_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
|
|
1372
|
+
}
|
|
1373
|
+
function buildSlackReplySelectActionId(selectIndex) {
|
|
1374
|
+
return `${SLACK_REPLY_SELECT_ACTION_ID}:${String(selectIndex)}`;
|
|
1375
|
+
}
|
|
1376
|
+
function buildSlackApprovalButtonActionId(buttonIndex, choiceIndex) {
|
|
1377
|
+
return `${SLACK_APPROVAL_BUTTON_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
|
|
1378
|
+
}
|
|
1379
|
+
function buildSlackApprovalSelectActionId(selectIndex) {
|
|
1380
|
+
return `${SLACK_APPROVAL_SELECT_ACTION_ID}:${String(selectIndex)}`;
|
|
1381
|
+
}
|
|
1382
|
+
function buildSlackCallbackButtonActionId(buttonIndex, choiceIndex) {
|
|
1383
|
+
return `${SLACK_CALLBACK_BUTTON_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
|
|
1384
|
+
}
|
|
1385
|
+
function buildSlackCallbackSelectActionId(selectIndex) {
|
|
1386
|
+
return `${SLACK_CALLBACK_SELECT_ACTION_ID}:${String(selectIndex)}`;
|
|
1387
|
+
}
|
|
1388
|
+
function buildSlackQuestionButtonActionId(buttonIndex, choiceIndex) {
|
|
1389
|
+
return `${SLACK_QUESTION_BUTTON_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
|
|
1390
|
+
}
|
|
1391
|
+
function resolveSlackButtonStyle(style) {
|
|
1031
1392
|
if (style === "primary" || style === "danger") return style;
|
|
1032
1393
|
if (style === "success") return "primary";
|
|
1033
1394
|
}
|
|
1034
|
-
function resolveSlackActionTarget(action,
|
|
1395
|
+
function resolveSlackActionTarget(action, questionOptionIndices) {
|
|
1035
1396
|
if (!action) return;
|
|
1036
1397
|
if (action.type === "approval") return {
|
|
1037
1398
|
kind: "approval",
|
|
1038
1399
|
value: encodeSlackApprovalAction(action)
|
|
1039
1400
|
};
|
|
1040
1401
|
if (action.type === "question") {
|
|
1402
|
+
if ("intent" in action) return;
|
|
1403
|
+
const optionIndex = resolveAskUserQuestionOptionIndex({
|
|
1404
|
+
questionOptionIndices,
|
|
1405
|
+
questionId: action.questionId,
|
|
1406
|
+
optionValue: action.optionValue
|
|
1407
|
+
});
|
|
1041
1408
|
const value = optionIndex === void 0 ? void 0 : encodeSlackQuestionAction({
|
|
1042
1409
|
questionId: action.questionId,
|
|
1043
1410
|
optionIndex
|
|
@@ -1067,10 +1434,10 @@ function resolveSlackActionTarget(action, optionIndex) {
|
|
|
1067
1434
|
value: command
|
|
1068
1435
|
} : void 0;
|
|
1069
1436
|
}
|
|
1070
|
-
function resolveSlackButtonTarget(button,
|
|
1437
|
+
function resolveSlackButtonTarget(button, questionOptionIndices) {
|
|
1071
1438
|
if (button.action !== void 0) {
|
|
1072
1439
|
const action = resolveMessagePresentationButtonAction(button);
|
|
1073
|
-
return action ? resolveSlackActionTarget(action,
|
|
1440
|
+
return action ? resolveSlackActionTarget(action, questionOptionIndices) : void 0;
|
|
1074
1441
|
}
|
|
1075
1442
|
const legacyUrl = normalizeOptionalString(button.url ?? button.webApp?.url ?? button.web_app?.url);
|
|
1076
1443
|
if (legacyUrl && isWithinSlackLimit(legacyUrl, SLACK_BUTTON_URL_MAX)) return {
|
|
@@ -1087,6 +1454,10 @@ function resolveSlackButtonTarget(button, optionIndex) {
|
|
|
1087
1454
|
url: legacyUrl
|
|
1088
1455
|
} : void 0;
|
|
1089
1456
|
}
|
|
1457
|
+
function isSlackTextFallbackButton(button) {
|
|
1458
|
+
const action = resolveMessagePresentationButtonAction(button);
|
|
1459
|
+
return action?.type === "question" && "intent" in action && action.intent === "custom-input";
|
|
1460
|
+
}
|
|
1090
1461
|
function resolveSlackOptionTarget(option) {
|
|
1091
1462
|
if (option.action !== void 0) {
|
|
1092
1463
|
const action = resolveMessagePresentationOptionAction(option);
|
|
@@ -1127,91 +1498,18 @@ function resolveSlackBlockOffsets(blocks) {
|
|
|
1127
1498
|
buttonIndexOffset = Math.max(buttonIndexOffset, readSlackOpenClawBlockIndex(blockId, "openclaw_reply_buttons_") ?? 0);
|
|
1128
1499
|
selectIndexOffset = Math.max(selectIndexOffset, readSlackOpenClawBlockIndex(blockId, "openclaw_reply_select_") ?? 0);
|
|
1129
1500
|
}
|
|
1130
|
-
return {
|
|
1131
|
-
buttonIndexOffset,
|
|
1132
|
-
dataTableCellCharacterCountOffset,
|
|
1133
|
-
dataVisualizationCountOffset,
|
|
1134
|
-
selectIndexOffset
|
|
1135
|
-
};
|
|
1136
|
-
}
|
|
1137
|
-
/**
|
|
1138
|
-
* @deprecated Use buildSlackPresentationBlocks with MessagePresentation.
|
|
1139
|
-
*/
|
|
1140
|
-
function buildSlackInteractiveBlocks(interactive, options = {}) {
|
|
1141
|
-
return
|
|
1142
|
-
blocks: [],
|
|
1143
|
-
buttonIndex: options.buttonIndexOffset ?? 0,
|
|
1144
|
-
selectIndex: options.selectIndexOffset ?? 0
|
|
1145
|
-
}, (state, block) => {
|
|
1146
|
-
if (block.type === "text") {
|
|
1147
|
-
const trimmed = block.text.trim();
|
|
1148
|
-
if (!trimmed) return state;
|
|
1149
|
-
state.blocks.push({
|
|
1150
|
-
type: "section",
|
|
1151
|
-
text: {
|
|
1152
|
-
type: "mrkdwn",
|
|
1153
|
-
text: truncateSlackText(trimmed, SLACK_SECTION_TEXT_MAX)
|
|
1154
|
-
}
|
|
1155
|
-
});
|
|
1156
|
-
return state;
|
|
1157
|
-
}
|
|
1158
|
-
if (block.type === "buttons") {
|
|
1159
|
-
const elements = block.buttons.flatMap((button, choiceIndex) => {
|
|
1160
|
-
const target = resolveSlackButtonTarget(button, choiceIndex);
|
|
1161
|
-
if (!target || (target.kind === "link" ? !isWithinSlackLimit(target.url, SLACK_BUTTON_URL_MAX) : !isWithinSlackLimit(target.value, 2e3))) return [];
|
|
1162
|
-
const style = resolveSlackButtonStyle(button.style);
|
|
1163
|
-
return [{
|
|
1164
|
-
type: "button",
|
|
1165
|
-
action_id: target.kind === "link" ? buildSlackReplyLinkActionId(state.buttonIndex + 1, choiceIndex) : target.kind === "approval" ? buildSlackApprovalButtonActionId(state.buttonIndex + 1, choiceIndex) : target.kind === "callback" ? buildSlackCallbackButtonActionId(state.buttonIndex + 1, choiceIndex) : target.kind === "question" ? buildSlackQuestionButtonActionId(state.buttonIndex + 1, choiceIndex) : buildSlackReplyButtonActionId(state.buttonIndex + 1, choiceIndex),
|
|
1166
|
-
text: {
|
|
1167
|
-
type: "plain_text",
|
|
1168
|
-
text: truncateSlackText(button.label, 75),
|
|
1169
|
-
emoji: true
|
|
1170
|
-
},
|
|
1171
|
-
...target.kind === "link" ? { url: target.url } : { value: target.value },
|
|
1172
|
-
...style ? { style } : {}
|
|
1173
|
-
}];
|
|
1174
|
-
}).slice(0, 25);
|
|
1175
|
-
if (elements.length === 0) return state;
|
|
1176
|
-
state.blocks.push({
|
|
1177
|
-
type: "actions",
|
|
1178
|
-
block_id: `openclaw_reply_buttons_${++state.buttonIndex}`,
|
|
1179
|
-
elements
|
|
1180
|
-
});
|
|
1181
|
-
return state;
|
|
1182
|
-
}
|
|
1183
|
-
const optionsLocal = block.options.flatMap((option) => {
|
|
1184
|
-
const target = resolveSlackOptionTarget(option);
|
|
1185
|
-
return target ? [{
|
|
1186
|
-
label: option.label,
|
|
1187
|
-
...target
|
|
1188
|
-
}] : [];
|
|
1189
|
-
}).filter(isRenderableSlackOption).slice(0, 100);
|
|
1190
|
-
const optionKinds = new Set(optionsLocal.map((option) => option.kind));
|
|
1191
|
-
if (optionsLocal.length === 0 || optionKinds.size !== 1) return state;
|
|
1192
|
-
state.blocks.push({
|
|
1193
|
-
type: "actions",
|
|
1194
|
-
block_id: `openclaw_reply_select_${++state.selectIndex}`,
|
|
1195
|
-
elements: [{
|
|
1196
|
-
type: "static_select",
|
|
1197
|
-
action_id: optionsLocal[0]?.kind === "approval" ? buildSlackApprovalSelectActionId(state.selectIndex) : optionsLocal[0]?.kind === "callback" ? buildSlackCallbackSelectActionId(state.selectIndex) : buildSlackReplySelectActionId(state.selectIndex),
|
|
1198
|
-
placeholder: {
|
|
1199
|
-
type: "plain_text",
|
|
1200
|
-
text: truncateSlackText(normalizeOptionalString(block.placeholder) ?? "Choose an option", 75),
|
|
1201
|
-
emoji: true
|
|
1202
|
-
},
|
|
1203
|
-
options: optionsLocal.map((option, _choiceIndex) => ({
|
|
1204
|
-
text: {
|
|
1205
|
-
type: "plain_text",
|
|
1206
|
-
text: truncateSlackText(option.label, 75),
|
|
1207
|
-
emoji: true
|
|
1208
|
-
},
|
|
1209
|
-
value: option.value
|
|
1210
|
-
}))
|
|
1211
|
-
}]
|
|
1212
|
-
});
|
|
1213
|
-
return state;
|
|
1214
|
-
}).blocks;
|
|
1501
|
+
return {
|
|
1502
|
+
buttonIndexOffset,
|
|
1503
|
+
dataTableCellCharacterCountOffset,
|
|
1504
|
+
dataVisualizationCountOffset,
|
|
1505
|
+
selectIndexOffset
|
|
1506
|
+
};
|
|
1507
|
+
}
|
|
1508
|
+
/**
|
|
1509
|
+
* @deprecated Use buildSlackPresentationBlocks with MessagePresentation.
|
|
1510
|
+
*/
|
|
1511
|
+
function buildSlackInteractiveBlocks(interactive, options = {}) {
|
|
1512
|
+
return buildSlackPresentationBlocks(interactive ? legacyInteractiveReplyToPresentation(interactive) : void 0, options);
|
|
1215
1513
|
}
|
|
1216
1514
|
/** Render portable presentation blocks as Slack Block Kit blocks. */
|
|
1217
1515
|
function buildSlackPresentationBlocks(presentation, options = {}) {
|
|
@@ -1234,19 +1532,18 @@ function buildSlackPresentationBlocks(presentation, options = {}) {
|
|
|
1234
1532
|
if (block.type === "text" || block.type === "context") {
|
|
1235
1533
|
const text = block.text.trim();
|
|
1236
1534
|
if (!text) continue;
|
|
1237
|
-
|
|
1535
|
+
for (const chunk of chunkSlackMrkdwnText(text, SLACK_SECTION_TEXT_MAX)) blocks.push(block.type === "context" ? {
|
|
1238
1536
|
type: "context",
|
|
1239
1537
|
elements: [{
|
|
1240
1538
|
type: "mrkdwn",
|
|
1241
|
-
text:
|
|
1539
|
+
text: chunk,
|
|
1242
1540
|
verbatim: true
|
|
1243
1541
|
}]
|
|
1244
|
-
}
|
|
1245
|
-
else blocks.push({
|
|
1542
|
+
} : {
|
|
1246
1543
|
type: "section",
|
|
1247
1544
|
text: {
|
|
1248
1545
|
type: "mrkdwn",
|
|
1249
|
-
text:
|
|
1546
|
+
text: chunk
|
|
1250
1547
|
}
|
|
1251
1548
|
});
|
|
1252
1549
|
continue;
|
|
@@ -1256,7 +1553,7 @@ function buildSlackPresentationBlocks(presentation, options = {}) {
|
|
|
1256
1553
|
continue;
|
|
1257
1554
|
}
|
|
1258
1555
|
if (block.type === "buttons") {
|
|
1259
|
-
const rendered = buildSlackPresentationButtonBlock(block, buttonIndex + 1);
|
|
1556
|
+
const rendered = buildSlackPresentationButtonBlock(block, buttonIndex + 1, options.questionOptionIndices);
|
|
1260
1557
|
if (rendered) {
|
|
1261
1558
|
buttonIndex += 1;
|
|
1262
1559
|
blocks.push(rendered);
|
|
@@ -1303,9 +1600,9 @@ function buildSlackPresentationBlocks(presentation, options = {}) {
|
|
|
1303
1600
|
function buildSlackPresentationChartBlock(block) {
|
|
1304
1601
|
return buildSlackDataVisualizationBlock(block);
|
|
1305
1602
|
}
|
|
1306
|
-
function buildSlackPresentationButtonBlock(block, buttonIndex) {
|
|
1603
|
+
function buildSlackPresentationButtonBlock(block, buttonIndex, questionOptionIndices) {
|
|
1307
1604
|
const elements = block.buttons.flatMap((button, choiceIndex) => {
|
|
1308
|
-
const target = resolveSlackButtonTarget(button,
|
|
1605
|
+
const target = resolveSlackButtonTarget(button, questionOptionIndices);
|
|
1309
1606
|
if (!target || (target.kind === "link" ? !isWithinSlackLimit(target.url, SLACK_BUTTON_URL_MAX) : !isWithinSlackLimit(target.value, 2e3))) return [];
|
|
1310
1607
|
const style = resolveSlackButtonStyle(button.style);
|
|
1311
1608
|
return [{
|
|
@@ -1343,16 +1640,16 @@ function canRenderSlackPresentation(presentation, options = {}) {
|
|
|
1343
1640
|
if (!canRenderSlackPresentationTables(presentation, options)) return false;
|
|
1344
1641
|
let dataVisualizationCount = options.dataVisualizationCountOffset ?? 0;
|
|
1345
1642
|
for (const block of presentation.blocks) {
|
|
1346
|
-
if (block.type === "text" || block.type === "context")
|
|
1347
|
-
if (!isWithinSlackLimit(block.text.trim(), 3e3)) return false;
|
|
1348
|
-
continue;
|
|
1349
|
-
}
|
|
1643
|
+
if (block.type === "text" || block.type === "context") continue;
|
|
1350
1644
|
if (block.type === "buttons") {
|
|
1351
|
-
|
|
1645
|
+
let nativeButtonCount = 0;
|
|
1646
|
+
if (!(block.buttons.every((button) => {
|
|
1647
|
+
if (isSlackTextFallbackButton(button)) return true;
|
|
1648
|
+
nativeButtonCount += 1;
|
|
1352
1649
|
if (!isWithinSlackLimit(button.label, 75)) return false;
|
|
1353
|
-
const target = resolveSlackButtonTarget(button,
|
|
1650
|
+
const target = resolveSlackButtonTarget(button, options.questionOptionIndices);
|
|
1354
1651
|
return target ? target.kind === "link" ? isWithinSlackLimit(target.url, SLACK_BUTTON_URL_MAX) : isWithinSlackLimit(target.value, 2e3) : false;
|
|
1355
|
-
}))) return false;
|
|
1652
|
+
}) && nativeButtonCount <= 25)) return false;
|
|
1356
1653
|
continue;
|
|
1357
1654
|
}
|
|
1358
1655
|
if (block.type === "select") {
|
|
@@ -1463,482 +1760,116 @@ function readTextObject(value, options = {}) {
|
|
|
1463
1760
|
function readTextValue(value, options = {}) {
|
|
1464
1761
|
return normalizeOptionalString(value) ?? readTextObject(value, options);
|
|
1465
1762
|
}
|
|
1466
|
-
function
|
|
1763
|
+
function renderSlackRichTextElement(value, renderReference) {
|
|
1764
|
+
const element = asOptionalRecord(value);
|
|
1765
|
+
if (!element) return "";
|
|
1467
1766
|
switch (element.type) {
|
|
1767
|
+
case "rich_text_section":
|
|
1768
|
+
case "rich_text_preformatted":
|
|
1769
|
+
case "rich_text_quote": return renderSlackRichTextElements(element.elements, "", renderReference);
|
|
1770
|
+
case "rich_text_list": return renderSlackRichTextElements(element.elements, "\n", renderReference);
|
|
1468
1771
|
case "text": return typeof element.text === "string" ? escapeSlackMrkdwn(element.text) : "";
|
|
1469
1772
|
case "link": return escapeSlackMrkdwn(normalizeOptionalString(element.text) ?? normalizeOptionalString(element.url) ?? "");
|
|
1470
1773
|
case "user": {
|
|
1471
1774
|
const userId = normalizeOptionalString(element.user_id);
|
|
1472
|
-
return userId ?
|
|
1775
|
+
return userId ? renderReference(`<@${userId}>`) : "";
|
|
1473
1776
|
}
|
|
1474
1777
|
case "channel": {
|
|
1475
1778
|
const channelId = normalizeOptionalString(element.channel_id);
|
|
1476
|
-
return channelId ?
|
|
1779
|
+
return channelId ? renderReference(`<#${channelId}>`) : "";
|
|
1477
1780
|
}
|
|
1478
1781
|
case "usergroup": {
|
|
1479
1782
|
const usergroupId = normalizeOptionalString(element.usergroup_id);
|
|
1480
|
-
return usergroupId ?
|
|
1783
|
+
return usergroupId ? renderReference(`<!subteam^${usergroupId}>`) : "";
|
|
1481
1784
|
}
|
|
1482
1785
|
case "broadcast": {
|
|
1483
1786
|
const range = normalizeOptionalString(element.range);
|
|
1484
|
-
return range ?
|
|
1787
|
+
return range ? renderReference(`<!${range}>`) : "";
|
|
1485
1788
|
}
|
|
1486
1789
|
case "emoji": {
|
|
1487
1790
|
const name = normalizeOptionalString(element.name);
|
|
1488
|
-
return name ? `:${name}:` : "";
|
|
1489
|
-
}
|
|
1490
|
-
case "date": return escapeSlackMrkdwn(normalizeOptionalString(element.fallback) ?? "");
|
|
1491
|
-
default: return "";
|
|
1492
|
-
}
|
|
1493
|
-
}
|
|
1494
|
-
function renderSlackRichTextElement(value) {
|
|
1495
|
-
const element = asOptionalRecord(value);
|
|
1496
|
-
if (!element) return "";
|
|
1497
|
-
switch (element.type) {
|
|
1498
|
-
case "rich_text_section":
|
|
1499
|
-
case "rich_text_preformatted":
|
|
1500
|
-
case "rich_text_quote": return renderSlackRichTextElements(element.elements, "");
|
|
1501
|
-
case "rich_text_list": return renderSlackRichTextElements(element.elements, "\n");
|
|
1502
|
-
default: return renderSlackRichTextLeaf(element);
|
|
1503
|
-
}
|
|
1504
|
-
}
|
|
1505
|
-
function renderSlackRichTextElements(value, separator) {
|
|
1506
|
-
if (!Array.isArray(value)) return "";
|
|
1507
|
-
return value.map(renderSlackRichTextElement).filter(Boolean).join(separator);
|
|
1508
|
-
}
|
|
1509
|
-
function readImageText(block) {
|
|
1510
|
-
const altText = normalizeOptionalString(block.alt_text);
|
|
1511
|
-
return (altText ? escapeSlackMrkdwn(altText) : void 0) ?? readTextObject(block.title);
|
|
1512
|
-
}
|
|
1513
|
-
function readVideoText(block, options = {}) {
|
|
1514
|
-
const altText = normalizeOptionalString(block.alt_text);
|
|
1515
|
-
return readTextObject(block.title, options) ?? (altText ? escapeSlackMrkdwn(altText) : void 0);
|
|
1516
|
-
}
|
|
1517
|
-
function readContextText(block, options = {}) {
|
|
1518
|
-
if (!Array.isArray(block.elements)) return;
|
|
1519
|
-
const parts = block.elements.map((element) => {
|
|
1520
|
-
const record = asOptionalRecord(element);
|
|
1521
|
-
const altText = normalizeOptionalString(record?.alt_text);
|
|
1522
|
-
return readTextObject(record, options) ?? (altText ? escapeSlackMrkdwn(altText) : void 0);
|
|
1523
|
-
}).filter((part) => Boolean(part));
|
|
1524
|
-
return parts.length > 0 ? parts.join(" ") : void 0;
|
|
1525
|
-
}
|
|
1526
|
-
function readControlElementText(value, options = {}) {
|
|
1527
|
-
const element = asOptionalRecord(value);
|
|
1528
|
-
const type = normalizeOptionalString(element?.type);
|
|
1529
|
-
if (type === "button" || type === "workflow_button") return readTextValue(element?.text, options);
|
|
1530
|
-
if (type && SLACK_SELECT_ELEMENT_TYPES.has(type)) return readTextObject(element?.placeholder, options);
|
|
1531
|
-
}
|
|
1532
|
-
function readControlElementsText(values, options = {}) {
|
|
1533
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1534
|
-
const labels = [];
|
|
1535
|
-
for (const value of values) {
|
|
1536
|
-
const candidate = readControlElementText(value, options);
|
|
1537
|
-
if (!candidate || seen.has(candidate)) continue;
|
|
1538
|
-
seen.add(candidate);
|
|
1539
|
-
labels.push(candidate);
|
|
1540
|
-
}
|
|
1541
|
-
return labels.length > 0 ? labels.join("\n") : void 0;
|
|
1542
|
-
}
|
|
1543
|
-
function readSectionText(block, options = {}) {
|
|
1544
|
-
const parts = [readTextObject(block.text, options)];
|
|
1545
|
-
if (Array.isArray(block.fields)) parts.push(...block.fields.map((field) => readTextObject(field, options)));
|
|
1546
|
-
parts.push(readControlElementText(block.accessory, options));
|
|
1547
|
-
const visibleParts = parts.filter((part) => Boolean(part));
|
|
1548
|
-
return visibleParts.length > 0 ? visibleParts.join("\n") : void 0;
|
|
1549
|
-
}
|
|
1550
|
-
function readActionsText(block, options = {}) {
|
|
1551
|
-
return Array.isArray(block.elements) ? readControlElementsText(block.elements, options) : void 0;
|
|
1552
|
-
}
|
|
1553
|
-
/** Read only user-visible text from one Slack block. */
|
|
1554
|
-
function renderSlackBlockFallbackText(raw, options = {}) {
|
|
1555
|
-
const block = asOptionalRecord(raw);
|
|
1556
|
-
if (!block) return;
|
|
1557
|
-
switch (block.type) {
|
|
1558
|
-
case "rich_text": return normalizeOptionalString(renderSlackRichTextElements(block.elements, "\n"));
|
|
1559
|
-
case "header": return readTextObject(block.text, options);
|
|
1560
|
-
case "section": return readSectionText(block, options);
|
|
1561
|
-
case "image": return readImageText(block) ?? "Shared an image";
|
|
1562
|
-
case "video": return readVideoText(block, options) ?? "Shared a video";
|
|
1563
|
-
case "file": return "Shared a file";
|
|
1564
|
-
case "context": return readContextText(block, options);
|
|
1565
|
-
case "actions": return readActionsText(block, options);
|
|
1566
|
-
case "data_visualization": return options.nativeDataFormat === "plain" ? renderSlackDataVisualizationFallbackText(block) : renderSlackDataVisualizationMrkdwnFallbackText(block);
|
|
1567
|
-
case "data_table": return options.nativeDataFormat === "plain" ? renderSlackDataTableFallbackText(block) : renderSlackDataTableMrkdwnFallbackText(block);
|
|
1568
|
-
case "table": return options.nativeDataFormat === "plain" ? renderSlackTableFallbackText(block) : renderSlackTableMrkdwnFallbackText(block);
|
|
1569
|
-
default: return;
|
|
1570
|
-
}
|
|
1571
|
-
}
|
|
1572
|
-
function buildSlackBlocksFallbackText(blocks) {
|
|
1573
|
-
for (const block of blocks) {
|
|
1574
|
-
const text = renderSlackBlockFallbackText(block);
|
|
1575
|
-
if (text) return text;
|
|
1576
|
-
}
|
|
1577
|
-
return "Shared a Block Kit message";
|
|
1578
|
-
}
|
|
1579
|
-
function buildSlackCompleteBlocksFallbackText(blocks) {
|
|
1580
|
-
return blocks.map((block) => renderSlackBlockFallbackText(block)).filter(Boolean).join("\n\n").trim() || buildSlackBlocksFallbackText(blocks);
|
|
1581
|
-
}
|
|
1582
|
-
//#endregion
|
|
1583
|
-
//#region extensions/slack/src/format.ts
|
|
1584
|
-
function escapeSlackMrkdwnSegment(text) {
|
|
1585
|
-
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1586
|
-
}
|
|
1587
|
-
const SLACK_ANGLE_TOKEN_RE = /<[^>\n]+>/g;
|
|
1588
|
-
function isAllowedSlackAngleToken(token) {
|
|
1589
|
-
if (!token.startsWith("<") || !token.endsWith(">")) return false;
|
|
1590
|
-
const inner = token.slice(1, -1);
|
|
1591
|
-
return inner.startsWith("@") || inner.startsWith("#") || inner.startsWith("!") || inner.startsWith("mailto:") || inner.startsWith("tel:") || inner.startsWith("http://") || inner.startsWith("https://") || inner.startsWith("slack://");
|
|
1592
|
-
}
|
|
1593
|
-
function escapeSlackMrkdwnContent(text) {
|
|
1594
|
-
if (!text) return "";
|
|
1595
|
-
if (!text.includes("&") && !text.includes("<") && !text.includes(">")) return text;
|
|
1596
|
-
SLACK_ANGLE_TOKEN_RE.lastIndex = 0;
|
|
1597
|
-
const out = [];
|
|
1598
|
-
let lastIndex = 0;
|
|
1599
|
-
for (let match = SLACK_ANGLE_TOKEN_RE.exec(text); match; match = SLACK_ANGLE_TOKEN_RE.exec(text)) {
|
|
1600
|
-
const matchIndex = match.index ?? 0;
|
|
1601
|
-
out.push(escapeSlackMrkdwnSegment(text.slice(lastIndex, matchIndex)));
|
|
1602
|
-
const token = match[0] ?? "";
|
|
1603
|
-
out.push(isAllowedSlackAngleToken(token) ? token : escapeSlackMrkdwnSegment(token));
|
|
1604
|
-
lastIndex = matchIndex + token.length;
|
|
1605
|
-
}
|
|
1606
|
-
out.push(escapeSlackMrkdwnSegment(text.slice(lastIndex)));
|
|
1607
|
-
return out.join("");
|
|
1608
|
-
}
|
|
1609
|
-
function escapeSlackMrkdwnText(text) {
|
|
1610
|
-
if (!text) return "";
|
|
1611
|
-
if (!text.includes("&") && !text.includes("<") && !text.includes(">")) return text;
|
|
1612
|
-
return text.split("\n").map((line) => {
|
|
1613
|
-
if (line.startsWith("> ")) return `> ${escapeSlackMrkdwnContent(line.slice(2))}`;
|
|
1614
|
-
return escapeSlackMrkdwnContent(line);
|
|
1615
|
-
}).join("\n");
|
|
1616
|
-
}
|
|
1617
|
-
function buildSlackLink(link, text) {
|
|
1618
|
-
const href = link.href.trim();
|
|
1619
|
-
if (!href) return null;
|
|
1620
|
-
const trimmedLabel = text.slice(link.start, link.end).trim();
|
|
1621
|
-
const comparableHref = href.startsWith("mailto:") ? href.slice(7) : href;
|
|
1622
|
-
if (!(trimmedLabel.length > 0 && trimmedLabel !== href && trimmedLabel !== comparableHref)) return null;
|
|
1623
|
-
const safeHref = escapeSlackMrkdwnSegment(href);
|
|
1624
|
-
return {
|
|
1625
|
-
start: link.start,
|
|
1626
|
-
end: link.end,
|
|
1627
|
-
open: `<${safeHref}|`,
|
|
1628
|
-
close: ">"
|
|
1629
|
-
};
|
|
1630
|
-
}
|
|
1631
|
-
const SLACK_MRKDWN_WORD_CHARACTER_RE = /[\p{L}\p{M}\p{N}_]/u;
|
|
1632
|
-
const SLACK_MRKDWN_PUNCTUATION_RE = /\p{P}/u;
|
|
1633
|
-
const SLACK_MRKDWN_SYMBOL_RE = /\p{S}/u;
|
|
1634
|
-
const SLACK_MRKDWN_CJK_SCRIPT_RE = /[\p{Script_Extensions=Han}\p{Script_Extensions=Hiragana}\p{Script_Extensions=Katakana}\p{Script_Extensions=Hangul}]/u;
|
|
1635
|
-
const SLACK_MRKDWN_EMOJI_PRESENTATION_RE = /\p{Emoji_Presentation}/u;
|
|
1636
|
-
function getCodePointBefore(text, index) {
|
|
1637
|
-
if (index <= 0) return "";
|
|
1638
|
-
const lastCodeUnit = text.charCodeAt(index - 1);
|
|
1639
|
-
if (lastCodeUnit >= 56320 && lastCodeUnit <= 57343 && index > 1) {
|
|
1640
|
-
const previousCodeUnit = text.charCodeAt(index - 2);
|
|
1641
|
-
if (previousCodeUnit >= 55296 && previousCodeUnit <= 56319) return text.slice(index - 2, index);
|
|
1642
|
-
}
|
|
1643
|
-
return text[index - 1] ?? "";
|
|
1644
|
-
}
|
|
1645
|
-
function getCodePointAt(text, index) {
|
|
1646
|
-
const codePoint = text.codePointAt(index);
|
|
1647
|
-
return codePoint === void 0 ? "" : String.fromCodePoint(codePoint);
|
|
1648
|
-
}
|
|
1649
|
-
function isSlackCjkPunctuation(character) {
|
|
1650
|
-
if (!SLACK_MRKDWN_PUNCTUATION_RE.test(character)) return false;
|
|
1651
|
-
if (SLACK_MRKDWN_CJK_SCRIPT_RE.test(character)) return true;
|
|
1652
|
-
const codePoint = character.codePointAt(0);
|
|
1653
|
-
if (codePoint === void 0) return false;
|
|
1654
|
-
const width = eastAsianWidthType(codePoint);
|
|
1655
|
-
return width === "fullwidth" || width === "halfwidth" || width === "wide" && !SLACK_MRKDWN_EMOJI_PRESENTATION_RE.test(character);
|
|
1656
|
-
}
|
|
1657
|
-
function isUnsafeSlackEmphasisBoundary(character) {
|
|
1658
|
-
if (SLACK_MRKDWN_WORD_CHARACTER_RE.test(character)) return true;
|
|
1659
|
-
const codePoint = character.codePointAt(0);
|
|
1660
|
-
if (codePoint === void 0 || codePoint <= 127) return false;
|
|
1661
|
-
return SLACK_MRKDWN_SYMBOL_RE.test(character) || isSlackCjkPunctuation(character);
|
|
1662
|
-
}
|
|
1663
|
-
function makeSlackEmphasisStylesSafe(ir) {
|
|
1664
|
-
const styles = ir.styles.filter((span) => {
|
|
1665
|
-
if (span.style !== "italic" && span.style !== "bold") return true;
|
|
1666
|
-
return !isUnsafeSlackEmphasisBoundary(getCodePointBefore(ir.text, span.start)) && !isUnsafeSlackEmphasisBoundary(getCodePointAt(ir.text, span.end));
|
|
1667
|
-
});
|
|
1668
|
-
return styles.length === ir.styles.length ? ir : {
|
|
1669
|
-
...ir,
|
|
1670
|
-
styles
|
|
1671
|
-
};
|
|
1672
|
-
}
|
|
1673
|
-
const SLACK_FORMAT_PROFILE = FormatCapabilityProfile.define({
|
|
1674
|
-
mechanism: "markdown",
|
|
1675
|
-
constructs: {
|
|
1676
|
-
underline: "strip",
|
|
1677
|
-
spoiler: "fallback",
|
|
1678
|
-
codeLanguage: "fallback",
|
|
1679
|
-
heading: "fallback",
|
|
1680
|
-
bulletList: "fallback",
|
|
1681
|
-
orderedList: "fallback",
|
|
1682
|
-
taskList: "fallback",
|
|
1683
|
-
table: "fallback",
|
|
1684
|
-
image: "fallback"
|
|
1685
|
-
},
|
|
1686
|
-
chunk: {
|
|
1687
|
-
limit: 4e3,
|
|
1688
|
-
unit: "chars",
|
|
1689
|
-
hardCap: 4e4
|
|
1690
|
-
}
|
|
1691
|
-
});
|
|
1692
|
-
const SLACK_ASSISTANT_TRANSCRIPT_PREFIX = "`Assistant:` ";
|
|
1693
|
-
function tokenizeSlackMrkdwn(text) {
|
|
1694
|
-
const tokens = [];
|
|
1695
|
-
for (let index = 0; index < text.length;) {
|
|
1696
|
-
if (text.startsWith("```", index)) {
|
|
1697
|
-
tokens.push("```");
|
|
1698
|
-
index += 3;
|
|
1699
|
-
continue;
|
|
1700
|
-
}
|
|
1701
|
-
const entity = [
|
|
1702
|
-
"&",
|
|
1703
|
-
"<",
|
|
1704
|
-
">"
|
|
1705
|
-
].find((candidate) => text.startsWith(candidate, index));
|
|
1706
|
-
if (entity) {
|
|
1707
|
-
tokens.push(entity);
|
|
1708
|
-
index += entity.length;
|
|
1709
|
-
continue;
|
|
1710
|
-
}
|
|
1711
|
-
if (text[index] === "<") {
|
|
1712
|
-
const end = text.indexOf(">", index + 1);
|
|
1713
|
-
const angleToken = end >= 0 ? text.slice(index, end + 1) : void 0;
|
|
1714
|
-
if (angleToken && !angleToken.includes("\n") && isAllowedSlackAngleToken(angleToken)) {
|
|
1715
|
-
tokens.push(angleToken);
|
|
1716
|
-
index += angleToken.length;
|
|
1717
|
-
continue;
|
|
1718
|
-
}
|
|
1719
|
-
}
|
|
1720
|
-
const codePoint = text.codePointAt(index);
|
|
1721
|
-
if (codePoint === void 0) break;
|
|
1722
|
-
const character = String.fromCodePoint(codePoint);
|
|
1723
|
-
index += character.length;
|
|
1724
|
-
if (character === "\\" && index < text.length) {
|
|
1725
|
-
const escapedCodePoint = text.codePointAt(index);
|
|
1726
|
-
if (escapedCodePoint !== void 0) {
|
|
1727
|
-
const escapedCharacter = String.fromCodePoint(escapedCodePoint);
|
|
1728
|
-
tokens.push(character + escapedCharacter);
|
|
1729
|
-
index += escapedCharacter.length;
|
|
1730
|
-
continue;
|
|
1731
|
-
}
|
|
1791
|
+
return name ? `:${name}:` : "";
|
|
1732
1792
|
}
|
|
1733
|
-
|
|
1793
|
+
case "date": return escapeSlackMrkdwn(normalizeOptionalString(element.fallback) ?? "");
|
|
1794
|
+
default: return "";
|
|
1734
1795
|
}
|
|
1735
|
-
return tokens;
|
|
1736
1796
|
}
|
|
1737
|
-
function
|
|
1738
|
-
if (
|
|
1739
|
-
|
|
1740
|
-
return null;
|
|
1797
|
+
function renderSlackRichTextElements(value, separator, renderReference) {
|
|
1798
|
+
if (!Array.isArray(value)) return "";
|
|
1799
|
+
return value.map((element) => renderSlackRichTextElement(element, renderReference)).filter(Boolean).join(separator);
|
|
1741
1800
|
}
|
|
1742
|
-
function
|
|
1743
|
-
|
|
1801
|
+
function readImageText(block) {
|
|
1802
|
+
const altText = normalizeOptionalString(block.alt_text);
|
|
1803
|
+
return (altText ? escapeSlackMrkdwn(altText) : void 0) ?? readTextObject(block.title);
|
|
1744
1804
|
}
|
|
1745
|
-
function
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
for (const range of projection.excludedRanges) {
|
|
1749
|
-
masked += projection.text.slice(cursor, range.start);
|
|
1750
|
-
masked += maskSlackExcludedText(projection.text.slice(range.start, range.end));
|
|
1751
|
-
cursor = range.end;
|
|
1752
|
-
}
|
|
1753
|
-
return masked + projection.text.slice(cursor);
|
|
1805
|
+
function readVideoText(block, options = {}) {
|
|
1806
|
+
const altText = normalizeOptionalString(block.alt_text);
|
|
1807
|
+
return readTextObject(block.title, options) ?? (altText ? escapeSlackMrkdwn(altText) : void 0);
|
|
1754
1808
|
}
|
|
1755
|
-
function
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
}).annotations?.some((annotation) => annotation.type === "assistant_transcript_role"));
|
|
1809
|
+
function readContextText(block, options = {}) {
|
|
1810
|
+
if (!Array.isArray(block.elements)) return;
|
|
1811
|
+
const parts = block.elements.map((element) => {
|
|
1812
|
+
const record = asOptionalRecord(element);
|
|
1813
|
+
const altText = normalizeOptionalString(record?.alt_text);
|
|
1814
|
+
return readTextObject(record, options) ?? (altText ? escapeSlackMrkdwn(altText) : void 0);
|
|
1815
|
+
}).filter((part) => Boolean(part));
|
|
1816
|
+
return parts.length > 0 ? parts.join(" ") : void 0;
|
|
1764
1817
|
}
|
|
1765
|
-
function
|
|
1766
|
-
|
|
1818
|
+
function readControlElementText(value, options = {}) {
|
|
1819
|
+
const element = asOptionalRecord(value);
|
|
1820
|
+
const type = normalizeOptionalString(element?.type);
|
|
1821
|
+
if (type === "button" || type === "workflow_button") return readTextValue(element?.text, options);
|
|
1822
|
+
if (type && SLACK_SELECT_ELEMENT_TYPES.has(type)) return readTextObject(element?.placeholder, options);
|
|
1767
1823
|
}
|
|
1768
|
-
function
|
|
1769
|
-
const
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
const
|
|
1773
|
-
|
|
1774
|
-
|
|
1824
|
+
function readControlElementsText(values, options = {}) {
|
|
1825
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1826
|
+
const labels = [];
|
|
1827
|
+
for (const value of values) {
|
|
1828
|
+
const candidate = readControlElementText(value, options);
|
|
1829
|
+
if (!candidate || seen.has(candidate)) continue;
|
|
1830
|
+
seen.add(candidate);
|
|
1831
|
+
labels.push(candidate);
|
|
1775
1832
|
}
|
|
1776
|
-
|
|
1777
|
-
if (labelSeparator >= 0) return decodeSlackMrkdwnEntities(inner.slice(labelSeparator + 1));
|
|
1778
|
-
if (inner.startsWith("@")) return "@";
|
|
1779
|
-
if (inner.startsWith("#")) return "#";
|
|
1780
|
-
if (inner.startsWith("!")) return "!";
|
|
1781
|
-
return decodeSlackMrkdwnEntities(inner);
|
|
1782
|
-
}
|
|
1783
|
-
function appendSlackVisibleProjection(projection, visible, excluded) {
|
|
1784
|
-
if (!visible) return;
|
|
1785
|
-
const start = projection.text.length;
|
|
1786
|
-
projection.text += visible;
|
|
1787
|
-
if (!excluded) return;
|
|
1788
|
-
const previous = projection.excludedRanges.at(-1);
|
|
1789
|
-
if (previous?.end === start) previous.end = projection.text.length;
|
|
1790
|
-
else projection.excludedRanges.push({
|
|
1791
|
-
start,
|
|
1792
|
-
end: projection.text.length
|
|
1793
|
-
});
|
|
1833
|
+
return labels.length > 0 ? labels.join("\n") : void 0;
|
|
1794
1834
|
}
|
|
1795
|
-
function
|
|
1796
|
-
const
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
let lineHasVisibleContent = false;
|
|
1802
|
-
for (const token of tokenizeSlackMrkdwn(text)) {
|
|
1803
|
-
const transition = resolveSlackCodeMarkerTransition(activeMarker, token);
|
|
1804
|
-
if (transition !== null) {
|
|
1805
|
-
activeMarker = transition;
|
|
1806
|
-
continue;
|
|
1807
|
-
}
|
|
1808
|
-
let visible = token;
|
|
1809
|
-
if (isAllowedSlackAngleToken(token)) visible = activeMarker ? token : projectSlackAngleToken(token, dateDisplay);
|
|
1810
|
-
else if (token === "&" || token === "<" || token === ">") visible = decodeSlackMrkdwnEntities(token);
|
|
1811
|
-
else if (!activeMarker && (token === "*" || token === "_" || token === "~")) visible = "";
|
|
1812
|
-
else if (!activeMarker && token === ">" && !lineHasVisibleContent) visible = "";
|
|
1813
|
-
else if (token.startsWith("\\") && token.length > 1) visible = token.slice(1);
|
|
1814
|
-
appendSlackVisibleProjection(projection, visible, activeMarker !== void 0);
|
|
1815
|
-
for (const character of visible) if (character === "\n") lineHasVisibleContent = false;
|
|
1816
|
-
else if (character !== " " && character !== " " && character !== "\r") lineHasVisibleContent = true;
|
|
1817
|
-
}
|
|
1818
|
-
return projection;
|
|
1835
|
+
function readSectionText(block, options = {}) {
|
|
1836
|
+
const parts = [readTextObject(block.text, options)];
|
|
1837
|
+
if (Array.isArray(block.fields)) parts.push(...block.fields.map((field) => readTextObject(field, options)));
|
|
1838
|
+
parts.push(readControlElementText(block.accessory, options));
|
|
1839
|
+
const visibleParts = parts.filter((part) => Boolean(part));
|
|
1840
|
+
return visibleParts.length > 0 ? visibleParts.join("\n") : void 0;
|
|
1819
1841
|
}
|
|
1820
|
-
function
|
|
1821
|
-
|
|
1822
|
-
const tokenProjection = projectSlackMrkdwnVisibleText(text, "token");
|
|
1823
|
-
const fallbackProjection = projectSlackMrkdwnVisibleText(text, "fallback");
|
|
1824
|
-
if (!slackProjectionHasRoleHeader(tokenProjection) && !slackProjectionHasRoleHeader(fallbackProjection)) return text;
|
|
1825
|
-
return `${SLACK_ASSISTANT_TRANSCRIPT_PREFIX}${text}`;
|
|
1842
|
+
function readActionsText(block, options = {}) {
|
|
1843
|
+
return Array.isArray(block.elements) ? readControlElementsText(block.elements, options) : void 0;
|
|
1826
1844
|
}
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1845
|
+
/** Read only user-visible text from one Slack block. */
|
|
1846
|
+
function renderSlackBlockFallbackText(raw, options = {}) {
|
|
1847
|
+
const block = asOptionalRecord(raw);
|
|
1848
|
+
if (!block) return;
|
|
1849
|
+
switch (block.type) {
|
|
1850
|
+
case "rich_text": return normalizeOptionalString(renderSlackRichTextElements(block.elements, "\n", options.nativeReferenceFormat === "plain" ? (text) => text : escapeSlackMrkdwn));
|
|
1851
|
+
case "header": return readTextObject(block.text, options);
|
|
1852
|
+
case "section": return readSectionText(block, options);
|
|
1853
|
+
case "image": return readImageText(block) ?? "Shared an image";
|
|
1854
|
+
case "video": return readVideoText(block, options) ?? "Shared a video";
|
|
1855
|
+
case "file": return "Shared a file";
|
|
1856
|
+
case "context": return readContextText(block, options);
|
|
1857
|
+
case "actions": return readActionsText(block, options);
|
|
1858
|
+
case "data_visualization": return options.nativeDataFormat === "plain" ? renderSlackDataVisualizationFallbackText(block) : renderSlackDataVisualizationMrkdwnFallbackText(block);
|
|
1859
|
+
case "data_table": return options.nativeDataFormat === "plain" ? renderSlackDataTableFallbackText(block) : renderSlackDataTableMrkdwnFallbackText(block);
|
|
1860
|
+
case "table": return options.nativeDataFormat === "plain" ? renderSlackTableFallbackText(block) : renderSlackTableMrkdwnFallbackText(block);
|
|
1861
|
+
default: return;
|
|
1836
1862
|
}
|
|
1837
|
-
if (chunk) chunks.push(chunk);
|
|
1838
|
-
return chunks;
|
|
1839
|
-
}
|
|
1840
|
-
function buildSlackRenderOptions() {
|
|
1841
|
-
return {
|
|
1842
|
-
annotationMarkers: { assistant_transcript_role: {
|
|
1843
|
-
open: "`",
|
|
1844
|
-
close: "`",
|
|
1845
|
-
suppressNestedFormatting: true
|
|
1846
|
-
} },
|
|
1847
|
-
styleMarkers: {
|
|
1848
|
-
bold: {
|
|
1849
|
-
open: "*",
|
|
1850
|
-
close: "*"
|
|
1851
|
-
},
|
|
1852
|
-
italic: {
|
|
1853
|
-
open: "_",
|
|
1854
|
-
close: "_"
|
|
1855
|
-
},
|
|
1856
|
-
strikethrough: {
|
|
1857
|
-
open: "~",
|
|
1858
|
-
close: "~"
|
|
1859
|
-
},
|
|
1860
|
-
code: {
|
|
1861
|
-
open: "`",
|
|
1862
|
-
close: "`"
|
|
1863
|
-
},
|
|
1864
|
-
code_block: {
|
|
1865
|
-
open: "```\n",
|
|
1866
|
-
close: "```"
|
|
1867
|
-
}
|
|
1868
|
-
},
|
|
1869
|
-
escapeText: escapeSlackMrkdwnText,
|
|
1870
|
-
buildLink: buildSlackLink
|
|
1871
|
-
};
|
|
1872
|
-
}
|
|
1873
|
-
function markdownToSlackMrkdwn(markdown, options = {}) {
|
|
1874
|
-
return renderMarkdownWithMarkers(makeSlackEmphasisStylesSafe(markdownToIR(markdown ?? "", {
|
|
1875
|
-
assistantTranscriptRoleHeaders: true,
|
|
1876
|
-
linkify: false,
|
|
1877
|
-
autolink: false,
|
|
1878
|
-
headingStyle: "rich",
|
|
1879
|
-
blockquotePrefix: "> ",
|
|
1880
|
-
tableMode: options.tableMode
|
|
1881
|
-
})), buildSlackRenderOptions(), SLACK_FORMAT_PROFILE);
|
|
1882
1863
|
}
|
|
1883
|
-
function
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
function chunkSlackMrkdwnText(text, limit) {
|
|
1888
|
-
if (text.length <= limit) return [text];
|
|
1889
|
-
if (!(text.includes("`") || text.includes("&") || text.includes("<") || text.includes(">") || (text.match(/<[^>\n]+>/gu)?.some(isAllowedSlackAngleToken) ?? false) || /\\[\s\S]/u.test(text))) return chunkTextForOutbound(text, limit);
|
|
1890
|
-
const chunks = [];
|
|
1891
|
-
let activeMarker;
|
|
1892
|
-
let content = "";
|
|
1893
|
-
const wrapper = () => activeMarker && limit > activeMarker.length * 2 ? activeMarker : void 0;
|
|
1894
|
-
const capacity = () => limit - (wrapper()?.length ?? 0) * 2;
|
|
1895
|
-
const flush = () => {
|
|
1896
|
-
if (!content) return;
|
|
1897
|
-
const marker = wrapper();
|
|
1898
|
-
chunks.push(marker ? `${marker}${content}${marker}` : content);
|
|
1899
|
-
content = "";
|
|
1900
|
-
};
|
|
1901
|
-
for (const token of tokenizeSlackMrkdwn(text)) {
|
|
1902
|
-
const transition = resolveSlackCodeMarkerTransition(activeMarker, token);
|
|
1903
|
-
if (transition !== null) {
|
|
1904
|
-
flush();
|
|
1905
|
-
activeMarker = transition;
|
|
1906
|
-
continue;
|
|
1907
|
-
}
|
|
1908
|
-
const contentLimit = capacity();
|
|
1909
|
-
if (token.length > contentLimit) {
|
|
1910
|
-
flush();
|
|
1911
|
-
const marker = wrapper();
|
|
1912
|
-
if (activeMarker && isAllowedSlackAngleToken(token)) {
|
|
1913
|
-
if (marker) chunks.push(...hardSliceSlackToken(token, contentLimit).map((fragment) => `${marker}${fragment}${marker}`));
|
|
1914
|
-
else chunks.push(...hardSliceSlackToken(escapeSlackMrkdwnSegment(token), limit));
|
|
1915
|
-
continue;
|
|
1916
|
-
}
|
|
1917
|
-
chunks.push(...token.length <= limit ? [token] : chunkTextForOutbound(token, limit));
|
|
1918
|
-
continue;
|
|
1919
|
-
}
|
|
1920
|
-
if (content && content.length + token.length > contentLimit) flush();
|
|
1921
|
-
content += token;
|
|
1864
|
+
function buildSlackBlocksFallbackText(blocks) {
|
|
1865
|
+
for (const block of blocks) {
|
|
1866
|
+
const text = renderSlackBlockFallbackText(block);
|
|
1867
|
+
if (text) return text;
|
|
1922
1868
|
}
|
|
1923
|
-
|
|
1924
|
-
return chunks;
|
|
1869
|
+
return "Shared a Block Kit message";
|
|
1925
1870
|
}
|
|
1926
|
-
function
|
|
1927
|
-
|
|
1928
|
-
assistantTranscriptRoleHeaders: true,
|
|
1929
|
-
linkify: false,
|
|
1930
|
-
autolink: false,
|
|
1931
|
-
headingStyle: "rich",
|
|
1932
|
-
blockquotePrefix: "> ",
|
|
1933
|
-
tableMode: options.tableMode
|
|
1934
|
-
}));
|
|
1935
|
-
const renderOptions = buildSlackRenderOptions();
|
|
1936
|
-
return renderMarkdownIRChunksWithinLimit({
|
|
1937
|
-
ir,
|
|
1938
|
-
limit,
|
|
1939
|
-
renderChunk: (chunk) => protectSlackAssistantTranscriptRoleHeaders(renderMarkdownWithMarkers(chunk, renderOptions, SLACK_FORMAT_PROFILE)),
|
|
1940
|
-
measureRendered: (rendered) => rendered.length
|
|
1941
|
-
}).map(({ rendered }) => rendered);
|
|
1871
|
+
function buildSlackCompleteBlocksFallbackText(blocks) {
|
|
1872
|
+
return blocks.map((block) => renderSlackBlockFallbackText(block)).filter(Boolean).join("\n\n").trim() || buildSlackBlocksFallbackText(blocks);
|
|
1942
1873
|
}
|
|
1943
1874
|
//#endregion
|
|
1944
1875
|
//#region extensions/slack/src/native-data-blocks.ts
|
|
@@ -2108,7 +2039,10 @@ function resolveSlackReplyDeliveryMessages(params) {
|
|
|
2108
2039
|
...baseText ? { nativeDataFallbackBaseText: baseText } : {}
|
|
2109
2040
|
});
|
|
2110
2041
|
}
|
|
2111
|
-
if (outsideText) messages.push({
|
|
2042
|
+
if (outsideText) messages.push({
|
|
2043
|
+
text: outsideText,
|
|
2044
|
+
authoredTextPlacement: "outside-blocks"
|
|
2045
|
+
});
|
|
2112
2046
|
return messages;
|
|
2113
2047
|
}
|
|
2114
2048
|
function resolveSlackReplyText(payload, text = payload.text) {
|
|
@@ -2247,14 +2181,20 @@ function renderNativePresentation(presentation, options) {
|
|
|
2247
2181
|
const blocks = buildSlackPresentationBlocks(presentation, options);
|
|
2248
2182
|
return blocks.length > 0 ? blocks : void 0;
|
|
2249
2183
|
}
|
|
2250
|
-
function appendPresentationPart(segments, presentation) {
|
|
2184
|
+
function appendPresentationPart(segments, presentation, questionOptionIndices) {
|
|
2251
2185
|
const currentBlocks = readLastBlockSegment(segments);
|
|
2252
|
-
const currentRendered = renderNativePresentation(presentation,
|
|
2186
|
+
const currentRendered = renderNativePresentation(presentation, {
|
|
2187
|
+
...resolvePresentationRenderOptions(segments, "current"),
|
|
2188
|
+
questionOptionIndices
|
|
2189
|
+
});
|
|
2253
2190
|
if (currentRendered && currentBlocks.length + currentRendered.length <= 50) {
|
|
2254
2191
|
appendBlockSegment(segments, currentRendered);
|
|
2255
2192
|
return;
|
|
2256
2193
|
}
|
|
2257
|
-
const freshRendered = renderNativePresentation(presentation,
|
|
2194
|
+
const freshRendered = renderNativePresentation(presentation, {
|
|
2195
|
+
...resolvePresentationRenderOptions(segments, "new-message"),
|
|
2196
|
+
questionOptionIndices
|
|
2197
|
+
});
|
|
2258
2198
|
if (freshRendered) {
|
|
2259
2199
|
appendBlockSegment(segments, freshRendered, true);
|
|
2260
2200
|
return;
|
|
@@ -2264,6 +2204,7 @@ function appendPresentationPart(segments, presentation) {
|
|
|
2264
2204
|
const SLACK_BUTTON_CONTROL_ACTION_IDS = [
|
|
2265
2205
|
SLACK_APPROVAL_BUTTON_ACTION_ID,
|
|
2266
2206
|
SLACK_CALLBACK_BUTTON_ACTION_ID,
|
|
2207
|
+
SLACK_QUESTION_BUTTON_ACTION_ID,
|
|
2267
2208
|
SLACK_REPLY_BUTTON_ACTION_ID,
|
|
2268
2209
|
SLACK_REPLY_LINK_ACTION_ID
|
|
2269
2210
|
];
|
|
@@ -2329,15 +2270,19 @@ function resolveSlackReplyBlockResolution(payload, options = {}) {
|
|
|
2329
2270
|
}
|
|
2330
2271
|
if (compiledChannelBlocks.length > 0) appendBlockSegment(segments, compiledChannelBlocks);
|
|
2331
2272
|
const presentation = normalizeMessagePresentation(payload.presentation);
|
|
2273
|
+
const questionOptionIndices = resolveAskUserQuestionOptionIndices(payload);
|
|
2332
2274
|
const presentationBlockOffset = readAllNativeBlocks(segments).length;
|
|
2333
2275
|
if (presentation?.title) appendPresentationPart(segments, {
|
|
2334
2276
|
title: presentation.title,
|
|
2335
2277
|
blocks: []
|
|
2336
|
-
});
|
|
2337
|
-
for (const block of presentation?.blocks ?? []) appendPresentationPart(segments, { blocks: [block] });
|
|
2278
|
+
}, questionOptionIndices);
|
|
2279
|
+
for (const block of presentation?.blocks ?? []) appendPresentationPart(segments, { blocks: [block] }, questionOptionIndices);
|
|
2338
2280
|
const renderedPresentationBlocks = readAllNativeBlocks(segments).slice(presentationBlockOffset);
|
|
2339
2281
|
appendBlockSegment(segments, subtractMirroredSlackControlRows({
|
|
2340
|
-
interactiveBlocks: buildSlackInteractiveBlocks(payload.interactive,
|
|
2282
|
+
interactiveBlocks: buildSlackInteractiveBlocks(payload.interactive, {
|
|
2283
|
+
...resolveSlackBlockOffsets(readAllNativeBlocks(segments)),
|
|
2284
|
+
questionOptionIndices
|
|
2285
|
+
}),
|
|
2341
2286
|
presentationBlocks: renderedPresentationBlocks
|
|
2342
2287
|
}));
|
|
2343
2288
|
const renderedTextFragments = segments.flatMap((segment) => {
|
|
@@ -2366,111 +2311,18 @@ function assertSlackDetachedTargetAllowed(accountId, teamId) {
|
|
|
2366
2311
|
if (installationKind && installationKind !== "workspace" && !teamId) throw new Error("unsupported_enterprise_slack_delivery: detached Slack operations require team:<team-id>:channel:<channel-id> or team:<team-id>:user:<user-id> until a workspace install is authenticated");
|
|
2367
2312
|
}
|
|
2368
2313
|
//#endregion
|
|
2369
|
-
//#region extensions/slack/src/monitor/
|
|
2370
|
-
|
|
2371
|
-
const
|
|
2372
|
-
const
|
|
2373
|
-
|
|
2374
|
-
const key = raw ?? "";
|
|
2375
|
-
const cached = slackSlugCache.get(key);
|
|
2376
|
-
if (cached !== void 0) return cached;
|
|
2377
|
-
const normalized = normalizeHyphenSlug(raw);
|
|
2378
|
-
slackSlugCache.set(key, normalized);
|
|
2379
|
-
if (slackSlugCache.size > SLACK_SLUG_CACHE_MAX) {
|
|
2380
|
-
const oldest = slackSlugCache.keys().next();
|
|
2381
|
-
if (!oldest.done) slackSlugCache.delete(oldest.value);
|
|
2382
|
-
}
|
|
2383
|
-
return normalized;
|
|
2384
|
-
}
|
|
2385
|
-
function normalizeAllowList(list) {
|
|
2386
|
-
return normalizeStringEntries$1(list);
|
|
2314
|
+
//#region extensions/slack/src/monitor/workspace-routing.ts
|
|
2315
|
+
function resolveSlackEnterpriseMainDmSessionKey(params) {
|
|
2316
|
+
const accountId = encodeURIComponent(params.accountId).toLowerCase();
|
|
2317
|
+
const teamId = encodeURIComponent(params.eventScope.teamId).toLowerCase();
|
|
2318
|
+
return `${params.baseSessionKey}:account:${accountId}:team:${teamId}`;
|
|
2387
2319
|
}
|
|
2388
|
-
function
|
|
2389
|
-
|
|
2320
|
+
function qualifySlackRoutePeerId(params) {
|
|
2321
|
+
if (!params.eventScope) return params.id;
|
|
2322
|
+
return `team:${encodeURIComponent(params.eventScope.teamId)}:${params.kind}:${encodeURIComponent(params.id)}`;
|
|
2390
2323
|
}
|
|
2391
|
-
function
|
|
2392
|
-
|
|
2393
|
-
if (!trimmed || trimmed === "*") return;
|
|
2394
|
-
try {
|
|
2395
|
-
const target = parseSlackTarget(trimmed);
|
|
2396
|
-
if (target?.kind === "user" && target.teamId) return target.id.toLowerCase();
|
|
2397
|
-
} catch {
|
|
2398
|
-
return;
|
|
2399
|
-
}
|
|
2400
|
-
const withoutPrefix = trimmed.replace(/^(slack:|user:)/, "");
|
|
2401
|
-
return SLACK_STABLE_USER_ID_RE.test(withoutPrefix) ? withoutPrefix : void 0;
|
|
2402
|
-
}
|
|
2403
|
-
function resolveSlackAllowListMatch(params) {
|
|
2404
|
-
const compiledAllowList = compileAllowlist(params.allowList);
|
|
2405
|
-
const teamId = normalizeOptionalLowercaseString(params.teamId);
|
|
2406
|
-
const id = normalizeOptionalLowercaseString(params.id);
|
|
2407
|
-
const name = normalizeOptionalLowercaseString(params.name);
|
|
2408
|
-
const slug = normalizeSlackSlug(name);
|
|
2409
|
-
const scopedCandidates = [{
|
|
2410
|
-
value: teamId && id ? `team:${teamId}:user:${id}` : void 0,
|
|
2411
|
-
source: "workspace-id"
|
|
2412
|
-
}];
|
|
2413
|
-
const unscopedCandidates = [
|
|
2414
|
-
{
|
|
2415
|
-
value: id,
|
|
2416
|
-
source: "id"
|
|
2417
|
-
},
|
|
2418
|
-
{
|
|
2419
|
-
value: id ? `slack:${id}` : void 0,
|
|
2420
|
-
source: "prefixed-id"
|
|
2421
|
-
},
|
|
2422
|
-
{
|
|
2423
|
-
value: id ? `user:${id}` : void 0,
|
|
2424
|
-
source: "prefixed-user"
|
|
2425
|
-
},
|
|
2426
|
-
...params.allowNameMatching === true ? [
|
|
2427
|
-
{
|
|
2428
|
-
value: name,
|
|
2429
|
-
source: "name"
|
|
2430
|
-
},
|
|
2431
|
-
{
|
|
2432
|
-
value: name ? `slack:${name}` : void 0,
|
|
2433
|
-
source: "prefixed-name"
|
|
2434
|
-
},
|
|
2435
|
-
{
|
|
2436
|
-
value: slug,
|
|
2437
|
-
source: "slug"
|
|
2438
|
-
}
|
|
2439
|
-
] : []
|
|
2440
|
-
];
|
|
2441
|
-
return resolveCompiledAllowlistMatch({
|
|
2442
|
-
compiledAllowlist: compiledAllowList,
|
|
2443
|
-
candidates: [...scopedCandidates, ...unscopedCandidates]
|
|
2444
|
-
});
|
|
2445
|
-
}
|
|
2446
|
-
function allowListMatches(params) {
|
|
2447
|
-
return resolveSlackAllowListMatch(params).allowed;
|
|
2448
|
-
}
|
|
2449
|
-
function resolveSlackUserAllowed(params) {
|
|
2450
|
-
const allowList = normalizeAllowListLower(params.allowList);
|
|
2451
|
-
if (allowList.length === 0) return true;
|
|
2452
|
-
return allowListMatches({
|
|
2453
|
-
allowList,
|
|
2454
|
-
teamId: params.teamId,
|
|
2455
|
-
id: params.userId,
|
|
2456
|
-
name: params.userName,
|
|
2457
|
-
allowNameMatching: params.allowNameMatching
|
|
2458
|
-
});
|
|
2459
|
-
}
|
|
2460
|
-
function resolveSlackUserAllowListForTeam(params) {
|
|
2461
|
-
const allowList = normalizeAllowListLower(params.allowList);
|
|
2462
|
-
const teamId = normalizeOptionalLowercaseString(params.teamId);
|
|
2463
|
-
return allowList.flatMap((entry) => {
|
|
2464
|
-
if (entry === "*") return [entry];
|
|
2465
|
-
if (!entry.startsWith("team:")) return [entry];
|
|
2466
|
-
try {
|
|
2467
|
-
const target = parseSlackTarget(entry);
|
|
2468
|
-
if (target?.kind === "user" && target.teamId?.toLowerCase() === teamId) return [entry];
|
|
2469
|
-
return params.preserveUnmatchedScopedEntries ? [entry] : [];
|
|
2470
|
-
} catch {
|
|
2471
|
-
return params.preserveUnmatchedScopedEntries ? [entry] : [];
|
|
2472
|
-
}
|
|
2473
|
-
});
|
|
2324
|
+
function qualifySlackConversationId(conversationId, eventScope) {
|
|
2325
|
+
return eventScope ? `team:${encodeURIComponent(eventScope.teamId)}:${conversationId}` : conversationId;
|
|
2474
2326
|
}
|
|
2475
2327
|
//#endregion
|
|
2476
2328
|
//#region extensions/slack/src/group-policy.ts
|
|
@@ -2524,4 +2376,4 @@ function resolveSlackGroupToolPolicy(params) {
|
|
|
2524
2376
|
});
|
|
2525
2377
|
}
|
|
2526
2378
|
//#endregion
|
|
2527
|
-
export {
|
|
2379
|
+
export { renderSlackMessagePresentationFallbackText as $, SLACK_MESSAGE_TEXT_HARD_LIMIT as A, SLACK_PRIVATE_ACTION_DELIVERY_RESULT as At, SLACK_REPLY_BUTTON_ACTION_ID as B, isSlackNativeResponseUrlRejection as C, isSlackApprovalAuthorizedSender as Ct, renderSlackBlockFallbackText as D, normalizeSlackApproverId as Dt, buildSlackCompleteBlocksFallbackText as E, isSlackExecApprovalClientEnabled as Et, canRenderSlackPresentation as F, isSlackCallbackActionId as G, SLACK_REPLY_SELECT_ACTION_ID as H, countSlackTextUtf8Bytes as I, decodeSlackQuestionAction as J, isSlackQuestionActionId as K, truncateSlackText as L, SLACK_TEXT_LIMIT as M, buildSlackInteractiveBlocks as N, resolveSlackAuthoredTextPlacement as O, resolveSlackExecApprovalTarget as Ot, buildSlackPresentationBlocks as P, normalizeSlackOutboundText as Q, truncateSlackTextByUtf8Bytes as R, isSlackInvalidBlocksResponse as S, getSlackApprovalApprovers as St, buildSlackBlocksFallbackText as T, isSlackExecApprovalAuthorizedSender as Tt, SLACK_SESSION_LINK_ACTION_ID as U, SLACK_REPLY_LINK_ACTION_ID as V, isSlackApprovalActionId as W, chunkSlackMrkdwnText as X, resolveSlackQuestionAction as Y, markdownToSlackMrkdwnChunks as Z, appendSlackNativeDataPlainTextFallback as _, shouldHandleSlackPluginViaForwardingSession as _t, qualifySlackConversationId as a, SLACK_MAX_BLOCKS as at, hasSlackNativeDataBlock as b, isSlackWorkspaceInstallation as bt, assertSlackDetachedTargetAllowed as c, hasSlackPluginApprovers as ct, resolveSlackReplyBlockResolution as d, normalizeSlackOriginTarget as dt, escapeSlackMrkdwn as et, resolveSlackReplyBlocks as f, resolveEnterpriseApprovalTeamId as ft, appendSlackNativeDataFallbackText as g, shouldHandleSlackNativeApprovalRequest as gt, SLACK_MALFORMED_NATIVE_DATA_FALLBACK as h, resolveTurnSourceSlackOriginTarget as ht, resolveSlackGroupToolPolicy as i, SLACK_SECTION_TEXT_MAX as it, SLACK_MESSAGE_TEXT_RECOMMENDED_LIMIT as j, resolveSlackAutoThreadId as jt, SLACK_EDIT_TEXT_MAX_BYTES as k, shouldSuppressLocalSlackExecApprovalPrompt as kt, hasSlackReplyStructuredContent as l, isSlackAnyNativeApprovalClientEnabled as lt, resolveSlackReplyRenderPlan as m, resolveSlackFallbackOriginTarget as mt, buildSlackChannelPolicyScope as n, decodeSlackApprovalAction as nt, qualifySlackRoutePeerId as o, parseSlackBlocksInput as ot, resolveSlackReplyDeliveryMessages as p, resolveSessionSlackOriginTarget as pt, resolveSlackQuestionActionIds as q, resolveSlackGroupRequireMention as r, SLACK_PRESENTATION_CAPABILITIES as rt, resolveSlackEnterpriseMainDmSessionKey as s, validateSlackBlocksArray as st, buildSlackChannelIdCandidates as t, SLACK_APPROVAL_HEADER_BLOCK_ID as tt, parseSlackReplyBlockSegments as u, normalizeSlackForwardTarget as ut, buildSlackNativeDataAccessibilityText as v, slackTargetsMatch as vt, stripSlackNativeDataBlocks as w, getSlackExecApprovalApprovers as wt, isSlackInvalidBlocksError as x, registerSlackInstallationState as xt, createSlackNativeDataBaseTextConsumer as y, getSlackInstallationKind as yt, SLACK_QUESTION_FINALIZATION_BLOCKS as z };
|