feat(split): both split panes name their harness and model

"Each session in the split view" (owner request) gets the tile header's
strip: the harness logo, the name and the model, painted by the same
_paintSessionHarness.

- Pane B's header is built from nodes now (it was innerHTML with the name
  escaped) and follows renames and model changes on every tab render, like a
  tile header; its close button is a tile button (26px target, 19px glyph).
- Pane A is the main terminal, which has no header of its own: while the
  split is open it gets the same strip, minus the close, as the first child of
  .terminal-wrap, and it names the active session. The strip takes 28px from
  the main terminal, so the opening resize fits it with the strip already in
  place, and closing removes the strip before giving the height back. Both go
  through sendResize / syncTerminalGeometry (#464): the close no longer calls
  a bare fitAddon.fit(), and a close that skips the server resize (Pane A's
  session ended) still refits through syncTerminalGeometry.
- The partial-history banner, which overlays the top of .terminal-wrap,
  starts below Pane A's strip while it is there.

test/split-pane-headers.test.ts drives the real split code on the grid's vm
harness: both headers, text-only names and models, refresh on a tab render,
no writes for an unchanged session, and the opening/closing fits.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-10-07 13:32:00 +02:00
parent 969f273fec
commit c6e13e4fcf
4 changed files with 360 additions and 34 deletions
+25 -19
View File
@@ -19376,31 +19376,33 @@ html[data-session-list="sidebar"][data-sidebar="collapsed"] .btn-sidebar-toggle
overflow: hidden;
}
/* A split pane's header strip, Pane B's always and Pane A's while the split is
open: harness logo, name, model, and Pane B's close (a tile button, see
.tile-btn). The tile header's size and layout, FIXED height like it (#464):
the terminal below is fitted to what is left. */
.terminal-pane-b-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 4px 8px;
gap: 6px;
flex: 0 0 28px;
height: 28px;
box-sizing: border-box;
padding: 0 2px 0 8px;
overflow: hidden;
font-size: 12px;
background: var(--bg-secondary, #1a1a1a);
border-bottom: 1px solid var(--border-color, #333);
flex: 0 0 auto;
user-select: none;
}
.terminal-pane-b-close {
/* A native <button> now backs this (keyboard-reachable close), so reset its
default chrome back to the plain glyph this rule always drew. */
border: none;
background: none;
font: inherit;
color: inherit;
cursor: pointer;
padding: 0 6px;
opacity: 0.7;
/* The partial-history banner overlays the top of .terminal-wrap; while Pane A
has its header there, it starts below it. */
.terminal-pane-a-header ~ .history-trunc-bar {
top: 28px;
}
.terminal-pane-b-close:hover {
opacity: 1;
.split-harness.run-mode-dot {
font-size: 13px;
}
.terminal-pane-b-container {
@@ -19507,7 +19509,8 @@ html[data-session-list="sidebar"][data-sidebar="collapsed"] .btn-sidebar-toggle
the logo and the buttons keep their size. The name does not shrink at all (a
shrink factor, however small, also takes a subpixel from a name that fits and
ellipsizes it) and is capped at this box's width instead. */
.tile-title {
.tile-title,
.split-title {
display: flex;
align-items: baseline;
gap: 6px;
@@ -19517,7 +19520,8 @@ html[data-session-list="sidebar"][data-sidebar="collapsed"] .btn-sidebar-toggle
white-space: nowrap;
}
.tile-name {
.tile-name,
.split-title > .session-name {
flex: 0 0 auto;
max-width: 100%;
min-width: 0;
@@ -19526,7 +19530,8 @@ html[data-session-list="sidebar"][data-sidebar="collapsed"] .btn-sidebar-toggle
text-overflow: ellipsis;
}
.tile-model {
.tile-model,
.split-model {
flex: 0 1 auto;
min-width: 0;
overflow: hidden;
@@ -19536,7 +19541,8 @@ html[data-session-list="sidebar"][data-sidebar="collapsed"] .btn-sidebar-toggle
font-size: 11px;
}
.tile-model::before {
.tile-model::before,
.split-model::before {
content: '\00B7';
margin-right: 6px;
}