{"version":3,"file":"auto-drain.d.ts","sourceRoot":"","sources":["../../../../src/runs/background/auto-drain.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,EAAE,KAAK,OAAO,EAAQ,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE/E,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,YAAY,EAEjB,MAAM,oBAAoB,CAAC;AAE5B,eAAO,MAAM,6BAA6B,QAAiB,CAAC;AAE5D,MAAM,WAAW,aAAa;IAC7B,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,CACN,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,IAAI,EAAE,gBAAgB,KAClB,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;IACvC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;CACxD;AAmBD,iGAAiG;AACjG,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA+B7E","sourcesContent":["import type { AgentToolResult } from \"@lpb-work/pi-agent-core\";\nimport { snapshotBackgroundWork } from \"../../api/background-work.ts\";\nimport { type Details, DIRS, type SubagentState } from \"../../shared/types.ts\";\nimport { listAsyncRuns } from \"./async-status.ts\";\nimport {\n\ttype SubagentWaitDeps,\n\ttype SubagentWaitParams,\n\ttype WaitEventBus,\n\twaitForSubagents,\n} from \"./subagent-wait.ts\";\n\nexport const DEFAULT_AUTO_DRAIN_TIMEOUT_MS = 30 * 60 * 1000;\n\nexport interface AutoDrainDeps {\n\tstate: SubagentState;\n\tevents?: WaitEventBus;\n\ttimeoutMs?: number;\n\tnow?: () => number;\n\twait?: (\n\t\tparams: SubagentWaitParams,\n\t\tsignal: AbortSignal | undefined,\n\t\tdeps: SubagentWaitDeps,\n\t) => Promise<AgentToolResult<Details>>;\n\thasWork?: (sessionId: string, nowMs: number) => boolean;\n}\n\nfunction resultText(value: AgentToolResult<Details>): string {\n\treturn value.content\n\t\t.map((part) => (part.type === \"text\" ? part.text : \"\"))\n\t\t.join(\" \")\n\t\t.trim();\n}\n\nfunction hasOutstandingWork(sessionId: string, nowMs: number): boolean {\n\tconst asyncRuns = listAsyncRuns(DIRS.async, {\n\t\tstates: [\"queued\", \"running\"],\n\t\tsessionId,\n\t\tresultsDir: DIRS.results,\n\t\tnow: () => nowMs,\n\t});\n\treturn asyncRuns.length > 0 || snapshotBackgroundWork(sessionId, nowMs).items.length > 0;\n}\n\n/** Drain all work owned by the current headless session, including work added while draining. */\nexport async function drainOutstandingWork(deps: AutoDrainDeps): Promise<void> {\n\tconst sessionId = deps.state.currentSessionId;\n\tif (!sessionId) throw new Error(\"Cannot auto-drain background work without an active session identity.\");\n\tconst now = deps.now ?? Date.now;\n\tconst timeoutMs = deps.timeoutMs ?? DEFAULT_AUTO_DRAIN_TIMEOUT_MS;\n\tif (!Number.isFinite(timeoutMs) || timeoutMs <= 0)\n\t\tthrow new Error(\"Auto-drain timeoutMs must be a positive finite number.\");\n\tconst deadlineAt = now() + timeoutMs;\n\tconst hasWork = deps.hasWork ?? hasOutstandingWork;\n\tconst wait = deps.wait ?? waitForSubagents;\n\n\twhile (hasWork(sessionId, now())) {\n\t\tconst remainingMs = deadlineAt - now();\n\t\tif (remainingMs <= 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`Auto-drain timed out after ${timeoutMs}ms with background work still active in session '${sessionId}'.`,\n\t\t\t);\n\t\t}\n\t\tconst waitResult = await wait({ all: true, timeoutMs: remainingMs }, undefined, {\n\t\t\tstate: deps.state,\n\t\t\tevents: deps.events,\n\t\t\tnow,\n\t\t\tstopOnAttention: false,\n\t\t\tfailOnFailedRuns: true,\n\t\t});\n\t\tif (waitResult.isError) {\n\t\t\tthrow new Error(\n\t\t\t\t`Auto-drain failed for session '${sessionId}': ${resultText(waitResult) || \"subagent_wait returned an error without details\"}.`,\n\t\t\t);\n\t\t}\n\t}\n}\n"]}