@spinabot/brigade 1.3.1 → 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 (231) 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/gateway.d.ts.map +1 -1
  191. package/dist/cli/commands/gateway.js +6 -0
  192. package/dist/cli/commands/gateway.js.map +1 -1
  193. package/dist/cli/commands/pairing.d.ts.map +1 -1
  194. package/dist/cli/commands/pairing.js +16 -2
  195. package/dist/cli/commands/pairing.js.map +1 -1
  196. package/dist/cli/commands/update.d.ts +17 -0
  197. package/dist/cli/commands/update.d.ts.map +1 -0
  198. package/dist/cli/commands/update.js +104 -0
  199. package/dist/cli/commands/update.js.map +1 -0
  200. package/dist/cli/program/build-program.d.ts.map +1 -1
  201. package/dist/cli/program/build-program.js +113 -0
  202. package/dist/cli/program/build-program.js.map +1 -1
  203. package/dist/config/paths.d.ts +1 -0
  204. package/dist/config/paths.d.ts.map +1 -1
  205. package/dist/config/paths.js +9 -0
  206. package/dist/config/paths.js.map +1 -1
  207. package/dist/core/gateway-probe.d.ts.map +1 -1
  208. package/dist/core/gateway-probe.js +9 -1
  209. package/dist/core/gateway-probe.js.map +1 -1
  210. package/dist/core/server.d.ts.map +1 -1
  211. package/dist/core/server.js +134 -2
  212. package/dist/core/server.js.map +1 -1
  213. package/dist/protocol.d.ts +25 -0
  214. package/dist/protocol.d.ts.map +1 -1
  215. package/dist/protocol.js.map +1 -1
  216. package/dist/system-prompt/assembler.d.ts.map +1 -1
  217. package/dist/system-prompt/assembler.js +17 -0
  218. package/dist/system-prompt/assembler.js.map +1 -1
  219. package/dist/system-prompt/identity-defaults.d.ts +28 -0
  220. package/dist/system-prompt/identity-defaults.d.ts.map +1 -1
  221. package/dist/system-prompt/identity-defaults.js +47 -0
  222. package/dist/system-prompt/identity-defaults.js.map +1 -1
  223. package/dist/ui/editor.d.ts.map +1 -1
  224. package/dist/ui/editor.js +1 -0
  225. package/dist/ui/editor.js.map +1 -1
  226. package/dist/version.d.ts +4 -3
  227. package/dist/version.d.ts.map +1 -1
  228. package/dist/version.js +27 -5
  229. package/dist/version.js.map +1 -1
  230. package/package.json +21 -4
  231. package/scripts/build-done.mjs +11 -2
@@ -38,12 +38,13 @@ import { DEFAULT_PORT, isFrame, modelToSummary, TICK_INTERVAL_MS, } from "../pro
38
38
  // session is surfaced for the turn's lifetime via `onSessionReady` so the
39
39
  // gateway can steer / abort / switch-model mid-stream.
40
40
  import { applyAutoEnableA2AAtBoot } from "../agents/a2a-policy-canonicalize.js";
41
- import { runResilientTurn } from "../agents/agent-loop.js";
41
+ import { flattenAssistantContent, runResilientTurn } from "../agents/agent-loop.js";
42
42
  import { BUNDLED_MODULES, clearDiscoveryCache, loadModules } from "../agents/extensions/index.js";
43
43
  import { setActiveRegistry } from "../agents/extensions/active-registry.js";
44
44
  import { DEFAULT_MAX_BODY_BYTES, DEFAULT_TIMEOUT_MS, readBodyWithLimit } from "./webhook-guards.js";
45
45
  import { extractFrameTags, shouldDeliverFrame } from "./ws-subscription-filter.js";
46
46
  import { setActiveChannelManager } from "../agents/channels/active-manager.js";
47
+ import { sanitizeReplyForChannel } from "../agents/channels/reply-sanitizer.js";
47
48
  import { startChannels } from "../agents/channels/manager.js";
