diff --git a/bun.lock b/bun.lock index 60b2c52..bbafa58 100644 --- a/bun.lock +++ b/bun.lock @@ -6,6 +6,7 @@ "dependencies": { "@modelcontextprotocol/sdk": "^1.12.1", "@tursodatabase/database": "^0.6.0", + "jsonc-parser": "^3.3.1", "zod": "^3.24.0", }, "devDependencies": { @@ -155,6 +156,8 @@ "json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="], + "jsonc-parser": ["jsonc-parser@3.3.1", "", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="], + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], diff --git a/package.json b/package.json index fd06659..4b04f2b 100644 --- a/package.json +++ b/package.json @@ -13,13 +13,14 @@ "LICENSE" ], "scripts": { - "build": "bun build packages/cli/src/index.ts --target node --external @tursodatabase/database --external @modelcontextprotocol/sdk --external zod --outfile dist/cli.mjs && node -e \"let f=require('fs');let c=f.readFileSync('dist/cli.mjs','utf8');f.writeFileSync('dist/cli.mjs',c.replace('#!/usr/bin/env bun','#!/usr/bin/env node'))\"", + "build": "bun build packages/cli/src/index.ts --target node --external @tursodatabase/database --external @modelcontextprotocol/sdk --external zod --external jsonc-parser --outfile dist/cli.mjs && node -e \"let f=require('fs');let c=f.readFileSync('dist/cli.mjs','utf8');f.writeFileSync('dist/cli.mjs',c.replace('#!/usr/bin/env bun','#!/usr/bin/env node'))\"", "prepublishOnly": "bun run build", "test": "bun test" }, "dependencies": { "@modelcontextprotocol/sdk": "^1.12.1", "@tursodatabase/database": "^0.6.0", + "jsonc-parser": "^3.3.1", "zod": "^3.24.0" }, "devDependencies": { diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 10f301e..7b1214c 100755 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -1,5 +1,6 @@ #!/usr/bin/env bun import { startMcpServer } from "./mcp.js"; +import { applyEdits, modify, parse as parseJsonc, type ParseError } from "jsonc-parser"; const command = process.argv[2]; @@ -61,12 +62,6 @@ if (!command || command === "serve") { key: "mcpServers", entry: mcpServersEntry, }, - { - name: "OpenCode", - path: join(xdgConfig, "opencode", "opencode.json"), - key: "mcp", - entry: opencodeMcpEntry, - }, ]; let configured = 0; @@ -98,6 +93,37 @@ if (!command || command === "serve") { configured++; } + // OpenCode: prefer opencode.jsonc over opencode.json + // Use jsonc-parser modify()/applyEdits() to preserve + // comments and formatting, mirroring OpenCode's addMcpToConfig(). + const opencodeDir = join(xdgConfig, "opencode"); + if (existsSync(opencodeDir)) { + const candidates = [ + join(opencodeDir, "opencode.jsonc"), + join(opencodeDir, "opencode.json"), + ]; + const target = candidates.find(existsSync) ?? candidates[0]; + const raw = existsSync(target) ? readFileSync(target, "utf-8") : "{}"; + const text = raw.trim() ? raw : "{}"; + + const errors: ParseError[] = []; + const parsed = parseJsonc(text, errors, { allowTrailingComma: true }); + if (errors.length) { + console.log(`OpenCode: config invalid, skipping (${target})`); + } else if ((parsed as any)?.mcp?.cachebro) { + console.log(`OpenCode: already configured (${target})`); + configured++; + } else { + const edits = modify(text, ["mcp", "cachebro"], opencodeMcpEntry, { + formattingOptions: { tabSize: 2, insertSpaces: true }, + }); + const updated = applyEdits(text, edits); + writeFileSync(target, updated.endsWith("\n") ? updated : updated + "\n"); + console.log(`OpenCode: configured (${target})`); + configured++; + } + } + if (configured === 0) { console.log("No supported tools detected. You can manually add cachebro to your MCP config:"); console.log(JSON.stringify({ mcpServers: { cachebro: mcpServersEntry } }, null, 2));