ccb-multi 0.1.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/CHANGELOG.md +31 -0
- package/README.md +232 -0
- package/bin/ccb-multi-clean.js +2 -0
- package/bin/ccb-multi-history.js +2 -0
- package/bin/ccb-multi-status.js +2 -0
- package/bin/ccb-multi.js +2 -0
- package/lib/cli/ccb-multi-clean.d.ts +3 -0
- package/lib/cli/ccb-multi-clean.d.ts.map +1 -0
- package/lib/cli/ccb-multi-clean.js +104 -0
- package/lib/cli/ccb-multi-clean.js.map +1 -0
- package/lib/cli/ccb-multi-history.d.ts +3 -0
- package/lib/cli/ccb-multi-history.d.ts.map +1 -0
- package/lib/cli/ccb-multi-history.js +99 -0
- package/lib/cli/ccb-multi-history.js.map +1 -0
- package/lib/cli/ccb-multi-status.d.ts +3 -0
- package/lib/cli/ccb-multi-status.d.ts.map +1 -0
- package/lib/cli/ccb-multi-status.js +56 -0
- package/lib/cli/ccb-multi-status.js.map +1 -0
- package/lib/cli/ccb-multi.d.ts +3 -0
- package/lib/cli/ccb-multi.d.ts.map +1 -0
- package/lib/cli/ccb-multi.js +45 -0
- package/lib/cli/ccb-multi.js.map +1 -0
- package/package.json +45 -0
- package/src/cli/ccb-multi-clean.ts +77 -0
- package/src/cli/ccb-multi-history.ts +71 -0
- package/src/cli/ccb-multi-status.ts +59 -0
- package/src/cli/ccb-multi.ts +47 -0
- package/tsconfig.json +19 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.1.0] - 2026-02-13
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Initial release of ccb-multi toolkit
|
|
10
|
+
- Multi-instance support for CCB (Claude Code Bridge)
|
|
11
|
+
- Professional ASCII art branding (CCB-MULTI logo)
|
|
12
|
+
- Four CLI commands:
|
|
13
|
+
- `ccb-multi` - Start CCB instance with specified providers
|
|
14
|
+
- `ccb-multi-status` - View status of all instances
|
|
15
|
+
- `ccb-multi-history` - View shared session history
|
|
16
|
+
- `ccb-multi-clean` - Clean up instance directories
|
|
17
|
+
- Shared session history across all instances via symlinks
|
|
18
|
+
- Isolated workspace for each instance
|
|
19
|
+
- Cross-platform compatibility (Windows, macOS, Linux)
|
|
20
|
+
- Comprehensive documentation with:
|
|
21
|
+
- CCB background and single-instance problem explanation
|
|
22
|
+
- Design philosophy and architecture diagram
|
|
23
|
+
- Prerequisites and installation guide
|
|
24
|
+
- Usage examples and comparison with git worktree
|
|
25
|
+
|
|
26
|
+
### Features
|
|
27
|
+
|
|
28
|
+
- Better solution than git worktree for parallel AI coding sessions
|
|
29
|
+
- Automatic instance isolation and cleanup
|
|
30
|
+
- Unified status tracking across all instances
|
|
31
|
+
- Shared resources (history, config) via symlinks
|
package/README.md
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# CCB-Multi - Multi-Instance Manager for Claude Code Bridge
|
|
2
|
+
|
|
3
|
+
Multi-instance manager for CCB (Claude Code Bridge) - Run multiple AI coding sessions in parallel.
|
|
4
|
+
|
|
5
|
+
## Background
|
|
6
|
+
|
|
7
|
+
### What is CCB?
|
|
8
|
+
|
|
9
|
+
[CCB (Claude Code Bridge)](https://github.com/bfly123/claude_code_bridge) is a powerful tool for real-time multi-AI collaboration, supporting Claude, Codex, and Gemini with persistent context and minimal token overhead.
|
|
10
|
+
|
|
11
|
+
**CCB's Strengths:**
|
|
12
|
+
- 🤖 Multi-AI provider support (Claude, Codex, Gemini)
|
|
13
|
+
- 🔄 Powerful task scheduling and orchestration
|
|
14
|
+
- 💾 Persistent context across sessions
|
|
15
|
+
- ⚡ Efficient token usage
|
|
16
|
+
|
|
17
|
+
### The Single-Instance Problem
|
|
18
|
+
|
|
19
|
+
**CCB runs as a single instance**, which creates significant limitations during development:
|
|
20
|
+
|
|
21
|
+
**Common Development Scenarios:**
|
|
22
|
+
|
|
23
|
+
1. **Parallel Feature Development**
|
|
24
|
+
- You're implementing Feature A with Claude
|
|
25
|
+
- Suddenly need to fix a critical bug in Feature B
|
|
26
|
+
- Must stop Feature A session, lose context, switch to Feature B
|
|
27
|
+
- Can't leverage Codex for Feature A while Claude handles Feature B
|
|
28
|
+
|
|
29
|
+
2. **Multi-Provider Workflows**
|
|
30
|
+
- Want Claude to review architecture
|
|
31
|
+
- Want Codex to implement algorithms
|
|
32
|
+
- Want Gemini to write documentation
|
|
33
|
+
- Can only run one at a time, losing the parallel efficiency
|
|
34
|
+
|
|
35
|
+
3. **Context Switching Overhead**
|
|
36
|
+
- Each time you switch tasks, you lose the current session context
|
|
37
|
+
- Need to rebuild context when returning to previous task
|
|
38
|
+
- Wastes time and tokens re-explaining the same context
|
|
39
|
+
|
|
40
|
+
**The Pain Point:** CCB's powerful capabilities are bottlenecked by single-instance limitation. You can't fully utilize multiple AI providers in parallel for different tasks.
|
|
41
|
+
|
|
42
|
+
## Our Solution: ccb-multi
|
|
43
|
+
|
|
44
|
+
ccb-multi solves the single-instance problem by enabling **multiple isolated CCB instances** while maintaining **shared session history**.
|
|
45
|
+
|
|
46
|
+
### Design Philosophy
|
|
47
|
+
|
|
48
|
+
**Instance Isolation + History Sharing**
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
52
|
+
│ Your Project Root │
|
|
53
|
+
├─────────────────────────────────────────────────────────────┤
|
|
54
|
+
│ │
|
|
55
|
+
│ .ccb/ │
|
|
56
|
+
│ ├── history/ ← Shared across all instances │
|
|
57
|
+
│ └── ccb.config ← Shared configuration │
|
|
58
|
+
│ │
|
|
59
|
+
│ .ccb-instances/ │
|
|
60
|
+
│ ├── instance-1/ ← Isolated workspace (Feature A) │
|
|
61
|
+
│ │ ├── .ccb/ │
|
|
62
|
+
│ │ │ └── history → ../../.ccb/history/ (symlink) │
|
|
63
|
+
│ │ └── [working files] │
|
|
64
|
+
│ │ │
|
|
65
|
+
│ └── instance-2/ ← Isolated workspace (Feature B) │
|
|
66
|
+
│ ├── .ccb/ │
|
|
67
|
+
│ │ └── history → ../../.ccb/history/ (symlink) │
|
|
68
|
+
│ └── [working files] │
|
|
69
|
+
│ │
|
|
70
|
+
└─────────────────────────────────────────────────────────────┘
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Key Design Decisions:**
|
|
74
|
+
|
|
75
|
+
1. **Isolated Workspaces**: Each instance has its own directory to avoid file conflicts
|
|
76
|
+
2. **Shared History**: All instances share `.ccb/history/` via symlinks for context continuity
|
|
77
|
+
3. **Shared Config**: Common configuration across all instances
|
|
78
|
+
4. **File Sync**: Changes sync back to project root automatically
|
|
79
|
+
|
|
80
|
+
### Why Not Git Worktree?
|
|
81
|
+
|
|
82
|
+
You might think: "Can't I just use `git worktree` for multiple working directories?"
|
|
83
|
+
|
|
84
|
+
**Git worktree** is a valid approach, but has limitations:
|
|
85
|
+
|
|
86
|
+
| Aspect | git worktree | ccb-multi |
|
|
87
|
+
|--------|-------------|-----------|
|
|
88
|
+
| **Session History** | ❌ Separate per worktree | ✅ Shared across instances |
|
|
89
|
+
| **Setup** | ❌ Manual worktree management | ✅ One command to start |
|
|
90
|
+
| **Cleanup** | ❌ Manual removal needed | ✅ Automatic cleanup |
|
|
91
|
+
| **Status Tracking** | ❌ No unified view | ✅ See all instances at once |
|
|
92
|
+
|
|
93
|
+
**ccb-multi** is purpose-built for CCB's multi-instance needs, with automatic history sharing and instance management.
|
|
94
|
+
|
|
95
|
+
## Features
|
|
96
|
+
|
|
97
|
+
✅ **Multi-instance Support**: Run multiple CCB instances simultaneously
|
|
98
|
+
✅ **Shared History**: All instances share conversation history and memory
|
|
99
|
+
✅ **Cross-platform**: Works on Windows, macOS, and Linux
|
|
100
|
+
✅ **Easy to Use**: Simple CLI commands
|
|
101
|
+
✅ **Monorepo Friendly**: Works with any project structure
|
|
102
|
+
|
|
103
|
+
## Prerequisites
|
|
104
|
+
|
|
105
|
+
Before installing ccb-multi, you need to have the following installed:
|
|
106
|
+
|
|
107
|
+
### 1. CCB (Claude Code Bridge)
|
|
108
|
+
|
|
109
|
+
CCB must be installed and configured on your system.
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Install CCB (follow CCB's official installation guide)
|
|
113
|
+
# https://github.com/bfly123/claude_code_bridge
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 2. tmux
|
|
117
|
+
|
|
118
|
+
ccb-multi requires tmux to manage multiple terminal sessions.
|
|
119
|
+
|
|
120
|
+
**macOS:**
|
|
121
|
+
```bash
|
|
122
|
+
brew install tmux
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Linux (Ubuntu/Debian):**
|
|
126
|
+
```bash
|
|
127
|
+
sudo apt-get install tmux
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Linux (CentOS/RHEL):**
|
|
131
|
+
```bash
|
|
132
|
+
sudo yum install tmux
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Windows:**
|
|
136
|
+
```bash
|
|
137
|
+
# Use WSL (Windows Subsystem for Linux) and install tmux in WSL
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 3. Start tmux
|
|
141
|
+
|
|
142
|
+
**IMPORTANT**: You must run ccb-multi inside a tmux session.
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# Start tmux
|
|
146
|
+
tmux
|
|
147
|
+
|
|
148
|
+
# Or attach to existing session
|
|
149
|
+
tmux attach
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Installation
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
npm install -g ccb-multi
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Usage
|
|
159
|
+
|
|
160
|
+
### Start an instance
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
# Start instance 1 with specific providers
|
|
164
|
+
ccb-multi 1 codex gemini claude
|
|
165
|
+
|
|
166
|
+
# Start instance 2
|
|
167
|
+
ccb-multi 2 codex gemini claude
|
|
168
|
+
|
|
169
|
+
# Start instance without specifying providers (uses config)
|
|
170
|
+
ccb-multi 1
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Check status
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
ccb-multi-status
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### View history
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
ccb-multi-history
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Clean up instances
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
ccb-multi-clean
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## How it Works
|
|
192
|
+
|
|
193
|
+
1. **Instance Isolation**: Each instance runs in its own directory (`.ccb-instances/instance-N`)
|
|
194
|
+
2. **Shared Resources**: All instances share:
|
|
195
|
+
- `.ccb/history/` - Conversation history
|
|
196
|
+
- `.ccb/ccb.config` - Configuration
|
|
197
|
+
3. **File Sync**: All file changes are synced to the project root via symlinks
|
|
198
|
+
|
|
199
|
+
## Project Structure
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
your-project/
|
|
203
|
+
.ccb/
|
|
204
|
+
history/ # Shared history (all instances)
|
|
205
|
+
ccb.config # Shared config
|
|
206
|
+
.ccb-instances/
|
|
207
|
+
instance-1/ # Instance 1
|
|
208
|
+
.ccb/
|
|
209
|
+
history -> ../../.ccb/history/
|
|
210
|
+
instance-2/ # Instance 2
|
|
211
|
+
.ccb/
|
|
212
|
+
history -> ../../.ccb/history/
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Requirements
|
|
216
|
+
|
|
217
|
+
- Node.js >= 14.0.0
|
|
218
|
+
- CCB (Claude Code Bridge) installed
|
|
219
|
+
- tmux installed and running
|
|
220
|
+
|
|
221
|
+
## License
|
|
222
|
+
|
|
223
|
+
MIT
|
|
224
|
+
|
|
225
|
+
## Author
|
|
226
|
+
|
|
227
|
+
dalio willd
|
|
228
|
+
|
|
229
|
+
## Repository
|
|
230
|
+
|
|
231
|
+
https://github.com/waoooo/ccb-multi
|
|
232
|
+
|
package/bin/ccb-multi.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ccb-multi-clean.d.ts","sourceRoot":"","sources":["../../src/cli/ccb-multi-clean.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
37
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
38
|
+
};
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
43
|
+
const utils_1 = require("../lib/utils");
|
|
44
|
+
const commander_1 = require("commander");
|
|
45
|
+
const program = new commander_1.Command();
|
|
46
|
+
program
|
|
47
|
+
.name('ccb-multi-clean')
|
|
48
|
+
.description('Clean up CCB multi-instance directories')
|
|
49
|
+
.option('-f, --force', 'Force clean without confirmation')
|
|
50
|
+
.action(async (options) => {
|
|
51
|
+
try {
|
|
52
|
+
const projectInfo = (0, utils_1.getProjectInfo)();
|
|
53
|
+
const instancesDir = (0, utils_1.getInstancesDir)(projectInfo.root);
|
|
54
|
+
console.log('');
|
|
55
|
+
console.log(chalk_1.default.cyan(' ██████╗ ██████╗██████╗ ███╗ ███╗██╗ ██╗██╗ ████████╗██╗'));
|
|
56
|
+
console.log(chalk_1.default.cyan(' ██╔════╝██╔════╝██╔══██╗ ████╗ ████║██║ ██║██║ ╚══██╔══╝██║'));
|
|
57
|
+
console.log(chalk_1.default.cyan(' ██║ ██║ ██████╔╝█████╗██╔████╔██║██║ ██║██║ ██║ ██║'));
|
|
58
|
+
console.log(chalk_1.default.cyan(' ██║ ██║ ██╔══██╗╚════╝██║╚██╔╝██║██║ ██║██║ ██║ ██║'));
|
|
59
|
+
console.log(chalk_1.default.cyan(' ╚██████╗╚██████╗██████╔╝ ██║ ╚═╝ ██║╚██████╔╝███████╗██║ ██║'));
|
|
60
|
+
console.log(chalk_1.default.cyan(' ╚═════╝ ╚═════╝╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝'));
|
|
61
|
+
console.log('');
|
|
62
|
+
console.log(' Multi-Instance Cleanup');
|
|
63
|
+
console.log('');
|
|
64
|
+
if (!fs.existsSync(instancesDir)) {
|
|
65
|
+
console.log(chalk_1.default.dim(' No instances directory found'));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const instances = fs.readdirSync(instancesDir)
|
|
69
|
+
.filter(name => name.startsWith('instance-'));
|
|
70
|
+
if (instances.length === 0) {
|
|
71
|
+
console.log(chalk_1.default.dim(' No instances to clean'));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
console.log(chalk_1.default.dim(` Found ${instances.length} instance(s) to remove:`));
|
|
75
|
+
console.log('');
|
|
76
|
+
instances.forEach(name => {
|
|
77
|
+
console.log(chalk_1.default.dim(` ${name}`));
|
|
78
|
+
});
|
|
79
|
+
console.log('');
|
|
80
|
+
if (!options.force) {
|
|
81
|
+
console.log(chalk_1.default.yellow(' Warning: This will delete all instance directories'));
|
|
82
|
+
console.log(chalk_1.default.dim(' (shared history will be preserved)'));
|
|
83
|
+
console.log('');
|
|
84
|
+
console.log(chalk_1.default.dim(' Run with --force to confirm'));
|
|
85
|
+
console.log('');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
// Clean up instances
|
|
89
|
+
for (const instance of instances) {
|
|
90
|
+
const instancePath = path.join(instancesDir, instance);
|
|
91
|
+
fs.rmSync(instancePath, { recursive: true, force: true });
|
|
92
|
+
console.log(chalk_1.default.green(` ✓ Removed ${instance}`));
|
|
93
|
+
}
|
|
94
|
+
console.log('');
|
|
95
|
+
console.log(chalk_1.default.green(' Cleanup complete'));
|
|
96
|
+
console.log('');
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
console.error(chalk_1.default.red(' ✗ Error:'), error instanceof Error ? error.message : error);
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
program.parse();
|
|
104
|
+
//# sourceMappingURL=ccb-multi-clean.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ccb-multi-clean.js","sourceRoot":"","sources":["../../src/cli/ccb-multi-clean.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ccb-multi-history.d.ts","sourceRoot":"","sources":["../../src/cli/ccb-multi-history.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
37
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
38
|
+
};
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
43
|
+
const utils_1 = require("../lib/utils");
|
|
44
|
+
async function main() {
|
|
45
|
+
try {
|
|
46
|
+
const projectInfo = (0, utils_1.getProjectInfo)();
|
|
47
|
+
const historyDir = path.join(projectInfo.root, '.ccb', 'history');
|
|
48
|
+
console.log('');
|
|
49
|
+
console.log(chalk_1.default.cyan(' ██████╗ ██████╗██████╗ ███╗ ███╗██╗ ██╗██╗ ████████╗██╗'));
|
|
50
|
+
console.log(chalk_1.default.cyan(' ██╔════╝██╔════╝██╔══██╗ ████╗ ████║██║ ██║██║ ╚══██╔══╝██║'));
|
|
51
|
+
console.log(chalk_1.default.cyan(' ██║ ██║ ██████╔╝█████╗██╔████╔██║██║ ██║██║ ██║ ██║'));
|
|
52
|
+
console.log(chalk_1.default.cyan(' ██║ ██║ ██╔══██╗╚════╝██║╚██╔╝██║██║ ██║██║ ██║ ██║'));
|
|
53
|
+
console.log(chalk_1.default.cyan(' ╚██████╗╚██████╗██████╔╝ ██║ ╚═╝ ██║╚██████╔╝███████╗██║ ██║'));
|
|
54
|
+
console.log(chalk_1.default.cyan(' ╚═════╝ ╚═════╝╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝'));
|
|
55
|
+
console.log('');
|
|
56
|
+
console.log(' Session History');
|
|
57
|
+
console.log('');
|
|
58
|
+
if (!fs.existsSync(historyDir)) {
|
|
59
|
+
console.log(chalk_1.default.dim(' No history directory found'));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
console.log(chalk_1.default.dim(' RECENT SESSIONS (shared across all instances)'));
|
|
63
|
+
console.log('');
|
|
64
|
+
// List recent history files
|
|
65
|
+
const files = fs.readdirSync(historyDir)
|
|
66
|
+
.filter(name => name.endsWith('.md'))
|
|
67
|
+
.map(name => ({
|
|
68
|
+
name,
|
|
69
|
+
path: path.join(historyDir, name),
|
|
70
|
+
stat: fs.statSync(path.join(historyDir, name))
|
|
71
|
+
}))
|
|
72
|
+
.sort((a, b) => b.stat.mtimeMs - a.stat.mtimeMs)
|
|
73
|
+
.slice(0, 10);
|
|
74
|
+
if (files.length === 0) {
|
|
75
|
+
console.log(chalk_1.default.dim(' No session history found'));
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
for (const file of files) {
|
|
79
|
+
const provider = file.name.split('-')[0];
|
|
80
|
+
const size = (file.stat.size / 1024).toFixed(1) + 'K';
|
|
81
|
+
const time = file.stat.mtime.toLocaleString('en-US', {
|
|
82
|
+
month: 'short',
|
|
83
|
+
day: 'numeric',
|
|
84
|
+
hour: '2-digit',
|
|
85
|
+
minute: '2-digit'
|
|
86
|
+
});
|
|
87
|
+
console.log(` ${chalk_1.default.cyan(provider.padEnd(8))} ${chalk_1.default.dim(size.padEnd(8))} ${chalk_1.default.dim(time)}`);
|
|
88
|
+
}
|
|
89
|
+
console.log('');
|
|
90
|
+
console.log(chalk_1.default.dim(` History location: ${historyDir}`));
|
|
91
|
+
console.log('');
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
console.error(chalk_1.default.red(' ✗ Error:'), error instanceof Error ? error.message : error);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
main();
|
|
99
|
+
//# sourceMappingURL=ccb-multi-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ccb-multi-history.js","sourceRoot":"","sources":["../../src/cli/ccb-multi-history.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ccb-multi-status.d.ts","sourceRoot":"","sources":["../../src/cli/ccb-multi-status.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const utils_1 = require("../lib/utils");
|
|
9
|
+
async function main() {
|
|
10
|
+
try {
|
|
11
|
+
const projectInfo = (0, utils_1.getProjectInfo)();
|
|
12
|
+
const instances = (0, utils_1.listInstances)(projectInfo.root);
|
|
13
|
+
console.log('');
|
|
14
|
+
console.log(chalk_1.default.cyan(' ██████╗ ██████╗██████╗ ███╗ ███╗██╗ ██╗██╗ ████████╗██╗'));
|
|
15
|
+
console.log(chalk_1.default.cyan(' ██╔════╝██╔════╝██╔══██╗ ████╗ ████║██║ ██║██║ ╚══██╔══╝██║'));
|
|
16
|
+
console.log(chalk_1.default.cyan(' ██║ ██║ ██████╔╝█████╗██╔████╔██║██║ ██║██║ ██║ ██║'));
|
|
17
|
+
console.log(chalk_1.default.cyan(' ██║ ██║ ██╔══██╗╚════╝██║╚██╔╝██║██║ ██║██║ ██║ ██║'));
|
|
18
|
+
console.log(chalk_1.default.cyan(' ╚██████╗╚██████╗██████╔╝ ██║ ╚═╝ ██║╚██████╔╝███████╗██║ ██║'));
|
|
19
|
+
console.log(chalk_1.default.cyan(' ╚═════╝ ╚═════╝╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝'));
|
|
20
|
+
console.log('');
|
|
21
|
+
console.log(' Multi-Instance Status');
|
|
22
|
+
console.log('');
|
|
23
|
+
if (instances.length === 0) {
|
|
24
|
+
console.log(chalk_1.default.dim(' No instances found'));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
let runningCount = 0;
|
|
28
|
+
let stoppedCount = 0;
|
|
29
|
+
console.log(chalk_1.default.dim(' INSTANCES'));
|
|
30
|
+
console.log('');
|
|
31
|
+
for (const instanceId of instances) {
|
|
32
|
+
const running = (0, utils_1.isInstanceRunning)(projectInfo.root, instanceId);
|
|
33
|
+
if (running) {
|
|
34
|
+
console.log(` ${chalk_1.default.green('●')} Instance ${instanceId} ${chalk_1.default.dim('running')}`);
|
|
35
|
+
runningCount++;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
console.log(` ${chalk_1.default.dim('○')} Instance ${instanceId} ${chalk_1.default.dim('stopped')}`);
|
|
39
|
+
stoppedCount++;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
console.log('');
|
|
43
|
+
console.log(chalk_1.default.dim(' SUMMARY'));
|
|
44
|
+
console.log('');
|
|
45
|
+
console.log(` Total ${instances.length}`);
|
|
46
|
+
console.log(` Running ${chalk_1.default.green(runningCount.toString())}`);
|
|
47
|
+
console.log(` Stopped ${chalk_1.default.dim(stoppedCount.toString())}`);
|
|
48
|
+
console.log('');
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
console.error(chalk_1.default.red(' ✗ Error:'), error instanceof Error ? error.message : error);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
main();
|
|
56
|
+
//# sourceMappingURL=ccb-multi-status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ccb-multi-status.js","sourceRoot":"","sources":["../../src/cli/ccb-multi-status.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ccb-multi.d.ts","sourceRoot":"","sources":["../../src/cli/ccb-multi.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const instance_1 = require("../lib/instance");
|
|
9
|
+
const utils_1 = require("../lib/utils");
|
|
10
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
11
|
+
const program = new commander_1.Command();
|
|
12
|
+
program
|
|
13
|
+
.name('ccb-multi')
|
|
14
|
+
.description('Multi-instance manager for CCB (Claude Code Bridge)')
|
|
15
|
+
.version('1.0.0')
|
|
16
|
+
.argument('<instance-id>', 'Instance ID (1, 2, 3, ...)')
|
|
17
|
+
.argument('[providers...]', 'AI providers (e.g., codex gemini claude)')
|
|
18
|
+
.action(async (instanceId, providers) => {
|
|
19
|
+
try {
|
|
20
|
+
const projectInfo = (0, utils_1.getProjectInfo)();
|
|
21
|
+
console.log('');
|
|
22
|
+
console.log(chalk_1.default.cyan(' ██████╗ ██████╗██████╗ ███╗ ███╗██╗ ██╗██╗ ████████╗██╗'));
|
|
23
|
+
console.log(chalk_1.default.cyan(' ██╔════╝██╔════╝██╔══██╗ ████╗ ████║██║ ██║██║ ╚══██╔══╝██║'));
|
|
24
|
+
console.log(chalk_1.default.cyan(' ██║ ██║ ██████╔╝█████╗██╔████╔██║██║ ██║██║ ██║ ██║'));
|
|
25
|
+
console.log(chalk_1.default.cyan(' ██║ ██║ ██╔══██╗╚════╝██║╚██╔╝██║██║ ██║██║ ██║ ██║'));
|
|
26
|
+
console.log(chalk_1.default.cyan(' ╚██████╗╚██████╗██████╔╝ ██║ ╚═╝ ██║╚██████╔╝███████╗██║ ██║'));
|
|
27
|
+
console.log(chalk_1.default.cyan(' ╚═════╝ ╚═════╝╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝'));
|
|
28
|
+
console.log('');
|
|
29
|
+
console.log(' Multi-Instance Manager for Claude Code Bridge');
|
|
30
|
+
console.log('');
|
|
31
|
+
console.log(chalk_1.default.dim(` Project ${projectInfo.name}`));
|
|
32
|
+
console.log(chalk_1.default.dim(` Instance ${instanceId}`));
|
|
33
|
+
if (providers.length > 0) {
|
|
34
|
+
console.log(chalk_1.default.dim(` Providers ${providers.join(', ')}`));
|
|
35
|
+
}
|
|
36
|
+
console.log('');
|
|
37
|
+
await (0, instance_1.startInstance)(instanceId, providers, projectInfo);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.error(chalk_1.default.red(' ✗ Error:'), error instanceof Error ? error.message : error);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
program.parse();
|
|
45
|
+
//# sourceMappingURL=ccb-multi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ccb-multi.js","sourceRoot":"","sources":["../../src/cli/ccb-multi.ts"],"names":[],"mappings":";;;;;;AAEA,yCAAoC;AACpC,8CAAgD;AAChD,wCAA8C;AAC9C,kDAA0B;AAE1B,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CAAC,qDAAqD,CAAC;KAClE,OAAO,CAAC,OAAO,CAAC;KAChB,QAAQ,CAAC,eAAe,EAAE,4BAA4B,CAAC;KACvD,QAAQ,CAAC,gBAAgB,EAAE,0CAA0C,CAAC;KACtE,MAAM,CAAC,KAAK,EAAE,UAAkB,EAAE,SAAmB,EAAE,EAAE;IACxD,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,IAAA,sBAAc,GAAE,CAAC;QAErC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,wEAAwE,CAAC,CAAC,CAAC;QAClG,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,wEAAwE,CAAC,CAAC,CAAC;QAClG,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,wEAAwE,CAAC,CAAC,CAAC;QAClG,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,wEAAwE,CAAC,CAAC,CAAC;QAClG,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,wEAAwE,CAAC,CAAC,CAAC;QAClG,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,wEAAwE,CAAC,CAAC,CAAC;QAClG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;QAC/D,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,mBAAmB,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC9D,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,mBAAmB,UAAU,EAAE,CAAC,CAAC,CAAC;QAExD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,mBAAmB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QACpE,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEhB,MAAM,IAAA,wBAAa,EAAC,UAAU,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;IAE1D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACvF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ccb-multi",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Multi-instance manager for CCB (Claude Code Bridge) - Run multiple AI coding sessions in parallel",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ccb-multi": "./bin/ccb-multi.js",
|
|
8
|
+
"ccb-multi-status": "./bin/ccb-multi-status.js",
|
|
9
|
+
"ccb-multi-history": "./bin/ccb-multi-history.js",
|
|
10
|
+
"ccb-multi-clean": "./bin/ccb-multi-clean.js"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"dev": "tsc --watch",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"ccb",
|
|
19
|
+
"claude",
|
|
20
|
+
"claude-code-bridge",
|
|
21
|
+
"multi-instance",
|
|
22
|
+
"ai",
|
|
23
|
+
"development",
|
|
24
|
+
"cli",
|
|
25
|
+
"parallel",
|
|
26
|
+
"coding-assistant"
|
|
27
|
+
],
|
|
28
|
+
"author": "dalio willd",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/daniellee2015/ccb-multi.git"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=14.0.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^20.0.0",
|
|
39
|
+
"typescript": "^5.0.0"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"chalk": "^4.1.2",
|
|
43
|
+
"commander": "^11.0.0"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { getProjectInfo, getInstancesDir } from '../lib/utils';
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
|
|
9
|
+
const program = new Command();
|
|
10
|
+
|
|
11
|
+
program
|
|
12
|
+
.name('ccb-multi-clean')
|
|
13
|
+
.description('Clean up CCB multi-instance directories')
|
|
14
|
+
.option('-f, --force', 'Force clean without confirmation')
|
|
15
|
+
.action(async (options) => {
|
|
16
|
+
try {
|
|
17
|
+
const projectInfo = getProjectInfo();
|
|
18
|
+
const instancesDir = getInstancesDir(projectInfo.root);
|
|
19
|
+
|
|
20
|
+
console.log('');
|
|
21
|
+
console.log(chalk.cyan(' ██████╗ ██████╗██████╗ ███╗ ███╗██╗ ██╗██╗ ████████╗██╗'));
|
|
22
|
+
console.log(chalk.cyan(' ██╔════╝██╔════╝██╔══██╗ ████╗ ████║██║ ██║██║ ╚══██╔══╝██║'));
|
|
23
|
+
console.log(chalk.cyan(' ██║ ██║ ██████╔╝█████╗██╔████╔██║██║ ██║██║ ██║ ██║'));
|
|
24
|
+
console.log(chalk.cyan(' ██║ ██║ ██╔══██╗╚════╝██║╚██╔╝██║██║ ██║██║ ██║ ██║'));
|
|
25
|
+
console.log(chalk.cyan(' ╚██████╗╚██████╗██████╔╝ ██║ ╚═╝ ██║╚██████╔╝███████╗██║ ██║'));
|
|
26
|
+
console.log(chalk.cyan(' ╚═════╝ ╚═════╝╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝'));
|
|
27
|
+
console.log('');
|
|
28
|
+
console.log(' Multi-Instance Cleanup');
|
|
29
|
+
console.log('');
|
|
30
|
+
|
|
31
|
+
if (!fs.existsSync(instancesDir)) {
|
|
32
|
+
console.log(chalk.dim(' No instances directory found'));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const instances = fs.readdirSync(instancesDir)
|
|
37
|
+
.filter(name => name.startsWith('instance-'));
|
|
38
|
+
|
|
39
|
+
if (instances.length === 0) {
|
|
40
|
+
console.log(chalk.dim(' No instances to clean'));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
console.log(chalk.dim(` Found ${instances.length} instance(s) to remove:`));
|
|
45
|
+
console.log('');
|
|
46
|
+
instances.forEach(name => {
|
|
47
|
+
console.log(chalk.dim(` ${name}`));
|
|
48
|
+
});
|
|
49
|
+
console.log('');
|
|
50
|
+
|
|
51
|
+
if (!options.force) {
|
|
52
|
+
console.log(chalk.yellow(' Warning: This will delete all instance directories'));
|
|
53
|
+
console.log(chalk.dim(' (shared history will be preserved)'));
|
|
54
|
+
console.log('');
|
|
55
|
+
console.log(chalk.dim(' Run with --force to confirm'));
|
|
56
|
+
console.log('');
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Clean up instances
|
|
61
|
+
for (const instance of instances) {
|
|
62
|
+
const instancePath = path.join(instancesDir, instance);
|
|
63
|
+
fs.rmSync(instancePath, { recursive: true, force: true });
|
|
64
|
+
console.log(chalk.green(` ✓ Removed ${instance}`));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
console.log('');
|
|
68
|
+
console.log(chalk.green(' Cleanup complete'));
|
|
69
|
+
console.log('');
|
|
70
|
+
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error(chalk.red(' ✗ Error:'), error instanceof Error ? error.message : error);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
program.parse();
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { getProjectInfo } from '../lib/utils';
|
|
7
|
+
|
|
8
|
+
async function main() {
|
|
9
|
+
try {
|
|
10
|
+
const projectInfo = getProjectInfo();
|
|
11
|
+
const historyDir = path.join(projectInfo.root, '.ccb', 'history');
|
|
12
|
+
|
|
13
|
+
console.log('');
|
|
14
|
+
console.log(chalk.cyan(' ██████╗ ██████╗██████╗ ███╗ ███╗██╗ ██╗██╗ ████████╗██╗'));
|
|
15
|
+
console.log(chalk.cyan(' ██╔════╝██╔════╝██╔══██╗ ████╗ ████║██║ ██║██║ ╚══██╔══╝██║'));
|
|
16
|
+
console.log(chalk.cyan(' ██║ ██║ ██████╔╝█████╗██╔████╔██║██║ ██║██║ ██║ ██║'));
|
|
17
|
+
console.log(chalk.cyan(' ██║ ██║ ██╔══██╗╚════╝██║╚██╔╝██║██║ ██║██║ ██║ ██║'));
|
|
18
|
+
console.log(chalk.cyan(' ╚██████╗╚██████╗██████╔╝ ██║ ╚═╝ ██║╚██████╔╝███████╗██║ ██║'));
|
|
19
|
+
console.log(chalk.cyan(' ╚═════╝ ╚═════╝╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝'));
|
|
20
|
+
console.log('');
|
|
21
|
+
console.log(' Session History');
|
|
22
|
+
console.log('');
|
|
23
|
+
|
|
24
|
+
if (!fs.existsSync(historyDir)) {
|
|
25
|
+
console.log(chalk.dim(' No history directory found'));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
console.log(chalk.dim(' RECENT SESSIONS (shared across all instances)'));
|
|
30
|
+
console.log('');
|
|
31
|
+
|
|
32
|
+
// List recent history files
|
|
33
|
+
const files = fs.readdirSync(historyDir)
|
|
34
|
+
.filter(name => name.endsWith('.md'))
|
|
35
|
+
.map(name => ({
|
|
36
|
+
name,
|
|
37
|
+
path: path.join(historyDir, name),
|
|
38
|
+
stat: fs.statSync(path.join(historyDir, name))
|
|
39
|
+
}))
|
|
40
|
+
.sort((a, b) => b.stat.mtimeMs - a.stat.mtimeMs)
|
|
41
|
+
.slice(0, 10);
|
|
42
|
+
|
|
43
|
+
if (files.length === 0) {
|
|
44
|
+
console.log(chalk.dim(' No session history found'));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
for (const file of files) {
|
|
49
|
+
const provider = file.name.split('-')[0];
|
|
50
|
+
const size = (file.stat.size / 1024).toFixed(1) + 'K';
|
|
51
|
+
const time = file.stat.mtime.toLocaleString('en-US', {
|
|
52
|
+
month: 'short',
|
|
53
|
+
day: 'numeric',
|
|
54
|
+
hour: '2-digit',
|
|
55
|
+
minute: '2-digit'
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
console.log(` ${chalk.cyan(provider.padEnd(8))} ${chalk.dim(size.padEnd(8))} ${chalk.dim(time)}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
console.log('');
|
|
62
|
+
console.log(chalk.dim(` History location: ${historyDir}`));
|
|
63
|
+
console.log('');
|
|
64
|
+
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error(chalk.red(' ✗ Error:'), error instanceof Error ? error.message : error);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
main();
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { getProjectInfo, listInstances, isInstanceRunning } from '../lib/utils';
|
|
5
|
+
|
|
6
|
+
async function main() {
|
|
7
|
+
try {
|
|
8
|
+
const projectInfo = getProjectInfo();
|
|
9
|
+
const instances = listInstances(projectInfo.root);
|
|
10
|
+
|
|
11
|
+
console.log('');
|
|
12
|
+
console.log(chalk.cyan(' ██████╗ ██████╗██████╗ ███╗ ███╗██╗ ██╗██╗ ████████╗██╗'));
|
|
13
|
+
console.log(chalk.cyan(' ██╔════╝██╔════╝██╔══██╗ ████╗ ████║██║ ██║██║ ╚══██╔══╝██║'));
|
|
14
|
+
console.log(chalk.cyan(' ██║ ██║ ██████╔╝█████╗██╔████╔██║██║ ██║██║ ██║ ██║'));
|
|
15
|
+
console.log(chalk.cyan(' ██║ ██║ ██╔══██╗╚════╝██║╚██╔╝██║██║ ██║██║ ██║ ██║'));
|
|
16
|
+
console.log(chalk.cyan(' ╚██████╗╚██████╗██████╔╝ ██║ ╚═╝ ██║╚██████╔╝███████╗██║ ██║'));
|
|
17
|
+
console.log(chalk.cyan(' ╚═════╝ ╚═════╝╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝'));
|
|
18
|
+
console.log('');
|
|
19
|
+
console.log(' Multi-Instance Status');
|
|
20
|
+
console.log('');
|
|
21
|
+
|
|
22
|
+
if (instances.length === 0) {
|
|
23
|
+
console.log(chalk.dim(' No instances found'));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let runningCount = 0;
|
|
28
|
+
let stoppedCount = 0;
|
|
29
|
+
|
|
30
|
+
console.log(chalk.dim(' INSTANCES'));
|
|
31
|
+
console.log('');
|
|
32
|
+
|
|
33
|
+
for (const instanceId of instances) {
|
|
34
|
+
const running = isInstanceRunning(projectInfo.root, instanceId);
|
|
35
|
+
|
|
36
|
+
if (running) {
|
|
37
|
+
console.log(` ${chalk.green('●')} Instance ${instanceId} ${chalk.dim('running')}`);
|
|
38
|
+
runningCount++;
|
|
39
|
+
} else {
|
|
40
|
+
console.log(` ${chalk.dim('○')} Instance ${instanceId} ${chalk.dim('stopped')}`);
|
|
41
|
+
stoppedCount++;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
console.log('');
|
|
46
|
+
console.log(chalk.dim(' SUMMARY'));
|
|
47
|
+
console.log('');
|
|
48
|
+
console.log(` Total ${instances.length}`);
|
|
49
|
+
console.log(` Running ${chalk.green(runningCount.toString())}`);
|
|
50
|
+
console.log(` Stopped ${chalk.dim(stoppedCount.toString())}`);
|
|
51
|
+
console.log('');
|
|
52
|
+
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error(chalk.red(' ✗ Error:'), error instanceof Error ? error.message : error);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
main();
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { startInstance } from '../lib/instance';
|
|
5
|
+
import { getProjectInfo } from '../lib/utils';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
|
|
8
|
+
const program = new Command();
|
|
9
|
+
|
|
10
|
+
program
|
|
11
|
+
.name('ccb-multi')
|
|
12
|
+
.description('Multi-instance manager for CCB (Claude Code Bridge)')
|
|
13
|
+
.version('1.0.0')
|
|
14
|
+
.argument('<instance-id>', 'Instance ID (1, 2, 3, ...)')
|
|
15
|
+
.argument('[providers...]', 'AI providers (e.g., codex gemini claude)')
|
|
16
|
+
.action(async (instanceId: string, providers: string[]) => {
|
|
17
|
+
try {
|
|
18
|
+
const projectInfo = getProjectInfo();
|
|
19
|
+
|
|
20
|
+
console.log('');
|
|
21
|
+
console.log(chalk.cyan(' ██████╗ ██████╗██████╗ ███╗ ███╗██╗ ██╗██╗ ████████╗██╗'));
|
|
22
|
+
console.log(chalk.cyan(' ██╔════╝██╔════╝██╔══██╗ ████╗ ████║██║ ██║██║ ╚══██╔══╝██║'));
|
|
23
|
+
console.log(chalk.cyan(' ██║ ██║ ██████╔╝█████╗██╔████╔██║██║ ██║██║ ██║ ██║'));
|
|
24
|
+
console.log(chalk.cyan(' ██║ ██║ ██╔══██╗╚════╝██║╚██╔╝██║██║ ██║██║ ██║ ██║'));
|
|
25
|
+
console.log(chalk.cyan(' ╚██████╗╚██████╗██████╔╝ ██║ ╚═╝ ██║╚██████╔╝███████╗██║ ██║'));
|
|
26
|
+
console.log(chalk.cyan(' ╚═════╝ ╚═════╝╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝'));
|
|
27
|
+
console.log('');
|
|
28
|
+
console.log(' Multi-Instance Manager for Claude Code Bridge');
|
|
29
|
+
console.log('');
|
|
30
|
+
console.log(chalk.dim(` Project ${projectInfo.name}`));
|
|
31
|
+
console.log(chalk.dim(` Instance ${instanceId}`));
|
|
32
|
+
|
|
33
|
+
if (providers.length > 0) {
|
|
34
|
+
console.log(chalk.dim(` Providers ${providers.join(', ')}`));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
console.log('');
|
|
38
|
+
|
|
39
|
+
await startInstance(instanceId, providers, projectInfo);
|
|
40
|
+
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error(chalk.red(' ✗ Error:'), error instanceof Error ? error.message : error);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
program.parse();
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2020"],
|
|
6
|
+
"outDir": "./lib",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["src/**/*"],
|
|
18
|
+
"exclude": ["node_modules", "lib"]
|
|
19
|
+
}
|