tiletopia/memory.md
megaproxy b352f8f049 Initial scaffold from M1 spike (tiletopia)
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>
2026-05-22 12:31:29 +01:00

4.6 KiB
Raw Blame History

memory — tiletopia

Durable memory for this project. Read at session start, update before session end. Date format: YYYY-MM-DD.

Decisions & rationale

  • Stack: Tauri 2 + Svelte 5 + TypeScript + Vite + pnpm + xterm.js + portable-pty. Mirrors claude-usage-widget so we reuse a known-good Windows-targeting toolchain (MSVC + WebView2 + NSIS installer). No new technology bets stacked on top of the new product bet.
  • Layout model: binary tree of splits, NOT free-form rectangles. Same as i3 / tmux / Zellij. Each internal node is HSplit/VSplit + ratio; each leaf is a terminal. Dragging a gutter mutates one parent ratio; both sibling subtrees reflow; descendants get resize. Adaptive resize falls out automatically with no constraint solver. Preset layouts ("3 columns", "2×2") are pre-built trees.
  • PTY backend: portable-pty (same crate WezTerm uses). Spawns wsl.exe -d <distro> --cd <path> on Windows. Manager is a Mutex<HashMap<PaneId, PaneHandle>> in Rust; each pane has a background reader thread that emits pane://{id}/data events.
  • Wire format: base64-encoded byte chunks via Tauri events. xterm.js's onData emits strings; we UTF-8 encode then base64. Slower than a typed-array payload but trivially correct. Revisit if throughput matters.
  • Source on Windows-native disk (D:\dev\tiletopia\), symlinked into WSL. Same pattern as rimlike (D:\godot\rimlike) and tavernkeep. Forced by pnpm 11.x's isDriveExFat crashing on \\wsl.localhost\... UNC paths.
  • Don't commit node_modules, src-tauri/target, or .pnpm-store. DO commit Cargo.lock (binary project, reproducible builds).
  • Session awareness without an in-pane agent. Plan: poll /proc/<pid>/cwd of the shell's child + foreground process every ~2s. Sufficient to detect cd and whether claude is running.

Open questions / TODOs

  • HMR distro picker reset. After a Vite hot reload, the previously-selected distro persists in Svelte 5 $state, so the picker doesn't re-default. Workaround in place (clickable distro buttons in titlebar). Fix properly in M3 when workspace state lives in a separate persisted store.
  • M2 — splits-tree layout component. Two panes side by side, draggable divider, both panes alive. Save/restore layout as JSON.
  • M3 — workspace persistence. Save/restore layouts + per-pane (distro, cwd, label) in %APPDATA%/tiletopia/workspaces.json. Preset layouts (3 columns, 2×2 grid). Distro picker UX, pane labels.
  • M4 — orchestration. Broadcast input groups, idle/finish notifications, Ctrl+K fuzzy palette.
  • M5 — Ship. Replace placeholder icons, NSIS installer, Forgejo release. Copy claude-usage-widget's release scripts.
  • Native Windows shells (cmd / pwsh)? portable-pty supports them for free; keep the option open. Decide whether to expose in UI at M3.
  • Persistent scrollback across app restarts. Would need an out-of-process mux daemon. Big scope creep; explicitly deferred past v1.
  • Keybinding philosophy. Copy tmux, copy WezTerm, or invent? Decide at M3.

Session log

2026-05-22

  • Graduated from ideas/wsl-mux/ to project. Renamed working name wsl-mux → final name tiletopia across Cargo/package/Tauri configs and source.
  • Promoted spike contents from D:\dev\wsl-mux\spike\ to D:\dev\tiletopia\ (no more spike subdir; the project IS what was the spike).
  • Initialized git, created private Forgejo repo tiletopia, pushed initial scaffold.
  • M1 verified manually on the Windows host: window opens, xterm.js renders, claude TUI works inside the pane, resize reflows cleanly, htop renders. Distro auto-pick chose docker-desktop (Docker Desktop's BusyBox helper distro) on first try — added explicit clickable distro buttons in the titlebar as both a diagnostic and a manual override. Clicking Ubuntu works end-to-end.
  • Old idea folder archived to ~/claude/archive/ideas/wsl-mux/ (preserves full brainstorm + session log).

External references

  • Approved plan / roadmap: ~/.claude/plans/imperative-coalescing-feigenbaum.md (M0M5 milestones with verification criteria for each)
  • Stack precedent: ~/claude/projects/claude-usage-widget/ — same Tauri + Svelte + WebView2 toolchain, already ships a Windows installer via Forgejo releases. WSL distro-probing logic copied/adapted into src-tauri/src/pty.rs.
  • Archived idea history: ~/claude/archive/ideas/wsl-mux/plan.md
  • Forgejo repo: https://git.rdx4.com/megaproxy/tiletopia
  • xterm.js docs: https://xtermjs.org/
  • portable-pty crate: https://crates.io/crates/portable-pty
  • Tauri 2 docs: https://v2.tauri.app/
  • Prior art for splits-tree layout: i3, tmux, Zellij, WezTerm