playwright-e2e-mcp 0.2.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # playwright-e2e-mcp
2
2
 
3
- [![CI](https://github.com/trajectiq-ai/E2E/actions/workflows/ci.yml/badge.svg)](https://github.com/trajectiq-ai/E2E/actions/workflows/ci.yml) [![release](https://img.shields.io/github/v/release/trajectiq-ai/E2E)](https://github.com/trajectiq-ai/E2E/releases) [![MCP Registry](https://img.shields.io/badge/MCP%20Registry-io.github.trajectiq--ai%2FE2E-2563eb)](https://registry.modelcontextprotocol.io/)
3
+ [![CI](https://github.com/xsignon-secure/E2E/actions/workflows/ci.yml/badge.svg)](https://github.com/xsignon-secure/E2E/actions/workflows/ci.yml) [![release](https://img.shields.io/github/v/release/xsignon-secure/E2E)](https://github.com/xsignon-secure/E2E/releases) [![MCP Registry](https://img.shields.io/badge/MCP%20Registry-io.github.xsignon--secure%2FE2E-2563eb)](https://registry.modelcontextprotocol.io/)
4
4
  [![M8ven Score](https://m8ven.ai/badge/mcp/trajectiq-ai/e2e)](https://m8ven.ai/mcp/trajectiq-ai/e2e?s=readme)
5
5
 
6
6
  An [MCP](https://modelcontextprotocol.io) server that **diagnoses and fixes failing Playwright
@@ -26,9 +26,13 @@ What it does that a browser-driving MCP or a raw `npx playwright test` does not:
26
26
  (`getByRole('button', { name: 'Proceed to checkout' })`), re-runs the test and reverts the
27
27
  edit if it is still red. When nothing on the page plausibly matches, it says the element is
28
28
  missing and does not patch the test to hide a real bug.
29
- - **Flakiness across runs.** Every run is recorded locally; `analyze-history` separates
30
- tests that flip (flaky) from ones that started failing (regressed) or always fail (broken),
31
- and groups failures that share one cause.
29
+ - **Flakiness with evidence.** `diagnose-flaky` repeats failing tests in one process and
30
+ gives a verdict per test; with `isolate: true` it re-runs them alone to tell a shared-state
31
+ bug that only bites in parallel from a race inside the test. Every run is recorded locally;
32
+ `analyze-history` separates tests that flip (flaky) from ones that started failing
33
+ (regressed) or always fail (broken), and groups failures that share one cause.
34
+ - **In CI too.** A [GitHub Action and `ci` command](#ci-github-action-and-ci-command) post the
35
+ same diagnosis, flaky verdict and fix diffs to the job summary and the PR.
32
36
  - **Pages behind a login.** Every page tool accepts a Playwright `storageState`, extra
33
37
  headers, and click/fill steps to reach a modal or a later step.
34
38
  - **Small on the wire.** In the [benchmark](bench/RESULTS.md), diagnosing and fixing one
@@ -48,12 +52,12 @@ work side by side in the same client.
48
52
  `https://playwright-e2e-mcp.vercel.app/api/mcp` returns for a client that sends the
49
53
  bearer token (without one, only `list-tests` and `get-failure` are listed):
50
54
 
51
- ![Token-protected endpoint: initialize handshake and the tool list](https://raw.githubusercontent.com/trajectiq-ai/E2E/main/docs/demo-endpoint.png)
55
+ ![Token-protected endpoint: initialize handshake and the tool list](https://raw.githubusercontent.com/xsignon-secure/E2E/main/docs/demo-endpoint.png)
52
56
 
53
57
  **A real test run** — `run-test` served over stdio by `npx -y playwright-e2e-mcp`
54
58
  against the bundled `examples/sample-test.spec.ts` (actual output, unedited):
55
59
 
56
- ![run-test result: 4 passed, 0 failed, 5.1s](https://raw.githubusercontent.com/trajectiq-ai/E2E/main/docs/demo-run-test.png)
60
+ ![run-test result: 4 passed, 0 failed, 5.1s](https://raw.githubusercontent.com/xsignon-secure/E2E/main/docs/demo-run-test.png)
57
61
 
58
62
  Images are rendered with `node scripts/gen-demo-images.mjs`: the run-test card is real
59
63
  captured output; the endpoint card is an illustration of the authenticated listing.
@@ -66,9 +70,9 @@ and every other MCP client — pick whichever route fits:
66
70
  | Route | How |
67
71
  | --- | --- |
68
72
  | **npm (canonical, fastest)** | `npx -y playwright-e2e-mcp` |
69
- | **MCP Registry** (registry-aware clients discover it automatically) | `io.github.trajectiq-ai/E2E` — [listing](https://registry.modelcontextprotocol.io/) |
70
- | **Any client, no npm account needed** | `npx -y github:trajectiq-ai/E2E#v0.2.1` (pin a release tag) |
71
- | **Claude Desktop, zero Node setup** | double-click the [`.mcpb` extension](https://github.com/trajectiq-ai/E2E/releases) |
73
+ | **MCP Registry** (registry-aware clients discover it automatically) | `io.github.xsignon-secure/E2E` — [listing](https://registry.modelcontextprotocol.io/) |
74
+ | **Any client, no npm account needed** | `npx -y github:xsignon-secure/E2E#v0.3.0` (pin a release tag) |
75
+ | **Claude Desktop, zero Node setup** | double-click the [`.mcpb` extension](https://github.com/xsignon-secure/E2E/releases) |
72
76
  | **Remote-only clients (ChatGPT connectors)** | `https://playwright-e2e-mcp.vercel.app/api/mcp` |
73
77
 
74
78
  One line for the common clients:
@@ -78,6 +82,9 @@ claude mcp add playwright-e2e -- npx -y playwright-e2e-mcp
78
82
  code --add-mcp '{"name":"playwright-e2e","command":"npx","args":["-y","playwright-e2e-mcp"]}'
79
83
  ```
80
84
 
85
+ Only need the fix loop? `--tools=core` (or `PW_MCP_TOOLS=core`) exposes six tools and
86
+ halves the tool-definition context; see [Configuration](#configuration).
87
+
81
88
  Details and per-client config: [Installation](#installation) ·
82
89
  [MCP client configuration](#mcp-client-configuration).
83
90
 
@@ -283,14 +290,21 @@ and write a red-highlighted diff image for review.
283
290
  | Argument | Type | Description |
284
291
  | --- | --- | --- |
285
292
  | `testFiles` | string[] | Tests to diagnose (`file:line` supported). Defaults to the tests that failed in the most recent run |
286
- | `runs` | number | Times to run them, `2–10` (default `3`) |
293
+ | `runs` | number | Repetitions, `2–10` (default `3`) |
294
+ | `isolate` | boolean | Also tell parallelism bugs from flakiness: repeat fully parallel (`workers` default `4`), then repeat the failing tests with one worker |
295
+ | `separateProcesses` | boolean | Start a fresh Playwright process per repetition instead of one `--repeat-each` process (slower; for flakes that depend on global setup or a cold start) |
287
296
  | `browser` / `headed` / `workers` / `config` | — | As with `run-test` |
288
- | `timeoutMs` | number | Hard wall-clock limit **per run** (default `120000`) |
297
+ | `timeoutMs` | number | Hard wall-clock limit **per repetition** (default `120000`); one `--repeat-each` process gets this × `runs` |
289
298
  | `projectRoot` | string | Project directory |
290
299
 
291
- Every run executes with `--retries=0` and auto-retry disabled, so each result is
292
- honest evidence. The response contains a per-run table (status, duration, first
293
- failure), the count of **distinct normalized error signatures**, and one of:
300
+ All repetitions run in **one Playwright process** with `--repeat-each` and
301
+ `--retries=0`, so each attempt is honest evidence and the browser and workers
302
+ start once instead of once per run (about 25% faster on the integration fixture,
303
+ more for suites with expensive setup). A small extra reporter records every
304
+ attempt, because Playwright's JSON report keeps only one result per test.
305
+
306
+ The verdict is **per test**: a table of passes, failures, duration spread and
307
+ first error for each test, plus the verdict block for the worst one:
294
308
 
295
309
  - **❌ CONSISTENTLY FAILING** — failed every run (same error → reproducible bug,
296
310
  different errors → still broken, just noisy). Fix it; it is not flaky.
@@ -299,7 +313,17 @@ failure), the count of **distinct normalized error signatures**, and one of:
299
313
  instability).
300
314
  - **✅ NOT REPRODUCING** — passed every re-run; the original failure was one-off.
301
315
 
302
- The last run is stored, so `get-failure` can analyze it immediately afterwards.
316
+ With `isolate: true` a second table compares each failing test **in parallel**
317
+ and **alone**:
318
+
319
+ | Reading | Meaning |
320
+ | --- | --- |
321
+ | 🔀 fails only in parallel | Passes every run alone: shared state between tests (same account, DB rows, files, ports). Give each worker its own data or run the file serially |
322
+ | ⏱️ flaky even alone | The race is inside the test or the app: missing `await`, asserting before the UI settles |
323
+ | ❌ fails alone too | Not a parallelism problem; a real bug |
324
+
325
+ Each repetition is recorded in the run history, and the last failing run is
326
+ stored, so `analyze-history` and `get-failure` work right afterwards.
303
327
 
304
328
  ### `suggest-fix`
305
329
 
@@ -367,11 +391,11 @@ Requirements:
367
391
 
368
392
  **No npm account needed** — install straight from GitHub (the `prepare` script
369
393
  builds `dist/` automatically on install). Pin a release tag: an unpinned
370
- `github:trajectiq-ai/E2E` runs whatever is on the default branch at that moment.
394
+ `github:xsignon-secure/E2E` runs whatever is on the default branch at that moment.
371
395
 
372
396
  ```bash
373
- npx -y github:trajectiq-ai/E2E#v0.2.1
374
- npm install -D github:trajectiq-ai/E2E#v0.2.1 @playwright/test # or as a project dependency
397
+ npx -y github:xsignon-secure/E2E#v0.3.0
398
+ npm install -D github:xsignon-secure/E2E#v0.3.0 @playwright/test # or as a project dependency
375
399
  npx playwright install chromium
376
400
  ```
377
401
 
@@ -379,11 +403,11 @@ Or grab the packaged tarball from the repo's **GitHub Releases** page and instal
379
403
  it locally:
380
404
 
381
405
  ```bash
382
- npm install -D https://github.com/trajectiq-ai/E2E/releases/download/v0.2.1/playwright-e2e-mcp-0.2.1.tgz
406
+ npm install -D https://github.com/xsignon-secure/E2E/releases/download/v0.3.0/playwright-e2e-mcp-0.3.0.tgz
383
407
  ```
384
408
 
385
409
  Listed in the **official [MCP Registry](https://registry.modelcontextprotocol.io/)** as
386
- `io.github.trajectiq-ai/E2E` — registry-aware clients discover it there, and every
410
+ `io.github.xsignon-secure/E2E` — registry-aware clients discover it there, and every
387
411
  `v*` release tag republishes the entry from CI via [`server.json`](server.json).
388
412
 
389
413
  ### MCP client configuration
@@ -395,7 +419,7 @@ Listed in the **official [MCP Registry](https://registry.modelcontextprotocol.io
395
419
  "mcpServers": {
396
420
  "playwright-e2e": {
397
421
  "command": "npx",
398
- "args": ["-y", "github:trajectiq-ai/E2E#v0.2.1"],
422
+ "args": ["-y", "github:xsignon-secure/E2E#v0.3.0"],
399
423
  "env": { "PW_MCP_PROJECT_ROOT": "/absolute/path/to/your/project" }
400
424
  }
401
425
  }
@@ -409,8 +433,8 @@ when the client launches it somewhere else (e.g. your home directory).
409
433
  **Codex / VS Code / Copilot CLIs:**
410
434
 
411
435
  ```bash
412
- codex mcp add playwright-e2e -- npx -y github:trajectiq-ai/E2E#v0.2.1
413
- code --add-mcp '{"name":"playwright-e2e","command":"npx","args":["-y","github:trajectiq-ai/E2E#v0.2.1"]}'
436
+ codex mcp add playwright-e2e -- npx -y github:xsignon-secure/E2E#v0.3.0
437
+ code --add-mcp '{"name":"playwright-e2e","command":"npx","args":["-y","github:xsignon-secure/E2E#v0.3.0"]}'
414
438
  ```
415
439
 
416
440
  Codex's defaults fight this server: the first launch clones the repo and runs
@@ -421,13 +445,13 @@ Codex's defaults fight this server: the first launch clones the repo and runs
421
445
  ```toml
422
446
  [mcp_servers.playwright-e2e]
423
447
  command = "npx"
424
- args = ["-y", "github:trajectiq-ai/E2E#v0.2.1"]
448
+ args = ["-y", "github:xsignon-secure/E2E#v0.3.0"]
425
449
  startup_timeout_sec = 60
426
450
  tool_timeout_sec = 600
427
451
  ```
428
452
 
429
453
  **Claude Desktop (one-click):** download and double-click the `.mcpb` Desktop
430
- Extension attached to the [latest release](https://github.com/trajectiq-ai/E2E/releases) —
454
+ Extension attached to the [latest release](https://github.com/xsignon-secure/E2E/releases) —
431
455
  the bundle ships its own dependencies, so no Node setup is required. On install it
432
456
  asks you to pick your **project root** (required, no default: choose the project
433
457
  folder, not your home directory) and wires it
@@ -436,7 +460,7 @@ into `PW_MCP_PROJECT_ROOT`, so the tools point at a real project from the first
436
460
  **Claude Code:**
437
461
 
438
462
  ```bash
439
- claude mcp add playwright-e2e -- npx -y github:trajectiq-ai/E2E#v0.2.1
463
+ claude mcp add playwright-e2e -- npx -y github:xsignon-secure/E2E#v0.3.0
440
464
  ```
441
465
 
442
466
  **Gemini CLI / Qwen Code:** paste the `mcpServers` block above into
@@ -545,11 +569,60 @@ Redeploy after a change: merge to `main`. Vercel's Git integration deploys
545
569
  every push, so there is no token to manage and no CLI step — watch the
546
570
  `Vercel` commit status for the deployment result.
547
571
 
572
+ ## CI: GitHub Action and `ci` command
573
+
574
+ The same diagnosis runs without an agent. `playwright-e2e-mcp ci` runs the
575
+ suite (auto-retry once, so flaky tests are reported as flaky, not failed),
576
+ optionally drafts `suggest-fix` diffs and a flaky verdict for the failures, and
577
+ writes one Markdown report to stdout, to `--output`, and to the GitHub job
578
+ summary when `GITHUB_STEP_SUMMARY` is set. Exit code `0` passed, `1` tests
579
+ failed, `2` the run itself failed.
580
+
581
+ ```bash
582
+ npx -y playwright-e2e-mcp ci --flaky-runs 3 --suggest 2 --output report.md
583
+ npx -y playwright-e2e-mcp ci --help
584
+ ```
585
+
586
+ As a GitHub Action, it adds the report to the job summary and keeps one PR
587
+ comment up to date when the run fails:
588
+
589
+ ```yaml
590
+ permissions:
591
+ contents: read
592
+ pull-requests: write # only for the PR comment
593
+ steps:
594
+ - uses: actions/checkout@v6
595
+ - uses: actions/setup-node@v6
596
+ with: { node-version: 24 }
597
+ - run: npm ci && npx playwright install --with-deps chromium
598
+ - uses: xsignon-secure/E2E@v0.3.0
599
+ with:
600
+ flaky-runs: 3 # 0 skips the flaky verdict
601
+ suggest: 2 # suggest-fix diffs for the first 2 failures
602
+ # args: --browser chromium tests/checkout
603
+ ```
604
+
605
+ Inputs: `project-root`, `args`, `flaky-runs`, `suggest`, `comment`,
606
+ `fail-on-failure`, `version`, `github-token`. Outputs: `exit-code`, `report`.
607
+
608
+ ## Docker
609
+
610
+ ```bash
611
+ docker build -t playwright-e2e-mcp .
612
+ docker run -i --rm -v "$PWD:/work" playwright-e2e-mcp # stdio MCP server
613
+ docker run --rm -v "$PWD:/work" playwright-e2e-mcp ci # CI report
614
+ ```
615
+
616
+ The image is based on `mcr.microsoft.com/playwright:v1.63.0-noble`, so its
617
+ browsers match Playwright 1.63. Mount your project at `/work`; its own
618
+ `node_modules` provide `@playwright/test`.
619
+
548
620
  ## Configuration
549
621
 
550
622
  | Environment variable | Default | Purpose |
551
623
  | --- | --- | --- |
552
624
  | `PW_MCP_PROJECT_ROOT` | server cwd | Default project root for every tool |
625
+ | `PW_MCP_TOOLS` | all | Which tools to expose, as tool names and/or profiles, comma separated (same as the `--tools=` flag). Profiles: `core` (run, status, failure, fix, flaky, list), `triage` (run, status, failure, flaky, history, list), `inspect` (page, selector, visual), `author` (list, page, selector, generate, run). All eleven tool definitions cost about 5.2k tokens of context per request; `core` costs about 2.4k |
553
626
  | `PW_MCP_STORAGE_STATE` | — | Default `storageState` file (inside the project) for the page tools |
554
627
  | `PW_MCP_HISTORY` | on | `0` stops recording runs to `.playwright-e2e-mcp/history.jsonl` |
555
628
  | `PW_MCP_ALLOWED_ROOTS` | — | Extra directories a caller may pass as `projectRoot` (`:`-separated, `;` on Windows). Anything outside these and the default root is rejected |
@@ -685,6 +758,10 @@ npm test # build + test/run-tests.mjs (unit tests, any Node ≥20)
685
758
  npm run e2e # build + e2e/run.mjs: live MCP ↔ Playwright integration suite
686
759
  npm run mcpb # build + bundle dist/ into playwright-e2e-mcp-<version>.mcpb (+ .sha256)
687
760
  npm run mcpb:smoke # ...then install that bundle in a temp dir, launch it and assert the handshake
761
+ npm run mcpb:sign # ...then sign it with MCPB_CERT/MCPB_KEY → <version>.signed.mcpb
762
+ npm run skill:zip # just the archive: dist-skill/playwright-e2e-mcp.zip
763
+ npm run skill:package # the uploadable folder: ../agensi-skill-<version>/ (skill copy, README, zip)
764
+ npm run skill:check # build, then fail if a packaged copy has drifted from skill/
688
765
  ```
689
766
 
690
767
  Tests cover the report parser (sample Playwright JSON, trace attachments), path utils
@@ -694,11 +771,15 @@ helpers, the **trace reader** (synthetic trace.zip: error, failed action, DOM sn
694
771
  `*.network` failed-request parsing, console error/warning events), the **image diff**
695
772
  (PNG round-trip, regions, color shift, dimension changes), the **change analyzer**
696
773
  (selector extraction, git + mtime paths), the **flaky verdict logic**
697
- (failure signatures, CONSISTENTLY FAILING / FLAKY / NOT REPRODUCING / NO TESTS RAN),
774
+ (failure signatures, CONSISTENTLY FAILING / FLAKY / NOT REPRODUCING / NO TESTS RAN,
775
+ per-test grouping of repeat attempts and the parallel-vs-alone reading), the `ci`
776
+ argument parser and tool profiles,
698
777
  the **HTTP bridge** (token, restricted mode, Host allowlist), the **security
699
778
  regressions** (sandbox escapes, argument smuggling, symlink writes, code injection,
700
779
  SSRF ranges, env scrubbing, decode limits), the `.mcpb` manifest, the `.mcpb` zip
701
- extractor, and the MCP config files.
780
+ extractor, the **skill package** (byte-identical rebuilds, a CRLF checkout hashing the
781
+ same, refusal of junk/binary/symlinks, and drift detection between `skill/` and a
782
+ packaged copy), and the MCP config files.
702
783
 
703
784
  ### Integration suite (`npm run e2e`)
704
785
 
@@ -718,13 +799,174 @@ that only appear end-to-end:
718
799
  - `get-failure` trace diagnostics: DOM at failure, the 404 network request,
719
800
  the `console.error` message, diagnosis and next steps,
720
801
  - auto-retry turning a first-run failure into `PASSED (1 flaky)`,
721
- - `diagnose-flaky` verdict **FLAKY** (2 of 3 runs) with retries disabled,
802
+ - `diagnose-flaky` verdict **FLAKY** (2 of 3 runs) with retries disabled, in one
803
+ `--repeat-each` process, and `isolate` reading a shared-slot test as "fails only in parallel",
804
+ - `--tools=` profiles trimming `tools/list`, and the `ci` command's exit code, report,
805
+ `--output` file and GitHub job summary,
722
806
  - `generate-e2e-test` writing its scaffold, plus error paths
723
807
  (missing test path, unknown tool, unreachable server).
724
808
 
725
809
  First run needs the browser once: `npx playwright install chromium`.
726
810
  CI runs the suite on Ubuntu and Windows (see `.github/workflows/ci.yml`).
727
811
 
812
+ ### Signing the bundle
813
+
814
+ ```bash
815
+ MCPB_CERT=~/signing/cert.pem MCPB_KEY=~/signing/key.pem npm run mcpb:sign
816
+ ```
817
+
818
+ Signing appends a PKCS#7 signature block to the bundle, so the signed file is
819
+ *the reproducible bundle plus that block*. That ordering is the point: the bytes
820
+ CI proved identical across platforms stay inside the signed file, and
821
+ `mcpb unsign` returns them exactly. `scripts/sign-mcpb.mjs` asserts that round
822
+ trip on every run and deletes its output if it fails, which is what keeps
823
+ `<version>.signed.mcpb` tied to `<version>.mcpb`.
824
+
825
+ The private key is read from a path you pass in (`--cert`/`--key` or
826
+ `MCPB_CERT`/`MCPB_KEY`) and never from the repository — keep it outside version
827
+ control, and back it up: the same key across releases is what makes the signer
828
+ recognisable.
829
+
830
+ What signing does and does not buy you is decided by the certificate, not by
831
+ this script. `mcpb verify` and `mcpb info` accept a signature only when the
832
+ certificate chains to something in the OS trust store, so with a self-signed
833
+ certificate a host still reports **Not signed** — the signature is real
834
+ integrity and key continuity, verifiable by the fingerprint the script prints,
835
+ but not third-party identity. A certificate issued by a public CA, or an
836
+ internal one installed on your machines, is what makes hosts report it as
837
+ signed.
838
+
839
+ ### Assembling a release
840
+
841
+ ```bash
842
+ npm run mcpb && npm pack # the bundle, then the npm tarball
843
+ npm run release:assemble -- --tag v0.2.3 # sign, checksum and write the notes
844
+ npm run release:publish -- --tag v0.2.3 --assets dist-release/assets \
845
+ --title-file dist-release/RELEASE_TITLE.txt \
846
+ --body-file dist-release/RELEASE_BODY.md --download dist-release/downloaded
847
+ npm run release:verify -- v0.2.3 --dir dist-release/downloaded
848
+ npm run release:publish -- --tag v0.2.3 --publish
849
+ ```
850
+
851
+ Pushing a `v*` tag runs exactly that sequence in
852
+ `.github/workflows/release.yml`. The release used to be assembled by hand, and
853
+ the notes were written from what those commands printed: every hash in them was
854
+ a copy, and nothing compared the bundle hash printed there with the bundle that
855
+ shipped.
856
+
857
+ `scripts/assemble-release.mjs` stages the whole release into
858
+ `dist-release/assets/`: the bundle and its sidecar, the **signed** bundle and the
859
+ signing certificate when a key is configured, the npm tarball, the skill package
860
+ built by the same writer as `npm run skill:zip`, and `SHA256SUMS.txt` covering
861
+ every file it staged. It empties that directory first, so a file left over from
862
+ an earlier run cannot be hashed and published as if this run had produced it.
863
+
864
+ The notes are half written, half generated. `release-notes/<tag>.md` holds the
865
+ prose — its H1 becomes the release title and has to name the tag — and the script
866
+ appends the asset table, the reproduction recipe carrying the real bundle hash,
867
+ the signer and fingerprint, and the commit list. The prose is held to the same
868
+ rule: a 64-character hex string in it has to be a hash this release publishes,
869
+ and writing an `### Assets` section of your own fails the assembly rather than
870
+ shipping a second, staler table. See [release-notes/README.md](release-notes/README.md).
871
+
872
+ `scripts/publish-release.mjs` fills the release **as a draft**, uploads the
873
+ assets, downloads every one of them back and compares it byte for byte, and only
874
+ `--publish` makes it public — after `release:verify` has re-derived the release
875
+ from the tag. Re-running is safe: a draft this workflow assembled is refreshed in
876
+ place, while a release it did not assemble, or one already published, is refused
877
+ by name instead of overwritten.
878
+
879
+ Signing is optional and its absence is stated rather than hidden: without the
880
+ `MCPB_KEY` and `MCPB_CERT` repository secrets the release is assembled and
881
+ published **unsigned**, with a notice in the run and a line saying so in the
882
+ notes. Add both — the private key stays out of the repository and out of the logs:
883
+
884
+ ```bash
885
+ gh secret set MCPB_KEY --repo xsignon-secure/E2E < ~/signing/key.pem
886
+ gh secret set MCPB_CERT --repo xsignon-secure/E2E < ~/signing/cert.pem
887
+ ```
888
+
889
+ Creating the release and uploading its assets needs `contents: write`, which the
890
+ job requests for itself; if it is refused, the run names the setting to change.
891
+
892
+ ### Verifying a published release
893
+
894
+ ```bash
895
+ git checkout v0.3.0 && npm ci && npm run mcpb
896
+ npm run release:verify -- v0.3.0
897
+ ```
898
+
899
+ The release notes promise that the tag rebuilds the published bundle byte for
900
+ byte. `scripts/verify-release.mjs` checks that promise from a checkout of the
901
+ tag: the published bundle against your fresh build, every checksum the release
902
+ publishes (and that nothing shippable is missing from `SHA256SUMS.txt`), a
903
+ **signed** bundle against the bytes its signature wraps, the **skill package**
904
+ against a rebuild from the same tag, and that the published archive still
905
+ extracts with that version's manifest. The skill package is required of a tag
906
+ whose tree carries the publishing workflow; older tags predate it, so there it
907
+ is checked when present and skipped when not, like the signing certificate.
908
+ `.github/workflows/verify-release.yml` runs it on demand for any past tag, and by
909
+ itself for a release published by hand. A release assembled by
910
+ `.github/workflows/release.yml` runs the same check on its own assets *before*
911
+ it is published — GitHub does not raise `release: published` for a release created
912
+ with the repository's own token, so the check is a step there rather than a
913
+ trigger. The `.tgz` is checked for download integrity only: npm
914
+ records the packer's line endings, so a tarball packed locally on another OS is
915
+ legitimately different.
916
+
917
+ ### Packaging the agent skill
918
+
919
+ ```bash
920
+ npm run skill:package # ../agensi-skill-<version>/, ready to upload
921
+ npm run skill:zip # only the archive: dist-skill/playwright-e2e-mcp.zip
922
+ npm run skill:check # build, then compare every copy
923
+ npm run skill:check -- ../agensi-skill-0.3.0
924
+ ```
925
+
926
+ `skill/` is an [Agent Skill](https://agentskills.io/specification) — the
927
+ instructions an agent follows to drive this server — and the marketplace gets
928
+ the same Markdown as a zip with `playwright-e2e-mcp/` at its root.
929
+ `scripts/package-skill.mjs` produces that zip, so the uploaded copy is built
930
+ rather than assembled by hand, and it refuses what the marketplace rejects: a
931
+ missing `SKILL.md`, a non-text file, a symlink, `Thumbs.db`.
932
+
933
+ `skill:package` writes the whole folder a release would otherwise assemble by
934
+ hand — the skill copy, `skill/README.md` and the archive — to
935
+ `../agensi-skill-<version>` (or `--out <dir>`), then verifies it with the same
936
+ comparison `check` uses, so a successful exit means the folder really is the
937
+ skill tree. It is idempotent: a folder that already matches is left untouched.
938
+ A folder that has drifted is refused instead of overwritten, because it may
939
+ already be published — bump `version` for a new package, or pass `--force` to
940
+ replace that one.
941
+
942
+ The archive comes from the same deterministic writer as the `.mcpb`, so the
943
+ same tree always hashes the same, and text payloads are LF-normalised first:
944
+ a CRLF checkout builds the bytes an LF one does. CI runs `skill:check`, generates
945
+ a package folder, and uploads the built zip as an artifact
946
+ (`.github/workflows/ci.yml`).
947
+
948
+ **Every release publishes the package too.** Assembling a release builds it from
949
+ the release tag and attaches it as `<name>-<version>-skill.zip`, and the
950
+ `.github/workflows/release.yml` run downloads that asset back off the draft and
951
+ byte-compares it with the build before anything is published. The marketplace
952
+ upload is that asset, not a folder someone assembled — a deterministic archive
953
+ means "the same build as the tagged release" is an exact statement, and
954
+ `release:verify` checks it again against a rebuild from the tag.
955
+ `.github/workflows/publish-skill-package.yml` stays for the repair path: run it
956
+ by hand to attach or rebuild the package for a release that is missing it.
957
+
958
+ `skill:check` is the other half of that, and the part that matters when a
959
+ package has already been uploaded. It builds twice (the bytes must agree),
960
+ reads the archive back and compares its contents with `skill/` file by file,
961
+ then compares a packaged copy — `../agensi-skill-<version>` by default, or a
962
+ path you pass: the package folder, the bare `playwright-e2e-mcp/` folder, or
963
+ the zip on its own. Comparisons are by content, never by archive bytes, because
964
+ a zip written by a platform `zip` tool carries real timestamps that say nothing
965
+ about whether the Markdown inside it is current. Any file that differs, is
966
+ missing or is extra is named on stderr and the command exits 1 — the repository
967
+ copy and the uploaded copy are the same document, so an edit to either one
968
+ should not be invisible.
969
+
728
970
  ### Try the example
729
971
 
730
972
  With Playwright installed in your project:
@@ -0,0 +1,29 @@
1
+ /**
2
+ * `playwright-e2e-mcp ci`: the same diagnosis the MCP tools give an agent,
3
+ * as a plain command for CI. It runs the suite (auto-retry once, so flaky
4
+ * tests are reported as flaky rather than failed), optionally repeats the
5
+ * failures through diagnose-flaky and drafts suggest-fix diffs, and writes
6
+ * one Markdown report: to stdout, to --output, and to the GitHub job
7
+ * summary when GITHUB_STEP_SUMMARY is set.
8
+ *
9
+ * Exit codes: 0 all passed (flaky allowed), 1 tests failed, 2 the run
10
+ * itself failed (no Playwright, config error, timeout) or bad arguments.
11
+ */
12
+ export declare const CI_USAGE: string;
13
+ export interface CiOptions {
14
+ projectRoot?: string;
15
+ config?: string;
16
+ browser?: 'chromium' | 'firefox' | 'webkit';
17
+ grep?: string;
18
+ workers?: number;
19
+ timeoutMs: number;
20
+ retry: boolean;
21
+ flakyRuns?: number;
22
+ suggest: number;
23
+ output?: string;
24
+ testFiles: string[];
25
+ }
26
+ /** Parse `ci` arguments (everything after the subcommand). Throws on bad input. */
27
+ export declare function parseCiArgs(argv: string[]): CiOptions;
28
+ /** Run the CI flow; returns the exit code. */
29
+ export declare function runCi(argv: string[]): Promise<number>;
package/dist/cli/ci.js ADDED
@@ -0,0 +1,145 @@
1
+ /**
2
+ * `playwright-e2e-mcp ci`: the same diagnosis the MCP tools give an agent,
3
+ * as a plain command for CI. It runs the suite (auto-retry once, so flaky
4
+ * tests are reported as flaky rather than failed), optionally repeats the
5
+ * failures through diagnose-flaky and drafts suggest-fix diffs, and writes
6
+ * one Markdown report: to stdout, to --output, and to the GitHub job
7
+ * summary when GITHUB_STEP_SUMMARY is set.
8
+ *
9
+ * Exit codes: 0 all passed (flaky allowed), 1 tests failed, 2 the run
10
+ * itself failed (no Playwright, config error, timeout) or bad arguments.
11
+ */
12
+ import { appendFile, writeFile } from 'node:fs/promises';
13
+ import { parseArgs } from 'node:util';
14
+ import { createLogger } from '../utils/logger.js';
15
+ import { createToolStore } from '../tools/shared.js';
16
+ import { runTestTool } from '../tools/run-test.js';
17
+ import { diagnoseFlakyTool } from '../tools/diagnose-flaky.js';
18
+ import { suggestFixTool } from '../tools/suggest-fix.js';
19
+ export const CI_USAGE = [
20
+ 'Usage: playwright-e2e-mcp ci [options] [test files…]',
21
+ '',
22
+ 'Runs the Playwright suite and writes a Markdown diagnosis (stdout, --output,',
23
+ 'and $GITHUB_STEP_SUMMARY when set). Exit 0 = passed, 1 = tests failed, 2 = run error.',
24
+ '',
25
+ ' --project-root <dir> project directory (default: PW_MCP_PROJECT_ROOT or cwd)',
26
+ ' --config <path|n> playwright.config path or 1-based index',
27
+ ' --browser <name> chromium | firefox | webkit',
28
+ ' --grep <regex> only tests whose title matches',
29
+ ' --workers <n> Playwright workers',
30
+ ' --timeout <ms> wall-clock limit for the run (default 600000)',
31
+ ' --no-retry do not auto-retry failures once',
32
+ ' --flaky-runs <n> repeat failing tests n times (2-10) for a flaky verdict',
33
+ ' --suggest <n> draft suggest-fix diffs for the first n failures (max 5)',
34
+ ' --output <file> also write the report to this file (for a PR comment)',
35
+ '',
36
+ ].join('\n');
37
+ function intOption(value, name, min, max) {
38
+ if (value === undefined)
39
+ return undefined;
40
+ const n = Number(value);
41
+ if (!Number.isInteger(n) || n < min || n > max)
42
+ throw new Error(`--${name} must be an integer from ${min} to ${max}`);
43
+ return n;
44
+ }
45
+ /** Parse `ci` arguments (everything after the subcommand). Throws on bad input. */
46
+ export function parseCiArgs(argv) {
47
+ const { values, positionals } = parseArgs({
48
+ args: argv,
49
+ allowPositionals: true,
50
+ strict: true,
51
+ options: {
52
+ 'project-root': { type: 'string' },
53
+ config: { type: 'string' },
54
+ browser: { type: 'string' },
55
+ grep: { type: 'string' },
56
+ workers: { type: 'string' },
57
+ timeout: { type: 'string' },
58
+ 'no-retry': { type: 'boolean' },
59
+ 'flaky-runs': { type: 'string' },
60
+ suggest: { type: 'string' },
61
+ output: { type: 'string' },
62
+ },
63
+ });
64
+ const browser = values.browser;
65
+ if (browser !== undefined && browser !== 'chromium' && browser !== 'firefox' && browser !== 'webkit') {
66
+ throw new Error('--browser must be chromium, firefox or webkit');
67
+ }
68
+ return {
69
+ projectRoot: values['project-root'],
70
+ config: values.config,
71
+ browser,
72
+ grep: values.grep,
73
+ workers: intOption(values.workers, 'workers', 1, 64),
74
+ timeoutMs: intOption(values.timeout, 'timeout', 1_000, 3_600_000) ?? 600_000,
75
+ retry: values['no-retry'] !== true,
76
+ flakyRuns: intOption(values['flaky-runs'], 'flaky-runs', 2, 10),
77
+ suggest: intOption(values.suggest, 'suggest', 0, 5) ?? 0,
78
+ output: values.output,
79
+ testFiles: positionals,
80
+ };
81
+ }
82
+ function text(response) {
83
+ return response.content.map((block) => block.text).join('\n');
84
+ }
85
+ /** Run the CI flow; returns the exit code. */
86
+ export async function runCi(argv) {
87
+ let options;
88
+ try {
89
+ options = parseCiArgs(argv);
90
+ }
91
+ catch (err) {
92
+ process.stderr.write(`${err.message}\n\n${CI_USAGE}`);
93
+ return 2;
94
+ }
95
+ const projectRoot = options.projectRoot ?? process.env.PW_MCP_PROJECT_ROOT ?? process.cwd();
96
+ const ctx = {
97
+ // Info logs would bury the report in CI output; LOG_LEVEL still wins.
98
+ logger: createLogger({
99
+ level: process.env.LOG_LEVEL || process.env.MCP_LOG_LEVEL ? undefined : 'warn',
100
+ bindings: { name: 'playwright-e2e-mcp', mode: 'ci' },
101
+ }),
102
+ store: createToolStore(),
103
+ projectRoot,
104
+ };
105
+ const sections = [];
106
+ const run = await runTestTool.handler({
107
+ testFiles: options.testFiles.length > 0 ? options.testFiles : undefined,
108
+ grep: options.grep,
109
+ browser: options.browser,
110
+ workers: options.workers,
111
+ timeoutMs: options.timeoutMs,
112
+ retryOnFailure: options.retry,
113
+ config: options.config,
114
+ }, ctx);
115
+ sections.push(text(run));
116
+ const result = ctx.store.lastRun?.result;
117
+ const failures = result?.failures ?? [];
118
+ let code = result === undefined || run.isError ? 2 : result.ok ? 0 : failures.length > 0 ? 1 : 2;
119
+ if (code === 1 && options.suggest > 0) {
120
+ // Before diagnose-flaky, which replaces the last run suggest-fix indexes into.
121
+ const count = Math.min(options.suggest, ctx.store.lastRun?.result.failures.length ?? 0);
122
+ for (let index = 1; index <= count; index += 1) {
123
+ const fix = await suggestFixTool.handler({ index, config: options.config }, ctx);
124
+ sections.push(text(fix).replace(/^## /m, '### '));
125
+ }
126
+ }
127
+ if (code === 1 && options.flakyRuns) {
128
+ const flaky = await diagnoseFlakyTool.handler({ runs: options.flakyRuns, config: options.config, browser: options.browser }, ctx);
129
+ sections.push(text(flaky).replace(/^## /m, '### '));
130
+ }
131
+ const report = `${sections.join('\n\n---\n\n')}\n\n<sub>Generated by [playwright-e2e-mcp](https://github.com/xsignon-secure/E2E) \`ci\`.</sub>\n`;
132
+ process.stdout.write(report);
133
+ try {
134
+ if (options.output)
135
+ await writeFile(options.output, report, 'utf8');
136
+ if (process.env.GITHUB_STEP_SUMMARY)
137
+ await appendFile(process.env.GITHUB_STEP_SUMMARY, report, 'utf8');
138
+ }
139
+ catch (err) {
140
+ process.stderr.write(`could not write the report: ${err.message}\n`);
141
+ code = Math.max(code, 2);
142
+ }
143
+ return code;
144
+ }
145
+ //# sourceMappingURL=ci.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci.js","sourceRoot":"","sources":["../../src/cli/ci.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -7,6 +7,6 @@
7
7
  * tests and tooling can construct a server without side effects.
8
8
  */
9
9
  import { logger } from './utils/logger.js';
10
- export { createServer, startServer, SERVER_NAME, SERVER_VERSION } from './server.js';
10
+ export { createServer, startServer, resolveToolSelection, TOOL_PROFILES, SERVER_NAME, SERVER_VERSION } from './server.js';
11
11
  export { createMcpHttpHandler, handleNodeRequest, MAX_BODY_BYTES } from './http.js';
12
12
  export { logger };