"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createTaskScopeRecoverCommand = createTaskScopeRecoverCommand;
const errors_1 = require("../../../lib/errors");
const output_1 = require("../../../lib/output");
const task_scope_recovery_1 = require("../../../lib/planning/task-scope-recovery");
const runtime_contract_1 = require("../../../lib/runtime/runtime-contract");
const global_format_1 = require("../global-format");
async function createTaskScopeRecoverCommand() {
    const { Command } = await import("commander");
    const command = new Command("scope-recover");
    command
        .description("Preview or atomically continue one exact posture-authorized additive scope revision in the existing lifecycle run.")
        .requiredOption("--run-directory <path>", "Existing fresh full-cycle-strict run bound to the selected task.")
        .requiredOption("--task-definition <path>", "Repository-relative canonical task-definition.md path.")
        .requiredOption("--attempt-id <identity>", "Exact open current attempt owning the preserved baseline and evidence.")
        .option("--successor-attempt-id <identity>", "Required when any deterministic addition already changed after the baseline.")
        .requiredOption("--task-revision <revision>", "Exact current 64-character task revision before recovery.")
        .requiredOption("--baseline-id <sha256>", "Exact immutable current-attempt runtime baseline identity.")
        .requiredOption("--contract-impact-fingerprint <sha256>", "Exact current posture-aware contract-impact fingerprint.")
        .option("--add-path <path>", "Repeatable exact proposed addition; omission derives the complete deterministic closure.", collect, [])
        .option("--add-validation <command>", "Repeatable exact proposed validation; omission derives the complete deterministic closure.", collect, [])
        .requiredOption("--recorded-by <actor>", "Non-empty scope-recovery actor.")
        .requiredOption("--recorded-at <timestamp>", "ISO-8601 recovery time with explicit timezone.")
        .requiredOption("--reason <text>", "Non-empty bounded recovery reason.")
        .option("--dry-run", "Classify the exact delta and preview pair writes without mutation; omit to apply.")
        .action((_, commandInstance) => {
        const format = (0, output_1.resolveOutputFormat)((0, global_format_1.getGlobalFormat)(commandInstance));
        if (format === null)
            throw (0, errors_1.createUsageError)("Output format must be one of: text, json.");
        const repository = (0, runtime_contract_1.createRepositoryContext)((0, runtime_contract_1.detectRepositoryRoot)(), false);
        const options = commandInstance.opts();
        const request = {
            repositoryRoot: repository.root,
            runDirectory: options.runDirectory,
            taskDefinitionPath: options.taskDefinition,
            attemptId: options.attemptId,
            successorAttemptId: options.successorAttemptId,
            taskRevision: options.taskRevision,
            baselineId: options.baselineId,
            contractImpactFingerprint: options.contractImpactFingerprint,
            proposedPaths: options.addPath,
            proposedValidationCommands: options.addValidation,
            recordedBy: options.recordedBy,
            recordedAt: options.recordedAt,
            reason: options.reason
        };
        let result;
        try {
            const preview = (0, task_scope_recovery_1.previewTaskScopeRecoverySync)(request);
            result = options.dryRun === true || preview.writeOutcome === "no-write"
                ? preview
                : (0, task_scope_recovery_1.applyTaskScopeRecoverySync)(preview);
        }
        catch (error) {
            throw normalizeScopeRecoveryError(error, options.taskDefinition);
        }
        if (!["previewed", "committed", "no-write"].includes(result.writeOutcome)) {
            throw outcomeError(result);
        }
        const nextAction = result.writeOutcome === "previewed"
            ? applyAction(request)
            : result.nextAction;
        (0, output_1.emitSuccess)({
            command: "task scope-recover",
            format,
            text: renderText(result, nextAction),
            data: {
                ...result,
                repositoryRoot: repository.root,
                detectionSource: repository.detectionSource,
                nextAction
            }
        });
    });
    command.addHelpText("after", [
        "",
        "Boundaries:",
        "  Preview is read-only for the task pair and classifies exact requested or derived additions by posture.",
        "  Apply accepts only the complete required writable/generated/validation closure from the current schema v2 fingerprint.",
        "  Read-only, frozen, unknown, objective, acceptance, ownership, external-authority, and destructive-boundary changes remain explicit no-write blockers.",
        "  Untouched additions amend the open attempt with a supplemental baseline; changed additions preserve all predecessor evidence under contract_gap and open one successor.",
        "  Use global --run-directory, --run-gate, and --run-artifact binding so the same direct or phase-anchored run captures the result."
    ].join("\n"));
    return command;
}
function collect(value, previous) {
    return [...previous, value];
}
function applyAction(request) {
    const argv = [
        "day-shift", "--run-gate", "task-scope-recover-apply",
        "--run-artifact", request.taskDefinitionPath,
        "task", "scope-recover",
        "--run-directory", request.runDirectory,
        "--task-definition", request.taskDefinitionPath,
        "--attempt-id", request.attemptId,
        ...(request.successorAttemptId === undefined || request.successorAttemptId === null
            ? []
            : ["--successor-attempt-id", request.successorAttemptId]),
        "--task-revision", request.taskRevision,
        "--baseline-id", request.baselineId,
        "--contract-impact-fingerprint", request.contractImpactFingerprint,
        ...flatOptions("--add-path", request.proposedPaths ?? []),
        ...flatOptions("--add-validation", request.proposedValidationCommands ?? []),
        "--recorded-by", request.recordedBy,
        "--recorded-at", request.recordedAt,
        "--reason", request.reason,
        "--format", "json"
    ];
    return {
        reasonCode: "apply-recovery",
        command: "task scope-recover",
        argv,
        callable: true,
        writeCapable: true
    };
}
function flatOptions(name, values) {
    return values.flatMap((value) => [name, value]);
}
function normalizeScopeRecoveryError(error, taskPath) {
    if (error instanceof errors_1.RuntimeError)
        return error;
    if (!(error instanceof task_scope_recovery_1.TaskScopeRecoveryError))
        throw error;
    const code = `TASK_SCOPE_RECOVER_${error.code.replace(/-/g, "_").toUpperCase()}`;
    const material = error.code === "material-scope-change" || error.code === "incomplete-delta";
    const exitCode = error.code === "stale-task-revision"
        || error.code === "stale-impact-fingerprint"
        || error.code === "stale-preview"
        ? errors_1.RuntimeExitCode.STALE_EVIDENCE
        : error.code === "git-inspection-unavailable"
            ? errors_1.RuntimeExitCode.UNAVAILABLE_DEPENDENCY
            : material || error.code === "run-ineligible" || error.code === "pair-invalid"
                || error.code === "attempt-mismatch" || error.code === "baseline-mismatch"
                ? errors_1.RuntimeExitCode.INVALID_CONFIG
                : errors_1.RuntimeExitCode.USAGE;
    return new errors_1.RuntimeError({
        message: material
            ? "Task scope recovery is blocked at a material authority boundary."
            : "Task scope recovery was rejected.",
        code,
        exitCode,
        writeOutcome: "no-writes",
        details: [
            error.message,
            `Classification: ${error.classification ?? (material ? "materially-ineligible" : "not-applicable")}.`,
            "No task, summary, attempt, baseline, validation, run, or receipt evidence was rewritten or deleted."
        ],
        findings: [{
                code,
                severity: "error",
                message: error.message,
                path: taskPath,
                noWriteBoundary: "Rejected scope recovery never widens arbitrary scope or mutates immutable lifecycle evidence."
            }],
        recoveryActions: [(0, errors_1.createNonCallableRecoveryAction)({
                id: material
                    ? "recovery.task-scope-recover.explicit-material-authorization"
                    : "recovery.task-scope-recover.refresh-exact-preview",
                command: "task scope-recover",
                explanation: material
                    ? "Obtain explicit authorization for the named authority-boundary change before revising the planning contract."
                    : "Refresh the exact run, task, attempt, baseline, and contract-impact identities before retrying.",
                reason: material
                    ? "A deterministic additive command cannot authorize material objective, acceptance, ownership, external-authority, destructive, read-only, frozen, or unknown changes."
                    : "The failure boundary cannot safely reconstruct stale or conflicting caller identities."
            })]
    });
}
function outcomeError(result) {
    const details = [
        `writeOutcome: ${result.writeOutcome}`,
        `intendedPaths: ${JSON.stringify(result.intendedPaths)}`,
        `changedPaths: ${JSON.stringify(result.changedPaths)}`,
        `conflicts: ${JSON.stringify(result.conflicts)}`,
        `recoveryPath: ${result.recoveryPath ?? "null"}`,
        `failure: ${result.failure ?? "null"}`
    ];
    if (result.writeOutcome === "conflict") {
        return new errors_1.RuntimeError({
            message: "Task scope-recovery preview is stale or conflicted.",
            code: "TASK_SCOPE_RECOVER_CONFLICT",
            exitCode: errors_1.RuntimeExitCode.CONCURRENCY_CONFLICT,
            writeOutcome: "no-writes",
            details
        });
    }
    if (result.writeOutcome === "incomplete") {
        return new errors_1.RuntimeError({
            message: "Task scope recovery stopped with incomplete repository state.",
            code: "TASK_SCOPE_RECOVER_INCOMPLETE",
            exitCode: errors_1.RuntimeExitCode.PARTIAL_MUTATION,
            writeOutcome: "partial",
            details,
            recoveryActions: [(0, errors_1.createNonCallableRecoveryAction)({
                    id: "recovery.inspect-task-scope-recovery-transaction",
                    explanation: "Inspect retained transaction evidence before retrying or repairing the task pair.",
                    reason: result.recoveryPath ?? "The retained transaction path was unavailable."
                })]
        });
    }
    return new errors_1.RuntimeError({
        message: "Task scope recovery produced no canonical result.",
        code: "TASK_SCOPE_RECOVER_NO_WRITE",
        exitCode: errors_1.RuntimeExitCode.ERROR,
        details
    });
}
function renderText(result, nextAction) {
    return [
        "Task additive scope recovery",
        "",
        `Task definition: ${result.taskDefinitionPath}`,
        `Attempt: ${result.attemptId}`,
        `Mode: ${result.mode}`,
        `Recovery ID: ${result.recoveryId}`,
        `Added paths: ${result.addedPaths.length}`,
        `Added validations: ${result.addedValidationCommands.length}`,
        `Invalidated validations: ${result.invalidatedValidationIds.length}`,
        `Write outcome: ${result.writeOutcome}`,
        `Next action: ${nextAction.argv.join(" ")}`
    ].join("\n");
}
