rechrome 1.28.0 → 1.28.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.
- package/README.md +1 -1
- package/package.json +4 -2
- package/rechrome.js +36 -8
- package/rechrome.ts +36 -8
package/README.md
CHANGED
|
@@ -285,7 +285,7 @@ directory. Pass `-s=<name>` for a named sub-session, or `--isolate` for a throwa
|
|
|
285
285
|
```bash
|
|
286
286
|
git clone https://github.com/snomiao/rechrome.git
|
|
287
287
|
cd rechrome
|
|
288
|
-
bun install
|
|
288
|
+
bun install # `prepare` also builds vendor/ from vendor-src/, so the checkout has a working CLI
|
|
289
289
|
bun link # makes this checkout the global rechrome / rech
|
|
290
290
|
bun test ./*.test.ts ./*.spec.ts ./scripts/*.test.ts # rechrome's own tests (plain `bun test` also finds the vendored forks' suites)
|
|
291
291
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rechrome",
|
|
3
|
-
"version": "1.28.
|
|
3
|
+
"version": "1.28.1",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/snomiao/rechrome.git"
|
|
@@ -32,7 +32,9 @@
|
|
|
32
32
|
"serve": "bun run rechrome.ts serve",
|
|
33
33
|
"test": "bun test",
|
|
34
34
|
"vendor-cli": "bash scripts/vendor-cli.sh",
|
|
35
|
-
"
|
|
35
|
+
"prepare": "bash scripts/vendor-cli.sh --prepare",
|
|
36
|
+
"check-pack": "bash scripts/check-pack.sh",
|
|
37
|
+
"prepublishOnly": "bash scripts/vendor-cli.sh && sed 's/\\.ts/\\.js/g' rechrome.ts > rechrome.js && sed 's/\\.ts/\\.js/g' serve.ts > serve.js && bun build extension-token.ts --target=bun --outfile=extension-token.js && bun build daemon-manager.ts --target=bun --outfile=daemon-manager.js && bun build listeners.ts --target=bun --outfile=listeners.js && bash scripts/check-pack.sh"
|
|
36
38
|
},
|
|
37
39
|
"devDependencies": {
|
|
38
40
|
"@types/bun": "latest",
|
package/rechrome.js
CHANGED
|
@@ -10,6 +10,7 @@ import { hostname, homedir, networkInterfaces } from "os";
|
|
|
10
10
|
import { isIPv4 } from "net";
|
|
11
11
|
import { join, basename, dirname } from "path";
|
|
12
12
|
import { pathToFileURL } from "url";
|
|
13
|
+
import { createRequire } from "node:module";
|
|
13
14
|
import { spawn as cpSpawn } from "child_process";
|
|
14
15
|
import { readFile, writeFile, rename, chmod, mkdir } from "node:fs/promises";
|
|
15
16
|
import { oxmgrInstallCommand, pickDaemonManager, type DaemonManager } from "./daemon-manager.js";
|
|
@@ -1446,23 +1447,41 @@ async function pmList(mgr: DaemonManager = daemonManager()): Promise<string> {
|
|
|
1446
1447
|
return await new Response(proc.stdout).text();
|
|
1447
1448
|
}
|
|
1448
1449
|
|
|
1450
|
+
// A candidate playwright-cli entry is usable only if the playwright-core it requires actually
|
|
1451
|
+
// resolves FROM that entry — the wrapper does `require('playwright-core/lib/tools/cli-client/program')`,
|
|
1452
|
+
// a deep subpath reachable only through the fork's patched `exports` map. existsSync on the .js is
|
|
1453
|
+
// not the same check: an uninitialised/half-built lib/playwright-cli submodule leaves the wrapper on
|
|
1454
|
+
// disk with no resolvable core, and the failure surfaces later as MODULE_NOT_FOUND inside the daemon.
|
|
1455
|
+
export function playwrightCliIsUsable(jsEntry: string): boolean {
|
|
1456
|
+
try {
|
|
1457
|
+
createRequire(jsEntry).resolve("playwright-core/lib/tools/cli-client/program");
|
|
1458
|
+
return true;
|
|
1459
|
+
} catch {
|
|
1460
|
+
return false;
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1449
1464
|
// Resolve which playwright-cli the daemon runs to drive Chrome. Priority:
|
|
1450
1465
|
// 1. PLAYWRIGHT_CLI env override — explicit, already a full command string.
|
|
1451
1466
|
// 2. Vendored fork in a git checkout (lib/playwright-cli/playwright-cli.js) — the patched
|
|
1452
1467
|
// multi-tab CLI + patched playwright-core (PLAYWRIGHT_MCP_PROFILE_DIRECTORY etc.).
|
|
1453
1468
|
// 3. The fork bundled into the npm tarball (vendor/playwright-cli/playwright-cli.js, produced by
|
|
1454
|
-
// scripts/vendor-cli.sh at prepublish
|
|
1455
|
-
// `bun i -g rechrome`: self-contained, no
|
|
1469
|
+
// scripts/vendor-cli.sh at prepublish, and by `prepare` on `bun install` in a checkout). This
|
|
1470
|
+
// is the batteries-included default for `bun i -g rechrome`: self-contained, no
|
|
1471
|
+
// @playwright/cli dep, no browser-binary download.
|
|
1456
1472
|
// 4. Bare `playwright-cli-multi-tab` on PATH — legacy fallback for a pre-existing global link.
|
|
1473
|
+
// Candidates 2–3 must also pass playwrightCliIsUsable(), so a present-but-broken one falls through.
|
|
1474
|
+
// lib/ stays ahead of vendor/ on purpose: a dev who built the fork wants their patched core, not
|
|
1475
|
+
// the (possibly older) vendor-src snapshot that `prepare` unpacks into vendor/.
|
|
1457
1476
|
// A resolved .js entry is run through `node` on Windows (which can't exec a .js by shebang) and
|
|
1458
1477
|
// bare on POSIX (its `#!/usr/bin/env node` shebang runs it under node, which the relay handshake
|
|
1459
1478
|
// needs — see daemonInstall). serve splits the result on spaces into argv.
|
|
1460
|
-
export function resolvePlaywrightCli(): string {
|
|
1479
|
+
export function resolvePlaywrightCli(root: string = import.meta.dir): string {
|
|
1461
1480
|
if (process.env.PLAYWRIGHT_CLI) return process.env.PLAYWRIGHT_CLI;
|
|
1462
1481
|
const jsEntry = [
|
|
1463
|
-
join(
|
|
1464
|
-
join(
|
|
1465
|
-
].
|
|
1482
|
+
join(root, "lib/playwright-cli/playwright-cli.js"),
|
|
1483
|
+
join(root, "vendor/playwright-cli/playwright-cli.js"),
|
|
1484
|
+
].filter(existsSync).find(playwrightCliIsUsable);
|
|
1466
1485
|
if (jsEntry) return IS_WINDOWS ? `node ${jsEntry}` : jsEntry;
|
|
1467
1486
|
return "playwright-cli-multi-tab";
|
|
1468
1487
|
}
|
|
@@ -2586,7 +2605,8 @@ export function rechCli(argv: string[], handlers: RechHandlers) {
|
|
|
2586
2605
|
? handlers.urlList()
|
|
2587
2606
|
: handlers.printProfileUri(a.profile, a.listener, { local: a.local, save: a.save }))
|
|
2588
2607
|
.command("connect <url>", "Use a URL from another machine in this project (checks it first)", y => y
|
|
2589
|
-
.positional("url", { type: "string", demandOption: true })
|
|
2608
|
+
.positional("url", { type: "string", demandOption: true, describe: "The URL printed by `rech url <profile>` on the machine with Chrome. Quote it: it contains #" })
|
|
2609
|
+
.example("rech connect 'https://host.example.js.net/rechrome/?profile=you%40example.com#key=…'", ""),
|
|
2590
2610
|
a => handlers.connect(a.url))
|
|
2591
2611
|
.command(["listener", "listeners"], "Control who can connect: listeners, allowed profiles, keys, public URLs", y => y
|
|
2592
2612
|
.command(["ls", "list", "$0"], "List listeners (keys hidden)", {}, () => handlers.listListeners())
|
|
@@ -2630,8 +2650,16 @@ export function rechCli(argv: string[], handlers: RechHandlers) {
|
|
|
2630
2650
|
.demandCommand(1)
|
|
2631
2651
|
.strict()
|
|
2632
2652
|
.help()
|
|
2653
|
+
.alias("help", "h")
|
|
2633
2654
|
.version(false)
|
|
2634
|
-
|
|
2655
|
+
// A parse error (missing argument, unknown option…) shows that command's help above the
|
|
2656
|
+
// error, so the fix is visible. Errors thrown by a command's own handler pass through.
|
|
2657
|
+
.fail((message, error, y) => {
|
|
2658
|
+
if (error) throw error;
|
|
2659
|
+
// Straight to stderr: Bun's console.error would paint the whole help red.
|
|
2660
|
+
y.showHelp((help: string) => process.stderr.write(`${help}\n\n`));
|
|
2661
|
+
throw new Error(`rech: ${/^Not enough non-option arguments/.test(message) ? "missing a required argument; see the usage line above" : message}`);
|
|
2662
|
+
});
|
|
2635
2663
|
}
|
|
2636
2664
|
|
|
2637
2665
|
if (import.meta.main) {
|
package/rechrome.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { hostname, homedir, networkInterfaces } from "os";
|
|
|
10
10
|
import { isIPv4 } from "net";
|
|
11
11
|
import { join, basename, dirname } from "path";
|
|
12
12
|
import { pathToFileURL } from "url";
|
|
13
|
+
import { createRequire } from "node:module";
|
|
13
14
|
import { spawn as cpSpawn } from "child_process";
|
|
14
15
|
import { readFile, writeFile, rename, chmod, mkdir } from "node:fs/promises";
|
|
15
16
|
import { oxmgrInstallCommand, pickDaemonManager, type DaemonManager } from "./daemon-manager.ts";
|
|
@@ -1446,23 +1447,41 @@ async function pmList(mgr: DaemonManager = daemonManager()): Promise<string> {
|
|
|
1446
1447
|
return await new Response(proc.stdout).text();
|
|
1447
1448
|
}
|
|
1448
1449
|
|
|
1450
|
+
// A candidate playwright-cli entry is usable only if the playwright-core it requires actually
|
|
1451
|
+
// resolves FROM that entry — the wrapper does `require('playwright-core/lib/tools/cli-client/program')`,
|
|
1452
|
+
// a deep subpath reachable only through the fork's patched `exports` map. existsSync on the .js is
|
|
1453
|
+
// not the same check: an uninitialised/half-built lib/playwright-cli submodule leaves the wrapper on
|
|
1454
|
+
// disk with no resolvable core, and the failure surfaces later as MODULE_NOT_FOUND inside the daemon.
|
|
1455
|
+
export function playwrightCliIsUsable(jsEntry: string): boolean {
|
|
1456
|
+
try {
|
|
1457
|
+
createRequire(jsEntry).resolve("playwright-core/lib/tools/cli-client/program");
|
|
1458
|
+
return true;
|
|
1459
|
+
} catch {
|
|
1460
|
+
return false;
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1449
1464
|
// Resolve which playwright-cli the daemon runs to drive Chrome. Priority:
|
|
1450
1465
|
// 1. PLAYWRIGHT_CLI env override — explicit, already a full command string.
|
|
1451
1466
|
// 2. Vendored fork in a git checkout (lib/playwright-cli/playwright-cli.js) — the patched
|
|
1452
1467
|
// multi-tab CLI + patched playwright-core (PLAYWRIGHT_MCP_PROFILE_DIRECTORY etc.).
|
|
1453
1468
|
// 3. The fork bundled into the npm tarball (vendor/playwright-cli/playwright-cli.js, produced by
|
|
1454
|
-
// scripts/vendor-cli.sh at prepublish
|
|
1455
|
-
// `bun i -g rechrome`: self-contained, no
|
|
1469
|
+
// scripts/vendor-cli.sh at prepublish, and by `prepare` on `bun install` in a checkout). This
|
|
1470
|
+
// is the batteries-included default for `bun i -g rechrome`: self-contained, no
|
|
1471
|
+
// @playwright/cli dep, no browser-binary download.
|
|
1456
1472
|
// 4. Bare `playwright-cli-multi-tab` on PATH — legacy fallback for a pre-existing global link.
|
|
1473
|
+
// Candidates 2–3 must also pass playwrightCliIsUsable(), so a present-but-broken one falls through.
|
|
1474
|
+
// lib/ stays ahead of vendor/ on purpose: a dev who built the fork wants their patched core, not
|
|
1475
|
+
// the (possibly older) vendor-src snapshot that `prepare` unpacks into vendor/.
|
|
1457
1476
|
// A resolved .js entry is run through `node` on Windows (which can't exec a .js by shebang) and
|
|
1458
1477
|
// bare on POSIX (its `#!/usr/bin/env node` shebang runs it under node, which the relay handshake
|
|
1459
1478
|
// needs — see daemonInstall). serve splits the result on spaces into argv.
|
|
1460
|
-
export function resolvePlaywrightCli(): string {
|
|
1479
|
+
export function resolvePlaywrightCli(root: string = import.meta.dir): string {
|
|
1461
1480
|
if (process.env.PLAYWRIGHT_CLI) return process.env.PLAYWRIGHT_CLI;
|
|
1462
1481
|
const jsEntry = [
|
|
1463
|
-
join(
|
|
1464
|
-
join(
|
|
1465
|
-
].
|
|
1482
|
+
join(root, "lib/playwright-cli/playwright-cli.js"),
|
|
1483
|
+
join(root, "vendor/playwright-cli/playwright-cli.js"),
|
|
1484
|
+
].filter(existsSync).find(playwrightCliIsUsable);
|
|
1466
1485
|
if (jsEntry) return IS_WINDOWS ? `node ${jsEntry}` : jsEntry;
|
|
1467
1486
|
return "playwright-cli-multi-tab";
|
|
1468
1487
|
}
|
|
@@ -2586,7 +2605,8 @@ export function rechCli(argv: string[], handlers: RechHandlers) {
|
|
|
2586
2605
|
? handlers.urlList()
|
|
2587
2606
|
: handlers.printProfileUri(a.profile, a.listener, { local: a.local, save: a.save }))
|
|
2588
2607
|
.command("connect <url>", "Use a URL from another machine in this project (checks it first)", y => y
|
|
2589
|
-
.positional("url", { type: "string", demandOption: true })
|
|
2608
|
+
.positional("url", { type: "string", demandOption: true, describe: "The URL printed by `rech url <profile>` on the machine with Chrome. Quote it: it contains #" })
|
|
2609
|
+
.example("rech connect 'https://host.example.ts.net/rechrome/?profile=you%40example.com#key=…'", ""),
|
|
2590
2610
|
a => handlers.connect(a.url))
|
|
2591
2611
|
.command(["listener", "listeners"], "Control who can connect: listeners, allowed profiles, keys, public URLs", y => y
|
|
2592
2612
|
.command(["ls", "list", "$0"], "List listeners (keys hidden)", {}, () => handlers.listListeners())
|
|
@@ -2630,8 +2650,16 @@ export function rechCli(argv: string[], handlers: RechHandlers) {
|
|
|
2630
2650
|
.demandCommand(1)
|
|
2631
2651
|
.strict()
|
|
2632
2652
|
.help()
|
|
2653
|
+
.alias("help", "h")
|
|
2633
2654
|
.version(false)
|
|
2634
|
-
|
|
2655
|
+
// A parse error (missing argument, unknown option…) shows that command's help above the
|
|
2656
|
+
// error, so the fix is visible. Errors thrown by a command's own handler pass through.
|
|
2657
|
+
.fail((message, error, y) => {
|
|
2658
|
+
if (error) throw error;
|
|
2659
|
+
// Straight to stderr: Bun's console.error would paint the whole help red.
|
|
2660
|
+
y.showHelp((help: string) => process.stderr.write(`${help}\n\n`));
|
|
2661
|
+
throw new Error(`rech: ${/^Not enough non-option arguments/.test(message) ? "missing a required argument; see the usage line above" : message}`);
|
|
2662
|
+
});
|
|
2635
2663
|
}
|
|
2636
2664
|
|
|
2637
2665
|
if (import.meta.main) {
|