From ae0ae68e14e8bac44bef8f7ca83c8bfc01fc1d56 Mon Sep 17 00:00:00 2001 From: roboomp Date: Tue, 30 Jun 2026 20:21:10 +0000 Subject: [PATCH] fix(lsp): included ruff-only roots for venv lookup Extended Python local-bin gating to Ruff-only root marker files so Windows virtualenv Scripts launchers are found before PATH fallback. Fixes #3916 --- packages/coding-agent/src/lsp/config.ts | 2 +- .../test/tools/lsp-regressions.test.ts | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/coding-agent/src/lsp/config.ts b/packages/coding-agent/src/lsp/config.ts index 7e4b99658..be6d8949c 100644 --- a/packages/coding-agent/src/lsp/config.ts +++ b/packages/coding-agent/src/lsp/config.ts @@ -209,7 +209,7 @@ export function hasRootMarkers(cwd: string, markers: string[]): boolean { * Local bin directories to check before $PATH, ordered by priority. * Each entry maps a root marker to the bin directory to check. */ -const PYTHON_ROOT_MARKERS = ["pyproject.toml", "requirements.txt", "setup.py", "Pipfile"]; +const PYTHON_ROOT_MARKERS = ["pyproject.toml", "requirements.txt", "setup.py", "Pipfile", "ruff.toml", ".ruff.toml"]; const LOCAL_BIN_PATHS: Array<{ markers: string[]; binDir: string }> = [ // Node.js - check node_modules/.bin/ diff --git a/packages/coding-agent/test/tools/lsp-regressions.test.ts b/packages/coding-agent/test/tools/lsp-regressions.test.ts index f9bc59cc8..aa324b3d7 100644 --- a/packages/coding-agent/test/tools/lsp-regressions.test.ts +++ b/packages/coding-agent/test/tools/lsp-regressions.test.ts @@ -1101,6 +1101,34 @@ describe("lsp regressions", () => { } }); + it("detects Ruff in Windows virtualenv Scripts directories for Ruff-only roots", async () => { + const originalPlatform = process.platform; + Object.defineProperty(process, "platform", { value: "win32", configurable: true, writable: true }); + const whichSpy = vi.spyOn(Bun, "which").mockReturnValue(null); + + try { + for (const marker of ["ruff.toml", ".ruff.toml"] as const) { + const tempDir = TempDir.createSync("@omp-lsp-win32-ruff-marker-"); + try { + await Bun.write(path.join(tempDir.path(), marker), ""); + const scriptsDir = path.join(tempDir.path(), ".venv", "Scripts"); + await fs.promises.mkdir(scriptsDir, { recursive: true }); + const localRuff = path.join(scriptsDir, "ruff.exe"); + await Bun.write(localRuff, ""); + + const config = loadConfig(tempDir.path()); + expect(config.servers.ruff?.resolvedCommand).toBe(localRuff); + } finally { + tempDir.removeSync(); + } + } + expect(whichSpy).not.toHaveBeenCalledWith("ruff"); + } finally { + Object.defineProperty(process, "platform", { value: originalPlatform, configurable: true, writable: true }); + vi.restoreAllMocks(); + } + }); + it("detects tlaplus files for LSP startup and language ids", async () => { const tempDir = TempDir.createSync("@omp-lsp-tlaplus-"); const specPath = path.join(tempDir.path(), "Spec.tla");