import { type AsarBlindFs, type AsarFsEnv } from "./asar-fs.js"; import { type CheckResult, type DoctorCheckGroup, type DoctorContext } from "../types.js"; /** * "80 of your 81 files are gone" — the ten-second diagnosis, automated, plus the * write probe whose exact error text is what told us it was a filter driver and * not a permissions problem. * * ── THE MANIFEST ───────────────────────────────────────────────────────────── * The desktop app ships `resources/install-manifest.json`, written at pack time * by packages/desktop/scripts/generate-manifest.mjs. Two consumers already read * it: the in-process startup check (desktop/src/integrity.ts) and the Windows * watchdog. This is the third, and it is the EXPENSIVE pass the startup check * deliberately defers — the startup check does presence and count only, so that * it costs the main loop nothing; the doctor re-hashes every file the manifest * recorded a hash for, because a user who ran `doctor` has asked to wait. * * The name and schema number are duplicated here rather than imported: the * declaration lives in `packages/desktop/src/install-manifest-contract.mjs`, * and `@aicommander/desktop` is not (and must not become) a dependency of the * agent — the agent ships to npm on its own. `install-manifest-parity.test.ts` * pins these two literals against that file, so a rename or a schema bump over * there fails a test here instead of silently switching this check off. * * A manifest we do not recognise is treated as ABSENT, never as damage. The * manifest cannot attest to itself, and accusing a user's antivirus on the * strength of a file we failed to parse is the one mistake that would make this * command untrustworthy. * * ── `critical` ─────────────────────────────────────────────────────────────── * The generator flags a file `critical` when its ABSENCE alone stops the app * starting — the runtime's own files. Per-feature and per-locale resources are * deliberately NOT critical: a quarantined `locales/am.pak` is missing, and * nothing more. The distinction is what keeps the verdict proportionate. */ /** Mirrors packages/desktop/src/install-manifest-contract.mjs — see the header. */ export declare const MANIFEST_FILENAME = "install-manifest.json"; /** Mirrors packages/desktop/src/install-manifest-contract.mjs — see the header. */ export declare const MANIFEST_SCHEMA = 1; interface ManifestEntry { path: string; size: number; sha256?: string; critical?: boolean; link?: boolean; } interface InstallManifest { schema: number; product?: string; version?: string; platform?: string; generatedAt?: string; manifestPath?: string; totalFiles?: number; files: ManifestEntry[]; } interface LoadedManifest { manifest: InstallManifest; /** The install root, recovered by stripping the manifest's own relative path. */ root: string; } /** * Load the manifest and recover the install root FROM it, by stripping the * manifest's own recorded relative path off where the file actually sits — * rather than reimplementing "resources/ on Windows, Contents/Resources on * macOS". The layout is the generator's business, and every consumer recovers * the root the same way (integrity.ts does exactly this). */ export declare function loadInstallManifest(resourcesPath: string, io?: AsarBlindFs): Promise; interface ManifestVerdict { result: CheckResult; root: string | null; } export declare function checkManifest(ctx: DoctorContext, fsEnv?: AsarFsEnv): Promise; export declare const installChecks: DoctorCheckGroup; export {};