@spinabot/brigade 1.6.1 → 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 (133) hide show
  1. package/dist/agents/channels/discord/account-config.d.ts +60 -0
  2. package/dist/agents/channels/discord/account-config.d.ts.map +1 -1
  3. package/dist/agents/channels/discord/account-config.js +89 -0
  4. package/dist/agents/channels/discord/account-config.js.map +1 -1
  5. package/dist/agents/channels/discord/adapter.d.ts +24 -1
  6. package/dist/agents/channels/discord/adapter.d.ts.map +1 -1
  7. package/dist/agents/channels/discord/adapter.js +208 -41
  8. package/dist/agents/channels/discord/adapter.js.map +1 -1
  9. package/dist/agents/channels/discord/component-blocks.d.ts +108 -0
  10. package/dist/agents/channels/discord/component-blocks.d.ts.map +1 -0
  11. package/dist/agents/channels/discord/component-blocks.js +113 -0
  12. package/dist/agents/channels/discord/component-blocks.js.map +1 -0
  13. package/dist/agents/channels/discord/components.d.ts +78 -0
  14. package/dist/agents/channels/discord/components.d.ts.map +1 -1
  15. package/dist/agents/channels/discord/components.js +89 -0
  16. package/dist/agents/channels/discord/components.js.map +1 -1
  17. package/dist/agents/channels/discord/connection.d.ts +195 -12
  18. package/dist/agents/channels/discord/connection.d.ts.map +1 -1
  19. package/dist/agents/channels/discord/connection.js +852 -38
  20. package/dist/agents/channels/discord/connection.js.map +1 -1
  21. package/dist/agents/channels/discord/directory-cache.d.ts +47 -0
  22. package/dist/agents/channels/discord/directory-cache.d.ts.map +1 -0
  23. package/dist/agents/channels/discord/directory-cache.js +131 -0
  24. package/dist/agents/channels/discord/directory-cache.js.map +1 -0
  25. package/dist/agents/channels/discord/directory-live.d.ts +61 -0
  26. package/dist/agents/channels/discord/directory-live.d.ts.map +1 -0
  27. package/dist/agents/channels/discord/directory-live.js +140 -0
  28. package/dist/agents/channels/discord/directory-live.js.map +1 -0
  29. package/dist/agents/channels/discord/format.d.ts +15 -0
  30. package/dist/agents/channels/discord/format.d.ts.map +1 -1
  31. package/dist/agents/channels/discord/format.js +56 -0
  32. package/dist/agents/channels/discord/format.js.map +1 -1
  33. package/dist/agents/channels/discord/guilds.d.ts +25 -0
  34. package/dist/agents/channels/discord/guilds.d.ts.map +1 -0
  35. package/dist/agents/channels/discord/guilds.js +46 -0
  36. package/dist/agents/channels/discord/guilds.js.map +1 -0
  37. package/dist/agents/channels/discord/inbound-extras.d.ts +166 -9
  38. package/dist/agents/channels/discord/inbound-extras.d.ts.map +1 -1
  39. package/dist/agents/channels/discord/inbound-extras.js +246 -8
  40. package/dist/agents/channels/discord/inbound-extras.js.map +1 -1
  41. package/dist/agents/channels/discord/index.d.ts +10 -3
  42. package/dist/agents/channels/discord/index.d.ts.map +1 -1
  43. package/dist/agents/channels/discord/index.js +10 -3
  44. package/dist/agents/channels/discord/index.js.map +1 -1
  45. package/dist/agents/channels/discord/modal-registry.d.ts +89 -0
  46. package/dist/agents/channels/discord/modal-registry.d.ts.map +1 -0
  47. package/dist/agents/channels/discord/modal-registry.js +104 -0
  48. package/dist/agents/channels/discord/modal-registry.js.map +1 -0
  49. package/dist/agents/channels/discord/modals.d.ts +100 -0
  50. package/dist/agents/channels/discord/modals.d.ts.map +1 -0
  51. package/dist/agents/channels/discord/modals.js +124 -0
  52. package/dist/agents/channels/discord/modals.js.map +1 -0
  53. package/dist/agents/channels/discord/permission-audit.d.ts +43 -0
  54. package/dist/agents/channels/discord/permission-audit.d.ts.map +1 -0
  55. package/dist/agents/channels/discord/permission-audit.js +192 -0
  56. package/dist/agents/channels/discord/permission-audit.js.map +1 -0
  57. package/dist/agents/channels/discord/plugin.d.ts +18 -2
  58. package/dist/agents/channels/discord/plugin.d.ts.map +1 -1
  59. package/dist/agents/channels/discord/plugin.js +73 -4
  60. package/dist/agents/channels/discord/plugin.js.map +1 -1
  61. package/dist/agents/channels/discord/probe.d.ts +23 -1
  62. package/dist/agents/channels/discord/probe.d.ts.map +1 -1
  63. package/dist/agents/channels/discord/probe.js +40 -5
  64. package/dist/agents/channels/discord/probe.js.map +1 -1
  65. package/dist/agents/channels/discord/rest-actions.d.ts +346 -0
  66. package/dist/agents/channels/discord/rest-actions.d.ts.map +1 -0
  67. package/dist/agents/channels/discord/rest-actions.js +559 -0
  68. package/dist/agents/channels/discord/rest-actions.js.map +1 -0
  69. package/dist/agents/channels/discord/rest-components.d.ts +122 -0
  70. package/dist/agents/channels/discord/rest-components.d.ts.map +1 -0
  71. package/dist/agents/channels/discord/rest-components.js +243 -0
  72. package/dist/agents/channels/discord/rest-components.js.map +1 -0
  73. package/dist/agents/channels/discord/security-audit.d.ts +29 -0
  74. package/dist/agents/channels/discord/security-audit.d.ts.map +1 -0
  75. package/dist/agents/channels/discord/security-audit.js +94 -0
  76. package/dist/agents/channels/discord/security-audit.js.map +1 -0
  77. package/dist/agents/channels/discord/security-doctor.d.ts +43 -0
  78. package/dist/agents/channels/discord/security-doctor.d.ts.map +1 -0
  79. package/dist/agents/channels/discord/security-doctor.js +83 -0
  80. package/dist/agents/channels/discord/security-doctor.js.map +1 -0
  81. package/dist/agents/channels/discord/status-issues.d.ts +37 -0
  82. package/dist/agents/channels/discord/status-issues.d.ts.map +1 -0
  83. package/dist/agents/channels/discord/status-issues.js +66 -0
  84. package/dist/agents/channels/discord/status-issues.js.map +1 -0
  85. package/dist/agents/channels/discord/subagent-thread-binding-store.d.ts +57 -0
  86. package/dist/agents/channels/discord/subagent-thread-binding-store.d.ts.map +1 -0
  87. package/dist/agents/channels/discord/subagent-thread-binding-store.js +98 -0
  88. package/dist/agents/channels/discord/subagent-thread-binding-store.js.map +1 -0
  89. package/dist/agents/channels/discord/subagent-thread-binding.d.ts +95 -0
  90. package/dist/agents/channels/discord/subagent-thread-binding.d.ts.map +1 -0
  91. package/dist/agents/channels/discord/subagent-thread-binding.js +208 -0
  92. package/dist/agents/channels/discord/subagent-thread-binding.js.map +1 -0
  93. package/dist/agents/channels/discord/system-events.d.ts +31 -0
  94. package/dist/agents/channels/discord/system-events.d.ts.map +1 -0
  95. package/dist/agents/channels/discord/system-events.js +74 -0
  96. package/dist/agents/channels/discord/system-events.js.map +1 -0
  97. package/dist/agents/channels/general-callback.d.ts +12 -0
  98. package/dist/agents/channels/general-callback.d.ts.map +1 -1
  99. package/dist/agents/channels/general-callback.js +18 -0
  100. package/dist/agents/channels/general-callback.js.map +1 -1
  101. package/dist/agents/channels/inbound-pipeline.d.ts.map +1 -1
  102. package/dist/agents/channels/inbound-pipeline.js +5 -3
  103. package/dist/agents/channels/inbound-pipeline.js.map +1 -1
  104. package/dist/agents/extensions/types.d.ts +7 -0
  105. package/dist/agents/extensions/types.d.ts.map +1 -1
  106. package/dist/agents/extensions/types.js.map +1 -1
  107. package/dist/agents/subagent-announce-delivery.d.ts +10 -0
  108. package/dist/agents/subagent-announce-delivery.d.ts.map +1 -1
  109. package/dist/agents/subagent-announce-delivery.js +1 -0
  110. package/dist/agents/subagent-announce-delivery.js.map +1 -1
  111. package/dist/agents/subagent-completion-bridge.d.ts.map +1 -1
  112. package/dist/agents/subagent-completion-bridge.js +81 -0
  113. package/dist/agents/subagent-completion-bridge.js.map +1 -1
  114. package/dist/agents/subagent-spawn.d.ts.map +1 -1
  115. package/dist/agents/subagent-spawn.js +57 -4
  116. package/dist/agents/subagent-spawn.js.map +1 -1
  117. package/dist/agents/tools/discord-action-tool.d.ts +224 -0
  118. package/dist/agents/tools/discord-action-tool.d.ts.map +1 -0
  119. package/dist/agents/tools/discord-action-tool.js +848 -0
  120. package/dist/agents/tools/discord-action-tool.js.map +1 -0
  121. package/dist/agents/tools/registry.d.ts.map +1 -1
  122. package/dist/agents/tools/registry.js +21 -0
  123. package/dist/agents/tools/registry.js.map +1 -1
  124. package/dist/agents/tools/sessions/index.d.ts +8 -0
  125. package/dist/agents/tools/sessions/index.d.ts.map +1 -1
  126. package/dist/agents/tools/sessions/index.js +15 -3
  127. package/dist/agents/tools/sessions/index.js.map +1 -1
  128. package/dist/buildstamp.json +1 -1
  129. package/dist/cli/commands/channels.d.ts +2 -0
  130. package/dist/cli/commands/channels.d.ts.map +1 -1
  131. package/dist/cli/commands/channels.js +58 -1
  132. package/dist/cli/commands/channels.js.map +1 -1
  133. package/package.json +1 -1
