@aryanduntley/pwa-debug 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +467 -0
- package/package.json +7 -5
- package/dist/.tsbuildinfo +0 -1
- package/dist/main.js.map +0 -1
- package/extension/content-script.js.map +0 -1
- package/extension/page-world.js.map +0 -1
- package/extension/service-worker.js.map +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
# pwa-debug-layer
|
|
2
|
+
|
|
3
|
+
An **AI-native debugging layer for PWAs and modern web apps**. It lets an AI agent (e.g. Claude Code via MCP) **see and act on your live, logged-in browser** the way a developer with full DevTools open would — DOM, console, network, framework state, store state, service workers, caches, and direct interaction — as structured data the model consumes natively.
|
|
4
|
+
|
|
5
|
+
It's built for the questions developers actually search for and that Chrome DevTools makes you assemble by hand: *why won't my service worker update? why is my cache stale? why won't my PWA install? why does this component have the wrong state?* — answered by an agent reading the runtime directly, against **your real browser profile** (extensions, auth, and all), not a sterile automated tab.
|
|
6
|
+
|
|
7
|
+
### What it answers
|
|
8
|
+
|
|
9
|
+
The PWA failures developers actually search for, read straight from your live runtime:
|
|
10
|
+
|
|
11
|
+
- **Why won't my service worker update? Why are some users on old code?** — SW lifecycle with waiting-vs-active versions, plus an update-propagation / version-skew analyzer.
|
|
12
|
+
- **Why is my cache stale? Why are chunks 404ing after a deploy?** — CacheStorage contents with age, and a cached-HTML-vs-JS skew check.
|
|
13
|
+
- **Why won't my PWA install?** — structured installability diagnostics with per-gap remediation, not just "manifest invalid."
|
|
14
|
+
- **What's actually in IndexedDB / localStorage right now?** — live storage inspection (*inspect IndexedDB live*).
|
|
15
|
+
- **What can this browser actually do?** — a live capability matrix (Push / Background Sync / Periodic Sync / Badging / File System Access / Window Controls Overlay).
|
|
16
|
+
|
|
17
|
+
All read from your real, logged-in profile — service-worker, cache, and extension state included — which `chrome-devtools-mcp`'s sterile automated Chrome can't see.
|
|
18
|
+
|
|
19
|
+
The goal is to eliminate the "user is the AI's eyes and hands" loop. Today, debugging a PWA with AI usually means the human copy/pastes DOM snippets, describes console errors, screenshots UI state, and hand-executes clicks. This project replaces that with direct, structured access.
|
|
20
|
+
|
|
21
|
+
> **Status: working on Linux.** The full MCP→IPC→native-host→service-worker→page-world round-trip is live, and a broad debugging surface is shipped:
|
|
22
|
+
> - **Capture** — console / network / error / DOM-mutation / lifecycle, with persistent ring buffers + disk spill.
|
|
23
|
+
> - **Framework introspection** — **React, Vue, Svelte, and Solid** (component/element trees, state, find-by-text/role).
|
|
24
|
+
> - **Store introspection** — **Redux, Zustand, Pinia, and Jotai** (read, subscribe, dispatch).
|
|
25
|
+
> - **Interaction + touch gestures** — click, fill, submit, hover, focus/blur, select, key/type, **drag, scroll, swipe, tap, double-tap, long-press, pinch**.
|
|
26
|
+
> - **Library-popup capture/replay** — WalletConnect / SDK modals: record, replay, tail, failure correlation.
|
|
27
|
+
> - **Replay & source maps** — rrweb `session_record`/`session_replay`, `source_map_resolve`.
|
|
28
|
+
> - **Browser launcher** — one-call `pdl_launch_browser` with `chrome-devtools-mcp` coexistence.
|
|
29
|
+
> - **PWA Runtime Diagnostics** — service-worker lifecycle + versions, CacheStorage contents + age, installability gaps, a live capability matrix, IndexedDB/web-storage inspection, update-propagation / version-skew analysis, and a one-shot runtime-state snapshot.
|
|
30
|
+
>
|
|
31
|
+
> **Verified on Linux** (the full suite live-tested against a real PWA). macOS/Windows code paths are implemented with unit coverage but still need real-machine retest ([help wanted](#help-wanted-macos--windows-verification)). Firefox is not supported (it doesn't speak CDP).
|
|
32
|
+
|
|
33
|
+
## How it differs from `chrome-devtools-mcp`
|
|
34
|
+
|
|
35
|
+
Google's [`chrome-devtools-mcp`](https://github.com/ChromeDevTools/chrome-devtools-mcp) gives an AI Chrome DevTools Protocol access (DOM, console, network, screenshots). That covers a lot.
|
|
36
|
+
|
|
37
|
+
`pwa-debug-layer` is **complementary** — it targets the things CDP can't reach:
|
|
38
|
+
|
|
39
|
+
- **Your real, logged-in browser.** `chrome-devtools-mcp` spawns a fresh automated Chrome — which shows "controlled by automated test software," blocks extension loading, and has none of your auth/session state, so authenticated apps are hard to debug ([the extensions/auth gap](https://medium.com/@vsanse24/no-extensions-allowed-the-chrome-devtools-mcp-dilemma-d58204aaab1f), [#265](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/265)). pwa-debug-layer's default `existing` mode attaches to **your normal profile**, with its real cookies, extensions, and service-worker state — exactly the real-profile SW/extension visibility people keep asking Google for ([#1173](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1173), [#96](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/96)).
|
|
40
|
+
- **Framework state.** React fiber trees, Vue reactive state, Svelte component graphs, Solid signals — read via the framework's own devtools hooks (`__REACT_DEVTOOLS_GLOBAL_HOOK__`, `__vue_app__`, `_vnode`, etc.). CDP can't see these.
|
|
41
|
+
- **Store state.** Redux / Zustand / Pinia / Jotai — read, subscribe, and dispatch.
|
|
42
|
+
- **Service-worker, cache & installability state.** SW lifecycle + versions, CacheStorage contents + age, manifest installability gaps, IndexedDB/web storage, and an update-propagation / version-skew analyzer — the highest-volume PWA pain (stale cache, "SW won't update," install failures, "why are some users on old code") that DevTools makes you piece together by hand.
|
|
43
|
+
- **Shadow DOM, iframes, dynamically-injected library widgets.** WalletConnect modals, third-party SDK popups, and other widgets that escape standard DOM tooling.
|
|
44
|
+
- **Page-world reach in general.** A MAIN-world script we inject reaches things isolated-world content scripts can't, and reaches them earlier than `initScript`-on-next-nav.
|
|
45
|
+
- **Persistent ring buffers + rrweb-style replay** across navigations and reloads.
|
|
46
|
+
- **Configurable filters** so the AI receives only the slice it asked for — no full-DOM noise.
|
|
47
|
+
|
|
48
|
+
The two are designed to coexist: install both, the AI uses each for what it does best, with zero tool-surface duplication.
|
|
49
|
+
|
|
50
|
+
## Architecture
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
┌──────────────────┐ MCP (stdio) ┌──────────────────────────┐
|
|
54
|
+
│ Claude Code │ ◄───────────► │ Native Messaging Host │
|
|
55
|
+
│ (or any MCP │ │ - MCP server │
|
|
56
|
+
│ client) │ │ - Ring buffers │
|
|
57
|
+
└──────────────────┘ │ - Replay/snapshot store │
|
|
58
|
+
└────────────┬─────────────┘
|
|
59
|
+
│ Native Messaging
|
|
60
|
+
│ (JSON over stdio)
|
|
61
|
+
▼
|
|
62
|
+
┌──────────────────────────┐
|
|
63
|
+
│ Extension Service Worker│
|
|
64
|
+
│ - chrome.debugger (CDP) │
|
|
65
|
+
│ - Tab/router │
|
|
66
|
+
└────────────┬─────────────┘
|
|
67
|
+
│
|
|
68
|
+
┌────────────────────────┼────────────────────────┐
|
|
69
|
+
▼ ▼ ▼
|
|
70
|
+
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
|
|
71
|
+
│ Content Script │ │ Page-World Script │ │ DevTools Panel │
|
|
72
|
+
│ (isolated world) │ │ (MAIN world) │ │ (planned) │
|
|
73
|
+
│ - DOM observe │ │ - React/Vue hooks │ │ - Human inspector │
|
|
74
|
+
│ - Action exec │ │ - fetch/XHR patch │ │ of AI session │
|
|
75
|
+
│ - Bridge to SW │ │ - Bus/RxJS taps │ │ │
|
|
76
|
+
└────────────────────┘ └────────────────────┘ └────────────────────┘
|
|
77
|
+
└────────── live page (the PWA being debugged) ─────────┘
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Three components, one installable unit:
|
|
81
|
+
|
|
82
|
+
- **Extension** owns the page (DOM, content scripts, page-world hooks).
|
|
83
|
+
- **Native host** owns persistence and the MCP server (long-lived, can hold buffers, can write files).
|
|
84
|
+
- **MCP** owns the AI contract.
|
|
85
|
+
|
|
86
|
+
Each does what only it can. See [`docs/PLAN.md`](docs/PLAN.md) for the full design.
|
|
87
|
+
|
|
88
|
+
## Browser support
|
|
89
|
+
|
|
90
|
+
**Chromium-family only**, sideloaded. Tested against:
|
|
91
|
+
|
|
92
|
+
- Chromium (native package)
|
|
93
|
+
- Google Chrome (`.deb` / `.rpm`)
|
|
94
|
+
- Brave Browser
|
|
95
|
+
- Microsoft Edge (Linux `.deb`)
|
|
96
|
+
- Vivaldi
|
|
97
|
+
- Opera
|
|
98
|
+
|
|
99
|
+
macOS Application Support paths and Windows HKCU-registry registration are implemented and have unit-test coverage; the manual round-trip retest currently runs on Linux.
|
|
100
|
+
|
|
101
|
+
### Snap browsers are not supported
|
|
102
|
+
|
|
103
|
+
If you installed your browser via **snap** (e.g. `snap install chromium` on Ubuntu), it will not work with `pwa-debug-layer`.
|
|
104
|
+
|
|
105
|
+
**Why:** snap's `home` interface allows the browser to *read* files in `$HOME` but blocks *exec* of any binary whose resolved path crosses a hidden directory (`~/.nvm/...`, `~/.config/...`). The native messaging host launcher and the node binary it invokes both live under hidden paths in a normal install, so spawn fails with `Permission denied` and the service worker reports `Native host has exited.` There is no fix on the extension/host side that doesn't require copying ~125 MB of node into a non-hidden install dir per registration; not worth the install bloat for a setup most distros let you avoid.
|
|
106
|
+
|
|
107
|
+
**What to do:** install your Chromium-family browser from a native package source instead:
|
|
108
|
+
|
|
109
|
+
- **Ubuntu/Debian:** `apt install chromium` from the universe repo if you've enabled the non-snap source, or `apt install brave-browser` / `microsoft-edge-stable` from their respective `.deb` repos. The Chromium tarball from chromium.org also works.
|
|
110
|
+
- **Fedora:** `dnf install chromium` is non-snap by default.
|
|
111
|
+
- **Arch:** `pacman -S chromium`.
|
|
112
|
+
|
|
113
|
+
Flatpak browsers are detected and have a manifest written, but flatpak confinement may also block exec — if it fails, run `flatpak override --user --filesystem=host <app-id>` and retry.
|
|
114
|
+
|
|
115
|
+
## Installation
|
|
116
|
+
|
|
117
|
+
### Prerequisites
|
|
118
|
+
|
|
119
|
+
- Node.js ≥ 20.19 (developed on 23.x)
|
|
120
|
+
- pnpm
|
|
121
|
+
- A Chromium-family browser **not installed via snap** (see above)
|
|
122
|
+
- An MCP-aware client (e.g. [Claude Code](https://docs.claude.com/en/docs/claude-code))
|
|
123
|
+
|
|
124
|
+
### 1. Build the host and extension
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
git clone https://github.com/<your-fork>/pwa-debug-layer
|
|
128
|
+
cd pwa-debug-layer
|
|
129
|
+
pnpm install
|
|
130
|
+
pnpm build # builds packages/host/dist/main.js and packages/extension/dist/
|
|
131
|
+
pnpm test # full workspace unit suite (shared + host + extension)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 2. Add the host to your MCP client
|
|
135
|
+
|
|
136
|
+
For Claude Code, add to your `.mcp.json` (project-scoped) or `~/.claude/mcp.json` (global):
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"mcpServers": {
|
|
141
|
+
"pwa-debug": {
|
|
142
|
+
"type": "stdio",
|
|
143
|
+
"command": "node",
|
|
144
|
+
"args": ["/absolute/path/to/pwa-debug-layer/packages/host/dist/main.js"]
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Restart Claude Code so it picks up the server.
|
|
151
|
+
|
|
152
|
+
### 3. Load the extension
|
|
153
|
+
|
|
154
|
+
1. Open `chrome://extensions` (or `brave://extensions`, etc.) in your browser.
|
|
155
|
+
2. Toggle **Developer mode** on.
|
|
156
|
+
3. Click **Load unpacked** and select `packages/extension/dist/`.
|
|
157
|
+
4. Note the extension's ID (shown on the card). Or, ask Claude to discover it for you in the next step — the extension service worker logs `[pwa-debug/sw] id=<id>` on every boot.
|
|
158
|
+
|
|
159
|
+
### 4. Tell Claude to set it up
|
|
160
|
+
|
|
161
|
+
The host registration is **AI-driven**. Six MCP tools are exposed for setup; Claude calls them via a guided flow:
|
|
162
|
+
|
|
163
|
+
> **Set up pwa-debug. The extension ID is `<your-id>`** *(or omit the ID and Claude can fetch it from the SW console if you also have `chrome-devtools-mcp` installed.)*
|
|
164
|
+
|
|
165
|
+
Claude will:
|
|
166
|
+
|
|
167
|
+
1. Call `host_status` to see what's already registered.
|
|
168
|
+
2. Call `host_register_extension(id)` — this writes a per-browser native-messaging manifest into every detected install (Chromium-family native, macOS Application Support, Windows HKCU registry), and drops a launcher script with an absolute node path (so the host spawns under sandboxed PATH environments).
|
|
169
|
+
3. Tell you to reload the extension at `chrome://extensions`.
|
|
170
|
+
4. After reload, call `host_status` again to confirm the manifest is on disk and the SW is connecting.
|
|
171
|
+
|
|
172
|
+
When the round-trip works you'll see in the SW console (`Inspect views: service worker` on the extension card):
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
[pwa-debug/sw] connected to host
|
|
176
|
+
[pwa-debug/sw] pong …
|
|
177
|
+
[pwa-debug/sw] hello … (5s after connect — host-pushed message proving bidirectional flow)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Launching a browser + `chrome-devtools-mcp` coexistence
|
|
181
|
+
|
|
182
|
+
`pwa-debug` and `chrome-devtools-mcp` are **two separate MCP servers** that share one browser. `pwa-debug` launches (or attaches to) a Chromium browser with a live remote-debugging port; `chrome-devtools-mcp` attaches to that same port over CDP. No proxying, no version coupling.
|
|
183
|
+
|
|
184
|
+
Register both with your client. For Claude Code:
|
|
185
|
+
|
|
186
|
+
```sh
|
|
187
|
+
# pwa-debug (this project) — adjust the path to your checkout
|
|
188
|
+
claude mcp add pwa-debug --scope user -- node /absolute/path/to/pwa-debug-layer/packages/host/dist/main.js
|
|
189
|
+
|
|
190
|
+
# chrome-devtools-mcp (optional but recommended) — runs via npx, no global install
|
|
191
|
+
# The --browserUrl port MUST match the port pwa-debug launches on (launch.defaultPort, default 9222).
|
|
192
|
+
claude mcp add chrome-devtools --scope user -- npx -y chrome-devtools-mcp@latest --browserUrl http://127.0.0.1:9222
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Or install `pwa-debug` as a Claude Code plugin
|
|
196
|
+
|
|
197
|
+
The repo ships a `.claude-plugin/` manifest whose MCP server runs the **published npm package** (`npx -y @aryanduntley/pwa-debug@latest`), so the plugin installs with **no clone and no build** — and picks up updates with **`/reload-plugins`**, no full restart:
|
|
198
|
+
|
|
199
|
+
```sh
|
|
200
|
+
# Add the marketplace straight from GitHub (no checkout needed)
|
|
201
|
+
/plugin marketplace add aryanduntley/pwa-debug-layer
|
|
202
|
+
# Install + enable the pwa-debug plugin
|
|
203
|
+
/plugin install pwa-debug@pwa-debug
|
|
204
|
+
# Bring the MCP server up with no restart:
|
|
205
|
+
/reload-plugins
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
> **No build needed.** The plugin's MCP entry is `npx -y @aryanduntley/pwa-debug@latest`, which fetches the prebuilt host (and its bundled extension) from npm. *Working on a local clone instead?* Skip the plugin and register your own build directly: `claude mcp add pwa-debug --scope user -- node /absolute/path/to/pwa-debug-layer/packages/host/dist/main.js`.
|
|
209
|
+
>
|
|
210
|
+
> **`chrome-devtools-mcp` is still separate.** The plugin declares **only** the `pwa-debug` host — `chrome-devtools-mcp` stays the optional `claude mcp add chrome-devtools …` above (no version coupling, no owning its launch). The bundled **`chrome-devtools-coexistence`** skill walks you through registering it; with a plugin install, its "make the tools appear" step is `/reload-plugins`.
|
|
211
|
+
|
|
212
|
+
> **Port must match.** `chrome-devtools-mcp`'s `--browserUrl` has to point at the exact port `pwa-debug` opens — the `launch.defaultPort` setting (default `9222`), or the active port from a current `pdl_launch_browser`. Rather than hand-write this, let Claude call **`pdl_register_chrome_devtools`**, which runs the `claude mcp add` above for you pinned to the right port (and **`pdl_check_setup`** flags a registration that is *unpinned* — no `--browserUrl`, so it spawns its own isolated browser — or pointed at the wrong port).
|
|
213
|
+
|
|
214
|
+
> **Mind the (re)connect.** A registration added or changed via `claude mcp add` only takes effect when the server (re)connects. Fastest path: open **`/mcp`** and **reconnect** `chrome-devtools` — this reloads it from the current registration (verified to pick up a changed `--browserUrl`) with **no full restart and no context loss**. If the client won't load it that way, **fully restart** Claude Code as a fallback. If instead you install `chrome-devtools-mcp` as a **plugin**, run **`/reload-plugins`**. The bundled **`chrome-devtools-coexistence`** skill walks Claude through all paths and, for the full-restart fallback, hands you a context note to paste back afterward.
|
|
215
|
+
|
|
216
|
+
> The host has no `install`/`serve` subcommand — `dist/main.js` auto-detects its mode: launched by Chrome (argv starts with `chrome-extension://`) it runs as the native-messaging host; launched by your MCP client it runs as the MCP server.
|
|
217
|
+
|
|
218
|
+
Then let Claude drive setup and launch:
|
|
219
|
+
|
|
220
|
+
1. **`pdl_check_setup`** — reports `{ ok, gaps[], recommendations[] }`: whether `chrome-devtools-mcp` is **registered** (read from the `claude` CLI) **and pinned with a `--browserUrl`** at the right debug port — it flags both an *unpinned* registration (which would spawn its own isolated browser instead of attaching to yours) and one pointed at the wrong port; the host manifest is installed (including **per active sandbox profile**); the extension dist is present; and an extension ID is registered. Follow its `next_steps` to close any gap.
|
|
221
|
+
2. **`pdl_register_chrome_devtools`** — writes the `chrome-devtools-mcp` registration for you, pinned to the active/`launch.defaultPort` port (idempotent; re-points it if it's unpinned or on the wrong port). *(Mutates your MCP config — Claude will ask first; a restart/reconnect follows, see above.)*
|
|
222
|
+
3. **`pdl_install_extension`** — copies the extension to `~/Downloads/pwa-debug-extension` (or a `target` you pass) with `chrome://extensions` "Load unpacked" instructions. *(On most browsers a sandbox mode preloads the extension so you can skip this; on **branded Google Chrome 142+** preload is impossible — this is the manual install the sandbox launch will point you to.)*
|
|
223
|
+
4. **`pdl_launch_browser`** — launches/attaches a browser with the debug port live and returns the `browserUrl` to hand to `chrome-devtools-mcp`. **Always launch first:** call this *before* any `chrome-devtools-mcp` tool, so the browser + debug port exist for it to attach to. Follow its `next_steps` — they carry the brand/version-specific guidance (preloaded vs. manual *Load unpacked*, or the modern-Chromium port caveat).
|
|
224
|
+
5. **`pdl_browser_status`** — shows what's been launched (browser, profile mode, port, pid), re-probes each debug port for liveness, and reports the extension service-worker heartbeat.
|
|
225
|
+
|
|
226
|
+
**The validated one-profile recipe** (what these tools converge on, verified live on Brave 148):
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
pdl_launch_browser({ browser: "brave", mode: "sandbox-persistent" })
|
|
230
|
+
→ dedicated profile at ~/.pwa-debug/profiles/brave with:
|
|
231
|
+
• the native-messaging manifest auto-written into the profile (so the extension connects), and
|
|
232
|
+
• the pwa-debug extension preloaded via --load-extension (Brave honors it), and
|
|
233
|
+
• --remote-debugging-port live (custom profile dir, so Chromium 136+ opens it).
|
|
234
|
+
pdl_register_chrome_devtools() → pins chrome-devtools-mcp at that port
|
|
235
|
+
restart / reconnect chrome-devtools-mcp → it attaches to the SAME browser
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Now `chrome-devtools-mcp` (CDP) and pwa-debug (extension → page-world) drive the same tab simultaneously — independent, non-contending channels (the extension uses page-world injection, **not** `chrome.debugger`, so there's no CDP-attacher contention).
|
|
239
|
+
|
|
240
|
+
## Profile modes
|
|
241
|
+
|
|
242
|
+
`pdl_launch_browser` takes `mode` (default `existing`), `browser` (defaults to your system-default Chromium browser), and `port` (default `9222`).
|
|
243
|
+
|
|
244
|
+
| Mode | Profile | When to use |
|
|
245
|
+
|---|---|---|
|
|
246
|
+
| **`existing`** *(default)* | Your normal browser profile | Debugging your real browsing session **with pwa-debug** (your real cookies, extensions, SW/cache state). Degrades gracefully: **(a)** debug port already live → attaches; **(b)** browser running *without* a debug port → opens a new window in the existing session (your extension tools work, `chrome-devtools-mcp` does not); **(c)** browser not running → spawns fresh with your profile. **Modern-Chromium caveat (136+):** Chromium refuses `--remote-debugging-port` on the **default** profile, so on a current browser `existing` mode gives you pwa-debug but **not** a CDP port — the launch reports this (`attached:false`, no false `browserUrl`) and steers you to `sandbox-persistent` for `chrome-devtools-mcp`. |
|
|
247
|
+
| **`sandbox-persistent`** | `~/.pwa-debug/profiles/<browser>/` (persists across restarts) | The **canonical both-tools profile** — a dedicated profile beside your main browser, with its own `--user-data-dir` (so the debug port works on Chromium 136+). The launcher auto-writes the native-messaging manifest into the profile and, on most browsers, **preloads** the pwa-debug extension via `--load-extension`. **Branded-Google-Chrome 142+ caveat:** Chrome removed `--load-extension`, so there the launch brings up the **debug port** (for `chrome-devtools-mcp`) but **not** the extension — it returns a one-time manual *Load unpacked* walkthrough (persists in this profile), or steers you to a non-Google Chromium where preload just works. |
|
|
248
|
+
| **`sandbox-temp`** | a fresh `mktemp` dir (removed on host shutdown) | One-off / CI / clean-state runs. Same as `sandbox-persistent`, but throwaway — so the Chrome-142+ manual-load step won't persist usefully here; prefer a non-Google Chromium for temp runs that need the extension. |
|
|
249
|
+
|
|
250
|
+
**Extension preload depends on the browser brand + version** (the launcher detects it from `--version` and adapts):
|
|
251
|
+
|
|
252
|
+
| Browser | `--load-extension` (sandbox preload) |
|
|
253
|
+
|---|---|
|
|
254
|
+
| Brave, Chromium, Edge, Opera, Vivaldi, Chrome for Testing | ✅ works on current versions |
|
|
255
|
+
| Google Chrome ≤ 136 | ✅ works |
|
|
256
|
+
| Google Chrome 137–141 | ✅ works — launcher adds `--disable-features=DisableLoadExtensionCommandLineSwitch` |
|
|
257
|
+
| **Google Chrome ≥ 142** | ❌ removed — launcher omits the dead flag and guides a one-time manual *Load unpacked* (or use Brave/Chromium) |
|
|
258
|
+
|
|
259
|
+
**Recommended coexistence setup:** `sandbox-persistent` on a **non-Google Chromium** (e.g. Brave or Chromium). That single profile gets the extension preloaded **and** a live debug port, so pwa-debug and `chrome-devtools-mcp` drive the same browser with zero manual steps.
|
|
260
|
+
|
|
261
|
+
## Browser support matrix
|
|
262
|
+
|
|
263
|
+
Chromium-family only (Firefox doesn't speak CDP). Linux is first-class. macOS/Windows binary detection, profile/user-data-dir paths, **and system-default detection** (macOS LaunchServices, Windows `UserChoice` registry) are all implemented with unit coverage, but **live verification on real macOS/Windows machines is still needed — see [Help wanted](#help-wanted-macos--windows-verification).**
|
|
264
|
+
|
|
265
|
+
| Browser | PATH names probed | Standard Linux binary | Linux profile dir (`existing` mode) |
|
|
266
|
+
|---|---|---|---|
|
|
267
|
+
| Chrome | `google-chrome`, `google-chrome-stable` | `/opt/google/chrome/chrome`, `/usr/bin/google-chrome*` | `~/.config/google-chrome` |
|
|
268
|
+
| Chromium | `chromium`, `chromium-browser` | `/usr/bin/chromium*`, `/snap/bin/chromium` | `~/.config/chromium` |
|
|
269
|
+
| Edge | `microsoft-edge`, `microsoft-edge-stable` | `/opt/microsoft/msedge/msedge` | `~/.config/microsoft-edge` |
|
|
270
|
+
| Brave | `brave-browser`, `brave` | `/opt/brave.com/brave/brave-browser` | `~/.config/BraveSoftware/Brave-Browser` |
|
|
271
|
+
| Vivaldi | `vivaldi`, `vivaldi-stable` | `/opt/vivaldi/vivaldi` | `~/.config/vivaldi` |
|
|
272
|
+
| Opera | `opera` | `/usr/bin/opera`, `/opt/opera/opera` | `~/.config/opera` |
|
|
273
|
+
|
|
274
|
+
- **System default:** the launcher prefers your system-default browser when you don't pass one — Linux via `xdg-settings get default-web-browser`, macOS via LaunchServices (`defaults read … LSHandlers`), Windows via the HKCU `UrlAssociations\http\UserChoice` ProgId. The macOS/Windows paths are implemented + unit-tested but not yet exercised on a real machine.
|
|
275
|
+
- **Default debug port** is `9222` (the `chrome-devtools-mcp` convention); override it without passing `port` each time via the `launch.defaultPort` setting (`settings.set`).
|
|
276
|
+
- **Snap profiles:** when launching a snap-packaged browser (`/snap/bin/…`) in `existing` mode, the launcher now resolves its confined profile (`~/snap/<snap>/common/<cfg>`) instead of `~/.config` — but note snap browsers still can't run the native-messaging host (see snap section), so this only matters if/when that confinement is lifted.
|
|
277
|
+
- **Brave Shields** can block the content script on a site — set Shields **Down** for the site if `session_ping` reports `page_blocks_scripts`.
|
|
278
|
+
- **Snap browsers are unsupported** for the native-messaging host (see below); the launcher can still spawn them, but the host round-trip won't connect. Use a native-package browser.
|
|
279
|
+
- **Flatpak** installs get a manifest written, but confinement may block exec — run `flatpak override --user --filesystem=host <app-id>` and retry.
|
|
280
|
+
|
|
281
|
+
## Help wanted: macOS / Windows verification
|
|
282
|
+
|
|
283
|
+
Development happens on Linux, so the macOS and Windows code paths are **written and unit-tested with injected fakes, but never run on a real machine.** If you're on macOS or Windows, trying these and reporting back (open an issue with the output) is the single most useful contribution right now:
|
|
284
|
+
|
|
285
|
+
**macOS**
|
|
286
|
+
- `pdl_check_setup` / `pdl_install_extension` — does the extension resolve and copy, and do the `chrome://extensions` instructions work?
|
|
287
|
+
- Browser binary detection under `/Applications/*.app/Contents/MacOS/…`.
|
|
288
|
+
- System-default detection: `defaults read com.apple.LaunchServices/com.apple.launchservices.secure LSHandlers` — does the parser pick the right browser? (Paste the raw output if it doesn't.)
|
|
289
|
+
- `pdl_launch_browser` mode `existing` (profile under `~/Library/Application Support/…`) and both sandbox modes.
|
|
290
|
+
|
|
291
|
+
**Windows**
|
|
292
|
+
- Browser detection under `%PROGRAMFILES%` / `%LOCALAPPDATA%`.
|
|
293
|
+
- System-default detection: `reg query "HKCU\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice" /v ProgId` — does the ProgId map to the right browser?
|
|
294
|
+
- `pdl_launch_browser` (profile under `%LOCALAPPDATA%\…\User Data`) and the HKCU native-messaging registration.
|
|
295
|
+
|
|
296
|
+
**Any OS**
|
|
297
|
+
- `pdl_browser_status` after restarting the host — launches now persist to `launches.json`, so previously-launched browsers should still be listed (with a fresh liveness re-probe). Confirm the list survives a restart and that closed browsers show as not-live.
|
|
298
|
+
|
|
299
|
+
The launcher never kills your running browser and sandbox modes use throwaway/dedicated profiles, so this is low-risk to try.
|
|
300
|
+
|
|
301
|
+
## Troubleshooting
|
|
302
|
+
|
|
303
|
+
### Verification sequence
|
|
304
|
+
|
|
305
|
+
When something isn't working, walk this ladder — each step localizes the failure:
|
|
306
|
+
|
|
307
|
+
1. **`pdl_check_setup`** — are all setup gaps closed? (CDP reachable, manifest installed, extension present, ID registered.)
|
|
308
|
+
2. **`pdl_browser_status`** — is a browser launched and is its debug port still live? Is the extension service worker connected (recent heartbeat)?
|
|
309
|
+
3. **`host_status`** — is the native-messaging host registered and is an NMH instance connected?
|
|
310
|
+
4. **`session_ping`** — does a full MCP → SW → page-world round-trip succeed on the active tab? (See the typed `pageWorldError` table below.)
|
|
311
|
+
|
|
312
|
+
### Common launcher gotchas
|
|
313
|
+
|
|
314
|
+
- **"I launched in `existing` mode but `chrome-devtools-mcp` can't attach."** Two causes. **(1)** Chrome opens `--remote-debugging-port` only at process start — if the browser was already running without it, `pdl_launch_browser` opens a new window (sub-state **b**) but can't add the port to the live process (`attached:false`). **(2)** On **Chromium 136+**, the port is refused on the *default* profile entirely, even on a fresh start. Either way: use `mode: sandbox-persistent` (a dedicated profile where the port works) for `chrome-devtools-mcp`.
|
|
315
|
+
- **Brave/Chrome says "Opening in existing browser session."** That's sub-state **b** — the binary handed your request to the already-running process instead of starting a fresh one with the port. Same fix as above.
|
|
316
|
+
- **Sandbox launch came up but pwa-debug never connects (Google Chrome 142+).** Branded Google Chrome 142+ permanently ignores `--load-extension`, so the sandbox can't auto-preload the extension — the launch says so and gives you a one-time `chrome://extensions` → Developer mode → *Load unpacked* walkthrough (it persists in that dedicated profile). Or relaunch with `browser: "brave"` / `"chromium"`, where preload works automatically. (`chrome-devtools-mcp` still works either way — the debug port is live.)
|
|
317
|
+
- **`chrome-devtools-mcp` opened its own blank browser instead of using yours.** Its registration is **unpinned** (no `--browserUrl`). Run `pdl_register_chrome_devtools` (or re-add with `--browserUrl http://127.0.0.1:<port>`) and restart/reconnect it; `pdl_check_setup` flags this.
|
|
318
|
+
- **Added the MCP server but the tools don't appear.** `.mcp.json` / client MCP config is read at startup — restart your MCP client (or `/mcp`-reconnect that server) after adding `pwa-debug` or `chrome-devtools`.
|
|
319
|
+
- **Tools worked, then stopped after I reloaded the extension.** Reloading the extension at `chrome://extensions` detaches content scripts from already-open tabs. Hard-refresh the page tab (Ctrl+Shift+R); the SW also auto-reinjects on the next `session_ping` (look for `pageWorldSelfHealed: true`). Sandbox modes avoid this entirely (extension preloaded before tabs open).
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
### `session_ping` returns `pageWorld: null` with a typed `pageWorldError`
|
|
323
|
+
|
|
324
|
+
`session_ping` reports failure modes as **typed codes** in `pageWorldError` (machine-readable) plus the original chrome-runtime string in `pageWorldErrorMessage` (for logs). The MCP `next_steps[]` field carries imperative, code-specific guidance — AI clients should relay it verbatim. Tabs that simply predated the extension reload (the most common dev-loop friction) are auto-recovered by the SW via `chrome.scripting.executeScript`; when that succeeds, `pageWorld` is populated and `pageWorldSelfHealed: true` appears alongside it. The table below is the canonical mapping (single source of truth: `NEXT_STEPS_BY_CODE` in `packages/host/src/mcp/tools/session_ping.ts`).
|
|
325
|
+
|
|
326
|
+
| `pageWorldError` | What it means | What to do |
|
|
327
|
+
|---|---|---|
|
|
328
|
+
| *(absent)* with `pageWorldSelfHealed: true` | The static content script was missing on the active tab; the SW silently re-injected `content-script.js` + `page-world.js` and retried. No action needed. | Informational only. |
|
|
329
|
+
| `cs_not_attached_refresh_tab` | Auto-recovery was attempted but did not stick (page rejected the injection or reloaded mid-flight). | Hard-refresh the page tab (Ctrl+Shift+R) and retry. If it repeats, reload the extension at `chrome://extensions` then hard-refresh. |
|
|
330
|
+
| `page_blocks_scripts` | A content blocker is rejecting the script (Brave Shields, uBlock Origin, AdGuard, or similar). Site CSP is also possible. | **Brave:** click the lion icon → set Shields **Down** for the site → refresh → retry. **uBlock Origin / similar:** disable for this site → refresh → retry. If neither, the site's own CSP is blocking and pwa-debug cannot bypass it. |
|
|
331
|
+
| `page_world_blocked` | The content script attached but the MAIN-world page-world bridge cannot be reached — the site's Content-Security-Policy blocks the inline script tag. | Site-level restriction; cannot bypass. Console + network capture may still work via the content-script side, but live page-world reads (state, evaluate) will not. |
|
|
332
|
+
| `restricted_url` | The active tab is on a URL browsers do not allow extensions to touch (`chrome://`, `chromewebstore.google.com`, `about:`, `devtools://`, `file://`, `view-source:`, etc.). | Switch focus to a regular `http(s)` tab of the PWA, then retry. |
|
|
333
|
+
| `no_active_tab` | No active `http(s)` tab is focused (DevTools window or extension popup may be focused instead). | Focus a regular browser tab and retry. |
|
|
334
|
+
| `cs_inject_failed` | The auto-recovery `chrome.scripting.executeScript` itself failed. The extension cannot reach this tab. | Reload the extension at `chrome://extensions` and hard-refresh the page (Ctrl+Shift+R). If it persists, the URL may be one the browser blocks all extensions from — check the address bar. |
|
|
335
|
+
|
|
336
|
+
To confirm the content script attached after a successful round-trip, open the page tab's DevTools (F12 on the page itself, **not** the SW console) and look for `[pwa-debug/cs] attached at <url>` in the Console.
|
|
337
|
+
|
|
338
|
+
## MCP tool surface
|
|
339
|
+
|
|
340
|
+
Every tool returns a structured response of the form `{ ok, data, error?, next_steps[] }`. The `next_steps` array encodes the rules of engagement for the AI — what to call next based on the actual response shape — mirroring the AIMFP `return_statements` pattern. The canonical list lives in `packages/host/src/mcp/tools/index.ts`.
|
|
341
|
+
|
|
342
|
+
### Host management & setup
|
|
343
|
+
|
|
344
|
+
| Tool | Purpose |
|
|
345
|
+
|---|---|
|
|
346
|
+
| `host_status` | Install/liveness state: registered IDs, manifest paths, launcher path, active connections. Cheap, idempotent. **Always call first.** |
|
|
347
|
+
| `host_register_extension(id)` / `host_unregister_extension(id)` | Add/remove an extension ID across per-browser manifests + launcher script. Idempotent. |
|
|
348
|
+
| `host_list_registrations` / `host_reset` | Read registered IDs; destructive cleanup to re-bootstrap. |
|
|
349
|
+
| `session_ping` | Full MCP → IPC → NMH → SW → page-world round-trip with typed `pageWorldError` codes + self-heal. |
|
|
350
|
+
| `pdl_check_setup` | Diagnose setup → `{ ok, gaps[], recommendations[] }` (CDP reachable, manifest installed, extension present, ID registered). |
|
|
351
|
+
| `pdl_install_extension({ target? })` | Copy the extension to a folder for unpacked install. |
|
|
352
|
+
|
|
353
|
+
### Browser launcher
|
|
354
|
+
|
|
355
|
+
| Tool | Purpose |
|
|
356
|
+
|---|---|
|
|
357
|
+
| `pdl_launch_browser({ browser?, port?, mode? })` | Launch/attach a Chromium browser with a live debug port. `mode`: `existing` (default), `sandbox-persistent`, `sandbox-temp`. Returns `browserUrl` for `chrome-devtools-mcp`. |
|
|
358
|
+
| `pdl_browser_status` | Managed launches (browser, profile mode, port, pid) with live debug-port re-probe + extension SW heartbeat. |
|
|
359
|
+
|
|
360
|
+
### Capture, evaluate, replay
|
|
361
|
+
|
|
362
|
+
| Tool | Purpose |
|
|
363
|
+
|---|---|
|
|
364
|
+
| `console_tail` / `network_tail` / `error_tail` | Cursor-paginated, filterable tails of the persistent capture ring buffers (memory + disk spill). |
|
|
365
|
+
| `recent_events` | Recent captured events across kinds for quick verification. |
|
|
366
|
+
| `evaluate` | Evaluate an expression in the page world. |
|
|
367
|
+
| `session_record` / `session_replay` | rrweb session recording + cursor-paginated replay. |
|
|
368
|
+
| `source_map_resolve` | Resolve generated stack frames to original `src/…:line:col`. |
|
|
369
|
+
| `settings_list_schema` / `settings_get` / `settings_set` | Read the typed settings schema; get/set values (allowlist, capture filters, disk-spill, etc.). |
|
|
370
|
+
|
|
371
|
+
### PWA runtime diagnostics
|
|
372
|
+
|
|
373
|
+
The namesake suite — read the debugged PWA's service-worker, cache, installability, storage, and update state. All page-world reads against your **real profile**; CDP / `chrome-devtools-mcp` can't surface these.
|
|
374
|
+
|
|
375
|
+
| Tool | Purpose |
|
|
376
|
+
|---|---|
|
|
377
|
+
| `sw_status` | Service-worker registrations: installing/waiting/active versions, `updateViaCache`, controller, and whether an update is stuck **waiting** (the #1 "why isn't my update showing"). |
|
|
378
|
+
| `sw_lifecycle_tail` | Cursor-paginated stream of SW lifecycle events (updatefound / statechange / controllerchange). |
|
|
379
|
+
| `cache_list` / `cache_inspect` / `cache_match` | CacheStorage caches + per-entry `{ url, status, content-type, size, ageSeconds, cache-control }`, and which cache serves a given URL — the core of stale-cache debugging. |
|
|
380
|
+
| `pwa_status` | Display mode / standalone, controller, permissions, and a live capability matrix (Push / Background Sync / Periodic Sync / Badging / File System Access / Window Controls Overlay). |
|
|
381
|
+
| `pwa_installability` | Discover + parse the manifest and run installability checks → structured `{ supported, gaps[], fixes[] }` with per-gap remediation. |
|
|
382
|
+
| `storage_get` | localStorage / sessionStorage snapshot (capped). |
|
|
383
|
+
| `idb_list` / `idb_query` | IndexedDB databases + object-store schema, then a read-only capped slice of records — *inspect IndexedDB live*. |
|
|
384
|
+
| `pwa_update_analyze` | Correlates SW status + cache ages + recent 404s into a verdict: waiting-update-on-active-client, cached-HTML-older-than-JS version skew, chunk 404s — *why are some users on old code?* |
|
|
385
|
+
| `pwa_snapshot` | One capped runtime-state blob (SW + store + web storage + IndexedDB + cache names) for deterministic bug-repro / hand-off. |
|
|
386
|
+
|
|
387
|
+
### Framework introspection
|
|
388
|
+
|
|
389
|
+
Read via each framework's own model — things CDP can't see. Tree/state where the framework persists it; element-level find everywhere.
|
|
390
|
+
|
|
391
|
+
| Tool family | Purpose |
|
|
392
|
+
|---|---|
|
|
393
|
+
| `react_tree` / `react_get_state` / `react_find_by_text` / `react_find_by_role` | React fiber-tree introspection + props/state/hooks by stable id + component lookup. |
|
|
394
|
+
| `vue_tree` / `vue_get_state` / `vue_find_by_text` / `vue_find_by_role` | Vue 3 `ComponentInternalInstance` tree + reactive state + lookup (parity with React). |
|
|
395
|
+
| `svelte_components` / `svelte_find_by_text` / `svelte_find_by_role` | Svelte component discovery + `__svelte_meta` source locations + element lookup (no instance state — Svelte exposes none). |
|
|
396
|
+
| `solid_detect` / `solid_find_by_text` / `solid_find_by_role` | Solid detection + element-level find (no persisted tree/state without `@solid-devtools`). |
|
|
397
|
+
|
|
398
|
+
### Store introspection
|
|
399
|
+
|
|
400
|
+
| Tool family | Purpose |
|
|
401
|
+
|---|---|
|
|
402
|
+
| `redux_get_state` / `redux_subscribe` / `redux_tail` / `redux_dispatch` | Redux read, change-delta subscribe/tail, JSONPath-lite slice, (opt-in) dispatch. |
|
|
403
|
+
| `store_get_state` / `store_subscribe` / `store_tail` / `store_dispatch` | Framework-agnostic adapter covering **Zustand / Pinia / Jotai** through one contract (read / subscribe / dispatch by name). |
|
|
404
|
+
|
|
405
|
+
### Interaction & touch gestures
|
|
406
|
+
|
|
407
|
+
Framework-agnostic native-event sequences dispatched so React/Vue/etc. delegated synthetic-event systems fire. Each targets a unified locator (selector / role / text / framework stable-id).
|
|
408
|
+
|
|
409
|
+
| Tool | Purpose |
|
|
410
|
+
|---|---|
|
|
411
|
+
| `pdl_click` / `pdl_dblclick` / `pdl_hover` | Pointer interactions. |
|
|
412
|
+
| `pdl_fill` / `pdl_submit` / `pdl_select_option` / `pdl_uncheck` | Form interactions. |
|
|
413
|
+
| `pdl_focus` / `pdl_blur` / `pdl_key_press` / `pdl_type_sequence` | Focus + keyboard. |
|
|
414
|
+
| `pdl_drag` / `pdl_scroll` / `pdl_swipe` / `pdl_tap` / `pdl_double_tap` / `pdl_long_press` / `pdl_pinch` | Touch/gesture primitives (direction/distance/duration/steps model — no hand-built coordinates). |
|
|
415
|
+
|
|
416
|
+
### Library popups
|
|
417
|
+
|
|
418
|
+
| Tool | Purpose |
|
|
419
|
+
|---|---|
|
|
420
|
+
| `popup_tail` | Tail the library-popup event stream (WalletConnect / RainbowKit / SDK modals, incl. shadow-root + nested). |
|
|
421
|
+
| `popup_record` / `popup_replay` | Intent-driven recording of a popup's full primary+nested stream (immune to ring-buffer eviction) + flat/primary/tree replay. |
|
|
422
|
+
| `popup_failures` | Correlate a popup's auth/connect failure with the console errors + failed requests during its open window. |
|
|
423
|
+
|
|
424
|
+
## Roadmap
|
|
425
|
+
|
|
426
|
+
- **Foundation** ✅ — pnpm workspace + build pipeline; MV3 extension loads cleanly; native-messaging round-trip; AI-managed host registration; cross-platform install (Linux native + macOS + Windows registry; snap unsupported); MCP↔IPC↔NMH↔SW bridge.
|
|
427
|
+
- **Capture** ✅ — console / network (fetch/XHR/WebSocket) / DOM-mutation / lifecycle producers; host ring buffers with disk spill + archive pruning; filterable, cursor-paginated `console_tail` / `network_tail`.
|
|
428
|
+
- **Framework introspection** ✅ — **React, Vue, Svelte, Solid** (trees/state where the framework persists them, find-by-text/role everywhere); page-world `evaluate`.
|
|
429
|
+
- **Store introspection** ✅ — **Redux** (read/subscribe/tail/dispatch) plus a framework-agnostic adapter covering **Zustand, Pinia, Jotai**.
|
|
430
|
+
- **Interaction & gestures** ✅ — discrete actions (click/fill/submit/hover/focus/blur/select/key/type) + touch gestures (drag/scroll/swipe/tap/double-tap/long-press/pinch) over a unified locator.
|
|
431
|
+
- **Library popups** ✅ — `popup_record` / `popup_replay` / `popup_tail` / `popup_failures` for WalletConnect & SDK modals (incl. shadow-root + nested).
|
|
432
|
+
- **Replay & source maps** ✅ — rrweb `session_record` / `session_replay`; `source_map_resolve` for stack frames.
|
|
433
|
+
- **Settings** ✅ — typed schema store (allowlist/blocklist, per-kind capture filters, per-site read controls, disk-spill).
|
|
434
|
+
- **Browser launcher** ✅ — `pdl_launch_browser` (existing + sandbox-persistent + sandbox-temp), `pdl_check_setup`, `pdl_browser_status`, `pdl_close_browser`, `pdl_install_extension`, `pdl_register_chrome_devtools`, and `chrome-devtools-mcp` coexistence.
|
|
435
|
+
- **PWA Runtime Diagnostics** ✅ — the namesake suite, live-verified against a real PWA. Service-worker introspection (`sw_status` + `sw_lifecycle_tail`: installing/waiting/active versions, `updateViaCache`, skipWaiting/claim/controllerchange); CacheStorage inspection (`cache_list` / `cache_inspect` / `cache_match` with size/age + match-by-URL); `pwa_status` (display mode, controller, permissions, live capability matrix — Push/Background Sync/Periodic Sync/Badging/File System Access/Window Controls Overlay); installability diagnostics (`pwa_installability` → structured `{gaps[], fixes[]}`); IndexedDB/web-storage inspection (`idb_list` / `idb_query` / `storage_get`); update-propagation / version-skew analysis (`pwa_update_analyze`); and a one-shot runtime-state snapshot (`pwa_snapshot`). Closes the stale-cache / "SW won't update" / install-failure / version-skew pain cluster against your real profile.
|
|
436
|
+
- **Later** — DevTools panel for human observation of an AI session; multi-tab routing model; event-causality graph (click → action → request → SW → cache → re-render); production-safe diagnostic mode for real-user failure capture.
|
|
437
|
+
- **Deferred** — Firefox port (needs WebDriver BiDi, not CDP); macOS/Windows live verification ([help wanted](#help-wanted-macos--windows-verification)); mobile; hosted/team mode.
|
|
438
|
+
- **Intentionally not pursued** — **Chrome Web Store distribution.** The extension grants broad page access (DOM, framework state, stores, network) and is only meaningful alongside its MCP host. It ships **bundled with the MCP only** and is installed via a manual, dev-mode "Load unpacked" (`pdl_install_extension` hands you the path + steps) — so every user knows exactly what they're running and why. Disabling Chrome Developer mode auto-disables it.
|
|
439
|
+
|
|
440
|
+
## Code style
|
|
441
|
+
|
|
442
|
+
- FP-only: pure functions, immutability, no OOP, no classes-with-methods.
|
|
443
|
+
- Side effects (CDP calls, file I/O, native messaging, MCP transport) at the edges; core logic pure.
|
|
444
|
+
- OOP library interfaces (Chrome APIs, MCP SDK, `winreg`) wrapped in thin functional adapters with injection points for tests.
|
|
445
|
+
|
|
446
|
+
## Repo layout
|
|
447
|
+
|
|
448
|
+
```
|
|
449
|
+
pwa-debug-layer/
|
|
450
|
+
├── packages/
|
|
451
|
+
│ ├── host/ Native-messaging host + MCP server (Node, ESM, rollup-bundled)
|
|
452
|
+
│ ├── extension/ WebExtension (MV3) — service worker, content script, page-world
|
|
453
|
+
│ └── shared/ Cross-package types
|
|
454
|
+
├── docs/
|
|
455
|
+
│ ├── PLAN.md Full design doc (architecture, capability matrix, phased plan)
|
|
456
|
+
│ └── goals.txt
|
|
457
|
+
├── examples/ (future: test PWAs)
|
|
458
|
+
└── reference/ Read-only reference checkouts
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
## Contributing
|
|
462
|
+
|
|
463
|
+
This is a personal project under active redesign. PRs welcome but please open an issue first to discuss scope — the architecture is still settling. The FP / no-OOP discipline applies to all contributions; see `CLAUDE.md` for the full rules.
|
|
464
|
+
|
|
465
|
+
## License
|
|
466
|
+
|
|
467
|
+
MIT — see [`LICENSE`](LICENSE).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aryanduntley/pwa-debug",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -41,12 +41,14 @@
|
|
|
41
41
|
},
|
|
42
42
|
"author": "aryanduntley",
|
|
43
43
|
"bin": {
|
|
44
|
+
"pwa-debug": "./dist/main.js",
|
|
44
45
|
"pwa-debug-host": "./dist/main.js"
|
|
45
46
|
},
|
|
46
47
|
"main": "./dist/main.js",
|
|
47
48
|
"files": [
|
|
48
|
-
"dist",
|
|
49
|
-
"extension"
|
|
49
|
+
"dist/main.js",
|
|
50
|
+
"extension/*.js",
|
|
51
|
+
"extension/manifest.json"
|
|
50
52
|
],
|
|
51
53
|
"dependencies": {
|
|
52
54
|
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
@@ -61,8 +63,8 @@
|
|
|
61
63
|
"@types/winreg": "^1.2.36",
|
|
62
64
|
"rollup": "^4.27.4",
|
|
63
65
|
"tslib": "^2.8.1",
|
|
64
|
-
"@pwa-debug/extension": "0.1.
|
|
65
|
-
"@pwa-debug/shared": "0.1.
|
|
66
|
+
"@pwa-debug/extension": "0.1.4",
|
|
67
|
+
"@pwa-debug/shared": "0.1.4"
|
|
66
68
|
},
|
|
67
69
|
"scripts": {
|
|
68
70
|
"typecheck": "tsc --noEmit",
|