Add OpenCode CLI
This commit is contained in:
parent
bfd9614fa2
commit
03fc685f72
12 changed files with 496 additions and 22 deletions
153
src/app/api/cli-tools/opencode-settings/route.js
Normal file
153
src/app/api/cli-tools/opencode-settings/route.js
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
"use server";
|
||||
|
||||
import { NextResponse } from "next/server";
|
||||
import { exec } from "child_process";
|
||||
import { promisify } from "util";
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
import os from "os";
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
const getConfigDir = () => path.join(os.homedir(), ".config", "opencode");
|
||||
const getConfigPath = () => path.join(getConfigDir(), "opencode.json");
|
||||
|
||||
const checkOpenCodeInstalled = async () => {
|
||||
try {
|
||||
const isWindows = os.platform() === "win32";
|
||||
const command = isWindows ? "where opencode" : "command -v opencode";
|
||||
await execAsync(command, { windowsHide: true });
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
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 (!config?.provider) return false;
|
||||
return !!config.provider["9router"];
|
||||
};
|
||||
|
||||
// GET - Check opencode CLI and read current settings
|
||||
export async function GET() {
|
||||
try {
|
||||
const isInstalled = await checkOpenCodeInstalled();
|
||||
|
||||
if (!isInstalled) {
|
||||
return NextResponse.json({
|
||||
installed: false,
|
||||
config: null,
|
||||
message: "OpenCode CLI is not installed",
|
||||
});
|
||||
}
|
||||
|
||||
const config = await readConfig();
|
||||
|
||||
return NextResponse.json({
|
||||
installed: true,
|
||||
config,
|
||||
has9Router: has9RouterConfig(config),
|
||||
configPath: getConfigPath(),
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("Error checking opencode settings:", error);
|
||||
return NextResponse.json({ error: "Failed to check opencode settings" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// POST - Apply 9Router as openai-compatible provider
|
||||
export async function POST(request) {
|
||||
try {
|
||||
const { baseUrl, apiKey, model } = await request.json();
|
||||
|
||||
if (!baseUrl || !model) {
|
||||
return NextResponse.json({ error: "baseUrl and model are required" }, { status: 400 });
|
||||
}
|
||||
|
||||
const configDir = getConfigDir();
|
||||
const configPath = getConfigPath();
|
||||
|
||||
await fs.mkdir(configDir, { recursive: true });
|
||||
|
||||
// Read existing config or start fresh
|
||||
let config = {};
|
||||
try {
|
||||
const existing = await fs.readFile(configPath, "utf-8");
|
||||
config = JSON.parse(existing);
|
||||
} catch { /* No existing config */ }
|
||||
|
||||
const normalizedBaseUrl = baseUrl.endsWith("/v1") ? baseUrl : `${baseUrl}/v1`;
|
||||
const keyToUse = apiKey || "sk_9router";
|
||||
|
||||
// Merge 9router provider
|
||||
if (!config.provider) config.provider = {};
|
||||
config.provider["9router"] = {
|
||||
npm: "@ai-sdk/openai-compatible",
|
||||
options: {
|
||||
baseURL: normalizedBaseUrl,
|
||||
apiKey: keyToUse,
|
||||
},
|
||||
models: {
|
||||
[model]: { name: model },
|
||||
},
|
||||
};
|
||||
|
||||
// Set as active model
|
||||
config.model = `9router/${model}`;
|
||||
|
||||
await fs.writeFile(configPath, JSON.stringify(config, null, 2));
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: "OpenCode settings applied successfully!",
|
||||
configPath,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("Error updating opencode settings:", error);
|
||||
return NextResponse.json({ error: "Failed to update opencode settings" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE - Remove 9Router provider from config
|
||||
export async function DELETE() {
|
||||
try {
|
||||
const configPath = getConfigPath();
|
||||
|
||||
let config = {};
|
||||
try {
|
||||
const existing = await fs.readFile(configPath, "utf-8");
|
||||
config = JSON.parse(existing);
|
||||
} catch (error) {
|
||||
if (error.code === "ENOENT") {
|
||||
return NextResponse.json({ success: true, message: "No config file to reset" });
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Remove 9router provider
|
||||
if (config.provider) delete config.provider["9router"];
|
||||
|
||||
// Reset model if it was pointing to 9router
|
||||
if (config.model?.startsWith("9router/")) delete config.model;
|
||||
|
||||
await fs.writeFile(configPath, JSON.stringify(config, null, 2));
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: "9Router settings removed from OpenCode",
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("Error resetting opencode settings:", error);
|
||||
return NextResponse.json({ error: "Failed to reset opencode settings" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue