chromex-mcp 1.8.0 → 1.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -78,7 +78,7 @@ Chromex is a direct CDP layer for coding agents. It sits between raw Chrome DevT
78
78
 
79
79
  The core runtime uses only Node.js built-in modules. Chromex does not install heavy browser automation runtimes, Selenium, browser drivers, telemetry SDKs, update checkers, or bundled browsers.
80
80
 
81
- The only exception is the optional `audit` command: it shells out to Lighthouse with `npx --yes lighthouse` when you explicitly run an audit. All other CLI and MCP commands run through Chromex's own CDP client.
81
+ The only exception is the optional `audit` command: it uses `npx` to resolve Lighthouse on demand, then runs the Lighthouse JavaScript CLI directly with Node when you explicitly run an audit. All other CLI and MCP commands run through Chromex's own CDP client.
82
82
 
83
83
  Development dependencies are used only for tests and token benchmarks.
84
84
 
package/docs/security.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  Chromex is designed for AI agents interacting with real browsers. Security is a first-class concern.
4
4
 
5
+ ## Reporting Vulnerabilities
6
+
7
+ Report suspected vulnerabilities privately to `whallysson.dev@gmail.com`. Do not open a public issue for an undisclosed vulnerability.
8
+
9
+ Include the affected versions and platforms, reproducible steps or a proof of concept, the expected impact, and any suggested remediation. Keep the report and technical details private until a fixed release is available or a disclosure date is agreed.
10
+
5
11
  ## Config File
6
12
 
7
13
  All security settings live in `~/.chromex/config.json` (auto-created on first run).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chromex-mcp",
3
- "version": "1.8.0",
3
+ "version": "1.8.2",
4
4
  "description": "Agent-first Chrome DevTools toolkit with a token-efficient CLI, 85 typed MCP tools, modal-free pipe transport, diagnostics, memory analysis, extensions, and WebMCP.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -50,6 +50,13 @@
50
50
  },
51
51
  "devDependencies": {
52
52
  "js-tiktoken": "^1.0.21",
53
- "vitest": "^3.0.0"
53
+ "vitest": "^4.1.11"
54
+ },
55
+ "overrides": {
56
+ "esbuild": "^0.28.1",
57
+ "nanoid": "^3.3.16",
58
+ "picomatch": "^4.0.4",
59
+ "postcss": "^8.5.23",
60
+ "vite": "^7.3.5"
54
61
  }
55
62
  }
@@ -1,13 +1,59 @@
1
- // Lighthouse audit via subprocess (zero deps -- invokes npx lighthouse externally)
2
1
  // Chrome: connects to existing browser via --port (reuses session)
3
2
  // Other browsers (Brave, Edge, etc.): Lighthouse launches its own headless Chrome
4
3
 
5
- import { execSync } from 'child_process';
4
+ import { execFileSync } from 'child_process';
6
5
  import { existsSync } from 'fs';
7
6
  import { resolveArtifactPath } from '../artifacts.mjs';
8
7
  import { evalStr } from './evaluate.mjs';
9
8
 
10
9
  const VALID_CATEGORIES = ['performance', 'accessibility', 'seo', 'best-practices'];
10
+ const LIGHTHOUSE_PACKAGE = 'lighthouse';
11
+ const LIGHTHOUSE_RESOLVER = `
12
+ const { existsSync, realpathSync } = require('node:fs');
13
+ const { delimiter, join } = require('node:path');
14
+ const executablePath = (process.env.PATH || '')
15
+ .split(delimiter)
16
+ .map(directory => join(directory, 'lighthouse'))
17
+ .find(existsSync);
18
+ if (!executablePath) throw new Error('Lighthouse executable not found');
19
+ process.stdout.write(realpathSync(executablePath));
20
+ `;
21
+ let cachedLighthouseCliPath;
22
+
23
+ function resolveLighthouseCliPath() {
24
+ if (cachedLighthouseCliPath && existsSync(cachedLighthouseCliPath)) {
25
+ return cachedLighthouseCliPath;
26
+ }
27
+
28
+ try {
29
+ const cliPath = execFileSync('npx', [
30
+ '--yes',
31
+ `--package=${LIGHTHOUSE_PACKAGE}`,
32
+ '--',
33
+ process.execPath,
34
+ '-e',
35
+ LIGHTHOUSE_RESOLVER,
36
+ ], {
37
+ encoding: 'utf8',
38
+ timeout: 120000,
39
+ stdio: ['pipe', 'pipe', 'pipe'],
40
+ shell: false,
41
+ }).trim();
42
+
43
+ if (!cliPath || !existsSync(cliPath)) {
44
+ throw new Error('Lighthouse executable not found after installation');
45
+ }
46
+
47
+ cachedLighthouseCliPath = cliPath;
48
+ return cachedLighthouseCliPath;
49
+ } catch (error) {
50
+ const stderr = error.stderr?.toString().trim() || '';
51
+ if (error.code === 'ENOENT') {
52
+ throw new Error('npx not found. Install Node.js with npm.');
53
+ }
54
+ throw new Error(`Lighthouse setup failed: ${stderr || error.message}`);
55
+ }
56
+ }
11
57
 
