9 Commits (main)

Author SHA1 Message Date
I Luk Kim d34359c9ab fix: Claude view parsing/scroll, ngrok warning bypass, reliable send
Claude parsed view:
- Tables now require a real column-border row (┌┬┐/├┼┤); welcome/notice boxes
  (rounded ╭╰, single │ column) no longer render as garbled tables
- Tighten code detection so log lines / prose with parentheses aren't boxed as code
- Status bar no longer eats prose/question lines containing a "·"; pull ctx%/model
  from combined statuslines
- Renderer hashes full block content, so streaming updates re-render instead of
  freezing ("parsed, then not")
- Left-normalize TUI lines shoved to the right on wide panes (text/response/tool
  output only; code/tables/diffs untouched)

Scroll history:
- Stop the loader flash-loop once scrollback is exhausted (noMoreHistory guard)
- Keep the reading position on load; older content is revealed by scrolling up
  further (preserve-position)

ngrok:
- No-cache pass-through service worker adds the ngrok-skip-browser-warning header
  to navigations so the free-tier interstitial is skipped on revisits
  (replaces the old caching SW; sw-unregister removed)

Send:
- Server awaits send_text before pressing Enter so the submit can't race the
  bracketed paste (fixes "had to press Enter twice")

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2 months ago
I Luk Kim 5e473b9ff6 fix: stop 8s terminal blank-flash on non-Claude surfaces
The periodic Claude-mode re-check (setInterval 8s) called
setClaudeMode(false) on plain/codex surfaces, which ran
claudeRenderer.clear() unconditionally. clear() empties the shared
output element (this.el), blanking live terminal/codex content until
the next repaint — perceived as text fading out then back every 8s.

- app.js: remove the 8s claude re-check interval
- terminal-view.js: only clear the renderer on an actual mode
  transition (changed), so redundant setClaudeMode/setCodexMode(false)
  no longer wipes the shared output
- index.html: bump terminal-view.js v12, app.js v21

Verified deterministically in Playwright: pre-fix the output wiped
48->0 ~350ms after each 8s /api/claude-surfaces fetch; post-fix 18s
window shows 0 fetches and content intact.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2 months ago
I Luk Kim 1f50014296 fix: scroll reliability, Claude-mode detection, desktop send
Scrolling:
- Fix snap-back race: render() read a stale autoScroll cache (updated only
  on async scroll events), yanking scrolled-up users back to the bottom
  during live output. Now measure the real bottom position from the DOM at
  render time and gate auto-follow on an explicit autoScroll flag.
- Restore scroll-to-top history loading; add a wheel-up handler so desktop
  (no touch, screen fits viewport → no scroll room → no scroll event) can
  still load scrollback. Resume live updates on scroll-to-bottom.
- Remove the auto-load-when-fits path that permanently froze live updates.
- terminal-container: touch-action pan-y, overflow-y scroll, overscroll
  contain; drop terminal-output min-height:100%; desktop app-container
  explicit 100dvh height.
- gestures.js touchmove → passive (let Safari composite child scroll).

Claude-mode detection:
- Match node-wrapped `claude` processes (check all ps args tokens).
- Enumerate ALL workspaces via `cmux tree --all`, not just the active
  window that the workspace.list socket returns.
- Don't cache empty results; keep last-known-good to survive transient
  ps/socket failures. Periodic client-side re-check.

Misc:
- Desktop: Enter sends, Shift/Cmd+Enter newline (mobile unchanged).
- Keyboard area touch-action:none (no vertical drift), key row pan-x.
- claude-parser _stripAnsi also strips C0/C1 control chars.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2 months ago
I Luk Kim 577b4d749b feat: fix one-press send, add Codex parsed view
Send button:
- submitText() sends text without trailing "\n", then a discrete Enter
  key event after 100ms. cmux delivers send_text as a bracketed paste,
  so a trailing newline became a literal newline in the Claude/Codex
  input box instead of submitting — this required a second (empty)
  press to actually send. Now one press = the full type-then-Enter
  sequence. Fixes Codex always needing two presses and Claude 4+ line
  messages not sending / rendering mid-state.
- data-text shortcut keys now type then send Enter separately
- mousedown.preventDefault keeps soft keyboard up so first tap submits
- Remove IME composition Enter handler (textarea Enter = newline now)

