Files
CodePilot/src/app/api/plugins/[id]/route.ts
T
7418andClaude Opus 4.6 ff1fb38735 feat: CodePilot - desktop GUI for Claude Code
Full-featured desktop application built with Next.js + Electron:
- Streaming chat with Claude Code via Agent SDK
- Session management with SQLite persistence
- Project file tree and file preview
- MCP server and custom skills management
- Permission controls with Code/Plan/Ask modes
- Dark/light theme, token tracking
- macOS DMG packaging with electron-builder

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 21:04:05 +08:00

114 lines
3.2 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import fs from 'fs';
import path from 'path';
import os from 'os';
import type { PluginInfo, ErrorResponse, SuccessResponse } from '@/types';
function getClaudeDir(): string {
return path.join(os.homedir(), '.claude');
}
function getSettingsPath(): string {
return path.join(getClaudeDir(), 'settings.json');
}
function readSettings(): Record<string, unknown> {
const settingsPath = getSettingsPath();
if (!fs.existsSync(settingsPath)) return {};
try {
return JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
} catch {
return {};
}
}
function writeSettings(settings: Record<string, unknown>): void {
const settingsPath = getSettingsPath();
const dir = path.dirname(settingsPath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf-8');
}
export async function GET(
_request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
): Promise<NextResponse<{ plugin: PluginInfo } | ErrorResponse>> {
const { id } = await params;
const pluginName = decodeURIComponent(id);
// Check in commands directory
const commandsDir = path.join(getClaudeDir(), 'commands');
const filePath = path.join(commandsDir, `${pluginName}.md`);
if (fs.existsSync(filePath)) {
const content = fs.readFileSync(filePath, 'utf-8');
const firstLine = content.split('\n')[0]?.trim() || '';
return NextResponse.json({
plugin: {
name: pluginName,
description: firstLine.startsWith('#')
? firstLine.replace(/^#+\s*/, '')
: `Skill: /${pluginName}`,
enabled: true,
},
});
}
// Check in settings customCommands
const settings = readSettings();
const customCommands = (settings.customCommands || {}) as Record<
string,
{ description?: string; enabled?: boolean }
>;
if (customCommands[pluginName]) {
const cmd = customCommands[pluginName];
return NextResponse.json({
plugin: {
name: pluginName,
description: cmd.description || `Custom command: /${pluginName}`,
enabled: cmd.enabled !== false,
},
});
}
return NextResponse.json({ error: 'Plugin not found' }, { status: 404 });
}
export async function PUT(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
): Promise<NextResponse<SuccessResponse | ErrorResponse>> {
try {
const { id } = await params;
const pluginName = decodeURIComponent(id);
const body = await request.json();
const { enabled } = body as { enabled: boolean };
const settings = readSettings();
if (!settings.customCommands) {
settings.customCommands = {};
}
const customCommands = settings.customCommands as Record<
string,
{ description?: string; enabled?: boolean }
>;
if (customCommands[pluginName]) {
customCommands[pluginName].enabled = enabled;
} else {
customCommands[pluginName] = { enabled };
}
writeSettings(settings);
return NextResponse.json({ success: true });
} catch (error) {
return NextResponse.json(
{ error: error instanceof Error ? error.message : 'Failed to update plugin' },
{ status: 500 }
);
}
}