@spinabot/brigade 1.5.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/agent-loop.d.ts.map +1 -1
- package/dist/agents/agent-loop.js +51 -1
- package/dist/agents/agent-loop.js.map +1 -1
- package/dist/agents/channels/bundled-channel-metas.d.ts +4 -0
- package/dist/agents/channels/bundled-channel-metas.d.ts.map +1 -1
- package/dist/agents/channels/bundled-channel-metas.js +22 -0
- package/dist/agents/channels/bundled-channel-metas.js.map +1 -1
- package/dist/agents/channels/discord/account-config.d.ts +117 -0
- package/dist/agents/channels/discord/account-config.d.ts.map +1 -0
- package/dist/agents/channels/discord/account-config.js +260 -0
- package/dist/agents/channels/discord/account-config.js.map +1 -0
- package/dist/agents/channels/discord/adapter.d.ts +56 -0
- package/dist/agents/channels/discord/adapter.d.ts.map +1 -0
- package/dist/agents/channels/discord/adapter.js +526 -0
- package/dist/agents/channels/discord/adapter.js.map +1 -0
- package/dist/agents/channels/discord/approval-authorize.d.ts +43 -0
- package/dist/agents/channels/discord/approval-authorize.d.ts.map +1 -0
- package/dist/agents/channels/discord/approval-authorize.js +71 -0
- package/dist/agents/channels/discord/approval-authorize.js.map +1 -0
- package/dist/agents/channels/discord/approval-native.d.ts +68 -0
- package/dist/agents/channels/discord/approval-native.d.ts.map +1 -0
- package/dist/agents/channels/discord/approval-native.js +81 -0
- package/dist/agents/channels/discord/approval-native.js.map +1 -0
- package/dist/agents/channels/discord/command-menu.d.ts +49 -0
- package/dist/agents/channels/discord/command-menu.d.ts.map +1 -0
- package/dist/agents/channels/discord/command-menu.js +73 -0
- package/dist/agents/channels/discord/command-menu.js.map +1 -0
- package/dist/agents/channels/discord/components.d.ts +97 -0
- package/dist/agents/channels/discord/components.d.ts.map +1 -0
- package/dist/agents/channels/discord/components.js +131 -0
- package/dist/agents/channels/discord/components.js.map +1 -0
- package/dist/agents/channels/discord/connection.d.ts +387 -0
- package/dist/agents/channels/discord/connection.d.ts.map +1 -0
- package/dist/agents/channels/discord/connection.js +786 -0
- package/dist/agents/channels/discord/connection.js.map +1 -0
- package/dist/agents/channels/discord/draft-stream.d.ts +92 -0
- package/dist/agents/channels/discord/draft-stream.d.ts.map +1 -0
- package/dist/agents/channels/discord/draft-stream.js +213 -0
- package/dist/agents/channels/discord/draft-stream.js.map +1 -0
- package/dist/agents/channels/discord/format.d.ts +55 -0
- package/dist/agents/channels/discord/format.d.ts.map +1 -0
- package/dist/agents/channels/discord/format.js +247 -0
- package/dist/agents/channels/discord/format.js.map +1 -0
- package/dist/agents/channels/discord/inbound-extras.d.ts +220 -0
- package/dist/agents/channels/discord/inbound-extras.d.ts.map +1 -0
- package/dist/agents/channels/discord/inbound-extras.js +351 -0
- package/dist/agents/channels/discord/inbound-extras.js.map +1 -0
- package/dist/agents/channels/discord/index.d.ts +14 -0
- package/dist/agents/channels/discord/index.d.ts.map +1 -0
- package/dist/agents/channels/discord/index.js +14 -0
- package/dist/agents/channels/discord/index.js.map +1 -0
- package/dist/agents/channels/discord/media.d.ts +85 -0
- package/dist/agents/channels/discord/media.d.ts.map +1 -0
- package/dist/agents/channels/discord/media.js +242 -0
- package/dist/agents/channels/discord/media.js.map +1 -0
- package/dist/agents/channels/discord/module.d.ts +15 -0
- package/dist/agents/channels/discord/module.d.ts.map +1 -0
- package/dist/agents/channels/discord/module.js +22 -0
- package/dist/agents/channels/discord/module.js.map +1 -0
- package/dist/agents/channels/discord/plugin.d.ts +73 -0
- package/dist/agents/channels/discord/plugin.d.ts.map +1 -0
- package/dist/agents/channels/discord/plugin.js +303 -0
- package/dist/agents/channels/discord/plugin.js.map +1 -0
- package/dist/agents/channels/discord/probe.d.ts +93 -0
- package/dist/agents/channels/discord/probe.d.ts.map +1 -0
- package/dist/agents/channels/discord/probe.js +158 -0
- package/dist/agents/channels/discord/probe.js.map +1 -0
- package/dist/agents/channels/discord/reasoning-lane.d.ts +42 -0
- package/dist/agents/channels/discord/reasoning-lane.d.ts.map +1 -0
- package/dist/agents/channels/discord/reasoning-lane.js +68 -0
- package/dist/agents/channels/discord/reasoning-lane.js.map +1 -0
- package/dist/agents/channels/inbound-pipeline.d.ts.map +1 -1
- package/dist/agents/channels/inbound-pipeline.js +65 -7
- package/dist/agents/channels/inbound-pipeline.js.map +1 -1
- package/dist/agents/channels/manager.d.ts.map +1 -1
- package/dist/agents/channels/manager.js +18 -0
- package/dist/agents/channels/manager.js.map +1 -1
- package/dist/agents/channels/sdk.d.ts +4 -0
- package/dist/agents/channels/sdk.d.ts.map +1 -1
- package/dist/agents/channels/sdk.js +4 -0
- package/dist/agents/channels/sdk.js.map +1 -1
- package/dist/agents/channels/slack/account-config.d.ts +172 -0
- package/dist/agents/channels/slack/account-config.d.ts.map +1 -0
- package/dist/agents/channels/slack/account-config.js +353 -0
- package/dist/agents/channels/slack/account-config.js.map +1 -0
- package/dist/agents/channels/slack/account-registry.d.ts +45 -0
- package/dist/agents/channels/slack/account-registry.d.ts.map +1 -0
- package/dist/agents/channels/slack/account-registry.js +58 -0
- package/dist/agents/channels/slack/account-registry.js.map +1 -0
- package/dist/agents/channels/slack/adapter.d.ts +66 -0
- package/dist/agents/channels/slack/adapter.d.ts.map +1 -0
- package/dist/agents/channels/slack/adapter.js +547 -0
- package/dist/agents/channels/slack/adapter.js.map +1 -0
- package/dist/agents/channels/slack/approval-authorize.d.ts +43 -0
- package/dist/agents/channels/slack/approval-authorize.d.ts.map +1 -0
- package/dist/agents/channels/slack/approval-authorize.js +71 -0
- package/dist/agents/channels/slack/approval-authorize.js.map +1 -0
- package/dist/agents/channels/slack/approval-native.d.ts +70 -0
- package/dist/agents/channels/slack/approval-native.d.ts.map +1 -0
- package/dist/agents/channels/slack/approval-native.js +85 -0
- package/dist/agents/channels/slack/approval-native.js.map +1 -0
- package/dist/agents/channels/slack/blocks.d.ts +125 -0
- package/dist/agents/channels/slack/blocks.d.ts.map +1 -0
- package/dist/agents/channels/slack/blocks.js +145 -0
- package/dist/agents/channels/slack/blocks.js.map +1 -0
- package/dist/agents/channels/slack/command-menu.d.ts +44 -0
- package/dist/agents/channels/slack/command-menu.d.ts.map +1 -0
- package/dist/agents/channels/slack/command-menu.js +66 -0
- package/dist/agents/channels/slack/command-menu.js.map +1 -0
- package/dist/agents/channels/slack/connection.d.ts +422 -0
- package/dist/agents/channels/slack/connection.d.ts.map +1 -0
- package/dist/agents/channels/slack/connection.js +1042 -0
- package/dist/agents/channels/slack/connection.js.map +1 -0
- package/dist/agents/channels/slack/directory-live.d.ts +129 -0
- package/dist/agents/channels/slack/directory-live.d.ts.map +1 -0
- package/dist/agents/channels/slack/directory-live.js +148 -0
- package/dist/agents/channels/slack/directory-live.js.map +1 -0
- package/dist/agents/channels/slack/draft-stream.d.ts +93 -0
- package/dist/agents/channels/slack/draft-stream.d.ts.map +1 -0
- package/dist/agents/channels/slack/draft-stream.js +218 -0
- package/dist/agents/channels/slack/draft-stream.js.map +1 -0
- package/dist/agents/channels/slack/format.d.ts +41 -0
- package/dist/agents/channels/slack/format.d.ts.map +1 -0
- package/dist/agents/channels/slack/format.js +271 -0
- package/dist/agents/channels/slack/format.js.map +1 -0
- package/dist/agents/channels/slack/inbound-extras.d.ts +179 -0
- package/dist/agents/channels/slack/inbound-extras.d.ts.map +1 -0
- package/dist/agents/channels/slack/inbound-extras.js +257 -0
- package/dist/agents/channels/slack/inbound-extras.js.map +1 -0
- package/dist/agents/channels/slack/index.d.ts +15 -0
- package/dist/agents/channels/slack/index.d.ts.map +1 -0
- package/dist/agents/channels/slack/index.js +15 -0
- package/dist/agents/channels/slack/index.js.map +1 -0
- package/dist/agents/channels/slack/media.d.ts +90 -0
- package/dist/agents/channels/slack/media.d.ts.map +1 -0
- package/dist/agents/channels/slack/media.js +215 -0
- package/dist/agents/channels/slack/media.js.map +1 -0
- package/dist/agents/channels/slack/module.d.ts +26 -0
- package/dist/agents/channels/slack/module.d.ts.map +1 -0
- package/dist/agents/channels/slack/module.js +67 -0
- package/dist/agents/channels/slack/module.js.map +1 -0
- package/dist/agents/channels/slack/plugin.d.ts +69 -0
- package/dist/agents/channels/slack/plugin.d.ts.map +1 -0
- package/dist/agents/channels/slack/plugin.js +318 -0
- package/dist/agents/channels/slack/plugin.js.map +1 -0
- package/dist/agents/channels/slack/probe.d.ts +72 -0
- package/dist/agents/channels/slack/probe.d.ts.map +1 -0
- package/dist/agents/channels/slack/probe.js +103 -0
- package/dist/agents/channels/slack/probe.js.map +1 -0
- package/dist/agents/channels/slack/proxy-agent.d.ts +30 -0
- package/dist/agents/channels/slack/proxy-agent.d.ts.map +1 -0
- package/dist/agents/channels/slack/proxy-agent.js +44 -0
- package/dist/agents/channels/slack/proxy-agent.js.map +1 -0
- package/dist/agents/channels/slack/reasoning-lane.d.ts +42 -0
- package/dist/agents/channels/slack/reasoning-lane.d.ts.map +1 -0
- package/dist/agents/channels/slack/reasoning-lane.js +68 -0
- package/dist/agents/channels/slack/reasoning-lane.js.map +1 -0
- package/dist/agents/channels/slack/user-directory.d.ts +69 -0
- package/dist/agents/channels/slack/user-directory.d.ts.map +1 -0
- package/dist/agents/channels/slack/user-directory.js +94 -0
- package/dist/agents/channels/slack/user-directory.js.map +1 -0
- package/dist/agents/channels/slack/webhook.d.ts +89 -0
- package/dist/agents/channels/slack/webhook.d.ts.map +1 -0
- package/dist/agents/channels/slack/webhook.js +228 -0
- package/dist/agents/channels/slack/webhook.js.map +1 -0
- package/dist/agents/channels/telegram/format.d.ts.map +1 -1
- package/dist/agents/channels/telegram/format.js +17 -1
- package/dist/agents/channels/telegram/format.js.map +1 -1
- package/dist/agents/channels/telegram/webhook.d.ts.map +1 -1
- package/dist/agents/channels/telegram/webhook.js +7 -1
- package/dist/agents/channels/telegram/webhook.js.map +1 -1
- package/dist/agents/extensions/modules/index.d.ts.map +1 -1
- package/dist/agents/extensions/modules/index.js +10 -0
- package/dist/agents/extensions/modules/index.js.map +1 -1
- package/dist/agents/tools/cron-tool.d.ts.map +1 -1
- package/dist/agents/tools/cron-tool.js +4 -1
- package/dist/agents/tools/cron-tool.js.map +1 -1
- package/dist/buildstamp.json +1 -1
- package/dist/core/auth-bridge.d.ts +1 -0
- package/dist/core/auth-bridge.d.ts.map +1 -1
- package/dist/core/auth-bridge.js +46 -1
- package/dist/core/auth-bridge.js.map +1 -1
- package/dist/core/server.d.ts.map +1 -1
- package/dist/core/server.js +40 -5
- package/dist/core/server.js.map +1 -1
- package/dist/cron/isolated-agent/run-executor.d.ts +11 -0
- package/dist/cron/isolated-agent/run-executor.d.ts.map +1 -1
- package/dist/cron/isolated-agent/run-executor.js +20 -4
- package/dist/cron/isolated-agent/run-executor.js.map +1 -1
- package/dist/cron/types.d.ts +8 -0
- package/dist/cron/types.d.ts.map +1 -1
- package/dist/system-prompt/assembler.d.ts.map +1 -1
- package/dist/system-prompt/assembler.js +4 -2
- package/dist/system-prompt/assembler.js.map +1 -1
- package/package.json +5 -1
|
@@ -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"}
|
|
@@ -0,0 +1,547 @@
|
|
|
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 { loadConfig } from "../../../core/config.js";
|
|
24
|
+
// Channel SDK barrel — the single import surface for the channel-authoring
|
|
25
|
+
// contract + shared helpers. Contract types (ChannelAdapter / ChannelHealth /
|
|
26
|
+
// ChannelStartContext / OutboundMedia / OutboundSendOptions) + `chunkText` come
|
|
27
|
+
// from one place instead of scattered paths.
|
|
28
|
+
import { chunkText, } from "../sdk.js";
|
|
29
|
+
import { listSlackAccountIds, resolveSlackAppToken, resolveSlackBotToken, resolveSlackProxyUrl, slackChannelEnabled, slackEventsConfig, slackLiveStreamEnabled, slackStreamThrottleMs, slackSurfaceReasoning, SLACK_CHANNEL_ID, SLACK_DEFAULT_ACCOUNT_ID, } from "./account-config.js";
|
|
30
|
+
import { buildSlackApprovalMessage } from "./approval-native.js";
|
|
31
|
+
import { resolveSlackApprover } from "./approval-authorize.js";
|
|
32
|
+
import { buildSlackInlineKeyboard } from "./blocks.js";
|
|
33
|
+
import { connectSlack } from "./connection.js";
|
|
34
|
+
import { createDraftStream } from "./draft-stream.js";
|
|
35
|
+
import { markdownToSlackMrkdwn, slackMrkdwnIsEmpty } from "./format.js";
|
|
36
|
+
import { splitSlackReasoning } from "./reasoning-lane.js";
|
|
37
|
+
/** Slack's practical per-message text limit (chars) for chunked sends. */
|
|
38
|
+
const SLACK_TEXT_LIMIT = 8_000;
|
|
39
|
+
export function createSlackAdapter(opts = {}) {
|
|
40
|
+
const accountId = opts.accountId?.trim() || SLACK_DEFAULT_ACCOUNT_ID;
|
|
41
|
+
const connectImpl = opts.connectImpl ?? connectSlack;
|
|
42
|
+
let connection = null;
|
|
43
|
+
// The ChannelStartContext doesn't carry the config, but the manager ALWAYS
|
|
44
|
+
// calls `isConfigured(cfg, env)` immediately before `start(ctx)` — so we
|
|
45
|
+
// capture the config + env it passed there and read the tokens from them in
|
|
46
|
+
// start(). This avoids a second config load and keeps the adapter pure.
|
|
47
|
+
let lastConfig = null;
|
|
48
|
+
let lastEnv = process.env;
|
|
49
|
+
// Health flags mirrored from the connection lifecycle so health() never has to
|
|
50
|
+
// round-trip Slack on the hot path (cron timer / send pre-flight).
|
|
51
|
+
// - `connected` flips true on a successful auth.test + socket start.
|
|
52
|
+
// - `tokenInvalid` is STICKY: an auth error means the token is dead and the
|
|
53
|
+
// only recovery is `brigade channels add --channel slack` with new tokens.
|
|
54
|
+
let connected = false;
|
|
55
|
+
let tokenInvalid = false;
|
|
56
|
+
const adapter = {
|
|
57
|
+
id: SLACK_CHANNEL_ID,
|
|
58
|
+
label: "Slack",
|
|
59
|
+
isConfigured(cfg, env) {
|
|
60
|
+
// Capture for start() — the manager calls this right before start(ctx).
|
|
61
|
+
lastConfig = cfg;
|
|
62
|
+
lastEnv = env ?? process.env;
|
|
63
|
+
if (!slackChannelEnabled(cfg))
|
|
64
|
+
return false;
|
|
65
|
+
// Need a resolvable bot token (config `${VAR}` ref or SLACK_BOT_TOKEN env).
|
|
66
|
+
if (!resolveSlackBotToken(cfg, accountId, env ?? process.env))
|
|
67
|
+
return false;
|
|
68
|
+
// Socket mode additionally needs an app-level token; events mode does not
|
|
69
|
+
// (it verifies the signing secret on the HTTP route instead).
|
|
70
|
+
if (slackEventsConfig(cfg).mode === "socket" && !resolveSlackAppToken(cfg, accountId, env ?? process.env)) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
// Multi-workspace follow-up: when the operator declares >1 account, the
|
|
74
|
+
// plugin path owns lifecycle and the legacy single adapter steps aside.
|
|
75
|
+
const isLegacyAdapter = accountId === SLACK_DEFAULT_ACCOUNT_ID;
|
|
76
|
+
if (isLegacyAdapter && listSlackAccountIds(cfg).length > 1)
|
|
77
|
+
return false;
|
|
78
|
+
return true;
|
|
79
|
+
},
|
|
80
|
+
async start(ctx) {
|
|
81
|
+
// Resolve the tokens from the config the manager handed isConfigured().
|
|
82
|
+
// Fall back to a fresh load defensively (e.g. a direct start() in a test
|
|
83
|
+
// that skipped isConfigured).
|
|
84
|
+
const cfg = lastConfig ?? (await loadStartConfig());
|
|
85
|
+
const botToken = resolveSlackBotToken(cfg, accountId, lastEnv);
|
|
86
|
+
if (!botToken) {
|
|
87
|
+
ctx.log("Slack not started — no bot token resolved (set channels.slack.botToken or SLACK_BOT_TOKEN).");
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const transport = slackEventsConfig(cfg);
|
|
91
|
+
const appToken = resolveSlackAppToken(cfg, accountId, lastEnv);
|
|
92
|
+
if (transport.mode === "socket" && !appToken) {
|
|
93
|
+
ctx.log("Slack not started — socket mode needs an app-level token (set channels.slack.appToken or SLACK_APP_TOKEN).");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
// Optional proxy — routes the Web API + Socket Mode websocket through it
|
|
97
|
+
// on networks where slack.com is blocked. Empty → direct (unchanged).
|
|
98
|
+
const proxyUrl = resolveSlackProxyUrl(cfg, accountId, lastEnv);
|
|
99
|
+
connection = await connectImpl({
|
|
100
|
+
botToken,
|
|
101
|
+
...(appToken ? { appToken } : {}),
|
|
102
|
+
...(proxyUrl ? { proxyUrl } : {}),
|
|
103
|
+
accountId,
|
|
104
|
+
mode: transport.mode,
|
|
105
|
+
log: ctx.log,
|
|
106
|
+
onConnected: () => {
|
|
107
|
+
connected = true;
|
|
108
|
+
tokenInvalid = false;
|
|
109
|
+
ctx.log("Slack ready");
|
|
110
|
+
ctx.onConnected?.();
|
|
111
|
+
},
|
|
112
|
+
onTokenInvalid: () => {
|
|
113
|
+
connected = false;
|
|
114
|
+
tokenInvalid = true;
|
|
115
|
+
ctx.log("Slack token was rejected. Run `brigade channels add --channel slack` with a fresh bot + app token.");
|
|
116
|
+
ctx.onLoggedOut?.();
|
|
117
|
+
},
|
|
118
|
+
onMessage: (msg) => {
|
|
119
|
+
void ctx.onInbound({
|
|
120
|
+
channel: SLACK_CHANNEL_ID,
|
|
121
|
+
accountId,
|
|
122
|
+
conversationId: msg.conversationId,
|
|
123
|
+
messageId: msg.messageId,
|
|
124
|
+
messageTimestampMs: msg.messageTimestampMs,
|
|
125
|
+
from: msg.from,
|
|
126
|
+
fromName: msg.fromName,
|
|
127
|
+
text: msg.text,
|
|
128
|
+
chatType: msg.chatType,
|
|
129
|
+
isGroup: msg.chatType === "group",
|
|
130
|
+
threadId: msg.threadId,
|
|
131
|
+
teamId: msg.teamId,
|
|
132
|
+
mentions: msg.mentions,
|
|
133
|
+
replyTo: msg.replyTo,
|
|
134
|
+
// Edit provenance rides through so the central pipeline / agent see
|
|
135
|
+
// "this was an edit".
|
|
136
|
+
...(msg.edited ? { edited: true } : {}),
|
|
137
|
+
// Deferred media thunk rides through untouched — the pipeline
|
|
138
|
+
// resolves it only after the access gate admits the sender.
|
|
139
|
+
resolveMedia: msg.resolveMedia,
|
|
140
|
+
raw: msg.raw,
|
|
141
|
+
});
|
|
142
|
+
},
|
|
143
|
+
// Inbound reaction → synthesise a short note and route it through the
|
|
144
|
+
// SAME inbound pipeline as a normal message so the access gate + routing
|
|
145
|
+
// apply uniformly. The note carries the added emoji(s) + the target id.
|
|
146
|
+
onReaction: (msg) => {
|
|
147
|
+
if (!msg.reaction)
|
|
148
|
+
return;
|
|
149
|
+
const note = buildReactionNote(msg.reaction.emojis, msg.reaction.targetMessageId, msg.fromName);
|
|
150
|
+
void ctx.onInbound({
|
|
151
|
+
channel: SLACK_CHANNEL_ID,
|
|
152
|
+
accountId,
|
|
153
|
+
conversationId: msg.conversationId,
|
|
154
|
+
from: msg.from,
|
|
155
|
+
...(msg.fromName !== undefined ? { fromName: msg.fromName } : {}),
|
|
156
|
+
text: note,
|
|
157
|
+
chatType: msg.chatType,
|
|
158
|
+
isGroup: msg.chatType === "group",
|
|
159
|
+
...(msg.threadId !== undefined ? { threadId: msg.threadId } : {}),
|
|
160
|
+
...(msg.teamId !== undefined ? { teamId: msg.teamId } : {}),
|
|
161
|
+
reaction: msg.reaction,
|
|
162
|
+
raw: msg.raw,
|
|
163
|
+
});
|
|
164
|
+
},
|
|
165
|
+
// Block-action press → emit an InboundMessage carrying `callbackQuery` so
|
|
166
|
+
// the central pipeline's approval-callback path resolves it. The
|
|
167
|
+
// connection has already acked the press.
|
|
168
|
+
onCallbackQuery: (msg) => {
|
|
169
|
+
if (!msg.callbackQuery)
|
|
170
|
+
return;
|
|
171
|
+
void ctx.onInbound({
|
|
172
|
+
channel: SLACK_CHANNEL_ID,
|
|
173
|
+
accountId,
|
|
174
|
+
conversationId: msg.conversationId,
|
|
175
|
+
from: msg.from,
|
|
176
|
+
...(msg.fromName !== undefined ? { fromName: msg.fromName } : {}),
|
|
177
|
+
text: "",
|
|
178
|
+
chatType: msg.chatType,
|
|
179
|
+
isGroup: msg.chatType === "group",
|
|
180
|
+
...(msg.threadId !== undefined ? { threadId: msg.threadId } : {}),
|
|
181
|
+
...(msg.teamId !== undefined ? { teamId: msg.teamId } : {}),
|
|
182
|
+
callbackQuery: msg.callbackQuery,
|
|
183
|
+
raw: msg.raw,
|
|
184
|
+
});
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
},
|
|
188
|
+
async stop() {
|
|
189
|
+
await connection?.close();
|
|
190
|
+
connection = null;
|
|
191
|
+
connected = false;
|
|
192
|
+
},
|
|
193
|
+
/**
|
|
194
|
+
* Synchronous read of the cached connection state:
|
|
195
|
+
* - `{ ok: true }` once the socket is live.
|
|
196
|
+
* - `{ ok: false, kind: "logged-out" }` after an auth error (sticky; re-token).
|
|
197
|
+
* - `{ ok: false, kind: "starting" }` between start() and first connect.
|
|
198
|
+
* - `{ ok: false, kind: "disconnected" }` for a transient drop mid-reconnect.
|
|
199
|
+
*/
|
|
200
|
+
health() {
|
|
201
|
+
if (tokenInvalid || connection?.isTokenInvalid()) {
|
|
202
|
+
return {
|
|
203
|
+
ok: false,
|
|
204
|
+
kind: "logged-out",
|
|
205
|
+
reason: "Slack token was rejected — Brigade can't send until a new token is set.",
|
|
206
|
+
remediation: "Run `brigade channels add --channel slack` and paste a fresh bot + app token.",
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
if (!connection) {
|
|
210
|
+
return { ok: false, kind: "starting", reason: "Slack adapter is not started yet." };
|
|
211
|
+
}
|
|
212
|
+
if (!connected || !connection.isConnected()) {
|
|
213
|
+
return {
|
|
214
|
+
ok: false,
|
|
215
|
+
kind: "disconnected",
|
|
216
|
+
reason: "Slack is reconnecting — sends will fail until the socket resumes.",
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
return { ok: true };
|
|
220
|
+
},
|
|
221
|
+
async sendText(conversationId, text, opts) {
|
|
222
|
+
if (!connection)
|
|
223
|
+
throw new Error("Slack channel is not started");
|
|
224
|
+
if (tokenInvalid || connection.isTokenInvalid()) {
|
|
225
|
+
throw new Error("Slack token is invalid — run `brigade channels add --channel slack` with a new token, then retry.");
|
|
226
|
+
}
|
|
227
|
+
const threadId = opts?.threadId;
|
|
228
|
+
// Native reply target (Slack thread_ts). Applied to the FIRST chunk only —
|
|
229
|
+
// threading every chunk of a long reply is redundant once the first lands
|
|
230
|
+
// in the thread. Omitted → unthreaded send (unchanged).
|
|
231
|
+
const replyToMessageId = opts?.replyToId;
|
|
232
|
+
const sendExtras = {};
|
|
233
|
+
if (threadId)
|
|
234
|
+
sendExtras.threadId = threadId;
|
|
235
|
+
if (opts?.linkPreview !== undefined)
|
|
236
|
+
sendExtras.linkPreview = opts.linkPreview;
|
|
237
|
+
// Chunk on the RAW markdown so fences/paragraphs aren't shredded, then
|
|
238
|
+
// convert each chunk to Slack mrkdwn and send with `mrkdwn: true`. A chunk
|
|
239
|
+
// whose rendered mrkdwn is empty (syntax-only) is re-sent as the raw chunk.
|
|
240
|
+
const chunks = chunkText(text, { limit: SLACK_TEXT_LIMIT });
|
|
241
|
+
let first = true;
|
|
242
|
+
for (const chunk of chunks) {
|
|
243
|
+
// Only the first chunk carries the reply thread target.
|
|
244
|
+
const replyOpt = first && replyToMessageId ? { replyToMessageId } : {};
|
|
245
|
+
const mrkdwn = markdownToSlackMrkdwn(chunk);
|
|
246
|
+
const body = slackMrkdwnIsEmpty(mrkdwn) ? chunk : mrkdwn;
|
|
247
|
+
if (body.trim().length === 0)
|
|
248
|
+
continue;
|
|
249
|
+
await connection.sendText(conversationId, body, { ...sendExtras, ...replyOpt });
|
|
250
|
+
first = false;
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
/**
|
|
254
|
+
* Open a LIVE reply stream — the gateway feeds the accumulating answer text
|
|
255
|
+
* via `update()`, this edits one Slack message in place (throttled ~1×/sec),
|
|
256
|
+
* and `finalize()` settles it on turn end. Returns `null` when streaming is
|
|
257
|
+
* disabled in config (`channels.slack.liveStream` is not true) OR the
|
|
258
|
+
* connection isn't live, so the pipeline falls back to the single final
|
|
259
|
+
* `sendText` — byte-unchanged from before streaming existed.
|
|
260
|
+
*
|
|
261
|
+
* Each draft chunk is rendered through the SAME markdown→mrkdwn converter the
|
|
262
|
+
* final path uses. When the running answer exceeds the limit the stream
|
|
263
|
+
* finalizes the current message at a boundary and rolls overflow into a new
|
|
264
|
+
* message.
|
|
265
|
+
*/
|
|
266
|
+
beginReplyStream(conversationId, sendOpts) {
|
|
267
|
+
if (!connection)
|
|
268
|
+
return null;
|
|
269
|
+
if (tokenInvalid || connection.isTokenInvalid())
|
|
270
|
+
return null;
|
|
271
|
+
const cfg = lastConfig;
|
|
272
|
+
if (!cfg || !slackLiveStreamEnabled(cfg))
|
|
273
|
+
return null;
|
|
274
|
+
const conn = connection;
|
|
275
|
+
const threadId = sendOpts?.threadId;
|
|
276
|
+
const stream = createDraftStream({
|
|
277
|
+
transport: {
|
|
278
|
+
async postMessage(text, o) {
|
|
279
|
+
const sent = await conn.sendText(conversationId, text, {
|
|
280
|
+
...(o.threadId !== undefined ? { threadId: o.threadId } : {}),
|
|
281
|
+
});
|
|
282
|
+
return { ts: sent.messageId };
|
|
283
|
+
},
|
|
284
|
+
async updateMessage(ts, text) {
|
|
285
|
+
await conn.editMessageText(conversationId, ts, text);
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
...(threadId !== undefined ? { threadId } : {}),
|
|
289
|
+
throttleMs: slackStreamThrottleMs(cfg),
|
|
290
|
+
maxChars: SLACK_TEXT_LIMIT,
|
|
291
|
+
// Render each draft chunk to Slack mrkdwn; fall back to the plain chunk
|
|
292
|
+
// when the mrkdwn is empty (syntax-only).
|
|
293
|
+
renderText: (chunk) => {
|
|
294
|
+
const mrkdwn = markdownToSlackMrkdwn(chunk);
|
|
295
|
+
return { text: slackMrkdwnIsEmpty(mrkdwn) ? chunk : mrkdwn };
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
return {
|
|
299
|
+
update: (text) => stream.update(text),
|
|
300
|
+
async finalize(finalText) {
|
|
301
|
+
await stream.finalize(finalText);
|
|
302
|
+
const ids = stream.messageIds();
|
|
303
|
+
const last = ids[ids.length - 1];
|
|
304
|
+
return last !== undefined ? { messageId: last } : undefined;
|
|
305
|
+
},
|
|
306
|
+
stop: () => stream.stop(),
|
|
307
|
+
};
|
|
308
|
+
},
|
|
309
|
+
/**
|
|
310
|
+
* OPTIONAL reasoning lane (default OFF). When `channels.slack.
|
|
311
|
+
* surfaceReasoning` is true, split the raw reply's `<think>` trace out and
|
|
312
|
+
* send it as a separate `🧠 Reasoning:` message BEFORE the answer. When the
|
|
313
|
+
* config gate is off (the default) OR the reply carried no reasoning, this
|
|
314
|
+
* sends NOTHING — the answer message the pipeline sends afterward is
|
|
315
|
+
* byte-identical either way.
|
|
316
|
+
*/
|
|
317
|
+
async deliverReasoning(conversationId, rawReply, sendOpts) {
|
|
318
|
+
if (!connection)
|
|
319
|
+
return;
|
|
320
|
+
if (tokenInvalid || connection.isTokenInvalid())
|
|
321
|
+
return;
|
|
322
|
+
const cfg = lastConfig;
|
|
323
|
+
if (!cfg || !slackSurfaceReasoning(cfg))
|
|
324
|
+
return;
|
|
325
|
+
const { reasoningText } = splitSlackReasoning(rawReply ?? "");
|
|
326
|
+
if (!reasoningText)
|
|
327
|
+
return;
|
|
328
|
+
// Reuse the adapter's own chunk+mrkdwn send path so a long reasoning trace
|
|
329
|
+
// is chunked at 8000 and formatted consistently with replies.
|
|
330
|
+
await adapter.sendText(conversationId, reasoningText, sendOpts);
|
|
331
|
+
},
|
|
332
|
+
// Slack ids are workspace user ids (`U…`); the pairing challenge card uses
|
|
333
|
+
// the "Your username" line. The bot is a SEPARATE account from the operator
|
|
334
|
+
// (its own app), so ownership is bootstrapped from the first CLI `pairing
|
|
335
|
+
// approve` — see `botIsSeparateFromOperator`.
|
|
336
|
+
pairing: { idLabel: "username", botIsSeparateFromOperator: true },
|
|
337
|
+
// Token-based setup wizard — `brigade channels add --channel slack` prompts
|
|
338
|
+
// for the bot token + app token and writes `channels.slack.botToken` /
|
|
339
|
+
// `channels.slack.appToken`. The signing secret (events mode only) is set
|
|
340
|
+
// directly as `channels.slack.signingSecret` when the operator switches to
|
|
341
|
+
// the HTTP transport.
|
|
342
|
+
setup: {
|
|
343
|
+
credentialKeys: [
|
|
344
|
+
{
|
|
345
|
+
key: "botToken",
|
|
346
|
+
prompt: "Slack bot token (xoxb-…, from the app's OAuth & Permissions page)",
|
|
347
|
+
secret: true,
|
|
348
|
+
envVar: "SLACK_BOT_TOKEN",
|
|
349
|
+
docsUrl: "https://api.slack.com/authentication/token-types#bot",
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
key: "appToken",
|
|
353
|
+
prompt: "Slack app-level token (xapp-…, for Socket Mode — Basic Information → App-Level Tokens)",
|
|
354
|
+
secret: true,
|
|
355
|
+
envVar: "SLACK_APP_TOKEN",
|
|
356
|
+
docsUrl: "https://api.slack.com/apis/connections/socket#token",
|
|
357
|
+
},
|
|
358
|
+
],
|
|
359
|
+
validateInput(key, value) {
|
|
360
|
+
const v = value.trim();
|
|
361
|
+
// Allow a `${VAR}` ref through (resolved at runtime).
|
|
362
|
+
if (/^\$\{[A-Z_][A-Z0-9_]*\}$/.test(v))
|
|
363
|
+
return null;
|
|
364
|
+
if (key === "botToken") {
|
|
365
|
+
if (/^xoxb-[A-Za-z0-9-]{10,}$/.test(v))
|
|
366
|
+
return null;
|
|
367
|
+
return "That doesn't look like a bot token — expected `xoxb-…` from the app's OAuth page.";
|
|
368
|
+
}
|
|
369
|
+
if (key === "appToken") {
|
|
370
|
+
if (/^xapp-[A-Za-z0-9-]{10,}$/.test(v))
|
|
371
|
+
return null;
|
|
372
|
+
return "That doesn't look like an app-level token — expected `xapp-…` for Socket Mode.";
|
|
373
|
+
}
|
|
374
|
+
return null;
|
|
375
|
+
},
|
|
376
|
+
},
|
|
377
|
+
async sendMedia(conversationId, media) {
|
|
378
|
+
if (!connection)
|
|
379
|
+
throw new Error("Slack channel is not started");
|
|
380
|
+
await connection.sendMedia(conversationId, media);
|
|
381
|
+
},
|
|
382
|
+
async react(conversationId, messageId, emoji) {
|
|
383
|
+
if (!connection)
|
|
384
|
+
return; // cosmetic — refuse silently when not started
|
|
385
|
+
await connection.react(conversationId, messageId, emoji);
|
|
386
|
+
},
|
|
387
|
+
async setComposing(conversationId, state) {
|
|
388
|
+
if (!connection)
|
|
389
|
+
return;
|
|
390
|
+
await connection.setComposing(conversationId, state);
|
|
391
|
+
},
|
|
392
|
+
// Static capability flags. The central `message_action` tool PRE-CHECKS the
|
|
393
|
+
// relevant flag here before calling `handleAction`, so an unsupported action
|
|
394
|
+
// fails cleanly without touching the adapter. Slack supports edit
|
|
395
|
+
// (chat.update), unsend (chat.delete), reactions (reactions.add/remove),
|
|
396
|
+
// reply (thread_ts), threads, and media (files.uploadV2).
|
|
397
|
+
capabilities: SLACK_CAPABILITIES,
|
|
398
|
+
// Native Block Kit button approvals. When a channel-routed turn raises an
|
|
399
|
+
// approval, the central router calls `sendApprovalPrompt` to render the
|
|
400
|
+
// question as buttons (payloads from the central codec); the press comes
|
|
401
|
+
// back as `InboundMessage.callbackQuery` and is resolved centrally. A
|
|
402
|
+
// pathological approval id that can't be encoded falls back to the text
|
|
403
|
+
// prompt (the router sends text when this throws).
|
|
404
|
+
approvalCapability: {
|
|
405
|
+
async sendApprovalPrompt(params) {
|
|
406
|
+
if (!connection)
|
|
407
|
+
throw new Error("Slack channel is not started");
|
|
408
|
+
const message = buildSlackApprovalMessage({
|
|
409
|
+
approvalId: params.approvalId,
|
|
410
|
+
command: params.command,
|
|
411
|
+
approvalKind: params.approvalKind,
|
|
412
|
+
...(params.toolName !== undefined ? { toolName: params.toolName } : {}),
|
|
413
|
+
});
|
|
414
|
+
if (!message) {
|
|
415
|
+
// Couldn't build byte-safe buttons — let the router fall back to text.
|
|
416
|
+
throw new Error("slack approval prompt: approval id too long for buttons");
|
|
417
|
+
}
|
|
418
|
+
// Send the fallback text + Block Kit blocks via the interactive path.
|
|
419
|
+
await connection.sendInteractive(params.conversationId, message.text, message.blocks, {
|
|
420
|
+
...(params.threadId !== undefined ? { threadId: params.threadId } : {}),
|
|
421
|
+
});
|
|
422
|
+
},
|
|
423
|
+
authorizeApprover(p) {
|
|
424
|
+
return resolveSlackApprover({
|
|
425
|
+
cfg: p.cfg,
|
|
426
|
+
...(p.senderId !== undefined ? { senderId: p.senderId } : {}),
|
|
427
|
+
...(p.accountId !== undefined ? { accountId: p.accountId } : {}),
|
|
428
|
+
});
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
// Edit / delete / react / reply a message + attach buttons. The manager
|
|
432
|
+
// pre-checks the capability flag (above) before calling, so an action only
|
|
433
|
+
// reaches here when Slack advertised support for it.
|
|
434
|
+
async handleAction(p) {
|
|
435
|
+
if (!connection)
|
|
436
|
+
return { ok: false, error: "Slack channel is not started" };
|
|
437
|
+
if (tokenInvalid || connection.isTokenInvalid()) {
|
|
438
|
+
return { ok: false, error: "Slack token is invalid — re-token before acting on messages." };
|
|
439
|
+
}
|
|
440
|
+
const a = p.action;
|
|
441
|
+
try {
|
|
442
|
+
switch (a.kind) {
|
|
443
|
+
case "edit": {
|
|
444
|
+
// Run the new text through the Slack mrkdwn formatter (same as the
|
|
445
|
+
// reply path); fall back to the raw text when it renders empty.
|
|
446
|
+
const mrkdwn = markdownToSlackMrkdwn(a.text);
|
|
447
|
+
const body = slackMrkdwnIsEmpty(mrkdwn) ? a.text : mrkdwn;
|
|
448
|
+
await connection.editMessageText(p.conversationId, a.messageId, body);
|
|
449
|
+
return { ok: true, messageId: a.messageId };
|
|
450
|
+
}
|
|
451
|
+
case "delete":
|
|
452
|
+
await connection.deleteMessage(p.conversationId, a.messageId);
|
|
453
|
+
return { ok: true, messageId: a.messageId };
|
|
454
|
+
case "react":
|
|
455
|
+
// An EMPTY emoji means "clear" (parity with WhatsApp/Telegram). Slack
|
|
456
|
+
// has no blanket clear + multiple reactions per message, so clear =
|
|
457
|
+
// remove the bot's OWN reactions on this message; a non-empty emoji
|
|
458
|
+
// adds as before.
|
|
459
|
+
if (a.emoji.trim() === "") {
|
|
460
|
+
await connection.removeOwnReactions(p.conversationId, a.messageId);
|
|
461
|
+
}
|
|
462
|
+
else {
|
|
463
|
+
await connection.react(p.conversationId, a.messageId, a.emoji);
|
|
464
|
+
}
|
|
465
|
+
return { ok: true, messageId: a.messageId };
|
|
466
|
+
case "reply": {
|
|
467
|
+
// A reply is just a threaded send; surface the new id.
|
|
468
|
+
const sent = await connection.sendText(p.conversationId, a.text, {
|
|
469
|
+
...(a.threadId !== undefined ? { threadId: a.threadId } : {}),
|
|
470
|
+
});
|
|
471
|
+
return { ok: true, messageId: sent.messageId };
|
|
472
|
+
}
|
|
473
|
+
case "buttons": {
|
|
474
|
+
// Send a NEW message with a general Block Kit keyboard. The button
|
|
475
|
+
// values are prefixed/sanitized by the builder; a press arrives as
|
|
476
|
+
// `callbackQuery` and routes through the pipeline as a turn (the
|
|
477
|
+
// central approval path declines a general payload).
|
|
478
|
+
const blocks = buildSlackInlineKeyboard(a.buttons.map((row) => row.map((b) => ({ text: b.text, data: b.data }))));
|
|
479
|
+
if (!blocks) {
|
|
480
|
+
return { ok: false, error: "no usable buttons (each needs a label + a data token ≤ 255 chars)" };
|
|
481
|
+
}
|
|
482
|
+
// Render the body to mrkdwn like the reply path; the interactive send
|
|
483
|
+
// is verbatim, so format here.
|
|
484
|
+
const mrkdwn = markdownToSlackMrkdwn(a.text);
|
|
485
|
+
const body = slackMrkdwnIsEmpty(mrkdwn) ? a.text : mrkdwn;
|
|
486
|
+
const sent = await connection.sendInteractive(p.conversationId, body, blocks, {
|
|
487
|
+
...(a.threadId !== undefined ? { threadId: a.threadId } : {}),
|
|
488
|
+
});
|
|
489
|
+
return { ok: true, messageId: sent.messageId };
|
|
490
|
+
}
|
|
491
|
+
default:
|
|
492
|
+
return { ok: false, error: `unsupported action kind` };
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
catch (err) {
|
|
496
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
497
|
+
}
|
|
498
|
+
},
|
|
499
|
+
selfId() {
|
|
500
|
+
return connection?.selfId() ?? undefined;
|
|
501
|
+
},
|
|
502
|
+
connectedAt() {
|
|
503
|
+
return connection?.connectedAt() ?? null;
|
|
504
|
+
},
|
|
505
|
+
lastEventAt() {
|
|
506
|
+
return connection?.lastEventAt() ?? null;
|
|
507
|
+
},
|
|
508
|
+
feedWebhookEvent(kind, payload) {
|
|
509
|
+
// Defensive: only dispatch a plausibly-shaped payload object.
|
|
510
|
+
if (!connection || !payload || typeof payload !== "object")
|
|
511
|
+
return;
|
|
512
|
+
connection.feedEvent(kind, payload);
|
|
513
|
+
},
|
|
514
|
+
transportMode() {
|
|
515
|
+
return connection ? connection.mode() : "unstarted";
|
|
516
|
+
},
|
|
517
|
+
};
|
|
518
|
+
return adapter;
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Synthesise the agent-facing note for an inbound reaction. The reaction itself
|
|
522
|
+
* carries no text, so the note ("<who> reacted :emoji: to message <id>") is what
|
|
523
|
+
* the central pipeline routes through dispatchTurn so the agent has context.
|
|
524
|
+
*/
|
|
525
|
+
export function buildReactionNote(emojis, targetMessageId, fromName) {
|
|
526
|
+
const who = fromName?.trim() || "Someone";
|
|
527
|
+
const emoji = emojis.map((e) => `:${e}:`).join(" ");
|
|
528
|
+
return `${who} reacted ${emoji} to message ${targetMessageId}.`;
|
|
529
|
+
}
|
|
530
|
+
/** Static Slack capability flags (shared by the legacy adapter + plugin meta). */
|
|
531
|
+
export const SLACK_CAPABILITIES = {
|
|
532
|
+
chatTypes: ["direct", "group", "thread"],
|
|
533
|
+
reactions: true,
|
|
534
|
+
edit: true,
|
|
535
|
+
unsend: true,
|
|
536
|
+
reply: true,
|
|
537
|
+
threads: true,
|
|
538
|
+
media: true,
|
|
539
|
+
};
|
|
540
|
+
/**
|
|
541
|
+
* Defensive config fallback for a direct `start()` that skipped `isConfigured`
|
|
542
|
+
* (the manager always calls isConfigured first, so this is the rare path).
|
|
543
|
+
*/
|
|
544
|
+
async function loadStartConfig() {
|
|
545
|
+
return loadConfig();
|
|
546
|
+
}
|
|
547
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../../src/agents/channels/slack/adapter.ts"],"names":[],"mappings":"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"}
|