/** * GitHub-release auto-installer for LSP servers (Pattern C). * * Cache layout under `/lsp-binaries/`: * * / * bin/ ← extracted binary (or shim) * extracted/ ← validated extraction (kept for upgrades) * .aft-version-check ← JSON: { last_checked, latest_eligible } * .aft-installing ← lockfile while a download/extract runs * * `bin/` is what we add to `lsp_paths_extra` so the Rust resolver * can find it. * * Extraction containment: * 1. Download to `/` with a hard size cap. * 2. Extract into a quarantine dir `/.staging-/`. * 3. Walk the staging tree and reject any entry that is a symlink, hardlink, * or whose canonical path escapes the staging root. * 4. Only after validation: `renameSync(staging, extracted)` atomically * replaces any prior extraction. * 5. Stage dir is always cleaned up — success or failure. * * GitHub pin resolution: * When `lsp.versions: { "owner/repo": "X" }` is set, we use GitHub's * `/releases/tags/` endpoint directly (with `v`-prefix tolerance) * instead of relying on the broader `/releases?per_page=30` probe. The * probe is for "what is the latest eligible version" — not "is this * specific pinned tag valid". */ import { type Arch, detectHostPlatform, findGithubServerById, GITHUB_LSP_TABLE, type GithubServerSpec, type Platform } from "./lsp-github-table.js"; /** Final binary path under our cache. */ export declare function ghBinaryPath(spec: GithubServerSpec, platform: Platform): string; export declare function isGithubInstalled(spec: GithubServerSpec, platform: Platform): boolean; export interface GithubInstallConfig { autoInstall: boolean; graceDays: number; /** Per-package version pin map; key is `owner/repo`. Bypasses grace. */ versions: Readonly>; disabled: ReadonlySet; } declare function assertAllowedDownloadUrl(rawUrl: string): URL; declare function downloadFile(url: string, destPath: string, fetchImpl: typeof fetch, assetSize?: number, signal?: AbortSignal): Promise; /** * Recursively validate that every entry under `stagingRoot` is contained * within it (zip-slip + symlink containment). * * Rejects: * - Any symlink (regardless of where it points). Symlinks in LSP * installs are extremely rare and would be a red flag. * - Any hardlink that has multiple inodes pointing at the same file * OUTSIDE the staging root (we can't easily detect this for hardlinks * to other paths inside the same archive, but those aren't a containment * escape). * - Any entry whose `realpath()` resolves outside `stagingRoot`. This * catches what the platform extractor missed if it failed to defend * against `..` traversal. * * Throws on any violation. The caller cleans up the staging dir. */ export declare function validateExtraction(stagingRoot: string): void; /** * Extract `archivePath` into `destDir` safely: * * 1. Stage extraction in `.staging-/`. * 2. Run the platform extractor against the staging dir. * 3. Validate the staging tree (no symlinks, no escapes). * 4. Atomic rename: `staging → destDir`. Any prior `destDir` is removed first. * 5. Always cleanup staging on any failure. */ export declare function precheckArchiveContents(archivePath: string, archiveType: string): void; export interface GithubAutoInstallResult { cachedBinDirs: string[]; installsStarted: number; /** Binary names whose installs are actively in flight at return time. */ installingBinaries: string[]; skipped: Array<{ id: string; reason: string; }>; /** * Promise that resolves when every backgrounded GitHub install settles. * Each install holds its per-package install lock for its full duration. * Plugin startup ignores this; tests await it. */ installsComplete: Promise; /** Re-scan the cache after background installs settle. */ getCachedBinDirs: () => string[]; } export declare function abortInFlightGithubInstalls(): Promise; /** * Run the GitHub-release auto-install pass for every Pattern C server. * * Sync return: per-server cached bin dirs + skipped reasons known at decision * time. Backgrounded installs settle into `installsComplete` so plugin * startup is not blocked on slow downloads. */ export declare function runGithubAutoInstall(relevantServers: ReadonlySet, config: GithubInstallConfig, fetchImpl?: typeof fetch): GithubAutoInstallResult; /** * Cheap project-relevance scan for GitHub-distributed servers. Root markers * win immediately; otherwise use the bounded shared extension walk for * monorepos with nested source files. */ export declare function discoverRelevantGithubServers(projectRoot: string): Set; /** * Test-only re-export of the GitHub download URL allowlist guard. * * The `__test` prefix marks this as test-internal. Production code * inside this module already calls `assertAllowedDownloadUrl` at the top * of `downloadFile`. We expose it here so the test suite can verify the * allowlist independently of full network mocking. */ export { type Arch, assertAllowedDownloadUrl as _assertAllowedDownloadUrlForTesting, detectHostPlatform, downloadFile as _downloadFileForTesting, findGithubServerById, GITHUB_LSP_TABLE, type GithubServerSpec, type Platform, precheckArchiveContents as _precheckArchiveSizeForTesting, }; //# sourceMappingURL=lsp-github-install.d.ts.map