@playwright/mcp 0.0.36-alpha-2025-09-02 → 0.0.36-alpha-2025-09-04

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 (69) hide show
  1. package/README.md +1 -1
  2. package/cli.js +1 -1
  3. package/index.d.ts +1 -1
  4. package/index.js +2 -2
  5. package/lib/{browserContextFactory.js → browser/browserContextFactory.js} +76 -36
  6. package/lib/{browserServerBackend.js → browser/browserServerBackend.js} +24 -22
  7. package/lib/{utils → browser}/codegen.js +8 -3
  8. package/lib/{config.js → browser/config.js} +43 -26
  9. package/lib/{context.js → browser/context.js} +27 -30
  10. package/lib/{response.js → browser/response.js} +14 -14
  11. package/lib/{sessionLog.js → browser/sessionLog.js} +23 -18
  12. package/lib/{tab.js → browser/tab.js} +29 -27
  13. package/lib/{tools → browser/tools}/common.js +11 -9
  14. package/lib/{tools → browser/tools}/console.js +7 -5
  15. package/lib/{tools → browser/tools}/dialogs.js +9 -7
  16. package/lib/browser/tools/evaluate.js +88 -0
  17. package/lib/{tools → browser/tools}/files.js +8 -6
  18. package/lib/browser/tools/form.js +92 -0
  19. package/lib/{tools → browser/tools}/install.js +18 -14
  20. package/lib/browser/tools/keyboard.js +113 -0
  21. package/lib/{tools → browser/tools}/mouse.js +18 -16
  22. package/lib/{tools → browser/tools}/navigate.js +10 -8
  23. package/lib/{tools → browser/tools}/network.js +7 -5
  24. package/lib/browser/tools/pdf.js +76 -0
  25. package/lib/browser/tools/screenshot.js +115 -0
  26. package/lib/browser/tools/snapshot.js +175 -0
  27. package/lib/{tools → browser/tools}/tabs.js +9 -7
  28. package/lib/{tools → browser/tools}/tool.js +6 -2
  29. package/lib/{tools → browser/tools}/utils.js +10 -5
  30. package/lib/{tools → browser/tools}/verify.js +59 -24
  31. package/lib/{tools → browser/tools}/wait.js +10 -8
  32. package/lib/browser/tools.js +61 -0
  33. package/lib/extension/cdpRelay.js +85 -48
  34. package/lib/extension/extensionContextFactory.js +48 -11
  35. package/lib/extension/protocol.js +4 -1
  36. package/lib/index.js +47 -12
  37. package/lib/{utils/log.js → log.js} +11 -4
  38. package/lib/{utils/package.js → package.js} +9 -5
  39. package/lib/program.js +68 -39
  40. package/lib/sdk/bundle.js +79 -0
  41. package/lib/{mcp → sdk}/http.js +57 -17
  42. package/lib/{mcp → sdk}/inProcessTransport.js +15 -20
  43. package/lib/{mcp → sdk}/manualPromise.js +11 -9
  44. package/lib/{mcp → sdk}/mdb.js +77 -38
  45. package/lib/{mcp → sdk}/proxyBackend.js +53 -16
  46. package/lib/sdk/server.js +164 -0
  47. package/lib/{mcp → sdk}/tool.js +8 -4
  48. package/lib/vscode/host.js +64 -35
  49. package/lib/vscode/main.js +48 -13
  50. package/package.json +6 -7
  51. package/lib/loop/loop.js +0 -69
  52. package/lib/loop/loopClaude.js +0 -152
  53. package/lib/loop/loopOpenAI.js +0 -141
  54. package/lib/loop/main.js +0 -60
  55. package/lib/loopTools/context.js +0 -67
  56. package/lib/loopTools/main.js +0 -54
  57. package/lib/loopTools/perform.js +0 -32
  58. package/lib/loopTools/snapshot.js +0 -29
  59. package/lib/loopTools/tool.js +0 -18
  60. package/lib/mcp/server.js +0 -123
  61. package/lib/tools/evaluate.js +0 -53
  62. package/lib/tools/form.js +0 -57
  63. package/lib/tools/keyboard.js +0 -78
  64. package/lib/tools/pdf.js +0 -40
  65. package/lib/tools/screenshot.js +0 -79
  66. package/lib/tools/snapshot.js +0 -139
  67. package/lib/tools.js +0 -54
  68. package/lib/utils/fileUtils.js +0 -36
  69. package/lib/utils/guid.js +0 -22
