import * as fs from 'fs'; /** * Silent CLI self-update. * * Two install kinds, two upgrade paths: * - npm — `npm install -g fullcourtdefense-cli@` replaces the * global files in place; a freshly spawned daemon then supersedes * the running one via the pid-lock version takeover. * - msi — the CLI runs from Program Files with a bundled node.exe; a * normal-user process cannot rewrite those files, so upgrades go * through the elevated "FullCourtDefense Updater" scheduled task * registered at MSI install time (downloads + verifies + msiexec). * * The org-level auto-update policy (on/off/pinned) arrives on the runtime * bundle; the daemon calls maybeSelfUpdate() on its poll ticks. */ export declare const MSI_UPDATER_TASK_NAME = "FullCourtDefense Updater"; export type InstallKind = 'msi' | 'npm'; /** MSI installs run the bundled runtime\node.exe from the install folder. */ export declare function detectInstallKind(): InstallKind; /** Semver compare; returns >0 when a is newer than b. Unparseable = oldest. */ export declare function compareCliVersions(a?: string, b?: string): number; export interface SelfUpdateResult { started: boolean; kind: InstallKind; detail: string; } export declare function resolveNpmCommand(platform?: NodeJS.Platform, execPath?: string, exists?: typeof fs.existsSync): string; /** * The updater task command for an install root. Prefers the Node updater * (runs on the MSI's own bundled runtime — no powershell.exe spawn, which * EDR/AppLocker block on hardened fleets); the PowerShell script remains the * command only for old payloads that predate the Node updater. Escaped for * `schtasks /TR` (embedded quotes as \"). */ export declare function buildUpdaterTaskCommand(root: string, exists?: (p: string) => boolean): string | undefined; /** * True when a registered task command should be re-registered: * - it still points at the PowerShell updater while this install carries * the Node updater (predates the PowerShell-free updater), or * - it runs the Node updater WITHOUT `--api-url` (an old self-healed task — * those default to prod, silently retargeting staging machines). */ export declare function updaterTaskNeedsModernization(taskToRun: string, root: string, exists?: (p: string) => boolean): boolean; /** * Task Scheduler XML for the updater task — settings-parity with the MSI's * own registration (Install-FullCourtDefense.ps1): StartWhenAvailable so a * laptop asleep at 03:07 catches up on wake, battery-friendly so the task is * not skipped/killed unplugged, SYSTEM at highest run level, daily trigger. * `schtasks /Create` flags cannot express these (its defaults silently drop * StartWhenAvailable and stop on battery) — registration goes through * `/Create /XML` instead. */ export declare function buildUpdaterTaskXml(root: string, apiUrl: string): string | undefined; /** * Upgrade an EXISTING updater task from the PowerShell command to the Node * command. Machines that upgraded from a pre-Node-updater MSI keep their old * task definition (the MSI re-registers it, but registration can be denied); * this converges them whenever a daemon runs elevated. Best-effort: needs an * elevated token to re-register a SYSTEM task, silent no-op otherwise. */ export declare function modernizeUpdaterTask(log: (message: string) => void, apiUrl?: string): void; /** * Updater script log (%ProgramData%\FullCourtDefense\updater.log) — the * elevated task's own words. Read by the diagnostics bundle and the update- * loop detector so a silently failing updater is explainable from the console * (Alin's machine triggered the task every 10 minutes for hours with zero * fleet-visible evidence of WHY). */ export declare function readUpdaterLogTail(maxLines?: number): string[]; /** * Clear update_loop distress once the machine PROVABLY moved past the loop: * the installed version reached (or passed) the looping target, or the * installed version changed at all since the attempts record was written. * Called at daemon boot (a fresh daemon starts right after every MSI update) * and when the bundle target is already satisfied. Without this, a resolved * loop keeps shipping in the 24h ledger snapshot and reads as a live problem * in the console. Cheap no-op when there is no attempts record. */ export declare function clearResolvedUpdateLoop(currentVersion: string | undefined, log?: (message: string) => void): void; /** * Upgrade this machine to targetVersion if it is newer than currentVersion. * Cheap no-op when already current, when a kick is still pending, or when the * platform path is unavailable. Never throws. */ export declare function maybeSelfUpdate(input: { currentVersion?: string; targetVersion?: string; enabled?: boolean; log?: (message: string) => void; /** Skip while a remote machine action is executing (never upgrade mid-action). */ busy?: boolean; /** Bypass the retry cooldown — used by explicit admin upgrade_cli actions so * they always attempt and report the REAL outcome instead of "in progress". */ force?: boolean; /** Control-plane URL this machine is enrolled against — preserved on any * self-healed updater task so staging machines never retarget prod. */ apiUrl?: string; }): SelfUpdateResult | undefined; /** Version the MSI updater script reads from the installed package.json. */ export declare function installedMsiVersion(installFolder: string): string | undefined;