@xbrowser/cli 1.22.0 → 1.23.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.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getPluginLoader,
3
3
  resetPluginLoader
4
- } from "./chunk-PIWNMC36.js";
4
+ } from "./chunk-A3MORKYR.js";
5
5
  import "./chunk-KFQGP6VL.js";
6
6
  export {
7
7
  getPluginLoader,
@@ -1,9 +1,9 @@
1
- import {
2
- HumanInteractionManager
3
- } from "./chunk-TEXCXIBW.js";
4
1
  import {
5
2
  buildViewerUrl
6
3
  } from "./chunk-3OD76SUE.js";
4
+ import {
5
+ HumanInteractionManager
6
+ } from "./chunk-W44UXZSC.js";
7
7
  import "./chunk-ZTHE5RBZ.js";
8
8
  import "./chunk-Q2DFJQGS.js";
9
9
  import "./chunk-KFQGP6VL.js";
@@ -1,9 +1,10 @@
1
+ import {
2
+ HumanInteractionManager
3
+ } from "./chunk-LPW6QS4M.js";
1
4
  import {
2
5
  buildViewerUrl
3
6
  } from "./chunk-3OD76SUE.js";
4
- import {
5
- HumanInteractionManager
6
- } from "./chunk-NKW4A74J.js";
7
+ import "./chunk-ZTHE5RBZ.js";
7
8
  import "./chunk-Q2DFJQGS.js";
8
9
  import "./chunk-KFQGP6VL.js";
9
10
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  HumanInteractionManager
3
- } from "./chunk-OMU63E6J.js";
3
+ } from "./chunk-FBQZ3PVD.js";
4
4
  import {
5
5
  buildViewerUrl
6
6
  } from "./chunk-TZPKFUBT.js";