12
58
  // Find any Chromium-based browser for CHROME_PATH env var
13
59
  function findChromiumPath() {
@@ -30,8 +76,9 @@ function findChromiumPath() {
30
76
  // Check if Chrome's HTTP debug endpoint is available (Brave/Edge don't expose it)
31
77
  function isHttpDebugAvailable(port) {
32
78
  try {
33
- const result = execSync(`curl -sf http://127.0.0.1:${port}/json/version`, {
79
+ const result = execFileSync('curl', ['-sf', `http://127.0.0.1:${port}/json/version`], {
34
80
  encoding: 'utf8', timeout: 3000, stdio: ['pipe', 'pipe', 'pipe'],
81
+ shell: false,
35
82
  });
36
83
  return result.length > 0;
37
84
  } catch {
@@ -88,7 +135,8 @@ export async function auditStr(cdp, sid, categories, device, reportPath) {
88
135
  mode = 'standalone (headless Chrome)';
89
136
  }
90
137
 
91
- const cmd = `npx --yes lighthouse ${JSON.stringify(url)} ${args.join(' ')}`;
138
+ const lighthouseArgs = [url, ...args];
139
+ const lighthouseCliPath = resolveLighthouseCliPath();
92
140
 
93
141
  // Set CHROME_PATH for standalone mode (Lighthouse uses chrome-launcher which reads it)
94
142
  const env = { ...process.env };
@@ -99,18 +147,16 @@ export async function auditStr(cdp, sid, categories, device, reportPath) {
99
147
 
100
148
  let jsonOutput;
101
149
  try {
102
- jsonOutput = execSync(cmd, {
150
+ jsonOutput = execFileSync(process.execPath, [lighthouseCliPath, ...lighthouseArgs], {
103
151
  encoding: 'utf8',
104
152
  timeout: 120000,
105
153
  stdio: ['pipe', 'pipe', 'pipe'],
106
154
  maxBuffer: 50 * 1024 * 1024,
107
155
  env,
156
+ shell: false,
108
157
  });
109
158
  } catch (e) {
110
159
  const stderr = e.stderr?.toString().trim() || '';
111
- if (stderr.includes('not found') || stderr.includes('ENOENT')) {
112
- throw new Error('lighthouse not found. Install: npm i -g lighthouse');
113
- }
114
160
  if (stderr.includes('No Chrome installations found')) {
115
161
  throw new Error('Lighthouse needs Chrome installed to run in standalone mode. Install Google Chrome or run against a Chrome instance with debug port.');
116
162
  }
@@ -801,7 +801,7 @@ const TOOLS = [
801
801
  categories: { type: 'string', description: 'Comma-separated: performance,accessibility,seo,best-practices (default: all)' },
802
802
  device: { type: 'string', enum: ['mobile', 'desktop'], description: 'Device preset (default: mobile)' },
803
803
  reportPath: { type: 'string', description: 'Path to save full HTML report' },
804
- }, ['target'], RO),
804
+ }, ['target'], DESTRUCTIVE),
805
805
 
806
806
  tool('chromex_stats',
807
807
  'Session analytics: command counts, average timing, error rates, action timeline. All data is local, never sent externally.',
@@ -1053,7 +1053,7 @@ function toolToCmd(name, p) {
1053
1053
  return { cmd: 'webmcp', args: a };
1054
1054
  }
1055
1055
  case 'chromex_webauthn': return { cmd: 'webauthn', args: [p.action] };
1056
- case 'chromex_audit': return { cmd: 'audit', args: [p.categories || '', p.device || '', p.reportPath || ''].filter(Boolean) };
1056
+ case 'chromex_audit': return { cmd: 'audit', args: [p.categories ?? '', p.device ?? '', p.reportPath ?? ''] };
1057
1057
  case 'chromex_stats': {
1058
1058
  const a = [];
1059
1059
  if (p.full) a.push('--full');