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>
This commit is contained in:
7418andClaude Opus 4.6 committed 2026-02-06 21:04:05 +08:00
1 parent 6776cc6297
commit ff1fb38735
149 files changed
+31117 -122

No files matched your search

+59
View File
@@ -0,0 +1,59 @@
import { NextRequest, NextResponse } from 'next/server';
import { updateTask, deleteTask, getTask } from '@/lib/db';
import type { TaskResponse, ErrorResponse, UpdateTaskRequest } from '@/types';
interface RouteContext {
params: Promise<{ id: string }>;
}
export async function PATCH(request: NextRequest, context: RouteContext) {
const { id } = await context.params;
try {
const body: UpdateTaskRequest = await request.json();
const existing = getTask(id);
if (!existing) {
return NextResponse.json<ErrorResponse>(
{ error: 'Task not found' },
{ status: 404 }
);
}
const updated = updateTask(id, body);
if (!updated) {
return NextResponse.json<ErrorResponse>(
{ error: 'Failed to update task' },
{ status: 500 }
);
}
return NextResponse.json<TaskResponse>({ task: updated });
} catch (error) {
return NextResponse.json<ErrorResponse>(
{ error: error instanceof Error ? error.message : 'Failed to update task' },
{ status: 500 }
);
}
}
export async function DELETE(_request: NextRequest, context: RouteContext) {
const { id } = await context.params;
try {
const deleted = deleteTask(id);
if (!deleted) {
return NextResponse.json<ErrorResponse>(
{ error: 'Task not found' },
{ status: 404 }
);
}
return NextResponse.json({ success: true });
} catch (error) {
return NextResponse.json<ErrorResponse>(
{ error: error instanceof Error ? error.message : 'Failed to delete task' },
{ status: 500 }
);
}
}
+46
View File
@@ -0,0 +1,46 @@
import { NextRequest, NextResponse } from 'next/server';
import { getTasksBySession, createTask } from '@/lib/db';
import type { TasksResponse, TaskResponse, ErrorResponse, CreateTaskRequest } from '@/types';
export async function GET(request: NextRequest) {
const { searchParams } = request.nextUrl;
const sessionId = searchParams.get('session_id');
if (!sessionId) {
return NextResponse.json<ErrorResponse>(
{ error: 'Missing session_id parameter' },
{ status: 400 }
);
}
try {
const tasks = getTasksBySession(sessionId);
return NextResponse.json<TasksResponse>({ tasks });
} catch (error) {
return NextResponse.json<ErrorResponse>(
{ error: error instanceof Error ? error.message : 'Failed to get tasks' },
{ status: 500 }
);
}
}
export async function POST(request: NextRequest) {
try {
const body: CreateTaskRequest = await request.json();
if (!body.session_id || !body.title) {
return NextResponse.json<ErrorResponse>(
{ error: 'Missing session_id or title' },
{ status: 400 }
);
}
const task = createTask(body.session_id, body.title, body.description);
return NextResponse.json<TaskResponse>({ task }, { status: 201 });
} catch (error) {
return NextResponse.json<ErrorResponse>(
{ error: error instanceof Error ? error.message : 'Failed to create task' },
{ status: 500 }
);
}
}