@tontoko/fast-playwright-mcp 0.0.4

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 (107) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +1047 -0
  3. package/cli.js +18 -0
  4. package/config.d.ts +124 -0
  5. package/index.d.ts +25 -0
  6. package/index.js +18 -0
  7. package/lib/actions.d.js +0 -0
  8. package/lib/batch/batch-executor.js +137 -0
  9. package/lib/browser-context-factory.js +252 -0
  10. package/lib/browser-server-backend.js +139 -0
  11. package/lib/config/constants.js +80 -0
  12. package/lib/config.js +405 -0
  13. package/lib/context.js +274 -0
  14. package/lib/diagnostics/common/diagnostic-base.js +63 -0
  15. package/lib/diagnostics/common/error-enrichment-utils.js +212 -0
  16. package/lib/diagnostics/common/index.js +56 -0
  17. package/lib/diagnostics/common/initialization-manager.js +210 -0
  18. package/lib/diagnostics/common/performance-tracker.js +132 -0
  19. package/lib/diagnostics/diagnostic-error.js +140 -0
  20. package/lib/diagnostics/diagnostic-level.js +123 -0
  21. package/lib/diagnostics/diagnostic-thresholds.js +347 -0
  22. package/lib/diagnostics/element-discovery.js +441 -0
  23. package/lib/diagnostics/enhanced-error-handler.js +376 -0
  24. package/lib/diagnostics/error-enrichment.js +157 -0
  25. package/lib/diagnostics/frame-reference-manager.js +179 -0
  26. package/lib/diagnostics/page-analyzer.js +639 -0
  27. package/lib/diagnostics/parallel-page-analyzer.js +129 -0
  28. package/lib/diagnostics/resource-manager.js +134 -0
  29. package/lib/diagnostics/smart-config.js +482 -0
  30. package/lib/diagnostics/smart-handle.js +118 -0
  31. package/lib/diagnostics/unified-system.js +717 -0
  32. package/lib/extension/cdp-relay.js +486 -0
  33. package/lib/extension/extension-context-factory.js +74 -0
  34. package/lib/extension/main.js +41 -0
  35. package/lib/file-utils.js +42 -0
  36. package/lib/generate-keys.js +75 -0
  37. package/lib/http-server.js +50 -0
  38. package/lib/in-process-client.js +64 -0
  39. package/lib/index.js +48 -0
  40. package/lib/javascript.js +90 -0
  41. package/lib/log.js +33 -0
  42. package/lib/loop/loop-claude.js +247 -0
  43. package/lib/loop/loop-open-ai.js +222 -0
  44. package/lib/loop/loop.js +174 -0
  45. package/lib/loop/main.js +46 -0
  46. package/lib/loopTools/context.js +76 -0
  47. package/lib/loopTools/main.js +65 -0
  48. package/lib/loopTools/perform.js +40 -0
  49. package/lib/loopTools/snapshot.js +37 -0
  50. package/lib/loopTools/tool.js +26 -0
  51. package/lib/manual-promise.js +125 -0
  52. package/lib/mcp/in-process-transport.js +91 -0
  53. package/lib/mcp/proxy-backend.js +127 -0
  54. package/lib/mcp/server.js +123 -0
  55. package/lib/mcp/transport.js +159 -0
  56. package/lib/package.js +28 -0
  57. package/lib/program.js +82 -0
  58. package/lib/response.js +493 -0
  59. package/lib/schemas/expectation.js +152 -0
  60. package/lib/session-log.js +210 -0
  61. package/lib/tab.js +417 -0
  62. package/lib/tools/base-tool-handler.js +141 -0
  63. package/lib/tools/batch-execute.js +150 -0
  64. package/lib/tools/common.js +65 -0
  65. package/lib/tools/console.js +60 -0
  66. package/lib/tools/diagnose/diagnose-analysis-runner.js +101 -0
  67. package/lib/tools/diagnose/diagnose-config-handler.js +130 -0
  68. package/lib/tools/diagnose/diagnose-report-builder.js +394 -0
  69. package/lib/tools/diagnose.js +147 -0
  70. package/lib/tools/dialogs.js +57 -0
  71. package/lib/tools/evaluate.js +67 -0
  72. package/lib/tools/files.js +53 -0
  73. package/lib/tools/find-elements.js +307 -0
  74. package/lib/tools/install.js +60 -0
  75. package/lib/tools/keyboard.js +93 -0
  76. package/lib/tools/mouse.js +110 -0
  77. package/lib/tools/navigate.js +82 -0
  78. package/lib/tools/network.js +50 -0
  79. package/lib/tools/pdf.js +46 -0
  80. package/lib/tools/screenshot.js +113 -0
  81. package/lib/tools/snapshot.js +158 -0
  82. package/lib/tools/tabs.js +97 -0
  83. package/lib/tools/tool.js +47 -0
  84. package/lib/tools/utils.js +131 -0
  85. package/lib/tools/wait.js +64 -0
  86. package/lib/tools.js +65 -0
  87. package/lib/types/batch.js +47 -0
  88. package/lib/types/diff.js +0 -0
  89. package/lib/types/performance.js +0 -0
  90. package/lib/types/threshold-base.js +0 -0
  91. package/lib/utils/array-utils.js +44 -0
  92. package/lib/utils/code-deduplication-utils.js +141 -0
  93. package/lib/utils/common-formatters.js +252 -0
  94. package/lib/utils/console-filter.js +64 -0
  95. package/lib/utils/diagnostic-report-utils.js +178 -0
  96. package/lib/utils/diff-formatter.js +126 -0
  97. package/lib/utils/disposable-manager.js +135 -0
  98. package/lib/utils/error-handler-middleware.js +77 -0
  99. package/lib/utils/image-processor.js +137 -0
  100. package/lib/utils/index.js +92 -0
  101. package/lib/utils/report-builder.js +189 -0
  102. package/lib/utils/request-logger.js +82 -0
  103. package/lib/utils/response-diff-detector.js +150 -0
  104. package/lib/utils/section-builder.js +62 -0
  105. package/lib/utils/tool-patterns.js +153 -0
  106. package/lib/utils.js +46 -0
  107. package/package.json +77 -0
