@szymonrybczak/playwright-mcp 0.0.2 → 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 (115) hide show
  1. package/index.d.ts +21 -8
  2. package/lib/cjs/_virtual/_commonjsHelpers.js +9 -0
  3. package/lib/cjs/_virtual/browser.js +11 -0
  4. package/lib/cjs/_virtual/browser2.js +7 -0
  5. package/lib/cjs/cloudflare/package.json.js +10 -0
  6. package/lib/cjs/index.js +28 -0
  7. package/lib/cjs/node_modules/debug/src/browser.js +290 -0
  8. package/lib/cjs/node_modules/debug/src/common.js +307 -0
  9. package/lib/cjs/node_modules/ms/index.js +176 -0
  10. package/lib/cjs/package.js +9 -0
  11. package/lib/cjs/src/browserContextFactory.js +240 -0
  12. package/lib/cjs/src/config.js +77 -0
  13. package/lib/cjs/src/connection.js +74 -0
  14. package/lib/cjs/src/context.js +281 -0
  15. package/lib/cjs/src/fileUtils.js +25 -0
  16. package/lib/cjs/src/index.js +15 -0
  17. package/lib/cjs/src/javascript.js +41 -0
  18. package/lib/cjs/src/manualPromise.js +39 -0
  19. package/lib/cjs/src/pageSnapshot.js +35 -0
  20. package/lib/cjs/src/tab.js +91 -0
  21. package/lib/cjs/src/tools/common.js +60 -0
  22. package/lib/cjs/src/tools/console.js +36 -0
  23. package/lib/cjs/src/tools/dialogs.js +44 -0
  24. package/lib/cjs/src/tools/files.js +43 -0
  25. package/lib/cjs/src/tools/install.js +49 -0
  26. package/lib/cjs/src/tools/keyboard.js +38 -0
  27. package/lib/cjs/src/tools/navigate.js +85 -0
  28. package/lib/cjs/src/tools/network.js +43 -0
  29. package/lib/cjs/src/tools/pdf.js +42 -0
  30. package/lib/cjs/src/tools/screenshot.js +69 -0
  31. package/lib/cjs/src/tools/snapshot.js +195 -0
  32. package/lib/cjs/src/tools/tabs.js +110 -0
  33. package/lib/cjs/src/tools/testing.js +52 -0
  34. package/lib/cjs/src/tools/tool.js +9 -0
  35. package/lib/cjs/src/tools/utils.js +75 -0
  36. package/lib/cjs/src/tools/vision.js +181 -0
  37. package/lib/cjs/src/tools/wait.js +51 -0
  38. package/lib/cjs/src/tools.js +54 -0
  39. package/lib/esm/_virtual/_commonjsHelpers.js +5 -0
  40. package/lib/esm/_virtual/browser.js +7 -0
  41. package/lib/esm/_virtual/browser2.js +3 -0
  42. package/lib/esm/cloudflare/package.json.js +5 -0
  43. package/lib/esm/index.js +24 -0
  44. package/lib/esm/node_modules/debug/src/browser.js +286 -0
  45. package/lib/esm/node_modules/debug/src/common.js +303 -0
  46. package/lib/esm/node_modules/ms/index.js +172 -0
  47. package/lib/esm/package.js +5 -0
  48. package/lib/esm/src/browserContextFactory.js +216 -0
  49. package/lib/esm/src/config.js +72 -0
  50. package/lib/esm/src/connection.js +69 -0
  51. package/lib/esm/src/context.js +277 -0
  52. package/lib/esm/src/fileUtils.js +20 -0
  53. package/lib/esm/src/index.js +11 -0
  54. package/lib/esm/src/javascript.js +35 -0
  55. package/lib/esm/src/manualPromise.js +35 -0
  56. package/lib/esm/src/pageSnapshot.js +31 -0
  57. package/lib/esm/src/tab.js +87 -0
  58. package/lib/esm/src/tools/common.js +56 -0
  59. package/lib/esm/src/tools/console.js +32 -0
  60. package/lib/esm/src/tools/dialogs.js +40 -0
  61. package/lib/esm/src/tools/files.js +39 -0
  62. package/lib/esm/src/tools/install.js +45 -0
  63. package/lib/esm/src/tools/keyboard.js +34 -0
  64. package/lib/esm/src/tools/navigate.js +81 -0
  65. package/lib/esm/src/tools/network.js +39 -0
  66. package/lib/esm/src/tools/pdf.js +38 -0
  67. package/lib/esm/src/tools/screenshot.js +65 -0
  68. package/lib/esm/src/tools/snapshot.js +191 -0
  69. package/lib/esm/src/tools/tabs.js +106 -0
  70. package/lib/esm/src/tools/testing.js +48 -0
  71. package/lib/esm/src/tools/tool.js +5 -0
  72. package/lib/esm/src/tools/utils.js +68 -0
  73. package/lib/esm/src/tools/vision.js +177 -0
  74. package/lib/esm/src/tools/wait.js +47 -0
  75. package/lib/esm/src/tools.js +49 -0
  76. package/package.json +15 -44
  77. package/LICENSE +0 -202
  78. package/README.md +0 -508
  79. package/cli.js +0 -18
  80. package/config.d.ts +0 -128
  81. package/index.js +0 -19
  82. package/lib/browserContextFactory.js +0 -227
  83. package/lib/browserServer.js +0 -151
  84. package/lib/config.js +0 -189
  85. package/lib/connection.js +0 -82
  86. package/lib/context.js +0 -291
  87. package/lib/fileUtils.js +0 -32
  88. package/lib/httpServer.js +0 -201
  89. package/lib/index.js +0 -36
  90. package/lib/javascript.js +0 -49
  91. package/lib/manualPromise.js +0 -111
  92. package/lib/package.js +0 -20
  93. package/lib/pageSnapshot.js +0 -43
  94. package/lib/program.js +0 -72
  95. package/lib/server.js +0 -48
  96. package/lib/tab.js +0 -101
  97. package/lib/tools/common.js +0 -68
  98. package/lib/tools/console.js +0 -44
  99. package/lib/tools/dialogs.js +0 -52
  100. package/lib/tools/files.js +0 -51
  101. package/lib/tools/install.js +0 -57
  102. package/lib/tools/keyboard.js +0 -46
  103. package/lib/tools/navigate.js +0 -93
  104. package/lib/tools/network.js +0 -51
  105. package/lib/tools/pdf.js +0 -49
  106. package/lib/tools/screenshot.js +0 -77
  107. package/lib/tools/snapshot.js +0 -204
  108. package/lib/tools/tabs.js +0 -118
  109. package/lib/tools/testing.js +0 -60
  110. package/lib/tools/tool.js +0 -18
  111. package/lib/tools/utils.js +0 -80
  112. package/lib/tools/vision.js +0 -189
  113. package/lib/tools/wait.js +0 -59
  114. package/lib/tools.js +0 -61
  115. package/lib/transport.js +0 -133
