crw-mcp 0.5.0 → 0.15.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.
package/bin/crw-mcp.js CHANGED
@@ -7,41 +7,133 @@ if (process.argv[2] === "init") {
7
7
  }
8
8
 
9
9
  const { spawnSync } = require("child_process");
10
+ const fs = require("fs");
10
11
  const path = require("path");
12
+ const os = require("os");
13
+ const https = require("https");
11
14
 
15
+ const VERSION = require("../package.json").version;
16
+ const REPO = "us/crw";
17
+
18
+ // Each platform has a prebuilt npm package (fast path, installed via
19
+ // optionalDependencies) AND a matching GitHub release asset (fallback path,
20
+ // downloaded on first run). The fallback makes the launcher robust to a
21
+ // missing/unpublishable platform package (e.g. npm security-held names) — no
22
+ // single package can freeze the channel, mirroring the PyPI launcher.
12
23
  const PLATFORMS = {
13
- "darwin-x64": "crw-mcp-darwin-x64",
14
- "darwin-arm64": "crw-mcp-darwin-arm64",
15
- "linux-x64": "crw-mcp-linux-x64",
16
- "linux-arm64": "crw-mcp-linux-arm64",
17
- "win32-x64": "crw-mcp-win32-x64",
18
- "win32-arm64": "crw-mcp-win32-arm64",
24
+ "darwin-x64": { pkg: "crw-mcp-darwin-x64", asset: "crw-mcp-darwin-x64.tar.gz" },
25
+ "darwin-arm64": { pkg: "crw-mcp-darwin-arm64", asset: "crw-mcp-darwin-arm64.tar.gz" },
26
+ "linux-x64": { pkg: "crw-mcp-linux-x64", asset: "crw-mcp-linux-x64.tar.gz" },
27
+ "linux-arm64": { pkg: "crw-mcp-linux-arm64", asset: "crw-mcp-linux-arm64.tar.gz" },
28
+ "win32-x64": { pkg: "crw-mcp-win32-x64", asset: "crw-mcp-win32-x64.zip" },
29
+ "win32-arm64": { pkg: "crw-mcp-win32-arm64", asset: "crw-mcp-win32-arm64.zip" },
19
30
  };
20
31
 
21
32
  const key = `${process.platform}-${process.arch}`;
22
- const pkg = PLATFORMS[key];
33
+ const plat = PLATFORMS[key];
23
34
 
