Skip to content

Commit 9b805a4

Browse files
committed
feat: Claude Code plugin packaging (openclaw format)
- openclaw.plugin.json: plugin manifest - .mcp.json: MCP server config using start.mjs - start.mjs: finds/builds rawdoc binary, spawns --serve - scripts/postinstall.mjs: auto-builds binary on install - package.json: npm package metadata for plugin registry Install: /install-plugin RandomCodeSpace/rawdoc
1 parent 708de8a commit 9b805a4

6 files changed

Lines changed: 145 additions & 2 deletions

File tree

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ dist/
88
.vscode/
99
.idea/
1010

11-
# MCP configs
12-
.mcp.json
11+
# IDE
12+
node_modules/
1313

1414
# OS
1515
.DS_Store

.mcp.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"mcpServers": {
3+
"rawdoc": {
4+
"command": "node",
5+
"args": [
6+
"${CLAUDE_PLUGIN_ROOT}/start.mjs"
7+
]
8+
}
9+
}
10+
}

openclaw.plugin.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"id": "rawdoc",
3+
"name": "rawdoc",
4+
"kind": "tool",
5+
"description": "Fetch web pages as clean markdown for AI agents. Strips noise, extracts content, 95%+ token reduction.",
6+
"version": "0.2.0",
7+
"sandbox": {
8+
"mode": "permissive",
9+
"filesystem_access": "none",
10+
"system_access": "none"
11+
},
12+
"configSchema": {
13+
"type": "object",
14+
"properties": {
15+
"enabled": {
16+
"type": "boolean",
17+
"default": true,
18+
"description": "Enable or disable the rawdoc plugin."
19+
}
20+
},
21+
"additionalProperties": false
22+
}
23+
}

package.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "rawdoc",
3+
"version": "0.2.0",
4+
"description": "Fetch web pages as clean markdown for AI agents",
5+
"main": "./start.mjs",
6+
"type": "module",
7+
"scripts": {
8+
"build": "go build -o rawdoc .",
9+
"test": "go test -count=1 ./...",
10+
"postinstall": "node scripts/postinstall.mjs"
11+
},
12+
"repository": {
13+
"type": "git",
14+
"url": "https://github.com/RandomCodeSpace/rawdoc.git"
15+
},
16+
"keywords": ["mcp", "claude-code", "markdown", "web-scraper", "documentation"],
17+
"license": "MIT"
18+
}

scripts/postinstall.mjs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env node
2+
// postinstall: build rawdoc binary if Go is available, otherwise check PATH
3+
import { execFileSync } from "node:child_process";
4+
import { existsSync } from "node:fs";
5+
import { dirname, resolve } from "node:path";
6+
import { fileURLToPath } from "node:url";
7+
import { platform } from "node:os";
8+
9+
const __dirname = dirname(fileURLToPath(import.meta.url));
10+
const root = resolve(__dirname, "..");
11+
const ext = platform() === "win32" ? ".exe" : "";
12+
const binary = resolve(root, `rawdoc${ext}`);
13+
14+
if (existsSync(binary)) {
15+
console.log(`[rawdoc] Binary already exists: ${binary}`);
16+
process.exit(0);
17+
}
18+
19+
// Try building from source
20+
try {
21+
console.log("[rawdoc] Building from source...");
22+
execFileSync("go", ["build", "-ldflags=-s -w", "-o", binary, "."], {
23+
cwd: root,
24+
stdio: "inherit",
25+
});
26+
console.log(`[rawdoc] Built: ${binary}`);
27+
process.exit(0);
28+
} catch {
29+
// Go not available — check if rawdoc is already in PATH
30+
try {
31+
const which = platform() === "win32" ? "where" : "which";
32+
const found = execFileSync(which, [`rawdoc${ext}`], { encoding: "utf8" }).trim();
33+
console.log(`[rawdoc] Found in PATH: ${found}`);
34+
process.exit(0);
35+
} catch {
36+
console.error("[rawdoc] Warning: Go not available and rawdoc not in PATH.");
37+
console.error("[rawdoc] Install manually: go install github.com/RandomCodeSpace/rawdoc@latest");
38+
// Don't fail postinstall — let start.mjs give the error at runtime
39+
process.exit(0);
40+
}
41+
}

start.mjs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#!/usr/bin/env node
2+
import { execFileSync, spawn } from "node:child_process";
3+
import { existsSync } from "node:fs";
4+
import { dirname, resolve } from "node:path";
5+
import { fileURLToPath } from "node:url";
6+
import { platform } from "node:os";
7+
8+
const __dirname = dirname(fileURLToPath(import.meta.url));
9+
10+
const os = platform();
11+
const ext = os === "win32" ? ".exe" : "";
12+
const binaryName = `rawdoc${ext}`;
13+
14+
// Check for binary in plugin directory first, then PATH
15+
let binaryPath = resolve(__dirname, binaryName);
16+
17+
if (!existsSync(binaryPath)) {
18+
// Try to find in PATH
19+
try {
20+
const which = os === "win32" ? "where" : "which";
21+
binaryPath = execFileSync(which, [binaryName], { encoding: "utf8" }).trim().split("\n")[0];
22+
} catch {
23+
// Try to build from source if Go is available
24+
try {
25+
console.error("[rawdoc] Binary not found, building from source...");
26+
execFileSync("go", ["build", "-o", resolve(__dirname, binaryName), "."], {
27+
cwd: __dirname,
28+
stdio: "inherit",
29+
});
30+
binaryPath = resolve(__dirname, binaryName);
31+
} catch {
32+
console.error("[rawdoc] Error: rawdoc binary not found and Go is not available to build it.");
33+
console.error("[rawdoc] Install with: go install github.com/RandomCodeSpace/rawdoc@latest");
34+
process.exit(1);
35+
}
36+
}
37+
}
38+
39+
// Spawn rawdoc in MCP server mode, piping stdio
40+
const child = spawn(binaryPath, ["--serve"], {
41+
stdio: ["inherit", "inherit", "inherit"],
42+
});
43+
44+
child.on("error", (err) => {
45+
console.error(`[rawdoc] Failed to start: ${err.message}`);
46+
process.exit(1);
47+
});
48+
49+
child.on("exit", (code) => {
50+
process.exit(code ?? 0);
51+
});

0 commit comments

Comments
 (0)