@chanl/cli 2.0.4 → 3.1.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 (78) 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__/cli-p0-scenarios.test.d.ts +2 -0
  19. package/dist/__tests__/cli-p0-scenarios.test.js +123 -0
  20. package/dist/__tests__/cli-p0-scenarios.test.js.map +1 -0
  21. package/dist/__tests__/helpers.d.ts +234 -0
  22. package/dist/__tests__/helpers.js +314 -0
  23. package/dist/__tests__/helpers.js.map +1 -0
  24. package/dist/__tests__/mcp.test.d.ts +2 -0
  25. package/dist/__tests__/mcp.test.js +470 -0
  26. package/dist/__tests__/mcp.test.js.map +1 -0
  27. package/dist/__tests__/prompts.test.d.ts +2 -0
  28. package/dist/__tests__/prompts.test.js +227 -0
  29. package/dist/__tests__/prompts.test.js.map +1 -0
  30. package/dist/__tests__/scenarios.test.d.ts +2 -0
  31. package/dist/__tests__/scenarios.test.js +270 -0
  32. package/dist/__tests__/scenarios.test.js.map +1 -0
  33. package/dist/__tests__/tools.test.d.ts +2 -0
  34. package/dist/__tests__/tools.test.js +331 -0
  35. package/dist/__tests__/tools.test.js.map +1 -0
  36. package/dist/__tests__/toolsets.test.d.ts +2 -0
  37. package/dist/__tests__/toolsets.test.js +196 -0
  38. package/dist/__tests__/toolsets.test.js.map +1 -0
  39. package/dist/__tests__/workspaces.test.d.ts +2 -0
  40. package/dist/__tests__/workspaces.test.js +155 -0
  41. package/dist/__tests__/workspaces.test.js.map +1 -0
  42. package/dist/cli.js +8 -0
  43. package/dist/cli.js.map +1 -1
  44. package/dist/commands/agents.js +194 -6
  45. package/dist/commands/agents.js.map +1 -1
  46. package/dist/commands/chat.js +2 -2
  47. package/dist/commands/chat.js.map +1 -1
  48. package/dist/commands/config.js +24 -2
  49. package/dist/commands/config.js.map +1 -1
  50. package/dist/commands/customers.d.ts +8 -0
  51. package/dist/commands/customers.js +289 -0
  52. package/dist/commands/customers.js.map +1 -0
  53. package/dist/commands/index.d.ts +3 -0
  54. package/dist/commands/index.js +7 -0
  55. package/dist/commands/index.js.map +1 -1
  56. package/dist/commands/memory.js +134 -1
  57. package/dist/commands/memory.js.map +1 -1
  58. package/dist/commands/messaging.d.ts +12 -0
  59. package/dist/commands/messaging.js +208 -0
  60. package/dist/commands/messaging.js.map +1 -0
  61. package/dist/commands/prompts.js +148 -1
  62. package/dist/commands/prompts.js.map +1 -1
  63. package/dist/commands/scenarios.js +121 -0
  64. package/dist/commands/scenarios.js.map +1 -1
  65. package/dist/commands/scorecards.js +3 -3
  66. package/dist/commands/scorecards.js.map +1 -1
  67. package/dist/commands/whatsapp.d.ts +8 -0
  68. package/dist/commands/whatsapp.js +332 -0
  69. package/dist/commands/whatsapp.js.map +1 -0
  70. package/dist/utils/config-store.d.ts +8 -0
  71. package/dist/utils/config-store.js +18 -1
  72. package/dist/utils/config-store.js.map +1 -1
  73. package/dist/utils/sdk-factory.js +15 -3
  74. package/dist/utils/sdk-factory.js.map +1 -1
  75. package/package.json +4 -4
  76. package/dist/__tests__/cli.test.js +0 -2308
  77. package/dist/__tests__/cli.test.js.map +0 -1
  78. /package/dist/__tests__/{cli.test.d.ts → agents.test.d.ts} +0 -0
