125 lines
3.8 KiB
TypeScript
125 lines
3.8 KiB
TypeScript
import path from "node:path";
|
|
import os from "node:os";
|
|
|
|
import { getHermesConfigPath } from "./hermesHome.ts";
|
|
import { generateClaudeConfig } from "./claude";
|
|
import { generateClineConfig } from "./cline";
|
|
import { generateCodexConfig } from "./codex";
|
|
import { generateContinueConfig } from "./continue";
|
|
import { generateHermesConfig } from "./hermes";
|
|
import { generateHermesAgentConfig, type HermesAgentConfigPayload } from "./hermes-agent";
|
|
import { generateKilocodeConfig } from "./kilocode";
|
|
import { generateOpencodeConfig } from "./opencode";
|
|
|
|
export interface GenerateOptions {
|
|
baseUrl: string;
|
|
apiKey: string;
|
|
model?: string;
|
|
}
|
|
|
|
export interface GenerateResult {
|
|
success: boolean;
|
|
configPath: string;
|
|
content?: string;
|
|
error?: string;
|
|
}
|
|
|
|
export function validateBaseUrl(url: string): boolean {
|
|
try {
|
|
const u = new URL(url);
|
|
return u.protocol === "http:" || u.protocol === "https:";
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function expandHome(p: string): string {
|
|
const home = os.homedir();
|
|
return p.replace(/^~\//, home + "/");
|
|
}
|
|
|
|
// Static paths that do not depend on runtime env vars can stay eagerly computed.
|
|
const STATIC_TOOL_CONFIG_PATHS: Record<string, string> = {
|
|
claude: path.join(os.homedir(), ".claude", "settings.json"),
|
|
codex: path.join(os.homedir(), ".codex", "config.yaml"),
|
|
opencode: path.join(os.homedir(), ".config", "opencode", "opencode.json"),
|
|
cline: path.join(os.homedir(), ".cline", "data", "globalState.json"),
|
|
kilocode: path.join(os.homedir(), ".config", "kilocode", "settings.json"),
|
|
continue: path.join(os.homedir(), ".continue", "config.yaml"),
|
|
};
|
|
|
|
/**
|
|
* Returns the config path for a given tool.
|
|
*
|
|
* Hermes entries are resolved lazily at call-time so `HERMES_HOME` is always
|
|
* honoured (#3628). All other tools use the eagerly-computed static map.
|
|
*/
|
|
function getToolConfigPath(toolId: string): string {
|
|
if (toolId === "hermes" || toolId === "hermes-agent") {
|
|
return getHermesConfigPath();
|
|
}
|
|
return STATIC_TOOL_CONFIG_PATHS[toolId] ?? "";
|
|
}
|
|
|
|
type ConfigGenerator = (options: GenerateOptions) => string | Promise<string>;
|
|
|
|
const GENERATORS: Record<string, ConfigGenerator> = {
|
|
claude: generateClaudeConfig,
|
|
codex: generateCodexConfig,
|
|
opencode: generateOpencodeConfig,
|
|
cline: generateClineConfig,
|
|
kilocode: generateKilocodeConfig,
|
|
continue: generateContinueConfig,
|
|
hermes: generateHermesConfig,
|
|
"hermes-agent": generateHermesAgentConfig as any, // rich multi-role version
|
|
};
|
|
|
|
export async function generateConfig(
|
|
toolId: string,
|
|
options: GenerateOptions
|
|
): Promise<GenerateResult> {
|
|
if (!validateBaseUrl(options.baseUrl)) {
|
|
return {
|
|
success: false,
|
|
configPath: "",
|
|
error: "Invalid baseUrl: must be an absolute HTTP(S) URL",
|
|
};
|
|
}
|
|
|
|
if (!options.apiKey || options.apiKey.trim().length === 0) {
|
|
return { success: false, configPath: "", error: "API key is required" };
|
|
}
|
|
|
|
try {
|
|
const generate = GENERATORS[toolId];
|
|
if (!generate) {
|
|
return { success: false, configPath: "", error: `Unknown tool: ${toolId}` };
|
|
}
|
|
const content = await generate(options);
|
|
const configPath = getToolConfigPath(toolId);
|
|
return { success: true, configPath, content };
|
|
} catch (err) {
|
|
const msg = err instanceof Error ? err.message : String(err);
|
|
return { success: false, configPath: "", error: `Generation failed: ${msg}` };
|
|
}
|
|
}
|
|
|
|
export async function generateAllConfigs(options: GenerateOptions): Promise<GenerateResult[]> {
|
|
const toolIds = [
|
|
"claude",
|
|
"codex",
|
|
"opencode",
|
|
"cline",
|
|
"kilocode",
|
|
"continue",
|
|
"hermes",
|
|
] as const;
|
|
const results = await Promise.allSettled(toolIds.map((id) => generateConfig(id, options)));
|
|
|
|
return results.map((r) =>
|
|
r.status === "fulfilled"
|
|
? r.value
|
|
: { success: false, configPath: "", error: r.reason?.message || "Unknown error" }
|
|
);
|
|
}
|