@spinabot/brigade 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/convex/channels.d.ts +5 -5
  2. package/convex/schema.d.ts +2 -2
  3. package/dist/agents/agent-loop.d.ts.map +1 -1
  4. package/dist/agents/agent-loop.js +27 -4
  5. package/dist/agents/agent-loop.js.map +1 -1
  6. package/dist/agents/channels/approval-callback-codec.d.ts +107 -0
  7. package/dist/agents/channels/approval-callback-codec.d.ts.map +1 -0
  8. package/dist/agents/channels/approval-callback-codec.js +173 -0
  9. package/dist/agents/channels/approval-callback-codec.js.map +1 -0
  10. package/dist/agents/channels/approval-router.d.ts +77 -20
  11. package/dist/agents/channels/approval-router.d.ts.map +1 -1
  12. package/dist/agents/channels/approval-router.js +163 -37
  13. package/dist/agents/channels/approval-router.js.map +1 -1
  14. package/dist/agents/channels/backoff.d.ts +55 -0
  15. package/dist/agents/channels/backoff.d.ts.map +1 -0
  16. package/dist/agents/channels/backoff.js +47 -0
  17. package/dist/agents/channels/backoff.js.map +1 -0
  18. package/dist/agents/channels/channel-secrets.d.ts +45 -0
  19. package/dist/agents/channels/channel-secrets.d.ts.map +1 -0
  20. package/dist/agents/channels/channel-secrets.js +69 -0
  21. package/dist/agents/channels/channel-secrets.js.map +1 -0
  22. package/dist/agents/channels/inbound-pipeline.d.ts.map +1 -1
  23. package/dist/agents/channels/inbound-pipeline.js +67 -3
  24. package/dist/agents/channels/inbound-pipeline.js.map +1 -1
  25. package/dist/agents/channels/last-sent-message.d.ts +46 -0
  26. package/dist/agents/channels/last-sent-message.d.ts.map +1 -0
  27. package/dist/agents/channels/last-sent-message.js +55 -0
  28. package/dist/agents/channels/last-sent-message.js.map +1 -0
  29. package/dist/agents/channels/manager.d.ts +52 -0
  30. package/dist/agents/channels/manager.d.ts.map +1 -1
  31. package/dist/agents/channels/manager.js +141 -31
  32. package/dist/agents/channels/manager.js.map +1 -1
  33. package/dist/agents/channels/plugin-channel-manager-facade.d.ts +13 -2
  34. package/dist/agents/channels/plugin-channel-manager-facade.d.ts.map +1 -1
  35. package/dist/agents/channels/plugin-channel-manager-facade.js +21 -0
  36. package/dist/agents/channels/plugin-channel-manager-facade.js.map +1 -1
  37. package/dist/agents/channels/sdk.d.ts +426 -0
  38. package/dist/agents/channels/sdk.d.ts.map +1 -0
  39. package/dist/agents/channels/sdk.js +274 -0
  40. package/dist/agents/channels/sdk.js.map +1 -0
  41. package/dist/agents/channels/telegram/account-config.d.ts +92 -0
  42. package/dist/agents/channels/telegram/account-config.d.ts.map +1 -0
  43. package/dist/agents/channels/telegram/account-config.js +192 -0
  44. package/dist/agents/channels/telegram/account-config.js.map +1 -0
  45. package/dist/agents/channels/telegram/adapter.d.ts +79 -0
  46. package/dist/agents/channels/telegram/adapter.d.ts.map +1 -0
  47. package/dist/agents/channels/telegram/adapter.js +475 -0
  48. package/dist/agents/channels/telegram/adapter.js.map +1 -0
  49. package/dist/agents/channels/telegram/allowed-updates.d.ts +44 -0
  50. package/dist/agents/channels/telegram/allowed-updates.d.ts.map +1 -0
  51. package/dist/agents/channels/telegram/allowed-updates.js +52 -0
  52. package/dist/agents/channels/telegram/allowed-updates.js.map +1 -0
  53. package/dist/agents/channels/telegram/approval-authorize.d.ts +41 -0
  54. package/dist/agents/channels/telegram/approval-authorize.d.ts.map +1 -0
  55. package/dist/agents/channels/telegram/approval-authorize.js +69 -0
  56. package/dist/agents/channels/telegram/approval-authorize.js.map +1 -0
  57. package/dist/agents/channels/telegram/approval-native.d.ts +68 -0
  58. package/dist/agents/channels/telegram/approval-native.d.ts.map +1 -0
  59. package/dist/agents/channels/telegram/approval-native.js +94 -0
  60. package/dist/agents/channels/telegram/approval-native.js.map +1 -0
  61. package/dist/agents/channels/telegram/command-menu.d.ts +35 -0
  62. package/dist/agents/channels/telegram/command-menu.d.ts.map +1 -0
  63. package/dist/agents/channels/telegram/command-menu.js +59 -0
  64. package/dist/agents/channels/telegram/command-menu.js.map +1 -0
  65. package/dist/agents/channels/telegram/connection.d.ts +359 -0
  66. package/dist/agents/channels/telegram/connection.d.ts.map +1 -0
  67. package/dist/agents/channels/telegram/connection.js +865 -0
  68. package/dist/agents/channels/telegram/connection.js.map +1 -0
  69. package/dist/agents/channels/telegram/format.d.ts +48 -0
  70. package/dist/agents/channels/telegram/format.d.ts.map +1 -0
  71. package/dist/agents/channels/telegram/format.js +256 -0
  72. package/dist/agents/channels/telegram/format.js.map +1 -0
  73. package/dist/agents/channels/telegram/inbound-extras.d.ts +73 -0
  74. package/dist/agents/channels/telegram/inbound-extras.d.ts.map +1 -0
  75. package/dist/agents/channels/telegram/inbound-extras.js +231 -0
  76. package/dist/agents/channels/telegram/inbound-extras.js.map +1 -0
  77. package/dist/agents/channels/telegram/index.d.ts +14 -0
  78. package/dist/agents/channels/telegram/index.d.ts.map +1 -0
  79. package/dist/agents/channels/telegram/index.js +14 -0
  80. package/dist/agents/channels/telegram/index.js.map +1 -0
  81. package/dist/agents/channels/telegram/media.d.ts +68 -0
  82. package/dist/agents/channels/telegram/media.d.ts.map +1 -0
  83. package/dist/agents/channels/telegram/media.js +143 -0
  84. package/dist/agents/channels/telegram/media.js.map +1 -0
  85. package/dist/agents/channels/telegram/module.d.ts +15 -0
  86. package/dist/agents/channels/telegram/module.d.ts.map +1 -0
  87. package/dist/agents/channels/telegram/module.js +36 -0
  88. package/dist/agents/channels/telegram/module.js.map +1 -0
  89. package/dist/agents/channels/telegram/plugin.d.ts +76 -0
  90. package/dist/agents/channels/telegram/plugin.d.ts.map +1 -0
  91. package/dist/agents/channels/telegram/plugin.js +314 -0
  92. package/dist/agents/channels/telegram/plugin.js.map +1 -0
  93. package/dist/agents/channels/telegram/probe.d.ts +54 -0
  94. package/dist/agents/channels/telegram/probe.d.ts.map +1 -0
  95. package/dist/agents/channels/telegram/probe.js +95 -0
  96. package/dist/agents/channels/telegram/probe.js.map +1 -0
  97. package/dist/agents/channels/telegram/webhook.d.ts +55 -0
  98. package/dist/agents/channels/telegram/webhook.d.ts.map +1 -0
  99. package/dist/agents/channels/telegram/webhook.js +141 -0
  100. package/dist/agents/channels/telegram/webhook.js.map +1 -0
  101. package/dist/agents/extensions/modules/index.d.ts.map +1 -1
  102. package/dist/agents/extensions/modules/index.js +4 -0
  103. package/dist/agents/extensions/modules/index.js.map +1 -1
  104. package/dist/agents/extensions/types.d.ts +72 -2
  105. package/dist/agents/extensions/types.d.ts.map +1 -1
  106. package/dist/agents/extensions/types.js.map +1 -1
  107. package/dist/agents/tools/connect-channel-tool.d.ts +86 -0
  108. package/dist/agents/tools/connect-channel-tool.d.ts.map +1 -0
  109. package/dist/agents/tools/connect-channel-tool.js +398 -0
  110. package/dist/agents/tools/connect-channel-tool.js.map +1 -0
  111. package/dist/agents/tools/message-action-tool.d.ts +67 -0
  112. package/dist/agents/tools/message-action-tool.d.ts.map +1 -0
  113. package/dist/agents/tools/message-action-tool.js +216 -0
  114. package/dist/agents/tools/message-action-tool.js.map +1 -0
  115. package/dist/agents/tools/registry.d.ts.map +1 -1
  116. package/dist/agents/tools/registry.js +19 -0
  117. package/dist/agents/tools/registry.js.map +1 -1
  118. package/dist/buildstamp.json +1 -1
  119. package/dist/cli/commands/channels.d.ts.map +1 -1
  120. package/dist/cli/commands/channels.js +27 -2
  121. package/dist/cli/commands/channels.js.map +1 -1
  122. package/dist/core/server.d.ts.map +1 -1
  123. package/dist/core/server.js +77 -27
  124. package/dist/core/server.js.map +1 -1
  125. package/dist/cron/service/state.d.ts +10 -0
  126. package/dist/cron/service/state.d.ts.map +1 -1
  127. package/dist/cron/service/state.js.map +1 -1
  128. package/dist/cron/service/timer.d.ts.map +1 -1
  129. package/dist/cron/service/timer.js +43 -14
  130. package/dist/cron/service/timer.js.map +1 -1
  131. package/dist/cron/session-reaper.d.ts +27 -0
  132. package/dist/cron/session-reaper.d.ts.map +1 -1
  133. package/dist/cron/session-reaper.js +81 -0
  134. package/dist/cron/session-reaper.js.map +1 -1
  135. package/dist/system-prompt/assembler.d.ts +14 -0
  136. package/dist/system-prompt/assembler.d.ts.map +1 -1
  137. package/dist/system-prompt/assembler.js +36 -14
  138. package/dist/system-prompt/assembler.js.map +1 -1
  139. package/package.json +22 -6