@@ -38,6 +38,36 @@ declare const CHANNEL_ID = "discord";
38
38
  declare const DEFAULT_ACCOUNT_ID = "default";
39
39
  /** Per-secret env var consulted as a last-resort fallback. */
40
40
  declare const BOT_TOKEN_ENV_VAR = "DISCORD_BOT_TOKEN";
41
+ /** Reaction-notification gating modes (see `channels.discord.reactionNotifications`). */
42
+ export type DiscordReactionNotificationMode = "off" | "own" | "all" | "allowlist";
43
+ /** Bot online-dot status (`channels.discord.presence.status`). */
44
+ export type DiscordPresenceStatus = "online" | "idle" | "dnd" | "invisible";
45
+ /** Activity row kind (`channels.discord.presence.activityType`). */
46
+ export type DiscordPresenceActivityType = "playing" | "streaming" | "listening" | "watching" | "custom" | "competing";
47
+ /** How an auto-thread is named (`channels.discord.autoThreadName`). */
48
+ export type DiscordAutoThreadNameMode = "generated" | "first-message";
49
+ /**
50
+ * Resolved presence applied on (re)connect. `activityType` is the discord.js
51
+ * `ActivityType` numeric enum value (playing=0, streaming=1, listening=2,
52
+ * watching=3, custom=4, competing=5); `activityText` is the activity name (the
53
+ * STATE line for a custom activity); `activityUrl` rides only on a streaming
54
+ * activity. `null` when no presence is configured.
55
+ */
56
+ export interface ResolvedDiscordPresence {
57
+ status: DiscordPresenceStatus;
58
+ activityType?: DiscordPresenceActivityType;
59
+ activityTypeCode?: number;
60
+ activityText?: string;
61
+ activityUrl?: string;
62
+ }
63
+ /** Resolved auto-thread policy (`channels.discord.autoThread*`). */
64
+ export interface ResolvedDiscordAutoThread {
65
+ enabled: boolean;
66
+ /** Thread name source. `"generated"` falls back to first-message until a completion runtime exists. */
67
+ nameMode: DiscordAutoThreadNameMode;
68
+ /** Idle minutes before Discord auto-archives the thread (60 / 1440 / 4320 / 10080). */
69
+ autoArchiveMinutes: number;
70
+ }
41
71
  /** Resolved per-account info — what the adapter runtime reads. */
