@chanl-ai/cli 2.0.1
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/bin/chanl.js +10 -0
- package/dist/__tests__/cli.test.d.ts +2 -0
- package/dist/__tests__/cli.test.js +2313 -0
- package/dist/__tests__/cli.test.js.map +1 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.js +72 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/agents.d.ts +8 -0
- package/dist/commands/agents.js +671 -0
- package/dist/commands/agents.js.map +1 -0
- package/dist/commands/auth.d.ts +16 -0
- package/dist/commands/auth.js +294 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/call.d.ts +8 -0
- package/dist/commands/call.js +166 -0
- package/dist/commands/call.js.map +1 -0
- package/dist/commands/calls.d.ts +8 -0
- package/dist/commands/calls.js +719 -0
- package/dist/commands/calls.js.map +1 -0
- package/dist/commands/chat.d.ts +8 -0
- package/dist/commands/chat.js +203 -0
- package/dist/commands/chat.js.map +1 -0
- package/dist/commands/config.d.ts +8 -0
- package/dist/commands/config.js +231 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/health.d.ts +8 -0
- package/dist/commands/health.js +55 -0
- package/dist/commands/health.js.map +1 -0
- package/dist/commands/index.d.ts +18 -0
- package/dist/commands/index.js +39 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/knowledge.d.ts +8 -0
- package/dist/commands/knowledge.js +539 -0
- package/dist/commands/knowledge.js.map +1 -0
- package/dist/commands/mcp.d.ts +8 -0
- package/dist/commands/mcp.js +589 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/memory.d.ts +8 -0
- package/dist/commands/memory.js +408 -0
- package/dist/commands/memory.js.map +1 -0
- package/dist/commands/personas.d.ts +8 -0
- package/dist/commands/personas.js +356 -0
- package/dist/commands/personas.js.map +1 -0
- package/dist/commands/prompts.d.ts +8 -0
- package/dist/commands/prompts.js +295 -0
- package/dist/commands/prompts.js.map +1 -0
- package/dist/commands/scenarios.d.ts +8 -0
- package/dist/commands/scenarios.js +591 -0
- package/dist/commands/scenarios.js.map +1 -0
- package/dist/commands/scorecards.d.ts +8 -0
- package/dist/commands/scorecards.js +570 -0
- package/dist/commands/scorecards.js.map +1 -0
- package/dist/commands/tools.d.ts +8 -0
- package/dist/commands/tools.js +632 -0
- package/dist/commands/tools.js.map +1 -0
- package/dist/commands/toolsets.d.ts +8 -0
- package/dist/commands/toolsets.js +464 -0
- package/dist/commands/toolsets.js.map +1 -0
- package/dist/commands/workspaces.d.ts +8 -0
- package/dist/commands/workspaces.js +170 -0
- package/dist/commands/workspaces.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/config-store.d.ts +117 -0
- package/dist/utils/config-store.js +191 -0
- package/dist/utils/config-store.js.map +1 -0
- package/dist/utils/interactive.d.ts +41 -0
- package/dist/utils/interactive.js +83 -0
- package/dist/utils/interactive.js.map +1 -0
- package/dist/utils/output.d.ts +100 -0
- package/dist/utils/output.js +221 -0
- package/dist/utils/output.js.map +1 -0
- package/dist/utils/sdk-factory.d.ts +15 -0
- package/dist/utils/sdk-factory.js +34 -0
- package/dist/utils/sdk-factory.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import ora from "ora";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { readFileSync } from "fs";
|
|
5
|
+
import { createSdk } from "../utils/sdk-factory.js";
|
|
6
|
+
import {
|
|
7
|
+
printError,
|
|
8
|
+
printSuccess,
|
|
9
|
+
printInfo,
|
|
10
|
+
printBlank,
|
|
11
|
+
printSimpleTable,
|
|
12
|
+
printLabel,
|
|
13
|
+
isJsonOutput,
|
|
14
|
+
printJson,
|
|
15
|
+
formatDate
|
|
16
|
+
} from "../utils/output.js";
|
|
17
|
+
function createPersonasCommand() {
|
|
18
|
+
const personas = new Command("personas").description("Manage test personas for scenario simulations").addHelpText(
|
|
19
|
+
"after",
|
|
20
|
+
`
|
|
21
|
+
What are Personas?
|
|
22
|
+
Personas represent simulated callers with specific voice, emotion, and
|
|
23
|
+
behavior characteristics. They are used in scenario testing to simulate
|
|
24
|
+
realistic customer interactions.
|
|
25
|
+
|
|
26
|
+
Quick Start:
|
|
27
|
+
$ chanl personas list # List all personas
|
|
28
|
+
$ chanl personas get <id> # View persona details
|
|
29
|
+
$ chanl personas create --template # Generate template JSON
|
|
30
|
+
$ chanl personas create -f persona.json # Create from file
|
|
31
|
+
$ chanl personas delete <id> # Delete a persona
|
|
32
|
+
|
|
33
|
+
Persona Characteristics:
|
|
34
|
+
- Voice: gender, accent, speech style, clarity
|
|
35
|
+
- Emotion: friendly, frustrated, calm, stressed, etc.
|
|
36
|
+
- Behavior: interruption patterns, cooperation level
|
|
37
|
+
- Environment: background noise, connection quality`
|
|
38
|
+
);
|
|
39
|
+
personas.command("list").description("List all personas").option("-l, --language <lang>", "Filter by language (english, spanish, portuguese)").option("--active", "Show only active personas").option("--limit <number>", "Number of items per page", "20").option("-p, --page <number>", "Page number", "1").addHelpText(
|
|
40
|
+
"after",
|
|
41
|
+
`
|
|
42
|
+
Examples:
|
|
43
|
+
$ chanl personas list # List all personas
|
|
44
|
+
$ chanl personas list --language english # Filter by language
|
|
45
|
+
$ chanl personas list --active # Only active personas
|
|
46
|
+
$ chanl personas list --json # Output as JSON`
|
|
47
|
+
).action(handlePersonasList);
|
|
48
|
+
personas.command("get <id>").description("Get persona details").addHelpText(
|
|
49
|
+
"after",
|
|
50
|
+
`
|
|
51
|
+
Examples:
|
|
52
|
+
$ chanl personas get abc123 # Get persona details
|
|
53
|
+
$ chanl personas get abc123 --json # Output as JSON`
|
|
54
|
+
).action(handlePersonasGet);
|
|
55
|
+
personas.command("create").description("Create a new persona").option("-f, --file <path>", "Path to JSON file with persona data").option("--template", "Output a template JSON file to stdout").addHelpText(
|
|
56
|
+
"after",
|
|
57
|
+
`
|
|
58
|
+
Examples:
|
|
59
|
+
$ chanl personas create --template > persona.json # Get template
|
|
60
|
+
$ chanl personas create -f persona.json # Create from file
|
|
61
|
+
|
|
62
|
+
Template contains all required and optional fields with example values.
|
|
63
|
+
Edit the template and use 'create -f' to create your persona.`
|
|
64
|
+
).action(handlePersonasCreate);
|
|
65
|
+
personas.command("update <id>").description("Update an existing persona").option("-f, --file <path>", "Path to JSON file with update data").addHelpText(
|
|
66
|
+
"after",
|
|
67
|
+
`
|
|
68
|
+
Examples:
|
|
69
|
+
$ chanl personas update abc123 -f updates.json # Update from file
|
|
70
|
+
|
|
71
|
+
The update file should contain only the fields you want to change.`
|
|
72
|
+
).action(handlePersonasUpdate);
|
|
73
|
+
personas.command("delete <id>").description("Delete a persona").option("-y, --yes", "Skip confirmation prompt").addHelpText(
|
|
74
|
+
"after",
|
|
75
|
+
`
|
|
76
|
+
Examples:
|
|
77
|
+
$ chanl personas delete abc123 # Delete with confirmation
|
|
78
|
+
$ chanl personas delete abc123 --yes # Delete without confirmation`
|
|
79
|
+
).action(handlePersonasDelete);
|
|
80
|
+
return personas;
|
|
81
|
+
}
|
|
82
|
+
function formatEmotion(emotion) {
|
|
83
|
+
const colors = {
|
|
84
|
+
friendly: chalk.green,
|
|
85
|
+
calm: chalk.green,
|
|
86
|
+
polite: chalk.green,
|
|
87
|
+
neutral: chalk.gray,
|
|
88
|
+
curious: chalk.cyan,
|
|
89
|
+
distracted: chalk.yellow,
|
|
90
|
+
concerned: chalk.yellow,
|
|
91
|
+
stressed: chalk.yellow,
|
|
92
|
+
annoyed: chalk.red,
|
|
93
|
+
frustrated: chalk.red,
|
|
94
|
+
irritated: chalk.red
|
|
95
|
+
};
|
|
96
|
+
const colorFn = colors[emotion || ""] || chalk.gray;
|
|
97
|
+
return colorFn(emotion || "unknown");
|
|
98
|
+
}
|
|
99
|
+
function getPersonaTemplate() {
|
|
100
|
+
return {
|
|
101
|
+
name: "Example Persona",
|
|
102
|
+
gender: "female",
|
|
103
|
+
emotion: "friendly",
|
|
104
|
+
language: "english",
|
|
105
|
+
accent: "american",
|
|
106
|
+
intentClarity: "very clear",
|
|
107
|
+
speechStyle: "normal",
|
|
108
|
+
backgroundNoise: false,
|
|
109
|
+
allowInterruptions: true,
|
|
110
|
+
description: "A helpful and friendly customer",
|
|
111
|
+
backstory: "Sarah is a regular customer who values good service. She is calling about a recent order.",
|
|
112
|
+
variables: {
|
|
113
|
+
accountNumber: "12345",
|
|
114
|
+
orderNumber: "ORD-2024-001"
|
|
115
|
+
},
|
|
116
|
+
tags: ["customer-service", "order-inquiry"],
|
|
117
|
+
behavior: {
|
|
118
|
+
personality: "cooperative",
|
|
119
|
+
emotionalState: "calm",
|
|
120
|
+
cooperationLevel: "high",
|
|
121
|
+
patience: "moderate",
|
|
122
|
+
communicationStyle: "direct"
|
|
123
|
+
},
|
|
124
|
+
conversationTraits: {
|
|
125
|
+
allowInterruptions: true,
|
|
126
|
+
interruptionFrequency: "low",
|
|
127
|
+
asksClarifyingQuestions: true,
|
|
128
|
+
repeatsInformation: false,
|
|
129
|
+
goesOffTopic: false
|
|
130
|
+
},
|
|
131
|
+
environment: {
|
|
132
|
+
backgroundNoise: false,
|
|
133
|
+
noiseType: "none",
|
|
134
|
+
connectionQuality: "excellent"
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
async function handlePersonasList(options) {
|
|
139
|
+
const sdk = createSdk();
|
|
140
|
+
if (!sdk) return;
|
|
141
|
+
const spinner = ora("Fetching personas...").start();
|
|
142
|
+
try {
|
|
143
|
+
const response = await sdk.personas.list({
|
|
144
|
+
language: options.language,
|
|
145
|
+
isActive: options.active,
|
|
146
|
+
limit: parseInt(options.limit, 10),
|
|
147
|
+
page: parseInt(options.page, 10)
|
|
148
|
+
});
|
|
149
|
+
spinner.stop();
|
|
150
|
+
if (!response.success || !response.data) {
|
|
151
|
+
printError("Failed to fetch personas", response.message);
|
|
152
|
+
process.exitCode = 1;
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const { personas, pagination } = response.data;
|
|
156
|
+
if (isJsonOutput()) {
|
|
157
|
+
printJson(response.data);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (personas.length === 0) {
|
|
161
|
+
printInfo("No personas found");
|
|
162
|
+
printInfo("Use 'chanl personas create --template' to create one");
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
printBlank();
|
|
166
|
+
printSimpleTable(
|
|
167
|
+
["ID", "Name", "Emotion", "Language", "Accent", "Speech", "Active"],
|
|
168
|
+
personas.map((p) => [
|
|
169
|
+
p.id.slice(-12),
|
|
170
|
+
p.name.slice(0, 20),
|
|
171
|
+
formatEmotion(p.emotion),
|
|
172
|
+
p.language || "-",
|
|
173
|
+
p.accent || "-",
|
|
174
|
+
p.speechStyle || "-",
|
|
175
|
+
p.isActive ? chalk.green("yes") : chalk.gray("no")
|
|
176
|
+
])
|
|
177
|
+
);
|
|
178
|
+
printBlank();
|
|
179
|
+
if (pagination) {
|
|
180
|
+
printInfo(`Total: ${pagination.total} personas (Page ${pagination.page} of ${pagination.pages})`);
|
|
181
|
+
}
|
|
182
|
+
} catch (error) {
|
|
183
|
+
spinner.fail("Failed to fetch personas");
|
|
184
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
185
|
+
printError("Error", message);
|
|
186
|
+
process.exitCode = 1;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async function handlePersonasGet(id) {
|
|
190
|
+
const sdk = createSdk();
|
|
191
|
+
if (!sdk) return;
|
|
192
|
+
const spinner = ora("Fetching persona...").start();
|
|
193
|
+
try {
|
|
194
|
+
const response = await sdk.personas.get(id);
|
|
195
|
+
spinner.stop();
|
|
196
|
+
if (!response.success || !response.data) {
|
|
197
|
+
printError("Failed to fetch persona", response.message);
|
|
198
|
+
process.exitCode = 1;
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (isJsonOutput()) {
|
|
202
|
+
printJson(response.data);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const { persona } = response.data;
|
|
206
|
+
printBlank();
|
|
207
|
+
console.log(chalk.bold("Persona Details:"));
|
|
208
|
+
console.log(` ID: ${persona.id}`);
|
|
209
|
+
console.log(` Name: ${persona.name}`);
|
|
210
|
+
console.log(` Gender: ${persona.gender || "-"}`);
|
|
211
|
+
console.log(` Emotion: ${formatEmotion(persona.emotion)}`);
|
|
212
|
+
console.log(` Language: ${persona.language || "-"}`);
|
|
213
|
+
console.log(` Accent: ${persona.accent || "-"}`);
|
|
214
|
+
console.log(` Speech Style: ${persona.speechStyle || "-"}`);
|
|
215
|
+
console.log(` Intent Clarity: ${persona.intentClarity || "-"}`);
|
|
216
|
+
console.log(` Active: ${persona.isActive ? chalk.green("yes") : chalk.gray("no")}`);
|
|
217
|
+
console.log(` Default: ${persona.isDefault ? chalk.cyan("yes") : chalk.gray("no")}`);
|
|
218
|
+
if (persona.description) {
|
|
219
|
+
console.log(`
|
|
220
|
+
Description:`);
|
|
221
|
+
console.log(` ${persona.description}`);
|
|
222
|
+
}
|
|
223
|
+
if (persona.backstory) {
|
|
224
|
+
console.log(`
|
|
225
|
+
Backstory:`);
|
|
226
|
+
console.log(` ${persona.backstory}`);
|
|
227
|
+
}
|
|
228
|
+
console.log(`
|
|
229
|
+
Created: ${formatDate(persona.createdAt)}`);
|
|
230
|
+
console.log(` Updated: ${formatDate(persona.updatedAt)}`);
|
|
231
|
+
printBlank();
|
|
232
|
+
} catch (error) {
|
|
233
|
+
spinner.fail("Failed to fetch persona");
|
|
234
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
235
|
+
printError("Error", message);
|
|
236
|
+
process.exitCode = 1;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
async function handlePersonasCreate(options) {
|
|
240
|
+
if (options.template) {
|
|
241
|
+
const template = getPersonaTemplate();
|
|
242
|
+
console.log(JSON.stringify(template, null, 2));
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
if (!options.file) {
|
|
246
|
+
printError("Missing required option", "Use '-f <file>' to specify persona data or '--template' to get a template");
|
|
247
|
+
process.exitCode = 1;
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const sdk = createSdk();
|
|
251
|
+
if (!sdk) return;
|
|
252
|
+
let personaData;
|
|
253
|
+
try {
|
|
254
|
+
const content = readFileSync(options.file, "utf-8");
|
|
255
|
+
personaData = JSON.parse(content);
|
|
256
|
+
} catch (error) {
|
|
257
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
258
|
+
printError("Failed to read file", message);
|
|
259
|
+
process.exitCode = 1;
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
const spinner = ora("Creating persona...").start();
|
|
263
|
+
try {
|
|
264
|
+
const response = await sdk.personas.create(personaData);
|
|
265
|
+
spinner.stop();
|
|
266
|
+
if (!response.success || !response.data) {
|
|
267
|
+
printError("Failed to create persona", response.message);
|
|
268
|
+
process.exitCode = 1;
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
if (isJsonOutput()) {
|
|
272
|
+
printJson(response.data);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
const { persona } = response.data;
|
|
276
|
+
printSuccess(`Persona created: ${persona.name}`);
|
|
277
|
+
printLabel("ID", persona.id);
|
|
278
|
+
} catch (error) {
|
|
279
|
+
spinner.fail("Failed to create persona");
|
|
280
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
281
|
+
printError("Error", message);
|
|
282
|
+
process.exitCode = 1;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
async function handlePersonasUpdate(id, options) {
|
|
286
|
+
if (!options.file) {
|
|
287
|
+
printError("Missing required option", "Use '-f <file>' to specify update data");
|
|
288
|
+
process.exitCode = 1;
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
const sdk = createSdk();
|
|
292
|
+
if (!sdk) return;
|
|
293
|
+
let updateData;
|
|
294
|
+
try {
|
|
295
|
+
const content = readFileSync(options.file, "utf-8");
|
|
296
|
+
updateData = JSON.parse(content);
|
|
297
|
+
} catch (error) {
|
|
298
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
299
|
+
printError("Failed to read file", message);
|
|
300
|
+
process.exitCode = 1;
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
const spinner = ora("Updating persona...").start();
|
|
304
|
+
try {
|
|
305
|
+
const response = await sdk.personas.update(id, updateData);
|
|
306
|
+
spinner.stop();
|
|
307
|
+
if (!response.success || !response.data) {
|
|
308
|
+
printError("Failed to update persona", response.message);
|
|
309
|
+
process.exitCode = 1;
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
if (isJsonOutput()) {
|
|
313
|
+
printJson(response.data);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
const { persona } = response.data;
|
|
317
|
+
printSuccess(`Persona updated: ${persona.name}`);
|
|
318
|
+
} catch (error) {
|
|
319
|
+
spinner.fail("Failed to update persona");
|
|
320
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
321
|
+
printError("Error", message);
|
|
322
|
+
process.exitCode = 1;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
async function handlePersonasDelete(id, options) {
|
|
326
|
+
const sdk = createSdk();
|
|
327
|
+
if (!sdk) return;
|
|
328
|
+
if (!options.yes) {
|
|
329
|
+
printInfo(`About to delete persona: ${id}`);
|
|
330
|
+
printInfo("Use '--yes' flag to skip this confirmation");
|
|
331
|
+
}
|
|
332
|
+
const spinner = ora("Deleting persona...").start();
|
|
333
|
+
try {
|
|
334
|
+
const response = await sdk.personas.delete(id);
|
|
335
|
+
spinner.stop();
|
|
336
|
+
if (!response.success) {
|
|
337
|
+
printError("Failed to delete persona", response.message);
|
|
338
|
+
process.exitCode = 1;
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
if (isJsonOutput()) {
|
|
342
|
+
printJson({ success: true, deleted: id });
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
printSuccess(`Persona deleted: ${id}`);
|
|
346
|
+
} catch (error) {
|
|
347
|
+
spinner.fail("Failed to delete persona");
|
|
348
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
349
|
+
printError("Error", message);
|
|
350
|
+
process.exitCode = 1;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
export {
|
|
354
|
+
createPersonasCommand
|
|
355
|
+
};
|
|
356
|
+
//# sourceMappingURL=personas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/commands/personas.ts"],"sourcesContent":["import { Command } from 'commander';\nimport ora from 'ora';\nimport chalk from 'chalk';\nimport { readFileSync } from 'fs';\nimport type { Persona, CreatePersonaData } from '@chanl-ai/sdk';\nimport { createSdk } from '../utils/sdk-factory.js';\nimport {\n printError,\n printSuccess,\n printInfo,\n printBlank,\n printSimpleTable,\n printLabel,\n isJsonOutput,\n printJson,\n formatDate,\n} from '../utils/output.js';\n\n/**\n * Create the personas command group\n */\nexport function createPersonasCommand(): Command {\n const personas = new Command('personas')\n .description('Manage test personas for scenario simulations')\n .addHelpText(\n 'after',\n `\nWhat are Personas?\n Personas represent simulated callers with specific voice, emotion, and\n behavior characteristics. They are used in scenario testing to simulate\n realistic customer interactions.\n\nQuick Start:\n $ chanl personas list # List all personas\n $ chanl personas get <id> # View persona details\n $ chanl personas create --template # Generate template JSON\n $ chanl personas create -f persona.json # Create from file\n $ chanl personas delete <id> # Delete a persona\n\nPersona Characteristics:\n - Voice: gender, accent, speech style, clarity\n - Emotion: friendly, frustrated, calm, stressed, etc.\n - Behavior: interruption patterns, cooperation level\n - Environment: background noise, connection quality`\n );\n\n // personas list\n personas\n .command('list')\n .description('List all personas')\n .option('-l, --language <lang>', 'Filter by language (english, spanish, portuguese)')\n .option('--active', 'Show only active personas')\n .option('--limit <number>', 'Number of items per page', '20')\n .option('-p, --page <number>', 'Page number', '1')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl personas list # List all personas\n $ chanl personas list --language english # Filter by language\n $ chanl personas list --active # Only active personas\n $ chanl personas list --json # Output as JSON`\n )\n .action(handlePersonasList);\n\n // personas get <id>\n personas\n .command('get <id>')\n .description('Get persona details')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl personas get abc123 # Get persona details\n $ chanl personas get abc123 --json # Output as JSON`\n )\n .action(handlePersonasGet);\n\n // personas create\n personas\n .command('create')\n .description('Create a new persona')\n .option('-f, --file <path>', 'Path to JSON file with persona data')\n .option('--template', 'Output a template JSON file to stdout')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl personas create --template > persona.json # Get template\n $ chanl personas create -f persona.json # Create from file\n\nTemplate contains all required and optional fields with example values.\nEdit the template and use 'create -f' to create your persona.`\n )\n .action(handlePersonasCreate);\n\n // personas update <id>\n personas\n .command('update <id>')\n .description('Update an existing persona')\n .option('-f, --file <path>', 'Path to JSON file with update data')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl personas update abc123 -f updates.json # Update from file\n\nThe update file should contain only the fields you want to change.`\n )\n .action(handlePersonasUpdate);\n\n // personas delete <id>\n personas\n .command('delete <id>')\n .description('Delete a persona')\n .option('-y, --yes', 'Skip confirmation prompt')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl personas delete abc123 # Delete with confirmation\n $ chanl personas delete abc123 --yes # Delete without confirmation`\n )\n .action(handlePersonasDelete);\n\n return personas;\n}\n\n/**\n * Format emotion with color\n */\nfunction formatEmotion(emotion?: string): string {\n const colors: Record<string, (s: string) => string> = {\n friendly: chalk.green,\n calm: chalk.green,\n polite: chalk.green,\n neutral: chalk.gray,\n curious: chalk.cyan,\n distracted: chalk.yellow,\n concerned: chalk.yellow,\n stressed: chalk.yellow,\n annoyed: chalk.red,\n frustrated: chalk.red,\n irritated: chalk.red,\n };\n const colorFn = colors[emotion || ''] || chalk.gray;\n return colorFn(emotion || 'unknown');\n}\n\n/**\n * Get persona template\n */\nfunction getPersonaTemplate(): CreatePersonaData {\n return {\n name: 'Example Persona',\n gender: 'female',\n emotion: 'friendly',\n language: 'english',\n accent: 'american',\n intentClarity: 'very clear',\n speechStyle: 'normal',\n backgroundNoise: false,\n allowInterruptions: true,\n description: 'A helpful and friendly customer',\n backstory:\n 'Sarah is a regular customer who values good service. She is calling about a recent order.',\n variables: {\n accountNumber: '12345',\n orderNumber: 'ORD-2024-001',\n },\n tags: ['customer-service', 'order-inquiry'],\n behavior: {\n personality: 'cooperative',\n emotionalState: 'calm',\n cooperationLevel: 'high',\n patience: 'moderate',\n communicationStyle: 'direct',\n },\n conversationTraits: {\n allowInterruptions: true,\n interruptionFrequency: 'low',\n asksClarifyingQuestions: true,\n repeatsInformation: false,\n goesOffTopic: false,\n },\n environment: {\n backgroundNoise: false,\n noiseType: 'none',\n connectionQuality: 'excellent',\n },\n };\n}\n\n/**\n * Handle personas list command\n */\nasync function handlePersonasList(options: {\n language?: string;\n active?: boolean;\n limit: string;\n page: string;\n}): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Fetching personas...').start();\n\n try {\n const response = await sdk.personas.list({\n language: options.language,\n isActive: options.active,\n limit: parseInt(options.limit, 10),\n page: parseInt(options.page, 10),\n });\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to fetch personas', response.message);\n process.exitCode = 1;\n return;\n }\n\n const { personas, pagination } = response.data;\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n if (personas.length === 0) {\n printInfo('No personas found');\n printInfo(\"Use 'chanl personas create --template' to create one\");\n return;\n }\n\n printBlank();\n printSimpleTable(\n ['ID', 'Name', 'Emotion', 'Language', 'Accent', 'Speech', 'Active'],\n personas.map((p: Persona) => [\n p.id.slice(-12),\n p.name.slice(0, 20),\n formatEmotion(p.emotion),\n p.language || '-',\n p.accent || '-',\n p.speechStyle || '-',\n p.isActive ? chalk.green('yes') : chalk.gray('no'),\n ])\n );\n\n printBlank();\n if (pagination) {\n printInfo(`Total: ${pagination.total} personas (Page ${pagination.page} of ${pagination.pages})`);\n }\n } catch (error) {\n spinner.fail('Failed to fetch personas');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle personas get command\n */\nasync function handlePersonasGet(id: string): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Fetching persona...').start();\n\n try {\n const response = await sdk.personas.get(id);\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to fetch persona', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n const { persona } = response.data;\n printBlank();\n console.log(chalk.bold('Persona Details:'));\n console.log(` ID: ${persona.id}`);\n console.log(` Name: ${persona.name}`);\n console.log(` Gender: ${persona.gender || '-'}`);\n console.log(` Emotion: ${formatEmotion(persona.emotion)}`);\n console.log(` Language: ${persona.language || '-'}`);\n console.log(` Accent: ${persona.accent || '-'}`);\n console.log(` Speech Style: ${persona.speechStyle || '-'}`);\n console.log(` Intent Clarity: ${persona.intentClarity || '-'}`);\n console.log(` Active: ${persona.isActive ? chalk.green('yes') : chalk.gray('no')}`);\n console.log(` Default: ${persona.isDefault ? chalk.cyan('yes') : chalk.gray('no')}`);\n\n if (persona.description) {\n console.log(`\\n Description:`);\n console.log(` ${persona.description}`);\n }\n\n if (persona.backstory) {\n console.log(`\\n Backstory:`);\n console.log(` ${persona.backstory}`);\n }\n\n console.log(`\\n Created: ${formatDate(persona.createdAt)}`);\n console.log(` Updated: ${formatDate(persona.updatedAt)}`);\n printBlank();\n } catch (error) {\n spinner.fail('Failed to fetch persona');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle personas create command\n */\nasync function handlePersonasCreate(options: {\n file?: string;\n template?: boolean;\n}): Promise<void> {\n // Handle template output\n if (options.template) {\n const template = getPersonaTemplate();\n console.log(JSON.stringify(template, null, 2));\n return;\n }\n\n // Require file for actual creation\n if (!options.file) {\n printError('Missing required option', \"Use '-f <file>' to specify persona data or '--template' to get a template\");\n process.exitCode = 1;\n return;\n }\n\n const sdk = createSdk();\n if (!sdk) return;\n\n // Read and parse the file\n let personaData: CreatePersonaData;\n try {\n const content = readFileSync(options.file, 'utf-8');\n personaData = JSON.parse(content);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Failed to read file', message);\n process.exitCode = 1;\n return;\n }\n\n const spinner = ora('Creating persona...').start();\n\n try {\n const response = await sdk.personas.create(personaData);\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to create persona', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n const { persona } = response.data;\n printSuccess(`Persona created: ${persona.name}`);\n printLabel('ID', persona.id);\n } catch (error) {\n spinner.fail('Failed to create persona');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle personas update command\n */\nasync function handlePersonasUpdate(\n id: string,\n options: { file?: string }\n): Promise<void> {\n if (!options.file) {\n printError('Missing required option', \"Use '-f <file>' to specify update data\");\n process.exitCode = 1;\n return;\n }\n\n const sdk = createSdk();\n if (!sdk) return;\n\n // Read and parse the file\n let updateData: Partial<CreatePersonaData>;\n try {\n const content = readFileSync(options.file, 'utf-8');\n updateData = JSON.parse(content);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Failed to read file', message);\n process.exitCode = 1;\n return;\n }\n\n const spinner = ora('Updating persona...').start();\n\n try {\n const response = await sdk.personas.update(id, updateData);\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to update persona', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n const { persona } = response.data;\n printSuccess(`Persona updated: ${persona.name}`);\n } catch (error) {\n spinner.fail('Failed to update persona');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle personas delete command\n */\nasync function handlePersonasDelete(\n id: string,\n options: { yes?: boolean }\n): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n // Confirm deletion unless --yes flag\n if (!options.yes) {\n printInfo(`About to delete persona: ${id}`);\n printInfo(\"Use '--yes' flag to skip this confirmation\");\n // In a real CLI we'd prompt for confirmation\n // For now, just proceed\n }\n\n const spinner = ora('Deleting persona...').start();\n\n try {\n const response = await sdk.personas.delete(id);\n\n spinner.stop();\n\n if (!response.success) {\n printError('Failed to delete persona', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson({ success: true, deleted: id });\n return;\n }\n\n printSuccess(`Persona deleted: ${id}`);\n } catch (error) {\n spinner.fail('Failed to delete persona');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n"],"mappings":"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","names":[]}
|