/** * Compact per-generation bookkeeping for cheap freshness checks (T12316). * * The published `graph_assessment` carries every retained reference with its * full evidence — 472 MB of JSON on this repository — so it cannot be read on * the query path. The file manifest records only what a freshness check needs * (path, size, mtime, content hash per indexed file), and the run summary * records what the last analysis cost, so a refresh can be estimated before it * is started. Both live in `_nexus_meta` next to the generation they describe. * * Code placed in `packages/core/` per Package-Boundary Check — verified against AGENTS.md. * * @task T12316 * @module nexus/graph-manifest */ import type { GraphIndexAssessment, GraphIndexRunSummary } from '@cleocode/contracts'; import type { NodeSQLiteDatabase } from 'drizzle-orm/node-sqlite'; /** * An inline refresh failed or was aborted (T14014): skip inline refreshes until * `until`, or until a successful analysis publishes a new generation. */ export interface RefreshCooldown { /** ISO 8601 instant the cooldown ends. */ until: string; /** Graph generation the failed refresh started from. */ generation: string | null; /** Why the refresh did not finish. */ reason: string; } /** One indexed file: `[path, size, mtimeMs, contentHash]`. */ export type GraphManifestEntry = [path: string, size: number, mtimeMs: number, hash: string]; /** Compact description of the files a published generation was built from. */ export interface GraphFileManifest { /** Generation the manifest describes. */ generation: string | null; /** * Absolute source root the paths are relative to. In memory it is absolute; * in `_nexus_meta` it is stored relative to the project root (T12474). */ sourceRoot: string; /** Explicitly included nested repositories, needed to walk the same tree. */ includedRepositories: string[]; /** When the generation was assessed. */ assessedAt: string; /** Every indexed file with a content hash. */ files: GraphManifestEntry[]; } /** Cost record of the last analysis that published a generation. */ export interface GraphRunCost { /** Mode, counts and per-phase milliseconds of that run. */ summary: GraphIndexRunSummary; /** End-to-end milliseconds, including provenance and publication. */ durationMs: number; /** When the run finished. */ recordedAt: string; } /** Files with an observed size, mtime and hash, as recorded by an index scan. */ interface ObservedFile { path: string; size?: number; mtimeMs?: number; contentHash?: string; } /** * Build the manifest for a generation from its observed files. * @param assessment - Assessment of the generation (source root, scope, timestamp). * @param files - Files whose size, mtime and hash were observed; others are omitted. * @returns The compact manifest. */ export declare function buildFileManifest(assessment: Pick, files: readonly ObservedFile[]): GraphFileManifest; /** * Write the manifest; call inside the transaction that publishes its generation. * * The source root is stored relative to `projectRoot` (T12474), so the record * stays valid after the project moves. * * @param tx - Open transaction on the project graph database. * @param manifest - Manifest of the generation being committed. * @param projectRoot - Canonical project root; when omitted the root is stored as given. */ export declare function writeFileManifest(tx: NodeSQLiteDatabase, manifest: GraphFileManifest, projectRoot?: string): void; /** * Remove the manifest; call when a generation is published without one, so a * stale manifest can never describe a different generation. * @param tx - Open transaction on the project graph database. */ export declare function clearFileManifest(tx: NodeSQLiteDatabase): void; /** * Read the manifest of the committed generation, its source root resolved * against the live project root. * * A manifest written before T12474 holds the absolute root of the machine that * analyzed it; when that root lies inside the project root recorded with the * same generation, it is rebased onto the live root, so a moved project walks * its own tree instead of a path that no longer exists. * * @param db - Project graph database. * @param projectRoot - Live project root the database was opened for. * @returns The manifest, or `null` when the generation predates manifests. * @throws When a stored manifest is malformed. */ export declare function readFileManifest(db: NodeSQLiteDatabase, projectRoot: string): GraphFileManifest | null; /** * Record what the last publishing analysis cost; advisory, used for estimates. * @param db - Project graph database. * @param cost - Summary and duration of the run. */ export declare function writeRunCost(db: NodeSQLiteDatabase, cost: GraphRunCost): void; /** * The revision the published generation indexed (T14007). Lenient: a missing, * unparseable or revision-less assessment reads as `null`, never a throw, so a * freshness answer is never lost to it. * * @param db - Project graph database. * @returns The recorded `assessedRevision`, or `null`. */ export declare function readIndexedRevision(db: NodeSQLiteDatabase): string | null; /** * Record an inline-refresh cooldown (T14014). * * @param db - Project graph database. * @param cooldown - Until when, from which generation, and why. */ export declare function writeRefreshCooldown(db: NodeSQLiteDatabase, cooldown: RefreshCooldown): void; /** * The inline-refresh cooldown in force, or `null` (T14014). It lapses at its * `until`, or as soon as a successful analysis publishes a new generation. * * @param db - Project graph database. * @param nowMs - The clock. * @returns The active cooldown, or `null`. */ export declare function readActiveRefreshCooldown(db: NodeSQLiteDatabase, nowMs?: number): RefreshCooldown | null; /** * Whether a cooldown is still in force: before its `until`, and no analysis * has published a new generation since it was recorded (T14014). * * @param db - Project graph database. * @param cooldown - A recorded cooldown (from `_nexus_meta` or its fallback file). * @param nowMs - The clock. * @returns True while it applies. */ export declare function refreshCooldownApplies(db: NodeSQLiteDatabase, cooldown: RefreshCooldown, nowMs?: number): boolean; /** * Read the last recorded run cost. * @param db - Project graph database. * @returns The cost, or `null` when none (or an unreadable one) is recorded. */ export declare function readRunCost(db: NodeSQLiteDatabase): GraphRunCost | null; export {}; //# sourceMappingURL=graph-manifest.d.ts.map