donsetch 0.5.0-beta.1
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 +84 -0
- package/bin/donsetch.js +69 -0
- package/install.js +152 -0
- package/package.json +42 -0
package/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# DonSeTch
|
|
2
|
+
|
|
3
|
+
> Web fetch, search and crawl for AI agents. Zero API keys.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/dondai44423/donsetch/actions/workflows/ci.yml)
|
|
6
|
+
|
|
7
|
+
DonSeTch is an MCP server that gives AI agents web research capabilities:
|
|
8
|
+
fetch any URL, search across 10+ engines, and crawl multi-page docs —
|
|
9
|
+
all with Chrome-true TLS fingerprinting and zero API keys.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g donsetch
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The postinstall script downloads the prebuilt binary for your platform
|
|
18
|
+
from [GitHub Releases](https://github.com/dondai44423/donsetch/releases).
|
|
19
|
+
|
|
20
|
+
| Platform | Binary |
|
|
21
|
+
|---|---|
|
|
22
|
+
| Linux x86_64 | `donsetch-linux-x64.tar.gz` |
|
|
23
|
+
| macOS arm64 | `donsetch-darwin-arm64.tar.gz` |
|
|
24
|
+
| Windows x86_64 | `donsetch-win32-x64.tar.gz` |
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Fetch a URL (Chrome-true TLS, anti-bot bypass)
|
|
30
|
+
donsetch fetch https://example.com
|
|
31
|
+
|
|
32
|
+
# Search (10+ keyless backends, semantic reranking)
|
|
33
|
+
donsetch search "rust async patterns"
|
|
34
|
+
|
|
35
|
+
# Crawl (sitemap-aware, focus-filtered)
|
|
36
|
+
donsetch crawl https://docs.example.com --focus "api reference"
|
|
37
|
+
|
|
38
|
+
# Start MCP server (for Claude Code, Cursor, Pi, etc.)
|
|
39
|
+
donsetch mcp
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## MCP Configuration
|
|
43
|
+
|
|
44
|
+
Add to your MCP client config:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"mcpServers": {
|
|
49
|
+
"donsetch": {
|
|
50
|
+
"command": "donsetch",
|
|
51
|
+
"args": ["mcp"]
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Or use `npx` without global install:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"mcpServers": {
|
|
62
|
+
"donsetch": {
|
|
63
|
+
"command": "npx",
|
|
64
|
+
"args": ["donsetch", "mcp"]
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Three tools: `web_fetch`, `web_search`, `web_crawl`.
|
|
71
|
+
|
|
72
|
+
## Build from source
|
|
73
|
+
|
|
74
|
+
Requirements: Rust 1.75+, Go 1.22+, NASM, LLVM/Clang (for BoringSSL bindgen).
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
git clone https://github.com/dondai44423/donsetch
|
|
78
|
+
cd donsetch
|
|
79
|
+
cargo build --release
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## License
|
|
83
|
+
|
|
84
|
+
AGPL-3.0 — Copyright (c) 2026 Bishesh Bhandari
|
package/bin/donsetch.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// donsetch CLI wrapper: spawn the native binary with forwarded stdio.
|
|
5
|
+
//
|
|
6
|
+
// For MCP server usage (`donsetch mcp`), the MCP client spawns this
|
|
7
|
+
// wrapper as a subprocess and communicates via stdin/stdout (JSON-RPC).
|
|
8
|
+
// stdio: 'inherit' pipes the native binary's stdio directly to the
|
|
9
|
+
// parent process, so the MCP protocol passes through unmodified.
|
|
10
|
+
//
|
|
11
|
+
// Signal forwarding: when the MCP client sends SIGTERM/SIGINT to this
|
|
12
|
+
// wrapper, we forward it to the native binary so it can clean up
|
|
13
|
+
// (close connections, save ghost state, etc.) before exiting.
|
|
14
|
+
|
|
15
|
+
const { spawn } = require('child_process');
|
|
16
|
+
const { existsSync } = require('fs');
|
|
17
|
+
const { join } = require('path');
|
|
18
|
+
|
|
19
|
+
// ── resolve binary path ─────────────────────────────────────────
|
|
20
|
+
const binaryName = process.platform === 'win32' ? 'donsetch.exe' : 'donsetch';
|
|
21
|
+
const binDir = join(__dirname, '..', 'binaries');
|
|
22
|
+
const binaryPath = join(binDir, binaryName);
|
|
23
|
+
|
|
24
|
+
if (!existsSync(binaryPath)) {
|
|
25
|
+
process.stderr.write('donsetch: binary not found. Run `npm rebuild donsetch` to reinstall.\n');
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ── spawn native binary ─────────────────────────────────────────
|
|
30
|
+
const child = spawn(binaryPath, process.argv.slice(2), {
|
|
31
|
+
stdio: 'inherit',
|
|
32
|
+
cwd: process.cwd(),
|
|
33
|
+
env: process.env,
|
|
34
|
+
windowsHide: true,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// ── forward signals to child ────────────────────────────────────
|
|
38
|
+
// When the parent receives SIGTERM/SIGINT (e.g. MCP client
|
|
39
|
+
// disconnecting), forward to the child so it can clean up.
|
|
40
|
+
let killed = false;
|
|
41
|
+
|
|
42
|
+
function forwardSignal(sig) {
|
|
43
|
+
if (!killed) {
|
|
44
|
+
killed = true;
|
|
45
|
+
try { child.kill(sig); } catch (_) {}
|
|
46
|
+
// Force exit after 5s if child doesn't respond
|
|
47
|
+
setTimeout(() => process.exit(1), 5000).unref();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
process.on('SIGTERM', () => forwardSignal('SIGTERM'));
|
|
52
|
+
process.on('SIGINT', () => forwardSignal('SIGINT'));
|
|
53
|
+
process.on('SIGHUP', () => forwardSignal('SIGHUP'));
|
|
54
|
+
|
|
55
|
+
// ── exit with child's code ──────────────────────────────────────
|
|
56
|
+
child.on('exit', (code, signal) => {
|
|
57
|
+
if (signal) {
|
|
58
|
+
// Re-raise the signal so the parent's exit reflects it
|
|
59
|
+
try { process.kill(process.pid, signal); } catch (_) {}
|
|
60
|
+
process.exit(128 + 15); // 128 + SIGTERM
|
|
61
|
+
} else {
|
|
62
|
+
process.exit(code || 0);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
child.on('error', (err) => {
|
|
67
|
+
process.stderr.write(`donsetch: failed to spawn binary: ${err.message}\n`);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
});
|
package/install.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// donsetch postinstall: download the prebuilt binary for this platform
|
|
5
|
+
// from GitHub Releases, verify SHA256, and extract to ./binaries/.
|
|
6
|
+
//
|
|
7
|
+
// The binary is NOT bundled in the npm package — it's fetched at
|
|
8
|
+
// install time from the GitHub release matching this package version.
|
|
9
|
+
// This keeps the npm registry clean (no 35 MB binary tarballs) and
|
|
10
|
+
// uses the same release artifacts that manual users download.
|
|
11
|
+
//
|
|
12
|
+
// Supported platforms:
|
|
13
|
+
// linux-x64 Linux x86_64
|
|
14
|
+
// darwin-arm64 macOS Apple Silicon
|
|
15
|
+
// win32-x64 Windows x86_64
|
|
16
|
+
|
|
17
|
+
const https = require('https');
|
|
18
|
+
const crypto = require('crypto');
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const path = require('path');
|
|
21
|
+
const { execSync } = require('child_process');
|
|
22
|
+
|
|
23
|
+
const REPO = 'dondai44423/donsetch';
|
|
24
|
+
const VERSION = require('./package.json').version;
|
|
25
|
+
const TAG = `v${VERSION}`;
|
|
26
|
+
|
|
27
|
+
// ── platform mapping ────────────────────────────────────────────
|
|
28
|
+
const PLATFORMS = {
|
|
29
|
+
'linux-x64': { asset: 'donsetch-linux-x64.tar.gz', binary: 'donsetch' },
|
|
30
|
+
'darwin-arm64': { asset: 'donsetch-darwin-arm64.tar.gz', binary: 'donsetch' },
|
|
31
|
+
'win32-x64': { asset: 'donsetch-win32-x64.tar.gz', binary: 'donsetch.exe' },
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const platKey = `${process.platform}-${process.arch}`;
|
|
35
|
+
const plat = PLATFORMS[platKey];
|
|
36
|
+
|
|
37
|
+
if (!plat) {
|
|
38
|
+
console.error(`donsetch: unsupported platform ${platKey}`);
|
|
39
|
+
console.error('');
|
|
40
|
+
console.error('Supported platforms:');
|
|
41
|
+
console.error(' linux-x64 Linux x86_64');
|
|
42
|
+
console.error(' darwin-arm64 macOS Apple Silicon');
|
|
43
|
+
console.error(' win32-x64 Windows x86_64');
|
|
44
|
+
console.error('');
|
|
45
|
+
console.error('Build from source: https://github.com/' + REPO);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const binDir = path.join(__dirname, 'binaries');
|
|
50
|
+
const binaryPath = path.join(binDir, plat.binary);
|
|
51
|
+
|
|
52
|
+
// Skip if already installed (npm cache reuse, reinstall, etc.)
|
|
53
|
+
if (fs.existsSync(binaryPath)) {
|
|
54
|
+
console.log(`donsetch: binary already present (${plat.binary})`);
|
|
55
|
+
process.exit(0);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
fs.mkdirSync(binDir, { recursive: true });
|
|
59
|
+
|
|
60
|
+
const baseUrl = `https://github.com/${REPO}/releases/download/${TAG}`;
|
|
61
|
+
const assetUrl = `${baseUrl}/${plat.asset}`;
|
|
62
|
+
const checksumUrl = `${baseUrl}/${plat.asset}.sha256`;
|
|
63
|
+
|
|
64
|
+
// ── download with redirect following ────────────────────────────
|
|
65
|
+
function download(url, dest) {
|
|
66
|
+
return new Promise((resolve, reject) => {
|
|
67
|
+
function get(u) {
|
|
68
|
+
const opts = { headers: { 'Accept': 'application/octet-stream', 'User-Agent': 'donsetch-npm-installer' } };
|
|
69
|
+
https.get(u, opts, (res) => {
|
|
70
|
+
if ([301, 302, 303, 307, 308].includes(res.statusCode)) {
|
|
71
|
+
res.resume();
|
|
72
|
+
get(res.headers.location);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (res.statusCode !== 200) {
|
|
76
|
+
res.resume();
|
|
77
|
+
reject(new Error(`HTTP ${res.statusCode} for ${u}`));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const file = fs.createWriteStream(dest);
|
|
81
|
+
res.pipe(file);
|
|
82
|
+
file.on('finish', () => { file.close(); resolve(); });
|
|
83
|
+
file.on('error', (err) => {
|
|
84
|
+
try { fs.unlinkSync(dest); } catch (_) {}
|
|
85
|
+
reject(err);
|
|
86
|
+
});
|
|
87
|
+
}).on('error', reject);
|
|
88
|
+
}
|
|
89
|
+
get(url);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ── main ────────────────────────────────────────────────────────
|
|
94
|
+
async function main() {
|
|
95
|
+
const tarball = path.join(binDir, plat.asset);
|
|
96
|
+
const checksumFile = path.join(binDir, 'checksum.sha256');
|
|
97
|
+
|
|
98
|
+
// 1. Download the binary tarball
|
|
99
|
+
console.log(`donsetch: downloading ${plat.asset} from ${TAG}...`);
|
|
100
|
+
await download(assetUrl, tarball);
|
|
101
|
+
|
|
102
|
+
// 2. Download the SHA256 checksum
|
|
103
|
+
console.log('donsetch: verifying checksum...');
|
|
104
|
+
await download(checksumUrl, checksumFile);
|
|
105
|
+
|
|
106
|
+
// 3. Verify SHA256
|
|
107
|
+
const expectedHash = fs.readFileSync(checksumFile, 'utf8').trim().split(/\s+/)[0];
|
|
108
|
+
const actualHash = crypto.createHash('sha256').update(fs.readFileSync(tarball)).digest('hex');
|
|
109
|
+
|
|
110
|
+
if (actualHash !== expectedHash) {
|
|
111
|
+
try { fs.unlinkSync(tarball); } catch (_) {}
|
|
112
|
+
try { fs.unlinkSync(checksumFile); } catch (_) {}
|
|
113
|
+
console.error(`donsetch: SHA256 mismatch!`);
|
|
114
|
+
console.error(` expected: ${expectedHash}`);
|
|
115
|
+
console.error(` actual: ${actualHash}`);
|
|
116
|
+
console.error('The download may have been corrupted or tampered with.');
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 4. Extract (tar is built into Linux, macOS, and Windows 10+)
|
|
121
|
+
console.log('donsetch: extracting...');
|
|
122
|
+
execSync(`tar xzf "${tarball}" -C "${binDir}"`, { stdio: 'inherit' });
|
|
123
|
+
|
|
124
|
+
// 5. Cleanup
|
|
125
|
+
try { fs.unlinkSync(tarball); } catch (_) {}
|
|
126
|
+
try { fs.unlinkSync(checksumFile); } catch (_) {}
|
|
127
|
+
|
|
128
|
+
// 6. Make executable (Unix only)
|
|
129
|
+
if (process.platform !== 'win32') {
|
|
130
|
+
fs.chmodSync(binaryPath, 0o755);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// 7. Verify the binary exists after extraction
|
|
134
|
+
if (!fs.existsSync(binaryPath)) {
|
|
135
|
+
console.error(`donsetch: expected ${plat.binary} not found after extraction`);
|
|
136
|
+
console.error(` looked at: ${binaryPath}`);
|
|
137
|
+
console.error(' contents of binaries/:', fs.readdirSync(binDir).join(', '));
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
console.log(`donsetch: installed ${plat.binary} to ${binaryPath}`);
|
|
142
|
+
console.log(`donsetch: run \`donsetch\` to see available commands.`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
main().catch((err) => {
|
|
146
|
+
console.error(`donsetch: install failed: ${err.message}`);
|
|
147
|
+
console.error('');
|
|
148
|
+
console.error('You can build from source:');
|
|
149
|
+
console.error(' git clone https://github.com/' + REPO);
|
|
150
|
+
console.error(' cd donsetch && cargo build --release');
|
|
151
|
+
process.exit(1);
|
|
152
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "donsetch",
|
|
3
|
+
"version": "0.5.0-beta.1",
|
|
4
|
+
"description": "Web fetch, search and crawl for AI agents. Zero API keys. Chrome-true TLS.",
|
|
5
|
+
"license": "AGPL-3.0-only",
|
|
6
|
+
"author": "Bishesh Bhandari",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/dondai44423/donsetch"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/dondai44423/donsetch#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/dondai44423/donsetch/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"mcp",
|
|
17
|
+
"web-fetch",
|
|
18
|
+
"search",
|
|
19
|
+
"crawl",
|
|
20
|
+
"ai-agent",
|
|
21
|
+
"scraper",
|
|
22
|
+
"tls",
|
|
23
|
+
"chrome",
|
|
24
|
+
"anti-bot",
|
|
25
|
+
"pdf",
|
|
26
|
+
"extraction"
|
|
27
|
+
],
|
|
28
|
+
"bin": {
|
|
29
|
+
"donsetch": "bin/donsetch.js"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"postinstall": "node install.js"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"install.js",
|
|
36
|
+
"bin/donsetch.js",
|
|
37
|
+
"README.md"
|
|
38
|
+
],
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=14"
|
|
41
|
+
}
|
|
42
|
+
}
|