mirror of
https://github.com/morluto/rea
synced 2026-10-25 22:08:11 -04:00
647717c050
* perf(javascript): reuse the source-analysis worker within a process Each analyze-javascript-application call started a new Node worker. That startup, not fixture IO or the shared CLI session, dominated the slow loader-review and factory-completion files. Park one healthy worker on the artifact resource scope and on the CLI process. Stop it when the scope, session, or one-shot process ends. Do not reuse after failure, cancellation, or a different heap or timeout. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(cli): close the JavaScript worker when dispatch throws Minimal dispatcher runtimes now export a no-op closeCliJavaScriptResources, and CLI dispatch plus output rendering always await that cleanup. A dispatch failure and a cleanup failure are both reported. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(artifacts): report close-hook failures with retained cleanup When retained cleanup and the scope close hook both fail, the close error keeps both causes and both resource labels. The pending owners and the hook stay registered so the next close retries each path. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(javascript): stop a replaced analysis worker before the next one starts A heap or timeout change now closes the parked worker before constructing its replacement. The scope retains that process only when the close fails. Co-authored-by: morluto <morluto@users.noreply.github.com> * style: format worker-reuse close and launch helpers Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(cli): report a failed JavaScript worker shutdown before exit Share one in-flight close and drop the CLI scope only after it succeeds, so a later caller retries a worker that is still owned. The one-shot exit callback writes that failure and exits non-zero, while a closed stdout pipe still exits 141. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(javascript): keep a worker parked during an overlapping limit change Claim the scope slot only when it is still empty after the replaced worker closes. A concurrent analysis that parked another healthy worker keeps that process, and the extra worker is closed through its own port. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(artifacts): run later close hooks when an earlier hook fails Run every registered close hook on each close. One failure is returned unchanged, and several failures are aggregated so a later hook is not skipped. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(javascript): fail a limit change when the previous worker stays alive A failed close used to be retained and then ignored, so MCP could return a successful analysis while the old process and its replacement were both owned. The request now fails before the replacement is constructed, and the still-live worker stays owned for a later close. Co-authored-by: morluto <morluto@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: morluto <morluto@users.noreply.github.com>
170 lines
8.6 KiB
TypeScript
170 lines
8.6 KiB
TypeScript
import { registerNativeFunctionMatchingCommands } from "./cli/nativeFunctionMatchingCommands.js";
|
|
import { registerCaptureCommands } from "./cli/captureCommands.js";
|
|
import { registerSignalCommands } from "./cli/signalCommands.js";
|
|
import { registerWasmCommands } from "./cli/wasmCommands.js";
|
|
import { snapshotEnvironment } from "./process/snapshotEnvironment.js";
|
|
import { createDirectAnalysis } from "./composition/directAnalysis.js";
|
|
import { registerEvmCommands } from "./cli/evmCommands.js";
|
|
import { registerDesktopApplicationCommands } from "./cli/desktopApplicationCommands.js";
|
|
import { registerGoCommands } from "./cli/goCommands.js";
|
|
import { registerModelCommands } from "./cli/modelCommands.js";
|
|
import { registerIl2cppCommands } from "./cli/il2cppCommands.js";
|
|
import { registerRustCommands } from "./cli/rustCommands.js";
|
|
import { registerSqliteCommands } from "./cli/sqliteCommands.js";
|
|
import { registerAnalysisViewCommands } from "./cli/analysisViewCommands.js";
|
|
import { registerBinaryDiagnosticsCommands } from "./cli/binaryDiagnosticsCommands.js";
|
|
import { registerFridaCommands } from "./cli/fridaCommands.js";
|
|
import type { FridaInstrumentationPort } from "./application/frida/FridaInstrumentationPort.js";
|
|
import { Cli } from "incur";
|
|
import { normalizeCliArguments } from "./cliOutput.js";
|
|
|
|
import { createLogger, parseLogLevel } from "./logger.js";
|
|
import { projectAnalysisError } from "./domain/analysisErrorProjection.js";
|
|
import { PRODUCT_IDENTITY } from "./identity.js";
|
|
import { npxRegistrationCommand } from "./application/ClientRegistrationIdentity.js";
|
|
import { registerSetupCommands } from "./cli/setupCommands.js";
|
|
import { registerCoreAnalysisCommands } from "./cli/coreAnalysisCommands.js";
|
|
import { registerUtilityCommands } from "./cli/utilityCommands.js";
|
|
import { registerArtifactCommands } from "./cli/artifactCommands.js";
|
|
import { registerManagedCommands } from "./cli/managedCommands.js";
|
|
import { registerFirmwareCommands } from "./cli/firmwareCommands.js";
|
|
import { registerAndroidCommands } from "./cli/androidCommands.js";
|
|
import { registerApktoolCommands } from "./cli/apktoolCommands.js";
|
|
import { registerPcapCommands } from "./cli/pcapCommands.js";
|
|
import { registerFlutterCommands } from "./cli/flutterCommands.js";
|
|
import { registerJebCommands } from "./cli/jebCommands.js";
|
|
import { registerAdbCommands } from "./cli/adbCommands.js";
|
|
import { registerEvidenceCommands } from "./cliEvidenceCommands.js";
|
|
import { registerEnvironmentCommands } from "./cli/environmentCommands.js";
|
|
import { registerProcessCommands } from "./cli/processCommands.js";
|
|
import { registerBrowserCommands } from "./cli/browserCommands.js";
|
|
import { registerWebScriptCommands } from "./cli/webScriptCommands.js";
|
|
import { registerWebModuleCommands } from "./cli/webModuleCommands.js";
|
|
import { registerWebSourceLocationCommands } from "./cli/webSourceLocationCommands.js";
|
|
import { registerWebRuntimeCommands } from "./cli/webRuntimeCommands.js";
|
|
import { registerWebNetworkCaptureCommands } from "./cli/webNetworkCaptureCommands.js";
|
|
import { registerJavaScriptRecoveryCommands } from "./cli/javascriptRecoveryCommands.js";
|
|
import { registerAdvancedBrowserCommands } from "./cli/browserAdvancedCommands.js";
|
|
import { registerBrowserScenarioCommands } from "./cliBrowserScenarioCommands.js";
|
|
import { registerElectronCommands } from "./cli/electronCommands.js";
|
|
import { registerJavaScriptRuntimeObservationCommands } from "./cliJavaScriptRuntimeCommands.js";
|
|
import { registerApplicationCommands } from "./cli/applicationCommands.js";
|
|
import { presentOmittableDefaults } from "./cli/omittableDefaults.js";
|
|
import type { CliInstance } from "./cli/types.js";
|
|
import {
|
|
streamCliCommandResults,
|
|
type CliResultOutput,
|
|
} from "./cli/cliResultOutput.js";
|
|
import { registerReverseEngineeringCommands } from "./cli/reverseEngineeringCommands.js";
|
|
import { registerCutterCommands } from "./cli/cutterCommands.js";
|
|
|
|
export { closeCliJavaScriptResources } from "./cli/javascriptApplicationAnalysis.js";
|
|
|
|
/**
|
|
* Describe CLI settings that are invalid before any command runs, as MCP does.
|
|
* Keep this aligned with PROCESS_START_CONFIGURATION_SETTINGS.
|
|
*/
|
|
export const cliConfigurationError = (
|
|
selectedEnvironment: Readonly<Record<string, string | undefined>>,
|
|
): string | undefined => {
|
|
const value = selectedEnvironment.REA_LOG_LEVEL;
|
|
if (value === undefined) return undefined;
|
|
const level = parseLogLevel(value);
|
|
return level.ok ? undefined : projectAnalysisError(level.error).message;
|
|
};
|
|
|
|
/**
|
|
* Build the one-shot Incur CLI without starting Hopper at import time.
|
|
* Analysis commands acquire and close their own sessions; bare `mcp` and
|
|
* `--mcp` are intercepted by the executable dispatcher before this module loads.
|
|
*/
|
|
export const createCli = (
|
|
selectedEnvironment: Readonly<
|
|
Record<string, string | undefined>
|
|
> = process.env,
|
|
resultOutput?: CliResultOutput,
|
|
fridaInstrumentation?: FridaInstrumentationPort,
|
|
): CliInstance => {
|
|
const environment = snapshotEnvironment(selectedEnvironment);
|
|
const analysis = createDirectAnalysis(environment);
|
|
// The executable reports an invalid level before every command except doctor.
|
|
// Doctor keeps going so its readiness report can name REA_LOG_LEVEL.
|
|
const level =
|
|
environment.REA_LOG_LEVEL === undefined
|
|
? undefined
|
|
: parseLogLevel(environment.REA_LOG_LEVEL);
|
|
const logger = createLogger(
|
|
"cli",
|
|
level?.ok === true ? level.value : "silent",
|
|
);
|
|
const cli = Cli.create(PRODUCT_IDENTITY.cliBinary, {
|
|
version: PRODUCT_IDENTITY.packageVersion,
|
|
description: "Reverse engineer anything from your terminal or agent.",
|
|
mcp: {
|
|
command: npxRegistrationCommand().join(" "),
|
|
instructions:
|
|
"Ask what software, artifact, protocol, or behavior the user wants to understand, then choose the available investigation capabilities that can produce evidence.",
|
|
},
|
|
sync: false,
|
|
update: {
|
|
// Incur's update:false only suppresses notices. Reject its explicit
|
|
// installer so ambiguous flags cannot bypass REA's verified workflow.
|
|
install: () => {
|
|
throw new Error(
|
|
"Use 'rea update' to update the identified installation. The '--update' alias accepts only global output flags.",
|
|
);
|
|
},
|
|
},
|
|
});
|
|
|
|
registerSetupCommands(cli, logger, environment);
|
|
registerReverseEngineeringCommands(cli, logger, environment);
|
|
registerCutterCommands(cli, logger, environment);
|
|
registerCoreAnalysisCommands(cli, logger, analysis.runDirectAnalysis);
|
|
registerUtilityCommands(cli, logger, environment, analysis);
|
|
registerWasmCommands(cli, logger, environment);
|
|
registerCaptureCommands(cli, logger, environment);
|
|
registerSignalCommands(cli, logger, environment);
|
|
registerEvmCommands(cli, logger, environment);
|
|
registerDesktopApplicationCommands(cli, logger);
|
|
registerGoCommands(cli, logger);
|
|
registerIl2cppCommands(cli, logger);
|
|
registerModelCommands(cli, logger);
|
|
registerRustCommands(cli, logger);
|
|
registerSqliteCommands(cli, logger, environment);
|
|
registerArtifactCommands(cli, logger, analysis.runProviderAnalysis);
|
|
registerManagedCommands(cli, logger, analysis.runProviderAnalysis);
|
|
registerAndroidCommands(cli, logger, environment);
|
|
registerApktoolCommands(cli, logger, environment);
|
|
registerPcapCommands(cli, logger, environment);
|
|
registerFlutterCommands(cli, logger);
|
|
registerJebCommands(cli, logger, environment);
|
|
registerAdbCommands(cli, logger, environment);
|
|
registerFirmwareCommands(cli, logger, environment);
|
|
registerBinaryDiagnosticsCommands(cli, logger, environment);
|
|
registerAnalysisViewCommands(cli, logger);
|
|
registerNativeFunctionMatchingCommands(cli, logger);
|
|
registerFridaCommands(cli, logger, fridaInstrumentation);
|
|
registerEvidenceCommands(cli, logger);
|
|
registerEnvironmentCommands(cli, logger, environment);
|
|
registerProcessCommands(cli, logger, environment);
|
|
registerBrowserCommands(cli, logger);
|
|
registerWebScriptCommands(cli, logger);
|
|
registerWebModuleCommands(cli, logger, environment);
|
|
registerWebSourceLocationCommands(cli, logger, environment);
|
|
registerWebRuntimeCommands(cli, logger);
|
|
registerWebNetworkCaptureCommands(cli, logger, environment);
|
|
registerJavaScriptRecoveryCommands(cli, logger, environment);
|
|
registerAdvancedBrowserCommands(cli, logger);
|
|
registerBrowserScenarioCommands(cli, logger, environment);
|
|
registerElectronCommands(cli, logger, environment);
|
|
registerJavaScriptRuntimeObservationCommands(cli, logger);
|
|
registerApplicationCommands(cli, logger);
|
|
presentOmittableDefaults(cli);
|
|
if (resultOutput !== undefined) streamCliCommandResults(cli, resultOutput);
|
|
const serve = cli.serve.bind(cli);
|
|
cli.serve = (arguments_ = process.argv.slice(2), options) =>
|
|
serve(normalizeCliArguments(arguments_), options);
|
|
return cli;
|
|
};
|