/**
 * Shape of persisted cloud session credentials.
 *
 * Per anti-pattern guidance: stores the bearer token (not the secret).
 * The secret is only used during create/join -- the token authenticates
 * subsequent requests.
 */
export interface PersistedCredentials {
    endpoint: string;
    /**
     * The token that OWNS this cwd's peer, when it differs from `token`.
     *
     * 🔴 A re-join issues a NEW token, and AUD-003 ownership is proven by the token that CREATED the
     * peer (or by its peerSecret). Clients before 3.23.5 destroyed the peerSecret on re-join, so
     * their only remaining proof is the previous token — and overwriting `token` threw that away too,
     * leaving the agent permanently locked out of its own peerId. Keeping the prior token here lets
     * register-peer re-prove ownership INSTANTLY instead of waiting out the relay's 30-minute
     * abandoned-peer window.
     */
    ownerToken?: string;
    sessionId: string;
    token: string;
    label?: string;
    /**
     * peerId of the registered peer for this cwd. Local-only; lets the Stop hook
     * (check-on-stop, a separate process) identify "me" without re-deriving it,
     * so it can filter directed-to-me messages and set the poll's peerId. Optional
     * for back-compat: credentials written before 3.12.2 (or by create/join before
     * a register) omit it, and the hook falls back to the state file.
     */
    peerId?: string;
    /**
     * AUD-003 peer-ownership credential, issued once by the relay when this peer was first
     * registered.
     *
     * WHY IT MUST BE PERSISTED: a peer is owned by the token that created it, and re-joining a
     * channel issues a NEW token. Without this secret an agent that re-joins can never re-register
     * its own peerId again — it would be locked out of its own identity by the very check that
     * protects it. Stored here (0600, same file as the bearer token, same threat model) and replayed
     * on register.
     *
     * Optional: absent for peers created before ownership existed, and absent on the common path
     * where the token has not changed.
     */
    peerSecret?: string;
    /**
     * COG-80: which agent registered this peer — the session id the register was given (a Claude
     * session id, a Codex thread id) and COGENT_PLATFORM ("cc", "codex"). Written on per-peer records
     * (and the folder file) by 3.25.9+; absent before.
     */
    agentSession?: string;
    platform?: string;
    /**
     * COG-80: every peer registered in this folder, keyed by peerId — its own channel connection,
     * ownership proof and agent. The top-level fields above still name the LAST-registered peer (the
     * Stop hooks, watch and mail read them). One file, one write: the map can never disagree with them.
     */
    peers?: Record<string, PeerEntry>;
    savedAt: string;
}
/** One peer's saved identity inside the folder file (COG-80). */
export type PeerEntry = Omit<PersistedCredentials, "peers" | "peerId">;
/**
 * Legacy global credential file used by cogent-bridge < 3.1.8.
 * A single file shared across every CC session on the host -- which is
 * exactly the cross-cwd "credential bleed" bug 3.1.8 fixes.  Kept here
 * as a constant so startup can detect-and-warn on upgrade.
 */
export declare const LEGACY_GLOBAL_CREDENTIAL_PATH: string;
/**
 * Resolve the credential path with the override hierarchy:
 *   1. explicit `credentialPath` arg          (tests, advanced users)
 *   2. process.env.COGENT_CREDENTIALS_FILE    (operators with custom paths)
 *   3. defaultCredentialPath(process.cwd())   (per-cwd, the new default)
 */
export declare function resolveCredentialPath(credentialPath?: string): string;
export declare function markJoinedInProcess(): void;
export declare function hasJoinedInProcess(): boolean;
/**
 * Test-only reset hook. Production code should never call this.
 */
export declare function __resetJoinedInProcessForTests(): void;
export declare function markCloudAttemptInProcess(): void;
export declare function getCloudAttemptGeneration(): number;
/**
 * Run `fn` whenever a join/create starts. Lets startup.ts cancel a pending presence retry without
 * the tools importing startup.ts (that import cycle reads back `undefined` — see peer-presence.ts).
 */
