source dump of claude code
at main 125 lines 3.2 kB view raw
1import { randomBytes } from 'crypto' 2import type { AppState } from './state/AppState.js' 3import type { AgentId } from './types/ids.js' 4import { getTaskOutputPath } from './utils/task/diskOutput.js' 5 6export type TaskType = 7 | 'local_bash' 8 | 'local_agent' 9 | 'remote_agent' 10 | 'in_process_teammate' 11 | 'local_workflow' 12 | 'monitor_mcp' 13 | 'dream' 14 15export type TaskStatus = 16 | 'pending' 17 | 'running' 18 | 'completed' 19 | 'failed' 20 | 'killed' 21 22/** 23 * True when a task is in a terminal state and will not transition further. 24 * Used to guard against injecting messages into dead teammates, evicting 25 * finished tasks from AppState, and orphan-cleanup paths. 26 */ 27export function isTerminalTaskStatus(status: TaskStatus): boolean { 28 return status === 'completed' || status === 'failed' || status === 'killed' 29} 30 31export type TaskHandle = { 32 taskId: string 33 cleanup?: () => void 34} 35 36export type SetAppState = (f: (prev: AppState) => AppState) => void 37 38export type TaskContext = { 39 abortController: AbortController 40 getAppState: () => AppState 41 setAppState: SetAppState 42} 43 44// Base fields shared by all task states 45export type TaskStateBase = { 46 id: string 47 type: TaskType 48 status: TaskStatus 49 description: string 50 toolUseId?: string 51 startTime: number 52 endTime?: number 53 totalPausedMs?: number 54 outputFile: string 55 outputOffset: number 56 notified: boolean 57} 58 59export type LocalShellSpawnInput = { 60 command: string 61 description: string 62 timeout?: number 63 toolUseId?: string 64 agentId?: AgentId 65 /** UI display variant: description-as-label, dialog title, status bar pill. */ 66 kind?: 'bash' | 'monitor' 67} 68 69// What getTaskByType dispatches for: kill. spawn/render were never 70// called polymorphically (removed in #22546). All six kill implementations 71// use only setAppState — getAppState/abortController were dead weight. 72export type Task = { 73 name: string 74 type: TaskType 75 kill(taskId: string, setAppState: SetAppState): Promise<void> 76} 77 78// Task ID prefixes 79const TASK_ID_PREFIXES: Record<string, string> = { 80 local_bash: 'b', // Keep as 'b' for backward compatibility 81 local_agent: 'a', 82 remote_agent: 'r', 83 in_process_teammate: 't', 84 local_workflow: 'w', 85 monitor_mcp: 'm', 86 dream: 'd', 87} 88 89// Get task ID prefix 90function getTaskIdPrefix(type: TaskType): string { 91 return TASK_ID_PREFIXES[type] ?? 'x' 92} 93 94// Case-insensitive-safe alphabet (digits + lowercase) for task IDs. 95// 36^8 ≈ 2.8 trillion combinations, sufficient to resist brute-force symlink attacks. 96const TASK_ID_ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz' 97 98export function generateTaskId(type: TaskType): string { 99 const prefix = getTaskIdPrefix(type) 100 const bytes = randomBytes(8) 101 let id = prefix 102 for (let i = 0; i < 8; i++) { 103 id += TASK_ID_ALPHABET[bytes[i]! % TASK_ID_ALPHABET.length] 104 } 105 return id 106} 107 108export function createTaskStateBase( 109 id: string, 110 type: TaskType, 111 description: string, 112 toolUseId?: string, 113): TaskStateBase { 114 return { 115 id, 116 type, 117 status: 'pending', 118 description, 119 toolUseId, 120 startTime: Date.now(), 121 outputFile: getTaskOutputPath(id), 122 outputOffset: 0, 123 notified: false, 124 } 125}