import { formatTaskNotification, formatTaskNotificationDisplay } from './manager.js';
import { runTaskSubagent } from './runner.js';
import { readTaskSidechainMessages } from './sidechain.js';
import { failedTaskSubagentResult } from './types.js';
export class TaskRunCoordinator {
    options;
    /** Construct a coordinator bound to a single subagent run scope. */
    constructor(options) {
        this.options = options;
    }
    /** Run the subagent in the foreground, streaming progress and resolving with the final result. */
    runForeground(prompt, options) {
        return runTaskSubagent({
            ...this.baseRunOptions(prompt, this.options.userMessageId),
            signal: options.signal,
            onReady: (controls) => {
                if (this.options.scopeId) {
                    this.options.taskManager.attachSender(this.options.scopeId, this.options.agentId, controls.sendMessage);
                }
            },
            onProgress: (progress) => {
                this.updateProgress(progress);
                options.onProgress?.(progress);
            }
        });
    }
    /** Fire-and-forget run that updates the registry and notifies the parent on completion. */
    startDetached(prompt, options = {}) {
        const abortController = options.abortController ?? new AbortController();
        const timeoutId = setTimeout(() => abortController.abort(), this.options.timeoutMs);
        // Snapshot the runId BEFORE the run starts. Resume increments it, so a
        // late-arriving result from a previous run can be discarded by `finish`.
        const runState = this.getRegisteredRun(options, abortController);
        const runId = runState?.runId ?? 0;
        void runTaskSubagent({
            ...this.baseRunOptions(prompt, options.resumeFromSidechain ? undefined : this.options.userMessageId),
            initialMessages: this.getInitialMessages(options.resumeFromSidechain),
            appendSidechain: options.resumeFromSidechain,
            signal: abortController.signal,
            onReady: (controls) => {
                if (this.options.scopeId) {
                    this.options.taskManager.attachSender(this.options.scopeId, this.options.agentId, controls.sendMessage);
                }
            },
            onProgress: (progress) => this.updateProgress(progress)
        })
            .then((result) => this.finishAndNotify(runId, result))
            .catch((error) => this.finishAndNotify(runId, failedTaskSubagentResult(error, this.options.effectiveModel)))
            .finally(() => clearTimeout(timeoutId));
    }
    /** Finalize the currently registered run for this scope with the given result. */
    finishCurrent(result) {
        const task = this.getCurrentRun();
        return task ? this.finishRun(task.runId, result) : undefined;
    }
    /** Finalize a specific runId, deduct child usage, and return the registered task. */
    finishRun(runId, result) {
        const { scopeId, taskManager, agentId } = this.options;
        if (!scopeId)
            return undefined;
        const task = taskManager.finish(scopeId, agentId, result, runId);
        if (!task)
            return undefined;
        this.options.context.deductChildUsage({
            input: result.usage.input,
            output: result.usage.output,
            turns: result.usage.turns
        });
        return task;
    }
    /** Finalize a run and emit a one-shot notification to the parent loop. */
    finishAndNotify(runId, result) {
        const task = this.finishRun(runId, result);
        const { scopeId, taskManager, agentId, notifyParent } = this.options;
        if (!task || !scopeId)
            return;
        if (taskManager.markNotified(scopeId, agentId)) {
            notifyParent?.(formatTaskNotification(task), scopeId, formatTaskNotificationDisplay(task));
        }
    }
    /** Build the shared runner options used by both foreground and detached runs. */
    baseRunOptions(prompt, userMessageId) {
        const { agent, tools, context, taskCwd, permissionPolicy, agentId, sidechain } = this.options;
        return {
            task: prompt,
            agent,
            tools,
            context: {
                ...context,
                cwd: taskCwd,
                permissionPolicy
            },
            userMessageId,
            agentId,
            sidechain
        };
    }
    /** Load prior messages from the sidechain transcript when resuming a backgrounded task. */
    getInitialMessages(resumeFromSidechain) {
        if (!resumeFromSidechain || !this.options.sidechain?.sessionFile)
            return undefined;
        return readTaskSidechainMessages(this.options.sidechain.sessionFile);
    }
    /** Resolve (or restart) the registered task entry for a detached run. */
    getRegisteredRun(options, abortController) {
        const { scopeId, taskManager, agentId } = this.options;
        if (!scopeId)
            return undefined;
        const task = options.useRegisteredRun
            ? taskManager.get(scopeId, agentId)
            : taskManager.restart(scopeId, agentId, abortController);
        return task && task !== 'ambiguous' ? task : undefined;
    }
    /** Look up the current registered task for this scope/agent, ignoring ambiguous matches. */
    getCurrentRun() {
        const { scopeId, taskManager, agentId } = this.options;
        if (!scopeId)
            return undefined;
        const task = taskManager.get(scopeId, agentId);
        return task && task !== 'ambiguous' ? task : undefined;
    }
    /** Forward subagent progress events into the shared TaskManager registry. */
    updateProgress(progress) {
        const { scopeId, taskManager, agentId } = this.options;
        if (!scopeId)
            return;
        taskManager.updateProgress(scopeId, agentId, {
            toolUses: progress.toolCalls.length,
            transcriptFile: progress.sessionFile,
            toolCalls: progress.toolCalls,
            outputLines: progress.outputLines,
            activeToolUses: progress.activeToolUses,
            usage: progress.usage,
            resultText: progress.text
        });
    }
}
//# sourceMappingURL=lifecycle.js.map