feat(sync): add Claude home sync parity across providers

This commit is contained in:
Kieran Klaassen
2026-03-02 21:02:21 -08:00
parent 1a0ddb9de1
commit 168c946033
38 changed files with 2323 additions and 307 deletions

View File

@@ -1,21 +1,62 @@
import fs from "fs/promises"
import path from "path"
import type { ClaudeHomeConfig } from "../parsers/claude-home"
import { forceSymlink, isValidSkillName } from "../utils/symlink"
import type { ClaudeMcpServer } from "../types/claude"
import { syncDroidCommands } from "./commands"
import { mergeJsonConfigAtKey } from "./json-config"
import { syncSkills } from "./skills"
type DroidMcpServer = {
type: "stdio" | "http"
command?: string
args?: string[]
env?: Record<string, string>
url?: string
headers?: Record<string, string>
disabled: boolean
}
export async function syncToDroid(
config: ClaudeHomeConfig,
outputRoot: string,
): Promise<void> {
const skillsDir = path.join(outputRoot, "skills")
await fs.mkdir(skillsDir, { recursive: true })
await syncSkills(config.skills, path.join(outputRoot, "skills"))
await syncDroidCommands(config, outputRoot)
for (const skill of config.skills) {
if (!isValidSkillName(skill.name)) {
console.warn(`Skipping skill with invalid name: ${skill.name}`)
continue
}
const target = path.join(skillsDir, skill.name)
await forceSymlink(skill.sourceDir, target)
if (Object.keys(config.mcpServers).length > 0) {
await mergeJsonConfigAtKey({
configPath: path.join(outputRoot, "mcp.json"),
key: "mcpServers",
incoming: convertMcpForDroid(config.mcpServers),
})
}
}
function convertMcpForDroid(
servers: Record<string, ClaudeMcpServer>,
): Record<string, DroidMcpServer> {
const result: Record<string, DroidMcpServer> = {}
for (const [name, server] of Object.entries(servers)) {
if (server.command) {
result[name] = {
type: "stdio",
command: server.command,
args: server.args,
env: server.env,
disabled: false,
}
continue
}
if (server.url) {
result[name] = {
type: "http",
url: server.url,
headers: server.headers,
disabled: false,
}
}
}
return result
}