source dump of claude code
at main 76 lines 2.6 kB view raw
1// Pure (non-React) kill helpers for LocalShellTask. 2// Extracted so runAgent.ts can kill agent-scoped bash tasks without pulling 3// React/Ink into its module graph (same rationale as guards.ts). 4 5import type { AppState } from '../../state/AppState.js' 6import type { AgentId } from '../../types/ids.js' 7import { logForDebugging } from '../../utils/debug.js' 8import { logError } from '../../utils/log.js' 9import { dequeueAllMatching } from '../../utils/messageQueueManager.js' 10import { evictTaskOutput } from '../../utils/task/diskOutput.js' 11import { updateTaskState } from '../../utils/task/framework.js' 12import { isLocalShellTask } from './guards.js' 13 14type SetAppStateFn = (updater: (prev: AppState) => AppState) => void 15 16export function killTask(taskId: string, setAppState: SetAppStateFn): void { 17 updateTaskState(taskId, setAppState, task => { 18 if (task.status !== 'running' || !isLocalShellTask(task)) { 19 return task 20 } 21 22 try { 23 logForDebugging(`LocalShellTask ${taskId} kill requested`) 24 task.shellCommand?.kill() 25 task.shellCommand?.cleanup() 26 } catch (error) { 27 logError(error) 28 } 29 30 task.unregisterCleanup?.() 31 if (task.cleanupTimeoutId) { 32 clearTimeout(task.cleanupTimeoutId) 33 } 34 35 return { 36 ...task, 37 status: 'killed', 38 notified: true, 39 shellCommand: null, 40 unregisterCleanup: undefined, 41 cleanupTimeoutId: undefined, 42 endTime: Date.now(), 43 } 44 }) 45 void evictTaskOutput(taskId) 46} 47 48/** 49 * Kill all running bash tasks spawned by a given agent. 50 * Called from runAgent.ts finally block so background processes don't outlive 51 * the agent that started them (prevents 10-day fake-logs.sh zombies). 52 */ 53export function killShellTasksForAgent( 54 agentId: AgentId, 55 getAppState: () => AppState, 56 setAppState: SetAppStateFn, 57): void { 58 const tasks = getAppState().tasks ?? {} 59 for (const [taskId, task] of Object.entries(tasks)) { 60 if ( 61 isLocalShellTask(task) && 62 task.agentId === agentId && 63 task.status === 'running' 64 ) { 65 logForDebugging( 66 `killShellTasksForAgent: killing orphaned shell task ${taskId} (agent ${agentId} exiting)`, 67 ) 68 killTask(taskId, setAppState) 69 } 70 } 71 // Purge any queued notifications addressed to this agent — its query loop 72 // has exited and won't drain them. killTask fires 'killed' notifications 73 // asynchronously; drop the ones already queued and any that land later sit 74 // harmlessly (no consumer matches a dead agentId). 75 dequeueAllMatching(cmd => cmd.agentId === agentId) 76}