snow-ai 0.2.24 → 0.2.26

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 (46) hide show
  1. package/dist/api/chat.d.ts +0 -8
  2. package/dist/api/chat.js +1 -144
  3. package/dist/api/responses.d.ts +0 -11
  4. package/dist/api/responses.js +1 -189
  5. package/dist/api/systemPrompt.d.ts +1 -1
  6. package/dist/api/systemPrompt.js +90 -295
  7. package/dist/app.d.ts +2 -1
  8. package/dist/app.js +11 -13
  9. package/dist/cli.js +16 -3
  10. package/dist/hooks/useClipboard.js +4 -4
  11. package/dist/hooks/useGlobalNavigation.d.ts +1 -1
  12. package/dist/hooks/useKeyboardInput.d.ts +1 -0
  13. package/dist/hooks/useKeyboardInput.js +8 -4
  14. package/dist/hooks/useTerminalFocus.d.ts +5 -0
  15. package/dist/hooks/useTerminalFocus.js +22 -2
  16. package/dist/mcp/aceCodeSearch.d.ts +58 -4
  17. package/dist/mcp/aceCodeSearch.js +563 -20
  18. package/dist/mcp/filesystem.d.ts +59 -10
  19. package/dist/mcp/filesystem.js +431 -124
  20. package/dist/mcp/ideDiagnostics.d.ts +36 -0
  21. package/dist/mcp/ideDiagnostics.js +92 -0
  22. package/dist/ui/components/ChatInput.js +6 -3
  23. package/dist/ui/pages/ChatScreen.d.ts +4 -2
  24. package/dist/ui/pages/ChatScreen.js +31 -2
  25. package/dist/ui/pages/ConfigProfileScreen.d.ts +7 -0
  26. package/dist/ui/pages/ConfigProfileScreen.js +300 -0
  27. package/dist/ui/pages/{ApiConfigScreen.d.ts → ConfigScreen.d.ts} +1 -1
  28. package/dist/ui/pages/ConfigScreen.js +748 -0
  29. package/dist/ui/pages/WelcomeScreen.js +7 -18
  30. package/dist/utils/apiConfig.d.ts +0 -2
  31. package/dist/utils/apiConfig.js +12 -0
  32. package/dist/utils/configManager.d.ts +45 -0
  33. package/dist/utils/configManager.js +274 -0
  34. package/dist/utils/contextCompressor.js +355 -49
  35. package/dist/utils/escapeHandler.d.ts +79 -0
  36. package/dist/utils/escapeHandler.js +153 -0
  37. package/dist/utils/incrementalSnapshot.js +2 -1
  38. package/dist/utils/mcpToolsManager.js +44 -0
  39. package/dist/utils/retryUtils.js +6 -0
  40. package/dist/utils/textBuffer.js +13 -15
  41. package/dist/utils/vscodeConnection.js +26 -11
  42. package/dist/utils/workspaceSnapshot.js +2 -1
  43. package/package.json +2 -1
  44. package/dist/ui/pages/ApiConfigScreen.js +0 -161
  45. package/dist/ui/pages/ModelConfigScreen.d.ts +0 -8
  46. package/dist/ui/pages/ModelConfigScreen.js +0 -504