package/README.md CHANGED
@@ -76,7 +76,7 @@ For more information, see the [Codex MCP documentation](https://github.com/opena
76
76
 
77
77
  #### Click the button to install:
78
78
 
79
- [![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](cursor://anysphere.cursor-deeplink/mcp/install?name=Playwright&config=eyJjb21tYW5kIjoibnB4IEBwbGF5d3JpZ2h0L21jcEBsYXRlc3QifQ%3D%3D)
79
+ [<img src="https://cursor.com/deeplink/mcp-install-dark.svg" alt="Install in Cursor">](cursor://anysphere.cursor-deeplink/mcp/install?name=Playwright&config=eyJjb21tYW5kIjoibnB4IEBwbGF5d3JpZ2h0L21jcEBsYXRlc3QifQ%3D%3D)
80
80
 
81
81
  #### Or install manually:
82
82
 
package/cli.js CHANGED
@@ -15,4 +15,4 @@
15
15
  * limitations under the License.
16
16
  */
17
17
 
18
- import './lib/program.js';
18
+ require('./lib/program');
package/index.d.ts CHANGED
@@ -16,7 +16,7 @@
16
16
  */
17
17
 
18
18
  import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
19
- import type { Config } from './config.js';
19
+ import type { Config } from './config';
20
20
  import type { BrowserContext } from 'playwright';
21
21
 
22
22
  export declare function createConnection(config?: Config, contextGetter?: () => Promise<BrowserContext>): Promise<Server>;
package/index.js CHANGED
@@ -15,5 +15,5 @@
15
15
  * limitations under the License.
16
16
  */
17
17
 
18
- import { createConnection } from './lib/index.js';
19
- export { createConnection };
18
+ const { createConnection } = require('./lib/index.js');
19
+ module.exports = { createConnection };
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /**
2
3
  * Copyright (c) Microsoft Corporation.
3
4
  *
@@ -13,18 +14,56 @@
13
14
  * See the License for the specific language governing permissions and
14
15
  * limitations under the License.
15
16
  */
16
- import fs from 'fs';
17
- import net from 'net';
18
- import path from 'path';
19
- import * as playwright from 'playwright';
17
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ var desc = Object.getOwnPropertyDescriptor(m, k);
20
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
21
+ desc = { enumerable: true, get: function() { return m[k]; } };
22
+ }
23
+ Object.defineProperty(o, k2, desc);
24
+ }) : (function(o, m, k, k2) {
25
+ if (k2 === undefined) k2 = k;
26
+ o[k2] = m[k];
27
+ }));
28
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
29
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
30
+ }) : function(o, v) {
31
+ o["default"] = v;
32
+ });
33
+ var __importStar = (this && this.__importStar) || (function () {
34
+ var ownKeys = function(o) {
35
+ ownKeys = Object.getOwnPropertyNames || function (o) {
36
+ var ar = [];
37
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
38
+ return ar;
39
+ };
40
+ return ownKeys(o);
41
+ };
42
+ return function (mod) {
43
+ if (mod && mod.__esModule) return mod;
44
+ var result = {};
45
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
46
+ __setModuleDefault(result, mod);
47
+ return result;
48
+ };
49
+ })();
50
+ var __importDefault = (this && this.__importDefault) || function (mod) {
51
+ return (mod && mod.__esModule) ? mod : { "default": mod };
52
+ };
53
+ Object.defineProperty(exports, "__esModule", { value: true });
54
+ exports.contextFactory = contextFactory;
55
+ const crypto_1 = __importDefault(require("crypto"));
56
+ const fs_1 = __importDefault(require("fs"));
57
+ const net_1 = __importDefault(require("net"));
58
+ const path_1 = __importDefault(require("path"));
59
+ const playwright = __importStar(require("playwright"));
20
60
  // @ts-ignore
21
- import { registryDirectory } from 'playwright-core/lib/server/registry/index';
61
+ const index_1 = require("playwright-core/lib/server/registry/index");
22
62
  // @ts-ignore
