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 +38 -62
- package/dist/channel.js.map +1 -1
- package/dist/channelLib.d.ts +42 -0
- package/dist/channelLib.d.ts.map +1 -0
- package/dist/channelLib.js +74 -0
- package/dist/channelLib.js.map +1 -0
- package/dist/channelLib.test.d.ts +2 -0
- package/dist/channelLib.test.d.ts.map +1 -0
- package/dist/channelLib.test.js +67 -0
- package/dist/channelLib.test.js.map +1 -0
- package/dist/channelSetup.d.ts +44 -0
- package/dist/channelSetup.d.ts.map +1 -0
- package/dist/channelSetup.js +61 -0
- package/dist/channelSetup.js.map +1 -0
- package/dist/channelSetup.test.d.ts +2 -0
- package/dist/channelSetup.test.d.ts.map +1 -0
- package/dist/channelSetup.test.js +75 -0
- package/dist/channelSetup.test.js.map +1 -0
- package/dist/client.d.ts +6 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +16 -0
- package/dist/client.js.map +1 -1
- package/dist/setup.js +77 -1
- package/dist/setup.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +28 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/tools.test.js +4 -2
- package/dist/tools/tools.test.js.map +1 -1
- package/dist/worker.js +4 -0
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
|
|
184
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|
package/dist/channel.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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;
|
|
1
|
+
{"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"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"}
|
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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;
|