/**
 * `r.repos` — the host-blind encrypted Git remote, as the SDK's programmatic
 * API (add-vault task 5.10).
 *
 * ARCHITECTURAL LAW (client-surface spec, "All protocol logic lives in the
 * SDK"): every piece of vault protocol behaviour — crypto core, keystore,
 * creation journal, snapshot + capture, publication state machines, ref
 * transactions, verification budget, token exchange, repair — is implemented
 * ONCE here. `run402 repos …`, `git-remote-run402`, and the MCP tools are
 * adapters over this namespace: argument parsing, TTY output, exit codes, and
 * local file I/O only. Anything the CLI can do is reachable programmatically
 * with identical semantics.
 *
 * `r402s-verify` is the deliberate exception: an independent second lineage
 * that must NOT share implementation code with this namespace, because
 * differential verification is its entire purpose.
 *
 * ISOMORPHIC / NODE SPLIT. Vault reads (the record, heads listing, policy,
 * override completion) need nothing but the HTTP client and run anywhere. The
 * verbs that touch a git working tree or the on-disk keystore — `init`,
 * `push`, `compact`, `verify`, `deploy`, `restore` — are Node-only and are
 * reached through DYNAMIC imports of `../node/*`, so importing `@run402/sdk`
 * in a browser or worker never pulls `node:fs` into the graph.
 *
 * CACHING. Nothing here is memoised. Two of these responses are
 * secret-bearing — the maintenance lease's `holder_token` (returned exactly
 * once) and anything derived from the keystore — and per
 * docs/agent-response-design.md a secret-bearing response is never cached,
 * never persisted into an agent-surface result store, and never logged.
 */
import type { Client } from "../kernel.js";
import { VAULT_BYO_UNMIRRORED_REMEDY_STATEMENT, VAULT_DURABILITY_STATEMENT, VAULT_MIRROR_KEYSTORE_STILL_REQUIRED_STATEMENT, VAULT_MIRROR_VALIDITY_NOT_FRESHNESS_STATEMENT, VAULT_TERMINAL_LOSS_DOCTOR_TEXT, VAULT_TERMINAL_LOSS_STATEMENT, VAULT_UNMIRRORED_FINDING_STATEMENT } from "./vault.crypto.js";
import type { NextAction } from "../errors.js";
/** The cold open's own verdicts — surfaced from `open()`; anything else leaves the handle lazy (see `open`). */
import type { VaultCaptureReceipt, VaultHeadsListingPage, VaultHeadsListingRequest, VaultHeadTarget, VaultOpenReceipt, VaultRecipientConfirmationReceipt, VaultRecoveryReceipt, VaultRotationReason } from "./vault.types.js";
import type { VaultCompactionGrant, VaultMaintenanceLease, VaultMaintenanceLeaseRequest, VaultTransport, VaultRecord } from "../node/vault-publication.js";
import type { VaultDeployOptions, VaultDeployResult } from "../node/vault-deploy.js";
import type { VaultPublishResult, VaultRefMap, VaultReconcileEnvelopeRecipientsResult, VaultReconcileWriterAdmissionsResult, VaultVerifiedState } from "../node/vault-publication.js";
import type { VaultCreationResult } from "../node/vault-creation-journal.js";
import type { VaultKeystore } from "../node/vault-keystore.js";
import type { VaultSnapshot } from "../node/vault-snapshot.js";
import type { VaultMirrorConfig, VaultMirrorCredential } from "../node/vault-mirror-config.js";
import type { VaultByoPresenceReport, VaultMirrorPushResult, VaultMirrorSyncSummary } from "../node/vault-mirror.js";
import type { VaultRecoverResult, VaultVerifyReport } from "../node/vault-recover.js";
import type { VaultMemberRecoveryBundle } from "../node/vault-member-bundle.js";
import type { VaultDegradedReadLive, VaultDegradedReadOutcome, VaultDegradedReadSource } from "../node/vault-degraded-read.js";
import type { RoomPresence } from "./rooms.types.js";
/** What `r.repos.status()` reports. Never carries key material. */
export interface VaultStatus {
    repo_id: string | null;
    project_id: string | null;
    /** The control plane's view. `null` when no vault is allocated for the project. */
    vault: VaultRecord | null;
    /** vault-agent-envelopes D5: what this KEY-HOLDER's session-start fulfilment did (`null` on a machine that holds no K_repo, or `reconcile: "forbidden"`). */
    reconcile_recipients?: VaultSessionReconcileResult | null;
    /** vault-agent-envelopes D3: what the enroll-if-absent step did for this keystore's key (`null` when it did not run). */
    enrollment?: VaultEnrollmentOutcome | null;
    keystore: {
        present: boolean;
        /** The principal's Ed25519 signing fingerprint, or `null` when identity is absent. */
        identity_fingerprint: string | null;
        /** `false` ⇒ read-only: this principal can decrypt and verify but cannot sign a head. */
        can_sign: boolean;
        /** `true` once this machine holds K_repo for the vault. */
        holds_repo_key: boolean;
        /**
         * WHERE the keystore lives, and what is in it.
         *
         * Terminal loss is stated three times in this surface; until 5.13 the path
         * to back up was stated nowhere, which made the warning unactionable. These
         * are file paths, never contents — nothing here is key material.
         * `repo` / `recovery_receipt` are `null` until a `repo_id` is known.
         */
        root: string;
        paths: {
            identity: string;
            repos: string;
            receipts: string;
            journal: string;
            audit_log: string;
            repo: string | null;
            recovery_receipt: string | null;
        };
    };
    /**
     * The `run402` git remote in the local repository, when there is one to read.
     * `null` when no `repo_dir` was given, the directory is not a repository, or
     * no such remote is configured.
     *
     * `matches` is a TRI-STATE. For an ID-FORM remote
     * (`run402::<org_id>/<project_id>`) it is `true`/`false` from the URL text
     * alone — the second half is a real project id, so comparing it against
     * this status's own project needs no lookup. For a SLUG-FORM remote
     * (`run402::<org-slug>/<name>`) the URL's second half is a repo NAME, not
     * a project id — comparing it as if it were one made a CORRECTLY
     * configured slug-form remote always report `matches: false` (the bug).
     * Instead it is compared against the local id-pin (`git config
     * r402.repoId`, task 4.5): pin present + equal → `true`; pin present +
     * different → `false`; no pin yet → `null` with `reason` explaining why
     * (no network read — `status` stays a pure observation). Render NO
     * mismatch warning for the `null` case anywhere — it is not evidence of
     * anything wrong, only of "not yet resolved on this machine".
     */
    remote: {
        name: string;
        url: string;
        matches: boolean | null;
        reason: string | null;
    } | null;
    /**
     * The id-pinning state of this checkout — `null`
     * when no `repo_dir` was given, or nothing is pinned there yet. A SLUG-form
     * remote pins `repo_id` in local git state the first time it resolves;
     * `resolved_from` names the `org-slug/name` it was resolved from. An
     * id-form remote never pins (it needs no pin — see
     * `resolveVaultAddress`'s doc comment), so a checkout on one always
     * reports `null` here even once its vault is otherwise fully resolved.
     */
    pinned: {
        repo_id: string;
        resolved_from: {
            org_slug: string;
            repo_name: string;
        } | null;
        room: string | null;
    } | null;
    /**
     * Whether this checkout's LOCAL `.git/info/exclude` already carries
     * `.run402/` (kygit-invite design D9's risk list: "`.git/info/exclude`
     * is per-clone and silent" — this is what makes the state visible).
     * `null` when no `repo_dir` was given.
     */
    messaging_cache_excluded: boolean | null;
    /**
     * The vault's ref map and HEAD target — present only when `refs: true` was
     * requested. Reading them means MATERIALIZING the chain, which is a
     * verification and advances the local materialized pin, so plain `status`
     * (an observation) leaves both `null`.
     */
    refs: Record<string, string> | null;
    head_target: VaultHeadTarget | null;
    pins: {
        highest_authenticated: string | null;
        highest_materialized: string | null;
    };
    vault_policy: "required" | "grandfathered" | null;
    /** Override journals on this machine that have not yet been completed. */
    pending_overrides: number;
    /**
     * Best-effort count of this vault's covering `key_envelope` recipients (the
     * same envelope-recipients read `Repos.access` uses), taken inside
     * `status()` when a vault is allocated. `null` when unknown — no vault, or
     * the read failed (never a new failure mode for `status`; falls back to the
     * single-principal V0-A statements below). This is what decides between
     * `terminal_loss_statement` and `durability_statement`: the V0-A terminal-loss
     * claim is specifically a single-principal claim, and is factually false to
     * print for a vault this client can locally prove has >= 2 recipients.
     */
    covering_recipients: number | null;
    /**
     * Stated verbatim per the client-surface spec — this sentence is normative
     * copy, not a summary, and is printed by `status` and `doctor` alike.
     * `null` exactly when `covering_recipients >= 2` — see `durability_statement`
     * for what is printed in that case instead.
     */
    terminal_loss_statement: typeof VAULT_TERMINAL_LOSS_STATEMENT | null;
    /** `null` exactly when `terminal_loss_statement` is — same condition, same reasoning. */
    terminal_loss_detail: typeof VAULT_TERMINAL_LOSS_DOCTOR_TEXT | null;
    /**
     * The protocol's durability sentence — printed in place of
     * `terminal_loss_statement` exactly when `covering_recipients >= 2`, since
     * the terminal-loss claim is false for a vault this client has locally
     * proven has a second covering recipient. `null` otherwise (including
     * "unknown" — the single-principal statements are the honest default).
     */
    durability_statement: typeof VAULT_DURABILITY_STATEMENT | null;
    warnings: {
        kind: string;
        message: string;
    }[];
    next_actions: {
        action: string;
        command?: string;
    }[];
}
/**
 * What {@link Repos.scaffoldRemote} did, and why (D1). `name` is `origin`
 * when it was free (or a caller-supplied name), `run402` when `origin` was
 * already taken by something else, or the caller's explicit `remote_name`.
 * `reason` is a human-readable sentence naming exactly what happened —
 * printed to stderr by every CLI caller, never synthesized twice.
 */
export interface VaultScaffoldRemoteResult {
    /** `scaffolded`: the remote is in place (added now or already present). `skipped`: `repo_dir` lies inside
     *  another repository, which is never touched — `toplevel` names it. */
    status: "scaffolded" | "skipped";
    /** Always `run402` unless an explicit `remote_name` was given; `origin` is never claimed. */
    name: string;
    url: string;
    created_repository: boolean;
    already_present: boolean;
    existing_url: string | null;
    reason: string;
    /** The enclosing repository's toplevel when `status` is `skipped`. */
    toplevel?: string;
    /**
     * `true` when `repo_dir` lies inside ANOTHER repository and was scaffolded
     * as its own nested repository (`nested: true`). The enclosing repository
     * is named by `enclosing_toplevel` and is never touched beyond one
     * `/<relative path>/` line in its local `.git/info/exclude`
     * (`excluded_in_enclosing` says whether that line is in place).
     */
    nested?: boolean;
    enclosing_toplevel?: string;
    excluded_in_enclosing?: boolean;
    /**
     * A `skipped` result names the way out: `create_nested_repo`, pointing at
     * `run402 repos create --nested --project <project_id>` — a nested repository
     * keeps an encrypted remote for the app without touching the enclosing
     * repository. Absent on a `scaffolded` result.
     */
    next_actions?: NextAction[];
}
export interface VaultInitResult {
    repo_id: string;
    project_id: string;
    /** Emitted once at creation — integrity data, not a secret. Print it, copy it, keep many copies. */
    recovery_receipt: VaultCreationResult["recovery_receipt"];
    genesis_sha256: string;
    /** The git remote that was added, when a working tree was scaffolded. */
    remote: VaultScaffoldRemoteResult | null;
    deduplicated: boolean;
    terminal_loss_statement: typeof VAULT_TERMINAL_LOSS_STATEMENT;
    /**
     * vault-byo-primary-bucket task 3.1/3.5 — the AUTHORITATIVE profile
     * (read back from the vault record, never assumed from what `init`'s
     * `byo` option requested). `"managed"` when `byo` was omitted, OR when it
     * was requested but this project's vault already existed as a managed
     * one under a different creation attempt.
     */
    storage_profile: "managed" | "byo";
    byo_destination: string | null;
}
export interface VaultCompactResult {
    generation: string;
    head_sha256: string;
    form: "wal" | "checkpoint";
    /** Set when a maintenance lease was taken and released around the checkpoint. */
    maintenance_lease_id: string | null;
    /** `false` when no `retention_cutoff` ticket could be obtained — roots are RETAINED (expiry is permissive). */
    cutoff_bound: boolean;
    covered_refs: number;
    covered_roots: number;
    /**
     * What the transient-storage preflight saw
     * (vault-compaction-headroom-preflight). `null` when the preflight could
     * not be answered — see {@link VaultCompactHeadroom} for why an
     * unanswerable check never blocks maintenance.
     */
    headroom: VaultCompactHeadroom | null;
}
/**
 * Compaction's transient pooled-storage arithmetic.
 *
 * Compaction publishes a checkpoint pack roughly the size of the vault's live
 * content while every superseded object stays stored until prune completes —
 * a transient footprint of roughly TWICE `source_bytes`, counted against the
 * ORG's pooled tier storage. Saying nothing about this leaves an org near
 * its cap paying the full encrypt+upload cost and then taking a mid-flight
 * quota refusal that names a quota rather than the mechanism.
 *
 * This is advisory-grade by construction: it can only refuse EARLIER and more
 * legibly than the platform's own storage-quota enforcement, never admit
 * something that enforcement would refuse.
 */
export interface VaultCompactHeadroom {
    /** Pooled storage the org is already using, across every project it owns. */
    pool_used_bytes: number;
    /** The org's plain, unraised pooled tier storage limit — always the tier's own figure, never the grant-raised one, so a disclosed "used of X pooled" never implies the tier itself grew. */
    pool_limit_bytes: number;
    /** The vault's billed `source_bytes` — the checkpoint-size proxy (design D1). */
    vault_source_bytes: number;
    /** `pool_used_bytes + vault_source_bytes`. */
    projected_transient_bytes: number;
    /** `false` when the projection exceeds the EFFECTIVE limit (`effective_pool_limit_bytes` when a grant is active, else `pool_limit_bytes`). */
    ok: boolean;
    /** `true` when the caller passed the override and a `false` `ok` was proceeded past anyway. */
    overridden: boolean;
    /**
     * vault-checkpoint-cadence design D3: `pool_limit_bytes` PLUS an active
     * compaction grant's `granted_bytes`, when one is active for this cycle —
     * the limit `ok`/`projected_transient_bytes` are actually computed
     * against. Equal to `pool_limit_bytes` (and omittable) when no grant is
     * active.
     */
    effective_pool_limit_bytes?: number;
    /** The grant this compaction opened for itself, when one was opened and is still tracked at disclosure time — `null`/absent otherwise (no grant, an older gateway, or one already closed). */
    compaction_grant?: {
        granted_bytes: number;
        expires_at: string;
    } | null;
}
/**
 * `run402 repos capture --dry-run`'s report shape
 * — {@link Repos.planCapture}'s return type. Every sizing field is `null`,
 * and `refs`/`objects` are empty, exactly when `allocation_needed` is `true`
 * — see that method's doc comment for why sizing is genuinely UNKNOWABLE
 * (not merely unreported) before the vault's encryption key exists.
 */
