ccmanager 0.2.0 → 0.2.1
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/components/App.js +35 -1
- package/dist/components/ConfigureCommand.js +367 -121
- 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 +1 -0
- package/dist/services/sessionManager.js +69 -0
- package/dist/services/sessionManager.test.js +103 -0
- package/dist/types/index.d.ts +13 -0
- package/package.json +1 -1
package/dist/components/App.js
CHANGED
|
@@ -6,9 +6,11 @@ import NewWorktree from './NewWorktree.js';
|
|
|
6
6
|
import DeleteWorktree from './DeleteWorktree.js';
|
|
7
7
|
import MergeWorktree from './MergeWorktree.js';
|
|
8
8
|
import Configuration from './Configuration.js';
|
|
9
|
+
import PresetSelector from './PresetSelector.js';
|
|
9
10
|
import { SessionManager } from '../services/sessionManager.js';
|
|
10
11
|
import { WorktreeService } from '../services/worktreeService.js';
|
|
11
12
|
import { shortcutManager } from '../services/shortcutManager.js';
|
|
13
|
+
import { configurationManager } from '../services/configurationManager.js';
|
|
12
14
|
const App = () => {
|
|
13
15
|
const { exit } = useApp();
|
|
14
16
|
const [view, setView] = useState('menu');
|
|
@@ -17,6 +19,7 @@ const App = () => {
|
|
|
17
19
|
const [activeSession, setActiveSession] = useState(null);
|
|
18
20
|
const [error, setError] = useState(null);
|
|
19
21
|
const [menuKey, setMenuKey] = useState(0); // Force menu refresh
|
|
22
|
+
const [selectedWorktree, setSelectedWorktree] = useState(null); // Store selected worktree for preset selection
|
|
20
23
|
useEffect(() => {
|
|
21
24
|
// Listen for session exits to return to menu automatically
|
|
22
25
|
const handleSessionExit = (session) => {
|
|
@@ -76,8 +79,15 @@ const App = () => {
|
|
|
76
79
|
// Get or create session for this worktree
|
|
77
80
|
let session = sessionManager.getSession(worktree.path);
|
|
78
81
|
if (!session) {
|
|
82
|
+
// Check if we should show preset selector
|
|
83
|
+
if (configurationManager.getSelectPresetOnStart()) {
|
|
84
|
+
setSelectedWorktree(worktree);
|
|
85
|
+
setView('preset-selector');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
79
88
|
try {
|
|
80
|
-
session
|
|
89
|
+
// Use preset-based session creation with default preset
|
|
90
|
+
session = await sessionManager.createSessionWithPreset(worktree.path);
|
|
81
91
|
}
|
|
82
92
|
catch (error) {
|
|
83
93
|
setError(`Failed to create session: ${error}`);
|
|
@@ -87,6 +97,27 @@ const App = () => {
|
|
|
87
97
|
setActiveSession(session);
|
|
88
98
|
setView('session');
|
|
89
99
|
};
|
|
100
|
+
const handlePresetSelected = async (presetId) => {
|
|
101
|
+
if (!selectedWorktree)
|
|
102
|
+
return;
|
|
103
|
+
try {
|
|
104
|
+
// Create session with selected preset
|
|
105
|
+
const session = await sessionManager.createSessionWithPreset(selectedWorktree.path, presetId);
|
|
106
|
+
setActiveSession(session);
|
|
107
|
+
setView('session');
|
|
108
|
+
setSelectedWorktree(null);
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
setError(`Failed to create session: ${error}`);
|
|
112
|
+
setView('menu');
|
|
113
|
+
setSelectedWorktree(null);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
const handlePresetSelectorCancel = () => {
|
|
117
|
+
setSelectedWorktree(null);
|
|
118
|
+
setView('menu');
|
|
119
|
+
setMenuKey(prev => prev + 1);
|
|
120
|
+
};
|
|
90
121
|
const handleReturnToMenu = () => {
|
|
91
122
|
setActiveSession(null);
|
|
92
123
|
setError(null);
|
|
@@ -229,6 +260,9 @@ const App = () => {
|
|
|
229
260
|
if (view === 'configuration') {
|
|
230
261
|
return React.createElement(Configuration, { onComplete: handleReturnToMenu });
|
|
231
262
|
}
|
|
263
|
+
if (view === 'preset-selector') {
|
|
264
|
+
return (React.createElement(PresetSelector, { onSelect: handlePresetSelected, onCancel: handlePresetSelectorCancel }));
|
|
265
|
+
}
|
|
232
266
|
return null;
|
|
233
267
|
};
|
|
234
268
|
export default App;
|
|
@@ -1,150 +1,240 @@
|
|
|
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';
|
|
6
7
|
const ConfigureCommand = ({ onComplete }) => {
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const [
|
|
10
|
-
const [
|
|
11
|
-
const [
|
|
8
|
+
const presetsConfig = configurationManager.getCommandPresets();
|
|
9
|
+
const [presets, setPresets] = useState(presetsConfig.presets);
|
|
10
|
+
const [defaultPresetId, setDefaultPresetId] = useState(presetsConfig.defaultPresetId);
|
|
11
|
+
const [selectPresetOnStart, setSelectPresetOnStart] = useState(configurationManager.getSelectPresetOnStart());
|
|
12
|
+
const [viewMode, setViewMode] = useState('list');
|
|
13
|
+
const [selectedPresetId, setSelectedPresetId] = useState(null);
|
|
12
14
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
15
|
+
const [editField, setEditField] = useState(null);
|
|
13
16
|
const [inputValue, setInputValue] = useState('');
|
|
14
|
-
const [
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
disabled: false,
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
label: 'Arguments',
|
|
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) => {
|
|
17
|
+
const [newPreset, setNewPreset] = useState({});
|
|
18
|
+
const [addStep, setAddStep] = useState('name');
|
|
19
|
+
const [errorMessage, setErrorMessage] = useState(null);
|
|
20
|
+
// Remove handleListNavigation as SelectInput handles navigation internally
|
|
21
|
+
// Remove handleListSelection as we now use handleSelectItem
|
|
22
|
+
const handleEditNavigation = (key) => {
|
|
23
|
+
const menuItems = 7; // name, command, args, fallbackArgs, set default, delete, back
|
|
53
24
|
if (key.upArrow) {
|
|
54
|
-
setSelectedIndex(prev => (prev > 0 ? prev - 1 : menuItems
|
|
25
|
+
setSelectedIndex(prev => (prev > 0 ? prev - 1 : menuItems - 1));
|
|
55
26
|
}
|
|
56
27
|
else if (key.downArrow) {
|
|
57
|
-
setSelectedIndex(prev => (prev < menuItems
|
|
28
|
+
setSelectedIndex(prev => (prev < menuItems - 1 ? prev + 1 : 0));
|
|
58
29
|
}
|
|
59
30
|
};
|
|
60
|
-
const
|
|
61
|
-
|
|
31
|
+
const handleEditSelection = () => {
|
|
32
|
+
const preset = presets.find(p => p.id === selectedPresetId);
|
|
33
|
+
if (!preset)
|
|
34
|
+
return;
|
|
35
|
+
switch (selectedIndex) {
|
|
36
|
+
case 0: // Name
|
|
37
|
+
setEditField('name');
|
|
38
|
+
setInputValue(preset.name);
|
|
39
|
+
break;
|
|
40
|
+
case 1: // Command
|
|
41
|
+
setEditField('command');
|
|
42
|
+
setInputValue(preset.command);
|
|
43
|
+
break;
|
|
44
|
+
case 2: // Args
|
|
45
|
+
setEditField('args');
|
|
46
|
+
setInputValue(preset.args?.join(' ') || '');
|
|
47
|
+
break;
|
|
48
|
+
case 3: // Fallback Args
|
|
49
|
+
setEditField('fallbackArgs');
|
|
50
|
+
setInputValue(preset.fallbackArgs?.join(' ') || '');
|
|
51
|
+
break;
|
|
52
|
+
case 4: // Set as Default
|
|
53
|
+
setDefaultPresetId(preset.id);
|
|
54
|
+
configurationManager.setDefaultPreset(preset.id);
|
|
55
|
+
break;
|
|
56
|
+
case 5: // Delete
|
|
57
|
+
if (presets.length > 1) {
|
|
58
|
+
setViewMode('delete-confirm');
|
|
59
|
+
setSelectedIndex(0);
|
|
60
|
+
}
|
|
61
|
+
break;
|
|
62
|
+
case 6: // Back
|
|
63
|
+
setViewMode('list');
|
|
64
|
+
setSelectedIndex(presets.findIndex(p => p.id === selectedPresetId));
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
const handleFieldUpdate = (value) => {
|
|
69
|
+
const preset = presets.find(p => p.id === selectedPresetId);
|
|
70
|
+
if (!preset || !editField)
|
|
71
|
+
return;
|
|
72
|
+
const updatedPreset = { ...preset };
|
|
73
|
+
switch (editField) {
|
|
74
|
+
case 'name':
|
|
75
|
+
// Prevent using "Default" as a name to avoid confusion
|
|
76
|
+
if (value.trim().toLowerCase() === 'default') {
|
|
77
|
+
setErrorMessage('Cannot use "Default" as a preset name. Please choose a different name.');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
updatedPreset.name = value;
|
|
81
|
+
break;
|
|
62
82
|
case 'command':
|
|
63
|
-
|
|
83
|
+
updatedPreset.command = value || 'claude';
|
|
84
|
+
break;
|
|
64
85
|
case 'args':
|
|
65
|
-
|
|
86
|
+
updatedPreset.args = value.trim()
|
|
87
|
+
? value.trim().split(/\s+/)
|
|
88
|
+
: undefined;
|
|
89
|
+
break;
|
|
66
90
|
case 'fallbackArgs':
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
91
|
+
updatedPreset.fallbackArgs = value.trim()
|
|
92
|
+
? value.trim().split(/\s+/)
|
|
93
|
+
: undefined;
|
|
94
|
+
break;
|
|
70
95
|
}
|
|
96
|
+
const updatedPresets = presets.map(p => p.id === preset.id ? updatedPreset : p);
|
|
97
|
+
setPresets(updatedPresets);
|
|
98
|
+
configurationManager.addPreset(updatedPreset);
|
|
99
|
+
setEditField(null);
|
|
100
|
+
setInputValue('');
|
|
101
|
+
setErrorMessage(null);
|
|
71
102
|
};
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
103
|
+
const handleAddPresetInput = (value) => {
|
|
104
|
+
switch (addStep) {
|
|
105
|
+
case 'name':
|
|
106
|
+
// Prevent using "Default" as a name to avoid confusion
|
|
107
|
+
if (value.trim().toLowerCase() === 'default') {
|
|
108
|
+
setErrorMessage('Cannot use "Default" as a preset name. Please choose a different name.');
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
setNewPreset({ ...newPreset, name: value });
|
|
112
|
+
setAddStep('command');
|
|
113
|
+
setInputValue('');
|
|
114
|
+
setErrorMessage(null);
|
|
80
115
|
break;
|
|
81
|
-
case '
|
|
82
|
-
|
|
116
|
+
case 'command':
|
|
117
|
+
setNewPreset({ ...newPreset, command: value || 'claude' });
|
|
118
|
+
setAddStep('args');
|
|
119
|
+
setInputValue('');
|
|
120
|
+
break;
|
|
121
|
+
case 'args': {
|
|
122
|
+
const args = value.trim() ? value.trim().split(/\s+/) : undefined;
|
|
123
|
+
setNewPreset({ ...newPreset, args });
|
|
124
|
+
setAddStep('fallbackArgs');
|
|
125
|
+
setInputValue('');
|
|
83
126
|
break;
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
127
|
+
}
|
|
128
|
+
case 'fallbackArgs': {
|
|
129
|
+
const fallbackArgs = value.trim()
|
|
130
|
+
? value.trim().split(/\s+/)
|
|
131
|
+
: undefined;
|
|
132
|
+
const id = Date.now().toString();
|
|
133
|
+
const completePreset = {
|
|
134
|
+
id,
|
|
135
|
+
name: newPreset.name || 'New Preset',
|
|
136
|
+
command: newPreset.command || 'claude',
|
|
137
|
+
args: newPreset.args,
|
|
138
|
+
fallbackArgs,
|
|
139
|
+
};
|
|
140
|
+
const updatedPresets = [...presets, completePreset];
|
|
141
|
+
setPresets(updatedPresets);
|
|
142
|
+
configurationManager.addPreset(completePreset);
|
|
143
|
+
setViewMode('list');
|
|
144
|
+
setSelectedIndex(updatedPresets.length - 1);
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
const handleDeleteConfirm = () => {
|
|
150
|
+
if (selectedIndex === 0) {
|
|
151
|
+
// Yes, delete
|
|
152
|
+
const newPresets = presets.filter(p => p.id !== selectedPresetId);
|
|
153
|
+
setPresets(newPresets);
|
|
154
|
+
// Update default if needed
|
|
155
|
+
if (defaultPresetId === selectedPresetId && newPresets.length > 0) {
|
|
156
|
+
const firstPreset = newPresets[0];
|
|
157
|
+
if (firstPreset) {
|
|
158
|
+
setDefaultPresetId(firstPreset.id);
|
|
159
|
+
configurationManager.setDefaultPreset(firstPreset.id);
|
|
88
160
|
}
|
|
161
|
+
}
|
|
162
|
+
configurationManager.deletePreset(selectedPresetId);
|
|
163
|
+
setViewMode('list');
|
|
164
|
+
setSelectedIndex(0);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
// Cancel
|
|
168
|
+
setViewMode('edit');
|
|
169
|
+
setSelectedIndex(5); // Back to delete option
|
|
89
170
|
}
|
|
90
171
|
};
|
|
91
172
|
useInput((input, key) => {
|
|
92
|
-
// Handle cancel shortcut in any mode
|
|
93
173
|
if (shortcutManager.matchesShortcut('cancel', input, key)) {
|
|
94
|
-
if (
|
|
95
|
-
|
|
174
|
+
if (editField) {
|
|
175
|
+
setEditField(null);
|
|
176
|
+
setInputValue('');
|
|
177
|
+
setErrorMessage(null);
|
|
178
|
+
}
|
|
179
|
+
else if (viewMode === 'edit') {
|
|
180
|
+
setViewMode('list');
|
|
181
|
+
setSelectedIndex(presets.findIndex(p => p.id === selectedPresetId));
|
|
182
|
+
setErrorMessage(null);
|
|
183
|
+
}
|
|
184
|
+
else if (viewMode === 'add') {
|
|
185
|
+
setViewMode('list');
|
|
186
|
+
setSelectedIndex(presets.length);
|
|
187
|
+
setErrorMessage(null);
|
|
188
|
+
}
|
|
189
|
+
else if (viewMode === 'delete-confirm') {
|
|
190
|
+
setViewMode('edit');
|
|
191
|
+
setSelectedIndex(5);
|
|
96
192
|
}
|
|
97
193
|
else {
|
|
98
|
-
|
|
99
|
-
setInputValue('');
|
|
194
|
+
onComplete();
|
|
100
195
|
}
|
|
101
196
|
return;
|
|
102
197
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
198
|
+
if (editField || (viewMode === 'add' && inputValue !== undefined)) {
|
|
199
|
+
// In input mode, let TextInput handle it
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (viewMode === 'list') {
|
|
203
|
+
// SelectInput handles navigation and selection
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
else if (viewMode === 'edit') {
|
|
207
|
+
handleEditNavigation(key);
|
|
106
208
|
if (key.return) {
|
|
107
|
-
|
|
209
|
+
handleEditSelection();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else if (viewMode === 'delete-confirm') {
|
|
213
|
+
if (key.upArrow || key.downArrow) {
|
|
214
|
+
setSelectedIndex(prev => (prev === 0 ? 1 : 0));
|
|
215
|
+
}
|
|
216
|
+
else if (key.return) {
|
|
217
|
+
handleDeleteConfirm();
|
|
108
218
|
}
|
|
109
219
|
}
|
|
110
220
|
});
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (editMode === 'command') {
|
|
114
|
-
updatedConfig.command = value || 'claude';
|
|
115
|
-
}
|
|
116
|
-
else if (editMode === 'args') {
|
|
117
|
-
// Parse arguments, handling empty string as no arguments
|
|
118
|
-
const args = value.trim() ? value.trim().split(/\s+/) : undefined;
|
|
119
|
-
updatedConfig.args = args;
|
|
120
|
-
}
|
|
121
|
-
else if (editMode === 'fallbackArgs') {
|
|
122
|
-
// Parse fallback arguments, handling empty string as no arguments
|
|
123
|
-
const fallbackArgs = value.trim() ? value.trim().split(/\s+/) : undefined;
|
|
124
|
-
updatedConfig.fallbackArgs = fallbackArgs;
|
|
125
|
-
}
|
|
126
|
-
// Update state only (don't save to file yet)
|
|
127
|
-
setConfig(updatedConfig);
|
|
128
|
-
// Check if there are changes
|
|
129
|
-
const hasChanges = JSON.stringify(updatedConfig) !== JSON.stringify(originalConfig);
|
|
130
|
-
setHasChanges(hasChanges);
|
|
131
|
-
// Return to menu
|
|
132
|
-
setEditMode('menu');
|
|
133
|
-
setInputValue('');
|
|
134
|
-
};
|
|
135
|
-
if (editMode !== 'menu') {
|
|
221
|
+
// Render input field
|
|
222
|
+
if (editField) {
|
|
136
223
|
const titles = {
|
|
224
|
+
name: 'Enter preset name:',
|
|
137
225
|
command: 'Enter command (e.g., claude):',
|
|
138
226
|
args: 'Enter command arguments (space-separated):',
|
|
139
227
|
fallbackArgs: 'Enter fallback arguments (space-separated):',
|
|
140
228
|
};
|
|
141
229
|
return (React.createElement(Box, { flexDirection: "column" },
|
|
142
230
|
React.createElement(Box, { marginBottom: 1 },
|
|
143
|
-
React.createElement(Text, { bold: true, color: "green" }, "
|
|
231
|
+
React.createElement(Text, { bold: true, color: "green" }, "Edit Preset")),
|
|
144
232
|
React.createElement(Box, { marginBottom: 1 },
|
|
145
|
-
React.createElement(Text, null, titles[
|
|
233
|
+
React.createElement(Text, null, titles[editField])),
|
|
234
|
+
errorMessage && (React.createElement(Box, { marginBottom: 1 },
|
|
235
|
+
React.createElement(Text, { color: "red" }, errorMessage))),
|
|
146
236
|
React.createElement(Box, null,
|
|
147
|
-
React.createElement(TextInput, { value: inputValue, onChange: setInputValue, onSubmit:
|
|
237
|
+
React.createElement(TextInput, { value: inputValue, onChange: setInputValue, onSubmit: handleFieldUpdate, placeholder: editField === 'args' || editField === 'fallbackArgs'
|
|
148
238
|
? 'e.g., --resume or leave empty'
|
|
149
239
|
: '' })),
|
|
150
240
|
React.createElement(Box, { marginTop: 1 },
|
|
@@ -154,29 +244,185 @@ const ConfigureCommand = ({ onComplete }) => {
|
|
|
154
244
|
' ',
|
|
155
245
|
"to cancel"))));
|
|
156
246
|
}
|
|
247
|
+
// Render add preset form
|
|
248
|
+
if (viewMode === 'add') {
|
|
249
|
+
const titles = {
|
|
250
|
+
name: 'Enter preset name:',
|
|
251
|
+
command: 'Enter command (e.g., claude):',
|
|
252
|
+
args: 'Enter command arguments (space-separated):',
|
|
253
|
+
fallbackArgs: 'Enter fallback arguments (space-separated):',
|
|
254
|
+
};
|
|
255
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
256
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
257
|
+
React.createElement(Text, { bold: true, color: "green" }, "Add New Preset")),
|
|
258
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
259
|
+
React.createElement(Text, null, titles[addStep])),
|
|
260
|
+
errorMessage && (React.createElement(Box, { marginBottom: 1 },
|
|
261
|
+
React.createElement(Text, { color: "red" }, errorMessage))),
|
|
262
|
+
React.createElement(Box, null,
|
|
263
|
+
React.createElement(TextInput, { value: inputValue, onChange: setInputValue, onSubmit: handleAddPresetInput, placeholder: addStep === 'args' || addStep === 'fallbackArgs'
|
|
264
|
+
? 'e.g., --resume or leave empty'
|
|
265
|
+
: addStep === 'name'
|
|
266
|
+
? 'e.g., Development'
|
|
267
|
+
: '' })),
|
|
268
|
+
React.createElement(Box, { marginTop: 1 },
|
|
269
|
+
React.createElement(Text, { dimColor: true },
|
|
270
|
+
"Press Enter to continue,",
|
|
271
|
+
' ',
|
|
272
|
+
shortcutManager.getShortcutDisplay('cancel'),
|
|
273
|
+
" to cancel"))));
|
|
274
|
+
}
|
|
275
|
+
// Render delete confirmation
|
|
276
|
+
if (viewMode === 'delete-confirm') {
|
|
277
|
+
const preset = presets.find(p => p.id === selectedPresetId);
|
|
278
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
279
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
280
|
+
React.createElement(Text, { bold: true, color: "red" }, "Confirm Delete")),
|
|
281
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
282
|
+
React.createElement(Text, null,
|
|
283
|
+
"Delete preset \"",
|
|
284
|
+
preset?.name,
|
|
285
|
+
"\"?")),
|
|
286
|
+
React.createElement(Box, { flexDirection: "column" },
|
|
287
|
+
React.createElement(Box, null,
|
|
288
|
+
React.createElement(Text, { color: selectedIndex === 0 ? 'red' : undefined },
|
|
289
|
+
selectedIndex === 0 ? '> ' : ' ',
|
|
290
|
+
"Yes, delete")),
|
|
291
|
+
React.createElement(Box, null,
|
|
292
|
+
React.createElement(Text, { color: selectedIndex === 1 ? 'cyan' : undefined },
|
|
293
|
+
selectedIndex === 1 ? '> ' : ' ',
|
|
294
|
+
"Cancel"))),
|
|
295
|
+
React.createElement(Box, { marginTop: 1 },
|
|
296
|
+
React.createElement(Text, { dimColor: true }, "Press \u2191\u2193 to navigate, Enter to confirm"))));
|
|
297
|
+
}
|
|
298
|
+
// Render edit preset view
|
|
299
|
+
if (viewMode === 'edit') {
|
|
300
|
+
const preset = presets.find(p => p.id === selectedPresetId);
|
|
301
|
+
if (!preset)
|
|
302
|
+
return null;
|
|
303
|
+
const isDefault = preset.id === defaultPresetId;
|
|
304
|
+
const canDelete = presets.length > 1;
|
|
305
|
+
const menuItems = [
|
|
306
|
+
{ label: 'Name', value: preset.name },
|
|
307
|
+
{ label: 'Command', value: preset.command },
|
|
308
|
+
{ label: 'Arguments', value: preset.args?.join(' ') || '(none)' },
|
|
309
|
+
{
|
|
310
|
+
label: 'Fallback Arguments',
|
|
311
|
+
value: preset.fallbackArgs?.join(' ') || '(none)',
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
label: isDefault ? 'Already Default' : 'Set as Default',
|
|
315
|
+
value: '',
|
|
316
|
+
isButton: true,
|
|
317
|
+
disabled: isDefault,
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
label: canDelete
|
|
321
|
+
? 'Delete Preset'
|
|
322
|
+
: 'Delete Preset (cannot delete last preset)',
|
|
323
|
+
value: '',
|
|
324
|
+
isButton: true,
|
|
325
|
+
disabled: !canDelete,
|
|
326
|
+
},
|
|
327
|
+
{ label: 'Back to List', value: '', isButton: true, disabled: false },
|
|
328
|
+
];
|
|
329
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
330
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
331
|
+
React.createElement(Text, { bold: true, color: "green" },
|
|
332
|
+
"Edit Preset: ",
|
|
333
|
+
preset.name)),
|
|
334
|
+
isDefault && (React.createElement(Box, { marginBottom: 1 },
|
|
335
|
+
React.createElement(Text, { color: "yellow" }, "\u2B50 This is the default preset"))),
|
|
336
|
+
React.createElement(Box, { flexDirection: "column" }, menuItems.map((item, index) => {
|
|
337
|
+
const isSelected = selectedIndex === index;
|
|
338
|
+
const color = item.disabled
|
|
339
|
+
? 'gray'
|
|
340
|
+
: isSelected
|
|
341
|
+
? 'cyan'
|
|
342
|
+
: undefined;
|
|
343
|
+
return (React.createElement(Box, { key: index, marginTop: item.isButton && index > 0 ? 1 : 0 },
|
|
344
|
+
React.createElement(Text, { color: color },
|
|
345
|
+
isSelected ? '> ' : ' ',
|
|
346
|
+
item.isButton ? (React.createElement(Text, { bold: isSelected && !item.disabled, dimColor: item.disabled }, item.label)) : (`${item.label}: ${item.value}`))));
|
|
347
|
+
})),
|
|
348
|
+
React.createElement(Box, { marginTop: 1 },
|
|
349
|
+
React.createElement(Text, { dimColor: true },
|
|
350
|
+
"Press \u2191\u2193 to navigate, Enter to edit/select,",
|
|
351
|
+
' ',
|
|
352
|
+
shortcutManager.getShortcutDisplay('cancel'),
|
|
353
|
+
" to go back"))));
|
|
354
|
+
}
|
|
355
|
+
// Render preset list (default view)
|
|
356
|
+
const selectItems = [
|
|
357
|
+
...presets.map(preset => {
|
|
358
|
+
const isDefault = preset.id === defaultPresetId;
|
|
359
|
+
const args = preset.args?.join(' ') || '';
|
|
360
|
+
const fallback = preset.fallbackArgs?.join(' ') || '';
|
|
361
|
+
let label = preset.name;
|
|
362
|
+
if (isDefault)
|
|
363
|
+
label += ' (default)';
|
|
364
|
+
label += `\n Command: ${preset.command}`;
|
|
365
|
+
if (args)
|
|
366
|
+
label += `\n Args: ${args}`;
|
|
367
|
+
if (fallback)
|
|
368
|
+
label += `\n Fallback: ${fallback}`;
|
|
369
|
+
return {
|
|
370
|
+
label,
|
|
371
|
+
value: preset.id,
|
|
372
|
+
};
|
|
373
|
+
}),
|
|
374
|
+
{ label: '─────────────────────────', value: 'separator1' },
|
|
375
|
+
{
|
|
376
|
+
label: `Select preset before session start: ${selectPresetOnStart ? '✅ Enabled' : '❌ Disabled'}`,
|
|
377
|
+
value: 'toggle-select-on-start',
|
|
378
|
+
},
|
|
379
|
+
{ label: '─────────────────────────', value: 'separator2' },
|
|
380
|
+
{ label: 'Add New Preset', value: 'add' },
|
|
381
|
+
{ label: '← Cancel', value: 'exit' },
|
|
382
|
+
];
|
|
383
|
+
const handleSelectItem = (item) => {
|
|
384
|
+
if (item.value === 'add') {
|
|
385
|
+
// Add New Preset
|
|
386
|
+
setViewMode('add');
|
|
387
|
+
setNewPreset({});
|
|
388
|
+
setAddStep('name');
|
|
389
|
+
setInputValue('');
|
|
390
|
+
}
|
|
391
|
+
else if (item.value === 'exit') {
|
|
392
|
+
// Exit
|
|
393
|
+
onComplete();
|
|
394
|
+
}
|
|
395
|
+
else if (item.value === 'toggle-select-on-start') {
|
|
396
|
+
// Toggle select preset on start
|
|
397
|
+
const newValue = !selectPresetOnStart;
|
|
398
|
+
setSelectPresetOnStart(newValue);
|
|
399
|
+
configurationManager.setSelectPresetOnStart(newValue);
|
|
400
|
+
}
|
|
401
|
+
else if (item.value.startsWith('separator')) {
|
|
402
|
+
// Ignore separator selections
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
// Selected a preset
|
|
407
|
+
const preset = presets.find(p => p.id === item.value);
|
|
408
|
+
if (preset) {
|
|
409
|
+
setSelectedPresetId(preset.id);
|
|
410
|
+
setViewMode('edit');
|
|
411
|
+
setSelectedIndex(0);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
};
|
|
157
415
|
return (React.createElement(Box, { flexDirection: "column" },
|
|
158
416
|
React.createElement(Box, { marginBottom: 1 },
|
|
159
|
-
React.createElement(Text, { bold: true, color: "green" }, "
|
|
417
|
+
React.createElement(Text, { bold: true, color: "green" }, "Command Presets")),
|
|
160
418
|
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
|
-
})),
|
|
419
|
+
React.createElement(Text, { dimColor: true }, "Configure command presets for running code sessions")),
|
|
420
|
+
React.createElement(SelectInput, { items: selectItems, onSelect: handleSelectItem, initialIndex: selectedIndex }),
|
|
173
421
|
React.createElement(Box, { marginTop: 1 },
|
|
174
422
|
React.createElement(Text, { dimColor: true },
|
|
175
|
-
"Press \u2191\u2193 to navigate, Enter to
|
|
423
|
+
"Press \u2191\u2193 to navigate, Enter to select,",
|
|
176
424
|
' ',
|
|
177
425
|
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"))));
|
|
426
|
+
" to exit"))));
|
|
181
427
|
};
|
|
182
428
|
export default ConfigureCommand;
|