aboutsummaryrefslogtreecommitdiffstats
path: root/dist/main
diff options
context:
space:
mode:
Diffstat (limited to 'dist/main')
-rw-r--r--dist/main/claude/index.js109
-rw-r--r--dist/main/claude/phases.js147
-rw-r--r--dist/main/db/index.js33
-rw-r--r--dist/main/db/projects.js28
-rw-r--r--dist/main/db/schema.js36
-rw-r--r--dist/main/db/sessions.js72
-rw-r--r--dist/main/index.js54
-rw-r--r--dist/main/index.sync-conflict-20260228-074140-M6474AW.js54
-rw-r--r--dist/main/ipc/handlers.js116
-rw-r--r--dist/main/preload.js38
-rw-r--r--dist/main/preload.sync-conflict-20260228-074140-M6474AW.js38
11 files changed, 725 insertions, 0 deletions
diff --git a/dist/main/claude/index.js b/dist/main/claude/index.js
new file mode 100644
index 0000000..42a9652
--- /dev/null
+++ b/dist/main/claude/index.js
@@ -0,0 +1,109 @@
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6exports.sendMessage = sendMessage;
7exports.interruptSession = interruptSession;
8exports.triggerReview = triggerReview;
9exports.advancePhase = advancePhase;
10exports.readArtifact = readArtifact;
11exports.writeArtifact = writeArtifact;
12exports.getPhaseInitialMessage = getPhaseInitialMessage;
13const claude_agent_sdk_1 = require("@anthropic-ai/claude-agent-sdk");
14const phases_1 = require("./phases");
15const projects_1 = require("../db/projects");
16const sessions_1 = require("../db/sessions");
17const node_fs_1 = __importDefault(require("node:fs"));
18const node_path_1 = __importDefault(require("node:path"));
19// Track active queries by session ID
20const activeQueries = new Map();
21function ensureArtifactDir(projectPath) {
22 const dir = node_path_1.default.join(projectPath, ".claude-flow");
23 if (!node_fs_1.default.existsSync(dir)) {
24 node_fs_1.default.mkdirSync(dir, { recursive: true });
25 }
26}
27async function sendMessage({ session, message, onMessage, }) {
28 const project = (0, projects_1.getProject)(session.project_id);
29 if (!project)
30 throw new Error("Project not found");
31 ensureArtifactDir(project.path);
32 const phaseConfig = (0, phases_1.getPhaseConfig)(session.phase, session.permission_mode);
33 const q = (0, claude_agent_sdk_1.query)({
34 prompt: message,
35 options: {
36 cwd: project.path,
37 resume: session.claude_session_id ?? undefined,
38 tools: phaseConfig.tools,
39 permissionMode: phaseConfig.permissionMode,
40 systemPrompt: phaseConfig.systemPrompt,
41 },
42 });
43 activeQueries.set(session.id, q);
44 try {
45 for await (const msg of q) {
46 // Capture session ID from init message
47 if (msg.type === "system" && msg.subtype === "init") {
48 if (!session.claude_session_id) {
49 (0, sessions_1.updateSession)(session.id, { claude_session_id: msg.session_id });
50 }
51 }
52 onMessage(msg);
53 }
54 }
55 finally {
56 activeQueries.delete(session.id);
57 }
58}
59function interruptSession(sessionId) {
60 const q = activeQueries.get(sessionId);
61 if (q) {
62 q.close();
63 activeQueries.delete(sessionId);
64 }
65}
66/**
67 * Trigger a review: Claude reads the document and addresses user annotations
68 */
69async function triggerReview(session, onMessage) {
70 const docName = (0, phases_1.getArtifactFilename)(session.phase);
71 const message = `I've updated .claude-flow/${docName} with annotations. Read the file, find all my inline notes (marked with // REVIEW:, // NOTE:, TODO:, or similar), address each one, and update the document accordingly. Do not implement anything yet.`;
72 await sendMessage({ session, message, onMessage });
73}
74/**
75 * Advance to the next phase
76 */
77function advancePhase(session) {
78 const nextPhase = (0, phases_1.getNextPhase)(session.phase);
79 if (nextPhase) {
80 (0, sessions_1.updateSession)(session.id, { phase: nextPhase });
81 }
82 return nextPhase;
83}
84/**
85 * Read an artifact file from the project's .claude-flow directory
86 */
87function readArtifact(projectPath, filename) {
88 const filePath = node_path_1.default.join(projectPath, ".claude-flow", filename);
89 if (node_fs_1.default.existsSync(filePath)) {
90 return node_fs_1.default.readFileSync(filePath, "utf-8");
91 }
92 return null;
93}
94/**
95 * Write an artifact file to the project's .claude-flow directory
96 */
97function writeArtifact(projectPath, filename, content) {
98 const dir = node_path_1.default.join(projectPath, ".claude-flow");
99 if (!node_fs_1.default.existsSync(dir)) {
100 node_fs_1.default.mkdirSync(dir, { recursive: true });
101 }
102 node_fs_1.default.writeFileSync(node_path_1.default.join(dir, filename), content, "utf-8");
103}
104/**
105 * Get the initial message for a phase
106 */
107function getPhaseInitialMessage(phase) {
108 return (0, phases_1.getPhaseConfig)(phase).initialMessage;
109}
diff --git a/dist/main/claude/phases.js b/dist/main/claude/phases.js
new file mode 100644
index 0000000..65ea46d
--- /dev/null
+++ b/dist/main/claude/phases.js
@@ -0,0 +1,147 @@
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.phaseConfigs = void 0;
4exports.getPhaseConfig = getPhaseConfig;
5exports.getNextPhase = getNextPhase;
6exports.getArtifactFilename = getArtifactFilename;
7exports.phaseConfigs = {
8 research: {
9 permissionMode: "acceptEdits",
10 tools: ["Read", "Glob", "Grep", "Bash", "Write"],
11 initialMessage: "What areas of the codebase should I research? What are you trying to build?",
12 systemPrompt: `You are in RESEARCH mode. Your ONLY job is to understand the codebase.
13
14CRITICAL RULES:
151. You MUST write ALL findings to .claude-flow/research.md — this is your PRIMARY output
162. DO NOT just respond in chat. The document viewer shows research.md, so write there.
173. DO NOT suggest moving to planning or implementation
184. DO NOT ask "are you ready to implement?" or similar
195. DO NOT modify any source code files
206. The user controls phase transitions via UI buttons — never prompt them about it
21
22WORKFLOW:
231. Ask what to research (if unclear)
242. Read files thoroughly using Read, Glob, Grep
253. Write structured findings to .claude-flow/research.md
264. Keep updating research.md as you learn more
27
28FORMAT for research.md:
29\`\`\`markdown
30# Research Findings
31
32## Overview
33[High-level summary of what you found]
34
35## Architecture
36[Key components, patterns, structure]
37
38## Relevant Files
39[List of important files with descriptions]
40
41## Key Insights
42[Important discoveries, patterns, potential issues]
43
44## Questions/Unknowns
45[Things that need clarification]
46\`\`\`
47
48When the user adds annotations (// REVIEW:, // NOTE:, TODO:) to research.md and clicks Review, address each annotation and update the document.
49
50Remember: Your output goes in research.md, not chat. Chat is for clarifying questions only.`,
51 },
52 plan: {
53 permissionMode: "acceptEdits",
54 tools: ["Read", "Glob", "Grep", "Write"],
55 initialMessage: "I'll create a detailed implementation plan based on my research. Writing to plan.md...",
56 systemPrompt: `You are in PLANNING mode. Your ONLY job is to create an implementation plan.
57
58CRITICAL RULES:
591. You MUST write the plan to .claude-flow/plan.md — this is your PRIMARY output
602. DO NOT just respond in chat. The document viewer shows plan.md, so write there.
613. DO NOT implement anything — no code changes to source files
624. DO NOT ask "should I start implementing?" or similar
635. The user controls phase transitions via UI buttons — never prompt them about it
646. Base your plan on .claude-flow/research.md
65
66WORKFLOW:
671. Read .claude-flow/research.md to understand the codebase
682. Write a detailed plan to .claude-flow/plan.md
693. Include specific code snippets showing proposed changes
704. Make the plan detailed enough that implementation is mechanical
71
72FORMAT for plan.md:
73\`\`\`markdown
74# Implementation Plan
75
76## Goal
77[What we're building/changing]
78
79## Approach
80[High-level strategy]
81
82## Changes
83
84### 1. [First change]
85**File:** path/to/file.ts
86**What:** [Description]
87**Code:**
88\\\`\\\`\\\`typescript
89// Proposed code
90\\\`\\\`\\\`
91
92### 2. [Second change]
93...
94
95## TODO
96- [ ] Task 1
97- [ ] Task 2
98- [ ] Task 3
99
100## Risks/Considerations
101[Potential issues, edge cases]
102\`\`\`
103
104When the user adds annotations to plan.md and clicks Review, address each annotation and update the document.
105
106Remember: Your output goes in plan.md, not chat. Chat is for clarifying questions only.`,
107 },
108 implement: {
109 permissionMode: "acceptEdits",
110 tools: ["Read", "Write", "Edit", "Bash", "Glob", "Grep"],
111 initialMessage: "Starting implementation. I'll follow the plan exactly and mark tasks complete as I go.",
112 systemPrompt: `You are in IMPLEMENTATION mode. Execute the approved plan.
113
114CRITICAL RULES:
1151. Read .claude-flow/plan.md and follow it exactly
1162. Mark tasks complete in plan.md as you finish them: - [ ] → - [x]
1173. DO NOT deviate from the plan without asking
1184. Run tests/typecheck if available
1195. Stop and ask if you encounter issues not covered by the plan
120
121WORKFLOW:
1221. Read .claude-flow/plan.md
1232. Execute each task in order
1243. Update plan.md to mark tasks complete
1254. Continue until all tasks are done
126
127If something in the plan is unclear or problematic, ask before proceeding.`,
128 },
129};
130function getPhaseConfig(phase, userPermissionMode) {
131 const config = { ...exports.phaseConfigs[phase] };
132 if (phase === "implement" && userPermissionMode) {
133 config.permissionMode = userPermissionMode;
134 }
135 return config;
136}
137function getNextPhase(phase) {
138 const transitions = {
139 research: "plan",
140 plan: "implement",
141 implement: null,
142 };
143 return transitions[phase];
144}
145function getArtifactFilename(phase) {
146 return phase === "research" ? "research.md" : "plan.md";
147}
diff --git a/dist/main/db/index.js b/dist/main/db/index.js
new file mode 100644
index 0000000..652d189
--- /dev/null
+++ b/dist/main/db/index.js
@@ -0,0 +1,33 @@
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6exports.getDb = getDb;
7exports.closeDb = closeDb;
8const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
9const electron_1 = require("electron");
10const node_path_1 = __importDefault(require("node:path"));
11const node_fs_1 = __importDefault(require("node:fs"));
12const schema_1 = require("./schema");
13let db = null;
14function getDb() {
15 if (db)
16 return db;
17 const dbDir = electron_1.app.getPath("userData");
18 if (!node_fs_1.default.existsSync(dbDir)) {
19 node_fs_1.default.mkdirSync(dbDir, { recursive: true });
20 }
21 const dbPath = node_path_1.default.join(dbDir, "claude-flow.db");
22 db = new better_sqlite3_1.default(dbPath);
23 db.pragma("journal_mode = WAL");
24 db.pragma("foreign_keys = ON");
25 (0, schema_1.initSchema)(db);
26 return db;
27}
28function closeDb() {
29 if (db) {
30 db.close();
31 db = null;
32 }
33}
diff --git a/dist/main/db/projects.js b/dist/main/db/projects.js
new file mode 100644
index 0000000..af36cc0
--- /dev/null
+++ b/dist/main/db/projects.js
@@ -0,0 +1,28 @@
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.listProjects = listProjects;
4exports.getProject = getProject;
5exports.createProject = createProject;
6exports.deleteProject = deleteProject;
7const index_1 = require("./index");
8const uuid_1 = require("uuid");
9function listProjects() {
10 return (0, index_1.getDb)()
11 .prepare("SELECT * FROM projects ORDER BY updated_at DESC")
12 .all();
13}
14function getProject(id) {
15 return (0, index_1.getDb)()
16 .prepare("SELECT * FROM projects WHERE id = ?")
17 .get(id);
18}
19function createProject(name, projectPath) {
20 const db = (0, index_1.getDb)();
21 const id = (0, uuid_1.v4)();
22 const now = Math.floor(Date.now() / 1000);
23 db.prepare("INSERT INTO projects (id, name, path, created_at, updated_at) VALUES (?, ?, ?, ?, ?)").run(id, name, projectPath, now, now);
24 return { id, name, path: projectPath, created_at: now, updated_at: now };
25}
26function deleteProject(id) {
27 (0, index_1.getDb)().prepare("DELETE FROM projects WHERE id = ?").run(id);
28}
diff --git a/dist/main/db/schema.js b/dist/main/db/schema.js
new file mode 100644
index 0000000..974e593
--- /dev/null
+++ b/dist/main/db/schema.js
@@ -0,0 +1,36 @@
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.initSchema = initSchema;
4function initSchema(db) {
5 db.exec(`
6 CREATE TABLE IF NOT EXISTS projects (
7 id TEXT PRIMARY KEY,
8 name TEXT NOT NULL,
9 path TEXT NOT NULL,
10 created_at INTEGER NOT NULL DEFAULT (unixepoch()),
11 updated_at INTEGER NOT NULL DEFAULT (unixepoch())
12 );
13
14 CREATE TABLE IF NOT EXISTS sessions (
15 id TEXT PRIMARY KEY,
16 project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
17 name TEXT NOT NULL,
18 phase TEXT NOT NULL DEFAULT 'research',
19 claude_session_id TEXT,
20 permission_mode TEXT NOT NULL DEFAULT 'acceptEdits',
21 created_at INTEGER NOT NULL DEFAULT (unixepoch()),
22 updated_at INTEGER NOT NULL DEFAULT (unixepoch())
23 );
24
25 CREATE TABLE IF NOT EXISTS messages (
26 id TEXT PRIMARY KEY,
27 session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
28 role TEXT NOT NULL,
29 content TEXT NOT NULL,
30 created_at INTEGER NOT NULL DEFAULT (unixepoch())
31 );
32
33 CREATE INDEX IF NOT EXISTS idx_sessions_project ON sessions(project_id);
34 CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id);
35 `);
36}
diff --git a/dist/main/db/sessions.js b/dist/main/db/sessions.js
new file mode 100644
index 0000000..b554898
--- /dev/null
+++ b/dist/main/db/sessions.js
@@ -0,0 +1,72 @@
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.listSessions = listSessions;
4exports.getSession = getSession;
5exports.createSession = createSession;
6exports.updateSession = updateSession;
7exports.deleteSession = deleteSession;
8exports.listMessages = listMessages;
9exports.addMessage = addMessage;
10const index_1 = require("./index");
11const uuid_1 = require("uuid");
12function listSessions(projectId) {
13 return (0, index_1.getDb)()
14 .prepare("SELECT * FROM sessions WHERE project_id = ? ORDER BY updated_at DESC")
15 .all(projectId);
16}
17function getSession(id) {
18 return (0, index_1.getDb)()
19 .prepare("SELECT * FROM sessions WHERE id = ?")
20 .get(id);
21}
22function createSession(projectId, name) {
23 const db = (0, index_1.getDb)();
24 const id = (0, uuid_1.v4)();
25 const now = Math.floor(Date.now() / 1000);
26 db.prepare(`INSERT INTO sessions (id, project_id, name, phase, permission_mode, created_at, updated_at)
27 VALUES (?, ?, ?, 'research', 'acceptEdits', ?, ?)`).run(id, projectId, name, now, now);
28 return {
29 id,
30 project_id: projectId,
31 name,
32 phase: "research",
33 claude_session_id: null,
34 permission_mode: "acceptEdits",
35 created_at: now,
36 updated_at: now,
37 };
38}
39function updateSession(id, updates) {
40 const db = (0, index_1.getDb)();
41 const sets = [];
42 const values = [];
43 for (const [key, value] of Object.entries(updates)) {
44 if (value !== undefined) {
45 sets.push(`${key} = ?`);
46 values.push(value);
47 }
48 }
49 if (sets.length > 0) {
50 sets.push("updated_at = ?");
51 values.push(Math.floor(Date.now() / 1000));
52 values.push(id);
53 db.prepare(`UPDATE sessions SET ${sets.join(", ")} WHERE id = ?`).run(...values);
54 }
55}
56function deleteSession(id) {
57 (0, index_1.getDb)().prepare("DELETE FROM sessions WHERE id = ?").run(id);
58}
59// Messages
60function listMessages(sessionId) {
61 return (0, index_1.getDb)()
62 .prepare("SELECT * FROM messages WHERE session_id = ? ORDER BY created_at ASC")
63 .all(sessionId);
64}
65function addMessage(sessionId, role, content) {
66 const db = (0, index_1.getDb)();
67 const id = (0, uuid_1.v4)();
68 const now = Math.floor(Date.now() / 1000);
69 db.prepare("INSERT INTO messages (id, session_id, role, content, created_at) VALUES (?, ?, ?, ?, ?)").run(id, sessionId, role, content, now);
70 db.prepare("UPDATE sessions SET updated_at = ? WHERE id = ?").run(now, sessionId);
71 return { id, session_id: sessionId, role, content, created_at: now };
72}
diff --git a/dist/main/index.js b/dist/main/index.js
new file mode 100644
index 0000000..a10a371
--- /dev/null
+++ b/dist/main/index.js
@@ -0,0 +1,54 @@
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6const electron_1 = require("electron");
7const node_path_1 = __importDefault(require("node:path"));
8const db_1 = require("./db");
9const handlers_1 = require("./ipc/handlers");
10const isDev = !electron_1.app.isPackaged;
11let mainWindow = null;
12function createWindow() {
13 mainWindow = new electron_1.BrowserWindow({
14 width: 1400,
15 height: 900,
16 minWidth: 1000,
17 minHeight: 600,
18 show: false,
19 titleBarStyle: "hiddenInset",
20 webPreferences: {
21 contextIsolation: true,
22 nodeIntegration: false,
23 preload: node_path_1.default.join(__dirname, "preload.js"),
24 },
25 });
26 (0, handlers_1.registerIpcHandlers)(mainWindow);
27 if (isDev) {
28 const url = process.env.VITE_DEV_SERVER_URL ?? "http://localhost:5173";
29 mainWindow.loadURL(url).finally(() => {
30 mainWindow.show();
31 mainWindow.webContents.openDevTools({ mode: "detach" });
32 });
33 }
34 else {
35 const indexHtml = node_path_1.default.join(electron_1.app.getAppPath(), "renderer", "dist", "index.html");
36 mainWindow.loadFile(indexHtml).finally(() => mainWindow.show());
37 }
38}
39electron_1.app.whenReady().then(() => {
40 // Initialize database
41 (0, db_1.getDb)();
42 createWindow();
43 electron_1.app.on("activate", () => {
44 if (electron_1.BrowserWindow.getAllWindows().length === 0) {
45 createWindow();
46 }
47 });
48});
49electron_1.app.on("window-all-closed", () => {
50 (0, db_1.closeDb)();
51 if (process.platform !== "darwin") {
52 electron_1.app.quit();
53 }
54});
diff --git a/dist/main/index.sync-conflict-20260228-074140-M6474AW.js b/dist/main/index.sync-conflict-20260228-074140-M6474AW.js
new file mode 100644
index 0000000..a10a371
--- /dev/null
+++ b/dist/main/index.sync-conflict-20260228-074140-M6474AW.js
@@ -0,0 +1,54 @@
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6const electron_1 = require("electron");
7const node_path_1 = __importDefault(require("node:path"));
8const db_1 = require("./db");
9const handlers_1 = require("./ipc/handlers");
10const isDev = !electron_1.app.isPackaged;
11let mainWindow = null;
12function createWindow() {
13 mainWindow = new electron_1.BrowserWindow({
14 width: 1400,
15 height: 900,
16 minWidth: 1000,
17 minHeight: 600,
18 show: false,
19 titleBarStyle: "hiddenInset",
20 webPreferences: {
21 contextIsolation: true,
22 nodeIntegration: false,
23 preload: node_path_1.default.join(__dirname, "preload.js"),
24 },
25 });
26 (0, handlers_1.registerIpcHandlers)(mainWindow);
27 if (isDev) {
28 const url = process.env.VITE_DEV_SERVER_URL ?? "http://localhost:5173";
29 mainWindow.loadURL(url).finally(() => {
30 mainWindow.show();
31 mainWindow.webContents.openDevTools({ mode: "detach" });
32 });
33 }
34 else {
35 const indexHtml = node_path_1.default.join(electron_1.app.getAppPath(), "renderer", "dist", "index.html");
36 mainWindow.loadFile(indexHtml).finally(() => mainWindow.show());
37 }
38}
39electron_1.app.whenReady().then(() => {
40 // Initialize database
41 (0, db_1.getDb)();
42 createWindow();
43 electron_1.app.on("activate", () => {
44 if (electron_1.BrowserWindow.getAllWindows().length === 0) {
45 createWindow();
46 }
47 });
48});
49electron_1.app.on("window-all-closed", () => {
50 (0, db_1.closeDb)();
51 if (process.platform !== "darwin") {
52 electron_1.app.quit();
53 }
54});
diff --git a/dist/main/ipc/handlers.js b/dist/main/ipc/handlers.js
new file mode 100644
index 0000000..c452cee
--- /dev/null
+++ b/dist/main/ipc/handlers.js
@@ -0,0 +1,116 @@
1"use strict";
2var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 if (k2 === undefined) k2 = k;
4 var desc = Object.getOwnPropertyDescriptor(m, k);
5 if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6 desc = { enumerable: true, get: function() { return m[k]; } };
7 }
8 Object.defineProperty(o, k2, desc);
9}) : (function(o, m, k, k2) {
10 if (k2 === undefined) k2 = k;
11 o[k2] = m[k];
12}));
13var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14 Object.defineProperty(o, "default", { enumerable: true, value: v });
15}) : function(o, v) {
16 o["default"] = v;
17});
18var __importStar = (this && this.__importStar) || (function () {
19 var ownKeys = function(o) {
20 ownKeys = Object.getOwnPropertyNames || function (o) {
21 var ar = [];
22 for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23 return ar;
24 };
25 return ownKeys(o);
26 };
27 return function (mod) {
28 if (mod && mod.__esModule) return mod;
29 var result = {};
30 if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31 __setModuleDefault(result, mod);
32 return result;
33 };
34})();
35Object.defineProperty(exports, "__esModule", { value: true });
36exports.registerIpcHandlers = registerIpcHandlers;
37const electron_1 = require("electron");
38const projects = __importStar(require("../db/projects"));
39const sessions = __importStar(require("../db/sessions"));
40const claude = __importStar(require("../claude"));
41function registerIpcHandlers(mainWindow) {
42 // Projects
43 electron_1.ipcMain.handle("projects:list", () => projects.listProjects());
44 electron_1.ipcMain.handle("projects:create", (_, name, path) => projects.createProject(name, path));
45 electron_1.ipcMain.handle("projects:delete", (_, id) => projects.deleteProject(id));
46 // Sessions
47 electron_1.ipcMain.handle("sessions:list", (_, projectId) => sessions.listSessions(projectId));
48 electron_1.ipcMain.handle("sessions:create", (_, projectId, name) => sessions.createSession(projectId, name));
49 electron_1.ipcMain.handle("sessions:delete", (_, id) => sessions.deleteSession(id));
50 electron_1.ipcMain.handle("sessions:get", (_, id) => sessions.getSession(id));
51 // Messages
52 electron_1.ipcMain.handle("messages:list", (_, sessionId) => sessions.listMessages(sessionId));
53 // Chat
54 electron_1.ipcMain.handle("chat:send", async (_, sessionId, message) => {
55 const session = sessions.getSession(sessionId);
56 if (!session)
57 throw new Error("Session not found");
58 // Store user message
59 sessions.addMessage(sessionId, "user", message);
60 await claude.sendMessage({
61 session,
62 message,
63 onMessage: (msg) => {
64 // Forward all messages to renderer
65 mainWindow.webContents.send("claude:message", sessionId, msg);
66 // Store assistant text messages
67 if (msg.type === "assistant") {
68 const content = msg.message.content
69 .filter((c) => c.type === "text" && c.text)
70 .map((c) => c.text)
71 .join("\n");
72 if (content) {
73 sessions.addMessage(sessionId, "assistant", content);
74 }
75 }
76 },
77 });
78 });
79 electron_1.ipcMain.handle("chat:interrupt", (_, sessionId) => {
80 claude.interruptSession(sessionId);
81 });
82 // Workflow
83 electron_1.ipcMain.handle("workflow:review", async (_, sessionId) => {
84 const session = sessions.getSession(sessionId);
85 if (!session)
86 throw new Error("Session not found");
87 await claude.triggerReview(session, (msg) => {
88 mainWindow.webContents.send("claude:message", sessionId, msg);
89 });
90 });
91 electron_1.ipcMain.handle("workflow:advance", (_, sessionId) => {
92 const session = sessions.getSession(sessionId);
93 if (!session)
94 throw new Error("Session not found");
95 return claude.advancePhase(session);
96 });
97 electron_1.ipcMain.handle("workflow:setPermissionMode", (_, sessionId, mode) => {
98 sessions.updateSession(sessionId, {
99 permission_mode: mode,
100 });
101 });
102 // Artifacts
103 electron_1.ipcMain.handle("artifact:read", (_, projectPath, filename) => {
104 return claude.readArtifact(projectPath, filename);
105 });
106 electron_1.ipcMain.handle("artifact:write", (_, projectPath, filename, content) => {
107 claude.writeArtifact(projectPath, filename, content);
108 });
109 // Dialogs
110 electron_1.ipcMain.handle("dialog:selectDirectory", async () => {
111 const result = await electron_1.dialog.showOpenDialog(mainWindow, {
112 properties: ["openDirectory"],
113 });
114 return result.canceled ? null : result.filePaths[0];
115 });
116}
diff --git a/dist/main/preload.js b/dist/main/preload.js
new file mode 100644
index 0000000..7978b53
--- /dev/null
+++ b/dist/main/preload.js
@@ -0,0 +1,38 @@
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const electron_1 = require("electron");
4const api = {
5 // Projects
6 listProjects: () => electron_1.ipcRenderer.invoke("projects:list"),
7 createProject: (name, path) => electron_1.ipcRenderer.invoke("projects:create", name, path),
8 deleteProject: (id) => electron_1.ipcRenderer.invoke("projects:delete", id),
9 // Sessions
10 listSessions: (projectId) => electron_1.ipcRenderer.invoke("sessions:list", projectId),
11 createSession: (projectId, name) => electron_1.ipcRenderer.invoke("sessions:create", projectId, name),
12 deleteSession: (id) => electron_1.ipcRenderer.invoke("sessions:delete", id),
13 getSession: (id) => electron_1.ipcRenderer.invoke("sessions:get", id),
14 // Messages
15 listMessages: (sessionId) => electron_1.ipcRenderer.invoke("messages:list", sessionId),
16 // Chat
17 sendMessage: (sessionId, message) => electron_1.ipcRenderer.invoke("chat:send", sessionId, message),
18 interruptSession: (sessionId) => electron_1.ipcRenderer.invoke("chat:interrupt", sessionId),
19 // Workflow
20 triggerReview: (sessionId) => electron_1.ipcRenderer.invoke("workflow:review", sessionId),
21 advancePhase: (sessionId) => electron_1.ipcRenderer.invoke("workflow:advance", sessionId),
22 setPermissionMode: (sessionId, mode) => electron_1.ipcRenderer.invoke("workflow:setPermissionMode", sessionId, mode),
23 // Artifacts
24 readArtifact: (projectPath, filename) => electron_1.ipcRenderer.invoke("artifact:read", projectPath, filename),
25 writeArtifact: (projectPath, filename, content) => electron_1.ipcRenderer.invoke("artifact:write", projectPath, filename, content),
26 // Events
27 onClaudeMessage: (callback) => {
28 const handler = (_, sessionId, message) => callback(sessionId, message);
29 electron_1.ipcRenderer.on("claude:message", handler);
30 return () => electron_1.ipcRenderer.removeListener("claude:message", handler);
31 },
32 // Dialogs
33 selectDirectory: async () => {
34 const result = await electron_1.ipcRenderer.invoke("dialog:selectDirectory");
35 return result;
36 },
37};
38electron_1.contextBridge.exposeInMainWorld("api", api);
diff --git a/dist/main/preload.sync-conflict-20260228-074140-M6474AW.js b/dist/main/preload.sync-conflict-20260228-074140-M6474AW.js
new file mode 100644
index 0000000..7978b53
--- /dev/null
+++ b/dist/main/preload.sync-conflict-20260228-074140-M6474AW.js
@@ -0,0 +1,38 @@
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const electron_1 = require("electron");
4const api = {
5 // Projects
6 listProjects: () => electron_1.ipcRenderer.invoke("projects:list"),
7 createProject: (name, path) => electron_1.ipcRenderer.invoke("projects:create", name, path),
8 deleteProject: (id) => electron_1.ipcRenderer.invoke("projects:delete", id),
9 // Sessions
10 listSessions: (projectId) => electron_1.ipcRenderer.invoke("sessions:list", projectId),
11 createSession: (projectId, name) => electron_1.ipcRenderer.invoke("sessions:create", projectId, name),
12 deleteSession: (id) => electron_1.ipcRenderer.invoke("sessions:delete", id),
13 getSession: (id) => electron_1.ipcRenderer.invoke("sessions:get", id),
14 // Messages
15 listMessages: (sessionId) => electron_1.ipcRenderer.invoke("messages:list", sessionId),
16 // Chat
17 sendMessage: (sessionId, message) => electron_1.ipcRenderer.invoke("chat:send", sessionId, message),
18 interruptSession: (sessionId) => electron_1.ipcRenderer.invoke("chat:interrupt", sessionId),
19 // Workflow
20 triggerReview: (sessionId) => electron_1.ipcRenderer.invoke("workflow:review", sessionId),
21 advancePhase: (sessionId) => electron_1.ipcRenderer.invoke("workflow:advance", sessionId),
22 setPermissionMode: (sessionId, mode) => electron_1.ipcRenderer.invoke("workflow:setPermissionMode", sessionId, mode),
23 // Artifacts
24 readArtifact: (projectPath, filename) => electron_1.ipcRenderer.invoke("artifact:read", projectPath, filename),
25 writeArtifact: (projectPath, filename, content) => electron_1.ipcRenderer.invoke("artifact:write", projectPath, filename, content),
26 // Events
27 onClaudeMessage: (callback) => {
28 const handler = (_, sessionId, message) => callback(sessionId, message);
29 electron_1.ipcRenderer.on("claude:message", handler);
30 return () => electron_1.ipcRenderer.removeListener("claude:message", handler);
31 },
32 // Dialogs
33 selectDirectory: async () => {
34 const result = await electron_1.ipcRenderer.invoke("dialog:selectDirectory");
35 return result;
36 },
37};
38electron_1.contextBridge.exposeInMainWorld("api", api);