ptywright 0.1.1 → 0.3.0
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/README.md +318 -1
- package/dist/agent.mjs +2 -0
- package/dist/bin/ptywright.mjs +6 -0
- package/dist/cli-CfvlbRoZ.mjs +3585 -0
- package/dist/cli.mjs +2 -0
- package/{src/index.ts → dist/index.mjs} +7 -9
- package/dist/mcp.mjs +2 -0
- package/dist/pty-cassette.mjs +24 -0
- package/dist/pty_like-Cpkh_O9B.mjs +404 -0
- package/dist/runner-zApMYWZx.mjs +3257 -0
- package/dist/runner-zi0nItvB.mjs +1874 -0
- package/dist/script.mjs +2 -0
- package/dist/server-BC3yo-dq.mjs +3068 -0
- package/dist/session.mjs +2 -0
- package/dist/terminal_session-DopC7Xg6.mjs +893 -0
- package/package.json +28 -21
- package/schemas/ptywright-agent-cassette.schema.json +57 -0
- package/schemas/ptywright-agent-check.schema.json +122 -0
- package/schemas/ptywright-agent-manifest.schema.json +107 -0
- package/schemas/ptywright-agent-promote.schema.json +146 -0
- package/schemas/ptywright-agent-replay-summary.schema.json +140 -0
- package/schemas/ptywright-agent-run.schema.json +126 -0
- package/schemas/ptywright-agent.schema.json +166 -0
- package/schemas/ptywright-pty-cassette.schema.json +86 -0
- package/schemas/ptywright-script-manifest.schema.json +75 -0
- package/schemas/ptywright-script-run-summary.schema.json +114 -0
- package/schemas/ptywright-script.schema.json +55 -3
- package/bin/ptywright +0 -4
- package/src/cli.ts +0 -414
- package/src/generator/doc_parser.ts +0 -341
- package/src/generator/generate.ts +0 -161
- package/src/generator/index.ts +0 -10
- package/src/generator/script_generator.ts +0 -209
- package/src/generator/step_extractor.ts +0 -397
- package/src/mcp/http_server.ts +0 -174
- package/src/mcp/script_recording.ts +0 -238
- package/src/mcp/server.ts +0 -1348
- package/src/pty/bun_pty_adapter.ts +0 -34
- package/src/pty/bun_terminal_adapter.ts +0 -149
- package/src/pty/pty_adapter.ts +0 -31
- package/src/script/dsl.ts +0 -188
- package/src/script/module.ts +0 -43
- package/src/script/path.ts +0 -151
- package/src/script/run.ts +0 -108
- package/src/script/run_all.ts +0 -229
- package/src/script/runner.ts +0 -983
- package/src/script/schema.ts +0 -237
- package/src/script/steps/assert_snapshot_equals.ts +0 -21
- package/src/script/steps/index.ts +0 -2
- package/src/script/suite_report.ts +0 -626
- package/src/session/session_manager.ts +0 -145
- package/src/session/terminal_session.ts +0 -473
- package/src/terminal/ansi.ts +0 -142
- package/src/terminal/keys.ts +0 -180
- package/src/terminal/mask.ts +0 -70
- package/src/terminal/mouse.ts +0 -75
- package/src/terminal/snapshot.ts +0 -196
- package/src/terminal/style.ts +0 -121
- package/src/terminal/view.ts +0 -49
- package/src/trace/asciicast.ts +0 -20
- package/src/trace/asciinema_player_assets.ts +0 -44
- package/src/trace/cast_to_txt.ts +0 -116
- package/src/trace/recorder.ts +0 -110
- package/src/trace/report.ts +0 -2092
- package/src/types.ts +0 -86
- package/src/util/hash.ts +0 -8
- package/src/util/sleep.ts +0 -5
package/src/cli.ts
DELETED
|
@@ -1,414 +0,0 @@
|
|
|
1
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
2
|
-
|
|
3
|
-
import type { PtywrightCapability } from "./mcp/server";
|
|
4
|
-
import { createPtywrightServer } from "./mcp/server";
|
|
5
|
-
import { startPtywrightHttpServer } from "./mcp/http_server";
|
|
6
|
-
import { runAllScripts } from "./script/run_all";
|
|
7
|
-
import { runScriptPath } from "./script/path";
|
|
8
|
-
|
|
9
|
-
function usage(): string {
|
|
10
|
-
return [
|
|
11
|
-
"ptywright <command>",
|
|
12
|
-
"",
|
|
13
|
-
"Commands:",
|
|
14
|
-
" mcp Start the MCP server over stdio (default)",
|
|
15
|
-
" mcp-http Start the MCP server over Streamable HTTP",
|
|
16
|
-
" run <file> Run one script (JSON/TS) and write artifacts",
|
|
17
|
-
" run-all [dir] Run all scripts in a directory and write a suite report",
|
|
18
|
-
" help Show help",
|
|
19
|
-
"",
|
|
20
|
-
"Run options:",
|
|
21
|
-
" --artifacts-dir <dir> Override artifacts directory",
|
|
22
|
-
" --steps <module.ts> Inject custom step handlers",
|
|
23
|
-
" --update-goldens Update golden snapshots",
|
|
24
|
-
"",
|
|
25
|
-
"Run-all options:",
|
|
26
|
-
" --dir <dir> Directory to scan (default: scripts)",
|
|
27
|
-
" --artifacts-root <dir> Suite artifacts root (default: .tmp/run-all)",
|
|
28
|
-
" --steps <module.ts> Inject custom step handlers",
|
|
29
|
-
" --update-goldens Update golden snapshots",
|
|
30
|
-
"",
|
|
31
|
-
"MCP options:",
|
|
32
|
-
" --caps <list> Capabilities: all|core|debug|script|recording",
|
|
33
|
-
"",
|
|
34
|
-
"MCP HTTP options (mcp-http):",
|
|
35
|
-
" --host <host> Bind host (default: 127.0.0.1)",
|
|
36
|
-
" --port <port> Bind port (default: 3000)",
|
|
37
|
-
" --allowed-origins <list> Comma/space separated Origin allowlist",
|
|
38
|
-
" --no-cors Disable CORS headers",
|
|
39
|
-
].join("\n");
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function isHelp(arg: string | undefined): boolean {
|
|
43
|
-
return arg === "-h" || arg === "--help" || arg === "help";
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function logLines(lines: Array<string | null | undefined>, stderr: boolean): void {
|
|
47
|
-
const filtered = lines.map((l) => l?.trim()).filter(Boolean) as string[];
|
|
48
|
-
for (const line of filtered) {
|
|
49
|
-
// eslint-disable-next-line no-console
|
|
50
|
-
(stderr ? console.error : console.log)(line);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function parseCaps(value: string): PtywrightCapability[] {
|
|
55
|
-
const parts = value
|
|
56
|
-
.split(/[\s,]+/g)
|
|
57
|
-
.map((p) => p.trim().toLowerCase())
|
|
58
|
-
.filter(Boolean);
|
|
59
|
-
|
|
60
|
-
const out: PtywrightCapability[] = [];
|
|
61
|
-
for (const p of parts) {
|
|
62
|
-
if (p === "all") out.push("all");
|
|
63
|
-
else if (p === "core") out.push("core");
|
|
64
|
-
else if (p === "debug") out.push("debug");
|
|
65
|
-
else if (p === "script" || p === "scripts" || p === "runner" || p === "run") out.push("script");
|
|
66
|
-
else if (p === "recording" || p === "record" || p === "rec") out.push("recording");
|
|
67
|
-
else throw new Error(`unknown capability: ${p}`);
|
|
68
|
-
}
|
|
69
|
-
return out;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function parseRunArgs(argv: string[]): {
|
|
73
|
-
scriptPath: string;
|
|
74
|
-
artifactsDir?: string;
|
|
75
|
-
stepsPath?: string;
|
|
76
|
-
updateGoldens: boolean;
|
|
77
|
-
} {
|
|
78
|
-
const out: {
|
|
79
|
-
scriptPath?: string;
|
|
80
|
-
artifactsDir?: string;
|
|
81
|
-
stepsPath?: string;
|
|
82
|
-
updateGoldens: boolean;
|
|
83
|
-
} = { updateGoldens: false };
|
|
84
|
-
|
|
85
|
-
for (let i = 0; i < argv.length; i += 1) {
|
|
86
|
-
const arg = argv[i];
|
|
87
|
-
const next = argv[i + 1];
|
|
88
|
-
|
|
89
|
-
if (!out.scriptPath && arg && !arg.startsWith("-")) {
|
|
90
|
-
out.scriptPath = arg;
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (arg === "--artifacts-dir" && next) {
|
|
95
|
-
out.artifactsDir = next;
|
|
96
|
-
i += 1;
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (arg === "--steps" && next) {
|
|
101
|
-
out.stepsPath = next;
|
|
102
|
-
i += 1;
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (arg === "--update-goldens") {
|
|
107
|
-
out.updateGoldens = true;
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
throw new Error(`unknown arg: ${arg ?? ""}`);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (!out.scriptPath) {
|
|
115
|
-
throw new Error("missing <file>\n\n" + usage());
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return out as {
|
|
119
|
-
scriptPath: string;
|
|
120
|
-
artifactsDir?: string;
|
|
121
|
-
stepsPath?: string;
|
|
122
|
-
updateGoldens: boolean;
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function parseRunAllArgs(argv: string[]): {
|
|
127
|
-
dir?: string;
|
|
128
|
-
artifactsRoot?: string;
|
|
129
|
-
stepsPath?: string;
|
|
130
|
-
updateGoldens: boolean;
|
|
131
|
-
} {
|
|
132
|
-
const out: {
|
|
133
|
-
dir?: string;
|
|
134
|
-
artifactsRoot?: string;
|
|
135
|
-
stepsPath?: string;
|
|
136
|
-
updateGoldens: boolean;
|
|
137
|
-
} = { updateGoldens: false };
|
|
138
|
-
|
|
139
|
-
for (let i = 0; i < argv.length; i += 1) {
|
|
140
|
-
const arg = argv[i];
|
|
141
|
-
const next = argv[i + 1];
|
|
142
|
-
|
|
143
|
-
if (!out.dir && arg && !arg.startsWith("-")) {
|
|
144
|
-
out.dir = arg;
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (arg === "--dir" && next) {
|
|
149
|
-
out.dir = next;
|
|
150
|
-
i += 1;
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (arg === "--artifacts-root" && next) {
|
|
155
|
-
out.artifactsRoot = next;
|
|
156
|
-
i += 1;
|
|
157
|
-
continue;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (arg === "--steps" && next) {
|
|
161
|
-
out.stepsPath = next;
|
|
162
|
-
i += 1;
|
|
163
|
-
continue;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if (arg === "--update-goldens") {
|
|
167
|
-
out.updateGoldens = true;
|
|
168
|
-
continue;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
throw new Error(`unknown arg: ${arg ?? ""}`);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return out as {
|
|
175
|
-
dir?: string;
|
|
176
|
-
artifactsRoot?: string;
|
|
177
|
-
stepsPath?: string;
|
|
178
|
-
updateGoldens: boolean;
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
async function cmdMcp(argv: string[]): Promise<void> {
|
|
183
|
-
let capabilities: PtywrightCapability[] | undefined;
|
|
184
|
-
|
|
185
|
-
for (let i = 0; i < argv.length; i += 1) {
|
|
186
|
-
const arg = argv[i];
|
|
187
|
-
const next = argv[i + 1];
|
|
188
|
-
|
|
189
|
-
if (isHelp(arg)) {
|
|
190
|
-
// eslint-disable-next-line no-console
|
|
191
|
-
console.log(usage());
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (arg === "--caps" && next) {
|
|
196
|
-
capabilities = parseCaps(next);
|
|
197
|
-
i += 1;
|
|
198
|
-
continue;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
throw new Error(`unknown arg: ${arg ?? ""}`);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
const { server, sessions } = createPtywrightServer({ capabilities });
|
|
205
|
-
const transport = new StdioServerTransport();
|
|
206
|
-
await server.connect(transport);
|
|
207
|
-
|
|
208
|
-
function shutdown(): void {
|
|
209
|
-
sessions.closeAll();
|
|
210
|
-
void server.close();
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
process.on("SIGINT", shutdown);
|
|
214
|
-
process.on("SIGTERM", shutdown);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
async function cmdMcpHttp(argv: string[]): Promise<void> {
|
|
218
|
-
let capabilities: PtywrightCapability[] | undefined;
|
|
219
|
-
let hostname: string | undefined;
|
|
220
|
-
let port: number | undefined;
|
|
221
|
-
let allowedOrigins: string[] | undefined;
|
|
222
|
-
let cors = true;
|
|
223
|
-
|
|
224
|
-
for (let i = 0; i < argv.length; i += 1) {
|
|
225
|
-
const arg = argv[i];
|
|
226
|
-
const next = argv[i + 1];
|
|
227
|
-
|
|
228
|
-
if (isHelp(arg)) {
|
|
229
|
-
// eslint-disable-next-line no-console
|
|
230
|
-
console.log(usage());
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
if (arg === "--caps" && next) {
|
|
235
|
-
capabilities = parseCaps(next);
|
|
236
|
-
i += 1;
|
|
237
|
-
continue;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
if ((arg === "--host" || arg === "--hostname") && next) {
|
|
241
|
-
hostname = next;
|
|
242
|
-
i += 1;
|
|
243
|
-
continue;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
if (arg === "--port" && next) {
|
|
247
|
-
const value = Number.parseInt(next, 10);
|
|
248
|
-
if (!Number.isFinite(value) || value < 0) {
|
|
249
|
-
throw new Error(`invalid --port: ${next}`);
|
|
250
|
-
}
|
|
251
|
-
port = value;
|
|
252
|
-
i += 1;
|
|
253
|
-
continue;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
if (arg === "--allowed-origins" && next) {
|
|
257
|
-
allowedOrigins = next
|
|
258
|
-
.split(/[\s,]+/g)
|
|
259
|
-
.map((v) => v.trim())
|
|
260
|
-
.filter(Boolean);
|
|
261
|
-
i += 1;
|
|
262
|
-
continue;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
if (arg === "--no-cors") {
|
|
266
|
-
cors = false;
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
throw new Error(`unknown arg: ${arg ?? ""}`);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
const handle = await startPtywrightHttpServer({
|
|
274
|
-
hostname,
|
|
275
|
-
port,
|
|
276
|
-
capabilities,
|
|
277
|
-
allowedOrigins,
|
|
278
|
-
cors,
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
// eslint-disable-next-line no-console
|
|
282
|
-
console.log(`listening ${handle.url}`);
|
|
283
|
-
// eslint-disable-next-line no-console
|
|
284
|
-
console.log(`health http://${handle.hostname}:${handle.port}/health`);
|
|
285
|
-
|
|
286
|
-
function shutdown(): void {
|
|
287
|
-
void handle.close();
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
process.on("SIGINT", shutdown);
|
|
291
|
-
process.on("SIGTERM", shutdown);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
async function cmdRun(argv: string[]): Promise<number> {
|
|
295
|
-
const args = parseRunArgs(argv);
|
|
296
|
-
const result = await runScriptPath(args.scriptPath, {
|
|
297
|
-
artifactsDir: args.artifactsDir,
|
|
298
|
-
updateGoldens: args.updateGoldens,
|
|
299
|
-
stepsPath: args.stepsPath,
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
if (!result.ok) {
|
|
303
|
-
logLines(
|
|
304
|
-
[
|
|
305
|
-
result.error,
|
|
306
|
-
result.artifactsDir ? `artifacts=${result.artifactsDir}` : null,
|
|
307
|
-
result.reportPath ? `report=${result.reportPath}` : null,
|
|
308
|
-
result.castPath ? `cast=${result.castPath}` : null,
|
|
309
|
-
result.failureArtifacts?.lastViewPath
|
|
310
|
-
? `last=${result.failureArtifacts.lastViewPath}`
|
|
311
|
-
: null,
|
|
312
|
-
result.failureArtifacts?.errorPath ? `error=${result.failureArtifacts.errorPath}` : null,
|
|
313
|
-
],
|
|
314
|
-
true,
|
|
315
|
-
);
|
|
316
|
-
return 1;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
logLines(
|
|
320
|
-
[
|
|
321
|
-
`ok artifacts=${result.artifactsDir}`,
|
|
322
|
-
result.reportPath ? `report=${result.reportPath}` : null,
|
|
323
|
-
result.castPath ? `cast=${result.castPath}` : null,
|
|
324
|
-
],
|
|
325
|
-
false,
|
|
326
|
-
);
|
|
327
|
-
return 0;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
async function cmdRunAll(argv: string[]): Promise<number> {
|
|
331
|
-
const args = parseRunAllArgs(argv);
|
|
332
|
-
const result = await runAllScripts({
|
|
333
|
-
dir: args.dir,
|
|
334
|
-
artifactsRoot: args.artifactsRoot,
|
|
335
|
-
stepsPath: args.stepsPath,
|
|
336
|
-
updateGoldens: args.updateGoldens,
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
const failures = result.entries.filter((e) => !e.result.ok);
|
|
340
|
-
|
|
341
|
-
if (failures.length === 0) {
|
|
342
|
-
// eslint-disable-next-line no-console
|
|
343
|
-
console.log(
|
|
344
|
-
`ok count=${result.entries.length} dir=${result.dir}\nreport=${result.reportPath}\nsummary=${result.summaryPath}`,
|
|
345
|
-
);
|
|
346
|
-
return 0;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// eslint-disable-next-line no-console
|
|
350
|
-
console.error(
|
|
351
|
-
`failed count=${failures.length}/${result.entries.length} dir=${result.dir}\nreport=${result.reportPath}\nsummary=${result.summaryPath}`,
|
|
352
|
-
);
|
|
353
|
-
for (const f of failures) {
|
|
354
|
-
if (f.result.ok) continue;
|
|
355
|
-
// eslint-disable-next-line no-console
|
|
356
|
-
console.error(`- ${f.filePath}: ${f.result.error}`);
|
|
357
|
-
if (f.result.failureArtifacts) {
|
|
358
|
-
// eslint-disable-next-line no-console
|
|
359
|
-
console.error(` artifacts=${f.result.artifactsDir ?? ""}`);
|
|
360
|
-
// eslint-disable-next-line no-console
|
|
361
|
-
console.error(` last=${f.result.failureArtifacts.lastViewPath}`);
|
|
362
|
-
// eslint-disable-next-line no-console
|
|
363
|
-
console.error(` error=${f.result.failureArtifacts.errorPath}`);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
return 1;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
export async function main(argv: string[] = process.argv.slice(2)): Promise<void> {
|
|
370
|
-
const [command, ...rest] = argv;
|
|
371
|
-
|
|
372
|
-
if (!command) {
|
|
373
|
-
await cmdMcp([]);
|
|
374
|
-
return;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
if (isHelp(command)) {
|
|
378
|
-
// eslint-disable-next-line no-console
|
|
379
|
-
console.log(usage());
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
if (command === "mcp") {
|
|
384
|
-
await cmdMcp(rest);
|
|
385
|
-
return;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
if (command === "mcp-http") {
|
|
389
|
-
await cmdMcpHttp(rest);
|
|
390
|
-
return;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
if (command === "run") {
|
|
394
|
-
process.exitCode = await cmdRun(rest);
|
|
395
|
-
return;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
if (command === "run-all") {
|
|
399
|
-
process.exitCode = await cmdRunAll(rest);
|
|
400
|
-
return;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
throw new Error(`unknown command: ${command}\n\n` + usage());
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
if (import.meta.main) {
|
|
407
|
-
try {
|
|
408
|
-
await main();
|
|
409
|
-
} catch (error) {
|
|
410
|
-
// eslint-disable-next-line no-console
|
|
411
|
-
console.error((error as Error).message);
|
|
412
|
-
process.exitCode = 1;
|
|
413
|
-
}
|
|
414
|
-
}
|