aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/ipc/handlers.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/ipc/handlers.ts')
-rw-r--r--src/main/ipc/handlers.ts117
1 files changed, 117 insertions, 0 deletions
diff --git a/src/main/ipc/handlers.ts b/src/main/ipc/handlers.ts
new file mode 100644
index 0000000..ce95f4c
--- /dev/null
+++ b/src/main/ipc/handlers.ts
@@ -0,0 +1,117 @@
1import { ipcMain, dialog, type BrowserWindow } from "electron";
2import * as projects from "../db/projects";
3import * as sessions from "../db/sessions";
4import * as claude from "../claude";
5import type { UserPermissionMode } from "../claude/phases";
6
7export function registerIpcHandlers(mainWindow: BrowserWindow): void {
8 // Projects
9 ipcMain.handle("projects:list", () => projects.listProjects());
10 ipcMain.handle("projects:create", (_, name: string, path: string) =>
11 projects.createProject(name, path)
12 );
13 ipcMain.handle("projects:delete", (_, id: string) =>
14 projects.deleteProject(id)
15 );
16
17 // Sessions
18 ipcMain.handle("sessions:list", (_, projectId: string) =>
19 sessions.listSessions(projectId)
20 );
21 ipcMain.handle("sessions:create", (_, projectId: string, name: string) =>
22 sessions.createSession(projectId, name)
23 );
24 ipcMain.handle("sessions:delete", (_, id: string) =>
25 sessions.deleteSession(id)
26 );
27 ipcMain.handle("sessions:get", (_, id: string) => sessions.getSession(id));
28
29 // Messages
30 ipcMain.handle("messages:list", (_, sessionId: string) =>
31 sessions.listMessages(sessionId)
32 );
33
34 // Chat
35 ipcMain.handle(
36 "chat:send",
37 async (_, sessionId: string, message: string) => {
38 const session = sessions.getSession(sessionId);
39 if (!session) throw new Error("Session not found");
40
41 // Store user message
42 sessions.addMessage(sessionId, "user", message);
43
44 await claude.sendMessage({
45 session,
46 message,
47 onMessage: (msg) => {
48 // Forward all messages to renderer
49 mainWindow.webContents.send("claude:message", sessionId, msg);
50
51 // Store assistant text messages
52 if (msg.type === "assistant") {
53 const content = (msg.message.content as Array<{ type: string; text?: string }>)
54 .filter((c) => c.type === "text" && c.text)
55 .map((c) => c.text!)
56 .join("\n");
57 if (content) {
58 sessions.addMessage(sessionId, "assistant", content);
59 }
60 }
61 },
62 });
63 }
64 );
65
66 ipcMain.handle("chat:interrupt", (_, sessionId: string) => {
67 claude.interruptSession(sessionId);
68 });
69
70 // Workflow
71 ipcMain.handle("workflow:review", async (_, sessionId: string) => {
72 const session = sessions.getSession(sessionId);
73 if (!session) throw new Error("Session not found");
74
75 await claude.triggerReview(session, (msg) => {
76 mainWindow.webContents.send("claude:message", sessionId, msg);
77 });
78 });
79
80 ipcMain.handle("workflow:advance", (_, sessionId: string) => {
81 const session = sessions.getSession(sessionId);
82 if (!session) throw new Error("Session not found");
83 return claude.advancePhase(session);
84 });
85
86 ipcMain.handle(
87 "workflow:setPermissionMode",
88 (_, sessionId: string, mode: string) => {
89 sessions.updateSession(sessionId, {
90 permission_mode: mode as UserPermissionMode,
91 });
92 }
93 );
94
95 // Artifacts
96 ipcMain.handle(
97 "artifact:read",
98 (_, projectPath: string, filename: string) => {
99 return claude.readArtifact(projectPath, filename);
100 }
101 );
102
103 ipcMain.handle(
104 "artifact:write",
105 (_, projectPath: string, filename: string, content: string) => {
106 claude.writeArtifact(projectPath, filename, content);
107 }
108 );
109
110 // Dialogs
111 ipcMain.handle("dialog:selectDirectory", async () => {
112 const result = await dialog.showOpenDialog(mainWindow, {
113 properties: ["openDirectory"],
114 });
115 return result.canceled ? null : result.filePaths[0];
116 });
117}