@toothfairyai/cli 1.1.1 → 1.1.2

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 (3) hide show
  1. package/bin/toothfairy.js +868 -856
  2. package/package.json +1 -1
  3. package/src/api.js +573 -380
package/bin/toothfairy.js CHANGED
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { Command } = require("commander");
4
- const chalk = require("chalk");
5
- const ora = require("ora");
6
- const { table } = require("table");
7
- require("dotenv").config();
8
- const path = require("path");
9
-
10
- const ToothFairyAPI = require("../src/api");
3
+ const { Command } = require('commander');
4
+ const chalk = require('chalk');
5
+ const ora = require('ora');
6
+ const { table } = require('table');
7
+ require('dotenv').config();
8
+ const path = require('path');
9
+
10
+ const ToothFairyAPI = require('../src/api');
11
11
  const {
12
12
  loadConfig,
13
13
  saveConfig,
@@ -15,40 +15,40 @@ const {
15
15
  getConfigPath,
16
16
  validateConfiguration,
17
17
  validateDocumentConfiguration,
18
- } = require("../src/config");
18
+ } = require('../src/config');
19
19
 
20
20
  const program = new Command();
21
21
 
22
22
  program
23
- .name("toothfairy")
23
+ .name('toothfairy')
24
24
  .description(
25
- "ToothFairyAI CLI - Interact with ToothFairyAI agents via command line"
25
+ 'ToothFairyAI CLI - Interact with ToothFairyAI agents via command line'
26
26
  )
27
- .version("1.0.0");
27
+ .version('1.0.0');
28
28
 
29
29
  program
30
- .option("-c, --config <path>", "path to configuration file")
31
- .option("-v, --verbose", "enable verbose logging");
30
+ .option('-c, --config <path>', 'path to configuration file')
31
+ .option('-v, --verbose', 'enable verbose logging');
32
32
 
33
33
  // Configure command
34
34
  program
35
- .command("configure")
36
- .description("Configure ToothFairy CLI credentials and settings")
35
+ .command('configure')
36
+ .description('Configure ToothFairy CLI credentials and settings')
37
37
  .option(
38
- "--base-url <url>",
39
- "ToothFairy API base URL",
40
- "https://api.toothfairyai.com"
38
+ '--base-url <url>',
39
+ 'ToothFairy API base URL',
40
+ 'https://api.toothfairyai.com'
41
41
  )
42
- .option("--ai-url <url>", "ToothFairyAI URL", "https://ai.toothfairyai.com")
42
+ .option('--ai-url <url>', 'ToothFairyAI URL', 'https://ai.toothfairyai.com')
43
43
  .option(
44
- "--ai-stream-url <url>",
45
- "ToothFairyAI Streaming URL",
46
- "https://ais.toothfairyai.com"
44
+ '--ai-stream-url <url>',
45
+ 'ToothFairyAI Streaming URL',
46
+ 'https://ais.toothfairyai.com'
47
47
  )
