@spinabot/brigade 1.3.2 → 1.4.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 (225) hide show
  1. package/README.md +54 -10
  2. package/convex/config.d.ts +2 -2
  3. package/convex/extensions.d.ts +2 -2
  4. package/convex/logs.d.ts +2 -2
  5. package/convex/memory.d.ts +7 -7
  6. package/convex/messages.d.ts +4 -4
  7. package/convex/schema.d.ts +17 -17
  8. package/convex/subagents.d.ts +12 -12
  9. package/dist/agents/agent-loop.d.ts +1 -0
  10. package/dist/agents/agent-loop.d.ts.map +1 -1
  11. package/dist/agents/agent-loop.js +1 -1
  12. package/dist/agents/agent-loop.js.map +1 -1
  13. package/dist/agents/channels/access-control/format-allow-from.d.ts +50 -0
  14. package/dist/agents/channels/access-control/format-allow-from.d.ts.map +1 -0
  15. package/dist/agents/channels/access-control/format-allow-from.js +64 -0
  16. package/dist/agents/channels/access-control/format-allow-from.js.map +1 -0
  17. package/dist/agents/channels/access-control/index.d.ts +2 -1
  18. package/dist/agents/channels/access-control/index.d.ts.map +1 -1
  19. package/dist/agents/channels/access-control/index.js +2 -1
  20. package/dist/agents/channels/access-control/index.js.map +1 -1
  21. package/dist/agents/channels/access-control/store.d.ts +15 -0
  22. package/dist/agents/channels/access-control/store.d.ts.map +1 -1
  23. package/dist/agents/channels/access-control/store.js +44 -1
  24. package/dist/agents/channels/access-control/store.js.map +1 -1
  25. package/dist/agents/channels/bundled-channel-metas.d.ts +26 -0
  26. package/dist/agents/channels/bundled-channel-metas.d.ts.map +1 -0
  27. package/dist/agents/channels/bundled-channel-metas.js +44 -0
  28. package/dist/agents/channels/bundled-channel-metas.js.map +1 -0
  29. package/dist/agents/channels/channel-messaging-registry.d.ts +130 -0
  30. package/dist/agents/channels/channel-messaging-registry.d.ts.map +1 -0
  31. package/dist/agents/channels/channel-messaging-registry.js +211 -0
  32. package/dist/agents/channels/channel-messaging-registry.js.map +1 -0
  33. package/dist/agents/channels/channel-meta-registry.d.ts +60 -0
  34. package/dist/agents/channels/channel-meta-registry.d.ts.map +1 -0
  35. package/dist/agents/channels/channel-meta-registry.js +128 -0
  36. package/dist/agents/channels/channel-meta-registry.js.map +1 -0
  37. package/dist/agents/channels/channel-security-registry.d.ts +138 -0
  38. package/dist/agents/channels/channel-security-registry.d.ts.map +1 -0
  39. package/dist/agents/channels/channel-security-registry.js +265 -0
  40. package/dist/agents/channels/channel-security-registry.js.map +1 -0
  41. package/dist/agents/channels/exposure.d.ts +44 -0
  42. package/dist/agents/channels/exposure.d.ts.map +1 -0
  43. package/dist/agents/channels/exposure.js +48 -0
  44. package/dist/agents/channels/exposure.js.map +1 -0
  45. package/dist/agents/channels/general-callback.d.ts +25 -0
  46. package/dist/agents/channels/general-callback.d.ts.map +1 -0
  47. package/dist/agents/channels/general-callback.js +31 -0
  48. package/dist/agents/channels/general-callback.js.map +1 -0
  49. package/dist/agents/channels/inbound-pipeline.d.ts +9 -0
  50. package/dist/agents/channels/inbound-pipeline.d.ts.map +1 -1
  51. package/dist/agents/channels/inbound-pipeline.js +429 -39
  52. package/dist/agents/channels/inbound-pipeline.js.map +1 -1
  53. package/dist/agents/channels/markdown-capability.d.ts +44 -0
  54. package/dist/agents/channels/markdown-capability.d.ts.map +1 -0
  55. package/dist/agents/channels/markdown-capability.js +66 -0
  56. package/dist/agents/channels/markdown-capability.js.map +1 -0
  57. package/dist/agents/channels/sdk.d.ts +170 -10
  58. package/dist/agents/channels/sdk.d.ts.map +1 -1
  59. package/dist/agents/channels/sdk.js +138 -6
  60. package/dist/agents/channels/sdk.js.map +1 -1
  61. package/dist/agents/channels/telegram/account-config.d.ts +41 -0
  62. package/dist/agents/channels/telegram/account-config.d.ts.map +1 -1
  63. package/dist/agents/channels/telegram/account-config.js +79 -0
  64. package/dist/agents/channels/telegram/account-config.js.map +1 -1
  65. package/dist/agents/channels/telegram/adapter.d.ts +6 -0
  66. package/dist/agents/channels/telegram/adapter.d.ts.map +1 -1
  67. package/dist/agents/channels/telegram/adapter.js +178 -6
  68. package/dist/agents/channels/telegram/adapter.js.map +1 -1
  69. package/dist/agents/channels/telegram/allowed-updates.d.ts +14 -5
  70. package/dist/agents/channels/telegram/allowed-updates.d.ts.map +1 -1
  71. package/dist/agents/channels/telegram/allowed-updates.js +8 -4
  72. package/dist/agents/channels/telegram/allowed-updates.js.map +1 -1
  73. package/dist/agents/channels/telegram/connection.d.ts +108 -1
  74. package/dist/agents/channels/telegram/connection.d.ts.map +1 -1
  75. package/dist/agents/channels/telegram/connection.js +219 -3
  76. package/dist/agents/channels/telegram/connection.js.map +1 -1
  77. package/dist/agents/channels/telegram/draft-stream.d.ts +98 -0
  78. package/dist/agents/channels/telegram/draft-stream.d.ts.map +1 -0
  79. package/dist/agents/channels/telegram/draft-stream.js +222 -0
  80. package/dist/agents/channels/telegram/draft-stream.js.map +1 -0
  81. package/dist/agents/channels/telegram/inbound-extras.d.ts +10 -1
  82. package/dist/agents/channels/telegram/inbound-extras.d.ts.map +1 -1
  83. package/dist/agents/channels/telegram/inbound-extras.js +66 -0
  84. package/dist/agents/channels/telegram/inbound-extras.js.map +1 -1
  85. package/dist/agents/channels/telegram/inline-keyboard.d.ts +36 -0
  86. package/dist/agents/channels/telegram/inline-keyboard.d.ts.map +1 -0
  87. package/dist/agents/channels/telegram/inline-keyboard.js +62 -0
  88. package/dist/agents/channels/telegram/inline-keyboard.js.map +1 -0
  89. package/dist/agents/channels/telegram/plugin.d.ts.map +1 -1
  90. package/dist/agents/channels/telegram/plugin.js +7 -11
  91. package/dist/agents/channels/telegram/plugin.js.map +1 -1
  92. package/dist/agents/channels/telegram/reasoning-lane.d.ts +41 -0
  93. package/dist/agents/channels/telegram/reasoning-lane.d.ts.map +1 -0
  94. package/dist/agents/channels/telegram/reasoning-lane.js +67 -0
  95. package/dist/agents/channels/telegram/reasoning-lane.js.map +1 -0
  96. package/dist/agents/channels/telegram/socks-dispatcher.d.ts +32 -0
  97. package/dist/agents/channels/telegram/socks-dispatcher.d.ts.map +1 -0
  98. package/dist/agents/channels/telegram/socks-dispatcher.js +97 -0
  99. package/dist/agents/channels/telegram/socks-dispatcher.js.map +1 -0
  100. package/dist/agents/channels/types.adapters.d.ts +137 -4
  101. package/dist/agents/channels/types.adapters.d.ts.map +1 -1
  102. package/dist/agents/channels/types.adapters.js +2 -2
  103. package/dist/agents/channels/types.core.d.ts +26 -2
  104. package/dist/agents/channels/types.core.d.ts.map +1 -1
  105. package/dist/agents/channels/types.plugin.d.ts +25 -7
  106. package/dist/agents/channels/types.plugin.d.ts.map +1 -1
  107. package/dist/agents/channels/types.plugin.js +6 -5
  108. package/dist/agents/channels/types.plugin.js.map +1 -1
  109. package/dist/agents/channels/whatsapp/adapter.d.ts +8 -0
  110. package/dist/agents/channels/whatsapp/adapter.d.ts.map +1 -1
  111. package/dist/agents/channels/whatsapp/adapter.js +7 -4
  112. package/dist/agents/channels/whatsapp/adapter.js.map +1 -1
  113. package/dist/agents/channels/whatsapp/connection.d.ts +24 -2
  114. package/dist/agents/channels/whatsapp/connection.d.ts.map +1 -1
  115. package/dist/agents/channels/whatsapp/connection.js +26 -5
  116. package/dist/agents/channels/whatsapp/connection.js.map +1 -1
  117. package/dist/agents/channels/whatsapp/plugin.d.ts.map +1 -1
  118. package/dist/agents/channels/whatsapp/plugin.js +6 -10
  119. package/dist/agents/channels/whatsapp/plugin.js.map +1 -1
  120. package/dist/agents/extensions/activation-planner.d.ts +125 -0
  121. package/dist/agents/extensions/activation-planner.d.ts.map +1 -0
  122. package/dist/agents/extensions/activation-planner.js +221 -0
  123. package/dist/agents/extensions/activation-planner.js.map +1 -0
  124. package/dist/agents/extensions/diagnose.d.ts +84 -0
  125. package/dist/agents/extensions/diagnose.d.ts.map +1 -0
  126. package/dist/agents/extensions/diagnose.js +123 -0
  127. package/dist/agents/extensions/diagnose.js.map +1 -0
  128. package/dist/agents/extensions/discovery.d.ts +85 -7
  129. package/dist/agents/extensions/discovery.d.ts.map +1 -1
  130. package/dist/agents/extensions/discovery.js +200 -15
  131. package/dist/agents/extensions/discovery.js.map +1 -1
  132. package/dist/agents/extensions/index.d.ts +3 -2
  133. package/dist/agents/extensions/index.d.ts.map +1 -1
  134. package/dist/agents/extensions/index.js +3 -2
  135. package/dist/agents/extensions/index.js.map +1 -1
  136. package/dist/agents/extensions/install-scan.d.ts +63 -0
  137. package/dist/agents/extensions/install-scan.d.ts.map +1 -0
  138. package/dist/agents/extensions/install-scan.js +201 -0
  139. package/dist/agents/extensions/install-scan.js.map +1 -0
  140. package/dist/agents/extensions/install.d.ts +135 -0
  141. package/dist/agents/extensions/install.d.ts.map +1 -0
  142. package/dist/agents/extensions/install.js +414 -0
  143. package/dist/agents/extensions/install.js.map +1 -0
  144. package/dist/agents/extensions/loader.d.ts +13 -2
  145. package/dist/agents/extensions/loader.d.ts.map +1 -1
  146. package/dist/agents/extensions/loader.js +126 -13
  147. package/dist/agents/extensions/loader.js.map +1 -1
  148. package/dist/agents/extensions/registry.d.ts +109 -0
  149. package/dist/agents/extensions/registry.d.ts.map +1 -1
  150. package/dist/agents/extensions/registry.js +172 -0
  151. package/dist/agents/extensions/registry.js.map +1 -1
  152. package/dist/agents/extensions/sdk-alias.d.ts +45 -0
  153. package/dist/agents/extensions/sdk-alias.d.ts.map +1 -0
  154. package/dist/agents/extensions/sdk-alias.js +94 -0
  155. package/dist/agents/extensions/sdk-alias.js.map +1 -0
  156. package/dist/agents/extensions/types.d.ts +155 -1
  157. package/dist/agents/extensions/types.d.ts.map +1 -1
  158. package/dist/agents/extensions/types.js.map +1 -1
  159. package/dist/agents/tools/composio-tool.d.ts +9 -1
  160. package/dist/agents/tools/composio-tool.d.ts.map +1 -1
  161. package/dist/agents/tools/composio-tool.js +68 -4
  162. package/dist/agents/tools/composio-tool.js.map +1 -1
  163. package/dist/agents/tools/message-action-tool.d.ts +6 -1
  164. package/dist/agents/tools/message-action-tool.d.ts.map +1 -1
  165. package/dist/agents/tools/message-action-tool.js +52 -2
  166. package/dist/agents/tools/message-action-tool.js.map +1 -1
  167. package/dist/agents/tools/send-message-tool.d.ts +1 -0
  168. package/dist/agents/tools/send-message-tool.d.ts.map +1 -1
  169. package/dist/agents/tools/send-message-tool.js +56 -1
  170. package/dist/agents/tools/send-message-tool.js.map +1 -1
  171. package/dist/buildstamp.json +1 -1
  172. package/dist/channel-sdk.d.ts +28 -0
  173. package/dist/channel-sdk.d.ts.map +1 -0
  174. package/dist/channel-sdk.js +28 -0
  175. package/dist/channel-sdk.js.map +1 -0
  176. package/dist/cli/commands/channels.d.ts.map +1 -1
  177. package/dist/cli/commands/channels.js +8 -8
  178. package/dist/cli/commands/channels.js.map +1 -1
  179. package/dist/cli/commands/connect.d.ts +8 -11
  180. package/dist/cli/commands/connect.d.ts.map +1 -1
  181. package/dist/cli/commands/connect.js +157 -17
  182. package/dist/cli/commands/connect.js.map +1 -1
  183. package/dist/cli/commands/doctor.d.ts.map +1 -1
  184. package/dist/cli/commands/doctor.js +64 -0
  185. package/dist/cli/commands/doctor.js.map +1 -1
  186. package/dist/cli/commands/extensions.d.ts +46 -0
  187. package/dist/cli/commands/extensions.d.ts.map +1 -0
  188. package/dist/cli/commands/extensions.js +578 -0
  189. package/dist/cli/commands/extensions.js.map +1 -0
  190. package/dist/cli/commands/pairing.d.ts.map +1 -1
  191. package/dist/cli/commands/pairing.js +16 -2
  192. package/dist/cli/commands/pairing.js.map +1 -1
  193. package/dist/cli/commands/update.d.ts +17 -0
  194. package/dist/cli/commands/update.d.ts.map +1 -0
  195. package/dist/cli/commands/update.js +104 -0
  196. package/dist/cli/commands/update.js.map +1 -0
  197. package/dist/cli/program/build-program.d.ts.map +1 -1
  198. package/dist/cli/program/build-program.js +113 -0
  199. package/dist/cli/program/build-program.js.map +1 -1
  200. package/dist/config/paths.d.ts +1 -0
  201. package/dist/config/paths.d.ts.map +1 -1
  202. package/dist/config/paths.js +9 -0
  203. package/dist/config/paths.js.map +1 -1
  204. package/dist/core/server.d.ts.map +1 -1
  205. package/dist/core/server.js +134 -2
  206. package/dist/core/server.js.map +1 -1
  207. package/dist/protocol.d.ts +25 -0
  208. package/dist/protocol.d.ts.map +1 -1
  209. package/dist/protocol.js.map +1 -1
  210. package/dist/system-prompt/assembler.d.ts.map +1 -1
  211. package/dist/system-prompt/assembler.js +17 -0
  212. package/dist/system-prompt/assembler.js.map +1 -1
  213. package/dist/system-prompt/identity-defaults.d.ts +28 -0
  214. package/dist/system-prompt/identity-defaults.d.ts.map +1 -1
  215. package/dist/system-prompt/identity-defaults.js +47 -0
  216. package/dist/system-prompt/identity-defaults.js.map +1 -1
  217. package/dist/ui/editor.d.ts.map +1 -1
  218. package/dist/ui/editor.js +1 -0
  219. package/dist/ui/editor.js.map +1 -1
  220. package/dist/version.d.ts +4 -3
  221. package/dist/version.d.ts.map +1 -1
  222. package/dist/version.js +27 -5
  223. package/dist/version.js.map +1 -1
  224. package/package.json +21 -4
  225. package/scripts/build-done.mjs +11 -2
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Built-in channel metas — the single source of truth for the bundled
3
+ * channels' user-facing metadata (`ChannelMeta`).
4
+ *
5
+ * This module is DELIBERATELY import-light: it pulls in nothing but the
6
+ * `ChannelMeta` type, so the channel-meta registry (and through it, the
7
+ * system-prompt markdown gate + the exposure resolver) can read bundled
8
+ * channel metadata WITHOUT eagerly loading the channel adapters (Baileys
9
+ * sockets, the Telegram bot runtime). The plugins import THESE constants for
10
+ * their `meta` field, so there is exactly one definition per channel.
11
+ *
12
+ * Canonical channel ids are inlined as literals here — they are stable
13
+ * constants (`"whatsapp"`, `"telegram"`) and re-importing them from each
14
+ * channel's `account-config` module would risk dragging adapter-adjacent code
15
+ * into this light module. The plugin's own `WHATSAPP_CHANNEL_ID` /
16
+ * `TELEGRAM_CHANNEL_ID` literals must stay in sync with the `id` fields below;
17
+ * they are the same string by construction.
18
+ */
19
+ /** WhatsApp channel metadata (markdown-capable; visible everywhere by default). */
20
+ export const WHATSAPP_CHANNEL_META = {
21
+ id: "whatsapp",
22
+ label: "WhatsApp",
23
+ selectionLabel: "WhatsApp",
24
+ docsPath: "channels/whatsapp",
25
+ blurb: "QR-pair a phone, DM/group chat over WhatsApp Web.",
26
+ order: 10,
27
+ markdownCapable: true,
28
+ };
29
+ /** Telegram channel metadata (markdown-capable; visible everywhere by default). */
30
+ export const TELEGRAM_CHANNEL_META = {
31
+ id: "telegram",
32
+ label: "Telegram",
33
+ selectionLabel: "Telegram",
34
+ docsPath: "channels/telegram",
35
+ blurb: "Paste a @BotFather token, DM/group chat over a Telegram bot.",
36
+ order: 20,
37
+ markdownCapable: true,
38
+ };
39
+ /** Every bundled channel meta, in declaration order. The registry seeds from this. */
40
+ export const BUNDLED_CHANNEL_METAS = [
41
+ WHATSAPP_CHANNEL_META,
42
+ TELEGRAM_CHANNEL_META,
43
+ ];
44
+ //# sourceMappingURL=bundled-channel-metas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundled-channel-metas.js","sourceRoot":"","sources":["../../../src/agents/channels/bundled-channel-metas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,mFAAmF;AACnF,MAAM,CAAC,MAAM,qBAAqB,GAAgB;IACjD,EAAE,EAAE,UAAU;IACd,KAAK,EAAE,UAAU;IACjB,cAAc,EAAE,UAAU;IAC1B,QAAQ,EAAE,mBAAmB;IAC7B,KAAK,EAAE,mDAAmD;IAC1D,KAAK,EAAE,EAAE;IACT,eAAe,EAAE,IAAI;CACrB,CAAC;AAEF,mFAAmF;AACnF,MAAM,CAAC,MAAM,qBAAqB,GAAgB;IACjD,EAAE,EAAE,UAAU;IACd,KAAK,EAAE,UAAU;IACjB,cAAc,EAAE,UAAU;IAC1B,QAAQ,EAAE,mBAAmB;IAC7B,KAAK,EAAE,8DAA8D;IACrE,KAAK,EAAE,EAAE;IACT,eAAe,EAAE,IAAI;CACrB,CAAC;AAEF,sFAAsF;AACtF,MAAM,CAAC,MAAM,qBAAqB,GAA2B;IAC5D,qBAAqB;IACrB,qBAAqB;CACrB,CAAC"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Channel-messaging registry — the process-wide lookup behind "how do I
3
+ * canonicalise / resolve an OUTBOUND target for channel <id>?".
4
+ *
5
+ * Mirrors the `channel-meta-registry.ts` pattern (FIX #9): a dynamic
6
+ * registration seam keyed by lowercased channel id, resolved through one
7
+ * process-global singleton so a hot reload (or CLI + gateway in one process)
8
+ * shares a single slot.
9
+ *
10
+ * WHY A REGISTRY (and not "reach into the plugin off the manager"): the
11
+ * `send_message` tool runs against the LEGACY `ChannelManager`
12
+ * (`agents/channels/manager.ts`), which hands back a runtime `ChannelAdapter`
13
+ * via `adapter(id)` and deliberately exposes NO `ChannelPlugin` (the plugins
14
+ * live behind the multi-account plugin manager + `core/server.ts`). Pulling a
15
+ * channel plugin module into the send path would also eagerly load its adapter
16
+ * (Baileys sockets, the Telegram bot runtime). So instead the plugin engine
17
+ * registers JUST the plugin's `messaging` adapter here — plain function
18
+ * references, import-light — and the send tool consults this registry.
19
+ *
20
+ * A channel with NO `messaging` adapter simply never registers; the send tool's
21
+ * `resolveOutboundTarget` then returns the raw `to` unchanged, so back-compat
22
+ * is preserved by construction.
23
+ */
24
+ import type { ChannelMessagingAdapter } from "./types.adapters.js";
25
+ /**
26
+ * Register (or replace) a channel's OUTBOUND messaging adapter. The plugin
27
+ * engine calls this when a channel module that declares `plugin.messaging`
28
+ * registers, so the `send_message` tool can address by name/handle/explicit
29
+ * target. Last registration per id wins. No-ops on an empty/unusable id.
30
+ */
31
+ export declare function registerChannelMessagingAdapter(channelId: string | null | undefined, adapter: ChannelMessagingAdapter): void;
32
+ /**
33
+ * Bulk-register every messaging adapter declared on a plugin list (skipping
34
+ * plugins that omit the slot). The gateway bootstrap calls this once with its
35
+ * `bundledChannelPlugins` — parallel to how it seeds the meta registry — so the
36
+ * send tool can address by name/handle for any channel that opts in. Plugins
37
+ * WITHOUT a `messaging` adapter are simply skipped, leaving raw-id passthrough.
38
+ */
39
+ export declare function syncChannelMessagingAdaptersFromPlugins(plugins: ReadonlyArray<{
40
+ id: string;
41
+ messaging?: ChannelMessagingAdapter;
42
+ }>): void;
43
+ /**
44
+ * Drop every dynamically-registered messaging adapter. PUBLIC — the gateway's
45
+ * `stopExtensions()` calls this during a `system.reload` teardown so the
46
+ * registry starts clean and `startExtensions()` re-syncs ONLY the currently-
47
+ * loaded channels (the sync seam is `.set()`-only and never removes a slot, so
48
+ * without this an edited/removed channel's messaging adapter would leak across
49
+ * the reload and keep rewriting outbound targets). Idempotent.
50
+ */
51
+ export declare function clearChannelMessagingRegistry(): void;
52
+ /** Test-only alias of {@link clearChannelMessagingRegistry}. Kept so existing tests don't break. */
53
+ export declare function resetChannelMessagingRegistryForTests(): void;
54
+ /**
55
+ * Look up a channel's registered OUTBOUND messaging adapter by id (or alias the
56
+ * caller already normalized). Returns `undefined` when the channel registered
57
+ * none — the caller then falls back to raw-id behaviour. Case-insensitive.
58
+ */
59
+ export declare function getChannelMessagingAdapter(channelId: string | null | undefined): ChannelMessagingAdapter | undefined;
60
+ /** Outcome of {@link resolveOutboundTarget}. */
61
+ export type ResolvedOutboundTarget = {
62
+ /**
63
+ * The concrete target id to hand `ChannelAdapter.sendText`. When no
64
+ * messaging adapter is registered (or it couldn't improve on the input),
65
+ * this is the caller's raw `to`, byte-for-byte.
66
+ */
67
+ to: string;
68
+ /**
69
+ * A different channel id the explicit form re-targeted to (e.g. the agent
70
+ * passed `telegram:123` while sending through whatsapp). `undefined` when
71
+ * the target stays on the same channel. The caller decides whether to honor
72
+ * a cross-channel hop (owner gate) — this helper only surfaces it.
73
+ */
74
+ channelId?: string;
75
+ /** Whether a messaging adapter actually participated (for logging/tests). */
76
+ usedAdapter: boolean;
77
+ /** Whether the optional `targetResolver` resolved a human name → id. */
78
+ resolvedByName: boolean;
79
+ };
80
+ /**
81
+ * Heuristic: does this `to` look like a human NAME / handle rather than an
82
+ * already-concrete conversation id? Concrete ids carry channel-shape markers
83
+ * (a `:` scheme, an `@` domain like `…@s.whatsapp.net`, a leading `+`, or are
84
+ * all-digits). A bare word / `@handle` is treated as a name worth resolving.
85
+ * Deliberately conservative — when unsure we DON'T treat it as a name, so we
86
+ * never send a resolver a value that's plainly an id.
87
+ */
88
+ export declare function looksLikeContactName(to: string): boolean;
89
+ /**
90
+ * Turn the agent's loose `to` into a concrete outbound target for `channelId`,
91
+ * using that channel's registered `messaging` adapter when present. The order
92
+ * matches the `ChannelMessagingAdapter` contract:
93
+ *
94
+ * 1. No adapter registered → return the raw `to` UNCHANGED (back-compat).
95
+ * 2. `parseExplicitTarget(to)` — honor an explicit `scheme:value` / `@handle`
96
+ * form (and surface any cross-channel id it named).
97
+ * 3. If we're still holding a NAME (not an explicit target) and the adapter
98
+ * ships a `targetResolver`, resolve name → id; on a null/throw result fall
99
+ * back to the name as-is.
100
+ * 4. `normalizeTarget(...)` — canonicalise the final target id.
101
+ *
102
+ * NEVER throws: a misbehaving adapter (parse/normalize/resolve throwing) is
103
+ * caught and degrades to the raw `to`, so a buggy channel can't break sends.
104
+ */
105
+ export declare function resolveOutboundTarget(params: {
106
+ channelId: string;
107
+ to: string;
108
+ }): Promise<ResolvedOutboundTarget>;
109
+ /**
110
+ * Canonicalise an INCOMING peer id to a stable conversation/session identity
111
+ * using the channel's registered `messaging` adapter when it ships the optional
112
+ * `resolveInboundConversation` hook (the inverse of the outbound `targetResolver`).
113
+ * The inbound pipeline calls this just before the 8-tier route resolver so a
114
+ * name-addressed inbound collapses onto the SAME conversation/session the
115
+ * outbound side targets.
116
+ *
117
+ * Contract — mirrors {@link resolveOutboundTarget}, conservative by construction:
118
+ * 1. No messaging adapter registered, OR it has no `resolveInboundConversation`
119
+ * → return the raw `peerId` UNCHANGED.
120
+ * 2. The hook returns `null`/empty, OR throws → return the raw `peerId`.
121
+ * 3. Otherwise → return the canonicalised id.
122
+ *
123
+ * NEVER throws. When the result equals the raw `peerId` (the default for any
124
+ * channel that doesn't opt in), downstream routing is byte-identical to today.
125
+ */
126
+ export declare function resolveInboundConversation(params: {
127
+ channelId: string;
128
+ peerId: string;
129
+ }): string;
130
+ //# sourceMappingURL=channel-messaging-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-messaging-registry.d.ts","sourceRoot":"","sources":["../../../src/agents/channels/channel-messaging-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAkBnE;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC9C,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACpC,OAAO,EAAE,uBAAuB,GAC9B,IAAI,CAIN;AAED;;;;;;GAMG;AACH,wBAAgB,uCAAuC,CACtD,OAAO,EAAE,aAAa,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,uBAAuB,CAAA;CAAE,CAAC,GACzE,IAAI,CAIN;AAED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,IAAI,IAAI,CAEpD;AAED,oGAAoG;AACpG,wBAAgB,qCAAqC,IAAI,IAAI,CAE5D;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACzC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAClC,uBAAuB,GAAG,SAAS,CAIrC;AAMD,gDAAgD;AAChD,MAAM,MAAM,sBAAsB,GAAG;IACpC;;;;OAIG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6EAA6E;IAC7E,WAAW,EAAE,OAAO,CAAC;IACrB,wEAAwE;IACxE,cAAc,EAAE,OAAO,CAAC;CACxB,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAWxD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;CACX,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAgDlC;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CACf,GAAG,MAAM,CAiBT"}
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Channel-messaging registry — the process-wide lookup behind "how do I
3
+ * canonicalise / resolve an OUTBOUND target for channel <id>?".
4
+ *
5
+ * Mirrors the `channel-meta-registry.ts` pattern (FIX #9): a dynamic
6
+ * registration seam keyed by lowercased channel id, resolved through one
7
+ * process-global singleton so a hot reload (or CLI + gateway in one process)
8
+ * shares a single slot.
9
+ *
10
+ * WHY A REGISTRY (and not "reach into the plugin off the manager"): the
11
+ * `send_message` tool runs against the LEGACY `ChannelManager`
12
+ * (`agents/channels/manager.ts`), which hands back a runtime `ChannelAdapter`
13
+ * via `adapter(id)` and deliberately exposes NO `ChannelPlugin` (the plugins
14
+ * live behind the multi-account plugin manager + `core/server.ts`). Pulling a
15
+ * channel plugin module into the send path would also eagerly load its adapter
16
+ * (Baileys sockets, the Telegram bot runtime). So instead the plugin engine
17
+ * registers JUST the plugin's `messaging` adapter here — plain function
18
+ * references, import-light — and the send tool consults this registry.
19
+ *
20
+ * A channel with NO `messaging` adapter simply never registers; the send tool's
21
+ * `resolveOutboundTarget` then returns the raw `to` unchanged, so back-compat
22
+ * is preserved by construction.
23
+ */
24
+ import { resolveGlobalSingleton } from "../../shared/global-singleton.js";
25
+ import { normalizeOptionalLowercaseString } from "../../shared/string-coerce.js";
26
+ /** Process-global slot so a hot reload (or CLI+gateway in one process) shares one registry. */
27
+ const REGISTRY_STATE_KEY = Symbol.for("brigade.channelMessagingRegistry.state");
28
+ function createState() {
29
+ return { byChannelId: new Map() };
30
+ }
31
+ function getState() {
32
+ return resolveGlobalSingleton(REGISTRY_STATE_KEY, createState);
33
+ }
34
+ /**
35
+ * Register (or replace) a channel's OUTBOUND messaging adapter. The plugin
36
+ * engine calls this when a channel module that declares `plugin.messaging`
37
+ * registers, so the `send_message` tool can address by name/handle/explicit
38
+ * target. Last registration per id wins. No-ops on an empty/unusable id.
39
+ */
40
+ export function registerChannelMessagingAdapter(channelId, adapter) {
41
+ const id = normalizeOptionalLowercaseString(channelId);
42
+ if (!id)
43
+ return;
44
+ getState().byChannelId.set(id, adapter);
45
+ }
46
+ /**
47
+ * Bulk-register every messaging adapter declared on a plugin list (skipping
48
+ * plugins that omit the slot). The gateway bootstrap calls this once with its
49
+ * `bundledChannelPlugins` — parallel to how it seeds the meta registry — so the
50
+ * send tool can address by name/handle for any channel that opts in. Plugins
51
+ * WITHOUT a `messaging` adapter are simply skipped, leaving raw-id passthrough.
52
+ */
53
+ export function syncChannelMessagingAdaptersFromPlugins(plugins) {
54
+ for (const plugin of plugins) {
55
+ if (plugin.messaging)
56
+ registerChannelMessagingAdapter(plugin.id, plugin.messaging);
57
+ }
58
+ }
59
+ /**
60
+ * Drop every dynamically-registered messaging adapter. PUBLIC — the gateway's
61
+ * `stopExtensions()` calls this during a `system.reload` teardown so the
62
+ * registry starts clean and `startExtensions()` re-syncs ONLY the currently-
63
+ * loaded channels (the sync seam is `.set()`-only and never removes a slot, so
64
+ * without this an edited/removed channel's messaging adapter would leak across
65
+ * the reload and keep rewriting outbound targets). Idempotent.
66
+ */
67
+ export function clearChannelMessagingRegistry() {
68
+ getState().byChannelId.clear();
69
+ }
70
+ /** Test-only alias of {@link clearChannelMessagingRegistry}. Kept so existing tests don't break. */
71
+ export function resetChannelMessagingRegistryForTests() {
72
+ clearChannelMessagingRegistry();
73
+ }
74
+ /**
75
+ * Look up a channel's registered OUTBOUND messaging adapter by id (or alias the
76
+ * caller already normalized). Returns `undefined` when the channel registered
77
+ * none — the caller then falls back to raw-id behaviour. Case-insensitive.
78
+ */
79
+ export function getChannelMessagingAdapter(channelId) {
80
+ const key = normalizeOptionalLowercaseString(channelId);
81
+ if (!key)
82
+ return undefined;
83
+ return getState().byChannelId.get(key);
84
+ }
85
+ /**
86
+ * Heuristic: does this `to` look like a human NAME / handle rather than an
87
+ * already-concrete conversation id? Concrete ids carry channel-shape markers
88
+ * (a `:` scheme, an `@` domain like `…@s.whatsapp.net`, a leading `+`, or are
89
+ * all-digits). A bare word / `@handle` is treated as a name worth resolving.
90
+ * Deliberately conservative — when unsure we DON'T treat it as a name, so we
91
+ * never send a resolver a value that's plainly an id.
92
+ */
93
+ export function looksLikeContactName(to) {
94
+ const t = to.trim();
95
+ if (t.length === 0)
96
+ return false;
97
+ // `scheme:value` (telegram:123) — explicit id form, not a name.
98
+ if (/^[a-z][a-z0-9_-]*:/i.test(t))
99
+ return false;
100
+ // `user@domain` JID (14057144199@s.whatsapp.net) — an id, not a name.
101
+ if (/@[^@\s]+\.[^@\s]+$/.test(t))
102
+ return false;
103
+ // Phone-ish (+15551234567 / 15551234567) — an id, not a name.
104
+ if (/^\+?\d[\d\s().-]{4,}$/.test(t))
105
+ return false;
106
+ // `@handle` OR a plain word/words → treat as a name worth resolving.
107
+ return true;
108
+ }
109
+ /**
110
+ * Turn the agent's loose `to` into a concrete outbound target for `channelId`,
111
+ * using that channel's registered `messaging` adapter when present. The order
112
+ * matches the `ChannelMessagingAdapter` contract:
113
+ *
114
+ * 1. No adapter registered → return the raw `to` UNCHANGED (back-compat).
115
+ * 2. `parseExplicitTarget(to)` — honor an explicit `scheme:value` / `@handle`
116
+ * form (and surface any cross-channel id it named).
117
+ * 3. If we're still holding a NAME (not an explicit target) and the adapter
118
+ * ships a `targetResolver`, resolve name → id; on a null/throw result fall
119
+ * back to the name as-is.
120
+ * 4. `normalizeTarget(...)` — canonicalise the final target id.
121
+ *
122
+ * NEVER throws: a misbehaving adapter (parse/normalize/resolve throwing) is
123
+ * caught and degrades to the raw `to`, so a buggy channel can't break sends.
124
+ */
125
+ export async function resolveOutboundTarget(params) {
126
+ const { channelId, to } = params;
127
+ const adapter = getChannelMessagingAdapter(channelId);
128
+ // (1) No messaging adapter → raw-id passthrough, byte-for-byte.
129
+ if (!adapter) {
130
+ return { to, usedAdapter: false, resolvedByName: false };
131
+ }
132
+ try {
133
+ let target = to;
134
+ let crossChannelId;
135
+ let isExplicit = false;
136
+ // (2) Explicit-target form?
137
+ const parsed = adapter.parseExplicitTarget(to);
138
+ if (parsed) {
139
+ isExplicit = true;
140
+ target = parsed.target;
141
+ if (parsed.channelId)
142
+ crossChannelId = parsed.channelId;
143
+ }
144
+ // (3) Name → id resolution (only when NOT an explicit target, the input
145
+ // reads like a name, and the channel ships a resolver).
146
+ let resolvedByName = false;
147
+ if (!isExplicit && typeof adapter.targetResolver === "function" && looksLikeContactName(target)) {
148
+ const resolved = await adapter.targetResolver(target);
149
+ if (resolved != null && resolved !== "") {
150
+ target = resolved;
151
+ resolvedByName = true;
152
+ }
153
+ // null/empty → fall through with the name unchanged (caller may still
154
+ // send to it verbatim, matching the no-resolver path).
155
+ }
156
+ // (4) Canonicalise.
157
+ const normalized = adapter.normalizeTarget(target);
158
+ const finalTo = normalized && normalized.length > 0 ? normalized : target;
159
+ return {
160
+ to: finalTo,
161
+ ...(crossChannelId ? { channelId: crossChannelId } : {}),
162
+ usedAdapter: true,
163
+ resolvedByName,
164
+ };
165
+ }
166
+ catch {
167
+ // A misbehaving adapter must never break sends — degrade to the raw id.
168
+ return { to, usedAdapter: false, resolvedByName: false };
169
+ }
170
+ }
171
+ /* -------------------------------------------------------------------------
172
+ * Default inbound-conversation resolution (the inverse of resolveOutboundTarget)
173
+ * --------------------------------------------------------------------- */
174
+ /**
175
+ * Canonicalise an INCOMING peer id to a stable conversation/session identity
176
+ * using the channel's registered `messaging` adapter when it ships the optional
177
+ * `resolveInboundConversation` hook (the inverse of the outbound `targetResolver`).
178
+ * The inbound pipeline calls this just before the 8-tier route resolver so a
179
+ * name-addressed inbound collapses onto the SAME conversation/session the
180
+ * outbound side targets.
181
+ *
182
+ * Contract — mirrors {@link resolveOutboundTarget}, conservative by construction:
183
+ * 1. No messaging adapter registered, OR it has no `resolveInboundConversation`
184
+ * → return the raw `peerId` UNCHANGED.
185
+ * 2. The hook returns `null`/empty, OR throws → return the raw `peerId`.
186
+ * 3. Otherwise → return the canonicalised id.
187
+ *
188
+ * NEVER throws. When the result equals the raw `peerId` (the default for any
189
+ * channel that doesn't opt in), downstream routing is byte-identical to today.
190
+ */
191
+ export function resolveInboundConversation(params) {
192
+ const { channelId, peerId } = params;
193
+ const adapter = getChannelMessagingAdapter(channelId);
194
+ // (1) No adapter / no inbound hook → raw peer id, byte-for-byte.
195
+ if (!adapter || typeof adapter.resolveInboundConversation !== "function") {
196
+ return peerId;
197
+ }
198
+ try {
199
+ const resolved = adapter.resolveInboundConversation(peerId);
200
+ // (2) null / empty → keep the raw peer id (no behaviour change).
201
+ if (resolved == null || resolved === "")
202
+ return peerId;
203
+ // (3) canonicalised id.
204
+ return resolved;
205
+ }
206
+ catch {
207
+ // A misbehaving adapter must never break inbound routing — degrade.
208
+ return peerId;
209
+ }
210
+ }
211
+ //# sourceMappingURL=channel-messaging-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-messaging-registry.js","sourceRoot":"","sources":["../../../src/agents/channels/channel-messaging-registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Channel-meta registry — the process-wide lookup behind "what does channel
3
+ * <id> declare about itself?" (markdown capability, exposure, aliases, …).
4
+ *
5
+ * Brand-scrubbed analogue of upstream's `src/channels/registry.ts` +
6
+ * `src/channels/chat-meta.ts` two-tier lookup, collapsed to the slice Brigade
7
+ * needs: a built-in catalog of the bundled channels' metas, plus a dynamic
8
+ * registration seam for channels that register through the plugin engine.
9
+ *
10
+ * WHY A REGISTRY (and not "just read `bundledChannelPlugins`"): the gateway's
11
+ * `bundledChannelPlugins` list (`core/server.ts`) is only populated for the
12
+ * MULTI-ACCOUNT plugin path, and pulling a channel plugin module into the
13
+ * system-prompt layer would eagerly load its adapter (Baileys sockets, the
14
+ * Telegram bot runtime, …). This module is import-light on purpose: the
15
+ * built-in metas are plain data constants (see `bundled-channel-metas.ts`),
16
+ * so the markdown gate + exposure resolver can consult channel metadata from
17
+ * anywhere — including the system-prompt assembly — without dragging the
18
+ * runtime in.
19
+ *
20
+ * Lookup order (mirrors upstream's built-in-then-plugin precedence):
21
+ * 1. Dynamically-registered plugin metas (last registration wins per id).
22
+ * 2. The built-in bundled catalog (WhatsApp, Telegram).
23
+ *
24
+ * Ids and aliases are matched case-insensitively. Unknown ids return
25
+ * `undefined` so callers can apply their own default (the markdown gate
26
+ * deliberately defaults markdown ON for unknown channels — see
27
+ * `isMarkdownCapableChannel`).
28
+ */
29
+ import type { ChannelMeta } from "./types.core.js";
30
+ /**
31
+ * Register (or replace) a channel's meta at runtime. The plugin engine calls
32
+ * this when a channel module registers, so external / future channels surface
33
+ * in the same lookups as the bundled ones. Last registration per id wins.
34
+ * No-ops on a meta without a usable id.
35
+ */
36
+ export declare function registerChannelMeta(meta: ChannelMeta): void;
37
+ /**
38
+ * Drop every dynamically-registered meta (the built-in catalog is untouched).
39
+ * PUBLIC — the gateway's `stopExtensions()` calls this during a `system.reload`
40
+ * teardown so the registry starts clean and the next `startExtensions()` re-
41
+ * registers ONLY the currently-loaded channels (registration is `.set()`-only
42
+ * and never removes, so without this a removed channel's meta would leak across
43
+ * the reload). Idempotent.
44
+ */
45
+ export declare function clearChannelMetaRegistry(): void;
46
+ /** Test-only alias of {@link clearChannelMetaRegistry}. Kept so existing tests don't break. */
47
+ export declare function resetChannelMetaRegistryForTests(): void;
48
+ /**
49
+ * Look up a registered channel plugin's full `ChannelMeta` by id or alias.
50
+ * Returns `undefined` for an unknown channel. Case-insensitive.
51
+ *
52
+ * Named to mirror the upstream accessor (`getRegisteredChannelPluginMeta`) so
53
+ * the parity story is legible; `getChatChannelMeta` is the friendlier alias.
54
+ */
55
+ export declare function getRegisteredChannelPluginMeta(channelId: string | null | undefined): ChannelMeta | undefined;
56
+ /** Friendlier alias for {@link getRegisteredChannelPluginMeta}. */
57
+ export declare function getChatChannelMeta(channelId: string | null | undefined): ChannelMeta | undefined;
58
+ /** Every channel meta currently known (built-in + dynamic), de-duplicated by id. */
59
+ export declare function listChannelMetas(): ChannelMeta[];
60
+ //# sourceMappingURL=channel-meta-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-meta-registry.d.ts","sourceRoot":"","sources":["../../../src/agents/channels/channel-meta-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAkBnD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAI3D;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C;AAED,+FAA+F;AAC/F,wBAAgB,gCAAgC,IAAI,IAAI,CAEvD;AAyBD;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAI5G;AAED,mEAAmE;AACnE,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAEhG;AAED,oFAAoF;AACpF,wBAAgB,gBAAgB,IAAI,WAAW,EAAE,CAahD"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Channel-meta registry — the process-wide lookup behind "what does channel
3
+ * <id> declare about itself?" (markdown capability, exposure, aliases, …).
4
+ *
5
+ * Brand-scrubbed analogue of upstream's `src/channels/registry.ts` +
6
+ * `src/channels/chat-meta.ts` two-tier lookup, collapsed to the slice Brigade
7
+ * needs: a built-in catalog of the bundled channels' metas, plus a dynamic
8
+ * registration seam for channels that register through the plugin engine.
9
+ *
10
+ * WHY A REGISTRY (and not "just read `bundledChannelPlugins`"): the gateway's
11
+ * `bundledChannelPlugins` list (`core/server.ts`) is only populated for the
12
+ * MULTI-ACCOUNT plugin path, and pulling a channel plugin module into the
13
+ * system-prompt layer would eagerly load its adapter (Baileys sockets, the
14
+ * Telegram bot runtime, …). This module is import-light on purpose: the
15
+ * built-in metas are plain data constants (see `bundled-channel-metas.ts`),
16
+ * so the markdown gate + exposure resolver can consult channel metadata from
17
+ * anywhere — including the system-prompt assembly — without dragging the
18
+ * runtime in.
19
+ *
20
+ * Lookup order (mirrors upstream's built-in-then-plugin precedence):
21
+ * 1. Dynamically-registered plugin metas (last registration wins per id).
22
+ * 2. The built-in bundled catalog (WhatsApp, Telegram).
23
+ *
24
+ * Ids and aliases are matched case-insensitively. Unknown ids return
25
+ * `undefined` so callers can apply their own default (the markdown gate
26
+ * deliberately defaults markdown ON for unknown channels — see
27
+ * `isMarkdownCapableChannel`).
28
+ */
29
+ import { resolveGlobalSingleton } from "../../shared/global-singleton.js";
30
+ import { normalizeOptionalLowercaseString } from "../../shared/string-coerce.js";
31
+ import { BUNDLED_CHANNEL_METAS } from "./bundled-channel-metas.js";
32
+ /** Process-global slot so a hot reload (or CLI+gateway in one process) shares one registry. */
33
+ const REGISTRY_STATE_KEY = Symbol.for("brigade.channelMetaRegistry.state");
34
+ function createState() {
35
+ return { dynamic: new Map() };
36
+ }
37
+ function getState() {
38
+ return resolveGlobalSingleton(REGISTRY_STATE_KEY, createState);
39
+ }
40
+ /**
41
+ * Register (or replace) a channel's meta at runtime. The plugin engine calls
42
+ * this when a channel module registers, so external / future channels surface
43
+ * in the same lookups as the bundled ones. Last registration per id wins.
44
+ * No-ops on a meta without a usable id.
45
+ */
46
+ export function registerChannelMeta(meta) {
47
+ const id = normalizeOptionalLowercaseString(meta?.id);
48
+ if (!id)
49
+ return;
50
+ getState().dynamic.set(id, meta);
51
+ }
52
+ /**
53
+ * Drop every dynamically-registered meta (the built-in catalog is untouched).
54
+ * PUBLIC — the gateway's `stopExtensions()` calls this during a `system.reload`
55
+ * teardown so the registry starts clean and the next `startExtensions()` re-
56
+ * registers ONLY the currently-loaded channels (registration is `.set()`-only
57
+ * and never removes, so without this a removed channel's meta would leak across
58
+ * the reload). Idempotent.
59
+ */
60
+ export function clearChannelMetaRegistry() {
61
+ getState().dynamic.clear();
62
+ }
63
+ /** Test-only alias of {@link clearChannelMetaRegistry}. Kept so existing tests don't break. */
64
+ export function resetChannelMetaRegistryForTests() {
65
+ clearChannelMetaRegistry();
66
+ }
67
+ /**
68
+ * Build the merged lookup map for a single resolution pass: built-in catalog
69
+ * first, then dynamic registrations layered on top (dynamic wins per id).
70
+ * Each meta is indexed by its own id AND every declared alias (all lowercased).
71
+ */
72
+ function buildLookup() {
73
+ const byKey = new Map();
74
+ const index = (meta) => {
75
+ const id = normalizeOptionalLowercaseString(meta.id);
76
+ if (!id)
77
+ return;
78
+ byKey.set(id, meta);
79
+ for (const alias of meta.aliases ?? []) {
80
+ const a = normalizeOptionalLowercaseString(alias);
81
+ if (a)
82
+ byKey.set(a, meta);
83
+ }
84
+ };
85
+ for (const meta of BUNDLED_CHANNEL_METAS)
86
+ index(meta);
87
+ // Dynamic registrations layer on top so an external plugin can override a
88
+ // bundled channel's meta (and so its id/aliases win on collision).
89
+ for (const meta of getState().dynamic.values())
90
+ index(meta);
91
+ return byKey;
92
+ }
93
+ /**
94
+ * Look up a registered channel plugin's full `ChannelMeta` by id or alias.
95
+ * Returns `undefined` for an unknown channel. Case-insensitive.
96
+ *
97
+ * Named to mirror the upstream accessor (`getRegisteredChannelPluginMeta`) so
98
+ * the parity story is legible; `getChatChannelMeta` is the friendlier alias.
99
+ */
100
+ export function getRegisteredChannelPluginMeta(channelId) {
101
+ const key = normalizeOptionalLowercaseString(channelId);
102
+ if (!key)
103
+ return undefined;
104
+ return buildLookup().get(key);
105
+ }
106
+ /** Friendlier alias for {@link getRegisteredChannelPluginMeta}. */
107
+ export function getChatChannelMeta(channelId) {
108
+ return getRegisteredChannelPluginMeta(channelId);
109
+ }
110
+ /** Every channel meta currently known (built-in + dynamic), de-duplicated by id. */
111
+ export function listChannelMetas() {
112
+ const seen = new Set();
113
+ const out = [];
114
+ const push = (meta) => {
115
+ const id = normalizeOptionalLowercaseString(meta.id);
116
+ if (!id || seen.has(id))
117
+ return;
118
+ seen.add(id);
119
+ out.push(meta);
120
+ };
121
+ // Dynamic first so an override replaces the bundled entry in the output.
122
+ for (const meta of getState().dynamic.values())
123
+ push(meta);
124
+ for (const meta of BUNDLED_CHANNEL_METAS)
125
+ push(meta);
126
+ return out;
127
+ }
128
+ //# sourceMappingURL=channel-meta-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-meta-registry.js","sourceRoot":"","sources":["../../../src/agents/channels/channel-meta-registry.ts"],"names":[],"mappings":"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"}