Skip to content

Commit 1f17546

Browse files
committed
fix: hydrate backend Coordinator.tasks on app restart
1 parent c2afca9 commit 1f17546

4 files changed

Lines changed: 86 additions & 0 deletions

File tree

electron/ipc/channels.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,5 @@ export enum IPC {
156156
MCP_CoordinatorNotificationDropAck = 'mcp_coordinator_notification_drop_ack',
157157
MCP_CoordinatedTaskPromptDelivered = 'mcp_coordinated_task_prompt_delivered',
158158
MCP_CoordinatorRestageAfterUserSend = 'mcp_coordinator_restage_after_user_send',
159+
MCP_HydrateCoordinatedTask = 'mcp_hydrate_coordinated_task',
159160
}

electron/ipc/register.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,6 +1217,42 @@ export function registerAllHandlers(win: BrowserWindow): void {
12171217
coordinator?.rescheduleRestageTimer(args.coordinatorTaskId);
12181218
},
12191219
);
1220+
1221+
ipcMain.handle(
1222+
IPC.MCP_HydrateCoordinatedTask,
1223+
(
1224+
_e,
1225+
args: {
1226+
id: string;
1227+
name: string;
1228+
projectId: string;
1229+
projectRoot: string;
1230+
branchName: string;
1231+
baseBranch?: string;
1232+
worktreePath: string;
1233+
coordinatorTaskId: string;
1234+
},
1235+
) => {
1236+
assertString(args.id, 'id');
1237+
assertString(args.name, 'name');
1238+
assertString(args.projectId, 'projectId');
1239+
validatePath(args.projectRoot, 'projectRoot');
1240+
assertString(args.branchName, 'branchName');
1241+
validatePath(args.worktreePath, 'worktreePath');
1242+
assertString(args.coordinatorTaskId, 'coordinatorTaskId');
1243+
coordinator?.hydrateTask({
1244+
id: args.id,
1245+
name: args.name,
1246+
projectId: args.projectId,
1247+
projectRoot: args.projectRoot,
1248+
branchName: args.branchName,
1249+
baseBranch: args.baseBranch,
1250+
worktreePath: args.worktreePath,
1251+
agentId: crypto.randomUUID(),
1252+
coordinatorTaskId: args.coordinatorTaskId,
1253+
});
1254+
},
1255+
);
12201256
}
12211257

12221258
// Enable coordinator mode: lazily import the Coordinator module and register handlers.

electron/mcp/coordinator.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,34 @@ export class Coordinator {
866866
return this.tasks.get(taskId);
867867
}
868868

869+
hydrateTask(opts: {
870+
id: string;
871+
name: string;
872+
projectId: string;
873+
projectRoot: string;
874+
branchName: string;
875+
baseBranch?: string;
876+
worktreePath: string;
877+
agentId: string;
878+
coordinatorTaskId: string;
879+
}): void {
880+
if (this.tasks.has(opts.id)) return;
881+
const task: CoordinatedTask = {
882+
id: opts.id,
883+
name: opts.name,
884+
projectId: opts.projectId,
885+
projectRoot: opts.projectRoot,
886+
branchName: opts.branchName,
887+
baseBranch: opts.baseBranch,
888+
worktreePath: opts.worktreePath,
889+
agentId: opts.agentId,
890+
coordinatorTaskId: opts.coordinatorTaskId,
891+
status: 'exited',
892+
exitCode: null,
893+
};
894+
this.tasks.set(task.id, task);
895+
}
896+
869897
registerCoordinator(coordinatorTaskId: string, projectId: string, worktreePath?: string): void {
870898
if (this.coordinators.has(coordinatorTaskId)) return;
871899
this.coordinators.set(coordinatorTaskId, {

src/App.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,27 @@ function App() {
347347
});
348348
}
349349

350+
// Hydrate backend coordinator task registry with persisted child tasks so MCP
351+
// tools (list_tasks, send_prompt, close_task, etc.) work after app restart.
352+
for (const taskId of [...store.taskOrder, ...store.collapsedTaskOrder]) {
353+
const task = store.tasks[taskId];
354+
if (!task?.coordinatedBy) continue;
355+
const projectRoot = store.projects.find((p) => p.id === task.projectId)?.path;
356+
if (!projectRoot) continue;
357+
invoke(IPC.MCP_HydrateCoordinatedTask, {
358+
id: task.id,
359+
name: task.name,
360+
projectId: task.projectId,
361+
projectRoot,
362+
branchName: task.branchName,
363+
baseBranch: task.baseBranch,
364+
worktreePath: task.worktreePath,
365+
coordinatorTaskId: task.coordinatedBy,
366+
}).catch((err) => {
367+
console.warn(`[MCP] Failed to hydrate coordinated task ${taskId}:`, err);
368+
});
369+
}
370+
350371
// Restore plan content for tasks that had a plan file before restart
351372
for (const taskId of [...store.taskOrder, ...store.collapsedTaskOrder]) {
352373
const task = store.tasks[taskId];

0 commit comments

Comments
 (0)