@spinabot/brigade 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/dist/agents/agent-loop.d.ts.map +1 -1
  2. package/dist/agents/agent-loop.js +51 -1
  3. package/dist/agents/agent-loop.js.map +1 -1
  4. package/dist/agents/channels/bundled-channel-metas.d.ts +2 -0
  5. package/dist/agents/channels/bundled-channel-metas.d.ts.map +1 -1
  6. package/dist/agents/channels/bundled-channel-metas.js +11 -0
  7. package/dist/agents/channels/bundled-channel-metas.js.map +1 -1
  8. package/dist/agents/channels/discord/account-config.d.ts +177 -0
  9. package/dist/agents/channels/discord/account-config.d.ts.map +1 -0
  10. package/dist/agents/channels/discord/account-config.js +349 -0
  11. package/dist/agents/channels/discord/account-config.js.map +1 -0
  12. package/dist/agents/channels/discord/adapter.d.ts +79 -0
  13. package/dist/agents/channels/discord/adapter.d.ts.map +1 -0
  14. package/dist/agents/channels/discord/adapter.js +693 -0
  15. package/dist/agents/channels/discord/adapter.js.map +1 -0
  16. package/dist/agents/channels/discord/approval-authorize.d.ts +43 -0
  17. package/dist/agents/channels/discord/approval-authorize.d.ts.map +1 -0
  18. package/dist/agents/channels/discord/approval-authorize.js +71 -0
  19. package/dist/agents/channels/discord/approval-authorize.js.map +1 -0
  20. package/dist/agents/channels/discord/approval-native.d.ts +68 -0
  21. package/dist/agents/channels/discord/approval-native.d.ts.map +1 -0
  22. package/dist/agents/channels/discord/approval-native.js +81 -0
  23. package/dist/agents/channels/discord/approval-native.js.map +1 -0
  24. package/dist/agents/channels/discord/command-menu.d.ts +49 -0
  25. package/dist/agents/channels/discord/command-menu.d.ts.map +1 -0
  26. package/dist/agents/channels/discord/command-menu.js +73 -0
  27. package/dist/agents/channels/discord/command-menu.js.map +1 -0
  28. package/dist/agents/channels/discord/component-blocks.d.ts +108 -0
  29. package/dist/agents/channels/discord/component-blocks.d.ts.map +1 -0
  30. package/dist/agents/channels/discord/component-blocks.js +113 -0
  31. package/dist/agents/channels/discord/component-blocks.js.map +1 -0
  32. package/dist/agents/channels/discord/components.d.ts +175 -0
  33. package/dist/agents/channels/discord/components.d.ts.map +1 -0
  34. package/dist/agents/channels/discord/components.js +220 -0
  35. package/dist/agents/channels/discord/components.js.map +1 -0
  36. package/dist/agents/channels/discord/connection.d.ts +570 -0
  37. package/dist/agents/channels/discord/connection.d.ts.map +1 -0
  38. package/dist/agents/channels/discord/connection.js +1600 -0
  39. package/dist/agents/channels/discord/connection.js.map +1 -0
  40. package/dist/agents/channels/discord/directory-cache.d.ts +47 -0
  41. package/dist/agents/channels/discord/directory-cache.d.ts.map +1 -0
  42. package/dist/agents/channels/discord/directory-cache.js +131 -0
  43. package/dist/agents/channels/discord/directory-cache.js.map +1 -0
  44. package/dist/agents/channels/discord/directory-live.d.ts +61 -0
  45. package/dist/agents/channels/discord/directory-live.d.ts.map +1 -0
  46. package/dist/agents/channels/discord/directory-live.js +140 -0
  47. package/dist/agents/channels/discord/directory-live.js.map +1 -0
  48. package/dist/agents/channels/discord/draft-stream.d.ts +92 -0
  49. package/dist/agents/channels/discord/draft-stream.d.ts.map +1 -0
  50. package/dist/agents/channels/discord/draft-stream.js +213 -0
  51. package/dist/agents/channels/discord/draft-stream.js.map +1 -0
  52. package/dist/agents/channels/discord/format.d.ts +70 -0
  53. package/dist/agents/channels/discord/format.d.ts.map +1 -0
  54. package/dist/agents/channels/discord/format.js +303 -0
  55. package/dist/agents/channels/discord/format.js.map +1 -0
  56. package/dist/agents/channels/discord/guilds.d.ts +25 -0
  57. package/dist/agents/channels/discord/guilds.d.ts.map +1 -0
  58. package/dist/agents/channels/discord/guilds.js +46 -0
  59. package/dist/agents/channels/discord/guilds.js.map +1 -0
  60. package/dist/agents/channels/discord/inbound-extras.d.ts +377 -0
  61. package/dist/agents/channels/discord/inbound-extras.d.ts.map +1 -0
  62. package/dist/agents/channels/discord/inbound-extras.js +589 -0
  63. package/dist/agents/channels/discord/inbound-extras.js.map +1 -0
  64. package/dist/agents/channels/discord/index.d.ts +21 -0
  65. package/dist/agents/channels/discord/index.d.ts.map +1 -0
  66. package/dist/agents/channels/discord/index.js +21 -0
  67. package/dist/agents/channels/discord/index.js.map +1 -0
  68. package/dist/agents/channels/discord/media.d.ts +85 -0
  69. package/dist/agents/channels/discord/media.d.ts.map +1 -0
  70. package/dist/agents/channels/discord/media.js +242 -0
  71. package/dist/agents/channels/discord/media.js.map +1 -0
  72. package/dist/agents/channels/discord/modal-registry.d.ts +89 -0
  73. package/dist/agents/channels/discord/modal-registry.d.ts.map +1 -0
  74. package/dist/agents/channels/discord/modal-registry.js +104 -0
  75. package/dist/agents/channels/discord/modal-registry.js.map +1 -0
  76. package/dist/agents/channels/discord/modals.d.ts +100 -0
  77. package/dist/agents/channels/discord/modals.d.ts.map +1 -0
  78. package/dist/agents/channels/discord/modals.js +124 -0
  79. package/dist/agents/channels/discord/modals.js.map +1 -0
  80. package/dist/agents/channels/discord/module.d.ts +15 -0
  81. package/dist/agents/channels/discord/module.d.ts.map +1 -0
  82. package/dist/agents/channels/discord/module.js +22 -0
  83. package/dist/agents/channels/discord/module.js.map +1 -0
  84. package/dist/agents/channels/discord/permission-audit.d.ts +43 -0
  85. package/dist/agents/channels/discord/permission-audit.d.ts.map +1 -0
  86. package/dist/agents/channels/discord/permission-audit.js +192 -0
  87. package/dist/agents/channels/discord/permission-audit.js.map +1 -0
  88. package/dist/agents/channels/discord/plugin.d.ts +89 -0
  89. package/dist/agents/channels/discord/plugin.d.ts.map +1 -0
  90. package/dist/agents/channels/discord/plugin.js +372 -0
  91. package/dist/agents/channels/discord/plugin.js.map +1 -0
  92. package/dist/agents/channels/discord/probe.d.ts +115 -0
  93. package/dist/agents/channels/discord/probe.d.ts.map +1 -0
  94. package/dist/agents/channels/discord/probe.js +193 -0
  95. package/dist/agents/channels/discord/probe.js.map +1 -0
  96. package/dist/agents/channels/discord/reasoning-lane.d.ts +42 -0
  97. package/dist/agents/channels/discord/reasoning-lane.d.ts.map +1 -0
  98. package/dist/agents/channels/discord/reasoning-lane.js +68 -0
  99. package/dist/agents/channels/discord/reasoning-lane.js.map +1 -0
  100. package/dist/agents/channels/discord/rest-actions.d.ts +346 -0
  101. package/dist/agents/channels/discord/rest-actions.d.ts.map +1 -0
  102. package/dist/agents/channels/discord/rest-actions.js +559 -0
  103. package/dist/agents/channels/discord/rest-actions.js.map +1 -0
  104. package/dist/agents/channels/discord/rest-components.d.ts +122 -0
  105. package/dist/agents/channels/discord/rest-components.d.ts.map +1 -0
  106. package/dist/agents/channels/discord/rest-components.js +243 -0
  107. package/dist/agents/channels/discord/rest-components.js.map +1 -0
  108. package/dist/agents/channels/discord/security-audit.d.ts +29 -0
  109. package/dist/agents/channels/discord/security-audit.d.ts.map +1 -0
  110. package/dist/agents/channels/discord/security-audit.js +94 -0
  111. package/dist/agents/channels/discord/security-audit.js.map +1 -0
  112. package/dist/agents/channels/discord/security-doctor.d.ts +43 -0
  113. package/dist/agents/channels/discord/security-doctor.d.ts.map +1 -0
  114. package/dist/agents/channels/discord/security-doctor.js +83 -0
  115. package/dist/agents/channels/discord/security-doctor.js.map +1 -0
  116. package/dist/agents/channels/discord/status-issues.d.ts +37 -0
  117. package/dist/agents/channels/discord/status-issues.d.ts.map +1 -0
  118. package/dist/agents/channels/discord/status-issues.js +66 -0
  119. package/dist/agents/channels/discord/status-issues.js.map +1 -0
  120. package/dist/agents/channels/discord/subagent-thread-binding-store.d.ts +57 -0
  121. package/dist/agents/channels/discord/subagent-thread-binding-store.d.ts.map +1 -0
  122. package/dist/agents/channels/discord/subagent-thread-binding-store.js +98 -0
  123. package/dist/agents/channels/discord/subagent-thread-binding-store.js.map +1 -0
  124. package/dist/agents/channels/discord/subagent-thread-binding.d.ts +95 -0
  125. package/dist/agents/channels/discord/subagent-thread-binding.d.ts.map +1 -0
  126. package/dist/agents/channels/discord/subagent-thread-binding.js +208 -0
  127. package/dist/agents/channels/discord/subagent-thread-binding.js.map +1 -0
  128. package/dist/agents/channels/discord/system-events.d.ts +31 -0
  129. package/dist/agents/channels/discord/system-events.d.ts.map +1 -0
  130. package/dist/agents/channels/discord/system-events.js +74 -0
  131. package/dist/agents/channels/discord/system-events.js.map +1 -0
  132. package/dist/agents/channels/general-callback.d.ts +12 -0
  133. package/dist/agents/channels/general-callback.d.ts.map +1 -1
  134. package/dist/agents/channels/general-callback.js +18 -0
  135. package/dist/agents/channels/general-callback.js.map +1 -1
  136. package/dist/agents/channels/inbound-pipeline.d.ts.map +1 -1
  137. package/dist/agents/channels/inbound-pipeline.js +70 -10
  138. package/dist/agents/channels/inbound-pipeline.js.map +1 -1
  139. package/dist/agents/channels/sdk.d.ts +2 -0
  140. package/dist/agents/channels/sdk.d.ts.map +1 -1
  141. package/dist/agents/channels/sdk.js +2 -0
  142. package/dist/agents/channels/sdk.js.map +1 -1
  143. package/dist/agents/extensions/modules/index.d.ts.map +1 -1
  144. package/dist/agents/extensions/modules/index.js +5 -0
  145. package/dist/agents/extensions/modules/index.js.map +1 -1
  146. package/dist/agents/extensions/types.d.ts +7 -0
  147. package/dist/agents/extensions/types.d.ts.map +1 -1
  148. package/dist/agents/extensions/types.js.map +1 -1
  149. package/dist/agents/subagent-announce-delivery.d.ts +10 -0
  150. package/dist/agents/subagent-announce-delivery.d.ts.map +1 -1
  151. package/dist/agents/subagent-announce-delivery.js +1 -0
  152. package/dist/agents/subagent-announce-delivery.js.map +1 -1
  153. package/dist/agents/subagent-completion-bridge.d.ts.map +1 -1
  154. package/dist/agents/subagent-completion-bridge.js +81 -0
  155. package/dist/agents/subagent-completion-bridge.js.map +1 -1
  156. package/dist/agents/subagent-spawn.d.ts.map +1 -1
  157. package/dist/agents/subagent-spawn.js +57 -4
  158. package/dist/agents/subagent-spawn.js.map +1 -1
  159. package/dist/agents/tools/cron-tool.d.ts.map +1 -1
  160. package/dist/agents/tools/cron-tool.js +4 -1
  161. package/dist/agents/tools/cron-tool.js.map +1 -1
  162. package/dist/agents/tools/discord-action-tool.d.ts +224 -0
  163. package/dist/agents/tools/discord-action-tool.d.ts.map +1 -0
  164. package/dist/agents/tools/discord-action-tool.js +848 -0
  165. package/dist/agents/tools/discord-action-tool.js.map +1 -0
  166. package/dist/agents/tools/registry.d.ts.map +1 -1
  167. package/dist/agents/tools/registry.js +21 -0
  168. package/dist/agents/tools/registry.js.map +1 -1
  169. package/dist/agents/tools/sessions/index.d.ts +8 -0
  170. package/dist/agents/tools/sessions/index.d.ts.map +1 -1
  171. package/dist/agents/tools/sessions/index.js +15 -3
  172. package/dist/agents/tools/sessions/index.js.map +1 -1
  173. package/dist/buildstamp.json +1 -1
  174. package/dist/cli/commands/channels.d.ts +2 -0
  175. package/dist/cli/commands/channels.d.ts.map +1 -1
  176. package/dist/cli/commands/channels.js +58 -1
  177. package/dist/cli/commands/channels.js.map +1 -1
  178. package/dist/core/auth-bridge.d.ts +1 -0
  179. package/dist/core/auth-bridge.d.ts.map +1 -1
  180. package/dist/core/auth-bridge.js +46 -1
  181. package/dist/core/auth-bridge.js.map +1 -1
  182. package/dist/core/server.d.ts.map +1 -1
  183. package/dist/core/server.js +18 -2
  184. package/dist/core/server.js.map +1 -1
  185. package/dist/cron/isolated-agent/run-executor.d.ts +11 -0
  186. package/dist/cron/isolated-agent/run-executor.d.ts.map +1 -1
  187. package/dist/cron/isolated-agent/run-executor.js +20 -4
  188. package/dist/cron/isolated-agent/run-executor.js.map +1 -1
  189. package/dist/cron/types.d.ts +8 -0
  190. package/dist/cron/types.d.ts.map +1 -1
  191. package/dist/system-prompt/assembler.d.ts.map +1 -1
  192. package/dist/system-prompt/assembler.js +4 -2
  193. package/dist/system-prompt/assembler.js.map +1 -1
  194. package/package.json +2 -1
