{"version":3,"file":"async-status.d.ts","sourceRoot":"","sources":["../../../../src/runs/background/async-status.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { formatDuration, formatModelThinking, formatTokens, shortenPath } from \"../../shared/formatters.ts\";\nimport { formatActivityLabel, formatParallelOutcome } from \"../../shared/status-format.ts\";\nimport type {\n\tActivityState,\n\tAsyncJobStep,\n\tAsyncParallelGroupStatus,\n\tAsyncStatus,\n\tChainCheckpointState,\n\tCostSummary,\n\tDetails,\n\tLaunchResolvedChildExtensionsV1,\n\tNestedRunSummary,\n\tRuntimeAcknowledgedChildExtensionsV1,\n\tSteeringStatus,\n\tSubagentRunMode,\n\tTokenUsage,\n\tTurnBudgetState,\n\tUsageBudgetState,\n} from \"../../shared/types.ts\";\nimport { readStatus } from \"../../shared/utils.ts\";\nimport type { ResolvedSubagentCapabilityCeiling, SubagentCapabilityAudit } from \"../shared/capability-ceiling.ts\";\nimport {\n\ttype ContextMode,\n\ttype ContextSummary,\n\tcontextModeLabel,\n\tsummarizeContextModes,\n} from \"../shared/context-mode.ts\";\nimport {\n\tattachRootChildrenToSteps,\n\tbuildNestedRouteIndex,\n\ttype NestedRoute,\n\tprojectNestedEvents,\n} from \"../shared/nested-events.ts\";\nimport { formatNestedRunStatusLines } from \"../shared/nested-render.ts\";\nimport { flatToLogicalStepIndex, normalizeParallelGroups } from \"./parallel-groups.ts\";\nimport { readProcessTerminal, sanitizeProcessTerminal } from \"./process-terminal.ts\";\nimport { reconcileAsyncRun, reconcileNestedAsyncDescendants } from \"./stale-run-reconciler.ts\";\n\ninterface AsyncRunStepSummary {\n\tindex: number;\n\tagent: string;\n\tcontext?: ContextMode;\n\tlabel?: string;\n\tdescription?: string;\n\tphase?: string;\n\toutputName?: string;\n\tstructured?: boolean;\n\tcheckpoint?: ChainCheckpointState;\n\tstatus: AsyncJobStep[\"status\"];\n\tactivityState?: ActivityState;\n\tlastActivityAt?: number;\n\tcurrentTool?: string;\n\tcurrentToolArgs?: string;\n\tcurrentToolStartedAt?: number;\n\tcurrentPath?: string;\n\trecentTools?: Array<{ tool: string; args: string; endMs: number }>;\n\trecentOutput?: string[];\n\tturnCount?: number;\n\ttoolCount?: number;\n\tsteering?: SteeringStatus;\n\tdurationMs?: number;\n\ttokens?: TokenUsage;\n\ttotalCost?: CostSummary;\n\tskills?: string[];\n\tmodel?: string;\n\tthinking?: string;\n\tattemptedModels?: string[];\n\tsessionFile?: string;\n\ttranscriptPath?: string;\n\terror?: string;\n\ttimedOut?: boolean;\n\tstopped?: boolean;\n\tturnBudget?: TurnBudgetState;\n\tturnBudgetExceeded?: boolean;\n\twrapUpRequested?: boolean;\n\tacceptance?: AsyncJobStep[\"acceptance\"];\n\tagentContract?: AsyncJobStep[\"agentContract\"];\n\texecution?: AsyncJobStep[\"execution\"];\n\treview?: AsyncJobStep[\"review\"];\n\teffects?: AsyncJobStep[\"effects\"];\n\tprocessTerminal?: AsyncJobStep[\"processTerminal\"];\n\tlaunchResolvedExtensions?: LaunchResolvedChildExtensionsV1;\n\truntimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1;\n\tcapabilityCeiling?: ResolvedSubagentCapabilityCeiling;\n\tcapabilityAudit?: SubagentCapabilityAudit;\n\tchildren?: NestedRunSummary[];\n}\n\nexport interface AsyncRunSummary {\n\tid: string;\n\tasyncDir: string;\n\tsessionId?: string;\n\tstate: \"queued\" | \"running\" | \"complete\" | \"failed\" | \"paused\" | \"stopped\" | \"rejected\";\n\terror?: string;\n\tactivityState?: ActivityState;\n\tlastActivityAt?: number;\n\tcurrentTool?: string;\n\tcurrentToolStartedAt?: number;\n\tcurrentPath?: string;\n\tturnCount?: number;\n\ttoolCount?: number;\n\tsteering?: SteeringStatus;\n\tmode: SubagentRunMode;\n\tcontext?: ContextSummary;\n\tcwd?: string;\n\tstartedAt: number;\n\tlastUpdate?: number;\n\tendedAt?: number;\n\ttimeoutMs?: number;\n\tdeadlineAt?: number;\n\ttimedOut?: boolean;\n\tstopped?: boolean;\n\tturnBudget?: TurnBudgetState;\n\tturnBudgetExceeded?: boolean;\n\twrapUpRequested?: boolean;\n\tcurrentStep?: number;\n\tchainStepCount?: number;\n\tpendingAppends?: number;\n\tparallelGroups?: AsyncParallelGroupStatus[];\n\tsteps: AsyncRunStepSummary[];\n\tcheckpoint?: ChainCheckpointState;\n\tsessionDir?: string;\n\toutputFile?: string;\n\ttotalTokens?: TokenUsage;\n\ttotalCost?: CostSummary;\n\tusageBudget?: UsageBudgetState;\n\tsessionFile?: string;\n\tnestedChildren?: NestedRunSummary[];\n\tnestedWarnings?: string[];\n\tprocessTerminal?: AsyncStatus[\"processTerminal\"];\n\tlaunchResolvedExtensions?: LaunchResolvedChildExtensionsV1;\n\truntimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1;\n\tcapabilityCeiling?: ResolvedSubagentCapabilityCeiling;\n\tcapabilityAudit?: SubagentCapabilityAudit;\n\tparentWorkflowRunId?: string;\n\tworkflowKey?: string;\n\tworkflow?: Details[\"workflow\"];\n}\n\ninterface AsyncRunListOptions {\n\tstates?: Array<AsyncRunSummary[\"state\"]>;\n\tsessionId?: string;\n\tlimit?: number;\n\t/** Limits status-file reads after candidates are ordered by status mtime. */\n\tentryLimit?: number;\n\tresultsDir?: string;\n\tkill?: (pid: number, signal?: NodeJS.Signals | 0) => boolean;\n\tnow?: () => number;\n\treconcile?: boolean;\n\trunId?: string;\n}\n\nfunction getErrorMessage(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nfunction isNotFoundError(error: unknown): boolean {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\t\"code\" in error &&\n\t\t(error as NodeJS.ErrnoException).code === \"ENOENT\"\n\t);\n}\n\nfunction isAsyncRunDir(root: string, entry: string): boolean {\n\tconst entryPath = path.join(root, entry);\n\ttry {\n\t\treturn fs.statSync(entryPath).isDirectory();\n\t} catch (error) {\n\t\tif (isNotFoundError(error)) return false;\n\t\tthrow new Error(`Failed to inspect async run path '${entryPath}': ${getErrorMessage(error)}`, {\n\t\t\tcause: error instanceof Error ? error : undefined,\n\t\t});\n\t}\n}\n\ntype TargetedAsyncRunResolution = { kind: \"exact\"; id: string } | { kind: \"scan\" } | { kind: \"reject\" };\n\n/**\n * Resolve an exact targeted run without following a run-directory symlink or\n * accepting a path whose canonical location escaped the async root.\n */\nexport function resolveTargetedAsyncRun(\n\tasyncDirRoot: string,\n\tid: string,\n\tsessionId?: string,\n): TargetedAsyncRunResolution {\n\tif (!id || id === \".\" || id === \"..\" || path.basename(id) !== id) return { kind: \"reject\" };\n\tconst asyncDir = path.join(asyncDirRoot, id);\n\tlet entryStat: fs.Stats;\n\ttry {\n\t\tentryStat = fs.lstatSync(asyncDir);\n\t} catch (error) {\n\t\tif (isNotFoundError(error)) return { kind: \"scan\" };\n\t\tthrow new Error(`Failed to inspect async run path '${asyncDir}': ${getErrorMessage(error)}`, {\n\t\t\tcause: error instanceof Error ? error : undefined,\n\t\t});\n\t}\n\tif (!entryStat.isDirectory() || entryStat.isSymbolicLink()) return { kind: \"reject\" };\n\ttry {\n\t\tconst canonicalRoot = fs.realpathSync(asyncDirRoot);\n\t\tconst canonicalDir = fs.realpathSync(asyncDir);\n\t\tif (canonicalDir !== canonicalRoot && !canonicalDir.startsWith(`${canonicalRoot}${path.sep}`))\n\t\t\treturn { kind: \"reject\" };\n\t} catch (error) {\n\t\tif (isNotFoundError(error)) return { kind: \"reject\" };\n\t\tthrow new Error(`Failed to resolve async run path '${asyncDir}': ${getErrorMessage(error)}`, {\n\t\t\tcause: error instanceof Error ? error : undefined,\n\t\t});\n\t}\n\tif (sessionId !== undefined) {\n\t\tconst status = readStatus(asyncDir);\n\t\tif (status?.sessionId !== sessionId) return { kind: \"scan\" };\n\t}\n\treturn { kind: \"exact\", id };\n}\n\nfunction outputFileMtime(outputFile: string | undefined): number | undefined {\n\tif (!outputFile) return undefined;\n\ttry {\n\t\treturn fs.statSync(outputFile).mtimeMs;\n\t} catch (error) {\n\t\tif (isNotFoundError(error)) return undefined;\n\t\tthrow new Error(`Failed to inspect async output file '${outputFile}': ${getErrorMessage(error)}`, {\n\t\t\tcause: error instanceof Error ? error : undefined,\n\t\t});\n\t}\n}\n\nfunction deriveAsyncActivityState(\n\tasyncDir: string,\n\tstatus: AsyncStatus,\n): { activityState?: ActivityState; lastActivityAt?: number } {\n\tif (status.state !== \"running\")\n\t\treturn { activityState: status.activityState, lastActivityAt: status.lastActivityAt };\n\tconst outputPath = status.outputFile\n\t\t? path.isAbsolute(status.outputFile)\n\t\t\t? status.outputFile\n\t\t\t: path.join(asyncDir, status.outputFile)\n\t\t: undefined;\n\tconst currentStep = typeof status.currentStep === \"number\" ? status.steps?.[status.currentStep] : undefined;\n\treturn {\n\t\tactivityState: status.activityState,\n\t\tlastActivityAt:\n\t\t\tstatus.lastActivityAt ??\n\t\t\toutputFileMtime(outputPath) ??\n\t\t\tcurrentStep?.lastActivityAt ??\n\t\t\tcurrentStep?.startedAt ??\n\t\t\tstatus.startedAt,\n\t};\n}\n\nfunction statusToSummary(\n\tasyncDir: string,\n\tstatus: AsyncStatus & { cwd?: string },\n\tnestedWarnings: string[] = [],\n\tnestedRoute?: NestedRoute,\n): AsyncRunSummary {\n\tif (status.sessionId !== undefined && typeof status.sessionId !== \"string\") {\n\t\tthrow new Error(`Invalid async status '${path.join(asyncDir, \"status.json\")}': sessionId must be a string.`);\n\t}\n\tconst { activityState, lastActivityAt } = deriveAsyncActivityState(asyncDir, status);\n\tconst processTerminal =\n\t\treadProcessTerminal(asyncDir, {\n\t\t\trunId: status.runId,\n\t\t\trunnerProcessInstanceId: status.processTerminal?.runnerProcessInstanceId,\n\t\t}) ??\n\t\tsanitizeProcessTerminal(\n\t\t\tstatus.processTerminal,\n\t\t\t{ runId: status.runId, runnerProcessInstanceId: status.processTerminal?.runnerProcessInstanceId },\n\t\t\tpath.join(asyncDir, \"status.json\"),\n\t\t);\n\tconst steps = status.steps ?? [];\n\tconst chainStepCount = status.chainStepCount ?? steps.length;\n\tconst parallelGroups = normalizeParallelGroups(status.parallelGroups, steps.length, chainStepCount);\n\tlet nestedChildren: NestedRunSummary[] = [];\n\tif (nestedWarnings.length === 0 && nestedRoute) {\n\t\ttry {\n\t\t\t// The route is resolved by the caller via buildNestedRouteIndex, so this\n\t\t\t// avoids a fresh scan of the nested-events directory per run.\n\t\t\tnestedChildren = projectNestedEvents(nestedRoute)?.children ?? [];\n\t\t} catch (error) {\n\t\t\tnestedWarnings.push(`Nested status unavailable: ${getErrorMessage(error)}`);\n\t\t}\n\t}\n\tconst summarizedSteps = steps.map((step, index) => {\n\t\tconst stepActivityState = step.activityState;\n\t\tconst stepLastActivityAt = step.lastActivityAt;\n\t\treturn {\n\t\t\tindex,\n\t\t\tagent: step.agent,\n\t\t\t...(step.context ? { context: step.context } : {}),\n\t\t\t...(step.label ? { label: step.label } : {}),\n\t\t\t...(step.description ? { description: step.description } : {}),\n\t\t\t...(step.phase ? { phase: step.phase } : {}),\n\t\t\t...(step.outputName ? { outputName: step.outputName } : {}),\n\t\t\t...(step.structured ? { structured: step.structured } : {}),\n\t\t\t...(step.checkpoint ? { checkpoint: step.checkpoint } : {}),\n\t\t\tstatus: step.status,\n\t\t\t...(stepActivityState ? { activityState: stepActivityState } : {}),\n\t\t\t...(stepLastActivityAt ? { lastActivityAt: stepLastActivityAt } : {}),\n\t\t\t...(step.currentTool ? { currentTool: step.currentTool } : {}),\n\t\t\t...(step.currentToolArgs ? { currentToolArgs: step.currentToolArgs } : {}),\n\t\t\t...(step.currentToolStartedAt ? { currentToolStartedAt: step.currentToolStartedAt } : {}),\n\t\t\t...(step.currentPath ? { currentPath: step.currentPath } : {}),\n\t\t\t...(step.recentTools ? { recentTools: step.recentTools.map((tool) => ({ ...tool })) } : {}),\n\t\t\t...(step.recentOutput ? { recentOutput: [...step.recentOutput] } : {}),\n\t\t\t...(step.turnCount !== undefined ? { turnCount: step.turnCount } : {}),\n\t\t\t...(step.toolCount !== undefined ? { toolCount: step.toolCount } : {}),\n\t\t\t...(step.steering ? { steering: step.steering } : {}),\n\t\t\t...(step.durationMs !== undefined ? { durationMs: step.durationMs } : {}),\n\t\t\t...(step.tokens ? { tokens: step.tokens } : {}),\n\t\t\t...(step.totalCost ? { totalCost: step.totalCost } : {}),\n\t\t\t...(step.skills ? { skills: step.skills } : {}),\n\t\t\t...(step.model ? { model: step.model } : {}),\n\t\t\t...(step.thinking ? { thinking: step.thinking } : {}),\n\t\t\t...(step.attemptedModels ? { attemptedModels: step.attemptedModels } : {}),\n\t\t\t...(step.sessionFile ? { sessionFile: step.sessionFile } : {}),\n\t\t\t...(step.transcriptPath ? { transcriptPath: step.transcriptPath } : {}),\n\t\t\t...(step.error ? { error: step.error } : {}),\n\t\t\t...(step.timedOut !== undefined ? { timedOut: step.timedOut } : {}),\n\t\t\t...(step.stopped !== undefined ? { stopped: step.stopped } : {}),\n\t\t\t...(step.turnBudget ? { turnBudget: step.turnBudget } : {}),\n\t\t\t...(step.turnBudgetExceeded !== undefined ? { turnBudgetExceeded: step.turnBudgetExceeded } : {}),\n\t\t\t...(step.wrapUpRequested !== undefined ? { wrapUpRequested: step.wrapUpRequested } : {}),\n\t\t\t...(step.acceptance ? { acceptance: step.acceptance } : {}),\n\t\t\t...(step.agentContract ? { agentContract: step.agentContract } : {}),\n\t\t\t...(step.launchContractDigest ? { launchContractDigest: step.launchContractDigest } : {}),\n\t\t\t...(step.launchResolvedExtensions ? { launchResolvedExtensions: step.launchResolvedExtensions } : {}),\n\t\t\t...(step.runtimeAcknowledgedExtensions\n\t\t\t\t? { runtimeAcknowledgedExtensions: step.runtimeAcknowledgedExtensions }\n\t\t\t\t: {}),\n\t\t\t...(step.execution ? { execution: step.execution } : {}),\n\t\t\t...(step.review ? { review: step.review } : {}),\n\t\t\t...(step.effects ? { effects: step.effects } : {}),\n\t\t\t...(step.processTerminal\n\t\t\t\t? {\n\t\t\t\t\t\tprocessTerminal: sanitizeProcessTerminal(\n\t\t\t\t\t\t\tstep.processTerminal,\n\t\t\t\t\t\t\t{ runId: status.runId, runnerProcessInstanceId: step.processTerminal.runnerProcessInstanceId },\n\t\t\t\t\t\t\t`${path.join(asyncDir, \"status.json\")} step ${index}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\t...(step.capabilityCeiling ? { capabilityCeiling: step.capabilityCeiling } : {}),\n\t\t\t...(step.capabilityAudit ? { capabilityAudit: step.capabilityAudit } : {}),\n\t\t\t...(step.children?.length ? { children: step.children } : {}),\n\t\t};\n\t});\n\tattachRootChildrenToSteps(status.runId || path.basename(asyncDir), summarizedSteps, nestedChildren);\n\treturn {\n\t\tid: status.runId || path.basename(asyncDir),\n\t\tasyncDir,\n\t\t...(status.sessionId ? { sessionId: status.sessionId } : {}),\n\t\tstate: status.state,\n\t\t...(status.error ? { error: status.error } : {}),\n\t\tactivityState,\n\t\tlastActivityAt,\n\t\tcurrentTool: status.currentTool,\n\t\tcurrentToolStartedAt: status.currentToolStartedAt,\n\t\tcurrentPath: status.currentPath,\n\t\tturnCount: status.turnCount,\n\t\ttoolCount: status.toolCount,\n\t\tsteering: status.steering,\n\t\tmode: status.mode,\n\t\t...(summarizeContextModes(summarizedSteps.map((step) => step.context))\n\t\t\t? { context: summarizeContextModes(summarizedSteps.map((step) => step.context)) }\n\t\t\t: {}),\n\t\tcwd: status.cwd,\n\t\tstartedAt: status.startedAt,\n\t\tlastUpdate: status.lastUpdate,\n\t\tendedAt: status.endedAt,\n\t\t...(status.timeoutMs !== undefined ? { timeoutMs: status.timeoutMs } : {}),\n\t\t...(status.deadlineAt !== undefined ? { deadlineAt: status.deadlineAt } : {}),\n\t\t...(status.timedOut !== undefined ? { timedOut: status.timedOut } : {}),\n\t\t...(status.stopped !== undefined ? { stopped: status.stopped } : {}),\n\t\t...(status.turnBudget ? { turnBudget: status.turnBudget } : {}),\n\t\t...(status.turnBudgetExceeded !== undefined ? { turnBudgetExceeded: status.turnBudgetExceeded } : {}),\n\t\t...(status.wrapUpRequested !== undefined ? { wrapUpRequested: status.wrapUpRequested } : {}),\n\t\tcurrentStep: status.currentStep,\n\t\t...(status.chainStepCount !== undefined ? { chainStepCount: status.chainStepCount } : {}),\n\t\t...(status.pendingAppends !== undefined ? { pendingAppends: status.pendingAppends } : {}),\n\t\t...(parallelGroups.length ? { parallelGroups } : {}),\n\t\tsteps: summarizedSteps,\n\t\t...(status.checkpoint ? { checkpoint: status.checkpoint } : {}),\n\t\t...(nestedChildren.length ? { nestedChildren } : {}),\n\t\t...(nestedWarnings.length ? { nestedWarnings } : {}),\n\t\t...(processTerminal ? { processTerminal } : {}),\n\t\t...(status.launchContractDigest ? { launchContractDigest: status.launchContractDigest } : {}),\n\t\t...(status.launchResolvedExtensions ? { launchResolvedExtensions: status.launchResolvedExtensions } : {}),\n\t\t...(status.runtimeAcknowledgedExtensions\n\t\t\t? { runtimeAcknowledgedExtensions: status.runtimeAcknowledgedExtensions }\n\t\t\t: {}),\n\t\t...(status.capabilityCeiling ? { capabilityCeiling: status.capabilityCeiling } : {}),\n\t\t...(status.capabilityAudit ? { capabilityAudit: status.capabilityAudit } : {}),\n\t\t...(status.parentWorkflowRunId ? { parentWorkflowRunId: status.parentWorkflowRunId } : {}),\n\t\t...(status.workflowKey ? { workflowKey: status.workflowKey } : {}),\n\t\t...(status.workflow ? { workflow: status.workflow } : {}),\n\t\t...(status.sessionDir ? { sessionDir: status.sessionDir } : {}),\n\t\t...(status.outputFile ? { outputFile: status.outputFile } : {}),\n\t\t...(status.totalTokens ? { totalTokens: status.totalTokens } : {}),\n\t\t...(status.totalCost ? { totalCost: status.totalCost } : {}),\n\t\t...(status.usageBudget ? { usageBudget: status.usageBudget } : {}),\n\t\t...(status.sessionFile ? { sessionFile: status.sessionFile } : {}),\n\t};\n}\n\nexport function summarizeAsyncStatus(asyncDir: string, status: AsyncStatus & { cwd?: string }): AsyncRunSummary {\n\treturn statusToSummary(asyncDir, status);\n}\n\nfunction sortRuns(runs: AsyncRunSummary[]): AsyncRunSummary[] {\n\tconst rank = (state: AsyncRunSummary[\"state\"]): number => {\n\t\tswitch (state) {\n\t\t\tcase \"running\":\n\t\t\t\treturn 0;\n\t\t\tcase \"queued\":\n\t\t\t\treturn 1;\n\t\t\tcase \"failed\":\n\t\t\t\treturn 2;\n\t\t\tcase \"stopped\":\n\t\t\t\treturn 2;\n\t\t\tcase \"paused\":\n\t\t\t\treturn 2;\n\t\t\tcase \"complete\":\n\t\t\t\treturn 3;\n\t\t\tdefault:\n\t\t\t\treturn 4;\n\t\t}\n\t};\n\treturn [...runs].sort((a, b) => {\n\t\tconst byState = rank(a.state) - rank(b.state);\n\t\tif (byState !== 0) return byState;\n\t\tconst aTime = a.lastUpdate ?? a.endedAt ?? a.startedAt;\n\t\tconst bTime = b.lastUpdate ?? b.endedAt ?? b.startedAt;\n\t\treturn bTime - aTime;\n\t});\n}\n\nexport function listAsyncRuns(asyncDirRoot: string, options: AsyncRunListOptions = {}): AsyncRunSummary[] {\n\tlet entries: string[];\n\ttry {\n\t\tif (options.runId !== undefined) {\n\t\t\tconst resolution = resolveTargetedAsyncRun(asyncDirRoot, options.runId, options.sessionId);\n\t\t\tentries =\n\t\t\t\tresolution.kind === \"exact\"\n\t\t\t\t\t? [resolution.id]\n\t\t\t\t\t: resolution.kind === \"scan\"\n\t\t\t\t\t\t? fs\n\t\t\t\t\t\t\t\t.readdirSync(asyncDirRoot)\n\t\t\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t\t\t(entry) =>\n\t\t\t\t\t\t\t\t\t\t(entry === options.runId || entry.startsWith(options.runId!)) &&\n\t\t\t\t\t\t\t\t\t\tresolveTargetedAsyncRun(asyncDirRoot, entry, options.sessionId).kind === \"exact\",\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t: [];\n\t\t} else {\n\t\t\tentries = fs.readdirSync(asyncDirRoot).filter((entry) => isAsyncRunDir(asyncDirRoot, entry));\n\t\t}\n\t} catch (error) {\n\t\tif (isNotFoundError(error)) return [];\n\t\tthrow new Error(`Failed to list async runs in '${asyncDirRoot}': ${getErrorMessage(error)}`, {\n\t\t\tcause: error instanceof Error ? error : undefined,\n\t\t});\n\t}\n\n\tif (options.entryLimit !== undefined) {\n\t\tconst limit = Math.max(0, Math.floor(options.entryLimit));\n\t\tentries = entries\n\t\t\t.map((entry) => {\n\t\t\t\ttry {\n\t\t\t\t\treturn { entry, mtimeMs: fs.statSync(path.join(asyncDirRoot, entry, \"status.json\")).mtimeMs };\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (isNotFoundError(error)) return undefined;\n\t\t\t\t\tthrow new Error(`Failed to inspect async status file for '${entry}': ${getErrorMessage(error)}`, {\n\t\t\t\t\t\tcause: error instanceof Error ? error : undefined,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t})\n\t\t\t.filter((candidate): candidate is { entry: string; mtimeMs: number } => candidate !== undefined)\n\t\t\t.sort((left, right) => right.mtimeMs - left.mtimeMs)\n\t\t\t.slice(0, limit)\n\t\t\t.map((candidate) => candidate.entry);\n\t}\n\n\tconst allowedStates = options.states ? new Set(options.states) : undefined;\n\tconst runs: AsyncRunSummary[] = [];\n\t// Route resolution for every run shares a single index built from the\n\t// nested-events directory, so the per-run lookup is O(1) instead of scanning\n\t// the directory once per run. The index is built lazily on first use, so\n\t// load-time restoration (which only wants queued/running runs) skips it\n\t// entirely when no active runs match.\n\tlet nestedRouteIndex: Map<string, NestedRoute> | undefined;\n\tconst resolveNestedRoute = (rootRunId: string): NestedRoute | undefined => {\n\t\tif (!nestedRouteIndex) nestedRouteIndex = buildNestedRouteIndex();\n\t\treturn nestedRouteIndex.get(rootRunId);\n\t};\n\tfor (const entry of entries) {\n\t\tconst asyncDir = path.join(asyncDirRoot, entry);\n\t\tconst reconciliation =\n\t\t\toptions.reconcile === false\n\t\t\t\t? undefined\n\t\t\t\t: reconcileAsyncRun(asyncDir, { resultsDir: options.resultsDir, kill: options.kill, now: options.now });\n\t\tconst status = (reconciliation?.status ?? readStatus(asyncDir)) as (AsyncStatus & { cwd?: string }) | null;\n\t\tif (!status) continue;\n\t\t// Filter before the nested-route lookup: the lookup builds an index over\n\t\t// the nested-events directory, so deferring it for filtered-out runs keeps\n\t\t// restoration at load from scanning that directory when no active runs\n\t\t// match.\n\t\tif (allowedStates && !allowedStates.has(status.state)) continue;\n\t\tif (options.sessionId && status.sessionId !== options.sessionId) continue;\n\t\tconst nestedWarnings: string[] = [];\n\t\tlet nestedRoute: NestedRoute | undefined;\n\t\tif (options.reconcile !== false) {\n\t\t\ttry {\n\t\t\t\tnestedRoute = resolveNestedRoute(status.runId || path.basename(asyncDir));\n\t\t\t\tif (nestedRoute)\n\t\t\t\t\treconcileNestedAsyncDescendants(nestedRoute, {\n\t\t\t\t\t\tresultsDir: options.resultsDir,\n\t\t\t\t\t\tkill: options.kill,\n\t\t\t\t\t\tnow: options.now,\n\t\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tnestedWarnings.push(`Nested status unavailable: ${getErrorMessage(error)}`);\n\t\t\t}\n\t\t}\n\t\tconst summary = statusToSummary(asyncDir, status, nestedWarnings, nestedRoute);\n\t\truns.push(summary);\n\t}\n\n\tconst sorted = sortRuns(runs);\n\treturn options.limit !== undefined ? sorted.slice(0, options.limit) : sorted;\n}\n\nfunction formatActivityFacts(input: {\n\tactivityState?: ActivityState;\n\tlastActivityAt?: number;\n\tcurrentTool?: string;\n\tcurrentToolStartedAt?: number;\n\tcurrentPath?: string;\n\tturnCount?: number;\n\ttoolCount?: number;\n\tsteering?: SteeringStatus;\n\tturnBudget?: TurnBudgetState;\n\tturnBudgetExceeded?: boolean;\n\twrapUpRequested?: boolean;\n}): string | undefined {\n\tconst facts: string[] = [];\n\tif (input.currentTool && input.currentToolStartedAt !== undefined)\n\t\tfacts.push(`tool ${input.currentTool} ${formatDuration(Math.max(0, Date.now() - input.currentToolStartedAt))}`);\n\telse if (input.currentTool) facts.push(`tool ${input.currentTool}`);\n\tif (input.currentPath) facts.push(shortenPath(input.currentPath));\n\tif (input.turnCount !== undefined) facts.push(`${input.turnCount} turns`);\n\tif (input.turnBudgetExceeded && input.turnBudget)\n\t\tfacts.push(\n\t\t\t`turn budget exceeded ${input.turnBudget.turnCount}/${input.turnBudget.maxTurns}+${input.turnBudget.graceTurns}`,\n\t\t);\n\telse if (input.turnBudget?.outcome === \"termination-deferred\")\n\t\tfacts.push(\n\t\t\t`turn-budget termination deferred ${input.turnBudget.turnCount}/${input.turnBudget.maxTurns}+${input.turnBudget.graceTurns}`,\n\t\t);\n\telse if (input.wrapUpRequested && input.turnBudget)\n\t\tfacts.push(`wrap-up requested ${input.turnBudget.turnCount}/${input.turnBudget.maxTurns}`);\n\telse if (input.turnBudget)\n\t\tfacts.push(\n\t\t\t`turn budget ${input.turnBudget.turnCount}/${input.turnBudget.maxTurns}+${input.turnBudget.graceTurns}`,\n\t\t);\n\tif (input.toolCount !== undefined) facts.push(`${input.toolCount} tools`);\n\tif (input.steering)\n\t\tfacts.push(\n\t\t\t`steering ${input.steering.scheduled} scheduled, ${input.steering.pending} pending, ${input.steering.delivered} delivered, ${input.steering.failed} failed, ${input.steering.recovered} recovered`,\n\t\t);\n\tconst activity = formatActivityLabel(input.lastActivityAt, input.activityState);\n\treturn activity || facts.length ? [activity, ...facts].filter(Boolean).join(\" | \") : undefined;\n}\n\nfunction formatStepLine(step: AsyncRunStepSummary): string {\n\tconst display = step.label ? `${step.label} (${step.agent})` : step.agent;\n\tconst context = contextModeLabel(step.context);\n\tconst phase = step.phase ? `[${step.phase}] ` : \"\";\n\tconst parts = [`${step.index + 1}. ${phase}${display}${context ? ` ${context}` : \"\"}`, step.status];\n\tconst activity = formatActivityFacts(step);\n\tif (activity) parts.push(activity);\n\tconst modelThinking = formatModelThinking(step.model, step.thinking);\n\tif (modelThinking) parts.push(modelThinking);\n\tif (step.durationMs !== undefined) parts.push(formatDuration(step.durationMs));\n\tif (step.tokens) parts.push(`${formatTokens(step.tokens.total)} tok`);\n\treturn parts.join(\" | \");\n}\n\nexport function formatAsyncRunOutputPath(run: Pick<AsyncRunSummary, \"asyncDir\" | \"outputFile\">): string | undefined {\n\tif (!run.outputFile) return undefined;\n\treturn path.isAbsolute(run.outputFile) ? run.outputFile : path.join(run.asyncDir, run.outputFile);\n}\n\nexport function formatAsyncRunProgressLabel(\n\trun: Pick<AsyncRunSummary, \"mode\" | \"state\" | \"currentStep\" | \"chainStepCount\" | \"parallelGroups\" | \"steps\">,\n): string {\n\tconst stepCount = run.steps.length || 1;\n\tconst chainStepCount = run.chainStepCount ?? stepCount;\n\tconst groups = normalizeParallelGroups(run.parallelGroups, run.steps.length, chainStepCount);\n\tconst activeGroup =\n\t\trun.currentStep !== undefined\n\t\t\t? groups.find((group) => run.currentStep! >= group.start && run.currentStep! < group.start + group.count)\n\t\t\t: undefined;\n\tif (activeGroup) {\n\t\tconst groupSteps = run.steps.slice(activeGroup.start, activeGroup.start + activeGroup.count);\n\t\tconst groupLabel = formatParallelOutcome(groupSteps, activeGroup.count, { showRunning: run.state === \"running\" });\n\t\tif (run.mode === \"parallel\") return groupLabel;\n\t\treturn `step ${activeGroup.stepIndex + 1}/${chainStepCount} · parallel group: ${groupLabel}`;\n\t}\n\tif (run.mode === \"parallel\")\n\t\treturn formatParallelOutcome(run.steps, stepCount, { showRunning: run.state === \"running\" });\n\tif (run.mode === \"chain\" && run.currentStep !== undefined && groups.length > 0) {\n\t\tconst logicalStep = flatToLogicalStepIndex(run.currentStep, chainStepCount, groups);\n\t\treturn `step ${logicalStep + 1}/${chainStepCount}`;\n\t}\n\treturn run.currentStep !== undefined ? `step ${run.currentStep + 1}/${stepCount}` : `steps ${stepCount}`;\n}\n\nfunction formatRunHeader(run: AsyncRunSummary): string {\n\tconst stepLabel = formatAsyncRunProgressLabel(run);\n\tconst cwd = run.cwd ? shortenPath(run.cwd) : shortenPath(run.asyncDir);\n\tconst activity = formatActivityFacts(run);\n\tconst pending = run.pendingAppends\n\t\t? ` | ${run.pendingAppends} pending append${run.pendingAppends === 1 ? \"\" : \"s\"}`\n\t\t: \"\";\n\tconst context = contextModeLabel(run.context);\n\treturn `${run.id} | ${run.state}${activity ? ` | ${activity}` : \"\"} | ${run.mode}${context ? ` ${context}` : \"\"} | ${stepLabel}${pending} | ${cwd}`;\n}\n\nexport function formatAsyncRunList(runs: AsyncRunSummary[], heading = \"Active async runs\"): string {\n\tif (runs.length === 0) return `No ${heading.toLowerCase()}.`;\n\n\tconst lines = [`${heading}: ${runs.length}`, \"\"];\n\tfor (const run of runs) {\n\t\tlines.push(`- ${formatRunHeader(run)}`);\n\t\tfor (const step of run.steps) {\n\t\t\tlines.push(`  ${formatStepLine(step)}`);\n\t\t\tlines.push(...formatNestedRunStatusLines(step.children, { indent: \"    \", maxLines: 12 }));\n\t\t}\n\t\tconst attached = new Set(run.steps.flatMap((step) => step.children?.map((child) => child.id) ?? []));\n\t\tconst unattached = run.nestedChildren?.filter((child) => !attached.has(child.id)) ?? [];\n\t\tlines.push(...formatNestedRunStatusLines(unattached, { indent: \"  \", maxLines: 12 }));\n\t\tif (run.error) lines.push(`  Error: ${run.error}`);\n\t\tfor (const warning of run.nestedWarnings ?? []) lines.push(`  Warning: ${warning}`);\n\t\tconst outputPath = formatAsyncRunOutputPath(run);\n\t\tif (outputPath) lines.push(`  output: ${shortenPath(outputPath)}`);\n\t\tif (run.sessionFile) lines.push(`  session: ${shortenPath(run.sessionFile)}`);\n\t\tlines.push(\"\");\n\t}\n\treturn lines.join(\"\\n\").trimEnd();\n}\n"]}