playwright-e2e-mcp 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +39 -9
  2. package/dist/apps/index.d.ts +29 -0
  3. package/dist/apps/index.js +52 -0
  4. package/dist/apps/index.js.map +1 -0
  5. package/dist/apps/test-report-html.d.ts +15 -0
  6. package/dist/apps/test-report-html.js +430 -0
  7. package/dist/apps/test-report-html.js.map +1 -0
  8. package/dist/cli/upload.d.ts +6 -5
  9. package/dist/cli/upload.js +20 -17
  10. package/dist/cli/upload.js.map +1 -1
  11. package/dist/index.js +4 -2
  12. package/dist/index.js.map +1 -1
  13. package/dist/oauth.d.ts +12 -2
  14. package/dist/oauth.js +44 -6
  15. package/dist/oauth.js.map +1 -1
  16. package/dist/server.js +17 -0
  17. package/dist/server.js.map +1 -1
  18. package/dist/tools/analyze-history.js +9 -9
  19. package/dist/tools/analyze-history.js.map +1 -1
  20. package/dist/tools/audit-tests.js +24 -6
  21. package/dist/tools/audit-tests.js.map +1 -1
  22. package/dist/tools/compare-visual-state.js +7 -1
  23. package/dist/tools/compare-visual-state.js.map +1 -1
  24. package/dist/tools/generate-e2e-test.js +27 -12
  25. package/dist/tools/generate-e2e-test.js.map +1 -1
  26. package/dist/tools/quarantine.js +7 -1
  27. package/dist/tools/quarantine.js.map +1 -1
  28. package/dist/tools/shared.d.ts +10 -0
  29. package/dist/tools/shared.js +15 -0
  30. package/dist/tools/shared.js.map +1 -1
  31. package/dist/tools/structured.d.ts +2 -0
  32. package/dist/tools/structured.js +4 -2
  33. package/dist/tools/structured.js.map +1 -1
  34. package/dist/tools/suggest-fix.js +6 -1
  35. package/dist/tools/suggest-fix.js.map +1 -1
  36. package/dist/types/index.d.ts +9 -0
  37. package/dist/utils/client-metadata.d.ts +46 -0
  38. package/dist/utils/client-metadata.js +174 -0
  39. package/dist/utils/client-metadata.js.map +1 -0
  40. package/dist/utils/confirm.d.ts +68 -0
  41. package/dist/utils/confirm.js +120 -0
  42. package/dist/utils/confirm.js.map +1 -0
  43. package/dist/utils/history-client.d.ts +32 -0
  44. package/dist/utils/{pro-client.js → history-client.js} +27 -20
  45. package/dist/utils/history-client.js.map +1 -0
  46. package/examples/github-actions/playwright-e2e.yml +5 -4
  47. package/package.json +1 -1
  48. package/skill/playwright-e2e-mcp/SKILL.md +8 -3
  49. package/skill/playwright-e2e-mcp/references/setup.md +2 -2
  50. package/dist/utils/pro-client.d.ts +0 -29
  51. package/dist/utils/pro-client.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-metadata.js","sourceRoot":"","sources":["../../src/utils/client-metadata.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Ask the person before a tool changes files in their project.
