@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.
Files changed (59) hide show
  1. package/dist/__tests__/agents.test.js +574 -0
  2. package/dist/__tests__/agents.test.js.map +1 -0
  3. package/dist/__tests__/auth.test.d.ts +2 -0
  4. package/dist/__tests__/auth.test.js +87 -0
  5. package/dist/__tests__/auth.test.js.map +1 -0
  6. package/dist/__tests__/calls.test.d.ts +2 -0
  7. package/dist/__tests__/calls.test.js +115 -0
  8. package/dist/__tests__/calls.test.js.map +1 -0
  9. package/dist/__tests__/chat.test.d.ts +2 -0
  10. package/dist/__tests__/chat.test.js +357 -0
  11. package/dist/__tests__/chat.test.js.map +1 -0
  12. package/dist/__tests__/cli-base.test.d.ts +2 -0
  13. package/dist/__tests__/cli-base.test.js +87 -0
  14. package/dist/__tests__/cli-base.test.js.map +1 -0
  15. package/dist/__tests__/cli-missing.test.d.ts +2 -0
  16. package/dist/__tests__/cli-missing.test.js +546 -0
  17. package/dist/__tests__/cli-missing.test.js.map +1 -0
  18. package/dist/__tests__/helpers.d.ts +234 -0
  19. package/dist/__tests__/helpers.js +314 -0
  20. package/dist/__tests__/helpers.js.map +1 -0
  21. package/dist/__tests__/mcp.test.d.ts +2 -0
  22. package/dist/__tests__/mcp.test.js +470 -0
  23. package/dist/__tests__/mcp.test.js.map +1 -0
  24. package/dist/__tests__/prompts.test.d.ts +2 -0
  25. package/dist/__tests__/prompts.test.js +227 -0
  26. package/dist/__tests__/prompts.test.js.map +1 -0
  27. package/dist/__tests__/scenarios.test.d.ts +2 -0
  28. package/dist/__tests__/scenarios.test.js +270 -0
  29. package/dist/__tests__/scenarios.test.js.map +1 -0
  30. package/dist/__tests__/tools.test.d.ts +2 -0
  31. package/dist/__tests__/tools.test.js +331 -0
  32. package/dist/__tests__/tools.test.js.map +1 -0
  33. package/dist/__tests__/toolsets.test.d.ts +2 -0
  34. package/dist/__tests__/toolsets.test.js +196 -0
  35. package/dist/__tests__/toolsets.test.js.map +1 -0
  36. package/dist/__tests__/workspaces.test.d.ts +2 -0
  37. package/dist/__tests__/workspaces.test.js +155 -0
  38. package/dist/__tests__/workspaces.test.js.map +1 -0
  39. package/dist/commands/agents.js +96 -6
  40. package/dist/commands/agents.js.map +1 -1
  41. package/dist/commands/chat.js +2 -2
  42. package/dist/commands/chat.js.map +1 -1
  43. package/dist/commands/config.js +24 -2
  44. package/dist/commands/config.js.map +1 -1
  45. package/dist/commands/memory.js +134 -1
  46. package/dist/commands/memory.js.map +1 -1
  47. package/dist/commands/prompts.js +148 -1
  48. package/dist/commands/prompts.js.map +1 -1
  49. package/dist/commands/scorecards.js +3 -3
  50. package/dist/commands/scorecards.js.map +1 -1
  51. package/dist/utils/config-store.d.ts +8 -0
  52. package/dist/utils/config-store.js +18 -1
  53. package/dist/utils/config-store.js.map +1 -1
  54. package/dist/utils/sdk-factory.js +15 -3
  55. package/dist/utils/sdk-factory.js.map +1 -1
  56. package/package.json +4 -4
  57. package/dist/__tests__/cli.test.js +0 -2308
  58. package/dist/__tests__/cli.test.js.map +0 -1
  59. /package/dist/__tests__/{cli.test.d.ts → agents.test.d.ts} +0 -0
