browser-extension-manager 1.7.0 → 1.7.2

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/CLAUDE.md CHANGED
@@ -43,6 +43,8 @@ To load the unpacked extension in Chrome: point chrome://extensions → "Load un
43
43
 
44
44
  ### For Framework Development (This Repository)
45
45
 
46
+ > **🚫 NEVER use `npx mgr ...` from the framework repo.** `npx mgr` is for CONSUMER projects only (where the bin is linked in `node_modules/.bin/`). From the framework repo, use `npm test`, `npm start`, etc. — the `scripts` in `package.json` call the local `bin/` directly. This applies to ALL four OMEGA frameworks (BEM/UJM/BXM/EM).
47
+
46
48
  1. `npm install`
47
49
  2. `npm start` — watch + compile `src/` → `dist/` via prepare-package
48
50
  3. Test in the **designated test consumer** — `../powertools-browser-extension` is BXM's consumer for validating framework changes end-to-end (exercise any consumer-level flow there freely: builds, tests, packaging, runtime). From inside it, run `npx mgr install dev` to swap BXM to this local repo — required whenever you edit the framework source and want the consumer to pick up the changes (the consumer otherwise keeps its installed `node_modules/browser-extension-manager`). Reverse with `npx mgr install live`.
@@ -198,10 +200,11 @@ See [docs/cli.md](docs/cli.md).
198
200
 
199
201
  ## Development Workflow
200
202
 
201
- - **🚫 NEVER run `npm start`** it's the user's long-running dev watcher. Assume it's already running; if it isn't, **instruct the user to run it** rather than running it yourself (running it again kills theirs). To see output, **read the `logs/*.log` files** (`dev.log`, `build.log`, `test.log`) never tail/attach to the process. Running `npx mgr test` is fine.
203
+ - **🚫 NEVER use `npx mgr ...` from the framework repo** `npx mgr` is for CONSUMER projects only (where the bin lives in `node_modules/.bin/`). From the framework repo, use `npm test`, `npm start`, etc. the `scripts` in `package.json` call `node bin/browser-extension-manager` directly. This applies to ALL four OMEGA frameworks (BEM/UJM/BXM/EM).
204
+ - **🚫 NEVER run `npm start`** (consumer projects) — it's the user's long-running dev watcher. Assume it's already running; if it isn't, **instruct the user to run it** rather than running it yourself (running it again kills theirs). To see output, **read the `logs/*.log` files** (`dev.log`, `build.log`, `test.log`) — never tail/attach to the process. Running `npx mgr test` is fine.
202
205
  - **Where the output logs live:** the gulp pipeline tees all stdout/stderr to `<projectRoot>/logs/dev.log` (on `npm start`) or `logs/build.log` (on `npm run build`), truncated fresh each run, ANSI-stripped. `cat logs/dev.log` (or `grep` it) instead of scrolling scrollback. `npx mgr test` writes `logs/test.log`. See [docs/build-system.md](docs/build-system.md#log-files).
203
206
  - **After editing files**, verify the gulp watcher recompiled successfully. Check for webpack/sass errors in the console output. A change that breaks the build is not a completed change.
204
- - **Live-test UI changes via CDP.** After code changes compile, use the `chrome-devtools` MCP tools (screenshots, click, evaluate JS, console logs) to verify the change works in the running browser. This is the primary way to confirm UI changes — type-checking and test suites verify code correctness, not feature correctness. See `~/.claude/mcp-server/servers/chrome-devtools/CLAUDE.md`.
207
+ - **Live-test the extension via CDP.** Use the `chrome-devtools-extension` MCP upstream — it launches a per-session Chrome for Testing with the unpacked extension pre-loaded (`BXM_EXTENSION_PATH="$(pwd)/packaged/chromium/raw" claude`, then `router__enable_upstream`; stable Chrome ignores `--load-extension`). Plain web pages (no extension needed): the regular `chrome-devtools` MCP tools — your session auto-launches its own private Chrome on the first tool call. This is the primary way to confirm UI changes — type-checking and test suites verify code correctness, not feature correctness. See [docs/cdp-debugging.md](docs/cdp-debugging.md) + `~/.claude/mcp-server/servers/chrome-devtools-extension/CLAUDE.md`.
205
208
 
206
209
  ## Supply-Chain Security
207
210
 
@@ -230,6 +233,8 @@ Whenever you make a behavioral change (new command, new flag, new pattern, remov
230
233
 
231
234
  Don't ship behavioral changes with stale docs. Validate first, then document — write docs that describe shipped reality, not intentions.
232
235
 
236
+ **The OMEGA docs are structurally MIRRORED.** This file's section skeleton, the consumer template (`src/defaults/CLAUDE.md`), shared-concept `docs/*.md` filenames, and the `omega:*` skills are identical in structure and order across the sister frameworks (UJM / BEM / BXM / EM / MAM — WM mirrors the library subset). Never add, rename, or reorder a section here without making the SAME change in every sister repo in the same pass. The canonical skeletons + omission rules live in the `omega:main` skill's `mirror-spec.md` resource.
237
+
233
238
  ## Documentation
234
239
 
235
240
  API references for each subsystem live in `docs/`:
@@ -1,6 +1,8 @@
1
1
  # ========== Default Values ==========
2
2
  # Browser Extension Manager (BXM) — consumer project
3
3
 
4
+ <!-- MAINTAINERS (framework repo): this consumer template is MIRRORED across UJM/BEM/BXM/EM/MAM — same sections, same order (framework-specific extras may be inserted; canonical sections are never reordered/renamed). Edit all five together. Canonical skeleton: omega:main skill → resources/mirror-spec.md -->
5
+
4
6
  ## Framework
5
7
 
6
8
  This project consumes **Browser Extension Manager** (BXM) — a comprehensive framework for building modern cross-browser extensions (Chrome, Firefox, Edge, Opera, Brave). BXM provides one-line bootstrap per extension context, a component-based architecture (view + styles + script per context), a multi-browser build/release pipeline that produces store-uploadable zips, cross-context auth synchronization, and a built-in four-layer test framework.
@@ -402,6 +402,11 @@ function filterBySource(source, files, sourceFilter, pathPart) {
402
402
  });
403
403
  }
