@happyvertical/ai 0.74.8

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 (77) hide show
  1. package/AGENT.md +33 -0
  2. package/LICENSE +7 -0
  3. package/README.md +384 -0
  4. package/dist/chunks/anthropic-BRwbhwIl.js +463 -0
  5. package/dist/chunks/anthropic-BRwbhwIl.js.map +1 -0
  6. package/dist/chunks/bedrock-Cf1xUerN.js +808 -0
  7. package/dist/chunks/bedrock-Cf1xUerN.js.map +1 -0
  8. package/dist/chunks/bifrost-3mXtQsTj.js +233 -0
  9. package/dist/chunks/bifrost-3mXtQsTj.js.map +1 -0
  10. package/dist/chunks/claude-cli-BrHRfkry.js +603 -0
  11. package/dist/chunks/claude-cli-BrHRfkry.js.map +1 -0
  12. package/dist/chunks/gateway-admin-C4GFPbZF.js +359 -0
  13. package/dist/chunks/gateway-admin-C4GFPbZF.js.map +1 -0
  14. package/dist/chunks/gemini-BfpHXDIQ.js +662 -0
  15. package/dist/chunks/gemini-BfpHXDIQ.js.map +1 -0
  16. package/dist/chunks/huggingface-280qv9iv.js +366 -0
  17. package/dist/chunks/huggingface-280qv9iv.js.map +1 -0
  18. package/dist/chunks/index-BT4thAvS.js +934 -0
  19. package/dist/chunks/index-BT4thAvS.js.map +1 -0
  20. package/dist/chunks/litellm-DhPKa_Jz.js +220 -0
  21. package/dist/chunks/litellm-DhPKa_Jz.js.map +1 -0
  22. package/dist/chunks/ollama-Di1ldur0.js +851 -0
  23. package/dist/chunks/ollama-Di1ldur0.js.map +1 -0
  24. package/dist/chunks/openai-5snI2diE.js +749 -0
  25. package/dist/chunks/openai-5snI2diE.js.map +1 -0
  26. package/dist/chunks/qwen-tts-DgPgdXxG.js +365 -0
  27. package/dist/chunks/qwen-tts-DgPgdXxG.js.map +1 -0
  28. package/dist/chunks/usage-DMWiJ2oB.js +21 -0
  29. package/dist/chunks/usage-DMWiJ2oB.js.map +1 -0
  30. package/dist/cli/claude-context.d.ts +3 -0
  31. package/dist/cli/claude-context.d.ts.map +1 -0
  32. package/dist/cli/claude-context.js +21 -0
  33. package/dist/cli/claude-context.js.map +1 -0
  34. package/dist/index.d.ts +20 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +21 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/node/factory.d.ts +27 -0
  39. package/dist/node/factory.d.ts.map +1 -0
  40. package/dist/shared/client.d.ts +410 -0
  41. package/dist/shared/client.d.ts.map +1 -0
  42. package/dist/shared/factory.d.ts +83 -0
  43. package/dist/shared/factory.d.ts.map +1 -0
  44. package/dist/shared/message.d.ts +71 -0
  45. package/dist/shared/message.d.ts.map +1 -0
  46. package/dist/shared/providers/anthropic.d.ts +82 -0
  47. package/dist/shared/providers/anthropic.d.ts.map +1 -0
  48. package/dist/shared/providers/bedrock.d.ts +49 -0
  49. package/dist/shared/providers/bedrock.d.ts.map +1 -0
  50. package/dist/shared/providers/bifrost.d.ts +25 -0
  51. package/dist/shared/providers/bifrost.d.ts.map +1 -0
  52. package/dist/shared/providers/claude-cli.d.ts +139 -0
  53. package/dist/shared/providers/claude-cli.d.ts.map +1 -0
  54. package/dist/shared/providers/gateway-admin.d.ts +35 -0
  55. package/dist/shared/providers/gateway-admin.d.ts.map +1 -0
  56. package/dist/shared/providers/gemini.d.ts +116 -0
  57. package/dist/shared/providers/gemini.d.ts.map +1 -0
  58. package/dist/shared/providers/huggingface.d.ts +33 -0
  59. package/dist/shared/providers/huggingface.d.ts.map +1 -0
  60. package/dist/shared/providers/litellm.d.ts +25 -0
  61. package/dist/shared/providers/litellm.d.ts.map +1 -0
  62. package/dist/shared/providers/ollama.d.ts +47 -0
  63. package/dist/shared/providers/ollama.d.ts.map +1 -0
  64. package/dist/shared/providers/openai.d.ts +272 -0
  65. package/dist/shared/providers/openai.d.ts.map +1 -0
  66. package/dist/shared/providers/qwen-tts.d.ts +85 -0
  67. package/dist/shared/providers/qwen-tts.d.ts.map +1 -0
  68. package/dist/shared/providers/usage.d.ts +14 -0
  69. package/dist/shared/providers/usage.d.ts.map +1 -0
  70. package/dist/shared/rate-limit.d.ts +13 -0
  71. package/dist/shared/rate-limit.d.ts.map +1 -0
  72. package/dist/shared/thread.d.ts +104 -0
  73. package/dist/shared/thread.d.ts.map +1 -0
  74. package/dist/shared/types.d.ts +1779 -0
  75. package/dist/shared/types.d.ts.map +1 -0
  76. package/metadata.json +35 -0
  77. package/package.json +62 -0