@@ -0,0 +1,398 @@
1
+ /**
2
+ * `connect_channel` — let the crew connect / disconnect a messaging channel
3
+ * from chat, LIVE, without a gateway restart.
4
+ *
5
+ * This is the marquee of the channel-foundation work: the operator can say
6
+ * "connect Telegram, here's the token from @BotFather" and the agent runs ONE
7
+ * grounded tool call that (1) seals the token as a `${VAR}` secret-ref in config
8
+ * (never the raw value on disk), (2) flips `channels.<channel>.enabled = true`
9
+ * via `mutateConfigAtomic`, and (3) starts the channel adapter live through the
10
+ * channel manager (`getActiveChannelManager().startChannel(id)`). No
11
+ * hand-editing brigade.json, no `brigade gateway restart`.
12
+ *
13
+ * GATING — per-call `senderIsOwner` (the cron-tool doctrine, NOT blanket
14
+ * ownerOnly):
15
+ * - `list` / `status` are READ-ONLY and safe for anyone (peers can see what's
16
+ * connected + each channel's health).
17
+ * - `connect` / `disconnect` MOVE A SECURITY BOUNDARY (they wire up / tear
18
+ * down a live messaging surface and persist credentials). A channel peer
19
+ * must NEVER do this, so those actions are refused unless the turn is
20
+ * owner-routed. `senderIsOwner` defaults to TRUE so the TUI / direct-RPC /
21
+ * test paths keep full access; the gateway threads `false` for
22
+ * approved-non-owner channel peers.
23
+ *
24
+ * SECRET HANDLING — durable seal + live env ref (two layers):
25
+ * - DURABLE: the token is written to Brigade's encrypted credential store via
26
+ * `sealChannelToken` (atomic 0600 JSON on disk; AES-256-GCM sealed in convex
27
+ * mode). This is the source of truth ACROSS a gateway reboot — the channel
28
+ * reads it back at start even after the process (and its env) is gone. This
29
+ * closes the gap where an env-only token evaporated on restart and the
30
+ * channel silently failed to authenticate.
31
+ * - LIVE: the raw token is also set into `process.env[BRIGADE_<CHANNEL>_TOKEN]`
32
+ * and the config stores ONLY the literal ref `"${BRIGADE_<CHANNEL>_TOKEN}"`
33
+ * so the just-started adapter resolves it immediately this process.
34
+ * - The resolved token NEVER touches brigade.json (only the `${VAR}` ref), and
35
+ * the tool result masks it.
36
+ */
37
+ import { Type } from "typebox";
38
+ import { loadConfig } from "../../core/config.js";
39
+ import { mutateConfigAtomic } from "../../config/io.js";
40
+ import { getActiveChannelManager } from "../channels/active-manager.js";
41
+ import { sealChannelToken } from "../channels/channel-secrets.js";
42
+ import { getActiveRegistry } from "../extensions/active-registry.js";
43
+ import { createSubsystemLogger } from "../../logging/subsystem-logger.js";
44
+ import { jsonResult } from "./common.js";
45
+ const log = createSubsystemLogger("tools/connect-channel");
46
+ const ConnectChannelParams = Type.Object({
47
+ action: Type.Union([
48
+ Type.Literal("list"),
49
+ Type.Literal("status"),
50
+ Type.Literal("connect"),
51
+ Type.Literal("disconnect"),
52
+ ], {
53
+ description: "list/status: report available + connected channels and their health (read-only, safe). connect: enable a channel + (when needed) store its token + start it LIVE. disconnect: stop + disable a channel at runtime.",
54
+ }),
55
+ channel: Type.Optional(Type.String({
56
+ description: 'Channel id under config.channels (e.g. "telegram", "whatsapp"). Required for connect / disconnect; for status, narrows to one channel.',
57
+ minLength: 1,
58
+ maxLength: 64,
59
+ })),
60
+ token: Type.Optional(Type.String({
61
+ description: "Secret/credential to connect a TOKEN-based channel (e.g. the Telegram bot token from @BotFather). Stored as a `${VAR}` secret-ref — NEVER persisted raw. Omit for channels that pair another way (WhatsApp uses a QR link, not a token — point the operator at `brigade channels link --channel whatsapp`).",
62
+ maxLength: 8192,
63
+ })),
64
+ });
65
+ export function makeConnectChannelTool(opts = {}) {
66
+ // Default to owner-access when omitted so legacy paths (TUI / tests) keep
67
+ // the previous full-access behaviour (same convention as cron-tool).
68
+ const senderIsOwner = opts.senderIsOwner !== false;
69
+ return {
70
+ name: "connect_channel",
71
+ label: "Connect Channel",
72
+ displaySummary: "connecting a messaging channel",
73
+ // NOTE: deliberately NOT `ownerOnly: true`. list/status are safe for
74
+ // peers; the per-call gate below refuses ONLY the mutating actions.
75
+ description: [
76
+ "Connect or disconnect a messaging channel (Telegram, WhatsApp, …) from chat, live, without a gateway restart.",
77
+ "list / status: report available + connected channels and their health (read-only — anyone can call).",
78
+ "connect {channel, token?}: OWNER-ONLY. Enables the channel, seals a provided token as a `${VAR}` secret-ref (never stored raw), and starts it LIVE via the channel manager. For token channels (Telegram) pass `token`; for QR channels (WhatsApp) omit it and tell the operator to run `brigade channels link --channel whatsapp`.",
79
+ "disconnect {channel}: OWNER-ONLY. Stops + disables the channel at runtime.",
80
+ "Call connect/disconnect ONLY on explicit operator request; report exactly what changed. Never hand-edit brigade.json — the config-write guard refuses it.",
81
+ ].join(" "),
82
+ parameters: ConnectChannelParams,
83
+ execute: async (_toolCallId, args) => {
84
+ const action = args.action;
85
+ // READ-ONLY actions — safe for anyone.
86
+ if (action === "list" || action === "status") {
87
+ const wantChannel = (args.channel ?? "").trim().toLowerCase();
88
+ const views = buildChannelViews(wantChannel || undefined);
89
+ if (action === "status" && wantChannel) {
90
+ const view = views.find((v) => v.channel === wantChannel);
91
+ if (!view) {
92
+ return jsonResult({
93
+ action,
94
+ ok: false,
95
+ message: `No channel adapter registered with id "${wantChannel}". Available: ${listAvailableIds().join(", ") || "none"}.`,
96
+ });
97
+ }
98
+ return jsonResult({
99
+ action,
100
+ ok: true,
101
+ channelState: view,
102
+ message: describeView(view),
103
+ });
104
+ }
105
+ return jsonResult({
106
+ action,
107
+ ok: true,
108
+ channels: views,
109
+ message: summarizeViews(views),
110
+ });
111
+ }
112
+ // MUTATING actions — owner-gated (per-call).
113
+ if (!senderIsOwner) {
114
+ return jsonResult({
115
+ action,
116
+ ok: false,
117
+ message: "connect_channel: connecting or disconnecting a channel is owner-only — a channel peer cannot alter the operator's channels. Ask the operator to do this from the TUI.",
118
+ });
119
+ }
120
+ const channel = (args.channel ?? "").trim().toLowerCase();
121
+ if (!channel) {
122
+ return jsonResult({
123
+ action,
124
+ ok: false,
125
+ message: `connect_channel ${action}: a channel id is required (e.g. "telegram").`,
126
+ });
127
+ }
128
+ // The adapter must be a registered, bundled channel — refuse arbitrary ids.
129
+ const known = listAvailableIds();
130
+ if (!known.includes(channel)) {
131
+ return jsonResult({
132
+ action,
133
+ ok: false,
134
+ message: `connect_channel ${action}: no channel adapter registered with id "${channel}". Available: ${known.join(", ") || "none"}.`,
135
+ });
136
+ }
137
+ if (action === "connect")
138
+ return connectChannel(channel, args.token);
139
+ return disconnectChannel(channel);
140
+ },
141
+ };
142
+ }
143
+ /* ───────────────────────────── connect ───────────────────────────── */
144
+ async function connectChannel(channel, rawToken) {
145
+ const token = (rawToken ?? "").trim();
146
+ // 1) Persist: enable the channel + (when a token was supplied) seal it.
147
+ // Two-layer seal so the token survives BOTH this process and a reboot:
148
+ // (a) DURABLE: write the token to the encrypted credential store
149
+ // (`sealChannelToken`) — atomic 0600 on disk, AES-256-GCM in convex
150
+ // mode. This is what the channel reads back at start AFTER a gateway
151
+ // restart (env is gone by then). Source of truth across reboots.
152
+ // (b) LIVE: set `process.env[VAR]` + a `${VAR}` ref in brigade.json so
153
+ // the just-started adapter resolves the token immediately this
154
+ // process without re-reading the sealed store.
155
+ // The raw token NEVER lands in brigade.json (only the `${VAR}` ref) and
156
+ // the tool result masks it.
157
+ let envVarName;
158
+ if (token) {
159
+ // (a) durable encrypted seal — survives the reboot.
160
+ try {
161
+ sealChannelToken(channel, token);
162
+ }
163
+ catch (err) {
164
+ log.warn("connect_channel: durable token seal failed (continuing with env ref)", {
165
+ channel,
166
+ error: err instanceof Error ? err.message : String(err),
167
+ });
168
+ }
169
+ // (b) live env for immediate resolution this process.
170
+ envVarName = secretEnvVarName(channel);
171
+ process.env[envVarName] = token;
172
+ }
173
+ const next = await mutateConfigAtomic((current) => {
174
+ const merged = { ...current };
175
+ const channels = {
176
+ ...(merged.channels ?? {}),
177
+ };
178
+ const entry = { ...(channels[channel] ?? {}) };
179
+ entry.enabled = true;
180
+ if (envVarName) {
181
+ // Store the literal ref string — a brand-new field is written verbatim
182
+ // by restoreEnvVarRefsRecursive, so `${VAR}` lands on disk (NOT the
183
+ // resolved token). For Telegram this is the canonical `botToken` slot.
184
+ entry[tokenConfigKey(channel)] = `\${${envVarName}}`;
185
+ }
186
+ channels[channel] = entry;
187
+ merged.channels = channels;
188
+ return merged;
189
+ });
190
+ // 2) Start it LIVE through the channel manager (no gateway restart). Pass the
191
+ // freshly-written config so isConfigured + start() see enabled + the token.
192
+ const manager = getActiveChannelManager();
193
+ if (!manager) {
194
+ // Honest fallback — config is written, but no live manager to start it.
195
+ log.info("connect_channel: config written but no live channel manager", { channel });
196
+ return jsonResult({
197
+ action: "connect",
198
+ ok: true,
199
+ started: false,
200
+ channelState: viewFor(channel, next),
201
+ message: `Configured "${channel}" (enabled${token ? " + token sealed" : ""}). The gateway isn't running, so it will connect on next start. Run \`brigade gateway\` (or restart it) to connect now.`,
202
+ });
203
+ }
204
+ const result = await manager.startChannel(channel, next);
205
+ const view = viewFor(channel, next);
206
+ if (result.ok) {
207
+ return jsonResult({
208
+ action: "connect",
209
+ ok: true,
210
+ started: result.started,
211
+ channelState: view,
212
+ message: result.started
213
+ ? `Connected "${channel}" — it's live now${token ? " (token sealed as a secret ref)" : ""}. ${describeView(view)}`
214
+ : `"${channel}" is already connected. ${describeView(view)}`,
215
+ });
216
+ }
217
+ // Config is written but the live start didn't take (e.g. still not
218
+ // configured, or the adapter's start threw). Be HONEST: report it and give
219
+ // the restart fallback.
220
+ return jsonResult({
221
+ action: "connect",
222
+ ok: false,
223
+ started: false,
224
+ channelState: view,
225
+ message: `Saved config for "${channel}" but couldn't start it live: ${result.message ?? result.reason ?? "unknown error"}. ${remediationFor(channel)}`,
226
+ });
227
+ }
228
+ /* ───────────────────────────── disconnect ───────────────────────────── */
229
+ async function disconnectChannel(channel) {
230
+ // 1) Stop it live (if a manager is running + it's started).
231
+ const manager = getActiveChannelManager();
232
+ let stopped = false;
233
+ if (manager) {
234
+ const res = await manager.stopChannel(channel);
235
+ stopped = res.stopped;
236
+ }
237
+ // 2) Disable it in config so it doesn't come back on the next boot.
238
+ const next = await mutateConfigAtomic((current) => {
239
+ const merged = { ...current };
240
+ const channels = {
241
+ ...(merged.channels ?? {}),
242
+ };
243
+ const entry = { ...(channels[channel] ?? {}) };
244
+ entry.enabled = false;
245
+ channels[channel] = entry;
246
+ merged.channels = channels;
247
+ return merged;
248
+ });
249
+ const view = viewFor(channel, next);
250
+ return jsonResult({
251
+ action: "disconnect",
252
+ ok: true,
253
+ stopped,
254
+ channelState: view,
255
+ message: stopped
256
+ ? `Disconnected "${channel}" — stopped it live and disabled it in config (won't reconnect on restart).`
257
+ : `Disabled "${channel}" in config. It wasn't running, so nothing to stop.`,
258
+ });
259
+ }
260
+ /* ───────────────────────────── helpers ───────────────────────────── */
261
+ /**
262
+ * Env var that backs a channel's sealed token. `telegram` →
263
+ * `BRIGADE_TELEGRAM_TOKEN`. Uppercased + non-alnum→`_` so any channel id
264
+ * yields a legal env name (and matches the `${VAR}` SECRET_REF_PATTERN, which
265
+ * requires `[A-Z_][A-Z0-9_]*`).
266
+ */
267
+ function secretEnvVarName(channel) {
268
+ const slug = channel.toUpperCase().replace(/[^A-Z0-9]+/g, "_").replace(/^_+|_+$/g, "");
269
+ return `BRIGADE_${slug || "CHANNEL"}_TOKEN`;
270
+ }
271
+ /**
272
+ * Which config key under `channels.<id>` holds the token. Telegram's adapter
273
+ * reads `botToken`; default to that name for unknown token channels too (it's
274
+ * the established convention).
275
+ */
276
+ function tokenConfigKey(_channel) {
277
+ return "botToken";
278
+ }
279
+ /** All registered channel ids (bundled + user). Empty when no registry mounted. */
280
+ function listAvailableIds() {
281
+ const registry = getActiveRegistry();
282
+ if (!registry)
283
+ return [];
284
+ return registry.channels.map((a) => a.id);
285
+ }
286
+ /** Set of channel ids currently started in this gateway process. */
287
+ function connectedIdSet() {
288
+ const manager = getActiveChannelManager();
289
+ return new Set(manager ? manager.started : []);
290
+ }
291
+ /** Build a view for every registered channel (or just one when `only` is set). */
292
+ function buildChannelViews(only) {
293
+ const registry = getActiveRegistry();
294
+ if (!registry)
295
+ return [];
296
+ const cfg = loadConfig();
297
+ const connected = connectedIdSet();
298
+ const manager = getActiveChannelManager();
299
+ const out = [];
300
+ for (const adapter of registry.channels) {
301
+ if (only && adapter.id !== only)
302
+ continue;
303
+ const enabled = cfg.channels?.[adapter.id]?.enabled === true;
304
+ let configured = false;
305
+ try {
306
+ configured = adapter.isConfigured(cfg);
307
+ }
308
+ catch {
309
+ /* adapters shouldn't throw here, but be safe */
310
+ }
311
+ const isConnected = connected.has(adapter.id);
312
+ const view = {
313
+ channel: adapter.id,
314
+ label: adapter.label,
315
+ enabled,
316
+ configured,
317
+ connected: isConnected,
318
+ };
319
+ // Health only meaningful for a started adapter exposing health().
320
+ if (isConnected && manager) {
321
+ const live = manager.adapter(adapter.id);
322
+ if (live && typeof live.health === "function") {
323
+ const h = live.health();
324
+ view.health = {
325
+ ok: h.ok,
326
+ ...(!h.ok && h.reason ? { reason: h.reason } : {}),
327
+ ...(!h.ok && h.remediation ? { remediation: h.remediation } : {}),
328
+ };
329
+ }
330
+ }
331
+ out.push(view);
332
+ }
333
+ return out;
334
+ }
335
+ /** Single-channel view from a specific config snapshot (post-write). */
336
+ function viewFor(channel, cfg) {
337
+ const registry = getActiveRegistry();
338
+ const adapter = registry?.channels.find((a) => a.id === channel);
339
+ const enabled = cfg.channels?.[channel]?.enabled === true;
340
+ const connected = connectedIdSet().has(channel);
341
+ let configured = false;
342
+ if (adapter) {
343
+ try {
344
+ configured = adapter.isConfigured(cfg);
345
+ }
346
+ catch {
347
+ /* ignore */
348
+ }
349
+ }
350
+ const view = {
351
+ channel,
352
+ label: adapter?.label ?? channel,
353
+ enabled,
354
+ configured,
355
+ connected,
356
+ };
357
+ const manager = getActiveChannelManager();
358
+ if (connected && manager) {
359
+ const live = manager.adapter(channel);
360
+ if (live && typeof live.health === "function") {
361
+ const h = live.health();
362
+ view.health = {
363
+ ok: h.ok,
364
+ ...(!h.ok && h.reason ? { reason: h.reason } : {}),
365
+ ...(!h.ok && h.remediation ? { remediation: h.remediation } : {}),
366
+ };
367
+ }
368
+ }
369
+ return view;
370
+ }
371
+ function describeView(v) {
372
+ const state = v.connected
373
+ ? v.health && !v.health.ok
374
+ ? `connected but degraded (${v.health.reason ?? "unknown"})`
375
+ : "connected"
376
+ : v.enabled
377
+ ? "enabled but not connected"
378
+ : "not connected";
379
+ return `${v.label}: ${state}.`;
380
+ }
381
+ function summarizeViews(views) {
382
+ if (views.length === 0)
383
+ return "No channels are registered.";
384
+ const connected = views.filter((v) => v.connected).map((v) => v.label);
385
+ const available = views.filter((v) => !v.connected).map((v) => v.label);
386
+ const parts = [];
387
+ parts.push(connected.length > 0 ? `Connected: ${connected.join(", ")}.` : "No channels connected.");
388
+ if (available.length > 0)
389
+ parts.push(`Available to connect: ${available.join(", ")}.`);
390
+ return parts.join(" ");
391
+ }
392
+ function remediationFor(channel) {
393
+ if (channel === "whatsapp") {
394
+ return "WhatsApp links via QR, not a token — run `brigade channels link --channel whatsapp` (gateway stopped), then it connects on next start.";
395
+ }
396
+ return `Check the token/settings, then retry — or restart the gateway with \`brigade gateway\` to pick up the saved config.`;
397
+ }
398
+ //# sourceMappingURL=connect-channel-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect-channel-tool.js","sourceRoot":"","sources":["../../../src/agents/tools/connect-channel-tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * `message_action` — agent-callable edit / delete / react on a channel message.
3
+ *
4
+ * Companion to `send_message` (which creates messages) and `connect_channel`
5
+ * (which wires up channels). Where `send_message` sends NEW text, this tool acts
6
+ * on an EXISTING message the agent already sent or received: edit its text,
7
+ * delete it, react to it with an emoji, or pin/unpin it. It is the one central
8
+ * surface for every channel's message-action capability — a channel opts in by
9
+ * implementing `ChannelAdapter.handleAction` + advertising the matching
10
+ * `capabilities` flag; this tool dispatches through the active channel manager
11
+ * and PRE-CHECKS that flag so an unsupported action fails cleanly without ever
12
+ * touching the adapter.
13
+ *
14
+ * Ownership: BLANKET owner-only. Editing or deleting an arbitrary message is a
15
+ * privileged act — a channel-routed peer must NEVER reach into the operator's
16
+ * conversations and mutate or remove messages. Unlike `send_message` (which a
17
+ * peer may use to reply to their OWN chat), there is no safe peer subset here,
18
+ * so the whole tool is refused for non-owner turns via a per-call gate (kept as
19
+ * a per-call gate, not a registration-time `ownerOnly`, so the refusal carries
20
+ * a clear actionable message instead of the tool silently vanishing).
21
+ *
22
+ * Text safety: `edit` text is run through the central `sanitizeReplyForChannel`
23
+ * (the same reasoning-leak scrubber every outbound reply uses) before it reaches
24
+ * the adapter, so an edited message can't leak `<think>` content either.
25
+ */
26
+ import { Type } from "typebox";
27
+ import type { ChannelApprovalRoute } from "../channels/approval-router.js";
28
+ import type { BrigadeTool } from "./types.js";
29
+ declare const MessageActionParams: Type.TObject<{
30
+ channel: Type.TString;
31
+ to: Type.TString;
32
+ action: Type.TObject<{
33
+ kind: Type.TUnion<[Type.TLiteral<"edit">, Type.TLiteral<"delete">, Type.TLiteral<"react">, Type.TLiteral<"pin">, Type.TLiteral<"unpin">]>;
34
+ messageId: Type.TOptional<Type.TString>;
35
+ text: Type.TOptional<Type.TString>;
36
+ emoji: Type.TOptional<Type.TString>;
37
+ }>;
38
+ accountId: Type.TOptional<Type.TString>;
39
+ }>;
40
+ interface MessageActionDetails {
41
+ channel: string;
42
+ to: string;
43
+ kind: string;
44
+ ok: boolean;
45
+ messageId?: string;
46
+ error?: string;
47
+ }
48
+ export interface MakeMessageActionToolOptions {
49
+ /** Active channel context for this turn (unused for routing today; kept for parity + future auto-fill). */
50
+ channelContext?: ChannelApprovalRoute;
51
+ /**
52
+ * Whether the calling turn is the workspace owner. Defaults to `true` so
53
+ * legacy paths (TUI / tests) keep access. A non-owner turn is refused
54
+ * wholesale — there is no safe peer subset for message mutation.
55
+ */
56
+ senderIsOwner?: boolean;
57
+ /**
58
+ * The calling agent's id — used to resolve "my last message" when the
59
+ * action omits `messageId` (the pipeline records the agent's last sent id
60
+ * per conversation). When omitted, the last-sent fallback is unavailable
61
+ * and an action with no `messageId` is refused as before.
62
+ */
63
+ agentId?: string;
64
+ }
65
+ export declare function makeMessageActionTool(opts?: MakeMessageActionToolOptions): BrigadeTool<typeof MessageActionParams, MessageActionDetails>;
66
+ export {};
67
+ //# sourceMappingURL=message-action-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-action-tool.d.ts","sourceRoot":"","sources":["../../../src/agents/tools/message-action-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAK/B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAU3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAkB9C,QAAA,MAAM,mBAAmB;;;;;;;;;;EAqCvB,CAAC;AAEH,UAAU,oBAAoB;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,4BAA4B;IAC5C,2GAA2G;IAC3G,cAAc,CAAC,EAAE,oBAAoB,CAAC;IACtC;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAiCD,wBAAgB,qBAAqB,CACpC,IAAI,GAAE,4BAAiC,GACrC,WAAW,CAAC,OAAO,mBAAmB,EAAE,oBAAoB,CAAC,CA+I/D"}