42
72
  export interface ResolvedDiscordAccount {
43
73
  accountId: string;
@@ -107,11 +137,41 @@ export declare function discordStreamThrottleMs(cfg: BrigadeConfig): number;
107
137
  * Default OFF — `<think>` reasoning is stripped from channel replies as today.
108
138
  */
109
139
  export declare function discordSurfaceReasoning(cfg: BrigadeConfig): boolean;
140
+ /**
141
+ * Resolve the reaction-notification mode (`channels.discord.reactionNotifications`).
142
+ * Defaults to `"own"` (only reactions on the bot's own messages wake the agent) so
143
+ * a stranger's reaction in an admitted channel no longer spams a turn. An invalid /
144
+ * unset value degrades to the `"own"` default.
145
+ */
146
+ export declare function discordReactionNotifications(cfg: BrigadeConfig): DiscordReactionNotificationMode;
110
147
  /**
111
148
  * Resolve the idle-thread-session TTL in ms, or `null` when unset / disabled.
112
149
  * Accepts a number (ms) or a duration string (`"6h"`, `"30m"`, …). The cron
113
150
  * session-reaper uses this to age out idle Discord thread sessions.
114
151
  */
115
152
  export declare function discordThreadIdleTtlMs(cfg: BrigadeConfig): number | null;
153
+ /**
154
+ * Resolve the bot presence to apply on (re)connect, or `null` when none is
155
+ * configured (`channels.discord.presence` absent / empty → keep Discord's
156
+ * default). A `status`-only block (no activity) still resolves so the operator
157
+ * can set just the online dot. An invalid `status` / `activityType` is dropped
158
+ * (degrades to the default), never throwing. The activity type is mapped to its
159
+ * discord.js `ActivityType` numeric code here so the connection stays
160
+ * discord.js-agnostic.
161
+ *
162
+ * Multi-account aware (mirrors the other per-account resolvers): the per-account
163
+ * `accounts[id].presence` wins, falling back to the top-level
164
+ * `channels.discord.presence`. Without this fallback a per-account
165
+ * `set-presence` write was a silent no-op (it read only the top-level slot).
166
+ */
167
+ export declare function resolveDiscordPresence(cfg: BrigadeConfig, accountId?: string | null): ResolvedDiscordPresence | null;
168
+ /**
169
+ * Resolve the auto-thread policy (`channels.discord.autoThread*`). Returns a
170
+ * resolved view with `enabled` false when the feature is off (the default). The
171
+ * name mode defaults to `"first-message"`; `autoArchiveDuration` is clamped to
172
+ * one of Discord's accepted values (60 / 1440 / 4320 / 10080), defaulting to
173
+ * 1440 (24h).
174
+ */
175
+ export declare function resolveDiscordAutoThread(cfg: BrigadeConfig): ResolvedDiscordAutoThread;
116
176
  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, };
