@chanl/cli 2.0.4 → 3.0.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/__tests__/agents.test.js +574 -0
- package/dist/__tests__/agents.test.js.map +1 -0
- package/dist/__tests__/auth.test.d.ts +2 -0
- package/dist/__tests__/auth.test.js +87 -0
- package/dist/__tests__/auth.test.js.map +1 -0
- package/dist/__tests__/calls.test.d.ts +2 -0
- package/dist/__tests__/calls.test.js +115 -0
- package/dist/__tests__/calls.test.js.map +1 -0
- package/dist/__tests__/chat.test.d.ts +2 -0
- package/dist/__tests__/chat.test.js +357 -0
- package/dist/__tests__/chat.test.js.map +1 -0
- package/dist/__tests__/cli-base.test.d.ts +2 -0
- package/dist/__tests__/cli-base.test.js +87 -0
- package/dist/__tests__/cli-base.test.js.map +1 -0
- package/dist/__tests__/cli-missing.test.d.ts +2 -0
- package/dist/__tests__/cli-missing.test.js +546 -0
- package/dist/__tests__/cli-missing.test.js.map +1 -0
- package/dist/__tests__/helpers.d.ts +234 -0
- package/dist/__tests__/helpers.js +314 -0
- package/dist/__tests__/helpers.js.map +1 -0
- package/dist/__tests__/mcp.test.d.ts +2 -0
- package/dist/__tests__/mcp.test.js +470 -0
- package/dist/__tests__/mcp.test.js.map +1 -0
- package/dist/__tests__/prompts.test.d.ts +2 -0
- package/dist/__tests__/prompts.test.js +227 -0
- package/dist/__tests__/prompts.test.js.map +1 -0
- package/dist/__tests__/scenarios.test.d.ts +2 -0
- package/dist/__tests__/scenarios.test.js +270 -0
- package/dist/__tests__/scenarios.test.js.map +1 -0
- package/dist/__tests__/tools.test.d.ts +2 -0
- package/dist/__tests__/tools.test.js +331 -0
- package/dist/__tests__/tools.test.js.map +1 -0
- package/dist/__tests__/toolsets.test.d.ts +2 -0
- package/dist/__tests__/toolsets.test.js +196 -0
- package/dist/__tests__/toolsets.test.js.map +1 -0
- package/dist/__tests__/workspaces.test.d.ts +2 -0
- package/dist/__tests__/workspaces.test.js +155 -0
- package/dist/__tests__/workspaces.test.js.map +1 -0
- package/dist/commands/agents.js +96 -6
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/chat.js +2 -2
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/config.js +24 -2
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/memory.js +134 -1
- package/dist/commands/memory.js.map +1 -1
- package/dist/commands/prompts.js +148 -1
- package/dist/commands/prompts.js.map +1 -1
- package/dist/commands/scorecards.js +3 -3
- package/dist/commands/scorecards.js.map +1 -1
- package/dist/utils/config-store.d.ts +8 -0
- package/dist/utils/config-store.js +18 -1
- package/dist/utils/config-store.js.map +1 -1
- package/dist/utils/sdk-factory.js +15 -3
- package/dist/utils/sdk-factory.js.map +1 -1
- package/package.json +4 -4
- package/dist/__tests__/cli.test.js +0 -2308
- package/dist/__tests__/cli.test.js.map +0 -1
- /package/dist/__tests__/{cli.test.d.ts → agents.test.d.ts} +0 -0
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
2
|
+
import { configStore } from "../utils/config-store";
|
|
3
|
+
import {
|
|
4
|
+
runCli,
|
|
5
|
+
installFetchMock,
|
|
6
|
+
mockFetchResponse,
|
|
7
|
+
expectFetchCalled,
|
|
8
|
+
setupFetchConfigStore,
|
|
9
|
+
getFetchBody
|
|
10
|
+
} from "./helpers";
|
|
11
|
+
vi.mock("../utils/config-store", () => ({
|
|
12
|
+
configStore: {
|
|
13
|
+
getApiKey: vi.fn(),
|
|
14
|
+
getBaseUrl: vi.fn(),
|
|
15
|
+
getWorkspaceId: vi.fn(),
|
|
16
|
+
getJwtToken: vi.fn(),
|
|
17
|
+
getAuthMethod: vi.fn(() => null),
|
|
18
|
+
getAppUrl: vi.fn(() => "https://app.chanl.ai"),
|
|
19
|
+
getDeployment: vi.fn(),
|
|
20
|
+
getApiPrefix: vi.fn(),
|
|
21
|
+
setApiKey: vi.fn(),
|
|
22
|
+
setBaseUrl: vi.fn(),
|
|
23
|
+
setWorkspaceId: vi.fn(),
|
|
24
|
+
removeApiKey: vi.fn(),
|
|
25
|
+
clearAuth: vi.fn(),
|
|
26
|
+
delete: vi.fn(),
|
|
27
|
+
isAuthenticated: vi.fn(),
|
|
28
|
+
getPath: vi.fn(() => "/home/user/.chanl/config.json")
|
|
29
|
+
}
|
|
30
|
+
}));
|
|
31
|
+
describe("CLI", () => {
|
|
32
|
+
let mockFetch;
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
vi.clearAllMocks();
|
|
35
|
+
mockFetch = installFetchMock();
|
|
36
|
+
setupFetchConfigStore(configStore);
|
|
37
|
+
});
|
|
38
|
+
afterEach(() => {
|
|
39
|
+
process.exitCode = void 0;
|
|
40
|
+
});
|
|
41
|
+
describe("agents import", () => {
|
|
42
|
+
const mockImportedAgent = {
|
|
43
|
+
id: "agent_imported_123",
|
|
44
|
+
name: "My VAPI Agent",
|
|
45
|
+
description: "Imported from VAPI",
|
|
46
|
+
platform: "vapi",
|
|
47
|
+
platformAgentId: "asst_abc",
|
|
48
|
+
status: "active",
|
|
49
|
+
deployments: [
|
|
50
|
+
{
|
|
51
|
+
orchestrator: "vapi",
|
|
52
|
+
externalId: "asst_abc",
|
|
53
|
+
status: "synced"
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
createdAt: "2026-03-09T10:00:00.000Z",
|
|
57
|
+
updatedAt: "2026-03-09T10:00:00.000Z"
|
|
58
|
+
};
|
|
59
|
+
it("should import an agent from VAPI and display results", async () => {
|
|
60
|
+
mockFetchResponse(mockFetch, {
|
|
61
|
+
success: true,
|
|
62
|
+
data: mockImportedAgent,
|
|
63
|
+
message: "Success",
|
|
64
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
65
|
+
});
|
|
66
|
+
const { logs, exitCode } = await runCli([
|
|
67
|
+
"agents",
|
|
68
|
+
"import",
|
|
69
|
+
"--from",
|
|
70
|
+
"vapi",
|
|
71
|
+
"--agent-id",
|
|
72
|
+
"asst_abc"
|
|
73
|
+
]);
|
|
74
|
+
expect(exitCode).toBe(0);
|
|
75
|
+
const output = logs.join("\n");
|
|
76
|
+
expect(output).toContain("My VAPI Agent");
|
|
77
|
+
expect(output).toContain("agent_imported_123");
|
|
78
|
+
expect(output).toContain("vapi");
|
|
79
|
+
expectFetchCalled(mockFetch, {
|
|
80
|
+
method: "POST",
|
|
81
|
+
path: "/api/v1/agents/import"
|
|
82
|
+
});
|
|
83
|
+
const body = getFetchBody(mockFetch);
|
|
84
|
+
expect(body.platform).toBe("vapi");
|
|
85
|
+
expect(body.externalAgentId).toBe("asst_abc");
|
|
86
|
+
});
|
|
87
|
+
it("should display external ID and deployment info", async () => {
|
|
88
|
+
mockFetchResponse(mockFetch, {
|
|
89
|
+
success: true,
|
|
90
|
+
data: mockImportedAgent,
|
|
91
|
+
message: "Success",
|
|
92
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
93
|
+
});
|
|
94
|
+
const { logs, exitCode } = await runCli([
|
|
95
|
+
"agents",
|
|
96
|
+
"import",
|
|
97
|
+
"--from",
|
|
98
|
+
"vapi",
|
|
99
|
+
"--agent-id",
|
|
100
|
+
"asst_abc"
|
|
101
|
+
]);
|
|
102
|
+
expect(exitCode).toBe(0);
|
|
103
|
+
const output = logs.join("\n");
|
|
104
|
+
expect(output).toContain("asst_abc");
|
|
105
|
+
});
|
|
106
|
+
it("should output JSON with --json flag", async () => {
|
|
107
|
+
mockFetchResponse(mockFetch, {
|
|
108
|
+
success: true,
|
|
109
|
+
data: mockImportedAgent,
|
|
110
|
+
message: "Success",
|
|
111
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
112
|
+
});
|
|
113
|
+
const { logs, exitCode } = await runCli([
|
|
114
|
+
"--json",
|
|
115
|
+
"agents",
|
|
116
|
+
"import",
|
|
117
|
+
"--from",
|
|
118
|
+
"vapi",
|
|
119
|
+
"--agent-id",
|
|
120
|
+
"asst_abc"
|
|
121
|
+
]);
|
|
122
|
+
expect(exitCode).toBe(0);
|
|
123
|
+
const output = logs.join("\n");
|
|
124
|
+
const parsed = JSON.parse(output);
|
|
125
|
+
expect(parsed.id).toBe("agent_imported_123");
|
|
126
|
+
expect(parsed.name).toBe("My VAPI Agent");
|
|
127
|
+
expect(parsed.platform).toBe("vapi");
|
|
128
|
+
expect(parsed.platformAgentId).toBe("asst_abc");
|
|
129
|
+
expect(parsed.deployments).toHaveLength(1);
|
|
130
|
+
expect(parsed.deployments[0].orchestrator).toBe("vapi");
|
|
131
|
+
});
|
|
132
|
+
it("should import from Retell platform", async () => {
|
|
133
|
+
const retellAgent = {
|
|
134
|
+
...mockImportedAgent,
|
|
135
|
+
id: "agent_imported_456",
|
|
136
|
+
name: "My Retell Agent",
|
|
137
|
+
platform: "retell",
|
|
138
|
+
platformAgentId: "ret_xyz",
|
|
139
|
+
deployments: [
|
|
140
|
+
{ orchestrator: "retell", externalId: "ret_xyz", status: "synced" }
|
|
141
|
+
]
|
|
142
|
+
};
|
|
143
|
+
mockFetchResponse(mockFetch, {
|
|
144
|
+
success: true,
|
|
145
|
+
data: retellAgent,
|
|
146
|
+
message: "Success",
|
|
147
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
148
|
+
});
|
|
149
|
+
const { logs, exitCode } = await runCli([
|
|
150
|
+
"agents",
|
|
151
|
+
"import",
|
|
152
|
+
"--from",
|
|
153
|
+
"retell",
|
|
154
|
+
"--agent-id",
|
|
155
|
+
"ret_xyz"
|
|
156
|
+
]);
|
|
157
|
+
expect(exitCode).toBe(0);
|
|
158
|
+
const output = logs.join("\n");
|
|
159
|
+
expect(output).toContain("My Retell Agent");
|
|
160
|
+
expect(output).toContain("retell");
|
|
161
|
+
const body = getFetchBody(mockFetch);
|
|
162
|
+
expect(body.platform).toBe("retell");
|
|
163
|
+
expect(body.externalAgentId).toBe("ret_xyz");
|
|
164
|
+
});
|
|
165
|
+
it("should handle import failure with error message", async () => {
|
|
166
|
+
mockFetchResponse(
|
|
167
|
+
mockFetch,
|
|
168
|
+
{
|
|
169
|
+
success: false,
|
|
170
|
+
error: { message: "Agent 'asst_nonexistent' not found on platform 'vapi'" },
|
|
171
|
+
data: null,
|
|
172
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
173
|
+
},
|
|
174
|
+
404
|
|
175
|
+
);
|
|
176
|
+
const { errors, exitCode } = await runCli([
|
|
177
|
+
"agents",
|
|
178
|
+
"import",
|
|
179
|
+
"--from",
|
|
180
|
+
"vapi",
|
|
181
|
+
"--agent-id",
|
|
182
|
+
"asst_nonexistent"
|
|
183
|
+
]);
|
|
184
|
+
expect(exitCode).toBe(1);
|
|
185
|
+
const errorOutput = errors.join("\n");
|
|
186
|
+
expect(errorOutput).toContain("not found");
|
|
187
|
+
});
|
|
188
|
+
it("should accept optional --name flag for name override", async () => {
|
|
189
|
+
mockFetchResponse(mockFetch, {
|
|
190
|
+
success: true,
|
|
191
|
+
data: { ...mockImportedAgent, name: "Custom Agent Name" },
|
|
192
|
+
message: "Success",
|
|
193
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
194
|
+
});
|
|
195
|
+
const { logs, exitCode } = await runCli([
|
|
196
|
+
"agents",
|
|
197
|
+
"import",
|
|
198
|
+
"--from",
|
|
199
|
+
"vapi",
|
|
200
|
+
"--agent-id",
|
|
201
|
+
"asst_abc",
|
|
202
|
+
"--name",
|
|
203
|
+
"Custom Agent Name"
|
|
204
|
+
]);
|
|
205
|
+
expect(exitCode).toBe(0);
|
|
206
|
+
const output = logs.join("\n");
|
|
207
|
+
expect(output).toContain("Custom Agent Name");
|
|
208
|
+
const body = getFetchBody(mockFetch);
|
|
209
|
+
expect(body.platform).toBe("vapi");
|
|
210
|
+
expect(body.externalAgentId).toBe("asst_abc");
|
|
211
|
+
expect(body.name).toBe("Custom Agent Name");
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
describe("agents templates", () => {
|
|
215
|
+
const mockTemplatesList = {
|
|
216
|
+
templates: [
|
|
217
|
+
{
|
|
218
|
+
id: "lead-qualifier",
|
|
219
|
+
name: "Lead Qualifier",
|
|
220
|
+
description: "Lead-qualification agent",
|
|
221
|
+
version: 1
|
|
222
|
+
}
|
|
223
|
+
]
|
|
224
|
+
};
|
|
225
|
+
it("should list templates", async () => {
|
|
226
|
+
mockFetchResponse(mockFetch, {
|
|
227
|
+
success: true,
|
|
228
|
+
data: mockTemplatesList,
|
|
229
|
+
message: "Success",
|
|
230
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
231
|
+
});
|
|
232
|
+
const { logs, exitCode } = await runCli(["agents", "templates"]);
|
|
233
|
+
expect(exitCode).toBe(0);
|
|
234
|
+
const output = logs.join("\n");
|
|
235
|
+
expect(output).toContain("lead-qualifier");
|
|
236
|
+
expect(output).toContain("Lead Qualifier");
|
|
237
|
+
expectFetchCalled(mockFetch, {
|
|
238
|
+
method: "GET",
|
|
239
|
+
path: "/api/v1/agents/templates"
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
it("should output JSON with --json flag", async () => {
|
|
243
|
+
mockFetchResponse(mockFetch, {
|
|
244
|
+
success: true,
|
|
245
|
+
data: mockTemplatesList,
|
|
246
|
+
message: "Success",
|
|
247
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
248
|
+
});
|
|
249
|
+
const { logs, exitCode } = await runCli(["--json", "agents", "templates"]);
|
|
250
|
+
expect(exitCode).toBe(0);
|
|
251
|
+
const parsed = JSON.parse(logs.join("\n"));
|
|
252
|
+
expect(parsed.templates).toHaveLength(1);
|
|
253
|
+
expect(parsed.templates[0].id).toBe("lead-qualifier");
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
describe("agents create --from-template", () => {
|
|
257
|
+
const mockCreatedAgent = {
|
|
258
|
+
agent: {
|
|
259
|
+
id: "agent_tpl_1",
|
|
260
|
+
name: "Lead Generation Agent",
|
|
261
|
+
templateId: "lead-qualifier",
|
|
262
|
+
platform: "custom",
|
|
263
|
+
status: "active",
|
|
264
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
265
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
const mockAppliedAgent = {
|
|
269
|
+
id: "agent_tpl_1",
|
|
270
|
+
name: "Lead Generation Agent",
|
|
271
|
+
templateId: "lead-qualifier",
|
|
272
|
+
templateVersion: 1,
|
|
273
|
+
platform: "custom",
|
|
274
|
+
status: "active",
|
|
275
|
+
promptUpdated: true
|
|
276
|
+
};
|
|
277
|
+
it("should create then apply the template, and report the final agent", async () => {
|
|
278
|
+
mockFetchResponse(mockFetch, {
|
|
279
|
+
success: true,
|
|
280
|
+
data: mockCreatedAgent,
|
|
281
|
+
message: "Success",
|
|
282
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
283
|
+
});
|
|
284
|
+
mockFetchResponse(mockFetch, {
|
|
285
|
+
success: true,
|
|
286
|
+
data: mockAppliedAgent,
|
|
287
|
+
message: "Success",
|
|
288
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
289
|
+
});
|
|
290
|
+
const { logs, exitCode } = await runCli([
|
|
291
|
+
"agents",
|
|
292
|
+
"create",
|
|
293
|
+
"--from-template",
|
|
294
|
+
"lead-qualifier",
|
|
295
|
+
"--name",
|
|
296
|
+
"Lead Generation Agent"
|
|
297
|
+
]);
|
|
298
|
+
expect(exitCode).toBe(0);
|
|
299
|
+
const output = logs.join("\n");
|
|
300
|
+
expect(output).toContain("Lead Generation Agent");
|
|
301
|
+
expect(output).toContain("agent_tpl_1");
|
|
302
|
+
expectFetchCalled(mockFetch, { method: "POST", path: "/api/v1/agents" }, 0);
|
|
303
|
+
const createBody = getFetchBody(mockFetch, 0);
|
|
304
|
+
expect(createBody.templateId).toBe("lead-qualifier");
|
|
305
|
+
expect(createBody.platform).toBe("custom");
|
|
306
|
+
expect(createBody.name).toBe("Lead Generation Agent");
|
|
307
|
+
expectFetchCalled(
|
|
308
|
+
mockFetch,
|
|
309
|
+
{ method: "POST", path: "/api/v1/agents/agent_tpl_1/apply-template" },
|
|
310
|
+
1
|
|
311
|
+
);
|
|
312
|
+
});
|
|
313
|
+
it("should require --name", async () => {
|
|
314
|
+
const { errors, exitCode } = await runCli([
|
|
315
|
+
"agents",
|
|
316
|
+
"create",
|
|
317
|
+
"--from-template",
|
|
318
|
+
"lead-qualifier"
|
|
319
|
+
]);
|
|
320
|
+
expect(exitCode).toBe(1);
|
|
321
|
+
expect(errors.join("\n")).toContain("--name");
|
|
322
|
+
expect(mockFetch).not.toHaveBeenCalled();
|
|
323
|
+
});
|
|
324
|
+
it("should handle a failed create without calling apply-template", async () => {
|
|
325
|
+
mockFetchResponse(
|
|
326
|
+
mockFetch,
|
|
327
|
+
{
|
|
328
|
+
success: false,
|
|
329
|
+
error: { message: "name is required" },
|
|
330
|
+
data: null,
|
|
331
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
332
|
+
},
|
|
333
|
+
400
|
|
334
|
+
);
|
|
335
|
+
const { errors, exitCode } = await runCli([
|
|
336
|
+
"agents",
|
|
337
|
+
"create",
|
|
338
|
+
"--from-template",
|
|
339
|
+
"lead-qualifier",
|
|
340
|
+
"--name",
|
|
341
|
+
"X"
|
|
342
|
+
]);
|
|
343
|
+
expect(exitCode).toBe(1);
|
|
344
|
+
expect(errors.join("\n")).toContain("name is required");
|
|
345
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
describe("agents publish", () => {
|
|
349
|
+
const mockPublishResult = {
|
|
350
|
+
externalId: "ext_vapi_789",
|
|
351
|
+
platform: "vapi",
|
|
352
|
+
status: "active",
|
|
353
|
+
mcpUrl: "https://my-workspace.chanl.dev/mcp",
|
|
354
|
+
action: "created"
|
|
355
|
+
};
|
|
356
|
+
it("should publish an agent and display results", async () => {
|
|
357
|
+
mockFetchResponse(mockFetch, {
|
|
358
|
+
success: true,
|
|
359
|
+
data: mockPublishResult,
|
|
360
|
+
message: "Success",
|
|
361
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
362
|
+
});
|
|
363
|
+
const { logs, exitCode } = await runCli([
|
|
364
|
+
"agents",
|
|
365
|
+
"publish",
|
|
366
|
+
"agent_123",
|
|
367
|
+
"--to",
|
|
368
|
+
"vapi"
|
|
369
|
+
]);
|
|
370
|
+
expect(exitCode).toBe(0);
|
|
371
|
+
const output = logs.join("\n");
|
|
372
|
+
expect(output).toContain("created");
|
|
373
|
+
expect(output).toContain("vapi");
|
|
374
|
+
expect(output).toContain("ext_vapi_789");
|
|
375
|
+
expectFetchCalled(mockFetch, {
|
|
376
|
+
method: "POST",
|
|
377
|
+
path: "/api/v1/agents/agent_123/deploy"
|
|
378
|
+
});
|
|
379
|
+
const body = getFetchBody(mockFetch);
|
|
380
|
+
expect(body.platform).toBe("vapi");
|
|
381
|
+
});
|
|
382
|
+
it("should show MCP URL when included in result", async () => {
|
|
383
|
+
mockFetchResponse(mockFetch, {
|
|
384
|
+
success: true,
|
|
385
|
+
data: mockPublishResult,
|
|
386
|
+
message: "Success",
|
|
387
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
388
|
+
});
|
|
389
|
+
const { logs, exitCode } = await runCli([
|
|
390
|
+
"agents",
|
|
391
|
+
"publish",
|
|
392
|
+
"agent_123",
|
|
393
|
+
"--to",
|
|
394
|
+
"vapi",
|
|
395
|
+
"--with-mcp"
|
|
396
|
+
]);
|
|
397
|
+
expect(exitCode).toBe(0);
|
|
398
|
+
const output = logs.join("\n");
|
|
399
|
+
expect(output).toContain("https://my-workspace.chanl.dev/mcp");
|
|
400
|
+
const body = getFetchBody(mockFetch);
|
|
401
|
+
expect(body.platform).toBe("vapi");
|
|
402
|
+
expect(body.includeMcp).toBe(true);
|
|
403
|
+
});
|
|
404
|
+
it("should pass --target option as targetExternalId", async () => {
|
|
405
|
+
mockFetchResponse(mockFetch, {
|
|
406
|
+
success: true,
|
|
407
|
+
data: { ...mockPublishResult, action: "updated" },
|
|
408
|
+
message: "Success",
|
|
409
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
410
|
+
});
|
|
411
|
+
const { logs, exitCode } = await runCli([
|
|
412
|
+
"agents",
|
|
413
|
+
"publish",
|
|
414
|
+
"agent_123",
|
|
415
|
+
"--to",
|
|
416
|
+
"vapi",
|
|
417
|
+
"--target",
|
|
418
|
+
"existing_ext_456"
|
|
419
|
+
]);
|
|
420
|
+
expect(exitCode).toBe(0);
|
|
421
|
+
const output = logs.join("\n");
|
|
422
|
+
expect(output).toContain("updated");
|
|
423
|
+
const body = getFetchBody(mockFetch);
|
|
424
|
+
expect(body.platform).toBe("vapi");
|
|
425
|
+
expect(body.targetExternalId).toBe("existing_ext_456");
|
|
426
|
+
});
|
|
427
|
+
it("should output JSON with --json flag", async () => {
|
|
428
|
+
mockFetchResponse(mockFetch, {
|
|
429
|
+
success: true,
|
|
430
|
+
data: mockPublishResult,
|
|
431
|
+
message: "Success",
|
|
432
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
433
|
+
});
|
|
434
|
+
const { logs, exitCode } = await runCli([
|
|
435
|
+
"--json",
|
|
436
|
+
"agents",
|
|
437
|
+
"publish",
|
|
438
|
+
"agent_123",
|
|
439
|
+
"--to",
|
|
440
|
+
"vapi"
|
|
441
|
+
]);
|
|
442
|
+
expect(exitCode).toBe(0);
|
|
443
|
+
const output = logs.join("\n");
|
|
444
|
+
const parsed = JSON.parse(output);
|
|
445
|
+
expect(parsed.externalId).toBe("ext_vapi_789");
|
|
446
|
+
expect(parsed.platform).toBe("vapi");
|
|
447
|
+
expect(parsed.action).toBe("created");
|
|
448
|
+
expect(parsed.mcpUrl).toBe("https://my-workspace.chanl.dev/mcp");
|
|
449
|
+
});
|
|
450
|
+
it("should handle publish failure with error message", async () => {
|
|
451
|
+
mockFetchResponse(
|
|
452
|
+
mockFetch,
|
|
453
|
+
{
|
|
454
|
+
success: false,
|
|
455
|
+
error: { message: "Agent 'agent_123' not found" },
|
|
456
|
+
data: null,
|
|
457
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
458
|
+
},
|
|
459
|
+
404
|
|
460
|
+
);
|
|
461
|
+
const { errors, exitCode } = await runCli([
|
|
462
|
+
"agents",
|
|
463
|
+
"publish",
|
|
464
|
+
"agent_123",
|
|
465
|
+
"--to",
|
|
466
|
+
"vapi"
|
|
467
|
+
]);
|
|
468
|
+
expect(exitCode).toBe(1);
|
|
469
|
+
const errorOutput = errors.join("\n");
|
|
470
|
+
expect(errorOutput).toContain("not found");
|
|
471
|
+
});
|
|
472
|
+
});
|
|
473
|
+
describe("agents push-mcp", () => {
|
|
474
|
+
const mockPushMcpResult = {
|
|
475
|
+
mcpUrl: "https://my-workspace.chanl.dev/mcp",
|
|
476
|
+
platform: "vapi",
|
|
477
|
+
externalId: "ext_vapi_789",
|
|
478
|
+
status: "configured"
|
|
479
|
+
};
|
|
480
|
+
it("should push MCP URL and display results", async () => {
|
|
481
|
+
mockFetchResponse(mockFetch, {
|
|
482
|
+
success: true,
|
|
483
|
+
data: mockPushMcpResult,
|
|
484
|
+
message: "Success",
|
|
485
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
486
|
+
});
|
|
487
|
+
const { logs, exitCode } = await runCli([
|
|
488
|
+
"agents",
|
|
489
|
+
"push-mcp",
|
|
490
|
+
"agent_123",
|
|
491
|
+
"--to",
|
|
492
|
+
"vapi"
|
|
493
|
+
]);
|
|
494
|
+
expect(exitCode).toBe(0);
|
|
495
|
+
const output = logs.join("\n");
|
|
496
|
+
expect(output).toContain("https://my-workspace.chanl.dev/mcp");
|
|
497
|
+
expect(output).toContain("vapi");
|
|
498
|
+
expect(output).toContain("ext_vapi_789");
|
|
499
|
+
expectFetchCalled(mockFetch, {
|
|
500
|
+
method: "POST",
|
|
501
|
+
path: "/api/v1/agents/agent_123/push-mcp"
|
|
502
|
+
});
|
|
503
|
+
const body = getFetchBody(mockFetch);
|
|
504
|
+
expect(body.platform).toBe("vapi");
|
|
505
|
+
});
|
|
506
|
+
it("should pass --target option as targetExternalId", async () => {
|
|
507
|
+
mockFetchResponse(mockFetch, {
|
|
508
|
+
success: true,
|
|
509
|
+
data: mockPushMcpResult,
|
|
510
|
+
message: "Success",
|
|
511
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
512
|
+
});
|
|
513
|
+
const { exitCode } = await runCli([
|
|
514
|
+
"agents",
|
|
515
|
+
"push-mcp",
|
|
516
|
+
"agent_123",
|
|
517
|
+
"--to",
|
|
518
|
+
"vapi",
|
|
519
|
+
"--target",
|
|
520
|
+
"existing_ext_456"
|
|
521
|
+
]);
|
|
522
|
+
expect(exitCode).toBe(0);
|
|
523
|
+
const body = getFetchBody(mockFetch);
|
|
524
|
+
expect(body.platform).toBe("vapi");
|
|
525
|
+
expect(body.targetExternalId).toBe("existing_ext_456");
|
|
526
|
+
});
|
|
527
|
+
it("should output JSON with --json flag", async () => {
|
|
528
|
+
mockFetchResponse(mockFetch, {
|
|
529
|
+
success: true,
|
|
530
|
+
data: mockPushMcpResult,
|
|
531
|
+
message: "Success",
|
|
532
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
533
|
+
});
|
|
534
|
+
const { logs, exitCode } = await runCli([
|
|
535
|
+
"--json",
|
|
536
|
+
"agents",
|
|
537
|
+
"push-mcp",
|
|
538
|
+
"agent_123",
|
|
539
|
+
"--to",
|
|
540
|
+
"vapi"
|
|
541
|
+
]);
|
|
542
|
+
expect(exitCode).toBe(0);
|
|
543
|
+
const output = logs.join("\n");
|
|
544
|
+
const parsed = JSON.parse(output);
|
|
545
|
+
expect(parsed.mcpUrl).toBe("https://my-workspace.chanl.dev/mcp");
|
|
546
|
+
expect(parsed.platform).toBe("vapi");
|
|
547
|
+
expect(parsed.externalId).toBe("ext_vapi_789");
|
|
548
|
+
expect(parsed.status).toBe("configured");
|
|
549
|
+
});
|
|
550
|
+
it("should handle push-mcp failure with error message", async () => {
|
|
551
|
+
mockFetchResponse(
|
|
552
|
+
mockFetch,
|
|
553
|
+
{
|
|
554
|
+
success: false,
|
|
555
|
+
error: { message: "Agent 'agent_123' not found" },
|
|
556
|
+
data: null,
|
|
557
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
558
|
+
},
|
|
559
|
+
404
|
|
560
|
+
);
|
|
561
|
+
const { errors, exitCode } = await runCli([
|
|
562
|
+
"agents",
|
|
563
|
+
"push-mcp",
|
|
564
|
+
"agent_123",
|
|
565
|
+
"--to",
|
|
566
|
+
"vapi"
|
|
567
|
+
]);
|
|
568
|
+
expect(exitCode).toBe(1);
|
|
569
|
+
const errorOutput = errors.join("\n");
|
|
570
|
+
expect(errorOutput).toContain("not found");
|
|
571
|
+
});
|
|
572
|
+
});
|
|
573
|
+
});
|
|
574
|
+
//# sourceMappingURL=agents.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/__tests__/agents.test.ts"],"sourcesContent":["/**\n * CLI agents tests — fetch-level mocking\n *\n * Covers `chanl agents import`, `agents publish`, `agents push-mcp`.\n * Real SDK runs; tests assert on the HTTP request the SDK ended up\n * producing. This catches CLI → SDK contract drift (e.g., CLI passing\n * `externalAgentId` when the SDK/API expects `externalId`).\n */\n\nimport { describe, it, expect, beforeEach, afterEach, vi, type Mock } from 'vitest';\nimport { configStore } from '../utils/config-store';\nimport {\n runCli,\n installFetchMock,\n mockFetchResponse,\n expectFetchCalled,\n setupFetchConfigStore,\n getFetchBody,\n type FetchConfigStoreMock,\n} from './helpers';\n\n// Real SDK runs — DO NOT mock '@chanl/sdk'.\nvi.mock('../utils/config-store', () => ({\n configStore: {\n getApiKey: vi.fn(),\n getBaseUrl: vi.fn(),\n getWorkspaceId: vi.fn(),\n getJwtToken: vi.fn(),\n getAuthMethod: vi.fn(() => null),\n getAppUrl: vi.fn(() => 'https://app.chanl.ai'),\n getDeployment: vi.fn(),\n getApiPrefix: vi.fn(),\n setApiKey: vi.fn(),\n setBaseUrl: vi.fn(),\n setWorkspaceId: vi.fn(),\n removeApiKey: vi.fn(),\n clearAuth: vi.fn(),\n delete: vi.fn(),\n isAuthenticated: vi.fn(),\n getPath: vi.fn(() => '/home/user/.chanl/config.json'),\n },\n}));\n\ndescribe('CLI', () => {\n let mockFetch: Mock;\n\n beforeEach(() => {\n vi.clearAllMocks();\n mockFetch = installFetchMock();\n setupFetchConfigStore(configStore as unknown as FetchConfigStoreMock);\n });\n\n afterEach(() => {\n process.exitCode = undefined;\n });\n\n // ============================================\n // Story 4: Agent Import from Third-Party Platform\n // ============================================\n describe('agents import', () => {\n const mockImportedAgent = {\n id: 'agent_imported_123',\n name: 'My VAPI Agent',\n description: 'Imported from VAPI',\n platform: 'vapi',\n platformAgentId: 'asst_abc',\n status: 'active',\n deployments: [\n {\n orchestrator: 'vapi',\n externalId: 'asst_abc',\n status: 'synced',\n },\n ],\n createdAt: '2026-03-09T10:00:00.000Z',\n updatedAt: '2026-03-09T10:00:00.000Z',\n };\n\n it('should import an agent from VAPI and display results', async () => {\n mockFetchResponse(mockFetch, {\n success: true,\n data: mockImportedAgent,\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli([\n 'agents', 'import', '--from', 'vapi', '--agent-id', 'asst_abc',\n ]);\n\n expect(exitCode).toBe(0);\n const output = logs.join('\\n');\n\n expect(output).toContain('My VAPI Agent');\n expect(output).toContain('agent_imported_123');\n expect(output).toContain('vapi');\n\n // Contract: CLI POSTs to /api/v1/agents/import with the normalized\n // body shape the SDK expects. If CLI passes the wrong field name\n // (`platform`/`externalAgentId`), this fails.\n expectFetchCalled(mockFetch, {\n method: 'POST',\n path: '/api/v1/agents/import',\n });\n const body = getFetchBody(mockFetch) as {\n platform: string;\n externalAgentId: string;\n };\n expect(body.platform).toBe('vapi');\n expect(body.externalAgentId).toBe('asst_abc');\n });\n\n it('should display external ID and deployment info', async () => {\n mockFetchResponse(mockFetch, {\n success: true,\n data: mockImportedAgent,\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli([\n 'agents', 'import', '--from', 'vapi', '--agent-id', 'asst_abc',\n ]);\n\n expect(exitCode).toBe(0);\n const output = logs.join('\\n');\n expect(output).toContain('asst_abc');\n });\n\n it('should output JSON with --json flag', async () => {\n mockFetchResponse(mockFetch, {\n success: true,\n data: mockImportedAgent,\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli([\n '--json', 'agents', 'import', '--from', 'vapi', '--agent-id', 'asst_abc',\n ]);\n\n expect(exitCode).toBe(0);\n const output = logs.join('\\n');\n const parsed = JSON.parse(output);\n expect(parsed.id).toBe('agent_imported_123');\n expect(parsed.name).toBe('My VAPI Agent');\n expect(parsed.platform).toBe('vapi');\n expect(parsed.platformAgentId).toBe('asst_abc');\n expect(parsed.deployments).toHaveLength(1);\n expect(parsed.deployments[0].orchestrator).toBe('vapi');\n });\n\n it('should import from Retell platform', async () => {\n const retellAgent = {\n ...mockImportedAgent,\n id: 'agent_imported_456',\n name: 'My Retell Agent',\n platform: 'retell',\n platformAgentId: 'ret_xyz',\n deployments: [\n { orchestrator: 'retell', externalId: 'ret_xyz', status: 'synced' },\n ],\n };\n\n mockFetchResponse(mockFetch, {\n success: true,\n data: retellAgent,\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli([\n 'agents', 'import', '--from', 'retell', '--agent-id', 'ret_xyz',\n ]);\n\n expect(exitCode).toBe(0);\n const output = logs.join('\\n');\n expect(output).toContain('My Retell Agent');\n expect(output).toContain('retell');\n\n const body = getFetchBody(mockFetch) as {\n platform: string;\n externalAgentId: string;\n };\n expect(body.platform).toBe('retell');\n expect(body.externalAgentId).toBe('ret_xyz');\n });\n\n it('should handle import failure with error message', async () => {\n // The SDK throws on 4xx/5xx responses — CLI catches and exits 1.\n // Note: the legacy SDK-mocked test used `success: false` in a 200\n // body, but the real SDK only treats HTTP status >= 400 as an\n // error. This test now drives the actual production failure path.\n mockFetchResponse(\n mockFetch,\n {\n success: false,\n error: { message: \"Agent 'asst_nonexistent' not found on platform 'vapi'\" },\n data: null,\n timestamp: new Date().toISOString(),\n },\n 404,\n );\n\n const { errors, exitCode } = await runCli([\n 'agents', 'import', '--from', 'vapi', '--agent-id', 'asst_nonexistent',\n ]);\n\n expect(exitCode).toBe(1);\n const errorOutput = errors.join('\\n');\n expect(errorOutput).toContain('not found');\n });\n\n it('should accept optional --name flag for name override', async () => {\n mockFetchResponse(mockFetch, {\n success: true,\n data: { ...mockImportedAgent, name: 'Custom Agent Name' },\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli([\n 'agents', 'import', '--from', 'vapi', '--agent-id', 'asst_abc', '--name', 'Custom Agent Name',\n ]);\n\n expect(exitCode).toBe(0);\n const output = logs.join('\\n');\n expect(output).toContain('Custom Agent Name');\n\n const body = getFetchBody(mockFetch) as {\n platform: string;\n externalAgentId: string;\n name: string;\n };\n expect(body.platform).toBe('vapi');\n expect(body.externalAgentId).toBe('asst_abc');\n expect(body.name).toBe('Custom Agent Name');\n });\n });\n\n // ============================================\n // Agent registry templates (list + provision)\n // ============================================\n describe('agents templates', () => {\n const mockTemplatesList = {\n templates: [\n {\n id: 'lead-qualifier',\n name: 'Lead Qualifier',\n description: 'Lead-qualification agent',\n version: 1,\n },\n ],\n };\n\n it('should list templates', async () => {\n mockFetchResponse(mockFetch, {\n success: true,\n data: mockTemplatesList,\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli(['agents', 'templates']);\n\n expect(exitCode).toBe(0);\n const output = logs.join('\\n');\n expect(output).toContain('lead-qualifier');\n expect(output).toContain('Lead Qualifier');\n\n expectFetchCalled(mockFetch, {\n method: 'GET',\n path: '/api/v1/agents/templates',\n });\n });\n\n it('should output JSON with --json flag', async () => {\n mockFetchResponse(mockFetch, {\n success: true,\n data: mockTemplatesList,\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli(['--json', 'agents', 'templates']);\n\n expect(exitCode).toBe(0);\n const parsed = JSON.parse(logs.join('\\n'));\n expect(parsed.templates).toHaveLength(1);\n expect(parsed.templates[0].id).toBe('lead-qualifier');\n });\n });\n\n describe('agents create --from-template', () => {\n const mockCreatedAgent = {\n agent: {\n id: 'agent_tpl_1',\n name: 'Lead Generation Agent',\n templateId: 'lead-qualifier',\n platform: 'custom',\n status: 'active',\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n },\n };\n\n const mockAppliedAgent = {\n id: 'agent_tpl_1',\n name: 'Lead Generation Agent',\n templateId: 'lead-qualifier',\n templateVersion: 1,\n platform: 'custom',\n status: 'active',\n promptUpdated: true,\n };\n\n it('should create then apply the template, and report the final agent', async () => {\n mockFetchResponse(mockFetch, {\n success: true,\n data: mockCreatedAgent,\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n mockFetchResponse(mockFetch, {\n success: true,\n data: mockAppliedAgent,\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli([\n 'agents', 'create', '--from-template', 'lead-qualifier', '--name', 'Lead Generation Agent',\n ]);\n\n expect(exitCode).toBe(0);\n const output = logs.join('\\n');\n expect(output).toContain('Lead Generation Agent');\n expect(output).toContain('agent_tpl_1');\n\n // Contract: create carries templateId + platform:custom, then a\n // second call cascades the template onto the newly-created agent id.\n expectFetchCalled(mockFetch, { method: 'POST', path: '/api/v1/agents' }, 0);\n const createBody = getFetchBody(mockFetch, 0) as { templateId: string; platform: string; name: string };\n expect(createBody.templateId).toBe('lead-qualifier');\n expect(createBody.platform).toBe('custom');\n expect(createBody.name).toBe('Lead Generation Agent');\n\n expectFetchCalled(\n mockFetch,\n { method: 'POST', path: '/api/v1/agents/agent_tpl_1/apply-template' },\n 1,\n );\n });\n\n it('should require --name', async () => {\n const { errors, exitCode } = await runCli([\n 'agents', 'create', '--from-template', 'lead-qualifier',\n ]);\n\n expect(exitCode).toBe(1);\n expect(errors.join('\\n')).toContain('--name');\n expect(mockFetch).not.toHaveBeenCalled();\n });\n\n it('should handle a failed create without calling apply-template', async () => {\n mockFetchResponse(\n mockFetch,\n {\n success: false,\n error: { message: 'name is required' },\n data: null,\n timestamp: new Date().toISOString(),\n },\n 400,\n );\n\n const { errors, exitCode } = await runCli([\n 'agents', 'create', '--from-template', 'lead-qualifier', '--name', 'X',\n ]);\n\n expect(exitCode).toBe(1);\n expect(errors.join('\\n')).toContain('name is required');\n expect(mockFetch).toHaveBeenCalledTimes(1);\n });\n });\n\n // ============================================\n // Story 5: Publish Agent to Third-Party Platform\n // ============================================\n describe('agents publish', () => {\n const mockPublishResult = {\n externalId: 'ext_vapi_789',\n platform: 'vapi',\n status: 'active',\n mcpUrl: 'https://my-workspace.chanl.dev/mcp',\n action: 'created',\n };\n\n it('should publish an agent and display results', async () => {\n mockFetchResponse(mockFetch, {\n success: true,\n data: mockPublishResult,\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli([\n 'agents', 'publish', 'agent_123', '--to', 'vapi',\n ]);\n\n expect(exitCode).toBe(0);\n const output = logs.join('\\n');\n\n expect(output).toContain('created');\n expect(output).toContain('vapi');\n expect(output).toContain('ext_vapi_789');\n\n // Contract: publish hits /agents/:id/deploy (NOT /agents/:id/publish).\n // Lock the deploy naming.\n expectFetchCalled(mockFetch, {\n method: 'POST',\n path: '/api/v1/agents/agent_123/deploy',\n });\n const body = getFetchBody(mockFetch) as { platform: string };\n expect(body.platform).toBe('vapi');\n });\n\n it('should show MCP URL when included in result', async () => {\n mockFetchResponse(mockFetch, {\n success: true,\n data: mockPublishResult,\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli([\n 'agents', 'publish', 'agent_123', '--to', 'vapi', '--with-mcp',\n ]);\n\n expect(exitCode).toBe(0);\n const output = logs.join('\\n');\n expect(output).toContain('https://my-workspace.chanl.dev/mcp');\n\n const body = getFetchBody(mockFetch) as {\n platform: string;\n includeMcp: boolean;\n };\n expect(body.platform).toBe('vapi');\n expect(body.includeMcp).toBe(true);\n });\n\n it('should pass --target option as targetExternalId', async () => {\n mockFetchResponse(mockFetch, {\n success: true,\n data: { ...mockPublishResult, action: 'updated' },\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli([\n 'agents', 'publish', 'agent_123', '--to', 'vapi', '--target', 'existing_ext_456',\n ]);\n\n expect(exitCode).toBe(0);\n const output = logs.join('\\n');\n expect(output).toContain('updated');\n\n const body = getFetchBody(mockFetch) as {\n platform: string;\n targetExternalId: string;\n };\n expect(body.platform).toBe('vapi');\n expect(body.targetExternalId).toBe('existing_ext_456');\n });\n\n it('should output JSON with --json flag', async () => {\n mockFetchResponse(mockFetch, {\n success: true,\n data: mockPublishResult,\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli([\n '--json', 'agents', 'publish', 'agent_123', '--to', 'vapi',\n ]);\n\n expect(exitCode).toBe(0);\n const output = logs.join('\\n');\n const parsed = JSON.parse(output);\n expect(parsed.externalId).toBe('ext_vapi_789');\n expect(parsed.platform).toBe('vapi');\n expect(parsed.action).toBe('created');\n expect(parsed.mcpUrl).toBe('https://my-workspace.chanl.dev/mcp');\n });\n\n it('should handle publish failure with error message', async () => {\n mockFetchResponse(\n mockFetch,\n {\n success: false,\n error: { message: \"Agent 'agent_123' not found\" },\n data: null,\n timestamp: new Date().toISOString(),\n },\n 404,\n );\n\n const { errors, exitCode } = await runCli([\n 'agents', 'publish', 'agent_123', '--to', 'vapi',\n ]);\n\n expect(exitCode).toBe(1);\n const errorOutput = errors.join('\\n');\n expect(errorOutput).toContain('not found');\n });\n });\n\n // ============================================\n // Story 6: Push MCP URL to Third-Party Agent\n // ============================================\n describe('agents push-mcp', () => {\n const mockPushMcpResult = {\n mcpUrl: 'https://my-workspace.chanl.dev/mcp',\n platform: 'vapi',\n externalId: 'ext_vapi_789',\n status: 'configured',\n };\n\n it('should push MCP URL and display results', async () => {\n mockFetchResponse(mockFetch, {\n success: true,\n data: mockPushMcpResult,\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli([\n 'agents', 'push-mcp', 'agent_123', '--to', 'vapi',\n ]);\n\n expect(exitCode).toBe(0);\n const output = logs.join('\\n');\n\n expect(output).toContain('https://my-workspace.chanl.dev/mcp');\n expect(output).toContain('vapi');\n expect(output).toContain('ext_vapi_789');\n\n // Separate /push-mcp endpoint (not collapsed into /deploy).\n expectFetchCalled(mockFetch, {\n method: 'POST',\n path: '/api/v1/agents/agent_123/push-mcp',\n });\n const body = getFetchBody(mockFetch) as { platform: string };\n expect(body.platform).toBe('vapi');\n });\n\n it('should pass --target option as targetExternalId', async () => {\n mockFetchResponse(mockFetch, {\n success: true,\n data: mockPushMcpResult,\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { exitCode } = await runCli([\n 'agents', 'push-mcp', 'agent_123', '--to', 'vapi', '--target', 'existing_ext_456',\n ]);\n\n expect(exitCode).toBe(0);\n\n const body = getFetchBody(mockFetch) as {\n platform: string;\n targetExternalId: string;\n };\n expect(body.platform).toBe('vapi');\n expect(body.targetExternalId).toBe('existing_ext_456');\n });\n\n it('should output JSON with --json flag', async () => {\n mockFetchResponse(mockFetch, {\n success: true,\n data: mockPushMcpResult,\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli([\n '--json', 'agents', 'push-mcp', 'agent_123', '--to', 'vapi',\n ]);\n\n expect(exitCode).toBe(0);\n const output = logs.join('\\n');\n const parsed = JSON.parse(output);\n expect(parsed.mcpUrl).toBe('https://my-workspace.chanl.dev/mcp');\n expect(parsed.platform).toBe('vapi');\n expect(parsed.externalId).toBe('ext_vapi_789');\n expect(parsed.status).toBe('configured');\n });\n\n it('should handle push-mcp failure with error message', async () => {\n mockFetchResponse(\n mockFetch,\n {\n success: false,\n error: { message: \"Agent 'agent_123' not found\" },\n data: null,\n timestamp: new Date().toISOString(),\n },\n 404,\n );\n\n const { errors, exitCode } = await runCli([\n 'agents', 'push-mcp', 'agent_123', '--to', 'vapi',\n ]);\n\n expect(exitCode).toBe(1);\n const errorOutput = errors.join('\\n');\n expect(errorOutput).toContain('not found');\n });\n });\n});\n"],"mappings":"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","names":[]}
|