@cotestdev/mcp_playwright 0.0.52 → 0.0.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/mcp/browser/browserContextFactory.js +1 -3
- package/lib/mcp/program.js +2 -1
- package/lib/mcp/terminal/command.js +2 -2
- package/lib/mcp/terminal/commands.js +21 -10
- package/lib/mcp/terminal/daemon.js +2 -1
- package/lib/mcp/terminal/helpGenerator.js +19 -1
- package/lib/mcp/terminal/program.js +24 -12
- package/lib/mcpBundleImpl/index.js +27 -27
- package/package.json +1 -1
- package/lib/common/config.js +0 -281
- package/lib/common/configLoader.js +0 -344
- package/lib/common/esmLoaderHost.js +0 -104
- package/lib/common/expectBundle.js +0 -43
- package/lib/common/expectBundleImpl.js +0 -407
- package/lib/common/fixtures.js +0 -302
- package/lib/common/globals.js +0 -58
- package/lib/common/ipc.js +0 -60
- package/lib/common/poolBuilder.js +0 -85
- package/lib/common/process.js +0 -132
- package/lib/common/suiteUtils.js +0 -140
- package/lib/common/test.js +0 -322
- package/lib/common/testLoader.js +0 -101
- package/lib/common/testType.js +0 -298
- package/lib/common/validators.js +0 -68
- package/lib/mcp/browser/actions.d.js +0 -16
- package/lib/mcp/browser/codegen.js +0 -66
- package/lib/mcp/browser/processUtils.js +0 -102
- package/lib/mcp/browser/tools/script.js +0 -60
- package/lib/mcp/sdk/bundle.js +0 -75
- package/lib/mcp/sdk/mdb.js +0 -208
- package/lib/mcp/sdk/proxyBackend.js +0 -128
- package/lib/mcp/vscode/host.js +0 -187
- package/lib/mcp/vscode/main.js +0 -77
- package/lib/mcpBundleImpl.js +0 -41
- package/lib/third_party/pirates.js +0 -62
- package/lib/third_party/tsconfig-loader.js +0 -103
- package/lib/transform/babelBundle.js +0 -43
- package/lib/transform/babelBundleImpl.js +0 -461
- package/lib/transform/babelHighlightUtils.js +0 -63
- package/lib/transform/compilationCache.js +0 -272
- package/lib/transform/esmLoader.js +0 -103
- package/lib/transform/portTransport.js +0 -67
- package/lib/transform/transform.js +0 -296
- package/lib/utilsBundleImpl/index.js +0 -218
- package/lib/utilsBundleImpl.js +0 -103
|
@@ -304,9 +304,7 @@ class SharedContextFactory {
|
|
|
304
304
|
}
|
|
305
305
|
}
|
|
306
306
|
async function computeTracesDir(config, clientInfo) {
|
|
307
|
-
|
|
308
|
-
return;
|
|
309
|
-
return await (0, import_config.outputFile)(config, clientInfo, `traces`, { origin: "code" });
|
|
307
|
+
return import_path.default.resolve((0, import_config.outputDir)(config, clientInfo), "traces");
|
|
310
308
|
}
|
|
311
309
|
async function browserContextOptionsFromConfig(config, clientInfo) {
|
|
312
310
|
const result = { ...config.browser.contextOptions };
|
package/lib/mcp/program.js
CHANGED
|
@@ -77,8 +77,9 @@ Please run the command below. It will install a local copy of ffmpeg and will no
|
|
|
77
77
|
Daemon listening on ${socketPath}`);
|
|
78
78
|
console.log("<EOF>");
|
|
79
79
|
} catch (error) {
|
|
80
|
+
const message = process.env.PWDEBUGIMPL ? error.stack || error.message : error.message;
|
|
80
81
|
console.log(`### Error
|
|
81
|
-
${
|
|
82
|
+
${message}`);
|
|
82
83
|
console.log("<EOF>");
|
|
83
84
|
}
|
|
84
85
|
return;
|
|
@@ -56,11 +56,11 @@ function zodParse(schema, data, type) {
|
|
|
56
56
|
const label = type === "option" ? `'--${prop}' option` : `'${prop}' argument`;
|
|
57
57
|
switch (issue.code) {
|
|
58
58
|
case "invalid_type":
|
|
59
|
-
return "error: " + label + ": " + issue.message.
|
|
59
|
+
return "error: " + label + ": " + issue.message.replace(/Invalid input:/, "").trim();
|
|
60
60
|
case "unrecognized_keys":
|
|
61
61
|
return "error: unknown " + label;
|
|
62
62
|
default:
|
|
63
|
-
return "error: " + label + ": " + issue.message
|
|
63
|
+
return "error: " + label + ": " + issue.message;
|
|
64
64
|
}
|
|
65
65
|
});
|
|
66
66
|
}).flat().join("\n"));
|
|
@@ -23,6 +23,17 @@ __export(commands_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(commands_exports);
|
|
24
24
|
var import_mcpBundle = require("../../mcpBundle");
|
|
25
25
|
var import_command = require("./command");
|
|
26
|
+
const numberArg = import_mcpBundle.z.preprocess((val, ctx) => {
|
|
27
|
+
const number = Number(val);
|
|
28
|
+
if (Number.isNaN(number)) {
|
|
29
|
+
ctx.issues.push({
|
|
30
|
+
code: "custom",
|
|
31
|
+
message: `expected number, received '${val}'`,
|
|
32
|
+
input: val
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return number;
|
|
36
|
+
}, import_mcpBundle.z.number());
|
|
26
37
|
const open = (0, import_command.declareCommand)({
|
|
27
38
|
name: "open",
|
|
28
39
|
description: "Open the browser",
|
|
@@ -131,8 +142,8 @@ const mouseMove = (0, import_command.declareCommand)({
|
|
|
131
142
|
description: "Move mouse to a given position",
|
|
132
143
|
category: "mouse",
|
|
133
144
|
args: import_mcpBundle.z.object({
|
|
134
|
-
x:
|
|
135
|
-
y:
|
|
145
|
+
x: numberArg.describe("X coordinate"),
|
|
146
|
+
y: numberArg.describe("Y coordinate")
|
|
136
147
|
}),
|
|
137
148
|
toolName: "browser_mouse_move_xy",
|
|
138
149
|
toolParams: ({ x, y }) => ({ x, y })
|
|
@@ -162,8 +173,8 @@ const mouseWheel = (0, import_command.declareCommand)({
|
|
|
162
173
|
description: "Scroll mouse wheel",
|
|
163
174
|
category: "mouse",
|
|
164
175
|
args: import_mcpBundle.z.object({
|
|
165
|
-
dx:
|
|
166
|
-
dy:
|
|
176
|
+
dx: numberArg.describe("Y delta"),
|
|
177
|
+
dy: numberArg.describe("X delta")
|
|
167
178
|
}),
|
|
168
179
|
toolName: "browser_mouse_wheel",
|
|
169
180
|
toolParams: ({ dx: deltaY, dy: deltaX }) => ({ deltaY, deltaX })
|
|
@@ -317,8 +328,8 @@ const resize = (0, import_command.declareCommand)({
|
|
|
317
328
|
description: "Resize the browser window",
|
|
318
329
|
category: "core",
|
|
319
330
|
args: import_mcpBundle.z.object({
|
|
320
|
-
w:
|
|
321
|
-
h:
|
|
331
|
+
w: numberArg.describe("Width of the browser window"),
|
|
332
|
+
h: numberArg.describe("Height of the browser window")
|
|
322
333
|
}),
|
|
323
334
|
toolName: "browser_resize",
|
|
324
335
|
toolParams: ({ w: width, h: height }) => ({ width, height })
|
|
@@ -356,7 +367,7 @@ const tabClose = (0, import_command.declareCommand)({
|
|
|
356
367
|
description: "Close a browser tab",
|
|
357
368
|
category: "tabs",
|
|
358
369
|
args: import_mcpBundle.z.object({
|
|
359
|
-
index:
|
|
370
|
+
index: numberArg.optional().describe("Tab index. If omitted, current tab is closed.")
|
|
360
371
|
}),
|
|
361
372
|
toolName: "browser_tabs",
|
|
362
373
|
toolParams: ({ index }) => ({ action: "close", index })
|
|
@@ -366,7 +377,7 @@ const tabSelect = (0, import_command.declareCommand)({
|
|
|
366
377
|
description: "Select a browser tab",
|
|
367
378
|
category: "tabs",
|
|
368
379
|
args: import_mcpBundle.z.object({
|
|
369
|
-
index:
|
|
380
|
+
index: numberArg.describe("Tab index")
|
|
370
381
|
}),
|
|
371
382
|
toolName: "browser_tabs",
|
|
372
383
|
toolParams: ({ index }) => ({ action: "select", index })
|
|
@@ -424,7 +435,7 @@ const cookieSet = (0, import_command.declareCommand)({
|
|
|
424
435
|
options: import_mcpBundle.z.object({
|
|
425
436
|
domain: import_mcpBundle.z.string().optional().describe("Cookie domain"),
|
|
426
437
|
path: import_mcpBundle.z.string().optional().describe("Cookie path"),
|
|
427
|
-
expires:
|
|
438
|
+
expires: numberArg.optional().describe("Cookie expiration as Unix timestamp"),
|
|
428
439
|
httpOnly: import_mcpBundle.z.boolean().optional().describe("Whether the cookie is HTTP only"),
|
|
429
440
|
secure: import_mcpBundle.z.boolean().optional().describe("Whether the cookie is secure"),
|
|
430
441
|
sameSite: import_mcpBundle.z.enum(["Strict", "Lax", "None"]).optional().describe("Cookie SameSite attribute")
|
|
@@ -552,7 +563,7 @@ const routeMock = (0, import_command.declareCommand)({
|
|
|
552
563
|
pattern: import_mcpBundle.z.string().describe('URL pattern to match (e.g., "**/api/users")')
|
|
553
564
|
}),
|
|
554
565
|
options: import_mcpBundle.z.object({
|
|
555
|
-
status:
|
|
566
|
+
status: numberArg.optional().describe("HTTP status code (default: 200)"),
|
|
556
567
|
body: import_mcpBundle.z.string().optional().describe("Response body (text or JSON string)"),
|
|
557
568
|
["content-type"]: import_mcpBundle.z.string().optional().describe("Content-Type header"),
|
|
558
569
|
header: import_mcpBundle.z.union([import_mcpBundle.z.string(), import_mcpBundle.z.array(import_mcpBundle.z.string())]).optional().transform((v) => v ? Array.isArray(v) ? v : [v] : void 0).describe('Header to add in "Name: Value" format (repeatable)'),
|
|
@@ -118,7 +118,8 @@ async function startMcpDaemonServer(config, contextFactory) {
|
|
|
118
118
|
}
|
|
119
119
|
} catch (e) {
|
|
120
120
|
daemonDebug("command failed", e);
|
|
121
|
-
|
|
121
|
+
const error = process.env.PWDEBUGIMPL ? e.stack || e.message : e.message;
|
|
122
|
+
await connection.send({ id, error });
|
|
122
123
|
}
|
|
123
124
|
};
|
|
124
125
|
});
|
|
@@ -23,6 +23,7 @@ __export(helpGenerator_exports, {
|
|
|
23
23
|
generateReadme: () => generateReadme
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(helpGenerator_exports);
|
|
26
|
+
var import_mcpBundle = require("../../mcpBundle");
|
|
26
27
|
var import_commands = require("./commands");
|
|
27
28
|
function commandArgs(command) {
|
|
28
29
|
const args = [];
|
|
@@ -134,12 +135,29 @@ function generateReadmeEntry(command) {
|
|
|
134
135
|
const suffix = "# " + command.description.toLowerCase();
|
|
135
136
|
return formatWithGap(prefix, suffix, 40);
|
|
136
137
|
}
|
|
138
|
+
function unwrapZodType(schema) {
|
|
139
|
+
if ("unwrap" in schema && typeof schema.unwrap === "function")
|
|
140
|
+
return unwrapZodType(schema.unwrap());
|
|
141
|
+
return schema;
|
|
142
|
+
}
|
|
137
143
|
function generateHelpJSON() {
|
|
144
|
+
const booleanOptions = /* @__PURE__ */ new Set();
|
|
145
|
+
for (const command of Object.values(import_commands.commands)) {
|
|
146
|
+
if (!command.options)
|
|
147
|
+
continue;
|
|
148
|
+
const optionsShape = command.options.shape;
|
|
149
|
+
for (const [name, schema] of Object.entries(optionsShape)) {
|
|
150
|
+
const innerSchema = unwrapZodType(schema);
|
|
151
|
+
if (innerSchema instanceof import_mcpBundle.z.ZodBoolean)
|
|
152
|
+
booleanOptions.add(name);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
138
155
|
const help = {
|
|
139
156
|
global: generateHelp(),
|
|
140
157
|
commands: Object.fromEntries(
|
|
141
158
|
Object.entries(import_commands.commands).map(([name, command]) => [name, generateCommandHelp(command)])
|
|
142
|
-
)
|
|
159
|
+
),
|
|
160
|
+
booleanOptions: [...booleanOptions]
|
|
143
161
|
};
|
|
144
162
|
return help;
|
|
145
163
|
}
|
|
@@ -56,9 +56,9 @@ class Session {
|
|
|
56
56
|
if (!this.isCompatible()) {
|
|
57
57
|
throw new Error(`Client is v${this._clientInfo.version}, session '${this.name}' is v${this._config.version}. Run
|
|
58
58
|
|
|
59
|
-
playwright-cli
|
|
59
|
+
playwright-cli${this.name !== "default" ? ` -s=${this.name}` : ""} open
|
|
60
60
|
|
|
61
|
-
to restart the session
|
|
61
|
+
to restart the browser session.`);
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
async run(args) {
|
|
@@ -405,17 +405,28 @@ const booleanOptions = [
|
|
|
405
405
|
];
|
|
406
406
|
async function program(packageLocation) {
|
|
407
407
|
const clientInfo = createClientInfo(packageLocation);
|
|
408
|
+
const help = require("./help.json");
|
|
408
409
|
const argv = process.argv.slice(2);
|
|
409
|
-
const
|
|
410
|
-
|
|
410
|
+
const boolean = [...help.booleanOptions, ...booleanOptions];
|
|
411
|
+
const args = require("minimist")(argv, { boolean });
|
|
412
|
+
for (const [key, value] of Object.entries(args)) {
|
|
413
|
+
if (key !== "_" && typeof value !== "boolean")
|
|
414
|
+
args[key] = String(value);
|
|
415
|
+
}
|
|
416
|
+
for (let index = 0; index < args._.length; index++)
|
|
417
|
+
args._[index] = String(args._[index]);
|
|
418
|
+
for (const option of boolean) {
|
|
411
419
|
if (!argv.includes(`--${option}`) && !argv.includes(`--no-${option}`))
|
|
412
420
|
delete args[option];
|
|
421
|
+
if (argv.some((arg) => arg.startsWith(`--${option}=`) || arg.startsWith(`--no-${option}=`))) {
|
|
422
|
+
console.error(`boolean option '--${option}' should not be passed with '=value', use '--${option}' or '--no-${option}' instead`);
|
|
423
|
+
process.exit(1);
|
|
424
|
+
}
|
|
413
425
|
}
|
|
414
426
|
if (args.s) {
|
|
415
427
|
args.session = args.s;
|
|
416
428
|
delete args.s;
|
|
417
429
|
}
|
|
418
|
-
const help = require("./help.json");
|
|
419
430
|
const commandName = args._?.[0];
|
|
420
431
|
if (args.version || args.v) {
|
|
421
432
|
console.log(clientInfo.version);
|
|
@@ -475,16 +486,16 @@ async function install(args) {
|
|
|
475
486
|
const cwd = process.cwd();
|
|
476
487
|
const playwrightDir = import_path.default.join(cwd, ".playwright");
|
|
477
488
|
await import_fs.default.promises.mkdir(playwrightDir, { recursive: true });
|
|
478
|
-
console.log(
|
|
489
|
+
console.log(`\u2705 Workspace initialized at \`${cwd}\`.`);
|
|
479
490
|
if (args.skills) {
|
|
480
491
|
const skillSourceDir = import_path.default.join(__dirname, "../../skill");
|
|
481
492
|
const skillDestDir = import_path.default.join(cwd, ".claude", "skills", "playwright-cli");
|
|
482
493
|
if (!import_fs.default.existsSync(skillSourceDir)) {
|
|
483
|
-
console.error("Skills source directory not found:", skillSourceDir);
|
|
494
|
+
console.error("\u274C Skills source directory not found:", skillSourceDir);
|
|
484
495
|
process.exit(1);
|
|
485
496
|
}
|
|
486
497
|
await import_fs.default.promises.cp(skillSourceDir, skillDestDir, { recursive: true });
|
|
487
|
-
console.log(
|
|
498
|
+
console.log(`\u2705 Skills installed to \`${import_path.default.relative(cwd, skillDestDir)}\`.`);
|
|
488
499
|
}
|
|
489
500
|
if (!args.config)
|
|
490
501
|
await ensureConfiguredBrowserInstalled();
|
|
@@ -516,7 +527,7 @@ async function createDefaultConfig(channel) {
|
|
|
516
527
|
}
|
|
517
528
|
};
|
|
518
529
|
await import_fs.default.promises.writeFile(defaultConfigFile(), JSON.stringify(config, null, 2));
|
|
519
|
-
console.log(
|
|
530
|
+
console.log(`\u2705 Created default config for ${channel} at ${import_path.default.relative(process.cwd(), defaultConfigFile())}.`);
|
|
520
531
|
}
|
|
521
532
|
async function findOrInstallDefaultBrowser() {
|
|
522
533
|
const { registry } = await import("playwright-core/lib/server/registry/index");
|
|
@@ -525,7 +536,7 @@ async function findOrInstallDefaultBrowser() {
|
|
|
525
536
|
const executable = registry.findExecutable(channel);
|
|
526
537
|
if (!executable?.executablePath())
|
|
527
538
|
continue;
|
|
528
|
-
console.log(
|
|
539
|
+
console.log(`\u2705 Found ${channel}, will use it as the default browser.`);
|
|
529
540
|
return channel;
|
|
530
541
|
}
|
|
531
542
|
const chromiumExecutable = registry.findExecutable("chromium");
|
|
@@ -670,9 +681,10 @@ async function renderSessionStatus(session) {
|
|
|
670
681
|
const text = [];
|
|
671
682
|
const config = session.config();
|
|
672
683
|
const canConnect = await session.canConnect();
|
|
673
|
-
const restartMarker = canConnect && !session.isCompatible() ? ` - v${config.version}, please reopen` : "";
|
|
674
684
|
text.push(`- ${session.name}:`);
|
|
675
|
-
text.push(` - status: ${canConnect ? "open" : "closed"}
|
|
685
|
+
text.push(` - status: ${canConnect ? "open" : "closed"}`);
|
|
686
|
+
if (canConnect && !session.isCompatible())
|
|
687
|
+
text.push(` - version: v${config.version} [incompatible please re-open]`);
|
|
676
688
|
if (config.resolvedConfig)
|
|
677
689
|
text.push(...renderResolvedConfig(config.resolvedConfig));
|
|
678
690
|
return text.join("\n");
|