@openclaw/slack 2026.8.1-beta.3 → 2026.8.2
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-C3sePHWa.js +87 -0
- package/dist/account-inspect-api.js +1 -1
- package/dist/{accounts-BlzxuYle.js → accounts-Dm_H77gH.js} +7 -10
- package/dist/{accounts.runtime-CbabBL8x.js → accounts.runtime-DRuEK6mL.js} +1 -1
- package/dist/{action-runtime-D6jg2CQd.js → action-runtime-B0kRJ69h.js} +90 -75
- package/dist/action-runtime.runtime-IuA14rev.js +2 -0
- package/dist/{actions-DFk0ANVB.js → actions-BOxiu2Vy.js} +278 -102
- package/dist/api.js +15 -15
- package/dist/{approval-handler.runtime-BNvAoKdK.js → approval-handler.runtime-l5_2JLqi.js} +58 -180
- package/dist/{channel-CA5w7qDF.js → channel-BguxhhNG.js} +97 -154
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel-type-CZWv55Wu.js → channel-type-ChkODKBW.js} +3 -3
- package/dist/{channel.setup-CpyYsEXH.js → channel.setup-BJohRJha.js} +54 -68
- package/dist/{config-schema-CN3XZRX5.js → config-schema-B9GwoRlE.js} +24 -15
- package/dist/configured-state.js +34 -0
- package/dist/{conversation-binding-route-DFVLUdYF.js → conversation-binding-route-Vee8Dgbf.js} +2 -2
- package/dist/{directory-config-BGYyuzWh.js → directory-config-Bmw4ykSy.js} +5 -4
- package/dist/directory-contract-api.js +1 -1
- package/dist/{directory-live-DjUJQLbq.js → directory-live-BOILcXPo.js} +2 -2
- package/dist/{doctor-contract-BAy7-EUQ.js → doctor-contract-BNjw9bxb.js} +5 -4
- package/dist/doctor-contract-api.js +1 -1
- package/dist/{group-policy-DyfB_ZIE.js → group-policy-BYH74y50.js} +643 -774
- package/dist/{message-tool-api-CqMr5Rmc.js → message-tool-api-BsZbsulu.js} +23 -5
- package/dist/message-tool-api.js +1 -1
- package/dist/{monitor-Chrecrb9.js → monitor-B72wWXWg.js} +3 -3
- package/dist/{outbound-adapter-DuRqAQXK.js → outbound-adapter-CPgYQ-BM.js} +94 -69
- package/dist/{pipeline.runtime-Bbfd5VFW.js → pipeline.runtime-CcdujV99.js} +357 -544
- package/dist/{policy-BKXSxrIS.js → policy-CUpBeOt9.js} +7 -4
- package/dist/{probe-BVA65leh.js → probe-gj5yQgN2.js} +209 -21
- package/dist/{provider-CUUiwsg2.js → provider-DW9YC_no.js} +301 -179
- package/dist/{relay-source-mhpMMRG-.js → relay-source-BLMdBrAw.js} +6 -4
- package/dist/{replies-SnWyXcsL.js → replies-DLjQ8RYU.js} +25 -10
- package/dist/{resolve-channels-BSpqC8jU.js → resolve-channels-Bv6IiGZ4.js} +4 -3
- package/dist/{resolve-users-Dvz9pDe0.js → resolve-users-BXw2pA7y.js} +4 -3
- package/dist/runtime-api.js +11 -11
- package/dist/{scopes-BSk4GZvZ.js → scopes-B9HRguDe.js} +1 -1
- package/dist/{send-CtnOxKCc.js → send-GUz4_v2E.js} +58 -42
- package/dist/send-results-eeOu_HYm.js +23 -0
- package/dist/{send.runtime-kYctMHSd.js → send.runtime-rScD-UJi.js} +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{setup-surface-BPFfp6So.js → setup-surface-Cc3P-z35.js} +6 -6
- package/dist/{shared-DJBaslN7.js → shared-CQGVZ_8a.js} +28 -8
- package/dist/{slash-dispatch.runtime-Cf2FTrnf.js → slash-dispatch.runtime-C2015r6s.js} +3 -3
- package/dist/{target-parsing-BnMD2ZqZ.js → target-parsing-PbxGDbr9.js} +11 -6
- package/dist/{targets-Cx5W_n3W.js → targets-7FexXJ62.js} +1 -1
- 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/negotiator/lib/accept.js +54 -0
- package/node_modules/@slack/bolt/node_modules/negotiator/lib/charset.js +10 -34
- package/node_modules/@slack/bolt/node_modules/negotiator/lib/encoding.js +9 -30
- package/node_modules/@slack/bolt/node_modules/negotiator/lib/language.js +15 -36
- package/node_modules/@slack/bolt/node_modules/negotiator/lib/mediaType.js +16 -134
- package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/LICENSE +22 -0
- package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/README.md +71 -0
- package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.d.ts +46 -0
- package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.js +176 -0
- package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.js.map +1 -0
- package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/package.json +52 -0
- package/node_modules/@slack/bolt/node_modules/negotiator/package.json +16 -10
- 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 +41 -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 +14 -6
- package/package.json +9 -7
- package/dist/account-configured-BwfXBo_F.js +0 -14
- package/dist/account-inspect-YJvFBbCR.js +0 -89
- package/dist/action-runtime.runtime-JtoOK9l5.js +0 -2
- package/dist/actions.runtime-CYLsYRai.js +0 -2
- package/dist/runtime-api-DBi7xc_g.js +0 -10
- package/dist/slack-client-kind-BXyOOICI.js +0 -94
- package/node_modules/@slack/bolt/node_modules/negotiator/HISTORY.md +0 -114
- 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
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as
|
|
3
|
-
import { t as
|
|
4
|
-
import { t as
|
|
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";
|
|
3
|
+
import { a as parseSlackTarget, n as formatSlackTarget, t as canonicalizeSlackApiTargetId } from "./target-parsing-PbxGDbr9.js";
|
|
4
|
+
import { t as slackContextTargetsMatch } from "./targets-7FexXJ62.js";
|
|
5
|
+
import { C as normalizeAllowListLower, D as resolveSlackUserAllowListForTeam, E as resolveSlackAllowListMatch } from "./probe-gj5yQgN2.js";
|
|
5
6
|
import { normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
|
|
6
|
-
import { asOptionalRecord, normalizeLowercaseStringOrEmpty,
|
|
7
|
+
import { asOptionalRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeStringifiedOptionalString, readNonBlankString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
7
8
|
import { normalizeMessageChannel } from "openclaw/plugin-sdk/routing";
|
|
8
9
|
import { FormatCapabilityProfile, chunkTextForOutbound, markdownToIR, renderMarkdownIRChunksWithinLimit, renderMarkdownWithMarkers } from "openclaw/plugin-sdk/text-chunking";
|
|
9
10
|
import { isSingleUseReplyToMode } from "openclaw/plugin-sdk/reply-reference";
|
|
@@ -11,17 +12,17 @@ import { buildChannelKeyCandidates } from "openclaw/plugin-sdk/channel-targets";
|
|
|
11
12
|
import { createNativeApprovalChannelRouteGates, doesApprovalRequestSelectChannelAccount, resolveApprovalKind, resolveApprovalRequestSessionConversation } from "openclaw/plugin-sdk/approval-native-runtime";
|
|
12
13
|
import { createChannelApprovalAuth, resolveApprovalApprovers } from "openclaw/plugin-sdk/approval-auth-runtime";
|
|
13
14
|
import { createChannelExecApprovalProfile, isChannelExecApprovalClientEnabledFromConfig, isChannelExecApprovalTargetRecipient, matchesApprovalRequestFilters } from "openclaw/plugin-sdk/approval-client-runtime";
|
|
15
|
+
import { normalizeHyphenSlug } from "openclaw/plugin-sdk/string-normalization-runtime";
|
|
14
16
|
import { channelRouteTargetsMatchExact, stringifyRouteThreadId } from "openclaw/plugin-sdk/channel-route";
|
|
15
17
|
import { resolveGlobalMap } from "openclaw/plugin-sdk/global-singleton";
|
|
16
|
-
import {
|
|
18
|
+
import { legacyInteractiveReplyToPresentation, normalizeMessagePresentation, renderMessagePresentationChartFallbackText, renderMessagePresentationFallbackText, renderMessagePresentationTableFallbackText, resolveMessagePresentationButtonAction, resolveMessagePresentationOptionAction } from "openclaw/plugin-sdk/interactive-runtime";
|
|
17
19
|
import { parseExecApprovalCommandText } from "openclaw/plugin-sdk/approval-reply-runtime";
|
|
20
|
+
import { resolveAskUserQuestionOptionIndex, resolveAskUserQuestionOptionIndices } from "openclaw/plugin-sdk/reply-payload";
|
|
18
21
|
import { buildApprovalResolutionRef } from "openclaw/plugin-sdk/approval-reference-runtime";
|
|
22
|
+
import { eastAsianWidthType } from "get-east-asian-width";
|
|
19
23
|
import { questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
|
|
20
24
|
import { sliceUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
21
|
-
import { eastAsianWidthType } from "get-east-asian-width";
|
|
22
25
|
import { readResponseTextLimited } from "openclaw/plugin-sdk/provider-http";
|
|
23
|
-
import { compileAllowlist, resolveCompiledAllowlistMatch } from "openclaw/plugin-sdk/allow-from";
|
|
24
|
-
import { normalizeHyphenSlug, normalizeStringEntries as normalizeStringEntries$1, normalizeStringEntriesLower } from "openclaw/plugin-sdk/string-normalization-runtime";
|
|
25
26
|
import { resolveScopeRequireMention, resolveScopeToolsPolicy } from "openclaw/plugin-sdk/channel-policy";
|
|
26
27
|
//#region extensions/slack/src/action-threading.ts
|
|
27
28
|
const SLACK_PRIVATE_ACTION_DELIVERY_RESULT = Symbol("slack.action.delivery-result");
|
|
@@ -43,14 +44,24 @@ function normalizeSlackUserLikeId(value) {
|
|
|
43
44
|
const upper = value.toUpperCase();
|
|
44
45
|
return /^[UW][A-Z0-9]+$/.test(upper) ? upper : void 0;
|
|
45
46
|
}
|
|
46
|
-
function
|
|
47
|
+
function normalizeSlackApproverTarget(value) {
|
|
47
48
|
const trimmed = normalizeStringifiedOptionalString(value);
|
|
48
49
|
if (!trimmed) return;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
try {
|
|
51
|
+
const target = parseSlackTarget(trimmed, { defaultKind: "user" });
|
|
52
|
+
const id = target?.kind === "user" ? normalizeSlackUserLikeId(target.id) : void 0;
|
|
53
|
+
return target?.teamId && id ? formatSlackTarget({
|
|
54
|
+
kind: "user",
|
|
55
|
+
id,
|
|
56
|
+
teamId: target.teamId.toUpperCase()
|
|
57
|
+
}) : id;
|
|
58
|
+
} catch {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function normalizeSlackApproverId(value) {
|
|
63
|
+
const target = normalizeSlackApproverTarget(value);
|
|
64
|
+
return target?.startsWith("team:") ? void 0 : target;
|
|
54
65
|
}
|
|
55
66
|
function resolveSlackOwnerApprovers(cfg) {
|
|
56
67
|
const ownerAllowFrom = cfg.commands?.ownerAllowFrom;
|
|
@@ -87,27 +98,40 @@ const resolveSlackExecApprovalTarget = slackExecApprovalProfile.resolveTarget;
|
|
|
87
98
|
const shouldSuppressLocalSlackExecApprovalPrompt = slackExecApprovalProfile.shouldSuppressLocalPrompt;
|
|
88
99
|
//#endregion
|
|
89
100
|
//#region extensions/slack/src/approval-auth.ts
|
|
101
|
+
function resolveSlackApprovalInputs(params) {
|
|
102
|
+
const account = resolveSlackAccount(params).config;
|
|
103
|
+
return {
|
|
104
|
+
allowFrom: resolveSlackAccountAllowFrom(params),
|
|
105
|
+
defaultTo: account.defaultTo
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function slackApprovalTargetMatches(senderId, approvers) {
|
|
109
|
+
const sender = parseSlackTarget(senderId, { defaultKind: "user" });
|
|
110
|
+
return sender?.kind === "user" && resolveSlackAllowListMatch({
|
|
111
|
+
allowList: normalizeAllowListLower([...approvers]),
|
|
112
|
+
teamId: sender.teamId,
|
|
113
|
+
id: sender.id
|
|
114
|
+
}).allowed;
|
|
115
|
+
}
|
|
90
116
|
const slackApproval = createChannelApprovalAuth({
|
|
91
117
|
channelLabel: "Slack",
|
|
92
|
-
resolveInputs:
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return {
|
|
98
|
-
allowFrom: resolveSlackAccountAllowFrom({
|
|
99
|
-
cfg,
|
|
100
|
-
accountId
|
|
101
|
-
}),
|
|
102
|
-
defaultTo: account.defaultTo
|
|
103
|
-
};
|
|
104
|
-
},
|
|
105
|
-
normalizeApprover: normalizeSlackApproverId,
|
|
106
|
-
normalizeDefaultTo: normalizeSlackApproverId,
|
|
107
|
-
isWildcardAuthorized: ({ purpose, senderId, inputs, approvers }) => purpose === "sender" && Boolean(senderId) && approvers.length === 0 && inputs.allowFrom?.some((entry) => String(entry).trim() === "*") === true
|
|
118
|
+
resolveInputs: resolveSlackApprovalInputs,
|
|
119
|
+
normalizeApprover: normalizeSlackApproverTarget,
|
|
120
|
+
normalizeDefaultTo: normalizeSlackApproverTarget,
|
|
121
|
+
normalizeSenderId: normalizeSlackApproverTarget,
|
|
122
|
+
isWildcardAuthorized: ({ purpose, senderId, inputs, approvers }) => Boolean(senderId && (slackApprovalTargetMatches(senderId, approvers) || purpose === "sender" && approvers.length === 0 && inputs.allowFrom?.some((entry) => String(entry).trim() === "*")))
|
|
108
123
|
});
|
|
109
124
|
const getSlackApprovalApprovers = slackApproval.resolveApprovers;
|
|
110
125
|
const isSlackApprovalAuthorizedSender = slackApproval.isAuthorizedSender;
|
|
126
|
+
function getSlackApprovalApproversForTeam(params) {
|
|
127
|
+
return resolveApprovalApprovers({
|
|
128
|
+
allowFrom: resolveSlackUserAllowListForTeam({
|
|
129
|
+
allowList: getSlackApprovalApprovers(params),
|
|
130
|
+
teamId: params.teamId
|
|
131
|
+
}),
|
|
132
|
+
normalizeApprover: normalizeSlackApproverTarget
|
|
133
|
+
});
|
|
134
|
+
}
|
|
111
135
|
//#endregion
|
|
112
136
|
//#region extensions/slack/src/installation-identity-state.ts
|
|
113
137
|
const slackInstallationStates = resolveGlobalMap(Symbol.for("openclaw.slack.installation-identities"), "close-and-restart");
|
|
@@ -142,7 +166,8 @@ const DEFAULT_APPROVAL_FORWARDING_MODE = "session";
|
|
|
142
166
|
const SLACK_DM_CHANNEL_ID_RE = /^D[A-Z0-9]{8,}$/i;
|
|
143
167
|
const SLACK_USER_ID_RE = /^[UW][A-Z0-9]{8,}$/i;
|
|
144
168
|
function isSlackApprovalTransportEnabled(params) {
|
|
145
|
-
|
|
169
|
+
const account = resolveSlackAccount(params);
|
|
170
|
+
return isSlackPluginAccountConfigured(account);
|
|
146
171
|
}
|
|
147
172
|
function resolveSlackNativeApprovalConfig(params) {
|
|
148
173
|
return resolveSlackAccount(params).config.execApprovals;
|
|
@@ -158,7 +183,8 @@ function normalizeComparableTarget(value) {
|
|
|
158
183
|
}
|
|
159
184
|
function extractSlackSessionKind(sessionKey) {
|
|
160
185
|
if (!sessionKey) return null;
|
|
161
|
-
const
|
|
186
|
+
const match = sessionKey.match(/slack:(direct|channel|group):/i);
|
|
187
|
+
const kind = normalizeLowercaseStringOrEmpty(match?.[1]);
|
|
162
188
|
return kind ? kind : null;
|
|
163
189
|
}
|
|
164
190
|
function resolveSlackTurnSourceDefaultKind(params) {
|
|
@@ -169,9 +195,10 @@ function resolveTurnSourceSlackOriginTarget(request) {
|
|
|
169
195
|
const turnSourceChannel = normalizeLowercaseStringOrEmpty(request.request.turnSourceChannel);
|
|
170
196
|
const turnSourceTo = normalizeOptionalString(request.request.turnSourceTo) ?? "";
|
|
171
197
|
if (turnSourceChannel !== "slack" || !turnSourceTo) return null;
|
|
198
|
+
const sessionKind = extractSlackSessionKind(request.request.sessionKey ?? void 0);
|
|
172
199
|
const parsed = parseSlackTarget(turnSourceTo, { defaultKind: resolveSlackTurnSourceDefaultKind({
|
|
173
200
|
turnSourceTo,
|
|
174
|
-
sessionKind
|
|
201
|
+
sessionKind
|
|
175
202
|
}) });
|
|
176
203
|
if (!parsed) return null;
|
|
177
204
|
return {
|
|
@@ -263,11 +290,12 @@ const { canApprovalPotentiallyRouteToChannel: canApprovalPotentiallyRouteToSlack
|
|
|
263
290
|
targetsMatch: slackTargetsMatch
|
|
264
291
|
});
|
|
265
292
|
function hasSlackPluginApprovers(params) {
|
|
266
|
-
return
|
|
293
|
+
return getSlackApprovalApproversForTeam(params).length > 0;
|
|
267
294
|
}
|
|
268
295
|
function isSlackPluginNativeApprovalClientConfigEnabled(params) {
|
|
296
|
+
const slackNativeConfig = resolveSlackNativeApprovalConfig(params);
|
|
269
297
|
return isChannelExecApprovalClientEnabledFromConfig({
|
|
270
|
-
enabled:
|
|
298
|
+
enabled: slackNativeConfig?.enabled,
|
|
271
299
|
approverCount: getSlackApprovalApprovers(params).length
|
|
272
300
|
});
|
|
273
301
|
}
|
|
@@ -304,7 +332,10 @@ function matchesSlackNativeApprovalFilters(params) {
|
|
|
304
332
|
}
|
|
305
333
|
function isSlackNativeApprovalAccountEligible(params) {
|
|
306
334
|
const config = resolveSlackNativeApprovalConfig(params);
|
|
307
|
-
const approverCount = params.approvalKind === "exec" ? getSlackExecApprovalApprovers(params).length :
|
|
335
|
+
const approverCount = params.approvalKind === "exec" ? getSlackExecApprovalApprovers(params).length : getSlackApprovalApproversForTeam({
|
|
336
|
+
...params,
|
|
337
|
+
teamId: resolveEnterpriseApprovalTeamId(params.request)
|
|
338
|
+
}).length;
|
|
308
339
|
return isSlackApprovalTransportEnabled(params) && isChannelExecApprovalClientEnabledFromConfig({
|
|
309
340
|
enabled: config?.enabled,
|
|
310
341
|
approverCount
|
|
@@ -924,106 +955,453 @@ function renderSlackDataVisualizationMrkdwnFallbackText(value) {
|
|
|
924
955
|
return typeof block.title === "string" && block.title.trim() ? escapeSlackMrkdwn(block.title.trim()) : void 0;
|
|
925
956
|
}
|
|
926
957
|
//#endregion
|
|
927
|
-
//#region extensions/slack/src/
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
function encodeSlackQuestionAction(action) {
|
|
931
|
-
if (!QUESTION_RECORD_ID_PATTERN.test(action.questionId) || !Number.isInteger(action.optionIndex) || action.optionIndex < 0 || action.optionIndex > 3) return;
|
|
932
|
-
const value = `${SLACK_QUESTION_VALUE_PREFIX}${action.questionId}:${action.optionIndex}`;
|
|
933
|
-
return value.length <= 2e3 ? value : void 0;
|
|
958
|
+
//#region extensions/slack/src/format.ts
|
|
959
|
+
function escapeSlackMrkdwnSegment(text) {
|
|
960
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
934
961
|
}
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
optionIndex: Number(match[2])
|
|
941
|
-
} : null;
|
|
962
|
+
const SLACK_ANGLE_TOKEN_RE = /<[^>\n]+>/g;
|
|
963
|
+
function isAllowedSlackAngleToken(token) {
|
|
964
|
+
if (!token.startsWith("<") || !token.endsWith(">")) return false;
|
|
965
|
+
const inner = token.slice(1, -1);
|
|
966
|
+
return inner.startsWith("@") || inner.startsWith("#") || inner.startsWith("!") || inner.startsWith("mailto:") || inner.startsWith("tel:") || inner.startsWith("http://") || inner.startsWith("https://") || inner.startsWith("slack://");
|
|
942
967
|
}
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
return;
|
|
968
|
+
function escapeSlackMrkdwnContent(text) {
|
|
969
|
+
if (!text) return "";
|
|
970
|
+
if (!text.includes("&") && !text.includes("<") && !text.includes(">")) return text;
|
|
971
|
+
SLACK_ANGLE_TOKEN_RE.lastIndex = 0;
|
|
972
|
+
const out = [];
|
|
973
|
+
let lastIndex = 0;
|
|
974
|
+
for (let match = SLACK_ANGLE_TOKEN_RE.exec(text); match; match = SLACK_ANGLE_TOKEN_RE.exec(text)) {
|
|
975
|
+
const matchIndex = match.index ?? 0;
|
|
976
|
+
out.push(escapeSlackMrkdwnSegment(text.slice(lastIndex, matchIndex)));
|
|
977
|
+
const token = match[0] ?? "";
|
|
978
|
+
out.push(isAllowedSlackAngleToken(token) ? token : escapeSlackMrkdwnSegment(token));
|
|
979
|
+
lastIndex = matchIndex + token.length;
|
|
956
980
|
}
|
|
957
|
-
|
|
981
|
+
out.push(escapeSlackMrkdwnSegment(text.slice(lastIndex)));
|
|
982
|
+
return out.join("");
|
|
958
983
|
}
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
const SLACK_CALLBACK_SELECT_ACTION_ID = "openclaw:callback_select";
|
|
967
|
-
const SLACK_APPROVAL_BUTTON_ACTION_ID = "openclaw:approval_button";
|
|
968
|
-
const SLACK_APPROVAL_SELECT_ACTION_ID = "openclaw:approval_select";
|
|
969
|
-
const SLACK_QUESTION_BUTTON_ACTION_ID = "openclaw:question_button";
|
|
970
|
-
const SLACK_QUESTION_FINALIZATION_BLOCKS = Symbol("slackQuestionFinalizationBlocks");
|
|
971
|
-
function isSlackQuestionActionId(actionId) {
|
|
972
|
-
return actionId === "openclaw:question_button" || actionId.startsWith(`openclaw:question_button:`);
|
|
984
|
+
function escapeSlackMrkdwnText(text) {
|
|
985
|
+
if (!text) return "";
|
|
986
|
+
if (!text.includes("&") && !text.includes("<") && !text.includes(">")) return text;
|
|
987
|
+
return text.split("\n").map((line) => {
|
|
988
|
+
if (line.startsWith("> ")) return `> ${escapeSlackMrkdwnContent(line.slice(2))}`;
|
|
989
|
+
return escapeSlackMrkdwnContent(line);
|
|
990
|
+
}).join("\n");
|
|
973
991
|
}
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
992
|
+
function buildSlackLink(link, text) {
|
|
993
|
+
const href = link.href.trim();
|
|
994
|
+
if (!href) return null;
|
|
995
|
+
const trimmedLabel = text.slice(link.start, link.end).trim();
|
|
996
|
+
const comparableHref = href.startsWith("mailto:") ? href.slice(7) : href;
|
|
997
|
+
if (!(trimmedLabel.length > 0 && trimmedLabel !== href && trimmedLabel !== comparableHref)) return null;
|
|
998
|
+
const safeHref = escapeSlackMrkdwnSegment(href);
|
|
999
|
+
return {
|
|
1000
|
+
start: link.start,
|
|
1001
|
+
end: link.end,
|
|
1002
|
+
open: `<${safeHref}|`,
|
|
1003
|
+
close: ">"
|
|
1004
|
+
};
|
|
980
1005
|
}
|
|
981
|
-
|
|
982
|
-
|
|
1006
|
+
const SLACK_MRKDWN_WORD_CHARACTER_RE = /[\p{L}\p{M}\p{N}_]/u;
|
|
1007
|
+
const SLACK_MRKDWN_PUNCTUATION_RE = /\p{P}/u;
|
|
1008
|
+
const SLACK_MRKDWN_SYMBOL_RE = /\p{S}/u;
|
|
1009
|
+
const SLACK_MRKDWN_CJK_SCRIPT_RE = /[\p{Script_Extensions=Han}\p{Script_Extensions=Hiragana}\p{Script_Extensions=Katakana}\p{Script_Extensions=Hangul}]/u;
|
|
1010
|
+
const SLACK_MRKDWN_EMOJI_PRESENTATION_RE = /\p{Emoji_Presentation}/u;
|
|
1011
|
+
function getCodePointBefore(text, index) {
|
|
1012
|
+
if (index <= 0) return "";
|
|
1013
|
+
const lastCodeUnit = text.charCodeAt(index - 1);
|
|
1014
|
+
if (lastCodeUnit >= 56320 && lastCodeUnit <= 57343 && index > 1) {
|
|
1015
|
+
const previousCodeUnit = text.charCodeAt(index - 2);
|
|
1016
|
+
if (previousCodeUnit >= 55296 && previousCodeUnit <= 56319) return text.slice(index - 2, index);
|
|
1017
|
+
}
|
|
1018
|
+
return text[index - 1] ?? "";
|
|
983
1019
|
}
|
|
984
|
-
function
|
|
985
|
-
|
|
1020
|
+
function getCodePointAt(text, index) {
|
|
1021
|
+
const codePoint = text.codePointAt(index);
|
|
1022
|
+
return codePoint === void 0 ? "" : String.fromCodePoint(codePoint);
|
|
986
1023
|
}
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
const
|
|
991
|
-
if (
|
|
992
|
-
|
|
993
|
-
return
|
|
1024
|
+
function isSlackCjkPunctuation(character) {
|
|
1025
|
+
if (!SLACK_MRKDWN_PUNCTUATION_RE.test(character)) return false;
|
|
1026
|
+
if (SLACK_MRKDWN_CJK_SCRIPT_RE.test(character)) return true;
|
|
1027
|
+
const codePoint = character.codePointAt(0);
|
|
1028
|
+
if (codePoint === void 0) return false;
|
|
1029
|
+
const width = eastAsianWidthType(codePoint);
|
|
1030
|
+
return width === "fullwidth" || width === "halfwidth" || width === "wide" && !SLACK_MRKDWN_EMOJI_PRESENTATION_RE.test(character);
|
|
994
1031
|
}
|
|
995
|
-
function
|
|
996
|
-
|
|
1032
|
+
function isUnsafeSlackEmphasisBoundary(character) {
|
|
1033
|
+
if (SLACK_MRKDWN_WORD_CHARACTER_RE.test(character)) return true;
|
|
1034
|
+
const codePoint = character.codePointAt(0);
|
|
1035
|
+
if (codePoint === void 0 || codePoint <= 127) return false;
|
|
1036
|
+
return SLACK_MRKDWN_SYMBOL_RE.test(character) || isSlackCjkPunctuation(character);
|
|
997
1037
|
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1038
|
+
function makeSlackEmphasisStylesSafe(ir) {
|
|
1039
|
+
const styles = ir.styles.filter((span) => {
|
|
1040
|
+
if (span.style !== "italic" && span.style !== "bold") return true;
|
|
1041
|
+
return !isUnsafeSlackEmphasisBoundary(getCodePointBefore(ir.text, span.start)) && !isUnsafeSlackEmphasisBoundary(getCodePointAt(ir.text, span.end));
|
|
1042
|
+
});
|
|
1043
|
+
return styles.length === ir.styles.length ? ir : {
|
|
1044
|
+
...ir,
|
|
1045
|
+
styles
|
|
1046
|
+
};
|
|
1047
|
+
}
|
|
1048
|
+
const SLACK_FORMAT_PROFILE = FormatCapabilityProfile.define({
|
|
1049
|
+
mechanism: "markdown",
|
|
1050
|
+
constructs: {
|
|
1051
|
+
underline: "strip",
|
|
1052
|
+
spoiler: "fallback",
|
|
1053
|
+
codeLanguage: "fallback",
|
|
1054
|
+
heading: "fallback",
|
|
1055
|
+
bulletList: "fallback",
|
|
1056
|
+
orderedList: "fallback",
|
|
1057
|
+
taskList: "fallback",
|
|
1058
|
+
table: "fallback",
|
|
1059
|
+
image: "fallback"
|
|
1060
|
+
},
|
|
1061
|
+
chunk: {
|
|
1062
|
+
limit: 4e3,
|
|
1063
|
+
unit: "chars",
|
|
1064
|
+
hardCap: 4e4
|
|
1013
1065
|
}
|
|
1014
|
-
|
|
1066
|
+
});
|
|
1067
|
+
const SLACK_ASSISTANT_TRANSCRIPT_PREFIX = "`Assistant:` ";
|
|
1068
|
+
function tokenizeSlackMrkdwn(text) {
|
|
1069
|
+
const tokens = [];
|
|
1070
|
+
for (let index = 0; index < text.length;) {
|
|
1071
|
+
if (text.startsWith("```", index)) {
|
|
1072
|
+
tokens.push("```");
|
|
1073
|
+
index += 3;
|
|
1074
|
+
continue;
|
|
1075
|
+
}
|
|
1076
|
+
const entity = [
|
|
1077
|
+
"&",
|
|
1078
|
+
"<",
|
|
1079
|
+
">"
|
|
1080
|
+
].find((candidate) => text.startsWith(candidate, index));
|
|
1081
|
+
if (entity) {
|
|
1082
|
+
tokens.push(entity);
|
|
1083
|
+
index += entity.length;
|
|
1084
|
+
continue;
|
|
1085
|
+
}
|
|
1086
|
+
if (text[index] === "<") {
|
|
1087
|
+
const end = text.indexOf(">", index + 1);
|
|
1088
|
+
const angleToken = end >= 0 ? text.slice(index, end + 1) : void 0;
|
|
1089
|
+
if (angleToken && !angleToken.includes("\n") && isAllowedSlackAngleToken(angleToken)) {
|
|
1090
|
+
tokens.push(angleToken);
|
|
1091
|
+
index += angleToken.length;
|
|
1092
|
+
continue;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
const codePoint = text.codePointAt(index);
|
|
1096
|
+
if (codePoint === void 0) break;
|
|
1097
|
+
const character = String.fromCodePoint(codePoint);
|
|
1098
|
+
index += character.length;
|
|
1099
|
+
if (character === "\\" && index < text.length) {
|
|
1100
|
+
const escapedCodePoint = text.codePointAt(index);
|
|
1101
|
+
if (escapedCodePoint !== void 0) {
|
|
1102
|
+
const escapedCharacter = String.fromCodePoint(escapedCodePoint);
|
|
1103
|
+
tokens.push(character + escapedCharacter);
|
|
1104
|
+
index += escapedCharacter.length;
|
|
1105
|
+
continue;
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
tokens.push(character);
|
|
1109
|
+
}
|
|
1110
|
+
return tokens;
|
|
1015
1111
|
}
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
return `${SLACK_REPLY_BUTTON_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
|
|
1112
|
+
function resolveSlackCodeMarkerTransition(active, token) {
|
|
1113
|
+
if (token === "```" && active !== "`") return active === "```" ? void 0 : "```";
|
|
1114
|
+
if (token === "`" && active !== "```") return active === "`" ? void 0 : "`";
|
|
1115
|
+
return null;
|
|
1021
1116
|
}
|
|
1022
|
-
function
|
|
1023
|
-
return
|
|
1117
|
+
function maskSlackExcludedText(text) {
|
|
1118
|
+
return text.split("\n").map((line) => line.trim() ? `x${" ".repeat(Math.max(0, line.length - 1))}` : " ".repeat(line.length)).join("\n");
|
|
1024
1119
|
}
|
|
1025
|
-
function
|
|
1026
|
-
|
|
1120
|
+
function maskSlackExcludedRanges(projection) {
|
|
1121
|
+
let masked = "";
|
|
1122
|
+
let cursor = 0;
|
|
1123
|
+
for (const range of projection.excludedRanges) {
|
|
1124
|
+
masked += projection.text.slice(cursor, range.start);
|
|
1125
|
+
masked += maskSlackExcludedText(projection.text.slice(range.start, range.end));
|
|
1126
|
+
cursor = range.end;
|
|
1127
|
+
}
|
|
1128
|
+
return masked + projection.text.slice(cursor);
|
|
1129
|
+
}
|
|
1130
|
+
function slackProjectionHasRoleHeader(projection) {
|
|
1131
|
+
return Boolean(markdownToIR(maskSlackExcludedRanges(projection), {
|
|
1132
|
+
assistantTranscriptRoleHeaders: true,
|
|
1133
|
+
autolink: false,
|
|
1134
|
+
blockquotePrefix: "",
|
|
1135
|
+
headingStyle: "none",
|
|
1136
|
+
linkify: false,
|
|
1137
|
+
tableMode: "off"
|
|
1138
|
+
}).annotations?.some((annotation) => annotation.type === "assistant_transcript_role"));
|
|
1139
|
+
}
|
|
1140
|
+
function decodeSlackMrkdwnEntities(text) {
|
|
1141
|
+
return text.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
1142
|
+
}
|
|
1143
|
+
function projectSlackAngleToken(token, dateDisplay) {
|
|
1144
|
+
const inner = token.slice(1, -1);
|
|
1145
|
+
if (inner.startsWith("!date^")) {
|
|
1146
|
+
const fallbackSeparator = inner.indexOf("|");
|
|
1147
|
+
const tokenString = (fallbackSeparator === -1 ? inner : inner.slice(0, fallbackSeparator)).split("^")[2] ?? "";
|
|
1148
|
+
const fallback = fallbackSeparator === -1 ? "" : inner.slice(fallbackSeparator + 1);
|
|
1149
|
+
return decodeSlackMrkdwnEntities(dateDisplay === "fallback" ? fallback || tokenString : tokenString || fallback);
|
|
1150
|
+
}
|
|
1151
|
+
const labelSeparator = inner.indexOf("|");
|
|
1152
|
+
if (labelSeparator >= 0) return decodeSlackMrkdwnEntities(inner.slice(labelSeparator + 1));
|
|
1153
|
+
if (inner.startsWith("@")) return "@";
|
|
1154
|
+
if (inner.startsWith("#")) return "#";
|
|
1155
|
+
if (inner.startsWith("!")) return "!";
|
|
1156
|
+
return decodeSlackMrkdwnEntities(inner);
|
|
1157
|
+
}
|
|
1158
|
+
function appendSlackVisibleProjection(projection, visible, excluded) {
|
|
1159
|
+
if (!visible) return;
|
|
1160
|
+
const start = projection.text.length;
|
|
1161
|
+
projection.text += visible;
|
|
1162
|
+
if (!excluded) return;
|
|
1163
|
+
const previous = projection.excludedRanges.at(-1);
|
|
1164
|
+
if (previous?.end === start) previous.end = projection.text.length;
|
|
1165
|
+
else projection.excludedRanges.push({
|
|
1166
|
+
start,
|
|
1167
|
+
end: projection.text.length
|
|
1168
|
+
});
|
|
1169
|
+
}
|
|
1170
|
+
function projectSlackMrkdwnVisibleText(text, dateDisplay) {
|
|
1171
|
+
const projection = {
|
|
1172
|
+
text: "",
|
|
1173
|
+
excludedRanges: []
|
|
1174
|
+
};
|
|
1175
|
+
let activeMarker;
|
|
1176
|
+
let lineHasVisibleContent = false;
|
|
1177
|
+
for (const token of tokenizeSlackMrkdwn(text)) {
|
|
1178
|
+
const transition = resolveSlackCodeMarkerTransition(activeMarker, token);
|
|
1179
|
+
if (transition !== null) {
|
|
1180
|
+
activeMarker = transition;
|
|
1181
|
+
continue;
|
|
1182
|
+
}
|
|
1183
|
+
let visible = token;
|
|
1184
|
+
if (isAllowedSlackAngleToken(token)) visible = activeMarker ? token : projectSlackAngleToken(token, dateDisplay);
|
|
1185
|
+
else if (token === "&" || token === "<" || token === ">") visible = decodeSlackMrkdwnEntities(token);
|
|
1186
|
+
else if (!activeMarker && (token === "*" || token === "_" || token === "~")) visible = "";
|
|
1187
|
+
else if (!activeMarker && token === ">" && !lineHasVisibleContent) visible = "";
|
|
1188
|
+
else if (token.startsWith("\\") && token.length > 1) visible = token.slice(1);
|
|
1189
|
+
appendSlackVisibleProjection(projection, visible, activeMarker !== void 0);
|
|
1190
|
+
for (const character of visible) if (character === "\n") lineHasVisibleContent = false;
|
|
1191
|
+
else if (character !== " " && character !== " " && character !== "\r") lineHasVisibleContent = true;
|
|
1192
|
+
}
|
|
1193
|
+
return projection;
|
|
1194
|
+
}
|
|
1195
|
+
function protectSlackAssistantTranscriptRoleHeaders(text) {
|
|
1196
|
+
if (text.startsWith(SLACK_ASSISTANT_TRANSCRIPT_PREFIX)) return text;
|
|
1197
|
+
if (!slackProjectionHasRoleHeader(projectSlackMrkdwnVisibleText(text, "token")) && (!text.includes("<!date^") || !slackProjectionHasRoleHeader(projectSlackMrkdwnVisibleText(text, "fallback")))) return text;
|
|
1198
|
+
return `${SLACK_ASSISTANT_TRANSCRIPT_PREFIX}${text}`;
|
|
1199
|
+
}
|
|
1200
|
+
function buildSlackRenderOptions() {
|
|
1201
|
+
return {
|
|
1202
|
+
annotationMarkers: { assistant_transcript_role: {
|
|
1203
|
+
open: "`",
|
|
1204
|
+
close: "`",
|
|
1205
|
+
suppressNestedFormatting: true
|
|
1206
|
+
} },
|
|
1207
|
+
styleMarkers: {
|
|
1208
|
+
bold: {
|
|
1209
|
+
open: "*",
|
|
1210
|
+
close: "*"
|
|
1211
|
+
},
|
|
1212
|
+
italic: {
|
|
1213
|
+
open: "_",
|
|
1214
|
+
close: "_"
|
|
1215
|
+
},
|
|
1216
|
+
strikethrough: {
|
|
1217
|
+
open: "~",
|
|
1218
|
+
close: "~"
|
|
1219
|
+
},
|
|
1220
|
+
code: {
|
|
1221
|
+
open: "`",
|
|
1222
|
+
close: "`"
|
|
1223
|
+
},
|
|
1224
|
+
code_block: {
|
|
1225
|
+
open: "```\n",
|
|
1226
|
+
close: "```"
|
|
1227
|
+
}
|
|
1228
|
+
},
|
|
1229
|
+
escapeText: escapeSlackMrkdwnText,
|
|
1230
|
+
buildLink: buildSlackLink
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
function normalizeSlackOutboundText(markdown, options = {}) {
|
|
1234
|
+
const ir = makeSlackEmphasisStylesSafe(markdownToIR(markdown ?? "", {
|
|
1235
|
+
assistantTranscriptRoleHeaders: true,
|
|
1236
|
+
linkify: false,
|
|
1237
|
+
autolink: false,
|
|
1238
|
+
headingStyle: "rich",
|
|
1239
|
+
blockquotePrefix: "> ",
|
|
1240
|
+
tableMode: options.tableMode
|
|
1241
|
+
}));
|
|
1242
|
+
return protectSlackAssistantTranscriptRoleHeaders(renderMarkdownWithMarkers(ir, buildSlackRenderOptions(), SLACK_FORMAT_PROFILE));
|
|
1243
|
+
}
|
|
1244
|
+
/** Chunk already-rendered Slack mrkdwn without splitting entities or code markers. */
|
|
1245
|
+
function chunkSlackMrkdwnText(text, limit) {
|
|
1246
|
+
if (text.length <= limit) return [text];
|
|
1247
|
+
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 });
|
|
1248
|
+
const chunks = [];
|
|
1249
|
+
let activeMarker;
|
|
1250
|
+
let content = "";
|
|
1251
|
+
const wrapper = (marker) => marker && limit > marker.length * 2 ? marker : void 0;
|
|
1252
|
+
const capacity = (marker) => limit - (wrapper(marker)?.length ?? 0);
|
|
1253
|
+
const flush = () => {
|
|
1254
|
+
const marker = wrapper(activeMarker);
|
|
1255
|
+
if (content && content !== marker) chunks.push(marker ? `${content}${marker}` : content);
|
|
1256
|
+
content = "";
|
|
1257
|
+
};
|
|
1258
|
+
for (const token of tokenizeSlackMrkdwn(text)) {
|
|
1259
|
+
const transition = resolveSlackCodeMarkerTransition(activeMarker, token);
|
|
1260
|
+
const nextMarker = transition === null ? activeMarker : transition;
|
|
1261
|
+
const sourceMarker = token === "`" || token === "```" ? token : void 0;
|
|
1262
|
+
if (transition !== null && sourceMarker && !wrapper(sourceMarker)) {
|
|
1263
|
+
activeMarker = nextMarker;
|
|
1264
|
+
continue;
|
|
1265
|
+
}
|
|
1266
|
+
if (content && content.length + token.length > capacity(nextMarker)) flush();
|
|
1267
|
+
activeMarker = nextMarker;
|
|
1268
|
+
if (!content && transition === void 0) continue;
|
|
1269
|
+
content ||= transition === null ? wrapper(activeMarker) ?? "" : "";
|
|
1270
|
+
const contentLimit = capacity(activeMarker) - (wrapper(activeMarker)?.length ?? 0);
|
|
1271
|
+
if (token.length > contentLimit) {
|
|
1272
|
+
flush();
|
|
1273
|
+
const marker = wrapper(activeMarker);
|
|
1274
|
+
if (activeMarker && isAllowedSlackAngleToken(token)) {
|
|
1275
|
+
if (marker) chunks.push(...chunkTextForOutbound(token, Math.max(1, Math.floor(contentLimit)), { preserveWhitespace: true }).map((fragment) => `${marker}${fragment}${marker}`));
|
|
1276
|
+
else chunks.push(...chunkTextForOutbound(escapeSlackMrkdwnSegment(token), Math.max(1, Math.floor(limit)), { preserveWhitespace: true }));
|
|
1277
|
+
continue;
|
|
1278
|
+
}
|
|
1279
|
+
chunks.push(...token.length <= limit ? [token] : chunkTextForOutbound(token, limit));
|
|
1280
|
+
continue;
|
|
1281
|
+
}
|
|
1282
|
+
content += token;
|
|
1283
|
+
}
|
|
1284
|
+
flush();
|
|
1285
|
+
return chunks;
|
|
1286
|
+
}
|
|
1287
|
+
function markdownToSlackMrkdwnChunks(markdown, limit, options = {}) {
|
|
1288
|
+
const ir = makeSlackEmphasisStylesSafe(markdownToIR(markdown ?? "", {
|
|
1289
|
+
assistantTranscriptRoleHeaders: true,
|
|
1290
|
+
linkify: false,
|
|
1291
|
+
autolink: false,
|
|
1292
|
+
headingStyle: "rich",
|
|
1293
|
+
blockquotePrefix: "> ",
|
|
1294
|
+
tableMode: options.tableMode
|
|
1295
|
+
}));
|
|
1296
|
+
const renderOptions = buildSlackRenderOptions();
|
|
1297
|
+
return renderMarkdownIRChunksWithinLimit({
|
|
1298
|
+
ir,
|
|
1299
|
+
limit,
|
|
1300
|
+
renderChunk: (chunk) => protectSlackAssistantTranscriptRoleHeaders(renderMarkdownWithMarkers(chunk, renderOptions, SLACK_FORMAT_PROFILE)),
|
|
1301
|
+
measureRendered: (rendered) => rendered.length
|
|
1302
|
+
}).map(({ rendered }) => rendered);
|
|
1303
|
+
}
|
|
1304
|
+
//#endregion
|
|
1305
|
+
//#region extensions/slack/src/question-actions.ts
|
|
1306
|
+
const SLACK_QUESTION_VALUE_PREFIX = "slq1:";
|
|
1307
|
+
const QUESTION_RECORD_ID_PATTERN = /^ask_[a-f0-9]{32}$/u;
|
|
1308
|
+
function encodeSlackQuestionAction(action) {
|
|
1309
|
+
if (!QUESTION_RECORD_ID_PATTERN.test(action.questionId) || !Number.isInteger(action.optionIndex) || action.optionIndex < 0 || action.optionIndex > 3) return;
|
|
1310
|
+
const value = `${SLACK_QUESTION_VALUE_PREFIX}${action.questionId}:${action.optionIndex}`;
|
|
1311
|
+
return value.length <= 2e3 ? value : void 0;
|
|
1312
|
+
}
|
|
1313
|
+
function decodeSlackQuestionAction(value) {
|
|
1314
|
+
if (typeof value !== "string" || value.length > 2e3) return null;
|
|
1315
|
+
const match = /^slq1:(ask_[a-f0-9]{32}):([0-3])$/u.exec(value);
|
|
1316
|
+
return match?.[1] && match[2] ? {
|
|
1317
|
+
questionId: match[1],
|
|
1318
|
+
optionIndex: Number(match[2])
|
|
1319
|
+
} : null;
|
|
1320
|
+
}
|
|
1321
|
+
async function resolveSlackQuestionAction(params) {
|
|
1322
|
+
let result;
|
|
1323
|
+
try {
|
|
1324
|
+
result = await (params.resolveQuestion ?? questionGatewayRuntime.resolveOption)({
|
|
1325
|
+
cfg: params.cfg,
|
|
1326
|
+
questionId: params.action.questionId,
|
|
1327
|
+
optionIndex: params.action.optionIndex,
|
|
1328
|
+
senderId: params.userId,
|
|
1329
|
+
clientDisplayName: `Slack question (${params.accountId})`
|
|
1330
|
+
});
|
|
1331
|
+
} catch {
|
|
1332
|
+
await params.respond("Could not submit this answer.").catch(() => {});
|
|
1333
|
+
return;
|
|
1334
|
+
}
|
|
1335
|
+
await params.respond(result.status === "answered" ? "Answer submitted." : "This question was already answered.").catch(() => {});
|
|
1336
|
+
}
|
|
1337
|
+
//#endregion
|
|
1338
|
+
//#region extensions/slack/src/reply-action-ids.ts
|
|
1339
|
+
const SLACK_REPLY_BUTTON_ACTION_ID = "openclaw:reply_button";
|
|
1340
|
+
const SLACK_REPLY_LINK_ACTION_ID = "openclaw:reply_link";
|
|
1341
|
+
const SLACK_SESSION_LINK_ACTION_ID = "openclaw:session_link";
|
|
1342
|
+
const SLACK_REPLY_SELECT_ACTION_ID = "openclaw:reply_select";
|
|
1343
|
+
const SLACK_CALLBACK_BUTTON_ACTION_ID = "openclaw:callback_button";
|
|
1344
|
+
const SLACK_CALLBACK_SELECT_ACTION_ID = "openclaw:callback_select";
|
|
1345
|
+
const SLACK_APPROVAL_BUTTON_ACTION_ID = "openclaw:approval_button";
|
|
1346
|
+
const SLACK_APPROVAL_SELECT_ACTION_ID = "openclaw:approval_select";
|
|
1347
|
+
const SLACK_QUESTION_BUTTON_ACTION_ID = "openclaw:question_button";
|
|
1348
|
+
const SLACK_QUESTION_FINALIZATION_BLOCKS = Symbol("slackQuestionFinalizationBlocks");
|
|
1349
|
+
function isSlackQuestionActionId(actionId) {
|
|
1350
|
+
return actionId === "openclaw:question_button" || actionId.startsWith(`openclaw:question_button:`);
|
|
1351
|
+
}
|
|
1352
|
+
/** Read only question control identities from the blocks actually sent to Slack. */
|
|
1353
|
+
function resolveSlackQuestionActionIds(blocks) {
|
|
1354
|
+
return (blocks ?? []).flatMap((block) => {
|
|
1355
|
+
if (block.type !== "actions") return [];
|
|
1356
|
+
return (block.elements ?? []).flatMap(({ action_id }) => action_id && isSlackQuestionActionId(action_id) ? [action_id] : []);
|
|
1357
|
+
});
|
|
1358
|
+
}
|
|
1359
|
+
function isSlackApprovalActionId(actionId) {
|
|
1360
|
+
return actionId === "openclaw:approval_button" || actionId === "openclaw:approval_select" || actionId.startsWith(`openclaw:approval_button:`) || actionId.startsWith(`openclaw:approval_select:`);
|
|
1361
|
+
}
|
|
1362
|
+
function isSlackCallbackActionId(actionId) {
|
|
1363
|
+
return actionId === "openclaw:callback_button" || actionId === "openclaw:callback_select" || actionId.startsWith(`openclaw:callback_button:`) || actionId.startsWith(`openclaw:callback_select:`);
|
|
1364
|
+
}
|
|
1365
|
+
//#endregion
|
|
1366
|
+
//#region extensions/slack/src/truncate.ts
|
|
1367
|
+
function truncateSlackText(value, max) {
|
|
1368
|
+
const trimmed = value.trim();
|
|
1369
|
+
if (trimmed.length <= max) return trimmed;
|
|
1370
|
+
if (max <= 1) return sliceUtf16Safe(trimmed, 0, max);
|
|
1371
|
+
return `${sliceUtf16Safe(trimmed, 0, max - 1)}…`;
|
|
1372
|
+
}
|
|
1373
|
+
function countSlackTextUtf8Bytes(value) {
|
|
1374
|
+
return Buffer.byteLength(value, "utf8");
|
|
1375
|
+
}
|
|
1376
|
+
/** Truncate Slack text without splitting a code point or exceeding a UTF-8 byte limit. */
|
|
1377
|
+
function truncateSlackTextByUtf8Bytes(value, maxBytes) {
|
|
1378
|
+
const trimmed = value.trim();
|
|
1379
|
+
if (maxBytes <= 0) return "";
|
|
1380
|
+
if (countSlackTextUtf8Bytes(trimmed) <= maxBytes) return trimmed;
|
|
1381
|
+
const suffix = "…";
|
|
1382
|
+
const suffixBytes = countSlackTextUtf8Bytes(suffix);
|
|
1383
|
+
const prefixBudget = maxBytes >= suffixBytes ? maxBytes - suffixBytes : maxBytes;
|
|
1384
|
+
let prefix = "";
|
|
1385
|
+
let prefixBytes = 0;
|
|
1386
|
+
for (const character of trimmed) {
|
|
1387
|
+
const characterBytes = countSlackTextUtf8Bytes(character);
|
|
1388
|
+
if (prefixBytes + characterBytes > prefixBudget) break;
|
|
1389
|
+
prefix += character;
|
|
1390
|
+
prefixBytes += characterBytes;
|
|
1391
|
+
}
|
|
1392
|
+
return maxBytes >= suffixBytes ? `${prefix}${suffix}` : prefix;
|
|
1393
|
+
}
|
|
1394
|
+
//#endregion
|
|
1395
|
+
//#region extensions/slack/src/blocks-render.ts
|
|
1396
|
+
const SLACK_BUTTON_URL_MAX = 3e3;
|
|
1397
|
+
function buildSlackReplyButtonActionId(buttonIndex, choiceIndex) {
|
|
1398
|
+
return `${SLACK_REPLY_BUTTON_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
|
|
1399
|
+
}
|
|
1400
|
+
function buildSlackReplyLinkActionId(buttonIndex, choiceIndex) {
|
|
1401
|
+
return `${SLACK_REPLY_LINK_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
|
|
1402
|
+
}
|
|
1403
|
+
function buildSlackReplySelectActionId(selectIndex) {
|
|
1404
|
+
return `${SLACK_REPLY_SELECT_ACTION_ID}:${String(selectIndex)}`;
|
|
1027
1405
|
}
|
|
1028
1406
|
function buildSlackApprovalButtonActionId(buttonIndex, choiceIndex) {
|
|
1029
1407
|
return `${SLACK_APPROVAL_BUTTON_ACTION_ID}:${String(buttonIndex)}:${String(choiceIndex + 1)}`;
|
|
@@ -1044,13 +1422,19 @@ function resolveSlackButtonStyle(style) {
|
|
|
1044
1422
|
if (style === "primary" || style === "danger") return style;
|
|
1045
1423
|
if (style === "success") return "primary";
|
|
1046
1424
|
}
|
|
1047
|
-
function resolveSlackActionTarget(action,
|
|
1425
|
+
function resolveSlackActionTarget(action, questionOptionIndices) {
|
|
1048
1426
|
if (!action) return;
|
|
1049
1427
|
if (action.type === "approval") return {
|
|
1050
1428
|
kind: "approval",
|
|
1051
1429
|
value: encodeSlackApprovalAction(action)
|
|
1052
1430
|
};
|
|
1053
1431
|
if (action.type === "question") {
|
|
1432
|
+
if ("intent" in action) return;
|
|
1433
|
+
const optionIndex = resolveAskUserQuestionOptionIndex({
|
|
1434
|
+
questionOptionIndices,
|
|
1435
|
+
questionId: action.questionId,
|
|
1436
|
+
optionValue: action.optionValue
|
|
1437
|
+
});
|
|
1054
1438
|
const value = optionIndex === void 0 ? void 0 : encodeSlackQuestionAction({
|
|
1055
1439
|
questionId: action.questionId,
|
|
1056
1440
|
optionIndex
|
|
@@ -1080,10 +1464,10 @@ function resolveSlackActionTarget(action, optionIndex) {
|
|
|
1080
1464
|
value: command
|
|
1081
1465
|
} : void 0;
|
|
1082
1466
|
}
|
|
1083
|
-
function resolveSlackButtonTarget(button,
|
|
1467
|
+
function resolveSlackButtonTarget(button, questionOptionIndices) {
|
|
1084
1468
|
if (button.action !== void 0) {
|
|
1085
1469
|
const action = resolveMessagePresentationButtonAction(button);
|
|
1086
|
-
return action ? resolveSlackActionTarget(action,
|
|
1470
|
+
return action ? resolveSlackActionTarget(action, questionOptionIndices) : void 0;
|
|
1087
1471
|
}
|
|
1088
1472
|
const legacyUrl = normalizeOptionalString(button.url ?? button.webApp?.url ?? button.web_app?.url);
|
|
1089
1473
|
if (legacyUrl && isWithinSlackLimit(legacyUrl, SLACK_BUTTON_URL_MAX)) return {
|
|
@@ -1100,6 +1484,10 @@ function resolveSlackButtonTarget(button, optionIndex) {
|
|
|
1100
1484
|
url: legacyUrl
|
|
1101
1485
|
} : void 0;
|
|
1102
1486
|
}
|
|
1487
|
+
function isSlackTextFallbackButton(button) {
|
|
1488
|
+
const action = resolveMessagePresentationButtonAction(button);
|
|
1489
|
+
return action?.type === "question" && "intent" in action && action.intent === "custom-input";
|
|
1490
|
+
}
|
|
1103
1491
|
function resolveSlackOptionTarget(option) {
|
|
1104
1492
|
if (option.action !== void 0) {
|
|
1105
1493
|
const action = resolveMessagePresentationOptionAction(option);
|
|
@@ -1140,91 +1528,18 @@ function resolveSlackBlockOffsets(blocks) {
|
|
|
1140
1528
|
buttonIndexOffset = Math.max(buttonIndexOffset, readSlackOpenClawBlockIndex(blockId, "openclaw_reply_buttons_") ?? 0);
|
|
1141
1529
|
selectIndexOffset = Math.max(selectIndexOffset, readSlackOpenClawBlockIndex(blockId, "openclaw_reply_select_") ?? 0);
|
|
1142
1530
|
}
|
|
1143
|
-
return {
|
|
1144
|
-
buttonIndexOffset,
|
|
1145
|
-
dataTableCellCharacterCountOffset,
|
|
1146
|
-
dataVisualizationCountOffset,
|
|
1147
|
-
selectIndexOffset
|
|
1148
|
-
};
|
|
1149
|
-
}
|
|
1150
|
-
/**
|
|
1151
|
-
* @deprecated Use buildSlackPresentationBlocks with MessagePresentation.
|
|
1152
|
-
*/
|
|
1153
|
-
function buildSlackInteractiveBlocks(interactive, options = {}) {
|
|
1154
|
-
return
|
|
1155
|
-
blocks: [],
|
|
1156
|
-
buttonIndex: options.buttonIndexOffset ?? 0,
|
|
1157
|
-
selectIndex: options.selectIndexOffset ?? 0
|
|
1158
|
-
}, (state, block) => {
|
|
1159
|
-
if (block.type === "text") {
|
|
1160
|
-
const trimmed = block.text.trim();
|
|
1161
|
-
if (!trimmed) return state;
|
|
1162
|
-
state.blocks.push({
|
|
1163
|
-
type: "section",
|
|
1164
|
-
text: {
|
|
1165
|
-
type: "mrkdwn",
|
|
1166
|
-
text: truncateSlackText(trimmed, SLACK_SECTION_TEXT_MAX)
|
|
1167
|
-
}
|
|
1168
|
-
});
|
|
1169
|
-
return state;
|
|
1170
|
-
}
|
|
1171
|
-
if (block.type === "buttons") {
|
|
1172
|
-
const elements = block.buttons.flatMap((button, choiceIndex) => {
|
|
1173
|
-
const target = resolveSlackButtonTarget(button, choiceIndex);
|
|
1174
|
-
if (!target || (target.kind === "link" ? !isWithinSlackLimit(target.url, SLACK_BUTTON_URL_MAX) : !isWithinSlackLimit(target.value, 2e3))) return [];
|
|
1175
|
-
const style = resolveSlackButtonStyle(button.style);
|
|
1176
|
-
return [{
|
|
1177
|
-
type: "button",
|
|
1178
|
-
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),
|
|
1179
|
-
text: {
|
|
1180
|
-
type: "plain_text",
|
|
1181
|
-
text: truncateSlackText(button.label, 75),
|
|
1182
|
-
emoji: true
|
|
1183
|
-
},
|
|
1184
|
-
...target.kind === "link" ? { url: target.url } : { value: target.value },
|
|
1185
|
-
...style ? { style } : {}
|
|
1186
|
-
}];
|
|
1187
|
-
}).slice(0, 25);
|
|
1188
|
-
if (elements.length === 0) return state;
|
|
1189
|
-
state.blocks.push({
|
|
1190
|
-
type: "actions",
|
|
1191
|
-
block_id: `openclaw_reply_buttons_${++state.buttonIndex}`,
|
|
1192
|
-
elements
|
|
1193
|
-
});
|
|
1194
|
-
return state;
|
|
1195
|
-
}
|
|
1196
|
-
const optionsLocal = block.options.flatMap((option) => {
|
|
1197
|
-
const target = resolveSlackOptionTarget(option);
|
|
1198
|
-
return target ? [{
|
|
1199
|
-
label: option.label,
|
|
1200
|
-
...target
|
|
1201
|
-
}] : [];
|
|
1202
|
-
}).filter(isRenderableSlackOption).slice(0, 100);
|
|
1203
|
-
const optionKinds = new Set(optionsLocal.map((option) => option.kind));
|
|
1204
|
-
if (optionsLocal.length === 0 || optionKinds.size !== 1) return state;
|
|
1205
|
-
state.blocks.push({
|
|
1206
|
-
type: "actions",
|
|
1207
|
-
block_id: `openclaw_reply_select_${++state.selectIndex}`,
|
|
1208
|
-
elements: [{
|
|
1209
|
-
type: "static_select",
|
|
1210
|
-
action_id: optionsLocal[0]?.kind === "approval" ? buildSlackApprovalSelectActionId(state.selectIndex) : optionsLocal[0]?.kind === "callback" ? buildSlackCallbackSelectActionId(state.selectIndex) : buildSlackReplySelectActionId(state.selectIndex),
|
|
1211
|
-
placeholder: {
|
|
1212
|
-
type: "plain_text",
|
|
1213
|
-
text: truncateSlackText(normalizeOptionalString(block.placeholder) ?? "Choose an option", 75),
|
|
1214
|
-
emoji: true
|
|
1215
|
-
},
|
|
1216
|
-
options: optionsLocal.map((option, _choiceIndex) => ({
|
|
1217
|
-
text: {
|
|
1218
|
-
type: "plain_text",
|
|
1219
|
-
text: truncateSlackText(option.label, 75),
|
|
1220
|
-
emoji: true
|
|
1221
|
-
},
|
|
1222
|
-
value: option.value
|
|
1223
|
-
}))
|
|
1224
|
-
}]
|
|
1225
|
-
});
|
|
1226
|
-
return state;
|
|
1227
|
-
}).blocks;
|
|
1531
|
+
return {
|
|
1532
|
+
buttonIndexOffset,
|
|
1533
|
+
dataTableCellCharacterCountOffset,
|
|
1534
|
+
dataVisualizationCountOffset,
|
|
1535
|
+
selectIndexOffset
|
|
1536
|
+
};
|
|
1537
|
+
}
|
|
1538
|
+
/**
|
|
1539
|
+
* @deprecated Use buildSlackPresentationBlocks with MessagePresentation.
|
|
1540
|
+
*/
|
|
1541
|
+
function buildSlackInteractiveBlocks(interactive, options = {}) {
|
|
1542
|
+
return buildSlackPresentationBlocks(interactive ? legacyInteractiveReplyToPresentation(interactive) : void 0, options);
|
|
1228
1543
|
}
|
|
1229
1544
|
/** Render portable presentation blocks as Slack Block Kit blocks. */
|
|
1230
1545
|
function buildSlackPresentationBlocks(presentation, options = {}) {
|
|
@@ -1247,19 +1562,18 @@ function buildSlackPresentationBlocks(presentation, options = {}) {
|
|
|
1247
1562
|
if (block.type === "text" || block.type === "context") {
|
|
1248
1563
|
const text = block.text.trim();
|
|
1249
1564
|
if (!text) continue;
|
|
1250
|
-
|
|
1565
|
+
for (const chunk of chunkSlackMrkdwnText(text, SLACK_SECTION_TEXT_MAX)) blocks.push(block.type === "context" ? {
|
|
1251
1566
|
type: "context",
|
|
1252
1567
|
elements: [{
|
|
1253
1568
|
type: "mrkdwn",
|
|
1254
|
-
text:
|
|
1569
|
+
text: chunk,
|
|
1255
1570
|
verbatim: true
|
|
1256
1571
|
}]
|
|
1257
|
-
}
|
|
1258
|
-
else blocks.push({
|
|
1572
|
+
} : {
|
|
1259
1573
|
type: "section",
|
|
1260
1574
|
text: {
|
|
1261
1575
|
type: "mrkdwn",
|
|
1262
|
-
text:
|
|
1576
|
+
text: chunk
|
|
1263
1577
|
}
|
|
1264
1578
|
});
|
|
1265
1579
|
continue;
|
|
@@ -1269,7 +1583,7 @@ function buildSlackPresentationBlocks(presentation, options = {}) {
|
|
|
1269
1583
|
continue;
|
|
1270
1584
|
}
|
|
1271
1585
|
if (block.type === "buttons") {
|
|
1272
|
-
const rendered = buildSlackPresentationButtonBlock(block, buttonIndex + 1);
|
|
1586
|
+
const rendered = buildSlackPresentationButtonBlock(block, buttonIndex + 1, options.questionOptionIndices);
|
|
1273
1587
|
if (rendered) {
|
|
1274
1588
|
buttonIndex += 1;
|
|
1275
1589
|
blocks.push(rendered);
|
|
@@ -1316,9 +1630,9 @@ function buildSlackPresentationBlocks(presentation, options = {}) {
|
|
|
1316
1630
|
function buildSlackPresentationChartBlock(block) {
|
|
1317
1631
|
return buildSlackDataVisualizationBlock(block);
|
|
1318
1632
|
}
|
|
1319
|
-
function buildSlackPresentationButtonBlock(block, buttonIndex) {
|
|
1633
|
+
function buildSlackPresentationButtonBlock(block, buttonIndex, questionOptionIndices) {
|
|
1320
1634
|
const elements = block.buttons.flatMap((button, choiceIndex) => {
|
|
1321
|
-
const target = resolveSlackButtonTarget(button,
|
|
1635
|
+
const target = resolveSlackButtonTarget(button, questionOptionIndices);
|
|
1322
1636
|
if (!target || (target.kind === "link" ? !isWithinSlackLimit(target.url, SLACK_BUTTON_URL_MAX) : !isWithinSlackLimit(target.value, 2e3))) return [];
|
|
1323
1637
|
const style = resolveSlackButtonStyle(button.style);
|
|
1324
1638
|
return [{
|
|
@@ -1356,16 +1670,16 @@ function canRenderSlackPresentation(presentation, options = {}) {
|
|
|
1356
1670
|
if (!canRenderSlackPresentationTables(presentation, options)) return false;
|
|
1357
1671
|
let dataVisualizationCount = options.dataVisualizationCountOffset ?? 0;
|
|
1358
1672
|
for (const block of presentation.blocks) {
|
|
1359
|
-
if (block.type === "text" || block.type === "context")
|
|
1360
|
-
if (!isWithinSlackLimit(block.text.trim(), 3e3)) return false;
|
|
1361
|
-
continue;
|
|
1362
|
-
}
|
|
1673
|
+
if (block.type === "text" || block.type === "context") continue;
|
|
1363
1674
|
if (block.type === "buttons") {
|
|
1364
|
-
|
|
1675
|
+
let nativeButtonCount = 0;
|
|
1676
|
+
if (!(block.buttons.every((button) => {
|
|
1677
|
+
if (isSlackTextFallbackButton(button)) return true;
|
|
1678
|
+
nativeButtonCount += 1;
|
|
1365
1679
|
if (!isWithinSlackLimit(button.label, 75)) return false;
|
|
1366
|
-
const target = resolveSlackButtonTarget(button,
|
|
1680
|
+
const target = resolveSlackButtonTarget(button, options.questionOptionIndices);
|
|
1367
1681
|
return target ? target.kind === "link" ? isWithinSlackLimit(target.url, SLACK_BUTTON_URL_MAX) : isWithinSlackLimit(target.value, 2e3) : false;
|
|
1368
|
-
}))) return false;
|
|
1682
|
+
}) && nativeButtonCount <= 25)) return false;
|
|
1369
1683
|
continue;
|
|
1370
1684
|
}
|
|
1371
1685
|
if (block.type === "select") {
|
|
@@ -1476,474 +1790,121 @@ function readTextObject(value, options = {}) {
|
|
|
1476
1790
|
function readTextValue(value, options = {}) {
|
|
1477
1791
|
return normalizeOptionalString(value) ?? readTextObject(value, options);
|
|
1478
1792
|
}
|
|
1479
|
-
function
|
|
1793
|
+
function renderSlackRichTextElement(value, renderReference) {
|
|
1794
|
+
const element = asOptionalRecord(value);
|
|
1795
|
+
if (!element) return "";
|
|
1480
1796
|
switch (element.type) {
|
|
1797
|
+
case "rich_text_section":
|
|
1798
|
+
case "rich_text_preformatted":
|
|
1799
|
+
case "rich_text_quote": return renderSlackRichTextElements(element.elements, "", renderReference);
|
|
1800
|
+
case "rich_text_list": return renderSlackRichTextElements(element.elements, "\n", renderReference);
|
|
1481
1801
|
case "text": return typeof element.text === "string" ? escapeSlackMrkdwn(element.text) : "";
|
|
1482
1802
|
case "link": return escapeSlackMrkdwn(normalizeOptionalString(element.text) ?? normalizeOptionalString(element.url) ?? "");
|
|
1483
1803
|
case "user": {
|
|
1484
1804
|
const userId = normalizeOptionalString(element.user_id);
|
|
1485
|
-
return userId ?
|
|
1805
|
+
return userId ? renderReference(`<@${userId}>`) : "";
|
|
1486
1806
|
}
|
|
1487
1807
|
case "channel": {
|
|
1488
1808
|
const channelId = normalizeOptionalString(element.channel_id);
|
|
1489
|
-
return channelId ?
|
|
1809
|
+
return channelId ? renderReference(`<#${channelId}>`) : "";
|
|
1490
1810
|
}
|
|
1491
1811
|
case "usergroup": {
|
|
1492
1812
|
const usergroupId = normalizeOptionalString(element.usergroup_id);
|
|
1493
|
-
return usergroupId ?
|
|
1813
|
+
return usergroupId ? renderReference(`<!subteam^${usergroupId}>`) : "";
|
|
1494
1814
|
}
|
|
1495
1815
|
case "broadcast": {
|
|
1496
1816
|
const range = normalizeOptionalString(element.range);
|
|
1497
|
-
return range ?
|
|
1817
|
+
return range ? renderReference(`<!${range}>`) : "";
|
|
1498
1818
|
}
|
|
1499
1819
|
case "emoji": {
|
|
1500
1820
|
const name = normalizeOptionalString(element.name);
|
|
1501
|
-
return name ? `:${name}:` : "";
|
|
1502
|
-
}
|
|
1503
|
-
case "date": return escapeSlackMrkdwn(normalizeOptionalString(element.fallback) ?? "");
|
|
1504
|
-
default: return "";
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
function renderSlackRichTextElement(value) {
|
|
1508
|
-
const element = asOptionalRecord(value);
|
|
1509
|
-
if (!element) return "";
|
|
1510
|
-
switch (element.type) {
|
|
1511
|
-
case "rich_text_section":
|
|
1512
|
-
case "rich_text_preformatted":
|
|
1513
|
-
case "rich_text_quote": return renderSlackRichTextElements(element.elements, "");
|
|
1514
|
-
case "rich_text_list": return renderSlackRichTextElements(element.elements, "\n");
|
|
1515
|
-
default: return renderSlackRichTextLeaf(element);
|
|
1516
|
-
}
|
|
1517
|
-
}
|
|
1518
|
-
function renderSlackRichTextElements(value, separator) {
|
|
1519
|
-
if (!Array.isArray(value)) return "";
|
|
1520
|
-
return value.map(renderSlackRichTextElement).filter(Boolean).join(separator);
|
|
1521
|
-
}
|
|
1522
|
-
function readImageText(block) {
|
|
1523
|
-
const altText = normalizeOptionalString(block.alt_text);
|
|
1524
|
-
return (altText ? escapeSlackMrkdwn(altText) : void 0) ?? readTextObject(block.title);
|
|
1525
|
-
}
|
|
1526
|
-
function readVideoText(block, options = {}) {
|
|
1527
|
-
const altText = normalizeOptionalString(block.alt_text);
|
|
1528
|
-
return readTextObject(block.title, options) ?? (altText ? escapeSlackMrkdwn(altText) : void 0);
|
|
1529
|
-
}
|
|
1530
|
-
function readContextText(block, options = {}) {
|
|
1531
|
-
if (!Array.isArray(block.elements)) return;
|
|
1532
|
-
const parts = block.elements.map((element) => {
|
|
1533
|
-
const record = asOptionalRecord(element);
|
|
1534
|
-
const altText = normalizeOptionalString(record?.alt_text);
|
|
1535
|
-
return readTextObject(record, options) ?? (altText ? escapeSlackMrkdwn(altText) : void 0);
|
|
1536
|
-
}).filter((part) => Boolean(part));
|
|
1537
|
-
return parts.length > 0 ? parts.join(" ") : void 0;
|
|
1538
|
-
}
|
|
1539
|
-
function readControlElementText(value, options = {}) {
|
|
1540
|
-
const element = asOptionalRecord(value);
|
|
1541
|
-
const type = normalizeOptionalString(element?.type);
|
|
1542
|
-
if (type === "button" || type === "workflow_button") return readTextValue(element?.text, options);
|
|
1543
|
-
if (type && SLACK_SELECT_ELEMENT_TYPES.has(type)) return readTextObject(element?.placeholder, options);
|
|
1544
|
-
}
|
|
1545
|
-
function readControlElementsText(values, options = {}) {
|
|
1546
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1547
|
-
const labels = [];
|
|
1548
|
-
for (const value of values) {
|
|
1549
|
-
const candidate = readControlElementText(value, options);
|
|
1550
|
-
if (!candidate || seen.has(candidate)) continue;
|
|
1551
|
-
seen.add(candidate);
|
|
1552
|
-
labels.push(candidate);
|
|
1553
|
-
}
|
|
1554
|
-
return labels.length > 0 ? labels.join("\n") : void 0;
|
|
1555
|
-
}
|
|
1556
|
-
function readSectionText(block, options = {}) {
|
|
1557
|
-
const parts = [readTextObject(block.text, options)];
|
|
1558
|
-
if (Array.isArray(block.fields)) parts.push(...block.fields.map((field) => readTextObject(field, options)));
|
|
1559
|
-
parts.push(readControlElementText(block.accessory, options));
|
|
1560
|
-
const visibleParts = parts.filter((part) => Boolean(part));
|
|
1561
|
-
return visibleParts.length > 0 ? visibleParts.join("\n") : void 0;
|
|
1562
|
-
}
|
|
1563
|
-
function readActionsText(block, options = {}) {
|
|
1564
|
-
return Array.isArray(block.elements) ? readControlElementsText(block.elements, options) : void 0;
|
|
1565
|
-
}
|
|
1566
|
-
/** Read only user-visible text from one Slack block. */
|
|
1567
|
-
function renderSlackBlockFallbackText(raw, options = {}) {
|
|
1568
|
-
const block = asOptionalRecord(raw);
|
|
1569
|
-
if (!block) return;
|
|
1570
|
-
switch (block.type) {
|
|
1571
|
-
case "rich_text": return normalizeOptionalString(renderSlackRichTextElements(block.elements, "\n"));
|
|
1572
|
-
case "header": return readTextObject(block.text, options);
|
|
1573
|
-
case "section": return readSectionText(block, options);
|
|
1574
|
-
case "image": return readImageText(block) ?? "Shared an image";
|
|
1575
|
-
case "video": return readVideoText(block, options) ?? "Shared a video";
|
|
1576
|
-
case "file": return "Shared a file";
|
|
1577
|
-
case "context": return readContextText(block, options);
|
|
1578
|
-
case "actions": return readActionsText(block, options);
|
|
1579
|
-
case "data_visualization": return options.nativeDataFormat === "plain" ? renderSlackDataVisualizationFallbackText(block) : renderSlackDataVisualizationMrkdwnFallbackText(block);
|
|
1580
|
-
case "data_table": return options.nativeDataFormat === "plain" ? renderSlackDataTableFallbackText(block) : renderSlackDataTableMrkdwnFallbackText(block);
|
|
1581
|
-
case "table": return options.nativeDataFormat === "plain" ? renderSlackTableFallbackText(block) : renderSlackTableMrkdwnFallbackText(block);
|
|
1582
|
-
default: return;
|
|
1583
|
-
}
|
|
1584
|
-
}
|
|
1585
|
-
function buildSlackBlocksFallbackText(blocks) {
|
|
1586
|
-
for (const block of blocks) {
|
|
1587
|
-
const text = renderSlackBlockFallbackText(block);
|
|
1588
|
-
if (text) return text;
|
|
1589
|
-
}
|
|
1590
|
-
return "Shared a Block Kit message";
|
|
1591
|
-
}
|
|
1592
|
-
function buildSlackCompleteBlocksFallbackText(blocks) {
|
|
1593
|
-
return blocks.map((block) => renderSlackBlockFallbackText(block)).filter(Boolean).join("\n\n").trim() || buildSlackBlocksFallbackText(blocks);
|
|
1594
|
-
}
|
|
1595
|
-
//#endregion
|
|
1596
|
-
//#region extensions/slack/src/format.ts
|
|
1597
|
-
function escapeSlackMrkdwnSegment(text) {
|
|
1598
|
-
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1599
|
-
}
|
|
1600
|
-
const SLACK_ANGLE_TOKEN_RE = /<[^>\n]+>/g;
|
|
1601
|
-
function isAllowedSlackAngleToken(token) {
|
|
1602
|
-
if (!token.startsWith("<") || !token.endsWith(">")) return false;
|
|
1603
|
-
const inner = token.slice(1, -1);
|
|
1604
|
-
return inner.startsWith("@") || inner.startsWith("#") || inner.startsWith("!") || inner.startsWith("mailto:") || inner.startsWith("tel:") || inner.startsWith("http://") || inner.startsWith("https://") || inner.startsWith("slack://");
|
|
1605
|
-
}
|
|
1606
|
-
function escapeSlackMrkdwnContent(text) {
|
|
1607
|
-
if (!text) return "";
|
|
1608
|
-
if (!text.includes("&") && !text.includes("<") && !text.includes(">")) return text;
|
|
1609
|
-
SLACK_ANGLE_TOKEN_RE.lastIndex = 0;
|
|
1610
|
-
const out = [];
|
|
1611
|
-
let lastIndex = 0;
|
|
1612
|
-
for (let match = SLACK_ANGLE_TOKEN_RE.exec(text); match; match = SLACK_ANGLE_TOKEN_RE.exec(text)) {
|
|
1613
|
-
const matchIndex = match.index ?? 0;
|
|
1614
|
-
out.push(escapeSlackMrkdwnSegment(text.slice(lastIndex, matchIndex)));
|
|
1615
|
-
const token = match[0] ?? "";
|
|
1616
|
-
out.push(isAllowedSlackAngleToken(token) ? token : escapeSlackMrkdwnSegment(token));
|
|
1617
|
-
lastIndex = matchIndex + token.length;
|
|
1618
|
-
}
|
|
1619
|
-
out.push(escapeSlackMrkdwnSegment(text.slice(lastIndex)));
|
|
1620
|
-
return out.join("");
|
|
1621
|
-
}
|
|
1622
|
-
function escapeSlackMrkdwnText(text) {
|
|
1623
|
-
if (!text) return "";
|
|
1624
|
-
if (!text.includes("&") && !text.includes("<") && !text.includes(">")) return text;
|
|
1625
|
-
return text.split("\n").map((line) => {
|
|
1626
|
-
if (line.startsWith("> ")) return `> ${escapeSlackMrkdwnContent(line.slice(2))}`;
|
|
1627
|
-
return escapeSlackMrkdwnContent(line);
|
|
1628
|
-
}).join("\n");
|
|
1629
|
-
}
|
|
1630
|
-
function buildSlackLink(link, text) {
|
|
1631
|
-
const href = link.href.trim();
|
|
1632
|
-
if (!href) return null;
|
|
1633
|
-
const trimmedLabel = text.slice(link.start, link.end).trim();
|
|
1634
|
-
const comparableHref = href.startsWith("mailto:") ? href.slice(7) : href;
|
|
1635
|
-
if (!(trimmedLabel.length > 0 && trimmedLabel !== href && trimmedLabel !== comparableHref)) return null;
|
|
1636
|
-
const safeHref = escapeSlackMrkdwnSegment(href);
|
|
1637
|
-
return {
|
|
1638
|
-
start: link.start,
|
|
1639
|
-
end: link.end,
|
|
1640
|
-
open: `<${safeHref}|`,
|
|
1641
|
-
close: ">"
|
|
1642
|
-
};
|
|
1643
|
-
}
|
|
1644
|
-
const SLACK_MRKDWN_WORD_CHARACTER_RE = /[\p{L}\p{M}\p{N}_]/u;
|
|
1645
|
-
const SLACK_MRKDWN_PUNCTUATION_RE = /\p{P}/u;
|
|
1646
|
-
const SLACK_MRKDWN_SYMBOL_RE = /\p{S}/u;
|
|
1647
|
-
const SLACK_MRKDWN_CJK_SCRIPT_RE = /[\p{Script_Extensions=Han}\p{Script_Extensions=Hiragana}\p{Script_Extensions=Katakana}\p{Script_Extensions=Hangul}]/u;
|
|
1648
|
-
const SLACK_MRKDWN_EMOJI_PRESENTATION_RE = /\p{Emoji_Presentation}/u;
|
|
1649
|
-
function getCodePointBefore(text, index) {
|
|
1650
|
-
if (index <= 0) return "";
|
|
1651
|
-
const lastCodeUnit = text.charCodeAt(index - 1);
|
|
1652
|
-
if (lastCodeUnit >= 56320 && lastCodeUnit <= 57343 && index > 1) {
|
|
1653
|
-
const previousCodeUnit = text.charCodeAt(index - 2);
|
|
1654
|
-
if (previousCodeUnit >= 55296 && previousCodeUnit <= 56319) return text.slice(index - 2, index);
|
|
1655
|
-
}
|
|
1656
|
-
return text[index - 1] ?? "";
|
|
1657
|
-
}
|
|
1658
|
-
function getCodePointAt(text, index) {
|
|
1659
|
-
const codePoint = text.codePointAt(index);
|
|
1660
|
-
return codePoint === void 0 ? "" : String.fromCodePoint(codePoint);
|
|
1661
|
-
}
|
|
1662
|
-
function isSlackCjkPunctuation(character) {
|
|
1663
|
-
if (!SLACK_MRKDWN_PUNCTUATION_RE.test(character)) return false;
|
|
1664
|
-
if (SLACK_MRKDWN_CJK_SCRIPT_RE.test(character)) return true;
|
|
1665
|
-
const codePoint = character.codePointAt(0);
|
|
1666
|
-
if (codePoint === void 0) return false;
|
|
1667
|
-
const width = eastAsianWidthType(codePoint);
|
|
1668
|
-
return width === "fullwidth" || width === "halfwidth" || width === "wide" && !SLACK_MRKDWN_EMOJI_PRESENTATION_RE.test(character);
|
|
1669
|
-
}
|
|
1670
|
-
function isUnsafeSlackEmphasisBoundary(character) {
|
|
1671
|
-
if (SLACK_MRKDWN_WORD_CHARACTER_RE.test(character)) return true;
|
|
1672
|
-
const codePoint = character.codePointAt(0);
|
|
1673
|
-
if (codePoint === void 0 || codePoint <= 127) return false;
|
|
1674
|
-
return SLACK_MRKDWN_SYMBOL_RE.test(character) || isSlackCjkPunctuation(character);
|
|
1675
|
-
}
|
|
1676
|
-
function makeSlackEmphasisStylesSafe(ir) {
|
|
1677
|
-
const styles = ir.styles.filter((span) => {
|
|
1678
|
-
if (span.style !== "italic" && span.style !== "bold") return true;
|
|
1679
|
-
return !isUnsafeSlackEmphasisBoundary(getCodePointBefore(ir.text, span.start)) && !isUnsafeSlackEmphasisBoundary(getCodePointAt(ir.text, span.end));
|
|
1680
|
-
});
|
|
1681
|
-
return styles.length === ir.styles.length ? ir : {
|
|
1682
|
-
...ir,
|
|
1683
|
-
styles
|
|
1684
|
-
};
|
|
1685
|
-
}
|
|
1686
|
-
const SLACK_FORMAT_PROFILE = FormatCapabilityProfile.define({
|
|
1687
|
-
mechanism: "markdown",
|
|
1688
|
-
constructs: {
|
|
1689
|
-
underline: "strip",
|
|
1690
|
-
spoiler: "fallback",
|
|
1691
|
-
codeLanguage: "fallback",
|
|
1692
|
-
heading: "fallback",
|
|
1693
|
-
bulletList: "fallback",
|
|
1694
|
-
orderedList: "fallback",
|
|
1695
|
-
taskList: "fallback",
|
|
1696
|
-
table: "fallback",
|
|
1697
|
-
image: "fallback"
|
|
1698
|
-
},
|
|
1699
|
-
chunk: {
|
|
1700
|
-
limit: 4e3,
|
|
1701
|
-
unit: "chars",
|
|
1702
|
-
hardCap: 4e4
|
|
1703
|
-
}
|
|
1704
|
-
});
|
|
1705
|
-
const SLACK_ASSISTANT_TRANSCRIPT_PREFIX = "`Assistant:` ";
|
|
1706
|
-
function tokenizeSlackMrkdwn(text) {
|
|
1707
|
-
const tokens = [];
|
|
1708
|
-
for (let index = 0; index < text.length;) {
|
|
1709
|
-
if (text.startsWith("```", index)) {
|
|
1710
|
-
tokens.push("```");
|
|
1711
|
-
index += 3;
|
|
1712
|
-
continue;
|
|
1713
|
-
}
|
|
1714
|
-
const entity = [
|
|
1715
|
-
"&",
|
|
1716
|
-
"<",
|
|
1717
|
-
">"
|
|
1718
|
-
].find((candidate) => text.startsWith(candidate, index));
|
|
1719
|
-
if (entity) {
|
|
1720
|
-
tokens.push(entity);
|
|
1721
|
-
index += entity.length;
|
|
1722
|
-
continue;
|
|
1723
|
-
}
|
|
1724
|
-
if (text[index] === "<") {
|
|
1725
|
-
const end = text.indexOf(">", index + 1);
|
|
1726
|
-
const angleToken = end >= 0 ? text.slice(index, end + 1) : void 0;
|
|
1727
|
-
if (angleToken && !angleToken.includes("\n") && isAllowedSlackAngleToken(angleToken)) {
|
|
1728
|
-
tokens.push(angleToken);
|
|
1729
|
-
index += angleToken.length;
|
|
1730
|
-
continue;
|
|
1731
|
-
}
|
|
1732
|
-
}
|
|
1733
|
-
const codePoint = text.codePointAt(index);
|
|
1734
|
-
if (codePoint === void 0) break;
|
|
1735
|
-
const character = String.fromCodePoint(codePoint);
|
|
1736
|
-
index += character.length;
|
|
1737
|
-
if (character === "\\" && index < text.length) {
|
|
1738
|
-
const escapedCodePoint = text.codePointAt(index);
|
|
1739
|
-
if (escapedCodePoint !== void 0) {
|
|
1740
|
-
const escapedCharacter = String.fromCodePoint(escapedCodePoint);
|
|
1741
|
-
tokens.push(character + escapedCharacter);
|
|
1742
|
-
index += escapedCharacter.length;
|
|
1743
|
-
continue;
|
|
1744
|
-
}
|
|
1821
|
+
return name ? `:${name}:` : "";
|
|
1745
1822
|
}
|
|
1746
|
-
|
|
1823
|
+
case "date": return escapeSlackMrkdwn(normalizeOptionalString(element.fallback) ?? "");
|
|
1824
|
+
default: return "";
|
|
1747
1825
|
}
|
|
1748
|
-
return tokens;
|
|
1749
|
-
}
|
|
1750
|
-
function resolveSlackCodeMarkerTransition(active, token) {
|
|
1751
|
-
if (token === "```" && active !== "`") return active === "```" ? void 0 : "```";
|
|
1752
|
-
if (token === "`" && active !== "```") return active === "`" ? void 0 : "`";
|
|
1753
|
-
return null;
|
|
1754
|
-
}
|
|
1755
|
-
function maskSlackExcludedText(text) {
|
|
1756
|
-
return text.split("\n").map((line) => line.trim() ? `x${" ".repeat(Math.max(0, line.length - 1))}` : " ".repeat(line.length)).join("\n");
|
|
1757
1826
|
}
|
|
1758
|
-
function
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
for (const range of projection.excludedRanges) {
|
|
1762
|
-
masked += projection.text.slice(cursor, range.start);
|
|
1763
|
-
masked += maskSlackExcludedText(projection.text.slice(range.start, range.end));
|
|
1764
|
-
cursor = range.end;
|
|
1765
|
-
}
|
|
1766
|
-
return masked + projection.text.slice(cursor);
|
|
1827
|
+
function renderSlackRichTextElements(value, separator, renderReference) {
|
|
1828
|
+
if (!Array.isArray(value)) return "";
|
|
1829
|
+
return value.map((element) => renderSlackRichTextElement(element, renderReference)).filter(Boolean).join(separator);
|
|
1767
1830
|
}
|
|
1768
|
-
function
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
autolink: false,
|
|
1772
|
-
blockquotePrefix: "",
|
|
1773
|
-
headingStyle: "none",
|
|
1774
|
-
linkify: false,
|
|
1775
|
-
tableMode: "off"
|
|
1776
|
-
}).annotations?.some((annotation) => annotation.type === "assistant_transcript_role"));
|
|
1831
|
+
function readImageText(block) {
|
|
1832
|
+
const altText = normalizeOptionalString(block.alt_text);
|
|
1833
|
+
return (altText ? escapeSlackMrkdwn(altText) : void 0) ?? readTextObject(block.title);
|
|
1777
1834
|
}
|
|
1778
|
-
function
|
|
1779
|
-
|
|
1835
|
+
function readVideoText(block, options = {}) {
|
|
1836
|
+
const altText = normalizeOptionalString(block.alt_text);
|
|
1837
|
+
return readTextObject(block.title, options) ?? (altText ? escapeSlackMrkdwn(altText) : void 0);
|
|
1780
1838
|
}
|
|
1781
|
-
function
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
const
|
|
1785
|
-
const
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
const labelSeparator = inner.indexOf("|");
|
|
1790
|
-
if (labelSeparator >= 0) return decodeSlackMrkdwnEntities(inner.slice(labelSeparator + 1));
|
|
1791
|
-
if (inner.startsWith("@")) return "@";
|
|
1792
|
-
if (inner.startsWith("#")) return "#";
|
|
1793
|
-
if (inner.startsWith("!")) return "!";
|
|
1794
|
-
return decodeSlackMrkdwnEntities(inner);
|
|
1839
|
+
function readContextText(block, options = {}) {
|
|
1840
|
+
if (!Array.isArray(block.elements)) return;
|
|
1841
|
+
const parts = block.elements.map((element) => {
|
|
1842
|
+
const record = asOptionalRecord(element);
|
|
1843
|
+
const altText = normalizeOptionalString(record?.alt_text);
|
|
1844
|
+
return readTextObject(record, options) ?? (altText ? escapeSlackMrkdwn(altText) : void 0);
|
|
1845
|
+
}).filter((part) => Boolean(part));
|
|
1846
|
+
return parts.length > 0 ? parts.join(" ") : void 0;
|
|
1795
1847
|
}
|
|
1796
|
-
function
|
|
1797
|
-
|
|
1798
|
-
const
|
|
1799
|
-
|
|
1800
|
-
if (
|
|
1801
|
-
const previous = projection.excludedRanges.at(-1);
|
|
1802
|
-
if (previous?.end === start) previous.end = projection.text.length;
|
|
1803
|
-
else projection.excludedRanges.push({
|
|
1804
|
-
start,
|
|
1805
|
-
end: projection.text.length
|
|
1806
|
-
});
|
|
1848
|
+
function readControlElementText(value, options = {}) {
|
|
1849
|
+
const element = asOptionalRecord(value);
|
|
1850
|
+
const type = normalizeOptionalString(element?.type);
|
|
1851
|
+
if (type === "button" || type === "workflow_button") return readTextValue(element?.text, options);
|
|
1852
|
+
if (type && SLACK_SELECT_ELEMENT_TYPES.has(type)) return readTextObject(element?.placeholder, options);
|
|
1807
1853
|
}
|
|
1808
|
-
function
|
|
1809
|
-
const
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
const transition = resolveSlackCodeMarkerTransition(activeMarker, token);
|
|
1817
|
-
if (transition !== null) {
|
|
1818
|
-
activeMarker = transition;
|
|
1819
|
-
continue;
|
|
1820
|
-
}
|
|
1821
|
-
let visible = token;
|
|
1822
|
-
if (isAllowedSlackAngleToken(token)) visible = activeMarker ? token : projectSlackAngleToken(token, dateDisplay);
|
|
1823
|
-
else if (token === "&" || token === "<" || token === ">") visible = decodeSlackMrkdwnEntities(token);
|
|
1824
|
-
else if (!activeMarker && (token === "*" || token === "_" || token === "~")) visible = "";
|
|
1825
|
-
else if (!activeMarker && token === ">" && !lineHasVisibleContent) visible = "";
|
|
1826
|
-
else if (token.startsWith("\\") && token.length > 1) visible = token.slice(1);
|
|
1827
|
-
appendSlackVisibleProjection(projection, visible, activeMarker !== void 0);
|
|
1828
|
-
for (const character of visible) if (character === "\n") lineHasVisibleContent = false;
|
|
1829
|
-
else if (character !== " " && character !== " " && character !== "\r") lineHasVisibleContent = true;
|
|
1854
|
+
function readControlElementsText(values, options = {}) {
|
|
1855
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1856
|
+
const labels = [];
|
|
1857
|
+
for (const value of values) {
|
|
1858
|
+
const candidate = readControlElementText(value, options);
|
|
1859
|
+
if (!candidate || seen.has(candidate)) continue;
|
|
1860
|
+
seen.add(candidate);
|
|
1861
|
+
labels.push(candidate);
|
|
1830
1862
|
}
|
|
1831
|
-
return
|
|
1832
|
-
}
|
|
1833
|
-
function protectSlackAssistantTranscriptRoleHeaders(text) {
|
|
1834
|
-
if (text.startsWith(SLACK_ASSISTANT_TRANSCRIPT_PREFIX)) return text;
|
|
1835
|
-
const tokenProjection = projectSlackMrkdwnVisibleText(text, "token");
|
|
1836
|
-
const fallbackProjection = projectSlackMrkdwnVisibleText(text, "fallback");
|
|
1837
|
-
if (!slackProjectionHasRoleHeader(tokenProjection) && !slackProjectionHasRoleHeader(fallbackProjection)) return text;
|
|
1838
|
-
return `${SLACK_ASSISTANT_TRANSCRIPT_PREFIX}${text}`;
|
|
1863
|
+
return labels.length > 0 ? labels.join("\n") : void 0;
|
|
1839
1864
|
}
|
|
1840
|
-
function
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
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
|
-
};
|
|
1865
|
+
function readSectionText(block, options = {}) {
|
|
1866
|
+
const parts = [readTextObject(block.text, options)];
|
|
1867
|
+
if (Array.isArray(block.fields)) parts.push(...block.fields.map((field) => readTextObject(field, options)));
|
|
1868
|
+
parts.push(readControlElementText(block.accessory, options));
|
|
1869
|
+
const visibleParts = parts.filter((part) => Boolean(part));
|
|
1870
|
+
return visibleParts.length > 0 ? visibleParts.join("\n") : void 0;
|
|
1872
1871
|
}
|
|
1873
|
-
function
|
|
1874
|
-
return
|
|
1875
|
-
assistantTranscriptRoleHeaders: true,
|
|
1876
|
-
linkify: false,
|
|
1877
|
-
autolink: false,
|
|
1878
|
-
headingStyle: "rich",
|
|
1879
|
-
blockquotePrefix: "> ",
|
|
1880
|
-
tableMode: options.tableMode
|
|
1881
|
-
})), buildSlackRenderOptions(), SLACK_FORMAT_PROFILE);
|
|
1872
|
+
function readActionsText(block, options = {}) {
|
|
1873
|
+
return Array.isArray(block.elements) ? readControlElementsText(block.elements, options) : void 0;
|
|
1882
1874
|
}
|
|
1883
|
-
|
|
1884
|
-
|
|
1875
|
+
/** Read only user-visible text from one Slack block. */
|
|
1876
|
+
function renderSlackBlockFallbackText(raw, options = {}) {
|
|
1877
|
+
const block = asOptionalRecord(raw);
|
|
1878
|
+
if (!block) return;
|
|
1879
|
+
switch (block.type) {
|
|
1880
|
+
case "rich_text": return normalizeOptionalString(renderSlackRichTextElements(block.elements, "\n", options.nativeReferenceFormat === "plain" ? (text) => text : escapeSlackMrkdwn));
|
|
1881
|
+
case "header": return readTextObject(block.text, options);
|
|
1882
|
+
case "section": return readSectionText(block, options);
|
|
1883
|
+
case "image": return readImageText(block) ?? "Shared an image";
|
|
1884
|
+
case "video": return readVideoText(block, options) ?? "Shared a video";
|
|
1885
|
+
case "file": return "Shared a file";
|
|
1886
|
+
case "context": return readContextText(block, options);
|
|
1887
|
+
case "actions": return readActionsText(block, options);
|
|
1888
|
+
case "data_visualization": return options.nativeDataFormat === "plain" ? renderSlackDataVisualizationFallbackText(block) : renderSlackDataVisualizationMrkdwnFallbackText(block);
|
|
1889
|
+
case "data_table": return options.nativeDataFormat === "plain" ? renderSlackDataTableFallbackText(block) : renderSlackDataTableMrkdwnFallbackText(block);
|
|
1890
|
+
case "table": return options.nativeDataFormat === "plain" ? renderSlackTableFallbackText(block) : renderSlackTableMrkdwnFallbackText(block);
|
|
1891
|
+
default: return;
|
|
1892
|
+
}
|
|
1885
1893
|
}
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
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(...chunkTextForOutbound(token, Math.max(1, Math.floor(contentLimit)), { preserveWhitespace: true }).map((fragment) => `${marker}${fragment}${marker}`));
|
|
1914
|
-
else chunks.push(...chunkTextForOutbound(escapeSlackMrkdwnSegment(token), Math.max(1, Math.floor(limit)), { preserveWhitespace: true }));
|
|
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;
|
|
1894
|
+
function buildSlackBlocksFallbackText(blocks) {
|
|
1895
|
+
for (const block of blocks) {
|
|
1896
|
+
const text = renderSlackBlockFallbackText(block);
|
|
1897
|
+
if (text) return text;
|
|
1922
1898
|
}
|
|
1923
|
-
|
|
1924
|
-
return chunks;
|
|
1899
|
+
return "Shared a Block Kit message";
|
|
1925
1900
|
}
|
|
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);
|
|
1901
|
+
function buildSlackCompleteBlocksFallbackText(blocks) {
|
|
1902
|
+
return blocks.map((block) => renderSlackBlockFallbackText(block)).filter(Boolean).join("\n\n").trim() || buildSlackBlocksFallbackText(blocks);
|
|
1942
1903
|
}
|
|
1943
1904
|
//#endregion
|
|
1944
1905
|
//#region extensions/slack/src/native-data-blocks.ts
|
|
1945
1906
|
const SLACK_MALFORMED_NATIVE_DATA_FALLBACK = "Slack could not render this chart or table data.";
|
|
1946
|
-
const SLACK_RESPONSE_URL_BODY_LIMIT_BYTES =
|
|
1907
|
+
const SLACK_RESPONSE_URL_BODY_LIMIT_BYTES = 16384;
|
|
1947
1908
|
const SLACK_RESPONSE_URL_BODY_TIMEOUT_MS = 3e4;
|
|
1948
1909
|
/** Detect a native Slack chart or table block. */
|
|
1949
1910
|
function hasSlackNativeDataBlock(blocks) {
|
|
@@ -2108,7 +2069,10 @@ function resolveSlackReplyDeliveryMessages(params) {
|
|
|
2108
2069
|
...baseText ? { nativeDataFallbackBaseText: baseText } : {}
|
|
2109
2070
|
});
|
|
2110
2071
|
}
|
|
2111
|
-
if (outsideText) messages.push({
|
|
2072
|
+
if (outsideText) messages.push({
|
|
2073
|
+
text: outsideText,
|
|
2074
|
+
authoredTextPlacement: "outside-blocks"
|
|
2075
|
+
});
|
|
2112
2076
|
return messages;
|
|
2113
2077
|
}
|
|
2114
2078
|
function resolveSlackReplyText(payload, text = payload.text) {
|
|
@@ -2247,14 +2211,20 @@ function renderNativePresentation(presentation, options) {
|
|
|
2247
2211
|
const blocks = buildSlackPresentationBlocks(presentation, options);
|
|
2248
2212
|
return blocks.length > 0 ? blocks : void 0;
|
|
2249
2213
|
}
|
|
2250
|
-
function appendPresentationPart(segments, presentation) {
|
|
2214
|
+
function appendPresentationPart(segments, presentation, questionOptionIndices) {
|
|
2251
2215
|
const currentBlocks = readLastBlockSegment(segments);
|
|
2252
|
-
const currentRendered = renderNativePresentation(presentation,
|
|
2216
|
+
const currentRendered = renderNativePresentation(presentation, {
|
|
2217
|
+
...resolvePresentationRenderOptions(segments, "current"),
|
|
2218
|
+
questionOptionIndices
|
|
2219
|
+
});
|
|
2253
2220
|
if (currentRendered && currentBlocks.length + currentRendered.length <= 50) {
|
|
2254
2221
|
appendBlockSegment(segments, currentRendered);
|
|
2255
2222
|
return;
|
|
2256
2223
|
}
|
|
2257
|
-
const freshRendered = renderNativePresentation(presentation,
|
|
2224
|
+
const freshRendered = renderNativePresentation(presentation, {
|
|
2225
|
+
...resolvePresentationRenderOptions(segments, "new-message"),
|
|
2226
|
+
questionOptionIndices
|
|
2227
|
+
});
|
|
2258
2228
|
if (freshRendered) {
|
|
2259
2229
|
appendBlockSegment(segments, freshRendered, true);
|
|
2260
2230
|
return;
|
|
@@ -2264,6 +2234,7 @@ function appendPresentationPart(segments, presentation) {
|
|
|
2264
2234
|
const SLACK_BUTTON_CONTROL_ACTION_IDS = [
|
|
2265
2235
|
SLACK_APPROVAL_BUTTON_ACTION_ID,
|
|
2266
2236
|
SLACK_CALLBACK_BUTTON_ACTION_ID,
|
|
2237
|
+
SLACK_QUESTION_BUTTON_ACTION_ID,
|
|
2267
2238
|
SLACK_REPLY_BUTTON_ACTION_ID,
|
|
2268
2239
|
SLACK_REPLY_LINK_ACTION_ID
|
|
2269
2240
|
];
|
|
@@ -2329,15 +2300,19 @@ function resolveSlackReplyBlockResolution(payload, options = {}) {
|
|
|
2329
2300
|
}
|
|
2330
2301
|
if (compiledChannelBlocks.length > 0) appendBlockSegment(segments, compiledChannelBlocks);
|
|
2331
2302
|
const presentation = normalizeMessagePresentation(payload.presentation);
|
|
2303
|
+
const questionOptionIndices = resolveAskUserQuestionOptionIndices(payload);
|
|
2332
2304
|
const presentationBlockOffset = readAllNativeBlocks(segments).length;
|
|
2333
2305
|
if (presentation?.title) appendPresentationPart(segments, {
|
|
2334
2306
|
title: presentation.title,
|
|
2335
2307
|
blocks: []
|
|
2336
|
-
});
|
|
2337
|
-
for (const block of presentation?.blocks ?? []) appendPresentationPart(segments, { blocks: [block] });
|
|
2308
|
+
}, questionOptionIndices);
|
|
2309
|
+
for (const block of presentation?.blocks ?? []) appendPresentationPart(segments, { blocks: [block] }, questionOptionIndices);
|
|
2338
2310
|
const renderedPresentationBlocks = readAllNativeBlocks(segments).slice(presentationBlockOffset);
|
|
2339
2311
|
appendBlockSegment(segments, subtractMirroredSlackControlRows({
|
|
2340
|
-
interactiveBlocks: buildSlackInteractiveBlocks(payload.interactive,
|
|
2312
|
+
interactiveBlocks: buildSlackInteractiveBlocks(payload.interactive, {
|
|
2313
|
+
...resolveSlackBlockOffsets(readAllNativeBlocks(segments)),
|
|
2314
|
+
questionOptionIndices
|
|
2315
|
+
}),
|
|
2341
2316
|
presentationBlocks: renderedPresentationBlocks
|
|
2342
2317
|
}));
|
|
2343
2318
|
const renderedTextFragments = segments.flatMap((segment) => {
|
|
@@ -2366,113 +2341,6 @@ function assertSlackDetachedTargetAllowed(accountId, teamId) {
|
|
|
2366
2341
|
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
2342
|
}
|
|
2368
2343
|
//#endregion
|
|
2369
|
-
//#region extensions/slack/src/monitor/allow-list.ts
|
|
2370
|
-
const SLACK_SLUG_CACHE_MAX = 512;
|
|
2371
|
-
const SLACK_STABLE_USER_ID_RE = /^[ubw][a-z0-9]+$/;
|
|
2372
|
-
const slackSlugCache = /* @__PURE__ */ new Map();
|
|
2373
|
-
function normalizeSlackSlug(raw) {
|
|
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);
|
|
2387
|
-
}
|
|
2388
|
-
function normalizeAllowListLower(list) {
|
|
2389
|
-
return normalizeStringEntriesLower(list);
|
|
2390
|
-
}
|
|
2391
|
-
function normalizeSlackAllowOwnerEntry(entry) {
|
|
2392
|
-
const trimmed = normalizeOptionalLowercaseString(entry);
|
|
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
|
-
});
|
|
2474
|
-
}
|
|
2475
|
-
//#endregion
|
|
2476
2344
|
//#region extensions/slack/src/monitor/workspace-routing.ts
|
|
2477
2345
|
function resolveSlackEnterpriseMainDmSessionKey(params) {
|
|
2478
2346
|
const accountId = encodeURIComponent(params.accountId).toLowerCase();
|
|
@@ -2528,8 +2396,9 @@ function resolveSlackGroupRequireMention(params) {
|
|
|
2528
2396
|
return resolveScopeRequireMention(resolveSlackGroupPolicyScope(params));
|
|
2529
2397
|
}
|
|
2530
2398
|
function resolveSlackGroupToolPolicy(params) {
|
|
2399
|
+
const scope = resolveSlackGroupPolicyScope(params);
|
|
2531
2400
|
return resolveScopeToolsPolicy({
|
|
2532
|
-
...
|
|
2401
|
+
...scope,
|
|
2533
2402
|
senderPolicyMode: params.senderPolicyMode,
|
|
2534
2403
|
senderId: params.senderId,
|
|
2535
2404
|
senderName: params.senderName,
|
|
@@ -2538,4 +2407,4 @@ function resolveSlackGroupToolPolicy(params) {
|
|
|
2538
2407
|
});
|
|
2539
2408
|
}
|
|
2540
2409
|
//#endregion
|
|
2541
|
-
export {
|
|
2410
|
+
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, getSlackApprovalApproversForTeam 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 };
|