@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.
Files changed (107) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +1047 -0
  3. package/cli.js +18 -0
  4. package/config.d.ts +124 -0
  5. package/index.d.ts +25 -0
  6. package/index.js +18 -0
  7. package/lib/actions.d.js +0 -0
  8. package/lib/batch/batch-executor.js +137 -0
  9. package/lib/browser-context-factory.js +252 -0
  10. package/lib/browser-server-backend.js +139 -0
  11. package/lib/config/constants.js +80 -0
  12. package/lib/config.js +405 -0
  13. package/lib/context.js +274 -0
  14. package/lib/diagnostics/common/diagnostic-base.js +63 -0
  15. package/lib/diagnostics/common/error-enrichment-utils.js +212 -0
  16. package/lib/diagnostics/common/index.js +56 -0
  17. package/lib/diagnostics/common/initialization-manager.js +210 -0
  18. package/lib/diagnostics/common/performance-tracker.js +132 -0
  19. package/lib/diagnostics/diagnostic-error.js +140 -0
  20. package/lib/diagnostics/diagnostic-level.js +123 -0
  21. package/lib/diagnostics/diagnostic-thresholds.js +347 -0
  22. package/lib/diagnostics/element-discovery.js +441 -0
  23. package/lib/diagnostics/enhanced-error-handler.js +376 -0
  24. package/lib/diagnostics/error-enrichment.js +157 -0
  25. package/lib/diagnostics/frame-reference-manager.js +179 -0
  26. package/lib/diagnostics/page-analyzer.js +639 -0
  27. package/lib/diagnostics/parallel-page-analyzer.js +129 -0
  28. package/lib/diagnostics/resource-manager.js +134 -0
  29. package/lib/diagnostics/smart-config.js +482 -0
  30. package/lib/diagnostics/smart-handle.js +118 -0
  31. package/lib/diagnostics/unified-system.js +717 -0
  32. package/lib/extension/cdp-relay.js +486 -0
  33. package/lib/extension/extension-context-factory.js +74 -0
  34. package/lib/extension/main.js +41 -0
  35. package/lib/file-utils.js +42 -0
  36. package/lib/generate-keys.js +75 -0
  37. package/lib/http-server.js +50 -0
  38. package/lib/in-process-client.js +64 -0
  39. package/lib/index.js +48 -0
  40. package/lib/javascript.js +90 -0
  41. package/lib/log.js +33 -0
  42. package/lib/loop/loop-claude.js +247 -0
  43. package/lib/loop/loop-open-ai.js +222 -0
  44. package/lib/loop/loop.js +174 -0
  45. package/lib/loop/main.js +46 -0
  46. package/lib/loopTools/context.js +76 -0
  47. package/lib/loopTools/main.js +65 -0
  48. package/lib/loopTools/perform.js +40 -0
  49. package/lib/loopTools/snapshot.js +37 -0
  50. package/lib/loopTools/tool.js +26 -0
  51. package/lib/manual-promise.js +125 -0
  52. package/lib/mcp/in-process-transport.js +91 -0
  53. package/lib/mcp/proxy-backend.js +127 -0
  54. package/lib/mcp/server.js +123 -0
  55. package/lib/mcp/transport.js +159 -0
  56. package/lib/package.js +28 -0
  57. package/lib/program.js +82 -0
  58. package/lib/response.js +493 -0
  59. package/lib/schemas/expectation.js +152 -0
  60. package/lib/session-log.js +210 -0
  61. package/lib/tab.js +417 -0
  62. package/lib/tools/base-tool-handler.js +141 -0
  63. package/lib/tools/batch-execute.js +150 -0
  64. package/lib/tools/common.js +65 -0
  65. package/lib/tools/console.js +60 -0
  66. package/lib/tools/diagnose/diagnose-analysis-runner.js +101 -0
  67. package/lib/tools/diagnose/diagnose-config-handler.js +130 -0
  68. package/lib/tools/diagnose/diagnose-report-builder.js +394 -0
  69. package/lib/tools/diagnose.js +147 -0
  70. package/lib/tools/dialogs.js +57 -0
  71. package/lib/tools/evaluate.js +67 -0
  72. package/lib/tools/files.js +53 -0
  73. package/lib/tools/find-elements.js +307 -0
  74. package/lib/tools/install.js +60 -0
  75. package/lib/tools/keyboard.js +93 -0
  76. package/lib/tools/mouse.js +110 -0
  77. package/lib/tools/navigate.js +82 -0
  78. package/lib/tools/network.js +50 -0
  79. package/lib/tools/pdf.js +46 -0
  80. package/lib/tools/screenshot.js +113 -0
  81. package/lib/tools/snapshot.js +158 -0
  82. package/lib/tools/tabs.js +97 -0
  83. package/lib/tools/tool.js +47 -0
  84. package/lib/tools/utils.js +131 -0
  85. package/lib/tools/wait.js +64 -0
  86. package/lib/tools.js +65 -0
  87. package/lib/types/batch.js +47 -0
  88. package/lib/types/diff.js +0 -0
  89. package/lib/types/performance.js +0 -0
  90. package/lib/types/threshold-base.js +0 -0
  91. package/lib/utils/array-utils.js +44 -0
  92. package/lib/utils/code-deduplication-utils.js +141 -0
  93. package/lib/utils/common-formatters.js +252 -0
  94. package/lib/utils/console-filter.js +64 -0
  95. package/lib/utils/diagnostic-report-utils.js +178 -0
  96. package/lib/utils/diff-formatter.js +126 -0
  97. package/lib/utils/disposable-manager.js +135 -0
  98. package/lib/utils/error-handler-middleware.js +77 -0
  99. package/lib/utils/image-processor.js +137 -0
  100. package/lib/utils/index.js +92 -0
  101. package/lib/utils/report-builder.js +189 -0
  102. package/lib/utils/request-logger.js +82 -0
  103. package/lib/utils/response-diff-detector.js +150 -0
  104. package/lib/utils/section-builder.js +62 -0
  105. package/lib/utils/tool-patterns.js +153 -0
  106. package/lib/utils.js +46 -0
  107. package/package.json +77 -0