48
49
  import { createChannelPluginManager, } from "../agents/channels/channel-plugin-manager.js";
49
50
  import { listWhatsAppAccountIds, whatsappChannelEnabled } from "../agents/channels/whatsapp/account-config.js";
@@ -51,6 +52,9 @@ import { createWhatsAppPlugin } from "../agents/channels/whatsapp/plugin.js";
51
52
  import { listTelegramAccountIds, telegramChannelEnabled, telegramThreadIdleTtlMs, } from "../agents/channels/telegram/account-config.js";
52
53
  import { createTelegramPlugin } from "../agents/channels/telegram/plugin.js";
53
54
  import { createPluginChannelManagerFacade } from "../agents/channels/plugin-channel-manager-facade.js";
55
+ import { clearChannelMessagingRegistry, syncChannelMessagingAdaptersFromPlugins, } from "../agents/channels/channel-messaging-registry.js";
56
+ import { clearChannelSecurityRegistry, syncChannelSecurityAdaptersFromPlugins, } from "../agents/channels/channel-security-registry.js";
57
+ import { clearChannelMetaRegistry, registerChannelMeta } from "../agents/channels/channel-meta-registry.js";
54
58
  import { makeOpQueue, withTimeout } from "./extension-lifecycle.js";
55
59
  import { resolveModelNeverMiss } from "../agents/model-resolution.js";
56
60
  import { listOpenRouterModels } from "../integrations/provider-discovery.js";
@@ -116,6 +120,8 @@ import { queryMemory } from "../agents/memory/query.js";
116
120
  import { FactStore } from "../agents/memory/records.js";
117
121
  import { makeConsolidationLlm, markConsolidationRun, runConsolidation, shouldRunConsolidation, } from "../agents/memory/consolidate.js";
118
122
  import { loadBrigadeAuthStorage } from "./auth-bridge.js";
123
+ import { validateApiKeyOnline } from "../providers/validate-key.js";
124
+ import { upsertApiKeyProfile } from "../auth/profiles.js";
119
125
  import { getBrigadeWorkspaceDir, loadConfig, saveConfig } from "./config.js";
120
126
  import { mutateConfigAtomic } from "../config/io.js";
121
127
  import { acquireGatewayLock } from "./gateway-lock.js";
@@ -1950,6 +1956,53 @@ async function continueBoot(args) {
1950
1956
  }
1951
1957
  };
1952
1958
  };
1959
+ /**
1960
+ * OPTIONAL live-streaming delta forwarder. Subscribes to the SAME Pi session
1961
+ * `attachTurnSession` watches, but extracts only the accumulating assistant
1962
+ * ANSWER text from each `message_update` and forwards it to the channel's
1963
+ * `onReplyDelta` sink so the channel can progressively edit its message. The
1964
+ * `<think>` reasoning is stripped here with the same sanitizer the final
1965
+ * reply uses, so a stream never leaks reasoning into a channel preview.
1966
+ *
1967
+ * When `sink` is undefined (TUI / cron / sub-agent / RPC callers) this is a
1968
+ * no-op that returns an inert detach — those turns never stream.
1969
+ */
1970
+ const attachReplyDeltaForwarder = (session, sink) => {
1971
+ if (!sink)
1972
+ return () => { };
1973
+ const detach = session.subscribe((piEvent) => {
1974
+ if (piEvent.type !== "message_update" && piEvent.type !== "message_end")
1975
+ return;
1976
+ const message = piEvent.message;
1977
+ if (!message || message.role !== "assistant")
1978
+ return;
1979
+ const raw = flattenAssistantContent(message.content);
1980
+ if (!raw)
1981
+ return;
1982
+ // Strip reasoning so the live preview shows only the answer-in-progress.
1983
+ const answer = sanitizeReplyForChannel(raw);
1984
+ if (answer) {
1985
+ try {
1986
+ sink(answer);
1987
+ }
1988
+ catch {
1989
+ /* a misbehaving sink must never break the turn */
1990
+ }
1991
+ }
1992
+ });
1993
+ let cleaned = false;
1994
+ return () => {
1995
+ if (cleaned)
1996
+ return;
1997
+ cleaned = true;
1998
+ try {
1999
+ detach();
2000
+ }
2001
+ catch {
2002
+ /* session may already be torn down */
2003
+ }
2004
+ };
2005
+ };
1953
2006
  // Sub-agent pi-event forwarder (Primitive #6). The gateway's
