@spinabot/brigade 1.4.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 (136) hide show
  1. package/README.md +20 -1
  2. package/dist/agents/channels/bundled-channel-metas.d.ts +2 -0
  3. package/dist/agents/channels/bundled-channel-metas.d.ts.map +1 -1
  4. package/dist/agents/channels/bundled-channel-metas.js +11 -0
  5. package/dist/agents/channels/bundled-channel-metas.js.map +1 -1
  6. package/dist/agents/channels/manager.d.ts.map +1 -1
  7. package/dist/agents/channels/manager.js +18 -0
  8. package/dist/agents/channels/manager.js.map +1 -1
  9. package/dist/agents/channels/sdk.d.ts +2 -0
  10. package/dist/agents/channels/sdk.d.ts.map +1 -1
  11. package/dist/agents/channels/sdk.js +2 -0
  12. package/dist/agents/channels/sdk.js.map +1 -1
  13. package/dist/agents/channels/slack/account-config.d.ts +172 -0
  14. package/dist/agents/channels/slack/account-config.d.ts.map +1 -0
  15. package/dist/agents/channels/slack/account-config.js +353 -0
  16. package/dist/agents/channels/slack/account-config.js.map +1 -0
  17. package/dist/agents/channels/slack/account-registry.d.ts +45 -0
  18. package/dist/agents/channels/slack/account-registry.d.ts.map +1 -0
  19. package/dist/agents/channels/slack/account-registry.js +58 -0
  20. package/dist/agents/channels/slack/account-registry.js.map +1 -0
  21. package/dist/agents/channels/slack/adapter.d.ts +66 -0
  22. package/dist/agents/channels/slack/adapter.d.ts.map +1 -0
  23. package/dist/agents/channels/slack/adapter.js +547 -0
  24. package/dist/agents/channels/slack/adapter.js.map +1 -0
  25. package/dist/agents/channels/slack/approval-authorize.d.ts +43 -0
  26. package/dist/agents/channels/slack/approval-authorize.d.ts.map +1 -0
  27. package/dist/agents/channels/slack/approval-authorize.js +71 -0
  28. package/dist/agents/channels/slack/approval-authorize.js.map +1 -0
  29. package/dist/agents/channels/slack/approval-native.d.ts +70 -0
  30. package/dist/agents/channels/slack/approval-native.d.ts.map +1 -0
  31. package/dist/agents/channels/slack/approval-native.js +85 -0
  32. package/dist/agents/channels/slack/approval-native.js.map +1 -0
  33. package/dist/agents/channels/slack/blocks.d.ts +125 -0
  34. package/dist/agents/channels/slack/blocks.d.ts.map +1 -0
  35. package/dist/agents/channels/slack/blocks.js +145 -0
  36. package/dist/agents/channels/slack/blocks.js.map +1 -0
  37. package/dist/agents/channels/slack/command-menu.d.ts +44 -0
  38. package/dist/agents/channels/slack/command-menu.d.ts.map +1 -0
  39. package/dist/agents/channels/slack/command-menu.js +66 -0
  40. package/dist/agents/channels/slack/command-menu.js.map +1 -0
  41. package/dist/agents/channels/slack/connection.d.ts +422 -0
  42. package/dist/agents/channels/slack/connection.d.ts.map +1 -0
  43. package/dist/agents/channels/slack/connection.js +1042 -0
  44. package/dist/agents/channels/slack/connection.js.map +1 -0
  45. package/dist/agents/channels/slack/directory-live.d.ts +129 -0
  46. package/dist/agents/channels/slack/directory-live.d.ts.map +1 -0
  47. package/dist/agents/channels/slack/directory-live.js +148 -0
  48. package/dist/agents/channels/slack/directory-live.js.map +1 -0
  49. package/dist/agents/channels/slack/draft-stream.d.ts +93 -0
  50. package/dist/agents/channels/slack/draft-stream.d.ts.map +1 -0
  51. package/dist/agents/channels/slack/draft-stream.js +218 -0
  52. package/dist/agents/channels/slack/draft-stream.js.map +1 -0
  53. package/dist/agents/channels/slack/format.d.ts +41 -0
  54. package/dist/agents/channels/slack/format.d.ts.map +1 -0
  55. package/dist/agents/channels/slack/format.js +271 -0
  56. package/dist/agents/channels/slack/format.js.map +1 -0
  57. package/dist/agents/channels/slack/inbound-extras.d.ts +179 -0
  58. package/dist/agents/channels/slack/inbound-extras.d.ts.map +1 -0
  59. package/dist/agents/channels/slack/inbound-extras.js +257 -0
  60. package/dist/agents/channels/slack/inbound-extras.js.map +1 -0
  61. package/dist/agents/channels/slack/index.d.ts +15 -0
  62. package/dist/agents/channels/slack/index.d.ts.map +1 -0
  63. package/dist/agents/channels/slack/index.js +15 -0
  64. package/dist/agents/channels/slack/index.js.map +1 -0
  65. package/dist/agents/channels/slack/media.d.ts +90 -0
  66. package/dist/agents/channels/slack/media.d.ts.map +1 -0
  67. package/dist/agents/channels/slack/media.js +215 -0
  68. package/dist/agents/channels/slack/media.js.map +1 -0
  69. package/dist/agents/channels/slack/module.d.ts +26 -0
  70. package/dist/agents/channels/slack/module.d.ts.map +1 -0
  71. package/dist/agents/channels/slack/module.js +67 -0
  72. package/dist/agents/channels/slack/module.js.map +1 -0
  73. package/dist/agents/channels/slack/plugin.d.ts +69 -0
  74. package/dist/agents/channels/slack/plugin.d.ts.map +1 -0
  75. package/dist/agents/channels/slack/plugin.js +318 -0
  76. package/dist/agents/channels/slack/plugin.js.map +1 -0
  77. package/dist/agents/channels/slack/probe.d.ts +72 -0
  78. package/dist/agents/channels/slack/probe.d.ts.map +1 -0
  79. package/dist/agents/channels/slack/probe.js +103 -0
  80. package/dist/agents/channels/slack/probe.js.map +1 -0
  81. package/dist/agents/channels/slack/proxy-agent.d.ts +30 -0
  82. package/dist/agents/channels/slack/proxy-agent.d.ts.map +1 -0
  83. package/dist/agents/channels/slack/proxy-agent.js +44 -0
  84. package/dist/agents/channels/slack/proxy-agent.js.map +1 -0
  85. package/dist/agents/channels/slack/reasoning-lane.d.ts +42 -0
  86. package/dist/agents/channels/slack/reasoning-lane.d.ts.map +1 -0
  87. package/dist/agents/channels/slack/reasoning-lane.js +68 -0
  88. package/dist/agents/channels/slack/reasoning-lane.js.map +1 -0
  89. package/dist/agents/channels/slack/user-directory.d.ts +69 -0
  90. package/dist/agents/channels/slack/user-directory.d.ts.map +1 -0
  91. package/dist/agents/channels/slack/user-directory.js +94 -0
  92. package/dist/agents/channels/slack/user-directory.js.map +1 -0
  93. package/dist/agents/channels/slack/webhook.d.ts +89 -0
  94. package/dist/agents/channels/slack/webhook.d.ts.map +1 -0
  95. package/dist/agents/channels/slack/webhook.js +228 -0
  96. package/dist/agents/channels/slack/webhook.js.map +1 -0
  97. package/dist/agents/channels/telegram/adapter.d.ts.map +1 -1
  98. package/dist/agents/channels/telegram/adapter.js +10 -3
  99. package/dist/agents/channels/telegram/adapter.js.map +1 -1
  100. package/dist/agents/channels/telegram/connection.d.ts +10 -0
  101. package/dist/agents/channels/telegram/connection.d.ts.map +1 -1
  102. package/dist/agents/channels/telegram/connection.js +161 -5
  103. package/dist/agents/channels/telegram/connection.js.map +1 -1
  104. package/dist/agents/channels/telegram/format.d.ts +17 -0
  105. package/dist/agents/channels/telegram/format.d.ts.map +1 -1
  106. package/dist/agents/channels/telegram/format.js +53 -1
  107. package/dist/agents/channels/telegram/format.js.map +1 -1
  108. package/dist/agents/channels/telegram/inbound-extras.d.ts +17 -1
  109. package/dist/agents/channels/telegram/inbound-extras.d.ts.map +1 -1
  110. package/dist/agents/channels/telegram/inbound-extras.js +68 -7
  111. package/dist/agents/channels/telegram/inbound-extras.js.map +1 -1
  112. package/dist/agents/channels/telegram/media.d.ts +8 -0
  113. package/dist/agents/channels/telegram/media.d.ts.map +1 -1
  114. package/dist/agents/channels/telegram/media.js +30 -2
  115. package/dist/agents/channels/telegram/media.js.map +1 -1
  116. package/dist/agents/channels/telegram/webhook.d.ts.map +1 -1
  117. package/dist/agents/channels/telegram/webhook.js +7 -1
  118. package/dist/agents/channels/telegram/webhook.js.map +1 -1
  119. package/dist/agents/extensions/modules/index.d.ts.map +1 -1
  120. package/dist/agents/extensions/modules/index.js +5 -0
  121. package/dist/agents/extensions/modules/index.js.map +1 -1
  122. package/dist/agents/extensions/types.d.ts +11 -0
  123. package/dist/agents/extensions/types.d.ts.map +1 -1
  124. package/dist/agents/extensions/types.js.map +1 -1
  125. package/dist/buildstamp.json +1 -1
  126. package/dist/cli/commands/convex-cmd.d.ts +2 -1
  127. package/dist/cli/commands/convex-cmd.d.ts.map +1 -1
  128. package/dist/cli/commands/convex-cmd.js +79 -6
  129. package/dist/cli/commands/convex-cmd.js.map +1 -1
  130. package/dist/cli/program/build-program.js +1 -1
  131. package/dist/cli/program/build-program.js.map +1 -1
  132. package/dist/core/server.d.ts.map +1 -1
  133. package/dist/core/server.js +24 -5
  134. package/dist/core/server.js.map +1 -1
  135. package/package.json +4 -1
  136. package/scripts/convex-dev.mjs +28 -2
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Slack media helpers — inbound download + outbound upload construction.
3
+ *
4
+ * INBOUND: Slack doesn't push file bytes; a message event carries file objects
5
+ * with an authenticated `url_private`. To get the bytes we GET that URL with an
6
+ * `Authorization: Bearer <botToken>` header (a plain fetch returns the login
7
+ * HTML otherwise). Bytes are saved under
8
+ * `~/.brigade/channels/slack/media/<YYYY-MM-DD>/<fileId>.<ext>` so the agent can
9
+ * `read` the attachment by path. In convex mode the cache relocates to the OS
10
+ * cache dir (never under ~/.brigade, to respect the strict-zero guard).
11
+ *
12
+ * OUTBOUND: `uploadSlackFile` posts a local path's bytes via the Web API's
13
+ * `files.uploadV2`, after running the path through Brigade's outbound media-path
14
+ * guard so a prompt-injected "send ~/.ssh/id_rsa" can't exfiltrate a secret. The
15
+ * `@slack/web-api` `WebClient` is injected (not imported here) so this module
16
+ * stays dependency-light + unit-testable.
17
+ */
18
+ import { createReadStream, mkdirSync, writeFileSync } from "node:fs";
19
+ import path from "node:path";
20
+ import { resolveChannelStateDir, resolveOsCacheDir } from "../../../config/paths.js";
21
+ import { tryGetRuntimeContext } from "../../../storage/runtime-context.js";
22
+ // Channel SDK barrel — the outbound-media exfil guard + the contract types.
23
+ // All contract types come from the channel SDK barrel so the channel is built
24
+ // entirely on `../sdk.js`.
25
+ import { validateOutboundMediaPath, } from "../sdk.js";
26
+ import { resolveSlackFileKind } from "./inbound-extras.js";
27
+ const CHANNEL_ID = "slack";
28
+ /**
29
+ * Defensive ceiling on an inbound file download. Slack's own per-file limit is
30
+ * generous; we cap at 50 MB so a huge upload can't blow out memory. Anything
31
+ * larger is skipped (the message still reaches the agent without the
32
+ * attachment).
33
+ */
34
+ const MAX_BYTES = 50 * 1024 * 1024;
35
+ /**
36
+ * Slack's file-CDN hosts. An inbound `url_private` only ever points at one of
37
+ * these — we attach the bot token as `Authorization: Bearer …`, so before
38
+ * fetching we REQUIRE https + a Slack host. Without this guard a
39
+ * prompt-injected / spoofed event could carry `http://169.254.169.254/…` (cloud
40
+ * metadata) or any attacker host and Brigade would happily send the bot token to
41
+ * it (SSRF + token exfiltration). Subdomains of these hosts are allowed.
42
+ */
43
+ const SLACK_FILE_HOSTS = ["slack.com", "slack-edge.com", "slack-files.com"];
44
+ /**
45
+ * True when `rawUrl` is an https URL whose host is a Slack file-CDN host (or a
46
+ * subdomain of one). Anything else (non-https, a non-Slack host, or an
47
+ * unparseable URL) returns false so the caller refuses to fetch with the token.
48
+ */
49
+ export function isAllowedSlackFileUrl(rawUrl) {
50
+ let parsed;
51
+ try {
52
+ parsed = new URL(rawUrl);
53
+ }
54
+ catch {
55
+ return false;
56
+ }
57
+ if (parsed.protocol !== "https:")
58
+ return false;
59
+ const host = parsed.hostname.toLowerCase();
60
+ return SLACK_FILE_HOSTS.some((h) => host === h || host.endsWith(`.${h}`));
61
+ }
62
+ /** YYYY-MM-DD (UTC) bucket — stable filename grouping for grep / review. */
63
+ function dayBucket() {
64
+ const d = new Date();
65
+ const pad = (x) => String(x).padStart(2, "0");
66
+ return `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())}`;
67
+ }
68
+ /** Derive a file extension from a Slack file object (filetype / name / kind). */
69
+ function extFromFile(file, kind) {
70
+ const type = (file.filetype ?? "").toLowerCase();
71
+ if (type && /^[a-z0-9]+$/.test(type))
72
+ return type;
73
+ const fromName = path.extname(file.name ?? "").replace(/^\./, "").toLowerCase();
74
+ if (fromName && /^[a-z0-9]+$/.test(fromName))
75
+ return fromName;
76
+ // Sensible default by kind when nothing carried an extension.
77
+ switch (kind) {
78
+ case "image":
79
+ return "png";
80
+ case "video":
81
+ return "mp4";
82
+ case "voice":
83
+ return "m4a";
84
+ case "audio":
85
+ return "mp3";
86
+ default:
87
+ return "bin";
88
+ }
89
+ }
90
+ /** Where downloaded media lands — OS cache in convex mode, channel-state dir otherwise. */
91
+ function mediaBaseDir() {
92
+ return tryGetRuntimeContext()?.mode === "convex"
93
+ ? path.join(resolveOsCacheDir(), "channels", CHANNEL_ID)
94
+ : resolveChannelStateDir(CHANNEL_ID);
95
+ }
96
+ /**
97
+ * Bounded retry for the transient file fetch. Slack's file CDN occasionally
98
+ * blips on a 5xx or a network reset; one or two quick retries turn a dropped
99
+ * attachment into a delivered one. The caller still wraps the whole thing in a
100
+ * try/catch that degrades to `null`, so an exhausted retry never breaks message
101
+ * delivery. Mirrors Telegram's `withMediaRetry`.
102
+ */
103
+ export async function withSlackRetry(fn, attempts = 3) {
104
+ let lastErr;
105
+ for (let i = 0; i < attempts; i++) {
106
+ try {
107
+ return await fn();
108
+ }
109
+ catch (err) {
110
+ lastErr = err;
111
+ if (i < attempts - 1)
112
+ await new Promise((r) => setTimeout(r, 200 * 2 ** i));
113
+ }
114
+ }
115
+ throw lastErr;
116
+ }
117
+ /**
118
+ * Download one inbound Slack file to disk and return its normalized descriptor,
119
+ * or `null` when the file couldn't be fetched (no url / too big / network error
120
+ * / tombstoned). Never throws — a download glitch must not break message
121
+ * delivery. The `Authorization: Bearer` header is REQUIRED; a plain GET of
122
+ * `url_private` returns Slack's HTML login page, not the bytes.
123
+ */
124
+ export async function downloadSlackFile(args) {
125
+ const { file, token, log } = args;
126
+ const doFetch = args.fetchImpl ?? fetch;
127
+ const url = file.url_private_download || file.url_private;
128
+ if (!url) {
129
+ log?.("slack file skipped — no private url", { fileId: file.id });
130
+ return null;
131
+ }
132
+ // SSRF / token-exfil guard: the bot token is attached below, so REFUSE any
133
+ // url that isn't https on a Slack file-CDN host. A spoofed event pointing at
134
+ // `http://169.254.169.254/…` (or any attacker host) must never receive the
135
+ // token. Checked BEFORE the fetch so the token never leaves the process.
136
+ if (!isAllowedSlackFileUrl(url)) {
137
+ log?.("slack file skipped — url is not an allowed Slack host (SSRF guard)", { fileId: file.id });
138
+ return null;
139
+ }
140
+ if (typeof file.size === "number" && file.size > MAX_BYTES) {
141
+ log?.("slack file skipped — exceeds size cap", { fileId: file.id, bytes: file.size, cap: MAX_BYTES });
142
+ return null;
143
+ }
144
+ const kind = resolveSlackFileKind(file);
145
+ try {
146
+ const res = await withSlackRetry(async () => {
147
+ // `redirect: "manual"` so a cross-origin 30x can't carry the
148
+ // Authorization header off to a non-Slack host (Slack file urls don't
149
+ // legitimately redirect cross-origin). A redirect surfaces as an opaque
150
+ // / non-ok response and falls through to the `!r.ok` handler below.
151
+ const r = await doFetch(url, { headers: { Authorization: `Bearer ${token}` }, redirect: "manual" });
152
+ // Retry 5xx (transient server/CDN blip); a 4xx falls through to the !ok
153
+ // handler below (no point retrying a permanent client error).
154
+ if (!r.ok && r.status >= 500)
155
+ throw new Error(`slack file fetch failed (${r.status})`);
156
+ return r;
157
+ });
158
+ if (!res.ok) {
159
+ log?.("slack file download failed", { fileId: file.id, status: res.status });
160
+ return null;
161
+ }
162
+ const buf = Buffer.from(await res.arrayBuffer());
163
+ if (buf.length === 0)
164
+ return null;
165
+ if (buf.length > MAX_BYTES) {
166
+ log?.("slack file skipped — exceeds size cap", { fileId: file.id, bytes: buf.length, cap: MAX_BYTES });
167
+ return null;
168
+ }
169
+ const dir = path.join(mediaBaseDir(), "media", dayBucket());
170
+ mkdirSync(dir, { recursive: true });
171
+ // file.id is stable across re-deliveries; use it as the filename so the same
172
+ // media resolves idempotently. Fall back to a timestamp.
173
+ const baseName = (file.id || `slack_${Date.now()}`).replace(/[^A-Za-z0-9_-]/g, "_");
174
+ const dest = path.join(dir, `${baseName}.${extFromFile(file, kind)}`);
175
+ writeFileSync(dest, buf, { mode: 0o600 });
176
+ return {
177
+ kind,
178
+ path: dest,
179
+ ...(file.mimetype ? { mimeType: file.mimetype } : {}),
180
+ ...(file.name ? { fileName: file.name } : {}),
181
+ ...(file.title ? { caption: file.title } : {}),
182
+ };
183
+ }
184
+ catch (err) {
185
+ log?.("slack file download failed", {
186
+ fileId: file.id,
187
+ error: err instanceof Error ? err.message : String(err),
188
+ });
189
+ return null;
190
+ }
191
+ }
192
+ /**
193
+ * Upload a local file (image / video / audio / doc) to a Slack channel via
194
+ * `files.uploadV2`, after running the path through Brigade's outbound
195
+ * media-path guard. Throws a clear operator-facing error when the guard refuses
196
+ * the path (the `send_media` tool surfaces it). The file is streamed from disk;
197
+ * the caption rides as `initial_comment`.
198
+ */
199
+ export async function uploadSlackFile(args) {
200
+ const { media } = args;
201
+ const verdict = validateOutboundMediaPath(media.path);
202
+ if (!verdict.ok) {
203
+ throw new Error(`Slack: ${verdict.reason ?? "refusing to attach this file"}`);
204
+ }
205
+ const filename = media.fileName || path.basename(media.path) || "file";
206
+ await args.client.files.uploadV2({
207
+ channel_id: args.channelId,
208
+ file: createReadStream(media.path),
209
+ filename,
210
+ ...(media.caption ? { initial_comment: media.caption } : {}),
211
+ ...(args.threadId ? { thread_ts: args.threadId } : {}),
212
+ });
213
+ }
214
+ export { MAX_BYTES as SLACK_MEDIA_MAX_BYTES };
215
+ //# sourceMappingURL=media.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media.js","sourceRoot":"","sources":["../../../../src/agents/channels/slack/media.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Slack extension module.
3
+ *
4
+ * Registers the Slack channel adapter through the seam. The loader gates it by
5
+ * the usual extension config (`extensions.disabled` / `entries`), and the
6
+ * adapter itself only starts when `channels.slack.enabled` is true AND a bot
7
+ * token resolves — so bundling this module is inert until the operator opts in.
8
+ *
9
+ * In EVENTS transport mode (`channels.slack.mode: "events"`) the module ALSO
10
+ * registers a gateway HTTP route PER configured workspace that receives Slack's
11
+ * event POSTs and feeds them into the started adapter for THAT workspace (after
12
+ * verifying the request signature with that workspace's signing secret). Socket
13
+ * mode (the default) registers no HTTP surface. Slack mirror of
14
+ * `telegram/module.ts`, extended for multi-workspace inbound:
15
+ *
16
+ * - The default account keeps the SAME inline adapter + base path
17
+ * (`/slack/events`) as the single-workspace path — byte-identical.
18
+ * - Each NAMED account (only present when >1 account is configured) gets its
19
+ * own route on a distinct path (`resolveSlackEventsPath`), whose `resolveSink`
20
+ * looks up THAT account's STARTED adapter at request time via the per-account
21
+ * adapter registry (`account-registry.ts`) the plugin populates on
22
+ * `startAccount`. `b.httpRoute(...)` is only available at `register()` time
23
+ * (before the plugin starts accounts), so the late binding is essential.
24
+ */
25
+ export declare const slackModule: import("../sdk.js").BrigadeModule;
26
+ //# sourceMappingURL=module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/slack/module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAcH,eAAO,MAAM,WAAW,mCAuCtB,CAAC"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Slack extension module.
3
+ *
4
+ * Registers the Slack channel adapter through the seam. The loader gates it by
5
+ * the usual extension config (`extensions.disabled` / `entries`), and the
6
+ * adapter itself only starts when `channels.slack.enabled` is true AND a bot
7
+ * token resolves — so bundling this module is inert until the operator opts in.
8
+ *
9
+ * In EVENTS transport mode (`channels.slack.mode: "events"`) the module ALSO
10
+ * registers a gateway HTTP route PER configured workspace that receives Slack's
11
+ * event POSTs and feeds them into the started adapter for THAT workspace (after
12
+ * verifying the request signature with that workspace's signing secret). Socket
13
+ * mode (the default) registers no HTTP surface. Slack mirror of
14
+ * `telegram/module.ts`, extended for multi-workspace inbound:
15
+ *
16
+ * - The default account keeps the SAME inline adapter + base path
17
+ * (`/slack/events`) as the single-workspace path — byte-identical.
18
+ * - Each NAMED account (only present when >1 account is configured) gets its
19
+ * own route on a distinct path (`resolveSlackEventsPath`), whose `resolveSink`
20
+ * looks up THAT account's STARTED adapter at request time via the per-account
21
+ * adapter registry (`account-registry.ts`) the plugin populates on
22
+ * `startAccount`. `b.httpRoute(...)` is only available at `register()` time
23
+ * (before the plugin starts accounts), so the late binding is essential.
24
+ */
25
+ import { defineModule } from "../sdk.js";
26
+ import { listSlackAccountIds, resolveSlackEventsPath, resolveSlackSigningSecret, slackEventsConfig, SLACK_DEFAULT_ACCOUNT_ID, } from "./account-config.js";
27
+ import { getSlackAccountSink } from "./account-registry.js";
28
+ import { createSlackAdapter } from "./adapter.js";
29
+ import { buildSlackWebhookRoute } from "./webhook.js";
30
+ export const slackModule = defineModule({
31
+ id: "slack",
32
+ register(b) {
33
+ const adapter = createSlackAdapter();
34
+ b.channel(adapter);
35
+ // Events transport: register the inbound gateway route(s). Gated on config so
36
+ // a Socket Mode (default) install exposes no inbound HTTP surface.
37
+ const transport = slackEventsConfig(b.config);
38
+ if (transport.mode !== "events")
39
+ return;
40
+ const accountIds = listSlackAccountIds(b.config);
41
+ // `listSlackAccountIds` returns `["default"]` for a single-workspace install
42
+ // and the named ids for a multi-workspace one. Single → byte-identical to the
43
+ // legacy single-route registration: the default route resolves the inline
44
+ // adapter directly. Multi → one route per workspace, each resolving its
45
+ // account's started adapter via the registry at request time.
46
+ const isMultiWorkspace = accountIds.length > 1;
47
+ for (const accountId of accountIds) {
48
+ const isDefault = accountId === SLACK_DEFAULT_ACCOUNT_ID;
49
+ b.httpRoute(buildSlackWebhookRoute({
50
+ // Default account keeps the base path; named accounts get a distinct,
51
+ // collision-free path so two workspaces never share one route.
52
+ path: resolveSlackEventsPath(b.config, accountId),
53
+ // Each route verifies with ITS OWN account's signing secret.
54
+ signingSecret: resolveSlackSigningSecret(b.config, accountId),
55
+ // The default account in a single-workspace install feeds the inline
56
+ // adapter directly (the legacy adapter owns the default lifecycle).
57
+ // Every other case resolves the per-account started adapter at request
58
+ // time — when the plugin owns the lifecycle the inline adapter steps
59
+ // aside, so we must look up the live one rather than capture it here.
60
+ resolveSink: isDefault && !isMultiWorkspace
61
+ ? () => adapter
62
+ : () => getSlackAccountSink(accountId) ?? null,
63
+ }));
64
+ }
65
+ },
66
+ });
67
+ //# sourceMappingURL=module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.js","sourceRoot":"","sources":["../../../../src/agents/channels/slack/module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EACN,mBAAmB,EACnB,sBAAsB,EACtB,yBAAyB,EACzB,iBAAiB,EACjB,wBAAwB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAqB,MAAM,cAAc,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAEtD,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAC;IACvC,EAAE,EAAE,OAAO;IACX,QAAQ,CAAC,CAAC;QACT,MAAM,OAAO,GAAG,kBAAkB,EAAkB,CAAC;QACrD,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACnB,8EAA8E;QAC9E,mEAAmE;QACnE,MAAM,SAAS,GAAG,iBAAiB,CAAC,CAAC,CAAC,MAAe,CAAC,CAAC;QACvD,IAAI,SAAS,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO;QAExC,MAAM,UAAU,GAAG,mBAAmB,CAAC,CAAC,CAAC,MAAe,CAAC,CAAC;QAC1D,6EAA6E;QAC7E,8EAA8E;QAC9E,0EAA0E;QAC1E,wEAAwE;QACxE,8DAA8D;QAC9D,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;QAC/C,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACpC,MAAM,SAAS,GAAG,SAAS,KAAK,wBAAwB,CAAC;YACzD,CAAC,CAAC,SAAS,CACV,sBAAsB,CAAC;gBACtB,sEAAsE;gBACtE,+DAA+D;gBAC/D,IAAI,EAAE,sBAAsB,CAAC,CAAC,CAAC,MAAe,EAAE,SAAS,CAAC;gBAC1D,6DAA6D;gBAC7D,aAAa,EAAE,yBAAyB,CAAC,CAAC,CAAC,MAAe,EAAE,SAAS,CAAC;gBACtE,qEAAqE;gBACrE,oEAAoE;gBACpE,uEAAuE;gBACvE,qEAAqE;gBACrE,sEAAsE;gBACtE,WAAW,EACV,SAAS,IAAI,CAAC,gBAAgB;oBAC7B,CAAC,CAAC,GAAG,EAAE,CAAC,OAAO;oBACf,CAAC,CAAC,GAAG,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC,IAAI,IAAI;aAChD,CAAC,CACF,CAAC;QACH,CAAC;IACF,CAAC;CACD,CAAC,CAAC"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Slack `ChannelPlugin` — the multi-WORKSPACE contract surface.
3
+ *
4
+ * Mirrors `telegram/plugin.ts`: wraps `createSlackAdapter()` (the per-connection
5
+ * implementation) with the lifecycle adapters the `ChannelPluginManager`
6
+ * consumes, so an operator can run MORE THAN ONE Slack workspace at once via:
7
+ *
8
+ * channels.slack = {
9
+ * enabled: true,
10
+ * accounts: [
11
+ * { id: "acme", botToken: "xoxb-AAA", appToken: "xapp-AAA" },
12
+ * { id: "labs", botToken: "xoxb-BBB", appToken: "xapp-BBB" },
13
+ * ],
14
+ * }
15
+ *
16
+ * - `config.listAccountIds` / `resolveAccount` → multi-workspace discovery
17
+ * - `gateway.startAccount` / `stopAccount` → per-workspace app lifecycle
18
+ * - `outbound.sendText` / `sendMedia` → routes by `target.accountId`
19
+ * - per-account approval-dispatcher registration → an exec-gate prompt raised
20
+ * by a turn on (slack, labs) replies on (slack, labs), not the default
21
+ *
22
+ * Per-account state lives in a `Map<accountId, AccountRuntime>` held in this
23
+ * closure — one app connection per account, partitioned token resolution per
24
+ * `channels.slack.accounts[].botToken`. Inbound dispatch reuses the shared
25
+ * `runChannelInboundPipeline` so the multi-workspace path carries the identical
26
+ * ACL + debounce + abort + approval-reply + approval-callback surface as the
27
+ * legacy single-adapter manager.
28
+ *
29
+ * The legacy single-account `createSlackAdapter` (started by the legacy
30
+ * `startChannels` manager) STEPS ASIDE when >1 account is configured — its
31
+ * `isConfigured` returns false for the default account in that case (mirrors
32
+ * Telegram), so the two paths never double-start an app.
33
+ */
34
+ import type { BrigadeConfig } from "../../../config/types.js";
35
+ import { type ChannelAdapter, type ChannelOutboundTarget, type ChannelPlugin, type StartChannelsArgs } from "../sdk.js";
36
+ import { type ResolvedSlackAccount } from "./account-config.js";
37
+ import { type SlackProbeResult } from "./probe.js";
38
+ /** Dependencies the gateway hands the plugin to drive turns + replies. */
39
+ export interface SlackPluginDeps {
40
+ /** Boot-time default agent for routing fallbacks. */
41
+ defaultAgentId: string;
42
+ /** Active gateway config — re-read fresh per inbound for live policy. */
43
+ loadConfig: () => BrigadeConfig;
44
+ /** Run one agent turn (the gateway's serialised turn executor). */
45
+ runTurn: StartChannelsArgs["runTurn"];
46
+ /**
47
+ * Optional adapter factory — tests inject a fake; production uses
48
+ * `createSlackAdapter`. Receives the per-account scope.
49
+ */
50
+ adapterFactory?: (args: {
51
+ accountId: string;
52
+ }) => ChannelAdapter;
53
+ }
54
+ /** Operator-grade view of a per-account app — exposed via attached helpers. */
55
+ export interface SlackPluginRuntimeView {
56
+ /** Currently-running account ids. */
57
+ startedAccountIds(): string[];
58
+ /** Look up the per-account adapter (or undefined when the account isn't started). */
59
+ getAdapter(accountId: string): ChannelAdapter | undefined;
60
+ /** Run an `auth.test` probe for an account (for status / doctor). */
61
+ probeAccount(accountId: string, cfg: BrigadeConfig): Promise<SlackProbeResult>;
62
+ }
63
+ /** Plugin handle with the extra per-account introspection surface attached. */
64
+ export type SlackPluginHandle = ChannelPlugin<ResolvedSlackAccount> & SlackPluginRuntimeView;
65
+ /** Construct the plugin instance, capturing per-account runtime state in closure. */
66
+ export declare function createSlackPlugin(deps: SlackPluginDeps): SlackPluginHandle;
67
+ /** Outbound dispatch helper for callers reaching the plugin directly. */
68
+ export type SlackOutboundTarget = ChannelOutboundTarget;
69
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/slack/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAK9D,OAAO,EAON,KAAK,cAAc,EAOnB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAKlB,KAAK,iBAAiB,EAEtB,MAAM,WAAW,CAAC;AACnB,OAAO,EAMN,KAAK,oBAAoB,EACzB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAkB/D,0EAA0E;AAC1E,MAAM,WAAW,eAAe;IAC/B,qDAAqD;IACrD,cAAc,EAAE,MAAM,CAAC;IACvB,yEAAyE;IACzE,UAAU,EAAE,MAAM,aAAa,CAAC;IAChC,mEAAmE;IACnE,OAAO,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAC;IACtC;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,KAAK,cAAc,CAAC;CACjE;AAED,+EAA+E;AAC/E,MAAM,WAAW,sBAAsB;IACtC,qCAAqC;IACrC,iBAAiB,IAAI,MAAM,EAAE,CAAC;IAC9B,qFAAqF;IACrF,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAAC;IAC1D,qEAAqE;IACrE,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;CAC/E;AAED,+EAA+E;AAC/E,MAAM,MAAM,iBAAiB,GAAG,aAAa,CAAC,oBAAoB,CAAC,GAAG,sBAAsB,CAAC;AAqB7F,qFAAqF;AACrF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,GAAG,iBAAiB,CA+O1E;AAOD,yEAAyE;AACzE,MAAM,MAAM,mBAAmB,GAAG,qBAAqB,CAAC"}