@@ -0,0 +1,150 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
+
20
+ // src/utils/response-diff-detector.ts
21
+ import { createHash } from "node:crypto";
22
+ import diff from "fast-diff";
23
+ import { DiffFormatter } from "./diff-formatter.js";
24
+
25
+ class ResponseDiffDetector {
26
+ storage = new Map;
27
+ formatter = new DiffFormatter;
28
+ detectDiff(current, toolName, options) {
29
+ const cacheKey = this.generateCacheKey(toolName);
30
+ const previous = this.storage.get(cacheKey);
31
+ if (!previous) {
32
+ this.storeResponse(current, toolName);
33
+ return {
34
+ hasDifference: false,
35
+ similarity: 1,
36
+ formattedDiff: "",
37
+ metadata: {
38
+ addedLines: 0,
39
+ removedLines: 0,
40
+ contextLines: 0,
41
+ totalLines: current.split(`
42
+ `).length
43
+ }
44
+ };
45
+ }
46
+ const diffSegments = this.calculateDiff(previous.content, current);
47
+ const similarity = this.calculateSimilarity(previous.content, current);
48
+ const hasDifference = similarity < 1 - options.threshold;
49
+ let formattedDiff = "";
50
+ const metadata = {
51
+ addedLines: 0,
52
+ removedLines: 0,
53
+ contextLines: 0,
54
+ totalLines: current.split(`
55
+ `).length
56
+ };
57
+ if (hasDifference) {
58
+ for (const segment of diffSegments) {
59
+ if (segment.type === "add") {
60
+ metadata.addedLines += segment.value.split(`
61
+ `).length - 1;
62
+ } else if (segment.type === "remove") {
63
+ metadata.removedLines += segment.value.split(`
64
+ `).length - 1;
65
+ } else {
66
+ metadata.contextLines += segment.value.split(`
67
+ `).length - 1;
68
+ }
69
+ }
70
+ switch (options.format) {
71
+ case "split":
72
+ formattedDiff = this.formatter.formatSplit(diffSegments);
73
+ break;
74
+ case "minimal":
75
+ formattedDiff = this.formatter.formatMinimal(diffSegments);
76
+ break;
77
+ default:
78
+ formattedDiff = this.formatter.formatUnified(diffSegments, options.context);
79
+ break;
80
+ }
81
+ if (formattedDiff.split(`
82
+ `).length > options.maxDiffLines) {
83
+ const lines = formattedDiff.split(`
84
+ `);
85
+ formattedDiff = lines.slice(0, options.maxDiffLines).join(`
86
+ `) + `
87
+ ... (${lines.length - options.maxDiffLines} more lines truncated)`;
88
+ }
89
+ }
90
+ this.storeResponse(current, toolName);
91
+ return {
92
+ hasDifference,
93
+ similarity,
94
+ formattedDiff,
95
+ metadata
96
+ };
97
+ }
98
+ storeResponse(content, toolName) {
99
+ const cacheKey = this.generateCacheKey(toolName);
100
+ const hash = createHash("sha256").update(content).digest("hex");
101
+ this.storage.set(cacheKey, {
102
+ toolName,
103
+ timestamp: Date.now(),
104
+ content,
105
+ hash
106
+ });
107
+ }
108
+ generateCacheKey(toolName) {
109
+ return `diff_cache_${toolName}`;
110
+ }
111
+ calculateDiff(oldText, newText) {
112
+ const result = diff(oldText, newText);
113
+ return result.map(([type, value]) => {
114
+ let diffType = "equal";
115
+ if (type === -1) {
116
+ diffType = "remove";
117
+ } else if (type === 1) {
118
+ diffType = "add";
119
+ }
120
+ return {
121
+ type: diffType,
122
+ value
123
+ };
124
+ });
125
+ }
126
+ calculateSimilarity(text1, text2) {
127
+ if (text1 === text2) {
128
+ return 1;
129
+ }
130
+ if (text1.length === 0 && text2.length === 0) {
131
+ return 1;
132
+ }
133
+ if (text1.length === 0 || text2.length === 0) {
134
+ return 0;
135
+ }
136
+ const diffSegments = this.calculateDiff(text1, text2);
137
+ let equalChars = 0;
138
+ let totalChars = 0;
139
+ for (const segment of diffSegments) {
140
+ totalChars += segment.value.length;
141
+ if (segment.type === "equal") {
142
+ equalChars += segment.value.length;
143
+ }
144
+ }
145
+ return totalChars > 0 ? equalChars / totalChars : 0;
146
+ }
147
+ }
148
+ export {
149
+ ResponseDiffDetector
150
+ };
@@ -0,0 +1,62 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
+
20
+ // src/utils/section-builder.ts
21
+ function buildDiagnosticSection(sections, title, content, level = 2) {
22
+ sections.push("");
23
+ sections.push(`${"#".repeat(level)} ${title}`);
24
+ if (typeof content === "function") {
25
+ content();
26
+ } else {
27
+ sections.push(...content);
28
+ }
29
+ }
30
+ function addKeyValuePairs(sections, pairs) {
31
+ for (const [key, value] of Object.entries(pairs)) {
32
+ sections.push(`- **${key}:** ${value}`);
33
+ }
34
+ }
35
+ function addListItems(sections, items, prefix = "-") {
36
+ for (const item of items) {
37
+ sections.push(`${prefix} ${item}`);
38
+ }
39
+ }
40
+ function addIfNotEmpty(sections, items, formatter) {
41
+ if (items.length > 0) {
42
+ for (const item of items) {
43
+ sections.push(formatter(item));
44
+ }
45
+ }
46
+ }
47
+ function buildPerformanceSection(sections, metrics) {
48
+ if (metrics.executionTime !== undefined) {
49
+ const icon = metrics.threshold && metrics.executionTime > metrics.threshold ? "⚠️" : "✅";
50
+ sections.push(`${icon} Execution time: ${metrics.executionTime}ms`);
51
+ if (metrics.threshold && metrics.executionTime > metrics.threshold) {
52
+ sections.push(`⚠️ Exceeded threshold (${metrics.threshold}ms)`);
53
+ }
54
+ }
55
+ }
56
+ export {
57
+ buildPerformanceSection,
58
+ buildDiagnosticSection,
59
+ addListItems,
60
+ addKeyValuePairs,
61
+ addIfNotEmpty
62
+ };
@@ -0,0 +1,153 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
+
20
+ // src/utils/tool-patterns.ts
21
+ import { BaseElementToolHandler } from "../tools/base-tool-handler.js";
22
+ import { getErrorMessage } from "./common-formatters.js";
23
+ var resolveElementLocator = async (tab, params) => {
24
+
25
+ class TempHandler extends BaseElementToolHandler {
26
+ constructor() {
27
+ super("temp");
28
+ }
29
+ executeToolLogic() {
30
+ return Promise.resolve();
31
+ }
32
+ resolveLocator(tabInstance, locatorParams) {
33
+ return this.resolveElementLocator(tabInstance, locatorParams);
34
+ }
35
+ }
36
+ return await new TempHandler().resolveLocator(tab, params);
37
+ };
38
+ var validateElementParams = (params) => {
39
+
40
+ class TempHandler extends BaseElementToolHandler {
41
+ constructor() {
42
+ super("temp");
43
+ }
44
+ executeToolLogic() {
45
+ return Promise.resolve();
46
+ }
47
+ validateParams(validationParams) {
48
+ this.validateElementParams(validationParams);
49
+ }
50
+ }
51
+ new TempHandler().validateParams(params);
52
+ };
53
+ function addToolErrorContext(response, error, toolName, params) {
54
+ const errorMessage = getErrorMessage(error);
55
+ response.addError(`Error in ${toolName}: ${errorMessage}`);
56
+ if (params?.element) {
57
+ response.addResult(`Element context: ${params.element}`);
58
+ }
59
+ if (params?.ref) {
60
+ response.addResult(`Reference: ${params.ref}`);
61
+ }
62
+ }
63
+ function applyCommonExpectations(response, expectation) {
64
+ if (expectation?.includeSnapshot !== false) {
65
+ response.setIncludeSnapshot();
66
+ }
67
+ }
68
+ async function waitForToolCompletion(tab, operation, toolName, operationName) {
69
+ try {
70
+ await tab.waitForCompletion(operation);
71
+ } catch (error) {
72
+ const opName = operationName ?? "operation";
73
+ throw new Error(`${toolName} ${opName} failed: ${getErrorMessage(error)}`);
74
+ }
75
+ }
76
+ function addOperationComment(response, operation, context) {
77
+ const comment = context ? `// ${operation} - ${context}` : `// ${operation}`;
78
+ response.addCode(comment);
79
+ }
80
+ function addMouseOperationComment(response, operation, params) {
81
+ if (params.element) {
82
+ addOperationComment(response, operation, `on ${params.element}`);
83
+ } else {
84
+ addOperationComment(response, operation, `at (${params.x}, ${params.y})`);
85
+ }
86
+ }
87
+ function addNavigationComment(response, operation, url) {
88
+ if (url) {
89
+ addOperationComment(response, operation, `to ${url}`);
90
+ } else {
91
+ addOperationComment(response, operation);
92
+ }
93
+ }
94
+ async function executeToolOperation(operation, toolName, response, params) {
95
+ try {
96
+ return await operation();
97
+ } catch (error) {
98
+ addToolErrorContext(response, error, toolName, params);
99
+ throw error;
100
+ }
101
+ }
102
+ function setupToolResponse(response, params) {
103
+ applyCommonExpectations(response, params.expectation);
104
+ }
105
+ async function validateAndResolveElement(tab, params) {
106
+ validateElementParams(params);
107
+ return await resolveElementLocator(tab, params);
108
+ }
109
+ var ToolPatterns = {
110
+ Mouse: {
111
+ addComment: addMouseOperationComment,
112
+ validate: (params) => {
113
+ if (params.x < 0 || params.y < 0) {
114
+ throw new Error("Mouse coordinates must be non-negative");
115
+ }
116
+ }
117
+ },
118
+ Navigation: {
119
+ addComment: addNavigationComment,
120
+ validateUrl: (url) => {
121
+ try {
122
+ new URL(url);
123
+ } catch {
124
+ throw new Error(`Invalid URL: ${url}`);
125
+ }
126
+ }
127
+ },
128
+ Element: {
129
+ validateAndResolve: validateAndResolveElement,
130
+ addErrorContext: (response, error, toolName, element) => {
131
+ const errorMsg = getErrorMessage(error);
132
+ response.addResult(`${toolName} failed: ${errorMsg}`);
133
+ if (element) {
134
+ response.addResult(`Target element: ${element}`);
135
+ response.addResult("Suggestion: Verify element is visible and interactable");
136
+ }
137
+ }
138
+ }
139
+ };
140
+ export {
141
+ waitForToolCompletion,
142
+ validateElementParams,
143
+ validateAndResolveElement,
144
+ setupToolResponse,
145
+ resolveElementLocator,
146
+ executeToolOperation,
147
+ applyCommonExpectations,
148
+ addToolErrorContext,
149
+ addOperationComment,
150
+ addNavigationComment,
151
+ addMouseOperationComment,
152
+ ToolPatterns
153
+ };
package/lib/utils.js ADDED
@@ -0,0 +1,46 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
+
20
+ // src/utils.ts
21
+ import { createHash as cryptoCreateHash } from "node:crypto";
22
+ function createHash(data) {
23
+ return cryptoCreateHash("sha256").update(data).digest("hex").slice(0, 7);
24
+ }
25
+ var UNSAFE_FILENAME_CHARS = /[<>:"/\\|?*]+/g;
26
+ function removeControlCharacters(str) {
27
+ return str.split("").map((char) => {
28
+ const code = char.charCodeAt(0);
29
+ return code >= 0 && code <= 31 || code === 127 ? "-" : char;
30
+ }).join("");
31
+ }
32
+ function sanitizeForFilePath(input) {
33
+ const sanitize = (str) => {
34
+ const cleanStr = removeControlCharacters(str);
35
+ return cleanStr.replace(UNSAFE_FILENAME_CHARS, "-");
36
+ };
37
+ const separator = input.lastIndexOf(".");
38
+ if (separator === -1) {
39
+ return sanitize(input);
40
+ }
41
+ return sanitize(input.substring(0, separator)) + "." + sanitize(input.substring(separator + 1));
42
+ }
43
+ export {
44
+ sanitizeForFilePath,
45
+ createHash
46
+ };
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "@tontoko/fast-playwright-mcp",
3
+ "version": "0.0.4",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "description": "Fast Playwright Tools for MCP",
8
+ "type": "module",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/tontoko/fast-playwright-mcp"
12
+ },
13
+ "homepage": "https://playwright.dev",
14
+ "engines": {
15
+ "node": ">=18"
16
+ },
17
+ "author": {
18
+ "name": "Microsoft Corporation"
19
+ },
20
+ "license": "Apache-2.0",
21
+ "scripts": {
22
+ "build": "bun build ./src/**/**/*.ts ./src/**/*.ts ./src/*.ts --outdir ./lib --root ./src --target node --format esm --external '*'",
23
+ "build:publish": "bun build ./src/**/**/*.ts ./src/**/*.ts ./src/*.ts --outdir ./lib --root ./src --target node --format esm --external '*'",
24
+ "benchmark": "bun benchmark/src/index.ts",
25
+ "benchmark:verbose": "bun benchmark/src/index.ts --verbose",
26
+ "benchmark:quiet": "bun benchmark/src/index.ts --quiet",
27
+ "lint": "ultracite lint",
28
+ "lint-fix": "ultracite format",
29
+ "update-readme": "bun utils/update-readme.js",
30
+ "watch": "tsc --watch",
31
+ "test": "playwright test",
32
+ "ctest": "playwright test --project=chrome",
33
+ "ftest": "playwright test --project=firefox",
34
+ "wtest": "playwright test --project=webkit",
35
+ "run-server": "bun lib/browserServer.js",
36
+ "clean": "rm -rf lib benchmark/lib",
37
+ "npm-publish": "npm run clean && npm run build:publish && npm run test && npm publish"
38
+ },
39
+ "exports": {
40
+ "./package.json": "./package.json",
41
+ ".": {
42
+ "types": "./index.d.ts",
43
+ "default": "./index.js"
44
+ }
45
+ },
46
+ "dependencies": {
47
+ "@modelcontextprotocol/sdk": "^1.16.0",
48
+ "@types/sharp": "^0.31.1",
49
+ "commander": "^13.1.0",
50
+ "debug": "^4.4.1",
51
+ "dotenv": "^17.2.0",
52
+ "fast-diff": "^1.3.0",
53
+ "mime": "^4.0.7",
54
+ "playwright": "1.55.0-alpha-2025-08-07",
55
+ "playwright-core": "1.55.0-alpha-2025-08-07",
56
+ "sharp": "^0.34.3",
57
+ "ws": "^8.18.1",
58
+ "zod": "^3.24.1",
59
+ "zod-to-json-schema": "^3.24.4"
60
+ },
61
+ "devDependencies": {
62
+ "@anthropic-ai/sdk": "^0.57.0",
63
+ "@biomejs/biome": "2.1.2",
64
+ "@playwright/test": "1.55.0-alpha-2025-08-07",
65
+ "@types/debug": "^4.1.12",
66
+ "@types/node": "^22.13.10",
67
+ "@types/ws": "^8.18.1",
68
+ "@typescript/native-preview": "^7.0.0-dev.20250808.1",
69
+ "esbuild": "^0.20.1",
70
+ "lefthook": "^1.12.2",
71
+ "openai": "^5.10.2",
72
+ "ultracite": "5.1.2"
73
+ },
74
+ "bin": {
75
+ "mcp-server-playwright": "cli.js"
76
+ }
77
+ }