feat(cli-tools): add OpenCode tool integration to CLI Tools page

This commit is contained in:
decolua 2026-03-03 11:04:56 +07:00
parent 03fc685f72
commit 38ded5c62f
6 changed files with 457 additions and 36 deletions

View file

@ -0,0 +1,148 @@
"use server";
import { NextResponse } from "next/server";
import fs from "fs/promises";
import path from "path";
import os from "os";
// Resolve chatLanguageModels.json path per OS
const getConfigPath = () => {
const home = os.homedir();
const platform = os.platform();
if (platform === "win32") {
return path.join(process.env.APPDATA || home, "Code", "User", "chatLanguageModels.json");
}
if (platform === "darwin") {
return path.join(home, "Library", "Application Support", "Code", "User", "chatLanguageModels.json");
}
return path.join(home, ".config", "Code", "User", "chatLanguageModels.json");
};
const readConfig = async () => {
try {
const content = await fs.readFile(getConfigPath(), "utf-8");
return JSON.parse(content);
} catch (error) {
if (error.code === "ENOENT") return null;
throw error;
}
};
const has9RouterConfig = (config) => {
if (!Array.isArray(config)) return false;
return config.some((entry) => entry.name === "9Router");
};
const get9RouterEntry = (config) => {
if (!Array.isArray(config)) return null;
return config.find((entry) => entry.name === "9Router") || null;
};
// GET - Read current copilot config
export async function GET() {
try {
const config = await readConfig();
const entry = get9RouterEntry(config);
return NextResponse.json({
installed: true,
config,
has9Router: has9RouterConfig(config),
configPath: getConfigPath(),
currentModel: entry?.models?.[0]?.id || null,
currentUrl: entry?.models?.[0]?.url || null,
});
} catch (error) {
console.log("Error checking copilot settings:", error);
return NextResponse.json({ error: "Failed to check copilot settings" }, { status: 500 });
}
}
// POST - Apply 9Router config to chatLanguageModels.json
export async function POST(request) {
try {
const { baseUrl, apiKey, models } = await request.json();
if (!baseUrl || !models?.length) {
return NextResponse.json({ error: "baseUrl and models are required" }, { status: 400 });
}
const configPath = getConfigPath();
await fs.mkdir(path.dirname(configPath), { recursive: true });
// Read existing config array
let config = [];
try {
const existing = await fs.readFile(configPath, "utf-8");
const parsed = JSON.parse(existing);
config = Array.isArray(parsed) ? parsed : [];
} catch { /* No existing config */ }
const endpointUrl = `${baseUrl}/chat/completions#models.ai.azure.com`;
const keyToUse = apiKey || "sk_9router";
const newEntry = {
name: "9Router",
vendor: "azure",
apiKey: keyToUse,
models: models.map((id) => ({
id,
name: id,
url: endpointUrl,
toolCalling: true,
vision: false,
maxInputTokens: 128000,
maxOutputTokens: 16000,
})),
};
// Replace existing 9Router entry or append
const idx = config.findIndex((e) => e.name === "9Router");
if (idx >= 0) {
config[idx] = newEntry;
} else {
config.push(newEntry);
}
await fs.writeFile(configPath, JSON.stringify(config, null, 2));
return NextResponse.json({
success: true,
message: "Copilot settings applied! Reload VS Code to take effect.",
configPath,
});
} catch (error) {
console.log("Error updating copilot settings:", error);
return NextResponse.json({ error: "Failed to update copilot settings" }, { status: 500 });
}
}
// DELETE - Remove 9Router entry from chatLanguageModels.json
export async function DELETE() {
try {
const configPath = getConfigPath();
let config = [];
try {
const existing = await fs.readFile(configPath, "utf-8");
const parsed = JSON.parse(existing);
config = Array.isArray(parsed) ? parsed : [];
} catch (error) {
if (error.code === "ENOENT") {
return NextResponse.json({ success: true, message: "No config file to reset" });
}
throw error;
}
config = config.filter((e) => e.name !== "9Router");
await fs.writeFile(configPath, JSON.stringify(config, null, 2));
return NextResponse.json({
success: true,
message: "9Router removed from Copilot config",
});
} catch (error) {
console.log("Error resetting copilot settings:", error);
return NextResponse.json({ error: "Failed to reset copilot settings" }, { status: 500 });
}
}