playwright 1.57.0-alpha-2025-10-15 → 1.57.0-alpha-2025-10-17

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.
@@ -28,20 +28,27 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var generateAgents_exports = {};
30
30
  __export(generateAgents_exports, {
31
- initClaudeCodeRepo: () => initClaudeCodeRepo,
32
- initOpencodeRepo: () => initOpencodeRepo,
33
- initVSCodeRepo: () => initVSCodeRepo
31
+ AgentGenerator: () => AgentGenerator,
32
+ ClaudeGenerator: () => ClaudeGenerator,
33
+ OpencodeGenerator: () => OpencodeGenerator,
34
+ VSCodeGenerator: () => VSCodeGenerator
34
35
  });
35
36
  module.exports = __toCommonJS(generateAgents_exports);
36
37
  var import_fs = __toESM(require("fs"));
37
38
  var import_path = __toESM(require("path"));
38
39
  var import_utilsBundle = require("playwright-core/lib/utilsBundle");
40
+ var import_utils = require("playwright-core/lib/utils");
41
+ var import_seed = require("../mcp/test/seed");
39
42
  class AgentParser {
43
+ static async loadAgents() {
44
+ const files = await import_fs.default.promises.readdir(__dirname);
45
+ return Promise.all(files.filter((file) => file.endsWith(".md")).map((file) => AgentParser.parseFile(import_path.default.join(__dirname, file))));
46
+ }
40
47
  static async parseFile(filePath) {
41
- const rawMarkdown = await import_fs.default.promises.readFile(filePath, "utf-8");
42
- const { header, content } = this.extractYamlAndContent(rawMarkdown);
48
+ const source = await import_fs.default.promises.readFile(filePath, "utf-8");
49
+ const { header, content } = this.extractYamlAndContent(source);
43
50
  const { instructions, examples } = this.extractInstructionsAndExamples(content);
44
- return { header, instructions, examples };
51
+ return { source, header, instructions, examples };
45
52
  }
46
53
  static extractYamlAndContent(markdown) {
47
54
  const lines = markdown.split("\n");
@@ -84,182 +91,275 @@ class AgentParser {
84
91
  return { instructions, examples };
85
92
  }
86
93
  }
87
- const claudeToolMap = /* @__PURE__ */ new Map([
88
- ["ls", ["Glob"]],
89
- ["grep", ["Grep"]],
90
- ["read", ["Read"]],
91
- ["edit", ["Edit", "MultiEdit"]],
92
- ["write", ["Write"]]
93
- ]);
94
- const commonMcpServers = {
95
- playwrightTest: {
96
- type: "local",
97
- command: "npx",
98
- args: ["playwright", "run-test-mcp-server"]
94
+ class ClaudeGenerator {
95
+ static async init(config, projectName) {
96
+ await initRepo(config, projectName);
97
+ const agents = await AgentParser.loadAgents();
98
+ await import_fs.default.promises.mkdir(".claude/agents", { recursive: true });
99
+ for (const agent of agents)
100
+ await writeFile(`.claude/agents/${agent.header.name}.md`, ClaudeGenerator.agentSpec(agent), "\u{1F916}", "agent definition");
101
+ await writeFile(".mcp.json", JSON.stringify({
102
+ mcpServers: {
103
+ "playwright-test": {
104
+ command: "npx",
105
+ args: ["playwright", "run-test-mcp-server"]
106
+ }
107
+ }
108
+ }, null, 2), "\u{1F527}", "mcp configuration");
109
+ initRepoDone();
99
110
  }
100
- };
101
- function saveAsClaudeCode(agent) {
102
- function asClaudeTool(tool) {
103
- const [first, second] = tool.split("/");
104
- if (!second)
105
- return (claudeToolMap.get(first) || [first]).join(", ");
106
- return `mcp__${first}__${second}`;
111
+ static agentSpec(agent) {
112
+ const claudeToolMap = /* @__PURE__ */ new Map([
113
+ ["search", ["Glob", "Grep"]],
114
+ ["read", ["Read"]],
115
+ ["edit", ["Edit", "MultiEdit"]],
116
+ ["write", ["Write"]]
117
+ ]);
118
+ function asClaudeTool(tool) {
119
+ const [first, second] = tool.split("/");
120
+ if (!second)
121
+ return (claudeToolMap.get(first) || [first]).join(", ");
122
+ return `mcp__${first}__${second}`;
123
+ }
124
+ const lines = [];
125
+ lines.push(`---`);
126
+ lines.push(`name: ${agent.header.name}`);
127
+ lines.push(`description: ${agent.header.description}. Examples: ${agent.examples.map((example) => `<example>${example}</example>`).join("")}`);
128
+ lines.push(`tools: ${agent.header.tools.map((tool) => asClaudeTool(tool)).join(", ")}`);
129
+ lines.push(`model: ${agent.header.model}`);
130
+ lines.push(`color: ${agent.header.color}`);
131
+ lines.push(`---`);
132
+ lines.push("");
133
+ lines.push(agent.instructions);
134
+ return lines.join("\n");
107
135
  }
108
- const lines = [];
109
- lines.push(`---`);
110
- lines.push(`name: playwright-test-${agent.header.name}`);
111
- lines.push(`description: ${agent.header.description}. Examples: ${agent.examples.map((example) => `<example>${example}</example>`).join("")}`);
112
- lines.push(`tools: ${agent.header.tools.map((tool) => asClaudeTool(tool)).join(", ")}`);
113
- lines.push(`model: ${agent.header.model}`);
114
- lines.push(`color: ${agent.header.color}`);
115
- lines.push(`---`);
116
- lines.push("");
117
- lines.push(agent.instructions);
118
- return lines.join("\n");
119
136
  }
120
- const opencodeToolMap = /* @__PURE__ */ new Map([
121
- ["ls", ["ls", "glob"]],
122
- ["grep", ["grep"]],
123
- ["read", ["read"]],
124
- ["edit", ["edit"]],
125
- ["write", ["write"]]
126
- ]);
127
- function saveAsOpencodeJson(agents) {
128
- function asOpencodeTool(tools, tool) {
129
- const [first, second] = tool.split("/");
130
- if (!second) {
131
- for (const tool2 of opencodeToolMap.get(first) || [first])
132
- tools[tool2] = true;
133
- } else {
134
- tools[`${first}*${second}`] = true;
137
+ class OpencodeGenerator {
138
+ static async init(config, projectName) {
139
+ await initRepo(config, projectName);
140
+ const agents = await AgentParser.loadAgents();
141
+ await import_fs.default.promises.mkdir(".opencode/prompts", { recursive: true });
142
+ for (const agent of agents) {
143
+ const prompt = [agent.instructions];
144
+ prompt.push("");
145
+ prompt.push(...agent.examples.map((example) => `<example>${example}</example>`));
146
+ await writeFile(`.opencode/prompts/${agent.header.name}.md`, prompt.join("\n"), "\u{1F916}", "agent definition");
135
147
  }
148
+ await writeFile("opencode.json", OpencodeGenerator.configuration(agents), "\u{1F527}", "opencode configuration");
149
+ initRepoDone();
136
150
  }
137
- const result = {};
138
- result["$schema"] = "https://opencode.ai/config.json";
139
- result["mcp"] = {};
140
- result["tools"] = {
141
- "playwright*": false
142
- };
143
- result["agent"] = {};
144
- for (const agent of agents) {
145
- const tools = {};
146
- result["agent"]["playwright-test-" + agent.header.name] = {
147
- description: agent.header.description,
148
- mode: "subagent",
149
- prompt: `{file:.opencode/prompts/playwright-test-${agent.header.name}.md}`,
150
- tools
151
+ static configuration(agents) {
152
+ const opencodeToolMap = /* @__PURE__ */ new Map([
153
+ ["search", ["ls", "glob", "grep"]],
154
+ ["read", ["read"]],
155
+ ["edit", ["edit"]],
156
+ ["write", ["write"]]
157
+ ]);
158
+ const asOpencodeTool = (tools, tool) => {
159
+ const [first, second] = tool.split("/");
160
+ if (!second) {
161
+ for (const tool2 of opencodeToolMap.get(first) || [first])
162
+ tools[tool2] = true;
163
+ } else {
164
+ tools[`${first}*${second}`] = true;
165
+ }
166
+ };
167
+ const result = {};
168
+ result["$schema"] = "https://opencode.ai/config.json";
169
+ result["mcp"] = {};
170
+ result["tools"] = {
171
+ "playwright*": false
151
172
  };
152
- for (const tool of agent.header.tools)
153
- asOpencodeTool(tools, tool);
173
+ result["agent"] = {};
174
+ for (const agent of agents) {
175
+ const tools = {};
176
+ result["agent"][agent.header.name] = {
177
+ description: agent.header.description,
178
+ mode: "subagent",
179
+ prompt: `{file:.opencode/prompts/${agent.header.name}.md}`,
180
+ tools
181
+ };
182
+ for (const tool of agent.header.tools)
183
+ asOpencodeTool(tools, tool);
184
+ }
185
+ result["mcp"]["playwright-test"] = {
186
+ type: "local",
187
+ command: ["npx", "playwright", "run-test-mcp-server"],
188
+ enabled: true
189
+ };
190
+ return JSON.stringify(result, null, 2);
154
191
  }
155
- const server = commonMcpServers.playwrightTest;
156
- result["mcp"]["playwright-test"] = {
157
- type: server.type,
158
- command: [server.command, ...server.args],
159
- enabled: true
160
- };
161
- return JSON.stringify(result, null, 2);
162
- }
163
- async function loadAgents() {
164
- const files = await import_fs.default.promises.readdir(__dirname);
165
- return Promise.all(files.filter((file) => file.endsWith(".md")).map((file) => AgentParser.parseFile(import_path.default.join(__dirname, file))));
166
- }
167
- async function writeFile(filePath, content) {
168
- console.log(`Writing file: ${filePath}`);
169
- await import_fs.default.promises.writeFile(filePath, content, "utf-8");
170
192
  }
171
- async function initClaudeCodeRepo() {
172
- const agents = await loadAgents();
173
- await import_fs.default.promises.mkdir(".claude/agents", { recursive: true });
174
- for (const agent of agents)
175
- await writeFile(`.claude/agents/playwright-test-${agent.header.name}.md`, saveAsClaudeCode(agent));
176
- await writeFile(".mcp.json", JSON.stringify({
177
- mcpServers: {
178
- "playwright-test": {
179
- command: commonMcpServers.playwrightTest.command,
180
- args: commonMcpServers.playwrightTest.args
181
- }
193
+ class AgentGenerator {
194
+ static async init(config, projectName) {
195
+ const agentsFolder = process.env.AGENTS_FOLDER;
196
+ if (!agentsFolder) {
197
+ console.error("AGENTS_FOLDER environment variable is not set");
198
+ return;
182
199
  }
183
- }, null, 2));
184
- }
185
- const vscodeToolMap = /* @__PURE__ */ new Map([
186
- ["ls", ["search/listDirectory", "search/fileSearch"]],
187
- ["grep", ["search/textSearch"]],
188
- ["read", ["search/readFile"]],
189
- ["edit", ["edit/editFiles"]],
190
- ["write", ["edit/createFile", "edit/createDirectory"]]
191
- ]);
192
- const vscodeToolsOrder = ["edit/createFile", "edit/createDirectory", "edit/editFiles", "search/fileSearch", "search/textSearch", "search/listDirectory", "search/readFile"];
193
- const vscodeMcpName = "playwright-test";
194
- function saveAsVSCodeChatmode(agent) {
195
- function asVscodeTool(tool) {
196
- const [first, second] = tool.split("/");
197
- if (second)
198
- return `${vscodeMcpName}/${second}`;
199
- return vscodeToolMap.get(first) || first;
200
+ await initRepo(config, projectName);
201
+ const agents = await AgentParser.loadAgents();
202
+ await import_fs.default.promises.mkdir(agentsFolder, { recursive: true });
203
+ for (const agent of agents)
204
+ await writeFile(`${agentsFolder}/${agent.header.name}.md`, agent.source, "\u{1F916}", "agent definition");
205
+ console.log("\u{1F527} MCP configuration");
206
+ console.log(JSON.stringify({
207
+ mcpServers: {
208
+ "playwright-test": {
209
+ type: "stdio",
210
+ command: "npx",
211
+ args: [
212
+ `--prefix=${import_path.default.resolve(process.cwd())}`,
213
+ "playwright",
214
+ "run-test-mcp-server",
215
+ `--headless`,
216
+ `--config=${import_path.default.resolve(process.cwd())}`
217
+ ],
218
+ tools: ["*"]
219
+ }
220
+ }
221
+ }, null, 2));
222
+ initRepoDone();
200
223
  }
201
- const tools = agent.header.tools.map(asVscodeTool).flat().sort((a, b) => {
202
- const indexA = vscodeToolsOrder.indexOf(a);
203
- const indexB = vscodeToolsOrder.indexOf(b);
204
- if (indexA === -1 && indexB === -1)
205
- return a.localeCompare(b);
206
- if (indexA === -1)
207
- return 1;
208
- if (indexB === -1)
209
- return -1;
210
- return indexA - indexB;
211
- }).map((tool) => `'${tool}'`).join(", ");
212
- const lines = [];
213
- lines.push(`---`);
214
- lines.push(`description: ${agent.header.description}.`);
215
- lines.push(`tools: [${tools}]`);
216
- lines.push(`---`);
217
- lines.push("");
218
- lines.push(agent.instructions);
219
- for (const example of agent.examples)
220
- lines.push(`<example>${example}</example>`);
221
- return lines.join("\n");
222
224
  }
223
- async function initVSCodeRepo() {
224
- const agents = await loadAgents();
225
- await import_fs.default.promises.mkdir(".github/chatmodes", { recursive: true });
226
- for (const agent of agents)
227
- await writeFile(`.github/chatmodes/${agent.header.name === "planner" ? " " : ""}\u{1F3AD} ${agent.header.name}.chatmode.md`, saveAsVSCodeChatmode(agent));
228
- await import_fs.default.promises.mkdir(".vscode", { recursive: true });
229
- const mcpJsonPath = ".vscode/mcp.json";
230
- let mcpJson = {
231
- servers: {},
232
- inputs: []
233
- };
234
- try {
235
- mcpJson = JSON.parse(import_fs.default.readFileSync(mcpJsonPath, "utf8"));
236
- } catch {
225
+ class VSCodeGenerator {
226
+ static async init(config, projectName) {
227
+ await initRepo(config, projectName);
228
+ const agents = await AgentParser.loadAgents();
229
+ const nameMap = /* @__PURE__ */ new Map([
230
+ ["playwright-test-planner", " \u{1F3AD} planner"],
231
+ ["playwright-test-generator", "\u{1F3AD} generator"],
232
+ ["playwright-test-healer", "\u{1F3AD} healer"]
233
+ ]);
234
+ await import_fs.default.promises.mkdir(".github/chatmodes", { recursive: true });
235
+ for (const agent of agents)
236
+ await writeFile(`.github/chatmodes/${nameMap.get(agent.header.name)}.chatmode.md`, VSCodeGenerator.agentSpec(agent), "\u{1F916}", "chatmode definition");
237
+ await import_fs.default.promises.mkdir(".vscode", { recursive: true });
238
+ const mcpJsonPath = ".vscode/mcp.json";
239
+ let mcpJson = {
240
+ servers: {},
241
+ inputs: []
242
+ };
243
+ try {
244
+ mcpJson = JSON.parse(import_fs.default.readFileSync(mcpJsonPath, "utf8"));
245
+ } catch {
246
+ }
247
+ if (!mcpJson.servers)
248
+ mcpJson.servers = {};
249
+ mcpJson.servers["playwright-test"] = {
250
+ type: "stdio",
251
+ command: "npx",
252
+ args: ["playwright", "run-test-mcp-server"]
253
+ };
254
+ await writeFile(mcpJsonPath, JSON.stringify(mcpJson, null, 2), "\u{1F527}", "mcp configuration");
255
+ initRepoDone();
256
+ }
257
+ static agentSpec(agent) {
258
+ const vscodeToolMap = /* @__PURE__ */ new Map([
259
+ ["search", ["search/listDirectory", "search/fileSearch", "search/textSearch"]],
260
+ ["read", ["search/readFile"]],
261
+ ["edit", ["edit/editFiles"]],
262
+ ["write", ["edit/createFile", "edit/createDirectory"]]
263
+ ]);
264
+ const vscodeToolsOrder = ["edit/createFile", "edit/createDirectory", "edit/editFiles", "search/fileSearch", "search/textSearch", "search/listDirectory", "search/readFile"];
265
+ const vscodeMcpName = "playwright-test";
266
+ function asVscodeTool(tool) {
267
+ const [first, second] = tool.split("/");
268
+ if (second)
269
+ return `${vscodeMcpName}/${second}`;
270
+ return vscodeToolMap.get(first) || first;
271
+ }
272
+ const tools = agent.header.tools.map(asVscodeTool).flat().sort((a, b) => {
273
+ const indexA = vscodeToolsOrder.indexOf(a);
274
+ const indexB = vscodeToolsOrder.indexOf(b);
275
+ if (indexA === -1 && indexB === -1)
276
+ return a.localeCompare(b);
277
+ if (indexA === -1)
278
+ return 1;
279
+ if (indexB === -1)
280
+ return -1;
281
+ return indexA - indexB;
282
+ }).map((tool) => `'${tool}'`).join(", ");
283
+ const lines = [];
284
+ lines.push(`---`);
285
+ lines.push(`description: ${agent.header.description}.`);
286
+ lines.push(`tools: [${tools}]`);
287
+ lines.push(`---`);
288
+ lines.push("");
289
+ lines.push(agent.instructions);
290
+ for (const example of agent.examples)
291
+ lines.push(`<example>${example}</example>`);
292
+ return lines.join("\n");
237
293
  }
238
- if (!mcpJson.servers)
239
- mcpJson.servers = {};
240
- mcpJson.servers["playwright-test"] = {
241
- type: "stdio",
242
- command: commonMcpServers.playwrightTest.command,
243
- args: commonMcpServers.playwrightTest.args,
244
- cwd: "${workspaceFolder}"
245
- };
246
- await writeFile(mcpJsonPath, JSON.stringify(mcpJson, null, 2));
247
- console.log(import_utilsBundle.colors.yellow(`${import_utilsBundle.colors.bold("Note:")} Playwright Test Agents require VSCode version 1.105+ or VSCode Insiders`));
248
294
  }
249
- async function initOpencodeRepo() {
250
- const agents = await loadAgents();
251
- await import_fs.default.promises.mkdir(".opencode/prompts", { recursive: true });
252
- for (const agent of agents) {
253
- const prompt = [agent.instructions];
254
- prompt.push("");
255
- prompt.push(...agent.examples.map((example) => `<example>${example}</example>`));
256
- await writeFile(`.opencode/prompts/playwright-test-${agent.header.name}.md`, prompt.join("\n"));
295
+ async function writeFile(filePath, content, icon, description) {
296
+ console.log(`- ${icon} ${import_path.default.relative(process.cwd(), filePath)} ${import_utilsBundle.colors.dim("- " + description)}`);
297
+ await (0, import_utils.mkdirIfNeeded)(filePath);
298
+ await import_fs.default.promises.writeFile(filePath, content, "utf-8");
299
+ }
300
+ async function initRepo(config, projectName) {
301
+ const project = (0, import_seed.seedProject)(config, projectName);
302
+ console.log(`\u{1F3AD} Using project "${project.project.name}" as a primary project`);
303
+ if (!import_fs.default.existsSync("specs")) {
304
+ await import_fs.default.promises.mkdir("specs");
305
+ await writeFile(import_path.default.join("specs", "README.md"), `# Specs
306
+
307
+ This is a directory for test plans.
308
+ `, "\u{1F4DD}", "directory for test plans");
257
309
  }
258
- await writeFile("opencode.json", saveAsOpencodeJson(agents));
310
+ if (!import_fs.default.existsSync("prompts")) {
311
+ await import_fs.default.promises.mkdir("prompts");
312
+ await writeFile(import_path.default.join("prompts", "README.md"), `# Prompts
313
+
314
+ This is a directory for useful prompts.
315
+ `, "\u{1F4DD}", "useful prompts");
316
+ }
317
+ let seedFile = await (0, import_seed.findSeedFile)(project);
318
+ if (!seedFile) {
319
+ seedFile = (0, import_seed.defaultSeedFile)(project);
320
+ await writeFile(seedFile, import_seed.seedFileContent, "\u{1F331}", "default environment seed file");
321
+ }
322
+ const coveragePromptFile = import_path.default.join("prompts", "test-coverage.md");
323
+ if (!import_fs.default.existsSync(coveragePromptFile))
324
+ await writeFile(coveragePromptFile, coveragePrompt(seedFile), "\u{1F4DD}", "test coverage prompt");
325
+ }
326
+ function initRepoDone() {
327
+ console.log("\u2705 Done.");
259
328
  }
329
+ const coveragePrompt = (seedFile) => `
330
+ # Produce test coverage
331
+
332
+ Parameters:
333
+ - Task: the task to perform
334
+ - Seed file (optional): the seed file to use, defaults to ${import_path.default.relative(process.cwd(), seedFile)}
335
+ - Test plan file (optional): the test plan file to write, under specs/ folder.
336
+
337
+ 1. Call #playwright-test-planner subagent with prompt:
338
+
339
+ <plan>
340
+ <task><!-- the task --></task>
341
+ <seed-file><!-- seed file param --></seed-file>
342
+ <plan-file><!-- test plan file --></plan-file>
343
+ </plan>
344
+
345
+ 2. For each test case from the test plan file (1.1, 1.2, ...), Call #playwright-test-generator subagent with prompt:
346
+
347
+ <generate>
348
+ <test-file><!-- Name of the file to save the test into, should be unique for test --></test-file>
349
+ <test-suite><!-- Name of the top level test spec w/o ordinal--></test-suite>
350
+ <test-name><!--Name of the test case without the ordinal --></test-name>
351
+ <seed-file><!-- Seed file from test plan --></seed-file>
352
+ <body><!-- Test case content including steps and expectations --></body>
353
+ </generate>
354
+
355
+ 3. Call #playwright-test-healer subagent with prompt:
356
+
357
+ <heal>Run all tests and fix the failing ones one after another.</heal>
358
+ `;
260
359
  // Annotate the CommonJS export names for ESM import in node:
261
360
  0 && (module.exports = {
262
- initClaudeCodeRepo,
263
- initOpencodeRepo,
264
- initVSCodeRepo
361
+ AgentGenerator,
362
+ ClaudeGenerator,
363
+ OpencodeGenerator,
364
+ VSCodeGenerator
265
365
  });
@@ -1,12 +1,11 @@
1
1
  ---
2
- name: generator
2
+ name: playwright-test-generator
3
3
  description: Use this agent when you need to create automated browser tests using Playwright
4
4
  model: sonnet
5
5
  color: blue
6
6
  tools:
7
- - ls
8
- - grep
9
7
  - read
8
+ - search
10
9
  - playwright-test/browser_click
11
10
  - playwright-test/browser_drag
12
11
  - playwright-test/browser_evaluate
@@ -1,12 +1,11 @@
1
1
  ---
2
- name: healer
2
+ name: playwright-test-healer
3
3
  description: Use this agent when you need to debug and fix failing Playwright tests
4
- color: red
5
4
  model: sonnet
5
+ color: red
6
6
  tools:
7
- - ls
8
- - grep
9
7
  - read
8
+ - search
10
9
  - write
11
10
  - edit
12
11
  - playwright-test/browser_console_messages
@@ -24,8 +23,8 @@ resolving Playwright test failures. Your mission is to systematically identify,
24
23
  broken Playwright tests using a methodical approach.
25
24
 
26
25
  Your workflow:
27
- 1. **Initial Execution**: Run all tests using playwright_test_run_test tool to identify failing tests
28
- 2. **Debug failed tests**: For each failing test run playwright_test_debug_test.
26
+ 1. **Initial Execution**: Run all tests using `test_run` tool to identify failing tests
27
+ 2. **Debug failed tests**: For each failing test run `test_debug`.
29
28
  3. **Error Investigation**: When the test pauses on errors, use available Playwright MCP tools to:
30
29
  - Examine the error details
31
30
  - Capture page snapshot to understand the context
@@ -1,12 +1,11 @@
1
1
  ---
2
- name: planner
2
+ name: playwright-test-planner
3
3
  description: Use this agent when you need to create comprehensive test plan for a web application or website
4
4
  model: sonnet
5
5
  color: green
6
6
  tools:
7
- - ls
8
- - grep
9
7
  - read
8
+ - search
10
9
  - write
11
10
  - playwright-test/browser_click
12
11
  - playwright-test/browser_close
@@ -38,7 +37,7 @@ You will:
38
37
  - Invoke the `planner_setup_page` tool once to set up page before using any other tools
39
38
  - Explore the browser snapshot
40
39
  - Do not take screenshots unless absolutely necessary
41
- - Use browser_* tools to navigate and discover interface
40
+ - Use `browser_*` tools to navigate and discover interface
42
41
  - Thoroughly explore the interface, identifying all interactive elements, forms, navigation paths, and functionality
43
42
 
44
43
  2. **Analyze User Flows**
@@ -61,7 +61,7 @@ const screenshot = (0, import_tool.defineTabTool)({
61
61
  if (params.fullPage && params.ref)
62
62
  throw new Error("fullPage cannot be used with element screenshots.");
63
63
  const fileType = params.type || "png";
64
- const fileName = await tab.context.outputFile(params.filename ?? (0, import_utils2.dateAsFileName)(fileType), { origin: "llm", reason: "Saving screenshot" });
64
+ const fileName = await tab.context.outputFile(params.filename || (0, import_utils2.dateAsFileName)(fileType), { origin: "llm", reason: "Saving screenshot" });
65
65
  const options = {
66
66
  type: fileType,
67
67
  quality: fileType === "png" ? void 0 : 90,
@@ -28,7 +28,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var seed_exports = {};
30
30
  __export(seed_exports, {
31
- ensureSeedTest: () => ensureSeedTest,
31
+ defaultSeedFile: () => defaultSeedFile,
32
+ ensureSeedFile: () => ensureSeedFile,
33
+ findSeedFile: () => findSeedFile,
34
+ seedFileContent: () => seedFileContent,
32
35
  seedProject: () => seedProject
33
36
  });
34
37
  module.exports = __toCommonJS(seed_exports);
@@ -44,29 +47,36 @@ function seedProject(config, projectName) {
44
47
  throw new Error(`Project ${projectName} not found`);
45
48
  return project;
46
49
  }
47
- async function ensureSeedTest(project, logNew) {
50
+ async function findSeedFile(project) {
48
51
  const files = await (0, import_projectUtils.collectFilesForProject)(project);
49
- const seed = files.find((file) => import_path.default.basename(file).includes("seed"));
50
- if (seed)
51
- return seed;
52
+ return files.find((file) => import_path.default.basename(file).includes("seed"));
53
+ }
54
+ function defaultSeedFile(project) {
52
55
  const testDir = project.project.testDir;
53
- const seedFile = import_path.default.resolve(testDir, "seed.spec.ts");
54
- if (logNew) {
55
- console.log(`Writing file: ${import_path.default.relative(process.cwd(), seedFile)}`);
56
- }
57
- await (0, import_utils.mkdirIfNeeded)(seedFile);
58
- await import_fs.default.promises.writeFile(seedFile, `import { test, expect } from '@playwright/test';
56
+ return import_path.default.resolve(testDir, "seed.spec.ts");
57
+ }
58
+ async function ensureSeedFile(project) {
59
+ const seedFile = await findSeedFile(project);
60
+ if (seedFile)
61
+ return seedFile;
62
+ const seedFilePath = defaultSeedFile(project);
63
+ await (0, import_utils.mkdirIfNeeded)(seedFilePath);
64
+ await import_fs.default.promises.writeFile(seedFilePath, seedFileContent);
65
+ return seedFilePath;
66
+ }
67
+ const seedFileContent = `import { test, expect } from '@playwright/test';
59
68
 
60
69
  test.describe('Test group', () => {
61
70
  test('seed', async ({ page }) => {
62
71
  // generate code here.
63
72
  });
64
73
  });
65
- `);
66
- return seedFile;
67
- }
74
+ `;
68
75
  // Annotate the CommonJS export names for ESM import in node:
69
76
  0 && (module.exports = {
70
- ensureSeedTest,
77
+ defaultSeedFile,
78
+ ensureSeedFile,
79
+ findSeedFile,
80
+ seedFileContent,
71
81
  seedProject
72
82
  });
@@ -98,7 +98,7 @@ class TestContext {
98
98
  const config = await testRunner.loadConfig();
99
99
  const project = (0, import_seed.seedProject)(config, projectName);
100
100
  if (!seedFile) {
101
- seedFile = await (0, import_seed.ensureSeedTest)(project, false);
101
+ seedFile = await (0, import_seed.ensureSeedFile)(project);
102
102
  } else {
103
103
  const candidateFiles = [];
104
104
  const testDir = project.project.testDir;
package/lib/program.js CHANGED
@@ -48,7 +48,6 @@ var import_testRunner = require("./runner/testRunner");
48
48
  var import_reporters = require("./runner/reporters");
49
49
  var import_exports = require("./mcp/sdk/exports");
50
50
  var import_testBackend = require("./mcp/test/testBackend");
51
- var import_seed = require("./mcp/test/seed");
52
51
  var import_program3 = require("./mcp/program");
53
52
  var import_watchdog = require("./mcp/browser/watchdog");
54
53
  var import_generateAgents = require("./agents/generateAgents");
@@ -180,24 +179,24 @@ function addInitAgentsCommand(program3) {
180
179
  const command = program3.command("init-agents");
181
180
  command.description("Initialize repository agents");
182
181
  const option = command.createOption("--loop <loop>", "Agentic loop provider");
183
- option.choices(["vscode", "claude", "opencode"]);
182
+ option.choices(["vscode", "claude", "opencode", "generic"]);
184
183
  command.addOption(option);
185
184
  command.option("-c, --config <file>", `Configuration file to find a project to use for seed test`);
186
185
  command.option("--project <project>", "Project to use for seed test");
187
186
  command.action(async (opts) => {
187
+ const config = await (0, import_configLoader.loadConfigFromFile)(opts.config);
188
188
  if (opts.loop === "opencode") {
189
- await (0, import_generateAgents.initOpencodeRepo)();
189
+ await import_generateAgents.OpencodeGenerator.init(config, opts.project);
190
190
  } else if (opts.loop === "vscode") {
191
- await (0, import_generateAgents.initVSCodeRepo)();
191
+ await import_generateAgents.VSCodeGenerator.init(config, opts.project);
192
192
  } else if (opts.loop === "claude") {
193
- await (0, import_generateAgents.initClaudeCodeRepo)();
193
+ await import_generateAgents.ClaudeGenerator.init(config, opts.project);
194
+ } else if (opts.loop === "generic") {
195
+ await import_generateAgents.AgentGenerator.init(config, opts.project);
194
196
  } else {
195
197
  command.help();
196
198
  return;
197
199
  }
198
- const config = await (0, import_configLoader.loadConfigFromFile)(opts.config);
199
- const project = (0, import_seed.seedProject)(config, opts.project);
200
- await (0, import_seed.ensureSeedTest)(project, true);
201
200
  });
202
201
  }
203
202
  async function runTests(args, opts) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playwright",
3
- "version": "1.57.0-alpha-2025-10-15",
3
+ "version": "1.57.0-alpha-2025-10-17",
4
4
  "description": "A high-level API to automate web browsers",
5
5
  "repository": {
6
6
  "type": "git",
@@ -64,7 +64,7 @@
64
64
  },
65
65
  "license": "Apache-2.0",
66
66
  "dependencies": {
67
- "playwright-core": "1.57.0-alpha-2025-10-15"
67
+ "playwright-core": "1.57.0-alpha-2025-10-17"
68
68
  },
69
69
  "optionalDependencies": {
70
70
  "fsevents": "2.3.2"