@cotestdev/mcp_playwright 0.0.12 → 0.0.15

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 (48) hide show
  1. package/lib/mcp/browser/browserContextFactory.js +49 -13
  2. package/lib/mcp/browser/browserServerBackend.js +5 -2
  3. package/lib/mcp/browser/config.js +95 -23
  4. package/lib/mcp/browser/context.js +28 -3
  5. package/lib/mcp/browser/response.js +240 -57
  6. package/lib/mcp/browser/sessionLog.js +1 -1
  7. package/lib/mcp/browser/tab.js +96 -69
  8. package/lib/mcp/browser/tools/common.js +8 -8
  9. package/lib/mcp/browser/tools/console.js +6 -3
  10. package/lib/mcp/browser/tools/dialogs.js +13 -13
  11. package/lib/mcp/browser/tools/evaluate.js +9 -20
  12. package/lib/mcp/browser/tools/files.js +10 -5
  13. package/lib/mcp/browser/tools/form.js +11 -22
  14. package/lib/mcp/browser/tools/install.js +3 -3
  15. package/lib/mcp/browser/tools/keyboard.js +12 -12
  16. package/lib/mcp/browser/tools/mouse.js +14 -14
  17. package/lib/mcp/browser/tools/navigate.js +5 -5
  18. package/lib/mcp/browser/tools/network.js +16 -5
  19. package/lib/mcp/browser/tools/pdf.js +7 -18
  20. package/lib/mcp/browser/tools/runCode.js +77 -0
  21. package/lib/mcp/browser/tools/screenshot.js +44 -33
  22. package/lib/mcp/browser/tools/snapshot.js +42 -33
  23. package/lib/mcp/browser/tools/tabs.js +7 -10
  24. package/lib/mcp/browser/tools/tool.js +8 -7
  25. package/lib/mcp/browser/tools/tracing.js +4 -4
  26. package/lib/mcp/browser/tools/utils.js +50 -52
  27. package/lib/mcp/browser/tools/verify.js +23 -34
  28. package/lib/mcp/browser/tools/wait.js +6 -6
  29. package/lib/mcp/browser/tools.js +4 -3
  30. package/lib/mcp/cli.js +17 -17
  31. package/lib/mcp/extension/cdpRelay.js +1 -1
  32. package/lib/mcp/extension/extensionContextFactory.js +4 -3
  33. package/lib/mcp/log.js +2 -2
  34. package/lib/mcp/program.js +21 -29
  35. package/lib/mcp/sdk/exports.js +1 -5
  36. package/lib/mcp/sdk/http.js +37 -50
  37. package/lib/mcp/sdk/server.js +61 -9
  38. package/lib/mcp/sdk/tool.js +5 -4
  39. package/lib/mcp/test/browserBackend.js +67 -61
  40. package/lib/mcp/test/generatorTools.js +122 -0
  41. package/lib/mcp/test/plannerTools.js +144 -0
  42. package/lib/mcp/test/seed.js +82 -0
  43. package/lib/mcp/test/streams.js +10 -7
  44. package/lib/mcp/test/testBackend.js +44 -24
  45. package/lib/mcp/test/testContext.js +243 -14
  46. package/lib/mcp/test/testTools.js +23 -109
  47. package/lib/util.js +12 -6
  48. package/package.json +1 -1