3
+ *
4
+ * Tools that write test code or project state (suggest-fix `apply`,
5
+ * generate-e2e-test, quarantine add/remove, compare-visual-state `baseline`)
6
+ * call `ctx.confirmWrite()` right before the write, with the exact change
7
+ * they are about to make. When the client can show a form (MCP elicitation),
8
+ * the server answers the call with an `input_required` result (the
9
+ * 2026-07-28 multi-round-trip pattern; the SDK turns it into a classic
10
+ * elicitation request for 2025 clients). The client shows the change, the
11
+ * person says yes or no, and the client retries the call with the answer.
12
+ *
13
+ * The approval is bound to the change: the question's key is a hash of the
14
+ * tool, title and detail, so if the retried call would write something
15
+ * different it asks again instead of reusing an old "yes".
16
+ *
17
+ * PW_MCP_CONFIRM_WRITES:
18
+ * auto (default) ask when the client supports elicitation; otherwise
19
+ * write as before and say no one was asked
20
+ * always ask, and refuse to write when the client cannot ask
21
+ * off never ask
22
+ */
23
+ import type { InputRequiredResult } from '@modelcontextprotocol/server';
24
+ export type ConfirmMode = 'auto' | 'always' | 'off';
25
+ /** What the tool is about to do, shown to the person. */
26
+ export interface WriteConfirmation {
27
+ /** One line: "Apply this fix to tests/cart.spec.ts:42?" */
28
+ title: string;
29
+ /** The change itself (a diff, the file to be written, the entry to add). */
30
+ detail: string;
31
+ }
32
+ /**
33
+ * - `approved`: the person said yes.
34
+ * - `declined`: the person said no (or cancelled): do not write.
35
+ * - `not-asked`: confirmation is off, or the client cannot ask: write as before.
36
+ */
37
+ export type ConfirmOutcome = 'approved' | 'declined' | 'not-asked';
38
+ export type ConfirmWrite = (request: WriteConfirmation) => Promise<ConfirmOutcome>;
39
+ /**
40
+ * Thrown by `confirmWrite` when the person has to be asked. It carries the
41
+ * `input_required` result; the server returns it instead of a tool result.
42
+ * Tools must let it through (guard() rethrows it).
43
+ */
44
+ export declare class ConfirmationPending extends Error {
45
+ readonly result: InputRequiredResult;
46
+ constructor(result: InputRequiredResult);
47
+ }
48
+ export declare function confirmMode(value?: string | undefined): ConfirmMode;
49
+ /** Longest change shown in the question; clients show it as plain text. */
50
+ export declare const MAX_DETAIL_CHARS = 4000;
51
+ /** Whether declared client capabilities include form-mode elicitation. */
52
+ export declare function supportsFormElicitation(capabilities: unknown): boolean;
53
+ /** The input key for one exact change: a new change gets a new question. */
54
+ export declare function confirmationKey(tool: string, request: WriteConfirmation): string;
55
+ export interface ConfirmerOptions {
56
+ tool: string;
57
+ /** Retried-call answers (`ctx.mcpReq.inputResponses`). */
58
+ inputResponses?: Record<string, unknown>;
59
+ /** Per-request envelope (2026-07-28) or undefined on 2025 connections. */
60
+ envelope?: Record<string, unknown>;
61
+ /** Capabilities from the 2025 initialize handshake. */
62
+ sessionCapabilities?: unknown;
63
+ mode?: ConfirmMode;
64
+ }
65
+ /** Build the `confirmWrite` a tool call gets in its context. */
66
+ export declare function createConfirmWrite(options: ConfirmerOptions): ConfirmWrite;
67
+ /** The line tools add to a result when the person was or was not asked. */
68
+ export declare function confirmationNote(outcome: ConfirmOutcome): string | undefined;
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Ask the person before a tool changes files in their project.
3
+ *
4
+ * Tools that write test code or project state (suggest-fix `apply`,
5
+ * generate-e2e-test, quarantine add/remove, compare-visual-state `baseline`)
6
+ * call `ctx.confirmWrite()` right before the write, with the exact change
7
+ * they are about to make. When the client can show a form (MCP elicitation),
8
+ * the server answers the call with an `input_required` result (the
9
+ * 2026-07-28 multi-round-trip pattern; the SDK turns it into a classic
10
+ * elicitation request for 2025 clients). The client shows the change, the
11
+ * person says yes or no, and the client retries the call with the answer.
12
+ *
13
+ * The approval is bound to the change: the question's key is a hash of the
14
+ * tool, title and detail, so if the retried call would write something
15
+ * different it asks again instead of reusing an old "yes".
16
+ *
17
+ * PW_MCP_CONFIRM_WRITES:
18
+ * auto (default) ask when the client supports elicitation; otherwise
19
+ * write as before and say no one was asked
20
+ * always ask, and refuse to write when the client cannot ask
21
+ * off never ask
22
+ */
23
+ import { createHash } from 'node:crypto';
24
+ import { CLIENT_CAPABILITIES_META_KEY, inputRequired, inputResponse } from '@modelcontextprotocol/server';
25
+ import { PlaywrightMcpError } from '../types/index.js';
26
+ /**
27
+ * Thrown by `confirmWrite` when the person has to be asked. It carries the
28
+ * `input_required` result; the server returns it instead of a tool result.
29
+ * Tools must let it through (guard() rethrows it).
30
+ */
31
+ export class ConfirmationPending extends Error {
32
+ result;
33
+ constructor(result) {
34
+ super('waiting for the person to confirm a file change');
35
+ this.name = 'ConfirmationPending';
36
+ this.result = result;
37
+ }
38
+ }
39
+ export function confirmMode(value = process.env.PW_MCP_CONFIRM_WRITES) {
40
+ const normalized = (value ?? '').trim().toLowerCase();
41
+ if (normalized === 'off' || normalized === '0' || normalized === 'false')
42
+ return 'off';
43
+ if (normalized === 'always' || normalized === 'require' || normalized === 'required')
44
+ return 'always';
45
+ return 'auto';
46
+ }
47
+ /** Longest change shown in the question; clients show it as plain text. */
48
+ export const MAX_DETAIL_CHARS = 4_000;
49
+ /** Whether declared client capabilities include form-mode elicitation. */
50
+ export function supportsFormElicitation(capabilities) {
51
+ if (!capabilities || typeof capabilities !== 'object')
52
+ return false;
53
+ const elicitation = capabilities.elicitation;
54
+ if (!elicitation || typeof elicitation !== 'object')
55
+ return false;
56
+ const modes = elicitation;
57
+ // `{}` (2025-06-18) means form mode; a client that lists modes must list form.
58
+ if ('form' in modes || 'url' in modes)
59
+ return 'form' in modes;
60
+ return true;
61
+ }
62
+ /** The input key for one exact change: a new change gets a new question. */
63
+ export function confirmationKey(tool, request) {
64
+ const digest = createHash('sha256').update(`${tool}\n${request.title}\n${request.detail}`).digest('hex');
65
+ return `confirm_write_${digest.slice(0, 20)}`;
66
+ }
67
+ function questionText(tool, request) {
68
+ const detail = request.detail.length > MAX_DETAIL_CHARS
69
+ ? `${request.detail.slice(0, MAX_DETAIL_CHARS)}\n… (${request.detail.length - MAX_DETAIL_CHARS} more characters)`
70
+ : request.detail;
71
+ return `${request.title}\n\n${detail}\n\n(${tool} asks before changing files in your project. Set PW_MCP_CONFIRM_WRITES=off to stop asking.)`;
72
+ }
73
+ /** Build the `confirmWrite` a tool call gets in its context. */
74
+ export function createConfirmWrite(options) {
75
+ return async (request) => {
76
+ const mode = options.mode ?? confirmMode();
77
+ if (mode === 'off')
78
+ return 'not-asked';
79
+ const key = confirmationKey(options.tool, request);
80
+ const answer = inputResponse(options.inputResponses, key);
81
+ if (answer.kind === 'elicit') {
82
+ return answer.action === 'accept' && answer.content?.confirm === true ? 'approved' : 'declined';
83
+ }
84
+ const capabilities = options.envelope?.[CLIENT_CAPABILITIES_META_KEY] ?? options.sessionCapabilities;
85
+ if (!supportsFormElicitation(capabilities)) {
86
+ if (mode === 'always') {
87
+ throw new PlaywrightMcpError(`Not written: ${request.title.replace(/\?$/, '')} needs your confirmation, and this client cannot ask`, 'INVALID_INPUT', {
88
+ hint: 'PW_MCP_CONFIRM_WRITES=always refuses file changes in clients without elicitation. Use a client that supports it, or set PW_MCP_CONFIRM_WRITES=auto.',
89
+ });
90
+ }
91
+ return 'not-asked';
92
+ }
93
+ throw new ConfirmationPending(inputRequired({
94
+ inputRequests: {
95
+ [key]: inputRequired.elicit({
96
+ message: questionText(options.tool, request),
97
+ requestedSchema: {
98
+ type: 'object',
99
+ properties: {
100
+ confirm: {
101
+ type: 'boolean',
102
+ title: 'Make this change',
103
+ description: 'Yes writes the change. No leaves your files as they are.',
104
+ default: false,
105
+ },
106
+ },
107
+ required: ['confirm'],
108
+ },
109
+ }),
110
+ },
111
+ }));
112
+ };
113
+ }
114
+ /** The line tools add to a result when the person was or was not asked. */
115
+ export function confirmationNote(outcome) {
116
+ if (outcome === 'approved')
117
+ return '> ✅ You confirmed this change.';
118
+ return undefined;
119
+ }
120
+ //# sourceMappingURL=confirm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirm.js","sourceRoot":"","sources":["../../src/utils/confirm.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Shared history client: CI runs from every machine in one history, kept
3
+ * by a history server the team hosts itself (history-server/ in this repo,
4
+ * free and MIT like everything else).
5
+ *
6
+ * Strictly opt-in. Nothing here makes a network call unless
7
+ * PW_MCP_HISTORY_TOKEN is set; without it the server behaves exactly as
8
+ * before. PW_MCP_HISTORY_URL points at the team's history server. There is
9
+ * deliberately no built-in default URL: the token only ever goes where the
10
+ * user pointed it. PW_MCP_PRO_KEY / PW_MCP_PRO_URL / PW_MCP_PRO_PROJECT,
11
+ * the names from 0.7 and 0.8, still work.
12
+ */
13
+ import type { HistoryEntry } from './run-history.js';
14
+ export interface HistorySettings {
15
+ key: string;
16
+ url: string;
17
+ }
18
+ /** The shared history settings, or undefined when none are set (the normal case). */
19
+ export declare function historySettings(env?: NodeJS.ProcessEnv): HistorySettings | undefined;
20
+ /**
21
+ * The project name runs are filed under: PW_MCP_HISTORY_PROJECT, else the
22
+ * GitHub repository (owner/name, from CI or the origin remote), else the
23
+ * folder name. The same rule on CI and laptops, so both see one history.
24
+ */
25
+ export declare function historyProjectName(root: string, env?: NodeJS.ProcessEnv): Promise<string>;
26
+ export declare function uploadRuns(settings: HistorySettings, project: string, runs: HistoryEntry[]): Promise<{
27
+ stored: number;
28
+ skipped: number;
29
+ }>;
30
+ export declare function fetchRuns(settings: HistorySettings, project: string, limit: number): Promise<HistoryEntry[]>;
31
+ /** Local and cloud runs together, oldest first, without duplicates. */
32
+ export declare function mergeRuns(local: HistoryEntry[], cloud: HistoryEntry[], last: number): HistoryEntry[];
@@ -1,11 +1,14 @@
1
1
  /**
2
- * Pro Cloud client: shared CI run history for teams that subscribe to Pro.
2
+ * Shared history client: CI runs from every machine in one history, kept
3
+ * by a history server the team hosts itself (history-server/ in this repo,
4
+ * free and MIT like everything else).
3
5
  *
4
6
  * Strictly opt-in. Nothing here makes a network call unless
5
- * PW_MCP_PRO_KEY is set; without it the server behaves exactly as before.
6
- * The key is the license key from the Pro subscription; PW_MCP_PRO_URL
7
- * points at the Pro Cloud deployment. There is deliberately no built-in
8
- * default URL: the key only ever goes where the user pointed it.
7
+ * PW_MCP_HISTORY_TOKEN is set; without it the server behaves exactly as
8
+ * before. PW_MCP_HISTORY_URL points at the team's history server. There is
9
+ * deliberately no built-in default URL: the token only ever goes where the
10
+ * user pointed it. PW_MCP_PRO_KEY / PW_MCP_PRO_URL / PW_MCP_PRO_PROJECT,
11
+ * the names from 0.7 and 0.8, still work.
9
12
  */