export interface VaultSnapshotPushPlan {
    /** `true` when this project has no vault yet — a real push/snapshot would allocate one first (push-to-create). This dry run never does. */
    allocation_needed: boolean;
    base_generation: string | null;
    would_admit_generation: string | null;
    /** `would_admit_generation` as a plain decimal string. */
    would_admit_generation_decimal: string | null;
    form: "wal" | "checkpoint" | null;
    refs: VaultRefMap;
    head_target: VaultHeadTarget | null;
    /** Every object that would be uploaded, with REAL sealed (encrypted) sizes. Empty when `allocation_needed`. */
    objects: Array<{
        object_kind: string;
        size_bytes: string;
    }>;
    object_count: number | null;
    /** Sum of `objects[].size_bytes` — the REAL ciphertext byte count. */
    encrypted_bytes: string | null;
    /** Sum of the plaintext pack bytes before sealing. */
    raw_bytes: string | null;
    /** The local capture this dry run computed — real, regardless of `allocation_needed`: capturing the work tree touches no network. */
    snapshot: VaultSnapshot;
    vault_commit: string;
    vault_commit_line: string;
}
/** One retention ROOT (a dropped ref tip) and whether its 90-day window has closed. */
export interface VaultPruneCandidate {
    ref: string;
    oid: string;
    dropped_at_generation: string;
    eligible: boolean;
    reason: string;
}
/** One STORED OBJECT the plan proposes deleting — what a `prune_intent`'s `delete_set` actually names. */
export interface VaultPruneObjectCandidate {
    object_id: string;
    object_kind: string;
    size_bytes: string;
}
export interface VaultPruneResult {
    /** Retention ROOTS and their windows — the retention view, unchanged. */
    candidates: VaultPruneCandidate[];
    eligible_count: number;
    retained_count: number;
    /**
     * The stored objects the plan proposes deleting, in the intent's canonical
     * order. A PROPOSAL: the gateway re-checks every candidate against the bound
     * `retention_cutoff` ticket and its own admission times, and refuses any that
     * is not retention-eligible. A client cannot prove either fact.
     */
    object_candidates: VaultPruneObjectCandidate[];
    /** Pruneable objects left out by the 10 000-per-intent cap; chunk into a later intent. */
    deferred_object_count: number;
    /** Why nothing may be pruned yet, or `null` when a submission is structurally possible. */
    blocked_reason: string | null;
    /**
     * The SIGNED `prune_intent_core` this plan proposes, and its stored-bytes
     * hash — what BOTH verifier receipts must sign. `null` when blocked.
     *
     * Round-trip this object verbatim into `submit`: it carries a random nonce
     * and object id, so a rebuilt core is a DIFFERENT core and the receipt
     * `r402s-verify` produced would no longer bind to it.
     */
    intent_core: import("../node/vault-prune.js").VaultPruneIntentCore | null;
    intent_core_sha256: string | null;
    /** What this SDK observed while restoring the latest checkpoint — the receipt's evidence. */
    attestation: import("../node/vault-publication.js").VaultStoredCheckpointAttestation | null;
    /** `true` only when an intent was accepted by the gateway. */
    submitted: boolean;
    /** The gateway's view of the submitted intent; `null` when nothing was submitted. */
    intent: import("../node/vault-prune.js").VaultPruneIntentRecord | null;
    /**
     * What the control-plane-signed completion CONFIRMS. `deleted` is the only
     * result that means the bytes are gone: `present_after_attempt` is a failed
     * deletion, not a successful one.
     */
    confirmation: import("../node/vault-prune.js").VaultPruneConfirmation | null;
    note: string;
}
/** Options shared by every Node-only verb. */
export interface VaultHandleOptions {
    /** The vault to act on. Resolved from `project_id` when omitted. */
    repo_id?: string;
    /** Resolve `repo_id` from the project (the cold-restart entry point). */
    project_id?: string;
    /**
     * vault-agent-envelopes D5 — the session-start envelope fulfilment a
     * KEY-HOLDING client runs on its first ordinary vault operation in a
     * process (read verbs included), so a pending member is covered the next
     * time ANY key-holder does anything. `"auto"` (default): run once per
     * process per vault, best-effort, reported on the handle. `"deferred"`
     * (`--no-reconcile`): skip, report `deferred_by_local_policy` with the
     * pending count — never pretends coverage. `"forbidden"`: forensic and
     * offline operations (`fsck`, `--no-write`, `recover`) — investigating a
     * suspicious pending recipient must not complete the disclosure.
     */
    reconcile?: "auto" | "deferred" | "forbidden";
    /** The local git working tree. Defaults to `process.cwd()`. */
    repo_dir?: string;
    /** Keystore root override (defaults to `~/.config/run402/vault`; `~/.config/run402/profiles/<wallet>/vault` under a named wallet). */
    keystore_root?: string;
    /** Pinned service public key for control-plane signature checks (cutoff tickets). */
    service_public_key?: Uint8Array | string;
    /** Heads verified per call; the verified prefix persists, so a budget-exceeded client resumes. */
    verification_budget?: number;
}
/** An opened vault plus the pieces the caller may want to keep using. */
export interface VaultHandle {
    repo_id: string;
    keystore: VaultKeystore;
    transport: VaultTransport;
    /** The full protocol object — every verb below is built on it. */
    vault: import("../node/vault-publication.js").Vault;
    /**
     * vault-agent-envelopes D4: non-null when this open restored the repo
     * file from the keystore's OWN envelope (a cold keystore joining a vault it
     * is a recipient of). Carries the honest trust tier — `platform_attested`
     * is not end-to-end authentication.
     */
    restored: import("../node/vault-publication.js").VaultColdOpenResult | null;
    /**
     * vault-agent-envelopes D5: the session-start fulfilment outcome for a
     * key-holding client (`null` when this open did not run one — a restored
     * keystore has nothing to wrap yet, `reconcile: "forbidden"`, or a later
     * open in the same process). Reported beside the verb's own result, never
     * folded into it.
     */
    reconcile_recipients: VaultSessionReconcileResult | null;
    /**
     * vault-multi-writer (task 5.7) — the session-start writer-admission
     * reconcile's outcome. `null` exactly when `reconcile: "forbidden"` — this
     * reconcile carries no disclosure risk (it wraps nothing), so unlike
     * {@link reconcile_recipients} it is otherwise ALWAYS attempted, no
     * custody-verification gate and no once-per-process memoization: {@link
     * import("../node/vault-publication.js").Vault.
     * reconcileWriterAdmissions} is already a fast no-op (one local pin check,
     * no network call) whenever this session's own key is not an active
     * writer.
     */
    writer_reconcile: VaultReconcileWriterAdmissionsPushResult | null;
    /** vault-agent-envelopes D3: what the enroll-if-absent step did for this keystore's key on this open. */
    enrollment: VaultEnrollmentOutcome;
}
/** The session-start reconcile's outcome (vault-agent-envelopes D5). */
export interface VaultSessionReconcileResult {
    attempted: boolean;
    outcome: "reconciled" | "skipped_error" | "deferred_by_local_policy" | "forbidden" | "custody_unverified";
    result?: VaultReconcileEnvelopeRecipientsResult;
    /** `deferred_by_local_policy` only: desired recipients this vault does not yet cover (best-effort; `null` when the read failed). */
    pending_count?: number | null;
    error?: string;
}
/** The enroll-if-absent step's outcome (vault-agent-envelopes D3). Never a rotation. */
export interface VaultEnrollmentOutcome {
    /** `already_active`: the directory holds this keystore's key (BOTH halves current — encryption active AND signing_fingerprint already matches, vault-multi-writer rev 47). `enrolled`: published + possession-proven in this call. `activated_pending`: an earlier unfinished publish was completed. `signing_republished` (rev 47): the encryption half was ALREADY active and needed no work; only the signing half was (re)published this call — never a rotation, the signing half is always freely republishable. `skipped_no_identity`: no local keystore identity (nothing to enroll — vault creation mints one). `skipped_no_principal`: whoami resolved no enrolling principal (e.g. a service key). `skipped_not_enrollable`: the principal's type is not custody-eligible (ci/system) — no identity is minted. `skipped_error`: whoami/publish/activate failed (older gateway, transport) — the verb still ran, but custody continuity is UNVERIFIED, so no automatic reconcile follows; `error` says why. */
    outcome: "already_active" | "enrolled" | "activated_pending" | "signing_republished" | "skipped_no_identity" | "skipped_no_principal" | "skipped_not_enrollable" | "skipped_error";
    ek_fingerprint: string | null;
    /**
     * vault-multi-writer rev 47 (task 5.3) — the keystore's vault-WRITER
     * signing half, published in the SAME call as the encryption half
     * whenever this keystore holds a signing seed. `null` when the identity
     * has no local signing seed (a read-only recovery identity — see
     * `VaultIdentityFile.signing_seed_hex`'s own doc comment) or when the
     * publish itself was never attempted (`skipped_no_identity`/
     * `skipped_no_principal`/`skipped_not_enrollable`). UNLIKE the encryption
     * half, the signing half is NEVER rotation-gated — a differing published
     * signing key is simply refreshed in place, never a `KEY_ROTATION_REQUIRED`
     * refusal, so this field's presence says nothing about whether a
     * publish actually happened this call vs. was already current.
     */
    signing_fingerprint: string | null;
    error?: string;
}
/** {@link Repos.capture}'s best-effort envelope-recipient reconcile outcome, reported beside (never folded into) the vault result — same non-blocking contract as {@link VaultMirrorPushResult}. */
export interface VaultReconcileEnvelopeRecipientsPushResult {
    attempted: boolean;
    outcome: "reconciled" | "skipped_error";
    result?: VaultReconcileEnvelopeRecipientsResult;
    error?: string;
}
/**
 * vault-multi-writer (task 5.7) — the writer-admission twin of {@link
 * VaultReconcileEnvelopeRecipientsPushResult}: best-effort, reported
 * beside (never folded into) the vault result. ONE shape used at every
 * wiring site (push/snapshot/deploy/session-start/read) — unlike the
 * envelope reconcile's split between this push-result shape and the
 * richer {@link VaultSessionReconcileResult}, `"forbidden"` is included
 * here too since this reconcile's session-start policy (task 5.7's own,
 * deliberately simpler than the envelope reconcile's custody-gated one —
 * see {@link VaultHandle.writer_reconcile}) honors only that one value;
 * it is simply unreachable at the push/snapshot/deploy sites, which never
 * check `options.reconcile` for this hook.
 */
export interface VaultReconcileWriterAdmissionsPushResult {
    attempted: boolean;
    outcome: "reconciled" | "skipped_error" | "forbidden";
    result?: VaultReconcileWriterAdmissionsResult;
    error?: string;
}
/** {@link Repos.handoff}'s result. `handoff_key` (the assembled `kgh1_…`) is returned exactly ONCE. */
export interface VaultHandoffMintResult {
    handoff_key: string;
    handoff_id: string;
    kind: "handoff";
    minted_role: string;
    expires_at: string;
    vault: {
        vault_id: string;
        address?: string | null;
        organization_id: string;
        project_id: string;
    };
    checkpoint: {
        generation: string;
        snapshot_oid_hmac: string;
    };
    capture: {
        modified_captured: number;
        untracked_captured: number;
        sensitive_excluded: string[];
        ignored_not_transferred_count: number;
    };
    /** The full local capture result, for a caller that wants more than the summarized `capture` block. */
    snapshot: import("../node/vault-snapshot.js").VaultHandoffSnapshot;
    warnings: {
        code: string;
        message: string;
    }[];
    next_actions: NextAction[];
}
export interface VaultHandoffListEntry {
    handoff_id: string;
    kind: string;
    state: "issued" | "redeemed" | "expired" | "revoked";
    minted_role: string;
    minted_by: string;
    expires_at: string;
    redeemed_by?: string | null;
}
export interface VaultHandoffListResult {
    handoffs: VaultHandoffListEntry[];
}
/** {@link Repos.resume}'s result. */
export interface VaultHandoffResumeResult {
    handoff_id: string;
    kind: "handoff";
    deduplicated: boolean;
    /** The Handoff Note, parsed — `null` when the commit message could not be read/parsed (still restored either way). */
    note: import("../node/vault-handoff.js").KygitHandoffNote | null;
    /** The note's raw commit-message text, for a caller that wants Markdown rendering over the parsed shape. */
    note_raw: string | null;
    restored: {
        dir: string;
        branch: string;
        base_head_oid: string;
        stash_oid: string;
    };
    membership: {
        organization_id: string;
        role: string;
        status: string;
    };
    members: unknown[];
    expires_at: string;
    /** vault-multi-writer rev 47 (task 5.6, design D5) — this checkout's own writer activation. `outcome: "active"` covers BOTH a fresh submission this call made and the idempotent-skip case (a prior attempt's activation already landed) — the writer IS active either way. */
    writer_activation: {
        outcome: "active";
        writer_key_id: string;
        generation: string;
    };
    reconcile_recipients: VaultReconcileEnvelopeRecipientsPushResult;
    next_actions: NextAction[];
}
/**
 * The gateway names the vault by its three ids on the wire — `repo_id`,
 * `org_id`, `project_id` (docs/style.md's API-boundary vocabulary) — on
 * BOTH the handoff mint (`POST /vaults/v1/:vault_id/handoffs`) and
 * claim (`POST /vaults/v1/handoffs/:handoff_id/redeem`) responses. The SDK
 * groups them under `vault` with the `organization_id` spelling every other
 * SDK result uses. Neither response carries a slug-form address, so
 * `address` is `null` unless the caller already knows one (a slug-form
 * remote at mint time). Pure; exported for tests.
 */
export declare function handoffVaultFromWire(wire: {
    repo_id: string;
    org_id: string;
    project_id: string;
}, address?: string | null): VaultHandoffMintResult["vault"];
/** The redeem response's `membership` block (`org_id` on the wire) in the SDK's `organization_id` spelling. Pure; exported for tests. */
export declare function handoffMembershipFromWire(wire: {
    org_id: string;
    role: string;
    status: string;
}): VaultHandoffResumeResult["membership"];
/**
 * An invite mints at `developer` unless `--role` narrows it or the minter's
 * own role is narrower — the ONE descriptor difference from a handoff, which
 * mints at the minter's own role (kygit-invite design D1). Declared here
 * because the client must predict the gateway's attenuated answer EXACTLY:
 * the `writer_admission_grant` is signed with `minted_role` inside it before
 * the mint call, and a disagreement is a `VALIDATION_FAILED` after the
 * checkpoint has already been captured and pushed.
 */
