@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,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack config-shape helpers (multi-WORKSPACE aware; mirrors Telegram's
|
|
3
|
+
* `account-config.ts`).
|
|
4
|
+
*
|
|
5
|
+
* Slack needs MORE than one secret per workspace, unlike Telegram's single bot
|
|
6
|
+
* token:
|
|
7
|
+
* - `botToken` (`xoxb-…`) — the bot user token; every Web API call uses it.
|
|
8
|
+
* - `appToken` (`xapp-…`) — the app-level token; REQUIRED for Socket Mode
|
|
9
|
+
* (opens the events websocket via
|
|
10
|
+
* `apps.connections.open`).
|
|
11
|
+
* - `signingSecret` — HMAC secret; REQUIRED for Events-API (HTTP)
|
|
12
|
+
* mode to verify Slack's request signature.
|
|
13
|
+
* - `userToken` (`xoxp-…`) — OPTIONAL; user-scoped token for reads that the
|
|
14
|
+
* bot token can't do (e.g. some file fetches).
|
|
15
|
+
*
|
|
16
|
+
* Two config shapes are recognised so the surface lines up with WhatsApp /
|
|
17
|
+
* Telegram:
|
|
18
|
+
*
|
|
19
|
+
* Legacy (single-workspace):
|
|
20
|
+
* channels.slack = { enabled: true, botToken: "xoxb-…", appToken: "xapp-…" }
|
|
21
|
+
*
|
|
22
|
+
* Multi-workspace:
|
|
23
|
+
* channels.slack = {
|
|
24
|
+
* enabled: true,
|
|
25
|
+
* accounts: [
|
|
26
|
+
* { id: "acme", botToken: "xoxb-AAA", appToken: "xapp-AAA" },
|
|
27
|
+
* { id: "labs", botToken: "xoxb-BBB", appToken: "xapp-BBB" },
|
|
28
|
+
* ],
|
|
29
|
+
* }
|
|
30
|
+
*
|
|
31
|
+
* A legacy config with no `accounts[]` reads as `[{ id: "default" }]`.
|
|
32
|
+
*
|
|
33
|
+
* Token resolution mirrors Telegram: a `${VAR}` ref expands against
|
|
34
|
+
* `process.env`; otherwise the literal passes through; then — for the bot token
|
|
35
|
+
* only — a DURABLE sealed token (written by `connect_channel`) is consulted so
|
|
36
|
+
* the channel survives a reboot; finally a per-secret env var is the last-resort
|
|
37
|
+
* fallback.
|
|
38
|
+
*
|
|
39
|
+
* Honesty note on sealing: `connect_channel` seals exactly ONE secret per
|
|
40
|
+
* channel, under `channel:slack` — that is the BOT token. The app-level token
|
|
41
|
+
* and signing secret are NOT durably sealed today; they must come from config
|
|
42
|
+
* (`${VAR}`/literal) or their per-secret env var (`SLACK_APP_TOKEN` /
|
|
43
|
+
* `SLACK_SIGNING_SECRET`). If a future `connect_channel` learns to seal those
|
|
44
|
+
* under `channel:slack:app` / `channel:slack:signing`, wire the sealed-read
|
|
45
|
+
* fallback back into `resolveSlackAppToken` / `resolveSlackSigningSecret`.
|
|
46
|
+
*/
|
|
47
|
+
import type { BrigadeConfig } from "../../../config/io.js";
|
|
48
|
+
declare const CHANNEL_ID = "slack";
|
|
49
|
+
declare const DEFAULT_ACCOUNT_ID = "default";
|
|
50
|
+
/** Per-secret env vars consulted as a last-resort fallback. */
|
|
51
|
+
declare const BOT_TOKEN_ENV_VAR = "SLACK_BOT_TOKEN";
|
|
52
|
+
declare const APP_TOKEN_ENV_VAR = "SLACK_APP_TOKEN";
|
|
53
|
+
declare const SIGNING_SECRET_ENV_VAR = "SLACK_SIGNING_SECRET";
|
|
54
|
+
declare const USER_TOKEN_ENV_VAR = "SLACK_USER_TOKEN";
|
|
55
|
+
/** Resolved per-account info — what the adapter runtime reads. */
|
|
56
|
+
export interface ResolvedSlackAccount {
|
|
57
|
+
accountId: string;
|
|
58
|
+
enabled: boolean;
|
|
59
|
+
/** Bot user token (`xoxb-…`), fully resolved, or `""` when unset. */
|
|
60
|
+
botToken: string;
|
|
61
|
+
/** App-level token (`xapp-…`) for Socket Mode, fully resolved, or `""`. */
|
|
62
|
+
appToken: string;
|
|
63
|
+
/** HMAC signing secret for Events-API mode, fully resolved, or `""`. */
|
|
64
|
+
signingSecret: string;
|
|
65
|
+
/** Optional user token (`xoxp-…`) for user-scoped reads, or `""`. */
|
|
66
|
+
userToken: string;
|
|
67
|
+
/**
|
|
68
|
+
* Proxy URL all Slack API calls + the Socket Mode websocket route through,
|
|
69
|
+
* fully resolved (`${VAR}` + env fallback applied), or `""` for a direct
|
|
70
|
+
* connection (the default).
|
|
71
|
+
*/
|
|
72
|
+
proxyUrl: string;
|
|
73
|
+
verbose: boolean;
|
|
74
|
+
}
|
|
75
|
+
/** Is the Slack channel switched on at all (any shape)? */
|
|
76
|
+
export declare function slackChannelEnabled(cfg: BrigadeConfig): boolean;
|
|
77
|
+
/** List configured account ids. Legacy single-account configs surface `["default"]`. */
|
|
78
|
+
export declare function listSlackAccountIds(cfg: BrigadeConfig): string[];
|
|
79
|
+
/** Resolve the bot user token (`xoxb-…`) for an account. */
|
|
80
|
+
export declare function resolveSlackBotToken(cfg: BrigadeConfig, accountId?: string | null, env?: NodeJS.ProcessEnv): string;
|
|
81
|
+
/**
|
|
82
|
+
* Resolve the app-level token (`xapp-…`, Socket Mode) for an account. NOT sealed
|
|
83
|
+
* by `connect_channel` today (sealKey `null`) — comes from config or
|
|
84
|
+
* `SLACK_APP_TOKEN`.
|
|
85
|
+
*/
|
|
86
|
+
export declare function resolveSlackAppToken(cfg: BrigadeConfig, accountId?: string | null, env?: NodeJS.ProcessEnv): string;
|
|
87
|
+
/**
|
|
88
|
+
* Resolve the HMAC signing secret (Events-API mode) for an account. NOT sealed
|
|
89
|
+
* by `connect_channel` today (sealKey `null`) — comes from config or
|
|
90
|
+
* `SLACK_SIGNING_SECRET`.
|
|
91
|
+
*/
|
|
92
|
+
export declare function resolveSlackSigningSecret(cfg: BrigadeConfig, accountId?: string | null, env?: NodeJS.ProcessEnv): string;
|
|
93
|
+
/** Resolve the optional user token (`xoxp-…`) for an account. */
|
|
94
|
+
export declare function resolveSlackUserToken(cfg: BrigadeConfig, accountId?: string | null, env?: NodeJS.ProcessEnv): string;
|
|
95
|
+
/**
|
|
96
|
+
* Resolve the proxy URL all Slack API calls (+ the Socket Mode websocket) should
|
|
97
|
+
* route through. Precedence (mirrors Telegram's `resolveTelegramProxyUrl`):
|
|
98
|
+
* 1. The per-account `accounts[].proxy` (multi-workspace shape), `${VAR}`-resolved.
|
|
99
|
+
* 2. The top-level `channels.slack.proxy`, `${VAR}`-resolved.
|
|
100
|
+
* 3. The first set standard proxy env var (`https_proxy` / `HTTPS_PROXY` /
|
|
101
|
+
* `all_proxy` / `ALL_PROXY`) — last-resort fallback.
|
|
102
|
+
* Returns `""` when none is configured → a DIRECT connection (the default,
|
|
103
|
+
* byte-unchanged from before proxy support existed).
|
|
104
|
+
*
|
|
105
|
+
* `${VAR}` refs are resolved here the same way `botToken` is, so an operator can
|
|
106
|
+
* keep the proxy (which may carry `user:pass@` creds) out of the committed
|
|
107
|
+
* config as `channels.slack.proxy: "${SLACK_PROXY}"`.
|
|
108
|
+
*/
|
|
109
|
+
export declare function resolveSlackProxyUrl(cfg: BrigadeConfig, accountId?: string | null, env?: NodeJS.ProcessEnv): string;
|
|
110
|
+
/**
|
|
111
|
+
* Mask a proxy URL down to `scheme://host:port` (creds + path dropped) so it is
|
|
112
|
+
* safe to log. A malformed URL is reduced to its scheme only; an empty input
|
|
113
|
+
* returns "". NEVER log a raw proxy URL — it may embed `user:pass@`.
|
|
114
|
+
*/
|
|
115
|
+
export declare function maskProxyUrl(proxyUrl: string): string;
|
|
116
|
+
/** Resolve a per-account view of the config (defaults + token resolution filled in). */
|
|
117
|
+
export declare function resolveSlackAccount(cfg: BrigadeConfig, accountId?: string | null, env?: NodeJS.ProcessEnv): ResolvedSlackAccount;
|
|
118
|
+
/** Resolved Slack transport config (mode + events-API details). */
|
|
119
|
+
export interface SlackEventsConfig {
|
|
120
|
+
/** `"socket"` (default) or `"events"`. */
|
|
121
|
+
mode: "socket" | "events";
|
|
122
|
+
/** Public base URL Slack POSTs to (events mode). `""` when unset. */
|
|
123
|
+
url: string;
|
|
124
|
+
/** Gateway route path (default `/slack/events`). */
|
|
125
|
+
path: string;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Resolve the Slack transport config. Defaults to `socket` (Brigade is
|
|
129
|
+
* local-first and Socket Mode needs no public URL); `events` is opt-in via
|
|
130
|
+
* `channels.slack.mode: "events"`.
|
|
131
|
+
*/
|
|
132
|
+
export declare function slackEventsConfig(cfg: BrigadeConfig): SlackEventsConfig;
|
|
133
|
+
/**
|
|
134
|
+
* Resolve the events-mode gateway route path for ONE account. Multi-workspace
|
|
135
|
+
* installs need a DISTINCT path per workspace (Slack POSTs to a per-app URL, and
|
|
136
|
+
* the gateway routes by exact path):
|
|
137
|
+
*
|
|
138
|
+
* - default account → the configured base events path (`channels.slack.events.
|
|
139
|
+
* path`, default `/slack/events`) — byte-identical to the single-workspace
|
|
140
|
+
* path so an existing default-only install is unchanged.
|
|
141
|
+
* - a named account → its explicit `accounts[].webhookPath` when set
|
|
142
|
+
* (`${VAR}`-resolved), else the derived `${basePath}/<accountId>` so two
|
|
143
|
+
* workspaces can't collide on one route.
|
|
144
|
+
*
|
|
145
|
+
* The base path is read from `slackEventsConfig`, so a custom
|
|
146
|
+
* `channels.slack.events.path` propagates to every derived per-account path.
|
|
147
|
+
*/
|
|
148
|
+
export declare function resolveSlackEventsPath(cfg: BrigadeConfig, accountId?: string | null, env?: NodeJS.ProcessEnv): string;
|
|
149
|
+
/**
|
|
150
|
+
* True when live reply-streaming is enabled (`channels.slack.liveStream`).
|
|
151
|
+
* Default OFF — the adapter delivers one final chunked message.
|
|
152
|
+
*/
|
|
153
|
+
export declare function slackLiveStreamEnabled(cfg: BrigadeConfig): boolean;
|
|
154
|
+
/**
|
|
155
|
+
* Resolve the streaming edit throttle in ms. Reads
|
|
156
|
+
* `channels.slack.streamThrottleMs`; falls back to 1000ms (floored at 250ms by
|
|
157
|
+
* the draft-stream).
|
|
158
|
+
*/
|
|
159
|
+
export declare function slackStreamThrottleMs(cfg: BrigadeConfig): number;
|
|
160
|
+
/**
|
|
161
|
+
* True when reasoning surfacing is enabled (`channels.slack.surfaceReasoning`).
|
|
162
|
+
* Default OFF — `<think>` reasoning is stripped from channel replies as today.
|
|
163
|
+
*/
|
|
164
|
+
export declare function slackSurfaceReasoning(cfg: BrigadeConfig): boolean;
|
|
165
|
+
/**
|
|
166
|
+
* Resolve the idle-thread-session TTL in ms, or `null` when unset / disabled.
|
|
167
|
+
* Accepts a number (ms) or a duration string (`"6h"`, `"30m"`, …). The cron
|
|
168
|
+
* session-reaper uses this to age out idle Slack thread sessions.
|
|
169
|
+
*/
|
|
170
|
+
export declare function slackThreadIdleTtlMs(cfg: BrigadeConfig): number | null;
|
|
171
|
+
export { CHANNEL_ID as SLACK_CHANNEL_ID, DEFAULT_ACCOUNT_ID as SLACK_DEFAULT_ACCOUNT_ID, BOT_TOKEN_ENV_VAR as SLACK_BOT_TOKEN_ENV_VAR, APP_TOKEN_ENV_VAR as SLACK_APP_TOKEN_ENV_VAR, SIGNING_SECRET_ENV_VAR as SLACK_SIGNING_SECRET_ENV_VAR, USER_TOKEN_ENV_VAR as SLACK_USER_TOKEN_ENV_VAR, };
|
|
172
|
+
//# sourceMappingURL=account-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-config.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/slack/account-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack config-shape helpers (multi-WORKSPACE aware; mirrors Telegram's
|
|
3
|
+
* `account-config.ts`).
|
|
4
|
+
*
|
|
5
|
+
* Slack needs MORE than one secret per workspace, unlike Telegram's single bot
|
|
6
|
+
* token:
|
|
7
|
+
* - `botToken` (`xoxb-…`) — the bot user token; every Web API call uses it.
|
|
8
|
+
* - `appToken` (`xapp-…`) — the app-level token; REQUIRED for Socket Mode
|
|
9
|
+
* (opens the events websocket via
|
|
10
|
+
* `apps.connections.open`).
|
|
11
|
+
* - `signingSecret` — HMAC secret; REQUIRED for Events-API (HTTP)
|
|
12
|
+
* mode to verify Slack's request signature.
|
|
13
|
+
* - `userToken` (`xoxp-…`) — OPTIONAL; user-scoped token for reads that the
|
|
14
|
+
* bot token can't do (e.g. some file fetches).
|
|
15
|
+
*
|
|
16
|
+
* Two config shapes are recognised so the surface lines up with WhatsApp /
|
|
17
|
+
* Telegram:
|
|
18
|
+
*
|
|
19
|
+
* Legacy (single-workspace):
|
|
20
|
+
* channels.slack = { enabled: true, botToken: "xoxb-…", appToken: "xapp-…" }
|
|
21
|
+
*
|
|
22
|
+
* Multi-workspace:
|
|
23
|
+
* channels.slack = {
|
|
24
|
+
* enabled: true,
|
|
25
|
+
* accounts: [
|
|
26
|
+
* { id: "acme", botToken: "xoxb-AAA", appToken: "xapp-AAA" },
|
|
27
|
+
* { id: "labs", botToken: "xoxb-BBB", appToken: "xapp-BBB" },
|
|
28
|
+
* ],
|
|
29
|
+
* }
|
|
30
|
+
*
|
|
31
|
+
* A legacy config with no `accounts[]` reads as `[{ id: "default" }]`.
|
|
32
|
+
*
|
|
33
|
+
* Token resolution mirrors Telegram: a `${VAR}` ref expands against
|
|
34
|
+
* `process.env`; otherwise the literal passes through; then — for the bot token
|
|
35
|
+
* only — a DURABLE sealed token (written by `connect_channel`) is consulted so
|
|
36
|
+
* the channel survives a reboot; finally a per-secret env var is the last-resort
|
|
37
|
+
* fallback.
|
|
38
|
+
*
|
|
39
|
+
* Honesty note on sealing: `connect_channel` seals exactly ONE secret per
|
|
40
|
+
* channel, under `channel:slack` — that is the BOT token. The app-level token
|
|
41
|
+
* and signing secret are NOT durably sealed today; they must come from config
|
|
42
|
+
* (`${VAR}`/literal) or their per-secret env var (`SLACK_APP_TOKEN` /
|
|
43
|
+
* `SLACK_SIGNING_SECRET`). If a future `connect_channel` learns to seal those
|
|
44
|
+
* under `channel:slack:app` / `channel:slack:signing`, wire the sealed-read
|
|
45
|
+
* fallback back into `resolveSlackAppToken` / `resolveSlackSigningSecret`.
|
|
46
|
+
*/
|
|
47
|
+
import { readSealedChannelToken } from "../channel-secrets.js";
|
|
48
|
+
const CHANNEL_ID = "slack";
|
|
49
|
+
const DEFAULT_ACCOUNT_ID = "default";
|
|
50
|
+
/** Per-secret env vars consulted as a last-resort fallback. */
|
|
51
|
+
const BOT_TOKEN_ENV_VAR = "SLACK_BOT_TOKEN";
|
|
52
|
+
const APP_TOKEN_ENV_VAR = "SLACK_APP_TOKEN";
|
|
53
|
+
const SIGNING_SECRET_ENV_VAR = "SLACK_SIGNING_SECRET";
|
|
54
|
+
const USER_TOKEN_ENV_VAR = "SLACK_USER_TOKEN";
|
|
55
|
+
/**
|
|
56
|
+
* Standard proxy env vars consulted as a last-resort proxy fallback, in
|
|
57
|
+
* precedence order. Lower-case wins over upper-case (curl/undici convention),
|
|
58
|
+
* and a TLS-oriented `https_proxy` outranks the catch-all `ALL_PROXY`. These
|
|
59
|
+
* mirror the keys undici's own `EnvHttpProxyAgent` honours (same set Telegram
|
|
60
|
+
* uses).
|
|
61
|
+
*/
|
|
62
|
+
const PROXY_ENV_VARS = ["https_proxy", "HTTPS_PROXY", "all_proxy", "ALL_PROXY"];
|
|
63
|
+
/**
|
|
64
|
+
* Sealed-token key for the bot token (`channel:slack`) — the ONLY Slack secret
|
|
65
|
+
* `connect_channel` seals today. The app token + signing secret are not sealed
|
|
66
|
+
* (see the header note), so their resolvers pass `sealKey: null`.
|
|
67
|
+
*/
|
|
68
|
+
const SEAL_KEY_BOT = CHANNEL_ID; // `channel:slack`
|
|
69
|
+
/** `${VAR}` secret-ref form — identical to `config/io.ts`'s SECRET_REF_PATTERN. */
|
|
70
|
+
const SECRET_REF_PATTERN = /^\$\{([A-Z_][A-Z0-9_]*)\}$/;
|
|
71
|
+
/** Default gateway path the Events-API transport registers + Slack POSTs to. */
|
|
72
|
+
const DEFAULT_EVENTS_PATH = "/slack/events";
|
|
73
|
+
/** Read `channels.slack` loosely (schema keeps it open). */
|
|
74
|
+
function slackChannelConfig(cfg) {
|
|
75
|
+
return cfg.channels?.[CHANNEL_ID];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Resolve a single token-ish string: a `${VAR}` ref expands against
|
|
79
|
+
* `process.env`; any other non-empty string passes through verbatim; empty /
|
|
80
|
+
* missing returns "".
|
|
81
|
+
*/
|
|
82
|
+
function resolveTokenRef(raw, env) {
|
|
83
|
+
if (typeof raw !== "string")
|
|
84
|
+
return "";
|
|
85
|
+
const trimmed = raw.trim();
|
|
86
|
+
if (!trimmed)
|
|
87
|
+
return "";
|
|
88
|
+
const m = SECRET_REF_PATTERN.exec(trimmed);
|
|
89
|
+
if (m && m[1])
|
|
90
|
+
return (env[m[1]] ?? "").trim();
|
|
91
|
+
return trimmed;
|
|
92
|
+
}
|
|
93
|
+
/** Is the Slack channel switched on at all (any shape)? */
|
|
94
|
+
export function slackChannelEnabled(cfg) {
|
|
95
|
+
return slackChannelConfig(cfg)?.enabled === true;
|
|
96
|
+
}
|
|
97
|
+
/** List configured account ids. Legacy single-account configs surface `["default"]`. */
|
|
98
|
+
export function listSlackAccountIds(cfg) {
|
|
99
|
+
const slot = slackChannelConfig(cfg);
|
|
100
|
+
if (!slot || slot.enabled !== true)
|
|
101
|
+
return [];
|
|
102
|
+
const accounts = Array.isArray(slot.accounts) ? slot.accounts : undefined;
|
|
103
|
+
if (!accounts || accounts.length === 0)
|
|
104
|
+
return [DEFAULT_ACCOUNT_ID];
|
|
105
|
+
const ids = [];
|
|
106
|
+
const seen = new Set();
|
|
107
|
+
for (const entry of accounts) {
|
|
108
|
+
const id = typeof entry?.id === "string" ? entry.id.trim() : "";
|
|
109
|
+
if (!id || seen.has(id))
|
|
110
|
+
continue;
|
|
111
|
+
seen.add(id);
|
|
112
|
+
ids.push(id);
|
|
113
|
+
}
|
|
114
|
+
// A half-typed `accounts:[]` still degrades to the default account so the
|
|
115
|
+
// channel isn't silently disabled.
|
|
116
|
+
return ids.length === 0 ? [DEFAULT_ACCOUNT_ID] : ids;
|
|
117
|
+
}
|
|
118
|
+
/** Look up the raw account entry from config (or null when missing). */
|
|
119
|
+
function findAccountEntry(cfg, accountId) {
|
|
120
|
+
const slot = slackChannelConfig(cfg);
|
|
121
|
+
if (!slot)
|
|
122
|
+
return null;
|
|
123
|
+
const accounts = Array.isArray(slot.accounts) ? slot.accounts : undefined;
|
|
124
|
+
if (!accounts)
|
|
125
|
+
return null;
|
|
126
|
+
for (const entry of accounts) {
|
|
127
|
+
const id = typeof entry?.id === "string" ? entry.id.trim() : "";
|
|
128
|
+
if (id === accountId)
|
|
129
|
+
return entry;
|
|
130
|
+
}
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Resolve one Slack secret for an account. Precedence (mirrors Telegram's token
|
|
135
|
+
* resolution): per-account config `${VAR}`/literal → top-level config → durable
|
|
136
|
+
* sealed token → per-secret env var. Returns `""` when nothing resolves.
|
|
137
|
+
*/
|
|
138
|
+
function resolveSecret(cfg, accountId, field, sealKey, envVar, env) {
|
|
139
|
+
const id = accountId?.trim() || DEFAULT_ACCOUNT_ID;
|
|
140
|
+
const slot = slackChannelConfig(cfg);
|
|
141
|
+
const entry = findAccountEntry(cfg, id);
|
|
142
|
+
const perAccount = resolveTokenRef(entry?.[field], env);
|
|
143
|
+
if (perAccount)
|
|
144
|
+
return perAccount;
|
|
145
|
+
const topLevel = resolveTokenRef(slot?.[field], env);
|
|
146
|
+
if (topLevel)
|
|
147
|
+
return topLevel;
|
|
148
|
+
if (sealKey) {
|
|
149
|
+
const sealed = readSealedChannelToken(sealKey);
|
|
150
|
+
if (sealed)
|
|
151
|
+
return sealed;
|
|
152
|
+
}
|
|
153
|
+
if (envVar) {
|
|
154
|
+
const fromEnv = (env[envVar] ?? "").trim();
|
|
155
|
+
if (fromEnv)
|
|
156
|
+
return fromEnv;
|
|
157
|
+
}
|
|
158
|
+
return "";
|
|
159
|
+
}
|
|
160
|
+
/** Resolve the bot user token (`xoxb-…`) for an account. */
|
|
161
|
+
export function resolveSlackBotToken(cfg, accountId, env = process.env) {
|
|
162
|
+
return resolveSecret(cfg, accountId, "botToken", SEAL_KEY_BOT, BOT_TOKEN_ENV_VAR, env);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Resolve the app-level token (`xapp-…`, Socket Mode) for an account. NOT sealed
|
|
166
|
+
* by `connect_channel` today (sealKey `null`) — comes from config or
|
|
167
|
+
* `SLACK_APP_TOKEN`.
|
|
168
|
+
*/
|
|
169
|
+
export function resolveSlackAppToken(cfg, accountId, env = process.env) {
|
|
170
|
+
return resolveSecret(cfg, accountId, "appToken", null, APP_TOKEN_ENV_VAR, env);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Resolve the HMAC signing secret (Events-API mode) for an account. NOT sealed
|
|
174
|
+
* by `connect_channel` today (sealKey `null`) — comes from config or
|
|
175
|
+
* `SLACK_SIGNING_SECRET`.
|
|
176
|
+
*/
|
|
177
|
+
export function resolveSlackSigningSecret(cfg, accountId, env = process.env) {
|
|
178
|
+
return resolveSecret(cfg, accountId, "signingSecret", null, SIGNING_SECRET_ENV_VAR, env);
|
|
179
|
+
}
|
|
180
|
+
/** Resolve the optional user token (`xoxp-…`) for an account. */
|
|
181
|
+
export function resolveSlackUserToken(cfg, accountId, env = process.env) {
|
|
182
|
+
return resolveSecret(cfg, accountId, "userToken", null, USER_TOKEN_ENV_VAR, env);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Resolve the proxy URL all Slack API calls (+ the Socket Mode websocket) should
|
|
186
|
+
* route through. Precedence (mirrors Telegram's `resolveTelegramProxyUrl`):
|
|
187
|
+
* 1. The per-account `accounts[].proxy` (multi-workspace shape), `${VAR}`-resolved.
|
|
188
|
+
* 2. The top-level `channels.slack.proxy`, `${VAR}`-resolved.
|
|
189
|
+
* 3. The first set standard proxy env var (`https_proxy` / `HTTPS_PROXY` /
|
|
190
|
+
* `all_proxy` / `ALL_PROXY`) — last-resort fallback.
|
|
191
|
+
* Returns `""` when none is configured → a DIRECT connection (the default,
|
|
192
|
+
* byte-unchanged from before proxy support existed).
|
|
193
|
+
*
|
|
194
|
+
* `${VAR}` refs are resolved here the same way `botToken` is, so an operator can
|
|
195
|
+
* keep the proxy (which may carry `user:pass@` creds) out of the committed
|
|
196
|
+
* config as `channels.slack.proxy: "${SLACK_PROXY}"`.
|
|
197
|
+
*/
|
|
198
|
+
export function resolveSlackProxyUrl(cfg, accountId, env = process.env) {
|
|
199
|
+
const id = accountId?.trim() || DEFAULT_ACCOUNT_ID;
|
|
200
|
+
const slot = slackChannelConfig(cfg);
|
|
201
|
+
const entry = findAccountEntry(cfg, id);
|
|
202
|
+
const perAccount = resolveTokenRef(entry?.proxy, env);
|
|
203
|
+
if (perAccount)
|
|
204
|
+
return perAccount;
|
|
205
|
+
const topLevel = resolveTokenRef(slot?.proxy, env);
|
|
206
|
+
if (topLevel)
|
|
207
|
+
return topLevel;
|
|
208
|
+
for (const key of PROXY_ENV_VARS) {
|
|
209
|
+
const value = (env[key] ?? "").trim();
|
|
210
|
+
if (value)
|
|
211
|
+
return value;
|
|
212
|
+
}
|
|
213
|
+
return "";
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Mask a proxy URL down to `scheme://host:port` (creds + path dropped) so it is
|
|
217
|
+
* safe to log. A malformed URL is reduced to its scheme only; an empty input
|
|
218
|
+
* returns "". NEVER log a raw proxy URL — it may embed `user:pass@`.
|
|
219
|
+
*/
|
|
220
|
+
export function maskProxyUrl(proxyUrl) {
|
|
221
|
+
const raw = (proxyUrl ?? "").trim();
|
|
222
|
+
if (!raw)
|
|
223
|
+
return "";
|
|
224
|
+
try {
|
|
225
|
+
const u = new URL(raw);
|
|
226
|
+
return `${u.protocol}//${u.host}`; // host includes :port; userinfo + path/query dropped
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
const scheme = /^([a-z][a-z0-9+.-]*):\/\//i.exec(raw)?.[1];
|
|
230
|
+
return scheme ? `${scheme}://<masked>` : "<masked>";
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/** Resolve a per-account view of the config (defaults + token resolution filled in). */
|
|
234
|
+
export function resolveSlackAccount(cfg, accountId, env = process.env) {
|
|
235
|
+
const slot = slackChannelConfig(cfg);
|
|
236
|
+
const id = accountId?.trim() || DEFAULT_ACCOUNT_ID;
|
|
237
|
+
const entry = findAccountEntry(cfg, id);
|
|
238
|
+
const enabled = entry?.enabled !== false && slot?.enabled === true;
|
|
239
|
+
return {
|
|
240
|
+
accountId: id,
|
|
241
|
+
enabled,
|
|
242
|
+
botToken: resolveSlackBotToken(cfg, id, env),
|
|
243
|
+
appToken: resolveSlackAppToken(cfg, id, env),
|
|
244
|
+
signingSecret: resolveSlackSigningSecret(cfg, id, env),
|
|
245
|
+
userToken: resolveSlackUserToken(cfg, id, env),
|
|
246
|
+
proxyUrl: resolveSlackProxyUrl(cfg, id, env),
|
|
247
|
+
verbose: slot?.verbose === true,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Resolve the Slack transport config. Defaults to `socket` (Brigade is
|
|
252
|
+
* local-first and Socket Mode needs no public URL); `events` is opt-in via
|
|
253
|
+
* `channels.slack.mode: "events"`.
|
|
254
|
+
*/
|
|
255
|
+
export function slackEventsConfig(cfg) {
|
|
256
|
+
const slot = slackChannelConfig(cfg);
|
|
257
|
+
const rawMode = typeof slot?.mode === "string" ? slot.mode.trim().toLowerCase() : "";
|
|
258
|
+
const mode = rawMode === "events" || rawMode === "http" ? "events" : "socket";
|
|
259
|
+
const ev = slot?.events ?? {};
|
|
260
|
+
const path = typeof ev.path === "string" && ev.path.trim() ? ev.path.trim() : DEFAULT_EVENTS_PATH;
|
|
261
|
+
return {
|
|
262
|
+
mode,
|
|
263
|
+
url: typeof ev.url === "string" ? ev.url.trim() : "",
|
|
264
|
+
path: path.startsWith("/") ? path : `/${path}`,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Normalize a path to a leading-slash, trailing-slash-stripped form so derived
|
|
269
|
+
* per-account paths concatenate cleanly. `"/slack/events/"` → `"/slack/events"`.
|
|
270
|
+
*/
|
|
271
|
+
function normalizeEventsPath(raw) {
|
|
272
|
+
const trimmed = (raw ?? "").trim();
|
|
273
|
+
const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
274
|
+
return withSlash.length > 1 ? withSlash.replace(/\/+$/, "") : withSlash;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Resolve the events-mode gateway route path for ONE account. Multi-workspace
|
|
278
|
+
* installs need a DISTINCT path per workspace (Slack POSTs to a per-app URL, and
|
|
279
|
+
* the gateway routes by exact path):
|
|
280
|
+
*
|
|
281
|
+
* - default account → the configured base events path (`channels.slack.events.
|
|
282
|
+
* path`, default `/slack/events`) — byte-identical to the single-workspace
|
|
283
|
+
* path so an existing default-only install is unchanged.
|
|
284
|
+
* - a named account → its explicit `accounts[].webhookPath` when set
|
|
285
|
+
* (`${VAR}`-resolved), else the derived `${basePath}/<accountId>` so two
|
|
286
|
+
* workspaces can't collide on one route.
|
|
287
|
+
*
|
|
288
|
+
* The base path is read from `slackEventsConfig`, so a custom
|
|
289
|
+
* `channels.slack.events.path` propagates to every derived per-account path.
|
|
290
|
+
*/
|
|
291
|
+
export function resolveSlackEventsPath(cfg, accountId, env = process.env) {
|
|
292
|
+
const id = accountId?.trim() || DEFAULT_ACCOUNT_ID;
|
|
293
|
+
const basePath = normalizeEventsPath(slackEventsConfig(cfg).path);
|
|
294
|
+
if (id === DEFAULT_ACCOUNT_ID)
|
|
295
|
+
return basePath;
|
|
296
|
+
const entry = findAccountEntry(cfg, id);
|
|
297
|
+
const explicit = resolveTokenRef(entry?.webhookPath, env);
|
|
298
|
+
if (explicit)
|
|
299
|
+
return normalizeEventsPath(explicit);
|
|
300
|
+
// Derive a collision-free path from the account id (path-segment-safe slug).
|
|
301
|
+
const slug = id.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || id;
|
|
302
|
+
return `${basePath}/${slug}`;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* True when live reply-streaming is enabled (`channels.slack.liveStream`).
|
|
306
|
+
* Default OFF — the adapter delivers one final chunked message.
|
|
307
|
+
*/
|
|
308
|
+
export function slackLiveStreamEnabled(cfg) {
|
|
309
|
+
return slackChannelConfig(cfg)?.liveStream === true;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Resolve the streaming edit throttle in ms. Reads
|
|
313
|
+
* `channels.slack.streamThrottleMs`; falls back to 1000ms (floored at 250ms by
|
|
314
|
+
* the draft-stream).
|
|
315
|
+
*/
|
|
316
|
+
export function slackStreamThrottleMs(cfg) {
|
|
317
|
+
const raw = slackChannelConfig(cfg)?.streamThrottleMs;
|
|
318
|
+
return typeof raw === "number" && raw > 0 ? raw : 1000;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* True when reasoning surfacing is enabled (`channels.slack.surfaceReasoning`).
|
|
322
|
+
* Default OFF — `<think>` reasoning is stripped from channel replies as today.
|
|
323
|
+
*/
|
|
324
|
+
export function slackSurfaceReasoning(cfg) {
|
|
325
|
+
return slackChannelConfig(cfg)?.surfaceReasoning === true;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Resolve the idle-thread-session TTL in ms, or `null` when unset / disabled.
|
|
329
|
+
* Accepts a number (ms) or a duration string (`"6h"`, `"30m"`, …). The cron
|
|
330
|
+
* session-reaper uses this to age out idle Slack thread sessions.
|
|
331
|
+
*/
|
|
332
|
+
export function slackThreadIdleTtlMs(cfg) {
|
|
333
|
+
const raw = slackChannelConfig(cfg)?.threadIdleTtlMs;
|
|
334
|
+
if (typeof raw === "number")
|
|
335
|
+
return raw > 0 ? raw : null;
|
|
336
|
+
if (typeof raw !== "string")
|
|
337
|
+
return null;
|
|
338
|
+
const trimmed = raw.trim();
|
|
339
|
+
if (!trimmed)
|
|
340
|
+
return null;
|
|
341
|
+
const m = /^(\d+)\s*(s|m|h|d|w)?$/i.exec(trimmed);
|
|
342
|
+
if (!m)
|
|
343
|
+
return null;
|
|
344
|
+
const n = Number(m[1]);
|
|
345
|
+
if (!Number.isFinite(n) || n <= 0)
|
|
346
|
+
return null;
|
|
347
|
+
const unit = (m[2] ?? "ms").toLowerCase();
|
|
348
|
+
const mult = { s: 1_000, m: 60_000, h: 3_600_000, d: 86_400_000, w: 604_800_000, ms: 1 };
|
|
349
|
+
const factor = mult[unit] ?? 1;
|
|
350
|
+
return n * factor;
|
|
351
|
+
}
|
|
352
|
+
export { CHANNEL_ID as SLACK_CHANNEL_ID, DEFAULT_ACCOUNT_ID as SLACK_DEFAULT_ACCOUNT_ID, BOT_TOKEN_ENV_VAR as SLACK_BOT_TOKEN_ENV_VAR, APP_TOKEN_ENV_VAR as SLACK_APP_TOKEN_ENV_VAR, SIGNING_SECRET_ENV_VAR as SLACK_SIGNING_SECRET_ENV_VAR, USER_TOKEN_ENV_VAR as SLACK_USER_TOKEN_ENV_VAR, };
|
|
353
|
+
//# sourceMappingURL=account-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-config.js","sourceRoot":"","sources":["../../../../src/agents/channels/slack/account-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAGH,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,MAAM,UAAU,GAAG,OAAO,CAAC;AAC3B,MAAM,kBAAkB,GAAG,SAAS,CAAC;AAErC,+DAA+D;AAC/D,MAAM,iBAAiB,GAAG,iBAAiB,CAAC;AAC5C,MAAM,iBAAiB,GAAG,iBAAiB,CAAC;AAC5C,MAAM,sBAAsB,GAAG,sBAAsB,CAAC;AACtD,MAAM,kBAAkB,GAAG,kBAAkB,CAAC;AAE9C;;;;;;GAMG;AACH,MAAM,cAAc,GAAG,CAAC,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,CAAU,CAAC;AAEzF;;;;GAIG;AACH,MAAM,YAAY,GAAG,UAAU,CAAC,CAAC,kBAAkB;AAEnD,mFAAmF;AACnF,MAAM,kBAAkB,GAAG,4BAA4B,CAAC;AAExD,gFAAgF;AAChF,MAAM,mBAAmB,GAAG,eAAe,CAAC;AA2F5C,4DAA4D;AAC5D,SAAS,kBAAkB,CAAC,GAAkB;IAC7C,OAAQ,GAA6D,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC,CAAC;AAC9F,CAAC;AAED;;;;GAIG;AACH,SAAS,eAAe,CAAC,GAAuB,EAAE,GAAsB;IACvE,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IACvC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IACxB,MAAM,CAAC,GAAG,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3C,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/C,OAAO,OAAO,CAAC;AAChB,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,mBAAmB,CAAC,GAAkB;IACrD,OAAO,kBAAkB,CAAC,GAAG,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;AAClD,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,mBAAmB,CAAC,GAAkB;IACrD,MAAM,IAAI,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IAC9C,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1E,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACpE,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC9B,MAAM,EAAE,GAAG,OAAO,KAAK,EAAE,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QAClC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACb,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACd,CAAC;IACD,0EAA0E;IAC1E,mCAAmC;IACnC,OAAO,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AACtD,CAAC;AAED,wEAAwE;AACxE,SAAS,gBAAgB,CAAC,GAAkB,EAAE,SAAiB;IAC9D,MAAM,IAAI,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1E,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC9B,MAAM,EAAE,GAAG,OAAO,KAAK,EAAE,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,IAAI,EAAE,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;IACpC,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CACrB,GAAkB,EAClB,SAAoC,EACpC,KAA8D,EAC9D,OAAsB,EACtB,MAAqB,EACrB,GAAsB;IAEtB,MAAM,EAAE,GAAG,SAAS,EAAE,IAAI,EAAE,IAAI,kBAAkB,CAAC;IACnD,MAAM,IAAI,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,gBAAgB,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACxC,MAAM,UAAU,GAAG,eAAe,CAAC,KAAK,EAAE,CAAC,KAAK,CAAuB,EAAE,GAAG,CAAC,CAAC;IAC9E,IAAI,UAAU;QAAE,OAAO,UAAU,CAAC;IAClC,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,EAAE,CAAC,KAAK,CAAuB,EAAE,GAAG,CAAC,CAAC;IAC3E,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,IAAI,OAAO,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,sBAAsB,CAAC,OAAO,CAAC,CAAC;QAC/C,IAAI,MAAM;YAAE,OAAO,MAAM,CAAC;IAC3B,CAAC;IACD,IAAI,MAAM,EAAE,CAAC;QACZ,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3C,IAAI,OAAO;YAAE,OAAO,OAAO,CAAC;IAC7B,CAAC;IACD,OAAO,EAAE,CAAC;AACX,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,oBAAoB,CACnC,GAAkB,EAClB,SAAyB,EACzB,MAAyB,OAAO,CAAC,GAAG;IAEpC,OAAO,aAAa,CAAC,GAAG,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,GAAG,CAAC,CAAC;AACxF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CACnC,GAAkB,EAClB,SAAyB,EACzB,MAAyB,OAAO,CAAC,GAAG;IAEpC,OAAO,aAAa,CAAC,GAAG,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,iBAAiB,EAAE,GAAG,CAAC,CAAC;AAChF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CACxC,GAAkB,EAClB,SAAyB,EACzB,MAAyB,OAAO,CAAC,GAAG;IAEpC,OAAO,aAAa,CAAC,GAAG,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,sBAAsB,EAAE,GAAG,CAAC,CAAC;AAC1F,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,qBAAqB,CACpC,GAAkB,EAClB,SAAyB,EACzB,MAAyB,OAAO,CAAC,GAAG;IAEpC,OAAO,aAAa,CAAC,GAAG,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,kBAAkB,EAAE,GAAG,CAAC,CAAC;AAClF,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,oBAAoB,CACnC,GAAkB,EAClB,SAAyB,EACzB,MAAyB,OAAO,CAAC,GAAG;IAEpC,MAAM,EAAE,GAAG,SAAS,EAAE,IAAI,EAAE,IAAI,kBAAkB,CAAC;IACnD,MAAM,IAAI,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,gBAAgB,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACxC,MAAM,UAAU,GAAG,eAAe,CAAC,KAAK,EAAE,KAA2B,EAAE,GAAG,CAAC,CAAC;IAC5E,IAAI,UAAU;QAAE,OAAO,UAAU,CAAC;IAClC,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,EAAE,KAA2B,EAAE,GAAG,CAAC,CAAC;IACzE,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,KAAK,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACtC,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;IACzB,CAAC;IACD,OAAO,EAAE,CAAC;AACX,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC5C,MAAM,GAAG,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACpC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,IAAI,CAAC;QACJ,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,OAAO,GAAG,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,qDAAqD;IACzF,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,MAAM,GAAG,4BAA4B,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC3D,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC;IACrD,CAAC;AACF,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,mBAAmB,CAClC,GAAkB,EAClB,SAAyB,EACzB,MAAyB,OAAO,CAAC,GAAG;IAEpC,MAAM,IAAI,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACrC,MAAM,EAAE,GAAG,SAAS,EAAE,IAAI,EAAE,IAAI,kBAAkB,CAAC;IACnD,MAAM,KAAK,GAAG,gBAAgB,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,KAAK,EAAE,OAAO,KAAK,KAAK,IAAI,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACnE,OAAO;QACN,SAAS,EAAE,EAAE;QACb,OAAO;QACP,QAAQ,EAAE,oBAAoB,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;QAC5C,QAAQ,EAAE,oBAAoB,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;QAC5C,aAAa,EAAE,yBAAyB,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;QACtD,SAAS,EAAE,qBAAqB,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;QAC9C,QAAQ,EAAE,oBAAoB,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;QAC5C,OAAO,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI;KAC/B,CAAC;AACH,CAAC;AAcD;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAkB;IACnD,MAAM,IAAI,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACrC,MAAM,OAAO,GAAG,OAAO,IAAI,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACrF,MAAM,IAAI,GAAwB,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;IACnG,MAAM,EAAE,GAAG,IAAI,EAAE,MAAM,IAAI,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC,IAAI,KAAK,QAAQ,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,mBAAmB,CAAC;IAClG,OAAO;QACN,IAAI;QACJ,GAAG,EAAE,OAAO,EAAE,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE;QACpD,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE;KAC9C,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,mBAAmB,CAAC,GAAW;IACvC,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACnC,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC;IACpE,OAAO,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACzE,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,sBAAsB,CACrC,GAAkB,EAClB,SAAyB,EACzB,MAAyB,OAAO,CAAC,GAAG;IAEpC,MAAM,EAAE,GAAG,SAAS,EAAE,IAAI,EAAE,IAAI,kBAAkB,CAAC;IACnD,MAAM,QAAQ,GAAG,mBAAmB,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;IAClE,IAAI,EAAE,KAAK,kBAAkB;QAAE,OAAO,QAAQ,CAAC;IAC/C,MAAM,KAAK,GAAG,gBAAgB,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,EAAE,WAAiC,EAAE,GAAG,CAAC,CAAC;IAChF,IAAI,QAAQ;QAAE,OAAO,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IACnD,6EAA6E;IAC7E,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;IAChF,OAAO,GAAG,QAAQ,IAAI,IAAI,EAAE,CAAC;AAC9B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,GAAkB;IACxD,OAAO,kBAAkB,CAAC,GAAG,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;AACrD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAkB;IACvD,MAAM,GAAG,GAAG,kBAAkB,CAAC,GAAG,CAAC,EAAE,gBAAgB,CAAC;IACtD,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AACxD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAkB;IACvD,OAAO,kBAAkB,CAAC,GAAG,CAAC,EAAE,gBAAgB,KAAK,IAAI,CAAC;AAC3D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAkB;IACtD,MAAM,GAAG,GAAG,kBAAkB,CAAC,GAAG,CAAC,EAAE,eAAe,CAAC;IACrD,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IACzD,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACzC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,MAAM,CAAC,GAAG,yBAAyB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAClD,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACvB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IAC1C,MAAM,IAAI,GAA2B,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;IACjH,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,OAAO,CAAC,GAAG,MAAM,CAAC;AACnB,CAAC;AAED,OAAO,EACN,UAAU,IAAI,gBAAgB,EAC9B,kBAAkB,IAAI,wBAAwB,EAC9C,iBAAiB,IAAI,uBAAuB,EAC5C,iBAAiB,IAAI,uBAAuB,EAC5C,sBAAsB,IAAI,4BAA4B,EACtD,kBAAkB,IAAI,wBAAwB,GAC9C,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-account Slack adapter registry — the cross-module bridge that lets the
|
|
3
|
+
* Events-API webhook routes (registered at module `register()` time in
|
|
4
|
+
* `module.ts`) find the per-account adapters that are STARTED later by
|
|
5
|
+
* `createSlackPlugin` (`plugin.ts`).
|
|
6
|
+
*
|
|
7
|
+
* Why this exists. In multi-workspace events mode each account has its OWN
|
|
8
|
+
* inbound webhook path (`/slack/events/<accountId>`). The gateway only accepts
|
|
9
|
+
* `b.httpRoute(...)` registrations during a module's `register()`, but the
|
|
10
|
+
* per-account adapters that those routes must feed are owned by the plugin's
|
|
11
|
+
* `startAccount` lifecycle, which runs AFTER `register()`. So the module
|
|
12
|
+
* registers one route per configured account up front, each route resolving its
|
|
13
|
+
* account's started adapter through THIS registry at request time (a thunk),
|
|
14
|
+
* and the plugin populates the registry on `startAccount` / clears it on
|
|
15
|
+
* `stopAccount`. Same shape + rationale as the channel approval-dispatcher
|
|
16
|
+
* registry (`approval-router.ts`): a process-wide singleton avoids threading the
|
|
17
|
+
* map through the gateway boot, and a single Slack workspace path is unaffected
|
|
18
|
+
* (the legacy single-adapter module owns its own route + adapter directly).
|
|
19
|
+
*
|
|
20
|
+
* Pinned via `resolveGlobalSingleton` so a hot reload / dual-build run shares
|
|
21
|
+
* one map (identical to the approval router).
|
|
22
|
+
*/
|
|
23
|
+
/** The minimal adapter surface a webhook route needs to feed inbound events. */
|
|
24
|
+
export interface SlackAccountSink {
|
|
25
|
+
/** Feed a parsed Slack payload into the started adapter's inbound path. */
|
|
26
|
+
feedWebhookEvent(kind: "event" | "interactive" | "slash", payload: unknown): void;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Register a started per-account adapter so its events-mode webhook route can
|
|
30
|
+
* feed inbound into it. The plugin calls this on `startAccount`. Idempotent —
|
|
31
|
+
* re-registering replaces the previous entry (restart-friendly).
|
|
32
|
+
*/
|
|
33
|
+
export declare function registerSlackAccountSink(accountId: string, sink: SlackAccountSink): void;
|
|
34
|
+
/**
|
|
35
|
+
* Drop a per-account adapter (the plugin calls this on `stopAccount`) so a
|
|
36
|
+
* torn-down workspace's route can't feed a dead adapter.
|
|
37
|
+
*/
|
|
38
|
+
export declare function removeSlackAccountSink(accountId: string): void;
|
|
39
|
+
/** Look up a started per-account adapter (or undefined when not started). */
|
|
40
|
+
export declare function getSlackAccountSink(accountId: string): SlackAccountSink | undefined;
|
|
41
|
+
/** Diagnostic — the account ids with a live sink. */
|
|
42
|
+
export declare function listSlackAccountSinks(): string[];
|
|
43
|
+
/** Test-only — clear every registered sink. */
|
|
44
|
+
export declare function resetSlackAccountSinksForTests(): void;
|
|
45
|
+
//# sourceMappingURL=account-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-registry.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/slack/account-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAKH,gFAAgF;AAChF,MAAM,WAAW,gBAAgB;IAChC,2EAA2E;IAC3E,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,aAAa,GAAG,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CAClF;AAcD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAExF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE9D;AAED,6EAA6E;AAC7E,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAEnF;AAED,qDAAqD;AACrD,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD;AAED,+CAA+C;AAC/C,wBAAgB,8BAA8B,IAAI,IAAI,CAErD"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-account Slack adapter registry — the cross-module bridge that lets the
|
|
3
|
+
* Events-API webhook routes (registered at module `register()` time in
|
|
4
|
+
* `module.ts`) find the per-account adapters that are STARTED later by
|
|
5
|
+
* `createSlackPlugin` (`plugin.ts`).
|
|
6
|
+
*
|
|
7
|
+
* Why this exists. In multi-workspace events mode each account has its OWN
|
|
8
|
+
* inbound webhook path (`/slack/events/<accountId>`). The gateway only accepts
|
|
9
|
+
* `b.httpRoute(...)` registrations during a module's `register()`, but the
|
|
10
|
+
* per-account adapters that those routes must feed are owned by the plugin's
|
|
11
|
+
* `startAccount` lifecycle, which runs AFTER `register()`. So the module
|
|
12
|
+
* registers one route per configured account up front, each route resolving its
|
|
13
|
+
* account's started adapter through THIS registry at request time (a thunk),
|
|
14
|
+
* and the plugin populates the registry on `startAccount` / clears it on
|
|
15
|
+
* `stopAccount`. Same shape + rationale as the channel approval-dispatcher
|
|
16
|
+
* registry (`approval-router.ts`): a process-wide singleton avoids threading the
|
|
17
|
+
* map through the gateway boot, and a single Slack workspace path is unaffected
|
|
18
|
+
* (the legacy single-adapter module owns its own route + adapter directly).
|
|
19
|
+
*
|
|
20
|
+
* Pinned via `resolveGlobalSingleton` so a hot reload / dual-build run shares
|
|
21
|
+
* one map (identical to the approval router).
|
|
22
|
+
*/
|
|
23
|
+
import { resolveGlobalSingleton } from "../../../shared/global-singleton.js";
|
|
24
|
+
import { SLACK_DEFAULT_ACCOUNT_ID } from "./account-config.js";
|
|
25
|
+
const SLACK_ACCOUNT_SINKS_KEY = Symbol.for("brigade.slack.accountSinks");
|
|
26
|
+
/** Keyed by accountId — one started adapter per workspace. */
|
|
27
|
+
const sinks = resolveGlobalSingleton(SLACK_ACCOUNT_SINKS_KEY, () => new Map());
|
|
28
|
+
function normalizeAccountId(accountId) {
|
|
29
|
+
return accountId && accountId.trim() ? accountId.trim() : SLACK_DEFAULT_ACCOUNT_ID;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Register a started per-account adapter so its events-mode webhook route can
|
|
33
|
+
* feed inbound into it. The plugin calls this on `startAccount`. Idempotent —
|
|
34
|
+
* re-registering replaces the previous entry (restart-friendly).
|
|
35
|
+
*/
|
|
36
|
+
export function registerSlackAccountSink(accountId, sink) {
|
|
37
|
+
sinks.set(normalizeAccountId(accountId), sink);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Drop a per-account adapter (the plugin calls this on `stopAccount`) so a
|
|
41
|
+
* torn-down workspace's route can't feed a dead adapter.
|
|
42
|
+
*/
|
|
43
|
+
export function removeSlackAccountSink(accountId) {
|
|
44
|
+
sinks.delete(normalizeAccountId(accountId));
|
|
45
|
+
}
|
|
46
|
+
/** Look up a started per-account adapter (or undefined when not started). */
|
|
47
|
+
export function getSlackAccountSink(accountId) {
|
|
48
|
+
return sinks.get(normalizeAccountId(accountId));
|
|
49
|
+
}
|
|
50
|
+
/** Diagnostic — the account ids with a live sink. */
|
|
51
|
+
export function listSlackAccountSinks() {
|
|
52
|
+
return [...sinks.keys()];
|
|
53
|
+
}
|
|
54
|
+
/** Test-only — clear every registered sink. */
|
|
55
|
+
export function resetSlackAccountSinksForTests() {
|
|
56
|
+
sinks.clear();
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=account-registry.js.map
|