import { ipcMain, dialog, type BrowserWindow } from "electron"; import * as projects from "../db/projects"; import * as sessions from "../db/sessions"; import * as claude from "../claude"; import type { UserPermissionMode } from "../claude/phases"; export function registerIpcHandlers(mainWindow: BrowserWindow): void { // Projects ipcMain.handle("projects:list", () => projects.listProjects()); ipcMain.handle("projects:create", (_, name: string, path: string) => projects.createProject(name, path) ); ipcMain.handle("projects:delete", (_, id: string) => projects.deleteProject(id) ); // Sessions ipcMain.handle("sessions:list", (_, projectId: string) => sessions.listSessions(projectId) ); ipcMain.handle("sessions:create", (_, projectId: string, name: string) => sessions.createSession(projectId, name) ); ipcMain.handle("sessions:delete", (_, id: string) => sessions.deleteSession(id) ); ipcMain.handle("sessions:get", (_, id: string) => sessions.getSession(id)); // Messages ipcMain.handle("messages:list", (_, sessionId: string) => sessions.listMessages(sessionId) ); // Chat ipcMain.handle( "chat:send", async (_, sessionId: string, message: string) => { const session = sessions.getSession(sessionId); if (!session) throw new Error("Session not found"); // Store user message sessions.addMessage(sessionId, "user", message); await claude.sendMessage({ session, message, onMessage: (msg) => { // Forward all messages to renderer mainWindow.webContents.send("claude:message", sessionId, msg); // Store assistant text messages if (msg.type === "assistant") { const content = (msg.message.content as Array<{ type: string; text?: string }>) .filter((c) => c.type === "text" && c.text) .map((c) => c.text!) .join("\n"); if (content) { sessions.addMessage(sessionId, "assistant", content); } } }, }); } ); ipcMain.handle("chat:interrupt", (_, sessionId: string) => { claude.interruptSession(sessionId); }); // Workflow ipcMain.handle("workflow:review", async (_, sessionId: string) => { const session = sessions.getSession(sessionId); if (!session) throw new Error("Session not found"); await claude.triggerReview(session, (msg) => { mainWindow.webContents.send("claude:message", sessionId, msg); }); }); ipcMain.handle("workflow:advance", (_, sessionId: string) => { const session = sessions.getSession(sessionId); if (!session) throw new Error("Session not found"); return claude.advancePhase(session); }); ipcMain.handle( "workflow:setPermissionMode", (_, sessionId: string, mode: string) => { sessions.updateSession(sessionId, { permission_mode: mode as UserPermissionMode, }); } ); // Artifacts ipcMain.handle( "artifact:read", (_, projectPath: string, filename: string) => { return claude.readArtifact(projectPath, filename); } ); ipcMain.handle( "artifact:write", (_, projectPath: string, filename: string, content: string) => { claude.writeArtifact(projectPath, filename, content); } ); // Dialogs ipcMain.handle("dialog:selectDirectory", async () => { const result = await dialog.showOpenDialog(mainWindow, { properties: ["openDirectory"], }); return result.canceled ? null : result.filePaths[0]; }); }