Files
rea/src/contracts/toolOutputSchemaGroups.ts
T
morluto 1712e6d821 feat!: make evidence bundles canonical MCP resources
Add immutable session bundle snapshots, bounded resource discovery, paginated unknowns, mutable current analysis snapshots, and provider-neutral navigation/address context tools.

BREAKING CHANGE: export_evidence_bundle now requires a filesystem path and no longer returns an inline bundle.
2026-07-29 17:36:40 +00:00

491 lines
16 KiB
TypeScript

import { z } from "zod";
import { jsonValueSchema } from "../domain/jsonValue.js";
import {
processCaptureComparisonSchema,
processCaptureSchema,
} from "../domain/processCapture.js";
import { residualUnknownSchema } from "../domain/residualUnknown.js";
import {
functionInstructionWindowSchema,
referenceKindSchema,
} from "../domain/hopperValues.js";
import { nativeApiInspectionResultSchema } from "../domain/nativeApiBoundary.js";
import {
demangleSwiftSchema,
inspectMachoSchema,
inspectPlistSchema,
inspectSignatureSchema,
listArchitecturesSchema,
} from "../domain/nativeInspection.js";
import {
artifactExtractionResultSchema,
artifactInventoryResultSchema,
} from "../domain/artifactGraph.js";
import { artifactInspectionResultSchema } from "../domain/artifactInspection.js";
import {
managedArtifactInspectionSchema,
managedMemberInspectionSchema,
managedNativeBoundaryInspectionSchema,
} from "../domain/managedArtifact.js";
import { managedMemberComparisonResultSchema } from "../domain/managedMemberComparison.js";
import { managedNativeVerificationResultSchema } from "../domain/managedNativeVerification.js";
import { managedReconstructionImportResultSchema } from "../domain/managedReconstruction.js";
import { managedRuntimeCorrelationResultSchema } from "../domain/managedRuntimeCorrelation.js";
import { managedApplicationGraphResultSchema } from "../domain/managedApplicationGraph.js";
import { artifactComparisonResultSchema } from "../domain/artifactComparison.js";
import { functionComparisonResultSchema } from "../domain/functionComparison.js";
import { bundleComparisonResultSchema } from "../domain/bundleComparison.js";
import { changedBehaviorResultSchema } from "../domain/changedBehavior.js";
import { callPathResultSchema } from "../domain/callPath.js";
import { staticRuntimeCorrelationResultSchema } from "../domain/staticRuntimeCorrelation.js";
import { reconstructionVerificationResultSchema } from "../domain/reconstructionVerification.js";
import { replayMachineRunOutputSchema } from "../domain/replayMachineRun.js";
import { analysisErrorProjectionSchema } from "./errorSchemas.js";
import {
addressList,
analysisActivity,
addressedEntry,
bounded,
containingProcedureResolution,
clientFeatureAvailabilitySchema,
functionDossierOutput,
graphNode,
lifecycleResultOf,
nullableText,
pageOutput,
procedureIdentity,
procedureInfoOutput,
evidenceResultOf as resultOf,
searchPageOutput,
segmentOutput,
sessionProvider,
providerIdentity,
toolAvailability,
symbolDiscoveryOutput,
targetFormatSchema,
targetKindSchema,
} from "./toolOutputSchemaPrimitives.js";
const contextFacetSchema = z.discriminatedUnion("state", [
z.object({ state: z.literal("available"), value: jsonValueSchema }),
z.object({
state: z.literal("unavailable"),
reason: z.string(),
remediation: z.string(),
}),
]);
/** Exact structured-content schemas shared by direct analysis providers. */
export const officialOutputSchemas: Readonly<Record<string, z.ZodObject>> = {
address_name: resultOf(nullableText),
comment: resultOf(nullableText),
current_address: resultOf(z.string()),
current_procedure: resultOf(z.string()),
current_document: resultOf(z.string()),
goto_address: resultOf(z.string()),
inline_comment: resultOf(nullableText),
list_bookmarks: resultOf(z.array(addressedEntry)),
list_documents: resultOf(z.array(z.string())),
list_names: resultOf(pageOutput),
list_procedures: resultOf(pageOutput),
list_segments: segmentOutput,
list_strings: resultOf(pageOutput),
next_address: resultOf(z.string()),
prev_address: resultOf(z.string()),
procedure_address: resultOf(z.string()),
procedure_assembly: resultOf(z.string()),
procedure_callees: resultOf(addressList),
procedure_callers: resultOf(addressList),
procedure_info: procedureInfoOutput,
read_function_instructions: resultOf(functionInstructionWindowSchema),
read_bytes: resultOf(
z.object({
address: z.string(),
requested_bytes: z.number().int().min(1).max(4_096),
returned_bytes: z.number().int().min(0).max(4_096),
bytes_hex: z.string().regex(/^(?:[a-f0-9]{2})*$/u),
complete: z.boolean(),
}),
),
address_to_file_offset: resultOf(
z.object({
address: z.string(),
file_offset: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
}),
),
procedure_references: resultOf(
z.object({
procedure: procedureIdentity,
direction: z.enum(["incoming", "outgoing"]),
references: bounded(
z.object({
source_address: z.string(),
target_address: z.string(),
source_procedure: procedureIdentity.nullable(),
target_procedure: procedureIdentity.nullable(),
kind: referenceKindSchema,
}),
),
instructions_scanned: z.number().int().min(0),
instruction_scan_truncated: z.boolean(),
}),
),
procedure_pseudo_code: resultOf(nullableText),
resolve_containing_procedure: resultOf(containingProcedureResolution),
search_procedures: resultOf(searchPageOutput),
search_strings: resultOf(searchPageOutput),
set_address_name: resultOf(z.boolean()),
set_addresses_names: resultOf(z.record(z.string(), z.boolean())),
set_bookmark: resultOf(z.boolean()),
set_comment: resultOf(z.boolean()),
set_current_document: resultOf(z.string()),
set_inline_comment: resultOf(z.boolean()),
unset_bookmark: resultOf(z.boolean()),
xrefs: resultOf(addressList),
};
const literalTraceOutput = resultOf(
z.object({
query: z.string(),
search_mode: z.literal("literal"),
operations_used: z.number().int().min(0),
operation_budget: z.number().int().min(1),
matches: z.array(
z.object({
type: z.enum(["string", "procedure"]),
address: z.string(),
value: z.string(),
}),
),
references: z.array(
z.object({
target_address: z.string(),
source_address: z.string(),
containing_procedure: containingProcedureResolution,
}),
),
truncated: z.boolean(),
residual_unknowns: z.array(z.string()),
}),
);
const callPathTraceOutput = resultOf(
z.object({
start: z.string(),
goal: z.string().nullable(),
direction: z.enum(["forward", "backward"]),
goal_status: z.enum(["not_requested", "reached", "not_reached"]),
nodes: z.array(
z.object({
address: z.string(),
depth: z.number().int().min(0),
}),
),
edges: z.array(
z.object({
source_address: z.string(),
target_address: z.string(),
discovery_depth: z.number().int().min(1),
}),
),
traversal_path: z.array(z.string()),
failures: z.array(
z.object({
address: z.string(),
error: analysisErrorProjectionSchema,
}),
),
frontier: z.array(z.string()),
limits: z.object({
max_depth: z.number().int().min(1),
max_nodes: z.number().int().min(1),
max_operations: z.number().int().min(1),
nodes_visited: z.number().int().min(1),
operations_used: z.number().int().min(0),
}),
truncated: z.boolean(),
residual_unknowns: z.array(z.string()),
limitations: z.array(z.string()),
}),
);
/** Exact structured-content schemas for composed analysis workflows. */
export const enhancedOutputSchemas: Readonly<Record<string, z.ZodObject>> = {
swift_classes: symbolDiscoveryOutput("classes"),
get_objc_classes: symbolDiscoveryOutput("classes"),
get_objc_protocols: symbolDiscoveryOutput("protocols"),
batch_decompile: resultOf(
z.object({
items: z.array(
z.discriminatedUnion("status", [
z.object({
address: z.string(),
status: z.literal("ok"),
pseudocode: z.string().min(1),
}),
z.object({
address: z.string(),
status: z.literal("error"),
error: analysisErrorProjectionSchema,
}),
]),
),
total: z.number().int().min(0),
succeeded: z.number().int().min(0),
failed: z.number().int().min(0),
}),
),
get_call_graph: resultOf(z.record(z.string(), z.array(graphNode))),
analyze_swift_types: resultOf(
z.object({
total: z.number().int().min(0),
categories: z.record(
z.string(),
z.object({
count: z.number().int().min(0),
items: z.array(addressedEntry),
}),
),
}),
),
find_xrefs_to_name: resultOf(
z.discriminatedUnion("status", [
z.object({
status: z.literal("resolved"),
name: z.string(),
address: z.string(),
xrefs: addressList,
}),
z.object({
status: z.literal("unresolved"),
name: z.string(),
reason: z.literal("name_not_found"),
}),
]),
),
binary_overview: resultOf(
z.object({
document: z.string(),
detail: z.enum(["concise", "detailed"]),
segments: z.array(
z.object({
name: z.string(),
start: z.string(),
end: z.string(),
length: z.number().min(0).optional(),
}),
),
segment_count: z.number().int().min(0),
procedure_count: z.number().int().min(0),
string_count: z.number().int().min(0),
}),
),
analyze_function: functionDossierOutput,
inspect_native_api: resultOf(nativeApiInspectionResultSchema),
trace_feature: literalTraceOutput,
find_code_for_string: literalTraceOutput,
trace_call_path: callPathTraceOutput,
};
/** Exact Evidence v2 schemas for provider-neutral native inspection. */
export const nativeOutputSchemas: Readonly<Record<string, z.ZodObject>> = {
inspect_macho: resultOf(inspectMachoSchema),
inspect_signature: resultOf(inspectSignatureSchema),
inspect_plist: resultOf(inspectPlistSchema),
list_architectures: resultOf(listArchitecturesSchema),
demangle_swift: resultOf(demangleSwiftSchema),
};
/** Exact Evidence v2 schemas for provider-neutral artifact graph operations. */
export const artifactOutputSchemas: Readonly<Record<string, z.ZodObject>> = {
inventory_artifact: resultOf(artifactInventoryResultSchema),
inspect_artifact: resultOf(artifactInspectionResultSchema),
extract_artifact: resultOf(artifactExtractionResultSchema),
};
/** Exact Evidence v2 schema for execution-free managed static analysis. */
export const managedOutputSchemas: Readonly<Record<string, z.ZodObject>> = {
inspect_managed_artifact: resultOf(managedArtifactInspectionSchema),
inspect_managed_members: resultOf(managedMemberInspectionSchema),
inspect_managed_native_boundaries: resultOf(
managedNativeBoundaryInspectionSchema,
),
};
/** Exact Evidence v2 schema for provider-neutral managed workflows. */
export const managedWorkflowOutputSchemas: Readonly<
Record<string, z.ZodObject>
> = {
compare_managed_members: resultOf(managedMemberComparisonResultSchema),
verify_managed_native_boundaries: resultOf(
managedNativeVerificationResultSchema,
),
import_managed_reconstruction: resultOf(
managedReconstructionImportResultSchema,
),
plan_managed_runtime_correlation: resultOf(
managedRuntimeCorrelationResultSchema,
),
project_managed_application_graph: resultOf(
managedApplicationGraphResultSchema,
),
};
/** Exact structured-content schemas for target lifecycle operations. */
export const sessionOutputSchemas: Readonly<Record<string, z.ZodObject>> = {
open_binary: lifecycleResultOf(
z.object({
path: z.string(),
format: targetFormatSchema,
kind: targetKindSchema,
loaderArgs: z.array(z.string()),
sha256: z.string().regex(/^[a-f0-9]{64}$/u),
architecture: z.enum(["x86", "x86_64", "arm", "arm64"]).nullable(),
}),
),
close_binary: lifecycleResultOf(
z.union([
z.null(),
z.object({
path: z.string(),
bytes: z.number().int().min(0),
entries: z.number().int().min(0),
}),
]),
),
binary_session: lifecycleResultOf(
z.union([
z.object({
view: z.literal("summary"),
open: z.boolean(),
provider: providerIdentity,
active_provider: providerIdentity.nullable(),
target: z
.object({
path: z.string(),
format: targetFormatSchema,
kind: targetKindSchema,
sha256: z.string().regex(/^[a-f0-9]{64}$/u),
architecture: z.enum(["x86", "x86_64", "arm", "arm64"]).nullable(),
})
.nullable(),
alignment: z.object({
state: z.enum(["aligned", "mcp_server_restart_required", "unknown"]),
reasons: z.array(z.string()),
remediation: z.string().nullable(),
}),
analysis_activity: analysisActivity,
recommended_actions: z.array(z.string()),
}),
z.object({
view: z.literal("capabilities"),
open: z.boolean(),
provider: providerIdentity,
active_provider: providerIdentity.nullable(),
capability_family: z.string().nullable(),
capabilities: z.object({
items: z.array(toolAvailability),
cursor: z.number().int().min(0),
limit: z.number().int().min(1),
total: z.number().int().min(0),
next_cursor: z.number().int().min(0).nullable(),
has_more: z.boolean(),
}),
client_features: clientFeatureAvailabilitySchema,
}),
z.union([
sessionProvider.extend({
view: z.literal("full"),
open: z.literal(false),
}),
sessionProvider.extend({
view: z.literal("full"),
open: z.literal(true),
path: z.string(),
format: targetFormatSchema,
kind: targetKindSchema,
sha256: z.string().regex(/^[a-f0-9]{64}$/u),
architecture: z.enum(["x86", "x86_64", "arm", "arm64"]).nullable(),
}),
]),
]),
),
export_evidence_bundle: lifecycleResultOf(
z.object({
path: z.string(),
bytes: z.number().int().min(0),
records: z.number().int().min(0),
unknowns: z.number().int().min(0),
}),
),
snapshot_evidence_bundle: lifecycleResultOf(
z.object({
bundle_digest: z.string().regex(/^[a-f0-9]{64}$/u),
bundle_version: z.literal(2),
bytes: z.number().int().min(0),
records: z.number().int().min(0),
unknowns: z.number().int().min(0),
bundle_uri: z.string().regex(/^rea:\/\/evidence-bundle\/[a-f0-9]{64}$/u),
}),
),
get_navigation_context: lifecycleResultOf(
z.object({
document: z.string(),
address: z.string(),
procedure: z.union([z.string(), z.null()]),
}),
),
inspect_address_context: lifecycleResultOf(
z.object({
address: z.string(),
document: z.string().nullable(),
name: contextFacetSchema,
procedure: contextFacetSchema,
comment: contextFacetSchema,
inline_comment: contextFacetSchema,
bookmarks: contextFacetSchema,
}),
),
import_evidence_bundle: lifecycleResultOf(
z.object({
imported: z.number().int().min(0),
total: z.number().int().min(0),
}),
),
capture_process_scenario: resultOf(processCaptureSchema),
compare_process_captures: resultOf(processCaptureComparisonSchema),
compare_artifacts: resultOf(artifactComparisonResultSchema),
compare_functions: resultOf(functionComparisonResultSchema),
compare_bundles: resultOf(bundleComparisonResultSchema),
find_changed_behavior: resultOf(changedBehaviorResultSchema),
build_call_path: resultOf(callPathResultSchema),
correlate_static_and_runtime: resultOf(staticRuntimeCorrelationResultSchema),
verify_reconstruction: resultOf(reconstructionVerificationResultSchema),
list_unknowns: lifecycleResultOf(
z.object({
items: z.array(
z.object({
unknown: residualUnknownSchema,
uri: z.string().regex(/^rea:\/\/unknown\/unk_[a-f0-9]{64}$/u),
}),
),
offset: z.number().int().min(0),
limit: z.number().int().min(1).max(500),
total: z.number().int().min(0),
next_offset: z.number().int().min(0).nullable(),
has_more: z.boolean(),
}),
),
record_unknown: lifecycleResultOf(residualUnknownSchema),
update_unknown: lifecycleResultOf(residualUnknownSchema),
verify_unknown_resolution: lifecycleResultOf(
z.object({
valid: z.boolean(),
truthVerified: z.boolean(),
unknown: residualUnknownSchema,
}),
),
run_replay_machine: lifecycleResultOf(replayMachineRunOutputSchema),
};