@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.
Files changed (195) 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 +4 -0
  5. package/dist/agents/channels/bundled-channel-metas.d.ts.map +1 -1
  6. package/dist/agents/channels/bundled-channel-metas.js +22 -0
  7. package/dist/agents/channels/bundled-channel-metas.js.map +1 -1
  8. package/dist/agents/channels/discord/account-config.d.ts +117 -0
  9. package/dist/agents/channels/discord/account-config.d.ts.map +1 -0
  10. package/dist/agents/channels/discord/account-config.js +260 -0
  11. package/dist/agents/channels/discord/account-config.js.map +1 -0
  12. package/dist/agents/channels/discord/adapter.d.ts +56 -0
  13. package/dist/agents/channels/discord/adapter.d.ts.map +1 -0
  14. package/dist/agents/channels/discord/adapter.js +526 -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/components.d.ts +97 -0
  29. package/dist/agents/channels/discord/components.d.ts.map +1 -0
  30. package/dist/agents/channels/discord/components.js +131 -0
  31. package/dist/agents/channels/discord/components.js.map +1 -0
  32. package/dist/agents/channels/discord/connection.d.ts +387 -0
  33. package/dist/agents/channels/discord/connection.d.ts.map +1 -0
  34. package/dist/agents/channels/discord/connection.js +786 -0
  35. package/dist/agents/channels/discord/connection.js.map +1 -0
  36. package/dist/agents/channels/discord/draft-stream.d.ts +92 -0
  37. package/dist/agents/channels/discord/draft-stream.d.ts.map +1 -0
  38. package/dist/agents/channels/discord/draft-stream.js +213 -0
  39. package/dist/agents/channels/discord/draft-stream.js.map +1 -0
  40. package/dist/agents/channels/discord/format.d.ts +55 -0
  41. package/dist/agents/channels/discord/format.d.ts.map +1 -0
  42. package/dist/agents/channels/discord/format.js +247 -0
  43. package/dist/agents/channels/discord/format.js.map +1 -0
  44. package/dist/agents/channels/discord/inbound-extras.d.ts +220 -0
  45. package/dist/agents/channels/discord/inbound-extras.d.ts.map +1 -0
  46. package/dist/agents/channels/discord/inbound-extras.js +351 -0
  47. package/dist/agents/channels/discord/inbound-extras.js.map +1 -0
  48. package/dist/agents/channels/discord/index.d.ts +14 -0
  49. package/dist/agents/channels/discord/index.d.ts.map +1 -0
  50. package/dist/agents/channels/discord/index.js +14 -0
  51. package/dist/agents/channels/discord/index.js.map +1 -0
  52. package/dist/agents/channels/discord/media.d.ts +85 -0
  53. package/dist/agents/channels/discord/media.d.ts.map +1 -0
  54. package/dist/agents/channels/discord/media.js +242 -0
  55. package/dist/agents/channels/discord/media.js.map +1 -0
  56. package/dist/agents/channels/discord/module.d.ts +15 -0
  57. package/dist/agents/channels/discord/module.d.ts.map +1 -0
  58. package/dist/agents/channels/discord/module.js +22 -0
  59. package/dist/agents/channels/discord/module.js.map +1 -0
  60. package/dist/agents/channels/discord/plugin.d.ts +73 -0
  61. package/dist/agents/channels/discord/plugin.d.ts.map +1 -0
  62. package/dist/agents/channels/discord/plugin.js +303 -0
  63. package/dist/agents/channels/discord/plugin.js.map +1 -0
  64. package/dist/agents/channels/discord/probe.d.ts +93 -0
  65. package/dist/agents/channels/discord/probe.d.ts.map +1 -0
  66. package/dist/agents/channels/discord/probe.js +158 -0
  67. package/dist/agents/channels/discord/probe.js.map +1 -0
  68. package/dist/agents/channels/discord/reasoning-lane.d.ts +42 -0
  69. package/dist/agents/channels/discord/reasoning-lane.d.ts.map +1 -0
  70. package/dist/agents/channels/discord/reasoning-lane.js +68 -0
  71. package/dist/agents/channels/discord/reasoning-lane.js.map +1 -0
  72. package/dist/agents/channels/inbound-pipeline.d.ts.map +1 -1
  73. package/dist/agents/channels/inbound-pipeline.js +65 -7
  74. package/dist/agents/channels/inbound-pipeline.js.map +1 -1
  75. package/dist/agents/channels/manager.d.ts.map +1 -1
  76. package/dist/agents/channels/manager.js +18 -0
  77. package/dist/agents/channels/manager.js.map +1 -1
  78. package/dist/agents/channels/sdk.d.ts +4 -0
  79. package/dist/agents/channels/sdk.d.ts.map +1 -1
  80. package/dist/agents/channels/sdk.js +4 -0
  81. package/dist/agents/channels/sdk.js.map +1 -1
  82. package/dist/agents/channels/slack/account-config.d.ts +172 -0
  83. package/dist/agents/channels/slack/account-config.d.ts.map +1 -0
  84. package/dist/agents/channels/slack/account-config.js +353 -0
  85. package/dist/agents/channels/slack/account-config.js.map +1 -0
  86. package/dist/agents/channels/slack/account-registry.d.ts +45 -0
  87. package/dist/agents/channels/slack/account-registry.d.ts.map +1 -0
  88. package/dist/agents/channels/slack/account-registry.js +58 -0
  89. package/dist/agents/channels/slack/account-registry.js.map +1 -0
  90. package/dist/agents/channels/slack/adapter.d.ts +66 -0
  91. package/dist/agents/channels/slack/adapter.d.ts.map +1 -0
  92. package/dist/agents/channels/slack/adapter.js +547 -0
  93. package/dist/agents/channels/slack/adapter.js.map +1 -0
  94. package/dist/agents/channels/slack/approval-authorize.d.ts +43 -0
  95. package/dist/agents/channels/slack/approval-authorize.d.ts.map +1 -0
  96. package/dist/agents/channels/slack/approval-authorize.js +71 -0
  97. package/dist/agents/channels/slack/approval-authorize.js.map +1 -0
  98. package/dist/agents/channels/slack/approval-native.d.ts +70 -0
  99. package/dist/agents/channels/slack/approval-native.d.ts.map +1 -0
  100. package/dist/agents/channels/slack/approval-native.js +85 -0
  101. package/dist/agents/channels/slack/approval-native.js.map +1 -0
  102. package/dist/agents/channels/slack/blocks.d.ts +125 -0
  103. package/dist/agents/channels/slack/blocks.d.ts.map +1 -0
  104. package/dist/agents/channels/slack/blocks.js +145 -0
  105. package/dist/agents/channels/slack/blocks.js.map +1 -0
  106. package/dist/agents/channels/slack/command-menu.d.ts +44 -0
  107. package/dist/agents/channels/slack/command-menu.d.ts.map +1 -0
  108. package/dist/agents/channels/slack/command-menu.js +66 -0
  109. package/dist/agents/channels/slack/command-menu.js.map +1 -0
  110. package/dist/agents/channels/slack/connection.d.ts +422 -0
  111. package/dist/agents/channels/slack/connection.d.ts.map +1 -0
  112. package/dist/agents/channels/slack/connection.js +1042 -0
  113. package/dist/agents/channels/slack/connection.js.map +1 -0
  114. package/dist/agents/channels/slack/directory-live.d.ts +129 -0
  115. package/dist/agents/channels/slack/directory-live.d.ts.map +1 -0
  116. package/dist/agents/channels/slack/directory-live.js +148 -0
  117. package/dist/agents/channels/slack/directory-live.js.map +1 -0
  118. package/dist/agents/channels/slack/draft-stream.d.ts +93 -0
  119. package/dist/agents/channels/slack/draft-stream.d.ts.map +1 -0
  120. package/dist/agents/channels/slack/draft-stream.js +218 -0
  121. package/dist/agents/channels/slack/draft-stream.js.map +1 -0
  122. package/dist/agents/channels/slack/format.d.ts +41 -0
  123. package/dist/agents/channels/slack/format.d.ts.map +1 -0
  124. package/dist/agents/channels/slack/format.js +271 -0
  125. package/dist/agents/channels/slack/format.js.map +1 -0
  126. package/dist/agents/channels/slack/inbound-extras.d.ts +179 -0
  127. package/dist/agents/channels/slack/inbound-extras.d.ts.map +1 -0
  128. package/dist/agents/channels/slack/inbound-extras.js +257 -0
  129. package/dist/agents/channels/slack/inbound-extras.js.map +1 -0
  130. package/dist/agents/channels/slack/index.d.ts +15 -0
  131. package/dist/agents/channels/slack/index.d.ts.map +1 -0
  132. package/dist/agents/channels/slack/index.js +15 -0
  133. package/dist/agents/channels/slack/index.js.map +1 -0
  134. package/dist/agents/channels/slack/media.d.ts +90 -0
  135. package/dist/agents/channels/slack/media.d.ts.map +1 -0
  136. package/dist/agents/channels/slack/media.js +215 -0
  137. package/dist/agents/channels/slack/media.js.map +1 -0
  138. package/dist/agents/channels/slack/module.d.ts +26 -0
  139. package/dist/agents/channels/slack/module.d.ts.map +1 -0
  140. package/dist/agents/channels/slack/module.js +67 -0
  141. package/dist/agents/channels/slack/module.js.map +1 -0
  142. package/dist/agents/channels/slack/plugin.d.ts +69 -0
  143. package/dist/agents/channels/slack/plugin.d.ts.map +1 -0
  144. package/dist/agents/channels/slack/plugin.js +318 -0
  145. package/dist/agents/channels/slack/plugin.js.map +1 -0
  146. package/dist/agents/channels/slack/probe.d.ts +72 -0
  147. package/dist/agents/channels/slack/probe.d.ts.map +1 -0
  148. package/dist/agents/channels/slack/probe.js +103 -0
  149. package/dist/agents/channels/slack/probe.js.map +1 -0
  150. package/dist/agents/channels/slack/proxy-agent.d.ts +30 -0
  151. package/dist/agents/channels/slack/proxy-agent.d.ts.map +1 -0
  152. package/dist/agents/channels/slack/proxy-agent.js +44 -0
  153. package/dist/agents/channels/slack/proxy-agent.js.map +1 -0
  154. package/dist/agents/channels/slack/reasoning-lane.d.ts +42 -0
  155. package/dist/agents/channels/slack/reasoning-lane.d.ts.map +1 -0
  156. package/dist/agents/channels/slack/reasoning-lane.js +68 -0
  157. package/dist/agents/channels/slack/reasoning-lane.js.map +1 -0
  158. package/dist/agents/channels/slack/user-directory.d.ts +69 -0
  159. package/dist/agents/channels/slack/user-directory.d.ts.map +1 -0
  160. package/dist/agents/channels/slack/user-directory.js +94 -0
  161. package/dist/agents/channels/slack/user-directory.js.map +1 -0
  162. package/dist/agents/channels/slack/webhook.d.ts +89 -0
  163. package/dist/agents/channels/slack/webhook.d.ts.map +1 -0
  164. package/dist/agents/channels/slack/webhook.js +228 -0
  165. package/dist/agents/channels/slack/webhook.js.map +1 -0
  166. package/dist/agents/channels/telegram/format.d.ts.map +1 -1
  167. package/dist/agents/channels/telegram/format.js +17 -1
  168. package/dist/agents/channels/telegram/format.js.map +1 -1
  169. package/dist/agents/channels/telegram/webhook.d.ts.map +1 -1
  170. package/dist/agents/channels/telegram/webhook.js +7 -1
  171. package/dist/agents/channels/telegram/webhook.js.map +1 -1
  172. package/dist/agents/extensions/modules/index.d.ts.map +1 -1
  173. package/dist/agents/extensions/modules/index.js +10 -0
  174. package/dist/agents/extensions/modules/index.js.map +1 -1
  175. package/dist/agents/tools/cron-tool.d.ts.map +1 -1
  176. package/dist/agents/tools/cron-tool.js +4 -1
  177. package/dist/agents/tools/cron-tool.js.map +1 -1
  178. package/dist/buildstamp.json +1 -1
  179. package/dist/core/auth-bridge.d.ts +1 -0
  180. package/dist/core/auth-bridge.d.ts.map +1 -1
  181. package/dist/core/auth-bridge.js +46 -1
  182. package/dist/core/auth-bridge.js.map +1 -1
  183. package/dist/core/server.d.ts.map +1 -1
  184. package/dist/core/server.js +40 -5
  185. package/dist/core/server.js.map +1 -1
  186. package/dist/cron/isolated-agent/run-executor.d.ts +11 -0
  187. package/dist/cron/isolated-agent/run-executor.d.ts.map +1 -1
  188. package/dist/cron/isolated-agent/run-executor.js +20 -4
  189. package/dist/cron/isolated-agent/run-executor.js.map +1 -1
  190. package/dist/cron/types.d.ts +8 -0
  191. package/dist/cron/types.d.ts.map +1 -1
  192. package/dist/system-prompt/assembler.d.ts.map +1 -1
  193. package/dist/system-prompt/assembler.js +4 -2
  194. package/dist/system-prompt/assembler.js.map +1 -1
  195. package/package.json +5 -1
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Convert agent-style markdown (Brigade agents output this by default) into
3
+ * Discord's message markup.
4
+ *
5
+ * Discord renders a near-CommonMark dialect natively, so — unlike Slack's
6
+ * `mrkdwn` (single-asterisk bold) or Telegram's strict HTML — most agent
7
+ * markdown passes through UNCHANGED:
8
+ * - **bold** / __underline__ → kept (Discord: `**bold**`, `__underline__`)
9
+ * - *italic* / _italic_ → kept
10
+ * - ~~strike~~ → kept
11
+ * - `code` → kept (interior verbatim)
12
+ * - ```fenced``` → kept (interior verbatim, language tag kept)
13
+ * - > quote → kept
14
+ * - `-`/`*`/`+` bullets → kept
15
+ * - 1. numbered lists → kept
16
+ * - # headings → kept (Discord renders `#`/`##`/`###` headers)
17
+ *
18
+ * The ONE load-bearing transform: a markdown link `[label](url)` renders
19
+ * LITERALLY in a normal Discord message (Discord only auto-links bare URLs and
20
+ * honours `[label](url)` in embeds, not plain content). So a plain-message link
21
+ * is rewritten to `label (url)` — the same readable fallback Slack/Telegram use
22
+ * when a link can't be a native token. A bare URL is left as-is (Discord
23
+ * auto-links it).
24
+ *
25
+ * MENTION PASSTHROUGH (critical): an agent that authored a Discord mention token
26
+ * means it to PING. Discord's tokens are `<@123>` (user), `<@!123>` (member
27
+ * nickname), `<@&123>` (role), `<#123>` (channel), `<:name:123>` / `<a:name:123>`
28
+ * (custom / animated emoji), and the literal `@everyone` / `@here`. Those are
29
+ * passed through VERBATIM so the mention actually resolves; everything else is
30
+ * left as Discord-native markdown. We do NOT entity-escape (Discord has no HTML
31
+ * entities) — we only neutralize a STRAY markdown link.
32
+ *
33
+ * Pure / deterministic — no I/O, no globals. Models the SHAPE of
34
+ * `slack/format.ts` (markdown in → channel-native formatting out) but emits
35
+ * Discord markup.
36
+ */
37
+ /** Discord's hard per-message content limit (chars). Sends chunk under this. */
38
+ export const DISCORD_MESSAGE_LIMIT = 2000;
39
+ /**
40
+ * A pre-formed Discord token that must pass through verbatim so it resolves:
41
+ * - `<@123>` / `<@!123>` user / member mention
42
+ * - `<@&123>` role mention
43
+ * - `<#123>` channel mention
44
+ * - `<:name:123>` / `<a:name:123>` custom / animated emoji
45
+ * - `<t:123>` / `<t:123:R>` timestamp
46
+ * Anchored at the `<` the scanner is sitting on. Returns the matched token
47
+ * length, or 0 when the `<…>` isn't a recognised Discord token.
48
+ */
49
+ function matchDiscordToken(text, start) {
50
+ // Find the closing `>` for this `<`.
51
+ const close = text.indexOf(">", start + 1);
52
+ if (close === -1)
53
+ return 0;
54
+ const inner = text.slice(start + 1, close);
55
+ // user / member: @123 or @!123 ; role: @&123 ; channel: #123
56
+ if (/^@!?\d+$/.test(inner))
57
+ return close - start + 1;
58
+ if (/^@&\d+$/.test(inner))
59
+ return close - start + 1;
60
+ if (/^#\d+$/.test(inner))
61
+ return close - start + 1;
62
+ // custom / animated emoji: :name:123 or a:name:123
63
+ if (/^a?:[A-Za-z0-9_]{2,32}:\d+$/.test(inner))
64
+ return close - start + 1;
65
+ // timestamp: t:123 or t:123:R
66
+ if (/^t:\d+(?::[tTdDfFR])?$/.test(inner))
67
+ return close - start + 1;
68
+ return 0;
69
+ }
70
+ /** Try to match a `[label](url)` link starting at `start` (the `[`). */
71
+ function matchMarkdownLink(text, start) {
72
+ const labelEnd = text.indexOf("]", start + 1);
73
+ if (labelEnd === -1)
74
+ return null;
75
+ if (text[labelEnd + 1] !== "(")
76
+ return null;
77
+ // Balanced-paren scan from just after the opening `(` so a URL that itself
78
+ // contains parentheses (e.g. `…/Mercury_(planet)`) keeps its closing `)`. A
79
+ // plain `indexOf(")")` would truncate at the FIRST `)`, dropping the rest.
80
+ let depth = 1;
81
+ let urlEnd = -1;
82
+ for (let j = labelEnd + 2; j < text.length; j++) {
83
+ const c = text[j];
84
+ if (c === "(")
85
+ depth += 1;
86
+ else if (c === ")") {
87
+ depth -= 1;
88
+ if (depth === 0) {
89
+ urlEnd = j;
90
+ break;
91
+ }
92
+ }
93
+ }
94
+ if (urlEnd === -1)
95
+ return null;
96
+ const label = text.slice(start + 1, labelEnd);
97
+ const url = text.slice(labelEnd + 2, urlEnd).trim();
98
+ // Only honour http/https/mailto/tel links — anything else stays literal so we
99
+ // never linkify a path / fragment that wasn't a real URL.
100
+ if (!/^(https?:\/\/|mailto:|tel:)/i.test(url))
101
+ return null;
102
+ if (!label)
103
+ return null;
104
+ return { label, url, end: urlEnd + 1 };
105
+ }
106
+ /**
107
+ * Render the INLINE span markup of one already-newline-free run into Discord
108
+ * markup. Inline code is preserved verbatim (its interior is never rewritten),
109
+ * Discord mention/emoji tokens pass through verbatim, and a markdown link is
110
+ * rewritten to the readable `label (url)` fallback. Everything else is passed
111
+ * through unchanged (Discord renders **bold** / *italic* / ~~strike~~ natively).
112
+ */
113
+ function renderInlineSpans(text) {
114
+ const out = [];
115
+ let i = 0;
116
+ const n = text.length;
117
+ while (i < n) {
118
+ const ch = text[i];
119
+ // Inline code: `…` — interior is verbatim (no link rewrite inside code).
120
+ if (ch === "`") {
121
+ // Support a run of backticks (`` `x` `` / ``` ``y`` ``` ) — match the
122
+ // same-length closing fence so an interior backtick doesn't close early.
123
+ const fenceMatch = /^`+/.exec(text.slice(i));
124
+ const fence = fenceMatch ? fenceMatch[0] : "`";
125
+ const close = text.indexOf(fence, i + fence.length);
126
+ if (close !== -1) {
127
+ out.push(text.slice(i, close + fence.length));
128
+ i = close + fence.length;
129
+ continue;
130
+ }
131
+ }
132
+ // Pre-formed Discord token (mention / channel / role / emoji / timestamp) —
133
+ // pass through verbatim so it actually resolves on Discord.
134
+ if (ch === "<") {
135
+ const len = matchDiscordToken(text, i);
136
+ if (len > 0) {
137
+ out.push(text.slice(i, i + len));
138
+ i += len;
139
+ continue;
140
+ }
141
+ }
142
+ // Markdown link: [label](url) → "label (url)" (a plain Discord message
143
+ // renders the markdown-link form literally, so we degrade to readable text).
144
+ if (ch === "[") {
145
+ const link = matchMarkdownLink(text, i);
146
+ if (link) {
147
+ // When the label already equals the url, just emit the bare url
148
+ // (Discord auto-links it) to avoid the noisy "url (url)".
149
+ out.push(link.label === link.url ? link.url : `${link.label} (${link.url})`);
150
+ i = link.end;
151
+ continue;
152
+ }
153
+ }
154
+ out.push(ch ?? "");
155
+ i += 1;
156
+ }
157
+ return out.join("");
158
+ }
159
+ /** Render a markdown pipe-table block as flat "cell | cell" lines. */
160
+ function renderTableBlock(block) {
161
+ const rows = [];
162
+ for (const row of block) {
163
+ // Drop the separator row (`| --- | :--: |`).
164
+ if (/^\s*\|?[\s|:-]+\|?\s*$/.test(row))
165
+ continue;
166
+ const cells = row
167
+ .trim()
168
+ .replace(/^\||\|$/g, "")
169
+ .split("|")
170
+ .map((c) => c.trim())
171
+ .filter(Boolean);
172
+ if (cells.length)
173
+ rows.push(cells.map((c) => renderInlineSpans(c)).join(" | "));
174
+ }
175
+ return rows.join("\n");
176
+ }
177
+ /**
178
+ * Convert agent-style markdown into Discord markup. Block structure (fenced code,
179
+ * tables) is handled line-by-line so a link inside a code fence is never
180
+ * rewritten; inline markup (links, mentions, code) is handled per-line by
181
+ * {@link renderInlineSpans}. Headings / bullets / numbered lists / blockquotes
182
+ * render natively on Discord, so they pass through with only their inline spans
183
+ * rewritten.
184
+ */
185
+ export function markdownToDiscord(markdown) {
186
+ if (!markdown)
187
+ return "";
188
+ const lines = markdown.split("\n");
189
+ const out = [];
190
+ let i = 0;
191
+ const n = lines.length;
192
+ while (i < n) {
193
+ const line = lines[i] ?? "";
194
+ // Fenced code block: ```lang … ``` — kept VERBATIM (language tag + interior),
195
+ // Discord renders it natively and a link inside must not be rewritten.
196
+ const fenceOpen = /^\s*```/.exec(line);
197
+ if (fenceOpen) {
198
+ out.push(line);
199
+ i += 1;
200
+ while (i < n) {
201
+ const inner = lines[i] ?? "";
202
+ out.push(inner);
203
+ i += 1;
204
+ if (/^\s*```\s*$/.test(inner))
205
+ break;
206
+ }
207
+ continue;
208
+ }
209
+ // Pipe-table block: ≥2 contiguous lines that start+end with `|`. Discord has
210
+ // no table rendering, so flatten to "cell | cell" lines (parity w/ Slack).
211
+ if (/^\s*\|.*\|\s*$/.test(line)) {
212
+ const start = i;
213
+ while (i < n && /^\s*\|.*\|\s*$/.test(lines[i] ?? ""))
214
+ i += 1;
215
+ if (i - start >= 2) {
216
+ out.push(renderTableBlock(lines.slice(start, i)));
217
+ continue;
218
+ }
219
+ i = start;
220
+ }
221
+ // Plain / heading / bullet / quote line — render inline spans; the block
222
+ // markers (`#`, `-`, `>`, `1.`) are left in place for Discord to render.
223
+ out.push(renderInlineSpans(line));
224
+ i += 1;
225
+ }
226
+ return out.join("\n");
227
+ }
228
+ /**
229
+ * True when the rendered Discord text carries no visible content — only
230
+ * whitespace and/or markdown markers. Discord rejects an empty message body, so
231
+ * the send path falls back / skips when this returns true. Mirrors
232
+ * `slackMrkdwnIsEmpty` intent.
233
+ */
234
+ export function discordTextIsEmpty(text) {
235
+ if (!text)
236
+ return true;
237
+ const stripped = text
238
+ // Mentions / channels / roles / emoji ARE content.
239
+ .replace(/<a?:[A-Za-z0-9_]+:\d+>/g, "x")
240
+ .replace(/<@[!&]?\d+>/g, "x")
241
+ .replace(/<#\d+>/g, "x")
242
+ .replace(/<t:\d+(?::[tTdDfFR])?>/g, "x")
243
+ .replace(/[*_~`>#|.\-\s]/g, "")
244
+ .trim();
245
+ return stripped.length === 0;
246
+ }
247
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../../../src/agents/channels/discord/format.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,220 @@
1
+ /**
2
+ * Pure extractors that turn a discord.js message / reaction / interaction into
3
+ * the normalized fields Brigade's `InboundMessage` carries. No network, no side
4
+ * effects — every function here is deterministic over its argument so they're
5
+ * trivial to unit-test without a live gateway.
6
+ *
7
+ * Discord's wire shape (rich discord.js objects, not raw JSON like Slack's
8
+ * Events API) differs from Slack/Telegram in load-bearing ways, so the logic is
9
+ * a Brigade-native re-implementation that models the SHAPE of
10
+ * `slack/inbound-extras.ts` (raw payload → normalized signals) while speaking
11
+ * Discord semantics:
12
+ *
13
+ * - Text arrives as `message.content` peppered with Discord TOKENS: `<@123>`
14
+ * / `<@!123>` (user/member), `<@&456>` (role), `<#789>` (channel),
15
+ * `<:name:111>` / `<a:name:111>` (custom emoji). {@link extractDiscordText}
16
+ * expands user/channel/role mentions into readable plain text the agent can
17
+ * parse (`@alex`, `#general`), resolving names via an injected cache when one
18
+ * is supplied (the cached guild/client primes them in the background).
19
+ * - The bot is "addressed" when its own user id appears as a `<@123>` mention.
20
+ * {@link extractDiscordMentions} surfaces the bot's id when addressed so the
21
+ * central group ACL admits the message — exactly as Slack surfaces the bot's
22
+ * id. Every OTHER user mention is surfaced too.
23
+ * - Channel kind: a DM channel → `direct`; a guild text channel / thread →
24
+ * `group` (see {@link discordChannelType}).
25
+ * - Threads ride on the channel being a thread (`threadId` = the thread
26
+ * channel id); the parent text channel is the conversation root.
27
+ * - Reply context rides on `message.reference.messageId`.
28
+ * - Attachments arrive as `message.attachments` (each a CDN `url` + metadata);
29
+ * the connection layer DEFERS the byte download until the access gate admits
30
+ * the sender (mirrors Slack/Telegram's deferred-media discipline).
31
+ *
32
+ * Brigade's CENTRAL inbound pipeline owns the actual ACL / mention / routing
33
+ * decision — these helpers only surface the raw signals it reads.
34
+ */
35
+ import type { InboundReplyContext } from "../sdk.js";
36
+ /** One attachment discord.js exposes on a message (the subset we read). */
37
+ export interface DiscordAttachmentLike {
38
+ id?: string;
39
+ name?: string | null;
40
+ /** CDN download URL (cdn.discordapp.com / media.discordapp.net). */
41
+ url?: string;
42
+ proxyURL?: string;
43
+ contentType?: string | null;
44
+ size?: number;
45
+ /** Discord marks voice messages with this flag-bit set; we treat them as voice. */
46
+ flags?: {
47
+ has?: (bit: unknown) => boolean;
48
+ } | number;
49
+ [key: string]: unknown;
50
+ }
51
+ /** A discord.js channel (the subset Brigade reads). `isThread()`/`isDMBased()` may be absent on a fake. */
52
+ export interface DiscordChannelLike {
53
+ id?: string;
54
+ /** Discord channel type enum value (0 = guild text, 1 = DM, 11/12 = thread, …). */
55
+ type?: number;
56
+ isThread?: () => boolean;
57
+ isDMBased?: () => boolean;
58
+ /** Parent text-channel id when this channel is a thread. */
59
+ parentId?: string | null;
60
+ [key: string]: unknown;
61
+ }
62
+ /** A discord.js guild (the subset Brigade reads). */
63
+ export interface DiscordGuildLike {
64
+ id?: string;
65
+ [key: string]: unknown;
66
+ }
67
+ /**
68
+ * The member's roles as Brigade reads them. On a live message discord.js hands
69
+ * a `GuildMemberRoleManager` whose `.cache` is a Collection (a Map subclass)
70
+ * keyed by role id; a fake / partial may pass a plain array of role ids. Both
71
+ * shapes (and an absent value) are honoured by {@link extractDiscordMemberRoleIds}.
72
+ */
73
+ export type DiscordMemberRolesLike = {
74
+ cache?: Map<string, unknown> | Iterable<[string, unknown]> | Iterable<{
75
+ id?: string;
76
+ }>;
77
+ } | Iterable<string> | string[] | null | undefined;
78
+ /** A discord.js user / author (the subset Brigade reads). */
79
+ export interface DiscordUserLike {
80
+ id?: string;
81
+ bot?: boolean;
82
+ username?: string;
83
+ globalName?: string | null;
84
+ /** Cached member display name (guild nickname), when discord.js resolved one. */
85
+ displayName?: string;
86
+ [key: string]: unknown;
87
+ }
88
+ /**
89
+ * A discord.js Message (the subset Brigade consumes). Only the fields used are
90
+ * typed; the live object carries far more.
91
+ */
92
+ export interface DiscordMessageLike {
93
+ id?: string;
94
+ content?: string;
95
+ author?: DiscordUserLike;
96
+ /**
97
+ * The member who sent it (guild nickname lives here). `roles` is discord.js's
98
+ * `GuildMemberRoleManager` (a `.cache` Collection keyed by role id) on a live
99
+ * message; a fake / partial may instead carry a plain array of role ids.
100
+ */
101
+ member?: {
102
+ nickname?: string | null;
103
+ displayName?: string;
104
+ roles?: DiscordMemberRolesLike;
105
+ } | null;
106
+ channelId?: string;
107
+ channel?: DiscordChannelLike;
108
+ guildId?: string | null;
109
+ guild?: DiscordGuildLike | null;
110
+ /** Epoch ms the message was created. */
111
+ createdTimestamp?: number;
112
+ /** Set when the message was edited (epoch ms), else null. */
113
+ editedTimestamp?: number | null;
114
+ /** Reply pointer — `messageId` is the message being replied to. */
115
+ reference?: {
116
+ messageId?: string | null;
117
+ channelId?: string | null;
118
+ guildId?: string | null;
119
+ } | null;
120
+ attachments?: Iterable<DiscordAttachmentLike> | Map<string, DiscordAttachmentLike> | DiscordAttachmentLike[];
121
+ /** A resolved Collection of mentioned users, or a plain array on a fake. */
122
+ mentions?: {
123
+ users?: Iterable<DiscordUserLike> | Map<string, DiscordUserLike> | DiscordUserLike[];
124
+ };
125
+ [key: string]: unknown;
126
+ }
127
+ /**
128
+ * Expand the Discord message TOKENS in a run of text into readable plain text:
129
+ * - `<@123>` / `<@!123>` → `@alex` (resolved name) or `@123`
130
+ * - `<@&456>` → `@role` (resolved) or `@&456`
131
+ * - `<#789>` → `#general` (resolved) or `#789`
132
+ * - `<:name:111>` / `<a:name:111>` → `:name:` (the readable emoji shortcode)
133
+ *
134
+ * Names resolve via the injected lookups (the connection primes them from the
135
+ * cached guild/client); without a resolver the bare id is surfaced. Pure +
136
+ * deterministic.
137
+ */
138
+ export declare function expandDiscordTokens(text: string, resolve?: {
139
+ user?: (id: string) => string | undefined;
140
+ role?: (id: string) => string | undefined;
141
+ channel?: (id: string) => string | undefined;
142
+ }): string;
143
+ /**
144
+ * The agent-facing plain text of a Discord message. Token-expanded (mentions /
145
+ * channels / roles / emoji → readable text). Binary blobs are dropped to "".
146
+ */
147
+ export declare function extractDiscordText(message: Pick<DiscordMessageLike, "content">, resolve?: Parameters<typeof expandDiscordTokens>[1]): string;
148
+ /** True when a discord.js channel is a thread (uses `isThread()` when present, else the type enum). */
149
+ export declare function isThreadChannel(channel: DiscordChannelLike | undefined | null): boolean;
150
+ /** True when a discord.js channel is a DM (uses `isDMBased()` when present, else the type enum). */
151
+ export declare function isDmChannel(channel: DiscordChannelLike | undefined | null): boolean;
152
+ /**
153
+ * Discord channel → Brigade chat type. A 1:1 DM → `direct`; a guild text channel
154
+ * or a thread → `group`. A group DM (rare for bots) → `group`. When no channel
155
+ * object is available, a missing `guildId` implies a DM.
156
+ */
157
+ export declare function discordChannelType(message: Pick<DiscordMessageLike, "channel" | "guildId">): "direct" | "group";
158
+ /**
159
+ * The thread channel id when the message landed in a thread, else undefined. The
160
+ * thread's own channel id is the thread id (Discord threads ARE channels).
161
+ */
162
+ export declare function discordThreadId(message: Pick<DiscordMessageLike, "channel" | "channelId">): string | undefined;
163
+ /**
164
+ * Reply-context (what message this inbound quotes), when it's a reply. Discord
165
+ * carries `message.reference.messageId` (the replied-to message id) but does NOT
166
+ * inline that message's text — so the context surfaces the parent message id and
167
+ * leaves `body` undefined (the connection can fetch the parent if it needs the
168
+ * excerpt). Returns undefined for a non-reply.
169
+ */
170
+ export declare function extractDiscordReplyContext(message: Pick<DiscordMessageLike, "reference">): InboundReplyContext | undefined;
171
+ /**
172
+ * Channel-native ids of users addressed in this message. Brigade's central group
173
+ * ACL treats a group message as "addressed to the bot" when the bot's own id
174
+ * appears in `mentions`; without this a group message never reaches the agent.
175
+ * So when the bot's own `<@id>` mention appears in the text we surface the bot's
176
+ * id (passed in). Every OTHER user mention is surfaced too so the pipeline sees
177
+ * who else was tagged.
178
+ *
179
+ * We scan BOTH the resolved `message.mentions.users` collection (when present)
180
+ * AND the raw `<@id>` / `<@!id>` tokens in the content, unioned + deduped — the
181
+ * collection is authoritative on a live message, the token scan is the fallback
182
+ * for a fake / a partial.
183
+ *
184
+ * @param botUserId the bot's own user id, surfaced when the bot is mentioned so
185
+ * the ACL admits the group message.
186
+ */
187
+ export declare function extractDiscordMentions(message: DiscordMessageLike, botUserId?: string): string[];
188
+ /**
189
+ * The guild-role ids the sending member holds, surfaced so the 8-tier route
190
+ * resolver's `binding.guild+roles` tier can match. Role NAMES are never used —
191
+ * only ids. Returns `[]` for a DM (no member) or when no roles resolve.
192
+ *
193
+ * Handles the three shapes the `member.roles` value can take:
194
+ * - discord.js `GuildMemberRoleManager` — a `.cache` Collection (Map subclass)
195
+ * keyed by role id; we read the keys (the role ids).
196
+ * - a plain array / iterable of role-id strings (a fake / partial).
197
+ * - absent / null (a DM, or a message with no resolved member) → `[]`.
198
+ *
199
+ * Pure + deterministic; deduped, with the `@everyone` role (whose id equals the
200
+ * guild id and is implicit for everyone) left in as-is — the resolver only
201
+ * matches ids a binding explicitly lists, so a stray everyone id is harmless.
202
+ */
203
+ export declare function extractDiscordMemberRoleIds(message: Pick<DiscordMessageLike, "member">): string[];
204
+ /**
205
+ * A short display name for the sender. A guild nickname wins (most specific),
206
+ * then the member/global display name, then the username, then the raw id.
207
+ */
208
+ export declare function buildDiscordSenderName(message: DiscordMessageLike): string | undefined;
209
+ /**
210
+ * Cheap presence probe — does this message carry a downloadable attachment?
211
+ * Walks `message.attachments` but never touches the network, so the connection
212
+ * layer can DEFER the actual download until AFTER the central access gate admits
213
+ * the sender (mirrors Slack/Telegram). Mirrors `hasInboundMedia`.
214
+ */
215
+ export declare function hasInboundMedia(message: Pick<DiscordMessageLike, "attachments">): boolean;
216
+ /** The list of downloadable attachments on a message. */
217
+ export declare function resolveInboundAttachments(message: Pick<DiscordMessageLike, "attachments">): DiscordAttachmentLike[];
218
+ /** The Brigade media-kind of a Discord attachment, from its contentType / filename / voice flag. */
219
+ export declare function resolveDiscordAttachmentKind(a: DiscordAttachmentLike): "image" | "video" | "audio" | "voice" | "document";
220
+ //# sourceMappingURL=inbound-extras.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbound-extras.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/discord/inbound-extras.ts"],"names":[],"mappings":"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"}