@tontoko/fast-playwright-mcp 0.0.4
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/LICENSE +202 -0
- package/README.md +1047 -0
- package/cli.js +18 -0
- package/config.d.ts +124 -0
- package/index.d.ts +25 -0
- package/index.js +18 -0
- package/lib/actions.d.js +0 -0
- package/lib/batch/batch-executor.js +137 -0
- package/lib/browser-context-factory.js +252 -0
- package/lib/browser-server-backend.js +139 -0
- package/lib/config/constants.js +80 -0
- package/lib/config.js +405 -0
- package/lib/context.js +274 -0
- package/lib/diagnostics/common/diagnostic-base.js +63 -0
- package/lib/diagnostics/common/error-enrichment-utils.js +212 -0
- package/lib/diagnostics/common/index.js +56 -0
- package/lib/diagnostics/common/initialization-manager.js +210 -0
- package/lib/diagnostics/common/performance-tracker.js +132 -0
- package/lib/diagnostics/diagnostic-error.js +140 -0
- package/lib/diagnostics/diagnostic-level.js +123 -0
- package/lib/diagnostics/diagnostic-thresholds.js +347 -0
- package/lib/diagnostics/element-discovery.js +441 -0
- package/lib/diagnostics/enhanced-error-handler.js +376 -0
- package/lib/diagnostics/error-enrichment.js +157 -0
- package/lib/diagnostics/frame-reference-manager.js +179 -0
- package/lib/diagnostics/page-analyzer.js +639 -0
- package/lib/diagnostics/parallel-page-analyzer.js +129 -0
- package/lib/diagnostics/resource-manager.js +134 -0
- package/lib/diagnostics/smart-config.js +482 -0
- package/lib/diagnostics/smart-handle.js +118 -0
- package/lib/diagnostics/unified-system.js +717 -0
- package/lib/extension/cdp-relay.js +486 -0
- package/lib/extension/extension-context-factory.js +74 -0
- package/lib/extension/main.js +41 -0
- package/lib/file-utils.js +42 -0
- package/lib/generate-keys.js +75 -0
- package/lib/http-server.js +50 -0
- package/lib/in-process-client.js +64 -0
- package/lib/index.js +48 -0
- package/lib/javascript.js +90 -0
- package/lib/log.js +33 -0
- package/lib/loop/loop-claude.js +247 -0
- package/lib/loop/loop-open-ai.js +222 -0
- package/lib/loop/loop.js +174 -0
- package/lib/loop/main.js +46 -0
- package/lib/loopTools/context.js +76 -0
- package/lib/loopTools/main.js +65 -0
- package/lib/loopTools/perform.js +40 -0
- package/lib/loopTools/snapshot.js +37 -0
- package/lib/loopTools/tool.js +26 -0
- package/lib/manual-promise.js +125 -0
- package/lib/mcp/in-process-transport.js +91 -0
- package/lib/mcp/proxy-backend.js +127 -0
- package/lib/mcp/server.js +123 -0
- package/lib/mcp/transport.js +159 -0
- package/lib/package.js +28 -0
- package/lib/program.js +82 -0
- package/lib/response.js +493 -0
- package/lib/schemas/expectation.js +152 -0
- package/lib/session-log.js +210 -0
- package/lib/tab.js +417 -0
- package/lib/tools/base-tool-handler.js +141 -0
- package/lib/tools/batch-execute.js +150 -0
- package/lib/tools/common.js +65 -0
- package/lib/tools/console.js +60 -0
- package/lib/tools/diagnose/diagnose-analysis-runner.js +101 -0
- package/lib/tools/diagnose/diagnose-config-handler.js +130 -0
- package/lib/tools/diagnose/diagnose-report-builder.js +394 -0
- package/lib/tools/diagnose.js +147 -0
- package/lib/tools/dialogs.js +57 -0
- package/lib/tools/evaluate.js +67 -0
- package/lib/tools/files.js +53 -0
- package/lib/tools/find-elements.js +307 -0
- package/lib/tools/install.js +60 -0
- package/lib/tools/keyboard.js +93 -0
- package/lib/tools/mouse.js +110 -0
- package/lib/tools/navigate.js +82 -0
- package/lib/tools/network.js +50 -0
- package/lib/tools/pdf.js +46 -0
- package/lib/tools/screenshot.js +113 -0
- package/lib/tools/snapshot.js +158 -0
- package/lib/tools/tabs.js +97 -0
- package/lib/tools/tool.js +47 -0
- package/lib/tools/utils.js +131 -0
- package/lib/tools/wait.js +64 -0
- package/lib/tools.js +65 -0
- package/lib/types/batch.js +47 -0
- package/lib/types/diff.js +0 -0
- package/lib/types/performance.js +0 -0
- package/lib/types/threshold-base.js +0 -0
- package/lib/utils/array-utils.js +44 -0
- package/lib/utils/code-deduplication-utils.js +141 -0
- package/lib/utils/common-formatters.js +252 -0
- package/lib/utils/console-filter.js +64 -0
- package/lib/utils/diagnostic-report-utils.js +178 -0
- package/lib/utils/diff-formatter.js +126 -0
- package/lib/utils/disposable-manager.js +135 -0
- package/lib/utils/error-handler-middleware.js +77 -0
- package/lib/utils/image-processor.js +137 -0
- package/lib/utils/index.js +92 -0
- package/lib/utils/report-builder.js +189 -0
- package/lib/utils/request-logger.js +82 -0
- package/lib/utils/response-diff-detector.js +150 -0
- package/lib/utils/section-builder.js +62 -0
- package/lib/utils/tool-patterns.js +153 -0
- package/lib/utils.js +46 -0
- package/package.json +77 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
|
+
|
|
20
|
+
// src/tools/navigate.ts
|
|
21
|
+
import { z } from "zod";
|
|
22
|
+
import { expectationSchema } from "../schemas/expectation.js";
|
|
23
|
+
import {
|
|
24
|
+
generateBackCode,
|
|
25
|
+
generateForwardCode,
|
|
26
|
+
generateNavigationCode
|
|
27
|
+
} from "../utils/common-formatters.js";
|
|
28
|
+
import { defineTabTool, defineTool } from "./tool.js";
|
|
29
|
+
var navigate = defineTool({
|
|
30
|
+
capability: "core",
|
|
31
|
+
schema: {
|
|
32
|
+
name: "browser_navigate",
|
|
33
|
+
title: "Navigate to a URL",
|
|
34
|
+
description: `Navigate to a URL.expectation:{includeSnapshot:true} to see what loaded,false if you know what to do next.snapshotOptions:{selector:"#content"} to focus on main content(saves 50% tokens).diffOptions:{enabled:true} when revisiting pages to see only changes.CONSIDER batch_execute for navigate→interact workflows.`,
|
|
35
|
+
inputSchema: z.object({
|
|
36
|
+
url: z.string().describe("The URL to navigate to"),
|
|
37
|
+
expectation: expectationSchema
|
|
38
|
+
}),
|
|
39
|
+
type: "destructive"
|
|
40
|
+
},
|
|
41
|
+
handle: async (context, params, response) => {
|
|
42
|
+
const tab = await context.ensureTab();
|
|
43
|
+
await tab.navigate(params.url);
|
|
44
|
+
response.addCode(generateNavigationCode(params.url));
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
var goBack = defineTabTool({
|
|
48
|
+
capability: "core",
|
|
49
|
+
schema: {
|
|
50
|
+
name: "browser_navigate_back",
|
|
51
|
+
title: "Go back",
|
|
52
|
+
description: "Go back to previous page.expectation:{includeSnapshot:true} to see previous page,false if continuing workflow.diffOptions:{enabled:true} shows only what changed from forward page.USE batch_execute for back→interact sequences.",
|
|
53
|
+
inputSchema: z.object({
|
|
54
|
+
expectation: expectationSchema
|
|
55
|
+
}),
|
|
56
|
+
type: "readOnly"
|
|
57
|
+
},
|
|
58
|
+
handle: async (tab, _params, response) => {
|
|
59
|
+
await tab.page.goBack();
|
|
60
|
+
response.addCode(generateBackCode());
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
var goForward = defineTabTool({
|
|
64
|
+
capability: "core",
|
|
65
|
+
schema: {
|
|
66
|
+
name: "browser_navigate_forward",
|
|
67
|
+
title: "Go forward",
|
|
68
|
+
description: "Go forward to next page.expectation:{includeSnapshot:true} to see next page,false if continuing workflow.diffOptions:{enabled:true} shows only what changed from previous page.USE batch_execute for forward→interact sequences.",
|
|
69
|
+
inputSchema: z.object({
|
|
70
|
+
expectation: expectationSchema
|
|
71
|
+
}),
|
|
72
|
+
type: "readOnly"
|
|
73
|
+
},
|
|
74
|
+
handle: async (tab, _params, response) => {
|
|
75
|
+
await tab.page.goForward();
|
|
76
|
+
response.addCode(generateForwardCode());
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
var navigate_default = [navigate, goBack, goForward];
|
|
80
|
+
export {
|
|
81
|
+
navigate_default as default
|
|
82
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
|
+
|
|
20
|
+
// src/tools/network.ts
|
|
21
|
+
import { z } from "zod";
|
|
22
|
+
import { defineTabTool } from "./tool.js";
|
|
23
|
+
var requests = defineTabTool({
|
|
24
|
+
capability: "core",
|
|
25
|
+
schema: {
|
|
26
|
+
name: "browser_network_requests",
|
|
27
|
+
title: "List network requests",
|
|
28
|
+
description: "Returns all network requests since loading the page",
|
|
29
|
+
inputSchema: z.object({}),
|
|
30
|
+
type: "readOnly"
|
|
31
|
+
},
|
|
32
|
+
handle: async (tab, _params, response) => {
|
|
33
|
+
const requestList = await Promise.resolve(tab.requests());
|
|
34
|
+
for (const [req, res] of requestList.entries()) {
|
|
35
|
+
response.addResult(renderRequest(req, res));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
function renderRequest(request, response) {
|
|
40
|
+
const result = [];
|
|
41
|
+
result.push(`[${request.method().toUpperCase()}] ${request.url()}`);
|
|
42
|
+
if (response) {
|
|
43
|
+
result.push(`=> [${response.status()}] ${response.statusText()}`);
|
|
44
|
+
}
|
|
45
|
+
return result.join(" ");
|
|
46
|
+
}
|
|
47
|
+
var network_default = [requests];
|
|
48
|
+
export {
|
|
49
|
+
network_default as default
|
|
50
|
+
};
|
package/lib/tools/pdf.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
|
+
|
|
20
|
+
// src/tools/pdf.ts
|
|
21
|
+
import { z } from "zod";
|
|
22
|
+
import { formatObject } from "../javascript.js";
|
|
23
|
+
import { defineTabTool } from "./tool.js";
|
|
24
|
+
var pdfSchema = z.object({
|
|
25
|
+
filename: z.string().optional().describe("File name to save the pdf to. Defaults to `page-{timestamp}.pdf` if not specified.")
|
|
26
|
+
});
|
|
27
|
+
var pdf = defineTabTool({
|
|
28
|
+
capability: "pdf",
|
|
29
|
+
schema: {
|
|
30
|
+
name: "browser_pdf_save",
|
|
31
|
+
title: "Save as PDF",
|
|
32
|
+
description: "Save page as PDF",
|
|
33
|
+
inputSchema: pdfSchema,
|
|
34
|
+
type: "readOnly"
|
|
35
|
+
},
|
|
36
|
+
handle: async (tab, params, response) => {
|
|
37
|
+
const fileName = await tab.context.outputFile(params.filename ?? `page-${new Date().toISOString()}.pdf`);
|
|
38
|
+
response.addCode(`await page.pdf(${formatObject({ path: fileName })});`);
|
|
39
|
+
response.addResult(`Saved page as ${fileName}`);
|
|
40
|
+
await tab.page.pdf({ path: fileName });
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
var pdf_default = [pdf];
|
|
44
|
+
export {
|
|
45
|
+
pdf_default as default
|
|
46
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
|
+
|
|
20
|
+
// src/tools/screenshot.ts
|
|
21
|
+
import { z } from "zod";
|
|
22
|
+
import { formatObject } from "../javascript.js";
|
|
23
|
+
import { expectationSchema } from "../schemas/expectation.js";
|
|
24
|
+
import { defineTabTool } from "./tool.js";
|
|
25
|
+
import { generateLocator } from "./utils.js";
|
|
26
|
+
var screenshotSchema = z.object({
|
|
27
|
+
type: z.enum(["png", "jpeg"]).default("png").describe("Image format for the screenshot. Default is png."),
|
|
28
|
+
filename: z.string().optional().describe("File name to save the screenshot to. Defaults to `page-{timestamp}.{png|jpeg}` if not specified."),
|
|
29
|
+
element: 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."),
|
|
30
|
+
ref: z.string().optional().describe("Exact target element reference from the page snapshot. If not provided, the screenshot will be taken of viewport. If ref is provided, element must be provided too."),
|
|
31
|
+
fullPage: z.boolean().optional().describe("When true, takes a screenshot of the full scrollable page, instead of the currently visible viewport. Cannot be used with element screenshots."),
|
|
32
|
+
expectation: expectationSchema
|
|
33
|
+
}).refine((data) => {
|
|
34
|
+
return !!data.element === !!data.ref;
|
|
35
|
+
}, {
|
|
36
|
+
message: "Both element and ref must be provided or neither.",
|
|
37
|
+
path: ["ref", "element"]
|
|
38
|
+
}).refine((data) => {
|
|
39
|
+
return !(data.fullPage && (data.element || data.ref));
|
|
40
|
+
}, {
|
|
41
|
+
message: "fullPage cannot be used with element screenshots.",
|
|
42
|
+
path: ["fullPage"]
|
|
43
|
+
});
|
|
44
|
+
async function prepareFileName(context, filename, fileType) {
|
|
45
|
+
const defaultName = `page-${new Date().toISOString()}.${fileType}`;
|
|
46
|
+
return await context.outputFile(filename ?? defaultName);
|
|
47
|
+
}
|
|
48
|
+
function createScreenshotOptions(fileType, fileName, fullPage) {
|
|
49
|
+
return {
|
|
50
|
+
type: fileType,
|
|
51
|
+
quality: fileType === "png" ? undefined : 90,
|
|
52
|
+
scale: "css",
|
|
53
|
+
path: fileName,
|
|
54
|
+
...fullPage !== undefined && { fullPage }
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function isElementScreenshotRequest(params) {
|
|
58
|
+
return !!(params.element && params.ref);
|
|
59
|
+
}
|
|
60
|
+
function getScreenshotTarget(params, isElementScreenshot) {
|
|
61
|
+
if (isElementScreenshot && params.element) {
|
|
62
|
+
return params.element;
|
|
63
|
+
}
|
|
64
|
+
return params.fullPage ? "full page" : "viewport";
|
|
65
|
+
}
|
|
66
|
+
async function getScreenshotLocator(tab, params, isElementScreenshot) {
|
|
67
|
+
if (!(isElementScreenshot && params.element && params.ref)) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
return await tab.refLocator({ element: params.element, ref: params.ref });
|
|
71
|
+
}
|
|
72
|
+
async function addScreenshotCode(response, locator, options) {
|
|
73
|
+
if (locator) {
|
|
74
|
+
response.addCode(`await page.${await generateLocator(locator)}.screenshot(${formatObject(options)});`);
|
|
75
|
+
} else {
|
|
76
|
+
response.addCode(`await page.screenshot(${formatObject(options)});`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function takeScreenshot(tab, locator, options) {
|
|
80
|
+
return locator ? await locator.screenshot(options) : await tab.page.screenshot(options);
|
|
81
|
+
}
|
|
82
|
+
var screenshot = defineTabTool({
|
|
83
|
+
capability: "core",
|
|
84
|
+
schema: {
|
|
85
|
+
name: "browser_take_screenshot",
|
|
86
|
+
title: "Take a screenshot",
|
|
87
|
+
description: `Take a screenshot of current page.Returns image data.expectation:{includeSnapshot:false} to avoid redundant accessibility tree(screenshot≠snapshot).imageOptions:{quality:50,format:"jpeg"} for 70% size reduction.fullPage:true for entire page,element+ref for specific element.USE CASES:visual verification,documentation,error capture.`,
|
|
88
|
+
inputSchema: screenshotSchema,
|
|
89
|
+
type: "readOnly"
|
|
90
|
+
},
|
|
91
|
+
handle: async (tab, params, response) => {
|
|
92
|
+
const fileType = params.type ?? "png";
|
|
93
|
+
const fileName = await prepareFileName(tab.context, params.filename, fileType);
|
|
94
|
+
const options = createScreenshotOptions(fileType, fileName, params.fullPage);
|
|
95
|
+
const isElementScreenshot = isElementScreenshotRequest(params);
|
|
96
|
+
const screenshotTarget = getScreenshotTarget(params, isElementScreenshot);
|
|
97
|
+
response.addCode(`// Screenshot ${screenshotTarget} and save it as ${fileName}`);
|
|
98
|
+
const locator = await getScreenshotLocator(tab, params, isElementScreenshot);
|
|
99
|
+
await addScreenshotCode(response, locator, options);
|
|
100
|
+
const buffer = await takeScreenshot(tab, locator, options);
|
|
101
|
+
response.addResult(`Took the ${screenshotTarget} screenshot and saved it as ${fileName}`);
|
|
102
|
+
if (!params.fullPage) {
|
|
103
|
+
response.addImage({
|
|
104
|
+
contentType: fileType === "png" ? "image/png" : "image/jpeg",
|
|
105
|
+
data: buffer
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
var screenshot_default = [screenshot];
|
|
111
|
+
export {
|
|
112
|
+
screenshot_default as default
|
|
113
|
+
};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
|
+
|
|
20
|
+
// src/tools/snapshot.ts
|
|
21
|
+
import { z } from "zod";
|
|
22
|
+
import { formatObject } from "../javascript.js";
|
|
23
|
+
import { expectationSchema } from "../schemas/expectation.js";
|
|
24
|
+
import { defineTabTool, defineTool } from "./tool.js";
|
|
25
|
+
import { generateLocator } from "./utils.js";
|
|
26
|
+
var snapshot = defineTool({
|
|
27
|
+
capability: "core",
|
|
28
|
+
schema: {
|
|
29
|
+
name: "browser_snapshot",
|
|
30
|
+
title: "Page snapshot",
|
|
31
|
+
description: `Capture accessibility snapshot of current page.AVOID calling directly - use expectation:{includeSnapshot:true} on other tools instead.USE CASES:Initial page inspection,debugging when other tools didn't capture needed info.snapshotOptions:{selector:"#content"} to focus on specific area.`,
|
|
32
|
+
inputSchema: z.object({
|
|
33
|
+
expectation: expectationSchema
|
|
34
|
+
}),
|
|
35
|
+
type: "readOnly"
|
|
36
|
+
},
|
|
37
|
+
handle: async (context, params, response) => {
|
|
38
|
+
await context.ensureTab();
|
|
39
|
+
response.setIncludeSnapshot();
|
|
40
|
+
if (params.expectation?.snapshotOptions) {
|
|
41
|
+
const tab = context.currentTabOrDie();
|
|
42
|
+
const options = params.expectation.snapshotOptions;
|
|
43
|
+
const tabSnapshot = await tab.capturePartialSnapshot(options.selector, options.maxLength);
|
|
44
|
+
response.setTabSnapshot(tabSnapshot);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
var elementSchema = z.object({
|
|
49
|
+
element: z.string().describe("Human-readable element description used to obtain permission to interact with the element"),
|
|
50
|
+
ref: z.string().describe("Exact target element reference from the page snapshot")
|
|
51
|
+
});
|
|
52
|
+
var clickSchema = elementSchema.extend({
|
|
53
|
+
doubleClick: z.boolean().optional().describe("Whether to perform a double click instead of a single click"),
|
|
54
|
+
button: z.enum(["left", "right", "middle"]).optional().describe("Button to click, defaults to left"),
|
|
55
|
+
expectation: expectationSchema
|
|
56
|
+
});
|
|
57
|
+
var click = defineTabTool({
|
|
58
|
+
capability: "core",
|
|
59
|
+
schema: {
|
|
60
|
+
name: "browser_click",
|
|
61
|
+
title: "Click",
|
|
62
|
+
description: `Perform click on web page.USE batch_execute for multi-click workflows.expectation:{includeSnapshot:false} when next action follows immediately,true to verify result.diffOptions:{enabled:true,format:"minimal"} shows only changes(saves 80% tokens).snapshotOptions:{selector:".result"} to focus on result area.doubleClick:true for double-click,button:"right" for context menu.`,
|
|
63
|
+
inputSchema: clickSchema,
|
|
64
|
+
type: "destructive"
|
|
65
|
+
},
|
|
66
|
+
handle: async (tab, params, response) => {
|
|
67
|
+
const locator = await tab.refLocator(params);
|
|
68
|
+
const button = params.button;
|
|
69
|
+
const buttonAttr = button ? `{ button: '${button}' }` : "";
|
|
70
|
+
if (params.doubleClick) {
|
|
71
|
+
response.addCode(`await page.${await generateLocator(locator)}.dblclick(${buttonAttr});`);
|
|
72
|
+
} else {
|
|
73
|
+
response.addCode(`await page.${await generateLocator(locator)}.click(${buttonAttr});`);
|
|
74
|
+
}
|
|
75
|
+
await tab.waitForCompletion(async () => {
|
|
76
|
+
if (params.doubleClick) {
|
|
77
|
+
await locator.dblclick({ button });
|
|
78
|
+
} else {
|
|
79
|
+
await locator.click({ button });
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
if (params.expectation?.includeSnapshot) {
|
|
83
|
+
const newSnapshot = await tab.captureSnapshot();
|
|
84
|
+
response.setTabSnapshot(newSnapshot);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
var drag = defineTabTool({
|
|
89
|
+
capability: "core",
|
|
90
|
+
schema: {
|
|
91
|
+
name: "browser_drag",
|
|
92
|
+
title: "Drag mouse",
|
|
93
|
+
description: `Perform drag and drop between two elements.expectation:{includeSnapshot:true,snapshotOptions:{selector:".drop-zone"}} to verify drop result.diffOptions:{enabled:true} shows only what moved.CONSIDER batch_execute if part of larger workflow.`,
|
|
94
|
+
inputSchema: z.object({
|
|
95
|
+
startElement: z.string().describe("Human-readable source element description used to obtain the permission to interact with the element"),
|
|
96
|
+
startRef: z.string().describe("Exact source element reference from the page snapshot"),
|
|
97
|
+
endElement: z.string().describe("Human-readable target element description used to obtain the permission to interact with the element"),
|
|
98
|
+
endRef: z.string().describe("Exact target element reference from the page snapshot"),
|
|
99
|
+
expectation: expectationSchema
|
|
100
|
+
}),
|
|
101
|
+
type: "destructive"
|
|
102
|
+
},
|
|
103
|
+
handle: async (tab, params, response) => {
|
|
104
|
+
const [startLocator, endLocator] = await tab.refLocators([
|
|
105
|
+
{ ref: params.startRef, element: params.startElement },
|
|
106
|
+
{ ref: params.endRef, element: params.endElement }
|
|
107
|
+
]);
|
|
108
|
+
await tab.waitForCompletion(async () => {
|
|
109
|
+
await startLocator.dragTo(endLocator);
|
|
110
|
+
});
|
|
111
|
+
response.addCode(`await page.${await generateLocator(startLocator)}.dragTo(page.${await generateLocator(endLocator)});`);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
var hover = defineTabTool({
|
|
115
|
+
capability: "core",
|
|
116
|
+
schema: {
|
|
117
|
+
name: "browser_hover",
|
|
118
|
+
title: "Hover mouse",
|
|
119
|
+
description: `Hover over element on page.expectation:{includeSnapshot:true} to capture tooltips/dropdown menus,false for simple hover.snapshotOptions:{selector:".tooltip"} to focus on tooltip area.Often followed by click - use batch_execute for hover→click sequences.`,
|
|
120
|
+
inputSchema: elementSchema.extend({
|
|
121
|
+
expectation: expectationSchema
|
|
122
|
+
}),
|
|
123
|
+
type: "readOnly"
|
|
124
|
+
},
|
|
125
|
+
handle: async (tab, params, response) => {
|
|
126
|
+
const locator = await tab.refLocator(params);
|
|
127
|
+
response.addCode(`await page.${await generateLocator(locator)}.hover();`);
|
|
128
|
+
await tab.waitForCompletion(async () => {
|
|
129
|
+
await locator.hover();
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
var selectOptionSchema = elementSchema.extend({
|
|
134
|
+
values: z.array(z.string()).describe("Array of values to select in the dropdown. This can be a single value or multiple values."),
|
|
135
|
+
expectation: expectationSchema
|
|
136
|
+
});
|
|
137
|
+
var selectOption = defineTabTool({
|
|
138
|
+
capability: "core",
|
|
139
|
+
schema: {
|
|
140
|
+
name: "browser_select_option",
|
|
141
|
+
title: "Select option",
|
|
142
|
+
description: `Select option in dropdown.values:["option1","option2"] for multi-select.expectation:{includeSnapshot:false} when part of form filling(use batch),true to verify selection.snapshotOptions:{selector:"form"} for form context.USE batch_execute for form workflows with multiple selects.`,
|
|
143
|
+
inputSchema: selectOptionSchema,
|
|
144
|
+
type: "destructive"
|
|
145
|
+
},
|
|
146
|
+
handle: async (tab, params, response) => {
|
|
147
|
+
const locator = await tab.refLocator(params);
|
|
148
|
+
response.addCode(`await page.${await generateLocator(locator)}.selectOption(${formatObject(params.values)});`);
|
|
149
|
+
await tab.waitForCompletion(async () => {
|
|
150
|
+
await locator.selectOption(params.values);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
var snapshot_default = [snapshot, click, drag, hover, selectOption];
|
|
155
|
+
export {
|
|
156
|
+
elementSchema,
|
|
157
|
+
snapshot_default as default
|
|
158
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
|
+
|
|
20
|
+
// src/tools/tabs.ts
|
|
21
|
+
import { z } from "zod";
|
|
22
|
+
import { expectationSchema } from "../schemas/expectation.js";
|
|
23
|
+
import { defineTool } from "./tool.js";
|
|
24
|
+
var listTabs = defineTool({
|
|
25
|
+
capability: "core-tabs",
|
|
26
|
+
schema: {
|
|
27
|
+
name: "browser_tab_list",
|
|
28
|
+
title: "List tabs",
|
|
29
|
+
description: "List browser tabs.Always returns tab list with titles and URLs.expectation:{includeSnapshot:false} for just tab info,true to also see current tab content.USE before tab_select to find right tab.",
|
|
30
|
+
inputSchema: z.object({
|
|
31
|
+
expectation: expectationSchema
|
|
32
|
+
}),
|
|
33
|
+
type: "readOnly"
|
|
34
|
+
},
|
|
35
|
+
handle: async (context, _params, response) => {
|
|
36
|
+
await context.ensureTab();
|
|
37
|
+
response.setIncludeTabs();
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
var selectTab = defineTool({
|
|
41
|
+
capability: "core-tabs",
|
|
42
|
+
schema: {
|
|
43
|
+
name: "browser_tab_select",
|
|
44
|
+
title: "Select a tab",
|
|
45
|
+
description: `Select a tab by index.expectation:{includeSnapshot:true} to see selected tab content,false if you know what's there.USE batch_execute for tab_select→interact workflows.`,
|
|
46
|
+
inputSchema: z.object({
|
|
47
|
+
index: z.number().describe("The index of the tab to select"),
|
|
48
|
+
expectation: expectationSchema
|
|
49
|
+
}),
|
|
50
|
+
type: "readOnly"
|
|
51
|
+
},
|
|
52
|
+
handle: async (context, params, response) => {
|
|
53
|
+
await context.selectTab(params.index);
|
|
54
|
+
response.setIncludeSnapshot();
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
var newTab = defineTool({
|
|
58
|
+
capability: "core-tabs",
|
|
59
|
+
schema: {
|
|
60
|
+
name: "browser_tab_new",
|
|
61
|
+
title: "Open a new tab",
|
|
62
|
+
description: `Open a new tab.url:"https://example.com" to navigate immediately,omit for blank tab.expectation:{includeSnapshot:true} to see new tab,false if opening for later use.CONSIDER batch_execute for new_tab→navigate→interact.`,
|
|
63
|
+
inputSchema: z.object({
|
|
64
|
+
url: z.string().optional().describe("The URL to navigate to in the new tab. If not provided, the new tab will be blank."),
|
|
65
|
+
expectation: expectationSchema
|
|
66
|
+
}),
|
|
67
|
+
type: "readOnly"
|
|
68
|
+
},
|
|
69
|
+
handle: async (context, params, response) => {
|
|
70
|
+
const tab = await context.newTab();
|
|
71
|
+
if (params.url) {
|
|
72
|
+
await tab.navigate(params.url);
|
|
73
|
+
}
|
|
74
|
+
response.setIncludeSnapshot();
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
var closeTab = defineTool({
|
|
78
|
+
capability: "core-tabs",
|
|
79
|
+
schema: {
|
|
80
|
+
name: "browser_tab_close",
|
|
81
|
+
title: "Close a tab",
|
|
82
|
+
description: "Close a tab.index:N to close specific tab,omit to close current.expectation:{includeSnapshot:false} usually sufficient,true to verify remaining tabs.USE batch_execute for multi-tab cleanup.",
|
|
83
|
+
inputSchema: z.object({
|
|
84
|
+
index: z.number().optional().describe("The index of the tab to close. Closes current tab if not provided."),
|
|
85
|
+
expectation: expectationSchema
|
|
86
|
+
}),
|
|
87
|
+
type: "destructive"
|
|
88
|
+
},
|
|
89
|
+
handle: async (context, params, response) => {
|
|
90
|
+
await context.closeTab(params.index);
|
|
91
|
+
response.setIncludeSnapshot();
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
var tabs_default = [listTabs, newTab, selectTab, closeTab];
|
|
95
|
+
export {
|
|
96
|
+
tabs_default as default
|
|
97
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
|
+
|
|
20
|
+
// src/tools/tool.ts
|
|
21
|
+
function defineTool(tool) {
|
|
22
|
+
return tool;
|
|
23
|
+
}
|
|
24
|
+
function defineTabTool(tool) {
|
|
25
|
+
return {
|
|
26
|
+
...tool,
|
|
27
|
+
handle: async (context, params, response) => {
|
|
28
|
+
const tab = context.currentTabOrDie();
|
|
29
|
+
const modalStates = tab.modalStates().map((state) => state.type);
|
|
30
|
+
if (tool.clearsModalState && !modalStates.includes(tool.clearsModalState)) {
|
|
31
|
+
response.addError(`Error: The tool "${tool.schema.name}" can only be used when there is related modal state present.
|
|
32
|
+
` + tab.modalStatesMarkdown().join(`
|
|
33
|
+
`));
|
|
34
|
+
} else if (!tool.clearsModalState && modalStates.length) {
|
|
35
|
+
response.addError(`Error: Tool "${tool.schema.name}" does not handle the modal state.
|
|
36
|
+
` + tab.modalStatesMarkdown().join(`
|
|
37
|
+
`));
|
|
38
|
+
} else {
|
|
39
|
+
return await tool.handle(tab, params, response);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export {
|
|
45
|
+
defineTool,
|
|
46
|
+
defineTabTool
|
|
47
|
+
};
|