@@ -0,0 +1,243 @@
1
+ import {
2
+ executeChain,
3
+ executeCommand
4
+ } from "./chunk-LFX24QJZ.js";
5
+ import "./chunk-2Q3GQRUP.js";
6
+ import "./chunk-JKVUFP3G.js";
7
+ import "./chunk-3OD76SUE.js";
8
+ import "./chunk-ZTHE5RBZ.js";
9
+ import "./chunk-Q2DFJQGS.js";
10
+ import "./chunk-7OP2ISEY.js";
11
+ import "./chunk-GYB5BOSP.js";
12
+ import "./chunk-MYH6FIBZ.js";
13
+ import "./chunk-GDKLH7ZY.js";
14
+ import "./chunk-WYETQ5C7.js";
15
+ import "./chunk-75DNUI6M.js";
16
+ import "./chunk-KFQGP6VL.js";
17
+
18
+ // src/mcp/server.ts
19
+ var TOOLS = [
20
+ {
21
+ name: "browser_navigate",
22
+ description: "Navigate to a URL and optionally run follow-up commands as a chain. Use this to open pages. Session auto-creates; pass session to isolate state.",
23
+ inputSchema: {
24
+ type: "object",
25
+ properties: {
26
+ url: { type: "string", description: "URL to navigate to" },
27
+ session: { type: "string", description: "Session name (default: mcp)" },
28
+ chain: {
29
+ type: "string",
30
+ description: 'Optional follow-up command chain joined by && (e.g. `click "#btn" && text .result`). Full command list: xbrowser --help'
31
+ }
32
+ },
33
+ required: ["url"]
34
+ }
35
+ },
36
+ {
37
+ name: "browser_act",
38
+ description: "Run an interaction command on the current page: click / fill / type / press / select / check / hover / scroll / wait / eval. Selectors support CSS and text= prefix.",
39
+ inputSchema: {
40
+ type: "object",
41
+ properties: {
42
+ command: {
43
+ type: "string",
44
+ description: "Command word, e.g. click / fill / press / wait / eval"
45
+ },
46
+ args: {
47
+ type: "object",
48
+ description: 'Command parameters, e.g. { selector: "#input", value: "hello" }'
49
+ },
50
+ session: { type: "string", description: "Session name (default: mcp)" }
51
+ },
52
+ required: ["command"]
53
+ }
54
+ },
55
+ {
56
+ name: "browser_read",
57
+ description: "Read page content: text / html / title / url. Cheaper than snapshot for plain content.",
58
+ inputSchema: {
59
+ type: "object",
60
+ properties: {
61
+ kind: { type: "string", enum: ["text", "html", "title", "url"] },
62
+ selector: { type: "string", description: "Optional CSS selector to scope the read" },
63
+ session: { type: "string", description: "Session name (default: mcp)" }
64
+ },
65
+ required: ["kind"]
66
+ }
67
+ },
68
+ {
69
+ name: "browser_snapshot",
70
+ description: "Accessibility-tree snapshot of interactive elements \u2014 the token-efficient way for an agent to see the page. Returns refs usable with browser_act selectors.",
71
+ inputSchema: {
72
+ type: "object",
73
+ properties: {
74
+ interactiveOnly: { type: "boolean", description: "Only interactive elements (default true)" },
75
+ session: { type: "string", description: "Session name (default: mcp)" }
76
+ }
77
+ }
78
+ },
79
+ {
80
+ name: "browser_screenshot",
81
+ description: "Take a screenshot. Returns the file path (use screenshot --base64 chain for inline images).",
82
+ inputSchema: {
83
+ type: "object",
84
+ properties: {
85
+ output: { type: "string", description: "Output PNG path" },
86
+ fullPage: { type: "boolean" },
87
+ session: { type: "string", description: "Session name (default: mcp)" }
88
+ }
89
+ }
90
+ },
91
+ {
92
+ name: "browser_network",
93
+ description: "Inspect captured network requests: list / top / analyze.",
94
+ inputSchema: {
95
+ type: "object",
96
+ properties: {
97
+ action: { type: "string", enum: ["list", "top", "analyze"] },
98
+ session: { type: "string", description: "Session name (default: mcp)" }
99
+ },
100
+ required: ["action"]
101
+ }
102
+ },
103
+ {
104
+ name: "browser_replay",
105
+ description: "Replay a recorded flow with the self-healing engine \u2014 survives site redesigns via selector cascade (semantic candidates \u2192 fingerprints \u2192 coordinates \u2192 knowledge base). Deterministic, no LLM cost.",
106
+ inputSchema: {
107
+ type: "object",
108
+ properties: {
109
+ file: { type: "string", description: "Path to recorded YAML/JSON" },
110
+ slowMo: { type: "number", description: "ms delay between steps" },
111
+ session: { type: "string", description: "Session name (default: mcp)" }
112
+ },
113
+ required: ["file"]
114
+ }
115
+ }
116
+ ];
117
+ var DEFAULT_SESSION = "mcp";
118
+ async function runTool(name, args) {
119
+ const session = args.session || DEFAULT_SESSION;
120
+ const sessionOpts = { sessionName: session };
121
+ const text = (v) => ({ content: [{ type: "text", text: JSON.stringify(v, null, 2) }] });
122
+ switch (name) {
123
+ case "browser_navigate": {
124
+ const url = args.url;
125
+ let chain = `goto ${url}`;
126
+ if (args.chain) chain += ` && ${args.chain}`;
127
+ const result = await executeChain(chain, sessionOpts);
128
+ return text({ ok: result.success, steps: result.steps?.map((s) => ({ command: s.command, success: s.success })) });
129
+ }
130
+ case "browser_act": {
131
+ const command = args.command;
132
+ const cmdArgs = args.args || {};
133
+ const result = await executeCommand(command, cmdArgs, session, {});
134
+ return text(result);
135
+ }
136
+ case "browser_read": {
137
+ const kind = args.kind;
138
+ const params = {};
139
+ if (args.selector) params.selector = args.selector;
140
+ const result = await executeCommand(kind, params, session, {});
141
+ return text(result);
142
+ }
143
+ case "browser_snapshot": {
144
+ const params = { interactiveOnly: args.interactiveOnly !== false };
145
+ const result = await executeCommand("snapshot", params, session, {});
146
+ return text(result);
147
+ }
148
+ case "browser_screenshot": {
149
+ const params = {
150
+ output: args.output || `output/mcp-${Date.now()}.png`,
151
+ ...args.fullPage ? { fullPage: true } : {}
152
+ };
153
+ const result = await executeCommand("screenshot", params, session, {});
154
+ return text(result);
155
+ }
156
+ case "browser_network": {
157
+ const result = await executeCommand(`network:${args.action}`, {}, session, {});
158
+ return text(result);
159
+ }
160
+ case "browser_replay": {
161
+ const params = {
162
+ file: args.file,
163
+ ...typeof args.slowMo === "number" ? { slowMo: args.slowMo } : {}
164
+ };
165
+ const result = await executeCommand("replay", params, session, {});
166
+ return text(result);
167
+ }
168
+ default:
169
+ throw new Error(`unknown tool: ${name}`);
170
+ }
171
+ }
172
+ function reply(id, result) {
173
+ process.stdout.write(JSON.stringify({ jsonrpc: "2.0", id, result }) + "\n");
174
+ }
175
+ function replyError(id, code, message) {
176
+ process.stdout.write(JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } }) + "\n");
177
+ }
178
+ async function handleRequest(req) {
179
+ if (req.id === void 0) return;
180
+ switch (req.method) {
181
+ case "initialize":
182
+ reply(req.id, {
183
+ protocolVersion: "2024-11-05",
184
+ capabilities: { tools: {} },
185
+ serverInfo: { name: "xbrowser", version: process.env.npm_package_version || "1.23.0" }
186
+ });
187
+ break;
188
+ case "notifications/initialized":
189
+ break;
190
+ case "tools/list":
191
+ reply(req.id, { tools: TOOLS });
192
+ break;
193
+ case "tools/call": {
194
+ const toolName = req.params.name;
195
+ const toolArgs = req.params.arguments || {};
196
+ try {
197
+ const result = await runTool(toolName, toolArgs);
198
+ reply(req.id, { content: result.content });
199
+ } catch (err) {
200
+ reply(req.id, {
201
+ content: [{ type: "text", text: `Error: ${err.message}` }],
202
+ isError: true
203
+ });
204
+ }
205
+ break;
206
+ }
207
+ default:
208
+ replyError(req.id, -32601, `method not found: ${req.method}`);
209
+ }
210
+ }
211
+ var inflight = 0;
212
+ function startMcpStdio() {
213
+ let buffer = "";
214
+ process.stdin.setEncoding("utf8");
215
+ process.stdin.on("data", (chunk) => {
216
+ buffer += chunk;
217
+ let idx;
218
+ while ((idx = buffer.indexOf("\n")) >= 0) {
219
+ const line = buffer.slice(0, idx).trim();
220
+ buffer = buffer.slice(idx + 1);
221
+ if (!line) continue;
222
+ try {
223
+ const req = JSON.parse(line);
224
+ inflight++;
225
+ handleRequest(req).catch((e) => {
226
+ if (req.id !== void 0) replyError(req.id, -32603, e.message);
227
+ }).finally(() => {
228
+ inflight--;
229
+ if (stdinClosed && inflight === 0) process.exit(0);
230
+ });
231
+ } catch {
232
+ }
233
+ }
234
+ });
235
+ let stdinClosed = false;
236
+ process.stdin.on("end", () => {
237
+ stdinClosed = true;
238
+ if (inflight === 0) process.exit(0);
239
+ });
240
+ }
241
+ export {
242
+ startMcpStdio
243
+ };
@@ -0,0 +1,240 @@
1
+ import {
2
+ executeChain,
3
+ executeCommand
4
+ } from "./chunk-TBSS7ES4.js";
5
+ import "./chunk-JKVUFP3G.js";
6
+ import "./chunk-3OD76SUE.js";
7
+ import "./chunk-ZTHE5RBZ.js";
8
+ import "./chunk-Q2DFJQGS.js";
9
+ import "./chunk-IFKJO2UR.js";
10
+ import "./chunk-GYB5BOSP.js";
11
+ import "./chunk-MYH6FIBZ.js";
12
+ import "./chunk-GDKLH7ZY.js";
13
+ import "./chunk-KFQGP6VL.js";
14
+
15
+ // src/mcp/server.ts
16
+ var TOOLS = [
17
+ {
18
+ name: "browser_navigate",
19
+ description: "Navigate to a URL and optionally run follow-up commands as a chain. Use this to open pages. Session auto-creates; pass session to isolate state.",
20
+ inputSchema: {
21
+ type: "object",
22
+ properties: {
23
+ url: { type: "string", description: "URL to navigate to" },
24
+ session: { type: "string", description: "Session name (default: mcp)" },
25
+ chain: {
26
+ type: "string",
27
+ description: 'Optional follow-up command chain joined by && (e.g. `click "#btn" && text .result`). Full command list: xbrowser --help'
28
+ }
29
+ },
30
+ required: ["url"]
31
+ }
32
+ },
33
+ {
34
+ name: "browser_act",
35
+ description: "Run an interaction command on the current page: click / fill / type / press / select / check / hover / scroll / wait / eval. Selectors support CSS and text= prefix.",
36
+ inputSchema: {
37
+ type: "object",
38
+ properties: {
39
+ command: {
40
+ type: "string",
41
+ description: "Command word, e.g. click / fill / press / wait / eval"
42
+ },
43
+ args: {
44
+ type: "object",
45
+ description: 'Command parameters, e.g. { selector: "#input", value: "hello" }'
46
+ },
47
+ session: { type: "string", description: "Session name (default: mcp)" }
48
+ },
49
+ required: ["command"]
50
+ }
51
+ },
52
+ {
53
+ name: "browser_read",
54
+ description: "Read page content: text / html / title / url. Cheaper than snapshot for plain content.",
55
+ inputSchema: {
56
+ type: "object",
57
+ properties: {
58
+ kind: { type: "string", enum: ["text", "html", "title", "url"] },
59
+ selector: { type: "string", description: "Optional CSS selector to scope the read" },
60
+ session: { type: "string", description: "Session name (default: mcp)" }
61
+ },
62
+ required: ["kind"]
63
+ }
64
+ },
65
+ {
66
+ name: "browser_snapshot",
67
+ description: "Accessibility-tree snapshot of interactive elements \u2014 the token-efficient way for an agent to see the page. Returns refs usable with browser_act selectors.",
68
+ inputSchema: {
69
+ type: "object",
70
+ properties: {
71
+ interactiveOnly: { type: "boolean", description: "Only interactive elements (default true)" },
72
+ session: { type: "string", description: "Session name (default: mcp)" }
73
+ }
74
+ }
75
+ },
76
+ {
77
+ name: "browser_screenshot",
78
+ description: "Take a screenshot. Returns the file path (use screenshot --base64 chain for inline images).",
79
+ inputSchema: {
80
+ type: "object",
81
+ properties: {
82
+ output: { type: "string", description: "Output PNG path" },
83
+ fullPage: { type: "boolean" },
84
+ session: { type: "string", description: "Session name (default: mcp)" }
85
+ }
86
+ }
87
+ },
88
+ {
89
+ name: "browser_network",
90
+ description: "Inspect captured network requests: list / top / analyze.",
91
+ inputSchema: {
92
+ type: "object",
93
+ properties: {
94
+ action: { type: "string", enum: ["list", "top", "analyze"] },
95
+ session: { type: "string", description: "Session name (default: mcp)" }
96
+ },
97
+ required: ["action"]
98
+ }
99
+ },
100
+ {
101
+ name: "browser_replay",
102
+ description: "Replay a recorded flow with the self-healing engine \u2014 survives site redesigns via selector cascade (semantic candidates \u2192 fingerprints \u2192 coordinates \u2192 knowledge base). Deterministic, no LLM cost.",
103
+ inputSchema: {
104
+ type: "object",
105
+ properties: {
106
+ file: { type: "string", description: "Path to recorded YAML/JSON" },
107
+ slowMo: { type: "number", description: "ms delay between steps" },
108
+ session: { type: "string", description: "Session name (default: mcp)" }
109
+ },
110
+ required: ["file"]
111
+ }
112
+ }
113
+ ];
114
+ var DEFAULT_SESSION = "mcp";
115
+ async function runTool(name, args) {
116
+ const session = args.session || DEFAULT_SESSION;
117
+ const sessionOpts = { sessionName: session };
118
+ const text = (v) => ({ content: [{ type: "text", text: JSON.stringify(v, null, 2) }] });
119
+ switch (name) {
120
+ case "browser_navigate": {
121
+ const url = args.url;
122
+ let chain = `goto ${url}`;
123
+ if (args.chain) chain += ` && ${args.chain}`;
124
+ const result = await executeChain(chain, sessionOpts);
125
+ return text({ ok: result.success, steps: result.steps?.map((s) => ({ command: s.command, success: s.success })) });
126
+ }
127
+ case "browser_act": {
128
+ const command = args.command;
129
+ const cmdArgs = args.args || {};
130
+ const result = await executeCommand(command, cmdArgs, session, {});
131
+ return text(result);
132
+ }
133
+ case "browser_read": {
134
+ const kind = args.kind;
135
+ const params = {};
136
+ if (args.selector) params.selector = args.selector;
137
+ const result = await executeCommand(kind, params, session, {});
138
+ return text(result);
139
+ }
140
+ case "browser_snapshot": {
141
+ const params = { interactiveOnly: args.interactiveOnly !== false };
142
+ const result = await executeCommand("snapshot", params, session, {});
143
+ return text(result);
144
+ }
145
+ case "browser_screenshot": {
146
+ const params = {
147
+ output: args.output || `output/mcp-${Date.now()}.png`,
148
+ ...args.fullPage ? { fullPage: true } : {}
149
+ };
150
+ const result = await executeCommand("screenshot", params, session, {});
151
+ return text(result);
152
+ }
153
+ case "browser_network": {
154
+ const result = await executeCommand(`network:${args.action}`, {}, session, {});
155
+ return text(result);
156
+ }
157
+ case "browser_replay": {
158
+ const params = {
159
+ file: args.file,
160
+ ...typeof args.slowMo === "number" ? { slowMo: args.slowMo } : {}
161
+ };
162
+ const result = await executeCommand("replay", params, session, {});
163
+ return text(result);
164
+ }
165
+ default:
166
+ throw new Error(`unknown tool: ${name}`);
167
+ }
168
+ }
169
+ function reply(id, result) {
170
+ process.stdout.write(JSON.stringify({ jsonrpc: "2.0", id, result }) + "\n");
171
+ }
172
+ function replyError(id, code, message) {
173
+ process.stdout.write(JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } }) + "\n");
174
+ }
175
+ async function handleRequest(req) {
176
+ if (req.id === void 0) return;
177
+ switch (req.method) {
178
+ case "initialize":
179
+ reply(req.id, {
180
+ protocolVersion: "2024-11-05",
181
+ capabilities: { tools: {} },
182
+ serverInfo: { name: "xbrowser", version: process.env.npm_package_version || "1.23.0" }
183
+ });
184
+ break;
185
+ case "notifications/initialized":
186
+ break;
187
+ case "tools/list":
188
+ reply(req.id, { tools: TOOLS });
189
+ break;
190
+ case "tools/call": {
191
+ const toolName = req.params.name;
192
+ const toolArgs = req.params.arguments || {};
193
+ try {
194
+ const result = await runTool(toolName, toolArgs);
195
+ reply(req.id, { content: result.content });
196
+ } catch (err) {
197
+ reply(req.id, {
198
+ content: [{ type: "text", text: `Error: ${err.message}` }],
199
+ isError: true
200
+ });
201
+ }
202
+ break;
203
+ }
204
+ default:
205
+ replyError(req.id, -32601, `method not found: ${req.method}`);
206
+ }
207
+ }
208
+ var inflight = 0;
209
+ function startMcpStdio() {
210
+ let buffer = "";
211
+ process.stdin.setEncoding("utf8");
212
+ process.stdin.on("data", (chunk) => {
213
+ buffer += chunk;
214
+ let idx;
215
+ while ((idx = buffer.indexOf("\n")) >= 0) {
216
+ const line = buffer.slice(0, idx).trim();
217
+ buffer = buffer.slice(idx + 1);
218
+ if (!line) continue;
219
+ try {
220
+ const req = JSON.parse(line);
221
+ inflight++;
222
+ handleRequest(req).catch((e) => {
223
+ if (req.id !== void 0) replyError(req.id, -32603, e.message);
224
+ }).finally(() => {
225
+ inflight--;
226
+ if (stdinClosed && inflight === 0) process.exit(0);
227
+ });
228
+ } catch {
229
+ }
230
+ }
231
+ });
232
+ let stdinClosed = false;
233
+ process.stdin.on("end", () => {
234
+ stdinClosed = true;
235
+ if (inflight === 0) process.exit(0);
236
+ });
237
+ }
238
+ export {
239
+ startMcpStdio
240
+ };
@@ -222,20 +222,31 @@ var SessionReplayer = class {
222
222
  break;
223
223
  }
