snow-ai 0.3.32 → 0.3.33
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/app.js +2 -2
- package/dist/ui/pages/CustomHeadersScreen.d.ts +2 -2
- package/dist/ui/pages/CustomHeadersScreen.js +486 -96
- package/dist/ui/pages/SystemPromptConfigScreen.d.ts +2 -2
- package/dist/ui/pages/SystemPromptConfigScreen.js +313 -78
- package/dist/ui/pages/WelcomeScreen.js +13 -1
- package/dist/utils/apiConfig.d.ts +52 -3
- package/dist/utils/apiConfig.js +150 -35
- package/dist/utils/mcpToolsManager.js +2 -1
- package/package.json +1 -1
package/dist/app.js
CHANGED
|
@@ -69,9 +69,9 @@ export default function App({ version, skipWelcome, headlessPrompt }) {
|
|
|
69
69
|
case 'mcp':
|
|
70
70
|
return (React.createElement(MCPConfigScreen, { onBack: () => setCurrentView('welcome'), onSave: () => setCurrentView('welcome') }));
|
|
71
71
|
case 'systemprompt':
|
|
72
|
-
return (React.createElement(SystemPromptConfigScreen, { onBack: () => setCurrentView('welcome')
|
|
72
|
+
return (React.createElement(SystemPromptConfigScreen, { onBack: () => setCurrentView('welcome') }));
|
|
73
73
|
case 'customheaders':
|
|
74
|
-
return
|
|
74
|
+
return React.createElement(CustomHeadersScreen, { onBack: () => setCurrentView('welcome') });
|
|
75
75
|
default:
|
|
76
76
|
return (React.createElement(WelcomeScreen, { version: version, onMenuSelect: handleMenuSelect }));
|
|
77
77
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import React from 'react';
|
|
1
2
|
type Props = {
|
|
2
3
|
onBack: () => void;
|
|
3
|
-
onSave: () => void;
|
|
4
4
|
};
|
|
5
|
-
export default function CustomHeadersScreen({ onBack }: Props): null;
|
|
5
|
+
export default function CustomHeadersScreen({ onBack }: Props): React.JSX.Element | null;
|
|
6
6
|
export {};
|
|
@@ -1,104 +1,494 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
const CONFIG_DIR = join(homedir(), '.snow');
|
|
8
|
-
const CUSTOM_HEADERS_FILE = join(CONFIG_DIR, 'custom-headers.json');
|
|
9
|
-
function getSystemEditor() {
|
|
10
|
-
if (platform() === 'win32') {
|
|
11
|
-
return 'notepad';
|
|
12
|
-
}
|
|
13
|
-
return process.env['EDITOR'] || 'vim';
|
|
14
|
-
}
|
|
15
|
-
function ensureConfigDirectory() {
|
|
16
|
-
if (!existsSync(CONFIG_DIR)) {
|
|
17
|
-
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
const DEFAULT_HEADERS_TEMPLATE = `{
|
|
21
|
-
"X-Custom-Header": "custom-value",
|
|
22
|
-
"User-Agent": "MyApp/1.0"
|
|
23
|
-
}`;
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { Box, Text, useInput } from 'ink';
|
|
3
|
+
import Gradient from 'ink-gradient';
|
|
4
|
+
import { Alert } from '@inkjs/ui';
|
|
5
|
+
import TextInput from 'ink-text-input';
|
|
6
|
+
import { getCustomHeadersConfig, saveCustomHeadersConfig, } from '../../utils/apiConfig.js';
|
|
24
7
|
export default function CustomHeadersScreen({ onBack }) {
|
|
25
|
-
const
|
|
8
|
+
const [config, setConfig] = useState(() => {
|
|
9
|
+
return (getCustomHeadersConfig() || {
|
|
10
|
+
active: '',
|
|
11
|
+
schemes: [],
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
const [view, setView] = useState('list');
|
|
15
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
16
|
+
const [currentAction, setCurrentAction] = useState('activate');
|
|
17
|
+
const [isEditing, setIsEditing] = useState(false);
|
|
18
|
+
const [editName, setEditName] = useState('');
|
|
19
|
+
const [editHeaders, setEditHeaders] = useState({});
|
|
20
|
+
const [editingField, setEditingField] = useState('name');
|
|
21
|
+
const [error, setError] = useState('');
|
|
22
|
+
// Headers editing state
|
|
23
|
+
const [headerKeys, setHeaderKeys] = useState([]);
|
|
24
|
+
const [headerSelectedIndex, setHeaderSelectedIndex] = useState(0);
|
|
25
|
+
const [headerEditingIndex, setHeaderEditingIndex] = useState(-1);
|
|
26
|
+
const [headerEditingField, setHeaderEditingField] = useState('key');
|
|
27
|
+
const [headerEditKey, setHeaderEditKey] = useState('');
|
|
28
|
+
const [headerEditValue, setHeaderEditValue] = useState('');
|
|
29
|
+
const actions = config.schemes.length > 0
|
|
30
|
+
? config.active
|
|
31
|
+
? ['activate', 'deactivate', 'edit', 'delete', 'add', 'back']
|
|
32
|
+
: ['activate', 'edit', 'delete', 'add', 'back']
|
|
33
|
+
: ['add', 'back'];
|
|
26
34
|
useEffect(() => {
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
const savedConfig = getCustomHeadersConfig();
|
|
36
|
+
if (savedConfig) {
|
|
37
|
+
setConfig(savedConfig);
|
|
38
|
+
}
|
|
39
|
+
}, [view]);
|
|
40
|
+
const saveAndRefresh = (newConfig) => {
|
|
41
|
+
try {
|
|
42
|
+
saveCustomHeadersConfig(newConfig);
|
|
43
|
+
setConfig(newConfig);
|
|
44
|
+
setError('');
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
setError(err instanceof Error ? err.message : 'Failed to save');
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const handleActivate = () => {
|
|
53
|
+
if (config.schemes.length === 0 || selectedIndex >= config.schemes.length)
|
|
54
|
+
return;
|
|
55
|
+
const scheme = config.schemes[selectedIndex];
|
|
56
|
+
const newConfig = {
|
|
57
|
+
...config,
|
|
58
|
+
active: scheme.id,
|
|
59
|
+
};
|
|
60
|
+
if (saveAndRefresh(newConfig)) {
|
|
61
|
+
setError('');
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const handleDeactivate = () => {
|
|
65
|
+
const newConfig = {
|
|
66
|
+
...config,
|
|
67
|
+
active: '',
|
|
68
|
+
};
|
|
69
|
+
if (saveAndRefresh(newConfig)) {
|
|
70
|
+
setError('');
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const handleEdit = () => {
|
|
74
|
+
if (config.schemes.length === 0 || selectedIndex >= config.schemes.length)
|
|
75
|
+
return;
|
|
76
|
+
const scheme = config.schemes[selectedIndex];
|
|
77
|
+
setEditName(scheme.name);
|
|
78
|
+
setEditHeaders(scheme.headers);
|
|
79
|
+
setEditingField('name');
|
|
80
|
+
setView('edit');
|
|
81
|
+
};
|
|
82
|
+
const handleDelete = () => {
|
|
83
|
+
setView('confirmDelete');
|
|
84
|
+
};
|
|
85
|
+
const confirmDelete = () => {
|
|
86
|
+
if (config.schemes.length === 0 || selectedIndex >= config.schemes.length)
|
|
87
|
+
return;
|
|
88
|
+
const schemeToDelete = config.schemes[selectedIndex];
|
|
89
|
+
const newSchemes = config.schemes.filter((_, i) => i !== selectedIndex);
|
|
90
|
+
const newActive = config.active === schemeToDelete.id && newSchemes.length > 0
|
|
91
|
+
? newSchemes[0].id
|
|
92
|
+
: config.active === schemeToDelete.id
|
|
93
|
+
? ''
|
|
94
|
+
: config.active;
|
|
95
|
+
const newConfig = {
|
|
96
|
+
active: newActive,
|
|
97
|
+
schemes: newSchemes,
|
|
98
|
+
};
|
|
99
|
+
if (saveAndRefresh(newConfig)) {
|
|
100
|
+
setSelectedIndex(Math.max(0, selectedIndex - 1));
|
|
101
|
+
setView('list');
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const handleAdd = () => {
|
|
105
|
+
setEditName('');
|
|
106
|
+
setEditHeaders({});
|
|
107
|
+
setEditingField('name');
|
|
108
|
+
setView('add');
|
|
109
|
+
};
|
|
110
|
+
const saveNewScheme = () => {
|
|
111
|
+
const newScheme = {
|
|
112
|
+
id: Date.now().toString(),
|
|
113
|
+
name: editName.trim() || 'Unnamed Scheme',
|
|
114
|
+
headers: editHeaders,
|
|
115
|
+
createdAt: new Date().toISOString(),
|
|
116
|
+
};
|
|
117
|
+
const newConfig = {
|
|
118
|
+
...config,
|
|
119
|
+
schemes: [...config.schemes, newScheme],
|
|
120
|
+
active: config.schemes.length === 0 ? newScheme.id : config.active,
|
|
121
|
+
};
|
|
122
|
+
if (saveAndRefresh(newConfig)) {
|
|
123
|
+
setView('list');
|
|
124
|
+
setSelectedIndex(config.schemes.length);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
const saveEditedScheme = () => {
|
|
128
|
+
if (config.schemes.length === 0 || selectedIndex >= config.schemes.length)
|
|
129
|
+
return;
|
|
130
|
+
const newConfig = {
|
|
131
|
+
...config,
|
|
132
|
+
schemes: config.schemes.map((s, i) => i === selectedIndex
|
|
133
|
+
? {
|
|
134
|
+
...s,
|
|
135
|
+
name: editName.trim() || 'Unnamed Scheme',
|
|
136
|
+
headers: editHeaders,
|
|
34
137
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
138
|
+
: s),
|
|
139
|
+
};
|
|
140
|
+
if (saveAndRefresh(newConfig)) {
|
|
141
|
+
setView('list');
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
// Headers editing functions
|
|
145
|
+
const enterHeadersEditMode = () => {
|
|
146
|
+
setHeaderKeys(Object.keys(editHeaders));
|
|
147
|
+
setHeaderSelectedIndex(0);
|
|
148
|
+
setHeaderEditingIndex(-1);
|
|
149
|
+
setView('editHeaders');
|
|
150
|
+
};
|
|
151
|
+
const exitHeadersEditMode = () => {
|
|
152
|
+
setView(view === 'add' ? 'add' : 'edit');
|
|
153
|
+
};
|
|
154
|
+
const addNewHeader = () => {
|
|
155
|
+
setHeaderEditKey('');
|
|
156
|
+
setHeaderEditValue('');
|
|
157
|
+
setHeaderEditingIndex(headerKeys.length);
|
|
158
|
+
setHeaderEditingField('key');
|
|
159
|
+
};
|
|
160
|
+
const editHeaderAtIndex = (index) => {
|
|
161
|
+
const key = headerKeys[index];
|
|
162
|
+
setHeaderEditKey(key);
|
|
163
|
+
setHeaderEditValue(editHeaders[key] || '');
|
|
164
|
+
setHeaderEditingIndex(index);
|
|
165
|
+
setHeaderEditingField('key');
|
|
166
|
+
};
|
|
167
|
+
const saveHeaderEdit = () => {
|
|
168
|
+
const trimmedKey = headerEditKey.trim();
|
|
169
|
+
const trimmedValue = headerEditValue.trim();
|
|
170
|
+
if (!trimmedKey) {
|
|
171
|
+
setHeaderEditingIndex(-1);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const newHeaders = { ...editHeaders };
|
|
175
|
+
if (headerEditingIndex < headerKeys.length) {
|
|
176
|
+
const oldKey = headerKeys[headerEditingIndex];
|
|
177
|
+
if (oldKey !== trimmedKey) {
|
|
178
|
+
delete newHeaders[oldKey];
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
newHeaders[trimmedKey] = trimmedValue;
|
|
182
|
+
setEditHeaders(newHeaders);
|
|
183
|
+
setHeaderKeys(Object.keys(newHeaders));
|
|
184
|
+
setHeaderEditingIndex(-1);
|
|
185
|
+
};
|
|
186
|
+
const deleteHeaderAtIndex = (index) => {
|
|
187
|
+
const key = headerKeys[index];
|
|
188
|
+
const newHeaders = { ...editHeaders };
|
|
189
|
+
delete newHeaders[key];
|
|
190
|
+
setEditHeaders(newHeaders);
|
|
191
|
+
setHeaderKeys(Object.keys(newHeaders));
|
|
192
|
+
setHeaderSelectedIndex(Math.max(0, Math.min(index, headerKeys.length - 2)));
|
|
193
|
+
};
|
|
194
|
+
// List view input handling
|
|
195
|
+
useInput((_input, key) => {
|
|
196
|
+
if (view !== 'list')
|
|
197
|
+
return;
|
|
198
|
+
if (key.escape) {
|
|
199
|
+
onBack();
|
|
200
|
+
}
|
|
201
|
+
else if (key.upArrow) {
|
|
202
|
+
if (config.schemes.length > 0) {
|
|
203
|
+
setSelectedIndex(prev => prev > 0 ? prev - 1 : config.schemes.length - 1);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
else if (key.downArrow) {
|
|
207
|
+
if (config.schemes.length > 0) {
|
|
208
|
+
setSelectedIndex(prev => prev < config.schemes.length - 1 ? prev + 1 : 0);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
else if (key.leftArrow) {
|
|
212
|
+
const currentIdx = actions.indexOf(currentAction);
|
|
213
|
+
setCurrentAction(actions[currentIdx > 0 ? currentIdx - 1 : actions.length - 1]);
|
|
214
|
+
}
|
|
215
|
+
else if (key.rightArrow) {
|
|
216
|
+
const currentIdx = actions.indexOf(currentAction);
|
|
217
|
+
setCurrentAction(actions[currentIdx < actions.length - 1 ? currentIdx + 1 : 0]);
|
|
218
|
+
}
|
|
219
|
+
else if (key.return) {
|
|
220
|
+
if (currentAction === 'activate') {
|
|
221
|
+
handleActivate();
|
|
222
|
+
}
|
|
223
|
+
else if (currentAction === 'deactivate') {
|
|
224
|
+
handleDeactivate();
|
|
225
|
+
}
|
|
226
|
+
else if (currentAction === 'edit') {
|
|
227
|
+
handleEdit();
|
|
228
|
+
}
|
|
229
|
+
else if (currentAction === 'delete') {
|
|
230
|
+
handleDelete();
|
|
231
|
+
}
|
|
232
|
+
else if (currentAction === 'add') {
|
|
233
|
+
handleAdd();
|
|
234
|
+
}
|
|
235
|
+
else if (currentAction === 'back') {
|
|
236
|
+
onBack();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}, { isActive: view === 'list' });
|
|
240
|
+
// Add/Edit view input handling
|
|
241
|
+
useInput((input, key) => {
|
|
242
|
+
if (view !== 'add' && view !== 'edit')
|
|
243
|
+
return;
|
|
244
|
+
if (key.escape) {
|
|
245
|
+
setView('list');
|
|
246
|
+
setError('');
|
|
247
|
+
}
|
|
248
|
+
else if (!isEditing && key.upArrow) {
|
|
249
|
+
setEditingField('name');
|
|
250
|
+
}
|
|
251
|
+
else if (!isEditing && key.downArrow) {
|
|
252
|
+
setEditingField('headers');
|
|
253
|
+
}
|
|
254
|
+
else if (key.return) {
|
|
255
|
+
if (editingField === 'headers' && !isEditing) {
|
|
256
|
+
enterHeadersEditMode();
|
|
257
|
+
}
|
|
258
|
+
else if (isEditing) {
|
|
259
|
+
setIsEditing(false);
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
setIsEditing(true);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
else if (input === 's' && (key.ctrl || key.meta)) {
|
|
266
|
+
if (view === 'add') {
|
|
267
|
+
saveNewScheme();
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
saveEditedScheme();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}, { isActive: view === 'add' || view === 'edit' });
|
|
274
|
+
// Headers edit view input handling
|
|
275
|
+
useInput((input, key) => {
|
|
276
|
+
if (view !== 'editHeaders')
|
|
277
|
+
return;
|
|
278
|
+
if (headerEditingIndex === -1) {
|
|
279
|
+
// 列表浏览模式
|
|
280
|
+
if (key.escape) {
|
|
281
|
+
exitHeadersEditMode();
|
|
282
|
+
}
|
|
283
|
+
else if (key.upArrow) {
|
|
284
|
+
setHeaderSelectedIndex(prev => prev > 0 ? prev - 1 : headerKeys.length);
|
|
285
|
+
}
|
|
286
|
+
else if (key.downArrow) {
|
|
287
|
+
setHeaderSelectedIndex(prev => prev < headerKeys.length ? prev + 1 : 0);
|
|
288
|
+
}
|
|
289
|
+
else if (key.return) {
|
|
290
|
+
if (headerSelectedIndex < headerKeys.length) {
|
|
291
|
+
editHeaderAtIndex(headerSelectedIndex);
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
addNewHeader();
|
|
38
295
|
}
|
|
39
296
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
exit();
|
|
44
|
-
const child = spawn(editor, [CUSTOM_HEADERS_FILE], {
|
|
45
|
-
stdio: 'inherit'
|
|
46
|
-
});
|
|
47
|
-
child.on('close', () => {
|
|
48
|
-
// Read edited content
|
|
49
|
-
if (existsSync(CUSTOM_HEADERS_FILE)) {
|
|
50
|
-
try {
|
|
51
|
-
const editedContent = readFileSync(CUSTOM_HEADERS_FILE, 'utf8');
|
|
52
|
-
const trimmedContent = editedContent.trim();
|
|
53
|
-
// Validate JSON format
|
|
54
|
-
if (trimmedContent === '' || trimmedContent === '{}') {
|
|
55
|
-
// Empty or empty object, delete file to reset
|
|
56
|
-
try {
|
|
57
|
-
const fs = require('fs');
|
|
58
|
-
fs.unlinkSync(CUSTOM_HEADERS_FILE);
|
|
59
|
-
console.log('Custom headers cleared. Please use `snow` to restart!');
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
// Delete failed, save empty object
|
|
63
|
-
writeFileSync(CUSTOM_HEADERS_FILE, '{}', 'utf8');
|
|
64
|
-
console.log('Custom headers cleared. Please use `snow` to restart!');
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
// Validate JSON
|
|
69
|
-
try {
|
|
70
|
-
const headers = JSON.parse(trimmedContent);
|
|
71
|
-
if (typeof headers !== 'object' || headers === null || Array.isArray(headers)) {
|
|
72
|
-
throw new Error('Headers must be a JSON object');
|
|
73
|
-
}
|
|
74
|
-
// Validate all values are strings
|
|
75
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
76
|
-
if (typeof value !== 'string') {
|
|
77
|
-
throw new Error(`Header value for "${key}" must be a string`);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
// Save valid headers
|
|
81
|
-
writeFileSync(CUSTOM_HEADERS_FILE, JSON.stringify(headers, null, 2), 'utf8');
|
|
82
|
-
console.log('Custom headers saved successfully! Please use `snow` to restart!');
|
|
83
|
-
}
|
|
84
|
-
catch (error) {
|
|
85
|
-
console.error('Invalid JSON format:', error instanceof Error ? error.message : 'Unknown error');
|
|
86
|
-
console.error('Custom headers were NOT saved. Please fix the JSON format and try again.');
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
catch (error) {
|
|
91
|
-
console.error('Failed to save custom headers:', error instanceof Error ? error.message : 'Unknown error');
|
|
92
|
-
}
|
|
297
|
+
else if (key.delete || input === 'd') {
|
|
298
|
+
if (headerSelectedIndex < headerKeys.length) {
|
|
299
|
+
deleteHeaderAtIndex(headerSelectedIndex);
|
|
93
300
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
// 编辑模式
|
|
305
|
+
if (key.escape) {
|
|
306
|
+
setHeaderEditingIndex(-1);
|
|
307
|
+
}
|
|
308
|
+
else if (key.upArrow && !isEditing) {
|
|
309
|
+
setHeaderEditingField('key');
|
|
310
|
+
}
|
|
311
|
+
else if (key.downArrow && !isEditing) {
|
|
312
|
+
setHeaderEditingField('value');
|
|
313
|
+
}
|
|
314
|
+
else if (key.return) {
|
|
315
|
+
if (isEditing) {
|
|
316
|
+
setIsEditing(false);
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
setIsEditing(true);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
else if (input === 's' && (key.ctrl || key.meta)) {
|
|
323
|
+
saveHeaderEdit();
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}, { isActive: view === 'editHeaders' });
|
|
327
|
+
// Delete confirmation input handling
|
|
328
|
+
useInput((input, key) => {
|
|
329
|
+
if (view !== 'confirmDelete')
|
|
330
|
+
return;
|
|
331
|
+
if (key.escape || input === 'n' || input === 'N') {
|
|
332
|
+
setView('list');
|
|
333
|
+
}
|
|
334
|
+
else if (input === 'y' || input === 'Y' || key.return) {
|
|
335
|
+
confirmDelete();
|
|
336
|
+
}
|
|
337
|
+
}, { isActive: view === 'confirmDelete' });
|
|
338
|
+
// Render list view
|
|
339
|
+
if (view === 'list') {
|
|
340
|
+
const activeScheme = config.schemes.find(s => s.id === config.active);
|
|
341
|
+
return (React.createElement(Box, { flexDirection: "column", padding: 1 },
|
|
342
|
+
React.createElement(Box, { marginBottom: 1, borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1 },
|
|
343
|
+
React.createElement(Box, { flexDirection: "column" },
|
|
344
|
+
React.createElement(Gradient, { name: "rainbow" }, "Custom Headers Management"),
|
|
345
|
+
React.createElement(Text, { color: "gray", dimColor: true }, "Manage multiple header schemes and switch between them"))),
|
|
346
|
+
error && (React.createElement(Box, { marginBottom: 1 },
|
|
347
|
+
React.createElement(Alert, { variant: "error" }, error))),
|
|
348
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
349
|
+
React.createElement(Text, { bold: true },
|
|
350
|
+
"Active Scheme:",
|
|
351
|
+
' ',
|
|
352
|
+
React.createElement(Text, { color: "green" }, activeScheme?.name || 'None'))),
|
|
353
|
+
config.schemes.length === 0 ? (React.createElement(Box, { marginBottom: 1 },
|
|
354
|
+
React.createElement(Text, { color: "yellow" }, "No header schemes configured. Press Enter to add one."))) : (React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
|
|
355
|
+
React.createElement(Text, { bold: true, color: "cyan" }, "Available Schemes:"),
|
|
356
|
+
config.schemes.map((scheme, index) => {
|
|
357
|
+
const headerCount = Object.keys(scheme.headers).length;
|
|
358
|
+
const headerPreview = headerCount > 0
|
|
359
|
+
? Object.entries(scheme.headers)
|
|
360
|
+
.slice(0, 2)
|
|
361
|
+
.map(([k, v]) => `${k}: ${v}`)
|
|
362
|
+
.join(', ')
|
|
363
|
+
: '';
|
|
364
|
+
return (React.createElement(Box, { key: scheme.id, marginLeft: 2 },
|
|
365
|
+
React.createElement(Text, { color: index === selectedIndex
|
|
366
|
+
? 'green'
|
|
367
|
+
: scheme.id === config.active
|
|
368
|
+
? 'cyan'
|
|
369
|
+
: 'white' },
|
|
370
|
+
index === selectedIndex ? '❯ ' : ' ',
|
|
371
|
+
scheme.id === config.active ? '✓ ' : ' ',
|
|
372
|
+
scheme.name,
|
|
373
|
+
headerPreview && (React.createElement(Text, { dimColor: true },
|
|
374
|
+
' ',
|
|
375
|
+
"- ",
|
|
376
|
+
headerPreview.substring(0, 50),
|
|
377
|
+
headerPreview.length > 50 ? '...' : '')))));
|
|
378
|
+
}))),
|
|
379
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
380
|
+
React.createElement(Text, { bold: true, color: "cyan" }, "Actions:")),
|
|
381
|
+
React.createElement(Box, { flexDirection: "column", marginBottom: 1, marginLeft: 2 }, actions.map(action => (React.createElement(Text, { key: action, color: currentAction === action ? 'green' : 'gray', bold: currentAction === action },
|
|
382
|
+
currentAction === action ? '❯ ' : ' ',
|
|
383
|
+
action === 'activate' && 'Activate',
|
|
384
|
+
action === 'deactivate' && 'Deactivate',
|
|
385
|
+
action === 'edit' && 'Edit',
|
|
386
|
+
action === 'delete' && 'Delete',
|
|
387
|
+
action === 'add' && 'Add New',
|
|
388
|
+
action === 'back' && '[ESC] Back')))),
|
|
389
|
+
React.createElement(Box, { marginTop: 1 },
|
|
390
|
+
React.createElement(Text, { color: "gray", dimColor: true }, "Use \u2191\u2193 to select scheme, \u2190\u2192 to select action, Enter to confirm"))));
|
|
391
|
+
}
|
|
392
|
+
// Render add/edit view
|
|
393
|
+
if (view === 'add' || view === 'edit') {
|
|
394
|
+
const headerCount = Object.keys(editHeaders).length;
|
|
395
|
+
const headerPreview = headerCount > 0
|
|
396
|
+
? Object.entries(editHeaders)
|
|
397
|
+
.slice(0, 3)
|
|
398
|
+
.map(([k, v]) => `${k}: ${v}`)
|
|
399
|
+
.join(', ')
|
|
400
|
+
: 'Not set';
|
|
401
|
+
return (React.createElement(Box, { flexDirection: "column", padding: 1 },
|
|
402
|
+
React.createElement(Box, { marginBottom: 1, borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1 },
|
|
403
|
+
React.createElement(Gradient, { name: "rainbow" }, view === 'add' ? 'Add New Header Scheme' : 'Edit Header Scheme')),
|
|
404
|
+
error && (React.createElement(Box, { marginBottom: 1 },
|
|
405
|
+
React.createElement(Alert, { variant: "error" }, error))),
|
|
406
|
+
React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
|
|
407
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
408
|
+
React.createElement(Box, { flexDirection: "column" },
|
|
409
|
+
React.createElement(Text, { color: editingField === 'name' ? 'green' : 'white' },
|
|
410
|
+
editingField === 'name' ? '❯ ' : ' ',
|
|
411
|
+
"Name:"),
|
|
412
|
+
editingField === 'name' && isEditing && (React.createElement(Box, { marginLeft: 3 },
|
|
413
|
+
React.createElement(TextInput, { value: editName, onChange: setEditName, placeholder: "Enter scheme name" }))),
|
|
414
|
+
(!isEditing || editingField !== 'name') && (React.createElement(Box, { marginLeft: 3 },
|
|
415
|
+
React.createElement(Text, { color: "gray" }, editName || 'Not set'))))),
|
|
416
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
417
|
+
React.createElement(Box, { flexDirection: "column" },
|
|
418
|
+
React.createElement(Text, { color: editingField === 'headers' ? 'green' : 'white' },
|
|
419
|
+
editingField === 'headers' ? '❯ ' : ' ',
|
|
420
|
+
"Headers (",
|
|
421
|
+
headerCount,
|
|
422
|
+
' ',
|
|
423
|
+
"configured):"),
|
|
424
|
+
editingField === 'headers' && !isEditing ? (React.createElement(Box, { marginLeft: 3 },
|
|
425
|
+
React.createElement(Text, { color: "cyan", dimColor: true }, "Press Enter to edit headers \u2192"))) : (React.createElement(Box, { marginLeft: 3 },
|
|
426
|
+
React.createElement(Text, { color: "gray" },
|
|
427
|
+
headerPreview.substring(0, 100),
|
|
428
|
+
headerPreview.length > 100 ? '...' : '')))))),
|
|
429
|
+
React.createElement(Box, { marginTop: 1 },
|
|
430
|
+
React.createElement(Text, { color: "gray", dimColor: true }, "\u2191\u2193: Navigate fields | Enter: Edit | Ctrl+S: Save | ESC: Cancel"))));
|
|
431
|
+
}
|
|
432
|
+
// Render headers edit view
|
|
433
|
+
if (view === 'editHeaders') {
|
|
434
|
+
return (React.createElement(Box, { flexDirection: "column", padding: 1 },
|
|
435
|
+
React.createElement(Box, { marginBottom: 1, borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1 },
|
|
436
|
+
React.createElement(Gradient, { name: "rainbow" },
|
|
437
|
+
"Edit Headers - ",
|
|
438
|
+
editName)),
|
|
439
|
+
headerEditingIndex === -1 ? (React.createElement(React.Fragment, null,
|
|
440
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
441
|
+
React.createElement(Text, { bold: true, color: "cyan" }, "Header List:")),
|
|
442
|
+
headerKeys.length === 0 ? (React.createElement(Box, { marginBottom: 1 },
|
|
443
|
+
React.createElement(Text, { color: "yellow" }, "No headers configured. Press Enter to add one."))) : (React.createElement(Box, { flexDirection: "column", marginBottom: 1 }, headerKeys.map((key, index) => {
|
|
444
|
+
const isSelected = index === headerSelectedIndex;
|
|
445
|
+
return (React.createElement(Box, { key: index, marginLeft: 2 },
|
|
446
|
+
React.createElement(Text, { color: isSelected ? 'green' : 'white', bold: isSelected },
|
|
447
|
+
isSelected ? '❯ ' : ' ',
|
|
448
|
+
key,
|
|
449
|
+
": ",
|
|
450
|
+
editHeaders[key])));
|
|
451
|
+
}))),
|
|
452
|
+
React.createElement(Box, { marginLeft: 2, marginBottom: 1 },
|
|
453
|
+
React.createElement(Text, { color: headerSelectedIndex === headerKeys.length ? 'green' : 'gray', bold: headerSelectedIndex === headerKeys.length },
|
|
454
|
+
headerSelectedIndex === headerKeys.length ? '❯ ' : ' ',
|
|
455
|
+
"[+] Add new header")),
|
|
456
|
+
React.createElement(Box, { marginTop: 1 },
|
|
457
|
+
React.createElement(Text, { color: "gray", dimColor: true }, "\u2191\u2193: Navigate | Enter: Edit/Add | D: Delete | ESC: Finish")))) : (React.createElement(React.Fragment, null,
|
|
458
|
+
React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
|
|
459
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
460
|
+
React.createElement(Box, { flexDirection: "column" },
|
|
461
|
+
React.createElement(Text, { color: headerEditingField === 'key' ? 'green' : 'white' },
|
|
462
|
+
headerEditingField === 'key' ? '❯ ' : ' ',
|
|
463
|
+
"Key:"),
|
|
464
|
+
headerEditingField === 'key' && isEditing && (React.createElement(Box, { marginLeft: 3 },
|
|
465
|
+
React.createElement(TextInput, { value: headerEditKey, onChange: setHeaderEditKey, placeholder: "Header key (e.g., X-API-Key)" }))),
|
|
466
|
+
(!isEditing || headerEditingField !== 'key') && (React.createElement(Box, { marginLeft: 3 },
|
|
467
|
+
React.createElement(Text, { color: "gray" }, headerEditKey || 'Not set'))))),
|
|
468
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
469
|
+
React.createElement(Box, { flexDirection: "column" },
|
|
470
|
+
React.createElement(Text, { color: headerEditingField === 'value' ? 'green' : 'white' },
|
|
471
|
+
headerEditingField === 'value' ? '❯ ' : ' ',
|
|
472
|
+
"Value:"),
|
|
473
|
+
headerEditingField === 'value' && isEditing && (React.createElement(Box, { marginLeft: 3 },
|
|
474
|
+
React.createElement(TextInput, { value: headerEditValue, onChange: setHeaderEditValue, placeholder: "Header value" }))),
|
|
475
|
+
(!isEditing || headerEditingField !== 'value') && (React.createElement(Box, { marginLeft: 3 },
|
|
476
|
+
React.createElement(Text, { color: "gray" }, headerEditValue || 'Not set')))))),
|
|
477
|
+
React.createElement(Box, { marginTop: 1 },
|
|
478
|
+
React.createElement(Text, { color: "gray", dimColor: true }, "\u2191\u2193: Navigate fields | Enter: Edit | Ctrl+S: Save | ESC: Cancel"))))));
|
|
479
|
+
}
|
|
480
|
+
// Render delete confirmation
|
|
481
|
+
if (view === 'confirmDelete') {
|
|
482
|
+
const schemeToDelete = config.schemes.length > 0 ? config.schemes[selectedIndex] : null;
|
|
483
|
+
return (React.createElement(Box, { flexDirection: "column", padding: 1 },
|
|
484
|
+
React.createElement(Alert, { variant: "warning" }, "Confirm Delete"),
|
|
485
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
486
|
+
React.createElement(Text, null,
|
|
487
|
+
"Are you sure you want to delete \"",
|
|
488
|
+
React.createElement(Text, { bold: true, color: "yellow" }, schemeToDelete?.name),
|
|
489
|
+
"\"?")),
|
|
490
|
+
React.createElement(Box, { marginTop: 1 },
|
|
491
|
+
React.createElement(Text, { color: "gray", dimColor: true }, "Press Y to confirm, N or ESC to cancel"))));
|
|
492
|
+
}
|
|
103
493
|
return null;
|
|
104
494
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import React from 'react';
|
|
1
2
|
type Props = {
|
|
2
3
|
onBack: () => void;
|
|
3
|
-
onSave: () => void;
|
|
4
4
|
};
|
|
5
|
-
export default function SystemPromptConfigScreen({ onBack }: Props): null;
|
|
5
|
+
export default function SystemPromptConfigScreen({ onBack }: Props): React.JSX.Element | null;
|
|
6
6
|
export {};
|