Skip to content

Commit bf2e9d9

Browse files
committed
fix: kill inner docker exec agent process on sub-task cleanup
1 parent fe68af9 commit bf2e9d9

2 files changed

Lines changed: 19 additions & 0 deletions

File tree

electron/mcp/coordinator.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ export class Coordinator {
380380
coordinatorTaskId: coordinatorId,
381381
status: 'creating',
382382
exitCode: null,
383+
dockerContainerName: this.coordinators.get(coordinatorId)?.dockerContainerName ?? null,
383384
};
384385

385386
this.tasks.set(task.id, task);
@@ -998,6 +999,20 @@ export class Coordinator {
998999
/* already dead */
9991000
}
10001001

1002+
// When spawned via `docker exec`, killing the host PTY only stops the exec
1003+
// client. Best-effort: kill the inner agent process still running inside the
1004+
// coordinator container.
1005+
if (task.dockerContainerName) {
1006+
execFile(
1007+
'docker',
1008+
['exec', task.dockerContainerName, 'pkill', '-TERM', '-f', 'claude'],
1009+
{ timeout: 5000 },
1010+
() => {
1011+
// Intentionally ignore errors: inner process may have already exited.
1012+
},
1013+
);
1014+
}
1015+
10011016
// Remove worktree
10021017
try {
10031018
await deleteTask({

electron/mcp/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ export interface CoordinatedTask {
2020
// Coordinator notification lifecycle flags
2121
assignedPromptDelivered?: boolean;
2222
reviewNotificationQueued?: boolean;
23+
/** When the coordinator runs in Docker, sub-tasks are spawned via `docker exec`.
24+
* Storing the container name here lets cleanupTask kill the inner process even
25+
* after the coordinator state is gone. */
26+
dockerContainerName?: string | null;
2327
}
2428

2529
export interface WaitForSignalDoneResult {

0 commit comments

Comments
 (0)