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.
Files changed (67) hide show
  1. package/README.md +318 -1
  2. package/dist/agent.mjs +2 -0
  3. package/dist/bin/ptywright.mjs +6 -0
  4. package/dist/cli-CfvlbRoZ.mjs +3585 -0
  5. package/dist/cli.mjs +2 -0
  6. package/{src/index.ts → dist/index.mjs} +7 -9
  7. package/dist/mcp.mjs +2 -0
  8. package/dist/pty-cassette.mjs +24 -0
  9. package/dist/pty_like-Cpkh_O9B.mjs +404 -0
  10. package/dist/runner-zApMYWZx.mjs +3257 -0
  11. package/dist/runner-zi0nItvB.mjs +1874 -0
  12. package/dist/script.mjs +2 -0
  13. package/dist/server-BC3yo-dq.mjs +3068 -0
  14. package/dist/session.mjs +2 -0
  15. package/dist/terminal_session-DopC7Xg6.mjs +893 -0
  16. package/package.json +28 -21
  17. package/schemas/ptywright-agent-cassette.schema.json +57 -0
  18. package/schemas/ptywright-agent-check.schema.json +122 -0
  19. package/schemas/ptywright-agent-manifest.schema.json +107 -0
  20. package/schemas/ptywright-agent-promote.schema.json +146 -0
  21. package/schemas/ptywright-agent-replay-summary.schema.json +140 -0
  22. package/schemas/ptywright-agent-run.schema.json +126 -0
  23. package/schemas/ptywright-agent.schema.json +166 -0
  24. package/schemas/ptywright-pty-cassette.schema.json +86 -0
  25. package/schemas/ptywright-script-manifest.schema.json +75 -0
  26. package/schemas/ptywright-script-run-summary.schema.json +114 -0
  27. package/schemas/ptywright-script.schema.json +55 -3
  28. package/bin/ptywright +0 -4
  29. package/src/cli.ts +0 -414
  30. package/src/generator/doc_parser.ts +0 -341
  31. package/src/generator/generate.ts +0 -161
  32. package/src/generator/index.ts +0 -10
  33. package/src/generator/script_generator.ts +0 -209
  34. package/src/generator/step_extractor.ts +0 -397
  35. package/src/mcp/http_server.ts +0 -174
  36. package/src/mcp/script_recording.ts +0 -238
  37. package/src/mcp/server.ts +0 -1348
  38. package/src/pty/bun_pty_adapter.ts +0 -34
  39. package/src/pty/bun_terminal_adapter.ts +0 -149
  40. package/src/pty/pty_adapter.ts +0 -31
  41. package/src/script/dsl.ts +0 -188
  42. package/src/script/module.ts +0 -43
  43. package/src/script/path.ts +0 -151
  44. package/src/script/run.ts +0 -108
  45. package/src/script/run_all.ts +0 -229
  46. package/src/script/runner.ts +0 -983
  47. package/src/script/schema.ts +0 -237
  48. package/src/script/steps/assert_snapshot_equals.ts +0 -21
  49. package/src/script/steps/index.ts +0 -2
  50. package/src/script/suite_report.ts +0 -626
  51. package/src/session/session_manager.ts +0 -145
  52. package/src/session/terminal_session.ts +0 -473
  53. package/src/terminal/ansi.ts +0 -142
  54. package/src/terminal/keys.ts +0 -180
  55. package/src/terminal/mask.ts +0 -70
  56. package/src/terminal/mouse.ts +0 -75
  57. package/src/terminal/snapshot.ts +0 -196
  58. package/src/terminal/style.ts +0 -121
  59. package/src/terminal/view.ts +0 -49
  60. package/src/trace/asciicast.ts +0 -20
  61. package/src/trace/asciinema_player_assets.ts +0 -44
  62. package/src/trace/cast_to_txt.ts +0 -116
  63. package/src/trace/recorder.ts +0 -110
  64. package/src/trace/report.ts +0 -2092
  65. package/src/types.ts +0 -86
  66. package/src/util/hash.ts +0 -8
  67. 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
- }