import { VAULT_FORMAT, VAULT_SUITE } from "../namespaces/vault.crypto.js";
import { type RedeemKind, type HandoffKeyPrefixEntry, type RedeemKeyParts, type HandoffKeyParts, type InviteKeyParts, type HandoffSecrets, HANDOFF_KEY_PREFIXES, uuidToBytes, assembleHandoffKey, assembleInviteKey, parseRedeemKey, parseHandoffKey, parseInviteKey, deriveHandoffSecrets, deriveInviteSecrets } from "./bearer-redeem-key.js";
export { HANDOFF_KEY_PREFIXES, uuidToBytes, assembleHandoffKey, assembleInviteKey, parseRedeemKey, parseHandoffKey, parseInviteKey, deriveHandoffSecrets, deriveInviteSecrets, };
export type { RedeemKind, HandoffKeyPrefixEntry, RedeemKeyParts, HandoffKeyParts, InviteKeyParts, HandoffSecrets };
/**
 * Third HKDF output of a redeem key's `master_secret` (design D4, protocol
 * §4.17; kind-parameterized by kygit-invite design D3): the one-use
 * admission Ed25519 seed. Derived directly from `master_secret` —
 * deliberately NEVER from `auth_secret` or `wrap_key` — so the gateway,
 * which receives `auth_secret` at redeem, stays computationally unable to
 * derive this seed and manufacture a different redeemer completion. The info
 * string is domain-separated by kind (`kygit/<kind>/writer-admission/v1`),
 * so an invite's admission seed never matches a handoff's for the same id
 * and master secret.
 */
export declare function deriveRedeemWriterAdmissionSeed(kind: RedeemKind, idBytes: Uint8Array, masterSecret: Uint8Array): Uint8Array;
/** Handoff-bound alias of {@link deriveRedeemWriterAdmissionSeed} — `kygit/handoff/writer-admission/v1`. */
export declare function deriveWriterAdmissionSeed(handoffIdBytes: Uint8Array, masterSecret: Uint8Array): Uint8Array;
/** The invite-kind sibling of {@link deriveWriterAdmissionSeed} — `kygit/invite/writer-admission/v1` (kygit-invite design D3). */
export declare function deriveInviteWriterAdmissionSeed(inviteIdBytes: Uint8Array, masterSecret: Uint8Array): Uint8Array;
export type VaultWriterMintedRole = "owner" | "admin" | "developer" | "billing" | "viewer";
/** Signed by the MINTING writer's own writer key, at handoff mint time. Never chain-stored directly — embedded verbatim inside an admitted `add_writer_key` transition's `authorization.kind:"handoff".grant` once consumed. */
export interface WriterAdmissionGrant {
    format: typeof VAULT_FORMAT;
    object_kind: "writer_admission_grant";
    suite: typeof VAULT_SUITE;
    repo_id: string;
    handoff_id: string;
    auth_hash: string;
    checkpoint_generation: string;
    checkpoint_head_sha256: string;
    grantor_writer_key_id: string;
    handoff_admission_pubkey: string;
    minted_role: VaultWriterMintedRole;
    claim_not_after: string;
    created_at: string;
    signature: string;
}
export interface BuildWriterAdmissionGrantInput {
    repo_id: string;
    handoff_id: string;
    /** The existing kygit-handoff `auth_hash` (from {@link deriveHandoffSecrets}), unrelated to this grant's own signature. */
    auth_hash: string;
    checkpoint_generation: string;
    checkpoint_head_sha256: string;
    minted_role: VaultWriterMintedRole;
    claim_not_after: string;
    created_at?: string;
    /** The MINTER's own existing active writer signing seed — NOT {@link deriveWriterAdmissionSeed}'s one-use seed, which belongs to the grant's `handoff_admission_pubkey` field, never to its signer. */
    grantor_signing_seed: Uint8Array;
    /** Raw 32-byte Ed25519 public key: `ed25519PublicKey(deriveWriterAdmissionSeed(...))`. */
    handoff_admission_pubkey: Uint8Array;
}
/** Mint side (D4): builds + signs `writer_admission_grant`. The gateway's own mint-time validation (grantor active + self-consistent, field equality) is server-side; this function only builds a well-formed, correctly-signed object. */
export declare function buildWriterAdmissionGrant(input: BuildWriterAdmissionGrantInput): WriterAdmissionGrant;
/**
 * Structural + signature verification of a `writer_admission_grant` against
 * the grantor's writer signing pubkey (raw bytes) — does NOT check chain
 * state (grantor active in the predecessor writer state, `handoff_id`
 * unconsumed). That is the caller's job: gateway-side at admission, or a
 * client-side pre-check before spending a grant it did not itself mint.
 */