@@ -0,0 +1,155 @@
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("workspaces list", () => {
44
+ it("should list workspaces with table output", async () => {
45
+ mockSdk.workspace.getAll.mockResolvedValue({
46
+ success: true,
47
+ data: [
48
+ {
49
+ id: "ws_abc123",
50
+ name: "My Workspace",
51
+ description: "Main workspace",
52
+ createdAt: "2025-01-01T00:00:00Z",
53
+ updatedAt: "2025-01-15T10:30:00Z"
54
+ },
55
+ {
56
+ id: "ws_def456",
57
+ name: "Test Workspace",
58
+ description: "Testing environment",
59
+ createdAt: "2025-02-01T00:00:00Z",
60
+ updatedAt: "2025-02-05T10:30:00Z"
61
+ }
62
+ ],
63
+ message: "Success",
64
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
65
+ });
66
+ const { logs, exitCode } = await runCli(["workspaces", "list"]);
67
+ expect(exitCode).toBe(0);
68
+ expect(mockSdk.workspace.getAll).toHaveBeenCalled();
69
+ const output = logs.join("\n");
70
+ expect(output).toContain("My Workspace");
71
+ expect(output).toContain("Test Workspace");
72
+ });
73
+ it("should list workspaces with JSON output", async () => {
74
+ const mockWorkspaces = [
75
+ {
76
+ id: "ws_abc123",
77
+ name: "My Workspace",
78
+ description: "Main workspace",
79
+ createdAt: "2025-01-01T00:00:00Z",
80
+ updatedAt: "2025-01-15T10:30:00Z"
81
+ }
82
+ ];
83
+ mockSdk.workspace.getAll.mockResolvedValue({
84
+ success: true,
85
+ data: mockWorkspaces,
86
+ message: "Success",
87
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
88
+ });
89
+ const { logs, exitCode } = await runCli(["--json", "workspaces", "list"]);
90
+ expect(exitCode).toBe(0);
91
+ const output = logs.join("\n");
92
+ const parsed = JSON.parse(output);
93
+ expect(parsed).toHaveLength(1);
94
+ expect(parsed[0].name).toBe("My Workspace");
95
+ });
96
+ });
97
+ describe("workspaces get", () => {
98
+ it("should get workspace details by ID", async () => {
99
+ mockSdk.workspace.getById.mockResolvedValue({
100
+ success: true,
101
+ data: {
102
+ id: "ws_abc123",
103
+ name: "My Workspace",
104
+ description: "Main workspace",
105
+ settings: { timezone: "UTC" },
106
+ createdAt: "2025-01-01T00:00:00Z",
107
+ updatedAt: "2025-01-15T10:30:00Z"
108
+ },
109
+ message: "Success",
110
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
111
+ });
112
+ const { logs, exitCode } = await runCli(["workspaces", "get", "ws_abc123"]);
113
+ expect(exitCode).toBe(0);
114
+ expect(mockSdk.workspace.getById).toHaveBeenCalledWith("ws_abc123");
115
+ const output = logs.join("\n");
116
+ expect(output).toContain("My Workspace");
117
+ expect(output).toContain("ws_abc123");
118
+ });
119
+ });
120
+ describe("workspaces use", () => {
121
+ it("should set active workspace", async () => {
122
+ mockSdk.workspace.getById.mockResolvedValue({
123
+ success: true,
124
+ data: {
125
+ id: "ws_abc123",
126
+ name: "My Workspace",
127
+ description: "Main workspace",
128
+ settings: {},
129
+ createdAt: "2025-01-01T00:00:00Z",
130
+ updatedAt: "2025-01-15T10:30:00Z"
131
+ },
132
+ message: "Success",
133
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
134
+ });
135
+ const { logs, exitCode } = await runCli(["workspaces", "use", "ws_abc123"]);
136
+ expect(exitCode).toBe(0);
137
+ expect(configStore.setWorkspaceId).toHaveBeenCalledWith("ws_abc123");
138
+ const output = logs.join("\n");
139
+ expect(output).toContain("ws_abc123");
140
+ });
141
+ it("should handle invalid workspace ID", async () => {
142
+ mockSdk.workspace.getById.mockResolvedValue({
143
+ success: false,
144
+ data: null,
145
+ message: "Workspace not found",
146
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
147
+ });
148
+ const { exitCode, errors } = await runCli(["workspaces", "use", "ws_invalid"]);
149
+ expect(exitCode).toBe(1);
150
+ expect(errors.some((e) => e.includes("not found") || e.includes("Failed"))).toBe(true);
151
+ expect(configStore.setWorkspaceId).not.toHaveBeenCalled();
152
+ });
153
+ });
154
+ });
155
+ //# sourceMappingURL=workspaces.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/__tests__/workspaces.test.ts"],"sourcesContent":["/**\n * CLI workspaces tests — workspaces list, workspaces get, workspaces use\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 // WORKSPACES CLI TESTS (Story 9)\n // ==========================================================================\n\n describe('workspaces list', () => {\n it('should list workspaces with table output', async () => {\n mockSdk.workspace.getAll.mockResolvedValue({\n success: true,\n data: [\n {\n id: 'ws_abc123',\n name: 'My Workspace',\n description: 'Main workspace',\n createdAt: '2025-01-01T00:00:00Z',\n updatedAt: '2025-01-15T10:30:00Z',\n },\n {\n id: 'ws_def456',\n name: 'Test Workspace',\n description: 'Testing environment',\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(['workspaces', 'list']);\n\n expect(exitCode).toBe(0);\n expect(mockSdk.workspace.getAll).toHaveBeenCalled();\n\n const output = logs.join('\\n');\n expect(output).toContain('My Workspace');\n expect(output).toContain('Test Workspace');\n });\n\n it('should list workspaces with JSON output', async () => {\n const mockWorkspaces = [\n {\n id: 'ws_abc123',\n name: 'My Workspace',\n description: 'Main workspace',\n createdAt: '2025-01-01T00:00:00Z',\n updatedAt: '2025-01-15T10:30:00Z',\n },\n ];\n\n mockSdk.workspace.getAll.mockResolvedValue({\n success: true,\n data: mockWorkspaces,\n message: 'Success',\n timestamp: new Date().toISOString(),\n });\n\n const { logs, exitCode } = await runCli(['--json', 'workspaces', '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('My Workspace');\n });\n });\n\n describe('workspaces get', () => {\n it('should get workspace details by ID', async () => {\n mockSdk.workspace.getById.mockResolvedValue({\n success: true,\n data: {\n id: 'ws_abc123',\n name: 'My Workspace',\n description: 'Main workspace',\n settings: { timezone: 'UTC' },\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(['workspaces', 'get', 'ws_abc123']);\n\n expect(exitCode).toBe(0);\n expect(mockSdk.workspace.getById).toHaveBeenCalledWith('ws_abc123');\n\n const output = logs.join('\\n');\n expect(output).toContain('My Workspace');\n expect(output).toContain('ws_abc123');\n });\n });\n\n describe('workspaces use', () => {\n it('should set active workspace', async () => {\n mockSdk.workspace.getById.mockResolvedValue({\n success: true,\n data: {\n id: 'ws_abc123',\n name: 'My Workspace',\n description: 'Main workspace',\n settings: {},\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(['workspaces', 'use', 'ws_abc123']);\n\n expect(exitCode).toBe(0);\n expect(configStore.setWorkspaceId).toHaveBeenCalledWith('ws_abc123');\n\n const output = logs.join('\\n');\n expect(output).toContain('ws_abc123');\n });\n\n it('should handle invalid workspace ID', async () => {\n mockSdk.workspace.getById.mockResolvedValue({\n success: false,\n data: null,\n message: 'Workspace not found',\n timestamp: new Date().toISOString(),\n });\n\n const { exitCode, errors } = await runCli(['workspaces', 'use', 'ws_invalid']);\n\n expect(exitCode).toBe(1);\n expect(errors.some((e) => e.includes('not found') || e.includes('Failed'))).toBe(true);\n expect(configStore.setWorkspaceId).not.toHaveBeenCalled();\n });\n });\n});\n"],"mappings":"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","names":[]}
package/dist/cli.js CHANGED
@@ -12,6 +12,10 @@ import {
12
12
  createCallCommand,
13
13
  createCallsCommand,
14
14
  createPersonasCommand,
15
+ createCustomersCommand,
16
+ createConversationsCommand,
17
+ createMessagesCommand,
18
+ createWhatsAppCommand,
15
19
  createAgentsCommand,
16
20
  createHealthCommand,
17
21
  createMcpCommand,
@@ -43,6 +47,10 @@ function createProgram() {
43
47
  program.addCommand(createCallCommand());
44
48
  program.addCommand(createCallsCommand());
45
49
  program.addCommand(createPersonasCommand());
50
+ program.addCommand(createCustomersCommand());
51
+ program.addCommand(createConversationsCommand());
52
+ program.addCommand(createMessagesCommand());
53
+ program.addCommand(createWhatsAppCommand());
46
54
  program.addCommand(createAgentsCommand());
47
55
  program.addCommand(createHealthCommand());
48
56
  program.addCommand(createMcpCommand());
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { createRequire } from 'module';\nimport { setOutputOptions } from './utils/output.js';\nimport {\n createAuthCommand,\n createLoginCommand,\n createLogoutCommand,\n createConfigCommand,\n createToolsCommand,\n createToolsetsCommand,\n createScenariosCommand,\n createCallCommand,\n createCallsCommand,\n createPersonasCommand,\n createAgentsCommand,\n createHealthCommand,\n createMcpCommand,\n createScorecardsCommand,\n createKnowledgeCommand,\n createMemoryCommand,\n createChatCommand,\n createPromptsCommand,\n createWorkspacesCommand,\n} from './commands/index.js';\n\nconst require = createRequire(import.meta.url);\nconst { version: CLI_VERSION } = require('../package.json') as { version: string };\n\n/**\n * Create and configure the CLI program\n */\nexport function createProgram(): Command {\n const program = new Command();\n\n program\n .name('chanl')\n .description('Command-line interface for Chanl Analytics')\n .version(CLI_VERSION, '-v, --version', 'Show CLI version')\n .option('--json', 'Output results as JSON')\n .option('--no-color', 'Disable colored output')\n .hook('preAction', (thisCommand) => {\n // Set global output options before any command runs\n const opts = thisCommand.opts();\n setOutputOptions({\n json: opts['json'] === true,\n noColor: opts['color'] === false,\n });\n });\n\n // Add commands\n program.addCommand(createLoginCommand());\n program.addCommand(createLogoutCommand());\n program.addCommand(createAuthCommand());\n program.addCommand(createConfigCommand());\n program.addCommand(createToolsCommand());\n program.addCommand(createToolsetsCommand());\n program.addCommand(createScenariosCommand());\n program.addCommand(createCallCommand());\n program.addCommand(createCallsCommand());\n program.addCommand(createPersonasCommand());\n program.addCommand(createAgentsCommand());\n program.addCommand(createHealthCommand());\n program.addCommand(createMcpCommand());\n program.addCommand(createScorecardsCommand());\n program.addCommand(createKnowledgeCommand());\n program.addCommand(createMemoryCommand());\n program.addCommand(createChatCommand());\n program.addCommand(createPromptsCommand());\n program.addCommand(createWorkspacesCommand());\n\n // Add helpful error handling\n program.showHelpAfterError(true);\n program.showSuggestionAfterError(true);\n\n return program;\n}\n\n/**\n * Run the CLI program\n */\nexport async function run(argv: string[] = process.argv): Promise<void> {\n const program = createProgram();\n\n try {\n await program.parseAsync(argv);\n } catch (error) {\n // Commander handles most errors, but catch any unhandled ones\n if (error instanceof Error) {\n console.error('Error:', error.message);\n }\n process.exitCode = 1;\n }\n}\n"],"mappings":"AAAA,SAAS,eAAe;AACxB,SAAS,qBAAqB;AAC9B,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,MAAMA,WAAU,cAAc,YAAY,GAAG;AAC7C,MAAM,EAAE,SAAS,YAAY,IAAIA,SAAQ,iBAAiB;AAKnD,SAAS,gBAAyB;AACvC,QAAM,UAAU,IAAI,QAAQ;AAE5B,UACG,KAAK,OAAO,EACZ,YAAY,4CAA4C,EACxD,QAAQ,aAAa,iBAAiB,kBAAkB,EACxD,OAAO,UAAU,wBAAwB,EACzC,OAAO,cAAc,wBAAwB,EAC7C,KAAK,aAAa,CAAC,gBAAgB;AAElC,UAAM,OAAO,YAAY,KAAK;AAC9B,qBAAiB;AAAA,MACf,MAAM,KAAK,MAAM,MAAM;AAAA,MACvB,SAAS,KAAK,OAAO,MAAM;AAAA,IAC7B,CAAC;AAAA,EACH,CAAC;AAGH,UAAQ,WAAW,mBAAmB,CAAC;AACvC,UAAQ,WAAW,oBAAoB,CAAC;AACxC,UAAQ,WAAW,kBAAkB,CAAC;AACtC,UAAQ,WAAW,oBAAoB,CAAC;AACxC,UAAQ,WAAW,mBAAmB,CAAC;AACvC,UAAQ,WAAW,sBAAsB,CAAC;AAC1C,UAAQ,WAAW,uBAAuB,CAAC;AAC3C,UAAQ,WAAW,kBAAkB,CAAC;AACtC,UAAQ,WAAW,mBAAmB,CAAC;AACvC,UAAQ,WAAW,sBAAsB,CAAC;AAC1C,UAAQ,WAAW,oBAAoB,CAAC;AACxC,UAAQ,WAAW,oBAAoB,CAAC;AACxC,UAAQ,WAAW,iBAAiB,CAAC;AACrC,UAAQ,WAAW,wBAAwB,CAAC;AAC5C,UAAQ,WAAW,uBAAuB,CAAC;AAC3C,UAAQ,WAAW,oBAAoB,CAAC;AACxC,UAAQ,WAAW,kBAAkB,CAAC;AACtC,UAAQ,WAAW,qBAAqB,CAAC;AACzC,UAAQ,WAAW,wBAAwB,CAAC;AAG5C,UAAQ,mBAAmB,IAAI;AAC/B,UAAQ,yBAAyB,IAAI;AAErC,SAAO;AACT;AAKA,eAAsB,IAAI,OAAiB,QAAQ,MAAqB;AACtE,QAAM,UAAU,cAAc;AAE9B,MAAI;AACF,UAAM,QAAQ,WAAW,IAAI;AAAA,EAC/B,SAAS,OAAO;AAEd,QAAI,iBAAiB,OAAO;AAC1B,cAAQ,MAAM,UAAU,MAAM,OAAO;AAAA,IACvC;AACA,YAAQ,WAAW;AAAA,EACrB;AACF;","names":["require"]}
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { createRequire } from 'module';\nimport { setOutputOptions } from './utils/output.js';\nimport {\n createAuthCommand,\n createLoginCommand,\n createLogoutCommand,\n createConfigCommand,\n createToolsCommand,\n createToolsetsCommand,\n createScenariosCommand,\n createCallCommand,\n createCallsCommand,\n createPersonasCommand,\n createCustomersCommand,\n createConversationsCommand,\n createMessagesCommand,\n createWhatsAppCommand,\n createAgentsCommand,\n createHealthCommand,\n createMcpCommand,\n createScorecardsCommand,\n createKnowledgeCommand,\n createMemoryCommand,\n createChatCommand,\n createPromptsCommand,\n createWorkspacesCommand,\n} from './commands/index.js';\n\nconst require = createRequire(import.meta.url);\nconst { version: CLI_VERSION } = require('../package.json') as { version: string };\n\n/**\n * Create and configure the CLI program\n */\nexport function createProgram(): Command {\n const program = new Command();\n\n program\n .name('chanl')\n .description('Command-line interface for Chanl Analytics')\n .version(CLI_VERSION, '-v, --version', 'Show CLI version')\n .option('--json', 'Output results as JSON')\n .option('--no-color', 'Disable colored output')\n .hook('preAction', (thisCommand) => {\n // Set global output options before any command runs\n const opts = thisCommand.opts();\n setOutputOptions({\n json: opts['json'] === true,\n noColor: opts['color'] === false,\n });\n });\n\n // Add commands\n program.addCommand(createLoginCommand());\n program.addCommand(createLogoutCommand());\n program.addCommand(createAuthCommand());\n program.addCommand(createConfigCommand());\n program.addCommand(createToolsCommand());\n program.addCommand(createToolsetsCommand());\n program.addCommand(createScenariosCommand());\n program.addCommand(createCallCommand());\n program.addCommand(createCallsCommand());\n program.addCommand(createPersonasCommand());\n program.addCommand(createCustomersCommand());\n program.addCommand(createConversationsCommand());\n program.addCommand(createMessagesCommand());\n program.addCommand(createWhatsAppCommand());\n program.addCommand(createAgentsCommand());\n program.addCommand(createHealthCommand());\n program.addCommand(createMcpCommand());\n program.addCommand(createScorecardsCommand());\n program.addCommand(createKnowledgeCommand());\n program.addCommand(createMemoryCommand());\n program.addCommand(createChatCommand());\n program.addCommand(createPromptsCommand());\n program.addCommand(createWorkspacesCommand());\n\n // Add helpful error handling\n program.showHelpAfterError(true);\n program.showSuggestionAfterError(true);\n\n return program;\n}\n\n/**\n * Run the CLI program\n */\nexport async function run(argv: string[] = process.argv): Promise<void> {\n const program = createProgram();\n\n try {\n await program.parseAsync(argv);\n } catch (error) {\n // Commander handles most errors, but catch any unhandled ones\n if (error instanceof Error) {\n console.error('Error:', error.message);\n }\n process.exitCode = 1;\n }\n}\n"],"mappings":"AAAA,SAAS,eAAe;AACxB,SAAS,qBAAqB;AAC9B,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,MAAMA,WAAU,cAAc,YAAY,GAAG;AAC7C,MAAM,EAAE,SAAS,YAAY,IAAIA,SAAQ,iBAAiB;AAKnD,SAAS,gBAAyB;AACvC,QAAM,UAAU,IAAI,QAAQ;AAE5B,UACG,KAAK,OAAO,EACZ,YAAY,4CAA4C,EACxD,QAAQ,aAAa,iBAAiB,kBAAkB,EACxD,OAAO,UAAU,wBAAwB,EACzC,OAAO,cAAc,wBAAwB,EAC7C,KAAK,aAAa,CAAC,gBAAgB;AAElC,UAAM,OAAO,YAAY,KAAK;AAC9B,qBAAiB;AAAA,MACf,MAAM,KAAK,MAAM,MAAM;AAAA,MACvB,SAAS,KAAK,OAAO,MAAM;AAAA,IAC7B,CAAC;AAAA,EACH,CAAC;AAGH,UAAQ,WAAW,mBAAmB,CAAC;AACvC,UAAQ,WAAW,oBAAoB,CAAC;AACxC,UAAQ,WAAW,kBAAkB,CAAC;AACtC,UAAQ,WAAW,oBAAoB,CAAC;AACxC,UAAQ,WAAW,mBAAmB,CAAC;AACvC,UAAQ,WAAW,sBAAsB,CAAC;AAC1C,UAAQ,WAAW,uBAAuB,CAAC;AAC3C,UAAQ,WAAW,kBAAkB,CAAC;AACtC,UAAQ,WAAW,mBAAmB,CAAC;AACvC,UAAQ,WAAW,sBAAsB,CAAC;AAC1C,UAAQ,WAAW,uBAAuB,CAAC;AAC3C,UAAQ,WAAW,2BAA2B,CAAC;AAC/C,UAAQ,WAAW,sBAAsB,CAAC;AAC1C,UAAQ,WAAW,sBAAsB,CAAC;AAC1C,UAAQ,WAAW,oBAAoB,CAAC;AACxC,UAAQ,WAAW,oBAAoB,CAAC;AACxC,UAAQ,WAAW,iBAAiB,CAAC;AACrC,UAAQ,WAAW,wBAAwB,CAAC;AAC5C,UAAQ,WAAW,uBAAuB,CAAC;AAC3C,UAAQ,WAAW,oBAAoB,CAAC;AACxC,UAAQ,WAAW,kBAAkB,CAAC;AACtC,UAAQ,WAAW,qBAAqB,CAAC;AACzC,UAAQ,WAAW,wBAAwB,CAAC;AAG5C,UAAQ,mBAAmB,IAAI;AAC/B,UAAQ,yBAAyB,IAAI;AAErC,SAAO;AACT;AAKA,eAAsB,IAAI,OAAiB,QAAQ,MAAqB;AACtE,QAAM,UAAU,cAAc;AAE9B,MAAI;AACF,UAAM,QAAQ,WAAW,IAAI;AAAA,EAC/B,SAAS,OAAO;AAEd,QAAI,iBAAiB,OAAO;AAC1B,cAAQ,MAAM,UAAU,MAAM,OAAO;AAAA,IACvC;AACA,YAAQ,WAAW;AAAA,EACrB;AACF;","names":["require"]}
@@ -27,7 +27,9 @@ Quick Start:
27
27
  $ chanl agents list # List all agents
28
28
  $ chanl agents get <id> # View agent details
29
29
  $ chanl agents sync vapi # Sync from VAPI
30
- $ chanl agents create --template vapi # Generate VAPI template
30
+ $ chanl agents templates # List provisionable templates
31
+ $ chanl agents create --from-template lead-qualifier --name "Lead Gen Bot"
32
+ $ chanl agents create --template vapi # Generate local VAPI scaffold
31
33
  $ chanl agents stats # View statistics
32
34
 
33
35
  Workflow:
@@ -52,15 +54,29 @@ Examples:
52
54
  $ chanl agents get abc123 # Get agent details
53
55
  $ chanl agents get abc123 --json # Output as JSON`
54
56
  ).action(handleAgentsGet);
55
- agents.command("create").description("Create a new agent").option("-f, --file <path>", "Path to JSON file with agent data").option("--template [platform]", "Output a template JSON (vapi, elevenlabs, custom)").addHelpText(
57
+ agents.command("templates").description("List registry templates you can provision an agent from").addHelpText(
56
58
  "after",
57
59
  `
58
60
  Examples:
59
- $ chanl agents create --template vapi > agent.json # VAPI template
60
- $ chanl agents create --template custom > agent.json # Custom template
61
+ $ chanl agents templates # List registry templates
62
+ $ chanl agents templates --json # Output as JSON
63
+
64
+ Provision one with:
65
+ $ chanl agents create --from-template lead-qualifier --name "My Agent"`
66
+ ).action(handleAgentsTemplates);
67
+ agents.command("create").description("Create a new agent").option("-f, --file <path>", "Path to JSON file with agent data").option("--template [platform]", "Output a local scaffold JSON (vapi, elevenlabs, custom) \u2014 no server call").option("--from-template <templateId>", "Provision from a registry template (see 'chanl agents templates')").option("-n, --name <name>", "Agent name (used with --from-template)").addHelpText(
68
+ "after",
69
+ `
70
+ Examples:
71
+ $ chanl agents create --from-template lead-qualifier --name "Lead Gen Bot"
72
+ # Provision from registry template
73
+ $ chanl agents create --template vapi > agent.json # VAPI scaffold JSON (local, no server call)
74
+ $ chanl agents create --template custom > agent.json # Custom scaffold JSON
61
75
  $ chanl agents create -f agent.json # Create from file
62
76
 
63
- Templates include platform-specific configurations and examples.`
77
+ '--from-template' creates a real, configured agent via the platform's template
78
+ registry (run 'chanl agents templates' to see what's available). '--template'
79
+ just prints a local JSON scaffold to fill in yourself.`
64
80
  ).action(handleAgentsCreate);
65
81
  agents.command("update <id>").description("Update an existing agent").option("-f, --file <path>", "Path to JSON file with update data").option("--sync-to-vapi", "Sync changes back to VAPI platform").addHelpText(
66
82
  "after",
@@ -116,6 +132,21 @@ Examples:
116
132
  $ chanl agents push-mcp agent_123 --to vapi --target ext_456
117
133
  $ chanl agents push-mcp agent_123 --to vapi --json`
118
134
  ).action(handleAgentsPushMcp);
135
+ agents.command("clone <id>").description("Clone an agent with optional overrides").option("-n, --name <name>", "New agent name").option("--model <provider/model>", "Override model (e.g., anthropic/claude-sonnet-4-5-20250929)").option("--type <type>", "Override type (voice, text, hybrid)").option("--platform <platform>", "Override platform").option("--prompt <text>", "Override system prompt").addHelpText(
136
+ "after",
137
+ `
138
+ Examples:
139
+ $ chanl agents clone agent_abc -n "Copy of Bot"
140
+ $ chanl agents clone agent_abc --model openai/gpt-4o-mini --type text
141
+ $ chanl agents clone agent_abc --json`
142
+ ).action(handleAgentsClone);
143
+ agents.command("report <agentId>").description("View scenario test report for an agent").option("--from <date>", "Report start date (ISO)").option("--to <date>", "Report end date (ISO)").addHelpText(
144
+ "after",
145
+ `
146
+ Examples:
147
+ $ chanl agents report agent_abc
148
+ $ chanl agents report agent_abc --json`
149
+ ).action(handleAgentsReport);
119
150
  agents.command("stats").description("View agent statistics").addHelpText(
120
151
  "after",
121
152
  `
@@ -293,6 +324,73 @@ async function handleAgentsGet(id) {
293
324
  process.exitCode = 1;
294
325
  }
295
326
  }
327
+ async function handleAgentsTemplates() {
328
+ const sdk = createSdk();
329
+ if (!sdk) return;
330
+ const spinner = ora("Fetching templates...").start();
331
+ try {
332
+ const response = await sdk.agents.listTemplates();
333
+ spinner.stop();
334
+ if (!response.success || !response.data) {
335
+ printError("Failed to fetch templates", response.message);
336
+ process.exitCode = 1;
337
+ return;
338
+ }
339
+ const { templates } = response.data;
340
+ if (isJsonOutput()) {
341
+ printJson(response.data);
342
+ return;
343
+ }
344
+ if (templates.length === 0) {
345
+ printInfo("No templates available");
346
+ return;
347
+ }
348
+ printBlank();
349
+ printSimpleTable(
350
+ ["ID", "Name", "Version", "Description"],
351
+ templates.map((t) => [t.id, t.name, t.version.toString(), t.description])
352
+ );
353
+ printBlank();
354
+ printInfo('Provision one with: chanl agents create --from-template <id> --name "My Agent"');
355
+ } catch (error) {
356
+ spinner.fail("Failed to fetch templates");
357
+ const message = error instanceof Error ? error.message : "Unknown error";
358
+ printError("Error", message);
359
+ process.exitCode = 1;
360
+ }
361
+ }
362
+ async function handleAgentsCreateFromTemplate(templateId, name) {
363
+ if (!name) {
364
+ printError("Missing required option", "Use '-n, --name <name>' together with --from-template");
365
+ process.exitCode = 1;
366
+ return;
367
+ }
368
+ const sdk = createSdk();
369
+ if (!sdk) return;
370
+ const spinner = ora(`Provisioning agent from template '${templateId}'...`).start();
371
+ try {
372
+ const response = await sdk.agents.createFromTemplate(templateId, { name });
373
+ spinner.stop();
374
+ if (!response.success || !response.data) {
375
+ printError("Failed to create agent from template", response.message);
376
+ process.exitCode = 1;
377
+ return;
378
+ }
379
+ if (isJsonOutput()) {
380
+ printJson(response.data);
381
+ return;
382
+ }
383
+ const agent = response.data;
384
+ printSuccess(`Agent created from template: ${agent.name}`);
385
+ printLabel("ID", agent.id);
386
+ printLabel("Template", templateId);
387
+ } catch (error) {
388
+ spinner.fail("Failed to create agent from template");
389
+ const message = error instanceof Error ? error.message : "Unknown error";
390
+ printError("Error", message);
391
+ process.exitCode = 1;
392
+ }
393
+ }
296
394
  async function handleAgentsCreate(options) {
297
395
  if (options.template !== void 0) {
298
396
  const platform = typeof options.template === "string" ? options.template : "custom";
@@ -300,8 +398,15 @@ async function handleAgentsCreate(options) {
300
398
  console.log(JSON.stringify(template, null, 2));
301
399
  return;
302
400
  }
401
+ if (options.fromTemplate) {
402
+ await handleAgentsCreateFromTemplate(options.fromTemplate, options.name);
403
+ return;
404
+ }
303
405
  if (!options.file) {
304
- printError("Missing required option", "Use '-f <file>' to specify agent data or '--template [platform]' to get a template");
406
+ printError(
407
+ "Missing required option",
408
+ "Use '-f <file>' for agent data, '--from-template <id>' to provision from a registry template, or '--template [platform]' for a local scaffold"
409
+ );
305
410
  process.exitCode = 1;
306
411
  return;
307
412
  }
@@ -665,6 +770,89 @@ async function handleAgentsStats() {
665
770
  process.exitCode = 1;
666
771
  }
667
772
  }
773
+ async function handleAgentsClone(id, options) {
774
+ const sdk = createSdk();
775
+ if (!sdk) return;
776
+ const spinner = ora("Cloning agent...").start();
777
+ try {
778
+ const response = await sdk.agents.clone(id, {
779
+ name: options.name,
780
+ model: options.model,
781
+ type: options.type,
782
+ platform: options.platform,
783
+ prompt: options.prompt
784
+ });
785
+ spinner.stop();
786
+ if (!response.success || !response.data) {
787
+ printError("Clone failed", response.message);
788
+ process.exitCode = 1;
789
+ return;
790
+ }
791
+ const cloned = response.data;
792
+ if (isJsonOutput()) {
793
+ printJson(cloned);
794
+ return;
795
+ }
796
+ printBlank();
797
+ console.log(chalk.green(`Cloned agent: ${cloned.id}`));
798
+ printLabel("Name", cloned.name);
799
+ if (cloned.type) printLabel("Type", cloned.type);
800
+ if (cloned.platform) printLabel("Platform", cloned.platform);
801
+ const model = cloned.configuration?.model;
802
+ if (model?.provider && model?.model) {
803
+ printLabel("Model", `${model.provider} / ${model.model}`);
804
+ }
805
+ printLabel("Cloned from", id);
806
+ printBlank();
807
+ } catch (error) {
808
+ spinner.fail("Clone failed");
809
+ printError("Error", error instanceof Error ? error.message : "Unknown error");
810
+ process.exitCode = 1;
811
+ }
812
+ }
813
+ async function handleAgentsReport(agentId, options) {
814
+ const sdk = createSdk();
815
+ if (!sdk) return;
816
+ const spinner = ora("Fetching agent test report...").start();
817
+ try {
818
+ const response = await sdk.scenarios.getAgentTestReport(agentId, {
819
+ from: options.from,
820
+ to: options.to
821
+ });
822
+ spinner.stop();
823
+ if (!response.success || !response.data) {
824
+ printError("Failed to fetch report", response.message);
825
+ process.exitCode = 1;
826
+ return;
827
+ }
828
+ if (isJsonOutput()) {
829
+ printJson(response.data);
830
+ return;
831
+ }
832
+ const report = response.data;
833
+ printBlank();
834
+ console.log(chalk.bold(`Test Report: ${agentId}`));
835
+ console.log(` Total runs: ${report.totalRuns} Passed: ${report.passed} Failed: ${report.failed}`);
836
+ console.log(` Avg score: ${report.avgScore}% Success rate: ${report.successRate}%`);
837
+ if (report.scenarios?.length) {
838
+ printBlank();
839
+ printSimpleTable(
840
+ ["Scenario", "Runs", "Avg Score", "Last Passed"],
841
+ report.scenarios.map((s) => [
842
+ s.scenarioName,
843
+ s.runs.toString(),
844
+ `${s.avgScore}%`,
845
+ s.lastPassed ? chalk.green("yes") : chalk.red("no")
846
+ ])
847
+ );
848
+ }
849
+ printBlank();
850
+ } catch (error) {
851
+ spinner.fail("Failed to fetch report");
852
+ printError("Error", error instanceof Error ? error.message : "Unknown error");
853
+ process.exitCode = 1;
854
+ }
855
+ }
668
856
  export {
669
857
  createAgentsCommand
670
858
  };