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.
@@ -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
- // Load current configuration once
8
- const currentConfig = configurationManager.getCommandConfig();
9
- const [originalConfig] = useState(currentConfig);
10
- const [config, setConfig] = useState(currentConfig);
11
- const [editMode, setEditMode] = useState('menu');
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 [hasChanges, setHasChanges] = useState(false);
15
- const menuItems = [
16
- {
17
- label: 'Command',
18
- value: config.command,
19
- key: 'command',
20
- isButton: false,
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) => {
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
- else if (key.downArrow) {
57
- setSelectedIndex(prev => (prev < menuItems.length - 1 ? prev + 1 : 0));
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 getInitialInputValue = (key) => {
61
- switch (key) {
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
- return config.command;
87
+ updatedPreset.command = value || 'claude';
88
+ break;
64
89
  case 'args':
65
- return config.args?.join(' ') || '';
90
+ updatedPreset.args = value.trim()
91
+ ? value.trim().split(/\s+/)
92
+ : undefined;
93
+ break;
66
94
  case 'fallbackArgs':
67
- return config.fallbackArgs?.join(' ') || '';
68
- default:
69
- return '';
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 handleMenuItemSelect = () => {
73
- const selectedItem = menuItems[selectedIndex];
74
- if (!selectedItem || selectedItem.disabled)
75
- return;
76
- switch (selectedItem.key) {
77
- case 'save':
78
- configurationManager.setCommandConfig(config);
79
- onComplete();
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 'exit':
82
- onComplete();
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
- default:
85
- if (!selectedItem.isButton) {
86
- setEditMode(selectedItem.key);
87
- setInputValue(getInitialInputValue(selectedItem.key));
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 (editMode === 'menu') {
95
- onComplete(); // Exit without saving
200
+ if (isSelectingStrategy) {
201
+ setIsSelectingStrategy(false);
96
202
  }
97
- else {
98
- setEditMode('menu');
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
- // Handle menu mode inputs
104
- if (editMode === 'menu') {
105
- handleMenuNavigation(key);
106
- if (key.return) {
107
- handleMenuItemSelect();
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
- const handleInputSubmit = (value) => {
112
- let updatedConfig = { ...config };
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') {
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" }, "Configure Command")),
289
+ React.createElement(Text, { bold: true, color: "green" }, "Edit Preset")),
144
290
  React.createElement(Box, { marginBottom: 1 },
145
- React.createElement(Text, null, titles[editMode])),
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: handleInputSubmit, placeholder: editMode === 'args' || editMode === 'fallbackArgs'
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" }, "Configure Command")),
502
+ React.createElement(Text, { bold: true, color: "green" }, "Command Presets")),
160
503
  React.createElement(Box, { marginBottom: 1 },
161
- React.createElement(Text, { dimColor: true }, "Configure the command and arguments for running code sessions")),
162
- hasChanges && (React.createElement(Box, { marginBottom: 1 },
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 edit,",
508
+ "Press \u2191\u2193 to navigate, Enter to select,",
176
509
  ' ',
177
510
  shortcutManager.getShortcutDisplay('cancel'),
178
- " to go back")),
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;
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ interface PresetSelectorProps {
3
+ onSelect: (presetId: string) => void;
4
+ onCancel: () => void;
5
+ }
6
+ declare const PresetSelector: React.FC<PresetSelectorProps>;
7
+ export default PresetSelector;