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
+8 -2
View File
@@ -80,6 +80,9 @@ export class FakeEl {
else this.children.splice(i, 0, child);
return child;
}
get firstChild() {
return this.children[0] ?? null;
}
get nextSibling() {
const siblings = this.parentElement?.children ?? [];
return siblings[siblings.indexOf(this) + 1] ?? null;
@@ -152,7 +155,8 @@ export class FakeTile {
export const main = new FakeEl();
main.className = 'main';
const wrap = new FakeEl();
/** The main terminal's `.terminal-wrap` (Pane A while a split is open). */
export const wrap = new FakeEl();
wrap.className = 'terminal-wrap';
main.appendChild(wrap);
export const section = new FakeEl();
@@ -317,8 +321,10 @@ export function resetGridHarness() {
delete windowStub.__codemanCliCatalog;
section.children = [];
main.className = 'main';
// A split a test left open moved .terminal-wrap into its container.
// A split a test left open moved .terminal-wrap into its container, with
// Pane A's header strip in it.
main.children = [];
wrap.children = [];
main.appendChild(wrap);
main.appendChild(section);
bySelector.clear();