snow-ai 0.2.25 → 0.2.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/systemPrompt.d.ts +1 -1
- package/dist/api/systemPrompt.js +39 -17
- package/dist/cli.js +8 -0
- package/dist/hooks/useClipboard.js +4 -4
- package/dist/hooks/useKeyboardInput.d.ts +1 -0
- package/dist/hooks/useKeyboardInput.js +8 -4
- package/dist/hooks/useTerminalFocus.d.ts +5 -0
- package/dist/hooks/useTerminalFocus.js +22 -2
- package/dist/mcp/aceCodeSearch.d.ts +58 -4
- package/dist/mcp/aceCodeSearch.js +563 -20
- package/dist/mcp/filesystem.d.ts +36 -29
- package/dist/mcp/filesystem.js +288 -123
- package/dist/mcp/ideDiagnostics.d.ts +36 -0
- package/dist/mcp/ideDiagnostics.js +92 -0
- package/dist/ui/components/ChatInput.js +6 -3
- package/dist/ui/pages/ConfigProfileScreen.d.ts +7 -0
- package/dist/ui/pages/ConfigProfileScreen.js +300 -0
- package/dist/ui/pages/ConfigScreen.js +228 -29
- package/dist/ui/pages/WelcomeScreen.js +1 -1
- package/dist/utils/apiConfig.js +12 -0
- package/dist/utils/configManager.d.ts +45 -0
- package/dist/utils/configManager.js +274 -0
- package/dist/utils/contextCompressor.js +0 -8
- package/dist/utils/escapeHandler.d.ts +79 -0
- package/dist/utils/escapeHandler.js +153 -0
- package/dist/utils/incrementalSnapshot.js +2 -1
- package/dist/utils/mcpToolsManager.js +44 -0
- package/dist/utils/textBuffer.js +13 -15
- package/dist/utils/vscodeConnection.js +26 -11
- package/dist/utils/workspaceSnapshot.js +2 -1
- package/package.json +2 -1
|
@@ -3,8 +3,10 @@ import { Box, Text, useInput } from 'ink';
|
|
|
3
3
|
import Gradient from 'ink-gradient';
|
|
4
4
|
import { Select, Alert, Spinner } from '@inkjs/ui';
|
|
5
5
|
import TextInput from 'ink-text-input';
|
|
6
|
+
import chalk from 'chalk';
|
|
6
7
|
import { getOpenAiConfig, updateOpenAiConfig, validateApiConfig, } from '../../utils/apiConfig.js';
|
|
7
8
|
import { fetchAvailableModels, filterModels, } from '../../api/models.js';
|
|
9
|
+
import { getActiveProfileName, getAllProfiles, switchProfile, createProfile, deleteProfile, saveProfile, } from '../../utils/configManager.js';
|
|
8
10
|
const focusEventTokenRegex = /(?:\x1b)?\[[0-9;]*[IO]/g;
|
|
9
11
|
const isFocusEventInput = (value) => {
|
|
10
12
|
if (!value) {
|
|
@@ -38,6 +40,11 @@ const stripFocusArtifacts = (value) => {
|
|
|
38
40
|
.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '');
|
|
39
41
|
};
|
|
40
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('');
|
|
41
48
|
// API settings
|
|
42
49
|
const [baseUrl, setBaseUrl] = useState('');
|
|
43
50
|
const [apiKey, setApiKey] = useState('');
|
|
@@ -50,7 +57,7 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
50
57
|
const [maxTokens, setMaxTokens] = useState(4096);
|
|
51
58
|
const [compactModelName, setCompactModelName] = useState('');
|
|
52
59
|
// UI state
|
|
53
|
-
const [currentField, setCurrentField] = useState('
|
|
60
|
+
const [currentField, setCurrentField] = useState('profile');
|
|
54
61
|
const [errors, setErrors] = useState([]);
|
|
55
62
|
const [isEditing, setIsEditing] = useState(false);
|
|
56
63
|
const [models, setModels] = useState([]);
|
|
@@ -78,6 +85,13 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
78
85
|
},
|
|
79
86
|
];
|
|
80
87
|
useEffect(() => {
|
|
88
|
+
loadProfilesAndConfig();
|
|
89
|
+
}, []);
|
|
90
|
+
const loadProfilesAndConfig = () => {
|
|
91
|
+
// Load profiles
|
|
92
|
+
const loadedProfiles = getAllProfiles();
|
|
93
|
+
setProfiles(loadedProfiles);
|
|
94
|
+
// Load current config
|
|
81
95
|
const config = getOpenAiConfig();
|
|
82
96
|
setBaseUrl(config.baseUrl);
|
|
83
97
|
setApiKey(config.apiKey);
|
|
@@ -88,7 +102,8 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
88
102
|
setMaxContextTokens(config.maxContextTokens || 4000);
|
|
89
103
|
setMaxTokens(config.maxTokens || 4096);
|
|
90
104
|
setCompactModelName(config.compactModel?.modelName || '');
|
|
91
|
-
|
|
105
|
+
setActiveProfile(getActiveProfileName());
|
|
106
|
+
};
|
|
92
107
|
const loadModels = async () => {
|
|
93
108
|
setLoading(true);
|
|
94
109
|
setLoadError('');
|
|
@@ -124,6 +139,8 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
124
139
|
];
|
|
125
140
|
};
|
|
126
141
|
const getCurrentValue = () => {
|
|
142
|
+
if (currentField === 'profile')
|
|
143
|
+
return activeProfile;
|
|
127
144
|
if (currentField === 'baseUrl')
|
|
128
145
|
return baseUrl;
|
|
129
146
|
if (currentField === 'apiKey')
|
|
@@ -140,6 +157,83 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
140
157
|
return compactModelName;
|
|
141
158
|
return '';
|
|
142
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
|
+
};
|
|
143
237
|
const handleModelChange = (value) => {
|
|
144
238
|
if (value === '__MANUAL_INPUT__') {
|
|
145
239
|
setManualInputMode(true);
|
|
@@ -181,7 +275,30 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
181
275
|
modelName: compactModelName,
|
|
182
276
|
};
|
|
183
277
|
}
|
|
278
|
+
// Save to main config
|
|
184
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
|
+
}
|
|
185
302
|
setErrors([]);
|
|
186
303
|
return true;
|
|
187
304
|
}
|
|
@@ -198,6 +315,29 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
198
315
|
if (isFocusEventInput(rawInput)) {
|
|
199
316
|
return;
|
|
200
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
|
+
}
|
|
201
341
|
// Handle loading state
|
|
202
342
|
if (loading) {
|
|
203
343
|
if (key.escape) {
|
|
@@ -239,7 +379,8 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
239
379
|
}
|
|
240
380
|
// Allow Escape key to exit Select component
|
|
241
381
|
if (isEditing &&
|
|
242
|
-
(currentField === '
|
|
382
|
+
(currentField === 'profile' ||
|
|
383
|
+
currentField === 'requestMethod' ||
|
|
243
384
|
currentField === 'advancedModel' ||
|
|
244
385
|
currentField === 'basicModel' ||
|
|
245
386
|
currentField === 'compactModelName') &&
|
|
@@ -360,15 +501,16 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
360
501
|
}
|
|
361
502
|
else if (!isEditing && key.upArrow) {
|
|
362
503
|
const fields = [
|
|
504
|
+
'profile',
|
|
363
505
|
'baseUrl',
|
|
364
506
|
'apiKey',
|
|
365
507
|
'requestMethod',
|
|
366
508
|
'anthropicBeta',
|
|
367
509
|
'advancedModel',
|
|
368
510
|
'basicModel',
|
|
511
|
+
'compactModelName',
|
|
369
512
|
'maxContextTokens',
|
|
370
513
|
'maxTokens',
|
|
371
|
-
'compactModelName',
|
|
372
514
|
];
|
|
373
515
|
const currentIndex = fields.indexOf(currentField);
|
|
374
516
|
if (currentIndex > 0) {
|
|
@@ -377,15 +519,16 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
377
519
|
}
|
|
378
520
|
else if (!isEditing && key.downArrow) {
|
|
379
521
|
const fields = [
|
|
522
|
+
'profile',
|
|
380
523
|
'baseUrl',
|
|
381
524
|
'apiKey',
|
|
382
525
|
'requestMethod',
|
|
383
526
|
'anthropicBeta',
|
|
384
527
|
'advancedModel',
|
|
385
528
|
'basicModel',
|
|
529
|
+
'compactModelName',
|
|
386
530
|
'maxContextTokens',
|
|
387
531
|
'maxTokens',
|
|
388
|
-
'compactModelName',
|
|
389
532
|
];
|
|
390
533
|
const currentIndex = fields.indexOf(currentField);
|
|
391
534
|
if (currentIndex < fields.length - 1) {
|
|
@@ -393,6 +536,40 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
393
536
|
}
|
|
394
537
|
}
|
|
395
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
|
+
}
|
|
396
573
|
if (loading) {
|
|
397
574
|
return (React.createElement(Box, { flexDirection: "column", padding: 1 },
|
|
398
575
|
!inlineMode && (React.createElement(Box, { marginBottom: 1, borderStyle: "double", borderColor: 'cyan', paddingX: 2 },
|
|
@@ -434,9 +611,33 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
434
611
|
!inlineMode && (React.createElement(Box, { marginBottom: 1, borderStyle: "double", borderColor: 'cyan', paddingX: 2 },
|
|
435
612
|
React.createElement(Box, { flexDirection: "column" },
|
|
436
613
|
React.createElement(Gradient, { name: "rainbow" }, "API & Model Configuration"),
|
|
437
|
-
React.createElement(Text, { color: "gray", dimColor: true }, "Configure your API settings and AI models")
|
|
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))))),
|
|
438
618
|
React.createElement(Box, { flexDirection: "column" },
|
|
439
|
-
React.createElement(
|
|
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)))),
|
|
440
641
|
React.createElement(Box, { flexDirection: "column" },
|
|
441
642
|
React.createElement(Text, { color: currentField === 'baseUrl' ? 'green' : 'white' },
|
|
442
643
|
currentField === 'baseUrl' ? '❯ ' : ' ',
|
|
@@ -465,19 +666,18 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
465
666
|
(!isEditing || currentField !== 'requestMethod') && (React.createElement(Box, { marginLeft: 3 },
|
|
466
667
|
React.createElement(Text, { color: "gray" }, requestMethodOptions.find(opt => opt.value === requestMethod)
|
|
467
668
|
?.label || 'Not set')))),
|
|
468
|
-
React.createElement(Box, { flexDirection: "column"
|
|
669
|
+
React.createElement(Box, { flexDirection: "column" },
|
|
469
670
|
React.createElement(Text, { color: currentField === 'anthropicBeta' ? 'green' : 'white' },
|
|
470
671
|
currentField === 'anthropicBeta' ? '❯ ' : ' ',
|
|
471
|
-
"Anthropic Beta
|
|
672
|
+
"Anthropic Beta:"),
|
|
472
673
|
React.createElement(Box, { marginLeft: 3 },
|
|
473
674
|
React.createElement(Text, { color: "gray" },
|
|
474
675
|
anthropicBeta ? '☑ Enabled' : '☐ Disabled',
|
|
475
676
|
" (Press Enter to toggle)"))),
|
|
476
|
-
React.createElement(Text, { color: "cyan", bold: true }, "Model Settings:"),
|
|
477
677
|
React.createElement(Box, { flexDirection: "column" },
|
|
478
678
|
React.createElement(Text, { color: currentField === 'advancedModel' ? 'green' : 'white' },
|
|
479
679
|
currentField === 'advancedModel' ? '❯ ' : ' ',
|
|
480
|
-
"Advanced Model
|
|
680
|
+
"Advanced Model:"),
|
|
481
681
|
currentField === 'advancedModel' && isEditing && (React.createElement(Box, { marginLeft: 3 },
|
|
482
682
|
React.createElement(Box, { flexDirection: "column" },
|
|
483
683
|
searchTerm && React.createElement(Text, { color: "cyan" },
|
|
@@ -489,7 +689,7 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
489
689
|
React.createElement(Box, { flexDirection: "column" },
|
|
490
690
|
React.createElement(Text, { color: currentField === 'basicModel' ? 'green' : 'white' },
|
|
491
691
|
currentField === 'basicModel' ? '❯ ' : ' ',
|
|
492
|
-
"Basic Model
|
|
692
|
+
"Basic Model:"),
|
|
493
693
|
currentField === 'basicModel' && isEditing && (React.createElement(Box, { marginLeft: 3 },
|
|
494
694
|
React.createElement(Box, { flexDirection: "column" },
|
|
495
695
|
searchTerm && React.createElement(Text, { color: "cyan" },
|
|
@@ -498,39 +698,38 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
498
698
|
React.createElement(Select, { options: getCurrentOptions(), defaultValue: getCurrentValue(), onChange: handleModelChange })))),
|
|
499
699
|
(!isEditing || currentField !== 'basicModel') && (React.createElement(Box, { marginLeft: 3 },
|
|
500
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')))),
|
|
501
713
|
React.createElement(Box, { flexDirection: "column" },
|
|
502
714
|
React.createElement(Text, { color: currentField === 'maxContextTokens' ? 'green' : 'white' },
|
|
503
715
|
currentField === 'maxContextTokens' ? '❯ ' : ' ',
|
|
504
|
-
"Max Context Tokens
|
|
716
|
+
"Max Context Tokens:"),
|
|
505
717
|
currentField === 'maxContextTokens' && isEditing && (React.createElement(Box, { marginLeft: 3 },
|
|
506
718
|
React.createElement(Text, { color: "cyan" },
|
|
507
719
|
"Enter value: ",
|
|
508
720
|
maxContextTokens))),
|
|
509
721
|
(!isEditing || currentField !== 'maxContextTokens') && (React.createElement(Box, { marginLeft: 3 },
|
|
510
722
|
React.createElement(Text, { color: "gray" }, maxContextTokens)))),
|
|
511
|
-
React.createElement(Box, { flexDirection: "column"
|
|
723
|
+
React.createElement(Box, { flexDirection: "column" },
|
|
512
724
|
React.createElement(Text, { color: currentField === 'maxTokens' ? 'green' : 'white' },
|
|
513
725
|
currentField === 'maxTokens' ? '❯ ' : ' ',
|
|
514
|
-
"Max Tokens
|
|
726
|
+
"Max Tokens:"),
|
|
515
727
|
currentField === 'maxTokens' && isEditing && (React.createElement(Box, { marginLeft: 3 },
|
|
516
728
|
React.createElement(Text, { color: "cyan" },
|
|
517
729
|
"Enter value: ",
|
|
518
730
|
maxTokens))),
|
|
519
731
|
(!isEditing || currentField !== 'maxTokens') && (React.createElement(Box, { marginLeft: 3 },
|
|
520
|
-
React.createElement(Text, { color: "gray" }, maxTokens)))),
|
|
521
|
-
React.createElement(Text, { color: "cyan", bold: true }, "Compact Model (Context Compression):"),
|
|
522
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
523
|
-
React.createElement(Text, { color: currentField === 'compactModelName' ? 'green' : 'white' },
|
|
524
|
-
currentField === 'compactModelName' ? '❯ ' : ' ',
|
|
525
|
-
"Model Name (uses same API credentials):"),
|
|
526
|
-
currentField === 'compactModelName' && isEditing && (React.createElement(Box, { marginLeft: 3 },
|
|
527
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
528
|
-
searchTerm && React.createElement(Text, { color: "cyan" },
|
|
529
|
-
"Filter: ",
|
|
530
|
-
searchTerm),
|
|
531
|
-
React.createElement(Select, { options: getCurrentOptions(), defaultValue: getCurrentValue(), onChange: handleModelChange })))),
|
|
532
|
-
(!isEditing || currentField !== 'compactModelName') && (React.createElement(Box, { marginLeft: 3 },
|
|
533
|
-
React.createElement(Text, { color: "gray" }, compactModelName || 'Not set'))))),
|
|
732
|
+
React.createElement(Text, { color: "gray" }, maxTokens))))),
|
|
534
733
|
errors.length > 0 && (React.createElement(Box, { flexDirection: "column", marginTop: 1 },
|
|
535
734
|
React.createElement(Text, { color: "red", bold: true }, "Errors:"),
|
|
536
735
|
errors.map((error, index) => (React.createElement(Text, { key: index, color: "red" },
|
|
@@ -24,7 +24,7 @@ export default function WelcomeScreen({ version = '1.0.0', onMenuSelect, }) {
|
|
|
24
24
|
{
|
|
25
25
|
label: 'API & Model Settings',
|
|
26
26
|
value: 'config',
|
|
27
|
-
infoText: 'Configure API settings and
|
|
27
|
+
infoText: 'Configure API settings, AI models, and manage profiles',
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
label: 'Proxy & Browser Settings',
|
package/dist/utils/apiConfig.js
CHANGED
|
@@ -112,6 +112,18 @@ export function updateOpenAiConfig(apiConfig) {
|
|
|
112
112
|
snowcfg: { ...currentConfig.snowcfg, ...apiConfig },
|
|
113
113
|
};
|
|
114
114
|
saveConfig(updatedConfig);
|
|
115
|
+
// Also save to the active profile if profiles system is initialized
|
|
116
|
+
try {
|
|
117
|
+
// Dynamic import to avoid circular dependencies
|
|
118
|
+
const { getActiveProfileName, saveProfile } = require('./configManager.js');
|
|
119
|
+
const activeProfileName = getActiveProfileName();
|
|
120
|
+
if (activeProfileName) {
|
|
121
|
+
saveProfile(activeProfileName, updatedConfig);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// Profiles system not available yet (during initialization), skip sync
|
|
126
|
+
}
|
|
115
127
|
}
|
|
116
128
|
export function getOpenAiConfig() {
|
|
117
129
|
const config = loadConfig();
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type AppConfig } from './apiConfig.js';
|
|
2
|
+
export interface ConfigProfile {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
isActive: boolean;
|
|
6
|
+
config: AppConfig;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Get the current active profile name
|
|
10
|
+
*/
|
|
11
|
+
export declare function getActiveProfileName(): string;
|
|
12
|
+
/**
|
|
13
|
+
* Load a specific profile
|
|
14
|
+
*/
|
|
15
|
+
export declare function loadProfile(profileName: string): AppConfig | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Save a profile
|
|
18
|
+
*/
|
|
19
|
+
export declare function saveProfile(profileName: string, config: AppConfig): void;
|
|
20
|
+
/**
|
|
21
|
+
* Get all available profiles
|
|
22
|
+
*/
|
|
23
|
+
export declare function getAllProfiles(): ConfigProfile[];
|
|
24
|
+
/**
|
|
25
|
+
* Switch to a different profile
|
|
26
|
+
* This copies the profile config to config.json and updates the active profile
|
|
27
|
+
*/
|
|
28
|
+
export declare function switchProfile(profileName: string): void;
|
|
29
|
+
/**
|
|
30
|
+
* Create a new profile
|
|
31
|
+
*/
|
|
32
|
+
export declare function createProfile(profileName: string, config?: AppConfig): void;
|
|
33
|
+
/**
|
|
34
|
+
* Delete a profile
|
|
35
|
+
*/
|
|
36
|
+
export declare function deleteProfile(profileName: string): void;
|
|
37
|
+
/**
|
|
38
|
+
* Rename a profile
|
|
39
|
+
*/
|
|
40
|
+
export declare function renameProfile(oldName: string, newName: string): void;
|
|
41
|
+
/**
|
|
42
|
+
* Initialize profiles system
|
|
43
|
+
* This should be called on app startup to ensure profiles are set up
|
|
44
|
+
*/
|
|
45
|
+
export declare function initializeProfiles(): void;
|