rechrome 1.7.0 → 1.8.0

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.
Files changed (3) hide show
  1. package/package.json +1 -1
  2. package/rech.js +39 -5
  3. package/rech.ts +39 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rechrome",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/snomiao/rechrome.git"
package/rech.js CHANGED
@@ -338,14 +338,38 @@ async function callServe(
338
338
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${key}` },
339
339
  body: JSON.stringify({ args, identity, env }),
340
340
  signal: AbortSignal.timeout(70_000),
341
- }).catch((e) => { console.error(`[rech] ${e.message}`); process.exit(1); });
342
- if (res.status === 401) { console.error("Unauthorized: bad key"); process.exit(1); }
341
+ }).catch(async (e) => {
342
+ console.error(`[rech] ${e.message}`);
343
+ const dnsResult = await import("dns/promises").then(m => m.lookup(host)).catch(() => null);
344
+ if (!dnsResult) {
345
+ console.error(`[rech] rech-client\n -x: DNS failed -> ${host}[unknown] -> rech-server[unknown]`);
346
+ } else {
347
+ const tcpOk = await new Promise<boolean>(resolve => {
348
+ import("net").then(({ createConnection }) => {
349
+ const s = createConnection({ host, port: Number(port), timeout: 3000 });
350
+ s.on("connect", () => { s.destroy(); resolve(true); });
351
+ s.on("error", () => resolve(false));
352
+ s.on("timeout", () => { s.destroy(); resolve(false); });
353
+ });
354
+ });
355
+ if (tcpOk) {
356
+ console.error(`[rech] rech-client -> ${host}:${port}\n -x: connection refused -> rech-server[unknown]`);
357
+ } else {
358
+ console.error(`[rech] rech-client -> ${host}(${dnsResult.address})\n -x: port ${port} unreachable -> rech-server[unknown]`);
359
+ }
360
+ }
361
+ process.exit(1);
362
+ });
363
+ if (res.status === 401) {
364
+ console.error(`[rech] rech-client -> rech-server[ok]\n -x: token rejected -> playwright[unknown]`);
365
+ process.exit(1);
366
+ }
343
367
  return res.json();
344
368
  }
345
369
 
346
370
  async function run(url: string, args: string[]) {
347
- const { host, port, protocol } = parseUrl(url);
348
- const effectiveProfile = parseUrl(url).profileDirectory || process.env.PLAYWRIGHT_MCP_PROFILE_DIRECTORY;
371
+ const { host, port, protocol, extensionId, extensionToken, profileDirectory, userDataDir } = parseUrl(url);
372
+ const effectiveProfile = profileDirectory || process.env.PLAYWRIGHT_MCP_PROFILE_DIRECTORY;
349
373
  const displayProfile = effectiveProfile ? await resolveProfileEmail(effectiveProfile) : undefined;
350
374
  const identity = await getClientIdentity();
351
375
  const profileSuffix = displayProfile ? ` profile:${displayProfile}` : "";
@@ -353,11 +377,21 @@ async function run(url: string, args: string[]) {
353
377
  `[rech] connecting to ${host}:${port} (identity: ${identity.gitUrl || `${identity.hostname}:${identity.cwd}`}${profileSuffix})`,
354
378
  );
355
379
 
380
+ const resolvedEnv = await getClientEnv({ extensionId, extensionToken, profileDirectory, userDataDir });
356
381
  const { status, stdout, stderr, files, existingSession } = await callServe(url, args);
357
382
 
358
383
  if (existingSession)
359
384
  console.error(`[rech] session already has open tabs — listing existing tabs instead of opening a new window`);
360
- if (stderr) process.stderr.write(stderr);
385
+ if (stderr) {
386
+ if (stderr.includes('Extension connection timeout')) {
387
+ const hasToken = !!resolvedEnv["PLAYWRIGHT_MCP_EXTENSION_TOKEN"];
388
+ const last = hasToken
389
+ ? ` -x: extension token rejected -> extension[unknown]`
390
+ : ` -> extension[not installed] (run: rech setup)`;
391
+ console.error(`[rech] rech-client -> rech-server[ok] -> playwright[ok]\n${last}`);
392
+ }
393
+ process.stderr.write(stderr);
394
+ }
361
395
  if (stdout) process.stdout.write(stdout);
362
396
 
363
397
  if (files?.length) {
package/rech.ts CHANGED
@@ -338,14 +338,38 @@ async function callServe(
338
338
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${key}` },
339
339
  body: JSON.stringify({ args, identity, env }),
