@spinabot/brigade 1.5.0 → 1.6.0

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 (109) hide show
  1. package/dist/agents/channels/bundled-channel-metas.d.ts +2 -0
  2. package/dist/agents/channels/bundled-channel-metas.d.ts.map +1 -1
  3. package/dist/agents/channels/bundled-channel-metas.js +11 -0
  4. package/dist/agents/channels/bundled-channel-metas.js.map +1 -1
  5. package/dist/agents/channels/manager.d.ts.map +1 -1
  6. package/dist/agents/channels/manager.js +18 -0
  7. package/dist/agents/channels/manager.js.map +1 -1
  8. package/dist/agents/channels/sdk.d.ts +2 -0
  9. package/dist/agents/channels/sdk.d.ts.map +1 -1
  10. package/dist/agents/channels/sdk.js +2 -0
  11. package/dist/agents/channels/sdk.js.map +1 -1
  12. package/dist/agents/channels/slack/account-config.d.ts +172 -0
  13. package/dist/agents/channels/slack/account-config.d.ts.map +1 -0
  14. package/dist/agents/channels/slack/account-config.js +353 -0
  15. package/dist/agents/channels/slack/account-config.js.map +1 -0
  16. package/dist/agents/channels/slack/account-registry.d.ts +45 -0
  17. package/dist/agents/channels/slack/account-registry.d.ts.map +1 -0
  18. package/dist/agents/channels/slack/account-registry.js +58 -0
  19. package/dist/agents/channels/slack/account-registry.js.map +1 -0
  20. package/dist/agents/channels/slack/adapter.d.ts +66 -0
  21. package/dist/agents/channels/slack/adapter.d.ts.map +1 -0
  22. package/dist/agents/channels/slack/adapter.js +547 -0
  23. package/dist/agents/channels/slack/adapter.js.map +1 -0
  24. package/dist/agents/channels/slack/approval-authorize.d.ts +43 -0
  25. package/dist/agents/channels/slack/approval-authorize.d.ts.map +1 -0
  26. package/dist/agents/channels/slack/approval-authorize.js +71 -0
  27. package/dist/agents/channels/slack/approval-authorize.js.map +1 -0
  28. package/dist/agents/channels/slack/approval-native.d.ts +70 -0
  29. package/dist/agents/channels/slack/approval-native.d.ts.map +1 -0
  30. package/dist/agents/channels/slack/approval-native.js +85 -0
  31. package/dist/agents/channels/slack/approval-native.js.map +1 -0
  32. package/dist/agents/channels/slack/blocks.d.ts +125 -0
  33. package/dist/agents/channels/slack/blocks.d.ts.map +1 -0
  34. package/dist/agents/channels/slack/blocks.js +145 -0
  35. package/dist/agents/channels/slack/blocks.js.map +1 -0
  36. package/dist/agents/channels/slack/command-menu.d.ts +44 -0
  37. package/dist/agents/channels/slack/command-menu.d.ts.map +1 -0
  38. package/dist/agents/channels/slack/command-menu.js +66 -0
  39. package/dist/agents/channels/slack/command-menu.js.map +1 -0
  40. package/dist/agents/channels/slack/connection.d.ts +422 -0
  41. package/dist/agents/channels/slack/connection.d.ts.map +1 -0
  42. package/dist/agents/channels/slack/connection.js +1042 -0
  43. package/dist/agents/channels/slack/connection.js.map +1 -0
  44. package/dist/agents/channels/slack/directory-live.d.ts +129 -0
  45. package/dist/agents/channels/slack/directory-live.d.ts.map +1 -0
  46. package/dist/agents/channels/slack/directory-live.js +148 -0
  47. package/dist/agents/channels/slack/directory-live.js.map +1 -0
  48. package/dist/agents/channels/slack/draft-stream.d.ts +93 -0
  49. package/dist/agents/channels/slack/draft-stream.d.ts.map +1 -0
  50. package/dist/agents/channels/slack/draft-stream.js +218 -0
  51. package/dist/agents/channels/slack/draft-stream.js.map +1 -0
  52. package/dist/agents/channels/slack/format.d.ts +41 -0
  53. package/dist/agents/channels/slack/format.d.ts.map +1 -0
  54. package/dist/agents/channels/slack/format.js +271 -0
  55. package/dist/agents/channels/slack/format.js.map +1 -0
  56. package/dist/agents/channels/slack/inbound-extras.d.ts +179 -0
  57. package/dist/agents/channels/slack/inbound-extras.d.ts.map +1 -0
  58. package/dist/agents/channels/slack/inbound-extras.js +257 -0
  59. package/dist/agents/channels/slack/inbound-extras.js.map +1 -0
  60. package/dist/agents/channels/slack/index.d.ts +15 -0
  61. package/dist/agents/channels/slack/index.d.ts.map +1 -0
  62. package/dist/agents/channels/slack/index.js +15 -0
  63. package/dist/agents/channels/slack/index.js.map +1 -0
  64. package/dist/agents/channels/slack/media.d.ts +90 -0
  65. package/dist/agents/channels/slack/media.d.ts.map +1 -0
  66. package/dist/agents/channels/slack/media.js +215 -0
  67. package/dist/agents/channels/slack/media.js.map +1 -0
  68. package/dist/agents/channels/slack/module.d.ts +26 -0
  69. package/dist/agents/channels/slack/module.d.ts.map +1 -0
  70. package/dist/agents/channels/slack/module.js +67 -0
  71. package/dist/agents/channels/slack/module.js.map +1 -0
  72. package/dist/agents/channels/slack/plugin.d.ts +69 -0
  73. package/dist/agents/channels/slack/plugin.d.ts.map +1 -0
  74. package/dist/agents/channels/slack/plugin.js +318 -0
  75. package/dist/agents/channels/slack/plugin.js.map +1 -0
  76. package/dist/agents/channels/slack/probe.d.ts +72 -0
  77. package/dist/agents/channels/slack/probe.d.ts.map +1 -0
  78. package/dist/agents/channels/slack/probe.js +103 -0
  79. package/dist/agents/channels/slack/probe.js.map +1 -0
  80. package/dist/agents/channels/slack/proxy-agent.d.ts +30 -0
  81. package/dist/agents/channels/slack/proxy-agent.d.ts.map +1 -0
  82. package/dist/agents/channels/slack/proxy-agent.js +44 -0
  83. package/dist/agents/channels/slack/proxy-agent.js.map +1 -0
  84. package/dist/agents/channels/slack/reasoning-lane.d.ts +42 -0
  85. package/dist/agents/channels/slack/reasoning-lane.d.ts.map +1 -0
  86. package/dist/agents/channels/slack/reasoning-lane.js +68 -0
  87. package/dist/agents/channels/slack/reasoning-lane.js.map +1 -0
  88. package/dist/agents/channels/slack/user-directory.d.ts +69 -0
  89. package/dist/agents/channels/slack/user-directory.d.ts.map +1 -0
  90. package/dist/agents/channels/slack/user-directory.js +94 -0
  91. package/dist/agents/channels/slack/user-directory.js.map +1 -0
  92. package/dist/agents/channels/slack/webhook.d.ts +89 -0
  93. package/dist/agents/channels/slack/webhook.d.ts.map +1 -0
  94. package/dist/agents/channels/slack/webhook.js +228 -0
  95. package/dist/agents/channels/slack/webhook.js.map +1 -0
  96. package/dist/agents/channels/telegram/format.d.ts.map +1 -1
  97. package/dist/agents/channels/telegram/format.js +17 -1
  98. package/dist/agents/channels/telegram/format.js.map +1 -1
  99. package/dist/agents/channels/telegram/webhook.d.ts.map +1 -1
  100. package/dist/agents/channels/telegram/webhook.js +7 -1
  101. package/dist/agents/channels/telegram/webhook.js.map +1 -1
  102. package/dist/agents/extensions/modules/index.d.ts.map +1 -1
  103. package/dist/agents/extensions/modules/index.js +5 -0
  104. package/dist/agents/extensions/modules/index.js.map +1 -1
  105. package/dist/buildstamp.json +1 -1
  106. package/dist/core/server.d.ts.map +1 -1
  107. package/dist/core/server.js +24 -5
  108. package/dist/core/server.js.map +1 -1
  109. package/package.json +4 -1