24
- if (!pkg) {
35
+ if (!plat) {
25
36
  console.error(
26
37
  `crw-mcp: unsupported platform ${key}. Supported: ${Object.keys(PLATFORMS).join(", ")}`
27
38
  );
28
39
  process.exit(1);
29
40
  }
30
41
 
31
- const ext = process.platform === "win32" ? ".exe" : "";
42
+ const binName = `crw-mcp${process.platform === "win32" ? ".exe" : ""}`;
32
43
 
33
- let bin;
34
- try {
35
- bin = path.join(
36
- path.dirname(require.resolve(`${pkg}/package.json`)),
37
- `crw-mcp${ext}`
38
- );
39
- } catch {
40
- console.error(
41
- `crw-mcp: platform package "${pkg}" not found. Try reinstalling:\n npm install crw-mcp`
42
- );
43
- process.exit(1);
44
+ // 1. Explicit override.
45
+ function fromEnv() {
46
+ const p = process.env.CRW_MCP_BINARY || process.env.CRW_BINARY;
47
+ return p && fs.existsSync(p) ? p : null;
48
+ }
49
+
50
+ // 2. Prebuilt platform package (fast path — no download).
51
+ function fromPackage() {
52
+ try {
53
+ const bin = path.join(
54
+ path.dirname(require.resolve(`${plat.pkg}/package.json`)),
55
+ binName
56
+ );
57
+ return fs.existsSync(bin) ? bin : null;
58
+ } catch {
59
+ return null;
60
+ }
61
+ }
62
+
63
+ function cacheDir() {
64
+ const base =
65
+ process.platform === "win32"
66
+ ? process.env.LOCALAPPDATA || path.join(os.homedir(), "AppData", "Local")
67
+ : process.env.XDG_CACHE_HOME || path.join(os.homedir(), ".cache");
68
+ return path.join(base, "crw-mcp", `v${VERSION}`);
69
+ }
70
+
71
+ function httpsGet(url, dest, redirects = 0) {
72
+ return new Promise((resolve, reject) => {
73
+ https
74
+ .get(url, { headers: { "User-Agent": `crw-mcp/${VERSION}` } }, (res) => {
75
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
76
+ res.resume();
77
+ if (redirects > 5) return reject(new Error("too many redirects"));
78
+ return resolve(httpsGet(res.headers.location, dest, redirects + 1));
79
+ }
80
+ if (res.statusCode !== 200) {
81
+ res.resume();
82
+ return reject(new Error(`HTTP ${res.statusCode} for ${url}`));
83
+ }
84
+ const file = fs.createWriteStream(dest);
85
+ res.pipe(file);
86
+ file.on("finish", () => file.close(() => resolve()));
87
+ file.on("error", reject);
88
+ })
89
+ .on("error", reject);
90
+ });
91
+ }
92
+
93
+ // 3. Download the matching release asset and extract it (cached per version).
94
+ async function fromDownload() {
95
+ const dir = cacheDir();
96
+ const bin = path.join(dir, binName);
97
+ if (fs.existsSync(bin)) return bin;
98
+
99
+ fs.mkdirSync(dir, { recursive: true });
100
+ const archive = path.join(dir, plat.asset);
101
+ const url = `https://github.com/${REPO}/releases/download/v${VERSION}/${plat.asset}`;
102
+
103
+ // stderr only: stdout is the MCP (JSON-RPC) channel.
104
+ console.error(`crw-mcp: downloading ${plat.asset} (v${VERSION})...`);
105
+ await httpsGet(url, archive);
106
+
107
+ const tarArgs = plat.asset.endsWith(".zip")
108
+ ? ["-xf", archive, "-C", dir]
109
+ : ["-xzf", archive, "-C", dir];
110
+ const x = spawnSync("tar", tarArgs, { stdio: "inherit" });
111
+ if (x.status !== 0) {
112
+ throw new Error(`failed to extract ${plat.asset} (tar exit ${x.status})`);
113
+ }
114
+ fs.rmSync(archive, { force: true });
115
+
116
+ if (!fs.existsSync(bin)) {
117
+ throw new Error(`binary ${binName} not found in ${plat.asset}`);
118
+ }
119
+ if (process.platform !== "win32") fs.chmodSync(bin, 0o755);
120
+ return bin;
121
+ }
122
+
123
+ async function resolveBinary() {
124
+ return fromEnv() || fromPackage() || (await fromDownload());
44
125
  }
45
126
 
46
- const result = spawnSync(bin, process.argv.slice(2), { stdio: "inherit" });
47
- process.exit(result.status ?? 1);
127
+ resolveBinary()
128
+ .then((bin) => {
129
+ const result = spawnSync(bin, process.argv.slice(2), { stdio: "inherit" });
130
+ process.exit(result.status ?? 1);
131
+ })
132
+ .catch((err) => {
133
+ console.error(
134
+ `crw-mcp: could not locate or download the ${key} binary.\n ${err.message}\n` +
135
+ ` Set CRW_MCP_BINARY=/path/to/crw-mcp to use a local build, or install\n` +
136
+ ` from https://github.com/${REPO}/releases.`
137
+ );
138
+ process.exit(1);
139
+ });
package/bin/init.js CHANGED
@@ -123,11 +123,13 @@ Without flags, auto-detects installed agents and installs to all of them.
123
123
  console.log(` export CRW_API_KEY=${apiKey}`);
124
124
  } else {
125
125
  console.log("\nCloud mode (fastcrw.com):");
126
+ console.log(" 500 free one-time credits, managed infra — https://fastcrw.com");
126
127
  console.log(" export CRW_API_KEY=fc-your-key");
127
- console.log(" export CRW_API_URL=https://fastcrw.com/api");
128
+ console.log(" export CRW_API_URL=https://api.fastcrw.com");
129
+ console.log(" Terms of Service: https://fastcrw.com/terms");
128
130
  }
129
131
 
130
- console.log("\nLocal mode (no key needed):");
132
+ console.log("\nLocal mode (free, same binary, fully capable):");
131
133
  console.log(" npx crw-mcp");
132
134
  console.log("\nDocs: https://fastcrw.com/docs");
133
135
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crw-mcp",
3
- "version": "0.5.0",
3
+ "version": "0.15.2",
4
4
  "description": "MCP server for CRW web scraper — scrape, crawl, and map tools for AI agents",
5
5
  "license": "AGPL-3.0",
6
6
  "homepage": "https://github.com/us/crw",
@@ -21,17 +21,18 @@
21
21
  "bin": {
22
22
  "crw-mcp": "bin/crw-mcp.js"
23
23
  },
24
+ "engines": {
25
+ "node": ">=18"
26
+ },
24
27
  "files": [
25
28
  "bin/crw-mcp.js",
26
29
  "bin/init.js",
27
30
  "skills/SKILL.md"
28
31
  ],
29
32
  "optionalDependencies": {
30
- "crw-mcp-darwin-x64": "0.3.5",
31
- "crw-mcp-darwin-arm64": "0.3.5",
32
- "crw-mcp-linux-x64": "0.3.5",
33
- "crw-mcp-linux-arm64": "0.3.5",
34
- "crw-mcp-win32-x64": "0.3.5",
35
- "crw-mcp-win32-arm64": "0.3.5"
33
+ "crw-mcp-darwin-x64": "0.15.2",
34
+ "crw-mcp-darwin-arm64": "0.15.2",
35
+ "crw-mcp-linux-x64": "0.15.2",
36
+ "crw-mcp-linux-arm64": "0.15.2"
36
37
  }
37
38
  }