Codex view:
- New codex-parser.js / codex-renderer.js for OpenAI Codex CLI surfaces
- /api/codex-surfaces endpoint; generalize surface-ref lookup into
  _getSurfaceRefsForProcess() (claude + codex)
- app.js updateCodexMode(), terminal.setCodexMode(), codex-mode body
  class (mutually exclusive with claude-mode)

Claude mode:
- Auto-load scrollback when content fits the viewport
- Trim claude-keyboard.js scaffolding; parser/renderer/CSS tweaks

Bump virtual-keyboard.js?v=9 cache-bust.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
3 months ago
I Luk Kim efb0be7896 feat: Claude mode UI improvements and stability enhancements
Claude mode view:
- Context-aware action row replaces all-keys row in Claude mode
  (mode pill, stop button, arrows; selection→option buttons; thinking→pulsing stop)
- Thinking block detection and pulse animation
- Response/text blocks preserve ANSI colors via ansiToHtml()
- Tool-use body collapsible for long outputs (>5 lines)
- Context usage progress bar in status bar (green/yellow/red)
- Mode pill group shows all 3 modes with active highlight + pop animation
- Selection options show focused state and keyboard shortcut hint
- Prompt turn boundaries with visual spacing

Stability:
- WebSocket heartbeat (app-level ping/pong, 15s timeout)
- WS max payload 1MB limit
- Auth rate-limit map periodic cleanup
- Socket connection timeout (10s)
- Terminal line buffer cap (10,000 lines)
- Password masking in console output

UX:
- Scrollback loading indicator
- Code/diff/tool-result copy buttons
- Collapsible tool results (>8 lines)
- Modifier key box-shadow transition

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5 months ago
I Luk Kim a3a607d1f4 chore: clean up project, add README, consolidate duplicate code
- Remove debug artifacts (debug-surface15.png, .playwright-mcp/, dev-notes.md)
- Add .playwright-mcp/ to .gitignore
- Add comprehensive README.md with architecture docs
- Consolidate duplicate _parseStatus() into Sidebar.parseStatus() static method
- Consolidate duplicate ANSI stripping into ClaudeRenderer._stripAnsi()
- Fix ANSI regex to handle OSC sequences in renderer
- Add ║ (U+2551) to box-drawing character sets in parser/renderer
- Guard scrollback handler against empty terminal state
- Remove duplicate process.noDeprecation from src/index.ts
- Remove debug console.log from scroll-request handler

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
5 months ago
I Luk Kim 5b9780fafb feat: Claude mode UI, status indicators, IME fix, tunnel support
- Add Claude Code parsed view with block-based rendering (prompt, tool-use,
  tool-result, code, diff, table, selection options, status bar)
- Add session status dots in sidebar and top bar (idle=yellow, working=green
  with pulse animation) parsed from terminal title characters
- Differentiate active input prompt vs previous submitted prompts with
  distinct background colors
- Fix Korean IME composition issue (last character on next line on Enter)
- Fix CSP inline script violation by moving to external sw-unregister.js
- Add per-block DOM diffing to prevent layout shifts on re-render
- Strip box-drawing borders from tool-result blocks for stable layout
- Add ngrok tunnel support, replace qrcode with qrcode-terminal
- Add Claude-specific keyboard action bar with mode toggle and shortcuts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
5 months ago
I Luk Kim 239c6d2ef6 feat: add Shift modifier key and fix keyboard toggle behavior
- Add Shift modifier button (⇧) alongside Ctrl/Alt with tap/double-tap lock support
- Server-side Shift key parsing (Shift-Tab → shift+tab, etc.)
- Keyboard toggle now only hides key rows, keeping text input always visible
- Fix shortcut-keys row: horizontal scroll instead of wrapping

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5 months ago
I Luk Kim 8bcd7eacd8 feat: initial commit with UX improvements
Add full project including 12 UX improvements: wider gesture edge zone (50px),
prefers-reduced-motion support, additional shortcut keys (^A ^E ^R ^W ^U) and
PageDown, Escape to close sidebar, haptic feedback, key repeat for arrow keys,
sidebar loading/empty state, login loading state, reconnect status indicator,
terminal dim on disconnect, QR modal focus management, and desktop keyboard toggle.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5 months ago