@@ -25,9 +25,11 @@ __export(tab_exports, {
25
25
  module.exports = __toCommonJS(tab_exports);
26
26
  var import_events = require("events");
27
27
  var import_utils = require("playwright-core/lib/utils");
28
- var import_utilsBundle = require("playwright-core/lib/utilsBundle");
29
28
  var import_utils2 = require("./tools/utils");
30
29
  var import_log = require("../log");
30
+ var import_dialogs = require("./tools/dialogs");
31
+ var import_files = require("./tools/files");
32
+ var import_transform = require("../../transform/transform");
31
33
  const TabEvents = {
32
34
  modalState: "modalState"
33
35
  };
@@ -37,27 +39,23 @@ class Tab extends import_events.EventEmitter {
37
39
  this._lastTitle = "about:blank";
38
40
  this._consoleMessages = [];
39
41
  this._recentConsoleMessages = [];
40
- this._requests = /* @__PURE__ */ new Map();
42
+ this._requests = /* @__PURE__ */ new Set();
41
43
  this._modalStates = [];
42
44
  this._downloads = [];
45
+ this._needsFullSnapshot = false;
43
46
  this.context = context;
44
47
  this.page = page;
45
48
  this._onPageClose = onPageClose;
46
49
  page.on("console", (event) => this._handleConsoleMessage(messageToConsoleMessage(event)));
47
50
  page.on("pageerror", (error) => this._handleConsoleMessage(pageErrorToConsoleMessage(error)));
48
- page.on("request", (request) => {
49
- this._requests.set(request, null);
50
- if (request.frame() === page.mainFrame() && request.isNavigationRequest())
51
- this._willNavigateMainFrameToNewDocument();
52
- });
53
- page.on("response", (response) => this._requests.set(response.request(), response));
51
+ page.on("request", (request) => this._requests.add(request));
54
52
  page.on("close", () => this._onClose());
55
53
  page.on("filechooser", (chooser) => {
56
54
  this.setModalState({
57
55
  type: "fileChooser",
58
56
  description: "File chooser",
59
57
  fileChooser: chooser,
60
- clearedBy: "browser_file_upload"
58
+ clearedBy: import_files.uploadFile.schema.name
61
59
  });
62
60
  });
63
61
  page.on("dialog", (dialog) => this._dialogShown(dialog));
@@ -67,25 +65,34 @@ class Tab extends import_events.EventEmitter {
67
65
  page.setDefaultNavigationTimeout(this.context.config.timeouts.navigation);
68
66
  page.setDefaultTimeout(this.context.config.timeouts.action);
69
67
  page[tabSymbol] = this;
70
- void this._initialize();
68
+ this._initializedPromise = this._initialize();
71
69
  }
72
70
  static forPage(page) {
73
71
  return page[tabSymbol];
74
72
  }
75
- async _initialize() {
76
- const messages = await this.page.consoleMessages().catch(() => []);
73
+ static async collectConsoleMessages(page) {
74
+ const result = [];
75
+ const messages = await page.consoleMessages().catch(() => []);
77
76
  for (const message of messages)
78
- this._handleConsoleMessage(messageToConsoleMessage(message));
79
- const errors = await this.page.pageErrors().catch(() => []);
77
+ result.push(messageToConsoleMessage(message));
78
+ const errors = await page.pageErrors().catch(() => []);
80
79
  for (const error of errors)
81
- this._handleConsoleMessage(pageErrorToConsoleMessage(error));
80
+ result.push(pageErrorToConsoleMessage(error));
81
+ return result;
82
+ }
83
+ async _initialize() {
84
+ for (const message of await Tab.collectConsoleMessages(this.page))
85
+ this._handleConsoleMessage(message);
82
86
  const requests = await this.page.requests().catch(() => []);
83
- for (const request of requests) {
84
- this._requests.set(request, null);
85
- void request.response().catch(() => null).then((response) => {
86
- if (response)
87
- this._requests.set(request, response);
88
- });
87
+ for (const request of requests)
88
+ this._requests.add(request);
89
+ for (const initPage of this.context.config.browser.initPage || []) {
90
+ try {
91
+ const { default: func } = await (0, import_transform.requireOrImport)(initPage);
92
+ await func({ page: this.page });
93
+ } catch (e) {
94
+ (0, import_log.logUnhandledError)(e);
95
+ }
89
96
  }
90
97
  }
91
98
  modalStates() {
@@ -98,22 +105,19 @@ class Tab extends import_events.EventEmitter {
98
105
  clearModalState(modalState) {
99
106
  this._modalStates = this._modalStates.filter((state) => state !== modalState);
100
107
  }
101
- modalStatesMarkdown() {
102
- return renderModalStates(this.context, this.modalStates());
103
- }
104
108
  _dialogShown(dialog) {
105
109
  this.setModalState({
106
110
  type: "dialog",
107
111
  description: `"${dialog.type()}" dialog with message "${dialog.message()}"`,
108
112
  dialog,
109
- clearedBy: "browser_handle_dialog"
113
+ clearedBy: import_dialogs.handleDialog.schema.name
110
114
  });
111
115
  }
112
116
  async _downloadStarted(download) {
113
117
  const entry = {
114
118
  download,
115
119
  finished: false,
116
- outputFile: await this.context.outputFile(download.suggestedFilename(), { origin: "web" })
120
+ outputFile: await this.context.outputFile(download.suggestedFilename(), { origin: "web", reason: "Saving download" })
117
121
  };
118
122
  this._downloads.push(entry);
119
123
  await download.saveAs(entry.outputFile);
@@ -132,9 +136,6 @@ class Tab extends import_events.EventEmitter {
132
136
  this._clearCollectedArtifacts();
133
137
  this._onPageClose(this);
134
138
  }
135
- _willNavigateMainFrameToNewDocument() {
136
- this._lastAriaSnapshot = void 0;
137
- }
138
139
  async updateTitle() {
139
140
  await this._raceAgainstModalStates(async () => {
140
141
  this._lastTitle = await (0, import_utils2.callOnPageNoTrace)(this.page, (page) => page.title());
@@ -147,23 +148,22 @@ class Tab extends import_events.EventEmitter {
147
148
  return this === this.context.currentTab();
148
149
  }
149
150
  async waitForLoadState(state, options) {
151
+ await this._initializedPromise;
150
152
  await (0, import_utils2.callOnPageNoTrace)(this.page, (page) => page.waitForLoadState(state, options).catch(import_log.logUnhandledError));
151
153
  }
152
154
  async navigate(url) {
155
+ await this._initializedPromise;
153
156
  this._clearCollectedArtifacts();
154
- this._willNavigateMainFrameToNewDocument();
155
- const downloadEvent = (0, import_utils2.callOnPageNoTrace)(this.page, (page) => page.waitForEvent("download").catch(import_log.logUnhandledError));
157
+ const { promise: downloadEvent, abort: abortDownloadEvent } = (0, import_utils2.eventWaiter)(this.page, "download", 3e3);
156
158
  try {
157
159
  await this.page.goto(url, { waitUntil: "domcontentloaded" });
160
+ abortDownloadEvent();
158
161
  } catch (_e) {
159
162
  const e = _e;
160
163
  const mightBeDownload = e.message.includes("net::ERR_ABORTED") || e.message.includes("Download is starting");
161
164
  if (!mightBeDownload)
162
165
  throw e;
163
- const download = await Promise.race([
164
- downloadEvent,
165
- new Promise((resolve) => setTimeout(resolve, 3e3))
166
- ]);
166
+ const download = await downloadEvent;
167
167
  if (!download)
168
168
  throw e;
169
169
  await new Promise((resolve) => setTimeout(resolve, 500));
@@ -171,31 +171,34 @@ class Tab extends import_events.EventEmitter {
171
171
  }
172
172
  await this.waitForLoadState("load", { timeout: 5e3 });
173
173
  }
174
- consoleMessages() {
175
- return this._consoleMessages;
174
+ async consoleMessages(level) {
175
+ await this._initializedPromise;
176
+ return this._consoleMessages.filter((message) => shouldIncludeMessage(level, message.type));
176
177
  }
177
- requests() {
178
+ async requests() {
179
+ await this._initializedPromise;
178
180
  return this._requests;
179
181
  }
180
182
  async captureSnapshot() {
183
+ await this._initializedPromise;
181
184
  let tabSnapshot;
182
185
  const modalStates = await this._raceAgainstModalStates(async () => {
183
- const snapshot = await this.page._snapshotForAI();
186
+ const snapshot = await this.page._snapshotForAI({ track: "response" });
184
187
  tabSnapshot = {
185
188
  url: this.page.url(),
186
189
  title: await this.page.title(),
187
- ariaSnapshot: snapshot,
188
- formattedAriaSnapshotDiff: this._lastAriaSnapshot ? generateAriaSnapshotDiff(this._lastAriaSnapshot, snapshot) : void 0,
190
+ ariaSnapshot: snapshot.full,
191
+ ariaSnapshotDiff: this._needsFullSnapshot ? void 0 : snapshot.incremental,
189
192
  modalStates: [],
190
193
  consoleMessages: [],
191
194
  downloads: this._downloads
192
195
  };
193
196
  });
194
197
  if (tabSnapshot) {
195
- tabSnapshot.consoleMessages = this._recentConsoleMessages;
198
+ tabSnapshot.consoleMessages = this._recentConsoleMessages.filter((message) => shouldIncludeMessage(this.context.config.console.level, message.type));
196
199
  this._recentConsoleMessages = [];
197
- this._lastAriaSnapshot = tabSnapshot.ariaSnapshot;
198
200
  }
201
+ this._needsFullSnapshot = !tabSnapshot;
199
202
  return tabSnapshot ?? {
200
203
  url: this.page.url(),
201
204
  title: "",
@@ -223,18 +226,24 @@ class Tab extends import_events.EventEmitter {
223
226
  ]);
224
227
  }
225
228
  async waitForCompletion(callback) {
229
+ await this._initializedPromise;
226
230
  await this._raceAgainstModalStates(() => (0, import_utils2.waitForCompletion)(this, callback));
227
231
  }
228
232
  async refLocator(params) {
233
+ await this._initializedPromise;
229
234
  return (await this.refLocators([params]))[0];
230
235
  }
231
236
  async refLocators(params) {
232
- const snapshot = await this.page._snapshotForAI();
233
- return params.map((param) => {
234
- if (!snapshot.includes(`[ref=${param.ref}]`))
237
+ await this._initializedPromise;
238
+ return Promise.all(params.map(async (param) => {
239
+ try {
240
+ const locator = this.page.locator(`aria-ref=${param.ref}`).describe(param.element);
241
+ const { resolvedSelector } = await locator._resolveSelector();
242
+ return { locator, resolved: (0, import_utils.asLocator)("javascript", resolvedSelector) };
243
+ } catch (e) {
235
244
  throw new Error(`Ref ${param.ref} not found in the current page snapshot. Try capturing new snapshot.`);
236
- return this.page.locator(`aria-ref=${param.ref}`).describe(param.element);
237
- });
245
+ }
246
+ }));
238
247
  }
239
248
  async waitForTimeout(time) {
240
249
  if (this._javaScriptBlocked()) {
@@ -242,7 +251,8 @@ class Tab extends import_events.EventEmitter {
242
251
  return;
243
252
  }
244
253
  await (0, import_utils2.callOnPageNoTrace)(this.page, (page) => {
245
- return page.evaluate(() => new Promise((f) => setTimeout(f, 1e3)));
254
+ return page.evaluate(() => new Promise((f) => setTimeout(f, 1e3))).catch(() => {
255
+ });
246
256
  });
247
257
  }
248
258
  }
@@ -256,43 +266,60 @@ function messageToConsoleMessage(message) {
256
266
  function pageErrorToConsoleMessage(errorOrValue) {
257
267
  if (errorOrValue instanceof Error) {
258
268
  return {
259
- type: void 0,
269
+ type: "error",
260
270
  text: errorOrValue.message,
261
271
  toString: () => errorOrValue.stack || errorOrValue.message
262
272
  };
263
273
  }
264
274
  return {
265
- type: void 0,
275
+ type: "error",
266
276
  text: String(errorOrValue),
267
277
  toString: () => String(errorOrValue)
268
278
  };
269
279
  }
270
- function renderModalStates(context, modalStates) {
271
- const result = ["### Modal state"];
280
+ function renderModalStates(modalStates) {
281
+ const result = [];
272
282
  if (modalStates.length === 0)
273
283
  result.push("- There is no modal state present");
274
284
  for (const state of modalStates)
275
285
  result.push(`- [${state.description}]: can be handled by the "${state.clearedBy}" tool`);
276
286
  return result;
277
287
  }
278
- const tabSymbol = Symbol("tabSymbol");
279
- function generateAriaSnapshotDiff(oldSnapshot, newSnapshot) {
280
- const diffs = (0, import_utils.diffAriaSnapshots)(import_utilsBundle.yaml, oldSnapshot, newSnapshot);
281
- if (diffs === "equal")
282
- return "<no changes>";
283
- if (diffs === "different")
284
- return;
285
- if (diffs.length > 3 || diffs.some((diff) => diff.newSource.split("\n").length > 100)) {
286
- return;
288
+ const consoleMessageLevels = ["error", "warning", "info", "debug"];
289
+ function shouldIncludeMessage(thresholdLevel, type) {
290
+ const messageLevel = consoleLevelForMessageType(type);
291
+ return consoleMessageLevels.indexOf(messageLevel) <= consoleMessageLevels.indexOf(thresholdLevel);
292
+ }
293
+ function consoleLevelForMessageType(type) {
294
+ switch (type) {
295
+ case "assert":
296
+ case "error":
297
+ return "error";
298
+ case "warning":
299
+ return "warning";
300
+ case "count":
301
+ case "dir":
302
+ case "dirxml":
303
+ case "info":
304
+ case "log":
305
+ case "table":
306
+ case "time":
307
+ case "timeEnd":
308
+ return "info";
309
+ case "clear":
310
+ case "debug":
311
+ case "endGroup":
312
+ case "profile":
313
+ case "profileEnd":
314
+ case "startGroup":
315
+ case "startGroupCollapsed":
316
+ case "trace":
317
+ return "debug";
318
+ default:
319
+ return "info";
287
320
  }
288
- const lines = [`The following refs have changed`];
289
- for (const diff of diffs)
290
- lines.push("", "```yaml", diff.newSource.trimEnd(), "```");
291
- const combined = lines.join("\n");
292
- if (combined.length >= newSnapshot.length)
293
- return;
294
- return combined;
295
321
  }
322
+ const tabSymbol = Symbol("tabSymbol");
296
323
  // Annotate the CommonJS export names for ESM import in node:
297
324
  0 && (module.exports = {
298
325
  Tab,
@@ -22,10 +22,10 @@ __export(common_exports, {
22
22
  default: () => common_default
23
23
  });
24
24
  module.exports = __toCommonJS(common_exports);
25
- var import_bundle = require("../../sdk/bundle");
25
+ var import_mcpBundle = require("playwright-core/lib/mcpBundle");
26
26
  var import_tool = require("./tool");
27
- const baseSchema = import_bundle.z.object({
28
- toolText: import_bundle.z.string().describe("A human-readable description of the action to perform by the tool.")
27
+ const baseSchema = import_mcpBundle.z.object({
28
+ toolText: import_mcpBundle.z.string().describe("A human-readable description of the action to perform by the tool.")
29
29
  });
30
30
  const close = (0, import_tool.defineTool)({
31
31
  capability: "core",
@@ -33,8 +33,8 @@ const close = (0, import_tool.defineTool)({
33
33
  name: "browser_close",
34
34
  title: "Close browser",
35
35
  description: "Close the page",
36
- inputSchema: baseSchema.extend({}),
37
- type: "readOnly"
36
+ inputSchema: import_mcpBundle.z.object({}),
37
+ type: "action"
38
38
  },
39
39
  handle: async (context, params, response) => {
40
40
  await context.closeBrowserContext();
@@ -49,10 +49,10 @@ const resize = (0, import_tool.defineTabTool)({
49
49
  title: "Resize browser window",
50
50
  description: "Resize the browser window",
51
51
  inputSchema: baseSchema.extend({
52
- width: import_bundle.z.number().describe("Width of the browser window"),
53
- height: import_bundle.z.number().describe("Height of the browser window")
52
+ width: import_mcpBundle.z.number().describe("Width of the browser window"),
53
+ height: import_mcpBundle.z.number().describe("Height of the browser window")
54
54
  }),
55
- type: "readOnly"
55
+ type: "action"
56
56
  },
57
57
  handle: async (tab, params, response) => {
58
58
  response.addCode(`await page.setViewportSize({ width: ${params.width}, height: ${params.height} });`);
@@ -21,7 +21,7 @@ __export(console_exports, {
21
21
  default: () => console_default
22
22
  });
23
23
  module.exports = __toCommonJS(console_exports);
24
- var import_bundle = require("../../sdk/bundle");
24
+ var import_mcpBundle = require("playwright-core/lib/mcpBundle");
25
25
  var import_tool = require("./tool");
26
26
  const console = (0, import_tool.defineTabTool)({
27
27
  capability: "core",
@@ -29,11 +29,14 @@ const console = (0, import_tool.defineTabTool)({
29
29
  name: "browser_console_messages",
30
30
  title: "Get console messages",
31
31
  description: "Returns all console messages",
32
- inputSchema: import_bundle.z.object({}),
32
+ inputSchema: import_mcpBundle.z.object({
33
+ level: import_mcpBundle.z.enum(["error", "warning", "info", "debug"]).default("info").describe('Level of the console messages to return. Each level includes the messages of more severe levels. Defaults to "info".')
34
+ }),
33
35
  type: "readOnly"
34
36
  },
35
37
  handle: async (tab, params, response) => {
36
- tab.consoleMessages().map((message) => response.addResult(message.toString()));
38
+ const messages = await tab.consoleMessages(params.level);
39
+ messages.map((message) => response.addResult(message.toString()));
37
40
  }
38
41
  });
39
42
  var console_default = [
@@ -18,12 +18,13 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var dialogs_exports = {};
20
20
  __export(dialogs_exports, {
21
- default: () => dialogs_default
21
+ default: () => dialogs_default,
22
+ handleDialog: () => handleDialog
22
23
  });
23
24
  module.exports = __toCommonJS(dialogs_exports);
24
- var import_bundle = require("../../sdk/bundle");
25
- var import_common = require("./common");
25
+ var import_mcpBundle = require("playwright-core/lib/mcpBundle");
26
26
  var import_tool = require("./tool");
27
+ var import_common = require("./common");
27
28
  const handleDialog = (0, import_tool.defineTabTool)({
28
29
  capability: "core",
29
30
  schema: {
@@ -31,10 +32,10 @@ const handleDialog = (0, import_tool.defineTabTool)({
31
32
  title: "Handle a dialog",
32
33
  description: "Handle a dialog",
33
34
  inputSchema: import_common.baseSchema.extend({
34
- accept: import_bundle.z.boolean().describe("Whether to accept the dialog."),
35
- promptText: import_bundle.z.string().optional().describe("The text of the prompt in case of a prompt dialog.")
35
+ accept: import_mcpBundle.z.boolean().describe("Whether to accept the dialog."),
36
+ promptText: import_mcpBundle.z.string().optional().describe("The text of the prompt in case of a prompt dialog.")
36
37
  }),
37
- type: "destructive"
38
+ type: "action"
38
39
  },
39
40
  handle: async (tab, params, response) => {
40
41
  response.setIncludeSnapshot();
@@ -43,15 +44,10 @@ const handleDialog = (0, import_tool.defineTabTool)({
43
44
  throw new Error("No dialog visible");
44
45
  tab.clearModalState(dialogState);
45
46
  await tab.waitForCompletion(async () => {
46
- if (params.accept) {
47
- if (params.promptText)
48
- response.addCode(`await page.on('dialog', dialog => dialog.accept(${JSON.stringify(params.promptText)}));`);
49
- else
50
- response.addCode(`await page.on('dialog', dialog => dialog.accept());`);
47
+ if (params.accept)
51
48
  await dialogState.dialog.accept(params.promptText);
52
- } else {
49
+ else
53
50
  await dialogState.dialog.dismiss();
54
- }
55
51
  });
56
52
  },
57
53
  clearsModalState: "dialog"
@@ -59,3 +55,7 @@ const handleDialog = (0, import_tool.defineTabTool)({
59
55
  var dialogs_default = [
60
56
  handleDialog
61
57
  ];
58
+ // Annotate the CommonJS export names for ESM import in node:
59
+ 0 && (module.exports = {
60
+ handleDialog
61
+ });
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,29 +15,20 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
  var evaluate_exports = {};
30
20
  __export(evaluate_exports, {
31
21
  default: () => evaluate_default
32
22
  });
33
23
  module.exports = __toCommonJS(evaluate_exports);
34
- var import_bundle = require("../../sdk/bundle");
24
+ var import_mcpBundle = require("playwright-core/lib/mcpBundle");
25
+ var import_utils = require("playwright-core/lib/utils");
35
26
  var import_tool = require("./tool");
36
- var javascript = __toESM(require("../codegen"));
37
- var import_utils = require("./utils");
38
27
  var import_common = require("./common");
39
28
  const evaluateSchema = import_common.baseSchema.extend({
40
- function: import_bundle.z.string().describe("() => { /* code */ } or (element) => { /* code */ } when element is provided"),
41
- element: import_bundle.z.string().optional().describe("Human-readable element description used to obtain permission to interact with the element"),
42
- ref: import_bundle.z.string().optional().describe("Exact target element reference from the page snapshot")
29
+ function: import_mcpBundle.z.string().describe("() => { /* code */ } or (element) => { /* code */ } when element is provided"),
30
+ element: import_mcpBundle.z.string().optional().describe("Human-readable element description used to obtain permission to interact with the element"),
31
+ ref: import_mcpBundle.z.string().optional().describe("Exact target element reference from the page snapshot")
43
32
  });
44
33
  const evaluate = (0, import_tool.defineTabTool)({
45
34
  capability: "core",
@@ -48,19 +37,19 @@ const evaluate = (0, import_tool.defineTabTool)({
48
37
  title: "Evaluate JavaScript",
49
38
  description: "Evaluate JavaScript expression on page or element",
50
39
  inputSchema: evaluateSchema,
51
- type: "destructive"
40
+ type: "action"
52
41
  },
53
42
  handle: async (tab, params, response) => {
54
43
  response.setIncludeSnapshot();
55
44
  let locator;
56
45
  if (params.ref && params.element) {
57
46
  locator = await tab.refLocator({ ref: params.ref, element: params.element });
58
- response.addCode(`await page.${await (0, import_utils.generateLocator)(locator)}.evaluate(${javascript.quote(params.function)});`);
47
+ response.addCode(`await page.${locator.resolved}.evaluate(${(0, import_utils.escapeWithQuotes)(params.function)});`);
59
48
  } else {
60
- response.addCode(`await page.evaluate(${javascript.quote(params.function)});`);
49
+ response.addCode(`await page.evaluate(${(0, import_utils.escapeWithQuotes)(params.function)});`);
61
50
  }
62
51
  await tab.waitForCompletion(async () => {
63
- const receiver = locator ?? tab.page;
52
+ const receiver = locator?.locator ?? tab.page;
64
53
  const result = await receiver._evaluateFunction(params.function);
65
54
  response.addResult(JSON.stringify(result, null, 2) || "undefined");
66
55
  });
@@ -18,12 +18,13 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var files_exports = {};
20
20
  __export(files_exports, {
21
- default: () => files_default
21
+ default: () => files_default,
22
+ uploadFile: () => uploadFile
22
23
  });
23
24
  module.exports = __toCommonJS(files_exports);
24
- var import_bundle = require("../../sdk/bundle");
25
- var import_common = require("./common");
25
+ var import_mcpBundle = require("playwright-core/lib/mcpBundle");
26
26
  var import_tool = require("./tool");
27
+ var import_common = require("./common");
27
28
  const uploadFile = (0, import_tool.defineTabTool)({
28
29
  capability: "core",
29
30
  schema: {
@@ -31,9 +32,9 @@ const uploadFile = (0, import_tool.defineTabTool)({
31
32
  title: "Upload files",
32
33
  description: "Upload one or multiple files",
33
34
  inputSchema: import_common.baseSchema.extend({
34
- paths: import_bundle.z.array(import_bundle.z.string()).optional().describe("The absolute paths to the files to upload. Can be single file or multiple files. If omitted, file chooser is cancelled.")
35
+ paths: import_mcpBundle.z.array(import_mcpBundle.z.string()).optional().describe("The absolute paths to the files to upload. Can be single file or multiple files. If omitted, file chooser is cancelled.")
35
36
  }),
36
- type: "destructive"
37
+ type: "action"
37
38
  },
38
39
  handle: async (tab, params, response) => {
39
40
  response.setIncludeSnapshot();
@@ -52,3 +53,7 @@ const uploadFile = (0, import_tool.defineTabTool)({
52
53
  var files_default = [
53
54
  uploadFile
54
55
  ];
56
+ // Annotate the CommonJS export names for ESM import in node:
57
+ 0 && (module.exports = {
58
+ uploadFile
59
+ });
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,24 +15,15 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
  var form_exports = {};
30
20
  __export(form_exports, {
31
21
  default: () => form_default
32
22
  });
33
23
  module.exports = __toCommonJS(form_exports);
34
- var import_bundle = require("../../sdk/bundle");
24
+ var import_mcpBundle = require("playwright-core/lib/mcpBundle");
25
+ var import_utils = require("playwright-core/lib/utils");
35
26
  var import_tool = require("./tool");
36
- var import_utils = require("./utils");
37
- var codegen = __toESM(require("../codegen"));
38
27
  var import_common = require("./common");
39
28
  const fillForm = (0, import_tool.defineTabTool)({
40
29
  capability: "core",
@@ -43,19 +32,19 @@ const fillForm = (0, import_tool.defineTabTool)({
43
32
  title: "Fill form",
44
33
  description: "Fill multiple form fields",
45
34
  inputSchema: import_common.baseSchema.extend({
46
- fields: import_bundle.z.array(import_bundle.z.object({
47
- name: import_bundle.z.string().describe("Human-readable field name"),
48
- type: import_bundle.z.enum(["textbox", "checkbox", "radio", "combobox", "slider"]).describe("Type of the field"),
49
- ref: import_bundle.z.string().describe("Exact target field reference from the page snapshot"),
50
- value: import_bundle.z.string().describe("Value to fill in the field. If the field is a checkbox, the value should be `true` or `false`. If the field is a combobox, the value should be the text of the option.")
35
+ fields: import_mcpBundle.z.array(import_mcpBundle.z.object({
36
+ name: import_mcpBundle.z.string().describe("Human-readable field name"),
37
+ type: import_mcpBundle.z.enum(["textbox", "checkbox", "radio", "combobox", "slider"]).describe("Type of the field"),
38
+ ref: import_mcpBundle.z.string().describe("Exact target field reference from the page snapshot"),
39
+ value: import_mcpBundle.z.string().describe("Value to fill in the field. If the field is a checkbox, the value should be `true` or `false`. If the field is a combobox, the value should be the text of the option.")
51
40
  })).describe("Fields to fill in")
52
41
  }),
53
- type: "destructive"
42
+ type: "input"
54
43
  },
55
44
  handle: async (tab, params, response) => {
56
45
  for (const field of params.fields) {
57
- const locator = await tab.refLocator({ element: field.name, ref: field.ref });
58
- const locatorSource = `await page.${await (0, import_utils.generateLocator)(locator)}`;
46
+ const { locator, resolved } = await tab.refLocator({ element: field.name, ref: field.ref });
47
+ const locatorSource = `await page.${resolved}`;
59
48
  if (field.type === "textbox" || field.type === "slider") {
60
49
  const secret = tab.context.lookupSecret(field.value);
61
50
  await locator.fill(secret.value);
@@ -65,7 +54,7 @@ const fillForm = (0, import_tool.defineTabTool)({
65
54
  response.addCode(`${locatorSource}.setChecked(${field.value});`);
66
55
  } else if (field.type === "combobox") {
67
56
  await locator.selectOption({ label: field.value });
68
- response.addCode(`${locatorSource}.selectOption(${codegen.quote(field.value)});`);
57
+ response.addCode(`${locatorSource}.selectOption(${(0, import_utils.escapeWithQuotes)(field.value)});`);
69
58
  }
70
59
  }
71
60
  }
@@ -33,7 +33,7 @@ __export(install_exports, {
33
33
  module.exports = __toCommonJS(install_exports);
34
34
  var import_child_process = require("child_process");
35
35
  var import_path = __toESM(require("path"));
36
- var import_bundle = require("../../sdk/bundle");
36
+ var import_mcpBundle = require("playwright-core/lib/mcpBundle");
37
37
  var import_tool = require("./tool");
38
38
  const install = (0, import_tool.defineTool)({
39
39
  capability: "core-install",
@@ -41,8 +41,8 @@ const install = (0, import_tool.defineTool)({
41
41
  name: "browser_install",
42
42
  title: "Install the browser specified in the config",
43
43
  description: "Install the browser specified in the config. Call this if you get an error about the browser not being installed.",
44
- inputSchema: import_bundle.z.object({}),
45
- type: "destructive"
44
+ inputSchema: import_mcpBundle.z.object({}),
45
+ type: "action"
46
46
  },
47
47
  handle: async (context, params, response) => {
48
48
  const channel = context.config.browser?.launchOptions?.channel ?? context.config.browser?.browserName ?? "chrome";