Wire copy-on-select in XtermSession (shared by the workspace terminal
and the /machine terminal): a header checkbox toggles the behavior and
persists to localStorage under spoon.terminal.copyOnSelect. On mount the
stored value takes precedence over the copyOnSelect prop default. When
enabled, onSelectionChange copies the current selection via
navigator.clipboard.writeText — guarded (empty selections skipped;
clipboard-unavailable/denied errors swallowed). The handler reads the
toggle through a ref so live flips apply without reconnecting.
WebLinksAddon remains loaded so printed URLs are clickable.
Manual verification: in /machine and a workspace terminal, enabling
copy-on-select and selecting text places it on the clipboard; a printed
URL is clickable and opens in a new tab.
- Add Symbols-Only Nerd Font Mono (woff2) under public/fonts; @font-face scoped
by unicode-range to the Nerd Font glyph ranges, so the ~1.1MB file only loads
when an icon actually renders (latin text stays on Victor Mono)
- Terminal + editor font stacks fall back to it for icons; terminal prewarms it
and repaints so powerline/oh-my-posh/eza/nvim icons show
- No server/env changes; ships in the spoon-next image (public/)
- New Terminal tab in the workspace shell, backed by xterm.js, that connects
to the worker's PTY WebSocket using a short-lived token minted by
/api/agent-jobs/:id/terminal-token (owner-auth'd, never exposes the worker
secret to the browser)
- Site-matched xterm theme (light/dark, live theme switching), Victor Mono,
binary stdin + JSON resize protocol, reconnect, graceful 'not configured'
state when NEXT_PUBLIC_SPOON_AGENT_WORKER_WS_URL is unset
- env: NEXT_PUBLIC_SPOON_AGENT_WORKER_WS_URL (client), SPOON_AGENT_TERMINAL_SECRET
- Add spoon-dark/spoon-light Monaco themes built from the site's design tokens
(teal --primary accent), switched by next-themes resolvedTheme
- Use Victor Mono (with ligatures + italic comments) for the editor font
- Disable Monaco's in-browser TS *semantic* diagnostics, which were false
positives (no node_modules / path aliases in the browser) e.g. 'Cannot find
module ~/server/auth'; keep real syntax-error reporting
- Gate the tree/diff/status loads (and 5s poll) on workspaceStatus being
active/idle, so we no longer hammer the 'workspace is not active' endpoint
while a worker is still picking up the job
- Show a 'Setting up your workspace…' pending state instead of surfacing
startup as a console error / stale-workspace recovery box; escalate to a
softer 'still waiting' hint after 90s if no worker picks it up
- Auto-reload the diff and file tree (debounced) whenever the agent records a
workspace change or a turn starts/ends, so diffs appear without a manual
Refresh
- The recovery box now only appears for a genuinely lost workspace (Convex
reports active but the worker can't reach it)
Replace the raw single-blob diff dump (Monaco, language=diff) and the plain
<pre> file diffs in chat with @git-diff-view/react:
- Parse the unified git diff into structured per-file entries (status,
+/- counts, binary detection) via parseDiffFiles()
- Workspace Diff tab: collapsible per-file cards with status badges, line
counts, syntax highlighting, and a Unified/Split toggle
- Agent chat: render each change's diff highlighted instead of plain text
- Theme follows next-themes resolvedTheme (light/dark)