export declare function verifyWriterAdmissionGrant(grant: WriterAdmissionGrant, grantorSigningPubkeyRaw: Uint8Array): boolean;
/** The statement `writer_acceptance` signs TWICE (design D225's fold of the consultation's separate `writer_key_proof` into a second signature over this same statement). */
export declare const HANDOFF_WRITER_ACCEPT_DOMAIN: "r402s/v0/handoff-writer-accept/v1";
export interface HandoffWriterAcceptStatement {
    domain: typeof HANDOFF_WRITER_ACCEPT_DOMAIN;
    handoff_id: string;
    auth_hash: string;
    writer_key_id: string;
    signing_pubkey: string;
    encryption_pubkey: string;
    encryption_fingerprint: string;
}
/** ONE object, TWO signatures over the SAME statement: possession of the one-use admission capability (`acceptance_signature`) AND possession of the redeemer's own permanent writer key (`possession_signature`). Never chain-stored directly — embedded verbatim inside an admitted `add_writer_key` transition's `authorization.kind:"handoff".acceptance` once consumed. */
export interface WriterAcceptance {
    statement: HandoffWriterAcceptStatement;
    acceptance_signature: string;
    possession_signature: string;
}
export interface BuildWriterAcceptanceInput {
    handoff_id: string;
    auth_hash: string;
    /** {@link deriveWriterAdmissionSeed}'s output — B derives it the SAME way A did, from its own copy of `master_secret`. */
    admission_seed: Uint8Array;
    /** The redeemer's OWN permanent writer signing seed — becomes `writer_key_id`/`signing_pubkey` on the statement. */
    redeemer_signing_seed: Uint8Array;
    redeemer_encryption_pubkey_raw: Uint8Array;
}
/**
 * Redeem side (D4): the redeemer can construct BOTH signatures before ever
 * seeing the stored grant, since it already knows `handoff_id`, `auth_hash`
 * (recomputed exactly as the existing redeem flow already does via
 * {@link deriveHandoffSecrets}), and its own keys.
 */
export declare function buildWriterAcceptance(input: BuildWriterAcceptanceInput): WriterAcceptance;
/**
 * Verifies BOTH signatures over the SAME statement: `acceptance_signature`
 * under the grant's `handoff_admission_pubkey` (proves B legitimately
 * redeemed THIS handoff), `possession_signature` under the statement's own
 * `signing_pubkey` (proves `writer_key_id`/`signing_pubkey` really belong
 * to whoever is submitting it, not a replayed statement about someone
 * else's key). Does not check `handoff_id`/`auth_hash` binding to a stored
 * grant, or single-use — those are the caller's job.
 */
