crawlio-browser 1.4.0 → 1.4.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.
Binary file
@@ -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.0";
4
+ var PKG_VERSION = "1.4.2";
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-JRZS5IP6.js";
10
+ } from "./chunk-ZFI2FHEC.js";
11
11
 
12
12
  // src/mcp-server/index.ts
13
13
  import { randomBytes as randomBytes2 } from "crypto";
@@ -4023,9 +4023,10 @@ function createCodeModeTools(bridge2, crawlio2) {
4023
4023
  }
4024
4024
 
4025
4025
  // src/mcp-server/index.ts
4026
+ process.title = "Crawlio Agent";
4026
4027
  var initMode = process.argv.includes("init") || process.argv.includes("--setup") || process.argv.includes("setup");
4027
4028
  if (initMode) {
4028
- const { runInit } = await import("./init-4ITWQXXA.js");
4029
+ const { runInit } = await import("./init-6IG2YJYU.js");
4029
4030
  await runInit(process.argv.slice(2));
4030
4031
  process.exit(0);
4031
4032
  }
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  PKG_VERSION
3
- } from "./chunk-JRZS5IP6.js";
3
+ } from "./chunk-ZFI2FHEC.js";
4
4
 
5
5
  // src/mcp-server/init.ts
6
6
  import { execFileSync, spawn } from "child_process";
7
- import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync, copyFileSync } from "fs";
7
+ import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync, copyFileSync, chmodSync } from "fs";
8
8
  import { join, resolve, dirname, sep, basename } from "path";
9
9
  import { homedir, platform } from "os";
10
10
  import { createServer as createNetServer } from "net";
@@ -60,12 +60,13 @@ function parseFlags(argv) {
60
60
  }
