@openclaw/slack 2026.7.2-beta.7 → 2026.7.34
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/README.md +1 -1
- package/dist/.setup/account-configured-DzC407uv.mjs +14 -0
- package/dist/.setup/account-inspect-CcqRNkC3.mjs +79 -0
- package/dist/.setup/account-reply-mode-Bvoq75cS.mjs +15 -0
- package/dist/.setup/accounts-uGn8E6uq.mjs +187 -0
- package/dist/.setup/accounts.runtime-k_V5-EOr.mjs +2 -0
- package/dist/.setup/action-runtime-iq6ZxO_b.mjs +395 -0
- package/dist/.setup/action-runtime.runtime-DXY8CdWJ.mjs +2 -0
- package/dist/.setup/actions-2VEX4Wdz.mjs +950 -0
- package/dist/.setup/actions.runtime-CfX8mK8Y.mjs +2 -0
- package/dist/.setup/approval-handler.runtime-COMbf4Ud.mjs +368 -0
- package/dist/.setup/channel-BqOekthS.mjs +1120 -0
- package/dist/.setup/channel.setup-DBlZCEvc.mjs +73 -0
- package/dist/.setup/client-B6i83rHk.mjs +116 -0
- package/dist/.setup/config-api-DnT9ohtE.mjs +2 -0
- package/dist/.setup/config-schema-DV93lEJ7.mjs +227 -0
- package/dist/.setup/directory-config-DB0OcZzw.mjs +55 -0
- package/dist/.setup/directory-live-O3jkDEJH.mjs +131 -0
- package/dist/.setup/doctor-contract-Dxk57DKz.mjs +147 -0
- package/dist/.setup/format-xuAop9a-.mjs +108 -0
- package/dist/.setup/interactive-replies-BLw4HEPS.mjs +193 -0
- package/dist/.setup/message-tool-api-D2m68v1f.mjs +128 -0
- package/dist/.setup/monitor-jTrujB_u.mjs +13 -0
- package/dist/.setup/outbound-adapter-DwAvZVk8.mjs +273 -0
- package/dist/.setup/pipeline.runtime-qFsXbTJf.mjs +3646 -0
- package/dist/.setup/plugin-routes-C3X0eVaK.mjs +22 -0
- package/dist/.setup/policy-C6VVHqUf.mjs +67 -0
- package/dist/.setup/probe-tmU762D2.mjs +48 -0
- package/dist/.setup/provider-Bjv1R5E2.mjs +4720 -0
- package/dist/.setup/relay-source-DR--lDW8.mjs +289 -0
- package/dist/.setup/replies-BO37R07g.mjs +288 -0
- package/dist/.setup/reply-blocks-Cwu6LYJI.mjs +882 -0
- package/dist/.setup/resolve-allowlist-common-CP8SH0Zf.mjs +43 -0
- package/dist/.setup/resolve-channels-CivvCeZv.mjs +81 -0
- package/dist/.setup/resolve-users-D5Qb64BJ.mjs +113 -0
- package/dist/.setup/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/dist/.setup/runtime-BOk7xkOl.mjs +8 -0
- package/dist/.setup/runtime-api-BnavgpzD.mjs +9 -0
- package/dist/.setup/runtime-setter-api-C-6lgBvk.mjs +3 -0
- package/dist/.setup/scopes-CYSKlU91.mjs +74 -0
- package/dist/.setup/secret-contract-C3ChHo5A.mjs +181 -0
- package/dist/.setup/secret-contract-api-CcCSHlV7.mjs +3 -0
- package/dist/.setup/security-audit-HMEYeSrJ.mjs +51 -0
- package/dist/.setup/send-DEOvcVM4.mjs +933 -0
- package/dist/.setup/send.runtime-Bmals7DV.mjs +2 -0
- package/dist/.setup/setup-core-uPGudyJH.mjs +344 -0
- package/dist/.setup/setup-plugin-api-DMKdqvij.mjs +3 -0
- package/dist/.setup/setup-surface-_4luZsPQ.mjs +130 -0
- package/dist/.setup/shared-BqyNq0up.mjs +269 -0
- package/dist/.setup/slash-dispatch.runtime-eyQo6mTA.mjs +32 -0
- package/dist/.setup/streaming-compat-DjlgH-Be.mjs +43 -0
- package/dist/.setup/target-parsing-C36VFWHQ.mjs +65 -0
- package/dist/.setup/targets-DnpzC22e.mjs +13 -0
- package/dist/account-inspect-api.js +1 -1
- package/dist/api.js +19 -18
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/configured-state.js +11 -0
- package/dist/directory-contract-api.js +1 -1
- package/dist/doctor-contract-api.js +1 -1
- package/dist/http-routes-api.js +1 -1
- package/dist/index.js +1 -1
- package/dist/interactive-replies-api.js +2 -0
- package/dist/message-tool-api.js +1 -1
- package/dist/runtime-api.js +13 -13
- package/dist/runtime-setter-api.js +1 -1
- package/dist/secret-contract-api.js +1 -1
- package/dist/security-contract-api.js +1 -1
- package/dist/setup-entry.js +5 -4
- package/dist/setup-plugin-api.js +1 -1
- package/node_modules/@slack/bolt/dist/App.d.ts +19 -4
- package/node_modules/@slack/bolt/dist/App.d.ts.map +1 -1
- package/node_modules/@slack/bolt/dist/App.js +40 -21
- package/node_modules/@slack/bolt/dist/App.js.map +1 -1
- package/node_modules/@slack/bolt/dist/WorkflowStep.d.ts +159 -0
- package/node_modules/@slack/bolt/dist/WorkflowStep.d.ts.map +1 -0
- package/node_modules/@slack/bolt/dist/WorkflowStep.js +217 -0
- package/node_modules/@slack/bolt/dist/WorkflowStep.js.map +1 -0
- package/node_modules/@slack/bolt/dist/context/create-respond.d.ts +3 -3
- package/node_modules/@slack/bolt/dist/context/create-respond.d.ts.map +1 -1
- package/node_modules/@slack/bolt/dist/context/create-respond.js +2 -13
- package/node_modules/@slack/bolt/dist/context/create-respond.js.map +1 -1
- package/node_modules/@slack/bolt/dist/errors.d.ts +8 -6
- package/node_modules/@slack/bolt/dist/errors.d.ts.map +1 -1
- package/node_modules/@slack/bolt/dist/errors.js +11 -11
- package/node_modules/@slack/bolt/dist/errors.js.map +1 -1
- package/node_modules/@slack/bolt/dist/helpers.d.ts.map +1 -1
- package/node_modules/@slack/bolt/dist/helpers.js +2 -1
- package/node_modules/@slack/bolt/dist/helpers.js.map +1 -1
- package/node_modules/@slack/bolt/dist/index.d.ts +1 -0
- package/node_modules/@slack/bolt/dist/index.d.ts.map +1 -1
- package/node_modules/@slack/bolt/dist/index.js +3 -1
- package/node_modules/@slack/bolt/dist/index.js.map +1 -1
- package/node_modules/@slack/bolt/dist/receivers/AwsLambdaReceiver.d.ts +1 -10
- package/node_modules/@slack/bolt/dist/receivers/AwsLambdaReceiver.d.ts.map +1 -1
- package/node_modules/@slack/bolt/dist/receivers/AwsLambdaReceiver.js +1 -5
- package/node_modules/@slack/bolt/dist/receivers/AwsLambdaReceiver.js.map +1 -1
- package/node_modules/@slack/bolt/dist/receivers/HTTPModuleFunctions.d.ts.map +1 -1
- package/node_modules/@slack/bolt/dist/receivers/HTTPModuleFunctions.js +14 -10
- package/node_modules/@slack/bolt/dist/receivers/HTTPModuleFunctions.js.map +1 -1
- package/node_modules/@slack/bolt/dist/receivers/SocketModeFunctions.d.ts.map +1 -1
- package/node_modules/@slack/bolt/dist/receivers/SocketModeFunctions.js +1 -1
- package/node_modules/@slack/bolt/dist/receivers/SocketModeFunctions.js.map +1 -1
- package/node_modules/@slack/bolt/dist/receivers/SocketModeReceiver.d.ts +1 -3
- package/node_modules/@slack/bolt/dist/receivers/SocketModeReceiver.d.ts.map +1 -1
- package/node_modules/@slack/bolt/dist/receivers/SocketModeReceiver.js +1 -2
- package/node_modules/@slack/bolt/dist/receivers/SocketModeReceiver.js.map +1 -1
- package/node_modules/@slack/bolt/dist/types/actions/index.d.ts +4 -2
- package/node_modules/@slack/bolt/dist/types/actions/index.d.ts.map +1 -1
- package/node_modules/@slack/bolt/dist/types/actions/index.js +2 -0
- package/node_modules/@slack/bolt/dist/types/actions/index.js.map +1 -1
- package/node_modules/@slack/bolt/dist/types/actions/workflow-step-edit.d.ts +49 -0
- package/node_modules/@slack/bolt/dist/types/actions/workflow-step-edit.d.ts.map +1 -0
- package/node_modules/@slack/bolt/dist/types/actions/workflow-step-edit.js +3 -0
- package/node_modules/@slack/bolt/dist/types/actions/workflow-step-edit.js.map +1 -0
- package/node_modules/@slack/bolt/dist/types/events/index.d.ts +0 -2
- package/node_modules/@slack/bolt/dist/types/events/index.d.ts.map +1 -1
- package/node_modules/@slack/bolt/dist/types/utilities.d.ts +2 -2
- package/node_modules/@slack/bolt/dist/types/utilities.d.ts.map +1 -1
- package/node_modules/@slack/bolt/dist/types/view/index.d.ts +31 -1
- package/node_modules/@slack/bolt/dist/types/view/index.d.ts.map +1 -1
- package/node_modules/@slack/bolt/node_modules/@slack/logger/README.md +1 -1
- package/node_modules/@slack/bolt/node_modules/@slack/logger/dist/index.js +13 -17
- package/node_modules/@slack/bolt/node_modules/@slack/logger/dist/index.js.map +1 -1
- package/node_modules/@slack/bolt/node_modules/@slack/logger/package.json +7 -6
- package/node_modules/@slack/bolt/node_modules/@slack/oauth/README.md +1 -1
- package/node_modules/@slack/bolt/node_modules/@slack/oauth/dist/errors.d.ts +14 -25
- package/node_modules/@slack/bolt/node_modules/@slack/oauth/dist/errors.d.ts.map +1 -1
- package/node_modules/@slack/bolt/node_modules/@slack/oauth/dist/errors.js +33 -24
- package/node_modules/@slack/bolt/node_modules/@slack/oauth/dist/errors.js.map +1 -1
- package/node_modules/@slack/bolt/node_modules/@slack/oauth/dist/install-provider.js +16 -58
- package/node_modules/@slack/bolt/node_modules/@slack/oauth/dist/install-provider.js.map +1 -1
- package/node_modules/@slack/bolt/node_modules/@slack/oauth/dist/installation-stores/file-store.js +2 -4
- package/node_modules/@slack/bolt/node_modules/@slack/oauth/dist/installation-stores/file-store.js.map +1 -1
- package/node_modules/@slack/bolt/node_modules/@slack/oauth/dist/installation-stores/memory-store.js +16 -3
- package/node_modules/@slack/bolt/node_modules/@slack/oauth/dist/installation-stores/memory-store.js.map +1 -1
- package/node_modules/@slack/bolt/node_modules/@slack/oauth/dist/state-stores/clear-state-store.js +0 -2
- package/node_modules/@slack/bolt/node_modules/@slack/oauth/dist/state-stores/clear-state-store.js.map +1 -1
- package/node_modules/@slack/bolt/node_modules/@slack/oauth/dist/state-stores/file-state-store.js +0 -3
- package/node_modules/@slack/bolt/node_modules/@slack/oauth/dist/state-stores/file-state-store.js.map +1 -1
- package/node_modules/@slack/bolt/node_modules/@slack/oauth/package.json +9 -8
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/README.md +221 -0
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/dist/package.json +67 -0
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/dist/src/SlackWebSocket.d.ts +96 -0
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/dist/src/SlackWebSocket.d.ts.map +1 -0
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/dist/src/SlackWebSocket.js +242 -0
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/dist/src/SlackWebSocket.js.map +1 -0
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/dist/src/SocketModeClient.d.ts +98 -0
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/dist/src/SocketModeClient.d.ts.map +1 -0
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/dist/src/SocketModeClient.js +363 -0
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/dist/src/SocketModeClient.js.map +1 -0
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/dist/src/SocketModeOptions.d.ts +47 -0
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/dist/src/SocketModeOptions.d.ts.map +1 -0
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/dist/src/errors.d.ts +60 -0
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/dist/src/errors.d.ts.map +1 -0
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/dist/src/errors.js +68 -0
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/dist/src/errors.js.map +1 -0
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/dist/src/index.d.ts +6 -0
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/dist/src/index.d.ts.map +1 -0
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/dist/src/index.js +13 -0
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/dist/src/index.js.map +1 -0
- package/node_modules/@slack/bolt/node_modules/@slack/socket-mode/package.json +67 -0
- package/node_modules/@slack/bolt/node_modules/@types/node/README.md +1 -1
- package/node_modules/@slack/bolt/node_modules/@types/node/fs/promises.d.ts +6 -16
- package/node_modules/@slack/bolt/node_modules/@types/node/package.json +2 -2
- package/node_modules/@slack/bolt/node_modules/@types/ws/README.md +15 -0
- package/node_modules/@slack/bolt/node_modules/@types/ws/index.d.mts +451 -0
- package/node_modules/@slack/bolt/node_modules/@types/ws/index.d.ts +445 -0
- package/node_modules/@slack/bolt/node_modules/@types/ws/package.json +72 -0
- package/node_modules/@slack/bolt/node_modules/agent-base/README.md +145 -0
- package/node_modules/@slack/bolt/node_modules/agent-base/dist/src/index.d.ts +78 -0
- package/node_modules/@slack/bolt/node_modules/agent-base/dist/src/index.js +203 -0
- package/node_modules/@slack/bolt/node_modules/agent-base/dist/src/index.js.map +1 -0
- package/node_modules/@slack/bolt/node_modules/agent-base/dist/src/promisify.d.ts +4 -0
- package/node_modules/@slack/bolt/node_modules/agent-base/dist/src/promisify.js +18 -0
- package/node_modules/@slack/bolt/node_modules/agent-base/dist/src/promisify.js.map +1 -0
- package/node_modules/@slack/bolt/node_modules/agent-base/package.json +64 -0
- package/node_modules/@slack/bolt/node_modules/agent-base/src/index.ts +345 -0
- package/node_modules/@slack/bolt/node_modules/agent-base/src/promisify.ts +33 -0
- package/node_modules/@slack/bolt/node_modules/asynckit/LICENSE +21 -0
- package/node_modules/@slack/bolt/node_modules/asynckit/README.md +233 -0
- package/node_modules/@slack/bolt/node_modules/asynckit/bench.js +76 -0
- package/node_modules/@slack/bolt/node_modules/asynckit/index.js +6 -0
- package/node_modules/@slack/bolt/node_modules/asynckit/lib/abort.js +29 -0
- package/node_modules/@slack/bolt/node_modules/asynckit/lib/async.js +34 -0
- package/node_modules/@slack/bolt/node_modules/asynckit/lib/defer.js +26 -0
- package/node_modules/@slack/bolt/node_modules/asynckit/lib/iterate.js +75 -0
- package/node_modules/@slack/bolt/node_modules/asynckit/lib/readable_asynckit.js +91 -0
- package/node_modules/@slack/bolt/node_modules/asynckit/lib/readable_parallel.js +25 -0
- package/node_modules/@slack/bolt/node_modules/asynckit/lib/readable_serial.js +25 -0
- package/node_modules/@slack/bolt/node_modules/asynckit/lib/readable_serial_ordered.js +29 -0
- package/node_modules/@slack/bolt/node_modules/asynckit/lib/state.js +37 -0
- package/node_modules/@slack/bolt/node_modules/asynckit/lib/streamify.js +141 -0
- package/node_modules/@slack/bolt/node_modules/asynckit/lib/terminator.js +29 -0
- package/node_modules/@slack/bolt/node_modules/asynckit/package.json +63 -0
- package/node_modules/@slack/bolt/node_modules/asynckit/parallel.js +43 -0
- package/node_modules/@slack/bolt/node_modules/asynckit/serial.js +17 -0
- package/node_modules/@slack/bolt/node_modules/asynckit/serialOrdered.js +75 -0
- package/node_modules/@slack/bolt/node_modules/asynckit/stream.js +21 -0
- package/node_modules/@slack/bolt/node_modules/axios/CHANGELOG.md +1934 -0
- package/node_modules/@slack/bolt/node_modules/axios/LICENSE +7 -0
- package/node_modules/@slack/bolt/node_modules/axios/MIGRATION_GUIDE.md +877 -0
- package/node_modules/@slack/bolt/node_modules/axios/README.md +2851 -0
- package/node_modules/@slack/bolt/node_modules/axios/dist/axios.js +5807 -0
- package/node_modules/@slack/bolt/node_modules/axios/dist/axios.min.js +5 -0
- package/node_modules/@slack/bolt/node_modules/axios/dist/axios.min.js.map +1 -0
- package/node_modules/@slack/bolt/node_modules/axios/dist/browser/axios.cjs +5829 -0
- package/node_modules/@slack/bolt/node_modules/axios/dist/esm/axios.js +5850 -0
- package/node_modules/@slack/bolt/node_modules/axios/dist/esm/axios.min.js +3 -0
- package/node_modules/@slack/bolt/node_modules/axios/dist/esm/axios.min.js.map +1 -0
- package/node_modules/@slack/bolt/node_modules/axios/dist/node/axios.cjs +6808 -0
- package/node_modules/@slack/bolt/node_modules/axios/index.d.cts +766 -0
- package/node_modules/@slack/bolt/node_modules/axios/index.d.ts +787 -0
- package/node_modules/@slack/bolt/node_modules/axios/index.js +45 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/adapters/README.md +36 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/adapters/adapters.js +132 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/adapters/fetch.js +696 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/adapters/http.js +1490 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/adapters/xhr.js +277 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/axios.js +89 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/cancel/CancelToken.js +135 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/cancel/CanceledError.js +22 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/cancel/isCancel.js +5 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/core/Axios.js +306 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/core/AxiosError.js +219 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/core/AxiosHeaders.js +474 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/core/InterceptorManager.js +171 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/core/README.md +8 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/core/buildFullPath.js +76 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/core/dispatchRequest.js +95 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/core/mergeConfig.js +174 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/core/methodList.js +17 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/core/setFormDataHeaders.js +27 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/core/settle.js +27 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/core/transformData.js +28 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/defaults/index.js +178 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/defaults/transitional.js +10 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/env/README.md +3 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/env/classes/FormData.js +2 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/env/data.js +1 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/AxiosTransformStream.js +156 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/AxiosURLSearchParams.js +59 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/Http2Sessions.js +121 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/HttpStatusCode.js +88 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/README.md +7 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/ZlibHeaderTransformStream.js +29 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/bind.js +14 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/buildURL.js +69 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/callbackify.js +18 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/combineURLs.js +23 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/composeSignals.js +68 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/cookies.js +64 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/deprecatedMethod.js +31 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/estimateDataURLDecodedBytes.js +166 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/formDataToJSON.js +125 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/formDataToStream.js +119 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/fromDataURI.js +69 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/isAbsoluteURL.js +19 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/isAxiosError.js +14 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/isURLSameOrigin.js +16 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/normalizeURLForProtocolCheck.js +24 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/null.js +2 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/parseHeaders.js +71 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/parseProtocol.js +6 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/progressEventReducer.js +54 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/readBlob.js +15 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/resolveConfig.js +107 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/sanitizeHeaderValue.js +60 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/shouldBypassProxy.js +505 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/speedometer.js +55 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/spread.js +28 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/throttle.js +45 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/toFormData.js +279 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/toURLEncodedForm.js +19 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/trackStream.js +89 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/helpers/validator.js +112 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/platform/browser/classes/Blob.js +3 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/platform/browser/classes/FormData.js +3 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/platform/browser/classes/URLSearchParams.js +4 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/platform/browser/index.js +13 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/platform/common/utils.js +52 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/platform/index.js +7 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/platform/node/classes/Buffer.js +11 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/platform/node/classes/FormData.js +3 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/platform/node/classes/URLSearchParams.js +4 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/platform/node/index.js +37 -0
- package/node_modules/@slack/bolt/node_modules/axios/lib/utils.js +1150 -0
- package/node_modules/@slack/bolt/node_modules/axios/package.json +203 -0
- package/node_modules/@slack/bolt/node_modules/combined-stream/License +19 -0
- package/node_modules/@slack/bolt/node_modules/combined-stream/Readme.md +138 -0
- package/node_modules/@slack/bolt/node_modules/combined-stream/lib/combined_stream.js +208 -0
- package/node_modules/@slack/bolt/node_modules/combined-stream/package.json +25 -0
- package/node_modules/@slack/bolt/node_modules/delayed-stream/.npmignore +1 -0
- package/node_modules/@slack/bolt/node_modules/delayed-stream/License +19 -0
- package/node_modules/@slack/bolt/node_modules/delayed-stream/Makefile +7 -0
- package/node_modules/@slack/bolt/node_modules/delayed-stream/Readme.md +141 -0
- package/node_modules/@slack/bolt/node_modules/delayed-stream/lib/delayed_stream.js +107 -0
- package/node_modules/@slack/bolt/node_modules/delayed-stream/package.json +27 -0
- package/node_modules/@slack/bolt/node_modules/es-set-tostringtag/.eslintrc +13 -0
- package/node_modules/@slack/bolt/node_modules/es-set-tostringtag/.nycrc +9 -0
- package/node_modules/@slack/bolt/node_modules/es-set-tostringtag/CHANGELOG.md +67 -0
- package/node_modules/@slack/bolt/node_modules/es-set-tostringtag/LICENSE +21 -0
- package/node_modules/@slack/bolt/node_modules/es-set-tostringtag/README.md +53 -0
- package/node_modules/@slack/bolt/node_modules/es-set-tostringtag/index.d.ts +10 -0
- package/node_modules/@slack/bolt/node_modules/es-set-tostringtag/index.js +35 -0
- package/node_modules/@slack/bolt/node_modules/es-set-tostringtag/package.json +78 -0
- package/node_modules/@slack/bolt/node_modules/es-set-tostringtag/test/index.js +85 -0
- package/node_modules/@slack/bolt/node_modules/es-set-tostringtag/tsconfig.json +9 -0
- package/node_modules/@slack/bolt/node_modules/follow-redirects/LICENSE +18 -0
- package/node_modules/@slack/bolt/node_modules/follow-redirects/README.md +157 -0
- package/node_modules/@slack/bolt/node_modules/follow-redirects/debug.js +15 -0
- package/node_modules/@slack/bolt/node_modules/follow-redirects/http.js +1 -0
- package/node_modules/@slack/bolt/node_modules/follow-redirects/https.js +1 -0
- package/node_modules/@slack/bolt/node_modules/follow-redirects/index.js +709 -0
- package/node_modules/@slack/bolt/node_modules/follow-redirects/package.json +58 -0
- package/node_modules/@slack/bolt/node_modules/form-data/CHANGELOG.md +669 -0
- package/node_modules/@slack/bolt/node_modules/form-data/License +19 -0
- package/node_modules/@slack/bolt/node_modules/form-data/README.md +350 -0
- package/node_modules/@slack/bolt/node_modules/form-data/index.d.ts +51 -0
- package/node_modules/@slack/bolt/node_modules/form-data/lib/browser.js +4 -0
- package/node_modules/@slack/bolt/node_modules/form-data/lib/form_data.js +514 -0
- package/node_modules/@slack/bolt/node_modules/form-data/lib/populate.js +10 -0
- package/node_modules/@slack/bolt/node_modules/form-data/node_modules/mime-db/HISTORY.md +507 -0
- package/node_modules/@slack/bolt/node_modules/form-data/node_modules/mime-db/LICENSE +23 -0
- package/node_modules/@slack/bolt/node_modules/form-data/node_modules/mime-db/README.md +100 -0
- package/node_modules/@slack/bolt/node_modules/form-data/node_modules/mime-db/db.json +8519 -0
- package/node_modules/@slack/bolt/node_modules/form-data/node_modules/mime-db/index.js +12 -0
- package/node_modules/@slack/bolt/node_modules/form-data/node_modules/mime-db/package.json +60 -0
- package/node_modules/@slack/bolt/node_modules/form-data/node_modules/mime-types/HISTORY.md +397 -0
- package/node_modules/@slack/bolt/node_modules/form-data/node_modules/mime-types/LICENSE +23 -0
- package/node_modules/@slack/bolt/node_modules/form-data/node_modules/mime-types/README.md +113 -0
- package/node_modules/@slack/bolt/node_modules/form-data/node_modules/mime-types/index.js +188 -0
- package/node_modules/@slack/bolt/node_modules/form-data/node_modules/mime-types/package.json +44 -0
- package/node_modules/@slack/bolt/node_modules/form-data/package.json +83 -0
- package/node_modules/@slack/bolt/node_modules/has-tostringtag/.eslintrc +5 -0
- package/node_modules/@slack/bolt/node_modules/has-tostringtag/.github/FUNDING.yml +12 -0
- package/node_modules/@slack/bolt/node_modules/has-tostringtag/.nycrc +13 -0
- package/node_modules/@slack/bolt/node_modules/has-tostringtag/CHANGELOG.md +42 -0
- package/node_modules/@slack/bolt/node_modules/has-tostringtag/LICENSE +21 -0
- package/node_modules/@slack/bolt/node_modules/has-tostringtag/README.md +46 -0
- package/node_modules/@slack/bolt/node_modules/has-tostringtag/index.d.ts +3 -0
- package/node_modules/@slack/bolt/node_modules/has-tostringtag/index.js +8 -0
- package/node_modules/@slack/bolt/node_modules/has-tostringtag/package.json +108 -0
- package/node_modules/@slack/bolt/node_modules/has-tostringtag/shams.d.ts +3 -0
- package/node_modules/@slack/bolt/node_modules/has-tostringtag/shams.js +8 -0
- package/node_modules/@slack/bolt/node_modules/has-tostringtag/test/index.js +21 -0
- package/node_modules/@slack/bolt/node_modules/has-tostringtag/test/shams/core-js.js +31 -0
- package/node_modules/@slack/bolt/node_modules/has-tostringtag/test/shams/get-own-property-symbols.js +30 -0
- package/node_modules/@slack/bolt/node_modules/has-tostringtag/test/tests.js +15 -0
- package/node_modules/@slack/bolt/node_modules/has-tostringtag/tsconfig.json +49 -0
- package/node_modules/@slack/bolt/node_modules/https-proxy-agent/README.md +137 -0
- package/node_modules/@slack/bolt/node_modules/https-proxy-agent/dist/agent.d.ts +30 -0
- package/node_modules/@slack/bolt/node_modules/https-proxy-agent/dist/agent.js +177 -0
- package/node_modules/@slack/bolt/node_modules/https-proxy-agent/dist/agent.js.map +1 -0
- package/node_modules/@slack/bolt/node_modules/https-proxy-agent/dist/index.d.ts +23 -0
- package/node_modules/@slack/bolt/node_modules/https-proxy-agent/dist/index.js +14 -0
- package/node_modules/@slack/bolt/node_modules/https-proxy-agent/dist/index.js.map +1 -0
- package/node_modules/@slack/bolt/node_modules/https-proxy-agent/dist/parse-proxy-response.d.ts +7 -0
- package/node_modules/@slack/bolt/node_modules/https-proxy-agent/dist/parse-proxy-response.js +66 -0
- package/node_modules/@slack/bolt/node_modules/https-proxy-agent/dist/parse-proxy-response.js.map +1 -0
- package/node_modules/@slack/bolt/node_modules/https-proxy-agent/package.json +56 -0
- package/node_modules/@slack/bolt/node_modules/iconv-lite/encodings/sbcs-data.js +0 -2
- package/node_modules/@slack/bolt/node_modules/iconv-lite/encodings/utf32.js +3 -10
- package/node_modules/@slack/bolt/node_modules/iconv-lite/package.json +2 -2
- package/node_modules/@slack/bolt/node_modules/iconv-lite/types/encodings.d.ts +0 -2
- package/node_modules/@slack/bolt/node_modules/media-typer/README.md +14 -15
- package/node_modules/@slack/bolt/node_modules/media-typer/index.js +8 -0
- package/node_modules/@slack/bolt/node_modules/media-typer/package.json +12 -16
- package/node_modules/@slack/bolt/node_modules/path-to-regexp/Readme.md +3 -3
- package/node_modules/@slack/bolt/node_modules/path-to-regexp/dist/index.js +158 -135
- package/node_modules/@slack/bolt/node_modules/path-to-regexp/dist/index.js.map +1 -1
- package/node_modules/@slack/bolt/node_modules/path-to-regexp/package.json +2 -2
- package/node_modules/@slack/bolt/node_modules/proxy-addr/HISTORY.md +60 -54
- package/node_modules/@slack/bolt/node_modules/proxy-addr/README.md +1 -1
- package/node_modules/@slack/bolt/node_modules/proxy-addr/index.js +32 -0
- package/node_modules/@slack/bolt/node_modules/proxy-addr/package.json +8 -4
- package/node_modules/@slack/bolt/node_modules/proxy-from-env/LICENSE +20 -0
- package/node_modules/@slack/bolt/node_modules/proxy-from-env/README.md +163 -0
- package/node_modules/@slack/bolt/node_modules/proxy-from-env/index.cjs +105 -0
- package/node_modules/@slack/bolt/node_modules/proxy-from-env/index.js +103 -0
- package/node_modules/@slack/bolt/node_modules/proxy-from-env/package.json +43 -0
- package/node_modules/@slack/bolt/node_modules/qs/CHANGELOG.md +0 -11
- package/node_modules/@slack/bolt/node_modules/qs/dist/qs.js +17 -17
- package/node_modules/@slack/bolt/node_modules/qs/lib/parse.js +8 -19
- package/node_modules/@slack/bolt/node_modules/qs/lib/utils.js +8 -47
- package/node_modules/@slack/bolt/node_modules/qs/package.json +5 -6
- package/node_modules/@slack/bolt/node_modules/qs/test/parse.js +0 -230
- package/node_modules/@slack/bolt/node_modules/qs/test/utils.js +0 -194
- package/node_modules/@slack/bolt/package.json +11 -10
- package/node_modules/@slack/types/README.md +1 -1
- package/node_modules/@slack/types/dist/events/app.d.ts +0 -28
- package/node_modules/@slack/types/dist/events/app.d.ts.map +1 -1
- package/node_modules/@slack/types/dist/events/index.d.ts +2 -2
- package/node_modules/@slack/types/dist/events/index.d.ts.map +1 -1
- package/node_modules/@slack/types/dist/events/index.js.map +1 -1
- package/node_modules/@slack/types/dist/events/message.d.ts +0 -2
- package/node_modules/@slack/types/dist/events/message.d.ts.map +1 -1
- package/node_modules/@slack/types/package.json +3 -3
- package/node_modules/@slack/web-api/README.md +1 -1
- package/node_modules/@slack/web-api/dist/WebClient.d.ts +71 -42
- package/node_modules/@slack/web-api/dist/WebClient.d.ts.map +1 -1
- package/node_modules/@slack/web-api/dist/WebClient.js +248 -180
- package/node_modules/@slack/web-api/dist/WebClient.js.map +1 -1
- package/node_modules/@slack/web-api/dist/chat-stream.js +22 -37
- package/node_modules/@slack/web-api/dist/chat-stream.js.map +1 -1
- package/node_modules/@slack/web-api/dist/errors.d.ts +51 -32
- package/node_modules/@slack/web-api/dist/errors.d.ts.map +1 -1
- package/node_modules/@slack/web-api/dist/errors.js +55 -64
- package/node_modules/@slack/web-api/dist/errors.js.map +1 -1
- package/node_modules/@slack/web-api/dist/file-upload.d.ts +9 -0
- package/node_modules/@slack/web-api/dist/file-upload.d.ts.map +1 -1
- package/node_modules/@slack/web-api/dist/file-upload.js +46 -41
- package/node_modules/@slack/web-api/dist/file-upload.js.map +1 -1
- package/node_modules/@slack/web-api/dist/index.d.ts +2 -2
- package/node_modules/@slack/web-api/dist/index.d.ts.map +1 -1
- package/node_modules/@slack/web-api/dist/index.js +1 -8
- package/node_modules/@slack/web-api/dist/index.js.map +1 -1
- package/node_modules/@slack/web-api/dist/methods.d.ts +38 -2
- package/node_modules/@slack/web-api/dist/methods.d.ts.map +1 -1
- package/node_modules/@slack/web-api/dist/methods.js +1384 -1347
- package/node_modules/@slack/web-api/dist/methods.js.map +1 -1
- package/node_modules/@slack/web-api/dist/types/request/files.d.ts +1 -0
- package/node_modules/@slack/web-api/dist/types/request/files.d.ts.map +1 -1
- package/node_modules/@slack/web-api/dist/types/request/index.d.ts +3 -3
- package/node_modules/@slack/web-api/dist/types/request/index.d.ts.map +1 -1
- package/node_modules/@slack/web-api/dist/types/request/manifest.d.ts +1 -66
- package/node_modules/@slack/web-api/dist/types/request/manifest.d.ts.map +1 -1
- package/node_modules/@slack/web-api/dist/types/request/rtm.d.ts +14 -1
- package/node_modules/@slack/web-api/dist/types/request/rtm.d.ts.map +1 -1
- package/node_modules/@slack/web-api/dist/types/request/workflows.d.ts +29 -0
- package/node_modules/@slack/web-api/dist/types/request/workflows.d.ts.map +1 -1
- package/node_modules/@slack/web-api/node_modules/@slack/logger/README.md +1 -1
- package/node_modules/@slack/web-api/node_modules/@slack/logger/dist/index.js +13 -17
- package/node_modules/@slack/web-api/node_modules/@slack/logger/dist/index.js.map +1 -1
- package/node_modules/@slack/web-api/node_modules/@slack/logger/package.json +7 -6
- package/node_modules/@slack/web-api/node_modules/@types/node/README.md +1 -1
- package/node_modules/@slack/web-api/node_modules/@types/node/fs/promises.d.ts +6 -16
- package/node_modules/@slack/web-api/node_modules/@types/node/package.json +2 -2
- package/node_modules/@slack/web-api/node_modules/agent-base/README.md +145 -0
- package/node_modules/@slack/web-api/node_modules/agent-base/dist/src/index.d.ts +78 -0
- package/node_modules/@slack/web-api/node_modules/agent-base/dist/src/index.js +203 -0
- package/node_modules/@slack/web-api/node_modules/agent-base/dist/src/index.js.map +1 -0
- package/node_modules/@slack/web-api/node_modules/agent-base/dist/src/promisify.d.ts +4 -0
- package/node_modules/@slack/web-api/node_modules/agent-base/dist/src/promisify.js +18 -0
- package/node_modules/@slack/web-api/node_modules/agent-base/dist/src/promisify.js.map +1 -0
- package/node_modules/@slack/web-api/node_modules/agent-base/package.json +64 -0
- package/node_modules/@slack/web-api/node_modules/agent-base/src/index.ts +345 -0
- package/node_modules/@slack/web-api/node_modules/agent-base/src/promisify.ts +33 -0
- package/node_modules/@slack/web-api/node_modules/asynckit/LICENSE +21 -0
- package/node_modules/@slack/web-api/node_modules/asynckit/README.md +233 -0
- package/node_modules/@slack/web-api/node_modules/asynckit/bench.js +76 -0
- package/node_modules/@slack/web-api/node_modules/asynckit/index.js +6 -0
- package/node_modules/@slack/web-api/node_modules/asynckit/lib/abort.js +29 -0
- package/node_modules/@slack/web-api/node_modules/asynckit/lib/async.js +34 -0
- package/node_modules/@slack/web-api/node_modules/asynckit/lib/defer.js +26 -0
- package/node_modules/@slack/web-api/node_modules/asynckit/lib/iterate.js +75 -0
- package/node_modules/@slack/web-api/node_modules/asynckit/lib/readable_asynckit.js +91 -0
- package/node_modules/@slack/web-api/node_modules/asynckit/lib/readable_parallel.js +25 -0
- package/node_modules/@slack/web-api/node_modules/asynckit/lib/readable_serial.js +25 -0
- package/node_modules/@slack/web-api/node_modules/asynckit/lib/readable_serial_ordered.js +29 -0
- package/node_modules/@slack/web-api/node_modules/asynckit/lib/state.js +37 -0
- package/node_modules/@slack/web-api/node_modules/asynckit/lib/streamify.js +141 -0
- package/node_modules/@slack/web-api/node_modules/asynckit/lib/terminator.js +29 -0
- package/node_modules/@slack/web-api/node_modules/asynckit/package.json +63 -0
- package/node_modules/@slack/web-api/node_modules/asynckit/parallel.js +43 -0
- package/node_modules/@slack/web-api/node_modules/asynckit/serial.js +17 -0
- package/node_modules/@slack/web-api/node_modules/asynckit/serialOrdered.js +75 -0
- package/node_modules/@slack/web-api/node_modules/asynckit/stream.js +21 -0
- package/node_modules/@slack/web-api/node_modules/axios/CHANGELOG.md +1934 -0
- package/node_modules/@slack/web-api/node_modules/axios/LICENSE +7 -0
- package/node_modules/@slack/web-api/node_modules/axios/MIGRATION_GUIDE.md +877 -0
- package/node_modules/@slack/web-api/node_modules/axios/README.md +2851 -0
- package/node_modules/@slack/web-api/node_modules/axios/dist/axios.js +5807 -0
- package/node_modules/@slack/web-api/node_modules/axios/dist/axios.min.js +5 -0
- package/node_modules/@slack/web-api/node_modules/axios/dist/axios.min.js.map +1 -0
- package/node_modules/@slack/web-api/node_modules/axios/dist/browser/axios.cjs +5829 -0
- package/node_modules/@slack/web-api/node_modules/axios/dist/esm/axios.js +5850 -0
- package/node_modules/@slack/web-api/node_modules/axios/dist/esm/axios.min.js +3 -0
- package/node_modules/@slack/web-api/node_modules/axios/dist/esm/axios.min.js.map +1 -0
- package/node_modules/@slack/web-api/node_modules/axios/dist/node/axios.cjs +6808 -0
- package/node_modules/@slack/web-api/node_modules/axios/index.d.cts +766 -0
- package/node_modules/@slack/web-api/node_modules/axios/index.d.ts +787 -0
- package/node_modules/@slack/web-api/node_modules/axios/index.js +45 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/adapters/README.md +36 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/adapters/adapters.js +132 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/adapters/fetch.js +696 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/adapters/http.js +1490 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/adapters/xhr.js +277 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/axios.js +89 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/cancel/CancelToken.js +135 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/cancel/CanceledError.js +22 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/cancel/isCancel.js +5 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/core/Axios.js +306 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/core/AxiosError.js +219 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/core/AxiosHeaders.js +474 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/core/InterceptorManager.js +171 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/core/README.md +8 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/core/buildFullPath.js +76 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/core/dispatchRequest.js +95 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/core/mergeConfig.js +174 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/core/methodList.js +17 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/core/setFormDataHeaders.js +27 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/core/settle.js +27 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/core/transformData.js +28 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/defaults/index.js +178 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/defaults/transitional.js +10 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/env/README.md +3 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/env/classes/FormData.js +2 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/env/data.js +1 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/AxiosTransformStream.js +156 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/AxiosURLSearchParams.js +59 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/Http2Sessions.js +121 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/HttpStatusCode.js +88 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/README.md +7 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/ZlibHeaderTransformStream.js +29 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/bind.js +14 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/buildURL.js +69 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/callbackify.js +18 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/combineURLs.js +23 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/composeSignals.js +68 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/cookies.js +64 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/deprecatedMethod.js +31 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/estimateDataURLDecodedBytes.js +166 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/formDataToJSON.js +125 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/formDataToStream.js +119 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/fromDataURI.js +69 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/isAbsoluteURL.js +19 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/isAxiosError.js +14 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/isURLSameOrigin.js +16 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/normalizeURLForProtocolCheck.js +24 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/null.js +2 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/parseHeaders.js +71 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/parseProtocol.js +6 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/progressEventReducer.js +54 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/readBlob.js +15 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/resolveConfig.js +107 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/sanitizeHeaderValue.js +60 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/shouldBypassProxy.js +505 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/speedometer.js +55 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/spread.js +28 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/throttle.js +45 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/toFormData.js +279 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/toURLEncodedForm.js +19 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/trackStream.js +89 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/helpers/validator.js +112 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/platform/browser/classes/Blob.js +3 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/platform/browser/classes/FormData.js +3 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/platform/browser/classes/URLSearchParams.js +4 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/platform/browser/index.js +13 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/platform/common/utils.js +52 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/platform/index.js +7 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/platform/node/classes/Buffer.js +11 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/platform/node/classes/FormData.js +3 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/platform/node/classes/URLSearchParams.js +4 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/platform/node/index.js +37 -0
- package/node_modules/@slack/web-api/node_modules/axios/lib/utils.js +1150 -0
- package/node_modules/@slack/web-api/node_modules/axios/package.json +203 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/.eslintrc +17 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/.github/FUNDING.yml +12 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/.nycrc +9 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/CHANGELOG.md +30 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/LICENSE +21 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/README.md +62 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/actualApply.d.ts +1 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/actualApply.js +10 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/applyBind.d.ts +19 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/applyBind.js +10 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/functionApply.d.ts +1 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/functionApply.js +4 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/functionCall.d.ts +1 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/functionCall.js +4 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/index.d.ts +64 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/index.js +15 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/package.json +85 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/reflectApply.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/reflectApply.js +4 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/test/index.js +63 -0
- package/node_modules/@slack/web-api/node_modules/call-bind-apply-helpers/tsconfig.json +9 -0
- package/node_modules/@slack/web-api/node_modules/combined-stream/License +19 -0
- package/node_modules/@slack/web-api/node_modules/combined-stream/Readme.md +138 -0
- package/node_modules/@slack/web-api/node_modules/combined-stream/lib/combined_stream.js +208 -0
- package/node_modules/@slack/web-api/node_modules/combined-stream/package.json +25 -0
- package/node_modules/@slack/web-api/node_modules/debug/LICENSE +20 -0
- package/node_modules/@slack/web-api/node_modules/debug/README.md +481 -0
- package/node_modules/@slack/web-api/node_modules/debug/package.json +64 -0
- package/node_modules/@slack/web-api/node_modules/debug/src/browser.js +272 -0
- package/node_modules/@slack/web-api/node_modules/debug/src/common.js +292 -0
- package/node_modules/@slack/web-api/node_modules/debug/src/index.js +10 -0
- package/node_modules/@slack/web-api/node_modules/debug/src/node.js +263 -0
- package/node_modules/@slack/web-api/node_modules/delayed-stream/.npmignore +1 -0
- package/node_modules/@slack/web-api/node_modules/delayed-stream/License +19 -0
- package/node_modules/@slack/web-api/node_modules/delayed-stream/Makefile +7 -0
- package/node_modules/@slack/web-api/node_modules/delayed-stream/Readme.md +141 -0
- package/node_modules/@slack/web-api/node_modules/delayed-stream/lib/delayed_stream.js +107 -0
- package/node_modules/@slack/web-api/node_modules/delayed-stream/package.json +27 -0
- package/node_modules/@slack/web-api/node_modules/dunder-proto/.eslintrc +5 -0
- package/node_modules/@slack/web-api/node_modules/dunder-proto/.github/FUNDING.yml +12 -0
- package/node_modules/@slack/web-api/node_modules/dunder-proto/.nycrc +13 -0
- package/node_modules/@slack/web-api/node_modules/dunder-proto/CHANGELOG.md +24 -0
- package/node_modules/@slack/web-api/node_modules/dunder-proto/LICENSE +21 -0
- package/node_modules/@slack/web-api/node_modules/dunder-proto/README.md +54 -0
- package/node_modules/@slack/web-api/node_modules/dunder-proto/get.d.ts +5 -0
- package/node_modules/@slack/web-api/node_modules/dunder-proto/get.js +30 -0
- package/node_modules/@slack/web-api/node_modules/dunder-proto/package.json +76 -0
- package/node_modules/@slack/web-api/node_modules/dunder-proto/set.d.ts +5 -0
- package/node_modules/@slack/web-api/node_modules/dunder-proto/set.js +35 -0
- package/node_modules/@slack/web-api/node_modules/dunder-proto/test/get.js +34 -0
- package/node_modules/@slack/web-api/node_modules/dunder-proto/test/index.js +4 -0
- package/node_modules/@slack/web-api/node_modules/dunder-proto/test/set.js +50 -0
- package/node_modules/@slack/web-api/node_modules/dunder-proto/tsconfig.json +9 -0
- package/node_modules/@slack/web-api/node_modules/es-define-property/.eslintrc +13 -0
- package/node_modules/@slack/web-api/node_modules/es-define-property/.github/FUNDING.yml +12 -0
- package/node_modules/@slack/web-api/node_modules/es-define-property/.nycrc +9 -0
- package/node_modules/@slack/web-api/node_modules/es-define-property/CHANGELOG.md +29 -0
- package/node_modules/@slack/web-api/node_modules/es-define-property/LICENSE +21 -0
- package/node_modules/@slack/web-api/node_modules/es-define-property/README.md +49 -0
- package/node_modules/@slack/web-api/node_modules/es-define-property/index.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/es-define-property/index.js +14 -0
- package/node_modules/@slack/web-api/node_modules/es-define-property/package.json +81 -0
- package/node_modules/@slack/web-api/node_modules/es-define-property/test/index.js +56 -0
- package/node_modules/@slack/web-api/node_modules/es-define-property/tsconfig.json +10 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/.eslintrc +5 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/.github/FUNDING.yml +12 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/CHANGELOG.md +40 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/LICENSE +21 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/README.md +55 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/eval.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/eval.js +4 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/index.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/index.js +4 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/package.json +80 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/range.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/range.js +4 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/ref.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/ref.js +4 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/syntax.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/syntax.js +4 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/test/index.js +19 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/tsconfig.json +49 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/type.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/type.js +4 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/uri.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/es-errors/uri.js +4 -0
- package/node_modules/@slack/web-api/node_modules/es-object-atoms/.eslintrc +16 -0
- package/node_modules/@slack/web-api/node_modules/es-object-atoms/.github/FUNDING.yml +12 -0
- package/node_modules/@slack/web-api/node_modules/es-object-atoms/CHANGELOG.md +44 -0
- package/node_modules/@slack/web-api/node_modules/es-object-atoms/LICENSE +21 -0
- package/node_modules/@slack/web-api/node_modules/es-object-atoms/README.md +63 -0
- package/node_modules/@slack/web-api/node_modules/es-object-atoms/RequireObjectCoercible.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/es-object-atoms/RequireObjectCoercible.js +11 -0
- package/node_modules/@slack/web-api/node_modules/es-object-atoms/ToObject.d.ts +7 -0
- package/node_modules/@slack/web-api/node_modules/es-object-atoms/ToObject.js +10 -0
- package/node_modules/@slack/web-api/node_modules/es-object-atoms/index.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/es-object-atoms/index.js +4 -0
- package/node_modules/@slack/web-api/node_modules/es-object-atoms/isObject.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/es-object-atoms/isObject.js +6 -0
- package/node_modules/@slack/web-api/node_modules/es-object-atoms/package.json +79 -0
- package/node_modules/@slack/web-api/node_modules/es-object-atoms/test/index.js +38 -0
- package/node_modules/@slack/web-api/node_modules/es-object-atoms/tsconfig.json +7 -0
- package/node_modules/@slack/web-api/node_modules/es-set-tostringtag/.eslintrc +13 -0
- package/node_modules/@slack/web-api/node_modules/es-set-tostringtag/.nycrc +9 -0
- package/node_modules/@slack/web-api/node_modules/es-set-tostringtag/CHANGELOG.md +67 -0
- package/node_modules/@slack/web-api/node_modules/es-set-tostringtag/LICENSE +21 -0
- package/node_modules/@slack/web-api/node_modules/es-set-tostringtag/README.md +53 -0
- package/node_modules/@slack/web-api/node_modules/es-set-tostringtag/index.d.ts +10 -0
- package/node_modules/@slack/web-api/node_modules/es-set-tostringtag/index.js +35 -0
- package/node_modules/@slack/web-api/node_modules/es-set-tostringtag/package.json +78 -0
- package/node_modules/@slack/web-api/node_modules/es-set-tostringtag/test/index.js +85 -0
- package/node_modules/@slack/web-api/node_modules/es-set-tostringtag/tsconfig.json +9 -0
- package/node_modules/@slack/web-api/node_modules/follow-redirects/LICENSE +18 -0
- package/node_modules/@slack/web-api/node_modules/follow-redirects/README.md +157 -0
- package/node_modules/@slack/web-api/node_modules/follow-redirects/debug.js +15 -0
- package/node_modules/@slack/web-api/node_modules/follow-redirects/http.js +1 -0
- package/node_modules/@slack/web-api/node_modules/follow-redirects/https.js +1 -0
- package/node_modules/@slack/web-api/node_modules/follow-redirects/index.js +709 -0
- package/node_modules/@slack/web-api/node_modules/follow-redirects/package.json +58 -0
- package/node_modules/@slack/web-api/node_modules/form-data/CHANGELOG.md +669 -0
- package/node_modules/@slack/web-api/node_modules/form-data/License +19 -0
- package/node_modules/@slack/web-api/node_modules/form-data/README.md +350 -0
- package/node_modules/@slack/web-api/node_modules/form-data/index.d.ts +51 -0
- package/node_modules/@slack/web-api/node_modules/form-data/lib/browser.js +4 -0
- package/node_modules/@slack/web-api/node_modules/form-data/lib/form_data.js +514 -0
- package/node_modules/@slack/web-api/node_modules/form-data/lib/populate.js +10 -0
- package/node_modules/@slack/web-api/node_modules/form-data/package.json +83 -0
- package/node_modules/@slack/web-api/node_modules/function-bind/.eslintrc +21 -0
- package/node_modules/@slack/web-api/node_modules/function-bind/.github/FUNDING.yml +12 -0
- package/node_modules/@slack/web-api/node_modules/function-bind/.github/SECURITY.md +3 -0
- package/node_modules/@slack/web-api/node_modules/function-bind/.nycrc +13 -0
- package/node_modules/@slack/web-api/node_modules/function-bind/CHANGELOG.md +136 -0
- package/node_modules/@slack/web-api/node_modules/function-bind/LICENSE +20 -0
- package/node_modules/@slack/web-api/node_modules/function-bind/README.md +46 -0
- package/node_modules/@slack/web-api/node_modules/function-bind/implementation.js +84 -0
- package/node_modules/@slack/web-api/node_modules/function-bind/index.js +5 -0
- package/node_modules/@slack/web-api/node_modules/function-bind/package.json +87 -0
- package/node_modules/@slack/web-api/node_modules/function-bind/test/.eslintrc +9 -0
- package/node_modules/@slack/web-api/node_modules/function-bind/test/index.js +252 -0
- package/node_modules/@slack/web-api/node_modules/get-intrinsic/.eslintrc +42 -0
- package/node_modules/@slack/web-api/node_modules/get-intrinsic/.github/FUNDING.yml +12 -0
- package/node_modules/@slack/web-api/node_modules/get-intrinsic/.nycrc +9 -0
- package/node_modules/@slack/web-api/node_modules/get-intrinsic/CHANGELOG.md +186 -0
- package/node_modules/@slack/web-api/node_modules/get-intrinsic/LICENSE +21 -0
- package/node_modules/@slack/web-api/node_modules/get-intrinsic/README.md +71 -0
- package/node_modules/@slack/web-api/node_modules/get-intrinsic/index.js +378 -0
- package/node_modules/@slack/web-api/node_modules/get-intrinsic/package.json +97 -0
- package/node_modules/@slack/web-api/node_modules/get-intrinsic/test/GetIntrinsic.js +274 -0
- package/node_modules/@slack/web-api/node_modules/get-proto/.eslintrc +10 -0
- package/node_modules/@slack/web-api/node_modules/get-proto/.github/FUNDING.yml +12 -0
- package/node_modules/@slack/web-api/node_modules/get-proto/.nycrc +9 -0
- package/node_modules/@slack/web-api/node_modules/get-proto/CHANGELOG.md +21 -0
- package/node_modules/@slack/web-api/node_modules/get-proto/LICENSE +21 -0
- package/node_modules/@slack/web-api/node_modules/get-proto/Object.getPrototypeOf.d.ts +5 -0
- package/node_modules/@slack/web-api/node_modules/get-proto/Object.getPrototypeOf.js +6 -0
- package/node_modules/@slack/web-api/node_modules/get-proto/README.md +50 -0
- package/node_modules/@slack/web-api/node_modules/get-proto/Reflect.getPrototypeOf.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/get-proto/Reflect.getPrototypeOf.js +4 -0
- package/node_modules/@slack/web-api/node_modules/get-proto/index.d.ts +5 -0
- package/node_modules/@slack/web-api/node_modules/get-proto/index.js +27 -0
- package/node_modules/@slack/web-api/node_modules/get-proto/package.json +81 -0
- package/node_modules/@slack/web-api/node_modules/get-proto/test/index.js +68 -0
- package/node_modules/@slack/web-api/node_modules/get-proto/tsconfig.json +9 -0
- package/node_modules/@slack/web-api/node_modules/gopd/.eslintrc +16 -0
- package/node_modules/@slack/web-api/node_modules/gopd/.github/FUNDING.yml +12 -0
- package/node_modules/@slack/web-api/node_modules/gopd/CHANGELOG.md +45 -0
- package/node_modules/@slack/web-api/node_modules/gopd/LICENSE +21 -0
- package/node_modules/@slack/web-api/node_modules/gopd/README.md +40 -0
- package/node_modules/@slack/web-api/node_modules/gopd/gOPD.d.ts +1 -0
- package/node_modules/@slack/web-api/node_modules/gopd/gOPD.js +4 -0
- package/node_modules/@slack/web-api/node_modules/gopd/index.d.ts +5 -0
- package/node_modules/@slack/web-api/node_modules/gopd/index.js +15 -0
- package/node_modules/@slack/web-api/node_modules/gopd/package.json +77 -0
- package/node_modules/@slack/web-api/node_modules/gopd/test/index.js +36 -0
- package/node_modules/@slack/web-api/node_modules/gopd/tsconfig.json +9 -0
- package/node_modules/@slack/web-api/node_modules/has-symbols/.eslintrc +11 -0
- package/node_modules/@slack/web-api/node_modules/has-symbols/.github/FUNDING.yml +12 -0
- package/node_modules/@slack/web-api/node_modules/has-symbols/.nycrc +9 -0
- package/node_modules/@slack/web-api/node_modules/has-symbols/CHANGELOG.md +91 -0
- package/node_modules/@slack/web-api/node_modules/has-symbols/LICENSE +21 -0
- package/node_modules/@slack/web-api/node_modules/has-symbols/README.md +46 -0
- package/node_modules/@slack/web-api/node_modules/has-symbols/index.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/has-symbols/index.js +14 -0
- package/node_modules/@slack/web-api/node_modules/has-symbols/package.json +111 -0
- package/node_modules/@slack/web-api/node_modules/has-symbols/shams.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/has-symbols/shams.js +45 -0
- package/node_modules/@slack/web-api/node_modules/has-symbols/test/index.js +22 -0
- package/node_modules/@slack/web-api/node_modules/has-symbols/test/shams/core-js.js +29 -0
- package/node_modules/@slack/web-api/node_modules/has-symbols/test/shams/get-own-property-symbols.js +29 -0
- package/node_modules/@slack/web-api/node_modules/has-symbols/test/tests.js +58 -0
- package/node_modules/@slack/web-api/node_modules/has-symbols/tsconfig.json +10 -0
- package/node_modules/@slack/web-api/node_modules/has-tostringtag/.eslintrc +5 -0
- package/node_modules/@slack/web-api/node_modules/has-tostringtag/.github/FUNDING.yml +12 -0
- package/node_modules/@slack/web-api/node_modules/has-tostringtag/.nycrc +13 -0
- package/node_modules/@slack/web-api/node_modules/has-tostringtag/CHANGELOG.md +42 -0
- package/node_modules/@slack/web-api/node_modules/has-tostringtag/LICENSE +21 -0
- package/node_modules/@slack/web-api/node_modules/has-tostringtag/README.md +46 -0
- package/node_modules/@slack/web-api/node_modules/has-tostringtag/index.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/has-tostringtag/index.js +8 -0
- package/node_modules/@slack/web-api/node_modules/has-tostringtag/package.json +108 -0
- package/node_modules/@slack/web-api/node_modules/has-tostringtag/shams.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/has-tostringtag/shams.js +8 -0
- package/node_modules/@slack/web-api/node_modules/has-tostringtag/test/index.js +21 -0
- package/node_modules/@slack/web-api/node_modules/has-tostringtag/test/shams/core-js.js +31 -0
- package/node_modules/@slack/web-api/node_modules/has-tostringtag/test/shams/get-own-property-symbols.js +30 -0
- package/node_modules/@slack/web-api/node_modules/has-tostringtag/test/tests.js +15 -0
- package/node_modules/@slack/web-api/node_modules/has-tostringtag/tsconfig.json +49 -0
- package/node_modules/@slack/web-api/node_modules/hasown/.github/FUNDING.yml +12 -0
- package/node_modules/@slack/web-api/node_modules/hasown/.nycrc +13 -0
- package/node_modules/@slack/web-api/node_modules/hasown/CHANGELOG.md +58 -0
- package/node_modules/@slack/web-api/node_modules/hasown/LICENSE +21 -0
- package/node_modules/@slack/web-api/node_modules/hasown/README.md +40 -0
- package/node_modules/@slack/web-api/node_modules/hasown/eslint.config.mjs +6 -0
- package/node_modules/@slack/web-api/node_modules/hasown/index.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/hasown/index.js +8 -0
- package/node_modules/@slack/web-api/node_modules/hasown/package.json +91 -0
- package/node_modules/@slack/web-api/node_modules/hasown/tsconfig.json +6 -0
- package/node_modules/@slack/web-api/node_modules/https-proxy-agent/README.md +137 -0
- package/node_modules/@slack/web-api/node_modules/https-proxy-agent/dist/agent.d.ts +30 -0
- package/node_modules/@slack/web-api/node_modules/https-proxy-agent/dist/agent.js +177 -0
- package/node_modules/@slack/web-api/node_modules/https-proxy-agent/dist/agent.js.map +1 -0
- package/node_modules/@slack/web-api/node_modules/https-proxy-agent/dist/index.d.ts +23 -0
- package/node_modules/@slack/web-api/node_modules/https-proxy-agent/dist/index.js +14 -0
- package/node_modules/@slack/web-api/node_modules/https-proxy-agent/dist/index.js.map +1 -0
- package/node_modules/@slack/web-api/node_modules/https-proxy-agent/dist/parse-proxy-response.d.ts +7 -0
- package/node_modules/@slack/web-api/node_modules/https-proxy-agent/dist/parse-proxy-response.js +66 -0
- package/node_modules/@slack/web-api/node_modules/https-proxy-agent/dist/parse-proxy-response.js.map +1 -0
- package/node_modules/@slack/web-api/node_modules/https-proxy-agent/package.json +56 -0
- package/node_modules/@slack/web-api/node_modules/is-electron/LICENSE +21 -0
- package/node_modules/@slack/web-api/node_modules/is-electron/README.md +25 -0
- package/node_modules/@slack/web-api/node_modules/is-electron/index.d.ts +2 -0
- package/node_modules/@slack/web-api/node_modules/is-electron/index.js +21 -0
- package/node_modules/@slack/web-api/node_modules/is-electron/package.json +34 -0
- package/node_modules/@slack/web-api/node_modules/is-stream/index.d.ts +79 -0
- package/node_modules/@slack/web-api/node_modules/is-stream/index.js +28 -0
- package/node_modules/@slack/web-api/node_modules/is-stream/package.json +42 -0
- package/node_modules/@slack/web-api/node_modules/is-stream/readme.md +60 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/.eslintrc +16 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/.github/FUNDING.yml +12 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/CHANGELOG.md +24 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/LICENSE +21 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/README.md +50 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/abs.d.ts +1 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/abs.js +4 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/constants/maxArrayLength.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/constants/maxArrayLength.js +4 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/constants/maxSafeInteger.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/constants/maxSafeInteger.js +5 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/constants/maxValue.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/constants/maxValue.js +5 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/floor.d.ts +1 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/floor.js +4 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/isFinite.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/isFinite.js +12 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/isInteger.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/isInteger.js +16 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/isNaN.d.ts +1 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/isNaN.js +6 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/isNegativeZero.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/isNegativeZero.js +6 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/max.d.ts +1 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/max.js +4 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/min.d.ts +1 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/min.js +4 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/mod.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/mod.js +9 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/package.json +86 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/pow.d.ts +1 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/pow.js +4 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/round.d.ts +1 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/round.js +4 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/sign.d.ts +3 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/sign.js +11 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/test/index.js +192 -0
- package/node_modules/@slack/web-api/node_modules/math-intrinsics/tsconfig.json +3 -0
- package/node_modules/@slack/web-api/node_modules/mime-db/HISTORY.md +507 -0
- package/node_modules/@slack/web-api/node_modules/mime-db/LICENSE +23 -0
- package/node_modules/@slack/web-api/node_modules/mime-db/README.md +100 -0
- package/node_modules/@slack/web-api/node_modules/mime-db/db.json +8519 -0
- package/node_modules/@slack/web-api/node_modules/mime-db/index.js +12 -0
- package/node_modules/@slack/web-api/node_modules/mime-db/package.json +60 -0
- package/node_modules/@slack/web-api/node_modules/mime-types/HISTORY.md +397 -0
- package/node_modules/@slack/web-api/node_modules/mime-types/LICENSE +23 -0
- package/node_modules/@slack/web-api/node_modules/mime-types/README.md +113 -0
- package/node_modules/@slack/web-api/node_modules/mime-types/index.js +188 -0
- package/node_modules/@slack/web-api/node_modules/mime-types/package.json +44 -0
- package/node_modules/@slack/web-api/node_modules/ms/index.js +162 -0
- package/node_modules/@slack/web-api/node_modules/ms/license.md +21 -0
- package/node_modules/@slack/web-api/node_modules/ms/package.json +38 -0
- package/node_modules/@slack/web-api/node_modules/ms/readme.md +59 -0
- package/node_modules/@slack/web-api/node_modules/proxy-from-env/LICENSE +20 -0
- package/node_modules/@slack/web-api/node_modules/proxy-from-env/README.md +163 -0
- package/node_modules/@slack/web-api/node_modules/proxy-from-env/index.cjs +105 -0
- package/node_modules/@slack/web-api/node_modules/proxy-from-env/index.js +103 -0
- package/node_modules/@slack/web-api/node_modules/proxy-from-env/package.json +43 -0
- package/node_modules/@slack/web-api/node_modules/safe-buffer/LICENSE +21 -0
- package/node_modules/@slack/web-api/node_modules/safe-buffer/README.md +584 -0
- package/node_modules/@slack/web-api/node_modules/safe-buffer/index.d.ts +187 -0
- package/node_modules/@slack/web-api/node_modules/safe-buffer/index.js +65 -0
- package/node_modules/@slack/web-api/node_modules/safe-buffer/package.json +51 -0
- package/node_modules/@slack/web-api/package.json +10 -6
- package/node_modules/typebox/build/compile/validator.d.mts +4 -1
- package/node_modules/typebox/build/guard/guard.d.mts +1 -1
- package/node_modules/typebox/build/guard/guard.mjs +2 -5
- package/node_modules/typebox/build/guard/string.mjs +4 -16
- package/node_modules/typebox/build/schema/engine/_functions.mjs +15 -34
- package/node_modules/typebox/build/type/action/readonly_object.d.mts +0 -5
- package/node_modules/typebox/build/type/action/readonly_object.mjs +0 -8
- package/node_modules/typebox/build/typebox.d.mts +1 -1
- package/node_modules/typebox/build/typebox.mjs +1 -1
- package/node_modules/typebox/package.json +1 -1
- package/node_modules/typebox/readme.md +32 -29
- package/node_modules/ws/lib/permessage-deflate.js +3 -1
- package/node_modules/ws/package.json +1 -1
- package/openclaw.plugin.json +1390 -1351
- package/package.json +19 -109
- package/dist/account-configured-BwfXBo_F.js +0 -14
- package/dist/account-inspect-DEKpg9Ip.js +0 -89
- package/dist/account-reply-mode-DrUXogvO.js +0 -14
- package/dist/accounts-CHAeNZOX.js +0 -186
- package/dist/accounts.runtime-BHD4Ma2R.js +0 -2
- package/dist/action-runtime-DfuYoMjG.js +0 -561
- package/dist/action-runtime.runtime-DQErZYpz.js +0 -2
- package/dist/actions-D3NuJvva.js +0 -876
- package/dist/actions.runtime-BIRU_G4M.js +0 -2
- package/dist/approval-handler.runtime-BA05P0QT.js +0 -367
- package/dist/block-text-DkHaoGem.js +0 -79
- package/dist/channel-B9fVdW3s.js +0 -1118
- package/dist/channel-type-DXyos1d2.js +0 -108
- package/dist/channel.setup-CLP5oTvh.js +0 -56
- package/dist/config-adapter-CxBQH8fq.js +0 -566
- package/dist/config-schema-SgZT6nXV.js +0 -373
- package/dist/cursor-pages-eX7p8Wwt.js +0 -19
- package/dist/directory-config-CnCIAktf.js +0 -54
- package/dist/directory-live-DKunWh3A.js +0 -131
- package/dist/doctor-contract-CsGH1Dfc.js +0 -158
- package/dist/group-policy-NQZti9t-.js +0 -2442
- package/dist/message-tool-api-DkhFpMoy.js +0 -127
- package/dist/monitor-CmKz0wtI.js +0 -13
- package/dist/outbound-adapter-BkuMp2Vs.js +0 -236
- package/dist/pipeline.runtime-DgtmuYCP.js +0 -4360
- package/dist/plugin-routes-CLp4obpN.js +0 -22
- package/dist/policy-PRysPn23.js +0 -65
- package/dist/preflight-audio.runtime-D5Bgags0.js +0 -3
- package/dist/probe-CgDsSops.js +0 -345
- package/dist/provider-DmRizMZt.js +0 -5900
- package/dist/relay-source-Blxj8xb4.js +0 -272
- package/dist/replies-4s_Vq_z9.js +0 -457
- package/dist/resolve-channels-yEqmM-3I.js +0 -92
- package/dist/resolve-users-BOrt5K-5.js +0 -118
- package/dist/rolldown-runtime-8H4AJuhK.js +0 -14
- package/dist/runtime-JSVZSWAj.js +0 -8
- package/dist/runtime-api-QMb-Q5Ko.js +0 -10
- package/dist/scopes-BJSrkAp6.js +0 -73
- package/dist/secret-contract-DxmvbxBF.js +0 -87
- package/dist/security-audit-DR097212.js +0 -41
- package/dist/send-DsLeZpST.js +0 -1269
- package/dist/send.runtime-gUdK6V3h.js +0 -2
- package/dist/setup-surface-BeNzrMrJ.js +0 -148
- package/dist/shared-DgIN3Dcr.js +0 -268
- package/dist/slash-dispatch.runtime-zPkyl7dB.js +0 -33
- package/dist/streaming-compat-3_X-21wW.js +0 -44
- package/dist/target-parsing-N6lHogYZ.js +0 -73
- package/dist/targets-KmjP2E8s.js +0 -13
- package/node_modules/@slack/socket-mode/README.md +0 -221
- package/node_modules/@slack/socket-mode/dist/package.json +0 -75
- package/node_modules/@slack/socket-mode/dist/src/SlackWebSocket.d.ts +0 -102
- package/node_modules/@slack/socket-mode/dist/src/SlackWebSocket.d.ts.map +0 -1
- package/node_modules/@slack/socket-mode/dist/src/SlackWebSocket.js +0 -330
- package/node_modules/@slack/socket-mode/dist/src/SlackWebSocket.js.map +0 -1
- package/node_modules/@slack/socket-mode/dist/src/SocketModeClient.d.ts +0 -104
- package/node_modules/@slack/socket-mode/dist/src/SocketModeClient.d.ts.map +0 -1
- package/node_modules/@slack/socket-mode/dist/src/SocketModeClient.js +0 -412
- package/node_modules/@slack/socket-mode/dist/src/SocketModeClient.js.map +0 -1
- package/node_modules/@slack/socket-mode/dist/src/SocketModeOptions.d.ts +0 -77
- package/node_modules/@slack/socket-mode/dist/src/SocketModeOptions.d.ts.map +0 -1
- package/node_modules/@slack/socket-mode/dist/src/errors.d.ts +0 -54
- package/node_modules/@slack/socket-mode/dist/src/errors.d.ts.map +0 -1
- package/node_modules/@slack/socket-mode/dist/src/errors.js +0 -64
- package/node_modules/@slack/socket-mode/dist/src/errors.js.map +0 -1
- package/node_modules/@slack/socket-mode/dist/src/index.d.ts +0 -6
- package/node_modules/@slack/socket-mode/dist/src/index.d.ts.map +0 -1
- package/node_modules/@slack/socket-mode/dist/src/index.js +0 -19
- package/node_modules/@slack/socket-mode/dist/src/index.js.map +0 -1
- package/node_modules/@slack/socket-mode/node_modules/@slack/logger/LICENSE +0 -23
- package/node_modules/@slack/socket-mode/node_modules/@slack/logger/README.md +0 -66
- package/node_modules/@slack/socket-mode/node_modules/@slack/logger/dist/index.d.ts +0 -94
- package/node_modules/@slack/socket-mode/node_modules/@slack/logger/dist/index.d.ts.map +0 -1
- package/node_modules/@slack/socket-mode/node_modules/@slack/logger/dist/index.js +0 -98
- package/node_modules/@slack/socket-mode/node_modules/@slack/logger/dist/index.js.map +0 -1
- package/node_modules/@slack/socket-mode/node_modules/@slack/logger/package.json +0 -42
- package/node_modules/@slack/socket-mode/node_modules/@types/node/README.md +0 -15
- package/node_modules/@slack/socket-mode/node_modules/@types/node/assert/strict.d.ts +0 -68
- package/node_modules/@slack/socket-mode/node_modules/@types/node/assert.d.ts +0 -1077
- package/node_modules/@slack/socket-mode/node_modules/@types/node/async_hooks.d.ts +0 -711
- package/node_modules/@slack/socket-mode/node_modules/@types/node/buffer.buffer.d.ts +0 -466
- package/node_modules/@slack/socket-mode/node_modules/@types/node/buffer.d.ts +0 -1799
- package/node_modules/@slack/socket-mode/node_modules/@types/node/child_process.d.ts +0 -1362
- package/node_modules/@slack/socket-mode/node_modules/@types/node/cluster.d.ts +0 -432
- package/node_modules/@slack/socket-mode/node_modules/@types/node/console.d.ts +0 -93
- package/node_modules/@slack/socket-mode/node_modules/@types/node/constants.d.ts +0 -14
- package/node_modules/@slack/socket-mode/node_modules/@types/node/crypto.d.ts +0 -3954
- package/node_modules/@slack/socket-mode/node_modules/@types/node/dgram.d.ts +0 -537
- package/node_modules/@slack/socket-mode/node_modules/@types/node/diagnostics_channel.d.ts +0 -794
- package/node_modules/@slack/socket-mode/node_modules/@types/node/dns/promises.d.ts +0 -497
- package/node_modules/@slack/socket-mode/node_modules/@types/node/dns.d.ts +0 -876
- package/node_modules/@slack/socket-mode/node_modules/@types/node/domain.d.ts +0 -150
- package/node_modules/@slack/socket-mode/node_modules/@types/node/events.d.ts +0 -1008
- package/node_modules/@slack/socket-mode/node_modules/@types/node/ffi.d.ts +0 -486
- package/node_modules/@slack/socket-mode/node_modules/@types/node/fs/promises.d.ts +0 -1481
- package/node_modules/@slack/socket-mode/node_modules/@types/node/fs.d.ts +0 -4786
- package/node_modules/@slack/socket-mode/node_modules/@types/node/globals.d.ts +0 -150
- package/node_modules/@slack/socket-mode/node_modules/@types/node/globals.typedarray.d.ts +0 -101
- package/node_modules/@slack/socket-mode/node_modules/@types/node/http.d.ts +0 -2172
- package/node_modules/@slack/socket-mode/node_modules/@types/node/http2.d.ts +0 -2489
- package/node_modules/@slack/socket-mode/node_modules/@types/node/https.d.ts +0 -400
- package/node_modules/@slack/socket-mode/node_modules/@types/node/index.d.ts +0 -115
- package/node_modules/@slack/socket-mode/node_modules/@types/node/inspector/promises.d.ts +0 -35
- package/node_modules/@slack/socket-mode/node_modules/@types/node/inspector.d.ts +0 -264
- package/node_modules/@slack/socket-mode/node_modules/@types/node/inspector.generated.d.ts +0 -4406
- package/node_modules/@slack/socket-mode/node_modules/@types/node/module.d.ts +0 -726
- package/node_modules/@slack/socket-mode/node_modules/@types/node/net.d.ts +0 -970
- package/node_modules/@slack/socket-mode/node_modules/@types/node/os.d.ts +0 -498
- package/node_modules/@slack/socket-mode/node_modules/@types/node/package.json +0 -155
- package/node_modules/@slack/socket-mode/node_modules/@types/node/path/posix.d.ts +0 -8
- package/node_modules/@slack/socket-mode/node_modules/@types/node/path/win32.d.ts +0 -8
- package/node_modules/@slack/socket-mode/node_modules/@types/node/path.d.ts +0 -178
- package/node_modules/@slack/socket-mode/node_modules/@types/node/perf_hooks.d.ts +0 -604
- package/node_modules/@slack/socket-mode/node_modules/@types/node/process.d.ts +0 -2217
- package/node_modules/@slack/socket-mode/node_modules/@types/node/punycode.d.ts +0 -89
- package/node_modules/@slack/socket-mode/node_modules/@types/node/querystring.d.ts +0 -139
- package/node_modules/@slack/socket-mode/node_modules/@types/node/quic.d.ts +0 -978
- package/node_modules/@slack/socket-mode/node_modules/@types/node/readline/promises.d.ts +0 -158
- package/node_modules/@slack/socket-mode/node_modules/@types/node/readline.d.ts +0 -508
- package/node_modules/@slack/socket-mode/node_modules/@types/node/repl.d.ts +0 -420
- package/node_modules/@slack/socket-mode/node_modules/@types/node/sea.d.ts +0 -47
- package/node_modules/@slack/socket-mode/node_modules/@types/node/sqlite.d.ts +0 -1123
- package/node_modules/@slack/socket-mode/node_modules/@types/node/stream/consumers.d.ts +0 -114
- package/node_modules/@slack/socket-mode/node_modules/@types/node/stream/iter.d.ts +0 -451
- package/node_modules/@slack/socket-mode/node_modules/@types/node/stream/promises.d.ts +0 -211
- package/node_modules/@slack/socket-mode/node_modules/@types/node/stream/web.d.ts +0 -300
- package/node_modules/@slack/socket-mode/node_modules/@types/node/stream.d.ts +0 -1806
- package/node_modules/@slack/socket-mode/node_modules/@types/node/string_decoder.d.ts +0 -27
- package/node_modules/@slack/socket-mode/node_modules/@types/node/test/reporters.d.ts +0 -59
- package/node_modules/@slack/socket-mode/node_modules/@types/node/test.d.ts +0 -2389
- package/node_modules/@slack/socket-mode/node_modules/@types/node/timers/promises.d.ts +0 -93
- package/node_modules/@slack/socket-mode/node_modules/@types/node/timers.d.ts +0 -149
- package/node_modules/@slack/socket-mode/node_modules/@types/node/tls.d.ts +0 -1193
- package/node_modules/@slack/socket-mode/node_modules/@types/node/trace_events.d.ts +0 -103
- package/node_modules/@slack/socket-mode/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +0 -462
- package/node_modules/@slack/socket-mode/node_modules/@types/node/ts5.6/compatibility/float16array.d.ts +0 -71
- package/node_modules/@slack/socket-mode/node_modules/@types/node/ts5.6/globals.typedarray.d.ts +0 -36
- package/node_modules/@slack/socket-mode/node_modules/@types/node/ts5.6/index.d.ts +0 -117
- package/node_modules/@slack/socket-mode/node_modules/@types/node/ts5.7/compatibility/float16array.d.ts +0 -72
- package/node_modules/@slack/socket-mode/node_modules/@types/node/ts5.7/index.d.ts +0 -117
- package/node_modules/@slack/socket-mode/node_modules/@types/node/tty.d.ts +0 -225
- package/node_modules/@slack/socket-mode/node_modules/@types/node/url.d.ts +0 -556
- package/node_modules/@slack/socket-mode/node_modules/@types/node/util/types.d.ts +0 -558
- package/node_modules/@slack/socket-mode/node_modules/@types/node/util.d.ts +0 -1677
- package/node_modules/@slack/socket-mode/node_modules/@types/node/v8.d.ts +0 -1062
- package/node_modules/@slack/socket-mode/node_modules/@types/node/vm.d.ts +0 -1136
- package/node_modules/@slack/socket-mode/node_modules/@types/node/wasi.d.ts +0 -131
- package/node_modules/@slack/socket-mode/node_modules/@types/node/web-globals/abortcontroller.d.ts +0 -59
- package/node_modules/@slack/socket-mode/node_modules/@types/node/web-globals/blob.d.ts +0 -23
- package/node_modules/@slack/socket-mode/node_modules/@types/node/web-globals/console.d.ts +0 -9
- package/node_modules/@slack/socket-mode/node_modules/@types/node/web-globals/crypto.d.ts +0 -39
- package/node_modules/@slack/socket-mode/node_modules/@types/node/web-globals/domexception.d.ts +0 -83
- package/node_modules/@slack/socket-mode/node_modules/@types/node/web-globals/encoding.d.ts +0 -11
- package/node_modules/@slack/socket-mode/node_modules/@types/node/web-globals/events.d.ts +0 -106
- package/node_modules/@slack/socket-mode/node_modules/@types/node/web-globals/fetch.d.ts +0 -69
- package/node_modules/@slack/socket-mode/node_modules/@types/node/web-globals/importmeta.d.ts +0 -13
- package/node_modules/@slack/socket-mode/node_modules/@types/node/web-globals/messaging.d.ts +0 -23
- package/node_modules/@slack/socket-mode/node_modules/@types/node/web-globals/navigator.d.ts +0 -25
- package/node_modules/@slack/socket-mode/node_modules/@types/node/web-globals/performance.d.ts +0 -45
- package/node_modules/@slack/socket-mode/node_modules/@types/node/web-globals/storage.d.ts +0 -24
- package/node_modules/@slack/socket-mode/node_modules/@types/node/web-globals/streams.d.ts +0 -115
- package/node_modules/@slack/socket-mode/node_modules/@types/node/web-globals/timers.d.ts +0 -44
- package/node_modules/@slack/socket-mode/node_modules/@types/node/web-globals/url.d.ts +0 -24
- package/node_modules/@slack/socket-mode/node_modules/@types/node/worker_threads.d.ts +0 -669
- package/node_modules/@slack/socket-mode/node_modules/@types/node/zlib/iter.d.ts +0 -131
- package/node_modules/@slack/socket-mode/node_modules/@types/node/zlib.d.ts +0 -589
- package/node_modules/@slack/socket-mode/node_modules/undici-types/LICENSE +0 -21
- package/node_modules/@slack/socket-mode/node_modules/undici-types/README.md +0 -6
- package/node_modules/@slack/socket-mode/node_modules/undici-types/agent.d.ts +0 -30
- package/node_modules/@slack/socket-mode/node_modules/undici-types/api.d.ts +0 -43
- package/node_modules/@slack/socket-mode/node_modules/undici-types/balanced-pool.d.ts +0 -30
- package/node_modules/@slack/socket-mode/node_modules/undici-types/cache-interceptor.d.ts +0 -179
- package/node_modules/@slack/socket-mode/node_modules/undici-types/cache.d.ts +0 -36
- package/node_modules/@slack/socket-mode/node_modules/undici-types/client-stats.d.ts +0 -15
- package/node_modules/@slack/socket-mode/node_modules/undici-types/client.d.ts +0 -129
- package/node_modules/@slack/socket-mode/node_modules/undici-types/connector.d.ts +0 -36
- package/node_modules/@slack/socket-mode/node_modules/undici-types/content-type.d.ts +0 -21
- package/node_modules/@slack/socket-mode/node_modules/undici-types/cookies.d.ts +0 -30
- package/node_modules/@slack/socket-mode/node_modules/undici-types/diagnostics-channel.d.ts +0 -74
- package/node_modules/@slack/socket-mode/node_modules/undici-types/dispatcher.d.ts +0 -253
- package/node_modules/@slack/socket-mode/node_modules/undici-types/dispatcher1-wrapper.d.ts +0 -7
- package/node_modules/@slack/socket-mode/node_modules/undici-types/env-http-proxy-agent.d.ts +0 -22
- package/node_modules/@slack/socket-mode/node_modules/undici-types/errors.d.ts +0 -177
- package/node_modules/@slack/socket-mode/node_modules/undici-types/eventsource.d.ts +0 -66
- package/node_modules/@slack/socket-mode/node_modules/undici-types/fetch.d.ts +0 -231
- package/node_modules/@slack/socket-mode/node_modules/undici-types/formdata.d.ts +0 -108
- package/node_modules/@slack/socket-mode/node_modules/undici-types/global-dispatcher.d.ts +0 -9
- package/node_modules/@slack/socket-mode/node_modules/undici-types/global-origin.d.ts +0 -7
- package/node_modules/@slack/socket-mode/node_modules/undici-types/h2c-client.d.ts +0 -73
- package/node_modules/@slack/socket-mode/node_modules/undici-types/handlers.d.ts +0 -14
- package/node_modules/@slack/socket-mode/node_modules/undici-types/header.d.ts +0 -165
- package/node_modules/@slack/socket-mode/node_modules/undici-types/index.d.ts +0 -93
- package/node_modules/@slack/socket-mode/node_modules/undici-types/interceptors.d.ts +0 -80
- package/node_modules/@slack/socket-mode/node_modules/undici-types/mock-agent.d.ts +0 -68
- package/node_modules/@slack/socket-mode/node_modules/undici-types/mock-call-history.d.ts +0 -111
- package/node_modules/@slack/socket-mode/node_modules/undici-types/mock-client.d.ts +0 -27
- package/node_modules/@slack/socket-mode/node_modules/undici-types/mock-errors.d.ts +0 -12
- package/node_modules/@slack/socket-mode/node_modules/undici-types/mock-interceptor.d.ts +0 -94
- package/node_modules/@slack/socket-mode/node_modules/undici-types/mock-pool.d.ts +0 -27
- package/node_modules/@slack/socket-mode/node_modules/undici-types/package.json +0 -55
- package/node_modules/@slack/socket-mode/node_modules/undici-types/patch.d.ts +0 -29
- package/node_modules/@slack/socket-mode/node_modules/undici-types/pool-stats.d.ts +0 -19
- package/node_modules/@slack/socket-mode/node_modules/undici-types/pool.d.ts +0 -39
- package/node_modules/@slack/socket-mode/node_modules/undici-types/proxy-agent.d.ts +0 -29
- package/node_modules/@slack/socket-mode/node_modules/undici-types/readable.d.ts +0 -68
- package/node_modules/@slack/socket-mode/node_modules/undici-types/retry-agent.d.ts +0 -8
- package/node_modules/@slack/socket-mode/node_modules/undici-types/retry-handler.d.ts +0 -125
- package/node_modules/@slack/socket-mode/node_modules/undici-types/round-robin-pool.d.ts +0 -39
- package/node_modules/@slack/socket-mode/node_modules/undici-types/snapshot-agent.d.ts +0 -113
- package/node_modules/@slack/socket-mode/node_modules/undici-types/socks5-proxy-agent.d.ts +0 -25
- package/node_modules/@slack/socket-mode/node_modules/undici-types/util.d.ts +0 -18
- package/node_modules/@slack/socket-mode/node_modules/undici-types/utility.d.ts +0 -7
- package/node_modules/@slack/socket-mode/node_modules/undici-types/webidl.d.ts +0 -346
- package/node_modules/@slack/socket-mode/node_modules/undici-types/websocket.d.ts +0 -188
- package/node_modules/@slack/socket-mode/package.json +0 -75
- package/node_modules/get-east-asian-width/index.d.ts +0 -60
- package/node_modules/get-east-asian-width/index.js +0 -30
- package/node_modules/get-east-asian-width/lookup-data.js +0 -21
- package/node_modules/get-east-asian-width/lookup.js +0 -138
- package/node_modules/get-east-asian-width/package.json +0 -71
- package/node_modules/get-east-asian-width/readme.md +0 -65
- package/node_modules/get-east-asian-width/utilities.js +0 -24
- package/node_modules/p-map/index.d.ts +0 -155
- package/node_modules/p-map/index.js +0 -285
- package/node_modules/p-map/license +0 -9
- package/node_modules/p-map/package.json +0 -57
- package/node_modules/p-map/readme.md +0 -190
- package/node_modules/undici/LICENSE +0 -21
- package/node_modules/undici/README.md +0 -741
- package/node_modules/undici/docs/docs/api/Agent.md +0 -84
- package/node_modules/undici/docs/docs/api/BalancedPool.md +0 -99
- package/node_modules/undici/docs/docs/api/CacheStorage.md +0 -30
- package/node_modules/undici/docs/docs/api/CacheStore.md +0 -164
- package/node_modules/undici/docs/docs/api/Client.md +0 -288
- package/node_modules/undici/docs/docs/api/ClientStats.md +0 -27
- package/node_modules/undici/docs/docs/api/Connector.md +0 -115
- package/node_modules/undici/docs/docs/api/ContentType.md +0 -57
- package/node_modules/undici/docs/docs/api/Cookies.md +0 -128
- package/node_modules/undici/docs/docs/api/Debug.md +0 -62
- package/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +0 -315
- package/node_modules/undici/docs/docs/api/Dispatcher.md +0 -1392
- package/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +0 -159
- package/node_modules/undici/docs/docs/api/Errors.md +0 -49
- package/node_modules/undici/docs/docs/api/EventSource.md +0 -45
- package/node_modules/undici/docs/docs/api/Fetch.md +0 -60
- package/node_modules/undici/docs/docs/api/GlobalInstallation.md +0 -139
- package/node_modules/undici/docs/docs/api/H2CClient.md +0 -263
- package/node_modules/undici/docs/docs/api/MockAgent.md +0 -603
- package/node_modules/undici/docs/docs/api/MockCallHistory.md +0 -197
- package/node_modules/undici/docs/docs/api/MockCallHistoryLog.md +0 -43
- package/node_modules/undici/docs/docs/api/MockClient.md +0 -81
- package/node_modules/undici/docs/docs/api/MockErrors.md +0 -12
- package/node_modules/undici/docs/docs/api/MockPool.md +0 -555
- package/node_modules/undici/docs/docs/api/Pool.md +0 -84
- package/node_modules/undici/docs/docs/api/PoolStats.md +0 -35
- package/node_modules/undici/docs/docs/api/ProxyAgent.md +0 -229
- package/node_modules/undici/docs/docs/api/RedirectHandler.md +0 -93
- package/node_modules/undici/docs/docs/api/RetryAgent.md +0 -50
- package/node_modules/undici/docs/docs/api/RetryHandler.md +0 -118
- package/node_modules/undici/docs/docs/api/RoundRobinPool.md +0 -145
- package/node_modules/undici/docs/docs/api/SnapshotAgent.md +0 -616
- package/node_modules/undici/docs/docs/api/Socks5ProxyAgent.md +0 -275
- package/node_modules/undici/docs/docs/api/Util.md +0 -25
- package/node_modules/undici/docs/docs/api/WebSocket.md +0 -141
- package/node_modules/undici/docs/docs/api/api-lifecycle.md +0 -91
- package/node_modules/undici/docs/docs/best-practices/client-certificate.md +0 -64
- package/node_modules/undici/docs/docs/best-practices/crawling.md +0 -58
- package/node_modules/undici/docs/docs/best-practices/mocking-request.md +0 -190
- package/node_modules/undici/docs/docs/best-practices/proxy.md +0 -127
- package/node_modules/undici/docs/docs/best-practices/undici-vs-builtin-fetch.md +0 -224
- package/node_modules/undici/docs/docs/best-practices/writing-tests.md +0 -63
- package/node_modules/undici/index-fetch.js +0 -65
- package/node_modules/undici/index.d.ts +0 -3
- package/node_modules/undici/index.js +0 -234
- package/node_modules/undici/lib/api/abort-signal.js +0 -59
- package/node_modules/undici/lib/api/api-connect.js +0 -110
- package/node_modules/undici/lib/api/api-pipeline.js +0 -252
- package/node_modules/undici/lib/api/api-request.js +0 -214
- package/node_modules/undici/lib/api/api-stream.js +0 -209
- package/node_modules/undici/lib/api/api-upgrade.js +0 -111
- package/node_modules/undici/lib/api/index.js +0 -7
- package/node_modules/undici/lib/api/readable.js +0 -580
- package/node_modules/undici/lib/cache/memory-cache-store.js +0 -234
- package/node_modules/undici/lib/cache/sqlite-cache-store.js +0 -461
- package/node_modules/undici/lib/core/connect.js +0 -153
- package/node_modules/undici/lib/core/constants.js +0 -143
- package/node_modules/undici/lib/core/diagnostics.js +0 -227
- package/node_modules/undici/lib/core/errors.js +0 -477
- package/node_modules/undici/lib/core/request.js +0 -453
- package/node_modules/undici/lib/core/socks5-client.js +0 -422
- package/node_modules/undici/lib/core/socks5-utils.js +0 -212
- package/node_modules/undici/lib/core/symbols.js +0 -75
- package/node_modules/undici/lib/core/tree.js +0 -160
- package/node_modules/undici/lib/core/util.js +0 -992
- package/node_modules/undici/lib/dispatcher/agent.js +0 -158
- package/node_modules/undici/lib/dispatcher/balanced-pool.js +0 -219
- package/node_modules/undici/lib/dispatcher/client-h1.js +0 -1722
- package/node_modules/undici/lib/dispatcher/client-h2.js +0 -995
- package/node_modules/undici/lib/dispatcher/client.js +0 -664
- package/node_modules/undici/lib/dispatcher/dispatcher-base.js +0 -184
- package/node_modules/undici/lib/dispatcher/dispatcher.js +0 -48
- package/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +0 -146
- package/node_modules/undici/lib/dispatcher/fixed-queue.js +0 -135
- package/node_modules/undici/lib/dispatcher/h2c-client.js +0 -51
- package/node_modules/undici/lib/dispatcher/pool-base.js +0 -214
- package/node_modules/undici/lib/dispatcher/pool.js +0 -118
- package/node_modules/undici/lib/dispatcher/proxy-agent.js +0 -319
- package/node_modules/undici/lib/dispatcher/retry-agent.js +0 -35
- package/node_modules/undici/lib/dispatcher/round-robin-pool.js +0 -137
- package/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +0 -260
- package/node_modules/undici/lib/encoding/index.js +0 -33
- package/node_modules/undici/lib/global.js +0 -59
- package/node_modules/undici/lib/handler/cache-handler.js +0 -578
- package/node_modules/undici/lib/handler/cache-revalidation-handler.js +0 -124
- package/node_modules/undici/lib/handler/decorator-handler.js +0 -67
- package/node_modules/undici/lib/handler/deduplication-handler.js +0 -460
- package/node_modules/undici/lib/handler/redirect-handler.js +0 -238
- package/node_modules/undici/lib/handler/retry-handler.js +0 -394
- package/node_modules/undici/lib/handler/unwrap-handler.js +0 -106
- package/node_modules/undici/lib/handler/wrap-handler.js +0 -105
- package/node_modules/undici/lib/interceptor/cache.js +0 -495
- package/node_modules/undici/lib/interceptor/decompress.js +0 -259
- package/node_modules/undici/lib/interceptor/deduplicate.js +0 -117
- package/node_modules/undici/lib/interceptor/dns.js +0 -571
- package/node_modules/undici/lib/interceptor/dump.js +0 -112
- package/node_modules/undici/lib/interceptor/redirect.js +0 -21
- package/node_modules/undici/lib/interceptor/response-error.js +0 -95
- package/node_modules/undici/lib/interceptor/retry.js +0 -19
- package/node_modules/undici/lib/llhttp/.gitkeep +0 -0
- package/node_modules/undici/lib/llhttp/constants.d.ts +0 -195
- package/node_modules/undici/lib/llhttp/constants.js +0 -531
- package/node_modules/undici/lib/llhttp/llhttp-wasm.js +0 -15
- package/node_modules/undici/lib/llhttp/llhttp_simd-wasm.js +0 -15
- package/node_modules/undici/lib/llhttp/utils.d.ts +0 -2
- package/node_modules/undici/lib/llhttp/utils.js +0 -12
- package/node_modules/undici/lib/mock/mock-agent.js +0 -232
- package/node_modules/undici/lib/mock/mock-call-history.js +0 -248
- package/node_modules/undici/lib/mock/mock-client.js +0 -68
- package/node_modules/undici/lib/mock/mock-errors.js +0 -29
- package/node_modules/undici/lib/mock/mock-interceptor.js +0 -209
- package/node_modules/undici/lib/mock/mock-pool.js +0 -68
- package/node_modules/undici/lib/mock/mock-symbols.js +0 -32
- package/node_modules/undici/lib/mock/mock-utils.js +0 -486
- package/node_modules/undici/lib/mock/pending-interceptors-formatter.js +0 -43
- package/node_modules/undici/lib/mock/snapshot-agent.js +0 -353
- package/node_modules/undici/lib/mock/snapshot-recorder.js +0 -588
- package/node_modules/undici/lib/mock/snapshot-utils.js +0 -158
- package/node_modules/undici/lib/util/cache.js +0 -414
- package/node_modules/undici/lib/util/date.js +0 -653
- package/node_modules/undici/lib/util/promise.js +0 -28
- package/node_modules/undici/lib/util/runtime-features.js +0 -124
- package/node_modules/undici/lib/util/stats.js +0 -32
- package/node_modules/undici/lib/util/timers.js +0 -425
- package/node_modules/undici/lib/web/cache/cache.js +0 -864
- package/node_modules/undici/lib/web/cache/cachestorage.js +0 -152
- package/node_modules/undici/lib/web/cache/util.js +0 -45
- package/node_modules/undici/lib/web/cookies/constants.js +0 -12
- package/node_modules/undici/lib/web/cookies/index.js +0 -199
- package/node_modules/undici/lib/web/cookies/parse.js +0 -314
- package/node_modules/undici/lib/web/cookies/util.js +0 -282
- package/node_modules/undici/lib/web/eventsource/eventsource-stream.js +0 -399
- package/node_modules/undici/lib/web/eventsource/eventsource.js +0 -501
- package/node_modules/undici/lib/web/eventsource/util.js +0 -29
- package/node_modules/undici/lib/web/fetch/LICENSE +0 -21
- package/node_modules/undici/lib/web/fetch/body.js +0 -509
- package/node_modules/undici/lib/web/fetch/constants.js +0 -131
- package/node_modules/undici/lib/web/fetch/data-url.js +0 -596
- package/node_modules/undici/lib/web/fetch/formdata-parser.js +0 -586
- package/node_modules/undici/lib/web/fetch/formdata.js +0 -259
- package/node_modules/undici/lib/web/fetch/global.js +0 -40
- package/node_modules/undici/lib/web/fetch/headers.js +0 -719
- package/node_modules/undici/lib/web/fetch/index.js +0 -2413
- package/node_modules/undici/lib/web/fetch/request.js +0 -1115
- package/node_modules/undici/lib/web/fetch/response.js +0 -641
- package/node_modules/undici/lib/web/fetch/util.js +0 -1522
- package/node_modules/undici/lib/web/infra/index.js +0 -229
- package/node_modules/undici/lib/web/subresource-integrity/Readme.md +0 -9
- package/node_modules/undici/lib/web/subresource-integrity/subresource-integrity.js +0 -307
- package/node_modules/undici/lib/web/webidl/index.js +0 -1006
- package/node_modules/undici/lib/web/websocket/connection.js +0 -329
- package/node_modules/undici/lib/web/websocket/constants.js +0 -126
- package/node_modules/undici/lib/web/websocket/events.js +0 -331
- package/node_modules/undici/lib/web/websocket/frame.js +0 -133
- package/node_modules/undici/lib/web/websocket/permessage-deflate.js +0 -100
- package/node_modules/undici/lib/web/websocket/receiver.js +0 -507
- package/node_modules/undici/lib/web/websocket/sender.js +0 -109
- package/node_modules/undici/lib/web/websocket/stream/websocketerror.js +0 -104
- package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +0 -498
- package/node_modules/undici/lib/web/websocket/util.js +0 -347
- package/node_modules/undici/lib/web/websocket/websocket.js +0 -758
- package/node_modules/undici/package.json +0 -152
- package/node_modules/undici/scripts/strip-comments.js +0 -10
- package/node_modules/undici/types/README.md +0 -6
- package/node_modules/undici/types/agent.d.ts +0 -32
- package/node_modules/undici/types/api.d.ts +0 -43
- package/node_modules/undici/types/balanced-pool.d.ts +0 -30
- package/node_modules/undici/types/cache-interceptor.d.ts +0 -179
- package/node_modules/undici/types/cache.d.ts +0 -36
- package/node_modules/undici/types/client-stats.d.ts +0 -15
- package/node_modules/undici/types/client.d.ts +0 -139
- package/node_modules/undici/types/connector.d.ts +0 -36
- package/node_modules/undici/types/content-type.d.ts +0 -21
- package/node_modules/undici/types/cookies.d.ts +0 -30
- package/node_modules/undici/types/diagnostics-channel.d.ts +0 -74
- package/node_modules/undici/types/dispatcher.d.ts +0 -275
- package/node_modules/undici/types/env-http-proxy-agent.d.ts +0 -22
- package/node_modules/undici/types/errors.d.ts +0 -177
- package/node_modules/undici/types/eventsource.d.ts +0 -66
- package/node_modules/undici/types/fetch.d.ts +0 -231
- package/node_modules/undici/types/formdata.d.ts +0 -114
- package/node_modules/undici/types/global-dispatcher.d.ts +0 -9
- package/node_modules/undici/types/global-origin.d.ts +0 -7
- package/node_modules/undici/types/h2c-client.d.ts +0 -73
- package/node_modules/undici/types/handlers.d.ts +0 -14
- package/node_modules/undici/types/header.d.ts +0 -160
- package/node_modules/undici/types/index.d.ts +0 -91
- package/node_modules/undici/types/interceptors.d.ts +0 -80
- package/node_modules/undici/types/mock-agent.d.ts +0 -68
- package/node_modules/undici/types/mock-call-history.d.ts +0 -111
- package/node_modules/undici/types/mock-client.d.ts +0 -27
- package/node_modules/undici/types/mock-errors.d.ts +0 -12
- package/node_modules/undici/types/mock-interceptor.d.ts +0 -94
- package/node_modules/undici/types/mock-pool.d.ts +0 -27
- package/node_modules/undici/types/patch.d.ts +0 -29
- package/node_modules/undici/types/pool-stats.d.ts +0 -19
- package/node_modules/undici/types/pool.d.ts +0 -41
- package/node_modules/undici/types/proxy-agent.d.ts +0 -29
- package/node_modules/undici/types/readable.d.ts +0 -68
- package/node_modules/undici/types/retry-agent.d.ts +0 -8
- package/node_modules/undici/types/retry-handler.d.ts +0 -125
- package/node_modules/undici/types/round-robin-pool.d.ts +0 -41
- package/node_modules/undici/types/snapshot-agent.d.ts +0 -109
- package/node_modules/undici/types/socks5-proxy-agent.d.ts +0 -25
- package/node_modules/undici/types/util.d.ts +0 -18
- package/node_modules/undici/types/utility.d.ts +0 -7
- package/node_modules/undici/types/webidl.d.ts +0 -347
- package/node_modules/undici/types/websocket.d.ts +0 -188
- /package/dist/{registry-bbjH7IHX.js → .setup/registry-bbjH7IHX.mjs} +0 -0
- /package/dist/{slash-commands.runtime-BTTMlmwy.js → .setup/slash-commands.runtime-BTTMlmwy.mjs} +0 -0
- /package/dist/{slash-plugin-commands.runtime-Dosfcx3X.js → .setup/slash-plugin-commands.runtime-Dosfcx3X.mjs} +0 -0
- /package/dist/{slash-skill-commands.runtime-CD1J2ODY.js → .setup/slash-skill-commands.runtime-CD1J2ODY.mjs} +0 -0
- /package/dist/{thread-ts-DUGhaYKq.js → .setup/thread-ts-DUGhaYKq.mjs} +0 -0
- /package/node_modules/@slack/{socket-mode → bolt/node_modules/@slack/socket-mode}/LICENSE +0 -0
- /package/node_modules/@slack/{socket-mode → bolt/node_modules/@slack/socket-mode}/dist/src/SocketModeOptions.js +0 -0
- /package/node_modules/@slack/{socket-mode → bolt/node_modules/@slack/socket-mode}/dist/src/SocketModeOptions.js.map +0 -0
- /package/node_modules/@slack/{socket-mode → bolt/node_modules/@slack/socket-mode}/dist/src/UnrecoverableSocketModeStartError.d.ts +0 -0
- /package/node_modules/@slack/{socket-mode → bolt/node_modules/@slack/socket-mode}/dist/src/UnrecoverableSocketModeStartError.d.ts.map +0 -0
- /package/node_modules/@slack/{socket-mode → bolt/node_modules/@slack/socket-mode}/dist/src/UnrecoverableSocketModeStartError.js +0 -0
- /package/node_modules/@slack/{socket-mode → bolt/node_modules/@slack/socket-mode}/dist/src/UnrecoverableSocketModeStartError.js.map +0 -0
- /package/node_modules/@slack/{socket-mode → bolt/node_modules/@slack/socket-mode}/dist/src/logger.d.ts +0 -0
- /package/node_modules/@slack/{socket-mode → bolt/node_modules/@slack/socket-mode}/dist/src/logger.d.ts.map +0 -0
- /package/node_modules/@slack/{socket-mode → bolt/node_modules/@slack/socket-mode}/dist/src/logger.js +0 -0
- /package/node_modules/@slack/{socket-mode → bolt/node_modules/@slack/socket-mode}/dist/src/logger.js.map +0 -0
- /package/node_modules/@slack/{socket-mode/node_modules/@types/node → bolt/node_modules/@types/ws}/LICENSE +0 -0
- /package/node_modules/@slack/{socket-mode → bolt}/node_modules/eventemitter3/LICENSE +0 -0
- /package/node_modules/@slack/{socket-mode → bolt}/node_modules/eventemitter3/README.md +0 -0
- /package/node_modules/@slack/{socket-mode → bolt}/node_modules/eventemitter3/dist/eventemitter3.esm.js +0 -0
- /package/node_modules/@slack/{socket-mode → bolt}/node_modules/eventemitter3/dist/eventemitter3.esm.min.js +0 -0
- /package/node_modules/@slack/{socket-mode → bolt}/node_modules/eventemitter3/dist/eventemitter3.esm.min.js.map +0 -0
- /package/node_modules/@slack/{socket-mode → bolt}/node_modules/eventemitter3/dist/eventemitter3.umd.js +0 -0
- /package/node_modules/@slack/{socket-mode → bolt}/node_modules/eventemitter3/dist/eventemitter3.umd.min.js +0 -0
- /package/node_modules/@slack/{socket-mode → bolt}/node_modules/eventemitter3/dist/eventemitter3.umd.min.js.map +0 -0
- /package/node_modules/@slack/{socket-mode → bolt}/node_modules/eventemitter3/index.d.ts +0 -0
- /package/node_modules/@slack/{socket-mode → bolt}/node_modules/eventemitter3/index.js +0 -0
- /package/node_modules/@slack/{socket-mode → bolt}/node_modules/eventemitter3/index.mjs +0 -0
- /package/node_modules/@slack/{socket-mode → bolt}/node_modules/eventemitter3/package.json +0 -0
- /package/node_modules/{get-east-asian-width → @slack/web-api/node_modules/is-stream}/license +0 -0
|
@@ -0,0 +1,4720 @@
|
|
|
1
|
+
import { n as registerSlackHttpHandler, r as normalizeSlackWebhookPath } from "./registry-bbjH7IHX.mjs";
|
|
2
|
+
import { a as resolveSlackAccount, d as resolveSlackAppToken, f as resolveSlackBotToken, o as resolveSlackAccountAllowFrom, s as resolveSlackAccountDmPolicy, u as formatSlackBotTokenIdentityWarning } from "./accounts-uGn8E6uq.mjs";
|
|
3
|
+
import { B as isSlackExecApprovalAuthorizedSender, D as isSlackAnyNativeApprovalClientEnabled, R as isSlackApprovalAuthorizedSender, a as SLACK_TEXT_LIMIT, b as truncateSlackText, c as formatSlackError, d as normalizeAllowListLower, f as normalizeSlackAllowOwnerEntry, l as allowListMatches, m as resolveSlackAllowListMatch, p as normalizeSlackSlug, u as normalizeAllowList } from "./reply-blocks-Cwu6LYJI.mjs";
|
|
4
|
+
import { n as isSlackInteractiveRepliesEnabled, t as compileSlackInteractiveReplies } from "./interactive-replies-BLw4HEPS.mjs";
|
|
5
|
+
import { c as resolveSlackWebClientOptions } from "./client-B6i83rHk.mjs";
|
|
6
|
+
import { t as getOptionalSlackRuntime } from "./runtime-BOk7xkOl.mjs";
|
|
7
|
+
import { i as setSlackDefaultSendIdentity } from "./send-DEOvcVM4.mjs";
|
|
8
|
+
import { t as resolveSlackChannelAllowlist } from "./resolve-channels-CivvCeZv.mjs";
|
|
9
|
+
import { t as resolveSlackUserAllowlist } from "./resolve-users-D5Qb64BJ.mjs";
|
|
10
|
+
import { n as resolveSlackChannelConfig, r as resolveSlackChannelLabel, t as isSlackChannelAllowedByPolicy } from "./policy-C6VVHqUf.mjs";
|
|
11
|
+
import { normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
12
|
+
import { asOptionalRecord, isRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries, normalizeStringEntriesLower, normalizeUniqueTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
13
|
+
import { normalizeAccountId, normalizeMainKey, resolveAgentRoute, resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
|
|
14
|
+
import { createChannelMessageReplyPipeline } from "openclaw/plugin-sdk/channel-outbound";
|
|
15
|
+
import { createChannelPairingChallengeIssuer } from "openclaw/plugin-sdk/channel-pairing";
|
|
16
|
+
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
17
|
+
import { computeBackoff, createNonExitingRuntime, createSubsystemLogger, danger, getChildLogger, logVerbose, shouldLogVerbose, sleepWithAbort, warn } from "openclaw/plugin-sdk/runtime-env";
|
|
18
|
+
import { chunkItems } from "openclaw/plugin-sdk/text-chunking";
|
|
19
|
+
import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
|
|
20
|
+
import { parseExecApprovalCommandText } from "openclaw/plugin-sdk/approval-reply-runtime";
|
|
21
|
+
import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
|
|
22
|
+
import { addAllowlistUserEntriesFromConfigEntry, buildAllowlistResolutionSummary, formatAllowlistMatchMeta, mergeAllowlist, patchAllowlistUsersInConfigEntries, summarizeMapping } from "openclaw/plugin-sdk/allow-from";
|
|
23
|
+
import { collectErrorGraphCandidates, formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
24
|
+
import { asDateTimestampMs, parseFiniteNumber, parseStrictFiniteNumber, resolveExpiresAtMsFromDurationMs, timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
|
|
25
|
+
import { resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-chunking";
|
|
26
|
+
import { createDedupeCache, createPersistentDedupeCache } from "openclaw/plugin-sdk/dedupe-runtime";
|
|
27
|
+
import { buildPluginBindingResolvedText, parsePluginBindingApprovalCustomId, recordInboundSession, resolveConversationLabel as resolveConversationLabel$1, resolvePluginConversationBindingApproval, resolveRuntimeConversationBindingRoute, upsertChannelPairingRequest } from "openclaw/plugin-sdk/conversation-runtime";
|
|
28
|
+
import { resolveNativeCommandsEnabled, resolveNativeSkillsEnabled } from "openclaw/plugin-sdk/native-command-config-runtime";
|
|
29
|
+
import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context";
|
|
30
|
+
import { DEFAULT_GROUP_HISTORY_LIMIT } from "openclaw/plugin-sdk/reply-history";
|
|
31
|
+
import { installRequestBodyLimitGuard } from "openclaw/plugin-sdk/webhook-request-guards";
|
|
32
|
+
import { getRuntimeConfig, getRuntimeConfig as getRuntimeConfig$1, getRuntimeConfigSnapshot } from "openclaw/plugin-sdk/runtime-config-snapshot";
|
|
33
|
+
import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
|
|
34
|
+
import { getSessionEntry, readSessionUpdatedAt, resolveChannelResetConfig, resolveSessionKey, resolveStorePath, resolveStorePath as resolveStorePath$1, updateLastRoute } from "openclaw/plugin-sdk/session-store-runtime";
|
|
35
|
+
import { resolveChannelContextVisibilityMode } from "openclaw/plugin-sdk/context-visibility-runtime";
|
|
36
|
+
import { resolveDefaultGroupPolicy, resolveOpenProviderRuntimeGroupPolicy as resolveOpenProviderRuntimeGroupPolicy$1, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
|
|
37
|
+
import { loadModelCatalog, resolveDefaultAgentId, resolveDefaultModelForAgent } from "openclaw/plugin-sdk/agent-runtime";
|
|
38
|
+
import { resolveChannelConfigWrites } from "openclaw/plugin-sdk/channel-config-writes";
|
|
39
|
+
import { mutateConfigFile } from "openclaw/plugin-sdk/config-mutation";
|
|
40
|
+
import { enqueueSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
|
|
41
|
+
import { resolveApprovalOverGateway } from "openclaw/plugin-sdk/approval-gateway-runtime";
|
|
42
|
+
import { formatCommandArgMenuTitle, resolveCommandAuthorization, resolveEffectiveAgentRuntime, resolveNativeCommandSessionTargets, resolveStoredModelOverride } from "openclaw/plugin-sdk/command-auth-native";
|
|
43
|
+
import { requestHeartbeat } from "openclaw/plugin-sdk/heartbeat-runtime";
|
|
44
|
+
import { createInteractiveConversationBindingHelpers, dispatchPluginInteractiveHandler } from "openclaw/plugin-sdk/plugin-runtime";
|
|
45
|
+
import { createChannelIngressResolver, defineStableChannelIngressIdentity, readChannelIngressStoreAllowFromForDmPolicy } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
46
|
+
import { createChannelInboundDebouncer, shouldDebounceTextInbound } from "openclaw/plugin-sdk/channel-inbound";
|
|
47
|
+
import { generateSecureToken } from "openclaw/plugin-sdk/secure-random-runtime";
|
|
48
|
+
import { buildUntrustedChannelMetadata } from "openclaw/plugin-sdk/security-runtime";
|
|
49
|
+
//#region extensions/slack/src/monitor/commands.ts
|
|
50
|
+
/**
|
|
51
|
+
* Strip Slack mentions (<@U123>, <@U123|name>) so command detection works on
|
|
52
|
+
* normalized text. Use in both prepare and debounce gate for consistency.
|
|
53
|
+
*/
|
|
54
|
+
function stripSlackMentionsForCommandDetection(text) {
|
|
55
|
+
return (text ?? "").replace(/<@[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
56
|
+
}
|
|
57
|
+
function normalizeSlackSlashCommandName(raw) {
|
|
58
|
+
return raw.replace(/^\/+/, "");
|
|
59
|
+
}
|
|
60
|
+
function resolveSlackSlashCommandConfig(raw) {
|
|
61
|
+
const name = normalizeSlackSlashCommandName(normalizeOptionalString(raw?.name) ?? "openclaw") || "openclaw";
|
|
62
|
+
return {
|
|
63
|
+
enabled: raw?.enabled === true,
|
|
64
|
+
name,
|
|
65
|
+
sessionPrefix: normalizeOptionalString(raw?.sessionPrefix) ?? "slack:slash",
|
|
66
|
+
ephemeral: raw?.ephemeral !== false
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function buildSlackSlashCommandMatcher(name) {
|
|
70
|
+
const escaped = normalizeSlackSlashCommandName(name).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
71
|
+
return new RegExp(`^/?${escaped}$`);
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region extensions/slack/src/monitor/channel-type.ts
|
|
75
|
+
function inferSlackChannelType(channelId) {
|
|
76
|
+
const trimmed = channelId?.trim();
|
|
77
|
+
if (!trimmed) return;
|
|
78
|
+
if (trimmed.startsWith("D")) return "im";
|
|
79
|
+
if (trimmed.startsWith("C")) return "channel";
|
|
80
|
+
if (trimmed.startsWith("G")) return "group";
|
|
81
|
+
}
|
|
82
|
+
function normalizeSlackChannelType(channelType, channelId) {
|
|
83
|
+
const normalized = normalizeOptionalLowercaseString(channelType);
|
|
84
|
+
const inferred = inferSlackChannelType(channelId);
|
|
85
|
+
if (normalized === "im" || normalized === "mpim" || normalized === "channel" || normalized === "group") {
|
|
86
|
+
if (inferred === "im" && normalized !== "im") return "im";
|
|
87
|
+
return normalized;
|
|
88
|
+
}
|
|
89
|
+
return inferred ?? "channel";
|
|
90
|
+
}
|
|
91
|
+
function resolveSlackChatType(channelType) {
|
|
92
|
+
if (channelType === "im") return "direct";
|
|
93
|
+
if (channelType === "mpim") return "group";
|
|
94
|
+
return "channel";
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region extensions/slack/src/monitor/context.ts
|
|
98
|
+
const SLACK_ASSISTANT_THREAD_CONTEXT_METADATA_EVENT = "assistant_thread_context";
|
|
99
|
+
function buildSlackAssistantThreadMetadata(context) {
|
|
100
|
+
const eventPayload = {};
|
|
101
|
+
if (context.channelId) eventPayload.channel_id = context.channelId;
|
|
102
|
+
if (context.teamId) eventPayload.team_id = context.teamId;
|
|
103
|
+
if (context.enterpriseId) eventPayload.enterprise_id = context.enterpriseId;
|
|
104
|
+
return {
|
|
105
|
+
event_type: SLACK_ASSISTANT_THREAD_CONTEXT_METADATA_EVENT,
|
|
106
|
+
event_payload: eventPayload
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function parseSlackAssistantThreadMetadata(value) {
|
|
110
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
111
|
+
const metadata = value;
|
|
112
|
+
if (metadata.event_type !== SLACK_ASSISTANT_THREAD_CONTEXT_METADATA_EVENT) return;
|
|
113
|
+
const payload = metadata.event_payload;
|
|
114
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return;
|
|
115
|
+
const record = payload;
|
|
116
|
+
const stringField = (key) => {
|
|
117
|
+
const raw = record[key];
|
|
118
|
+
return typeof raw === "string" && raw.trim() ? raw.trim() : void 0;
|
|
119
|
+
};
|
|
120
|
+
return {
|
|
121
|
+
channelId: stringField("channel_id"),
|
|
122
|
+
teamId: stringField("team_id"),
|
|
123
|
+
enterpriseId: stringField("enterprise_id")
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
const SLACK_ASSISTANT_CONTEXT_TTL_MS = 864e5;
|
|
127
|
+
const SLACK_ASSISTANT_CONTEXT_CLEANUP_INTERVAL_MS = 6e5;
|
|
128
|
+
function createSlackMonitorContext(params) {
|
|
129
|
+
const channelHistories = /* @__PURE__ */ new Map();
|
|
130
|
+
const logger = getChildLogger({ module: "slack-auto-reply" });
|
|
131
|
+
const channelCache = /* @__PURE__ */ new Map();
|
|
132
|
+
const userCache = /* @__PURE__ */ new Map();
|
|
133
|
+
const seenMessages = createDedupeCache({
|
|
134
|
+
ttlMs: 6e4,
|
|
135
|
+
maxSize: 500
|
|
136
|
+
});
|
|
137
|
+
const assistantThreadContexts = /* @__PURE__ */ new Map();
|
|
138
|
+
let lastAssistantContextCleanupAt = Date.now();
|
|
139
|
+
const allowFrom = normalizeAllowList(params.allowFrom);
|
|
140
|
+
const groupDmChannels = normalizeAllowList(params.groupDmChannels);
|
|
141
|
+
const groupDmChannelsLower = normalizeAllowListLower(groupDmChannels);
|
|
142
|
+
const defaultRequireMention = params.defaultRequireMention ?? true;
|
|
143
|
+
const hasChannelAllowlistConfig = Object.keys(params.channelsConfig ?? {}).length > 0;
|
|
144
|
+
const channelsConfigKeys = Object.keys(params.channelsConfig ?? {});
|
|
145
|
+
const markMessageSeen = (channelId, ts) => {
|
|
146
|
+
if (!channelId || !ts) return false;
|
|
147
|
+
return seenMessages.check(`${channelId}:${ts}`);
|
|
148
|
+
};
|
|
149
|
+
const releaseSeenMessage = (channelId, ts) => {
|
|
150
|
+
if (!channelId || !ts) return;
|
|
151
|
+
seenMessages.delete(`${channelId}:${ts}`);
|
|
152
|
+
};
|
|
153
|
+
const assistantContextKey = (channelId, threadTs) => `${channelId}:${threadTs}`;
|
|
154
|
+
const cleanupAssistantThreadContexts = () => {
|
|
155
|
+
const now = Date.now();
|
|
156
|
+
if (now - lastAssistantContextCleanupAt < SLACK_ASSISTANT_CONTEXT_CLEANUP_INTERVAL_MS) return;
|
|
157
|
+
lastAssistantContextCleanupAt = now;
|
|
158
|
+
const cutoff = now - SLACK_ASSISTANT_CONTEXT_TTL_MS;
|
|
159
|
+
for (const [key, entry] of assistantThreadContexts) if (entry.updatedAt < cutoff) assistantThreadContexts.delete(key);
|
|
160
|
+
};
|
|
161
|
+
const getSlackAssistantThreadContext = (channelId, threadTs) => {
|
|
162
|
+
if (!channelId || !threadTs) return;
|
|
163
|
+
const key = assistantContextKey(channelId, threadTs);
|
|
164
|
+
const entry = assistantThreadContexts.get(key);
|
|
165
|
+
if (!entry) return;
|
|
166
|
+
if (Date.now() - entry.updatedAt > SLACK_ASSISTANT_CONTEXT_TTL_MS) {
|
|
167
|
+
assistantThreadContexts.delete(key);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
return entry;
|
|
171
|
+
};
|
|
172
|
+
const saveSlackAssistantThreadContext = (context) => {
|
|
173
|
+
cleanupAssistantThreadContexts();
|
|
174
|
+
assistantThreadContexts.set(assistantContextKey(context.assistantChannelId, context.threadTs), {
|
|
175
|
+
...context,
|
|
176
|
+
updatedAt: Date.now()
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
const resolveSlackSystemEventSessionKey = (p) => {
|
|
180
|
+
const channelId = normalizeOptionalString(p.channelId) ?? "";
|
|
181
|
+
const senderId = normalizeOptionalString(p.senderId) ?? "";
|
|
182
|
+
const channelType = normalizeSlackChannelType(p.channelType, channelId);
|
|
183
|
+
const isDirectMessage = channelType === "im";
|
|
184
|
+
if (!channelId && (!isDirectMessage || !senderId)) return params.mainKey;
|
|
185
|
+
const isGroup = channelType === "mpim";
|
|
186
|
+
const from = isDirectMessage ? `slack:${channelId || senderId}` : isGroup ? `slack:group:${channelId}` : `slack:channel:${channelId}`;
|
|
187
|
+
const chatType = isDirectMessage ? "direct" : isGroup ? "group" : "channel";
|
|
188
|
+
try {
|
|
189
|
+
const peerKind = isDirectMessage ? "direct" : isGroup ? "group" : "channel";
|
|
190
|
+
const peerId = isDirectMessage ? senderId : channelId;
|
|
191
|
+
if (peerId) {
|
|
192
|
+
const route = resolveAgentRoute({
|
|
193
|
+
cfg: params.cfg,
|
|
194
|
+
channel: "slack",
|
|
195
|
+
accountId: params.accountId,
|
|
196
|
+
teamId: params.teamId,
|
|
197
|
+
peer: {
|
|
198
|
+
kind: peerKind,
|
|
199
|
+
id: peerId
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
const threadTs = normalizeOptionalString(p.threadTs);
|
|
203
|
+
const baseConversationId = isDirectMessage ? `user:${senderId}` : channelId;
|
|
204
|
+
const threadBindingRoute = threadTs ? resolveRuntimeConversationBindingRoute({
|
|
205
|
+
route,
|
|
206
|
+
conversation: {
|
|
207
|
+
channel: "slack",
|
|
208
|
+
accountId: params.accountId,
|
|
209
|
+
conversationId: threadTs,
|
|
210
|
+
parentConversationId: baseConversationId
|
|
211
|
+
}
|
|
212
|
+
}) : null;
|
|
213
|
+
const runtimeRoute = threadBindingRoute?.boundSessionKey || threadBindingRoute?.bindingRecord ? threadBindingRoute : resolveRuntimeConversationBindingRoute({
|
|
214
|
+
route,
|
|
215
|
+
conversation: {
|
|
216
|
+
channel: "slack",
|
|
217
|
+
accountId: params.accountId,
|
|
218
|
+
conversationId: baseConversationId
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
if (runtimeRoute.boundSessionKey) return runtimeRoute.route.sessionKey;
|
|
222
|
+
return resolveThreadSessionKeys({
|
|
223
|
+
baseSessionKey: runtimeRoute.route.sessionKey,
|
|
224
|
+
threadId: threadTs,
|
|
225
|
+
parentSessionKey: threadTs && params.threadInheritParent ? runtimeRoute.route.sessionKey : void 0
|
|
226
|
+
}).sessionKey;
|
|
227
|
+
}
|
|
228
|
+
} catch {}
|
|
229
|
+
const legacySessionKey = resolveSessionKey(params.sessionScope, {
|
|
230
|
+
From: from,
|
|
231
|
+
ChatType: chatType,
|
|
232
|
+
Provider: "slack"
|
|
233
|
+
}, params.mainKey, resolveDefaultAgentId(params.cfg));
|
|
234
|
+
return resolveThreadSessionKeys({
|
|
235
|
+
baseSessionKey: legacySessionKey,
|
|
236
|
+
threadId: normalizeOptionalString(p.threadTs),
|
|
237
|
+
parentSessionKey: normalizeOptionalString(p.threadTs) && params.threadInheritParent ? legacySessionKey : void 0
|
|
238
|
+
}).sessionKey;
|
|
239
|
+
};
|
|
240
|
+
const resolveChannelName = async (channelId) => {
|
|
241
|
+
const cached = channelCache.get(channelId);
|
|
242
|
+
if (cached) return cached;
|
|
243
|
+
try {
|
|
244
|
+
const info = await params.app.client.conversations.info({
|
|
245
|
+
token: params.botToken,
|
|
246
|
+
channel: channelId
|
|
247
|
+
});
|
|
248
|
+
const name = info.channel && "name" in info.channel ? info.channel.name : void 0;
|
|
249
|
+
const channel = info.channel ?? void 0;
|
|
250
|
+
const entry = {
|
|
251
|
+
name,
|
|
252
|
+
type: channel?.is_im ? "im" : channel?.is_mpim ? "mpim" : channel?.is_channel ? "channel" : channel?.is_group ? "group" : void 0,
|
|
253
|
+
topic: channel && "topic" in channel ? channel.topic?.value ?? void 0 : void 0,
|
|
254
|
+
purpose: channel && "purpose" in channel ? channel.purpose?.value ?? void 0 : void 0
|
|
255
|
+
};
|
|
256
|
+
channelCache.set(channelId, entry);
|
|
257
|
+
return entry;
|
|
258
|
+
} catch {
|
|
259
|
+
return {};
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
const resolveUserName = async (userId) => {
|
|
263
|
+
const cached = userCache.get(userId);
|
|
264
|
+
if (cached) return cached;
|
|
265
|
+
try {
|
|
266
|
+
const info = await params.app.client.users.info({
|
|
267
|
+
token: params.botToken,
|
|
268
|
+
user: userId
|
|
269
|
+
});
|
|
270
|
+
const profile = info.user?.profile;
|
|
271
|
+
const entry = { name: profile?.display_name || profile?.real_name || info.user?.name || void 0 };
|
|
272
|
+
userCache.set(userId, entry);
|
|
273
|
+
return entry;
|
|
274
|
+
} catch {
|
|
275
|
+
return {};
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
const setSlackThreadStatus = async (p) => {
|
|
279
|
+
if (!p.threadTs) return;
|
|
280
|
+
try {
|
|
281
|
+
await params.app.client.assistant.threads.setStatus({
|
|
282
|
+
token: params.botToken,
|
|
283
|
+
channel_id: p.channelId,
|
|
284
|
+
thread_ts: p.threadTs,
|
|
285
|
+
status: p.status,
|
|
286
|
+
...p.loadingMessages?.length ? { loading_messages: p.loadingMessages.slice(0, 10) } : {}
|
|
287
|
+
});
|
|
288
|
+
} catch (err) {
|
|
289
|
+
logVerbose(`slack status update failed for channel ${p.channelId}: ${formatSlackError(err)}`);
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
const setSlackAssistantSuggestedPrompts = async (p) => {
|
|
293
|
+
const prompts = p.prompts.map((prompt) => ({
|
|
294
|
+
title: prompt.title.trim(),
|
|
295
|
+
message: prompt.message.trim()
|
|
296
|
+
})).filter((prompt) => prompt.title && prompt.message).slice(0, 4);
|
|
297
|
+
if (prompts.length === 0) return false;
|
|
298
|
+
try {
|
|
299
|
+
await params.app.client.assistant.threads.setSuggestedPrompts({
|
|
300
|
+
token: params.botToken,
|
|
301
|
+
channel_id: p.channelId,
|
|
302
|
+
thread_ts: p.threadTs,
|
|
303
|
+
...p.title?.trim() ? { title: p.title.trim() } : {},
|
|
304
|
+
prompts
|
|
305
|
+
});
|
|
306
|
+
return true;
|
|
307
|
+
} catch (err) {
|
|
308
|
+
logVerbose(`slack suggested prompts update failed for channel ${p.channelId}: ${formatSlackError(err)}`);
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
const isChannelAllowed = (p) => {
|
|
313
|
+
const channelType = normalizeSlackChannelType(p.channelType, p.channelId);
|
|
314
|
+
const isDirectMessage = channelType === "im";
|
|
315
|
+
const isGroupDm = channelType === "mpim";
|
|
316
|
+
const isRoom = channelType === "channel" || channelType === "group";
|
|
317
|
+
if (isDirectMessage && !params.dmEnabled) return false;
|
|
318
|
+
if (isGroupDm && !params.groupDmEnabled) return false;
|
|
319
|
+
if (isGroupDm && groupDmChannels.length > 0) {
|
|
320
|
+
const candidates = [
|
|
321
|
+
p.channelId,
|
|
322
|
+
p.channelName ? `#${p.channelName}` : void 0,
|
|
323
|
+
p.channelName,
|
|
324
|
+
p.channelName ? normalizeSlackSlug(p.channelName) : void 0
|
|
325
|
+
].filter((value) => Boolean(value)).map((value) => normalizeLowercaseStringOrEmpty(value));
|
|
326
|
+
if (!(groupDmChannelsLower.includes("*") || candidates.some((candidate) => groupDmChannelsLower.includes(candidate)))) return false;
|
|
327
|
+
}
|
|
328
|
+
if (isRoom && p.channelId) {
|
|
329
|
+
const channelConfig = resolveSlackChannelConfig({
|
|
330
|
+
channelId: p.channelId,
|
|
331
|
+
channelName: p.channelName,
|
|
332
|
+
channels: params.channelsConfig,
|
|
333
|
+
channelKeys: channelsConfigKeys,
|
|
334
|
+
defaultRequireMention,
|
|
335
|
+
allowNameMatching: params.allowNameMatching
|
|
336
|
+
});
|
|
337
|
+
const channelMatchMeta = formatAllowlistMatchMeta(channelConfig);
|
|
338
|
+
const channelAllowed = channelConfig?.allowed !== false;
|
|
339
|
+
const channelAllowlistConfigured = hasChannelAllowlistConfig;
|
|
340
|
+
if (!isSlackChannelAllowedByPolicy({
|
|
341
|
+
groupPolicy: params.groupPolicy,
|
|
342
|
+
channelAllowlistConfigured,
|
|
343
|
+
channelAllowed
|
|
344
|
+
})) {
|
|
345
|
+
logVerbose(`slack: drop channel ${p.channelId} (groupPolicy=${params.groupPolicy}, ${channelMatchMeta})`);
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
const hasExplicitConfig = Boolean(channelConfig?.matchSource);
|
|
349
|
+
if (!channelAllowed && (params.groupPolicy !== "open" || hasExplicitConfig)) {
|
|
350
|
+
logVerbose(`slack: drop channel ${p.channelId} (${channelMatchMeta})`);
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
logVerbose(`slack: allow channel ${p.channelId} (${channelMatchMeta})`);
|
|
354
|
+
}
|
|
355
|
+
return true;
|
|
356
|
+
};
|
|
357
|
+
const shouldDropMismatchedSlackEvent = (body) => {
|
|
358
|
+
if (!body || typeof body !== "object") return false;
|
|
359
|
+
const raw = body;
|
|
360
|
+
const incomingApiAppId = typeof raw.api_app_id === "string" ? raw.api_app_id : "";
|
|
361
|
+
const incomingTeamId = typeof raw.team_id === "string" ? raw.team_id : typeof raw.team?.id === "string" ? raw.team.id : "";
|
|
362
|
+
if (params.apiAppId && incomingApiAppId && incomingApiAppId !== params.apiAppId) {
|
|
363
|
+
logVerbose(`slack: drop event with api_app_id=${incomingApiAppId} (expected ${params.apiAppId})`);
|
|
364
|
+
return true;
|
|
365
|
+
}
|
|
366
|
+
if (params.teamId && incomingTeamId && incomingTeamId !== params.teamId) {
|
|
367
|
+
logVerbose(`slack: drop event with team_id=${incomingTeamId} (expected ${params.teamId})`);
|
|
368
|
+
return true;
|
|
369
|
+
}
|
|
370
|
+
return false;
|
|
371
|
+
};
|
|
372
|
+
return {
|
|
373
|
+
cfg: params.cfg,
|
|
374
|
+
accountId: params.accountId,
|
|
375
|
+
botToken: params.botToken,
|
|
376
|
+
app: params.app,
|
|
377
|
+
runtime: params.runtime,
|
|
378
|
+
channelRuntime: params.channelRuntime,
|
|
379
|
+
botUserId: params.botUserId,
|
|
380
|
+
botId: params.botId,
|
|
381
|
+
teamId: params.teamId,
|
|
382
|
+
apiAppId: params.apiAppId,
|
|
383
|
+
historyLimit: params.historyLimit,
|
|
384
|
+
dmHistoryLimit: Math.max(0, params.dmHistoryLimit ?? 0),
|
|
385
|
+
channelHistories,
|
|
386
|
+
sessionScope: params.sessionScope,
|
|
387
|
+
mainKey: params.mainKey,
|
|
388
|
+
dmEnabled: params.dmEnabled,
|
|
389
|
+
dmPolicy: params.dmPolicy,
|
|
390
|
+
allowFrom,
|
|
391
|
+
allowNameMatching: params.allowNameMatching,
|
|
392
|
+
groupDmEnabled: params.groupDmEnabled,
|
|
393
|
+
groupDmChannels,
|
|
394
|
+
defaultRequireMention,
|
|
395
|
+
channelsConfig: params.channelsConfig,
|
|
396
|
+
channelsConfigKeys,
|
|
397
|
+
groupPolicy: params.groupPolicy,
|
|
398
|
+
useAccessGroups: params.useAccessGroups,
|
|
399
|
+
reactionMode: params.reactionMode,
|
|
400
|
+
reactionAllowlist: params.reactionAllowlist,
|
|
401
|
+
replyToMode: params.replyToMode,
|
|
402
|
+
threadHistoryScope: params.threadHistoryScope,
|
|
403
|
+
threadInheritParent: params.threadInheritParent,
|
|
404
|
+
threadRequireExplicitMention: params.threadRequireExplicitMention,
|
|
405
|
+
slashCommand: params.slashCommand,
|
|
406
|
+
textLimit: params.textLimit,
|
|
407
|
+
ackReactionScope: params.ackReactionScope,
|
|
408
|
+
typingReaction: params.typingReaction,
|
|
409
|
+
mediaMaxBytes: params.mediaMaxBytes,
|
|
410
|
+
removeAckAfterReply: params.removeAckAfterReply,
|
|
411
|
+
logger,
|
|
412
|
+
markMessageSeen,
|
|
413
|
+
releaseSeenMessage,
|
|
414
|
+
shouldDropMismatchedSlackEvent,
|
|
415
|
+
resolveSlackSystemEventSessionKey,
|
|
416
|
+
isChannelAllowed,
|
|
417
|
+
resolveChannelName,
|
|
418
|
+
resolveUserName,
|
|
419
|
+
setSlackThreadStatus,
|
|
420
|
+
getSlackAssistantThreadContext,
|
|
421
|
+
saveSlackAssistantThreadContext,
|
|
422
|
+
setSlackAssistantSuggestedPrompts
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
//#endregion
|
|
426
|
+
//#region extensions/slack/src/monitor/events/assistant.ts
|
|
427
|
+
const DEFAULT_ASSISTANT_PROMPTS = [
|
|
428
|
+
{
|
|
429
|
+
title: "What can you do?",
|
|
430
|
+
message: "What can you help me with?"
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
title: "Summarize this channel",
|
|
434
|
+
message: "Summarize the recent activity in this channel."
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
title: "Draft a reply",
|
|
438
|
+
message: "Help me draft a reply."
|
|
439
|
+
}
|
|
440
|
+
];
|
|
441
|
+
function normalizeAssistantThread(event, getPrevious) {
|
|
442
|
+
const thread = event.assistant_thread;
|
|
443
|
+
if (!thread) return null;
|
|
444
|
+
const channelId = thread.channel_id?.trim();
|
|
445
|
+
const threadTs = thread.thread_ts?.trim();
|
|
446
|
+
if (!channelId || !threadTs) return null;
|
|
447
|
+
const previous = getPrevious?.(channelId, threadTs);
|
|
448
|
+
const threadContext = thread.context;
|
|
449
|
+
const eventContext = event.context;
|
|
450
|
+
const resolveContextString = (key, previousValue) => threadContext?.[key]?.trim() || eventContext?.[key]?.trim() || previousValue;
|
|
451
|
+
const enterpriseId = (() => {
|
|
452
|
+
if (threadContext && "enterprise_id" in threadContext) return threadContext.enterprise_id === null ? null : threadContext.enterprise_id?.trim() || previous?.enterpriseId;
|
|
453
|
+
if (eventContext && "enterprise_id" in eventContext) return eventContext.enterprise_id === null ? null : eventContext.enterprise_id?.trim() || previous?.enterpriseId;
|
|
454
|
+
return previous?.enterpriseId;
|
|
455
|
+
})();
|
|
456
|
+
return {
|
|
457
|
+
assistantChannelId: channelId,
|
|
458
|
+
threadTs,
|
|
459
|
+
userId: thread.user_id?.trim() || previous?.userId,
|
|
460
|
+
channelId: resolveContextString("channel_id", previous?.channelId),
|
|
461
|
+
teamId: resolveContextString("team_id", previous?.teamId),
|
|
462
|
+
enterpriseId
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
async function persistAssistantThreadMetadata(params) {
|
|
466
|
+
const { ctx, assistantThread } = params;
|
|
467
|
+
try {
|
|
468
|
+
const initialMessage = ((await ctx.app.client.conversations.replies({
|
|
469
|
+
token: ctx.botToken,
|
|
470
|
+
channel: assistantThread.assistantChannelId,
|
|
471
|
+
ts: assistantThread.threadTs,
|
|
472
|
+
oldest: assistantThread.threadTs,
|
|
473
|
+
include_all_metadata: true,
|
|
474
|
+
limit: 4
|
|
475
|
+
})).messages ?? []).find((message) => !message.subtype && message.user === ctx.botUserId && message.ts);
|
|
476
|
+
if (!initialMessage?.ts) return;
|
|
477
|
+
await ctx.app.client.chat.update({
|
|
478
|
+
token: ctx.botToken,
|
|
479
|
+
channel: assistantThread.assistantChannelId,
|
|
480
|
+
ts: initialMessage.ts,
|
|
481
|
+
text: initialMessage.text ?? "",
|
|
482
|
+
blocks: Array.isArray(initialMessage.blocks) ? initialMessage.blocks : [],
|
|
483
|
+
metadata: buildSlackAssistantThreadMetadata(assistantThread)
|
|
484
|
+
});
|
|
485
|
+
} catch (err) {
|
|
486
|
+
logVerbose(`slack assistant thread metadata persist failed for channel ${assistantThread.assistantChannelId}: ${formatErrorMessage(err)}`);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
function registerSlackAssistantEvents(params) {
|
|
490
|
+
const { ctx, trackEvent } = params;
|
|
491
|
+
const slackApp = ctx.app;
|
|
492
|
+
slackApp.event("assistant_thread_started", async ({ event, body }) => {
|
|
493
|
+
try {
|
|
494
|
+
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
|
|
495
|
+
trackEvent?.();
|
|
496
|
+
const assistantThread = normalizeAssistantThread(event, ctx.getSlackAssistantThreadContext);
|
|
497
|
+
if (!assistantThread) {
|
|
498
|
+
logVerbose("slack assistant_thread_started dropped: missing assistant thread channel/thread");
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
ctx.saveSlackAssistantThreadContext(assistantThread);
|
|
502
|
+
await ctx.setSlackAssistantSuggestedPrompts({
|
|
503
|
+
channelId: assistantThread.assistantChannelId,
|
|
504
|
+
threadTs: assistantThread.threadTs,
|
|
505
|
+
title: "Try asking",
|
|
506
|
+
prompts: DEFAULT_ASSISTANT_PROMPTS
|
|
507
|
+
});
|
|
508
|
+
} catch (err) {
|
|
509
|
+
ctx.runtime.error?.(danger(`slack assistant_thread_started handler failed: ${formatErrorMessage(err)}`));
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
slackApp.event("assistant_thread_context_changed", async ({ event, body }) => {
|
|
513
|
+
try {
|
|
514
|
+
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
|
|
515
|
+
trackEvent?.();
|
|
516
|
+
const assistantThread = normalizeAssistantThread(event, ctx.getSlackAssistantThreadContext);
|
|
517
|
+
if (!assistantThread) {
|
|
518
|
+
logVerbose("slack assistant_thread_context_changed dropped: missing assistant thread channel/thread");
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
ctx.saveSlackAssistantThreadContext(assistantThread);
|
|
522
|
+
await persistAssistantThreadMetadata({
|
|
523
|
+
ctx,
|
|
524
|
+
assistantThread
|
|
525
|
+
});
|
|
526
|
+
} catch (err) {
|
|
527
|
+
ctx.runtime.error?.(danger(`slack assistant_thread_context_changed handler failed: ${formatErrorMessage(err)}`));
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
//#endregion
|
|
532
|
+
//#region extensions/slack/src/channel-migration.ts
|
|
533
|
+
function resolveAccountChannels(cfg, accountId) {
|
|
534
|
+
if (!accountId) return {};
|
|
535
|
+
const normalized = normalizeAccountId(accountId);
|
|
536
|
+
const accounts = cfg.channels?.slack?.accounts;
|
|
537
|
+
if (!accounts || typeof accounts !== "object") return {};
|
|
538
|
+
const exact = accounts[normalized];
|
|
539
|
+
if (exact?.channels) return { channels: exact.channels };
|
|
540
|
+
const matchKey = Object.keys(accounts).find((key) => normalizeLowercaseStringOrEmpty(key) === normalizeLowercaseStringOrEmpty(normalized));
|
|
541
|
+
return { channels: matchKey ? accounts[matchKey]?.channels : void 0 };
|
|
542
|
+
}
|
|
543
|
+
function migrateSlackChannelsInPlace(channels, oldChannelId, newChannelId) {
|
|
544
|
+
if (!channels) return {
|
|
545
|
+
migrated: false,
|
|
546
|
+
skippedExisting: false
|
|
547
|
+
};
|
|
548
|
+
if (oldChannelId === newChannelId) return {
|
|
549
|
+
migrated: false,
|
|
550
|
+
skippedExisting: false
|
|
551
|
+
};
|
|
552
|
+
if (!Object.hasOwn(channels, oldChannelId)) return {
|
|
553
|
+
migrated: false,
|
|
554
|
+
skippedExisting: false
|
|
555
|
+
};
|
|
556
|
+
if (Object.hasOwn(channels, newChannelId)) return {
|
|
557
|
+
migrated: false,
|
|
558
|
+
skippedExisting: true
|
|
559
|
+
};
|
|
560
|
+
channels[newChannelId] = channels[oldChannelId];
|
|
561
|
+
delete channels[oldChannelId];
|
|
562
|
+
return {
|
|
563
|
+
migrated: true,
|
|
564
|
+
skippedExisting: false
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
function migrateSlackChannelConfig(params) {
|
|
568
|
+
const scopes = [];
|
|
569
|
+
let migrated = false;
|
|
570
|
+
let skippedExisting = false;
|
|
571
|
+
const accountChannels = resolveAccountChannels(params.cfg, params.accountId).channels;
|
|
572
|
+
if (accountChannels) {
|
|
573
|
+
const result = migrateSlackChannelsInPlace(accountChannels, params.oldChannelId, params.newChannelId);
|
|
574
|
+
if (result.migrated) {
|
|
575
|
+
migrated = true;
|
|
576
|
+
scopes.push("account");
|
|
577
|
+
}
|
|
578
|
+
if (result.skippedExisting) skippedExisting = true;
|
|
579
|
+
}
|
|
580
|
+
const globalChannels = params.cfg.channels?.slack?.channels;
|
|
581
|
+
if (globalChannels) {
|
|
582
|
+
const result = migrateSlackChannelsInPlace(globalChannels, params.oldChannelId, params.newChannelId);
|
|
583
|
+
if (result.migrated) {
|
|
584
|
+
migrated = true;
|
|
585
|
+
scopes.push("global");
|
|
586
|
+
}
|
|
587
|
+
if (result.skippedExisting) skippedExisting = true;
|
|
588
|
+
}
|
|
589
|
+
return {
|
|
590
|
+
migrated,
|
|
591
|
+
skippedExisting,
|
|
592
|
+
scopes
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
//#endregion
|
|
596
|
+
//#region extensions/slack/src/monitor/events/channels.ts
|
|
597
|
+
function registerSlackChannelEvents(params) {
|
|
598
|
+
const { ctx, trackEvent } = params;
|
|
599
|
+
const enqueueChannelSystemEvent = (paramsLocal) => {
|
|
600
|
+
if (!ctx.isChannelAllowed({
|
|
601
|
+
channelId: paramsLocal.channelId,
|
|
602
|
+
channelName: paramsLocal.channelName,
|
|
603
|
+
channelType: "channel"
|
|
604
|
+
})) return;
|
|
605
|
+
const label = resolveSlackChannelLabel({
|
|
606
|
+
channelId: paramsLocal.channelId,
|
|
607
|
+
channelName: paramsLocal.channelName
|
|
608
|
+
});
|
|
609
|
+
const sessionKey = ctx.resolveSlackSystemEventSessionKey({
|
|
610
|
+
channelId: paramsLocal.channelId,
|
|
611
|
+
channelType: "channel"
|
|
612
|
+
});
|
|
613
|
+
enqueueSystemEvent(`Slack channel ${paramsLocal.kind}: ${label}.`, {
|
|
614
|
+
sessionKey,
|
|
615
|
+
contextKey: `slack:channel:${paramsLocal.kind}:${paramsLocal.channelId ?? paramsLocal.channelName ?? "unknown"}`
|
|
616
|
+
});
|
|
617
|
+
};
|
|
618
|
+
ctx.app.event("channel_created", async ({ event, body }) => {
|
|
619
|
+
try {
|
|
620
|
+
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
|
|
621
|
+
trackEvent?.();
|
|
622
|
+
const payload = event;
|
|
623
|
+
const channelId = payload.channel?.id;
|
|
624
|
+
const channelName = payload.channel?.name;
|
|
625
|
+
enqueueChannelSystemEvent({
|
|
626
|
+
kind: "created",
|
|
627
|
+
channelId,
|
|
628
|
+
channelName
|
|
629
|
+
});
|
|
630
|
+
} catch (err) {
|
|
631
|
+
ctx.runtime.error?.(danger(`slack channel created handler failed: ${formatErrorMessage(err)}`));
|
|
632
|
+
}
|
|
633
|
+
});
|
|
634
|
+
ctx.app.event("channel_rename", async ({ event, body }) => {
|
|
635
|
+
try {
|
|
636
|
+
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
|
|
637
|
+
trackEvent?.();
|
|
638
|
+
const payload = event;
|
|
639
|
+
const channelId = payload.channel?.id;
|
|
640
|
+
const channelName = payload.channel?.name_normalized ?? payload.channel?.name;
|
|
641
|
+
enqueueChannelSystemEvent({
|
|
642
|
+
kind: "renamed",
|
|
643
|
+
channelId,
|
|
644
|
+
channelName
|
|
645
|
+
});
|
|
646
|
+
} catch (err) {
|
|
647
|
+
ctx.runtime.error?.(danger(`slack channel rename handler failed: ${formatErrorMessage(err)}`));
|
|
648
|
+
}
|
|
649
|
+
});
|
|
650
|
+
ctx.app.event("channel_id_changed", async ({ event, body }) => {
|
|
651
|
+
try {
|
|
652
|
+
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
|
|
653
|
+
trackEvent?.();
|
|
654
|
+
const payload = event;
|
|
655
|
+
const oldChannelId = payload.old_channel_id;
|
|
656
|
+
const newChannelId = payload.new_channel_id;
|
|
657
|
+
if (!oldChannelId || !newChannelId) return;
|
|
658
|
+
const channelInfo = await ctx.resolveChannelName(newChannelId);
|
|
659
|
+
const label = resolveSlackChannelLabel({
|
|
660
|
+
channelId: newChannelId,
|
|
661
|
+
channelName: channelInfo?.name
|
|
662
|
+
});
|
|
663
|
+
ctx.runtime.log?.(warn(`[slack] Channel ID changed: ${oldChannelId} → ${newChannelId} (${label})`));
|
|
664
|
+
if (!resolveChannelConfigWrites({
|
|
665
|
+
cfg: ctx.cfg,
|
|
666
|
+
channelId: "slack",
|
|
667
|
+
accountId: ctx.accountId
|
|
668
|
+
})) {
|
|
669
|
+
ctx.runtime.log?.(warn("[slack] Config writes disabled; skipping channel config migration."));
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
const migration = migrateSlackChannelConfig({
|
|
673
|
+
cfg: getRuntimeConfig(),
|
|
674
|
+
accountId: ctx.accountId,
|
|
675
|
+
oldChannelId,
|
|
676
|
+
newChannelId
|
|
677
|
+
});
|
|
678
|
+
if (migration.migrated) {
|
|
679
|
+
migrateSlackChannelConfig({
|
|
680
|
+
cfg: ctx.cfg,
|
|
681
|
+
accountId: ctx.accountId,
|
|
682
|
+
oldChannelId,
|
|
683
|
+
newChannelId
|
|
684
|
+
});
|
|
685
|
+
await mutateConfigFile({
|
|
686
|
+
afterWrite: { mode: "auto" },
|
|
687
|
+
mutate: (draft) => {
|
|
688
|
+
migrateSlackChannelConfig({
|
|
689
|
+
cfg: draft,
|
|
690
|
+
accountId: ctx.accountId,
|
|
691
|
+
oldChannelId,
|
|
692
|
+
newChannelId
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
});
|
|
696
|
+
ctx.runtime.log?.(warn("[slack] Channel config migrated and saved successfully."));
|
|
697
|
+
} else if (migration.skippedExisting) ctx.runtime.log?.(warn(`[slack] Channel config already exists for ${newChannelId}; leaving ${oldChannelId} unchanged`));
|
|
698
|
+
else ctx.runtime.log?.(warn(`[slack] No config found for old channel ID ${oldChannelId}; migration logged only`));
|
|
699
|
+
} catch (err) {
|
|
700
|
+
ctx.runtime.error?.(danger(`slack channel_id_changed handler failed: ${formatErrorMessage(err)}`));
|
|
701
|
+
}
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
//#endregion
|
|
705
|
+
//#region extensions/slack/src/monitor/events/home.ts
|
|
706
|
+
function buildSlackHomeView() {
|
|
707
|
+
return {
|
|
708
|
+
type: "home",
|
|
709
|
+
callback_id: "openclaw:home",
|
|
710
|
+
blocks: [
|
|
711
|
+
{
|
|
712
|
+
type: "header",
|
|
713
|
+
text: {
|
|
714
|
+
type: "plain_text",
|
|
715
|
+
text: "OpenClaw"
|
|
716
|
+
}
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
type: "section",
|
|
720
|
+
text: {
|
|
721
|
+
type: "mrkdwn",
|
|
722
|
+
text: "Send a DM, mention OpenClaw in a channel, or use `/openclaw` to start a session."
|
|
723
|
+
}
|
|
724
|
+
},
|
|
725
|
+
{
|
|
726
|
+
type: "context",
|
|
727
|
+
elements: [{
|
|
728
|
+
type: "mrkdwn",
|
|
729
|
+
text: "This Home tab is safe to show to any workspace member who opens the app."
|
|
730
|
+
}]
|
|
731
|
+
}
|
|
732
|
+
]
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
function registerSlackHomeEvents(params) {
|
|
736
|
+
const { ctx, trackEvent } = params;
|
|
737
|
+
ctx.app.event("app_home_opened", async ({ event, body }) => {
|
|
738
|
+
try {
|
|
739
|
+
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
|
|
740
|
+
trackEvent?.();
|
|
741
|
+
const payload = event;
|
|
742
|
+
if (!payload.user || payload.tab === "messages") return;
|
|
743
|
+
await ctx.app.client.views.publish({
|
|
744
|
+
token: ctx.botToken,
|
|
745
|
+
user_id: payload.user,
|
|
746
|
+
view: buildSlackHomeView()
|
|
747
|
+
});
|
|
748
|
+
} catch (err) {
|
|
749
|
+
ctx.runtime.error?.(danger(`slack app home handler failed: ${formatErrorMessage(err)}`));
|
|
750
|
+
}
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
//#endregion
|
|
754
|
+
//#region extensions/slack/src/interactive-dispatch.ts
|
|
755
|
+
async function dispatchSlackPluginInteractiveHandler(params) {
|
|
756
|
+
return await dispatchPluginInteractiveHandler({
|
|
757
|
+
channel: "slack",
|
|
758
|
+
data: params.data,
|
|
759
|
+
dedupeId: params.interactionId,
|
|
760
|
+
onMatched: params.onMatched,
|
|
761
|
+
invoke: ({ registration, namespace, payload }) => registration.handler({
|
|
762
|
+
...params.ctx,
|
|
763
|
+
channel: "slack",
|
|
764
|
+
interaction: {
|
|
765
|
+
...params.ctx.interaction,
|
|
766
|
+
data: params.data,
|
|
767
|
+
namespace,
|
|
768
|
+
payload
|
|
769
|
+
},
|
|
770
|
+
respond: params.respond,
|
|
771
|
+
...createInteractiveConversationBindingHelpers({
|
|
772
|
+
registration,
|
|
773
|
+
senderId: params.ctx.senderId,
|
|
774
|
+
conversation: {
|
|
775
|
+
channel: "slack",
|
|
776
|
+
accountId: params.ctx.accountId,
|
|
777
|
+
conversationId: params.ctx.conversationId,
|
|
778
|
+
parentConversationId: params.ctx.parentConversationId,
|
|
779
|
+
threadId: params.ctx.threadId
|
|
780
|
+
}
|
|
781
|
+
})
|
|
782
|
+
})
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
//#endregion
|
|
786
|
+
//#region extensions/slack/src/monitor/auth.ts
|
|
787
|
+
let slackChannelMembersCache = /* @__PURE__ */ new WeakMap();
|
|
788
|
+
const DEFAULT_CHANNEL_MEMBERS_CACHE_TTL_MS = 6e4;
|
|
789
|
+
const CHANNEL_MEMBERS_CACHE_MAX = 512;
|
|
790
|
+
const SLACK_CHANNEL_ID = "slack";
|
|
791
|
+
const SLACK_USER_NAME_KIND = "plugin:slack-user-name";
|
|
792
|
+
function normalizeSlackUserId(raw) {
|
|
793
|
+
const value = (raw ?? "").trim().toLowerCase();
|
|
794
|
+
if (!value) return "";
|
|
795
|
+
const mention = value.match(/^<@([a-z0-9_]+)>$/i);
|
|
796
|
+
if (mention?.[1]) return mention[1];
|
|
797
|
+
return value.replace(/^(slack:|user:)/, "");
|
|
798
|
+
}
|
|
799
|
+
function isSlackStableUserId(value) {
|
|
800
|
+
return /^[ubw][a-z0-9_]+$/i.test(value);
|
|
801
|
+
}
|
|
802
|
+
function normalizeSlackStableEntry(entry) {
|
|
803
|
+
const normalized = entry.trim().toLowerCase();
|
|
804
|
+
if (!normalized) return null;
|
|
805
|
+
const userId = normalizeSlackUserId(normalized);
|
|
806
|
+
return isSlackStableUserId(userId) ? userId : null;
|
|
807
|
+
}
|
|
808
|
+
function normalizeSlackNameEntry(entry) {
|
|
809
|
+
const normalized = entry.trim().toLowerCase();
|
|
810
|
+
if (!normalized || normalizeSlackStableEntry(normalized)) return null;
|
|
811
|
+
return normalized.replace(/^slack:/, "") || null;
|
|
812
|
+
}
|
|
813
|
+
function normalizeSlackNameSubject(value) {
|
|
814
|
+
return value.trim().toLowerCase() || null;
|
|
815
|
+
}
|
|
816
|
+
function normalizeSlackNameSlugEntry(entry) {
|
|
817
|
+
const name = normalizeSlackNameEntry(entry);
|
|
818
|
+
if (!name) return null;
|
|
819
|
+
const slug = normalizeSlackSlug(name);
|
|
820
|
+
return slug && slug !== name ? slug : null;
|
|
821
|
+
}
|
|
822
|
+
const slackIngressIdentity = defineStableChannelIngressIdentity({
|
|
823
|
+
key: "senderId",
|
|
824
|
+
kind: "stable-id",
|
|
825
|
+
normalizeEntry: normalizeSlackStableEntry,
|
|
826
|
+
normalizeSubject: normalizeSlackUserId,
|
|
827
|
+
sensitivity: "pii",
|
|
828
|
+
aliases: [["senderName", normalizeSlackNameEntry], ["senderNameSlug", normalizeSlackNameSlugEntry]].map(([key, normalizeEntry]) => ({
|
|
829
|
+
key,
|
|
830
|
+
kind: SLACK_USER_NAME_KIND,
|
|
831
|
+
normalizeEntry,
|
|
832
|
+
normalizeSubject: normalizeSlackNameSubject,
|
|
833
|
+
dangerous: true,
|
|
834
|
+
sensitivity: "pii"
|
|
835
|
+
}))
|
|
836
|
+
});
|
|
837
|
+
function createSlackIngressSubject(params) {
|
|
838
|
+
const senderId = normalizeSlackUserId(params.senderId);
|
|
839
|
+
const senderName = params.senderName?.trim().toLowerCase();
|
|
840
|
+
return {
|
|
841
|
+
stableId: senderId,
|
|
842
|
+
aliases: {
|
|
843
|
+
senderName,
|
|
844
|
+
senderNameSlug: senderName ? normalizeSlackSlug(senderName) : void 0
|
|
845
|
+
}
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
function createSlackIngressResolver(ctx) {
|
|
849
|
+
return createChannelIngressResolver({
|
|
850
|
+
channelId: SLACK_CHANNEL_ID,
|
|
851
|
+
accountId: ctx.accountId,
|
|
852
|
+
identity: slackIngressIdentity,
|
|
853
|
+
cfg: ctx.cfg
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
function readSlackCacheTtlMs(envName, fallback) {
|
|
857
|
+
const raw = process.env[envName]?.trim();
|
|
858
|
+
if (!raw) return fallback;
|
|
859
|
+
const parsed = /^\d+$/.test(raw) ? Number(raw) : NaN;
|
|
860
|
+
return Number.isSafeInteger(parsed) ? parsed : fallback;
|
|
861
|
+
}
|
|
862
|
+
function getChannelMembersCache(ctx) {
|
|
863
|
+
const existing = slackChannelMembersCache.get(ctx);
|
|
864
|
+
if (existing) return existing;
|
|
865
|
+
const next = /* @__PURE__ */ new Map();
|
|
866
|
+
slackChannelMembersCache.set(ctx, next);
|
|
867
|
+
return next;
|
|
868
|
+
}
|
|
869
|
+
function pruneChannelMembersCache(cache) {
|
|
870
|
+
while (cache.size > CHANNEL_MEMBERS_CACHE_MAX) {
|
|
871
|
+
const oldest = cache.keys().next();
|
|
872
|
+
if (oldest.done) return;
|
|
873
|
+
cache.delete(oldest.value);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
function buildBaseAllowFrom(ctx) {
|
|
877
|
+
return normalizeAllowListLower(normalizeAllowList(ctx.allowFrom));
|
|
878
|
+
}
|
|
879
|
+
async function resolveSlackEffectiveAllowFrom(ctx, options) {
|
|
880
|
+
const base = buildBaseAllowFrom(ctx);
|
|
881
|
+
if (options?.includePairingStore !== true) return base;
|
|
882
|
+
let storeAllowFrom;
|
|
883
|
+
try {
|
|
884
|
+
const resolved = await readChannelIngressStoreAllowFromForDmPolicy({
|
|
885
|
+
provider: "slack",
|
|
886
|
+
accountId: ctx.accountId,
|
|
887
|
+
dmPolicy: ctx.dmPolicy
|
|
888
|
+
});
|
|
889
|
+
storeAllowFrom = Array.isArray(resolved) ? resolved : [];
|
|
890
|
+
} catch {
|
|
891
|
+
storeAllowFrom = [];
|
|
892
|
+
}
|
|
893
|
+
return normalizeAllowListLower([...base, ...storeAllowFrom]);
|
|
894
|
+
}
|
|
895
|
+
async function fetchSlackChannelMemberIds(ctx, channelId) {
|
|
896
|
+
const members = /* @__PURE__ */ new Set();
|
|
897
|
+
let cursor;
|
|
898
|
+
do {
|
|
899
|
+
const response = await ctx.app.client.conversations.members({
|
|
900
|
+
token: ctx.botToken,
|
|
901
|
+
channel: channelId,
|
|
902
|
+
limit: 999,
|
|
903
|
+
...cursor ? { cursor } : {}
|
|
904
|
+
});
|
|
905
|
+
for (const member of normalizeAllowListLower(response.members)) members.add(member);
|
|
906
|
+
const nextCursor = response.response_metadata?.next_cursor?.trim();
|
|
907
|
+
cursor = nextCursor ? nextCursor : void 0;
|
|
908
|
+
} while (cursor);
|
|
909
|
+
return members;
|
|
910
|
+
}
|
|
911
|
+
async function resolveSlackChannelMemberIds(ctx, channelId) {
|
|
912
|
+
const cache = getChannelMembersCache(ctx);
|
|
913
|
+
const key = `${ctx.accountId}:${channelId}`;
|
|
914
|
+
const ttlMs = readSlackCacheTtlMs("OPENCLAW_SLACK_CHANNEL_MEMBERS_CACHE_TTL_MS", DEFAULT_CHANNEL_MEMBERS_CACHE_TTL_MS);
|
|
915
|
+
const rawNowMs = Date.now();
|
|
916
|
+
const nowMs = asDateTimestampMs(rawNowMs);
|
|
917
|
+
const cached = cache.get(key);
|
|
918
|
+
if (cached?.members) {
|
|
919
|
+
if (ttlMs > 0 && nowMs !== void 0 && cached.expiresAtMs >= nowMs) return cached.members;
|
|
920
|
+
cache.delete(key);
|
|
921
|
+
}
|
|
922
|
+
if (cached?.pending) return await cached.pending;
|
|
923
|
+
const pending = fetchSlackChannelMemberIds(ctx, channelId);
|
|
924
|
+
const pendingExpiresAtMs = ttlMs > 0 ? resolveExpiresAtMsFromDurationMs(ttlMs, { nowMs: rawNowMs }) : void 0;
|
|
925
|
+
cache.set(key, {
|
|
926
|
+
expiresAtMs: pendingExpiresAtMs ?? 0,
|
|
927
|
+
pending
|
|
928
|
+
});
|
|
929
|
+
pruneChannelMembersCache(cache);
|
|
930
|
+
try {
|
|
931
|
+
const members = await pending;
|
|
932
|
+
const membersExpiresAtMs = ttlMs > 0 ? resolveExpiresAtMsFromDurationMs(ttlMs) : void 0;
|
|
933
|
+
if (membersExpiresAtMs !== void 0) {
|
|
934
|
+
cache.set(key, {
|
|
935
|
+
expiresAtMs: membersExpiresAtMs,
|
|
936
|
+
members
|
|
937
|
+
});
|
|
938
|
+
pruneChannelMembersCache(cache);
|
|
939
|
+
} else cache.delete(key);
|
|
940
|
+
return members;
|
|
941
|
+
} finally {
|
|
942
|
+
if (cache.get(key)?.pending === pending) cache.delete(key);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
function resolveExplicitSlackOwnerIds(allowFromLower) {
|
|
946
|
+
const ownerIds = /* @__PURE__ */ new Set();
|
|
947
|
+
for (const entry of allowFromLower) {
|
|
948
|
+
const ownerId = normalizeSlackAllowOwnerEntry(entry);
|
|
949
|
+
if (ownerId) ownerIds.add(ownerId);
|
|
950
|
+
}
|
|
951
|
+
return [...ownerIds];
|
|
952
|
+
}
|
|
953
|
+
async function authorizeSlackBotRoomMessage(params) {
|
|
954
|
+
const channelUserAllowList = normalizeAllowListLower(params.channelUsers).filter((entry) => entry !== "*");
|
|
955
|
+
if (channelUserAllowList.length > 0 && allowListMatches({
|
|
956
|
+
allowList: channelUserAllowList,
|
|
957
|
+
id: params.senderId,
|
|
958
|
+
name: params.senderName,
|
|
959
|
+
allowNameMatching: params.ctx.allowNameMatching
|
|
960
|
+
})) return true;
|
|
961
|
+
const explicitOwnerIds = resolveExplicitSlackOwnerIds(params.allowFromLower);
|
|
962
|
+
if (explicitOwnerIds.length === 0) {
|
|
963
|
+
logVerbose(`slack: drop bot message ${params.senderId} in ${params.channelId} (no explicit owner id for presence check)`);
|
|
964
|
+
return false;
|
|
965
|
+
}
|
|
966
|
+
try {
|
|
967
|
+
const channelMemberIds = await resolveSlackChannelMemberIds(params.ctx, params.channelId);
|
|
968
|
+
if (explicitOwnerIds.some((ownerId) => channelMemberIds.has(ownerId))) return true;
|
|
969
|
+
logVerbose(`slack: drop bot message ${params.senderId} in ${params.channelId} (no owner present)`);
|
|
970
|
+
} catch (error) {
|
|
971
|
+
logVerbose(`slack: drop bot message ${params.senderId} in ${params.channelId} (owner presence lookup failed: ${formatErrorMessage(error)})`);
|
|
972
|
+
}
|
|
973
|
+
return false;
|
|
974
|
+
}
|
|
975
|
+
function wildcardWhenOpen(entries) {
|
|
976
|
+
return entries.length > 0 ? [...entries] : ["*"];
|
|
977
|
+
}
|
|
978
|
+
function slackIngressConversationKind(channelType) {
|
|
979
|
+
return channelType === "im" ? "direct" : channelType === "mpim" ? "group" : "channel";
|
|
980
|
+
}
|
|
981
|
+
async function resolveSlackCommandIngress(params) {
|
|
982
|
+
const isDirectMessage = params.channelType === "im";
|
|
983
|
+
const channelUsers = normalizeAllowListLower(params.channelUsers);
|
|
984
|
+
const channelUsersConfigured = !isDirectMessage && channelUsers.length > 0;
|
|
985
|
+
return await createSlackIngressResolver(params.ctx).message({
|
|
986
|
+
subject: createSlackIngressSubject({
|
|
987
|
+
senderId: params.senderId,
|
|
988
|
+
senderName: params.senderName
|
|
989
|
+
}),
|
|
990
|
+
conversation: {
|
|
991
|
+
kind: slackIngressConversationKind(params.channelType),
|
|
992
|
+
id: params.channelId
|
|
993
|
+
},
|
|
994
|
+
event: {
|
|
995
|
+
kind: params.eventKind ?? "message",
|
|
996
|
+
authMode: "inbound",
|
|
997
|
+
mayPair: false
|
|
998
|
+
},
|
|
999
|
+
dmPolicy: isDirectMessage ? "open" : "disabled",
|
|
1000
|
+
groupPolicy: channelUsersConfigured ? "allowlist" : "open",
|
|
1001
|
+
policy: {
|
|
1002
|
+
groupAllowFromFallbackToAllowFrom: false,
|
|
1003
|
+
mutableIdentifierMatching: params.ctx.allowNameMatching ? "enabled" : "disabled",
|
|
1004
|
+
...params.activation ? { activation: params.activation } : {}
|
|
1005
|
+
},
|
|
1006
|
+
mentionFacts: params.mentionFacts,
|
|
1007
|
+
allowFrom: isDirectMessage ? ["*"] : params.ownerAllowFromLower,
|
|
1008
|
+
groupAllowFrom: channelUsersConfigured ? channelUsers : [],
|
|
1009
|
+
command: {
|
|
1010
|
+
allowTextCommands: params.allowTextCommands,
|
|
1011
|
+
hasControlCommand: params.hasControlCommand,
|
|
1012
|
+
modeWhenAccessGroupsOff: params.modeWhenAccessGroupsOff,
|
|
1013
|
+
...isDirectMessage ? { commandOwnerAllowFrom: params.ownerAllowFromLower } : {}
|
|
1014
|
+
}
|
|
1015
|
+
});
|
|
1016
|
+
}
|
|
1017
|
+
async function decideSlackSystemIngress(params) {
|
|
1018
|
+
const isDirectMessage = params.channelType === "im";
|
|
1019
|
+
const channelUsers = normalizeAllowListLower(params.channelUsers);
|
|
1020
|
+
const channelUsersConfigured = !isDirectMessage && channelUsers.length > 0;
|
|
1021
|
+
const ownerAllowFrom = params.interactiveEvent && channelUsersConfigured ? params.ownerAllowFromLower.filter((entry) => entry !== "*") : params.ownerAllowFromLower;
|
|
1022
|
+
const hasAnyCommandAllowlist = ownerAllowFrom.length > 0 || channelUsersConfigured;
|
|
1023
|
+
const groupAllowFrom = (() => {
|
|
1024
|
+
if (isDirectMessage) return [];
|
|
1025
|
+
if (params.interactiveEvent && hasAnyCommandAllowlist) return channelUsersConfigured ? channelUsers : [];
|
|
1026
|
+
if (channelUsersConfigured) return channelUsers;
|
|
1027
|
+
return params.channelId ? ["*"] : wildcardWhenOpen(params.ownerAllowFromLower);
|
|
1028
|
+
})();
|
|
1029
|
+
return (await createSlackIngressResolver(params.ctx).message({
|
|
1030
|
+
subject: createSlackIngressSubject({
|
|
1031
|
+
senderId: params.senderId,
|
|
1032
|
+
senderName: params.senderName
|
|
1033
|
+
}),
|
|
1034
|
+
conversation: {
|
|
1035
|
+
kind: slackIngressConversationKind(params.channelType),
|
|
1036
|
+
id: params.channelId ?? "slack-system"
|
|
1037
|
+
},
|
|
1038
|
+
event: {
|
|
1039
|
+
kind: params.interactiveEvent ? "button" : "system",
|
|
1040
|
+
authMode: params.interactiveEvent && hasAnyCommandAllowlist ? "command" : "inbound",
|
|
1041
|
+
mayPair: false
|
|
1042
|
+
},
|
|
1043
|
+
dmPolicy: isDirectMessage ? "open" : "disabled",
|
|
1044
|
+
groupPolicy: params.interactiveEvent && hasAnyCommandAllowlist ? "open" : channelUsersConfigured || !params.channelId && params.ownerAllowFromLower.length > 0 ? "allowlist" : "open",
|
|
1045
|
+
policy: {
|
|
1046
|
+
groupAllowFromFallbackToAllowFrom: false,
|
|
1047
|
+
mutableIdentifierMatching: params.ctx.allowNameMatching ? "enabled" : "disabled"
|
|
1048
|
+
},
|
|
1049
|
+
allowFrom: isDirectMessage ? wildcardWhenOpen(params.ownerAllowFromLower) : ownerAllowFrom,
|
|
1050
|
+
groupAllowFrom,
|
|
1051
|
+
command: params.interactiveEvent && hasAnyCommandAllowlist ? {
|
|
1052
|
+
useAccessGroups: true,
|
|
1053
|
+
allowTextCommands: true,
|
|
1054
|
+
modeWhenAccessGroupsOff: "configured",
|
|
1055
|
+
commandOwnerAllowFrom: ownerAllowFrom
|
|
1056
|
+
} : void 0
|
|
1057
|
+
})).ingress;
|
|
1058
|
+
}
|
|
1059
|
+
async function authorizeSlackSystemEventSender(params) {
|
|
1060
|
+
const senderId = params.senderId?.trim();
|
|
1061
|
+
if (!senderId) return {
|
|
1062
|
+
allowed: false,
|
|
1063
|
+
reason: "missing-sender"
|
|
1064
|
+
};
|
|
1065
|
+
const expectedSenderId = params.expectedSenderId?.trim();
|
|
1066
|
+
if (expectedSenderId && expectedSenderId !== senderId) return {
|
|
1067
|
+
allowed: false,
|
|
1068
|
+
reason: "sender-mismatch"
|
|
1069
|
+
};
|
|
1070
|
+
if (params.interactiveEvent && !expectedSenderId) return {
|
|
1071
|
+
allowed: false,
|
|
1072
|
+
reason: "missing-expected-sender"
|
|
1073
|
+
};
|
|
1074
|
+
const channelId = params.channelId?.trim();
|
|
1075
|
+
let channelType = normalizeSlackChannelType(params.channelType, channelId);
|
|
1076
|
+
let channelName;
|
|
1077
|
+
if (channelId) {
|
|
1078
|
+
const info = await params.ctx.resolveChannelName(channelId).catch(() => ({}));
|
|
1079
|
+
channelName = info.name;
|
|
1080
|
+
const resolvedTypeSource = params.channelType ?? info.type;
|
|
1081
|
+
channelType = normalizeSlackChannelType(resolvedTypeSource, channelId);
|
|
1082
|
+
if (!params.ctx.isChannelAllowed({
|
|
1083
|
+
channelId,
|
|
1084
|
+
channelName,
|
|
1085
|
+
channelType
|
|
1086
|
+
})) return {
|
|
1087
|
+
allowed: false,
|
|
1088
|
+
reason: "channel-not-allowed",
|
|
1089
|
+
channelType,
|
|
1090
|
+
channelName
|
|
1091
|
+
};
|
|
1092
|
+
if (params.interactiveEvent) {
|
|
1093
|
+
const inferredFromId = inferSlackChannelType(channelId);
|
|
1094
|
+
const sourceNormalized = typeof resolvedTypeSource === "string" ? resolvedTypeSource.toLowerCase().trim() : void 0;
|
|
1095
|
+
if (inferredFromId === void 0 && !(sourceNormalized === "im" || sourceNormalized === "mpim" || sourceNormalized === "channel" || sourceNormalized === "group")) return {
|
|
1096
|
+
allowed: false,
|
|
1097
|
+
reason: "ambiguous-channel-type",
|
|
1098
|
+
channelType,
|
|
1099
|
+
channelName
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
const senderName = (await params.ctx.resolveUserName(senderId).catch(() => ({}))).name;
|
|
1104
|
+
const ingressChannelType = channelType ?? "channel";
|
|
1105
|
+
if (ingressChannelType === "im") {
|
|
1106
|
+
if (!params.ctx.dmEnabled || params.ctx.dmPolicy === "disabled") return {
|
|
1107
|
+
allowed: false,
|
|
1108
|
+
reason: "dm-disabled",
|
|
1109
|
+
channelType,
|
|
1110
|
+
channelName
|
|
1111
|
+
};
|
|
1112
|
+
}
|
|
1113
|
+
const allowFromLower = await resolveSlackEffectiveAllowFrom(params.ctx, { includePairingStore: ingressChannelType === "im" });
|
|
1114
|
+
const channelConfig = channelId ? resolveSlackChannelConfig({
|
|
1115
|
+
channelId,
|
|
1116
|
+
channelName,
|
|
1117
|
+
channels: params.ctx.channelsConfig,
|
|
1118
|
+
channelKeys: params.ctx.channelsConfigKeys,
|
|
1119
|
+
defaultRequireMention: params.ctx.defaultRequireMention,
|
|
1120
|
+
allowNameMatching: params.ctx.allowNameMatching
|
|
1121
|
+
}) : null;
|
|
1122
|
+
const channelUsersAllowlistConfigured = Array.isArray(channelConfig?.users) && channelConfig.users.length > 0;
|
|
1123
|
+
if ((await decideSlackSystemIngress({
|
|
1124
|
+
ctx: params.ctx,
|
|
1125
|
+
senderId,
|
|
1126
|
+
senderName,
|
|
1127
|
+
channelType: ingressChannelType,
|
|
1128
|
+
channelId,
|
|
1129
|
+
ownerAllowFromLower: allowFromLower,
|
|
1130
|
+
channelUsers: channelConfig?.users,
|
|
1131
|
+
interactiveEvent: params.interactiveEvent === true
|
|
1132
|
+
})).decision === "allow") return {
|
|
1133
|
+
allowed: true,
|
|
1134
|
+
channelType,
|
|
1135
|
+
channelName
|
|
1136
|
+
};
|
|
1137
|
+
if (channelType === "im" || !channelId) return {
|
|
1138
|
+
allowed: false,
|
|
1139
|
+
reason: "sender-not-allowlisted",
|
|
1140
|
+
...channelId ? {
|
|
1141
|
+
channelType,
|
|
1142
|
+
channelName
|
|
1143
|
+
} : {}
|
|
1144
|
+
};
|
|
1145
|
+
return {
|
|
1146
|
+
allowed: false,
|
|
1147
|
+
reason: params.interactiveEvent && channelUsersAllowlistConfigured && allowFromLower.length > 0 ? "sender-not-authorized" : channelUsersAllowlistConfigured ? "sender-not-channel-allowed" : "sender-not-allowlisted",
|
|
1148
|
+
channelType,
|
|
1149
|
+
channelName
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
//#endregion
|
|
1153
|
+
//#region extensions/slack/src/monitor/mrkdwn.ts
|
|
1154
|
+
function escapeSlackMrkdwn(value) {
|
|
1155
|
+
return value.replaceAll("\\", "\\\\").replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replace(/([*_`~])/g, "\\$1");
|
|
1156
|
+
}
|
|
1157
|
+
//#endregion
|
|
1158
|
+
//#region extensions/slack/src/monitor/events/interactions.block-actions.ts
|
|
1159
|
+
function readOptionValues(options) {
|
|
1160
|
+
if (!Array.isArray(options)) return;
|
|
1161
|
+
const values = options.map((option) => option && typeof option === "object" ? option.value : null).filter((value) => typeof value === "string" && value.trim().length > 0);
|
|
1162
|
+
return values.length > 0 ? values : void 0;
|
|
1163
|
+
}
|
|
1164
|
+
function readOptionLabels(options) {
|
|
1165
|
+
if (!Array.isArray(options)) return;
|
|
1166
|
+
const labels = options.map((option) => option && typeof option === "object" ? option.text?.text ?? null : null).filter((label) => typeof label === "string" && label.trim().length > 0);
|
|
1167
|
+
return labels.length > 0 ? labels : void 0;
|
|
1168
|
+
}
|
|
1169
|
+
function uniqueNonEmptyStrings(values) {
|
|
1170
|
+
return normalizeUniqueTrimmedStringList(values);
|
|
1171
|
+
}
|
|
1172
|
+
function collectRichTextFragments(value, out) {
|
|
1173
|
+
if (!value || typeof value !== "object") return;
|
|
1174
|
+
const typed = value;
|
|
1175
|
+
if (typeof typed.text === "string" && typed.text.trim().length > 0) out.push(typed.text.trim());
|
|
1176
|
+
if (Array.isArray(typed.elements)) for (const child of typed.elements) collectRichTextFragments(child, out);
|
|
1177
|
+
}
|
|
1178
|
+
function summarizeRichTextPreview(value) {
|
|
1179
|
+
const fragments = [];
|
|
1180
|
+
collectRichTextFragments(value, fragments);
|
|
1181
|
+
if (fragments.length === 0) return;
|
|
1182
|
+
const joined = fragments.join(" ").replace(/\s+/g, " ").trim();
|
|
1183
|
+
if (!joined) return;
|
|
1184
|
+
const max = 120;
|
|
1185
|
+
return joined.length <= max ? joined : truncateSlackText(joined, max);
|
|
1186
|
+
}
|
|
1187
|
+
function readInteractionAction(raw) {
|
|
1188
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
|
|
1189
|
+
return raw;
|
|
1190
|
+
}
|
|
1191
|
+
function summarizeAction(action) {
|
|
1192
|
+
const typed = action;
|
|
1193
|
+
const actionType = typed.type;
|
|
1194
|
+
const selectedUsers = uniqueNonEmptyStrings([...typed.selected_user ? [typed.selected_user] : [], ...Array.isArray(typed.selected_users) ? typed.selected_users : []]);
|
|
1195
|
+
const selectedChannels = uniqueNonEmptyStrings([...typed.selected_channel ? [typed.selected_channel] : [], ...Array.isArray(typed.selected_channels) ? typed.selected_channels : []]);
|
|
1196
|
+
const selectedConversations = uniqueNonEmptyStrings([...typed.selected_conversation ? [typed.selected_conversation] : [], ...Array.isArray(typed.selected_conversations) ? typed.selected_conversations : []]);
|
|
1197
|
+
const selectedValues = uniqueNonEmptyStrings([
|
|
1198
|
+
...typed.selected_option?.value ? [typed.selected_option.value] : [],
|
|
1199
|
+
...readOptionValues(typed.selected_options) ?? [],
|
|
1200
|
+
...selectedUsers,
|
|
1201
|
+
...selectedChannels,
|
|
1202
|
+
...selectedConversations
|
|
1203
|
+
]);
|
|
1204
|
+
const selectedLabels = uniqueNonEmptyStrings([...typed.selected_option?.text?.text ? [typed.selected_option.text.text] : [], ...readOptionLabels(typed.selected_options) ?? []]);
|
|
1205
|
+
const inputValue = typeof typed.value === "string" ? typed.value : void 0;
|
|
1206
|
+
const inputNumber = actionType === "number_input" && inputValue != null ? parseStrictFiniteNumber(inputValue) : void 0;
|
|
1207
|
+
const parsedNumber = Number.isFinite(inputNumber) ? inputNumber : void 0;
|
|
1208
|
+
const inputEmail = actionType === "email_text_input" && inputValue?.includes("@") ? inputValue : void 0;
|
|
1209
|
+
let inputUrl;
|
|
1210
|
+
if (actionType === "url_text_input" && inputValue) try {
|
|
1211
|
+
inputUrl = new URL(inputValue).toString();
|
|
1212
|
+
} catch {
|
|
1213
|
+
inputUrl = void 0;
|
|
1214
|
+
}
|
|
1215
|
+
const richTextValue = actionType === "rich_text_input" ? typed.rich_text_value : void 0;
|
|
1216
|
+
const richTextPreview = summarizeRichTextPreview(richTextValue);
|
|
1217
|
+
return {
|
|
1218
|
+
actionType,
|
|
1219
|
+
inputKind: actionType === "number_input" ? "number" : actionType === "email_text_input" ? "email" : actionType === "url_text_input" ? "url" : actionType === "rich_text_input" ? "rich_text" : inputValue != null ? "text" : void 0,
|
|
1220
|
+
value: typed.value,
|
|
1221
|
+
selectedValues: selectedValues.length > 0 ? selectedValues : void 0,
|
|
1222
|
+
selectedUsers: selectedUsers.length > 0 ? selectedUsers : void 0,
|
|
1223
|
+
selectedChannels: selectedChannels.length > 0 ? selectedChannels : void 0,
|
|
1224
|
+
selectedConversations: selectedConversations.length > 0 ? selectedConversations : void 0,
|
|
1225
|
+
selectedLabels: selectedLabels.length > 0 ? selectedLabels : void 0,
|
|
1226
|
+
selectedDate: typed.selected_date,
|
|
1227
|
+
selectedTime: typed.selected_time,
|
|
1228
|
+
selectedDateTime: typeof typed.selected_date_time === "number" ? typed.selected_date_time : void 0,
|
|
1229
|
+
inputValue,
|
|
1230
|
+
inputNumber: parsedNumber,
|
|
1231
|
+
inputEmail,
|
|
1232
|
+
inputUrl,
|
|
1233
|
+
richTextValue,
|
|
1234
|
+
richTextPreview,
|
|
1235
|
+
workflowTriggerUrl: typed.workflow?.trigger_url,
|
|
1236
|
+
workflowId: typed.workflow?.workflow_id
|
|
1237
|
+
};
|
|
1238
|
+
}
|
|
1239
|
+
function formatInteractionSelectionLabel(params) {
|
|
1240
|
+
if (params.summary.actionType === "button" && params.buttonText?.trim()) return params.buttonText.trim();
|
|
1241
|
+
if (params.summary.selectedLabels?.length) {
|
|
1242
|
+
if (params.summary.selectedLabels.length <= 3) return params.summary.selectedLabels.join(", ");
|
|
1243
|
+
return `${params.summary.selectedLabels.slice(0, 3).join(", ")} +${params.summary.selectedLabels.length - 3}`;
|
|
1244
|
+
}
|
|
1245
|
+
if (params.summary.selectedValues?.length) {
|
|
1246
|
+
if (params.summary.selectedValues.length <= 3) return params.summary.selectedValues.join(", ");
|
|
1247
|
+
return `${params.summary.selectedValues.slice(0, 3).join(", ")} +${params.summary.selectedValues.length - 3}`;
|
|
1248
|
+
}
|
|
1249
|
+
if (params.summary.selectedDate) return params.summary.selectedDate;
|
|
1250
|
+
if (params.summary.selectedTime) return params.summary.selectedTime;
|
|
1251
|
+
if (typeof params.summary.selectedDateTime === "number") {
|
|
1252
|
+
const selectedDateTime = timestampMsToIsoString(params.summary.selectedDateTime * 1e3);
|
|
1253
|
+
if (selectedDateTime) return selectedDateTime;
|
|
1254
|
+
}
|
|
1255
|
+
if (params.summary.richTextPreview) return params.summary.richTextPreview;
|
|
1256
|
+
if (params.summary.value?.trim()) return params.summary.value.trim();
|
|
1257
|
+
return params.actionId;
|
|
1258
|
+
}
|
|
1259
|
+
function formatInteractionConfirmationText(params) {
|
|
1260
|
+
const userId = normalizeOptionalString(params.userId);
|
|
1261
|
+
const actor = userId ? ` by <@${userId}>` : "";
|
|
1262
|
+
return `:white_check_mark: *${escapeSlackMrkdwn(params.selectedLabel)}* selected${actor}`;
|
|
1263
|
+
}
|
|
1264
|
+
function buildSlackPluginInteractionData(params) {
|
|
1265
|
+
const actionId = normalizeOptionalString(params.actionId) ?? "";
|
|
1266
|
+
if (!actionId) return null;
|
|
1267
|
+
const payload = normalizeOptionalString(params.summary.value) || params.summary.selectedValues?.map((value) => normalizeOptionalString(value)).find(Boolean) || "";
|
|
1268
|
+
if (actionId === "openclaw:reply_button" || actionId === "openclaw:reply_select" || actionId.startsWith(`openclaw:reply_button:`) || actionId.startsWith(`openclaw:reply_select:`)) return payload || null;
|
|
1269
|
+
return payload ? `${actionId}:${payload}` : actionId;
|
|
1270
|
+
}
|
|
1271
|
+
function isSlackReplyActionId(actionId) {
|
|
1272
|
+
return actionId === "openclaw:reply_button" || actionId === "openclaw:reply_select" || actionId.startsWith(`openclaw:reply_button:`) || actionId.startsWith(`openclaw:reply_select:`);
|
|
1273
|
+
}
|
|
1274
|
+
function isSlackReplyLinkAction(parsed) {
|
|
1275
|
+
if (parsed.actionId === "openclaw:reply_link" || parsed.actionId.startsWith(`openclaw:reply_link:`)) return true;
|
|
1276
|
+
const legacyUrl = normalizeOptionalString(parsed.typedAction.url);
|
|
1277
|
+
return Boolean(legacyUrl && isSlackReplyActionId(parsed.actionId));
|
|
1278
|
+
}
|
|
1279
|
+
function buildSlackPluginInteractionId(params) {
|
|
1280
|
+
const primaryValue = normalizeOptionalString(params.summary.value) || params.summary.selectedValues?.map((value) => normalizeOptionalString(value)).find(Boolean) || "";
|
|
1281
|
+
return [
|
|
1282
|
+
normalizeOptionalString(params.userId) ?? "",
|
|
1283
|
+
normalizeOptionalString(params.channelId) ?? "",
|
|
1284
|
+
normalizeOptionalString(params.messageTs) ?? "",
|
|
1285
|
+
normalizeOptionalString(params.triggerId) ?? "",
|
|
1286
|
+
normalizeOptionalString(params.actionId) ?? "",
|
|
1287
|
+
primaryValue
|
|
1288
|
+
].join(":");
|
|
1289
|
+
}
|
|
1290
|
+
function parseSlackBlockAction(params) {
|
|
1291
|
+
const typedBody = params.body;
|
|
1292
|
+
const typedAction = readInteractionAction(params.action);
|
|
1293
|
+
if (!typedAction) {
|
|
1294
|
+
params.log?.(`slack:interaction malformed action payload channel=${typedBody.channel?.id ?? typedBody.container?.channel_id ?? "unknown"} user=${typedBody.user?.id ?? "unknown"}`);
|
|
1295
|
+
return null;
|
|
1296
|
+
}
|
|
1297
|
+
const typedActionWithText = typedAction;
|
|
1298
|
+
return {
|
|
1299
|
+
typedBody,
|
|
1300
|
+
typedAction,
|
|
1301
|
+
typedActionWithText,
|
|
1302
|
+
actionId: typeof typedActionWithText.action_id === "string" ? typedActionWithText.action_id : "unknown",
|
|
1303
|
+
blockId: typedActionWithText.block_id,
|
|
1304
|
+
userId: typedBody.user?.id ?? "unknown",
|
|
1305
|
+
channelId: typedBody.channel?.id ?? typedBody.container?.channel_id,
|
|
1306
|
+
messageTs: typedBody.message?.ts ?? typedBody.container?.message_ts,
|
|
1307
|
+
threadTs: typedBody.container?.thread_ts ?? typedBody.message?.thread_ts,
|
|
1308
|
+
actionSummary: summarizeAction(typedAction)
|
|
1309
|
+
};
|
|
1310
|
+
}
|
|
1311
|
+
async function respondEphemeral(respond, text) {
|
|
1312
|
+
if (!respond) return;
|
|
1313
|
+
try {
|
|
1314
|
+
await respond({
|
|
1315
|
+
text,
|
|
1316
|
+
response_type: "ephemeral"
|
|
1317
|
+
});
|
|
1318
|
+
} catch {}
|
|
1319
|
+
}
|
|
1320
|
+
async function updateSlackInteractionMessage(params) {
|
|
1321
|
+
if (!params.channelId || !params.messageTs) return;
|
|
1322
|
+
await params.ctx.app.client.chat.update({
|
|
1323
|
+
channel: params.channelId,
|
|
1324
|
+
ts: params.messageTs,
|
|
1325
|
+
text: params.text,
|
|
1326
|
+
...params.blocks ? { blocks: params.blocks } : {}
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1329
|
+
async function authorizeSlackBlockAction(params) {
|
|
1330
|
+
const auth = await authorizeSlackSystemEventSender({
|
|
1331
|
+
ctx: params.ctx,
|
|
1332
|
+
senderId: params.parsed.userId,
|
|
1333
|
+
channelId: params.parsed.channelId,
|
|
1334
|
+
expectedSenderId: params.parsed.userId,
|
|
1335
|
+
interactiveEvent: true
|
|
1336
|
+
});
|
|
1337
|
+
if (auth.allowed) return auth;
|
|
1338
|
+
params.ctx.runtime.log?.(`slack:interaction drop action=${params.parsed.actionId} user=${params.parsed.userId} channel=${params.parsed.channelId ?? "unknown"} reason=${auth.reason ?? "unauthorized"}`);
|
|
1339
|
+
await respondEphemeral(params.respond, "You are not authorized to use this control.");
|
|
1340
|
+
return { allowed: false };
|
|
1341
|
+
}
|
|
1342
|
+
async function handleSlackPluginBindingApproval(params) {
|
|
1343
|
+
const pluginBindingApproval = parsePluginBindingApprovalCustomId(params.pluginInteractionData);
|
|
1344
|
+
if (!pluginBindingApproval) return false;
|
|
1345
|
+
const resolved = await resolvePluginConversationBindingApproval({
|
|
1346
|
+
approvalId: pluginBindingApproval.approvalId,
|
|
1347
|
+
decision: pluginBindingApproval.decision,
|
|
1348
|
+
senderId: params.parsed.userId
|
|
1349
|
+
});
|
|
1350
|
+
try {
|
|
1351
|
+
await updateSlackInteractionMessage({
|
|
1352
|
+
ctx: params.ctx,
|
|
1353
|
+
channelId: params.parsed.channelId,
|
|
1354
|
+
messageTs: params.parsed.messageTs,
|
|
1355
|
+
text: params.parsed.typedBody.message?.text ?? "",
|
|
1356
|
+
blocks: []
|
|
1357
|
+
});
|
|
1358
|
+
} catch {}
|
|
1359
|
+
await respondEphemeral(params.respond, buildPluginBindingResolvedText(resolved));
|
|
1360
|
+
return true;
|
|
1361
|
+
}
|
|
1362
|
+
async function handleSlackExecApprovalInteraction(params) {
|
|
1363
|
+
const approval = parseExecApprovalCommandText(params.pluginInteractionData);
|
|
1364
|
+
if (!approval) return false;
|
|
1365
|
+
const pluginApprovalAuthorizedSender = isSlackApprovalAuthorizedSender({
|
|
1366
|
+
cfg: params.ctx.cfg,
|
|
1367
|
+
accountId: params.ctx.accountId,
|
|
1368
|
+
senderId: params.parsed.userId
|
|
1369
|
+
});
|
|
1370
|
+
const execApprovalAuthorizedSender = isSlackExecApprovalAuthorizedSender({
|
|
1371
|
+
cfg: params.ctx.cfg,
|
|
1372
|
+
accountId: params.ctx.accountId,
|
|
1373
|
+
senderId: params.parsed.userId
|
|
1374
|
+
});
|
|
1375
|
+
const isPluginApproval = approval.approvalId.startsWith("plugin:");
|
|
1376
|
+
const resolveUnprefixedAsPlugin = !isPluginApproval && !execApprovalAuthorizedSender && pluginApprovalAuthorizedSender;
|
|
1377
|
+
const authorized = isPluginApproval ? pluginApprovalAuthorizedSender : execApprovalAuthorizedSender || resolveUnprefixedAsPlugin;
|
|
1378
|
+
const allowPluginFallback = !isPluginApproval && execApprovalAuthorizedSender && pluginApprovalAuthorizedSender;
|
|
1379
|
+
if (!authorized) {
|
|
1380
|
+
params.ctx.runtime.log?.(`slack:interaction drop exec approval user=${params.parsed.userId} (not authorized)`);
|
|
1381
|
+
await respondEphemeral(params.respond, "You are not authorized to approve this request.");
|
|
1382
|
+
return true;
|
|
1383
|
+
}
|
|
1384
|
+
try {
|
|
1385
|
+
await resolveApprovalOverGateway({
|
|
1386
|
+
cfg: params.ctx.cfg,
|
|
1387
|
+
approvalId: approval.approvalId,
|
|
1388
|
+
decision: approval.decision,
|
|
1389
|
+
senderId: params.parsed.userId,
|
|
1390
|
+
allowPluginFallback,
|
|
1391
|
+
...resolveUnprefixedAsPlugin ? { resolveMethod: "plugin" } : {},
|
|
1392
|
+
clientDisplayName: `Slack approval (${params.parsed.userId.trim() || "unknown"})`
|
|
1393
|
+
});
|
|
1394
|
+
} catch (error) {
|
|
1395
|
+
params.ctx.runtime.log?.(`slack:interaction exec approval resolve failed id=${approval.approvalId}: ${String(error)}`);
|
|
1396
|
+
throw error;
|
|
1397
|
+
}
|
|
1398
|
+
try {
|
|
1399
|
+
await updateSlackInteractionMessage({
|
|
1400
|
+
ctx: params.ctx,
|
|
1401
|
+
channelId: params.parsed.channelId,
|
|
1402
|
+
messageTs: params.parsed.messageTs,
|
|
1403
|
+
text: params.parsed.typedBody.message?.text ?? "",
|
|
1404
|
+
blocks: []
|
|
1405
|
+
});
|
|
1406
|
+
} catch {}
|
|
1407
|
+
return true;
|
|
1408
|
+
}
|
|
1409
|
+
async function dispatchSlackPluginInteraction(params) {
|
|
1410
|
+
const pluginInteractionId = buildSlackPluginInteractionId({
|
|
1411
|
+
userId: params.parsed.userId,
|
|
1412
|
+
channelId: params.parsed.channelId,
|
|
1413
|
+
messageTs: params.parsed.messageTs,
|
|
1414
|
+
triggerId: params.parsed.typedBody.trigger_id,
|
|
1415
|
+
actionId: params.parsed.actionId,
|
|
1416
|
+
summary: params.parsed.actionSummary
|
|
1417
|
+
});
|
|
1418
|
+
if (await handleSlackPluginBindingApproval({
|
|
1419
|
+
ctx: params.ctx,
|
|
1420
|
+
parsed: params.parsed,
|
|
1421
|
+
pluginInteractionData: params.pluginInteractionData,
|
|
1422
|
+
respond: params.respond
|
|
1423
|
+
})) return true;
|
|
1424
|
+
const pluginResult = await dispatchSlackPluginInteractiveHandler({
|
|
1425
|
+
data: params.pluginInteractionData,
|
|
1426
|
+
interactionId: pluginInteractionId,
|
|
1427
|
+
ctx: {
|
|
1428
|
+
accountId: params.ctx.accountId,
|
|
1429
|
+
interactionId: pluginInteractionId,
|
|
1430
|
+
conversationId: params.parsed.channelId ?? "",
|
|
1431
|
+
parentConversationId: void 0,
|
|
1432
|
+
threadId: params.parsed.threadTs,
|
|
1433
|
+
senderId: params.parsed.userId,
|
|
1434
|
+
senderUsername: void 0,
|
|
1435
|
+
auth: params.auth,
|
|
1436
|
+
interaction: {
|
|
1437
|
+
kind: params.parsed.actionSummary.actionType === "button" ? "button" : "select",
|
|
1438
|
+
actionId: params.parsed.actionId,
|
|
1439
|
+
blockId: params.parsed.blockId,
|
|
1440
|
+
messageTs: params.parsed.messageTs,
|
|
1441
|
+
threadTs: params.parsed.threadTs,
|
|
1442
|
+
value: params.parsed.actionSummary.value,
|
|
1443
|
+
selectedValues: params.parsed.actionSummary.selectedValues,
|
|
1444
|
+
selectedLabels: params.parsed.actionSummary.selectedLabels,
|
|
1445
|
+
triggerId: params.parsed.typedBody.trigger_id,
|
|
1446
|
+
responseUrl: params.parsed.typedBody.response_url
|
|
1447
|
+
}
|
|
1448
|
+
},
|
|
1449
|
+
respond: {
|
|
1450
|
+
acknowledge: async () => {},
|
|
1451
|
+
reply: async ({ text, responseType }) => {
|
|
1452
|
+
if (!text) return;
|
|
1453
|
+
await params.respond?.({
|
|
1454
|
+
text,
|
|
1455
|
+
response_type: responseType ?? "ephemeral"
|
|
1456
|
+
});
|
|
1457
|
+
},
|
|
1458
|
+
followUp: async ({ text, responseType }) => {
|
|
1459
|
+
if (!text) return;
|
|
1460
|
+
await params.respond?.({
|
|
1461
|
+
text,
|
|
1462
|
+
response_type: responseType ?? "ephemeral"
|
|
1463
|
+
});
|
|
1464
|
+
},
|
|
1465
|
+
editMessage: async ({ text, blocks }) => {
|
|
1466
|
+
await updateSlackInteractionMessage({
|
|
1467
|
+
ctx: params.ctx,
|
|
1468
|
+
channelId: params.parsed.channelId,
|
|
1469
|
+
messageTs: params.parsed.messageTs,
|
|
1470
|
+
text: text ?? params.parsed.typedBody.message?.text ?? "",
|
|
1471
|
+
blocks: Array.isArray(blocks) ? blocks : void 0
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
});
|
|
1476
|
+
return pluginResult.matched && pluginResult.handled;
|
|
1477
|
+
}
|
|
1478
|
+
async function resolveSlackBlockActionCommandAuthorized(params) {
|
|
1479
|
+
const commandsAllowFrom = params.ctx.cfg.commands?.allowFrom;
|
|
1480
|
+
if (commandsAllowFrom != null && typeof commandsAllowFrom === "object" && (Array.isArray(commandsAllowFrom.slack) || Array.isArray(commandsAllowFrom["*"]))) return resolveCommandAuthorization({
|
|
1481
|
+
ctx: {
|
|
1482
|
+
Provider: "slack",
|
|
1483
|
+
Surface: "slack",
|
|
1484
|
+
OriginatingChannel: "slack",
|
|
1485
|
+
AccountId: params.ctx.accountId,
|
|
1486
|
+
ChatType: params.auth.channelType === "im" ? "direct" : "group",
|
|
1487
|
+
From: params.parsed.channelId ? `slack:${params.parsed.channelId}` : "slack",
|
|
1488
|
+
SenderId: params.parsed.userId
|
|
1489
|
+
},
|
|
1490
|
+
cfg: params.ctx.cfg,
|
|
1491
|
+
commandAuthorized: false
|
|
1492
|
+
}).isAuthorizedSender;
|
|
1493
|
+
const isDirectMessage = params.auth.channelType === "im";
|
|
1494
|
+
const isRoom = params.auth.channelType === "channel" || params.auth.channelType === "group";
|
|
1495
|
+
const allowFromLower = await resolveSlackEffectiveAllowFrom(params.ctx, { includePairingStore: isDirectMessage });
|
|
1496
|
+
const senderName = (await params.ctx.resolveUserName(params.parsed.userId).catch(() => void 0))?.name;
|
|
1497
|
+
let channelUsers = [];
|
|
1498
|
+
if (isRoom && params.parsed.channelId) {
|
|
1499
|
+
const channelConfig = resolveSlackChannelConfig({
|
|
1500
|
+
channelId: params.parsed.channelId,
|
|
1501
|
+
channelName: params.auth.channelName,
|
|
1502
|
+
channels: params.ctx.channelsConfig,
|
|
1503
|
+
channelKeys: params.ctx.channelsConfigKeys,
|
|
1504
|
+
defaultRequireMention: params.ctx.defaultRequireMention,
|
|
1505
|
+
allowNameMatching: params.ctx.allowNameMatching
|
|
1506
|
+
});
|
|
1507
|
+
channelUsers = Array.isArray(channelConfig?.users) ? channelConfig.users : [];
|
|
1508
|
+
}
|
|
1509
|
+
return (await resolveSlackCommandIngress({
|
|
1510
|
+
ctx: params.ctx,
|
|
1511
|
+
senderId: params.parsed.userId,
|
|
1512
|
+
senderName,
|
|
1513
|
+
channelType: params.auth.channelType ?? "channel",
|
|
1514
|
+
channelId: params.parsed.channelId ?? "slack-interaction",
|
|
1515
|
+
ownerAllowFromLower: allowFromLower,
|
|
1516
|
+
channelUsers,
|
|
1517
|
+
allowTextCommands: false,
|
|
1518
|
+
hasControlCommand: true,
|
|
1519
|
+
eventKind: "button",
|
|
1520
|
+
modeWhenAccessGroupsOff: "configured"
|
|
1521
|
+
})).commandAccess.authorized;
|
|
1522
|
+
}
|
|
1523
|
+
function enqueueSlackBlockActionEvent(params) {
|
|
1524
|
+
const eventPayload = {
|
|
1525
|
+
interactionType: "block_action",
|
|
1526
|
+
actionId: params.parsed.actionId,
|
|
1527
|
+
blockId: params.parsed.blockId,
|
|
1528
|
+
...params.parsed.actionSummary,
|
|
1529
|
+
userId: params.parsed.userId,
|
|
1530
|
+
teamId: params.parsed.typedBody.team?.id,
|
|
1531
|
+
triggerId: params.parsed.typedBody.trigger_id,
|
|
1532
|
+
responseUrl: params.parsed.typedBody.response_url,
|
|
1533
|
+
channelId: params.parsed.channelId,
|
|
1534
|
+
messageTs: params.parsed.messageTs,
|
|
1535
|
+
threadTs: params.parsed.threadTs
|
|
1536
|
+
};
|
|
1537
|
+
params.ctx.runtime.log?.(`slack:interaction action=${params.parsed.actionId} type=${params.parsed.actionSummary.actionType ?? "unknown"} user=${params.parsed.userId} channel=${params.parsed.channelId}`);
|
|
1538
|
+
const sessionKey = params.ctx.resolveSlackSystemEventSessionKey({
|
|
1539
|
+
channelId: params.parsed.channelId,
|
|
1540
|
+
channelType: params.auth.channelType,
|
|
1541
|
+
senderId: params.parsed.userId,
|
|
1542
|
+
threadTs: params.parsed.threadTs
|
|
1543
|
+
});
|
|
1544
|
+
const contextParts = [
|
|
1545
|
+
"slack:interaction",
|
|
1546
|
+
params.parsed.channelId,
|
|
1547
|
+
params.parsed.messageTs,
|
|
1548
|
+
params.parsed.actionId
|
|
1549
|
+
].filter(Boolean);
|
|
1550
|
+
if (enqueueSystemEvent(params.formatSystemEvent(eventPayload), {
|
|
1551
|
+
sessionKey,
|
|
1552
|
+
contextKey: contextParts.join(":"),
|
|
1553
|
+
deliveryContext: {
|
|
1554
|
+
channel: "slack",
|
|
1555
|
+
to: params.auth.channelType === "im" ? `user:${params.parsed.userId}` : params.parsed.channelId ? `channel:${params.parsed.channelId}` : void 0,
|
|
1556
|
+
accountId: params.ctx.accountId,
|
|
1557
|
+
threadId: params.parsed.threadTs
|
|
1558
|
+
}
|
|
1559
|
+
})) requestHeartbeat({
|
|
1560
|
+
source: "hook",
|
|
1561
|
+
intent: "immediate",
|
|
1562
|
+
reason: "hook:slack-interaction",
|
|
1563
|
+
sessionKey,
|
|
1564
|
+
heartbeat: { target: "last" }
|
|
1565
|
+
});
|
|
1566
|
+
}
|
|
1567
|
+
function buildSlackConfirmationBlocks(params) {
|
|
1568
|
+
const selectedLabel = formatInteractionSelectionLabel({
|
|
1569
|
+
actionId: params.parsed.actionId,
|
|
1570
|
+
summary: params.parsed.actionSummary,
|
|
1571
|
+
buttonText: params.parsed.typedActionWithText.text?.text
|
|
1572
|
+
});
|
|
1573
|
+
return params.originalBlocks.map((block) => {
|
|
1574
|
+
const typedBlock = block;
|
|
1575
|
+
if (typedBlock.type === "actions" && typedBlock.block_id === params.parsed.blockId) return {
|
|
1576
|
+
type: "context",
|
|
1577
|
+
elements: [{
|
|
1578
|
+
type: "mrkdwn",
|
|
1579
|
+
text: formatInteractionConfirmationText({
|
|
1580
|
+
selectedLabel,
|
|
1581
|
+
userId: params.parsed.userId
|
|
1582
|
+
})
|
|
1583
|
+
}]
|
|
1584
|
+
};
|
|
1585
|
+
return block;
|
|
1586
|
+
});
|
|
1587
|
+
}
|
|
1588
|
+
async function updateSlackLegacyBlockAction(params) {
|
|
1589
|
+
const originalBlocks = params.parsed.typedBody.message?.blocks;
|
|
1590
|
+
if (!Array.isArray(originalBlocks) || !params.parsed.channelId || !params.parsed.messageTs || !params.parsed.blockId) return;
|
|
1591
|
+
try {
|
|
1592
|
+
await updateSlackInteractionMessage({
|
|
1593
|
+
ctx: params.ctx,
|
|
1594
|
+
channelId: params.parsed.channelId,
|
|
1595
|
+
messageTs: params.parsed.messageTs,
|
|
1596
|
+
text: params.parsed.typedBody.message?.text ?? "",
|
|
1597
|
+
blocks: buildSlackConfirmationBlocks({
|
|
1598
|
+
parsed: params.parsed,
|
|
1599
|
+
originalBlocks
|
|
1600
|
+
})
|
|
1601
|
+
});
|
|
1602
|
+
} catch {
|
|
1603
|
+
await respondEphemeral(params.respond, `Button "${params.parsed.actionId}" clicked!`);
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
async function handleSlackBlockAction(params) {
|
|
1607
|
+
const { ack, body, action, respond } = params.args;
|
|
1608
|
+
await ack();
|
|
1609
|
+
if (params.ctx.shouldDropMismatchedSlackEvent?.(body)) {
|
|
1610
|
+
params.ctx.runtime.log?.("slack:interaction drop block action payload (mismatched app/team)");
|
|
1611
|
+
return;
|
|
1612
|
+
}
|
|
1613
|
+
const parsed = parseSlackBlockAction({
|
|
1614
|
+
body,
|
|
1615
|
+
action,
|
|
1616
|
+
log: params.ctx.runtime.log
|
|
1617
|
+
});
|
|
1618
|
+
if (!parsed) return;
|
|
1619
|
+
if (isSlackReplyLinkAction(parsed)) return;
|
|
1620
|
+
params.trackEvent?.();
|
|
1621
|
+
const pluginInteractionData = buildSlackPluginInteractionData({
|
|
1622
|
+
actionId: parsed.actionId,
|
|
1623
|
+
summary: parsed.actionSummary
|
|
1624
|
+
});
|
|
1625
|
+
if (pluginInteractionData && isSlackReplyActionId(parsed.actionId)) {
|
|
1626
|
+
if (await handleSlackExecApprovalInteraction({
|
|
1627
|
+
ctx: params.ctx,
|
|
1628
|
+
parsed,
|
|
1629
|
+
pluginInteractionData,
|
|
1630
|
+
respond
|
|
1631
|
+
})) return;
|
|
1632
|
+
}
|
|
1633
|
+
const auth = await authorizeSlackBlockAction({
|
|
1634
|
+
ctx: params.ctx,
|
|
1635
|
+
parsed,
|
|
1636
|
+
respond
|
|
1637
|
+
});
|
|
1638
|
+
if (!auth.allowed) return;
|
|
1639
|
+
if (pluginInteractionData && isSlackReplyActionId(parsed.actionId)) {
|
|
1640
|
+
if (await handleSlackPluginBindingApproval({
|
|
1641
|
+
ctx: params.ctx,
|
|
1642
|
+
parsed,
|
|
1643
|
+
pluginInteractionData,
|
|
1644
|
+
respond
|
|
1645
|
+
})) return;
|
|
1646
|
+
} else if (pluginInteractionData) {
|
|
1647
|
+
const isAuthorizedSender = await resolveSlackBlockActionCommandAuthorized({
|
|
1648
|
+
ctx: params.ctx,
|
|
1649
|
+
parsed,
|
|
1650
|
+
auth
|
|
1651
|
+
});
|
|
1652
|
+
if (await dispatchSlackPluginInteraction({
|
|
1653
|
+
ctx: params.ctx,
|
|
1654
|
+
parsed,
|
|
1655
|
+
pluginInteractionData,
|
|
1656
|
+
auth: { isAuthorizedSender },
|
|
1657
|
+
respond
|
|
1658
|
+
})) return;
|
|
1659
|
+
}
|
|
1660
|
+
enqueueSlackBlockActionEvent({
|
|
1661
|
+
ctx: params.ctx,
|
|
1662
|
+
parsed,
|
|
1663
|
+
auth,
|
|
1664
|
+
formatSystemEvent: params.formatSystemEvent
|
|
1665
|
+
});
|
|
1666
|
+
await updateSlackLegacyBlockAction({
|
|
1667
|
+
ctx: params.ctx,
|
|
1668
|
+
parsed,
|
|
1669
|
+
respond
|
|
1670
|
+
});
|
|
1671
|
+
}
|
|
1672
|
+
function registerSlackBlockActionHandler(params) {
|
|
1673
|
+
if (typeof params.ctx.app.action !== "function") return;
|
|
1674
|
+
params.ctx.app.action(/.+/, async (args) => {
|
|
1675
|
+
await handleSlackBlockAction({
|
|
1676
|
+
ctx: params.ctx,
|
|
1677
|
+
trackEvent: params.trackEvent,
|
|
1678
|
+
args,
|
|
1679
|
+
formatSystemEvent: params.formatSystemEvent
|
|
1680
|
+
});
|
|
1681
|
+
});
|
|
1682
|
+
}
|
|
1683
|
+
//#endregion
|
|
1684
|
+
//#region extensions/slack/src/modal-metadata.ts
|
|
1685
|
+
function parseSlackModalPrivateMetadata(raw) {
|
|
1686
|
+
if (typeof raw !== "string" || raw.trim().length === 0) return {};
|
|
1687
|
+
try {
|
|
1688
|
+
const parsed = JSON.parse(raw);
|
|
1689
|
+
return {
|
|
1690
|
+
sessionKey: normalizeOptionalString(parsed.sessionKey),
|
|
1691
|
+
channelId: normalizeOptionalString(parsed.channelId),
|
|
1692
|
+
channelType: normalizeOptionalString(parsed.channelType),
|
|
1693
|
+
userId: normalizeOptionalString(parsed.userId),
|
|
1694
|
+
pluginInteractiveData: normalizeOptionalString(parsed.pluginInteractiveData)
|
|
1695
|
+
};
|
|
1696
|
+
} catch {
|
|
1697
|
+
return {};
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
//#endregion
|
|
1701
|
+
//#region extensions/slack/src/monitor/events/interactions.modal.ts
|
|
1702
|
+
const OPENCLAW_MODAL_CALLBACK_PREFIX = "openclaw:";
|
|
1703
|
+
function resolveSlackModalPluginInteractiveData(params) {
|
|
1704
|
+
const metadataData = params.metadata.pluginInteractiveData?.trim();
|
|
1705
|
+
if (metadataData) return metadataData;
|
|
1706
|
+
if (!params.callbackId.startsWith(OPENCLAW_MODAL_CALLBACK_PREFIX)) return;
|
|
1707
|
+
return params.callbackId.slice(9).trim() || void 0;
|
|
1708
|
+
}
|
|
1709
|
+
function shouldHandleSlackModalLifecycleBody(body) {
|
|
1710
|
+
const typed = body;
|
|
1711
|
+
if ((typed.view?.callback_id ?? "").startsWith(OPENCLAW_MODAL_CALLBACK_PREFIX)) return true;
|
|
1712
|
+
const metadata = parseSlackModalPrivateMetadata(typed.view?.private_metadata);
|
|
1713
|
+
return Boolean(metadata.pluginInteractiveData?.trim());
|
|
1714
|
+
}
|
|
1715
|
+
function resolveSlackModalPluginNamespace(data) {
|
|
1716
|
+
if (!data) return;
|
|
1717
|
+
const separatorIndex = data.indexOf(":");
|
|
1718
|
+
return separatorIndex >= 0 ? data.slice(0, separatorIndex) : data;
|
|
1719
|
+
}
|
|
1720
|
+
function resolveSlackPluginSystemEventPayload(result) {
|
|
1721
|
+
if (!result || typeof result !== "object") return;
|
|
1722
|
+
const systemEvent = result.systemEvent;
|
|
1723
|
+
if (!systemEvent || typeof systemEvent !== "object") return;
|
|
1724
|
+
const typed = systemEvent;
|
|
1725
|
+
const output = {};
|
|
1726
|
+
if (typeof typed.summary === "string" && typed.summary.trim()) output.summary = typed.summary;
|
|
1727
|
+
if (typeof typed.reference === "string" && typed.reference.trim()) output.reference = typed.reference;
|
|
1728
|
+
if (typed.data && typeof typed.data === "object" && !Array.isArray(typed.data)) output.data = typed.data;
|
|
1729
|
+
return Object.keys(output).length > 0 ? output : void 0;
|
|
1730
|
+
}
|
|
1731
|
+
function resolveModalSessionRouting(params) {
|
|
1732
|
+
const metadata = params.metadata;
|
|
1733
|
+
if (metadata.sessionKey) return {
|
|
1734
|
+
sessionKey: metadata.sessionKey,
|
|
1735
|
+
channelId: metadata.channelId,
|
|
1736
|
+
channelType: metadata.channelType
|
|
1737
|
+
};
|
|
1738
|
+
if (metadata.channelId) return {
|
|
1739
|
+
sessionKey: params.ctx.resolveSlackSystemEventSessionKey({
|
|
1740
|
+
channelId: metadata.channelId,
|
|
1741
|
+
channelType: metadata.channelType,
|
|
1742
|
+
senderId: params.userId
|
|
1743
|
+
}),
|
|
1744
|
+
channelId: metadata.channelId,
|
|
1745
|
+
channelType: metadata.channelType
|
|
1746
|
+
};
|
|
1747
|
+
return { sessionKey: params.ctx.resolveSlackSystemEventSessionKey({}) };
|
|
1748
|
+
}
|
|
1749
|
+
function summarizeSlackViewLifecycleContext(view) {
|
|
1750
|
+
const rootViewId = view.root_view_id;
|
|
1751
|
+
const previousViewId = view.previous_view_id;
|
|
1752
|
+
return {
|
|
1753
|
+
rootViewId,
|
|
1754
|
+
previousViewId,
|
|
1755
|
+
externalId: view.external_id,
|
|
1756
|
+
viewHash: view.hash,
|
|
1757
|
+
isStackedView: Boolean(previousViewId)
|
|
1758
|
+
};
|
|
1759
|
+
}
|
|
1760
|
+
function resolveSlackModalEventBase(params) {
|
|
1761
|
+
const metadata = parseSlackModalPrivateMetadata(params.body.view?.private_metadata);
|
|
1762
|
+
const callbackId = params.body.view?.callback_id ?? "unknown";
|
|
1763
|
+
const userId = params.body.user?.id ?? "unknown";
|
|
1764
|
+
const viewId = params.body.view?.id;
|
|
1765
|
+
const inputs = params.summarizeViewState(params.body.view?.state?.values);
|
|
1766
|
+
const sessionRouting = resolveModalSessionRouting({
|
|
1767
|
+
ctx: params.ctx,
|
|
1768
|
+
metadata,
|
|
1769
|
+
userId
|
|
1770
|
+
});
|
|
1771
|
+
return {
|
|
1772
|
+
callbackId,
|
|
1773
|
+
userId,
|
|
1774
|
+
expectedUserId: metadata.userId,
|
|
1775
|
+
viewId,
|
|
1776
|
+
sessionRouting,
|
|
1777
|
+
stateValues: params.body.view?.state?.values,
|
|
1778
|
+
payload: {
|
|
1779
|
+
actionId: `view:${callbackId}`,
|
|
1780
|
+
callbackId,
|
|
1781
|
+
viewId,
|
|
1782
|
+
userId,
|
|
1783
|
+
teamId: params.body.team?.id,
|
|
1784
|
+
...summarizeSlackViewLifecycleContext({
|
|
1785
|
+
root_view_id: params.body.view?.root_view_id,
|
|
1786
|
+
previous_view_id: params.body.view?.previous_view_id,
|
|
1787
|
+
external_id: params.body.view?.external_id,
|
|
1788
|
+
hash: params.body.view?.hash
|
|
1789
|
+
}),
|
|
1790
|
+
privateMetadata: params.body.view?.private_metadata,
|
|
1791
|
+
routedChannelId: sessionRouting.channelId,
|
|
1792
|
+
routedChannelType: sessionRouting.channelType,
|
|
1793
|
+
inputs
|
|
1794
|
+
}
|
|
1795
|
+
};
|
|
1796
|
+
}
|
|
1797
|
+
async function dispatchSlackModalPluginInteractiveHandler(params) {
|
|
1798
|
+
if (!params.data) return {
|
|
1799
|
+
matched: false,
|
|
1800
|
+
handled: false,
|
|
1801
|
+
duplicate: false
|
|
1802
|
+
};
|
|
1803
|
+
const isViewClosed = params.interactionType === "view_closed";
|
|
1804
|
+
const interactionId = [
|
|
1805
|
+
params.interactionType,
|
|
1806
|
+
params.payload.callbackId,
|
|
1807
|
+
params.payload.viewId,
|
|
1808
|
+
params.payload.userId
|
|
1809
|
+
].filter(Boolean).join(":");
|
|
1810
|
+
const result = await dispatchSlackPluginInteractiveHandler({
|
|
1811
|
+
data: params.data,
|
|
1812
|
+
interactionId,
|
|
1813
|
+
ctx: {
|
|
1814
|
+
accountId: params.ctx.accountId,
|
|
1815
|
+
interactionId,
|
|
1816
|
+
conversationId: params.sessionRouting.channelId ?? "",
|
|
1817
|
+
parentConversationId: void 0,
|
|
1818
|
+
threadId: void 0,
|
|
1819
|
+
senderId: params.payload.userId,
|
|
1820
|
+
senderUsername: void 0,
|
|
1821
|
+
auth: params.auth,
|
|
1822
|
+
interaction: {
|
|
1823
|
+
kind: params.interactionType,
|
|
1824
|
+
callbackId: params.payload.callbackId,
|
|
1825
|
+
viewId: params.payload.viewId,
|
|
1826
|
+
rootViewId: params.payload.rootViewId,
|
|
1827
|
+
previousViewId: params.payload.previousViewId,
|
|
1828
|
+
externalId: params.payload.externalId,
|
|
1829
|
+
isStackedView: params.payload.isStackedView,
|
|
1830
|
+
isCleared: isViewClosed ? params.body.is_cleared === true : void 0,
|
|
1831
|
+
inputs: params.payload.inputs,
|
|
1832
|
+
stateValues: params.stateValues,
|
|
1833
|
+
triggerId: params.body.trigger_id
|
|
1834
|
+
}
|
|
1835
|
+
},
|
|
1836
|
+
respond: {
|
|
1837
|
+
acknowledge: async () => {},
|
|
1838
|
+
reply: async () => {},
|
|
1839
|
+
followUp: async () => {},
|
|
1840
|
+
editMessage: async () => {}
|
|
1841
|
+
}
|
|
1842
|
+
});
|
|
1843
|
+
return {
|
|
1844
|
+
...result,
|
|
1845
|
+
namespace: result.matched ? resolveSlackModalPluginNamespace(params.data) : void 0,
|
|
1846
|
+
systemEvent: result.matched ? resolveSlackPluginSystemEventPayload(result.result) : void 0
|
|
1847
|
+
};
|
|
1848
|
+
}
|
|
1849
|
+
async function emitSlackModalLifecycleEvent(params) {
|
|
1850
|
+
const { callbackId, userId, expectedUserId, viewId, sessionRouting, stateValues, payload } = resolveSlackModalEventBase({
|
|
1851
|
+
ctx: params.ctx,
|
|
1852
|
+
body: params.body,
|
|
1853
|
+
summarizeViewState: params.summarizeViewState
|
|
1854
|
+
});
|
|
1855
|
+
const pluginInteractiveData = resolveSlackModalPluginInteractiveData({
|
|
1856
|
+
callbackId,
|
|
1857
|
+
metadata: parseSlackModalPrivateMetadata(params.body.view?.private_metadata)
|
|
1858
|
+
});
|
|
1859
|
+
const isViewClosed = params.interactionType === "view_closed";
|
|
1860
|
+
const isCleared = params.body.is_cleared === true;
|
|
1861
|
+
const eventPayload = isViewClosed ? {
|
|
1862
|
+
interactionType: params.interactionType,
|
|
1863
|
+
...payload,
|
|
1864
|
+
isCleared
|
|
1865
|
+
} : {
|
|
1866
|
+
interactionType: params.interactionType,
|
|
1867
|
+
...payload
|
|
1868
|
+
};
|
|
1869
|
+
if (isViewClosed) params.ctx.runtime.log?.(`slack:interaction view_closed callback=${callbackId} user=${userId} cleared=${isCleared}`);
|
|
1870
|
+
else params.ctx.runtime.log?.(`slack:interaction view_submission callback=${callbackId} user=${userId} inputs=${payload.inputs.length}`);
|
|
1871
|
+
if (!expectedUserId) {
|
|
1872
|
+
if (pluginInteractiveData) try {
|
|
1873
|
+
await dispatchSlackModalPluginInteractiveHandler({
|
|
1874
|
+
ctx: params.ctx,
|
|
1875
|
+
body: params.body,
|
|
1876
|
+
interactionType: params.interactionType,
|
|
1877
|
+
data: pluginInteractiveData,
|
|
1878
|
+
auth: { isAuthorizedSender: false },
|
|
1879
|
+
payload,
|
|
1880
|
+
stateValues,
|
|
1881
|
+
sessionRouting
|
|
1882
|
+
});
|
|
1883
|
+
} catch (error) {
|
|
1884
|
+
params.ctx.runtime.log?.(`slack:interaction modal plugin dispatch failed callback=${callbackId} error=${error instanceof Error ? error.message : String(error)}`);
|
|
1885
|
+
}
|
|
1886
|
+
params.ctx.runtime.log?.(`slack:interaction drop modal callback=${callbackId} user=${userId} reason=missing-expected-user`);
|
|
1887
|
+
return;
|
|
1888
|
+
}
|
|
1889
|
+
const auth = await authorizeSlackSystemEventSender({
|
|
1890
|
+
ctx: params.ctx,
|
|
1891
|
+
senderId: userId,
|
|
1892
|
+
channelId: sessionRouting.channelId,
|
|
1893
|
+
channelType: sessionRouting.channelType,
|
|
1894
|
+
expectedSenderId: expectedUserId,
|
|
1895
|
+
interactiveEvent: true
|
|
1896
|
+
});
|
|
1897
|
+
if (!auth.allowed) {
|
|
1898
|
+
params.ctx.runtime.log?.(`slack:interaction drop modal callback=${callbackId} user=${userId} reason=${auth.reason ?? "unauthorized"}`);
|
|
1899
|
+
return;
|
|
1900
|
+
}
|
|
1901
|
+
let pluginDispatch;
|
|
1902
|
+
try {
|
|
1903
|
+
pluginDispatch = await dispatchSlackModalPluginInteractiveHandler({
|
|
1904
|
+
ctx: params.ctx,
|
|
1905
|
+
body: params.body,
|
|
1906
|
+
interactionType: params.interactionType,
|
|
1907
|
+
data: pluginInteractiveData,
|
|
1908
|
+
auth: { isAuthorizedSender: auth.allowed },
|
|
1909
|
+
payload,
|
|
1910
|
+
stateValues,
|
|
1911
|
+
sessionRouting
|
|
1912
|
+
});
|
|
1913
|
+
} catch (error) {
|
|
1914
|
+
params.ctx.runtime.log?.(`slack:interaction modal plugin dispatch failed callback=${callbackId} error=${error instanceof Error ? error.message : String(error)}`);
|
|
1915
|
+
}
|
|
1916
|
+
const pluginEventFields = pluginDispatch?.matched === true ? {
|
|
1917
|
+
pluginHandled: pluginDispatch.handled,
|
|
1918
|
+
pluginNamespace: pluginDispatch.namespace,
|
|
1919
|
+
pluginDuplicate: pluginDispatch.duplicate || void 0,
|
|
1920
|
+
pluginSystemEvent: pluginDispatch.systemEvent
|
|
1921
|
+
} : {};
|
|
1922
|
+
enqueueSystemEvent(params.formatSystemEvent({
|
|
1923
|
+
...eventPayload,
|
|
1924
|
+
...pluginEventFields
|
|
1925
|
+
}), {
|
|
1926
|
+
sessionKey: sessionRouting.sessionKey,
|
|
1927
|
+
contextKey: [
|
|
1928
|
+
params.contextPrefix,
|
|
1929
|
+
callbackId,
|
|
1930
|
+
viewId,
|
|
1931
|
+
userId
|
|
1932
|
+
].filter(Boolean).join(":")
|
|
1933
|
+
});
|
|
1934
|
+
}
|
|
1935
|
+
function registerModalLifecycleHandler(params) {
|
|
1936
|
+
params.register(params.matcher, async ({ ack, body }) => {
|
|
1937
|
+
if (!shouldHandleSlackModalLifecycleBody(body)) return;
|
|
1938
|
+
await ack();
|
|
1939
|
+
if (params.ctx.shouldDropMismatchedSlackEvent?.(body)) {
|
|
1940
|
+
params.ctx.runtime.log?.(`slack:interaction drop ${params.interactionType} payload (mismatched app/team)`);
|
|
1941
|
+
return;
|
|
1942
|
+
}
|
|
1943
|
+
params.trackEvent?.();
|
|
1944
|
+
await emitSlackModalLifecycleEvent({
|
|
1945
|
+
ctx: params.ctx,
|
|
1946
|
+
body,
|
|
1947
|
+
interactionType: params.interactionType,
|
|
1948
|
+
contextPrefix: params.contextPrefix,
|
|
1949
|
+
summarizeViewState: params.summarizeViewState,
|
|
1950
|
+
formatSystemEvent: params.formatSystemEvent
|
|
1951
|
+
});
|
|
1952
|
+
});
|
|
1953
|
+
}
|
|
1954
|
+
//#endregion
|
|
1955
|
+
//#region extensions/slack/src/monitor/events/interactions.shortcuts.ts
|
|
1956
|
+
function resolveMessageThreadTs(body) {
|
|
1957
|
+
const threadTs = body.message.thread_ts;
|
|
1958
|
+
return typeof threadTs === "string" && threadTs.trim() ? threadTs.trim() : void 0;
|
|
1959
|
+
}
|
|
1960
|
+
async function handleSlackShortcut(params) {
|
|
1961
|
+
const { ack, body } = params.args;
|
|
1962
|
+
await ack();
|
|
1963
|
+
if (params.ctx.shouldDropMismatchedSlackEvent?.(body)) {
|
|
1964
|
+
params.ctx.runtime.log?.("slack:interaction drop shortcut payload (mismatched app/team)");
|
|
1965
|
+
return;
|
|
1966
|
+
}
|
|
1967
|
+
const callbackId = body.callback_id?.trim();
|
|
1968
|
+
const userId = body.user?.id?.trim();
|
|
1969
|
+
if (!callbackId || !userId) {
|
|
1970
|
+
params.ctx.runtime.log?.("slack:interaction drop shortcut reason=invalid-payload");
|
|
1971
|
+
return;
|
|
1972
|
+
}
|
|
1973
|
+
params.trackEvent?.();
|
|
1974
|
+
const isMessageShortcut = body.type === "message_action";
|
|
1975
|
+
const messageBody = isMessageShortcut ? body : void 0;
|
|
1976
|
+
const channelId = messageBody?.channel.id?.trim() || void 0;
|
|
1977
|
+
if (isMessageShortcut && !channelId) {
|
|
1978
|
+
params.ctx.runtime.log?.(`slack:interaction drop shortcut callback=${callbackId} user=${userId} reason=missing-channel`);
|
|
1979
|
+
return;
|
|
1980
|
+
}
|
|
1981
|
+
const threadTs = messageBody ? resolveMessageThreadTs(messageBody) : void 0;
|
|
1982
|
+
const auth = await authorizeSlackSystemEventSender({
|
|
1983
|
+
ctx: params.ctx,
|
|
1984
|
+
senderId: userId,
|
|
1985
|
+
channelId,
|
|
1986
|
+
channelType: isMessageShortcut ? void 0 : "im",
|
|
1987
|
+
expectedSenderId: userId,
|
|
1988
|
+
interactiveEvent: true
|
|
1989
|
+
});
|
|
1990
|
+
if (!auth.allowed) {
|
|
1991
|
+
params.ctx.runtime.log?.(`slack:interaction drop shortcut callback=${callbackId} user=${userId} reason=${auth.reason ?? "unauthorized"}`);
|
|
1992
|
+
return;
|
|
1993
|
+
}
|
|
1994
|
+
const interactionType = isMessageShortcut ? "message_shortcut" : "global_shortcut";
|
|
1995
|
+
const messageTs = messageBody?.message.ts || messageBody?.message_ts;
|
|
1996
|
+
const eventPayload = {
|
|
1997
|
+
interactionType,
|
|
1998
|
+
actionId: `shortcut:${callbackId}`,
|
|
1999
|
+
callbackId,
|
|
2000
|
+
userId,
|
|
2001
|
+
teamId: body.team?.id ?? body.user.team_id,
|
|
2002
|
+
triggerId: body.trigger_id,
|
|
2003
|
+
actionTs: body.action_ts,
|
|
2004
|
+
channelId,
|
|
2005
|
+
channelName: messageBody?.channel.name,
|
|
2006
|
+
messageTs,
|
|
2007
|
+
threadTs,
|
|
2008
|
+
messageUserId: messageBody?.message.user,
|
|
2009
|
+
messageText: messageBody?.message.text,
|
|
2010
|
+
responseUrl: messageBody?.response_url
|
|
2011
|
+
};
|
|
2012
|
+
const sessionKey = params.ctx.resolveSlackSystemEventSessionKey({
|
|
2013
|
+
channelId,
|
|
2014
|
+
channelType: auth.channelType,
|
|
2015
|
+
senderId: userId,
|
|
2016
|
+
threadTs
|
|
2017
|
+
});
|
|
2018
|
+
const contextKey = [
|
|
2019
|
+
"slack:interaction:shortcut",
|
|
2020
|
+
interactionType,
|
|
2021
|
+
callbackId,
|
|
2022
|
+
channelId,
|
|
2023
|
+
messageTs,
|
|
2024
|
+
body.action_ts
|
|
2025
|
+
].filter(Boolean).join(":");
|
|
2026
|
+
params.ctx.runtime.log?.(`slack:interaction ${interactionType} callback=${callbackId} user=${userId} channel=${channelId ?? "direct"}`);
|
|
2027
|
+
if (enqueueSystemEvent(params.formatSystemEvent(eventPayload), {
|
|
2028
|
+
sessionKey,
|
|
2029
|
+
contextKey,
|
|
2030
|
+
deliveryContext: {
|
|
2031
|
+
channel: "slack",
|
|
2032
|
+
to: auth.channelType === "im" ? `user:${userId}` : `channel:${channelId}`,
|
|
2033
|
+
accountId: params.ctx.accountId,
|
|
2034
|
+
threadId: threadTs
|
|
2035
|
+
}
|
|
2036
|
+
})) requestHeartbeat({
|
|
2037
|
+
source: "hook",
|
|
2038
|
+
intent: "immediate",
|
|
2039
|
+
reason: "hook:slack-interaction",
|
|
2040
|
+
sessionKey,
|
|
2041
|
+
heartbeat: { target: "last" }
|
|
2042
|
+
});
|
|
2043
|
+
}
|
|
2044
|
+
function registerSlackShortcutHandler(params) {
|
|
2045
|
+
if (typeof params.ctx.app.shortcut !== "function") return;
|
|
2046
|
+
params.ctx.app.shortcut(/.+/, async (args) => {
|
|
2047
|
+
await handleSlackShortcut({
|
|
2048
|
+
ctx: params.ctx,
|
|
2049
|
+
trackEvent: params.trackEvent,
|
|
2050
|
+
args,
|
|
2051
|
+
formatSystemEvent: params.formatSystemEvent
|
|
2052
|
+
});
|
|
2053
|
+
});
|
|
2054
|
+
}
|
|
2055
|
+
//#endregion
|
|
2056
|
+
//#region extensions/slack/src/monitor/events/interactions.ts
|
|
2057
|
+
const SLACK_INTERACTION_EVENT_PREFIX = "Slack interaction: ";
|
|
2058
|
+
const REDACTED_INTERACTION_VALUE = "[redacted]";
|
|
2059
|
+
const SLACK_INTERACTION_EVENT_MAX_CHARS = 2400;
|
|
2060
|
+
const SLACK_INTERACTION_STRING_MAX_CHARS = 160;
|
|
2061
|
+
const SLACK_INTERACTION_ARRAY_MAX_ITEMS = 64;
|
|
2062
|
+
const SLACK_INTERACTION_COMPACT_INPUTS_MAX_ITEMS = 3;
|
|
2063
|
+
const SLACK_INTERACTION_REDACTED_KEYS = /* @__PURE__ */ new Set([
|
|
2064
|
+
"triggerId",
|
|
2065
|
+
"responseUrl",
|
|
2066
|
+
"workflowTriggerUrl",
|
|
2067
|
+
"privateMetadata",
|
|
2068
|
+
"viewHash"
|
|
2069
|
+
]);
|
|
2070
|
+
function sanitizeSlackInteractionPayloadValue(value, key) {
|
|
2071
|
+
if (value === void 0) return;
|
|
2072
|
+
if (key && SLACK_INTERACTION_REDACTED_KEYS.has(key)) {
|
|
2073
|
+
if (typeof value !== "string" || value.trim().length === 0) return;
|
|
2074
|
+
return REDACTED_INTERACTION_VALUE;
|
|
2075
|
+
}
|
|
2076
|
+
if (typeof value === "string") return truncateSlackText(value, SLACK_INTERACTION_STRING_MAX_CHARS);
|
|
2077
|
+
if (Array.isArray(value)) {
|
|
2078
|
+
const sanitized = value.slice(0, SLACK_INTERACTION_ARRAY_MAX_ITEMS).map((entry) => sanitizeSlackInteractionPayloadValue(entry)).filter((entry) => entry !== void 0);
|
|
2079
|
+
if (value.length > SLACK_INTERACTION_ARRAY_MAX_ITEMS) sanitized.push(`…+${value.length - SLACK_INTERACTION_ARRAY_MAX_ITEMS} more`);
|
|
2080
|
+
return sanitized;
|
|
2081
|
+
}
|
|
2082
|
+
if (!value || typeof value !== "object") return value;
|
|
2083
|
+
const output = {};
|
|
2084
|
+
for (const [entryKey, entryValue] of Object.entries(value)) {
|
|
2085
|
+
const sanitized = sanitizeSlackInteractionPayloadValue(entryValue, entryKey);
|
|
2086
|
+
if (sanitized === void 0) continue;
|
|
2087
|
+
if (typeof sanitized === "string" && sanitized.length === 0) continue;
|
|
2088
|
+
if (Array.isArray(sanitized) && sanitized.length === 0) continue;
|
|
2089
|
+
output[entryKey] = sanitized;
|
|
2090
|
+
}
|
|
2091
|
+
return output;
|
|
2092
|
+
}
|
|
2093
|
+
function buildCompactSlackInteractionPayload(payload) {
|
|
2094
|
+
const rawInputs = Array.isArray(payload.inputs) ? payload.inputs : [];
|
|
2095
|
+
const compactInputs = rawInputs.slice(0, SLACK_INTERACTION_COMPACT_INPUTS_MAX_ITEMS).flatMap((entry) => {
|
|
2096
|
+
if (!entry || typeof entry !== "object") return [];
|
|
2097
|
+
const typed = entry;
|
|
2098
|
+
return [{
|
|
2099
|
+
actionId: typed.actionId,
|
|
2100
|
+
blockId: typed.blockId,
|
|
2101
|
+
actionType: typed.actionType,
|
|
2102
|
+
inputKind: typed.inputKind,
|
|
2103
|
+
selectedValues: typed.selectedValues,
|
|
2104
|
+
selectedLabels: typed.selectedLabels,
|
|
2105
|
+
inputValue: typed.inputValue,
|
|
2106
|
+
inputNumber: typed.inputNumber,
|
|
2107
|
+
selectedDate: typed.selectedDate,
|
|
2108
|
+
selectedTime: typed.selectedTime,
|
|
2109
|
+
selectedDateTime: typed.selectedDateTime,
|
|
2110
|
+
richTextPreview: typed.richTextPreview
|
|
2111
|
+
}];
|
|
2112
|
+
});
|
|
2113
|
+
return {
|
|
2114
|
+
interactionType: payload.interactionType,
|
|
2115
|
+
actionId: payload.actionId,
|
|
2116
|
+
callbackId: payload.callbackId,
|
|
2117
|
+
actionType: payload.actionType,
|
|
2118
|
+
actionTs: payload.actionTs,
|
|
2119
|
+
userId: payload.userId,
|
|
2120
|
+
teamId: payload.teamId,
|
|
2121
|
+
channelId: payload.channelId ?? payload.routedChannelId,
|
|
2122
|
+
messageTs: payload.messageTs,
|
|
2123
|
+
threadTs: payload.threadTs,
|
|
2124
|
+
messageUserId: payload.messageUserId,
|
|
2125
|
+
messageText: payload.messageText,
|
|
2126
|
+
viewId: payload.viewId,
|
|
2127
|
+
isCleared: payload.isCleared,
|
|
2128
|
+
selectedValues: payload.selectedValues,
|
|
2129
|
+
selectedLabels: payload.selectedLabels,
|
|
2130
|
+
selectedDate: payload.selectedDate,
|
|
2131
|
+
selectedTime: payload.selectedTime,
|
|
2132
|
+
selectedDateTime: payload.selectedDateTime,
|
|
2133
|
+
workflowId: payload.workflowId,
|
|
2134
|
+
routedChannelType: payload.routedChannelType,
|
|
2135
|
+
pluginHandled: payload.pluginHandled,
|
|
2136
|
+
pluginNamespace: payload.pluginNamespace,
|
|
2137
|
+
pluginDuplicate: payload.pluginDuplicate,
|
|
2138
|
+
pluginSystemEvent: payload.pluginSystemEvent,
|
|
2139
|
+
inputs: compactInputs.length > 0 ? compactInputs : void 0,
|
|
2140
|
+
inputsOmitted: rawInputs.length > SLACK_INTERACTION_COMPACT_INPUTS_MAX_ITEMS ? rawInputs.length - SLACK_INTERACTION_COMPACT_INPUTS_MAX_ITEMS : void 0,
|
|
2141
|
+
payloadTruncated: true
|
|
2142
|
+
};
|
|
2143
|
+
}
|
|
2144
|
+
function formatSlackInteractionSystemEvent(payload) {
|
|
2145
|
+
const toEventText = (value) => `${SLACK_INTERACTION_EVENT_PREFIX}${JSON.stringify(value)}`;
|
|
2146
|
+
const sanitizedPayload = sanitizeSlackInteractionPayloadValue(payload) ?? {};
|
|
2147
|
+
let eventText = toEventText(sanitizedPayload);
|
|
2148
|
+
if (eventText.length <= SLACK_INTERACTION_EVENT_MAX_CHARS) return eventText;
|
|
2149
|
+
eventText = toEventText(sanitizeSlackInteractionPayloadValue(buildCompactSlackInteractionPayload(sanitizedPayload)));
|
|
2150
|
+
if (eventText.length <= SLACK_INTERACTION_EVENT_MAX_CHARS) return eventText;
|
|
2151
|
+
return toEventText({
|
|
2152
|
+
interactionType: sanitizedPayload.interactionType,
|
|
2153
|
+
actionId: sanitizedPayload.actionId ?? "unknown",
|
|
2154
|
+
userId: sanitizedPayload.userId,
|
|
2155
|
+
channelId: sanitizedPayload.channelId ?? sanitizedPayload.routedChannelId,
|
|
2156
|
+
payloadTruncated: true
|
|
2157
|
+
});
|
|
2158
|
+
}
|
|
2159
|
+
function summarizeViewState(values) {
|
|
2160
|
+
if (!values || typeof values !== "object") return [];
|
|
2161
|
+
const entries = [];
|
|
2162
|
+
for (const [blockId, blockValue] of Object.entries(values)) {
|
|
2163
|
+
if (!blockValue || typeof blockValue !== "object") continue;
|
|
2164
|
+
for (const [actionId, rawAction] of Object.entries(blockValue)) {
|
|
2165
|
+
if (!rawAction || typeof rawAction !== "object") continue;
|
|
2166
|
+
const actionSummary = summarizeAction(rawAction);
|
|
2167
|
+
entries.push({
|
|
2168
|
+
blockId,
|
|
2169
|
+
actionId,
|
|
2170
|
+
...actionSummary
|
|
2171
|
+
});
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
return entries;
|
|
2175
|
+
}
|
|
2176
|
+
function registerSlackInteractionEvents(params) {
|
|
2177
|
+
const { ctx, trackEvent } = params;
|
|
2178
|
+
registerSlackBlockActionHandler({
|
|
2179
|
+
ctx,
|
|
2180
|
+
trackEvent,
|
|
2181
|
+
formatSystemEvent: formatSlackInteractionSystemEvent
|
|
2182
|
+
});
|
|
2183
|
+
registerSlackShortcutHandler({
|
|
2184
|
+
ctx,
|
|
2185
|
+
trackEvent,
|
|
2186
|
+
formatSystemEvent: formatSlackInteractionSystemEvent
|
|
2187
|
+
});
|
|
2188
|
+
if (typeof ctx.app.view !== "function") return;
|
|
2189
|
+
const modalMatcher = /.*/;
|
|
2190
|
+
registerModalLifecycleHandler({
|
|
2191
|
+
register: (matcher, handler) => ctx.app.view(matcher, handler),
|
|
2192
|
+
matcher: modalMatcher,
|
|
2193
|
+
ctx,
|
|
2194
|
+
trackEvent,
|
|
2195
|
+
interactionType: "view_submission",
|
|
2196
|
+
contextPrefix: "slack:interaction:view",
|
|
2197
|
+
summarizeViewState,
|
|
2198
|
+
formatSystemEvent: formatSlackInteractionSystemEvent
|
|
2199
|
+
});
|
|
2200
|
+
const viewClosed = ctx.app.viewClosed;
|
|
2201
|
+
if (typeof viewClosed !== "function") return;
|
|
2202
|
+
registerModalLifecycleHandler({
|
|
2203
|
+
register: viewClosed,
|
|
2204
|
+
matcher: modalMatcher,
|
|
2205
|
+
ctx,
|
|
2206
|
+
trackEvent,
|
|
2207
|
+
interactionType: "view_closed",
|
|
2208
|
+
contextPrefix: "slack:interaction:view-closed",
|
|
2209
|
+
summarizeViewState,
|
|
2210
|
+
formatSystemEvent: formatSlackInteractionSystemEvent
|
|
2211
|
+
});
|
|
2212
|
+
}
|
|
2213
|
+
//#endregion
|
|
2214
|
+
//#region extensions/slack/src/monitor/events/system-event-context.ts
|
|
2215
|
+
async function authorizeAndResolveSlackSystemEventContext(params) {
|
|
2216
|
+
const { ctx, senderId, channelId, channelType, eventKind } = params;
|
|
2217
|
+
const auth = await authorizeSlackSystemEventSender({
|
|
2218
|
+
ctx,
|
|
2219
|
+
senderId,
|
|
2220
|
+
channelId,
|
|
2221
|
+
channelType
|
|
2222
|
+
});
|
|
2223
|
+
if (!auth.allowed) {
|
|
2224
|
+
logVerbose(`slack: drop ${eventKind} sender ${senderId ?? "unknown"} channel=${channelId ?? "unknown"} reason=${auth.reason ?? "unauthorized"}`);
|
|
2225
|
+
return;
|
|
2226
|
+
}
|
|
2227
|
+
return {
|
|
2228
|
+
channelLabel: resolveSlackChannelLabel({
|
|
2229
|
+
channelId,
|
|
2230
|
+
channelName: auth.channelName
|
|
2231
|
+
}),
|
|
2232
|
+
sessionKey: ctx.resolveSlackSystemEventSessionKey({
|
|
2233
|
+
channelId,
|
|
2234
|
+
channelType: auth.channelType,
|
|
2235
|
+
senderId
|
|
2236
|
+
})
|
|
2237
|
+
};
|
|
2238
|
+
}
|
|
2239
|
+
//#endregion
|
|
2240
|
+
//#region extensions/slack/src/monitor/events/members.ts
|
|
2241
|
+
function registerSlackMemberEvents(params) {
|
|
2242
|
+
const { ctx, trackEvent } = params;
|
|
2243
|
+
const handleMemberChannelEvent = async (paramsLocal) => {
|
|
2244
|
+
try {
|
|
2245
|
+
if (ctx.shouldDropMismatchedSlackEvent(paramsLocal.body)) return;
|
|
2246
|
+
trackEvent?.();
|
|
2247
|
+
const payload = paramsLocal.event;
|
|
2248
|
+
const channelId = payload.channel;
|
|
2249
|
+
const channelInfo = channelId ? await ctx.resolveChannelName(channelId) : {};
|
|
2250
|
+
const channelType = payload.channel_type ?? channelInfo?.type;
|
|
2251
|
+
const ingressContext = await authorizeAndResolveSlackSystemEventContext({
|
|
2252
|
+
ctx,
|
|
2253
|
+
senderId: payload.user,
|
|
2254
|
+
channelId,
|
|
2255
|
+
channelType,
|
|
2256
|
+
eventKind: `member-${paramsLocal.verb}`
|
|
2257
|
+
});
|
|
2258
|
+
if (!ingressContext) return;
|
|
2259
|
+
const userLabel = (payload.user ? await ctx.resolveUserName(payload.user) : {})?.name ?? payload.user ?? "someone";
|
|
2260
|
+
enqueueSystemEvent(`Slack: ${userLabel} ${paramsLocal.verb} ${ingressContext.channelLabel}.`, {
|
|
2261
|
+
sessionKey: ingressContext.sessionKey,
|
|
2262
|
+
contextKey: `slack:member:${paramsLocal.verb}:${channelId ?? "unknown"}:${payload.user ?? "unknown"}`
|
|
2263
|
+
});
|
|
2264
|
+
} catch (err) {
|
|
2265
|
+
ctx.runtime.error?.(danger(`slack ${paramsLocal.verb} handler failed: ${formatErrorMessage(err)}`));
|
|
2266
|
+
}
|
|
2267
|
+
};
|
|
2268
|
+
ctx.app.event("member_joined_channel", async ({ event, body }) => {
|
|
2269
|
+
await handleMemberChannelEvent({
|
|
2270
|
+
verb: "joined",
|
|
2271
|
+
event,
|
|
2272
|
+
body
|
|
2273
|
+
});
|
|
2274
|
+
});
|
|
2275
|
+
ctx.app.event("member_left_channel", async ({ event, body }) => {
|
|
2276
|
+
await handleMemberChannelEvent({
|
|
2277
|
+
verb: "left",
|
|
2278
|
+
event,
|
|
2279
|
+
body
|
|
2280
|
+
});
|
|
2281
|
+
});
|
|
2282
|
+
}
|
|
2283
|
+
//#endregion
|
|
2284
|
+
//#region extensions/slack/src/monitor/events/message-subtype-handlers.ts
|
|
2285
|
+
const SUBTYPE_HANDLER_REGISTRY = {
|
|
2286
|
+
message_changed: {
|
|
2287
|
+
subtype: "message_changed",
|
|
2288
|
+
eventKind: "message_changed",
|
|
2289
|
+
describe: (channelLabel) => `Slack message edited in ${channelLabel}.`,
|
|
2290
|
+
contextKey: (event) => {
|
|
2291
|
+
const changed = event;
|
|
2292
|
+
return `slack:message:changed:${changed.channel ?? "unknown"}:${changed.message?.ts ?? changed.previous_message?.ts ?? changed.event_ts ?? "unknown"}`;
|
|
2293
|
+
},
|
|
2294
|
+
resolveSenderId: (event) => {
|
|
2295
|
+
const changed = event;
|
|
2296
|
+
return changed.message?.user ?? changed.previous_message?.user ?? changed.message?.bot_id ?? changed.previous_message?.bot_id;
|
|
2297
|
+
},
|
|
2298
|
+
resolveChannelId: (event) => event.channel,
|
|
2299
|
+
resolveChannelType: () => void 0
|
|
2300
|
+
},
|
|
2301
|
+
message_deleted: {
|
|
2302
|
+
subtype: "message_deleted",
|
|
2303
|
+
eventKind: "message_deleted",
|
|
2304
|
+
describe: (channelLabel) => `Slack message deleted in ${channelLabel}.`,
|
|
2305
|
+
contextKey: (event) => {
|
|
2306
|
+
const deleted = event;
|
|
2307
|
+
return `slack:message:deleted:${deleted.channel ?? "unknown"}:${deleted.deleted_ts ?? deleted.event_ts ?? "unknown"}`;
|
|
2308
|
+
},
|
|
2309
|
+
resolveSenderId: (event) => {
|
|
2310
|
+
const deleted = event;
|
|
2311
|
+
return deleted.previous_message?.user ?? deleted.previous_message?.bot_id;
|
|
2312
|
+
},
|
|
2313
|
+
resolveChannelId: (event) => event.channel,
|
|
2314
|
+
resolveChannelType: () => void 0
|
|
2315
|
+
}
|
|
2316
|
+
};
|
|
2317
|
+
function resolveSlackMessageSubtypeHandler(event) {
|
|
2318
|
+
const subtype = event.subtype;
|
|
2319
|
+
if (subtype !== "message_changed" && subtype !== "message_deleted") return;
|
|
2320
|
+
return SUBTYPE_HANDLER_REGISTRY[subtype];
|
|
2321
|
+
}
|
|
2322
|
+
//#endregion
|
|
2323
|
+
//#region extensions/slack/src/monitor/events/messages.ts
|
|
2324
|
+
const slackInboundLog = createSubsystemLogger("gateway/channels/slack").child("inbound");
|
|
2325
|
+
function formatSlackInboundLogLine(params) {
|
|
2326
|
+
return `Inbound app_mention ${`slack:${params.workspaceId}:channel:${params.channelId}:user:${params.userId}`} -> bot:${params.botUserId} (${params.channelType}, ${params.bodyChars} chars)`;
|
|
2327
|
+
}
|
|
2328
|
+
function isSlackUserId(value) {
|
|
2329
|
+
return /^[UW][A-Z0-9]+$/.test(value);
|
|
2330
|
+
}
|
|
2331
|
+
function addUserCandidate(candidates, value, botUserId) {
|
|
2332
|
+
const id = normalizeOptionalString(value);
|
|
2333
|
+
if (!id || id === botUserId || !isSlackUserId(id)) return;
|
|
2334
|
+
candidates.add(id);
|
|
2335
|
+
}
|
|
2336
|
+
function collectMetadataUserCandidates(candidates, value, botUserId) {
|
|
2337
|
+
const metadata = asOptionalRecord(value);
|
|
2338
|
+
const payload = asOptionalRecord(metadata?.event_payload);
|
|
2339
|
+
if (!payload) return;
|
|
2340
|
+
for (const key of [
|
|
2341
|
+
"user",
|
|
2342
|
+
"user_id",
|
|
2343
|
+
"actor_user_id",
|
|
2344
|
+
"author_user_id",
|
|
2345
|
+
"slack_user_id"
|
|
2346
|
+
]) addUserCandidate(candidates, payload[key], botUserId);
|
|
2347
|
+
}
|
|
2348
|
+
function resolveAssistantMessageChangedSender(params) {
|
|
2349
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
2350
|
+
collectMetadataUserCandidates(candidates, params.message?.metadata, params.botUserId);
|
|
2351
|
+
return candidates.size === 1 ? [...candidates][0] : void 0;
|
|
2352
|
+
}
|
|
2353
|
+
function isSelfAttributedMessageChange(params) {
|
|
2354
|
+
const topUser = normalizeOptionalString(params.event.user);
|
|
2355
|
+
const messageUser = normalizeOptionalString(params.message?.user);
|
|
2356
|
+
const messageBotId = normalizeOptionalString(params.message?.bot_id);
|
|
2357
|
+
return Boolean(params.ctx.botUserId) && (topUser === params.ctx.botUserId || messageUser === params.ctx.botUserId) || Boolean(params.ctx.botId) && messageBotId === params.ctx.botId;
|
|
2358
|
+
}
|
|
2359
|
+
function resolveAssistantMessageChangedInbound(params) {
|
|
2360
|
+
if (params.event.subtype !== "message_changed") return;
|
|
2361
|
+
const changed = params.event;
|
|
2362
|
+
const message = asOptionalRecord(changed.message);
|
|
2363
|
+
if (!message || !isSelfAttributedMessageChange({
|
|
2364
|
+
event: changed,
|
|
2365
|
+
message,
|
|
2366
|
+
ctx: params.ctx
|
|
2367
|
+
})) return;
|
|
2368
|
+
if (normalizeSlackChannelType(normalizeOptionalString(changed.channel_type), changed.channel) !== "im") return;
|
|
2369
|
+
const senderId = resolveAssistantMessageChangedSender({
|
|
2370
|
+
message,
|
|
2371
|
+
botUserId: params.ctx.botUserId
|
|
2372
|
+
});
|
|
2373
|
+
if (!senderId) {
|
|
2374
|
+
if (shouldLogVerbose()) logVerbose(`slack: assistant_app_thread message_changed in DM channel=${changed.channel} dropped: no sender resolved from metadata`);
|
|
2375
|
+
return;
|
|
2376
|
+
}
|
|
2377
|
+
return {
|
|
2378
|
+
type: "message",
|
|
2379
|
+
channel: changed.channel ?? params.event.channel,
|
|
2380
|
+
channel_type: "im",
|
|
2381
|
+
user: senderId,
|
|
2382
|
+
text: normalizeOptionalString(message.text),
|
|
2383
|
+
ts: normalizeOptionalString(message.ts) ?? normalizeOptionalString(changed.event_ts),
|
|
2384
|
+
thread_ts: normalizeOptionalString(message.thread_ts),
|
|
2385
|
+
event_ts: changed.event_ts,
|
|
2386
|
+
assistant_thread: asOptionalRecord(message.assistant_thread) ?? asOptionalRecord(changed.assistant_thread),
|
|
2387
|
+
files: Array.isArray(message.files) ? message.files : void 0,
|
|
2388
|
+
attachments: Array.isArray(message.attachments) ? message.attachments : void 0
|
|
2389
|
+
};
|
|
2390
|
+
}
|
|
2391
|
+
function registerSlackMessageEvents(params) {
|
|
2392
|
+
const { ctx, handleSlackMessage } = params;
|
|
2393
|
+
const handleIncomingMessageEvent = async ({ event, body }) => {
|
|
2394
|
+
try {
|
|
2395
|
+
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
|
|
2396
|
+
const message = event;
|
|
2397
|
+
const assistantChangedInbound = resolveAssistantMessageChangedInbound({
|
|
2398
|
+
event: message,
|
|
2399
|
+
ctx
|
|
2400
|
+
});
|
|
2401
|
+
if (assistantChangedInbound) {
|
|
2402
|
+
await handleSlackMessage(assistantChangedInbound, { source: "message" });
|
|
2403
|
+
return;
|
|
2404
|
+
}
|
|
2405
|
+
if (message.subtype === "message_changed" && isSelfAttributedMessageChange({
|
|
2406
|
+
event: message,
|
|
2407
|
+
message: asOptionalRecord(message.message),
|
|
2408
|
+
ctx
|
|
2409
|
+
})) return;
|
|
2410
|
+
const subtypeHandler = resolveSlackMessageSubtypeHandler(message);
|
|
2411
|
+
if (subtypeHandler) {
|
|
2412
|
+
const channelId = subtypeHandler.resolveChannelId(message);
|
|
2413
|
+
const ingressContext = await authorizeAndResolveSlackSystemEventContext({
|
|
2414
|
+
ctx,
|
|
2415
|
+
senderId: subtypeHandler.resolveSenderId(message),
|
|
2416
|
+
channelId,
|
|
2417
|
+
channelType: subtypeHandler.resolveChannelType(message),
|
|
2418
|
+
eventKind: subtypeHandler.eventKind
|
|
2419
|
+
});
|
|
2420
|
+
if (!ingressContext) return;
|
|
2421
|
+
enqueueSystemEvent(subtypeHandler.describe(ingressContext.channelLabel), {
|
|
2422
|
+
sessionKey: ingressContext.sessionKey,
|
|
2423
|
+
contextKey: subtypeHandler.contextKey(message)
|
|
2424
|
+
});
|
|
2425
|
+
return;
|
|
2426
|
+
}
|
|
2427
|
+
await handleSlackMessage(message, { source: "message" });
|
|
2428
|
+
} catch (err) {
|
|
2429
|
+
ctx.runtime.error?.(danger(`slack handler failed: ${formatErrorMessage(err)}`));
|
|
2430
|
+
}
|
|
2431
|
+
};
|
|
2432
|
+
ctx.app.event("message", async ({ event, body }) => {
|
|
2433
|
+
await handleIncomingMessageEvent({
|
|
2434
|
+
event,
|
|
2435
|
+
body
|
|
2436
|
+
});
|
|
2437
|
+
});
|
|
2438
|
+
ctx.app.event("app_mention", async ({ event, body }) => {
|
|
2439
|
+
try {
|
|
2440
|
+
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
|
|
2441
|
+
const mention = event;
|
|
2442
|
+
const channelType = normalizeSlackChannelType(mention.channel_type, mention.channel);
|
|
2443
|
+
if (channelType === "im" || channelType === "mpim") return;
|
|
2444
|
+
slackInboundLog.info(formatSlackInboundLogLine({
|
|
2445
|
+
workspaceId: ctx.teamId,
|
|
2446
|
+
channelId: mention.channel,
|
|
2447
|
+
channelType: channelType ?? "channel",
|
|
2448
|
+
userId: normalizeOptionalString(mention.user) ?? "unknown",
|
|
2449
|
+
botUserId: ctx.botUserId,
|
|
2450
|
+
bodyChars: normalizeOptionalString(mention.text)?.length ?? 0
|
|
2451
|
+
}));
|
|
2452
|
+
await handleSlackMessage(mention, {
|
|
2453
|
+
source: "app_mention",
|
|
2454
|
+
wasMentioned: true
|
|
2455
|
+
});
|
|
2456
|
+
} catch (err) {
|
|
2457
|
+
ctx.runtime.error?.(danger(`slack mention handler failed: ${formatErrorMessage(err)}`));
|
|
2458
|
+
}
|
|
2459
|
+
});
|
|
2460
|
+
}
|
|
2461
|
+
//#endregion
|
|
2462
|
+
//#region extensions/slack/src/monitor/events/pins.ts
|
|
2463
|
+
async function handleSlackPinEvent(params) {
|
|
2464
|
+
const { ctx, trackEvent, body, event, action, contextKeySuffix, errorLabel } = params;
|
|
2465
|
+
try {
|
|
2466
|
+
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
|
|
2467
|
+
trackEvent?.();
|
|
2468
|
+
const payload = event;
|
|
2469
|
+
const channelId = payload.channel_id;
|
|
2470
|
+
const ingressContext = await authorizeAndResolveSlackSystemEventContext({
|
|
2471
|
+
ctx,
|
|
2472
|
+
senderId: payload.user,
|
|
2473
|
+
channelId,
|
|
2474
|
+
eventKind: "pin"
|
|
2475
|
+
});
|
|
2476
|
+
if (!ingressContext) return;
|
|
2477
|
+
const userLabel = (payload.user ? await ctx.resolveUserName(payload.user) : {})?.name ?? payload.user ?? "someone";
|
|
2478
|
+
const itemType = payload.item?.type ?? "item";
|
|
2479
|
+
const messageId = payload.item?.message?.ts ?? payload.event_ts;
|
|
2480
|
+
enqueueSystemEvent(`Slack: ${userLabel} ${action} a ${itemType} in ${ingressContext.channelLabel}.`, {
|
|
2481
|
+
sessionKey: ingressContext.sessionKey,
|
|
2482
|
+
contextKey: `slack:pin:${contextKeySuffix}:${channelId ?? "unknown"}:${messageId ?? "unknown"}`
|
|
2483
|
+
});
|
|
2484
|
+
} catch (err) {
|
|
2485
|
+
ctx.runtime.error?.(danger(`slack ${errorLabel} handler failed: ${formatErrorMessage(err)}`));
|
|
2486
|
+
}
|
|
2487
|
+
}
|
|
2488
|
+
function registerSlackPinEvents(params) {
|
|
2489
|
+
const { ctx, trackEvent } = params;
|
|
2490
|
+
ctx.app.event("pin_added", async ({ event, body }) => {
|
|
2491
|
+
await handleSlackPinEvent({
|
|
2492
|
+
ctx,
|
|
2493
|
+
trackEvent,
|
|
2494
|
+
body,
|
|
2495
|
+
event,
|
|
2496
|
+
action: "pinned",
|
|
2497
|
+
contextKeySuffix: "added",
|
|
2498
|
+
errorLabel: "pin added"
|
|
2499
|
+
});
|
|
2500
|
+
});
|
|
2501
|
+
ctx.app.event("pin_removed", async ({ event, body }) => {
|
|
2502
|
+
await handleSlackPinEvent({
|
|
2503
|
+
ctx,
|
|
2504
|
+
trackEvent,
|
|
2505
|
+
body,
|
|
2506
|
+
event,
|
|
2507
|
+
action: "unpinned",
|
|
2508
|
+
contextKeySuffix: "removed",
|
|
2509
|
+
errorLabel: "pin removed"
|
|
2510
|
+
});
|
|
2511
|
+
});
|
|
2512
|
+
}
|
|
2513
|
+
//#endregion
|
|
2514
|
+
//#region extensions/slack/src/monitor/events/reactions.ts
|
|
2515
|
+
function shouldEmitSlackReactionNotification(params) {
|
|
2516
|
+
const { ctx, event, actorName } = params;
|
|
2517
|
+
if (ctx.reactionMode === "off") return false;
|
|
2518
|
+
if (ctx.reactionMode === "own") return Boolean(ctx.botUserId && event.item_user === ctx.botUserId);
|
|
2519
|
+
if (ctx.reactionMode === "allowlist") {
|
|
2520
|
+
const allowList = normalizeAllowListLower(ctx.reactionAllowlist);
|
|
2521
|
+
if (allowList.length === 0) return false;
|
|
2522
|
+
return allowListMatches({
|
|
2523
|
+
allowList,
|
|
2524
|
+
id: event.user,
|
|
2525
|
+
name: actorName,
|
|
2526
|
+
allowNameMatching: ctx.allowNameMatching
|
|
2527
|
+
});
|
|
2528
|
+
}
|
|
2529
|
+
return ctx.reactionMode === "all";
|
|
2530
|
+
}
|
|
2531
|
+
function registerSlackReactionEvents(params) {
|
|
2532
|
+
const { ctx, trackEvent } = params;
|
|
2533
|
+
const handleReactionEvent = async (event, action) => {
|
|
2534
|
+
try {
|
|
2535
|
+
const item = event.item;
|
|
2536
|
+
if (!item || item.type !== "message") return;
|
|
2537
|
+
if (ctx.reactionMode === "off") return;
|
|
2538
|
+
if (ctx.reactionMode === "own" && (!ctx.botUserId || event.item_user !== ctx.botUserId)) return;
|
|
2539
|
+
trackEvent?.();
|
|
2540
|
+
const ingressContext = await authorizeAndResolveSlackSystemEventContext({
|
|
2541
|
+
ctx,
|
|
2542
|
+
senderId: event.user,
|
|
2543
|
+
channelId: item.channel,
|
|
2544
|
+
eventKind: "reaction"
|
|
2545
|
+
});
|
|
2546
|
+
if (!ingressContext) return;
|
|
2547
|
+
const actorInfoPromise = event.user ? ctx.resolveUserName(event.user) : Promise.resolve(void 0);
|
|
2548
|
+
const authorInfoPromise = event.item_user ? ctx.resolveUserName(event.item_user) : Promise.resolve(void 0);
|
|
2549
|
+
const [actorInfo, authorInfo] = await Promise.all([actorInfoPromise, authorInfoPromise]);
|
|
2550
|
+
if (!shouldEmitSlackReactionNotification({
|
|
2551
|
+
ctx,
|
|
2552
|
+
event,
|
|
2553
|
+
actorName: actorInfo?.name
|
|
2554
|
+
})) return;
|
|
2555
|
+
const actorLabel = actorInfo?.name ?? event.user;
|
|
2556
|
+
const emojiLabel = event.reaction ?? "emoji";
|
|
2557
|
+
const authorLabel = authorInfo?.name ?? event.item_user;
|
|
2558
|
+
const baseText = `Slack reaction ${action}: :${emojiLabel}: by ${actorLabel} in ${ingressContext.channelLabel} msg ${item.ts}`;
|
|
2559
|
+
const text = authorLabel ? `${baseText} from ${authorLabel}` : baseText;
|
|
2560
|
+
enqueueSystemEvent(text, {
|
|
2561
|
+
sessionKey: ingressContext.sessionKey,
|
|
2562
|
+
contextKey: `slack:reaction:${action}:${item.channel}:${item.ts}:${event.user}:${emojiLabel}`
|
|
2563
|
+
});
|
|
2564
|
+
} catch (err) {
|
|
2565
|
+
ctx.runtime.error?.(danger(`slack reaction handler failed: ${formatErrorMessage(err)}`));
|
|
2566
|
+
}
|
|
2567
|
+
};
|
|
2568
|
+
ctx.app.event("reaction_added", async ({ event, body }) => {
|
|
2569
|
+
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
|
|
2570
|
+
await handleReactionEvent(event, "added");
|
|
2571
|
+
});
|
|
2572
|
+
ctx.app.event("reaction_removed", async ({ event, body }) => {
|
|
2573
|
+
if (ctx.shouldDropMismatchedSlackEvent(body)) return;
|
|
2574
|
+
await handleReactionEvent(event, "removed");
|
|
2575
|
+
});
|
|
2576
|
+
}
|
|
2577
|
+
//#endregion
|
|
2578
|
+
//#region extensions/slack/src/monitor/events.ts
|
|
2579
|
+
function registerSlackMonitorEvents(params) {
|
|
2580
|
+
registerSlackMessageEvents({
|
|
2581
|
+
ctx: params.ctx,
|
|
2582
|
+
handleSlackMessage: params.handleSlackMessage
|
|
2583
|
+
});
|
|
2584
|
+
registerSlackReactionEvents({
|
|
2585
|
+
ctx: params.ctx,
|
|
2586
|
+
trackEvent: params.trackEvent
|
|
2587
|
+
});
|
|
2588
|
+
registerSlackMemberEvents({
|
|
2589
|
+
ctx: params.ctx,
|
|
2590
|
+
trackEvent: params.trackEvent
|
|
2591
|
+
});
|
|
2592
|
+
registerSlackChannelEvents({
|
|
2593
|
+
ctx: params.ctx,
|
|
2594
|
+
trackEvent: params.trackEvent
|
|
2595
|
+
});
|
|
2596
|
+
registerSlackPinEvents({
|
|
2597
|
+
ctx: params.ctx,
|
|
2598
|
+
trackEvent: params.trackEvent
|
|
2599
|
+
});
|
|
2600
|
+
registerSlackHomeEvents({
|
|
2601
|
+
ctx: params.ctx,
|
|
2602
|
+
trackEvent: params.trackEvent
|
|
2603
|
+
});
|
|
2604
|
+
registerSlackInteractionEvents({
|
|
2605
|
+
ctx: params.ctx,
|
|
2606
|
+
trackEvent: params.trackEvent
|
|
2607
|
+
});
|
|
2608
|
+
registerSlackAssistantEvents({
|
|
2609
|
+
ctx: params.ctx,
|
|
2610
|
+
trackEvent: params.trackEvent
|
|
2611
|
+
});
|
|
2612
|
+
}
|
|
2613
|
+
//#endregion
|
|
2614
|
+
//#region extensions/slack/src/monitor/inbound-delivery-state.ts
|
|
2615
|
+
const deliveredMessages = createPersistentDedupeCache({
|
|
2616
|
+
globalKey: Symbol.for("openclaw.slackInboundDeliveries"),
|
|
2617
|
+
ttlMs: 864e5,
|
|
2618
|
+
maxSize: 2e4,
|
|
2619
|
+
persistent: {
|
|
2620
|
+
namespace: "slack.inbound-deliveries",
|
|
2621
|
+
maxEntries: 2e4,
|
|
2622
|
+
openStore: (options) => getOptionalSlackRuntime()?.state.openKeyedStore(options),
|
|
2623
|
+
logError: (error) => {
|
|
2624
|
+
try {
|
|
2625
|
+
getOptionalSlackRuntime()?.logging.getChildLogger({
|
|
2626
|
+
plugin: "slack",
|
|
2627
|
+
feature: "inbound-delivery-state"
|
|
2628
|
+
}).warn("Slack persistent inbound delivery state failed", { error: String(error) });
|
|
2629
|
+
} catch {}
|
|
2630
|
+
}
|
|
2631
|
+
}
|
|
2632
|
+
});
|
|
2633
|
+
function makeKey(accountId, channelId, ts) {
|
|
2634
|
+
return `${accountId}:${channelId}:${ts}`;
|
|
2635
|
+
}
|
|
2636
|
+
async function hasSlackInboundMessageDelivery(params) {
|
|
2637
|
+
if (!params.accountId || !params.channelId || !params.ts) return false;
|
|
2638
|
+
return await deliveredMessages.lookup(makeKey(params.accountId, params.channelId, params.ts));
|
|
2639
|
+
}
|
|
2640
|
+
async function recordSlackInboundMessageDeliveries(params) {
|
|
2641
|
+
if (!params.accountId || params.messages.length === 0) return;
|
|
2642
|
+
const deliveredAt = Date.now();
|
|
2643
|
+
const keys = /* @__PURE__ */ new Set();
|
|
2644
|
+
for (const message of params.messages) {
|
|
2645
|
+
if (!message.channel || !message.ts) continue;
|
|
2646
|
+
keys.add(makeKey(params.accountId, message.channel, message.ts));
|
|
2647
|
+
}
|
|
2648
|
+
await Promise.all(Array.from(keys, (key) => deliveredMessages.register(key, { deliveredAt }, { at: deliveredAt })));
|
|
2649
|
+
}
|
|
2650
|
+
//#endregion
|
|
2651
|
+
//#region extensions/slack/src/monitor/message-handler/debounce-key.ts
|
|
2652
|
+
function resolveSlackSenderId(message) {
|
|
2653
|
+
return message.user ?? message.bot_id ?? null;
|
|
2654
|
+
}
|
|
2655
|
+
function isSlackDirectMessageChannel(channelId) {
|
|
2656
|
+
return channelId.startsWith("D");
|
|
2657
|
+
}
|
|
2658
|
+
function isTopLevelSlackMessage(message) {
|
|
2659
|
+
return !message.thread_ts && !message.parent_user_id;
|
|
2660
|
+
}
|
|
2661
|
+
function buildTopLevelSlackConversationKey(message, accountId) {
|
|
2662
|
+
if (!isTopLevelSlackMessage(message)) return null;
|
|
2663
|
+
const senderId = resolveSlackSenderId(message);
|
|
2664
|
+
if (!senderId) return null;
|
|
2665
|
+
return `slack:${accountId}:${message.channel}:${senderId}`;
|
|
2666
|
+
}
|
|
2667
|
+
function buildSlackDebounceKey(message, accountId) {
|
|
2668
|
+
const senderId = resolveSlackSenderId(message);
|
|
2669
|
+
if (!senderId) return null;
|
|
2670
|
+
const messageTs = message.ts ?? message.event_ts;
|
|
2671
|
+
return `slack:${accountId}:${message.thread_ts ? `${message.channel}:${message.thread_ts}` : message.parent_user_id && messageTs ? `${message.channel}:maybe-thread:${messageTs}` : messageTs && !isSlackDirectMessageChannel(message.channel) ? `${message.channel}:${messageTs}` : message.channel}:${senderId}`;
|
|
2672
|
+
}
|
|
2673
|
+
//#endregion
|
|
2674
|
+
//#region extensions/slack/src/monitor/thread-resolution.ts
|
|
2675
|
+
const DEFAULT_THREAD_TS_CACHE_TTL_MS = 6e4;
|
|
2676
|
+
const DEFAULT_THREAD_TS_CACHE_MAX = 500;
|
|
2677
|
+
const normalizeThreadTs = (threadTs) => {
|
|
2678
|
+
const trimmed = threadTs?.trim();
|
|
2679
|
+
return trimmed ? trimmed : void 0;
|
|
2680
|
+
};
|
|
2681
|
+
const markAmbiguousThreadReply = (message) => ({
|
|
2682
|
+
...message,
|
|
2683
|
+
_ambiguousThreadReply: true
|
|
2684
|
+
});
|
|
2685
|
+
async function resolveThreadTsFromHistory(params) {
|
|
2686
|
+
try {
|
|
2687
|
+
const response = await params.client.conversations.history({
|
|
2688
|
+
channel: params.channelId,
|
|
2689
|
+
latest: params.messageTs,
|
|
2690
|
+
oldest: params.messageTs,
|
|
2691
|
+
inclusive: true,
|
|
2692
|
+
limit: 1
|
|
2693
|
+
});
|
|
2694
|
+
const message = response.messages?.find((entry) => entry.ts === params.messageTs) ?? response.messages?.[0];
|
|
2695
|
+
return normalizeThreadTs(message?.thread_ts);
|
|
2696
|
+
} catch (err) {
|
|
2697
|
+
if (shouldLogVerbose()) logVerbose(`slack inbound: failed to resolve thread_ts via conversations.history for channel=${params.channelId} ts=${params.messageTs}: ${formatSlackError(err)}`);
|
|
2698
|
+
return;
|
|
2699
|
+
}
|
|
2700
|
+
}
|
|
2701
|
+
function createSlackThreadTsResolver(params) {
|
|
2702
|
+
const ttlMs = Math.max(0, parseFiniteNumber(params.cacheTtlMs) ?? DEFAULT_THREAD_TS_CACHE_TTL_MS);
|
|
2703
|
+
const maxSize = Math.max(0, parseFiniteNumber(params.maxSize) ?? DEFAULT_THREAD_TS_CACHE_MAX);
|
|
2704
|
+
const cache = /* @__PURE__ */ new Map();
|
|
2705
|
+
const inflight = /* @__PURE__ */ new Map();
|
|
2706
|
+
const getCached = (key, now) => {
|
|
2707
|
+
const entry = cache.get(key);
|
|
2708
|
+
if (!entry) return;
|
|
2709
|
+
if (entry.expiresAt === 0) {
|
|
2710
|
+
cache.delete(key);
|
|
2711
|
+
cache.set(key, entry);
|
|
2712
|
+
return entry.threadTs;
|
|
2713
|
+
}
|
|
2714
|
+
const normalizedNow = asDateTimestampMs(now);
|
|
2715
|
+
if (normalizedNow === void 0 || asDateTimestampMs(entry.expiresAt) === void 0 || entry.expiresAt <= normalizedNow) {
|
|
2716
|
+
cache.delete(key);
|
|
2717
|
+
return;
|
|
2718
|
+
}
|
|
2719
|
+
cache.delete(key);
|
|
2720
|
+
cache.set(key, entry);
|
|
2721
|
+
return entry.threadTs;
|
|
2722
|
+
};
|
|
2723
|
+
const setCached = (key, threadTs, now) => {
|
|
2724
|
+
const expiresAt = ttlMs > 0 ? resolveExpiresAtMsFromDurationMs(ttlMs, { nowMs: now }) : 0;
|
|
2725
|
+
if (expiresAt === void 0) {
|
|
2726
|
+
cache.delete(key);
|
|
2727
|
+
return;
|
|
2728
|
+
}
|
|
2729
|
+
cache.delete(key);
|
|
2730
|
+
cache.set(key, {
|
|
2731
|
+
threadTs,
|
|
2732
|
+
expiresAt
|
|
2733
|
+
});
|
|
2734
|
+
pruneMapToMaxSize(cache, maxSize);
|
|
2735
|
+
};
|
|
2736
|
+
return { resolve: async (request) => {
|
|
2737
|
+
const { message } = request;
|
|
2738
|
+
if (!message.parent_user_id || message.thread_ts || !message.ts) return message;
|
|
2739
|
+
const cacheKey = `${message.channel}:${message.ts}`;
|
|
2740
|
+
const cached = getCached(cacheKey, Date.now());
|
|
2741
|
+
if (cached !== void 0) return cached ? {
|
|
2742
|
+
...message,
|
|
2743
|
+
thread_ts: cached
|
|
2744
|
+
} : markAmbiguousThreadReply(message);
|
|
2745
|
+
if (shouldLogVerbose()) logVerbose(`slack inbound: missing thread_ts for thread reply channel=${message.channel} ts=${message.ts} source=${request.source}`);
|
|
2746
|
+
let pending = inflight.get(cacheKey);
|
|
2747
|
+
if (!pending) {
|
|
2748
|
+
pending = resolveThreadTsFromHistory({
|
|
2749
|
+
client: params.client,
|
|
2750
|
+
channelId: message.channel,
|
|
2751
|
+
messageTs: message.ts
|
|
2752
|
+
});
|
|
2753
|
+
inflight.set(cacheKey, pending);
|
|
2754
|
+
}
|
|
2755
|
+
let resolved;
|
|
2756
|
+
try {
|
|
2757
|
+
resolved = await pending;
|
|
2758
|
+
} finally {
|
|
2759
|
+
inflight.delete(cacheKey);
|
|
2760
|
+
}
|
|
2761
|
+
setCached(cacheKey, resolved ?? null, Date.now());
|
|
2762
|
+
if (resolved) {
|
|
2763
|
+
if (shouldLogVerbose()) logVerbose(`slack inbound: resolved missing thread_ts channel=${message.channel} ts=${message.ts} -> thread_ts=${resolved}`);
|
|
2764
|
+
return {
|
|
2765
|
+
...message,
|
|
2766
|
+
thread_ts: resolved
|
|
2767
|
+
};
|
|
2768
|
+
}
|
|
2769
|
+
if (shouldLogVerbose()) logVerbose(`slack inbound: could not resolve missing thread_ts channel=${message.channel} ts=${message.ts}; marking reply ambiguous`);
|
|
2770
|
+
return markAmbiguousThreadReply(message);
|
|
2771
|
+
} };
|
|
2772
|
+
}
|
|
2773
|
+
//#endregion
|
|
2774
|
+
//#region extensions/slack/src/monitor/message-handler.ts
|
|
2775
|
+
const loadSlackMessagePipeline = createLazyRuntimeModule(() => import("./pipeline.runtime-qFsXbTJf.mjs"));
|
|
2776
|
+
function createSlackDispatchCompletion() {
|
|
2777
|
+
let resolve;
|
|
2778
|
+
let reject;
|
|
2779
|
+
return {
|
|
2780
|
+
promise: new Promise((nextResolve, nextReject) => {
|
|
2781
|
+
resolve = nextResolve;
|
|
2782
|
+
reject = nextReject;
|
|
2783
|
+
}),
|
|
2784
|
+
resolve,
|
|
2785
|
+
reject
|
|
2786
|
+
};
|
|
2787
|
+
}
|
|
2788
|
+
const APP_MENTION_RETRY_TTL_MS = 6e4;
|
|
2789
|
+
const RETRYABLE_FLUSH_MAX_ATTEMPTS = 3;
|
|
2790
|
+
const RETRYABLE_FLUSH_RETRY_DELAY_MS = 1e3;
|
|
2791
|
+
const REPLY_SESSION_INIT_CONFLICT_MESSAGE_RE = /reply session initialization conflicted for \S+/u;
|
|
2792
|
+
var SlackRetryableInboundError = class extends Error {
|
|
2793
|
+
constructor(message, options) {
|
|
2794
|
+
super(message, options);
|
|
2795
|
+
this.name = "SlackRetryableInboundError";
|
|
2796
|
+
}
|
|
2797
|
+
};
|
|
2798
|
+
function isRetryableSlackInboundError(error) {
|
|
2799
|
+
if (error instanceof SlackRetryableInboundError) return true;
|
|
2800
|
+
return collectErrorGraphCandidates(error, (current) => [current.cause, current.error]).some((candidate) => REPLY_SESSION_INIT_CONFLICT_MESSAGE_RE.test(formatErrorMessage(candidate)));
|
|
2801
|
+
}
|
|
2802
|
+
function shouldDebounceSlackMessage(message, cfg) {
|
|
2803
|
+
const textForCommandDetection = stripSlackMentionsForCommandDetection(message.text ?? "");
|
|
2804
|
+
return shouldDebounceTextInbound({
|
|
2805
|
+
text: textForCommandDetection,
|
|
2806
|
+
cfg,
|
|
2807
|
+
hasMedia: Boolean(message.files && message.files.length > 0)
|
|
2808
|
+
});
|
|
2809
|
+
}
|
|
2810
|
+
function buildSeenMessageKey(channelId, ts) {
|
|
2811
|
+
if (!channelId || !ts) return null;
|
|
2812
|
+
return `${channelId}:${ts}`;
|
|
2813
|
+
}
|
|
2814
|
+
function createSlackMessageHandler(params) {
|
|
2815
|
+
const { ctx, account, trackEvent } = params;
|
|
2816
|
+
const { debounceMs, debouncer } = createChannelInboundDebouncer({
|
|
2817
|
+
cfg: ctx.cfg,
|
|
2818
|
+
channel: "slack",
|
|
2819
|
+
buildKey: (entry) => buildSlackDebounceKey(entry.message, ctx.accountId),
|
|
2820
|
+
shouldDebounce: (entry) => shouldDebounceSlackMessage(entry.message, ctx.cfg),
|
|
2821
|
+
onFlush: async (entries) => {
|
|
2822
|
+
const retryEntries = (sourceError) => {
|
|
2823
|
+
if (!isRetryableSlackInboundError(sourceError)) return false;
|
|
2824
|
+
const nextEntries = entries.map((entry) => {
|
|
2825
|
+
if (entry.opts.dispatchCompletion) return null;
|
|
2826
|
+
const retryAttempt = entry.opts.retryAttempt ?? 0;
|
|
2827
|
+
if (retryAttempt >= RETRYABLE_FLUSH_MAX_ATTEMPTS) return null;
|
|
2828
|
+
const { dispatchCompletion: _dispatchCompletion, ...retryOpts } = entry.opts;
|
|
2829
|
+
return {
|
|
2830
|
+
...entry,
|
|
2831
|
+
opts: {
|
|
2832
|
+
...retryOpts,
|
|
2833
|
+
retryAttempt: retryAttempt + 1
|
|
2834
|
+
}
|
|
2835
|
+
};
|
|
2836
|
+
}).filter((entry) => entry !== null);
|
|
2837
|
+
if (nextEntries.length === 0) return false;
|
|
2838
|
+
setTimeout(() => {
|
|
2839
|
+
for (const entry of nextEntries) enqueueSlackMessage(entry.message, entry.opts).catch((err) => {
|
|
2840
|
+
ctx.runtime.error?.(`slack inbound retry enqueue failed: ${formatErrorMessage(err)}`);
|
|
2841
|
+
});
|
|
2842
|
+
}, RETRYABLE_FLUSH_RETRY_DELAY_MS).unref?.();
|
|
2843
|
+
return true;
|
|
2844
|
+
};
|
|
2845
|
+
const completions = entries.map((entry) => entry.opts.dispatchCompletion).filter((completion) => completion !== void 0);
|
|
2846
|
+
try {
|
|
2847
|
+
await (async () => {
|
|
2848
|
+
const last = entries.at(-1);
|
|
2849
|
+
if (!last) return;
|
|
2850
|
+
const flushedKey = buildSlackDebounceKey(last.message, ctx.accountId);
|
|
2851
|
+
const topLevelConversationKey = buildTopLevelSlackConversationKey(last.message, ctx.accountId);
|
|
2852
|
+
if (flushedKey && topLevelConversationKey) {
|
|
2853
|
+
const pendingKeys = pendingTopLevelDebounceKeys.get(topLevelConversationKey);
|
|
2854
|
+
if (pendingKeys) {
|
|
2855
|
+
pendingKeys.delete(flushedKey);
|
|
2856
|
+
if (pendingKeys.size === 0) pendingTopLevelDebounceKeys.delete(topLevelConversationKey);
|
|
2857
|
+
}
|
|
2858
|
+
}
|
|
2859
|
+
const combinedText = entries.length === 1 ? last.message.text ?? "" : entries.map((entry) => entry.message.text ?? "").filter(Boolean).join("\n");
|
|
2860
|
+
const combinedMentioned = entries.some((entry) => Boolean(entry.opts.wasMentioned));
|
|
2861
|
+
const syntheticMessage = {
|
|
2862
|
+
...last.message,
|
|
2863
|
+
text: combinedText
|
|
2864
|
+
};
|
|
2865
|
+
const seenMessageKey = buildSeenMessageKey(last.message.channel, last.message.ts);
|
|
2866
|
+
try {
|
|
2867
|
+
const { prepareSlackMessage, dispatchPreparedSlackMessage } = await loadSlackMessagePipeline();
|
|
2868
|
+
const { dispatchCompletion: _completion, awaitDispatch: _awaitDispatch, ...lastOpts } = last.opts;
|
|
2869
|
+
const appMentionRetryKey = seenMessageKey && lastOpts.source === "app_mention" && !ctx.botUserId ? seenMessageKey : void 0;
|
|
2870
|
+
if (appMentionRetryKey) appMentionPreparingKeys.add(appMentionRetryKey);
|
|
2871
|
+
const prepared = await (async () => {
|
|
2872
|
+
try {
|
|
2873
|
+
const result = await prepareSlackMessage({
|
|
2874
|
+
ctx,
|
|
2875
|
+
account,
|
|
2876
|
+
message: syntheticMessage,
|
|
2877
|
+
opts: {
|
|
2878
|
+
...lastOpts,
|
|
2879
|
+
wasMentioned: combinedMentioned || last.opts.wasMentioned,
|
|
2880
|
+
...seenMessageKey && lastOpts.source === "message" ? { shouldRecordDroppedHistory: () => !appMentionPreparingKeys.has(seenMessageKey) && !appMentionDispatchedKeys.has(seenMessageKey) } : {}
|
|
2881
|
+
}
|
|
2882
|
+
});
|
|
2883
|
+
if (result && seenMessageKey) {
|
|
2884
|
+
pruneAppMentionRetryKeys(Date.now());
|
|
2885
|
+
if (last.opts.source === "app_mention") rememberExpiringAppMentionKey(appMentionDispatchedKeys, seenMessageKey);
|
|
2886
|
+
else if (last.opts.source === "message" && appMentionDispatchedKeys.has(seenMessageKey)) {
|
|
2887
|
+
appMentionDispatchedKeys.delete(seenMessageKey);
|
|
2888
|
+
appMentionRetryKeys.delete(seenMessageKey);
|
|
2889
|
+
return null;
|
|
2890
|
+
}
|
|
2891
|
+
appMentionRetryKeys.delete(seenMessageKey);
|
|
2892
|
+
}
|
|
2893
|
+
return result;
|
|
2894
|
+
} finally {
|
|
2895
|
+
if (appMentionRetryKey) appMentionPreparingKeys.delete(appMentionRetryKey);
|
|
2896
|
+
}
|
|
2897
|
+
})();
|
|
2898
|
+
if (!prepared) return;
|
|
2899
|
+
if (entries.length > 1) {
|
|
2900
|
+
const ids = entries.map((entry) => entry.message.ts).filter(Boolean);
|
|
2901
|
+
if (ids.length > 0) {
|
|
2902
|
+
prepared.ctxPayload.MessageSids = ids;
|
|
2903
|
+
prepared.ctxPayload.MessageSidFirst = ids[0];
|
|
2904
|
+
prepared.ctxPayload.MessageSidLast = ids[ids.length - 1];
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
try {
|
|
2908
|
+
await dispatchPreparedSlackMessage(prepared);
|
|
2909
|
+
await recordSlackInboundMessageDeliveries({
|
|
2910
|
+
accountId: ctx.accountId,
|
|
2911
|
+
messages: entries.map((entry) => entry.message)
|
|
2912
|
+
});
|
|
2913
|
+
} catch (error) {
|
|
2914
|
+
if (!isRetryableSlackInboundError(error)) await recordSlackInboundMessageDeliveries({
|
|
2915
|
+
accountId: ctx.accountId,
|
|
2916
|
+
messages: entries.map((entry) => entry.message)
|
|
2917
|
+
});
|
|
2918
|
+
throw error;
|
|
2919
|
+
}
|
|
2920
|
+
} catch (error) {
|
|
2921
|
+
if (isRetryableSlackInboundError(error)) for (const entry of entries) {
|
|
2922
|
+
const entrySeenKey = buildSeenMessageKey(entry.message.channel, entry.message.ts);
|
|
2923
|
+
if (entrySeenKey) appMentionDispatchedKeys.delete(entrySeenKey);
|
|
2924
|
+
ctx.releaseSeenMessage(entry.message.channel, entry.message.ts);
|
|
2925
|
+
}
|
|
2926
|
+
throw error;
|
|
2927
|
+
}
|
|
2928
|
+
})();
|
|
2929
|
+
for (const completion of completions) completion.resolve();
|
|
2930
|
+
} catch (error) {
|
|
2931
|
+
retryEntries(error);
|
|
2932
|
+
for (const completion of completions) completion.reject(error);
|
|
2933
|
+
throw error;
|
|
2934
|
+
}
|
|
2935
|
+
},
|
|
2936
|
+
onError: (err) => {
|
|
2937
|
+
ctx.runtime.error?.(`slack inbound debounce flush failed: ${formatErrorMessage(err)}`);
|
|
2938
|
+
}
|
|
2939
|
+
});
|
|
2940
|
+
const threadTsResolver = createSlackThreadTsResolver({ client: ctx.app.client });
|
|
2941
|
+
const pendingTopLevelDebounceKeys = /* @__PURE__ */ new Map();
|
|
2942
|
+
const appMentionRetryKeys = /* @__PURE__ */ new Map();
|
|
2943
|
+
const appMentionPreparingKeys = /* @__PURE__ */ new Set();
|
|
2944
|
+
const appMentionDispatchedKeys = /* @__PURE__ */ new Map();
|
|
2945
|
+
const pruneAppMentionRetryKeys = (rawNow) => {
|
|
2946
|
+
const now = asDateTimestampMs(rawNow);
|
|
2947
|
+
if (now === void 0) {
|
|
2948
|
+
appMentionRetryKeys.clear();
|
|
2949
|
+
appMentionDispatchedKeys.clear();
|
|
2950
|
+
return false;
|
|
2951
|
+
}
|
|
2952
|
+
for (const [key, expiresAt] of appMentionRetryKeys) if (asDateTimestampMs(expiresAt) === void 0 || expiresAt <= now) appMentionRetryKeys.delete(key);
|
|
2953
|
+
for (const [key, expiresAt] of appMentionDispatchedKeys) if (asDateTimestampMs(expiresAt) === void 0 || expiresAt <= now) appMentionDispatchedKeys.delete(key);
|
|
2954
|
+
return true;
|
|
2955
|
+
};
|
|
2956
|
+
const rememberExpiringAppMentionKey = (map, key) => {
|
|
2957
|
+
const now = Date.now();
|
|
2958
|
+
if (!pruneAppMentionRetryKeys(now)) return;
|
|
2959
|
+
const expiresAt = resolveExpiresAtMsFromDurationMs(APP_MENTION_RETRY_TTL_MS, { nowMs: now });
|
|
2960
|
+
if (expiresAt !== void 0) map.set(key, expiresAt);
|
|
2961
|
+
};
|
|
2962
|
+
const rememberAppMentionRetryKey = (key) => {
|
|
2963
|
+
rememberExpiringAppMentionKey(appMentionRetryKeys, key);
|
|
2964
|
+
};
|
|
2965
|
+
const consumeAppMentionRetryKey = (key) => {
|
|
2966
|
+
if (!pruneAppMentionRetryKeys(Date.now())) return false;
|
|
2967
|
+
if (!appMentionRetryKeys.has(key)) return false;
|
|
2968
|
+
appMentionRetryKeys.delete(key);
|
|
2969
|
+
return true;
|
|
2970
|
+
};
|
|
2971
|
+
async function enqueueSlackMessage(message, opts) {
|
|
2972
|
+
if (opts.source === "message" && message.type !== "message") return;
|
|
2973
|
+
if (opts.source === "message" && message.subtype && message.subtype !== "file_share" && message.subtype !== "bot_message" && message.subtype !== "thread_broadcast") return;
|
|
2974
|
+
const seenMessageKey = buildSeenMessageKey(message.channel, message.ts);
|
|
2975
|
+
if (seenMessageKey && await hasSlackInboundMessageDelivery({
|
|
2976
|
+
accountId: ctx.accountId,
|
|
2977
|
+
channelId: message.channel,
|
|
2978
|
+
ts: message.ts
|
|
2979
|
+
})) return;
|
|
2980
|
+
const wasSeen = seenMessageKey ? ctx.markMessageSeen(message.channel, message.ts) : false;
|
|
2981
|
+
if (seenMessageKey && opts.source === "message" && !wasSeen) rememberAppMentionRetryKey(seenMessageKey);
|
|
2982
|
+
if (seenMessageKey && wasSeen) {
|
|
2983
|
+
if (opts.source !== "app_mention" || !consumeAppMentionRetryKey(seenMessageKey)) return;
|
|
2984
|
+
}
|
|
2985
|
+
trackEvent?.();
|
|
2986
|
+
const resolvedMessage = await threadTsResolver.resolve({
|
|
2987
|
+
message,
|
|
2988
|
+
source: opts.source
|
|
2989
|
+
});
|
|
2990
|
+
const debounceKey = buildSlackDebounceKey(resolvedMessage, ctx.accountId);
|
|
2991
|
+
const conversationKey = buildTopLevelSlackConversationKey(resolvedMessage, ctx.accountId);
|
|
2992
|
+
const canDebounce = debounceMs > 0 && shouldDebounceSlackMessage(resolvedMessage, ctx.cfg);
|
|
2993
|
+
if (!canDebounce && conversationKey) {
|
|
2994
|
+
const pendingKeys = pendingTopLevelDebounceKeys.get(conversationKey);
|
|
2995
|
+
if (pendingKeys && pendingKeys.size > 0) {
|
|
2996
|
+
const keysToFlush = Array.from(pendingKeys);
|
|
2997
|
+
for (const pendingKey of keysToFlush) await debouncer.flushKey(pendingKey);
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
if (canDebounce && debounceKey && conversationKey) {
|
|
3001
|
+
const pendingKeys = pendingTopLevelDebounceKeys.get(conversationKey) ?? /* @__PURE__ */ new Set();
|
|
3002
|
+
pendingKeys.add(debounceKey);
|
|
3003
|
+
pendingTopLevelDebounceKeys.set(conversationKey, pendingKeys);
|
|
3004
|
+
}
|
|
3005
|
+
const dispatchCompletion = opts.awaitDispatch ? createSlackDispatchCompletion() : void 0;
|
|
3006
|
+
await debouncer.enqueue({
|
|
3007
|
+
message: resolvedMessage,
|
|
3008
|
+
opts: {
|
|
3009
|
+
...opts,
|
|
3010
|
+
...dispatchCompletion ? { dispatchCompletion: {
|
|
3011
|
+
resolve: dispatchCompletion.resolve,
|
|
3012
|
+
reject: dispatchCompletion.reject
|
|
3013
|
+
} } : {}
|
|
3014
|
+
}
|
|
3015
|
+
});
|
|
3016
|
+
return dispatchCompletion;
|
|
3017
|
+
}
|
|
3018
|
+
return async (message, opts) => {
|
|
3019
|
+
await (await enqueueSlackMessage(message, opts))?.promise;
|
|
3020
|
+
};
|
|
3021
|
+
}
|
|
3022
|
+
//#endregion
|
|
3023
|
+
//#region extensions/slack/src/monitor/reconnect-policy.ts
|
|
3024
|
+
const SLACK_AUTH_ERROR_RE = /account_inactive|invalid_auth|token_revoked|token_expired|not_authed|org_login_required|team_access_not_granted|user_removed_from_team|team_disabled|missing_scope|cannot_find_service|invalid_token/i;
|
|
3025
|
+
const NO_ERROR_DETAIL = "no error detail";
|
|
3026
|
+
const SLACK_SOCKET_RECONNECT_POLICY = {
|
|
3027
|
+
initialMs: 2e3,
|
|
3028
|
+
maxMs: 3e4,
|
|
3029
|
+
factor: 1.8,
|
|
3030
|
+
jitter: .25
|
|
3031
|
+
};
|
|
3032
|
+
const SLACK_SOCKET_SHARED_CONNECTION_DOCS_URL = "https://docs.slack.dev/apis/events-api/using-socket-mode#using-multiple-connections";
|
|
3033
|
+
const SLACK_SOCKET_HELLO_MARKER = Buffer.from("\"hello\"");
|
|
3034
|
+
function getSocketEmitter(app) {
|
|
3035
|
+
const receiver = app.receiver;
|
|
3036
|
+
const client = receiver && typeof receiver === "object" ? receiver.client : void 0;
|
|
3037
|
+
if (!client || typeof client !== "object") return null;
|
|
3038
|
+
const on = client.on;
|
|
3039
|
+
const off = client.off;
|
|
3040
|
+
if (typeof on !== "function" || typeof off !== "function") return null;
|
|
3041
|
+
return {
|
|
3042
|
+
on: (event, listener) => on.call(client, event, listener),
|
|
3043
|
+
off: (event, listener) => off.call(client, event, listener)
|
|
3044
|
+
};
|
|
3045
|
+
}
|
|
3046
|
+
function isBufferArray(value) {
|
|
3047
|
+
return Array.isArray(value) && value.every((entry) => Buffer.isBuffer(entry));
|
|
3048
|
+
}
|
|
3049
|
+
function resolveSlackSocketModeConnectionCount(message) {
|
|
3050
|
+
const buffer = Buffer.isBuffer(message) ? message : message instanceof ArrayBuffer ? Buffer.from(message) : isBufferArray(message) ? Buffer.concat(message) : void 0;
|
|
3051
|
+
if (!buffer?.includes(SLACK_SOCKET_HELLO_MARKER)) return;
|
|
3052
|
+
let payload;
|
|
3053
|
+
try {
|
|
3054
|
+
payload = JSON.parse(buffer.toString("utf8"));
|
|
3055
|
+
} catch {
|
|
3056
|
+
return;
|
|
3057
|
+
}
|
|
3058
|
+
const count = isRecord(payload) && payload.type === "hello" ? payload.num_connections : void 0;
|
|
3059
|
+
return typeof count === "number" && Number.isSafeInteger(count) && count >= 0 ? count : void 0;
|
|
3060
|
+
}
|
|
3061
|
+
function formatSlackSocketModeSharedConnectionWarning(activeConnections) {
|
|
3062
|
+
return [
|
|
3063
|
+
`slack socket mode reports ${activeConnections} active connections for this Slack app`,
|
|
3064
|
+
"Slack may deliver each event to any one connection",
|
|
3065
|
+
"ensure every OpenClaw gateway sharing this app has equivalent routing and authorization, or use a separate Slack app per gateway, one relay ingress, or HTTP Request URLs behind a load balancer",
|
|
3066
|
+
`See ${SLACK_SOCKET_SHARED_CONNECTION_DOCS_URL}`
|
|
3067
|
+
].join("; ");
|
|
3068
|
+
}
|
|
3069
|
+
function registerSlackSocketModeConnectionDiagnostics(params) {
|
|
3070
|
+
const emitter = getSocketEmitter(params.app);
|
|
3071
|
+
if (!emitter) return () => {};
|
|
3072
|
+
let hasWarned = false;
|
|
3073
|
+
const listener = (message, isBinary) => {
|
|
3074
|
+
if (isBinary === true || hasWarned) return;
|
|
3075
|
+
const activeConnections = resolveSlackSocketModeConnectionCount(message);
|
|
3076
|
+
if (activeConnections === void 0 || activeConnections <= 1) return;
|
|
3077
|
+
hasWarned = true;
|
|
3078
|
+
params.onSharedConnection(activeConnections);
|
|
3079
|
+
};
|
|
3080
|
+
emitter.on("ws_message", listener);
|
|
3081
|
+
return () => {
|
|
3082
|
+
emitter.off("ws_message", listener);
|
|
3083
|
+
};
|
|
3084
|
+
}
|
|
3085
|
+
function waitForSlackSocketDisconnect(app, abortSignal) {
|
|
3086
|
+
return new Promise((resolve) => {
|
|
3087
|
+
const emitter = getSocketEmitter(app);
|
|
3088
|
+
if (!emitter) {
|
|
3089
|
+
abortSignal?.addEventListener("abort", () => resolve({ event: "disconnect" }), { once: true });
|
|
3090
|
+
return;
|
|
3091
|
+
}
|
|
3092
|
+
const disconnectListener = () => resolveOnce({ event: "disconnect" });
|
|
3093
|
+
const startFailListener = (error) => resolveOnce({
|
|
3094
|
+
event: "unable_to_socket_mode_start",
|
|
3095
|
+
error
|
|
3096
|
+
});
|
|
3097
|
+
const errorListener = (error) => resolveOnce({
|
|
3098
|
+
event: "error",
|
|
3099
|
+
error
|
|
3100
|
+
});
|
|
3101
|
+
const abortListener = () => resolveOnce({ event: "disconnect" });
|
|
3102
|
+
const cleanup = () => {
|
|
3103
|
+
emitter.off("disconnected", disconnectListener);
|
|
3104
|
+
emitter.off("unable_to_socket_mode_start", startFailListener);
|
|
3105
|
+
emitter.off("error", errorListener);
|
|
3106
|
+
abortSignal?.removeEventListener("abort", abortListener);
|
|
3107
|
+
};
|
|
3108
|
+
const resolveOnce = (value) => {
|
|
3109
|
+
cleanup();
|
|
3110
|
+
resolve(value);
|
|
3111
|
+
};
|
|
3112
|
+
emitter.on("disconnected", disconnectListener);
|
|
3113
|
+
emitter.on("unable_to_socket_mode_start", startFailListener);
|
|
3114
|
+
emitter.on("error", errorListener);
|
|
3115
|
+
abortSignal?.addEventListener("abort", abortListener, { once: true });
|
|
3116
|
+
});
|
|
3117
|
+
}
|
|
3118
|
+
/**
|
|
3119
|
+
* Detect permanent Slack account and credential failures.
|
|
3120
|
+
* Transient request and HTTP failures stay in OpenClaw's reconnect loop.
|
|
3121
|
+
*/
|
|
3122
|
+
function isNonRecoverableSlackAuthError(error) {
|
|
3123
|
+
return SLACK_AUTH_ERROR_RE.test(formatUnknownError(error, ""));
|
|
3124
|
+
}
|
|
3125
|
+
function formatUnknownError(error, fallback = NO_ERROR_DETAIL) {
|
|
3126
|
+
return formatSlackError(error, fallback);
|
|
3127
|
+
}
|
|
3128
|
+
//#endregion
|
|
3129
|
+
//#region extensions/slack/src/monitor/provider-support.ts
|
|
3130
|
+
const OPENCLAW_SLACK_CLIENT_PING_TIMEOUT_MS = 15e3;
|
|
3131
|
+
const OPENCLAW_SLACK_SOCKET_START_FAILED_EVENT = "unable_to_socket_mode_start";
|
|
3132
|
+
const OPENCLAW_SLACK_NATIVE_RECONNECT_OBSERVER_KEY = "__openclawNativeReconnectFailureObserver";
|
|
3133
|
+
const SLACK_SOCKET_PONG_TIMEOUT_WARNING_PREFIX = "A pong wasn't received from the server";
|
|
3134
|
+
const SLACK_SOCKET_PING_TIMEOUT_WARNING_PREFIX = "A ping wasn't received from the server";
|
|
3135
|
+
const SLACK_SOCKET_LOG_LEVEL_IGNORED_WARNING_RE = /^The logLevel given to .+ was ignored as you also gave logger$/;
|
|
3136
|
+
function isConstructorFunction(value) {
|
|
3137
|
+
return typeof value === "function";
|
|
3138
|
+
}
|
|
3139
|
+
function installSlackNativeReconnectFailureObserver(receiver) {
|
|
3140
|
+
if (!receiver || typeof receiver !== "object") return;
|
|
3141
|
+
const client = Reflect.get(receiver, "client");
|
|
3142
|
+
if (!client || typeof client !== "object") return;
|
|
3143
|
+
if (Reflect.get(client, OPENCLAW_SLACK_NATIVE_RECONNECT_OBSERVER_KEY)) return;
|
|
3144
|
+
const delayReconnectAttempt = Reflect.get(client, "delayReconnectAttempt");
|
|
3145
|
+
const emit = Reflect.get(client, "emit");
|
|
3146
|
+
if (typeof delayReconnectAttempt !== "function" || typeof emit !== "function") return;
|
|
3147
|
+
Reflect.set(client, OPENCLAW_SLACK_NATIVE_RECONNECT_OBSERVER_KEY, true);
|
|
3148
|
+
Reflect.set(client, "delayReconnectAttempt", function patchedDelayReconnectAttempt(callback) {
|
|
3149
|
+
if (typeof callback !== "function") return delayReconnectAttempt.call(this, callback);
|
|
3150
|
+
const nextFailureCount = Number(Reflect.get(this, "numOfConsecutiveReconnectionFailures") ?? 0) + 1;
|
|
3151
|
+
Reflect.set(this, "numOfConsecutiveReconnectionFailures", nextFailureCount);
|
|
3152
|
+
const pingTimeoutMs = Number(Reflect.get(this, "clientPingTimeoutMS"));
|
|
3153
|
+
const delayMs = (Number.isFinite(pingTimeoutMs) && pingTimeoutMs >= 0 ? pingTimeoutMs : OPENCLAW_SLACK_CLIENT_PING_TIMEOUT_MS) * nextFailureCount;
|
|
3154
|
+
const logger = Reflect.get(this, "logger");
|
|
3155
|
+
logger?.debug?.(`Before trying to reconnect, this client will wait for ${delayMs} milliseconds`);
|
|
3156
|
+
return new Promise((resolve, reject) => {
|
|
3157
|
+
setTimeout(() => {
|
|
3158
|
+
if (Reflect.get(this, "shuttingDown")) {
|
|
3159
|
+
logger?.debug?.("Client shutting down, will not attempt reconnect.");
|
|
3160
|
+
resolve(void 0);
|
|
3161
|
+
return;
|
|
3162
|
+
}
|
|
3163
|
+
logger?.debug?.("Continuing with reconnect...");
|
|
3164
|
+
emit.call(this, "reconnecting");
|
|
3165
|
+
Promise.resolve(callback.call(this)).then(resolve, (error) => {
|
|
3166
|
+
if (callback === Reflect.get(this, "start")) {
|
|
3167
|
+
emit.call(this, OPENCLAW_SLACK_SOCKET_START_FAILED_EVENT, error);
|
|
3168
|
+
resolve(void 0);
|
|
3169
|
+
return;
|
|
3170
|
+
}
|
|
3171
|
+
reject(toLintErrorObject(error, "Non-Error rejection"));
|
|
3172
|
+
});
|
|
3173
|
+
}, delayMs);
|
|
3174
|
+
});
|
|
3175
|
+
});
|
|
3176
|
+
}
|
|
3177
|
+
function createSlackRelayReceiver() {
|
|
3178
|
+
return {
|
|
3179
|
+
init() {},
|
|
3180
|
+
start: () => Promise.resolve(void 0),
|
|
3181
|
+
stop: () => Promise.resolve(void 0)
|
|
3182
|
+
};
|
|
3183
|
+
}
|
|
3184
|
+
function resolveSlackBoltModule(value) {
|
|
3185
|
+
if (!value || typeof value !== "object") return null;
|
|
3186
|
+
const app = Reflect.get(value, "App");
|
|
3187
|
+
const httpReceiver = Reflect.get(value, "HTTPReceiver");
|
|
3188
|
+
const socketModeReceiver = Reflect.get(value, "SocketModeReceiver");
|
|
3189
|
+
if (!isConstructorFunction(app) || !isConstructorFunction(httpReceiver) || !isConstructorFunction(socketModeReceiver)) return null;
|
|
3190
|
+
return {
|
|
3191
|
+
App: app,
|
|
3192
|
+
HTTPReceiver: httpReceiver,
|
|
3193
|
+
SocketModeReceiver: socketModeReceiver
|
|
3194
|
+
};
|
|
3195
|
+
}
|
|
3196
|
+
function resolveSlackBoltInterop(params) {
|
|
3197
|
+
const { defaultImport, namespaceImport } = params;
|
|
3198
|
+
const nestedDefault = defaultImport && typeof defaultImport === "object" ? Reflect.get(defaultImport, "default") : void 0;
|
|
3199
|
+
const namespaceDefault = namespaceImport && typeof namespaceImport === "object" ? Reflect.get(namespaceImport, "default") : void 0;
|
|
3200
|
+
const namespaceReceiver = namespaceImport && typeof namespaceImport === "object" ? Reflect.get(namespaceImport, "HTTPReceiver") : void 0;
|
|
3201
|
+
const namespaceSocketModeReceiver = namespaceImport && typeof namespaceImport === "object" ? Reflect.get(namespaceImport, "SocketModeReceiver") : void 0;
|
|
3202
|
+
const directModule = resolveSlackBoltModule(defaultImport) ?? resolveSlackBoltModule(nestedDefault) ?? resolveSlackBoltModule(namespaceDefault) ?? resolveSlackBoltModule(namespaceImport);
|
|
3203
|
+
if (directModule) return directModule;
|
|
3204
|
+
if (isConstructorFunction(defaultImport) && isConstructorFunction(namespaceReceiver) && isConstructorFunction(namespaceSocketModeReceiver)) return {
|
|
3205
|
+
App: defaultImport,
|
|
3206
|
+
HTTPReceiver: namespaceReceiver,
|
|
3207
|
+
SocketModeReceiver: namespaceSocketModeReceiver
|
|
3208
|
+
};
|
|
3209
|
+
throw new TypeError("Unable to resolve @slack/bolt App/HTTPReceiver exports");
|
|
3210
|
+
}
|
|
3211
|
+
function publishSlackConnectedStatus(setStatus) {
|
|
3212
|
+
if (!setStatus) return;
|
|
3213
|
+
setStatus({
|
|
3214
|
+
connected: true,
|
|
3215
|
+
lastConnectedAt: Date.now(),
|
|
3216
|
+
healthState: "healthy",
|
|
3217
|
+
lastError: null
|
|
3218
|
+
});
|
|
3219
|
+
}
|
|
3220
|
+
function publishSlackDisconnectedStatus(setStatus, error) {
|
|
3221
|
+
if (!setStatus) return;
|
|
3222
|
+
const at = Date.now();
|
|
3223
|
+
const message = error ? formatUnknownError(error) : void 0;
|
|
3224
|
+
setStatus({
|
|
3225
|
+
connected: false,
|
|
3226
|
+
healthState: "disconnected",
|
|
3227
|
+
lastDisconnect: message ? {
|
|
3228
|
+
at,
|
|
3229
|
+
error: message
|
|
3230
|
+
} : { at },
|
|
3231
|
+
lastError: message ?? null
|
|
3232
|
+
});
|
|
3233
|
+
}
|
|
3234
|
+
function isSlackSocketHeartbeatTimeoutWarning(args) {
|
|
3235
|
+
return typeof args[0] === "string" && (args[0].startsWith(SLACK_SOCKET_PONG_TIMEOUT_WARNING_PREFIX) || args[0].startsWith(SLACK_SOCKET_PING_TIMEOUT_WARNING_PREFIX));
|
|
3236
|
+
}
|
|
3237
|
+
function isSlackSocketSelfInflictedLoggerWarning(args) {
|
|
3238
|
+
return typeof args[0] === "string" && SLACK_SOCKET_LOG_LEVEL_IGNORED_WARNING_RE.test(args[0]);
|
|
3239
|
+
}
|
|
3240
|
+
function formatSlackSdkLogArgs(args) {
|
|
3241
|
+
return args.map((arg) => formatUnknownError(arg, "")).filter(Boolean).join(" ");
|
|
3242
|
+
}
|
|
3243
|
+
function createSlackSocketModeLogger(sink = console) {
|
|
3244
|
+
let level = "info";
|
|
3245
|
+
let name = "socket-mode";
|
|
3246
|
+
const prefix = () => `socket-mode:${name}`;
|
|
3247
|
+
let lastMessage;
|
|
3248
|
+
const remember = (args) => {
|
|
3249
|
+
const message = formatSlackSdkLogArgs([prefix(), ...args]);
|
|
3250
|
+
if (message) lastMessage = message;
|
|
3251
|
+
};
|
|
3252
|
+
return {
|
|
3253
|
+
debug: () => {},
|
|
3254
|
+
info: () => {},
|
|
3255
|
+
warn: (...args) => {
|
|
3256
|
+
if (isSlackSocketHeartbeatTimeoutWarning(args) || isSlackSocketSelfInflictedLoggerWarning(args)) return;
|
|
3257
|
+
remember(args);
|
|
3258
|
+
sink.warn(prefix(), ...args);
|
|
3259
|
+
},
|
|
3260
|
+
error: (...args) => {
|
|
3261
|
+
remember(args);
|
|
3262
|
+
sink.error(prefix(), ...args);
|
|
3263
|
+
},
|
|
3264
|
+
setLevel: (nextLevel) => {
|
|
3265
|
+
level = nextLevel;
|
|
3266
|
+
},
|
|
3267
|
+
getLevel: () => level,
|
|
3268
|
+
setName: (nextName) => {
|
|
3269
|
+
name = nextName;
|
|
3270
|
+
},
|
|
3271
|
+
getLastMessage: () => lastMessage
|
|
3272
|
+
};
|
|
3273
|
+
}
|
|
3274
|
+
function shouldSkipOpenClawSlackSelfEvent(args) {
|
|
3275
|
+
const botId = args.context?.botId;
|
|
3276
|
+
const botUserId = args.context?.botUserId;
|
|
3277
|
+
const message = asOptionalRecord(args.message);
|
|
3278
|
+
if (message?.subtype === "bot_message" && botId && message.bot_id === botId) return true;
|
|
3279
|
+
const event = asOptionalRecord(args.event);
|
|
3280
|
+
if (event?.type === "message" && event.subtype === "message_changed" && event.user === botUserId) return false;
|
|
3281
|
+
const eventsWhichShouldBeKept = /* @__PURE__ */ new Set(["member_joined_channel", "member_left_channel"]);
|
|
3282
|
+
return Boolean(botUserId && event && event.user === botUserId && typeof event.type === "string" && !eventsWhichShouldBeKept.has(event.type));
|
|
3283
|
+
}
|
|
3284
|
+
function createSlackBoltApp(params) {
|
|
3285
|
+
const socketModeLogger = createSlackSocketModeLogger();
|
|
3286
|
+
const socketModeReceiverOptions = {
|
|
3287
|
+
appToken: params.appToken ?? "",
|
|
3288
|
+
autoReconnectEnabled: true,
|
|
3289
|
+
clientPingTimeout: params.socketMode?.clientPingTimeout ?? OPENCLAW_SLACK_CLIENT_PING_TIMEOUT_MS,
|
|
3290
|
+
logger: socketModeLogger,
|
|
3291
|
+
installerOptions: { clientOptions: params.clientOptions }
|
|
3292
|
+
};
|
|
3293
|
+
if (params.socketMode?.serverPingTimeout !== void 0) socketModeReceiverOptions.serverPingTimeout = params.socketMode.serverPingTimeout;
|
|
3294
|
+
if (params.socketMode?.pingPongLoggingEnabled !== void 0) socketModeReceiverOptions.pingPongLoggingEnabled = params.socketMode.pingPongLoggingEnabled;
|
|
3295
|
+
let receiver;
|
|
3296
|
+
if (params.slackMode === "socket") {
|
|
3297
|
+
receiver = new params.interop.SocketModeReceiver(socketModeReceiverOptions);
|
|
3298
|
+
installSlackNativeReconnectFailureObserver(receiver);
|
|
3299
|
+
} else if (params.slackMode === "http") receiver = new params.interop.HTTPReceiver({
|
|
3300
|
+
signingSecret: params.signingSecret ?? "",
|
|
3301
|
+
endpoints: params.slackWebhookPath
|
|
3302
|
+
});
|
|
3303
|
+
else receiver = createSlackRelayReceiver();
|
|
3304
|
+
const app = new params.interop.App({
|
|
3305
|
+
token: params.botToken,
|
|
3306
|
+
clientOptions: params.clientOptions,
|
|
3307
|
+
ignoreSelf: false,
|
|
3308
|
+
tokenVerificationEnabled: false,
|
|
3309
|
+
...receiver ? { receiver } : {}
|
|
3310
|
+
});
|
|
3311
|
+
app.use(async (args) => {
|
|
3312
|
+
if (shouldSkipOpenClawSlackSelfEvent(args)) return;
|
|
3313
|
+
await args.next();
|
|
3314
|
+
});
|
|
3315
|
+
return {
|
|
3316
|
+
app,
|
|
3317
|
+
receiver,
|
|
3318
|
+
socketModeLogger
|
|
3319
|
+
};
|
|
3320
|
+
}
|
|
3321
|
+
function createSlackSocketDisconnectWaiter(app, abortSignal) {
|
|
3322
|
+
const waiterAbortController = new AbortController();
|
|
3323
|
+
const relayAbort = () => waiterAbortController.abort();
|
|
3324
|
+
let latest;
|
|
3325
|
+
abortSignal?.addEventListener("abort", relayAbort, { once: true });
|
|
3326
|
+
return {
|
|
3327
|
+
promise: waitForSlackSocketDisconnect(app, waiterAbortController.signal).then((value) => {
|
|
3328
|
+
latest = value;
|
|
3329
|
+
return value;
|
|
3330
|
+
}),
|
|
3331
|
+
getLatest: () => latest,
|
|
3332
|
+
cancel: () => {
|
|
3333
|
+
waiterAbortController.abort();
|
|
3334
|
+
abortSignal?.removeEventListener("abort", relayAbort);
|
|
3335
|
+
},
|
|
3336
|
+
complete: () => {
|
|
3337
|
+
abortSignal?.removeEventListener("abort", relayAbort);
|
|
3338
|
+
}
|
|
3339
|
+
};
|
|
3340
|
+
}
|
|
3341
|
+
async function startSlackSocketAndWaitForDisconnect(params) {
|
|
3342
|
+
const disconnectWaiter = createSlackSocketDisconnectWaiter(params.app, params.abortSignal);
|
|
3343
|
+
try {
|
|
3344
|
+
await Promise.resolve(params.app.start());
|
|
3345
|
+
if (params.abortSignal?.aborted) {
|
|
3346
|
+
disconnectWaiter.cancel();
|
|
3347
|
+
return null;
|
|
3348
|
+
}
|
|
3349
|
+
params.onStarted?.();
|
|
3350
|
+
const disconnect = await disconnectWaiter.promise;
|
|
3351
|
+
disconnectWaiter.complete();
|
|
3352
|
+
return disconnect;
|
|
3353
|
+
} catch (err) {
|
|
3354
|
+
await Promise.resolve();
|
|
3355
|
+
const disconnect = disconnectWaiter.getLatest();
|
|
3356
|
+
disconnectWaiter.cancel();
|
|
3357
|
+
if (isMissingSocketStartErrorDetail(err) && disconnect?.error !== void 0) throw toLintErrorObject(disconnect.error, "Non-Error thrown");
|
|
3358
|
+
if (isMissingSocketStartErrorDetail(err)) {
|
|
3359
|
+
const suffix = disconnect ? ` after ${disconnect.event}` : "";
|
|
3360
|
+
throw new Error(`Slack Socket Mode start failed${suffix} without error detail`, { cause: err });
|
|
3361
|
+
}
|
|
3362
|
+
throw err;
|
|
3363
|
+
}
|
|
3364
|
+
}
|
|
3365
|
+
function isMissingSocketStartErrorDetail(err) {
|
|
3366
|
+
return err === void 0 || err === null || err === "" || err instanceof Error && err.message === "";
|
|
3367
|
+
}
|
|
3368
|
+
function resolveSlackSocketShutdownClient(app) {
|
|
3369
|
+
if (!app || typeof app !== "object") return;
|
|
3370
|
+
const receiver = Reflect.get(app, "receiver");
|
|
3371
|
+
if (!receiver || typeof receiver !== "object") return;
|
|
3372
|
+
const client = Reflect.get(receiver, "client");
|
|
3373
|
+
if (!client || typeof client !== "object") return;
|
|
3374
|
+
return client;
|
|
3375
|
+
}
|
|
3376
|
+
async function gracefulStopSlackApp(app) {
|
|
3377
|
+
const socketClient = resolveSlackSocketShutdownClient(app);
|
|
3378
|
+
if (socketClient) socketClient.shuttingDown = true;
|
|
3379
|
+
await Promise.resolve(app.stop()).catch(() => void 0);
|
|
3380
|
+
}
|
|
3381
|
+
function formatSlackResolvedLabel(params) {
|
|
3382
|
+
const extras = params.extra?.filter(Boolean) ?? [];
|
|
3383
|
+
const suffix = extras.length > 0 ? ` (id:${params.id}, ${extras.join(", ")})` : ` (id:${params.id})`;
|
|
3384
|
+
return `${params.input}→${params.name ?? params.id}${suffix}`;
|
|
3385
|
+
}
|
|
3386
|
+
function formatSlackChannelResolved(entry) {
|
|
3387
|
+
const id = entry.id ?? entry.input;
|
|
3388
|
+
return formatSlackResolvedLabel({
|
|
3389
|
+
input: entry.input,
|
|
3390
|
+
id,
|
|
3391
|
+
name: entry.name,
|
|
3392
|
+
extra: entry.archived ? ["archived"] : []
|
|
3393
|
+
});
|
|
3394
|
+
}
|
|
3395
|
+
function formatSlackUserResolved(entry) {
|
|
3396
|
+
const id = entry.id ?? entry.input;
|
|
3397
|
+
return formatSlackResolvedLabel({
|
|
3398
|
+
input: entry.input,
|
|
3399
|
+
id,
|
|
3400
|
+
name: entry.name,
|
|
3401
|
+
extra: entry.note ? [entry.note] : []
|
|
3402
|
+
});
|
|
3403
|
+
}
|
|
3404
|
+
function toLintErrorObject(value, fallbackMessage) {
|
|
3405
|
+
if (value instanceof Error) return value;
|
|
3406
|
+
if (typeof value === "string") return new Error(value);
|
|
3407
|
+
const error = new Error(fallbackMessage, { cause: value });
|
|
3408
|
+
if (typeof value === "object" && value !== null || typeof value === "function") Object.assign(error, value);
|
|
3409
|
+
return error;
|
|
3410
|
+
}
|
|
3411
|
+
//#endregion
|
|
3412
|
+
//#region extensions/slack/src/monitor/dm-auth.ts
|
|
3413
|
+
async function authorizeSlackDirectMessage(params) {
|
|
3414
|
+
if (!params.ctx.dmEnabled || params.ctx.dmPolicy === "disabled") {
|
|
3415
|
+
await params.onDisabled();
|
|
3416
|
+
return false;
|
|
3417
|
+
}
|
|
3418
|
+
if (params.ctx.dmPolicy === "open" && params.allowFromLower.includes("*")) return true;
|
|
3419
|
+
const senderName = (await params.resolveSenderName(params.senderId))?.name ?? void 0;
|
|
3420
|
+
const allowMatch = resolveSlackAllowListMatch({
|
|
3421
|
+
allowList: params.allowFromLower,
|
|
3422
|
+
id: params.senderId,
|
|
3423
|
+
name: senderName,
|
|
3424
|
+
allowNameMatching: params.ctx.allowNameMatching
|
|
3425
|
+
});
|
|
3426
|
+
const allowMatchMeta = formatAllowlistMatchMeta(allowMatch);
|
|
3427
|
+
if (allowMatch.allowed) return true;
|
|
3428
|
+
if (params.ctx.dmPolicy === "pairing") {
|
|
3429
|
+
await createChannelPairingChallengeIssuer({
|
|
3430
|
+
channel: "slack",
|
|
3431
|
+
accountId: params.accountId,
|
|
3432
|
+
upsertPairingRequest: async ({ id, meta }) => await upsertChannelPairingRequest({
|
|
3433
|
+
channel: "slack",
|
|
3434
|
+
id,
|
|
3435
|
+
accountId: params.accountId,
|
|
3436
|
+
meta
|
|
3437
|
+
})
|
|
3438
|
+
})({
|
|
3439
|
+
senderId: params.senderId,
|
|
3440
|
+
senderIdLine: `Your Slack user id: ${params.senderId}`,
|
|
3441
|
+
meta: { name: senderName },
|
|
3442
|
+
sendPairingReply: params.sendPairingReply,
|
|
3443
|
+
onCreated: () => {
|
|
3444
|
+
params.log(`slack pairing request sender=${params.senderId} name=${senderName ?? "unknown"} (${allowMatchMeta})`);
|
|
3445
|
+
},
|
|
3446
|
+
onReplyError: (err) => {
|
|
3447
|
+
params.log(`slack pairing reply failed for ${params.senderId}: ${formatErrorMessage(err)}`);
|
|
3448
|
+
}
|
|
3449
|
+
});
|
|
3450
|
+
return false;
|
|
3451
|
+
}
|
|
3452
|
+
await params.onUnauthorized({
|
|
3453
|
+
allowMatchMeta,
|
|
3454
|
+
senderName
|
|
3455
|
+
});
|
|
3456
|
+
return false;
|
|
3457
|
+
}
|
|
3458
|
+
//#endregion
|
|
3459
|
+
//#region extensions/slack/src/monitor/external-arg-menu-store.ts
|
|
3460
|
+
const SLACK_EXTERNAL_ARG_MENU_TOKEN_BYTES = 18;
|
|
3461
|
+
const SLACK_EXTERNAL_ARG_MENU_TOKEN_PATTERN = new RegExp(`^[A-Za-z0-9_-]{${Math.ceil(24)}}$`);
|
|
3462
|
+
const SLACK_EXTERNAL_ARG_MENU_TTL_MS = 6e5;
|
|
3463
|
+
const SLACK_EXTERNAL_ARG_MENU_PREFIX = "openclaw_cmdarg_ext:";
|
|
3464
|
+
function pruneSlackExternalArgMenuStore(store, rawNow) {
|
|
3465
|
+
const now = asDateTimestampMs(rawNow);
|
|
3466
|
+
if (now === void 0) {
|
|
3467
|
+
store.clear();
|
|
3468
|
+
return;
|
|
3469
|
+
}
|
|
3470
|
+
for (const [token, entry] of store.entries()) if (asDateTimestampMs(entry.expiresAt) === void 0 || entry.expiresAt <= now) store.delete(token);
|
|
3471
|
+
}
|
|
3472
|
+
function createSlackExternalArgMenuToken(store) {
|
|
3473
|
+
let token;
|
|
3474
|
+
do
|
|
3475
|
+
token = generateSecureToken(SLACK_EXTERNAL_ARG_MENU_TOKEN_BYTES);
|
|
3476
|
+
while (store.has(token));
|
|
3477
|
+
return token;
|
|
3478
|
+
}
|
|
3479
|
+
function createSlackExternalArgMenuStore() {
|
|
3480
|
+
const store = /* @__PURE__ */ new Map();
|
|
3481
|
+
return {
|
|
3482
|
+
create(params, now = Date.now()) {
|
|
3483
|
+
pruneSlackExternalArgMenuStore(store, now);
|
|
3484
|
+
const token = createSlackExternalArgMenuToken(store);
|
|
3485
|
+
const expiresAt = resolveExpiresAtMsFromDurationMs(SLACK_EXTERNAL_ARG_MENU_TTL_MS, { nowMs: now });
|
|
3486
|
+
if (expiresAt !== void 0) store.set(token, {
|
|
3487
|
+
choices: params.choices,
|
|
3488
|
+
userId: params.userId,
|
|
3489
|
+
expiresAt
|
|
3490
|
+
});
|
|
3491
|
+
return token;
|
|
3492
|
+
},
|
|
3493
|
+
readToken(raw) {
|
|
3494
|
+
if (typeof raw !== "string" || !raw.startsWith("openclaw_cmdarg_ext:")) return;
|
|
3495
|
+
const token = raw.slice(20).trim();
|
|
3496
|
+
return SLACK_EXTERNAL_ARG_MENU_TOKEN_PATTERN.test(token) ? token : void 0;
|
|
3497
|
+
},
|
|
3498
|
+
get(token, now = Date.now()) {
|
|
3499
|
+
pruneSlackExternalArgMenuStore(store, now);
|
|
3500
|
+
return store.get(token);
|
|
3501
|
+
}
|
|
3502
|
+
};
|
|
3503
|
+
}
|
|
3504
|
+
//#endregion
|
|
3505
|
+
//#region extensions/slack/src/monitor/room-context.ts
|
|
3506
|
+
function resolveSlackRoomContextHints(params) {
|
|
3507
|
+
const untrustedChannelMetadata = params.isRoomish ? buildUntrustedChannelMetadata({
|
|
3508
|
+
source: "slack",
|
|
3509
|
+
label: "Slack channel description",
|
|
3510
|
+
entries: [params.channelInfo?.topic, params.channelInfo?.purpose]
|
|
3511
|
+
}) : void 0;
|
|
3512
|
+
const systemPromptParts = [params.isRoomish ? normalizeOptionalString(params.channelConfig?.systemPrompt) ?? null : null].filter((entry) => Boolean(entry));
|
|
3513
|
+
return {
|
|
3514
|
+
untrustedChannelMetadata,
|
|
3515
|
+
groupSystemPrompt: systemPromptParts.length > 0 ? systemPromptParts.join("\n\n") : void 0
|
|
3516
|
+
};
|
|
3517
|
+
}
|
|
3518
|
+
//#endregion
|
|
3519
|
+
//#region extensions/slack/src/monitor/slash.ts
|
|
3520
|
+
const SLACK_COMMAND_ARG_ACTION_ID = "openclaw_cmdarg";
|
|
3521
|
+
const SLACK_COMMAND_ARG_ACTION_LISTENER = /^openclaw_cmdarg/;
|
|
3522
|
+
const SLACK_COMMAND_ARG_VALUE_PREFIX = "cmdarg";
|
|
3523
|
+
const SLACK_COMMAND_ARG_BUTTON_ROW_SIZE = 5;
|
|
3524
|
+
const SLACK_COMMAND_ARG_OVERFLOW_MIN = 3;
|
|
3525
|
+
const SLACK_COMMAND_ARG_OVERFLOW_MAX = 5;
|
|
3526
|
+
const SLACK_COMMAND_ARG_SELECT_OPTIONS_MAX = 100;
|
|
3527
|
+
const SLACK_COMMAND_ARG_SELECT_OPTION_TEXT_MAX = 75;
|
|
3528
|
+
const SLACK_COMMAND_ARG_SELECT_OPTION_VALUE_MAX = 150;
|
|
3529
|
+
const SLACK_COMMAND_ARG_BUTTON_TEXT_MAX = 75;
|
|
3530
|
+
const SLACK_COMMAND_ARG_BUTTON_VALUE_MAX = 2e3;
|
|
3531
|
+
const SLACK_COMMAND_ARG_CONFIRM_TEXT_MAX = 300;
|
|
3532
|
+
const SLACK_HEADER_TEXT_MAX = 150;
|
|
3533
|
+
const SLACK_COMMAND_ARG_ACTION_BLOCKS_MAX = 47;
|
|
3534
|
+
const loadSlashCommandsRuntime = createLazyRuntimeModule(() => import("./slash-commands.runtime-BTTMlmwy.mjs"));
|
|
3535
|
+
const loadSlashDispatchRuntime = createLazyRuntimeModule(() => import("./slash-dispatch.runtime-eyQo6mTA.mjs"));
|
|
3536
|
+
const loadSlackPluginCommandsRuntime = createLazyRuntimeModule(() => import("./slash-plugin-commands.runtime-Dosfcx3X.mjs"));
|
|
3537
|
+
const loadSlashSkillCommandsRuntime = createLazyRuntimeModule(() => import("./slash-skill-commands.runtime-CD1J2ODY.mjs"));
|
|
3538
|
+
function resolveSlackCommandMenuModelContext(params) {
|
|
3539
|
+
if (!params.sessionKey.trim()) return {};
|
|
3540
|
+
try {
|
|
3541
|
+
const defaultModel = resolveDefaultModelForAgent({
|
|
3542
|
+
cfg: params.cfg,
|
|
3543
|
+
agentId: params.agentId
|
|
3544
|
+
});
|
|
3545
|
+
const storePath = resolveStorePath(params.cfg.session?.store, { agentId: params.agentId });
|
|
3546
|
+
const entry = getSessionEntry({
|
|
3547
|
+
storePath,
|
|
3548
|
+
sessionKey: params.sessionKey
|
|
3549
|
+
});
|
|
3550
|
+
let provider;
|
|
3551
|
+
let model;
|
|
3552
|
+
if (entry?.modelOverrideSource === "auto" && normalizeOptionalString(entry.modelOverride)) {
|
|
3553
|
+
provider = defaultModel.provider;
|
|
3554
|
+
model = defaultModel.model;
|
|
3555
|
+
} else {
|
|
3556
|
+
const override = resolveStoredModelOverride({
|
|
3557
|
+
sessionEntry: entry,
|
|
3558
|
+
loadSessionEntry: (sessionKey) => getSessionEntry({
|
|
3559
|
+
storePath,
|
|
3560
|
+
sessionKey
|
|
3561
|
+
}),
|
|
3562
|
+
sessionKey: params.sessionKey,
|
|
3563
|
+
defaultProvider: defaultModel.provider
|
|
3564
|
+
});
|
|
3565
|
+
provider = override?.model ? override.provider || defaultModel.provider : normalizeOptionalString(entry?.providerOverride) ?? normalizeOptionalString(entry?.modelProvider);
|
|
3566
|
+
model = override?.model ? override.model : normalizeOptionalString(entry?.modelOverride) ?? normalizeOptionalString(entry?.model);
|
|
3567
|
+
}
|
|
3568
|
+
return {
|
|
3569
|
+
...provider ? { provider } : {},
|
|
3570
|
+
...model ? { model } : {},
|
|
3571
|
+
agentRuntime: resolveEffectiveAgentRuntime({
|
|
3572
|
+
cfg: params.cfg,
|
|
3573
|
+
provider: provider ?? defaultModel.provider,
|
|
3574
|
+
modelId: model ?? defaultModel.model,
|
|
3575
|
+
agentId: params.agentId,
|
|
3576
|
+
sessionKey: params.sessionKey,
|
|
3577
|
+
sessionEntry: entry
|
|
3578
|
+
})
|
|
3579
|
+
};
|
|
3580
|
+
} catch {
|
|
3581
|
+
return {};
|
|
3582
|
+
}
|
|
3583
|
+
}
|
|
3584
|
+
const slackExternalArgMenuStore = createSlackExternalArgMenuStore();
|
|
3585
|
+
function buildSlackArgMenuConfirm(params) {
|
|
3586
|
+
const command = escapeSlackMrkdwn(params.command);
|
|
3587
|
+
const arg = escapeSlackMrkdwn(params.arg);
|
|
3588
|
+
return {
|
|
3589
|
+
title: {
|
|
3590
|
+
type: "plain_text",
|
|
3591
|
+
text: "Confirm selection"
|
|
3592
|
+
},
|
|
3593
|
+
text: {
|
|
3594
|
+
type: "mrkdwn",
|
|
3595
|
+
text: truncateSlackText(`Run */${command}* with *${arg}* set to this value?`, SLACK_COMMAND_ARG_CONFIRM_TEXT_MAX)
|
|
3596
|
+
},
|
|
3597
|
+
confirm: {
|
|
3598
|
+
type: "plain_text",
|
|
3599
|
+
text: "Run command"
|
|
3600
|
+
},
|
|
3601
|
+
deny: {
|
|
3602
|
+
type: "plain_text",
|
|
3603
|
+
text: "Cancel"
|
|
3604
|
+
}
|
|
3605
|
+
};
|
|
3606
|
+
}
|
|
3607
|
+
function storeSlackExternalArgMenu(params) {
|
|
3608
|
+
return slackExternalArgMenuStore.create({
|
|
3609
|
+
choices: params.choices,
|
|
3610
|
+
userId: params.userId
|
|
3611
|
+
});
|
|
3612
|
+
}
|
|
3613
|
+
function readSlackExternalArgMenuToken(raw) {
|
|
3614
|
+
return slackExternalArgMenuStore.readToken(raw);
|
|
3615
|
+
}
|
|
3616
|
+
function encodeSlackCommandArgValue(parts) {
|
|
3617
|
+
return [
|
|
3618
|
+
SLACK_COMMAND_ARG_VALUE_PREFIX,
|
|
3619
|
+
encodeURIComponent(parts.command),
|
|
3620
|
+
encodeURIComponent(parts.arg),
|
|
3621
|
+
encodeURIComponent(parts.value),
|
|
3622
|
+
encodeURIComponent(parts.userId)
|
|
3623
|
+
].join("|");
|
|
3624
|
+
}
|
|
3625
|
+
function parseSlackCommandArgValue(raw) {
|
|
3626
|
+
if (!raw) return null;
|
|
3627
|
+
const parts = raw.split("|");
|
|
3628
|
+
if (parts.length !== 5 || parts[0] !== SLACK_COMMAND_ARG_VALUE_PREFIX) return null;
|
|
3629
|
+
const [, command, arg, value, userId] = parts;
|
|
3630
|
+
if (!command || !arg || !value || !userId) return null;
|
|
3631
|
+
const decode = (text) => {
|
|
3632
|
+
try {
|
|
3633
|
+
return decodeURIComponent(text);
|
|
3634
|
+
} catch {
|
|
3635
|
+
return null;
|
|
3636
|
+
}
|
|
3637
|
+
};
|
|
3638
|
+
const decodedCommand = decode(command);
|
|
3639
|
+
const decodedArg = decode(arg);
|
|
3640
|
+
const decodedValue = decode(value);
|
|
3641
|
+
const decodedUserId = decode(userId);
|
|
3642
|
+
if (!decodedCommand || !decodedArg || !decodedValue || !decodedUserId) return null;
|
|
3643
|
+
return {
|
|
3644
|
+
command: decodedCommand,
|
|
3645
|
+
arg: decodedArg,
|
|
3646
|
+
value: decodedValue,
|
|
3647
|
+
userId: decodedUserId
|
|
3648
|
+
};
|
|
3649
|
+
}
|
|
3650
|
+
function buildSlackArgMenuOptions(choices) {
|
|
3651
|
+
return choices.map((choice) => ({
|
|
3652
|
+
text: {
|
|
3653
|
+
type: "plain_text",
|
|
3654
|
+
text: truncateSlackText(choice.label, SLACK_COMMAND_ARG_SELECT_OPTION_TEXT_MAX)
|
|
3655
|
+
},
|
|
3656
|
+
value: choice.value
|
|
3657
|
+
}));
|
|
3658
|
+
}
|
|
3659
|
+
function buildSlackCommandArgMenuBlocks(params) {
|
|
3660
|
+
const encodedChoices = params.choices.map((choice) => ({
|
|
3661
|
+
label: choice.label,
|
|
3662
|
+
value: encodeSlackCommandArgValue({
|
|
3663
|
+
command: params.command,
|
|
3664
|
+
arg: params.arg,
|
|
3665
|
+
value: choice.value,
|
|
3666
|
+
userId: params.userId
|
|
3667
|
+
})
|
|
3668
|
+
}));
|
|
3669
|
+
const canUseStaticSelect = encodedChoices.every((choice) => choice.value.length <= SLACK_COMMAND_ARG_SELECT_OPTION_VALUE_MAX);
|
|
3670
|
+
const canUseOverflow = canUseStaticSelect && encodedChoices.length >= SLACK_COMMAND_ARG_OVERFLOW_MIN && encodedChoices.length <= SLACK_COMMAND_ARG_OVERFLOW_MAX;
|
|
3671
|
+
const canUseExternalSelect = params.supportsExternalSelect && canUseStaticSelect && encodedChoices.length > SLACK_COMMAND_ARG_SELECT_OPTIONS_MAX;
|
|
3672
|
+
const rows = canUseOverflow ? [{
|
|
3673
|
+
type: "actions",
|
|
3674
|
+
elements: [{
|
|
3675
|
+
type: "overflow",
|
|
3676
|
+
action_id: SLACK_COMMAND_ARG_ACTION_ID,
|
|
3677
|
+
confirm: buildSlackArgMenuConfirm({
|
|
3678
|
+
command: params.command,
|
|
3679
|
+
arg: params.arg
|
|
3680
|
+
}),
|
|
3681
|
+
options: buildSlackArgMenuOptions(encodedChoices)
|
|
3682
|
+
}]
|
|
3683
|
+
}] : canUseExternalSelect ? [{
|
|
3684
|
+
type: "actions",
|
|
3685
|
+
block_id: `${SLACK_EXTERNAL_ARG_MENU_PREFIX}${params.createExternalMenuToken(encodedChoices)}`,
|
|
3686
|
+
elements: [{
|
|
3687
|
+
type: "external_select",
|
|
3688
|
+
action_id: SLACK_COMMAND_ARG_ACTION_ID,
|
|
3689
|
+
confirm: buildSlackArgMenuConfirm({
|
|
3690
|
+
command: params.command,
|
|
3691
|
+
arg: params.arg
|
|
3692
|
+
}),
|
|
3693
|
+
min_query_length: 0,
|
|
3694
|
+
placeholder: {
|
|
3695
|
+
type: "plain_text",
|
|
3696
|
+
text: `Search ${params.arg}`
|
|
3697
|
+
}
|
|
3698
|
+
}]
|
|
3699
|
+
}] : encodedChoices.length <= SLACK_COMMAND_ARG_BUTTON_ROW_SIZE || !canUseStaticSelect ? chunkItems(encodedChoices.filter((choice) => choice.value.length <= SLACK_COMMAND_ARG_BUTTON_VALUE_MAX), SLACK_COMMAND_ARG_BUTTON_ROW_SIZE).map((choices, rowIndex) => ({
|
|
3700
|
+
type: "actions",
|
|
3701
|
+
elements: choices.map((choice, colIndex) => ({
|
|
3702
|
+
type: "button",
|
|
3703
|
+
action_id: `${SLACK_COMMAND_ARG_ACTION_ID}_${rowIndex}_${colIndex}`,
|
|
3704
|
+
text: {
|
|
3705
|
+
type: "plain_text",
|
|
3706
|
+
text: truncateSlackText(choice.label, SLACK_COMMAND_ARG_BUTTON_TEXT_MAX)
|
|
3707
|
+
},
|
|
3708
|
+
value: choice.value,
|
|
3709
|
+
confirm: buildSlackArgMenuConfirm({
|
|
3710
|
+
command: params.command,
|
|
3711
|
+
arg: params.arg
|
|
3712
|
+
})
|
|
3713
|
+
}))
|
|
3714
|
+
})) : chunkItems(encodedChoices, SLACK_COMMAND_ARG_SELECT_OPTIONS_MAX).map((choices, index) => ({
|
|
3715
|
+
type: "actions",
|
|
3716
|
+
elements: [{
|
|
3717
|
+
type: "static_select",
|
|
3718
|
+
action_id: SLACK_COMMAND_ARG_ACTION_ID,
|
|
3719
|
+
confirm: buildSlackArgMenuConfirm({
|
|
3720
|
+
command: params.command,
|
|
3721
|
+
arg: params.arg
|
|
3722
|
+
}),
|
|
3723
|
+
placeholder: {
|
|
3724
|
+
type: "plain_text",
|
|
3725
|
+
text: index === 0 ? `Choose ${params.arg}` : `Choose ${params.arg} (${index + 1})`
|
|
3726
|
+
},
|
|
3727
|
+
options: buildSlackArgMenuOptions(choices)
|
|
3728
|
+
}]
|
|
3729
|
+
}));
|
|
3730
|
+
const headerText = truncateSlackText(`/${params.command}: choose ${params.arg}`, SLACK_HEADER_TEXT_MAX);
|
|
3731
|
+
const sectionText = truncateSlackText(params.title, 3e3);
|
|
3732
|
+
const contextText = truncateSlackText(`Select one option to continue /${params.command} (${params.arg})`, 3e3);
|
|
3733
|
+
const visibleRows = rows.slice(0, SLACK_COMMAND_ARG_ACTION_BLOCKS_MAX);
|
|
3734
|
+
return [
|
|
3735
|
+
{
|
|
3736
|
+
type: "header",
|
|
3737
|
+
text: {
|
|
3738
|
+
type: "plain_text",
|
|
3739
|
+
text: headerText
|
|
3740
|
+
}
|
|
3741
|
+
},
|
|
3742
|
+
{
|
|
3743
|
+
type: "section",
|
|
3744
|
+
text: {
|
|
3745
|
+
type: "mrkdwn",
|
|
3746
|
+
text: sectionText
|
|
3747
|
+
}
|
|
3748
|
+
},
|
|
3749
|
+
{
|
|
3750
|
+
type: "context",
|
|
3751
|
+
elements: [{
|
|
3752
|
+
type: "mrkdwn",
|
|
3753
|
+
text: contextText
|
|
3754
|
+
}]
|
|
3755
|
+
},
|
|
3756
|
+
...visibleRows
|
|
3757
|
+
];
|
|
3758
|
+
}
|
|
3759
|
+
async function registerSlackMonitorSlashCommands(params) {
|
|
3760
|
+
const { ctx, account, trackEvent } = params;
|
|
3761
|
+
const startupCfg = ctx.cfg;
|
|
3762
|
+
const runtime = ctx.runtime;
|
|
3763
|
+
const supportsInteractiveArgMenus = typeof ctx.app.action === "function";
|
|
3764
|
+
let supportsExternalArgMenus = typeof ctx.app.options === "function";
|
|
3765
|
+
const slashCommand = resolveSlackSlashCommandConfig(ctx.slashCommand ?? account.config.slashCommand);
|
|
3766
|
+
const handleSlashCommand = async (p) => {
|
|
3767
|
+
const { command, ack, respond, body, prompt, commandArgs, commandDefinition } = p;
|
|
3768
|
+
const cfg = getRuntimeConfigSnapshot() ?? ctx.cfg;
|
|
3769
|
+
try {
|
|
3770
|
+
if (ctx.shouldDropMismatchedSlackEvent?.(body)) {
|
|
3771
|
+
await ack();
|
|
3772
|
+
runtime.log?.(`slack: drop slash command from user=${command.user_id ?? "unknown"} channel=${command.channel_id ?? "unknown"} (mismatched app/team)`);
|
|
3773
|
+
return;
|
|
3774
|
+
}
|
|
3775
|
+
trackEvent?.();
|
|
3776
|
+
if (!prompt.trim()) {
|
|
3777
|
+
await ack({
|
|
3778
|
+
text: "Message required.",
|
|
3779
|
+
response_type: "ephemeral"
|
|
3780
|
+
});
|
|
3781
|
+
return;
|
|
3782
|
+
}
|
|
3783
|
+
await ack();
|
|
3784
|
+
if (ctx.botUserId && command.user_id === ctx.botUserId) return;
|
|
3785
|
+
const channelInfo = await ctx.resolveChannelName(command.channel_id);
|
|
3786
|
+
const channelType = normalizeSlackChannelType(channelInfo?.type ?? (command.channel_name === "directmessage" ? "im" : void 0), command.channel_id);
|
|
3787
|
+
const chatType = resolveSlackChatType(channelType);
|
|
3788
|
+
const isDirectMessage = channelType === "im";
|
|
3789
|
+
const isGroupDm = channelType === "mpim";
|
|
3790
|
+
const isRoom = channelType === "channel" || channelType === "group";
|
|
3791
|
+
const isRoomish = isRoom || isGroupDm;
|
|
3792
|
+
if (!ctx.isChannelAllowed({
|
|
3793
|
+
channelId: command.channel_id,
|
|
3794
|
+
channelName: channelInfo?.name,
|
|
3795
|
+
channelType
|
|
3796
|
+
})) {
|
|
3797
|
+
await respond({
|
|
3798
|
+
text: "This channel is not allowed.",
|
|
3799
|
+
response_type: "ephemeral"
|
|
3800
|
+
});
|
|
3801
|
+
return;
|
|
3802
|
+
}
|
|
3803
|
+
const effectiveAllowFromLower = await resolveSlackEffectiveAllowFrom(ctx, { includePairingStore: isDirectMessage });
|
|
3804
|
+
let commandAuthorized = false;
|
|
3805
|
+
let channelConfig = null;
|
|
3806
|
+
if (isDirectMessage) {
|
|
3807
|
+
if (!await authorizeSlackDirectMessage({
|
|
3808
|
+
ctx,
|
|
3809
|
+
accountId: ctx.accountId,
|
|
3810
|
+
senderId: command.user_id,
|
|
3811
|
+
allowFromLower: effectiveAllowFromLower,
|
|
3812
|
+
resolveSenderName: ctx.resolveUserName,
|
|
3813
|
+
sendPairingReply: async (text) => {
|
|
3814
|
+
await respond({
|
|
3815
|
+
text,
|
|
3816
|
+
response_type: "ephemeral"
|
|
3817
|
+
});
|
|
3818
|
+
},
|
|
3819
|
+
onDisabled: async () => {
|
|
3820
|
+
await respond({
|
|
3821
|
+
text: "Slack DMs are disabled.",
|
|
3822
|
+
response_type: "ephemeral"
|
|
3823
|
+
});
|
|
3824
|
+
},
|
|
3825
|
+
onUnauthorized: async ({ allowMatchMeta }) => {
|
|
3826
|
+
logVerbose(`slack: blocked slash sender ${command.user_id} (dmPolicy=${ctx.dmPolicy}, ${allowMatchMeta})`);
|
|
3827
|
+
await respond({
|
|
3828
|
+
text: "You are not authorized to use this command.",
|
|
3829
|
+
response_type: "ephemeral"
|
|
3830
|
+
});
|
|
3831
|
+
},
|
|
3832
|
+
log: logVerbose
|
|
3833
|
+
})) return;
|
|
3834
|
+
}
|
|
3835
|
+
if (isRoom) {
|
|
3836
|
+
channelConfig = resolveSlackChannelConfig({
|
|
3837
|
+
channelId: command.channel_id,
|
|
3838
|
+
channelName: channelInfo?.name,
|
|
3839
|
+
channels: ctx.channelsConfig,
|
|
3840
|
+
channelKeys: ctx.channelsConfigKeys,
|
|
3841
|
+
defaultRequireMention: ctx.defaultRequireMention,
|
|
3842
|
+
allowNameMatching: ctx.allowNameMatching
|
|
3843
|
+
});
|
|
3844
|
+
if (ctx.useAccessGroups) {
|
|
3845
|
+
const channelAllowlistConfigured = (ctx.channelsConfigKeys?.length ?? 0) > 0;
|
|
3846
|
+
const channelAllowed = channelConfig?.allowed !== false;
|
|
3847
|
+
if (!isSlackChannelAllowedByPolicy({
|
|
3848
|
+
groupPolicy: ctx.groupPolicy,
|
|
3849
|
+
channelAllowlistConfigured,
|
|
3850
|
+
channelAllowed
|
|
3851
|
+
})) {
|
|
3852
|
+
await respond({
|
|
3853
|
+
text: "This channel is not allowed.",
|
|
3854
|
+
response_type: "ephemeral"
|
|
3855
|
+
});
|
|
3856
|
+
return;
|
|
3857
|
+
}
|
|
3858
|
+
const hasExplicitConfig = Boolean(channelConfig?.matchSource);
|
|
3859
|
+
if (!channelAllowed && (ctx.groupPolicy !== "open" || hasExplicitConfig)) {
|
|
3860
|
+
await respond({
|
|
3861
|
+
text: "This channel is not allowed.",
|
|
3862
|
+
response_type: "ephemeral"
|
|
3863
|
+
});
|
|
3864
|
+
return;
|
|
3865
|
+
}
|
|
3866
|
+
}
|
|
3867
|
+
}
|
|
3868
|
+
const senderName = (await ctx.resolveUserName(command.user_id))?.name ?? command.user_name ?? command.user_id;
|
|
3869
|
+
const slashIngress = await resolveSlackCommandIngress({
|
|
3870
|
+
ctx,
|
|
3871
|
+
senderId: command.user_id,
|
|
3872
|
+
senderName,
|
|
3873
|
+
channelType: channelType ?? "channel",
|
|
3874
|
+
channelId: command.channel_id,
|
|
3875
|
+
ownerAllowFromLower: effectiveAllowFromLower,
|
|
3876
|
+
channelUsers: isRoom ? channelConfig?.users : void 0,
|
|
3877
|
+
allowTextCommands: false,
|
|
3878
|
+
hasControlCommand: false,
|
|
3879
|
+
eventKind: "slash-command",
|
|
3880
|
+
modeWhenAccessGroupsOff: "configured"
|
|
3881
|
+
});
|
|
3882
|
+
const senderGate = slashIngress.senderAccess.gate;
|
|
3883
|
+
if (isRoom && senderGate?.allowed === false) {
|
|
3884
|
+
await respond({
|
|
3885
|
+
text: "You are not authorized to use this command here.",
|
|
3886
|
+
response_type: "ephemeral"
|
|
3887
|
+
});
|
|
3888
|
+
return;
|
|
3889
|
+
}
|
|
3890
|
+
commandAuthorized = slashIngress.commandAccess.authorized;
|
|
3891
|
+
if (isRoomish) {
|
|
3892
|
+
if (ctx.useAccessGroups && !commandAuthorized) {
|
|
3893
|
+
await respond({
|
|
3894
|
+
text: "You are not authorized to use this command.",
|
|
3895
|
+
response_type: "ephemeral"
|
|
3896
|
+
});
|
|
3897
|
+
return;
|
|
3898
|
+
}
|
|
3899
|
+
}
|
|
3900
|
+
let resolvedSlashRoute;
|
|
3901
|
+
const resolveSlashRoute = async () => {
|
|
3902
|
+
if (resolvedSlashRoute) return resolvedSlashRoute;
|
|
3903
|
+
const { resolveAgentRoute } = await loadSlashDispatchRuntime();
|
|
3904
|
+
resolvedSlashRoute = resolveAgentRoute({
|
|
3905
|
+
cfg,
|
|
3906
|
+
channel: "slack",
|
|
3907
|
+
accountId: account.accountId,
|
|
3908
|
+
teamId: ctx.teamId || void 0,
|
|
3909
|
+
peer: {
|
|
3910
|
+
kind: isDirectMessage ? "direct" : isRoom ? "channel" : "group",
|
|
3911
|
+
id: isDirectMessage ? command.user_id : command.channel_id
|
|
3912
|
+
}
|
|
3913
|
+
});
|
|
3914
|
+
return resolvedSlashRoute;
|
|
3915
|
+
};
|
|
3916
|
+
if (commandDefinition && supportsInteractiveArgMenus) {
|
|
3917
|
+
const { resolveCommandArgMenu } = await loadSlashCommandsRuntime();
|
|
3918
|
+
const menuNeedsModelContext = !(commandArgs?.raw && !commandArgs.values) && commandDefinition.args?.some((arg) => typeof arg.choices === "function" && commandArgs?.values?.[arg.name] == null);
|
|
3919
|
+
const menuRoute = menuNeedsModelContext ? await resolveSlashRoute() : void 0;
|
|
3920
|
+
const menuModelContext = menuRoute ? resolveSlackCommandMenuModelContext({
|
|
3921
|
+
cfg,
|
|
3922
|
+
agentId: menuRoute.agentId,
|
|
3923
|
+
sessionKey: menuRoute.sessionKey
|
|
3924
|
+
}) : {};
|
|
3925
|
+
const menuModelCatalog = commandDefinition.key === "think" && menuNeedsModelContext ? await loadModelCatalog({
|
|
3926
|
+
config: cfg,
|
|
3927
|
+
readOnly: true
|
|
3928
|
+
}) : void 0;
|
|
3929
|
+
const menu = resolveCommandArgMenu({
|
|
3930
|
+
command: commandDefinition,
|
|
3931
|
+
args: commandArgs,
|
|
3932
|
+
cfg,
|
|
3933
|
+
...menuModelContext,
|
|
3934
|
+
...menuModelCatalog?.length ? { catalog: menuModelCatalog } : {}
|
|
3935
|
+
});
|
|
3936
|
+
if (menu) {
|
|
3937
|
+
const commandLabel = commandDefinition.nativeName ?? commandDefinition.key;
|
|
3938
|
+
const title = formatCommandArgMenuTitle({
|
|
3939
|
+
command: commandDefinition,
|
|
3940
|
+
menu
|
|
3941
|
+
});
|
|
3942
|
+
await respond({
|
|
3943
|
+
text: title,
|
|
3944
|
+
blocks: buildSlackCommandArgMenuBlocks({
|
|
3945
|
+
title,
|
|
3946
|
+
command: commandLabel,
|
|
3947
|
+
arg: menu.arg.name,
|
|
3948
|
+
choices: menu.choices,
|
|
3949
|
+
userId: command.user_id,
|
|
3950
|
+
supportsExternalSelect: supportsExternalArgMenus,
|
|
3951
|
+
createExternalMenuToken: (choices) => storeSlackExternalArgMenu({
|
|
3952
|
+
choices,
|
|
3953
|
+
userId: command.user_id
|
|
3954
|
+
})
|
|
3955
|
+
}),
|
|
3956
|
+
response_type: "ephemeral"
|
|
3957
|
+
});
|
|
3958
|
+
return;
|
|
3959
|
+
}
|
|
3960
|
+
}
|
|
3961
|
+
const channelName = channelInfo?.name;
|
|
3962
|
+
const roomLabel = channelName ? `#${channelName}` : `#${command.channel_id}`;
|
|
3963
|
+
const { deliverSlackSlashReplies, dispatchReplyWithDispatcher, finalizeInboundContext, recordInboundSessionMetaSafe, resolveAgentRoute, resolveChunkMode, resolveConversationLabel, resolveMarkdownTableMode } = await loadSlashDispatchRuntime();
|
|
3964
|
+
const route = resolvedSlashRoute ?? resolveAgentRoute({
|
|
3965
|
+
cfg,
|
|
3966
|
+
channel: "slack",
|
|
3967
|
+
accountId: account.accountId,
|
|
3968
|
+
teamId: ctx.teamId || void 0,
|
|
3969
|
+
peer: {
|
|
3970
|
+
kind: isDirectMessage ? "direct" : isRoom ? "channel" : "group",
|
|
3971
|
+
id: isDirectMessage ? command.user_id : command.channel_id
|
|
3972
|
+
}
|
|
3973
|
+
});
|
|
3974
|
+
const { untrustedChannelMetadata, groupSystemPrompt } = resolveSlackRoomContextHints({
|
|
3975
|
+
isRoomish,
|
|
3976
|
+
channelInfo,
|
|
3977
|
+
channelConfig
|
|
3978
|
+
});
|
|
3979
|
+
const { sessionKey, commandTargetSessionKey } = resolveNativeCommandSessionTargets({
|
|
3980
|
+
agentId: route.agentId,
|
|
3981
|
+
sessionPrefix: slashCommand.sessionPrefix,
|
|
3982
|
+
userId: command.user_id,
|
|
3983
|
+
targetSessionKey: route.sessionKey,
|
|
3984
|
+
lowercaseSessionKey: true
|
|
3985
|
+
});
|
|
3986
|
+
const slashReplyTarget = !slashCommand.ephemeral && isRoomish ? `channel:${command.channel_id}` : `user:${command.user_id}`;
|
|
3987
|
+
const ctxPayload = finalizeInboundContext({
|
|
3988
|
+
Body: prompt,
|
|
3989
|
+
BodyForAgent: prompt,
|
|
3990
|
+
RawBody: prompt,
|
|
3991
|
+
CommandBody: prompt,
|
|
3992
|
+
CommandArgs: commandArgs,
|
|
3993
|
+
From: isDirectMessage ? `slack:${command.user_id}` : isRoom ? `slack:channel:${command.channel_id}` : `slack:group:${command.channel_id}`,
|
|
3994
|
+
To: `slash:${command.user_id}`,
|
|
3995
|
+
ChatType: chatType,
|
|
3996
|
+
ConversationLabel: resolveConversationLabel({
|
|
3997
|
+
ChatType: chatType,
|
|
3998
|
+
SenderName: senderName,
|
|
3999
|
+
GroupSubject: isRoomish ? roomLabel : void 0,
|
|
4000
|
+
From: isDirectMessage ? `slack:${command.user_id}` : isRoom ? `slack:channel:${command.channel_id}` : `slack:group:${command.channel_id}`
|
|
4001
|
+
}) ?? (isDirectMessage ? senderName : roomLabel),
|
|
4002
|
+
GroupSubject: isRoomish ? roomLabel : void 0,
|
|
4003
|
+
GroupSpace: ctx.teamId || void 0,
|
|
4004
|
+
GroupSystemPrompt: groupSystemPrompt,
|
|
4005
|
+
UntrustedContext: untrustedChannelMetadata ? [untrustedChannelMetadata] : void 0,
|
|
4006
|
+
SenderName: senderName,
|
|
4007
|
+
SenderId: command.user_id,
|
|
4008
|
+
Provider: "slack",
|
|
4009
|
+
Surface: "slack",
|
|
4010
|
+
WasMentioned: true,
|
|
4011
|
+
MessageSid: command.trigger_id,
|
|
4012
|
+
Timestamp: Date.now(),
|
|
4013
|
+
SessionKey: sessionKey,
|
|
4014
|
+
CommandTargetSessionKey: commandTargetSessionKey,
|
|
4015
|
+
AccountId: route.accountId,
|
|
4016
|
+
CommandSource: "native",
|
|
4017
|
+
CommandAuthorized: commandAuthorized,
|
|
4018
|
+
OriginatingChannel: "slack",
|
|
4019
|
+
OriginatingTo: slashReplyTarget
|
|
4020
|
+
});
|
|
4021
|
+
await recordInboundSessionMetaSafe({
|
|
4022
|
+
cfg,
|
|
4023
|
+
agentId: route.agentId,
|
|
4024
|
+
sessionKey: ctxPayload.SessionKey ?? route.sessionKey,
|
|
4025
|
+
ctx: ctxPayload,
|
|
4026
|
+
onError: (err) => runtime.error?.(danger(`slack slash: failed updating session meta: ${formatErrorMessage(err)}`))
|
|
4027
|
+
});
|
|
4028
|
+
const { onModelSelected, ...replyPipeline } = createChannelMessageReplyPipeline({
|
|
4029
|
+
cfg,
|
|
4030
|
+
agentId: route.agentId,
|
|
4031
|
+
channel: "slack",
|
|
4032
|
+
accountId: route.accountId,
|
|
4033
|
+
transformReplyPayload: (payload) => {
|
|
4034
|
+
if (payload.isReasoning === true) return null;
|
|
4035
|
+
return isSlackInteractiveRepliesEnabled({
|
|
4036
|
+
cfg,
|
|
4037
|
+
accountId: route.accountId
|
|
4038
|
+
}) ? compileSlackInteractiveReplies(payload) : payload;
|
|
4039
|
+
}
|
|
4040
|
+
});
|
|
4041
|
+
const messageSentHookTarget = ctxPayload.OriginatingTo ?? ctxPayload.To ?? slashReplyTarget;
|
|
4042
|
+
const deliverSlashPayloads = async (replies) => {
|
|
4043
|
+
await deliverSlackSlashReplies({
|
|
4044
|
+
replies,
|
|
4045
|
+
respond,
|
|
4046
|
+
ephemeral: slashCommand.ephemeral,
|
|
4047
|
+
textLimit: ctx.textLimit,
|
|
4048
|
+
messageSentHookTarget,
|
|
4049
|
+
accountId: route.accountId,
|
|
4050
|
+
sessionKeyForInternalHooks: ctxPayload.SessionKey ?? route.sessionKey,
|
|
4051
|
+
isGroup: isRoomish,
|
|
4052
|
+
groupId: isRoomish ? command.channel_id : void 0,
|
|
4053
|
+
chunkMode: resolveChunkMode(cfg, "slack", route.accountId),
|
|
4054
|
+
tableMode: resolveMarkdownTableMode({
|
|
4055
|
+
cfg,
|
|
4056
|
+
channel: "slack",
|
|
4057
|
+
accountId: route.accountId
|
|
4058
|
+
})
|
|
4059
|
+
});
|
|
4060
|
+
};
|
|
4061
|
+
const { counts } = await dispatchReplyWithDispatcher({
|
|
4062
|
+
ctx: ctxPayload,
|
|
4063
|
+
cfg,
|
|
4064
|
+
dispatcherOptions: {
|
|
4065
|
+
...replyPipeline,
|
|
4066
|
+
deliver: async (payload) => deliverSlashPayloads([payload]),
|
|
4067
|
+
onError: (err, info) => {
|
|
4068
|
+
runtime.error?.(danger(`slack slash ${info.kind} reply failed: ${formatSlackError(err)}`));
|
|
4069
|
+
}
|
|
4070
|
+
},
|
|
4071
|
+
replyOptions: {
|
|
4072
|
+
skillFilter: channelConfig?.skills,
|
|
4073
|
+
onModelSelected
|
|
4074
|
+
}
|
|
4075
|
+
});
|
|
4076
|
+
if (counts.final + counts.tool + counts.block === 0) await deliverSlashPayloads([]);
|
|
4077
|
+
} catch (err) {
|
|
4078
|
+
runtime.error?.(danger(`slack slash handler failed: ${formatErrorMessage(err)}`));
|
|
4079
|
+
await respond({
|
|
4080
|
+
text: "Sorry, something went wrong handling that command.",
|
|
4081
|
+
response_type: "ephemeral"
|
|
4082
|
+
});
|
|
4083
|
+
}
|
|
4084
|
+
};
|
|
4085
|
+
const nativeEnabled = resolveNativeCommandsEnabled({
|
|
4086
|
+
providerId: "slack",
|
|
4087
|
+
providerSetting: account.config.commands?.native,
|
|
4088
|
+
globalSetting: startupCfg.commands?.native
|
|
4089
|
+
});
|
|
4090
|
+
const nativeSkillsEnabled = resolveNativeSkillsEnabled({
|
|
4091
|
+
providerId: "slack",
|
|
4092
|
+
providerSetting: account.config.commands?.nativeSkills,
|
|
4093
|
+
globalSetting: startupCfg.commands?.nativeSkills
|
|
4094
|
+
});
|
|
4095
|
+
let nativeCommands = [];
|
|
4096
|
+
let slashCommandsRuntime = null;
|
|
4097
|
+
if (nativeEnabled) {
|
|
4098
|
+
slashCommandsRuntime = await loadSlashCommandsRuntime();
|
|
4099
|
+
const skillCommands = nativeSkillsEnabled ? (await loadSlashSkillCommandsRuntime()).listSkillCommandsForAgents({ cfg: startupCfg }) : [];
|
|
4100
|
+
nativeCommands = slashCommandsRuntime.listNativeCommandSpecsForConfig(startupCfg, {
|
|
4101
|
+
skillCommands,
|
|
4102
|
+
provider: "slack"
|
|
4103
|
+
});
|
|
4104
|
+
const existingNativeNames = new Set(normalizeStringEntriesLower(nativeCommands.map((command) => command.name)));
|
|
4105
|
+
const { listProviderPluginCommandSpecs } = await loadSlackPluginCommandsRuntime();
|
|
4106
|
+
for (const pluginCommand of listProviderPluginCommandSpecs("slack")) {
|
|
4107
|
+
const normalizedName = normalizeLowercaseStringOrEmpty(pluginCommand.name);
|
|
4108
|
+
if (!normalizedName || existingNativeNames.has(normalizedName)) continue;
|
|
4109
|
+
existingNativeNames.add(normalizedName);
|
|
4110
|
+
nativeCommands.push(pluginCommand);
|
|
4111
|
+
}
|
|
4112
|
+
}
|
|
4113
|
+
if (nativeCommands.length > 0) {
|
|
4114
|
+
if (!slashCommandsRuntime) throw new Error("Missing commands runtime for native Slack commands.");
|
|
4115
|
+
for (const command of nativeCommands) ctx.app.command(`/${command.name}`, async ({ command: cmd, ack, respond, body }) => {
|
|
4116
|
+
const commandDefinition = slashCommandsRuntime.findCommandByNativeName(command.name, "slack");
|
|
4117
|
+
const rawText = cmd.text?.trim() ?? "";
|
|
4118
|
+
const commandArgs = commandDefinition ? slashCommandsRuntime.parseCommandArgs(commandDefinition, rawText) : rawText ? { raw: rawText } : void 0;
|
|
4119
|
+
const prompt = commandDefinition ? slashCommandsRuntime.buildCommandTextFromArgs(commandDefinition, commandArgs) : rawText ? `/${command.name} ${rawText}` : `/${command.name}`;
|
|
4120
|
+
await handleSlashCommand({
|
|
4121
|
+
command: cmd,
|
|
4122
|
+
ack,
|
|
4123
|
+
respond,
|
|
4124
|
+
body,
|
|
4125
|
+
prompt,
|
|
4126
|
+
commandArgs,
|
|
4127
|
+
commandDefinition: commandDefinition ?? void 0
|
|
4128
|
+
});
|
|
4129
|
+
});
|
|
4130
|
+
} else if (slashCommand.enabled) ctx.app.command(buildSlackSlashCommandMatcher(slashCommand.name), async ({ command, ack, respond, body }) => {
|
|
4131
|
+
await handleSlashCommand({
|
|
4132
|
+
command,
|
|
4133
|
+
ack,
|
|
4134
|
+
respond,
|
|
4135
|
+
body,
|
|
4136
|
+
prompt: command.text?.trim() ?? ""
|
|
4137
|
+
});
|
|
4138
|
+
});
|
|
4139
|
+
else logVerbose("slack: slash commands disabled");
|
|
4140
|
+
if (nativeCommands.length === 0 || !supportsInteractiveArgMenus) return;
|
|
4141
|
+
const registerArgOptions = () => {
|
|
4142
|
+
const appWithOptions = ctx.app;
|
|
4143
|
+
if (typeof appWithOptions.options !== "function") return;
|
|
4144
|
+
appWithOptions.options(SLACK_COMMAND_ARG_ACTION_ID, async ({ ack, body }) => {
|
|
4145
|
+
if (ctx.shouldDropMismatchedSlackEvent?.(body)) {
|
|
4146
|
+
await ack({ options: [] });
|
|
4147
|
+
runtime.log?.("slack: drop slash arg options payload (mismatched app/team)");
|
|
4148
|
+
return;
|
|
4149
|
+
}
|
|
4150
|
+
trackEvent?.();
|
|
4151
|
+
const typedBody = body;
|
|
4152
|
+
const token = readSlackExternalArgMenuToken(typedBody.actions?.[0]?.block_id ?? typedBody.block_id);
|
|
4153
|
+
if (!token) {
|
|
4154
|
+
await ack({ options: [] });
|
|
4155
|
+
return;
|
|
4156
|
+
}
|
|
4157
|
+
const entry = slackExternalArgMenuStore.get(token);
|
|
4158
|
+
if (!entry) {
|
|
4159
|
+
await ack({ options: [] });
|
|
4160
|
+
return;
|
|
4161
|
+
}
|
|
4162
|
+
const requesterUserId = typedBody.user?.id?.trim();
|
|
4163
|
+
if (!requesterUserId || requesterUserId !== entry.userId) {
|
|
4164
|
+
await ack({ options: [] });
|
|
4165
|
+
return;
|
|
4166
|
+
}
|
|
4167
|
+
const query = normalizeLowercaseStringOrEmpty(typedBody.value);
|
|
4168
|
+
await ack({ options: entry.choices.filter((choice) => !query || normalizeLowercaseStringOrEmpty(choice.label).includes(query)).slice(0, SLACK_COMMAND_ARG_SELECT_OPTIONS_MAX).map((choice) => ({
|
|
4169
|
+
text: {
|
|
4170
|
+
type: "plain_text",
|
|
4171
|
+
text: truncateSlackText(choice.label, SLACK_COMMAND_ARG_SELECT_OPTION_TEXT_MAX)
|
|
4172
|
+
},
|
|
4173
|
+
value: choice.value
|
|
4174
|
+
})) });
|
|
4175
|
+
});
|
|
4176
|
+
};
|
|
4177
|
+
try {
|
|
4178
|
+
registerArgOptions();
|
|
4179
|
+
} catch (err) {
|
|
4180
|
+
supportsExternalArgMenus = false;
|
|
4181
|
+
runtime.log?.(warn("slack: external arg-menu registration failed; falling back to static slash command menus. Enable verbose logs for details."));
|
|
4182
|
+
logVerbose(`slack: external arg-menu registration failed, falling back to static menus: ${formatErrorMessage(err)}`);
|
|
4183
|
+
}
|
|
4184
|
+
const registerArgAction = (actionId) => {
|
|
4185
|
+
ctx.app.action(actionId, async (args) => {
|
|
4186
|
+
const { ack, body, respond } = args;
|
|
4187
|
+
const action = args.action;
|
|
4188
|
+
await ack();
|
|
4189
|
+
if (ctx.shouldDropMismatchedSlackEvent?.(body)) {
|
|
4190
|
+
runtime.log?.("slack: drop slash arg action payload (mismatched app/team)");
|
|
4191
|
+
return;
|
|
4192
|
+
}
|
|
4193
|
+
const respondFn = respond ?? (async (payload) => {
|
|
4194
|
+
if (!body.channel?.id || !body.user?.id) return;
|
|
4195
|
+
await ctx.app.client.chat.postEphemeral({
|
|
4196
|
+
token: ctx.botToken,
|
|
4197
|
+
channel: body.channel.id,
|
|
4198
|
+
user: body.user.id,
|
|
4199
|
+
text: payload.text,
|
|
4200
|
+
blocks: payload.blocks
|
|
4201
|
+
});
|
|
4202
|
+
});
|
|
4203
|
+
const parsed = parseSlackCommandArgValue(action?.value ?? action?.selected_option?.value);
|
|
4204
|
+
if (!parsed) {
|
|
4205
|
+
await respondFn({
|
|
4206
|
+
text: "Sorry, that button is no longer valid.",
|
|
4207
|
+
response_type: "ephemeral"
|
|
4208
|
+
});
|
|
4209
|
+
return;
|
|
4210
|
+
}
|
|
4211
|
+
if (body.user?.id && parsed.userId !== body.user.id) {
|
|
4212
|
+
await respondFn({
|
|
4213
|
+
text: "That menu is for another user.",
|
|
4214
|
+
response_type: "ephemeral"
|
|
4215
|
+
});
|
|
4216
|
+
return;
|
|
4217
|
+
}
|
|
4218
|
+
const { buildCommandTextFromArgs, findCommandByNativeName } = await loadSlashCommandsRuntime();
|
|
4219
|
+
const commandDefinition = findCommandByNativeName(parsed.command, "slack");
|
|
4220
|
+
const commandArgs = { values: { [parsed.arg]: parsed.value } };
|
|
4221
|
+
const prompt = commandDefinition ? buildCommandTextFromArgs(commandDefinition, commandArgs) : `/${parsed.command} ${parsed.value}`;
|
|
4222
|
+
const user = body.user;
|
|
4223
|
+
const userName = user && "name" in user && user.name ? user.name : user && "username" in user && user.username ? user.username : user?.id ?? "";
|
|
4224
|
+
const triggerId = "trigger_id" in body ? body.trigger_id : void 0;
|
|
4225
|
+
const commandPayload = {
|
|
4226
|
+
user_id: user?.id ?? "",
|
|
4227
|
+
user_name: userName,
|
|
4228
|
+
channel_id: body.channel?.id ?? "",
|
|
4229
|
+
channel_name: body.channel?.name ?? body.channel?.id ?? "",
|
|
4230
|
+
trigger_id: triggerId
|
|
4231
|
+
};
|
|
4232
|
+
await handleSlashCommand({
|
|
4233
|
+
command: commandPayload,
|
|
4234
|
+
ack: async () => {},
|
|
4235
|
+
respond: respondFn,
|
|
4236
|
+
body,
|
|
4237
|
+
prompt,
|
|
4238
|
+
commandArgs,
|
|
4239
|
+
commandDefinition: commandDefinition ?? void 0
|
|
4240
|
+
});
|
|
4241
|
+
});
|
|
4242
|
+
};
|
|
4243
|
+
registerArgAction(SLACK_COMMAND_ARG_ACTION_LISTENER);
|
|
4244
|
+
}
|
|
4245
|
+
//#endregion
|
|
4246
|
+
//#region extensions/slack/src/monitor/provider.ts
|
|
4247
|
+
let slackBoltInterop;
|
|
4248
|
+
async function getSlackBoltInterop() {
|
|
4249
|
+
if (!slackBoltInterop) {
|
|
4250
|
+
const slackBoltModule = await import("@slack/bolt");
|
|
4251
|
+
slackBoltInterop = resolveSlackBoltInterop({
|
|
4252
|
+
defaultImport: slackBoltModule.default,
|
|
4253
|
+
namespaceImport: slackBoltModule
|
|
4254
|
+
});
|
|
4255
|
+
}
|
|
4256
|
+
return slackBoltInterop;
|
|
4257
|
+
}
|
|
4258
|
+
const loadSlackRelaySource = createLazyRuntimeModule(() => import("./relay-source-DR--lDW8.mjs"));
|
|
4259
|
+
const SLACK_WEBHOOK_MAX_BODY_BYTES = 1048576;
|
|
4260
|
+
const SLACK_WEBHOOK_BODY_TIMEOUT_MS = 3e4;
|
|
4261
|
+
function resolveStableSlackUserIdEntry(raw) {
|
|
4262
|
+
const trimmed = raw.trim();
|
|
4263
|
+
if (!trimmed) return;
|
|
4264
|
+
const mention = /^<@([A-Z][A-Z0-9]+)>$/i.exec(trimmed);
|
|
4265
|
+
if (mention) return mention[1]?.toUpperCase();
|
|
4266
|
+
const prefixed = /^(?:slack:|user:)([A-Z][A-Z0-9]+)$/i.exec(trimmed);
|
|
4267
|
+
if (prefixed) return prefixed[1]?.toUpperCase();
|
|
4268
|
+
return /^[UW][A-Z0-9]+$/i.test(trimmed) ? trimmed.toUpperCase() : void 0;
|
|
4269
|
+
}
|
|
4270
|
+
function resolveStableSlackUserAllowlistEntries(entries) {
|
|
4271
|
+
const resolved = [];
|
|
4272
|
+
for (const input of entries) {
|
|
4273
|
+
const id = resolveStableSlackUserIdEntry(input);
|
|
4274
|
+
if (id) resolved.push({
|
|
4275
|
+
input,
|
|
4276
|
+
resolved: true,
|
|
4277
|
+
id
|
|
4278
|
+
});
|
|
4279
|
+
}
|
|
4280
|
+
return resolved;
|
|
4281
|
+
}
|
|
4282
|
+
function formatSlackSocketReconnectMessage(params) {
|
|
4283
|
+
const suffix = params.error ? ` (${formatUnknownError(params.error)})` : "";
|
|
4284
|
+
return `slack socket disconnected (${params.event}); reconnecting in ${Math.round(params.delayMs / 1e3)}s (attempt ${params.attempt}/∞)${suffix}`;
|
|
4285
|
+
}
|
|
4286
|
+
function formatSlackSocketStartRetryMessage(params) {
|
|
4287
|
+
const reason = formatUnknownError(params.error, "Slack Socket Mode start failed without error detail");
|
|
4288
|
+
const sdkContext = params.sdkContext?.trim() ? `; last SDK log: ${params.sdkContext.trim()}` : "";
|
|
4289
|
+
return `slack socket mode failed to start; retry ${params.attempt}/∞ in ${Math.round(params.delayMs / 1e3)}s reason="${reason}${sdkContext}"`;
|
|
4290
|
+
}
|
|
4291
|
+
function parseApiAppIdFromAppToken(raw) {
|
|
4292
|
+
const token = raw?.trim();
|
|
4293
|
+
if (!token) return;
|
|
4294
|
+
return /^xapp-\d-([a-z0-9]+)-/i.exec(token)?.[1]?.toUpperCase();
|
|
4295
|
+
}
|
|
4296
|
+
function resolveSlackRelayConfig(params) {
|
|
4297
|
+
const relay = params.relay && typeof params.relay === "object" && !Array.isArray(params.relay) ? params.relay : {};
|
|
4298
|
+
const url = normalizeOptionalString(relay.url);
|
|
4299
|
+
const authToken = normalizeResolvedSecretInputString({
|
|
4300
|
+
value: relay.authToken,
|
|
4301
|
+
path: `channels.slack.accounts.${params.accountId}.relay.authToken`
|
|
4302
|
+
});
|
|
4303
|
+
const gatewayId = normalizeOptionalString(relay.gatewayId);
|
|
4304
|
+
if (!url || !authToken || !gatewayId) throw new Error(`Slack relay mode requires relay.url, relay.authToken, and relay.gatewayId for account "${params.accountId}".`);
|
|
4305
|
+
return {
|
|
4306
|
+
url,
|
|
4307
|
+
authToken,
|
|
4308
|
+
gatewayId
|
|
4309
|
+
};
|
|
4310
|
+
}
|
|
4311
|
+
async function monitorSlackProvider(opts = {}) {
|
|
4312
|
+
const cfg = opts.config ?? getRuntimeConfig$1();
|
|
4313
|
+
const runtime = opts.runtime ?? createNonExitingRuntime();
|
|
4314
|
+
const account = resolveSlackAccount({
|
|
4315
|
+
cfg,
|
|
4316
|
+
accountId: opts.accountId
|
|
4317
|
+
});
|
|
4318
|
+
if (!account.enabled) {
|
|
4319
|
+
runtime.log?.(`[${account.accountId}] slack account disabled; monitor startup skipped`);
|
|
4320
|
+
if (opts.abortSignal?.aborted) return;
|
|
4321
|
+
await new Promise((resolve) => {
|
|
4322
|
+
opts.abortSignal?.addEventListener("abort", () => resolve(), { once: true });
|
|
4323
|
+
});
|
|
4324
|
+
return;
|
|
4325
|
+
}
|
|
4326
|
+
const historyLimit = Math.max(0, account.config.historyLimit ?? cfg.messages?.groupChat?.historyLimit ?? DEFAULT_GROUP_HISTORY_LIMIT);
|
|
4327
|
+
const dmHistoryLimit = Math.max(0, account.config.dmHistoryLimit ?? 0);
|
|
4328
|
+
const sessionCfg = cfg.session;
|
|
4329
|
+
const sessionScope = sessionCfg?.scope ?? "per-sender";
|
|
4330
|
+
const mainKey = normalizeMainKey(sessionCfg?.mainKey);
|
|
4331
|
+
const slackMode = opts.mode ?? account.config.mode ?? "socket";
|
|
4332
|
+
const slackWebhookPath = normalizeSlackWebhookPath(account.config.webhookPath);
|
|
4333
|
+
const signingSecret = normalizeResolvedSecretInputString({
|
|
4334
|
+
value: account.config.signingSecret,
|
|
4335
|
+
path: `channels.slack.accounts.${account.accountId}.signingSecret`
|
|
4336
|
+
});
|
|
4337
|
+
const botToken = resolveSlackBotToken(opts.botToken ?? account.botToken);
|
|
4338
|
+
const appToken = resolveSlackAppToken(opts.appToken ?? account.appToken);
|
|
4339
|
+
const relayConfig = slackMode === "relay" ? resolveSlackRelayConfig({
|
|
4340
|
+
relay: account.config.relay,
|
|
4341
|
+
accountId: account.accountId
|
|
4342
|
+
}) : void 0;
|
|
4343
|
+
if (!botToken || slackMode === "socket" && !appToken) {
|
|
4344
|
+
const missing = slackMode === "http" ? `Slack bot token missing for account "${account.accountId}" (set channels.slack.accounts.${account.accountId}.botToken or SLACK_BOT_TOKEN for default).` : slackMode === "relay" ? `Slack bot token missing for account "${account.accountId}" (set channels.slack.accounts.${account.accountId}.botToken or SLACK_BOT_TOKEN for default).` : `Slack bot + app tokens missing for account "${account.accountId}" (set channels.slack.accounts.${account.accountId}.botToken/appToken or SLACK_BOT_TOKEN/SLACK_APP_TOKEN for default).`;
|
|
4345
|
+
throw new Error(missing);
|
|
4346
|
+
}
|
|
4347
|
+
if (slackMode === "http" && !signingSecret) throw new Error(`Slack signing secret missing for account "${account.accountId}" (set channels.slack.signingSecret or channels.slack.accounts.${account.accountId}.signingSecret).`);
|
|
4348
|
+
const slackCfg = account.config;
|
|
4349
|
+
const dmConfig = slackCfg.dm;
|
|
4350
|
+
const dmEnabled = dmConfig?.enabled ?? true;
|
|
4351
|
+
const dmPolicy = resolveSlackAccountDmPolicy({
|
|
4352
|
+
cfg,
|
|
4353
|
+
accountId: account.accountId
|
|
4354
|
+
}) ?? "pairing";
|
|
4355
|
+
let allowFrom = resolveSlackAccountAllowFrom({
|
|
4356
|
+
cfg,
|
|
4357
|
+
accountId: account.accountId
|
|
4358
|
+
});
|
|
4359
|
+
const groupDmEnabled = dmConfig?.groupEnabled ?? false;
|
|
4360
|
+
const groupDmChannels = dmConfig?.groupChannels;
|
|
4361
|
+
let channelsConfig = slackCfg.channels;
|
|
4362
|
+
const defaultGroupPolicy = resolveDefaultGroupPolicy(cfg);
|
|
4363
|
+
const providerConfigPresent = cfg.channels?.slack !== void 0;
|
|
4364
|
+
const { groupPolicy, providerMissingFallbackApplied } = resolveOpenProviderRuntimeGroupPolicy$1({
|
|
4365
|
+
providerConfigPresent,
|
|
4366
|
+
groupPolicy: slackCfg.groupPolicy,
|
|
4367
|
+
defaultGroupPolicy
|
|
4368
|
+
});
|
|
4369
|
+
warnMissingProviderGroupPolicyFallbackOnce({
|
|
4370
|
+
providerMissingFallbackApplied,
|
|
4371
|
+
providerKey: "slack",
|
|
4372
|
+
accountId: account.accountId,
|
|
4373
|
+
log: (message) => runtime.log?.(warn(message))
|
|
4374
|
+
});
|
|
4375
|
+
const resolveToken = account.userToken || botToken;
|
|
4376
|
+
const useAccessGroups = cfg.commands?.useAccessGroups !== false;
|
|
4377
|
+
const reactionMode = slackCfg.reactionNotifications ?? "own";
|
|
4378
|
+
const reactionAllowlist = slackCfg.reactionAllowlist ?? [];
|
|
4379
|
+
const replyToMode = slackCfg.replyToMode ?? "off";
|
|
4380
|
+
const threadHistoryScope = slackCfg.thread?.historyScope ?? "thread";
|
|
4381
|
+
const threadInheritParent = slackCfg.thread?.inheritParent ?? false;
|
|
4382
|
+
const threadRequireExplicitMention = slackCfg.thread?.requireExplicitMention ?? false;
|
|
4383
|
+
const slashCommand = resolveSlackSlashCommandConfig(opts.slashCommand ?? slackCfg.slashCommand);
|
|
4384
|
+
const allowNameMatching = isDangerousNameMatchingEnabled(slackCfg);
|
|
4385
|
+
const textLimit = resolveTextChunkLimit(cfg, "slack", account.accountId, { fallbackLimit: SLACK_TEXT_LIMIT });
|
|
4386
|
+
const ackReactionScope = cfg.messages?.ackReactionScope ?? "group-mentions";
|
|
4387
|
+
const typingReaction = slackCfg.typingReaction?.trim() ?? "";
|
|
4388
|
+
const mediaMaxBytes = (opts.mediaMaxMb ?? slackCfg.mediaMaxMb ?? 20) * 1024 * 1024;
|
|
4389
|
+
const removeAckAfterReply = cfg.messages?.removeAckAfterReply ?? false;
|
|
4390
|
+
const clientOptions = resolveSlackWebClientOptions();
|
|
4391
|
+
const { app, receiver, socketModeLogger } = createSlackBoltApp({
|
|
4392
|
+
interop: await getSlackBoltInterop(),
|
|
4393
|
+
slackMode,
|
|
4394
|
+
botToken,
|
|
4395
|
+
appToken: slackMode === "socket" ? appToken ?? void 0 : void 0,
|
|
4396
|
+
signingSecret: slackMode === "http" ? signingSecret ?? void 0 : void 0,
|
|
4397
|
+
slackWebhookPath,
|
|
4398
|
+
clientOptions,
|
|
4399
|
+
...slackCfg.socketMode ? { socketMode: slackCfg.socketMode } : {}
|
|
4400
|
+
});
|
|
4401
|
+
const gracefulStop = async () => {
|
|
4402
|
+
await gracefulStopSlackApp(app);
|
|
4403
|
+
};
|
|
4404
|
+
const slackHttpHandler = slackMode === "http" && receiver ? async (req, res) => {
|
|
4405
|
+
const httpReceiver = receiver;
|
|
4406
|
+
const guard = installRequestBodyLimitGuard(req, res, {
|
|
4407
|
+
maxBytes: SLACK_WEBHOOK_MAX_BODY_BYTES,
|
|
4408
|
+
timeoutMs: SLACK_WEBHOOK_BODY_TIMEOUT_MS,
|
|
4409
|
+
responseFormat: "text"
|
|
4410
|
+
});
|
|
4411
|
+
if (guard.isTripped()) return;
|
|
4412
|
+
try {
|
|
4413
|
+
await Promise.resolve(httpReceiver.requestListener(req, res));
|
|
4414
|
+
} catch (err) {
|
|
4415
|
+
if (!guard.isTripped()) throw err;
|
|
4416
|
+
} finally {
|
|
4417
|
+
guard.dispose();
|
|
4418
|
+
}
|
|
4419
|
+
} : null;
|
|
4420
|
+
let unregisterHttpHandler = null;
|
|
4421
|
+
const unregisterSocketModeConnectionDiagnostics = slackMode === "socket" ? registerSlackSocketModeConnectionDiagnostics({
|
|
4422
|
+
app,
|
|
4423
|
+
onSharedConnection: (activeConnections) => {
|
|
4424
|
+
runtime.log?.(warn(formatSlackSocketModeSharedConnectionWarning(activeConnections)));
|
|
4425
|
+
}
|
|
4426
|
+
}) : () => {};
|
|
4427
|
+
let botUserId = "";
|
|
4428
|
+
let botId = "";
|
|
4429
|
+
let teamId = "";
|
|
4430
|
+
let apiAppId = "";
|
|
4431
|
+
const expectedApiAppIdFromAppToken = slackMode === "socket" ? parseApiAppIdFromAppToken(appToken) : void 0;
|
|
4432
|
+
let authTestFailed = false;
|
|
4433
|
+
let authTestError;
|
|
4434
|
+
let authIdentityWarning;
|
|
4435
|
+
try {
|
|
4436
|
+
const auth = await app.client.auth.test();
|
|
4437
|
+
const authUserId = normalizeOptionalString(auth.user_id) ?? "";
|
|
4438
|
+
botId = normalizeOptionalString(auth.bot_id) ?? "";
|
|
4439
|
+
botUserId = botId ? authUserId : "";
|
|
4440
|
+
teamId = auth.team_id ?? "";
|
|
4441
|
+
apiAppId = auth.api_app_id ?? "";
|
|
4442
|
+
authIdentityWarning = formatSlackBotTokenIdentityWarning({
|
|
4443
|
+
auth,
|
|
4444
|
+
accountId: account.accountId
|
|
4445
|
+
});
|
|
4446
|
+
if (!authUserId) {
|
|
4447
|
+
authTestFailed = true;
|
|
4448
|
+
authTestError = "auth.test returned no user_id";
|
|
4449
|
+
}
|
|
4450
|
+
} catch (err) {
|
|
4451
|
+
authTestFailed = true;
|
|
4452
|
+
authTestError = err instanceof Error ? err.message : String(err);
|
|
4453
|
+
}
|
|
4454
|
+
if (authTestFailed) runtime.log?.(warn(`[${account.accountId}] slack auth.test failed at boot (${authTestError ?? "unknown error"}); explicit bot-mention detection will be disabled until restart with a valid bot token; required-mention channels will fail closed without another trusted activation signal`));
|
|
4455
|
+
if (authIdentityWarning) runtime.log?.(warn(authIdentityWarning));
|
|
4456
|
+
if (apiAppId && expectedApiAppIdFromAppToken && apiAppId !== expectedApiAppIdFromAppToken) runtime.error?.(`slack token mismatch: bot token api_app_id=${apiAppId} but app token looks like api_app_id=${expectedApiAppIdFromAppToken}`);
|
|
4457
|
+
const ctx = createSlackMonitorContext({
|
|
4458
|
+
cfg,
|
|
4459
|
+
accountId: account.accountId,
|
|
4460
|
+
botToken,
|
|
4461
|
+
app,
|
|
4462
|
+
runtime,
|
|
4463
|
+
channelRuntime: opts.channelRuntime,
|
|
4464
|
+
botUserId,
|
|
4465
|
+
botId,
|
|
4466
|
+
teamId,
|
|
4467
|
+
apiAppId,
|
|
4468
|
+
historyLimit,
|
|
4469
|
+
dmHistoryLimit,
|
|
4470
|
+
sessionScope,
|
|
4471
|
+
mainKey,
|
|
4472
|
+
dmEnabled,
|
|
4473
|
+
dmPolicy,
|
|
4474
|
+
allowFrom,
|
|
4475
|
+
allowNameMatching,
|
|
4476
|
+
groupDmEnabled,
|
|
4477
|
+
groupDmChannels,
|
|
4478
|
+
defaultRequireMention: slackCfg.requireMention,
|
|
4479
|
+
channelsConfig,
|
|
4480
|
+
groupPolicy,
|
|
4481
|
+
useAccessGroups,
|
|
4482
|
+
reactionMode,
|
|
4483
|
+
reactionAllowlist,
|
|
4484
|
+
replyToMode,
|
|
4485
|
+
threadHistoryScope,
|
|
4486
|
+
threadInheritParent,
|
|
4487
|
+
threadRequireExplicitMention,
|
|
4488
|
+
slashCommand,
|
|
4489
|
+
textLimit,
|
|
4490
|
+
ackReactionScope,
|
|
4491
|
+
typingReaction,
|
|
4492
|
+
mediaMaxBytes,
|
|
4493
|
+
removeAckAfterReply
|
|
4494
|
+
});
|
|
4495
|
+
const trackEvent = opts.setStatus ? () => {
|
|
4496
|
+
opts.setStatus({
|
|
4497
|
+
lastEventAt: Date.now(),
|
|
4498
|
+
lastInboundAt: Date.now()
|
|
4499
|
+
});
|
|
4500
|
+
} : void 0;
|
|
4501
|
+
const handleSlackMessage = createSlackMessageHandler({
|
|
4502
|
+
ctx,
|
|
4503
|
+
account,
|
|
4504
|
+
trackEvent
|
|
4505
|
+
});
|
|
4506
|
+
if (isSlackAnyNativeApprovalClientEnabled({
|
|
4507
|
+
cfg,
|
|
4508
|
+
accountId: account.accountId
|
|
4509
|
+
})) registerChannelRuntimeContext({
|
|
4510
|
+
channelRuntime: opts.channelRuntime,
|
|
4511
|
+
channelId: "slack",
|
|
4512
|
+
accountId: account.accountId,
|
|
4513
|
+
capability: CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY,
|
|
4514
|
+
context: {
|
|
4515
|
+
app,
|
|
4516
|
+
config: slackCfg.execApprovals ?? {}
|
|
4517
|
+
},
|
|
4518
|
+
abortSignal: opts.abortSignal
|
|
4519
|
+
});
|
|
4520
|
+
registerSlackMonitorEvents({
|
|
4521
|
+
ctx,
|
|
4522
|
+
account,
|
|
4523
|
+
handleSlackMessage,
|
|
4524
|
+
trackEvent
|
|
4525
|
+
});
|
|
4526
|
+
await registerSlackMonitorSlashCommands({
|
|
4527
|
+
ctx,
|
|
4528
|
+
account,
|
|
4529
|
+
trackEvent
|
|
4530
|
+
});
|
|
4531
|
+
if (slackMode === "http" && slackHttpHandler) unregisterHttpHandler = registerSlackHttpHandler({
|
|
4532
|
+
path: slackWebhookPath,
|
|
4533
|
+
handler: slackHttpHandler,
|
|
4534
|
+
log: runtime.log,
|
|
4535
|
+
accountId: account.accountId
|
|
4536
|
+
});
|
|
4537
|
+
if (resolveToken) (async () => {
|
|
4538
|
+
if (opts.abortSignal?.aborted) return;
|
|
4539
|
+
if (channelsConfig && Object.keys(channelsConfig).length > 0) try {
|
|
4540
|
+
const entries = Object.keys(channelsConfig).filter((key) => key !== "*");
|
|
4541
|
+
if (entries.length > 0) {
|
|
4542
|
+
const resolved = await resolveSlackChannelAllowlist({
|
|
4543
|
+
token: resolveToken,
|
|
4544
|
+
entries
|
|
4545
|
+
});
|
|
4546
|
+
const nextChannels = { ...channelsConfig };
|
|
4547
|
+
const mapping = [];
|
|
4548
|
+
const unresolved = [];
|
|
4549
|
+
for (const entry of resolved) {
|
|
4550
|
+
const source = channelsConfig?.[entry.input];
|
|
4551
|
+
if (!source) continue;
|
|
4552
|
+
if (!entry.resolved || !entry.id) {
|
|
4553
|
+
unresolved.push(entry.input);
|
|
4554
|
+
continue;
|
|
4555
|
+
}
|
|
4556
|
+
mapping.push(formatSlackChannelResolved(entry));
|
|
4557
|
+
const existing = nextChannels[entry.id] ?? {};
|
|
4558
|
+
nextChannels[entry.id] = {
|
|
4559
|
+
...source,
|
|
4560
|
+
...existing
|
|
4561
|
+
};
|
|
4562
|
+
}
|
|
4563
|
+
channelsConfig = nextChannels;
|
|
4564
|
+
ctx.channelsConfig = nextChannels;
|
|
4565
|
+
summarizeMapping("slack channels", mapping, unresolved, runtime);
|
|
4566
|
+
}
|
|
4567
|
+
} catch (err) {
|
|
4568
|
+
runtime.log?.(`slack channel resolve failed; using config entries. ${formatUnknownError(err)}`);
|
|
4569
|
+
}
|
|
4570
|
+
const allowEntries = normalizeStringEntries(allowFrom).filter((entry) => entry !== "*");
|
|
4571
|
+
if (allowEntries.length > 0) {
|
|
4572
|
+
const stableResolvedUsers = resolveStableSlackUserAllowlistEntries(allowEntries);
|
|
4573
|
+
if (stableResolvedUsers.length > 0) {
|
|
4574
|
+
const { mapping, additions } = buildAllowlistResolutionSummary(stableResolvedUsers, { formatResolved: formatSlackUserResolved });
|
|
4575
|
+
allowFrom = mergeAllowlist({
|
|
4576
|
+
existing: allowFrom,
|
|
4577
|
+
additions
|
|
4578
|
+
});
|
|
4579
|
+
ctx.allowFrom = normalizeAllowList(allowFrom);
|
|
4580
|
+
summarizeMapping("slack users", mapping, [], runtime);
|
|
4581
|
+
}
|
|
4582
|
+
if (allowNameMatching) try {
|
|
4583
|
+
const resolvedUsers = await resolveSlackUserAllowlist({
|
|
4584
|
+
token: resolveToken,
|
|
4585
|
+
entries: allowEntries
|
|
4586
|
+
});
|
|
4587
|
+
const { mapping, unresolved, additions } = buildAllowlistResolutionSummary(resolvedUsers, { formatResolved: formatSlackUserResolved });
|
|
4588
|
+
allowFrom = mergeAllowlist({
|
|
4589
|
+
existing: allowFrom,
|
|
4590
|
+
additions
|
|
4591
|
+
});
|
|
4592
|
+
ctx.allowFrom = normalizeAllowList(allowFrom);
|
|
4593
|
+
summarizeMapping("slack users", mapping, unresolved, runtime);
|
|
4594
|
+
} catch (err) {
|
|
4595
|
+
runtime.log?.(`slack user resolve failed; using config entries. ${formatUnknownError(err)}`);
|
|
4596
|
+
}
|
|
4597
|
+
}
|
|
4598
|
+
if (channelsConfig && Object.keys(channelsConfig).length > 0) {
|
|
4599
|
+
const userEntries = /* @__PURE__ */ new Set();
|
|
4600
|
+
for (const channel of Object.values(channelsConfig)) addAllowlistUserEntriesFromConfigEntry(userEntries, channel);
|
|
4601
|
+
if (userEntries.size > 0) {
|
|
4602
|
+
const stableResolvedUsers = resolveStableSlackUserAllowlistEntries(Array.from(userEntries));
|
|
4603
|
+
if (stableResolvedUsers.length > 0) {
|
|
4604
|
+
const { resolvedMap, mapping } = buildAllowlistResolutionSummary(stableResolvedUsers, { formatResolved: formatSlackUserResolved });
|
|
4605
|
+
const nextChannels = patchAllowlistUsersInConfigEntries({
|
|
4606
|
+
entries: channelsConfig,
|
|
4607
|
+
resolvedMap
|
|
4608
|
+
});
|
|
4609
|
+
channelsConfig = nextChannels;
|
|
4610
|
+
ctx.channelsConfig = nextChannels;
|
|
4611
|
+
summarizeMapping("slack channel users", mapping, [], runtime);
|
|
4612
|
+
}
|
|
4613
|
+
if (allowNameMatching) try {
|
|
4614
|
+
const resolvedUsers = await resolveSlackUserAllowlist({
|
|
4615
|
+
token: resolveToken,
|
|
4616
|
+
entries: Array.from(userEntries)
|
|
4617
|
+
});
|
|
4618
|
+
const { resolvedMap, mapping, unresolved } = buildAllowlistResolutionSummary(resolvedUsers, { formatResolved: formatSlackUserResolved });
|
|
4619
|
+
const nextChannels = patchAllowlistUsersInConfigEntries({
|
|
4620
|
+
entries: channelsConfig,
|
|
4621
|
+
resolvedMap
|
|
4622
|
+
});
|
|
4623
|
+
channelsConfig = nextChannels;
|
|
4624
|
+
ctx.channelsConfig = nextChannels;
|
|
4625
|
+
summarizeMapping("slack channel users", mapping, unresolved, runtime);
|
|
4626
|
+
} catch (err) {
|
|
4627
|
+
runtime.log?.(`slack channel user resolve failed; using config entries. ${formatUnknownError(err)}`);
|
|
4628
|
+
}
|
|
4629
|
+
}
|
|
4630
|
+
}
|
|
4631
|
+
})();
|
|
4632
|
+
const stopOnAbort = () => {
|
|
4633
|
+
if (opts.abortSignal?.aborted && slackMode === "socket") gracefulStop();
|
|
4634
|
+
};
|
|
4635
|
+
opts.abortSignal?.addEventListener("abort", stopOnAbort, { once: true });
|
|
4636
|
+
try {
|
|
4637
|
+
if (slackMode === "socket") {
|
|
4638
|
+
let reconnectAttempts = 0;
|
|
4639
|
+
let hasLoggedSocketConnected = false;
|
|
4640
|
+
while (!opts.abortSignal?.aborted) try {
|
|
4641
|
+
const disconnect = await startSlackSocketAndWaitForDisconnect({
|
|
4642
|
+
app,
|
|
4643
|
+
abortSignal: opts.abortSignal,
|
|
4644
|
+
onStarted: () => {
|
|
4645
|
+
reconnectAttempts = 0;
|
|
4646
|
+
publishSlackConnectedStatus(opts.setStatus);
|
|
4647
|
+
if (!hasLoggedSocketConnected) {
|
|
4648
|
+
hasLoggedSocketConnected = true;
|
|
4649
|
+
runtime.log?.("slack socket mode connected");
|
|
4650
|
+
}
|
|
4651
|
+
}
|
|
4652
|
+
});
|
|
4653
|
+
if (!disconnect) break;
|
|
4654
|
+
if (opts.abortSignal?.aborted) break;
|
|
4655
|
+
publishSlackDisconnectedStatus(opts.setStatus, disconnect.error);
|
|
4656
|
+
if (disconnect.error && isNonRecoverableSlackAuthError(disconnect.error)) {
|
|
4657
|
+
runtime.error?.(`slack socket mode disconnected due to non-recoverable auth error — skipping channel (${formatUnknownError(disconnect.error)})`);
|
|
4658
|
+
throw disconnect.error instanceof Error ? disconnect.error : new Error(formatUnknownError(disconnect.error));
|
|
4659
|
+
}
|
|
4660
|
+
reconnectAttempts += 1;
|
|
4661
|
+
const delayMs = computeBackoff(SLACK_SOCKET_RECONNECT_POLICY, reconnectAttempts);
|
|
4662
|
+
runtime.log?.(warn(formatSlackSocketReconnectMessage({
|
|
4663
|
+
event: disconnect.event,
|
|
4664
|
+
attempt: reconnectAttempts,
|
|
4665
|
+
delayMs,
|
|
4666
|
+
error: disconnect.error
|
|
4667
|
+
})));
|
|
4668
|
+
await gracefulStop();
|
|
4669
|
+
try {
|
|
4670
|
+
await sleepWithAbort(delayMs, opts.abortSignal);
|
|
4671
|
+
} catch {
|
|
4672
|
+
break;
|
|
4673
|
+
}
|
|
4674
|
+
} catch (err) {
|
|
4675
|
+
if (isNonRecoverableSlackAuthError(err)) {
|
|
4676
|
+
runtime.error?.(`slack socket mode failed to start due to non-recoverable auth error — skipping channel (${formatUnknownError(err)})`);
|
|
4677
|
+
throw err;
|
|
4678
|
+
}
|
|
4679
|
+
reconnectAttempts += 1;
|
|
4680
|
+
const delayMs = computeBackoff(SLACK_SOCKET_RECONNECT_POLICY, reconnectAttempts);
|
|
4681
|
+
runtime.error?.(formatSlackSocketStartRetryMessage({
|
|
4682
|
+
attempt: reconnectAttempts,
|
|
4683
|
+
delayMs,
|
|
4684
|
+
error: err,
|
|
4685
|
+
sdkContext: socketModeLogger.getLastMessage()
|
|
4686
|
+
}));
|
|
4687
|
+
try {
|
|
4688
|
+
await sleepWithAbort(delayMs, opts.abortSignal);
|
|
4689
|
+
} catch {
|
|
4690
|
+
break;
|
|
4691
|
+
}
|
|
4692
|
+
continue;
|
|
4693
|
+
}
|
|
4694
|
+
} else if (slackMode === "relay" && relayConfig) {
|
|
4695
|
+
runtime.log?.(`slack relay mode connecting to ${relayConfig.url} gateway_id:${relayConfig.gatewayId}`);
|
|
4696
|
+
await (await loadSlackRelaySource()).monitorSlackRelaySource({
|
|
4697
|
+
config: relayConfig,
|
|
4698
|
+
handleSlackMessage,
|
|
4699
|
+
runtime,
|
|
4700
|
+
abortSignal: opts.abortSignal,
|
|
4701
|
+
setStatus: opts.setStatus,
|
|
4702
|
+
setIdentity: (identity) => setSlackDefaultSendIdentity(account.accountId, identity)
|
|
4703
|
+
});
|
|
4704
|
+
} else {
|
|
4705
|
+
runtime.log?.(`slack http mode listening at ${slackWebhookPath}`);
|
|
4706
|
+
if (!opts.abortSignal?.aborted) await new Promise((resolve) => {
|
|
4707
|
+
opts.abortSignal?.addEventListener("abort", () => resolve(), { once: true });
|
|
4708
|
+
});
|
|
4709
|
+
}
|
|
4710
|
+
} finally {
|
|
4711
|
+
if (slackMode === "relay") setSlackDefaultSendIdentity(account.accountId, void 0);
|
|
4712
|
+
opts.abortSignal?.removeEventListener("abort", stopOnAbort);
|
|
4713
|
+
unregisterSocketModeConnectionDiagnostics();
|
|
4714
|
+
unregisterHttpHandler?.();
|
|
4715
|
+
await gracefulStop();
|
|
4716
|
+
}
|
|
4717
|
+
}
|
|
4718
|
+
const resolveSlackRuntimeGroupPolicy = resolveOpenProviderRuntimeGroupPolicy$1;
|
|
4719
|
+
//#endregion
|
|
4720
|
+
export { stripSlackMentionsForCommandDetection as C, buildSlackSlashCommandMatcher as S, readSessionUpdatedAt as _, SLACK_SOCKET_RECONNECT_POLICY as a, resolveStorePath$1 as b, recordInboundSession as c, resolveSlackCommandIngress as d, resolveSlackEffectiveAllowFrom as f, resolveSlackChatType as g, normalizeSlackChannelType as h, authorizeSlackDirectMessage as i, resolveConversationLabel$1 as l, parseSlackAssistantThreadMetadata as m, resolveSlackRuntimeGroupPolicy as n, formatUnknownError as o, buildSlackAssistantThreadMetadata as p, resolveSlackRoomContextHints as r, escapeSlackMrkdwn as s, monitorSlackProvider as t, authorizeSlackBotRoomMessage as u, resolveChannelContextVisibilityMode as v, updateLastRoute as x, resolveChannelResetConfig as y };
|