crawlio-browser 1.4.4 → 1.4.5

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
  // src/shared/constants.ts
2
2
  import { homedir } from "os";
3
3
  import { join } from "path";
4
- var PKG_VERSION = "1.4.4";
4
+ var PKG_VERSION = "1.4.5";
5
5
  var WS_PORT = 9333;
6
6
  var WS_HOST = "127.0.0.1";
7
7
  var CRAWLIO_PORT_FILE = join(
@@ -7,7 +7,7 @@ import {
7
7
  WS_PORT,
8
8
  WS_RECONNECT_GRACE,
9
9
  WS_STALE_THRESHOLD
10
- } from "./chunk-QZGTL4WX.js";
10
+ } from "./chunk-3UA6NXNB.js";
11
11
 
12
12
  // src/mcp-server/index.ts
13
13
  import { randomBytes as randomBytes2 } from "crypto";
@@ -4027,7 +4027,7 @@ function createCodeModeTools(bridge2, crawlio2) {
4027
4027
  process.title = "Crawlio Agent";
4028
4028
  var initMode = process.argv.includes("init") || process.argv.includes("--setup") || process.argv.includes("setup");
4029
4029
  if (initMode) {
4030
- const { runInit } = await import("./init-I76TEVJC.js");
4030
+ const { runInit } = await import("./init-AJOP2HY7.js");
4031
4031
  await runInit(process.argv.slice(2));
4032
4032
  process.exit(0);
4033
4033
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  PKG_VERSION
3
- } from "./chunk-QZGTL4WX.js";
3
+ } from "./chunk-3UA6NXNB.js";
4
4
 
5
5
  // src/mcp-server/init.ts
6
6
  import { execFileSync, spawn } from "child_process";
@@ -58,21 +58,220 @@ function parseFlags(argv) {
58
58
  }
59
59
  return opts;
60
60
  }
