"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CliWorkerLauncher = void 0;
exports.buildWorkerInvocation = buildWorkerInvocation;
exports.buildWorkerContinuationIssueInvocation = buildWorkerContinuationIssueInvocation;
exports.buildWorkerIssueDraftInvocation = buildWorkerIssueDraftInvocation;
exports.buildWorkerTemplateDraftInvocation = buildWorkerTemplateDraftInvocation;
exports.buildWorkerTemplateUpdateInvocation = buildWorkerTemplateUpdateInvocation;
exports.buildWorkerAiWorkflowOptionAutofillInvocation = buildWorkerAiWorkflowOptionAutofillInvocation;
exports.buildWorkerFollowupProposalReviewInvocation = buildWorkerFollowupProposalReviewInvocation;
exports.buildWorkerWorkflowTemplateFitReviewInvocation = buildWorkerWorkflowTemplateFitReviewInvocation;
exports.buildWorkerWorkflowPlanReviewInvocation = buildWorkerWorkflowPlanReviewInvocation;
exports.buildWorkerPullRequestReviewNecessityInvocation = buildWorkerPullRequestReviewNecessityInvocation;
exports.buildWorkerEventHookInvocation = buildWorkerEventHookInvocation;
exports.buildWorkerEventHookDraftInvocation = buildWorkerEventHookDraftInvocation;
exports.buildWorkerCatalogSearchSelectionInvocation = buildWorkerCatalogSearchSelectionInvocation;
const control_plane_config_1 = require("../config/control-plane-config");
const command_1 = require("../core/command");
const catalog_1 = require("../i18n/catalog");
const catalog_search_selection_1 = require("./catalog-search-selection");
const cli_worker_launcher_support_1 = require("./cli-worker-launcher-support");
const decision_1 = require("./decision");
const errors_1 = require("./errors");
const prompt_1 = require("./prompt");
const structured_draft_metadata_1 = require("./structured-draft-metadata");
const pi_worker_runtime_1 = require("./pi-worker-runtime");
const pi_capability_review_bash_1 = require("./pi-capability-review-bash");
const decision_output_1 = require("./decision-output");
const WORKER_DECISION_REPAIR_ATTEMPTS = [2, 3];
const WORKER_DECISION_REPAIR_MAX_ATTEMPTS = 3;
const WORKER_SPECS = {
    codex: {
        command: "codex",
        buildArgs(input, prompt) {
            return [
                "exec",
                "--json",
                "--skip-git-repo-check",
                "--sandbox",
                "danger-full-access",
                "-C",
                input.workspacePath,
                prompt,
            ];
        },
    },
    claude: {
        command: "claude",
        buildArgs(_input, prompt) {
            return [
                "-p",
                "--output-format",
                "stream-json",
                "--permission-mode",
                "bypassPermissions",
                "--verbose",
                prompt,
            ];
        },
    },
};
const CATALOG_SEARCH_COMMON_ALLOWED_COMMANDS = [
    "alpaca catalog topics list",
];
const CATALOG_SEARCH_KIND_ALLOWED_COMMANDS = {
    skill: [
        "alpaca skill catalog list --include-system",
        "alpaca skill search",
        "alpaca skill list",
    ],
    mcp: [
        "alpaca mcp catalog list --include-system",
        "alpaca mcp search",
        "alpaca mcp list",
    ],
};
class CliWorkerLauncher {
    name;
    authProfile;
    customWorker;
    homeDirectory;
    env;
    locale;
    timeoutMs;
    noOutputTimeoutMs;
    constructor(input) {
        if (typeof input === "string") {
            this.name = input;
            this.authProfile = null;
            this.customWorker = null;
            this.homeDirectory = undefined;
            this.env = process.env;
            this.locale = catalog_1.DEFAULT_APP_LOCALE;
            this.timeoutMs = 60 * 60 * 1_000;
            this.noOutputTimeoutMs = null;
            return;
        }
        this.name = input.name;
        this.authProfile = input.authProfile ?? null;
        this.customWorker = input.customWorker ?? null;
        this.homeDirectory = input.homeDirectory;
        this.env = input.env ?? process.env;
        this.locale = input.locale ?? catalog_1.DEFAULT_APP_LOCALE;
        this.timeoutMs = input.timeoutMs ?? 60 * 60 * 1_000;
        this.noOutputTimeoutMs = input.noOutputTimeoutMs ?? null;
    }
    async ensureAvailable() {
        if (this.customWorker !== null) {
            await (0, pi_worker_runtime_1.ensurePiWorkerRuntimeAvailable)(this.locale);
            return;
        }
        if (!(0, control_plane_config_1.isBuiltInWorkerName)(this.name)) {
            throw new errors_1.WorkerUnavailableError(`Unknown worker: ${this.name}`, {
                publicMessage: (0, catalog_1.translate)(this.locale, "worker.error.unavailable"),
            });
        }
        const spec = WORKER_SPECS[this.name];
        const exists = await (0, command_1.commandExists)(spec.command);
        if (!exists) {
            throw new errors_1.WorkerUnavailableError((0, catalog_1.translate)(this.locale, "worker.error.commandNotInstalled", {
                command: spec.command,
            }), {
                publicMessage: (0, catalog_1.translate)(this.locale, "worker.error.unavailable"),
            });
        }
    }
    async checkAuth() {
        await this.ensureAvailable();
        return {
            name: `${this.name} auth`,
            status: "warning",
            message: (0, catalog_1.translate)(this.locale, "worker.error.authProbeNotImplemented"),
        };
    }
    async run(input) {
        const initialRun = await runWorkerCommand({
            name: this.name,
            input,
            authProfile: this.authProfile,
            customWorker: this.customWorker,
            homeDirectory: this.homeDirectory,
            env: this.env,
            locale: this.locale,
            timeoutMs: this.timeoutMs,
            noOutputTimeoutMs: this.noOutputTimeoutMs,
        });
        let totalWorkerDurationMs = initialRun.workerDurationMs;
        try {
            return finalizeWorkerResult({
                rawOutput: initialRun.stdout,
                workerDurationMs: totalWorkerDurationMs,
                locale: this.locale,
                workflow: input.workflow ?? null,
                validateDecision: input.validateDecision,
                repairTrace: {
                    attemptCount: 1,
                    repaired: false,
                    kind: null,
                    result: "not_needed",
                    initialIssues: [],
                },
            });
        }
        catch (error) {
            if (!(0, cli_worker_launcher_support_1.shouldRepairWorkerDecision)(error)) {
                addWorkerFailureDuration(error, totalWorkerDurationMs);
                throw error;
            }
            let currentError = error;
            let currentRawOutput = initialRun.stdout;
            let initialRepairContext = null;
            for (const attemptCount of WORKER_DECISION_REPAIR_ATTEMPTS) {
                if (attemptCount > 2 &&
                    !shouldRetryWorkerDecisionRepair(currentError)) {
                    addWorkerFailureDuration(currentError, totalWorkerDurationMs);
                    throw currentError;
                }
                const repairContext = (0, cli_worker_launcher_support_1.buildRepairContext)(currentRawOutput, currentError);
                initialRepairContext ??= repairContext;
                (0, cli_worker_launcher_support_1.emitRepairRetryStartDiagnostic)(input, repairContext, currentError, attemptCount, WORKER_DECISION_REPAIR_MAX_ATTEMPTS);
                let repairRun = null;
                try {
                    repairRun = await runWorkerCommand({
                        name: this.name,
                        input: {
                            ...input,
                            repairContext,
                        },
                        authProfile: this.authProfile,
                        customWorker: this.customWorker,
                        homeDirectory: this.homeDirectory,
                        env: this.env,
                        locale: this.locale,
                        timeoutMs: this.timeoutMs,
                        noOutputTimeoutMs: this.noOutputTimeoutMs,
                    });
                    totalWorkerDurationMs += repairRun.workerDurationMs;
                    const result = finalizeWorkerResult({
                        rawOutput: repairRun.stdout,
                        workerDurationMs: totalWorkerDurationMs,
                        locale: this.locale,
                        workflow: input.workflow ?? null,
                        validateDecision: input.validateDecision,
                        repairTrace: {
                            attemptCount,
                            repaired: true,
                            kind: initialRepairContext.kind,
                            result: "succeeded",
                            initialIssues: initialRepairContext.issues,
                        },
                    });
                    (0, cli_worker_launcher_support_1.emitRepairRetryEndDiagnostic)(input, repairContext, "succeeded", undefined, attemptCount, WORKER_DECISION_REPAIR_MAX_ATTEMPTS);
                    return result;
                }
                catch (repairError) {
                    if (repairRun === null && (0, errors_1.isWorkerFailureError)(repairError)) {
                        totalWorkerDurationMs += repairError.workerDurationMs;
                    }
                    (0, cli_worker_launcher_support_1.emitRepairRetryEndDiagnostic)(input, repairContext, "failed", repairError, attemptCount, WORKER_DECISION_REPAIR_MAX_ATTEMPTS);
                    if (attemptCount >= WORKER_DECISION_REPAIR_MAX_ATTEMPTS ||
                        !shouldRetryWorkerDecisionRepair(repairError)) {
                        addWorkerFailureDuration(repairError, totalWorkerDurationMs);
                        throw repairError;
                    }
                    currentError = repairError;
                    currentRawOutput = repairRun?.stdout ?? "";
                }
            }
            addWorkerFailureDuration(currentError, totalWorkerDurationMs);
            throw currentError;
        }
    }
    async runContinuationIssueSelection(input) {
        const run = await runWorkerContinuationIssueSelectionCommand({
            name: this.name,
            input,
            authProfile: this.authProfile,
            customWorker: this.customWorker,
            homeDirectory: this.homeDirectory,
            env: this.env,
            locale: this.locale,
            timeoutMs: this.timeoutMs,
            noOutputTimeoutMs: this.noOutputTimeoutMs,
        });
        return {
            rawOutput: run.stdout,
            decision: (0, decision_1.parseWorkerContinuationIssueDecision)(run.stdout, this.locale),
        };
    }
    async runIssueDraft(input) {
        return this.runStructuredDraft(input, ISSUE_DRAFT_OPERATION);
    }
    async runAiWorkflowOptionAutofill(input) {
        return this.runStructuredDraft(input, AI_WORKFLOW_OPTION_AUTOFILL_OPERATION);
    }
    async runFollowupProposalReview(input) {
        return this.runStructuredDraft(input, FOLLOWUP_PROPOSAL_REVIEW_OPERATION);
    }
    async runWorkflowTemplateFitReview(input) {
        return this.runStructuredDraft(input, WORKFLOW_TEMPLATE_FIT_REVIEW_OPERATION);
    }
    async runWorkflowPlanReview(input) {
        return this.runStructuredDraft(input, WORKFLOW_PLAN_REVIEW_OPERATION);
    }
    async runPullRequestReviewNecessity(input) {
        return this.runStructuredDraft(input, PULL_REQUEST_REVIEW_NECESSITY_OPERATION);
    }
    async runTemplateDraft(input) {
        return this.runStructuredDraft(input, TEMPLATE_DRAFT_OPERATION);
    }
    async runTemplateUpdate(input) {
        return this.runStructuredDraft(input, TEMPLATE_UPDATE_OPERATION);
    }
    async runCatalogSearchSelection(input) {
        const run = await runWorkerCatalogSearchSelectionCommand({
            name: this.name,
            input,
            authProfile: this.authProfile,
            customWorker: this.customWorker,
            homeDirectory: this.homeDirectory,
            env: this.env,
            locale: this.locale,
            timeoutMs: this.timeoutMs,
            noOutputTimeoutMs: this.noOutputTimeoutMs,
        });
        return {
            rawOutput: run.stdout,
            selection: (0, catalog_search_selection_1.parseWorkerCatalogSearchSelection)(run.stdout, this.locale),
            workerDurationMs: run.workerDurationMs,
        };
    }
    async runEventHook(input) {
        const run = await runWorkerEventHookCommand({
            name: this.name,
            input,
            authProfile: this.authProfile,
            customWorker: this.customWorker,
            homeDirectory: this.homeDirectory,
            env: this.env,
            locale: this.locale,
            timeoutMs: this.timeoutMs,
        });
        return {
            rawOutput: run.stdout,
            result: parseWorkerEventHookResultAfterAttempt(run, this.locale),
            workerDurationMs: run.workerDurationMs,
        };
    }
    async runEventHookDraft(input) {
        return this.runStructuredDraft(input, EVENT_HOOK_DRAFT_OPERATION, {
            noOutputTimeoutMs: null,
        });
    }
    async runStructuredDraft(draftInput, operation, options = {}) {
        return runStructuredDraftOperation({
            name: this.name,
            draftInput,
            authProfile: this.authProfile,
            customWorker: this.customWorker,
            homeDirectory: this.homeDirectory,
            env: this.env,
            locale: this.locale,
            timeoutMs: this.timeoutMs,
            noOutputTimeoutMs: options.noOutputTimeoutMs === undefined
                ? this.noOutputTimeoutMs
                : options.noOutputTimeoutMs,
            operation,
        });
    }
}
exports.CliWorkerLauncher = CliWorkerLauncher;
function parseWorkerEventHookResultAfterAttempt(run, locale) {
    try {
        return (0, decision_1.parseWorkerEventHookResult)(run.stdout, locale);
    }
    catch (error) {
        if ((0, errors_1.isWorkerFailureError)(error)) {
            error.attempted = true;
            error.workerDurationMs = run.workerDurationMs;
        }
        throw error;
    }
}
function addWorkerFailureDuration(error, workerDurationMs) {
    if (!(0, errors_1.isWorkerFailureError)(error)) {
        return;
    }
    error.workerDurationMs = workerDurationMs;
}
function shouldRetryWorkerDecisionRepair(error) {
    return ((0, cli_worker_launcher_support_1.shouldRepairWorkerDecision)(error) &&
        [...error.validationIssues, ...error.issues].some((issue) => issue.code === "too_big"));
}
function buildWorkerInvocation(name, input, authProfile = null, baseEnv = process.env, locale = catalog_1.DEFAULT_APP_LOCALE) {
    const prompt = (0, prompt_1.buildWorkerPrompt)(name, input);
    return buildWorkerCommandInvocation({
        name,
        input,
        prompt,
        authProfile,
        baseEnv,
        locale,
    });
}
function buildWorkerContinuationIssueInvocation(name, input, authProfile = null, baseEnv = process.env, locale = catalog_1.DEFAULT_APP_LOCALE) {
    const prompt = (0, prompt_1.buildWorkerContinuationIssuePrompt)(name, input.input, input.systemPrompts);
    return buildWorkerCommandInvocation({
        name,
        input: {
            workspacePath: input.workspacePath,
        },
        prompt,
        authProfile,
        baseEnv,
        locale,
    });
}
function buildWorkerIssueDraftInvocation(name, input, authProfile = null, baseEnv = process.env, locale = catalog_1.DEFAULT_APP_LOCALE) {
    return buildWorkerStructuredDraftPromptInvocation(name, input, prompt_1.buildWorkerIssueDraftPrompt, authProfile, baseEnv, locale);
}
function buildWorkerTemplateDraftInvocation(name, input, authProfile = null, baseEnv = process.env, locale = catalog_1.DEFAULT_APP_LOCALE) {
    return buildWorkerStructuredDraftPromptInvocation(name, input, prompt_1.buildWorkerTemplateDraftPrompt, authProfile, baseEnv, locale);
}
function buildWorkerTemplateUpdateInvocation(name, input, authProfile = null, baseEnv = process.env, locale = catalog_1.DEFAULT_APP_LOCALE) {
    return buildWorkerStructuredDraftPromptInvocation(name, input, prompt_1.buildWorkerTemplateUpdatePrompt, authProfile, baseEnv, locale);
}
function buildWorkerAiWorkflowOptionAutofillInvocation(name, input, authProfile = null, baseEnv = process.env, locale = catalog_1.DEFAULT_APP_LOCALE) {
    return buildWorkerStructuredDraftPromptInvocation(name, input, prompt_1.buildWorkerAiWorkflowOptionAutofillPrompt, authProfile, baseEnv, locale);
}
function buildWorkerFollowupProposalReviewInvocation(name, input, authProfile = null, baseEnv = process.env, locale = catalog_1.DEFAULT_APP_LOCALE) {
    return buildWorkerStructuredDraftPromptInvocation(name, input, prompt_1.buildWorkerFollowupProposalReviewPrompt, authProfile, baseEnv, locale);
}
function buildWorkerWorkflowTemplateFitReviewInvocation(name, input, authProfile = null, baseEnv = process.env, locale = catalog_1.DEFAULT_APP_LOCALE) {
    return buildWorkerStructuredDraftPromptInvocation(name, input, prompt_1.buildWorkerWorkflowTemplateFitReviewPrompt, authProfile, baseEnv, locale, "read-only");
}
function buildWorkerWorkflowPlanReviewInvocation(name, input, authProfile = null, baseEnv = process.env, locale = catalog_1.DEFAULT_APP_LOCALE) {
    return buildWorkerStructuredDraftPromptInvocation(name, input, prompt_1.buildWorkerWorkflowPlanReviewPrompt, authProfile, baseEnv, locale, "capability-review-read-only");
}
function buildWorkerPullRequestReviewNecessityInvocation(name, input, authProfile = null, baseEnv = process.env, locale = catalog_1.DEFAULT_APP_LOCALE) {
    return buildWorkerStructuredDraftPromptInvocation(name, input, prompt_1.buildWorkerPullRequestReviewNecessityPrompt, authProfile, baseEnv, locale, "read-only");
}
function buildWorkerEventHookInvocation(name, input, authProfile = null, baseEnv = process.env, locale = catalog_1.DEFAULT_APP_LOCALE) {
    const prompt = (0, prompt_1.buildWorkerEventHookPrompt)(name, input);
    return buildWorkerCommandInvocation({
        name,
        input: {
            workspacePath: input.workspacePath,
        },
        prompt,
        authProfile,
        baseEnv,
        locale,
    });
}
function buildWorkerEventHookDraftInvocation(name, input, authProfile = null, baseEnv = process.env, locale = catalog_1.DEFAULT_APP_LOCALE) {
    return buildWorkerStructuredDraftPromptInvocation(name, input, prompt_1.buildWorkerEventHookDraftPrompt, authProfile, baseEnv, locale);
}
function buildWorkerCatalogSearchSelectionInvocation(name, input, authProfile = null, baseEnv = process.env, locale = catalog_1.DEFAULT_APP_LOCALE) {
    const prompt = (0, catalog_search_selection_1.buildWorkerCatalogSearchSelectionPrompt)(name, input);
    return buildWorkerCommandInvocation({
        name,
        input: {
            workspacePath: input.workspacePath,
        },
        prompt,
        authProfile,
        baseEnv,
        locale,
        commandPolicy: "catalog-search-read-only",
        catalogSearchKind: input.kind,
    });
}
function buildWorkerStructuredDraftPromptInvocation(name, input, buildPrompt, authProfile, baseEnv, locale, commandPolicy) {
    return buildStructuredDraftInvocation({
        name,
        input,
        buildPrompt,
        authProfile,
        baseEnv,
        locale,
        ...(commandPolicy === undefined ? {} : { commandPolicy }),
    });
}
function buildStructuredDraftInvocation(input) {
    const prompt = input.buildPrompt(input.name, input.input, input.input.repairContext ?? null);
    return buildWorkerCommandInvocation({
        name: input.name,
        input: {
            workspacePath: input.input.workspacePath,
        },
        prompt,
        authProfile: input.authProfile,
        baseEnv: input.baseEnv,
        locale: input.locale,
        ...(input.commandPolicy === undefined
            ? {}
            : { commandPolicy: input.commandPolicy }),
    });
}
function buildWorkerCommandInvocation(input) {
    if (!(0, control_plane_config_1.isBuiltInWorkerName)(input.name)) {
        throw new errors_1.WorkerUnavailableError(`Unknown worker: ${input.name}`, {
            publicMessage: (0, catalog_1.translate)(input.locale, "worker.error.unavailable"),
        });
    }
    const spec = WORKER_SPECS[input.name];
    const args = buildWorkerCommandArgs({
        name: input.name,
        input: input.input,
        prompt: input.prompt,
        defaultArgs: spec.buildArgs,
        ...(input.commandPolicy === undefined
            ? {}
            : { commandPolicy: input.commandPolicy }),
        ...(input.catalogSearchKind === undefined
            ? {}
            : { catalogSearchKind: input.catalogSearchKind }),
    });
    return {
        command: spec.command,
        args,
        env: (0, cli_worker_launcher_support_1.buildWorkerEnvironment)(input.authProfile, input.baseEnv, input.locale),
    };
}
function buildWorkerCommandArgs(input) {
    switch (input.commandPolicy) {
        case "capability-review-read-only":
            return buildCapabilityReviewWorkerArgs(input.name, input.input, input.prompt);
        case "catalog-search-read-only":
            if (input.catalogSearchKind === undefined) {
                throw new Error("Catalog search command policy requires search kind.");
            }
            return buildReadOnlyCatalogSearchWorkerArgs(input.name, input.input, input.prompt, input.catalogSearchKind);
        case "read-only":
            return buildReadOnlyWorkerArgs(input.name, input.input, input.prompt);
        case undefined:
            return input.defaultArgs(input.input, input.prompt);
    }
    throw new Error(`Unsupported worker command policy: ${input.commandPolicy}`);
}
function buildCapabilityReviewWorkerArgs(name, input, prompt) {
    switch (name) {
        case "codex":
            return [
                "exec",
                "--json",
                "--skip-git-repo-check",
                "--sandbox",
                "read-only",
                "-C",
                input.workspacePath,
                prompt,
            ];
        case "claude":
            return [
                "-p",
                "--output-format",
                "stream-json",
                "--permission-mode",
                "default",
                "--allowedTools",
                renderClaudeAllowedCapabilityReviewTools(),
                "--verbose",
                prompt,
            ];
    }
    throw new Error(`Unsupported built-in worker: ${name}`);
}
function buildReadOnlyWorkerArgs(name, input, prompt) {
    switch (name) {
        case "codex":
            return [
                "exec",
                "--json",
                "--skip-git-repo-check",
                "--sandbox",
                "read-only",
                "-C",
                input.workspacePath,
                prompt,
            ];
        case "claude":
            return [
                "-p",
                "--output-format",
                "stream-json",
                "--permission-mode",
                "default",
                "--tools",
                "",
                "--verbose",
                prompt,
            ];
    }
    throw new Error(`Unsupported built-in worker: ${name}`);
}
function buildReadOnlyCatalogSearchWorkerArgs(name, input, prompt, kind) {
    switch (name) {
        case "codex":
            return [
                "exec",
                "--json",
                "--skip-git-repo-check",
                "--sandbox",
                "read-only",
                "-C",
                input.workspacePath,
                prompt,
            ];
        case "claude":
            return [
                "-p",
                "--output-format",
                "stream-json",
                "--permission-mode",
                "default",
                "--allowedTools",
                renderClaudeAllowedCatalogSearchTools(kind),
                "--verbose",
                prompt,
            ];
    }
    throw new Error(`Unsupported built-in worker: ${name}`);
}
function renderClaudeAllowedCatalogSearchTools(kind) {
    return [
        ...CATALOG_SEARCH_COMMON_ALLOWED_COMMANDS,
        ...CATALOG_SEARCH_KIND_ALLOWED_COMMANDS[kind],
    ]
        .map((command) => `Bash(${command}:*)`)
        .join(",");
}
function renderClaudeAllowedCapabilityReviewTools() {
    return pi_capability_review_bash_1.CAPABILITY_REVIEW_ALLOWED_COMMANDS.map((command) => `Bash(${command}:*)`).join(",");
}
function finalizeWorkerResult(input) {
    const decision = (0, decision_1.parseWorkerDecision)(input.rawOutput, {
        locale: input.locale,
        workflow: input.workflow ?? null,
    });
    (0, cli_worker_launcher_support_1.validateDecision)(decision, input.validateDecision);
    return {
        rawOutput: input.rawOutput,
        decision,
        workerDurationMs: input.workerDurationMs,
        ...(input.repairTrace !== undefined
            ? { repairTrace: input.repairTrace }
            : {}),
    };
}
const ISSUE_DRAFT_OPERATION = createStructuredDraftOperation({
    buildInvocation: buildWorkerIssueDraftInvocation,
    buildPrompt: prompt_1.buildWorkerIssueDraftPrompt,
    parseDecision: (rawOutput, input, locale) => (0, decision_1.parseWorkerIssueDraftDecision)(rawOutput, {
        draftInput: input,
        locale,
    }),
    resultKey: "draft",
    parseErrorConstructor: decision_1.WorkerIssueDraftParseError,
    metadata: structured_draft_metadata_1.STRUCTURED_DRAFT_METADATA.issueDraft,
});
const AI_WORKFLOW_OPTION_AUTOFILL_OPERATION = createStructuredDraftOperation({
    buildInvocation: buildWorkerAiWorkflowOptionAutofillInvocation,
    buildPrompt: prompt_1.buildWorkerAiWorkflowOptionAutofillPrompt,
    parseDecision: (rawOutput, input, locale) => (0, decision_1.parseWorkerAiWorkflowOptionAutofillDecision)(rawOutput, {
        autofillInput: input,
        locale,
    }),
    resultKey: "autofill",
    parseErrorConstructor: decision_1.WorkerAiWorkflowOptionAutofillParseError,
    metadata: structured_draft_metadata_1.STRUCTURED_DRAFT_METADATA.aiWorkflowOptionAutofill,
});
const FOLLOWUP_PROPOSAL_REVIEW_OPERATION = createStructuredDraftOperation({
    buildInvocation: buildWorkerFollowupProposalReviewInvocation,
    buildPrompt: prompt_1.buildWorkerFollowupProposalReviewPrompt,
    parseDecision: (rawOutput, input, locale) => (0, decision_1.parseWorkerFollowupProposalReviewDecision)(rawOutput, {
        reviewInput: input,
        locale,
    }),
    resultKey: "review",
    parseErrorConstructor: decision_1.WorkerFollowupProposalReviewParseError,
    metadata: structured_draft_metadata_1.STRUCTURED_DRAFT_METADATA.followupProposalReview,
});
const WORKFLOW_TEMPLATE_FIT_REVIEW_OPERATION = createStructuredDraftOperation({
    buildInvocation: buildWorkerWorkflowTemplateFitReviewInvocation,
    buildPrompt: prompt_1.buildWorkerWorkflowTemplateFitReviewPrompt,
    commandPolicy: "read-only",
    parseDecision: (rawOutput, input, locale) => (0, decision_1.parseWorkerWorkflowTemplateFitReviewDecision)(rawOutput, {
        reviewInput: input,
        locale,
    }),
    resultKey: "review",
    parseErrorConstructor: decision_1.WorkerWorkflowTemplateFitReviewParseError,
    metadata: structured_draft_metadata_1.STRUCTURED_DRAFT_METADATA.workflowTemplateFitReview,
});
const WORKFLOW_PLAN_REVIEW_OPERATION = createStructuredDraftOperation({
    buildInvocation: buildWorkerWorkflowPlanReviewInvocation,
    buildPrompt: prompt_1.buildWorkerWorkflowPlanReviewPrompt,
    commandPolicy: "capability-review-read-only",
    parseDecision: (rawOutput, input, locale) => (0, decision_1.parseWorkerWorkflowPlanReviewDecision)(rawOutput, {
        reviewInput: input,
        locale,
    }),
    resultKey: "review",
    parseErrorConstructor: decision_1.WorkerWorkflowPlanReviewParseError,
    metadata: structured_draft_metadata_1.STRUCTURED_DRAFT_METADATA.workflowPlanReview,
});
const PULL_REQUEST_REVIEW_NECESSITY_OPERATION = createStructuredDraftOperation({
    buildInvocation: buildWorkerPullRequestReviewNecessityInvocation,
    buildPrompt: prompt_1.buildWorkerPullRequestReviewNecessityPrompt,
    commandPolicy: "read-only",
    parseDecision: (rawOutput, input, locale) => (0, decision_1.parseWorkerPullRequestReviewNecessityDecision)(rawOutput, {
        decisionInput: input,
        locale,
    }),
    resultKey: "decision",
    parseErrorConstructor: decision_1.WorkerPullRequestReviewNecessityParseError,
    metadata: structured_draft_metadata_1.STRUCTURED_DRAFT_METADATA.pullRequestReviewNecessity,
});
const EVENT_HOOK_DRAFT_OPERATION = createStructuredDraftOperation({
    buildInvocation: buildWorkerEventHookDraftInvocation,
    buildPrompt: prompt_1.buildWorkerEventHookDraftPrompt,
    parseDecision: (rawOutput, input, locale) => (0, decision_1.parseWorkerEventHookDraftDecision)(rawOutput, {
        draftInput: input,
        locale,
    }),
    resultKey: "draft",
    parseErrorConstructor: decision_1.WorkerEventHookDraftParseError,
    metadata: structured_draft_metadata_1.STRUCTURED_DRAFT_METADATA.eventHookDraft,
});
const TEMPLATE_DRAFT_OPERATION = createStructuredDraftOperation({
    buildInvocation: buildWorkerTemplateDraftInvocation,
    buildPrompt: prompt_1.buildWorkerTemplateDraftPrompt,
    parseDecision: (rawOutput, input, locale) => (0, decision_1.parseWorkerTemplateDraftDecision)(rawOutput, {
        draftInput: input,
        locale,
    }),
    resultKey: "draft",
    parseErrorConstructor: decision_1.WorkerTemplateDraftParseError,
    metadata: structured_draft_metadata_1.STRUCTURED_DRAFT_METADATA.templateDraft,
});
const TEMPLATE_UPDATE_OPERATION = createStructuredDraftOperation({
    buildInvocation: buildWorkerTemplateUpdateInvocation,
    buildPrompt: prompt_1.buildWorkerTemplateUpdatePrompt,
    parseDecision: (rawOutput, input, locale) => (0, decision_1.parseWorkerTemplateUpdateDecision)(rawOutput, {
        updateInput: input,
        locale,
    }),
    resultKey: "update",
    parseErrorConstructor: decision_1.WorkerTemplateUpdateParseError,
    metadata: structured_draft_metadata_1.STRUCTURED_DRAFT_METADATA.templateUpdate,
});
function createStructuredDraftOperation(input) {
    return {
        buildInvocation: input.buildInvocation,
        buildPrompt: input.buildPrompt,
        ...(input.commandPolicy === undefined
            ? {}
            : { commandPolicy: input.commandPolicy }),
        parseDecision: input.parseDecision,
        resultKey: input.resultKey,
        isParseError: (error) => error instanceof input.parseErrorConstructor,
        metadata: input.metadata,
    };
}
function withStructuredRepairTrace(result, repairTrace) {
    return {
        ...result,
        ...(repairTrace !== undefined ? { repairTrace } : {}),
    };
}
function runStructuredDraftOperation(input) {
    const operation = input.operation;
    return runStructuredDraftWithRepair({
        draftInput: input.draftInput,
        runCommand: (draftInput) => runWorkerStructuredDraftCommand({
            name: input.name,
            input: draftInput,
            authProfile: input.authProfile,
            env: input.env,
            locale: input.locale,
            timeoutMs: input.timeoutMs,
            noOutputTimeoutMs: input.noOutputTimeoutMs,
            customWorker: input.customWorker,
            homeDirectory: input.homeDirectory,
            buildPrompt: operation.buildPrompt,
            buildInvocation: operation.buildInvocation,
            ...(operation.commandPolicy === undefined
                ? {}
                : { commandPolicy: operation.commandPolicy }),
        }),
        finalize: ({ rawOutput, draftInput, repairTrace, workerDurationMs }) => finalizeStructuredDraftResult({
            rawOutput,
            parsed: operation.parseDecision(rawOutput, draftInput, input.locale),
            resultKey: operation.resultKey,
            repairTrace,
            workerDurationMs,
        }),
        isParseError: operation.isParseError,
        metadata: operation.metadata,
    });
}
function finalizeStructuredDraftResult(input) {
    return withStructuredRepairTrace({
        rawOutput: input.rawOutput,
        [input.resultKey]: input.parsed,
        workerDurationMs: input.workerDurationMs,
    }, input.repairTrace);
}
async function runStructuredDraftWithRepair(input) {
    const initialRun = await input.runCommand(input.draftInput);
    try {
        return input.finalize({
            rawOutput: initialRun.stdout,
            workerDurationMs: initialRun.workerDurationMs,
            draftInput: input.draftInput,
            repairTrace: {
                attemptCount: 1,
                repaired: false,
                kind: null,
                result: "not_needed",
                initialIssues: [],
            },
        });
    }
    catch (error) {
        if (!input.isParseError(error)) {
            throw error;
        }
        const repairContext = (0, cli_worker_launcher_support_1.buildStructuredDraftRepairContext)(initialRun.stdout, error, (0, structured_draft_metadata_1.readStructuredDraftRepairKind)(error, input.metadata));
        (0, cli_worker_launcher_support_1.emitStructuredDraftRepairRetryStartDiagnostic)(input.draftInput, input.metadata.diagnosticLabel, repairContext, error.message);
        try {
            const repairRun = await input.runCommand({
                ...input.draftInput,
                repairContext,
            });
            const result = input.finalize({
                rawOutput: repairRun.stdout,
                workerDurationMs: initialRun.workerDurationMs + repairRun.workerDurationMs,
                draftInput: input.draftInput,
                repairTrace: {
                    attemptCount: 2,
                    repaired: true,
                    kind: repairContext.kind,
                    result: "succeeded",
                    initialIssues: repairContext.issues,
                },
            });
            (0, cli_worker_launcher_support_1.emitStructuredDraftRepairRetryEndDiagnostic)(input.draftInput, input.metadata.diagnosticLabel, repairContext, "succeeded");
            return result;
        }
        catch (repairError) {
            (0, cli_worker_launcher_support_1.emitStructuredDraftRepairRetryEndDiagnostic)(input.draftInput, input.metadata.diagnosticLabel, repairContext, "failed", repairError);
            throw repairError;
        }
    }
}
async function runWorkerCommand(input) {
    if (input.customWorker !== null) {
        return runCustomWorkerPromptCommand({
            name: input.name,
            customWorker: input.customWorker,
            prompt: (0, prompt_1.buildWorkerPrompt)(input.name, input.input),
            workspacePath: input.input.workspacePath,
            env: input.env,
            locale: input.locale,
            homeDirectory: input.homeDirectory,
            timeoutMs: input.timeoutMs,
            noOutputTimeoutMs: input.noOutputTimeoutMs,
            onStdoutChunk: input.input.onStdoutChunk,
            onStderrChunk: input.input.onStderrChunk,
        });
    }
    const invocation = buildWorkerInvocation(input.name, input.input, input.authProfile, input.env, input.locale);
    const startedAtMs = Date.now();
    try {
        const result = await (0, command_1.runStreamingCommand)({
            command: invocation.command,
            args: invocation.args,
            cwd: input.input.workspacePath,
            timeoutMs: input.timeoutMs,
            noOutputTimeoutMs: input.noOutputTimeoutMs,
            locale: input.locale,
            ...(invocation.env ? { env: invocation.env } : {}),
        }, {
            onStdoutChunk: input.input.onStdoutChunk,
            onStderrChunk: input.input.onStderrChunk,
        });
        assertWorkerOutputSucceeded(invocation.command, result.stdout, input.locale);
        return {
            stdout: result.stdout,
            workerDurationMs: Date.now() - startedAtMs,
        };
    }
    catch (error) {
        const wrapped = (0, cli_worker_launcher_support_1.wrapWorkerRunError)(invocation.command, error, input.locale);
        if (wrapped instanceof Error && "workerDurationMs" in wrapped) {
            wrapped.workerDurationMs = Date.now() - startedAtMs;
        }
        throw wrapped;
    }
}
async function runWorkerContinuationIssueSelectionCommand(input) {
    if (input.customWorker !== null) {
        return runCustomWorkerPromptCommand({
            name: input.name,
            customWorker: input.customWorker,
            prompt: (0, prompt_1.buildWorkerContinuationIssuePrompt)(input.name, input.input.input, input.input.systemPrompts),
            workspacePath: input.input.workspacePath,
            env: input.env,
            locale: input.locale,
            homeDirectory: input.homeDirectory,
            timeoutMs: input.timeoutMs,
            noOutputTimeoutMs: input.noOutputTimeoutMs,
            onStdoutChunk: input.input.onStdoutChunk,
            onStderrChunk: input.input.onStderrChunk,
        });
    }
    const invocation = buildWorkerContinuationIssueInvocation(input.name, input.input, input.authProfile, input.env, input.locale);
    try {
        const result = await (0, command_1.runStreamingCommand)({
            command: invocation.command,
            args: invocation.args,
            cwd: input.input.workspacePath,
            timeoutMs: input.timeoutMs,
            noOutputTimeoutMs: input.noOutputTimeoutMs,
            locale: input.locale,
            ...(invocation.env ? { env: invocation.env } : {}),
        }, {
            onStdoutChunk: input.input.onStdoutChunk,
            onStderrChunk: input.input.onStderrChunk,
        });
        assertWorkerOutputSucceeded(invocation.command, result.stdout, input.locale);
        return { stdout: result.stdout };
    }
    catch (error) {
        throw (0, cli_worker_launcher_support_1.wrapWorkerRunError)(invocation.command, error, input.locale);
    }
}
async function runWorkerEventHookCommand(input) {
    if (input.customWorker !== null) {
        return runCustomWorkerPromptCommand({
            name: input.name,
            customWorker: input.customWorker,
            prompt: (0, prompt_1.buildWorkerEventHookPrompt)(input.name, input.input),
            workspacePath: input.input.workspacePath,
            env: input.env,
            locale: input.locale,
            homeDirectory: input.homeDirectory,
            timeoutMs: input.timeoutMs,
            noOutputTimeoutMs: null,
            onStdoutChunk: input.input.onStdoutChunk,
            onStderrChunk: input.input.onStderrChunk,
        });
    }
    const invocation = buildWorkerEventHookInvocation(input.name, input.input, input.authProfile, input.env, input.locale);
    const startedAtMs = Date.now();
    try {
        const result = await (0, command_1.runStreamingCommand)({
            command: invocation.command,
            args: invocation.args,
            cwd: input.input.workspacePath,
            timeoutMs: input.timeoutMs,
            locale: input.locale,
            ...(invocation.env ? { env: invocation.env } : {}),
        }, {
            onStdoutChunk: input.input.onStdoutChunk,
            onStderrChunk: input.input.onStderrChunk,
        });
        assertWorkerOutputSucceeded(invocation.command, result.stdout, input.locale);
        return {
            stdout: result.stdout,
            workerDurationMs: Date.now() - startedAtMs,
        };
    }
    catch (error) {
        const wrapped = (0, cli_worker_launcher_support_1.wrapWorkerRunError)(invocation.command, error, input.locale);
        if (wrapped instanceof Error && "workerDurationMs" in wrapped) {
            wrapped.workerDurationMs = Date.now() - startedAtMs;
        }
        throw wrapped;
    }
}
async function runWorkerCatalogSearchSelectionCommand(input) {
    if (input.customWorker !== null) {
        return runCustomWorkerPromptCommand({
            name: input.name,
            customWorker: input.customWorker,
            prompt: (0, catalog_search_selection_1.buildWorkerCatalogSearchSelectionPrompt)(input.name, input.input),
            workspacePath: input.input.workspacePath,
            env: input.env,
            locale: input.locale,
            homeDirectory: input.homeDirectory,
            timeoutMs: input.timeoutMs,
            noOutputTimeoutMs: input.noOutputTimeoutMs,
            commandPolicy: "catalog-search-read-only",
            onStdoutChunk: input.input.onStdoutChunk,
            onStderrChunk: input.input.onStderrChunk,
        });
    }
    const invocation = buildWorkerCatalogSearchSelectionInvocation(input.name, input.input, input.authProfile, input.env, input.locale);
    const startedAtMs = Date.now();
    try {
        const result = await (0, command_1.runStreamingCommand)({
            command: invocation.command,
            args: invocation.args,
            cwd: input.input.workspacePath,
            timeoutMs: input.timeoutMs,
            noOutputTimeoutMs: input.noOutputTimeoutMs,
            locale: input.locale,
            ...(invocation.env ? { env: invocation.env } : {}),
        }, {
            onStdoutChunk: input.input.onStdoutChunk,
            onStderrChunk: input.input.onStderrChunk,
        });
        assertWorkerOutputSucceeded(invocation.command, result.stdout, input.locale);
        return {
            stdout: result.stdout,
            workerDurationMs: Date.now() - startedAtMs,
        };
    }
    catch (error) {
        const wrapped = (0, cli_worker_launcher_support_1.wrapWorkerRunError)(invocation.command, error, input.locale);
        if (wrapped instanceof Error && "workerDurationMs" in wrapped) {
            wrapped.workerDurationMs = Date.now() - startedAtMs;
        }
        throw wrapped;
    }
}
async function runWorkerStructuredDraftCommand(input) {
    if (input.customWorker !== null) {
        return runCustomWorkerPromptCommand({
            name: input.name,
            customWorker: input.customWorker,
            prompt: input.buildPrompt(input.name, input.input, input.input.repairContext ?? null),
            workspacePath: input.input.workspacePath,
            env: input.env,
            locale: input.locale,
            homeDirectory: input.homeDirectory,
            timeoutMs: input.timeoutMs,
            noOutputTimeoutMs: input.noOutputTimeoutMs,
            ...(input.commandPolicy === undefined
                ? {}
                : { commandPolicy: input.commandPolicy }),
            onStdoutChunk: input.input.onStdoutChunk,
            onStderrChunk: input.input.onStderrChunk,
        });
    }
    const invocation = input.buildInvocation(input.name, input.input, input.authProfile, input.env, input.locale);
    const startedAtMs = Date.now();
    try {
        const result = await (0, command_1.runStreamingCommand)({
            command: invocation.command,
            args: invocation.args,
            cwd: input.input.workspacePath,
            timeoutMs: input.timeoutMs,
            noOutputTimeoutMs: input.noOutputTimeoutMs,
            locale: input.locale,
            ...(invocation.env ? { env: invocation.env } : {}),
        }, {
            onStdoutChunk: input.input.onStdoutChunk,
            onStderrChunk: input.input.onStderrChunk,
        });
        assertWorkerOutputSucceeded(invocation.command, result.stdout, input.locale);
        return {
            stdout: result.stdout,
            workerDurationMs: Date.now() - startedAtMs,
        };
    }
    catch (error) {
        const wrapped = (0, cli_worker_launcher_support_1.wrapWorkerRunError)(invocation.command, error, input.locale);
        if (wrapped instanceof Error && "workerDurationMs" in wrapped) {
            wrapped.workerDurationMs = Date.now() - startedAtMs;
        }
        throw wrapped;
    }
}
async function runCustomWorkerPromptCommand(input) {
    const startedAtMs = Date.now();
    try {
        const run = await (0, pi_worker_runtime_1.runPiWorkerPrompt)({
            workerName: input.name,
            config: input.customWorker,
            prompt: input.prompt,
            workspacePath: input.workspacePath,
            env: input.env,
            locale: input.locale,
            homeDirectory: input.homeDirectory,
            timeoutMs: input.timeoutMs,
            noOutputTimeoutMs: input.noOutputTimeoutMs,
            ...(input.commandPolicy === undefined
                ? {}
                : { commandPolicy: input.commandPolicy }),
            onStdoutChunk: input.onStdoutChunk,
            onStderrChunk: input.onStderrChunk,
        });
        const stdout = normalizeCustomWorkerDecisionOutput(run.stdout);
        assertWorkerOutputSucceeded("pi", stdout, input.locale);
        return { ...run, stdout };
    }
    catch (error) {
        const wrapped = (0, cli_worker_launcher_support_1.wrapWorkerRunError)("pi", error, input.locale);
        if (wrapped instanceof Error && "workerDurationMs" in wrapped) {
            wrapped.workerDurationMs = Date.now() - startedAtMs;
        }
        throw wrapped;
    }
}
function normalizeCustomWorkerDecisionOutput(stdout) {
    if ((0, decision_output_1.extractPreferredWorkerDecisionBlock)(stdout) !== null) {
        return stdout;
    }
    const jsonText = extractCustomWorkerJsonOutput(stdout);
    if (jsonText === null) {
        return stdout;
    }
    try {
        const parsed = JSON.parse(jsonText);
        if (parsed === null ||
            typeof parsed !== "object" ||
            Array.isArray(parsed)) {
            return stdout;
        }
        return [
            decision_output_1.DECISION_START_MARKER,
            JSON.stringify(parsed),
            decision_output_1.DECISION_END_MARKER,
        ].join("\n");
    }
    catch {
        return [decision_output_1.DECISION_START_MARKER, jsonText.trim(), decision_output_1.DECISION_END_MARKER].join("\n");
    }
}
function extractCustomWorkerJsonOutput(stdout) {
    const trimmed = stdout.trim();
    if (trimmed.length === 0) {
        return null;
    }
    if (trimmed.startsWith("{")) {
        return trimmed;
    }
    let lastJsonBlock = null;
    for (const match of trimmed.matchAll(/```(?:json|JSON)?\s*\n([\s\S]*?)\n```/gu)) {
        const json = match[1]?.trim();
        if (json?.startsWith("{")) {
            lastJsonBlock = json;
        }
    }
    return extractTrailingJsonObjectCandidate(trimmed) ?? lastJsonBlock;
}
function extractTrailingJsonObjectCandidate(stdout) {
    if (!stdout.endsWith("}")) {
        return null;
    }
    const parsedSuffix = extractParsedTrailingJsonObject(stdout);
    if (parsedSuffix !== null) {
        return parsedSuffix;
    }
    const decisionLikeSuffix = extractTrailingDecisionLikeObject(stdout);
    if (decisionLikeSuffix !== null) {
        return decisionLikeSuffix;
    }
    const lastLine = stdout.slice(stdout.lastIndexOf("\n") + 1).trim();
    if (lastLine.startsWith("{")) {
        return lastLine;
    }
    return null;
}
function extractTrailingDecisionLikeObject(stdout) {
    const startIndex = [
        '{"outcome"',
        "{'outcome'",
        '{"action"',
        "{'action'",
    ].reduce((latestIndex, marker) => {
        const markerIndex = stdout.lastIndexOf(marker);
        return markerIndex > latestIndex ? markerIndex : latestIndex;
    }, -1);
    return startIndex >= 0 ? stdout.slice(startIndex).trim() : null;
}
function extractParsedTrailingJsonObject(stdout) {
    for (let startIndex = stdout.lastIndexOf("{"); startIndex >= 0; startIndex = stdout.lastIndexOf("{", startIndex - 1)) {
        const candidate = stdout.slice(startIndex).trim();
        try {
            const parsed = JSON.parse(candidate);
            if (parsed !== null &&
                typeof parsed === "object" &&
                !Array.isArray(parsed)) {
                return candidate;
            }
        }
        catch { }
    }
    return null;
}
function assertWorkerOutputSucceeded(command, stdout, locale) {
    const failure = (0, cli_worker_launcher_support_1.classifyWorkerOutputFailure)(command, stdout, locale);
    if (failure !== null) {
        throw failure;
    }
}
