Commit 4a0e982
sync: update from upstream (#31)
* planning
* feat(preview): in-app browser preview panel
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.
* fix
* feat(preview): element-pick attachments + sandboxed picker preload
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).
* fix(preview): port browser preview to current main
Co-authored-by: codex <codex@users.noreply.github.com>
* fix(preview): initialize and open browser reliably
Co-authored-by: codex <codex@users.noreply.github.com>
* fix(preview): declare RPC authorization scopes
Co-authored-by: codex <codex@users.noreply.github.com>
* Add preview annotation capture tooling
- 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>
* Add shared MCP preview automation
* Refine collaborative browser preview
Co-authored-by: codex <codex@users.noreply.github.com>
* Port browser preview annotations to desktop
- 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
* Refactor MCP services into top-level modules
- Move MCP session registry and preview broker out of `Layers/` and `Services/`
- Update imports, tests, and server wiring to use the new module layout
* Refactor desktop preview IPC onto shared manager
- 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
* Port preview manager to Effect-based browser sessions
- derive preview partitions through `BrowserSession`
- serialize session state and async preview control flow
- update tests for screenshot, automation, and partition behavior
* Scope preview listeners and control sessions
- 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
* Add SWR preview session state and resubscribe handling
- Fetch preview sessions through atom-backed SWR state
- Recover browser preview sessions after reconnects
- Ignore older streamed snapshots when SWR revalidates
* Prevent stale preview snapshots from resurrecting sessions
- Track preview store revisions per thread
- Ignore stale SWR results while revalidating
- Avoid restoring closed sessions from outdated data
* Unify browser asset preview routing
- Replace attachment and favicon routes with signed asset URLs
- Harden workspace and attachment asset resolution
- Update browser preview components and shared contracts
* Fix preview CI test fixtures
* Fix terminal browser test mock
* Restore terminal drawer header toggle
* Use real preview tooltips
* Document browser preview phase 0.5 findings and plans
- 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
* Remove outdated plans for shared HTTP MCP server and visible preview 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.
* rm test artifacts
* Fix Bitbucket source control availability toggle
* Guard VCS status updates against stale targets (pingdotgg#3084)
* Wrap authorized clients in fading scroll area (pingdotgg#3085)
* Preserve diff surface when toggling right panel (pingdotgg#3083)
* fix(desktop): mac start:desktop crash from rewritten framework symlinks (pingdotgg#3058)
* refactor: resolve host process state through Effect (pingdotgg#2959)
Co-authored-by: Julius Marminge <julius@mac.lan>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* Add workspace file browser and preview panel (pingdotgg#3087)
* Unify compact subheaders and diff file navigation
- Add shared compact subheader styling for preview, file, and diff panels
- Open diff files in the thread file viewer when available
- Fix macOS cursor auto-hide and Option-modified shortcut matching
* Tighten workspace control spacing in the header
- Align header controls with the 12px right inset
- Use a smaller control offset in window controls overlay mode
* Show disabled reasons for unavailable right panel surfaces (pingdotgg#3093)
* [codex] Fix first browser annotation capture (pingdotgg#3095)
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
* Use `fff` for workspace search queries (pingdotgg#3099)
* [codex] Fix terminal line height for QR readability (pingdotgg#3096)
* [codex] Trace first-party relay clients (pingdotgg#2995)
Co-authored-by: codex <codex@users.noreply.github.com>
* fix sync merge gaps for terminal runtime env wiring
restore upstream projectScriptRuntimeEnv and thread drawer runtime env props dropped during fork merge
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com>
Co-authored-by: JustMarkDev <procopiomarco@protonmail.com>
Co-authored-by: Icarus Wings <10465470+TheIcarusWings@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@mac.lan>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Theo Browne <me@t3.gg>
Co-authored-by: Wout Stiens <71498452+StiensWout@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>363 files changed
Lines changed: 28865 additions & 13566 deletions
File tree
- .github/workflows
- apps
- desktop
- scripts
- src
- app
- electron
- ipc
- methods
- preview
- window
- mobile/src/features/observability
- server
- integration
- scripts
- src
- assets
- cli
- cloud
- diagnostics
- environment/Layers
- mcp
- toolkits/preview
- orchestration/Layers
- preview
- process
- project/Layers
- provider
- Drivers
- Layers
- acp
- relay
- telemetry
- Layers
- terminal/Layers
- textGeneration
- workspace
- Layers
- Services
- web
- src
- assets
- browser
- cloud
- components
- chat
- files
- preview
- settings
- ui
- environments/runtime
- hooks
- lib
- routes
- rpc
- docs/user
- infra/relay
- scripts
- src
- oxlint-plugin-t3code
- rules
- packages
- client-runtime/src
- contracts/src
- effect-acp/test/examples
- effect-codex-app-server
- src
- test
- examples
- fixtures
- ssh/src
- tailscale/src
- patches
- scripts
- lib
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
245 | 245 | | |
246 | 246 | | |
247 | 247 | | |
| 248 | + | |
| 249 | + | |
248 | 250 | | |
249 | 251 | | |
250 | 252 | | |
251 | 253 | | |
252 | 254 | | |
253 | 255 | | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
254 | 288 | | |
255 | 289 | | |
256 | 290 | | |
| |||
337 | 371 | | |
338 | 372 | | |
339 | 373 | | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
340 | 388 | | |
341 | 389 | | |
342 | 390 | | |
| |||
620 | 668 | | |
621 | 669 | | |
622 | 670 | | |
| 671 | + | |
| 672 | + | |
| 673 | + | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
| 679 | + | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
623 | 685 | | |
624 | 686 | | |
625 | 687 | | |
| |||
782 | 844 | | |
783 | 845 | | |
784 | 846 | | |
| 847 | + | |
| 848 | + | |
| 849 | + | |
| 850 | + | |
| 851 | + | |
| 852 | + | |
| 853 | + | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
| 858 | + | |
| 859 | + | |
| 860 | + | |
785 | 861 | | |
786 | 862 | | |
787 | 863 | | |
| |||
828 | 904 | | |
829 | 905 | | |
830 | 906 | | |
| 907 | + | |
| 908 | + | |
| 909 | + | |
831 | 910 | | |
832 | 911 | | |
833 | 912 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
23 | | - | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
24 | 26 | | |
25 | 27 | | |
26 | 28 | | |
27 | 29 | | |
28 | 30 | | |
29 | 31 | | |
| 32 | + | |
30 | 33 | | |
31 | 34 | | |
32 | 35 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
3 | 4 | | |
4 | 5 | | |
5 | | - | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
6 | 11 | | |
7 | 12 | | |
8 | 13 | | |
| |||
29 | 34 | | |
30 | 35 | | |
31 | 36 | | |
| 37 | + | |
| 38 | + | |
32 | 39 | | |
33 | 40 | | |
34 | 41 | | |
| |||
53 | 60 | | |
54 | 61 | | |
55 | 62 | | |
56 | | - | |
| 63 | + | |
57 | 64 | | |
58 | 65 | | |
59 | 66 | | |
60 | 67 | | |
61 | 68 | | |
62 | 69 | | |
63 | 70 | | |
64 | | - | |
| 71 | + | |
65 | 72 | | |
66 | 73 | | |
67 | 74 | | |
| |||
79 | 86 | | |
80 | 87 | | |
81 | 88 | | |
82 | | - | |
| 89 | + | |
| 90 | + | |
83 | 91 | | |
84 | 92 | | |
85 | 93 | | |
| |||
189 | 197 | | |
190 | 198 | | |
191 | 199 | | |
192 | | - | |
| 200 | + | |
193 | 201 | | |
194 | 202 | | |
195 | 203 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| 17 | + | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| |||
30 | 31 | | |
31 | 32 | | |
32 | 33 | | |
33 | | - | |
| 34 | + | |
34 | 35 | | |
35 | 36 | | |
| 37 | + | |
| 38 | + | |
36 | 39 | | |
37 | 40 | | |
38 | 41 | | |
| |||
295 | 298 | | |
296 | 299 | | |
297 | 300 | | |
298 | | - | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
299 | 306 | | |
300 | 307 | | |
301 | 308 | | |
| |||
307 | 314 | | |
308 | 315 | | |
309 | 316 | | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
310 | 342 | | |
311 | 343 | | |
312 | 344 | | |
313 | 345 | | |
314 | 346 | | |
315 | 347 | | |
316 | | - | |
| 348 | + | |
317 | 349 | | |
318 | 350 | | |
319 | 351 | | |
320 | 352 | | |
321 | 353 | | |
322 | 354 | | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
323 | 363 | | |
324 | | - | |
| 364 | + | |
325 | 365 | | |
326 | 366 | | |
327 | 367 | | |
| |||
0 commit comments