rechrome 1.8.2 → 1.9.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/package.json +1 -1
- package/rech.js +51 -28
- package/rech.ts +51 -28
package/package.json
CHANGED
package/rech.js
CHANGED
|
@@ -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
|
|
@@ -611,13 +624,19 @@ async function setup(opts: { profile?: string } = {}): Promise<void> {
|
|
|
611
624
|
const statusUrl = `chrome-extension://${extId}/status.html`;
|
|
612
625
|
console.log(`\n Get auth token from the extension:`);
|
|
613
626
|
console.log(` ${statusUrl}`);
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
627
|
+
if (isTTY) {
|
|
628
|
+
Bun.spawn(
|
|
629
|
+
["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
630
|
+
`--profile-directory=${profileDir}`, statusUrl],
|
|
631
|
+
{ stdout: "ignore", stderr: "ignore", detached: true },
|
|
632
|
+
);
|
|
633
|
+
console.log(`\n Or click the extension icon in the Chrome toolbar.`);
|
|
634
|
+
console.log(` Copy the token shown on the page (PLAYWRIGHT_MCP_EXTENSION_TOKEN=...).\n`);
|
|
635
|
+
} else {
|
|
636
|
+
console.log(`\n [agent] Open the URL above in Chrome (profile: ${profileDisplay})`);
|
|
637
|
+
console.log(` [agent] Find PLAYWRIGHT_MCP_EXTENSION_TOKEN=... on that page`);
|
|
638
|
+
console.log(` [agent] Provide the token value on next stdin line:\n`);
|
|
639
|
+
}
|
|
621
640
|
const tokenInput = (await ask(" Paste token: ")).trim();
|
|
622
641
|
const token = tokenInput.replace(/^.*?=/, "").trim();
|
|
623
642
|
if (!token || token.length < 20) { console.error(" Invalid token (too short)"); return null; }
|
|
@@ -639,16 +658,7 @@ async function setup(opts: { profile?: string } = {}): Promise<void> {
|
|
|
639
658
|
const { extId, token } = primary;
|
|
640
659
|
const profileEmail = profileInfoSel.user_name || profileDir;
|
|
641
660
|
|
|
642
|
-
//
|
|
643
|
-
const pwdEnvPath = join(process.cwd(), ".env.local");
|
|
644
|
-
const pwdRechPath = join(process.cwd(), ".rechrome", ".env.local");
|
|
645
|
-
const homeEnvPath = join(process.env.HOME!, ".env.local");
|
|
646
|
-
const saveChoice = (await ask(
|
|
647
|
-
`\n[4/4] Save RECHROME_URL to:\n 1. ${pwdEnvPath} (current dir) [default]\n 2. ${pwdRechPath} (current dir, rechrome-only)\n 3. ${homeEnvPath} (user home)\n\n Choice [1]: `
|
|
648
|
-
)).trim();
|
|
649
|
-
const globalEnvPath = saveChoice === "3" ? homeEnvPath : saveChoice === "2" ? pwdRechPath : pwdEnvPath;
|
|
650
|
-
if (saveChoice === "2") mkdirSync(join(process.cwd(), ".rechrome"), { recursive: true });
|
|
651
|
-
const existing = await file(globalEnvPath).text().catch(() => "");
|
|
661
|
+
// Build RECHROME_URL and show it before asking where to save
|
|
652
662
|
const rechUrl = new URL(url);
|
|
653
663
|
if (!rechUrl.username) rechUrl.username = randomBytes(9).toString("base64url");
|
|
654
664
|
rechUrl.searchParams.set("extension_id", extId);
|
|
@@ -656,14 +666,27 @@ async function setup(opts: { profile?: string } = {}): Promise<void> {
|
|
|
656
666
|
rechUrl.searchParams.set("profile", profileEmail);
|
|
657
667
|
if (userDataDir) rechUrl.searchParams.set("user_data_dir", userDataDir);
|
|
658
668
|
const newLine = `RECHROME_URL=${rechUrl.toString()}`;
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
669
|
+
console.log(`\n[4/4] Your RECHROME_URL:\n\n ${newLine}\n`);
|
|
670
|
+
if (!isTTY) console.log(` [agent] Provide save destination on next stdin line: 1=cwd, 2=cwd rechrome-only, 3=home, 4=skip\n`);
|
|
671
|
+
|
|
672
|
+
const pwdEnvPath = join(process.cwd(), ".env.local");
|
|
673
|
+
const pwdRechPath = join(process.cwd(), ".rechrome", ".env.local");
|
|
674
|
+
const homeEnvPath = join(process.env.HOME!, ".env.local");
|
|
675
|
+
const saveChoice = (await ask(
|
|
676
|
+
`Save to:\n 1. ${pwdEnvPath} (current dir) [default]\n 2. ${pwdRechPath} (current dir, rechrome-only)\n 3. ${homeEnvPath} (user home)\n 4. Skip (already copied)\n\n Choice [1]: `
|
|
677
|
+
)).trim();
|
|
678
|
+
if (saveChoice !== "4") {
|
|
679
|
+
const globalEnvPath = saveChoice === "3" ? homeEnvPath : saveChoice === "2" ? pwdRechPath : pwdEnvPath;
|
|
680
|
+
if (saveChoice === "2") mkdirSync(join(process.cwd(), ".rechrome"), { recursive: true });
|
|
681
|
+
const existing = await file(globalEnvPath).text().catch(() => "");
|
|
682
|
+
const keysToRemove = ["PLAYWRIGHT_MCP_USER_DATA_DIR", "PLAYWRIGHT_MCP_EXTENSION_ID", "PLAYWRIGHT_MCP_EXTENSION_TOKEN", "PLAYWRIGHT_MCP_PROFILE_DIRECTORY"];
|
|
683
|
+
let lines = existing.trimEnd().split("\n").filter(l => !keysToRemove.some(k => l.startsWith(`${k}=`)));
|
|
684
|
+
const rechIdx = lines.findIndex(l => l.startsWith("RECHROME_URL="));
|
|
685
|
+
if (rechIdx >= 0) lines[rechIdx] = newLine;
|
|
686
|
+
else lines.push(newLine);
|
|
687
|
+
await Bun.write(globalEnvPath, lines.join("\n").trim() + "\n");
|
|
688
|
+
console.log(`\nSaved to ${globalEnvPath}`);
|
|
689
|
+
}
|
|
667
690
|
|
|
668
691
|
// Save primary to token registry
|
|
669
692
|
await saveTokenEntry(profileEmail, { extensionId: extId, token, profileDir, userDataDir: userDataDir ?? undefined });
|
package/rech.ts
CHANGED
|
@@ -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
|
|
@@ -611,13 +624,19 @@ async function setup(opts: { profile?: string } = {}): Promise<void> {
|
|
|
611
624
|
const statusUrl = `chrome-extension://${extId}/status.html`;
|
|
612
625
|
console.log(`\n Get auth token from the extension:`);
|
|
613
626
|
console.log(` ${statusUrl}`);
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
627
|
+
if (isTTY) {
|
|
628
|
+
Bun.spawn(
|
|
629
|
+
["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
630
|
+
`--profile-directory=${profileDir}`, statusUrl],
|
|
631
|
+
{ stdout: "ignore", stderr: "ignore", detached: true },
|
|
632
|
+
);
|
|
633
|
+
console.log(`\n Or click the extension icon in the Chrome toolbar.`);
|
|
634
|
+
console.log(` Copy the token shown on the page (PLAYWRIGHT_MCP_EXTENSION_TOKEN=...).\n`);
|
|
635
|
+
} else {
|
|
636
|
+
console.log(`\n [agent] Open the URL above in Chrome (profile: ${profileDisplay})`);
|
|
637
|
+
console.log(` [agent] Find PLAYWRIGHT_MCP_EXTENSION_TOKEN=... on that page`);
|
|
638
|
+
console.log(` [agent] Provide the token value on next stdin line:\n`);
|
|
639
|
+
}
|
|
621
640
|
const tokenInput = (await ask(" Paste token: ")).trim();
|
|
622
641
|
const token = tokenInput.replace(/^.*?=/, "").trim();
|
|
623
642
|
if (!token || token.length < 20) { console.error(" Invalid token (too short)"); return null; }
|
|
@@ -639,16 +658,7 @@ async function setup(opts: { profile?: string } = {}): Promise<void> {
|
|
|
639
658
|
const { extId, token } = primary;
|
|
640
659
|
const profileEmail = profileInfoSel.user_name || profileDir;
|
|
641
660
|
|
|
642
|
-
//
|
|
643
|
-
const pwdEnvPath = join(process.cwd(), ".env.local");
|
|
644
|
-
const pwdRechPath = join(process.cwd(), ".rechrome", ".env.local");
|
|
645
|
-
const homeEnvPath = join(process.env.HOME!, ".env.local");
|
|
646
|
-
const saveChoice = (await ask(
|
|
647
|
-
`\n[4/4] Save RECHROME_URL to:\n 1. ${pwdEnvPath} (current dir) [default]\n 2. ${pwdRechPath} (current dir, rechrome-only)\n 3. ${homeEnvPath} (user home)\n\n Choice [1]: `
|
|
648
|
-
)).trim();
|
|
649
|
-
const globalEnvPath = saveChoice === "3" ? homeEnvPath : saveChoice === "2" ? pwdRechPath : pwdEnvPath;
|
|
650
|
-
if (saveChoice === "2") mkdirSync(join(process.cwd(), ".rechrome"), { recursive: true });
|
|
651
|
-
const existing = await file(globalEnvPath).text().catch(() => "");
|
|
661
|
+
// Build RECHROME_URL and show it before asking where to save
|
|
652
662
|
const rechUrl = new URL(url);
|
|
653
663
|
if (!rechUrl.username) rechUrl.username = randomBytes(9).toString("base64url");
|
|
654
664
|
rechUrl.searchParams.set("extension_id", extId);
|
|
@@ -656,14 +666,27 @@ async function setup(opts: { profile?: string } = {}): Promise<void> {
|
|
|
656
666
|
rechUrl.searchParams.set("profile", profileEmail);
|
|
657
667
|
if (userDataDir) rechUrl.searchParams.set("user_data_dir", userDataDir);
|
|
658
668
|
const newLine = `RECHROME_URL=${rechUrl.toString()}`;
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
669
|
+
console.log(`\n[4/4] Your RECHROME_URL:\n\n ${newLine}\n`);
|
|
670
|
+
if (!isTTY) console.log(` [agent] Provide save destination on next stdin line: 1=cwd, 2=cwd rechrome-only, 3=home, 4=skip\n`);
|
|
671
|
+
|
|
672
|
+
const pwdEnvPath = join(process.cwd(), ".env.local");
|
|
673
|
+
const pwdRechPath = join(process.cwd(), ".rechrome", ".env.local");
|
|
674
|
+
const homeEnvPath = join(process.env.HOME!, ".env.local");
|
|
675
|
+
const saveChoice = (await ask(
|
|
676
|
+
`Save to:\n 1. ${pwdEnvPath} (current dir) [default]\n 2. ${pwdRechPath} (current dir, rechrome-only)\n 3. ${homeEnvPath} (user home)\n 4. Skip (already copied)\n\n Choice [1]: `
|
|
677
|
+
)).trim();
|
|
678
|
+
if (saveChoice !== "4") {
|
|
679
|
+
const globalEnvPath = saveChoice === "3" ? homeEnvPath : saveChoice === "2" ? pwdRechPath : pwdEnvPath;
|
|
680
|
+
if (saveChoice === "2") mkdirSync(join(process.cwd(), ".rechrome"), { recursive: true });
|
|
681
|
+
const existing = await file(globalEnvPath).text().catch(() => "");
|
|
682
|
+
const keysToRemove = ["PLAYWRIGHT_MCP_USER_DATA_DIR", "PLAYWRIGHT_MCP_EXTENSION_ID", "PLAYWRIGHT_MCP_EXTENSION_TOKEN", "PLAYWRIGHT_MCP_PROFILE_DIRECTORY"];
|
|
683
|
+
let lines = existing.trimEnd().split("\n").filter(l => !keysToRemove.some(k => l.startsWith(`${k}=`)));
|
|
684
|
+
const rechIdx = lines.findIndex(l => l.startsWith("RECHROME_URL="));
|
|
685
|
+
if (rechIdx >= 0) lines[rechIdx] = newLine;
|
|
686
|
+
else lines.push(newLine);
|
|
687
|
+
await Bun.write(globalEnvPath, lines.join("\n").trim() + "\n");
|
|
688
|
+
console.log(`\nSaved to ${globalEnvPath}`);
|
|
689
|
+
}
|
|
667
690
|
|
|
668
691
|
// Save primary to token registry
|
|
669
692
|
await saveTokenEntry(profileEmail, { extensionId: extId, token, profileDir, userDataDir: userDataDir ?? undefined });
|