mirror of
https://github.com/morluto/rea.git
synced 2026-11-14 18:52:48 +00:00
* fix(cli): validate named inputs before target admission * fix(mcp): preserve valid inputs when advertised schema references widen * test(inputs): reach session behavior with admitted inputs One-shot admission now rejects incomplete requests before a session exists. Lifecycle tests supply the required fields, and unknown arguments are rejected before provider issues are retained. * fix(cli): preserve Electron fuse path spelling Anchor relative fuse paths without stripping dot segments, and let an empty path reach the operation so it still reports invalid_request. * fix(cli): reject outline-depth unless detail is summary The advertised schema already required detail summary whenever outline-depth was present. The parser still applied the full default and accepted that combination, so its output failed the same schema. Parsing now rejects it before the command runs. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
136 lines
5.1 KiB
TypeScript
136 lines
5.1 KiB
TypeScript
import { localPathStringSchema } from "../domain/localPath.js";
|
|
import { absoluteCallerPath } from "../filesystem/callerPath.js";
|
|
import { z } from "incur";
|
|
import { AnalysisInputError } from "../domain/analysisErrorCore.js";
|
|
import { err } from "../domain/result.js";
|
|
import { createIl2cppMetadataService } from "../composition/il2cpp.js";
|
|
import { CLI_COMMANDS } from "../cliCommandNames.js";
|
|
import { logCliCommand } from "../cliLogging.js";
|
|
import type { Logger } from "pino";
|
|
import type { CliInstance } from "./types.js";
|
|
import { withCommandCancellation } from "./commandCancellation.js";
|
|
import {
|
|
analysisEvidenceDeliveryOptions,
|
|
deliverCliAnalysisEvidence,
|
|
} from "./analysisEvidenceDelivery.js";
|
|
|
|
/** CLI and MCP share inspection; one-shot summaries preserve a complete Evidence file. */
|
|
export const registerIl2cppCommands = (
|
|
cli: CliInstance,
|
|
logger: Logger,
|
|
): void => {
|
|
cli.command(CLI_COMMANDS.inspectIl2cppMetadata, {
|
|
description:
|
|
"Inventory IL2CPP global-metadata.dat names, owners and string literals, optionally linking method addresses from the native binary",
|
|
args: z.object({
|
|
path: localPathStringSchema.describe(
|
|
"Local global-metadata.dat (version 24, 27, 29, 31 or 39)",
|
|
),
|
|
}),
|
|
options: z
|
|
.object({
|
|
...analysisEvidenceDeliveryOptions,
|
|
binary: localPathStringSchema
|
|
.optional()
|
|
.describe(
|
|
"Matching native binary (Mach-O GameAssembly.dylib, PE GameAssembly.dll or ELF libil2cpp.so) to link method addresses; read only",
|
|
),
|
|
architecture: z
|
|
.enum(["arm64", "amd64"])
|
|
.optional()
|
|
.describe("Slice of a universal Mach-O binary"),
|
|
genericInstances: z
|
|
.boolean()
|
|
.optional()
|
|
.describe(
|
|
"Also link generic method instances (Type<Args>$$Method<Args>) and include them in --ghidra-seeds; needs --binary",
|
|
),
|
|
ghidraSeeds: localPathStringSchema
|
|
.optional()
|
|
.describe(
|
|
"Also write REA_GHIDRA_SEED_FILE function seeds named Type$$Method for every linked method; needs --binary",
|
|
),
|
|
seedBase: z
|
|
.string()
|
|
.regex(/^0x[0-9a-fA-F]{1,16}$/u)
|
|
.optional()
|
|
.describe(
|
|
"Address Ghidra loads the binary at; seeds are seed-base + RVA (default: Ghidra's loader default, 0x100000 for an ELF linked at 0, else the link base)",
|
|
),
|
|
})
|
|
.meta({
|
|
dependentRequired: {
|
|
architecture: ["binary"],
|
|
ghidraSeeds: ["binary"],
|
|
seedBase: ["ghidraSeeds"],
|
|
},
|
|
if: {
|
|
properties: { genericInstances: { const: true } },
|
|
required: ["genericInstances"],
|
|
},
|
|
then: { required: ["binary"] },
|
|
}),
|
|
run: ({ args, options }) =>
|
|
withCommandCancellation((signal) =>
|
|
logCliCommand(logger, CLI_COMMANDS.inspectIl2cppMetadata, async () => {
|
|
const service = createIl2cppMetadataService();
|
|
return deliverCliAnalysisEvidence({
|
|
callerInputPath: args.path,
|
|
...(options.binary === undefined
|
|
? {}
|
|
: { callerInputPaths: { binary_path: options.binary } }),
|
|
run: () => {
|
|
const input = {
|
|
path: absoluteCallerPath(args.path),
|
|
detail: "complete" as const,
|
|
...(options.binary === undefined
|
|
? {}
|
|
: { binary_path: absoluteCallerPath(options.binary) }),
|
|
...(options.architecture === undefined
|
|
? {}
|
|
: { binary_architecture: options.architecture }),
|
|
...(options.genericInstances === true
|
|
? { generic_instances: true }
|
|
: {}),
|
|
};
|
|
if (options.ghidraSeeds !== undefined)
|
|
return service.inspectWithGhidraSeeds(
|
|
input,
|
|
{
|
|
path: absoluteCallerPath(options.ghidraSeeds),
|
|
...(options.seedBase === undefined
|
|
? {}
|
|
: { base: options.seedBase }),
|
|
},
|
|
{ signal },
|
|
);
|
|
if (options.seedBase !== undefined)
|
|
return Promise.resolve(
|
|
err(
|
|
new AnalysisInputError(
|
|
"inspect_il2cpp_metadata",
|
|
undefined,
|
|
[
|
|
{
|
|
path: ["seed_base"],
|
|
reason: "invalid_value",
|
|
message: "--seed-base requires --ghidra-seeds.",
|
|
},
|
|
],
|
|
),
|
|
),
|
|
);
|
|
return service.inspect(input, { signal });
|
|
},
|
|
service,
|
|
providerId: "il2cpp-metadata",
|
|
operation: "inspect_il2cpp_metadata",
|
|
signal,
|
|
detail: options.detail,
|
|
evidenceOutput: options.evidence_output,
|
|
});
|
|
}),
|
|
),
|
|
});
|
|
};
|