"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createResumeCreateCommand = createResumeCreateCommand;
exports.createResumeInspectCommand = createResumeInspectCommand;
exports.createResumeResumeCommand = createResumeResumeCommand;
exports.createResumeClearCommand = createResumeClearCommand;
exports.createResumeCleanupCommand = createResumeCleanupCommand;
const errors_1 = require("../../../lib/errors");
const agent_context_1 = require("../../../lib/agent-context");
const output_1 = require("../../../lib/output");
const resume_capsule_1 = require("../../../lib/resume-capsule");
const work_selection_1 = require("../../../lib/work-selection");
const runtime_contract_1 = require("../../../lib/runtime/runtime-contract");
async function createResumeCreateCommand() {
    const { Command } = await import("commander");
    return new Command("create")
        .description("Create or explicitly replace an evidence-backed user-local resume capsule.")
        .requiredOption("--artifact <path>", "Repository-relative selected planning artifact.")
        .option("--session <name>", "Named local session. Defaults to default.")
        .option("--completed-action <id...>", "Historical completed action ids to record.")
        .option("--evidence <path...>", "Repository-relative evidence paths to hash.")
        .option("--postcondition <path...>", "Repository-relative postcondition evidence paths to hash.")
        .option("--blocker <text...>", "Unresolved blocker evidence to preserve.")
        .option("--expires-in-hours <hours>", "Positive expiry in hours. Defaults to 24.")
        .option("--if-match <token>", "Opaque token from resume inspect; required to replace existing state.")
        .action((options, commandInstance) => {
        const root = repositoryRoot(commandInstance);
        const context = (0, agent_context_1.createArtifactAgentContext)({ repositoryRoot: root, artifactPath: options.artifact, session: options.session, detail: "compact" });
        const result = (0, resume_capsule_1.createResumeCapsule)({
            repositoryRoot: root,
            artifactPath: context.selection.artifactPath,
            session: options.session,
            completedActionIds: options.completedAction,
            evidencePaths: options.evidence,
            postconditionPaths: options.postcondition,
            unresolvedBlockers: options.blocker,
            nextAction: context.recommendedNextAction,
            expiresInMs: parseExpiry(options.expiresInHours),
            ifMatch: options.ifMatch
        });
        emit("resume create", commandInstance, result, true, "Resume capsule updated");
    });
}
async function createResumeInspectCommand() {
    const { Command } = await import("commander");
    return new Command("inspect")
        .description("Inspect capsule freshness without writing capsule or selection state.")
        .option("--artifact <path>", "Explicit artifact identity for conflict checking.")
        .option("--session <name>", "Named local session. Defaults to default.")
        .action((options, commandInstance) => {
        const root = repositoryRoot(commandInstance);
        const selection = (0, work_selection_1.inspectWorkSelection)({ repositoryRoot: root, session: options.session });
        const result = (0, resume_capsule_1.inspectResumeCapsule)({ repositoryRoot: root, session: options.session, explicitArtifactPath: options.artifact, selectedArtifactPath: selection.state === "fresh" ? selection.selection?.artifactPath : null });
        emit("resume inspect", commandInstance, { ...result, readOnly: true, noWriteBoundary: "Inspection does not create, refresh, replace, clear, or clean capsule or selection state." }, false, "Resume capsule inspection");
    });
}
async function createResumeResumeCommand() {
    const { Command } = await import("commander");
    return new Command("resume")
        .description("Revalidate a capsule and report the currently permitted next action without writing state.")
        .option("--artifact <path>", "Explicit artifact identity; takes precedence and conflicts fail closed.")
        .option("--session <name>", "Named local session. Defaults to default.")
        .action((options, commandInstance) => {
        const root = repositoryRoot(commandInstance);
        const selection = (0, work_selection_1.inspectWorkSelection)({ repositoryRoot: root, session: options.session });
        const inspection = (0, resume_capsule_1.resumeFromCapsule)({ repositoryRoot: root, session: options.session, explicitArtifactPath: options.artifact, selectedArtifactPath: selection.state === "fresh" ? selection.selection?.artifactPath : null });
        assertResumable(inspection);
        const context = (0, agent_context_1.createArtifactAgentContext)({ repositoryRoot: root, artifactPath: inspection.capsule.artifactPath, session: options.session, detail: "compact" });
        emit("resume resume", commandInstance, {
            ...inspection,
            currentNextAction: context.recommendedNextAction,
            currentBlockers: context.relevantBlockers,
            recordedNextActionMatches: inspection.capsule.nextAction.id === context.recommendedNextAction.id,
            readOnly: true,
            noWriteBoundary: "Resume revalidates canonical evidence and reports current action legality without changing capsule or selection state."
        }, false, "Resume capsule is fresh");
    });
}
async function createResumeClearCommand() {
    const { Command } = await import("commander");
    return new Command("clear").description("Clear one named resume capsule explicitly.")
        .option("--session <name>", "Named local session. Defaults to default.")
        .option("--if-match <token>", "Opaque token from resume inspect; required when state exists.")
        .action((options, commandInstance) => emit("resume clear", commandInstance, (0, resume_capsule_1.clearResumeCapsule)({ repositoryRoot: repositoryRoot(commandInstance), ...options }), true, "Resume capsule clear"));
}
async function createResumeCleanupCommand() {
    const { Command } = await import("commander");
    return new Command("cleanup").description("Clear one stale or expired capsule while preserving fresh or absent state.")
        .option("--session <name>", "Named local session. Defaults to default.")
        .option("--if-match <token>", "Opaque token from resume inspect; required to clear stale state.")
        .action((options, commandInstance) => emit("resume cleanup", commandInstance, (0, resume_capsule_1.cleanupResumeCapsule)({ repositoryRoot: repositoryRoot(commandInstance), ...options }), true, "Resume capsule cleanup"));
}
function assertResumable(value) {
    if (value.state === "fresh")
        return;
    if (value.state === "conflict") {
        throw new errors_1.RuntimeError({
            code: "RESUME_SELECTION_CONFLICT",
            exitCode: errors_1.RuntimeExitCode.CONCURRENCY_CONFLICT,
            message: "Resume capsule conflicts with current explicit or selected artifact evidence.",
            details: [`Capsule artifact: ${value.capsule?.artifactPath}`, `Current artifact: ${value.conflict?.explicitArtifactPath}`, "No capsule or selection state was changed."],
            recoveryActions: [(0, errors_1.createDescriptorBackedRecoveryAction)({ command: "resume clear", argv: ["day-shift", "resume", "clear", "--session", value.session, "--if-match", value.preconditionToken], explanation: "Clear the conflicting capsule explicitly after reviewing current evidence." })]
        });
    }
    if (value.state === "stale") {
        throw new errors_1.RuntimeError({
            code: "RESUME_CAPSULE_STALE",
            exitCode: errors_1.RuntimeExitCode.STALE_EVIDENCE,
            message: "Resume capsule evidence is stale and cannot prove action completion.",
            details: [`Reason: ${value.staleReason}`, "Completed action ids were suppressed. No capsule or selection state was changed."],
            recoveryActions: [(0, errors_1.createDescriptorBackedRecoveryAction)({ command: "resume cleanup", argv: ["day-shift", "resume", "cleanup", "--session", value.session, "--if-match", value.preconditionToken], explanation: "Clear stale capsule state after reviewing current evidence." })]
        });
    }
    throw new errors_1.RuntimeError({
        code: "RESUME_CAPSULE_MISSING",
        exitCode: errors_1.RuntimeExitCode.USAGE,
        message: "No resume capsule is available for this session.",
        details: ["Create a capsule from an explicit artifact and current workflow evidence. No state was changed."],
        recoveryActions: [(0, errors_1.createNonCallableRecoveryAction)({ id: "recovery.create-resume-capsule", command: "resume create", explanation: "Create a capsule for the intended artifact.", reason: "No authoritative artifact value is available for exact create argv." })]
    });
}
function parseExpiry(value) {
    if (value === undefined)
        return undefined;
    const hours = Number(value);
    if (!Number.isFinite(hours) || hours <= 0)
        throw (0, errors_1.createUsageError)("--expires-in-hours must be a positive number.");
    return Math.round(hours * 60 * 60 * 1000);
}
function emit(command, commandInstance, data, write, heading) {
    const format = (0, output_1.resolveOutputFormat)(commandInstance.optsWithGlobals?.().format);
    if (format === null)
        throw (0, errors_1.createUsageError)("Output format must be one of: text, json.");
    (0, output_1.emitSuccess)({ command, format, data: write ? { ...data, stateSurface: "user-local resume capsule" } : data, text: [heading, `Session: ${data.session}`, `State: ${data.state ?? data.reason ?? "updated"}`, (0, output_1.renderTerminalBoundary)(write ? { kind: data.changed === false ? "mutating-no-op" : "write-applied", reason: data.changed === false ? data.reason : undefined, target: data.session, stateSurface: "user-local resume capsule" } : { kind: "read-only" })].join("\n") });
}
function repositoryRoot(commandInstance) {
    const root = commandInstance?.parent?.parent ?? commandInstance;
    return (root?.configRepositoryContext ?? (0, runtime_contract_1.createRepositoryContext)((0, runtime_contract_1.detectRepositoryRoot)(), false)).root;
}
