9router/src/app/api/cli-tools/claude-settings/route.js
2026-04-06 17:32:44 +07:00

202 lines
5.1 KiB
JavaScript

"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);
// Get claude settings path based on OS
const getClaudeSettingsPath = () => {
const homeDir = os.homedir();
return path.join(homeDir, ".claude", "settings.json");
};
// Check if claude CLI is installed (via which/where or config file exists)
const checkClaudeInstalled = async () => {
try {
const isWindows = os.platform() === "win32";
const command = isWindows ? "where claude" : "which claude";
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(getClaudeSettingsPath());
return true;
} catch {
return false;
}
}
};
// Read current settings
const readSettings = async () => {
try {
const settingsPath = getClaudeSettingsPath();
const content = await fs.readFile(settingsPath, "utf-8");
return JSON.parse(content);
} catch (error) {
if (error.code === "ENOENT") {
return null;
}
throw error;
}
};
// GET - Check claude CLI and read current settings
export async function GET() {
try {
const isInstalled = await checkClaudeInstalled();
if (!isInstalled) {
return NextResponse.json({
installed: false,
settings: null,
message: "Claude CLI is not installed",
});
}
const settings = await readSettings();
const has9Router = !!(settings?.env?.ANTHROPIC_BASE_URL);
return NextResponse.json({
installed: true,
settings: settings,
has9Router: has9Router,
settingsPath: getClaudeSettingsPath(),
});
} catch (error) {
console.log("Error checking claude settings:", error);
return NextResponse.json(
{ error: "Failed to check claude settings" },
{ status: 500 }
);
}
}
// POST - Backup old fields and write new settings
export async function POST(request) {
try {
const { env } = await request.json();
if (!env || typeof env !== "object") {
return NextResponse.json(
{ error: "Invalid env object" },
{ status: 400 }
);
}
const settingsPath = getClaudeSettingsPath();
const claudeDir = path.dirname(settingsPath);
// Ensure .claude directory exists
await fs.mkdir(claudeDir, { recursive: true });
// Read current settings
let currentSettings = {};
try {
const content = await fs.readFile(settingsPath, "utf-8");
currentSettings = JSON.parse(content);
} catch (error) {
if (error.code !== "ENOENT") {
throw error;
}
}
// Normalize ANTHROPIC_BASE_URL to ensure /v1 suffix
if (env.ANTHROPIC_BASE_URL) {
env.ANTHROPIC_BASE_URL = env.ANTHROPIC_BASE_URL.endsWith("/v1")
? env.ANTHROPIC_BASE_URL
: `${env.ANTHROPIC_BASE_URL}/v1`;
}
// Merge new env with existing settings
const newSettings = {
...currentSettings,
env: {
...(currentSettings.env || {}),
...env,
},
};
// Write new settings
await fs.writeFile(settingsPath, JSON.stringify(newSettings, null, 2));
return NextResponse.json({
success: true,
message: "Settings updated successfully",
});
} catch (error) {
console.log("Error updating claude settings:", error);
return NextResponse.json(
{ error: "Failed to update claude settings" },
{ status: 500 }
);
}
}
// Fields to remove when resetting
const RESET_ENV_KEYS = [
"ANTHROPIC_BASE_URL",
"ANTHROPIC_AUTH_TOKEN",
"ANTHROPIC_DEFAULT_OPUS_MODEL",
"ANTHROPIC_DEFAULT_SONNET_MODEL",
"ANTHROPIC_DEFAULT_HAIKU_MODEL",
"API_TIMEOUT_MS",
];
// DELETE - Reset settings (remove env fields)
export async function DELETE() {
try {
const settingsPath = getClaudeSettingsPath();
// Read current settings
let currentSettings = {};
try {
const content = await fs.readFile(settingsPath, "utf-8");
currentSettings = JSON.parse(content);
} catch (error) {
if (error.code === "ENOENT") {
return NextResponse.json({
success: true,
message: "No settings file to reset",
});
}
throw error;
}
// Remove specified env fields
if (currentSettings.env) {
RESET_ENV_KEYS.forEach((key) => {
delete currentSettings.env[key];
});
// Clean up empty env object
if (Object.keys(currentSettings.env).length === 0) {
delete currentSettings.env;
}
}
// Write updated settings
await fs.writeFile(settingsPath, JSON.stringify(currentSettings, null, 2));
return NextResponse.json({
success: true,
message: "Settings reset successfully",
});
} catch (error) {
console.log("Error resetting claude settings:", error);
return NextResponse.json(
{ error: "Failed to reset claude settings" },
{ status: 500 }
);
}
}