117
177
  //# sourceMappingURL=account-config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"account-config.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/discord/account-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAG3D,QAAA,MAAM,UAAU,YAAY,CAAC;AAC7B,QAAA,MAAM,kBAAkB,YAAY,CAAC;AAErC,8DAA8D;AAC9D,QAAA,MAAM,iBAAiB,sBAAsB,CAAC;AA+D9C,kEAAkE;AAClE,MAAM,WAAW,sBAAsB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CACjB;AAqBD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,6DAA6D;AAC7D,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAEjE;AAED,wFAAwF;AACxF,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,EAAE,CAgBlE;AAeD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACrC,GAAG,EAAE,aAAa,EAClB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,EACzB,GAAG,GAAE,MAAM,CAAC,UAAwB,GAClC,MAAM,CAaR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACrC,GAAG,EAAE,aAAa,EAClB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,EACzB,GAAG,GAAE,MAAM,CAAC,UAAwB,GAClC,MAAM,CAaR;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUrD;AAED,wFAAwF;AACxF,wBAAgB,qBAAqB,CACpC,GAAG,EAAE,aAAa,EAClB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,EACzB,GAAG,GAAE,MAAM,CAAC,UAAwB,GAClC,sBAAsB,CAYxB;AAID;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAEpE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAGlE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAEnE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAcxE;AAED,OAAO,EACN,UAAU,IAAI,kBAAkB,EAChC,kBAAkB,IAAI,0BAA0B,EAChD,iBAAiB,IAAI,yBAAyB,GAC9C,CAAC"}
1
+ {"version":3,"file":"account-config.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/discord/account-config.ts"],"names":[],"mappings":"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"}
@@ -53,6 +53,18 @@ const PROXY_ENV_VARS = ["https_proxy", "HTTPS_PROXY", "all_proxy", "ALL_PROXY"];
53
53
  const SEAL_KEY_BOT = CHANNEL_ID; // `channel:discord`
54
54
  /** `${VAR}` secret-ref form — identical to `config/io.ts`'s SECRET_REF_PATTERN. */
55
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;
56
68
  /** Read `channels.discord` loosely (schema keeps it open). */
