claude-code-plus-plus 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/LICENSE +21 -0
- package/README.md +74 -0
- package/assets/screenshot.png +0 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +2 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/worktree-manager.d.ts +26 -0
- package/dist/core/worktree-manager.d.ts.map +1 -0
- package/dist/core/worktree-manager.js +177 -0
- package/dist/core/worktree-manager.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +208 -0
- package/dist/index.js.map +1 -0
- package/dist/sidebar.d.ts +13 -0
- package/dist/sidebar.d.ts.map +1 -0
- package/dist/sidebar.js +1535 -0
- package/dist/sidebar.js.map +1 -0
- package/dist/state.d.ts +53 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +101 -0
- package/dist/state.js.map +1 -0
- package/dist/terminal-manager.d.ts +16 -0
- package/dist/terminal-manager.d.ts.map +1 -0
- package/dist/terminal-manager.js +364 -0
- package/dist/terminal-manager.js.map +1 -0
- package/dist/tmux.d.ts +163 -0
- package/dist/tmux.d.ts.map +1 -0
- package/dist/tmux.js +360 -0
- package/dist/tmux.js.map +1 -0
- package/dist/types.d.ts +13 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +57 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 blitzjb
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Claude Code++
|
|
2
|
+
|
|
3
|
+
A multi-pane terminal interface for running parallel Claude Code agents with git worktree isolation.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Multi-session management**: Run multiple Claude Code sessions simultaneously
|
|
10
|
+
- **Git worktree isolation**: Each session can operate in its own git worktree
|
|
11
|
+
- **Terminal manager**: Create and manage terminal panes within each session
|
|
12
|
+
- **tmux-based**: Leverages tmux for robust pane management and session persistence
|
|
13
|
+
- **Keyboard-driven**: Full keyboard navigation with mouse support
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install -g claude-code-plus-plus
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Requirements
|
|
22
|
+
|
|
23
|
+
- Node.js >= 18.0.0
|
|
24
|
+
- tmux installed and available in PATH
|
|
25
|
+
- Claude Code CLI (`claude`) installed
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
Run in any git repository:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
claude++
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Or use the shorter alias:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
ccp
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Keyboard Shortcuts
|
|
42
|
+
|
|
43
|
+
### Sidebar Navigation
|
|
44
|
+
| Key | Action |
|
|
45
|
+
|-----|--------|
|
|
46
|
+
| `↑`/`k` | Move selection up |
|
|
47
|
+
| `↓`/`j` | Move selection down |
|
|
48
|
+
| `Enter` | Create session / Switch to session |
|
|
49
|
+
| `n` | New worktree |
|
|
50
|
+
| `d` | Delete session/worktree |
|
|
51
|
+
| `r` | Rename |
|
|
52
|
+
| `Ctrl+T` | New terminal in current session |
|
|
53
|
+
| `Ctrl+G` | Toggle sidebar |
|
|
54
|
+
| `Ctrl+C` | Quit menu |
|
|
55
|
+
|
|
56
|
+
### Terminal Manager
|
|
57
|
+
| Key | Action |
|
|
58
|
+
|-----|--------|
|
|
59
|
+
| `1-9` | Switch to terminal tab |
|
|
60
|
+
| Click | Switch to clicked tab |
|
|
61
|
+
| `n` | New terminal |
|
|
62
|
+
| `d` | Delete current terminal |
|
|
63
|
+
|
|
64
|
+
## How It Works
|
|
65
|
+
|
|
66
|
+
Claude Code++ creates a tmux session with:
|
|
67
|
+
- A sidebar for managing worktrees and sessions
|
|
68
|
+
- A main area for Claude Code and terminal panes
|
|
69
|
+
|
|
70
|
+
Each Claude session is associated with a git worktree, allowing you to work on multiple branches simultaneously with isolated Claude Code agents.
|
|
71
|
+
|
|
72
|
+
## License
|
|
73
|
+
|
|
74
|
+
MIT
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Worktree } from '../types.js';
|
|
2
|
+
export declare class WorktreeManager {
|
|
3
|
+
private basePath;
|
|
4
|
+
private repoPath;
|
|
5
|
+
private git;
|
|
6
|
+
constructor(repoPath: string, basePath?: string);
|
|
7
|
+
private generateId;
|
|
8
|
+
private ensureBaseDir;
|
|
9
|
+
list(): Promise<Worktree[]>;
|
|
10
|
+
create(branch: string, newBranch?: boolean): Promise<Worktree>;
|
|
11
|
+
remove(path: string, force?: boolean): Promise<void>;
|
|
12
|
+
prune(): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Rename a worktree's branch and move its directory atomically.
|
|
15
|
+
* If either operation fails, rollback any changes.
|
|
16
|
+
*/
|
|
17
|
+
rename(worktreePath: string, oldBranch: string, newBranch: string): Promise<string>;
|
|
18
|
+
/**
|
|
19
|
+
* Get the path of a worktree by branch name
|
|
20
|
+
*/
|
|
21
|
+
getWorktreePath(branch: string): Promise<string | null>;
|
|
22
|
+
getBranches(): Promise<string[]>;
|
|
23
|
+
getRepoPath(): string;
|
|
24
|
+
getBasePath(): string;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=worktree-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree-manager.d.ts","sourceRoot":"","sources":["../../src/core/worktree-manager.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAO5C,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,GAAG,CAAY;gBAEX,QAAQ,EAAE,MAAM,EAAE,QAAQ,GAAE,MAA8B;IAMtE,OAAO,CAAC,UAAU;YAIJ,aAAa;IAQrB,IAAI,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IA4C3B,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,GAAE,OAAe,GAAG,OAAO,CAAC,QAAQ,CAAC;IAyBrE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAwB3D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;;OAGG;IACG,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA4BzF;;OAEG;IACG,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAMvD,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAStC,WAAW,IAAI,MAAM;IAIrB,WAAW,IAAI,MAAM;CAGtB"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { simpleGit } from 'simple-git';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { join, basename } from 'path';
|
|
4
|
+
import { mkdir, rm, access } from 'fs/promises';
|
|
5
|
+
import { appendFileSync } from 'fs';
|
|
6
|
+
function debugLog(...args) {
|
|
7
|
+
const msg = `[${new Date().toISOString()}] [WorktreeManager] ${args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a)).join(' ')}\n`;
|
|
8
|
+
appendFileSync('/tmp/claude-pp-debug.log', msg);
|
|
9
|
+
}
|
|
10
|
+
export class WorktreeManager {
|
|
11
|
+
basePath;
|
|
12
|
+
repoPath;
|
|
13
|
+
git;
|
|
14
|
+
constructor(repoPath, basePath = '~/.claude-worktrees') {
|
|
15
|
+
this.repoPath = repoPath;
|
|
16
|
+
this.basePath = basePath.replace('~', homedir());
|
|
17
|
+
this.git = simpleGit(repoPath);
|
|
18
|
+
}
|
|
19
|
+
generateId() {
|
|
20
|
+
return Math.random().toString(36).substring(2, 10);
|
|
21
|
+
}
|
|
22
|
+
async ensureBaseDir() {
|
|
23
|
+
try {
|
|
24
|
+
await access(this.basePath);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
await mkdir(this.basePath, { recursive: true });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async list() {
|
|
31
|
+
try {
|
|
32
|
+
const result = await this.git.raw(['worktree', 'list', '--porcelain']);
|
|
33
|
+
const worktrees = [];
|
|
34
|
+
const blocks = result.trim().split('\n\n');
|
|
35
|
+
for (const block of blocks) {
|
|
36
|
+
if (!block.trim())
|
|
37
|
+
continue;
|
|
38
|
+
const lines = block.split('\n');
|
|
39
|
+
let path = '';
|
|
40
|
+
let branch = '';
|
|
41
|
+
for (const line of lines) {
|
|
42
|
+
if (line.startsWith('worktree ')) {
|
|
43
|
+
path = line.substring(9);
|
|
44
|
+
}
|
|
45
|
+
else if (line.startsWith('branch ')) {
|
|
46
|
+
branch = line.substring(7).replace('refs/heads/', '');
|
|
47
|
+
}
|
|
48
|
+
else if (line === 'detached') {
|
|
49
|
+
branch = '(detached)';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (path) {
|
|
53
|
+
const isMain = path === this.repoPath;
|
|
54
|
+
worktrees.push({
|
|
55
|
+
id: isMain ? 'main' : this.generateId(),
|
|
56
|
+
path,
|
|
57
|
+
branch: branch || basename(path),
|
|
58
|
+
isMain,
|
|
59
|
+
sessions: [],
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return worktrees;
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
// If not a git repo or worktree command fails, return empty
|
|
67
|
+
console.error('Failed to list worktrees:', error);
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async create(branch, newBranch = false) {
|
|
72
|
+
await this.ensureBaseDir();
|
|
73
|
+
const sanitizedBranch = branch.replace(/[^a-zA-Z0-9-_]/g, '-');
|
|
74
|
+
const worktreePath = join(this.basePath, `${basename(this.repoPath)}-${sanitizedBranch}`);
|
|
75
|
+
try {
|
|
76
|
+
if (newBranch) {
|
|
77
|
+
await this.git.raw(['worktree', 'add', '-b', branch, worktreePath]);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
await this.git.raw(['worktree', 'add', worktreePath, branch]);
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
id: this.generateId(),
|
|
84
|
+
path: worktreePath,
|
|
85
|
+
branch,
|
|
86
|
+
isMain: false,
|
|
87
|
+
sessions: [],
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
throw new Error(`Failed to create worktree for branch '${branch}': ${error}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async remove(path, force = false) {
|
|
95
|
+
debugLog('remove called with path:', path, 'force:', force);
|
|
96
|
+
try {
|
|
97
|
+
const args = ['worktree', 'remove'];
|
|
98
|
+
if (force)
|
|
99
|
+
args.push('--force');
|
|
100
|
+
args.push(path);
|
|
101
|
+
debugLog('Running git', args.join(' '));
|
|
102
|
+
await this.git.raw(args);
|
|
103
|
+
debugLog('git worktree remove succeeded');
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
debugLog('git worktree remove failed:', error);
|
|
107
|
+
// Try to clean up manually if git worktree remove fails
|
|
108
|
+
if (force) {
|
|
109
|
+
debugLog('Attempting manual cleanup');
|
|
110
|
+
await rm(path, { recursive: true, force: true });
|
|
111
|
+
await this.git.raw(['worktree', 'prune']);
|
|
112
|
+
debugLog('Manual cleanup succeeded');
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
throw new Error(`Failed to remove worktree at '${path}': ${error}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async prune() {
|
|
120
|
+
await this.git.raw(['worktree', 'prune']);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Rename a worktree's branch and move its directory atomically.
|
|
124
|
+
* If either operation fails, rollback any changes.
|
|
125
|
+
*/
|
|
126
|
+
async rename(worktreePath, oldBranch, newBranch) {
|
|
127
|
+
const sanitizedNewBranch = newBranch.replace(/[^a-zA-Z0-9-_]/g, '-');
|
|
128
|
+
const newWorktreePath = join(this.basePath, `${basename(this.repoPath)}-${sanitizedNewBranch}`);
|
|
129
|
+
// Step 1: Rename the branch
|
|
130
|
+
try {
|
|
131
|
+
await this.git.raw(['branch', '-m', oldBranch, newBranch]);
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
throw new Error(`Failed to rename branch '${oldBranch}' to '${newBranch}': ${error}`);
|
|
135
|
+
}
|
|
136
|
+
// Step 2: Move the worktree directory
|
|
137
|
+
try {
|
|
138
|
+
await this.git.raw(['worktree', 'move', worktreePath, newWorktreePath]);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
// Rollback: rename branch back
|
|
142
|
+
try {
|
|
143
|
+
await this.git.raw(['branch', '-m', newBranch, oldBranch]);
|
|
144
|
+
}
|
|
145
|
+
catch (rollbackError) {
|
|
146
|
+
// Rollback failed - we're in an inconsistent state
|
|
147
|
+
throw new Error(`Failed to move worktree and rollback failed. Manual intervention required. Original error: ${error}`);
|
|
148
|
+
}
|
|
149
|
+
throw new Error(`Failed to move worktree from '${worktreePath}' to '${newWorktreePath}': ${error}`);
|
|
150
|
+
}
|
|
151
|
+
return newWorktreePath;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Get the path of a worktree by branch name
|
|
155
|
+
*/
|
|
156
|
+
async getWorktreePath(branch) {
|
|
157
|
+
const worktrees = await this.list();
|
|
158
|
+
const wt = worktrees.find(w => w.branch === branch);
|
|
159
|
+
return wt?.path || null;
|
|
160
|
+
}
|
|
161
|
+
async getBranches() {
|
|
162
|
+
try {
|
|
163
|
+
const result = await this.git.branch(['-a']);
|
|
164
|
+
return result.all;
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
return [];
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
getRepoPath() {
|
|
171
|
+
return this.repoPath;
|
|
172
|
+
}
|
|
173
|
+
getBasePath() {
|
|
174
|
+
return this.basePath;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=worktree-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree-manager.js","sourceRoot":"","sources":["../../src/core/worktree-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAa,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,IAAI,CAAC;AAGpC,SAAS,QAAQ,CAAC,GAAG,IAAW;IAC9B,MAAM,GAAG,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,uBAAuB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;IAClJ,cAAc,CAAC,0BAA0B,EAAE,GAAG,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,OAAO,eAAe;IAClB,QAAQ,CAAS;IACjB,QAAQ,CAAS;IACjB,GAAG,CAAY;IAEvB,YAAY,QAAgB,EAAE,WAAmB,qBAAqB;QACpE,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;QACjD,IAAI,CAAC,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IACjC,CAAC;IAEO,UAAU;QAChB,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACrD,CAAC;IAEO,KAAK,CAAC,aAAa;QACzB,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;YACvE,MAAM,SAAS,GAAe,EAAE,CAAC;YAEjC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAE3C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;oBAAE,SAAS;gBAE5B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAChC,IAAI,IAAI,GAAG,EAAE,CAAC;gBACd,IAAI,MAAM,GAAG,EAAE,CAAC;gBAEhB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;oBACzB,IAAI,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;wBACjC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;oBAC3B,CAAC;yBAAM,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;wBACtC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;oBACxD,CAAC;yBAAM,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;wBAC/B,MAAM,GAAG,YAAY,CAAC;oBACxB,CAAC;gBACH,CAAC;gBAED,IAAI,IAAI,EAAE,CAAC;oBACT,MAAM,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC,QAAQ,CAAC;oBACtC,SAAS,CAAC,IAAI,CAAC;wBACb,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE;wBACvC,IAAI;wBACJ,MAAM,EAAE,MAAM,IAAI,QAAQ,CAAC,IAAI,CAAC;wBAChC,MAAM;wBACN,QAAQ,EAAE,EAAE;qBACb,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAED,OAAO,SAAS,CAAC;QACnB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,4DAA4D;YAC5D,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;YAClD,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,MAAc,EAAE,YAAqB,KAAK;QACrD,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAE3B,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;QAC/D,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,eAAe,EAAE,CAAC,CAAC;QAE1F,IAAI,CAAC;YACH,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;YACtE,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;YAChE,CAAC;YAED,OAAO;gBACL,EAAE,EAAE,IAAI,CAAC,UAAU,EAAE;gBACrB,IAAI,EAAE,YAAY;gBAClB,MAAM;gBACN,MAAM,EAAE,KAAK;gBACb,QAAQ,EAAE,EAAE;aACb,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,yCAAyC,MAAM,MAAM,KAAK,EAAE,CAAC,CAAC;QAChF,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAY,EAAE,QAAiB,KAAK;QAC/C,QAAQ,CAAC,0BAA0B,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC5D,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YACpC,IAAI,KAAK;gBAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAChC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEhB,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YACxC,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACzB,QAAQ,CAAC,+BAA+B,CAAC,CAAC;QAC5C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,QAAQ,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;YAC/C,wDAAwD;YACxD,IAAI,KAAK,EAAE,CAAC;gBACV,QAAQ,CAAC,2BAA2B,CAAC,CAAC;gBACtC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBACjD,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;gBAC1C,QAAQ,CAAC,0BAA0B,CAAC,CAAC;YACvC,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,KAAK,CAAC,iCAAiC,IAAI,MAAM,KAAK,EAAE,CAAC,CAAC;YACtE,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,MAAM,CAAC,YAAoB,EAAE,SAAiB,EAAE,SAAiB;QACrE,MAAM,kBAAkB,GAAG,SAAS,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;QACrE,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,kBAAkB,EAAE,CAAC,CAAC;QAEhG,4BAA4B;QAC5B,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;QAC7D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,4BAA4B,SAAS,SAAS,SAAS,MAAM,KAAK,EAAE,CAAC,CAAC;QACxF,CAAC;QAED,sCAAsC;QACtC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,eAAe,CAAC,CAAC,CAAC;QAC1E,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,+BAA+B;YAC/B,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;YAC7D,CAAC;YAAC,OAAO,aAAa,EAAE,CAAC;gBACvB,mDAAmD;gBACnD,MAAM,IAAI,KAAK,CAAC,8FAA8F,KAAK,EAAE,CAAC,CAAC;YACzH,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,iCAAiC,YAAY,SAAS,eAAe,MAAM,KAAK,EAAE,CAAC,CAAC;QACtG,CAAC;QAED,OAAO,eAAe,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CAAC,MAAc;QAClC,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QACpC,MAAM,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;QACpD,OAAO,EAAE,EAAE,IAAI,IAAI,IAAI,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,WAAW;QACf,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YAC7C,OAAO,MAAM,CAAC,GAAG,CAAC;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Claude Code++ - Multi-pane terminal for parallel Claude Code agents
|
|
4
|
+
*
|
|
5
|
+
* Uses tmux for true pane isolation:
|
|
6
|
+
* ┌──────────────┬─────────────────────────────────┐
|
|
7
|
+
* │ Sidebar │ │
|
|
8
|
+
* │ (worktrees) │ Main Terminal │
|
|
9
|
+
* │ │ (Claude Code runs here) │
|
|
10
|
+
* │ │ │
|
|
11
|
+
* └──────────────┴─────────────────────────────────┘
|
|
12
|
+
*
|
|
13
|
+
* Sessions persist across restarts - just reattach to existing tmux session.
|
|
14
|
+
* State is stored in ~/.claude-plus-plus/<project>/
|
|
15
|
+
*/
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;GAaG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Claude Code++ - Multi-pane terminal for parallel Claude Code agents
|
|
4
|
+
*
|
|
5
|
+
* Uses tmux for true pane isolation:
|
|
6
|
+
* ┌──────────────┬─────────────────────────────────┐
|
|
7
|
+
* │ Sidebar │ │
|
|
8
|
+
* │ (worktrees) │ Main Terminal │
|
|
9
|
+
* │ │ (Claude Code runs here) │
|
|
10
|
+
* │ │ │
|
|
11
|
+
* └──────────────┴─────────────────────────────────┘
|
|
12
|
+
*
|
|
13
|
+
* Sessions persist across restarts - just reattach to existing tmux session.
|
|
14
|
+
* State is stored in ~/.claude-plus-plus/<project>/
|
|
15
|
+
*/
|
|
16
|
+
import { resolve, dirname } from 'path';
|
|
17
|
+
import { fileURLToPath } from 'url';
|
|
18
|
+
import { existsSync, writeFileSync, chmodSync } from 'fs';
|
|
19
|
+
import { execSync } from 'child_process';
|
|
20
|
+
import { Tmux } from './tmux.js';
|
|
21
|
+
import { getTmuxSessionName } from './state.js';
|
|
22
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
23
|
+
const __dirname = dirname(__filename);
|
|
24
|
+
// Parse arguments
|
|
25
|
+
const args = process.argv.slice(2);
|
|
26
|
+
let repoPath = process.cwd();
|
|
27
|
+
for (let i = 0; i < args.length; i++) {
|
|
28
|
+
const arg = args[i];
|
|
29
|
+
if (arg === '--help' || arg === '-h') {
|
|
30
|
+
console.log(`
|
|
31
|
+
Claude Code++ - Multi-pane terminal for parallel Claude Code agents
|
|
32
|
+
|
|
33
|
+
Usage: claude++ [options] [path]
|
|
34
|
+
|
|
35
|
+
Options:
|
|
36
|
+
-h, --help Show this help message
|
|
37
|
+
-v, --version Show version
|
|
38
|
+
--new Force create new session (kill existing)
|
|
39
|
+
|
|
40
|
+
Arguments:
|
|
41
|
+
path Path to git repository (defaults to current directory)
|
|
42
|
+
|
|
43
|
+
Keyboard Shortcuts (in sidebar):
|
|
44
|
+
↑/↓ or j/k Navigate worktrees/sessions
|
|
45
|
+
Enter Create new session or switch to selected
|
|
46
|
+
Ctrl+T New session for current worktree
|
|
47
|
+
d Delete selected session
|
|
48
|
+
Ctrl+C Quit (kills tmux session)
|
|
49
|
+
|
|
50
|
+
Tmux Shortcuts:
|
|
51
|
+
Ctrl+B then ←/→ Switch between sidebar and terminal panes
|
|
52
|
+
Ctrl+B then d Detach from session (keeps running in background!)
|
|
53
|
+
|
|
54
|
+
Session Persistence:
|
|
55
|
+
- Sessions persist when you detach (Ctrl+B d)
|
|
56
|
+
- Run claude++ again to reattach to existing sessions
|
|
57
|
+
- State stored in ~/.claude-plus-plus/<project>/
|
|
58
|
+
|
|
59
|
+
Examples:
|
|
60
|
+
claude++ # Run in current directory
|
|
61
|
+
claude++ ~/projects/myapp # Run in specific repo
|
|
62
|
+
claude++ --new # Force new session
|
|
63
|
+
`);
|
|
64
|
+
process.exit(0);
|
|
65
|
+
}
|
|
66
|
+
if (arg === '--version' || arg === '-v') {
|
|
67
|
+
console.log('claude++ v0.1.0');
|
|
68
|
+
process.exit(0);
|
|
69
|
+
}
|
|
70
|
+
if (arg === '--new') {
|
|
71
|
+
// Will be handled below
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
// Assume it's a path
|
|
75
|
+
if (!arg.startsWith('-')) {
|
|
76
|
+
repoPath = resolve(arg);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const forceNew = args.includes('--new');
|
|
80
|
+
// Check if tmux is available
|
|
81
|
+
if (!Tmux.isAvailable()) {
|
|
82
|
+
console.error('Error: tmux is required but not installed.');
|
|
83
|
+
console.error('Install with: brew install tmux (macOS) or apt install tmux (Linux)');
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
// Generate unique session name for this project
|
|
87
|
+
const sessionName = getTmuxSessionName(repoPath);
|
|
88
|
+
const tmux = new Tmux(sessionName);
|
|
89
|
+
// Check if session already exists
|
|
90
|
+
if (tmux.sessionExists() && !forceNew) {
|
|
91
|
+
console.log(`Reattaching to existing session: ${sessionName}`);
|
|
92
|
+
console.log('(Use --new to force create a fresh session)');
|
|
93
|
+
const exitCode = tmux.attach();
|
|
94
|
+
// User detached or session ended - exit cleanly
|
|
95
|
+
process.exit(exitCode);
|
|
96
|
+
}
|
|
97
|
+
// Kill existing session if --new flag
|
|
98
|
+
if (forceNew && tmux.sessionExists()) {
|
|
99
|
+
console.log('Killing existing session...');
|
|
100
|
+
tmux.killSession();
|
|
101
|
+
}
|
|
102
|
+
console.log(`Starting Claude++ for: ${repoPath}`);
|
|
103
|
+
console.log(`Session: ${sessionName}`);
|
|
104
|
+
// Create session - starts as single pane for sidebar
|
|
105
|
+
tmux.createSession(repoPath);
|
|
106
|
+
// Configure tmux for better UX
|
|
107
|
+
tmux.setOption('mouse', 'on', true);
|
|
108
|
+
// Auto-copy mouse selection to system clipboard (macOS)
|
|
109
|
+
// When you select text with mouse in tmux, it auto-copies to clipboard on release
|
|
110
|
+
execSync(`tmux bind-key -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-pipe-and-cancel "pbcopy"`, { stdio: 'ignore' });
|
|
111
|
+
execSync(`tmux bind-key -T copy-mode MouseDragEnd1Pane send-keys -X copy-pipe-and-cancel "pbcopy"`, { stdio: 'ignore' });
|
|
112
|
+
tmux.setOption('status', 'off'); // Hide tmux status bar
|
|
113
|
+
tmux.setOption('pane-border-style', 'fg=colour238');
|
|
114
|
+
tmux.setOption('pane-active-border-style', 'fg=colour39');
|
|
115
|
+
// Get the initial pane ID - this will be our sidebar
|
|
116
|
+
const panes = tmux.listPanes();
|
|
117
|
+
const sidebarPaneId = panes[0].id;
|
|
118
|
+
// Split to create welcome pane on the right
|
|
119
|
+
tmux.splitHorizontal(25, repoPath); // 25% for sidebar, 75% for welcome
|
|
120
|
+
// After split: pane 0 is left (sidebar), pane 1 is right (welcome)
|
|
121
|
+
const panesAfterSplit = tmux.listPanes();
|
|
122
|
+
const welcomePaneId = panesAfterSplit[1].id;
|
|
123
|
+
// Disable scroll wheel on sidebar pane only
|
|
124
|
+
tmux.disableScrollForPane(sidebarPaneId);
|
|
125
|
+
// Set up global hotkey: Ctrl+G to toggle sidebar
|
|
126
|
+
tmux.bindSidebarToggle(sidebarPaneId, 25, 2);
|
|
127
|
+
// Detect if running from source (tsx) or built (node)
|
|
128
|
+
function getSidebarCommand() {
|
|
129
|
+
const tsPath = resolve(__dirname, 'sidebar.ts');
|
|
130
|
+
const jsPath = resolve(__dirname, 'sidebar.js');
|
|
131
|
+
// Pass all necessary info to sidebar
|
|
132
|
+
// Note: welcomePaneId is passed as the "terminal" pane - sidebar will manage actual session panes
|
|
133
|
+
const args = [
|
|
134
|
+
`"${repoPath}"`,
|
|
135
|
+
`"${sessionName}"`,
|
|
136
|
+
`"${welcomePaneId}"`,
|
|
137
|
+
`"${sidebarPaneId}"`,
|
|
138
|
+
].join(' ');
|
|
139
|
+
if (existsSync(tsPath)) {
|
|
140
|
+
return `npx tsx "${tsPath}" ${args}`;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
return `node "${jsPath}" ${args}`;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// Run sidebar in left pane
|
|
147
|
+
tmux.runInPane(sidebarPaneId, getSidebarCommand());
|
|
148
|
+
// Set up hook to enforce sidebar width on attach
|
|
149
|
+
execSync(`tmux set-hook -t ${sessionName} client-attached "resize-pane -t ${sidebarPaneId} -x 25"`, { stdio: 'ignore' });
|
|
150
|
+
// Global Ctrl+T binding - sends Ctrl+T to sidebar pane to create terminal
|
|
151
|
+
execSync(`tmux bind-key -T root C-t send-keys -t ${sidebarPaneId} C-t`, { stdio: 'ignore' });
|
|
152
|
+
// Write and run welcome script in right pane
|
|
153
|
+
const welcomeScript = `/tmp/claude-pp-welcome-${sessionName}.sh`;
|
|
154
|
+
const welcomeContent = `#!/bin/bash
|
|
155
|
+
clear
|
|
156
|
+
cat << 'WELCOME'
|
|
157
|
+
|
|
158
|
+
╔═══════════════════════════════════════════════════════════╗
|
|
159
|
+
║ ║
|
|
160
|
+
║ ██████╗██╗ █████╗ ██╗ ██╗██████╗ ███████╗ ║
|
|
161
|
+
║ ██╔════╝██║ ██╔══██╗██║ ██║██╔══██╗██╔════╝ ║
|
|
162
|
+
║ ██║ ██║ ███████║██║ ██║██║ ██║█████╗ ║
|
|
163
|
+
║ ██║ ██║ ██╔══██║██║ ██║██║ ██║██╔══╝ ║
|
|
164
|
+
║ ╚██████╗███████╗██║ ██║╚██████╔╝██████╔╝███████╗ ║
|
|
165
|
+
║ ╚═════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝ ║
|
|
166
|
+
║ CODE ++ ║
|
|
167
|
+
║ ║
|
|
168
|
+
╚═══════════════════════════════════════════════════════════╝
|
|
169
|
+
|
|
170
|
+
Multi-agent Claude Code with git worktree isolation
|
|
171
|
+
|
|
172
|
+
───────────────────────────────────────────────────────────────
|
|
173
|
+
|
|
174
|
+
GETTING STARTED
|
|
175
|
+
|
|
176
|
+
↑/↓ or j/k Navigate worktrees & sessions
|
|
177
|
+
Enter Create new session or switch to selected
|
|
178
|
+
Ctrl+T Open terminal (works from any pane)
|
|
179
|
+
n Create new worktree
|
|
180
|
+
d Delete selected session
|
|
181
|
+
Ctrl+G Toggle sidebar
|
|
182
|
+
|
|
183
|
+
───────────────────────────────────────────────────────────────
|
|
184
|
+
|
|
185
|
+
TMUX SHORTCUTS
|
|
186
|
+
|
|
187
|
+
Ctrl+B ←/→ Switch between panes
|
|
188
|
+
Ctrl+B d Detach (sessions keep running!)
|
|
189
|
+
|
|
190
|
+
───────────────────────────────────────────────────────────────
|
|
191
|
+
|
|
192
|
+
Select a worktree in the sidebar and press Enter to begin.
|
|
193
|
+
|
|
194
|
+
WELCOME
|
|
195
|
+
# Keep the shell open but hide the prompt
|
|
196
|
+
read -r
|
|
197
|
+
`;
|
|
198
|
+
writeFileSync(welcomeScript, welcomeContent);
|
|
199
|
+
chmodSync(welcomeScript, 0o755);
|
|
200
|
+
tmux.sendKeys(welcomePaneId, welcomeScript, true);
|
|
201
|
+
// Focus the sidebar pane initially
|
|
202
|
+
tmux.selectPane(sidebarPaneId);
|
|
203
|
+
// Attach to the session
|
|
204
|
+
console.log('Attaching to tmux session...');
|
|
205
|
+
console.log('Detach with Ctrl+B d (sessions keep running!)');
|
|
206
|
+
const exitCode = tmux.attach();
|
|
207
|
+
process.exit(exitCode);
|
|
208
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Sidebar application - runs in the left tmux pane
|
|
4
|
+
* Displays worktrees and manages Claude sessions
|
|
5
|
+
*
|
|
6
|
+
* Each session is a separate tmux pane that stays alive.
|
|
7
|
+
* Switching sessions swaps which pane is visible.
|
|
8
|
+
*
|
|
9
|
+
* State is saved to ~/.claude-plus-plus/<project>/ for potential restore.
|
|
10
|
+
* However, primary persistence is via tmux - just detach (Ctrl+B d) and reattach!
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=sidebar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["../src/sidebar.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG"}
|