Files
reverse-engineering-anything/src/cli/javascriptRuntimeCommands.ts
T
morlutoandCursor Agent b31fc5d5fb fix(cli): advertise domain constraints for selector and path options (#9181)
* fix(cli): advertise domain constraints for selector and path options

Android class, method, and mapping fields, ADB setting keys, and browser
endpoints used bare strings in --schema. They now reuse the domain fields,
so empty selectors, relative mapping paths, and malformed setting keys
fail in the advertised schema.

* fix(cli): keep selector limits when argument parsing rejects them

Empty browser and Electron selectors now fail in the CLI parser, so their
diagnostics are VALIDATION_ERROR with the one-character minimum. ADB
setting keys stay on the selector repair path, which restores maximum 256
and the identifier pattern.

* test(cli): assert empty-selector codes without frozen prose

Empty browser and Electron selectors still fail as VALIDATION_ERROR
too_small on the named field. The tests no longer copy Zod's sentence.

* test(cli): compare endpoint diagnostics with the domain schema

Browser and Inspector tests take custom issue text from the schema that
owns it, and empty capture comparison must name both missing inspection
fields.

* fix(cli): remove duplicate merged schema import

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-11-07 16:17:09 +08:00

149 lines
5.4 KiB
TypeScript

import { projectCliAnalysisResult } from "./projectCliAnalysisResult.js";
import { Cli, z } from "incur";
import {
listJavaScriptRuntimeTargets,
observeJavaScriptRuntime,
} from "../application/javascript/JavaScriptRuntimeObservationService.js";
import { createJavaScriptRuntimeObservationProvider } from "../composition/javascriptRuntimeObservation.js";
import { V8InspectorAdmission } from "../inspector/V8InspectorProvider.js";
import { cliDomainInput } from "./domainInput.js";
import { cliDecimalField } from "./options.js";
import { CLI_COMMANDS } from "../cliCommandNames.js";
import { logCliCommand } from "../cliLogging.js";
import {
javascriptRuntimeKindSchema,
listJavaScriptRuntimeTargetsInputSchema,
observeJavaScriptRuntimeInputSchema,
} from "../domain/javascript/javascriptRuntimeObservation.js";
import { analysisInputErrorFromIssues } from "../domain/inputIssueProjection.js";
import { projectAnalysisError } from "../domain/analysisErrorProjection.js";
import { finishAnalysisCommand } from "./finishAnalysisCommand.js";
import type { JsonValue } from "../domain/jsonValue.js";
import type { Logger } from "pino";
import { withCommandCancellation } from "./commandCancellation.js";
const observeOptionsSchema = z.object({
runtimeKind: javascriptRuntimeKindSchema
.optional()
.describe(
"Declared target role; Inspector cannot authenticate the Electron role",
),
observationMs: cliDecimalField(
observeJavaScriptRuntimeInputSchema.shape.observation_ms,
).describe("Observation window in milliseconds"),
});
/** Register CLI equivalents of passive V8 Inspector tools. */
export const registerJavaScriptRuntimeObservationCommands = (
cli: ReturnType<typeof Cli.create>,
logger: Logger,
environment: Readonly<Record<string, string | undefined>>,
): void => {
const admission = new V8InspectorAdmission();
const providerForCommand = () =>
createJavaScriptRuntimeObservationProvider(
environment,
undefined,
admission,
);
cli.command(CLI_COMMANDS.listJavaScriptRuntimeTargets, {
description: "List Node/Electron V8 Inspector targets",
args: z.object({
endpoint: cliDomainInput(
listJavaScriptRuntimeTargetsInputSchema.shape.inspector_endpoint,
).describe("Literal-loopback Inspector endpoint"),
}),
run: ({ args }) =>
withCommandCancellation((signal) =>
logCliCommand(
logger,
CLI_COMMANDS.listJavaScriptRuntimeTargets,
async () => {
const provider = providerForCommand();
const input = {
inspector_endpoint: args.endpoint,
};
const parsed =
listJavaScriptRuntimeTargetsInputSchema.safeParse(input);
if (!parsed.success)
return cliError(
analysisInputErrorFromIssues(
"list_javascript_runtime_targets",
parsed.error.issues,
input,
),
);
return await finishAnalysisCommand(
() =>
listJavaScriptRuntimeTargets(provider, parsed.data, {
signal,
}),
{ close: () => provider.close?.() ?? Promise.resolve() },
provider.identity().id,
"list_javascript_runtime_targets",
signal,
"V8 Inspector resources",
).then(projectCliAnalysisResult);
},
),
),
});
cli.command(CLI_COMMANDS.observeJavaScriptRuntime, {
description: "Passively observe one exact Node/Electron Inspector target",
args: z.object({
endpoint: cliDomainInput(
listJavaScriptRuntimeTargetsInputSchema.shape.inspector_endpoint,
).describe("Literal-loopback Inspector endpoint"),
targetId: observeJavaScriptRuntimeInputSchema.shape.target_id.describe(
"Target from list-javascript-runtime-targets",
),
}),
options: observeOptionsSchema,
run: ({ args, options }) =>
withCommandCancellation((signal) =>
logCliCommand(
logger,
CLI_COMMANDS.observeJavaScriptRuntime,
async () => {
const provider = providerForCommand();
const input = {
inspector_endpoint: args.endpoint,
target_id: args.targetId,
runtime_kind: options.runtimeKind,
observation_ms: options.observationMs,
};
const parsed = observeJavaScriptRuntimeInputSchema.safeParse(input);
if (!parsed.success)
return cliError(
analysisInputErrorFromIssues(
"observe_javascript_runtime",
parsed.error.issues,
input,
),
);
return await finishAnalysisCommand(
() =>
observeJavaScriptRuntime(provider, parsed.data, {
signal,
}),
{ close: () => provider.close?.() ?? Promise.resolve() },
provider.identity().id,
"observe_javascript_runtime",
signal,
"V8 Inspector resources",
).then(projectCliAnalysisResult);
},
),
),
});
};
const cliError = (
error: Parameters<typeof projectAnalysisError>[0],
): JsonValue => ({
error: "JavaScript runtime observation failed",
...projectAnalysisError(error),
});