1954
2007
  // `attachTurnSession` only subscribes to the TOP-LEVEL Pi session — when
1955
2008
  // a sub-agent runs (via `subagent-runner` recursing into `runSingleTurn`),
@@ -2231,7 +2284,12 @@ async function continueBoot(args) {
2231
2284
  if (turnState.cleanup)
2232
2285
  turnState.cleanup();
2233
2286
  turnState.activeSession = session;
2234
- turnState.cleanup = attachTurnSession(session, turnSessionKey, targetAgentId);
2287
+ const detachStream = attachReplyDeltaForwarder(session, turn.onReplyDelta);
2288
+ const detachTurn = attachTurnSession(session, turnSessionKey, targetAgentId);
2289
+ turnState.cleanup = () => {
2290
+ detachStream();
2291
+ detachTurn();
2292
+ };
2235
2293
  },
2236
2294
  });
2237
2295
  // Queue a debounced, batched memory-extraction sweep over the settled
@@ -2753,6 +2811,49 @@ async function continueBoot(args) {
2753
2811
  broadcastStateAllBindings();
2754
2812
  return undefined;
2755
2813
  }
2814
+ case "add-provider": {
2815
+ const p = params;
2816
+ // Adding a provider persists a gateway-WIDE credential — strictly an
2817
+ // operator write. Every WS connection is currently granted the full
2818
+ // operator scope set (single-operator model), but gate explicitly so
2819
+ // the day a narrower scope is issued, key-add stays owner-only.
2820
+ if (!caller.scopes.includes("operator.write") &&
2821
+ !caller.scopes.includes("operator.admin")) {
2822
+ const err = new Error("add-provider requires operator.write");
2823
+ err.code = "forbidden";
2824
+ throw err;
2825
+ }
2826
+ const providerId = p.providerId?.trim();
2827
+ const apiKey = p.apiKey?.trim();
2828
+ if (!providerId)
2829
+ throw new Error("providerId is required");
2830
+ if (!apiKey)
2831
+ throw new Error("apiKey is required");
2832
+ // Live validation against the provider's models endpoint (8s timeout):
2833
+ // 401/403 hard-reject; rate-limit / outage soft-accept with a warning.
2834
+ let warning;
2835
+ let modelCount;
2836
+ if (!p.skipValidation) {
2837
+ const v = await validateApiKeyOnline(providerId, apiKey);
2838
+ if (!v.ok)
2839
+ throw new Error(v.reason);
2840
+ warning = v.warning;
2841
+ modelCount = v.modelCount;
2842
+ }
2843
+ // Persist into main's auth-profiles.json (mode 0600) — the same store
2844
+ // `brigade onboard` writes, so the key survives a gateway restart.
2845
+ upsertApiKeyProfile(DEFAULT_AGENT_ID, { provider: providerId, key: apiKey });
2846
+ // Hot-load the credential into the gateway's live auth view so the model
2847
+ // registry resolves this provider's models on the NEXT turn without a
2848
+ // restart. `authStorage` is the boot store ModelRegistry was created with.
2849
+ authStorage.set(providerId, { type: "api_key", key: apiKey });
2850
+ // Drop cached per-agent auth views so non-boot agents rebuild from disk
2851
+ // and see the new credential too (boot agent re-caches `authStorage`).
2852
+ authStorageByAgent.clear();
2853
+ modelRegistry.refresh();
2854
+ broadcastStateAllBindings();
2855
+ return { ok: true, provider: providerId, modelCount, warning };
2856
+ }
2756
2857
  case "get-state": {
2757
2858
  return buildSnapshot();
2758
2859
  }