@@ -0,0 +1,349 @@
1
+ /**
2
+ * Discord config-shape helpers (multi-ACCOUNT aware; mirrors Slack's
3
+ * `account-config.ts`).
4
+ *
5
+ * Discord needs ONE secret per account — the bot token (every Gateway login +
6
+ * REST call uses it). Unlike Slack (bot + app + signing tokens), there is no
7
+ * second credential: the Gateway opens a websocket with the bot token, and the
8
+ * same token drives the REST outbound. So this module is closer to Telegram's
9
+ * single-token shape than Slack's three-token one, but it keeps Slack's
10
+ * multi-account discovery so an operator can run >1 bot at once.
11
+ *
12
+ * Two config shapes are recognised so the surface lines up with WhatsApp /
13
+ * Telegram / Slack:
14
+ *
15
+ * Legacy (single-account):
16
+ * channels.discord = { enabled: true, botToken: "…" }
17
+ *
18
+ * Multi-account:
19
+ * channels.discord = {
20
+ * enabled: true,
21
+ * accounts: [
22
+ * { id: "main", botToken: "…AAA" },
23
+ * { id: "labs", botToken: "…BBB" },
24
+ * ],
25
+ * }
26
+ *
27
+ * A legacy config with no `accounts[]` reads as `[{ id: "default" }]`.
28
+ *
29
+ * Token resolution mirrors Slack/Telegram: a `${VAR}` ref expands against
30
+ * `process.env`; otherwise the literal passes through; then a DURABLE sealed
31
+ * token (written by `connect_channel`) is consulted so the channel survives a
32
+ * reboot; finally the per-secret env var `DISCORD_BOT_TOKEN` is the last-resort
33
+ * fallback. A leading `Bot ` prefix (Discord's REST scheme prefix) is stripped
34
+ * so an operator who pasted the whole `Authorization` header still works.
35
+ */
36
+ import { readSealedChannelToken } from "../channel-secrets.js";
37
+ const CHANNEL_ID = "discord";
38
+ const DEFAULT_ACCOUNT_ID = "default";
39
+ /** Per-secret env var consulted as a last-resort fallback. */
40
+ const BOT_TOKEN_ENV_VAR = "DISCORD_BOT_TOKEN";
41
+ /**
42
+ * Standard proxy env vars consulted as a last-resort proxy fallback, in
43
+ * precedence order. Lower-case wins over upper-case (curl/undici convention),
44
+ * and a TLS-oriented `https_proxy` outranks the catch-all `ALL_PROXY`. Mirrors
45
+ * the keys Slack/Telegram honour.
46
+ */
47
+ const PROXY_ENV_VARS = ["https_proxy", "HTTPS_PROXY", "all_proxy", "ALL_PROXY"];
48
+ /**
49
+ * Sealed-token key for the bot token (`channel:discord`) — the secret
50
+ * `connect_channel` seals. The bot token is the only Discord credential, so it
51
+ * is the one that gets the sealed-read fallback.
52
+ */
53
+ const SEAL_KEY_BOT = CHANNEL_ID; // `channel:discord`
54
+ /** `${VAR}` secret-ref form — identical to `config/io.ts`'s SECRET_REF_PATTERN. */
55
+ const SECRET_REF_PATTERN = /^\$\{([A-Z_][A-Z0-9_]*)\}$/;
56
+ /** discord.js `ActivityType` numeric codes, keyed by the config string. */
57
+ const ACTIVITY_TYPE_CODE = {
58
+ playing: 0,
59
+ streaming: 1,
60
+ listening: 2,
61
+ watching: 3,
62
+ custom: 4,
63
+ competing: 5,
64
+ };
65
+ /** Valid auto-archive durations Discord accepts (minutes). */
66
+ const AUTO_ARCHIVE_DURATIONS = new Set([60, 1440, 4320, 10080]);
67
+ const DEFAULT_AUTO_ARCHIVE_MINUTES = 1440;
68
+ /** Read `channels.discord` loosely (schema keeps it open). */
69
+ function discordChannelConfig(cfg) {
70
+ return cfg.channels?.[CHANNEL_ID];
71
+ }
72
+ /**
73
+ * Resolve a single token-ish string: a `${VAR}` ref expands against
74
+ * `process.env`; any other non-empty string passes through verbatim; empty /
75
+ * missing returns "".
76
+ */
77
+ function resolveTokenRef(raw, env) {
78
+ if (typeof raw !== "string")
79
+ return "";
80
+ const trimmed = raw.trim();
81
+ if (!trimmed)
82
+ return "";
83
+ const m = SECRET_REF_PATTERN.exec(trimmed);
84
+ if (m && m[1])
85
+ return (env[m[1]] ?? "").trim();
86
+ return trimmed;
87
+ }
88
+ /**
89
+ * Strip a leading `Bot ` scheme prefix from a Discord token. Discord's REST
90
+ * `Authorization` header is `Bot <token>`; an operator who pasted the whole
91
+ * header still gets a clean token. Idempotent + case-insensitive.
92
+ */
93
+ export function stripBotPrefix(token) {
94
+ return token.replace(/^Bot\s+/i, "").trim();
95
+ }
96
+ /** Is the Discord channel switched on at all (any shape)? */
97
+ export function discordChannelEnabled(cfg) {
98
+ return discordChannelConfig(cfg)?.enabled === true;
99
+ }
100
+ /** List configured account ids. Legacy single-account configs surface `["default"]`. */
101
+ export function listDiscordAccountIds(cfg) {
102
+ const slot = discordChannelConfig(cfg);
103
+ if (!slot || slot.enabled !== true)
104
+ return [];
105
+ const accounts = Array.isArray(slot.accounts) ? slot.accounts : undefined;
106
+ if (!accounts || accounts.length === 0)
107
+ return [DEFAULT_ACCOUNT_ID];
108
+ const ids = [];
109
+ const seen = new Set();
110
+ for (const entry of accounts) {
111
+ const id = typeof entry?.id === "string" ? entry.id.trim() : "";
112
+ if (!id || seen.has(id))
113
+ continue;
114
+ seen.add(id);
115
+ ids.push(id);
116
+ }
117
+ // A half-typed `accounts:[]` still degrades to the default account so the
118
+ // channel isn't silently disabled.
119
+ return ids.length === 0 ? [DEFAULT_ACCOUNT_ID] : ids;
120
+ }
121
+ /** Look up the raw account entry from config (or null when missing). */
122
+ function findAccountEntry(cfg, accountId) {
123
+ const slot = discordChannelConfig(cfg);
124
+ if (!slot)
125
+ return null;
126
+ const accounts = Array.isArray(slot.accounts) ? slot.accounts : undefined;
127
+ if (!accounts)
128
+ return null;
129
+ for (const entry of accounts) {
130
+ const id = typeof entry?.id === "string" ? entry.id.trim() : "";
131
+ if (id === accountId)
132
+ return entry;
133
+ }
134
+ return null;
135
+ }
136
+ /**
137
+ * Resolve the Discord bot token for an account. Precedence (mirrors Slack's
138
+ * token resolution): per-account config `${VAR}`/literal → top-level config →
139
+ * durable sealed token → per-secret env var. The `Bot ` scheme prefix is
140
+ * stripped from whichever source wins. Returns `""` when nothing resolves.
141
+ */
142
+ export function resolveDiscordBotToken(cfg, accountId, env = process.env) {
143
+ const id = accountId?.trim() || DEFAULT_ACCOUNT_ID;
144
+ const slot = discordChannelConfig(cfg);
145
+ const entry = findAccountEntry(cfg, id);
146
+ const perAccount = resolveTokenRef(entry?.botToken, env);
147
+ if (perAccount)
148
+ return stripBotPrefix(perAccount);
149
+ const topLevel = resolveTokenRef(slot?.botToken, env);
150
+ if (topLevel)
151
+ return stripBotPrefix(topLevel);
152
+ const sealed = readSealedChannelToken(SEAL_KEY_BOT);
153
+ if (sealed)
154
+ return stripBotPrefix(sealed);
155
+ const fromEnv = (env[BOT_TOKEN_ENV_VAR] ?? "").trim();
156
+ if (fromEnv)
157
+ return stripBotPrefix(fromEnv);
158
+ return "";
159
+ }
160
+ /**
161
+ * Resolve the proxy URL all Discord REST calls (+ the Gateway websocket) should
162
+ * route through. Precedence (mirrors Slack's `resolveSlackProxyUrl`):
163
+ * 1. The per-account `accounts[].proxy` (multi-account shape), `${VAR}`-resolved.
164
+ * 2. The top-level `channels.discord.proxy`, `${VAR}`-resolved.
165
+ * 3. The first set standard proxy env var (`https_proxy` / `HTTPS_PROXY` /
166
+ * `all_proxy` / `ALL_PROXY`) — last-resort fallback.
167
+ * Returns `""` when none is configured → a DIRECT connection (the default).
168
+ *
169
+ * `${VAR}` refs are resolved here the same way `botToken` is, so an operator can
170
+ * keep the proxy (which may carry `user:pass@` creds) out of the committed
171
+ * config as `channels.discord.proxy: "${DISCORD_PROXY}"`.
172
+ */
173
+ export function resolveDiscordProxyUrl(cfg, accountId, env = process.env) {
174
+ const id = accountId?.trim() || DEFAULT_ACCOUNT_ID;
175
+ const slot = discordChannelConfig(cfg);
176
+ const entry = findAccountEntry(cfg, id);
177
+ const perAccount = resolveTokenRef(entry?.proxy, env);
178
+ if (perAccount)
179
+ return perAccount;
180
+ const topLevel = resolveTokenRef(slot?.proxy, env);
181
+ if (topLevel)
182
+ return topLevel;
183
+ for (const key of PROXY_ENV_VARS) {
184
+ const value = (env[key] ?? "").trim();
185
+ if (value)
186
+ return value;
187
+ }
188
+ return "";
189
+ }
190
+ /**
191
+ * Mask a proxy URL down to `scheme://host:port` (creds + path dropped) so it is
192
+ * safe to log. A malformed URL is reduced to its scheme only; an empty input
193
+ * returns "". NEVER log a raw proxy URL — it may embed `user:pass@`.
194
+ */
195
+ export function maskProxyUrl(proxyUrl) {
196
+ const raw = (proxyUrl ?? "").trim();
197
+ if (!raw)
198
+ return "";
199
+ try {
200
+ const u = new URL(raw);
201
+ return `${u.protocol}//${u.host}`; // host includes :port; userinfo + path/query dropped
202
+ }
203
+ catch {
204
+ const scheme = /^([a-z][a-z0-9+.-]*):\/\//i.exec(raw)?.[1];
205
+ return scheme ? `${scheme}://<masked>` : "<masked>";
206
+ }
207
+ }
208
+ /** Resolve a per-account view of the config (defaults + token resolution filled in). */
209
+ export function resolveDiscordAccount(cfg, accountId, env = process.env) {
210
+ const slot = discordChannelConfig(cfg);
211
+ const id = accountId?.trim() || DEFAULT_ACCOUNT_ID;
212
+ const entry = findAccountEntry(cfg, id);
213
+ const enabled = entry?.enabled !== false && slot?.enabled === true;
214
+ return {
215
+ accountId: id,
216
+ enabled,
217
+ botToken: resolveDiscordBotToken(cfg, id, env),
218
+ proxyUrl: resolveDiscordProxyUrl(cfg, id, env),
219
+ verbose: slot?.verbose === true,
220
+ };
221
+ }
222
+ /* ───────────────────────── lifecycle / streaming config ───────────────────────── */
223
+ /**
224
+ * True when live reply-streaming is enabled (`channels.discord.liveStream`).
225
+ * Default OFF — the adapter delivers one final chunked message.
226
+ */
227
+ export function discordLiveStreamEnabled(cfg) {
228
+ return discordChannelConfig(cfg)?.liveStream === true;
229
+ }
230
+ /**
231
+ * Resolve the streaming edit throttle in ms. Reads
232
+ * `channels.discord.streamThrottleMs`; falls back to 1000ms (floored at 250ms by
233
+ * the draft-stream).
234
+ */
235
+ export function discordStreamThrottleMs(cfg) {
236
+ const raw = discordChannelConfig(cfg)?.streamThrottleMs;
237
+ return typeof raw === "number" && raw > 0 ? raw : 1000;
238
+ }
239
+ /**
240
+ * True when reasoning surfacing is enabled (`channels.discord.surfaceReasoning`).
241
+ * Default OFF — `<think>` reasoning is stripped from channel replies as today.
242
+ */
243
+ export function discordSurfaceReasoning(cfg) {
244
+ return discordChannelConfig(cfg)?.surfaceReasoning === true;
245
+ }
246
+ /**
247
+ * Resolve the reaction-notification mode (`channels.discord.reactionNotifications`).
248
+ * Defaults to `"own"` (only reactions on the bot's own messages wake the agent) so
249
+ * a stranger's reaction in an admitted channel no longer spams a turn. An invalid /
250
+ * unset value degrades to the `"own"` default.
251
+ */
252
+ export function discordReactionNotifications(cfg) {
253
+ const raw = discordChannelConfig(cfg)?.reactionNotifications;
254
+ if (raw === "off" || raw === "own" || raw === "all" || raw === "allowlist")
255
+ return raw;
256
+ return "own";
257
+ }
258
+ /**
259
+ * Resolve the idle-thread-session TTL in ms, or `null` when unset / disabled.
260
+ * Accepts a number (ms) or a duration string (`"6h"`, `"30m"`, …). The cron
261
+ * session-reaper uses this to age out idle Discord thread sessions.
262
+ */
263
+ export function discordThreadIdleTtlMs(cfg) {
264
+ const raw = discordChannelConfig(cfg)?.threadIdleTtlMs;
265
+ if (typeof raw === "number")
266
+ return raw > 0 ? raw : null;
267
+ if (typeof raw !== "string")
268
+ return null;
269
+ const trimmed = raw.trim();
270
+ if (!trimmed)
271
+ return null;
272
+ const m = /^(\d+)\s*(s|m|h|d|w)?$/i.exec(trimmed);
273
+ if (!m)
274
+ return null;
275
+ const n = Number(m[1]);
276
+ if (!Number.isFinite(n) || n <= 0)
277
+ return null;
278
+ const unit = (m[2] ?? "ms").toLowerCase();
279
+ const mult = { s: 1_000, m: 60_000, h: 3_600_000, d: 86_400_000, w: 604_800_000, ms: 1 };
280
+ const factor = mult[unit] ?? 1;
281
+ return n * factor;
282
+ }
283
+ /* ───────────────────────── presence / auto-thread config ───────────────────────── */
284
+ /**
285
+ * Resolve the bot presence to apply on (re)connect, or `null` when none is
286
+ * configured (`channels.discord.presence` absent / empty → keep Discord's
287
+ * default). A `status`-only block (no activity) still resolves so the operator
288
+ * can set just the online dot. An invalid `status` / `activityType` is dropped
289
+ * (degrades to the default), never throwing. The activity type is mapped to its
290
+ * discord.js `ActivityType` numeric code here so the connection stays
291
+ * discord.js-agnostic.
292
+ *
293
+ * Multi-account aware (mirrors the other per-account resolvers): the per-account
294
+ * `accounts[id].presence` wins, falling back to the top-level
295
+ * `channels.discord.presence`. Without this fallback a per-account
296
+ * `set-presence` write was a silent no-op (it read only the top-level slot).
297
+ */
298
+ export function resolveDiscordPresence(cfg, accountId) {
299
+ const id = accountId?.trim() || DEFAULT_ACCOUNT_ID;
300
+ const entry = findAccountEntry(cfg, id);
301
+ const slot = (entry?.presence && typeof entry.presence === "object" ? entry.presence : undefined) ??
302
+ discordChannelConfig(cfg)?.presence;
303
+ if (!slot || typeof slot !== "object")
304
+ return null;
305
+ const statusRaw = typeof slot.status === "string" ? slot.status.trim().toLowerCase() : "";
306
+ const status = statusRaw === "online" || statusRaw === "idle" || statusRaw === "dnd" || statusRaw === "invisible"
307
+ ? statusRaw
308
+ : "online";
309
+ const activityText = typeof slot.activityText === "string" ? slot.activityText.trim() : "";
310
+ const activityTypeRaw = typeof slot.activityType === "string" ? slot.activityType.trim().toLowerCase() : undefined;
311
+ const activityType = activityTypeRaw && activityTypeRaw in ACTIVITY_TYPE_CODE ? activityTypeRaw : undefined;
312
+ const activityUrl = typeof slot.activityUrl === "string" ? slot.activityUrl.trim() : "";
313
+ // Nothing meaningful configured (no status, no activity) → no presence.
314
+ const hasStatus = statusRaw !== "";
315
+ const hasActivity = activityText !== "" || activityType !== undefined;
316
+ if (!hasStatus && !hasActivity)
317
+ return null;
318
+ const resolved = { status };
319
+ if (hasActivity) {
320
+ // An activity row needs at least a type; default to `custom` (the status
321
+ // STATE line) when only text was given.
322
+ const type = activityType ?? "custom";
323
+ resolved.activityType = type;
324
+ resolved.activityTypeCode = ACTIVITY_TYPE_CODE[type];
325
+ if (activityText)
326
+ resolved.activityText = activityText;
327
+ if (type === "streaming" && activityUrl)
328
+ resolved.activityUrl = activityUrl;
329
+ }
330
+ return resolved;
331
+ }
332
+ /**
333
+ * Resolve the auto-thread policy (`channels.discord.autoThread*`). Returns a
334
+ * resolved view with `enabled` false when the feature is off (the default). The
335
+ * name mode defaults to `"first-message"`; `autoArchiveDuration` is clamped to
336
+ * one of Discord's accepted values (60 / 1440 / 4320 / 10080), defaulting to
337
+ * 1440 (24h).
338
+ */
339
+ export function resolveDiscordAutoThread(cfg) {
340
+ const slot = discordChannelConfig(cfg);
341
+ const enabled = slot?.autoThread === true;
342
+ const nameRaw = typeof slot?.autoThreadName === "string" ? slot.autoThreadName.trim().toLowerCase() : "";
343
+ const nameMode = nameRaw === "generated" ? "generated" : "first-message";
344
+ const rawDuration = typeof slot?.autoArchiveDuration === "number" ? Math.round(slot.autoArchiveDuration) : NaN;
345
+ const autoArchiveMinutes = AUTO_ARCHIVE_DURATIONS.has(rawDuration) ? rawDuration : DEFAULT_AUTO_ARCHIVE_MINUTES;
346
+ return { enabled, nameMode, autoArchiveMinutes };
347
+ }
348
+ export { CHANNEL_ID as DISCORD_CHANNEL_ID, DEFAULT_ACCOUNT_ID as DISCORD_DEFAULT_ACCOUNT_ID, BOT_TOKEN_ENV_VAR as DISCORD_BOT_TOKEN_ENV_VAR, };
349
+ //# sourceMappingURL=account-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-config.js","sourceRoot":"","sources":["../../../../src/agents/channels/discord/account-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Discord channel adapter.
3
+ *
4
+ * Implements the Brigade `ChannelAdapter` contract on top of the discord.js
5
+ * Gateway + REST connection. Like Slack, Discord is TOKEN-based: the operator
6
+ * pastes a bot token from the Discord Developer Portal, so this adapter declares
7
+ * a `setup` wizard (one credential) and has NO QR/link flow. Enablement is
8
+ * explicit — `channels.discord.enabled: true` plus a resolvable bot token.
9
+ *
10
+ * Modeled directly on `slack/adapter.ts`: same health-flag mirroring, same
11
+ * deferred-media passthrough on inbound, same chunk-then-send outbound shape
12
+ * (chunk markdown ≤2000, convert each chunk to Discord markup, send). Discord
13
+ * markup never "fails to parse" the way Telegram HTML can, so the outbound path
14
+ * is simple — an empty rendered chunk falls back to the raw chunk.
15
+ *
16
+ * Capabilities: edit (message.edit), unsend (message.delete), reactions
17
+ * (message.react), reply (reply reference + threads), threads, media
18
+ * (AttachmentBuilder), buttons (ActionRow + Button), and NATIVE slash commands
19
+ * (registered via REST application commands on connect). Unlike Slack, Discord's
20
+ * command menu IS pushed programmatically — `nativeCommands: true`.
21
+ */
22
+ import type { BrigadeConfig } from "../../../config/io.js";
23
+ import { type ChannelAdapter, type ChannelCapabilities } from "../sdk.js";
24
+ import { type ResolvedDiscordPresence } from "./account-config.js";
25
+ import { type ConnectDiscordArgs, type DiscordConnection, type DiscordInboundMessage, type DiscordPresencePayload } from "./connection.js";
26
+ /**
27
+ * Map a resolved presence config into the discord.js `PresenceData` payload the
28
+ * connection applies on (re)connect (Phase 5). A `custom` activity (type 4)
29
+ * carries its text in the `state` field (Discord renders custom status from the
30
+ * state); every other type uses `name`. A `streaming` activity (type 1) adds the
31
+ * `url`. Returns `null` when no presence is configured.
32
+ */
33
+ export declare function mapDiscordPresencePayload(presence: ResolvedDiscordPresence | null): DiscordPresencePayload | null;
34
+ /** Adapter construction options — all optional for back-compat. */
35
+ export interface CreateDiscordAdapterOptions {
36
+ /** Per-account scope. Defaults to `"default"` (single-account). */
37
+ accountId?: string;
38
+ /**
39
+ * TEST SEAM: override how the connection is built. Production leaves this
40
+ * undefined and `connectDiscord` lazy-loads discord.js. Tests inject a fake.
41
+ */
42
+ connectImpl?: (args: ConnectDiscordArgs) => Promise<DiscordConnection>;
43
+ }
44
+ export declare function createDiscordAdapter(opts?: CreateDiscordAdapterOptions): ChannelAdapter;
45
+ /**
46
+ * Decide whether an inbound reaction-add should wake the agent, per the
47
+ * `channels.discord.reactionNotifications` mode (default `"own"`):
48
+ * - `"off"` → never;
49
+ * - `"own"` → only when the reacted message was authored by the bot
50
+ * (`reaction.targetAuthorId === selfId`);
51
+ * - `"all"` → always (legacy behavior);
52
+ * - `"allowlist"` → only when the reactor (`msg.from`) is on the channel
53
+ * allow-list — the central store list ∪ config `allowFrom`.
54
+ * A null config defensively falls back to `"own"`. Reaction-REMOVE is unaffected
55
+ * (handled in the connection's dedupe-release path).
56
+ */
57
+ export declare function shouldNotifyReaction(msg: DiscordInboundMessage, cfg: BrigadeConfig | null, selfId: string | undefined, accountId?: string): boolean;
58
+ /**
59
+ * Synthesise the agent-facing note for an inbound reaction. The reaction itself
60
+ * carries no text, so the note ("<who> reacted :emoji: to message <id>") is what
61
+ * the central pipeline routes through dispatchTurn so the agent has context.
62
+ */
63
+ export declare function buildReactionNote(emojis: string[], targetMessageId: string, fromName?: string): string;
64
+ /** Static Discord capability flags (shared by the legacy adapter + plugin meta). */
65
+ export declare const DISCORD_CAPABILITIES: ChannelCapabilities;
66
+ /**
67
+ * The Discord adapter shape with its liveness extension. `createDiscordAdapter`
68
+ * returns a `ChannelAdapter`, but the concrete object ALSO carries `lastEventAt`
69
+ * (not in the base contract). Callers that need it cast through this type.
70
+ */
71
+ export interface DiscordAdapter extends ChannelAdapter {
72
+ /**
73
+ * Epoch ms of the most recent inbound event (liveness diagnostic), or null
74
+ * before the first event / when not started. Observability only — never flips
75
+ * health to "down" (a quiet channel is legitimately idle).
76
+ */
77
+ lastEventAt(): number | null;
78
+ }
79
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/discord/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAK3D,OAAO,EAGN,KAAK,cAAc,EAEnB,KAAK,mBAAmB,EAQxB,MAAM,WAAW,CAAC;AAEnB,OAAO,EAaN,KAAK,uBAAuB,EAC5B,MAAM,qBAAqB,CAAC;AAK7B,OAAO,EAGN,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,MAAM,iBAAiB,CAAC;AASzB;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,IAAI,GAAG,sBAAsB,GAAG,IAAI,CAiBjH;AAED,mEAAmE;AACnE,MAAM,WAAW,2BAA2B;IAC3C,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACvE;AAED,wBAAgB,oBAAoB,CAAC,IAAI,GAAE,2BAAgC,GAAG,cAAc,CAwiB3F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CACnC,GAAG,EAAE,qBAAqB,EAC1B,GAAG,EAAE,aAAa,GAAG,IAAI,EACzB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,SAAS,CAAC,EAAE,MAAM,GAChB,OAAO,CAsBT;AASD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAKtG;AAED,oFAAoF;AACpF,eAAO,MAAM,oBAAoB,EAAE,mBASlC,CAAC;AAEF;;;;GAIG;AACH,MAAM,WAAW,cAAe,SAAQ,cAAc;IACrD;;;;OAIG;IACH,WAAW,IAAI,MAAM,GAAG,IAAI,CAAC;CAC7B"}