fix(doctor): honor explicit Hopper launcher

This commit is contained in:
N0zoM1z0 2026-07-14 20:34:57 +00:00
parent 528c05e2fa
commit 9208592f41
2 changed files with 44 additions and 13 deletions

View File

@ -121,14 +121,16 @@ export const runDoctor = async (
},
),
);
const candidates = [
host.configuredHopperPath,
DEFAULT_HOPPER,
SYSTEM_LINUX_HOPPER,
linuxHopperLauncherPath(homedir()),
...(await host.manualHopperPaths()),
await host.brewHopperPath(),
].filter((value): value is string => value !== undefined);
const candidates =
host.configuredHopperPath === undefined
? [
DEFAULT_HOPPER,
SYSTEM_LINUX_HOPPER,
linuxHopperLauncherPath(homedir()),
...(await host.manualHopperPaths()),
await host.brewHopperPath(),
].filter((value): value is string => value !== undefined)
: [host.configuredHopperPath];
let hopperPath: string | undefined;
for (const candidate of new Set(candidates))
if (await host.executable(candidate)) {
@ -136,11 +138,21 @@ export const runDoctor = async (
break;
}
checks.push(
check("hopper", hopperPath !== undefined, hopperPath, {
remediation:
"Run rea setup to install Hopper, or set HOPPER_LAUNCHER_PATH.",
classification: "missing_analysis_engine",
}),
check(
"hopper",
hopperPath !== undefined,
hopperPath ?? host.configuredHopperPath,
{
remediation:
host.configuredHopperPath === undefined
? "Run rea setup to install Hopper, or set HOPPER_LAUNCHER_PATH."
: "Unset or update HOPPER_LAUNCHER_PATH to an executable Hopper launcher.",
classification:
host.configuredHopperPath === undefined
? "missing_analysis_engine"
: "config_drift",
},
),
);
if (host.platform === "linux" && hopperPath !== undefined)
checks.push(

View File

@ -60,6 +60,25 @@ describe("doctor", () => {
expect(result.healthy).toBe(true);
});
it("does not fall back when the configured Hopper launcher is invalid", async () => {
const configuredPath = "/invalid/custom/hopper";
const result = await runDoctor(
undefined,
host({ configuredHopperPath: configuredPath }),
);
expect(result.hopperPath).toBeUndefined();
expect(result.healthy).toBe(false);
expect(result.checks.find(({ name }) => name === "hopper")).toEqual({
name: "hopper",
ok: false,
classification: "config_drift",
detail: configuredPath,
remediation:
"Unset or update HOPPER_LAUNCHER_PATH to an executable Hopper launcher.",
});
});
it("distinguishes stale skills, path shadowing, and unobservable live state", async () => {
const result = await runDoctor(
undefined,