- window_state.rs: persist only the main window's workspaces. The aggregator
flattened every window's tabs into the saved file; main then adopted the
whole blob on launch, so detached windows' ephemeral tabs (and Pane N
drag-out artifacts) accumulated without bound.
- TabStrip: portal the close-confirm popover to <body> with fixed,
viewport-clamped positioning so the horizontally-scrolling strip can't clip
it and it never runs off a window edge.
- styles.css: make themed ::-webkit-scrollbar global, not just xterm viewport.
- LeafPane: B1 drag-out ghost chip (portal, edge-pinned, orange detach state).
- App.tsx: moveToNewWindow waits briefly for pane registration instead of
failing instantly on an in-flight spawn/adopt.
- gitignore cargo-test.lo*.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two small QoL additions:
- styles.css: WebKit pseudo-element styling for .xterm-viewport
scrollbars (8px wide, dark thumb #2a2a2a on transparent track,
hover lighten). Matches the rest of the dark theme so the right
edge of each terminal stops looking like default OS chrome.
- tree.ts: setAllBroadcast(root, on) helper that flips every leaf's
broadcast flag to the given value, preserving object identity
where nothing changed.
- App.tsx: titlebar 📡 button showing global broadcast state
("all off" / "all on" / "N/M"). Click toggles every pane between
all-broadcasting and all-off. Orange when any panes are
broadcasting; darker orange when partial.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After hours of fighting Svelte 5's prop-reactivity through the
recursive Pane → SplitNode → LeafPane chain (props captured at
mount, never updated; context+getter pattern crashed; DOM-direct
workarounds created zombie-split click-intercept bugs), we
checkpointed the Svelte version (branch svelte-archive at e9015b2,
tarball at D:\archives\tiletopia-svelte-2026-05-22.tar.gz) and
rewrote the frontend in React.
Kept verbatim:
- All of src-tauri/ (Rust backend, Tauri config, icons)
- scripts/ (make-icon.py, release.sh)
- README.md, CLAUDE.md, memory.md
- src/lib/layout/tree.ts (pure TS — 43 tests still pass)
- src/ipc.ts (Tauri command wrappers)
Rewrote in React:
- src/App.tsx (top-level state via useState, OrchestrationProvider
for descendants via React.Context)
- src/lib/layout/orchestration.tsx (React Context API for shared
state — known-reliable reactivity, no Svelte 5 wall)
- src/lib/layout/Pane.tsx (recursive dispatcher)
- src/lib/layout/SplitNode.tsx (draggable gutter, local ratio state)
- src/lib/layout/LeafPane.tsx (toolbar + XtermPane)
- src/components/XtermPane.tsx (xterm.js wrapper, refs for callbacks)
- src/components/Notifications.tsx, Palette.tsx
Build: Vite + @vitejs/plugin-react. TypeScript strict. Same Tauri 2
config. Verified: pnpm check (clean), pnpm test (43/43 pass).
Not yet verified: pnpm tauri dev — that requires the Windows host.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tauri 2 + Svelte 5 + xterm.js + portable-pty. Single full-window
WSL terminal pane with clickable distro picker. M1 verified manually
on Windows: window opens, xterm.js renders, claude TUI works,
resize reflows cleanly.
Graduated from ~/claude/ideas/wsl-mux/ per the approved plan at
~/.claude/plans/imperative-coalescing-feigenbaum.md. See memory.md
for decisions, open TODOs, and the M2-M5 roadmap.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>