@@ -0,0 +1,53 @@
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/files.ts
21
+ import { z } from "zod";
22
+ import { expectationSchema } from "../schemas/expectation.js";
23
+ import { defineTabTool } from "./tool.js";
24
+ var uploadFile = defineTabTool({
25
+ capability: "core",
26
+ schema: {
27
+ name: "browser_file_upload",
28
+ title: "Upload files",
29
+ description: `Upload one or multiple files to file input.paths:["/path/file1.jpg","/path/file2.pdf"] for multiple files.expectation:{includeSnapshot:true,snapshotOptions:{selector:"form"}} to verify upload.Must be triggered after file input interaction.USE batch_execute for click→upload workflows.`,
30
+ inputSchema: z.object({
31
+ paths: z.array(z.string()).describe("The absolute paths to the files to upload. Can be a single file or multiple files."),
32
+ expectation: expectationSchema
33
+ }),
34
+ type: "destructive"
35
+ },
36
+ handle: async (tab, params, response) => {
37
+ response.setIncludeSnapshot();
38
+ const modalState = tab.modalStates().find((state) => state.type === "fileChooser");
39
+ if (!modalState) {
40
+ throw new Error("No file chooser visible");
41
+ }
42
+ response.addCode(`await fileChooser.setFiles(${JSON.stringify(params.paths)})`);
43
+ tab.clearModalState(modalState);
44
+ await tab.waitForCompletion(async () => {
45
+ await modalState.fileChooser.setFiles(params.paths);
46
+ });
47
+ },
48
+ clearsModalState: "fileChooser"
49
+ });
50
+ var files_default = [uploadFile];
51
+ export {
52
+ files_default as default
53
+ };
@@ -0,0 +1,307 @@
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/find-elements.ts
21
+ import { z } from "zod";
22
+ import { ElementDiscovery } from "../diagnostics/element-discovery.js";
23
+ import { PageAnalyzer } from "../diagnostics/page-analyzer.js";
24
+ import { ArrayBuilder } from "../utils/code-deduplication-utils.js";
25
+ import { UnifiedDiagnosticSystem } from "../diagnostics/unified-system.js";
26
+ import { expectationSchema } from "../schemas/expectation.js";
27
+ import { getErrorMessage } from "../utils/common-formatters.js";
28
+ import {
29
+ DiagnosticReportBuilder,
30
+ formatConfidencePercentage
31
+ } from "../utils/report-builder.js";
32
+ import { defineTabTool } from "./tool.js";
33
+ var findElementsSchema = z.object({
34
+ searchCriteria: z.object({
35
+ text: z.string().optional().describe("Text content to search for"),
36
+ role: z.string().optional().describe("ARIA role to search for"),
37
+ tagName: z.string().optional().describe("HTML tag name to search for"),
38
+ attributes: z.record(z.string()).optional().describe("Attributes to match")
39
+ }).describe("Search criteria for finding elements"),
40
+ maxResults: z.number().optional().default(10).describe("Maximum number of results to return"),
41
+ includeDiagnosticInfo: z.boolean().optional().default(false).describe("Include diagnostic information about the page"),
42
+ useUnifiedSystem: z.boolean().optional().default(true).describe("Use unified diagnostic system for enhanced error handling"),
43
+ enableEnhancedDiscovery: z.boolean().optional().default(true).describe("Enable enhanced element discovery with contextual suggestions"),
44
+ performanceThreshold: z.number().optional().default(500).describe("Performance threshold in milliseconds for element discovery"),
45
+ expectation: expectationSchema.optional()
46
+ }).describe("Find elements using multiple search criteria");
47
+ var browserFindElements = defineTabTool({
48
+ capability: "core",
49
+ schema: {
50
+ name: "browser_find_elements",
51
+ title: "Find elements",
52
+ type: "readOnly",
53
+ description: "Find elements on the page using multiple search criteria such as text, role, tag name, or attributes. Returns matching elements sorted by confidence.",
54
+ inputSchema: findElementsSchema
55
+ },
56
+ handle: async (tab, params, response) => {
57
+ const context = new FindElementsContext(params);
58
+ contextInstance = context;
59
+ try {
60
+ const alternatives = await findElements(tab, context);
61
+ if (alternatives.length === 0) {
62
+ response.addResult("No elements found matching the specified criteria.");
63
+ return;
64
+ }
65
+ const resultsText = formatElementResults(alternatives);
66
+ await addDiagnosticInfoIfRequested(tab, context, resultsText);
67
+ addPerformanceInfoIfAvailable(context, resultsText);
68
+ response.addResult(resultsText.join(`
69
+ `));
70
+ } catch (error) {
71
+ response.addError(`Error finding elements: ${getErrorMessage(error)}`);
72
+ } finally {
73
+ await cleanupResources();
74
+ }
75
+ }
76
+ });
77
+
78
+ class FindElementsContext {
79
+ unifiedSystem = null;
80
+ elementDiscovery = null;
81
+ operationResult;
82
+ params;
83
+ constructor(params) {
84
+ this.params = params;
85
+ }
86
+ get useUnifiedSystem() {
87
+ return this.params.useUnifiedSystem ?? true;
88
+ }
89
+ get enableEnhancedDiscovery() {
90
+ return this.params.enableEnhancedDiscovery ?? true;
91
+ }
92
+ get performanceThreshold() {
93
+ return this.params.performanceThreshold ?? 500;
94
+ }
95
+ get includeDiagnosticInfo() {
96
+ return this.params.includeDiagnosticInfo ?? false;
97
+ }
98
+ get searchCriteria() {
99
+ return this.params.searchCriteria;
100
+ }
101
+ get maxResults() {
102
+ return this.params.maxResults;
103
+ }
104
+ }
105
+ async function findElements(tab, context) {
106
+ if (context.useUnifiedSystem) {
107
+ return await findElementsWithUnifiedSystem(tab, context);
108
+ }
109
+ return await findElementsWithLegacySystem(tab, context);
110
+ }
111
+ async function findElementsWithUnifiedSystem(tab, context) {
112
+ const configOverrides = buildUnifiedSystemConfig(context);
113
+ context.unifiedSystem = UnifiedDiagnosticSystem.getInstance(tab.page, configOverrides);
114
+ const operationResult = await context.unifiedSystem.findAlternativeElements(context.searchCriteria);
115
+ context.operationResult = operationResult;
116
+ if (!operationResult.success) {
117
+ throw new Error(buildErrorMessage(operationResult.error));
118
+ }
119
+ return operationResult.data ?? [];
120
+ }
121
+ async function findElementsWithLegacySystem(tab, context) {
122
+ context.elementDiscovery = new ElementDiscovery(tab.page);
123
+ const legacyResults = await context.elementDiscovery.findAlternativeElements({
124
+ originalSelector: "",
125
+ searchCriteria: context.searchCriteria,
126
+ maxResults: context.maxResults
127
+ });
128
+ const alternatives = legacyResults.map((result) => ({
129
+ ref: result.selector,
130
+ element: result.selector,
131
+ description: `Element with selector ${result.selector}`,
132
+ confidence: result.confidence,
133
+ textContent: "",
134
+ attributes: {},
135
+ selector: result.selector
136
+ }));
137
+ context.operationResult = {
138
+ success: true,
139
+ data: alternatives,
140
+ executionTime: 0
141
+ };
142
+ return alternatives;
143
+ }
144
+ function buildUnifiedSystemConfig(context) {
145
+ return {
146
+ features: {
147
+ enableParallelAnalysis: true,
148
+ enableSmartHandleManagement: true,
149
+ enableAdvancedElementDiscovery: context.enableEnhancedDiscovery,
150
+ enableResourceLeakDetection: true,
151
+ enableRealTimeMonitoring: false
152
+ },
153
+ performance: {
154
+ enableMetricsCollection: true,
155
+ enableResourceMonitoring: true,
156
+ enablePerformanceWarnings: true,
157
+ autoOptimization: true,
158
+ thresholds: {
159
+ executionTime: {
160
+ elementDiscovery: context.performanceThreshold,
161
+ pageAnalysis: 1000,
162
+ resourceMonitoring: 200,
163
+ parallelAnalysis: 2000
164
+ },
165
+ memory: {
166
+ maxMemoryUsage: 100 * 1024 * 1024,
167
+ memoryLeakThreshold: 50 * 1024 * 1024,
168
+ gcTriggerThreshold: 80 * 1024 * 1024
169
+ },
170
+ performance: {
171
+ domElementLimit: 1e4,
172
+ maxDepthLimit: 50,
173
+ largeSubtreeThreshold: 1000
174
+ },
175
+ dom: {
176
+ totalElements: 1e4,
177
+ maxDepth: 50,
178
+ largeSubtrees: 10,
179
+ elementsWarning: 1500,
180
+ elementsDanger: 3000,
181
+ depthWarning: 15,
182
+ depthDanger: 20,
183
+ largeSubtreeThreshold: 500
184
+ },
185
+ interaction: {
186
+ clickableElements: 100,
187
+ formElements: 50,
188
+ clickableHigh: 100
189
+ },
190
+ layout: {
191
+ fixedElements: 10,
192
+ highZIndexElements: 5,
193
+ highZIndexThreshold: 1000,
194
+ excessiveZIndexThreshold: 9999
195
+ }
196
+ }
197
+ }
198
+ };
199
+ }
200
+ function buildErrorMessage(errorInfo) {
201
+ let errorMessage = `Element discovery failed: ${errorInfo?.message ?? "Unknown error"}`;
202
+ if (errorInfo?.suggestions && errorInfo.suggestions.length > 0) {
203
+ errorMessage += `
204
+
205
+ Suggestions:`;
206
+ for (const suggestion of errorInfo.suggestions) {
207
+ errorMessage += `
208
+ - ${suggestion}`;
209
+ }
210
+ }
211
+ return errorMessage;
212
+ }
213
+ function formatElementResults(alternatives) {
214
+ const builder = new DiagnosticReportBuilder;
215
+ builder.addLine(`Found ${alternatives.length} elements matching the criteria:`);
216
+ builder.addEmptyLine();
217
+ for (const [index, alt] of alternatives.entries()) {
218
+ builder.addLine(`${index + 1}. Selector: ${alt.selector}`);
219
+ builder.addLine(` Confidence: ${formatConfidencePercentage(alt.confidence)}`);
220
+ builder.addLine(` Reason: ${alt.reason ?? "No reason provided"}`);
221
+ if (index < alternatives.length - 1) {
222
+ builder.addEmptyLine();
223
+ }
224
+ }
225
+ return builder.getSections();
226
+ }
227
+ async function addDiagnosticInfoIfRequested(tab, context, resultsText) {
228
+ if (!context.includeDiagnosticInfo) {
229
+ return;
230
+ }
231
+ if (context.unifiedSystem) {
232
+ await addUnifiedDiagnosticInfo(context.unifiedSystem, resultsText);
233
+ } else {
234
+ await addLegacyDiagnosticInfo(tab, resultsText);
235
+ }
236
+ }
237
+ async function addUnifiedDiagnosticInfo(unifiedSystem, resultsText) {
238
+ const diagResult = await unifiedSystem.analyzePageStructure();
239
+ const builder = new DiagnosticReportBuilder;
240
+ if (diagResult.success) {
241
+ const diagnosticInfo = diagResult.data;
242
+ builder.addSection("Enhanced Diagnostic Information", (b) => {
243
+ b.addKeyValue("Analysis time", `${diagResult.executionTime ?? 0}ms`);
244
+ addStructuralDiagnosticInfo(diagnosticInfo, b.getSections());
245
+ });
246
+ } else {
247
+ builder.addSection("Diagnostic Information", (b) => {
248
+ b.addListItem(`Error getting diagnostic information: ${diagResult.error?.message ?? "Unknown error"}`);
249
+ });
250
+ }
251
+ resultsText.push("", ...builder.getSections());
252
+ }
253
+ function addStructuralDiagnosticInfo(diagnosticInfo, resultsText) {
254
+ if (diagnosticInfo?.structureAnalysis) {
255
+ addParallelAnalysisInfo(diagnosticInfo.structureAnalysis, resultsText);
256
+ } else {
257
+ addStandardAnalysisInfo(diagnosticInfo, resultsText);
258
+ }
259
+ }
260
+ function addParallelAnalysisInfo(structure, resultsText) {
261
+ const analysisInfo = new ArrayBuilder().add(`- Page has ${structure.iframes?.count ?? 0} iframes detected: ${structure.iframes?.detected}`).add(`- Total visible elements: ${structure.elements?.totalVisible ?? 0}`).add(`- Total interactable elements: ${structure.elements?.totalInteractable ?? 0}`).addIf(!!(structure.modalStates?.blockedBy && structure.modalStates.blockedBy.length > 0), `- Page blocked by: ${structure.modalStates?.blockedBy?.join(", ") ?? ""}`).build();
262
+ resultsText.push(...analysisInfo);
263
+ }
264
+ function addStandardAnalysisInfo(diagnosticInfo, resultsText) {
265
+ const analysisInfo = new ArrayBuilder().add(`- Page has ${diagnosticInfo?.iframes?.count ?? 0} iframes detected: ${diagnosticInfo?.iframes?.detected}`).add(`- Total visible elements: ${diagnosticInfo?.elements?.totalVisible ?? 0}`).add(`- Total interactable elements: ${diagnosticInfo?.elements?.totalInteractable ?? 0}`).addIf(!!(diagnosticInfo?.modalStates?.blockedBy && diagnosticInfo.modalStates.blockedBy.length > 0), `- Page blocked by: ${diagnosticInfo?.modalStates?.blockedBy?.join(", ") ?? ""}`).build();
266
+ resultsText.push(...analysisInfo);
267
+ }
268
+ async function addLegacyDiagnosticInfo(tab, resultsText) {
269
+ const pageAnalyzer = new PageAnalyzer(tab.page);
270
+ try {
271
+ const diagnosticInfo = await pageAnalyzer.analyzePageStructure();
272
+ resultsText.push("", "### Diagnostic Information");
273
+ resultsText.push(`- Page has ${diagnosticInfo.iframes.count} iframes detected: ${diagnosticInfo.iframes.detected}`);
274
+ resultsText.push(`- Total visible elements: ${diagnosticInfo.elements.totalVisible}`);
275
+ resultsText.push(`- Total interactable elements: ${diagnosticInfo.elements.totalInteractable}`);
276
+ if (diagnosticInfo.modalStates.blockedBy.length > 0) {
277
+ resultsText.push(`- Page blocked by: ${diagnosticInfo.modalStates.blockedBy.join(", ")}`);
278
+ }
279
+ } finally {
280
+ await pageAnalyzer.dispose();
281
+ }
282
+ }
283
+ function addPerformanceInfoIfAvailable(context, resultsText) {
284
+ if (!(context.useUnifiedSystem && context.operationResult && context.enableEnhancedDiscovery)) {
285
+ return;
286
+ }
287
+ const builder = new DiagnosticReportBuilder;
288
+ builder.addSection("Enhanced Discovery Information", (b) => {
289
+ b.addKeyValue("Discovery execution time", `${context.operationResult?.executionTime ?? 0}ms`);
290
+ if (context.operationResult?.executionTime && context.operationResult?.executionTime > context.performanceThreshold) {
291
+ b.addListItem(`⚠️ Discovery exceeded performance threshold (${context.performanceThreshold}ms)`);
292
+ } else {
293
+ b.addListItem("✅ Discovery within performance threshold");
294
+ }
295
+ });
296
+ resultsText.push("", ...builder.getSections());
297
+ }
298
+ var contextInstance = null;
299
+ async function cleanupResources() {
300
+ if (contextInstance?.elementDiscovery) {
301
+ await contextInstance.elementDiscovery.dispose();
302
+ }
303
+ contextInstance = null;
304
+ }
305
+ export {
306
+ browserFindElements
307
+ };
@@ -0,0 +1,60 @@
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/install.ts
21
+ import { fork } from "node:child_process";
22
+ import path from "node:path";
23
+ import { fileURLToPath } from "node:url";
24
+ import { z } from "zod";
25
+ import { defineTool } from "./tool.js";
26
+ var install = defineTool({
27
+ capability: "core-install",
28
+ schema: {
29
+ name: "browser_install",
30
+ title: "Install the browser specified in the config",
31
+ description: "Install the browser specified in the config. Call this if you get an error about the browser not being installed.",
32
+ inputSchema: z.object({}),
33
+ type: "destructive"
34
+ },
35
+ handle: async (context, _params, response) => {
36
+ const channel = context.config.browser?.launchOptions?.channel ?? context.config.browser?.browserName ?? "chrome";
37
+ const cliUrl = import.meta.resolve("playwright/package.json");
38
+ const cliPath = path.join(fileURLToPath(cliUrl), "..", "cli.js");
39
+ const child = fork(cliPath, ["install", channel], {
40
+ stdio: "pipe"
41
+ });
42
+ const output = [];
43
+ child.stdout?.on("data", (data) => output.push(data.toString()));
44
+ child.stderr?.on("data", (data) => output.push(data.toString()));
45
+ await new Promise((resolve, reject) => {
46
+ child.on("close", (code) => {
47
+ if (code === 0) {
48
+ resolve();
49
+ } else {
50
+ reject(new Error(`Failed to install browser: ${output.join("")}`));
51
+ }
52
+ });
53
+ });
54
+ response.setIncludeTabs();
55
+ }
56
+ });
57
+ var install_default = [install];
58
+ export {
59
+ install_default as default
60
+ };
@@ -0,0 +1,93 @@
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/keyboard.ts
21
+ import { z } from "zod";
22
+ import { quote } from "../javascript.js";
23
+ import { expectationSchema } from "../schemas/expectation.js";
24
+ import { generateKeyPressCode } from "../utils/common-formatters.js";
25
+ import { baseElementSchema as elementSchema } from "./base-tool-handler.js";
26
+ import { defineTabTool } from "./tool.js";
27
+ import { generateLocator } from "./utils.js";
28
+ var pressKey = defineTabTool({
29
+ capability: "core",
30
+ schema: {
31
+ name: "browser_press_key",
32
+ title: "Press a key",
33
+ description: "Press a key on the keyboard.Common keys:Enter,Escape,ArrowUp/Down/Left/Right,Tab,Backspace.expectation:{includeSnapshot:false} for navigation keys,true for content changes.CONSIDER batch_execute for multiple key presses.",
34
+ inputSchema: z.object({
35
+ key: z.string().describe("Name of the key to press or a character to generate, such as `ArrowLeft` or `a`"),
36
+ expectation: expectationSchema
37
+ }),
38
+ type: "destructive"
39
+ },
40
+ handle: async (tab, params, response) => {
41
+ response.addCode(`// Press ${params.key}`);
42
+ response.addCode(generateKeyPressCode(params.key));
43
+ await tab.waitForCompletion(async () => {
44
+ await tab.page.keyboard.press(params.key);
45
+ });
46
+ if (params.expectation?.includeSnapshot) {
47
+ const newSnapshot = await tab.captureSnapshot();
48
+ response.setTabSnapshot(newSnapshot);
49
+ }
50
+ }
51
+ });
52
+ var typeSchema = elementSchema.extend({
53
+ element: z.string().describe("Human-readable element description used to obtain permission to interact with the element"),
54
+ ref: z.string().describe("Exact target element reference from the page snapshot"),
55
+ text: z.string().describe("Text to type into the element"),
56
+ submit: z.boolean().optional().describe("Whether to submit entered text (press Enter after)"),
57
+ slowly: z.boolean().optional().describe("Whether type one character at a time. Useful for triggering key handlers in the page. By default entire text is filled in at once."),
58
+ expectation: expectationSchema
59
+ });
60
+ var type = defineTabTool({
61
+ capability: "core",
62
+ schema: {
63
+ name: "browser_type",
64
+ title: "Type text",
65
+ description: `Type text into editable element.FOR FORMS:Use batch_execute to fill multiple fields efficiently.slowly:true for auto-complete fields,submit:true to press Enter after.expectation:{includeSnapshot:false} when filling multiple fields(use batch),true for final verification.snapshotOptions:{selector:"form"} to focus on form only.diffOptions:{enabled:true} shows only what changed in form.`,
66
+ inputSchema: typeSchema,
67
+ type: "destructive"
68
+ },
69
+ handle: async (tab, params, response) => {
70
+ const locator = await tab.refLocator(params);
71
+ await tab.waitForCompletion(async () => {
72
+ if (params.slowly) {
73
+ response.addCode(`await page.${await generateLocator(locator)}.pressSequentially(${quote(params.text)});`);
74
+ await locator.pressSequentially(params.text);
75
+ } else {
76
+ response.addCode(`await page.${await generateLocator(locator)}.fill(${quote(params.text)});`);
77
+ await locator.fill(params.text);
78
+ }
79
+ if (params.submit) {
80
+ response.addCode(`await page.${await generateLocator(locator)}.press('Enter');`);
81
+ await locator.press("Enter");
82
+ }
83
+ });
84
+ if (params.expectation?.includeSnapshot) {
85
+ const newSnapshot = await tab.captureSnapshot();
86
+ response.setTabSnapshot(newSnapshot);
87
+ }
88
+ }
89
+ });
90
+ var keyboard_default = [pressKey, type];
91
+ export {
92
+ keyboard_default as default
93
+ };
@@ -0,0 +1,110 @@
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/mouse.ts
21
+ import { z } from "zod";
22
+ import { expectationSchema } from "../schemas/expectation.js";
23
+ import {
24
+ generateMouseClickCode,
25
+ generateMouseDragCode,
26
+ generateMouseMoveCode
27
+ } from "../utils/common-formatters.js";
28
+ import { baseElementSchema } from "./base-tool-handler.js";
29
+ import { defineTabTool } from "./tool.js";
30
+ var elementSchema = baseElementSchema.pick({ element: true }).required({ element: true });
31
+ var mouseMove = defineTabTool({
32
+ capability: "vision",
33
+ schema: {
34
+ name: "browser_mouse_move_xy",
35
+ title: "Move mouse",
36
+ description: "Move mouse to specific coordinates.Requires --caps=vision.x,y:coordinates.expectation:{includeSnapshot:false} for simple move,true to see hover effects.PREFER element-based interactions over coordinates when possible.",
37
+ inputSchema: elementSchema.extend({
38
+ x: z.number().describe("X coordinate"),
39
+ y: z.number().describe("Y coordinate"),
40
+ expectation: expectationSchema
41
+ }),
42
+ type: "readOnly"
43
+ },
44
+ handle: async (tab, params, response) => {
45
+ response.addCode(`// Move mouse to (${params.x}, ${params.y})`);
46
+ response.addCode(generateMouseMoveCode(params.x, params.y));
47
+ await tab.waitForCompletion(async () => {
48
+ await tab.page.mouse.move(params.x, params.y);
49
+ });
50
+ }
51
+ });
52
+ var mouseClick = defineTabTool({
53
+ capability: "vision",
54
+ schema: {
55
+ name: "browser_mouse_click_xy",
56
+ title: "Click",
57
+ description: "Click at specific coordinates.Requires --caps=vision.x,y:click position.expectation:{includeSnapshot:true} to verify result.PREFER browser_click with element ref over coordinates.USE batch_execute for coordinate-based workflows.",
58
+ inputSchema: elementSchema.extend({
59
+ x: z.number().describe("X coordinate"),
60
+ y: z.number().describe("Y coordinate"),
61
+ expectation: expectationSchema
62
+ }),
63
+ type: "destructive"
64
+ },
65
+ handle: async (tab, params, response) => {
66
+ response.setIncludeSnapshot();
67
+ response.addCode(`// Click mouse at coordinates (${params.x}, ${params.y})`);
68
+ response.addCode(generateMouseMoveCode(params.x, params.y));
69
+ for (const code of generateMouseClickCode()) {
70
+ response.addCode(code);
71
+ }
72
+ await tab.waitForCompletion(async () => {
73
+ await tab.page.mouse.move(params.x, params.y);
74
+ await tab.page.mouse.down();
75
+ await tab.page.mouse.up();
76
+ });
77
+ }
78
+ });
79
+ var mouseDrag = defineTabTool({
80
+ capability: "vision",
81
+ schema: {
82
+ name: "browser_mouse_drag_xy",
83
+ title: "Drag mouse",
84
+ description: `Drag from one coordinate to another.Requires --caps=vision.startX,startY→endX,endY.expectation:{includeSnapshot:true,snapshotOptions:{selector:".drop-zone"}} to verify.PREFER browser_drag with element refs over coordinates.`,
85
+ inputSchema: elementSchema.extend({
86
+ startX: z.number().describe("Start X coordinate"),
87
+ startY: z.number().describe("Start Y coordinate"),
88
+ endX: z.number().describe("End X coordinate"),
89
+ endY: z.number().describe("End Y coordinate"),
90
+ expectation: expectationSchema
91
+ }),
92
+ type: "destructive"
93
+ },
94
+ handle: async (tab, params, response) => {
95
+ response.setIncludeSnapshot();
96
+ for (const code of generateMouseDragCode(params.startX, params.startY, params.endX, params.endY)) {
97
+ response.addCode(code);
98
+ }
99
+ await tab.waitForCompletion(async () => {
100
+ await tab.page.mouse.move(params.startX, params.startY);
101
+ await tab.page.mouse.down();
102
+ await tab.page.mouse.move(params.endX, params.endY);
103
+ await tab.page.mouse.up();
104
+ });
105
+ }
106
+ });
107
+ var mouse_default = [mouseMove, mouseClick, mouseDrag];
108
+ export {
109
+ mouse_default as default
110
+ };