export declare function onCloudAttemptInProcess(fn: () => void): () => void;
export declare function hasCloudAttemptInProcess(): boolean;
/**
 * Test-only reset hook. Production code should never call this.
 */
export declare function __resetCloudAttemptInProcessForTests(): void;
/**
 * Load persisted credentials from disk.
 * Returns null on any error (file not found, JSON parse failure, etc.).
 */
export declare function loadCredentials(credentialPath?: string): Promise<PersistedCredentials | null>;
/**
 * Save credentials to disk as pretty-printed JSON.
 * Creates the parent directory if it does not exist.
 */
export declare function saveCredentials(creds: PersistedCredentials, credentialPath?: string): Promise<void>;
/**
 * Persist a peerSecret the relay just issued for `peerId` in `sessionId`.
 *
 * 🔴 The relay returns a secret only when it MINTS one (the peer was created, re-created after an
 * eviction, or adopted) and never again. Every register path must keep it: the self-heal
 * re-registration and the startup presence restore used to discard it, so the next re-join (a new
 * token) left the agent holding a dead secret and PEER_NOT_YOURS forever (klaire-frontend,
 * 2026-09-30). Credentials for another channel are left alone.
 */
export declare function rememberIssuedPeerSecret(sessionId: string, peerId: string, peerSecret: string): Promise<void>;
export declare function setCurrentCloudConnection(c: {
    endpoint: string;
    sessionId: string;
    token: string;
} | null): void;
export declare function getCurrentCloudConnection(): {
    endpoint: string;
    sessionId: string;
    token: string;
} | null;
/** A peer's saved identity: the top-level fields when they name it (always the newest), else its entry. */
export declare function peerCredentials(folder: PersistedCredentials | null, peerId: string): PersistedCredentials | null;
/** Every peer saved in this folder, one record each (entries; plus the top-level peer if it has none). */
export declare function peerRecordsOf(folder: PersistedCredentials | null): PersistedCredentials[];
export declare function loadPeerRecord(peerId: string, credentialPath?: string): Promise<PersistedCredentials | null>;
export declare function loadPeerRecords(credentialPath?: string): Promise<PersistedCredentials[]>;
/** Write `rec` as this peer's entry, leaving the top-level fields and every other entry as they are. */
export declare function savePeerRecord(rec: PersistedCredentials & {
    peerId: string;
}, credentialPath?: string): Promise<void>;
export declare function deletePeerRecord(peerId: string, credentialPath?: string): Promise<void>;
/**
 * Which saved identity a bridge starting in this folder may restore (COG-80).
 *
 *  - No per-peer records yet (a folder last registered before 3.25.9): the folder file, as before.
 *  - The record whose agentSession is this bridge's own session (Claude Code passes it at start).
 *  - Otherwise the ONE record written by an agent of this bridge's platform: Codex passes no session
 *    at start, and a Claude session id changes on /clear. Never another platform's record — that is
 *    the KLAIRE failure, a Claude bridge coming back as the Codex agent.
 *  - Two or more candidates and no session match: nothing. Guessing would hand one agent the other's
 *    name; the agent registers its name explicitly instead (skip says which names were seen).
 */
export declare function chooseRestoreCredentials(folder: PersistedCredentials | null, records: PersistedCredentials[], ownSession: string | undefined, platform: string): {
    creds: PersistedCredentials | null;
    skip?: string;
};
/**
 * Delete the credential file from disk.
 * Silently ignores ENOENT (file already absent).
 */
export declare function clearCredentials(credentialPath?: string): Promise<void>;
/**
 * Detect whether the legacy global credential file exists. Used by startup
 * to warn the operator about the path migration on first run after upgrade.
 */
export declare function legacyGlobalCredentialsExist(): Promise<boolean>;
//# sourceMappingURL=credential-store.d.ts.map