export declare const INVITE_DEFAULT_ROLE = "developer";
/** A room's `(org_id, room_key)` pair, as it rides the invite mint/redeem responses. */
export interface VaultInviteRoom {
    organization_id: string;
    room_key: string;
}
/** Best-effort report of whether {@link Repos.invite}'s room message was posted — a failure here (e.g. the daily quota) never voids the mint (design D4). */
export interface VaultInviteRoomMessageResult {
    posted: boolean;
    message_id?: string;
    /** The posted message's room cursor — a CLI advances the inviter's stored cursor past it, so the inviter's own `messages wait` is woken by the joiner's arrival, never by its own message. */
    cursor?: string;
    reason?: string;
}
/** Best-effort report of whether the inviter's own presence was registered before minting (design D4) — the mint still proceeds without one. */
export interface VaultInvitePresenceResult {
    registered: boolean;
    presence_id?: string;
    name?: string;
    error?: string;
}
/** {@link Repos.invite}'s result. `invite_key` (the assembled `kgi1_…`) is returned exactly ONCE. */
export interface VaultInviteMintResult {
    invite_key: string;
    invite_id: string;
    kind: "invite";
    minted_role: string;
    expires_at: string;
    vault: {
        vault_id: string;
        address?: string | null;
        organization_id: string;
        project_id: string;
    };
    room: VaultInviteRoom;
    checkpoint: {
        generation: string;
        snapshot_oid_hmac: string;
    };
    capture: {
        modified_captured: number;
        untracked_captured: number;
        sensitive_excluded: string[];
        ignored_not_transferred_count: number;
    };
    /** The full local capture result, for a caller that wants more than the summarized `capture` block. */
    snapshot: import("../node/vault-snapshot.js").VaultHandoffSnapshot;
    inviter_presence: VaultInvitePresenceResult;
    room_message: VaultInviteRoomMessageResult;
    warnings: {
        code: string;
        message: string;
    }[];
    next_actions: NextAction[];
}
export interface VaultInviteListEntry {
    invite_id: string;
    kind: string;
    state: "issued" | "redeemed" | "expired" | "revoked";
    minted_role: string;
    minted_by: string;
    room_key: string;
    expires_at: string;
    redeemed_by?: string | null;
}
export interface VaultInviteListResult {
    invites: VaultInviteListEntry[];
}
/** The inviter's presence, resolved live at redeem time (design vault-invite's own claim requirement) — `null` when the inviter never registered one. */
export interface VaultInviteInviter {
    presence_id: string;
    name: string;
    program: string | null;
    model: string | null;
    state: string;
    last_active: string;
}
/** {@link Repos.join}'s result. */
export interface VaultInviteJoinResult {
    invite_id: string;
    kind: "invite";
    deduplicated: boolean;
    /** The Invite Note, parsed — `null` when the commit message could not be read/parsed (still restored either way). */
    note: import("../node/vault-handoff.js").KygitInviteNote | null;
    /** The note's raw commit-message text, for a caller that wants Markdown rendering over the parsed shape. */
    note_raw: string | null;
    restored: {
        dir: string;
        branch: string;
        base_head_oid: string;
        stash_oid: string;
    };
    membership: {
        organization_id: string;
        role: string;
        status: string;
    };
    members: unknown[];
    room: VaultInviteRoom;
    inviter: VaultInviteInviter | null;
    /** This session's OWN presence in the room (what the arrival fact was posted as), or `null` when registration failed. A CLI persists it into the joined checkout so the first `messages wait` there speaks as the same session. */
    presence: {
        presence_id: string;
        name: string;
    } | null;
    /** Why `presence` is null (the registration refusal, verbatim), else null. A joined checkout without a presence still works — its first `messages wait` registers one — but the reason is never silent. */
    presence_failure: string | null;
    live_presences: RoomPresence[];
    cursor: string | null;
    recent_messages: unknown[];
    expires_at: string;
    /**
     * vault-multi-writer rev 47 (kygit-invite design D5/D9) — this
     * checkout's own writer activation, driven through the SAME shared
     * `add_writer_key` door {@link Repos.resume} uses, BEFORE `join()`
     * returns, so the joiner's first `git push` is an ordinary push.
     * `outcome: "active"` covers both a fresh submission and the
     * idempotent-skip case. `outcome: "pending"` is D9's not-stranded path: a
     * concurrent rotation or a lost network left this key a PENDING writer of
     * the vault; any live writer's next push or `repos access sync` admits
     * it, and `next_actions` carries `request_writer_sync` saying so.
     */
    writer_activation: {
        outcome: "active";
        writer_key_id: string;
        generation: string;
    } | {
        outcome: "pending";
        writer_key_id: string;
        reason: string;
    };
    reconcile_recipients: VaultReconcileEnvelopeRecipientsPushResult;
    next_actions: NextAction[];
}
/** What {@link Repos.openOrCreate} did. `created` is `null` exactly when `found` is `true`. */
/** `run402 repos mirror` (no-arg, a READ) and `repos view`'s mirror summary both compose this — what this machine and the mirror each believe (both honesty statements ride every response). */
export interface VaultMirrorStatus {
    repo_id: string;
    configured: boolean;
    /** `s3://bucket/prefix` or a directory path — never a credential. */
    destination: string | null;
    credential_kind: "profile" | "ambient" | null;
    /** The newest generation the MIRROR holds and chain-verifies (keyless). `null` when unconfigured, unreachable, or empty. */
    mirrored_generation: string | null;
    /** The LIVE vault's newest generation (one vault-record read). `null` when unconfigured or the vault has never captured. */
    newest_generation: string | null;
    /** `null` when either side is unknown (never fabricated from a partial read). */
    is_current: boolean | null;
    /** Present exactly when `is_current === false`. */
    closing_command: string | null;
    /** vault-mirror-default: when a mirror write/sync last completed with zero failures (local config fact — never transmitted). `null` when unconfigured or never succeeded. */
    last_success_at: string | null;
    /** vault-mirror-default: the standing `vault_unmirrored` finding — informational, never blocking; `null` once a mirror write or sync has succeeded (see {@link vaultUnmirroredFinding}). */
    finding: VaultUnmirroredFinding | null;
    validity_not_freshness: typeof VAULT_MIRROR_VALIDITY_NOT_FRESHNESS_STATEMENT;
    keystore_still_required: typeof VAULT_MIRROR_KEYSTORE_STILL_REQUIRED_STATEMENT;
}
/**
 * vault-mirror-default — the named standing finding for a vault with no
 * customer-held mirror copy yet. vault-byo-primary-bucket task 3.5
 * widens `message` to the BYO remedy wording ({@link
 * VAULT_BYO_UNMIRRORED_REMEDY_STATEMENT}) for a BYO vault — it applies
 * there too (D7): a single-bucket BYO vault has exactly as few copies as an
 * unmirrored managed one, and the remedy names a SECOND customer-held
 * location the same way.
 */
export interface VaultUnmirroredFinding {
    kind: "vault_unmirrored";
    message: typeof VAULT_UNMIRRORED_FINDING_STATEMENT | typeof VAULT_BYO_UNMIRRORED_REMEDY_STATEMENT;
    /** The one command that moves toward clearing it: configure when unconfigured, backfill when configured-but-never-succeeded. */
    setup_command: string;
}
/**
 * vault-byo-primary-bucket task 3.3 — the number of `{key, object_kind}`
 * entries `VAULT_BYO_OBJECT_MISSING`'s `details.missing` lists before
 * truncating (`details.missing_count` always carries the true total, and
 * `details.missing_truncated` says whether the list above was cut). A
 * chain-referenced object list can be arbitrarily large; an error envelope
 * is not the place to reproduce it whole. Matches the platform's existing
 * `sample_keys`-class cap (asset-sync's plan response, `PLATFORM_INCIDENT_
 * FANOUT_CAP`) rather than inventing a new number.
 */
export declare const VAULT_BYO_OBJECT_MISSING_LIST_CAP = 50;
/**
 * vault-byo-primary-bucket task 3.3 (design D6) — `repos fsck`'s wiring of
 * the shipped {@link import("../node/vault-mirror.js").verifyByoObjectsPresent}
 * read-half primitive. Present on {@link VaultFsckResult.byo_presence}
 * ONLY for a `storage_profile: "byo"` vault — `undefined` (the key absent
 * from JSON entirely) for a managed vault, so a managed vault's `fsck`
 * output is byte-identical to before this task.
 *
 * `verified: true` NEVER coexists with a missing object: a nonzero absence
 * throws `VAULT_BYO_OBJECT_MISSING` instead of returning here (see
 * {@link Repos.fsck}'s own doc comment) — this shape only ever reports
 * the two honest non-failure outcomes, "checked, all present" and "could
 * not check".
 */
export interface VaultFsckByoPresence {
    /**
     * `true` iff this call actually HEAD-checked the destination (local BYO
     * write credentials were configured on this machine). `false` means "not
     * checked" — see `not_checked_reason` — which is deliberately NOT a
     * failure: a BYO vault a returning agent has no local credentials for
     * must never break its ordinary `fsck`.
     */
    verified: boolean;
    /** The BYO destination's address, from the vault record. Populated even when `verified` is `false` — a BYO vault always names its destination; it is the CREDENTIAL to reach it that may be missing on this machine. */
    destination: string | null;
    /** Objects HEAD-checked against the destination. `0` when `verified` is `false`. */
    checked_count: number;
    /** Present only when `verified` is `false` — why this call could not verify presence. Never blank: silence must never be mistaken for a clean verdict. */
    not_checked_reason: string | null;
}
/**
 * `repos fsck`'s result. Explicit pin fields make a local mutation visible rather than
 * implicit — the external review's clause-5 requirement for any verb that
 * may advance local trust state.
 */
export interface VaultFsckResult {
    repo_id: string;
    /** `false` under `--no-write` (`write: false`) — nothing local was persisted, regardless of what was computed. */
    write: boolean;
    verified_from_generation: string | null;
    /**
     * Alias for `chain_verified_to_generation` below (kept for back-compat —
     * every existing caller reads this field). Chain/signature verification
     * ALWAYS reaches this generation, independent of decrypt capability
     * (D193, rev 42: an admitted `rotate_epoch` transition is keylessly
     * structural, never a stopping point for chain verification).
     */
    verified_to_generation: string;
    /** Same value as `verified_to_generation` — the honest name for what this field actually measures (Request 1's split). */
    chain_verified_to_generation: string;
    /**
     * The newest generation this call could actually DECRYPT — restoration's
     * real ceiling. Equals `chain_verified_to_generation` on a healthy vault;
     * falls short of it when an admitted `rotate_epoch` transition's own
     * envelope could not be opened by this keystore (`epoch_decrypt_failure`
     * names exactly which epoch/rotation and why — never a bare, undifferentiated
     * `VAULT_AEAD_AUTH_FAILURE`). `refs`/`head_target`/`pin_after.highest_materialized`
     * below all reflect THIS generation, not the chain-verified one, when they differ.
     */
    decryptable_to_generation: string;
    /** Non-null iff `decryptable_to_generation` fell short of `chain_verified_to_generation` — the named epoch boundary (Request 1). */
    epoch_decrypt_failure: import("../node/vault-publication.js").VaultEpochDecryptFailure | null;
    /** `true` only when `write` was true AND a pin actually moved. */
    local_state_changed: boolean;
    pin_before: {
        highest_authenticated: string | null;
        highest_materialized: string | null;
    };
    pin_after: {
        highest_authenticated: string | null;
        highest_materialized: string | null;
    };
    /** The real, computed ref map, AS OF `decryptable_to_generation` — present even under `--no-write` (computing is not the same as persisting). */
    refs: VaultRefMap;
    head_target: VaultHeadTarget | null;
    /** Present only when `--mirror` was requested. Proves validity, never freshness — see its own honesty statements. */
    mirror: VaultVerifyReport | null;
    /**
     * clone-installs-retained-refs (D2, task 1.3): the healing path for a
     * pre-change clone (or a checkout whose original write degraded per D3) —
     * `null` under `--no-write` (a genuine audit mode persists nothing, refs
     * included) or when no local checkout was addressed (`repo_dir` absent, or
     * `repo_dir` is not itself a git repository — an ordinary, silent no-op,
     * never a warning).
     */
    retained_refs: import("../node/vault-publication.js").VaultRetainedRefsReconcileResult | null;
    /**
     * D210 (rev 44) — best-effort submission of THIS call's OWN
     * `chain_verified_to_generation`/`decryptable_to_generation` as
     * recipient-attested proof-of-open evidence (`POST
     * …/recipients/:principal_id/proof-of-open`), the SDK/CLI follow-up
     * D210's own decision log names ("an `fsck --attest-open`-class
     * submitter"). Automatic in WRITE mode when this keystore holds a local
     * encryption identity; `{attempted: false, ...}` under `--no-write` (a
     * genuine audit mode creates no server-side state) or when there is no
     * local identity to submit evidence for. This NEVER changes `fsck`'s own
     * verdict above — a submission failure (principal resolution, network,
     * `OPEN_PROOF_MISMATCH`) is recorded in `error` and nothing else; a
     * `recipient_open_receipt` is EVIDENCE, never authorization (§4.14).
     */
    open_proof: VaultOpenProofOutcome;
    /**
     * vault-byo-primary-bucket task 3.3 — see {@link VaultFsckByoPresence}.
     * Absent entirely (not `null`) for a `storage_profile: "managed"` vault, so
     * `JSON.stringify` drops the key and a managed vault's `fsck` output stays
     * byte-identical to before this task existed. A `verified: true` result
     * with objects missing is never returned here — see the interface's own
     * doc comment for why that case throws `VAULT_BYO_OBJECT_MISSING`
     * instead.
     */
    byo_presence?: VaultFsckByoPresence;
}
/** {@link VaultFsckResult.open_proof} — the outcome of `fsck`'s best-effort D210 proof-of-open submission. */
export interface VaultOpenProofOutcome {
    /** `false` iff this call decided LOCALLY there was nothing to submit (write:false, or no local encryption identity) — no network call was made. */
    attempted: boolean;
    /** `true` iff the gateway accepted the submission (200 or 201) — `receipt`/`deduplicated` are populated. */
    submitted: boolean;
    /** `true` — the gateway returned the tuple's EXISTING receipt (200, an idempotent replay). `false` — a fresh receipt was minted (201). `null` when `submitted` is `false`. */
    deduplicated: boolean | null;
    /** The `recipient_open_receipt` the gateway returned, present iff `submitted`. */
    receipt: VaultOpenReceipt | null;
    /** Present iff `attempted` and NOT `submitted` — why the gateway (or principal resolution before it) refused. */
    error: {
        code: string;
        message: string;
    } | null;
}
/**
 * D210 (rev 44) — the decision function behind `fsck`'s best-effort
 * proof-of-open submission, factored out of {@link Repos}'s private
 * `#submitFsckOpenProof` so it is directly unit-testable with injected
 * (fake) `resolvePrincipalId`/`submit` dependencies, independent of a real
 * HTTP-backed vault. `fsck()` itself supplies the REAL dependencies (`GET
 * /agent/v1/whoami`, {@link Repos.submitProofOfOpen}) — this function
 * contains no HTTP/transport code of its own.
 *
 * Gating (all LOCAL, no network call made when either holds):
 *   - `write === false` — a genuine audit mode; submitting a receipt is a
 *     real server-side mutation (idempotent or not), so it never fires.
 *   - `ekFingerprint === null` — no local encryption identity to submit
 *     evidence FOR.
 *
 * Otherwise: resolve `principal_id` (`resolvePrincipalId`), then submit
 * `evidence` VERBATIM — `chain_verified_to_generation`/
 * `decryptable_to_generation` pass through completely unchanged from the
 * caller, never recomputed or rounded here.
 *
 * FAILURE CONTAINMENT (the load-bearing property): this function NEVER
 * throws. Every failure — `resolvePrincipalId` resolving `null`,
 * `resolvePrincipalId`/`readerEntrypoint`/`submit` throwing for any reason
 * (network, `OPEN_PROOF_MISMATCH`, anything) — is caught and reported in
 * the returned outcome's `error`; the caller's own already-computed result
 * (`fsck`'s verdict) is never touched by this function's own failure.
 */
