import { SDK_STATE_VERSION } from "../broker/state-version"; import { type GuideEntryV1, type GuideManifestV1 } from "./manifest"; import { type GuideVerificationErrorCode } from "./verify"; /** * Verified on-disk cache for trusted advisory guides. * * Layout under `/sdk/guides/cache/` (mode 0700): * meta.json — atomic commit pointer {version, manifestId, sequence, generation, installedAt} * meta.json.lock — cross-process install lock (project `withFileLock` convention) * generations//manifest.json — canonical manifest bytes * generations//manifest.sig — detached Ed25519 signature * generations//guides/ — immutable advisory text * * A complete generation is written and fsynced before `meta.json` is atomically * replaced under the install lock. Readers follow only the committed * generation, so an interrupted install cannot expose a new manifest with * stale metadata or disturb the previously valid cache. */ export interface GuideCacheMetaV1 { version: typeof SDK_STATE_VERSION; manifestId: string; sequence: number; installedAt: number; generation: string; } export interface GuideCacheGuideV1 { id: string; title: string; sha256: string; text: string; } export interface VerifiedGuideCache { manifest: GuideManifestV1; signatureBytes: Uint8Array; meta: GuideCacheMetaV1; guides: GuideCacheGuideV1[]; } export type GuideCacheReadResult = { ok: true; value: VerifiedGuideCache; } | { ok: false; error: { code: "missing_cache" | "corrupt_cache" | "expired_cache" | "unsupported_state_version"; message: string; }; }; export type GuideCacheInstallResult = { ok: true; value: VerifiedGuideCache; } | { ok: false; error: { code: GuideVerificationErrorCode | "invalid_input" | "io_error"; message: string; }; }; export declare function guideCacheDir(agentDir: string): string; /** * Reads and re-verifies the cache end to end: manifest parse, meta commit * record, detached signature, expiry against `now`, and every advisory hash. * Any failure is reported as `corrupt_cache` (or `expired_cache` when the * signature is valid but stale) and the cache is left untouched — a corrupt * entry never destroys the data a future, still-valid install may replace. */ export declare function readGuideCache(params: { agentDir: string; now: number; }): Promise; /** * Installs a verified manifest plus its advisory content into the cache. * * Order of operations: * 1. Verify the manifest signature, expiry, and every advisory hash before * any write — a tampered or expired payload never touches disk. * 2. Under the cache's cross-process install lock, enforce the monotonic * version floor against the committed meta record (`rollback` when the * candidate does not advance the channel). * 3. Write and fsync a complete immutable generation, then atomically replace * `meta.json` as the only commit pointer. * * Steps 2–3 are serialized with `/meta.json.lock` (the project's * `withFileLock` convention): the floor is re-read under the same lock that * guards the commit pointer replacement, so a concurrent install can never * read an older floor, observe a newer commit, and then downgrade the channel. * Any failure aborts before the commit, leaving the prior valid cache fully * intact and readable. */ export declare function installGuideCache(params: { agentDir: string; manifest: GuideManifestV1; signatureBytes: Uint8Array; advisories: readonly { entry: GuideEntryV1; text: Uint8Array; }[]; now: number; }): Promise;