10
13
  import { execFile } from 'node:child_process';
11
14
  import path from 'node:path';
@@ -13,15 +16,19 @@ import { PlaywrightMcpError } from '../types/index.js';
13
16
  import { parseHistory } from './run-history.js';
14
17
  const PROJECT_RE = /^[A-Za-z0-9][\w./-]{0,99}$/;
15
18
  const UPLOAD_BATCH = 100;
16
- /** The Pro settings, or undefined when Pro is not configured (the normal case). */
17
- export function proSettings(env = process.env) {
18
- const key = env.PW_MCP_PRO_KEY?.trim();
19
+ const pick = (env, name, legacy) => {
20
+ const value = env[name]?.trim() || env[legacy]?.trim();
21
+ return value || undefined;
22
+ };
23
+ /** The shared history settings, or undefined when none are set (the normal case). */
24
+ export function historySettings(env = process.env) {
25
+ const key = pick(env, 'PW_MCP_HISTORY_TOKEN', 'PW_MCP_PRO_KEY');
19
26
  if (!key)
20
27
  return undefined;
21
- const url = (env.PW_MCP_PRO_URL?.trim() ?? '').replace(/\/+$/, '');
28
+ const url = (pick(env, 'PW_MCP_HISTORY_URL', 'PW_MCP_PRO_URL') ?? '').replace(/\/+$/, '');
22
29
  if (!url) {
23
- throw new PlaywrightMcpError('PW_MCP_PRO_KEY is set but PW_MCP_PRO_URL is not', 'INVALID_INPUT', {
24
- hint: 'Set PW_MCP_PRO_URL to the Pro Cloud address from your welcome email, or unset PW_MCP_PRO_KEY.',
30
+ throw new PlaywrightMcpError('PW_MCP_HISTORY_TOKEN is set but PW_MCP_HISTORY_URL is not', 'INVALID_INPUT', {
31
+ hint: "Set PW_MCP_HISTORY_URL to your team's history server, or unset PW_MCP_HISTORY_TOKEN.",
25
32
  });
26
33
  }
27
34
  let parsed;
@@ -29,11 +36,11 @@ export function proSettings(env = process.env) {
29
36
  parsed = new URL(url);
30
37
  }
31
38
  catch {
32
- throw new PlaywrightMcpError(`PW_MCP_PRO_URL is not a URL: ${url}`, 'INVALID_INPUT');
39
+ throw new PlaywrightMcpError(`PW_MCP_HISTORY_URL is not a URL: ${url}`, 'INVALID_INPUT');
33
40
  }
34
41
  const local = parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1';
35
42
  if (parsed.protocol !== 'https:' && !(local && parsed.protocol === 'http:')) {
36
- throw new PlaywrightMcpError('PW_MCP_PRO_URL must use https', 'INVALID_INPUT', { hint: 'The Pro key is sent with every request.' });
43
+ throw new PlaywrightMcpError('PW_MCP_HISTORY_URL must use https', 'INVALID_INPUT', { hint: 'The token is sent with every request.' });
37
44
  }
38
45
  return { key, url };
39
46
  }
@@ -43,12 +50,12 @@ function git(args, cwd) {
43
50
  });
44
51
  }
45
52
  /**
46
- * The project name runs are filed under: PW_MCP_PRO_PROJECT, else the
53
+ * The project name runs are filed under: PW_MCP_HISTORY_PROJECT, else the
47
54
  * GitHub repository (owner/name, from CI or the origin remote), else the
48
55
  * folder name. The same rule on CI and laptops, so both see one history.
49
56
  */
50
- export async function proProjectName(root, env = process.env) {
51
- const candidates = [env.PW_MCP_PRO_PROJECT, env.GITHUB_REPOSITORY];
57
+ export async function historyProjectName(root, env = process.env) {
58
+ const candidates = [env.PW_MCP_HISTORY_PROJECT, env.PW_MCP_PRO_PROJECT, env.GITHUB_REPOSITORY];
52
59
  const remote = await git(['remote', 'get-url', 'origin'], root);
53
60
  const match = remote ? /[:/]([^/:]+\/[^/]+?)(?:\.git)?$/.exec(remote) : null;
54
61
  candidates.push(match?.[1], path.basename(root));
@@ -70,13 +77,13 @@ async function call(settings, method, pathAndQuery, body) {
70
77
  });
71
78
  }
72
79
  catch (error) {
73
- throw new PlaywrightMcpError(`Pro Cloud is unreachable (${settings.url}): ${error.message}`, 'UNKNOWN', {
74
- hint: 'Check the network and PW_MCP_PRO_URL; local history still works.',
80
+ throw new PlaywrightMcpError(`The history server is unreachable (${settings.url}): ${error.message}`, 'UNKNOWN', {
81
+ hint: 'Check the network and PW_MCP_HISTORY_URL; local history still works.',
75
82
  });
76
83
  }
77
84
  const data = (await response.json().catch(() => ({})));
78
85
  if (!response.ok) {
79
- throw new PlaywrightMcpError(`Pro Cloud: ${data.error ?? `HTTP ${response.status}`}`, response.status === 401 ? 'INVALID_INPUT' : 'UNKNOWN', {
86
+ throw new PlaywrightMcpError(`History server: ${data.error ?? `HTTP ${response.status}`}`, response.status === 401 ? 'INVALID_INPUT' : 'UNKNOWN', {
80
87
  hint: data.hint,
81
88
  });
82
89
  }
@@ -111,4 +118,4 @@ export function mergeRuns(local, cloud, last) {
111
118
  }
112
119
  return out.sort((a, b) => a.at.localeCompare(b.at)).slice(-last);
113
120
  }
114
- //# sourceMappingURL=pro-client.js.map
121
+ //# sourceMappingURL=history-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history-client.js","sourceRoot":"","sources":["../../src/utils/history-client.ts"],"names":[],"mappings":"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"}
@@ -38,7 +38,7 @@ jobs:
38
38
 
39
39
  - name: Run Playwright E2E diagnosis action
40
40
  id: e2e
41
- uses: xsignon-secure/E2E@v0.8.0
41
+ uses: xsignon-secure/E2E@v0.10.0
42
42
  with:
43
43
  # Directory containing playwright.config.* (default is workspace root)
44
44
  project-root: .
@@ -64,9 +64,10 @@ jobs:
64
64
  # Heal guard: block test changes that pass by checking less (deleted assertions, skipped tests, .only)
65
65
  # guard: true
66
66
 
67
- # Pro Cloud integration (optional, paid): upload run history to Pro Cloud
68
- # pro-key: ${{ secrets.PW_MCP_PRO_KEY }}
69
- # pro-url: https://pro.example.com
67
+ # Shared team history (optional, free): upload runs to your self-hosted history server
68
+ # (history-server/ in xsignon-secure/E2E)
69
+ # history-token: ${{ secrets.PW_MCP_HISTORY_TOKEN }}
70
+ # history-url: https://history.example.com
70
71
 
71
72
  # Fail step when tests fail (default: true)
72
73
  fail-on-failure: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playwright-e2e-mcp",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "MCP server and agent skill that run, diagnose and fix failing Playwright tests (TypeScript and pytest): CI report diagnosis, trace analysis, verified locator fixes, flaky verdicts, breaking commits, heal guard, accessibility and Web Vitals audits.",
5
5
  "author": "xsignon-secure (https://github.com/xsignon-secure)",
6
6
  "mcpName": "io.github.xsignon-secure/E2E",
@@ -13,7 +13,7 @@ and concrete next steps. It can also propose and apply a verified fix for a brok
13
13
  locator, inspect pages behind a login, run long suites in the background and keep
14
14
  a local history of every run.
15
15
 
16
- This skill is written for playwright-e2e-mcp 0.8.0 and works with 0.2.0 or
16
+ This skill is written for playwright-e2e-mcp 0.10.0 and works with 0.2.0 or
17
17
  newer. If `suggest-fix`, `get-run-status` or `analyze-history` is missing, the
18
18
  server is older than 0.2.0: use the steps that do not need those tools and tell
19
19
  the user to update it. `diagnose-flaky`'s per-test table and `isolate` option
@@ -25,7 +25,12 @@ history views and strict-mode fixes in `suggest-fix` arrived in 0.5.0;
25
25
  `save-login`, `check-test-change` and `quarantine` arrived in 0.7.0; the
26
26
  `switchTab` page step, `blockWrites`, recovery of crashed runs and
27
27
  pytest-playwright projects (`run-test`, `get-failure`, `list-tests`) arrived in
28
- 0.8.0. If `doctor` says a newer version is out, pass its upgrade command on to
28
+ 0.8.0; the free self-hosted history server (`PW_MCP_HISTORY_URL` /
29
+ `PW_MCP_HISTORY_TOKEN`, replacing the old Pro settings, which still work) arrived
30
+ in 0.9.0; asking before changing files, the interactive test report (MCP Apps)
31
+ and sign-in with Client ID Metadata Documents arrived in 0.10.0. If a tool that
32
+ writes returns `declined: true`, the user said no: do not retry the write, show
33
+ them the proposed change instead. If `doctor` says a newer version is out, pass its upgrade command on to
29
34
  the user.
30
35
 
31
36
  ## Before you start
@@ -281,7 +286,7 @@ with the commit it tested. `analyze-history` views:
281
286
  `selector` for one region) returns the accessibility snapshot and a
282
287
  `toMatchAriaSnapshot` assertion to paste into a spec.
283
288
  - **Set up CI:** when the user wants the same diagnosis on every pull request,
284
- point them to the GitHub Action (`uses: xsignon-secure/E2E@v0.8.0`) or the
289
+ point them to the GitHub Action (`uses: xsignon-secure/E2E@v0.10.0`) or the
285
290
  `npx -y playwright-e2e-mcp ci` command in `references/setup.md`. It writes the
286
291
  run, flaky verdicts and fix diffs to the job summary and one PR comment.
287
292
  - **Accessibility:** `audit-accessibility` with `url` runs axe-core against
@@ -83,7 +83,7 @@ Set these in the server's `env` block. None of them are secrets except
83
83
  | `PW_MCP_STORAGE_STATE` | none | Default Playwright storageState JSON (inside the project) for the page tools, so signed-in pages open logged in |
84
84
  | `PW_MCP_SHUFFLE_SEEDS` | random | Seeds for `diagnose-flaky`'s `order` pass (comma separated), to replay reported orders |
85
85
  | `PW_MCP_LOGIN_ENV` | — | Extra variables `save-login` may type through `{{env:NAME}}`, comma separated (default: only `E2E_*`, `TEST_*`, `PW_*`, `PLAYWRIGHT_*`, `LOGIN_*`) |
86
- | `PW_MCP_PRO_KEY` / `PW_MCP_PRO_URL` | — | Optional paid Pro: CI runs uploaded with `upload` show up in `analyze-history` (`source: both`). Unset = no network calls |
86
+ | `PW_MCP_HISTORY_URL` / `PW_MCP_HISTORY_TOKEN` | — | Optional, free: the team's self-hosted history server (`history-server/` in the repo). CI runs uploaded with `upload` show up in `analyze-history` (`source: both`). Unset = no network calls. Old names `PW_MCP_PRO_KEY` / `PW_MCP_PRO_URL` still work |
87
87
  | `PW_MCP_BLOCK_WRITES` | off | `1` makes the page tools abort POST, PUT, PATCH and DELETE requests that no mock or HAR answers (0.8.0+) |
88
88
  | `PW_MCP_PYTHON` | project venv, then `python3` | The Python used for pytest-playwright projects (0.8.0+) |
89
89
  | `PW_MCP_PROTOCOL` | both | `legacy` stops offering the 2026-07-28 MCP revision (0.8.0+) |
@@ -119,7 +119,7 @@ Exit code 0 means passed, 1 tests failed, 2 the run itself failed. On GitHub
119
119
  Actions it also writes to the job summary. As an Action:
120
120
 
121
121
  ```yaml
122
- - uses: xsignon-secure/E2E@v0.8.0
122
+ - uses: xsignon-secure/E2E@v0.10.0
123
123
  with:
124
124
  flaky-runs: 3
125
125
  suggest: 2
@@ -1,29 +0,0 @@
1
- /**
2
- * Pro Cloud client: shared CI run history for teams that subscribe to Pro.
3
- *
4
- * Strictly opt-in. Nothing here makes a network call unless
5
- * PW_MCP_PRO_KEY is set; without it the server behaves exactly as before.
6
- * The key is the license key from the Pro subscription; PW_MCP_PRO_URL
7
- * points at the Pro Cloud deployment. There is deliberately no built-in
8
- * default URL: the key only ever goes where the user pointed it.
9
- */
10
- import type { HistoryEntry } from './run-history.js';
11
- export interface ProSettings {
12
- key: string;
13
- url: string;
14
- }
15
- /** The Pro settings, or undefined when Pro is not configured (the normal case). */
16
- export declare function proSettings(env?: NodeJS.ProcessEnv): ProSettings | undefined;
17
- /**
18
- * The project name runs are filed under: PW_MCP_PRO_PROJECT, else the
19
- * GitHub repository (owner/name, from CI or the origin remote), else the
20
- * folder name. The same rule on CI and laptops, so both see one history.
21
- */
22
- export declare function proProjectName(root: string, env?: NodeJS.ProcessEnv): Promise<string>;
23
- export declare function uploadRuns(settings: ProSettings, project: string, runs: HistoryEntry[]): Promise<{
24
- stored: number;
25
- skipped: number;
26
- }>;
27
- export declare function fetchRuns(settings: ProSettings, project: string, limit: number): Promise<HistoryEntry[]>;
28
- /** Local and cloud runs together, oldest first, without duplicates. */
29
- export declare function mergeRuns(local: HistoryEntry[], cloud: HistoryEntry[], last: number): HistoryEntry[];
@@ -1 +0,0 @@
1
- {"version":3,"file":"pro-client.js","sourceRoot":"","sources":["../../src/utils/pro-client.ts"],"names":[],"mappings":"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"}