mirror of
https://github.com/morluto/rea.git
synced 2026-11-06 23:06:18 +00:00
* feat(browser): import saved Playwright v10 trace evidence * fix(browser): preserve original Playwright ZIP member names
280 lines
9.9 KiB
TypeScript
280 lines
9.9 KiB
TypeScript
import { registerPlaywrightTraceCommand } from "./playwrightTraceCommand.js";
|
|
import { registerApiContractCommand } from "./apiContractCommand.js";
|
|
import { Cli, z } from "incur";
|
|
|
|
import { CLI_COMMANDS } from "../cliCommandNames.js";
|
|
import { parseCliJsonInput } from "../cliJsonInput.js";
|
|
import { logCliCommand } from "../cliLogging.js";
|
|
import { projectAnalysisError } from "../domain/analysisErrorProjection.js";
|
|
import type { AnalysisError } from "../domain/analysisErrorBase.js";
|
|
import type { JsonValue } from "../domain/jsonValue.js";
|
|
import type { Logger } from "pino";
|
|
import { registerSourceToBundleCommand } from "./sourceToBundleCommand.js";
|
|
import { registerStaticObservedEndpointsCommand } from "./staticObservedEndpointsCommand.js";
|
|
import { analysisInputErrorFromIssues } from "../domain/inputIssueProjection.js";
|
|
import type { EvidenceLookup } from "../application/EvidenceInputResolver.js";
|
|
import type { Evidence } from "../domain/evidence.js";
|
|
import type { Result } from "../domain/result.js";
|
|
import {
|
|
evidenceBundleOption,
|
|
runEvidenceInputCommand,
|
|
} from "./evidenceInputCommand.js";
|
|
import { withCommandCancellation } from "./commandCancellation.js";
|
|
|
|
type CliInstance = ReturnType<typeof Cli.create>;
|
|
|
|
/** Register CLI equivalents of provider-neutral application graph workflows. */
|
|
export const registerApplicationCommands = (
|
|
cli: ReturnType<typeof Cli.create>,
|
|
logger: Logger,
|
|
): void => {
|
|
registerEvidenceJsonCommand({
|
|
cli,
|
|
logger,
|
|
name: CLI_COMMANDS.traceApplicationFeature,
|
|
operation: "trace_application_feature",
|
|
description:
|
|
"Trace a typed seed through authenticated application Evidence JSON",
|
|
workflow: async (input, lookup, signal) => {
|
|
const { traceApplicationFeatureEvidence } =
|
|
await import("../application/javascript/JavaScriptApplicationWorkflowService.js");
|
|
const result = traceApplicationFeatureEvidence(input, lookup, { signal });
|
|
return result.ok ? { ok: true, value: result.value.evidence } : result;
|
|
},
|
|
});
|
|
registerEvidenceJsonCommand({
|
|
cli,
|
|
logger,
|
|
name: CLI_COMMANDS.traceJavaScriptSemantics,
|
|
operation: "trace_javascript_semantics",
|
|
description:
|
|
"Trace bounded static semantic relations through authenticated application Evidence",
|
|
workflow: async (input, lookup, signal) => {
|
|
const { traceJavaScriptSemanticsEvidence } =
|
|
await import("../application/javascript/JavaScriptSemanticTraceService.js");
|
|
const result = traceJavaScriptSemanticsEvidence(input, lookup, {
|
|
signal,
|
|
});
|
|
return result.ok ? { ok: true, value: result.value.evidence } : result;
|
|
},
|
|
});
|
|
registerEvidenceJsonCommand({
|
|
cli,
|
|
logger,
|
|
name: CLI_COMMANDS.compareApplicationVersions,
|
|
operation: "compare_application_versions",
|
|
description:
|
|
"Compare two authenticated JavaScript Application Graph versions",
|
|
workflow: async (input, lookup, signal) => {
|
|
const { compareApplicationVersionsEvidence } =
|
|
await import("../application/javascript/JavaScriptApplicationWorkflowService.js");
|
|
const result = compareApplicationVersionsEvidence(input, lookup, {
|
|
signal,
|
|
});
|
|
return result.ok ? { ok: true, value: result.value.evidence } : result;
|
|
},
|
|
});
|
|
registerSourceToBundleCommand(cli, logger);
|
|
registerStaticObservedEndpointsCommand(cli, logger);
|
|
registerApiContractCommand(cli, logger);
|
|
registerPlaywrightTraceCommand(cli, logger);
|
|
registerEvidenceJsonCommand({
|
|
cli,
|
|
logger,
|
|
name: CLI_COMMANDS.compareJavaScriptExportShapes,
|
|
operation: "compare_javascript_export_shapes",
|
|
description:
|
|
"Compare exact static JavaScript export return shapes without execution",
|
|
workflow: async (input, lookup, signal) => {
|
|
const { compareJavaScriptExportShapesEvidence } =
|
|
await import("../application/javascript/JavaScriptApplicationWorkflowService.js");
|
|
const result = compareJavaScriptExportShapesEvidence(input, lookup, {
|
|
signal,
|
|
});
|
|
return result.ok ? { ok: true, value: result.value.evidence } : result;
|
|
},
|
|
});
|
|
registerObligationLedgerCommand(cli, logger);
|
|
registerCoverageCommand(cli, logger);
|
|
registerEvidenceJsonCommand({
|
|
cli,
|
|
logger,
|
|
name: CLI_COMMANDS.projectAndroidApplicationGraph,
|
|
operation: "project_android_application_graph",
|
|
description:
|
|
"Project authenticated APK inventory Evidence into an Android application graph",
|
|
workflow: async (input, lookup, signal) => {
|
|
const { projectAndroidApplicationEvidence } =
|
|
await import("../application/android/AndroidApplicationService.js");
|
|
const result = projectAndroidApplicationEvidence(input, lookup, {
|
|
signal,
|
|
});
|
|
return result.ok ? { ok: true, value: result.value.evidence } : result;
|
|
},
|
|
});
|
|
registerEvidenceJsonCommand({
|
|
cli,
|
|
logger,
|
|
name: CLI_COMMANDS.projectAppleApplicationGraph,
|
|
operation: "project_apple_application_graph",
|
|
description:
|
|
"Project authenticated IPA or macOS app inventory Evidence into an Apple application graph",
|
|
workflow: async (input, lookup, signal) => {
|
|
const { projectAppleApplicationEvidence } =
|
|
await import("../application/apple/AppleApplicationService.js");
|
|
const result = projectAppleApplicationEvidence(input, lookup, { signal });
|
|
return result.ok ? { ok: true, value: result.value.evidence } : result;
|
|
},
|
|
});
|
|
registerEvidenceJsonCommand({
|
|
cli,
|
|
logger,
|
|
name: CLI_COMMANDS.projectHarmonyApplicationGraph,
|
|
operation: "project_harmony_application_graph",
|
|
description:
|
|
"Project authenticated HarmonyOS HAP, HSP, or App Pack inventory Evidence into an application graph",
|
|
workflow: async (input, lookup, signal) => {
|
|
const { projectHarmonyApplicationEvidence } =
|
|
await import("../application/harmony/HarmonyApplicationService.js");
|
|
const result = projectHarmonyApplicationEvidence(input, lookup, {
|
|
signal,
|
|
});
|
|
return result.ok ? { ok: true, value: result.value.evidence } : result;
|
|
},
|
|
});
|
|
};
|
|
|
|
const registerObligationLedgerCommand = (
|
|
cli: CliInstance,
|
|
logger: Logger,
|
|
): void =>
|
|
registerJsonCommand({
|
|
cli,
|
|
logger,
|
|
name: CLI_COMMANDS.buildReconstructionObligationLedger,
|
|
description:
|
|
"Generate a deterministic Evidence-backed reconstruction obligation ledger page",
|
|
inputSchema: z.unknown(),
|
|
workflow: async (input) => {
|
|
const { buildReconstructionObligationLedgerEvidence } =
|
|
await import("../application/ReconstructionObligationLedgerService.js");
|
|
return buildReconstructionObligationLedgerEvidence(input);
|
|
},
|
|
});
|
|
|
|
const registerCoverageCommand = (cli: CliInstance, logger: Logger): void =>
|
|
registerJsonCommand({
|
|
cli,
|
|
logger,
|
|
name: CLI_COMMANDS.evaluateReconstructionCoverage,
|
|
description: "Evaluate inline fail-closed reconstruction coverage",
|
|
inputSchema: z.unknown(),
|
|
workflow: async (input) => {
|
|
const { evaluateReconstructionCoverage } =
|
|
await import("../application/ReconstructionCoverageService.js");
|
|
return evaluateReconstructionCoverage(input);
|
|
},
|
|
});
|
|
|
|
interface JsonCommandOptions<Schema extends z.ZodType> {
|
|
readonly cli: CliInstance;
|
|
readonly logger: Logger;
|
|
readonly name: string;
|
|
readonly description: string;
|
|
readonly inputSchema: Schema;
|
|
readonly workflow: (
|
|
input: z.output<Schema>,
|
|
) => Promise<
|
|
| { readonly ok: true; readonly value: JsonValue }
|
|
| { readonly ok: false; readonly error: AnalysisError }
|
|
>;
|
|
}
|
|
|
|
const registerJsonCommand = <Schema extends z.ZodType>({
|
|
cli,
|
|
logger,
|
|
name,
|
|
description,
|
|
inputSchema,
|
|
workflow,
|
|
}: JsonCommandOptions<Schema>): void => {
|
|
cli.command(name, {
|
|
description,
|
|
args: z.object({
|
|
inputJson: z.string().describe("Inline workflow JSON or JSON file path"),
|
|
}),
|
|
run: ({ args }) =>
|
|
logCliCommand(logger, name, async () => {
|
|
const input = await parseCliJsonInput(args.inputJson, name);
|
|
if (!input.ok) return input.error;
|
|
const parsed = inputSchema.safeParse(input.value);
|
|
if (!parsed.success)
|
|
return {
|
|
error: "Application workflow failed",
|
|
...projectAnalysisError(
|
|
analysisInputErrorFromIssues(
|
|
name,
|
|
parsed.error.issues,
|
|
input.value,
|
|
),
|
|
),
|
|
};
|
|
const result = await workflow(parsed.data);
|
|
return result.ok
|
|
? result.value
|
|
: {
|
|
error: "Application workflow failed",
|
|
...projectAnalysisError(result.error, "invocation"),
|
|
};
|
|
}),
|
|
});
|
|
};
|
|
|
|
/** Evidence consumers share one explicit portable source and cancellation lifetime. */
|
|
const registerEvidenceJsonCommand = ({
|
|
cli,
|
|
logger,
|
|
name,
|
|
operation,
|
|
description,
|
|
workflow,
|
|
}: {
|
|
readonly cli: CliInstance;
|
|
readonly logger: Logger;
|
|
readonly name: string;
|
|
readonly operation: string;
|
|
readonly description: string;
|
|
readonly workflow: (
|
|
input: unknown,
|
|
lookup: EvidenceLookup | undefined,
|
|
signal: AbortSignal,
|
|
) => Promise<Result<Evidence, AnalysisError>>;
|
|
}): void => {
|
|
cli.command(name, {
|
|
description,
|
|
args: z.object({
|
|
inputJson: z.string().describe("Inline workflow JSON or JSON file path"),
|
|
}),
|
|
options: z.object({ evidenceBundle: evidenceBundleOption }),
|
|
run: ({ args, options }) =>
|
|
withCommandCancellation((signal) =>
|
|
logCliCommand(logger, name, async () => {
|
|
const input = await parseCliJsonInput(args.inputJson, name, signal);
|
|
if (!input.ok) return input.error;
|
|
const result = await runEvidenceInputCommand(
|
|
operation,
|
|
options.evidenceBundle,
|
|
signal,
|
|
(lookup) => workflow(input.value, lookup, signal),
|
|
);
|
|
return result.ok
|
|
? result.value
|
|
: {
|
|
error: "Application workflow failed",
|
|
...result.error,
|
|
};
|
|
}),
|
|
),
|
|
});
|
|
};
|