@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,100 @@
1
+ /**
2
+ * Discord modal (form) building + submission decoding (Fix 3b).
3
+ *
4
+ * A modal is opened with `interaction.showModal(modal)` in response to a button
5
+ * press; on submit Discord delivers a `ModalSubmitInteraction` whose `fields`
6
+ * accessor yields each text input's value keyed by the field's custom_id. This
7
+ * module:
8
+ * - {@link buildDiscordModal} turns a registry {@link DiscordModalEntry} into a
9
+ * discord.js `ModalBuilder` (text inputs only — Discord's STABLE modals
10
+ * support only text inputs, which is correct for v1). It takes the discord.js
11
+ * builder constructors as an argument so a non-Discord boot never imports
12
+ * them and tests can inject lightweight fakes.
13
+ * - {@link extractModalFieldValues} reads the submitted values off a
14
+ * `ModalSubmitInteraction` defensively (pure — no discord.js).
15
+ * - {@link formatModalSubmissionText} renders a readable turn body from the
16
+ * entry's field labels + the submitted values (pure).
17
+ *
18
+ * The submission is routed as a NORMAL inbound message (`onMessage`) carrying the
19
+ * formatted text — a filled form is a typed turn, not a button tap — so the agent
20
+ * sees the labels + values exactly as a person would type them.
21
+ */
22
+ import { type DiscordModalEntry, type DiscordModalField } from "./modal-registry.js";
23
+ /** The custom_id key the modal itself carries: `modal:<modalId>`. */
24
+ export declare const DISCORD_MODAL_CUSTOM_ID_PREFIX = "modal:";
25
+ /** Wrap a modal id into the modal's custom_id marker. */
26
+ export declare function buildDiscordModalCustomId(modalId: string): string;
27
+ /** True when a pressed-button / submitted-modal custom_id is a modal marker. */
28
+ export declare function isDiscordModalCustomId(value: string | undefined): boolean;
29
+ /** Strip the marker, returning the modal id (or "" when not a modal marker). */
30
+ export declare function decodeDiscordModalCustomId(value: string | undefined): string;
31
+ /**
32
+ * The discord.js builder constructors {@link buildDiscordModal} needs. Injected
33
+ * (rather than imported) so a non-Discord boot never loads discord.js and tests
34
+ * inject fakes. The real values are `discord.ModalBuilder`, `ActionRowBuilder`,
35
+ * and `TextInputBuilder`.
36
+ */
37
+ export interface DiscordModalBuilderDeps {
38
+ ModalBuilder: new () => DiscordModalBuilderLike;
39
+ ActionRowBuilder: new () => DiscordModalRowBuilderLike;
40
+ TextInputBuilder: new () => DiscordTextInputBuilderLike;
41
+ }
42
+ interface DiscordModalBuilderLike {
43
+ setCustomId(id: string): this;
44
+ setTitle(title: string): this;
45
+ addComponents(...rows: unknown[]): this;
46
+ }
47
+ interface DiscordModalRowBuilderLike {
48
+ addComponents(...inputs: unknown[]): this;
49
+ }
50
+ interface DiscordTextInputBuilderLike {
51
+ setCustomId(id: string): this;
52
+ setLabel(label: string): this;
53
+ setStyle(style: number): this;
54
+ setRequired(required: boolean): this;
55
+ setPlaceholder(placeholder: string): this;
56
+ }
57
+ /**
58
+ * Build a discord.js `ModalBuilder` from a registry entry. Each field becomes a
59
+ * `TextInputBuilder` in its own `ActionRowBuilder` (Discord requires one input
60
+ * per row). Title + labels are capped to Discord's limits. `title` is the modal
61
+ * heading; pass it explicitly since the registry stores the form fields, not the
62
+ * heading.
63
+ */
64
+ export declare function buildDiscordModal(deps: DiscordModalBuilderDeps, params: {
65
+ modalId: string;
66
+ title: string;
67
+ entry: DiscordModalEntry;
68
+ }): DiscordModalBuilderLike;
69
+ /** The minimal `ModalSubmitInteraction.fields` surface we read. */
70
+ interface DiscordModalSubmitFieldsLike {
71
+ /** discord.js: returns the submitted string value for a field custom_id. */
72
+ getTextInputValue?: (customId: string) => string;
73
+ /** Some shapes expose a raw field collection; read it as a fallback. */
74
+ fields?: Map<string, {
75
+ value?: string;
76
+ }> | Iterable<{
77
+ customId?: string;
78
+ value?: string;
79
+ }>;
80
+ }
81
+ /**
82
+ * Pull the submitted `{ fieldId → value }` map off a modal-submit interaction,
83
+ * for the given entry's fields. Reads via `getTextInputValue` first (the stable
84
+ * discord.js accessor), falling back to a raw fields collection. Fully guarded —
85
+ * a missing value yields "".
86
+ */
87
+ export declare function extractModalFieldValues(interaction: {
88
+ fields?: DiscordModalSubmitFieldsLike;
89
+ } | undefined, fields: DiscordModalField[]): Record<string, string>;
90
+ /**
91
+ * Render a readable turn body from a modal submission. Each filled field is a
92
+ * `Label: value` line; an empty field is shown as `Label: (empty)` so the agent
93
+ * sees the full form. A leading `[form]` marker tags the turn like `[button]`
94
+ * does for a tap, so the agent can recognize a form submission.
95
+ */
96
+ export declare function formatModalSubmissionText(entry: {
97
+ fields: DiscordModalField[];
98
+ }, values: Record<string, string>): string;
99
+ export type { DiscordModalField };
100
+ //# sourceMappingURL=modals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modals.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/discord/modals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAA4B,KAAK,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAE/G,qEAAqE;AACrE,eAAO,MAAM,8BAA8B,WAAW,CAAC;AAEvD,yDAAyD;AACzD,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,gFAAgF;AAChF,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEzE;AAED,gFAAgF;AAChF,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAG5E;AAMD;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACvC,YAAY,EAAE,UAAU,uBAAuB,CAAC;IAChD,gBAAgB,EAAE,UAAU,0BAA0B,CAAC;IACvD,gBAAgB,EAAE,UAAU,2BAA2B,CAAC;CACxD;AAED,UAAU,uBAAuB;IAChC,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CACxC;AACD,UAAU,0BAA0B;IACnC,aAAa,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CAC1C;AACD,UAAU,2BAA2B;IACpC,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;IACrC,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1C;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAChC,IAAI,EAAE,uBAAuB,EAC7B,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,iBAAiB,CAAA;CAAE,GAClE,uBAAuB,CAiBzB;AAED,mEAAmE;AACnE,UAAU,4BAA4B;IACrC,4EAA4E;IAC5E,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IACjD,wEAAwE;IACxE,MAAM,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,QAAQ,CAAC;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC3F;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACtC,WAAW,EAAE;IAAE,MAAM,CAAC,EAAE,4BAA4B,CAAA;CAAE,GAAG,SAAS,EAClE,MAAM,EAAE,iBAAiB,EAAE,GACzB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA6BxB;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACxC,KAAK,EAAE;IAAE,MAAM,EAAE,iBAAiB,EAAE,CAAA;CAAE,EACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC5B,MAAM,CAQR;AAED,YAAY,EAAE,iBAAiB,EAAE,CAAC"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Discord modal (form) building + submission decoding (Fix 3b).
3
+ *
4
+ * A modal is opened with `interaction.showModal(modal)` in response to a button
5
+ * press; on submit Discord delivers a `ModalSubmitInteraction` whose `fields`
6
+ * accessor yields each text input's value keyed by the field's custom_id. This
7
+ * module:
8
+ * - {@link buildDiscordModal} turns a registry {@link DiscordModalEntry} into a
9
+ * discord.js `ModalBuilder` (text inputs only — Discord's STABLE modals
10
+ * support only text inputs, which is correct for v1). It takes the discord.js
11
+ * builder constructors as an argument so a non-Discord boot never imports
12
+ * them and tests can inject lightweight fakes.
13
+ * - {@link extractModalFieldValues} reads the submitted values off a
14
+ * `ModalSubmitInteraction` defensively (pure — no discord.js).
15
+ * - {@link formatModalSubmissionText} renders a readable turn body from the
16
+ * entry's field labels + the submitted values (pure).
17
+ *
18
+ * The submission is routed as a NORMAL inbound message (`onMessage`) carrying the
19
+ * formatted text — a filled form is a typed turn, not a button tap — so the agent
20
+ * sees the labels + values exactly as a person would type them.
21
+ */
22
+ import { DISCORD_TEXT_INPUT_STYLE } from "./modal-registry.js";
23
+ /** The custom_id key the modal itself carries: `modal:<modalId>`. */
24
+ export const DISCORD_MODAL_CUSTOM_ID_PREFIX = "modal:";
25
+ /** Wrap a modal id into the modal's custom_id marker. */
26
+ export function buildDiscordModalCustomId(modalId) {
27
+ return `${DISCORD_MODAL_CUSTOM_ID_PREFIX}${modalId}`;
28
+ }
29
+ /** True when a pressed-button / submitted-modal custom_id is a modal marker. */
30
+ export function isDiscordModalCustomId(value) {
31
+ return typeof value === "string" && value.startsWith(DISCORD_MODAL_CUSTOM_ID_PREFIX);
32
+ }
33
+ /** Strip the marker, returning the modal id (or "" when not a modal marker). */
34
+ export function decodeDiscordModalCustomId(value) {
35
+ if (!isDiscordModalCustomId(value))
36
+ return "";
37
+ return value.slice(DISCORD_MODAL_CUSTOM_ID_PREFIX.length);
38
+ }
39
+ /** Discord caps a modal title at 45 chars + a text-input label at 45 chars. */
40
+ const DISCORD_MODAL_TITLE_MAX = 45;
41
+ const DISCORD_MODAL_LABEL_MAX = 45;
42
+ /**
43
+ * Build a discord.js `ModalBuilder` from a registry entry. Each field becomes a
44
+ * `TextInputBuilder` in its own `ActionRowBuilder` (Discord requires one input
45
+ * per row). Title + labels are capped to Discord's limits. `title` is the modal
46
+ * heading; pass it explicitly since the registry stores the form fields, not the
47
+ * heading.
48
+ */
49
+ export function buildDiscordModal(deps, params) {
50
+ const modal = new deps.ModalBuilder()
51
+ .setCustomId(buildDiscordModalCustomId(params.modalId))
52
+ .setTitle((params.title || "Form").slice(0, DISCORD_MODAL_TITLE_MAX));
53
+ const rows = [];
54
+ for (const field of params.entry.fields) {
55
+ const input = new deps.TextInputBuilder()
56
+ .setCustomId(field.id)
57
+ .setLabel((field.label || field.id).slice(0, DISCORD_MODAL_LABEL_MAX))
58
+ .setStyle(field.style === "paragraph" ? DISCORD_TEXT_INPUT_STYLE.paragraph : DISCORD_TEXT_INPUT_STYLE.short)
59
+ .setRequired(field.required !== false);
60
+ if (field.placeholder)
61
+ input.setPlaceholder(field.placeholder);
62
+ const row = new deps.ActionRowBuilder().addComponents(input);
63
+ rows.push(row);
64
+ }
65
+ modal.addComponents(...rows);
66
+ return modal;
67
+ }
68
+ /**
69
+ * Pull the submitted `{ fieldId → value }` map off a modal-submit interaction,
70
+ * for the given entry's fields. Reads via `getTextInputValue` first (the stable
71
+ * discord.js accessor), falling back to a raw fields collection. Fully guarded —
72
+ * a missing value yields "".
73
+ */
74
+ export function extractModalFieldValues(interaction, fields) {
75
+ const out = {};
76
+ const accessor = interaction?.fields;
77
+ // Build a fallback id→value map from a raw collection once, if present.
78
+ const fallback = new Map();
79
+ const rawFields = accessor?.fields;
80
+ if (rawFields) {
81
+ if (rawFields instanceof Map) {
82
+ for (const [id, v] of rawFields)
83
+ fallback.set(id, typeof v?.value === "string" ? v.value : "");
84
+ }
85
+ else {
86
+ for (const v of rawFields) {
87
+ if (typeof v?.customId === "string")
88
+ fallback.set(v.customId, typeof v.value === "string" ? v.value : "");
89
+ }
90
+ }
91
+ }
92
+ for (const field of fields) {
93
+ let value = "";
94
+ if (typeof accessor?.getTextInputValue === "function") {
95
+ try {
96
+ value = accessor.getTextInputValue(field.id) ?? "";
97
+ }
98
+ catch {
99
+ value = fallback.get(field.id) ?? "";
100
+ }
101
+ }
102
+ else {
103
+ value = fallback.get(field.id) ?? "";
104
+ }
105
+ out[field.id] = typeof value === "string" ? value : "";
106
+ }
107
+ return out;
108
+ }
109
+ /**
110
+ * Render a readable turn body from a modal submission. Each filled field is a
111
+ * `Label: value` line; an empty field is shown as `Label: (empty)` so the agent
112
+ * sees the full form. A leading `[form]` marker tags the turn like `[button]`
113
+ * does for a tap, so the agent can recognize a form submission.
114
+ */
115
+ export function formatModalSubmissionText(entry, values) {
116
+ const lines = ["[form]"];
117
+ for (const field of entry.fields) {
118
+ const raw = values[field.id];
119
+ const value = typeof raw === "string" && raw.trim().length > 0 ? raw.trim() : "(empty)";
120
+ lines.push(`${field.label || field.id}: ${value}`);
121
+ }
122
+ return lines.join("\n");
123
+ }
124
+ //# sourceMappingURL=modals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modals.js","sourceRoot":"","sources":["../../../../src/agents/channels/discord/modals.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Discord extension module.
3
+ *
4
+ * Registers the Discord channel adapter through the seam. The loader gates it by
5
+ * the usual extension config (`extensions.disabled` / `entries`), and the
6
+ * adapter itself only starts when `channels.discord.enabled` is true AND a bot
7
+ * token resolves — so bundling this module is inert until the operator opts in.
8
+ *
9
+ * Unlike Slack's module, Discord registers NO gateway HTTP route: the Gateway
10
+ * (WebSocket) is the only inbound transport (no public URL needed, analogous to
11
+ * Slack Socket Mode / Telegram long-polling), so there is no events-mode webhook
12
+ * to wire. Discord mirror of `telegram/module.ts` (the polling-only shape).
13
+ */
14
+ export declare const discordModule: import("../sdk.js").BrigadeModule;
15
+ //# sourceMappingURL=module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/discord/module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,eAAO,MAAM,aAAa,mCAKxB,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Discord extension module.
3
+ *
4
+ * Registers the Discord channel adapter through the seam. The loader gates it by
5
+ * the usual extension config (`extensions.disabled` / `entries`), and the
6
+ * adapter itself only starts when `channels.discord.enabled` is true AND a bot
7
+ * token resolves — so bundling this module is inert until the operator opts in.
8
+ *
9
+ * Unlike Slack's module, Discord registers NO gateway HTTP route: the Gateway
10
+ * (WebSocket) is the only inbound transport (no public URL needed, analogous to
11
+ * Slack Socket Mode / Telegram long-polling), so there is no events-mode webhook
12
+ * to wire. Discord mirror of `telegram/module.ts` (the polling-only shape).
13
+ */
14
+ import { defineModule } from "../sdk.js";
15
+ import { createDiscordAdapter } from "./adapter.js";
16
+ export const discordModule = defineModule({
17
+ id: "discord",
18
+ register(b) {
19
+ b.channel(createDiscordAdapter());
20
+ },
21
+ });
22
+ //# sourceMappingURL=module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.js","sourceRoot":"","sources":["../../../../src/agents/channels/discord/module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,MAAM,CAAC,MAAM,aAAa,GAAG,YAAY,CAAC;IACzC,EAAE,EAAE,SAAS;IACb,QAAQ,CAAC,CAAC;QACT,CAAC,CAAC,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IACnC,CAAC;CACD,CAAC,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Discord channel-permission audit — the #2 Discord footgun after the MESSAGE
3
+ * CONTENT intent.
4
+ *
5
+ * A bot can be "connected" and still silently fail to post because its role
6
+ * lacks `View Channel` + `Send Messages` in a specific channel (or a channel
7
+ * permission OVERWRITE denies it). This module computes the bot's EFFECTIVE
8
+ * permissions per channel the same way Discord does — base @everyone + the
9
+ * bot's role permissions, then the channel's permission overwrites (deny then
10
+ * allow, applied @everyone → roles → member) — and reports which channels are
11
+ * missing the two required bits.
12
+ *
13
+ * Self-contained REST (no `discord.js`): `GET /channels/{id}` →
14
+ * `GET /guilds/{guildId}` (roles) → `GET /guilds/{guildId}/members/{botId}`
15
+ * (the bot's roles), plus a one-time `GET /users/@me` for the bot id. Injectable
16
+ * fetch (tests stub it); never throws — a per-channel failure surfaces as an
17
+ * `error` row, never an exception. Only NUMERIC ids are audited; a non-numeric
18
+ * key is reported unresolved so the operator fixes the config.
19
+ */
20
+ /** Per-channel audit result. */
21
+ export interface DiscordChannelPermissionResult {
22
+ channelId: string;
23
+ /** True when the bot has every required bit (or Administrator). */
24
+ ok: boolean;
25
+ /** Required permission names the bot is MISSING (empty when ok). */
26
+ missingRequired: string[];
27
+ /** Best-effort error when the channel couldn't be evaluated. */
28
+ error?: string;
29
+ }
30
+ /** Overall audit result. */
31
+ export interface DiscordPermissionAuditResult {
32
+ channels: DiscordChannelPermissionResult[];
33
+ /** Count of supplied ids that weren't numeric snowflakes (can't be audited). */
34
+ unresolvedChannels: number;
35
+ }
36
+ /**
37
+ * Audit the bot's `ViewChannel` + `SendMessages` in each supplied channel id.
38
+ * Non-numeric ids are counted under `unresolvedChannels` and skipped (Discord
39
+ * ids are numeric snowflakes — a name/slug key can't be resolved via REST). The
40
+ * bot user id is fetched once via `/users/@me`. Best-effort + never throws.
41
+ */
42
+ export declare function auditDiscordChannelPermissions(token: string, channelIds: string[], fetchImpl?: typeof fetch): Promise<DiscordPermissionAuditResult>;
43
+ //# sourceMappingURL=permission-audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permission-audit.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/discord/permission-audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAeH,gCAAgC;AAChC,MAAM,WAAW,8BAA8B;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,EAAE,EAAE,OAAO,CAAC;IACZ,oEAAoE;IACpE,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,4BAA4B;AAC5B,MAAM,WAAW,4BAA4B;IAC5C,QAAQ,EAAE,8BAA8B,EAAE,CAAC;IAC3C,gFAAgF;IAChF,kBAAkB,EAAE,MAAM,CAAC;CAC3B;AA+HD;;;;;GAKG;AACH,wBAAsB,8BAA8B,CACnD,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAAE,EACpB,SAAS,GAAE,OAAO,KAAa,GAC7B,OAAO,CAAC,4BAA4B,CAAC,CAuDvC"}
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Discord channel-permission audit — the #2 Discord footgun after the MESSAGE
3
+ * CONTENT intent.
4
+ *
5
+ * A bot can be "connected" and still silently fail to post because its role
6
+ * lacks `View Channel` + `Send Messages` in a specific channel (or a channel
7
+ * permission OVERWRITE denies it). This module computes the bot's EFFECTIVE
8
+ * permissions per channel the same way Discord does — base @everyone + the
9
+ * bot's role permissions, then the channel's permission overwrites (deny then
10
+ * allow, applied @everyone → roles → member) — and reports which channels are
11
+ * missing the two required bits.
12
+ *
13
+ * Self-contained REST (no `discord.js`): `GET /channels/{id}` →
14
+ * `GET /guilds/{guildId}` (roles) → `GET /guilds/{guildId}/members/{botId}`
15
+ * (the bot's roles), plus a one-time `GET /users/@me` for the bot id. Injectable
16
+ * fetch (tests stub it); never throws — a per-channel failure surfaces as an
17
+ * `error` row, never an exception. Only NUMERIC ids are audited; a non-numeric
18
+ * key is reported unresolved so the operator fixes the config.
19
+ */
20
+ /** Discord permission bits (bigint). */
21
+ const PERM_ADMINISTRATOR = 1n << 3n;
22
+ const PERM_VIEW_CHANNEL = 1n << 10n;
23
+ const PERM_SEND_MESSAGES = 1n << 11n;
24
+ const DISCORD_API_BASE = "https://discord.com/api/v10";
25
+ /** Required permissions a bot needs to operate in a channel. */
26
+ const REQUIRED = [
27
+ { bit: PERM_VIEW_CHANNEL, name: "ViewChannel" },
28
+ { bit: PERM_SEND_MESSAGES, name: "SendMessages" },
29
+ ];
30
+ /** A numeric snowflake id (Discord ids are decimal strings). */
31
+ function isNumericId(value) {
32
+ return /^\d+$/.test(value.trim());
33
+ }
34
+ /** Apply an overwrite's deny then allow to a running permission bitfield. */
35
+ function applyOverwrite(perms, ow) {
36
+ let next = perms;
37
+ if (ow.deny) {
38
+ try {
39
+ next &= ~BigInt(ow.deny);
40
+ }
41
+ catch {
42
+ /* malformed bitstring — ignore */
43
+ }
44
+ }
45
+ if (ow.allow) {
46
+ try {
47
+ next |= BigInt(ow.allow);
48
+ }
49
+ catch {
50
+ /* malformed bitstring — ignore */
51
+ }
52
+ }
53
+ return next;
54
+ }
55
+ /** Authenticated GET → parsed JSON object, or throws with a compact message. */
56
+ async function getJson(url, token, fetchImpl) {
57
+ const res = await fetchImpl(url, {
58
+ method: "GET",
59
+ headers: { Authorization: `Bot ${token}`, "content-type": "application/json" },
60
+ });
61
+ if (!res.ok) {
62
+ throw new Error(`HTTP ${res.status}`);
63
+ }
64
+ return (await res.json());
65
+ }
66
+ /**
67
+ * Compute the bot's effective permission bitfield in one channel, mirroring
68
+ * Discord's resolution order: base (@everyone role + the bot's roles), then
69
+ * @everyone overwrite, then the bot's role overwrites, then the bot's member
70
+ * overwrite. Administrator short-circuits to "all". Returns the bitfield.
71
+ */
72
+ function computeEffectivePermissions(params) {
73
+ const { botId, guildId, channel, guild, member } = params;
74
+ const rolesById = new Map();
75
+ for (const role of guild.roles ?? []) {
76
+ if (typeof role.id !== "string")
77
+ continue;
78
+ let bits = 0n;
79
+ try {
80
+ bits = role.permissions ? BigInt(role.permissions) : 0n;
81
+ }
82
+ catch {
83
+ bits = 0n;
84
+ }
85
+ rolesById.set(role.id, bits);
86
+ }
87
+ // Base = @everyone (role id === guildId) + each of the bot's roles.
88
+ let perms = rolesById.get(guildId) ?? 0n;
89
+ const memberRoleIds = Array.isArray(member.roles) ? member.roles : [];
90
+ for (const roleId of memberRoleIds) {
91
+ perms |= rolesById.get(roleId) ?? 0n;
92
+ }
93
+ // Administrator → all permissions, overwrites ignored.
94
+ if ((perms & PERM_ADMINISTRATOR) === PERM_ADMINISTRATOR) {
95
+ return ~0n;
96
+ }
97
+ const overwrites = Array.isArray(channel.permission_overwrites) ? channel.permission_overwrites : [];
98
+ // @everyone overwrite.
99
+ for (const ow of overwrites) {
100
+ if (ow.id === guildId)
101
+ perms = applyOverwrite(perms, ow);
102
+ }
103
+ // The bot's role overwrites (accumulate allow/deny across them).
104
+ let roleAllow = 0n;
105
+ let roleDeny = 0n;
106
+ for (const ow of overwrites) {
107
+ if (ow.type === 0 && ow.id && memberRoleIds.includes(ow.id)) {
108
+ try {
109
+ if (ow.deny)
110
+ roleDeny |= BigInt(ow.deny);
111
+ if (ow.allow)
112
+ roleAllow |= BigInt(ow.allow);
113
+ }
114
+ catch {
115
+ /* ignore malformed */
116
+ }
117
+ }
118
+ }
119
+ perms &= ~roleDeny;
120
+ perms |= roleAllow;
121
+ // The bot's member overwrite (highest precedence).
122
+ for (const ow of overwrites) {
123
+ if (ow.id === botId)
124
+ perms = applyOverwrite(perms, ow);
125
+ }
126
+ return perms;
127
+ }
128
+ /**
129
+ * Audit the bot's `ViewChannel` + `SendMessages` in each supplied channel id.
130
+ * Non-numeric ids are counted under `unresolvedChannels` and skipped (Discord
131
+ * ids are numeric snowflakes — a name/slug key can't be resolved via REST). The
132
+ * bot user id is fetched once via `/users/@me`. Best-effort + never throws.
133
+ */
134
+ export async function auditDiscordChannelPermissions(token, channelIds, fetchImpl = fetch) {
135
+ const clean = (token ?? "").trim();
136
+ const ids = (channelIds ?? []).map((c) => (c ?? "").trim()).filter(Boolean);
137
+ const numeric = ids.filter(isNumericId);
138
+ const unresolvedChannels = ids.length - numeric.length;
139
+ if (!clean || numeric.length === 0) {
140
+ return { channels: [], unresolvedChannels };
141
+ }
142
+ // Resolve the bot user id once (needed for the member overwrite + member fetch).
143
+ let botId = "";
144
+ try {
145
+ const me = await getJson(`${DISCORD_API_BASE}/users/@me`, clean, fetchImpl);
146
+ botId = typeof me?.id === "string" ? me.id : "";
147
+ }
148
+ catch {
149
+ botId = "";
150
+ }
151
+ if (!botId) {
152
+ return {
153
+ channels: numeric.map((channelId) => ({
154
+ channelId,
155
+ ok: false,
156
+ missingRequired: REQUIRED.map((r) => r.name),
157
+ error: "could not resolve bot identity (/users/@me failed)",
158
+ })),
159
+ unresolvedChannels,
160
+ };
161
+ }
162
+ const channels = [];
163
+ for (const channelId of numeric) {
164
+ try {
165
+ const channel = await getJson(`${DISCORD_API_BASE}/channels/${channelId}`, clean, fetchImpl);
166
+ const guildId = typeof channel.guild_id === "string" ? channel.guild_id : "";
167
+ if (!guildId) {
168
+ // A DM / group channel has no guild perms — treat as ok (the bot can
169
+ // always send to a DM it can fetch).
170
+ channels.push({ channelId, ok: true, missingRequired: [] });
171
+ continue;
172
+ }
173
+ const [guild, member] = await Promise.all([
174
+ getJson(`${DISCORD_API_BASE}/guilds/${guildId}`, clean, fetchImpl),
175
+ getJson(`${DISCORD_API_BASE}/guilds/${guildId}/members/${botId}`, clean, fetchImpl),
176
+ ]);
177
+ const perms = computeEffectivePermissions({ botId, guildId, channel, guild, member });
178
+ const missingRequired = REQUIRED.filter((r) => (perms & r.bit) !== r.bit).map((r) => r.name);
179
+ channels.push({ channelId, ok: missingRequired.length === 0, missingRequired });
180
+ }
181
+ catch (err) {
182
+ channels.push({
183
+ channelId,
184
+ ok: false,
185
+ missingRequired: REQUIRED.map((r) => r.name),
186
+ error: err instanceof Error ? err.message : String(err),
187
+ });
188
+ }
189
+ }
190
+ return { channels, unresolvedChannels };
191
+ }
192
+ //# sourceMappingURL=permission-audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permission-audit.js","sourceRoot":"","sources":["../../../../src/agents/channels/discord/permission-audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,wCAAwC;AACxC,MAAM,kBAAkB,GAAG,EAAE,IAAI,EAAE,CAAC;AACpC,MAAM,iBAAiB,GAAG,EAAE,IAAI,GAAG,CAAC;AACpC,MAAM,kBAAkB,GAAG,EAAE,IAAI,GAAG,CAAC;AAErC,MAAM,gBAAgB,GAAG,6BAA6B,CAAC;AAEvD,gEAAgE;AAChE,MAAM,QAAQ,GAAyC;IACtD,EAAE,GAAG,EAAE,iBAAiB,EAAE,IAAI,EAAE,aAAa,EAAE;IAC/C,EAAE,GAAG,EAAE,kBAAkB,EAAE,IAAI,EAAE,cAAc,EAAE;CACjD,CAAC;AA8CF,gEAAgE;AAChE,SAAS,WAAW,CAAC,KAAa;IACjC,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AACnC,CAAC;AAED,6EAA6E;AAC7E,SAAS,cAAc,CAAC,KAAa,EAAE,EAAuB;IAC7D,IAAI,IAAI,GAAG,KAAK,CAAC;IACjB,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;QACb,IAAI,CAAC;YACJ,IAAI,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACR,kCAAkC;QACnC,CAAC;IACF,CAAC;IACD,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;QACd,IAAI,CAAC;YACJ,IAAI,IAAI,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACR,kCAAkC;QACnC,CAAC;IACF,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED,gFAAgF;AAChF,KAAK,UAAU,OAAO,CAAI,GAAW,EAAE,KAAa,EAAE,SAAuB;IAC5E,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,EAAE,aAAa,EAAE,OAAO,KAAK,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;KAC9E,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAM,CAAC;AAChC,CAAC;AAED;;;;;GAKG;AACH,SAAS,2BAA2B,CAAC,MAMpC;IACA,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAC1D,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC5C,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;QACtC,IAAI,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ;YAAE,SAAS;QAC1C,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI,CAAC;YACJ,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACzD,CAAC;QAAC,MAAM,CAAC;YACR,IAAI,GAAG,EAAE,CAAC;QACX,CAAC;QACD,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAC9B,CAAC;IACD,oEAAoE;IACpE,IAAI,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IACzC,MAAM,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACtE,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE,CAAC;QACpC,KAAK,IAAI,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACtC,CAAC;IACD,uDAAuD;IACvD,IAAI,CAAC,KAAK,GAAG,kBAAkB,CAAC,KAAK,kBAAkB,EAAE,CAAC;QACzD,OAAO,CAAC,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC;IACrG,uBAAuB;IACvB,KAAK,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;QAC7B,IAAI,EAAE,CAAC,EAAE,KAAK,OAAO;YAAE,KAAK,GAAG,cAAc,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC1D,CAAC;IACD,iEAAiE;IACjE,IAAI,SAAS,GAAG,EAAE,CAAC;IACnB,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClB,KAAK,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;QAC7B,IAAI,EAAE,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;YAC7D,IAAI,CAAC;gBACJ,IAAI,EAAE,CAAC,IAAI;oBAAE,QAAQ,IAAI,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;gBACzC,IAAI,EAAE,CAAC,KAAK;oBAAE,SAAS,IAAI,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;YAC7C,CAAC;YAAC,MAAM,CAAC;gBACR,sBAAsB;YACvB,CAAC;QACF,CAAC;IACF,CAAC;IACD,KAAK,IAAI,CAAC,QAAQ,CAAC;IACnB,KAAK,IAAI,SAAS,CAAC;IACnB,mDAAmD;IACnD,KAAK,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;QAC7B,IAAI,EAAE,CAAC,EAAE,KAAK,KAAK;YAAE,KAAK,GAAG,cAAc,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,8BAA8B,CACnD,KAAa,EACb,UAAoB,EACpB,YAA0B,KAAK;IAE/B,MAAM,KAAK,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACnC,MAAM,GAAG,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5E,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACxC,MAAM,kBAAkB,GAAG,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IACvD,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,kBAAkB,EAAE,CAAC;IAC7C,CAAC;IACD,iFAAiF;IACjF,IAAI,KAAK,GAAG,EAAE,CAAC;IACf,IAAI,CAAC;QACJ,MAAM,EAAE,GAAG,MAAM,OAAO,CAAkB,GAAG,gBAAgB,YAAY,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;QAC7F,KAAK,GAAG,OAAO,EAAE,EAAE,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACR,KAAK,GAAG,EAAE,CAAC;IACZ,CAAC;IACD,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,OAAO;YACN,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;gBACrC,SAAS;gBACT,EAAE,EAAE,KAAK;gBACT,eAAe,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;gBAC5C,KAAK,EAAE,oDAAoD;aAC3D,CAAC,CAAC;YACH,kBAAkB;SAClB,CAAC;IACH,CAAC;IACD,MAAM,QAAQ,GAAqC,EAAE,CAAC;IACtD,KAAK,MAAM,SAAS,IAAI,OAAO,EAAE,CAAC;QACjC,IAAI,CAAC;YACJ,MAAM,OAAO,GAAG,MAAM,OAAO,CAAgB,GAAG,gBAAgB,aAAa,SAAS,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;YAC5G,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7E,IAAI,CAAC,OAAO,EAAE,CAAC;gBACd,qEAAqE;gBACrE,qCAAqC;gBACrC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,EAAE,EAAE,CAAC,CAAC;gBAC5D,SAAS;YACV,CAAC;YACD,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBACzC,OAAO,CAAc,GAAG,gBAAgB,WAAW,OAAO,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC;gBAC/E,OAAO,CAAe,GAAG,gBAAgB,WAAW,OAAO,YAAY,KAAK,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC;aACjG,CAAC,CAAC;YACH,MAAM,KAAK,GAAG,2BAA2B,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YACtF,MAAM,eAAe,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAC7F,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC;QACjF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,QAAQ,CAAC,IAAI,CAAC;gBACb,SAAS;gBACT,EAAE,EAAE,KAAK;gBACT,eAAe,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;gBAC5C,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACvD,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,CAAC;AACzC,CAAC"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Discord `ChannelPlugin` — the multi-ACCOUNT contract surface.
3
+ *
4
+ * Mirrors `slack/plugin.ts`: wraps `createDiscordAdapter()` (the per-connection
5
+ * implementation) with the lifecycle adapters the `ChannelPluginManager`
6
+ * consumes, so an operator can run MORE THAN ONE Discord bot at once via:
7
+ *
8
+ * channels.discord = {
9
+ * enabled: true,
10
+ * accounts: [
11
+ * { id: "main", botToken: "…AAA" },
12
+ * { id: "labs", botToken: "…BBB" },
13
+ * ],
14
+ * }
15
+ *
16
+ * - `config.listAccountIds` / `resolveAccount` → multi-account discovery
17
+ * - `gateway.startAccount` / `stopAccount` → per-account bot lifecycle
18
+ * - `outbound.sendText` / `sendMedia` → routes by `target.accountId`
19
+ * - per-account approval-dispatcher registration → an exec-gate prompt raised
20
+ * by a turn on (discord, labs) replies on (discord, labs), not the default
21
+ *
22
+ * Per-account state lives in a `Map<accountId, AccountRuntime>` held in this
23
+ * closure — one Gateway connection per account, partitioned token resolution per
24
+ * `channels.discord.accounts[].botToken`. Inbound dispatch reuses the shared
25
+ * `runChannelInboundPipeline` so the multi-account path carries the identical
26
+ * ACL + debounce + abort + approval-reply + approval-callback surface as the
27
+ * legacy single-adapter manager.
28
+ *
29
+ * The legacy single-account `createDiscordAdapter` (started by the legacy
30
+ * `startChannels` manager) STEPS ASIDE when >1 account is configured — its
31
+ * `isConfigured` returns false for the default account in that case (mirrors
32
+ * Slack), so the two paths never double-start a bot.
33
+ *
34
+ * Discord has no events-mode HTTP route (the Gateway is the only inbound
35
+ * transport), so — unlike Slack's plugin — there is NO per-account webhook-sink
36
+ * registry to populate.
37
+ */
38
+ import type { BrigadeConfig } from "../../../config/types.js";
39
+ import { type ChannelAdapter, type ChannelOutboundTarget, type ChannelPlugin, type StartChannelsArgs } from "../sdk.js";
40
+ import { type ResolvedDiscordAccount } from "./account-config.js";
41
+ import { type DiscordProbeResult } from "./probe.js";
42
+ import { type DiscordPermissionAuditResult } from "./permission-audit.js";
43
+ /** Dependencies the gateway hands the plugin to drive turns + replies. */
44
+ export interface DiscordPluginDeps {
45
+ /** Boot-time default agent for routing fallbacks. */
46
+ defaultAgentId: string;
47
+ /** Active gateway config — re-read fresh per inbound for live policy. */
48
+ loadConfig: () => BrigadeConfig;
49
+ /** Run one agent turn (the gateway's serialised turn executor). */
50
+ runTurn: StartChannelsArgs["runTurn"];
51
+ /**
52
+ * Optional adapter factory — tests inject a fake; production uses
53
+ * `createDiscordAdapter`. Receives the per-account scope.
54
+ */
55
+ adapterFactory?: (args: {
56
+ accountId: string;
57
+ }) => ChannelAdapter;
58
+ }
59
+ /** Probe result + optional channel-permission audit (Phase 5 diagnostics). */
60
+ export type DiscordProbeWithAudit = DiscordProbeResult & {
61
+ /** Channel-permission audit for the configured guild channels, when run. */
62
+ permissionAudit?: DiscordPermissionAuditResult;
63
+ };
64
+ /** Operator-grade view of a per-account bot — exposed via attached helpers. */
65
+ export interface DiscordPluginRuntimeView {
66
+ /** Currently-running account ids. */
67
+ startedAccountIds(): string[];
68
+ /** Look up the per-account adapter (or undefined when the account isn't started). */
69
+ getAdapter(accountId: string): ChannelAdapter | undefined;
70
+ /**
71
+ * Run a `/users/@me` probe for an account (for status / doctor). Also runs the
72
+ * channel-permission audit over any configured guild channels (Phase 5).
73
+ */
74
+ probeAccount(accountId: string, cfg: BrigadeConfig): Promise<DiscordProbeWithAudit>;
75
+ }
76
+ /**
77
+ * Collect the numeric guild channel ids configured under
78
+ * `channels.discord.guilds.<guildId>.channels.<channelId>` so the permission
79
+ * audit knows which channels to check. Non-numeric keys are passed through too —
80
+ * the audit reports them as unresolved. Returns [] when none are configured.
81
+ */
82
+ export declare function collectConfiguredDiscordChannelIds(cfg: BrigadeConfig): string[];
83
+ /** Plugin handle with the extra per-account introspection surface attached. */
84
+ export type DiscordPluginHandle = ChannelPlugin<ResolvedDiscordAccount> & DiscordPluginRuntimeView;
85
+ /** Construct the plugin instance, capturing per-account runtime state in closure. */
86
+ export declare function createDiscordPlugin(deps: DiscordPluginDeps): DiscordPluginHandle;
87
+ /** Outbound dispatch helper for callers reaching the plugin directly. */
88
+ export type DiscordOutboundTarget = ChannelOutboundTarget;
89
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/discord/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAK9D,OAAO,EAON,KAAK,cAAc,EAOnB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAKlB,KAAK,iBAAiB,EAEtB,MAAM,WAAW,CAAC;AACnB,OAAO,EAMN,KAAK,sBAAsB,EAC3B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAgB,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EAAkC,KAAK,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AAoB1G,0EAA0E;AAC1E,MAAM,WAAW,iBAAiB;IACjC,qDAAqD;IACrD,cAAc,EAAE,MAAM,CAAC;IACvB,yEAAyE;IACzE,UAAU,EAAE,MAAM,aAAa,CAAC;IAChC,mEAAmE;IACnE,OAAO,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAC;IACtC;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,KAAK,cAAc,CAAC;CACjE;AAED,8EAA8E;AAC9E,MAAM,MAAM,qBAAqB,GAAG,kBAAkB,GAAG;IACxD,4EAA4E;IAC5E,eAAe,CAAC,EAAE,4BAA4B,CAAC;CAC/C,CAAC;AAEF,+EAA+E;AAC/E,MAAM,WAAW,wBAAwB;IACxC,qCAAqC;IACrC,iBAAiB,IAAI,MAAM,EAAE,CAAC;IAC9B,qFAAqF;IACrF,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAAC;IAC1D;;;OAGG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACpF;AAED;;;;;GAKG;AACH,wBAAgB,kCAAkC,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,EAAE,CAe/E;AAED,+EAA+E;AAC/E,MAAM,MAAM,mBAAmB,GAAG,aAAa,CAAC,sBAAsB,CAAC,GAAG,wBAAwB,CAAC;AAqBnG,qFAAqF;AACrF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,GAAG,mBAAmB,CA4QhF;AAOD,yEAAyE;AACzE,MAAM,MAAM,qBAAqB,GAAG,qBAAqB,CAAC"}