File size: 4,778 Bytes
88c4c60 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | "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 getDataDir = () => path.join(os.homedir(), ".cline", "data");
const getGlobalStatePath = () => path.join(getDataDir(), "globalState.json");
const getSecretsPath = () => path.join(getDataDir(), "secrets.json");
const checkInstalled = async () => {
try {
const isWindows = os.platform() === "win32";
const command = isWindows ? "where cline" : "which cline";
const env = isWindows
? { ...process.env, PATH: `${process.env.APPDATA}\\npm;${process.env.PATH}` }
: process.env;
await execAsync(command, { windowsHide: true, env });
return true;
} catch {
try {
await fs.access(getGlobalStatePath());
return true;
} catch {
return false;
}
}
};
const readJson = async (filePath) => {
try {
const content = await fs.readFile(filePath, "utf-8");
return JSON.parse(content);
} catch (error) {
if (error.code === "ENOENT") return null;
throw error;
}
};
const has9RouterConfig = (globalState) => {
if (!globalState) return false;
const isOpenAi =
globalState.actModeApiProvider === "openai" || globalState.planModeApiProvider === "openai";
const baseUrl = globalState.openAiBaseUrl || "";
return isOpenAi && (baseUrl.includes("localhost") || baseUrl.includes("127.0.0.1") || baseUrl.includes("9router"));
};
export async function GET() {
try {
const installed = await checkInstalled();
if (!installed) {
return NextResponse.json({ installed: false, settings: null, message: "Cline CLI is not installed" });
}
const globalState = await readJson(getGlobalStatePath());
return NextResponse.json({
installed: true,
settings: {
actModeApiProvider: globalState?.actModeApiProvider,
planModeApiProvider: globalState?.planModeApiProvider,
openAiBaseUrl: globalState?.openAiBaseUrl,
openAiModelId: globalState?.openAiModelId,
},
has9Router: has9RouterConfig(globalState),
globalStatePath: getGlobalStatePath(),
});
} catch (error) {
console.log("Error checking cline settings:", error);
return NextResponse.json({ error: "Failed to check cline settings" }, { status: 500 });
}
}
export async function POST(request) {
try {
const { baseUrl, apiKey, model } = await request.json();
if (!baseUrl || !apiKey || !model) {
return NextResponse.json({ error: "baseUrl, apiKey and model are required" }, { status: 400 });
}
await fs.mkdir(getDataDir(), { recursive: true });
// Cline expects base WITHOUT /v1
const normalizedBaseUrl = baseUrl.endsWith("/v1") ? baseUrl.slice(0, -3) : baseUrl;
const globalState = (await readJson(getGlobalStatePath())) || {};
globalState.actModeApiProvider = "openai";
globalState.planModeApiProvider = "openai";
globalState.openAiBaseUrl = normalizedBaseUrl;
globalState.openAiModelId = model;
globalState.planModeOpenAiModelId = model;
await fs.writeFile(getGlobalStatePath(), JSON.stringify(globalState, null, 2));
const secrets = (await readJson(getSecretsPath())) || {};
secrets.openAiApiKey = apiKey;
await fs.writeFile(getSecretsPath(), JSON.stringify(secrets, null, 2));
return NextResponse.json({ success: true, message: "Cline settings applied successfully!", globalStatePath: getGlobalStatePath() });
} catch (error) {
console.log("Error updating cline settings:", error);
return NextResponse.json({ error: "Failed to update cline settings" }, { status: 500 });
}
}
export async function DELETE() {
try {
const globalState = await readJson(getGlobalStatePath());
if (!globalState) {
return NextResponse.json({ success: true, message: "No settings file to reset" });
}
if (globalState.actModeApiProvider === "openai") {
delete globalState.openAiBaseUrl;
delete globalState.openAiModelId;
delete globalState.planModeOpenAiModelId;
globalState.actModeApiProvider = "cline";
globalState.planModeApiProvider = "cline";
}
await fs.writeFile(getGlobalStatePath(), JSON.stringify(globalState, null, 2));
const secrets = (await readJson(getSecretsPath())) || {};
delete secrets.openAiApiKey;
await fs.writeFile(getSecretsPath(), JSON.stringify(secrets, null, 2));
return NextResponse.json({ success: true, message: "9Router settings removed from Cline" });
} catch (error) {
console.log("Error resetting cline settings:", error);
return NextResponse.json({ error: "Failed to reset cline settings" }, { status: 500 });
}
}
|