404
404
 
405
+ // Glob ignore patterns implementing the "underscore = not a suite" convention:
406
+ // `_`-prefixed FILES (e.g. test/_init.js) and everything under a `_`-prefixed
407
+ // DIRECTORY at any depth (helpers, fixtures — e.g. test/_helpers/harness.js).
408
+ const DISCOVERY_IGNORE = ['**/_*.js', '**/_*/**'];
409
+
405
410
  function discoverTestFiles(target) {
406
411
  const { source: sourceFilter, pathPart } = parseTarget(target);
407
412
  const framework = [];
@@ -425,7 +430,7 @@ function discoverTestFiles(target) {
425
430
  // Consumers write their own boot tests under <cwd>/test/boot/.
426
431
  const frameworkSuitesDir = path.join(__dirname, 'suites');
427
432
  if (jetpack.exists(frameworkSuitesDir)) {
428
- const ignore = ['_**'];
433
+ const ignore = [...DISCOVERY_IGNORE];
429
434
  if (!isFrameworkSelfTest) ignore.push('boot/**');
430
435
  glob('**/*.js', { cwd: frameworkSuitesDir, ignore }).sort().forEach((rel) => {
431
436
  framework.push(path.join(frameworkSuitesDir, rel));
@@ -434,9 +439,10 @@ function discoverTestFiles(target) {
434
439
 
435
440
  // Consumer project suites — CWD/test/**/*.js. Skip when running from inside the
436
441
  // framework's own dist tree (where consumer-tests-dir === framework-tests-parent).
442
+ // Excludes `_`-prefixed files and directories (see DISCOVERY_IGNORE).
437
443
  const projectTestsDir = path.join(process.cwd(), 'test');
438
444
  if (jetpack.exists(projectTestsDir) && projectTestsDir !== path.dirname(frameworkSuitesDir)) {
439
- glob('**/*.js', { cwd: projectTestsDir, ignore: ['_**'] }).sort().forEach((rel) => {
445
+ glob('**/*.js', { cwd: projectTestsDir, ignore: [...DISCOVERY_IGNORE] }).sort().forEach((rel) => {
440
446
  project.push(path.join(projectTestsDir, rel));
441
447
  });
442
448
  }
@@ -512,4 +518,4 @@ async function runInitSetups() {
512
518
  }
513
519
  }
514
520
 
515
- module.exports = { run, SkipError };
521
+ module.exports = { run, SkipError, DISCOVERY_IGNORE };
@@ -0,0 +1,63 @@
1
+ // Build-layer tests for test-suite discovery — specifically the
2
+ // "underscore = not a suite" convention: `_`-prefixed files and everything
3
+ // under `_`-prefixed directories (at ANY depth) must be excluded, so consumers
4
+ // can keep helpers and fixture trees (e.g. test/_helpers/harness.js)
5
+ // next to their suites.
6
+
7
+ const path = require('path');
8
+
9
+ module.exports = {
10
+ type: 'suite',
11
+ layer: 'build',
12
+ description: 'test discovery — underscore exclusion convention',
13
+ tests: [
14
+ {
15
+ name: 'runner exports DISCOVERY_IGNORE',
16
+ run: (ctx) => {
17
+ const runner = require(path.join(__dirname, '..', '..', 'runner.js'));
18
+ ctx.expect(Array.isArray(runner.DISCOVERY_IGNORE)).toBe(true);
19
+ ctx.expect(runner.DISCOVERY_IGNORE.length >= 2).toBe(true);
20
+ },
21
+ },
22
+ {
23
+ name: 'glob with DISCOVERY_IGNORE skips _ files and _ dirs at any depth',
24
+ run: (ctx) => {
25
+ const fs = require('fs');
26
+ const os = require('os');
27
+ const glob = require('glob').globSync;
28
+ const { DISCOVERY_IGNORE } = require(path.join(__dirname, '..', '..', 'runner.js'));
29
+
30
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'bxm-discovery-test-'));
31
+ const write = (rel) => {
32
+ const file = path.join(tmp, rel);
33
+ fs.mkdirSync(path.dirname(file), { recursive: true });
34
+ fs.writeFileSync(file, 'module.exports = {};\n');
35
+ };
36
+
37
+ // Should be DISCOVERED:
38
+ write('build/config.test.js');
39
+ write('page/runner.test.js');
40
+ write('boot/nested/deep.test.js');
41
+
42
+ // Should be EXCLUDED:
43
+ write('_init.js'); // top-level _ file
44
+ write('page/_helper.js'); // nested _ file
45
+ write('_helpers/harness.js'); // file in top-level _ dir
46
+ write('_fixtures/packages/runner/mod/index.js'); // deep inside a _ dir
47
+ write('boot/_private/util.js'); // _ dir below a layer dir
48
+
49
+ const found = glob('**/*.js', { cwd: tmp, ignore: [...DISCOVERY_IGNORE] }).sort();
50
+
51
+ try {
52
+ ctx.expect(found).toEqual([
53
+ 'boot/nested/deep.test.js',
54
+ 'build/config.test.js',
55
+ 'page/runner.test.js',
56
+ ]);
57
+ } finally {
58
+ fs.rmSync(tmp, { recursive: true, force: true });
59
+ }
60
+ },
61
+ },
62
+ ],
63
+ };
@@ -1,45 +1,42 @@
1
1
  # CDP Debugging (driving a live browser)
2
2
 
3
- How to launch a browser you can CONTROL — see the extension live, screenshot it, click, type, read console logs, inspect network requests — for agents (Claude via MCP/CDP) and humans. For BXM this is THE dev surface: the extension only exists inside a running Chrome.
3
+ How to drive a browser you can CONTROL — see the extension live, screenshot it, click, type, read console logs, inspect network requests — for agents (Claude via MCP/CDP) and humans. For BXM this is THE dev surface: the extension only exists inside a running browser.
4
4
 
5
- > Mirrored across the four sister frameworks (UJM / BEM / BXM / EM) — same core section, framework-flavored. Edit all four together.
5
+ > Mirrored across the five sister frameworks (UJM / BEM / BXM / EM / WM) — same core section, framework-flavored. Edit all five together.
6
6
 
7
- ## Launching a controllable Chrome (the canonical command)
7
+ ## The browser: your Claude session owns one
8
8
 
9
- ```bash
10
- open -gna "Google Chrome" --args \
11
- --remote-debugging-port=9223 \
12
- --user-data-dir="$HOME/Library/Application Support/chrome-profiles/agent" \
13
- --no-first-run --no-default-browser-check \
14
- --disable-background-timer-throttling \
15
- --disable-backgrounding-occluded-windows \
16
- --disable-renderer-backgrounding
17
- ```
9
+ Browser work runs through the **`chrome-devtools` MCP** (via mcp-router). There is NO launch procedure anymore — no ports, no profile dirs, no curl checks:
18
10
 
19
- Verify it's up: `curl -s http://127.0.0.1:9223/json/version`
11
+ - **Just call the tools** — `new_page`, `navigate_page`, `take_screenshot`, `click`, `fill`, `evaluate_script`, `list_console_messages`, `list_network_requests`. The browser auto-launches on the first call.
12
+ - **Each Claude session gets its OWN private Chrome** (`--isolated`): temp profile, CDP over an internal pipe. Parallel sessions cannot see or touch each other's pages — open and close pages freely, the whole browser is yours.
13
+ - **It dies with the session.** No orphans, no cleanup, nothing to kill.
14
+ - **Ephemeral profile** — cookies/logins do NOT persist between sessions. If a flow needs auth, log in during the task.
15
+ - **Self-signed HTTPS is pre-accepted** (`--acceptInsecureCerts` in the upstream) — dev servers load without certificate interstitials.
16
+ - **NEVER quit/kill Chrome by app name** (`killall "Google Chrome"`, osascript) — that's the user's personal browser, not yours.
20
17
 
21
- The rules that make this work (each one learned the hard way):
18
+ Humans: the agent's Chrome window is visible you can watch it drive. Full reference: `~/.claude/mcp-server/servers/chrome-devtools/CLAUDE.md`.
22
19
 
23
- - **`open -gna` launches WITHOUT stealing focus.** `-g` = don't bring to foreground, `-n` = new instance (required — without it `open` just activates the already-running daily Chrome and the `--args` are ignored). Launching the Chrome binary directly ALWAYS activates the app and steals focus. Do NOT use `-j`/`--hide` — animations need a visible window; instead the three `--disable-*` flags keep timers/rAF/rendering at FULL speed while the window sits behind your work (verified: rAF at the display's native 120fps while backgrounded, focus never moved).
24
- - **`--user-data-dir` is REQUIRED, not optional.** Chrome 136+ **silently ignores** `--remote-debugging-port` on the default profile — no error, no port, nothing (verified on Chrome 149). This is the #1 "why isn't CDP up" trap.
25
- - **The profile dir IS the persistent state** — logins AND installed extensions. Cookies + localStorage survive relaunches (verified by round-trip), and so does an unpacked extension you've loaded (see below). Ecosystem convention: ONE shared profile at `~/Library/Application Support/chrome-profiles/agent` across all four frameworks, so setup is one-time.
26
- - **One Chrome instance per profile dir — but MANY agents per instance.** CDP is multi-client (verified: two concurrent clients driving different tabs of one instance): agents and sessions attach to the SAME port, each drives its own tab, and all share the profile's logins and extensions. One agent per tab is the only rule. A second launch with the same dir just opens a window in the existing instance and **ignores the new debug port** — attach to the running one instead. Reach for a second profile + port (`…/b` on 9224) only for a different IDENTITY (a different account = a different cookie jar) or hard isolation.
27
- - It runs **side-by-side with the daily Chrome** — a different `--user-data-dir` is a fully separate instance.
28
- - **Quit by profile match, never by app name**: `pkill -f "chrome-profiles/agent"`. (`osascript 'tell app "Google Chrome" to quit'` hits the daily browser too — same app name.)
20
+ ## Electron apps are the exception (attach, don't launch)
29
21
 
30
- ## Loading the extension (BXM specifics)
22
+ An Electron dev app is a running singleton — you ATTACH to it instead of launching a browser: the `chrome-devtools-electron` MCP upstream (reads `EM_CDP_PORT`, default 9222, expanded once at session start) or EM's per-invocation `npx mgr cdp`. See EM's `docs/cdp-debugging.md`.
31
23
 
32
- - **`--load-extension` does NOT work on stable Chrome** — silently ignored (verified on Chrome 149; support was removed from branded Chrome around v137). Do not build tooling on it.
33
- - Instead, load it ONCE through the UI: in the agent-profile Chrome, open `chrome://extensions` → enable **Developer mode** → **Load unpacked** → select the build output. **The persistent profile keeps it installed across every relaunch** — reload it from `chrome://extensions` (or the ⟳ button) after rebuilds.
34
- - The extension's surfaces appear as CDP targets: the background service worker (`type: "service_worker"`, `chrome-extension://<id>/…`), the popup while it's open, and content scripts inside the page targets they're injected into.
24
+ ## BXM specifics: testing the extension (`chrome-devtools-extension` upstream)
35
25
 
36
- ## Driving it
26
+ The plain `chrome-devtools` browser has NO extension in it — and `--load-extension` is silently ignored by branded stable Chrome (removed ~v137; verified on 149). The fix is the dedicated **`chrome-devtools-extension` MCP upstream**: the same per-session isolated model, but it launches **Chrome for Testing** (which still honors `--load-extension` — verified on CfT 150) with your unpacked extension pre-loaded into the ephemeral profile.
37
27
 
38
- | Client | Good for | Port handoff |
39
- |---|---|---|
40
- | `chrome-devtools` MCP | rich interaction — click, fill, type, screenshots, network requests, console messages, performance traces | `CHROME_CDP_PORT` env var, **expanded ONCE when the Claude session spawns its MCP — set it BEFORE launching `claude`** (mid-session changes do nothing) |
41
- | Any CDP client — including EM's `npx mgr cdp` run from any EM project | quick JS eval, per-renderer screenshots | per invocation: `EM_CDP_PORT=9223 npx mgr cdp eval "<url-substring>" 'document.title'` |
28
+ The recipe:
42
29
 
43
- Port conventions: **9222** = Electron apps (EM), **9223+** = Chrome instances.
30
+ 1. **Build the loadable output**: `npm run build` → `packaged/chromium/raw/` (strict-JSON manifest; `dist/` is NOT Chrome-loadable — its manifest is JSON5).
31
+ 2. **Launch the session with the extension path** (env is expanded ONCE at session start — set it BEFORE `claude`):
32
+ ```bash
33
+ BXM_EXTENSION_PATH="$(pwd)/packaged/chromium/raw" claude
34
+ ```
35
+ 3. **In the session, enable the upstream** (it's on-demand): `router__enable_upstream { name: "chrome-devtools-extension" }`. The first tool call launches CfT with the extension loaded. Tools are namespaced `chrome-devtools-extension__*` (34 tools — the base set + extension tools).
36
+ 4. **Rebuild loop**: after `npm run build`, `router__disable_upstream` + `router__enable_upstream` → fresh browser with the rebuilt extension (the profile is ephemeral; the extension loads at launch).
44
37
 
45
- Navigating to a brand's UJM dev site? BrowserSync serves over HTTPS (self-signed cert). Prefer `https://localhost:4000`; fall back to the machine's local network IP (e.g. `https://192.168.x.x:4000`) if localhost doesn't connect. Port 4000 by default, increments to 4001+ when multiple sites run. Read the exact URL from `.temp/_config_browsersync.yml` at the root of the WEBSITE project (the UJM consumer — e.g. `<brand>-website/.temp/_config_browsersync.yml`, NOT this extension repo).
38
+ What you can reach: the popup and extension pages as page targets, content scripts inside the pages they're injected into, and the background service worker (`evaluate_script` takes a `serviceWorkerId`). Chrome for Testing binaries live in `~/.cache/puppeteer/chrome/` (the upstream auto-resolves the newest; update with `npu npx @puppeteer/browsers install chrome@stable`).
39
+
40
+ Full recipe + gotchas: `~/.claude/mcp-server/servers/chrome-devtools-extension/CLAUDE.md`.
41
+
42
+ Navigating to a brand's UJM dev site? **`https://localhost:4000` — NEVER the LAN IP** (`https://192.168.x.x:...`). Port 4000 by default, increments (4001, …) when multiple sites run; exact port in `.temp/_config_browsersync.yml` at the WEBSITE project root (the UJM consumer, NOT this extension repo).
@@ -157,7 +157,7 @@ Consumers writing their own tests get this automatically when running through `n
157
157
  - **Framework defaults**: `<BXM>/dist/test/suites/**/*.js`
158
158
  - **Consumer suites**: `<cwd>/test/**/*.js`
159
159
 
160
- Directories starting with `_` are ignored. Files load alphabetically.
160
+ **The underscore convention** (`DISCOVERY_IGNORE` in `src/test/runner.js`): `_`-prefixed FILES (`test/_init.js`, `test/page/_helper.js`) and everything under a `_`-prefixed DIRECTORY at **any depth** (`test/_fixtures/**`, `test/boot/_private/**`) are excluded from suite discovery. Put shared helpers, fixture data, and non-test support files in `_`-prefixed paths — e.g. `test/_fixtures/`, `test/_helpers/`. The runner still specifically loads `test/_init.js` as the lifecycle hook. Matches the same convention in BEM/EM/UJM. Files load alphabetically.
161
161
 
162
162
  **Framework's boot suites are scoped to BXM self-test runs only.** When a consumer runs `npx bxm test`, the framework's `dist/test/suites/boot/**` is excluded from discovery (those tests assert on BXM's internal fixture extension). Consumers write their own boot tests under `<cwd>/test/boot/`. See [test-boot-layer.md](test-boot-layer.md).
163
163
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "browser-extension-manager",
3
- "version": "1.7.0",
3
+ "version": "1.7.2",
4
4
  "description": "Browser Extension Manager dependency manager",
5
5
  "main": "dist/index.js",
6
6
  "exports": {
@@ -34,8 +34,8 @@
34
34
  "mgr": "bin/browser-extension-manager"
35
35
  },
36
36
  "files": [
37
- "dist/",
38
37
  "bin/",
38
+ "dist/",
39
39
  "docs/",
40
40
  "CLAUDE.md"
41
41
  ],