57
69
  function discordChannelConfig(cfg) {
58
70
  return cfg.channels?.[CHANNEL_ID];
@@ -231,6 +243,18 @@ export function discordStreamThrottleMs(cfg) {
231
243
  export function discordSurfaceReasoning(cfg) {
232
244
  return discordChannelConfig(cfg)?.surfaceReasoning === true;
233
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
+ }
234
258
  /**
235
259
  * Resolve the idle-thread-session TTL in ms, or `null` when unset / disabled.
236
260
  * Accepts a number (ms) or a duration string (`"6h"`, `"30m"`, …). The cron
@@ -256,5 +280,70 @@ export function discordThreadIdleTtlMs(cfg) {
256
280
  const factor = mult[unit] ?? 1;
257
281
  return n * factor;
258
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
+ }
259
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, };
260
349
  //# sourceMappingURL=account-config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"account-config.js","sourceRoot":"","sources":["../../../../src/agents/channels/discord/account-config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"account-config.js","sourceRoot":"","sources":["../../../../src/agents/channels/discord/account-config.ts"],"names":[],"mappings":"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"}
@@ -19,8 +19,18 @@
19
19
  * (registered via REST application commands on connect). Unlike Slack, Discord's
20
20
  * command menu IS pushed programmatically — `nativeCommands: true`.
21
21
  */
22
+ import type { BrigadeConfig } from "../../../config/io.js";
22
23
  import { type ChannelAdapter, type ChannelCapabilities } from "../sdk.js";
23
- import { type ConnectDiscordArgs, type DiscordConnection } from "./connection.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;
24
34
  /** Adapter construction options — all optional for back-compat. */
25
35
  export interface CreateDiscordAdapterOptions {
26
36
  /** Per-account scope. Defaults to `"default"` (single-account). */
@@ -32,6 +42,19 @@ export interface CreateDiscordAdapterOptions {
32
42
  connectImpl?: (args: ConnectDiscordArgs) => Promise<DiscordConnection>;
33
43
  }
34
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;
35
58
  /**
36
59
  * Synthesise the agent-facing note for an inbound reaction. The reaction itself
37
60
  * carries no text, so the note ("<who> reacted :emoji: to message <id>") is what
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/discord/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAOH,OAAO,EAGN,KAAK,cAAc,EAEnB,KAAK,mBAAmB,EAQxB,MAAM,WAAW,CAAC;AAgBnB,OAAO,EAAkB,KAAK,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAQlG,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,CA4c3F;AAED;;;;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"}
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"}
@@ -24,20 +24,62 @@ import { loadConfig } from "../../../core/config.js";
24
24
  // contract + shared helpers. Contract types + `chunkText` + `buildBundledCommands`
25
25
  // come from one place instead of scattered paths.
26
26
  import { buildBundledCommands, chunkText, } from "../sdk.js";
27
- import { discordChannelEnabled, discordLiveStreamEnabled, discordStreamThrottleMs, discordSurfaceReasoning, listDiscordAccountIds, resolveDiscordBotToken, resolveDiscordProxyUrl, DISCORD_CHANNEL_ID, DISCORD_DEFAULT_ACCOUNT_ID, } from "./account-config.js";
27
+ import { readAllowFrom } from "../access-control/store.js";
28
+ import { discordChannelEnabled, discordLiveStreamEnabled, discordReactionNotifications, discordStreamThrottleMs, discordSurfaceReasoning, listDiscordAccountIds, resolveDiscordAutoThread, resolveDiscordBotToken, resolveDiscordPresence, resolveDiscordProxyUrl, DISCORD_CHANNEL_ID, DISCORD_DEFAULT_ACCOUNT_ID, } from "./account-config.js";
28
29
  import { resolveDiscordApprover } from "./approval-authorize.js";
29
30
  import { buildDiscordApprovalMessage } from "./approval-native.js";
30
31
  import { buildDiscordButtonRows } from "./components.js";
31
32
  import { buildDiscordCommandManifest } from "./command-menu.js";
32
- import { connectDiscord } from "./connection.js";
33
+ import { connectDiscord, sanitizeThreadName, } from "./connection.js";
34
+ import { resolveDiscordHandle } from "./directory-cache.js";
33
35
  import { createDraftStream } from "./draft-stream.js";
34
- import { discordTextIsEmpty, markdownToDiscord } from "./format.js";
36
+ import { discordTextIsEmpty, markdownToDiscord, rewriteKnownMentions } from "./format.js";
35
37
  import { splitDiscordReasoning } from "./reasoning-lane.js";
36
38
  /** Discord's per-message text limit (chars) for chunked sends. */
37
39
  const DISCORD_TEXT_LIMIT = 2_000;
40
+ /**
41
+ * Map a resolved presence config into the discord.js `PresenceData` payload the
42
+ * connection applies on (re)connect (Phase 5). A `custom` activity (type 4)
43
+ * carries its text in the `state` field (Discord renders custom status from the
44
+ * state); every other type uses `name`. A `streaming` activity (type 1) adds the
45
+ * `url`. Returns `null` when no presence is configured.
46
+ */
47
+ export function mapDiscordPresencePayload(presence) {
48
+ if (!presence)
49
+ return null;
50
+ const payload = { status: presence.status };
51
+ if (presence.activityTypeCode !== undefined) {
52
+ const isCustom = presence.activityTypeCode === 4;
53
+ const text = presence.activityText ?? "";
54
+ const activity = {
55
+ // A custom activity needs a non-empty `name` per Discord; the visible text
56
+ // rides in `state`. Other types put the text in `name`.
57
+ name: isCustom ? "Custom Status" : text,
58
+ type: presence.activityTypeCode,
59
+ };
60
+ if (isCustom && text)
61
+ activity.state = text;
62
+ if (presence.activityTypeCode === 1 && presence.activityUrl)
63
+ activity.url = presence.activityUrl;
64
+ payload.activities = [activity];
65
+ }
66
+ return payload;
67
+ }
38
68
  export function createDiscordAdapter(opts = {}) {
39
69
  const accountId = opts.accountId?.trim() || DISCORD_DEFAULT_ACCOUNT_ID;
40
70
  const connectImpl = opts.connectImpl ?? connectDiscord;
71
+ // Resolver bound to THIS adapter's account, handed to `rewriteKnownMentions`
72
+ // so a plain `@handle` the agent typed becomes a `<@id>` ping when (and only
73
+ // when) the inbound directory cache has seen that handle for this account.
74
+ const resolveMention = (handle) => resolveDiscordHandle(accountId, handle);
75
+ // Render an outbound chunk: rewrite known `@handle` mentions to `<@id>` FIRST
76
+ // (so the converter sees a real mention token), then markdown→Discord, with the
77
+ // raw chunk as the empty-render fallback (a syntax-only chunk must still send).
78
+ const renderOutbound = (chunk) => {
79
+ const withMentions = rewriteKnownMentions(chunk, resolveMention);
80
+ const rendered = markdownToDiscord(withMentions);
81
+ return discordTextIsEmpty(rendered) ? withMentions : rendered;
82
+ };
41
83
  let connection = null;
42
84
  // The ChannelStartContext doesn't carry the config, but the manager ALWAYS
43
85
  // calls `isConfigured(cfg, env)` immediately before `start(ctx)` — so we
@@ -52,6 +94,60 @@ export function createDiscordAdapter(opts = {}) {
52
94
  // only recovery is `brigade channels add --channel discord` with a new token.
53
95
  let connected = false;
54
96
  let tokenInvalid = false;
97
+ /**
98
+ * Cheap SYNCHRONOUS gate: should this inbound trigger autoThread creation? True
99
+ * only when the feature is on, the message isn't already in a thread, and it's
100
+ * a guild text message carrying text + the ids needed to anchor a thread. Keeps
101
+ * the non-autoThread inbound path fully synchronous.
102
+ */
103
+ const shouldAutoThread = (msg) => {
104
+ if (msg.threadId)
105
+ return false; // already in a thread
106
+ const cfg = lastConfig;
107
+ if (!cfg || !connection)
108
+ return false;
109
+ if (!resolveDiscordAutoThread(cfg).enabled)
110
+ return false;
111
+ // Guild text message only (a DM has no guildId; a reaction/callback carries no text).
112
+ return Boolean((msg.guildId ?? "").trim() &&
113
+ (msg.conversationId ?? "").trim() &&
114
+ (msg.messageId ?? "").trim() &&
115
+ (msg.text ?? "").trim());
116
+ };
117
+ /**
118
+ * Phase 5 autoThread: create a thread off an inbound guild text message and
119
+ * return the new thread id (caller guards with {@link shouldAutoThread}).
120
+ * Returns the message's existing `threadId` (undefined) on any failure so the
121
+ * reply stays un-threaded.
122
+ *
123
+ * Thread naming: `"first-message"` uses the inbound's first line; `"generated"`
124
+ * would use an LLM-titled name, but Brigade has no simple-completion helper —
125
+ * so `"generated"` FALLS BACK to the first-message name here (no completion
126
+ * runtime is built).
127
+ */
128
+ const maybeAutoThread = async (msg) => {
129
+ const existing = msg.threadId;
130
+ const cfg = lastConfig;
131
+ if (!cfg || !connection)
132
+ return existing;
133
+ const auto = resolveDiscordAutoThread(cfg);
134
+ const channelId = (msg.conversationId ?? "").trim();
135
+ const messageId = (msg.messageId ?? "").trim();
136
+ const text = (msg.text ?? "").trim();
137
+ // Name source: first-message (or generated → fallback to first-message until
138
+ // a completion runtime exists).
139
+ const name = sanitizeThreadName(text, messageId);
140
+ try {
141
+ const created = await connection.createThreadFromMessage(channelId, messageId, {
142
+ name,
143
+ autoArchiveMinutes: auto.autoArchiveMinutes,
144
+ });
145
+ return created ?? existing;
146
+ }
147
+ catch {
148
+ return existing;
149
+ }
150
+ };
55
151
  const adapter = {
56
152
  id: DISCORD_CHANNEL_ID,
57
153
  label: "Discord",
@@ -88,9 +184,12 @@ export function createDiscordAdapter(opts = {}) {
88
184
  // The native slash-command manifest, derived from Brigade's central
89
185
  // channel commands; registered right after the connection is live (below).
90
186
  const commandManifest = buildDiscordCommandManifest(buildBundledCommands(adapter));
187
+ // Resolve the optional bot presence to apply on (re)connect (Phase 5).
188
+ const presencePayload = mapDiscordPresencePayload(resolveDiscordPresence(cfg, accountId));
91
189
  const conn = await connectImpl({
92
190
  botToken,
93
191
  ...(proxyUrl ? { proxyUrl } : {}),
192
+ ...(presencePayload ? { presence: presencePayload } : {}),
94
193
  accountId,
95
194
  log: ctx.log,
96
195
  onConnected: () => {
@@ -106,40 +205,62 @@ export function createDiscordAdapter(opts = {}) {
106
205
  ctx.onLoggedOut?.();
107
206
  },
108
207
  onMessage: (msg) => {
109
- void ctx.onInbound({
110
- channel: DISCORD_CHANNEL_ID,
111
- accountId,
112
- conversationId: msg.conversationId,
113
- messageId: msg.messageId,
114
- messageTimestampMs: msg.messageTimestampMs,
115
- from: msg.from,
116
- fromName: msg.fromName,
117
- text: msg.text,
118
- chatType: msg.chatType,
119
- isGroup: msg.chatType === "group",
120
- threadId: msg.threadId,
121
- // Discord routes on guildId + member role ids (NOT teamId — that
122
- // is Slack's workspace tier; setting it would risk colliding with
123
- // a Slack team binding).
124
- guildId: msg.guildId,
125
- memberRoleIds: msg.memberRoleIds,
126
- mentions: msg.mentions,
127
- replyTo: msg.replyTo,
128
- // Edit provenance rides through so the central pipeline / agent see
129
- // "this was an edit".
130
- ...(msg.edited ? { edited: true } : {}),
131
- // Deferred media thunk rides through untouched — the pipeline
132
- // resolves it only after the access gate admits the sender.
133
- resolveMedia: msg.resolveMedia,
134
- raw: msg.raw,
135
- });
208
+ // Build the inbound with a resolved thread id. The dispatch is
209
+ // SYNCHRONOUS when no thread needs creating (the common path, unchanged
210
+ // behavior); only autoThread creation defers to a microtask.
211
+ const dispatch = (threadId) => {
212
+ void ctx.onInbound({
213
+ channel: DISCORD_CHANNEL_ID,
214
+ accountId,
215
+ conversationId: msg.conversationId,
216
+ messageId: msg.messageId,
217
+ messageTimestampMs: msg.messageTimestampMs,
218
+ from: msg.from,
219
+ fromName: msg.fromName,
220
+ text: msg.text,
221
+ chatType: msg.chatType,
222
+ isGroup: msg.chatType === "group",
223
+ threadId,
224
+ // Discord routes on guildId + member role ids (NOT teamId — that
225
+ // is Slack's workspace tier; setting it would risk colliding with
226
+ // a Slack team binding).
227
+ guildId: msg.guildId,
228
+ memberRoleIds: msg.memberRoleIds,
229
+ mentions: msg.mentions,
230
+ replyTo: msg.replyTo,
231
+ // Edit provenance rides through so the central pipeline / agent see
232
+ // "this was an edit".
233
+ ...(msg.edited ? { edited: true } : {}),
234
+ // Deferred media thunk rides through untouched — the pipeline
235
+ // resolves it only after the access gate admits the sender.
236
+ resolveMedia: msg.resolveMedia,
237
+ raw: msg.raw,
238
+ });
239
+ };
240
+ // Phase 5 autoThread: when enabled (and this is a fresh guild text
241
+ // message), spawn a thread off the message and route the reply into it.
242
+ // `shouldAutoThread` is a cheap synchronous gate so the non-autoThread
243
+ // path stays fully synchronous.
244
+ if (shouldAutoThread(msg)) {
245
+ void maybeAutoThread(msg).then(dispatch).catch(() => dispatch(msg.threadId));
246
+ }
247
+ else {
248
+ dispatch(msg.threadId);
249
+ }
136
250
  },
137
251
  // Inbound reaction → synthesise a short note and route it through the
138
252
  // SAME inbound pipeline as a normal message so the access gate + routing
139
253
  // apply uniformly. The note carries the added emoji(s) + the target id.
254
+ //
255
+ // GATED by `channels.discord.reactionNotifications` (default "own") so a
256
+ // stranger's reaction in an admitted channel no longer spams the agent:
257
+ // off → drop all; own → only reactions on the bot's own messages;
258
+ // all → route every reaction; allowlist → only allow-listed reactors.
140
259
  onReaction: (msg) => {
141
260
  if (!msg.reaction)
142
261
  return;
262
+ if (!shouldNotifyReaction(msg, lastConfig, connection?.selfId() ?? undefined, accountId))
263
+ return;
143
264
  const note = buildReactionNote(msg.reaction.emojis, msg.reaction.targetMessageId, msg.fromName);
144
265
  void ctx.onInbound({
145
266
  channel: DISCORD_CHANNEL_ID,
@@ -241,14 +362,15 @@ export function createDiscordAdapter(opts = {}) {
241
362
  // convert each chunk to Discord markup and send. A chunk whose rendered
242
363
  // markup is empty (syntax-only) is re-sent as the raw chunk.
243
364
  const chunks = chunkText(text, { limit: DISCORD_TEXT_LIMIT });
365
+ // A silent send rides through on every chunk (SuppressNotifications).
366
+ const silentOpt = opts?.silent ? { silent: true } : {};
244
367
  let first = true;
245
368
  for (const chunk of chunks) {
246
369
  const replyOpt = first && replyToMessageId ? { replyToMessageId } : {};
247
- const rendered = markdownToDiscord(chunk);
248
- const body = discordTextIsEmpty(rendered) ? chunk : rendered;
370
+ const body = renderOutbound(chunk);
249
371
  if (body.trim().length === 0)
250
372
  continue;
251
- await connection.sendText(conversationId, body, { ...sendExtras, ...replyOpt });
373
+ await connection.sendText(conversationId, body, { ...sendExtras, ...silentOpt, ...replyOpt });
252
374
  first = false;
253
375
  }
254
376
  },
@@ -290,11 +412,10 @@ export function createDiscordAdapter(opts = {}) {
290
412
  ...(threadId !== undefined ? { threadId } : {}),
291
413
  throttleMs: discordStreamThrottleMs(cfg),
292
414
  maxChars: DISCORD_TEXT_LIMIT,
293
- // Render each draft chunk to Discord markup; fall back to the plain chunk
294
- // when it renders empty (syntax-only).
415
+ // Render each draft chunk to Discord markup (incl. known-mention rewrite);
416
+ // fall back to the plain chunk when it renders empty (syntax-only).
295
417
  renderText: (chunk) => {
296
- const rendered = markdownToDiscord(chunk);
297
- return { text: discordTextIsEmpty(rendered) ? chunk : rendered };
418
+ return { text: renderOutbound(chunk) };
298
419
  },
299
420
  });
300
421
  return {
@@ -432,14 +553,19 @@ export function createDiscordAdapter(opts = {}) {
432
553
  try {
433
554
  switch (a.kind) {
434
555
  case "edit": {
435
- const rendered = markdownToDiscord(a.text);
436
- const body = discordTextIsEmpty(rendered) ? a.text : rendered;
556
+ const body = renderOutbound(a.text);
437
557
  await connection.editMessageText(p.conversationId, a.messageId, body);
438
558
  return { ok: true, messageId: a.messageId };
439
559
  }
440
560
  case "delete":
441
561
  await connection.deleteMessage(p.conversationId, a.messageId);
442
562
  return { ok: true, messageId: a.messageId };
563
+ case "pin":
564
+ await connection.pinMessage(p.conversationId, a.messageId);
565
+ return { ok: true, messageId: a.messageId };
566
+ case "unpin":
567
+ await connection.unpinMessage(p.conversationId, a.messageId);
568
+ return { ok: true, messageId: a.messageId };
443
569
  case "react":
444
570
  // An EMPTY emoji means "clear" (parity with WhatsApp/Telegram/Slack):
445
571
  // remove the bot's OWN reactions on this message; a non-empty emoji
@@ -467,8 +593,7 @@ export function createDiscordAdapter(opts = {}) {
467
593
  if (!rows) {
468
594
  return { ok: false, error: "no usable buttons (each needs a label + a data token ≤ 100 chars)" };
469
595
  }
470
- const rendered = markdownToDiscord(a.text);
471
- const body = discordTextIsEmpty(rendered) ? a.text : rendered;
596
+ const body = renderOutbound(a.text);
472
597
  const sent = await connection.sendInteractive(p.conversationId, body, rows, {
473
598
  ...(a.threadId !== undefined ? { threadId: a.threadId } : {}),
474
599
  });
@@ -494,6 +619,48 @@ export function createDiscordAdapter(opts = {}) {
494
619
  };
495
620
  return adapter;
496
621
  }
622
+ /**
623
+ * Decide whether an inbound reaction-add should wake the agent, per the
624
+ * `channels.discord.reactionNotifications` mode (default `"own"`):
625
+ * - `"off"` → never;
626
+ * - `"own"` → only when the reacted message was authored by the bot
627
+ * (`reaction.targetAuthorId === selfId`);
628
+ * - `"all"` → always (legacy behavior);
629
+ * - `"allowlist"` → only when the reactor (`msg.from`) is on the channel
630
+ * allow-list — the central store list ∪ config `allowFrom`.
631
+ * A null config defensively falls back to `"own"`. Reaction-REMOVE is unaffected
632
+ * (handled in the connection's dedupe-release path).
633
+ */
634
+ export function shouldNotifyReaction(msg, cfg, selfId, accountId) {
635
+ const mode = cfg ? discordReactionNotifications(cfg) : "own";
636
+ switch (mode) {
637
+ case "off":
638
+ return false;
639
+ case "all":
640
+ return true;
641
+ case "allowlist": {
642
+ const reactor = msg.from?.trim();
643
+ if (!reactor)
644
+ return false;
645
+ const acct = accountId?.trim() || undefined;
646
+ const storeAllow = readAllowFrom(DISCORD_CHANNEL_ID, acct);
647
+ const configAllow = readDiscordAllowFrom(cfg);
648
+ const allow = new Set([...storeAllow, ...configAllow].map((id) => id.trim()).filter(Boolean));
649
+ return allow.has(reactor);
650
+ }
651
+ case "own":
652
+ default: {
653
+ const targetAuthor = msg.reaction?.targetAuthorId?.trim();
654
+ return Boolean(selfId && targetAuthor && targetAuthor === selfId.trim());
655
+ }
656
+ }
657
+ }
658
+ /** Read `channels.discord.allowFrom` (config-declared allow-list ids) defensively. */
659
+ function readDiscordAllowFrom(cfg) {
660
+ const slot = cfg?.channels?.[DISCORD_CHANNEL_ID];
661
+ const list = slot?.allowFrom;
662
+ return Array.isArray(list) ? list.map((x) => String(x)) : [];
663
+ }
497
664
  /**
498
665
  * Synthesise the agent-facing note for an inbound reaction. The reaction itself
499
666
  * carries no text, so the note ("<who> reacted :emoji: to message <id>") is what