23
- import { startTraceViewerServer } from 'playwright-core/lib/server';
24
- import { logUnhandledError, testDebug } from './utils/log.js';
25
- import { createHash } from './utils/guid.js';
26
- import { outputFile } from './config.js';
27
- export function contextFactory(config) {
63
+ const server_1 = require("playwright-core/lib/server");
64
+ const log_1 = require("../log");
65
+ const config_1 = require("./config");
66
+ function contextFactory(config) {
28
67
  if (config.browser.remoteEndpoint)
29
68
  return new RemoteContextFactory(config);
30
69
  if (config.browser.cdpEndpoint)
@@ -34,9 +73,6 @@ export function contextFactory(config) {
34
73
  return new PersistentContextFactory(config);
35
74
  }
36
75
  class BaseContextFactory {
37
- config;
38
- _logName;
39
- _browserPromise;
40
76
  constructor(name, config) {
41
77
  this._logName = name;
42
78
  this.config = config;
@@ -44,7 +80,7 @@ class BaseContextFactory {
44
80
  async _obtainBrowser(clientInfo) {
45
81
  if (this._browserPromise)
46
82
  return this._browserPromise;
47
- testDebug(`obtain browser (${this._logName})`);
83
+ (0, log_1.testDebug)(`obtain browser (${this._logName})`);
48
84
  this._browserPromise = this._doObtainBrowser(clientInfo);
49
85
  void this._browserPromise.then(browser => {
50
86
  browser.on('disconnected', () => {
@@ -59,7 +95,7 @@ class BaseContextFactory {
59
95
  throw new Error('Not implemented');
60
96
  }
61
97
  async createContext(clientInfo) {
62
- testDebug(`create browser context (${this._logName})`);
98
+ (0, log_1.testDebug)(`create browser context (${this._logName})`);
63
99
  const browser = await this._obtainBrowser(clientInfo);
64
100
  const browserContext = await this._doCreateContext(browser);
65
101
  return { browserContext, close: () => this._closeBrowserContext(browserContext, browser) };
@@ -68,13 +104,13 @@ class BaseContextFactory {
68
104
  throw new Error('Not implemented');
69
105
  }
70
106
  async _closeBrowserContext(browserContext, browser) {
71
- testDebug(`close browser context (${this._logName})`);
107
+ (0, log_1.testDebug)(`close browser context (${this._logName})`);
72
108
  if (browser.contexts().length === 1)
73
109
  this._browserPromise = undefined;
74
- await browserContext.close().catch(logUnhandledError);
110
+ await browserContext.close().catch(log_1.logUnhandledError);
75
111
  if (browser.contexts().length === 0) {
76
- testDebug(`close browser (${this._logName})`);
77
- await browser.close().catch(logUnhandledError);
112
+ (0, log_1.testDebug)(`close browser (${this._logName})`);
113
+ await browser.close().catch(log_1.logUnhandledError);
78
114
  }
79
115
  }
80
116
  }
@@ -127,20 +163,20 @@ class RemoteContextFactory extends BaseContextFactory {
127
163
  }
128
164
  }
129
165
  class PersistentContextFactory {
130
- config;
131
- name = 'persistent';
132
- description = 'Create a new persistent browser context';
133
- _userDataDirs = new Set();
134
166
  constructor(config) {
167
+ this.name = 'persistent';
168
+ this.description = 'Create a new persistent browser context';
169
+ this._userDataDirs = new Set();
135
170
  this.config = config;
136
171
  }
137
172
  async createContext(clientInfo) {
173
+ var _a;
138
174
  await injectCdpPort(this.config.browser);
139
- testDebug('create browser context (persistent)');
140
- const userDataDir = this.config.browser.userDataDir ?? await this._createUserDataDir(clientInfo.rootPath);
175
+ (0, log_1.testDebug)('create browser context (persistent)');
176
+ const userDataDir = (_a = this.config.browser.userDataDir) !== null && _a !== void 0 ? _a : await this._createUserDataDir(clientInfo.rootPath);
141
177
  const tracesDir = await startTraceServer(this.config, clientInfo.rootPath);
142
178
  this._userDataDirs.add(userDataDir);
143
- testDebug('lock user data dir', userDataDir);
179
+ (0, log_1.testDebug)('lock user data dir', userDataDir);
144
180
  const browserType = playwright[this.config.browser.browserName];
145
181
  for (let i = 0; i < 5; i++) {
146
182
  try {
@@ -168,19 +204,20 @@ class PersistentContextFactory {
168
204
  throw new Error(`Browser is already in use for ${userDataDir}, use --isolated to run multiple instances of the same browser`);
169
205
  }
170
206
  async _closeBrowserContext(browserContext, userDataDir) {
171
- testDebug('close browser context (persistent)');
172
- testDebug('release user data dir', userDataDir);
207
+ (0, log_1.testDebug)('close browser context (persistent)');
208
+ (0, log_1.testDebug)('release user data dir', userDataDir);
173
209
  await browserContext.close().catch(() => { });
174
210
  this._userDataDirs.delete(userDataDir);
175
- testDebug('close browser context complete (persistent)');
211
+ (0, log_1.testDebug)('close browser context complete (persistent)');
176
212
  }
177
213
  async _createUserDataDir(rootPath) {
178
- const dir = process.env.PWMCP_PROFILES_DIR_FOR_TEST ?? registryDirectory;
179
- const browserToken = this.config.browser.launchOptions?.channel ?? this.config.browser?.browserName;
214
+ var _a, _b, _c, _d;
215
+ const dir = (_a = process.env.PWMCP_PROFILES_DIR_FOR_TEST) !== null && _a !== void 0 ? _a : index_1.registryDirectory;
216
+ const browserToken = (_c = (_b = this.config.browser.launchOptions) === null || _b === void 0 ? void 0 : _b.channel) !== null && _c !== void 0 ? _c : (_d = this.config.browser) === null || _d === void 0 ? void 0 : _d.browserName;
180
217
  // Hesitant putting hundreds of files into the user's workspace, so using it for hashing instead.
181
218
  const rootPathToken = rootPath ? `-${createHash(rootPath)}` : '';
182
- const result = path.join(dir, `mcp-${browserToken}${rootPathToken}`);
183
- await fs.promises.mkdir(result, { recursive: true });
219
+ const result = path_1.default.join(dir, `mcp-${browserToken}${rootPathToken}`);
220
+ await fs_1.default.promises.mkdir(result, { recursive: true });
184
221
  return result;
185
222
  }
186
223
  }
@@ -190,7 +227,7 @@ async function injectCdpPort(browserConfig) {
190
227
  }
191
228
  async function findFreePort() {
192
229
  return new Promise((resolve, reject) => {
193
- const server = net.createServer();
230
+ const server = net_1.default.createServer();
194
231
  server.listen(0, () => {
195
232
  const { port } = server.address();
196
233
  server.close(() => resolve(port));
@@ -201,11 +238,14 @@ async function findFreePort() {
201
238
  async function startTraceServer(config, rootPath) {
202
239
  if (!config.saveTrace)
203
240
  return undefined;
204
- const tracesDir = await outputFile(config, rootPath, `traces-${Date.now()}`);
205
- const server = await startTraceViewerServer();
241
+ const tracesDir = await (0, config_1.outputFile)(config, rootPath, `traces-${Date.now()}`);
242
+ const server = await (0, server_1.startTraceViewerServer)();
206
243
  const urlPrefix = server.urlPrefix('human-readable');
207
244
  const url = urlPrefix + '/trace/index.html?trace=' + tracesDir + '/trace.json';
208
245
  // eslint-disable-next-line no-console
209
246
  console.error('\nTrace viewer listening on ' + url);
210
247
  return tracesDir;
211
248
  }
249
+ function createHash(data) {
250
+ return crypto_1.default.createHash('sha256').update(data).digest('hex').slice(0, 7);
251
+ }
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /**
2
3
  * Copyright (c) Microsoft Corporation.
3
4
  *
@@ -13,33 +14,31 @@
13
14
  * See the License for the specific language governing permissions and
14
15
  * limitations under the License.
15
16
  */
16
- import { fileURLToPath } from 'url';
17
- import { Context } from './context.js';
18
- import { logUnhandledError } from './utils/log.js';
19
- import { Response } from './response.js';
20
- import { SessionLog } from './sessionLog.js';
21
- import { filteredTools } from './tools.js';
22
- import { toMcpTool } from './mcp/tool.js';
23
- export class BrowserServerBackend {
24
- _tools;
25
- _context;
26
- _sessionLog;
27
- _config;
28
- _browserContextFactory;
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.BrowserServerBackend = void 0;
19
+ const url_1 = require("url");
20
+ const context_1 = require("./context");
21
+ const log_1 = require("../log");
22
+ const response_1 = require("./response");
23
+ const sessionLog_1 = require("./sessionLog");
24
+ const tools_1 = require("./tools");
25
+ const tool_1 = require("../sdk/tool");
26
+ class BrowserServerBackend {
29
27
  constructor(config, factory) {
30
28
  this._config = config;
31
29
  this._browserContextFactory = factory;
32
- this._tools = filteredTools(config);
30
+ this._tools = (0, tools_1.filteredTools)(config);
33
31
  }
34
32
  async initialize(server, clientVersion, roots) {
33
+ var _a;
35
34
  let rootPath;
36
35
  if (roots.length > 0) {
37
- const firstRootUri = roots[0]?.uri;
36
+ const firstRootUri = (_a = roots[0]) === null || _a === void 0 ? void 0 : _a.uri;
38
37
  const url = firstRootUri ? new URL(firstRootUri) : undefined;
39
- rootPath = url ? fileURLToPath(url) : undefined;
38
+ rootPath = url ? (0, url_1.fileURLToPath)(url) : undefined;
40
39
  }
41
- this._sessionLog = this._config.saveSession ? await SessionLog.create(this._config, rootPath) : undefined;
42
- this._context = new Context({
40
+ this._sessionLog = this._config.saveSession ? await sessionLog_1.SessionLog.create(this._config, rootPath) : undefined;
41
+ this._context = new context_1.Context({
43
42
  tools: this._tools,
44
43
  config: this._config,
45
44
  browserContextFactory: this._browserContextFactory,
@@ -48,20 +47,21 @@ export class BrowserServerBackend {
48
47
  });
49
48
  }
50
49
  async listTools() {
51
- return this._tools.map(tool => toMcpTool(tool.schema));
50
+ return this._tools.map(tool => (0, tool_1.toMcpTool)(tool.schema));
52
51
  }
53
52
  async callTool(name, rawArguments) {
53
+ var _a;
54
54
  const tool = this._tools.find(tool => tool.schema.name === name);
55
55
  if (!tool)
56
56
  throw new Error(`Tool "${name}" not found`);
57
57
  const parsedArguments = tool.schema.inputSchema.parse(rawArguments || {});
58
58
  const context = this._context;
59
- const response = new Response(context, name, parsedArguments);
59
+ const response = new response_1.Response(context, name, parsedArguments);
60
60
  context.setRunningTool(name);
61
61
  try {
62
62
  await tool.handle(context, parsedArguments, response);
63
63
  await response.finish();
64
- this._sessionLog?.logResponse(response);
64
+ (_a = this._sessionLog) === null || _a === void 0 ? void 0 : _a.logResponse(response);
65
65
  }
66
66
  catch (error) {
67
67
  response.addError(String(error));
@@ -72,6 +72,8 @@ export class BrowserServerBackend {
72
72
  return response.serialize();
73
73
  }
74
74
  serverClosed() {
75
- void this._context?.dispose().catch(logUnhandledError);
75
+ var _a;
76
+ void ((_a = this._context) === null || _a === void 0 ? void 0 : _a.dispose().catch(log_1.logUnhandledError));
76
77
  }
77
78
  }
79
+ exports.BrowserServerBackend = BrowserServerBackend;
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /**
2
3
  * Copyright (c) Microsoft Corporation.
3
4
  *
@@ -13,11 +14,15 @@
13
14
  * See the License for the specific language governing permissions and
14
15
  * limitations under the License.
15
16
  */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.escapeWithQuotes = escapeWithQuotes;
19
+ exports.quote = quote;
20
+ exports.formatObject = formatObject;
16
21
  // adapted from:
17
22
  // - https://github.com/microsoft/playwright/blob/76ee48dc9d4034536e3ec5b2c7ce8be3b79418a8/packages/playwright-core/src/utils/isomorphic/stringUtils.ts
18
23
  // - https://github.com/microsoft/playwright/blob/76ee48dc9d4034536e3ec5b2c7ce8be3b79418a8/packages/playwright-core/src/server/codegen/javascript.ts
19
24
  // NOTE: this function should not be used to escape any selectors.
20
- export function escapeWithQuotes(text, char = '\'') {
25
+ function escapeWithQuotes(text, char = '\'') {
21
26
  const stringified = JSON.stringify(text);
22
27
  const escapedText = stringified.substring(1, stringified.length - 1).replace(/\\"/g, '"');
23
28
  if (char === '\'')
@@ -28,10 +33,10 @@ export function escapeWithQuotes(text, char = '\'') {
28
33
  return char + escapedText.replace(/[`]/g, '\\`') + char;
29
34
  throw new Error('Invalid escape char');
30
35
  }
31
- export function quote(text) {
36
+ function quote(text) {
32
37
  return escapeWithQuotes(text, '\'');
33
38
  }
34
- export function formatObject(value, indent = ' ') {
39
+ function formatObject(value, indent = ' ') {
35
40
  if (typeof value === 'string')
36
41
  return quote(value);
37
42
  if (Array.isArray(value))
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /**
2
3
  * Copyright (c) Microsoft Corporation.
3
4
  *
@@ -13,17 +14,26 @@
13
14
  * See the License for the specific language governing permissions and
14
15
  * limitations under the License.
15
16
  */
16
- import fs from 'fs';
17
- import os from 'os';
18
- import path from 'path';
19
- import { devices } from 'playwright';
20
- import { sanitizeForFilePath } from './utils/fileUtils.js';
17
+ var __importDefault = (this && this.__importDefault) || function (mod) {
18
+ return (mod && mod.__esModule) ? mod : { "default": mod };
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.resolveConfig = resolveConfig;
22
+ exports.resolveCLIConfig = resolveCLIConfig;
23
+ exports.configFromCLIOptions = configFromCLIOptions;
24
+ exports.outputFile = outputFile;
25
+ exports.semicolonSeparatedList = semicolonSeparatedList;
26
+ exports.commaSeparatedList = commaSeparatedList;
27
+ const fs_1 = __importDefault(require("fs"));
28
+ const os_1 = __importDefault(require("os"));
29
+ const path_1 = __importDefault(require("path"));
30
+ const playwright_1 = require("playwright");
21
31
  const defaultConfig = {
22
32
  browser: {
23
33
  browserName: 'chromium',
24
34
  launchOptions: {
25
35
  channel: 'chrome',
26
- headless: os.platform() === 'linux' && !process.env.DISPLAY,
36
+ headless: os_1.default.platform() === 'linux' && !process.env.DISPLAY,
27
37
  chromiumSandbox: true,
28
38
  },
29
39
  contextOptions: {
@@ -37,10 +47,10 @@ const defaultConfig = {
37
47
  server: {},
38
48
  saveTrace: false,
39
49
  };
40
- export async function resolveConfig(config) {
50
+ async function resolveConfig(config) {
41
51
  return mergeConfig(defaultConfig, config);
42
52
  }
43
- export async function resolveCLIConfig(cliOptions) {
53
+ async function resolveCLIConfig(cliOptions) {
44
54
  const configInFile = await loadConfig(cliOptions.config);
45
55
  const envOverrides = configFromEnv();
46
56
  const cliOverrides = configFromCLIOptions(cliOptions);
@@ -50,7 +60,7 @@ export async function resolveCLIConfig(cliOptions) {
50
60
  result = mergeConfig(result, cliOverrides);
51
61
  return result;
52
62
  }
53
- export function configFromCLIOptions(cliOptions) {
63
+ function configFromCLIOptions(cliOptions) {
54
64
  let browserName;
55
65
  let channel;
56
66
  switch (cliOptions.browser) {
@@ -92,7 +102,7 @@ export function configFromCLIOptions(cliOptions) {
92
102
  if (cliOptions.device && cliOptions.cdpEndpoint)
93
103
  throw new Error('Device emulation is not supported with cdpEndpoint.');
94
104
  // Context options
95
- const contextOptions = cliOptions.device ? devices[cliOptions.device] : {};
105
+ const contextOptions = cliOptions.device ? playwright_1.devices[cliOptions.device] : {};
96
106
  if (cliOptions.storageState)
97
107
  contextOptions.storageState = cliOptions.storageState;
98
108
  if (cliOptions.userAgent)
@@ -170,37 +180,37 @@ async function loadConfig(configFile) {
170
180
  if (!configFile)
171
181
  return {};
172
182
  try {
173
- return JSON.parse(await fs.promises.readFile(configFile, 'utf8'));
183
+ return JSON.parse(await fs_1.default.promises.readFile(configFile, 'utf8'));
174
184
  }
175
185
  catch (error) {
176
186
  throw new Error(`Failed to load config file: ${configFile}, ${error}`);
177
187
  }
178
188
  }
179
- export async function outputFile(config, rootPath, name) {
180
- const outputDir = config.outputDir
181
- ?? (rootPath ? path.join(rootPath, '.playwright-mcp') : undefined)
182
- ?? path.join(os.tmpdir(), 'playwright-mcp-output', sanitizeForFilePath(new Date().toISOString()));
183
- await fs.promises.mkdir(outputDir, { recursive: true });
189
+ async function outputFile(config, rootPath, name) {
190
+ var _a, _b;
191
+ const outputDir = (_b = (_a = config.outputDir) !== null && _a !== void 0 ? _a : (rootPath ? path_1.default.join(rootPath, '.playwright-mcp') : undefined)) !== null && _b !== void 0 ? _b : path_1.default.join(os_1.default.tmpdir(), 'playwright-mcp-output', sanitizeForFilePath(new Date().toISOString()));
192
+ await fs_1.default.promises.mkdir(outputDir, { recursive: true });
184
193
  const fileName = sanitizeForFilePath(name);
185
- return path.join(outputDir, fileName);
194
+ return path_1.default.join(outputDir, fileName);
186
195
  }
187
196
  function pickDefined(obj) {
188
- return Object.fromEntries(Object.entries(obj ?? {}).filter(([_, v]) => v !== undefined));
197
+ return Object.fromEntries(Object.entries(obj !== null && obj !== void 0 ? obj : {}).filter(([_, v]) => v !== undefined));
189
198
  }
190
199
  function mergeConfig(base, overrides) {
200
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
191
201
  const browser = {
192
202
  ...pickDefined(base.browser),
193
203
  ...pickDefined(overrides.browser),
194
- browserName: overrides.browser?.browserName ?? base.browser?.browserName ?? 'chromium',
195
- isolated: overrides.browser?.isolated ?? base.browser?.isolated ?? false,
204
+ browserName: (_d = (_b = (_a = overrides.browser) === null || _a === void 0 ? void 0 : _a.browserName) !== null && _b !== void 0 ? _b : (_c = base.browser) === null || _c === void 0 ? void 0 : _c.browserName) !== null && _d !== void 0 ? _d : 'chromium',
205
+ isolated: (_h = (_f = (_e = overrides.browser) === null || _e === void 0 ? void 0 : _e.isolated) !== null && _f !== void 0 ? _f : (_g = base.browser) === null || _g === void 0 ? void 0 : _g.isolated) !== null && _h !== void 0 ? _h : false,
196
206
  launchOptions: {
197
- ...pickDefined(base.browser?.launchOptions),
198
- ...pickDefined(overrides.browser?.launchOptions),
207
+ ...pickDefined((_j = base.browser) === null || _j === void 0 ? void 0 : _j.launchOptions),
208
+ ...pickDefined((_k = overrides.browser) === null || _k === void 0 ? void 0 : _k.launchOptions),
199
209
  ...{ assistantMode: true },
200
210
  },
201
211
  contextOptions: {
202
- ...pickDefined(base.browser?.contextOptions),
203
- ...pickDefined(overrides.browser?.contextOptions),
212
+ ...pickDefined((_l = base.browser) === null || _l === void 0 ? void 0 : _l.contextOptions),
213
+ ...pickDefined((_m = overrides.browser) === null || _m === void 0 ? void 0 : _m.contextOptions),
204
214
  },
205
215
  };
206
216
  if (browser.browserName !== 'chromium' && browser.launchOptions)
@@ -219,12 +229,12 @@ function mergeConfig(base, overrides) {
219
229
  },
220
230
  };
221
231
  }
222
- export function semicolonSeparatedList(value) {
232
+ function semicolonSeparatedList(value) {
223
233
  if (!value)
224
234
  return undefined;
225
235
  return value.split(';').map(v => v.trim());
226
236
  }
227
- export function commaSeparatedList(value) {
237
+ function commaSeparatedList(value) {
228
238
  if (!value)
229
239
  return undefined;
230
240
  return value.split(',').map(v => v.trim());
@@ -244,3 +254,10 @@ function envToBoolean(value) {
244
254
  function envToString(value) {
245
255
  return value ? value.trim() : undefined;
246
256
  }
257
+ function sanitizeForFilePath(s) {
258
+ const sanitize = (s) => s.replace(/[\x00-\x2C\x2E-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+/g, '-');
259
+ const separator = s.lastIndexOf('.');
260
+ if (separator === -1)
261
+ return sanitize(s);
262
+ return sanitize(s.substring(0, separator)) + '.' + sanitize(s.substring(separator + 1));
263
+ }
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /**
2
3
  * Copyright (c) Microsoft Corporation.
3
4
  *
@@ -13,26 +14,20 @@
13
14
  * See the License for the specific language governing permissions and
14
15
  * limitations under the License.
15
16
  */
16
- import debug from 'debug';
17
- import { logUnhandledError } from './utils/log.js';
18
- import { Tab } from './tab.js';
19
- import { outputFile } from './config.js';
20
- const testDebug = debug('pw:mcp:test');
21
- export class Context {
22
- tools;
23
- config;
24
- sessionLog;
25
- options;
26
- _browserContextPromise;
27
- _browserContextFactory;
28
- _tabs = [];
29
- _currentTab;
30
- _clientInfo;
31
- static _allContexts = new Set();
32
- _closeBrowserContextPromise;
33
- _runningToolName;
34
- _abortController = new AbortController();
17
+ var __importDefault = (this && this.__importDefault) || function (mod) {
18
+ return (mod && mod.__esModule) ? mod : { "default": mod };
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.InputRecorder = exports.Context = void 0;
22
+ const debug_1 = __importDefault(require("debug"));
23
+ const log_1 = require("../log");
24
+ const tab_1 = require("./tab");
25
+ const config_1 = require("./config");
26
+ const testDebug = (0, debug_1.default)('pw:mcp:test');
27
+ class Context {
35
28
  constructor(options) {
29
+ this._tabs = [];
30
+ this._abortController = new AbortController();
36
31
  this.tools = options.tools;
37
32
  this.config = options.config;
38
33
  this.sessionLog = options.sessionLog;
@@ -85,10 +80,10 @@ export class Context {
85
80
  return url;
86
81
  }
87
82
  async outputFile(name) {
88
- return outputFile(this.config, this._clientInfo.rootPath, name);
83
+ return (0, config_1.outputFile)(this.config, this._clientInfo.rootPath, name);
89
84
  }
90
85
  _onPageCreated(page) {
91
- const tab = new Tab(this, page, tab => this._onPageClosed(tab));
86
+ const tab = new tab_1.Tab(this, page, tab => this._onPageClosed(tab));
92
87
  this._tabs.push(tab);
93
88
  if (!this._currentTab)
94
89
  this._currentTab = tab;
@@ -105,7 +100,7 @@ export class Context {
105
100
  }
106
101
  async closeBrowserContext() {
107
102
  if (!this._closeBrowserContextPromise)
108
- this._closeBrowserContextPromise = this._closeBrowserContextImpl().catch(logUnhandledError);
103
+ this._closeBrowserContextPromise = this._closeBrowserContextImpl().catch(log_1.logUnhandledError);
109
104
  await this._closeBrowserContextPromise;
110
105
  this._closeBrowserContextPromise = undefined;
111
106
  }
@@ -133,12 +128,13 @@ export class Context {
133
128
  Context._allContexts.delete(this);
134
129
  }
135
130
  async _setupRequestInterception(context) {
136
- if (this.config.network?.allowedOrigins?.length) {
131
+ var _a, _b, _c, _d;
132
+ if ((_b = (_a = this.config.network) === null || _a === void 0 ? void 0 : _a.allowedOrigins) === null || _b === void 0 ? void 0 : _b.length) {
137
133
  await context.route('**', route => route.abort('blockedbyclient'));
138
134
  for (const origin of this.config.network.allowedOrigins)
139
135
  await context.route(`*://${origin}/**`, route => route.continue());
140
136
  }
141
- if (this.config.network?.blockedOrigins?.length) {
137
+ if ((_d = (_c = this.config.network) === null || _c === void 0 ? void 0 : _c.blockedOrigins) === null || _d === void 0 ? void 0 : _d.length) {
142
138
  for (const origin of this.config.network.blockedOrigins)
143
139
  await context.route(`*://${origin}/**`, route => route.abort('blockedbyclient'));
144
140
  }
@@ -175,9 +171,9 @@ export class Context {
175
171
  return result;
176
172
  }
177
173
  }
178
- export class InputRecorder {
179
- _context;
180
- _browserContext;
174
+ exports.Context = Context;
175
+ Context._allContexts = new Set();
176
+ class InputRecorder {
181
177
  constructor(context, browserContext) {
182
178
  this._context = context;
183
179
  this._browserContext = browserContext;
@@ -196,14 +192,14 @@ export class InputRecorder {
196
192
  actionAdded: (page, data, code) => {
197
193
  if (this._context.isRunningTool())
198
194
  return;
199
- const tab = Tab.forPage(page);
195
+ const tab = tab_1.Tab.forPage(page);
200
196
  if (tab)
201
197
  sessionLog.logUserAction(data.action, tab, code, false);
202
198
  },
203
199
  actionUpdated: (page, data, code) => {
204
200
  if (this._context.isRunningTool())
205
201
  return;
206
- const tab = Tab.forPage(page);
202
+ const tab = tab_1.Tab.forPage(page);
207
203
  if (tab)
208
204
  sessionLog.logUserAction(data.action, tab, code, true);
209
205
  },
@@ -212,7 +208,7 @@ export class InputRecorder {
212
208
  return;
213
209
  if (data.signal.name !== 'navigation')
214
210
  return;
215
- const tab = Tab.forPage(page);
211
+ const tab = tab_1.Tab.forPage(page);
216
212
  const navigateAction = {
217
213
  name: 'navigate',
218
214
  url: data.signal.url,
@@ -224,3 +220,4 @@ export class InputRecorder {
224
220
  });
225
221
  }
226
222
  }
223
+ exports.InputRecorder = InputRecorder;