@openclaw/slack 2026.7.2-beta.3 → 2026.7.2-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/dist/account-inspect-api.js +1 -1
  2. package/dist/{account-inspect-Bvbtu3iH.js → account-inspect-jn1xLaVi.js} +2 -2
  3. package/dist/account-reply-mode-DrUXogvO.js +14 -0
  4. package/dist/{accounts-DQEbYKh9.js → accounts-BSr252c_.js} +6 -27
  5. package/dist/{accounts.runtime-BIKmJdtJ.js → accounts.runtime-CjULMLTa.js} +1 -1
  6. package/dist/{action-runtime-DqkRwO3Z.js → action-runtime-CFU52n4W.js} +7 -7
  7. package/dist/action-runtime.runtime-9-17zvKH.js +2 -0
  8. package/dist/{actions-CF0tUY5q.js → actions-D51foiwR.js} +5 -5
  9. package/dist/{actions.runtime-hCbx4RXg.js → actions.runtime-BMJwtf5C.js} +1 -1
  10. package/dist/api.js +15 -14
  11. package/dist/{approval-handler.runtime-Em8I1-8-.js → approval-handler.runtime-3b4-wxMl.js} +2 -2
  12. package/dist/{channel-4-TRi1D6.js → channel-Ds8NKvfr.js} +26 -24
  13. package/dist/channel-config-api.js +1 -1
  14. package/dist/channel-plugin-api.js +1 -1
  15. package/dist/{channel-type-Cu1yjNg2.js → channel-type-DXkUajFP.js} +3 -3
  16. package/dist/{channel.setup-CgkADtZg.js → channel.setup-DOSTEDfA.js} +6 -5
  17. package/dist/{config-schema-XjJGfwQC.js → config-schema-B4j4tCOI.js} +231 -26
  18. package/dist/{directory-config-Bv0lcUlH.js → directory-config-B08pm5ZT.js} +1 -1
  19. package/dist/directory-contract-api.js +1 -1
  20. package/dist/{directory-live-CzUIB7th.js → directory-live-DpPKzPrn.js} +2 -2
  21. package/dist/{doctor-contract-DKpe5VBr.js → doctor-contract-U6oVntbM.js} +60 -89
  22. package/dist/doctor-contract-api.js +1 -1
  23. package/dist/{group-policy-Bw-65m3V.js → group-policy-CdnQzQBI.js} +32 -5
  24. package/dist/{interactive-replies-Dm_t2R9S.js → interactive-replies-C3ffk6oN.js} +1 -1
  25. package/dist/interactive-replies-api.js +1 -1
  26. package/dist/{message-tool-api-C2pcf5du.js → message-tool-api-ByVyIVOh.js} +2 -2
  27. package/dist/message-tool-api.js +1 -1
  28. package/dist/{monitor-CNFeF30h.js → monitor-CnB_WKvF.js} +3 -3
  29. package/dist/{outbound-adapter-CVi2uok0.js → outbound-adapter-DuPz2HHt.js} +3 -3
  30. package/dist/{pipeline.runtime-CTvokbty.js → pipeline.runtime-5rRYZuX5.js} +110 -77
  31. package/dist/{policy-b_dOPDCq.js → policy-C31RYSuT.js} +1 -1
  32. package/dist/{probe-Borhn9PQ.js → probe-CVRuArHA.js} +1 -1
  33. package/dist/{provider-B-HVL5ZE.js → provider-htuIJGFD.js} +365 -200
  34. package/dist/{relay-source-Ea_P9VcO.js → relay-source-Df9EaiTF.js} +1 -1
  35. package/dist/{replies-B4bOdrYb.js → replies-Cgr2Gli4.js} +3 -3
  36. package/dist/{resolve-channels-KTc568SU.js → resolve-channels-DodP2TFx.js} +1 -1
  37. package/dist/{resolve-users-DeGJf1yp.js → resolve-users-M9eF8891.js} +1 -1
  38. package/dist/{runtime-api-BFfNpzDe.js → runtime-api-D5XYMMsf.js} +3 -2
  39. package/dist/runtime-api.js +11 -11
  40. package/dist/{scopes-lx08L56K.js → scopes-CJRpHkDC.js} +1 -1
  41. package/dist/{security-audit-CikQhBUY.js → security-audit-Cz6erklv.js} +0 -10
  42. package/dist/security-contract-api.js +1 -1
  43. package/dist/{send-KuTDky7i.js → send-BZ1tPv7-.js} +4 -4
  44. package/dist/{send.runtime-CXyxws1D.js → send.runtime-a2pilFor.js} +1 -1
  45. package/dist/{setup-core-CeiAVwQ3.js → setup-core-tPxMuFez.js} +138 -40
  46. package/dist/setup-plugin-api.js +1 -1
  47. package/dist/{setup-surface-DLA0vHXp.js → setup-surface-wV-S1dE_.js} +43 -27
  48. package/dist/{shared-C4yVB0Q-.js → shared-BfMskaMx.js} +9 -8
  49. package/dist/{slash-dispatch.runtime-BT-mMm-f.js → slash-dispatch.runtime-lfeIsXTX.js} +1 -1
  50. package/node_modules/@types/node/README.md +1 -1
  51. package/node_modules/@types/node/fs/promises.d.ts +16 -6
  52. package/node_modules/@types/node/package.json +2 -2
  53. package/node_modules/agent-base/README.md +145 -0
  54. package/node_modules/agent-base/dist/src/index.d.ts +78 -0
  55. package/node_modules/agent-base/dist/src/index.js +203 -0
  56. package/node_modules/agent-base/dist/src/index.js.map +1 -0
  57. package/node_modules/agent-base/dist/src/promisify.d.ts +4 -0
  58. package/node_modules/agent-base/dist/src/promisify.js +18 -0
  59. package/node_modules/agent-base/dist/src/promisify.js.map +1 -0
  60. package/node_modules/agent-base/package.json +64 -0
  61. package/node_modules/agent-base/src/index.ts +345 -0
  62. package/node_modules/agent-base/src/promisify.ts +33 -0
  63. package/node_modules/axios/CHANGELOG.md +197 -1
  64. package/node_modules/axios/README.md +424 -256
  65. package/node_modules/axios/dist/axios.js +589 -204
  66. package/node_modules/axios/dist/axios.min.js +3 -3
  67. package/node_modules/axios/dist/axios.min.js.map +1 -1
  68. package/node_modules/axios/dist/browser/axios.cjs +630 -185
  69. package/node_modules/axios/dist/esm/axios.js +630 -185
  70. package/node_modules/axios/dist/esm/axios.min.js +2 -2
  71. package/node_modules/axios/dist/esm/axios.min.js.map +1 -1
  72. package/node_modules/axios/dist/node/axios.cjs +949 -301
  73. package/node_modules/axios/index.d.cts +28 -5
  74. package/node_modules/axios/index.d.ts +24 -3
  75. package/node_modules/axios/lib/adapters/adapters.js +1 -1
  76. package/node_modules/axios/lib/adapters/fetch.js +223 -49
  77. package/node_modules/axios/lib/adapters/http.js +408 -193
  78. package/node_modules/axios/lib/adapters/xhr.js +3 -1
  79. package/node_modules/axios/lib/core/Axios.js +4 -2
  80. package/node_modules/axios/lib/core/AxiosError.js +13 -1
  81. package/node_modules/axios/lib/core/AxiosHeaders.js +13 -42
  82. package/node_modules/axios/lib/core/buildFullPath.js +29 -1
  83. package/node_modules/axios/lib/core/mergeConfig.js +35 -0
  84. package/node_modules/axios/lib/defaults/transitional.js +2 -0
  85. package/node_modules/axios/lib/env/data.js +1 -1
  86. package/node_modules/axios/lib/helpers/AxiosURLSearchParams.js +1 -3
  87. package/node_modules/axios/lib/helpers/Http2Sessions.js +119 -0
  88. package/node_modules/axios/lib/helpers/buildURL.js +7 -4
  89. package/node_modules/axios/lib/helpers/composeSignals.js +48 -47
  90. package/node_modules/axios/lib/helpers/cookies.js +5 -1
  91. package/node_modules/axios/lib/helpers/estimateDataURLDecodedBytes.js +16 -11
  92. package/node_modules/axios/lib/helpers/formDataToJSON.js +26 -4
  93. package/node_modules/axios/lib/helpers/formDataToStream.js +2 -2
  94. package/node_modules/axios/lib/helpers/fromDataURI.js +20 -5
  95. package/node_modules/axios/lib/helpers/progressEventReducer.js +3 -0
  96. package/node_modules/axios/lib/helpers/resolveConfig.js +26 -13
  97. package/node_modules/axios/lib/helpers/sanitizeHeaderValue.js +60 -0
  98. package/node_modules/axios/lib/helpers/shouldBypassProxy.js +33 -1
  99. package/node_modules/axios/lib/helpers/toFormData.js +48 -12
  100. package/node_modules/axios/lib/helpers/validator.js +1 -1
  101. package/node_modules/axios/lib/utils.js +105 -19
  102. package/node_modules/axios/package.json +31 -13
  103. package/node_modules/https-proxy-agent/README.md +137 -0
  104. package/node_modules/https-proxy-agent/dist/agent.d.ts +30 -0
  105. package/node_modules/https-proxy-agent/dist/agent.js +177 -0
  106. package/node_modules/https-proxy-agent/dist/agent.js.map +1 -0
  107. package/node_modules/https-proxy-agent/dist/index.d.ts +23 -0
  108. package/node_modules/https-proxy-agent/dist/index.js +14 -0
  109. package/node_modules/https-proxy-agent/dist/index.js.map +1 -0
  110. package/node_modules/https-proxy-agent/dist/parse-proxy-response.d.ts +7 -0
  111. package/node_modules/https-proxy-agent/dist/parse-proxy-response.js +66 -0
  112. package/node_modules/https-proxy-agent/dist/parse-proxy-response.js.map +1 -0
  113. package/node_modules/https-proxy-agent/package.json +56 -0
  114. package/node_modules/iconv-lite/encodings/sbcs-data.js +2 -0
  115. package/node_modules/iconv-lite/encodings/utf32.js +10 -3
  116. package/node_modules/iconv-lite/package.json +2 -2
  117. package/node_modules/iconv-lite/types/encodings.d.ts +2 -0
  118. package/node_modules/path-to-regexp/Readme.md +3 -3
  119. package/node_modules/path-to-regexp/dist/index.js +135 -158
  120. package/node_modules/path-to-regexp/dist/index.js.map +1 -1
  121. package/node_modules/path-to-regexp/package.json +2 -2
  122. package/node_modules/qs/CHANGELOG.md +11 -0
  123. package/node_modules/qs/dist/qs.js +17 -17
  124. package/node_modules/qs/lib/parse.js +19 -8
  125. package/node_modules/qs/lib/utils.js +47 -8
  126. package/node_modules/qs/package.json +6 -5
  127. package/node_modules/qs/test/parse.js +230 -0
  128. package/node_modules/qs/test/utils.js +194 -0
  129. package/node_modules/typebox/build/compile/validator.d.mts +1 -4
  130. package/node_modules/typebox/build/guard/guard.d.mts +1 -1
  131. package/node_modules/typebox/build/guard/guard.mjs +5 -2
  132. package/node_modules/typebox/build/guard/string.mjs +16 -4
  133. package/node_modules/typebox/build/schema/engine/_functions.mjs +34 -15
  134. package/node_modules/typebox/build/type/action/readonly_object.d.mts +5 -0
  135. package/node_modules/typebox/build/type/action/readonly_object.mjs +8 -0
  136. package/node_modules/typebox/build/typebox.d.mts +1 -1
  137. package/node_modules/typebox/build/typebox.mjs +1 -1
  138. package/node_modules/typebox/package.json +1 -1
  139. package/node_modules/typebox/readme.md +29 -32
  140. package/node_modules/ws/lib/receiver.js +15 -32
  141. package/node_modules/ws/lib/websocket-server.js +4 -4
  142. package/node_modules/ws/lib/websocket.js +4 -4
  143. package/node_modules/ws/package.json +5 -1
  144. package/npm-shrinkwrap.json +54 -27
  145. package/openclaw.plugin.json +1759 -1908
  146. package/package.json +92 -14
  147. package/dist/action-runtime.runtime-DEWOcFM4.js +0 -2
  148. package/dist/config-api-Df9a1B8C.js +0 -3
  149. package/node_modules/axios/dist/axios.js.map +0 -1
  150. package/node_modules/axios/dist/browser/axios.cjs.map +0 -1
  151. package/node_modules/axios/dist/esm/axios.js.map +0 -1
  152. package/node_modules/axios/dist/node/axios.cjs.map +0 -1
