Files
reverse-engineering-anything/src/cli/analysisSelector.ts
T
morluto 4eafd9dee5 refactor(cli): project core native commands with open_binary target options (#10736)
* refactor(cli): project core native commands with open_binary target options

A session target's opening fields may now be caller paths, admitted
resolved and passed on as the caller spelled them, and a union of text
forms such as the provider selector renders as one argv token.

nativeTarget declares a native executable opened with open_binary's
format, architecture, entry point and provider fields, plus the snapshot
where a command loads one. runDirectOnTarget runs an operation on that
target through runDirectAnalysis, with Evidence delivery when declared.

Eleven core native commands are now derived from their contracts. Their
inputs are admitted by the service's contract parse, which replaces the
CLI's copies of the byte-pattern and data-type selector checks.
inspect-native-dispatch-metadata now exposes the contract's Objective-C
class import address fields.

* fix(cli): read core native contracts from their contract groups so startup stays lazy

* refactor(cli): project procedure-references and inspect-native-api with named selector options (#10738)

* refactor(cli): project procedure-references and inspect-native-api with named selector options

A contract projection may let the caller give a positional selector with
a named option instead, for values that begin with a dash. The positional
becomes optional; equal values agree (native addresses by identity), and
different values, or neither for a required field, are refused before the
target is opened. selectCliAnalysisSelector owns that rule and returns a
Result; resolveCliAnalysisSelector remains for the hand-written core
binary commands.

procedure-references and inspect-native-api are now derived from their
contracts on the native session target, which completes the core native
family.

* fix(cli): refuse empty named and positional selectors before opening the target

* refactor(cli): project inspect, xrefs, trace, function and instructions from their contracts (#10747)

The five core binary commands are derived from their contracts on the
native session target with the snapshot option, using named selector
options for the procedure, address and query.

A selector projection may require a selector the contract lets the MCP
caller omit: xrefs' address defaults to Hopper's cursor, which a one-shot
CLI command does not have. A selector names one object, so neither
spelling may be empty, as before, even where the contract's text admits
it.

open_binary's pairing rules now refuse an unpaired --target-format,
--architecture or --entry-point for inspect before the target is opened,
naming the CLI key.

* fix(cli): read core binary contracts from their contract groups so startup stays lazy
2026-11-15 21:32:33 +08:00

92 lines
3.2 KiB
TypeScript

import { nativeAddressInputSchema } from "../domain/native/nativeAddress.js";
import { AnalysisInputError } from "../domain/analysisErrorCore.js";
import { err, ok, type Result } from "../domain/result.js";
/** Each separately emitted args/options schema must expose the selector choice. */
export const requiredSelectorGuidance = (alternatives: string): string =>
`Supply at least one of ${alternatives}.`;
export const addressOrProcedureGuidance = requiredSelectorGuidance(
"the positional address or --procedure",
);
/** Agreement details belong on the command, rather than every schema field. */
export const equalSelectorGuidance =
"Equal values are accepted; conflicts fail.";
/** Data type selectors stay optional in the options schema; exactly one is required. */
export const dataTypeSelectorGuidance =
"Supply exactly one of --type or --address.";
/**
* How two spellings of one selector agree: `text` only when identical,
* `native` also when both are the same native address.
*/
export type CliSelectorKind = "text" | "native";
/**
* Select the value of a selector the caller may give positionally or
* through its named option, preserving the named spelling. Equal values
* agree; different values, or neither when `required`, are refused.
*/
export const selectCliAnalysisSelector = (
positional: string | undefined,
named: string | undefined,
selector: {
readonly option: string;
readonly operation: string;
readonly kind: CliSelectorKind;
readonly required: boolean;
},
): Result<string | undefined, AnalysisInputError> => {
const { option, operation, kind, required } = selector;
const equivalent = (): boolean => {
if (positional === named) return true;
if (kind !== "native") return false;
const left = nativeAddressInputSchema.safeParse(positional);
const right = nativeAddressInputSchema.safeParse(named);
return left.success && right.success && left.data === right.data;
};
if (positional !== undefined && named !== undefined && !equivalent())
return err(
new AnalysisInputError(operation, undefined, [
{
path: [option],
reason: "invalid_value",
message: `The positional selector and --${option} select different objects; supply one selector.`,
},
]),
);
const selected = named ?? positional;
if (selected === undefined && required)
return err(
new AnalysisInputError(operation, undefined, [
{
path: [option],
reason: "missing_argument",
message: `Supply a positional selector or --${option}=<value>. Use the named option for values beginning with a dash.`,
expected: "string",
},
]),
);
return ok(selected);
};
/** Preserve a CLI selector supplied positionally or through its named option. */
export const resolveCliAnalysisSelector = (
positional: string | undefined,
named: string | undefined,
option: string,
operation: string,
kind: CliSelectorKind = "text",
): string => {
const selected = selectCliAnalysisSelector(positional, named, {
option,
operation,
kind,
required: true,
});
if (!selected.ok) throw selected.error;
return selected.value!;
};