@@ -4364,6 +4465,17 @@ async function continueBoot(args) {
4364
4465
  opts.consoleStream?.info?.(`service ${id} stop error: ${err instanceof Error ? err.message : String(err)}`);
4365
4466
  }
4366
4467
  }
4468
+ // Reset the process-wide channel slot registries (messaging / security /
4469
+ // meta). These are populated by `startExtensions()` via a `.set()`-only sync
4470
+ // seam that never REMOVES a slot, so an operator who removes/edits a slot-
4471
+ // bearing channel and reloads would otherwise leak its stale adapter: a stale
4472
+ // security adapter keeps TIGHTENING DM policy (security-relevant) and a stale
4473
+ // messaging adapter keeps rewriting outbound targets. Clearing here means a
4474
+ // reload starts clean and `startExtensions()` re-syncs ONLY the currently-
4475
+ // loaded channels. Each clear is idempotent + total, so shutdown is safe too.
4476
+ clearChannelMessagingRegistry();
4477
+ clearChannelSecurityRegistry();
4478
+ clearChannelMetaRegistry();
4367
4479
  };
4368
4480
  // Load the extension registry and start/mount everything it yields: channels,
4369
4481
  // background services, HTTP routes, gateway methods, plus a built-in
@@ -4383,6 +4495,16 @@ async function continueBoot(args) {
4383
4495
  // pipeline reaching a TranscriptionProvider) can fetch it without threading it
4384
4496
  // through every channel adapter's args. Cleared on shutdown.
4385
4497
  setActiveRegistry(registry);
4498
+ // Channel slot registries — populate the process-wide messaging + security
4499
+ // registries from EVERY channel that declared `b.channelMessaging(...)` /
4500
+ // `b.channelSecurity(...)`, over the FULL registered set (bundled + user
4501
+ // channels alike), UNCONDITIONALLY — never gated on the multi-account branch
4502
+ // below. Without this, a channel that declares a `messaging`/`security` slot
4503
+ // is inert: the `send_message` outbound resolver + the inbound DM-policy
4504
+ // consult never see it. A channel that omits the slot registers nothing and
4505
+ // keeps today's raw-id / central-policy behaviour by construction.
4506
+ syncChannelMessagingAdaptersFromPlugins(registry.channelMessagingAdapters);
4507
+ syncChannelSecurityAdaptersFromPlugins(registry.channelSecurityAdapters);
4386
4508
  // Gateway methods: module-registered RPCs + two built-ins. The `system.`
4387
4509
  // prefix is reserved for built-ins — a module that uses it would be
4388
4510
  // silently overwritten below, so warn instead of failing quietly.
@@ -4611,6 +4733,16 @@ async function continueBoot(args) {
4611
4733
  multiAccountSummary.push(`telegram x${telegramAccounts.length}`);
4612
4734
  }
4613
4735
  const pluginById = new Map(bundledChannelPlugins.map((p) => [p.id, p]));
4736
+ // Register each constructed plugin's `meta` + its `messaging`/`security`
4737
+ // slots into the process-wide registries. These are full `ChannelPlugin`
4738
+ // objects (carrying the slots) that are NOT registered through the
4739
+ // `b.channelMessaging`/`b.channelSecurity` context seam, so the
4740
+ // registry-getter sync above doesn't see them — wire them here so a
4741
+ // multi-account plugin's declared slots are live too.
4742
+ for (const plugin of bundledChannelPlugins)
4743
+ registerChannelMeta(plugin.meta);
4744
+ syncChannelMessagingAdaptersFromPlugins(bundledChannelPlugins);
4745
+ syncChannelSecurityAdaptersFromPlugins(bundledChannelPlugins);
4614
4746
  channelPluginManager = createChannelPluginManager({
4615
4747
  loadConfig: () => cfg,
4616
4748
  listChannelPlugins: () => bundledChannelPlugins,