export type AddonInstallSource = "npm" | "local" | "upload" | "bundled" | "seed";
export interface AddonManifestEntry {
    /** Full pkg name, e.g. `@camstack/addon-pipeline`. */
    name: string;
    /** Semver currently installed. */
    version: string;
    /** Where this version came from. */
    source: AddonInstallSource;
    /** ISO 8601 of first install. */
    installedAt: string;
    /** ISO 8601 of last update (== installedAt for first install). */
    updatedAt: string;
    /**
     * Path (absolute) of the most recent pre-update backup, if any.
     * Used by `applyUpdate` rollback when an upgrade fails its post-restart
     * health check. Cleared once the new version is confirmed healthy.
     */
    lastBackupDir?: string;
    /**
     * Free-form, addon-specific metadata. Currently unused but reserved so
     * future fields (e.g. integrity hash, peer-dep checks) don't require a
     * manifest schema bump.
     */
    meta?: Record<string, unknown>;
}
export interface AddonManifestFile {
    /**
     * Schema version. Increment whenever the on-disk shape changes
     * incompatibly so older readers can refuse to load.
     */
    version: 1;
    /** Per-package state, keyed by full pkg name. */
    addons: Record<string, AddonManifestEntry>;
    /** ISO 8601 of last manifest write. */
    updatedAt: string;
}
export declare class AddonManifest {
    private readonly manifestPath;
    private cache;
    constructor(addonsDir: string);
    /**
     * Read the manifest from disk. Returns an empty manifest if the file is
     * missing or corrupted (logs a warning to stderr in the corrupted case).
     * Cached per instance — call `invalidate()` to force a re-read.
     */
    read(): AddonManifestFile;
    /**
     * Atomic write — writes to a tmpfile in the same directory, then renames.
     * Rename is atomic on the same filesystem, so readers can never observe
     * a half-written file.
     */
    write(manifest: AddonManifestFile): void;
    /** Lookup a single addon's manifest entry, or `null` if not tracked. */
    get(name: string): AddonManifestEntry | null;
    /** List every tracked entry. */
    list(): AddonManifestEntry[];
    /**
     * Insert or replace an addon entry. `installedAt` is preserved if the
     * entry already exists; only `updatedAt` advances on subsequent writes.
     */
    upsert(name: string, fields: Omit<AddonManifestEntry, "name" | "installedAt" | "updatedAt">): void;
    /** Remove an addon from tracking (e.g. uninstall). */
    remove(name: string): void;
    /**
     * Drop the in-memory cache so the next `read()` re-loads from disk.
     * Useful when an external process may have written the manifest.
     */
    invalidate(): void;
    /**
     * Migration helper: if the manifest is empty but the addons directory
     * has packages with `.install-source` markers (the legacy per-addon
     * tracking), seed the manifest from those markers. Runs once at boot.
     * Returns the number of entries migrated.
     */
    migrateFromInstallSourceMarkers(addonsDir: string): number;
    private empty;
}
//# sourceMappingURL=addon-manifest.d.ts.map