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 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
+ ![Claude Code++ Screenshot](assets/screenshot.png)
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,2 @@
1
+ export { WorktreeManager } from './worktree-manager.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -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,2 @@
1
+ export { WorktreeManager } from './worktree-manager.js';
2
+ //# sourceMappingURL=index.js.map
@@ -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":"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"}
@@ -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"}