Skip to content

feat: searchable scrollback, and a roadmap for v0.5-v0.7 - #345

Open
attson wants to merge 8 commits into
mainfrom
docs/sync-layer-roadmap
Open

feat: searchable scrollback, and a roadmap for v0.5-v0.7#345
attson wants to merge 8 commits into
mainfrom
docs/sync-layer-roadmap

Conversation

@attson

@attson attson commented Aug 16, 2026

Copy link
Copy Markdown
Owner

What

Two things, in order: a direction spec for the next three versions, then the first item it schedules.

Direction (3 docs commits). docs/superpowers/specs/2026-08-16-sync-layer-roadmap-design.md picks the config-sync layer as the through-line for v0.5-v0.7. The reasoning: internal/prefssync + desktop/ssh_sync.go already implement per-key LWW sync plus account_key sealed envelopes, but only 8 keys are wired to it — while the roadmap backlog is full of items (font, size, start directory, env vars, shortcut bindings) that are exactly the content that engine is missing. Treating them as one line instead of two backlogs means each capability also buys cross-device consistency.

docs/roadmap.md is rewritten around that: new P5 / P6 / P7 sections as items 19-32, old P3 (collaboration) demoted to backlog and P4 (history/replay) deferred, each with a dated note. The stale v0.5 label comes off the completed P2.

Item 19 — terminal scrollback search (5 commits). Mod+F (⌘F / Ctrl+F) opens a search bar over the focused pane; typing searches incrementally, matches highlight, Enter / Shift+Enter step through, a counter shows position over total, Esc closes and clears.

How

  • terminal.search joins the shortcut registry on Mod+KeyF. The session-sidebar search moves to Mod+Shift+KeyFuser-visible behavior change, matching iTerm2 / Ghostty / VS Code where ⌘F searches the terminal.
  • TerminalSearchBar.vue is self-contained: it owns the query and the key semantics and knows nothing about xterm, so it is mount-testable (TerminalView.vue is not).
  • App.vue bumps one monotonic counter, drilled through PaneGrid to every pane; each pane opens its bar only when props.focused.
  • The package is the unscoped xterm-addon-search@^0.13.0 — this repo is on xterm v5, so @xterm/addon-search (v6) would be an API mismatch.

Testing

  • Frontend 162 files / 1970 tests; web 232 tests; go vet ./... clean; go test ./desktop/ passing.
  • internal/relay/web-dist/ rebuilt on Node 20 and verified drift-free twice, so CI's embed gate passes.
  • Every task got its own spec+quality review, plus a whole-branch review and a scoped re-review of the fix wave.

Not covered by automation: nine manual GUI checks (plan file, Task 3 Step 9). A headless agent cannot drive the desktop GUI, so this is the remaining gate. Check 9 is the one worth running first — search, Esc, reopen — it covers a real bug the whole-branch review caught, where a retained query rendered a false "No results" until the next keystroke.

Notes for the reviewer

  • onSearchClose routes through the existing focusTerminalIfDriver() rather than calling term?.focus() directly. This is load-bearing: TerminalView.test.ts pins exactly one direct focus site, because stray xterm refocus pops the iOS soft keyboard, and on the relay web UI the stricter focusTerminalForPaneActivation() would drop focus to body on Esc.
  • Mobile has no touch entry point for search — it opens only via physical keyboard. In scope for item 19 (local terminal basics); an aux-key-bar button would be a new item.

attson added 8 commits August 16, 2026 22:46
Records the direction for the next three versions: treat the existing
prefssync engine + sealed SSH vault as the main line, and grow local
terminal features and SSH host capabilities as content for it.

Scoped out explicitly: the attention-scheduling line (widget forms B/C,
running-session pinning, unwired hook events) stays as-is; old P3
(sharing / presence / audit) and P4 (history / replay) drop to backlog.
Adds P5 (local terminal basics + wiring existing config into prefssync),
P6 (SSH host capabilities) and P7 (sync layer wrap-up) as items 19-32.

Demotes P3 (collaboration) to backlog and defers P4 (history / replay),
each with a dated note explaining why. Drops the stale v0.5 label from
the completed P2. Trims backlog entries now covered by P5/P7 and records
the attention-scheduling follow-ups (running-session pinning, widget
forms B/C, unwired hook events) there instead.
Reviewer finding: onSearchClose's term?.focus() was a second unconditional
direct-focus call site, contradicting the pinned invariant in
"does not focus xterm while the pane is still a viewer" (only one such
call is allowed, and it must be driver-gated). A viewer pane has
disableStdin: !isDriver.value, so returning focus to a read-only terminal
buys nothing while risking the iOS soft-keyboard pop this file guards
against elsewhere. Route through focusTerminalIfDriver() instead; the
search bar itself still opens on viewer panes, gated only by
props.focused.
Addresses the "with fixes" ruling on the scrollback-search branch:

- TerminalSearchBar: reopening with a retained query re-runs the search
  instead of showing a stale "no results" (query survives v-if close,
  counters were reset by the parent)
- TerminalSearchBar: counter shows "N+" instead of a lying "0/N" once the
  addon's highlightLimit caps resultIndex at -1
- TerminalSearchBar: swap hardcoded hex colours for the app's CSS vars
  where they match exactly, use var(--border) for the near-match, add
  aria-label to the three buttons, switch the close glyph to match the
  other six close buttons in the app
- TerminalView.test.ts: pin onSearchFind's empty-query reset branch, tie
  "search bar is positioned" back to .term-view being the actual
  positioning context via styleBlockFor, tighten two unbounded [\s\S]*?
  regexes into body-scoped matches
- Docs: fix stale Cmd/Ctrl+F sidebar-search binding (now Shift+F) in the
  published remote-takeover guide and the architecture spec; correct the
  roadmap's shipped-package-name/shortcut claims for item 19 and the same
  errors in the source design spec, plus its now-stale Status header;
  bump the roadmap's version/date line to the actual latest tag; extend
  the plan's manual QA checklist with the reopen-retains-query case

Rebuilt the web embed (internal/relay/web-dist) to match.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant