agenthub-multiagent-mcp 1.45.0 → 1.47.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.
package/dist/channel.js CHANGED
@@ -20,6 +20,7 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
20
20
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
21
21
  import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
22
22
  import WebSocket from "ws";
23
+ import { buildChannelNotification, buildReplyBody, channelEnabled } from "./channelLib.js";
23
24
  // =============================================================================
24
25
  // Config
25
26
  // =============================================================================
@@ -27,6 +28,11 @@ const API_URL = process.env.AGENTHUB_URL || "https://agenthub.contetial.com";
27
28
  const API_KEY = process.env.AGENTHUB_API_KEY || "";
28
29
  const AGENT_ID = process.env.AGENTHUB_AGENT_ID || "";
29
30
  const WS_URL = API_URL.replace(/^https:/, "wss:").replace(/^http:/, "ws:");
31
+ // Phase B kill switch (add-inbox-push-bridge §2.1): the plugin is OFF unless
32
+ // AGENTHUB_INBOX_CHANNEL_ENABLED is explicitly truthy. When off it still serves
33
+ // MCP (so `--channels server:agenthub-channel` doesn't error) but opens no
34
+ // WebSocket and emits no notifications.
35
+ const ENABLED = channelEnabled();
30
36
  // =============================================================================
31
37
  // MCP Server with channel capability
32
38
  // =============================================================================
@@ -88,30 +94,26 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
88
94
  return { content: [{ type: "text", text: "Error: message_id and body are required" }] };
89
95
  }
90
96
  try {
97
+ // Resolve the original sender so the reply is addressed correctly and the
98
+ // original message transitions to `responded` (the reply_to POST does that
99
+ // server-side — no separate status PATCH needed). Mirrors
100
+ // mcp__agenthub__reply. (add-inbox-push-bridge §2.2)
101
+ const origResp = await fetch(`${API_URL}/api/messages/${messageId}`, {
102
+ headers: { "X-API-Key": API_KEY },
103
+ });
104
+ if (!origResp.ok) {
105
+ return { content: [{ type: "text", text: `Reply failed: could not load original message (HTTP ${origResp.status})` }] };
106
+ }
107
+ const original = (await origResp.json());
91
108
  const resp = await fetch(`${API_URL}/api/messages`, {
92
109
  method: "POST",
93
110
  headers: { "Content-Type": "application/json", "X-API-Key": API_KEY },
94
- body: JSON.stringify({
95
- from_agent: AGENT_ID,
96
- to_agent: "", // Will be filled from reply_to context
97
- type: "response",
98
- subject: "Re: (via channel)",
99
- body: body.slice(0, 5000),
100
- reply_to: messageId,
101
- }),
111
+ body: JSON.stringify(buildReplyBody(original, AGENT_ID, body, messageId)),
102
112
  });
103
113
  if (resp.ok) {
104
- // Also mark as read
105
- await fetch(`${API_URL}/api/messages/${messageId}/status`, {
106
- method: "PATCH",
107
- headers: { "Content-Type": "application/json", "X-API-Key": API_KEY },
108
- body: JSON.stringify({ status: "read" }),
109
- });
110
- return { content: [{ type: "text", text: `Reply sent successfully.` }] };
111
- }
112
- else {
113
- return { content: [{ type: "text", text: `Reply failed: HTTP ${resp.status}` }] };
114
+ return { content: [{ type: "text", text: `Reply sent to ${original.from_agent}.` }] };
114
115
  }
116
+ return { content: [{ type: "text", text: `Reply failed: HTTP ${resp.status}` }] };
115
117
  }
