diff --git a/.jscpd-baseline.json b/.jscpd-baseline.json
index 75910ca3..a5e74326 100644
--- a/.jscpd-baseline.json
+++ b/.jscpd-baseline.json
@@ -7,7 +7,6 @@
"8a060e80d0b739f6": 1,
"938e89086d5dc1f1": 1,
"9bf006a9ac0610a2": 1,
- "a2ffe737302d8522": 1,
"abecc2a6b6900f86": 1,
"ade32fb042158fe0": 1,
"b44f3991fa8ccb97": 1,
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ae2bb406..37966422 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,16 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
- **Edit overrides in VS Code.** **Open in VS Code**, on an override's tab, its right-click menu in the Explorer or the command palette, opens its file there. Save it in VS Code, or any other editor, and the page reloads with your version, just as if you had saved in the app. A tab left open shows the new text; if it has edits you haven't saved, it keeps them and offers the saved file's version instead. **Show in folder** finds the file for any other editor.
- **Share your overrides.** The new menu on the Explorer's **Overrides** section (or the command palette) exports a workspace's overrides and rules as one file, and imports one: send it to a teammate and they see the page with your fix, or copy your changes to another workspace. An import adds only what the workspace doesn't have yet, so your own versions are kept, and tells you what it left out.
+- **Open the page in your other browsers.** The icons beside the address bar open a menu of the browsers on your computer (Chrome, Firefox, Safari, Edge, Brave…), each with its version: pick one and the page opens there, to see whether something looks broken in it. The command palette has them too (**Open in Firefox**), and **Settings › Browsers** hides the ones you don't want offered, or adds one the app didn't find.
+- **Open it with your changes.** Chromium browsers and Firefox also offer **Open in … with your changes**: the app starts the browser with a profile of its own and serves your overrides and rules in every tab you open there, reloading them after a change as it does its own page. The browser menu lists those tabs: bring one to the front, open it in the app or capture it. The browser stays open when you let go of it, and the app finds it again next time. In Firefox, an override replaces the whole response (its headers are its file type's) and patch mode serves your saved text; an override for one GraphQL operation answers there too.
+- **WebKit with your changes.** Safari can only be opened as it is, so the browser menu offers **WebKit**, Playwright's build of Safari's engine, on every system: the first time, it asks to download it (about 90 MB, its progress in the menu), then opens the page there with your overrides and rules. **Settings › Browsers** removes the download. On Linux it may need system libraries (`sudo npx playwright install-deps webkit`).
+- **Your own Chrome with your changes.** Turn on remote debugging in Chrome (`chrome://inspect/#remote-debugging`, Chrome 144 and later) and the browser menu offers **Use your own Chrome with your changes**: the page opens in a new tab of your everyday Chrome, with your extensions and logins, served your changes. Your other tabs are left alone, and letting go leaves Chrome as it was.
+- **Captures.** The new button at the end of the preview's toolbar captures what the page shows, the whole page (up to 32,767 pixels tall, however long it is) or one element you pick (even in a cross-site frame), and lists your captures with their thumbnails, newest first, with a search. A capture's page shows it at any zoom, down to its pixels and the colour under the pointer; copy it, save a copy or rename it. Each workspace keeps its own.
+- **Check the page against a design.** Import a design (PNG, JPEG or WebP; drop or paste it on the menu too; a name with `@2x` sets its scale), or bring a frame in from **Figma** by its link with your personal access token, and compare it with the page captured at the design's width: side by side, swiped, faded over it, or as their difference, with how much of the page differs and where. Edges only smoothed differently (anti-aliasing) show in yellow and don't count.
+- **A design over the live page.** **Put over the page** lays a design over the page itself, at its width, with its opacity, a difference blend and a nudge to line it up, even on a site whose Content-Security-Policy is strict. It stays through reloads and out of your captures, and goes over the tabs of the browsers you opened with your changes too.
+- **Capture in every browser.** **Capture › In every browser** captures the whole page in the app and in every browser you opened with your changes, at the same size, and shows them side by side against the app's capture or a design, each with how much of it differs.
+- **Your open tabs.** The browser menu can list the tabs open in your everyday Firefox, and on macOS in your Safari, Chrome, Edge, Brave, Arc or Vivaldi while they run (macOS asks you first): pick one to open its page in the app.
+
### Changed
- **No more white title bar on Linux.** The editor's window no longer has the system's light title bar above its own. The app's dark title bar is now the top of the window: drag it to move the window, and the minimize, maximize and close buttons sit at its right end, in its colours.
diff --git a/README.md b/README.md
index 757d31ed..57100056 100644
--- a/README.md
+++ b/README.md
@@ -105,6 +105,12 @@ Each workspace keeps its own page, tabs, overrides, rules and actions, so a fix
Right-click a file to block it (an analytics script, a slow third-party iframe) before it reaches the server, or to remove a page's Content-Security-Policy, with an Undo. Rules can also set or remove any response header, or let the page call an API on another origin, preflights and cookies included. Each rule shows how often it applied and to which URLs.
+### Check it in other browsers and against designs
+
+- **Your other browsers** (Chrome, Firefox, Safari, Edge…) are a click away beside the address bar. Chromium browsers and Firefox can also open the page **with your changes**: the app serves your overrides and rules in their tabs too, lays your design over them, and lists those tabs. So can **WebKit** (Playwright's build of Safari's engine, downloaded the first time you use it) on any system, and **your own Chrome** once you turn on remote debugging for it (`chrome://inspect/#remote-debugging`): only the tabs the app opens there get your changes.
+- **Capture** what the page shows, the whole page or one element, here or in those browsers; **Capture in every browser** takes them all at once, at the same size, and shows where they differ.
+- **Compare with a design** pixel by pixel: side by side, swiped, faded, or as their difference with how much differs and where, or lay the design over the live page at its width. Bring a design in from a file, by dropping or pasting it, or from **Figma** by a frame's link (with a personal access token, kept encrypted).
+
### And
- **Never lose work.** Closing the app keeps unsaved edits as drafts and reopens your tabs and the last page; overrides switch on and off one by one.
@@ -205,8 +211,15 @@ Everything stays on your machine: no telemetry, no uploads. Besides the sites yo
| Settings | `settings.json` |
| The last version run, to know when to show What's New | `update.json` |
| Workspaces: each one's name and tile, last page, open tabs, unsaved drafts and site icon | `session/` |
+| Captures and designs, with their thumbnails | `workspace/shots.json`, `workspace/shots/` |
+| Browsers you added or hid | `browsers.json` |
+| Your Figma token, encrypted by the system (once it has worked) | `figma-token` |
+| The WebKit build, once downloaded | `browsers/playwright/` |
+| The profiles of browsers opened with your changes (their logins stay there) | `browsers/` |
| The site's cookies, logins, storage | A persistent browser profile used only by the site view |
+Your everyday Firefox's session file, and on macOS your other browsers' tabs (through scripting, which macOS asks you to allow), are read only when you ask the browser menu for your open tabs, and only their addresses and titles are shown.
+
The data folder is `~/.config/Console Editor` on Linux, `~/Library/Application Support/Console Editor` on macOS and `%APPDATA%\Console Editor` on Windows. Uninstalling the app keeps it. Running from source uses a separate `Console Editor (dev)` folder next to it, so a dev build never touches your real data. Set `CONSOLE_EDITOR_USER_DATA` to use another folder.
## Limitations
@@ -221,6 +234,8 @@ The data folder is `~/.config/Console Editor` on Linux, `~/Library/Application S
- A response override with **Send request** on (the default for a GET) answers after the server has: the request is still sent, so a POST would still create what it creates, which is why overrides made from anything but a GET start with it off. An event stream an override matches is replaced as a whole, which ends it.
- A paused request waits only as long as the page does: if the page gives up on it (a timeout, leaving the page), its tab closes with a note.
- WebSocket messages are shown, not changed: Chromium reports them but can't hold or edit them. A HAR import makes overrides for fetch and XHR responses only, not for documents or scripts.
+- In Firefox opened with your changes, an override answers before the request is sent (Firefox can only replace a response then): its headers are its file type's rather than the server's, patch mode serves your saved text, and a script behind an `integrity` attribute needs the page's HTML overridden too. Breakpoints, the console and the Network panel stay with the app's own page. Safari is opened as it is: check its engine with your changes in WebKit, which quits when you let go of it. On Linux, WebKit needs system libraries you may have to install (`sudo npx playwright install-deps webkit`).
+- A full-page capture stops at 32 767 device pixels tall, the tallest image the compare page can draw. Past 16 384 (Chromium's limit for one capture) it is captured in parts and joined, which takes a while on a long page at high density.
- Chromium's local-network checks are off in the app's browser, so a patched localhost or intranet page can still reach its own servers. Browse only sites you're working on (see [SPEC §8](docs/SPEC.md#8-security)).
## Roadmap
@@ -228,9 +243,8 @@ The data folder is `~/.config/Console Editor` on Linux, `~/Library/Application S
What shipped, release by release, is in the **[CHANGELOG](CHANGELOG.md)**. Next:
- [ ] Parameters and scenarios for actions
-- [ ] Edit in your own editor (watch the overrides folder), and export/import patch sets for teammates
- [ ] Search across every file the page loaded
-- [ ] Drive your own Chrome over CDP
+- [ ] The console, Network panel and inspector for a tab in another browser ([research](docs/BROWSERS_RESEARCH.md))
- [ ] Vue's renders and a data-flow view in the component inspector ([research](docs/INSPECTOR_RESEARCH.md))
- [ ] Signed and notarized builds (and with them, installing updates in place on macOS)
diff --git a/build/entitlements.mac.plist b/build/entitlements.mac.plist
index 59ee0aff..4c977e77 100644
--- a/build/entitlements.mac.plist
+++ b/build/entitlements.mac.plist
@@ -17,5 +17,8 @@
com.apple.security.personal-information.location
+
+ com.apple.security.automation.apple-events
+
diff --git a/docs/BROWSERS_RESEARCH.md b/docs/BROWSERS_RESEARCH.md
new file mode 100644
index 00000000..b192c834
--- /dev/null
+++ b/docs/BROWSERS_RESEARCH.md
@@ -0,0 +1,323 @@
+# Research: other browsers, captures and designs
+
+**Status.** Phases 1 to 8 are built (SPEC §6.16–§6.18), and phase 9 but for the console, Network panel and inspector of an outside tab. WebKit's build couldn't be downloaded here, so it is checked with Playwright's Chromium standing in for it (see [Phase 8](#phase-8-webkit)). The to-do list below says, item by item, what was built and where it went another way.
+
+**Question.** Two things in one request:
+
+1. **Other browsers.** Show the browsers installed on this computer next to the address bar. Open the page in any of them to see whether something is broken there, and search the tabs they have open.
+2. **Captures and designs.** Put a thumbnail at the right end of the toolbar that opens a list of images. The images are captures of the page, and designs to check it against pixel by pixel.
+
+**Short answer.** Yes, in steps. Four findings shape the design:
+
+1. **Opening a page in another browser works everywhere. Opening it with your overrides and rules depends on the browser's engine:**
+ - **Chromium browsers** (Chrome, Edge, Brave, Vivaldi, Opera, Arc, Chromium): the app's engine already runs over a WebSocket connection (`engine/websocketTransport`, which the integration tests use). A Chromium browser the app launches can serve the workspace's changes the way the app's own page does. This is roadmap M3's external Chrome.
+ - **Firefox** no longer speaks CDP. WebDriver BiDi can pause and answer requests, but it needs a second, smaller engine that reuses the app's matching, rules and transforms.
+ - **Safari** has no automation that can change what it loads. The app can only open the page in it. To check the WebKit engine with your changes, the app can use Playwright's WebKit build, on every system.
+2. **Captures come from CDP.** The viewport, the full page or one element can be captured at any pixel density, without resizing the window.
+3. **A design can go over the live page, even on sites whose CSP forbids images from other sources.** The app draws the design on a canvas in an isolated world (verified below). It can't be HTML in the app's own window, because the native page view is drawn above the app's DOM.
+4. **Most of the plumbing exists.** The app already has: a CDP connection to an outside browser, a transport-agnostic engine, the element picker, per-workspace stores and a still of the page for popovers.
+
+---
+
+## 1. What the reference app does
+
+The screenshots show two popovers.
+
+- **Browser switcher.** At the address bar's left is a 2×2 cluster of browser icons (Arc, Safari, Chrome, and a dashed slot to add one). It opens a list headed **Search browser tabs…**, with a gear and a chevron. Tabs are grouped by browser (Arc: a Figma file, a `localhost:5199` page, …), each with its favicon, title and host.
+- **Files.** At the toolbar's right is a stack of thumbnails. It opens a list headed **Search files…**, with segments **All · Captures · Exports**. Each row has a thumbnail, a file name (`page-834.png`, `page-834-full.png`), a line such as "Export · Image · 15h ago", and a chevron.
+
+## 2. What the app has today
+
+| Piece | Where | What this work gets from it |
+|---|---|---|
+| A still of the page | `PageController/snapshotPage` (`capturePage()`: the viewport, as JPEG), `usePageSnapshot` | Popovers over the page freeze it into this still, since the native view is drawn above the DOM. The two new popovers do the same |
+| CDP over WebSocket | `engine/websocketTransport` (`CdpConnection`, `attachToPage`). `test/helpers/chromium.ts` launches Chromium with `--remote-debugging-port=0` and a profile of its own | Driving an outside Chromium browser, and running the engine on its tabs |
+| A transport-agnostic engine | `InterceptionEngine` / `PageInterception` over `CdpTransport`. Plain functions live in `engine/rules` (header, CORS and block rules) and `engine/transform` (headers, charsets, SRI, source maps). Matching is in `OverrideMatcher` and `requestMatches`; patch mode is `patchLive` | Overrides and rules in a Chromium browser as they are. A Firefox engine reuses the plain functions |
+| Element picking | The inspector's picker (SPEC §6.13), in any frame | Capturing one element |
+| Per-workspace stores | `ActionStore`, `OverrideStore`: written atomically, one write at a time, removed with their workspace | A `ShotStore` built the same way |
+| Chromium flags the app needs | `chromiumFlags` (`LOCAL_NETWORK_ACCESS_FEATURES`) | The same flags for a Chromium browser the app launches |
+| Toolbar in both places | `PreviewToolbar` (placement `editor` or `window`) | The two new buttons show in the editor and in the website's own window |
+| Roadmap | M2 "responsive device presets"; M3 external Chrome with a `WebSocketTransport`; story U14 | Setting a design's width uses the same emulation as device presets. Phase 5 below is M3 |
+
+## 3. Verified
+
+These were probed in Chromium 141 (Playwright's build, headless) on a page served with `Content-Security-Policy: default-src 'self'; img-src 'self'`.
+
+| Fact (verified) | Consequence |
+|---|---|
+| An `
` with a `data:` URL is blocked by that CSP, even when an isolated world (`Page.createIsolatedWorld`) creates it | The overlay can't be an `
` or a CSS background |
+| In the same isolated world, `createImageBitmap(new Blob([bytes]))` drawn on a `