@@ -0,0 +1,603 @@
1
+ import { spawn, exec } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import { A as AIError, c as extractTextContent, b as AuthenticationError, R as RateLimitError, a as ContextLengthError } from "./index-BT4thAvS.js";
4
+ import { e as emitUsage } from "./usage-DMWiJ2oB.js";
5
+ const execAsync = promisify(exec);
6
+ class ClaudeCliProvider {
7
+ options;
8
+ cliPath = null;
9
+ anthropicFallback = null;
10
+ /**
11
+ * Creates a new Claude CLI provider instance
12
+ * @param options - Configuration options for the Claude CLI provider
13
+ */
14
+ constructor(options) {
15
+ this.options = {
16
+ defaultModel: "sonnet",
17
+ ...options
18
+ };
19
+ }
20
+ /**
21
+ * Checks if ANTHROPIC_API_KEY is available and initializes fallback provider if needed
22
+ * @private
23
+ */
24
+ async initializeFallback() {
25
+ if (this.anthropicFallback !== null) {
26
+ return;
27
+ }
28
+ const apiKey = process.env.ANTHROPIC_API_KEY;
29
+ if (!apiKey) {
30
+ return;
31
+ }
32
+ const { AnthropicProvider } = await import("./anthropic-BRwbhwIl.js");
33
+ const modelMap = {
34
+ sonnet: "claude-3-5-sonnet-20241022",
35
+ opus: "claude-3-opus-20240229",
36
+ haiku: "claude-3-haiku-20240307"
37
+ };
38
+ const defaultModel = modelMap[this.options.defaultModel || "sonnet"] || "claude-3-5-sonnet-20241022";
39
+ this.anthropicFallback = new AnthropicProvider({
40
+ type: "anthropic",
41
+ apiKey,
42
+ defaultModel,
43
+ onUsage: this.options.onUsage,
44
+ usageTags: this.options.usageTags
45
+ });
46
+ }
47
+ /**
48
+ * Finds the Claude CLI binary in PATH or uses custom cliPath
49
+ * Does NOT execute the CLI during detection to avoid keychain prompts
50
+ * @throws {AIError} When CLI cannot be found
51
+ * @private
52
+ */
53
+ async findCli() {
54
+ if (this.cliPath) {
55
+ return this.cliPath;
56
+ }
57
+ if (this.options.cliPath) {
58
+ const fs2 = await import("node:fs/promises");
59
+ try {
60
+ await fs2.access(this.options.cliPath);
61
+ this.cliPath = this.options.cliPath;
62
+ return this.cliPath;
63
+ } catch (_error) {
64
+ throw new AIError(
65
+ `Claude CLI not found at specified path: ${this.options.cliPath}. Set ANTHROPIC_API_KEY environment variable to avoid CLI dependency.`,
66
+ "CLI_NOT_FOUND",
67
+ "claude-cli"
68
+ );
69
+ }
70
+ }
71
+ const commonPaths = [
72
+ `${process.env.HOME}/.claude/local/claude`,
73
+ // Default installation path
74
+ "/usr/local/bin/claude",
75
+ "/opt/homebrew/bin/claude"
76
+ ];
77
+ const fs = await import("node:fs/promises");
78
+ for (const path of commonPaths) {
79
+ try {
80
+ await fs.access(path);
81
+ this.cliPath = path;
82
+ return this.cliPath;
83
+ } catch (_error) {
84
+ }
85
+ }
86
+ try {
87
+ const { stdout } = await execAsync("which claude");
88
+ const path = stdout.trim();
89
+ if (path) {
90
+ this.cliPath = path;
91
+ return this.cliPath;
92
+ }
93
+ } catch (_error) {
94
+ }
95
+ throw new AIError(
96
+ "Claude CLI not found. Set ANTHROPIC_API_KEY environment variable to use Anthropic SDK instead, or install Claude Code CLI. Visit https://docs.claude.com/en/docs/claude-code/ for installation instructions.",
97
+ "CLI_NOT_FOUND",
98
+ "claude-cli"
99
+ );
100
+ }
101
+ /**
102
+ * Normalizes model name to full model ID or short name
103
+ * @private
104
+ */
105
+ normalizeModel(model) {
106
+ const m = model || this.options.defaultModel || "sonnet";
107
+ const modelMap = {
108
+ sonnet: "sonnet",
109
+ opus: "opus",
110
+ haiku: "haiku"
111
+ };
112
+ return modelMap[m] || m;
113
+ }
114
+ /**
115
+ * Execute Claude CLI command and return parsed JSON output
116
+ * @private
117
+ */
118
+ async executeCommand(prompt, options = {}) {
119
+ const cliPath = await this.findCli();
120
+ const model = this.normalizeModel(options.model);
121
+ const args = ["--print", "--output-format", "json", "--model", model];
122
+ if (options.systemPrompt) {
123
+ args.push("--system-prompt", options.systemPrompt);
124
+ }
125
+ args.push(prompt);
126
+ return new Promise((resolve, reject) => {
127
+ let stdout = "";
128
+ let stderr = "";
129
+ const child = spawn(cliPath, args, {
130
+ stdio: ["ignore", "pipe", "pipe"]
131
+ });
132
+ child.stdout.on("data", (data) => {
133
+ stdout += data.toString();
134
+ });
135
+ child.stderr.on("data", (data) => {
136
+ stderr += data.toString();
137
+ });
138
+ child.on("error", (error) => {
139
+ reject(
140
+ new AIError(
141
+ `Failed to execute Claude CLI: ${error.message}`,
142
+ "EXECUTION_ERROR",
143
+ "claude-cli"
144
+ )
145
+ );
146
+ });
147
+ child.on("close", (code) => {
148
+ if (code !== 0) {
149
+ reject(this.mapCliError(stderr, code || void 0));
150
+ return;
151
+ }
152
+ try {
153
+ const result = JSON.parse(stdout);
154
+ resolve(result);
155
+ } catch (_error) {
156
+ reject(
157
+ new AIError(
158
+ "Failed to parse CLI output as JSON",
159
+ "PARSE_ERROR",
160
+ "claude-cli"
161
+ )
162
+ );
163
+ }
164
+ });
165
+ });
166
+ }
167
+ /**
168
+ * Execute Claude CLI command with streaming output
169
+ * @private
170
+ */
171
+ async *executeStreamingCommand(prompt, options = {}) {
172
+ const cliPath = await this.findCli();
173
+ const model = this.normalizeModel(options.model);
174
+ const args = [
175
+ "--print",
176
+ "--output-format",
177
+ "stream-json",
178
+ "--verbose",
179
+ // Required for stream-json format
180
+ "--model",
181
+ model
182
+ ];
183
+ if (options.systemPrompt) {
184
+ args.push("--system-prompt", options.systemPrompt);
185
+ }
186
+ args.push(prompt);
187
+ const child = spawn(cliPath, args, {
188
+ stdio: ["ignore", "pipe", "pipe"]
189
+ });
190
+ let stderr = "";
191
+ child.stderr.on("data", (data) => {
192
+ stderr += data.toString();
193
+ });
194
+ let buffer = "";
195
+ for await (const chunk of child.stdout) {
196
+ buffer += chunk.toString();
197
+ const lines = buffer.split("\n");
198
+ buffer = lines.pop() || "";
199
+ for (const line of lines) {
200
+ if (line.trim()) {
201
+ try {
202
+ const parsed = JSON.parse(line);
203
+ if (parsed.type === "assistant" && parsed.message?.content) {
204
+ for (const contentBlock of parsed.message.content) {
205
+ if (contentBlock.type === "text" && contentBlock.text) {
206
+ const text = contentBlock.text;
207
+ if (options.onProgress) {
208
+ options.onProgress(text);
209
+ }
210
+ yield text;
211
+ }
212
+ }
213
+ } else if (parsed.type === "result" && parsed.result) {
214
+ const text = parsed.result;
215
+ if (options.onProgress) {
216
+ options.onProgress(text);
217
+ }
218
+ yield text;
219
+ }
220
+ } catch (_error) {
221
+ }
222
+ }
223
+ }
224
+ }
225
+ const exitCode = await new Promise((resolve) => {
226
+ child.on("close", (code) => resolve(code || 0));
227
+ });
228
+ if (exitCode !== 0) {
229
+ throw this.mapCliError(stderr, exitCode);
230
+ }
231
+ }
232
+ /**
233
+ * Maps messages to a single prompt for CLI
234
+ * @private
235
+ */
236
+ mapMessagesToPrompt(messages) {
237
+ let systemPrompt;
238
+ const conversationParts = [];
239
+ for (const message of messages) {
240
+ const textContent = extractTextContent(message.content);
241
+ if (message.role === "system") {
242
+ systemPrompt = systemPrompt ? `${systemPrompt}
243
+
244
+ ${textContent}` : textContent;
245
+ } else if (message.role === "user") {
246
+ conversationParts.push(`User: ${textContent}`);
247
+ } else if (message.role === "assistant") {
248
+ conversationParts.push(`Assistant: ${textContent}`);
249
+ }
250
+ }
251
+ if (conversationParts.length === 1 && conversationParts[0].startsWith("User: ")) {
252
+ return {
253
+ prompt: conversationParts[0].substring(6),
254
+ // Remove "User: " prefix
255
+ systemPrompt
256
+ };
257
+ }
258
+ return {
259
+ prompt: conversationParts.join("\n\n"),
260
+ systemPrompt
261
+ };
262
+ }
263
+ /**
264
+ * Maps CLI errors to standardized error types
265
+ * @private
266
+ */
267
+ mapCliError(stderr, exitCode) {
268
+ const errorText = stderr.toLowerCase();
269
+ if (errorText.includes("not authenticated") || errorText.includes("login required")) {
270
+ return new AuthenticationError("claude-cli");
271
+ }
272
+ if (errorText.includes("rate limit") || errorText.includes("too many requests")) {
273
+ return new RateLimitError("claude-cli");
274
+ }
275
+ if (errorText.includes("context length") || errorText.includes("too long")) {
276
+ return new ContextLengthError("claude-cli");
277
+ }
278
+ return new AIError(
279
+ `Claude CLI error (exit code ${exitCode}): ${stderr}`,
280
+ "CLI_ERROR",
281
+ "claude-cli"
282
+ );
283
+ }
284
+ /**
285
+ * Generate a chat completion using Claude CLI
286
+ * @param messages - Array of conversation messages
287
+ * @param options - Optional configuration for the chat completion
288
+ * @returns Promise resolving to the AI response with content and metadata
289
+ * @throws {AIError} When the CLI execution fails
290
+ *
291
+ * @example
292
+ * ```typescript
293
+ * const response = await provider.chat([
294
+ * { role: 'system', content: 'You are a helpful assistant.' },
295
+ * { role: 'user', content: 'Explain quantum computing' }
296
+ * ], {
297
+ * model: 'sonnet'
298
+ * });
299
+ * ```
300
+ */
301
+ async chat(messages, options = {}) {
302
+ await this.initializeFallback();
303
+ if (this.anthropicFallback) {
304
+ return this.anthropicFallback.chat(messages, options);
305
+ }
306
+ const startTime = Date.now();
307
+ let { prompt, systemPrompt } = this.mapMessagesToPrompt(messages);
308
+ if (options.responseFormat?.type === "json_object") {
309
+ const jsonInstruction = "\n\nIMPORTANT: You must respond with valid JSON only. Do not include any explanatory text outside the JSON object.";
310
+ systemPrompt = systemPrompt ? systemPrompt + jsonInstruction : jsonInstruction.trim();
311
+ }
312
+ const result = await this.executeCommand(prompt, {
313
+ model: options.model,
314
+ systemPrompt,
315
+ temperature: options.temperature,
316
+ maxTokens: options.maxTokens
317
+ });
318
+ const model = options.model || this.options.defaultModel;
319
+ const usage = result.usage ? {
320
+ promptTokens: result.usage.input_tokens || 0,
321
+ completionTokens: result.usage.output_tokens || 0,
322
+ totalTokens: (result.usage.input_tokens || 0) + (result.usage.output_tokens || 0)
323
+ } : void 0;
324
+ emitUsage(
325
+ this.options,
326
+ "claude-cli",
327
+ "chat",
328
+ model,
329
+ usage,
330
+ startTime,
331
+ options.usageTags
332
+ );
333
+ return {
334
+ content: result.result || result.content || result.text || JSON.stringify(result),
335
+ model,
336
+ finishReason: result.is_error ? "stop" : "stop",
337
+ usage
338
+ };
339
+ }
340
+ /**
341
+ * Generate a text completion (delegates to chat)
342
+ */
343
+ async complete(prompt, options = {}) {
344
+ await this.initializeFallback();
345
+ if (this.anthropicFallback) {
346
+ return this.anthropicFallback.complete(prompt, options);
347
+ }
348
+ return this.chat([{ role: "user", content: prompt }], {
349
+ model: options.model,
350
+ maxTokens: options.maxTokens,
351
+ temperature: options.temperature,
352
+ topP: options.topP,
353
+ n: options.n,
354
+ stop: options.stop,
355
+ stream: options.stream,
356
+ onProgress: options.onProgress,
357
+ usageTags: options.usageTags
358
+ });
359
+ }
360
+ /**
361
+ * Simple message interface for single-turn interactions with optional history
362
+ *
363
+ * @param text - The message text to send
364
+ * @param options - Configuration options including history, model, etc.
365
+ * @returns Promise resolving to the response content string
366
+ *
367
+ * @example
368
+ * ```typescript
369
+ * // Simple usage
370
+ * const response = await provider.message('Hello!');
371
+ *
372
+ * // With history
373
+ * const response = await provider.message('What was my question?', {
374
+ * history: [
375
+ * { role: 'user', content: 'What is 2+2?' },
376
+ * { role: 'assistant', content: '4' }
377
+ * ]
378
+ * });
379
+ * ```
380
+ */
381
+ async message(text, options = {}) {
382
+ await this.initializeFallback();
383
+ if (this.anthropicFallback) {
384
+ return this.anthropicFallback.message(text, options);
385
+ }
386
+ const messages = [
387
+ ...options.history || [],
388
+ { role: options.role || "user", content: text }
389
+ ];
390
+ const response = await this.chat(messages, {
391
+ model: options.model,
392
+ maxTokens: options.maxTokens,
393
+ temperature: options.temperature,
394
+ topP: options.topP,
395
+ stop: options.stop,
396
+ stream: options.stream,
397
+ frequencyPenalty: options.frequencyPenalty,
398
+ presencePenalty: options.presencePenalty,
399
+ responseFormat: options.responseFormat,
400
+ seed: options.seed,
401
+ tools: options.tools,
402
+ toolChoice: options.toolChoice,
403
+ onProgress: options.onProgress,
404
+ usageTags: options.usageTags
405
+ });
406
+ return response.content;
407
+ }
408
+ /**
409
+ * Embeddings are not supported by Claude CLI or Anthropic
410
+ */
411
+ async embed(_text, _options = {}) {
412
+ throw new AIError(
413
+ "Claude CLI does not support embeddings. Use OpenAI or another provider for embeddings.",
414
+ "NOT_SUPPORTED",
415
+ "claude-cli"
416
+ );
417
+ }
418
+ /**
419
+ * Image embeddings are not supported by Claude CLI
420
+ */
421
+ async embedImage(_image, _options = {}) {
422
+ throw new AIError(
423
+ "Claude CLI does not support image embeddings. Use OpenAI or Gemini.",
424
+ "NOT_SUPPORTED",
425
+ "claude-cli"
426
+ );
427
+ }
428
+ /**
429
+ * Image description is not yet implemented for Claude CLI
430
+ * Note: Claude supports vision, but this would require significant implementation
431
+ */
432
+ async describeImage(_image, _prompt, _options = {}) {
433
+ throw new AIError(
434
+ "Image description is not yet implemented for Claude CLI. Use OpenAI or Gemini.",
435
+ "NOT_IMPLEMENTED",
436
+ "claude-cli"
437
+ );
438
+ }
439
+ /**
440
+ * Image generation is not supported by Claude
441
+ */
442
+ async generateImage(_prompt, _options = {}) {
443
+ throw new AIError(
444
+ "Claude does not support image generation. Use OpenAI or Gemini.",
445
+ "NOT_SUPPORTED",
446
+ "claude-cli"
447
+ );
448
+ }
449
+ /**
450
+ * Stream chat completion using Claude CLI
451
+ */
452
+ async *stream(messages, options = {}) {
453
+ await this.initializeFallback();
454
+ if (this.anthropicFallback) {
455
+ yield* this.anthropicFallback.stream(messages, options);
456
+ return;
457
+ }
458
+ const startTime = Date.now();
459
+ let { prompt, systemPrompt } = this.mapMessagesToPrompt(messages);
460
+ if (options.responseFormat?.type === "json_object") {
461
+ const jsonInstruction = "\n\nIMPORTANT: You must respond with valid JSON only. Do not include any explanatory text outside the JSON object.";
462
+ systemPrompt = systemPrompt ? systemPrompt + jsonInstruction : jsonInstruction.trim();
463
+ }
464
+ yield* this.executeStreamingCommand(prompt, {
465
+ model: options.model,
466
+ systemPrompt,
467
+ onProgress: options.onProgress
468
+ });
469
+ const model = options.model || this.options.defaultModel;
470
+ emitUsage(
471
+ this.options,
472
+ "claude-cli",
473
+ "stream",
474
+ model,
475
+ void 0,
476
+ startTime,
477
+ options.usageTags
478
+ );
479
+ }
480
+ /**
481
+ * Count tokens in text (approximation)
482
+ */
483
+ async countTokens(text) {
484
+ await this.initializeFallback();
485
+ if (this.anthropicFallback) {
486
+ return this.anthropicFallback.countTokens(text);
487
+ }
488
+ return Math.ceil(text.length / 3.5);
489
+ }
490
+ /**
491
+ * Get available models (static list of Claude models)
492
+ */
493
+ async getModels() {
494
+ await this.initializeFallback();
495
+ if (this.anthropicFallback) {
496
+ return this.anthropicFallback.getModels();
497
+ }
498
+ return [
499
+ {
500
+ id: "sonnet",
501
+ name: "Claude Sonnet",
502
+ description: "Balanced Claude model via CLI",
503
+ contextLength: 2e5,
504
+ capabilities: ["text", "chat", "vision"],
505
+ supportsFunctions: false,
506
+ supportsVision: false
507
+ },
508
+ {
509
+ id: "opus",
510
+ name: "Claude Opus",
511
+ description: "Most powerful Claude model via CLI",
512
+ contextLength: 2e5,
513
+ capabilities: ["text", "chat"],
514
+ supportsFunctions: false,
515
+ supportsVision: false
516
+ },
517
+ {
518
+ id: "haiku",
519
+ name: "Claude Haiku",
520
+ description: "Fast Claude model via CLI",
521
+ contextLength: 2e5,
522
+ capabilities: ["text", "chat"],
523
+ supportsFunctions: false,
524
+ supportsVision: false
525
+ }
526
+ ];
527
+ }
528
+ /**
529
+ * Get provider capabilities
530
+ */
531
+ async getCapabilities() {
532
+ await this.initializeFallback();
533
+ if (this.anthropicFallback) {
534
+ return this.anthropicFallback.getCapabilities();
535
+ }
536
+ return {
537
+ chat: true,
538
+ completion: true,
539
+ embeddings: false,
540
+ // Claude CLI doesn't support embeddings
541
+ streaming: true,
542
+ functions: false,
543
+ // Not supported via CLI
544
+ vision: false,
545
+ // Not supported in current CLI version
546
+ fineTuning: false,
547
+ imageEmbeddings: false,
548
+ imageGeneration: false,
549
+ tts: false,
550
+ voiceCloning: false,
551
+ voiceDesign: false,
552
+ maxContextLength: 2e5,
553
+ supportedOperations: ["chat", "completion", "streaming"]
554
+ };
555
+ }
556
+ // ============================================================================
557
+ // TTS Methods (Not supported - use Qwen3-TTS provider)
558
+ // ============================================================================
559
+ async synthesizeSpeech(_text, _options) {
560
+ throw new AIError(
561
+ "TTS is not supported by Claude CLI provider. Use Qwen3-TTS provider.",
562
+ "NOT_IMPLEMENTED",
563
+ "claude-cli"
564
+ );
565
+ }
566
+ streamSpeech(_text, _options) {
567
+ const error = new AIError(
568
+ "TTS streaming is not supported by Claude CLI provider. Use Qwen3-TTS provider.",
569
+ "NOT_IMPLEMENTED",
570
+ "claude-cli"
571
+ );
572
+ return {
573
+ [Symbol.asyncIterator]: () => ({
574
+ next: () => Promise.reject(error)
575
+ })
576
+ };
577
+ }
578
+ async cloneVoice(_options) {
579
+ throw new AIError(
580
+ "Voice cloning is not supported by Claude CLI provider. Use Qwen3-TTS provider.",
581
+ "NOT_IMPLEMENTED",
582
+ "claude-cli"
583
+ );
584
+ }
585
+ async designVoice(_options) {
586
+ throw new AIError(
587
+ "Voice design is not supported by Claude CLI provider. Use Qwen3-TTS provider.",
588
+ "NOT_IMPLEMENTED",
589
+ "claude-cli"
590
+ );
591
+ }
592
+ async getVoices(_options) {
593
+ throw new AIError(
594
+ "Voice listing is not supported by Claude CLI provider. Use Qwen3-TTS provider.",
595
+ "NOT_IMPLEMENTED",
596
+ "claude-cli"
597
+ );
598
+ }
599
+ }
600
+ export {
601
+ ClaudeCliProvider
602
+ };
603
+ //# sourceMappingURL=claude-cli-BrHRfkry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-cli-BrHRfkry.js","sources":["../../src/shared/providers/claude-cli.ts"],"sourcesContent":["/**\n * Claude CLI provider implementation\n *\n * Provides a standardized interface for interacting with Claude via the Claude Code CLI,\n * enabling users with Claude Max subscriptions to use their subscription instead of\n * paying for API usage. Supports chat completions and streaming responses.\n * Authentication is handled via existing Claude session or setup-token.\n *\n * **Authentication Priority:**\n * 1. ANTHROPIC_API_KEY environment variable (uses Anthropic SDK, no keychain prompts)\n * 2. Claude CLI with setup-token (for CI/CD, no keychain prompts)\n * 3. Claude CLI with keychain (may prompt for password on macOS)\n */\n\nimport { exec, spawn } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nimport type {\n AICapabilities,\n AIInterface,\n AIMessage,\n AIModel,\n AIResponse,\n ChatOptions,\n ClaudeCliOptions,\n CompletionOptions,\n EmbeddingOptions,\n EmbeddingResponse,\n ImageDescriptionOptions,\n ImageEmbeddingOptions,\n ImageGenerationOptions,\n ImageGenerationResponse,\n MessageOptions,\n TokenUsage,\n TTSOptions,\n TTSResponse,\n Voice,\n VoiceCloneOptions,\n VoiceDesignOptions,\n VoiceListOptions,\n} from '../types';\nimport {\n AIError,\n AuthenticationError,\n ContextLengthError,\n extractTextContent,\n RateLimitError,\n} from '../types';\nimport { emitUsage } from './usage';\n\nconst execAsync = promisify(exec);\n\n/**\n * Claude CLI provider implementation that shells out to the Claude Code CLI.\n * Supports chat completions, streaming, and leverages Claude Max subscription.\n * Does not support embeddings (use OpenAI or another provider for embeddings).\n *\n * If ANTHROPIC_API_KEY environment variable is set, automatically falls back to\n * using the Anthropic provider to avoid macOS keychain password prompts.\n */\nexport class ClaudeCliProvider implements AIInterface {\n private options: ClaudeCliOptions;\n private cliPath: string | null = null;\n private anthropicFallback: AIInterface | null = null;\n\n /**\n * Creates a new Claude CLI provider instance\n * @param options - Configuration options for the Claude CLI provider\n */\n constructor(options: ClaudeCliOptions) {\n this.options = {\n defaultModel: 'sonnet',\n ...options,\n };\n }\n\n /**\n * Checks if ANTHROPIC_API_KEY is available and initializes fallback provider if needed\n * @private\n */\n private async initializeFallback(): Promise<void> {\n if (this.anthropicFallback !== null) {\n return; // Already initialized\n }\n\n const apiKey = process.env.ANTHROPIC_API_KEY;\n if (!apiKey) {\n return; // No API key, will use CLI\n }\n\n // Lazy load Anthropic provider to avoid circular dependency\n const { AnthropicProvider } = await import('./anthropic.js');\n\n // Map claude-cli model names to Anthropic model IDs\n const modelMap: Record<string, string> = {\n sonnet: 'claude-3-5-sonnet-20241022',\n opus: 'claude-3-opus-20240229',\n haiku: 'claude-3-haiku-20240307',\n };\n\n const defaultModel =\n modelMap[this.options.defaultModel || 'sonnet'] ||\n 'claude-3-5-sonnet-20241022';\n\n this.anthropicFallback = new AnthropicProvider({\n type: 'anthropic',\n apiKey,\n defaultModel,\n onUsage: this.options.onUsage,\n usageTags: this.options.usageTags,\n });\n }\n\n /**\n * Finds the Claude CLI binary in PATH or uses custom cliPath\n * Does NOT execute the CLI during detection to avoid keychain prompts\n * @throws {AIError} When CLI cannot be found\n * @private\n */\n private async findCli(): Promise<string> {\n if (this.cliPath) {\n return this.cliPath;\n }\n\n // If custom path provided, check if it exists (don't execute it)\n if (this.options.cliPath) {\n const fs = await import('node:fs/promises');\n try {\n await fs.access(this.options.cliPath);\n this.cliPath = this.options.cliPath;\n return this.cliPath;\n } catch (_error) {\n throw new AIError(\n `Claude CLI not found at specified path: ${this.options.cliPath}. Set ANTHROPIC_API_KEY environment variable to avoid CLI dependency.`,\n 'CLI_NOT_FOUND',\n 'claude-cli',\n );\n }\n }\n\n // Try common installation locations first\n const commonPaths = [\n `${process.env.HOME}/.claude/local/claude`, // Default installation path\n '/usr/local/bin/claude',\n '/opt/homebrew/bin/claude',\n ];\n\n const fs = await import('node:fs/promises');\n for (const path of commonPaths) {\n try {\n await fs.access(path);\n this.cliPath = path;\n return this.cliPath;\n } catch (_error) {\n // Try next path\n }\n }\n\n // Try to find in PATH with which (doesn't execute the binary)\n try {\n const { stdout } = await execAsync('which claude');\n const path = stdout.trim();\n if (path) {\n this.cliPath = path;\n return this.cliPath;\n }\n } catch (_error) {\n // Not found\n }\n\n throw new AIError(\n 'Claude CLI not found. Set ANTHROPIC_API_KEY environment variable to use Anthropic SDK instead, or install Claude Code CLI. Visit https://docs.claude.com/en/docs/claude-code/ for installation instructions.',\n 'CLI_NOT_FOUND',\n 'claude-cli',\n );\n }\n\n /**\n * Normalizes model name to full model ID or short name\n * @private\n */\n private normalizeModel(model?: string): string {\n const m = model || this.options.defaultModel || 'sonnet';\n\n // Map short names to CLI-compatible values\n const modelMap: Record<string, string> = {\n sonnet: 'sonnet',\n opus: 'opus',\n haiku: 'haiku',\n };\n\n return modelMap[m] || m;\n }\n\n /**\n * Execute Claude CLI command and return parsed JSON output\n * @private\n */\n private async executeCommand(\n prompt: string,\n options: {\n model?: string;\n systemPrompt?: string;\n temperature?: number;\n maxTokens?: number;\n } = {},\n ): Promise<any> {\n const cliPath = await this.findCli();\n const model = this.normalizeModel(options.model);\n\n const args = ['--print', '--output-format', 'json', '--model', model];\n\n if (options.systemPrompt) {\n args.push('--system-prompt', options.systemPrompt);\n }\n\n args.push(prompt);\n\n return new Promise((resolve, reject) => {\n let stdout = '';\n let stderr = '';\n\n const child = spawn(cliPath, args, {\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n child.stdout.on('data', (data) => {\n stdout += data.toString();\n });\n\n child.stderr.on('data', (data) => {\n stderr += data.toString();\n });\n\n child.on('error', (error) => {\n reject(\n new AIError(\n `Failed to execute Claude CLI: ${error.message}`,\n 'EXECUTION_ERROR',\n 'claude-cli',\n ),\n );\n });\n\n child.on('close', (code) => {\n if (code !== 0) {\n reject(this.mapCliError(stderr, code || undefined));\n return;\n }\n\n try {\n // Parse JSON output\n const result = JSON.parse(stdout);\n resolve(result);\n } catch (_error) {\n reject(\n new AIError(\n 'Failed to parse CLI output as JSON',\n 'PARSE_ERROR',\n 'claude-cli',\n ),\n );\n }\n });\n });\n }\n\n /**\n * Execute Claude CLI command with streaming output\n * @private\n */\n private async *executeStreamingCommand(\n prompt: string,\n options: {\n model?: string;\n systemPrompt?: string;\n onProgress?: (chunk: string) => void;\n } = {},\n ): AsyncIterable<string> {\n const cliPath = await this.findCli();\n const model = this.normalizeModel(options.model);\n\n const args = [\n '--print',\n '--output-format',\n 'stream-json',\n '--verbose', // Required for stream-json format\n '--model',\n model,\n ];\n\n if (options.systemPrompt) {\n args.push('--system-prompt', options.systemPrompt);\n }\n\n args.push(prompt);\n\n const child = spawn(cliPath, args, {\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n let stderr = '';\n\n child.stderr.on('data', (data) => {\n stderr += data.toString();\n });\n\n // Process streaming JSON chunks\n let buffer = '';\n\n for await (const chunk of child.stdout) {\n buffer += chunk.toString();\n\n // Process complete JSON objects (one per line)\n const lines = buffer.split('\\n');\n buffer = lines.pop() || ''; // Keep incomplete line in buffer\n\n for (const line of lines) {\n if (line.trim()) {\n try {\n const parsed = JSON.parse(line);\n // Claude CLI stream-json format outputs complete messages\n // Look for assistant message with content\n if (parsed.type === 'assistant' && parsed.message?.content) {\n for (const contentBlock of parsed.message.content) {\n if (contentBlock.type === 'text' && contentBlock.text) {\n const text = contentBlock.text;\n if (options.onProgress) {\n options.onProgress(text);\n }\n yield text;\n }\n }\n }\n // Also handle result type for final output\n else if (parsed.type === 'result' && parsed.result) {\n const text = parsed.result;\n if (options.onProgress) {\n options.onProgress(text);\n }\n yield text;\n }\n } catch (_error) {\n // Skip malformed JSON lines\n }\n }\n }\n }\n\n // Wait for process to complete\n const exitCode = await new Promise<number>((resolve) => {\n child.on('close', (code) => resolve(code || 0));\n });\n\n if (exitCode !== 0) {\n throw this.mapCliError(stderr, exitCode);\n }\n }\n\n /**\n * Maps messages to a single prompt for CLI\n * @private\n */\n private mapMessagesToPrompt(messages: AIMessage[]): {\n prompt: string;\n systemPrompt?: string;\n } {\n let systemPrompt: string | undefined;\n const conversationParts: string[] = [];\n\n for (const message of messages) {\n const textContent = extractTextContent(message.content);\n if (message.role === 'system') {\n systemPrompt = systemPrompt\n ? `${systemPrompt}\\n\\n${textContent}`\n : textContent;\n } else if (message.role === 'user') {\n conversationParts.push(`User: ${textContent}`);\n } else if (message.role === 'assistant') {\n conversationParts.push(`Assistant: ${textContent}`);\n }\n }\n\n // If only one user message and no conversation, return it directly\n if (\n conversationParts.length === 1 &&\n conversationParts[0].startsWith('User: ')\n ) {\n return {\n prompt: conversationParts[0].substring(6), // Remove \"User: \" prefix\n systemPrompt,\n };\n }\n\n return {\n prompt: conversationParts.join('\\n\\n'),\n systemPrompt,\n };\n }\n\n /**\n * Maps CLI errors to standardized error types\n * @private\n */\n\n private mapCliError(stderr: string, exitCode?: number): AIError {\n const errorText = stderr.toLowerCase();\n\n // Authentication errors\n if (\n errorText.includes('not authenticated') ||\n errorText.includes('login required')\n ) {\n return new AuthenticationError('claude-cli');\n }\n\n // Rate limiting\n if (\n errorText.includes('rate limit') ||\n errorText.includes('too many requests')\n ) {\n return new RateLimitError('claude-cli');\n }\n\n // Context length\n if (\n errorText.includes('context length') ||\n errorText.includes('too long')\n ) {\n return new ContextLengthError('claude-cli');\n }\n\n return new AIError(\n `Claude CLI error (exit code ${exitCode}): ${stderr}`,\n 'CLI_ERROR',\n 'claude-cli',\n );\n }\n\n /**\n * Generate a chat completion using Claude CLI\n * @param messages - Array of conversation messages\n * @param options - Optional configuration for the chat completion\n * @returns Promise resolving to the AI response with content and metadata\n * @throws {AIError} When the CLI execution fails\n *\n * @example\n * ```typescript\n * const response = await provider.chat([\n * { role: 'system', content: 'You are a helpful assistant.' },\n * { role: 'user', content: 'Explain quantum computing' }\n * ], {\n * model: 'sonnet'\n * });\n * ```\n */\n async chat(\n messages: AIMessage[],\n options: ChatOptions = {},\n ): Promise<AIResponse> {\n // Check if ANTHROPIC_API_KEY is available and use fallback if so\n await this.initializeFallback();\n if (this.anthropicFallback) {\n return this.anthropicFallback.chat(messages, options);\n }\n\n const startTime = Date.now();\n let { prompt, systemPrompt } = this.mapMessagesToPrompt(messages);\n\n // Add JSON format instruction if requested\n if (options.responseFormat?.type === 'json_object') {\n const jsonInstruction =\n '\\n\\nIMPORTANT: You must respond with valid JSON only. Do not include any explanatory text outside the JSON object.';\n systemPrompt = systemPrompt\n ? systemPrompt + jsonInstruction\n : jsonInstruction.trim();\n }\n\n const result = await this.executeCommand(prompt, {\n model: options.model,\n systemPrompt,\n temperature: options.temperature,\n maxTokens: options.maxTokens,\n });\n\n const model = options.model || this.options.defaultModel;\n const usage: TokenUsage | undefined = result.usage\n ? {\n promptTokens: result.usage.input_tokens || 0,\n completionTokens: result.usage.output_tokens || 0,\n totalTokens:\n (result.usage.input_tokens || 0) +\n (result.usage.output_tokens || 0),\n }\n : undefined;\n\n emitUsage(\n this.options,\n 'claude-cli',\n 'chat',\n model!,\n usage,\n startTime,\n options.usageTags,\n );\n\n // Parse Claude CLI JSON output\n return {\n content:\n result.result ||\n result.content ||\n result.text ||\n JSON.stringify(result),\n model,\n finishReason: result.is_error ? 'stop' : 'stop',\n usage,\n };\n }\n\n /**\n * Generate a text completion (delegates to chat)\n */\n async complete(\n prompt: string,\n options: CompletionOptions = {},\n ): Promise<AIResponse> {\n // Check if ANTHROPIC_API_KEY is available and use fallback if so\n await this.initializeFallback();\n if (this.anthropicFallback) {\n return this.anthropicFallback.complete(prompt, options);\n }\n\n return this.chat([{ role: 'user', content: prompt }], {\n model: options.model,\n maxTokens: options.maxTokens,\n temperature: options.temperature,\n topP: options.topP,\n n: options.n,\n stop: options.stop,\n stream: options.stream,\n onProgress: options.onProgress,\n usageTags: options.usageTags,\n });\n }\n\n /**\n * Simple message interface for single-turn interactions with optional history\n *\n * @param text - The message text to send\n * @param options - Configuration options including history, model, etc.\n * @returns Promise resolving to the response content string\n *\n * @example\n * ```typescript\n * // Simple usage\n * const response = await provider.message('Hello!');\n *\n * // With history\n * const response = await provider.message('What was my question?', {\n * history: [\n * { role: 'user', content: 'What is 2+2?' },\n * { role: 'assistant', content: '4' }\n * ]\n * });\n * ```\n */\n async message(text: string, options: MessageOptions = {}): Promise<string> {\n // Check if ANTHROPIC_API_KEY is available and use fallback if so\n await this.initializeFallback();\n if (this.anthropicFallback) {\n return this.anthropicFallback.message(text, options);\n }\n\n // Build messages array from history + current message\n const messages: AIMessage[] = [\n ...(options.history || []),\n { role: options.role || 'user', content: text },\n ];\n\n const response = await this.chat(messages, {\n model: options.model,\n maxTokens: options.maxTokens,\n temperature: options.temperature,\n topP: options.topP,\n stop: options.stop,\n stream: options.stream,\n frequencyPenalty: options.frequencyPenalty,\n presencePenalty: options.presencePenalty,\n responseFormat: options.responseFormat,\n seed: options.seed,\n tools: options.tools,\n toolChoice: options.toolChoice,\n onProgress: options.onProgress,\n usageTags: options.usageTags,\n });\n\n return response.content;\n }\n\n /**\n * Embeddings are not supported by Claude CLI or Anthropic\n */\n async embed(\n _text: string | string[],\n _options: EmbeddingOptions = {},\n ): Promise<EmbeddingResponse> {\n // Note: Even with fallback, Anthropic doesn't support embeddings\n throw new AIError(\n 'Claude CLI does not support embeddings. Use OpenAI or another provider for embeddings.',\n 'NOT_SUPPORTED',\n 'claude-cli',\n );\n }\n\n /**\n * Image embeddings are not supported by Claude CLI\n */\n async embedImage(\n _image: string | Buffer,\n _options: ImageEmbeddingOptions = {},\n ): Promise<EmbeddingResponse> {\n throw new AIError(\n 'Claude CLI does not support image embeddings. Use OpenAI or Gemini.',\n 'NOT_SUPPORTED',\n 'claude-cli',\n );\n }\n\n /**\n * Image description is not yet implemented for Claude CLI\n * Note: Claude supports vision, but this would require significant implementation\n */\n async describeImage(\n _image: string | Buffer,\n _prompt?: string,\n _options: ImageDescriptionOptions = {},\n ): Promise<string> {\n throw new AIError(\n 'Image description is not yet implemented for Claude CLI. Use OpenAI or Gemini.',\n 'NOT_IMPLEMENTED',\n 'claude-cli',\n );\n }\n\n /**\n * Image generation is not supported by Claude\n */\n async generateImage(\n _prompt: string,\n _options: ImageGenerationOptions = {},\n ): Promise<ImageGenerationResponse> {\n throw new AIError(\n 'Claude does not support image generation. Use OpenAI or Gemini.',\n 'NOT_SUPPORTED',\n 'claude-cli',\n );\n }\n\n /**\n * Stream chat completion using Claude CLI\n */\n async *stream(\n messages: AIMessage[],\n options: ChatOptions = {},\n ): AsyncIterable<string> {\n // Check if ANTHROPIC_API_KEY is available and use fallback if so\n await this.initializeFallback();\n if (this.anthropicFallback) {\n yield* this.anthropicFallback.stream(messages, options);\n return;\n }\n\n const startTime = Date.now();\n let { prompt, systemPrompt } = this.mapMessagesToPrompt(messages);\n\n // Add JSON format instruction if requested\n if (options.responseFormat?.type === 'json_object') {\n const jsonInstruction =\n '\\n\\nIMPORTANT: You must respond with valid JSON only. Do not include any explanatory text outside the JSON object.';\n systemPrompt = systemPrompt\n ? systemPrompt + jsonInstruction\n : jsonInstruction.trim();\n }\n\n yield* this.executeStreamingCommand(prompt, {\n model: options.model,\n systemPrompt,\n onProgress: options.onProgress,\n });\n\n const model = options.model || this.options.defaultModel;\n emitUsage(\n this.options,\n 'claude-cli',\n 'stream',\n model!,\n undefined,\n startTime,\n options.usageTags,\n );\n }\n\n /**\n * Count tokens in text (approximation)\n */\n async countTokens(text: string): Promise<number> {\n // Check if ANTHROPIC_API_KEY is available and use fallback if so\n await this.initializeFallback();\n if (this.anthropicFallback) {\n return this.anthropicFallback.countTokens(text);\n }\n\n // Claude uses a different tokenizer, approximate similar to Anthropic\n return Math.ceil(text.length / 3.5);\n }\n\n /**\n * Get available models (static list of Claude models)\n */\n async getModels(): Promise<AIModel[]> {\n // Check if ANTHROPIC_API_KEY is available and use fallback if so\n await this.initializeFallback();\n if (this.anthropicFallback) {\n return this.anthropicFallback.getModels();\n }\n\n return [\n {\n id: 'sonnet',\n name: 'Claude Sonnet',\n description: 'Balanced Claude model via CLI',\n contextLength: 200000,\n capabilities: ['text', 'chat', 'vision'],\n supportsFunctions: false,\n supportsVision: false,\n },\n {\n id: 'opus',\n name: 'Claude Opus',\n description: 'Most powerful Claude model via CLI',\n contextLength: 200000,\n capabilities: ['text', 'chat'],\n supportsFunctions: false,\n supportsVision: false,\n },\n {\n id: 'haiku',\n name: 'Claude Haiku',\n description: 'Fast Claude model via CLI',\n contextLength: 200000,\n capabilities: ['text', 'chat'],\n supportsFunctions: false,\n supportsVision: false,\n },\n ];\n }\n\n /**\n * Get provider capabilities\n */\n async getCapabilities(): Promise<AICapabilities> {\n // Check if ANTHROPIC_API_KEY is available and use fallback if so\n await this.initializeFallback();\n if (this.anthropicFallback) {\n return this.anthropicFallback.getCapabilities();\n }\n\n return {\n chat: true,\n completion: true,\n embeddings: false, // Claude CLI doesn't support embeddings\n streaming: true,\n functions: false, // Not supported via CLI\n vision: false, // Not supported in current CLI version\n fineTuning: false,\n imageEmbeddings: false,\n imageGeneration: false,\n tts: false,\n voiceCloning: false,\n voiceDesign: false,\n maxContextLength: 200000,\n supportedOperations: ['chat', 'completion', 'streaming'],\n };\n }\n\n // ============================================================================\n // TTS Methods (Not supported - use Qwen3-TTS provider)\n // ============================================================================\n\n async synthesizeSpeech(\n _text: string,\n _options?: TTSOptions,\n ): Promise<TTSResponse> {\n throw new AIError(\n 'TTS is not supported by Claude CLI provider. Use Qwen3-TTS provider.',\n 'NOT_IMPLEMENTED',\n 'claude-cli',\n );\n }\n\n streamSpeech(_text: string, _options?: TTSOptions): AsyncIterable<Buffer> {\n const error = new AIError(\n 'TTS streaming is not supported by Claude CLI provider. Use Qwen3-TTS provider.',\n 'NOT_IMPLEMENTED',\n 'claude-cli',\n );\n return {\n [Symbol.asyncIterator]: () => ({\n next: () => Promise.reject(error),\n }),\n };\n }\n\n async cloneVoice(_options: VoiceCloneOptions): Promise<Voice> {\n throw new AIError(\n 'Voice cloning is not supported by Claude CLI provider. Use Qwen3-TTS provider.',\n 'NOT_IMPLEMENTED',\n 'claude-cli',\n );\n }\n\n async designVoice(_options: VoiceDesignOptions): Promise<Voice> {\n throw new AIError(\n 'Voice design is not supported by Claude CLI provider. Use Qwen3-TTS provider.',\n 'NOT_IMPLEMENTED',\n 'claude-cli',\n );\n }\n\n async getVoices(_options?: VoiceListOptions): Promise<Voice[]> {\n throw new AIError(\n 'Voice listing is not supported by Claude CLI provider. Use Qwen3-TTS provider.',\n 'NOT_IMPLEMENTED',\n 'claude-cli',\n );\n }\n}\n"],"names":["fs"],"mappings":"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"}