@cotestdev/mcp_playwright 0.0.35 → 0.0.37
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 +12 -12
- package/lib/mcp/browser/browserServerBackend.js +24 -12
- package/lib/mcp/browser/config.js +37 -7
- package/lib/mcp/browser/context.js +13 -61
- package/lib/mcp/browser/response.js +183 -251
- package/lib/mcp/browser/sessionLog.js +19 -104
- package/lib/mcp/browser/tab.js +49 -28
- package/lib/mcp/browser/tools/common.js +8 -9
- package/lib/mcp/browser/tools/console.js +20 -3
- package/lib/mcp/browser/tools/dialogs.js +2 -3
- package/lib/mcp/browser/tools/evaluate.js +8 -6
- package/lib/mcp/browser/tools/files.js +2 -2
- package/lib/mcp/browser/tools/form.js +2 -2
- package/lib/mcp/browser/tools/install.js +4 -1
- package/lib/mcp/browser/tools/keyboard.js +77 -10
- package/lib/mcp/browser/tools/mouse.js +59 -7
- package/lib/mcp/browser/tools/navigate.js +51 -8
- package/lib/mcp/browser/tools/network.js +21 -3
- package/lib/mcp/browser/tools/pdf.js +4 -3
- package/lib/mcp/browser/tools/runCode.js +8 -12
- package/lib/mcp/browser/tools/schema.js +31 -0
- package/lib/mcp/browser/tools/screenshot.js +10 -28
- package/lib/mcp/browser/tools/snapshot.js +40 -24
- package/lib/mcp/browser/tools/tabs.js +10 -10
- package/lib/mcp/browser/tools/tool.js +3 -6
- package/lib/mcp/browser/tools/tracing.js +3 -3
- package/lib/mcp/browser/tools/utils.js +2 -2
- package/lib/mcp/browser/tools/verify.js +9 -9
- package/lib/mcp/browser/tools/wait.js +3 -3
- package/lib/mcp/browser/tools.js +2 -2
- package/lib/mcp/extension/extensionContextFactory.js +2 -2
- package/lib/mcp/program.js +3 -2
- package/lib/mcp/terminal/cli.js +4 -216
- package/lib/mcp/terminal/command.js +56 -0
- package/lib/mcp/terminal/commands.js +528 -0
- package/lib/mcp/terminal/daemon.js +42 -25
- package/lib/mcp/terminal/helpGenerator.js +152 -0
- package/lib/mcp/terminal/program.js +434 -0
- package/lib/mcp/terminal/socketConnection.js +2 -4
- package/lib/mcpBundleImpl/index.js +44 -44
- package/lib/util.js +3 -6
- package/package.json +1 -1
|
@@ -23,32 +23,41 @@ __export(navigate_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(navigate_exports);
|
|
24
24
|
var import_mcpBundle = require("../../../mcpBundle");
|
|
25
25
|
var import_tool = require("./tool");
|
|
26
|
-
var
|
|
26
|
+
var import_schema = require("./schema");
|
|
27
27
|
const navigate = (0, import_tool.defineTool)({
|
|
28
|
-
capability: "core",
|
|
28
|
+
capability: "core-navigation",
|
|
29
29
|
schema: {
|
|
30
30
|
name: "browser_navigate",
|
|
31
31
|
title: "Navigate to a URL",
|
|
32
32
|
description: "Navigate to a URL",
|
|
33
|
-
inputSchema:
|
|
33
|
+
inputSchema: import_schema.baseSchema.extend({
|
|
34
34
|
url: import_mcpBundle.z.string().describe("The URL to navigate to")
|
|
35
35
|
}),
|
|
36
36
|
type: "action"
|
|
37
37
|
},
|
|
38
38
|
handle: async (context, params, response) => {
|
|
39
39
|
const tab = await context.ensureTab();
|
|
40
|
-
|
|
40
|
+
let url = params.url;
|
|
41
|
+
try {
|
|
42
|
+
new URL(url);
|
|
43
|
+
} catch (e) {
|
|
44
|
+
if (url.startsWith("localhost"))
|
|
45
|
+
url = "http://" + url;
|
|
46
|
+
else
|
|
47
|
+
url = "https://" + url;
|
|
48
|
+
}
|
|
49
|
+
await tab.navigate(url);
|
|
41
50
|
response.setIncludeSnapshot();
|
|
42
51
|
response.addCode(`await page.goto('${params.url}');`);
|
|
43
52
|
}
|
|
44
53
|
});
|
|
45
54
|
const goBack = (0, import_tool.defineTabTool)({
|
|
46
|
-
capability: "core",
|
|
55
|
+
capability: "core-navigation",
|
|
47
56
|
schema: {
|
|
48
57
|
name: "browser_navigate_back",
|
|
49
58
|
title: "Go back",
|
|
50
|
-
description: "Go back to the previous page",
|
|
51
|
-
inputSchema:
|
|
59
|
+
description: "Go back to the previous page in the history",
|
|
60
|
+
inputSchema: import_schema.baseSchema.extend({}),
|
|
52
61
|
type: "action"
|
|
53
62
|
},
|
|
54
63
|
handle: async (tab, params, response) => {
|
|
@@ -57,7 +66,41 @@ const goBack = (0, import_tool.defineTabTool)({
|
|
|
57
66
|
response.addCode(`await page.goBack();`);
|
|
58
67
|
}
|
|
59
68
|
});
|
|
69
|
+
const goForward = (0, import_tool.defineTabTool)({
|
|
70
|
+
capability: "core-navigation",
|
|
71
|
+
skillOnly: true,
|
|
72
|
+
schema: {
|
|
73
|
+
name: "browser_navigate_forward",
|
|
74
|
+
title: "Go forward",
|
|
75
|
+
description: "Go forward to the next page in the history",
|
|
76
|
+
inputSchema: import_schema.baseSchema.extend({}),
|
|
77
|
+
type: "action"
|
|
78
|
+
},
|
|
79
|
+
handle: async (tab, params, response) => {
|
|
80
|
+
await tab.page.goForward();
|
|
81
|
+
response.setIncludeSnapshot();
|
|
82
|
+
response.addCode(`await page.goForward();`);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
const reload = (0, import_tool.defineTabTool)({
|
|
86
|
+
capability: "core-navigation",
|
|
87
|
+
skillOnly: true,
|
|
88
|
+
schema: {
|
|
89
|
+
name: "browser_reload",
|
|
90
|
+
title: "Reload the page",
|
|
91
|
+
description: "Reload the current page",
|
|
92
|
+
inputSchema: import_schema.baseSchema.extend({}),
|
|
93
|
+
type: "action"
|
|
94
|
+
},
|
|
95
|
+
handle: async (tab, params, response) => {
|
|
96
|
+
await tab.page.reload();
|
|
97
|
+
response.setIncludeSnapshot();
|
|
98
|
+
response.addCode(`await page.reload();`);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
60
101
|
var navigate_default = [
|
|
61
102
|
navigate,
|
|
62
|
-
goBack
|
|
103
|
+
goBack,
|
|
104
|
+
goForward,
|
|
105
|
+
reload
|
|
63
106
|
];
|
|
@@ -30,17 +30,34 @@ const requests = (0, import_tool.defineTabTool)({
|
|
|
30
30
|
title: "List network requests",
|
|
31
31
|
description: "Returns all network requests since loading the page",
|
|
32
32
|
inputSchema: import_mcpBundle.z.object({
|
|
33
|
-
includeStatic: import_mcpBundle.z.boolean().default(false).describe("Whether to include successful static resources like images, fonts, scripts, etc. Defaults to false.")
|
|
33
|
+
includeStatic: import_mcpBundle.z.boolean().default(false).describe("Whether to include successful static resources like images, fonts, scripts, etc. Defaults to false."),
|
|
34
|
+
filename: import_mcpBundle.z.string().optional().describe("Filename to save the network requests to. If not provided, requests are returned as text.")
|
|
34
35
|
}),
|
|
35
36
|
type: "readOnly"
|
|
36
37
|
},
|
|
37
38
|
handle: async (tab, params, response) => {
|
|
38
39
|
const requests2 = await tab.requests();
|
|
40
|
+
const text = [];
|
|
39
41
|
for (const request of requests2) {
|
|
40
42
|
const rendered = await renderRequest(request, params.includeStatic);
|
|
41
43
|
if (rendered)
|
|
42
|
-
|
|
44
|
+
text.push(rendered);
|
|
43
45
|
}
|
|
46
|
+
await response.addResult("Network", text.join("\n"), { prefix: "network", ext: "log", suggestedFilename: params.filename });
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
const networkClear = (0, import_tool.defineTabTool)({
|
|
50
|
+
capability: "core",
|
|
51
|
+
skillOnly: true,
|
|
52
|
+
schema: {
|
|
53
|
+
name: "browser_network_clear",
|
|
54
|
+
title: "Clear network requests",
|
|
55
|
+
description: "Clear all network requests",
|
|
56
|
+
inputSchema: import_mcpBundle.z.object({}),
|
|
57
|
+
type: "readOnly"
|
|
58
|
+
},
|
|
59
|
+
handle: async (tab, params, response) => {
|
|
60
|
+
await tab.clearRequests();
|
|
44
61
|
}
|
|
45
62
|
});
|
|
46
63
|
async function renderRequest(request, includeStatic) {
|
|
@@ -56,5 +73,6 @@ async function renderRequest(request, includeStatic) {
|
|
|
56
73
|
return result.join(" ");
|
|
57
74
|
}
|
|
58
75
|
var network_default = [
|
|
59
|
-
requests
|
|
76
|
+
requests,
|
|
77
|
+
networkClear
|
|
60
78
|
];
|
|
@@ -38,9 +38,10 @@ const pdf = (0, import_tool.defineTabTool)({
|
|
|
38
38
|
type: "readOnly"
|
|
39
39
|
},
|
|
40
40
|
handle: async (tab, params, response) => {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
await
|
|
41
|
+
const data = await tab.page.pdf();
|
|
42
|
+
const suggestedFilename = params.filename ?? (0, import_utils2.dateAsFileName)("page", "pdf");
|
|
43
|
+
await response.addResult("Page as pdf", data, { prefix: "page", ext: "pdf", suggestedFilename });
|
|
44
|
+
response.addCode(`await page.pdf(${(0, import_utils.formatObject)({ path: suggestedFilename })});`);
|
|
44
45
|
}
|
|
45
46
|
});
|
|
46
47
|
var pdf_default = [
|
|
@@ -35,9 +35,10 @@ var import_vm = __toESM(require("vm"));
|
|
|
35
35
|
var import_utils = require("playwright-core/lib/utils");
|
|
36
36
|
var import_test = require("playwright/test");
|
|
37
37
|
var import_mcpBundle = require("../../../mcpBundle");
|
|
38
|
+
var import_ai_runner = require("@cotestdev/ai-runner");
|
|
38
39
|
var import_tool = require("./tool");
|
|
39
|
-
var
|
|
40
|
-
const codeSchema =
|
|
40
|
+
var import_schema = require("./schema");
|
|
41
|
+
const codeSchema = import_schema.baseSchema.extend({
|
|
41
42
|
code: import_mcpBundle.z.string().describe(`A JavaScript function containing Playwright code to execute. It will be invoked with a single argument, page, which you can use for any page interaction. For example: \`async (page) => { await page.getByRole('button', { name: 'Submit' }).click(); return await page.title(); }\``)
|
|
42
43
|
});
|
|
43
44
|
const runCode = (0, import_tool.defineTabTool)({
|
|
@@ -50,7 +51,6 @@ const runCode = (0, import_tool.defineTabTool)({
|
|
|
50
51
|
type: "action"
|
|
51
52
|
},
|
|
52
53
|
handle: async (tab, params, response) => {
|
|
53
|
-
response.setIncludeSnapshot();
|
|
54
54
|
response.addCode(`await (${params.code})(page);`);
|
|
55
55
|
const __end__ = new import_utils.ManualPromise();
|
|
56
56
|
const context = {
|
|
@@ -70,13 +70,12 @@ const runCode = (0, import_tool.defineTabTool)({
|
|
|
70
70
|
await import_vm.default.runInContext(snippet, context);
|
|
71
71
|
const result = await __end__;
|
|
72
72
|
if (typeof result === "string")
|
|
73
|
-
response.
|
|
73
|
+
response.addTextResult(result);
|
|
74
74
|
});
|
|
75
75
|
}
|
|
76
76
|
});
|
|
77
|
-
const scriptSchema =
|
|
78
|
-
code: import_mcpBundle.z.string().describe(`A JavaScript function containing Playwright code to execute. It will be invoked with a single argument, page, which you can use for any page interaction. For example: \`async (page) => { await page.getByRole('button', { name: 'Submit' }).click(); return await page.title(); }\``)
|
|
79
|
-
params: import_mcpBundle.z.record(import_mcpBundle.z.any()).optional().describe("Parameters to pass to the script.")
|
|
77
|
+
const scriptSchema = import_mcpBundle.z.object({
|
|
78
|
+
code: import_mcpBundle.z.string().describe(`A JavaScript function containing Playwright code to execute. It will be invoked with a single argument, page, which you can use for any page interaction. For example: \`async (page) => { await page.getByRole('button', { name: 'Submit' }).click(); return await page.title(); }\``)
|
|
80
79
|
});
|
|
81
80
|
const runScript = (0, import_tool.defineTabTool)({
|
|
82
81
|
capability: "extra",
|
|
@@ -93,12 +92,9 @@ const runScript = (0, import_tool.defineTabTool)({
|
|
|
93
92
|
const context = {
|
|
94
93
|
page: tab.page,
|
|
95
94
|
expect: import_test.expect,
|
|
95
|
+
Runner: import_ai_runner.Runner,
|
|
96
96
|
__end__
|
|
97
97
|
};
|
|
98
|
-
if (params.params) {
|
|
99
|
-
for (const [key, value] of Object.entries(params.params))
|
|
100
|
-
context[key] = value;
|
|
101
|
-
}
|
|
102
98
|
import_vm.default.createContext(context);
|
|
103
99
|
await tab.waitForCompletion(async () => {
|
|
104
100
|
const snippet = `(async () => {
|
|
@@ -112,7 +108,7 @@ const runScript = (0, import_tool.defineTabTool)({
|
|
|
112
108
|
await import_vm.default.runInContext(snippet, context);
|
|
113
109
|
const result = await __end__;
|
|
114
110
|
if (typeof result === "string")
|
|
115
|
-
response.
|
|
111
|
+
response.addTextResult(result);
|
|
116
112
|
});
|
|
117
113
|
}
|
|
118
114
|
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var schema_exports = {};
|
|
20
|
+
__export(schema_exports, {
|
|
21
|
+
baseSchema: () => baseSchema
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(schema_exports);
|
|
24
|
+
var import_mcpBundle = require("../../../mcpBundle");
|
|
25
|
+
const baseSchema = import_mcpBundle.z.object({
|
|
26
|
+
toolText: import_mcpBundle.z.string().describe("A human-readable description of the action to perform by the tool.")
|
|
27
|
+
});
|
|
28
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
29
|
+
0 && (module.exports = {
|
|
30
|
+
baseSchema
|
|
31
|
+
});
|
|
@@ -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,14 +15,6 @@ 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 screenshot_exports = {};
|
|
30
20
|
__export(screenshot_exports, {
|
|
@@ -32,15 +22,14 @@ __export(screenshot_exports, {
|
|
|
32
22
|
scaleImageToFitMessage: () => scaleImageToFitMessage
|
|
33
23
|
});
|
|
34
24
|
module.exports = __toCommonJS(screenshot_exports);
|
|
35
|
-
var import_fs = __toESM(require("fs"));
|
|
36
25
|
var import_utils = require("playwright-core/lib/utils");
|
|
37
26
|
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
|
|
38
27
|
var import_utils2 = require("playwright-core/lib/utils");
|
|
39
28
|
var import_mcpBundle = require("../../../mcpBundle");
|
|
40
29
|
var import_tool = require("./tool");
|
|
41
30
|
var import_utils3 = require("./utils");
|
|
42
|
-
var
|
|
43
|
-
const screenshotSchema =
|
|
31
|
+
var import_schema = require("./schema");
|
|
32
|
+
const screenshotSchema = import_schema.baseSchema.extend({
|
|
44
33
|
type: import_mcpBundle.z.enum(["png", "jpeg"]).default("png").describe("Image format for the screenshot. Default is png."),
|
|
45
34
|
filename: import_mcpBundle.z.string().optional().describe("File name to save the screenshot to. Defaults to `page-{timestamp}.{png|jpeg}` if not specified. Prefer relative file names to stay within the output directory."),
|
|
46
35
|
element: import_mcpBundle.z.string().optional().describe("Human-readable element description used to obtain permission to screenshot the element. If not provided, the screenshot will be taken of viewport. If element is provided, ref must be provided too."),
|
|
@@ -57,8 +46,6 @@ const screenshot = (0, import_tool.defineTabTool)({
|
|
|
57
46
|
type: "readOnly"
|
|
58
47
|
},
|
|
59
48
|
handle: async (tab, params, response) => {
|
|
60
|
-
if (!!params.element !== !!params.ref)
|
|
61
|
-
throw new Error("Both element and ref must be provided or neither.");
|
|
62
49
|
if (params.fullPage && params.ref)
|
|
63
50
|
throw new Error("fullPage cannot be used with element screenshots.");
|
|
64
51
|
const fileType = params.type || "png";
|
|
@@ -68,22 +55,17 @@ const screenshot = (0, import_tool.defineTabTool)({
|
|
|
68
55
|
scale: "css",
|
|
69
56
|
...params.fullPage !== void 0 && { fullPage: params.fullPage }
|
|
70
57
|
};
|
|
71
|
-
const
|
|
72
|
-
const screenshotTarget = isElementScreenshot ? params.element : params.fullPage ? "full page" : "viewport";
|
|
73
|
-
const fileName = await response.addFile(params.filename || (0, import_utils3.dateAsFileName)(fileType), { origin: "llm", reason: `Screenshot of ${screenshotTarget}` });
|
|
74
|
-
response.addCode(`// Screenshot ${screenshotTarget} and save it as ${fileName}`);
|
|
58
|
+
const screenshotTarget = params.ref ? params.element || "element" : params.fullPage ? "full page" : "viewport";
|
|
75
59
|
const ref = params.ref ? await tab.refLocator({ element: params.element || "", ref: params.ref }) : null;
|
|
60
|
+
const data = ref ? await ref.locator.screenshot(options) : await tab.page.screenshot(options);
|
|
61
|
+
const suggestedFilename = params.filename || (0, import_utils3.dateAsFileName)(ref ? "element" : "page", fileType);
|
|
62
|
+
response.addCode(`// Screenshot ${screenshotTarget} and save it as ${suggestedFilename}`);
|
|
76
63
|
if (ref)
|
|
77
|
-
response.addCode(`await page.${ref.resolved}.screenshot(${(0, import_utils2.formatObject)(options)});`);
|
|
64
|
+
response.addCode(`await page.${ref.resolved}.screenshot(${(0, import_utils2.formatObject)({ ...options, path: suggestedFilename })});`);
|
|
78
65
|
else
|
|
79
|
-
response.addCode(`await page.screenshot(${(0, import_utils2.formatObject)(options)});`);
|
|
80
|
-
const
|
|
81
|
-
await (
|
|
82
|
-
await import_fs.default.promises.writeFile(fileName, buffer);
|
|
83
|
-
response.addImage({
|
|
84
|
-
contentType: fileType === "png" ? "image/png" : "image/jpeg",
|
|
85
|
-
data: scaleImageToFitMessage(buffer, fileType)
|
|
86
|
-
});
|
|
66
|
+
response.addCode(`await page.screenshot(${(0, import_utils2.formatObject)({ ...options, path: suggestedFilename })});`);
|
|
67
|
+
const contentType = fileType === "png" ? "image/png" : "image/jpeg";
|
|
68
|
+
await response.addResult(`Screenshot of ${screenshotTarget}`, data, { prefix: ref ? "element" : "page", ext: fileType, suggestedFilename, contentType });
|
|
87
69
|
}
|
|
88
70
|
});
|
|
89
71
|
function scaleImageToFitMessage(buffer, imageType) {
|
|
@@ -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,14 +15,6 @@ 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 snapshot_exports = {};
|
|
30
20
|
__export(snapshot_exports, {
|
|
@@ -32,11 +22,10 @@ __export(snapshot_exports, {
|
|
|
32
22
|
elementSchema: () => elementSchema
|
|
33
23
|
});
|
|
34
24
|
module.exports = __toCommonJS(snapshot_exports);
|
|
35
|
-
var import_fs = __toESM(require("fs"));
|
|
36
25
|
var import_mcpBundle = require("../../../mcpBundle");
|
|
37
26
|
var import_utils = require("playwright-core/lib/utils");
|
|
38
27
|
var import_tool = require("./tool");
|
|
39
|
-
var
|
|
28
|
+
var import_schema = require("./schema");
|
|
40
29
|
const snapshot = (0, import_tool.defineTool)({
|
|
41
30
|
capability: "core",
|
|
42
31
|
schema: {
|
|
@@ -50,17 +39,10 @@ const snapshot = (0, import_tool.defineTool)({
|
|
|
50
39
|
},
|
|
51
40
|
handle: async (context, params, response) => {
|
|
52
41
|
await context.ensureTab();
|
|
53
|
-
response.setIncludeFullSnapshot();
|
|
54
|
-
if (params.filename) {
|
|
55
|
-
await response.finish();
|
|
56
|
-
const renderedResponse = response.render();
|
|
57
|
-
const fileName = await response.addFile(params.filename, { origin: "llm", reason: "Saved snapshot" });
|
|
58
|
-
await import_fs.default.promises.writeFile(fileName, renderedResponse.asText());
|
|
59
|
-
response.setIncludeMetaOnly();
|
|
60
|
-
}
|
|
42
|
+
response.setIncludeFullSnapshot(params.filename);
|
|
61
43
|
}
|
|
62
44
|
});
|
|
63
|
-
const elementSchema =
|
|
45
|
+
const elementSchema = import_schema.baseSchema.extend({
|
|
64
46
|
element: import_mcpBundle.z.string().optional().describe("Human-readable element description used to obtain permission to interact with the element"),
|
|
65
47
|
ref: import_mcpBundle.z.string().describe("Exact target element reference from the page snapshot")
|
|
66
48
|
});
|
|
@@ -105,7 +87,7 @@ const drag = (0, import_tool.defineTabTool)({
|
|
|
105
87
|
name: "browser_drag",
|
|
106
88
|
title: "Drag mouse",
|
|
107
89
|
description: "Perform drag and drop between two elements",
|
|
108
|
-
inputSchema:
|
|
90
|
+
inputSchema: import_schema.baseSchema.extend({
|
|
109
91
|
startElement: import_mcpBundle.z.string().describe("Human-readable source element description used to obtain the permission to interact with the element"),
|
|
110
92
|
startRef: import_mcpBundle.z.string().describe("Exact source element reference from the page snapshot"),
|
|
111
93
|
endElement: import_mcpBundle.z.string().describe("Human-readable target element description used to obtain the permission to interact with the element"),
|
|
@@ -175,7 +157,39 @@ const pickLocator = (0, import_tool.defineTabTool)({
|
|
|
175
157
|
},
|
|
176
158
|
handle: async (tab, params, response) => {
|
|
177
159
|
const { resolved } = await tab.refLocator(params);
|
|
178
|
-
response.
|
|
160
|
+
response.addTextResult(resolved);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
const check = (0, import_tool.defineTabTool)({
|
|
164
|
+
capability: "core-input",
|
|
165
|
+
skillOnly: true,
|
|
166
|
+
schema: {
|
|
167
|
+
name: "browser_check",
|
|
168
|
+
title: "Check",
|
|
169
|
+
description: "Check a checkbox or radio button",
|
|
170
|
+
inputSchema: elementSchema,
|
|
171
|
+
type: "input"
|
|
172
|
+
},
|
|
173
|
+
handle: async (tab, params, response) => {
|
|
174
|
+
const { locator, resolved } = await tab.refLocator(params);
|
|
175
|
+
response.addCode(`await page.${resolved}.check();`);
|
|
176
|
+
await locator.check();
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
const uncheck = (0, import_tool.defineTabTool)({
|
|
180
|
+
capability: "core-input",
|
|
181
|
+
skillOnly: true,
|
|
182
|
+
schema: {
|
|
183
|
+
name: "browser_uncheck",
|
|
184
|
+
title: "Uncheck",
|
|
185
|
+
description: "Uncheck a checkbox or radio button",
|
|
186
|
+
inputSchema: elementSchema,
|
|
187
|
+
type: "input"
|
|
188
|
+
},
|
|
189
|
+
handle: async (tab, params, response) => {
|
|
190
|
+
const { locator, resolved } = await tab.refLocator(params);
|
|
191
|
+
response.addCode(`await page.${resolved}.uncheck();`);
|
|
192
|
+
await locator.uncheck();
|
|
179
193
|
}
|
|
180
194
|
});
|
|
181
195
|
var snapshot_default = [
|
|
@@ -184,7 +198,9 @@ var snapshot_default = [
|
|
|
184
198
|
drag,
|
|
185
199
|
hover,
|
|
186
200
|
selectOption,
|
|
187
|
-
pickLocator
|
|
201
|
+
pickLocator,
|
|
202
|
+
check,
|
|
203
|
+
uncheck
|
|
188
204
|
];
|
|
189
205
|
// Annotate the CommonJS export names for ESM import in node:
|
|
190
206
|
0 && (module.exports = {
|
|
@@ -23,14 +23,15 @@ __export(tabs_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(tabs_exports);
|
|
24
24
|
var import_mcpBundle = require("../../../mcpBundle");
|
|
25
25
|
var import_tool = require("./tool");
|
|
26
|
-
var
|
|
26
|
+
var import_response = require("../response");
|
|
27
|
+
var import_schema = require("./schema");
|
|
27
28
|
const browserTabs = (0, import_tool.defineTool)({
|
|
28
29
|
capability: "core-tabs",
|
|
29
30
|
schema: {
|
|
30
31
|
name: "browser_tabs",
|
|
31
32
|
title: "Manage tabs",
|
|
32
33
|
description: "List, create, close, or select a browser tab.",
|
|
33
|
-
inputSchema:
|
|
34
|
+
inputSchema: import_schema.baseSchema.extend({
|
|
34
35
|
action: import_mcpBundle.z.enum(["list", "new", "close", "select"]).describe("Operation to perform"),
|
|
35
36
|
index: import_mcpBundle.z.number().optional().describe("Tab index, used for close/select. If omitted for close, current tab is closed.")
|
|
36
37
|
}),
|
|
@@ -40,27 +41,26 @@ const browserTabs = (0, import_tool.defineTool)({
|
|
|
40
41
|
switch (params.action) {
|
|
41
42
|
case "list": {
|
|
42
43
|
await context.ensureTab();
|
|
43
|
-
|
|
44
|
-
return;
|
|
44
|
+
break;
|
|
45
45
|
}
|
|
46
46
|
case "new": {
|
|
47
47
|
await context.newTab();
|
|
48
|
-
|
|
49
|
-
return;
|
|
48
|
+
break;
|
|
50
49
|
}
|
|
51
50
|
case "close": {
|
|
52
51
|
await context.closeTab(params.index);
|
|
53
|
-
|
|
54
|
-
return;
|
|
52
|
+
break;
|
|
55
53
|
}
|
|
56
54
|
case "select": {
|
|
57
55
|
if (params.index === void 0)
|
|
58
56
|
throw new Error("Tab index is required");
|
|
59
57
|
await context.selectTab(params.index);
|
|
60
|
-
|
|
61
|
-
return;
|
|
58
|
+
break;
|
|
62
59
|
}
|
|
63
60
|
}
|
|
61
|
+
const tabHeaders = await Promise.all(context.tabs().map((tab) => tab.headerSnapshot()));
|
|
62
|
+
const result = (0, import_response.renderTabsMarkdown)(tabHeaders);
|
|
63
|
+
response.addTextResult(result.join("\n"));
|
|
64
64
|
}
|
|
65
65
|
});
|
|
66
66
|
var tabs_default = [
|
|
@@ -31,15 +31,12 @@ function defineTabTool(tool) {
|
|
|
31
31
|
handle: async (context, params, response) => {
|
|
32
32
|
const tab = await context.ensureTab();
|
|
33
33
|
const modalStates = tab.modalStates().map((state) => state.type);
|
|
34
|
-
if (tool.clearsModalState && !modalStates.includes(tool.clearsModalState))
|
|
35
|
-
response.setIncludeModalStates(tab.modalStates());
|
|
34
|
+
if (tool.clearsModalState && !modalStates.includes(tool.clearsModalState))
|
|
36
35
|
response.addError(`Error: The tool "${tool.schema.name}" can only be used when there is related modal state present.`);
|
|
37
|
-
|
|
38
|
-
response.setIncludeModalStates(tab.modalStates());
|
|
36
|
+
else if (!tool.clearsModalState && modalStates.length)
|
|
39
37
|
response.addError(`Error: Tool "${tool.schema.name}" does not handle the modal state.`);
|
|
40
|
-
|
|
38
|
+
else
|
|
41
39
|
return tool.handle(tab, params, response);
|
|
42
|
-
}
|
|
43
40
|
}
|
|
44
41
|
};
|
|
45
42
|
}
|
|
@@ -34,7 +34,7 @@ const tracingStart = (0, import_tool.defineTool)({
|
|
|
34
34
|
},
|
|
35
35
|
handle: async (context, params, response) => {
|
|
36
36
|
const browserContext = await context.ensureBrowserContext();
|
|
37
|
-
const tracesDir = await context.outputFile(`traces`, { origin: "code",
|
|
37
|
+
const tracesDir = await context.outputFile(`traces`, { origin: "code", title: "Collecting trace" });
|
|
38
38
|
const name = "trace-" + Date.now();
|
|
39
39
|
await browserContext.tracing.start({
|
|
40
40
|
name,
|
|
@@ -45,7 +45,7 @@ const tracingStart = (0, import_tool.defineTool)({
|
|
|
45
45
|
const traceLegend = `- Action log: ${tracesDir}/${name}.trace
|
|
46
46
|
- Network log: ${tracesDir}/${name}.network
|
|
47
47
|
- Resources with content by sha1: ${tracesDir}/resources`;
|
|
48
|
-
response.
|
|
48
|
+
response.addTextResult(`Tracing started, saving to ${tracesDir}.
|
|
49
49
|
${traceLegend}`);
|
|
50
50
|
browserContext.tracing[traceLegendSymbol] = traceLegend;
|
|
51
51
|
}
|
|
@@ -63,7 +63,7 @@ const tracingStop = (0, import_tool.defineTool)({
|
|
|
63
63
|
const browserContext = await context.ensureBrowserContext();
|
|
64
64
|
await browserContext.tracing.stop();
|
|
65
65
|
const traceLegend = browserContext.tracing[traceLegendSymbol];
|
|
66
|
-
response.
|
|
66
|
+
response.addTextResult(`Tracing stopped.
|
|
67
67
|
${traceLegend}`);
|
|
68
68
|
}
|
|
69
69
|
});
|
|
@@ -62,9 +62,9 @@ async function waitForCompletion(tab, callback) {
|
|
|
62
62
|
async function callOnPageNoTrace(page, callback) {
|
|
63
63
|
return await page._wrapApiCall(() => callback(page), { internal: true });
|
|
64
64
|
}
|
|
65
|
-
function dateAsFileName(extension) {
|
|
65
|
+
function dateAsFileName(prefix, extension) {
|
|
66
66
|
const date = /* @__PURE__ */ new Date();
|
|
67
|
-
return
|
|
67
|
+
return `${prefix}-${date.toISOString().replace(/[:.]/g, "-")}.${extension}`;
|
|
68
68
|
}
|
|
69
69
|
function eventWaiter(page, event, timeout) {
|
|
70
70
|
const disposables = [];
|
|
@@ -24,14 +24,14 @@ module.exports = __toCommonJS(verify_exports);
|
|
|
24
24
|
var import_mcpBundle = require("../../../mcpBundle");
|
|
25
25
|
var import_utils = require("playwright-core/lib/utils");
|
|
26
26
|
var import_tool = require("./tool");
|
|
27
|
-
var
|
|
27
|
+
var import_schema = require("./schema");
|
|
28
28
|
const verifyElement = (0, import_tool.defineTabTool)({
|
|
29
29
|
capability: "testing",
|
|
30
30
|
schema: {
|
|
31
31
|
name: "browser_verify_element_visible",
|
|
32
32
|
title: "Verify element visible",
|
|
33
33
|
description: "Verify element is visible on the page",
|
|
34
|
-
inputSchema:
|
|
34
|
+
inputSchema: import_schema.baseSchema.extend({
|
|
35
35
|
role: import_mcpBundle.z.string().describe('ROLE of the element. Can be found in the snapshot like this: `- {ROLE} "Accessible Name":`'),
|
|
36
36
|
accessibleName: import_mcpBundle.z.string().describe('ACCESSIBLE_NAME of the element. Can be found in the snapshot like this: `- role "{ACCESSIBLE_NAME}"`')
|
|
37
37
|
}),
|
|
@@ -44,7 +44,7 @@ const verifyElement = (0, import_tool.defineTabTool)({
|
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
46
46
|
response.addCode(`await expect(page.getByRole(${(0, import_utils.escapeWithQuotes)(params.role)}, { name: ${(0, import_utils.escapeWithQuotes)(params.accessibleName)} })).toBeVisible();`);
|
|
47
|
-
response.
|
|
47
|
+
response.addTextResult("Done");
|
|
48
48
|
}
|
|
49
49
|
});
|
|
50
50
|
const verifyText = (0, import_tool.defineTabTool)({
|
|
@@ -53,7 +53,7 @@ const verifyText = (0, import_tool.defineTabTool)({
|
|
|
53
53
|
name: "browser_verify_text_visible",
|
|
54
54
|
title: "Verify text visible",
|
|
55
55
|
description: `Verify text is visible on the page. Prefer ${verifyElement.schema.name} if possible.`,
|
|
56
|
-
inputSchema:
|
|
56
|
+
inputSchema: import_schema.baseSchema.extend({
|
|
57
57
|
text: import_mcpBundle.z.string().describe('TEXT to verify. Can be found in the snapshot like this: `- role "Accessible Name": {TEXT}` or like this: `- text: {TEXT}`')
|
|
58
58
|
}),
|
|
59
59
|
type: "assertion"
|
|
@@ -65,7 +65,7 @@ const verifyText = (0, import_tool.defineTabTool)({
|
|
|
65
65
|
return;
|
|
66
66
|
}
|
|
67
67
|
response.addCode(`await expect(page.getByText(${(0, import_utils.escapeWithQuotes)(params.text)})).toBeVisible();`);
|
|
68
|
-
response.
|
|
68
|
+
response.addTextResult("Done");
|
|
69
69
|
}
|
|
70
70
|
});
|
|
71
71
|
const verifyList = (0, import_tool.defineTabTool)({
|
|
@@ -74,7 +74,7 @@ const verifyList = (0, import_tool.defineTabTool)({
|
|
|
74
74
|
name: "browser_verify_list_visible",
|
|
75
75
|
title: "Verify list visible",
|
|
76
76
|
description: "Verify list is visible on the page",
|
|
77
|
-
inputSchema:
|
|
77
|
+
inputSchema: import_schema.baseSchema.extend({
|
|
78
78
|
element: import_mcpBundle.z.string().describe("Human-readable list description"),
|
|
79
79
|
ref: import_mcpBundle.z.string().describe("Exact target element reference that points to the list"),
|
|
80
80
|
items: import_mcpBundle.z.array(import_mcpBundle.z.string()).describe("Items to verify")
|
|
@@ -97,7 +97,7 @@ const verifyList = (0, import_tool.defineTabTool)({
|
|
|
97
97
|
${itemTexts.map((t) => ` - listitem: ${(0, import_utils.escapeWithQuotes)(t, '"')}`).join("\n")}
|
|
98
98
|
\``;
|
|
99
99
|
response.addCode(`await expect(page.locator('body')).toMatchAriaSnapshot(${ariaSnapshot});`);
|
|
100
|
-
response.
|
|
100
|
+
response.addTextResult("Done");
|
|
101
101
|
}
|
|
102
102
|
});
|
|
103
103
|
const verifyValue = (0, import_tool.defineTabTool)({
|
|
@@ -106,7 +106,7 @@ const verifyValue = (0, import_tool.defineTabTool)({
|
|
|
106
106
|
name: "browser_verify_value",
|
|
107
107
|
title: "Verify value",
|
|
108
108
|
description: "Verify element value",
|
|
109
|
-
inputSchema:
|
|
109
|
+
inputSchema: import_schema.baseSchema.extend({
|
|
110
110
|
type: import_mcpBundle.z.enum(["textbox", "checkbox", "radio", "combobox", "slider"]).describe("Type of the element"),
|
|
111
111
|
element: import_mcpBundle.z.string().describe("Human-readable element description"),
|
|
112
112
|
ref: import_mcpBundle.z.string().describe("Exact target element reference that points to the element"),
|
|
@@ -133,7 +133,7 @@ const verifyValue = (0, import_tool.defineTabTool)({
|
|
|
133
133
|
const matcher = value ? "toBeChecked" : "not.toBeChecked";
|
|
134
134
|
response.addCode(`await expect(${locatorSource}).${matcher}();`);
|
|
135
135
|
}
|
|
136
|
-
response.
|
|
136
|
+
response.addTextResult("Done");
|
|
137
137
|
}
|
|
138
138
|
});
|
|
139
139
|
var verify_default = [
|