crawlio-browser 1.4.4 → 1.4.6
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/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-WJU4IGLN.js";
|
|
11
11
|
|
|
12
12
|
// src/mcp-server/index.ts
|
|
13
13
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
@@ -1266,7 +1266,7 @@ var TOOL_TIMEOUTS = {
|
|
|
1266
1266
|
get_frame_tree: 1e4,
|
|
1267
1267
|
switch_to_frame: 5e3,
|
|
1268
1268
|
switch_to_main_frame: 5e3,
|
|
1269
|
-
create_tab:
|
|
1269
|
+
create_tab: 2e4,
|
|
1270
1270
|
close_tab: 5e3,
|
|
1271
1271
|
switch_tab: 5e3,
|
|
1272
1272
|
set_cookie: 5e3,
|
|
@@ -2156,25 +2156,28 @@ function createTools(bridge2, crawlio2) {
|
|
|
2156
2156
|
// --- Tab management tools (AC-3) ---
|
|
2157
2157
|
{
|
|
2158
2158
|
name: "create_tab",
|
|
2159
|
-
description: "Create a new browser tab with the given URL.
|
|
2159
|
+
description: "Create a new browser tab with the given URL. Pass connect:true to auto-attach CDP and start capturing \u2014 the tab is immediately ready for interaction (screenshot, evaluate, navigate, etc).",
|
|
2160
2160
|
inputSchema: {
|
|
2161
2161
|
type: "object",
|
|
2162
2162
|
properties: {
|
|
2163
2163
|
url: { type: "string", description: "URL to open in the new tab" },
|
|
2164
|
-
active: { type: "boolean", description: "Whether to make the new tab active/focused (default: true)" }
|
|
2164
|
+
active: { type: "boolean", description: "Whether to make the new tab active/focused (default: true)" },
|
|
2165
|
+
connect: { type: "boolean", description: "Auto-connect CDP debugger after creation \u2014 tab is ready for interaction immediately (default: false)" }
|
|
2165
2166
|
},
|
|
2166
2167
|
required: ["url"]
|
|
2167
2168
|
},
|
|
2168
2169
|
handler: async (args) => {
|
|
2169
2170
|
const schema = z.object({
|
|
2170
2171
|
url: urlSchema,
|
|
2171
|
-
active: z.boolean().default(true)
|
|
2172
|
+
active: z.boolean().default(true),
|
|
2173
|
+
connect: z.boolean().default(false)
|
|
2172
2174
|
});
|
|
2173
2175
|
const parsed = schema.parse(args);
|
|
2174
2176
|
const data = await bridge2.send({
|
|
2175
2177
|
type: "create_tab",
|
|
2176
2178
|
url: parsed.url,
|
|
2177
|
-
active: parsed.active
|
|
2179
|
+
active: parsed.active,
|
|
2180
|
+
connect: parsed.connect
|
|
2178
2181
|
}, TOOL_TIMEOUTS.create_tab);
|
|
2179
2182
|
return toolSuccess(data);
|
|
2180
2183
|
}
|
|
@@ -4027,7 +4030,7 @@ function createCodeModeTools(bridge2, crawlio2) {
|
|
|
4027
4030
|
process.title = "Crawlio Agent";
|
|
4028
4031
|
var initMode = process.argv.includes("init") || process.argv.includes("--setup") || process.argv.includes("setup");
|
|
4029
4032
|
if (initMode) {
|
|
4030
|
-
const { runInit } = await import("./init-
|
|
4033
|
+
const { runInit } = await import("./init-E233DCMN.js");
|
|
4031
4034
|
await runInit(process.argv.slice(2));
|
|
4032
4035
|
process.exit(0);
|
|
4033
4036
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PKG_VERSION
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-WJU4IGLN.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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
|
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") {
|
|
@@ -91,7 +290,7 @@ function buildStdioEntry(options) {
|
|
|
91
290
|
if (options?.full) args2.push("--full");
|
|
92
291
|
return { command: nodePath, args: args2 };
|
|
93
292
|
}
|
|
94
|
-
const args = ["-y",
|
|
293
|
+
const args = ["-y", "crawlio-browser"];
|
|
95
294
|
if (options?.full) args.push("--full");
|
|
96
295
|
return { command: "npx", args };
|
|
97
296
|
}
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
3
|
+
"version": "1.4.6",
|
|
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",
|