340
340
  signal: AbortSignal.timeout(70_000),
341
- }).catch((e) => { console.error(`[rech] ${e.message}`); process.exit(1); });
342
- if (res.status === 401) { console.error("Unauthorized: bad key"); process.exit(1); }
341
+ }).catch(async (e) => {
342
+ console.error(`[rech] ${e.message}`);
343
+ const dnsResult = await import("dns/promises").then(m => m.lookup(host)).catch(() => null);
344
+ if (!dnsResult) {
345
+ console.error(`[rech] rech-client\n -x: DNS failed -> ${host}[unknown] -> rech-server[unknown]`);
346
+ } else {
347
+ const tcpOk = await new Promise<boolean>(resolve => {
348
+ import("net").then(({ createConnection }) => {
349
+ const s = createConnection({ host, port: Number(port), timeout: 3000 });
350
+ s.on("connect", () => { s.destroy(); resolve(true); });
351
+ s.on("error", () => resolve(false));
352
+ s.on("timeout", () => { s.destroy(); resolve(false); });
353
+ });
354
+ });
355
+ if (tcpOk) {
356
+ console.error(`[rech] rech-client -> ${host}:${port}\n -x: connection refused -> rech-server[unknown]`);
357
+ } else {
358
+ console.error(`[rech] rech-client -> ${host}(${dnsResult.address})\n -x: port ${port} unreachable -> rech-server[unknown]`);
359
+ }
360
+ }
361
+ process.exit(1);
362
+ });
363
+ if (res.status === 401) {
364
+ console.error(`[rech] rech-client -> rech-server[ok]\n -x: token rejected -> playwright[unknown]`);
365
+ process.exit(1);
366
+ }
343
367
  return res.json();
344
368
  }
345
369
 
346
370
  async function run(url: string, args: string[]) {
347
- const { host, port, protocol } = parseUrl(url);
348
- const effectiveProfile = parseUrl(url).profileDirectory || process.env.PLAYWRIGHT_MCP_PROFILE_DIRECTORY;
371
+ const { host, port, protocol, extensionId, extensionToken, profileDirectory, userDataDir } = parseUrl(url);
372
+ const effectiveProfile = profileDirectory || process.env.PLAYWRIGHT_MCP_PROFILE_DIRECTORY;
349
373
  const displayProfile = effectiveProfile ? await resolveProfileEmail(effectiveProfile) : undefined;
350
374
  const identity = await getClientIdentity();
351
375
  const profileSuffix = displayProfile ? ` profile:${displayProfile}` : "";
@@ -353,11 +377,21 @@ async function run(url: string, args: string[]) {
353
377
  `[rech] connecting to ${host}:${port} (identity: ${identity.gitUrl || `${identity.hostname}:${identity.cwd}`}${profileSuffix})`,
354
378
  );
355
379
 
380
+ const resolvedEnv = await getClientEnv({ extensionId, extensionToken, profileDirectory, userDataDir });
356
381
  const { status, stdout, stderr, files, existingSession } = await callServe(url, args);
357
382
 
358
383
  if (existingSession)
359
384
  console.error(`[rech] session already has open tabs — listing existing tabs instead of opening a new window`);
360
- if (stderr) process.stderr.write(stderr);
385
+ if (stderr) {
386
+ if (stderr.includes('Extension connection timeout')) {
387
+ const hasToken = !!resolvedEnv["PLAYWRIGHT_MCP_EXTENSION_TOKEN"];
388
+ const last = hasToken
389
+ ? ` -x: extension token rejected -> extension[unknown]`
390
+ : ` -> extension[not installed] (run: rech setup)`;
391
+ console.error(`[rech] rech-client -> rech-server[ok] -> playwright[ok]\n${last}`);
392
+ }
393
+ process.stderr.write(stderr);
394
+ }
361
395
  if (stdout) process.stdout.write(stdout);
362
396
 
363
397
  if (files?.length) {