/**
 * @fileoverview Server-side logic for the in-app self-updater.
 *
 * Powers App Settings → Updates. Codeman is installed as a git clone and run
 * under systemd (Linux) or launchd (macOS); updating means `git checkout <release
 * tag> && npm install && npm run build && restart-the-service`. The hard part is
 * that the update restarts the very process performing it, so the actual work
 * runs in a DETACHED `scripts/self-update.sh` that outlives the restart, writing
 * progress to `dataPath('update-status.json')` which the browser polls across the
 * connection drop.
 *
 * Channel: latest tagged RELEASE (tags look like `codeman@0.9.3`). Dirty trees
 * are auto-stashed (stash left for the user). Detection is manual (a button).
 *
 * Split into PURE helpers (semver/tag parsing, reconcile decision) that are unit
 * tested, and IO wrappers (`getInstallInfo`, `checkForUpdate`, `startUpdate`,
 * `reconcileUpdateOnBoot`) that touch git/network/fs.
 *
 * Related: `src/types/update.ts`, `scripts/self-update.sh`, routes in
 * `src/web/routes/system-routes.ts`.
 *
 * @module web/self-update
 */
import type { InstallInfo, SupervisorKind, UpdateCheckResult, UpdateStatus } from '../types/update.js';
export declare function isInFlight(status: UpdateStatus | null | undefined): boolean;
export interface ParsedVersion {
    major: number;
    minor: number;
    patch: number;
    /** Non-empty for prereleases like `0.9.3-rc1`. */
    prerelease: string;
}
/**
 * Parse a semver out of a release tag. Accepts `codeman@0.9.3`, `aicodeman@0.9.3`,
 * `v0.9.3`, and bare `0.9.3` (with optional `-prerelease`). Returns null if no
 * `X.Y.Z` is present.
 */
export declare function parseVersionFromTag(tag: string): ParsedVersion | null;
/** Compare two parsed versions. Returns >0 if a>b, <0 if a<b, 0 if equal. A release outranks a prerelease of the same X.Y.Z. */
export declare function compareVersions(a: ParsedVersion, b: ParsedVersion): number;
/** True when `latest` is a strictly newer STABLE version than `current`. */
export declare function isNewerStableVersion(current: string, latest: string): boolean;
/**
 * From a list of `refs/tags/...` (or bare tag names), pick the highest STABLE
 * release tag we recognize. Skips prereleases and unrecognized tags.
 */
export declare function pickLatestStableTag(tagRefs: string[]): {
    tag: string;
    version: string;
} | null;
/** Tags must match this before they're ever passed to the shell. */
export declare function isValidReleaseTag(tag: string): boolean;
/** Derive `{owner, repo}` from a GitHub SSH or HTTPS remote URL. */
export declare function parseGitHubRepo(remoteUrl: string): {
    owner: string;
    repo: string;
} | null;
/**
 * PURE boot-time reconcile decision. Given the persisted status, the version the
 * freshly-booted process is actually running, and `now`, return the status to
 * persist — or null to leave it untouched.
 *
 * Rules (see plan "Hardening"):
 * - Terminal phases → untouched, EXCEPT `completed-needs-manual-restart`: once we
 *   boot into the staged target version the manual restart evidently happened, so
 *   it flips to `completed` (otherwise the stale instruction lingers in the UI).
 * - Only the `restarting` marker (written right before the updater triggers our
 *   restart) flips to completed/failed by comparing running version vs. target.
 * - Other in-flight phases are owned by the still-running updater scope — leave
 *   them alone so a normal/crash restart mid-update isn't misreported.
 * - A backstop staleness guard fails any in-flight status older than the window.
 */
export declare function reconcileStatusDecision(status: UpdateStatus | null, runningVersion: string, now: number): UpdateStatus | null;
/** Read the persisted status; tolerant of a missing/torn file (returns null). */
export declare function readUpdateStatus(): UpdateStatus | null;
/** Write the status atomically (temp + rename — readers never see a torn file). */
export declare function writeUpdateStatusAtomic(status: UpdateStatus): void;
/** Reconcile the status file on server boot (call once, early in start()). */
export declare function reconcileUpdateOnBoot(now?: number): void;
/**
 * Resolve the repo root from this module's location. Compiled to
 * `dist/web/self-update.js` (or `src/web/self-update.ts` under tsx) → two levels
 * up is the package root that holds `package.json` and `.git`. Matches the
 * `require('../../package.json')` resolution in `server.ts`.
 */
export declare function resolveInstallDir(): string;
/**
 * Detect which init system supervises us. Detection happens HERE (in the running
 * server, which has a rich env) and the result is passed to the updater script —
 * the detached child must not re-probe with a stripped-down environment.
 */
export declare function detectSupervisor(): SupervisorKind;
/** Inspect the running install: kind, dir, branch, dirtiness, supervisor, version. */
export declare function getInstallInfo(): InstallInfo;
/** Check the configured remote for a newer release than the running version. */
export declare function checkForUpdate(): Promise<UpdateCheckResult>;
export type StartUpdateResult = {
    ok: true;
    updateId: string;
    toTag: string;
    toVersion: string | null;
} | {
    ok: false;
    code: 'disabled' | 'not-git' | 'in-flight' | 'up-to-date' | 'bad-tag' | 'error';
    message: string;
};
/**
 * Validate, snapshot the current commit, write the initial status, and spawn the
 * detached updater. Returns immediately — progress is reported via the status file.
 */
export declare function startUpdate(): Promise<StartUpdateResult>;
/** Current status for the polling endpoint; null collapses to an explicit idle. */
export declare function getUpdateStatusForApi(): UpdateStatus;
//# sourceMappingURL=self-update.d.ts.map