"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createTaskValidationSetCommand = createTaskValidationSetCommand;
const errors_1 = require("../../../lib/errors");
const output_1 = require("../../../lib/output");
const lifecycle_run_context_1 = require("../../../lib/lifecycle-run-context");
const task_validation_set_1 = require("../../../lib/planning/task-validation-set");
const task_validation_1 = require("../../../lib/planning/task-validation");
const task_chronology_recovery_1 = require("../../../lib/planning/task-chronology-recovery");
const task_validation_recovery_1 = require("../../../lib/planning/task-validation-recovery");
const runtime_contract_1 = require("../../../lib/runtime/runtime-contract");
const global_format_1 = require("../global-format");
async function createTaskValidationSetCommand() {
    const { Command } = await import('commander');
    const command = new Command('validation-set');
    command
        .description("Preview or sequentially execute the current task revision's declared validation commands, recording each exact shell-free argv once and stopping on the first required failure.")
        .requiredOption('--task-definition <path>', 'Repository-relative canonical task-definition.md path.')
        .requiredOption('--attempt-id <identity>', 'Owning open current attempt identity.')
        .requiredOption('--task-revision <revision>', 'Exact current 64-character task-definition SHA-256 revision.')
        .option('--validation-id <identity>', 'Execute only this exact unrecorded identity from the current declared set.')
        .option('--retry-validation-id <identity>', 'Execute one exact failed identity as an explicit append-only superseding retry.')
        .option('--timeout-ms <milliseconds>', 'Per-command timeout from 1 through 86400000 milliseconds.', '900000')
        .option('--dry-run', 'Return deterministic command, evidence, retry, and precondition plans without spawning or writing.')
        .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();
        let preview;
        try {
            preview = (0, task_validation_set_1.previewTaskValidationSetSync)({
                repositoryRoot: repository.root,
                taskDefinitionPath: options.taskDefinition,
                attemptId: options.attemptId,
                taskRevision: options.taskRevision,
                validationId: options.validationId,
                retryValidationId: options.retryValidationId,
                timeoutMs: parseTimeout(options.timeoutMs),
            });
        }
        catch (error) {
            if (error instanceof task_validation_1.TaskValidationChronologyError) {
                const chronologyRecovery = resolveChronologyRecoveryAction({
                    commandInstance,
                    repositoryRoot: repository.root,
                    taskDefinitionPath: options.taskDefinition,
                    attemptId: options.attemptId,
                    taskRevision: options.taskRevision,
                    observedAt: error.observedAt,
                });
                throw new errors_1.RuntimeError({
                    message: 'Task validation-set rejected lifecycle chronology before execution.',
                    code: 'TASK_VALIDATION_BEFORE_ATTEMPT_OPEN',
                    exitCode: errors_1.RuntimeExitCode.INVALID_CONFIG,
                    writeOutcome: 'no-writes',
                    details: [
                        error.message,
                        `attemptOpenedAt: ${error.attemptOpenedAt}`,
                        `observedAt: ${error.observedAt}`,
                    ],
                    recoveryActions: chronologyRecovery === null
                        ? [(0, errors_1.createNonCallableRecoveryAction)({
                                id: 'recovery.validation.inspect-attempt-chronology',
                                command: 'task attempt-abort',
                                explanation: 'If the future opened_at is invalid, select the applicable audited attempt recovery; otherwise wait until that instant before previewing validation again.',
                                reason: 'No eligible evidence-preserving chronology recovery was proven from the selected lifecycle run.',
                            })]
                        : [chronologyRecovery],
                });
            }
            throw (0, errors_1.createUsageError)(error instanceof Error ? error.message : String(error), [
                'No declared validation command was inferred, executed, or recorded. Refresh the exact task revision and current attempt before retrying.',
            ]);
        }
        let result = preview;
        if (options.dryRun !== true) {
            try {
                result = (0, task_validation_set_1.applyTaskValidationSetSync)(preview);
            }
            catch (error) {
                throw (0, errors_1.createUsageError)(error instanceof Error ? error.message : String(error), [
                    'Validation-set execution stopped. Do not infer or rerun an outcome that was not returned as a recorded item.',
                ]);
            }
            queuePerCommandLifecycleEvidence(result);
        }
        if (result.outcome === 'failed' || result.outcome === 'blocked') {
            getRootCommand(commandInstance).runtimeExitCode = errors_1.RuntimeExitCode.ERROR;
        }
        (0, output_1.emitSuccess)({
            command: 'task validation-set',
            format,
            text: renderText(result),
            findings: [...result.preflightFindings],
            data: {
                ...result,
                repositoryRoot: repository.root,
                detectionSource: repository.detectionSource,
                shell: false,
                dryRun: options.dryRun === true,
                noWriteBoundary: options.dryRun === true
                    ? 'No declared command was spawned and no task-pair or lifecycle evidence was written.'
                    : null,
            },
        });
    });
    return command;
}
function resolveChronologyRecoveryAction(options) {
    const runDirectory = options.commandInstance.optsWithGlobals().runDirectory;
    if (typeof runDirectory !== 'string' || runDirectory.trim() === '')
        return null;
    try {
        const inspection = (0, lifecycle_run_context_1.inspectLifecycleRunContext)({
            repositoryRoot: options.repositoryRoot,
            runDirectory,
            selectedArtifactPath: options.taskDefinitionPath,
        });
        const reason = 'Recover legacy lifecycle timestamps that conflict with immutable source-run evidence.';
        (0, task_chronology_recovery_1.previewTaskChronologyRecoverySync)({
            repositoryRoot: options.repositoryRoot,
            runDirectory,
            taskDefinitionPath: options.taskDefinitionPath,
            attemptId: options.attemptId,
            taskRevision: options.taskRevision,
            recordedBy: inspection.manifest.actor,
            recordedAt: options.observedAt,
            reason,
        });
        return (0, task_validation_recovery_1.createTaskChronologyRecoveryAction)({
            runDirectory,
            taskDefinitionPath: options.taskDefinitionPath,
            attemptId: options.attemptId,
            taskRevision: options.taskRevision,
            recordedBy: inspection.manifest.actor,
            recordedAt: options.observedAt,
            reason,
        });
    }
    catch {
        return null;
    }
}
function queuePerCommandLifecycleEvidence(result) {
    const executed = new Set(result.executedValidationIds);
    for (const item of result.items) {
        if (!executed.has(item.validationId) && item.state !== 'unrecordable')
            continue;
        const status = item.state === 'unrecordable' ? 'error' : 'ok';
        (0, output_1.queueLifecycleRunCaptureEnvelope)({
            commandIdentity: 'task validation-record',
            artifactPath: result.taskDefinitionPath,
            gate: `task-validation-${String(item.index + 1).padStart(2, '0')}`,
            envelopeText: `${JSON.stringify({
                protocolVersion: 2,
                status,
                command: 'task validation-record',
                ...(status === 'ok'
                    ? { data: lifecycleItemData(item) }
                    : {
                        error: {
                            code: 'TASK_VALIDATION_UNRECORDABLE',
                            message: item.failure ?? 'The exact command outcome could not be recorded.',
                            writeOutcome: 'no-writes',
                        },
                        data: lifecycleItemData(item),
                    }),
            })}\n`,
        });
    }
}
function lifecycleItemData(item) {
    return {
        validationId: item.validationId,
        supersedesValidationId: item.supersedesValidationId,
        index: item.index,
        name: item.name,
        commandArgv: item.commandArgv,
        required: item.required,
        state: item.state,
        status: item.status,
        exitCode: item.exitCode,
        recordedAt: item.recordedAt,
        durationMs: item.durationMs,
        termination: item.termination,
        failureKind: item.failureKind,
        environmentExecutionFailure: item.environmentExecutionFailure,
        executionEvidence: item.executionEvidence,
        recoveryActions: item.state === 'unrecordable' ? itemRecoveryActions(item) : [],
        evidencePath: item.evidencePath,
        writeOutcome: item.state === 'unrecordable' ? 'no-writes' : 'committed',
    };
}
function itemRecoveryActions(item) {
    if (item.environmentExecutionFailure !== null) {
        return [(0, task_validation_recovery_1.createTaskValidationEnvironmentRecoveryAction)(item.environmentExecutionFailure)];
    }
    if (item.executionEvidence === null)
        return [];
    return [(0, task_validation_recovery_1.createTaskValidationUnrecordableRecoveryAction)()];
}
function renderText(result) {
    return [
        'Task validation set',
        '',
        `Task definition: ${result.taskDefinitionPath}`,
        `Attempt ID: ${result.attemptId}`,
        `Task revision: ${result.taskRevision}`,
        `Mode: ${result.mode}`,
        `Outcome: ${result.outcome}`,
        `Declared commands: ${result.declaredCommandCount}`,
        `Executed validations: ${result.executedValidationIds.length}`,
        `Remaining validations: ${result.remainingValidationIds.length}`,
        `Write outcome: ${result.writeOutcome}`,
        `Next action: ${result.nextAction?.argv.join(' ') ?? '(none)'}`,
    ].join('\n');
}
function parseTimeout(value) {
    if (!/^\d+$/u.test(value))
        throw (0, errors_1.createUsageError)('--timeout-ms must be an integer.');
    const timeout = Number(value);
    if (timeout < 1 || timeout > 86_400_000) {
        throw (0, errors_1.createUsageError)('--timeout-ms must be from 1 through 86400000.');
    }
    return timeout;
}
function getRootCommand(commandInstance) {
    let current = commandInstance;
    while (current.parent !== null && current.parent !== undefined)
        current = current.parent;
    return current;
}