224
224
  case "scroll": {
225
- const [dir, distStr] = (action.value || "down:300").split(":");
226
- const dist = Number(distStr) || 300;
227
- const sign = dir === "up" ? -1 : dir === "left" ? 0 : 1;
228
225
  const selector = await this.resolveAndWait(action).catch(() => void 0);
229
- if (selector) {
230
- await page.evaluate(`
231
- (function() {
232
- const el = ${queryJS(selector)};
233
- if (el) el.scrollTop += ${sign * dist};
234
- })()
235
- `).catch(() => {
226
+ if (action.value) {
227
+ const [dir, distStr] = action.value.split(":");
228
+ const dist = Number(distStr) || 300;
229
+ const dx = dir === "left" ? -dist : dir === "right" ? dist : 0;
230
+ const dy = dir === "up" ? -dist : dir === "down" ? dist : 0;
231
+ if (selector) {
232
+ await page.evaluate(`
233
+ (function() {
234
+ const el = ${queryJS(selector)};
235
+ if (el) { el.scrollLeft += ${dx}; el.scrollTop += ${dy}; }
236
+ })()
237
+ `).catch(() => {
238
+ });
239
+ } else {
240
+ await page.evaluate(`window.scrollBy(${dx}, ${dy})`).catch(() => {
241
+ });
242
+ }
243
+ } else if (typeof action.scrollX === "number" || typeof action.scrollY === "number") {
244
+ const sx = action.scrollX ?? 0;
245
+ const sy = action.scrollY ?? 0;
246
+ await page.evaluate(`window.scrollTo(${sx}, ${sy})`).catch(() => {
236
247
  });
237
248
  } else {
238
- await page.evaluate(`window.scrollBy(0, ${sign * dist})`).catch(() => {
249
+ await page.evaluate(`window.scrollBy(0, 300)`).catch(() => {
239
250
  });
240
251
  }
241
252
  break;
@@ -406,12 +417,6 @@ var SessionReplayer = class {
406
417
  }, selector);
407
418
  break;
408
419
  }
409
- case "scroll": {
410
- await page.evaluate(() => {
411
- window.scrollBy(action.scrollX ?? 0, action.scrollY ?? 0);
412
- });
413
- break;
414
- }
415
420
  default:
416
421
  break;
417
422
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xbrowser/cli",
3
- "version": "1.22.0",
3
+ "version": "1.23.1",
4
4
  "description": "Browser automation CLI for web scraping, headless browsing, SEO analysis, and AI agent workflows. A command-line alternative to Playwright, Puppeteer, and Selenium.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -72,30 +72,34 @@
72
72
  "scripts": {
73
73
  "build": "tsup",
74
74
  "dev": "tsup --watch",
75
- "lint": "eslint src/ bin/ --ext .ts",
75
+ "lint": "eslint src/ bin/ tests/ --ext .ts",
76
+ "lint:plugins": "eslint .xcli/plugins/ --ext .ts --max-warnings 0",
76
77
  "lint:plugin-contract": "node lint-scripts/check-plugin-contract.mjs && node lint-scripts/check-plugin-status.mjs",
77
78
  "lint:plugin-status": "node lint-scripts/check-plugin-status.mjs --update",
78
79
  "stealth:check": "vitest run tests/cdp-driver/stealth-health.test.ts tests/cdp-driver/stealth-audit.test.ts tests/cdp-driver/stealth-probe.test.ts",
79
80
  "lint:docs": "node lint-scripts/check-docs-consistency.mjs",
80
81
  "typecheck": "tsc --noEmit",
82
+ "typecheck:tests": "tsc -p tsconfig.tests.json --noEmit",
83
+ "typecheck:plugins": "tsc -p tsconfig.plugins.json --noEmit",
81
84
  "start": "node dist/cli.js",
82
85
  "test": "vitest run",
83
86
  "test:watch": "vitest",
84
87
  "test:e2e": "vitest run --config vitest.e2e.config.ts",
85
- "validate": "npm run typecheck && npm run lint && npm run lint:docs && npm run lint:plugin-contract && npm run build && npm test",
88
+ "test:arena": "vitest run --config vitest.arena.config.ts",
89
+ "validate": "npm run typecheck && npm run typecheck:plugins && npm run lint && npm run lint:plugins && npm run lint:docs && npm run lint:plugin-contract && npm run build && npm test",
86
90
  "prepare": "husky"
87
91
  },
88
92
  "dependencies": {
89
- "@dyyz1993/xcli-core": "^0.19.0",
93
+ "@dyyz1993/xcli-core": "^0.19.1",
90
94
  "@types/react-syntax-highlighter": "^15.5.13",
91
95
  "@types/turndown": "^5.0.6",
92
96
  "cheerio": "^1.2.0",
93
- "imapflow": "^1.3.3",
97
+ "imapflow": "^1.7.8",
94
98
  "lucide-react": "^1.14.0",
95
99
  "react-markdown": "^10.1.0",
96
100
  "react-syntax-highlighter": "^16.1.1",
97
101
  "remark-gfm": "^4.0.1",
98
- "sharp": "^0.34.5",
102
+ "sharp": "^0.35.4",
99
103
  "turndown": "^7.2.4",
100
104
  "turndown-plugin-gfm": "^1.0.2",
101
105
  "ws": "^8.21.0",
@@ -124,6 +128,6 @@
124
128
  ]
125
129
  },
126
130
  "optionalDependencies": {
127
- "undici": "^7.28.0"
131
+ "undici": "^7.29.1"
128
132
  }
129
133
  }