export declare function computeOpenProofOutcome(input: {
    write: boolean;
    ekFingerprint: string | null;
    evidence: {
        chain_verified_to_generation: string;
        decryptable_to_generation: string;
    };
    resolvePrincipalId: () => Promise<string | null>;
    readerEntrypoint: () => Promise<string>;
    submit: (principalId: string, ekFingerprint: string, evidence: {
        chain_verified_to_generation: string;
        decryptable_to_generation: string;
        reader_entrypoint: string;
    }) => Promise<{
        receipt: VaultOpenReceipt;
        deduplicated: boolean;
    }>;
}): Promise<VaultOpenProofOutcome>;
/**
 * vault-byo-primary-bucket task 3.3 (design D6) — the decision function
 * behind `fsck`'s BYO presence check, factored out of {@link Repos}'s
 * private `#checkByoPresence` the same way {@link computeOpenProofOutcome}
 * is factored out of `#submitFsckOpenProof`, so it is directly unit-testable
 * with an injected (fake) `hasLocalConfig`/`verifyPresence`, independent of
 * a real keystore or HTTP client. `#checkByoPresence` supplies the REAL
 * dependencies (`readByoConfig` against the real keystore,
 * `verifyByoObjectsPresent` against the real client) — this function
 * contains no filesystem/HTTP code of its own.
 *
 * Runs AUTOMATICALLY for a `storage_profile: "byo"` vault — never behind a
 * new flag, so a returning agent's ordinary `fsck` catches a
 * silently-emptied bucket without having to know to ask for it. Returns
 * `undefined` for a managed vault (`vault?.storage_profile !== "byo"` is
 * the FIRST check, before `hasLocalConfig`/`verifyPresence` are ever
 * called) — a managed vault pays zero extra network/filesystem work and
 * this task changes nothing about it (design D6/D9).
 *
 * NO local credentials configured (`hasLocalConfig()` returns `false`) is
 * reported, never thrown — a BYO vault this machine cannot reach is an
 * honest "not checked", not a failure that should break `fsck` for a
 * credential-less returning agent (see {@link VaultFsckByoPresence}'s
 * own doc comment). A confirmed absence is the opposite: it THROWS
 * `VAULT_BYO_OBJECT_MISSING` — the same severity class as {@link
 * Repos.mirrorVerify}'s own `VAULT_MIRROR_NOT_CONFIGURED` throw when
 * `--mirror` is requested against an unconfigured vault — this is exactly
 * the honesty D6 names: "we can tell the customer what SHOULD exist and
 * does not", stated as a real refusal rather than a silently-embedded
 * finding. The listed entries are capped at
 * {@link VAULT_BYO_OBJECT_MISSING_LIST_CAP} (a chain-referenced object
 * list can be arbitrarily large and this is an error envelope, not a
 * report); `missing_count` always carries the true total regardless of how
 * many are listed.
 *
 * `verifyPresence()` is a pure read (HEAD checks only, via
 * `verifyByoObjectsPresent`) — this function persists nothing itself, so
 * it behaves identically whether `fsck` was called with `write: true` or
 * `write: false`.
 */
export declare function computeByoPresenceOutcome(input: {
    repoId: string;
    vault: {
        storage_profile?: "managed" | "byo";
        byo_destination?: string | null;
    } | null;
    hasLocalConfig: () => boolean;
    verifyPresence: () => Promise<VaultByoPresenceReport>;
}): Promise<VaultFsckByoPresence | undefined>;
/**
 * `repos access`'s result — a READ over whatever the live gateway surface
 * exposes today. The gateway's `envelope-recipients` read reports
 * server-authoritative, membership-driven desired-recipient state
 * (`desired[]` + `desired_state_version`), so per-recipient `envelope_state`
 * (`converged` when the desired key is wrapped on this vault, `pending` when
 * it is not, `pending_removal` when membership removal has not yet been
 * enforced) is real. `envelope_state_available` reflects this at RUNTIME —
 * it is `false` only against an older gateway that has not shipped
 * `desired[]` yet (a rolling deploy window, or a pinned older `apiBase`),
 * never a hardcoded claim.
 *
 * ONE gap remains genuine and gateway-independent: `history_scope` (which
 * epochs each recipient can read) has no substrate to report, because
 * vault protocol v0 pins a single fixed epoch for a vault's entire
 * lifetime — there is no per-epoch scope to have. `stale_access` below is
 * the closest observable proxy for the same underlying limitation: a
 * `pending_removal` recipient whose fingerprint is STILL covered still
 * decrypts every commit (past AND future) under that one epoch, because
 * epoch rotation — the mechanism that would actually revoke them — is
 * mid-fold in `vault-human-envelopes` under adversarial protocol review.
 *
 * `access` reports what the read surface HAS: the org's directory of
 * encryption-key-holding members, which of the vault's current
 * envelope-recipient fingerprints match a directory entry, the
 * server-reported desired state per recipient when available, and
 * (Node-only, best-effort) this machine's own local TOFU pin for each
 * principal, when it has ever wrapped one.
 */
export interface VaultAccessRecipient {
    principal_id: string;
    display_name: string | null;
    /** This recipient's fingerprint per the org directory. */
    fingerprint: string;
    /** `true` when this fingerprint has a `key_envelope` on the vault today. */
    covered: boolean;
    /**
     * The server's desired-recipient state for this principal, cross-referenced
     * against `covered`: `"converged"` (desired + covered), `"pending"`
     * (desired, not yet wrapped), `"pending_removal"` (membership removed
     * them but this vault has not been re-keyed away from them — see
     * `stale_access`), or `null` when the gateway did not report desired-state
     * for this principal (older gateway, or the directory and desired-state
     * reads disagree, which should not happen but is reported honestly rather
     * than papered over).
     */
    envelope_state: "converged" | "pending" | "pending_removal" | null;
    /** THIS machine's own local trust-on-first-use record for this principal, or `null` if this machine never wrapped them. Never a server-side fact. */
    tofu_pin: {
        fingerprint: string;
        matches_directory: boolean;
    } | null;
}
/** A principal whose membership was removed (desired state `pending_removal`) but who STILL holds a covering `key_envelope` on this vault — real, continuing access that removal did not revoke, because vault v0 has no epoch-rotation mechanism yet. See {@link VaultAccessResult}'s doc comment. */
export interface VaultStaleAccessEntry {
    principal_id: string;
    display_name: string | null;
    fingerprint: string;
}
export interface VaultAccessResult {
    repo_id: string;
    org_id: string | null;
    /** vault-agent-envelopes D5: this KEY-HOLDER's session-start fulfilment outcome (`null` when this machine holds no K_repo for the vault, or `reconcile: "forbidden"`). */
    reconcile_recipients?: VaultSessionReconcileResult | null;
    /** vault-agent-envelopes D3: the enroll-if-absent step's outcome (`null` when it did not run). */
    enrollment?: VaultEnrollmentOutcome | null;
    recipients: VaultAccessRecipient[];
    /** Vault-covering fingerprints (from the server) that match neither a directory entry nor a desired-state row — genuinely orphaned, revoked outside this org's membership model, or external. Excludes fingerprints already explained by `stale_access` AND by `this_keystore`. */
    unmatched_covered_fingerprints: string[];
    /**
     * Node-only, best-effort: set when an otherwise-unmatched covering
     * fingerprint equals THIS keystore's own encryption-key fingerprint — the
     * one case an unmatched fingerprint is locally provable rather than a
     * genuine unknown. Typically the vault creator's own wallet-principal
     * keystore, which the org directory never lists (it only enrolls human
     * keys). `null` when no local match was found (including non-Node
     * callers, or a machine that never held this identity).
     */
    this_keystore: {
        fingerprint: string;
        /** `true` iff the directory holds this keystore's key as ACTIVE (vault-agent-envelopes: agents enroll too). */
        enrolled: boolean;
        /** `absent` = no published key (the next vault operation enrolls); `pending` = published, possession unproven; `rotation_required` = the principal's published key is a DIFFERENT key; `unknown` = whoami unavailable. */
        publish_state: "active" | "pending" | "absent" | "rotation_required" | "unknown";
        covered_on_this_vault: boolean;
        /** @deprecated alias of `covered_on_this_vault`. */
        covered: boolean;
        next_actions?: Array<{
            action: string;
            why: string;
        }>;
    } | null;
    /** Removed members who still decrypt this vault — see {@link VaultStaleAccessEntry}. Always `[]` when `envelope_state_available` is `false` (no desired-state substrate to compute it from). */
    stale_access: VaultStaleAccessEntry[];
    /** `true` when the gateway reported desired-recipient state (`desired[]`) for this read, making `recipients[].envelope_state` and `stale_access` real rather than absent. `false` only against an older gateway. */
    envelope_state_available: boolean;
    /** Always `false` — see this type's own doc comment for why this is a protocol-level absence, not a missing gateway feature. */
    history_scope_available: false;
    /** The honest, human-readable statement of the gap above. Read it before assuming `covered: true` means "converged," and before assuming `pending_removal` means access was actually revoked. */
    gap: string;
    /** Present only when `stale_access` is nonempty — the exact owner-driven remedy (D193-D203, rev 42): `repos access repair` for a general re-key, `repos access revoke-key <principal_id>` for one targeted principal. */
    next_actions?: {
        action: string;
        why: string;
    }[];
}
/**
 * `repos list`'s bulk read —
 * `GET /vaults/v1?org_id=<uuid>`.
 * FROZEN response shape, agreed with the gateway
 * team ahead of the route landing; the route may still 404 on a gateway
 * that has not shipped it yet, and callers should fall back to the
 * per-project walk (`status()` in a loop) until then — see
 * `cli/lib/repos.mjs`'s `list()` for that fallback, kept only until every
 * deployed gateway answers this route.
 */
export interface VaultOrgVaultSummary {
    repo_id: string;
    project_id: string;
    project_name: string | null;
    repo_name: string | null;
    org_slug: string | null;
    vault_policy: "required" | "grandfathered" | null;
    newest_generation: string | null;
    source_bytes: string;
    genesis_admitted_at: string | null;
    created_at: string;
    /** vault-byo-primary-bucket task 3.5 — absent-or-`"managed"` is byte-identical to today. */
    storage_profile?: "managed" | "byo";
}
export interface VaultOrgVaultsListing {
    vaults: VaultOrgVaultSummary[];
    /** Keyset pagination (agent-response-design): opaque, store-and-echo. */
    has_more?: boolean;
    next_cursor?: string | null;
}
export interface VaultOpenOrCreateResult {
    handle: VaultHandle;
    /** `true` when the vault already existed — nothing was allocated by this call. */
    found: boolean;
    created: {
        /** Mirrors `VaultInitResult.deduplicated`: an existing local creation journal was resumed to completion rather than started fresh — nothing was re-minted. */
        deduplicated: boolean;
        /** Emitted once at creation — integrity data, not a secret. Print it, copy it, keep many copies. Persisted into the keystore regardless. */
        recovery_receipt: VaultCreationResult["recovery_receipt"];
        genesis_sha256: string;
    } | null;
    terminal_loss_statement: typeof VAULT_TERMINAL_LOSS_STATEMENT;
}
/**
 * {@link Repos.deploy}'s post-push glue: attach the best-effort
 * mirror/reconcile hooks to a deploy result, gated on whether this deploy
 * actually landed a new generation in the vault. Extracted as a standalone
 * function (rather than inlined in `deploy()`) purely so the gating can be
 * unit-tested with fake thunks — the real hooks (`#tryMirrorPush` /
 * `#tryReconcileEnvelopeRecipients`) are private class methods that already
 * catch everything and never reject, so this function does not need its own
 * try/catch: it only decides WHETHER to call them and how to merge what they
 * resolve to.
 *
 * `DEPLOYED_AND_VAULTED` and `DEPLOY_FAILED_VAULTED` are the only two
 * outcomes that carry a `generation` — a vault push actually landed. The
 * other three (`DEPLOY_BLOCKED_PUSH_FAILED`, `DEPLOY_FAILED_UNVAULTED`,
 * `DEPLOYED_UNVAULTED_OVERRIDE`) published nothing new, so `mirror_push` /
 * `reconcile_recipients` are OMITTED rather than a faked `skipped_*` value —
 * there is nothing this deploy did that either hook could report on.
 */
