@cotestdev/mcp_playwright 0.0.14 → 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.
- package/lib/mcp/browser/browserContextFactory.js +49 -13
- package/lib/mcp/browser/browserServerBackend.js +5 -2
- package/lib/mcp/browser/config.js +95 -23
- package/lib/mcp/browser/context.js +28 -3
- package/lib/mcp/browser/response.js +240 -57
- package/lib/mcp/browser/sessionLog.js +1 -1
- package/lib/mcp/browser/tab.js +96 -69
- package/lib/mcp/browser/tools/common.js +8 -8
- package/lib/mcp/browser/tools/console.js +6 -3
- package/lib/mcp/browser/tools/dialogs.js +13 -13
- package/lib/mcp/browser/tools/evaluate.js +9 -20
- package/lib/mcp/browser/tools/files.js +10 -5
- package/lib/mcp/browser/tools/form.js +11 -22
- package/lib/mcp/browser/tools/install.js +3 -3
- package/lib/mcp/browser/tools/keyboard.js +12 -12
- package/lib/mcp/browser/tools/mouse.js +14 -14
- package/lib/mcp/browser/tools/navigate.js +5 -5
- package/lib/mcp/browser/tools/network.js +16 -5
- package/lib/mcp/browser/tools/pdf.js +7 -18
- package/lib/mcp/browser/tools/runCode.js +77 -0
- package/lib/mcp/browser/tools/screenshot.js +44 -33
- package/lib/mcp/browser/tools/snapshot.js +42 -33
- package/lib/mcp/browser/tools/tabs.js +7 -10
- package/lib/mcp/browser/tools/tool.js +8 -7
- package/lib/mcp/browser/tools/tracing.js +4 -4
- package/lib/mcp/browser/tools/utils.js +50 -52
- package/lib/mcp/browser/tools/verify.js +23 -34
- package/lib/mcp/browser/tools/wait.js +6 -6
- package/lib/mcp/browser/tools.js +4 -3
- package/lib/mcp/extension/cdpRelay.js +1 -1
- package/lib/mcp/extension/extensionContextFactory.js +4 -3
- package/lib/mcp/log.js +2 -2
- package/lib/mcp/program.js +21 -29
- package/lib/mcp/sdk/exports.js +1 -5
- package/lib/mcp/sdk/http.js +37 -50
- package/lib/mcp/sdk/server.js +61 -9
- package/lib/mcp/sdk/tool.js +5 -4
- package/lib/mcp/test/browserBackend.js +67 -61
- package/lib/mcp/test/generatorTools.js +122 -0
- package/lib/mcp/test/plannerTools.js +144 -0
- package/lib/mcp/test/seed.js +82 -0
- package/lib/mcp/test/streams.js +10 -7
- package/lib/mcp/test/testBackend.js +44 -24
- package/lib/mcp/test/testContext.js +243 -14
- package/lib/mcp/test/testTools.js +23 -109
- package/lib/util.js +12 -6
- package/package.json +1 -1
package/lib/mcp/browser/tab.js
CHANGED
|
@@ -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
|
|
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:
|
|
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
|
-
|
|
68
|
+
this._initializedPromise = this._initialize();
|
|
71
69
|
}
|
|
72
70
|
static forPage(page) {
|
|
73
71
|
return page[tabSymbol];
|
|
74
72
|
}
|
|
75
|
-
async
|
|
76
|
-
const
|
|
73
|
+
static async collectConsoleMessages(page) {
|
|
74
|
+
const result = [];
|
|
75
|
+
const messages = await page.consoleMessages().catch(() => []);
|
|
77
76
|
for (const message of messages)
|
|
78
|
-
|
|
79
|
-
const errors = await
|
|
77
|
+
result.push(messageToConsoleMessage(message));
|
|
78
|
+
const errors = await page.pageErrors().catch(() => []);
|
|
80
79
|
for (const error of errors)
|
|
81
|
-
|
|
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.
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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:
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
233
|
-
return params.map((param) => {
|
|
234
|
-
|
|
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
|
-
|
|
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:
|
|
269
|
+
type: "error",
|
|
260
270
|
text: errorOrValue.message,
|
|
261
271
|
toString: () => errorOrValue.stack || errorOrValue.message
|
|
262
272
|
};
|
|
263
273
|
}
|
|
264
274
|
return {
|
|
265
|
-
type:
|
|
275
|
+
type: "error",
|
|
266
276
|
text: String(errorOrValue),
|
|
267
277
|
toString: () => String(errorOrValue)
|
|
268
278
|
};
|
|
269
279
|
}
|
|
270
|
-
function renderModalStates(
|
|
271
|
-
const result = [
|
|
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
|
|
279
|
-
function
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
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
|
|
25
|
+
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
|
|
26
26
|
var import_tool = require("./tool");
|
|
27
|
-
const baseSchema =
|
|
28
|
-
toolText:
|
|
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:
|
|
37
|
-
type: "
|
|
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:
|
|
53
|
-
height:
|
|
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: "
|
|
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
|
|
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:
|
|
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(
|
|
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
|
|
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:
|
|
35
|
-
promptText:
|
|
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: "
|
|
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
|
-
|
|
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
|
|
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:
|
|
41
|
-
element:
|
|
42
|
-
ref:
|
|
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: "
|
|
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.${
|
|
47
|
+
response.addCode(`await page.${locator.resolved}.evaluate(${(0, import_utils.escapeWithQuotes)(params.function)});`);
|
|
59
48
|
} else {
|
|
60
|
-
response.addCode(`await page.evaluate(${
|
|
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
|
|
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:
|
|
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: "
|
|
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
|
|
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:
|
|
47
|
-
name:
|
|
48
|
-
type:
|
|
49
|
-
ref:
|
|
50
|
-
value:
|
|
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: "
|
|
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.${
|
|
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(${
|
|
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
|
|
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:
|
|
45
|
-
type: "
|
|
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";
|