"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.publishFollowupIssueIfNeeded = publishFollowupIssueIfNeeded;
exports.publishRequestedFollowupIssue = publishRequestedFollowupIssue;
exports.hasFollowupRequestLabel = hasFollowupRequestLabel;
exports.publishSourceFollowupIssueIfNeeded = publishSourceFollowupIssueIfNeeded;
exports.applyFollowupPublicationState = applyFollowupPublicationState;
exports.publishFollowupSourceWorkflowState = publishFollowupSourceWorkflowState;
exports.isEligibleFollowupSource = isEligibleFollowupSource;
exports.removeFollowupRequestLabel = removeFollowupRequestLabel;
// biome-ignore lint/nursery/noExcessiveLinesPerFile: Follow-up publication stays centralized while terminal, manual, merge-cleanup, and closed-scan paths share one policy implementation.
const node_crypto_1 = require("node:crypto");
const promises_1 = require("node:timers/promises");
const control_plane_config_1 = require("../../config/control-plane-config");
const runner_1 = require("../../event-hooks/runner");
const catalog_1 = require("../../i18n/catalog");
const base_title_1 = require("../../issues/base-title");
const followup_request_body_1 = require("../../issues/followup-request-body");
const post_completion_comments_1 = require("../../issues/post-completion-comments");
const types_1 = require("../../platform/ticket-tracker/types");
const workflow_labels_1 = require("../../platform/ticket-tracker/workflow-labels");
const default_system_workflows_1 = require("../../workflows/default-system-workflows");
const publish_request_builders_1 = require("../../workflows/publish-request-builders");
const publisher_shared_1 = require("../../workflows/publisher-shared");
const state_1 = require("../../workflows/state");
const template_bindings_1 = require("../../workflows/template-bindings");
const template_registry_1 = require("../../workflows/template-registry");
const types_2 = require("../../workflows/types");
const workflow_state_read_support_1 = require("../../workflows/workflow-state-read-support");
const child_issue_title_1 = require("./child-issue-title");
const issue_creation_publication_1 = require("./issue-creation-publication");
const publisher_factory_1 = require("./publisher-factory");
const shared_1 = require("./shared");
const utils_1 = require("./spawn-child/utils");
const workflow_template_root_1 = require("./workflow-template-root");
const FOLLOWUP_FEEDBACK_HEADING_KEY = "run.followup.feedback.heading";
async function publishFollowupIssueIfNeeded(input) {
    const hadFollowupRequestLabel = hasFollowupRequestLabel(input.context, input.transitionState.issue);
    const outcome = await publishSourceFollowupIssueIfNeeded({
        context: input.context,
        workflowLabels: input.workflowLabels,
        sourceIssue: input.transitionState.issue,
        sourceWorkflowState: input.transitionState.workflowState,
        sourceConsecutiveAiRuns: input.transitionState.presentation.commentConsecutiveAiRuns,
        responseLanguage: input.transitionState.responseLanguage,
        completionSummary: input.transitionState.summary,
        clearRequestLabelOnSuccess: true,
        publishFeedback: true,
    });
    input.transitionState.workflowState = outcome.workflowState;
    if (hadFollowupRequestLabel && outcome.shouldClearRequestLabel) {
        if (outcome.workflowState !== null) {
            await publishFollowupSourceWorkflowState({
                context: input.context,
                sourceIssue: input.transitionState.issue,
                workflowState: outcome.workflowState,
                responseLanguage: input.transitionState.responseLanguage,
                clearRequestLabel: true,
            });
        }
    }
    return outcome.issue;
}
async function publishRequestedFollowupIssue(input) {
    const prepared = await prepareRequestedFollowupPublication(input);
    const { context, followupRequestBody, normalizedFollowupRequestBody, requestMetadata, sourceCompletionSummary, sourceWorkflowState, } = prepared;
    if (!isEligibleFollowupSource(input.sourceIssue)) {
        return {
            kind: "skipped",
            reason: "not-eligible-source",
            ...buildFollowupPublicationRequestFields({
                requestTitle: requestMetadata.title,
                requestDigest: requestMetadata.digest,
                ...(input.category !== undefined ? { category: input.category } : {}),
            }),
        };
    }
    const bindingResult = await resolveRequestedFollowupPublicationBinding(input, context);
    if (bindingResult.kind === "failed") {
        return publishRequestedFollowupFailureResult({
            enabled: input.publishFeedback === true,
            context,
            sourceIssue: input.sourceIssue,
            responseLanguage: input.responseLanguage,
            sourceCompletionSummary,
            followupRequestBody,
            ...followupRequestReasonField(input.followupRequestReason),
            reason: bindingResult.reason,
            requestTitle: requestMetadata.title,
            requestDigest: requestMetadata.digest,
            ...(input.category !== undefined ? { category: input.category } : {}),
        });
    }
    if (input.dryRun === true) {
        return {
            kind: "dry_run",
            reason: (0, catalog_1.translate)(input.responseLanguage, "run.followup.feedback.dryRun", {
                templatePath: formatFollowupWorkflowBindingLabel(bindingResult.binding),
            }),
            requestTitle: requestMetadata.title,
            requestDigest: requestMetadata.digest,
            ...(input.category !== undefined ? { category: input.category } : {}),
        };
    }
    try {
        const publication = await createOrReuseFollowupIssue({
            context,
            workflowLabels: input.workflowLabels,
            sourceIssue: input.sourceIssue,
            sourceWorkflowState,
            sourceConsecutiveAiRuns: input.sourceConsecutiveAiRuns,
            followupBinding: bindingResult.binding,
            responseLanguage: input.responseLanguage,
            sourceCompletionSummary,
            followupRequestBody,
            ...followupRequestReasonField(input.followupRequestReason),
            followupRequestBodyIsExplicit: normalizedFollowupRequestBody !== null,
            requestDigest: requestMetadata.digest,
            requestTitle: requestMetadata.title,
            ...(input.titleSeed !== undefined ? { titleSeed: input.titleSeed } : {}),
        });
        const result = {
            kind: publication.kind,
            issue: publication.issue,
            requestTitle: requestMetadata.title,
            requestDigest: requestMetadata.digest,
            ...(input.category !== undefined ? { category: input.category } : {}),
        };
        await publishDirectFollowupPublicationFeedback({
            enabled: input.publishFeedback === true && publication.sourceFeedbackEligible,
            context,
            sourceIssue: input.sourceIssue,
            responseLanguage: input.responseLanguage,
            sourceCompletionSummary,
            result,
            followupRequestBody,
            ...followupRequestReasonField(input.followupRequestReason),
            workflowTemplateLabel: formatFollowupWorkflowBindingLabel(bindingResult.binding),
        });
        return result;
    }
    catch (error) {
        const reason = error instanceof Error ? error.message : "Unknown failure.";
        return publishRequestedFollowupFailureResult({
            enabled: input.publishFeedback === true,
            context,
            sourceIssue: input.sourceIssue,
            responseLanguage: input.responseLanguage,
            sourceCompletionSummary,
            followupRequestBody,
            ...followupRequestReasonField(input.followupRequestReason),
            reason,
            requestTitle: requestMetadata.title,
            requestDigest: requestMetadata.digest,
            ...(input.category !== undefined ? { category: input.category } : {}),
        });
    }
}
async function prepareRequestedFollowupPublication(input) {
    const sourceWorkflowState = input.sourceWorkflowState ??
        (await (0, workflow_state_read_support_1.resolvePersistedIssueWorkflowState)(input.context.ticketTracker, input.sourceIssue.id));
    const context = resolveFollowupPublicationContext({
        context: input.context,
        sourceWorkflowState,
    });
    const normalizedFollowupRequestBody = normalizeFollowupText(input.followupRequestBody);
    const followupRequestBody = normalizedFollowupRequestBody ??
        (0, catalog_1.translate)(input.responseLanguage, "run.followup.body.defaultRequest");
    const sourceCompletionSummary = resolveSourceCompletionSummary({
        workflowState: sourceWorkflowState,
        fallbackSummary: input.completionSummary,
    }) ??
        (0, catalog_1.translate)(input.responseLanguage, "run.followup.body.defaultCompletion");
    const requestMetadata = buildFollowupRequestMetadata({
        sourceIssue: input.sourceIssue,
        followupRequestBody,
        ...(input.titleSeed !== undefined ? { titleSeed: input.titleSeed } : {}),
        ...(input.requestDigest !== undefined
            ? { requestDigest: input.requestDigest }
            : {}),
        ...(input.requestTitle !== undefined
            ? { requestTitle: input.requestTitle }
            : {}),
    });
    return {
        sourceWorkflowState,
        context,
        normalizedFollowupRequestBody,
        followupRequestBody,
        sourceCompletionSummary,
        requestMetadata,
    };
}
function resolveRequestedFollowupPublicationBinding(input, context) {
    return resolveFollowupBindingForRequestedPublication({
        context,
        sourceIssue: input.sourceIssue,
        responseLanguage: input.responseLanguage,
        ...(input.followupBinding !== undefined
            ? { followupBinding: input.followupBinding }
            : {}),
        ...(input.explicitSelector !== undefined
            ? { explicitSelector: input.explicitSelector }
            : {}),
    });
}
function followupRequestReasonField(followupRequestReason) {
    return followupRequestReason === undefined ? {} : { followupRequestReason };
}
function buildFollowupPublicationRequestFields(input) {
    return {
        ...(input.requestTitle !== undefined
            ? { requestTitle: input.requestTitle }
            : {}),
        ...(input.requestDigest !== undefined
            ? { requestDigest: input.requestDigest }
            : {}),
        ...(input.category !== undefined ? { category: input.category } : {}),
    };
}
function buildFollowupRequestResult(kind, request, input) {
    const metadata = {
        ...(request.requestTitle !== undefined
            ? { requestTitle: request.requestTitle }
            : {}),
        ...(request.requestDigest !== undefined
            ? { requestDigest: request.requestDigest }
            : {}),
        ...(request.category !== undefined ? { category: request.category } : {}),
    };
    return {
        kind,
        reason: input.reason,
        ...buildFollowupPublicationRequestFields(metadata),
    };
}
async function publishRequestedFollowupFailureResult(input) {
    const result = {
        kind: "failed",
        reason: input.reason,
        requestTitle: input.requestTitle,
        requestDigest: input.requestDigest,
        ...(input.category !== undefined ? { category: input.category } : {}),
    };
    await publishDirectFollowupPublicationFeedback({
        enabled: input.enabled,
        context: input.context,
        sourceIssue: input.sourceIssue,
        responseLanguage: input.responseLanguage,
        sourceCompletionSummary: input.sourceCompletionSummary,
        result,
        followupRequestBody: input.followupRequestBody,
        ...(input.followupRequestReason !== undefined
            ? { followupRequestReason: input.followupRequestReason }
            : {}),
    });
    return result;
}
async function resolveFollowupBindingForRequestedPublication(input) {
    try {
        if (input.followupBinding !== undefined) {
            return { kind: "resolved", binding: input.followupBinding };
        }
        const bindingInput = {
            repoRoot: (0, workflow_template_root_1.getWorkflowTemplateRepoRoot)(input.context),
            defaultSelector: (0, control_plane_config_1.resolveFollowupDefaultWorkflowSelector)(input.context.config.followup),
            responseLanguage: input.responseLanguage,
        };
        if (input.explicitSelector !== undefined) {
            bindingInput.explicitSelector = input.explicitSelector;
        }
        return await resolveFollowupWorkflowBinding(bindingInput);
    }
    catch (error) {
        const reason = error instanceof Error ? error.message : "Unknown failure.";
        return { kind: "failed", reason };
    }
}
async function publishDirectFollowupPublicationFeedback(input) {
    if (input.enabled !== true) {
        return;
    }
    await publishFollowupPublicationFeedback({
        context: input.context,
        sourceIssue: input.sourceIssue,
        responseLanguage: input.responseLanguage,
        sourceCompletionSummary: input.sourceCompletionSummary,
        entries: [
            {
                result: input.result,
                followupRequestBody: input.followupRequestBody,
                ...(input.followupRequestReason !== undefined
                    ? { followupRequestReason: input.followupRequestReason }
                    : {}),
                ...(input.workflowTemplateLabel !== undefined
                    ? { workflowTemplateLabel: input.workflowTemplateLabel }
                    : {}),
            },
        ],
    });
}
async function publishFollowupPublicationFeedback(input) {
    const feedbackSummary = renderFollowupPublicationFeedback(input);
    if (feedbackSummary === null) {
        return;
    }
    await publishFollowupSourceUpdate({
        context: input.context,
        sourceIssue: input.sourceIssue,
        responseLanguage: input.responseLanguage,
        feedbackSummary,
        feedbackHeadingKey: FOLLOWUP_FEEDBACK_HEADING_KEY,
    });
}
function renderFollowupPublicationFeedback(input) {
    if (input.entries.length === 0) {
        return null;
    }
    const locale = input.responseLanguage;
    const recommendationItemsByDigest = indexFollowupRecommendationItems(input.recommendation?.items ?? []);
    const completionSummary = normalizeFollowupText(input.sourceCompletionSummary);
    const lines = [
        `- **${(0, catalog_1.translate)(locale, "run.followup.body.sourceIssue")}:** [${input.sourceIssue.displayId}](${input.sourceIssue.url})`,
        `- **${(0, catalog_1.translate)(locale, "run.followup.body.sourceInspection")}:** \`${buildFollowupSourceInspectionCommand(input.sourceIssue)}\``,
    ];
    if (completionSummary !== null) {
        lines.push(`- **${(0, catalog_1.translate)(locale, "run.followup.feedback.sourceCompletion")}:** ${completionSummary}`);
    }
    const recommendationReason = normalizeFollowupText(input.recommendation?.reason);
    if (recommendationReason !== null) {
        lines.push(`- **${(0, catalog_1.translate)(locale, "run.followup.feedback.overallReason")}:** ${recommendationReason}`);
    }
    appendFollowupCategorySummary({
        lines,
        locale,
        recommendation: input.recommendation,
        maxIssuesPerSource: input.followupMaxIssuesPerSource,
        entries: input.entries,
    });
    for (const entry of input.entries) {
        const item = entry.result.requestDigest !== undefined
            ? (recommendationItemsByDigest.get(entry.result.requestDigest) ?? null)
            : null;
        lines.push("", renderFollowupFeedbackEntryHeading({ entry, item }), "", `- **${(0, catalog_1.translate)(locale, "run.followup.feedback.status")}:** ${renderFollowupFeedbackStatus(entry.result, locale)}`);
        const workflowTemplate = resolveFollowupFeedbackWorkflowTemplate({
            entry,
            item,
        });
        if (workflowTemplate !== null) {
            lines.push(`- **${(0, catalog_1.translate)(locale, "run.followup.feedback.workflowTemplate")}:** ${workflowTemplate}`);
        }
        appendFollowupFeedbackTextSection({
            lines,
            locale,
            headingKey: "run.followup.feedback.requestBody",
            value: item?.body ??
                entry.request?.followupRequestBody ??
                entry.followupRequestBody,
        });
        appendFollowupFeedbackTextSection({
            lines,
            locale,
            headingKey: "run.followup.feedback.requestReason",
            value: item?.reason ??
                entry.request?.followupRequestReason ??
                entry.followupRequestReason,
        });
    }
    return lines.join("\n");
}
function appendFollowupCategorySummary(input) {
    if (input.maxIssuesPerSource === undefined) {
        return;
    }
    input.lines.push("", `**${(0, catalog_1.translate)(input.locale, "run.followup.feedback.categorySummary")}**`, "", [
        `| ${(0, catalog_1.translate)(input.locale, "run.followup.feedback.category")}`,
        (0, catalog_1.translate)(input.locale, "run.followup.feedback.categoryResult"),
        (0, catalog_1.translate)(input.locale, "run.followup.feedback.categoryLimit"),
        `${(0, catalog_1.translate)(input.locale, "run.followup.feedback.categoryNote")} |`,
    ].join(" | "), "|---|---:|---:|---|");
    for (const category of types_2.WORKFLOW_FOLLOWUP_RECOMMENDATION_CATEGORIES) {
        const summary = summarizeFollowupCategory({
            category,
            recommendation: input.recommendation,
            entries: input.entries,
        });
        input.lines.push([
            `| ${renderFollowupCategoryLabel(input.locale, category)}`,
            (0, catalog_1.translate)(input.locale, "run.followup.feedback.categoryResult.createdReused", { count: summary.createdOrReused }),
            String(input.maxIssuesPerSource[category]),
            `${renderFollowupCategoryNote(input.locale, summary, input.maxIssuesPerSource[category])} |`,
        ].join(" | "));
    }
}
function summarizeFollowupCategory(input) {
    let createdOrReused = 0;
    const issueDisplayIds = [];
    let failed = 0;
    let skipped = 0;
    for (const entry of input.entries) {
        if (entry.result.category !== input.category) {
            continue;
        }
        if (entry.result.kind === "created" || entry.result.kind === "reused") {
            createdOrReused += 1;
            issueDisplayIds.push(entry.result.issue.displayId);
        }
        else if (entry.result.kind === "failed") {
            failed += 1;
        }
        else if (entry.result.kind === "skipped") {
            skipped += 1;
        }
    }
    return {
        recommended: input.recommendation?.items.filter((item) => item.category === input.category).length ?? 0,
        createdOrReused,
        issueDisplayIds,
        failed,
        skipped,
    };
}
function renderFollowupCategoryLabel(locale, category) {
    return (0, catalog_1.translate)(locale, `run.followup.feedback.category.${category}`);
}
function renderFollowupCategoryNote(locale, summary, limit) {
    const notes = [];
    if (summary.issueDisplayIds.length > 0) {
        notes.push(summary.issueDisplayIds.join(", "));
    }
    if (summary.recommended === 0) {
        notes.push((0, catalog_1.translate)(locale, "run.followup.feedback.category.recommendedNone"));
    }
    if (summary.recommended > 0 && limit === 0) {
        notes.push((0, catalog_1.translate)(locale, "run.followup.feedback.category.limitZero"));
    }
    if (summary.failed > 0) {
        notes.push((0, catalog_1.translate)(locale, "run.followup.feedback.category.failedCount", {
            count: summary.failed,
        }));
    }
    if (summary.skipped > 0) {
        notes.push((0, catalog_1.translate)(locale, "run.followup.feedback.category.skippedCount", {
            count: summary.skipped,
        }));
    }
    return notes.length > 0 ? notes.join(" / ") : "-";
}
function appendFollowupFeedbackTextSection(input) {
    const text = normalizeFollowupText(input.value);
    if (text === null) {
        return;
    }
    input.lines.push("", `**${(0, catalog_1.translate)(input.locale, input.headingKey)}**`, "", text);
}
function indexFollowupRecommendationItems(items) {
    return new Map(items.map((item) => [
        buildFollowupRequestDigest({ title: item.title, body: item.body }),
        item,
    ]));
}
function renderFollowupFeedbackEntryHeading(input) {
    const title = normalizeFollowupText(input.item?.title) ??
        normalizeFollowupText(input.entry.result.requestTitle) ??
        normalizeFollowupText(input.entry.request?.requestTitle) ??
        "Follow-up";
    if (input.entry.result.kind === "created" ||
        input.entry.result.kind === "reused") {
        return `### ${input.entry.result.issue.displayId} ${title}`;
    }
    return `### ${title}`;
}
function renderFollowupFeedbackStatus(result, locale) {
    switch (result.kind) {
        case "created":
            return `${(0, catalog_1.translate)(locale, "run.followup.feedback.status.created")} [${result.issue.displayId}](${result.issue.url})`;
        case "reused":
            return `${(0, catalog_1.translate)(locale, "run.followup.feedback.status.reused")} [${result.issue.displayId}](${result.issue.url})`;
        case "failed":
            return `${(0, catalog_1.translate)(locale, "run.followup.feedback.status.failed")}: ${result.reason}`;
        case "skipped":
        case "dry_run":
            return `${(0, catalog_1.translate)(locale, "run.followup.feedback.status.skipped")}: ${result.reason}`;
    }
}
function resolveFollowupFeedbackWorkflowTemplate(input) {
    return (normalizeFollowupText(input.item?.workflowTemplate) ??
        normalizeFollowupText(input.entry.workflowTemplateLabel) ??
        (input.entry.request?.workflowTemplateSelector !== undefined
            ? formatFollowupWorkflowSelectorLabel(input.entry.request.workflowTemplateSelector)
            : null));
}
function formatFollowupWorkflowSelectorLabel(selector) {
    return selector.mode === "template" ? selector.templatePath : selector.mode;
}
function hasFollowupRequestLabel(context, issue) {
    const label = (0, workflow_labels_1.getFollowupRequestLabelName)(context.config.ticketTracker.workflowLabels);
    return issue.labelNames?.includes(label) ?? false;
}
async function publishSourceFollowupIssueIfNeeded(input) {
    const requestInput = {
        context: input.context,
        sourceIssue: input.sourceIssue,
        workflowState: input.sourceWorkflowState,
    };
    if (input.completionSummary !== undefined) {
        requestInput.completionSummary = input.completionSummary;
    }
    if (input.followupRequestBody !== undefined) {
        requestInput.followupRequestBody = input.followupRequestBody;
    }
    if (input.forceProposalPolicy !== undefined) {
        requestInput.forceProposalPolicy = input.forceProposalPolicy;
    }
    if (input.forceProposalApproval !== undefined) {
        requestInput.forceProposalApproval = input.forceProposalApproval;
    }
    if (input.materializeWorkflowState !== undefined) {
        requestInput.materializeWorkflowState = input.materializeWorkflowState;
    }
    const request = resolveSourceFollowupRequest(requestInput);
    if (request.kind === "none") {
        return {
            result: null,
            results: [],
            workflowState: request.workflowState,
            issue: null,
            issues: [],
            shouldClearRequestLabel: false,
        };
    }
    if (request.kind === "skipped" || request.kind === "failed") {
        return publishUnresolvedSourceFollowupOutcome({ input, request });
    }
    const reviewedRequest = await maybeApplyFollowupProposalReview({
        input,
        request,
    });
    if (reviewedRequest.kind === "skipped" || reviewedRequest.kind === "failed") {
        return publishUnresolvedSourceFollowupOutcome({
            input,
            request: reviewedRequest,
        });
    }
    return publishResolvedSourceFollowupRequests({
        input,
        request: reviewedRequest,
        sourceWorkflowState: reviewedRequest.workflowState,
    });
}
async function publishUnresolvedSourceFollowupOutcome(input) {
    const result = {
        kind: input.request.kind,
        reason: input.request.reason,
    };
    const workflowState = applyFollowupPublicationState({
        workflowState: input.request.workflowState,
        policy: input.request.policy,
        publication: {
            status: input.request.kind,
            reason: input.request.reason,
            at: new Date().toISOString(),
        },
    });
    const nextWorkflowState = input.request.kind === "failed" && input.request.preserveProposal === true
        ? preserveFollowupProposal({
            previousWorkflowState: input.request.workflowState,
            nextWorkflowState: workflowState,
        })
        : workflowState;
    if (input.input.publishFeedback === true && input.input.dryRun !== true) {
        await publishFollowupPublicationFeedback({
            context: input.input.context,
            sourceIssue: input.input.sourceIssue,
            responseLanguage: input.input.responseLanguage,
            sourceCompletionSummary: resolveSourceCompletionSummary({
                workflowState: nextWorkflowState,
                fallbackSummary: input.input.completionSummary,
            }),
            recommendation: input.request.policy === "if_needed"
                ? (nextWorkflowState?.followup?.recommendation ?? null)
                : null,
            followupMaxIssuesPerSource: resolveFeedbackMaxIssuesPerSource({
                context: input.input.context,
                policy: input.request.policy,
                workflowState: input.request.workflowState,
            }),
            entries: [{ result }],
        });
    }
    return {
        result,
        results: [result],
        workflowState: nextWorkflowState,
        issue: null,
        issues: [],
        shouldClearRequestLabel: false,
    };
}
function preserveFollowupProposal(input) {
    const proposal = input.previousWorkflowState?.followup?.proposal;
    if (input.nextWorkflowState === null ||
        input.nextWorkflowState.followup === undefined ||
        proposal === undefined ||
        proposal === null) {
        return input.nextWorkflowState;
    }
    return {
        ...input.nextWorkflowState,
        followup: {
            ...input.nextWorkflowState.followup,
            proposal,
        },
    };
}
async function publishResolvedSourceFollowupRequests(input) {
    const results = [];
    let workflowState = input.sourceWorkflowState;
    const followupRequests = await resolveSourceFollowupPublicationRequests({
        input: input.input,
        hasRequestLabel: input.request.hasRequestLabel,
        requests: input.request.requests,
    });
    const partitionedRequests = partitionFollowupRequestsByApproval({
        workflowState,
        requests: followupRequests,
        forceAuto: input.request.forceAutoPublication === true,
    });
    const autoRequests = applyFollowupMaxIssuesPerSourceToAutoRequests({
        context: input.input.context,
        policy: input.request.policy,
        workflowState,
        requests: partitionedRequests.autoRequests,
    });
    const confirmRequests = partitionedRequests.confirmRequests;
    for (const followupRequest of autoRequests) {
        const result = await publishResolvedSourceFollowupRequest({
            input: input.input,
            sourceWorkflowState: input.sourceWorkflowState,
            followupRequest,
        });
        results.push(result);
        if (input.input.dryRun !== true) {
            workflowState = applyFollowupPublicationState({
                workflowState,
                policy: input.request.policy,
                publication: buildFollowupPublicationState(result),
            });
        }
    }
    if (confirmRequests.length > 0 && input.input.dryRun !== true) {
        const proposal = await publishFollowupProposal({
            context: input.input.context,
            sourceIssue: input.input.sourceIssue,
            responseLanguage: input.input.responseLanguage,
            workflowState,
            policy: input.request.policy,
            requests: confirmRequests,
            sourceCompletionSummary: resolveBatchSourceCompletionSummary({
                requests: confirmRequests,
                workflowState,
            }),
        });
        workflowState = proposal.workflowState;
        results.push(...proposal.results);
    }
    if (input.input.publishFeedback === true && input.input.dryRun !== true) {
        await publishFollowupPublicationFeedback({
            context: input.input.context,
            sourceIssue: input.input.sourceIssue,
            responseLanguage: input.input.responseLanguage,
            sourceCompletionSummary: resolveBatchSourceCompletionSummary({
                requests: followupRequests,
                workflowState,
            }),
            recommendation: input.request.policy === "if_needed"
                ? (workflowState?.followup?.recommendation ?? null)
                : null,
            followupMaxIssuesPerSource: resolveFeedbackMaxIssuesPerSource({
                context: input.input.context,
                policy: input.request.policy,
                workflowState: input.request.workflowState,
            }),
            entries: results.map((resultEntry, index) => {
                const request = autoRequests[index];
                return {
                    result: resultEntry,
                    ...(request !== undefined ? { request } : {}),
                };
            }),
        });
    }
    if (input.request.fromPendingProposal === true &&
        results.some((entry) => entry.kind === "failed")) {
        workflowState = preserveFollowupProposal({
            previousWorkflowState: input.request.workflowState,
            nextWorkflowState: workflowState,
        });
    }
    const result = results.find((entry) => entry.kind === "created" || entry.kind === "reused") ??
        results[0] ??
        null;
    const issues = results.flatMap((entry) => entry.kind === "created" || entry.kind === "reused" ? [entry.issue] : []);
    const hasSuccessfulPendingProposalApproval = input.request.fromPendingProposal === true &&
        results.length > 0 &&
        results.every((entry) => entry.kind !== "failed");
    const shouldClearRequestLabel = input.input.clearRequestLabelOnSuccess === true &&
        input.request.hasRequestLabel &&
        (input.request.fromPendingProposal === true
            ? hasSuccessfulPendingProposalApproval
            : issues.length > 0);
    return {
        result,
        results,
        workflowState,
        issue: issues[0] ?? null,
        issues,
        shouldClearRequestLabel,
    };
}
function partitionFollowupRequestsByApproval(input) {
    if (input.forceAuto === true) {
        return { autoRequests: [...input.requests], confirmRequests: [] };
    }
    const approval = input.workflowState?.followup?.proposalApproval ?? "auto";
    if (approval === "auto") {
        return { autoRequests: [...input.requests], confirmRequests: [] };
    }
    if (approval === "confirm") {
        return { autoRequests: [], confirmRequests: [...input.requests] };
    }
    const autoRequests = [];
    const confirmRequests = [];
    for (const request of input.requests) {
        (request.proposalApproval === "auto" ? autoRequests : confirmRequests).push(request);
    }
    return { autoRequests, confirmRequests };
}
function applyFollowupMaxIssuesPerSourceToAutoRequests(input) {
    if (input.policy !== "if_needed") {
        return [...input.requests];
    }
    const effectiveConfig = resolveFollowupEffectiveConfig({
        config: input.context.config,
        sourceWorkflowState: input.workflowState,
    });
    const maxIssuesPerSource = effectiveConfig.followup.maxIssuesPerSource;
    if (input.requests.length > 0 &&
        maxIssuesPerSource.mainWork <= 0 &&
        maxIssuesPerSource.maintenance <= 0) {
        return [
            {
                requestTitle: "Follow-up recommendation items skipped",
                failureReason: "Follow-up automation was enabled, but both followup.maxIssuesPerSource.mainWork and followup.maxIssuesPerSource.maintenance are 0.",
                skipped: true,
            },
        ];
    }
    return applyFollowupMaxIssuesPerSource({
        requests: input.requests,
        maxIssuesPerSource,
    });
}
async function publishFollowupProposal(input) {
    if (input.requests.length === 0) {
        return { workflowState: input.workflowState, results: [] };
    }
    const feedbackSummary = renderFollowupProposalFeedback(input);
    const comment = await publishFollowupSourceUpdate({
        context: input.context,
        sourceIssue: input.sourceIssue,
        responseLanguage: input.responseLanguage,
        feedbackSummary,
        feedbackHeadingKey: FOLLOWUP_FEEDBACK_HEADING_KEY,
    });
    if (comment === null) {
        return {
            workflowState: input.workflowState,
            results: input.requests.map((request) => buildFollowupRequestResult("failed", request, {
                reason: "Follow-up proposal comment could not be published.",
            })),
        };
    }
    return {
        workflowState: applyFollowupProposalState({
            workflowState: input.workflowState,
            policy: input.policy,
            comment,
            requests: input.requests,
        }),
        results: input.requests.map((request) => buildFollowupRequestResult("skipped", request, {
            reason: "Follow-up proposal is waiting for approval.",
        })),
    };
}
function applyFollowupProposalState(input) {
    if (input.workflowState === null) {
        return null;
    }
    return {
        ...input.workflowState,
        followup: {
            ...(input.workflowState.followup ?? {
                proposalPolicy: input.policy,
                proposalApproval: "confirm",
            }),
            proposalPolicy: input.policy,
            proposal: {
                status: "pending",
                commentId: input.comment.id,
                createdAt: input.comment.createdAt,
                sourceRecommendationDigest: buildFollowupProposalDigest(input.requests),
                items: input.requests.map(followupRequestToRecommendationItem),
            },
        },
    };
}
function buildFollowupProposalDigest(requests) {
    return (0, node_crypto_1.createHash)("sha256")
        .update(JSON.stringify(requests.map((request) => ({
        title: request.requestTitle ?? request.titleSeed ?? "",
        body: request.followupRequestBody ?? "",
        reason: request.followupRequestReason ?? "",
        category: request.category ?? "mainWork",
    }))))
        .digest("hex");
}
function followupRequestToRecommendationItem(request) {
    const workflowTemplate = request.workflowTemplateSelector !== undefined
        ? renderWorkflowTemplateSelectorForProposal(request.workflowTemplateSelector)
        : undefined;
    return {
        category: request.category ?? "mainWork",
        title: request.requestTitle ?? request.titleSeed ?? "Follow-up work",
        body: request.followupRequestBody ??
            "Review the source issue and complete the approved follow-up work.",
        reason: request.followupRequestReason ??
            "This follow-up was explicitly requested for the source issue.",
        ...(workflowTemplate !== undefined ? { workflowTemplate } : {}),
    };
}
function renderWorkflowTemplateSelectorForProposal(selector) {
    return selector.mode === "template"
        ? selector.templatePath
        : selector.mode === "no_template"
            ? "no_template"
            : undefined;
}
function renderFollowupProposalFeedback(input) {
    const locale = input.responseLanguage;
    const lines = [
        `- **${(0, catalog_1.translate)(locale, "run.followup.body.sourceIssue")}:** [${input.sourceIssue.displayId}](${input.sourceIssue.url})`,
        `- **${(0, catalog_1.translate)(locale, "run.followup.body.sourceInspection")}:** \`${buildFollowupSourceInspectionCommand(input.sourceIssue)}\``,
    ];
    if (input.sourceCompletionSummary !== null) {
        lines.push(`- **${(0, catalog_1.translate)(locale, "run.followup.feedback.sourceCompletion")}:** ${input.sourceCompletionSummary}`);
    }
    lines.push("", `- **${(0, catalog_1.translate)(locale, "run.followup.feedback.proposalCandidateCount")}:** ${String(input.requests.length)}`, "", (0, catalog_1.translate)(locale, "run.followup.feedback.proposalReviewInstructions"));
    for (const [index, request] of input.requests.entries()) {
        lines.push("", `### ${String(index + 1)}. ${request.requestTitle ?? request.titleSeed ?? "Follow-up work"}`, "", `- **${(0, catalog_1.translate)(locale, "run.followup.feedback.category")}:** ${renderFollowupCategoryLabel(locale, request.category ?? "mainWork")}`);
        appendFollowupFeedbackTextSection({
            lines,
            locale,
            headingKey: "run.followup.feedback.requestReason",
            value: request.followupRequestReason,
        });
        appendFollowupFeedbackTextSection({
            lines,
            locale,
            headingKey: "run.followup.feedback.requestBody",
            value: request.followupRequestBody,
        });
    }
    return lines.join("\n");
}
function resolveFeedbackMaxIssuesPerSource(input) {
    return input.policy === "if_needed"
        ? resolveFollowupEffectiveConfig({
            config: input.context.config,
            sourceWorkflowState: input.workflowState,
        }).followup.maxIssuesPerSource
        : undefined;
}
async function resolveSourceFollowupPublicationRequests(input) {
    if (!input.hasRequestLabel ||
        input.requests.every((request) => request.followupRequestBody !== undefined ||
            request.failureReason !== undefined)) {
        return [...input.requests];
    }
    const postCompletionRequestBody = await resolvePostCompletionFollowupRequestBody(input.input);
    if (postCompletionRequestBody === null) {
        return [...input.requests];
    }
    return input.requests.map((request) => request.followupRequestBody === undefined &&
        request.failureReason === undefined
        ? { ...request, followupRequestBody: postCompletionRequestBody }
        : request);
}
async function resolvePostCompletionFollowupRequestBody(input) {
    const completedAt = input.sourceIssue.completedAt;
    if (completedAt === undefined || completedAt === null) {
        return null;
    }
    let comments;
    try {
        comments = await (0, shared_1.loadSortedIssueComments)(input.context.ticketTracker, input.sourceIssue.id, { timeline: "issue-only" });
    }
    catch {
        return null;
    }
    const postCompletionComments = (0, post_completion_comments_1.selectPostCompletionUserComments)({
        comments,
        completedAt,
    });
    const commentBodies = postCompletionComments
        .map((comment) => comment.body.trim())
        .filter((body) => body.length > 0);
    return commentBodies.length === 0 ? null : commentBodies.join("\n\n");
}
async function publishResolvedSourceFollowupRequest(input) {
    if (input.followupRequest.failureReason !== undefined) {
        const result = buildUnpublishedFollowupPublicationResult(input.followupRequest);
        return result;
    }
    return publishRequestedFollowupIssue(buildRequestedFollowupPublicationInput(input));
}
function buildUnpublishedFollowupPublicationResult(followupRequest) {
    return {
        kind: followupRequest.skipped === true ? "skipped" : "failed",
        reason: followupRequest.failureReason ?? "Unknown failure.",
        ...(followupRequest.requestTitle !== undefined
            ? { requestTitle: followupRequest.requestTitle }
            : {}),
        ...(followupRequest.requestDigest !== undefined
            ? { requestDigest: followupRequest.requestDigest }
            : {}),
        ...(followupRequest.category !== undefined
            ? { category: followupRequest.category }
            : {}),
    };
}
function buildRequestedFollowupPublicationInput(input) {
    const publishInput = {
        context: input.input.context,
        workflowLabels: input.input.workflowLabels,
        sourceIssue: input.input.sourceIssue,
        sourceWorkflowState: input.sourceWorkflowState,
        responseLanguage: input.input.responseLanguage,
    };
    const request = input.followupRequest;
    if (request.sourceCompletionSummary !== undefined) {
        publishInput.completionSummary = request.sourceCompletionSummary;
    }
    if (request.followupRequestBody !== undefined) {
        publishInput.followupRequestBody = request.followupRequestBody;
    }
    if (request.followupRequestReason !== undefined) {
        publishInput.followupRequestReason = request.followupRequestReason;
    }
    if (request.titleSeed !== undefined) {
        publishInput.titleSeed = request.titleSeed;
    }
    if (request.requestDigest !== undefined) {
        publishInput.requestDigest = request.requestDigest;
    }
    if (request.requestTitle !== undefined) {
        publishInput.requestTitle = request.requestTitle;
    }
    if (request.category !== undefined) {
        publishInput.category = request.category;
    }
    if (input.input.sourceConsecutiveAiRuns !== undefined) {
        publishInput.sourceConsecutiveAiRuns = input.input.sourceConsecutiveAiRuns;
    }
    if (request.workflowTemplateSelector !== undefined) {
        publishInput.explicitSelector = request.workflowTemplateSelector;
    }
    else if (input.input.explicitSelector !== undefined) {
        publishInput.explicitSelector = input.input.explicitSelector;
    }
    if (input.input.dryRun !== undefined) {
        publishInput.dryRun = input.input.dryRun;
    }
    return publishInput;
}
async function maybeApplyFollowupProposalReview(input) {
    const proposal = input.request.workflowState?.followup?.proposal;
    if (input.request.fromPendingProposal !== true ||
        proposal === undefined ||
        proposal === null ||
        input.input.dryRun === true) {
        return input.request;
    }
    const reviewContext = await collectFollowupProposalReviewContext({
        context: input.input.context,
        sourceIssue: input.input.sourceIssue,
        proposalCommentId: proposal.commentId,
        proposalCreatedAt: proposal.createdAt,
    });
    if (reviewContext.userCommentsAfterProposal.length === 0) {
        return input.request;
    }
    if (input.input.context.worker === undefined ||
        input.input.context.worker.runFollowupProposalReview === undefined) {
        return buildFollowupProposalReviewFailedRequest({
            request: input.request,
            reason: "Follow-up proposal review requires a configured worker.",
        });
    }
    try {
        const sourceIssue = {
            displayId: input.input.sourceIssue.displayId,
            title: input.input.sourceIssue.title,
            body: input.input.sourceIssue.body,
            url: input.input.sourceIssue.url,
            ...(input.input.sourceIssue.completedAt !== undefined
                ? { completedAt: input.input.sourceIssue.completedAt }
                : {}),
        };
        const result = await input.input.context.worker.runFollowupProposalReview({
            sourceIssue,
            completionSummary: resolveSourceCompletionSummary({
                workflowState: input.request.workflowState,
                fallbackSummary: input.input.completionSummary,
            }),
            proposal: {
                commentId: proposal.commentId,
                body: reviewContext.proposalBody,
                items: proposal.items,
            },
            userCommentsAfterProposal: reviewContext.userCommentsAfterProposal,
            preferredWorkflowTemplates: [
                ...input.input.context.config.followup.preferredWorkflowTemplates,
            ],
            maxIssuesPerSource: input.input.context.config.followup.maxIssuesPerSource,
            outputLanguage: input.input.responseLanguage,
            workspacePath: input.input.context.cwd,
            repositoryRoot: input.input.context.cwd,
        });
        if (result.kind !== "success") {
            return buildFollowupProposalReviewFailedRequest({
                request: input.request,
                reason: "Follow-up proposal review worker was unavailable.",
            });
        }
        const reviewedItems = result.launchResult.review.items;
        return {
            ...input.request,
            requests: reviewedItems.length === 0
                ? [buildEmptyFollowupProposalReviewRequest()]
                : buildApprovedFollowupProposalPublicationRequests({
                    items: reviewedItems,
                    baseRequest: buildFollowupProposalReviewBaseRequest({
                        request: input.request,
                    }),
                    workflowState: input.request.workflowState,
                }),
        };
    }
    catch (error) {
        return buildFollowupProposalReviewFailedRequest({
            request: input.request,
            reason: `Follow-up proposal review failed: ${error instanceof Error ? error.message : String(error)}`,
        });
    }
}
async function collectFollowupProposalReviewContext(input) {
    let comments;
    try {
        comments = await (0, shared_1.loadSortedIssueComments)(input.context.ticketTracker, input.sourceIssue.id, { timeline: "issue-only" });
    }
    catch {
        return { proposalBody: "", userCommentsAfterProposal: [] };
    }
    const proposalBody = comments.find((comment) => comment.id === input.proposalCommentId)?.body ??
        "";
    const userCommentsAfterProposal = (0, post_completion_comments_1.selectPostCompletionUserComments)({
        comments,
        completedAt: input.proposalCreatedAt,
    }).map((comment) => ({
        author: comment.author,
        createdAt: comment.createdAt,
        body: comment.body,
    }));
    return { proposalBody, userCommentsAfterProposal };
}
function buildFollowupProposalReviewBaseRequest(input) {
    const sourceCompletionSummary = input.request.requests
        .map((request) => request.sourceCompletionSummary)
        .find((summary) => summary !== undefined);
    return {
        ...(sourceCompletionSummary !== undefined
            ? { sourceCompletionSummary }
            : {}),
    };
}
function buildEmptyFollowupProposalReviewRequest() {
    return {
        requestTitle: "Follow-up proposal candidates removed",
        failureReason: "Follow-up proposal review removed all candidates before approval.",
        skipped: true,
    };
}
function buildFollowupProposalReviewFailedRequest(input) {
    return {
        kind: "failed",
        policy: input.request.policy,
        workflowState: input.request.workflowState,
        reason: input.reason,
        preserveProposal: true,
    };
}
function resolveSourceFollowupRequest(input) {
    const hasRequestLabel = hasFollowupRequestLabel(input.context, input.sourceIssue);
    const policy = input.forceProposalPolicy ??
        (hasRequestLabel
            ? "always"
            : (input.workflowState?.followup?.proposalPolicy ?? "off"));
    const stateInput = {
        context: input.context,
        sourceIssue: input.sourceIssue,
        workflowState: input.workflowState,
        policy,
        materializeWorkflowState: input.materializeWorkflowState === true || policy !== "off",
    };
    const workflowState = buildSourceFollowupWorkflowState(stateInput);
    if (policy === "off") {
        return { kind: "none", workflowState };
    }
    const recommendation = workflowState?.followup?.recommendation ?? null;
    if (policy === "if_needed" && recommendation?.recommended !== true) {
        return {
            kind: "skipped",
            policy,
            workflowState,
            reason: recommendation?.reason ??
                "Follow-up automation was enabled, but the worker did not recommend a follow-up.",
        };
    }
    const recommendationSourceFailure = policy === "if_needed"
        ? resolveAutoFollowupRecommendationSourceFailure(workflowState)
        : null;
    if (recommendationSourceFailure !== null) {
        return {
            kind: "failed",
            policy: "if_needed",
            workflowState,
            reason: recommendationSourceFailure,
        };
    }
    const sourceCompletionSummary = resolveSourceCompletionSummary({
        workflowState,
        fallbackSummary: input.completionSummary,
    });
    const baseRequest = {
        ...(sourceCompletionSummary !== null ? { sourceCompletionSummary } : {}),
        ...(input.followupRequestBody !== undefined
            ? { followupRequestBody: input.followupRequestBody }
            : {}),
    };
    if (hasRequestLabel &&
        workflowState?.followup?.proposal !== undefined &&
        workflowState.followup.proposal !== null) {
        return {
            kind: "publish",
            policy: "always",
            workflowState,
            requests: buildApprovedFollowupProposalPublicationRequests({
                items: workflowState.followup.proposal.items,
                baseRequest,
                workflowState,
            }),
            hasRequestLabel,
            fromPendingProposal: true,
            forceAutoPublication: true,
        };
    }
    if (policy === "if_needed") {
        const items = recommendation?.items ?? [];
        if (items.length === 0) {
            return {
                kind: "skipped",
                policy,
                workflowState,
                reason: recommendation?.reason ??
                    "Follow-up automation was enabled, but the worker did not recommend a follow-up.",
            };
        }
        const requests = buildFollowupRecommendationPublicationRequests({
            items,
            baseRequest,
            workflowState,
        });
        if (requests.length === 0) {
            return { kind: "none", workflowState };
        }
        return {
            kind: "publish",
            policy,
            workflowState,
            requests,
            hasRequestLabel,
            forceAutoPublication: input.forceProposalApproval === "auto",
        };
    }
    const recommendationItems = recommendation?.items ?? [];
    if (input.forceProposalPolicy === undefined &&
        input.followupRequestBody === undefined &&
        !hasRequestLabel &&
        recommendationItems.length > 0) {
        return {
            kind: "publish",
            policy,
            workflowState,
            requests: buildFollowupRecommendationPublicationRequests({
                items: recommendationItems,
                baseRequest,
                workflowState,
            }),
            hasRequestLabel,
            forceAutoPublication: input.forceProposalApproval === "auto" || hasRequestLabel,
        };
    }
    return {
        kind: "publish",
        policy,
        workflowState,
        requests: [baseRequest],
        hasRequestLabel,
        forceAutoPublication: input.forceProposalApproval === "auto" || hasRequestLabel,
    };
}
function buildApprovedFollowupProposalPublicationRequests(input) {
    const requests = [];
    for (const item of input.items) {
        const requestDigest = buildFollowupRequestDigest({
            title: item.title,
            body: item.body,
        });
        if (hasCompletedAutoFollowupPublication({
            workflowState: input.workflowState,
            requestDigest,
        })) {
            continue;
        }
        const request = {
            ...input.baseRequest,
            category: item.category,
            followupRequestBody: item.body.trim(),
            followupRequestReason: item.reason.trim(),
            titleSeed: item.title.trim(),
            requestDigest,
            requestTitle: item.title.trim(),
        };
        if (item.workflowTemplate !== undefined) {
            const workflowTemplateSelector = (0, types_2.parseFollowupWorkflowTemplateCandidateSelector)(item.workflowTemplate);
            if (workflowTemplateSelector === null) {
                request.failureReason = `Follow-up proposal included an invalid workflowTemplate value: ${item.workflowTemplate}.`;
            }
            else {
                request.workflowTemplateSelector = workflowTemplateSelector;
            }
        }
        requests.push(request);
    }
    return requests;
}
function buildFollowupRecommendationPublicationRequests(input) {
    const requests = [];
    for (const [sourceIndex, item] of input.items.entries()) {
        const requestDigest = buildFollowupRequestDigest({
            title: item.title,
            body: item.body,
        });
        if (hasCompletedAutoFollowupPublication({
            workflowState: input.workflowState,
            requestDigest,
        })) {
            continue;
        }
        const request = {
            ...input.baseRequest,
            category: item.category,
            followupRequestBody: item.body.trim(),
            followupRequestReason: item.reason.trim(),
            titleSeed: item.title.trim(),
            requestDigest,
            requestTitle: item.title.trim(),
            sourceIndex,
            ...(item.proposalApproval !== undefined
                ? { proposalApproval: item.proposalApproval }
                : {}),
        };
        if (item.workflowTemplate !== undefined) {
            const workflowTemplateSelector = (0, types_2.parseFollowupWorkflowTemplateCandidateSelector)(item.workflowTemplate);
            if (workflowTemplateSelector === null) {
                request.failureReason = `Follow-up recommendation included an invalid workflowTemplate value: ${item.workflowTemplate}.`;
            }
            else {
                request.workflowTemplateSelector = workflowTemplateSelector;
            }
        }
        requests.push({ sourceIndex, request });
    }
    return requests
        .sort((left, right) => left.sourceIndex - right.sourceIndex)
        .map(({ request }) => request);
}
function applyFollowupMaxIssuesPerSource(input) {
    const requests = [];
    const categoryCounts = {
        mainWork: 0,
        maintenance: 0,
    };
    const skippedSummaries = {};
    for (const [fallbackIndex, request] of input.requests.entries()) {
        const category = request.category;
        const sourceIndex = request.sourceIndex ?? fallbackIndex;
        if (category === undefined) {
            requests.push({ sourceIndex, request });
            continue;
        }
        if (categoryCounts[category] >= input.maxIssuesPerSource[category]) {
            const summary = skippedSummaries[category] ?? {
                sourceIndex,
                skippedCount: 0,
            };
            summary.skippedCount += 1;
            skippedSummaries[category] = summary;
            continue;
        }
        categoryCounts[category] += 1;
        requests.push({ sourceIndex, request });
    }
    for (const category of types_2.WORKFLOW_FOLLOWUP_RECOMMENDATION_CATEGORIES) {
        const summary = skippedSummaries[category];
        if (summary === undefined) {
            continue;
        }
        requests.push({
            sourceIndex: summary.sourceIndex,
            request: {
                category,
                requestTitle: `Additional ${category} follow-up recommendation items skipped`,
                failureReason: `Follow-up recommendation included ${String(categoryCounts[category] + summary.skippedCount)} ${category} item(s), exceeding followup.maxIssuesPerSource.${category} (${String(input.maxIssuesPerSource[category])}); only the first ${String(input.maxIssuesPerSource[category])} ${category} item(s) were published.`,
                skipped: true,
            },
        });
    }
    return requests
        .sort((left, right) => left.sourceIndex - right.sourceIndex)
        .map(({ request }) => request);
}
function hasCompletedAutoFollowupPublication(input) {
    return (input.workflowState?.followup?.publications ?? []).some((publication) => publication.requestDigest === input.requestDigest &&
        (publication.status === "created" ||
            publication.status === "reused" ||
            publication.status === "skipped"));
}
function resolveFollowupPublicationContext(input) {
    const config = resolveFollowupEffectiveConfig({
        config: input.context.config,
        sourceWorkflowState: input.sourceWorkflowState,
    });
    return config === input.context.config
        ? input.context
        : {
            ...input.context,
            config,
        };
}
function resolveFollowupEffectiveConfig(input) {
    return (0, control_plane_config_1.resolveIssueEffectiveConfigForWorkflowState)(input.config, input.sourceWorkflowState);
}
function resolveSourceCompletionSummary(input) {
    const finalResultSummary = normalizeFollowupText(input.workflowState?.finalResult?.resultSummary);
    const fallbackSummary = normalizeFollowupText(input.fallbackSummary);
    return fallbackSummary ?? finalResultSummary;
}
function resolveBatchSourceCompletionSummary(input) {
    return (input.requests
        .map((request) => normalizeFollowupText(request.sourceCompletionSummary))
        .find((summary) => summary !== null) ??
        resolveSourceCompletionSummary({ workflowState: input.workflowState }));
}
function resolveAutoFollowupRecommendationSourceFailure(workflowState) {
    const source = workflowState?.followup?.recommendationSource;
    if (source === undefined || source === null) {
        return "Automatic follow-up recommendation was not published because it does not include workflow_closing provenance.";
    }
    if (source.kind !== "workflow_closing") {
        return "Automatic follow-up recommendation was not published because its provenance is not workflow_closing.";
    }
    if (source.freshnessVerified !== true) {
        return "Automatic follow-up recommendation was not published because workflow_closing freshness was not verified.";
    }
    if (!source.workspaceHeadCommitOid.trim()) {
        return "Automatic follow-up recommendation was not published because workflow_closing did not record a workspace HEAD commit.";
    }
    return null;
}
function buildSourceFollowupWorkflowState(input) {
    if (input.workflowState === null && !input.materializeWorkflowState) {
        return null;
    }
    const workflowState = input.workflowState ??
        (0, state_1.buildPersistedWorkflowState)({
            workflowSurface: resolveSourceWorkflowSurface(input.sourceIssue),
            workflowTemplates: (0, template_bindings_1.createUnresolvedWorkflowTemplateBindings)(buildFollowupWorkflowTemplateDefaults(input)),
            baseBranch: input.context.config.repositoryHost.baseBranch,
            executionContract: (0, state_1.createDefaultWorkflowExecutionContract)(),
            plan: null,
            followup: {
                proposalPolicy: input.policy,
                proposalApproval: input.context.config.followup.proposalApproval,
            },
        });
    return {
        ...workflowState,
        followup: {
            ...workflowState.followup,
            proposalPolicy: input.policy,
            proposalApproval: workflowState.followup?.proposalApproval ??
                input.context.config.followup.proposalApproval,
        },
    };
}
function buildFollowupWorkflowTemplateDefaults(input) {
    return (0, control_plane_config_1.resolveWorkflowTemplateDefaultsWithFollowup)(input.context.config);
}
function resolveSourceWorkflowSurface(sourceIssue) {
    return sourceIssue.kind === types_1.TRACKER_ITEM_KINDS.pullRequest
        ? "pull_request"
        : "issue";
}
function applyFollowupPublicationState(input) {
    if (input.workflowState === null) {
        return null;
    }
    const publications = input.workflowState.followup?.publications ?? [];
    if (publications.some((publication) => isSameFollowupPublication(publication, input.publication))) {
        return input.workflowState;
    }
    return {
        ...input.workflowState,
        followup: {
            ...(input.workflowState.followup ?? {
                proposalPolicy: input.policy,
                proposalApproval: "auto",
            }),
            proposalPolicy: input.policy,
            proposal: null,
            publications: [...publications, input.publication],
        },
    };
}
function isSameFollowupPublication(left, right) {
    if (left.requestDigest !== undefined &&
        right.requestDigest !== undefined &&
        left.requestDigest === right.requestDigest) {
        return ((isIssueFollowupPublication(left) && isIssueFollowupPublication(right)) ||
            left.status === right.status);
    }
    if (isIssueFollowupPublication(left) &&
        isIssueFollowupPublication(right) &&
        left.issueId === right.issueId) {
        return true;
    }
    if ("reason" in left &&
        "reason" in right &&
        left.status === right.status &&
        left.reason === right.reason &&
        left.requestTitle === right.requestTitle) {
        return true;
    }
    return false;
}
function isIssueFollowupPublication(publication) {
    return publication.status === "created" || publication.status === "reused";
}
async function publishFollowupSourceWorkflowState(input) {
    await (0, publisher_factory_1.createRunWorkflowPublisher)(input.context).publishWorkflow((0, publish_request_builders_1.buildExistingIssueWorkflowPublishRequest)({
        issueId: input.sourceIssue.id,
        preloadedIssue: input.sourceIssue,
        workflowState: input.workflowState,
        commentCursorPolicy: {
            mode: publisher_shared_1.WORKFLOW_COMMENT_CURSOR_POLICY_MODES.preserve,
        },
        responseLanguage: input.responseLanguage,
    }));
    if (input.clearRequestLabel === true) {
        await publishFollowupSourceUpdate({
            context: input.context,
            sourceIssue: input.sourceIssue,
            responseLanguage: input.responseLanguage,
            clearRequestLabel: true,
        });
    }
}
function buildFollowupPublicationState(result) {
    const at = new Date().toISOString();
    const requestFields = {
        ...(result.requestTitle !== undefined
            ? { requestTitle: result.requestTitle }
            : {}),
        ...(result.requestDigest !== undefined
            ? { requestDigest: result.requestDigest }
            : {}),
        ...(result.category !== undefined ? { category: result.category } : {}),
    };
    switch (result.kind) {
        case "created":
        case "reused":
            return {
                status: result.kind,
                issueId: result.issue.id,
                issueDisplayId: result.issue.displayId,
                url: result.issue.url,
                at,
                ...requestFields,
            };
        case "failed":
        case "skipped":
            return {
                status: result.kind,
                reason: result.reason,
                at,
                ...requestFields,
            };
        case "dry_run":
            return {
                status: "skipped",
                reason: result.reason,
                at,
                ...requestFields,
            };
    }
}
async function createOrReuseFollowupIssue(input) {
    const originLink = buildFollowupOriginLink({
        sourceIssue: input.sourceIssue,
        requestDigest: input.requestDigest,
        requestTitle: input.requestTitle,
    });
    const reusableIssue = await findReusableFollowupIssue({
        context: input.context,
        sourceIssue: input.sourceIssue,
        originLink,
    });
    if (reusableIssue !== null) {
        return {
            kind: "reused",
            issue: reusableIssue,
            sourceFeedbackEligible: true,
        };
    }
    const assignee = await (0, utils_1.resolveSingleServiceAssignee)(input.context.currentUserLogin, input.context.ticketTracker);
    const publisher = (0, publisher_factory_1.createRunWorkflowPublisher)(input.context);
    const followupDraft = buildFollowupIssueDraft({
        sourceIssue: input.sourceIssue,
        sourceWorkflowState: input.sourceWorkflowState,
        responseLanguage: input.responseLanguage,
        sourceCompletionSummary: input.sourceCompletionSummary,
        followupRequestBody: input.followupRequestBody,
        ...(input.followupRequestReason !== undefined
            ? { followupRequestReason: input.followupRequestReason }
            : {}),
        followupRequestBodyIsExplicit: input.followupRequestBodyIsExplicit,
        ...(input.titleSeed !== undefined ? { titleSeed: input.titleSeed } : {}),
    });
    const result = await (0, issue_creation_publication_1.executeIssuePublicationPlans)({
        publisher,
        plans: [
            (0, issue_creation_publication_1.buildCreateIssuePublicationPlan)({
                source: "followup",
                branchTarget: "effective_base_branch",
                relationship: {
                    kind: "followup_origin",
                    sourceIssueId: input.sourceIssue.id,
                },
                title: followupDraft.title,
                body: followupDraft.body,
                trackerFields: {
                    assignees: [assignee],
                    labelNames: [input.workflowLabels.aiReady],
                    ...(input.sourceIssue.milestoneRef !== undefined
                        ? { milestoneRef: input.sourceIssue.milestoneRef }
                        : {}),
                    ...(input.sourceIssue.projectRef !== undefined
                        ? { projectRef: input.sourceIssue.projectRef }
                        : {}),
                },
                workflowState: buildFollowupWorkflowState({
                    sourceWorkflowState: input.sourceWorkflowState,
                    baseBranchDefault: input.context.config.repositoryHost.baseBranch,
                    followupConfig: input.context.config.followup,
                    sourceConsecutiveAiRuns: input.sourceConsecutiveAiRuns ??
                        input.sourceWorkflowState?.consecutiveAiRuns,
                    executionContract: followupDraft.executionContract,
                    followupBinding: input.followupBinding,
                    originLink,
                }),
                runLimitPolicy: {
                    config: input.context.config,
                    workflowLabels: input.workflowLabels,
                },
                newIssueFailurePolicy: "close_created_internal_issue",
                responseLanguage: input.responseLanguage,
            }),
        ],
    });
    const execution = result.executions[0];
    if (execution === undefined || execution.issue === undefined) {
        throw new Error("Follow-up issue was not created.");
    }
    const issue = execution.issue;
    const canonicalIssue = await findCanonicalFollowupIssueAfterCreate({
        context: input.context,
        sourceIssue: input.sourceIssue,
        originLink,
        createdIssue: issue,
        generatedDraft: followupDraft,
    });
    if (canonicalIssue !== null && canonicalIssue.id !== issue.id) {
        await input.context.ticketTracker.closeIssue(issue.id);
        return {
            kind: "reused",
            issue: canonicalIssue,
            sourceFeedbackEligible: false,
        };
    }
    await runCreatedFollowupEventHooks({
        context: input.context,
        request: execution.request,
        publication: execution.publication,
    });
    return { kind: "created", issue, sourceFeedbackEligible: true };
}
async function runCreatedFollowupEventHooks(input) {
    if (input.request === null || input.publication === null) {
        throw new Error("Follow-up issue creation is missing publication details.");
    }
    await (0, runner_1.runEventHooksForPublications)({
        repoRoot: (0, workflow_template_root_1.getWorkflowTemplateRepoRoot)(input.context),
        config: input.context.config,
        publications: [
            {
                request: input.request,
                result: input.publication,
                origin: "issue_creation",
                run: null,
            },
        ],
        ...(input.context.worker !== undefined
            ? { worker: input.context.worker }
            : {}),
        ...(input.context.logHomeDirectory !== undefined
            ? { homeDirectory: input.context.logHomeDirectory }
            : {}),
    });
}
async function findCanonicalFollowupIssueAfterCreate(input) {
    let canonicalIssue = null;
    for (let attempt = 0; attempt < 4; attempt += 1) {
        canonicalIssue = await findReusableFollowupIssue(input);
        if (canonicalIssue !== null &&
            canonicalIssue.id !== input.createdIssue.id) {
            return canonicalIssue;
        }
        if (attempt < 3) {
            await (0, promises_1.setTimeout)(25);
        }
    }
    return canonicalIssue;
}
function isEligibleFollowupSource(issue) {
    return (issue.kind === types_1.TRACKER_ITEM_KINDS.issue ||
        issue.kind === types_1.TRACKER_ITEM_KINDS.pullRequest);
}
async function resolveFollowupWorkflowBinding(input) {
    const selector = input.explicitSelector ?? input.defaultSelector;
    if (selector.mode === "no_template" || selector.mode === "template") {
        const catalog = await (0, template_registry_1.loadWorkflowTemplates)((0, template_registry_1.getWorkflowTemplatesDirectoryPath)(input.repoRoot), input.responseLanguage);
        let binding;
        try {
            binding = (0, template_bindings_1.resolveWorkflowTemplateBinding)({
                catalog,
                surface: "followup",
                selector,
            });
        }
        catch (error) {
            if (!(0, template_bindings_1.isMissingDefaultSystemWorkflowTemplateError)(error)) {
                throw error;
            }
            return {
                kind: "failed",
                reason: (0, catalog_1.translate)(input.responseLanguage, "run.followup.failed.missingTemplate", { templatePath: error.templatePath }),
            };
        }
        if (binding.resolution.kind === "template") {
            return {
                kind: "resolved",
                binding,
            };
        }
        return {
            kind: "failed",
            reason: (0, catalog_1.translate)(input.responseLanguage, "run.followup.failed.missingTemplate", {
                templatePath: selector.mode === "template"
                    ? selector.templatePath
                    : ((0, default_system_workflows_1.resolveDefaultSystemWorkflowTemplatePath)("followup") ??
                        selector.mode),
            }),
        };
    }
    return {
        kind: "resolved",
        binding: (0, template_bindings_1.createWorkflowTemplateBinding)({ selector }),
    };
}
function formatFollowupWorkflowBindingLabel(binding) {
    if (binding.resolution.kind === "template") {
        return binding.resolution.templatePath;
    }
    return binding.selector.mode;
}
async function findReusableFollowupIssue(input) {
    const candidates = await findReusableFollowupIssues(input);
    candidates.sort(compareReusableFollowupIssues);
    return candidates[0] ?? null;
}
async function findReusableFollowupIssues(input) {
    const candidates = await collectReusableFollowupCandidates(input);
    const reusableIssues = [];
    for (const candidate of candidates) {
        if (!isReusableFollowupCandidate(candidate)) {
            continue;
        }
        const workflowState = await (0, workflow_state_read_support_1.resolvePersistedIssueWorkflowState)(input.context.ticketTracker, candidate.id);
        if (workflowState === null) {
            if (input.generatedDraft !== undefined &&
                isGeneratedFollowupDraftCandidate({
                    candidate,
                    generatedDraft: input.generatedDraft,
                    currentUserLogin: input.context.currentUserLogin,
                })) {
                reusableIssues.push(await input.context.ticketTracker.getIssue(candidate.id));
            }
            continue;
        }
        if (workflowState?.workflowSurface !== "followup") {
            continue;
        }
        if (workflowState.originLink === undefined) {
            continue;
        }
        if (!originLinksEqual(workflowState.originLink, input.originLink)) {
            continue;
        }
        reusableIssues.push(await input.context.ticketTracker.getIssue(candidate.id));
    }
    return reusableIssues;
}
async function collectReusableFollowupCandidates(input) {
    const byId = new Map();
    const titleCandidates = await input.context.ticketTracker.searchIssueRecords({
        state: "open",
        mode: "title",
        text: (0, child_issue_title_1.renderParentIssueTitleSuffix)(input.sourceIssue.displayId),
        includePullRequests: false,
        limit: null,
    });
    for (const candidate of titleCandidates) {
        byId.set(candidate.id, candidate);
    }
    const sourceCandidates = await input.context.ticketTracker.searchIssueRecords({
        state: "open",
        mode: "query",
        text: input.sourceIssue.url,
        includePullRequests: false,
        limit: null,
    });
    for (const candidate of sourceCandidates) {
        byId.set(candidate.id, candidate);
    }
    return [...byId.values()];
}
function compareReusableFollowupIssues(left, right) {
    const leftNumber = parseTrackerIssueNumber(left.displayId) ?? parseTrackerIssueNumber(left.id);
    const rightNumber = parseTrackerIssueNumber(right.displayId) ??
        parseTrackerIssueNumber(right.id);
    if (leftNumber !== null &&
        rightNumber !== null &&
        leftNumber !== rightNumber) {
        return leftNumber - rightNumber;
    }
    const updatedComparison = left.updatedAt.localeCompare(right.updatedAt);
    if (updatedComparison !== 0) {
        return updatedComparison;
    }
    return left.id.localeCompare(right.id);
}
function parseTrackerIssueNumber(value) {
    const match = value.match(/\d+/u);
    if (match === null) {
        return null;
    }
    const number = Number(match[0]);
    return Number.isSafeInteger(number) ? number : null;
}
function isReusableFollowupCandidate(issue) {
    return issue.kind === types_1.TRACKER_ITEM_KINDS.issue && issue.isOpen;
}
function isGeneratedFollowupDraftCandidate(input) {
    return (input.currentUserLogin !== undefined &&
        input.candidate.author === input.currentUserLogin &&
        input.candidate.title.trim() === input.generatedDraft.title.trim() &&
        normalizeFollowupBodyForMatch(input.candidate.body) ===
            normalizeFollowupBodyForMatch(input.generatedDraft.body));
}
function normalizeFollowupBodyForMatch(value) {
    return value.replace(/\r\n?/gu, "\n").trim();
}
function buildFollowupWorkflowState(input) {
    const stateInput = {
        workflowSurface: "followup",
        workflowTemplates: (0, template_bindings_1.setWorkflowTemplateBinding)({
            workflowTemplates: input.sourceWorkflowState?.workflowTemplates ??
                (0, template_bindings_1.createUnresolvedWorkflowTemplateBindings)(),
            surface: "followup",
            binding: input.followupBinding,
        }),
        baseBranch: input.sourceWorkflowState?.baseBranch ?? input.baseBranchDefault,
        originLink: input.originLink,
        executionContract: input.executionContract,
        followup: {
            ...resolveFollowupIssueFollowupState(input),
        },
        plan: null,
    };
    if (input.sourceWorkflowState?.priorityRank !== undefined) {
        stateInput.priorityRank = input.sourceWorkflowState.priorityRank;
    }
    const configOverrides = resolveFollowupIssueConfigOverrides(input);
    if (configOverrides !== undefined) {
        stateInput.configOverrides = configOverrides;
    }
    if (input.sourceConsecutiveAiRuns !== undefined) {
        stateInput.consecutiveAiRuns = input.sourceConsecutiveAiRuns;
    }
    if (input.sourceWorkflowState?.totalAiRunHours !== undefined) {
        stateInput.totalAiRunHours = input.sourceWorkflowState.totalAiRunHours;
    }
    return (0, state_1.buildPersistedWorkflowState)(stateInput);
}
function resolveFollowupIssueFollowupState(input) {
    if (input.followupConfig.childIssuePolicy === "off") {
        return (0, types_2.createOffWorkflowFollowupState)();
    }
    return {
        proposalPolicy: input.followupConfig.proposalPolicy,
        proposalApproval: input.followupConfig.proposalApproval,
    };
}
function resolveFollowupIssueConfigOverrides(input) {
    const configOverrides = input.sourceWorkflowState?.configOverrides;
    if (input.followupConfig.childIssuePolicy !== "off") {
        return configOverrides;
    }
    const entries = (configOverrides?.entries ?? []).filter((entry) => !entry.path.startsWith("followup."));
    entries.push({
        op: "set",
        path: "followup.proposalPolicy",
        value: "off",
    });
    return { entries };
}
function buildFollowupOriginLink(input) {
    return {
        kind: "followup",
        sourceIssueId: input.sourceIssue.id,
        sourceIssueDisplayId: input.sourceIssue.displayId,
        sourceIssueUrl: input.sourceIssue.url,
        followupRequestDigest: input.requestDigest,
        followupRequestTitle: input.requestTitle,
    };
}
function originLinksEqual(left, right) {
    return (left.kind === right.kind &&
        left.sourceIssueId === right.sourceIssueId &&
        left.followupRequestDigest === right.followupRequestDigest);
}
function buildFollowupIssueDraft(input) {
    const objectiveSeedInput = {
        ...(input.titleSeed !== undefined ? { titleSeed: input.titleSeed } : {}),
    };
    if (input.followupRequestBodyIsExplicit) {
        objectiveSeedInput.followupRequestBody = input.followupRequestBody;
    }
    const objectiveSeed = resolveFollowupObjectiveSeed(objectiveSeedInput);
    const title = (0, child_issue_title_1.appendParentIssueTitleSuffix)(objectiveSeed ?? (0, base_title_1.resolveIssueBaseTitle)(input.sourceIssue), input.sourceIssue.displayId);
    const body = buildFollowupIssueBody(input);
    return {
        title,
        body,
        executionContract: buildInitialFollowupExecutionContract({
            ...input,
            objectiveSeed,
        }),
    };
}
function buildInitialFollowupExecutionContract(input) {
    const locale = input.responseLanguage;
    const objective = input.objectiveSeed ??
        (0, catalog_1.translate)(locale, "run.followup.contract.defaultObjective", {
            displayId: input.sourceIssue.displayId,
        });
    return {
        ...(0, state_1.createDefaultWorkflowExecutionContract)(objective),
        doneWhen: [
            (0, catalog_1.translate)(locale, "run.followup.contract.doneWhen.requestResolved"),
            (0, catalog_1.translate)(locale, "run.followup.contract.doneWhen.evidenceNamed"),
        ],
        inputs: [
            (0, catalog_1.translate)(locale, "run.followup.contract.input.sourceIssue", {
                displayId: input.sourceIssue.displayId,
                url: input.sourceIssue.url,
            }),
            (0, catalog_1.translate)(locale, "run.followup.contract.input.request", {
                request: input.followupRequestBody.trim(),
            }),
        ],
        outputs: [
            (0, catalog_1.translate)(locale, "run.followup.contract.output.result"),
            (0, catalog_1.translate)(locale, "run.followup.contract.output.evidence"),
        ],
    };
}
function resolveFollowupObjectiveSeed(input) {
    const titleSeed = normalizeFollowupText(input.titleSeed);
    if (titleSeed !== null) {
        return titleSeed;
    }
    const requestBody = normalizeFollowupText(input.followupRequestBody);
    if (requestBody === null) {
        return null;
    }
    const firstParagraph = requestBody
        .split(/\n\s*\n|\r?\n/)
        .map((line) => line.trim())
        .find((line) => line.length > 0);
    if (firstParagraph === undefined || firstParagraph.length > 180) {
        return null;
    }
    return firstParagraph;
}
function buildFollowupRequestMetadata(input) {
    const title = normalizeFollowupText(input.requestTitle) ??
        resolveFollowupObjectiveSeed({
            ...(input.titleSeed !== undefined ? { titleSeed: input.titleSeed } : {}),
            followupRequestBody: input.followupRequestBody,
        }) ??
        (0, base_title_1.resolveIssueBaseTitle)(input.sourceIssue);
    const digest = normalizeFollowupText(input.requestDigest) ??
        buildFollowupRequestDigest({
            title,
            body: input.followupRequestBody,
        });
    return { title, digest };
}
function buildFollowupRequestDigest(input) {
    return (0, node_crypto_1.createHash)("sha256")
        .update(`${input.title.trim()}\n\n${input.body.trim()}`)
        .digest("hex")
        .slice(0, 16);
}
function normalizeFollowupText(value) {
    const trimmed = value?.trim();
    return trimmed === undefined || trimmed.length === 0 ? null : trimmed;
}
function buildFollowupSourceInspectionLines(input) {
    const locale = input.responseLanguage;
    const lines = [
        `- ${(0, catalog_1.translate)(locale, "run.followup.body.sourceIssue")}: [${input.sourceIssue.displayId}](${input.sourceIssue.url})`,
        `- ${(0, catalog_1.translate)(locale, "run.followup.body.sourceInspection")}: \`${buildFollowupSourceInspectionCommand(input.sourceIssue)}\``,
        `- ${(0, catalog_1.translate)(locale, "run.followup.body.postCompletionCommentNote")}`,
    ];
    const childContext = resolvePlannedChildFollowupSourceContext(input.sourceWorkflowState);
    if (childContext === null) {
        return lines;
    }
    const parentLines = [
        ...lines,
        `- ${(0, catalog_1.translate)(locale, "run.followup.body.parentIssue")}: ${childContext.parentRef}`,
        `- ${(0, catalog_1.translate)(locale, "run.followup.body.parentInspection")}: \`${buildFollowupParentInspectionCommand(childContext.parentRef)}\``,
    ];
    if (childContext.parentStepContractSnapshot === undefined) {
        return parentLines;
    }
    return [
        ...parentLines,
        `- ${(0, catalog_1.translate)(locale, "run.followup.body.parentStepObjective")}: ${childContext.parentStepContractSnapshot.objective}`,
        `- ${(0, catalog_1.translate)(locale, "run.followup.body.parentStepDoneWhen")}:`,
        ...formatFollowupContractItemLines(childContext.parentStepContractSnapshot.doneWhen),
        `- ${(0, catalog_1.translate)(locale, "run.followup.body.parentStepOutputs")}:`,
        ...formatFollowupContractItemLines(childContext.parentStepContractSnapshot.outputs),
    ];
}
function buildFollowupSourceInspectionCommand(sourceIssue) {
    return `alpaca issue show --issue ${sourceIssue.id} --view followup --format text`;
}
function buildFollowupParentInspectionCommand(parentRef) {
    return `alpaca issue show --issue ${parentRef.replace(/^#/u, "")} --view full --format text`;
}
function resolvePlannedChildFollowupSourceContext(workflowState) {
    if (workflowState?.workflowSurface !== "issue" ||
        workflowState.parentLink === undefined ||
        workflowState.detachedFromParentReason != null) {
        return null;
    }
    return {
        parentRef: workflowState.parentLink.parentRef,
        ...(workflowState.parentStepContractSnapshot !== undefined
            ? { parentStepContractSnapshot: workflowState.parentStepContractSnapshot }
            : {}),
    };
}
function formatFollowupContractItemLines(values) {
    return values.map((value) => `  - ${value}`);
}
function buildFollowupIssueBody(input) {
    const locale = input.responseLanguage;
    const requestReason = normalizeFollowupText(input.followupRequestReason);
    const reasonLines = requestReason === null
        ? []
        : [
            "",
            `## ${(0, catalog_1.translate)(locale, "run.followup.body.reasonHeading")}`,
            "",
            requestReason,
        ];
    return [
        (0, followup_request_body_1.buildFollowupRequestHeadingLine)(locale),
        "",
        input.followupRequestBody.trim(),
        ...reasonLines,
        "",
        `## ${(0, catalog_1.translate)(locale, "run.followup.body.completionHeading")}`,
        "",
        input.sourceCompletionSummary.trim(),
        "",
        `## ${(0, catalog_1.translate)(locale, "run.followup.body.contextHeading")}`,
        "",
        ...buildFollowupSourceInspectionLines(input),
        "",
        `## ${(0, catalog_1.translate)(locale, "run.followup.body.workHeading")}`,
        "",
        (0, catalog_1.translate)(locale, "run.followup.body.workInstruction"),
    ].join("\n");
}
async function publishFollowupSourceUpdate(input) {
    const label = (0, workflow_labels_1.getFollowupRequestLabelName)(input.context.config.ticketTracker.workflowLabels);
    const currentLabels = input.sourceIssue.labelNames ?? [];
    const nextLabels = input.clearRequestLabel === true
        ? removeFollowupRequestLabel({
            workflowLabels: input.context.config.ticketTracker.workflowLabels,
            sourceIssue: input.sourceIssue,
        })
        : currentLabels;
    const shouldPatchLabels = input.clearRequestLabel === true && currentLabels.includes(label);
    const feedbackSummary = input.feedbackSummary?.trim();
    if (!shouldPatchLabels && !feedbackSummary) {
        return null;
    }
    try {
        const result = await (0, publisher_factory_1.createRunWorkflowPublisher)(input.context).publishWorkflow((0, publish_request_builders_1.buildExistingIssueWorkflowPublishRequest)({
            issueId: input.sourceIssue.id,
            preloadedIssue: input.sourceIssue,
            workflowState: null,
            ...(shouldPatchLabels
                ? { trackerFields: { labelNames: nextLabels } }
                : {}),
            ...(feedbackSummary
                ? {
                    visibleUpdate: {
                        kind: "feedback",
                        summary: feedbackSummary,
                        ...(input.feedbackHeadingKey !== undefined
                            ? { headingKey: input.feedbackHeadingKey }
                            : {}),
                    },
                    visibleUpdateDedupeCursor: null,
                }
                : {}),
            commentCursorPolicy: {
                mode: publisher_shared_1.WORKFLOW_COMMENT_CURSOR_POLICY_MODES.preserve,
            },
            responseLanguage: input.responseLanguage,
        }));
        if (shouldPatchLabels) {
            input.sourceIssue.labelNames = nextLabels;
        }
        return result.visibleUpdateComment;
    }
    catch {
        // Follow-up source feedback should not block close or future retries.
        return null;
    }
}
function removeFollowupRequestLabel(input) {
    const label = (0, workflow_labels_1.getFollowupRequestLabelName)(input.workflowLabels);
    return (input.sourceIssue.labelNames ?? []).filter((current) => current !== label);
}
