Yogesh
initial deploy
cd8bd0a
Raw
History Blame Contribute Delete
11.8 kB
"use server";
import { NextResponse } from "next/server";
import fs from "fs/promises";
import path from "path";
import os from "os";
import { requireCliToolsAuth } from "@/lib/api/requireCliToolsAuth";
import {
ensureCliConfigWriteAllowed,
getCliPrimaryConfigPath,
getCliRuntimeStatus,
} from "@/shared/services/cliRuntime";
import { createBackup } from "@/shared/services/backupService";
import { saveCliToolLastConfigured, deleteCliToolLastConfigured } from "@/lib/db/cliToolState";
import { cliModelConfigSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
import { getApiKeyById } from "@/lib/localDb";
const getQwenSettingsPath = () => getCliPrimaryConfigPath("qwen");
const getQwenDir = () => path.dirname(getQwenSettingsPath());
const getQwenEnvPath = () => path.join(getQwenDir(), ".env");
// Read current settings.json
const readSettings = async () => {
try {
const settingsPath = getQwenSettingsPath();
const content = await fs.readFile(settingsPath, "utf-8");
return JSON.parse(content);
} catch (error: any) {
if (error.code === "ENOENT") return null;
throw error;
}
};
// Read current .env file
const readEnv = async () => {
try {
const envPath = getQwenEnvPath();
return await fs.readFile(envPath, "utf-8");
} catch (error: any) {
if (error.code === "ENOENT") return "";
throw error;
}
};
// Check if settings has OmniRoute config
const hasOmniRouteConfig = (settings: any) => {
if (!settings || !settings.modelProviders) return false;
const openai = settings.modelProviders.openai;
if (!Array.isArray(openai)) return false;
return openai.some((p: any) => {
if (p.name?.includes("OmniRoute") || p.id === "omniroute") return true;
if (!p.baseUrl) return false;
try {
const urlObj = new URL(p.baseUrl);
const host = urlObj.hostname;
const isDashScope =
host === "dashscope.aliyuncs.com" || host.endsWith(".dashscope.aliyuncs.com");
const isOpenAI = host === "api.openai.com" || host.endsWith(".openai.com");
return !isDashScope && !isOpenAI;
} catch {
return true; // invalid URLs are treated as custom endpoints
}
});
};
// GET - Check Qwen CLI and read current settings
export async function GET(request: Request) {
const authError = await requireCliToolsAuth(request);
if (authError) return authError;
try {
const runtime = await getCliRuntimeStatus("qwen");
if (!runtime.installed || !runtime.runnable) {
return NextResponse.json({
installed: runtime.installed,
runnable: runtime.runnable,
command: runtime.command,
commandPath: runtime.commandPath,
runtimeMode: runtime.runtimeMode,
reason: runtime.reason,
settings: null,
message:
runtime.installed && !runtime.runnable
? "Qwen Code CLI is installed but not runnable"
: "Qwen Code CLI is not installed",
});
}
const settings = await readSettings();
return NextResponse.json({
installed: runtime.installed,
runnable: runtime.runnable,
command: runtime.command,
commandPath: runtime.commandPath,
runtimeMode: runtime.runtimeMode,
reason: runtime.reason,
settings,
hasOmniRoute: hasOmniRouteConfig(settings),
settingsPath: getQwenSettingsPath(),
envPath: getQwenEnvPath(),
});
} catch (error) {
console.log("Error checking qwen settings:", error);
return NextResponse.json({ error: "Failed to check qwen settings" }, { status: 500 });
}
}
// POST - Write OmniRoute config to settings.json + .env
export async function POST(request: Request) {
const authError = await requireCliToolsAuth(request);
if (authError) return authError;
let rawBody;
try {
rawBody = await request.json();
} catch {
return NextResponse.json(
{
error: {
message: "Invalid request",
details: [{ field: "body", message: "Invalid JSON body" }],
},
},
{ status: 400 }
);
}
try {
const writeGuard = ensureCliConfigWriteAllowed();
if (writeGuard) {
return NextResponse.json({ error: writeGuard }, { status: 403 });
}
// Extract keyId BEFORE validation — Zod strips unknown fields
const keyId = typeof rawBody?.keyId === "string" ? rawBody.keyId.trim() : null;
const validation = validateBody(cliModelConfigSchema, rawBody);
if (isValidationFailure(validation)) {
return NextResponse.json({ error: validation.error }, { status: 400 });
}
let { baseUrl, apiKey, model } = validation.data;
// Resolve real key from DB by ID
if (keyId) {
try {
const keyRecord = await getApiKeyById(keyId);
if (keyRecord?.key) apiKey = keyRecord.key as string;
} catch {
/* non-critical */
}
}
const resolvedApiKey = apiKey || "sk_omniroute";
const resolvedModel = model || "coder-model";
const normalizedBaseUrl = String(baseUrl || "")
.trim()
.replace(/\/+$/, "");
const qwenDir = getQwenDir();
const settingsPath = getQwenSettingsPath();
const envPath = getQwenEnvPath();
// Ensure directory exists
await fs.mkdir(qwenDir, { recursive: true });
// Backup current settings before modifying
await createBackup("qwen", settingsPath);
// --- Write API keys to ~/.qwen/.env ---
let envContent = await readEnv();
const envLines = envContent.split("\n").filter((line) => {
// Remove old OmniRoute-related keys we're about to write
return (
!line.startsWith("OPENAI_API_KEY=") &&
!line.startsWith("ANTHROPIC_API_KEY=") &&
!line.startsWith("GEMINI_API_KEY=")
);
});
envLines.push(`OPENAI_API_KEY=${resolvedApiKey}`);
envLines.push(`ANTHROPIC_API_KEY=${resolvedApiKey}`);
envLines.push(`GEMINI_API_KEY=${resolvedApiKey}`);
await fs.writeFile(envPath, envLines.join("\n").trim() + "\n", "utf-8");
// --- Write modelProviders to settings.json ---
let existingConfig: Record<string, any> = {};
try {
const raw = await fs.readFile(settingsPath, "utf-8");
existingConfig = JSON.parse(raw);
} catch {
// File doesn't exist or invalid JSON
}
if (!existingConfig.modelProviders) existingConfig.modelProviders = {};
// openai provider — primary, supports all models via OmniRoute
const openaiEntry = {
id: resolvedModel,
name: `${resolvedModel} (OmniRoute)`,
envKey: "OPENAI_API_KEY",
baseUrl: normalizedBaseUrl,
generationConfig: {
contextWindowSize: 200000,
},
};
if (!existingConfig.modelProviders.openai) existingConfig.modelProviders.openai = [];
const openaiProviders = existingConfig.modelProviders.openai;
const openaiIdx = openaiProviders.findIndex(
(p: any) => p && (p.baseUrl === normalizedBaseUrl || p.id === "omniroute")
);
if (openaiIdx >= 0) {
openaiProviders[openaiIdx] = openaiEntry;
} else {
openaiProviders.push(openaiEntry);
}
// anthropic provider — for Claude models via OmniRoute
const anthropicEntry = {
id: "claude-sonnet-4-6",
name: "Claude Sonnet 4.6 (OmniRoute)",
envKey: "ANTHROPIC_API_KEY",
baseUrl: normalizedBaseUrl,
generationConfig: {
contextWindowSize: 200000,
},
};
if (!existingConfig.modelProviders.anthropic) existingConfig.modelProviders.anthropic = [];
const anthropicProviders = existingConfig.modelProviders.anthropic;
const anthropicIdx = anthropicProviders.findIndex(
(p: any) => p && p.baseUrl === normalizedBaseUrl
);
if (anthropicIdx >= 0) {
anthropicProviders[anthropicIdx] = anthropicEntry;
} else {
anthropicProviders.push(anthropicEntry);
}
// gemini provider — for Gemini models via OmniRoute
const geminiEntry = {
id: "gemini-3-flash",
name: "Gemini 3 Flash (OmniRoute)",
envKey: "GEMINI_API_KEY",
baseUrl: normalizedBaseUrl,
};
if (!existingConfig.modelProviders.gemini) existingConfig.modelProviders.gemini = [];
const geminiProviders = existingConfig.modelProviders.gemini;
const geminiIdx = geminiProviders.findIndex((p: any) => p && p.baseUrl === normalizedBaseUrl);
if (geminiIdx >= 0) {
geminiProviders[geminiIdx] = geminiEntry;
} else {
geminiProviders.push(geminiEntry);
}
await fs.writeFile(settingsPath, JSON.stringify(existingConfig, null, 2), "utf-8");
// Persist last-configured timestamp
try {
saveCliToolLastConfigured("qwen");
} catch {
/* non-critical */
}
return NextResponse.json({
success: true,
message: "Qwen Code config saved successfully!",
settingsPath,
envPath,
});
} catch (error) {
console.log("Error updating qwen settings:", error);
return NextResponse.json({ error: "Failed to update qwen settings" }, { status: 500 });
}
}
// DELETE - Remove OmniRoute config from settings.json and .env
export async function DELETE(request: Request) {
const authError = await requireCliToolsAuth(request);
if (authError) return authError;
try {
const writeGuard = ensureCliConfigWriteAllowed();
if (writeGuard) {
return NextResponse.json({ error: writeGuard }, { status: 403 });
}
const settingsPath = getQwenSettingsPath();
const envPath = getQwenEnvPath();
// Backup current settings before resetting
await createBackup("qwen", settingsPath);
// --- Clean settings.json ---
let existingConfig: Record<string, any> = {};
try {
const raw = await fs.readFile(settingsPath, "utf-8");
existingConfig = JSON.parse(raw);
} catch (error: any) {
if (error.code === "ENOENT") {
return NextResponse.json({
success: true,
message: "No settings file to reset",
});
}
throw error;
}
// Remove OmniRoute entries from each provider type
const providerTypes = ["openai", "anthropic", "gemini"];
for (const type of providerTypes) {
if (Array.isArray(existingConfig.modelProviders?.[type])) {
existingConfig.modelProviders[type] = existingConfig.modelProviders[type].filter(
(p: any) => !p.name?.includes("OmniRoute") && p.id !== "omniroute"
);
// Remove empty provider arrays
if (existingConfig.modelProviders[type].length === 0) {
delete existingConfig.modelProviders[type];
}
}
}
// Clean up empty modelProviders
if (existingConfig.modelProviders && Object.keys(existingConfig.modelProviders).length === 0) {
delete existingConfig.modelProviders;
}
await fs.writeFile(settingsPath, JSON.stringify(existingConfig, null, 2), "utf-8");
// --- Clean .env ---
const RESET_ENV_KEYS = ["OPENAI_API_KEY", "ANTHROPIC_API_KEY", "GEMINI_API_KEY"];
try {
let envContent = await fs.readFile(envPath, "utf-8");
const envLines = envContent
.split("\n")
.filter((line) => !RESET_ENV_KEYS.some((key) => line.startsWith(`${key}=`)));
await fs.writeFile(envPath, envLines.join("\n").trim() + "\n", "utf-8");
} catch {
// .env doesn't exist — nothing to clean
}
// Clear last-configured timestamp
try {
deleteCliToolLastConfigured("qwen");
} catch {
/* non-critical */
}
return NextResponse.json({
success: true,
message: "OmniRoute settings removed from Qwen Code",
});
} catch (error) {
console.log("Error resetting qwen settings:", error);
return NextResponse.json({ error: "Failed to reset qwen settings" }, { status: 500 });
}
}