Merge remote-tracking branch 'origin/main' into fix/main-red-ida-javascript-tests

This commit is contained in:
Kaoru0822 2026-10-14 02:13:07 +00:00
commit c0e4aa91bb
5 changed files with 84 additions and 2 deletions

View File

@ -10,6 +10,12 @@ Start a JEB client that serves MCP and point REA at it:
- In the JEB GUI client, start the MCP server from the _File_ menu (or via the VIBRE assistant).
- Headless, use JEB's documented programmatic route (`JebMcpServerInstance` from the JEB API) with the JEB client on your classpath; JEB 5.48's `-c` headless mode does not accept `--mcp` directly.
For setup registration, set `REA_JEB_MCP_URL` in the REA process environment
before running `rea setup`. The approved setup plan preserves the exact selected
URL after validating its syntax. That validation does not establish that the
JEB service is reachable or that a project is open; use the existing
`inspect-jeb-client` command for a read-only service query.
Verified against JEB 5.48.0 (Linux x64, licensed build) serving `jeb-mcp-server` 1.3.0 over streamable HTTP.
## Operations

View File

@ -99,6 +99,8 @@ export interface DoctorHost {
brewHopperPath(): Promise<string | undefined>;
manualHopperPaths(): Promise<readonly string[]>;
providerInspections?(): Promise<readonly DoctorProviderInspection[]>;
/** Validated provider settings preserved by setup, independent of readiness. */
providerRegistrationEnvironment?(): Readonly<Record<string, string>>;
installationPaths?(): Promise<readonly string[]>;
installedSkillIdentity?(
clientIds: readonly string[],
@ -368,6 +370,9 @@ export interface SystemDoctorHostOptions {
readonly providerInspections?: () => Promise<
readonly DoctorProviderInspection[]
>;
readonly providerRegistrationEnvironment?: () => Readonly<
Record<string, string>
>;
readonly linuxDemoRuntimeCheck?: () => Promise<DoctorCheck>;
}
@ -478,6 +483,12 @@ export const systemDoctorHost = (
...(options.providerInspections === undefined
? {}
: { providerInspections: options.providerInspections }),
...(options.providerRegistrationEnvironment === undefined
? {}
: {
providerRegistrationEnvironment:
options.providerRegistrationEnvironment,
}),
async ilspyCmdVersion(path) {
try {
await access(path, constants.X_OK);

View File

@ -175,6 +175,7 @@ export const systemSetupHost = (
...providerRegistrationEnvironment(
diagnosis.providerInspections ?? [],
),
...doctorHost.providerRegistrationEnvironment?.(),
...(diagnosis.hopperPath === undefined
? {}
: { HOPPER_LAUNCHER_PATH: diagnosis.hopperPath }),

View File

@ -7,14 +7,23 @@ import { fileURLToPath } from "node:url";
import { inspectJadxProvider } from "./android/JadxDoctor.js";
import { inspectSystemGhidraProvider } from "./ghidra/GhidraDoctor.js";
import { inspectIdaRegistration } from "./ida/IdaDoctor.js";
import { parseJebMcpEndpoint } from "./jeb/JebMcpEndpoint.js";
import { selectLinuxPrivateDisplayStrategy } from "./hopper/LinuxPrivateDisplayProbe.js";
/** Compose provider diagnostics at the outer CLI adapter boundary. */
export const createSystemDoctorHost = (
environment: Readonly<NodeJS.ProcessEnv> = process.env,
): DoctorHost =>
systemDoctorHost({
): DoctorHost => {
const selectedJebEndpoint = environment.REA_JEB_MCP_URL;
const selectedJebRegistrationEnvironment: Readonly<Record<string, string>> =
selectedJebEndpoint !== undefined &&
selectedJebEndpoint.length > 0 &&
parseJebMcpEndpoint(selectedJebEndpoint).ok
? { REA_JEB_MCP_URL: selectedJebEndpoint }
: {};
return systemDoctorHost({
environment,
providerRegistrationEnvironment: () => selectedJebRegistrationEnvironment,
providerInspections: async () => [
await inspectSystemGhidraProvider(environment),
inspectIdaRegistration(environment.REA_IDA_MCP_CONFIG),
@ -22,6 +31,7 @@ export const createSystemDoctorHost = (
],
linuxDemoRuntimeCheck: () => inspectLinuxPrivateDisplay(environment),
});
};
const HOPPER_DEMO_HELPER_PATH = fileURLToPath(
new URL("../scripts/hopper-demo-x11.py", import.meta.url),

View File

@ -92,6 +92,60 @@ it("composes provider diagnostics from selected configuration rather than ambien
expect(JSON.stringify(inspections)).not.toContain("/ambient/");
});
it("preserves a validated selected JEB endpoint in setup registrations without claiming live readiness", async () => {
const root = await mkdtemp(join(tmpdir(), "rea-jeb-setup-"));
const endpoint = "http://127.0.0.1:8425/mcp/";
const ambientEndpoint = "http://127.0.0.1:8426/mcp";
vi.stubEnv("REA_JEB_MCP_URL", ambientEndpoint);
try {
const environment = {
HOME: root,
USERPROFILE: root,
CODEX_HOME: join(root, "codex"),
REA_JEB_MCP_URL: endpoint,
};
const doctorHost = createSystemDoctorHost(environment);
const setupHost = systemSetupHost(doctorHost, environment);
const state = await setupHost.initialSetupState();
expect(state.providerEnvironment).toHaveProperty(
"REA_JEB_MCP_URL",
endpoint,
);
const planned = await runSetup(
{
...options(false),
dryRun: true,
clientIds: ["codex"],
installSkill: false,
},
setupHost,
);
expect(planned.status).toBe("planned");
expect(JSON.stringify(planned.plannedActions)).toContain(endpoint);
expect(JSON.stringify(planned.plannedActions)).not.toContain(
ambientEndpoint,
);
expect(
createSystemDoctorHost({}).providerRegistrationEnvironment?.(),
).toEqual({});
expect(
createSystemDoctorHost({
REA_JEB_MCP_URL: "http://127.0.0.1:8425/mcp",
}).providerRegistrationEnvironment?.(),
).toEqual({ REA_JEB_MCP_URL: "http://127.0.0.1:8425/mcp" });
expect(
createSystemDoctorHost({
REA_JEB_MCP_URL: "https://example.com/mcp",
}).providerRegistrationEnvironment?.(),
).toEqual({});
} finally {
vi.unstubAllEnvs();
await rm(root, { recursive: true, force: true });
}
});
it("passes only selected environment to updater subprocesses and drops npm invocation identity", async () => {
vi.stubEnv("REA_UPDATE_MARKER", "ambient");
const result = await runUpdateCommand(