crawlmark-mcp 0.1.2 → 0.1.3
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 +4 -4
- package/dist/setup/apps.js +58 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -309,7 +309,7 @@ Configure your MCP client
|
|
|
309
309
|
**Claude Code** (from npm):
|
|
310
310
|
|
|
311
311
|
```bash
|
|
312
|
-
claude mcp add crawlmark -s user -- npx -y crawlmark-mcp
|
|
312
|
+
claude mcp add crawlmark -s user -- npx -y crawlmark-mcp@latest
|
|
313
313
|
```
|
|
314
314
|
|
|
315
315
|
**Claude Code** (from source):
|
|
@@ -325,18 +325,18 @@ claude mcp add crawlmark -s user -- node --disable-warning=ExperimentalWarning /
|
|
|
325
325
|
"mcpServers": {
|
|
326
326
|
"crawlmark": {
|
|
327
327
|
"command": "npx",
|
|
328
|
-
"args": ["-y", "crawlmark-mcp"]
|
|
328
|
+
"args": ["-y", "crawlmark-mcp@latest"]
|
|
329
329
|
}
|
|
330
330
|
}
|
|
331
331
|
}
|
|
332
332
|
```
|
|
333
333
|
|
|
334
|
-
**Codex** (`~/.codex/config.toml`, or run `codex mcp add crawlmark -- npx -y crawlmark-mcp`):
|
|
334
|
+
**Codex** (`~/.codex/config.toml`, or run `codex mcp add crawlmark -- npx -y crawlmark-mcp@latest`):
|
|
335
335
|
|
|
336
336
|
```toml
|
|
337
337
|
[mcp_servers.crawlmark]
|
|
338
338
|
command = "npx"
|
|
339
|
-
args = ["-y", "crawlmark-mcp"]
|
|
339
|
+
args = ["-y", "crawlmark-mcp@latest"]
|
|
340
340
|
```
|
|
341
341
|
|
|
342
342
|
For a source checkout, use `"command": "node"` and `"args": ["--disable-warning=ExperimentalWarning", "/absolute/path/to/crawlmark-mcp/dist/index.js"]`. Claude Desktop, Cursor and Codex may not load your shell's `PATH`, so if one can't find `node` or `npx`, use the absolute path (`which node`). Credentials come from `.env` in the config home, so no `env` block is needed unless your settings live somewhere other than the default; then add `"env": { "CRAWLMARK_HOME": "/path/to/home" }`.
|
package/dist/setup/apps.js
CHANGED
|
@@ -29,9 +29,33 @@ export function cmdLine(cmd, args) {
|
|
|
29
29
|
export function isNpxCache(projectRoot) {
|
|
30
30
|
return projectRoot.split(/[\\/]/).includes("_npx");
|
|
31
31
|
}
|
|
32
|
+
/** What an npx install registers. `@latest` makes npx check for a newer crawlmark each time an app starts it. */
|
|
33
|
+
export const NPX_SPEC = "crawlmark-mcp@latest";
|
|
34
|
+
/**
|
|
35
|
+
* True when `current` is the entry an earlier crawlmark wrote from an npx install (`npx -y crawlmark-mcp`, no
|
|
36
|
+
* version) and `launch` is the same entry with `@latest`. That's an update of crawlmark's own entry, not a
|
|
37
|
+
* different server, so the wizard offers it with yes as the default.
|
|
38
|
+
*/
|
|
39
|
+
export function isNpxLatestUpgrade(current, launch) {
|
|
40
|
+
if (!current || typeof current.command !== "string")
|
|
41
|
+
return false;
|
|
42
|
+
// `claude mcp get` prints the args as one string; app configs keep an array.
|
|
43
|
+
const args = Array.isArray(current.args) ? current.args : typeof current.args === "string" ? current.args.trim().split(/\s+/) : undefined;
|
|
44
|
+
if (!args)
|
|
45
|
+
return false;
|
|
46
|
+
const npx = /(^|[\\/])npx(\.cmd)?$/i;
|
|
47
|
+
if (!npx.test(current.command) || !npx.test(launch.command))
|
|
48
|
+
return false;
|
|
49
|
+
if (JSON.stringify(args) !== JSON.stringify(["-y", "crawlmark-mcp"]) || JSON.stringify(launch.args) !== JSON.stringify(["-y", NPX_SPEC]))
|
|
50
|
+
return false;
|
|
51
|
+
const env = (e) => JSON.stringify(Object.entries((e && typeof e === "object" ? e : {})).sort());
|
|
52
|
+
return env(current.env) === env(launch.env);
|
|
53
|
+
}
|
|
54
|
+
const NPX_UPGRADE_NOTE = "It runs `npx -y crawlmark-mcp`, which keeps reusing the version npx downloaded first.";
|
|
55
|
+
const NPX_UPGRADE_QUESTION = "Update it to `npx -y crawlmark-mcp@latest`, so it picks up new versions?";
|
|
32
56
|
/**
|
|
33
57
|
* How an app should start the server. CRAWLMARK_HOME is passed when the home isn't
|
|
34
|
-
* the project root. From an npx cache, `npx -y crawlmark-mcp` is registered instead
|
|
58
|
+
* the project root. From an npx cache, `npx -y crawlmark-mcp@latest` is registered instead
|
|
35
59
|
* of the cache path. `nodeCommand` is `node` (Claude Code, which inherits the shell
|
|
36
60
|
* PATH) or an absolute path (Claude Desktop, Cursor and Codex, which may not).
|
|
37
61
|
*/
|
|
@@ -39,7 +63,7 @@ export function serverLaunch(ctx, nodeCommand) {
|
|
|
39
63
|
const env = ctx.paths.homeSource === "project" ? undefined : { CRAWLMARK_HOME: ctx.paths.home };
|
|
40
64
|
if (isNpxCache(ctx.paths.projectRoot)) {
|
|
41
65
|
const npx = nodeCommand === "node" ? "npx" : join(dirname(nodeCommand), process.platform === "win32" ? "npx.cmd" : "npx");
|
|
42
|
-
return { command: npx, args: ["-y",
|
|
66
|
+
return { command: npx, args: ["-y", NPX_SPEC], ...(env ? { env } : {}) };
|
|
43
67
|
}
|
|
44
68
|
return { command: nodeCommand, args: ["--disable-warning=ExperimentalWarning", join(ctx.paths.projectRoot, "dist", "index.js")], ...(env ? { env } : {}) };
|
|
45
69
|
}
|
|
@@ -153,11 +177,15 @@ async function registerClaudeCode(ctx, probe, notes) {
|
|
|
153
177
|
return "manual";
|
|
154
178
|
}
|
|
155
179
|
const scope = current.scope ?? "user";
|
|
156
|
-
|
|
180
|
+
const upgrade = isNpxLatestUpgrade(current, launch);
|
|
181
|
+
if (upgrade)
|
|
182
|
+
ctx.out(`Claude Code has crawlmark registered. ${NPX_UPGRADE_NOTE}`);
|
|
183
|
+
else
|
|
184
|
+
ctx.out("Claude Code already has a crawlmark server, with a different command:");
|
|
157
185
|
ctx.out(` current: ${describeRegistration(current)}`);
|
|
158
186
|
ctx.out(` new: ${describeRegistration({ ...launch, scope: "user" })}`);
|
|
159
|
-
// Default no, so --yes never removes
|
|
160
|
-
if (!(await ctx.prompt.confirm(`Replace it (claude mcp remove ${SERVER_NAME} -s ${scope}, then add)?`,
|
|
187
|
+
// Default no for a different server, so --yes never removes one; yes for crawlmark's own older npx entry.
|
|
188
|
+
if (!(await ctx.prompt.confirm(upgrade ? NPX_UPGRADE_QUESTION : `Replace it (claude mcp remove ${SERVER_NAME} -s ${scope}, then add)?`, upgrade))) {
|
|
161
189
|
notes.push({ kind: "info", text: "Kept the existing Claude Code registration." });
|
|
162
190
|
return "skipped";
|
|
163
191
|
}
|
|
@@ -195,8 +223,15 @@ async function registerJsonApp(ctx, id, notes) {
|
|
|
195
223
|
}
|
|
196
224
|
uiFor(ctx).preview(`${app} config: ${path}`, describeDesktopChange(merge, entry));
|
|
197
225
|
// Replacing a different crawlmark entry defaults to no, so --yes never replaces one.
|
|
198
|
-
const
|
|
199
|
-
if (
|
|
226
|
+
const upgrade = merge.replaced && isNpxLatestUpgrade(merge.previous, entry);
|
|
227
|
+
if (upgrade)
|
|
228
|
+
ctx.out(NPX_UPGRADE_NOTE);
|
|
229
|
+
const question = upgrade
|
|
230
|
+
? `${NPX_UPGRADE_QUESTION} (the current file is kept as .bak)`
|
|
231
|
+
: merge.replaced
|
|
232
|
+
? "Replace the existing crawlmark entry? (the current file is kept as .bak)"
|
|
233
|
+
: "Write this change? (the current file is kept as .bak)";
|
|
234
|
+
if (!(await ctx.prompt.confirm(question, upgrade || !merge.replaced))) {
|
|
200
235
|
notes.push({ kind: "info", text: `Skipped ${app}.` });
|
|
201
236
|
return "skipped";
|
|
202
237
|
}
|
|
@@ -287,10 +322,14 @@ async function registerCodexCli(ctx, probe, notes) {
|
|
|
287
322
|
notes.push({ kind: "warn", text: `To replace it yourself: codex mcp remove ${SERVER_NAME}, then ${display}` });
|
|
288
323
|
return "manual";
|
|
289
324
|
}
|
|
290
|
-
|
|
325
|
+
const upgrade = isNpxLatestUpgrade(state.entry, launch);
|
|
326
|
+
if (upgrade)
|
|
327
|
+
ctx.out(`Codex has crawlmark registered. ${NPX_UPGRADE_NOTE}`);
|
|
328
|
+
else
|
|
329
|
+
ctx.out("Codex already has a crawlmark server, with a different command:");
|
|
291
330
|
ctx.out(` current: ${describeRegistration(state.entry)}`);
|
|
292
331
|
ctx.out(` new: ${describeRegistration(want)}`);
|
|
293
|
-
if (!(await ctx.prompt.confirm(`Replace it (codex mcp remove ${SERVER_NAME}, then add)?`,
|
|
332
|
+
if (!(await ctx.prompt.confirm(upgrade ? NPX_UPGRADE_QUESTION : `Replace it (codex mcp remove ${SERVER_NAME}, then add)?`, upgrade))) {
|
|
294
333
|
notes.push({ kind: "info", text: "Kept the existing Codex registration." });
|
|
295
334
|
return "skipped";
|
|
296
335
|
}
|
|
@@ -330,8 +369,15 @@ async function registerCodexToml(ctx, notes) {
|
|
|
330
369
|
return "already";
|
|
331
370
|
}
|
|
332
371
|
uiFor(ctx).preview(`Codex config: ${path}`, describeCodexChange(plan, entry));
|
|
333
|
-
const
|
|
334
|
-
if (
|
|
372
|
+
const upgrade = plan.replaced && isNpxLatestUpgrade(plan.previous, serverLaunch(ctx, ctx.node.execPath));
|
|
373
|
+
if (upgrade)
|
|
374
|
+
ctx.out(NPX_UPGRADE_NOTE);
|
|
375
|
+
const question = upgrade
|
|
376
|
+
? `${NPX_UPGRADE_QUESTION} (the current file is kept as .bak)`
|
|
377
|
+
: plan.replaced
|
|
378
|
+
? "Replace the existing crawlmark entry? (the current file is kept as .bak)"
|
|
379
|
+
: "Write this change? (the current file is kept as .bak)";
|
|
380
|
+
if (!(await ctx.prompt.confirm(question, upgrade || !plan.replaced))) {
|
|
335
381
|
notes.push({ kind: "info", text: "Skipped Codex." });
|
|
336
382
|
return "skipped";
|
|
337
383
|
}
|
|
@@ -370,7 +416,7 @@ export async function registerApps(ctx) {
|
|
|
370
416
|
const ui = uiFor(ctx);
|
|
371
417
|
const notes = [];
|
|
372
418
|
if (isNpxCache(ctx.paths.projectRoot)) {
|
|
373
|
-
ctx.out("crawlmark is running from a temporary npx cache, so Claude will start it with `npx -y crawlmark-mcp` instead of this path.");
|
|
419
|
+
ctx.out("crawlmark is running from a temporary npx cache, so Claude will start it with `npx -y crawlmark-mcp@latest` instead of this path.");
|
|
374
420
|
}
|
|
375
421
|
const probes = await ui.spin("Looking for AI apps...", () => detectApps(ctx), { plain: false });
|
|
376
422
|
const defaults = probes.filter((p) => p.detected).map((p) => p.id);
|
package/package.json
CHANGED