playwright 1.57.0-alpha-2025-10-16 → 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.
- package/lib/agents/generateAgents.js +210 -177
- package/lib/agents/generator.md +2 -3
- package/lib/agents/healer.md +3 -4
- package/lib/agents/planner.md +2 -3
- package/lib/program.js +6 -4
- package/package.json +2 -2
|
@@ -28,9 +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 generateAgents_exports = {};
|
|
30
30
|
__export(generateAgents_exports, {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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"));
|
|
@@ -39,11 +40,15 @@ var import_utilsBundle = require("playwright-core/lib/utilsBundle");
|
|
|
39
40
|
var import_utils = require("playwright-core/lib/utils");
|
|
40
41
|
var import_seed = require("../mcp/test/seed");
|
|
41
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
|
+
}
|
|
42
47
|
static async parseFile(filePath) {
|
|
43
|
-
const
|
|
44
|
-
const { header, content } = this.extractYamlAndContent(
|
|
48
|
+
const source = await import_fs.default.promises.readFile(filePath, "utf-8");
|
|
49
|
+
const { header, content } = this.extractYamlAndContent(source);
|
|
45
50
|
const { instructions, examples } = this.extractInstructionsAndExamples(content);
|
|
46
|
-
return { header, instructions, examples };
|
|
51
|
+
return { source, header, instructions, examples };
|
|
47
52
|
}
|
|
48
53
|
static extractYamlAndContent(markdown) {
|
|
49
54
|
const lines = markdown.split("\n");
|
|
@@ -86,85 +91,206 @@ class AgentParser {
|
|
|
86
91
|
return { instructions, examples };
|
|
87
92
|
}
|
|
88
93
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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();
|
|
101
110
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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");
|
|
109
135
|
}
|
|
110
|
-
const lines = [];
|
|
111
|
-
lines.push(`---`);
|
|
112
|
-
lines.push(`name: playwright-test-${agent.header.name}`);
|
|
113
|
-
lines.push(`description: ${agent.header.description}. Examples: ${agent.examples.map((example) => `<example>${example}</example>`).join("")}`);
|
|
114
|
-
lines.push(`tools: ${agent.header.tools.map((tool) => asClaudeTool(tool)).join(", ")}`);
|
|
115
|
-
lines.push(`model: ${agent.header.model}`);
|
|
116
|
-
lines.push(`color: ${agent.header.color}`);
|
|
117
|
-
lines.push(`---`);
|
|
118
|
-
lines.push("");
|
|
119
|
-
lines.push(agent.instructions);
|
|
120
|
-
return lines.join("\n");
|
|
121
136
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
]
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (!second) {
|
|
133
|
-
for (const tool2 of opencodeToolMap.get(first) || [first])
|
|
134
|
-
tools[tool2] = true;
|
|
135
|
-
} else {
|
|
136
|
-
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");
|
|
137
147
|
}
|
|
148
|
+
await writeFile("opencode.json", OpencodeGenerator.configuration(agents), "\u{1F527}", "opencode configuration");
|
|
149
|
+
initRepoDone();
|
|
138
150
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
|
172
|
+
};
|
|
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
|
|
153
189
|
};
|
|
154
|
-
|
|
155
|
-
asOpencodeTool(tools, tool);
|
|
190
|
+
return JSON.stringify(result, null, 2);
|
|
156
191
|
}
|
|
157
|
-
const server = commonMcpServers.playwrightTest;
|
|
158
|
-
result["mcp"]["playwright-test"] = {
|
|
159
|
-
type: server.type,
|
|
160
|
-
command: [server.command, ...server.args],
|
|
161
|
-
enabled: true
|
|
162
|
-
};
|
|
163
|
-
return JSON.stringify(result, null, 2);
|
|
164
192
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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;
|
|
199
|
+
}
|
|
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();
|
|
223
|
+
}
|
|
224
|
+
}
|
|
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");
|
|
293
|
+
}
|
|
168
294
|
}
|
|
169
295
|
async function writeFile(filePath, content, icon, description) {
|
|
170
296
|
console.log(`- ${icon} ${import_path.default.relative(process.cwd(), filePath)} ${import_utilsBundle.colors.dim("- " + description)}`);
|
|
@@ -200,100 +326,6 @@ This is a directory for useful prompts.
|
|
|
200
326
|
function initRepoDone() {
|
|
201
327
|
console.log("\u2705 Done.");
|
|
202
328
|
}
|
|
203
|
-
async function initClaudeCodeRepo(config, projectName) {
|
|
204
|
-
await initRepo(config, projectName);
|
|
205
|
-
const agents = await loadAgents();
|
|
206
|
-
await import_fs.default.promises.mkdir(".claude/agents", { recursive: true });
|
|
207
|
-
for (const agent of agents)
|
|
208
|
-
await writeFile(`.claude/agents/playwright-test-${agent.header.name}.md`, saveAsClaudeCode(agent), "\u{1F916}", "agent definition");
|
|
209
|
-
await writeFile(".mcp.json", JSON.stringify({
|
|
210
|
-
mcpServers: {
|
|
211
|
-
"playwright-test": {
|
|
212
|
-
command: commonMcpServers.playwrightTest.command,
|
|
213
|
-
args: commonMcpServers.playwrightTest.args
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}, null, 2), "\u{1F527}", "mcp configuration");
|
|
217
|
-
initRepoDone();
|
|
218
|
-
}
|
|
219
|
-
const vscodeToolMap = /* @__PURE__ */ new Map([
|
|
220
|
-
["ls", ["search/listDirectory", "search/fileSearch"]],
|
|
221
|
-
["grep", ["search/textSearch"]],
|
|
222
|
-
["read", ["search/readFile"]],
|
|
223
|
-
["edit", ["edit/editFiles"]],
|
|
224
|
-
["write", ["edit/createFile", "edit/createDirectory"]]
|
|
225
|
-
]);
|
|
226
|
-
const vscodeToolsOrder = ["edit/createFile", "edit/createDirectory", "edit/editFiles", "search/fileSearch", "search/textSearch", "search/listDirectory", "search/readFile"];
|
|
227
|
-
const vscodeMcpName = "playwright-test";
|
|
228
|
-
function saveAsVSCodeChatmode(agent) {
|
|
229
|
-
function asVscodeTool(tool) {
|
|
230
|
-
const [first, second] = tool.split("/");
|
|
231
|
-
if (second)
|
|
232
|
-
return `${vscodeMcpName}/${second}`;
|
|
233
|
-
return vscodeToolMap.get(first) || first;
|
|
234
|
-
}
|
|
235
|
-
const tools = agent.header.tools.map(asVscodeTool).flat().sort((a, b) => {
|
|
236
|
-
const indexA = vscodeToolsOrder.indexOf(a);
|
|
237
|
-
const indexB = vscodeToolsOrder.indexOf(b);
|
|
238
|
-
if (indexA === -1 && indexB === -1)
|
|
239
|
-
return a.localeCompare(b);
|
|
240
|
-
if (indexA === -1)
|
|
241
|
-
return 1;
|
|
242
|
-
if (indexB === -1)
|
|
243
|
-
return -1;
|
|
244
|
-
return indexA - indexB;
|
|
245
|
-
}).map((tool) => `'${tool}'`).join(", ");
|
|
246
|
-
const lines = [];
|
|
247
|
-
lines.push(`---`);
|
|
248
|
-
lines.push(`description: ${agent.header.description}.`);
|
|
249
|
-
lines.push(`tools: [${tools}]`);
|
|
250
|
-
lines.push(`---`);
|
|
251
|
-
lines.push("");
|
|
252
|
-
lines.push(agent.instructions);
|
|
253
|
-
for (const example of agent.examples)
|
|
254
|
-
lines.push(`<example>${example}</example>`);
|
|
255
|
-
return lines.join("\n");
|
|
256
|
-
}
|
|
257
|
-
async function initVSCodeRepo(config, projectName) {
|
|
258
|
-
await initRepo(config, projectName);
|
|
259
|
-
const agents = await loadAgents();
|
|
260
|
-
await import_fs.default.promises.mkdir(".github/chatmodes", { recursive: true });
|
|
261
|
-
for (const agent of agents)
|
|
262
|
-
await writeFile(`.github/chatmodes/${agent.header.name === "planner" ? " " : ""}\u{1F3AD} ${agent.header.name}.chatmode.md`, saveAsVSCodeChatmode(agent), "\u{1F916}", "chatmode definition");
|
|
263
|
-
await import_fs.default.promises.mkdir(".vscode", { recursive: true });
|
|
264
|
-
const mcpJsonPath = ".vscode/mcp.json";
|
|
265
|
-
let mcpJson = {
|
|
266
|
-
servers: {},
|
|
267
|
-
inputs: []
|
|
268
|
-
};
|
|
269
|
-
try {
|
|
270
|
-
mcpJson = JSON.parse(import_fs.default.readFileSync(mcpJsonPath, "utf8"));
|
|
271
|
-
} catch {
|
|
272
|
-
}
|
|
273
|
-
if (!mcpJson.servers)
|
|
274
|
-
mcpJson.servers = {};
|
|
275
|
-
mcpJson.servers["playwright-test"] = {
|
|
276
|
-
type: "stdio",
|
|
277
|
-
command: commonMcpServers.playwrightTest.command,
|
|
278
|
-
args: commonMcpServers.playwrightTest.args,
|
|
279
|
-
cwd: "${workspaceFolder}"
|
|
280
|
-
};
|
|
281
|
-
await writeFile(mcpJsonPath, JSON.stringify(mcpJson, null, 2), "\u{1F527}", "mcp configuration");
|
|
282
|
-
initRepoDone();
|
|
283
|
-
}
|
|
284
|
-
async function initOpencodeRepo(config, projectName) {
|
|
285
|
-
await initRepo(config, projectName);
|
|
286
|
-
const agents = await loadAgents();
|
|
287
|
-
await import_fs.default.promises.mkdir(".opencode/prompts", { recursive: true });
|
|
288
|
-
for (const agent of agents) {
|
|
289
|
-
const prompt = [agent.instructions];
|
|
290
|
-
prompt.push("");
|
|
291
|
-
prompt.push(...agent.examples.map((example) => `<example>${example}</example>`));
|
|
292
|
-
await writeFile(`.opencode/prompts/playwright-test-${agent.header.name}.md`, prompt.join("\n"), "\u{1F916}", "agent definition");
|
|
293
|
-
}
|
|
294
|
-
await writeFile("opencode.json", saveAsOpencodeJson(agents), "\u{1F527}", "opencode configuration");
|
|
295
|
-
initRepoDone();
|
|
296
|
-
}
|
|
297
329
|
const coveragePrompt = (seedFile) => `
|
|
298
330
|
# Produce test coverage
|
|
299
331
|
|
|
@@ -302,7 +334,7 @@ Parameters:
|
|
|
302
334
|
- Seed file (optional): the seed file to use, defaults to ${import_path.default.relative(process.cwd(), seedFile)}
|
|
303
335
|
- Test plan file (optional): the test plan file to write, under specs/ folder.
|
|
304
336
|
|
|
305
|
-
1. Call #planner subagent with prompt:
|
|
337
|
+
1. Call #playwright-test-planner subagent with prompt:
|
|
306
338
|
|
|
307
339
|
<plan>
|
|
308
340
|
<task><!-- the task --></task>
|
|
@@ -310,7 +342,7 @@ Parameters:
|
|
|
310
342
|
<plan-file><!-- test plan file --></plan-file>
|
|
311
343
|
</plan>
|
|
312
344
|
|
|
313
|
-
2. For each test case from the test plan file (1.1, 1.2, ...), Call #generator subagent with prompt:
|
|
345
|
+
2. For each test case from the test plan file (1.1, 1.2, ...), Call #playwright-test-generator subagent with prompt:
|
|
314
346
|
|
|
315
347
|
<generate>
|
|
316
348
|
<test-file><!-- Name of the file to save the test into, should be unique for test --></test-file>
|
|
@@ -320,13 +352,14 @@ Parameters:
|
|
|
320
352
|
<body><!-- Test case content including steps and expectations --></body>
|
|
321
353
|
</generate>
|
|
322
354
|
|
|
323
|
-
3. Call #healer subagent with prompt:
|
|
355
|
+
3. Call #playwright-test-healer subagent with prompt:
|
|
324
356
|
|
|
325
357
|
<heal>Run all tests and fix the failing ones one after another.</heal>
|
|
326
358
|
`;
|
|
327
359
|
// Annotate the CommonJS export names for ESM import in node:
|
|
328
360
|
0 && (module.exports = {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
361
|
+
AgentGenerator,
|
|
362
|
+
ClaudeGenerator,
|
|
363
|
+
OpencodeGenerator,
|
|
364
|
+
VSCodeGenerator
|
|
332
365
|
});
|
package/lib/agents/generator.md
CHANGED
|
@@ -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
|
package/lib/agents/healer.md
CHANGED
|
@@ -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
|
package/lib/agents/planner.md
CHANGED
|
@@ -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
|
package/lib/program.js
CHANGED
|
@@ -179,18 +179,20 @@ function addInitAgentsCommand(program3) {
|
|
|
179
179
|
const command = program3.command("init-agents");
|
|
180
180
|
command.description("Initialize repository agents");
|
|
181
181
|
const option = command.createOption("--loop <loop>", "Agentic loop provider");
|
|
182
|
-
option.choices(["vscode", "claude", "opencode"]);
|
|
182
|
+
option.choices(["vscode", "claude", "opencode", "generic"]);
|
|
183
183
|
command.addOption(option);
|
|
184
184
|
command.option("-c, --config <file>", `Configuration file to find a project to use for seed test`);
|
|
185
185
|
command.option("--project <project>", "Project to use for seed test");
|
|
186
186
|
command.action(async (opts) => {
|
|
187
187
|
const config = await (0, import_configLoader.loadConfigFromFile)(opts.config);
|
|
188
188
|
if (opts.loop === "opencode") {
|
|
189
|
-
await
|
|
189
|
+
await import_generateAgents.OpencodeGenerator.init(config, opts.project);
|
|
190
190
|
} else if (opts.loop === "vscode") {
|
|
191
|
-
await
|
|
191
|
+
await import_generateAgents.VSCodeGenerator.init(config, opts.project);
|
|
192
192
|
} else if (opts.loop === "claude") {
|
|
193
|
-
await
|
|
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;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "playwright",
|
|
3
|
-
"version": "1.57.0-alpha-2025-10-
|
|
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-
|
|
67
|
+
"playwright-core": "1.57.0-alpha-2025-10-17"
|
|
68
68
|
},
|
|
69
69
|
"optionalDependencies": {
|
|
70
70
|
"fsevents": "2.3.2"
|