"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.defineCommandDescriptor = defineCommandDescriptor;
exports.normalizeCommandDescriptor = normalizeCommandDescriptor;
exports.normalizeCommandDescriptorRegistry = normalizeCommandDescriptorRegistry;
exports.findCommandDescriptor = findCommandDescriptor;
function defineCommandDescriptor(capability, overrides = {}) {
    const command = capability.command.trim();
    const writeCapable = capability.writeCapable;
    const coordinationScope = capability.coordinationScope ?? "none";
    const authorization = inferAuthorization(writeCapable, coordinationScope);
    const transitionKind = writeCapable
        ? capability.mutationPosture ?? "updates-selected-artifact"
        : "state-observed";
    return {
        ...capability,
        aliases: overrides.aliases ?? [],
        inputs: overrides.inputs ?? [],
        validationNotes: overrides.validationNotes ?? [
            "Arguments and options are validated by the command adapter; descriptor/runtime drift is checked separately."
        ],
        examples: overrides.examples ?? [{
                description: capability.summary,
                argv: [
                    "day-shift",
                    ...command.split(/\s+/),
                    ...(writeCapable ? [] : ["--format", "json"])
                ]
            }],
        semantics: overrides.semantics ?? null,
        effects: overrides.effects ?? {
            filesystem: writeCapable ? "write" : "read",
            scope: capability.targetPathPosture ?? "repository-local evidence",
            network: "none",
            hostState: coordinationScope === "local-installation" ? (writeCapable ? "write" : "read") : "none",
            destructive: false,
            interactive: false
        },
        authorization: overrides.authorization ?? authorization,
        confirmation: overrides.confirmation ?? (writeCapable ? "explicit-command" : "none"),
        selectionRequired: overrides.selectionRequired ?? coordinationScope === "selected-artifact",
        idempotency: overrides.idempotency ?? (writeCapable ? "operation-defined" : "idempotent"),
        preconditions: overrides.preconditions ?? (coordinationScope === "selected-artifact" ? [{
                id: "selected-artifact",
                description: "A current repository-relative planning artifact selection is available.",
                kind: "selection",
                required: true
            }] : []),
        transition: overrides.transition ?? {
            id: `${command.replace(/\s+/g, ".")}:${transitionKind}`,
            kind: transitionKind,
            expected: writeCapable
                ? `Applies the declared ${transitionKind} transition within ${coordinationScope} scope.`
                : "Returns current evidence without changing repository or host state.",
            expectedPostconditions: [{
                    id: writeCapable ? "declared-transition-applied" : "state-reported-without-write",
                    description: writeCapable
                        ? `The declared ${transitionKind} transition is reflected by canonical repository evidence.`
                        : "Current evidence is returned and repository and host state remain unchanged."
                }]
        }
    };
}
function normalizeCommandDescriptor(registration, normalizeCapability) {
    const capability = normalizeCapability(registration);
    const aliases = normalizeTextList(registration.aliases, `${capability.command} aliases`);
    const validationNotes = normalizeTextList(registration.validationNotes, `${capability.command} validationNotes`, true);
    const inputs = Object.freeze(registration.inputs.map((input, index) => normalizeInput(input, `${capability.command} input ${index + 1}`)));
    const examples = Object.freeze(registration.examples.map((example, index) => normalizeExample(example, capability.command, index)));
    const semantics = normalizeSemanticContract(registration.semantics, capability.command);
    const preconditions = Object.freeze(registration.preconditions.map((precondition, index) => normalizePrecondition(precondition, `${capability.command} precondition ${index + 1}`)));
    const expectedPostconditions = Object.freeze(registration.transition.expectedPostconditions.map((postcondition, index) => ({
        id: requireIdentifier(postcondition.id, `${capability.command} expected postcondition ${index + 1} id`),
        description: requireText(postcondition.description, `${capability.command} expected postcondition ${index + 1} description`)
    })));
    if (capability.availability === "callable" && examples.length === 0) {
        throw new Error(`Command '${capability.command}' must declare at least one exact argv example.`);
    }
    if (semantics !== null && JSON.stringify(semantics.exactExamples) !== JSON.stringify(examples.map((example) => example.argv))) {
        throw new Error(`Command '${capability.command}' semantic exact examples must match descriptor examples.`);
    }
    if (capability.availability !== "callable" && examples.length > 0) {
        throw new Error(`Non-callable command '${capability.command}' must not declare runnable argv examples.`);
    }
    if (expectedPostconditions.length === 0) {
        throw new Error(`Command '${capability.command}' must declare at least one expected postcondition.`);
    }
    validateSafetyMetadata(registration, capability);
    return Object.freeze({
        ...capability,
        aliases,
        inputs,
        validationNotes,
        examples,
        semantics,
        effects: Object.freeze({ ...registration.effects }),
        authorization: registration.authorization,
        confirmation: registration.confirmation,
        selectionRequired: registration.selectionRequired,
        idempotency: registration.idempotency,
        preconditions,
        transition: Object.freeze({
            ...registration.transition,
            id: requireIdentifier(registration.transition.id, `${capability.command} transition id`),
            expected: requireText(registration.transition.expected, `${capability.command} transition expected`),
            expectedPostconditions
        })
    });
}
function normalizeSemanticContract(contract, command) {
    if (contract === null)
        return null;
    const normalizeRuleInput = (value, label) => requireIdentifier(value, label);
    const normalized = {
        conditionalInputs: Object.freeze(contract.conditionalInputs.map((rule, index) => Object.freeze({
            input: normalizeRuleInput(rule.input, `${command} conditional input ${index + 1}`),
            whenInput: normalizeRuleInput(rule.whenInput, `${command} conditional source ${index + 1}`),
            equals: rule.equals
        }))),
        dependentInputs: Object.freeze(contract.dependentInputs.map((rule, index) => Object.freeze({
            input: normalizeRuleInput(rule.input, `${command} dependent input ${index + 1}`),
            requires: Object.freeze(rule.requires.map((value, relatedIndex) => normalizeRuleInput(value, `${command} dependent input ${index + 1} requirement ${relatedIndex + 1}`)))
        }))),
        conflictingInputs: Object.freeze(contract.conflictingInputs.map((rule, index) => {
            const inputs = Object.freeze(rule.inputs.map((value, inputIndex) => normalizeRuleInput(value, `${command} conflict ${index + 1} input ${inputIndex + 1}`)));
            if (inputs.length < 2)
                throw new Error(`${command} conflict ${index + 1} must name at least two inputs.`);
            return Object.freeze({ inputs });
        })),
        mutableFields: normalizeTextList(contract.mutableFields, `${command} mutableFields`),
        genericGuards: Object.freeze(contract.genericGuards.map((guard, index) => Object.freeze({
            id: requireIdentifier(guard.id, `${command} generic guard ${index + 1} id`),
            description: requireText(guard.description, `${command} generic guard ${index + 1} description`)
        }))),
        failureTaxonomy: Object.freeze({ ...contract.failureTaxonomy }),
        recoveries: Object.freeze(contract.recoveries.map((recovery, index) => Object.freeze({
            command: requireText(recovery.command, `${command} recovery ${index + 1} command`),
            requiredInputs: Object.freeze(recovery.requiredInputs.map((value, inputIndex) => normalizeRuleInput(value, `${command} recovery ${index + 1} required input ${inputIndex + 1}`))),
            callableWhen: recovery.callableWhen,
            availability: recovery.availability
        }))),
        exactExamples: Object.freeze(contract.exactExamples.map((argv, index) => Object.freeze(normalizeExample({ description: `Semantic example ${index + 1}.`, argv }, command, index).argv)))
    };
    if (JSON.stringify(normalized.exactExamples) !== JSON.stringify(contract.exactExamples.map((argv) => [...argv]))) {
        throw new Error(`Command '${command}' semantic exact examples could not be normalized.`);
    }
    return Object.freeze(normalized);
}
function normalizeCommandDescriptorRegistry(registrations, normalizeCapability) {
    const seen = new Set();
    return Object.freeze(registrations.map((registration) => {
        const descriptor = normalizeCommandDescriptor(registration, normalizeCapability);
        if (seen.has(descriptor.command)) {
            throw new Error(`Duplicate command descriptor registration for '${descriptor.command}'.`);
        }
        seen.add(descriptor.command);
        return descriptor;
    }));
}
function findCommandDescriptor(registry, command) {
    return registry.find((entry) => entry.command === command) ?? null;
}
function inferAuthorization(writeCapable, coordinationScope) {
    if (!writeCapable)
        return "read";
    return coordinationScope === "local-installation" ? "host-write" : "workspace-write";
}
function validateSafetyMetadata(registration, capability) {
    const command = capability.command;
    const expectedArgvPrefix = ["day-shift", ...command.split(/\s+/)];
    const effects = registration.effects;
    if (!["none", "read", "write"].includes(effects.hostState)
        || typeof effects.destructive !== "boolean"
        || typeof effects.interactive !== "boolean") {
        throw new Error(`Command '${command}' must declare host-state, destructive, and interactive posture.`);
    }
    if ((effects.destructive || effects.network !== "none" || effects.hostState === "write")
        && registration.confirmation !== "explicit-command") {
        throw new Error(`Command '${command}' has destructive, networked, or host-write effects without explicit confirmation.`);
    }
    for (const example of registration.examples) {
        if (!expectedArgvPrefix.every((segment, index) => example.argv[index] === segment)) {
            throw new Error(`Command '${command}' example argv must start with '${expectedArgvPrefix.join(" ")}'.`);
        }
    }
    if (!capability.writeCapable) {
        if (registration.authorization !== "read"
            || registration.confirmation !== "none"
            || registration.effects.filesystem === "write"
            || registration.effects.hostState === "write"
            || registration.effects.destructive
            || registration.transition.kind !== "state-observed") {
            throw new Error(`Read-only command '${command}' has inconsistent authorization, effects, confirmation, or transition metadata.`);
        }
        return;
    }
    if (registration.authorization === "read"
        || registration.confirmation === "none"
        || registration.effects.filesystem !== "write"
        || registration.transition.kind === "state-observed") {
        throw new Error(`Write-capable command '${command}' has inconsistent authorization, effects, confirmation, or transition metadata.`);
    }
    if (registration.selectionRequired !== (capability.coordinationScope === "selected-artifact")) {
        throw new Error(`Command '${command}' selectionRequired must match selected-artifact coordination scope.`);
    }
}
function normalizeInput(input, label) {
    if (input.kind !== "argument" && input.kind !== "option") {
        throw new Error(`${label} uses unsupported kind '${input.kind}'.`);
    }
    return Object.freeze({
        ...input,
        name: requireText(input.name, `${label} name`),
        valueType: input.valueType ?? "string",
        validation: requireText(input.validation, `${label} validation`)
    });
}
function normalizePrecondition(precondition, label) {
    if (!["selection", "artifact-state", "command-input"].includes(precondition.kind)) {
        throw new Error(`${label} uses unsupported kind '${precondition.kind}'.`);
    }
    return Object.freeze({
        id: requireIdentifier(precondition.id, `${label} id`),
        description: requireText(precondition.description, `${label} description`),
        kind: precondition.kind,
        required: precondition.required
    });
}
function normalizeExample(example, command, index) {
    if (!Array.isArray(example.argv) || example.argv.length === 0
        || example.argv.some((value) => typeof value !== "string" || value.length === 0)) {
        throw new Error(`Command '${command}' example ${index + 1} must provide a non-empty exact argv array.`);
    }
    return Object.freeze({
        description: requireText(example.description, `${command} example ${index + 1} description`),
        argv: Object.freeze([...example.argv])
    });
}
function normalizeTextList(values, label, requireEntry = false) {
    const normalized = Object.freeze(values.map((value, index) => requireText(value, `${label} ${index + 1}`)));
    if (requireEntry && normalized.length === 0)
        throw new Error(`${label} must not be empty.`);
    return normalized;
}
function requireText(value, label) {
    if (typeof value !== "string" || value.trim().length === 0)
        throw new Error(`${label} must be a non-empty string.`);
    return value.trim();
}
function requireIdentifier(value, label) {
    const normalized = requireText(value, label);
    if (!/^[a-z0-9]+(?:[.:_-][a-z0-9]+)*$/.test(normalized)) {
        throw new Error(`${label} must use a stable lowercase identifier.`);
    }
    return normalized;
}