@@ -0,0 +1,748 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { Box, Text, useInput } from 'ink';
3
+ import Gradient from 'ink-gradient';
4
+ import { Select, Alert, Spinner } from '@inkjs/ui';
5
+ import TextInput from 'ink-text-input';
6
+ import chalk from 'chalk';
7
+ import { getOpenAiConfig, updateOpenAiConfig, validateApiConfig, } from '../../utils/apiConfig.js';
8
+ import { fetchAvailableModels, filterModels, } from '../../api/models.js';
9
+ import { getActiveProfileName, getAllProfiles, switchProfile, createProfile, deleteProfile, saveProfile, } from '../../utils/configManager.js';
10
+ const focusEventTokenRegex = /(?:\x1b)?\[[0-9;]*[IO]/g;
11
+ const isFocusEventInput = (value) => {
12
+ if (!value) {
13
+ return false;
14
+ }
15
+ if (value === '\x1b[I' ||
16
+ value === '\x1b[O' ||
17
+ value === '[I' ||
18
+ value === '[O') {
19
+ return true;
20
+ }
21
+ const trimmed = value.trim();
22
+ if (!trimmed) {
23
+ return false;
24
+ }
25
+ const tokens = trimmed.match(focusEventTokenRegex);
26
+ if (!tokens) {
27
+ return false;
28
+ }
29
+ const normalized = trimmed.replace(/\s+/g, '');
30
+ const tokensCombined = tokens.join('');
31
+ return tokensCombined === normalized;
32
+ };
33
+ const stripFocusArtifacts = (value) => {
34
+ if (!value) {
35
+ return '';
36
+ }
37
+ return value
38
+ .replace(/\x1b\[[0-9;]*[IO]/g, '')
39
+ .replace(/\[[0-9;]*[IO]/g, '')
40
+ .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '');
41
+ };
42
+ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
43
+ // Profile management
44
+ const [profiles, setProfiles] = useState([]);
45
+ const [activeProfile, setActiveProfile] = useState('');
46
+ const [profileMode, setProfileMode] = useState('normal');
47
+ const [newProfileName, setNewProfileName] = useState('');
48
+ // API settings
49
+ const [baseUrl, setBaseUrl] = useState('');
50
+ const [apiKey, setApiKey] = useState('');
51
+ const [requestMethod, setRequestMethod] = useState('chat');
52
+ const [anthropicBeta, setAnthropicBeta] = useState(false);
53
+ // Model settings
54
+ const [advancedModel, setAdvancedModel] = useState('');
55
+ const [basicModel, setBasicModel] = useState('');
56
+ const [maxContextTokens, setMaxContextTokens] = useState(4000);
57
+ const [maxTokens, setMaxTokens] = useState(4096);
58
+ const [compactModelName, setCompactModelName] = useState('');
59
+ // UI state
60
+ const [currentField, setCurrentField] = useState('profile');
61
+ const [errors, setErrors] = useState([]);
62
+ const [isEditing, setIsEditing] = useState(false);
63
+ const [models, setModels] = useState([]);
64
+ const [loading, setLoading] = useState(false);
65
+ const [loadError, setLoadError] = useState('');
66
+ const [searchTerm, setSearchTerm] = useState('');
67
+ const [manualInputMode, setManualInputMode] = useState(false);
68
+ const [manualInputValue, setManualInputValue] = useState('');
69
+ const requestMethodOptions = [
70
+ {
71
+ label: 'Chat Completions - Modern chat API (GPT-4, GPT-3.5-turbo)',
72
+ value: 'chat',
73
+ },
74
+ {
75
+ label: 'Responses - New responses API (2025, with built-in tools)',
76
+ value: 'responses',
77
+ },
78
+ {
79
+ label: 'Gemini - Google Gemini API',
80
+ value: 'gemini',
81
+ },
82
+ {
83
+ label: 'Anthropic - Claude API',
84
+ value: 'anthropic',
85
+ },
86
+ ];
87
+ useEffect(() => {
88
+ loadProfilesAndConfig();
89
+ }, []);
90
+ const loadProfilesAndConfig = () => {
91
+ // Load profiles
92
+ const loadedProfiles = getAllProfiles();
93
+ setProfiles(loadedProfiles);
94
+ // Load current config
95
+ const config = getOpenAiConfig();
96
+ setBaseUrl(config.baseUrl);
97
+ setApiKey(config.apiKey);
98
+ setRequestMethod(config.requestMethod || 'chat');
99
+ setAnthropicBeta(config.anthropicBeta || false);
100
+ setAdvancedModel(config.advancedModel || '');
101
+ setBasicModel(config.basicModel || '');
102
+ setMaxContextTokens(config.maxContextTokens || 4000);
103
+ setMaxTokens(config.maxTokens || 4096);
104
+ setCompactModelName(config.compactModel?.modelName || '');
105
+ setActiveProfile(getActiveProfileName());
106
+ };
107
+ const loadModels = async () => {
108
+ setLoading(true);
109
+ setLoadError('');
110
+ // Temporarily save current config to use the latest baseUrl/apiKey
111
+ const tempConfig = {
112
+ baseUrl,
113
+ apiKey,
114
+ requestMethod,
115
+ };
116
+ updateOpenAiConfig(tempConfig);
117
+ try {
118
+ const fetchedModels = await fetchAvailableModels();
119
+ setModels(fetchedModels);
120
+ }
121
+ catch (err) {
122
+ const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
123
+ setLoadError(errorMessage);
124
+ throw err;
125
+ }
126
+ finally {
127
+ setLoading(false);
128
+ }
129
+ };
130
+ const getCurrentOptions = () => {
131
+ const filteredModels = filterModels(models, searchTerm);
132
+ const modelOptions = filteredModels.map(model => ({
133
+ label: model.id,
134
+ value: model.id,
135
+ }));
136
+ return [
137
+ { label: 'Manual Input (Enter model name)', value: '__MANUAL_INPUT__' },
138
+ ...modelOptions,
139
+ ];
140
+ };
141
+ const getCurrentValue = () => {
142
+ if (currentField === 'profile')
143
+ return activeProfile;
144
+ if (currentField === 'baseUrl')
145
+ return baseUrl;
146
+ if (currentField === 'apiKey')
147
+ return apiKey;
148
+ if (currentField === 'advancedModel')
149
+ return advancedModel;
150
+ if (currentField === 'basicModel')
151
+ return basicModel;
152
+ if (currentField === 'maxContextTokens')
153
+ return maxContextTokens.toString();
154
+ if (currentField === 'maxTokens')
155
+ return maxTokens.toString();
156
+ if (currentField === 'compactModelName')
157
+ return compactModelName;
158
+ return '';
159
+ };
160
+ const handleProfileChange = (value) => {
161
+ if (value === '__CREATE_NEW__') {
162
+ setProfileMode('creating');
163
+ setNewProfileName('');
164
+ return;
165
+ }
166
+ if (value === '__DELETE__') {
167
+ if (activeProfile === 'default') {
168
+ setErrors(['Cannot delete the default profile']);
169
+ return;
170
+ }
171
+ setProfileMode('deleting');
172
+ return;
173
+ }
174
+ // Switch profile
175
+ try {
176
+ switchProfile(value);
177
+ loadProfilesAndConfig();
178
+ setIsEditing(false);
179
+ setErrors([]);
180
+ }
181
+ catch (err) {
182
+ setErrors([
183
+ err instanceof Error ? err.message : 'Failed to switch profile',
184
+ ]);
185
+ }
186
+ };
187
+ const handleCreateProfile = () => {
188
+ const cleaned = stripFocusArtifacts(newProfileName).trim();
189
+ if (!cleaned) {
190
+ setErrors(['Profile name cannot be empty']);
191
+ return;
192
+ }
193
+ try {
194
+ // Create new profile with current config
195
+ const currentConfig = {
196
+ snowcfg: {
197
+ baseUrl,
198
+ apiKey,
199
+ requestMethod,
200
+ anthropicBeta,
201
+ advancedModel,
202
+ basicModel,
203
+ maxContextTokens,
204
+ maxTokens,
205
+ compactModel: compactModelName ? { modelName: compactModelName } : undefined,
206
+ },
207
+ };
208
+ createProfile(cleaned, currentConfig);
209
+ switchProfile(cleaned);
210
+ loadProfilesAndConfig();
211
+ setProfileMode('normal');
212
+ setNewProfileName('');
213
+ setIsEditing(false);
214
+ setErrors([]);
215
+ }
216
+ catch (err) {
217
+ setErrors([
218
+ err instanceof Error ? err.message : 'Failed to create profile',
219
+ ]);
220
+ }
221
+ };
222
+ const handleDeleteProfile = () => {
223
+ try {
224
+ deleteProfile(activeProfile);
225
+ loadProfilesAndConfig();
226
+ setProfileMode('normal');
227
+ setIsEditing(false);
228
+ setErrors([]);
229
+ }
230
+ catch (err) {
231
+ setErrors([
232
+ err instanceof Error ? err.message : 'Failed to delete profile',
233
+ ]);
234
+ setProfileMode('normal');
235
+ }
236
+ };
237
+ const handleModelChange = (value) => {
238
+ if (value === '__MANUAL_INPUT__') {
239
+ setManualInputMode(true);
240
+ setManualInputValue('');
241
+ return;
242
+ }
243
+ if (currentField === 'advancedModel') {
244
+ setAdvancedModel(value);
245
+ }
246
+ else if (currentField === 'basicModel') {
247
+ setBasicModel(value);
248
+ }
249
+ else if (currentField === 'compactModelName') {
250
+ setCompactModelName(value);
251
+ }
252
+ setIsEditing(false);
253
+ setSearchTerm('');
254
+ };
255
+ const saveConfiguration = () => {
256
+ const validationErrors = validateApiConfig({
257
+ baseUrl,
258
+ apiKey,
259
+ requestMethod,
260
+ });
261
+ if (validationErrors.length === 0) {
262
+ const config = {
263
+ baseUrl,
264
+ apiKey,
265
+ requestMethod,
266
+ anthropicBeta,
267
+ advancedModel,
268
+ basicModel,
269
+ maxContextTokens,
270
+ maxTokens,
271
+ };
272
+ // Only save compactModel if modelName is provided (uses same baseUrl/apiKey)
273
+ if (compactModelName) {
274
+ config.compactModel = {
275
+ modelName: compactModelName,
276
+ };
277
+ }
278
+ // Save to main config
279
+ updateOpenAiConfig(config);
280
+ // Also save to the current profile
281
+ try {
282
+ const fullConfig = {
283
+ snowcfg: {
284
+ baseUrl,
285
+ apiKey,
286
+ requestMethod,
287
+ anthropicBeta,
288
+ advancedModel,
289
+ basicModel,
290
+ maxContextTokens,
291
+ maxTokens,
292
+ compactModel: compactModelName
293
+ ? { modelName: compactModelName }
294
+ : undefined,
295
+ },
296
+ };
297
+ saveProfile(activeProfile, fullConfig);
298
+ }
299
+ catch (err) {
300
+ console.error('Failed to save profile:', err);
301
+ }
302
+ setErrors([]);
303
+ return true;
304
+ }
305
+ else {
306
+ setErrors(validationErrors);
307
+ return false;
308
+ }
309
+ };
310
+ useInput((rawInput, key) => {
311
+ const input = stripFocusArtifacts(rawInput);
312
+ if (!input && isFocusEventInput(rawInput)) {
313
+ return;
314
+ }
315
+ if (isFocusEventInput(rawInput)) {
316
+ return;
317
+ }
318
+ // Handle profile creation mode
319
+ if (profileMode === 'creating') {
320
+ if (key.return) {
321
+ handleCreateProfile();
322
+ }
323
+ else if (key.escape) {
324
+ setProfileMode('normal');
325
+ setNewProfileName('');
326
+ setErrors([]);
327
+ }
328
+ return;
329
+ }
330
+ // Handle profile deletion confirmation
331
+ if (profileMode === 'deleting') {
332
+ if (input === 'y' || input === 'Y') {
333
+ handleDeleteProfile();
334
+ }
335
+ else if (input === 'n' || input === 'N' || key.escape) {
336
+ setProfileMode('normal');
337
+ setErrors([]);
338
+ }
339
+ return;
340
+ }
341
+ // Handle loading state
342
+ if (loading) {
343
+ if (key.escape) {
344
+ setLoading(false);
345
+ }
346
+ return;
347
+ }
348
+ // Handle manual input mode
349
+ if (manualInputMode) {
350
+ if (key.return) {
351
+ const cleaned = stripFocusArtifacts(manualInputValue).trim();
352
+ if (cleaned) {
353
+ if (currentField === 'advancedModel') {
354
+ setAdvancedModel(cleaned);
355
+ }
356
+ else if (currentField === 'basicModel') {
357
+ setBasicModel(cleaned);
358
+ }
359
+ else if (currentField === 'compactModelName') {
360
+ setCompactModelName(cleaned);
361
+ }
362
+ }
363
+ setManualInputMode(false);
364
+ setManualInputValue('');
365
+ setIsEditing(false);
366
+ setSearchTerm('');
367
+ }
368
+ else if (key.escape) {
369
+ setManualInputMode(false);
370
+ setManualInputValue('');
371
+ }
372
+ else if (key.backspace || key.delete) {
373
+ setManualInputValue(prev => prev.slice(0, -1));
374
+ }
375
+ else if (input && input.match(/[a-zA-Z0-9-_./:]/)) {
376
+ setManualInputValue(prev => prev + stripFocusArtifacts(input));
377
+ }
378
+ return;
379
+ }
380
+ // Allow Escape key to exit Select component
381
+ if (isEditing &&
382
+ (currentField === 'profile' ||
383
+ currentField === 'requestMethod' ||
384
+ currentField === 'advancedModel' ||
385
+ currentField === 'basicModel' ||
386
+ currentField === 'compactModelName') &&
387
+ key.escape) {
388
+ setIsEditing(false);
389
+ setSearchTerm('');
390
+ return;
391
+ }
392
+ // Handle editing mode
393
+ if (isEditing) {
394
+ // For baseUrl and apiKey, TextInput component handles all input, just handle Return to exit
395
+ if (currentField === 'baseUrl' || currentField === 'apiKey') {
396
+ if (key.return) {
397
+ setIsEditing(false);
398
+ }
399
+ return;
400
+ }
401
+ // Handle numeric input for token fields
402
+ if (currentField === 'maxContextTokens' || currentField === 'maxTokens') {
403
+ if (input && input.match(/[0-9]/)) {
404
+ const currentValue = currentField === 'maxContextTokens' ? maxContextTokens : maxTokens;
405
+ const newValue = parseInt(currentValue.toString() + input, 10);
406
+ if (!isNaN(newValue)) {
407
+ if (currentField === 'maxContextTokens') {
408
+ setMaxContextTokens(newValue);
409
+ }
410
+ else {
411
+ setMaxTokens(newValue);
412
+ }
413
+ }
414
+ }
415
+ else if (key.backspace || key.delete) {
416
+ const currentValue = currentField === 'maxContextTokens' ? maxContextTokens : maxTokens;
417
+ const currentStr = currentValue.toString();
418
+ const newStr = currentStr.slice(0, -1);
419
+ const newValue = parseInt(newStr, 10);
420
+ if (currentField === 'maxContextTokens') {
421
+ setMaxContextTokens(!isNaN(newValue) ? newValue : 0);
422
+ }
423
+ else {
424
+ setMaxTokens(!isNaN(newValue) ? newValue : 0);
425
+ }
426
+ }
427
+ else if (key.return) {
428
+ const minValue = currentField === 'maxContextTokens' ? 4000 : 100;
429
+ const currentValue = currentField === 'maxContextTokens' ? maxContextTokens : maxTokens;
430
+ const finalValue = currentValue < minValue ? minValue : currentValue;
431
+ if (currentField === 'maxContextTokens') {
432
+ setMaxContextTokens(finalValue);
433
+ }
434
+ else {
435
+ setMaxTokens(finalValue);
436
+ }
437
+ setIsEditing(false);
438
+ }
439
+ return;
440
+ }
441
+ // Allow typing to filter for model selection
442
+ if (input && input.match(/[a-zA-Z0-9-_.]/)) {
443
+ setSearchTerm(prev => prev + input);
444
+ }
445
+ else if (key.backspace || key.delete) {
446
+ setSearchTerm(prev => prev.slice(0, -1));
447
+ }
448
+ return;
449
+ }
450
+ // Handle save/exit globally
451
+ if (input === 's' && (key.ctrl || key.meta)) {
452
+ if (saveConfiguration()) {
453
+ onSave();
454
+ }
455
+ }
456
+ else if (key.escape) {
457
+ saveConfiguration();
458
+ onBack();
459
+ }
460
+ else if (key.return) {
461
+ if (isEditing) {
462
+ setIsEditing(false);
463
+ }
464
+ else {
465
+ // Enter edit mode
466
+ if (currentField === 'anthropicBeta') {
467
+ setAnthropicBeta(!anthropicBeta);
468
+ }
469
+ else if (currentField === 'maxContextTokens' ||
470
+ currentField === 'maxTokens') {
471
+ setIsEditing(true);
472
+ }
473
+ else if (currentField === 'advancedModel' ||
474
+ currentField === 'basicModel' ||
475
+ currentField === 'compactModelName') {
476
+ // Load models for model fields
477
+ setLoadError(''); // Clear previous error
478
+ loadModels()
479
+ .then(() => {
480
+ setIsEditing(true);
481
+ })
482
+ .catch(() => {
483
+ // Error is already set in loadModels, just enter manual input mode
484
+ setManualInputMode(true);
485
+ setManualInputValue(getCurrentValue());
486
+ });
487
+ }
488
+ else {
489
+ setIsEditing(true);
490
+ }
491
+ }
492
+ }
493
+ else if (input === 'm' && !isEditing) {
494
+ // Shortcut: press 'm' for manual input mode
495
+ if (currentField === 'advancedModel' ||
496
+ currentField === 'basicModel' ||
497
+ currentField === 'compactModelName') {
498
+ setManualInputMode(true);
499
+ setManualInputValue(getCurrentValue());
500
+ }
501
+ }
502
+ else if (!isEditing && key.upArrow) {
503
+ const fields = [
504
+ 'profile',
505
+ 'baseUrl',
506
+ 'apiKey',
507
+ 'requestMethod',
508
+ 'anthropicBeta',
509
+ 'advancedModel',
510
+ 'basicModel',
511
+ 'compactModelName',
512
+ 'maxContextTokens',
513
+ 'maxTokens',
514
+ ];
515
+ const currentIndex = fields.indexOf(currentField);
516
+ if (currentIndex > 0) {
517
+ setCurrentField(fields[currentIndex - 1]);
518
+ }
519
+ }
520
+ else if (!isEditing && key.downArrow) {
521
+ const fields = [
522
+ 'profile',
523
+ 'baseUrl',
524
+ 'apiKey',
525
+ 'requestMethod',
526
+ 'anthropicBeta',
527
+ 'advancedModel',
528
+ 'basicModel',
529
+ 'compactModelName',
530
+ 'maxContextTokens',
531
+ 'maxTokens',
532
+ ];
533
+ const currentIndex = fields.indexOf(currentField);
534
+ if (currentIndex < fields.length - 1) {
535
+ setCurrentField(fields[currentIndex + 1]);
536
+ }
537
+ }
538
+ });
539
+ // Render profile creation mode
540
+ if (profileMode === 'creating') {
541
+ return (React.createElement(Box, { flexDirection: "column", padding: 1 },
542
+ !inlineMode && (React.createElement(Box, { marginBottom: 1, borderStyle: "double", borderColor: 'cyan', paddingX: 2 },
543
+ React.createElement(Box, { flexDirection: "column" },
544
+ React.createElement(Gradient, { name: "rainbow" }, "Create New Profile"),
545
+ React.createElement(Text, { color: "gray", dimColor: true }, "Enter a name for the new configuration profile")))),
546
+ React.createElement(Box, { flexDirection: "column" },
547
+ React.createElement(Text, { color: "cyan" }, "Profile Name:"),
548
+ React.createElement(Box, { marginLeft: 2 },
549
+ React.createElement(TextInput, { value: newProfileName, onChange: value => setNewProfileName(stripFocusArtifacts(value)), placeholder: "e.g., work, personal, test" }))),
550
+ errors.length > 0 && (React.createElement(Box, { marginTop: 1 },
551
+ React.createElement(Text, { color: "red" }, errors[0]))),
552
+ React.createElement(Box, { marginTop: 1 },
553
+ React.createElement(Alert, { variant: "info" }, "Press Enter to create, Esc to cancel"))));
554
+ }
555
+ // Render profile deletion confirmation
556
+ if (profileMode === 'deleting') {
557
+ return (React.createElement(Box, { flexDirection: "column", padding: 1 },
558
+ !inlineMode && (React.createElement(Box, { marginBottom: 1, borderStyle: "double", borderColor: 'cyan', paddingX: 2 },
559
+ React.createElement(Box, { flexDirection: "column" },
560
+ React.createElement(Gradient, { name: "rainbow" }, "Delete Profile"),
561
+ React.createElement(Text, { color: "gray", dimColor: true }, "Confirm profile deletion")))),
562
+ React.createElement(Box, { flexDirection: "column" },
563
+ React.createElement(Text, { color: "yellow" },
564
+ "Are you sure you want to delete the profile \"",
565
+ activeProfile,
566
+ "\"?"),
567
+ React.createElement(Text, { color: "gray", dimColor: true }, "This action cannot be undone. You will be switched to the default profile.")),
568
+ errors.length > 0 && (React.createElement(Box, { marginTop: 1 },
569
+ React.createElement(Text, { color: "red" }, errors[0]))),
570
+ React.createElement(Box, { marginTop: 1 },
571
+ React.createElement(Alert, { variant: "warning" }, "Press Y to confirm, N or Esc to cancel"))));
572
+ }
573
+ if (loading) {
574
+ return (React.createElement(Box, { flexDirection: "column", padding: 1 },
575
+ !inlineMode && (React.createElement(Box, { marginBottom: 1, borderStyle: "double", borderColor: 'cyan', paddingX: 2 },
576
+ React.createElement(Box, { flexDirection: "column" },
577
+ React.createElement(Gradient, { name: "rainbow" }, "API & Model Configuration"),
578
+ React.createElement(Text, { color: "gray", dimColor: true }, "Loading available models...")))),
579
+ React.createElement(Box, { flexDirection: "column" },
580
+ React.createElement(Box, null,
581
+ React.createElement(Spinner, { type: "dots" }),
582
+ React.createElement(Text, { color: "cyan" }, " Fetching models from API...")),
583
+ React.createElement(Box, { marginLeft: 2 },
584
+ React.createElement(Text, { color: "gray", dimColor: true }, "This may take a few seconds depending on your network connection"))),
585
+ React.createElement(Box, { flexDirection: "column", marginTop: 1 },
586
+ React.createElement(Alert, { variant: "info" }, "Press Esc to cancel and return to configuration"))));
587
+ }
588
+ if (manualInputMode) {
589
+ return (React.createElement(Box, { flexDirection: "column", padding: 1 },
590
+ !inlineMode && (React.createElement(Box, { marginBottom: 1, borderStyle: "double", borderColor: 'cyan', paddingX: 2 },
591
+ React.createElement(Box, { flexDirection: "column" },
592
+ React.createElement(Gradient, { name: "rainbow" }, "Manual Input Model"),
593
+ React.createElement(Text, { color: "gray", dimColor: true }, "Enter model name manually")))),
594
+ loadError && (React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
595
+ React.createElement(Text, { color: "yellow" }, "\u26A0 Failed to load models from API"),
596
+ React.createElement(Text, { color: "gray", dimColor: true }, loadError))),
597
+ React.createElement(Box, { flexDirection: "column" },
598
+ React.createElement(Text, { color: "cyan" },
599
+ currentField === 'advancedModel' && 'Advanced Model',
600
+ currentField === 'basicModel' && 'Basic Model',
601
+ currentField === 'compactModelName' && 'Compact Model',
602
+ ":"),
603
+ React.createElement(Box, { marginLeft: 2 },
604
+ React.createElement(Text, { color: "green" },
605
+ `> ${manualInputValue}`,
606
+ React.createElement(Text, { color: "white" }, "_")))),
607
+ React.createElement(Box, { flexDirection: "column", marginTop: 1 },
608
+ React.createElement(Alert, { variant: "info" }, "Press Enter to confirm, Esc to cancel"))));
609
+ }
610
+ return (React.createElement(Box, { flexDirection: "column", padding: 1 },
611
+ !inlineMode && (React.createElement(Box, { marginBottom: 1, borderStyle: "double", borderColor: 'cyan', paddingX: 2 },
612
+ React.createElement(Box, { flexDirection: "column" },
613
+ React.createElement(Gradient, { name: "rainbow" }, "API & Model Configuration"),
614
+ React.createElement(Text, { color: "gray", dimColor: true }, "Configure your API settings and AI models"),
615
+ activeProfile && (React.createElement(Text, { color: "cyan", dimColor: true },
616
+ "Active Profile: ",
617
+ activeProfile))))),
618
+ React.createElement(Box, { flexDirection: "column" },
619
+ React.createElement(Box, { flexDirection: "column" },
620
+ React.createElement(Text, { color: currentField === 'profile' ? 'green' : 'white' },
621
+ currentField === 'profile' ? '❯ ' : ' ',
622
+ "Profile:"),
623
+ currentField === 'profile' && isEditing && (React.createElement(Box, { marginLeft: 3 },
624
+ React.createElement(Select, { options: [
625
+ ...profiles.map(p => ({
626
+ label: `${p.displayName}${p.isActive ? ' (Active)' : ''}`,
627
+ value: p.name,
628
+ })),
629
+ {
630
+ label: chalk.green('+ New Profile'),
631
+ value: '__CREATE_NEW__',
632
+ },
633
+ {
634
+ label: chalk.red('🆇 Delete Profile'),
635
+ value: '__DELETE__',
636
+ },
637
+ ], defaultValue: activeProfile, onChange: handleProfileChange }))),
638
+ (!isEditing || currentField !== 'profile') && (React.createElement(Box, { marginLeft: 3 },
639
+ React.createElement(Text, { color: "gray" }, profiles.find(p => p.name === activeProfile)?.displayName ||
640
+ activeProfile)))),
641
+ React.createElement(Box, { flexDirection: "column" },
642
+ React.createElement(Text, { color: currentField === 'baseUrl' ? 'green' : 'white' },
643
+ currentField === 'baseUrl' ? '❯ ' : ' ',
644
+ "Base URL:"),
645
+ currentField === 'baseUrl' && isEditing && (React.createElement(Box, { marginLeft: 3 },
646
+ React.createElement(TextInput, { value: baseUrl, onChange: value => setBaseUrl(stripFocusArtifacts(value)), placeholder: "https://api.openai.com/v1" }))),
647
+ (!isEditing || currentField !== 'baseUrl') && (React.createElement(Box, { marginLeft: 3 },
648
+ React.createElement(Text, { color: "gray" }, baseUrl || 'Not set')))),
649
+ React.createElement(Box, { flexDirection: "column" },
650
+ React.createElement(Text, { color: currentField === 'apiKey' ? 'green' : 'white' },
651
+ currentField === 'apiKey' ? '❯ ' : ' ',
652
+ "API Key:"),
653
+ currentField === 'apiKey' && isEditing && (React.createElement(Box, { marginLeft: 3 },
654
+ React.createElement(TextInput, { value: apiKey, onChange: value => setApiKey(stripFocusArtifacts(value)), placeholder: "sk-...", mask: "*" }))),
655
+ (!isEditing || currentField !== 'apiKey') && (React.createElement(Box, { marginLeft: 3 },
656
+ React.createElement(Text, { color: "gray" }, apiKey ? '*'.repeat(Math.min(apiKey.length, 20)) : 'Not set')))),
657
+ React.createElement(Box, { flexDirection: "column" },
658
+ React.createElement(Text, { color: currentField === 'requestMethod' ? 'green' : 'white' },
659
+ currentField === 'requestMethod' ? '❯ ' : ' ',
660
+ "Request Method:"),
661
+ currentField === 'requestMethod' && isEditing && (React.createElement(Box, { marginLeft: 3 },
662
+ React.createElement(Select, { options: requestMethodOptions, defaultValue: requestMethod, onChange: value => {
663
+ setRequestMethod(value);
664
+ setIsEditing(false);
665
+ } }))),
666
+ (!isEditing || currentField !== 'requestMethod') && (React.createElement(Box, { marginLeft: 3 },
667
+ React.createElement(Text, { color: "gray" }, requestMethodOptions.find(opt => opt.value === requestMethod)
668
+ ?.label || 'Not set')))),
669
+ React.createElement(Box, { flexDirection: "column" },
670
+ React.createElement(Text, { color: currentField === 'anthropicBeta' ? 'green' : 'white' },
671
+ currentField === 'anthropicBeta' ? '❯ ' : ' ',
672
+ "Anthropic Beta:"),
673
+ React.createElement(Box, { marginLeft: 3 },
674
+ React.createElement(Text, { color: "gray" },
675
+ anthropicBeta ? '☑ Enabled' : '☐ Disabled',
676
+ " (Press Enter to toggle)"))),
677
+ React.createElement(Box, { flexDirection: "column" },
678
+ React.createElement(Text, { color: currentField === 'advancedModel' ? 'green' : 'white' },
679
+ currentField === 'advancedModel' ? '❯ ' : ' ',
680
+ "Advanced Model:"),
681
+ currentField === 'advancedModel' && isEditing && (React.createElement(Box, { marginLeft: 3 },
682
+ React.createElement(Box, { flexDirection: "column" },
683
+ searchTerm && React.createElement(Text, { color: "cyan" },
684
+ "Filter: ",
685
+ searchTerm),
686
+ React.createElement(Select, { options: getCurrentOptions(), defaultValue: getCurrentValue(), onChange: handleModelChange })))),
687
+ (!isEditing || currentField !== 'advancedModel') && (React.createElement(Box, { marginLeft: 3 },
688
+ React.createElement(Text, { color: "gray" }, advancedModel || 'Not set')))),
689
+ React.createElement(Box, { flexDirection: "column" },
690
+ React.createElement(Text, { color: currentField === 'basicModel' ? 'green' : 'white' },
691
+ currentField === 'basicModel' ? '❯ ' : ' ',
692
+ "Basic Model:"),
693
+ currentField === 'basicModel' && isEditing && (React.createElement(Box, { marginLeft: 3 },
694
+ React.createElement(Box, { flexDirection: "column" },
695
+ searchTerm && React.createElement(Text, { color: "cyan" },
696
+ "Filter: ",
697
+ searchTerm),
698
+ React.createElement(Select, { options: getCurrentOptions(), defaultValue: getCurrentValue(), onChange: handleModelChange })))),
699
+ (!isEditing || currentField !== 'basicModel') && (React.createElement(Box, { marginLeft: 3 },
700
+ React.createElement(Text, { color: "gray" }, basicModel || 'Not set')))),
701
+ React.createElement(Box, { flexDirection: "column" },
702
+ React.createElement(Text, { color: currentField === 'compactModelName' ? 'green' : 'white' },
703
+ currentField === 'compactModelName' ? '❯ ' : ' ',
704
+ "Compact Model:"),
705
+ currentField === 'compactModelName' && isEditing && (React.createElement(Box, { marginLeft: 3 },
706
+ React.createElement(Box, { flexDirection: "column" },
707
+ searchTerm && React.createElement(Text, { color: "cyan" },
708
+ "Filter: ",
709
+ searchTerm),
710
+ React.createElement(Select, { options: getCurrentOptions(), defaultValue: getCurrentValue(), onChange: handleModelChange })))),
711
+ (!isEditing || currentField !== 'compactModelName') && (React.createElement(Box, { marginLeft: 3 },
712
+ React.createElement(Text, { color: "gray" }, compactModelName || 'Not set')))),
713
+ React.createElement(Box, { flexDirection: "column" },
714
+ React.createElement(Text, { color: currentField === 'maxContextTokens' ? 'green' : 'white' },
715
+ currentField === 'maxContextTokens' ? '❯ ' : ' ',
716
+ "Max Context Tokens:"),
717
+ currentField === 'maxContextTokens' && isEditing && (React.createElement(Box, { marginLeft: 3 },
718
+ React.createElement(Text, { color: "cyan" },
719
+ "Enter value: ",
720
+ maxContextTokens))),
721
+ (!isEditing || currentField !== 'maxContextTokens') && (React.createElement(Box, { marginLeft: 3 },
722
+ React.createElement(Text, { color: "gray" }, maxContextTokens)))),
723
+ React.createElement(Box, { flexDirection: "column" },
724
+ React.createElement(Text, { color: currentField === 'maxTokens' ? 'green' : 'white' },
725
+ currentField === 'maxTokens' ? '❯ ' : ' ',
726
+ "Max Tokens:"),
727
+ currentField === 'maxTokens' && isEditing && (React.createElement(Box, { marginLeft: 3 },
728
+ React.createElement(Text, { color: "cyan" },
729
+ "Enter value: ",
730
+ maxTokens))),
731
+ (!isEditing || currentField !== 'maxTokens') && (React.createElement(Box, { marginLeft: 3 },
732
+ React.createElement(Text, { color: "gray" }, maxTokens))))),
733
+ errors.length > 0 && (React.createElement(Box, { flexDirection: "column", marginTop: 1 },
734
+ React.createElement(Text, { color: "red", bold: true }, "Errors:"),
735
+ errors.map((error, index) => (React.createElement(Text, { key: index, color: "red" },
736
+ "\u2022 ",
737
+ error))))),
738
+ React.createElement(Box, { flexDirection: "column", marginTop: 1 }, isEditing ? (React.createElement(React.Fragment, null,
739
+ React.createElement(Alert, { variant: "info" },
740
+ "Editing mode:",
741
+ ' ',
742
+ currentField === 'advancedModel' ||
743
+ currentField === 'basicModel' ||
744
+ currentField === 'compactModelName'
745
+ ? 'Type to filter, ↑↓ to select, Enter to confirm'
746
+ : 'Press Enter to save and exit editing'))) : (React.createElement(React.Fragment, null,
747
+ React.createElement(Alert, { variant: "info" }, "Use \u2191\u2193 to navigate, Enter to edit, M for manual input, Ctrl+S or Esc to save"))))));
748
+ }