116
118
  catch (err) {
117
119
  return { content: [{ type: "text", text: `Reply failed: ${err}` }] };
@@ -139,7 +141,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
139
141
  let ws = null;
140
142
  let reconnectAttempts = 0;
141
143
  function connectWebSocket() {
142
- if (!AGENT_ID || !API_KEY)
144
+ if (!ENABLED || !AGENT_ID || !API_KEY)
143
145
  return;
144
146
  const url = `${WS_URL}/ws/agents/${AGENT_ID}`;
145
147
  ws = new WebSocket(url, { headers: { "X-API-Key": API_KEY } });
@@ -153,47 +155,18 @@ function connectWebSocket() {
153
155
  ws?.send(JSON.stringify({ type: "pong", timestamp: new Date().toISOString() }));
154
156
  return;
155
157
  }
156
- if (msg.type === "message" && msg.message) {
157
- const m = msg.message;
158
- // Ignore messages from self
159
- if (m.from_agent === AGENT_ID) {
160
- ws?.send(JSON.stringify({ type: "ack", message_id: m.id, timestamp: new Date().toISOString() }));
161
- return;
162
- }
163
- // ACK the message
164
- ws?.send(JSON.stringify({ type: "ack", message_id: m.id, timestamp: new Date().toISOString() }));
165
- // Emit channel notification — this injects into the active session
166
- const priority = m.priority === "urgent" ? " [URGENT]" : m.priority === "high" ? " [HIGH]" : "";
167
- const content = `📨 Message from ${m.from_agent}${priority}\nSubject: ${m.subject}\n\n${m.body}\n\nMessage ID: ${m.id}\nUse agenthub_reply with this message_id to respond.`;
168
- await server.notification({
169
- method: "notifications/claude/channel",
170
- params: {
171
- content,
172
- meta: {
173
- source: "agenthub",
174
- from: m.from_agent,
175
- subject: m.subject,
176
- message_id: m.id,
177
- type: m.type,
178
- priority: m.priority,
179
- },
180
- },
181
- });
158
+ // ACK every inbound message event (incl. self) so the server can advance
159
+ // delivery state, even when we don't surface it as a channel turn.
160
+ if (msg.type === "message" && msg.message?.id) {
161
+ ws?.send(JSON.stringify({ type: "ack", message_id: msg.message.id, timestamp: new Date().toISOString() }));
182
162
  }
183
- if (msg.type === "task" && msg.task) {
184
- const t = msg.task;
163
+ // Decide what (if anything) to inject into the session. Returns null for
164
+ // self-messages and event types we don't push.
165
+ const note = buildChannelNotification(msg, AGENT_ID);
166
+ if (note) {
185
167
  await server.notification({
186
168
  method: "notifications/claude/channel",
187
- params: {
188
- content: `📋 New task assigned by ${t.assigned_by}\n\n${t.task}\n\nTask ID: ${t.id}\nPriority: ${t.priority}`,
189
- meta: {
190
- source: "agenthub",
191
- from: t.assigned_by,
192
- task_id: t.id,
193
- type: "task",
194
- priority: t.priority,
195
- },
196
- },
169
+ params: { content: note.content, meta: note.meta },
197
170
  });
198
171
  }
199
172
  }
@@ -210,10 +183,12 @@ function connectWebSocket() {
210
183
  });
211
184
  }
212
185
  function scheduleReconnect() {
186
+ // Never permanently give up (add-inbox-push-bridge §2.3): a dormant channel
187
+ // must self-heal when the server returns. Backoff is capped at 30s; the
188
+ // exponent is clamped so attempt counts can't overflow Math.pow. The Phase A
189
+ // SessionStart poll remains the delivery floor during any outage.
213
190
  reconnectAttempts++;
214
- if (reconnectAttempts > 10)
215
- return; // Give up after 10 attempts
216
- const delay = Math.min(1000 * Math.pow(2, reconnectAttempts - 1), 30000);
191
+ const delay = Math.min(1000 * Math.pow(2, Math.min(reconnectAttempts - 1, 5)), 30000);
217
192
  setTimeout(connectWebSocket, delay);
218
193
  }
219
194
  // =============================================================================
@@ -222,8 +197,9 @@ function scheduleReconnect() {
222
197
  async function main() {
223
198
  const transport = new StdioServerTransport();
224
199
  await server.connect(transport);
225
- // Connect WebSocket after MCP is ready
226
- if (AGENT_ID && API_KEY) {
200
+ // Connect WebSocket after MCP is ready — only when the channel is enabled and
201
+ // credentials are present. Disabled is a clean no-op (MCP serves, no socket).
202
+ if (ENABLED && AGENT_ID && API_KEY) {
227
203
  connectWebSocket();
228
204
  }
229
205
  }
@@ -1 +1 @@
1
- {"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,SAAS,MAAM,IAAI,CAAC;AAC3B,OAAO,EAAE,wBAAwB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAE3F,gFAAgF;AAChF,SAAS;AACT,gFAAgF;AAEhF,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,gCAAgC,CAAC;AAC7E,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE,CAAC;AACnD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC;AACrD,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;AAE3E,6EAA6E;AAC7E,gFAAgF;AAChF,2EAA2E;AAC3E,wCAAwC;AACxC,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;AAEjC,gFAAgF;AAChF,qCAAqC;AACrC,gFAAgF;AAEhF,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,OAAO,EAAE,EAC9C;IACE,YAAY,EAAE;QACZ,YAAY,EAAE,EAAE,gBAAgB,EAAE,EAAE,EAAE;QACtC,KAAK,EAAE,EAAE;KACV;IACD,YAAY,EAAE,2CAA2C,QAAQ;;;uDAGd;CACpD,CACF,CAAC;AAEF,gFAAgF;AAChF,2BAA2B;AAC3B,gFAAgF;AAEhF,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;IAC5D,KAAK,EAAE;QACL;YACE,IAAI,EAAE,gBAAgB;YACtB,WAAW,EAAE,oEAAoE;YACjF,WAAW,EAAE;gBACX,IAAI,EAAE,QAAiB;gBACvB,UAAU,EAAE;oBACV,UAAU,EAAE;wBACV,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,qDAAqD;qBACnE;oBACD,IAAI,EAAE;wBACJ,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,iBAAiB;qBAC/B;iBACF;gBACD,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,CAAC;aACjC;SACF;QACD;YACE,IAAI,EAAE,oBAAoB;YAC1B,WAAW,EAAE,mDAAmD;YAChE,WAAW,EAAE;gBACX,IAAI,EAAE,QAAiB;gBACvB,UAAU,EAAE;oBACV,UAAU,EAAE;wBACV,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,gCAAgC;qBAC9C;iBACF;gBACD,QAAQ,EAAE,CAAC,YAAY,CAAC;aACzB;SACF;KACF;CACF,CAAC,CAAC,CAAC;AAEJ,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;IAChE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAEjD,IAAI,IAAI,KAAK,gBAAgB,EAAE,CAAC;QAC9B,MAAM,SAAS,GAAG,IAAI,EAAE,UAAoB,CAAC;QAC7C,MAAM,IAAI,GAAG,IAAI,EAAE,IAAc,CAAC;QAElC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,EAAE,CAAC;YACxB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,yCAAyC,EAAE,CAAC,EAAE,CAAC;QACnG,CAAC;QAED,IAAI,CAAC;YACH,0EAA0E;YAC1E,2EAA2E;YAC3E,0DAA0D;YAC1D,qDAAqD;YACrD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,iBAAiB,SAAS,EAAE,EAAE;gBACnE,OAAO,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE;aAClC,CAAC,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,uDAAuD,QAAQ,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC;YACnI,CAAC;YACD,MAAM,QAAQ,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA4C,CAAC;YAEpF,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,eAAe,EAAE;gBAClD,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,WAAW,EAAE,OAAO,EAAE;gBACrE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;aAC1E,CAAC,CAAC;YAEH,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;gBACZ,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,iBAAiB,QAAQ,CAAC,UAAU,GAAG,EAAE,CAAC,EAAE,CAAC;YACjG,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,sBAAsB,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;QAC7F,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,iBAAiB,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC;QAChF,CAAC;IACH,CAAC;IAED,IAAI,IAAI,KAAK,oBAAoB,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,IAAI,EAAE,UAAoB,CAAC;QAC7C,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,GAAG,OAAO,iBAAiB,SAAS,SAAS,EAAE;gBACzD,MAAM,EAAE,OAAO;gBACf,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,WAAW,EAAE,OAAO,EAAE;gBACrE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;aACzC,CAAC,CAAC;YACH,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,EAAE,CAAC;QAC3E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,WAAW,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC;QAC1E,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,iBAAiB,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;AACjF,CAAC,CAAC,CAAC;AAEH,gFAAgF;AAChF,gEAAgE;AAChE,gFAAgF;AAEhF,IAAI,EAAE,GAAqB,IAAI,CAAC;AAChC,IAAI,iBAAiB,GAAG,CAAC,CAAC;AAE1B,SAAS,gBAAgB;IACvB,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ,IAAI,CAAC,OAAO;QAAE,OAAO;IAE9C,MAAM,GAAG,GAAG,GAAG,MAAM,cAAc,QAAQ,EAAE,CAAC;IAC9C,EAAE,GAAG,IAAI,SAAS,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IAE/D,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;QACjB,iBAAiB,GAAG,CAAC,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,IAAoB,EAAE,EAAE;QAC9C,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;YAExC,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACxB,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC;gBAChF,OAAO;YACT,CAAC;YAED,yEAAyE;YACzE,mEAAmE;YACnE,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC,OAAO,EAAE,EAAE,EAAE,CAAC;gBAC9C,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC;YAC7G,CAAC;YAED,yEAAyE;YACzE,+CAA+C;YAC/C,MAAM,IAAI,GAAG,wBAAwB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YACrD,IAAI,IAAI,EAAE,CAAC;gBACT,MAAM,MAAM,CAAC,YAAY,CAAC;oBACxB,MAAM,EAAE,8BAA8B;oBACtC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;iBACnD,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,wBAAwB;QAC1B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QAClB,EAAE,GAAG,IAAI,CAAC;QACV,iBAAiB,EAAE,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QAClB,2BAA2B;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,iBAAiB;IACxB,4EAA4E;IAC5E,wEAAwE;IACxE,6EAA6E;IAC7E,kEAAkE;IAClE,iBAAiB,EAAE,CAAC;IACpB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,iBAAiB,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACtF,UAAU,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;AACtC,CAAC;AAED,gFAAgF;AAChF,QAAQ;AACR,gFAAgF;AAEhF,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,8EAA8E;IAC9E,8EAA8E;IAC9E,IAAI,OAAO,IAAI,QAAQ,IAAI,OAAO,EAAE,CAAC;QACnC,gBAAgB,EAAE,CAAC;IACrB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Pure helpers for the AgentHub channel plugin (add-inbox-push-bridge).
3
+ *
4
+ * Extracted from channel.ts so the WS→notification mapping, kill switch, and
5
+ * reply-body construction are unit-testable without opening a socket or running
6
+ * the MCP server. channel.ts wires these into the live plugin.
7
+ */
8
+ export interface ChannelNotification {
9
+ content: string;
10
+ meta: Record<string, unknown>;
11
+ }
12
+ /**
13
+ * Phase B kill switch (§2.1). The plugin is OFF unless
14
+ * AGENTHUB_INBOX_CHANNEL_ENABLED is explicitly truthy. Independent of
15
+ * AGENTHUB_AUTO_INBOX (the Phase A SessionStart poll), which stays the floor.
16
+ */
17
+ export declare function channelEnabled(env?: NodeJS.ProcessEnv): boolean;
18
+ /**
19
+ * Map a raw AgentHub WS event to a channel notification, or null when nothing
20
+ * should be surfaced (self-message, or an event type we don't push). The caller
21
+ * still ACKs message events even when this returns null (self-filter case).
22
+ */
23
+ export declare function buildChannelNotification(msg: unknown, agentId: string): ChannelNotification | null;
24
+ /**
25
+ * Build the reply POST body (§2.2). Mirrors mcp__agenthub__reply semantics: the
26
+ * recipient resolves to the ORIGINAL sender (never empty) and the reply carries
27
+ * reply_to, which is what transitions the original message to `responded`
28
+ * server-side. The old plugin posted to_agent:"" then PATCHed status to `read`,
29
+ * which left the original un-responded — fixed here.
30
+ */
31
+ export declare function buildReplyBody(original: {
32
+ from_agent: string;
33
+ subject: string;
34
+ }, agentId: string, body: string, messageId: string): {
35
+ from_agent: string;
36
+ to_agent: string;
37
+ type: "response";
38
+ subject: string;
39
+ body: string;
40
+ reply_to: string;
41
+ };
42
+ //# sourceMappingURL=channelLib.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channelLib.d.ts","sourceRoot":"","sources":["../src/channelLib.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAE5E;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE,MAAM,GACd,mBAAmB,GAAG,IAAI,CAuC5B;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EACjD,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB,CASA"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Pure helpers for the AgentHub channel plugin (add-inbox-push-bridge).
3
+ *
4
+ * Extracted from channel.ts so the WS→notification mapping, kill switch, and
5
+ * reply-body construction are unit-testable without opening a socket or running
6
+ * the MCP server. channel.ts wires these into the live plugin.
7
+ */
8
+ /**
9
+ * Phase B kill switch (§2.1). The plugin is OFF unless
10
+ * AGENTHUB_INBOX_CHANNEL_ENABLED is explicitly truthy. Independent of
11
+ * AGENTHUB_AUTO_INBOX (the Phase A SessionStart poll), which stays the floor.
12
+ */
13
+ export function channelEnabled(env = process.env) {
14
+ return /^(1|true|yes|on)$/i.test((env.AGENTHUB_INBOX_CHANNEL_ENABLED || "").trim());
15
+ }
16
+ /**
17
+ * Map a raw AgentHub WS event to a channel notification, or null when nothing
18
+ * should be surfaced (self-message, or an event type we don't push). The caller
19
+ * still ACKs message events even when this returns null (self-filter case).
20
+ */
21
+ export function buildChannelNotification(msg, agentId) {
22
+ if (!msg || typeof msg !== "object")
23
+ return null;
24
+ const m = msg;
25
+ if (m.type === "message" && m.message) {
26
+ const msgObj = m.message;
27
+ // Never echo a message the agent itself sent.
28
+ if (msgObj.from_agent === agentId)
29
+ return null;
30
+ const priority = msgObj.priority === "urgent" ? " [URGENT]" : msgObj.priority === "high" ? " [HIGH]" : "";
31
+ const content = `📨 Message from ${msgObj.from_agent}${priority}\n` +
32
+ `Subject: ${msgObj.subject}\n\n${msgObj.body}\n\n` +
33
+ `Message ID: ${msgObj.id}\n` +
34
+ `Use agenthub_reply with this message_id to respond.`;
35
+ return {
36
+ content,
37
+ meta: {
38
+ source: "agenthub",
39
+ from: msgObj.from_agent,
40
+ subject: msgObj.subject,
41
+ message_id: msgObj.id,
42
+ type: msgObj.type,
43
+ priority: msgObj.priority,
44
+ },
45
+ };
46
+ }
47
+ if (m.type === "task" && m.task) {
48
+ const t = m.task;
49
+ return {
50
+ content: `📋 New task assigned by ${t.assigned_by}\n\n${t.task}\n\n` +
51
+ `Task ID: ${t.id}\nPriority: ${t.priority}`,
52
+ meta: { source: "agenthub", from: t.assigned_by, task_id: t.id, type: "task", priority: t.priority },
53
+ };
54
+ }
55
+ return null;
56
+ }
57
+ /**
58
+ * Build the reply POST body (§2.2). Mirrors mcp__agenthub__reply semantics: the
59
+ * recipient resolves to the ORIGINAL sender (never empty) and the reply carries
60
+ * reply_to, which is what transitions the original message to `responded`
61
+ * server-side. The old plugin posted to_agent:"" then PATCHed status to `read`,
62
+ * which left the original un-responded — fixed here.
63
+ */
64
+ export function buildReplyBody(original, agentId, body, messageId) {
65
+ return {
66
+ from_agent: agentId,
67
+ to_agent: original.from_agent,
68
+ type: "response",
69
+ subject: `Re: ${original.subject}`,
70
+ body: body.slice(0, 5000),
71
+ reply_to: messageId,
72
+ };
73
+ }
74
+ //# sourceMappingURL=channelLib.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channelLib.js","sourceRoot":"","sources":["../src/channelLib.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,MAAyB,OAAO,CAAC,GAAG;IACjE,OAAO,oBAAoB,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,8BAA8B,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AACtF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CACtC,GAAY,EACZ,OAAe;IAEf,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACjD,MAAM,CAAC,GAAG,GAAmD,CAAC;IAE9D,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;QACtC,MAAM,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC;QACzB,8CAA8C;QAC9C,IAAI,MAAM,CAAC,UAAU,KAAK,OAAO;YAAE,OAAO,IAAI,CAAC;QAC/C,MAAM,QAAQ,GACZ,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3F,MAAM,OAAO,GACX,mBAAmB,MAAM,CAAC,UAAU,GAAG,QAAQ,IAAI;YACnD,YAAY,MAAM,CAAC,OAAO,OAAO,MAAM,CAAC,IAAI,MAAM;YAClD,eAAe,MAAM,CAAC,EAAE,IAAI;YAC5B,qDAAqD,CAAC;QACxD,OAAO;YACL,OAAO;YACP,IAAI,EAAE;gBACJ,MAAM,EAAE,UAAU;gBAClB,IAAI,EAAE,MAAM,CAAC,UAAU;gBACvB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,UAAU,EAAE,MAAM,CAAC,EAAE;gBACrB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;aAC1B;SACF,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QAChC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;QACjB,OAAO;YACL,OAAO,EACL,2BAA2B,CAAC,CAAC,WAAW,OAAO,CAAC,CAAC,IAAI,MAAM;gBAC3D,YAAY,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,QAAQ,EAAE;YAC7C,IAAI,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE;SACrG,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,QAAiD,EACjD,OAAe,EACf,IAAY,EACZ,SAAiB;IASjB,OAAO;QACL,UAAU,EAAE,OAAO;QACnB,QAAQ,EAAE,QAAQ,CAAC,UAAU;QAC7B,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,OAAO,QAAQ,CAAC,OAAO,EAAE;QAClC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC;QACzB,QAAQ,EAAE,SAAS;KACpB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=channelLib.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channelLib.test.d.ts","sourceRoot":"","sources":["../src/channelLib.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,67 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { buildChannelNotification, buildReplyBody, channelEnabled } from "./channelLib.js";
3
+ // add-inbox-push-bridge §4 — hardening tests for the channel plugin's pure logic.
4
+ describe("channelEnabled (kill switch §2.1)", () => {
5
+ it("is off when unset", () => {
6
+ expect(channelEnabled({})).toBe(false);
7
+ });
8
+ it("is off for falsey strings", () => {
9
+ for (const v of ["", "false", "0", "no", "off", " "]) {
10
+ expect(channelEnabled({ AGENTHUB_INBOX_CHANNEL_ENABLED: v })).toBe(false);
11
+ }
12
+ });
13
+ it("is on only for explicit truthy values (case-insensitive, trimmed)", () => {
14
+ for (const v of ["true", "TRUE", "1", "yes", "on", " true "]) {
15
+ expect(channelEnabled({ AGENTHUB_INBOX_CHANNEL_ENABLED: v })).toBe(true);
16
+ }
17
+ });
18
+ });
19
+ describe("buildChannelNotification (§4.1)", () => {
20
+ const agentId = "me";
21
+ it("maps an inbound message to a channel notification", () => {
22
+ const note = buildChannelNotification({
23
+ type: "message",
24
+ message: { id: "m1", from_agent: "alice", subject: "Hi", body: "ping", priority: "normal", type: "question" },
25
+ }, agentId);
26
+ expect(note).not.toBeNull();
27
+ expect(note.content).toContain("Message from alice");
28
+ expect(note.content).toContain("ping");
29
+ expect(note.content).toContain("m1");
30
+ expect(note.meta).toMatchObject({ source: "agenthub", from: "alice", message_id: "m1" });
31
+ });
32
+ it("surfaces priority for urgent/high", () => {
33
+ const urgent = buildChannelNotification({ type: "message", message: { id: "m2", from_agent: "alice", subject: "x", body: "y", priority: "urgent" } }, agentId);
34
+ expect(urgent.content).toContain("[URGENT]");
35
+ });
36
+ it("returns null for a self-message (no echo)", () => {
37
+ const note = buildChannelNotification({ type: "message", message: { id: "m3", from_agent: agentId, subject: "x", body: "y" } }, agentId);
38
+ expect(note).toBeNull();
39
+ });
40
+ it("maps a task event", () => {
41
+ const note = buildChannelNotification({ type: "task", task: { id: "t1", assigned_by: "boss", task: "do it", priority: "high" } }, agentId);
42
+ expect(note).not.toBeNull();
43
+ expect(note.content).toContain("New task assigned by boss");
44
+ expect(note.meta).toMatchObject({ task_id: "t1", type: "task" });
45
+ });
46
+ it("returns null for unknown / malformed events", () => {
47
+ expect(buildChannelNotification({ type: "pong" }, agentId)).toBeNull();
48
+ expect(buildChannelNotification({ type: "message" }, agentId)).toBeNull(); // no message body
49
+ expect(buildChannelNotification(null, agentId)).toBeNull();
50
+ expect(buildChannelNotification("nope", agentId)).toBeNull();
51
+ });
52
+ });
53
+ describe("buildReplyBody (reply correctness §2.2)", () => {
54
+ it("addresses the reply to the original sender and carries reply_to", () => {
55
+ const body = buildReplyBody({ from_agent: "alice", subject: "Hi" }, "me", "thanks", "m1");
56
+ expect(body.to_agent).toBe("alice"); // NOT "" — the old bug
57
+ expect(body.from_agent).toBe("me");
58
+ expect(body.type).toBe("response");
59
+ expect(body.subject).toBe("Re: Hi");
60
+ expect(body.reply_to).toBe("m1"); // reply_to is what marks the original `responded`
61
+ });
62
+ it("truncates the body to 5000 chars", () => {
63
+ const body = buildReplyBody({ from_agent: "a", subject: "s" }, "me", "x".repeat(6000), "m1");
64
+ expect(body.body.length).toBe(5000);
65
+ });
66
+ });
67
+ //# sourceMappingURL=channelLib.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channelLib.test.js","sourceRoot":"","sources":["../src/channelLib.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Interactive-session wiring for the AgentHub channel plugin
3
+ * (add-inbox-push-bridge §3). Builds the `agenthub-channel` MCP-server entry and
4
+ * merges it idempotently into a project's MCP config, so a normal `claude`
5
+ * session can opt in via `--channels server:agenthub-channel`.
6
+ *
7
+ * Pure + filesystem helpers are split so the merge logic is unit-testable.
8
+ */
9
+ export declare const CHANNEL_SERVER_NAME = "agenthub-channel";
10
+ export interface McpServerEntry {
11
+ type: "stdio";
12
+ command: string;
13
+ args: string[];
14
+ env: Record<string, string>;
15
+ }
16
+ export interface ChannelEntryOptions {
17
+ url: string;
18
+ apiKey: string;
19
+ agentId: string;
20
+ /** Defaults to true (explicit opt-in). false writes the entry but keeps the
21
+ * plugin a no-op via the §2.1 kill switch — safe to install while disabled. */
22
+ enabled?: boolean;
23
+ }
24
+ /**
25
+ * The MCP-server entry that makes `server:agenthub-channel` resolvable. Runs the
26
+ * published `agenthub-channel` bin via npx (same distribution as the main MCP),
27
+ * carrying the agent's existing AgentHub creds + the kill switch.
28
+ */
29
+ export declare function channelMcpServerEntry(opts: ChannelEntryOptions): McpServerEntry;
30
+ /**
31
+ * Idempotently set the channel server entry under `mcpServers`, preserving every
32
+ * other server. Re-running with the same opts produces the same config.
33
+ */
34
+ export declare function mergeChannelServer(config: Record<string, unknown>, entry: McpServerEntry, name?: string): Record<string, unknown>;
35
+ /**
36
+ * Read a JSON MCP-config file (or start from {} if absent/empty), merge the
37
+ * channel entry, and write it back with 2-space indent. Returns whether the file
38
+ * was newly created and whether the channel entry already matched (no-op).
39
+ */
40
+ export declare function applyChannelToConfigFile(filePath: string, opts: ChannelEntryOptions, name?: string): {
41
+ created: boolean;
42
+ unchanged: boolean;
43
+ };
44
+ //# sourceMappingURL=channelSetup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channelSetup.d.ts","sourceRoot":"","sources":["../src/channelSetup.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,eAAO,MAAM,mBAAmB,qBAAqB,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB;oFACgF;IAChF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,mBAAmB,GAAG,cAAc,CAc/E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,KAAK,EAAE,cAAc,EACrB,IAAI,GAAE,MAA4B,GACjC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAGzB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,mBAAmB,EACzB,IAAI,GAAE,MAA4B,GACjC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAgB1C"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Interactive-session wiring for the AgentHub channel plugin
3
+ * (add-inbox-push-bridge §3). Builds the `agenthub-channel` MCP-server entry and
4
+ * merges it idempotently into a project's MCP config, so a normal `claude`
5
+ * session can opt in via `--channels server:agenthub-channel`.
6
+ *
7
+ * Pure + filesystem helpers are split so the merge logic is unit-testable.
8
+ */
9
+ import * as fs from "fs";
10
+ export const CHANNEL_SERVER_NAME = "agenthub-channel";
11
+ /**
12
+ * The MCP-server entry that makes `server:agenthub-channel` resolvable. Runs the
13
+ * published `agenthub-channel` bin via npx (same distribution as the main MCP),
14
+ * carrying the agent's existing AgentHub creds + the kill switch.
15
+ */
16
+ export function channelMcpServerEntry(opts) {
17
+ return {
18
+ type: "stdio",
19
+ command: "npx",
20
+ args: ["-y", "-p", "agenthub-multiagent-mcp@latest", CHANNEL_SERVER_NAME],
21
+ env: {
22
+ AGENTHUB_URL: opts.url,
23
+ AGENTHUB_API_KEY: opts.apiKey,
24
+ AGENTHUB_AGENT_ID: opts.agentId,
25
+ // §3.2 — the opt-in is safe even when disabled: the plugin no-ops unless
26
+ // this is truthy (see channelEnabled / §2.1).
27
+ AGENTHUB_INBOX_CHANNEL_ENABLED: opts.enabled === false ? "false" : "true",
28
+ },
29
+ };
30
+ }
31
+ /**
32
+ * Idempotently set the channel server entry under `mcpServers`, preserving every
33
+ * other server. Re-running with the same opts produces the same config.
34
+ */
35
+ export function mergeChannelServer(config, entry, name = CHANNEL_SERVER_NAME) {
36
+ const existing = config.mcpServers || {};
37
+ return { ...config, mcpServers: { ...existing, [name]: entry } };
38
+ }
39
+ /**
40
+ * Read a JSON MCP-config file (or start from {} if absent/empty), merge the
41
+ * channel entry, and write it back with 2-space indent. Returns whether the file
42
+ * was newly created and whether the channel entry already matched (no-op).
43
+ */
44
+ export function applyChannelToConfigFile(filePath, opts, name = CHANNEL_SERVER_NAME) {
45
+ let config = {};
46
+ let created = true;
47
+ if (fs.existsSync(filePath)) {
48
+ created = false;
49
+ const raw = fs.readFileSync(filePath, "utf-8").trim();
50
+ if (raw) {
51
+ config = JSON.parse(raw);
52
+ }
53
+ }
54
+ const entry = channelMcpServerEntry(opts);
55
+ const before = JSON.stringify(config.mcpServers?.[name]);
56
+ const merged = mergeChannelServer(config, entry, name);
57
+ const after = JSON.stringify(merged.mcpServers[name]);
58
+ fs.writeFileSync(filePath, JSON.stringify(merged, null, 2));
59
+ return { created, unchanged: before === after };
60
+ }
61
+ //# sourceMappingURL=channelSetup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channelSetup.js","sourceRoot":"","sources":["../src/channelSetup.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB,MAAM,CAAC,MAAM,mBAAmB,GAAG,kBAAkB,CAAC;AAkBtD;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAyB;IAC7D,OAAO;QACL,IAAI,EAAE,OAAO;QACb,OAAO,EAAE,KAAK;QACd,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,gCAAgC,EAAE,mBAAmB,CAAC;QACzE,GAAG,EAAE;YACH,YAAY,EAAE,IAAI,CAAC,GAAG;YACtB,gBAAgB,EAAE,IAAI,CAAC,MAAM;YAC7B,iBAAiB,EAAE,IAAI,CAAC,OAAO;YAC/B,yEAAyE;YACzE,8CAA8C;YAC9C,8BAA8B,EAAE,IAAI,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM;SAC1E;KACF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAA+B,EAC/B,KAAqB,EACrB,OAAe,mBAAmB;IAElC,MAAM,QAAQ,GAAI,MAAM,CAAC,UAAkD,IAAI,EAAE,CAAC;IAClF,OAAO,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,EAAE,GAAG,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;AACnE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CACtC,QAAgB,EAChB,IAAyB,EACzB,OAAe,mBAAmB;IAElC,IAAI,MAAM,GAA4B,EAAE,CAAC;IACzC,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,OAAO,GAAG,KAAK,CAAC;QAChB,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QACtD,IAAI,GAAG,EAAE,CAAC;YACR,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA4B,CAAC;QACtD,CAAC;IACH,CAAC;IACD,MAAM,KAAK,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAE,MAAM,CAAC,UAAsC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IACtF,MAAM,MAAM,GAAG,kBAAkB,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IACvD,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAE,MAAM,CAAC,UAAsC,CAAC,IAAI,CAAC,CAAC,CAAC;IACnF,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5D,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,KAAK,EAAE,CAAC;AAClD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=channelSetup.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channelSetup.test.d.ts","sourceRoot":"","sources":["../src/channelSetup.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,75 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import * as fs from "fs";
3
+ import * as os from "os";
4
+ import * as path from "path";
5
+ import { channelMcpServerEntry, mergeChannelServer, applyChannelToConfigFile, CHANNEL_SERVER_NAME, } from "./channelSetup.js";
6
+ // add-inbox-push-bridge §3 — interactive-session wiring helpers.
7
+ const OPTS = { url: "https://h.example.com", apiKey: "k123", agentId: "agent-x" };
8
+ describe("channelMcpServerEntry", () => {
9
+ it("builds a stdio npx entry carrying creds + opt-in", () => {
10
+ const e = channelMcpServerEntry(OPTS);
11
+ expect(e.type).toBe("stdio");
12
+ expect(e.command).toBe("npx");
13
+ expect(e.args).toContain(CHANNEL_SERVER_NAME);
14
+ expect(e.env.AGENTHUB_URL).toBe("https://h.example.com");
15
+ expect(e.env.AGENTHUB_API_KEY).toBe("k123");
16
+ expect(e.env.AGENTHUB_AGENT_ID).toBe("agent-x");
17
+ expect(e.env.AGENTHUB_INBOX_CHANNEL_ENABLED).toBe("true");
18
+ });
19
+ it("respects the kill switch when installed disabled (§3.2)", () => {
20
+ const e = channelMcpServerEntry({ ...OPTS, enabled: false });
21
+ expect(e.env.AGENTHUB_INBOX_CHANNEL_ENABLED).toBe("false");
22
+ });
23
+ });
24
+ describe("mergeChannelServer", () => {
25
+ it("adds the channel server while preserving existing servers", () => {
26
+ const before = { mcpServers: { agenthub: { command: "npx" } }, other: 1 };
27
+ const merged = mergeChannelServer(before, channelMcpServerEntry(OPTS));
28
+ expect(merged.mcpServers.agenthub).toEqual({ command: "npx" }); // preserved
29
+ expect(merged.mcpServers[CHANNEL_SERVER_NAME]).toBeDefined();
30
+ expect(merged.other).toBe(1);
31
+ });
32
+ it("is idempotent — re-merging the same entry yields the same config", () => {
33
+ const entry = channelMcpServerEntry(OPTS);
34
+ const once = mergeChannelServer({}, entry);
35
+ const twice = mergeChannelServer(once, entry);
36
+ expect(JSON.stringify(twice)).toBe(JSON.stringify(once));
37
+ });
38
+ });
39
+ describe("applyChannelToConfigFile", () => {
40
+ let dir;
41
+ let file;
42
+ beforeEach(() => {
43
+ dir = fs.mkdtempSync(path.join(os.tmpdir(), "channel-setup-"));
44
+ file = path.join(dir, ".mcp.json");
45
+ });
46
+ afterEach(() => {
47
+ fs.rmSync(dir, { recursive: true, force: true });
48
+ });
49
+ it("creates a config file when none exists", () => {
50
+ const r = applyChannelToConfigFile(file, OPTS);
51
+ expect(r.created).toBe(true);
52
+ const written = JSON.parse(fs.readFileSync(file, "utf-8"));
53
+ expect(written.mcpServers[CHANNEL_SERVER_NAME].env.AGENTHUB_AGENT_ID).toBe("agent-x");
54
+ });
55
+ it("merges into an existing config without clobbering other servers", () => {
56
+ fs.writeFileSync(file, JSON.stringify({ mcpServers: { agenthub: { command: "npx", args: [] } } }));
57
+ const r = applyChannelToConfigFile(file, OPTS);
58
+ expect(r.created).toBe(false);
59
+ const written = JSON.parse(fs.readFileSync(file, "utf-8"));
60
+ expect(written.mcpServers.agenthub).toBeDefined(); // preserved
61
+ expect(written.mcpServers[CHANNEL_SERVER_NAME]).toBeDefined();
62
+ });
63
+ it("is idempotent — second apply reports unchanged", () => {
64
+ applyChannelToConfigFile(file, OPTS);
65
+ const second = applyChannelToConfigFile(file, OPTS);
66
+ expect(second.unchanged).toBe(true);
67
+ });
68
+ it("tolerates an empty file", () => {
69
+ fs.writeFileSync(file, "");
70
+ const r = applyChannelToConfigFile(file, OPTS);
71
+ expect(r.created).toBe(false);
72
+ expect(JSON.parse(fs.readFileSync(file, "utf-8")).mcpServers[CHANNEL_SERVER_NAME]).toBeDefined();
73
+ });
74
+ });
75
+ //# sourceMappingURL=channelSetup.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channelSetup.test.js","sourceRoot":"","sources":["../src/channelSetup.test.ts"],"names":[],"mappings":"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"}
package/dist/client.d.ts CHANGED
@@ -200,6 +200,12 @@ export declare class ApiClient {
200
200
  */
201
201
  employeeSlackDM(toUser: string, text: string): Promise<unknown>;
202
202
  deliverFile(messageId: string, filePath: string, comment?: string): Promise<unknown>;
203
+ /**
204
+ * Upload a local file to an arbitrary Slack channel or DM (add-slack-file-upload).
205
+ * target is a channel id (C…/G…), a #channel-name, or a user id (U…/W…, DM).
206
+ * Reads the file locally and base64-encodes it — same contract as deliverFile.
207
+ */
208
+ uploadSlackFile(target: string, filePath: string, comment?: string): Promise<unknown>;
203
209
  registerAgent(id: string, name?: string, owner?: string, workingDir?: string, model?: string, projectKey?: string): Promise<{
204
210
  agent_id: string;
205
211
  name: string;