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.
- package/dist/api/chat.d.ts +0 -8
- package/dist/api/chat.js +1 -144
- package/dist/api/responses.d.ts +0 -11
- package/dist/api/responses.js +1 -189
- package/dist/api/systemPrompt.d.ts +1 -1
- package/dist/api/systemPrompt.js +90 -295
- package/dist/app.d.ts +2 -1
- package/dist/app.js +11 -13
- package/dist/cli.js +16 -3
- package/dist/hooks/useClipboard.js +4 -4
- package/dist/hooks/useGlobalNavigation.d.ts +1 -1
- 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 +59 -10
- package/dist/mcp/filesystem.js +431 -124
- 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/ChatScreen.d.ts +4 -2
- package/dist/ui/pages/ChatScreen.js +31 -2
- package/dist/ui/pages/ConfigProfileScreen.d.ts +7 -0
- package/dist/ui/pages/ConfigProfileScreen.js +300 -0
- package/dist/ui/pages/{ApiConfigScreen.d.ts → ConfigScreen.d.ts} +1 -1
- package/dist/ui/pages/ConfigScreen.js +748 -0
- package/dist/ui/pages/WelcomeScreen.js +7 -18
- package/dist/utils/apiConfig.d.ts +0 -2
- 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 +355 -49
- 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/retryUtils.js +6 -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
- package/dist/ui/pages/ApiConfigScreen.js +0 -161
- package/dist/ui/pages/ModelConfigScreen.d.ts +0 -8
- package/dist/ui/pages/ModelConfigScreen.js +0 -504
|
@@ -7,6 +7,7 @@ import { mcpTools as filesystemTools } from '../mcp/filesystem.js';
|
|
|
7
7
|
import { mcpTools as terminalTools } from '../mcp/bash.js';
|
|
8
8
|
import { mcpTools as aceCodeSearchTools } from '../mcp/aceCodeSearch.js';
|
|
9
9
|
import { mcpTools as websearchTools } from '../mcp/websearch.js';
|
|
10
|
+
import { mcpTools as ideDiagnosticsTools } from '../mcp/ideDiagnostics.js';
|
|
10
11
|
import { TodoService } from '../mcp/todo.js';
|
|
11
12
|
import { sessionManager } from './sessionManager.js';
|
|
12
13
|
import { logger } from './logger.js';
|
|
@@ -177,6 +178,28 @@ async function refreshToolsCache() {
|
|
|
177
178
|
},
|
|
178
179
|
});
|
|
179
180
|
}
|
|
181
|
+
// Add built-in IDE Diagnostics tools (always available)
|
|
182
|
+
const ideDiagnosticsServiceTools = ideDiagnosticsTools.map(tool => ({
|
|
183
|
+
name: tool.name.replace('ide_', ''),
|
|
184
|
+
description: tool.description,
|
|
185
|
+
inputSchema: tool.inputSchema,
|
|
186
|
+
}));
|
|
187
|
+
servicesInfo.push({
|
|
188
|
+
serviceName: 'ide',
|
|
189
|
+
tools: ideDiagnosticsServiceTools,
|
|
190
|
+
isBuiltIn: true,
|
|
191
|
+
connected: true,
|
|
192
|
+
});
|
|
193
|
+
for (const tool of ideDiagnosticsTools) {
|
|
194
|
+
allTools.push({
|
|
195
|
+
type: 'function',
|
|
196
|
+
function: {
|
|
197
|
+
name: `ide-${tool.name.replace('ide_', '')}`,
|
|
198
|
+
description: tool.description,
|
|
199
|
+
parameters: tool.inputSchema,
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
}
|
|
180
203
|
// Add user-configured MCP server tools (probe for availability but don't maintain connections)
|
|
181
204
|
try {
|
|
182
205
|
const mcpConfig = getMCPConfig();
|
|
@@ -519,6 +542,10 @@ export async function executeMCPTool(toolName, args, abortSignal, onTokenUpdate)
|
|
|
519
542
|
serviceName = 'websearch';
|
|
520
543
|
actualToolName = toolName.substring('websearch-'.length);
|
|
521
544
|
}
|
|
545
|
+
else if (toolName.startsWith('ide-')) {
|
|
546
|
+
serviceName = 'ide';
|
|
547
|
+
actualToolName = toolName.substring('ide-'.length);
|
|
548
|
+
}
|
|
522
549
|
else {
|
|
523
550
|
// Check configured MCP services
|
|
524
551
|
try {
|
|
@@ -625,6 +652,23 @@ export async function executeMCPTool(toolName, args, abortSignal, onTokenUpdate)
|
|
|
625
652
|
throw new Error(`Unknown websearch tool: ${actualToolName}`);
|
|
626
653
|
}
|
|
627
654
|
}
|
|
655
|
+
else if (serviceName === 'ide') {
|
|
656
|
+
// Handle built-in IDE Diagnostics tools (no connection needed)
|
|
657
|
+
const { ideDiagnosticsService } = await import('../mcp/ideDiagnostics.js');
|
|
658
|
+
switch (actualToolName) {
|
|
659
|
+
case 'get_diagnostics':
|
|
660
|
+
const diagnostics = await ideDiagnosticsService.getDiagnostics(args.filePath);
|
|
661
|
+
// Format diagnostics for better readability
|
|
662
|
+
const formatted = ideDiagnosticsService.formatDiagnostics(diagnostics, args.filePath);
|
|
663
|
+
return {
|
|
664
|
+
diagnostics,
|
|
665
|
+
formatted,
|
|
666
|
+
summary: `Found ${diagnostics.length} diagnostic(s) in ${args.filePath}`,
|
|
667
|
+
};
|
|
668
|
+
default:
|
|
669
|
+
throw new Error(`Unknown IDE tool: ${actualToolName}`);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
628
672
|
else {
|
|
629
673
|
// Handle user-configured MCP service tools - connect only when needed
|
|
630
674
|
const mcpConfig = getMCPConfig();
|
package/dist/utils/retryUtils.js
CHANGED
|
@@ -64,6 +64,12 @@ function isRetriableError(error) {
|
|
|
64
64
|
errorMessage.includes('unavailable')) {
|
|
65
65
|
return true;
|
|
66
66
|
}
|
|
67
|
+
// Connection terminated by server
|
|
68
|
+
if (errorMessage.includes('terminated') ||
|
|
69
|
+
errorMessage.includes('connection reset') ||
|
|
70
|
+
errorMessage.includes('socket hang up')) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
67
73
|
return false;
|
|
68
74
|
}
|
|
69
75
|
/**
|
package/dist/utils/textBuffer.js
CHANGED
|
@@ -4,21 +4,16 @@ import { cpLen, cpSlice, visualWidth, toCodePoints } from './textUtils.js';
|
|
|
4
4
|
*/
|
|
5
5
|
function sanitizeInput(str) {
|
|
6
6
|
// Replace problematic characters but preserve basic formatting
|
|
7
|
-
return str
|
|
7
|
+
return (str
|
|
8
8
|
.replace(/\r\n/g, '\n') // Normalize line endings
|
|
9
9
|
.replace(/\r/g, '\n') // Convert remaining \r to \n
|
|
10
10
|
.replace(/\t/g, ' ') // Convert tabs to spaces
|
|
11
|
-
// Remove focus events
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
.replace(
|
|
15
|
-
// Also remove standalone [I and [O if they appear at word boundaries
|
|
16
|
-
// This catches cases where escape sequences arrive fragmented
|
|
17
|
-
// But we preserve legitimate text like "FOO[I]BAR" or "[Inside]"
|
|
18
|
-
.replace(/(?:^|\s)\[I(?:\s|$)/g, ' ')
|
|
19
|
-
.replace(/(?:^|\s)\[O(?:\s|$)/g, ' ')
|
|
11
|
+
// Remove focus events emitted during terminal focus changes
|
|
12
|
+
.replace(/\x1b\[[IO]/g, '')
|
|
13
|
+
// Remove stray [I/[O] tokens that precede drag-and-drop payloads
|
|
14
|
+
.replace(/(^|\s+)\[(?:I|O)(?=(?:\s|$|["'~\\\/]|[A-Za-z]:))/g, '$1')
|
|
20
15
|
// Remove control characters except newlines
|
|
21
|
-
.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '');
|
|
16
|
+
.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, ''));
|
|
22
17
|
}
|
|
23
18
|
export class TextBuffer {
|
|
24
19
|
constructor(viewport, onUpdate) {
|
|
@@ -145,7 +140,9 @@ export class TextBuffer {
|
|
|
145
140
|
let fullText = this.content;
|
|
146
141
|
for (const placeholder of this.pasteStorage.values()) {
|
|
147
142
|
if (placeholder.placeholder) {
|
|
148
|
-
fullText = fullText
|
|
143
|
+
fullText = fullText
|
|
144
|
+
.split(placeholder.placeholder)
|
|
145
|
+
.join(placeholder.content);
|
|
149
146
|
}
|
|
150
147
|
}
|
|
151
148
|
return fullText;
|
|
@@ -258,7 +255,7 @@ export class TextBuffer {
|
|
|
258
255
|
content: this.pasteAccumulator,
|
|
259
256
|
charCount: totalChars,
|
|
260
257
|
index: this.pasteCounter,
|
|
261
|
-
placeholder: placeholderText
|
|
258
|
+
placeholder: placeholderText,
|
|
262
259
|
});
|
|
263
260
|
// 在记录的位置插入占位符
|
|
264
261
|
const before = cpSlice(this.content, 0, this.pastePlaceholderPosition);
|
|
@@ -271,7 +268,8 @@ export class TextBuffer {
|
|
|
271
268
|
const before = cpSlice(this.content, 0, this.pastePlaceholderPosition);
|
|
272
269
|
const after = cpSlice(this.content, this.pastePlaceholderPosition);
|
|
273
270
|
this.content = before + this.pasteAccumulator + after;
|
|
274
|
-
this.cursorIndex =
|
|
271
|
+
this.cursorIndex =
|
|
272
|
+
this.pastePlaceholderPosition + cpLen(this.pasteAccumulator);
|
|
275
273
|
}
|
|
276
274
|
// 清理状态
|
|
277
275
|
this.pasteAccumulator = '';
|
|
@@ -501,7 +499,7 @@ export class TextBuffer {
|
|
|
501
499
|
data: base64Data,
|
|
502
500
|
mimeType: mimeType,
|
|
503
501
|
index: this.imageCounter,
|
|
504
|
-
placeholder: placeholderText
|
|
502
|
+
placeholder: placeholderText,
|
|
505
503
|
});
|
|
506
504
|
this.insertPlainText(placeholderText);
|
|
507
505
|
this.scheduleUpdate();
|
|
@@ -280,16 +280,21 @@ class VSCodeConnectionManager {
|
|
|
280
280
|
return;
|
|
281
281
|
}
|
|
282
282
|
const requestId = Math.random().toString(36).substring(7);
|
|
283
|
+
let isResolved = false;
|
|
283
284
|
const timeout = setTimeout(() => {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
285
|
+
if (!isResolved) {
|
|
286
|
+
cleanup();
|
|
287
|
+
resolve([]); // Timeout, return empty array
|
|
288
|
+
}
|
|
289
|
+
}, 2000); // Reduce timeout from 5s to 2s to avoid long blocking
|
|
287
290
|
const handler = (message) => {
|
|
288
291
|
try {
|
|
289
292
|
const data = JSON.parse(message.toString());
|
|
290
293
|
if (data.type === 'diagnostics' && data.requestId === requestId) {
|
|
291
|
-
|
|
292
|
-
|
|
294
|
+
if (!isResolved) {
|
|
295
|
+
cleanup();
|
|
296
|
+
resolve(data.diagnostics || []);
|
|
297
|
+
}
|
|
293
298
|
}
|
|
294
299
|
}
|
|
295
300
|
catch (error) {
|
|
@@ -297,15 +302,25 @@ class VSCodeConnectionManager {
|
|
|
297
302
|
}
|
|
298
303
|
};
|
|
299
304
|
const cleanup = () => {
|
|
305
|
+
isResolved = true;
|
|
300
306
|
clearTimeout(timeout);
|
|
301
|
-
this.client
|
|
307
|
+
if (this.client) {
|
|
308
|
+
this.client.off('message', handler);
|
|
309
|
+
}
|
|
302
310
|
};
|
|
303
311
|
this.client.on('message', handler);
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
312
|
+
// Add error handling for send operation
|
|
313
|
+
try {
|
|
314
|
+
this.client.send(JSON.stringify({
|
|
315
|
+
type: 'getDiagnostics',
|
|
316
|
+
requestId,
|
|
317
|
+
filePath,
|
|
318
|
+
}));
|
|
319
|
+
}
|
|
320
|
+
catch (error) {
|
|
321
|
+
cleanup();
|
|
322
|
+
resolve([]); // If send fails, return empty array
|
|
323
|
+
}
|
|
309
324
|
});
|
|
310
325
|
}
|
|
311
326
|
/**
|
|
@@ -2,6 +2,7 @@ import fs from 'fs/promises';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import os from 'os';
|
|
4
4
|
import crypto from 'crypto';
|
|
5
|
+
import { logger } from '../utils/logger.js';
|
|
5
6
|
/**
|
|
6
7
|
* Workspace Snapshot Manager
|
|
7
8
|
* Provides git-like version control for workspace files
|
|
@@ -196,7 +197,7 @@ class WorkspaceSnapshotManager {
|
|
|
196
197
|
}
|
|
197
198
|
}
|
|
198
199
|
catch (error) {
|
|
199
|
-
|
|
200
|
+
logger.error('Failed to list snapshots:', error);
|
|
200
201
|
}
|
|
201
202
|
return snapshots.sort((a, b) => b.messageIndex - a.messageIndex);
|
|
202
203
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "snow-ai",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.26",
|
|
4
4
|
"description": "Intelligent Command Line Assistant powered by AI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"cli-highlight": "^2.1.11",
|
|
48
48
|
"diff": "^8.0.2",
|
|
49
49
|
"figlet": "^1.8.2",
|
|
50
|
+
"fzf": "^0.5.2",
|
|
50
51
|
"https-proxy-agent": "^7.0.6",
|
|
51
52
|
"ink": "^5.2.1",
|
|
52
53
|
"ink-gradient": "^3.0.0",
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect } from 'react';
|
|
2
|
-
import { Box, Text, useInput } from 'ink';
|
|
3
|
-
import Gradient from 'ink-gradient';
|
|
4
|
-
import { Select, Alert } from '@inkjs/ui';
|
|
5
|
-
import TextInput from 'ink-text-input';
|
|
6
|
-
import { getOpenAiConfig, updateOpenAiConfig, validateApiConfig, } from '../../utils/apiConfig.js';
|
|
7
|
-
export default function ApiConfigScreen({ onBack, onSave, inlineMode = false }) {
|
|
8
|
-
const [baseUrl, setBaseUrl] = useState('');
|
|
9
|
-
const [apiKey, setApiKey] = useState('');
|
|
10
|
-
const [requestMethod, setRequestMethod] = useState('chat');
|
|
11
|
-
const [anthropicBeta, setAnthropicBeta] = useState(false);
|
|
12
|
-
const [currentField, setCurrentField] = useState('baseUrl');
|
|
13
|
-
const [errors, setErrors] = useState([]);
|
|
14
|
-
const [isEditing, setIsEditing] = useState(false);
|
|
15
|
-
const requestMethodOptions = [
|
|
16
|
-
{
|
|
17
|
-
label: 'Chat Completions - Modern chat API (GPT-4, GPT-3.5-turbo)',
|
|
18
|
-
value: 'chat',
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
label: 'Responses - New responses API (2025, with built-in tools)',
|
|
22
|
-
value: 'responses',
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
label: 'Gemini - Google Gemini API',
|
|
26
|
-
value: 'gemini',
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
label: 'Anthropic - Claude API',
|
|
30
|
-
value: 'anthropic',
|
|
31
|
-
},
|
|
32
|
-
];
|
|
33
|
-
useEffect(() => {
|
|
34
|
-
const config = getOpenAiConfig();
|
|
35
|
-
setBaseUrl(config.baseUrl);
|
|
36
|
-
setApiKey(config.apiKey);
|
|
37
|
-
setRequestMethod(config.requestMethod || 'chat');
|
|
38
|
-
setAnthropicBeta(config.anthropicBeta || false);
|
|
39
|
-
}, []);
|
|
40
|
-
useInput((input, key) => {
|
|
41
|
-
// Allow Escape key to exit Select component without changes
|
|
42
|
-
if (isEditing && currentField === 'requestMethod' && key.escape) {
|
|
43
|
-
setIsEditing(false);
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
// Don't handle other input when Select component is active
|
|
47
|
-
if (isEditing && currentField === 'requestMethod') {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
// Handle save/exit globally
|
|
51
|
-
if (input === 's' && (key.ctrl || key.meta)) {
|
|
52
|
-
const validationErrors = validateApiConfig({ baseUrl, apiKey, requestMethod });
|
|
53
|
-
if (validationErrors.length === 0) {
|
|
54
|
-
updateOpenAiConfig({ baseUrl, apiKey, requestMethod, anthropicBeta });
|
|
55
|
-
setErrors([]);
|
|
56
|
-
onSave();
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
setErrors(validationErrors);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
else if (key.escape) {
|
|
63
|
-
const validationErrors = validateApiConfig({ baseUrl, apiKey, requestMethod });
|
|
64
|
-
if (validationErrors.length === 0) {
|
|
65
|
-
updateOpenAiConfig({ baseUrl, apiKey, requestMethod, anthropicBeta });
|
|
66
|
-
setErrors([]);
|
|
67
|
-
}
|
|
68
|
-
onBack();
|
|
69
|
-
}
|
|
70
|
-
else if (key.return) {
|
|
71
|
-
if (isEditing) {
|
|
72
|
-
// Exit edit mode, return to navigation
|
|
73
|
-
setIsEditing(false);
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
// Enter edit mode for current field (toggle for checkbox)
|
|
77
|
-
if (currentField === 'anthropicBeta') {
|
|
78
|
-
setAnthropicBeta(!anthropicBeta);
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
setIsEditing(true);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
else if (!isEditing && key.upArrow) {
|
|
86
|
-
if (currentField === 'apiKey') {
|
|
87
|
-
setCurrentField('baseUrl');
|
|
88
|
-
}
|
|
89
|
-
else if (currentField === 'requestMethod') {
|
|
90
|
-
setCurrentField('apiKey');
|
|
91
|
-
}
|
|
92
|
-
else if (currentField === 'anthropicBeta') {
|
|
93
|
-
setCurrentField('requestMethod');
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
else if (!isEditing && key.downArrow) {
|
|
97
|
-
if (currentField === 'baseUrl') {
|
|
98
|
-
setCurrentField('apiKey');
|
|
99
|
-
}
|
|
100
|
-
else if (currentField === 'apiKey') {
|
|
101
|
-
setCurrentField('requestMethod');
|
|
102
|
-
}
|
|
103
|
-
else if (currentField === 'requestMethod') {
|
|
104
|
-
setCurrentField('anthropicBeta');
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
return (React.createElement(Box, { flexDirection: "column", padding: 1 },
|
|
109
|
-
!inlineMode && (React.createElement(Box, { marginBottom: 2, borderStyle: "double", borderColor: "cyan", paddingX: 2, paddingY: 1 },
|
|
110
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
111
|
-
React.createElement(Gradient, { name: "rainbow" }, "OpenAI API Configuration"),
|
|
112
|
-
React.createElement(Text, { color: "gray", dimColor: true }, "Configure your OpenAI API settings")))),
|
|
113
|
-
React.createElement(Box, { flexDirection: "column", marginBottom: 2 },
|
|
114
|
-
React.createElement(Box, { marginBottom: 1 },
|
|
115
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
116
|
-
React.createElement(Text, { color: currentField === 'baseUrl' ? 'green' : 'white' },
|
|
117
|
-
currentField === 'baseUrl' ? '❯ ' : ' ',
|
|
118
|
-
"Base URL:"),
|
|
119
|
-
currentField === 'baseUrl' && isEditing && (React.createElement(Box, { marginLeft: 3 },
|
|
120
|
-
React.createElement(TextInput, { value: baseUrl, onChange: setBaseUrl, placeholder: "https://api.openai.com/v1" }))),
|
|
121
|
-
(!isEditing || currentField !== 'baseUrl') && (React.createElement(Box, { marginLeft: 3 },
|
|
122
|
-
React.createElement(Text, { color: "gray" }, baseUrl || 'Not set'))))),
|
|
123
|
-
React.createElement(Box, { marginBottom: 1 },
|
|
124
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
125
|
-
React.createElement(Text, { color: currentField === 'apiKey' ? 'green' : 'white' },
|
|
126
|
-
currentField === 'apiKey' ? '❯ ' : ' ',
|
|
127
|
-
"API Key:"),
|
|
128
|
-
currentField === 'apiKey' && isEditing && (React.createElement(Box, { marginLeft: 3 },
|
|
129
|
-
React.createElement(TextInput, { value: apiKey, onChange: setApiKey, placeholder: "sk-...", mask: "*" }))),
|
|
130
|
-
(!isEditing || currentField !== 'apiKey') && (React.createElement(Box, { marginLeft: 3 },
|
|
131
|
-
React.createElement(Text, { color: "gray" }, apiKey ? '*'.repeat(Math.min(apiKey.length, 20)) : 'Not set'))))),
|
|
132
|
-
React.createElement(Box, { marginBottom: 1 },
|
|
133
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
134
|
-
React.createElement(Text, { color: currentField === 'requestMethod' ? 'green' : 'white' },
|
|
135
|
-
currentField === 'requestMethod' ? '❯ ' : ' ',
|
|
136
|
-
"Request Method:"),
|
|
137
|
-
currentField === 'requestMethod' && isEditing && (React.createElement(Box, { marginLeft: 3 },
|
|
138
|
-
React.createElement(Select, { options: requestMethodOptions, defaultValue: requestMethod, onChange: (value) => {
|
|
139
|
-
setRequestMethod(value);
|
|
140
|
-
setIsEditing(false); // Auto exit edit mode after selection
|
|
141
|
-
} }))),
|
|
142
|
-
(!isEditing || currentField !== 'requestMethod') && (React.createElement(Box, { marginLeft: 3 },
|
|
143
|
-
React.createElement(Text, { color: "gray" }, requestMethodOptions.find(opt => opt.value === requestMethod)?.label || 'Not set'))))),
|
|
144
|
-
React.createElement(Box, { marginBottom: 1 },
|
|
145
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
146
|
-
React.createElement(Text, { color: currentField === 'anthropicBeta' ? 'green' : 'white' },
|
|
147
|
-
currentField === 'anthropicBeta' ? '❯ ' : ' ',
|
|
148
|
-
"Anthropic Beta (for Claude API):"),
|
|
149
|
-
React.createElement(Box, { marginLeft: 3 },
|
|
150
|
-
React.createElement(Text, { color: "gray" },
|
|
151
|
-
anthropicBeta ? '☑ Enabled' : '☐ Disabled',
|
|
152
|
-
" (Press Enter to toggle)"))))),
|
|
153
|
-
errors.length > 0 && (React.createElement(Box, { flexDirection: "column", marginBottom: 2 },
|
|
154
|
-
React.createElement(Text, { color: "red", bold: true }, "Errors:"),
|
|
155
|
-
errors.map((error, index) => (React.createElement(Text, { key: index, color: "red" },
|
|
156
|
-
"\u2022 ",
|
|
157
|
-
error))))),
|
|
158
|
-
React.createElement(Box, { flexDirection: "column" }, isEditing ? (React.createElement(React.Fragment, null,
|
|
159
|
-
React.createElement(Alert, { variant: "info" }, "Editing mode: Press Enter to save and exit editing (Make your changes and press Enter when done)"))) : (React.createElement(React.Fragment, null,
|
|
160
|
-
React.createElement(Alert, { variant: "info" }, "Use \u2191\u2193 to navigate between fields, press Enter to edit, and press Ctrl+S or Esc to save and return"))))));
|
|
161
|
-
}
|