Skip to content

Commit 56913e0

Browse files
Jonathan D.A. Jewellclaude
andcommitted
feat: integrate with poly-ssg-mcp hub
- Added poly-ssg-mcp as hub reference in ECOSYSTEM.scm - Added adapters/ directory with 28 SSG adapters from hub - Adapters provide MCP-compatible interfaces for static site generators Part of the poly-ssg-mcp satellite network. See: https://github.com/hyperpolymath/poly-ssg-mcp Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent a738ec2 commit 56913e0

30 files changed

+3863
-0
lines changed

ECOSYSTEM.scm

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@
1212
"Part of hyperpolymath ecosystem. Follows RSR guidelines.")
1313

1414
(related-projects
15+
(project
16+
(name "poly-ssg-mcp")
17+
(url "https://github.com/hyperpolymath/poly-ssg-mcp")
18+
(relationship "hub")
19+
(description "Unified MCP server for 28 SSGs - provides adapter interface")
20+
(differentiation
21+
"poly-ssg-mcp = Hub with all SSG adapters via MCP
22+
This project = Satellite SSG implementation using the hub"))
1523
(project (name "rhodium-standard-repositories")
1624
(url "https://github.com/hyperpolymath/rhodium-standard-repositories")
1725
(relationship "standard")))

adapters/README.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# SSG Adapters
2+
3+
These adapters are synchronized from the [poly-ssg-mcp](https://github.com/hyperpolymath/poly-ssg-mcp) hub.
4+
5+
## Usage
6+
7+
Each adapter wraps a specific static site generator CLI and exposes it via the MCP protocol.
8+
9+
## Available Adapters
10+
11+
| Adapter | Language | SSG |
12+
|---------|----------|-----|
13+
| babashka.js | Clojure | Babashka |
14+
| cobalt.js | Rust | Cobalt |
15+
| coleslaw.js | Common Lisp | Coleslaw |
16+
| cryogen.js | Clojure | Cryogen |
17+
| documenter.js | Julia | Documenter.jl |
18+
| ema.js | Haskell | Ema |
19+
| fornax.js | F# | Fornax |
20+
| franklin.js | Julia | Franklin.jl |
21+
| frog.js | Racket | Frog |
22+
| hakyll.js | Haskell | Hakyll |
23+
| laika.js | Scala | Laika |
24+
| marmot.js | Crystal | Marmot |
25+
| mdbook.js | Rust | mdBook |
26+
| nimble-publisher.js | Elixir | NimblePublisher |
27+
| nimrod.js | Nim | Nimrod |
28+
| orchid.js | Kotlin | Orchid |
29+
| perun.js | Clojure | Perun |
30+
| pollen.js | Racket | Pollen |
31+
| publish.js | Swift | Publish |
32+
| reggae.js | D | Reggae |
33+
| scalatex.js | Scala | ScalaTex |
34+
| serum.js | Elixir | Serum |
35+
| staticwebpages.js | Julia | StaticWebPages.jl |
36+
| tableau.js | Elixir | Tableau |
37+
| wub.js | Tcl | Wub |
38+
| yocaml.js | OCaml | YOCaml |
39+
| zola.js | Rust | Zola |
40+
| zotonic.js | Erlang | Zotonic |
41+
42+
## Synchronization
43+
44+
To update these adapters from the hub:
45+
46+
```bash
47+
~/Documents/scripts/transfer-ssg-adapters.sh --satellite $(basename $(pwd))
48+
```
49+
50+
---
51+
*Synced from poly-ssg-mcp hub*

adapters/babashka.js

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// SPDX-License-Identifier: MIT
2+
// SPDX-FileCopyrightText: 2025 Jonathan D.A. Jewell
3+
4+
/**
5+
* Babashka adapter - Fast Clojure scripting for static sites
6+
* https://babashka.org/
7+
*/
8+
9+
export const name = "Babashka";
10+
export const language = "Clojure";
11+
export const description = "Fast Clojure scripting runtime, usable for static site generation";
12+
13+
let connected = false;
14+
let bbPath = "bb";
15+
16+
async function runCommand(args, cwd = null) {
17+
const cmd = new Deno.Command(bbPath, {
18+
args,
19+
cwd: cwd || Deno.cwd(),
20+
stdout: "piped",
21+
stderr: "piped",
22+
});
23+
const output = await cmd.output();
24+
const decoder = new TextDecoder();
25+
return {
26+
success: output.success,
27+
stdout: decoder.decode(output.stdout),
28+
stderr: decoder.decode(output.stderr),
29+
code: output.code,
30+
};
31+
}
32+
33+
export async function connect() {
34+
try {
35+
const result = await runCommand(["--version"]);
36+
connected = result.success;
37+
return connected;
38+
} catch {
39+
connected = false;
40+
return false;
41+
}
42+
}
43+
44+
export async function disconnect() {
45+
connected = false;
46+
}
47+
48+
export function isConnected() {
49+
return connected;
50+
}
51+
52+
export const tools = [
53+
{
54+
name: "babashka_run",
55+
description: "Run a Babashka script",
56+
inputSchema: {
57+
type: "object",
58+
properties: {
59+
path: { type: "string", description: "Working directory" },
60+
script: { type: "string", description: "Script file to run" },
61+
},
62+
required: ["script"],
63+
},
64+
execute: async ({ path, script }) => await runCommand([script], path),
65+
},
66+
{
67+
name: "babashka_eval",
68+
description: "Evaluate Clojure expression",
69+
inputSchema: {
70+
type: "object",
71+
properties: {
72+
path: { type: "string", description: "Working directory" },
73+
expr: { type: "string", description: "Clojure expression" },
74+
},
75+
required: ["expr"],
76+
},
77+
execute: async ({ path, expr }) => await runCommand(["-e", expr], path),
78+
},
79+
{
80+
name: "babashka_tasks",
81+
description: "List available tasks",
82+
inputSchema: {
83+
type: "object",
84+
properties: {
85+
path: { type: "string", description: "Working directory" },
86+
},
87+
},
88+
execute: async ({ path }) => await runCommand(["tasks"], path),
89+
},
90+
{
91+
name: "babashka_task",
92+
description: "Run a task from bb.edn",
93+
inputSchema: {
94+
type: "object",
95+
properties: {
96+
path: { type: "string", description: "Working directory" },
97+
task: { type: "string", description: "Task name" },
98+
},
99+
required: ["task"],
100+
},
101+
execute: async ({ path, task }) => await runCommand([task], path),
102+
},
103+
{
104+
name: "babashka_nrepl",
105+
description: "Start nREPL server",
106+
inputSchema: {
107+
type: "object",
108+
properties: {
109+
path: { type: "string", description: "Working directory" },
110+
port: { type: "number", description: "Port number" },
111+
},
112+
},
113+
execute: async ({ path, port }) => {
114+
const args = ["nrepl-server"];
115+
if (port) args.push(String(port));
116+
return await runCommand(args, path);
117+
},
118+
},
119+
{
120+
name: "babashka_version",
121+
description: "Get Babashka version",
122+
inputSchema: { type: "object", properties: {} },
123+
execute: async () => await runCommand(["--version"]),
124+
},
125+
];

adapters/cobalt.js

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
// SPDX-License-Identifier: MIT
2+
// SPDX-FileCopyrightText: 2025 Jonathan D.A. Jewell
3+
4+
/**
5+
* Cobalt adapter - Static site generator in Rust
6+
* https://cobalt-org.github.io/
7+
*/
8+
9+
export const name = "Cobalt";
10+
export const language = "Rust";
11+
export const description = "Straightforward static site generator written in Rust";
12+
13+
let connected = false;
14+
let binaryPath = "cobalt";
15+
16+
async function runCommand(args, cwd = null) {
17+
const cmd = new Deno.Command(binaryPath, {
18+
args,
19+
cwd: cwd || Deno.cwd(),
20+
stdout: "piped",
21+
stderr: "piped",
22+
});
23+
const output = await cmd.output();
24+
const decoder = new TextDecoder();
25+
return {
26+
success: output.success,
27+
stdout: decoder.decode(output.stdout),
28+
stderr: decoder.decode(output.stderr),
29+
code: output.code,
30+
};
31+
}
32+
33+
export async function connect() {
34+
try {
35+
const result = await runCommand(["--version"]);
36+
connected = result.success;
37+
return connected;
38+
} catch {
39+
connected = false;
40+
return false;
41+
}
42+
}
43+
44+
export async function disconnect() {
45+
connected = false;
46+
}
47+
48+
export function isConnected() {
49+
return connected;
50+
}
51+
52+
export const tools = [
53+
{
54+
name: "cobalt_init",
55+
description: "Initialize a new Cobalt site",
56+
inputSchema: {
57+
type: "object",
58+
properties: {
59+
path: { type: "string", description: "Path for the new site" },
60+
},
61+
},
62+
execute: async ({ path }) => {
63+
const args = ["init"];
64+
if (path) args.push(path);
65+
return await runCommand(args);
66+
},
67+
},
68+
{
69+
name: "cobalt_build",
70+
description: "Build the Cobalt site",
71+
inputSchema: {
72+
type: "object",
73+
properties: {
74+
path: { type: "string", description: "Path to site root" },
75+
destination: { type: "string", description: "Output directory" },
76+
drafts: { type: "boolean", description: "Include drafts" },
77+
},
78+
},
79+
execute: async ({ path, destination, drafts }) => {
80+
const args = ["build"];
81+
if (destination) args.push("--destination", destination);
82+
if (drafts) args.push("--drafts");
83+
return await runCommand(args, path);
84+
},
85+
},
86+
{
87+
name: "cobalt_serve",
88+
description: "Start Cobalt development server",
89+
inputSchema: {
90+
type: "object",
91+
properties: {
92+
path: { type: "string", description: "Path to site root" },
93+
port: { type: "number", description: "Port number" },
94+
host: { type: "string", description: "Host to bind to" },
95+
drafts: { type: "boolean", description: "Include drafts" },
96+
},
97+
},
98+
execute: async ({ path, port, host, drafts }) => {
99+
const args = ["serve"];
100+
if (port) args.push("--port", String(port));
101+
if (host) args.push("--host", host);
102+
if (drafts) args.push("--drafts");
103+
return await runCommand(args, path);
104+
},
105+
},
106+
{
107+
name: "cobalt_watch",
108+
description: "Watch for changes and rebuild",
109+
inputSchema: {
110+
type: "object",
111+
properties: {
112+
path: { type: "string", description: "Path to site root" },
113+
},
114+
},
115+
execute: async ({ path }) => await runCommand(["watch"], path),
116+
},
117+
{
118+
name: "cobalt_clean",
119+
description: "Clean the build directory",
120+
inputSchema: {
121+
type: "object",
122+
properties: {
123+
path: { type: "string", description: "Path to site root" },
124+
},
125+
},
126+
execute: async ({ path }) => await runCommand(["clean"], path),
127+
},
128+
{
129+
name: "cobalt_new",
130+
description: "Create a new post",
131+
inputSchema: {
132+
type: "object",
133+
properties: {
134+
path: { type: "string", description: "Path to site root" },
135+
title: { type: "string", description: "Post title" },
136+
},
137+
required: ["title"],
138+
},
139+
execute: async ({ path, title }) => await runCommand(["new", title], path),
140+
},
141+
{
142+
name: "cobalt_version",
143+
description: "Get Cobalt version",
144+
inputSchema: { type: "object", properties: {} },
145+
execute: async () => await runCommand(["--version"]),
146+
},
147+
];

0 commit comments

Comments
 (0)