Skip to content

planning#110

Merged
aaditagrawal merged 32 commits into
sync/fork-ci-mobile-safetyfrom
sync/upstream-20260614-preview-vcs-ui
Jun 24, 2026
Merged

planning#110
aaditagrawal merged 32 commits into
sync/fork-ci-mobile-safetyfrom
sync/upstream-20260614-preview-vcs-ui

Conversation

@aaditagrawal

Copy link
Copy Markdown
Owner

What Changed

Why

UI Changes

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

aidenybai and others added 30 commits June 13, 2026 22:18
Adds a desktop-only browser preview that lives in the right panel slot
alongside plan/diff. Lets the user point an Electron <webview> at any
URL — typed into a chrome-style URL bar, clicked from the empty-state
list of detected localhost dev servers, or auto-opened by a project
script with `previewUrl` set. Single-tab per thread.

Server (Effect/Layers):
- PreviewManager: per-(thread, tab) session metadata via SynchronizedRef
  + PubSub<PreviewEvent>; survives WS reconnect via `list`/replay.
- PreviewPortScanner: lsof on macOS/Linux, TCP probe fallback on
  Windows; reference-counted polling so we only scan when subscribed.
- WS RPC + streams (`preview.open|navigate|refresh|close|list|reportStatus`,
  `subscribePreviewEvents`, `subscribeDiscoveredLocalServers`).

Desktop:
- PreviewViewManager owns Chromium WebContents per tab, mediates
  navigation/zoom/devtools/clear-storage. registerWebview gates by
  webContents.getType() === "webview" and host-window match.
- IPC channels for create/close/register/navigate/back/forward/refresh/
  zoom/hardReload/openDevTools/clearCookies/clearCache/getBrowserPartition.
- Forwards app-level shortcuts (mod+shift+J, mod+K, mod+,, mod+W) from
  the webview back to the main window.
- Persisted browser session partition (cookies, cache).

Web:
- PreviewPanel/PreviewView/PreviewWebview render the surface; chrome row
  with back/forward/refresh + URL input + Open-in-browser + 3-dot menu
  (Hard reload, DevTools, Zoom −/+/reset, Clear cookies/cache).
- usePreviewSession subscribes to server events; usePreviewBridge
  mirrors desktop state into the store and forwards Loading→Success/
  LoadFailed back to the server.
- previewStateStore: per-thread snapshot + desktopOverlay + recently-
  seen URLs (Zustand).
- rightPanelStore arbitrates plan vs. preview vs. diff; ChatView's
  toggles strip the `?diff=1` URL hint when switching to preview and
  vice versa so the panels are mutually exclusive.
- Top-nav Globe toggle in ChatHeader (desktop builds only) and a
  `mod+shift+J` keybinding routed via a typed previewActionBus.
- PreviewEmptyState lists detected localhost servers (scanner +
  configured project URLs + recently-seen) with live "listening" pulse.
- PreviewUnreachable: theme-aware port of Chromium's "site can't be
  reached" page.
- Resizable inline panel (RightPanelResizeHandle + useResizableWidth);
  width persists to localStorage on drag-end.
- Terminal link "Open in preview" context-menu integration for loopback
  URLs.

Contracts:
- preview.ts schemas (PreviewSessionSnapshot, PreviewNavStatus,
  PreviewEvent, RPC inputs/results, DiscoveredLocalServer).
- ProjectScript schema gains optional `previewUrl` + `autoOpenPreview`.
- New keybinding commands: preview.toggle/refresh/focusUrl/zoomIn/Out/
  resetZoom; new `when:` contexts `previewFocus` / `previewOpen`.

Shared:
- @t3tools/shared/preview: normalizePreviewUrl, isPreviewableUrl,
  isLoopbackHost, newPreviewTabId, LSOF_LOCAL_HOST_TOKENS.

Tests:
- contracts: schema decode tests for all preview events/snapshots/inputs.
- shared: URL normalization coverage.
- server: PreviewManager (open/navigate/reportStatus/refresh/close,
  multi-subscriber isolation, idempotency); PortScanner (lsof parsing
  including IPv6, TCP probe, reference-counted polling).
- web: previewStateStore (per-tab event application, dedupe,
  reconnect recovery); rightPanelStore arbitration.
Adds an in-page element picker to the preview browser. Clicking the
crosshair button in the chrome row activates a blue-highlight picker
inside the guest webview; clicking an element captures its component
name (via react-grab), source location, html/css preview, and selector,
then attaches it to the chat composer as a chip that serializes into an
`<element_context>` block in the outgoing message.

Architecture:
- Per-`<webview>` preload bundle (`preview-pick-preload.cjs`) renders
  the overlay, hosts the picker event loop, and bubbles the picked
  payload back to main via the per-WebContents `wc.ipc` channel (not
  `sendToHost`, which only fires on the host renderer's <webview>
  element and never reaches main).
