From 32dda0c19eee5ddf91a35d9e21374f9cb111b07d Mon Sep 17 00:00:00 2001 From: N0zoM1z0 <1705004398@qq.com> Date: Fri, 17 Jul 2026 01:15:31 +0800 Subject: [PATCH] feat(doctor): admit the Windows x64 Ghidra boundary --- src/application/Doctor.ts | 9 ++++++--- tests/doctor.test.ts | 33 ++++++++++++++++++++++++++++++++- tests/ghidraDoctor.test.ts | 26 +++++++++++++++++++++++++- 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/application/Doctor.ts b/src/application/Doctor.ts index 919c84fe9..2baaa2c58 100644 --- a/src/application/Doctor.ts +++ b/src/application/Doctor.ts @@ -64,6 +64,7 @@ export interface DoctorProviderInspection { /** Read-only host capabilities required by diagnostics. */ export interface DoctorHost { readonly platform: NodeJS.Platform; + readonly architecture: NodeJS.Architecture; readonly nodeVersion: string; readonly configuredHopperPath?: string; readonly configuredIlspyCmdPath?: string; @@ -141,18 +142,19 @@ export const runDoctor = async ( host.platform === "linux" ? await host.linuxDistribution() : undefined; const supportedHost = (host.platform === "darwin" && macosMajor >= 12) || - (host.platform === "linux" && linuxDistribution?.supported === true); + (host.platform === "linux" && linuxDistribution?.supported === true) || + (host.platform === "win32" && host.architecture === "x64"); checks.push( check( "host", supportedHost, macosVersion ?? (linuxDistribution === undefined - ? host.platform + ? `${host.platform} ${host.architecture}` : `${linuxDistribution.id} ${linuxDistribution.versionId ?? "unknown"}`), { remediation: - "REA supports macOS 12+, Ubuntu 24.04+, Fedora 41+, and 64-bit Arch Linux.", + "REA supports macOS 12+, Ubuntu 24.04+, Fedora 41+, 64-bit Arch Linux, and the experimental Windows x64 Ghidra P0 boundary.", classification: "unsupported_host", }, ), @@ -357,6 +359,7 @@ export const systemDoctorHost = ( options: SystemDoctorHostOptions = {}, ): DoctorHost => ({ platform: process.platform, + architecture: process.arch, nodeVersion: process.versions.node, ...(process.env.HOPPER_LAUNCHER_PATH === undefined ? {} diff --git a/tests/doctor.test.ts b/tests/doctor.test.ts index 602da2dc0..b3cd8be6b 100644 --- a/tests/doctor.test.ts +++ b/tests/doctor.test.ts @@ -5,6 +5,7 @@ import { PRODUCT_IDENTITY } from "../src/identity.js"; const host = (overrides: Partial = {}): DoctorHost => ({ platform: "darwin", + architecture: "x64", nodeVersion: "24.18.0", macosVersion: () => Promise.resolve("12.0"), linuxDistribution: () => Promise.resolve(undefined), @@ -40,7 +41,7 @@ describe("doctor", () => { ), ).toEqual({ node: "Install Node.js 22.19+ or 24.11+.", - host: "REA supports macOS 12+, Ubuntu 24.04+, Fedora 41+, and 64-bit Arch Linux.", + host: "REA supports macOS 12+, Ubuntu 24.04+, Fedora 41+, 64-bit Arch Linux, and the experimental Windows x64 Ghidra P0 boundary.", hopper: "Run rea setup to install Hopper, or set HOPPER_LAUNCHER_PATH.", target: "Supply a readable local app or program path.", }); @@ -56,6 +57,36 @@ describe("doctor", () => { expect(result.checks.find(({ name }) => name === "host")?.ok).toBe(false); }, ); + + it("admits only the experimental Windows x64 host boundary", async () => { + const windows = await runDoctor( + undefined, + host({ + platform: "win32", + architecture: "x64", + macosVersion: () => Promise.resolve(undefined), + executable: () => Promise.resolve(false), + }), + ); + const arm = await runDoctor( + undefined, + host({ + platform: "win32", + architecture: "arm64", + macosVersion: () => Promise.resolve(undefined), + executable: () => Promise.resolve(false), + }), + ); + + expect(windows.checks.find(({ name }) => name === "host")).toMatchObject({ + ok: true, + detail: "win32 x64", + }); + expect(arm.checks.find(({ name }) => name === "host")).toMatchObject({ + ok: false, + detail: "win32 arm64", + }); + }); it("detects a manual configured Hopper before Homebrew", async () => { const result = await runDoctor( undefined, diff --git a/tests/ghidraDoctor.test.ts b/tests/ghidraDoctor.test.ts index fd798614e..8130afff8 100644 --- a/tests/ghidraDoctor.test.ts +++ b/tests/ghidraDoctor.test.ts @@ -30,12 +30,13 @@ const inspection = ( options: { readonly installDir?: string; readonly architecture?: NodeJS.Architecture; + readonly platform?: NodeJS.Platform; } = { installDir: INSTALL }, overrides: Partial = {}, ): GhidraInstallationInspection => inspectGhidraInstallation( { - platform: "linux", + platform: options.platform ?? "linux", architecture: options.architecture ?? "x64", ...(options.installDir === undefined ? {} @@ -49,6 +50,7 @@ const doctorHost = ( hopperAvailable = false, ): DoctorHost => ({ platform: "linux", + architecture: "x64", nodeVersion: "24.18.0", macosVersion: () => Promise.resolve(undefined), linuxDistribution: () => @@ -98,6 +100,28 @@ describe("Ghidra doctor integration", () => { }); }); + it("accepts the experimental Windows x64 Ghidra provider boundary", async () => { + const ghidra = inspection({ + installDir: "C:\\tools\\ghidra_12.1.2_PUBLIC", + platform: "win32", + }); + const result = await runDoctor(undefined, { + ...doctorHost(ghidra), + platform: "win32", + architecture: "x64", + linuxDistribution: () => Promise.resolve(undefined), + }); + + expect(result.healthy).toBe(true); + expect(result.checks.find(({ name }) => name === "host")).toMatchObject({ + ok: true, + detail: "win32 x64", + }); + expect(result.checks.find(({ name }) => name === "ghidra")).toMatchObject({ + ok: true, + }); + }); + it.each([ [ "bad installation",