/** * Disk layout and bookkeeping for AFT's auto-installed LSP cache. * * Layout under `/lsp-packages/`: * * / * node_modules/.bin/ ← actual installed binary * node_modules//... * package.json ← created by `bun add` * .aft-version-check ← JSON: { last_checked: ISO, latest: "X.Y.Z" } * .aft-installing ← presence = install in progress (lockfile) * * For scoped packages like `@vue/language-server`, the `@` is preserved in * the directory path. `` is URL-encoded to keep filesystem-safe paths * for any future packages with unusual characters. */ /** Keep aftCacheBase as an alias for getAftCacheRoot so existing callers using the older name continue to work. */ export declare function aftCacheBase(): string; /** Root directory for npm-installed LSP packages. */ export declare function lspCacheRoot(): string; /** Directory for one specific npm package's install. */ export declare function lspPackageDir(npmPackage: string): string; /** Path to the binary inside that package's `node_modules/.bin/`. */ export declare function lspBinaryPath(npmPackage: string, binary: string): string; /** Directory passed to Rust as part of `lsp_paths_extra`. */ export declare function lspBinDir(npmPackage: string): string; /** True when the cached binary file exists. */ export declare function isInstalled(npmPackage: string, binary: string): boolean; /** * Per-install metadata recorded after a successful install. * * Persisting the installed version lets us detect a * `lsp.versions` pin change and trigger a transparent reinstall. * * Persisting the SHA-256 of the downloaded archive enables * Trust-On-First-Use verification — if the same tag is ever reinstalled * with a different hash, we reject it (the release was retroactively * rewritten or the download was tampered with). `sha256` is optional * because npm-installed packages don't have a single archive to hash, * and historic installs predating this field have no recorded hash. * * `version` is the resolved tag/semver string (npm package version or * GitHub release tag). `installedAt` is informational only. */ export interface InstalledMeta { version: string; installedAt: string; /** SHA-256 of the downloaded archive (GitHub installs only). */ sha256?: string; } /** * Write the installed-version record into `installDir`. Used by both the * npm install path (cache layout `//`) and the GitHub * install path (cache layout `//`). Best-effort — * failures only logged. * * Pass `sha256` for GitHub installs so the next session can do TOFU * verification (audit v0.17 #1). npm installs leave it undefined since * there's no single archive to hash. */ export declare function writeInstalledMetaIn(installDir: string, version: string, sha256?: string): void; /** Read the installed-version record from `installDir`, or null if missing/corrupt. */ export declare function readInstalledMetaIn(installDir: string): InstalledMeta | null; /** npm install path: write installed metadata into the package cache dir. * * Pass `sha256` of the installed binary so the next * session can do TOFU verification on reinstalls of the same version. */ export declare function writeInstalledMeta(packageKey: string, version: string, sha256?: string): void; /** npm install path: read installed metadata from the package cache dir. */ export declare function readInstalledMeta(packageKey: string): InstalledMeta | null; /** * Acquire an install lock for `lockKey` using an atomic `O_EXCL` open. * * The previous implementation used `existsSync` + `writeFileSync({flag:"w"})` * which is a textbook TOCTOU: two concurrent processes both pass the check, * both call write (which truncates with flag "w"), and both think they own * the lock. With `wx` the second process's open() fails atomically. * * Stale-lock recovery: if the lock file exists, we read it. If the recorded * PID is no longer alive OR the file is older than `STALE_LOCK_MS`, we claim * the lock by atomically replacing it (unlink + create with `wx`). If that * race fails (someone else just claimed it), we return false honestly. * * The lock file content is `\n\n` so other processes * can detect dead owners. */ export declare function acquireInstallLock(lockKey: string): boolean; export declare function releaseInstallLock(lockKey: string): void; /** * Run `task` while holding the install lock. The lock is released only * when `task` settles (resolves or rejects), not when it starts. * * Returns the task's resolved value, or `null` if the lock could not be * acquired (caller should treat as "another install in progress"). */ export declare function withInstallLock(lockKey: string, task: () => Promise): Promise; /** Last-checked metadata stored next to the install. */ interface VersionCheckRecord { /** ISO timestamp of the last `npm registry probe`. */ last_checked: string; /** Version string that was eligible at last check (after grace filter). */ latest_eligible: string | null; } export declare function readVersionCheck(npmPackage: string): VersionCheckRecord | null; export declare function writeVersionCheck(npmPackage: string, latest: string | null): void; /** True if more than `graceDays` × 24h have elapsed since `last_checked`. */ export declare function shouldRecheckVersion(record: VersionCheckRecord | null, weeklyCheckIntervalMs?: number): boolean; export {}; //# sourceMappingURL=lsp-cache.d.ts.map