/** * Renaissance Correspondence — signed, replayable coordination between agents. * * The signed event names its device and session explicitly. This module never * derives either value from the host, process, environment, or another ambient * telemetry source. Claims are expiring courtesy notices, not locks, ownership, * or delegated authority. * * Canonical bytes and event IDs implement the bounded I-JSON profile accepted * by `agent-correspondence/v0.1`: strings, booleans, null, arrays, objects, and * safe integers. That admitted subset is serialized as RFC 8785 JCS. Floats, * non-finite numbers, unsafe integers, undefined values, lone UTF-16 * surrogates, and U+0000 in strings or property names are rejected locally. * * Receive side: every record returned by `list`, `replay`, and `voice` carries * an explicit `verification`. Authorship is proved only by * `verifyCorrespondenceSignature` against an Ed25519 public key the caller * already holds for the sender. The default is fail-open-but-loud: with no key * for a sender the record still arrives, marked `verified: false` with reason * `no_verifying_key`, because a reader that cannot resolve a key must still be * able to see that an event exists. Pass `require_verified: true` to fail * closed and refuse the page instead. */ import { type HttpConfig } from "./_http.js"; export declare const CORRESPONDENCE_PROTOCOL: "agent-correspondence/v0.1"; export declare const CORRESPONDENCE_SIGNATURE_ALGORITHM: "Ed25519"; export declare const CORRESPONDENCE_KINDS: readonly ["intent", "claim.open", "claim.renew", "claim.release", "progress", "observation", "artifact.offer", "ack.seen", "ack.understood", "ack.accepted", "ack.applied", "ack.rejected", "conflict.raise", "conflict.resolve", "pause", "rest", "resume", "refusal", "handoff", "close", "repair"]; export type CorrespondenceKind = (typeof CORRESPONDENCE_KINDS)[number]; export type CorrespondenceJsonValue = null | boolean | string | number | CorrespondenceJsonValue[] | { [key: string]: CorrespondenceJsonValue; }; export interface CorrespondenceSender { identity_id: string; signing_key_id: string; /** Caller-chosen UUID. The SDK never reads a hardware identifier. */ device_id: string; /** Caller-chosen UUID. The SDK never reads a process or runtime session. */ session_id: string; } export interface CorrespondenceScope { base_revision: string | null; branch: string | null; /** Normalized repository-relative prefixes. `.` means the whole repo. */ paths: string[]; } export interface CorrespondenceAuthority { automatic_action: "never"; grants: []; } export interface CorrespondenceSummaryBody { summary: string; } export interface CorrespondenceClaimOpenBody { claim_id: string; generation: 1; expires_at: string; } export interface CorrespondenceClaimRenewBody { claim_id: string; generation: number; predecessor_event_id: string; expires_at: string; } export interface CorrespondenceClaimReleaseBody { claim_id: string; generation: number; predecessor_event_id: string; detail?: string; } export type CorrespondenceArtifact = { kind: "git_commit"; revision: string; } | { kind: "git_patch" | "content_digest"; digest: string; locator?: string; }; export interface CorrespondenceArtifactOfferBody { artifact: CorrespondenceArtifact; summary?: string; } export interface CorrespondenceAckBody { target_event_id: string; detail?: string; } export interface CorrespondenceAckAppliedBody extends CorrespondenceAckBody { result_revision: string; } export interface CorrespondenceConflictRaiseBody { target_event_ids: string[]; summary?: string; } export interface CorrespondenceResolutionBody { target_event_ids: string[]; summary: string; result_revision?: string; } export interface CorrespondencePauseBody { until?: string | null; detail?: string; } export interface CorrespondenceTargetBody { target_event_id: string; detail?: string; } export interface CorrespondenceRefusalBody { target_event_id?: string; detail?: string; } export interface CorrespondenceHandoffBody { summary: string; next_safe_action: string; /** Optional locator only; it does not import the handoff's authority. */ handoff_id?: string; } export interface CorrespondenceCloseBody { summary?: string; } export interface CorrespondenceBodyByKind { intent: CorrespondenceSummaryBody; "claim.open": CorrespondenceClaimOpenBody; "claim.renew": CorrespondenceClaimRenewBody; "claim.release": CorrespondenceClaimReleaseBody; progress: CorrespondenceSummaryBody; observation: CorrespondenceSummaryBody; "artifact.offer": CorrespondenceArtifactOfferBody; "ack.seen": CorrespondenceAckBody; "ack.understood": CorrespondenceAckBody; "ack.accepted": CorrespondenceAckBody; "ack.applied": CorrespondenceAckAppliedBody; "ack.rejected": CorrespondenceAckBody; "conflict.raise": CorrespondenceConflictRaiseBody; "conflict.resolve": CorrespondenceResolutionBody; pause: CorrespondencePauseBody; rest: CorrespondencePauseBody; resume: CorrespondenceTargetBody; refusal: CorrespondenceRefusalBody; handoff: CorrespondenceHandoffBody; close: CorrespondenceCloseBody; repair: CorrespondenceResolutionBody; } interface CorrespondenceEventBase { protocol: typeof CORRESPONDENCE_PROTOCOL; project_id: string; repository_id: string; thread_id: string; sender: CorrespondenceSender; parents: string[]; session_seq: number; issued_at: string; scope: CorrespondenceScope; authority: CorrespondenceAuthority; } export type CorrespondenceEventCore = { [K in CorrespondenceKind]: CorrespondenceEventBase & { kind: K; body: CorrespondenceBodyByKind[K]; }; }[CorrespondenceKind]; export interface CorrespondenceSignature { algorithm: typeof CORRESPONDENCE_SIGNATURE_ALGORITHM; value_b64url: string; } export type CorrespondenceSignedEvent = CorrespondenceEventCore & { event_id: string; signature: CorrespondenceSignature; }; export type CorrespondenceUnsignedInput = { [K in CorrespondenceKind]: Omit & { kind: K; body: CorrespondenceBodyByKind[K]; }; }[CorrespondenceKind]; export type CorrespondenceAppendOptions = CorrespondenceUnsignedInput & { /** Caller-held 32-byte Ed25519 seed, raw or canonical standard base64. * It is used locally and never sent. */ signing_key: Uint8Array | string; }; export interface CorrespondenceReceipt { /** Canonical decimal string; project-local monotone receipt order, gaps allowed. */ received_seq: string; received_at: string; } export interface CorrespondenceEventRecord { event: CorrespondenceSignedEvent; receipt: CorrespondenceReceipt; missing_parents: string[]; /** Server projection state. Receipt order is not causal or wall-clock proof. */ lineage_status: "not_applicable" | "valid" | "pending" | "invalid"; } /** Caller-held Ed25519 public key: raw 32 bytes, standard base64, or base64url. */ export type CorrespondenceVerifyingKey = Uint8Array | string; export type CorrespondenceSigningKeyResolver = (signingKeyId: string, event: CorrespondenceSignedEvent) => CorrespondenceVerifyingKey | undefined | Promise; export type CorrespondenceVerificationReason = "verified" /** No caller-held key for this signer; authorship is unproved, not disproved. */ | "no_verifying_key" | "signature_mismatch" | "event_id_mismatch" | "malformed_event"; export interface CorrespondenceVerification { verified: boolean; reason: CorrespondenceVerificationReason; /** `sender.signing_key_id` a caller must resolve a public key for. */ signing_key_id: string; detail?: string; } export interface CorrespondenceVerifyOptions { /** * Caller-held Ed25519 public keys indexed by `sender.signing_key_id`. * * These must come from the reader's own record of the sender. Never feed a * key carried by the same response that carried the event: whoever served * the event would then also choose the key that "verifies" it, and the check * would prove nothing. Do not "simplify" this by reading a key off the wire. */ signing_keys?: Readonly> | ReadonlyMap; /** Async-capable resolver for keychain- or directory-backed signer keys. */ resolve_signing_key?: CorrespondenceSigningKeyResolver; /** Fail closed: refuse the read instead of returning an unverified record. */ require_verified?: boolean; } /** An event record with the reader's own local verdict attached. */ export interface CorrespondenceVerifiedEventRecord extends CorrespondenceEventRecord { verification: CorrespondenceVerification; } export interface CorrespondenceWarning { code: "session_fork" | "claim_lineage_pending"; detail: string; event_ids?: string[]; paths?: string[]; } export interface CorrespondenceAppendResponse extends CorrespondenceEventRecord { /** Advisory, current-at-write observations. Not part of the signed event. */ warnings: CorrespondenceWarning[]; } export interface CorrespondenceListOptions extends CorrespondenceVerifyOptions { repository_id: string; thread_id?: string; /** Exclusive project-local receipt cursor, kept as a decimal string. */ after?: string; limit?: number; } export interface CorrespondenceEventsPage { protocol: typeof CORRESPONDENCE_PROTOCOL; scope: "project_private"; events: CorrespondenceVerifiedEventRecord[]; page: { after: string | null; next_after: string | null; has_more: boolean; }; } /** One surviving active claim branch tip. Multiple tips may coexist. */ export interface CorrespondenceActiveClaim { claim_id: string; generation: number; event_id: string; owner_identity_id: string; device_id: string; session_id: string; thread_id: string; scope: CorrespondenceScope; expires_at: string; conflicted: boolean; /** Up to 16 other valid branch tips, including inactive/released tips. */ competing_event_ids: string[]; } export interface CorrespondenceClaimsResponse { protocol: typeof CORRESPONDENCE_PROTOCOL; scope: "project_private"; evaluated_at: string; cursor: string | null; projection_status: "complete" | "truncated" | "unavailable"; truncated: boolean; claims: CorrespondenceActiveClaim[]; } export interface CorrespondenceClaimsOptions { repository_id: string; thread_id?: string; /** Optional normalized path prefix used to narrow overlap projection. */ path?: string; } export interface CorrespondenceMissingParentsConflict { event_id: string; missing_parent_ids: string[]; } export interface CorrespondenceSessionForkConflict { identity_id: string; device_id: string; session_id: string; session_seq: number; event_ids: string[]; } export interface CorrespondenceOverlappingClaimsConflict { left_event_id: string; right_event_id: string; paths: string[]; } export interface CorrespondenceVoiceOptions extends CorrespondenceVerifyOptions { repository_id: string; thread_id?: string; } export interface CorrespondenceVoiceConflicts { missing_parents: CorrespondenceMissingParentsConflict[]; session_forks: CorrespondenceSessionForkConflict[]; overlapping_claims: CorrespondenceOverlappingClaimsConflict[]; } /** Finite coordination snapshot. Realtime hints remain Wake voice events. */ export interface CorrespondenceVoiceSnapshot { protocol: typeof CORRESPONDENCE_PROTOCOL; scope: "project_private"; evaluated_at: string; cursor: string | null; projection_status: "complete" | "truncated" | "unavailable"; truncated: boolean; recent_events: CorrespondenceVerifiedEventRecord[]; active_claims: CorrespondenceActiveClaim[]; conflicts: CorrespondenceVoiceConflicts; } /** Serialize one value in the bounded v0.1 I-JSON/JCS profile. */ export declare function canonicalCorrespondenceJson(value: CorrespondenceJsonValue): string; /** Canonical 32-byte digest signed by an event author. */ export declare function canonicalCorrespondenceEventBytes(core: CorrespondenceEventCore): Uint8Array; /** Sign a correspondence core locally with a raw or standard-base64 32-byte Ed25519 seed. */ export declare function signCorrespondenceEvent(core: CorrespondenceEventCore, signingKey: Uint8Array | string): CorrespondenceSignature; /** Content address of `{...core, signature}`. Receipt fields are deliberately excluded. */ export declare function correspondenceEventId(core: CorrespondenceEventCore, signature: CorrespondenceSignature): string; /** Build a complete signed wire event without performing network I/O. */ export declare function createSignedCorrespondenceEvent(input: CorrespondenceUnsignedInput, signingKey: Uint8Array | string): CorrespondenceSignedEvent; /** * Verify a received event against an Ed25519 public key the caller already * holds for that sender. This rebuilds the same canonical bytes the sending * path signs, so it is the mirror of `signCorrespondenceEvent`. * * The key argument must be the reader's own record of the signer. A key taken * from the response that carried the event would make this check circular and * worthless — the server would be choosing both the event and the key that * approves it. */ export declare function verifyCorrespondenceSignature(event: CorrespondenceSignedEvent, publicKey: CorrespondenceVerifyingKey): boolean; /** * Decide locally whether one received event is authentic, and say why when it * is not. Content addressing is checked first: an `event_id` that does not * address `{...core, signature}` is refused before any key work. */ export declare function verifyCorrespondenceEvent(event: CorrespondenceSignedEvent, opts?: CorrespondenceVerifyOptions): Promise; export declare class CorrespondenceClient { private readonly http; private readonly onMutation; /** @internal */ constructor(http: HttpConfig, onMutation?: () => void); /** Sign locally and append one immutable event. Unknown parents are allowed. */ append(opts: CorrespondenceAppendOptions): Promise; /** * Read one durable receipt-ordered page. This is authoritative; voice is * only a hint. Each record is annotated with the reader's own * `verification` verdict before it is returned. */ list(opts: CorrespondenceListOptions): Promise; /** Replay durable pages in server receipt order without inferring causality or a winner. */ replay(opts: CorrespondenceListOptions): AsyncIterableIterator; /** Read every active claim branch tip; never collapses conflicting tips into one. */ activeClaims(opts: CorrespondenceClaimsOptions): Promise; /** * Read the bounded finite coordination snapshot. This is JSON, never SSE; * use `at.wake.voice({ identityId, keys: ["correspondence"] })` only as an * invalidation hint and replay `/events` from the last durable receipt * cursor. */ voice(opts: CorrespondenceVoiceOptions): Promise; } export {};