export declare function verifyWriterAcceptance(acceptance: WriterAcceptance, admissionPubkeyRaw: Uint8Array): boolean;
/** The literal payload the mint side seals and the redeem side opens, for the handoff kind. */
export interface HandoffEnvelopePayload {
    v: 1;
    kind: "handoff";
    repo_id: string;
    /** The pinned epoch (16-hex), matching the vault's `epoch` at capture time. */
    epoch: string;
    /** `K_e` for `epoch`, lowercase hex — the vault's own symmetric key, delivered directly. */
    k_e_hex: string;
    /**
     * Every epoch key the minter holds (`epoch` → lowercase hex), so a handoff
     * minted after an epoch rotation lets the recipient open the pre-rotation
     * generations too. Optional: absent on an envelope minted before this
     * field existed, in which case `k_e_hex` for `epoch` is all the recipient
     * gets (a vault that never rotated needs nothing more).
     */
    epoch_keys?: Record<string, string>;
    checkpoint: {
        generation: string;
        commit_oid: string;
    };
    note_schema: "kygit.handoff-note.v1";
}
/** Frame tag for the handoff envelope format — DISTINCT from `r402s/v0`'s `"R402S0"` object frame (design D3: never stored as a vault object). The LEGACY v1 tag: nothing seals it any more, but a pre-vault-multi-writer handoff row still carries one and {@link openHandoffEnvelope} still opens it. */
export declare const HANDOFF_ENVELOPE_KIND: "kygit-handoff-envelope-v1";
/** Seal the handoff payload under `wrap_key` as a LEGACY v1 envelope. Returns the standard-base64 wire form (openapi `format: byte`) + its declared kind tag. Nothing in the shipped flow calls this any more — {@link sealHandoffEnvelopeV2} is what `handoff` seals — but the v1 shape stays openable and sealable for the conformance vectors. */
export declare function sealHandoffEnvelope(handoffIdBytes: Uint8Array, wrapKey: Uint8Array, payload: HandoffEnvelopePayload, nonce?: Uint8Array): {
    sealed_envelope: string;
    envelope_kind: string;
};
/** Open a sealed handoff envelope under `wrap_key` (standard base64 as the redeem response carries it, or base64url). Throws `HANDOFF_ENVELOPE_INVALID` on any header mismatch, a `v:2` (or otherwise non-v1) payload shape, and `HANDOFF_AEAD_AUTH_FAILURE` on a bad key/AAD/ciphertext. */
export declare function openHandoffEnvelope(handoffIdBytes: Uint8Array, wrapKey: Uint8Array, sealedEnvelope: string, envelopeKind?: string): HandoffEnvelopePayload;
/** The v2 envelope kind the handoff mint seals. */
export declare const HANDOFF_ENVELOPE_V2_KIND: "kygit-handoff-envelope-v2";
/** The v2 envelope kind the invite mint seals (kygit-invite design D3) — its own tag, never confusable with the handoff one even for the same id. */
export declare const INVITE_ENVELOPE_V2_KIND: "kygit-invite-envelope-v2";
/**
 * `v: 2` (NOT 1) is the payload's own shape discriminator, independent of
 * `envelope_kind` — a v1 opener's `p.v !== 1` shape check therefore refuses
 * a v2 payload outright (`HANDOFF_ENVELOPE_INVALID`) rather than silently
 * misreading it as v1; `v` and `envelope_kind` agreeing is exactly what
 * makes either one a meaningful, non-spoofable version signal.
 */
export interface HandoffEnvelopePayloadV2 extends Omit<HandoffEnvelopePayload, "v"> {
    v: 2;
    writer_admission_grant_sha256: string;
}
/** The invite-kind sibling of {@link HandoffEnvelopePayloadV2} — identical shape but for its `kind`/`note_schema` tags (kygit-invite design D3: "the payload is otherwise identical to the handoff envelope — the room does NOT ride in the envelope"). */
export interface InviteEnvelopePayloadV2 extends Omit<HandoffEnvelopePayloadV2, "kind" | "note_schema"> {
    kind: "invite";
    note_schema: "kygit.invite-note.v1";
}
/** Seal a v2 handoff envelope — identical framing to {@link sealHandoffEnvelope}, tagged `kygit-handoff-envelope-v2` so its AAD (and therefore its ciphertext) is never confusable with a v1 envelope of the same handoff. */
export declare function sealHandoffEnvelopeV2(handoffIdBytes: Uint8Array, wrapKey: Uint8Array, payload: HandoffEnvelopePayloadV2, nonce?: Uint8Array): {
    sealed_envelope: string;
    envelope_kind: string;
};
/** The invite-kind sibling of {@link sealHandoffEnvelopeV2} — the ONLY invite envelope there is (kygit-invite design D3). */
export declare function sealInviteEnvelope(inviteIdBytes: Uint8Array, wrapKey: Uint8Array, payload: InviteEnvelopePayloadV2, nonce?: Uint8Array): {
    sealed_envelope: string;
    envelope_kind: string;
};
/**
 * Open a v2 envelope for a writer-activation flow. Refuses a v1 (or any
 * other non-v2) `envelope_kind` LOCALLY with `HANDOFF_ENVELOPE_UNSUPPORTED`
 * BEFORE attempting to decrypt anything — post-vault-multi-writer, a
 * writer-activation-aware `resume` needs `writer_admission_grant_sha256` to
 * cross-check the returned grant, and a pre-rev-47 v1 envelope structurally
 * has none. Shares ONLY the frame/AEAD-opening step with
 * {@link openHandoffEnvelope} ({@link openRedeemEnvelope}) — NOT that
 * function itself, since its `v !== 1` shape check would (correctly) refuse
 * a v2 payload; this function applies its own `v !== 2` shape check
 * instead. Callers that only need K_repo/checkpoint delivery, with no
 * writer activation, keep using {@link openHandoffEnvelope} against a v1
 * envelope as before — v1 and v2 are NOT interchangeable at the shape
 * layer, by design.
 */
