@cotestdev/mcp_playwright 0.0.48 → 0.0.49

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.
@@ -28,7 +28,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var program_exports = {};
30
30
  __export(program_exports, {
31
- printResponse: () => printResponse,
32
31
  program: () => program
33
32
  });
34
33
  module.exports = __toCommonJS(program_exports);
@@ -40,102 +39,66 @@ var import_os = __toESM(require("os"));
40
39
  var import_path = __toESM(require("path"));
41
40
  var import_socketConnection = require("./socketConnection");
42
41
  class Session {
43
- constructor(name, connection) {
42
+ constructor(name, options) {
44
43
  this._nextMessageId = 1;
45
44
  this._callbacks = /* @__PURE__ */ new Map();
46
45
  this.name = name;
47
- this._connection = connection;
48
- this._connection.onmessage = (message) => this._onMessage(message);
49
- this._connection.onclose = () => this.close();
46
+ this._socketPath = this._daemonSocketPath();
47
+ this._options = options;
50
48
  }
51
49
  async run(args) {
52
- return await this._send("run", { args });
50
+ return await this._send("run", { args, cwd: process.cwd() });
53
51
  }
54
52
  async stop() {
55
- await this._send("stop");
53
+ if (!await this.canConnect()) {
54
+ console.log(`Session '${this.name}' is not running.`);
55
+ return;
56
+ }
57
+ await this._send("stop").catch((e) => {
58
+ if (e.message !== "Session closed")
59
+ throw e;
60
+ });
56
61
  this.close();
62
+ if (import_os.default.platform() !== "win32")
63
+ await import_fs.default.promises.unlink(this._socketPath).catch(() => {
64
+ });
65
+ console.log(`Session '${this.name}' stopped.`);
66
+ }
67
+ async restart(options) {
68
+ await this.stop();
69
+ this._options = options;
70
+ await this._startDaemonIfNeeded();
57
71
  }
58
72
  async _send(method, params = {}) {
73
+ const connection = await this._startDaemonIfNeeded();
59
74
  const messageId = this._nextMessageId++;
60
75
  const message = {
61
76
  id: messageId,
62
77
  method,
63
- params
78
+ params,
79
+ version: this._options.daemonVersion
64
80
  };
65
- await this._connection.send(message);
66
- return new Promise((resolve, reject) => {
67
- this._callbacks.set(messageId, { resolve, reject });
81
+ const responsePromise = new Promise((resolve, reject) => {
82
+ this._callbacks.set(messageId, { resolve, reject, method, params });
68
83
  });
84
+ const [result] = await Promise.all([responsePromise, connection.send(message)]);
85
+ return result;
69
86
  }
70
87
  close() {
88
+ if (!this._connection)
89
+ return;
71
90
  for (const callback of this._callbacks.values())
72
91
  callback.reject(new Error("Session closed"));
73
92
  this._callbacks.clear();
74
93
  this._connection.close();
94
+ this._connection = void 0;
75
95
  }
76
- _onMessage(object) {
77
- if (object.id && this._callbacks.has(object.id)) {
78
- const callback = this._callbacks.get(object.id);
79
- this._callbacks.delete(object.id);
80
- if (object.error)
81
- callback.reject(new Error(object.error));
82
- else
83
- callback.resolve(object.result);
84
- } else if (object.id) {
85
- throw new Error(`Unexpected message id: ${object.id}`);
86
- } else {
87
- throw new Error(`Unexpected message without id: ${JSON.stringify(object)}`);
88
- }
89
- }
90
- }
91
- class SessionManager {
92
- constructor(options) {
93
- this._options = options;
94
- }
95
- async list() {
96
- const dir = daemonProfilesDir;
97
- try {
98
- const files = await import_fs.default.promises.readdir(dir);
99
- const sessions = /* @__PURE__ */ new Map();
100
- for (const file of files) {
101
- if (file.startsWith("ud-")) {
102
- const sessionName = file.split("-")[1];
103
- const live = await this._canConnect(sessionName);
104
- sessions.set(sessionName, live);
105
- }
106
- }
107
- return sessions;
108
- } catch {
109
- return /* @__PURE__ */ new Map();
110
- }
111
- }
112
- async run(args) {
113
- const sessionName = this._resolveSessionName(args.session);
114
- const session = await this._connect(sessionName);
115
- const result = await session.run(args);
116
- await printResponse(result);
117
- session.close();
118
- }
119
- async stop(sessionName) {
120
- sessionName = this._resolveSessionName(sessionName);
121
- if (!await this._canConnect(sessionName)) {
122
- console.log(`Session '${sessionName}' is not running.`);
123
- return;
124
- }
125
- const session = await this._connect(sessionName);
126
- await session.stop();
127
- console.log(`Session '${sessionName}' stopped.`);
128
- }
129
- async delete(sessionName) {
130
- sessionName = this._resolveSessionName(sessionName);
131
- if (await this._canConnect(sessionName)) {
132
- const session = await this._connect(sessionName);
133
- await session.stop();
134
- }
96
+ async delete() {
97
+ await this.stop();
135
98
  const dataDirs = await import_fs.default.promises.readdir(daemonProfilesDir).catch(() => []);
136
- const matchingDirs = dataDirs.filter((dir) => dir.startsWith(`ud-${sessionName}-`));
99
+ const matchingDirs = dataDirs.filter((dir) => dir.startsWith(`ud-${this.name}-`));
137
100
  if (matchingDirs.length === 0) {
138
- console.log(`No user data found for session '${sessionName}'.`);
101
+ console.log(`No user data found for session '${this.name}'.`);
139
102
  return;
140
103
  }
141
104
  for (const dir of matchingDirs) {
@@ -143,11 +106,11 @@ class SessionManager {
143
106
  for (let i = 0; i < 5; i++) {
144
107
  try {
145
108
  await import_fs.default.promises.rm(userDataDir, { recursive: true });
146
- console.log(`Deleted user data for session '${sessionName}'.`);
109
+ console.log(`Deleted user data for session '${this.name}'.`);
147
110
  break;
148
111
  } catch (e) {
149
112
  if (e.code === "ENOENT") {
150
- console.log(`No user data found for session '${sessionName}'.`);
113
+ console.log(`No user data found for session '${this.name}'.`);
151
114
  break;
152
115
  }
153
116
  await new Promise((resolve) => setTimeout(resolve, 1e3));
@@ -156,39 +119,70 @@ class SessionManager {
156
119
  }
157
120
  }
158
121
  }
159
- if (import_os.default.platform() !== "win32") {
160
- const socketPath = this._daemonSocketPath(sessionName);
161
- await import_fs.default.promises.unlink(socketPath).catch(() => {
122
+ }
123
+ async _connect() {
124
+ return await new Promise((resolve) => {
125
+ const socket = import_net.default.createConnection(this._socketPath, () => {
126
+ resolve({ socket });
162
127
  });
163
- }
128
+ socket.on("error", (error) => {
129
+ if (import_os.default.platform() !== "win32")
130
+ void import_fs.default.promises.unlink(this._socketPath).catch(() => {
131
+ }).then(() => resolve({ error }));
132
+ else
133
+ resolve({ error });
134
+ });
135
+ });
164
136
  }
165
- async configure(args) {
166
- const sessionName = this._resolveSessionName(args.session);
167
- if (await this._canConnect(sessionName)) {
168
- const session2 = await this._connect(sessionName);
169
- await session2.stop();
137
+ async canConnect() {
138
+ const { socket } = await this._connect();
139
+ if (socket) {
140
+ socket.destroy();
141
+ return true;
170
142
  }
171
- this._options.config = args._[1];
172
- const session = await this._connect(sessionName);
173
- session.close();
174
- }
175
- async _connect(sessionName) {
176
- const socketPath = this._daemonSocketPath(sessionName);
177
- if (await this._canConnect(sessionName)) {
178
- try {
179
- return await this._connectToSocket(sessionName, socketPath);
180
- } catch (e) {
181
- if (import_os.default.platform() !== "win32")
182
- await import_fs.default.promises.unlink(socketPath).catch(() => {
183
- });
143
+ return false;
144
+ }
145
+ async _startDaemonIfNeeded() {
146
+ if (this._connection)
147
+ return this._connection;
148
+ let { socket } = await this._connect();
149
+ if (!socket)
150
+ socket = await this._startDaemon();
151
+ this._connection = new import_socketConnection.SocketConnection(socket, this._options.daemonVersion);
152
+ this._connection.onmessage = (message) => this._onMessage(message);
153
+ this._connection.onversionerror = (id, e) => {
154
+ if (e.received && e.received !== "undefined-for-test") {
155
+ return false;
184
156
  }
157
+ console.error(`Daemon is older than client, killing it.`);
158
+ this.stop().then(() => process.exit(1)).catch(() => process.exit(1));
159
+ return true;
160
+ };
161
+ this._connection.onclose = () => this.close();
162
+ return this._connection;
163
+ }
164
+ _onMessage(object) {
165
+ if (object.id && this._callbacks.has(object.id)) {
166
+ const callback = this._callbacks.get(object.id);
167
+ this._callbacks.delete(object.id);
168
+ if (object.error)
169
+ callback.reject(new Error(object.error));
170
+ else
171
+ callback.resolve(object.result);
172
+ } else if (object.id) {
173
+ throw new Error(`Unexpected message id: ${object.id}`);
174
+ } else {
175
+ throw new Error(`Unexpected message without id: ${JSON.stringify(object)}`);
185
176
  }
177
+ }
178
+ async _startDaemon() {
186
179
  await import_fs.default.promises.mkdir(daemonProfilesDir, { recursive: true });
187
- const userDataDir = import_path.default.resolve(daemonProfilesDir, `ud-${sessionName}`);
180
+ const userDataDir = import_path.default.resolve(daemonProfilesDir, `ud-${this.name}`);
188
181
  const cliPath = import_path.default.join(__dirname, "../../../cli.js");
189
182
  const configFile = resolveConfigFile(this._options.config);
190
183
  const configArg = configFile !== void 0 ? [`--config=${configFile}`] : [];
191
184
  const headedArg = this._options.headed ? [`--daemon-headed`] : [];
185
+ const extensionArg = this._options.extension ? [`--extension`] : [];
192
186
  const outLog = import_path.default.join(daemonProfilesDir, "out.log");
193
187
  const errLog = import_path.default.join(daemonProfilesDir, "err.log");
194
188
  const out = import_fs.default.openSync(outLog, "w");
@@ -196,10 +190,13 @@ class SessionManager {
196
190
  const child = (0, import_child_process.spawn)(process.execPath, [
197
191
  cliPath,
198
192
  "run-mcp-server",
199
- `--daemon=${socketPath}`,
193
+ `--output-dir=${outputDir}`,
194
+ `--daemon=${this._socketPath}`,
200
195
  `--daemon-data-dir=${userDataDir}`,
196
+ `--daemon-version=${this._options.daemonVersion}`,
201
197
  ...configArg,
202
- ...headedArg
198
+ ...headedArg,
199
+ ...extensionArg
203
200
  ], {
204
201
  detached: true,
205
202
  stdio: ["ignore", out, err],
@@ -207,53 +204,104 @@ class SessionManager {
207
204
  // Will be used as root.
208
205
  });
209
206
  child.unref();
210
- console.log(`<!-- Daemon for \`${sessionName}\` session started with pid ${child.pid}.`);
207
+ console.log(`<!-- Daemon for \`${this.name}\` session started with pid ${child.pid}.`);
211
208
  if (configFile)
212
209
  console.log(`- Using config file at \`${import_path.default.relative(process.cwd(), configFile)}\`.`);
213
- const sessionSuffix = sessionName !== "default" ? ` "${sessionName}"` : "";
210
+ const sessionSuffix = this.name !== "default" ? ` "${this.name}"` : "";
214
211
  console.log(`- You can stop the session daemon with \`playwright-cli session-stop${sessionSuffix}\` when done.`);
215
212
  console.log(`- You can delete the session data with \`playwright-cli session-delete${sessionSuffix}\` when done.`);
216
213
  console.log("-->");
217
214
  const maxRetries = 50;
218
215
  const retryDelay = 100;
219
216
  for (let i = 0; i < maxRetries; i++) {
220
- await new Promise((resolve) => setTimeout(resolve, 100));
217
+ await new Promise((resolve) => setTimeout(resolve, retryDelay));
221
218
  try {
222
- return await this._connectToSocket(sessionName, socketPath);
219
+ const { socket } = await this._connect();
220
+ if (socket)
221
+ return socket;
223
222
  } catch (e) {
224
- if (e.code !== "ENOENT")
223
+ if (e.code !== "ENOENT" && e.code !== "ECONNREFUSED")
225
224
  throw e;
226
225
  }
227
226
  }
228
227
  const outData = await import_fs.default.promises.readFile(outLog, "utf-8").catch(() => "");
229
228
  const errData = await import_fs.default.promises.readFile(errLog, "utf-8").catch(() => "");
230
- console.error(`Failed to connect to daemon at ${socketPath} after ${maxRetries * retryDelay}ms`);
229
+ console.error(`Failed to connect to daemon at ${this._socketPath} after ${maxRetries * retryDelay}ms`);
231
230
  if (outData.length)
232
231
  console.log(outData);
233
232
  if (errData.length)
234
233
  console.error(errData);
235
234
  process.exit(1);
236
235
  }
237
- async _connectToSocket(sessionName, socketPath) {
238
- const socket = await new Promise((resolve, reject) => {
239
- const socket2 = import_net.default.createConnection(socketPath, () => {
240
- resolve(socket2);
241
- });
242
- socket2.on("error", reject);
243
- });
244
- return new Session(sessionName, new import_socketConnection.SocketConnection(socket));
245
- }
246
- async _canConnect(sessionName) {
247
- const socketPath = this._daemonSocketPath(sessionName);
248
- return new Promise((resolve) => {
249
- const socket = import_net.default.createConnection(socketPath, () => {
250
- socket.destroy();
251
- resolve(true);
252
- });
253
- socket.on("error", () => {
254
- resolve(false);
255
- });
256
- });
236
+ _daemonSocketPath() {
237
+ const socketName = `${this.name}.sock`;
238
+ if (import_os.default.platform() === "win32")
239
+ return `\\\\.\\pipe\\${installationDirHash}-${socketName}`;
240
+ const socketsDir = process.env.PLAYWRIGHT_DAEMON_SOCKETS_DIR || import_path.default.join(import_os.default.tmpdir(), "playwright-cli");
241
+ return import_path.default.join(socketsDir, installationDirHash, socketName);
242
+ }
243
+ }
244
+ class SessionManager {
245
+ constructor(sessions, options) {
246
+ this.sessions = sessions;
247
+ this.options = options;
248
+ }
249
+ static async create(options) {
250
+ const dir = daemonProfilesDir;
251
+ const sessions = /* @__PURE__ */ new Map([
252
+ ["default", new Session("default", options)]
253
+ ]);
254
+ try {
255
+ const files = await import_fs.default.promises.readdir(dir);
256
+ for (const file of files) {
257
+ if (file.startsWith("ud-")) {
258
+ const sessionName = file.split("-")[1];
259
+ sessions.set(sessionName, new Session(sessionName, options));
260
+ }
261
+ }
262
+ } catch {
263
+ }
264
+ return new SessionManager(sessions, options);
265
+ }
266
+ async run(args) {
267
+ const sessionName = this._resolveSessionName(args.session);
268
+ let session = this.sessions.get(sessionName);
269
+ if (!session) {
270
+ session = new Session(sessionName, { ...this.options, ...args });
271
+ this.sessions.set(sessionName, session);
272
+ }
273
+ const result = await session.run({ ...args, outputDir });
274
+ console.log(result.text);
275
+ session.close();
276
+ }
277
+ async stop(sessionName) {
278
+ sessionName = this._resolveSessionName(sessionName);
279
+ const session = this.sessions.get(sessionName);
280
+ if (!session || !await session.canConnect()) {
281
+ console.log(`Session '${sessionName}' is not running.`);
282
+ return;
283
+ }
284
+ await session.stop();
285
+ }
286
+ async delete(sessionName) {
287
+ sessionName = this._resolveSessionName(sessionName);
288
+ const session = this.sessions.get(sessionName);
289
+ if (!session) {
290
+ console.log(`No user data found for session '${sessionName}'.`);
291
+ return;
292
+ }
293
+ await session.delete();
294
+ this.sessions.delete(sessionName);
295
+ }
296
+ async configure(args) {
297
+ const sessionName = this._resolveSessionName(args.session);
298
+ let session = this.sessions.get(sessionName);
299
+ if (!session) {
300
+ session = new Session(sessionName, this.options);
301
+ this.sessions.set(sessionName, session);
302
+ }
303
+ await session.restart({ ...this.options, ...args, config: args._[1] });
304
+ session.close();
257
305
  }
258
306
  _resolveSessionName(sessionName) {
259
307
  if (sessionName)
@@ -262,21 +310,14 @@ class SessionManager {
262
310
  return process.env.PLAYWRIGHT_CLI_SESSION;
263
311
  return "default";
264
312
  }
265
- _daemonSocketPath(sessionName) {
266
- const socketName = `${sessionName}.sock`;
267
- if (import_os.default.platform() === "win32")
268
- return `\\\\.\\pipe\\${installationDirHash}-${socketName}`;
269
- const socketsDir = process.env.PLAYWRIGHT_DAEMON_SOCKETS_DIR || import_path.default.join(import_os.default.tmpdir(), "playwright-cli");
270
- return import_path.default.join(socketsDir, installationDirHash, socketName);
271
- }
272
313
  }
273
314
  async function handleSessionCommand(sessionManager, subcommand, args) {
274
315
  if (subcommand === "list") {
275
- const sessions = await sessionManager.list();
316
+ const sessions = sessionManager.sessions;
276
317
  console.log("Sessions:");
277
- for (const [sessionName, live] of sessions.entries()) {
278
- const liveMarker = live ? " (live)" : "";
279
- console.log(` ${sessionName}${liveMarker}`);
318
+ for (const session of sessions.values()) {
319
+ const liveMarker = await session.canConnect() ? " (live)" : "";
320
+ console.log(` ${session.name}${liveMarker}`);
280
321
  }
281
322
  if (sessions.size === 0)
282
323
  console.log(" (no sessions)");
@@ -287,9 +328,9 @@ async function handleSessionCommand(sessionManager, subcommand, args) {
287
328
  return;
288
329
  }
289
330
  if (subcommand === "stop-all") {
290
- const sessions = await sessionManager.list();
291
- for (const sessionName of sessions.keys())
292
- await sessionManager.stop(sessionName);
331
+ const sessions = sessionManager.sessions;
332
+ for (const session of sessions.values())
333
+ await session.stop();
293
334
  return;
294
335
  }
295
336
  if (subcommand === "delete") {
@@ -325,10 +366,12 @@ const daemonProfilesDir = (() => {
325
366
  async function program(options) {
326
367
  const argv = process.argv.slice(2);
327
368
  const args = require("minimist")(argv, {
328
- boolean: ["help", "version", "headed"]
369
+ boolean: ["help", "version", "headed", "extension"]
329
370
  });
330
371
  if (!argv.includes("--headed") && !argv.includes("--no-headed"))
331
372
  delete args.headed;
373
+ if (!argv.includes("--extension"))
374
+ delete args.extension;
332
375
  const help = require("./help.json");
333
376
  const commandName = args._[0];
334
377
  if (args.version || args.v) {
@@ -351,7 +394,7 @@ async function program(options) {
351
394
  console.log(help.global);
352
395
  process.exit(1);
353
396
  }
354
- const sessionManager = new SessionManager(args);
397
+ const sessionManager = await SessionManager.create({ daemonVersion: options.version, ...args });
355
398
  if (commandName.startsWith("session")) {
356
399
  const subcommand = args._[0].split("-").slice(1).join("-");
357
400
  await handleSessionCommand(sessionManager, subcommand, args);
@@ -361,61 +404,13 @@ async function program(options) {
361
404
  await handleSessionCommand(sessionManager, "config", args);
362
405
  return;
363
406
  }
364
- await sessionManager.run(args);
365
- }
366
- async function printResponse(response) {
367
- const { sections } = response;
368
- if (!sections) {
369
- console.log("### Error\n" + response.text);
407
+ if (commandName === "close") {
408
+ await handleSessionCommand(sessionManager, "stop", args);
370
409
  return;
371
410
  }
372
- const text = [];
373
- for (const section of sections) {
374
- text.push(`### ${section.title}`);
375
- for (const result of section.content) {
376
- if (!result.file) {
377
- if (result.text !== void 0)
378
- text.push(result.text);
379
- continue;
380
- }
381
- const generatedFileName = await outputFile(dateAsFileName(result.file.prefix, result.file.ext), { origin: "code" });
382
- const fileName = result.file.suggestedFilename ? await outputFile(result.file.suggestedFilename, { origin: "llm" }) : generatedFileName;
383
- text.push(`- [${result.title}](${import_path.default.relative(process.cwd(), fileName)})`);
384
- if (result.data)
385
- await import_fs.default.promises.writeFile(fileName, result.data);
386
- else if (result.isBase64)
387
- await import_fs.default.promises.writeFile(fileName, Buffer.from(result.text, "base64"));
388
- else
389
- await import_fs.default.promises.writeFile(fileName, result.text);
390
- }
391
- }
392
- console.log(text.join("\n"));
393
- }
394
- function dateAsFileName(prefix, extension) {
395
- const date = /* @__PURE__ */ new Date();
396
- return `${prefix}-${date.toISOString().replace(/[:.]/g, "-")}.${extension}`;
411
+ await sessionManager.run(args);
397
412
  }
398
413
  const outputDir = import_path.default.join(process.cwd(), ".playwright-cli");
399
- async function outputFile(fileName, options) {
400
- await import_fs.default.promises.mkdir(outputDir, { recursive: true });
401
- if (options.origin === "code")
402
- return import_path.default.resolve(outputDir, fileName);
403
- if (options.origin === "llm") {
404
- fileName = fileName.split("\\").join("/");
405
- const resolvedFile = import_path.default.resolve(outputDir, fileName);
406
- if (!resolvedFile.startsWith(import_path.default.resolve(outputDir) + import_path.default.sep))
407
- throw new Error(`Resolved file path ${resolvedFile} is outside of the output directory ${outputDir}. Use relative file names to stay within the output directory.`);
408
- return resolvedFile;
409
- }
410
- return import_path.default.join(outputDir, sanitizeForFilePath(fileName));
411
- }
412
- function sanitizeForFilePath(s) {
413
- const sanitize = (s2) => s2.replace(/[\x00-\x2C\x2E-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+/g, "-");
414
- const separator = s.lastIndexOf(".");
415
- if (separator === -1)
416
- return sanitize(s);
417
- return sanitize(s.substring(0, separator)) + "." + sanitize(s.substring(separator + 1));
418
- }
419
414
  function resolveConfigFile(configParam) {
420
415
  const configFile = configParam || process.env.PLAYWRIGHT_CLI_CONFIG;
421
416
  if (configFile)
@@ -429,6 +424,5 @@ function resolveConfigFile(configParam) {
429
424
  }
430
425
  // Annotate the CommonJS export names for ESM import in node:
431
426
  0 && (module.exports = {
432
- printResponse,
433
427
  program
434
428
  });
@@ -22,9 +22,10 @@ __export(socketConnection_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(socketConnection_exports);
24
24
  class SocketConnection {
25
- constructor(socket) {
25
+ constructor(socket, version) {
26
26
  this._pendingBuffers = [];
27
27
  this._socket = socket;
28
+ this._version = version;
28
29
  socket.on("data", (buffer) => this._onData(buffer));
29
30
  socket.on("close", () => {
30
31
  this.onclose?.();
@@ -33,7 +34,7 @@ class SocketConnection {
33
34
  }
34
35
  async send(message) {
35
36
  await new Promise((resolve, reject) => {
36
- this._socket.write(`${JSON.stringify(message)}
37
+ this._socket.write(`${JSON.stringify({ ...message, version: this._version })}
37
38
  `, (error) => {
38
39
  if (error)
39
40
  reject(error);
@@ -66,7 +67,12 @@ class SocketConnection {
66
67
  }
67
68
  _dispatchMessage(message) {
68
69
  try {
69
- this.onmessage?.(JSON.parse(message));
70
+ const parsedMessage = JSON.parse(message);
71
+ if (parsedMessage.version !== this._version) {
72
+ if (this.onversionerror?.(parsedMessage.id, { expected: this._version, received: parsedMessage.version }))
73
+ return;
74
+ }
75
+ this.onmessage?.(parsedMessage);
70
76
  } catch (e) {
71
77
  console.error("failed to dispatch message", e);
72
78
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cotestdev/mcp_playwright",
3
- "version": "0.0.48",
3
+ "version": "0.0.49",
4
4
  "description": "Playwright MCP (Model Context Protocol) tools for browser automation",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -25,7 +25,7 @@
25
25
  "author": "",
26
26
  "license": "Apache-2.0",
27
27
  "dependencies": {
28
- "@cotestdev/ai-runner-fake": "^0.0.7",
28
+ "@cotestdev/ai-runner-fake": "^0.0.9",
29
29
  "playwright": "^1.40.0",
30
30
  "playwright-core": "^1.40.0"
31
31
  },