ccmanager 0.2.0 → 1.0.0
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/README.md +26 -4
- package/dist/components/App.js +35 -1
- package/dist/components/ConfigureCommand.js +455 -124
- package/dist/components/PresetSelector.d.ts +7 -0
- package/dist/components/PresetSelector.js +52 -0
- package/dist/services/configurationManager.d.ts +11 -1
- package/dist/services/configurationManager.js +111 -3
- package/dist/services/configurationManager.selectPresetOnStart.test.d.ts +1 -0
- package/dist/services/configurationManager.selectPresetOnStart.test.js +103 -0
- package/dist/services/configurationManager.test.d.ts +1 -0
- package/dist/services/configurationManager.test.js +313 -0
- package/dist/services/sessionManager.d.ts +2 -4
- package/dist/services/sessionManager.js +78 -30
- package/dist/services/sessionManager.test.js +103 -0
- package/dist/services/stateDetector.d.ts +16 -0
- package/dist/services/stateDetector.js +67 -0
- package/dist/services/stateDetector.test.d.ts +1 -0
- package/dist/services/stateDetector.test.js +242 -0
- package/dist/types/index.d.ts +16 -0
- package/package.json +1 -1
|
@@ -1,150 +1,298 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
2
|
import { Box, Text, useInput } from 'ink';
|
|
3
3
|
import TextInput from 'ink-text-input';
|
|
4
|
+
import SelectInput from 'ink-select-input';
|
|
4
5
|
import { configurationManager } from '../services/configurationManager.js';
|
|
5
6
|
import { shortcutManager } from '../services/shortcutManager.js';
|
|
7
|
+
const formatDetectionStrategy = (strategy) => {
|
|
8
|
+
const value = strategy || 'claude';
|
|
9
|
+
return value === 'gemini' ? 'Gemini' : 'Claude';
|
|
10
|
+
};
|
|
6
11
|
const ConfigureCommand = ({ onComplete }) => {
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const [
|
|
10
|
-
const [
|
|
11
|
-
const [
|
|
12
|
+
const presetsConfig = configurationManager.getCommandPresets();
|
|
13
|
+
const [presets, setPresets] = useState(presetsConfig.presets);
|
|
14
|
+
const [defaultPresetId, setDefaultPresetId] = useState(presetsConfig.defaultPresetId);
|
|
15
|
+
const [selectPresetOnStart, setSelectPresetOnStart] = useState(configurationManager.getSelectPresetOnStart());
|
|
16
|
+
const [viewMode, setViewMode] = useState('list');
|
|
17
|
+
const [selectedPresetId, setSelectedPresetId] = useState(null);
|
|
12
18
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
19
|
+
const [editField, setEditField] = useState(null);
|
|
13
20
|
const [inputValue, setInputValue] = useState('');
|
|
14
|
-
const [
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
{
|
|
24
|
-
|
|
25
|
-
value: config.args?.join(' ') || '(none)',
|
|
26
|
-
key: 'args',
|
|
27
|
-
isButton: false,
|
|
28
|
-
disabled: false,
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
label: 'Fallback Arguments',
|
|
32
|
-
value: config.fallbackArgs?.join(' ') || '(none)',
|
|
33
|
-
key: 'fallbackArgs',
|
|
34
|
-
isButton: false,
|
|
35
|
-
disabled: false,
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
label: hasChanges ? '💾 Save Changes' : '💾 Save Changes (no changes)',
|
|
39
|
-
value: '',
|
|
40
|
-
key: 'save',
|
|
41
|
-
isButton: true,
|
|
42
|
-
disabled: !hasChanges,
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
label: '❌ Exit Without Saving',
|
|
46
|
-
value: '',
|
|
47
|
-
key: 'exit',
|
|
48
|
-
isButton: true,
|
|
49
|
-
disabled: false,
|
|
50
|
-
},
|
|
51
|
-
];
|
|
52
|
-
const handleMenuNavigation = (key) => {
|
|
53
|
-
if (key.upArrow) {
|
|
54
|
-
setSelectedIndex(prev => (prev > 0 ? prev - 1 : menuItems.length - 1));
|
|
21
|
+
const [isSelectingStrategy, setIsSelectingStrategy] = useState(false);
|
|
22
|
+
const [isSelectingStrategyInAdd, setIsSelectingStrategyInAdd] = useState(false);
|
|
23
|
+
const [newPreset, setNewPreset] = useState({});
|
|
24
|
+
const [addStep, setAddStep] = useState('name');
|
|
25
|
+
const [errorMessage, setErrorMessage] = useState(null);
|
|
26
|
+
// Remove handleListNavigation as SelectInput handles navigation internally
|
|
27
|
+
// Remove handleListSelection as we now use handleSelectItem
|
|
28
|
+
const handleEditMenuSelect = (item) => {
|
|
29
|
+
// Ignore separator selections
|
|
30
|
+
if (item.value.startsWith('separator')) {
|
|
31
|
+
return;
|
|
55
32
|
}
|
|
56
|
-
|
|
57
|
-
|
|
33
|
+
const preset = presets.find(p => p.id === selectedPresetId);
|
|
34
|
+
if (!preset)
|
|
35
|
+
return;
|
|
36
|
+
switch (item.value) {
|
|
37
|
+
case 'name':
|
|
38
|
+
setEditField('name');
|
|
39
|
+
setInputValue(preset.name);
|
|
40
|
+
break;
|
|
41
|
+
case 'command':
|
|
42
|
+
setEditField('command');
|
|
43
|
+
setInputValue(preset.command);
|
|
44
|
+
break;
|
|
45
|
+
case 'args':
|
|
46
|
+
setEditField('args');
|
|
47
|
+
setInputValue(preset.args?.join(' ') || '');
|
|
48
|
+
break;
|
|
49
|
+
case 'fallbackArgs':
|
|
50
|
+
setEditField('fallbackArgs');
|
|
51
|
+
setInputValue(preset.fallbackArgs?.join(' ') || '');
|
|
52
|
+
break;
|
|
53
|
+
case 'detectionStrategy':
|
|
54
|
+
setIsSelectingStrategy(true);
|
|
55
|
+
break;
|
|
56
|
+
case 'setDefault':
|
|
57
|
+
setDefaultPresetId(preset.id);
|
|
58
|
+
configurationManager.setDefaultPreset(preset.id);
|
|
59
|
+
break;
|
|
60
|
+
case 'delete':
|
|
61
|
+
if (presets.length > 1) {
|
|
62
|
+
setViewMode('delete-confirm');
|
|
63
|
+
setSelectedIndex(0);
|
|
64
|
+
}
|
|
65
|
+
break;
|
|
66
|
+
case 'back':
|
|
67
|
+
setViewMode('list');
|
|
68
|
+
setSelectedIndex(presets.findIndex(p => p.id === selectedPresetId));
|
|
69
|
+
break;
|
|
58
70
|
}
|
|
59
71
|
};
|
|
60
|
-
const
|
|
61
|
-
|
|
72
|
+
const handleFieldUpdate = (value) => {
|
|
73
|
+
const preset = presets.find(p => p.id === selectedPresetId);
|
|
74
|
+
if (!preset || !editField)
|
|
75
|
+
return;
|
|
76
|
+
const updatedPreset = { ...preset };
|
|
77
|
+
switch (editField) {
|
|
78
|
+
case 'name':
|
|
79
|
+
// Prevent using "Default" as a name to avoid confusion
|
|
80
|
+
if (value.trim().toLowerCase() === 'default') {
|
|
81
|
+
setErrorMessage('Cannot use "Default" as a preset name. Please choose a different name.');
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
updatedPreset.name = value;
|
|
85
|
+
break;
|
|
62
86
|
case 'command':
|
|
63
|
-
|
|
87
|
+
updatedPreset.command = value || 'claude';
|
|
88
|
+
break;
|
|
64
89
|
case 'args':
|
|
65
|
-
|
|
90
|
+
updatedPreset.args = value.trim()
|
|
91
|
+
? value.trim().split(/\s+/)
|
|
92
|
+
: undefined;
|
|
93
|
+
break;
|
|
66
94
|
case 'fallbackArgs':
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
95
|
+
updatedPreset.fallbackArgs = value.trim()
|
|
96
|
+
? value.trim().split(/\s+/)
|
|
97
|
+
: undefined;
|
|
98
|
+
break;
|
|
70
99
|
}
|
|
100
|
+
const updatedPresets = presets.map(p => p.id === preset.id ? updatedPreset : p);
|
|
101
|
+
setPresets(updatedPresets);
|
|
102
|
+
configurationManager.addPreset(updatedPreset);
|
|
103
|
+
setEditField(null);
|
|
104
|
+
setInputValue('');
|
|
105
|
+
setErrorMessage(null);
|
|
71
106
|
};
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
107
|
+
const handleAddPresetInput = (value) => {
|
|
108
|
+
switch (addStep) {
|
|
109
|
+
case 'name':
|
|
110
|
+
// Prevent using "Default" as a name to avoid confusion
|
|
111
|
+
if (value.trim().toLowerCase() === 'default') {
|
|
112
|
+
setErrorMessage('Cannot use "Default" as a preset name. Please choose a different name.');
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
setNewPreset({ ...newPreset, name: value });
|
|
116
|
+
setAddStep('command');
|
|
117
|
+
setInputValue('');
|
|
118
|
+
setErrorMessage(null);
|
|
80
119
|
break;
|
|
81
|
-
case '
|
|
82
|
-
|
|
120
|
+
case 'command':
|
|
121
|
+
setNewPreset({ ...newPreset, command: value || 'claude' });
|
|
122
|
+
setAddStep('args');
|
|
123
|
+
setInputValue('');
|
|
124
|
+
break;
|
|
125
|
+
case 'args': {
|
|
126
|
+
const args = value.trim() ? value.trim().split(/\s+/) : undefined;
|
|
127
|
+
setNewPreset({ ...newPreset, args });
|
|
128
|
+
setAddStep('fallbackArgs');
|
|
129
|
+
setInputValue('');
|
|
83
130
|
break;
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
131
|
+
}
|
|
132
|
+
case 'fallbackArgs': {
|
|
133
|
+
const fallbackArgs = value.trim()
|
|
134
|
+
? value.trim().split(/\s+/)
|
|
135
|
+
: undefined;
|
|
136
|
+
setNewPreset({ ...newPreset, fallbackArgs });
|
|
137
|
+
setAddStep('detectionStrategy');
|
|
138
|
+
setIsSelectingStrategyInAdd(true);
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
const handleStrategySelect = (item) => {
|
|
144
|
+
const preset = presets.find(p => p.id === selectedPresetId);
|
|
145
|
+
if (!preset)
|
|
146
|
+
return;
|
|
147
|
+
const updatedPreset = { ...preset };
|
|
148
|
+
updatedPreset.detectionStrategy = item.value;
|
|
149
|
+
const updatedPresets = presets.map(p => p.id === preset.id ? updatedPreset : p);
|
|
150
|
+
setPresets(updatedPresets);
|
|
151
|
+
configurationManager.addPreset(updatedPreset);
|
|
152
|
+
setIsSelectingStrategy(false);
|
|
153
|
+
};
|
|
154
|
+
const handleAddStrategySelect = (item) => {
|
|
155
|
+
const id = Date.now().toString();
|
|
156
|
+
const completePreset = {
|
|
157
|
+
id,
|
|
158
|
+
name: newPreset.name || 'New Preset',
|
|
159
|
+
command: newPreset.command || 'claude',
|
|
160
|
+
args: newPreset.args,
|
|
161
|
+
fallbackArgs: newPreset.fallbackArgs,
|
|
162
|
+
detectionStrategy: item.value,
|
|
163
|
+
};
|
|
164
|
+
const updatedPresets = [...presets, completePreset];
|
|
165
|
+
setPresets(updatedPresets);
|
|
166
|
+
configurationManager.addPreset(completePreset);
|
|
167
|
+
setViewMode('list');
|
|
168
|
+
setSelectedIndex(updatedPresets.length - 1);
|
|
169
|
+
setNewPreset({});
|
|
170
|
+
setAddStep('name');
|
|
171
|
+
setInputValue('');
|
|
172
|
+
setIsSelectingStrategyInAdd(false);
|
|
173
|
+
setErrorMessage(null);
|
|
174
|
+
};
|
|
175
|
+
const handleDeleteConfirm = () => {
|
|
176
|
+
if (selectedIndex === 0) {
|
|
177
|
+
// Yes, delete
|
|
178
|
+
const newPresets = presets.filter(p => p.id !== selectedPresetId);
|
|
179
|
+
setPresets(newPresets);
|
|
180
|
+
// Update default if needed
|
|
181
|
+
if (defaultPresetId === selectedPresetId && newPresets.length > 0) {
|
|
182
|
+
const firstPreset = newPresets[0];
|
|
183
|
+
if (firstPreset) {
|
|
184
|
+
setDefaultPresetId(firstPreset.id);
|
|
185
|
+
configurationManager.setDefaultPreset(firstPreset.id);
|
|
88
186
|
}
|
|
187
|
+
}
|
|
188
|
+
configurationManager.deletePreset(selectedPresetId);
|
|
189
|
+
setViewMode('list');
|
|
190
|
+
setSelectedIndex(0);
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
// Cancel
|
|
194
|
+
setViewMode('edit');
|
|
195
|
+
setSelectedIndex(6); // Back to delete option (index updated for new field)
|
|
89
196
|
}
|
|
90
197
|
};
|
|
91
198
|
useInput((input, key) => {
|
|
92
|
-
// Handle cancel shortcut in any mode
|
|
93
199
|
if (shortcutManager.matchesShortcut('cancel', input, key)) {
|
|
94
|
-
if (
|
|
95
|
-
|
|
200
|
+
if (isSelectingStrategy) {
|
|
201
|
+
setIsSelectingStrategy(false);
|
|
96
202
|
}
|
|
97
|
-
else {
|
|
98
|
-
|
|
203
|
+
else if (isSelectingStrategyInAdd) {
|
|
204
|
+
setIsSelectingStrategyInAdd(false);
|
|
205
|
+
setViewMode('list');
|
|
206
|
+
setAddStep('name');
|
|
207
|
+
setNewPreset({});
|
|
208
|
+
}
|
|
209
|
+
else if (editField) {
|
|
210
|
+
setEditField(null);
|
|
99
211
|
setInputValue('');
|
|
212
|
+
setErrorMessage(null);
|
|
213
|
+
}
|
|
214
|
+
else if (viewMode === 'edit') {
|
|
215
|
+
setViewMode('list');
|
|
216
|
+
setSelectedIndex(presets.findIndex(p => p.id === selectedPresetId));
|
|
217
|
+
setErrorMessage(null);
|
|
218
|
+
}
|
|
219
|
+
else if (viewMode === 'add') {
|
|
220
|
+
setViewMode('list');
|
|
221
|
+
setSelectedIndex(presets.length);
|
|
222
|
+
setErrorMessage(null);
|
|
223
|
+
}
|
|
224
|
+
else if (viewMode === 'delete-confirm') {
|
|
225
|
+
setViewMode('edit');
|
|
226
|
+
setSelectedIndex(6); // Updated index for delete option
|
|
100
227
|
}
|
|
228
|
+
else {
|
|
229
|
+
onComplete();
|
|
230
|
+
}
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (editField ||
|
|
234
|
+
(viewMode === 'add' &&
|
|
235
|
+
inputValue !== undefined &&
|
|
236
|
+
!isSelectingStrategyInAdd) ||
|
|
237
|
+
isSelectingStrategy ||
|
|
238
|
+
isSelectingStrategyInAdd) {
|
|
239
|
+
// In input mode, let TextInput or SelectInput handle it
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (viewMode === 'list' || viewMode === 'edit') {
|
|
243
|
+
// SelectInput handles navigation and selection
|
|
101
244
|
return;
|
|
102
245
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
246
|
+
else if (viewMode === 'delete-confirm') {
|
|
247
|
+
if (key.upArrow || key.downArrow) {
|
|
248
|
+
setSelectedIndex(prev => (prev === 0 ? 1 : 0));
|
|
249
|
+
}
|
|
250
|
+
else if (key.return) {
|
|
251
|
+
handleDeleteConfirm();
|
|
108
252
|
}
|
|
109
253
|
}
|
|
110
254
|
});
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
|
|
255
|
+
// Render strategy selection
|
|
256
|
+
if (isSelectingStrategy) {
|
|
257
|
+
const preset = presets.find(p => p.id === selectedPresetId);
|
|
258
|
+
if (!preset)
|
|
259
|
+
return null;
|
|
260
|
+
const strategyItems = [
|
|
261
|
+
{ label: 'Claude', value: 'claude' },
|
|
262
|
+
{ label: 'Gemini', value: 'gemini' },
|
|
263
|
+
];
|
|
264
|
+
const currentStrategy = preset.detectionStrategy || 'claude';
|
|
265
|
+
const initialIndex = strategyItems.findIndex(item => item.value === currentStrategy);
|
|
266
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
267
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
268
|
+
React.createElement(Text, { bold: true, color: "green" }, "Select Detection Strategy")),
|
|
269
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
270
|
+
React.createElement(Text, null, "Choose the state detection strategy for this preset:")),
|
|
271
|
+
React.createElement(SelectInput, { items: strategyItems, onSelect: handleStrategySelect, initialIndex: initialIndex }),
|
|
272
|
+
React.createElement(Box, { marginTop: 1 },
|
|
273
|
+
React.createElement(Text, { dimColor: true },
|
|
274
|
+
"Press Enter to select,",
|
|
275
|
+
' ',
|
|
276
|
+
shortcutManager.getShortcutDisplay('cancel'),
|
|
277
|
+
" to cancel"))));
|
|
278
|
+
}
|
|
279
|
+
// Render input field
|
|
280
|
+
if (editField) {
|
|
136
281
|
const titles = {
|
|
282
|
+
name: 'Enter preset name:',
|
|
137
283
|
command: 'Enter command (e.g., claude):',
|
|
138
284
|
args: 'Enter command arguments (space-separated):',
|
|
139
285
|
fallbackArgs: 'Enter fallback arguments (space-separated):',
|
|
140
286
|
};
|
|
141
287
|
return (React.createElement(Box, { flexDirection: "column" },
|
|
142
288
|
React.createElement(Box, { marginBottom: 1 },
|
|
143
|
-
React.createElement(Text, { bold: true, color: "green" }, "
|
|
289
|
+
React.createElement(Text, { bold: true, color: "green" }, "Edit Preset")),
|
|
144
290
|
React.createElement(Box, { marginBottom: 1 },
|
|
145
|
-
React.createElement(Text, null, titles[
|
|
291
|
+
React.createElement(Text, null, titles[editField])),
|
|
292
|
+
errorMessage && (React.createElement(Box, { marginBottom: 1 },
|
|
293
|
+
React.createElement(Text, { color: "red" }, errorMessage))),
|
|
146
294
|
React.createElement(Box, null,
|
|
147
|
-
React.createElement(TextInput, { value: inputValue, onChange: setInputValue, onSubmit:
|
|
295
|
+
React.createElement(TextInput, { value: inputValue, onChange: setInputValue, onSubmit: handleFieldUpdate, placeholder: editField === 'args' || editField === 'fallbackArgs'
|
|
148
296
|
? 'e.g., --resume or leave empty'
|
|
149
297
|
: '' })),
|
|
150
298
|
React.createElement(Box, { marginTop: 1 },
|
|
@@ -154,29 +302,212 @@ const ConfigureCommand = ({ onComplete }) => {
|
|
|
154
302
|
' ',
|
|
155
303
|
"to cancel"))));
|
|
156
304
|
}
|
|
305
|
+
// Render add preset form
|
|
306
|
+
if (viewMode === 'add') {
|
|
307
|
+
if (isSelectingStrategyInAdd) {
|
|
308
|
+
const strategyItems = [
|
|
309
|
+
{ label: 'Claude', value: 'claude' },
|
|
310
|
+
{ label: 'Gemini', value: 'gemini' },
|
|
311
|
+
];
|
|
312
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
313
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
314
|
+
React.createElement(Text, { bold: true, color: "green" }, "Add New Preset - Detection Strategy")),
|
|
315
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
316
|
+
React.createElement(Text, null, "Choose the state detection strategy for this preset:")),
|
|
317
|
+
React.createElement(SelectInput, { items: strategyItems, onSelect: handleAddStrategySelect, initialIndex: 0 }),
|
|
318
|
+
React.createElement(Box, { marginTop: 1 },
|
|
319
|
+
React.createElement(Text, { dimColor: true },
|
|
320
|
+
"Press Enter to select,",
|
|
321
|
+
' ',
|
|
322
|
+
shortcutManager.getShortcutDisplay('cancel'),
|
|
323
|
+
" to cancel"))));
|
|
324
|
+
}
|
|
325
|
+
const titles = {
|
|
326
|
+
name: 'Enter preset name:',
|
|
327
|
+
command: 'Enter command (e.g., claude):',
|
|
328
|
+
args: 'Enter command arguments (space-separated):',
|
|
329
|
+
fallbackArgs: 'Enter fallback arguments (space-separated):',
|
|
330
|
+
};
|
|
331
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
332
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
333
|
+
React.createElement(Text, { bold: true, color: "green" }, "Add New Preset")),
|
|
334
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
335
|
+
React.createElement(Text, null, titles[addStep])),
|
|
336
|
+
errorMessage && (React.createElement(Box, { marginBottom: 1 },
|
|
337
|
+
React.createElement(Text, { color: "red" }, errorMessage))),
|
|
338
|
+
React.createElement(Box, null,
|
|
339
|
+
React.createElement(TextInput, { value: inputValue, onChange: setInputValue, onSubmit: handleAddPresetInput, placeholder: addStep === 'args' || addStep === 'fallbackArgs'
|
|
340
|
+
? 'e.g., --resume or leave empty'
|
|
341
|
+
: addStep === 'name'
|
|
342
|
+
? 'e.g., Development'
|
|
343
|
+
: '' })),
|
|
344
|
+
React.createElement(Box, { marginTop: 1 },
|
|
345
|
+
React.createElement(Text, { dimColor: true },
|
|
346
|
+
"Press Enter to continue,",
|
|
347
|
+
' ',
|
|
348
|
+
shortcutManager.getShortcutDisplay('cancel'),
|
|
349
|
+
" to cancel"))));
|
|
350
|
+
}
|
|
351
|
+
// Render delete confirmation
|
|
352
|
+
if (viewMode === 'delete-confirm') {
|
|
353
|
+
const preset = presets.find(p => p.id === selectedPresetId);
|
|
354
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
355
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
356
|
+
React.createElement(Text, { bold: true, color: "red" }, "Confirm Delete")),
|
|
357
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
358
|
+
React.createElement(Text, null,
|
|
359
|
+
"Delete preset \"",
|
|
360
|
+
preset?.name,
|
|
361
|
+
"\"?")),
|
|
362
|
+
React.createElement(Box, { flexDirection: "column" },
|
|
363
|
+
React.createElement(Box, null,
|
|
364
|
+
React.createElement(Text, { color: selectedIndex === 0 ? 'red' : undefined },
|
|
365
|
+
selectedIndex === 0 ? '> ' : ' ',
|
|
366
|
+
"Yes, delete")),
|
|
367
|
+
React.createElement(Box, null,
|
|
368
|
+
React.createElement(Text, { color: selectedIndex === 1 ? 'cyan' : undefined },
|
|
369
|
+
selectedIndex === 1 ? '> ' : ' ',
|
|
370
|
+
"Cancel"))),
|
|
371
|
+
React.createElement(Box, { marginTop: 1 },
|
|
372
|
+
React.createElement(Text, { dimColor: true }, "Press \u2191\u2193 to navigate, Enter to confirm"))));
|
|
373
|
+
}
|
|
374
|
+
// Render edit preset view
|
|
375
|
+
if (viewMode === 'edit') {
|
|
376
|
+
const preset = presets.find(p => p.id === selectedPresetId);
|
|
377
|
+
if (!preset)
|
|
378
|
+
return null;
|
|
379
|
+
const isDefault = preset.id === defaultPresetId;
|
|
380
|
+
const canDelete = presets.length > 1;
|
|
381
|
+
const editMenuItems = [
|
|
382
|
+
{
|
|
383
|
+
label: `Name: ${preset.name}`,
|
|
384
|
+
value: 'name',
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
label: `Command: ${preset.command}`,
|
|
388
|
+
value: 'command',
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
label: `Arguments: ${preset.args?.join(' ') || '(none)'}`,
|
|
392
|
+
value: 'args',
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
label: `Fallback Arguments: ${preset.fallbackArgs?.join(' ') || '(none)'}`,
|
|
396
|
+
value: 'fallbackArgs',
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
label: `Detection Strategy: ${formatDetectionStrategy(preset.detectionStrategy)}`,
|
|
400
|
+
value: 'detectionStrategy',
|
|
401
|
+
},
|
|
402
|
+
{ label: '─────────────────────────', value: 'separator1' },
|
|
403
|
+
{
|
|
404
|
+
label: isDefault ? '⭐ Already Default' : 'Set as Default',
|
|
405
|
+
value: 'setDefault',
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
label: canDelete
|
|
409
|
+
? 'Delete Preset'
|
|
410
|
+
: 'Delete Preset (cannot delete last preset)',
|
|
411
|
+
value: 'delete',
|
|
412
|
+
},
|
|
413
|
+
{ label: '─────────────────────────', value: 'separator2' },
|
|
414
|
+
{ label: '← Back to List', value: 'back' },
|
|
415
|
+
];
|
|
416
|
+
// Filter out disabled items for SelectInput
|
|
417
|
+
const selectableItems = editMenuItems.filter(item => {
|
|
418
|
+
if (item.value === 'setDefault' && isDefault)
|
|
419
|
+
return false;
|
|
420
|
+
if (item.value === 'delete' && !canDelete)
|
|
421
|
+
return false;
|
|
422
|
+
return true;
|
|
423
|
+
});
|
|
424
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
425
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
426
|
+
React.createElement(Text, { bold: true, color: "green" },
|
|
427
|
+
"Edit Preset: ",
|
|
428
|
+
preset.name)),
|
|
429
|
+
isDefault && (React.createElement(Box, { marginBottom: 1 },
|
|
430
|
+
React.createElement(Text, { color: "yellow" }, "\u2B50 This is the default preset"))),
|
|
431
|
+
React.createElement(SelectInput, { items: selectableItems, onSelect: handleEditMenuSelect }),
|
|
432
|
+
React.createElement(Box, { marginTop: 1 },
|
|
433
|
+
React.createElement(Text, { dimColor: true },
|
|
434
|
+
"Press \u2191\u2193 to navigate, Enter to edit/select,",
|
|
435
|
+
' ',
|
|
436
|
+
shortcutManager.getShortcutDisplay('cancel'),
|
|
437
|
+
" to go back"))));
|
|
438
|
+
}
|
|
439
|
+
// Render preset list (default view)
|
|
440
|
+
const selectItems = [
|
|
441
|
+
...presets.map(preset => {
|
|
442
|
+
const isDefault = preset.id === defaultPresetId;
|
|
443
|
+
const args = preset.args?.join(' ') || '';
|
|
444
|
+
const fallback = preset.fallbackArgs?.join(' ') || '';
|
|
445
|
+
let label = preset.name;
|
|
446
|
+
if (isDefault)
|
|
447
|
+
label += ' (default)';
|
|
448
|
+
label += `\n Command: ${preset.command}`;
|
|
449
|
+
if (args)
|
|
450
|
+
label += `\n Args: ${args}`;
|
|
451
|
+
if (fallback)
|
|
452
|
+
label += `\n Fallback: ${fallback}`;
|
|
453
|
+
label += `\n Detection: ${formatDetectionStrategy(preset.detectionStrategy)}`;
|
|
454
|
+
return {
|
|
455
|
+
label,
|
|
456
|
+
value: preset.id,
|
|
457
|
+
};
|
|
458
|
+
}),
|
|
459
|
+
{ label: '─────────────────────────', value: 'separator1' },
|
|
460
|
+
{
|
|
461
|
+
label: `Select preset before session start: ${selectPresetOnStart ? '✅ Enabled' : '❌ Disabled'}`,
|
|
462
|
+
value: 'toggle-select-on-start',
|
|
463
|
+
},
|
|
464
|
+
{ label: '─────────────────────────', value: 'separator2' },
|
|
465
|
+
{ label: 'Add New Preset', value: 'add' },
|
|
466
|
+
{ label: '← Cancel', value: 'exit' },
|
|
467
|
+
];
|
|
468
|
+
const handleSelectItem = (item) => {
|
|
469
|
+
if (item.value === 'add') {
|
|
470
|
+
// Add New Preset
|
|
471
|
+
setViewMode('add');
|
|
472
|
+
setNewPreset({});
|
|
473
|
+
setAddStep('name');
|
|
474
|
+
setInputValue('');
|
|
475
|
+
}
|
|
476
|
+
else if (item.value === 'exit') {
|
|
477
|
+
// Exit
|
|
478
|
+
onComplete();
|
|
479
|
+
}
|
|
480
|
+
else if (item.value === 'toggle-select-on-start') {
|
|
481
|
+
// Toggle select preset on start
|
|
482
|
+
const newValue = !selectPresetOnStart;
|
|
483
|
+
setSelectPresetOnStart(newValue);
|
|
484
|
+
configurationManager.setSelectPresetOnStart(newValue);
|
|
485
|
+
}
|
|
486
|
+
else if (item.value.startsWith('separator')) {
|
|
487
|
+
// Ignore separator selections
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
else {
|
|
491
|
+
// Selected a preset
|
|
492
|
+
const preset = presets.find(p => p.id === item.value);
|
|
493
|
+
if (preset) {
|
|
494
|
+
setSelectedPresetId(preset.id);
|
|
495
|
+
setViewMode('edit');
|
|
496
|
+
setSelectedIndex(0);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
};
|
|
157
500
|
return (React.createElement(Box, { flexDirection: "column" },
|
|
158
501
|
React.createElement(Box, { marginBottom: 1 },
|
|
159
|
-
React.createElement(Text, { bold: true, color: "green" }, "
|
|
502
|
+
React.createElement(Text, { bold: true, color: "green" }, "Command Presets")),
|
|
160
503
|
React.createElement(Box, { marginBottom: 1 },
|
|
161
|
-
React.createElement(Text, { dimColor: true }, "Configure
|
|
162
|
-
|
|
163
|
-
React.createElement(Text, { color: "yellow" }, "\u26A0\uFE0F You have unsaved changes"))),
|
|
164
|
-
React.createElement(Box, { flexDirection: "column" }, menuItems.map((item, index) => {
|
|
165
|
-
const isSelected = selectedIndex === index;
|
|
166
|
-
const isDisabled = item.disabled || false;
|
|
167
|
-
const color = isDisabled ? 'gray' : isSelected ? 'cyan' : undefined;
|
|
168
|
-
return (React.createElement(Box, { key: item.key, marginTop: item.isButton && index > 0 ? 1 : 0 },
|
|
169
|
-
React.createElement(Text, { color: color },
|
|
170
|
-
isSelected ? '> ' : ' ',
|
|
171
|
-
item.isButton ? (React.createElement(Text, { bold: isSelected && !isDisabled, dimColor: isDisabled }, item.label)) : (`${item.label}: ${item.value}`))));
|
|
172
|
-
})),
|
|
504
|
+
React.createElement(Text, { dimColor: true }, "Configure command presets for running code sessions")),
|
|
505
|
+
React.createElement(SelectInput, { items: selectItems, onSelect: handleSelectItem, initialIndex: selectedIndex }),
|
|
173
506
|
React.createElement(Box, { marginTop: 1 },
|
|
174
507
|
React.createElement(Text, { dimColor: true },
|
|
175
|
-
"Press \u2191\u2193 to navigate, Enter to
|
|
508
|
+
"Press \u2191\u2193 to navigate, Enter to select,",
|
|
176
509
|
' ',
|
|
177
510
|
shortcutManager.getShortcutDisplay('cancel'),
|
|
178
|
-
" to
|
|
179
|
-
React.createElement(Box, { marginTop: 1 },
|
|
180
|
-
React.createElement(Text, { dimColor: true }, "Note: If command fails with main args, fallback args will be tried"))));
|
|
511
|
+
" to exit"))));
|
|
181
512
|
};
|
|
182
513
|
export default ConfigureCommand;
|