@@ -0,0 +1,281 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+
5
+ const browser = require('../_virtual/browser.js');
6
+ const utils = require('./tools/utils.js');
7
+ const manualPromise = require('./manualPromise.js');
8
+ const tab = require('./tab.js');
9
+ const config = require('./config.js');
10
+
11
+ const testDebug = browser.default("pw:mcp:test");
12
+ class Context {
13
+ tools;
14
+ config;
15
+ _browserContextPromise;
16
+ _browserContextFactory;
17
+ _tabs = [];
18
+ _currentTab;
19
+ _modalStates = [];
20
+ _pendingAction;
21
+ _downloads = [];
22
+ clientVersion;
23
+ constructor(tools, config, browserContextFactory) {
24
+ this.tools = tools;
25
+ this.config = config;
26
+ this._browserContextFactory = browserContextFactory;
27
+ testDebug("create context");
28
+ }
29
+ clientSupportsImages() {
30
+ if (this.config.imageResponses === "allow")
31
+ return true;
32
+ if (this.config.imageResponses === "omit")
33
+ return false;
34
+ return !this.clientVersion?.name.includes("cursor");
35
+ }
36
+ modalStates() {
37
+ return this._modalStates;
38
+ }
39
+ setModalState(modalState, inTab) {
40
+ this._modalStates.push({ ...modalState, tab: inTab });
41
+ }
42
+ clearModalState(modalState) {
43
+ this._modalStates = this._modalStates.filter((state) => state !== modalState);
44
+ }
45
+ modalStatesMarkdown() {
46
+ const result = ["### Modal state"];
47
+ if (this._modalStates.length === 0)
48
+ result.push("- There is no modal state present");
49
+ for (const state of this._modalStates) {
50
+ const tool = this.tools.find((tool2) => tool2.clearsModalState === state.type);
51
+ result.push(`- [${state.description}]: can be handled by the "${tool?.schema.name}" tool`);
52
+ }
53
+ return result;
54
+ }
55
+ tabs() {
56
+ return this._tabs;
57
+ }
58
+ currentTabOrDie() {
59
+ if (!this._currentTab)
60
+ throw new Error("No current snapshot available. Capture a snapshot or navigate to a new location first.");
61
+ return this._currentTab;
62
+ }
63
+ async newTab() {
64
+ const { browserContext } = await this._ensureBrowserContext();
65
+ const page = await browserContext.newPage();
66
+ this._currentTab = this._tabs.find((t) => t.page === page);
67
+ return this._currentTab;
68
+ }
69
+ async selectTab(index) {
70
+ this._currentTab = this._tabs[index - 1];
71
+ await this._currentTab.page.bringToFront();
72
+ }
73
+ async ensureTab() {
74
+ const { browserContext } = await this._ensureBrowserContext();
75
+ if (!this._currentTab)
76
+ await browserContext.newPage();
77
+ return this._currentTab;
78
+ }
79
+ async listTabsMarkdown() {
80
+ if (!this._tabs.length)
81
+ return "### No tabs open";
82
+ const lines = ["### Open tabs"];
83
+ for (let i = 0; i < this._tabs.length; i++) {
84
+ const tab = this._tabs[i];
85
+ const title = await tab.title();
86
+ const url = tab.page.url();
87
+ const current = tab === this._currentTab ? " (current)" : "";
88
+ lines.push(`- ${i + 1}:${current} [${title}] (${url})`);
89
+ }
90
+ return lines.join("\n");
91
+ }
92
+ async closeTab(index) {
93
+ const tab = index === void 0 ? this._currentTab : this._tabs[index - 1];
94
+ await tab?.page.close();
95
+ return await this.listTabsMarkdown();
96
+ }
97
+ async run(tool, params) {
98
+ const toolResult = await tool.handle(this, tool.schema.inputSchema.parse(params || {}));
99
+ const { code, action, waitForNetwork, captureSnapshot, resultOverride } = toolResult;
100
+ const racingAction = action ? () => this._raceAgainstModalDialogs(action) : void 0;
101
+ if (resultOverride)
102
+ return resultOverride;
103
+ if (!this._currentTab) {
104
+ return {
105
+ content: [{
106
+ type: "text",
107
+ text: 'No open pages available. Use the "browser_navigate" tool to navigate to a page first.'
108
+ }]
109
+ };
110
+ }
111
+ const tab = this.currentTabOrDie();
112
+ let actionResult;
113
+ try {
114
+ if (waitForNetwork)
115
+ actionResult = await utils.waitForCompletion(this, tab, async () => racingAction?.()) ?? void 0;
116
+ else
117
+ actionResult = await racingAction?.() ?? void 0;
118
+ } finally {
119
+ if (captureSnapshot && !this._javaScriptBlocked())
120
+ await tab.captureSnapshot();
121
+ }
122
+ const result = [];
123
+ result.push(`- Ran Playwright code:
124
+ \`\`\`js
125
+ ${code.join("\n")}
126
+ \`\`\`
127
+ `);
128
+ if (this.modalStates().length) {
129
+ result.push(...this.modalStatesMarkdown());
130
+ return {
131
+ content: [{
132
+ type: "text",
133
+ text: result.join("\n")
134
+ }]
135
+ };
136
+ }
137
+ if (this._downloads.length) {
138
+ result.push("", "### Downloads");
139
+ for (const entry of this._downloads) {
140
+ if (entry.finished)
141
+ result.push(`- Downloaded file ${entry.download.suggestedFilename()} to ${entry.outputFile}`);
142
+ else
143
+ result.push(`- Downloading file ${entry.download.suggestedFilename()} ...`);
144
+ }
145
+ result.push("");
146
+ }
147
+ if (this.tabs().length > 1)
148
+ result.push(await this.listTabsMarkdown(), "");
149
+ if (this.tabs().length > 1)
150
+ result.push("### Current tab");
151
+ result.push(
152
+ `- Page URL: ${tab.page.url()}`,
153
+ `- Page Title: ${await tab.title()}`
154
+ );
155
+ if (captureSnapshot && tab.hasSnapshot())
156
+ result.push(tab.snapshotOrDie().text());
157
+ const content = actionResult?.content ?? [];
158
+ return {
159
+ content: [
160
+ ...content,
161
+ {
162
+ type: "text",
163
+ text: result.join("\n")
164
+ }
165
+ ]
166
+ };
167
+ }
168
+ async waitForTimeout(time) {
169
+ if (!this._currentTab || this._javaScriptBlocked()) {
170
+ await new Promise((f) => setTimeout(f, time));
171
+ return;
172
+ }
173
+ await utils.callOnPageNoTrace(this._currentTab.page, (page) => {
174
+ return page.evaluate(() => new Promise((f) => setTimeout(f, 1e3)));
175
+ });
176
+ }
177
+ async _raceAgainstModalDialogs(action) {
178
+ this._pendingAction = {
179
+ dialogShown: new manualPromise.ManualPromise()
180
+ };
181
+ let result;
182
+ try {
183
+ await Promise.race([
184
+ action().then((r) => result = r),
185
+ this._pendingAction.dialogShown
186
+ ]);
187
+ } finally {
188
+ this._pendingAction = void 0;
189
+ }
190
+ return result;
191
+ }
192
+ _javaScriptBlocked() {
193
+ return this._modalStates.some((state) => state.type === "dialog");
194
+ }
195
+ dialogShown(tab, dialog) {
196
+ this.setModalState({
197
+ type: "dialog",
198
+ description: `"${dialog.type()}" dialog with message "${dialog.message()}"`,
199
+ dialog
200
+ }, tab);
201
+ this._pendingAction?.dialogShown.resolve();
202
+ }
203
+ async downloadStarted(tab, download) {
204
+ const entry = {
205
+ download,
206
+ finished: false,
207
+ outputFile: await config.outputFile(this.config, download.suggestedFilename())
208
+ };
209
+ this._downloads.push(entry);
210
+ await download.saveAs(entry.outputFile);
211
+ entry.finished = true;
212
+ }
213
+ _onPageCreated(page) {
214
+ const tab$1 = new tab.Tab(this, page, (tab2) => this._onPageClosed(tab2));
215
+ this._tabs.push(tab$1);
216
+ if (!this._currentTab)
217
+ this._currentTab = tab$1;
218
+ }
219
+ _onPageClosed(tab) {
220
+ this._modalStates = this._modalStates.filter((state) => state.tab !== tab);
221
+ const index = this._tabs.indexOf(tab);
222
+ if (index === -1)
223
+ return;
224
+ this._tabs.splice(index, 1);
225
+ if (this._currentTab === tab)
226
+ this._currentTab = this._tabs[Math.min(index, this._tabs.length - 1)];
227
+ if (!this._tabs.length)
228
+ void this.close();
229
+ }
230
+ async close() {
231
+ if (!this._browserContextPromise)
232
+ return;
233
+ testDebug("close context");
234
+ const promise = this._browserContextPromise;
235
+ this._browserContextPromise = void 0;
236
+ await promise.then(async ({ browserContext, close }) => {
237
+ if (this.config.saveTrace)
238
+ await browserContext.tracing.stop();
239
+ await close();
240
+ });
241
+ }
242
+ async _setupRequestInterception(context) {
243
+ if (this.config.network?.allowedOrigins?.length) {
244
+ await context.route("**", (route) => route.abort("blockedbyclient"));
245
+ for (const origin of this.config.network.allowedOrigins)
246
+ await context.route(`*://${origin}/**`, (route) => route.continue());
247
+ }
248
+ if (this.config.network?.blockedOrigins?.length) {
249
+ for (const origin of this.config.network.blockedOrigins)
250
+ await context.route(`*://${origin}/**`, (route) => route.abort("blockedbyclient"));
251
+ }
252
+ }
253
+ _ensureBrowserContext() {
254
+ if (!this._browserContextPromise) {
255
+ this._browserContextPromise = this._setupBrowserContext();
256
+ this._browserContextPromise.catch(() => {
257
+ this._browserContextPromise = void 0;
258
+ });
259
+ }
260
+ return this._browserContextPromise;
261
+ }
262
+ async _setupBrowserContext() {
263
+ const result = await this._browserContextFactory.createContext();
264
+ const { browserContext } = result;
265
+ await this._setupRequestInterception(browserContext);
266
+ for (const page of browserContext.pages())
267
+ this._onPageCreated(page);
268
+ browserContext.on("page", (page) => this._onPageCreated(page));
269
+ if (this.config.saveTrace) {
270
+ await browserContext.tracing.start({
271
+ name: "trace",
272
+ screenshots: false,
273
+ snapshots: true,
274
+ sources: false
275
+ });
276
+ }
277
+ return result;
278
+ }
279
+ }
280
+
281
+ exports.Context = Context;
@@ -0,0 +1,25 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+
5
+ const os = require('node:os');
6
+ const path = require('node:path');
7
+
8
+ function cacheDir() {
9
+ let cacheDirectory;
10
+ if (process.platform === "linux")
11
+ cacheDirectory = process.env.XDG_CACHE_HOME || path.join(os.homedir(), ".cache");
12
+ else if (process.platform === "darwin")
13
+ cacheDirectory = path.join(os.homedir(), "Library", "Caches");
14
+ else if (process.platform === "win32")
15
+ cacheDirectory = process.env.LOCALAPPDATA || path.join(os.homedir(), "AppData", "Local");
16
+ else
17
+ throw new Error("Unsupported platform: " + process.platform);
18
+ return path.join(cacheDirectory, "ms-playwright");
19
+ }
20
+ async function userDataDir(browserConfig) {
21
+ return path.join(cacheDir(), "ms-playwright", `mcp-${browserConfig.launchOptions?.channel ?? browserConfig?.browserName}-profile`);
22
+ }
23
+
24
+ exports.cacheDir = cacheDir;
25
+ exports.userDataDir = userDataDir;
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+
5
+ const connection = require('./connection.js');
6
+ const config = require('./config.js');
7
+ const browserContextFactory = require('./browserContextFactory.js');
8
+
9
+ async function createConnection(userConfig = {}, contextGetter) {
10
+ const config$1 = await config.resolveConfig(userConfig);
11
+ const factory = browserContextFactory.contextFactory(config$1.browser);
12
+ return connection.createConnection(config$1, factory);
13
+ }
14
+
15
+ exports.createConnection = createConnection;
@@ -0,0 +1,41 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+
5
+ function escapeWithQuotes(text, char = "'") {
6
+ const stringified = JSON.stringify(text);
7
+ const escapedText = stringified.substring(1, stringified.length - 1).replace(/\\"/g, '"');
8
+ if (char === "'")
9
+ return char + escapedText.replace(/[']/g, "\\'") + char;
10
+ if (char === '"')
11
+ return char + escapedText.replace(/["]/g, '\\"') + char;
12
+ if (char === "`")
13
+ return char + escapedText.replace(/[`]/g, "`") + char;
14
+ throw new Error("Invalid escape char");
15
+ }
16
+ function quote(text) {
17
+ return escapeWithQuotes(text, "'");
18
+ }
19
+ function formatObject(value, indent = " ") {
20
+ if (typeof value === "string")
21
+ return quote(value);
22
+ if (Array.isArray(value))
23
+ return `[${value.map((o) => formatObject(o)).join(", ")}]`;
24
+ if (typeof value === "object") {
25
+ const keys = Object.keys(value).filter((key) => value[key] !== void 0).sort();
26
+ if (!keys.length)
27
+ return "{}";
28
+ const tokens = [];
29
+ for (const key of keys)
30
+ tokens.push(`${key}: ${formatObject(value[key])}`);
31
+ return `{
32
+ ${indent}${tokens.join(`,
33
+ ${indent}`)}
34
+ }`;
35
+ }
36
+ return String(value);
37
+ }
38
+
39
+ exports.escapeWithQuotes = escapeWithQuotes;
40
+ exports.formatObject = formatObject;
41
+ exports.quote = quote;
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+
5
+ class ManualPromise extends Promise {
6
+ _resolve;
7
+ _reject;
8
+ _isDone;
9
+ constructor() {
10
+ let resolve;
11
+ let reject;
12
+ super((f, r) => {
13
+ resolve = f;
14
+ reject = r;
15
+ });
16
+ this._isDone = false;
17
+ this._resolve = resolve;
18
+ this._reject = reject;
19
+ }
20
+ isDone() {
21
+ return this._isDone;
22
+ }
23
+ resolve(t) {
24
+ this._isDone = true;
25
+ this._resolve(t);
26
+ }
27
+ reject(e) {
28
+ this._isDone = true;
29
+ this._reject(e);
30
+ }
31
+ static get [Symbol.species]() {
32
+ return Promise;
33
+ }
34
+ get [Symbol.toStringTag]() {
35
+ return "ManualPromise";
36
+ }
37
+ }
38
+
39
+ exports.ManualPromise = ManualPromise;
@@ -0,0 +1,35 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+
5
+ const utils = require('./tools/utils.js');
6
+
7
+ class PageSnapshot {
8
+ _page;
9
+ _text;
10
+ constructor(page) {
11
+ this._page = page;
12
+ }
13
+ static async create(page) {
14
+ const snapshot = new PageSnapshot(page);
15
+ await snapshot._build();
16
+ return snapshot;
17
+ }
18
+ text() {
19
+ return this._text;
20
+ }
21
+ async _build() {
22
+ const snapshot = await utils.callOnPageNoTrace(this._page, (page) => page._snapshotForAI());
23
+ this._text = [
24
+ `- Page Snapshot`,
25
+ "```yaml",
26
+ snapshot,
27
+ "```"
28
+ ].join("\n");
29
+ }
30
+ refLocator(params) {
31
+ return this._page.locator(`aria-ref=${params.ref}`).describe(params.element);
32
+ }
33
+ }
34
+
35
+ exports.PageSnapshot = PageSnapshot;
@@ -0,0 +1,91 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+
5
+ const pageSnapshot = require('./pageSnapshot.js');
6
+ const utils = require('./tools/utils.js');
7
+
8
+ class Tab {
9
+ context;
10
+ page;
11
+ _consoleMessages = [];
12
+ _requests = /* @__PURE__ */ new Map();
13
+ _snapshot;
14
+ _onPageClose;
15
+ constructor(context, page, onPageClose) {
16
+ this.context = context;
17
+ this.page = page;
18
+ this._onPageClose = onPageClose;
19
+ page.on("console", (event) => this._consoleMessages.push(event));
20
+ page.on("request", (request) => this._requests.set(request, null));
21
+ page.on("response", (response) => this._requests.set(response.request(), response));
22
+ page.on("close", () => this._onClose());
23
+ page.on("filechooser", (chooser) => {
24
+ this.context.setModalState({
25
+ type: "fileChooser",
26
+ description: "File chooser",
27
+ fileChooser: chooser
28
+ }, this);
29
+ });
30
+ page.on("dialog", (dialog) => this.context.dialogShown(this, dialog));
31
+ page.on("download", (download) => {
32
+ void this.context.downloadStarted(this, download);
33
+ });
34
+ page.setDefaultNavigationTimeout(6e4);
35
+ page.setDefaultTimeout(5e3);
36
+ }
37
+ _clearCollectedArtifacts() {
38
+ this._consoleMessages.length = 0;
39
+ this._requests.clear();
40
+ }
41
+ _onClose() {
42
+ this._clearCollectedArtifacts();
43
+ this._onPageClose(this);
44
+ }
45
+ async title() {
46
+ return await utils.callOnPageNoTrace(this.page, (page) => page.title());
47
+ }
48
+ async waitForLoadState(state, options) {
49
+ await utils.callOnPageNoTrace(this.page, (page) => page.waitForLoadState(state, options).catch(() => {
50
+ }));
51
+ }
52
+ async navigate(url) {
53
+ this._clearCollectedArtifacts();
54
+ const downloadEvent = utils.callOnPageNoTrace(this.page, (page) => page.waitForEvent("download").catch(() => {
55
+ }));
56
+ try {
57
+ await this.page.goto(url, { waitUntil: "domcontentloaded" });
58
+ } catch (_e) {
59
+ const e = _e;
60
+ const mightBeDownload = e.message.includes("net::ERR_ABORTED") || e.message.includes("Download is starting");
61
+ if (!mightBeDownload)
62
+ throw e;
63
+ const download = await Promise.race([
64
+ downloadEvent,
65
+ new Promise((resolve) => setTimeout(resolve, 1e3))
66
+ ]);
67
+ if (!download)
68
+ throw e;
69
+ }
70
+ await this.waitForLoadState("load", { timeout: 5e3 });
71
+ }
72
+ hasSnapshot() {
73
+ return !!this._snapshot;
74
+ }
75
+ snapshotOrDie() {
76
+ if (!this._snapshot)
77
+ throw new Error("No snapshot available");
78
+ return this._snapshot;
79
+ }
80
+ consoleMessages() {
81
+ return this._consoleMessages;
82
+ }
83
+ requests() {
84
+ return this._requests;
85
+ }
86
+ async captureSnapshot() {
87
+ this._snapshot = await pageSnapshot.PageSnapshot.create(this.page);
88
+ }
89
+ }
90
+
91
+ exports.Tab = Tab;
@@ -0,0 +1,60 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
4
+
5
+ const zod = require('zod');
6
+ const tool = require('./tool.js');
7
+
8
+ const close = tool.defineTool({
9
+ capability: "core",
10
+ schema: {
11
+ name: "browser_close",
12
+ title: "Close browser",
13
+ description: "Close the page",
14
+ inputSchema: zod.z.object({}),
15
+ type: "readOnly"
16
+ },
17
+ handle: async (context) => {
18
+ await context.close();
19
+ return {
20
+ code: [`await page.close()`],
21
+ captureSnapshot: false,
22
+ waitForNetwork: false
23
+ };
24
+ }
25
+ });
26
+ const resize = (captureSnapshot) => tool.defineTool({
27
+ capability: "core",
28
+ schema: {
29
+ name: "browser_resize",
30
+ title: "Resize browser window",
31
+ description: "Resize the browser window",
32
+ inputSchema: zod.z.object({
33
+ width: zod.z.coerce.number().describe("Width of the browser window"),
34
+ height: zod.z.coerce.number().describe("Height of the browser window")
35
+ }),
36
+ type: "readOnly"
37
+ },
38
+ handle: async (context, params) => {
39
+ const tab = context.currentTabOrDie();
40
+ const code = [
41
+ `// Resize browser window to ${params.width}x${params.height}`,
42
+ `await page.setViewportSize({ width: ${params.width}, height: ${params.height} });`
43
+ ];
44
+ const action = async () => {
45
+ await tab.page.setViewportSize({ width: params.width, height: params.height });
46
+ };
47
+ return {
48
+ code,
49
+ action,
50
+ captureSnapshot,
51
+ waitForNetwork: true
52
+ };
53
+ }
54
+ });
55
+ const common = (captureSnapshot) => [
56
+ close,
57
+ resize(captureSnapshot)
58
+ ];
59
+
60
+ exports.default = common;
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
4
+
5
+ const zod = require('zod');
6
+ const tool = require('./tool.js');
7
+
8
+ const console = tool.defineTool({
9
+ capability: "core",
10
+ schema: {
11
+ name: "browser_console_messages",
12
+ title: "Get console messages",
13
+ description: "Returns all console messages",
14
+ inputSchema: zod.z.object({}),
15
+ type: "readOnly"
16
+ },
17
+ handle: async (context) => {
18
+ const messages = context.currentTabOrDie().consoleMessages();
19
+ const log = messages.map((message) => `[${message.type().toUpperCase()}] ${message.text()}`).join("\n");
20
+ return {
21
+ code: [`// <internal code to get console messages>`],
22
+ action: async () => {
23
+ return {
24
+ content: [{ type: "text", text: log }]
25
+ };
26
+ },
27
+ captureSnapshot: false,
28
+ waitForNetwork: false
29
+ };
30
+ }
31
+ });
32
+ const console$1 = [
33
+ console
34
+ ];
35
+
36
+ exports.default = console$1;
@@ -0,0 +1,44 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
4
+
5
+ const zod = require('zod');
6
+ const tool = require('./tool.js');
7
+
8
+ const handleDialog = (captureSnapshot) => tool.defineTool({
9
+ capability: "core",
10
+ schema: {
11
+ name: "browser_handle_dialog",
12
+ title: "Handle a dialog",
13
+ description: "Handle a dialog",
14
+ inputSchema: zod.z.object({
15
+ accept: zod.z.coerce.boolean().describe("Whether to accept the dialog."),
16
+ promptText: zod.z.string().optional().describe("The text of the prompt in case of a prompt dialog.")
17
+ }),
18
+ type: "destructive"
19
+ },
20
+ handle: async (context, params) => {
21
+ const dialogState = context.modalStates().find((state) => state.type === "dialog");
22
+ if (!dialogState)
23
+ throw new Error("No dialog visible");
24
+ if (params.accept)
25
+ await dialogState.dialog.accept(params.promptText);
26
+ else
27
+ await dialogState.dialog.dismiss();
28
+ context.clearModalState(dialogState);
29
+ const code = [
30
+ `// <internal code to handle "${dialogState.dialog.type()}" dialog>`
31
+ ];
32
+ return {
33
+ code,
34
+ captureSnapshot,
35
+ waitForNetwork: false
36
+ };
37
+ },
38
+ clearsModalState: "dialog"
39
+ });
40
+ const dialogs = (captureSnapshot) => [
41
+ handleDialog(captureSnapshot)
42
+ ];
43
+
44
+ exports.default = dialogs;