Files
agentdock/runner/registry.js
T

169 lines
4.7 KiB
JavaScript

export const TOOLS = Object.freeze({
codex: {
id: "codex",
command: "codex",
name: "Codex",
vendor: "OpenAI",
mono: "CX",
modelFlag: "--model",
secretNames: ["OPENAI_API_KEY"],
},
claude: {
id: "claude",
command: "claude",
name: "Claude Code",
vendor: "Anthropic",
mono: "CC",
modelFlag: "--model",
secretNames: ["ANTHROPIC_API_KEY"],
},
codebuddy: {
id: "codebuddy",
command: "codebuddy",
name: "CodeBuddy",
vendor: "Tencent",
mono: "CB",
modelFlag: "--model",
secretNames: ["CODEBUDDY_API_KEY"],
},
kimi: {
id: "kimi",
command: "kimi",
name: "Kimi CLI",
vendor: "Moonshot AI",
mono: "KM",
modelFlag: "--model",
secretNames: ["MOONSHOT_API_KEY"],
},
opencode: {
id: "opencode",
command: "opencode",
name: "OpenCode",
vendor: "SST / Open source",
mono: "OC",
modelFlag: "--model",
secretNames: [
"OPENAI_API_KEY",
"ANTHROPIC_API_KEY",
"DEEPSEEK_API_KEY",
"GOOGLE_GENERATIVE_AI_API_KEY",
],
},
qwen: {
id: "qwen",
command: "qwen",
name: "Qwen Code",
vendor: "Alibaba",
mono: "QW",
modelFlag: "--model",
secretNames: ["DASHSCOPE_API_KEY"],
},
dsh: {
id: "dsh",
command: "dsh",
name: "DeepSeek Harness",
vendor: "DeepSeek",
mono: "DS",
secretNames: ["DEEPSEEK_API_KEY"],
profiles: ["headless"],
},
ccswitch: {
id: "ccswitch",
command: "cc-switch",
name: "CC Switch",
vendor: "Community CLI",
mono: "CS",
secretNames: [],
visible: false,
integration: true,
},
multica: {
id: "multica",
command: "multica-setup",
name: "Multica Runtime",
vendor: "Multica",
mono: "MU",
secretNames: [],
visible: false,
integration: true,
},
});
export const SECRET_ENV_ALLOWLIST = new Set(
Object.values(TOOLS).flatMap((tool) => tool.secretNames),
);
export function toolById(id) {
return typeof id === "string" ? TOOLS[id] : undefined;
}
export function buildCommand(tool, request = {}) {
const args = [];
const input = request.initialInput?.trim() || "";
if (tool.integration) {
if (request.purpose !== "authorization") throw new Error("Integration tools only support setup sessions");
if (tool.id === "multica") {
for (const [flag, value] of [["--server-url", request.serverUrl], ["--app-url", request.appUrl]]) {
if (!value) continue;
let url;
try { url = new URL(value); } catch { throw new Error(`${flag} must be a valid URL`); }
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password) throw new Error(`${flag} must be an HTTP(S) URL without embedded credentials`);
args.push(flag, url.toString().replace(/\/$/, ""));
}
}
return { command: tool.command, args, interactive: true };
}
if (request.purpose === "task" && !input) {
throw new Error("A task message is required");
}
if (request.purpose === "task") {
switch (tool.id) {
case "codex":
args.push("exec", "--color", "never", "--skip-git-repo-check");
break;
case "claude":
case "codebuddy":
args.push("--print", "--output-format", "text");
break;
case "kimi":
args.push("--prompt", input, "--output-format", "text");
break;
case "opencode":
args.push("run", "--format", "default");
break;
case "qwen":
args.push("--prompt", input, "--output-format", "text");
break;
case "dsh":
args.push("--profile", "headless", input);
return { command: tool.command, args, interactive: false };
default:
throw new Error("Unsupported CLI task mode");
}
if (tool.modelFlag && typeof request.model === "string" && request.model.trim()) {
args.push(tool.modelFlag, request.model.trim().slice(0, 128));
}
if (!["kimi", "qwen"].includes(tool.id)) args.push(input);
return { command: tool.command, args, interactive: false };
}
if (tool.id === "dsh") {
const profile = request.profile || "headless";
if (!tool.profiles.includes(profile)) {
throw new Error("DeepSeek Harness profile must be headless or web");
}
if (profile === "headless" && !request.initialInput?.trim()) {
throw new Error("DeepSeek Harness requires a task before starting");
}
args.push("--profile", profile);
if (profile === "headless" && request.initialInput) args.push(request.initialInput);
} else if (tool.modelFlag && typeof request.model === "string" && request.model.trim()) {
args.push(tool.modelFlag, request.model.trim().slice(0, 128));
}
return { command: tool.command, args, interactive: true };
}