diff --git a/src/lib/onboard/windows-host-ollama.test.ts b/src/lib/onboard/windows-host-ollama.test.ts new file mode 100644 index 0000000000..da12abcef8 --- /dev/null +++ b/src/lib/onboard/windows-host-ollama.test.ts @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { afterEach, describe, expect, it, vi } from "vitest"; + +const runCapture = vi.fn<(cmd: readonly string[]) => string>(() => ""); + +vi.mock("../runner", () => ({ + runCapture: (cmd: readonly string[]) => runCapture(cmd), +})); + +vi.mock("../platform", () => ({ + isWsl: vi.fn(() => true), +})); + +import { isWsl } from "../platform"; +import { detectWindowsHostOllama } from "./windows-host-ollama"; + +describe("detectWindowsHostOllama", () => { + afterEach(() => { + vi.clearAllMocks(); + vi.mocked(isWsl).mockReturnValue(true); + }); + + it("detects installed-but-not-running Ollama via known install path (#4066)", () => { + const knownPath = "C:\\Users\\tester\\AppData\\Local\\Programs\\Ollama\\ollama.exe"; + runCapture.mockImplementation((command: readonly string[]) => { + const cmd = command.join(" "); + if (cmd.includes("Get-Command ollama.exe")) return ""; + if (cmd.includes("Get-Process ollama") && cmd.includes("Path")) return ""; + if (cmd.includes("Get-Process ollama") && cmd.includes("Id")) return ""; + if (cmd.includes("Test-Path -LiteralPath")) return knownPath; + if (cmd.includes("Get-NetTCPConnection")) return ""; + return ""; + }); + + expect(detectWindowsHostOllama()).toEqual({ + installed: true, + installedPath: knownPath, + loopbackOnly: false, + }); + }); +}); diff --git a/src/lib/onboard/windows-host-ollama.ts b/src/lib/onboard/windows-host-ollama.ts index e131c4d5ee..a496d34887 100644 --- a/src/lib/onboard/windows-host-ollama.ts +++ b/src/lib/onboard/windows-host-ollama.ts @@ -55,12 +55,9 @@ function probeInstalledPath(): string { // lookup (#3949). const processPath = powershell(GET_PROCESS_OLLAMA_PATH); if (processPath.length > 0) return processPath; - // Some WSL-launched PowerShell sessions can see the Windows ollama PID - // but cannot read the Path property. Only after observing the live - // daemon, fall back to fixed installer locations so the restart path - // still has an explicit executable to launch. - const pid = powershell(GET_PROCESS_OLLAMA_ID); - if (!pid) return ""; + // Silent installs often land in fixed locations without updating PATH or + // leaving a running daemon to probe. Check those paths even when no PID is + // visible so WSL onboarding offers Start instead of Install (#4066). return powershell(GET_KNOWN_OLLAMA_INSTALL_PATH); }