snow-ai 0.3.4 → 0.3.6
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/anthropic.js +38 -13
- package/dist/api/types.d.ts +1 -0
- package/dist/hooks/useConversation.js +226 -59
- package/dist/hooks/useSnapshotState.d.ts +2 -0
- package/dist/hooks/useToolConfirmation.js +1 -1
- package/dist/mcp/subagent.d.ts +35 -0
- package/dist/mcp/subagent.js +64 -0
- package/dist/ui/components/ChatInput.d.ts +1 -2
- package/dist/ui/components/ChatInput.js +47 -39
- package/dist/ui/components/FileRollbackConfirmation.d.ts +3 -2
- package/dist/ui/components/FileRollbackConfirmation.js +81 -22
- package/dist/ui/components/MessageList.d.ts +7 -1
- package/dist/ui/components/MessageList.js +16 -5
- package/dist/ui/components/ToolResultPreview.js +21 -1
- package/dist/ui/pages/ChatScreen.js +29 -20
- package/dist/ui/pages/ConfigScreen.js +47 -46
- package/dist/ui/pages/ProxyConfigScreen.js +1 -1
- package/dist/ui/pages/SubAgentConfigScreen.d.ts +9 -0
- package/dist/ui/pages/SubAgentConfigScreen.js +352 -0
- package/dist/ui/pages/SubAgentListScreen.d.ts +9 -0
- package/dist/ui/pages/SubAgentListScreen.js +114 -0
- package/dist/ui/pages/WelcomeScreen.js +30 -2
- package/dist/utils/incrementalSnapshot.d.ts +7 -0
- package/dist/utils/incrementalSnapshot.js +34 -0
- package/dist/utils/mcpToolsManager.js +41 -1
- package/dist/utils/retryUtils.js +5 -0
- package/dist/utils/sessionConverter.d.ts +1 -0
- package/dist/utils/sessionConverter.js +192 -89
- package/dist/utils/subAgentConfig.d.ts +43 -0
- package/dist/utils/subAgentConfig.js +126 -0
- package/dist/utils/subAgentExecutor.d.ts +29 -0
- package/dist/utils/subAgentExecutor.js +272 -0
- package/dist/utils/toolExecutor.d.ts +10 -2
- package/dist/utils/toolExecutor.js +46 -5
- package/package.json +1 -1
- package/dist/ui/pages/ConfigProfileScreen.d.ts +0 -7
- package/dist/ui/pages/ConfigProfileScreen.js +0 -300
|
@@ -1,300 +0,0 @@
|
|
|
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 { getAllProfiles, switchProfile, createProfile, deleteProfile, renameProfile, } from '../../utils/configManager.js';
|
|
7
|
-
import ConfigScreen from './ConfigScreen.js';
|
|
8
|
-
const focusEventTokenRegex = /(?:\x1b)?\[[0-9;]*[IO]/g;
|
|
9
|
-
const isFocusEventInput = (value) => {
|
|
10
|
-
if (!value) {
|
|
11
|
-
return false;
|
|
12
|
-
}
|
|
13
|
-
if (value === '\x1b[I' ||
|
|
14
|
-
value === '\x1b[O' ||
|
|
15
|
-
value === '[I' ||
|
|
16
|
-
value === '[O') {
|
|
17
|
-
return true;
|
|
18
|
-
}
|
|
19
|
-
const trimmed = value.trim();
|
|
20
|
-
if (!trimmed) {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
const tokens = trimmed.match(focusEventTokenRegex);
|
|
24
|
-
if (!tokens) {
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
const normalized = trimmed.replace(/\s+/g, '');
|
|
28
|
-
const tokensCombined = tokens.join('');
|
|
29
|
-
return tokensCombined === normalized;
|
|
30
|
-
};
|
|
31
|
-
const stripFocusArtifacts = (value) => {
|
|
32
|
-
if (!value) {
|
|
33
|
-
return '';
|
|
34
|
-
}
|
|
35
|
-
return value
|
|
36
|
-
.replace(/\x1b\[[0-9;]*[IO]/g, '')
|
|
37
|
-
.replace(/\[[0-9;]*[IO]/g, '')
|
|
38
|
-
.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '');
|
|
39
|
-
};
|
|
40
|
-
export default function ConfigProfileScreen({ onBack, onSelectProfile, }) {
|
|
41
|
-
const [profiles, setProfiles] = useState([]);
|
|
42
|
-
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
43
|
-
const [mode, setMode] = useState('list');
|
|
44
|
-
const [inputValue, setInputValue] = useState('');
|
|
45
|
-
const [error, setError] = useState('');
|
|
46
|
-
// Load profiles on mount
|
|
47
|
-
useEffect(() => {
|
|
48
|
-
refreshProfiles();
|
|
49
|
-
}, []);
|
|
50
|
-
const refreshProfiles = () => {
|
|
51
|
-
const loadedProfiles = getAllProfiles();
|
|
52
|
-
setProfiles(loadedProfiles);
|
|
53
|
-
// Find active profile and set selected index
|
|
54
|
-
const activeIndex = loadedProfiles.findIndex(p => p.isActive);
|
|
55
|
-
if (activeIndex !== -1) {
|
|
56
|
-
setSelectedIndex(activeIndex);
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
const handleCreateProfile = () => {
|
|
60
|
-
const cleaned = stripFocusArtifacts(inputValue).trim();
|
|
61
|
-
if (!cleaned) {
|
|
62
|
-
setError('Profile name cannot be empty');
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
try {
|
|
66
|
-
createProfile(cleaned);
|
|
67
|
-
refreshProfiles();
|
|
68
|
-
setMode('list');
|
|
69
|
-
setInputValue('');
|
|
70
|
-
setError('');
|
|
71
|
-
}
|
|
72
|
-
catch (err) {
|
|
73
|
-
setError(err instanceof Error ? err.message : 'Failed to create profile');
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
const handleRenameProfile = () => {
|
|
77
|
-
const cleaned = stripFocusArtifacts(inputValue).trim();
|
|
78
|
-
const currentProfile = profiles[selectedIndex];
|
|
79
|
-
if (!currentProfile) {
|
|
80
|
-
setError('No profile selected');
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
if (!cleaned) {
|
|
84
|
-
setError('Profile name cannot be empty');
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
try {
|
|
88
|
-
renameProfile(currentProfile.name, cleaned);
|
|
89
|
-
refreshProfiles();
|
|
90
|
-
setMode('list');
|
|
91
|
-
setInputValue('');
|
|
92
|
-
setError('');
|
|
93
|
-
}
|
|
94
|
-
catch (err) {
|
|
95
|
-
setError(err instanceof Error ? err.message : 'Failed to rename profile');
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
const handleDeleteProfile = () => {
|
|
99
|
-
const currentProfile = profiles[selectedIndex];
|
|
100
|
-
if (!currentProfile) {
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
try {
|
|
104
|
-
deleteProfile(currentProfile.name);
|
|
105
|
-
refreshProfiles();
|
|
106
|
-
setMode('list');
|
|
107
|
-
setError('');
|
|
108
|
-
setSelectedIndex(Math.max(0, selectedIndex - 1));
|
|
109
|
-
}
|
|
110
|
-
catch (err) {
|
|
111
|
-
setError(err instanceof Error ? err.message : 'Failed to delete profile');
|
|
112
|
-
setMode('list');
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
const handleSwitchProfile = () => {
|
|
116
|
-
const currentProfile = profiles[selectedIndex];
|
|
117
|
-
if (!currentProfile) {
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
try {
|
|
121
|
-
switchProfile(currentProfile.name);
|
|
122
|
-
onSelectProfile(currentProfile.name);
|
|
123
|
-
}
|
|
124
|
-
catch (err) {
|
|
125
|
-
setError(err instanceof Error ? err.message : 'Failed to switch profile');
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
const handleEditProfile = () => {
|
|
129
|
-
const currentProfile = profiles[selectedIndex];
|
|
130
|
-
if (!currentProfile) {
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
// Switch to this profile first to make it active for editing
|
|
134
|
-
try {
|
|
135
|
-
switchProfile(currentProfile.name);
|
|
136
|
-
setMode('edit');
|
|
137
|
-
setError('');
|
|
138
|
-
}
|
|
139
|
-
catch (err) {
|
|
140
|
-
setError(err instanceof Error ? err.message : 'Failed to edit profile');
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
const handleEditComplete = () => {
|
|
144
|
-
// Refresh profiles to show updated config
|
|
145
|
-
refreshProfiles();
|
|
146
|
-
setMode('list');
|
|
147
|
-
setError('');
|
|
148
|
-
};
|
|
149
|
-
useInput((rawInput, key) => {
|
|
150
|
-
const input = stripFocusArtifacts(rawInput);
|
|
151
|
-
if (!input && isFocusEventInput(rawInput)) {
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
if (isFocusEventInput(rawInput)) {
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
// Handle text input modes
|
|
158
|
-
if (mode === 'create' || mode === 'rename') {
|
|
159
|
-
if (key.return) {
|
|
160
|
-
if (mode === 'create') {
|
|
161
|
-
handleCreateProfile();
|
|
162
|
-
}
|
|
163
|
-
else if (mode === 'rename') {
|
|
164
|
-
handleRenameProfile();
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
else if (key.escape) {
|
|
168
|
-
setMode('list');
|
|
169
|
-
setInputValue('');
|
|
170
|
-
setError('');
|
|
171
|
-
}
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
// Handle edit mode - don't intercept input
|
|
175
|
-
if (mode === 'edit') {
|
|
176
|
-
// ConfigScreen handles all input
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
// Handle delete confirmation
|
|
180
|
-
if (mode === 'delete-confirm') {
|
|
181
|
-
if (input === 'y' || input === 'Y') {
|
|
182
|
-
handleDeleteProfile();
|
|
183
|
-
}
|
|
184
|
-
else if (input === 'n' || input === 'N' || key.escape) {
|
|
185
|
-
setMode('list');
|
|
186
|
-
setError('');
|
|
187
|
-
}
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
// Handle list mode
|
|
191
|
-
if (mode === 'list') {
|
|
192
|
-
if (key.escape) {
|
|
193
|
-
onBack();
|
|
194
|
-
}
|
|
195
|
-
else if (key.upArrow) {
|
|
196
|
-
setSelectedIndex(Math.max(0, selectedIndex - 1));
|
|
197
|
-
setError('');
|
|
198
|
-
}
|
|
199
|
-
else if (key.downArrow) {
|
|
200
|
-
setSelectedIndex(Math.min(profiles.length - 1, selectedIndex + 1));
|
|
201
|
-
setError('');
|
|
202
|
-
}
|
|
203
|
-
else if (key.return) {
|
|
204
|
-
handleSwitchProfile();
|
|
205
|
-
}
|
|
206
|
-
else if (input === 'n' || input === 'N') {
|
|
207
|
-
setMode('create');
|
|
208
|
-
setInputValue('');
|
|
209
|
-
setError('');
|
|
210
|
-
}
|
|
211
|
-
else if (input === 'e' || input === 'E') {
|
|
212
|
-
handleEditProfile();
|
|
213
|
-
}
|
|
214
|
-
else if (input === 'r' || input === 'R') {
|
|
215
|
-
const currentProfile = profiles[selectedIndex];
|
|
216
|
-
if (currentProfile) {
|
|
217
|
-
setInputValue(currentProfile.name);
|
|
218
|
-
setMode('rename');
|
|
219
|
-
setError('');
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
else if (input === 'd' || input === 'D') {
|
|
223
|
-
const currentProfile = profiles[selectedIndex];
|
|
224
|
-
if (currentProfile && currentProfile.name !== 'default') {
|
|
225
|
-
setMode('delete-confirm');
|
|
226
|
-
setError('');
|
|
227
|
-
}
|
|
228
|
-
else if (currentProfile?.name === 'default') {
|
|
229
|
-
setError('Cannot delete the default profile');
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
// Render input mode
|
|
235
|
-
if (mode === 'create' || mode === 'rename') {
|
|
236
|
-
return (React.createElement(Box, { flexDirection: "column", padding: 1 },
|
|
237
|
-
React.createElement(Box, { marginBottom: 1, borderStyle: "double", borderColor: "cyan", paddingX: 2 },
|
|
238
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
239
|
-
React.createElement(Gradient, { name: "rainbow" }, mode === 'create' ? 'Create New Profile' : 'Rename Profile'),
|
|
240
|
-
React.createElement(Text, { color: "gray", dimColor: true }, mode === 'create'
|
|
241
|
-
? 'Enter a name for the new profile'
|
|
242
|
-
: 'Enter a new name for the profile'))),
|
|
243
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
244
|
-
React.createElement(Text, { color: "cyan" }, "Profile Name:"),
|
|
245
|
-
React.createElement(Box, { marginLeft: 2 },
|
|
246
|
-
React.createElement(TextInput, { value: inputValue, onChange: value => setInputValue(stripFocusArtifacts(value)), placeholder: "e.g., work, personal, test" }))),
|
|
247
|
-
error && (React.createElement(Box, { marginTop: 1 },
|
|
248
|
-
React.createElement(Text, { color: "red" },
|
|
249
|
-
"Error: ",
|
|
250
|
-
error))),
|
|
251
|
-
React.createElement(Box, { marginTop: 1 },
|
|
252
|
-
React.createElement(Alert, { variant: "info" }, "Press Enter to save, Esc to cancel"))));
|
|
253
|
-
}
|
|
254
|
-
// Render delete confirmation
|
|
255
|
-
if (mode === 'delete-confirm') {
|
|
256
|
-
const currentProfile = profiles[selectedIndex];
|
|
257
|
-
return (React.createElement(Box, { flexDirection: "column", padding: 1 },
|
|
258
|
-
React.createElement(Box, { marginBottom: 1, borderStyle: "double", borderColor: "cyan", paddingX: 2 },
|
|
259
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
260
|
-
React.createElement(Gradient, { name: "rainbow" }, "Delete Profile"),
|
|
261
|
-
React.createElement(Text, { color: "gray", dimColor: true }, "Confirm profile deletion"))),
|
|
262
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
263
|
-
React.createElement(Text, { color: "yellow" },
|
|
264
|
-
"Are you sure you want to delete the profile \"",
|
|
265
|
-
currentProfile?.displayName,
|
|
266
|
-
"\"?"),
|
|
267
|
-
React.createElement(Text, { color: "gray", dimColor: true }, "This action cannot be undone.")),
|
|
268
|
-
React.createElement(Box, { marginTop: 1 },
|
|
269
|
-
React.createElement(Alert, { variant: "warning" }, "Press Y to confirm, N or Esc to cancel"))));
|
|
270
|
-
}
|
|
271
|
-
// Render edit mode
|
|
272
|
-
if (mode === 'edit') {
|
|
273
|
-
return (React.createElement(ConfigScreen, { onBack: handleEditComplete, onSave: handleEditComplete, inlineMode: false }));
|
|
274
|
-
}
|
|
275
|
-
// Render profile list
|
|
276
|
-
return (React.createElement(Box, { flexDirection: "column", padding: 1 },
|
|
277
|
-
React.createElement(Box, { marginBottom: 1, borderStyle: "double", borderColor: "cyan", paddingX: 2 },
|
|
278
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
279
|
-
React.createElement(Gradient, { name: "rainbow" }, "Configuration Profiles"),
|
|
280
|
-
React.createElement(Text, { color: "gray", dimColor: true }, "Manage multiple configuration profiles"))),
|
|
281
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
282
|
-
React.createElement(Text, { color: "cyan", bold: true }, "Available Profiles:"),
|
|
283
|
-
profiles.map((profile, index) => (React.createElement(Box, { key: profile.name, flexDirection: "column", marginLeft: 1 },
|
|
284
|
-
React.createElement(Text, { color: index === selectedIndex ? 'green' : 'white', bold: profile.isActive },
|
|
285
|
-
index === selectedIndex ? '❯ ' : ' ',
|
|
286
|
-
profile.displayName,
|
|
287
|
-
profile.isActive && (React.createElement(Text, { color: "cyan", dimColor: true },
|
|
288
|
-
' ',
|
|
289
|
-
"(Active)"))),
|
|
290
|
-
index === selectedIndex && (React.createElement(Box, { marginLeft: 3 },
|
|
291
|
-
React.createElement(Text, { color: "gray", dimColor: true },
|
|
292
|
-
"API: ",
|
|
293
|
-
profile.config.snowcfg.baseUrl))))))),
|
|
294
|
-
error && (React.createElement(Box, { marginTop: 1 },
|
|
295
|
-
React.createElement(Text, { color: "red" },
|
|
296
|
-
"Error: ",
|
|
297
|
-
error))),
|
|
298
|
-
React.createElement(Box, { flexDirection: "column", marginTop: 1 },
|
|
299
|
-
React.createElement(Alert, { variant: "info" }, "\u2191\u2193: Navigate \u2022 Enter: Switch \u2022 E: Edit \u2022 N: New \u2022 R: Rename \u2022 D: Delete \u2022 Esc: Back"))));
|
|
300
|
-
}
|