/**
 * GitHub-backed data sync for Endfield-MCP.
 *
 * Mirrors the design of PRTS-MCP's `ts/src/data/sync.ts` — the same proven
 * decision tree, cascade fallback, and atomic-write semantics. The only
 * Endfield-specific parts are the User-Agent and the absence of the
 * `upstream-<sha>` tag convention (our mirror uses plain semver tags, so
 * commitSha === tag verbatim).
 *
 * Contract:
 * - Downloads GitHub Release zip assets only when the release tag changes.
 * - Skips the upstream API call entirely when cached data is fresher than
 *   CACHE_TTL_SECONDS (avoids burning GitHub anonymous quota on every start).
 * - Falls back gracefully to cached data when the network is unavailable,
 *   and to "no data" only when neither cache nor network can provide.
 * - All writes are write-to-tmp-then-rename for crash safety.
 */
/** Describes an upstream GitHub repository and the files required from it. */
export interface RepoSpec {
    owner: string;
    repo: string;
    branch: string;
    files: readonly string[];
    /** Absolute path to the local directory where files are written. */
    localRoot: string;
}
export type SyncStatus = "updated" | "up_to_date" | "offline_fallback" | "no_data";
export interface SyncResult {
    spec: RepoSpec;
    status: SyncStatus;
    commitSha: string | null;
    error: string | null;
}
/** Describes a GitHub Release asset to download as a local zip. */
export interface ReleaseSpec {
    owner: string;
    repo: string;
    /** Asset filename in the release, e.g. "endfield-tables.zip". */
    assetName: string;
    /** Absolute destination path for the downloaded zip. */
    localZip: string;
    /** Optional validator returning missing or invalid zip entries. */
    validateZip?: (zipPath: string) => string[];
}
/** Describes a GitHub Release zip asset that should be extracted locally. */
export interface ReleaseArchiveSpec {
    owner: string;
    repo: string;
    assetName: string;
    localZip: string;
    localRoot: string;
    requiredFiles: readonly string[];
}
/**
 * Fetch the release tag and asset download URL for the requested asset.
 *
 * Lists the repo's releases (newest first) and returns the first Release
 * that actually contains `spec.assetName`. We deliberately do NOT use the
 * `/releases/latest` endpoint: that returns the single newest Release for the
 * whole repo, which only carries *that* release's assets. Once a repo ships
 * several independent assets across different Releases (tables/story/worldview),
 * `/releases/latest` makes every non-latest asset look "missing" and breaks
 * their syncs. Listing + asset-name matching is robust to that layout.
 *
 * Return / throw contract (load-bearing — `syncRelease` distinguishes the two):
 *   - Returns `{tag, url}` when a Release carrying the asset is found.
 *   - Returns `null` when the API responded but NO scanned Release has the
 *     asset (genuine absence — caller must NOT retry via blind download).
 *   - THROWS on network/API failure (caller treats as "unreachable" and may
 *     fall back to blind download / cached data).
 *
 * This distinction matters because the blind-download fallback in `syncRelease`
 * constructs a `releases/latest/download/<asset>` URL — which only makes sense
 * when we genuinely couldn't reach the API, not when the API confirmed the
 * asset is absent.
 */
export declare function checkLatestRelease(spec: ReleaseSpec, timeoutMs?: number): Promise<{
    tag: string;
    url: string;
} | null>;
/**
 * Download the release asset zip atomically, then write cache metadata.
 * Uses write-to-tmp-then-rename for crash safety.
 */
export declare function downloadReleaseAsset(spec: ReleaseSpec, tag: string, assetUrl: string, timeoutMs?: number): Promise<void>;
/**
 * Check latest GitHub Release and download the zip if the tag has changed.
 *
 * Decision tree:
 *   1. Cache fresh AND zip exists → up_to_date (skip API call).
 *   2. Network failure → offline_fallback (zip exists) / no_data (no zip).
 *   3. Tag unchanged AND zip exists → up_to_date (refresh fetchedAt).
 *   4. Tag changed or zip missing → downloadReleaseAsset → updated / fallback.
 */
export declare function syncRelease(spec: ReleaseSpec): Promise<SyncResult>;
/**
 * Download a GitHub Release zip asset and extract it into localRoot.
 *
 * Keeps the data distribution path aligned with PRTS-MCP's pattern
 * (release zip → local extraction → DirectoryStore reads) while preserving
 * whatever on-disk layout the Endfield mirror ships.
 */
export declare function syncReleaseArchive(spec: ReleaseArchiveSpec): Promise<SyncResult>;