@@ -0,0 +1,227 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
2
+ import { configStore } from "../utils/config-store";
3
+ import { ChanlSDK } from "@chanl/sdk";
4
+ import {
5
+ runCli,
6
+ makeMockSdk,
7
+ setupAuthenticatedConfigStore
8
+ } from "./helpers";
9
+ vi.mock("@chanl/sdk", () => ({
10
+ ChanlSDK: vi.fn()
11
+ }));
12
+ vi.mock("../utils/config-store", () => ({
13
+ configStore: {
14
+ getApiKey: vi.fn(),
15
+ getBaseUrl: vi.fn(() => "https://api.chanl.ai"),
16
+ getWorkspaceId: vi.fn(() => "ws_123"),
17
+ getJwtToken: vi.fn(() => null),
18
+ getAuthMethod: vi.fn(() => null),
19
+ getAppUrl: vi.fn(() => "https://app.chanl.ai"),
20
+ getDeployment: vi.fn(() => "cloud"),
21
+ getApiPrefix: vi.fn(() => "/api/v1"),
22
+ setApiKey: vi.fn(),
23
+ setBaseUrl: vi.fn(),
24
+ setWorkspaceId: vi.fn(),
25
+ removeApiKey: vi.fn(),
26
+ clearAuth: vi.fn(),
27
+ delete: vi.fn(),
28
+ isAuthenticated: vi.fn(),
29
+ getPath: vi.fn(() => "/home/user/.chanl/config.json")
30
+ }
31
+ }));
32
+ describe("CLI", () => {
33
+ let mockSdk;
34
+ beforeEach(() => {
35
+ vi.clearAllMocks();
36
+ mockSdk = makeMockSdk();
37
+ ChanlSDK.mockImplementation(() => mockSdk);
38
+ setupAuthenticatedConfigStore(configStore);
39
+ });
40
+ afterEach(() => {
41
+ process.exitCode = void 0;
42
+ });
43
+ describe("prompts list", () => {
44
+ it("should list prompts with table output", async () => {
45
+ mockSdk.prompts.list.mockResolvedValue({
46
+ success: true,
47
+ data: [
48
+ {
49
+ id: "prompt_abc123",
50
+ name: "Support Greeting",
51
+ category: "support",
52
+ status: "active",
53
+ version: 3,
54
+ createdAt: "2025-01-01T00:00:00Z",
55
+ updatedAt: "2025-01-15T10:30:00Z"
56
+ },
57
+ {
58
+ id: "prompt_def456",
59
+ name: "Sales Pitch",
60
+ category: "sales",
61
+ status: "draft",
62
+ version: 1,
63
+ createdAt: "2025-02-01T00:00:00Z",
64
+ updatedAt: "2025-02-05T10:30:00Z"
65
+ }
66
+ ],
67
+ message: "Success",
68
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
69
+ });
70
+ const { logs, exitCode } = await runCli(["prompts", "list"]);
71
+ expect(exitCode).toBe(0);
72
+ expect(mockSdk.prompts.list).toHaveBeenCalled();
73
+ const output = logs.join("\n");
74
+ expect(output).toContain("Support Greeting");
75
+ expect(output).toContain("Sales Pitch");
76
+ });
77
+ it("should list prompts with JSON output", async () => {
78
+ const mockPrompts = [
79
+ {
80
+ id: "prompt_abc123",
81
+ name: "Support Greeting",
82
+ category: "support",
83
+ status: "active"
84
+ }
85
+ ];
86
+ mockSdk.prompts.list.mockResolvedValue({
87
+ success: true,
88
+ data: mockPrompts,
89
+ message: "Success",
90
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
91
+ });
92
+ const { logs, exitCode } = await runCli(["--json", "prompts", "list"]);
93
+ expect(exitCode).toBe(0);
94
+ const output = logs.join("\n");
95
+ const parsed = JSON.parse(output);
96
+ expect(parsed).toHaveLength(1);
97
+ expect(parsed[0].name).toBe("Support Greeting");
98
+ });
99
+ it("should unwrap API list shape { prompts: [...] } for JSON output", async () => {
100
+ mockSdk.prompts.list.mockResolvedValue({
101
+ success: true,
102
+ data: {
103
+ prompts: [{ id: "prompt_xyz", name: "Wrapped List", category: "general" }],
104
+ total: 1
105
+ },
106
+ message: "Success",
107
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
108
+ });
109
+ const { logs, exitCode } = await runCli(["--json", "prompts", "list"]);
110
+ expect(exitCode).toBe(0);
111
+ const parsed = JSON.parse(logs.join("\n"));
112
+ expect(parsed).toHaveLength(1);
113
+ expect(parsed[0].name).toBe("Wrapped List");
114
+ });
115
+ it("should show message when no prompts found", async () => {
116
+ mockSdk.prompts.list.mockResolvedValue({
117
+ success: true,
118
+ data: [],
119
+ message: "Success",
120
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
121
+ });
122
+ const { logs, exitCode } = await runCli(["prompts", "list"]);
123
+ expect(exitCode).toBe(0);
124
+ const output = logs.join("\n");
125
+ expect(output).toContain("No prompts found");
126
+ });
127
+ });
128
+ describe("prompts get", () => {
129
+ it("should get prompt details by ID", async () => {
130
+ mockSdk.prompts.get.mockResolvedValue({
131
+ success: true,
132
+ data: {
133
+ id: "prompt_abc123",
134
+ name: "Support Greeting",
135
+ content: "Hello! How can I help you today?",
136
+ category: "support",
137
+ status: "active",
138
+ version: 3,
139
+ tags: ["greeting", "support"],
140
+ createdAt: "2025-01-01T00:00:00Z",
141
+ updatedAt: "2025-01-15T10:30:00Z"
142
+ },
143
+ message: "Success",
144
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
145
+ });
146
+ const { logs, exitCode } = await runCli(["prompts", "get", "prompt_abc123"]);
147
+ expect(exitCode).toBe(0);
148
+ expect(mockSdk.prompts.get).toHaveBeenCalledWith("prompt_abc123");
149
+ const output = logs.join("\n");
150
+ expect(output).toContain("Support Greeting");
151
+ expect(output).toContain("prompt_abc123");
152
+ });
153
+ it("should output JSON when --json flag is used", async () => {
154
+ mockSdk.prompts.get.mockResolvedValue({
155
+ success: true,
156
+ data: {
157
+ id: "prompt_abc123",
158
+ name: "Support Greeting",
159
+ content: "Hello! How can I help you today?",
160
+ category: "support",
161
+ status: "active"
162
+ },
163
+ message: "Success",
164
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
165
+ });
166
+ const { logs, exitCode } = await runCli(["--json", "prompts", "get", "prompt_abc123"]);
167
+ expect(exitCode).toBe(0);
168
+ const output = logs.join("\n");
169
+ const parsed = JSON.parse(output);
170
+ expect(parsed.name).toBe("Support Greeting");
171
+ expect(parsed.content).toBe("Hello! How can I help you today?");
172
+ });
173
+ it("should handle not found error", async () => {
174
+ mockSdk.prompts.get.mockResolvedValue({
175
+ success: false,
176
+ data: null,
177
+ message: "Prompt not found",
178
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
179
+ });
180
+ const { exitCode, errors } = await runCli(["prompts", "get", "nonexistent"]);
181
+ expect(exitCode).toBe(1);
182
+ expect(errors.some((e) => e.includes("Failed") || e.includes("not found"))).toBe(true);
183
+ });
184
+ });
185
+ describe("prompts delete", () => {
186
+ it("should delete a prompt", async () => {
187
+ mockSdk.prompts.delete.mockResolvedValue({
188
+ success: true,
189
+ data: null,
190
+ message: "Success",
191
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
192
+ });
193
+ const { logs, exitCode } = await runCli(["prompts", "delete", "prompt_abc123", "--yes"]);
194
+ expect(exitCode).toBe(0);
195
+ expect(mockSdk.prompts.delete).toHaveBeenCalledWith("prompt_abc123");
196
+ const output = logs.join("\n");
197
+ expect(output).toContain("deleted");
198
+ });
199
+ });
200
+ describe("prompts versions list", () => {
201
+ it("should list prompt versions", async () => {
202
+ mockSdk.prompts.getVersions.mockResolvedValue({
203
+ success: true,
204
+ data: [{ version: 2, versionName: "v2", isActive: true, createdAt: "2025-01-01T00:00:00Z" }],
205
+ message: "Success",
206
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
207
+ });
208
+ const { exitCode } = await runCli(["prompts", "versions", "list", "prompt_abc123"]);
209
+ expect(exitCode).toBe(0);
210
+ expect(mockSdk.prompts.getVersions).toHaveBeenCalledWith("prompt_abc123");
211
+ });
212
+ });
213
+ describe("prompts revert", () => {
214
+ it("should revert to a version", async () => {
215
+ mockSdk.prompts.revert.mockResolvedValue({
216
+ success: true,
217
+ data: { id: "prompt_abc123", version: 1 },
218
+ message: "Success",
219
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
220
+ });
221
+ const { exitCode } = await runCli(["prompts", "revert", "prompt_abc123", "--to-version", "1"]);
222
+ expect(exitCode).toBe(0);
223
+ expect(mockSdk.prompts.revert).toHaveBeenCalledWith("prompt_abc123", { version: 1 });
224
+ });
225
+ });
226
+ });
227
+ //# sourceMappingURL=prompts.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/__tests__/prompts.test.ts"],"sourcesContent":["/**\n * CLI prompts tests — prompts list, prompts get, prompts delete\n */\n\nimport { describe, it, expect, beforeEach, afterEach, vi, Mock } from 'vitest';\nimport { configStore } from '../utils/config-store';\nimport { ChanlSDK } from '@chanl/sdk';\nimport {\n runCli,\n makeMockSdk,\n setupAuthenticatedConfigStore,\n type MockSdk,\n} from './helpers';\n\n// Mock the SDK\nvi.mock('@chanl/sdk', () => ({\n ChanlSDK: vi.fn(),\n}));\n\n// Mock config store\nvi.mock('../utils/config-store', () => ({\n configStore: {\n getApiKey: vi.fn(),\n getBaseUrl: vi.fn(() => 'https://api.chanl.ai'),\n getWorkspaceId: vi.fn(() => 'ws_123'),\n getJwtToken: vi.fn(() => null),\n getAuthMethod: vi.fn(() => null),\n getAppUrl: vi.fn(() => 'https://app.chanl.ai'),\n getDeployment: vi.fn(() => 'cloud'),\n getApiPrefix: vi.fn(() => '/api/v1'),\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 mockSdk: MockSdk;\n\n beforeEach(() => {\n vi.clearAllMocks();\n mockSdk = makeMockSdk();\n (ChanlSDK as Mock).mockImplementation(() => mockSdk);\n setupAuthenticatedConfigStore(configStore as unknown as {\n getApiKey: Mock;\n getWorkspaceId: Mock;\n isAuthenticated: Mock;\n });\n });\n\n afterEach(() => {\n process.exitCode = undefined;\n });\n\n // ==========================================================================\n // PROMPTS CLI TESTS (Story 8)\n // ==========================================================================\n\n describe('prompts list', () => {\n it('should list prompts with table output', async () => {\n mockSdk.prompts.list.mockResolvedValue({\n success: true,\n data: [\n {\n id: 'prompt_abc123',\n name: 'Support Greeting',\n category: 'support',\n status: 'active',\n version: 3,\n createdAt: '2025-01-01T00:00:00Z',\n updatedAt: '2025-01-15T10:30:00Z',\n },\n {\n id: 'prompt_def456',\n name: 'Sales Pitch',\n category: 'sales',\n status: 'draft',\n version: 1,\n createdAt: '2025-02-01T00:00:00Z',\n updatedAt: '2025-02-05T10:30:00Z',\n },\n ],\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli(['prompts', 'list']);\n\n expect(exitCode).toBe(0);\n expect(mockSdk.prompts.list).toHaveBeenCalled();\n\n const output = logs.join('\\n');\n expect(output).toContain('Support Greeting');\n expect(output).toContain('Sales Pitch');\n });\n\n it('should list prompts with JSON output', async () => {\n const mockPrompts = [\n {\n id: 'prompt_abc123',\n name: 'Support Greeting',\n category: 'support',\n status: 'active',\n },\n ];\n\n mockSdk.prompts.list.mockResolvedValue({\n success: true,\n data: mockPrompts,\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli(['--json', 'prompts', 'list']);\n\n expect(exitCode).toBe(0);\n\n const output = logs.join('\\n');\n const parsed = JSON.parse(output);\n expect(parsed).toHaveLength(1);\n expect(parsed[0].name).toBe('Support Greeting');\n });\n\n it('should unwrap API list shape { prompts: [...] } for JSON output', async () => {\n mockSdk.prompts.list.mockResolvedValue({\n success: true,\n data: {\n prompts: [{ id: 'prompt_xyz', name: 'Wrapped List', category: 'general' }],\n total: 1,\n },\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli(['--json', 'prompts', 'list']);\n\n expect(exitCode).toBe(0);\n const parsed = JSON.parse(logs.join('\\n'));\n expect(parsed).toHaveLength(1);\n expect(parsed[0].name).toBe('Wrapped List');\n });\n\n it('should show message when no prompts found', async () => {\n mockSdk.prompts.list.mockResolvedValue({\n success: true,\n data: [],\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli(['prompts', 'list']);\n\n expect(exitCode).toBe(0);\n\n const output = logs.join('\\n');\n expect(output).toContain('No prompts found');\n });\n });\n\n describe('prompts get', () => {\n it('should get prompt details by ID', async () => {\n mockSdk.prompts.get.mockResolvedValue({\n success: true,\n data: {\n id: 'prompt_abc123',\n name: 'Support Greeting',\n content: 'Hello! How can I help you today?',\n category: 'support',\n status: 'active',\n version: 3,\n tags: ['greeting', 'support'],\n createdAt: '2025-01-01T00:00:00Z',\n updatedAt: '2025-01-15T10:30:00Z',\n },\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli(['prompts', 'get', 'prompt_abc123']);\n\n expect(exitCode).toBe(0);\n expect(mockSdk.prompts.get).toHaveBeenCalledWith('prompt_abc123');\n\n const output = logs.join('\\n');\n expect(output).toContain('Support Greeting');\n expect(output).toContain('prompt_abc123');\n });\n\n it('should output JSON when --json flag is used', async () => {\n mockSdk.prompts.get.mockResolvedValue({\n success: true,\n data: {\n id: 'prompt_abc123',\n name: 'Support Greeting',\n content: 'Hello! How can I help you today?',\n category: 'support',\n status: 'active',\n },\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli(['--json', 'prompts', 'get', 'prompt_abc123']);\n\n expect(exitCode).toBe(0);\n\n const output = logs.join('\\n');\n const parsed = JSON.parse(output);\n expect(parsed.name).toBe('Support Greeting');\n expect(parsed.content).toBe('Hello! How can I help you today?');\n });\n\n it('should handle not found error', async () => {\n mockSdk.prompts.get.mockResolvedValue({\n success: false,\n data: null,\n message: 'Prompt not found',\n timestamp: new Date().toISOString(),\n });\n\n const { exitCode, errors } = await runCli(['prompts', 'get', 'nonexistent']);\n\n expect(exitCode).toBe(1);\n expect(errors.some((e) => e.includes('Failed') || e.includes('not found'))).toBe(true);\n });\n });\n\n describe('prompts delete', () => {\n it('should delete a prompt', async () => {\n mockSdk.prompts.delete.mockResolvedValue({\n success: true,\n data: null,\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli(['prompts', 'delete', 'prompt_abc123', '--yes']);\n\n expect(exitCode).toBe(0);\n expect(mockSdk.prompts.delete).toHaveBeenCalledWith('prompt_abc123');\n\n const output = logs.join('\\n');\n expect(output).toContain('deleted');\n });\n });\n\n describe('prompts versions list', () => {\n it('should list prompt versions', async () => {\n mockSdk.prompts.getVersions.mockResolvedValue({\n success: true,\n data: [{ version: 2, versionName: 'v2', isActive: true, createdAt: '2025-01-01T00:00:00Z' }],\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { exitCode } = await runCli(['prompts', 'versions', 'list', 'prompt_abc123']);\n expect(exitCode).toBe(0);\n expect(mockSdk.prompts.getVersions).toHaveBeenCalledWith('prompt_abc123');\n });\n });\n\n describe('prompts revert', () => {\n it('should revert to a version', async () => {\n mockSdk.prompts.revert.mockResolvedValue({\n success: true,\n data: { id: 'prompt_abc123', version: 1 },\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { exitCode } = await runCli(['prompts', 'revert', 'prompt_abc123', '--to-version', '1']);\n expect(exitCode).toBe(0);\n expect(mockSdk.prompts.revert).toHaveBeenCalledWith('prompt_abc123', { version: 1 });\n });\n });\n});\n"],"mappings":"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","names":[]}
@@ -0,0 +1,2 @@
1
+
2
+ export { }
@@ -0,0 +1,270 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
2
+ import { configStore } from "../utils/config-store";
3
+ import { ChanlSDK } from "@chanl/sdk";
4
+ import {
5
+ runCli,
6
+ makeMockSdk,
7
+ setupAuthenticatedConfigStore
8
+ } from "./helpers";
9
+ vi.mock("@chanl/sdk", () => ({
10
+ ChanlSDK: vi.fn()
11
+ }));
12
+ vi.mock("../utils/config-store", () => ({
13
+ configStore: {
14
+ getApiKey: vi.fn(),
15
+ getBaseUrl: vi.fn(() => "https://api.chanl.ai"),
16
+ getWorkspaceId: vi.fn(() => "ws_123"),
17
+ getJwtToken: vi.fn(() => null),
18
+ getAuthMethod: vi.fn(() => null),
19
+ getAppUrl: vi.fn(() => "https://app.chanl.ai"),
20
+ getDeployment: vi.fn(() => "cloud"),
21
+ getApiPrefix: vi.fn(() => "/api/v1"),
22
+ setApiKey: vi.fn(),
23
+ setBaseUrl: vi.fn(),
24
+ setWorkspaceId: vi.fn(),
25
+ removeApiKey: vi.fn(),
26
+ clearAuth: vi.fn(),
27
+ delete: vi.fn(),
28
+ isAuthenticated: vi.fn(),
29
+ getPath: vi.fn(() => "/home/user/.chanl/config.json")
30
+ }
31
+ }));
32
+ describe("CLI", () => {
33
+ let mockSdk;
34
+ beforeEach(() => {
35
+ vi.clearAllMocks();
36
+ mockSdk = makeMockSdk();
37
+ ChanlSDK.mockImplementation(() => mockSdk);
38
+ setupAuthenticatedConfigStore(configStore);
39
+ });
40
+ afterEach(() => {
41
+ process.exitCode = void 0;
42
+ });
43
+ describe("scenarios execution with tool calls", () => {
44
+ const mockToolCalls = [
45
+ {
46
+ id: "tc-001",
47
+ name: "get_weather",
48
+ parameters: { city: "London" },
49
+ result: { temperature: "12\xB0C" },
50
+ status: "success",
51
+ durationMs: 245,
52
+ startedAt: "2025-01-09T10:30:00.000Z",
53
+ completedAt: "2025-01-09T10:30:00.245Z"
54
+ },
55
+ {
56
+ id: "tc-002",
57
+ name: "send_email",
58
+ parameters: { to: "user@test.com" },
59
+ status: "error",
60
+ durationMs: 1200,
61
+ startedAt: "2025-01-09T10:30:01.000Z",
62
+ error: { message: "SMTP connection failed", code: "NETWORK_ERROR" }
63
+ }
64
+ ];
65
+ it("should display tool calls in execution details", async () => {
66
+ mockSdk.scenarios.getExecution.mockResolvedValue({
67
+ success: true,
68
+ data: {
69
+ id: "exec_tc1",
70
+ executionId: "exec_tc1",
71
+ scenarioId: "scen_abc123",
72
+ status: "completed",
73
+ overallScore: 85,
74
+ duration: 12.5,
75
+ stepResults: [
76
+ {
77
+ stepId: "step_1",
78
+ status: "completed",
79
+ actualResponse: "The weather is 12\xB0C in London.",
80
+ toolCalls: mockToolCalls
81
+ }
82
+ ]
83
+ },
84
+ message: "Success",
85
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
86
+ });
87
+ const { logs, exitCode } = await runCli(["scenarios", "execution", "exec_tc1"]);
88
+ expect(exitCode).toBe(0);
89
+ expect(mockSdk.scenarios.getExecution).toHaveBeenCalledWith("exec_tc1");
90
+ const output = logs.join("\n");
91
+ expect(output).toContain("Tool Calls");
92
+ expect(output).toContain("get_weather");
93
+ expect(output).toContain("send_email");
94
+ expect(output).toContain("245ms");
95
+ expect(output).toContain("SMTP connection failed");
96
+ });
97
+ it("should include tool calls in JSON execution output", async () => {
98
+ mockSdk.scenarios.getExecution.mockResolvedValue({
99
+ success: true,
100
+ data: {
101
+ execution: {
102
+ id: "exec_tc2",
103
+ executionId: "exec_tc2",
104
+ scenarioId: "scen_abc123",
105
+ status: "completed",
106
+ overallScore: 85,
107
+ duration: 12.5,
108
+ stepResults: [
109
+ {
110
+ stepId: "step_1",
111
+ status: "completed",
112
+ actualResponse: "The weather is 12\xB0C in London.",
113
+ toolCalls: mockToolCalls
114
+ }
115
+ ]
116
+ }
117
+ },
118
+ message: "Success",
119
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
120
+ });
121
+ const { logs, exitCode } = await runCli(["--json", "scenarios", "execution", "exec_tc2"]);
122
+ expect(exitCode).toBe(0);
123
+ const output = logs.join("\n");
124
+ const parsed = JSON.parse(output);
125
+ expect(parsed.execution).toBeDefined();
126
+ expect(parsed.execution.stepResults[0].toolCalls).toHaveLength(2);
127
+ expect(parsed.execution.stepResults[0].toolCalls[0].name).toBe("get_weather");
128
+ expect(parsed.execution.stepResults[0].toolCalls[1].name).toBe("send_email");
129
+ });
130
+ });
131
+ describe("scenarios run-all", () => {
132
+ const mockBatchResult = {
133
+ agentId: "agent_abc",
134
+ totalScenarios: 3,
135
+ passed: 3,
136
+ failed: 0,
137
+ averageScore: 90,
138
+ allPassed: true,
139
+ minScore: 80,
140
+ results: [
141
+ {
142
+ scenarioId: "scen_001",
143
+ scenarioName: "Greeting Flow",
144
+ executionId: "exec_001",
145
+ status: "completed",
146
+ score: 90,
147
+ duration: 15.5,
148
+ toolCallCount: 2,
149
+ passed: true
150
+ },
151
+ {
152
+ scenarioId: "scen_002",
153
+ scenarioName: "Refund Flow",
154
+ executionId: "exec_002",
155
+ status: "completed",
156
+ score: 85,
157
+ duration: 22.3,
158
+ toolCallCount: 3,
159
+ passed: true
160
+ },
161
+ {
162
+ scenarioId: "scen_003",
163
+ scenarioName: "Escalation Flow",
164
+ executionId: "exec_003",
165
+ status: "completed",
166
+ score: 95,
167
+ duration: 10.1,
168
+ toolCallCount: 1,
169
+ passed: true
170
+ }
171
+ ]
172
+ };
173
+ it("should display results when all scenarios pass", async () => {
174
+ mockSdk.scenarios.runAll.mockResolvedValue(mockBatchResult);
175
+ const { logs, exitCode } = await runCli([
176
+ "scenarios",
177
+ "run-all",
178
+ "--agent",
179
+ "agent_abc",
180
+ "--min-score",
181
+ "80"
182
+ ]);
183
+ expect(exitCode).toBe(0);
184
+ expect(mockSdk.scenarios.runAll).toHaveBeenCalledWith(
185
+ expect.objectContaining({
186
+ agentId: "agent_abc",
187
+ minScore: 80
188
+ })
189
+ );
190
+ const output = logs.join("\n");
191
+ expect(output).toContain("Greeting Flow");
192
+ expect(output).toContain("Refund Flow");
193
+ expect(output).toContain("Escalation Flow");
194
+ expect(output).toMatch(/3.*passed/i);
195
+ });
196
+ it("should exit code 1 when any scenario fails", async () => {
197
+ const failedResult = {
198
+ ...mockBatchResult,
199
+ allPassed: false,
200
+ passed: 2,
201
+ failed: 1,
202
+ averageScore: 78,
203
+ results: [
204
+ { ...mockBatchResult.results[0] },
205
+ { ...mockBatchResult.results[1], score: 60, passed: false },
206
+ { ...mockBatchResult.results[2] }
207
+ ]
208
+ };
209
+ mockSdk.scenarios.runAll.mockResolvedValue(failedResult);
210
+ const { exitCode } = await runCli([
211
+ "scenarios",
212
+ "run-all",
213
+ "--agent",
214
+ "agent_abc",
215
+ "--min-score",
216
+ "80"
217
+ ]);
218
+ expect(exitCode).toBe(1);
219
+ });
220
+ it("should output JSON with --json flag", async () => {
221
+ mockSdk.scenarios.runAll.mockResolvedValue(mockBatchResult);
222
+ const { logs, exitCode } = await runCli([
223
+ "--json",
224
+ "scenarios",
225
+ "run-all",
226
+ "--agent",
227
+ "agent_abc"
228
+ ]);
229
+ expect(exitCode).toBe(0);
230
+ const output = logs.join("\n");
231
+ const parsed = JSON.parse(output);
232
+ expect(parsed.allPassed).toBe(true);
233
+ expect(parsed.totalScenarios).toBe(3);
234
+ expect(parsed.results).toHaveLength(3);
235
+ });
236
+ it("should pass parallel option to SDK", async () => {
237
+ mockSdk.scenarios.runAll.mockResolvedValue(mockBatchResult);
238
+ await runCli([
239
+ "scenarios",
240
+ "run-all",
241
+ "--agent",
242
+ "agent_abc",
243
+ "--parallel",
244
+ "5"
245
+ ]);
246
+ expect(mockSdk.scenarios.runAll).toHaveBeenCalledWith(
247
+ expect.objectContaining({
248
+ agentId: "agent_abc",
249
+ parallel: 5
250
+ })
251
+ );
252
+ });
253
+ it("should display summary with average score", async () => {
254
+ mockSdk.scenarios.runAll.mockResolvedValue(mockBatchResult);
255
+ const { logs } = await runCli([
256
+ "scenarios",
257
+ "run-all",
258
+ "--agent",
259
+ "agent_abc"
260
+ ]);
261
+ const output = logs.join("\n");
262
+ expect(output).toContain("90");
263
+ });
264
+ it("should not call SDK when --agent option is missing", async () => {
265
+ await runCli(["scenarios", "run-all"]);
266
+ expect(mockSdk.scenarios.runAll).not.toHaveBeenCalled();
267
+ });
268
+ });
269
+ });
270
+ //# sourceMappingURL=scenarios.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/__tests__/scenarios.test.ts"],"sourcesContent":["/**\n * CLI scenarios tests — scenarios execution with tool calls, scenarios run-all\n */\n\nimport { describe, it, expect, beforeEach, afterEach, vi, Mock } from 'vitest';\nimport { configStore } from '../utils/config-store';\nimport { ChanlSDK } from '@chanl/sdk';\nimport {\n runCli,\n makeMockSdk,\n setupAuthenticatedConfigStore,\n type MockSdk,\n} from './helpers';\n\n// Mock the SDK\nvi.mock('@chanl/sdk', () => ({\n ChanlSDK: vi.fn(),\n}));\n\n// Mock config store\nvi.mock('../utils/config-store', () => ({\n configStore: {\n getApiKey: vi.fn(),\n getBaseUrl: vi.fn(() => 'https://api.chanl.ai'),\n getWorkspaceId: vi.fn(() => 'ws_123'),\n getJwtToken: vi.fn(() => null),\n getAuthMethod: vi.fn(() => null),\n getAppUrl: vi.fn(() => 'https://app.chanl.ai'),\n getDeployment: vi.fn(() => 'cloud'),\n getApiPrefix: vi.fn(() => '/api/v1'),\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 mockSdk: MockSdk;\n\n beforeEach(() => {\n vi.clearAllMocks();\n mockSdk = makeMockSdk();\n (ChanlSDK as Mock).mockImplementation(() => mockSdk);\n setupAuthenticatedConfigStore(configStore as unknown as {\n getApiKey: Mock;\n getWorkspaceId: Mock;\n isAuthenticated: Mock;\n });\n });\n\n afterEach(() => {\n process.exitCode = undefined;\n });\n\n describe('scenarios execution with tool calls', () => {\n const mockToolCalls = [\n {\n id: 'tc-001',\n name: 'get_weather',\n parameters: { city: 'London' },\n result: { temperature: '12°C' },\n status: 'success',\n durationMs: 245,\n startedAt: '2025-01-09T10:30:00.000Z',\n completedAt: '2025-01-09T10:30:00.245Z',\n },\n {\n id: 'tc-002',\n name: 'send_email',\n parameters: { to: 'user@test.com' },\n status: 'error',\n durationMs: 1200,\n startedAt: '2025-01-09T10:30:01.000Z',\n error: { message: 'SMTP connection failed', code: 'NETWORK_ERROR' },\n },\n ];\n\n it('should display tool calls in execution details', async () => {\n mockSdk.scenarios.getExecution.mockResolvedValue({\n success: true,\n data: {\n id: 'exec_tc1',\n executionId: 'exec_tc1',\n scenarioId: 'scen_abc123',\n status: 'completed',\n overallScore: 85,\n duration: 12.5,\n stepResults: [\n {\n stepId: 'step_1',\n status: 'completed',\n actualResponse: 'The weather is 12°C in London.',\n toolCalls: mockToolCalls,\n },\n ],\n },\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli(['scenarios', 'execution', 'exec_tc1']);\n\n expect(exitCode).toBe(0);\n expect(mockSdk.scenarios.getExecution).toHaveBeenCalledWith('exec_tc1');\n\n const output = logs.join('\\n');\n // Should display Tool Calls section\n expect(output).toContain('Tool Calls');\n // Should display tool names\n expect(output).toContain('get_weather');\n expect(output).toContain('send_email');\n // Should display duration\n expect(output).toContain('245ms');\n // Should display error message for failed tool call\n expect(output).toContain('SMTP connection failed');\n });\n\n it('should include tool calls in JSON execution output', async () => {\n mockSdk.scenarios.getExecution.mockResolvedValue({\n success: true,\n data: {\n execution: {\n id: 'exec_tc2',\n executionId: 'exec_tc2',\n scenarioId: 'scen_abc123',\n status: 'completed',\n overallScore: 85,\n duration: 12.5,\n stepResults: [\n {\n stepId: 'step_1',\n status: 'completed',\n actualResponse: 'The weather is 12°C in London.',\n toolCalls: mockToolCalls,\n },\n ],\n },\n },\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli(['--json', 'scenarios', 'execution', 'exec_tc2']);\n\n expect(exitCode).toBe(0);\n\n const output = logs.join('\\n');\n const parsed = JSON.parse(output);\n expect(parsed.execution).toBeDefined();\n expect(parsed.execution.stepResults[0].toolCalls).toHaveLength(2);\n expect(parsed.execution.stepResults[0].toolCalls[0].name).toBe('get_weather');\n expect(parsed.execution.stepResults[0].toolCalls[1].name).toBe('send_email');\n });\n });\n\n // ============================================\n // Story 7: Batch Scenario Execution (run-all)\n // RED-phase tests — `chanl scenarios run-all` command does NOT exist yet\n // ============================================\n describe('scenarios run-all', () => {\n const mockBatchResult = {\n agentId: 'agent_abc',\n totalScenarios: 3,\n passed: 3,\n failed: 0,\n averageScore: 90,\n allPassed: true,\n minScore: 80,\n results: [\n {\n scenarioId: 'scen_001',\n scenarioName: 'Greeting Flow',\n executionId: 'exec_001',\n status: 'completed',\n score: 90,\n duration: 15.5,\n toolCallCount: 2,\n passed: true,\n },\n {\n scenarioId: 'scen_002',\n scenarioName: 'Refund Flow',\n executionId: 'exec_002',\n status: 'completed',\n score: 85,\n duration: 22.3,\n toolCallCount: 3,\n passed: true,\n },\n {\n scenarioId: 'scen_003',\n scenarioName: 'Escalation Flow',\n executionId: 'exec_003',\n status: 'completed',\n score: 95,\n duration: 10.1,\n toolCallCount: 1,\n passed: true,\n },\n ],\n };\n\n it('should display results when all scenarios pass', async () => {\n mockSdk.scenarios.runAll.mockResolvedValue(mockBatchResult);\n\n const { logs, exitCode } = await runCli([\n 'scenarios', 'run-all', '--agent', 'agent_abc', '--min-score', '80',\n ]);\n\n expect(exitCode).toBe(0);\n expect(mockSdk.scenarios.runAll).toHaveBeenCalledWith(\n expect.objectContaining({\n agentId: 'agent_abc',\n minScore: 80,\n }),\n );\n\n const output = logs.join('\\n');\n // Should display scenario names\n expect(output).toContain('Greeting Flow');\n expect(output).toContain('Refund Flow');\n expect(output).toContain('Escalation Flow');\n // Should display pass indicator\n expect(output).toMatch(/3.*passed/i);\n });\n\n it('should exit code 1 when any scenario fails', async () => {\n const failedResult = {\n ...mockBatchResult,\n allPassed: false,\n passed: 2,\n failed: 1,\n averageScore: 78,\n results: [\n { ...mockBatchResult.results[0] },\n { ...mockBatchResult.results[1], score: 60, passed: false },\n { ...mockBatchResult.results[2] },\n ],\n };\n\n mockSdk.scenarios.runAll.mockResolvedValue(failedResult);\n\n const { exitCode } = await runCli([\n 'scenarios', 'run-all', '--agent', 'agent_abc', '--min-score', '80',\n ]);\n\n expect(exitCode).toBe(1);\n });\n\n it('should output JSON with --json flag', async () => {\n mockSdk.scenarios.runAll.mockResolvedValue(mockBatchResult);\n\n const { logs, exitCode } = await runCli([\n '--json', 'scenarios', 'run-all', '--agent', 'agent_abc',\n ]);\n\n expect(exitCode).toBe(0);\n\n const output = logs.join('\\n');\n const parsed = JSON.parse(output);\n expect(parsed.allPassed).toBe(true);\n expect(parsed.totalScenarios).toBe(3);\n expect(parsed.results).toHaveLength(3);\n });\n\n it('should pass parallel option to SDK', async () => {\n mockSdk.scenarios.runAll.mockResolvedValue(mockBatchResult);\n\n await runCli([\n 'scenarios', 'run-all', '--agent', 'agent_abc', '--parallel', '5',\n ]);\n\n expect(mockSdk.scenarios.runAll).toHaveBeenCalledWith(\n expect.objectContaining({\n agentId: 'agent_abc',\n parallel: 5,\n }),\n );\n });\n\n it('should display summary with average score', async () => {\n mockSdk.scenarios.runAll.mockResolvedValue(mockBatchResult);\n\n const { logs } = await runCli([\n 'scenarios', 'run-all', '--agent', 'agent_abc',\n ]);\n\n const output = logs.join('\\n');\n // Should display average score\n expect(output).toContain('90');\n });\n\n it('should not call SDK when --agent option is missing', async () => {\n await runCli(['scenarios', 'run-all']);\n\n // Commander throws on missing required option before handler runs\n expect(mockSdk.scenarios.runAll).not.toHaveBeenCalled();\n });\n });\n});\n"],"mappings":"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","names":[]}
@@ -0,0 +1,2 @@
1
+
2
+ export { }