delete the native terminal tab strip, so it cannot come back on a refresh - #159
Merged
Conversation
plans/LODY-TERMINAL-TABS.md §4.6 named this "PR 2 — the deletion". A terminal is a tab of the session strip; the native strip was the second tab system item 4 forbids, and it kept coming back. TWO LEAKS, NOT ONE. 1. The BOOT WINDOW. `lodySurfaceMounts` needs a box that answered `present`, and the capability probe starts at `probing` on every cold load — up to 7.5 s of retries. The panes filled that window with the native strip and then swapped it for the session strip. That is the flash on refresh. 2. The BARE `/workspaces/:id`, which is the permanent half. That address is `chat === null`, where the surface is hidden and the panes owned the tabs. `useLodyRail` only sent a workspace to the landing when its document held ZERO tabs, so a returning member with tabs stayed on the native strip for good — every bookmark, every workspace switch and every `closeChat()` landed there. Deleted: `WebAppHeader` (the strip, the `+`, rename and the row context menu), its per-region mount in `WorkPanes`, the tab drag-and-drop (`use-workspace-tab-drag.ts`, `workspace-drag.ts`, `moveTab`, `splitTab`, `otherRegion`) whose only handle was a draggable cell in that strip, and every stylesheet rule that drew them. Replaced with: - `shell/PaneChrome.tsx`. The boot window gets a state of its own — a tab-strip skeleton in the shape `WebAppLoadingShell` already uses — and it carries the mobile nav-drawer button, which was a child of the deleted header and is not a tab control. - The workspace ROOT resolves into the chat plane wherever the session strip draws the tabs, so no address is left without one. - A close on the rail's terminal rows. The strip's `×` was the only close there was, and mobile and a box with no session plane never draw the session strip — without this a member could open a terminal and never end its tmux session. `terminalFirstWorkspaceTabs()` goes too: it seeded exactly the tabs only the deleted strip could draw into a fresh workspace on a pre-Lody image. That box now gets the rail's "Sessions need a newer machine" notice, which is the honest answer. Nothing stored is rewritten. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN
Type-level fallout only: the rail hook lost `tabCount` and `onLegacyDefaultTabs` and gained `surfaceHostsTabs`; `WorkPanes` lost its strip props; `SessionRail` and `ShellNav` gained the row close. `lody-old-box-fallback.test.tsx` changes MEANING, not just shape: it asserted that a box with no session plane keeps the native pane strip, which was §4.6's rule and is exactly what "PR 2" reverses. It now asserts the opposite — no strip anywhere — and that a fresh workspace on such a box seeds no legacy tabs. `workspace-panes.test.ts` loses the cases that exercised `moveTab`, `splitTab` and the drag geometry, which are deleted. The one behaviour worth keeping from them — the split collapses when the main pane empties — is rewritten against a hand-built document. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN
`legacy-tab-strip-deleted.test.ts` is the source pin, on the precedent `lody-lazy-boundary.test.ts` set: no module imports the deleted modules, names their DOM markers or their symbols, and no stylesheet still draws them. A render test can only prove the strip did not appear in the cases somebody thought to mount, and both leaks were cases nobody had mounted — this one cannot be satisfied by a gate or a branch, only by the code being gone. It also pins what must SURVIVE: the drawer's segment strip shares the tab-cell chrome, and a class-name sweep is exactly how that gets deleted by accident. `lody-terminal-tab-wave3.test.tsx` gets the behavioural half. F2's answer changed with the product — it asserted the panes draw a strip where the surface is hidden, and now asserts the workspace root resolves into the chat plane instead — and a new case holds the probe open to prove the boot window draws a skeleton and never the old strip. Two neighbouring cases followed the same rule rather than being weakened: ADJ1 loses its "with the panes up" arm because there is no pane address left to read, and F7's inertness loop states the root's normalisation instead of hiding it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN
`WebAppHeader`'s `×` was the whole of `closeTtydSession`'s reach into the UI. Mobile and a box with no session plane never draw the session strip, so deleting the native one left them able to open a terminal and never end its tmux session. The row becomes a `div` wrapping `.shell-s__open`, because a button cannot nest inside a button. The row's OWN geometry stays on `.shell-s`: `lody-blitz-theme.test.ts` pins it equal to the vendored row's, and the two have to read as one list rather than two components. On a touch device there is no hover to reveal the close with, and that rail IS the tab list there, so it is always drawn and finger-sized. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN
`shell-smoke.test.tsx` runs with the flag OFF, where the native strip was the whole tab UI. Its subjects survive — persistence, pane retention, the rail's own record, the mobile sheet — so each case is re-driven through the control that survives rather than dropped: a rail row selects, the row's `×` closes, and the rail's `+` spawns. Rail rows gain `data-session-id`, so a test can address one the way it addressed a tab cell. Two cases are REMOVED, both because their subject is deleted and neither has any other: the managed-session context menu (rename), and dragging a tab into the other pane. Every other case changed its selector, not its claim. `lody-rail-defaults`, `lody-rail-interactions` and `lody-tab-selection-sync` now state which layout they describe. `surfaceHostsTabs: false` is "the panes own the view", which is exactly what those files are about and is the only place `closeChat` still means anything. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN
pythonlearner1025
force-pushed
the
delete-legacy-tab-system
branch
from
September 1, 2026 21:40
1a06695 to
377d691
Compare
pythonlearner1025
added a commit
that referenced
this pull request
Sep 1, 2026
One conflict, in `webapp-workspace.css`, where two deletions met: - main's #159 removed the pane tab strips and their drag chrome (`.webapp-pane-strip`, `.webapp-tab-cell--dragging`, `.webapp-tab-insert`, `.webapp-pane-drop`), and `test/legacy-tab-strip-deleted.test.ts` now pins their absence. - the redesign removed all seven `.webapp-statusline--degraded` rules; four copies merged away on their own, and these three conflicted only because they sit against the block #159 deleted. Nothing renders the class on either side. The resolution takes both deletions and keeps main's note about where the split chrome went. Braces balance; the media query still closes where it did. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN
pythonlearner1025
added a commit
that referenced
this pull request
Sep 4, 2026
Brings the quick-action strip up to date with main after #159, #164, #171, #173, #181, #183, #197 and #207. Thirteen files conflicted; the resolutions, so a reviewer can check them one by one: - `WebAppHeader.tsx`: deleted with the native tab strip on main (#159); the PR's edits to it are moot. Its two exports moved where main put them (`NewTabMenu`, `SessionTypeIcon`). - `CloudApp.tsx`: main's strip deletion wins over the PR's drag wiring (`useWorkspaceTabDrag`, `moveTab`, `splitTab`, the drag ghost); the PR's side-panel binding, Connections host tab and mobile panel sheet stay; main's `workspace-chat-memory` stays. `filesHostRegion`, `ShareToDriveDialog` and `FolderAttachmentView` went with the Files pane the PR retires — their only callers were inside it. - `router.tsx`: the PR's side-panel hooks sit above main's mobile early return, because hooks must. - `SessionRailSidebar.tsx`, `SessionRail.tsx`: main's rows with the close button, minus the `filePath` the PR removed with file tabs. - `lody-surface-tabs.test.tsx`: main moved the seam pin into `lody-seam-pin.test.ts`; the PR's anchors for the three new files and the four session-detail lines are ported there. - `shell-smoke.test.tsx`: main's "the split is a placement" assertions, driven by the Connections icon the PR's strip draws; the drag test goes with the drag. - `workspace-panes.test.ts`: `moveTab` is gone, so the backgrounded panel case builds its side-pane document by hand. - `SessionTypeIcon.tsx`: `WebAppTabModel.panel` narrows to `'connections'`, which is the one panel the PR leaves. Main already used seam numbers 10 and 11 for other patches, so the PR's two seams are 19 and 20 everywhere: the ledger, the seam-pin test, the baselines README, the upstream PR drafts and every code comment. The merge runbook's file table keeps the PR's rows with the new numbers and now says plainly that the ledger is the authority for the count. Gates on the merged tree: webapp typecheck, lint gate, and the full webapp vitest run (113 files, 948 tests) pass. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The panels-a and panels-b QA lanes confirmed seven rows on a real box. This
branch corrects all seven. Five are approved fixes. Two are user rulings.
Seam patch 10 — the side panel file surfaces
Three of these four rows are defects in the upstream desktop branch. Every hunk
is additive. Each row is one upstream PR.
mounted
{fileQuickOpenDialog}only in the mobile return. The key handler ranand prevented the default, but no dialog existed. The dialog now mounts at the
desktop root, beside the other portalled dialogs.
requestKeyholds theidentity of the acquisition effect, and a reconnect moves no input in that
key. The failure therefore outlived the outage. The hook now takes
reloadNonceand returnsreload. It re-arms on an offline-to-online edge ofthe owning machine. The panel also draws the same "Try again" that the
local-error branch had.
draws "Copy file path".
MobileFileViewerDrawercarried this control from thestart, under the same key.
hidden for v1. A box runs no language service, so both entries answered every
identifier with "Host language service does not support this file". The gate
sits on the two
addActioncalls, not on their callbacks. An action with nocallback still sits in the context menu and does nothing.
SP26 uses the shape of seam patch 7. Each level takes one optional prop, and
every prop defaults to the behaviour of today. One new
v1-scope.tsfieldcontrols all of them:
languageService.vendor/lody/BLITZ-PATCHES.mddeclares every hunk. PR #157 took the number 9while this branch was open, so this patch is 10. The merge drill of seam patch 1
now counts both: FIFTEEN diverged files after patch 9, and TWENTY after this one.
Three fixes outside the vendor tree
shrink-0controls of the tab strip overflowed past the right window edge. QA measured
"Add panel" at cx=1911 and "Show sidebar" at cx=1943 on a 1920 screen. One
declaration in
blitz-skin.csssends that overflow to the left. Thedeclaration can move nothing while the strip has room, because the scroll area
beside those controls is
flex-1. The reachable duplicate at cx=1844 is theheader toolbar copy, which upstream draws only while collapsed.
sessions.fileSave.conflictDetailinterpolates{{conflict}}. No call site supplies that variable, and none can. Thesave-conflict banner therefore printed the raw placeholder.
sessions.fileViewer.save.withShortcutadvertised "Save (⌘S / Ctrl+S)". This surface mounts no dispatcher for that
chord. The title now names the action alone. The command layer stays
unmounted.
packages/webapp/src/lody/i18n.tsoverrides both strings, so neither fix is avendor edit. Each test also asserts that the vendored string still holds the
defect. An upstream correction therefore fails a test, and the override is
deleted rather than left in place.
Tests
packages/webapp/test/lody-panel-fixes.test.tsxpins all seven rows. It mountsand drives the real vendored file-tree panel and side-panel strip. It runs both
strings through the real i18next instance. It pins at the source what needs a
daemon. Both rulings have their own test: no Cmd+S advert, and the LSP entries
off behind the v1-scope flag. No test was deleted.
Gates
npm run typecheckpasses.npm run lint:gatepasses: 74 anti-slop findings,all at baseline, and 0 blitz-house findings.
BLITZDEV_MANAGED=1 npm testgives792 passed and 0 assertion failures. One file,
lody-post-signin-turn.test.ts,cannot boot its harness on this box: the box runs its own
lody startdaemon,which holds port 17789 permanently. That is the flake the harness names in its
own error text, and it is unrelated to this branch.
🤖 Generated with Claude Code
https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN