rechrome 1.9.0 → 1.9.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/package.json +1 -1
- package/rech.js +39 -14
- package/rech.ts +39 -14
package/package.json
CHANGED
package/rech.js
CHANGED
|
@@ -362,7 +362,7 @@ async function callServe(
|
|
|
362
362
|
process.exit(1);
|
|
363
363
|
});
|
|
364
364
|
if (res.status === 401) {
|
|
365
|
-
console.error(`[rech] rech-client -> rech-server[ok]\n -x: token rejected -> playwright[unknown]`);
|
|
365
|
+
console.error(`[rech] rech-client -> rech-server[ok]\n -x: token rejected (used: ${key.slice(0, 6)}...) -> playwright[unknown]`);
|
|
366
366
|
process.exit(1);
|
|
367
367
|
}
|
|
368
368
|
return res.json();
|
|
@@ -517,10 +517,23 @@ async function daemonUninstall(): Promise<void> {
|
|
|
517
517
|
async function setup(opts: { profile?: string } = {}): Promise<void> {
|
|
518
518
|
const { createInterface } = await import("readline");
|
|
519
519
|
const isTTY = process.stdin.isTTY ?? false;
|
|
520
|
-
|
|
520
|
+
let rl: ReturnType<typeof createInterface> | null = null;
|
|
521
|
+
let stdinQueue: string[] | null = null;
|
|
522
|
+
if (isTTY) {
|
|
523
|
+
rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
524
|
+
} else {
|
|
525
|
+
// Pre-read all piped stdin lines so readline close doesn't block later prompts
|
|
526
|
+
stdinQueue = await new Promise<string[]>(resolve => {
|
|
527
|
+
const lines: string[] = [];
|
|
528
|
+
const r = createInterface({ input: process.stdin });
|
|
529
|
+
r.on("line", l => lines.push(l));
|
|
530
|
+
r.on("close", () => resolve(lines));
|
|
531
|
+
});
|
|
532
|
+
}
|
|
521
533
|
const ask = (q: string, def = "") => {
|
|
522
|
-
|
|
523
|
-
|
|
534
|
+
process.stdout.write(q);
|
|
535
|
+
if (stdinQueue !== null) { const ans = stdinQueue.shift() ?? def; process.stdout.write(ans + "\n"); return Promise.resolve(ans); }
|
|
536
|
+
return new Promise<string>(r => rl!.question("", ans => r(ans || def)));
|
|
524
537
|
};
|
|
525
538
|
|
|
526
539
|
// [1/4] Daemon
|
|
@@ -536,13 +549,18 @@ async function setup(opts: { profile?: string } = {}): Promise<void> {
|
|
|
536
549
|
const { host, port, protocol } = parseUrl(url);
|
|
537
550
|
|
|
538
551
|
const { key: serveKey } = parseUrl(url);
|
|
539
|
-
|
|
552
|
+
// First check if server is up at all (unauthenticated root), then verify our key matches
|
|
553
|
+
const anonPing = await fetch(`${protocol}://${host}:${port}/`, { signal: AbortSignal.timeout(2000) }).catch(() => null);
|
|
554
|
+
const authPing = anonPing ? await fetch(`${protocol}://${host}:${port}/ping`, {
|
|
540
555
|
headers: { Authorization: `Bearer ${serveKey}` },
|
|
541
556
|
signal: AbortSignal.timeout(2000),
|
|
542
|
-
}).catch(() => null);
|
|
543
|
-
if (authPing?.ok) {
|
|
557
|
+
}).catch(() => null) : null;
|
|
558
|
+
if (anonPing && authPing?.ok) {
|
|
544
559
|
console.log(` Already running at ${protocol}://${host}:${port} — skipping reinstall`);
|
|
545
560
|
await runOxmgr(["service", "install"]);
|
|
561
|
+
} else if (anonPing && !authPing?.ok) {
|
|
562
|
+
console.log(` Server running but key mismatch — reinstalling with new key`);
|
|
563
|
+
await daemonInstall(url);
|
|
546
564
|
} else {
|
|
547
565
|
await daemonInstall(url);
|
|
548
566
|
console.log(` Registered daemon: ${OXMGR_PROCESS_NAME}`);
|
|
@@ -611,13 +629,19 @@ async function setup(opts: { profile?: string } = {}): Promise<void> {
|
|
|
611
629
|
const statusUrl = `chrome-extension://${extId}/status.html`;
|
|
612
630
|
console.log(`\n Get auth token from the extension:`);
|
|
613
631
|
console.log(` ${statusUrl}`);
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
632
|
+
if (isTTY) {
|
|
633
|
+
Bun.spawn(
|
|
634
|
+
["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
635
|
+
`--profile-directory=${profileDir}`, statusUrl],
|
|
636
|
+
{ stdout: "ignore", stderr: "ignore", detached: true },
|
|
637
|
+
);
|
|
638
|
+
console.log(`\n Or click the extension icon in the Chrome toolbar.`);
|
|
639
|
+
console.log(` Copy the token shown on the page (PLAYWRIGHT_MCP_EXTENSION_TOKEN=...).\n`);
|
|
640
|
+
} else {
|
|
641
|
+
console.log(`\n [agent] Open the URL above in Chrome (profile: ${profileDisplay})`);
|
|
642
|
+
console.log(` [agent] Find PLAYWRIGHT_MCP_EXTENSION_TOKEN=... on that page`);
|
|
643
|
+
console.log(` [agent] Provide the token value on next stdin line:\n`);
|
|
644
|
+
}
|
|
621
645
|
const tokenInput = (await ask(" Paste token: ")).trim();
|
|
622
646
|
const token = tokenInput.replace(/^.*?=/, "").trim();
|
|
623
647
|
if (!token || token.length < 20) { console.error(" Invalid token (too short)"); return null; }
|
|
@@ -648,6 +672,7 @@ async function setup(opts: { profile?: string } = {}): Promise<void> {
|
|
|
648
672
|
if (userDataDir) rechUrl.searchParams.set("user_data_dir", userDataDir);
|
|
649
673
|
const newLine = `RECHROME_URL=${rechUrl.toString()}`;
|
|
650
674
|
console.log(`\n[4/4] Your RECHROME_URL:\n\n ${newLine}\n`);
|
|
675
|
+
if (!isTTY) console.log(` [agent] Provide save destination on next stdin line: 1=cwd, 2=cwd rechrome-only, 3=home, 4=skip\n`);
|
|
651
676
|
|
|
652
677
|
const pwdEnvPath = join(process.cwd(), ".env.local");
|
|
653
678
|
const pwdRechPath = join(process.cwd(), ".rechrome", ".env.local");
|
package/rech.ts
CHANGED
|
@@ -362,7 +362,7 @@ async function callServe(
|
|
|
362
362
|
process.exit(1);
|
|
363
363
|
});
|
|
364
364
|
if (res.status === 401) {
|
|
365
|
-
console.error(`[rech] rech-client -> rech-server[ok]\n -x: token rejected -> playwright[unknown]`);
|
|
365
|
+
console.error(`[rech] rech-client -> rech-server[ok]\n -x: token rejected (used: ${key.slice(0, 6)}...) -> playwright[unknown]`);
|
|
366
366
|
process.exit(1);
|
|
367
367
|
}
|
|
368
368
|
return res.json();
|
|
@@ -517,10 +517,23 @@ async function daemonUninstall(): Promise<void> {
|
|
|
517
517
|
async function setup(opts: { profile?: string } = {}): Promise<void> {
|
|
518
518
|
const { createInterface } = await import("readline");
|
|
519
519
|
const isTTY = process.stdin.isTTY ?? false;
|
|
520
|
-
|
|
520
|
+
let rl: ReturnType<typeof createInterface> | null = null;
|
|
521
|
+
let stdinQueue: string[] | null = null;
|
|
522
|
+
if (isTTY) {
|
|
523
|
+
rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
524
|
+
} else {
|
|
525
|
+
// Pre-read all piped stdin lines so readline close doesn't block later prompts
|
|
526
|
+
stdinQueue = await new Promise<string[]>(resolve => {
|
|
527
|
+
const lines: string[] = [];
|
|
528
|
+
const r = createInterface({ input: process.stdin });
|
|
529
|
+
r.on("line", l => lines.push(l));
|
|
530
|
+
r.on("close", () => resolve(lines));
|
|
531
|
+
});
|
|
532
|
+
}
|
|
521
533
|
const ask = (q: string, def = "") => {
|
|
522
|
-
|
|
523
|
-
|
|
534
|
+
process.stdout.write(q);
|
|
535
|
+
if (stdinQueue !== null) { const ans = stdinQueue.shift() ?? def; process.stdout.write(ans + "\n"); return Promise.resolve(ans); }
|
|
536
|
+
return new Promise<string>(r => rl!.question("", ans => r(ans || def)));
|
|
524
537
|
};
|
|
525
538
|
|
|
526
539
|
// [1/4] Daemon
|
|
@@ -536,13 +549,18 @@ async function setup(opts: { profile?: string } = {}): Promise<void> {
|
|
|
536
549
|
const { host, port, protocol } = parseUrl(url);
|
|
537
550
|
|
|
538
551
|
const { key: serveKey } = parseUrl(url);
|
|
539
|
-
|
|
552
|
+
// First check if server is up at all (unauthenticated root), then verify our key matches
|
|
553
|
+
const anonPing = await fetch(`${protocol}://${host}:${port}/`, { signal: AbortSignal.timeout(2000) }).catch(() => null);
|
|
554
|
+
const authPing = anonPing ? await fetch(`${protocol}://${host}:${port}/ping`, {
|
|
540
555
|
headers: { Authorization: `Bearer ${serveKey}` },
|
|
541
556
|
signal: AbortSignal.timeout(2000),
|
|
542
|
-
}).catch(() => null);
|
|
543
|
-
if (authPing?.ok) {
|
|
557
|
+
}).catch(() => null) : null;
|
|
558
|
+
if (anonPing && authPing?.ok) {
|
|
544
559
|
console.log(` Already running at ${protocol}://${host}:${port} — skipping reinstall`);
|
|
545
560
|
await runOxmgr(["service", "install"]);
|
|
561
|
+
} else if (anonPing && !authPing?.ok) {
|
|
562
|
+
console.log(` Server running but key mismatch — reinstalling with new key`);
|
|
563
|
+
await daemonInstall(url);
|
|
546
564
|
} else {
|
|
547
565
|
await daemonInstall(url);
|
|
548
566
|
console.log(` Registered daemon: ${OXMGR_PROCESS_NAME}`);
|
|
@@ -611,13 +629,19 @@ async function setup(opts: { profile?: string } = {}): Promise<void> {
|
|
|
611
629
|
const statusUrl = `chrome-extension://${extId}/status.html`;
|
|
612
630
|
console.log(`\n Get auth token from the extension:`);
|
|
613
631
|
console.log(` ${statusUrl}`);
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
632
|
+
if (isTTY) {
|
|
633
|
+
Bun.spawn(
|
|
634
|
+
["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
635
|
+
`--profile-directory=${profileDir}`, statusUrl],
|
|
636
|
+
{ stdout: "ignore", stderr: "ignore", detached: true },
|
|
637
|
+
);
|
|
638
|
+
console.log(`\n Or click the extension icon in the Chrome toolbar.`);
|
|
639
|
+
console.log(` Copy the token shown on the page (PLAYWRIGHT_MCP_EXTENSION_TOKEN=...).\n`);
|
|
640
|
+
} else {
|
|
641
|
+
console.log(`\n [agent] Open the URL above in Chrome (profile: ${profileDisplay})`);
|
|
642
|
+
console.log(` [agent] Find PLAYWRIGHT_MCP_EXTENSION_TOKEN=... on that page`);
|
|
643
|
+
console.log(` [agent] Provide the token value on next stdin line:\n`);
|
|
644
|
+
}
|
|
621
645
|
const tokenInput = (await ask(" Paste token: ")).trim();
|
|
622
646
|
const token = tokenInput.replace(/^.*?=/, "").trim();
|
|
623
647
|
if (!token || token.length < 20) { console.error(" Invalid token (too short)"); return null; }
|
|
@@ -648,6 +672,7 @@ async function setup(opts: { profile?: string } = {}): Promise<void> {
|
|
|
648
672
|
if (userDataDir) rechUrl.searchParams.set("user_data_dir", userDataDir);
|
|
649
673
|
const newLine = `RECHROME_URL=${rechUrl.toString()}`;
|
|
650
674
|
console.log(`\n[4/4] Your RECHROME_URL:\n\n ${newLine}\n`);
|
|
675
|
+
if (!isTTY) console.log(` [agent] Provide save destination on next stdin line: 1=cwd, 2=cwd rechrome-only, 3=home, 4=skip\n`);
|
|
651
676
|
|
|
652
677
|
const pwdEnvPath = join(process.cwd(), ".env.local");
|
|
653
678
|
const pwdRechPath = join(process.cwd(), ".rechrome", ".env.local");
|