export declare function attachVaultDeployHooks(result: VaultDeployResult, mirror: () => Promise<VaultMirrorPushResult>, reconcile: () => Promise<VaultReconcileEnvelopeRecipientsPushResult>): Promise<VaultDeployResult & {
    mirror_push?: VaultMirrorPushResult;
    reconcile_recipients?: VaultReconcileEnvelopeRecipientsPushResult;
}>;
export declare class Repos {
    #private;
    constructor(client: Client);
    /** The vault record — policy, allocation generation, storage + maintenance state. */
    get(repoId: string): Promise<VaultRecord>;
    /**
     * Resolve a project's vault with no local state. This is the cold-restart
     * entry point: an agent that lost its machine but still holds authority on
     * the project learns its `repo_id` here.
     */
    forProject(projectId: string): Promise<VaultRecord>;
    /**
     * Every vault the organization owns, one round trip — `repos list`'s bulk
     * read. See {@link
     * VaultOrgVaultsListing}'s doc comment for the FROZEN response shape and
     * the 404-until-shipped fallback contract.
     */
    listByOrg(orgId: string): Promise<VaultOrgVaultsListing>;
    /**
     * Resolve a vault by its address-form `org-slug/name` —
     * `GET /vaults/v1?repo=<org-slug>/<name>`.
     * `RESOURCE_NOT_FOUND` for no such org OR no such name (deliberately
     * collapsed — see the design's slug-namespace-probing note);
     * `SLUG_RELEASED` (read it with {@link vaultSlugReleasedInfo}) while the
     * slug is in its post-rename cooldown — never auto-followed.
     */
    forRepo(address: {
        org_slug: string;
        repo_name: string;
    }): Promise<VaultRecord>;
    /**
     * Resolve a parsed remote address (`parseVaultRemoteUrl`'s output),
     * dispatching on its form: id-form resolves exactly like
     * {@link forProject}; slug-form resolves via {@link forRepo}. A pure read —
     * no pinning, no creation. Node-only callers wanting BOTH should use
     * {@link resolveOrCreateAddress} instead, which also drives the local pin
     * and (opt-in) push-to-create.
     */
    resolveAddress(address: VaultRemoteAddress): Promise<VaultRecord>;
    /**
     * One page of the heads listing (D186).
     *
     * `after_generation` is the REQUIRED verification anchor — a semantic input,
     * never a paging knob — and must stay CONSTANT across a page sequence.
     * `limit` is required. `cursor` is omitted on the first request and is then
     * the prior page's `next_cursor` echoed UNCHANGED: store and echo, never
     * parse. A malformed or stale cursor is `INVALID_CURSOR`; recover by
     * restarting from `after_generation` with no cursor.
     */
    heads(repoId: string, request: VaultHeadsListingRequest): Promise<VaultHeadsListingPage>;
    /**
     * Walk the whole listing above the anchor, verifying page coupling, ordering,
     * and gaplessness as it goes (a gap is `CHAIN_BROKEN`, never a silent skip).
     */
    allHeads(repoId: string, options: {
        after_generation: string;
        limit?: string;
    }): Promise<{
        heads: VaultHeadsListingPage["heads"];
        pages: number;
        total: string | null;
    }>;
    /**
     * Set the activation policy. Owner + step-up, audited, reason required.
     * `grandfathered` leaves a doctor-persistent warning until it returns to
     * `required`.
     */
    setPolicy(repoId: string, input: {
        vault_policy: "required" | "grandfathered";
        reason?: string;
    }): Promise<{
        vault_policy: string;
        vault_policy_version: string;
        changed: boolean;
        warnings: {
            kind: string;
            message: string;
        }[];
    }>;
    /**
     * Clear an unvaulted-override advisory by presenting a capture receipt that
     * matches the journaled operation on EVERY field. A partial match never
     * clears it.
     */
    completeOverride(repoId: string, input: {
        operation_id: string;
        capture_receipt: VaultCaptureReceipt;
    }): Promise<{
        operation_id: string;
        advisory_cleared: boolean;
        generation: string;
        head_sha256: string;
    }>;
    /**
     * Take the owner's maintenance reservation for a compact/prune cycle.
     *
     * SECRET-BEARING: `holder_token` is returned exactly ONCE and is the liveness
     * instrument for heartbeat/release. Never log it, never cache it, never place
     * it in an agent-surface result store.
     */
    /** `POST …/recipients/:principal_id/confirm` (D197) — first-seen pin confirmation. */
    confirmRecipient(repoId: string, principalId: string, newFingerprint: string): Promise<VaultRecipientConfirmationReceipt>;
    /** `POST …/recipients/:principal_id/repin` (D197) — re-pin ceremony. */
    repinRecipient(repoId: string, principalId: string, input: {
        old_ek_fingerprint: string;
        new_fingerprint: string;
    }): Promise<VaultRecipientConfirmationReceipt>;
    /**
     * vault-agent-envelopes D3 — a KEY-HOLDER explicitly accepts a recipient's
     * CHANGED key. The session-start reconcile refuses to wrap under a
     * fingerprint that differs from this keystore's TOFU pin
     * (`pinned_key_mismatch`) — that refusal is the substitution defence and
     * is never bypassed automatically, not even after an owner's revoke: from
     * this machine's view an owner-driven re-key and a platform substitution
     * look identical, and the audit event is not proof against the platform.
     * Acceptance is a deliberate act naming the new fingerprint (the
     * out-of-band verification point — read it back with the recipient over any
     * channel; it is public data): this records the D197 re-pin receipt with the
     * gateway AND moves the local pin, so the next reconcile wraps. Refuses when
     * `new_fingerprint` is not what the org directory currently serves for the
     * principal (a stale or mistyped fingerprint never pins).
     */
    acceptRecipientKeyChange(options: VaultHandleOptions & {
        principal_id: string;
        new_fingerprint: string;
    }): Promise<{
        repo_id: string;
        principal_id: string;
        old_fingerprint: string | null;
        new_fingerprint: string;
        receipt: VaultRecipientConfirmationReceipt | null;
    }>;
    /**
     * `POST …/recipients/:principal_id/key-revocation` (D199) — declares
     * `reason:"recipient_key_revoked"` admissible for the NEXT rotation this
     * org's vaults submit; org-scoped, advances the same watermark a member
     * removal does. Returns the D194 counters — the ONE client-visible read of
     * them, which is why {@link rotateEpochForKeyRevocation} exists as the
     * fully self-contained entry point.
     */
    declareRecipientKeyRevoked(repoId: string, principalId: string): Promise<{
        recipient_state_version: string;
        recipient_revocation_version: string;
    }>;
    /**
     * `POST …/epoch-secret-exposure` (D199) — declares `reason:"epoch_secret_exposed"`
     * admissible for THIS vault (deliberately vault-scoped, not org-wide — one
     * vault's leaked `K_repo`/`K_e` is not evidence any sibling vault is
     * compromised). This is the rekey remedy for a leaked/exposed vault key:
     * declare exposure here, then drive a `rotate_epoch` with
     * `reason:"epoch_secret_exposed"` (the required counters must be supplied
     * from a source other than this call — see {@link rotateEpoch}'s doc
     * comment on the confirmed gap in what the gateway exposes today).
     */
    declareEpochSecretExposed(repoId: string): Promise<{
        epoch_secret_exposure_version: string;
    }>;
    /** `POST …/writer-authority/declare-unavailable` (D202) — an explicit, audited fact that the writer signing key is gone. */
    declareWriterAuthorityUnavailable(repoId: string): Promise<{
        declared_at: string;
        declared_by: string | null;
    }>;
    /**
     * `POST …/recipients/:principal_id/proof-of-open` (D210, rev 44) — submit
     * `fsck`'s OWN `chain_verified_to_generation`/`decryptable_to_generation`
     * evidence VERBATIM as proof that `principalId` can open this vault under
     * its current epoch. `fsck()` itself calls this automatically (in write
     * mode, when a local encryption identity exists) — call it directly only
     * for a manual/explicit submission (e.g. resubmitting after fixing a
     * local keystore issue, or from a caller that already resolved its own
     * `principal_id` and does not want the extra `whoami` round trip
     * `fsck()`'s own auto-submission pays).
     *
     * Self-match only: the gateway requires `principalId` to equal the
     * AUTHENTICATED caller, never overridable by any credential class — a
     * mismatch is the ordinary 403 `VAULT_ACCESS_DENIED`. Idempotent on
     * `(repo_id, principal_id, ek_fingerprint, decryptable_to_generation)` —
     * `deduplicated: true` means the gateway returned the tuple's EXISTING
     * receipt (HTTP 200) rather than minting a fresh one (HTTP 201).
     */
    submitProofOfOpen(repoId: string, principalId: string, evidence: {
        ek_fingerprint: string;
        chain_verified_to_generation: string;
        decryptable_to_generation: string;
        reader_entrypoint: string;
    }): Promise<{
        receipt: VaultOpenReceipt;
        deduplicated: boolean;
    }>;
    acquireMaintenanceLease(request: VaultMaintenanceLeaseRequest): Promise<VaultMaintenanceLease>;
    /**
     * Open the vault: keystore + HTTP transport + the protocol object. Every verb
     * below builds on this; call it directly when you need the raw protocol
     * surface (ref transactions, repair, checkpoint building).
     */
    open(options?: VaultHandleOptions): Promise<VaultHandle>;
    /**
     * Open a vault, allocating it first when it does not exist yet (D2 — lazy
     * allocation on first push).
     *
     * This is the ONE primitive the remote helper and the capture lane
     * (`run402 repos capture`/`snapshot`) drive so that a push against an
     * unallocated project runs the six-stage creation journal inline instead of
     * refusing: it resolves `repo_id` from `project_id` exactly like
     * {@link open}, and when that resolution fails, tries to create the vault —
     * but ONLY when `org_id` was supplied. Without `org_id` this method is
     * byte-identical to `open()`: the original resolution failure is rethrown
     * unchanged, so every existing caller of `open()` that has no reason to
     * create anything sees no behavior change at all by switching to this.
     *
     * RESUMABILITY (client-surface spec, D2): before starting a fresh creation
     * attempt this looks for an INCOMPLETE local journal already matching this
     * exact `(org_id, project_id)` and resumes ITS `client_creation_id`, rather
     * than starting a second competing attempt every time the process is
     * interrupted mid-creation. Kill the process after ALLOCATED and call this
     * again: the same journal — not a new one — drives to ACTIVE, and exactly
     * one vault exists either way. An explicit `client_creation_id` (tests, or
     * a caller resuming a specific attempt by hand) always wins over that search.
     */
    openOrCreate(options: VaultHandleOptions & {
        org_id?: string;
        client_creation_id?: string;
    }): Promise<VaultOpenOrCreateResult>;
    /**
     * Resolve a parsed remote address to an OPEN handle, pinning `repo_id` in
     * local git state on the first successful resolution of EITHER form
     * (vault-client-round-trips design D4 widens the original slug-form-only
     * pin to id-form too — an id-form address needs no pin to survive a
     * rename, but the resolution round trip it skips is the same either way),
     * and — when `allow_create` is set and resolution misses — push-to-create
     * it. This is what the remote helper and `vault snapshot` drive for a
     * `run402::<org>/<name>` remote, whichever form it names, so a caller need
     * not branch on the address's form itself. A pinned id/address that no
     * longer resolves (404) clears the pin and re-resolves once.
     *
     * `SLUG_RELEASED` is NEVER auto-followed — it rethrows unchanged; read it
     * with {@link vaultSlugReleasedInfo} for the successor slug and cooldown.
     */
    resolveOrCreateAddress(options: VaultHandleOptions & {
        address: VaultRemoteAddress;
        /** Push-to-create on a slug-form miss (D6). `false` (default): a miss is an ordinary not-found refusal — the read path (`list`/`fetch`, `status`). */
        allow_create?: boolean;
        client_creation_id?: string;
        /** Fires once, only when THIS call allocated the vault. Awaited before the handle is returned. */
        onVaultCreated?: (created: NonNullable<import("../node/vault-address.js").VaultAddressResolution["created"]>) => void | Promise<void>;
    }): Promise<VaultOpenOrCreateResult & {
        resolution: import("../node/vault-address.js").VaultAddressResolution;
    }>;
    /**
     * Stale-pin recovery for OFFLINE address resolutions
     * (vault-force-spelling-and-pin-fold): an id-carrying pin resolves with
     * zero network reads, so a pin gone stale (its vault deleted and the
     * project re-allocated a new one) surfaces as the VERB's first repo-scoped
     * read failing rather than as a resolution failure. Call this with that
     * failure: it answers a fresh opened handle + resolution to retry the verb
     * against exactly once, or `null` when there is nothing to recover — the
     * error is not a vault-absent signal, the resolution was not offline, or
     * re-resolution lands on the SAME `repo_id` (the pin was fine and the
     * original refusal is real; it is restored, and recovery never widens what
     * an unauthorized caller learns).
     */
    recoverStalePin(options: VaultHandleOptions & {
        address: VaultRemoteAddress;
        repo_dir: string;
        resolution: import("../node/vault-address.js").VaultAddressResolution;
        error: unknown;
    }): Promise<(VaultOpenOrCreateResult & {
        resolution: import("../node/vault-address.js").VaultAddressResolution;
    }) | null>;
    /**
     * Create the vault for a project and scaffold the git remote.
     *
     * Runs the six-stage creation journal — `LOCAL_KEYS_PREPARED → ALLOCATED →
     * OBJECTS_PREPARED → OBJECTS_FINALIZED → GENESIS_PREPARED → ACTIVE`, each
     * fsynced before the next step, with no ciphertext existing before allocation
     * supplies the `repo_id` the key derivation needs. Crash-safe and resumable
     * on `client_creation_id`.
     *
     * An existing `origin` remote is never modified or claimed; only a remote
     * named `run402` is added.
     */
    init(options: {
        org_id: string;
        project_id: string;
        repo_dir?: string;
        keystore_root?: string;
        /** Resume a specific creation attempt (or pin it in tests). */
        client_creation_id?: string;
        /** Skip the git scaffold — allocate the vault only. */
        scaffold_git?: boolean;
        /**
         * Scaffold `repo_dir` as its OWN repository even when it lies inside
         * another one (see {@link Repos.scaffoldRemote}'s `nested`). Default
         * `false`: an app root inside another repository is reported `skipped`.
         */
        nested?: boolean;
        remote_name?: string;
        remote_url?: string;
        service_public_key?: Uint8Array | string;
        /**
         * vault-byo-primary-bucket task 3.1/3.2/3.5 — request a BYO vault.
         * Same raw-string shape `mirrorSet` already takes (`destination_url` +
         * `credential` + `region`/`endpoint`), so a CLI edge stays a thin
         * adapter — no destination parsing lives outside the SDK. Omitted (the
         * default) is byte-identical to today. This method RUNS the
         * allocation-time bucket probe (D6) itself, BEFORE any allocation
         * request — a failed probe throws `VAULT_BYO_BUCKET_PROBE_FAILED`
         * and nothing is created.
         */
        byo?: {
            destination_url: string;
            credential?: import("../node/vault-mirror-config.js").VaultMirrorCredential;
            region?: string;
            endpoint?: string;
        };
    }): Promise<VaultInitResult>;
    /**
     * Add the run402 git remote, initialising the repository if absent.
     *
     * D1 — claim `origin` additively. LLM muscle memory is `git push origin
     * main` from a billion training examples, and a side-remote name costs
     * every agent a correction cycle, so when the repository has no `origin`
     * remote ours BECOMES `origin`. An existing `origin` is NEVER modified or
     * reclaimed — no matter what it points at, including a prior run of this
     * exact call — so the fallback is `run402`, and when THAT is also taken by
     * something else, nothing is added at all: the additive discipline holds
     * for every remote name this method ever touches, not just `origin`.
     *
     * An explicit `remote_name` is a caller override (no current caller passes
     * one) and skips the origin/run402 dance entirely — the caller already
     * decided the name; this method still never modifies an existing remote
     * under it.
     *
     * No key material or allocation is required — the cold-start path gains no
     * prompts or network dependencies from this.
     *
     * `nested: true` — the monorepo case. An app root that lies INSIDE another
     * repository (an agent workspace with many apps under one checkout) is
     * still made its own repository: `git init -b main` in `repo_dir`, the
     * remote added there, and ONE line — `/<relative path of repo_dir>/` —
     * appended to the ENCLOSING repository's local `.git/info/exclude`
     * (located via `rev-parse --git-path info/exclude`, so a worktree resolves
     * to its common dir) so the enclosing checkout never lists the nested
     * repository as untracked noise. Never `.gitignore` (tracked content),
     * never the index, never a submodule: nothing else in the enclosing
     * repository changes, and its remotes are untouched. Idempotent — a second
     * call on the already-nested app root adds nothing and re-reports the same
     * shape. Without `nested`, the same situation is reported `skipped` with a
     * `create_nested_repo` next_action naming this way out.
     */
    scaffoldRemote(options: {
        repo_dir: string;
        org_id: string;
        project_id: string;
        remote_name?: string;
        remote_url?: string;
        nested?: boolean;
    }): Promise<VaultScaffoldRemoteResult>;
    /**
     * What this machine and the control plane each believe about the vault.
     *
     * Truthful for a VAULT-ONLY project (protocol D183): a project that has never
     * deployed raises no deploy-related warning, and the terminal-loss statement
     * is stated verbatim exactly as for any other vault.
     */
    status(options?: VaultHandleOptions & {
        /**
         * Also report the vault's ref map and HEAD target.
         *
         * Opt-in because it is not free and not read-only in the local sense:
         * materializing walks the head chain (a verification) and advances the
         * keystore's materialized pin. `status` without it stays a pure
         * observation, which is what makes it safe to run anywhere.
         */
        refs?: boolean;
    }): Promise<VaultStatus>;
    /**
     * Capture the working tree and publish it — the push half of a deploy, run on
     * its own. Never gated on a deploy: a vault-only project pushes for months
     * without one.
     *
     * WHAT THIS PUBLISHES, and what it deliberately does not. This is the CAPTURE
     * lane: it publishes the protocol-owned `refs/run402/deploys/latest` plus the
     * `head_target` read off the local HEAD. The repository's OWN refs —
     * `refs/heads/*` and `refs/tags/*` — reach the vault through
     * `git push run402 …` via `git-remote-run402`, which is the lane the spec
     * charges with reproducing them ("the helper SHALL reproduce the exact set of
     * objects reachable from the declared canonical refs (`refs/heads/*`,
     * `refs/tags/*`, protocol-owned `refs/run402/*`), plus the `HEAD` target" —
     * vault-client-surface, "Faithful helper"; `run402 repos capture` is
     * separately defined as "capture and push outside a deploy" under "Source
     * verbs"). The split is forced by §6.6: a dirty tree captures as a SYNTHETIC
     * commit that sits on no branch, so moving `refs/heads/main` onto it would
     * rewrite the user's branch on every dirty push — exactly the history
     * clobbering §6.1's fast-forward + force-with-lease rules exist to prevent.
     *
     * Hence `protocol_refs: "allow"`: this lane BUILDS the protocol ref itself,
     * so it opts in. The remote helper must keep the `"refuse"` default, because
     * there the refnames are user-supplied and a user must not be able to squat
     * the `refs/run402/*` namespace.
     *
     * Before reporting a push as landed the vault compares finalization receipts
     * against its expected manifest and reads the admitted head back from
     * storage. A 200 alone is never enough (§0 client obligations).
     */
    capture(options: VaultHandleOptions & {
        /**
         * The owning org. Supply it to run D2's lazy allocation: when this
         * project's vault does not exist yet, capture() runs the six-stage
         * creation journal inline (via {@link openOrCreate}) before capturing
         * and publishing — one command, no prior `vault init`. Without it,
         * capture() behaves exactly as it always did: a push against an
         * unallocated vault throws the resolution failure unchanged.
         */
        org_id?: string;
        /**
         * A parsed remote address (`parseVaultRemoteUrl`'s output).
         * When given, this push resolves
         * (and, for a slug-form address, pins) through
         * {@link resolveOrCreateAddress} INSTEAD of `openOrCreate`'s
         * project_id-based path; `org_id`/`project_id`/`repo_id` are ignored.
         * Mirrors `git push`'s own push-to-create dispatch in the remote
         * helper, for callers (`vault snapshot`) that resolve the target
         * from the local git remote instead of `--project`.
         */
        address?: VaultRemoteAddress;
        /** Resume a specific creation attempt (or pin it in tests); auto-discovered from the local keystore otherwise. */
        client_creation_id?: string;
        /**
         * Fires once, only when THIS call allocated the vault — the moment to
         * print the one-shot recovery receipt and keystore path. Awaited
         * before capture/publish continue, so any async work inside it (e.g.
         * resolving the keystore path to print) completes and stays ordered
         * BEFORE the rest of this push's own output.
         */
        onVaultCreated?: (created: NonNullable<VaultOpenOrCreateResult["created"]>) => void | Promise<void>;
        /**
         * Capture options, forwarded verbatim to `captureSnapshot`. The commit
         * message for the synthetic commit a dirty tree produces lives HERE
         * (`snapshot: { message }`) — there is deliberately no second top-level
         * `message` field, because a `snapshot` passthrough plus a sibling
         * shortcut is two ways to say one thing with no defined precedence.
         */
        snapshot?: Omit<import("../node/vault-snapshot.js").VaultSnapshotOptions, "dir">;
        onCommitLine?: (line: string) => void;
        checkpoint?: boolean;
    }): Promise<VaultPublishResult & {
        snapshot: VaultSnapshot;
        vault_commit: string;
        vault_commit_line: string;
        mirror_push: VaultMirrorPushResult;
        byo_chain_copy: VaultMirrorPushResult;
        reconcile_recipients: VaultReconcileEnvelopeRecipientsPushResult;
        writer_reconcile: VaultReconcileWriterAdmissionsPushResult;
    }>;
    /**
     * Mint a Handoff Key: capture a stash-shaped checkpoint (design D1),
     * push it (retained, on no branch — {@link VAULT_DEPLOY_REF} carries
     * it exactly like an ordinary `capture()`, never `refs/heads/*`), seal the
     * vault's current epoch key under a fresh `wrap_key`, and mint through
     * the gateway. The assembled `kgh1_…` key is returned exactly ONCE —
     * nothing here or downstream persists it.
     *
     * `options.note` omits `capture` — this method fills it with the real
     * capture figures and runs the client-side secret scan BEFORE the
     * handoff commit is written (design D10: no override flag).
     */
    handoff(options: VaultHandleOptions & {
        address?: VaultRemoteAddress;
        role?: string;
        ttlSeconds?: number;
        note: Omit<import("../node/vault-handoff.js").KygitHandoffNote, "capture">;
        includeSensitive?: string[];
        onCommitLine?: (line: string) => void;
    }): Promise<VaultHandoffMintResult>;
    /** List a vault's handoffs (ids, kind, state, role, expiry, redeemed_by — never the hash or envelope). */
    listHandoffs(options: VaultHandleOptions): Promise<VaultHandoffListResult>;
    /** Revoke a handoff (idempotent — a second revoke of an already-revoked/redeemed/expired row still answers `200`). */
    revokeHandoff(handoffId: string, options: VaultHandleOptions): Promise<{
        handoff_id: string;
        state: string;
    }>;
    /**
     * Mint an Invite Key: capture a stash-shaped checkpoint exactly as
     * {@link Repos.handoff} does (design D1), push it (retained, on no
     * branch), register the INVITER's own presence in the invite's room
     * (design D4 — before the mint, so the row can carry
     * `inviter_presence_id`; a registration failure is reported and the mint
     * proceeds without one), seal the vault's current epoch key under a fresh
     * `wrap_key`, mint through the gateway at `developer` (or `role`,
     * attenuated to never exceed the minter's own), and post ONE message from
     * the inviter's presence naming the checkpoint and the invite id (never
     * the key) — a message-post failure is reported in `room_message` and never
     * voids the mint (design D4). The assembled `kgi1_…` key is returned
     * exactly ONCE — nothing here or downstream persists it. Creating an
     * invite never touches the inviter's worktree, index, branch, refs, or
     * access.
     *
     * `options.note` omits `capture` — this method fills it with the real
     * capture figures and runs the client-side secret scan BEFORE the invite
     * commit is written (design D10/kygit-invite D3: no override flag).
     */
    invite(options: VaultHandleOptions & {
        address?: VaultRemoteAddress;
        role?: string;
        ttlSeconds?: number;
        /** Named org room to invite into. Omitted: the project's default room (its own id). */
        roomKey?: string;
        note: Omit<import("../node/vault-handoff.js").KygitInviteNote, "capture">;
        includeSensitive?: string[];
        onCommitLine?: (line: string) => void;
        /** Harness-derived presence labels (design D8) — never guessed by the SDK itself. */
        program?: string;
        model?: string;
        /** Opaque session identity for the inviter's own presence registration (see {@link RegisterPresenceOptions.sessionKey}). */
        sessionKey?: string;
        /** Display-only "what I'm working on" for the inviter's presence. */
        task?: string;
    }): Promise<VaultInviteMintResult>;
    /** List a vault's invites (ids, kind, state, role, room, expiry, redeemed_by — never the hash or envelope). */
    listInvites(options: VaultHandleOptions): Promise<VaultInviteListResult>;
    /** Revoke an invite (idempotent — a second revoke of an already-revoked/redeemed/expired row still answers `200`). */
    revokeInvite(inviteId: string, options: VaultHandleOptions): Promise<{
        invite_id: string;
        state: string;
    }>;
    /**
     * Resume a Handoff Key: parse → ensure this machine has a wallet (the
     * claim is bare SIWX, so on a fresh machine the wallet file is created
     * here — a keypair on disk, no faucet, no tier, no payment, ever; design
     * D5) → redeem → open the
     * sealed envelope → write the repo file to the keystore BEFORE touching
     * disk → clone at the base HEAD → `git stash apply --index` → local
     * git-config pins only → the session-start reconcile so a principal
     * envelope supersedes the bearer one.
     */
    /**
     * vault-multi-writer rev 47 (task 5.6, design D4/D5) — order: parse →
     * ensure wallet → ensure identity → derive auth/wrap/admission → build
     * acceptance → redeem → verify grant → open envelope → check the grant
     * hash → persist repo file with `pending_writer_admission` → clone →
     * verify chain → submit the ref-neutral activation head → reconcile
     * principal envelope → apply the checkpoint. Reported as
     * `writer_activation` and `reconcile_recipients` (D5's "recipient
     * coverage"), two blocks, because they are two properties.
     *
     * Crash-resumable by construction, not by a special-cased retry branch:
     * the acceptance is derived fresh every call from the (deterministic)
     * admission seed + this checkout's own identity, so re-running this
     * ENTIRE method after a crash anywhere before activation lands is safe —
     * the redeem route is itself idempotent (same-redeemer replay returns the
     * SAME grant). The one step that is NOT safely repeatable is submitting
     * the activation head a second time (the chain burns `handoff_id`
     * single-use) — `submitWriterActivationHead` handles that by checking
     * whether this checkout's own key is ALREADY in the freshly-verified
     * writer set before ever building a transition, exactly mirroring
     * `handoff()`'s own writer precheck (task 5.5), just inverted: there
     * "not yet a writer" refuses; here "already a writer" means skip.
     */
    resume(options: {
        key: string;
        to?: string;
        keystore_root?: string;
        onLine?: (line: string) => void;
    }): Promise<VaultHandoffResumeResult>;
    /**
     * Join an Invite Key: parse (refusing a `kgh1_` handoff key by name,
     * pointing at `resume` — design D9) → ensure this machine has a wallet
     * (design D5, mirroring {@link Repos.resume}'s own bare-wallet
     * backstop; the CALLER folds the fuller cold-start chain — wallet,
     * faucet, one x402 prototype payment — before invoking this, never
     * blocking the redemption itself) → redeem → open the sealed envelope → write
     * the repo file to the keystore BEFORE touching disk → clone at the base
     * HEAD → `git stash apply --index` → local git-config pins (including
     * `r402.room` set to the invite's OWN room, never just the project id) →
     * append `.run402/` to `.git/info/exclude` → the session-start reconcile
     * → register THIS session's presence in the room and post ONE arrival
     * fact naming it and the checkpoint (idempotent on the invite id;
     * best-effort — a presence or fact failure never blocks arrival) → read
     * the most recent messages for the arrival view.
     */
    join(options: {
        key: string;
        to?: string;
        keystore_root?: string;
        onLine?: (line: string) => void;
        /** Harness-derived presence labels (design D8) — never guessed by the SDK itself. */
        program?: string;
        model?: string;
        /** Opaque session identity for this session's own presence registration (see {@link RegisterPresenceOptions.sessionKey}). */
        sessionKey?: string;
        /** Display-only "what I'm working on" for this session's presence; defaults to naming the invite. */
        task?: string;
        /** How many recent messages to read for the arrival view. Default 10. */
        recentMessagesLimit?: number;
    }): Promise<VaultInviteJoinResult>;
    /**
     * The capture-time copies a plain `git push` through the remote helper
     * owes exactly as {@link capture} and {@link deploy} do: the opt-in mirror
     * mirror write and, on a BYO vault, the signed-chain copy into the customer
     * bucket (vault-byo-primary-bucket task 3.3). The helper publishes
     * through `Vault.push` directly, so it calls this right after a
     * generation lands. Same contract as the private hooks it composes:
     * best-effort, NEVER throws, never alters the push already committed —
     * each outcome is reported on its own field (`skipped_no_mirror` costs no
     * network call).
     */
    postPublishCopies(input: {
        repo_id: string;
        keystore: VaultKeystore;
    }): Promise<{
        mirror_push: VaultMirrorPushResult;
        byo_chain_copy: VaultMirrorPushResult;
    }>;
    /**
     * A REAL preview of what {@link capture} would publish
     * — never publishes anything, and never allocates. `run402 repos
     * capture --dry-run` and `git-remote-run402`'s `option dry-run true` are
     * both thin adapters over this method.
     *
     * "Refusing beats fake success" (this file's own architectural law) governs
     * the shape of what happens when the vault does not exist yet: unlike
     * {@link capture}, this NEVER allocates one (push-to-create must not allocate
     * on a dry run) — it resolves READ-ONLY (`open`/`resolveOrCreateAddress`
     * with `allow_create: false`), and when that resolution misses, returns
     * `allocation_needed: true` with every sizing field `null` rather than a
     * guess. Sizing is genuinely unknowable before allocation: encryption uses
     * a `K_repo` this project has not been assigned yet, so there is no key to
     * preview a push under — only the real capture (this method still runs
     * `captureSnapshot`, which is local, filter-free work) can be computed.
     *
     * Everything else is the SAME real local pipeline `push` runs — capture,
     * pack building, sealing/encryption — computed by
     * {@link import("../node/vault-publication.js").Vault.planPush},
     * which is what actually stops short of the two network mutations
     * (`uploadObjects`, `admitHead`). See its doc comment for what
     * `would_admit_generation` does and does not promise.
     */
    planCapture(options: VaultHandleOptions & {
        /** Same as {@link capture}'s `address` — a parsed remote address. Resolved READ-ONLY (`allow_create: false`); never push-to-creates. */
        address?: VaultRemoteAddress;
        snapshot?: Omit<import("../node/vault-snapshot.js").VaultSnapshotOptions, "dir">;
        onCommitLine?: (line: string) => void;
        checkpoint?: boolean;
    }): Promise<VaultSnapshotPushPlan>;
    /**
     * Compaction's transient-storage preflight
     * (vault-compaction-headroom-preflight, design D1/D2).
     *
     * Three postures, in order of information quality:
     *   1. the check answers "won't fit" → typed refusal, before any upload;
     *   2. the caller passed the override → proceed, marked `overridden`;
     *   3. the check CANNOT be answered → proceed after one stderr note.
     *
     * (3) is deliberate: failing closed on ignorance would make compaction's
     * availability depend on an ADVISORY read, which is wrong for a maintenance
     * verb whose refusals must come from the authority that owns the quota.
     *
     * The size proxy is the vault's billed `source_bytes` (D1). The true
     * checkpoint-pack size is unknowable before packing, but it is bounded above
     * by — and usually near — the vault's live content. Deliberately
     * conservative when history exceeds live content; the override exists
     * precisely because a proxy can overestimate.
     */
    /**
     * Read compaction's transient-storage arithmetic WITHOUT compacting — the
     * same figures `compact` preflights on, with none of its policy. `repos gc`
     * uses it to disclose headroom on the `--submit` half, where no compaction
     * runs but the numbers are just as worth showing. `null` when the pooled
     * figures cannot be read.
     */
    compactHeadroom(options?: VaultHandleOptions): Promise<VaultCompactHeadroom | null>;
    /**
     * Open this vault's compaction headroom grant directly (vault-checkpoint-cadence
     * design D3) — `compact()` already does this internally; this standalone
     * entry point exists for callers that need to inspect or drive the grant
     * without also running a full compaction cycle (tests; a future
     * operator/diagnostic surface). Throws `VAULT_COMPACTION_GRANT_ACTIVE`
     * (409) verbatim when another compaction already holds this project's
     * grant.
     */
    openCompactionGrant(options?: VaultHandleOptions): Promise<VaultCompactionGrant>;
    /** Close this vault's compaction headroom grant directly — idempotent; `{closed: false}` when nothing was active. */
    closeCompactionGrant(options?: VaultHandleOptions): Promise<{
        closed: boolean;
    }>;
    /**
     * Publish a checkpoint covering the canonical refs, every root unexpired at
     * the cutoff, and the `HEAD` target — under a maintenance lease so a
     * concurrent cycle cannot race it.
     *
     * The lease's `holder_token` is held in memory for the duration and released
     * in a `finally`; it is never returned to the caller, logged, or cached.
     * A repository beyond the V0 checkpoint maximum is refused at preflight with
     * `CHECKPOINT_SET_LIMIT_EXCEEDED`.
     */
    compact(options?: VaultHandleOptions & {
        /** Skip the lease entirely (single-writer situations, tests). */
        lease?: boolean;
        /**
         * The cycle's reservation sizes. Both default to `"0"` — a ZERO
         * reservation, which is honest but not free: the control plane reserves
         * nothing, so a cycle whose objects exceed the (absent) headroom can be
         * refused mid-flight rather than at preflight. Supply real figures once
         * the caller can size the checkpoint it is about to write.
         */
        r1_size_bytes?: string;
        r2_cap_size_bytes?: string;
        /**
         * Proceed even when the transient-storage preflight says the org's
         * pooled tier storage cannot hold both the new checkpoint and the
         * not-yet-pruned history. The platform's own quota enforcement remains
         * the authority either way — this only skips the earlier, more legible
         * refusal. CLI: `--force-headroom`.
         */
        ignoreHeadroom?: boolean;
    }): Promise<VaultCompactResult>;
    /**
     * Plan a prune — and, with both verifier receipts in hand, submit it.
     *
     * TWO PHASES, because the protocol is two-phase (§7.3) and no amount of API
     * sugar can collapse it:
     *
     *   1. `prune()` walks the verified chain, computes the GC root set, subtracts
     *      it from the pruneable universe, and returns a SIGNED
     *      `prune_intent_core` plus its `intent_core_sha256`. Nothing is
     *      submitted and nothing is deleted.
     *   2. Run `r402s-verify` against that core, then call
     *      `prune({ submit: { core, verifier_receipt } })` with the core
     *      ROUND-TRIPPED VERBATIM. This SDK produces its own `run402-cli` receipt
     *      by restoring the latest checkpoint and recomputing its commitments;
     *      the second receipt is `r402s-verify`'s and is never synthesized here,
     *      because two receipts from one lineage prove nothing.
     *
     * The `deleted` list in the result comes from the control-plane-signed
     * completion and nothing else. `present_after_attempt` is a FAILED deletion
     * and is never counted as one.
     */
    prune(options?: VaultHandleOptions & {
        now?: () => Date;
        /**
         * `effective_admitted_at` for a root's drop generation, or `null` when
         * this client cannot resolve it. A `null` RETAINS the root: expiry is
         * permissive, and `effective_admitted_at = max(prepared_at, the admission
         * record's storage creation time)` — deriving it from `prepared_at` alone
         * would SHORTEN the retention lane, which the protocol forbids.
         */
        effective_admitted_at?: (droppedAtGeneration: string) => string | null;
        /**
         * Submit the plan. `core` MUST be the exact object a prior `prune()`
         * returned, and `verifier_receipt` MUST be `r402s-verify`'s receipt over
         * that core's `intent_core_sha256`.
         */
        submit?: {
            core: import("../node/vault-prune.js").VaultPruneIntentCore;
            verifier_receipt: import("../node/vault-prune.js").VaultVerifierReceipt;
            /** Poll budget for the signed completion. Absent ⇒ submit and report the intent without waiting. */
            wait?: {
                attempts?: number;
                interval_ms?: number;
            };
        };
    }): Promise<VaultPruneResult>;
    /**
     * Verify the head chain from the authenticated pin up to the newest listed
     * generation, then return the verified state.
     *
     * Fails closed: a regression below the pin is `GENERATION_REGRESSION`, a gap
     * or bad link is `CHAIN_BROKEN`, an unvalidatable transition descriptor is
     * `UPGRADE_REQUIRED` (read-only past it, never skipped). The verification
     * budget is resumable — a `VERIFICATION_BUDGET_EXCEEDED` client continues
     * from its verified prefix rather than restarting.
     */
    verify(options?: VaultHandleOptions & {
        persist?: boolean;
    }): Promise<VaultVerifiedState>;
    /**
     * `repos fsck` (repo-surface-consolidation D2/D3): walk the head chain
     * AND materialize the ref map, reporting
     * BOTH local trust pins — authenticated and materialized — before and
     * after, with an explicit `local_state_changed` flag. This is the one
     * place chain materialization and pin advance live; `view` never
     * calls it.
     *
     * `options.write` (default `true`) is the inverse of the CLI's
     * `--no-write`: `false` still walks, verifies, and decrypt-validates
     * everything (the returned `refs`/`chain_verified_to_generation`/
     * `decryptable_to_generation` are real, computed answers, not estimates)
     * but persists neither pin — a genuine audit mode, not a simulation.
     * `options.mirror` additionally runs the keyless mirror verification
     * ({@link mirrorVerify}) and folds its report in; that half proves the
     * mirror's validity, never its freshness (its own honesty statements ride
     * the result unchanged).
     *
     * **Request 1 (decrypt-validation, D193-D203 rev 42).** `fsck` walks the
     * chain in TOLERANT decrypt-validation mode
     * (`verifyToNewest({decryptValidate: true, strict: false})`) rather than
     * the ordinary fail-closed `materialize()` — chain/signature verification
     * ALWAYS reaches the true newest generation regardless of decrypt
     * capability (an admitted `rotate_epoch` is keylessly structural), and a
     * generation this call cannot actually DECRYPT is never again reported as
     * bare "verified": `chain_verified_to_generation` and
     * `decryptable_to_generation` are reported separately and can genuinely
     * differ — the incident-shape truth ("chain verified to 10, decryptable
     * to 7, `VAULT_EPOCH_NOT_OPENABLE` at epoch 2/rotation …") is exactly
     * what this split makes representable. `refs`/`head_target`/
     * `pin_after.highest_materialized` all reflect `decryptable_to_generation`.
     *
     * **vault-byo-primary-bucket task 3.3 (design D6).** For a
     * `storage_profile: "byo"` vault, `fsck` ALSO adjudicates the customer's
     * own bucket against run402's signed chain — see {@link
     * #checkByoPresence} for the full contract (automatic, never a flag;
     * fails soft with no local credentials; throws
     * `VAULT_BYO_OBJECT_MISSING` on a confirmed absence). A managed vault
     * is byte-identical to before this task.
     */
    fsck(options?: VaultHandleOptions & {
        write?: boolean;
        mirror?: boolean;
    }): Promise<VaultFsckResult>;
    /**
     * Wrap this vault's current epoch key to every org member who has
     * published an encryption key but has no `key_envelope` on this vault yet
     * — vault-human-envelopes task 4.1's ADD-path workaround. See {@link
     * import("../node/vault-publication.js").Vault.
     * reconcileEnvelopeRecipients} for the full design (TOFU pinning, the
     * gateway `public_key` gap, and why this is a workaround rather than the
     * eventual epoch-rotation design).
     *
     * No CLI verb runs this directly — `repos access` is the inspection
     * read. `deploy()` runs it, best-effort,
     * whenever a deploy lands a new generation in the vault — design D5's
     * "deploy time" hook, "the same 'one command every agent runs' argument
     * that decided deploy-implies-capture." `capture()` (capture-and-publish
     * outside a deploy) runs the identical hook after every successful
     * publish, for the vault-only-project cadence. See
     * `#tryReconcileEnvelopeRecipients` below for both call sites, and
     * {@link Repos.access} for the READ half repo-surface-consolidation
     * ships in its place.
     */
    reconcileEnvelopeRecipients(options?: VaultHandleOptions): Promise<VaultReconcileEnvelopeRecipientsResult>;
    /**
     * vault-multi-writer (task 5.7) — admit every eligible `pending_writers[]`
     * candidate (active org membership at role developer+, a published,
     * possession-verified signing key, not yet in the writer set) via a fresh
     * `add_writer_key{"writer"}` head per candidate. This session's OWN key
     * must already be an active writer — see {@link
     * import("../node/vault-publication.js").Vault.
     * reconcileWriterAdmissions}'s doc comment for why that is checked
     * locally, once, rather than surfaced as N identical gateway refusals.
     *
     * The explicit standalone entry point for the SAME reconcile task 5.7
     * also wires onto session-start/push/snapshot/deploy — calling it here
     * is idempotent-safe alongside whatever `open()` above already ran
     * internally (an already-admitted candidate is simply reported under
     * `already_covered`, never re-admitted), mirroring {@link
     * reconcileEnvelopeRecipients}'s own identical redundancy-tolerant shape.
     */
    reconcile(options?: VaultHandleOptions): Promise<VaultReconcileWriterAdmissionsResult>;
    /**
     * Drive one epoch rotation (D193-D203, rev 42) — the client half of
     * epoch rotation: sample a fresh `K_e`, compute the H-partition from live
     * desired-recipient state + the effective pin manifest, seal one
     * `key_envelope` per included recipient, submit the create-only
     * `rotation_attempt_descriptor`, submit the `rotate_epoch` head, verify
     * this principal's own envelope opens to the committed key (when it is
     * itself a recipient), and advance the local keystore's epoch pointer.
     * See {@link import("../node/vault-publication.js").Vault.
     * rotateEpoch}'s own doc comment for the full obligations and — load-
     * bearing — the confirmed gap in what the gateway exposes for
     * `recipient_state_version`/`recipient_revocation_version` outside the
     * `recipient_key_revoked` reason, and (also load-bearing) `options.
     * pending_confirmations` for folding a receipted `/confirm`/`/repin`
     * result into THIS rotation's head instead of a separately-gated
     * `publishPinManifestUpdate` call.
     */
    rotateEpoch(options: VaultHandleOptions & {
        reason: VaultRotationReason;
        recipient_state_version: string;
        recipient_revocation_version: string;
        client_idempotency_key?: string;
        pending_confirmations?: {
            principal_id: string;
            ek_fingerprint: string;
            receipt: VaultRecipientConfirmationReceipt;
        }[];
    }): Promise<import("../node/vault-publication.js").VaultRotationResult>;
    /**
     * The ONE fully self-contained rotation entry point: declares
     * `reason:"recipient_key_revoked"` for `principalId` (owner + step-up)
     * and drives the rotation from that call's OWN returned counters — no
     * external counter source needed. The rekey remedy for the exact witness
     * task 5.0 records: a specific member's key is compromised/should no
     * longer be trusted.
     */
    /**
     * The writer-capable rotation that completes an org membership removal
     * (`reason:"member_removed"`, vault-multi-writer D6): counters come off
     * the envelope-recipients read, no declaration, no owner step-up — any
     * surviving writer can run it. `capture()` runs it automatically when the
     * gate names an outstanding removal; this is the explicit entry point
     * (`run402 orgs members rm` drives it on every vault the caller can).
     */
    rotateEpochForMemberRemoval(options?: VaultHandleOptions & {
        client_idempotency_key?: string;
    }): Promise<import("../node/vault-publication.js").VaultRotationResult>;
    rotateEpochForKeyRevocation(principalId: string, options?: VaultHandleOptions & {
        client_idempotency_key?: string;
    }): Promise<import("../node/vault-publication.js").VaultRotationResult>;
    /**
     * Publish a receipted `recipient_pin_manifest` update (D197) — the
     * publication half of the `/confirm`/`/repin` ceremonies above. Call
     * after {@link confirmRecipient}/{@link repinRecipient} returns a receipt;
     * this is `gitvault.writer`-sufficient (the owner-gated half already
     * happened at the ceremony route).
     *
     * **This publish is an ORDINARY admission** and is therefore itself
     * refused `EPOCH_ROTATION_REQUIRED` while this vault has a migration/
     * revocation/exposure condition outstanding (D193).
     * `#enrichEpochRotationRequiredForPinManifest`
     * below decorates that refusal with the remedy: fold the SAME receipt
     * into `rotateEpoch({..., pending_confirmations: [...]})` instead, which
     * durably publishes it on a `rotate_epoch` admission (the gate's own
     * escape valve) rather than a separately-gated ordinary one.
     */
    publishPinManifestUpdate(input: {
        principal_id: string;
        ek_fingerprint: string;
        receipt: VaultRecipientConfirmationReceipt;
    } & VaultHandleOptions): Promise<import("../node/vault-publication.js").VaultPublishResult>;
    /**
     * `repos access` (repo-surface-consolidation D5/D10) — a READ-ONLY report
     * of who can open this vault, composed from whatever the live gateway
     * surface exposes today. Never wraps, never mutates a `key_envelope` —
     * that mutating half stays {@link reconcileEnvelopeRecipients}, reachable
     * only through the deploy/push best-effort hooks until `access repair`
     * ships (gated on `vault-human-envelopes`' epoch-rotation work). See
     * {@link VaultAccessResult}'s doc comment for the honest gap this
     * reports rather than invents.
     */
    access(options?: VaultHandleOptions): Promise<VaultAccessResult>;
    /**
     * The vault-gated deploy: both lanes under one fresh `capture_id`, resolving
     * to exactly one of five outcomes — `DEPLOYED_AND_VAULTED`,
     * `DEPLOY_BLOCKED_PUSH_FAILED`, `DEPLOY_FAILED_VAULTED`,
     * `DEPLOY_FAILED_UNVAULTED`, `DEPLOYED_UNVAULTED_OVERRIDE`.
     *
     * The push is never gated on deploy success, and a build that fails before a
     * canonical apply plan exists still captures (with a null plan digest, so no
     * activation token can be minted from it).
     *
     * `run402 deploy` is design D5's PRIMARY envelope-recipient reconcile hook
     * ("the same 'one command every agent runs' argument that decided
     * deploy-implies-capture") and design D6's primary mirror-write trigger
     * — both fire HERE, not inside {@link runVaultDeploy} itself, mirroring
     * {@link capture}'s exact non-blocking contract: best-effort, NEVER throw,
     * NEVER alter the deploy outcome already resolved above, reported BESIDE it
     * on `mirror_push` / `reconcile_recipients`. They fire only when this
     * deploy actually landed a new generation in the vault
     * (`DEPLOYED_AND_VAULTED` / `DEPLOY_FAILED_VAULTED` — the outcomes carrying
     * a `generation`); the other three outcomes published nothing new, so
     * there is nothing to mirror or reconcile against ({@link
     * import("../node/vault-mirror.js").mirrorPushForGeneration}'s own
     * contract: "fires after an ordinary vault push/deploy produces a new
     * generation"). Both fields are therefore OMITTED — never a faked
     * `skipped_*` outcome — when no generation landed.
     */
    deploy(options: Omit<VaultDeployOptions, "vault"> & VaultHandleOptions): Promise<VaultDeployResult & {
        mirror_push?: VaultMirrorPushResult;
        byo_chain_copy?: VaultMirrorPushResult;
        reconcile_recipients?: VaultReconcileEnvelopeRecipientsPushResult;
        writer_reconcile?: VaultReconcileWriterAdmissionsPushResult;
    }>;
    /**
     * Drain every unvaulted-override journal on this machine: push the exact
     * journaled snapshot and present the capture receipt for full-field
     * comparison. A partial match never clears the advisory.
     */
    drainOverrides(options?: VaultHandleOptions): Promise<import("../node/vault-deploy.js").VaultOverrideDrainReport>;
    /**
     * Reproduce the vault's object database into a git repository — the clone-back
     * path. Needs only git and a surviving keystore: no deployment artifact, CAS
     * entry, or apply operation is consulted.
     */
    restore(options: VaultHandleOptions & {
        target_dir: string;
    }): Promise<{
        refs: Record<string, string>;
        generation: string;
        retained_refs: import("../node/vault-publication.js").VaultRetainedRefsReconcileResult;
    }>;
    /**
     * Wrap an ALREADY-RESOLVED vault read with degraded-read fallback: run
     * `options.attemptLive` (the caller's own live call — its
     * `vault.materialize()` for a `list`-shaped read, or
     * `vault.restoreObjectsInto(dir)` for a `fetch`-shaped one), and on a
     * network-class failure (never on an authorization refusal or any other
     * 4xx — see `isNetworkClassVaultReadError`), fall back to the vault's
     * configured mirror via the SAME `r402s-recover` engine `recover()` uses.
     *
     * Deliberately takes an already-open `vault`/`keystore`/`repo_id` rather
     * than resolving them itself: named-address resolution (slug-form vs.
     * id-form), stale-pin recovery, and cross-command vault-instance reuse
     * within one `git-remote-run402` session are CLI-layer concerns that
     * already live in `cli/lib/remote-helper-session.mjs` — this method owns
     * only the trigger discipline and the fallback engine, never vault
     * resolution, so it composes with that existing flow instead of
     * duplicating it.
     *
     * `out_dir` is REQUIRED for the fallback to ever run — pass the resolved,
     * git-proven repository directory (`resolveGitInvocationRepo`'s own
     * `repo_dir`, never a guess from `cwd`). `null` (no resolvable repository,
     * e.g. a bare `git ls-remote` outside any checkout) disables the fallback
     * entirely: the original gateway error surfaces exactly as it always did.
     */
    withDegradedRead<T extends VaultDegradedReadLive>(options: {
        attemptLive: () => Promise<T>;
        keystore: VaultKeystore;
        repo_id: string;
        out_dir: string | null;
    }): Promise<VaultDegradedReadOutcome<T>>;
    /**
     * vault-byo-primary-bucket (design D4): the degraded read for the OPEN
     * itself. {@link withDegradedRead} wraps a handle's live read, but a plain
     * `git fetch`/`clone` needs the gateway once BEFORE any read — to open the
     * handle (enrollment, the vault record). When that open fails
     * network-class and this checkout already knows the vault — a pinned
     * `repo_id`, or the keystore's own project→repo file for an id-form
     * address (vault-offline-clone-resolve) — the whole read is served from
     * the vault's BYO destination or configured mirror, exactly as
     * `withDegradedRead` would have after a failed live read. `null` when this
     * cannot help (a non-network failure, no local identity for the vault, no
     * local copy source), so the caller rethrows its ORIGINAL error unchanged.
     * Writes are never rerouted.
     */
    degradedOpenFallback(input: {
        repo_dir: string;
        error: unknown;
        address?: import("../node/vault-address.js").ResolveVaultAddressOptions["address"];
        repo_id?: string;
    }): Promise<VaultDegradedReadOutcome<VaultDegradedReadLive> | null>;
    /**
     * Configure (or replace) the customer-owned mirror destination for one
     * vault. Client-side ONLY — the destination + credential NAME are written
     * beside the keystore (design D2); run402 never sees or stores a raw
     * secret value. `s3://<bucket>/<prefix>` needs `credential`; a plain
     * filesystem path needs none.
     */
    mirrorSet(options: VaultHandleOptions & {
        destination_url: string;
        credential?: VaultMirrorCredential;
        region?: string;
        endpoint?: string;
    }): Promise<VaultMirrorConfig>;
    /** Remove the mirror config for one vault. Never touches the mirror's own bytes (design: config removal ≠ data deletion). */
    mirrorRemove(options?: VaultHandleOptions): Promise<{
        repo_id: string;
        removed: boolean;
    }>;
    /**
     * What this machine and the mirror each believe: whether a mirror is
     * configured, the newest generation the MIRROR holds and can chain-verify
     * (keyless — never touches keys), the LIVE vault's newest generation (one
     * read of the vault record), and — when they disagree — the closing
     * command. Both honesty statements (design D8) ride every response.
     */
    mirrorStatus(options?: VaultHandleOptions & {
        is_byo?: boolean;
    }): Promise<VaultMirrorStatus>;
    /** List the vault's stored objects, diff against the mirror, fetch + hash-verify + write what's missing, in admission order. Resumable and idempotent. */
    mirrorSync(options?: VaultHandleOptions): Promise<VaultMirrorSyncSummary>;
    /** Keyless integrity probe against the CONFIGURED mirror: discovery + chain verification + closure/absence adjudication, never decryption (`run402 repos fsck --mirror`). */
    mirrorVerify(options?: VaultHandleOptions): Promise<VaultVerifyReport>;
    /**
     * `r402s-recover` (design D4): rebuild a working git repository straight
     * from a mirrored `source/<repo_id>/` prefix — NO SERVER INVOLVED. `source`
     * is `s3://<bucket>[/<prefix>]` or a local directory; when it names more
     * than one mirrored vault, pass `repo_id` explicitly. Recovery proves
     * validity, never freshness (both honesty statements ride every result).
     *
     * vault-recovery-custody: a human member with no keystore recovers with
     * `member_bundle` (the exported `r402s-member-recovery-bundle/v1`, or the
     * mirror's own `member-recovery-bundles/` sidecar when omitted) +
     * `source_recovery_code`; a raw WebAuthn PRF output is NOT a supported
     * input. The recovery-receipt pin stays the trust anchor either way —
     * pass `recovery_receipt` when there is no keystore holding one.
     */
    recover(options: {
        source: string;
        out_dir: string;
        repo_id?: string;
        credential?: VaultMirrorCredential;
        region?: string;
        endpoint?: string;
        recovery_receipt?: VaultRecoveryReceipt;
        keystore_root?: string;
        member_bundle?: VaultMemberRecoveryBundle;
        source_recovery_code?: string;
        rp_id?: string;
    }): Promise<VaultRecoverResult>;
    /**
     * Re-apply the local immutable-object cache's eviction window (design D3,
     * task 4.2) for one vault — a periodic backstop wired into `run402 repos
     * gc`, catching any orphaned cache file a crashed write might have left
     * behind. Purely local: no network call beyond resolving `repo_id` when
     * only `project_id` was supplied. Idempotent and safe to call on a repo
     * with no cache directory at all (a no-op).
     */
    sweepObjectCache(options: VaultHandleOptions): Promise<void>;
}
/**
 * The composite escalation trigger (design D7): ANY of these crossing its
 * threshold escalates the quiet genesis-time note into a standing warning.
 * Deliberately an OR — any single metric alone is gameable by triviality
 * (an agent that pads one dimension to stay under a lone threshold). Shipped
 * as defaults; tunable in this ONE place, not a protocol contract.
 */