@@ -0,0 +1,353 @@
1
+ /**
2
+ * Slack config-shape helpers (multi-WORKSPACE aware; mirrors Telegram's
3
+ * `account-config.ts`).
4
+ *
5
+ * Slack needs MORE than one secret per workspace, unlike Telegram's single bot
6
+ * token:
7
+ * - `botToken` (`xoxb-…`) — the bot user token; every Web API call uses it.
8
+ * - `appToken` (`xapp-…`) — the app-level token; REQUIRED for Socket Mode
9
+ * (opens the events websocket via
10
+ * `apps.connections.open`).
11
+ * - `signingSecret` — HMAC secret; REQUIRED for Events-API (HTTP)
12
+ * mode to verify Slack's request signature.
13
+ * - `userToken` (`xoxp-…`) — OPTIONAL; user-scoped token for reads that the
14
+ * bot token can't do (e.g. some file fetches).
15
+ *
16
+ * Two config shapes are recognised so the surface lines up with WhatsApp /
17
+ * Telegram:
18
+ *
19
+ * Legacy (single-workspace):
20
+ * channels.slack = { enabled: true, botToken: "xoxb-…", appToken: "xapp-…" }
21
+ *
22
+ * Multi-workspace:
23
+ * channels.slack = {
24
+ * enabled: true,
25
+ * accounts: [
26
+ * { id: "acme", botToken: "xoxb-AAA", appToken: "xapp-AAA" },
27
+ * { id: "labs", botToken: "xoxb-BBB", appToken: "xapp-BBB" },
28
+ * ],
29
+ * }
30
+ *
31
+ * A legacy config with no `accounts[]` reads as `[{ id: "default" }]`.
32
+ *
33
+ * Token resolution mirrors Telegram: a `${VAR}` ref expands against
34
+ * `process.env`; otherwise the literal passes through; then — for the bot token
35
+ * only — a DURABLE sealed token (written by `connect_channel`) is consulted so
36
+ * the channel survives a reboot; finally a per-secret env var is the last-resort
37
+ * fallback.
38
+ *
39
+ * Honesty note on sealing: `connect_channel` seals exactly ONE secret per
40
+ * channel, under `channel:slack` — that is the BOT token. The app-level token
41
+ * and signing secret are NOT durably sealed today; they must come from config
42
+ * (`${VAR}`/literal) or their per-secret env var (`SLACK_APP_TOKEN` /
43
+ * `SLACK_SIGNING_SECRET`). If a future `connect_channel` learns to seal those
44
+ * under `channel:slack:app` / `channel:slack:signing`, wire the sealed-read
45
+ * fallback back into `resolveSlackAppToken` / `resolveSlackSigningSecret`.
46
+ */
47
+ import { readSealedChannelToken } from "../channel-secrets.js";
48
+ const CHANNEL_ID = "slack";
49
+ const DEFAULT_ACCOUNT_ID = "default";
50
+ /** Per-secret env vars consulted as a last-resort fallback. */
51
+ const BOT_TOKEN_ENV_VAR = "SLACK_BOT_TOKEN";
52
+ const APP_TOKEN_ENV_VAR = "SLACK_APP_TOKEN";
53
+ const SIGNING_SECRET_ENV_VAR = "SLACK_SIGNING_SECRET";
54
+ const USER_TOKEN_ENV_VAR = "SLACK_USER_TOKEN";
55
+ /**
56
+ * Standard proxy env vars consulted as a last-resort proxy fallback, in
57
+ * precedence order. Lower-case wins over upper-case (curl/undici convention),
58
+ * and a TLS-oriented `https_proxy` outranks the catch-all `ALL_PROXY`. These
59
+ * mirror the keys undici's own `EnvHttpProxyAgent` honours (same set Telegram
60
+ * uses).
61
+ */
62
+ const PROXY_ENV_VARS = ["https_proxy", "HTTPS_PROXY", "all_proxy", "ALL_PROXY"];
63
+ /**
64
+ * Sealed-token key for the bot token (`channel:slack`) — the ONLY Slack secret
65
+ * `connect_channel` seals today. The app token + signing secret are not sealed
66
+ * (see the header note), so their resolvers pass `sealKey: null`.
67
+ */
68
+ const SEAL_KEY_BOT = CHANNEL_ID; // `channel:slack`
69
+ /** `${VAR}` secret-ref form — identical to `config/io.ts`'s SECRET_REF_PATTERN. */
70
+ const SECRET_REF_PATTERN = /^\$\{([A-Z_][A-Z0-9_]*)\}$/;
71
+ /** Default gateway path the Events-API transport registers + Slack POSTs to. */
72
+ const DEFAULT_EVENTS_PATH = "/slack/events";
73
+ /** Read `channels.slack` loosely (schema keeps it open). */
74
+ function slackChannelConfig(cfg) {
75
+ return cfg.channels?.[CHANNEL_ID];
76
+ }
77
+ /**
78
+ * Resolve a single token-ish string: a `${VAR}` ref expands against
79
+ * `process.env`; any other non-empty string passes through verbatim; empty /
80
+ * missing returns "".
81
+ */
82
+ function resolveTokenRef(raw, env) {
83
+ if (typeof raw !== "string")
84
+ return "";
85
+ const trimmed = raw.trim();
86
+ if (!trimmed)
87
+ return "";
88
+ const m = SECRET_REF_PATTERN.exec(trimmed);
89
+ if (m && m[1])
90
+ return (env[m[1]] ?? "").trim();
91
+ return trimmed;
92
+ }
93
+ /** Is the Slack channel switched on at all (any shape)? */
94
+ export function slackChannelEnabled(cfg) {
95
+ return slackChannelConfig(cfg)?.enabled === true;
96
+ }
97
+ /** List configured account ids. Legacy single-account configs surface `["default"]`. */
98
+ export function listSlackAccountIds(cfg) {
99
+ const slot = slackChannelConfig(cfg);
100
+ if (!slot || slot.enabled !== true)
101
+ return [];
102
+ const accounts = Array.isArray(slot.accounts) ? slot.accounts : undefined;
103
+ if (!accounts || accounts.length === 0)
104
+ return [DEFAULT_ACCOUNT_ID];
105
+ const ids = [];
106
+ const seen = new Set();
107
+ for (const entry of accounts) {
108
+ const id = typeof entry?.id === "string" ? entry.id.trim() : "";
109
+ if (!id || seen.has(id))
110
+ continue;
111
+ seen.add(id);
112
+ ids.push(id);
113
+ }
114
+ // A half-typed `accounts:[]` still degrades to the default account so the
115
+ // channel isn't silently disabled.
116
+ return ids.length === 0 ? [DEFAULT_ACCOUNT_ID] : ids;
117
+ }
118
+ /** Look up the raw account entry from config (or null when missing). */
119
+ function findAccountEntry(cfg, accountId) {
120
+ const slot = slackChannelConfig(cfg);
121
+ if (!slot)
122
+ return null;
123
+ const accounts = Array.isArray(slot.accounts) ? slot.accounts : undefined;
124
+ if (!accounts)
125
+ return null;
126
+ for (const entry of accounts) {
127
+ const id = typeof entry?.id === "string" ? entry.id.trim() : "";
128
+ if (id === accountId)
129
+ return entry;
130
+ }
131
+ return null;
132
+ }
133
+ /**
134
+ * Resolve one Slack secret for an account. Precedence (mirrors Telegram's token
135
+ * resolution): per-account config `${VAR}`/literal → top-level config → durable
136
+ * sealed token → per-secret env var. Returns `""` when nothing resolves.
137
+ */
138
+ function resolveSecret(cfg, accountId, field, sealKey, envVar, env) {
139
+ const id = accountId?.trim() || DEFAULT_ACCOUNT_ID;
140
+ const slot = slackChannelConfig(cfg);
141
+ const entry = findAccountEntry(cfg, id);
142
+ const perAccount = resolveTokenRef(entry?.[field], env);
143
+ if (perAccount)
144
+ return perAccount;
145
+ const topLevel = resolveTokenRef(slot?.[field], env);
146
+ if (topLevel)
147
+ return topLevel;
148
+ if (sealKey) {
149
+ const sealed = readSealedChannelToken(sealKey);
150
+ if (sealed)
151
+ return sealed;
152
+ }
153
+ if (envVar) {
154
+ const fromEnv = (env[envVar] ?? "").trim();
155
+ if (fromEnv)
156
+ return fromEnv;
157
+ }
158
+ return "";
159
+ }
160
+ /** Resolve the bot user token (`xoxb-…`) for an account. */
161
+ export function resolveSlackBotToken(cfg, accountId, env = process.env) {
162
+ return resolveSecret(cfg, accountId, "botToken", SEAL_KEY_BOT, BOT_TOKEN_ENV_VAR, env);
163
+ }
164
+ /**
165
+ * Resolve the app-level token (`xapp-…`, Socket Mode) for an account. NOT sealed
166
+ * by `connect_channel` today (sealKey `null`) — comes from config or
167
+ * `SLACK_APP_TOKEN`.
168
+ */
169
+ export function resolveSlackAppToken(cfg, accountId, env = process.env) {
170
+ return resolveSecret(cfg, accountId, "appToken", null, APP_TOKEN_ENV_VAR, env);
171
+ }
172
+ /**
173
+ * Resolve the HMAC signing secret (Events-API mode) for an account. NOT sealed
174
+ * by `connect_channel` today (sealKey `null`) — comes from config or
175
+ * `SLACK_SIGNING_SECRET`.
176
+ */
177
+ export function resolveSlackSigningSecret(cfg, accountId, env = process.env) {
178
+ return resolveSecret(cfg, accountId, "signingSecret", null, SIGNING_SECRET_ENV_VAR, env);
179
+ }
180
+ /** Resolve the optional user token (`xoxp-…`) for an account. */
181
+ export function resolveSlackUserToken(cfg, accountId, env = process.env) {
182
+ return resolveSecret(cfg, accountId, "userToken", null, USER_TOKEN_ENV_VAR, env);
183
+ }
184
+ /**
185
+ * Resolve the proxy URL all Slack API calls (+ the Socket Mode websocket) should
186
+ * route through. Precedence (mirrors Telegram's `resolveTelegramProxyUrl`):
187
+ * 1. The per-account `accounts[].proxy` (multi-workspace shape), `${VAR}`-resolved.
188
+ * 2. The top-level `channels.slack.proxy`, `${VAR}`-resolved.
189
+ * 3. The first set standard proxy env var (`https_proxy` / `HTTPS_PROXY` /
190
+ * `all_proxy` / `ALL_PROXY`) — last-resort fallback.
191
+ * Returns `""` when none is configured → a DIRECT connection (the default,
192
+ * byte-unchanged from before proxy support existed).
193
+ *
194
+ * `${VAR}` refs are resolved here the same way `botToken` is, so an operator can
195
+ * keep the proxy (which may carry `user:pass@` creds) out of the committed
196
+ * config as `channels.slack.proxy: "${SLACK_PROXY}"`.
197
+ */
198
+ export function resolveSlackProxyUrl(cfg, accountId, env = process.env) {
199
+ const id = accountId?.trim() || DEFAULT_ACCOUNT_ID;
200
+ const slot = slackChannelConfig(cfg);
201
+ const entry = findAccountEntry(cfg, id);
202
+ const perAccount = resolveTokenRef(entry?.proxy, env);
203
+ if (perAccount)
204
+ return perAccount;
205
+ const topLevel = resolveTokenRef(slot?.proxy, env);
206
+ if (topLevel)
207
+ return topLevel;
208
+ for (const key of PROXY_ENV_VARS) {
209
+ const value = (env[key] ?? "").trim();
210
+ if (value)
211
+ return value;
212
+ }
213
+ return "";
214
+ }
215
+ /**
216
+ * Mask a proxy URL down to `scheme://host:port` (creds + path dropped) so it is
217
+ * safe to log. A malformed URL is reduced to its scheme only; an empty input
218
+ * returns "". NEVER log a raw proxy URL — it may embed `user:pass@`.
219
+ */
220
+ export function maskProxyUrl(proxyUrl) {
221
+ const raw = (proxyUrl ?? "").trim();
222
+ if (!raw)
223
+ return "";
224
+ try {
225
+ const u = new URL(raw);
226
+ return `${u.protocol}//${u.host}`; // host includes :port; userinfo + path/query dropped
227
+ }
228
+ catch {
229
+ const scheme = /^([a-z][a-z0-9+.-]*):\/\//i.exec(raw)?.[1];
230
+ return scheme ? `${scheme}://<masked>` : "<masked>";
231
+ }
232
+ }
233
+ /** Resolve a per-account view of the config (defaults + token resolution filled in). */
234
+ export function resolveSlackAccount(cfg, accountId, env = process.env) {
235
+ const slot = slackChannelConfig(cfg);
236
+ const id = accountId?.trim() || DEFAULT_ACCOUNT_ID;
237
+ const entry = findAccountEntry(cfg, id);
238
+ const enabled = entry?.enabled !== false && slot?.enabled === true;
239
+ return {
240
+ accountId: id,
241
+ enabled,
242
+ botToken: resolveSlackBotToken(cfg, id, env),
243
+ appToken: resolveSlackAppToken(cfg, id, env),
244
+ signingSecret: resolveSlackSigningSecret(cfg, id, env),
245
+ userToken: resolveSlackUserToken(cfg, id, env),
246
+ proxyUrl: resolveSlackProxyUrl(cfg, id, env),
247
+ verbose: slot?.verbose === true,
248
+ };
249
+ }
250
+ /**
251
+ * Resolve the Slack transport config. Defaults to `socket` (Brigade is
252
+ * local-first and Socket Mode needs no public URL); `events` is opt-in via
253
+ * `channels.slack.mode: "events"`.
254
+ */
255
+ export function slackEventsConfig(cfg) {
256
+ const slot = slackChannelConfig(cfg);
257
+ const rawMode = typeof slot?.mode === "string" ? slot.mode.trim().toLowerCase() : "";
258
+ const mode = rawMode === "events" || rawMode === "http" ? "events" : "socket";
259
+ const ev = slot?.events ?? {};
260
+ const path = typeof ev.path === "string" && ev.path.trim() ? ev.path.trim() : DEFAULT_EVENTS_PATH;
261
+ return {
262
+ mode,
263
+ url: typeof ev.url === "string" ? ev.url.trim() : "",
264
+ path: path.startsWith("/") ? path : `/${path}`,
265
+ };
266
+ }
267
+ /**
268
+ * Normalize a path to a leading-slash, trailing-slash-stripped form so derived
269
+ * per-account paths concatenate cleanly. `"/slack/events/"` → `"/slack/events"`.
270
+ */
271
+ function normalizeEventsPath(raw) {
272
+ const trimmed = (raw ?? "").trim();
273
+ const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
274
+ return withSlash.length > 1 ? withSlash.replace(/\/+$/, "") : withSlash;
275
+ }
276
+ /**
277
+ * Resolve the events-mode gateway route path for ONE account. Multi-workspace
278
+ * installs need a DISTINCT path per workspace (Slack POSTs to a per-app URL, and
279
+ * the gateway routes by exact path):
280
+ *
281
+ * - default account → the configured base events path (`channels.slack.events.
282
+ * path`, default `/slack/events`) — byte-identical to the single-workspace
283
+ * path so an existing default-only install is unchanged.
284
+ * - a named account → its explicit `accounts[].webhookPath` when set
285
+ * (`${VAR}`-resolved), else the derived `${basePath}/<accountId>` so two
286
+ * workspaces can't collide on one route.
287
+ *
288
+ * The base path is read from `slackEventsConfig`, so a custom
289
+ * `channels.slack.events.path` propagates to every derived per-account path.
290
+ */
291
+ export function resolveSlackEventsPath(cfg, accountId, env = process.env) {
292
+ const id = accountId?.trim() || DEFAULT_ACCOUNT_ID;
293
+ const basePath = normalizeEventsPath(slackEventsConfig(cfg).path);
294
+ if (id === DEFAULT_ACCOUNT_ID)
295
+ return basePath;
296
+ const entry = findAccountEntry(cfg, id);
297
+ const explicit = resolveTokenRef(entry?.webhookPath, env);
298
+ if (explicit)
299
+ return normalizeEventsPath(explicit);
300
+ // Derive a collision-free path from the account id (path-segment-safe slug).
301
+ const slug = id.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || id;
302
+ return `${basePath}/${slug}`;
303
+ }
304
+ /**
305
+ * True when live reply-streaming is enabled (`channels.slack.liveStream`).
306
+ * Default OFF — the adapter delivers one final chunked message.
307
+ */
308
+ export function slackLiveStreamEnabled(cfg) {
309
+ return slackChannelConfig(cfg)?.liveStream === true;
310
+ }
311
+ /**
312
+ * Resolve the streaming edit throttle in ms. Reads
313
+ * `channels.slack.streamThrottleMs`; falls back to 1000ms (floored at 250ms by
314
+ * the draft-stream).
315
+ */
316
+ export function slackStreamThrottleMs(cfg) {
317
+ const raw = slackChannelConfig(cfg)?.streamThrottleMs;
318
+ return typeof raw === "number" && raw > 0 ? raw : 1000;
319
+ }
320
+ /**
321
+ * True when reasoning surfacing is enabled (`channels.slack.surfaceReasoning`).
322
+ * Default OFF — `<think>` reasoning is stripped from channel replies as today.
323
+ */
324
+ export function slackSurfaceReasoning(cfg) {
325
+ return slackChannelConfig(cfg)?.surfaceReasoning === true;
326
+ }
327
+ /**
328
+ * Resolve the idle-thread-session TTL in ms, or `null` when unset / disabled.
329
+ * Accepts a number (ms) or a duration string (`"6h"`, `"30m"`, …). The cron
330
+ * session-reaper uses this to age out idle Slack thread sessions.
331
+ */
332
+ export function slackThreadIdleTtlMs(cfg) {
333
+ const raw = slackChannelConfig(cfg)?.threadIdleTtlMs;
334
+ if (typeof raw === "number")
335
+ return raw > 0 ? raw : null;
336
+ if (typeof raw !== "string")
337
+ return null;
338
+ const trimmed = raw.trim();
339
+ if (!trimmed)
340
+ return null;
341
+ const m = /^(\d+)\s*(s|m|h|d|w)?$/i.exec(trimmed);
342
+ if (!m)
343
+ return null;
344
+ const n = Number(m[1]);
345
+ if (!Number.isFinite(n) || n <= 0)
346
+ return null;
347
+ const unit = (m[2] ?? "ms").toLowerCase();
348
+ const mult = { s: 1_000, m: 60_000, h: 3_600_000, d: 86_400_000, w: 604_800_000, ms: 1 };
349
+ const factor = mult[unit] ?? 1;
350
+ return n * factor;
351
+ }
352
+ export { CHANNEL_ID as SLACK_CHANNEL_ID, DEFAULT_ACCOUNT_ID as SLACK_DEFAULT_ACCOUNT_ID, BOT_TOKEN_ENV_VAR as SLACK_BOT_TOKEN_ENV_VAR, APP_TOKEN_ENV_VAR as SLACK_APP_TOKEN_ENV_VAR, SIGNING_SECRET_ENV_VAR as SLACK_SIGNING_SECRET_ENV_VAR, USER_TOKEN_ENV_VAR as SLACK_USER_TOKEN_ENV_VAR, };
353
+ //# sourceMappingURL=account-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-config.js","sourceRoot":"","sources":["../../../../src/agents/channels/slack/account-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Per-account Slack adapter registry — the cross-module bridge that lets the
3
+ * Events-API webhook routes (registered at module `register()` time in
4
+ * `module.ts`) find the per-account adapters that are STARTED later by
5
+ * `createSlackPlugin` (`plugin.ts`).
6
+ *
7
+ * Why this exists. In multi-workspace events mode each account has its OWN
8
+ * inbound webhook path (`/slack/events/<accountId>`). The gateway only accepts
9
+ * `b.httpRoute(...)` registrations during a module's `register()`, but the
10
+ * per-account adapters that those routes must feed are owned by the plugin's
11
+ * `startAccount` lifecycle, which runs AFTER `register()`. So the module
12
+ * registers one route per configured account up front, each route resolving its
13
+ * account's started adapter through THIS registry at request time (a thunk),
14
+ * and the plugin populates the registry on `startAccount` / clears it on
15
+ * `stopAccount`. Same shape + rationale as the channel approval-dispatcher
16
+ * registry (`approval-router.ts`): a process-wide singleton avoids threading the
17
+ * map through the gateway boot, and a single Slack workspace path is unaffected
18
+ * (the legacy single-adapter module owns its own route + adapter directly).
19
+ *
20
+ * Pinned via `resolveGlobalSingleton` so a hot reload / dual-build run shares
21
+ * one map (identical to the approval router).
22
+ */
23
+ /** The minimal adapter surface a webhook route needs to feed inbound events. */
24
+ export interface SlackAccountSink {
25
+ /** Feed a parsed Slack payload into the started adapter's inbound path. */
26
+ feedWebhookEvent(kind: "event" | "interactive" | "slash", payload: unknown): void;
27
+ }
28
+ /**
29
+ * Register a started per-account adapter so its events-mode webhook route can
30
+ * feed inbound into it. The plugin calls this on `startAccount`. Idempotent —
31
+ * re-registering replaces the previous entry (restart-friendly).
32
+ */
33
+ export declare function registerSlackAccountSink(accountId: string, sink: SlackAccountSink): void;
34
+ /**
35
+ * Drop a per-account adapter (the plugin calls this on `stopAccount`) so a
36
+ * torn-down workspace's route can't feed a dead adapter.
37
+ */
38
+ export declare function removeSlackAccountSink(accountId: string): void;
39
+ /** Look up a started per-account adapter (or undefined when not started). */
40
+ export declare function getSlackAccountSink(accountId: string): SlackAccountSink | undefined;
41
+ /** Diagnostic — the account ids with a live sink. */
42
+ export declare function listSlackAccountSinks(): string[];
43
+ /** Test-only — clear every registered sink. */
44
+ export declare function resetSlackAccountSinksForTests(): void;
45
+ //# sourceMappingURL=account-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-registry.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/slack/account-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAKH,gFAAgF;AAChF,MAAM,WAAW,gBAAgB;IAChC,2EAA2E;IAC3E,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,aAAa,GAAG,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CAClF;AAcD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAExF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE9D;AAED,6EAA6E;AAC7E,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAEnF;AAED,qDAAqD;AACrD,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD;AAED,+CAA+C;AAC/C,wBAAgB,8BAA8B,IAAI,IAAI,CAErD"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Per-account Slack adapter registry — the cross-module bridge that lets the
3
+ * Events-API webhook routes (registered at module `register()` time in
4
+ * `module.ts`) find the per-account adapters that are STARTED later by
5
+ * `createSlackPlugin` (`plugin.ts`).
6
+ *
7
+ * Why this exists. In multi-workspace events mode each account has its OWN
8
+ * inbound webhook path (`/slack/events/<accountId>`). The gateway only accepts
9
+ * `b.httpRoute(...)` registrations during a module's `register()`, but the
10
+ * per-account adapters that those routes must feed are owned by the plugin's
11
+ * `startAccount` lifecycle, which runs AFTER `register()`. So the module
12
+ * registers one route per configured account up front, each route resolving its
13
+ * account's started adapter through THIS registry at request time (a thunk),
14
+ * and the plugin populates the registry on `startAccount` / clears it on
15
+ * `stopAccount`. Same shape + rationale as the channel approval-dispatcher
16
+ * registry (`approval-router.ts`): a process-wide singleton avoids threading the
17
+ * map through the gateway boot, and a single Slack workspace path is unaffected
18
+ * (the legacy single-adapter module owns its own route + adapter directly).
19
+ *
20
+ * Pinned via `resolveGlobalSingleton` so a hot reload / dual-build run shares
21
+ * one map (identical to the approval router).
22
+ */
23
+ import { resolveGlobalSingleton } from "../../../shared/global-singleton.js";
24
+ import { SLACK_DEFAULT_ACCOUNT_ID } from "./account-config.js";
25
+ const SLACK_ACCOUNT_SINKS_KEY = Symbol.for("brigade.slack.accountSinks");
26
+ /** Keyed by accountId — one started adapter per workspace. */
27
+ const sinks = resolveGlobalSingleton(SLACK_ACCOUNT_SINKS_KEY, () => new Map());
28
+ function normalizeAccountId(accountId) {
29
+ return accountId && accountId.trim() ? accountId.trim() : SLACK_DEFAULT_ACCOUNT_ID;
30
+ }
31
+ /**
32
+ * Register a started per-account adapter so its events-mode webhook route can
33
+ * feed inbound into it. The plugin calls this on `startAccount`. Idempotent —
34
+ * re-registering replaces the previous entry (restart-friendly).
35
+ */
36
+ export function registerSlackAccountSink(accountId, sink) {
37
+ sinks.set(normalizeAccountId(accountId), sink);
38
+ }
39
+ /**
40
+ * Drop a per-account adapter (the plugin calls this on `stopAccount`) so a
41
+ * torn-down workspace's route can't feed a dead adapter.
42
+ */
43
+ export function removeSlackAccountSink(accountId) {
44
+ sinks.delete(normalizeAccountId(accountId));
45
+ }
46
+ /** Look up a started per-account adapter (or undefined when not started). */
47
+ export function getSlackAccountSink(accountId) {
48
+ return sinks.get(normalizeAccountId(accountId));
49
+ }
50
+ /** Diagnostic — the account ids with a live sink. */
51
+ export function listSlackAccountSinks() {
52
+ return [...sinks.keys()];
53
+ }
54
+ /** Test-only — clear every registered sink. */
55
+ export function resetSlackAccountSinksForTests() {
56
+ sinks.clear();
57
+ }
58
+ //# sourceMappingURL=account-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-registry.js","sourceRoot":"","sources":["../../../../src/agents/channels/slack/account-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAQ/D,MAAM,uBAAuB,GAAG,MAAM,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;AAEzE,8DAA8D;AAC9D,MAAM,KAAK,GAAG,sBAAsB,CACnC,uBAAuB,EACvB,GAAG,EAAE,CAAC,IAAI,GAAG,EAA4B,CACzC,CAAC;AAEF,SAAS,kBAAkB,CAAC,SAAoC;IAC/D,OAAO,SAAS,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,wBAAwB,CAAC;AACpF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,SAAiB,EAAE,IAAsB;IACjF,KAAK,CAAC,GAAG,CAAC,kBAAkB,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC;AAChD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,SAAiB;IACvD,KAAK,CAAC,MAAM,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,mBAAmB,CAAC,SAAiB;IACpD,OAAO,KAAK,CAAC,GAAG,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,qBAAqB;IACpC,OAAO,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AAC1B,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,8BAA8B;IAC7C,KAAK,CAAC,KAAK,EAAE,CAAC;AACf,CAAC"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Slack channel adapter.
3
+ *
4
+ * Implements the Brigade `ChannelAdapter` contract on top of the Socket Mode +
5
+ * Web API connection. Like Telegram, Slack is TOKEN-based: the operator pastes a
6
+ * bot token (`xoxb-…`) + an app-level token (`xapp-…`, for Socket Mode) from the
7
+ * Slack app config, so this adapter declares a `setup` wizard (two credentials)
8
+ * and has NO QR/link flow. Enablement is explicit — `channels.slack.enabled:
9
+ * true` plus a resolvable bot token.
10
+ *
11
+ * Modeled directly on `telegram/adapter.ts`: same health-flag mirroring, same
12
+ * deferred-media passthrough on inbound, same chunk-then-send outbound shape
13
+ * (chunk markdown ≤8000, convert each chunk to Slack mrkdwn, send with
14
+ * `mrkdwn: true`). Slack mrkdwn never "fails to parse" the way Telegram HTML can,
15
+ * so the outbound path is simpler — an empty rendered chunk falls back to the
16
+ * raw chunk, but there's no parse-error retry.
17
+ *
18
+ * Capabilities: edit (chat.update), unsend (chat.delete), reactions
19
+ * (reactions.add/remove), reply (thread_ts), threads, media (files.uploadV2),
20
+ * and Block Kit buttons. NO polls / forum-topic-create / programmatic command
21
+ * menu (Slack slash commands are registered in the app config UI).
22
+ */
23
+ import { type ChannelAdapter, type ChannelCapabilities } from "../sdk.js";
24
+ import { type ConnectSlackArgs, type SlackConnection } from "./connection.js";
25
+ /** Adapter construction options — all optional for back-compat. */
26
+ export interface CreateSlackAdapterOptions {
27
+ /** Per-account (workspace) scope. Defaults to `"default"` (single-account). */
28
+ accountId?: string;
29
+ /**
30
+ * TEST SEAM: override how the connection is built. Production leaves this
31
+ * undefined and `connectSlack` lazy-loads the Slack SDKs. Tests inject a fake.
32
+ */
33
+ connectImpl?: (args: ConnectSlackArgs) => Promise<SlackConnection>;
34
+ }
35
+ export declare function createSlackAdapter(opts?: CreateSlackAdapterOptions): ChannelAdapter;
36
+ /**
37
+ * Synthesise the agent-facing note for an inbound reaction. The reaction itself
38
+ * carries no text, so the note ("<who> reacted :emoji: to message <id>") is what
39
+ * the central pipeline routes through dispatchTurn so the agent has context.
40
+ */
41
+ export declare function buildReactionNote(emojis: string[], targetMessageId: string, fromName?: string): string;
42
+ /** Static Slack capability flags (shared by the legacy adapter + plugin meta). */
43
+ export declare const SLACK_CAPABILITIES: ChannelCapabilities;
44
+ /**
45
+ * The Slack adapter shape with its webhook + transport extensions. `createSlack
46
+ * Adapter` returns a `ChannelAdapter`, but the concrete object ALSO carries
47
+ * `feedWebhookEvent` + `transportMode` (not in the base contract). Callers that
48
+ * need them cast through this type.
49
+ */
50
+ export interface SlackAdapter extends ChannelAdapter {
51
+ /**
52
+ * Feed a raw Slack payload (events-API mode). The gateway HTTP route calls
53
+ * this after verifying the signing-secret signature. No-op when not started or
54
+ * in socket mode. `kind` selects the event family.
55
+ */
56
+ feedWebhookEvent(kind: "event" | "interactive" | "slash", payload: unknown): void;
57
+ /** The transport mode this adapter's connection runs (`"socket"` | `"events"`). */
58
+ transportMode(): "socket" | "events" | "unstarted";
59
+ /**
60
+ * Epoch ms of the most recent inbound event (liveness diagnostic), or null
61
+ * before the first event / when not started. Observability only — never flips
62
+ * health to "down" (a quiet channel is legitimately idle).
63
+ */
64
+ lastEventAt(): number | null;
65
+ }
66
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/slack/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAQH,OAAO,EACN,KAAK,cAAc,EAEnB,KAAK,mBAAmB,EASxB,MAAM,WAAW,CAAC;AAiBnB,OAAO,EAAgB,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAQ5F,mEAAmE;AACnE,MAAM,WAAW,yBAAyB;IACzC,+EAA+E;IAC/E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;CACnE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,GAAE,yBAA8B,GAAG,cAAc,CAoevF;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAItG;AAED,kFAAkF;AAClF,eAAO,MAAM,kBAAkB,EAAE,mBAQhC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,YAAa,SAAQ,cAAc;IACnD;;;;OAIG;IACH,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,aAAa,GAAG,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAClF,mFAAmF;IACnF,aAAa,IAAI,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;IACnD;;;;OAIG;IACH,WAAW,IAAI,MAAM,GAAG,IAAI,CAAC;CAC7B"}