@extension.dev/mcp 4.9.0 → 5.1.1

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.
@@ -10,7 +10,7 @@
10
10
  "name": "extension-mcp",
11
11
  "source": "./",
12
12
  "description": "MCP tools for browser extension development: scaffold from 60+ templates, run the dev server with HMR, inspect the live DOM and logs, and publish store-ready builds for Chrome, Edge, and Firefox.",
13
- "version": "4.9.0",
13
+ "version": "5.1.1",
14
14
  "category": "development",
15
15
  "author": {
16
16
  "name": "Cezar Augusto"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "extension-mcp",
3
3
  "description": "MCP tools for browser extension development: scaffold from 60+ templates, run the dev server with HMR, inspect the live DOM and logs, and publish store-ready builds for Chrome, Edge, and Firefox. Ships /extension, /extension-add, /extension-debug, and /extension-publish commands.",
4
- "version": "4.9.0",
4
+ "version": "5.1.1",
5
5
  "author": {
6
6
  "name": "Cezar Augusto",
7
7
  "email": "boss@cezaraugusto.net",
package/CHANGELOG.md CHANGED
@@ -1,5 +1,155 @@
1
1
  # Changelog
2
2
 
3
+ ## 5.1.1
4
+
5
+ ### Added
6
+
7
+ - `extension_deploy` warns when a Firefox or Edge submission ships without
8
+ the STORE.md notes the platform submits automatically (Firefox reviewer
9
+ and release notes, Edge certification notes). The warnings ride along in
10
+ the result as `warnings` and never block the submission; Chrome-only
11
+ submissions stay silent.
12
+
13
+ ## 5.1.0
14
+
15
+ The engine closed its entire open bug range (Extension.js 61-73) in the
16
+ 4.0.14 canary line. This release re-aligns the MCP with the fixed engine,
17
+ finishes the MCP-side half of those bugs, and continues the
18
+ report-failure-not-false-success program that 5.0.0 started. 5.0.0 was never
19
+ published to npm; installing 5.1.0 picks up both.
20
+
21
+ ### Fixed
22
+
23
+ - **Sessions now genuinely survive the MCP process.** `detached: true` alone
24
+ never did it: the child held pipes to the MCP, so when the MCP exited the
25
+ next compile log line killed the dev server with EPIPE. Launch tools
26
+ (`extension_dev`/`start`/`preview`) now stream the child's output to a
27
+ session log file (returned as `logPath`) instead of pipes. A detached
28
+ session outlives the MCP and a fresh MCP process rediscovers it through
29
+ `ready.json` and can stop it. Pinned by a detach-contract test.
30
+ - **`extension_preview` no longer reports `launched` for a process that died
31
+ in seconds.** It health-checks the child like `dev`/`start` (the MCP half of
32
+ engine bug 72), and all three launch tools read the engine's new
33
+ `browser_exited` stamp, so a browser that dies after launch (for example a
34
+ rejected add-on) returns `status:"browser-exited"` instead of success.
35
+ - **`extension_doctor` names a dead browser.** A `browser_exited` ready
36
+ contract now produces a runtime-errors failure that says the browser died,
37
+ with the matching remedy, instead of the generic "fix the build error"
38
+ wording that pointed at a build that was fine.
39
+ - **`extension_create` verifies the scaffold.** A resolved create over a
40
+ partial tree (an interrupted template download) returned `nextSteps`
41
+ pointing at a project that could not compile. It now checks the manifest
42
+ exists and returns `status:"incomplete"` when it does not.
43
+ - **`extension_manifest_validate` is per-target honest.** `chromium:`/
44
+ `firefox:` prefixed keys resolve per target, `edge` joins the default
45
+ matrix, `manifest_version` must be 2 or 3, a `default_locale` without its
46
+ `_locales` catalog blocks, and a missing 128px store icon warns
47
+ (`extension_inspect` reports `has128Icon`).
48
+ - **Stale state stops being served as live.** `extension_logs` stamps
49
+ `stale:true` when the producing session is dead or from a different run;
50
+ `extension_wait` returns `runtimeErrors` alongside ready instead of a bare
51
+ green over a crashing worker; `extension_build` reports
52
+ `productionDivergence` when the production manifest lost permissions or
53
+ resources relative to source.
54
+ - **`extension_open`'s `asTab` fallback fires on the user-gesture wall**, and
55
+ `extension_storage` set without a `key` answers in MCP vocabulary rather
56
+ than CLI flags.
57
+
58
+ ### Added
59
+
60
+ - **Structured bundler warnings on `extension_build`.** The engine now
61
+ persists its build summary to `dist/extension-js/<browser>/
62
+ build-summary.json` (the transport half of engine bug 73), and the tool
63
+ returns it as `buildWarnings` (with `buildWarningsTruncated` naming the
64
+ true count when the engine capped the list). Older engines simply omit the
65
+ field; nothing is scraped from stdout.
66
+ - **Popup-faithful headless rendering.** A popup rendered as a tab is now
67
+ sized like the real popup: the document's content size is measured over
68
+ CDP, clamped to Chrome's 25x25-800x600 popup bounds, and the window is
69
+ resized to it (reported as `renderedAsTab.popupBounds`). If the browser
70
+ does not verifiably honor the resize, the tool keeps saying "no popup
71
+ sizing" instead of implying fidelity. Note headless-new is one such
72
+ browser: it accepts `Browser.setWindowBounds` and changes nothing, so
73
+ headless sessions get the honest fallback, not a resized window. The
74
+ measurement also leaves `body`'s authored width alone; only the root takes
75
+ the temporary fit-content override, so a popup that sizes itself through
76
+ `body { width }` measures at its real width.
77
+ - **CI typechecks the tests.** `pnpm typecheck` covers `src/` and the test
78
+ tsconfig, wired into the CI matrix, so type drift between tools and their
79
+ tests cannot accumulate silently again.
80
+
81
+ ### Changed
82
+
83
+ - **Tool prose caught up with the fixed engine.** `extension_eval` and
84
+ `extension_dom_inspect` now advertise the surface contexts
85
+ (`popup`/`options`/`sidebar`/`devtools`) and override pages
86
+ (`newtab`/`history`/`bookmarks`) the engine's relay serves, needing no tab
87
+ id. The "content eval is known-broken" guard is version-honest: on
88
+ Extension.js >= 4.0.14 a null is the expression's real result, and the note
89
+ says so instead of condemning a repaired path. Firefox hints name every
90
+ working route.
91
+
92
+ A pass focused on a single question: when something has gone wrong, does the
93
+ tool say so? Five tools were reporting success over a failure. All five now
94
+ verify before they claim anything.
95
+
96
+ ### Breaking
97
+
98
+ - **`extension_build` refuses a broken build.** It runs the
99
+ `extension_manifest_validate` checks as a preflight and returns
100
+ `status:"blocked"` on build-blocking errors instead of shelling out to a build
101
+ it knows is broken. Pass `skipValidation: true` for the old behavior. It also
102
+ returns `success:false` with `status:"incomplete"` when the bundler exits 0 but
103
+ a declared entrypoint never reached `dist/`, because the browser refuses to
104
+ load that artifact. Non-blocking findings ride along as `manifestWarnings`.
105
+ - **Browser resolution defaults to `chrome`, not `chromium`.** A dead session
106
+ used to fall through to a blind default, so every call after a dev server
107
+ exited silently retargeted a browser the caller never ran. A dead session now
108
+ resolves to its own browser with `source:"stale"`.
109
+ - **`extension_open` renames `tab` to `target`.** The value is a CDP target id,
110
+ not a `chrome.tabs` id, and the old name invited callers to pass it straight
111
+ into tools that need a numeric tab id.
112
+
113
+ ### Fixed
114
+
115
+ - **`extension_doctor` no longer reports `healthy:true` over a crashing
116
+ extension.** Its runtime-error check read the wrong field, so every error row
117
+ in `logs.ndjson` collapsed to an empty string and was skipped. It now reads the
118
+ engine's `messageParts` payload, with an `errorName`/`stack` fallback, and
119
+ collapses a throw that repeats on every event.
120
+ - **`extension_dev` and `extension_start` no longer report `status:"started"`
121
+ for a server that already exited.** Both health-check the child process and
122
+ return `status:"exited"` with the exit code, signal, and the child's own output
123
+ as evidence.
124
+ - **`extension_open` no longer reports success for a navigation that failed.**
125
+ Navigating to a `chrome-extension://` origin is cross process and swaps the
126
+ render frame, so the pre-navigation session reported a stale error URL on
127
+ success and success on failure. It now confirms against a fresh target list.
128
+ This affected the `url` navigation path shipped in 4.9.0, not only the new
129
+ surface rendering.
130
+ - **`extension_open` targets the right extension.** A dev session also loads
131
+ Extension.js's own manager extension, and taking the first extension target
132
+ navigated against the wrong origin. The id is now derived from the dist path
133
+ the session actually loaded.
134
+
135
+ ### Added
136
+
137
+ - **Headless surface rendering.** `extension_open` accepts `asTab` for
138
+ `popup`/`options`/`sidebar`, rendering the surface document in a real tab so it
139
+ can be inspected where no window exists to host a popup. It is applied
140
+ automatically when a headless session refuses to open the surface, with a note
141
+ saying what was substituted.
142
+ - **Tab targeting by url.** `extension_eval` and `extension_dom_inspect` take a
143
+ `url` and otherwise default to the active tab, and `extension_dom_inspect`
144
+ gains `listTabs` for discovery. The engine gained this in 4.0.13; the tool
145
+ descriptions had been telling callers a numeric tab id was required.
146
+ - **Friendlier arguments.** `timeoutMs`, `lines`, `tabId`, `href` and
147
+ `browserName` fold onto their canonical names, `withConsole` accepts `true`,
148
+ and the input validator understands union types.
149
+ - **`extension_create` matches your package manager.** Hints and the engine
150
+ warning now use bun, pnpm or yarn when that is what the scaffold used, and the
151
+ warning reads the pin the scaffold actually wrote.
152
+
3
153
  ## 4.9.0
4
154
 
5
155
  A second pass from the persona swarm, closing the gaps 4.8.0 left and the top
@@ -7,13 +157,13 @@ new blockers it surfaced.
7
157
 
8
158
  - **Honest `extension_manifest_validate`.** It now scans the project source for
9
159
  permission-gated `chrome.*`/`browser.*` calls and flags any the manifest does
10
- not declare an API used without its permission is `undefined` at runtime and
160
+ not declare, an API used without its permission is `undefined` at runtime and
11
161
  crashes the context, the exact case where validate used to report `valid:true`.
12
162
  The headline is now honest (`valid:false` + `buildBlocking:true` on any error),
13
163
  and it accepts singular `browser` as an alias for `browsers`.
14
164
  - **`extension_open` can navigate a tab.** Pass a `url` (Chromium, via CDP) to
15
165
  drive a content-script test page, a `webNavigation` target, or the popup as a
16
- page (`chrome-extension://<id>/popup.html`) the loop the surface-only open
166
+ page (`chrome-extension://<id>/popup.html`), the loop the surface-only open
17
167
  could not do. `target` is accepted as an alias for `surface`.
18
168
  - **`extension_stop` actually reaps the session.** It now terminates the dev CLI
19
169
  and both browser families (gecko profile + chromium `--load-extension`, under
@@ -184,12 +334,12 @@ that removed nearly all friction a real MCP client hit.
184
334
  --browser=chromium --allow-control` `` becomes `extension_dev with
185
335
  { browser: "chromium", allowControl: true }`, and stray
186
336
  `--allow-control` / `--allow-eval` / `--browser=<x>` mentions become
187
- their tool-argument names. Result data is never touched only
337
+ their tool-argument names. Result data is never touched, only
188
338
  error/hint prose. Tool descriptions now name `allowControl` /
189
339
  `allowEval` directly, so agents no longer discover the gates by
190
340
  fuzzing the schema.
191
341
  - The no-channel error now names the session that IS running ("Active
192
- session browser(s) for this project: chrome pass that as `browser`"),
342
+ session browser(s) for this project: chrome, pass that as `browser`"),
193
343
  so an agent retargets instead of spawning a second, conflicting
194
344
  session. Same for the `extension_logs` follow miss.
195
345
  - `extension_list_extensions` / `extension_source_inspect` accept
@@ -225,7 +375,7 @@ Session lifecycle + determinism release. Tool count 27 -> 28.
225
375
  - CLI spawns are deterministic: dev/start/preview and the act tools now
226
376
  prefer the project's own `node_modules/.bin/extension`, falling back to
227
377
  `npx extension@<pinned>` where the pin derives from the vendored
228
- `extension-develop` version never a floating `latest`.
378
+ `extension-develop` version, never a floating `latest`.
229
379
  - Session registry keys are path-normalized, so a stop with an absolute
230
380
  path matches a session registered with a relative one.
231
381
  - Tests: registry suite now asserts against the exported `tools` array
@@ -300,9 +450,9 @@ this release graduates that line to stable and becomes `latest`.
300
450
  @extension.dev/skill pairing.
301
451
  - MIT license shipped; repository moved to extensiondev/mcp.
302
452
 
303
- # @extension.dev/mcp Changelog
453
+ # @extension.dev/mcp, Changelog
304
454
 
305
- ## Unreleased agent-bridge tools
455
+ ## Unreleased, agent-bridge tools
306
456
 
307
457
  Adds the MCP client surface for the Extension.js **agent bridge** (dev-time
308
458
  observe + act + inspect). All new tools shell out to the `extension` CLI verbs
@@ -312,32 +462,32 @@ a recent **`extension` CLI that ships the bridge verbs** (`logs`, `eval`,
312
462
 
313
463
  > ⚠️ **Release order:** publish this package ONLY after the `extension` /
314
464
  > `extension-develop` suite that ships those verbs is on npm. The published CLI
315
- > at the time of writing (`3.17.0`) does NOT have them publishing this package
465
+ > at the time of writing (`3.17.0`) does NOT have them, publishing this package
316
466
  > before the suite would ship tools that fail with "unknown command". Bump the
317
467
  > version + `extension-*` deps to that suite release, then publish.
318
468
 
319
469
  New tools (22 total):
320
470
 
321
- - **`extension_logs`** read/stream logs from every extension context
471
+ - **`extension_logs`**, read/stream logs from every extension context
322
472
  (background, content, popup/options/sidebar/devtools); filters
323
473
  `level`/`context`/`url`/`tab`/`since`, bounded `follow` window.
324
- - **`extension_eval`** evaluate an expression in a context (requires the dev
474
+ - **`extension_eval`**, evaluate an expression in a context (requires the dev
325
475
  session started with `--allow-eval`; MV3 service worker is CSP-gated).
326
- - **`extension_storage`** read/write `chrome.storage` (requires `--allow-control`).
327
- - **`extension_reload`** reload the extension or a tab (`--allow-control`).
328
- - **`extension_open`** open popup/options/sidebar (`--allow-control`).
329
- - **`extension_dom_inspect`** CDP-free DOM snapshot of content/page or an open
476
+ - **`extension_storage`**, read/write `chrome.storage` (requires `--allow-control`).
477
+ - **`extension_reload`**, reload the extension or a tab (`--allow-control`).
478
+ - **`extension_open`**, open popup/options/sidebar (`--allow-control`).
479
+ - **`extension_dom_inspect`**, CDP-free DOM snapshot of content/page or an open
330
480
  surface (popup/options/sidebar/devtools); `withConsole` merges recent logs.
331
- - **`extension_publish`** publish to extension.dev and return a shareable URL
481
+ - **`extension_publish`**, publish to extension.dev and return a shareable URL
332
482
  (auth-gated; requires `EXTENSION_DEV_TOKEN`).
333
- - **`extension_source_inspect`** gains **`deepDom`** pierce CLOSED shadow roots
483
+ - **`extension_source_inspect`** gains **`deepDom`**, pierce CLOSED shadow roots
334
484
  via CDP (Chromium only).
335
485
 
336
486
  Internal: `lib/act` (CLI shell-out helper), `lib/exec.runExtensionCli` (capture),
337
487
  `lib/cdp.getClosedShadowRoots`. Test infra aligned to the workspace vitest
338
488
  catalog.
339
489
 
340
- ## Unreleased login (auth tools)
490
+ ## Unreleased, login (auth tools)
341
491
 
342
492
  Adds the missing `login` flow so `extension_publish` no longer requires the user
343
493
  to mint and export `EXTENSION_DEV_TOKEN` by hand. Auth stays auth-AWARE: the
@@ -345,13 +495,13 @@ token lives in a local credentials file, never in the MCP process state or logs.
345
495
 
346
496
  New tools (25 total):
347
497
 
348
- - **`extension_login`** GitHub **device-code** flow (no local server; works
498
+ - **`extension_login`**, GitHub **device-code** flow (no local server; works
349
499
  headless). Two-phase: call with `project` (`<workspace>/<project>`) to get a
350
500
  code + URL, call again with the returned `deviceCode` to finish. On success it
351
501
  writes a project-scoped token to the credentials file. Never returns the token.
352
- - **`extension_whoami`** report the stored workspace/project and token expiry
502
+ - **`extension_whoami`**, report the stored workspace/project and token expiry
353
503
  without revealing the token.
354
- - **`extension_logout`** delete the local credentials file.
504
+ - **`extension_logout`**, delete the local credentials file.
355
505
 
356
506
  Token resolution for publish is now `EXTENSION_DEV_TOKEN` env **>** the
357
507
  credentials file (expired file tokens are ignored).
@@ -361,8 +511,8 @@ Credentials file (versioned, `0600`): `$XDG_CONFIG_HOME/extension-dev/auth.json`
361
511
 
362
512
  Platform endpoints this depends on (in `apps/www.extension.dev`):
363
513
 
364
- - `GET /api/cli/login/config` public GitHub OAuth client id + scope.
365
- - `POST /api/cli/login/exchange` trades a GitHub **user** token for a
514
+ - `GET /api/cli/login/config`, public GitHub OAuth client id + scope.
515
+ - `POST /api/cli/login/exchange`, trades a GitHub **user** token for a
366
516
  project-scoped access token after checking workspace membership. Modeled on
367
517
  `/api/oidc/exchange`; tokens are recorded so they stay revocable.
368
518
 
package/README.md CHANGED
@@ -41,7 +41,7 @@ Built on [Extension.js](https://extension.js.org), the open-source cross-browser
41
41
  claude mcp add extension-dev npx @extension.dev/mcp
42
42
  ```
43
43
 
44
- Or install it as a plugin the MCP server plus the `/extension`, `/extension-add`, `/extension-debug`, and `/extension-publish` commands in one step:
44
+ Or install it as a plugin, the MCP server plus the `/extension`, `/extension-add`, `/extension-debug`, and `/extension-publish` commands in one step:
45
45
 
46
46
  ```
47
47
  /plugin marketplace add extensiondev/mcp
@@ -123,11 +123,11 @@ cp node_modules/@extension.dev/mcp/claude/commands/*.md ~/my-extension/.claude/c
123
123
  | platform | `extension_release_promote` | Promote a build to a release channel, headless |
124
124
  | platform | `extension_deploy` | Submit to the Chrome, Firefox, and Edge stores through extension.dev |
125
125
 
126
- Browser-launching tools (`dev`, `start`, `preview`) shell out to the `extension` CLI the project's own `node_modules/.bin/extension` when present, otherwise `npx extension@<pinned>` at the version this package is verified against; everything else runs in-process.
126
+ Browser-launching tools (`dev`, `start`, `preview`) shell out to the `extension` CLI, the project's own `node_modules/.bin/extension` when present, otherwise `npx extension@<pinned>` at the version this package is verified against; everything else runs in-process.
127
127
 
128
128
  ## From preview to store
129
129
 
130
- The platform tools connect agents to [extension.dev](https://extension.dev): `extension_login` runs a GitHub device-code flow and stores a project-scoped token locally (never returned to the agent), `extension_publish` turns a build into a shareable preview URL, and `extension_release_promote` promotes a tested build to a release channel from CI or an agent session, no browser required. `extension_deploy` submits a built extension to the Chrome Web Store, Edge Add-ons, and Firefox AMO through extension.dev, which holds your store credentials and dispatches the release from your project's mirror CI it defaults to a dry run and store credentials are never tool arguments.
130
+ The platform tools connect agents to [extension.dev](https://extension.dev): `extension_login` runs a GitHub device-code flow and stores a project-scoped token locally (never returned to the agent), `extension_publish` turns a build into a shareable preview URL, and `extension_release_promote` promotes a tested build to a release channel from CI or an agent session, no browser required. `extension_deploy` submits a built extension to the Chrome Web Store, Edge Add-ons, and Firefox AMO through extension.dev, which holds your store credentials and dispatches the release from your project's mirror CI, it defaults to a dry run and store credentials are never tool arguments.
131
131
 
132
132
  ## The extension.dev stack
133
133
 
@@ -1,6 +1,6 @@
1
1
  # How the pieces connect
2
2
 
3
- This document explains how the three Claude integration layers the template, the Claude Code rules, and the MCP tools connect through the [examples](https://github.com/extension-js/examples) repo.
3
+ This document explains how the three Claude integration layers (the template, the Claude Code rules, and the MCP tools) connect through the [examples](https://github.com/extension-js/examples) repo.
4
4
 
5
5
  ## The examples repo is the backbone
6
6
 
@@ -154,7 +154,7 @@ MCP server calls extensionCreate() → same go-git-it flow as CLI
154
154
 
155
155
  1. **Single source of truth.** `templates-meta.json` is generated from the actual examples. No manual sync needed. Add a template to `examples/`, run `pnpm run generate`, and all three layers pick it up.
156
156
 
157
- 2. **The examples repo is the knowledge base.** The MCP server doesn't hard-code extension patterns it reads them from examples. This means new patterns (like `sidebar-claude`) are immediately available to Claude without updating the MCP server.
157
+ 2. **The examples repo is the knowledge base.** The MCP server doesn't hard-code extension patterns, it reads them from examples. This means new patterns (like `sidebar-claude`) are immediately available to Claude without updating the MCP server.
158
158
 
159
159
  3. **Graceful degradation.** Users who don't use MCP still benefit from CLAUDE.md. Users who don't use Claude Code still benefit from the template. Each layer works independently.
160
160
 
package/claude/CLAUDE.md CHANGED
@@ -1,4 +1,4 @@
1
- # extension.dev Claude Code Instructions
1
+ # extension.dev, Claude Code Instructions
2
2
 
3
3
  You are working on a browser extension project built with the [extension.dev](https://extension.dev) platform, a zero-config cross-browser extension framework.
4
4
 
@@ -23,11 +23,11 @@ The extension.dev platform ships 60+ templates in the [examples](https://github.
23
23
 
24
24
  | Surface | Vanilla | React | Vue | Svelte | AI |
25
25
  | -------------- | ------------ | ---------------- | ------------- | ---------------- | ---------------- |
26
- | Content script | `content` | `content-react` | `content-vue` | `content-svelte` | |
27
- | Sidebar | `sidebar` | `sidebar-shadcn` | — | | `sidebar-claude` |
28
- | Action popup | `action` | — | | | `action-chatgpt` |
29
- | New tab | `new` | `new-react` | `new-vue` | `new-svelte` | |
30
- | Full framework | `javascript` | `react` | `vue` | `svelte` | |
26
+ | Content script | `content` | `content-react` | `content-vue` | `content-svelte` | n/a |
27
+ | Sidebar | `sidebar` | `sidebar-shadcn` | n/a |, | `sidebar-claude` |
28
+ | Action popup | `action` | n/a |, | n/a | `action-chatgpt` |
29
+ | New tab | `new` | `new-react` | `new-vue` | `new-svelte` | n/a |
30
+ | Full framework | `javascript` | `react` | `vue` | `svelte` | n/a |
31
31
 
32
32
  **When recommending a template:**
33
33
 
@@ -56,7 +56,7 @@ A typical extension.dev project:
56
56
  ```
57
57
  my-extension/
58
58
  src/
59
- manifest.json # Required the source of truth
59
+ manifest.json # Required: the source of truth
60
60
  background.ts # Service worker (Chromium) / background script (Firefox)
61
61
  content/ # Content scripts
62
62
  scripts.tsx
@@ -151,16 +151,16 @@ export default {
151
151
  3. **Service workers vs background scripts.** Chromium uses `service_worker` (single file). Firefox uses `scripts` (array).
152
152
  4. **Environment variables.** Use `EXTENSION_PUBLIC_*` prefix for variables accessible in extension code. `import.meta.env.EXTENSION_PUBLIC_BROWSER` gives the current browser.
153
153
  5. **Asset imports.** Import images/fonts directly in your code. The build system handles bundling.
154
- 6. **CSS Modules.** Use `*.module.css` / `*.module.scss`. Never use the `?url` suffix for CSS module imports it breaks class name hashing.
154
+ 6. **CSS Modules.** Use `*.module.css` / `*.module.scss`. Never use the `?url` suffix for CSS module imports, it breaks class name hashing.
155
155
 
156
156
  ## When creating new extensions
157
157
 
158
158
  1. Check if an existing template matches the use case (see template catalog above)
159
159
  2. If yes: `npx extension@latest create my-ext --template=<slug>`
160
- 3. If no: start from `manifest.json` define what the extension needs
160
+ 3. If no: start from `manifest.json`, define what the extension needs
161
161
  4. Add entry points referenced by the manifest (background, content scripts, UI pages)
162
- 5. Install framework deps if needed (React, Vue, etc.) the framework auto-detects them
163
- 6. Run `npm run dev` the dev server handles the rest
162
+ 5. Install framework deps if needed (React, Vue, etc.), the framework auto-detects them
163
+ 6. Run `npm run dev`, the dev server handles the rest
164
164
 
165
165
  **Learning from examples:** When building a feature you haven't done before, read the source of a relevant template from the examples repo. The source for any template is at:
166
166
 
@@ -234,11 +234,11 @@ npm run dev -- --logs info --log-url "example.com"
234
234
 
235
235
  ### Triggering events without clicking (requires `--allow-control`)
236
236
 
237
- - `extension open action` fire the toolbar action (opens its popup, or replays `chrome.action.onClicked`).
238
- - `extension open command --name <cmd>` replay a `chrome.commands.onCommand` keyboard shortcut.
239
- - `extension_list_extensions` (MCP tool; no CLI verb) list extensions with a live context in the browser (Chromium, read-only).
237
+ - `extension open action`, fire the toolbar action (opens its popup, or replays `chrome.action.onClicked`).
238
+ - `extension open command --name <cmd>`, replay a `chrome.commands.onCommand` keyboard shortcut.
239
+ - `extension_list_extensions` (MCP tool; no CLI verb), list extensions with a live context in the browser (Chromium, read-only).
240
240
 
241
- These replay your captured listeners, so they work on Chrome and Firefox but carry **no user gesture**, so `activeTab` is not granted (the result reports `gesture: false`, plus a `warning` when the manifest declares `activeTab`). If you need a genuine-gesture click (activeTab granted), use [chrome-devtools-mcp](https://github.com/ChromeDevTools/chrome-devtools-mcp)'s `trigger_extension_action` (Chromium only) alongside this server.
241
+ These replay your captured listeners, so they work on Chrome and Firefox, but carry **no user gesture**, so `activeTab` is not granted (the result reports `gesture: false`, plus a `warning` when the manifest declares `activeTab`). If you need a genuine-gesture click (activeTab granted), use [chrome-devtools-mcp](https://github.com/ChromeDevTools/chrome-devtools-mcp)'s `trigger_extension_action` (Chromium only) alongside this server.
242
242
 
243
243
  ## Contributing templates to the examples repo
244
244
 
package/claude/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # extension.dev Claude Code Integration
1
+ # extension.dev, Claude Code Integration
2
2
 
3
3
  Drop-in instructions, rules, and example prompts for building browser extensions with the [extension.dev](https://extension.dev) platform using Claude Code.
4
4
 
@@ -11,10 +11,10 @@ claude/
11
11
  CLAUDE.md Drop-in Claude Code instructions for any extension project
12
12
  ARCHITECTURE.md How the template, CLAUDE.md, and MCP layers connect
13
13
  commands/
14
- extension.md /extension create, dev, build, add features, debug
15
- extension-add.md /extension-add add sidebar, popup, content script, etc.
16
- extension-debug.md /extension-debug live DOM/console inspection
17
- extension-publish.md /extension-publish store submission prep
14
+ extension.md /extension: create, dev, build, add features, debug
15
+ extension-add.md /extension-add: add sidebar, popup, content script, etc.
16
+ extension-debug.md /extension-debug: live DOM/console inspection
17
+ extension-publish.md /extension-publish: store submission prep
18
18
  rules/
19
19
  extension-dev.md Core rules: project structure, manifest, commands
20
20
  cross-browser.md Cross-browser manifest field mapping
@@ -61,9 +61,9 @@ Claude Code will automatically pick up the instructions and know how to:
61
61
 
62
62
  The [examples repo](https://github.com/extension-js/examples) publishes `templates-meta.json` as a nightly release asset. This file is the single source of truth for:
63
63
 
64
- - **CLAUDE.md** references it so Claude knows all available templates
65
- - **MCP tools** `extension_list_templates` fetches and queries it at runtime
66
- - **`extension create`** resolves template slugs to repo URLs via the same naming convention
64
+ - **CLAUDE.md**, references it so Claude knows all available templates
65
+ - **MCP tools**, `extension_list_templates` fetches and queries it at runtime
66
+ - **`extension create`**, resolves template slugs to repo URLs via the same naming convention
67
67
 
68
68
  When a new template is added to the examples repo, all three layers pick it up automatically.
69
69
 
@@ -7,8 +7,8 @@ Add a new feature surface to the current extension project. The user said: $ARGU
7
7
 
8
8
  ## Parse arguments
9
9
 
10
- - First argument: feature type one of: `sidebar`, `popup`, `content-script`, `background`, `newtab`, `options`, `devtools`
11
- - Second argument (optional): framework one of: `react`, `vue`, `svelte`, `preact`, `vanilla`. Default: detect from existing project, fall back to `react`
10
+ - First argument: feature type, one of: `sidebar`, `popup`, `content-script`, `background`, `newtab`, `options`, `devtools`
11
+ - Second argument (optional): framework, one of: `react`, `vue`, `svelte`, `preact`, `vanilla`. Default: detect from existing project, fall back to `react`
12
12
 
13
13
  ## Steps
14
14
 
@@ -18,7 +18,7 @@ Add a new feature surface to the current extension project. The user said: $ARGU
18
18
  - Detect the framework from existing dependencies in `package.json`
19
19
 
20
20
  2. **Get the reference pattern**
21
- If MCP tool `extension_add_feature` is available, use it it returns the exact manifest additions, files to create, and reference template.
21
+ If MCP tool `extension_add_feature` is available, use it. It returns the exact manifest additions, files to create, and reference template.
22
22
 
23
23
  If MCP tool `extension_get_template_source` is available, read the reference template source to get real implementation patterns.
24
24
 
@@ -37,17 +37,17 @@ Add a new feature surface to the current extension project. The user said: $ARGU
37
37
 
38
38
  4. **Create the files**
39
39
  For HTML-based features (sidebar, popup, newtab, options, devtools):
40
- - `src/<feature>/index.html` HTML entry with script tag
41
- - `src/<feature>/scripts.tsx` Framework mount point (or `.ts` for vanilla)
42
- - `src/<feature>/styles.css` Stylesheet
43
- - `src/<feature>/<Feature>App.tsx` Main component (non-vanilla only)
40
+ - `src/<feature>/index.html`, HTML entry with script tag
41
+ - `src/<feature>/scripts.tsx`, Framework mount point (or `.ts` for vanilla)
42
+ - `src/<feature>/styles.css`, Stylesheet
43
+ - `src/<feature>/<Feature>App.tsx`, Main component (non-vanilla only)
44
44
 
45
45
  For content scripts:
46
- - `src/content/scripts.ts` Entry point
47
- - `src/content/styles.css` Injected styles
46
+ - `src/content/scripts.ts`, Entry point
47
+ - `src/content/styles.css`, Injected styles
48
48
 
49
49
  For background:
50
- - `src/background.ts` Service worker / background script
50
+ - `src/background.ts`, Service worker / background script
51
51
 
52
52
  5. **Handle sidebar specifically**
53
53
  If adding a sidebar, also create/update `src/background.ts`:
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Debug a running extension inspect DOM, console, content script injection
2
+ description: Debug a running extension, inspect DOM, console, content script injection
3
3
  argument-hint: "[url] [selectors...]"
4
4
  ---
5
5
 
@@ -25,8 +25,8 @@ Debug the currently running extension dev session. The user said: $ARGUMENTS
25
25
 
26
26
  3. **Exercise event handlers (when the bug is in an action / command / shortcut)**
27
27
  If the session was started with `--allow-control`, fire the events a user would, without clicking:
28
- - `extension_open` with `surface: "action"` triggers the toolbar action (opens its popup, or replays `chrome.action.onClicked`).
29
- - `extension_open` with `surface: "command"` and `name: "<cmd>"` replays a `chrome.commands.onCommand` keyboard shortcut.
28
+ - `extension_open` with `surface: "action"`, triggers the toolbar action (opens its popup, or replays `chrome.action.onClicked`).
29
+ - `extension_open` with `surface: "command"` and `name: "<cmd>"`, replays a `chrome.commands.onCommand` keyboard shortcut.
30
30
  - Then re-inspect or read `extension_logs` to see what the handler did.
31
31
 
32
32
  **Caveat:** replay carries no user gesture, so `activeTab` is NOT granted. If the handler depends on `activeTab` (e.g. `chrome.scripting.executeScript` on the active tab, `captureVisibleTab`), the result includes `gesture: false` and a `warning`, and behavior differs from a real click. For a genuine-gesture click (activeTab granted), use chrome-devtools-mcp's `trigger_extension_action` (Chromium only) alongside this server.
@@ -37,16 +37,16 @@ Debug the currently running extension dev session. The user said: $ARGUMENTS
37
37
  Based on what you find, check for:
38
38
  - **"It didn't load"**: Check extension root count. If 0, content scripts may not be injecting. Check manifest `content_scripts` matches patterns and the target URL.
39
39
  - **Console errors**: Report top errors. Common ones:
40
- - `Uncaught TypeError` likely a missing import or wrong module format
41
- - `Content Security Policy` extension CSP blocking inline scripts
42
- - `chrome.runtime.lastError` API permission missing
40
+ - `Uncaught TypeError`, likely a missing import or wrong module format
41
+ - `Content Security Policy`, extension CSP blocking inline scripts
42
+ - `chrome.runtime.lastError`, API permission missing
43
43
  - **Wrong page**: Check if the content script `matches` pattern in manifest covers the target URL
44
- - **Shadow DOM empty**: Extension root exists but shadow content is empty likely a CSS or framework mounting issue
44
+ - **Shadow DOM empty**: Extension root exists but shadow content is empty, likely a CSS or framework mounting issue
45
45
 
46
46
  5. **Suggest fixes** based on the diagnosis
47
47
 
48
48
  ## Examples
49
49
 
50
- - `/extension-debug` inspect the default page target
51
- - `/extension-debug https://example.com` inspect a specific URL
52
- - `/extension-debug https://example.com #my-root .sidebar` inspect URL and probe selectors
50
+ - `/extension-debug`, inspect the default page target
51
+ - `/extension-debug https://example.com`, inspect a specific URL
52
+ - `/extension-debug https://example.com #my-root .sidebar`, inspect URL and probe selectors
@@ -9,27 +9,27 @@ You are helping build a browser extension with the extension.dev platform. The u
9
9
 
10
10
  Parse the user's intent from `$ARGUMENTS` and execute the matching action:
11
11
 
12
- ### "create <name>" or "new <name>" Scaffold a new extension
12
+ ### "create <name>" or "new <name>", Scaffold a new extension
13
13
 
14
14
  1. If MCP tool `extension_list_templates` is available, use it to find the best template matching the user's description (check for surface type, framework, and keywords)
15
15
  2. If not, check the template catalog: `curl -sL https://github.com/extension-js/examples/releases/download/nightly/templates-meta.json | jq '.templates[] | {slug, description, uiFramework, surfaces}'`
16
16
  3. Run `npx extension@latest create <name> --template=<best-match>`
17
17
  4. Report what was created and suggest `npm run dev`
18
18
 
19
- ### "dev" or "run" Start development
19
+ ### "dev" or "run", Start development
20
20
 
21
21
  1. Run `npm run dev` (or `npx extension dev`) in the project root
22
22
  2. Tell the user the browser will open with their extension loaded
23
- 3. Mention HMR is active changes will hot-reload
23
+ 3. Mention HMR is active, changes will hot-reload
24
24
 
25
- ### "build" Build for production
25
+ ### "build", Build for production
26
26
 
27
27
  1. Run `npm run build` (or `npx extension build`)
28
28
  2. After success, report the output in `dist/chrome/`
29
29
  3. If the user mentions "firefox" or "both", also build with `--browser=firefox`
30
30
  4. If they mention "zip" or "store", add `--zip`
31
31
 
32
- ### "add <feature>" Add a feature surface
32
+ ### "add <feature>", Add a feature surface
33
33
 
34
34
  1. If MCP tool `extension_add_feature` is available, use it to get the manifest additions and file list
35
35
  2. Otherwise, determine what's needed from the feature type:
@@ -40,14 +40,14 @@ Parse the user's intent from `$ARGUMENTS` and execute the matching action:
40
40
  - **background**: `background.service_worker` (Chromium) + `background.scripts` (Firefox)
41
41
  3. Create the files and update `src/manifest.json`
42
42
 
43
- ### "debug" or "inspect" Debug a running extension
43
+ ### "debug" or "inspect", Debug a running extension
44
44
 
45
45
  1. If MCP tool `extension_source_inspect` is available, use it with `include: ["html", "console", "extension_roots"]`
46
46
  2. If there's a URL mentioned, pass it as the target
47
47
  3. If there are CSS selectors mentioned, pass them as `probe`
48
48
  4. Report: injected HTML, console errors, extension root state
49
49
 
50
- ### "validate" Check manifest for issues
50
+ ### "validate", Check manifest for issues
51
51
 
52
52
  1. If MCP tool `extension_manifest_validate` is available, use it
53
53
  2. Otherwise, read `src/manifest.json` and check:
@@ -56,7 +56,7 @@ Parse the user's intent from `$ARGUMENTS` and execute the matching action:
56
56
  - Permissions: `sidePanel` present if `side_panel` is declared
57
57
  - Background: `service_worker` (Chromium) and `scripts` (Firefox) both present
58
58
 
59
- ### "template <query>" Search for a template
59
+ ### "template <query>", Search for a template
60
60
 
61
61
  1. If MCP tool `extension_list_templates` is available, use it with the query
62
62
  2. Otherwise, search the catalog JSON
@@ -6,7 +6,7 @@
6
6
 
7
7
  ## How Claude should approach this
8
8
 
9
- 1. **Update manifest.json** add side panel config for both browsers:
9
+ 1. **Update manifest.json**, add side panel config for both browsers:
10
10
 
11
11
  ```json
12
12
  {
@@ -47,7 +47,7 @@
47
47
  }
48
48
  ```
49
49
 
50
- 4. **Create the sidebar UI** `src/sidebar/index.html`, `src/sidebar/scripts.tsx`, `src/sidebar/styles.css`
50
+ 4. **Create the sidebar UI**, `src/sidebar/index.html`, `src/sidebar/scripts.tsx`, `src/sidebar/styles.css`
51
51
 
52
52
  5. **Test both browsers:**
53
53
  ```bash
@@ -13,7 +13,7 @@
13
13
  cd page-summarizer
14
14
  ```
15
15
 
16
- 2. **Define the manifest** content script for the floating button, background script for orchestration:
16
+ 2. **Define the manifest**, content script for the floating button, background script for orchestration:
17
17
 
18
18
  ```json
19
19
  {
@@ -35,7 +35,7 @@
35
35
  }
36
36
  ```
37
37
 
38
- 3. **Build the content script** inject a floating button, handle click to extract `document.body.innerText`, send to background for processing.
38
+ 3. **Build the content script**, inject a floating button, handle click to extract `document.body.innerText`, send to background for processing.
39
39
 
40
40
  4. **Test it:**
41
41
  ```bash