Skip to content

Commit a9d361d

Browse files
authored
chore(release): v3.4.0 (#54)
feat: Replace broken panes system with working VS Code-style split view - Delete broken panes.js (1018 lines of buggy code) - Add new splits.js with clean 2-pane split implementation - Each split has independent terminal instance and WebSocket - Drag tabs to right edge to create splits - Resizable divider, keyboard shortcuts, proper cleanup - Remove all pane manager code from app.js and session-manager.js - Update README with split view documentation fix: All split view issues resolved - Sessions no longer get lost - Panels can be closed reliably - Drag and drop works correctly - No orphaned terminals or leaked connections - Proper state management All tests passing (12/12). Backward compatible.
1 parent 069d627 commit a9d361d

10 files changed

Lines changed: 715 additions & 1164 deletions

File tree

CHANGELOG.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,44 @@
11
# Changelog
22

3+
## [3.4.0] - 2025-10-23
4+
5+
### Added
6+
- **VS Code-Style Split View**: New working split view system that actually works!
7+
- Drag any tab to the right edge of the terminal to create a side-by-side split
8+
- Each split has its own independent terminal instance and WebSocket connection
9+
- Resizable divider between splits (drag to adjust width)
10+
- Keyboard shortcuts: `Ctrl+1`/`Ctrl+2` to focus splits, `Ctrl+\` to close split
11+
- Close button (X) in top-right of right split
12+
- Automatic session switching per split
13+
- Clean state management with localStorage persistence
14+
15+
### Removed
16+
- **Broken panes.js system** (1018 lines of buggy code)
17+
- Removed complex grid-based tiling that had fundamental design flaws
18+
- Removed all pane manager code from app.js and session-manager.js
19+
- Removed tile HTML and CSS (~200 lines)
20+
- Removed "Add Pane" button from tab bar
21+
22+
### Fixed
23+
- Sessions no longer get lost during split operations
24+
- Panels can now be closed reliably
25+
- Drag and drop now works correctly
26+
- No more orphaned terminal instances
27+
- No more WebSocket connection leaks
28+
- Proper cleanup when closing splits
29+
30+
### Changed
31+
- Simplified from complex N×M grid to simple 2-pane horizontal split
32+
- Each split maintains its own terminal and connection (true independence)
33+
- Split view is opt-in: create by dragging tabs, not auto-enabled
34+
- Cleaner codebase: 400 lines of working code vs 1000+ lines of broken code
35+
36+
### Notes
37+
- This is a complete rewrite of the split/pane system
38+
- Much more reliable and matches VS Code behavior exactly
39+
- All existing functionality (tabs, sessions, single-pane mode) unchanged
40+
- Test suite: 12/12 passing
41+
342
## [3.3.0] - 2025-10-23
443

544
### Fixed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ npx claude-code-web --disable-auth
3636
- 🌍 **Multi-Browser Access** - Connect to the same session from different browsers/devices
3737
- 💾 **Session Persistence** - Sessions remain active even when disconnecting
3838
- 📜 **Output Buffering** - Reconnect and see previous output from your session
39+
- 🔀 **VS Code-Style Split View** - Drag tabs to create side-by-side terminals for different sessions
3940

4041
## Installation
4142

bin/cc-web.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const program = new Command();
1111
program
1212
.name('cc-web')
1313
.description('Web-based interface for Claude Code CLI')
14-
.version('3.3.0')
14+
.version('3.4.0')
1515
.option('-p, --port <number>', 'port to run the server on', '32352')
1616
.option('--no-open', 'do not automatically open browser')
1717
.option('--auth <token>', 'authentication token for secure access')

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "claude-code-web",
3-
"version": "3.3.0",
3+
"version": "3.4.0",
44
"description": "Web-based interface for Claude Code CLI accessible via browser",
55
"main": "src/server.js",
66
"bin": {

src/public/app.js

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class ClaudeCodeWebInterface {
3232
this.sessionTimer = null;
3333
this.sessionTimerInterval = null;
3434

35-
this.paneManager = null;
35+
this.splitContainer = null;
3636
this.init();
3737
}
3838

@@ -73,8 +73,6 @@ class ClaudeCodeWebInterface {
7373
this.setupTerminal();
7474
this.setupUI();
7575
this.setupPlanDetector();
76-
// Pane manager after UI exists (optional multi-pane)
77-
this.paneManager = new PaneManager(this);
7876
this.loadSettings();
7977
this.applyAliasesToUI();
8078
this.disablePullToRefresh();
@@ -85,8 +83,12 @@ class ClaudeCodeWebInterface {
8583
// Initialize the session tab manager and wait for sessions to load
8684
this.sessionTabManager = new SessionTabManager(this);
8785
await this.sessionTabManager.init();
88-
// Respect user preference from storage; do not auto-enable panes by default
89-
// PaneManager.restoreFromStorage() will enable if previously enabled.
86+
87+
// Initialize split container
88+
if (window.SplitContainer) {
89+
this.splitContainer = new window.SplitContainer(this);
90+
this.splitContainer.setupDropZones();
91+
}
9092

9193
// Show mode switcher on mobile
9294
if (this.isMobile) {
@@ -115,7 +117,6 @@ class ClaudeCodeWebInterface {
115117

116118
window.addEventListener('resize', () => {
117119
this.fitTerminal();
118-
if (this.paneManager?.enabled) this.paneManager.panes.forEach(p => p.fit());
119120
});
120121

121122
window.addEventListener('beforeunload', () => {
@@ -453,27 +454,6 @@ class ClaudeCodeWebInterface {
453454
if (retryBtn) retryBtn.addEventListener('click', () => this.reconnect());
454455

455456
// Tile view toggle
456-
const tileToggle = document.getElementById('tileViewToggle');
457-
if (tileToggle) {
458-
tileToggle.addEventListener('click', () => {
459-
if (!this.paneManager) return;
460-
if (this.paneManager.enabled) {
461-
this.paneManager.disable();
462-
} else {
463-
this.paneManager.enable();
464-
}
465-
});
466-
}
467-
const addPaneBtn = document.getElementById('addPaneBtn');
468-
if (addPaneBtn) {
469-
addPaneBtn.addEventListener('click', () => {
470-
if (!this.paneManager?.enabled) {
471-
this.paneManager?.enable();
472-
}
473-
this.paneManager?.addPane();
474-
});
475-
}
476-
477457
// Mobile menu event listeners
478458
if (closeMenuBtn) closeMenuBtn.addEventListener('click', () => this.closeMobileMenu());
479459
if (settingsBtnMobile) {
@@ -664,6 +644,10 @@ class ClaudeCodeWebInterface {
664644
this.sessionTabManager.updateTabStatus(message.sessionId, message.active ? 'active' : 'idle');
665645
}
666646

647+
// Notify split container of session change
648+
if (this.splitContainer) {
649+
this.splitContainer.onTabSwitch(message.sessionId);
650+
}
667651

668652
// Resolve pending join promise if it exists
669653
if (this.pendingJoinResolve && this.pendingJoinSessionId === message.sessionId) {
@@ -824,9 +808,6 @@ class ClaudeCodeWebInterface {
824808
if (this.sessionTabManager && message.sessionId) {
825809
this.sessionTabManager.closeSession(message.sessionId, { skipServerRequest: true });
826810
}
827-
if (this.paneManager) {
828-
try { this.paneManager.tabs.forEach((t,i)=>this.paneManager.removeTabFromPane(i, message.sessionId)); } catch(_) {}
829-
}
830811
this.loadSessions();
831812
break;
832813

@@ -843,8 +824,6 @@ class ClaudeCodeWebInterface {
843824
message.plan,
844825
message.limits
845826
);
846-
// Also refresh pane session selectors when sessions list changes
847-
if (this.paneManager) this.paneManager.refreshSessionSelects();
848827
break;
849828

850829
default:
@@ -1071,7 +1050,6 @@ class ClaudeCodeWebInterface {
10711050
}
10721051

10731052
this.terminal.options.fontSize = settings.fontSize;
1074-
if (this.paneManager?.panes) this.paneManager.panes.forEach(p => { if (p.terminal) p.terminal.options.fontSize = settings.fontSize; p.fit();});
10751053

10761054
this.fitTerminal();
10771055
}

src/public/index.html

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,6 @@
7979
</div>
8080
</div>
8181
<div class="tab-actions">
82-
<button class="tab-tile" id="addPaneBtn" title="Add Pane">
83-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
84-
<rect x="3" y="3" width="18" height="18" rx="2"/>
85-
<line x1="12" y1="8" x2="12" y2="16"/>
86-
<line x1="8" y1="12" x2="16" y2="12"/>
87-
</svg>
88-
</button>
8982
<button class="tab-settings" id="settingsBtn" title="Settings">
9083
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
9184
<path d="M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z"/>
@@ -116,25 +109,6 @@ <h2><span class="icon" aria-hidden="true"><svg width="18" height="18" viewBox="0
116109
<div id="terminal"></div>
117110
</div>
118111
</div>
119-
<!-- Tiled Panes Container (hidden by default) -->
120-
<div class="tiles-container" id="tilesContainer" style="display:none;">
121-
<div class="tile-grid" id="tileGrid">
122-
<div class="tile-pane" data-index="0">
123-
<div class="tile-toolbar">
124-
<div class="pane-tabs" data-index="0"></div>
125-
<button class="pane-add" data-index="0" title="Add tab">
126-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
127-
</button>
128-
<select class="tile-session-select" data-index="0" style="display:none"></select>
129-
<div class="spacer"></div>
130-
<button class="tile-close" data-index="0" title="Close Pane">
131-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
132-
</button>
133-
</div>
134-
<div class="tile-terminal" id="tileTerminal0"></div>
135-
</div>
136-
</div>
137-
</div>
138112
</main>
139113

140114
<!-- App-wide overlay (moved out of terminal container to avoid width issues) -->
@@ -332,7 +306,7 @@ <h2>Sessions</h2>
332306
<script src="auth.js"></script>
333307
<script src="plan-detector.js"></script>
334308
<script src="session-manager.js"></script>
335-
<script src="panes.js"></script>
309+
<script src="splits.js"></script>
336310
<script src="icons.js"></script>
337311
<script src="app.js"></script>
338312

0 commit comments

Comments
 (0)