48
- .option("--api-key <key>", "API key")
49
- .option("--workspace-id <id>", "Workspace ID")
50
- .option("--user-id <id>", "User ID")
51
- .option("--config-path <path>", "Path to save config file")
48
+ .option('--api-key <key>', 'API key')
49
+ .option('--workspace-id <id>', 'Workspace ID')
50
+ .option('--user-id <id>', 'User ID')
51
+ .option('--config-path <path>', 'Path to save config file')
52
52
  .action(async (options) => {
53
53
  try {
54
54
  // Load existing config if it exists, otherwise use defaults
@@ -57,44 +57,44 @@ program
57
57
  existingConfig = loadConfig(options.configPath);
58
58
  } catch (error) {
59
59
  // No existing config, use empty defaults
60
- existingConfig = new ToothFairyConfig("", "", "", "", "", "");
60
+ existingConfig = new ToothFairyConfig('', '', '', '', '', '');
61
61
  }
62
62
 
63
63
  // Merge provided options with existing config
64
64
  const config = new ToothFairyConfig(
65
65
  options.baseUrl ||
66
66
  existingConfig.baseUrl ||
67
- "https://api.toothfairyai.com",
68
- options.aiUrl || existingConfig.aiUrl || "https://ai.toothfairyai.com",
67
+ 'https://api.toothfairyai.com',
68
+ options.aiUrl || existingConfig.aiUrl || 'https://ai.toothfairyai.com',
69
69
  options.aiStreamUrl ||
70
70
  existingConfig.aiStreamUrl ||
71
- "https://ais.toothfairyai.com",
72
- options.apiKey || existingConfig.apiKey || "",
73
- options.workspaceId || existingConfig.workspaceId || "",
74
- options.userId || existingConfig.userId || ""
71
+ 'https://ais.toothfairyai.com',
72
+ options.apiKey || existingConfig.apiKey || '',
73
+ options.workspaceId || existingConfig.workspaceId || '',
74
+ options.userId || existingConfig.userId || ''
75
75
  );
76
76
 
77
77
  // Validate that at least API key and workspace ID are set
78
78
  if (!config.apiKey || !config.workspaceId) {
79
79
  const missing = [];
80
- if (!config.apiKey) missing.push("--api-key");
81
- if (!config.workspaceId) missing.push("--workspace-id");
80
+ if (!config.apiKey) missing.push('--api-key');
81
+ if (!config.workspaceId) missing.push('--workspace-id');
82
82
 
83
83
  console.error(
84
84
  chalk.red(
85
- `Error: Missing required configuration: ${missing.join(" and ")}`
85
+ `Error: Missing required configuration: ${missing.join(' and ')}`
86
86
  )
87
87
  );
88
88
  console.error(
89
89
  chalk.yellow(
90
- "These fields are required for first-time configuration or when not already set."
90
+ 'These fields are required for first-time configuration or when not already set.'
91
91
  )
92
92
  );
93
93
  process.exit(1);
94
94
  }
95
95
 
96
96
  saveConfig(config, options.configPath);
97
- console.log(chalk.green("Configuration saved successfully!"));
97
+ console.log(chalk.green('Configuration saved successfully!'));
98
98
  if (!options.configPath) {
99
99
  console.log(`Config saved to: ${getConfigPath()}`);
100
100
  }
@@ -106,20 +106,21 @@ program
106
106
 
107
107
  // Send command
108
108
  program
109
- .command("send")
110
- .description("Send a message to a ToothFairyAI agent")
111
- .argument("<message>", "message to send")
112
- .requiredOption("--agent-id <id>", "Agent ID to send message to")
113
- .option("--phone-number <number>", "Phone number for SMS channel")
114
- .option("--customer-id <id>", "Customer ID")
115
- .option("--provider-id <id>", "SMS provider ID")
116
- .option("--customer-info <json>", "Customer info as JSON string")
117
- .option("--image <path>", "Path to image file (png, jpg, jpeg, gif, bmp, svg)")
118
- .option("--audio <path>", "Path to audio file (wav, mp3, aac, ogg, flac)")
119
- .option("--video <path>", "Path to video file (mp4, avi, mov, wmv, flv, webm)")
120
- .option("--file <path...>", "Path to document files (max 5)")
121
- .option("-o, --output <format>", "Output format (json|text)", "text")
122
- .option("-v, --verbose", "Show detailed response information")
109
+ .command('send')
110
+ .description('Send a message to a ToothFairyAI agent')
111
+ .argument('<message>', 'message to send')
112
+ .requiredOption('--agent-id <id>', 'Agent ID to send message to')
113
+ .option('--chat-id <id>', 'Chat ID to use existing conversation (optional)')
114
+ .option('--phone-number <number>', 'Phone number for SMS channel')
115
+ .option('--customer-id <id>', 'Customer ID')
116
+ .option('--provider-id <id>', 'SMS provider ID')
117
+ .option('--customer-info <json>', 'Customer info as JSON string')
118
+ .option('--image <path>', 'Path to image file (png, jpg, jpeg, gif, bmp, svg)')
119
+ .option('--audio <path>', 'Path to audio file (wav, mp3, aac, ogg, flac)')
120
+ .option('--video <path>', 'Path to video file (mp4, avi, mov, wmv, flv, webm)')
121
+ .option('--file <path...>', 'Path to document files (max 5)')
122
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
123
+ .option('-v, --verbose', 'Show detailed response information')
123
124
  .action(async (message, options, command) => {
124
125
  try {
125
126
  const globalOptions = command.parent.opts();
@@ -170,41 +171,42 @@ program
170
171
  options.customerId,
171
172
  options.providerId,
172
173
  customerInfo,
173
- attachments
174
+ attachments,
175
+ options.chatId
174
176
  );
175
177
 
176
178
  spinner.stop();
177
179
 
178
- if (options.output === "json") {
180
+ if (options.output === 'json') {
179
181
  console.log(JSON.stringify(response, null, 2));
180
182
  } else {
181
183
  const agentResp = response.agentResponse;
182
184
 
183
185
  if (options.verbose) {
184
186
  // Verbose mode: show all details
185
- console.log(chalk.green.bold("Message sent successfully!"));
187
+ console.log(chalk.green.bold('Message sent successfully!'));
186
188
  console.log();
187
189
 
188
190
  const data = [
189
- ["Field", "Value"],
190
- ["Chat ID", response.chatId],
191
- ["Message ID", response.messageId],
191
+ ['Field', 'Value'],
192
+ ['Chat ID', response.chatId],
193
+ ['Message ID', response.messageId],
192
194
  ];
193
195
 
194
196
  console.log(
195
197
  table(data, {
196
198
  header: {
197
- alignment: "center",
198
- content: "Response Details",
199
+ alignment: 'center',
200
+ content: 'Response Details',
199
201
  },
200
202
  })
201
203
  );
202
204
 
203
205
  // Show full agent response
204
- console.log(chalk.blue.bold("Agent Response (Full):"));
205
- console.log("─".repeat(50));
206
+ console.log(chalk.blue.bold('Agent Response (Full):'));
207
+ console.log('─'.repeat(50));
206
208
  console.log(JSON.stringify(agentResp, null, 2));
207
- console.log("─".repeat(50));
209
+ console.log('─'.repeat(50));
208
210
  } else {
209
211
  // Default mode: show only the clean agent text
210
212
  if (agentResp.contents && agentResp.contents.content) {
@@ -217,7 +219,7 @@ program
217
219
  // Fallback if no recognizable text format
218
220
  console.log(
219
221
  chalk.yellow(
220
- "No text response found. Use --verbose for full details."
222
+ 'No text response found. Use --verbose for full details.'
221
223
  )
222
224
  );
223
225
  }
@@ -231,23 +233,24 @@ program
231
233
 
232
234
  // Send Stream command
233
235
  program
234
- .command("send-stream")
236
+ .command('send-stream')
235
237
  .description(
236
- "Send a message to a ToothFairyAI agent with real-time streaming response"
238
+ 'Send a message to a ToothFairyAI agent with real-time streaming response'
237
239
  )
238
- .argument("<message>", "message to send")
239
- .requiredOption("--agent-id <id>", "Agent ID to send message to")
240
- .option("--phone-number <number>", "Phone number for SMS channel")
241
- .option("--customer-id <id>", "Customer ID")
242
- .option("--provider-id <id>", "SMS provider ID")
243
- .option("--customer-info <json>", "Customer info as JSON string")
240
+ .argument('<message>', 'message to send')
241
+ .requiredOption('--agent-id <id>', 'Agent ID to send message to')
242
+ .option('--chat-id <id>', 'Chat ID to use existing conversation (optional)')
243
+ .option('--phone-number <number>', 'Phone number for SMS channel')
244
+ .option('--customer-id <id>', 'Customer ID')
245
+ .option('--provider-id <id>', 'SMS provider ID')
246
+ .option('--customer-info <json>', 'Customer info as JSON string')
244
247
  .option('--image <path>', 'Path to image file (PNG, max 1)')
245
248
  .option('--audio <path>', 'Path to audio file (WAV, max 1)')
246
249
  .option('--video <path>', 'Path to video file (MP4, max 1)')
247
250
  .option('--file <path>', 'Path to file (max 5, can be used multiple times)', (value, previous) => previous.concat([value]), [])
248
- .option("-o, --output <format>", "Output format (json|text)", "text")
249
- .option("-v, --verbose", "Show detailed streaming information")
250
- .option("--show-progress", "Show agent processing status updates")
251
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
252
+ .option('-v, --verbose', 'Show detailed streaming information')
253
+ .option('--show-progress', 'Show agent processing status updates')
251
254
  .action(async (message, options, command) => {
252
255
  /*
253
256
  STREAMING BEHAVIOR EXPLAINED:
@@ -289,7 +292,7 @@ program
289
292
  try {
290
293
  customerInfo = JSON.parse(options.customerInfo);
291
294
  } catch (error) {
292
- console.error(chalk.red("Invalid JSON in customer-info"));
295
+ console.error(chalk.red('Invalid JSON in customer-info'));
293
296
  process.exit(1);
294
297
  }
295
298
  }
@@ -316,7 +319,7 @@ program
316
319
  console.log();
317
320
 
318
321
  // Initialize variables for streaming
319
- let currentText = "";
322
+ let currentText = '';
320
323
  let finalResponse = null;
321
324
  let processingStatus = null;
322
325
  let lastUpdateTime = 0;
@@ -324,52 +327,52 @@ program
324
327
 
325
328
  const mapStateWithLabel = (state) => {
326
329
  switch (state) {
327
- case "data_processing_completed":
328
- return "šŸ“Š **Retrieving data**";
329
- case "tools_processing_completed":
330
- return "šŸ› ļø **Choosing tools**";
331
- case "replying":
332
- return "🧚 **Responding**";
333
- case "main_generation_completed":
334
- return "✨ **Generation completed**";
335
- case "memory_updated":
336
- return "šŸ’¾ Memory updated";
337
- case "updating_memory":
338
- return "šŸ’¾ Updating memory...";
339
- case "init":
340
- return "šŸš€ Initializing...";
341
- case "initial_setup_completed":
342
- return "āœ… Setup completed";
343
- case "image_analysis_in_progress":
344
- return "šŸ–¼ļø Analyzing image...";
345
- case "video_analysis_in_progress":
346
- return "šŸŽ„ Analyzing video...";
347
- case "audio_analysis_in_progress":
348
- return "šŸŽµ Analyzing audio...";
349
- case "image_generation_in_progress":
350
- return "šŸŽØ Generating image...";
351
- case "video_generation_in_progress":
352
- return "šŸŽ¬ Generating video...";
353
- case "3D_model_generation_in_progress":
354
- return "šŸ—ļø Creating 3D model...";
355
- case "code_generation_in_progress":
356
- return "šŸ’» Generating code...";
357
- case "code_execution_in_progress":
358
- return "⚔ Executing code...";
359
- case "internet_search_in_progress":
360
- return "šŸ” Searching internet...";
361
- case "planning_in_progress":
362
- return "šŸ—ŗļø Planning response...";
363
- case "handed_off_to_human":
364
- return "šŸ‘¤ Handed off to human";
365
- case "completed":
366
- return "šŸŽ‰ Completed";
330
+ case 'data_processing_completed':
331
+ return 'šŸ“Š **Retrieving data**';
332
+ case 'tools_processing_completed':
333
+ return 'šŸ› ļø **Choosing tools**';
334
+ case 'replying':
335
+ return '🧚 **Responding**';
336
+ case 'main_generation_completed':
337
+ return '✨ **Generation completed**';
338
+ case 'memory_updated':
339
+ return 'šŸ’¾ Memory updated';
340
+ case 'updating_memory':
341
+ return 'šŸ’¾ Updating memory...';
342
+ case 'init':
343
+ return 'šŸš€ Initializing...';
344
+ case 'initial_setup_completed':
345
+ return 'āœ… Setup completed';
346
+ case 'image_analysis_in_progress':
347
+ return 'šŸ–¼ļø Analyzing image...';
348
+ case 'video_analysis_in_progress':
349
+ return 'šŸŽ„ Analyzing video...';
350
+ case 'audio_analysis_in_progress':
351
+ return 'šŸŽµ Analyzing audio...';
352
+ case 'image_generation_in_progress':
353
+ return 'šŸŽØ Generating image...';
354
+ case 'video_generation_in_progress':
355
+ return 'šŸŽ¬ Generating video...';
356
+ case '3D_model_generation_in_progress':
357
+ return 'šŸ—ļø Creating 3D model...';
358
+ case 'code_generation_in_progress':
359
+ return 'šŸ’» Generating code...';
360
+ case 'code_execution_in_progress':
361
+ return '⚔ Executing code...';
362
+ case 'internet_search_in_progress':
363
+ return 'šŸ” Searching internet...';
364
+ case 'planning_in_progress':
365
+ return 'šŸ—ŗļø Planning response...';
366
+ case 'handed_off_to_human':
367
+ return 'šŸ‘¤ Handed off to human';
368
+ case 'completed':
369
+ return 'šŸŽ‰ Completed';
367
370
  default:
368
371
  return `šŸ“Š ${state}`;
369
372
  }
370
373
  };
371
374
 
372
- if (options.output === "json") {
375
+ if (options.output === 'json') {
373
376
  // JSON mode: collect all events and output at the end
374
377
  const allEvents = [];
375
378
 
@@ -383,15 +386,17 @@ program
383
386
  (eventType, eventData) => {
384
387
  allEvents.push({ event_type: eventType, event_data: eventData });
385
388
 
386
- if (eventType === "error") {
389
+ if (eventType === 'error') {
387
390
  console.error(
388
391
  chalk.red(
389
- `Streaming error: ${eventData.message || "Unknown error"}`
392
+ `Streaming error: ${eventData.message || 'Unknown error'}`
390
393
  )
391
394
  );
392
395
  }
393
396
  },
394
- attachments
397
+ attachments,
398
+ options.showProgress,
399
+ options.chatId
395
400
  );
396
401
 
397
402
  console.log(JSON.stringify(allEvents, null, 2));
@@ -400,14 +405,14 @@ program
400
405
  let currentSpinner = null;
401
406
 
402
407
  // Function to update display with status filtering
403
- const updateDisplay = (text, agentStatus, type = "response") => {
408
+ const updateDisplay = (text, agentStatus, type = 'response') => {
404
409
  if (currentSpinner) {
405
410
  currentSpinner.stop();
406
411
  currentSpinner = null;
407
412
  }
408
413
 
409
414
  // Only show text when agent is actually replying
410
- if (text && type === "response" && agentStatus === "replying") {
415
+ if (text && type === 'response' && agentStatus === 'replying') {
411
416
  const trimmedText = text.trim();
412
417
  const now = Date.now();
413
418
 
@@ -420,7 +425,7 @@ program
420
425
  ) {
421
426
  if (!hasStartedResponse) {
422
427
  // First time showing response - print header on new line
423
- console.log(chalk.green("🧚 Responding"));
428
+ console.log(chalk.green('🧚 Responding'));
424
429
  hasStartedResponse = true;
425
430
  }
426
431
  // Stream new text content on new line
@@ -453,25 +458,30 @@ program
453
458
  );
454
459
  }
455
460
 
461
+ // Skip processing sse_event types to avoid duplicates - they're for raw debugging only
462
+ if (eventType === 'sse_event') {
463
+ return;
464
+ }
465
+
456
466
  // Handle connection status events
457
- if (eventData.status === "connected") {
467
+ if (eventData.status === 'connected') {
458
468
  if (options.showProgress) {
459
- console.log(chalk.green("šŸ”— Connected to streaming server"));
469
+ console.log(chalk.green('šŸ”— Connected to streaming server'));
460
470
  }
461
471
  return;
462
472
  }
463
473
 
464
- if (eventData.status === "complete") {
474
+ if (eventData.status === 'complete') {
465
475
  if (options.showProgress) {
466
476
  console.log(
467
- chalk.green("\nšŸŽ‰ Stream completed successfully!")
477
+ chalk.green('\nšŸŽ‰ Stream completed successfully!')
468
478
  );
469
479
  }
470
480
  return;
471
481
  }
472
482
 
473
483
  // Handle message events
474
- if (eventData.type === "message") {
484
+ if (eventData.type === 'message') {
475
485
  let metadata = {};
476
486
  let agentStatus = null;
477
487
 
@@ -498,12 +508,12 @@ program
498
508
  }
499
509
 
500
510
  // Handle progressive text streaming
501
- if (eventData.text && agentStatus === "replying") {
502
- updateDisplay(eventData.text, agentStatus, "response");
511
+ if (eventData.text && agentStatus === 'replying') {
512
+ updateDisplay(eventData.text, agentStatus, 'response');
503
513
  }
504
514
 
505
515
  // Handle fulfilled status (final response)
506
- if (eventData.status === "fulfilled") {
516
+ if (eventData.status === 'fulfilled') {
507
517
  finalResponse = eventData;
508
518
  if (currentText) {
509
519
  // Clean final display with magic wand emoji
@@ -511,7 +521,7 @@ program
511
521
  currentSpinner.stop();
512
522
  currentSpinner = null;
513
523
  }
514
- console.log(chalk.blue("šŸŖ„ Response complete"));
524
+ console.log(chalk.blue('šŸŖ„ Response complete'));
515
525
  }
516
526
  }
517
527
 
@@ -522,7 +532,7 @@ program
522
532
  ) {
523
533
  // These are attachment events - could show notification if needed
524
534
  if (options.verbose) {
525
- console.log(chalk.dim("\nšŸ“Ž Attachments processed"));
535
+ console.log(chalk.dim('\nšŸ“Ž Attachments processed'));
526
536
  }
527
537
  }
528
538
 
@@ -530,15 +540,15 @@ program
530
540
  // Function execution metadata
531
541
  if (options.verbose) {
532
542
  console.log(
533
- chalk.dim("\nāš™ļø Function execution metadata received")
543
+ chalk.dim('\nāš™ļø Function execution metadata received')
534
544
  );
535
545
  }
536
546
  }
537
547
  }
538
548
 
539
549
  // Handle errors
540
- if (eventType === "error") {
541
- const errorMsg = eventData.message || "Unknown streaming error";
550
+ if (eventType === 'error') {
551
+ const errorMsg = eventData.message || 'Unknown streaming error';
542
552
  if (currentSpinner) {
543
553
  currentSpinner.stop();
544
554
  }
@@ -546,7 +556,9 @@ program
546
556
  process.exit(1);
547
557
  }
548
558
  },
549
- attachments
559
+ attachments,
560
+ options.showProgress,
561
+ options.chatId
550
562
  );
551
563
 
552
564
  // Clean up spinner after streaming completes
@@ -558,48 +570,48 @@ program
558
570
 
559
571
  if (options.verbose && finalResponse) {
560
572
  // Show final response metadata in verbose mode
561
- console.log(chalk.cyan.bold("\nšŸ“Š Final Response Metadata"));
562
- console.log("─".repeat(50));
573
+ console.log(chalk.cyan.bold('\nšŸ“Š Final Response Metadata'));
574
+ console.log('─'.repeat(50));
563
575
 
564
576
  // Parse and display metadata from the final response
565
577
  if (finalResponse.metadata) {
566
578
  try {
567
579
  const metadata = JSON.parse(finalResponse.metadata);
568
580
  for (const [key, value] of Object.entries(metadata)) {
569
- if (key === "agent_processing_status") {
581
+ if (key === 'agent_processing_status') {
570
582
  console.log(chalk.cyan(`${key}:`), chalk.green(value));
571
- } else if (key === "duration") {
583
+ } else if (key === 'duration') {
572
584
  console.log(
573
585
  chalk.cyan(`${key}:`),
574
586
  chalk.yellow(`${value}s`)
575
587
  );
576
- } else if (key === "sources" && Array.isArray(value)) {
588
+ } else if (key === 'sources' && Array.isArray(value)) {
577
589
  console.log(
578
590
  chalk.cyan(`${key}:`),
579
- value.length > 0 ? value.join(", ") : "None"
591
+ value.length > 0 ? value.join(', ') : 'None'
580
592
  );
581
593
  } else {
582
594
  console.log(chalk.cyan(`${key}:`), String(value));
583
595
  }
584
596
  }
585
597
  } catch (e) {
586
- console.log(chalk.red("Could not parse metadata"));
598
+ console.log(chalk.red('Could not parse metadata'));
587
599
  }
588
600
  }
589
601
 
590
602
  // Show additional response fields
591
603
  if (finalResponse.message_id) {
592
- console.log(chalk.cyan("message_id:"), finalResponse.message_id);
604
+ console.log(chalk.cyan('message_id:'), finalResponse.message_id);
593
605
  }
594
606
  if (finalResponse.t_text_summary) {
595
- console.log(chalk.cyan("summary:"), finalResponse.t_text_summary);
607
+ console.log(chalk.cyan('summary:'), finalResponse.t_text_summary);
596
608
  }
597
609
 
598
- console.log("─".repeat(50));
610
+ console.log('─'.repeat(50));
599
611
  }
600
612
 
601
613
  if (!currentText) {
602
- console.log(chalk.yellow("No text response received from agent."));
614
+ console.log(chalk.yellow('No text response received from agent.'));
603
615
  }
604
616
  } catch (streamError) {
605
617
  if (currentSpinner) {
@@ -616,22 +628,22 @@ program
616
628
 
617
629
  // Search command
618
630
  program
619
- .command("search")
620
- .description("Search for documents in the knowledge hub")
621
- .argument("<query>", "search query text")
631
+ .command('search')
632
+ .description('Search for documents in the knowledge hub')
633
+ .argument('<query>', 'search query text')
622
634
  .option(
623
- "-k, --top-k <number>",
624
- "Number of documents to retrieve (1-50)",
625
- "10"
635
+ '-k, --top-k <number>',
636
+ 'Number of documents to retrieve (1-50)',
637
+ '10'
626
638
  )
627
639
  .option(
628
- "--status <status>",
629
- "Filter by document status (published|suspended)"
640
+ '--status <status>',
641
+ 'Filter by document status (published|suspended)'
630
642
  )
631
- .option("--document-id <id>", "Search within specific document ID")
632
- .option("--topics <topics>", "Comma-separated topic IDs to filter by")
633
- .option("-o, --output <format>", "Output format (json|text)", "text")
634
- .option("-v, --verbose", "Show detailed search information")
643
+ .option('--document-id <id>', 'Search within specific document ID')
644
+ .option('--topics <topics>', 'Comma-separated topic IDs to filter by')
645
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
646
+ .option('-v, --verbose', 'Show detailed search information')
635
647
  .action(async (query, options, command) => {
636
648
  try {
637
649
  const globalOptions = command.parent.opts();
@@ -651,7 +663,7 @@ program
651
663
  const topK = parseInt(options.topK);
652
664
  if (isNaN(topK) || topK < 1 || topK > 50) {
653
665
  console.error(
654
- chalk.red("Error: --top-k must be a number between 1 and 50")
666
+ chalk.red('Error: --top-k must be a number between 1 and 50')
655
667
  );
656
668
  process.exit(1);
657
669
  }
@@ -659,7 +671,7 @@ program
659
671
  // Build metadata filters
660
672
  const metadata = {};
661
673
  if (options.status) {
662
- if (!["published", "suspended"].includes(options.status)) {
674
+ if (!['published', 'suspended'].includes(options.status)) {
663
675
  console.error(
664
676
  chalk.red(
665
677
  'Error: --status must be either "published" or "suspended"'
@@ -674,7 +686,7 @@ program
674
686
  }
675
687
  if (options.topics) {
676
688
  const topicList = options.topics
677
- .split(",")
689
+ .split(',')
678
690
  .map((t) => t.trim())
679
691
  .filter((t) => t);
680
692
  if (topicList.length > 0) {
@@ -682,7 +694,7 @@ program
682
694
  }
683
695
  }
684
696
 
685
- const spinner = ora("Searching knowledge hub...").start();
697
+ const spinner = ora('Searching knowledge hub...').start();
686
698
 
687
699
  const results = await api.searchDocuments(
688
700
  query,
@@ -692,7 +704,7 @@ program
692
704
 
693
705
  spinner.stop();
694
706
 
695
- if (options.output === "json") {
707
+ if (options.output === 'json') {
696
708
  console.log(JSON.stringify(results, null, 2));
697
709
  } else {
698
710
  // Handle different response formats - results might be array or dict
@@ -701,22 +713,22 @@ program
701
713
  : results.results || [];
702
714
 
703
715
  if (!documents || documents.length === 0) {
704
- console.log(chalk.yellow("No documents found for your query"));
716
+ console.log(chalk.yellow('No documents found for your query'));
705
717
  return;
706
718
  }
707
719
 
708
720
  console.log(chalk.green.bold(`Found ${documents.length} document(s)`));
709
- console.log("=".repeat(50));
721
+ console.log('='.repeat(50));
710
722
 
711
723
  documents.forEach((doc) => {
712
724
  const score = doc.cosinesim || 0;
713
- const docId = doc.doc_id || doc.chunk_id || "N/A";
725
+ const docId = doc.doc_id || doc.chunk_id || 'N/A';
714
726
 
715
727
  // Extract text content directly from document
716
- const textContent = doc.raw_text || "No content available";
717
- const docStatus = doc.status || "unknown";
728
+ const textContent = doc.raw_text || 'No content available';
729
+ const docStatus = doc.status || 'unknown';
718
730
  const docTopics = doc.topics || [];
719
- const docTitle = doc.title || "Untitled";
731
+ const docTitle = doc.title || 'Untitled';
720
732
 
721
733
  console.log(
722
734
  chalk.cyan.bold(`\n${docTitle}`),
@@ -726,16 +738,16 @@ program
726
738
  if (options.verbose) {
727
739
  // Verbose mode: show all details
728
740
  const data = [
729
- ["Field", "Value"],
730
- ["Document ID", docId],
731
- ["Title", docTitle],
732
- ["Relevance Score", score.toFixed(4)],
733
- ["Status", docStatus],
734
- ["Topics", docTopics.length > 0 ? docTopics.join(", ") : "None"],
741
+ ['Field', 'Value'],
742
+ ['Document ID', docId],
743
+ ['Title', docTitle],
744
+ ['Relevance Score', score.toFixed(4)],
745
+ ['Status', docStatus],
746
+ ['Topics', docTopics.length > 0 ? docTopics.join(', ') : 'None'],
735
747
  [
736
- "Content Preview",
748
+ 'Content Preview',
737
749
  textContent.length > 200
738
- ? textContent.substring(0, 200) + "..."
750
+ ? textContent.substring(0, 200) + '...'
739
751
  : textContent,
740
752
  ],
741
753
  ];
@@ -743,13 +755,13 @@ program
743
755
  console.log(table(data));
744
756
  } else {
745
757
  // Default mode: show clean content
746
- console.log("─".repeat(50));
758
+ console.log('─'.repeat(50));
747
759
  const displayContent =
748
760
  textContent.length > 500
749
- ? textContent.substring(0, 500) + "..."
761
+ ? textContent.substring(0, 500) + '...'
750
762
  : textContent;
751
763
  console.log(displayContent);
752
- console.log("─".repeat(50));
764
+ console.log('─'.repeat(50));
753
765
  }
754
766
  });
755
767
  }
@@ -761,9 +773,9 @@ program
761
773
 
762
774
  // Chats command
763
775
  program
764
- .command("chats")
765
- .description("List all chats in the workspace")
766
- .option("-o, --output <format>", "Output format (json|text)", "text")
776
+ .command('chats')
777
+ .description('List all chats in the workspace')
778
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
767
779
  .action(async (options, command) => {
768
780
  try {
769
781
  const globalOptions = command.parent.opts();
@@ -779,18 +791,18 @@ program
779
791
  globalOptions.verbose || options.verbose
780
792
  );
781
793
 
782
- const spinner = ora("Fetching chats...").start();
794
+ const spinner = ora('Fetching chats...').start();
783
795
  const chatsData = await api.getAllChats();
784
796
  spinner.stop();
785
797
 
786
- if (options.output === "json") {
798
+ if (options.output === 'json') {
787
799
  console.log(JSON.stringify(chatsData, null, 2));
788
800
  } else {
789
801
  if (
790
802
  !chatsData ||
791
803
  (Array.isArray(chatsData) && chatsData.length === 0)
792
804
  ) {
793
- console.log(chalk.yellow("No chats found"));
805
+ console.log(chalk.yellow('No chats found'));
794
806
  return;
795
807
  }
796
808
 
@@ -798,22 +810,22 @@ program
798
810
  ? chatsData
799
811
  : chatsData.items || [];
800
812
 
801
- const data = [["Chat ID", "Name", "Customer ID", "Created"]];
813
+ const data = [['Chat ID', 'Name', 'Customer ID', 'Created']];
802
814
 
803
815
  chatList.forEach((chat) => {
804
816
  data.push([
805
- chat.id || "N/A",
806
- chat.name || "N/A",
807
- chat.customerId || "N/A",
808
- chat.createdAt || "N/A",
817
+ chat.id || 'N/A',
818
+ chat.name || 'N/A',
819
+ chat.customerId || 'N/A',
820
+ chat.createdAt || 'N/A',
809
821
  ]);
810
822
  });
811
823
 
812
824
  console.log(
813
825
  table(data, {
814
826
  header: {
815
- alignment: "center",
816
- content: "Workspace Chats",
827
+ alignment: 'center',
828
+ content: 'Workspace Chats',
817
829
  },
818
830
  })
819
831
  );
@@ -826,10 +838,10 @@ program
826
838
 
827
839
  // Chat command (get specific chat)
828
840
  program
829
- .command("chat")
830
- .description("Get details of a specific chat")
831
- .argument("<chat-id>", "Chat ID to retrieve")
832
- .option("-o, --output <format>", "Output format (json|text)", "text")
841
+ .command('chat')
842
+ .description('Get details of a specific chat')
843
+ .argument('<chat-id>', 'Chat ID to retrieve')
844
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
833
845
  .action(async (chatId, options, command) => {
834
846
  try {
835
847
  const globalOptions = command.parent.opts();
@@ -849,17 +861,17 @@ program
849
861
  const chatData = await api.getChat(chatId);
850
862
  spinner.stop();
851
863
 
852
- if (options.output === "json") {
864
+ if (options.output === 'json') {
853
865
  console.log(JSON.stringify(chatData, null, 2));
854
866
  } else {
855
- console.log(chalk.green.bold("Chat Details"));
867
+ console.log(chalk.green.bold('Chat Details'));
856
868
  console.log();
857
869
 
858
- const data = [["Field", "Value"]];
870
+ const data = [['Field', 'Value']];
859
871
 
860
872
  Object.entries(chatData).forEach(([key, value]) => {
861
873
  let displayValue = value;
862
- if (typeof value === "object" && value !== null) {
874
+ if (typeof value === 'object' && value !== null) {
863
875
  displayValue = JSON.stringify(value, null, 2);
864
876
  }
865
877
  data.push([key, String(displayValue)]);
@@ -932,32 +944,32 @@ program
932
944
 
933
945
  // Config show command
934
946
  program
935
- .command("config-show")
936
- .description("Show current configuration")
947
+ .command('config-show')
948
+ .description('Show current configuration')
937
949
  .action(async (options, command) => {
938
950
  try {
939
951
  const globalOptions = command.parent.opts();
940
952
  const config = loadConfig(globalOptions.config);
941
953
 
942
954
  const data = [
943
- ["Setting", "Value"],
944
- ["Base URL", config.baseUrl],
945
- ["AI URL", config.aiUrl],
955
+ ['Setting', 'Value'],
956
+ ['Base URL', config.baseUrl],
957
+ ['AI URL', config.aiUrl],
946
958
  [
947
- "API Key",
959
+ 'API Key',
948
960
  config.apiKey
949
- ? `${"*".repeat(20)}...${config.apiKey.slice(-4)}`
950
- : "Not set",
961
+ ? `${'*'.repeat(20)}...${config.apiKey.slice(-4)}`
962
+ : 'Not set',
951
963
  ],
952
- ["Workspace ID", config.workspaceId],
953
- ["User ID", config.userId ? config.userId : "Not set"],
964
+ ['Workspace ID', config.workspaceId],
965
+ ['User ID', config.userId ? config.userId : 'Not set'],
954
966
  ];
955
967
 
956
968
  console.log(
957
969
  table(data, {
958
970
  header: {
959
- alignment: "center",
960
- content: "Current Configuration",
971
+ alignment: 'center',
972
+ content: 'Current Configuration',
961
973
  },
962
974
  })
963
975
  );
@@ -969,22 +981,22 @@ program
969
981
 
970
982
  // Create document command
971
983
  program
972
- .command("create-doc")
984
+ .command('create-doc')
973
985
  .description(
974
- "Create a document from a file path or URL with automatic type detection"
986
+ 'Create a document from a file path or URL with automatic type detection'
975
987
  )
976
- .argument("<file-path-or-url>", "Path to file or URL to create document from")
988
+ .argument('<file-path-or-url>', 'Path to file or URL to create document from')
977
989
  .option(
978
- "--user-id <id>",
979
- "User ID (optional, uses configured value if not provided)"
990
+ '--user-id <id>',
991
+ 'User ID (optional, uses configured value if not provided)'
980
992
  )
981
- .option("--title <title>", "Document title (defaults to filename or URL)")
982
- .option("--folder-id <id>", "Folder ID (defaults to 'mrcRoot')", "mrcRoot")
983
- .option("--topics <topics>", "Comma-separated topic IDs")
984
- .option("--status <status>", "Document status (draft|published)", "published")
985
- .option("--scope <scope>", "Document scope")
986
- .option("-o, --output <format>", "Output format (json|text)", "text")
987
- .option("-v, --verbose", "Show detailed creation information")
993
+ .option('--title <title>', 'Document title (defaults to filename or URL)')
994
+ .option('--folder-id <id>', 'Folder ID (defaults to \'mrcRoot\')', 'mrcRoot')
995
+ .option('--topics <topics>', 'Comma-separated topic IDs')
996
+ .option('--status <status>', 'Document status (draft|published)', 'published')
997
+ .option('--scope <scope>', 'Document scope')
998
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
999
+ .option('-v, --verbose', 'Show detailed creation information')
988
1000
  .action(async (filePathOrUrl, options, command) => {
989
1001
  try {
990
1002
  const globalOptions = command.parent.opts();
@@ -1004,13 +1016,13 @@ program
1004
1016
  let topics = [];
1005
1017
  if (options.topics) {
1006
1018
  topics = options.topics
1007
- .split(",")
1019
+ .split(',')
1008
1020
  .map((t) => t.trim())
1009
1021
  .filter((t) => t);
1010
1022
  }
1011
1023
 
1012
1024
  // Validate status
1013
- if (options.status && !["draft", "published"].includes(options.status)) {
1025
+ if (options.status && !['draft', 'published'].includes(options.status)) {
1014
1026
  console.error(
1015
1027
  chalk.red('Error: --status must be either "draft" or "published"')
1016
1028
  );
@@ -1019,10 +1031,10 @@ program
1019
1031
 
1020
1032
  console.log(chalk.cyan(`Creating document from ${filePathOrUrl}...`));
1021
1033
  if (options.verbose) {
1022
- console.log(chalk.dim(`Title: ${options.title || "Auto-detected"}`));
1034
+ console.log(chalk.dim(`Title: ${options.title || 'Auto-detected'}`));
1023
1035
  console.log(chalk.dim(`Folder ID: ${options.folderId}`));
1024
1036
  console.log(
1025
- chalk.dim(`Topics: ${topics.length > 0 ? topics.join(", ") : "None"}`)
1037
+ chalk.dim(`Topics: ${topics.length > 0 ? topics.join(', ') : 'None'}`)
1026
1038
  );
1027
1039
  console.log(chalk.dim(`Status: ${options.status}`));
1028
1040
  if (options.scope) {
@@ -1030,7 +1042,7 @@ program
1030
1042
  }
1031
1043
  }
1032
1044
 
1033
- const spinner = ora("Creating document...").start();
1045
+ const spinner = ora('Creating document...').start();
1034
1046
 
1035
1047
  // Use provided userId or fall back to configured userId
1036
1048
  const userId = options.userId || config.userId;
@@ -1047,10 +1059,10 @@ program
1047
1059
 
1048
1060
  spinner.stop();
1049
1061
 
1050
- if (options.output === "json") {
1062
+ if (options.output === 'json') {
1051
1063
  console.log(JSON.stringify(result, null, 2));
1052
1064
  } else {
1053
- console.log(chalk.green.bold("āœ… Document created successfully!"));
1065
+ console.log(chalk.green.bold('āœ… Document created successfully!'));
1054
1066
  console.log();
1055
1067
 
1056
1068
  // Extract document info from result
@@ -1060,14 +1072,14 @@ program
1060
1072
 
1061
1073
  documents.forEach((doc, index) => {
1062
1074
  const data = [
1063
- ["Field", "Value"],
1064
- ["Document ID", doc.id || "N/A"],
1065
- ["Title", doc.title || "N/A"],
1066
- ["Type", doc.type || "N/A"],
1067
- ["Status", doc.status || "N/A"],
1068
- ["Folder ID", doc.folderid || doc.folder_id || "N/A"],
1069
- ["External Path", doc.external_path || "N/A"],
1070
- ["Created At", doc.created_at || doc.createdAt || "N/A"],
1075
+ ['Field', 'Value'],
1076
+ ['Document ID', doc.id || 'N/A'],
1077
+ ['Title', doc.title || 'N/A'],
1078
+ ['Type', doc.type || 'N/A'],
1079
+ ['Status', doc.status || 'N/A'],
1080
+ ['Folder ID', doc.folderid || doc.folder_id || 'N/A'],
1081
+ ['External Path', doc.external_path || 'N/A'],
1082
+ ['Created At', doc.created_at || doc.createdAt || 'N/A'],
1071
1083
  ];
1072
1084
 
1073
1085
  if (documents.length > 1) {
@@ -1077,14 +1089,14 @@ program
1077
1089
  console.log(
1078
1090
  table(data, {
1079
1091
  header: {
1080
- alignment: "center",
1081
- content: "Document Details",
1092
+ alignment: 'center',
1093
+ content: 'Document Details',
1082
1094
  },
1083
1095
  })
1084
1096
  );
1085
1097
 
1086
1098
  if (doc.topics && doc.topics.length > 0) {
1087
- console.log(chalk.cyan(`Topics: ${doc.topics.join(", ")}`));
1099
+ console.log(chalk.cyan(`Topics: ${doc.topics.join(', ')}`));
1088
1100
  }
1089
1101
  });
1090
1102
  }
@@ -1096,15 +1108,15 @@ program
1096
1108
 
1097
1109
  // Update document command
1098
1110
  program
1099
- .command("update-doc")
1100
- .description("Update an existing document")
1101
- .argument("<document-id>", "ID of the document to update")
1102
- .option("--type <type>", "Document type")
1103
- .option("--rawtext <text>", "Raw text content")
1104
- .option("--title <title>", "Document title")
1105
- .option("--status <status>", "Document status (draft|published)")
1106
- .option("-o, --output <format>", "Output format (json|text)", "text")
1107
- .option("-v, --verbose", "Show detailed update information")
1111
+ .command('update-doc')
1112
+ .description('Update an existing document')
1113
+ .argument('<document-id>', 'ID of the document to update')
1114
+ .option('--type <type>', 'Document type')
1115
+ .option('--rawtext <text>', 'Raw text content')
1116
+ .option('--title <title>', 'Document title')
1117
+ .option('--status <status>', 'Document status (draft|published)')
1118
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
1119
+ .option('-v, --verbose', 'Show detailed update information')
1108
1120
  .action(async (documentId, options, command) => {
1109
1121
  try {
1110
1122
  const globalOptions = command.parent.opts();
@@ -1126,7 +1138,7 @@ program
1126
1138
  if (options.rawtext) fields.rawtext = options.rawtext;
1127
1139
  if (options.title) fields.title = options.title;
1128
1140
  if (options.status) {
1129
- if (!["draft", "published"].includes(options.status)) {
1141
+ if (!['draft', 'published'].includes(options.status)) {
1130
1142
  console.error(
1131
1143
  chalk.red('Error: --status must be either "draft" or "published"')
1132
1144
  );
@@ -1137,10 +1149,10 @@ program
1137
1149
 
1138
1150
  if (Object.keys(fields).length === 0) {
1139
1151
  console.error(
1140
- chalk.red("Error: At least one field must be provided to update")
1152
+ chalk.red('Error: At least one field must be provided to update')
1141
1153
  );
1142
1154
  console.error(
1143
- chalk.yellow("Available fields: --type, --rawtext, --title, --status")
1155
+ chalk.yellow('Available fields: --type, --rawtext, --title, --status')
1144
1156
  );
1145
1157
  process.exit(1);
1146
1158
  }
@@ -1148,7 +1160,7 @@ program
1148
1160
  console.log(chalk.cyan(`Updating document ${documentId}...`));
1149
1161
  if (options.verbose) {
1150
1162
  console.log(
1151
- chalk.dim(`Fields to update: ${Object.keys(fields).join(", ")}`)
1163
+ chalk.dim(`Fields to update: ${Object.keys(fields).join(', ')}`)
1152
1164
  );
1153
1165
  }
1154
1166
 
@@ -1157,41 +1169,41 @@ program
1157
1169
  if (!userId) {
1158
1170
  console.error(
1159
1171
  chalk.red(
1160
- "Error: User ID is required. Configure it with 'toothfairy configure --user-id YOUR_USER_ID'"
1172
+ 'Error: User ID is required. Configure it with \'toothfairy configure --user-id YOUR_USER_ID\''
1161
1173
  )
1162
1174
  );
1163
1175
  process.exit(1);
1164
1176
  }
1165
1177
 
1166
- const spinner = ora("Updating document...").start();
1178
+ const spinner = ora('Updating document...').start();
1167
1179
 
1168
1180
  const result = await api.updateDocument(documentId, userId, fields);
1169
1181
 
1170
1182
  spinner.stop();
1171
1183
 
1172
- if (options.output === "json") {
1184
+ if (options.output === 'json') {
1173
1185
  console.log(JSON.stringify(result, null, 2));
1174
1186
  } else {
1175
- console.log(chalk.green.bold("āœ… Document updated successfully!"));
1187
+ console.log(chalk.green.bold('āœ… Document updated successfully!'));
1176
1188
  console.log();
1177
1189
 
1178
1190
  const data = [
1179
- ["Field", "Value"],
1180
- ["Document ID", documentId],
1181
- ["Updated Fields", Object.keys(fields).join(", ")],
1191
+ ['Field', 'Value'],
1192
+ ['Document ID', documentId],
1193
+ ['Updated Fields', Object.keys(fields).join(', ')],
1182
1194
  ];
1183
1195
 
1184
1196
  console.log(
1185
1197
  table(data, {
1186
1198
  header: {
1187
- alignment: "center",
1188
- content: "Update Details",
1199
+ alignment: 'center',
1200
+ content: 'Update Details',
1189
1201
  },
1190
1202
  })
1191
1203
  );
1192
1204
 
1193
1205
  if (options.verbose && result) {
1194
- console.log(chalk.dim("\nAPI Response:"));
1206
+ console.log(chalk.dim('\nAPI Response:'));
1195
1207
  console.log(chalk.dim(JSON.stringify(result, null, 2)));
1196
1208
  }
1197
1209
  }
@@ -1203,11 +1215,11 @@ program
1203
1215
 
1204
1216
  // Get document command
1205
1217
  program
1206
- .command("get-doc")
1207
- .description("Get details of a specific document")
1208
- .argument("<document-id>", "ID of the document to retrieve")
1209
- .option("-o, --output <format>", "Output format (json|text)", "text")
1210
- .option("-v, --verbose", "Show detailed document information")
1218
+ .command('get-doc')
1219
+ .description('Get details of a specific document')
1220
+ .argument('<document-id>', 'ID of the document to retrieve')
1221
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
1222
+ .option('-v, --verbose', 'Show detailed document information')
1211
1223
  .action(async (documentId, options, command) => {
1212
1224
  try {
1213
1225
  const globalOptions = command.parent.opts();
@@ -1225,58 +1237,58 @@ program
1225
1237
 
1226
1238
  console.log(chalk.cyan(`Retrieving document ${documentId}...`));
1227
1239
 
1228
- const spinner = ora("Fetching document...").start();
1240
+ const spinner = ora('Fetching document...').start();
1229
1241
 
1230
1242
  const result = await api.getDocument(documentId);
1231
1243
 
1232
1244
  spinner.stop();
1233
1245
 
1234
- if (options.output === "json") {
1246
+ if (options.output === 'json') {
1235
1247
  console.log(JSON.stringify(result, null, 2));
1236
1248
  } else {
1237
- console.log(chalk.green.bold("šŸ“„ Document Details"));
1249
+ console.log(chalk.green.bold('šŸ“„ Document Details'));
1238
1250
  console.log();
1239
1251
 
1240
1252
  // Handle different response structures
1241
1253
  const doc = result.data[0] || result;
1242
1254
 
1243
1255
  const data = [
1244
- ["Field", "Value"],
1245
- ["Document ID", doc.id || documentId],
1246
- ["Title", doc.title || "N/A"],
1247
- ["Type", doc.type || "N/A"],
1248
- ["Status", doc.status || "N/A"],
1249
- ["Folder ID", doc.folderid || doc.folder_id || "N/A"],
1250
- ["Created At", doc.created_at || doc.createdAt || "N/A"],
1251
- ["Updated At", doc.updated_at || doc.updatedAt || "N/A"],
1256
+ ['Field', 'Value'],
1257
+ ['Document ID', doc.id || documentId],
1258
+ ['Title', doc.title || 'N/A'],
1259
+ ['Type', doc.type || 'N/A'],
1260
+ ['Status', doc.status || 'N/A'],
1261
+ ['Folder ID', doc.folderid || doc.folder_id || 'N/A'],
1262
+ ['Created At', doc.created_at || doc.createdAt || 'N/A'],
1263
+ ['Updated At', doc.updated_at || doc.updatedAt || 'N/A'],
1252
1264
  ];
1253
1265
 
1254
1266
  if (doc.external_path) {
1255
- data.push(["External Path", doc.external_path]);
1267
+ data.push(['External Path', doc.external_path]);
1256
1268
  }
1257
1269
 
1258
1270
  console.log(
1259
1271
  table(data, {
1260
1272
  header: {
1261
- alignment: "center",
1262
- content: "Document Information",
1273
+ alignment: 'center',
1274
+ content: 'Document Information',
1263
1275
  },
1264
1276
  })
1265
1277
  );
1266
1278
 
1267
1279
  if (doc.topics && doc.topics.length > 0) {
1268
- console.log(chalk.cyan(`\nTopics: ${doc.topics.join(", ")}`));
1280
+ console.log(chalk.cyan(`\nTopics: ${doc.topics.join(', ')}`));
1269
1281
  }
1270
1282
 
1271
1283
  if (doc.rawtext && options.verbose) {
1272
- console.log(chalk.blue.bold("\nšŸ“ Raw Text Content:"));
1273
- console.log("─".repeat(50));
1284
+ console.log(chalk.blue.bold('\nšŸ“ Raw Text Content:'));
1285
+ console.log('─'.repeat(50));
1274
1286
  const displayText =
1275
1287
  doc.rawtext.length > 500
1276
- ? doc.rawtext.substring(0, 500) + "..."
1288
+ ? doc.rawtext.substring(0, 500) + '...'
1277
1289
  : doc.rawtext;
1278
1290
  console.log(displayText);
1279
- console.log("─".repeat(50));
1291
+ console.log('─'.repeat(50));
1280
1292
  }
1281
1293
  }
1282
1294
  } catch (error) {
@@ -1287,12 +1299,12 @@ program
1287
1299
 
1288
1300
  // Delete document command
1289
1301
  program
1290
- .command("delete-doc")
1291
- .description("Delete a document")
1292
- .argument("<document-id>", "ID of the document to delete")
1293
- .option("--confirm", "Skip confirmation prompt")
1294
- .option("-o, --output <format>", "Output format (json|text)", "text")
1295
- .option("-v, --verbose", "Show detailed deletion information")
1302
+ .command('delete-doc')
1303
+ .description('Delete a document')
1304
+ .argument('<document-id>', 'ID of the document to delete')
1305
+ .option('--confirm', 'Skip confirmation prompt')
1306
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
1307
+ .option('-v, --verbose', 'Show detailed deletion information')
1296
1308
  .action(async (documentId, options, command) => {
1297
1309
  try {
1298
1310
  const globalOptions = command.parent.opts();
@@ -1310,7 +1322,7 @@ program
1310
1322
 
1311
1323
  // Confirmation prompt (unless --confirm flag is used)
1312
1324
  if (!options.confirm) {
1313
- const readline = require("readline");
1325
+ const readline = require('readline');
1314
1326
  const rl = readline.createInterface({
1315
1327
  input: process.stdin,
1316
1328
  output: process.stdout,
@@ -1327,43 +1339,43 @@ program
1327
1339
 
1328
1340
  rl.close();
1329
1341
 
1330
- if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
1331
- console.log(chalk.gray("Deletion cancelled."));
1342
+ if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
1343
+ console.log(chalk.gray('Deletion cancelled.'));
1332
1344
  process.exit(0);
1333
1345
  }
1334
1346
  }
1335
1347
 
1336
1348
  console.log(chalk.cyan(`Deleting document ${documentId}...`));
1337
1349
 
1338
- const spinner = ora("Deleting document...").start();
1350
+ const spinner = ora('Deleting document...').start();
1339
1351
 
1340
1352
  const result = await api.deleteDocument(documentId);
1341
1353
 
1342
1354
  spinner.stop();
1343
1355
 
1344
- if (options.output === "json") {
1356
+ if (options.output === 'json') {
1345
1357
  console.log(JSON.stringify(result, null, 2));
1346
1358
  } else {
1347
- console.log(chalk.green.bold("āœ… Document deleted successfully!"));
1359
+ console.log(chalk.green.bold('āœ… Document deleted successfully!'));
1348
1360
  console.log();
1349
1361
 
1350
1362
  const data = [
1351
- ["Field", "Value"],
1352
- ["Document ID", documentId],
1353
- ["Status", "Deleted"],
1363
+ ['Field', 'Value'],
1364
+ ['Document ID', documentId],
1365
+ ['Status', 'Deleted'],
1354
1366
  ];
1355
1367
 
1356
1368
  console.log(
1357
1369
  table(data, {
1358
1370
  header: {
1359
- alignment: "center",
1360
- content: "Deletion Details",
1371
+ alignment: 'center',
1372
+ content: 'Deletion Details',
1361
1373
  },
1362
1374
  })
1363
1375
  );
1364
1376
 
1365
1377
  if (options.verbose && result) {
1366
- console.log(chalk.dim("\nAPI Response:"));
1378
+ console.log(chalk.dim('\nAPI Response:'));
1367
1379
  console.log(chalk.dim(JSON.stringify(result, null, 2)));
1368
1380
  }
1369
1381
  }
@@ -1375,19 +1387,19 @@ program
1375
1387
 
1376
1388
  // Upload file command
1377
1389
  program
1378
- .command("upload")
1379
- .description("Upload a file to ToothFairy workspace")
1380
- .argument("<file-path>", "Path to file to upload")
1390
+ .command('upload')
1391
+ .description('Upload a file to ToothFairy workspace')
1392
+ .argument('<file-path>', 'Path to file to upload')
1381
1393
  .option(
1382
- "--import-type <type>",
1383
- "Import type (optional, auto-detected from extension)"
1394
+ '--import-type <type>',
1395
+ 'Import type (optional, auto-detected from extension)'
1384
1396
  )
1385
1397
  .option(
1386
- "--content-type <type>",
1387
- "Content type (optional, auto-detected from extension)"
1398
+ '--content-type <type>',
1399
+ 'Content type (optional, auto-detected from extension)'
1388
1400
  )
1389
- .option("-o, --output <format>", "Output format (json|text)", "text")
1390
- .option("-v, --verbose", "Show detailed upload information")
1401
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
1402
+ .option('-v, --verbose', 'Show detailed upload information')
1391
1403
  .action(async (filePath, options, command) => {
1392
1404
  try {
1393
1405
  const globalOptions = command.parent.opts();
@@ -1409,54 +1421,54 @@ program
1409
1421
 
1410
1422
  // Validate file extension
1411
1423
  const validExtensions = [
1412
- "pdf",
1413
- "docx",
1414
- "txt",
1415
- "csv",
1416
- "md",
1417
- "html",
1418
- "xlsx",
1419
- "pptx",
1420
- "ppt",
1421
- "png",
1422
- "jpg",
1423
- "jpeg",
1424
- "gif",
1425
- "bmp",
1426
- "svg",
1427
- "java",
1428
- "py",
1429
- "yaml",
1430
- "yml",
1431
- "sql",
1432
- "sh",
1433
- "php",
1434
- "js",
1435
- "ts",
1436
- "tsx",
1437
- "jsx",
1438
- "csharp",
1439
- "rb",
1440
- "jsonl",
1441
- "wav",
1442
- "mp3",
1443
- "aac",
1444
- "ogg",
1445
- "flac",
1446
- "mp4",
1447
- "avi",
1448
- "mov",
1449
- "wmv",
1450
- "flv",
1451
- "webm",
1452
- "json",
1424
+ 'pdf',
1425
+ 'docx',
1426
+ 'txt',
1427
+ 'csv',
1428
+ 'md',
1429
+ 'html',
1430
+ 'xlsx',
1431
+ 'pptx',
1432
+ 'ppt',
1433
+ 'png',
1434
+ 'jpg',
1435
+ 'jpeg',
1436
+ 'gif',
1437
+ 'bmp',
1438
+ 'svg',
1439
+ 'java',
1440
+ 'py',
1441
+ 'yaml',
1442
+ 'yml',
1443
+ 'sql',
1444
+ 'sh',
1445
+ 'php',
1446
+ 'js',
1447
+ 'ts',
1448
+ 'tsx',
1449
+ 'jsx',
1450
+ 'csharp',
1451
+ 'rb',
1452
+ 'jsonl',
1453
+ 'wav',
1454
+ 'mp3',
1455
+ 'aac',
1456
+ 'ogg',
1457
+ 'flac',
1458
+ 'mp4',
1459
+ 'avi',
1460
+ 'mov',
1461
+ 'wmv',
1462
+ 'flv',
1463
+ 'webm',
1464
+ 'json',
1453
1465
  ];
1454
1466
 
1455
1467
  const ext = path.extname(resolvedPath).toLowerCase().slice(1);
1456
1468
  if (!validExtensions.includes(ext)) {
1457
1469
  console.error(chalk.red(`Error: Unsupported file extension '.${ext}'`));
1458
1470
  console.error(
1459
- chalk.yellow(`Supported extensions: ${validExtensions.join(", ")}`)
1471
+ chalk.yellow(`Supported extensions: ${validExtensions.join(', ')}`)
1460
1472
  );
1461
1473
  process.exit(1);
1462
1474
  }
@@ -1466,7 +1478,7 @@ program
1466
1478
  console.log(chalk.dim(`Local path: ${resolvedPath}`));
1467
1479
  }
1468
1480
 
1469
- let currentSpinner = ora("Preparing upload...").start();
1481
+ let currentSpinner = ora('Preparing upload...').start();
1470
1482
  let lastProgress = 0;
1471
1483
 
1472
1484
  const result = await api.uploadFile(
@@ -1494,33 +1506,33 @@ program
1494
1506
  currentSpinner.stop();
1495
1507
  }
1496
1508
 
1497
- if (options.output === "json") {
1509
+ if (options.output === 'json') {
1498
1510
  console.log(JSON.stringify(result, null, 2));
1499
1511
  } else {
1500
- console.log(chalk.green.bold("āœ… Upload completed successfully!"));
1512
+ console.log(chalk.green.bold('āœ… Upload completed successfully!'));
1501
1513
  console.log();
1502
1514
 
1503
1515
  const data = [
1504
- ["Field", "Value"],
1505
- ["Original File", result.originalFilename],
1506
- ["Sanitized File", result.sanitizedFilename],
1507
- ["Import Type", result.importType],
1508
- ["Content Type", result.contentType],
1509
- ["Size", `${result.sizeInMB.toFixed(2)}MB`],
1510
- ["Download Name", result.filename],
1516
+ ['Field', 'Value'],
1517
+ ['Original File', result.originalFilename],
1518
+ ['Sanitized File', result.sanitizedFilename],
1519
+ ['Import Type', result.importType],
1520
+ ['Content Type', result.contentType],
1521
+ ['Size', `${result.sizeInMB.toFixed(2)}MB`],
1522
+ ['Download Name', result.filename],
1511
1523
  ];
1512
1524
 
1513
1525
  console.log(
1514
1526
  table(data, {
1515
1527
  header: {
1516
- alignment: "center",
1517
- content: "Upload Details",
1528
+ alignment: 'center',
1529
+ content: 'Upload Details',
1518
1530
  },
1519
1531
  })
1520
1532
  );
1521
1533
 
1522
1534
  if (options.verbose) {
1523
- console.log(chalk.dim(`File Key: ${result.fileKey || "N/A"}`));
1535
+ console.log(chalk.dim(`File Key: ${result.fileKey || 'N/A'}`));
1524
1536
  console.log(chalk.dim(`Upload URL: ${result.uploadURL}`));
1525
1537
  }
1526
1538
  }
@@ -1532,24 +1544,24 @@ program
1532
1544
 
1533
1545
  // Download file command
1534
1546
  program
1535
- .command("download")
1536
- .description("Download a file from ToothFairy workspace")
1547
+ .command('download')
1548
+ .description('Download a file from ToothFairy workspace')
1537
1549
  .requiredOption(
1538
- "--filename <name>",
1539
- "Name of the file to download (from upload response)"
1550
+ '--filename <name>',
1551
+ 'Name of the file to download (from upload response)'
1540
1552
  )
1541
1553
  .option(
1542
- "--workspace-id <id>",
1543
- "Workspace ID (uses config default if not specified)"
1554
+ '--workspace-id <id>',
1555
+ 'Workspace ID (uses config default if not specified)'
1544
1556
  )
1545
- .option("--context <context>", "Download context (default: pdf)", "pdf")
1546
- .option("--output-dir <dir>", "Output directory", "./downloads")
1557
+ .option('--context <context>', 'Download context (default: pdf)', 'pdf')
1558
+ .option('--output-dir <dir>', 'Output directory', './downloads')
1547
1559
  .option(
1548
- "--output-name <name>",
1549
- "Output filename (defaults to original filename)"
1560
+ '--output-name <name>',
1561
+ 'Output filename (defaults to original filename)'
1550
1562
  )
1551
- .option("-o, --output <format>", "Output format (json|text)", "text")
1552
- .option("-v, --verbose", "Show detailed download information")
1563
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
1564
+ .option('-v, --verbose', 'Show detailed download information')
1553
1565
  .action(async (options, command) => {
1554
1566
  try {
1555
1567
  const globalOptions = command.parent.opts();
@@ -1579,7 +1591,7 @@ program
1579
1591
  console.log(chalk.dim(`Output path: ${outputPath}`));
1580
1592
  }
1581
1593
 
1582
- let currentSpinner = ora("Preparing download...").start();
1594
+ let currentSpinner = ora('Preparing download...').start();
1583
1595
  let lastProgress = 0;
1584
1596
 
1585
1597
  const result = await api.downloadFile(
@@ -1607,25 +1619,25 @@ program
1607
1619
  currentSpinner.stop();
1608
1620
  }
1609
1621
 
1610
- if (options.output === "json") {
1622
+ if (options.output === 'json') {
1611
1623
  console.log(JSON.stringify(result, null, 2));
1612
1624
  } else {
1613
- console.log(chalk.green.bold("āœ… Download completed successfully!"));
1625
+ console.log(chalk.green.bold('āœ… Download completed successfully!'));
1614
1626
  console.log();
1615
1627
 
1616
1628
  const data = [
1617
- ["Field", "Value"],
1618
- ["File", options.filename],
1619
- ["Size", `${result.sizeInMB}MB`],
1620
- ["Output Path", result.outputPath],
1621
- ["Workspace ID", workspaceId],
1629
+ ['Field', 'Value'],
1630
+ ['File', options.filename],
1631
+ ['Size', `${result.sizeInMB}MB`],
1632
+ ['Output Path', result.outputPath],
1633
+ ['Workspace ID', workspaceId],
1622
1634
  ];
1623
1635
 
1624
1636
  console.log(
1625
1637
  table(data, {
1626
1638
  header: {
1627
- alignment: "center",
1628
- content: "Download Details",
1639
+ alignment: 'center',
1640
+ content: 'Download Details',
1629
1641
  },
1630
1642
  })
1631
1643
  );
@@ -1638,20 +1650,20 @@ program
1638
1650
 
1639
1651
  // Create entity command
1640
1652
  program
1641
- .command("create-entity")
1642
- .description("Create a new entity with specified type")
1643
- .argument("<label>", "Entity label")
1653
+ .command('create-entity')
1654
+ .description('Create a new entity with specified type')
1655
+ .argument('<label>', 'Entity label')
1644
1656
  .option(
1645
- "--user-id <id>",
1646
- "User ID (optional, uses configured value if not provided)"
1657
+ '--user-id <id>',
1658
+ 'User ID (optional, uses configured value if not provided)'
1647
1659
  )
1648
- .option("--type <type>", "Entity type (intent|ner|topic)", "topic")
1649
- .option("--description <desc>", "Entity description")
1650
- .option("--emoji <emoji>", "Entity emoji")
1651
- .option("--parent-entity <id>", "Parent entity ID")
1652
- .option("--background-color <color>", "Background color (hex format)")
1653
- .option("-o, --output <format>", "Output format (json|text)", "text")
1654
- .option("-v, --verbose", "Show detailed creation information")
1660
+ .option('--type <type>', 'Entity type (intent|ner|topic)', 'topic')
1661
+ .option('--description <desc>', 'Entity description')
1662
+ .option('--emoji <emoji>', 'Entity emoji')
1663
+ .option('--parent-entity <id>', 'Parent entity ID')
1664
+ .option('--background-color <color>', 'Background color (hex format)')
1665
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
1666
+ .option('-v, --verbose', 'Show detailed creation information')
1655
1667
  .action(async (label, options, command) => {
1656
1668
  try {
1657
1669
  const globalOptions = command.parent.opts();
@@ -1659,12 +1671,12 @@ program
1659
1671
  validateDocumentConfiguration(config);
1660
1672
 
1661
1673
  // Validate entity type
1662
- const validTypes = ["intent", "ner", "topic"];
1674
+ const validTypes = ['intent', 'ner', 'topic'];
1663
1675
  if (!validTypes.includes(options.type)) {
1664
1676
  console.error(
1665
1677
  chalk.red(`Error: Invalid entity type '${options.type}'`)
1666
1678
  );
1667
- console.error(chalk.yellow(`Valid types: ${validTypes.join(", ")}`));
1679
+ console.error(chalk.yellow(`Valid types: ${validTypes.join(', ')}`));
1668
1680
  process.exit(1);
1669
1681
  }
1670
1682
 
@@ -1674,7 +1686,7 @@ program
1674
1686
  if (!hexColorRegex.test(options.backgroundColor)) {
1675
1687
  console.error(
1676
1688
  chalk.red(
1677
- "Error: Background color must be in hex format (e.g., #FF5733)"
1689
+ 'Error: Background color must be in hex format (e.g., #FF5733)'
1678
1690
  )
1679
1691
  );
1680
1692
  process.exit(1);
@@ -1696,7 +1708,7 @@ program
1696
1708
  chalk.cyan(`Creating entity "${label}" of type "${options.type}"...`)
1697
1709
  );
1698
1710
 
1699
- const spinner = ora("Creating entity...").start();
1711
+ const spinner = ora('Creating entity...').start();
1700
1712
 
1701
1713
  const result = await api.createEntity(
1702
1714
  userId,
@@ -1710,36 +1722,36 @@ program
1710
1722
 
1711
1723
  spinner.stop();
1712
1724
 
1713
- if (options.output === "json") {
1725
+ if (options.output === 'json') {
1714
1726
  console.log(JSON.stringify(result, null, 2));
1715
1727
  } else {
1716
- console.log(chalk.green.bold("āœ… Entity created successfully!"));
1728
+ console.log(chalk.green.bold('āœ… Entity created successfully!'));
1717
1729
  console.log();
1718
1730
 
1719
1731
  const data = [
1720
- ["Field", "Value"],
1721
- ["ID", result.id || "N/A"],
1722
- ["Label", result.label],
1723
- ["Type", result.type],
1724
- ["Description", result.description || "N/A"],
1725
- ["Emoji", result.emoji || "N/A"],
1726
- ["Parent Entity", result.parentEntity || "N/A"],
1727
- ["Background Color", result.backgroundColor || "N/A"],
1728
- ["Workspace ID", result.workspaceid],
1729
- ["Created By", result.createdBy],
1732
+ ['Field', 'Value'],
1733
+ ['ID', result.id || 'N/A'],
1734
+ ['Label', result.label],
1735
+ ['Type', result.type],
1736
+ ['Description', result.description || 'N/A'],
1737
+ ['Emoji', result.emoji || 'N/A'],
1738
+ ['Parent Entity', result.parentEntity || 'N/A'],
1739
+ ['Background Color', result.backgroundColor || 'N/A'],
1740
+ ['Workspace ID', result.workspaceid],
1741
+ ['Created By', result.createdBy],
1730
1742
  ];
1731
1743
 
1732
1744
  console.log(
1733
1745
  table(data, {
1734
1746
  header: {
1735
- alignment: "center",
1736
- content: "Entity Details",
1747
+ alignment: 'center',
1748
+ content: 'Entity Details',
1737
1749
  },
1738
1750
  })
1739
1751
  );
1740
1752
 
1741
1753
  if (options.verbose && result) {
1742
- console.log(chalk.dim("\nAPI Response:"));
1754
+ console.log(chalk.dim('\nAPI Response:'));
1743
1755
  console.log(chalk.dim(JSON.stringify(result, null, 2)));
1744
1756
  }
1745
1757
  }
@@ -1751,17 +1763,17 @@ program
1751
1763
 
1752
1764
  // Update entity command
1753
1765
  program
1754
- .command("update-entity")
1755
- .description("Update an existing entity")
1756
- .argument("<id>", "Entity ID")
1757
- .option("--label <label>", "New entity label")
1758
- .option("--type <type>", "New entity type (intent|ner|topic)")
1759
- .option("--description <desc>", "New entity description")
1760
- .option("--emoji <emoji>", "New entity emoji")
1761
- .option("--parent-entity <id>", "New parent entity ID")
1762
- .option("--background-color <color>", "New background color (hex format)")
1763
- .option("-o, --output <format>", "Output format (json|text)", "text")
1764
- .option("-v, --verbose", "Show detailed update information")
1766
+ .command('update-entity')
1767
+ .description('Update an existing entity')
1768
+ .argument('<id>', 'Entity ID')
1769
+ .option('--label <label>', 'New entity label')
1770
+ .option('--type <type>', 'New entity type (intent|ner|topic)')
1771
+ .option('--description <desc>', 'New entity description')
1772
+ .option('--emoji <emoji>', 'New entity emoji')
1773
+ .option('--parent-entity <id>', 'New parent entity ID')
1774
+ .option('--background-color <color>', 'New background color (hex format)')
1775
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
1776
+ .option('-v, --verbose', 'Show detailed update information')
1765
1777
  .action(async (entityId, options, command) => {
1766
1778
  try {
1767
1779
  const globalOptions = command.parent.opts();
@@ -1770,12 +1782,12 @@ program
1770
1782
 
1771
1783
  // Validate entity type if provided
1772
1784
  if (options.type) {
1773
- const validTypes = ["intent", "ner", "topic"];
1785
+ const validTypes = ['intent', 'ner', 'topic'];
1774
1786
  if (!validTypes.includes(options.type)) {
1775
1787
  console.error(
1776
1788
  chalk.red(`Error: Invalid entity type '${options.type}'`)
1777
1789
  );
1778
- console.error(chalk.yellow(`Valid types: ${validTypes.join(", ")}`));
1790
+ console.error(chalk.yellow(`Valid types: ${validTypes.join(', ')}`));
1779
1791
  process.exit(1);
1780
1792
  }
1781
1793
  }
@@ -1786,7 +1798,7 @@ program
1786
1798
  if (!hexColorRegex.test(options.backgroundColor)) {
1787
1799
  console.error(
1788
1800
  chalk.red(
1789
- "Error: Background color must be in hex format (e.g., #FF5733)"
1801
+ 'Error: Background color must be in hex format (e.g., #FF5733)'
1790
1802
  )
1791
1803
  );
1792
1804
  process.exit(1);
@@ -1804,7 +1816,7 @@ program
1804
1816
 
1805
1817
  console.log(chalk.cyan(`Updating entity ${entityId}...`));
1806
1818
 
1807
- const spinner = ora("Updating entity...").start();
1819
+ const spinner = ora('Updating entity...').start();
1808
1820
 
1809
1821
  const result = await api.updateEntity(
1810
1822
  entityId,
@@ -1818,34 +1830,34 @@ program
1818
1830
 
1819
1831
  spinner.stop();
1820
1832
 
1821
- if (options.output === "json") {
1833
+ if (options.output === 'json') {
1822
1834
  console.log(JSON.stringify(result, null, 2));
1823
1835
  } else {
1824
- console.log(chalk.green.bold("āœ… Entity updated successfully!"));
1836
+ console.log(chalk.green.bold('āœ… Entity updated successfully!'));
1825
1837
  console.log();
1826
1838
 
1827
1839
  const data = [
1828
- ["Field", "Value"],
1829
- ["ID", result.id || entityId],
1830
- ["Label", result.label || "N/A"],
1831
- ["Type", result.type || "N/A"],
1832
- ["Description", result.description || "N/A"],
1833
- ["Emoji", result.emoji || "N/A"],
1834
- ["Parent Entity", result.parentEntity || "N/A"],
1835
- ["Background Color", result.backgroundColor || "N/A"],
1840
+ ['Field', 'Value'],
1841
+ ['ID', result.id || entityId],
1842
+ ['Label', result.label || 'N/A'],
1843
+ ['Type', result.type || 'N/A'],
1844
+ ['Description', result.description || 'N/A'],
1845
+ ['Emoji', result.emoji || 'N/A'],
1846
+ ['Parent Entity', result.parentEntity || 'N/A'],
1847
+ ['Background Color', result.backgroundColor || 'N/A'],
1836
1848
  ];
1837
1849
 
1838
1850
  console.log(
1839
1851
  table(data, {
1840
1852
  header: {
1841
- alignment: "center",
1842
- content: "Updated Entity Details",
1853
+ alignment: 'center',
1854
+ content: 'Updated Entity Details',
1843
1855
  },
1844
1856
  })
1845
1857
  );
1846
1858
 
1847
1859
  if (options.verbose && result) {
1848
- console.log(chalk.dim("\nAPI Response:"));
1860
+ console.log(chalk.dim('\nAPI Response:'));
1849
1861
  console.log(chalk.dim(JSON.stringify(result, null, 2)));
1850
1862
  }
1851
1863
  }
@@ -1857,11 +1869,11 @@ program
1857
1869
 
1858
1870
  // Get entity command
1859
1871
  program
1860
- .command("get-entity")
1861
- .description("Get details of a specific entity")
1862
- .argument("<id>", "Entity ID")
1863
- .option("-o, --output <format>", "Output format (json|text)", "text")
1864
- .option("-v, --verbose", "Show detailed information")
1872
+ .command('get-entity')
1873
+ .description('Get details of a specific entity')
1874
+ .argument('<id>', 'Entity ID')
1875
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
1876
+ .option('-v, --verbose', 'Show detailed information')
1865
1877
  .action(async (entityId, options, command) => {
1866
1878
  try {
1867
1879
  const globalOptions = command.parent.opts();
@@ -1879,23 +1891,23 @@ program
1879
1891
 
1880
1892
  console.log(chalk.cyan(`Fetching entity ${entityId}...`));
1881
1893
 
1882
- const spinner = ora("Fetching entity...").start();
1894
+ const spinner = ora('Fetching entity...').start();
1883
1895
 
1884
1896
  const entityData = await api.getEntity(entityId);
1885
1897
 
1886
1898
  spinner.stop();
1887
1899
 
1888
- if (options.output === "json") {
1900
+ if (options.output === 'json') {
1889
1901
  console.log(JSON.stringify(entityData, null, 2));
1890
1902
  } else {
1891
- console.log(chalk.green.bold("Entity Details"));
1903
+ console.log(chalk.green.bold('Entity Details'));
1892
1904
  console.log();
1893
1905
 
1894
- const data = [["Field", "Value"]];
1906
+ const data = [['Field', 'Value']];
1895
1907
 
1896
1908
  Object.entries(entityData).forEach(([key, value]) => {
1897
1909
  let displayValue = value;
1898
- if (typeof value === "object" && value !== null) {
1910
+ if (typeof value === 'object' && value !== null) {
1899
1911
  displayValue = JSON.stringify(value, null, 2);
1900
1912
  }
1901
1913
  data.push([key, String(displayValue)]);
@@ -1911,12 +1923,12 @@ program
1911
1923
 
1912
1924
  // Delete entity command
1913
1925
  program
1914
- .command("delete-entity")
1915
- .description("Delete an entity")
1916
- .argument("<id>", "Entity ID")
1917
- .option("--confirm", "Skip confirmation prompt")
1918
- .option("-o, --output <format>", "Output format (json|text)", "text")
1919
- .option("-v, --verbose", "Show detailed deletion information")
1926
+ .command('delete-entity')
1927
+ .description('Delete an entity')
1928
+ .argument('<id>', 'Entity ID')
1929
+ .option('--confirm', 'Skip confirmation prompt')
1930
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
1931
+ .option('-v, --verbose', 'Show detailed deletion information')
1920
1932
  .action(async (entityId, options, command) => {
1921
1933
  try {
1922
1934
  const globalOptions = command.parent.opts();
@@ -1934,7 +1946,7 @@ program
1934
1946
 
1935
1947
  // Confirmation prompt (unless --confirm flag is used)
1936
1948
  if (!options.confirm) {
1937
- const readline = require("readline");
1949
+ const readline = require('readline');
1938
1950
  const rl = readline.createInterface({
1939
1951
  input: process.stdin,
1940
1952
  output: process.stdout,
@@ -1951,43 +1963,43 @@ program
1951
1963
 
1952
1964
  rl.close();
1953
1965
 
1954
- if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
1955
- console.log(chalk.gray("Deletion cancelled."));
1966
+ if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
1967
+ console.log(chalk.gray('Deletion cancelled.'));
1956
1968
  process.exit(0);
1957
1969
  }
1958
1970
  }
1959
1971
 
1960
1972
  console.log(chalk.cyan(`Deleting entity ${entityId}...`));
1961
1973
 
1962
- const spinner = ora("Deleting entity...").start();
1974
+ const spinner = ora('Deleting entity...').start();
1963
1975
 
1964
1976
  const result = await api.deleteEntity(entityId);
1965
1977
 
1966
1978
  spinner.stop();
1967
1979
 
1968
- if (options.output === "json") {
1980
+ if (options.output === 'json') {
1969
1981
  console.log(JSON.stringify(result, null, 2));
1970
1982
  } else {
1971
- console.log(chalk.green.bold("āœ… Entity deleted successfully!"));
1983
+ console.log(chalk.green.bold('āœ… Entity deleted successfully!'));
1972
1984
  console.log();
1973
1985
 
1974
1986
  const data = [
1975
- ["Field", "Value"],
1976
- ["Entity ID", entityId],
1977
- ["Status", "Deleted"],
1987
+ ['Field', 'Value'],
1988
+ ['Entity ID', entityId],
1989
+ ['Status', 'Deleted'],
1978
1990
  ];
1979
1991
 
1980
1992
  console.log(
1981
1993
  table(data, {
1982
1994
  header: {
1983
- alignment: "center",
1984
- content: "Deletion Details",
1995
+ alignment: 'center',
1996
+ content: 'Deletion Details',
1985
1997
  },
1986
1998
  })
1987
1999
  );
1988
2000
 
1989
2001
  if (options.verbose && result) {
1990
- console.log(chalk.dim("\nAPI Response:"));
2002
+ console.log(chalk.dim('\nAPI Response:'));
1991
2003
  console.log(chalk.dim(JSON.stringify(result, null, 2)));
1992
2004
  }
1993
2005
  }
@@ -1999,13 +2011,13 @@ program
1999
2011
 
2000
2012
  // List entities command
2001
2013
  program
2002
- .command("list-entities")
2003
- .description("List all entities in the workspace")
2004
- .option("--type <type>", "Filter by entity type (intent|ner|topic)")
2005
- .option("--limit <number>", "Maximum number of entities to return", "50")
2006
- .option("--offset <number>", "Number of entities to skip", "0")
2007
- .option("-o, --output <format>", "Output format (json|text)", "text")
2008
- .option("-v, --verbose", "Show detailed information")
2014
+ .command('list-entities')
2015
+ .description('List all entities in the workspace')
2016
+ .option('--type <type>', 'Filter by entity type (intent|ner|topic)')
2017
+ .option('--limit <number>', 'Maximum number of entities to return', '50')
2018
+ .option('--offset <number>', 'Number of entities to skip', '0')
2019
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
2020
+ .option('-v, --verbose', 'Show detailed information')
2009
2021
  .action(async (options, command) => {
2010
2022
  try {
2011
2023
  const globalOptions = command.parent.opts();
@@ -2014,12 +2026,12 @@ program
2014
2026
 
2015
2027
  // Validate entity type filter if provided
2016
2028
  if (options.type) {
2017
- const validTypes = ["intent", "ner", "topic"];
2029
+ const validTypes = ['intent', 'ner', 'topic'];
2018
2030
  if (!validTypes.includes(options.type)) {
2019
2031
  console.error(
2020
2032
  chalk.red(`Error: Invalid entity type '${options.type}'`)
2021
2033
  );
2022
- console.error(chalk.yellow(`Valid types: ${validTypes.join(", ")}`));
2034
+ console.error(chalk.yellow(`Valid types: ${validTypes.join(', ')}`));
2023
2035
  process.exit(1);
2024
2036
  }
2025
2037
  }
@@ -2033,9 +2045,9 @@ program
2033
2045
  globalOptions.verbose || options.verbose
2034
2046
  );
2035
2047
 
2036
- console.log(chalk.cyan("Fetching entities..."));
2048
+ console.log(chalk.cyan('Fetching entities...'));
2037
2049
 
2038
- const spinner = ora("Loading entities...").start();
2050
+ const spinner = ora('Loading entities...').start();
2039
2051
 
2040
2052
  const result = await api.listEntities(
2041
2053
  options.type,
@@ -2045,29 +2057,29 @@ program
2045
2057
 
2046
2058
  spinner.stop();
2047
2059
 
2048
- if (options.output === "json") {
2060
+ if (options.output === 'json') {
2049
2061
  console.log(JSON.stringify(result, null, 2));
2050
2062
  } else {
2051
2063
  if (!result || result.length === 0) {
2052
- console.log(chalk.yellow("No entities found."));
2064
+ console.log(chalk.yellow('No entities found.'));
2053
2065
  return;
2054
2066
  }
2055
2067
 
2056
2068
  console.log(chalk.green.bold(`Found ${result.length} entities`));
2057
2069
  console.log();
2058
2070
 
2059
- const data = [["ID", "Label", "Type", "Description", "Emoji"]];
2071
+ const data = [['ID', 'Label', 'Type', 'Description', 'Emoji']];
2060
2072
 
2061
2073
  result.forEach((entity) => {
2062
2074
  data.push([
2063
- (entity.id || "N/A").substring(0, 20) + "...",
2064
- entity.label || "N/A",
2065
- entity.type || "N/A",
2066
- (entity.description || "N/A").substring(0, 30) +
2075
+ (entity.id || 'N/A').substring(0, 20) + '...',
2076
+ entity.label || 'N/A',
2077
+ entity.type || 'N/A',
2078
+ (entity.description || 'N/A').substring(0, 30) +
2067
2079
  (entity.description && entity.description.length > 30
2068
- ? "..."
2069
- : ""),
2070
- entity.emoji || "N/A",
2080
+ ? '...'
2081
+ : ''),
2082
+ entity.emoji || 'N/A',
2071
2083
  ]);
2072
2084
  });
2073
2085
 
@@ -2076,7 +2088,7 @@ program
2076
2088
  // Note: total count not available in flat array response
2077
2089
 
2078
2090
  if (options.verbose && result) {
2079
- console.log(chalk.dim("\nAPI Response:"));
2091
+ console.log(chalk.dim('\nAPI Response:'));
2080
2092
  console.log(chalk.dim(JSON.stringify(result, null, 2)));
2081
2093
  }
2082
2094
  }
@@ -2088,19 +2100,19 @@ program
2088
2100
 
2089
2101
  // Create folder command
2090
2102
  program
2091
- .command("create-folder")
2092
- .description("Create a new folder with specified name")
2093
- .argument("<name>", "Folder name")
2103
+ .command('create-folder')
2104
+ .description('Create a new folder with specified name')
2105
+ .argument('<name>', 'Folder name')
2094
2106
  .option(
2095
- "--user-id <id>",
2096
- "User ID (optional, uses configured value if not provided)"
2107
+ '--user-id <id>',
2108
+ 'User ID (optional, uses configured value if not provided)'
2097
2109
  )
2098
- .option("--description <desc>", "Folder description")
2099
- .option("--emoji <emoji>", "Folder emoji")
2100
- .option("--status <status>", "Folder status")
2101
- .option("--parent <id>", "Parent folder ID")
2102
- .option("-o, --output <format>", "Output format (json|text)", "text")
2103
- .option("-v, --verbose", "Show detailed creation information")
2110
+ .option('--description <desc>', 'Folder description')
2111
+ .option('--emoji <emoji>', 'Folder emoji')
2112
+ .option('--status <status>', 'Folder status')
2113
+ .option('--parent <id>', 'Parent folder ID')
2114
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
2115
+ .option('-v, --verbose', 'Show detailed creation information')
2104
2116
  .action(async (name, options, command) => {
2105
2117
  try {
2106
2118
  const globalOptions = command.parent.opts();
@@ -2120,7 +2132,7 @@ program
2120
2132
 
2121
2133
  console.log(chalk.cyan(`Creating folder "${name}"...`));
2122
2134
 
2123
- const spinner = ora("Creating folder...").start();
2135
+ const spinner = ora('Creating folder...').start();
2124
2136
 
2125
2137
  const result = await api.createFolder(
2126
2138
  userId,
@@ -2133,35 +2145,35 @@ program
2133
2145
 
2134
2146
  spinner.stop();
2135
2147
 
2136
- if (options.output === "json") {
2148
+ if (options.output === 'json') {
2137
2149
  console.log(JSON.stringify(result, null, 2));
2138
2150
  } else {
2139
- console.log(chalk.green.bold("āœ… Folder created successfully!"));
2151
+ console.log(chalk.green.bold('āœ… Folder created successfully!'));
2140
2152
  console.log();
2141
2153
 
2142
2154
  const data = [
2143
- ["Field", "Value"],
2144
- ["ID", result.id || "N/A"],
2145
- ["Name", result.name],
2146
- ["Description", result.description || "N/A"],
2147
- ["Emoji", result.emoji || "N/A"],
2148
- ["Status", result.status || "N/A"],
2149
- ["Parent", result.parent || "N/A"],
2150
- ["Workspace ID", result.workspaceID],
2151
- ["Created By", result.createdBy],
2155
+ ['Field', 'Value'],
2156
+ ['ID', result.id || 'N/A'],
2157
+ ['Name', result.name],
2158
+ ['Description', result.description || 'N/A'],
2159
+ ['Emoji', result.emoji || 'N/A'],
2160
+ ['Status', result.status || 'N/A'],
2161
+ ['Parent', result.parent || 'N/A'],
2162
+ ['Workspace ID', result.workspaceID],
2163
+ ['Created By', result.createdBy],
2152
2164
  ];
2153
2165
 
2154
2166
  console.log(
2155
2167
  table(data, {
2156
2168
  header: {
2157
- alignment: "center",
2158
- content: "Folder Details",
2169
+ alignment: 'center',
2170
+ content: 'Folder Details',
2159
2171
  },
2160
2172
  })
2161
2173
  );
2162
2174
 
2163
2175
  if (options.verbose && result) {
2164
- console.log(chalk.dim("\nAPI Response:"));
2176
+ console.log(chalk.dim('\nAPI Response:'));
2165
2177
  console.log(chalk.dim(JSON.stringify(result, null, 2)));
2166
2178
  }
2167
2179
  }
@@ -2173,16 +2185,16 @@ program
2173
2185
 
2174
2186
  // Update folder command
2175
2187
  program
2176
- .command("update-folder")
2177
- .description("Update an existing folder")
2178
- .argument("<id>", "Folder ID")
2179
- .option("--name <name>", "New folder name")
2180
- .option("--description <desc>", "New folder description")
2181
- .option("--emoji <emoji>", "New folder emoji")
2182
- .option("--status <status>", "New folder status")
2183
- .option("--parent <id>", "New parent folder ID")
2184
- .option("-o, --output <format>", "Output format (json|text)", "text")
2185
- .option("-v, --verbose", "Show detailed update information")
2188
+ .command('update-folder')
2189
+ .description('Update an existing folder')
2190
+ .argument('<id>', 'Folder ID')
2191
+ .option('--name <name>', 'New folder name')
2192
+ .option('--description <desc>', 'New folder description')
2193
+ .option('--emoji <emoji>', 'New folder emoji')
2194
+ .option('--status <status>', 'New folder status')
2195
+ .option('--parent <id>', 'New parent folder ID')
2196
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
2197
+ .option('-v, --verbose', 'Show detailed update information')
2186
2198
  .action(async (folderId, options, command) => {
2187
2199
  try {
2188
2200
  const globalOptions = command.parent.opts();
@@ -2200,7 +2212,7 @@ program
2200
2212
 
2201
2213
  console.log(chalk.cyan(`Updating folder ${folderId}...`));
2202
2214
 
2203
- const spinner = ora("Updating folder...").start();
2215
+ const spinner = ora('Updating folder...').start();
2204
2216
 
2205
2217
  const result = await api.updateFolder(
2206
2218
  folderId,
@@ -2213,33 +2225,33 @@ program
2213
2225
 
2214
2226
  spinner.stop();
2215
2227
 
2216
- if (options.output === "json") {
2228
+ if (options.output === 'json') {
2217
2229
  console.log(JSON.stringify(result, null, 2));
2218
2230
  } else {
2219
- console.log(chalk.green.bold("āœ… Folder updated successfully!"));
2231
+ console.log(chalk.green.bold('āœ… Folder updated successfully!'));
2220
2232
  console.log();
2221
2233
 
2222
2234
  const data = [
2223
- ["Field", "Value"],
2224
- ["ID", result.id || folderId],
2225
- ["Name", result.name || "N/A"],
2226
- ["Description", result.description || "N/A"],
2227
- ["Emoji", result.emoji || "N/A"],
2228
- ["Status", result.status || "N/A"],
2229
- ["Parent", result.parent || "N/A"],
2235
+ ['Field', 'Value'],
2236
+ ['ID', result.id || folderId],
2237
+ ['Name', result.name || 'N/A'],
2238
+ ['Description', result.description || 'N/A'],
2239
+ ['Emoji', result.emoji || 'N/A'],
2240
+ ['Status', result.status || 'N/A'],
2241
+ ['Parent', result.parent || 'N/A'],
2230
2242
  ];
2231
2243
 
2232
2244
  console.log(
2233
2245
  table(data, {
2234
2246
  header: {
2235
- alignment: "center",
2236
- content: "Updated Folder Details",
2247
+ alignment: 'center',
2248
+ content: 'Updated Folder Details',
2237
2249
  },
2238
2250
  })
2239
2251
  );
2240
2252
 
2241
2253
  if (options.verbose && result) {
2242
- console.log(chalk.dim("\nAPI Response:"));
2254
+ console.log(chalk.dim('\nAPI Response:'));
2243
2255
  console.log(chalk.dim(JSON.stringify(result, null, 2)));
2244
2256
  }
2245
2257
  }
@@ -2251,11 +2263,11 @@ program
2251
2263
 
2252
2264
  // Get folder command
2253
2265
  program
2254
- .command("get-folder")
2255
- .description("Get details of a specific folder")
2256
- .argument("<id>", "Folder ID")
2257
- .option("-o, --output <format>", "Output format (json|text)", "text")
2258
- .option("-v, --verbose", "Show detailed information")
2266
+ .command('get-folder')
2267
+ .description('Get details of a specific folder')
2268
+ .argument('<id>', 'Folder ID')
2269
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
2270
+ .option('-v, --verbose', 'Show detailed information')
2259
2271
  .action(async (folderId, options, command) => {
2260
2272
  try {
2261
2273
  const globalOptions = command.parent.opts();
@@ -2273,23 +2285,23 @@ program
2273
2285
 
2274
2286
  console.log(chalk.cyan(`Fetching folder ${folderId}...`));
2275
2287
 
2276
- const spinner = ora("Fetching folder...").start();
2288
+ const spinner = ora('Fetching folder...').start();
2277
2289
 
2278
2290
  const folderData = await api.getFolder(folderId);
2279
2291
 
2280
2292
  spinner.stop();
2281
2293
 
2282
- if (options.output === "json") {
2294
+ if (options.output === 'json') {
2283
2295
  console.log(JSON.stringify(folderData, null, 2));
2284
2296
  } else {
2285
- console.log(chalk.green.bold("Folder Details"));
2297
+ console.log(chalk.green.bold('Folder Details'));
2286
2298
  console.log();
2287
2299
 
2288
- const data = [["Field", "Value"]];
2300
+ const data = [['Field', 'Value']];
2289
2301
 
2290
2302
  Object.entries(folderData).forEach(([key, value]) => {
2291
2303
  let displayValue = value;
2292
- if (typeof value === "object" && value !== null) {
2304
+ if (typeof value === 'object' && value !== null) {
2293
2305
  displayValue = JSON.stringify(value, null, 2);
2294
2306
  }
2295
2307
  data.push([key, String(displayValue)]);
@@ -2305,12 +2317,12 @@ program
2305
2317
 
2306
2318
  // Delete folder command
2307
2319
  program
2308
- .command("delete-folder")
2309
- .description("Delete a folder")
2310
- .argument("<id>", "Folder ID")
2311
- .option("--confirm", "Skip confirmation prompt")
2312
- .option("-o, --output <format>", "Output format (json|text)", "text")
2313
- .option("-v, --verbose", "Show detailed deletion information")
2320
+ .command('delete-folder')
2321
+ .description('Delete a folder')
2322
+ .argument('<id>', 'Folder ID')
2323
+ .option('--confirm', 'Skip confirmation prompt')
2324
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
2325
+ .option('-v, --verbose', 'Show detailed deletion information')
2314
2326
  .action(async (folderId, options, command) => {
2315
2327
  try {
2316
2328
  const globalOptions = command.parent.opts();
@@ -2328,7 +2340,7 @@ program
2328
2340
 
2329
2341
  // Confirmation prompt (unless --confirm flag is used)
2330
2342
  if (!options.confirm) {
2331
- const readline = require("readline");
2343
+ const readline = require('readline');
2332
2344
  const rl = readline.createInterface({
2333
2345
  input: process.stdin,
2334
2346
  output: process.stdout,
@@ -2345,43 +2357,43 @@ program
2345
2357
 
2346
2358
  rl.close();
2347
2359
 
2348
- if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
2349
- console.log(chalk.gray("Deletion cancelled."));
2360
+ if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
2361
+ console.log(chalk.gray('Deletion cancelled.'));
2350
2362
  process.exit(0);
2351
2363
  }
2352
2364
  }
2353
2365
 
2354
2366
  console.log(chalk.cyan(`Deleting folder ${folderId}...`));
2355
2367
 
2356
- const spinner = ora("Deleting folder...").start();
2368
+ const spinner = ora('Deleting folder...').start();
2357
2369
 
2358
2370
  const result = await api.deleteFolder(folderId);
2359
2371
 
2360
2372
  spinner.stop();
2361
2373
 
2362
- if (options.output === "json") {
2374
+ if (options.output === 'json') {
2363
2375
  console.log(JSON.stringify(result, null, 2));
2364
2376
  } else {
2365
- console.log(chalk.green.bold("āœ… Folder deleted successfully!"));
2377
+ console.log(chalk.green.bold('āœ… Folder deleted successfully!'));
2366
2378
  console.log();
2367
2379
 
2368
2380
  const data = [
2369
- ["Field", "Value"],
2370
- ["Folder ID", folderId],
2371
- ["Status", "Deleted"],
2381
+ ['Field', 'Value'],
2382
+ ['Folder ID', folderId],
2383
+ ['Status', 'Deleted'],
2372
2384
  ];
2373
2385
 
2374
2386
  console.log(
2375
2387
  table(data, {
2376
2388
  header: {
2377
- alignment: "center",
2378
- content: "Deletion Details",
2389
+ alignment: 'center',
2390
+ content: 'Deletion Details',
2379
2391
  },
2380
2392
  })
2381
2393
  );
2382
2394
 
2383
2395
  if (options.verbose && result) {
2384
- console.log(chalk.dim("\nAPI Response:"));
2396
+ console.log(chalk.dim('\nAPI Response:'));
2385
2397
  console.log(chalk.dim(JSON.stringify(result, null, 2)));
2386
2398
  }
2387
2399
  }
@@ -2393,13 +2405,13 @@ program
2393
2405
 
2394
2406
  // List folders command
2395
2407
  program
2396
- .command("list-folders")
2397
- .description("List all folders in the workspace")
2398
- .option("--status <status>", "Filter by folder status")
2399
- .option("--limit <number>", "Maximum number of folders to return", "50")
2400
- .option("--offset <number>", "Number of folders to skip", "0")
2401
- .option("-o, --output <format>", "Output format (json|text)", "text")
2402
- .option("-v, --verbose", "Show detailed information")
2408
+ .command('list-folders')
2409
+ .description('List all folders in the workspace')
2410
+ .option('--status <status>', 'Filter by folder status')
2411
+ .option('--limit <number>', 'Maximum number of folders to return', '50')
2412
+ .option('--offset <number>', 'Number of folders to skip', '0')
2413
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
2414
+ .option('-v, --verbose', 'Show detailed information')
2403
2415
  .action(async (options, command) => {
2404
2416
  try {
2405
2417
  const globalOptions = command.parent.opts();
@@ -2415,9 +2427,9 @@ program
2415
2427
  globalOptions.verbose || options.verbose
2416
2428
  );
2417
2429
 
2418
- console.log(chalk.cyan("Fetching folders..."));
2430
+ console.log(chalk.cyan('Fetching folders...'));
2419
2431
 
2420
- const spinner = ora("Loading folders...").start();
2432
+ const spinner = ora('Loading folders...').start();
2421
2433
 
2422
2434
  const result = await api.listFolders(
2423
2435
  options.status,
@@ -2427,29 +2439,29 @@ program
2427
2439
 
2428
2440
  spinner.stop();
2429
2441
 
2430
- if (options.output === "json") {
2442
+ if (options.output === 'json') {
2431
2443
  console.log(JSON.stringify(result, null, 2));
2432
2444
  } else {
2433
2445
  if (!result || result.length === 0) {
2434
- console.log(chalk.yellow("No folders found."));
2446
+ console.log(chalk.yellow('No folders found.'));
2435
2447
  return;
2436
2448
  }
2437
2449
 
2438
2450
  console.log(chalk.green.bold(`Found ${result.length} folders`));
2439
2451
  console.log();
2440
2452
 
2441
- const data = [["ID", "Name", "Description", "Status", "Emoji"]];
2453
+ const data = [['ID', 'Name', 'Description', 'Status', 'Emoji']];
2442
2454
 
2443
2455
  result.forEach((folder) => {
2444
2456
  data.push([
2445
- (folder.id || "N/A").substring(0, 20) + "...",
2446
- folder.name || "N/A",
2447
- (folder.description || "N/A").substring(0, 30) +
2457
+ (folder.id || 'N/A').substring(0, 20) + '...',
2458
+ folder.name || 'N/A',
2459
+ (folder.description || 'N/A').substring(0, 30) +
2448
2460
  (folder.description && folder.description.length > 30
2449
- ? "..."
2450
- : ""),
2451
- folder.status || "N/A",
2452
- folder.emoji || "N/A",
2461
+ ? '...'
2462
+ : ''),
2463
+ folder.status || 'N/A',
2464
+ folder.emoji || 'N/A',
2453
2465
  ]);
2454
2466
  });
2455
2467
 
@@ -2458,7 +2470,7 @@ program
2458
2470
  // Note: total count not available in flat array response
2459
2471
 
2460
2472
  if (options.verbose && result) {
2461
- console.log(chalk.dim("\nAPI Response:"));
2473
+ console.log(chalk.dim('\nAPI Response:'));
2462
2474
  console.log(chalk.dim(JSON.stringify(result, null, 2)));
2463
2475
  }
2464
2476
  }
@@ -2470,23 +2482,23 @@ program
2470
2482
 
2471
2483
  // Create prompt command
2472
2484
  program
2473
- .command("create-prompt")
2474
- .description("Create a new prompt with specified parameters")
2475
- .argument("<type>", "Prompt type")
2476
- .argument("<label>", "Prompt label")
2477
- .argument("<prompt-length>", "Prompt length (number)")
2478
- .argument("<interpolation-string>", "Interpolation string")
2485
+ .command('create-prompt')
2486
+ .description('Create a new prompt with specified parameters')
2487
+ .argument('<type>', 'Prompt type')
2488
+ .argument('<label>', 'Prompt label')
2489
+ .argument('<prompt-length>', 'Prompt length (number)')
2490
+ .argument('<interpolation-string>', 'Interpolation string')
2479
2491
  .option(
2480
- "--user-id <id>",
2481
- "User ID (optional, uses configured value if not provided)"
2492
+ '--user-id <id>',
2493
+ 'User ID (optional, uses configured value if not provided)'
2482
2494
  )
2483
- .option("--scope <scope>", "Prompt scope")
2484
- .option("--style <style>", "Prompt style")
2485
- .option("--domain <domain>", "Prompt domain")
2486
- .option("--prompt-placeholder <placeholder>", "Prompt placeholder")
2487
- .option("--available-to-agents <agents>", "Comma-separated agent IDs")
2488
- .option("-o, --output <format>", "Output format (json|text)", "text")
2489
- .option("-v, --verbose", "Show detailed creation information")
2495
+ .option('--scope <scope>', 'Prompt scope')
2496
+ .option('--style <style>', 'Prompt style')
2497
+ .option('--domain <domain>', 'Prompt domain')
2498
+ .option('--prompt-placeholder <placeholder>', 'Prompt placeholder')
2499
+ .option('--available-to-agents <agents>', 'Comma-separated agent IDs')
2500
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
2501
+ .option('-v, --verbose', 'Show detailed creation information')
2490
2502
  .action(
2491
2503
  async (
2492
2504
  type,
@@ -2505,7 +2517,7 @@ program
2505
2517
  const parsedPromptLength = parseFloat(promptLength);
2506
2518
  if (isNaN(parsedPromptLength)) {
2507
2519
  console.error(
2508
- chalk.red("Error: Prompt length must be a valid number")
2520
+ chalk.red('Error: Prompt length must be a valid number')
2509
2521
  );
2510
2522
  process.exit(1);
2511
2523
  }
@@ -2514,7 +2526,7 @@ program
2514
2526
  let availableToAgents = null;
2515
2527
  if (options.availableToAgents) {
2516
2528
  availableToAgents = options.availableToAgents
2517
- .split(",")
2529
+ .split(',')
2518
2530
  .map((id) => id.trim())
2519
2531
  .filter((id) => id);
2520
2532
  }
@@ -2534,7 +2546,7 @@ program
2534
2546
  chalk.cyan(`Creating prompt "${label}" of type "${type}"...`)
2535
2547
  );
2536
2548
 
2537
- const spinner = ora("Creating prompt...").start();
2549
+ const spinner = ora('Creating prompt...').start();
2538
2550
 
2539
2551
  const result = await api.createPrompt(
2540
2552
  userId,
@@ -2551,44 +2563,44 @@ program
2551
2563
 
2552
2564
  spinner.stop();
2553
2565
 
2554
- if (options.output === "json") {
2566
+ if (options.output === 'json') {
2555
2567
  console.log(JSON.stringify(result, null, 2));
2556
2568
  } else {
2557
- console.log(chalk.green.bold("āœ… Prompt created successfully!"));
2569
+ console.log(chalk.green.bold('āœ… Prompt created successfully!'));
2558
2570
  console.log();
2559
2571
 
2560
2572
  const data = [
2561
- ["Field", "Value"],
2562
- ["ID", result.id || "N/A"],
2563
- ["Type", result.type],
2564
- ["Label", result.label],
2565
- ["Prompt Length", result.promptLength],
2566
- ["Interpolation String", result.interpolationString],
2567
- ["Scope", result.scope || "N/A"],
2568
- ["Style", result.style || "N/A"],
2569
- ["Domain", result.domain || "N/A"],
2570
- ["Prompt Placeholder", result.promptPlaceholder || "N/A"],
2573
+ ['Field', 'Value'],
2574
+ ['ID', result.id || 'N/A'],
2575
+ ['Type', result.type],
2576
+ ['Label', result.label],
2577
+ ['Prompt Length', result.promptLength],
2578
+ ['Interpolation String', result.interpolationString],
2579
+ ['Scope', result.scope || 'N/A'],
2580
+ ['Style', result.style || 'N/A'],
2581
+ ['Domain', result.domain || 'N/A'],
2582
+ ['Prompt Placeholder', result.promptPlaceholder || 'N/A'],
2571
2583
  [
2572
- "Available To Agents",
2584
+ 'Available To Agents',
2573
2585
  result.availableToAgents
2574
- ? result.availableToAgents.join(", ")
2575
- : "N/A",
2586
+ ? result.availableToAgents.join(', ')
2587
+ : 'N/A',
2576
2588
  ],
2577
- ["Workspace ID", result.workspaceID],
2578
- ["Created By", result.createdBy],
2589
+ ['Workspace ID', result.workspaceID],
2590
+ ['Created By', result.createdBy],
2579
2591
  ];
2580
2592
 
2581
2593
  console.log(
2582
2594
  table(data, {
2583
2595
  header: {
2584
- alignment: "center",
2585
- content: "Prompt Details",
2596
+ alignment: 'center',
2597
+ content: 'Prompt Details',
2586
2598
  },
2587
2599
  })
2588
2600
  );
2589
2601
 
2590
2602
  if (options.verbose && result) {
2591
- console.log(chalk.dim("\nAPI Response:"));
2603
+ console.log(chalk.dim('\nAPI Response:'));
2592
2604
  console.log(chalk.dim(JSON.stringify(result, null, 2)));
2593
2605
  }
2594
2606
  }
@@ -2601,20 +2613,20 @@ program
2601
2613
 
2602
2614
  // Update prompt command
2603
2615
  program
2604
- .command("update-prompt")
2605
- .description("Update an existing prompt")
2606
- .argument("<id>", "Prompt ID")
2607
- .option("--type <type>", "New prompt type")
2608
- .option("--label <label>", "New prompt label")
2609
- .option("--prompt-length <length>", "New prompt length (number)")
2610
- .option("--interpolation-string <string>", "New interpolation string")
2611
- .option("--scope <scope>", "New prompt scope")
2612
- .option("--style <style>", "New prompt style")
2613
- .option("--domain <domain>", "New prompt domain")
2614
- .option("--prompt-placeholder <placeholder>", "New prompt placeholder")
2615
- .option("--available-to-agents <agents>", "New comma-separated agent IDs")
2616
- .option("-o, --output <format>", "Output format (json|text)", "text")
2617
- .option("-v, --verbose", "Show detailed update information")
2616
+ .command('update-prompt')
2617
+ .description('Update an existing prompt')
2618
+ .argument('<id>', 'Prompt ID')
2619
+ .option('--type <type>', 'New prompt type')
2620
+ .option('--label <label>', 'New prompt label')
2621
+ .option('--prompt-length <length>', 'New prompt length (number)')
2622
+ .option('--interpolation-string <string>', 'New interpolation string')
2623
+ .option('--scope <scope>', 'New prompt scope')
2624
+ .option('--style <style>', 'New prompt style')
2625
+ .option('--domain <domain>', 'New prompt domain')
2626
+ .option('--prompt-placeholder <placeholder>', 'New prompt placeholder')
2627
+ .option('--available-to-agents <agents>', 'New comma-separated agent IDs')
2628
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
2629
+ .option('-v, --verbose', 'Show detailed update information')
2618
2630
  .action(async (promptId, options, command) => {
2619
2631
  try {
2620
2632
  const globalOptions = command.parent.opts();
@@ -2627,7 +2639,7 @@ program
2627
2639
  parsedPromptLength = parseFloat(options.promptLength);
2628
2640
  if (isNaN(parsedPromptLength)) {
2629
2641
  console.error(
2630
- chalk.red("Error: Prompt length must be a valid number")
2642
+ chalk.red('Error: Prompt length must be a valid number')
2631
2643
  );
2632
2644
  process.exit(1);
2633
2645
  }
@@ -2637,7 +2649,7 @@ program
2637
2649
  let availableToAgents = null;
2638
2650
  if (options.availableToAgents) {
2639
2651
  availableToAgents = options.availableToAgents
2640
- .split(",")
2652
+ .split(',')
2641
2653
  .map((id) => id.trim())
2642
2654
  .filter((id) => id);
2643
2655
  }
@@ -2653,7 +2665,7 @@ program
2653
2665
 
2654
2666
  console.log(chalk.cyan(`Updating prompt ${promptId}...`));
2655
2667
 
2656
- const spinner = ora("Updating prompt...").start();
2668
+ const spinner = ora('Updating prompt...').start();
2657
2669
 
2658
2670
  const result = await api.updatePrompt(
2659
2671
  promptId,
@@ -2670,42 +2682,42 @@ program
2670
2682
 
2671
2683
  spinner.stop();
2672
2684
 
2673
- if (options.output === "json") {
2685
+ if (options.output === 'json') {
2674
2686
  console.log(JSON.stringify(result, null, 2));
2675
2687
  } else {
2676
- console.log(chalk.green.bold("āœ… Prompt updated successfully!"));
2688
+ console.log(chalk.green.bold('āœ… Prompt updated successfully!'));
2677
2689
  console.log();
2678
2690
 
2679
2691
  const data = [
2680
- ["Field", "Value"],
2681
- ["ID", result.id || promptId],
2682
- ["Type", result.type || "N/A"],
2683
- ["Label", result.label || "N/A"],
2684
- ["Prompt Length", result.promptLength || "N/A"],
2685
- ["Interpolation String", result.interpolationString || "N/A"],
2686
- ["Scope", result.scope || "N/A"],
2687
- ["Style", result.style || "N/A"],
2688
- ["Domain", result.domain || "N/A"],
2689
- ["Prompt Placeholder", result.promptPlaceholder || "N/A"],
2692
+ ['Field', 'Value'],
2693
+ ['ID', result.id || promptId],
2694
+ ['Type', result.type || 'N/A'],
2695
+ ['Label', result.label || 'N/A'],
2696
+ ['Prompt Length', result.promptLength || 'N/A'],
2697
+ ['Interpolation String', result.interpolationString || 'N/A'],
2698
+ ['Scope', result.scope || 'N/A'],
2699
+ ['Style', result.style || 'N/A'],
2700
+ ['Domain', result.domain || 'N/A'],
2701
+ ['Prompt Placeholder', result.promptPlaceholder || 'N/A'],
2690
2702
  [
2691
- "Available To Agents",
2703
+ 'Available To Agents',
2692
2704
  result.availableToAgents
2693
- ? result.availableToAgents.join(", ")
2694
- : "N/A",
2705
+ ? result.availableToAgents.join(', ')
2706
+ : 'N/A',
2695
2707
  ],
2696
2708
  ];
2697
2709
 
2698
2710
  console.log(
2699
2711
  table(data, {
2700
2712
  header: {
2701
- alignment: "center",
2702
- content: "Updated Prompt Details",
2713
+ alignment: 'center',
2714
+ content: 'Updated Prompt Details',
2703
2715
  },
2704
2716
  })
2705
2717
  );
2706
2718
 
2707
2719
  if (options.verbose && result) {
2708
- console.log(chalk.dim("\nAPI Response:"));
2720
+ console.log(chalk.dim('\nAPI Response:'));
2709
2721
  console.log(chalk.dim(JSON.stringify(result, null, 2)));
2710
2722
  }
2711
2723
  }
@@ -2717,11 +2729,11 @@ program
2717
2729
 
2718
2730
  // Get prompt command
2719
2731
  program
2720
- .command("get-prompt")
2721
- .description("Get details of a specific prompt")
2722
- .argument("<id>", "Prompt ID")
2723
- .option("-o, --output <format>", "Output format (json|text)", "text")
2724
- .option("-v, --verbose", "Show detailed information")
2732
+ .command('get-prompt')
2733
+ .description('Get details of a specific prompt')
2734
+ .argument('<id>', 'Prompt ID')
2735
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
2736
+ .option('-v, --verbose', 'Show detailed information')
2725
2737
  .action(async (promptId, options, command) => {
2726
2738
  try {
2727
2739
  const globalOptions = command.parent.opts();
@@ -2739,23 +2751,23 @@ program
2739
2751
 
2740
2752
  console.log(chalk.cyan(`Fetching prompt ${promptId}...`));
2741
2753
 
2742
- const spinner = ora("Fetching prompt...").start();
2754
+ const spinner = ora('Fetching prompt...').start();
2743
2755
 
2744
2756
  const promptData = await api.getPrompt(promptId);
2745
2757
 
2746
2758
  spinner.stop();
2747
2759
 
2748
- if (options.output === "json") {
2760
+ if (options.output === 'json') {
2749
2761
  console.log(JSON.stringify(promptData, null, 2));
2750
2762
  } else {
2751
- console.log(chalk.green.bold("Prompt Details"));
2763
+ console.log(chalk.green.bold('Prompt Details'));
2752
2764
  console.log();
2753
2765
 
2754
- const data = [["Field", "Value"]];
2766
+ const data = [['Field', 'Value']];
2755
2767
 
2756
2768
  Object.entries(promptData).forEach(([key, value]) => {
2757
2769
  let displayValue = value;
2758
- if (typeof value === "object" && value !== null) {
2770
+ if (typeof value === 'object' && value !== null) {
2759
2771
  displayValue = JSON.stringify(value, null, 2);
2760
2772
  }
2761
2773
  data.push([key, String(displayValue)]);
@@ -2771,12 +2783,12 @@ program
2771
2783
 
2772
2784
  // Delete prompt command
2773
2785
  program
2774
- .command("delete-prompt")
2775
- .description("Delete a prompt")
2776
- .argument("<id>", "Prompt ID")
2777
- .option("--confirm", "Skip confirmation prompt")
2778
- .option("-o, --output <format>", "Output format (json|text)", "text")
2779
- .option("-v, --verbose", "Show detailed deletion information")
2786
+ .command('delete-prompt')
2787
+ .description('Delete a prompt')
2788
+ .argument('<id>', 'Prompt ID')
2789
+ .option('--confirm', 'Skip confirmation prompt')
2790
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
2791
+ .option('-v, --verbose', 'Show detailed deletion information')
2780
2792
  .action(async (promptId, options, command) => {
2781
2793
  try {
2782
2794
  const globalOptions = command.parent.opts();
@@ -2794,7 +2806,7 @@ program
2794
2806
 
2795
2807
  // Confirmation prompt (unless --confirm flag is used)
2796
2808
  if (!options.confirm) {
2797
- const readline = require("readline");
2809
+ const readline = require('readline');
2798
2810
  const rl = readline.createInterface({
2799
2811
  input: process.stdin,
2800
2812
  output: process.stdout,
@@ -2811,43 +2823,43 @@ program
2811
2823
 
2812
2824
  rl.close();
2813
2825
 
2814
- if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
2815
- console.log(chalk.gray("Deletion cancelled."));
2826
+ if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
2827
+ console.log(chalk.gray('Deletion cancelled.'));
2816
2828
  process.exit(0);
2817
2829
  }
2818
2830
  }
2819
2831
 
2820
2832
  console.log(chalk.cyan(`Deleting prompt ${promptId}...`));
2821
2833
 
2822
- const spinner = ora("Deleting prompt...").start();
2834
+ const spinner = ora('Deleting prompt...').start();
2823
2835
 
2824
2836
  const result = await api.deletePrompt(promptId);
2825
2837
 
2826
2838
  spinner.stop();
2827
2839
 
2828
- if (options.output === "json") {
2840
+ if (options.output === 'json') {
2829
2841
  console.log(JSON.stringify(result, null, 2));
2830
2842
  } else {
2831
- console.log(chalk.green.bold("āœ… Prompt deleted successfully!"));
2843
+ console.log(chalk.green.bold('āœ… Prompt deleted successfully!'));
2832
2844
  console.log();
2833
2845
 
2834
2846
  const data = [
2835
- ["Field", "Value"],
2836
- ["Prompt ID", promptId],
2837
- ["Status", "Deleted"],
2847
+ ['Field', 'Value'],
2848
+ ['Prompt ID', promptId],
2849
+ ['Status', 'Deleted'],
2838
2850
  ];
2839
2851
 
2840
2852
  console.log(
2841
2853
  table(data, {
2842
2854
  header: {
2843
- alignment: "center",
2844
- content: "Deletion Details",
2855
+ alignment: 'center',
2856
+ content: 'Deletion Details',
2845
2857
  },
2846
2858
  })
2847
2859
  );
2848
2860
 
2849
2861
  if (options.verbose && result) {
2850
- console.log(chalk.dim("\nAPI Response:"));
2862
+ console.log(chalk.dim('\nAPI Response:'));
2851
2863
  console.log(chalk.dim(JSON.stringify(result, null, 2)));
2852
2864
  }
2853
2865
  }
@@ -2859,13 +2871,13 @@ program
2859
2871
 
2860
2872
  // List prompts command
2861
2873
  program
2862
- .command("list-prompts")
2863
- .description("List all prompts in the workspace")
2864
- .option("--type <type>", "Filter by prompt type")
2865
- .option("--limit <number>", "Maximum number of prompts to return", "50")
2866
- .option("--offset <number>", "Number of prompts to skip", "0")
2867
- .option("-o, --output <format>", "Output format (json|text)", "text")
2868
- .option("-v, --verbose", "Show detailed information")
2874
+ .command('list-prompts')
2875
+ .description('List all prompts in the workspace')
2876
+ .option('--type <type>', 'Filter by prompt type')
2877
+ .option('--limit <number>', 'Maximum number of prompts to return', '50')
2878
+ .option('--offset <number>', 'Number of prompts to skip', '0')
2879
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
2880
+ .option('-v, --verbose', 'Show detailed information')
2869
2881
  .action(async (options, command) => {
2870
2882
  try {
2871
2883
  const globalOptions = command.parent.opts();
@@ -2881,9 +2893,9 @@ program
2881
2893
  globalOptions.verbose || options.verbose
2882
2894
  );
2883
2895
 
2884
- console.log(chalk.cyan("Fetching prompts..."));
2896
+ console.log(chalk.cyan('Fetching prompts...'));
2885
2897
 
2886
- const spinner = ora("Loading prompts...").start();
2898
+ const spinner = ora('Loading prompts...').start();
2887
2899
 
2888
2900
  const result = await api.listPrompts(
2889
2901
  options.type,
@@ -2893,27 +2905,27 @@ program
2893
2905
 
2894
2906
  spinner.stop();
2895
2907
 
2896
- if (options.output === "json") {
2908
+ if (options.output === 'json') {
2897
2909
  console.log(JSON.stringify(result, null, 2));
2898
2910
  } else {
2899
2911
  if (!result || result.length === 0) {
2900
- console.log(chalk.yellow("No prompts found."));
2912
+ console.log(chalk.yellow('No prompts found.'));
2901
2913
  return;
2902
2914
  }
2903
2915
 
2904
2916
  console.log(chalk.green.bold(`Found ${result.length} prompts`));
2905
2917
  console.log();
2906
2918
 
2907
- const data = [["ID", "Type", "Label", "Length", "Domain"]];
2919
+ const data = [['ID', 'Type', 'Label', 'Length', 'Domain']];
2908
2920
 
2909
2921
  result.forEach((prompt) => {
2910
2922
  data.push([
2911
- (prompt.id || "N/A").substring(0, 20) + "...",
2912
- prompt.type || "N/A",
2913
- (prompt.label || "N/A").substring(0, 30) +
2914
- (prompt.label && prompt.label.length > 30 ? "..." : ""),
2915
- prompt.promptLength || "N/A",
2916
- prompt.domain || "N/A",
2923
+ (prompt.id || 'N/A').substring(0, 20) + '...',
2924
+ prompt.type || 'N/A',
2925
+ (prompt.label || 'N/A').substring(0, 30) +
2926
+ (prompt.label && prompt.label.length > 30 ? '...' : ''),
2927
+ prompt.promptLength || 'N/A',
2928
+ prompt.domain || 'N/A',
2917
2929
  ]);
2918
2930
  });
2919
2931
 
@@ -2922,7 +2934,7 @@ program
2922
2934
  // Note: total count not available in flat array response
2923
2935
 
2924
2936
  if (options.verbose && result) {
2925
- console.log(chalk.dim("\nAPI Response:"));
2937
+ console.log(chalk.dim('\nAPI Response:'));
2926
2938
  console.log(chalk.dim(JSON.stringify(result, null, 2)));
2927
2939
  }
2928
2940
  }
@@ -2934,259 +2946,259 @@ program
2934
2946
 
2935
2947
  // Help guide command
2936
2948
  program
2937
- .command("help-guide")
2938
- .description("Show detailed help and usage examples")
2949
+ .command('help-guide')
2950
+ .description('Show detailed help and usage examples')
2939
2951
  .action(() => {
2940
- console.log(chalk.cyan.bold("šŸš€ ToothFairyAI CLI - Quick Start Guide"));
2941
- console.log("=".repeat(50));
2952
+ console.log(chalk.cyan.bold('šŸš€ ToothFairyAI CLI - Quick Start Guide'));
2953
+ console.log('='.repeat(50));
2942
2954
 
2943
- console.log(chalk.green.bold("\nšŸš€ Getting Started"));
2944
- console.log("1. First, configure your credentials:");
2955
+ console.log(chalk.green.bold('\nšŸš€ Getting Started'));
2956
+ console.log('1. First, configure your credentials:');
2945
2957
  console.log(
2946
2958
  chalk.dim(
2947
- " tf configure --api-key YOUR_KEY --workspace-id YOUR_WORKSPACE"
2959
+ ' tf configure --api-key YOUR_KEY --workspace-id YOUR_WORKSPACE'
2948
2960
  )
2949
2961
  );
2950
2962
 
2951
- console.log("\n2. Send a message to an agent:");
2963
+ console.log('\n2. Send a message to an agent:');
2952
2964
  console.log(
2953
2965
  chalk.dim(' tf send "Hello, I need help" --agent-id YOUR_AGENT_ID')
2954
2966
  );
2955
2967
 
2956
- console.log("\n3. Search the knowledge hub:");
2968
+ console.log('\n3. Search the knowledge hub:');
2957
2969
  console.log(chalk.dim(' tf search "AI configuration help"'));
2958
2970
 
2959
- console.log("\n4. Explore your workspace:");
2971
+ console.log('\n4. Explore your workspace:');
2960
2972
  console.log(
2961
- chalk.dim(" tf chats # List all conversations")
2973
+ chalk.dim(' tf chats # List all conversations')
2962
2974
  );
2963
2975
  console.log(
2964
- chalk.dim(" tf config-show # View current settings")
2976
+ chalk.dim(' tf config-show # View current settings')
2965
2977
  );
2966
2978
 
2967
- console.log(chalk.blue.bold("\nšŸ’¬ Agent Communication Examples"));
2979
+ console.log(chalk.blue.bold('\nšŸ’¬ Agent Communication Examples'));
2968
2980
 
2969
2981
  const agentExamples = [
2970
2982
  [
2971
- "Simple message",
2983
+ 'Simple message',
2972
2984
  'tf send "What are your hours?" --agent-id "info-agent"',
2973
2985
  ],
2974
2986
  [
2975
- "With customer info",
2987
+ 'With customer info',
2976
2988
  'tf send "Schedule appointment" --agent-id "scheduler" --customer-info \'{"name": "John"}\'',
2977
2989
  ],
2978
- ["Verbose output", 'tf send "Hello" --agent-id "agent-123" --verbose'],
2990
+ ['Verbose output', 'tf send "Hello" --agent-id "agent-123" --verbose'],
2979
2991
  [
2980
- "JSON for scripting",
2992
+ 'JSON for scripting',
2981
2993
  'tf send "Help" --agent-id "agent-123" --output json',
2982
2994
  ],
2983
2995
  ];
2984
2996
 
2985
- const agentData = [["Use Case", "Command"], ...agentExamples];
2997
+ const agentData = [['Use Case', 'Command'], ...agentExamples];
2986
2998
  console.log(
2987
2999
  table(agentData, {
2988
3000
  header: {
2989
- alignment: "center",
2990
- content: "Agent Communication",
3001
+ alignment: 'center',
3002
+ content: 'Agent Communication',
2991
3003
  },
2992
3004
  })
2993
3005
  );
2994
3006
 
2995
- console.log(chalk.magenta.bold("\nšŸ” Knowledge Hub Search Examples"));
3007
+ console.log(chalk.magenta.bold('\nšŸ” Knowledge Hub Search Examples'));
2996
3008
 
2997
3009
  const searchExamples = [
2998
- ["Basic search", 'tf search "AI agent configuration"'],
2999
- ["Filter by status", 'tf search "machine learning" --status published'],
3000
- ["Limit results", 'tf search "troubleshooting" --top-k 3'],
3010
+ ['Basic search', 'tf search "AI agent configuration"'],
3011
+ ['Filter by status', 'tf search "machine learning" --status published'],
3012
+ ['Limit results', 'tf search "troubleshooting" --top-k 3'],
3001
3013
  [
3002
- "Topic filtering",
3014
+ 'Topic filtering',
3003
3015
  'tf search "automation" --topics "topic_123,topic_456"',
3004
3016
  ],
3005
- ["Specific document", 'tf search "settings" --document-id "doc_550..."'],
3006
- ["Verbose details", 'tf search "deployment" --verbose'],
3007
- ["JSON output", 'tf search "API docs" --output json'],
3017
+ ['Specific document', 'tf search "settings" --document-id "doc_550..."'],
3018
+ ['Verbose details', 'tf search "deployment" --verbose'],
3019
+ ['JSON output', 'tf search "API docs" --output json'],
3008
3020
  ];
3009
3021
 
3010
- const searchData = [["Use Case", "Command"], ...searchExamples];
3022
+ const searchData = [['Use Case', 'Command'], ...searchExamples];
3011
3023
  console.log(
3012
3024
  table(searchData, {
3013
3025
  header: {
3014
- alignment: "center",
3015
- content: "Knowledge Hub Search",
3026
+ alignment: 'center',
3027
+ content: 'Knowledge Hub Search',
3016
3028
  },
3017
3029
  })
3018
3030
  );
3019
3031
 
3020
- console.log(chalk.blue.bold("\nšŸ“ File Management Examples"));
3032
+ console.log(chalk.blue.bold('\nšŸ“ File Management Examples'));
3021
3033
 
3022
3034
  const fileExamples = [
3023
- ["Upload PDF file", 'tf upload "./document.pdf"'],
3035
+ ['Upload PDF file', 'tf upload "./document.pdf"'],
3024
3036
  [
3025
- "Upload with custom type",
3037
+ 'Upload with custom type',
3026
3038
  'tf upload "./file.txt" --import-type "imported_doc_files"',
3027
3039
  ],
3028
- ["Upload image file", 'tf upload "./photo.jpg"'],
3040
+ ['Upload image file', 'tf upload "./photo.jpg"'],
3029
3041
  [
3030
- "Upload with content type",
3042
+ 'Upload with content type',
3031
3043
  'tf upload "./data.csv" --content-type "text/csv"',
3032
3044
  ],
3033
3045
  [
3034
- "Download uploaded file",
3046
+ 'Download uploaded file',
3035
3047
  'tf download --filename "imported-image/workspace123/1672531200000image.jpg"',
3036
3048
  ],
3037
3049
  [
3038
- "Download to custom dir",
3050
+ 'Download to custom dir',
3039
3051
  'tf download --filename "imported_doc_files/workspace123/1672531200000document.pdf" --output-dir "./results"',
3040
3052
  ],
3041
3053
  [
3042
- "Download with custom name",
3054
+ 'Download with custom name',
3043
3055
  'tf download --filename "imported_doc_files/workspace123/1672531200000report.docx" --output-name "final-report.docx"',
3044
3056
  ],
3045
3057
  ];
3046
3058
 
3047
- const fileData = [["Use Case", "Command"], ...fileExamples];
3059
+ const fileData = [['Use Case', 'Command'], ...fileExamples];
3048
3060
  console.log(
3049
3061
  table(fileData, {
3050
3062
  header: {
3051
- alignment: "center",
3052
- content: "File Management",
3063
+ alignment: 'center',
3064
+ content: 'File Management',
3053
3065
  },
3054
3066
  })
3055
3067
  );
3056
3068
 
3057
- console.log(chalk.green.bold("\nšŸ“‹ Workspace Management Examples"));
3069
+ console.log(chalk.green.bold('\nšŸ“‹ Workspace Management Examples'));
3058
3070
 
3059
3071
  const mgmtExamples = [
3060
- ["List all chats", "tf chats"],
3061
- ["View chat details", "tf chat CHAT_ID"],
3062
- ["Show config", "tf config-show"],
3063
- ["Detailed help", "tf help-guide"],
3072
+ ['List all chats', 'tf chats'],
3073
+ ['View chat details', 'tf chat CHAT_ID'],
3074
+ ['Show config', 'tf config-show'],
3075
+ ['Detailed help', 'tf help-guide'],
3064
3076
  ];
3065
3077
 
3066
- const mgmtData = [["Use Case", "Command"], ...mgmtExamples];
3078
+ const mgmtData = [['Use Case', 'Command'], ...mgmtExamples];
3067
3079
  console.log(
3068
3080
  table(mgmtData, {
3069
3081
  header: {
3070
- alignment: "center",
3071
- content: "Workspace Management",
3082
+ alignment: 'center',
3083
+ content: 'Workspace Management',
3072
3084
  },
3073
3085
  })
3074
3086
  );
3075
3087
 
3076
- console.log(chalk.yellow.bold("\nšŸ”§ Configuration Options"));
3088
+ console.log(chalk.yellow.bold('\nšŸ”§ Configuration Options'));
3077
3089
  const configOptions = [
3078
- ["Method", "Description", "Example"],
3090
+ ['Method', 'Description', 'Example'],
3079
3091
  [
3080
- "Environment",
3081
- "Set environment variables",
3082
- "export TF_API_KEY=your_key",
3092
+ 'Environment',
3093
+ 'Set environment variables',
3094
+ 'export TF_API_KEY=your_key',
3083
3095
  ],
3084
3096
  [
3085
- "Config file",
3086
- "Use ~/.toothfairy/config.yml",
3087
- "api_key: your_key\\nworkspace_id: your_workspace",
3097
+ 'Config file',
3098
+ 'Use ~/.toothfairy/config.yml',
3099
+ 'api_key: your_key\\nworkspace_id: your_workspace',
3088
3100
  ],
3089
3101
  [
3090
- "CLI arguments",
3091
- "Pass config file path",
3092
- "tf --config /path/to/config.yml send ...",
3102
+ 'CLI arguments',
3103
+ 'Pass config file path',
3104
+ 'tf --config /path/to/config.yml send ...',
3093
3105
  ],
3094
3106
  ];
3095
3107
 
3096
3108
  console.log(table(configOptions));
3097
3109
 
3098
- console.log(chalk.red.bold("\nāš ļø Common Issues & Solutions"));
3110
+ console.log(chalk.red.bold('\nāš ļø Common Issues & Solutions'));
3099
3111
  const issues = [
3100
- ["Issue", "Solution"],
3112
+ ['Issue', 'Solution'],
3101
3113
  [
3102
- "Configuration incomplete",
3103
- "Run: tf configure --api-key YOUR_KEY --workspace-id YOUR_WORKSPACE",
3114
+ 'Configuration incomplete',
3115
+ 'Run: tf configure --api-key YOUR_KEY --workspace-id YOUR_WORKSPACE',
3104
3116
  ],
3105
3117
  [
3106
- "No text response found",
3107
- "Use --verbose flag to see full response details",
3118
+ 'No text response found',
3119
+ 'Use --verbose flag to see full response details',
3108
3120
  ],
3109
- ["Agent not responding", "Check agent-id is correct and agent is active"],
3121
+ ['Agent not responding', 'Check agent-id is correct and agent is active'],
3110
3122
  [
3111
- "Network errors",
3112
- "Verify API endpoints are accessible and credentials are valid",
3123
+ 'Network errors',
3124
+ 'Verify API endpoints are accessible and credentials are valid',
3113
3125
  ],
3114
3126
  ];
3115
3127
 
3116
3128
  console.log(table(issues));
3117
3129
 
3118
- console.log(chalk.cyan.bold("\nšŸ” Search Filtering Guide"));
3119
- console.log("Knowledge Hub search supports powerful filtering options:");
3130
+ console.log(chalk.cyan.bold('\nšŸ” Search Filtering Guide'));
3131
+ console.log('Knowledge Hub search supports powerful filtering options:');
3120
3132
  console.log(
3121
- "• " +
3122
- chalk.cyan("--status") +
3123
- ": Filter documents by 'published' or 'suspended' status"
3133
+ '• ' +
3134
+ chalk.cyan('--status') +
3135
+ ': Filter documents by \'published\' or \'suspended\' status'
3124
3136
  );
3125
3137
  console.log(
3126
- "• " +
3127
- chalk.cyan("--topics") +
3128
- ": Use topic IDs from ToothFairyAI (comma-separated)"
3138
+ '• ' +
3139
+ chalk.cyan('--topics') +
3140
+ ': Use topic IDs from ToothFairyAI (comma-separated)'
3129
3141
  );
3130
3142
  console.log(
3131
- "• " + chalk.cyan("--document-id") + ": Search within a specific document"
3143
+ '• ' + chalk.cyan('--document-id') + ': Search within a specific document'
3132
3144
  );
3133
3145
  console.log(
3134
- "• " + chalk.cyan("--top-k") + ": Control number of results (1-50)"
3146
+ '• ' + chalk.cyan('--top-k') + ': Control number of results (1-50)'
3135
3147
  );
3136
3148
  console.log(
3137
- "• " + chalk.cyan("--verbose") + ": Show relevance scores and metadata"
3149
+ '• ' + chalk.cyan('--verbose') + ': Show relevance scores and metadata'
3138
3150
  );
3139
3151
 
3140
- console.log(chalk.blue.bold("\nšŸ“ File Upload/Download Guide"));
3141
- console.log("File operations support various formats and contexts:");
3152
+ console.log(chalk.blue.bold('\nšŸ“ File Upload/Download Guide'));
3153
+ console.log('File operations support various formats and contexts:');
3142
3154
  console.log(
3143
- "• " + chalk.cyan("File size limit") + ": 15MB maximum per file"
3155
+ '• ' + chalk.cyan('File size limit') + ': 15MB maximum per file'
3144
3156
  );
3145
3157
  console.log(
3146
- "• " +
3147
- chalk.cyan("Supported formats") +
3148
- ": pdf, docx, txt, csv, md, html, xlsx, pptx, png, jpg, jpeg, java, py, yaml, sql, js, ts, jsonl, wav, mp4, json"
3158
+ '• ' +
3159
+ chalk.cyan('Supported formats') +
3160
+ ': pdf, docx, txt, csv, md, html, xlsx, pptx, png, jpg, jpeg, java, py, yaml, sql, js, ts, jsonl, wav, mp4, json'
3149
3161
  );
3150
3162
  console.log(
3151
- "• " +
3152
- chalk.cyan("Upload contexts") +
3153
- ": Files are automatically categorized by extension (pdf → imported-pdf, wav → imported_audio_files, etc.)"
3163
+ '• ' +
3164
+ chalk.cyan('Upload contexts') +
3165
+ ': Files are automatically categorized by extension (pdf → imported-pdf, wav → imported_audio_files, etc.)'
3154
3166
  );
3155
3167
  console.log(
3156
- "• " +
3157
- chalk.cyan("Download") +
3158
- ": Use the filename from upload response to download files"
3168
+ '• ' +
3169
+ chalk.cyan('Download') +
3170
+ ': Use the filename from upload response to download files'
3159
3171
  );
3160
3172
  console.log(
3161
- "• " +
3162
- chalk.cyan("Progress tracking") +
3163
- ": Real-time upload/download progress with size information"
3173
+ '• ' +
3174
+ chalk.cyan('Progress tracking') +
3175
+ ': Real-time upload/download progress with size information'
3164
3176
  );
3165
3177
 
3166
- console.log(chalk.magenta.bold("\nšŸ“– More Help"));
3178
+ console.log(chalk.magenta.bold('\nšŸ“– More Help'));
3167
3179
  console.log(
3168
- "• Use " + chalk.cyan("tf COMMAND --help") + " for command-specific help"
3180
+ '• Use ' + chalk.cyan('tf COMMAND --help') + ' for command-specific help'
3169
3181
  );
3170
3182
  console.log(
3171
- "• Use " +
3172
- chalk.cyan("--verbose") +
3173
- " flag to see detailed request/response information"
3183
+ '• Use ' +
3184
+ chalk.cyan('--verbose') +
3185
+ ' flag to see detailed request/response information'
3174
3186
  );
3175
3187
  console.log(
3176
- "• Use " + chalk.cyan("--output json") + " for machine-readable output"
3188
+ '• Use ' + chalk.cyan('--output json') + ' for machine-readable output'
3177
3189
  );
3178
3190
  console.log(
3179
- "• Configuration is loaded from: environment variables → ~/.toothfairy/config.yml → CLI args"
3191
+ '• Configuration is loaded from: environment variables → ~/.toothfairy/config.yml → CLI args'
3180
3192
  );
3181
3193
 
3182
- console.log(chalk.green.bold("\n✨ Pro Tips"));
3194
+ console.log(chalk.green.bold('\n✨ Pro Tips'));
3183
3195
  const tips = [
3184
- "šŸ’¾ Save time: Configure once with 'tf configure', then just use 'tf send' and 'tf search'",
3185
- "šŸ” Debug issues: Use '--verbose' to see full API responses and troubleshoot",
3186
- "šŸ“ Scripting: Use '--output json' and tools like 'jq' to parse responses",
3187
- "⚔ Quick tests: Only --agent-id is required for send, only query for search",
3188
- "šŸŽÆ Better search: Use --status, --topics, and --document-id for targeted results",
3189
- "šŸ”§ Multiple environments: Use different config files with '--config' flag",
3196
+ 'šŸ’¾ Save time: Configure once with \'tf configure\', then just use \'tf send\' and \'tf search\'',
3197
+ 'šŸ” Debug issues: Use \'--verbose\' to see full API responses and troubleshoot',
3198
+ 'šŸ“ Scripting: Use \'--output json\' and tools like \'jq\' to parse responses',
3199
+ '⚔ Quick tests: Only --agent-id is required for send, only query for search',
3200
+ 'šŸŽÆ Better search: Use --status, --topics, and --document-id for targeted results',
3201
+ 'šŸ”§ Multiple environments: Use different config files with \'--config\' flag',
3190
3202
  ];
3191
3203
 
3192
3204
  tips.forEach((tip) => {
@@ -3195,20 +3207,20 @@ program
3195
3207
 
3196
3208
  console.log(
3197
3209
  chalk.dim(
3198
- "\nToothFairy CLI v1.0.0 - For more help, visit the documentation"
3210
+ '\nToothFairy CLI v1.0.0 - For more help, visit the documentation'
3199
3211
  )
3200
3212
  );
3201
3213
  });
3202
3214
 
3203
3215
  // Generate speech command
3204
3216
  program
3205
- .command("generate-speech")
3206
- .description("Generate speech audio from text using ToothFairyAI")
3207
- .argument("<text>", "Text to convert to speech")
3208
- .option("--chat-id <id>", "Chat ID for context (optional)")
3209
- .option("--last-message-id <id>", "Last message ID for context (optional)")
3210
- .option("-o, --output <format>", "Output format (json|text)", "text")
3211
- .option("-v, --verbose", "Show detailed generation information")
3217
+ .command('generate-speech')
3218
+ .description('Generate speech audio from text using ToothFairyAI')
3219
+ .argument('<text>', 'Text to convert to speech')
3220
+ .option('--chat-id <id>', 'Chat ID for context (optional)')
3221
+ .option('--last-message-id <id>', 'Last message ID for context (optional)')
3222
+ .option('-o, --output <format>', 'Output format (json|text)', 'text')
3223
+ .option('-v, --verbose', 'Show detailed generation information')
3212
3224
  .action(async (text, options, command) => {
3213
3225
  try {
3214
3226
  const globalOptions = command.parent.opts();
@@ -3224,7 +3236,7 @@ program
3224
3236
  globalOptions.verbose || options.verbose
3225
3237
  );
3226
3238
 
3227
- console.log(chalk.cyan("Generating speech from text..."));
3239
+ console.log(chalk.cyan('Generating speech from text...'));
3228
3240
  if (options.verbose) {
3229
3241
  console.log(chalk.dim(`Text: "${text}"`));
3230
3242
  if (options.chatId) {
@@ -3235,7 +3247,7 @@ program
3235
3247
  }
3236
3248
  }
3237
3249
 
3238
- const spinner = ora("Generating audio...").start();
3250
+ const spinner = ora('Generating audio...').start();
3239
3251
 
3240
3252
  const result = await api.generateSpeech(
3241
3253
  text,
@@ -3245,44 +3257,44 @@ program
3245
3257
 
3246
3258
  spinner.stop();
3247
3259
 
3248
- if (options.output === "json") {
3260
+ if (options.output === 'json') {
3249
3261
  console.log(JSON.stringify(result, null, 2));
3250
3262
  } else {
3251
- console.log(chalk.green.bold("šŸŽµ Speech generated successfully!"));
3263
+ console.log(chalk.green.bold('šŸŽµ Speech generated successfully!'));
3252
3264
  console.log();
3253
3265
 
3254
3266
  const data = [
3255
- ["Field", "Value"],
3256
- ["Text Length", `${text.length} characters`],
3267
+ ['Field', 'Value'],
3268
+ ['Text Length', `${text.length} characters`],
3257
3269
  ];
3258
3270
 
3259
3271
  if (result.audioUrl) {
3260
- data.push(["Audio URL", result.audioUrl]);
3272
+ data.push(['Audio URL', result.audioUrl]);
3261
3273
  }
3262
3274
  if (result.duration) {
3263
- data.push(["Duration", `${result.duration}s`]);
3275
+ data.push(['Duration', `${result.duration}s`]);
3264
3276
  }
3265
3277
  if (result.format) {
3266
- data.push(["Format", result.format]);
3278
+ data.push(['Format', result.format]);
3267
3279
  }
3268
3280
  if (options.chatId) {
3269
- data.push(["Chat ID", options.chatId]);
3281
+ data.push(['Chat ID', options.chatId]);
3270
3282
  }
3271
3283
  if (options.lastMessageId) {
3272
- data.push(["Last Message ID", options.lastMessageId]);
3284
+ data.push(['Last Message ID', options.lastMessageId]);
3273
3285
  }
3274
3286
 
3275
3287
  console.log(
3276
3288
  table(data, {
3277
3289
  header: {
3278
- alignment: "center",
3279
- content: "Speech Generation Results",
3290
+ alignment: 'center',
3291
+ content: 'Speech Generation Results',
3280
3292
  },
3281
3293
  })
3282
3294
  );
3283
3295
 
3284
3296
  if (options.verbose && result) {
3285
- console.log(chalk.dim("\nAPI Response:"));
3297
+ console.log(chalk.dim('\nAPI Response:'));
3286
3298
  console.log(chalk.dim(JSON.stringify(result, null, 2)));
3287
3299
  }
3288
3300
  }