mirror of
https://github.com/codeaashu/claude-code.git
synced 2026-04-09 06:38:46 +03:00
claude-code
This commit is contained in:
523
src/tasks/LocalShellTask/LocalShellTask.tsx
Normal file
523
src/tasks/LocalShellTask/LocalShellTask.tsx
Normal file
File diff suppressed because one or more lines are too long
42
src/tasks/LocalShellTask/guards.ts
Normal file
42
src/tasks/LocalShellTask/guards.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
// Pure type + type guard for LocalShellTask state.
|
||||
// Extracted from LocalShellTask.tsx so non-React consumers (stopTask.ts via
|
||||
// print.ts) don't pull React/ink into the module graph.
|
||||
|
||||
import type { TaskStateBase } from '../../Task.js'
|
||||
import type { AgentId } from '../../types/ids.js'
|
||||
import type { ShellCommand } from '../../utils/ShellCommand.js'
|
||||
|
||||
export type BashTaskKind = 'bash' | 'monitor'
|
||||
|
||||
export type LocalShellTaskState = TaskStateBase & {
|
||||
type: 'local_bash' // Keep as 'local_bash' for backward compatibility with persisted session state
|
||||
command: string
|
||||
result?: {
|
||||
code: number
|
||||
interrupted: boolean
|
||||
}
|
||||
completionStatusSentInAttachment: boolean
|
||||
shellCommand: ShellCommand | null
|
||||
unregisterCleanup?: () => void
|
||||
cleanupTimeoutId?: NodeJS.Timeout
|
||||
// Track what we last reported for computing deltas (total lines from TaskOutput)
|
||||
lastReportedTotalLines: number
|
||||
// Whether the task has been backgrounded (false = foreground running, true = backgrounded)
|
||||
isBackgrounded: boolean
|
||||
// Agent that spawned this task. Used to kill orphaned bash tasks when the
|
||||
// agent exits (see killShellTasksForAgent). Undefined = main thread.
|
||||
agentId?: AgentId
|
||||
// UI display variant. 'monitor' → shows description instead of command,
|
||||
// 'Monitor details' dialog title, distinct status bar pill.
|
||||
kind?: BashTaskKind
|
||||
}
|
||||
|
||||
export function isLocalShellTask(task: unknown): task is LocalShellTaskState {
|
||||
return (
|
||||
typeof task === 'object' &&
|
||||
task !== null &&
|
||||
'type' in task &&
|
||||
task.type === 'local_bash'
|
||||
)
|
||||
}
|
||||
|
||||
77
src/tasks/LocalShellTask/killShellTasks.ts
Normal file
77
src/tasks/LocalShellTask/killShellTasks.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
// Pure (non-React) kill helpers for LocalShellTask.
|
||||
// Extracted so runAgent.ts can kill agent-scoped bash tasks without pulling
|
||||
// React/Ink into its module graph (same rationale as guards.ts).
|
||||
|
||||
import type { AppState } from '../../state/AppState.js'
|
||||
import type { AgentId } from '../../types/ids.js'
|
||||
import { logForDebugging } from '../../utils/debug.js'
|
||||
import { logError } from '../../utils/log.js'
|
||||
import { dequeueAllMatching } from '../../utils/messageQueueManager.js'
|
||||
import { evictTaskOutput } from '../../utils/task/diskOutput.js'
|
||||
import { updateTaskState } from '../../utils/task/framework.js'
|
||||
import { isLocalShellTask } from './guards.js'
|
||||
|
||||
type SetAppStateFn = (updater: (prev: AppState) => AppState) => void
|
||||
|
||||
export function killTask(taskId: string, setAppState: SetAppStateFn): void {
|
||||
updateTaskState(taskId, setAppState, task => {
|
||||
if (task.status !== 'running' || !isLocalShellTask(task)) {
|
||||
return task
|
||||
}
|
||||
|
||||
try {
|
||||
logForDebugging(`LocalShellTask ${taskId} kill requested`)
|
||||
task.shellCommand?.kill()
|
||||
task.shellCommand?.cleanup()
|
||||
} catch (error) {
|
||||
logError(error)
|
||||
}
|
||||
|
||||
task.unregisterCleanup?.()
|
||||
if (task.cleanupTimeoutId) {
|
||||
clearTimeout(task.cleanupTimeoutId)
|
||||
}
|
||||
|
||||
return {
|
||||
...task,
|
||||
status: 'killed',
|
||||
notified: true,
|
||||
shellCommand: null,
|
||||
unregisterCleanup: undefined,
|
||||
cleanupTimeoutId: undefined,
|
||||
endTime: Date.now(),
|
||||
}
|
||||
})
|
||||
void evictTaskOutput(taskId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Kill all running bash tasks spawned by a given agent.
|
||||
* Called from runAgent.ts finally block so background processes don't outlive
|
||||
* the agent that started them (prevents 10-day fake-logs.sh zombies).
|
||||
*/
|
||||
export function killShellTasksForAgent(
|
||||
agentId: AgentId,
|
||||
getAppState: () => AppState,
|
||||
setAppState: SetAppStateFn,
|
||||
): void {
|
||||
const tasks = getAppState().tasks ?? {}
|
||||
for (const [taskId, task] of Object.entries(tasks)) {
|
||||
if (
|
||||
isLocalShellTask(task) &&
|
||||
task.agentId === agentId &&
|
||||
task.status === 'running'
|
||||
) {
|
||||
logForDebugging(
|
||||
`killShellTasksForAgent: killing orphaned shell task ${taskId} (agent ${agentId} exiting)`,
|
||||
)
|
||||
killTask(taskId, setAppState)
|
||||
}
|
||||
}
|
||||
// Purge any queued notifications addressed to this agent — its query loop
|
||||
// has exited and won't drain them. killTask fires 'killed' notifications
|
||||
// asynchronously; drop the ones already queued and any that land later sit
|
||||
// harmlessly (no consumer matches a dead agentId).
|
||||
dequeueAllMatching(cmd => cmd.agentId === agentId)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user