export declare const VAULT_LOSS_WARNING_THRESHOLDS: {
    readonly generations: 10;
    readonly source_bytes: number;
    readonly days_since_genesis: 14;
};
/**
 * vault-clone-scaling (bench P3): generations-since-checkpoint at or
 * above this advises `run402 repos gc`. Same one-place-to-tune convention
 * as {@link VAULT_LOSS_WARNING_THRESHOLDS}; an advisory, never a gate.
 */
export declare const VAULT_CHECKPOINT_ADVISORY_GENERATIONS = 25;
/** {@link vaultCheckpointStaleness}'s result. */
export interface VaultCheckpointStaleness {
    generations_since_checkpoint: number;
    advised: boolean;
}
/**
 * Pure staleness computation over two 16-hex generations. TOTAL: garbage
 * or unknown coverage (`null`) yields `{0, advised: false}` — advisory
 * call sites must never be able to break a verb, so unparseable input is
 * silence, not an error. Coverage `null` means "this checkout has not
 * locally learned the vault's checkpoint coverage" (see the keystore's
 * `checkpoint_covers_through` doc), which is deliberately indistinguishable
 * from fresh here.
 */
export declare function vaultCheckpointStaleness(input: {
    newest_generation: string;
    covers_through_generation: string | null;
}): VaultCheckpointStaleness;
/** Which composite metric(s) crossed their D7 threshold, if any. */
export interface VaultLossWarningTrip {
    generations: boolean;
    source_bytes: boolean;
    days_since_genesis: boolean;
}
/**
 * D7: has this vault crossed the composite terminal-loss escalation trigger?
 * Pure — no I/O, no clock dependency beyond the optional `now` override
 * (tests). `admitted_generations` and `storage.source_bytes` are decimal
 * strings (protocol convention for values that could exceed safe-integer
 * precision in principle; comfortably within it here).
 *
 * There is deliberately no companion "is this resolved" function on the
 * TRIP computation itself: whether the generations/bytes/days thresholds
 * crossed is independent of how many principals cover the vault, and this
 * function stays a pure threshold check forever — a caller does not un-trip
 * it, ever, in V0. What DOES now exist, one call site up in `status()`, is a
 * way to downgrade the COPY once tripped: a locally-provable read of the
 * vault's covering-recipient count (the same envelope-recipients read
 * `Repos.access` uses) can show this is no longer the single-principal
 * case the message below describes. See
 * {@link vaultKeystoreBackupReminderMessage} for that downgraded form.
 */
