ccmanager 3.3.0 → 3.3.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/README.md CHANGED
@@ -112,23 +112,24 @@ Note: Shortcuts from `shortcuts.json` will be automatically migrated to `config.
112
112
 
113
113
  ## Supported AI Assistants
114
114
 
115
- CCManager now supports multiple AI coding assistants with tailored state detection:
116
-
117
- ### Claude Code (Default)
118
- - Command: `claude`
119
- - State detection: Built-in patterns for Claude's prompts and status messages
120
-
121
- ### Gemini CLI
122
- - Command: `gemini`
123
- - State detection: Custom patterns for Gemini's confirmation prompts
124
- - Installation: [google-gemini/gemini-cli](https://github.com/google-gemini/gemini-cli)
115
+ CCManager supports multiple AI coding assistants with tailored state detection for each:
116
+
117
+ | Assistant | Command | Installation |
118
+ |-----------|---------|--------------|
119
+ | Claude Code (Default) | `claude` | [code.claude.com](https://code.claude.com/docs/en/setup) |
120
+ | Gemini CLI | `gemini` | [github.com/google-gemini/gemini-cli](https://github.com/google-gemini/gemini-cli) |
121
+ | Codex CLI | `codex` | [github.com/openai/codex](https://github.com/openai/codex) |
122
+ | Cursor Agent | `cursor-agent` | [cursor.com/cli](https://cursor.com/docs/cli/overview) |
123
+ | Copilot CLI | `copilot` | [github.com/github/copilot-cli](https://github.com/github/copilot-cli) |
124
+ | Cline CLI | `cline` | [github.com/cline/cline](https://github.com/cline/cline) |
125
+ | OpenCode | `opencode` | [opencode.ai/docs](https://opencode.ai/docs) |
125
126
 
126
127
  Each assistant has its own state detection strategy to properly track:
127
128
  - **Idle**: Ready for new input
128
129
  - **Busy**: Processing a request
129
130
  - **Waiting**: Awaiting user confirmation
130
131
 
131
- See [Gemini Support Documentation](docs/gemini-support.md) for detailed configuration instructions.
132
+ See [Gemini Support Documentation](docs/gemini-support.md) for CCManager-specific configuration.
132
133
 
133
134
 
134
135
  ## Command Configuration
@@ -25,6 +25,16 @@ const createStrategyItems = () => {
25
25
  };
26
26
  // Type-safe strategy items that ensures all StateDetectionStrategy values are included
27
27
  const ALL_STRATEGY_ITEMS = createStrategyItems();
28
+ // Default command mapping for each strategy
29
+ const DEFAULT_COMMANDS = {
30
+ claude: 'claude',
31
+ gemini: 'gemini',
32
+ codex: 'codex',
33
+ cursor: 'cursor',
34
+ 'github-copilot': 'copilot',
35
+ cline: 'cline',
36
+ opencode: 'opencode',
37
+ };
28
38
  const formatDetectionStrategy = (strategy) => {
29
39
  const value = strategy || 'claude';
30
40
  switch (value) {
@@ -57,7 +67,7 @@ const ConfigureCommand = ({ onComplete }) => {
57
67
  const [isSelectingStrategy, setIsSelectingStrategy] = useState(false);
58
68
  const [isSelectingStrategyInAdd, setIsSelectingStrategyInAdd] = useState(false);
59
69
  const [newPreset, setNewPreset] = useState({});
60
- const [addStep, setAddStep] = useState('name');
70
+ const [addStep, setAddStep] = useState('detectionStrategy');
61
71
  const [errorMessage, setErrorMessage] = useState(null);
62
72
  // Remove handleListNavigation as SelectInput handles navigation internally
63
73
  // Remove handleListSelection as we now use handleSelectItem
@@ -142,19 +152,8 @@ const ConfigureCommand = ({ onComplete }) => {
142
152
  };
143
153
  const handleAddPresetInput = (value) => {
144
154
  switch (addStep) {
145
- case 'name':
146
- // Prevent using "Default" as a name to avoid confusion
147
- if (value.trim().toLowerCase() === 'default') {
148
- setErrorMessage('Cannot use "Default" as a preset name. Please choose a different name.');
149
- return;
150
- }
151
- setNewPreset({ ...newPreset, name: value });
152
- setAddStep('command');
153
- setInputValue('');
154
- setErrorMessage(null);
155
- break;
156
155
  case 'command':
157
- setNewPreset({ ...newPreset, command: value || 'claude' });
156
+ setNewPreset({ ...newPreset, command: value });
158
157
  setAddStep('args');
159
158
  setInputValue('');
160
159
  break;
@@ -170,8 +169,38 @@ const ConfigureCommand = ({ onComplete }) => {
170
169
  ? value.trim().split(/\s+/)
171
170
  : undefined;
172
171
  setNewPreset({ ...newPreset, fallbackArgs });
172
+ setAddStep('name');
173
+ setInputValue('');
174
+ break;
175
+ }
176
+ case 'name': {
177
+ if (!value.trim()) {
178
+ setErrorMessage('Preset name cannot be empty. Please enter a name.');
179
+ return;
180
+ }
181
+ if (value.trim().toLowerCase() === 'default') {
182
+ setErrorMessage('Cannot use "Default" as a preset name. Please choose a different name.');
183
+ return;
184
+ }
185
+ const id = Date.now().toString();
186
+ const completePreset = {
187
+ id,
188
+ name: value,
189
+ command: newPreset.command || 'claude',
190
+ args: newPreset.args,
191
+ fallbackArgs: newPreset.fallbackArgs,
192
+ detectionStrategy: newPreset.detectionStrategy || 'claude',
193
+ };
194
+ const updatedPresets = [...presets, completePreset];
195
+ setPresets(updatedPresets);
196
+ configurationManager.addPreset(completePreset);
197
+ setViewMode('list');
198
+ setSelectedIndex(updatedPresets.length - 1);
199
+ setNewPreset({});
173
200
  setAddStep('detectionStrategy');
174
- setIsSelectingStrategyInAdd(true);
201
+ setInputValue('');
202
+ setIsSelectingStrategyInAdd(false);
203
+ setErrorMessage(null);
175
204
  break;
176
205
  }
177
206
  }
@@ -188,25 +217,16 @@ const ConfigureCommand = ({ onComplete }) => {
188
217
  setIsSelectingStrategy(false);
189
218
  };
190
219
  const handleAddStrategySelect = (item) => {
191
- const id = Date.now().toString();
192
- const completePreset = {
193
- id,
194
- name: newPreset.name || 'New Preset',
195
- command: newPreset.command || 'claude',
196
- args: newPreset.args,
197
- fallbackArgs: newPreset.fallbackArgs,
198
- detectionStrategy: item.value,
199
- };
200
- const updatedPresets = [...presets, completePreset];
201
- setPresets(updatedPresets);
202
- configurationManager.addPreset(completePreset);
203
- setViewMode('list');
204
- setSelectedIndex(updatedPresets.length - 1);
205
- setNewPreset({});
206
- setAddStep('name');
207
- setInputValue('');
220
+ const strategy = item.value;
221
+ const defaultCommand = DEFAULT_COMMANDS[strategy];
222
+ setNewPreset({
223
+ ...newPreset,
224
+ detectionStrategy: strategy,
225
+ command: defaultCommand,
226
+ });
227
+ setAddStep('command');
228
+ setInputValue(defaultCommand);
208
229
  setIsSelectingStrategyInAdd(false);
209
- setErrorMessage(null);
210
230
  };
211
231
  const handleDeleteConfirm = () => {
212
232
  if (selectedIndex === 0) {
@@ -239,7 +259,7 @@ const ConfigureCommand = ({ onComplete }) => {
239
259
  else if (isSelectingStrategyInAdd) {
240
260
  setIsSelectingStrategyInAdd(false);
241
261
  setViewMode('list');
242
- setAddStep('name');
262
+ setAddStep('detectionStrategy');
243
263
  setNewPreset({});
244
264
  }
245
265
  else if (editField) {
@@ -338,6 +358,8 @@ const ConfigureCommand = ({ onComplete }) => {
338
358
  React.createElement(Text, { bold: true, color: "green" }, "Add New Preset - Detection Strategy")),
339
359
  React.createElement(Box, { marginBottom: 1 },
340
360
  React.createElement(Text, null, "Choose the state detection strategy for this preset:")),
361
+ React.createElement(Box, { marginBottom: 1 },
362
+ React.createElement(Text, { dimColor: true }, "The command will be auto-set based on the strategy (can be changed later)")),
341
363
  React.createElement(SelectInput, { items: strategyItems, onSelect: handleAddStrategySelect, initialIndex: 0 }),
342
364
  React.createElement(Box, { marginTop: 1 },
343
365
  React.createElement(Text, { dimColor: true },
@@ -347,23 +369,26 @@ const ConfigureCommand = ({ onComplete }) => {
347
369
  " to cancel"))));
348
370
  }
349
371
  const titles = {
350
- name: 'Enter preset name:',
351
- command: 'Enter command (e.g., claude):',
372
+ detectionStrategy: 'Select detection strategy:',
373
+ command: 'Enter command (default set by strategy, can be modified):',
352
374
  args: 'Enter command arguments (space-separated):',
353
375
  fallbackArgs: 'Enter fallback arguments (space-separated):',
376
+ name: 'Enter preset name (freely customizable):',
354
377
  };
355
378
  return (React.createElement(Box, { flexDirection: "column" },
356
379
  React.createElement(Box, { marginBottom: 1 },
357
380
  React.createElement(Text, { bold: true, color: "green" }, "Add New Preset")),
358
381
  React.createElement(Box, { marginBottom: 1 },
359
382
  React.createElement(Text, null, titles[addStep])),
383
+ addStep === 'command' && (React.createElement(Box, { marginBottom: 1 },
384
+ React.createElement(Text, { dimColor: true }, "Auto-filled from your strategy selection. You can change this if needed."))),
360
385
  errorMessage && (React.createElement(Box, { marginBottom: 1 },
361
386
  React.createElement(Text, { color: "red" }, errorMessage))),
362
387
  React.createElement(Box, null,
363
- React.createElement(TextInputWrapper, { value: inputValue, onChange: setInputValue, onSubmit: handleAddPresetInput, placeholder: addStep === 'args' || addStep === 'fallbackArgs'
364
- ? 'e.g., --resume or leave empty'
365
- : addStep === 'name'
366
- ? 'e.g., Development'
388
+ React.createElement(TextInputWrapper, { value: inputValue, onChange: setInputValue, onSubmit: handleAddPresetInput, placeholder: addStep === 'name'
389
+ ? 'e.g., Development'
390
+ : addStep === 'args' || addStep === 'fallbackArgs'
391
+ ? 'e.g., --resume or leave empty'
367
392
  : '' })),
368
393
  React.createElement(Box, { marginTop: 1 },
369
394
  React.createElement(Text, { dimColor: true },
@@ -494,7 +519,8 @@ const ConfigureCommand = ({ onComplete }) => {
494
519
  // Add New Preset
495
520
  setViewMode('add');
496
521
  setNewPreset({});
497
- setAddStep('name');
522
+ setAddStep('detectionStrategy');
523
+ setIsSelectingStrategyInAdd(true);
498
524
  setInputValue('');
499
525
  }
500
526
  else if (item.value === 'exit') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccmanager",
3
- "version": "3.3.0",
3
+ "version": "3.3.1",
4
4
  "description": "TUI application for managing multiple Claude Code sessions across Git worktrees",
5
5
  "license": "MIT",
6
6
  "author": "Kodai Kabasawa",
@@ -41,11 +41,11 @@
41
41
  "bin"
42
42
  ],
43
43
  "optionalDependencies": {
44
- "@kodaikabasawa/ccmanager-darwin-arm64": "3.3.0",
45
- "@kodaikabasawa/ccmanager-darwin-x64": "3.3.0",
46
- "@kodaikabasawa/ccmanager-linux-arm64": "3.3.0",
47
- "@kodaikabasawa/ccmanager-linux-x64": "3.3.0",
48
- "@kodaikabasawa/ccmanager-win32-x64": "3.3.0"
44
+ "@kodaikabasawa/ccmanager-darwin-arm64": "3.3.1",
45
+ "@kodaikabasawa/ccmanager-darwin-x64": "3.3.1",
46
+ "@kodaikabasawa/ccmanager-linux-arm64": "3.3.1",
47
+ "@kodaikabasawa/ccmanager-linux-x64": "3.3.1",
48
+ "@kodaikabasawa/ccmanager-win32-x64": "3.3.1"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@eslint/js": "^9.28.0",
@@ -68,14 +68,14 @@
68
68
  },
69
69
  "prettier": "@vdemedes/prettier-config",
70
70
  "dependencies": {
71
- "@xterm/headless": "^5.5.0",
71
+ "@xterm/headless": "^6.0.0",
72
72
  "effect": "^3.18.2",
73
73
  "ink": "5.2.1",
74
74
  "ink-select-input": "^6.0.0",
75
75
  "ink-text-input": "^6.0.0",
76
76
  "meow": "^11.0.0",
77
77
  "react": "18.3.1",
78
- "react-devtools-core": "^4.19.1",
78
+ "react-devtools-core": "^7.0.1",
79
79
  "react-dom": "18.3.1",
80
80
  "strip-ansi": "^7.1.0"
81
81
  }