playwright-e2e-mcp 0.5.1 → 0.6.1
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 +55 -20
- package/dist/cli/ci.d.ts +5 -0
- package/dist/cli/ci.js +97 -5
- package/dist/cli/ci.js.map +1 -1
- package/dist/cli/doctor.d.ts +31 -0
- package/dist/cli/doctor.js +200 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/init.js +2 -1
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/review.d.ts +50 -0
- package/dist/cli/review.js +148 -0
- package/dist/cli/review.js.map +1 -0
- package/dist/http.d.ts +14 -1
- package/dist/http.js +43 -8
- package/dist/http.js.map +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/oauth.d.ts +10 -0
- package/dist/oauth.js +29 -1
- package/dist/oauth.js.map +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.js +65 -5
- package/dist/server.js.map +1 -1
- package/dist/tools/audit-accessibility.d.ts +24 -0
- package/dist/tools/audit-accessibility.js +8 -1
- package/dist/tools/audit-accessibility.js.map +1 -1
- package/dist/tools/audit-performance.d.ts +24 -0
- package/dist/tools/audit-performance.js +14 -2
- package/dist/tools/audit-performance.js.map +1 -1
- package/dist/tools/audit-tests.d.ts +62 -0
- package/dist/tools/audit-tests.js +209 -0
- package/dist/tools/audit-tests.js.map +1 -0
- package/dist/tools/bisect-failure.d.ts +42 -0
- package/dist/tools/bisect-failure.js +291 -0
- package/dist/tools/bisect-failure.js.map +1 -0
- package/dist/tools/compare-visual-state.d.ts +24 -0
- package/dist/tools/diagnose-flaky.js +20 -3
- package/dist/tools/diagnose-flaky.js.map +1 -1
- package/dist/tools/generate-e2e-test.js +1 -1
- package/dist/tools/generate-e2e-test.js.map +1 -1
- package/dist/tools/get-failure.js +11 -2
- package/dist/tools/get-failure.js.map +1 -1
- package/dist/tools/get-run-status.js +4 -3
- package/dist/tools/get-run-status.js.map +1 -1
- package/dist/tools/inspect-page.d.ts +24 -0
- package/dist/tools/inspect-page.js +9 -5
- package/dist/tools/inspect-page.js.map +1 -1
- package/dist/tools/list-tests.js +5 -1
- package/dist/tools/list-tests.js.map +1 -1
- package/dist/tools/probe-script.js +87 -9
- package/dist/tools/probe-script.js.map +1 -1
- package/dist/tools/run-test.js +3 -2
- package/dist/tools/run-test.js.map +1 -1
- package/dist/tools/shared.d.ts +23 -1
- package/dist/tools/shared.js +91 -26
- package/dist/tools/shared.js.map +1 -1
- package/dist/tools/structured.d.ts +334 -0
- package/dist/tools/structured.js +176 -0
- package/dist/tools/structured.js.map +1 -0
- package/dist/tools/suggest-fix.js +15 -5
- package/dist/tools/suggest-fix.js.map +1 -1
- package/dist/tools/validate-selector.d.ts +27 -0
- package/dist/tools/validate-selector.js +28 -5
- package/dist/tools/validate-selector.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/attempt-limiter.d.ts +31 -0
- package/dist/utils/attempt-limiter.js +58 -0
- package/dist/utils/attempt-limiter.js.map +1 -0
- package/dist/utils/bisect.d.ts +31 -0
- package/dist/utils/bisect.js +47 -0
- package/dist/utils/bisect.js.map +1 -0
- package/dist/utils/flake-rules.d.ts +46 -0
- package/dist/utils/flake-rules.js +327 -0
- package/dist/utils/flake-rules.js.map +1 -0
- package/dist/utils/locator-expr.d.ts +3 -1
- package/dist/utils/locator-expr.js +25 -7
- package/dist/utils/locator-expr.js.map +1 -1
- package/package.json +5 -4
- package/skill/playwright-e2e-mcp/SKILL.md +19 -2
- package/skill/playwright-e2e-mcp/references/setup.md +2 -2
- package/skill/playwright-e2e-mcp/references/tools.md +34 -1
package/README.md
CHANGED
|
@@ -47,6 +47,8 @@ load-report ───┴─▶ get-failure ──▶ suggest-fix (apply + re-run
|
|
|
47
47
|
(CI job report) │ └─ refuses when the element is really gone (app bug)
|
|
48
48
|
└─ DOM at failure, failed requests, console errors
|
|
49
49
|
every run ──▶ analyze-history (flaky / broken / slow / which commit broke it)
|
|
50
|
+
test code ──▶ audit-tests (flake risks, ranked by history, verified rewrites)
|
|
51
|
+
red at HEAD ─▶ bisect-failure (runs it across git history, names the breaking commit)
|
|
50
52
|
```
|
|
51
53
|
|
|
52
54
|
## Key features
|
|
@@ -59,6 +61,26 @@ every run ──▶ analyze-history (flaky / broken / slow / which commit broke
|
|
|
59
61
|
with Playwright MCP plus a shell ([benchmark](#benchmark)).
|
|
60
62
|
- **Free and open source.** MIT, no account, no API key, no telemetry, no paid tier.
|
|
61
63
|
|
|
64
|
+
## 🚀 What only this MCP does
|
|
65
|
+
|
|
66
|
+
Most testing MCPs let an AI drive a browser: Microsoft's Playwright MCP, Chrome DevTools MCP,
|
|
67
|
+
ExecuteAutomation's mcp-playwright and the Selenium MCP. They're great for clicking through a
|
|
68
|
+
page. None of them, as of October 2026, does the following. This one does:
|
|
69
|
+
|
|
70
|
+
| Capability | What you get |
|
|
71
|
+
| --- | --- |
|
|
72
|
+
| 🎯 **Find the commit that broke a test** | `bisect-failure` runs the test across your git history, in a temporary worktree that leaves your checkout alone, and names the first bad commit with its diff and the failure |
|
|
73
|
+
| 🧪 **Flake-risk audit of your test code** | `audit-tests` finds hard waits, one-shot assertions, missing `await`s and fragile selectors. It ranks them by how flaky those tests really were, then applies the safe rewrites and re-runs them to prove them |
|
|
74
|
+
| ✅ **Fixes that prove themselves** | `suggest-fix` swaps in a locator proven unique on the DOM at failure, re-runs the test and reverts if it's still red. It refuses to patch over a real app bug |
|
|
75
|
+
| 🔬 **Flaky-test verdicts with evidence** | `diagnose-flaky` repeats tests with retries off and tells a race from shared state from **test order**, naming the test it depends on and the seed that reproduces it |
|
|
76
|
+
| 📈 **Memory of every run** | `analyze-history` ranks flaky, regressed and broken tests, groups failures by cause, tracks slow tests and names the commit where each one went bad |
|
|
77
|
+
| 🏗️ **Diagnose CI failures locally** | `load-report` loads a CI job's report and traces (sharded too), so the same diagnosis and verified fixes work on failures from CI |
|
|
78
|
+
| 💬 **One-click fixes on pull requests** | The GitHub Action verifies each fix in CI and posts it as a **suggested change** reviewers apply with one click |
|
|
79
|
+
| ♿⚡ **Audits that hand back tests** | Accessibility (axe-core) and Web Vitals audits return verified locators for each problem plus a ready regression or budget test |
|
|
80
|
+
|
|
81
|
+
It works alongside a browser MCP rather than replacing it: that one drives the page, and this one
|
|
82
|
+
keeps your suite green.
|
|
83
|
+
|
|
62
84
|
## What you can ask
|
|
63
85
|
|
|
64
86
|
| | You ask your AI… | It does this |
|
|
@@ -78,7 +100,7 @@ every run ──▶ analyze-history (flaky / broken / slow / which commit broke
|
|
|
78
100
|
|
|
79
101
|
## Requirements
|
|
80
102
|
|
|
81
|
-
- Node.js
|
|
103
|
+
- Node.js 22 or newer
|
|
82
104
|
- A project that uses `@playwright/test`, with a browser installed (`npx playwright install chromium`)
|
|
83
105
|
- Claude Code, Claude Desktop, Cursor, VS Code, Windsurf, Codex, Gemini CLI or any other MCP client
|
|
84
106
|
|
|
@@ -90,6 +112,7 @@ other servers alone:
|
|
|
90
112
|
|
|
91
113
|
```bash
|
|
92
114
|
npx -y playwright-e2e-mcp init # --client all | cursor,vscode … · --dry-run
|
|
115
|
+
npx -y playwright-e2e-mcp doctor # checks Node, Playwright, browsers and client setup
|
|
93
116
|
```
|
|
94
117
|
|
|
95
118
|
**Or let your agent do it.** Paste this into any coding agent:
|
|
@@ -230,9 +253,9 @@ Running and fixing your own tests needs your project, so use the local install f
|
|
|
230
253
|
| --- | --- |
|
|
231
254
|
| Skill only, any agent | `npx skills add xsignon-secure/E2E` |
|
|
232
255
|
| MCP Registry | `io.github.xsignon-secure/E2E` ([listing](https://registry.modelcontextprotocol.io/)); registry-aware clients find it there |
|
|
233
|
-
| Straight from GitHub, no npm | `npx -y github:xsignon-secure/E2E#v0.
|
|
234
|
-
| Release tarball | `npm install -D https://github.com/xsignon-secure/E2E/releases/download/v0.
|
|
235
|
-
| Docker | `docker run -i --rm -v "$PWD:/work" playwright-e2e-mcp` (see [Development](docs/development.md#docker)) |
|
|
256
|
+
| Straight from GitHub, no npm | `npx -y github:xsignon-secure/E2E#v0.6.1` (pin a release tag) |
|
|
257
|
+
| Release tarball | `npm install -D https://github.com/xsignon-secure/E2E/releases/download/v0.6.1/playwright-e2e-mcp-0.6.1.tgz` |
|
|
258
|
+
| Docker | `docker run -i --rm -v "$PWD:/work" ghcr.io/xsignon-secure/playwright-e2e-mcp` (published on each release; see [Development](docs/development.md#docker)) |
|
|
236
259
|
| Local checkout | `"command": "node", "args": ["/path/to/E2E/dist/index.js"]` |
|
|
237
260
|
|
|
238
261
|
</details>
|
|
@@ -248,16 +271,19 @@ Run my Playwright tests and fix whatever fails.
|
|
|
248
271
|
Your agent should run the suite, read the failure, and propose a fix it has re-run. To check the
|
|
249
272
|
setup without your own tests, ask it to run `examples/sample-test.spec.ts` from this repo.
|
|
250
273
|
|
|
251
|
-
## What's new in 0.
|
|
274
|
+
## What's new in 0.6
|
|
252
275
|
|
|
253
|
-
- **
|
|
254
|
-
|
|
255
|
-
- **
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
-
|
|
260
|
-
|
|
276
|
+
- **Find the commit that broke a test:** `bisect-failure` runs the test across git history in a
|
|
277
|
+
temporary worktree and names the first bad commit, its changes and the failure there.
|
|
278
|
+
- **Flake-risk audit:** `audit-tests` finds hard waits, one-shot assertions, missing `await`s and
|
|
279
|
+
fragile selectors, ranked by real flakiness, and applies the safe rewrites with a verifying run.
|
|
280
|
+
- **One-click fixes on pull requests:** the GitHub Action proves each fix in CI and posts it as a
|
|
281
|
+
suggested change.
|
|
282
|
+
- **`doctor`:** `npx playwright-e2e-mcp doctor` checks Node, Playwright, browsers and client setup.
|
|
283
|
+
- **Structured results:** every tool returns JSON next to its Markdown, with output schemas.
|
|
284
|
+
- **Phones, tablets, Chrome and Edge:** `device` presets and `channel` for every page tool, and a
|
|
285
|
+
Docker image on `ghcr.io`.
|
|
286
|
+
- **Node 22 or newer** is now required, and the hosted endpoint limits guessing of its key.
|
|
261
287
|
|
|
262
288
|
[All release notes](https://github.com/xsignon-secure/E2E/releases)
|
|
263
289
|
|
|
@@ -279,6 +305,8 @@ setup without your own tests, ask it to run `examples/sample-test.spec.ts` from
|
|
|
279
305
|
| `audit-performance` | Measure lab **Web Vitals** (LCP, CLS, TBT, FCP, TTFB, INP during steps), optionally as a throttled phone and the median of several runs; rate them or check budgets, name the LCP and shifting elements as verified locators, list heavy and render-blocking requests, and return a budget test |
|
|
280
306
|
| `diagnose-flaky` | Run a failing test 2–10 times **with retries disabled** and return an evidence verdict: `CONSISTENTLY FAILING`, `FLAKY` or `NOT REPRODUCING`; tells parallelism and **test-order** bugs from races |
|
|
281
307
|
| `analyze-history` | Rank flaky, regressed and broken tests from the local run history, group failures by cause, list the slowest tests, show stability by day, name **the commit where each test went bad**, or show one test's timeline |
|
|
308
|
+
| `audit-tests` | Audit the **test code** for flake risks (hard waits, one-shot assertions instead of web-first ones, missing `await`s, `.only`, force clicks, `networkidle`, element handles, layout selectors), ranked by how flaky those tests have been in the run history; `fix: true` rewrites the mechanical ones, re-runs the files and reverts if they fail |
|
|
309
|
+
| `bisect-failure` | **Find the commit that broke a test**: binary-search git history between a good and a bad commit, running the test at each step in a temporary worktree (your checkout is untouched), and report the first bad commit, what it changed and how the test failed |
|
|
282
310
|
|
|
283
311
|
Two **prompts** package the main workflows for clients that show them as slash commands:
|
|
284
312
|
`fix-failing-test` and `triage-flaky-tests`.
|
|
@@ -333,26 +361,29 @@ npx -y playwright-e2e-mcp ci --help
|
|
|
333
361
|
```
|
|
334
362
|
|
|
335
363
|
As a GitHub Action, it adds the report to the job summary and keeps one PR
|
|
336
|
-
comment up to date when the run fails
|
|
364
|
+
comment up to date when the run fails. On a pull request it also re-runs each
|
|
365
|
+
failing test with its suggested fix and posts the fixes that pass as **suggested
|
|
366
|
+
changes** on the failing lines, so a reviewer applies one with the **Commit
|
|
367
|
+
suggestion** button (only on lines the PR changed; the rest stay in the report):
|
|
337
368
|
|
|
338
369
|
```yaml
|
|
339
370
|
permissions:
|
|
340
371
|
contents: read
|
|
341
|
-
pull-requests: write #
|
|
372
|
+
pull-requests: write # for the PR comment and the suggested fixes
|
|
342
373
|
steps:
|
|
343
374
|
- uses: actions/checkout@v6
|
|
344
375
|
- uses: actions/setup-node@v6
|
|
345
376
|
with: { node-version: 24 }
|
|
346
377
|
- run: npm ci && npx playwright install --with-deps chromium
|
|
347
|
-
- uses: xsignon-secure/E2E@v0.
|
|
378
|
+
- uses: xsignon-secure/E2E@v0.6.1
|
|
348
379
|
with:
|
|
349
380
|
flaky-runs: 3 # 0 skips the flaky verdict
|
|
350
381
|
suggest: 2 # suggest-fix diffs for the first 2 failures
|
|
351
382
|
# args: --browser chromium tests/checkout
|
|
352
383
|
```
|
|
353
384
|
|
|
354
|
-
Inputs: `project-root`, `args`, `flaky-runs`, `suggest`, `comment`,
|
|
355
|
-
`fail-on-failure`, `version`, `github-token`. Outputs: `exit-code`, `report`.
|
|
385
|
+
Inputs: `project-root`, `args`, `flaky-runs`, `suggest`, `comment`, `review`,
|
|
386
|
+
`verify-fixes`, `fail-on-failure`, `version`, `github-token`. Outputs: `exit-code`, `report`.
|
|
356
387
|
|
|
357
388
|
## Configuration
|
|
358
389
|
|
|
@@ -362,13 +393,17 @@ Inputs: `project-root`, `args`, `flaky-runs`, `suggest`, `comment`,
|
|
|
362
393
|
| Environment variable | Default | Purpose |
|
|
363
394
|
| --- | --- | --- |
|
|
364
395
|
| `PW_MCP_PROJECT_ROOT` | server cwd | Default project root for every tool |
|
|
365
|
-
| `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, CI report, flaky, history, list), `inspect` (page, selector, accessibility, performance, visual), `author` (list, page, selector, generate, run). All
|
|
396
|
+
| `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, CI report, flaky, history, test audit, bisect, list), `inspect` (page, selector, accessibility, performance, visual), `author` (list, page, selector, generate, run). All sixteen tool definitions cost about 12k tokens of context per request; `core` costs about 4k (10k and 2.3k with `PW_MCP_OUTPUT_SCHEMAS=0`) |
|
|
397
|
+
| `PW_MCP_OUTPUT_SCHEMAS` | on | `0` leaves the output schemas out of the tool list to save context. Results still carry `structuredContent` (see [Structured results](docs/tools.md#structured-results)) |
|
|
366
398
|
| `PW_MCP_STORAGE_STATE` | — | Default `storageState` file (inside the project) for the page tools |
|
|
367
399
|
| `PW_MCP_SHUFFLE_SEEDS` | random | Comma-separated seeds for `diagnose-flaky`'s `order` pass, to replay the orders a diagnosis reported |
|
|
368
400
|
| `PW_MCP_HISTORY` | on | `0` stops recording runs to `.playwright-e2e-mcp/history.jsonl` |
|
|
369
401
|
| `PW_MCP_ALLOWED_ROOTS` | — | Extra directories a caller may pass as `projectRoot` (`:`-separated, `;` on Windows). Anything outside these and the default root is rejected |
|
|
370
|
-
| `PW_MCP_HTTP_TOKEN` | — | HTTP bridge only: bearer token
|
|
402
|
+
| `PW_MCP_HTTP_TOKEN` | — | HTTP bridge only: bearer token that unlocks all tools: 16+ characters, 32+ recommended (see [Hosted endpoint](docs/hosted-endpoint.md)) |
|
|
371
403
|
| `PW_MCP_ALLOWED_HOSTS` | localhost + Vercel hostnames when there is no token | HTTP bridge only: comma-separated `Host` allowlist; `*` accepts any |
|
|
404
|
+
| `PW_MCP_MAX_FAILED_AUTH` | `20` | HTTP bridge only: wrong tokens or access keys one client address may send in 15 minutes before it gets `429` |
|
|
405
|
+
| `PW_MCP_OAUTH_REDIRECT_HOSTS` | any https host | HTTP bridge only: comma-separated hosts OAuth apps may return to, e.g. `claude.ai,chatgpt.com`; `.example.com` covers subdomains; localhost always works |
|
|
406
|
+
| `PW_MCP_TRUST_PROXY` | off (on for Vercel) | HTTP bridge only: `1` trusts `X-Real-IP` / `X-Forwarded-For` from a reverse proxy in front, so the sign-in limit counts per client, not per proxy |
|
|
372
407
|
| `PW_MCP_PASSTHROUGH_ENV` | — | HTTP bridge only: comma-separated extra variables passed to test runs (e.g. `BASE_URL`) |
|
|
373
408
|
| `PW_MCP_MAX_CHILDREN` | `4` | HTTP bridge only: how many test runs and browser probes may run at once |
|
|
374
409
|
| `PW_MCP_BLOCK_PRIVATE_URLS` | off (on for the HTTP bridge) | `1` makes the URL tools refuse loopback, private-network and cloud-metadata addresses, including redirects and subresources |
|
package/dist/cli/ci.d.ts
CHANGED
|
@@ -21,9 +21,14 @@ export interface CiOptions {
|
|
|
21
21
|
flakyRuns?: number;
|
|
22
22
|
suggest: number;
|
|
23
23
|
output?: string;
|
|
24
|
+
verifyFixes: boolean;
|
|
25
|
+
suggestions?: string;
|
|
26
|
+
review: boolean;
|
|
24
27
|
testFiles: string[];
|
|
25
28
|
}
|
|
26
29
|
/** Parse `ci` arguments (everything after the subcommand). Throws on bad input. */
|
|
27
30
|
export declare function parseCiArgs(argv: string[]): CiOptions;
|
|
31
|
+
/** A project-relative file as a repository-relative posix path, or undefined outside the repository. */
|
|
32
|
+
export declare function repoPath(projectRoot: string, file: string, repoRoot: string): string | undefined;
|
|
28
33
|
/** Run the CI flow; returns the exit code. */
|
|
29
34
|
export declare function runCi(argv: string[]): Promise<number>;
|
package/dist/cli/ci.js
CHANGED
|
@@ -9,13 +9,15 @@
|
|
|
9
9
|
* Exit codes: 0 all passed (flaky allowed), 1 tests failed, 2 the run
|
|
10
10
|
* itself failed (no Playwright, config error, timeout) or bad arguments.
|
|
11
11
|
*/
|
|
12
|
-
import { appendFile, writeFile } from 'node:fs/promises';
|
|
12
|
+
import { appendFile, readFile, writeFile } from 'node:fs/promises';
|
|
13
|
+
import path from 'node:path';
|
|
13
14
|
import { parseArgs } from 'node:util';
|
|
14
15
|
import { createLogger } from '../utils/logger.js';
|
|
15
16
|
import { createToolStore } from '../tools/shared.js';
|
|
16
17
|
import { runTestTool } from '../tools/run-test.js';
|
|
17
18
|
import { diagnoseFlakyTool } from '../tools/diagnose-flaky.js';
|
|
18
19
|
import { suggestFixTool } from '../tools/suggest-fix.js';
|
|
20
|
+
import { postSuggestionReview, pullRequestFromEnv } from './review.js';
|
|
19
21
|
export const CI_USAGE = [
|
|
20
22
|
'Usage: playwright-e2e-mcp ci [options] [test files…]',
|
|
21
23
|
'',
|
|
@@ -32,6 +34,10 @@ export const CI_USAGE = [
|
|
|
32
34
|
' --flaky-runs <n> repeat failing tests n times (2-10) for a flaky verdict',
|
|
33
35
|
' --suggest <n> draft suggest-fix diffs for the first n failures (max 5)',
|
|
34
36
|
' --output <file> also write the report to this file (for a PR comment)',
|
|
37
|
+
' --verify-fixes apply each suggested fix, re-run its test, then restore the file',
|
|
38
|
+
' --suggestions <file> write the suggested fixes as JSON (repository-relative paths)',
|
|
39
|
+
' --review on a GitHub pull request, post the fixes as suggested changes',
|
|
40
|
+
' (needs GITHUB_TOKEN or GH_TOKEN with pull-requests: write)',
|
|
35
41
|
'',
|
|
36
42
|
].join('\n');
|
|
37
43
|
function intOption(value, name, min, max) {
|
|
@@ -59,6 +65,9 @@ export function parseCiArgs(argv) {
|
|
|
59
65
|
'flaky-runs': { type: 'string' },
|
|
60
66
|
suggest: { type: 'string' },
|
|
61
67
|
output: { type: 'string' },
|
|
68
|
+
'verify-fixes': { type: 'boolean' },
|
|
69
|
+
suggestions: { type: 'string' },
|
|
70
|
+
review: { type: 'boolean' },
|
|
62
71
|
},
|
|
63
72
|
});
|
|
64
73
|
const browser = values.browser;
|
|
@@ -76,12 +85,35 @@ export function parseCiArgs(argv) {
|
|
|
76
85
|
flakyRuns: intOption(values['flaky-runs'], 'flaky-runs', 2, 10),
|
|
77
86
|
suggest: intOption(values.suggest, 'suggest', 0, 5) ?? 0,
|
|
78
87
|
output: values.output,
|
|
88
|
+
verifyFixes: values['verify-fixes'] === true,
|
|
89
|
+
suggestions: values.suggestions,
|
|
90
|
+
review: values.review === true,
|
|
79
91
|
testFiles: positionals,
|
|
80
92
|
};
|
|
81
93
|
}
|
|
82
94
|
function text(response) {
|
|
83
95
|
return response.content.map((block) => block.text).join('\n');
|
|
84
96
|
}
|
|
97
|
+
function structured(response) {
|
|
98
|
+
return response.structuredContent;
|
|
99
|
+
}
|
|
100
|
+
/** Put the original line back after a verification run applied a fix. */
|
|
101
|
+
async function restoreLine(file, line, before, after) {
|
|
102
|
+
const source = await readFile(file, 'utf8');
|
|
103
|
+
const eol = source.includes('\r\n') ? '\r\n' : '\n';
|
|
104
|
+
const lines = source.split(/\r?\n/);
|
|
105
|
+
if (lines[line - 1] !== after)
|
|
106
|
+
return;
|
|
107
|
+
lines[line - 1] = before;
|
|
108
|
+
await writeFile(file, lines.join(eol), 'utf8');
|
|
109
|
+
}
|
|
110
|
+
/** A project-relative file as a repository-relative posix path, or undefined outside the repository. */
|
|
111
|
+
export function repoPath(projectRoot, file, repoRoot) {
|
|
112
|
+
const relative = path.relative(path.resolve(repoRoot), path.resolve(projectRoot, file));
|
|
113
|
+
if (relative === '' || relative.startsWith('..') || path.isAbsolute(relative))
|
|
114
|
+
return undefined;
|
|
115
|
+
return relative.split(path.sep).join('/');
|
|
116
|
+
}
|
|
85
117
|
/** Run the CI flow; returns the exit code. */
|
|
86
118
|
export async function runCi(argv) {
|
|
87
119
|
let options;
|
|
@@ -116,12 +148,72 @@ export async function runCi(argv) {
|
|
|
116
148
|
const result = ctx.store.lastRun?.result;
|
|
117
149
|
const failures = result?.failures ?? [];
|
|
118
150
|
let code = result === undefined || run.isError ? 2 : result.ok ? 0 : failures.length > 0 ? 1 : 2;
|
|
119
|
-
|
|
151
|
+
const fixes = [];
|
|
152
|
+
const suggest = options.review || options.suggestions ? Math.max(options.suggest, 1) : options.suggest;
|
|
153
|
+
if (code === 1 && suggest > 0 && ctx.store.lastRun) {
|
|
120
154
|
// Before diagnose-flaky, which replaces the last run suggest-fix indexes into.
|
|
121
|
-
|
|
155
|
+
// A verification run replaces it too, so each fix starts from the suite run.
|
|
156
|
+
const suiteRun = ctx.store.lastRun;
|
|
157
|
+
const count = Math.min(suggest, suiteRun.result.failures.length);
|
|
122
158
|
for (let index = 1; index <= count; index += 1) {
|
|
123
|
-
|
|
124
|
-
|
|
159
|
+
ctx.store.setLastRun(suiteRun);
|
|
160
|
+
const response = await suggestFixTool.handler({ index, config: options.config }, ctx);
|
|
161
|
+
let section = text(response).replace(/^## /m, '### ');
|
|
162
|
+
const fix = structured(response)?.fix;
|
|
163
|
+
let verified = false;
|
|
164
|
+
if (fix && options.verifyFixes) {
|
|
165
|
+
ctx.store.setLastRun(suiteRun);
|
|
166
|
+
const trial = await suggestFixTool.handler({ index, config: options.config, apply: true, allowExpectationUpdate: true }, ctx);
|
|
167
|
+
verified = structured(trial)?.verified === true;
|
|
168
|
+
// A passing fix stays written by suggest-fix; CI only reports it.
|
|
169
|
+
if (verified)
|
|
170
|
+
await restoreLine(path.resolve(projectRoot, fix.file), fix.line, fix.before, fix.after);
|
|
171
|
+
section += verified
|
|
172
|
+
? '\n\n✅ **Verified in CI:** the test passes with this change.'
|
|
173
|
+
: '\n\n⚠️ **Not verified:** the test still failed with this change in CI.';
|
|
174
|
+
}
|
|
175
|
+
sections.push(section);
|
|
176
|
+
const failure = suiteRun.result.failures[index - 1];
|
|
177
|
+
const target = fix ? repoPath(projectRoot, fix.file, process.env.GITHUB_WORKSPACE ?? projectRoot) : undefined;
|
|
178
|
+
if (fix && target && (verified || !options.verifyFixes)) {
|
|
179
|
+
fixes.push({
|
|
180
|
+
path: target,
|
|
181
|
+
line: fix.line,
|
|
182
|
+
before: fix.before,
|
|
183
|
+
after: fix.after,
|
|
184
|
+
kind: fix.kind,
|
|
185
|
+
confidence: fix.confidence,
|
|
186
|
+
why: fix.why,
|
|
187
|
+
verified,
|
|
188
|
+
test: failure?.title ?? fix.file,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
ctx.store.setLastRun(suiteRun);
|
|
193
|
+
}
|
|
194
|
+
if (options.suggestions) {
|
|
195
|
+
try {
|
|
196
|
+
await writeFile(options.suggestions, `${JSON.stringify(fixes, null, 2)}\n`, 'utf8');
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
process.stderr.write(`could not write the suggestions: ${err.message}\n`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (options.review && fixes.length > 0) {
|
|
203
|
+
const pr = await pullRequestFromEnv();
|
|
204
|
+
if (!pr) {
|
|
205
|
+
process.stderr.write('--review: not a pull_request run, or no GITHUB_TOKEN/GH_TOKEN; fixes stay in the report.\n');
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
const review = await postSuggestionReview(fixes, pr);
|
|
209
|
+
if (review.error)
|
|
210
|
+
process.stderr.write(`::warning::Could not post suggested fixes: ${review.error}\n`);
|
|
211
|
+
else if (review.posted.length > 0) {
|
|
212
|
+
sections.push(`💡 Posted ${review.posted.length === 1 ? 'a suggested change' : `${review.posted.length} suggested changes`} on this PR: use **Commit suggestion** to apply.`);
|
|
213
|
+
}
|
|
214
|
+
if (review.outsideDiff.length > 0) {
|
|
215
|
+
process.stderr.write(`${review.outsideDiff.length} fix(es) are on lines this PR did not change, so they are only in the report.\n`);
|
|
216
|
+
}
|
|
125
217
|
}
|
|
126
218
|
}
|
|
127
219
|
if (code === 1 && options.flakyRuns) {
|
package/dist/cli/ci.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ci.js","sourceRoot":"","sources":["../../src/cli/ci.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"ci.js","sourceRoot":"","sources":["../../src/cli/ci.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGvE,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,sDAAsD;IACtD,EAAE;IACF,8EAA8E;IAC9E,uFAAuF;IACvF,EAAE;IACF,kFAAkF;IAClF,kEAAkE;IAClE,sDAAsD;IACtD,yDAAyD;IACzD,6CAA6C;IAC7C,wEAAwE;IACxE,0DAA0D;IAC1D,kFAAkF;IAClF,mFAAmF;IACnF,gFAAgF;IAChF,2FAA2F;IAC3F,wFAAwF;IACxF,wFAAwF;IACxF,qFAAqF;IACrF,EAAE;CACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAmBb,SAAS,SAAS,CAAC,KAAyB,EAAE,IAAY,EAAE,GAAW,EAAE,GAAW;IAClF,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACxB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,KAAK,IAAI,4BAA4B,GAAG,OAAO,GAAG,EAAE,CAAC,CAAC;IACtH,OAAO,CAAC,CAAC;AACX,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,WAAW,CAAC,IAAc;IACxC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;QACxC,IAAI,EAAE,IAAI;QACV,gBAAgB,EAAE,IAAI;QACtB,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE;YACP,cAAc,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAClC,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC1B,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC3B,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACxB,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC3B,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC3B,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;YAC/B,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAChC,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC3B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC1B,cAAc,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;YACnC,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC/B,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;SAC5B;KACF,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IAC/B,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,UAAU,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACrG,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACnE,CAAC;IACD,OAAO;QACL,WAAW,EAAE,MAAM,CAAC,cAAc,CAAC;QACnC,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,OAAO;QACP,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,OAAO,EAAE,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC;QACpD,SAAS,EAAE,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC,IAAI,OAAO;QAC5E,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,KAAK,IAAI;QAClC,SAAS,EAAE,SAAS,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/D,OAAO,EAAE,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC;QACxD,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,WAAW,EAAE,MAAM,CAAC,cAAc,CAAC,KAAK,IAAI;QAC5C,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,KAAK,IAAI;QAC9B,SAAS,EAAE,WAAW;KACvB,CAAC;AACJ,CAAC;AAED,SAAS,IAAI,CAAC,QAAsB;IAClC,OAAO,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,UAAU,CAAC,QAAsB;IACxC,OAAO,QAAQ,CAAC,iBAAiD,CAAC;AACpE,CAAC;AAED,yEAAyE;AACzE,KAAK,UAAU,WAAW,CAAC,IAAY,EAAE,IAAY,EAAE,MAAc,EAAE,KAAa;IAClF,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IACpD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACpC,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,KAAK,KAAK;QAAE,OAAO;IACtC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC;IACzB,MAAM,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;AACjD,CAAC;AAED,wGAAwG;AACxG,MAAM,UAAU,QAAQ,CAAC,WAAmB,EAAE,IAAY,EAAE,QAAgB;IAC1E,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC;IACxF,IAAI,QAAQ,KAAK,EAAE,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAC;IAChG,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC5C,CAAC;AAED,8CAA8C;AAC9C,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,IAAc;IACxC,IAAI,OAAkB,CAAC;IACvB,IAAI,CAAC;QACH,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAI,GAAa,CAAC,OAAO,OAAO,QAAQ,EAAE,CAAC,CAAC;QACjE,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAC5F,MAAM,GAAG,GAAgB;QACvB,sEAAsE;QACtE,MAAM,EAAE,YAAY,CAAC;YACnB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM;YAC9E,QAAQ,EAAE,EAAE,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,IAAI,EAAE;SACrD,CAAC;QACF,KAAK,EAAE,eAAe,EAAE;QACxB,WAAW;KACZ,CAAC;IAEF,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,OAAO,CACnC;QACE,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;QACvE,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,cAAc,EAAE,OAAO,CAAC,KAAK;QAC7B,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,EACD,GAAG,CACJ,CAAC;IACF,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAEzB,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC;IACzC,MAAM,QAAQ,GAAG,MAAM,EAAE,QAAQ,IAAI,EAAE,CAAC;IACxC,IAAI,IAAI,GAAG,MAAM,KAAK,SAAS,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEjG,MAAM,KAAK,GAAoB,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IACvG,IAAI,IAAI,KAAK,CAAC,IAAI,OAAO,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QACnD,+EAA+E;QAC/E,6EAA6E;QAC7E,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC;QACnC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACjE,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,IAAI,KAAK,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;YAC/C,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YAC/B,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC;YACtF,IAAI,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACtD,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC;YACtC,IAAI,QAAQ,GAAG,KAAK,CAAC;YACrB,IAAI,GAAG,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;gBAC/B,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;gBAC/B,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,OAAO,CACxC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,sBAAsB,EAAE,IAAI,EAAE,EAC5E,GAAG,CACJ,CAAC;gBACF,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,EAAE,QAAQ,KAAK,IAAI,CAAC;gBAChD,kEAAkE;gBAClE,IAAI,QAAQ;oBAAE,MAAM,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;gBACtG,OAAO,IAAI,QAAQ;oBACjB,CAAC,CAAC,6DAA6D;oBAC/D,CAAC,CAAC,wEAAwE,CAAC;YAC/E,CAAC;YACD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACvB,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YACpD,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC9G,IAAI,GAAG,IAAI,MAAM,IAAI,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;gBACxD,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,KAAK,EAAE,GAAG,CAAC,KAAK;oBAChB,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,UAAU,EAAE,GAAG,CAAC,UAAU;oBAC1B,GAAG,EAAE,GAAG,CAAC,GAAG;oBACZ,QAAQ;oBACR,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,CAAC,IAAI;iBACjC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QACD,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IACjC,CAAC;IAED,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACtF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oCAAqC,GAAa,CAAC,OAAO,IAAI,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvC,MAAM,EAAE,GAAG,MAAM,kBAAkB,EAAE,CAAC;QACtC,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4FAA4F,CAAC,CAAC;QACrH,CAAC;aAAM,CAAC;YACN,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACrD,IAAI,MAAM,CAAC,KAAK;gBAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8CAA8C,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;iBAClG,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAClC,QAAQ,CAAC,IAAI,CACX,aAAa,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,oBAAoB,kDAAkD,CAC/J,CAAC;YACJ,CAAC;YACD,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAClC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,iFAAiF,CAAC,CAAC;YACtI,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,IAAI,KAAK,CAAC,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACpC,MAAM,KAAK,GAAG,MAAM,iBAAiB,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC;QAClI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,mGAAmG,CAAC;IAClJ,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,CAAC;QACH,IAAI,OAAO,CAAC,MAAM;YAAE,MAAM,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QACpE,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB;YAAE,MAAM,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACzG,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,+BAAgC,GAAa,CAAC,OAAO,IAAI,CAAC,CAAC;QAChF,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `playwright-e2e-mcp doctor`: checks the things a first run usually trips
|
|
3
|
+
* on and says how to fix each one: Node version, the Playwright config and
|
|
4
|
+
* install, installed browsers, test files, and whether the server and the
|
|
5
|
+
* agent skill are wired into the project's MCP clients.
|
|
6
|
+
*
|
|
7
|
+
* It only reads: nothing is installed or written.
|
|
8
|
+
*
|
|
9
|
+
* Exit codes: 0 nothing failed (warnings allowed), 1 a check failed,
|
|
10
|
+
* 2 bad arguments.
|
|
11
|
+
*/
|
|
12
|
+
export declare const DOCTOR_USAGE: string;
|
|
13
|
+
/** Oldest Node major the server supports. */
|
|
14
|
+
export declare const MIN_NODE_MAJOR = 22;
|
|
15
|
+
export type CheckStatus = 'ok' | 'warn' | 'fail';
|
|
16
|
+
export interface DoctorCheck {
|
|
17
|
+
name: string;
|
|
18
|
+
status: CheckStatus;
|
|
19
|
+
detail: string;
|
|
20
|
+
/** What to run or change; present for warn and fail. */
|
|
21
|
+
fix?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface DoctorReport {
|
|
24
|
+
version: string;
|
|
25
|
+
projectRoot: string;
|
|
26
|
+
checks: DoctorCheck[];
|
|
27
|
+
ok: boolean;
|
|
28
|
+
}
|
|
29
|
+
export declare function runDoctorChecks(projectRoot: string, home?: string): Promise<DoctorReport>;
|
|
30
|
+
export declare function renderDoctorReport(report: DoctorReport): string;
|
|
31
|
+
export declare function runDoctor(argv: string[], out?: (text: string) => void): Promise<number>;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `playwright-e2e-mcp doctor`: checks the things a first run usually trips
|
|
3
|
+
* on and says how to fix each one: Node version, the Playwright config and
|
|
4
|
+
* install, installed browsers, test files, and whether the server and the
|
|
5
|
+
* agent skill are wired into the project's MCP clients.
|
|
6
|
+
*
|
|
7
|
+
* It only reads: nothing is installed or written.
|
|
8
|
+
*
|
|
9
|
+
* Exit codes: 0 nothing failed (warnings allowed), 1 a check failed,
|
|
10
|
+
* 2 bad arguments.
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
13
|
+
import { createRequire } from 'node:module';
|
|
14
|
+
import os from 'node:os';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
import { parseArgs } from 'node:util';
|
|
17
|
+
import { detectProject, findTestFiles } from '../utils/project-detector.js';
|
|
18
|
+
import { SERVER_VERSION } from '../server.js';
|
|
19
|
+
import { SERVER_NAME, SKILL_NAME } from './init.js';
|
|
20
|
+
export const DOCTOR_USAGE = [
|
|
21
|
+
'Usage: playwright-e2e-mcp doctor [options]',
|
|
22
|
+
'',
|
|
23
|
+
'Checks Node, the Playwright config and install, browsers, test files and the',
|
|
24
|
+
'MCP client setup, and says how to fix anything missing. Reads only.',
|
|
25
|
+
'',
|
|
26
|
+
' --project-root <dir> project directory (default: cwd)',
|
|
27
|
+
' --json print the checks as JSON',
|
|
28
|
+
'',
|
|
29
|
+
].join('\n');
|
|
30
|
+
/** Oldest Node major the server supports. */
|
|
31
|
+
export const MIN_NODE_MAJOR = 22;
|
|
32
|
+
/** Where each client keeps its project-scoped MCP config (see init). */
|
|
33
|
+
function clientConfigs(root, home) {
|
|
34
|
+
return [
|
|
35
|
+
{ client: 'Claude Code', file: path.join(root, '.mcp.json') },
|
|
36
|
+
{ client: 'Cursor', file: path.join(root, '.cursor', 'mcp.json') },
|
|
37
|
+
{ client: 'VS Code', file: path.join(root, '.vscode', 'mcp.json') },
|
|
38
|
+
{ client: 'Gemini CLI', file: path.join(root, '.gemini', 'settings.json') },
|
|
39
|
+
{ client: 'Codex', file: path.join(root, '.codex', 'config.toml') },
|
|
40
|
+
{ client: 'Windsurf', file: path.join(home, '.codeium', 'windsurf', 'mcp_config.json') },
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
function mentionsServer(file) {
|
|
44
|
+
try {
|
|
45
|
+
const text = readFileSync(file, 'utf8');
|
|
46
|
+
return text.includes(`"${SERVER_NAME}"`) || text.includes(`mcp_servers.${SERVER_NAME}`) || text.includes('playwright-e2e-mcp');
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function nodeCheck(version = process.versions.node) {
|
|
53
|
+
const major = Number(version.split('.')[0]);
|
|
54
|
+
if (major >= MIN_NODE_MAJOR)
|
|
55
|
+
return { name: 'Node.js', status: 'ok', detail: `v${version}` };
|
|
56
|
+
return {
|
|
57
|
+
name: 'Node.js',
|
|
58
|
+
status: 'fail',
|
|
59
|
+
detail: `v${version} is older than the supported ${MIN_NODE_MAJOR}`,
|
|
60
|
+
fix: `Install Node.js ${MIN_NODE_MAJOR} or newer (https://nodejs.org)`,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** Each browser's install state, read through the project's own Playwright. */
|
|
64
|
+
function browserChecks(root, playwrightPackage) {
|
|
65
|
+
let pw;
|
|
66
|
+
try {
|
|
67
|
+
pw = createRequire(path.join(root, 'package.json'))(playwrightPackage);
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
return [
|
|
71
|
+
{
|
|
72
|
+
name: 'Browsers',
|
|
73
|
+
status: 'fail',
|
|
74
|
+
detail: `could not load ${playwrightPackage}: ${err.message.split('\n')[0]}`,
|
|
75
|
+
fix: 'Reinstall dependencies (npm install), then npx playwright install chromium',
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
}
|
|
79
|
+
const installed = [];
|
|
80
|
+
const missing = [];
|
|
81
|
+
for (const name of ['chromium', 'firefox', 'webkit']) {
|
|
82
|
+
let executable = '';
|
|
83
|
+
try {
|
|
84
|
+
executable = pw[name]?.executablePath() ?? '';
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
executable = '';
|
|
88
|
+
}
|
|
89
|
+
(executable && existsSync(executable) ? installed : missing).push(name);
|
|
90
|
+
}
|
|
91
|
+
if (!installed.includes('chromium')) {
|
|
92
|
+
return [
|
|
93
|
+
{
|
|
94
|
+
name: 'Browsers',
|
|
95
|
+
status: 'fail',
|
|
96
|
+
detail: installed.length ? `Chromium is missing (installed: ${installed.join(', ')})` : 'no browsers installed for this Playwright version',
|
|
97
|
+
fix: 'npx playwright install chromium',
|
|
98
|
+
},
|
|
99
|
+
];
|
|
100
|
+
}
|
|
101
|
+
return [{ name: 'Browsers', status: 'ok', detail: `installed: ${installed.join(', ')}${missing.length ? ` (not installed: ${missing.join(', ')})` : ''}` }];
|
|
102
|
+
}
|
|
103
|
+
export async function runDoctorChecks(projectRoot, home = os.homedir()) {
|
|
104
|
+
const checks = [nodeCheck()];
|
|
105
|
+
const detection = await detectProject(projectRoot);
|
|
106
|
+
const root = detection.root;
|
|
107
|
+
if (!detection.configPath) {
|
|
108
|
+
checks.push({
|
|
109
|
+
name: 'Playwright config',
|
|
110
|
+
status: 'fail',
|
|
111
|
+
detail: `no playwright.config.* in ${projectRoot} or its parents`,
|
|
112
|
+
fix: 'Run this in your Playwright project, or create one with npm init playwright@latest',
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
else if (detection.configCandidates.length > 1) {
|
|
116
|
+
checks.push({
|
|
117
|
+
name: 'Playwright config',
|
|
118
|
+
status: 'warn',
|
|
119
|
+
detail: `${detection.configCandidates.length} configs in ${root}; tools use ${path.basename(detection.configPath)} unless told otherwise`,
|
|
120
|
+
fix: 'Pass the config you mean to run-test, or keep one config per folder',
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
checks.push({ name: 'Playwright config', status: 'ok', detail: path.relative(projectRoot, detection.configPath) || detection.configPath });
|
|
125
|
+
}
|
|
126
|
+
if (!detection.hasPlaywright || !detection.playwrightPackage) {
|
|
127
|
+
checks.push({
|
|
128
|
+
name: 'Playwright',
|
|
129
|
+
status: 'fail',
|
|
130
|
+
detail: 'neither @playwright/test nor playwright is installed in node_modules',
|
|
131
|
+
fix: 'npm install -D @playwright/test',
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
checks.push({ name: 'Playwright', status: 'ok', detail: `${detection.playwrightPackage} ${detection.playwrightVersion ?? '(unknown version)'}` });
|
|
136
|
+
checks.push(...browserChecks(root, detection.playwrightPackage));
|
|
137
|
+
}
|
|
138
|
+
if (detection.configPath) {
|
|
139
|
+
const files = await findTestFiles(root, { testDir: detection.testDir, limit: 1000 });
|
|
140
|
+
checks.push(files.length
|
|
141
|
+
? { name: 'Test files', status: 'ok', detail: `${files.length}${files.length >= 1000 ? '+' : ''} found` }
|
|
142
|
+
: {
|
|
143
|
+
name: 'Test files',
|
|
144
|
+
status: 'warn',
|
|
145
|
+
detail: `none found under ${detection.testDir ? path.relative(root, detection.testDir) || '.' : 'the project'}`,
|
|
146
|
+
fix: 'Add a *.spec.ts file, or ask your agent to write one with generate-e2e-test',
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
const configured = clientConfigs(projectRoot, home).filter(({ file }) => mentionsServer(file));
|
|
150
|
+
checks.push(configured.length
|
|
151
|
+
? { name: 'MCP clients', status: 'ok', detail: `set up for ${configured.map((c) => c.client).join(', ')}` }
|
|
152
|
+
: {
|
|
153
|
+
name: 'MCP clients',
|
|
154
|
+
status: 'warn',
|
|
155
|
+
detail: 'no project config for Claude Code, Cursor, VS Code, Gemini CLI, Codex or Windsurf mentions the server',
|
|
156
|
+
fix: 'npx -y playwright-e2e-mcp init (or add it in your client by hand; see the README)',
|
|
157
|
+
});
|
|
158
|
+
const skill = [path.join(projectRoot, '.agents', 'skills', SKILL_NAME), path.join(projectRoot, '.claude', 'skills', SKILL_NAME)].find((dir) => existsSync(path.join(dir, 'SKILL.md')));
|
|
159
|
+
checks.push(skill
|
|
160
|
+
? { name: 'Agent skill', status: 'ok', detail: path.relative(projectRoot, skill) }
|
|
161
|
+
: { name: 'Agent skill', status: 'warn', detail: 'not installed in this project', fix: 'npx -y playwright-e2e-mcp init' });
|
|
162
|
+
return { version: SERVER_VERSION, projectRoot, checks, ok: !checks.some((c) => c.status === 'fail') };
|
|
163
|
+
}
|
|
164
|
+
const MARK = { ok: '✓', warn: '!', fail: '✗' };
|
|
165
|
+
export function renderDoctorReport(report) {
|
|
166
|
+
const width = Math.max(...report.checks.map((c) => c.name.length));
|
|
167
|
+
const lines = [`playwright-e2e-mcp ${report.version} doctor: ${report.projectRoot}`, ''];
|
|
168
|
+
for (const check of report.checks) {
|
|
169
|
+
lines.push(`${MARK[check.status]} ${check.name.padEnd(width)} ${check.detail}`);
|
|
170
|
+
if (check.fix)
|
|
171
|
+
lines.push(` ${' '.repeat(width)} fix: ${check.fix}`);
|
|
172
|
+
}
|
|
173
|
+
const failed = report.checks.filter((c) => c.status === 'fail').length;
|
|
174
|
+
const warned = report.checks.filter((c) => c.status === 'warn').length;
|
|
175
|
+
lines.push('');
|
|
176
|
+
lines.push(failed
|
|
177
|
+
? `${failed} problem${failed === 1 ? '' : 's'} to fix before the tools can run your tests.`
|
|
178
|
+
: warned
|
|
179
|
+
? `Ready, with ${warned} suggestion${warned === 1 ? '' : 's'} above.`
|
|
180
|
+
: 'Everything is ready.');
|
|
181
|
+
return `${lines.join('\n')}\n`;
|
|
182
|
+
}
|
|
183
|
+
export async function runDoctor(argv, out = (t) => process.stdout.write(t)) {
|
|
184
|
+
let values;
|
|
185
|
+
try {
|
|
186
|
+
({ values } = parseArgs({
|
|
187
|
+
args: argv,
|
|
188
|
+
strict: true,
|
|
189
|
+
options: { 'project-root': { type: 'string' }, json: { type: 'boolean' } },
|
|
190
|
+
}));
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
out(`doctor: ${err.message}\n\n${DOCTOR_USAGE}`);
|
|
194
|
+
return 2;
|
|
195
|
+
}
|
|
196
|
+
const report = await runDoctorChecks(path.resolve(values['project-root'] ?? '.'));
|
|
197
|
+
out(values.json ? `${JSON.stringify(report, null, 2)}\n` : renderDoctorReport(report));
|
|
198
|
+
return report.ok ? 0 : 1;
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEpD,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,4CAA4C;IAC5C,EAAE;IACF,8EAA8E;IAC9E,qEAAqE;IACrE,EAAE;IACF,2DAA2D;IAC3D,mDAAmD;IACnD,EAAE;CACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,6CAA6C;AAC7C,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAC;AAmBjC,wEAAwE;AACxE,SAAS,aAAa,CAAC,IAAY,EAAE,IAAY;IAC/C,OAAO;QACL,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE;QAC7D,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC,EAAE;QAClE,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC,EAAE;QACnE,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,eAAe,CAAC,EAAE;QAC3E,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE;QACnE,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,iBAAiB,CAAC,EAAE;KACzF,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,IAAY;IAClC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACxC,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,WAAW,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,eAAe,WAAW,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;IACjI,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI;IAChD,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,IAAI,KAAK,IAAI,cAAc;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,OAAO,EAAE,EAAE,CAAC;IAC7F,OAAO;QACL,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,MAAM;QACd,MAAM,EAAE,IAAI,OAAO,gCAAgC,cAAc,EAAE;QACnE,GAAG,EAAE,mBAAmB,cAAc,gCAAgC;KACvE,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,SAAS,aAAa,CAAC,IAAY,EAAE,iBAAyB;IAC5D,IAAI,EAA4D,CAAC;IACjE,IAAI,CAAC;QACH,EAAE,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,iBAAiB,CAAc,CAAC;IACtF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL;gBACE,IAAI,EAAE,UAAU;gBAChB,MAAM,EAAE,MAAM;gBACd,MAAM,EAAE,kBAAkB,iBAAiB,KAAM,GAAa,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;gBACvF,GAAG,EAAE,4EAA4E;aAClF;SACF,CAAC;IACJ,CAAC;IACD,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,IAAI,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,CAAC;QACrD,IAAI,UAAU,GAAG,EAAE,CAAC;QACpB,IAAI,CAAC;YACH,UAAU,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC;QAChD,CAAC;QAAC,MAAM,CAAC;YACP,UAAU,GAAG,EAAE,CAAC;QAClB,CAAC;QACD,CAAC,UAAU,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QACpC,OAAO;YACL;gBACE,IAAI,EAAE,UAAU;gBAChB,MAAM,EAAE,MAAM;gBACd,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,mCAAmC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,mDAAmD;gBAC3I,GAAG,EAAE,iCAAiC;aACvC;SACF,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,oBAAoB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AAC9J,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,WAAmB,EAAE,IAAI,GAAG,EAAE,CAAC,OAAO,EAAE;IAC5E,MAAM,MAAM,GAAkB,CAAC,SAAS,EAAE,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,WAAW,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC;IAE5B,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC;QAC1B,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,mBAAmB;YACzB,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,6BAA6B,WAAW,iBAAiB;YACjE,GAAG,EAAE,oFAAoF;SAC1F,CAAC,CAAC;IACL,CAAC;SAAM,IAAI,SAAS,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjD,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,mBAAmB;YACzB,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,GAAG,SAAS,CAAC,gBAAgB,CAAC,MAAM,eAAe,IAAI,eAAe,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,UAAU,CAAC,wBAAwB;YACzI,GAAG,EAAE,qEAAqE;SAC3E,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,SAAS,CAAC,UAAU,CAAC,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC,CAAC;IAC7I,CAAC;IAED,IAAI,CAAC,SAAS,CAAC,aAAa,IAAI,CAAC,SAAS,CAAC,iBAAiB,EAAE,CAAC;QAC7D,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,YAAY;YAClB,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,sEAAsE;YAC9E,GAAG,EAAE,iCAAiC;SACvC,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,iBAAiB,IAAI,SAAS,CAAC,iBAAiB,IAAI,mBAAmB,EAAE,EAAE,CAAC,CAAC;QAClJ,MAAM,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,IAAI,EAAE,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACnE,CAAC;IAED,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACrF,MAAM,CAAC,IAAI,CACT,KAAK,CAAC,MAAM;YACV,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE;YACzG,CAAC,CAAC;gBACE,IAAI,EAAE,YAAY;gBAClB,MAAM,EAAE,MAAM;gBACd,MAAM,EAAE,oBAAoB,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,aAAa,EAAE;gBAC/G,GAAG,EAAE,6EAA6E;aACnF,CACN,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/F,MAAM,CAAC,IAAI,CACT,UAAU,CAAC,MAAM;QACf,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE;QAC3G,CAAC,CAAC;YACE,IAAI,EAAE,aAAa;YACnB,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,uGAAuG;YAC/G,GAAG,EAAE,mFAAmF;SACzF,CACN,CAAC;IAEF,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAC5I,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,CACvC,CAAC;IACF,MAAM,CAAC,IAAI,CACT,KAAK;QACH,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAC,EAAE;QAClF,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,+BAA+B,EAAE,GAAG,EAAE,gCAAgC,EAAE,CAC5H,CAAC;IAEF,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,EAAE,CAAC;AACxG,CAAC;AAED,MAAM,IAAI,GAAgC,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;AAE5E,MAAM,UAAU,kBAAkB,CAAC,MAAoB;IACrD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IACnE,MAAM,KAAK,GAAG,CAAC,sBAAsB,MAAM,CAAC,OAAO,YAAY,MAAM,CAAC,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;IACzF,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QACjF,IAAI,KAAK,CAAC,GAAG;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;IACvE,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;IACvE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CACR,MAAM;QACJ,CAAC,CAAC,GAAG,MAAM,WAAW,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,8CAA8C;QAC3F,CAAC,CAAC,MAAM;YACN,CAAC,CAAC,eAAe,MAAM,cAAc,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,SAAS;YACrE,CAAC,CAAC,sBAAsB,CAC7B,CAAC;IACF,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACjC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAc,EAAE,GAAG,GAA2B,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1G,IAAI,MAAmD,CAAC;IACxD,IAAI,CAAC;QACH,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;YACtB,IAAI,EAAE,IAAI;YACV,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,EAAE,cAAc,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE;SAC3E,CAAC,CAAC,CAAC;IACN,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,WAAY,GAAa,CAAC,OAAO,OAAO,YAAY,EAAE,CAAC,CAAC;QAC5D,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IAClF,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;IACvF,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3B,CAAC"}
|
package/dist/cli/init.js
CHANGED
|
@@ -213,7 +213,8 @@ export function runInit(argv, out = (l) => process.stdout.write(`${l}\n`)) {
|
|
|
213
213
|
}
|
|
214
214
|
out('');
|
|
215
215
|
out('Next: make sure browsers are installed (npx playwright install chromium), then');
|
|
216
|
-
out('restart or reload the agent so it picks up the new server.');
|
|
216
|
+
out('restart or reload the agent so it picks up the new server. Check the setup any');
|
|
217
|
+
out('time with: npx -y playwright-e2e-mcp doctor');
|
|
217
218
|
return changes.some((c) => c.action === 'error') ? 1 : 0;
|
|
218
219
|
}
|
|
219
220
|
//# sourceMappingURL=init.js.map
|