@wdio/mcp 3.4.3 → 3.5.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.
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/show-trace.ts
4
+ import { createServer } from "http";
5
+ import { readFileSync, existsSync, readdirSync, statSync } from "fs";
6
+ import { resolve, basename, join } from "path";
7
+ import { exec } from "child_process";
8
+ function openBrowser(url) {
9
+ const cmd = process.platform === "darwin" ? `open "${url}"` : process.platform === "win32" ? `start "" "${url}"` : `xdg-open "${url}"`;
10
+ exec(cmd);
11
+ }
12
+ function findLatestTrace() {
13
+ const traceDir = join(process.cwd(), ".trace");
14
+ if (!existsSync(traceDir)) return null;
15
+ const zips = readdirSync(traceDir).filter((f) => f.endsWith(".zip")).map((f) => ({ name: f, mtime: statSync(join(traceDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
16
+ return zips.length > 0 ? join(traceDir, zips[0].name) : null;
17
+ }
18
+ var argPath = process.argv[2];
19
+ var absolutePath;
20
+ if (argPath) {
21
+ absolutePath = resolve(argPath);
22
+ if (!existsSync(absolutePath)) {
23
+ console.error(`File not found: ${absolutePath}`);
24
+ process.exit(1);
25
+ }
26
+ } else {
27
+ const latest = findLatestTrace();
28
+ if (!latest) {
29
+ console.error("No trace found. Run a session with trace enabled, or pass a zip path.");
30
+ process.exit(1);
31
+ }
32
+ absolutePath = latest;
33
+ console.error(`Using latest trace: ${absolutePath}`);
34
+ }
35
+ var fileName = basename(absolutePath);
36
+ var fileData = readFileSync(absolutePath);
37
+ var server = createServer((req, res) => {
38
+ if (req.method === "OPTIONS") {
39
+ res.writeHead(204, {
40
+ "Access-Control-Allow-Origin": "https://player.vibium.dev",
41
+ "Access-Control-Allow-Methods": "GET"
42
+ });
43
+ res.end();
44
+ return;
45
+ }
46
+ if (req.url === `/${fileName}`) {
47
+ res.writeHead(200, {
48
+ "Content-Type": "application/zip",
49
+ "Content-Length": String(fileData.length),
50
+ "Access-Control-Allow-Origin": "https://player.vibium.dev"
51
+ });
52
+ res.end(fileData);
53
+ return;
54
+ }
55
+ res.writeHead(404);
56
+ res.end();
57
+ });
58
+ server.listen(0, "127.0.0.1", () => {
59
+ const addr = server.address();
60
+ const port = typeof addr === "object" && addr ? addr.port : 0;
61
+ const traceUrl = `http://localhost:${port}/${fileName}`;
62
+ const viewerUrl = `https://player.vibium.dev/?record=${encodeURIComponent(traceUrl)}`;
63
+ console.error(`Serving ${fileName} on ${traceUrl}`);
64
+ console.error(`Opening ${viewerUrl}`);
65
+ console.error("Press Ctrl+C to stop.");
66
+ openBrowser(viewerUrl);
67
+ });
68
+ //# sourceMappingURL=show-trace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/show-trace.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { createServer } from 'node:http';\nimport { readFileSync, existsSync, readdirSync, statSync } from 'node:fs';\nimport { resolve, basename, join } from 'node:path';\nimport { exec } from 'node:child_process';\n\nfunction openBrowser(url: string): void {\n const cmd =\n process.platform === 'darwin'\n ? `open \"${url}\"`\n : process.platform === 'win32'\n ? `start \"\" \"${url}\"`\n : `xdg-open \"${url}\"`;\n exec(cmd);\n}\n\nfunction findLatestTrace(): string | null {\n const traceDir = join(process.cwd(), '.trace');\n if (!existsSync(traceDir)) return null;\n\n const zips = readdirSync(traceDir)\n .filter((f) => f.endsWith('.zip'))\n .map((f) => ({ name: f, mtime: statSync(join(traceDir, f)).mtimeMs }))\n .sort((a, b) => b.mtime - a.mtime);\n\n return zips.length > 0 ? join(traceDir, zips[0].name) : null;\n}\n\nconst argPath = process.argv[2];\nlet absolutePath: string;\n\nif (argPath) {\n absolutePath = resolve(argPath);\n if (!existsSync(absolutePath)) {\n console.error(`File not found: ${absolutePath}`);\n process.exit(1);\n }\n} else {\n const latest = findLatestTrace();\n if (!latest) {\n console.error('No trace found. Run a session with trace enabled, or pass a zip path.');\n process.exit(1);\n }\n absolutePath = latest;\n console.error(`Using latest trace: ${absolutePath}`);\n}\n\nconst fileName = basename(absolutePath);\nconst fileData = readFileSync(absolutePath);\n\nconst server = createServer((req, res) => {\n if (req.method === 'OPTIONS') {\n res.writeHead(204, {\n 'Access-Control-Allow-Origin': 'https://player.vibium.dev',\n 'Access-Control-Allow-Methods': 'GET',\n });\n res.end();\n return;\n }\n\n if (req.url === `/${fileName}`) {\n res.writeHead(200, {\n 'Content-Type': 'application/zip',\n 'Content-Length': String(fileData.length),\n 'Access-Control-Allow-Origin': 'https://player.vibium.dev',\n });\n res.end(fileData);\n return;\n }\n\n res.writeHead(404);\n res.end();\n});\n\nserver.listen(0, '127.0.0.1', () => {\n const addr = server.address();\n const port = typeof addr === 'object' && addr ? addr.port : 0;\n const traceUrl = `http://localhost:${port}/${fileName}`;\n const viewerUrl = `https://player.vibium.dev/?record=${encodeURIComponent(traceUrl)}`;\n\n console.error(`Serving ${fileName} on ${traceUrl}`);\n console.error(`Opening ${viewerUrl}`);\n console.error('Press Ctrl+C to stop.');\n\n openBrowser(viewerUrl);\n});"],"mappings":";;;AACA,SAAS,oBAAoB;AAC7B,SAAS,cAAc,YAAY,aAAa,gBAAgB;AAChE,SAAS,SAAS,UAAU,YAAY;AACxC,SAAS,YAAY;AAErB,SAAS,YAAY,KAAmB;AACtC,QAAM,MACJ,QAAQ,aAAa,WACjB,SAAS,GAAG,MACZ,QAAQ,aAAa,UACnB,aAAa,GAAG,MAChB,aAAa,GAAG;AACxB,OAAK,GAAG;AACV;AAEA,SAAS,kBAAiC;AACxC,QAAM,WAAW,KAAK,QAAQ,IAAI,GAAG,QAAQ;AAC7C,MAAI,CAAC,WAAW,QAAQ,EAAG,QAAO;AAElC,QAAM,OAAO,YAAY,QAAQ,EAC9B,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,CAAC,EAChC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,SAAS,KAAK,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,EACpE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAEnC,SAAO,KAAK,SAAS,IAAI,KAAK,UAAU,KAAK,CAAC,EAAE,IAAI,IAAI;AAC1D;AAEA,IAAM,UAAU,QAAQ,KAAK,CAAC;AAC9B,IAAI;AAEJ,IAAI,SAAS;AACX,iBAAe,QAAQ,OAAO;AAC9B,MAAI,CAAC,WAAW,YAAY,GAAG;AAC7B,YAAQ,MAAM,mBAAmB,YAAY,EAAE;AAC/C,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,OAAO;AACL,QAAM,SAAS,gBAAgB;AAC/B,MAAI,CAAC,QAAQ;AACX,YAAQ,MAAM,uEAAuE;AACrF,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,iBAAe;AACf,UAAQ,MAAM,uBAAuB,YAAY,EAAE;AACrD;AAEA,IAAM,WAAW,SAAS,YAAY;AACtC,IAAM,WAAW,aAAa,YAAY;AAE1C,IAAM,SAAS,aAAa,CAAC,KAAK,QAAQ;AACxC,MAAI,IAAI,WAAW,WAAW;AAC5B,QAAI,UAAU,KAAK;AAAA,MACjB,+BAA+B;AAAA,MAC/B,gCAAgC;AAAA,IAClC,CAAC;AACD,QAAI,IAAI;AACR;AAAA,EACF;AAEA,MAAI,IAAI,QAAQ,IAAI,QAAQ,IAAI;AAC9B,QAAI,UAAU,KAAK;AAAA,MACjB,gBAAgB;AAAA,MAChB,kBAAkB,OAAO,SAAS,MAAM;AAAA,MACxC,+BAA+B;AAAA,IACjC,CAAC;AACD,QAAI,IAAI,QAAQ;AAChB;AAAA,EACF;AAEA,MAAI,UAAU,GAAG;AACjB,MAAI,IAAI;AACV,CAAC;AAED,OAAO,OAAO,GAAG,aAAa,MAAM;AAClC,QAAM,OAAO,OAAO,QAAQ;AAC5B,QAAM,OAAO,OAAO,SAAS,YAAY,OAAO,KAAK,OAAO;AAC5D,QAAM,WAAW,oBAAoB,IAAI,IAAI,QAAQ;AACrD,QAAM,YAAY,qCAAqC,mBAAmB,QAAQ,CAAC;AAEnF,UAAQ,MAAM,WAAW,QAAQ,OAAO,QAAQ,EAAE;AAClD,UAAQ,MAAM,WAAW,SAAS,EAAE;AACpC,UAAQ,MAAM,uBAAuB;AAErC,cAAY,SAAS;AACvB,CAAC;","names":[]}
package/lib/trace.d.ts ADDED
@@ -0,0 +1,89 @@
1
+ interface ContextOptionsEvent {
2
+ version: 8;
3
+ type: 'context-options';
4
+ origin: 'library';
5
+ libraryName: string;
6
+ libraryVersion: string;
7
+ browserName: string;
8
+ platform: 'darwin' | 'linux' | 'windows';
9
+ wallTime: number;
10
+ monotonicTime: 0;
11
+ sdkLanguage: 'javascript';
12
+ title: string;
13
+ contextId: string;
14
+ options: {
15
+ viewport: {
16
+ width: number;
17
+ height: number;
18
+ };
19
+ };
20
+ }
21
+ interface ScreencastFrameEvent {
22
+ type: 'screencast-frame';
23
+ pageId: string;
24
+ sha1: string;
25
+ width: number;
26
+ height: number;
27
+ timestamp: number;
28
+ }
29
+ interface BeforeActionEvent {
30
+ type: 'before';
31
+ callId: string;
32
+ startTime: number;
33
+ class: string;
34
+ method: string;
35
+ pageId: string;
36
+ params: Record<string, unknown>;
37
+ title: string;
38
+ }
39
+ interface AfterActionEvent {
40
+ type: 'after';
41
+ callId: string;
42
+ endTime: number;
43
+ error?: {
44
+ message: string;
45
+ };
46
+ }
47
+ type TraceEvent = ContextOptionsEvent | ScreencastFrameEvent | BeforeActionEvent | AfterActionEvent;
48
+ interface TraceScreenshot {
49
+ resourceName: string;
50
+ data: Buffer;
51
+ width: number;
52
+ height: number;
53
+ }
54
+ interface TraceSession {
55
+ sessionId: string;
56
+ startWallTime: number;
57
+ startHrTime: bigint;
58
+ pageId: string;
59
+ contextId: string;
60
+ callCounter: number;
61
+ events: TraceEvent[];
62
+ screenshots: TraceScreenshot[];
63
+ browserName: string;
64
+ viewport: {
65
+ width: number;
66
+ height: number;
67
+ };
68
+ sessionType: 'browser' | 'ios' | 'android';
69
+ lastAfterEndTime: number;
70
+ screenshotChain: Promise<void>;
71
+ }
72
+
73
+ declare function buildTraceZip(session: TraceSession): Promise<Buffer>;
74
+
75
+ declare function createTraceSession(sessionId: string, browserName: string, viewport: {
76
+ width: number;
77
+ height: number;
78
+ }, title: string, sessionType?: 'browser' | 'ios' | 'android'): TraceSession;
79
+ declare function getTraceSession(sessionId: string): TraceSession | undefined;
80
+ declare function getMonotonicMs(session: TraceSession): number;
81
+
82
+ interface TraceAction {
83
+ class: string;
84
+ method: string;
85
+ }
86
+ declare function mapToolToTraceAction(toolName: string): TraceAction | null;
87
+ declare function formatActionTitle(action: TraceAction, params: Record<string, unknown>): string;
88
+
89
+ export { type TraceEvent, type TraceScreenshot, type TraceSession, buildTraceZip, createTraceSession, formatActionTitle, getMonotonicMs, getTraceSession, mapToolToTraceAction };
package/lib/trace.js ADDED
@@ -0,0 +1,110 @@
1
+ // src/trace/zip-writer.ts
2
+ import yazl from "yazl";
3
+ function buildTraceZip(session) {
4
+ return new Promise((resolve, reject) => {
5
+ const zipFile = new yazl.ZipFile();
6
+ const traceNdjson = session.events.map((e) => JSON.stringify(e)).join("\n");
7
+ const traceBuffer = Buffer.from(traceNdjson, "utf8");
8
+ zipFile.addBuffer(traceBuffer, "trace.trace");
9
+ zipFile.addBuffer(Buffer.alloc(0), "trace.network");
10
+ for (const screenshot of session.screenshots) {
11
+ zipFile.addBuffer(screenshot.data, `resources/${screenshot.resourceName}`);
12
+ }
13
+ zipFile.end();
14
+ const chunks = [];
15
+ zipFile.outputStream.on("data", (chunk) => chunks.push(chunk));
16
+ zipFile.outputStream.on("end", () => resolve(Buffer.concat(chunks)));
17
+ zipFile.outputStream.on("error", reject);
18
+ });
19
+ }
20
+
21
+ // src/trace/state.ts
22
+ import { createRequire } from "module";
23
+ var require2 = createRequire(import.meta.url);
24
+ var { version: LIBRARY_VERSION } = require2("../../package.json");
25
+ var traceSessions = /* @__PURE__ */ new Map();
26
+ function createTraceSession(sessionId, browserName, viewport, title, sessionType = "browser") {
27
+ const prefix = sessionId.slice(0, 8);
28
+ const session = {
29
+ sessionId,
30
+ startWallTime: Date.now(),
31
+ startHrTime: process.hrtime.bigint(),
32
+ pageId: `page@${prefix}`,
33
+ contextId: `context@${prefix}`,
34
+ callCounter: 0,
35
+ events: [],
36
+ screenshots: [],
37
+ browserName,
38
+ viewport,
39
+ sessionType,
40
+ lastAfterEndTime: 0,
41
+ screenshotChain: Promise.resolve()
42
+ };
43
+ session.events.push({
44
+ version: 8,
45
+ type: "context-options",
46
+ origin: "library",
47
+ libraryName: "@wdio/mcp",
48
+ libraryVersion: LIBRARY_VERSION,
49
+ browserName,
50
+ platform: process.platform === "darwin" ? "darwin" : process.platform === "win32" ? "windows" : "linux",
51
+ wallTime: session.startWallTime,
52
+ monotonicTime: 0,
53
+ sdkLanguage: "javascript",
54
+ title,
55
+ contextId: session.contextId,
56
+ options: { viewport }
57
+ });
58
+ traceSessions.set(sessionId, session);
59
+ return session;
60
+ }
61
+ function getTraceSession(sessionId) {
62
+ return traceSessions.get(sessionId);
63
+ }
64
+ function getMonotonicMs(session) {
65
+ return Number((process.hrtime.bigint() - session.startHrTime) / 1000000n);
66
+ }
67
+
68
+ // src/trace/tool-mapping.ts
69
+ var TOOL_MAP = {
70
+ navigate: { class: "Page", method: "navigate" },
71
+ click_element: { class: "Element", method: "click" },
72
+ set_value: { class: "Element", method: "fill" },
73
+ scroll: { class: "Page", method: "scroll" },
74
+ tap_element: { class: "Element", method: "tap" },
75
+ swipe: { class: "Page", method: "swipe" },
76
+ drag_and_drop: { class: "Element", method: "dragTo" },
77
+ execute_script: { class: "Page", method: "evaluate" },
78
+ launch_chrome: { class: "Browser", method: "launch" }
79
+ };
80
+ function mapToolToTraceAction(toolName) {
81
+ return TOOL_MAP[toolName] ?? null;
82
+ }
83
+ function extractSelectorLabel(selector) {
84
+ const uiautomator = selector.match(/\.(?:text|description|textContains)\("([^"]+)"\)/);
85
+ if (uiautomator) return uiautomator[1];
86
+ if (selector.startsWith("~")) return selector.slice(1);
87
+ const predicate = selector.match(/(?:label|name|value)\s*==\s*"([^"]+)"/);
88
+ if (predicate) return predicate[1];
89
+ const xpath = selector.match(/@(?:text|label|name|content-desc)="([^"]+)"/);
90
+ if (xpath) return xpath[1];
91
+ return selector;
92
+ }
93
+ function formatActionTitle(action, params) {
94
+ const { class: cls, method } = action;
95
+ const firstKey = Object.keys(params)[0];
96
+ const firstVal = Object.values(params)[0];
97
+ if (firstVal === void 0) return `${cls}.${method}()`;
98
+ const raw = String(firstVal);
99
+ const label = firstKey === "selector" ? extractSelectorLabel(raw) : raw;
100
+ return `${cls}.${method}("${label.slice(0, 80)}")`;
101
+ }
102
+ export {
103
+ buildTraceZip,
104
+ createTraceSession,
105
+ formatActionTitle,
106
+ getMonotonicMs,
107
+ getTraceSession,
108
+ mapToolToTraceAction
109
+ };
110
+ //# sourceMappingURL=trace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/trace/zip-writer.ts","../src/trace/state.ts","../src/trace/tool-mapping.ts"],"sourcesContent":["import yazl from 'yazl';\nimport type { TraceSession } from './types.js';\n\nexport function buildTraceZip(session: TraceSession): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const zipFile = new yazl.ZipFile();\n\n const traceNdjson = session.events.map((e) => JSON.stringify(e)).join('\\n');\n const traceBuffer = Buffer.from(traceNdjson, 'utf8');\n zipFile.addBuffer(traceBuffer, 'trace.trace');\n zipFile.addBuffer(Buffer.alloc(0), 'trace.network');\n\n for (const screenshot of session.screenshots) {\n zipFile.addBuffer(screenshot.data, `resources/${screenshot.resourceName}`);\n }\n\n zipFile.end();\n\n const chunks: Buffer[] = [];\n zipFile.outputStream.on('data', (chunk: Buffer) => chunks.push(chunk));\n zipFile.outputStream.on('end', () => resolve(Buffer.concat(chunks)));\n zipFile.outputStream.on('error', reject);\n });\n}\n","import { createRequire } from 'node:module';\nimport type { TraceSession } from './types.js';\n\nconst require = createRequire(import.meta.url);\nconst { version: LIBRARY_VERSION } = require('../../package.json') as { version: string };\n\nconst traceSessions = new Map<string, TraceSession>();\n\nexport function createTraceSession(\n sessionId: string,\n browserName: string,\n viewport: { width: number; height: number },\n title: string,\n sessionType: 'browser' | 'ios' | 'android' = 'browser',\n): TraceSession {\n const prefix = sessionId.slice(0, 8);\n const session: TraceSession = {\n sessionId,\n startWallTime: Date.now(),\n startHrTime: process.hrtime.bigint(),\n pageId: `page@${prefix}`,\n contextId: `context@${prefix}`,\n callCounter: 0,\n events: [],\n screenshots: [],\n browserName,\n viewport,\n sessionType,\n lastAfterEndTime: 0,\n screenshotChain: Promise.resolve(),\n };\n\n session.events.push({\n version: 8,\n type: 'context-options',\n origin: 'library',\n libraryName: '@wdio/mcp',\n libraryVersion: LIBRARY_VERSION,\n browserName,\n platform: process.platform === 'darwin' ? 'darwin' : process.platform === 'win32' ? 'windows' : 'linux',\n wallTime: session.startWallTime,\n monotonicTime: 0,\n sdkLanguage: 'javascript',\n title,\n contextId: session.contextId,\n options: { viewport },\n });\n\n traceSessions.set(sessionId, session);\n return session;\n}\n\nexport function getTraceSession(sessionId: string): TraceSession | undefined {\n return traceSessions.get(sessionId);\n}\n\nexport function deleteTraceSession(sessionId: string): void {\n traceSessions.delete(sessionId);\n}\n\nexport function getMonotonicMs(session: TraceSession): number {\n return Number((process.hrtime.bigint() - session.startHrTime) / 1_000_000n);\n}\n","export interface TraceAction {\n class: string;\n method: string;\n}\n\nconst TOOL_MAP: Record<string, TraceAction> = {\n navigate: { class: 'Page', method: 'navigate' },\n click_element: { class: 'Element', method: 'click' },\n set_value: { class: 'Element', method: 'fill' },\n scroll: { class: 'Page', method: 'scroll' },\n tap_element: { class: 'Element', method: 'tap' },\n swipe: { class: 'Page', method: 'swipe' },\n drag_and_drop: { class: 'Element', method: 'dragTo' },\n execute_script: { class: 'Page', method: 'evaluate' },\n launch_chrome: { class: 'Browser', method: 'launch' },\n};\n\nexport function mapToolToTraceAction(toolName: string): TraceAction | null {\n return TOOL_MAP[toolName] ?? null;\n}\n\nfunction extractSelectorLabel(selector: string): string {\n // UiAutomator: android=new UiSelector().text(\"Label\") or .description(\"Label\")\n const uiautomator = selector.match(/\\.(?:text|description|textContains)\\(\"([^\"]+)\"\\)/);\n if (uiautomator) return uiautomator[1];\n\n // Accessibility ID: ~label\n if (selector.startsWith('~')) return selector.slice(1);\n\n // iOS predicate: -ios predicate string:label == \"X\" or name == \"X\"\n const predicate = selector.match(/(?:label|name|value)\\s*==\\s*\"([^\"]+)\"/);\n if (predicate) return predicate[1];\n\n // XPath attribute: [@text=\"X\"] [@label=\"X\"] [@name=\"X\"] [@content-desc=\"X\"]\n const xpath = selector.match(/@(?:text|label|name|content-desc)=\"([^\"]+)\"/);\n if (xpath) return xpath[1];\n\n return selector;\n}\n\nexport function formatActionTitle(action: TraceAction, params: Record<string, unknown>): string {\n const { class: cls, method } = action;\n const firstKey = Object.keys(params)[0];\n const firstVal = Object.values(params)[0];\n if (firstVal === undefined) return `${cls}.${method}()`;\n\n const raw = String(firstVal);\n const label = firstKey === 'selector' ? extractSelectorLabel(raw) : raw;\n return `${cls}.${method}(\"${label.slice(0, 80)}\")`;\n}\n"],"mappings":"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","names":["require"]}
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "type": "git",
7
7
  "url": "git://github.com/webdriverio/mcp.git"
8
8
  },
9
- "version": "3.4.3",
9
+ "version": "3.5.0",
10
10
  "description": "MCP server with WebdriverIO for browser and mobile app automation (iOS/Android via Appium)",
11
11
  "main": "./lib/server.js",
12
12
  "module": "./lib/server.js",
@@ -19,10 +19,15 @@
19
19
  "./snapshot": {
20
20
  "import": "./lib/snapshot.js",
21
21
  "types": "./lib/snapshot.d.ts"
22
+ },
23
+ "./trace": {
24
+ "import": "./lib/trace.js",
25
+ "types": "./lib/trace.d.ts"
22
26
  }
23
27
  },
24
28
  "bin": {
25
- "wdio-mcp": "lib/server.js"
29
+ "wdio-mcp": "lib/server.js",
30
+ "wdio-show-trace": "lib/show-trace.js"
26
31
  },
27
32
  "license": "MIT",
28
33
  "publishConfig": {
@@ -55,11 +60,14 @@
55
60
  "sharp": "^0.34.5",
56
61
  "webdriverio": "^9.27.0",
57
62
  "xpath": "^0.0.34",
63
+ "yazl": "^3.3.1",
58
64
  "zod": "^4.3.6"
59
65
  },
60
66
  "devDependencies": {
61
67
  "@release-it/conventional-changelog": "^10.0.6",
62
68
  "@types/node": "^20.19.37",
69
+ "@types/yauzl": "^2.10.3",
70
+ "@types/yazl": "^3.3.1",
63
71
  "@wdio/eslint": "^0.1.3",
64
72
  "@wdio/types": "^9.27.0",
65
73
  "eslint": "^9.39.4",
@@ -71,7 +79,8 @@
71
79
  "tsup": "^8.5.1",
72
80
  "tsx": "^4.21.0",
73
81
  "typescript": "~5.9.3",
74
- "vitest": "^4.1.2"
82
+ "vitest": "^4.1.2",
83
+ "yauzl": "^3.3.0"
75
84
  },
76
85
  "packageManager": "pnpm@10.32.1",
77
86
  "pnpm": {
@@ -79,7 +88,7 @@
79
88
  "release-it>undici": "^6.24.0",
80
89
  "basic-ftp": "^5.3.1",
81
90
  "lodash": "^4.18.1",
82
- "hono": "^4.12.17",
91
+ "hono": "^4.12.18",
83
92
  "@hono/node-server": "^1.19.14",
84
93
  "fast-xml-parser": "^5.7.3",
85
94
  "defu": "^6.1.7",