61
- function buildAddMcpArgs(options) {
62
- const args = ["-y", "add-mcp"];
63
- const pkg = `crawlio-browser@${PKG_VERSION}`;
64
- if (options.portal) {
65
- args.push(MCP_URL);
66
- } else if (options.full) {
67
- args.push(`${pkg} --full`);
68
- } else {
69
- args.push(pkg);
61
+ var CLIENT_REGISTRY = [
62
+ {
63
+ name: "Claude Code",
64
+ configPath: join(HOME, ".claude.json"),
65
+ serverKey: "mcpServers",
66
+ format: "json",
67
+ detect: () => existsSync(join(HOME, ".claude"))
68
+ },
69
+ {
70
+ name: "Claude Desktop",
71
+ configPath: join(HOME, "Library", "Application Support", "Claude", "claude_desktop_config.json"),
72
+ serverKey: "mcpServers",
73
+ format: "json",
74
+ detect: () => existsSync(join(HOME, "Library", "Application Support", "Claude"))
75
+ },
76
+ {
77
+ name: "VS Code",
78
+ configPath: join(HOME, "Library", "Application Support", "Code", "User", "mcp.json"),
79
+ serverKey: "servers",
80
+ format: "json",
81
+ detect: () => existsSync(join(HOME, ".vscode"))
82
+ },
83
+ {
84
+ name: "Cursor",
85
+ configPath: join(HOME, ".cursor", "mcp.json"),
86
+ serverKey: "mcpServers",
87
+ format: "json",
88
+ detect: () => existsSync(join(HOME, ".cursor"))
89
+ },
90
+ {
91
+ name: "Windsurf",
92
+ configPath: join(HOME, ".codeium", "windsurf", "mcp_config.json"),
93
+ serverKey: "mcpServers",
94
+ format: "json",
95
+ detect: () => existsSync(join(HOME, ".codeium", "windsurf"))
96
+ },
97
+ {
98
+ name: "Cline (VS Code)",
99
+ configPath: join(HOME, "Library", "Application Support", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
100
+ serverKey: "mcpServers",
101
+ format: "json",
102
+ detect: () => existsSync(join(HOME, "Library", "Application Support", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings")),
103
+ transform: (entry) => ({ ...entry, disabled: false })
104
+ },
105
+ {
106
+ name: "Cline CLI",
107
+ configPath: join(HOME, ".cline", "data", "settings", "cline_mcp_settings.json"),
108
+ serverKey: "mcpServers",
109
+ format: "json",
110
+ detect: () => existsSync(join(HOME, ".cline")),
111
+ transform: (entry) => ({ ...entry, disabled: false })
112
+ },
113
+ {
114
+ name: "Copilot CLI",
115
+ configPath: join(HOME, ".copilot", "mcp-config.json"),
116
+ serverKey: "mcpServers",
117
+ format: "json",
118
+ detect: () => existsSync(join(HOME, ".copilot"))
119
+ },
120
+ {
121
+ name: "Gemini CLI",
122
+ configPath: join(HOME, ".gemini", "settings.json"),
123
+ serverKey: "mcpServers",
124
+ format: "json",
125
+ detect: () => existsSync(join(HOME, ".gemini"))
126
+ },
127
+ {
128
+ name: "Codex CLI",
129
+ configPath: join(HOME, ".codex", "config.toml"),
130
+ serverKey: "mcp_servers",
131
+ format: "toml",
132
+ detect: () => existsSync(join(HOME, ".codex"))
133
+ },
134
+ {
135
+ name: "Goose",
136
+ configPath: join(HOME, ".config", "goose", "config.yaml"),
137
+ serverKey: "extensions",
138
+ format: "yaml",
139
+ detect: () => existsSync(join(HOME, ".config", "goose"))
140
+ },
141
+ {
142
+ name: "OpenCode",
143
+ configPath: join(HOME, ".config", "opencode", "opencode.json"),
144
+ serverKey: "mcp",
145
+ format: "json",
146
+ detect: () => existsSync(join(HOME, ".config", "opencode")),
147
+ transform: (entry) => {
148
+ const e = entry;
149
+ return { command: [e.command, ...e.args || []], env: entry.env };
150
+ }
151
+ },
152
+ {
153
+ name: "Zed",
154
+ configPath: join(HOME, "Library", "Application Support", "Zed", "settings.json"),
155
+ serverKey: "context_servers",
156
+ format: "json",
157
+ detect: () => existsSync(join(HOME, "Library", "Application Support", "Zed")),
158
+ transform: (entry) => ({
159
+ settings: { source: "custom", command: entry }
160
+ })
161
+ },
162
+ {
163
+ name: "Antigravity",
164
+ configPath: join(HOME, ".gemini", "antigravity", "mcp_config.json"),
165
+ serverKey: "mcpServers",
166
+ format: "json",
167
+ detect: () => existsSync(join(HOME, ".gemini", "antigravity"))
168
+ }
169
+ ];
170
+ function configureClient(client, entry, dryRun) {
171
+ const finalEntry = client.transform ? client.transform(entry) : entry;
172
+ if (client.format === "json") {
173
+ let config = {};
174
+ if (existsSync(client.configPath)) {
175
+ try {
176
+ config = JSON.parse(readFileSync(client.configPath, "utf-8"));
177
+ } catch {
178
+ config = {};
179
+ }
180
+ }
181
+ const section = config[client.serverKey] || {};
182
+ if ("crawlio-browser" in section) return "skipped";
183
+ if (dryRun) return "configured";
184
+ section["crawlio-browser"] = finalEntry;
185
+ config[client.serverKey] = section;
186
+ mkdirSync(dirname(client.configPath), { recursive: true });
187
+ writeFileSync(client.configPath, JSON.stringify(config, null, 2) + "\n");
188
+ return "configured";
189
+ }
190
+ if (client.format === "toml") {
191
+ let content = "";
192
+ if (existsSync(client.configPath)) {
193
+ content = readFileSync(client.configPath, "utf-8");
194
+ }
195
+ if (content.includes("[mcp_servers.crawlio-browser]") || content.includes('[mcp_servers."crawlio-browser"]')) {
196
+ return "skipped";
197
+ }
198
+ if (dryRun) return "configured";
199
+ const e = entry;
200
+ const argsStr = (e.args || []).map((a) => `"${a}"`).join(", ");
201
+ const block = `
202
+ [mcp_servers.crawlio-browser]
203
+ command = "${e.command}"
204
+ args = [${argsStr}]
205
+ `;
206
+ mkdirSync(dirname(client.configPath), { recursive: true });
207
+ writeFileSync(client.configPath, content + block);
208
+ return "configured";
70
209
  }
71
- args.push("--name", "crawlio-browser", "--global", "--yes");
72
- for (const agent of options.agents) {
73
- args.push("-a", agent);
210
+ if (client.format === "yaml") {
211
+ let content = "";
212
+ if (existsSync(client.configPath)) {
213
+ content = readFileSync(client.configPath, "utf-8");
214
+ }
215
+ if (content.includes("crawlio-browser:")) {
216
+ return "skipped";
217
+ }
218
+ if (dryRun) return "configured";
219
+ const e = entry;
220
+ const argsYaml = (e.args || []).map((a) => ` - ${a}`).join("\n");
221
+ const block = `
222
+ crawlio-browser:
223
+ name: crawlio-browser
224
+ type: stdio
225
+ cmd: ${e.command}
226
+ args:
227
+ ${argsYaml}
228
+ `;
229
+ if (!content.includes("extensions:")) {
230
+ content += "\nextensions:\n";
231
+ }
232
+ mkdirSync(dirname(client.configPath), { recursive: true });
233
+ writeFileSync(client.configPath, content + block);
234
+ return "configured";
74
235
  }
75
- return args;
236
+ return "error";
237
+ }
238
+ function configureAllClients(options) {
239
+ const entry = options.portal ? buildPortalEntry() : buildStdioEntry({ full: options.full });
240
+ const candidates = options.agents.length > 0 ? CLIENT_REGISTRY.filter((c) => options.agents.some((a) => c.name.toLowerCase().includes(a.toLowerCase()))) : CLIENT_REGISTRY.filter((c) => c.detect());
241
+ if (candidates.length === 0) {
242
+ console.log(` ${dim(" No MCP clients detected on this machine")}`);
243
+ printManualInstructions(entry);
244
+ return;
245
+ }
246
+ let configured = 0;
247
+ let skipped = 0;
248
+ for (const client of candidates) {
249
+ const result = configureClient(client, entry, options.dryRun);
250
+ if (result === "configured") {
251
+ const prefix = options.dryRun ? dim("~") : green("+");
252
+ console.log(` ${prefix} ${client.name} ${dim("\u2192 " + client.configPath)}`);
253
+ configured++;
254
+ } else if (result === "skipped") {
255
+ console.log(` ${dim("=")} ${client.name} ${dim("(already configured)")}`);
256
+ skipped++;
257
+ } else {
258
+ console.log(` ${yellow("!")} ${client.name} ${dim("\u2014 failed to write config")}`);
259
+ }
260
+ }
261
+ if (configured === 0 && skipped > 0) {
262
+ console.log(` ${dim(" All detected clients already configured")}`);
263
+ }
264
+ }
265
+ function printManualInstructions(entry) {
266
+ console.log("");
267
+ console.log(` ${dim("Add this to your MCP client config:")}`);
268
+ console.log("");
269
+ const snippet = { "crawlio-browser": entry };
270
+ const lines = JSON.stringify(snippet, null, 2).split("\n");
271
+ for (const line of lines) {
272
+ console.log(` ${dim(line)}`);
273
+ }
274
+ console.log("");
76
275
  }
77
276
  function buildStdioEntry(options) {
78
277
  if (platform() === "darwin") {
@@ -620,7 +819,7 @@ async function portalFlow(options) {
620
819
  await ensurePortalRunning(options.dryRun);
621
820
  console.log("");
622
821
  console.log(` ${cyan("\u25C6")} ${bold("MCP Configuration")} ${dim("(portal mode)")}`);
623
- runAddMcp(options);
822
+ configureAllClients(options);
624
823
  }
625
824
  async function configureMetaMcp(found, options) {
626
825
  console.log("");
@@ -667,47 +866,7 @@ async function configureMetaMcp(found, options) {
667
866
  function configureStdioClients(options) {
668
867
  console.log("");
669
868
  console.log(` ${cyan("\u25C6")} ${bold("MCP Configuration")} ${dim("(stdio mode)")}`);
670
- runAddMcp(options);
671
- }
672
- function runAddMcp(options) {
673
- const npxBin = platform() === "win32" ? "npx.cmd" : "npx";
674
- const args = buildAddMcpArgs(options);
675
- if (options.dryRun) {
676
- console.log(` ${dim("~")} Would run: ${npxBin} ${args.join(" ")}`);
677
- return;
678
- }
679
- try {
680
- const output = execFileSync(npxBin, args, {
681
- encoding: "utf-8",
682
- timeout: 6e4,
683
- env: { ...process.env, npm_config_yes: "true" }
684
- });
685
- const lines = output.split("\n").filter((l) => l.trim());
686
- let configuredCount = 0;
687
- for (const line of lines) {
688
- const trimmed = line.trim();
689
- if (trimmed) {
690
- console.log(` ${green("+")} ${trimmed}`);
691
- configuredCount++;
692
- }
693
- }
694
- if (configuredCount === 0) {
695
- console.log(` ${dim(" add-mcp ran but no clients detected")}`);
696
- }
697
- } catch (error) {
698
- const errObj = error;
699
- const code = errObj?.code;
700
- const msg = error instanceof Error ? error.message : String(error);
701
- if (code === "ENOENT") {
702
- console.log(` ${yellow("!")} ${npxBin} not found in PATH \u2014 install Node.js 18+ and retry`);
703
- } else if (code === "ETIMEDOUT" || msg.includes("ETIMEDOUT") || msg.includes("timed out")) {
704
- console.log(` ${yellow("!")} add-mcp timed out \u2014 check network and retry`);
705
- } else {
706
- console.log(` ${yellow("!")} add-mcp failed: ${msg.slice(0, 200)}`);
707
- }
708
- const target = options.portal ? MCP_URL : "crawlio-browser";
709
- console.log(` ${dim(` Manual: npx add-mcp ${target} --name crawlio-browser --global`)}`);
710
- }
869
+ configureAllClients(options);
711
870
  }
712
871
  var LOGO_LINES = [
713
872
  " \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 ",
@@ -832,10 +991,12 @@ async function runInit(argv) {
832
991
  await printSummary(options);
833
992
  }
834
993
  export {
835
- buildAddMcpArgs,
994
+ CLIENT_REGISTRY,
836
995
  buildCloudflareEntry,
837
996
  buildPortalEntry,
838
997
  buildStdioEntry,
998
+ configureAllClients,
999
+ configureClient,
839
1000
  createAppWrapper,
840
1001
  extractSkillName,
841
1002
  findConflictingConfigs,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crawlio-browser",
3
- "version": "1.4.4",
3
+ "version": "1.4.5",
4
4
  "description": "MCP server with 96 CDP-backed tools for browser automation — screenshots, DOM, network capture, framework detection, cookies, storage, session recording, performance metrics via Chrome",
5
5
  "type": "module",
6
6
  "main": "dist/mcp-server/index.js",