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
|
package/dist/mcp-server/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
WS_PORT,
|
|
8
8
|
WS_RECONNECT_GRACE,
|
|
9
9
|
WS_STALE_THRESHOLD
|
|
10
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
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(
|
|
67
|
+
args.push(`${pkg} --full`);
|
|
67
68
|
} else {
|
|
68
|
-
args.push(
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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
|
],
|