UNPKG

pi-lens

Version:

Real-time code feedback for pi — LSP, linters, formatters, type-checking, structural analysis & booboo

150 lines (147 loc) • 4.37 kB
import { createRequire as __pilensCreateRequire } from "node:module"; const require = __pilensCreateRequire(import.meta.url); import { assertInstallAllowed } from "./chunk-NTUJEGDZ.js"; import { classifyProbeFailure, installRetryDelayMs } from "./chunk-WONERJTP.js"; import { safeSpawnAsync } from "./chunk-VN2AXLEX.js"; import { logExtension } from "./chunk-O6TQT6RI.js"; // dist/clients/dispatch/runners/utils/lazy-installer.js var LAZY_INSTALL_SPECS = { rubocop: { command: "gem", args: ["install", "rubocop", "--no-document"] }, "rust-clippy": { command: "rustup", args: ["component", "add", "clippy"] }, rustfmt: { command: "rustup", args: ["component", "add", "rustfmt"] } }; var LAZY_INSTALL_IGNORES_AMBIENT_SIGNAL = true; var LAZY_INSTALL_TIMEOUT_MS = 18e4; var attempts = /* @__PURE__ */ new Map(); function key(cwd, tool) { return `${cwd}:${tool}`; } function getLazyInstallAttempt(tool, cwd) { return attempts.get(key(cwd, tool))?.fact; } function resetLazyInstallAttempts() { attempts.clear(); } function suppressionFor(state) { if (!state) return null; if (state.fact.outcome === "succeeded") return "succeeded"; if (state.retryAtMs === 0) return "held"; return Date.now() < state.retryAtMs ? "cooling" : null; } var inFlight = /* @__PURE__ */ new Map(); async function runLazyInstall(tool, cwd, spec) { const k = key(cwd, tool); const running = inFlight.get(k); if (running) return running; const previous = attempts.get(k); const suppressed = suppressionFor(previous); if (suppressed !== null) { logExtension({ subsystem: "install", message: `lazy-install ${tool} suppressed (${suppressed})`, metadata: { tool, cwd, suppressed, outcome: previous?.fact.outcome, ...previous?.fact.reason && { reason: previous.fact.reason }, ...suppressed === "cooling" && { retryAfterMs: Math.max(0, (previous?.retryAtMs ?? 0) - Date.now()) } } }); return false; } const started = performInstall(k, tool, cwd, spec); inFlight.set(k, started); try { return await started; } finally { inFlight.delete(k); } } async function performInstall(k, tool, cwd, spec) { let result; try { result = await safeSpawnAsync(spec.command, spec.args, { timeout: LAZY_INSTALL_TIMEOUT_MS, cwd, ...LAZY_INSTALL_IGNORES_AMBIENT_SIGNAL && { ignoreAmbientSignal: true } }); } catch (err) { result = { stdout: "", stderr: err?.message ?? String(err), status: null, error: err, failure: "spawn" }; } if (!result.error && result.status === 0) { attempts.set(k, { fact: { outcome: "succeeded" }, retryAtMs: 0, transientAttempts: 0 }); return true; } const classified = classifyProbeFailure(result, { command: spec.command, unclassifiedFailureOutcome: "transient" }); const durable = classified.outcome === "missing"; const reason = (result.error?.message ?? result.stderr ?? `exit ${result.status}`).trim().slice(0, 200); const settledPrevious = attempts.get(k); const transientAttempts = durable ? 0 : (settledPrevious?.transientAttempts ?? 0) + 1; const cooldownMs = durable ? 0 : installRetryDelayMs(transientAttempts); const retryAtMs = cooldownMs === 0 ? 0 : Date.now() + cooldownMs; attempts.set(k, { fact: { outcome: "failed", reason }, retryAtMs, transientAttempts }); logExtension({ subsystem: "install", message: `lazy-install ${tool} failed: ${reason}`, metadata: { tool, cwd, command: spec.command, cause: classified.cause, durable, transientAttempts, held: retryAtMs === 0, ...retryAtMs > 0 && { retryAfterMs: retryAtMs - Date.now() }, evidence: classified.evidence } }); return false; } async function tryLazyInstall(tool, cwd) { if (!assertInstallAllowed(`runner lazy install: ${tool}`)) return false; return runLazyInstall(tool, cwd, LAZY_INSTALL_SPECS[tool]); } async function tryLazyInstallForFormatter(tool, cwd) { if (!assertInstallAllowed(`formatter lazy install: ${tool}`)) return false; return runLazyInstall(tool, cwd, LAZY_INSTALL_SPECS[tool]); } export { getLazyInstallAttempt, resetLazyInstallAttempts, tryLazyInstall, tryLazyInstallForFormatter };