@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,422 @@
1
+ /**
2
+ * Slack connection (Socket Mode inbound + Web API outbound).
3
+ *
4
+ * The Brigade analogue of `telegram/connection.ts`, distilled to Slack's two
5
+ * SDKs. `@slack/web-api` (`WebClient`) drives every OUTBOUND call (post / update
6
+ * / delete / react / upload / open-DM); `@slack/socket-mode`
7
+ * (`SocketModeClient`) opens the INBOUND events websocket (no public URL needed
8
+ * — the local-first default, analogous to Telegram long-polling). Both are
9
+ * lazy-imported here (`await import(...)` inside `connectSlack`) so a non-Slack
10
+ * boot never pays for them. Types are `type`-only so the static import never
11
+ * pulls the runtime in.
12
+ *
13
+ * Lifecycle:
14
+ * - `auth.test()` BOOTSTRAPS the connection — it both proves the bot token
15
+ * (an `invalid_auth` surfaces here → terminal) and caches the bot's
16
+ * `user_id` + `team_id` (the group ACL needs the bot's own user id to detect
17
+ * `<@bot>` mentions + to filter the bot's own echoes; without it group
18
+ * messages never reach the agent and the bot could reply to itself).
19
+ * - The SocketModeClient subscribes message / app_mention / reaction /
20
+ * interactive (block_actions) / slash_commands events. Each handler ACKs the
21
+ * envelope FIRST (Slack redelivers an un-acked event), then normalizes the
22
+ * payload into a `SlackInboundMessage` and routes it via `onMessage` /
23
+ * `onCallbackQuery` / `onReaction`. File bytes are downloaded via a DEFERRED
24
+ * `resolveMedia` thunk — only after the central access gate admits the
25
+ * sender (mirrors WhatsApp/Telegram).
26
+ * - The SocketModeClient auto-reconnects internally; we SUPERVISE the initial
27
+ * `.start()` with the SAME backoff curve as Telegram (2s → 30s, ×1.8, ±25%)
28
+ * and go terminal on an auth error (the only fix is a new token).
29
+ * - Events are de-duplicated by `ts` / `client_msg_id` (a redelivered envelope
30
+ * after a reconnect must not double-run the agent).
31
+ *
32
+ * Two transport modes share ONE normalize + dedupe + dispatch surface: Socket
33
+ * Mode (default) and Events API (HTTP webhook). The webhook route calls
34
+ * {@link SlackConnection.feedEvent} with each POSTed event, which runs the same
35
+ * handlers the socket uses.
36
+ */
37
+ import { type InboundMediaAttachment, type InboundReplyContext, type OutboundMedia } from "../sdk.js";
38
+ import { type SlackMessageEvent, type SlackReactionEvent } from "./inbound-extras.js";
39
+ import { type SlackUploadApi } from "./media.js";
40
+ /**
41
+ * Jittered exponential backoff for reconnect attempt `attempt` (0-based). Thin
42
+ * wrapper over the neutral `nextBackoffDelay` helper — kept as a named export so
43
+ * `index.ts` and the connection tests have a stable entry point.
44
+ */
45
+ export declare function slackBackoffDelay(attempt: number): number;
46
+ /** Slack's hard limit on a single message body is 40k; we chunk well under it. */
47
+ declare const SLACK_MESSAGE_LIMIT = 8000;
48
+ /** A normalized inbound Slack message (text and/or files). Mirrors `TgInboundMessage`. */
49
+ export interface SlackInboundMessage {
50
+ /** Channel id as a string — the conversation id. */
51
+ conversationId: string;
52
+ /** Slack message `ts` — surfaces for reply / edit / delete targeting. */
53
+ messageId?: string;
54
+ /** When Slack stamped the message (epoch ms, derived from `ts`). */
55
+ messageTimestampMs?: number;
56
+ /** Sender id within the workspace — the user id (`U…`). */
57
+ from: string;
58
+ /** Sender display name (the user id today; resolved names need a `users.info`). */
59
+ fromName?: string;
60
+ /** Plain message text (token-expanded, entity-unescaped). May be empty for files. */
61
+ text: string;
62
+ /** `direct` (im) or `group` (mpim/channel/group). */
63
+ chatType: "direct" | "group";
64
+ /** Workspace (team) id this message arrived in — feeds the route resolver's team tier. */
65
+ teamId?: string;
66
+ /** Thread parent `ts` as a string, when the message belongs to a thread. */
67
+ threadId?: string;
68
+ /** User ids `<@…>`-mentioned (incl. the bot's own id when addressed). */
69
+ mentions?: string[];
70
+ /** Quoted-reply context, when this message is a threaded reply. */
71
+ replyTo?: InboundReplyContext;
72
+ /**
73
+ * DEFERRED media download. The connection layer does NOT download eagerly —
74
+ * the pipeline invokes this ONLY after the access gate admits the sender, so a
75
+ * blocked stranger's file is never fetched. Resolves to an empty array for
76
+ * text-only messages.
77
+ */
78
+ resolveMedia?: () => Promise<InboundMediaAttachment[]>;
79
+ /**
80
+ * Inline-button callback context — present ONLY when this inbound is a
81
+ * `block_actions` press rather than a typed message. `data` is the opaque
82
+ * payload the pressed button declared at send time (an approval-callback codec
83
+ * string OR a general-prefixed token); `callbackId` is unused by Slack (the
84
+ * press is acked by the socket handler before routing) but carried for parity
85
+ * with the central pipeline's `callbackQuery` shape. Undefined for ordinary
86
+ * messages.
87
+ */
88
+ callbackQuery?: {
89
+ data: string;
90
+ callbackId: string;
91
+ };
92
+ /** True when this inbound is a `message_changed` edit (text carries the NEW text). */
93
+ edited?: boolean;
94
+ /**
95
+ * Inbound reaction context — present ONLY when this inbound is a
96
+ * `reaction_added` event. `emojis` are the newly-added reaction emoji(s);
97
+ * `targetMessageId` is the message they landed on. Undefined for typed messages.
98
+ */
99
+ reaction?: {
100
+ emojis: string[];
101
+ targetMessageId: string;
102
+ };
103
+ /** Raw Slack event (for adapters that need more). */
104
+ raw: unknown;
105
+ }
106
+ /** A Slack API response envelope (`ok` + optional `error` code + data). */
107
+ type SlackApiResponse = {
108
+ ok?: boolean;
109
+ error?: string;
110
+ [key: string]: unknown;
111
+ };
112
+ /**
113
+ * The minimal slice of `@slack/web-api`'s `WebClient` the connection drives.
114
+ * Declared as an interface (rather than importing the concrete class) so tests
115
+ * can inject a fake with zero network — the runtime path builds a real
116
+ * `WebClient` and it structurally satisfies this shape.
117
+ */
118
+ export interface SlackWebClientLike extends SlackUploadApi {
119
+ auth: {
120
+ test(): Promise<SlackApiResponse & {
121
+ user_id?: string;
122
+ user?: string;
123
+ team_id?: string;
124
+ team?: string;
125
+ bot_id?: string;
126
+ }>;
127
+ };
128
+ users?: {
129
+ info(args: {
130
+ user: string;
131
+ }): Promise<SlackApiResponse & {
132
+ user?: {
133
+ id?: string;
134
+ name?: string;
135
+ real_name?: string;
136
+ profile?: {
137
+ display_name?: string;
138
+ real_name?: string;
139
+ };
140
+ };
141
+ }>;
142
+ };
143
+ chat: {
144
+ postMessage(args: Record<string, unknown>): Promise<SlackApiResponse & {
145
+ ts?: string;
146
+ channel?: string;
147
+ }>;
148
+ update(args: Record<string, unknown>): Promise<SlackApiResponse & {
149
+ ts?: string;
150
+ }>;
151
+ delete(args: Record<string, unknown>): Promise<SlackApiResponse>;
152
+ };
153
+ reactions: {
154
+ add(args: Record<string, unknown>): Promise<SlackApiResponse>;
155
+ remove(args: Record<string, unknown>): Promise<SlackApiResponse>;
156
+ /**
157
+ * Read the reactions on a message (each carries the emoji `name` + the
158
+ * `users` who added it). Used by `removeOwnReactions` to find which
159
+ * reactions the bot itself placed so a "clear" can remove them — Slack
160
+ * `reactions.remove` needs a specific name, so there's no blanket clear.
161
+ * Optional so test fakes that don't drive reaction-clear still satisfy this
162
+ * shape; the real `WebClient` always provides it.
163
+ */
164
+ get?(args: {
165
+ channel: string;
166
+ timestamp: string;
167
+ }): Promise<SlackApiResponse & {
168
+ message?: {
169
+ reactions?: Array<{
170
+ name?: string;
171
+ users?: string[];
172
+ }>;
173
+ };
174
+ }>;
175
+ };
176
+ conversations: {
177
+ open(args: Record<string, unknown>): Promise<SlackApiResponse & {
178
+ channel?: {
179
+ id?: string;
180
+ };
181
+ }>;
182
+ /**
183
+ * Fetch the messages of a thread (the parent + its replies). Used by the
184
+ * thread-history backfill: when the bot is @-mentioned INTO a pre-existing
185
+ * thread it sees only the parent ts, so this pulls the prior messages to
186
+ * give the agent the conversation it just walked into. Optional so the many
187
+ * test fakes that don't drive backfill still satisfy this shape; the real
188
+ * `WebClient` always provides it.
189
+ */
190
+ replies?(args: {
191
+ channel: string;
192
+ ts: string;
193
+ limit?: number;
194
+ }): Promise<SlackApiResponse & {
195
+ messages?: Array<{
196
+ user?: string;
197
+ bot_id?: string;
198
+ text?: string;
199
+ ts?: string;
200
+ }>;
201
+ }>;
202
+ };
203
+ }
204
+ /** A handler payload the SocketModeClient delivers for an events_api event. */
205
+ export interface SocketEventArgs {
206
+ ack: (response?: unknown) => Promise<void>;
207
+ body?: {
208
+ team_id?: string;
209
+ event?: SlackMessageEvent | SlackReactionEvent;
210
+ [key: string]: unknown;
211
+ };
212
+ event?: SlackMessageEvent | SlackReactionEvent;
213
+ retry_num?: number;
214
+ }
215
+ /** A handler payload the SocketModeClient delivers for an `interactive` event. */
216
+ export interface SocketInteractiveArgs {
217
+ ack: (response?: unknown) => Promise<void>;
218
+ body?: SlackInteractivePayload;
219
+ }
220
+ /** A handler payload the SocketModeClient delivers for a `slash_commands` event. */
221
+ export interface SocketSlashArgs {
222
+ ack: (response?: unknown) => Promise<void>;
223
+ body?: SlackSlashCommandPayload;
224
+ }
225
+ /** A `block_actions` interactive payload (the subset Brigade reads). */
226
+ export interface SlackInteractivePayload {
227
+ type?: string;
228
+ team?: {
229
+ id?: string;
230
+ };
231
+ user?: {
232
+ id?: string;
233
+ name?: string;
234
+ username?: string;
235
+ };
236
+ channel?: {
237
+ id?: string;
238
+ };
239
+ message?: {
240
+ ts?: string;
241
+ thread_ts?: string;
242
+ };
243
+ actions?: Array<{
244
+ action_id?: string;
245
+ value?: string;
246
+ block_id?: string;
247
+ }>;
248
+ [key: string]: unknown;
249
+ }
250
+ /** A `slash_commands` payload (the subset Brigade reads). */
251
+ export interface SlackSlashCommandPayload {
252
+ command?: string;
253
+ text?: string;
254
+ user_id?: string;
255
+ user_name?: string;
256
+ channel_id?: string;
257
+ team_id?: string;
258
+ [key: string]: unknown;
259
+ }
260
+ /**
261
+ * The minimal slice of `@slack/socket-mode`'s `SocketModeClient` the connection
262
+ * drives — an EventEmitter with `.on(eventName, handler)`, `.start()`, and
263
+ * `.disconnect()`. Declared as an interface so tests inject a fake emitter.
264
+ */
265
+ export interface SlackSocketClientLike {
266
+ on(event: string, handler: (args: never) => unknown): void;
267
+ start(): Promise<unknown>;
268
+ disconnect(): Promise<unknown> | unknown;
269
+ }
270
+ export interface ConnectSlackArgs {
271
+ /** Bot user token (`xoxb-…`). NEVER logged. Every Web API call uses it. */
272
+ botToken: string;
273
+ /** App-level token (`xapp-…`) for Socket Mode. Required in socket mode. NEVER logged. */
274
+ appToken?: string;
275
+ /** Account namespace stamped on inbounds (single-account → "default"). */
276
+ accountId?: string;
277
+ /**
278
+ * Transport mode. `"socket"` (default, local-first — Socket Mode needs no
279
+ * public URL) drives the events websocket; `"events"` builds the WebClient
280
+ * but does NOT open a socket — the gateway HTTP route feeds events in via
281
+ * {@link SlackConnection.feedEvent}. Defaults to socket.
282
+ */
283
+ mode?: "socket" | "events";
284
+ /**
285
+ * Optional proxy URL all Slack API calls (+ the Socket Mode websocket) route
286
+ * through. Use it on networks where `slack.com` is blocked. Form:
287
+ * `http(s)://[user:pass@]host:port` for an HTTP CONNECT proxy, or
288
+ * `socks5://[user:pass@]host:port` (also `socks://` / `socks4://` /
289
+ * `socks5h://`) for a SOCKS proxy. When omitted/empty the connection is DIRECT
290
+ * (unchanged default). HTTP(S) proxies use `https-proxy-agent`; SOCKS proxies
291
+ * use `socks-proxy-agent` (see `proxy-agent.ts`).
292
+ */
293
+ proxyUrl?: string;
294
+ /** Called once `auth.test` succeeds and the socket connects. */
295
+ onConnected?: () => void;
296
+ /** Called when the token is rejected (invalid_auth) — terminal, re-token required. */
297
+ onTokenInvalid?: () => void;
298
+ /** Called for every inbound message. */
299
+ onMessage: (msg: SlackInboundMessage) => void;
300
+ /**
301
+ * Called for every inbound `block_actions` press. The socket handler has
302
+ * ALREADY acked the press before this fires, so the handler only routes the
303
+ * normalized inbound (which carries `callbackQuery: { data, callbackId }`).
304
+ * Optional — when omitted, presses are still acked + deduped but not routed.
305
+ */
306
+ onCallbackQuery?: (msg: SlackInboundMessage) => void;
307
+ /**
308
+ * Called for every inbound `reaction_added`. The normalized inbound carries
309
+ * `reaction: { emojis, targetMessageId }` and no text. Optional — when
310
+ * omitted, reaction events are deduped but not routed.
311
+ */
312
+ onReaction?: (msg: SlackInboundMessage) => void;
313
+ /** Subsystem logger. */
314
+ log: (msg: string, meta?: Record<string, unknown>) => void;
315
+ /**
316
+ * TEST SEAM: supply the WebClient + SocketModeClient instead of building real
317
+ * ones. Production leaves these undefined and the SDKs are lazy-imported. The
318
+ * second `agent` arg is the resolved proxy agent (undefined for a direct
319
+ * connection) — production threads it into the real `WebClient` /
320
+ * `SocketModeClient`; a test fake can assert it was handed the agent.
321
+ */
322
+ webClientFactory?: (botToken: string, agent?: unknown) => SlackWebClientLike;
323
+ socketModeFactory?: (appToken: string, agent?: unknown) => SlackSocketClientLike;
324
+ /**
325
+ * TEST SEAM: override how the proxy agent is built from `proxyUrl`. Production
326
+ * leaves this undefined and `buildSlackProxyAgent` lazy-imports the proxy-agent
327
+ * packages. Lets a test assert the resolver ran without a real proxy.
328
+ */
329
+ proxyAgentFactory?: (proxyUrl: string) => Promise<unknown>;
330
+ /** TEST SEAM: skip the real backoff sleep so reconnect tests run instantly. */
331
+ sleepImpl?: (ms: number) => Promise<void>;
332
+ }
333
+ export interface SlackConnection {
334
+ /** The bot's user id once connected, else null (the self id for mention/echo detection). */
335
+ selfId(): string | null;
336
+ /** The bot's @handle once connected, else null. */
337
+ selfName(): string | null;
338
+ /** The workspace (team) id once connected, else null. */
339
+ teamId(): string | null;
340
+ /** Epoch ms of the most recent successful connect, else null. */
341
+ connectedAt(): number | null;
342
+ /**
343
+ * Epoch ms of the most recent INBOUND event of any kind (message / reaction /
344
+ * interactive / slash, via socket OR webhook), else null. Liveness signal: a
345
+ * socket can read "connected" while silently dead, so a stale `lastEventAt`
346
+ * surfaces a half-dead connection. Observability only — a quiet channel is
347
+ * legitimately idle, so this NEVER flips health to "down".
348
+ */
349
+ lastEventAt(): number | null;
350
+ /** True once `auth.test` has succeeded and the socket is live. */
351
+ isConnected(): boolean;
352
+ /** True once an auth error marked the token terminally invalid. */
353
+ isTokenInvalid(): boolean;
354
+ /** Send a single text message. Returns the posted message's `ts`. */
355
+ sendText(channel: string, text: string, opts?: SlackSendTextOpts): Promise<{
356
+ messageId: string;
357
+ }>;
358
+ /**
359
+ * Send a message carrying Block Kit `blocks` (the native approval prompt /
360
+ * general buttons). `text` is the fallback; `blocks` is an opaque Block Kit
361
+ * array. Text is sent verbatim (no markdown→mrkdwn pass) so the caller
362
+ * controls formatting.
363
+ */
364
+ sendInteractive(channel: string, text: string, blocks: unknown, opts?: SlackSendTextOpts): Promise<{
365
+ messageId: string;
366
+ }>;
367
+ /** Upload a media attachment via files.uploadV2. */
368
+ sendMedia(channel: string, media: OutboundMedia, opts?: SlackSendMediaOpts): Promise<void>;
369
+ /** React to a previous message with an emoji name (no colons). */
370
+ react(channel: string, messageId: string, emoji: string): Promise<void>;
371
+ /** Remove a reaction from a message. Best-effort. */
372
+ removeReaction(channel: string, messageId: string, emoji: string): Promise<void>;
373
+ /**
374
+ * Remove EVERY reaction the bot itself placed on a message. Slack has no
375
+ * blanket "clear reactions" call (and a non-bot user's reactions aren't ours
376
+ * to touch), so this reads `reactions.get`, finds the reactions whose `users`
377
+ * include the bot's own id, and `reactions.remove`s each. Best-effort: a
378
+ * missing slice / fetch error / `no_reaction` is swallowed. This is what the
379
+ * central `message_action` "react" with an EMPTY emoji maps to (parity with
380
+ * WhatsApp/Telegram, where empty = clear).
381
+ */
382
+ removeOwnReactions(channel: string, messageId: string): Promise<void>;
383
+ /** Edit a previously-sent message's text. */
384
+ editMessageText(channel: string, messageId: string, text: string, opts?: SlackSendTextOpts): Promise<void>;
385
+ /** Delete a message. */
386
+ deleteMessage(channel: string, messageId: string): Promise<void>;
387
+ /** Open (or resolve) a DM channel with a user; returns the DM channel id. */
388
+ openDirectMessage(userId: string): Promise<string>;
389
+ /**
390
+ * Feed a raw Slack event envelope into the inbound path (events-API mode).
391
+ * Dispatches to the SAME handlers the socket uses, so webhook + socket share
392
+ * one normalize + dedupe surface. The `kind` selects the handler family.
393
+ */
394
+ feedEvent(kind: "event" | "interactive" | "slash", payload: unknown): void;
395
+ /** The transport mode this connection runs (`"socket"` | `"events"`). */
396
+ mode(): "socket" | "events";
397
+ /** Signal typing — emulated with a ⏳ reaction on the user's last message (Slack has no bot typing API). */
398
+ setComposing(channel: string, state: "composing" | "paused", threadId?: string): Promise<void>;
399
+ /** Read-receipt no-op (Slack bots can't mark-read). */
400
+ markRead(): Promise<void>;
401
+ /** Disconnect the socket + tear down. */
402
+ close(): Promise<void>;
403
+ }
404
+ export interface SlackSendTextOpts {
405
+ /** Thread parent ts — reply within this thread. */
406
+ threadId?: string;
407
+ /** Native reply target — the message ts to reply under (mapped to thread_ts). */
408
+ replyToMessageId?: string;
409
+ /** Set false to disable link unfurling for this send. */
410
+ linkPreview?: boolean;
411
+ }
412
+ export interface SlackSendMediaOpts {
413
+ /** Thread parent ts to upload into. */
414
+ threadId?: string;
415
+ }
416
+ /** An auth failure → the token is wrong / revoked / expired / scope-stripped (terminal). */
417
+ export declare function isSlackUnauthorized(err: unknown): boolean;
418
+ /** Strip a Slack token (`xoxb-…`/`xapp-…`/`xoxp-…`) out of a string before it logs. */
419
+ export declare function redactSlackToken(text: string, ...tokens: string[]): string;
420
+ export declare function connectSlack(args: ConnectSlackArgs): Promise<SlackConnection>;
421
+ export { SLACK_MESSAGE_LIMIT };
422
+ //# sourceMappingURL=connection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/slack/connection.ts"],"names":[],"mappings":"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"}