61
61
  function buildAddMcpArgs(options) {
62
62
  const args = ["-y", "add-mcp"];
63
+ const pkg = `crawlio-browser@${PKG_VERSION}`;
63
64
  if (options.portal) {
64
65
  args.push(MCP_URL);
65
66
  } else if (options.full) {
66
- args.push("crawlio-browser --full");
67
+ args.push(`${pkg} --full`);
67
68
  } else {
68
- args.push("crawlio-browser");
69
+ args.push(pkg);
69
70
  }
70
71
  args.push("--name", "crawlio-browser", "--global", "--yes");
71
72
  for (const agent of options.agents) {
@@ -74,7 +75,16 @@ function buildAddMcpArgs(options) {
74
75
  return args;
75
76
  }
76
77
  function buildStdioEntry(options) {
77
- const args = ["-y", "crawlio-browser"];
78
+ if (platform() === "darwin") {
79
+ const serverPath = getServerEntryPath();
80
+ const wrapperPath = createAppWrapper(serverPath);
81
+ if (wrapperPath) {
82
+ const args2 = [];
83
+ if (options?.full) args2.push("--full");
84
+ return { command: wrapperPath, args: args2 };
85
+ }
86
+ }
87
+ const args = ["-y", `crawlio-browser@${PKG_VERSION}`];
78
88
  if (options?.full) args.push("--full");
79
89
  return { command: "npx", args };
80
90
  }
@@ -82,7 +92,15 @@ function buildPortalEntry() {
82
92
  return { type: "http", url: MCP_URL };
83
93
  }
84
94
  function isAlreadyConfigured(config) {
85
- return "crawlio-browser" in config.mcpServers;
95
+ if ("crawlio-browser" in config.mcpServers || "crawlio-agent" in config.mcpServers) return true;
96
+ for (const entry of Object.values(config.mcpServers)) {
97
+ const e = entry;
98
+ const args = e?.args;
99
+ if (args?.some((a) => typeof a === "string" && a.includes("crawlio-browser"))) return true;
100
+ const cmd = e?.command;
101
+ if (cmd?.includes("crawlio-browser")) return true;
102
+ }
103
+ return false;
86
104
  }
87
105
  function buildCloudflareEntry(accountId, apiToken) {
88
106
  return {
@@ -109,7 +127,9 @@ async function confirm(question, defaultYes = true) {
109
127
  function findMcpConfig() {
110
128
  const candidates = [
111
129
  join(process.cwd(), ".mcp.json"),
112
- join(HOME, ".mcp.json")
130
+ join(HOME, ".mcp.json"),
131
+ join(HOME, ".claude", "mcp.json")
132
+ // Claude Code global config
113
133
  ];
114
134
  for (const p of candidates) {
115
135
  if (!existsSync(p)) continue;
@@ -124,6 +144,28 @@ function findMcpConfig() {
124
144
  }
125
145
  return null;
126
146
  }
147
+ function findConflictingConfigs() {
148
+ const locations = [
149
+ join(process.cwd(), ".mcp.json"),
150
+ join(HOME, ".mcp.json"),
151
+ join(HOME, ".claude", "mcp.json"),
152
+ // Claude Code project config (if different from cwd)
153
+ join(process.cwd(), ".claude", "mcp.json")
154
+ ];
155
+ const conflicts = [];
156
+ for (const p of locations) {
157
+ if (!existsSync(p)) continue;
158
+ try {
159
+ const raw = readFileSync(p, "utf-8");
160
+ const parsed = JSON.parse(raw);
161
+ if (parsed?.mcpServers && isAlreadyConfigured(parsed)) {
162
+ conflicts.push(p);
163
+ }
164
+ } catch {
165
+ }
166
+ }
167
+ return conflicts;
168
+ }
127
169
  async function healthCheck() {
128
170
  try {
129
171
  const res = await fetch(HEALTH_URL);
@@ -155,6 +197,64 @@ function resolveNodePath() {
155
197
  }
156
198
  return process.execPath;
157
199
  }
200
+ function createAppWrapper(serverEntryPath) {
201
+ if (platform() !== "darwin") return null;
202
+ const crawlioDir = join(HOME, ".crawlio");
203
+ const appDir = join(crawlioDir, "Crawlio Agent.app");
204
+ const contentsDir = join(appDir, "Contents");
205
+ const macosDir = join(contentsDir, "MacOS");
206
+ const resourcesDir = join(contentsDir, "Resources");
207
+ const wrapperBin = join(macosDir, "crawlio-agent");
208
+ try {
209
+ mkdirSync(macosDir, { recursive: true });
210
+ mkdirSync(resourcesDir, { recursive: true });
211
+ } catch {
212
+ return null;
213
+ }
214
+ const plist = `<?xml version="1.0" encoding="UTF-8"?>
215
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
216
+ <plist version="1.0">
217
+ <dict>
218
+ <key>CFBundleName</key>
219
+ <string>Crawlio Agent</string>
220
+ <key>CFBundleIdentifier</key>
221
+ <string>com.crawlio.agent</string>
222
+ <key>CFBundleExecutable</key>
223
+ <string>crawlio-agent</string>
224
+ <key>CFBundleIconFile</key>
225
+ <string>AppIcon</string>
226
+ <key>CFBundlePackageType</key>
227
+ <string>APPL</string>
228
+ <key>LSBackgroundOnly</key>
229
+ <true/>
230
+ </dict>
231
+ </plist>`;
232
+ try {
233
+ writeFileSync(join(contentsDir, "Info.plist"), plist);
234
+ } catch {
235
+ return null;
236
+ }
237
+ const moduleDir = dirname(fileURLToPath(import.meta.url));
238
+ const iconSrc = resolve(moduleDir, "..", "..", "assets", "AppIcon.icns");
239
+ const iconDest = join(resourcesDir, "AppIcon.icns");
240
+ if (existsSync(iconSrc)) {
241
+ try {
242
+ copyFileSync(iconSrc, iconDest);
243
+ } catch {
244
+ }
245
+ }
246
+ const nodePath = resolveNodePath();
247
+ const script = `#!/bin/bash
248
+ exec "${nodePath}" "${serverEntryPath}" "$@"
249
+ `;
250
+ try {
251
+ writeFileSync(wrapperBin, script);
252
+ chmodSync(wrapperBin, 493);
253
+ } catch {
254
+ return null;
255
+ }
256
+ return wrapperBin;
257
+ }
158
258
  function isPortFree(port) {
159
259
  return new Promise((resolve2) => {
160
260
  const srv = createNetServer();
@@ -172,7 +272,7 @@ function generatePlist(nodePath, serverPath) {
172
272
  <plist version="1.0">
173
273
  <dict>
174
274
  <key>Label</key>
175
- <string>com.crawlio.browser</string>
275
+ <string>com.crawlio.agent</string>
176
276
  <key>ProgramArguments</key>
177
277
  <array>
178
278
  <string>${nodePath}</string>
@@ -209,7 +309,7 @@ async function ensurePortalRunning(dryRun) {
209
309
  console.log(` ${dim("~")} Node path: ${nodePath}`);
210
310
  console.log(` ${dim("~")} Server entry: ${serverPath}`);
211
311
  if (platform() === "darwin") {
212
- const plistPath = join(HOME, "Library/LaunchAgents/com.crawlio.browser.plist");
312
+ const plistPath = join(HOME, "Library/LaunchAgents/com.crawlio.agent.plist");
213
313
  console.log(` ${dim("~")} Would write plist to: ${plistPath}`);
214
314
  console.log(` ${dim("~")} Would run: launchctl load ${plistPath}`);
215
315
  } else {
@@ -219,7 +319,7 @@ async function ensurePortalRunning(dryRun) {
219
319
  }
220
320
  if (platform() === "darwin") {
221
321
  const plistDir = join(HOME, "Library/LaunchAgents");
222
- const plistPath = join(plistDir, "com.crawlio.browser.plist");
322
+ const plistPath = join(plistDir, "com.crawlio.agent.plist");
223
323
  const logDir = join(HOME, "Library/Logs/Crawlio");
224
324
  mkdirSync(logDir, { recursive: true });
225
325
  mkdirSync(plistDir, { recursive: true });
@@ -519,9 +619,27 @@ async function configureMetaMcp(found, options) {
519
619
  console.log("");
520
620
  console.log(` ${cyan("\u25C6")} ${bold("MCP Configuration")} ${dim("(.mcp.json)")}`);
521
621
  if (isAlreadyConfigured(found.config)) {
522
- console.log(` ${green("+")} crawlio-browser already configured \u2014 skipping`);
622
+ console.log(` ${green("+")} crawlio-browser already configured in ${dim(found.path)}`);
523
623
  return;
524
624
  }
625
+ const conflicts = findConflictingConfigs();
626
+ if (conflicts.length > 0) {
627
+ console.log(` ${yellow("!")} crawlio-browser already configured in:`);
628
+ for (const c of conflicts) {
629
+ console.log(` ${dim("\u2192")} ${c}`);
630
+ }
631
+ console.log(` ${yellow("!")} Adding a second entry would cause a port collision (port 9333)`);
632
+ if (!options.yes) {
633
+ const proceed = await confirm("Add anyway? (not recommended)", false);
634
+ if (!proceed) {
635
+ console.log(` ${dim("Skipped \u2014 using existing configuration")}`);
636
+ return;
637
+ }
638
+ } else {
639
+ console.log(` ${dim("Skipped \u2014 existing configuration takes priority")}`);
640
+ return;
641
+ }
642
+ }
525
643
  if (!options.yes) {
526
644
  const proceed = await confirm("Add crawlio-browser to this config?");
527
645
  if (!proceed) {
@@ -711,7 +829,9 @@ export {
711
829
  buildCloudflareEntry,
712
830
  buildPortalEntry,
713
831
  buildStdioEntry,
832
+ createAppWrapper,
714
833
  extractSkillName,
834
+ findConflictingConfigs,
715
835
  findMcpConfig,
716
836
  installBrowserSkill,
717
837
  isAlreadyConfigured,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crawlio-browser",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
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",
@@ -11,6 +11,7 @@
11
11
  "bin/crawlio-browser.js",
12
12
  "dist/mcp-server/",
13
13
  "skills/",
14
+ "assets/",
14
15
  ".claude-plugin/",
15
16
  "README.md"
16
17
  ],