@@ -1,17 +1,17 @@
1
1
  import { n as registerSlackHttpHandler, r as normalizeSlackWebhookPath } from "./registry-bbjH7IHX.js";
2
- import { a as resolveSlackAccount, d as formatSlackBotTokenIdentityWarning, f as resolveSlackAppToken, i as resolveDefaultSlackAccountId, o as resolveSlackAccountAllowFrom, p as resolveSlackBotToken, s as resolveSlackAccountDmPolicy } from "./accounts-DQEbYKh9.js";
3
- import { F as SLACK_TEXT_LIMIT, G as isSlackQuestionActionId, K as decodeSlackQuestionAction, U as isSlackApprovalActionId, W as isSlackCallbackActionId, X as decodeSlackApprovalAction, Y as escapeSlackMrkdwn, a as allowListMatches, c as normalizeSlackAllowOwnerEntry, ft as isSlackApprovalAuthorizedSender, l as normalizeSlackSlug, mt as isSlackExecApprovalAuthorizedSender, nt as isSlackAnyNativeApprovalClientEnabled, o as normalizeAllowList, q as resolveSlackQuestionAction, s as normalizeAllowListLower, u as resolveSlackAllowListMatch, z as truncateSlackText } from "./group-policy-Bw-65m3V.js";
4
- import { n as isSlackInteractiveRepliesEnabled, t as compileSlackInteractiveReplies } from "./interactive-replies-Dm_t2R9S.js";
5
- import { m as resolveSlackWebClientOptions, o as createSlackStartupAuthClient, r as formatSlackError, u as getSlackListenerUploadCompletionClient } from "./probe-Borhn9PQ.js";
6
- import { n as getSlackRuntime } from "./runtime-JSVZSWAj.js";
7
- import { i as setSlackDefaultSendIdentity } from "./send-KuTDky7i.js";
8
- import { t as resolveSlackChannelAllowlist } from "./resolve-channels-KTc568SU.js";
9
- import { t as resolveSlackUserAllowlist } from "./resolve-users-DeGJf1yp.js";
10
- import { n as resolveSlackChannelConfig, r as resolveSlackChannelLabel, t as isSlackChannelAllowedByPolicy } from "./policy-b_dOPDCq.js";
2
+ import { a as resolveSlackAccount, d as resolveSlackAppToken, f as resolveSlackBotToken, i as resolveDefaultSlackAccountId, o as resolveSlackAccountAllowFrom, s as resolveSlackAccountDmPolicy, u as formatSlackBotTokenIdentityWarning } from "./accounts-BSr252c_.js";
3
+ import { F as SLACK_TEXT_LIMIT, G as isSlackQuestionActionId, K as decodeSlackQuestionAction, U as isSlackApprovalActionId, W as isSlackCallbackActionId, X as decodeSlackApprovalAction, Y as escapeSlackMrkdwn, a as allowListMatches, c as normalizeSlackAllowOwnerEntry, ft as isSlackApprovalAuthorizedSender, l as normalizeSlackSlug, mt as isSlackExecApprovalAuthorizedSender, nt as isSlackAnyNativeApprovalClientEnabled, o as normalizeAllowList, q as resolveSlackQuestionAction, s as normalizeAllowListLower, u as resolveSlackAllowListMatch, z as truncateSlackText } from "./group-policy-CdnQzQBI.js";
4
+ import { n as isSlackInteractiveRepliesEnabled, t as compileSlackInteractiveReplies } from "./interactive-replies-C3ffk6oN.js";
5
+ import { m as resolveSlackWebClientOptions, o as createSlackStartupAuthClient, r as formatSlackError, u as getSlackListenerUploadCompletionClient } from "./probe-CVRuArHA.js";
6
+ import { n as getSlackRuntime, t as getOptionalSlackRuntime } from "./runtime-JSVZSWAj.js";
7
+ import { i as setSlackDefaultSendIdentity } from "./send-BZ1tPv7-.js";
8
+ import { t as resolveSlackChannelAllowlist } from "./resolve-channels-DodP2TFx.js";
9
+ import { t as resolveSlackUserAllowlist } from "./resolve-users-M9eF8891.js";
10
+ import { n as resolveSlackChannelConfig, r as resolveSlackChannelLabel, t as isSlackChannelAllowedByPolicy } from "./policy-C31RYSuT.js";
11
11
  import { normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input";
12
12
  import { asOptionalRecord, isRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries, normalizeStringEntriesLower, normalizeUniqueTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
13
13
  import { normalizeAccountId, normalizeMainKey, resolveAgentRoute, resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
14
- import { DEFAULT_INGRESS_ADOPTION_STALL_MS, DEFAULT_INGRESS_RETRY_DEAD_LETTER_MIN_AGE_MS, DEFAULT_INGRESS_RETRY_MAX_ATTEMPTS, bindIngressLifecycleToReplyOptions, createChannelIngressDrain, createChannelMessageReplyPipeline } from "openclaw/plugin-sdk/channel-outbound";
14
+ import { createChannelIngressMonitor, createChannelMessageReplyPipeline } from "openclaw/plugin-sdk/channel-outbound";
15
15
  import { createChannelPairingChallengeIssuer } from "openclaw/plugin-sdk/channel-pairing";
16
16
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
17
17
  import { computeBackoff, createNonExitingRuntime, createSubsystemLogger, danger, getChildLogger, logVerbose, shouldLogVerbose, sleepWithAbort, warn } from "openclaw/plugin-sdk/runtime-env";
@@ -35,7 +35,7 @@ import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-na
35
35
  import { getSessionEntry, readSessionUpdatedAt, resolveChannelResetConfig, resolveSessionKey, resolveStorePath, resolveStorePath as resolveStorePath$1, updateLastRoute } from "openclaw/plugin-sdk/session-store-runtime";
36
36
  import { resolveChannelContextVisibilityMode } from "openclaw/plugin-sdk/context-visibility-runtime";
37
37
  import { resolveDefaultGroupPolicy, resolveOpenProviderRuntimeGroupPolicy as resolveOpenProviderRuntimeGroupPolicy$1, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
38
- import { loadModelCatalog, resolveDefaultAgentId, resolveDefaultModelForAgent } from "openclaw/plugin-sdk/agent-runtime";
38
+ import { loadPreparedModelCatalog, resolveAgentDir, resolveDefaultAgentId, resolveDefaultModelForAgent } from "openclaw/plugin-sdk/agent-runtime";
39
39
  import { resolveChannelConfigWrites } from "openclaw/plugin-sdk/channel-config-writes";
40
40
  import { mutateConfigFile } from "openclaw/plugin-sdk/config-mutation";
41
41
  import { enqueueSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
@@ -45,7 +45,7 @@ import { requestHeartbeat } from "openclaw/plugin-sdk/heartbeat-runtime";
45
45
  import { createInteractiveConversationBindingHelpers, dispatchPluginInteractiveHandler } from "openclaw/plugin-sdk/plugin-runtime";
46
46
  import { createChannelIngressResolver, defineStableChannelIngressIdentity, readChannelIngressStoreAllowFromForDmPolicy } from "openclaw/plugin-sdk/channel-ingress-runtime";
47
47
  import { createChannelInboundDebouncer, shouldDebounceTextInbound } from "openclaw/plugin-sdk/channel-inbound";
48
- import { createChannelReplayGuard } from "openclaw/plugin-sdk/persistent-dedupe";
48
+ import { createChannelReplayGuard, runClaimableDedupeClaimLoop } from "openclaw/plugin-sdk/persistent-dedupe";
49
49
  import { generateSecureToken } from "openclaw/plugin-sdk/secure-random-runtime";
50
50
  //#region extensions/slack/src/monitor/commands.ts
51
51
  /**
@@ -72,6 +72,151 @@ function buildSlackSlashCommandMatcher(name) {
72
72
  return new RegExp(`^/?${escaped}$`);
73
73
  }
74
74
  //#endregion
75
+ //#region extensions/slack/src/monitor/agent-view-state.ts
76
+ const SLACK_AGENT_VIEW_STATE_NAMESPACE = "agent-view-workspaces";
77
+ const SLACK_AGENT_VIEW_THREAD_STATE_NAMESPACE = "agent-view-threads";
78
+ const SLACK_AGENT_VIEW_STATE_MAX_ENTRIES = 4096;
79
+ const SLACK_AGENT_VIEW_THREAD_STATE_MAX_ENTRIES = 4096;
80
+ const SLACK_MANAGED_THREAD_CACHE_MAX_ENTRIES = 4096;
81
+ function createSlackAgentViewState(params) {
82
+ let enabled = false;
83
+ let loaded = false;
84
+ let persisted = false;
85
+ let workspaceStore;
86
+ let threadStore;
87
+ let warned = false;
88
+ const managedThreads = /* @__PURE__ */ new Map();
89
+ const warnOnce = (action, error) => {
90
+ if (warned) return;
91
+ warned = true;
92
+ params.warn(action, error);
93
+ };
94
+ const openWorkspaceStore = () => {
95
+ if (workspaceStore) return workspaceStore;
96
+ const runtime = getOptionalSlackRuntime();
97
+ if (!runtime) return;
98
+ try {
99
+ workspaceStore = runtime.state.openKeyedStore({
100
+ namespace: SLACK_AGENT_VIEW_STATE_NAMESPACE,
101
+ maxEntries: SLACK_AGENT_VIEW_STATE_MAX_ENTRIES
102
+ });
103
+ return workspaceStore;
104
+ } catch (error) {
105
+ warnOnce("open", error);
106
+ return;
107
+ }
108
+ };
109
+ const openThreadStore = () => {
110
+ if (threadStore) return threadStore;
111
+ const runtime = getOptionalSlackRuntime();
112
+ if (!runtime) return;
113
+ try {
114
+ threadStore = runtime.state.openKeyedStore({
115
+ namespace: SLACK_AGENT_VIEW_THREAD_STATE_NAMESPACE,
116
+ maxEntries: SLACK_AGENT_VIEW_THREAD_STATE_MAX_ENTRIES
117
+ });
118
+ return threadStore;
119
+ } catch (error) {
120
+ warnOnce("open", error);
121
+ return;
122
+ }
123
+ };
124
+ const workspaceStateKey = params.apiAppId ? JSON.stringify([
125
+ "workspace",
126
+ params.accountId,
127
+ params.teamId,
128
+ params.apiAppId
129
+ ]) : void 0;
130
+ const record = async () => {
131
+ enabled = true;
132
+ loaded = true;
133
+ if (persisted || !workspaceStateKey) return;
134
+ const openedStore = openWorkspaceStore();
135
+ if (!openedStore) return;
136
+ try {
137
+ await openedStore.register(workspaceStateKey, {
138
+ experience: "agent",
139
+ observedAt: Date.now()
140
+ });
141
+ persisted = true;
142
+ } catch (error) {
143
+ warnOnce("persist", error);
144
+ }
145
+ };
146
+ const isEnabled = async () => {
147
+ if (enabled) return true;
148
+ if (loaded) return false;
149
+ if (!workspaceStateKey) {
150
+ loaded = true;
151
+ return false;
152
+ }
153
+ const openedStore = openWorkspaceStore();
154
+ if (!openedStore) return false;
155
+ try {
156
+ const stored = await openedStore.lookup(workspaceStateKey);
157
+ loaded = true;
158
+ enabled = stored?.experience === "agent";
159
+ persisted = enabled;
160
+ return enabled;
161
+ } catch (error) {
162
+ warnOnce("load", error);
163
+ return false;
164
+ }
165
+ };
166
+ const managedThreadKey = (channelId, threadTs) => JSON.stringify([channelId, threadTs]);
167
+ const managedThreadStateKey = (channelId, threadTs) => params.apiAppId ? JSON.stringify([
168
+ "thread",
169
+ params.accountId,
170
+ params.teamId,
171
+ params.apiAppId,
172
+ channelId,
173
+ threadTs
174
+ ]) : void 0;
175
+ const rememberManagedThread = (key) => {
176
+ managedThreads.delete(key);
177
+ managedThreads.set(key, true);
178
+ if (managedThreads.size <= SLACK_MANAGED_THREAD_CACHE_MAX_ENTRIES) return;
179
+ const oldestKey = managedThreads.keys().next().value;
180
+ if (oldestKey !== void 0) managedThreads.delete(oldestKey);
181
+ };
182
+ const recordManagedThread = async (channelId, threadTs) => {
183
+ const key = managedThreadKey(channelId, threadTs);
184
+ rememberManagedThread(key);
185
+ const stateKey = managedThreadStateKey(channelId, threadTs);
186
+ const openedStore = stateKey ? openThreadStore() : void 0;
187
+ if (!openedStore || !stateKey) return;
188
+ try {
189
+ await openedStore.register(stateKey, {
190
+ experience: "managed-thread",
191
+ observedAt: Date.now()
192
+ });
193
+ } catch (error) {
194
+ warnOnce("persist", error);
195
+ }
196
+ };
197
+ const isManagedThread = async (channelId, threadTs) => {
198
+ const key = managedThreadKey(channelId, threadTs);
199
+ if (managedThreads.has(key)) return true;
200
+ const stateKey = managedThreadStateKey(channelId, threadTs);
201
+ const openedStore = stateKey ? openThreadStore() : void 0;
202
+ if (!openedStore || !stateKey) return false;
203
+ try {
204
+ const found = (await openedStore.lookup(stateKey))?.experience === "managed-thread";
205
+ if (found) rememberManagedThread(key);
206
+ return found;
207
+ } catch (error) {
208
+ warnOnce("load", error);
209
+ return false;
210
+ }
211
+ };
212
+ return {
213
+ isEnabled,
214
+ isManagedThread,
215
+ record,
216
+ recordManagedThread
217
+ };
218
+ }
219
+ //#endregion
75
220
  //#region extensions/slack/src/monitor/channel-type.ts
76
221
  function inferSlackChannelType(channelId) {
77
222
  const trimmed = channelId?.trim();
@@ -111,6 +256,42 @@ function writeLruMapEntry(cache, cacheKey, entry, maxEntries) {
111
256
  pruneMapToMaxSize(cache, maxEntries);
112
257
  }
113
258
  //#endregion
259
+ //#region extensions/slack/src/monitor/suggested-prompts.ts
260
+ const DEFAULT_SLACK_SUGGESTED_PROMPTS = [
261
+ {
262
+ title: "What can you do?",
263
+ message: "What can you help me with?"
264
+ },
265
+ {
266
+ title: "Summarize this channel",
267
+ message: "Summarize the recent activity in this channel."
268
+ },
269
+ {
270
+ title: "Draft a reply",
271
+ message: "Help me draft a reply."
272
+ }
273
+ ];
274
+ async function updateSlackSuggestedPrompts(params) {
275
+ const prompts = params.prompts.map((prompt) => ({
276
+ title: prompt.title.trim(),
277
+ message: prompt.message.trim()
278
+ })).filter((prompt) => prompt.title && prompt.message).slice(0, 4);
279
+ if (prompts.length === 0) return false;
280
+ try {
281
+ await params.client.assistant.threads.setSuggestedPrompts({
282
+ token: params.botToken,
283
+ channel_id: params.channelId,
284
+ ...params.threadTs ? { thread_ts: params.threadTs } : {},
285
+ ...params.title?.trim() ? { title: params.title.trim() } : {},
286
+ prompts
287
+ });
288
+ return true;
289
+ } catch (error) {
290
+ logVerbose(`slack suggested prompts update failed for channel ${params.channelId}: ${formatSlackError(error)}`);
291
+ return false;
292
+ }
293
+ }
294
+ //#endregion
114
295
  //#region extensions/slack/src/monitor/context.ts
115
296
  const SLACK_ASSISTANT_THREAD_CONTEXT_METADATA_EVENT = "assistant_thread_context";
116
297
  const SLACK_CHANNEL_CACHE_MAX_ENTRIES = 1024;
@@ -157,6 +338,12 @@ function createSlackMonitorContext(params) {
157
338
  });
158
339
  const assistantThreadContexts = /* @__PURE__ */ new Map();
159
340
  let lastAssistantContextCleanupAt = Date.now();
341
+ const agentViewState = createSlackAgentViewState({
342
+ accountId: params.accountId,
343
+ teamId: params.teamId,
344
+ apiAppId: params.apiAppId,
345
+ warn: (action, error) => logger.warn({ error: formatSlackError(error) }, `Slack Agent View state failed to ${action}`)
346
+ });
160
347
  const allowFrom = normalizeAllowList(params.allowFrom);
161
348
  const groupDmChannels = normalizeAllowList(params.groupDmChannels);
162
349
  const groupDmChannelsLower = new Set(normalizeAllowListLower(groupDmChannels).map((entry) => entry.replace(/^channel:/, "")));
@@ -331,26 +518,11 @@ function createSlackMonitorContext(params) {
331
518
  logVerbose(`slack status update failed for channel ${p.channelId}: ${formatSlackError(err)}`);
332
519
  }
333
520
  };
334
- const setSlackAssistantSuggestedPrompts = async (p) => {
335
- const prompts = p.prompts.map((prompt) => ({
336
- title: prompt.title.trim(),
337
- message: prompt.message.trim()
338
- })).filter((prompt) => prompt.title && prompt.message).slice(0, 4);
339
- if (prompts.length === 0) return false;
340
- try {
341
- await params.app.client.assistant.threads.setSuggestedPrompts({
342
- token: params.botToken,
343
- channel_id: p.channelId,
344
- thread_ts: p.threadTs,
345
- ...p.title?.trim() ? { title: p.title.trim() } : {},
346
- prompts
347
- });
348
- return true;
349
- } catch (err) {
350
- logVerbose(`slack suggested prompts update failed for channel ${p.channelId}: ${formatSlackError(err)}`);
351
- return false;
352
- }
353
- };
521
+ const setSlackSuggestedPrompts = (input) => updateSlackSuggestedPrompts({
522
+ ...input,
523
+ botToken: params.botToken,
524
+ client: params.app.client
525
+ });
354
526
  const isChannelAllowed = (p) => {
355
527
  const channelType = normalizeSlackChannelType(p.channelType, p.channelId);
356
528
  const isDirectMessage = channelType === "im";
@@ -466,7 +638,6 @@ function createSlackMonitorContext(params) {
466
638
  ackReactionScope: params.ackReactionScope,
467
639
  typingReaction: params.typingReaction,
468
640
  mediaMaxBytes: params.mediaMaxBytes,
469
- removeAckAfterReply: params.removeAckAfterReply,
470
641
  logger,
471
642
  shouldDropMismatchedSlackEvent,
472
643
  resolveSlackSystemEventSessionKey,
@@ -478,7 +649,11 @@ function createSlackMonitorContext(params) {
478
649
  setSlackThreadStatus,
479
650
  getSlackAssistantThreadContext,
480
651
  saveSlackAssistantThreadContext,
481
- setSlackAssistantSuggestedPrompts
652
+ setSlackSuggestedPrompts,
653
+ recordSlackAgentView: agentViewState.record,
654
+ isSlackAgentView: agentViewState.isEnabled,
655
+ recordSlackManagedViewThread: agentViewState.recordManagedThread,
656
+ isSlackManagedViewThread: agentViewState.isManagedThread
482
657
  };
483
658
  }
484
659
  //#endregion
@@ -521,8 +696,8 @@ function assertEnterpriseSlackPolicyConfig(params) {
521
696
  predicate: isStableSlackAllowlistUserEntry
522
697
  });
523
698
  assertStableEntries({
524
- values: config.dm?.allowFrom,
525
- path: `channels.slack.accounts.${accountId}.dm.allowFrom`,
699
+ values: config.allowFrom,
700
+ path: `channels.slack.accounts.${accountId}.allowFrom`,
526
701
  predicate: isStableSlackAllowlistUserEntry
527
702
  });
528
703
  assertStableEntries({
@@ -611,21 +786,21 @@ function resolveSlackIdentityHealth(params) {
611
786
  };
612
787
  }
613
788
  //#endregion
789
+ //#region extensions/slack/src/monitor/events/agent.ts
790
+ function registerSlackAgentEvents(params) {
791
+ const { ctx, trackEvent } = params;
792
+ ctx.app.event("app_context_changed", async ({ body }) => {
793
+ try {
794
+ if (ctx.shouldDropMismatchedSlackEvent(body)) return;
795
+ trackEvent?.();
796
+ await ctx.recordSlackAgentView();
797
+ } catch (error) {
798
+ ctx.runtime.error?.(danger(`slack app_context_changed handler failed: ${formatErrorMessage(error)}`));
799
+ }
800
+ });
801
+ }
802
+ //#endregion
614
803
  //#region extensions/slack/src/monitor/events/assistant.ts
615
- const DEFAULT_ASSISTANT_PROMPTS = [
616
- {
617
- title: "What can you do?",
618
- message: "What can you help me with?"
619
- },
620
- {
621
- title: "Summarize this channel",
622
- message: "Summarize the recent activity in this channel."
623
- },
624
- {
625
- title: "Draft a reply",
626
- message: "Help me draft a reply."
627
- }
628
- ];
629
804
  function normalizeAssistantThread(event, getPrevious) {
630
805
  const thread = event.assistant_thread;
631
806
  if (!thread) return null;
@@ -687,11 +862,11 @@ function registerSlackAssistantEvents(params) {
687
862
  return;
688
863
  }
689
864
  ctx.saveSlackAssistantThreadContext(assistantThread);
690
- await ctx.setSlackAssistantSuggestedPrompts({
865
+ await ctx.setSlackSuggestedPrompts({
691
866
  channelId: assistantThread.assistantChannelId,
692
867
  threadTs: assistantThread.threadTs,
693
868
  title: "Try asking",
694
- prompts: DEFAULT_ASSISTANT_PROMPTS
869
+ prompts: DEFAULT_SLACK_SUGGESTED_PROMPTS
695
870
  });
696
871
  } catch (err) {
697
872
  ctx.runtime.error?.(danger(`slack assistant_thread_started handler failed: ${formatErrorMessage(err)}`));
@@ -931,7 +1106,16 @@ function registerSlackHomeEvents(params) {
931
1106
  if (ctx.shouldDropMismatchedSlackEvent(body)) return;
932
1107
  trackEvent?.();
933
1108
  const payload = event;
934
- if (!payload.user || payload.tab === "messages") return;
1109
+ if (!payload.user) return;
1110
+ if (payload.tab === "messages") {
1111
+ if (!payload.channel) return;
1112
+ if (await ctx.setSlackSuggestedPrompts({
1113
+ channelId: payload.channel,
1114
+ title: "Try asking",
1115
+ prompts: DEFAULT_SLACK_SUGGESTED_PROMPTS
1116
+ })) await ctx.recordSlackAgentView();
1117
+ return;
1118
+ }
935
1119
  await ctx.app.client.views.publish({
936
1120
  token: ctx.botToken,
937
1121
  user_id: payload.user,
@@ -2812,13 +2996,37 @@ function resolveSlackIngressLane(body, eventId) {
2812
2996
  function isSlackEventCallback(body) {
2813
2997
  return asOptionalRecord(body)?.type === "event_callback";
2814
2998
  }
2815
- function assertSlackIngressPayload(payload, eventId) {
2816
- if (payload.version !== SLACK_INGRESS_PAYLOAD_VERSION) throw new SlackIngressPayloadError(`Slack ingress payload ${eventId} was invalid.`);
2999
+ function decodeSlackIngressPayload(payload, eventId) {
2817
3000
  if (payload.kind === "relay") {
2818
3001
  if (!asOptionalRecord(payload.message)) throw new SlackIngressPayloadError(`Slack relay ingress payload ${eventId} was invalid.`);
2819
- return;
3002
+ return {
3003
+ version: payload.version,
3004
+ body: payload
3005
+ };
2820
3006
  }
2821
3007
  if (!asOptionalRecord(payload.body) || resolveSlackEventId(payload.body) !== eventId) throw new SlackIngressPayloadError(`Slack ingress payload ${eventId} was invalid.`);
3008
+ return {
3009
+ version: payload.version,
3010
+ body: payload
3011
+ };
3012
+ }
3013
+ function inspectSlackIngress(raw) {
3014
+ if (raw.kind === "relay") {
3015
+ const eventId = resolveSlackRelayIngressEventId({
3016
+ deliveryId: raw.deliveryId,
3017
+ message: raw.message
3018
+ });
3019
+ return {
3020
+ eventId,
3021
+ laneKey: resolveSlackIngressLane({ event: raw.message }, eventId)
3022
+ };
3023
+ }
3024
+ const eventId = resolveSlackEventId(raw.body);
3025
+ if (!eventId) throw new SlackIngressPayloadError("Slack Events API envelope missing event_id.");
3026
+ return {
3027
+ eventId,
3028
+ laneKey: resolveSlackIngressLane(raw.body, eventId)
3029
+ };
2822
3030
  }
2823
3031
  function resolveSlackIngressNonRetryableFailure(error) {
2824
3032
  for (const candidate of collectErrorGraphCandidates(error, (current) => [
@@ -2844,115 +3052,97 @@ function resolveSlackIngressTurnLifecycle(context) {
2844
3052
  return typeof lifecycle.onAdopted === "function" && lifecycle.abortSignal instanceof AbortSignal ? lifecycle : null;
2845
3053
  }
2846
3054
  function createSlackDurableIngress(options) {
2847
- let queue = options.queue;
2848
- let drain;
2849
3055
  let app;
2850
3056
  let relayDispatch;
2851
- let running = false;
2852
- let requested = false;
2853
- let pumping;
2854
- let pollTimer;
2855
- let lastPrunedAt = 0;
2856
- const getQueue = () => {
2857
- queue ??= getSlackRuntime().state.openChannelIngressQueue({ accountId: options.accountId });
2858
- return queue;
2859
- };
2860
- const getDrain = () => {
2861
- drain ??= createChannelIngressDrain({
2862
- queue: getQueue(),
2863
- adoptionStallTimeoutMs: options.adoptionStallTimeoutMs ?? DEFAULT_INGRESS_ADOPTION_STALL_MS,
2864
- retryPolicy: {
2865
- maxAttempts: DEFAULT_INGRESS_RETRY_MAX_ATTEMPTS,
2866
- deadLetterMinAgeMs: DEFAULT_INGRESS_RETRY_DEAD_LETTER_MIN_AGE_MS
3057
+ const monitor = createChannelIngressMonitor({
3058
+ queue: options.queue ?? (() => getSlackRuntime().state.openChannelIngressQueue({ accountId: options.accountId })),
3059
+ inspect: inspectSlackIngress,
3060
+ payload: {
3061
+ version: SLACK_INGRESS_PAYLOAD_VERSION,
3062
+ serialize: (raw, { receivedAt }) => raw.kind === "relay" ? {
3063
+ kind: "relay",
3064
+ receivedAt,
3065
+ message: raw.message
3066
+ } : {
3067
+ kind: "events-api",
3068
+ receivedAt,
3069
+ body: raw.body,
3070
+ ...raw.retryNum === void 0 ? {} : { retryNum: raw.retryNum },
3071
+ ...raw.retryReason === void 0 ? {} : { retryReason: raw.retryReason }
2867
3072
  },
2868
- resolveNonRetryableFailure: resolveSlackIngressNonRetryableFailure,
2869
- deriveLaneKey: (record) => record.payload.kind === "relay" ? resolveSlackIngressLane({ event: record.payload.message }, record.id) : resolveSlackIngressLane(record.payload.body, record.id),
2870
- ...options.onLog ? { onLog: options.onLog } : {},
2871
- ...options.abortSignal ? { abortSignal: options.abortSignal } : {},
2872
- dispatchClaimedEvent: async (event, lifecycle) => {
2873
- assertSlackIngressPayload(event.payload, event.id);
2874
- if (lifecycle.abortSignal.aborted) throw lifecycle.abortSignal.reason;
2875
- const bound = bindIngressLifecycleToReplyOptions(lifecycle);
2876
- if (event.payload.kind === "relay") {
2877
- if (!relayDispatch) throw new Error("Slack relay ingress dispatcher is not attached.");
2878
- await relayDispatch(event.payload.message, bound.turnAdoptionLifecycle);
2879
- return;
2880
- }
2881
- if (!app) throw new Error("Slack ingress receiver is not attached to a Bolt app.");
2882
- await app.processEvent({
2883
- body: event.payload.body,
2884
- ack: async () => {},
2885
- ...event.payload.retryNum === void 0 ? {} : { retryNum: event.payload.retryNum },
2886
- ...event.payload.retryReason === void 0 ? {} : { retryReason: event.payload.retryReason },
2887
- customProperties: { [SLACK_INGRESS_LIFECYCLE_CONTEXT_KEY]: bound.turnAdoptionLifecycle }
2888
- });
3073
+ deserialize: (body, { claim }) => body.kind === "relay" ? {
3074
+ kind: "relay",
3075
+ deliveryId: claim.id.startsWith("relay:") ? claim.id.slice(6) : claim.id,
3076
+ message: body.message
3077
+ } : {
3078
+ kind: "events-api",
3079
+ body: body.body,
3080
+ ...body.retryNum === void 0 ? {} : { retryNum: body.retryNum },
3081
+ ...body.retryReason === void 0 ? {} : { retryReason: body.retryReason }
3082
+ },
3083
+ encode: ({ body }) => ({
3084
+ version: SLACK_INGRESS_PAYLOAD_VERSION,
3085
+ ...body
3086
+ }),
3087
+ decode: (payload, { claim }) => decodeSlackIngressPayload(payload, claim.id),
3088
+ createClaimError: (_kind, claim) => new SlackIngressPayloadError(`Slack ingress payload ${claim.id} was invalid.`)
3089
+ },
3090
+ onDurableAdmission: async (raw) => {
3091
+ if (raw.kind === "events-api") await raw.afterDurableAdmission?.();
3092
+ },
3093
+ deliver: async (raw, lifecycle) => {
3094
+ if (raw.kind === "relay") {
3095
+ if (!relayDispatch) throw new Error("Slack relay ingress dispatcher is not attached.");
3096
+ await relayDispatch(raw.message, lifecycle);
3097
+ return;
2889
3098
  }
2890
- });
2891
- return drain;
2892
- };
2893
- const pruneIfDue = async () => {
2894
- const now = Date.now();
2895
- if (now - lastPrunedAt < SLACK_INGRESS_PRUNE_INTERVAL_MS) return;
2896
- await getQueue().prune({
3099
+ if (!app) throw new Error("Slack ingress receiver is not attached to a Bolt app.");
3100
+ await app.processEvent({
3101
+ body: raw.body,
3102
+ ack: async () => {},
3103
+ ...raw.retryNum === void 0 ? {} : { retryNum: raw.retryNum },
3104
+ ...raw.retryReason === void 0 ? {} : { retryReason: raw.retryReason },
3105
+ customProperties: { [SLACK_INGRESS_LIFECYCLE_CONTEXT_KEY]: lifecycle }
3106
+ });
3107
+ },
3108
+ pollIntervalMs: options.pollIntervalMs ?? SLACK_INGRESS_POLL_INTERVAL_MS,
3109
+ retention: {
3110
+ pruneIntervalMs: SLACK_INGRESS_PRUNE_INTERVAL_MS,
2897
3111
  completedTtlMs: SLACK_INGRESS_COMPLETED_TTL_MS,
2898
3112
  completedMaxEntries: SLACK_INGRESS_COMPLETED_MAX_ENTRIES,
2899
3113
  failedTtlMs: SLACK_INGRESS_FAILED_TTL_MS,
2900
- failedMaxEntries: SLACK_INGRESS_FAILED_MAX_ENTRIES,
2901
- now
2902
- });
2903
- lastPrunedAt = now;
2904
- };
2905
- const runPump = async () => {
2906
- try {
2907
- for (;;) {
2908
- requested = false;
2909
- await pruneIfDue();
2910
- const activeDrain = getDrain();
2911
- const { started } = await activeDrain.drainOnce();
2912
- await activeDrain.waitForIdle();
2913
- if (!running || !requested && started === 0) break;
2914
- }
2915
- } catch (error) {
2916
- options.onLog?.(`slack ingress drain failed: ${formatErrorMessage(error)}`);
2917
- } finally {
2918
- pumping = void 0;
2919
- if (running && requested) requestDrain();
2920
- }
2921
- };
2922
- const requestDrain = () => {
2923
- requested = true;
2924
- if (!running || pumping) return;
2925
- pumping = runPump();
2926
- };
3114
+ failedMaxEntries: SLACK_INGRESS_FAILED_MAX_ENTRIES
3115
+ },
3116
+ appendRetryDelaysMs: [0],
3117
+ drain: {
3118
+ resolveNonRetryableFailure: resolveSlackIngressNonRetryableFailure,
3119
+ deriveLaneKey: (record) => record.payload.kind === "relay" ? resolveSlackIngressLane({ event: record.payload.message }, record.id) : resolveSlackIngressLane(record.payload.body, record.id),
3120
+ ...options.adoptionStallTimeoutMs === void 0 ? {} : { adoptionStallTimeoutMs: options.adoptionStallTimeoutMs },
3121
+ ...options.onLog ? { onLog: options.onLog } : {}
3122
+ },
3123
+ ...options.abortSignal ? { abortSignal: options.abortSignal } : {},
3124
+ onError: (error) => options.onLog?.(`slack ingress drain failed: ${formatErrorMessage(error)}`)
3125
+ });
2927
3126
  const acceptReceiverEvent = async (event) => {
2928
3127
  if (!isSlackEventCallback(event.body)) {
2929
3128
  if (!app) throw new Error("Slack ingress receiver is not attached to a Bolt app.");
2930
3129
  await app.processEvent(event);
2931
3130
  return;
2932
3131
  }
2933
- const eventId = resolveSlackEventId(event.body);
2934
- if (!eventId) throw new SlackIngressPayloadError("Slack Events API envelope missing event_id.");
2935
- const receivedAt = Date.now();
2936
- await getQueue().enqueue(eventId, {
2937
- version: SLACK_INGRESS_PAYLOAD_VERSION,
2938
- receivedAt,
3132
+ await monitor.admit({
2939
3133
  kind: "events-api",
2940
3134
  body: event.body,
2941
3135
  ...event.retryNum === void 0 ? {} : { retryNum: event.retryNum },
2942
- ...event.retryReason === void 0 ? {} : { retryReason: event.retryReason }
2943
- }, { receivedAt });
2944
- await event.ack();
2945
- requestDrain();
3136
+ ...event.retryReason === void 0 ? {} : { retryReason: event.retryReason },
3137
+ afterDurableAdmission: () => event.ack()
3138
+ });
2946
3139
  };
2947
3140
  const acceptRelayEvent = async (event) => {
2948
- const receivedAt = Date.now();
2949
- await getQueue().enqueue(resolveSlackRelayIngressEventId(event), {
2950
- version: SLACK_INGRESS_PAYLOAD_VERSION,
2951
- receivedAt,
3141
+ await monitor.admit({
2952
3142
  kind: "relay",
3143
+ deliveryId: event.deliveryId,
2953
3144
  message: event.message
2954
- }, { receivedAt });
2955
- requestDrain();
3145
+ });
2956
3146
  };
2957
3147
  return {
2958
3148
  wrapReceiver: (receiver) => {
@@ -2971,31 +3161,9 @@ function createSlackDurableIngress(options) {
2971
3161
  attachRelayDispatch: (dispatch) => {
2972
3162
  relayDispatch = dispatch;
2973
3163
  },
2974
- start: () => {
2975
- if (running) return;
2976
- running = true;
2977
- pollTimer = setInterval(requestDrain, options.pollIntervalMs ?? SLACK_INGRESS_POLL_INTERVAL_MS);
2978
- pollTimer.unref?.();
2979
- requestDrain();
2980
- },
2981
- stop: async () => {
2982
- running = false;
2983
- if (pollTimer) {
2984
- clearInterval(pollTimer);
2985
- pollTimer = void 0;
2986
- }
2987
- drain?.dispose();
2988
- await pumping;
2989
- await drain?.waitForIdle();
2990
- },
2991
- waitForIdle: async () => {
2992
- for (;;) {
2993
- const activePump = pumping;
2994
- if (!activePump) break;
2995
- await activePump;
2996
- }
2997
- await drain?.waitForIdle();
2998
- }
3164
+ start: monitor.start,
3165
+ stop: monitor.stop,
3166
+ waitForIdle: monitor.waitForIdle
2999
3167
  };
3000
3168
  }
3001
3169
  //#endregion
@@ -3377,6 +3545,10 @@ function registerSlackMonitorEvents(params) {
3377
3545
  slashCommandName: params.appHomeSlashCommandName,
3378
3546
  trackEvent: params.trackEvent
3379
3547
  });
3548
+ registerSlackAgentEvents({
3549
+ ctx: params.ctx,
3550
+ trackEvent: params.trackEvent
3551
+ });
3380
3552
  registerSlackInteractionEvents({
3381
3553
  ctx: params.ctx,
3382
3554
  trackEvent: params.trackEvent
@@ -3423,22 +3595,11 @@ function createSlackMessageDispatchReplayGuard(params = {}) {
3423
3595
  }
3424
3596
  /** Claim one logical message key; an in-flight sibling claim settles to duplicate. */
3425
3597
  async function claimSlackMessageDispatchReplay(params) {
3426
- let releaseRetries = 0;
3427
- while (true) {
3428
- const claim = await params.guard.claim({ keys: [params.key] });
3429
- if (claim.kind === "claimed") return {
3430
- kind: "claimed",
3431
- handle: claim.handle
3432
- };
3433
- if (claim.kind === "duplicate" || claim.kind === "invalid") return { kind: "duplicate" };
3434
- try {
3435
- await claim.pending;
3436
- return { kind: "duplicate" };
3437
- } catch {
3438
- releaseRetries += 1;
3439
- if (releaseRetries > 1) return { kind: "duplicate" };
3440
- }
3441
- }
3598
+ const claim = await runClaimableDedupeClaimLoop(() => params.guard.claim({ keys: [params.key] }), (_error, rejectionCount) => rejectionCount <= 1);
3599
+ return claim.kind === "claimed" ? {
3600
+ kind: "claimed",
3601
+ handle: claim.handle
3602
+ } : { kind: "duplicate" };
3442
3603
  }
3443
3604
  //#endregion
3444
3605
  //#region extensions/slack/src/monitor/message-handler/debounce-key.ts
@@ -3566,7 +3727,7 @@ function createSlackThreadTsResolver(params) {
3566
3727
  }
3567
3728
  //#endregion
3568
3729
  //#region extensions/slack/src/monitor/message-handler.ts
3569
- const loadSlackMessagePipeline = createLazyRuntimeModule(() => import("./pipeline.runtime-CTvokbty.js"));
3730
+ const loadSlackMessagePipeline = createLazyRuntimeModule(() => import("./pipeline.runtime-5rRYZuX5.js"));
3570
3731
  function createSlackDispatchCompletion() {
3571
3732
  let resolve;
3572
3733
  let reject;
@@ -4144,13 +4305,11 @@ function createSlackBoltApp(params) {
4144
4305
  const socketModeReceiverOptions = {
4145
4306
  appToken: params.appToken ?? "",
4146
4307
  autoReconnectEnabled: true,
4147
- clientPingTimeout: params.socketMode?.clientPingTimeout ?? OPENCLAW_SLACK_CLIENT_PING_TIMEOUT_MS,
4308
+ clientPingTimeout: OPENCLAW_SLACK_CLIENT_PING_TIMEOUT_MS,
4148
4309
  logger: socketModeLogger,
4149
4310
  installerOptions: { clientOptions: params.clientOptions },
4150
4311
  ...params.wrapReceiver ? { processEventErrorHandler: async () => false } : {}
4151
4312
  };
4152
- if (params.socketMode?.serverPingTimeout !== void 0) socketModeReceiverOptions.serverPingTimeout = params.socketMode.serverPingTimeout;
4153
- if (params.socketMode?.pingPongLoggingEnabled !== void 0) socketModeReceiverOptions.pingPongLoggingEnabled = params.socketMode.pingPongLoggingEnabled;
4154
4313
  let receiver;
4155
4314
  if (params.slackMode === "socket") {
4156
4315
  receiver = new params.interop.SocketModeReceiver(socketModeReceiverOptions);
@@ -4415,7 +4574,7 @@ const SLACK_COMMAND_ARG_CONFIRM_TEXT_MAX = 300;
4415
4574
  const SLACK_HEADER_TEXT_MAX = 150;
4416
4575
  const SLACK_COMMAND_ARG_ACTION_BLOCKS_MAX = 47;
4417
4576
  const loadSlashCommandsRuntime = createLazyRuntimeModule(() => import("./slash-commands.runtime-BTTMlmwy.js"));
4418
- const loadSlashDispatchRuntime = createLazyRuntimeModule(() => import("./slash-dispatch.runtime-BT-mMm-f.js"));
4577
+ const loadSlashDispatchRuntime = createLazyRuntimeModule(() => import("./slash-dispatch.runtime-lfeIsXTX.js"));
4419
4578
  const loadSlackPluginCommandsRuntime = createLazyRuntimeModule(() => import("./slash-plugin-commands.runtime-Dosfcx3X.js"));
4420
4579
  const loadSlashSkillCommandsRuntime = createLazyRuntimeModule(() => import("./slash-skill-commands.runtime-CD1J2ODY.js"));
4421
4580
  function resolveSlackCommandMenuModelContext(params) {
@@ -4808,8 +4967,12 @@ async function registerSlackMonitorSlashCommands(params) {
4808
4967
  agentId: menuRoute.agentId,
4809
4968
  sessionKey: menuRoute.sessionKey
4810
4969
  }) : {};
4811
- const menuModelCatalog = commandDefinition.key === "think" && menuNeedsModelContext ? await loadModelCatalog({
4970
+ const menuModelCatalog = commandDefinition.key === "think" && menuNeedsModelContext ? await loadPreparedModelCatalog({
4812
4971
  config: cfg,
4972
+ ...menuRoute ? {
4973
+ agentId: menuRoute.agentId,
4974
+ agentDir: resolveAgentDir(cfg, menuRoute.agentId)
4975
+ } : {},
4813
4976
  readOnly: true
4814
4977
  }) : void 0;
4815
4978
  const menu = resolveCommandArgMenu({
@@ -4867,7 +5030,7 @@ async function registerSlackMonitorSlashCommands(params) {
4867
5030
  sessionPrefix: slashCommand.sessionPrefix,
4868
5031
  userId: command.user_id,
4869
5032
  targetSessionKey: route.sessionKey,
4870
- lowercaseSessionKey: true
5033
+ sessionKeyCase: "lowercase"
4871
5034
  });
4872
5035
  const slashReplyTarget = !slashCommand.ephemeral && isRoomish ? `channel:${command.channel_id}` : `user:${command.user_id}`;
4873
5036
  const ctxPayload = finalizeInboundContext({
@@ -4946,12 +5109,17 @@ async function registerSlackMonitorSlashCommands(params) {
4946
5109
  });
4947
5110
  };
4948
5111
  const pendingSlashReplies = [];
5112
+ const shouldDeliverBlockImmediately = commandDefinition?.key === "login";
4949
5113
  const { counts } = await dispatchReplyWithDispatcher({
4950
5114
  ctx: ctxPayload,
4951
5115
  cfg,
4952
5116
  dispatcherOptions: {
4953
5117
  ...replyPipeline,
4954
- deliver: async (payload) => {
5118
+ deliver: async (payload, info) => {
5119
+ if (info.kind === "block" && shouldDeliverBlockImmediately) {
5120
+ await deliverSlashPayloads([payload]);
5121
+ return;
5122
+ }
4955
5123
  pendingSlashReplies.push(payload);
4956
5124
  },
4957
5125
  onError: (err, info) => {
@@ -5155,7 +5323,7 @@ async function getSlackBoltInterop() {
5155
5323
  }
5156
5324
  return slackBoltInterop;
5157
5325
  }
5158
- const loadSlackRelaySource = createLazyRuntimeModule(() => import("./relay-source-Ea_P9VcO.js"));
5326
+ const loadSlackRelaySource = createLazyRuntimeModule(() => import("./relay-source-Df9EaiTF.js"));
5159
5327
  const SLACK_WEBHOOK_MAX_BODY_BYTES = 1024 * 1024;
5160
5328
  const SLACK_WEBHOOK_BODY_TIMEOUT_MS = 3e4;
5161
5329
  function resolveStableSlackUserIdEntry(raw) {
@@ -5301,7 +5469,7 @@ async function monitorSlackProvider(opts = {}) {
5301
5469
  log: (message) => runtime.log?.(warn(message))
5302
5470
  });
5303
5471
  const resolveToken = account.userToken || botToken;
5304
- const useAccessGroups = cfg.commands?.useAccessGroups !== false;
5472
+ const useAccessGroups = true;
5305
5473
  const reactionMode = slackCfg.reactionNotifications ?? "own";
5306
5474
  const reactionAllowlist = slackCfg.reactionAllowlist ?? [];
5307
5475
  const replyToMode = slackCfg.replyToMode ?? "off";
@@ -5313,7 +5481,6 @@ async function monitorSlackProvider(opts = {}) {
5313
5481
  const ackReactionScope = cfg.messages?.ackReactionScope ?? "group-mentions";
5314
5482
  const typingReaction = slackCfg.typingReaction?.trim() ?? "";
5315
5483
  const mediaMaxBytes = (opts.mediaMaxMb ?? slackCfg.mediaMaxMb ?? 20) * 1024 * 1024;
5316
- const removeAckAfterReply = cfg.messages?.removeAckAfterReply ?? false;
5317
5484
  const clientOptions = resolveSlackWebClientOptions();
5318
5485
  const durableIngress = createSlackDurableIngress({
5319
5486
  accountId: account.accountId,
@@ -5328,7 +5495,6 @@ async function monitorSlackProvider(opts = {}) {
5328
5495
  signingSecret: slackMode === "http" ? signingSecret ?? void 0 : void 0,
5329
5496
  slackWebhookPath,
5330
5497
  clientOptions,
5331
- ...slackCfg.socketMode ? { socketMode: slackCfg.socketMode } : {},
5332
5498
  wrapReceiver: durableIngress.wrapReceiver
5333
5499
  });
5334
5500
  const gracefulStop = async () => {
@@ -5435,8 +5601,7 @@ async function monitorSlackProvider(opts = {}) {
5435
5601
  textLimit,
5436
5602
  ackReactionScope,
5437
5603
  typingReaction,
5438
- mediaMaxBytes,
5439
- removeAckAfterReply
5604
+ mediaMaxBytes
5440
5605
  });
5441
5606
  const trackEvent = opts.setStatus ? () => {
5442
5607
  opts.setStatus({