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
package/README.md
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
# CCManager -
|
|
1
|
+
# CCManager - AI Code Assistant Session Manager
|
|
2
2
|
|
|
3
|
-
CCManager is a TUI application for managing multiple Claude Code
|
|
3
|
+
CCManager is a TUI application for managing multiple AI coding assistant sessions (Claude Code, Gemini CLI) across Git worktrees.
|
|
4
4
|
|
|
5
5
|
https://github.com/user-attachments/assets/a6d80e73-dc06-4ef8-849d-e3857f6c7024
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
- Run multiple
|
|
9
|
+
- Run multiple AI assistant sessions in parallel across different Git worktrees
|
|
10
|
+
- Support for multiple AI coding assistants (Claude Code, Gemini CLI)
|
|
10
11
|
- Switch between sessions seamlessly
|
|
11
12
|
- Visual status indicators for session states (busy, waiting, idle)
|
|
12
13
|
- Create, merge, and delete worktrees from within the app
|
|
13
14
|
- Configurable keyboard shortcuts
|
|
14
|
-
- Command
|
|
15
|
+
- Command presets with automatic fallback support
|
|
16
|
+
- Configurable state detection strategies for different CLI tools
|
|
15
17
|
- Status change hooks for automation and notifications
|
|
16
18
|
|
|
17
19
|
## Why CCManager over Claude Squad?
|
|
@@ -108,6 +110,26 @@ Note: Shortcuts from `shortcuts.json` will be automatically migrated to `config.
|
|
|
108
110
|
- Ctrl+D
|
|
109
111
|
- Ctrl+[ (equivalent to Escape)
|
|
110
112
|
|
|
113
|
+
## Supported AI Assistants
|
|
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)
|
|
125
|
+
|
|
126
|
+
Each assistant has its own state detection strategy to properly track:
|
|
127
|
+
- **Idle**: Ready for new input
|
|
128
|
+
- **Busy**: Processing a request
|
|
129
|
+
- **Waiting**: Awaiting user confirmation
|
|
130
|
+
|
|
131
|
+
See [Gemini Support Documentation](docs/gemini-support.md) for detailed configuration instructions.
|
|
132
|
+
|
|
111
133
|
|
|
112
134
|
## Command Configuration
|
|
113
135
|
|
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;
|