@guanzhu.me/pw-cli 0.0.18 → 0.0.20

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guanzhu.me/pw-cli",
3
- "version": "0.0.18",
3
+ "version": "0.0.20",
4
4
  "description": "Persistent Playwright browser CLI with headed defaults, profile support, queueing, and script execution",
5
5
  "bin": {
6
6
  "pw-cli": "./bin/pw-cli.js"
@@ -9,7 +9,27 @@ const crypto = require('crypto');
9
9
  const { execSync } = require('child_process');
10
10
  const { readState, writeState, clearState, getProfileDir } = require('./state');
11
11
  const { probeCDP, findFreePort, sleep, fetchActivePageUrl } = require('./utils');
12
- const { ws, wsServer } = require('../node_modules/@playwright/cli/node_modules/playwright-core/lib/utilsBundleImpl');
12
+
13
+ function loadPlaywrightUtilsBundle() {
14
+ const candidates = [
15
+ '../node_modules/@playwright/cli/node_modules/playwright-core/lib/utilsBundleImpl',
16
+ '../node_modules/@playwright/cli/node_modules/playwright-core/lib/utilsBundleImpl/index.js',
17
+ ];
18
+
19
+ for (const candidate of candidates) {
20
+ try {
21
+ return require(candidate);
22
+ } catch (error) {
23
+ if (error.code !== 'MODULE_NOT_FOUND') {
24
+ throw error;
25
+ }
26
+ }
27
+ }
28
+
29
+ throw new Error('Unable to load playwright-core utilsBundleImpl from @playwright/cli. Reinstall @playwright/cli or playwright.');
30
+ }
31
+
32
+ const { ws, wsServer } = loadPlaywrightUtilsBundle();
13
33
 
14
34
  const DAEMON_SCRIPT = path.join(__dirname, 'launch-daemon.js');
15
35
 
@@ -242,13 +262,14 @@ class ExtensionConnection {
242
262
  }
243
263
 
244
264
  class CDPRelayServer {
245
- constructor(server, browserChannel, userDataDir, executablePath) {
265
+ constructor(server, browserChannel, userDataDir, executablePath, extensionToken) {
246
266
  this._playwrightConnection = null;
247
267
  this._extensionConnection = null;
248
268
  this._nextSessionId = 1;
249
269
  this._browserChannel = browserChannel;
250
270
  this._userDataDir = userDataDir;
251
271
  this._executablePath = executablePath;
272
+ this._extensionToken = extensionToken || null;
252
273
  const uuid = crypto.randomUUID();
253
274
  const address = server.address();
254
275
  this._wsHost = `ws://127.0.0.1:${address.port}`;
@@ -294,6 +315,9 @@ class CDPRelayServer {
294
315
  url.searchParams.set('mcpRelayUrl', relayUrl);
295
316
  url.searchParams.set('client', JSON.stringify({ name: clientName }));
296
317
  url.searchParams.set('protocolVersion', '1');
318
+ if (this._extensionToken) {
319
+ url.searchParams.set('token', this._extensionToken);
320
+ }
297
321
 
298
322
  const executablePath = this._executablePath || resolveExtensionExecutablePath(this._browserChannel);
299
323
  const args = [];
@@ -318,6 +342,13 @@ class CDPRelayServer {
318
342
  return;
319
343
  }
320
344
  if (url.pathname === this._extensionPath) {
345
+ if (this._extensionToken) {
346
+ const token = url.searchParams.get('token');
347
+ if (token !== this._extensionToken) {
348
+ socket.close(4003, 'Invalid token');
349
+ return;
350
+ }
351
+ }
321
352
  this._handleExtensionConnection(socket);
322
353
  return;
323
354
  }
@@ -459,7 +490,8 @@ async function startExtensionRelay(extension) {
459
490
  server.once('error', reject);
460
491
  server.listen(0, '127.0.0.1', resolve);
461
492
  });
462
- const relay = new CDPRelayServer(server, browser, null, null);
493
+ const extensionToken = process.env.PLAYWRIGHT_MCP_EXTENSION_TOKEN || null;
494
+ const relay = new CDPRelayServer(server, browser, null, null, extensionToken);
463
495
  await relay.ensureExtensionConnectionForMCPContext('pw-cli');
464
496
  return { relay, server };
465
497
  }