export declare function vaultLossWarningTrip(record: Pick<VaultRecord, "admitted_generations" | "storage" | "genesis_admitted_at">, now?: Date): VaultLossWarningTrip;
/** Any composite metric tripped — the standing warning threshold itself. */
export declare function vaultLossWarningTripped(trip: VaultLossWarningTrip): boolean;
/**
 * The standing warning text (design D7): names what tripped, states the
 * resolution honestly (a second principal or human envelope — nothing this
 * client can verify yet), and never claims an attestation would clear it.
 *
 * This is the SINGLE-PRINCIPAL form — use it only when the vault's
 * covering-recipient count is unknown or <= 1. Once a caller has locally
 * proven >= 2 covering recipients, its premise ("only one principal can open
 * it") is false; use {@link vaultKeystoreBackupReminderMessage} instead.
 */
export declare function vaultLossWarningMessage(trip: VaultLossWarningTrip): string;
/**
 * D7's downgraded form (dogfood item 2): once `status()` has locally proven
 * this vault carries >= 2 covering recipients (via the same envelope-recipients
 * read `Repos.access` uses), the single-principal premise behind
 * {@link vaultLossWarningMessage} is false for THIS vault — printing it
 * anyway would be a false terminal-loss claim. The composite threshold still
 * fires the SAME way (this function does not touch `vaultLossWarningTrip`/
 * `vaultLossWarningTripped` at all — a real value-at-risk signal is still
 * worth a reminder), but the copy switches to the protocol's own
 * keystore-qualified durability sentence instead of asserting single-principal
 * risk, and never claims terminal loss.
 */