export declare function openHandoffEnvelopeV2(handoffIdBytes: Uint8Array, wrapKey: Uint8Array, sealedEnvelope: string, envelopeKind: string): HandoffEnvelopePayloadV2;
/** The invite-kind sibling of {@link openHandoffEnvelopeV2} — throws `INVITE_ENVELOPE_UNSUPPORTED` / `INVITE_ENVELOPE_INVALID` / `INVITE_AEAD_AUTH_FAILURE` (kygit-invite design D3). */
export declare function openInviteEnvelope(inviteIdBytes: Uint8Array, wrapKey: Uint8Array, sealedEnvelope: string, envelopeKind?: string): InviteEnvelopePayloadV2;
export interface KygitHandoffNoteCapture {
    base_head: string;
    branch: string | null;
    modified_captured: number;
    untracked_captured: number;
    sensitive_excluded: string[];
    ignored_not_transferred_count: number;
}
/** The fields shared by every redeem-kind note — free-text fields are Markdown. */
interface KygitRedeemNoteBase {
    created_at: string;
    from: {
        agent: string;
        harness?: string;
        model?: string;
    };
    summary: string;
    completed?: string[];
    in_progress?: string[];
    failing?: string[];
    tried?: string[];
    next_steps?: string[];
    commands?: {
        test?: string;
        build?: string;
        run?: string;
    };
    decisions?: string[];
    open_questions?: string[];
    capture: KygitHandoffNoteCapture;
}
/** `kygit.handoff-note.v1` — the handoff commit's message, verbatim JSON. */
export interface KygitHandoffNote extends KygitRedeemNoteBase {
    schema: "kygit.handoff-note.v1";
}
/** `kygit.invite-note.v1` — the invite commit's message, verbatim JSON. Same fields as {@link KygitHandoffNote} (kygit-invite design D3). */
export interface KygitInviteNote extends KygitRedeemNoteBase {
    schema: "kygit.invite-note.v1";
}
export declare function isKygitHandoffNote(value: unknown): value is KygitHandoffNote;
export declare function isKygitInviteNote(value: unknown): value is KygitInviteNote;
export interface HandoffNoteSecretFinding {
    field: string;
    reason: string;
}
/**
 * Refuse a note that carries a bare secret — no override flag exists
 * (design D10): a note is read by another agent, and secrets have the
 * secrets API. `null` when the note is clean.
 */
export declare function scanHandoffNoteForSecrets(note: KygitHandoffNote): HandoffNoteSecretFinding | null;
/** The invite-kind sibling of {@link scanHandoffNoteForSecrets} (kygit-invite design D3). */
export declare function scanInviteNoteForSecrets(note: KygitInviteNote): HandoffNoteSecretFinding | null;
/** Throws `HANDOFF_NOTE_CONTAINS_SECRET` naming the field — call before the handoff commit is written. */
export declare function assertHandoffNoteHasNoSecret(note: KygitHandoffNote): void;
/** Throws `INVITE_NOTE_CONTAINS_SECRET` naming the field — call before the invite commit is written (kygit-invite design D3). */
export declare function assertInviteNoteHasNoSecret(note: KygitInviteNote): void;
//# sourceMappingURL=vault-handoff.d.ts.map