- Main coordinates via `PreviewViewManager.pickElement(tabId)`, which
  cancels any in-flight session, force-focuses the guest (so the first
  click on a remote page actually reaches the preload), then awaits the
  payload. User-initiated cancels (Escape, beforeunload) echo `null`
  back to main; main-initiated cancels and supersession tear down
  silently to avoid the new-pick-resolves-with-stale-null race.
- Renderer fetches partition + webPreferences + preload URL in a single
  `getPreviewConfig()` IPC call, snapshots the previously-focused host
  element before triggering a pick, and restores focus when the pick
  resolves so the user's textarea cursor isn't lost.

Security posture for the guest webview:
- `webpreferences="contextIsolation=false,sandbox=true,nodeIntegration=false"`
  centralized in `preview-webview-preferences.ts`. contextIsolation off
  is required so react-grab's `getElementContext` can reach the page's
  React DevTools hook on `globalThis`. sandbox stays on so the page
  cannot reach Node APIs even with shared globals (without it, the
  preload's `require` would land on the page's `globalThis` and any
  third-party site could send arbitrary IPC to main).
- Defense in depth: a `will-attach-webview` handler in main, gated on
  the preview partition, force-pins `sandbox: true`, all
  `nodeIntegration*: false`, and the absolute preload PATH (not URL —
  that field rejects file:// URLs with "preload script must have
  absolute path" and silently disables the picker).

Composer + transcript integration:
- New `elementContexts` slice in `composerDraftStore` (mirrors the
  terminal-context slice: dedup by selector+tag+component+url, persist
  via partializer, restore on send-failure retry).
- `ComposerPendingElementContexts` chip row above the editor.
- `deriveDisplayedUserMessageState` now strips both `<element_context>`
  AND `<terminal_context>` blocks (element first, since it's appended
  last) and exposes element entries to `MessagesTimeline`, which renders
  them as compact chips beneath the message body.
- Pick button is disabled with explanatory tooltip when the page failed
  to load (the React `<PreviewUnreachable>` overlay covers the webview,
  so picks would silently dangle otherwise).

Tests added:
- `preview-webview-preferences.test.ts` locks down the security flags
  (contextIsolation=false, sandbox=true, nodeIntegration=false, no
  whitespace, only true/false literal values).
- `preview-pick-label-position.test.ts` covers the floating-label
  clamp/flip math (no off-screen overflow, flip-below when no room
  above, etc.).
- `picked-element-payload.test.ts` validator coverage.
- `elementContext.test.ts` for the serialization round-trip,
  normalization, dedup, and label formatting.
- `composerDraftStore.test.ts` element-contexts slice (add, dedup,
  remove, set, clear, persistence round-trip).
- `ChatView.logic.test.ts` sendable-content-with-element-only.

Build: new `tsdown` entry inlines react-grab + bippy into the picker
preload bundle (~59KB / 19KB gzipped).
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
- Add structured annotation payload validation and tests
- Update preview preload to capture selected elements, regions, and strokes
- Wire new preview annotation UI into the web app

Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
- Add IPC and runtime plumbing for preview annotation theming
- Generate and ship annotation CSS for the desktop overlay
- Add pointer and artifact handling for browser preview interactions
- Move MCP session registry and preview broker out of `Layers/` and `Services/`
- Update imports, tests, and server wiring to use the new module layout
- Move preview session and IPC wiring into the new preview module
- Tighten IPC validation with schema-based handlers
- Update preview asset paths and tests for the browser preview port
- derive preview partitions through `BrowserSession`
- serialize session state and async preview control flow
- update tests for screenshot, automation, and partition behavior
- Tie preview and debugger listeners to Effect scopes
- Factor shared automation helpers for snapshot and input handling
- Improve cleanup for browser preview sessions and port scanning
- Fetch preview sessions through atom-backed SWR state
- Recover browser preview sessions after reconnects
- Ignore older streamed snapshots when SWR revalidates
- Track preview store revisions per thread
- Ignore stale SWR results while revalidating
- Avoid restoring closed sessions from outdated data
- Replace attachment and favicon routes with signed asset URLs
- Harden workspace and attachment asset resolution
- Update browser preview components and shared contracts
- Add phase 0 and 0.5 ADRs, findings, and spike notes
- Update browser preview docs and supporting UI/test files
- Record the chosen renderer, automation, recording, tunnel, and input decisions
…browser automation via CDP. Consolidate and refine the architecture and process models for the new preview automation framework, including updated contracts, server-side broker, and desktop integration. Introduce new WS methods for client communication and enhance security measures for token management. Ensure comprehensive testing strategies are in place for all components.
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ee12950c-ccdf-4c3e-b230-c902fc7112a1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sync/upstream-20260614-preview-vcs-ui

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@aaditagrawal
aaditagrawal marked this pull request as ready for review June 24, 2026 08:44
@aaditagrawal
aaditagrawal merged commit 1aee97e into sync/fork-ci-mobile-safety Jun 24, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ effective changed lines (test files excluded in mixed PRs). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants