aboutsummaryrefslogtreecommitdiffstats
path: root/src/main
diff options
context:
space:
mode:
authorbndw <ben@bdw.to>2026-03-04 21:36:32 -0800
committerbndw <ben@bdw.to>2026-03-04 21:36:32 -0800
commit73d2680b83ccbdbd8dfec2d319533e98b379b830 (patch)
tree193eaf5157edcf12d06dde85fb44efaf3aae2004 /src/main
parentb6405dd6a4ba65fc5dc6746db7be7be7d0bb29f3 (diff)
feat: Thread optional `phase` param into `db/sessions.ts::cre… (+7 more)
- ✅ Thread optional `phase` param into `db/sessions.ts::createSession()` - ✅ Thread optional `phase` param into `ipc/handlers.ts` sessions:create handler - ✅ Thread optional `phase` param into `preload.ts` createSession API - ✅ Update Plan phase system prompt to gracefully handle missing research.md - ✅ Update Implement phase system prompt to gracefully handle missing plan.md - ✅ Create `renderer/src/components/NewSessionModal.tsx` - ✅ Update `App.tsx`: add modal state, split handler, add modal JSX - ✅ Add modal CSS to `globals.css`
Diffstat (limited to 'src/main')
-rw-r--r--src/main/claude/index.ts5
-rw-r--r--src/main/claude/phases.ts10
-rw-r--r--src/main/db/sessions.ts8
-rw-r--r--src/main/ipc/handlers.ts6
-rw-r--r--src/main/preload.ts6
5 files changed, 19 insertions, 16 deletions
diff --git a/src/main/claude/index.ts b/src/main/claude/index.ts
index 8cf512c..9139f17 100644
--- a/src/main/claude/index.ts
+++ b/src/main/claude/index.ts
@@ -48,8 +48,9 @@ export async function sendMessage({
48 // Load any custom system prompt for this phase (null → use default) 48 // Load any custom system prompt for this phase (null → use default)
49 const customSystemPrompt = getSetting(`systemPrompt.${session.phase}`) ?? undefined; 49 const customSystemPrompt = getSetting(`systemPrompt.${session.phase}`) ?? undefined;
50 50
51 // Load global model override (empty string or null → let SDK use its default) 51 // Phase-specific model override takes precedence; falls back to global default.
52 const configuredModel = getSetting("model") || undefined; 52 const configuredModel =
53 getSetting(`model.${session.phase}`) || getSetting("model") || undefined;
53 54
54 // Load MCP servers config (JSON string → object, or undefined if not set) 55 // Load MCP servers config (JSON string → object, or undefined if not set)
55 const mcpServersJson = getSetting("mcpServers"); 56 const mcpServersJson = getSetting("mcpServers");
diff --git a/src/main/claude/phases.ts b/src/main/claude/phases.ts
index a1cbba1..e8c16df 100644
--- a/src/main/claude/phases.ts
+++ b/src/main/claude/phases.ts
@@ -87,11 +87,12 @@ CRITICAL RULES:
87 87
88CONTEXT: 88CONTEXT:
89- Read CLAUDE.md at project root for codebase overview 89- Read CLAUDE.md at project root for codebase overview
90- Read ${artifactDir}/research.md to understand the specific task 90- Read ${artifactDir}/research.md to understand the specific task.
91 If research.md does not exist, this session began at the planning phase — base your plan on the task description provided in the chat instead.
91 92
92WORKFLOW: 93WORKFLOW:
931. Read CLAUDE.md for codebase overview 941. Read CLAUDE.md for codebase overview
942. Read ${artifactDir}/research.md to understand the specific task 952. Read ${artifactDir}/research.md if it exists; otherwise use the task description from chat
953. Write a detailed plan to ${artifactDir}/plan.md 963. Write a detailed plan to ${artifactDir}/plan.md
964. Include specific code snippets showing proposed changes 974. Include specific code snippets showing proposed changes
975. Make the plan detailed enough that implementation is mechanical 985. Make the plan detailed enough that implementation is mechanical
@@ -141,14 +142,15 @@ Remember: Your output goes in ${artifactDir}/plan.md, not chat. Chat is for clar
141 systemPrompt: (artifactDir) => `You are in IMPLEMENTATION mode. Execute the approved plan. 142 systemPrompt: (artifactDir) => `You are in IMPLEMENTATION mode. Execute the approved plan.
142 143
143CRITICAL RULES: 144CRITICAL RULES:
1441. Read ${artifactDir}/plan.md and follow it exactly 1451. Read ${artifactDir}/plan.md if it exists and follow it exactly.
146 If plan.md does not exist, this session began at the implementation phase — implement based on the task description provided in the chat messages.
1452. Mark tasks complete in ${artifactDir}/plan.md as you finish them: - [ ] → - [x] 1472. Mark tasks complete in ${artifactDir}/plan.md as you finish them: - [ ] → - [x]
1463. DO NOT deviate from the plan without asking 1483. DO NOT deviate from the plan without asking
1474. Run tests/typecheck if available 1494. Run tests/typecheck if available
1485. Stop and ask if you encounter issues not covered by the plan 1505. Stop and ask if you encounter issues not covered by the plan
149 151
150WORKFLOW: 152WORKFLOW:
1511. Read ${artifactDir}/plan.md 1531. Read ${artifactDir}/plan.md (if it exists)
1522. Execute each task in order 1542. Execute each task in order
1533. Update ${artifactDir}/plan.md to mark tasks complete 1553. Update ${artifactDir}/plan.md to mark tasks complete
1544. Continue until all tasks are done 1564. Continue until all tasks are done
diff --git a/src/main/db/sessions.ts b/src/main/db/sessions.ts
index 3e6352c..bc22d15 100644
--- a/src/main/db/sessions.ts
+++ b/src/main/db/sessions.ts
@@ -36,21 +36,21 @@ export function getSession(id: string): Session | undefined {
36 .get(id) as Session | undefined; 36 .get(id) as Session | undefined;
37} 37}
38 38
39export function createSession(projectId: string, name: string): Session { 39export function createSession(projectId: string, name: string, phase: Phase = "research"): Session {
40 const db = getDb(); 40 const db = getDb();
41 const id = uuid(); 41 const id = uuid();
42 const now = Math.floor(Date.now() / 1000); 42 const now = Math.floor(Date.now() / 1000);
43 43
44 db.prepare( 44 db.prepare(
45 `INSERT INTO sessions (id, project_id, name, phase, permission_mode, created_at, updated_at) 45 `INSERT INTO sessions (id, project_id, name, phase, permission_mode, created_at, updated_at)
46 VALUES (?, ?, ?, 'research', 'acceptEdits', ?, ?)` 46 VALUES (?, ?, ?, ?, 'acceptEdits', ?, ?)`
47 ).run(id, projectId, name, now, now); 47 ).run(id, projectId, name, phase, now, now);
48 48
49 return { 49 return {
50 id, 50 id,
51 project_id: projectId, 51 project_id: projectId,
52 name, 52 name,
53 phase: "research", 53 phase,
54 claude_session_id: null, 54 claude_session_id: null,
55 permission_mode: "acceptEdits", 55 permission_mode: "acceptEdits",
56 git_branch: null, 56 git_branch: null,
diff --git a/src/main/ipc/handlers.ts b/src/main/ipc/handlers.ts
index 4894e1d..975ad01 100644
--- a/src/main/ipc/handlers.ts
+++ b/src/main/ipc/handlers.ts
@@ -5,7 +5,7 @@ import * as claude from "../claude";
5import * as settingsDb from "../db/settings"; 5import * as settingsDb from "../db/settings";
6import { createSessionBranch, ensureGitIgnore, ensureGitRepo, getCurrentBranch } from "../git"; 6import { createSessionBranch, ensureGitIgnore, ensureGitRepo, getCurrentBranch } from "../git";
7import { discoverMcpTools } from "../mcp"; 7import { discoverMcpTools } from "../mcp";
8import type { UserPermissionMode } from "../claude/phases"; 8import type { UserPermissionMode, Phase } from "../claude/phases";
9import { getDefaultSystemPromptTemplate } from "../claude/phases"; 9import { getDefaultSystemPromptTemplate } from "../claude/phases";
10 10
11export function registerIpcHandlers(mainWindow: BrowserWindow): void { 11export function registerIpcHandlers(mainWindow: BrowserWindow): void {
@@ -23,11 +23,11 @@ export function registerIpcHandlers(mainWindow: BrowserWindow): void {
23 sessions.listSessions(projectId) 23 sessions.listSessions(projectId)
24 ); 24 );
25 25
26 ipcMain.handle("sessions:create", (_, projectId: string, name: string) => { 26 ipcMain.handle("sessions:create", (_, projectId: string, name: string, phase?: Phase) => {
27 const project = projects.getProject(projectId); 27 const project = projects.getProject(projectId);
28 if (!project) throw new Error("Project not found"); 28 if (!project) throw new Error("Project not found");
29 29
30 const session = sessions.createSession(projectId, name); 30 const session = sessions.createSession(projectId, name, phase);
31 31
32 // Ensure .claude-flow/ is gitignored from day one. 32 // Ensure .claude-flow/ is gitignored from day one.
33 // Branch creation is deferred until the session advances to implement. 33 // Branch creation is deferred until the session advances to implement.
diff --git a/src/main/preload.ts b/src/main/preload.ts
index e7ee0aa..fbdf871 100644
--- a/src/main/preload.ts
+++ b/src/main/preload.ts
@@ -12,7 +12,7 @@ export interface ClaudeFlowAPI {
12 12
13 // Sessions 13 // Sessions
14 listSessions: (projectId: string) => Promise<Session[]>; 14 listSessions: (projectId: string) => Promise<Session[]>;
15 createSession: (projectId: string, name: string) => Promise<Session>; 15 createSession: (projectId: string, name: string, phase?: Phase) => Promise<Session>;
16 deleteSession: (id: string) => Promise<void>; 16 deleteSession: (id: string) => Promise<void>;
17 getSession: (id: string) => Promise<Session | undefined>; 17 getSession: (id: string) => Promise<Session | undefined>;
18 renameSession: (id: string, name: string) => Promise<void>; 18 renameSession: (id: string, name: string) => Promise<void>;
@@ -86,8 +86,8 @@ const api: ClaudeFlowAPI = {
86 86
87 // Sessions 87 // Sessions
88 listSessions: (projectId) => ipcRenderer.invoke("sessions:list", projectId), 88 listSessions: (projectId) => ipcRenderer.invoke("sessions:list", projectId),
89 createSession: (projectId, name) => 89 createSession: (projectId, name, phase) =>
90 ipcRenderer.invoke("sessions:create", projectId, name), 90 ipcRenderer.invoke("sessions:create", projectId, name, phase),
91 deleteSession: (id) => ipcRenderer.invoke("sessions:delete", id), 91 deleteSession: (id) => ipcRenderer.invoke("sessions:delete", id),
92 getSession: (id) => ipcRenderer.invoke("sessions:get", id), 92 getSession: (id) => ipcRenderer.invoke("sessions:get", id),
93 renameSession: (id, name) => ipcRenderer.invoke("sessions:rename", id, name), 93 renameSession: (id, name) => ipcRenderer.invoke("sessions:rename", id, name),