export declare function vaultKeystoreBackupReminderMessage(trip: VaultLossWarningTrip, coveringRecipients: number): string;
/**
 * vault-mirror-default — the pure `vault_unmirrored` computation, in ONE
 * place so doctor and `repos view` echo the same finding instead of each
 * deriving their own (the loss-warning pattern above). Present when no mirror
 * is configured, OR when one is configured but has no success evidence yet —
 * either the local `last_success_at` stamp (survives a transiently unreachable
 * mirror) or a chain-verified `mirrored_generation` read from the mirror
 * itself (covers mirrors synced before the stamp existed). Informational,
 * never blocking; every input is client-local or read from the CUSTOMER'S
 * mirror — nothing here touches the gateway.
 */
export declare function vaultUnmirroredFinding(state: {
    configured: boolean;
    last_success_at: string | null;
    mirrored_generation: string | null;
    /** vault-byo-primary-bucket task 3.5 — when true, `message` uses the BYO remedy wording (a SECOND customer-held location) instead of the plain unmirrored statement. */
    is_byo?: boolean;
}): VaultUnmirroredFinding | null;
/**
 * vault-byo-primary-bucket (design D4) — the ONE stderr line a degraded
 * chain/payload read prints: the fallback's own destination (never a
 * credential) plus the canonical, mechanism-only statement. `list`/`fetch`
 * degrading in the SAME `git-remote-run402` session each print their own
 * line (one per degraded READ, not one per session) — see
 * `Repos.withDegradedRead`'s own doc comment.
 */
export declare function vaultDegradedReadNote(source: VaultDegradedReadSource): string;
/** `run402::<org_id>/<project_id>` — what `git-remote-run402` resolves. */
export declare function vaultRemoteUrl(orgId: string, projectId: string): string;
/**
 * `run402::<org-slug>/<repo-name>` — the address-form remote builder
 * (repo-first-onramp task 4, design D6). Same string shape as
 * {@link vaultRemoteUrl} (the wire slot admits both forms undiscriminated
 * — see {@link vaultRemoteAddressForm}); kept as its own named function so
 * a call site states which form it means rather than reusing the id-form
 * builder for a semantically different pair of arguments.
 */
export declare function vaultRemoteUrlForRepo(orgSlug: string, repoName: string): string;
/** What {@link parseVaultRemoteUrl} returns — the two undiscriminated address halves. */
export interface VaultRemoteAddress {
    org_id: string;
    project_id: string;
}
/**
 * Parse a `run402::<org>/<project>` remote URL into its two address halves.
 * `run402::` is the one remote scheme: `null` for anything that is not a
 * `<scheme>::` address at all, and a typed `REMOTE_SCHEME_UNSUPPORTED`
 * refusal naming the scheme for any other `<scheme>::` spelling.
 */
export declare function parseVaultRemoteUrl(url: string): VaultRemoteAddress | null;
/** Which address form a parsed `run402::` remote is (repo-first-onramp task 4, design D6). */
export type VaultRemoteAddressForm = "id" | "slug";
/**
 * Discriminate a parsed address's form (design D6, "resolved"): "org UUIDs
 * and `prj_` prefixes make slug-vs-id in the same slot unambiguous." Both
 * halves must look id-shaped for the address to be treated as id-form — a
 * genuine `run402::<org_uuid>/<prj_id>` address always satisfies both at
 * once, since real org ids are UUIDs and real project ids are always
 * `prj_`-prefixed; anything else (an org slug half, or a bare repo-name half)
 * is slug-form. Resolution accepts either (task 4.3).
 */
export declare function vaultRemoteAddressForm(address: VaultRemoteAddress): VaultRemoteAddressForm;
/** What a `SLUG_RELEASED` refusal names — the successor slug and the cooldown window (design D6). */
export interface VaultSlugReleasedInfo {
    successor_slug: string | null;
    released_at: string | null;
    cooldown_until: string | null;
}
/**
 * `SLUG_RELEASED` (a renamed/deleted org slug, still inside its ~90-day
 * cooldown) surfaces as a typed, actionable fact — NEVER auto-followed
 * (design D6: "no redirects, deliberately"). `null` when `err` is not a
 * `SLUG_RELEASED` refusal.
 */
export declare function vaultSlugReleasedInfo(err: unknown): VaultSlugReleasedInfo | null;
//# sourceMappingURL=repos.d.ts.map