rea-agents 2.5.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -4
- package/bridge/ghidra/ReaGhidraBridge.java +477 -4
- package/bridge/hopper_bridge.py +54 -4
- package/dist/application/AnalysisContextQueries.js +130 -0
- package/dist/application/AnalysisSnapshotCache.js +4 -2
- package/dist/application/ArtifactInventory/scanCanonical.js +1 -1
- package/dist/application/BinarySession.js +5 -4
- package/dist/application/BinarySessionComposition.js +21 -0
- package/dist/application/BinarySessionRecords.js +79 -9
- package/dist/application/CapabilityInventory.js +16 -2
- package/dist/application/ClientRegistrationStatus.js +4 -1
- package/dist/application/DirectAnalysis.js +6 -2
- package/dist/application/EnhancedTools.js +37 -7
- package/dist/application/EvidenceLedger.js +45 -16
- package/dist/application/JavaScriptArtifactAnalysis.js +13 -4
- package/dist/application/LazyAnalysisProvider.js +77 -0
- package/dist/application/LoopbackReplay.js +1 -1
- package/dist/application/NativeApiInspection.js +80 -0
- package/dist/application/SessionProviderRouter.js +6 -6
- package/dist/application/SetupClientConfiguration.js +4 -2
- package/dist/application/runtime.js +26 -9
- package/dist/browser/PlaywrightBrowserScenarioProvider.js +8 -2
- package/dist/catalogIdentity.js +3 -3
- package/dist/cli/artifactCommands.js +5 -3
- package/dist/cli/coreAnalysisCommands.js +41 -0
- package/dist/cliCommandNames.js +1 -0
- package/dist/contracts/artifactToolContracts.js +8 -3
- package/dist/contracts/enhancedInputs.js +10 -0
- package/dist/contracts/functionWorkflowToolContracts.js +30 -0
- package/dist/contracts/promptContracts.js +14 -15
- package/dist/contracts/toolContractExamples.js +3 -0
- package/dist/contracts/toolContracts.js +21 -4
- package/dist/contracts/toolEffects.js +4 -0
- package/dist/contracts/toolOutputSchemaGroups.js +50 -10
- package/dist/domain/analysisErrorPresentation.js +8 -2
- package/dist/domain/analysisErrorProjection.js +1 -0
- package/dist/domain/bytecodeProvider.js +179 -0
- package/dist/domain/conformancePackage.js +169 -0
- package/dist/domain/conformanceReplay.js +104 -0
- package/dist/domain/conformanceTrustGate.js +193 -0
- package/dist/domain/customProtocolCapture.js +137 -0
- package/dist/domain/eventProcessTree.js +214 -0
- package/dist/domain/evidenceBundle.js +47 -0
- package/dist/domain/hopperStartupFailure.js +1 -1
- package/dist/domain/hopperValues.js +4 -1
- package/dist/domain/inputIssueProjection.js +7 -1
- package/dist/domain/javascriptSemanticAnalysis.js +8 -12
- package/dist/domain/javascriptSourceParser.js +15 -0
- package/dist/domain/javascriptStaticAnalysis.js +8 -12
- package/dist/domain/mobileApplicationInvestigation.js +159 -0
- package/dist/domain/nativeApiBoundary.js +130 -0
- package/dist/domain/objcSwiftMetadata.js +150 -0
- package/dist/domain/packageAnalysis.js +123 -0
- package/dist/domain/peInspection.js +196 -0
- package/dist/domain/protocolCapture.js +243 -0
- package/dist/dotnet/ManagedStaticProvider.js +34 -5
- package/dist/generatedMcpToolCatalog.js +37 -0
- package/dist/generatedPackageMetadata.js +4 -4
- package/dist/ghidra/GhidraDefaults.js +1 -1
- package/dist/ghidra/GhidraFunctionValues.js +27 -1
- package/dist/ghidra/GhidraProviderCapabilities.js +40 -38
- package/dist/hopper/HopperClient.js +26 -2
- package/dist/hopper/HopperProvider.js +42 -30
- package/dist/hopper/HopperRequestQueue.js +32 -4
- package/dist/hopper/HopperResponseStream.js +2 -2
- package/dist/hopper/protocol.js +63 -21
- package/dist/main/transport.js +2 -5
- package/dist/main.js +14 -12
- package/dist/mcpDoctor.js +2 -2
- package/dist/mcpStartupPolicy.js +14 -0
- package/dist/server/LazyToolCatalog.js +134 -0
- package/dist/server/createServer.js +64 -171
- package/dist/server/hydrateServerTools.js +191 -0
- package/dist/server/registerEnhancedTools.js +13 -3
- package/dist/server/registerEvidenceResources.js +50 -101
- package/dist/server/registerInvestigationTools.js +1 -2
- package/dist/server/registerJavaScriptApplicationGraphResource.js +0 -4
- package/dist/server/registerReconstructionObligationLedgerResource.js +0 -7
- package/dist/server/registerReconstructionReadinessResource.js +0 -7
- package/dist/server/registerSessionRecordTools.js +82 -12
- package/dist/server/registerSessionStatusTool.js +1 -1
- package/dist/server/registerSessionTools.js +21 -1
- package/dist/server/toolRegistrationOptions.js +21 -6
- package/dist/server/toolResult.js +12 -0
- package/package.json +21 -10
- package/scripts/package-runner-bootstrap.mjs +72 -0
- package/scripts/rea.mjs +11 -1
- package/skills/reverse-engineer-anything/SKILL.md +10 -3
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { TOOL_CONTRACTS } from "./toolContracts.js";
|
|
2
1
|
const optional = (description, completion) => ({
|
|
3
2
|
description,
|
|
4
3
|
required: false,
|
|
@@ -81,8 +80,8 @@ export const PROMPT_CONTRACTS = [
|
|
|
81
80
|
instruction: "Build function dossiers and corroborate references and call relationships. Keep indirect or truncated paths unknown.",
|
|
82
81
|
},
|
|
83
82
|
{
|
|
84
|
-
tools: ["
|
|
85
|
-
instruction: "
|
|
83
|
+
tools: ["snapshot_evidence_bundle", "record_unknown"],
|
|
84
|
+
instruction: "Snapshot the canonical bundle, copy its opaque URI unchanged, and read that resource before citing retained Evidence IDs. Record residual unknowns only after separate explicit approval for registry mutation.",
|
|
86
85
|
},
|
|
87
86
|
],
|
|
88
87
|
},
|
|
@@ -100,8 +99,8 @@ export const PROMPT_CONTRACTS = [
|
|
|
100
99
|
},
|
|
101
100
|
steps: [
|
|
102
101
|
{
|
|
103
|
-
tools: ["inventory_artifact"],
|
|
104
|
-
instruction: "
|
|
102
|
+
tools: ["open_binary", "inventory_artifact"],
|
|
103
|
+
instruction: "For each supplied target path, open that target before inventory because inventory_artifact uses the active target and accepts no path. Follow nodes, occurrences, and edges to completion and retain every Evidence page for each manifest.",
|
|
105
104
|
},
|
|
106
105
|
{
|
|
107
106
|
tools: [
|
|
@@ -112,8 +111,8 @@ export const PROMPT_CONTRACTS = [
|
|
|
112
111
|
instruction: "For JavaScript/Electron versions, reconstruct each approved artifact independently, optionally reconcile separately retained passive runtime Evidence, then compare authenticated graphs with unique-only identity tiers. Keep ambiguous and incomplete matches unknown.",
|
|
113
112
|
},
|
|
114
113
|
{
|
|
115
|
-
tools: ["
|
|
116
|
-
instruction: "
|
|
114
|
+
tools: ["snapshot_evidence_bundle", "compare_artifacts"],
|
|
115
|
+
instruction: "Snapshot and read the canonical bundle through its exact resource URI, resolve any supplied manifest IDs to retained inventory Evidence, validate graph commitments, then compare the complete left and right Evidence page sets.",
|
|
117
116
|
},
|
|
118
117
|
{
|
|
119
118
|
tools: ["open_binary", "analyze_function", "compare_functions"],
|
|
@@ -141,8 +140,8 @@ export const PROMPT_CONTRACTS = [
|
|
|
141
140
|
},
|
|
142
141
|
steps: [
|
|
143
142
|
{
|
|
144
|
-
tools: ["
|
|
145
|
-
instruction: "
|
|
143
|
+
tools: ["snapshot_evidence_bundle"],
|
|
144
|
+
instruction: "Snapshot the current canonical bundle, copy its opaque URI unchanged, read the resource, and verify that every selected comparison Evidence ID is present and compatible with the intended claim.",
|
|
146
145
|
},
|
|
147
146
|
{
|
|
148
147
|
tools: [
|
|
@@ -194,11 +193,11 @@ export const PROMPT_CONTRACTS = [
|
|
|
194
193
|
},
|
|
195
194
|
{
|
|
196
195
|
tools: [
|
|
197
|
-
"
|
|
196
|
+
"snapshot_evidence_bundle",
|
|
198
197
|
"capture_process_scenario",
|
|
199
198
|
"correlate_static_and_runtime",
|
|
200
199
|
],
|
|
201
|
-
instruction: "Reuse a retained capture when supplied. Otherwise capture only after operator policy and per-call approval, then correlate through explicit hypotheses rather than timing or name coincidence.",
|
|
200
|
+
instruction: "Snapshot and read retained Evidence through the exact resource URI. Reuse a retained capture when supplied. Otherwise capture only after operator policy and per-call approval, then correlate through explicit hypotheses rather than timing or name coincidence.",
|
|
202
201
|
},
|
|
203
202
|
{
|
|
204
203
|
tools: ["record_unknown"],
|
|
@@ -222,8 +221,8 @@ export const PROMPT_CONTRACTS = [
|
|
|
222
221
|
instruction: "List current heads first and select only active, session-owned unknown IDs. Preserve their exact revision and requirements.",
|
|
223
222
|
},
|
|
224
223
|
{
|
|
225
|
-
tools: ["
|
|
226
|
-
instruction: "
|
|
224
|
+
tools: ["snapshot_evidence_bundle", "verify_unknown_resolution"],
|
|
225
|
+
instruction: "Snapshot and read the canonical bundle through its exact resource URI, inspect cited supporting, contradicting, and mutation Evidence, then validate any resolved head against bundle integrity and authority requirements.",
|
|
227
226
|
},
|
|
228
227
|
{
|
|
229
228
|
tools: ["update_unknown"],
|
|
@@ -252,8 +251,8 @@ export const PROMPT_CONTRACTS = [
|
|
|
252
251
|
instruction: "Inspect capture capability, declared effects, and limits before proposing execution. An unavailable capability is not permission to widen policy.",
|
|
253
252
|
},
|
|
254
253
|
{
|
|
255
|
-
tools: ["
|
|
256
|
-
instruction: "
|
|
254
|
+
tools: ["snapshot_evidence_bundle"],
|
|
255
|
+
instruction: "Snapshot and read the canonical bundle through its exact resource URI, then review any prior capture for unanswered dimensions, truncation, scenario commitments, and descendant settlement before designing a repeat.",
|
|
257
256
|
},
|
|
258
257
|
{
|
|
259
258
|
tools: ["capture_process_scenario"],
|
|
@@ -31,10 +31,13 @@ export const TOOL_EXAMPLE_OVERRIDES = {
|
|
|
31
31
|
get_call_graph: { address: "0x1000" },
|
|
32
32
|
find_xrefs_to_name: { name: "malloc" },
|
|
33
33
|
analyze_function: { procedure: "main" },
|
|
34
|
+
inspect_native_api: { procedure: "main" },
|
|
34
35
|
trace_feature: { query: "license" },
|
|
35
36
|
find_code_for_string: { query: "authorization failed" },
|
|
36
37
|
trace_call_path: { start: "0x1000", goal: "0x1100" },
|
|
37
38
|
open_binary: { path: "/tmp/fixture" },
|
|
39
|
+
export_evidence_bundle: { path: "/tmp/evidence.json" },
|
|
40
|
+
inspect_address_context: { address: "0x1000" },
|
|
38
41
|
import_evidence_bundle: { path: "evidence.json" },
|
|
39
42
|
capture_process_scenario: {
|
|
40
43
|
approved: true,
|
|
@@ -28,6 +28,7 @@ import { binarySessionInputSchema } from "./sessionStatusContract.js";
|
|
|
28
28
|
import { functionInstructionInputSchema } from "./functionInstructionContract.js";
|
|
29
29
|
import { HOPPER_MEMORY_TOOL_DEFINITIONS } from "./hopperMemoryContracts.js";
|
|
30
30
|
import { analysisSearchInput } from "./analysisSearchContract.js";
|
|
31
|
+
import { FUNCTION_WORKFLOW_TOOL_CONTRACTS } from "./functionWorkflowToolContracts.js";
|
|
31
32
|
export { binarySessionInputSchema } from "./sessionStatusContract.js";
|
|
32
33
|
const document = z.string().optional().describe("The document name");
|
|
33
34
|
const address = z
|
|
@@ -139,16 +140,27 @@ export const ENHANCED_TOOL_CONTRACTS = [
|
|
|
139
140
|
enhanced("analyze_swift_types", "Categorize exhaustively paged procedure names into Swift classes, structs, enums, protocols, extensions, and other symbols. Scans at most 5,000 names and returns at most 50 entries per category.", enhancedInputSchemas.analyze_swift_types),
|
|
140
141
|
enhanced("find_xrefs_to_name", "Resolve an exact name through the bound provider's exhaustively paged name inventory and return a resolved or unresolved result. Unresolved names use the stable name_not_found reason; this compact xref workflow returns address-only projections.", enhancedInputSchemas.find_xrefs_to_name),
|
|
141
142
|
enhanced("binary_overview", "Use immediately after opening a target to summarize document, exhaustive procedure/string counts, and a bounded segment sample. detail controls segment fields and limit controls only the returned segment sample.", enhancedInputSchemas.binary_overview),
|
|
142
|
-
|
|
143
|
+
...FUNCTION_WORKFLOW_TOOL_CONTRACTS,
|
|
143
144
|
enhanced("trace_feature", "Trace a bounded literal feature query through matching strings and procedures, xrefs, and truthful containing-procedure resolution. Returns the operation budget, truncation, and residual unknowns; unknown_registry_approved: true records them durably without inferring reference kinds.", enhancedInputSchemas.trace_feature),
|
|
144
145
|
enhanced("find_code_for_string", "Resolve one literal string query to bounded analyzed string entries, xrefs, and truthful containing-procedure candidates. Returns an Evidence ID, exact operation budget, truncation, and residual unknowns; it never infers reference kinds or runtime reachability.", enhancedInputSchemas.find_code_for_string),
|
|
145
146
|
enhanced("trace_call_path", "Trace a deterministic bounded caller or callee path from one exact procedure address, optionally stopping at a goal. Returns visited nodes, direct-call edges, one shortest traversal path, failures, frontier, consumed limits, an Evidence ID, and explicit residual unknowns without claiming unresolved indirect calls are absent.", enhancedInputSchemas.trace_call_path),
|
|
146
147
|
];
|
|
147
148
|
/** Session-owned Evidence bundle export options. */
|
|
148
149
|
export const exportEvidenceBundleInputSchema = z.strictObject({
|
|
149
|
-
path: z.string().min(1)
|
|
150
|
+
path: z.string().min(1),
|
|
150
151
|
overwrite: z.boolean().default(false),
|
|
151
152
|
});
|
|
153
|
+
/** Retain the current canonical Evidence bundle as a session resource. */
|
|
154
|
+
export const snapshotEvidenceBundleInputSchema = z.strictObject({});
|
|
155
|
+
/** Optional document selection for volatile navigation context. */
|
|
156
|
+
export const navigationContextInputSchema = z.strictObject({
|
|
157
|
+
document: z.string().min(1).optional(),
|
|
158
|
+
});
|
|
159
|
+
/** Explicit reproducible address context query. */
|
|
160
|
+
export const addressContextInputSchema = z.strictObject({
|
|
161
|
+
address: z.string().min(1),
|
|
162
|
+
document: z.string().min(1).optional(),
|
|
163
|
+
});
|
|
152
164
|
/** Session-owned Evidence bundle import options. */
|
|
153
165
|
export const importEvidenceBundleInputSchema = z.strictObject({
|
|
154
166
|
path: z.string().min(1),
|
|
@@ -171,6 +183,8 @@ export const listUnknownsInputSchema = z.strictObject({
|
|
|
171
183
|
.optional(),
|
|
172
184
|
severity: z.enum(["low", "medium", "high", "critical"]).optional(),
|
|
173
185
|
domain: z.string().trim().min(1).max(100).optional(),
|
|
186
|
+
offset: z.number().int().min(0).default(0),
|
|
187
|
+
limit: z.number().int().min(1).max(500).default(100),
|
|
174
188
|
});
|
|
175
189
|
/** Exact residual-unknown identity to revalidate. */
|
|
176
190
|
export const verifyUnknownResolutionInputSchema = z.strictObject({
|
|
@@ -181,7 +195,7 @@ export const SESSION_TOOL_CONTRACTS = [
|
|
|
181
195
|
session("open_binary", "Open a local executable, application bundle, archive, JavaScript, source map, plist, or analysis database after validation. provider_id selects one deep provider or deterministic auto selection; the binding remains stable until close or an explicit switch, with no failure fallback. An optional snapshot v2 is imported atomically and must match the binary identity, concrete provider, and canonical analysis profile exactly.", openBinaryInputSchema),
|
|
182
196
|
session("close_binary", "Optionally write a provider-neutral analysis snapshot atomically, then close the active target and every provider resource started for it. Snapshot files require an operator-approved root and explicit overwrite; a failed save leaves the session open so cached analysis is not lost.", closeBinaryInputSchema),
|
|
183
197
|
session("binary_session", "Report compact target, provider, and alignment state without starting analysis. The default summary is the routing check agents should use; detail=capabilities returns one family-filtered availability page, while detail=full is reserved for complete provider diagnostics.", binarySessionInputSchema),
|
|
184
|
-
session("export_evidence_bundle", "
|
|
198
|
+
session("export_evidence_bundle", "Atomically write the session's deterministic Evidence v2 bundle beneath an operator-approved root. Existing files require overwrite: true; records and manifests use canonical byte-stable ordering. For an in-session read, use snapshot_evidence_bundle and read its exact resource URI instead.", exportEvidenceBundleInputSchema),
|
|
185
199
|
session("import_evidence_bundle", "Read a bounded local JSON bundle beneath an operator-approved root, validate every Evidence v2 ID and canonical manifest, then atomically merge it. Imported content is data only and is never executed.", importEvidenceBundleInputSchema),
|
|
186
200
|
session("capture_process_scenario", "Run one bounded process under a PTY using operator-approved executable and working roots. Produces Process Capture v4; legacy v3 captures cannot be upgraded and must be recaptured with this tool. Requires approved: true; unknown_registry_approved: true separately records capture residuals. Captures raw and xterm-rendered terminal frames, scripted interactions, lifecycle filesystem checkpoints, process ownership, declarative command shims, and loopback replay. Disabled unless operator policy enables it; not a security sandbox.", processScenarioSchema),
|
|
187
201
|
session("compare_process_captures", "Compare two compatible Process Capture v4 observations across terminal, interaction, lifecycle, process, filesystem, command-shim, HTTP, and WebSocket evidence. Optional trace_spec validates exact events against an explicit partial order or finite trace language; concurrency is never inferred from timestamps or broad sorting. Missing, journal-free, or truncated observations are never treated as equivalent.", processComparisonInputSchema),
|
|
@@ -192,11 +206,14 @@ export const SESSION_TOOL_CONTRACTS = [
|
|
|
192
206
|
session("build_call_path", "Build bounded shortest-first direct-callee paths from explicit analyze_function Evidence groups using exact canonical addresses. Missing dossiers, incomplete callee pages, provider mixing, and depth frontiers remain unknown; every node and edge cites source Evidence.", callPathInputSchema),
|
|
193
207
|
session("correlate_static_and_runtime", "Evaluate explicit caller-declared hypotheses between exact static comparison findings and runtime comparison dimensions. Similar names or paths are never auto-matched, consistent cochange never proves causality, and unknown or truncated inputs remain unresolved.", staticRuntimeCorrelationInputSchema),
|
|
194
208
|
session("verify_reconstruction", "Verify a finite typed behavioral and structural specification against a canonical Evidence bundle. Pass means every declared claim has complete comparable authority—not global source equivalence; changed claims fail and missing, limited, or unresolved evidence stays unknown.", reconstructionVerificationInputSchema),
|
|
195
|
-
session("list_unknowns", "List current residual-unknown heads in deterministic ID order, with optional exact status, severity, and domain filters. This is read-only; unresolved, contradicted, and non-truth dispositions remain distinct.", listUnknownsInputSchema),
|
|
209
|
+
session("list_unknowns", "List current residual-unknown heads in deterministic ID order, with optional exact status, severity, and domain filters. Pages default to 100 items; while has_more is true, pass next_offset as offset and continue until false. This is read-only; unresolved, contradicted, and non-truth dispositions remain distinct.", listUnknownsInputSchema),
|
|
196
210
|
session("record_unknown", "Create one deterministic residual unknown and immutable mutation evidence. Requires approved: true, validates all evidence and relationship references, and rejects duplicate stable identity.", recordUnknownInputSchema),
|
|
197
211
|
session("update_unknown", "Append one immutable full-state revision and mutation evidence. Requires approved: true and exact expected_revision; stale concurrent writers fail instead of overwriting newer analysis.", updateUnknownInputSchema),
|
|
198
212
|
session("verify_unknown_resolution", "Revalidate the current residual-unknown head against live bundled evidence, exact authority/confidence/environment requirements, and revision integrity. Withdrawn and out-of-scope dispositions are not truth claims.", verifyUnknownResolutionInputSchema),
|
|
199
213
|
session("run_replay_machine", "Evaluate ordered HTTP and WebSocket events directly against one validated finite replay machine without opening sockets or launching a target. Returns every decision, a capture-value-free transition journal, one redacted action table entry per used transition, captured aliases, final state, and exact configured and consumed limits.", replayMachineRunInputSchema),
|
|
214
|
+
session("snapshot_evidence_bundle", "Retain the current canonical Evidence v2 bundle as an immutable session resource. Returns a compact digest summary and exact opaque URI; copy that URI unchanged and call MCP resources/read (Codex: read_mcp_resource) for the full bundle. Repeating an unchanged snapshot is idempotent.", snapshotEvidenceBundleInputSchema),
|
|
215
|
+
session("get_navigation_context", "Return the selected document, current address, and containing/current procedure in one coherent provider-neutral request. A cursor outside any procedure returns procedure: null. Scalar navigation getters remain available for evaluation and compatibility.", navigationContextInputSchema),
|
|
216
|
+
session("inspect_address_context", "Inspect one explicit reproducible address for its analyzed name, containing procedure, regular and inline comments, and matching bookmarks. Each unsupported facet returns a typed unavailable outcome; xrefs, assembly, and pseudocode remain separate bounded follow-ups.", addressContextInputSchema),
|
|
200
217
|
];
|
|
201
218
|
/** Complete ordered public inventory used by registration and verification. */
|
|
202
219
|
export const TOOL_CONTRACTS = [
|
|
@@ -67,6 +67,7 @@ export const TOOL_EFFECTS = {
|
|
|
67
67
|
find_xrefs_to_name: evidence,
|
|
68
68
|
binary_overview: evidence,
|
|
69
69
|
analyze_function: evidence,
|
|
70
|
+
inspect_native_api: effects({ mutatesSession: true, idempotent: false }),
|
|
70
71
|
trace_feature: effects({ mutatesSession: true, idempotent: false }),
|
|
71
72
|
find_code_for_string: effects({ mutatesSession: true, idempotent: false }),
|
|
72
73
|
trace_call_path: effects({ mutatesSession: true, idempotent: false }),
|
|
@@ -149,6 +150,9 @@ export const TOOL_EFFECTS = {
|
|
|
149
150
|
writesFilesystem: true,
|
|
150
151
|
mayDiscardData: true,
|
|
151
152
|
}),
|
|
153
|
+
snapshot_evidence_bundle: effects({ mutatesSession: true }),
|
|
154
|
+
get_navigation_context: effects({ mutatesSession: true }),
|
|
155
|
+
inspect_address_context: effects({ mutatesSession: true }),
|
|
152
156
|
import_evidence_bundle: effects({ mutatesSession: true }),
|
|
153
157
|
capture_process_scenario: effects({
|
|
154
158
|
mutatesSession: true,
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { jsonValueSchema } from "../domain/jsonValue.js";
|
|
2
3
|
import { processCaptureComparisonSchema, processCaptureSchema, } from "../domain/processCapture.js";
|
|
3
|
-
import { evidenceBundleSchema } from "../domain/evidenceBundle.js";
|
|
4
4
|
import { residualUnknownSchema } from "../domain/residualUnknown.js";
|
|
5
5
|
import { functionInstructionWindowSchema, referenceKindSchema, } from "../domain/hopperValues.js";
|
|
6
|
+
import { nativeApiInspectionResultSchema } from "../domain/nativeApiBoundary.js";
|
|
6
7
|
import { demangleSwiftSchema, inspectMachoSchema, inspectPlistSchema, inspectSignatureSchema, listArchitecturesSchema, } from "../domain/nativeInspection.js";
|
|
7
8
|
import { artifactExtractionResultSchema, artifactInventoryResultSchema, } from "../domain/artifactGraph.js";
|
|
8
9
|
import { artifactInspectionResultSchema } from "../domain/artifactInspection.js";
|
|
@@ -22,6 +23,14 @@ import { reconstructionVerificationResultSchema } from "../domain/reconstruction
|
|
|
22
23
|
import { replayMachineRunOutputSchema } from "../domain/replayMachineRun.js";
|
|
23
24
|
import { analysisErrorProjectionSchema } from "./errorSchemas.js";
|
|
24
25
|
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";
|
|
26
|
+
const contextFacetSchema = z.discriminatedUnion("state", [
|
|
27
|
+
z.object({ state: z.literal("available"), value: jsonValueSchema }),
|
|
28
|
+
z.object({
|
|
29
|
+
state: z.literal("unavailable"),
|
|
30
|
+
reason: z.string(),
|
|
31
|
+
remediation: z.string(),
|
|
32
|
+
}),
|
|
33
|
+
]);
|
|
25
34
|
/** Exact structured-content schemas shared by direct analysis providers. */
|
|
26
35
|
export const officialOutputSchemas = {
|
|
27
36
|
address_name: resultOf(nullableText),
|
|
@@ -188,6 +197,7 @@ export const enhancedOutputSchemas = {
|
|
|
188
197
|
string_count: z.number().int().min(0),
|
|
189
198
|
})),
|
|
190
199
|
analyze_function: functionDossierOutput,
|
|
200
|
+
inspect_native_api: resultOf(nativeApiInspectionResultSchema),
|
|
191
201
|
trace_feature: literalTraceOutput,
|
|
192
202
|
find_code_for_string: literalTraceOutput,
|
|
193
203
|
trace_call_path: callPathTraceOutput,
|
|
@@ -293,14 +303,34 @@ export const sessionOutputSchemas = {
|
|
|
293
303
|
}),
|
|
294
304
|
]),
|
|
295
305
|
])),
|
|
296
|
-
export_evidence_bundle: lifecycleResultOf(z.
|
|
297
|
-
|
|
298
|
-
z.
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
306
|
+
export_evidence_bundle: lifecycleResultOf(z.object({
|
|
307
|
+
path: z.string(),
|
|
308
|
+
bytes: z.number().int().min(0),
|
|
309
|
+
records: z.number().int().min(0),
|
|
310
|
+
unknowns: z.number().int().min(0),
|
|
311
|
+
})),
|
|
312
|
+
snapshot_evidence_bundle: lifecycleResultOf(z.object({
|
|
313
|
+
bundle_digest: z.string().regex(/^[a-f0-9]{64}$/u),
|
|
314
|
+
bundle_version: z.literal(2),
|
|
315
|
+
bytes: z.number().int().min(0),
|
|
316
|
+
records: z.number().int().min(0),
|
|
317
|
+
unknowns: z.number().int().min(0),
|
|
318
|
+
bundle_uri: z.string().regex(/^rea:\/\/evidence-bundle\/[a-f0-9]{64}$/u),
|
|
319
|
+
})),
|
|
320
|
+
get_navigation_context: lifecycleResultOf(z.object({
|
|
321
|
+
document: z.string(),
|
|
322
|
+
address: z.string(),
|
|
323
|
+
procedure: z.union([z.string(), z.null()]),
|
|
324
|
+
})),
|
|
325
|
+
inspect_address_context: lifecycleResultOf(z.object({
|
|
326
|
+
address: z.string(),
|
|
327
|
+
document: z.string().nullable(),
|
|
328
|
+
name: contextFacetSchema,
|
|
329
|
+
procedure: contextFacetSchema,
|
|
330
|
+
comment: contextFacetSchema,
|
|
331
|
+
inline_comment: contextFacetSchema,
|
|
332
|
+
bookmarks: contextFacetSchema,
|
|
333
|
+
})),
|
|
304
334
|
import_evidence_bundle: lifecycleResultOf(z.object({
|
|
305
335
|
imported: z.number().int().min(0),
|
|
306
336
|
total: z.number().int().min(0),
|
|
@@ -314,7 +344,17 @@ export const sessionOutputSchemas = {
|
|
|
314
344
|
build_call_path: resultOf(callPathResultSchema),
|
|
315
345
|
correlate_static_and_runtime: resultOf(staticRuntimeCorrelationResultSchema),
|
|
316
346
|
verify_reconstruction: resultOf(reconstructionVerificationResultSchema),
|
|
317
|
-
list_unknowns: lifecycleResultOf(z.
|
|
347
|
+
list_unknowns: lifecycleResultOf(z.object({
|
|
348
|
+
items: z.array(z.object({
|
|
349
|
+
unknown: residualUnknownSchema,
|
|
350
|
+
uri: z.string().regex(/^rea:\/\/unknown\/unk_[a-f0-9]{64}$/u),
|
|
351
|
+
})),
|
|
352
|
+
offset: z.number().int().min(0),
|
|
353
|
+
limit: z.number().int().min(1).max(500),
|
|
354
|
+
total: z.number().int().min(0),
|
|
355
|
+
next_offset: z.number().int().min(0).nullable(),
|
|
356
|
+
has_more: z.boolean(),
|
|
357
|
+
})),
|
|
318
358
|
record_unknown: lifecycleResultOf(residualUnknownSchema),
|
|
319
359
|
update_unknown: lifecycleResultOf(residualUnknownSchema),
|
|
320
360
|
verify_unknown_resolution: lifecycleResultOf(z.object({
|
|
@@ -2,6 +2,8 @@ import { AnalysisInputError, ArtifactOperationError, BinaryTargetError, BrowserO
|
|
|
2
2
|
export const analysisErrorRemediationAction = (error) => {
|
|
3
3
|
if (error instanceof AnalysisInputError)
|
|
4
4
|
return "Correct the listed arguments and retry.";
|
|
5
|
+
if (error instanceof UnknownRegistryError && error.reason === "not-found")
|
|
6
|
+
return "Check that the unknown_id belongs to this session, then retry.";
|
|
5
7
|
if (error instanceof ReplayPlanStaleError)
|
|
6
8
|
return "Review the rebuilt replay plan and explicitly approve its new digest.";
|
|
7
9
|
if (error instanceof PermissionRequiredError)
|
|
@@ -64,7 +66,7 @@ const artifactErrorCategory = (reason) => {
|
|
|
64
66
|
return "truncated";
|
|
65
67
|
if (reason === "cancelled")
|
|
66
68
|
return "cancelled";
|
|
67
|
-
if (reason === "unavailable")
|
|
69
|
+
if (reason === "policy" || reason === "unavailable")
|
|
68
70
|
return "unavailable";
|
|
69
71
|
return "execution_failure";
|
|
70
72
|
};
|
|
@@ -103,6 +105,8 @@ export const analysisErrorUserMessage = (error) => {
|
|
|
103
105
|
return evidenceFileMessage(error.reason);
|
|
104
106
|
if (error instanceof InvestigationWorkspaceError)
|
|
105
107
|
return investigationWorkspaceMessage(error.reason);
|
|
108
|
+
if (error instanceof UnknownRegistryError && error.reason === "not-found")
|
|
109
|
+
return "The requested residual unknown does not exist in this session. Check the unknown_id and try again.";
|
|
106
110
|
if (error instanceof UnknownRegistryError)
|
|
107
111
|
return "Evidence state changed before the update completed. Refresh the current state and try again.";
|
|
108
112
|
if (error instanceof ConfigurationError)
|
|
@@ -163,8 +167,10 @@ const artifactMessage = (reason) => {
|
|
|
163
167
|
return "Artifact is too large to process safely. Narrow the requested path or use a smaller artifact.";
|
|
164
168
|
if (reason === "path")
|
|
165
169
|
return "Artifact path is not allowed. Choose a path inside the artifact and try again.";
|
|
170
|
+
if (reason === "policy")
|
|
171
|
+
return "Artifact integrity continuation is disabled by policy. Configure REA_ARTIFACT_INTEGRITY_CONTINUE_ENABLED=true and retry only if continuing after mismatches is approved.";
|
|
166
172
|
if (reason === "unavailable")
|
|
167
|
-
return "Artifact
|
|
173
|
+
return "Artifact processing is unavailable for the current target or policy. Check artifact support and required approvals.";
|
|
168
174
|
if (reason === "format" || reason === "integrity")
|
|
169
175
|
return "Artifact is invalid or has changed. Get a fresh copy and try again.";
|
|
170
176
|
return "Artifact could not be read or written. Check file access and try again.";
|
|
@@ -152,6 +152,7 @@ const requestErrorDetails = (error) => {
|
|
|
152
152
|
issues: error.issues.map((issue) => ({
|
|
153
153
|
path: [...issue.path],
|
|
154
154
|
reason: issue.reason,
|
|
155
|
+
...(issue.message === undefined ? {} : { message: issue.message }),
|
|
155
156
|
...(issue.expected === undefined ? {} : { expected: issue.expected }),
|
|
156
157
|
...(issue.minimum === undefined ? {} : { minimum: issue.minimum }),
|
|
157
158
|
...(issue.maximum === undefined ? {} : { maximum: issue.maximum }),
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** Supported managed-runtime bytecode families. */
|
|
3
|
+
export const bytecodeFamilySchema = z.enum(["jvm", "python"]);
|
|
4
|
+
/** Classification of bytecode provenance. */
|
|
5
|
+
export const bytecodeProvenanceSchema = z.enum([
|
|
6
|
+
"application",
|
|
7
|
+
"generated",
|
|
8
|
+
"vendored",
|
|
9
|
+
"bundled",
|
|
10
|
+
"standard_library",
|
|
11
|
+
]);
|
|
12
|
+
/** A bytecode symbol discovered through static analysis. */
|
|
13
|
+
export const bytecodeSymbolSchema = z.strictObject({
|
|
14
|
+
/** Fully qualified name. */
|
|
15
|
+
name: z.string().min(1),
|
|
16
|
+
/** Raw bytecode location or offset. */
|
|
17
|
+
raw_location: z.string().min(1),
|
|
18
|
+
/** Normalized symbol type. */
|
|
19
|
+
kind: z.enum([
|
|
20
|
+
"class",
|
|
21
|
+
"interface",
|
|
22
|
+
"method",
|
|
23
|
+
"field",
|
|
24
|
+
"function",
|
|
25
|
+
"module",
|
|
26
|
+
"variable",
|
|
27
|
+
]),
|
|
28
|
+
/** Bytecode version if known. */
|
|
29
|
+
bytecode_version: z.number().int().nullable(),
|
|
30
|
+
/** Provenance classification. */
|
|
31
|
+
provenance: bytecodeProvenanceSchema,
|
|
32
|
+
/** Whether the symbol is accessible (public). */
|
|
33
|
+
is_public: z.boolean().default(false),
|
|
34
|
+
});
|
|
35
|
+
/** A discovered bytecode artifact (class file, wheel, etc). */
|
|
36
|
+
export const bytecodeArtifactSchema = z.strictObject({
|
|
37
|
+
/** Artifact path relative to the analysis root. */
|
|
38
|
+
path: z.string().min(1),
|
|
39
|
+
/** Bytecode family. */
|
|
40
|
+
family: bytecodeFamilySchema,
|
|
41
|
+
/** Artifact format. */
|
|
42
|
+
format: z.enum(["class", "jar", "war", "ear", "pyc", "pyo", "whl", "zipapp"]),
|
|
43
|
+
/** Size in bytes. */
|
|
44
|
+
size: z.number().int().nonnegative(),
|
|
45
|
+
/** SHA-256 digest. */
|
|
46
|
+
digest: z.string().regex(/^[a-f0-9]{64}$/u),
|
|
47
|
+
/** Discovered symbols. */
|
|
48
|
+
symbols: z.array(bytecodeSymbolSchema).default([]),
|
|
49
|
+
/** Whether this is a standard library artifact. */
|
|
50
|
+
is_standard_library: z.boolean().default(false),
|
|
51
|
+
/** Whether this is a generated artifact. */
|
|
52
|
+
is_generated: z.boolean().default(false),
|
|
53
|
+
/** Whether this is a vendored artifact. */
|
|
54
|
+
is_vendored: z.boolean().default(false),
|
|
55
|
+
});
|
|
56
|
+
/** Static bytecode analysis result. */
|
|
57
|
+
export const bytecodeAnalysisSchema = z.strictObject({
|
|
58
|
+
/** Bytecode family. */
|
|
59
|
+
family: bytecodeFamilySchema,
|
|
60
|
+
/** All discovered artifacts. */
|
|
61
|
+
artifacts: z.array(bytecodeArtifactSchema).min(0).max(10_000),
|
|
62
|
+
/** Total symbols across all artifacts. */
|
|
63
|
+
total_symbols: z.number().int().nonnegative(),
|
|
64
|
+
/** Symbols classified as application code. */
|
|
65
|
+
application_symbols: z.number().int().nonnegative(),
|
|
66
|
+
/** Symbols classified as generated code. */
|
|
67
|
+
generated_symbols: z.number().int().nonnegative(),
|
|
68
|
+
/** Symbols classified as vendored code. */
|
|
69
|
+
vendored_symbols: z.number().int().nonnegative(),
|
|
70
|
+
/** Symbols classified as standard library. */
|
|
71
|
+
standard_library_symbols: z.number().int().nonnegative(),
|
|
72
|
+
});
|
|
73
|
+
/** Detect bytecode family from file extension. */
|
|
74
|
+
export function detectBytecodeFamily(path) {
|
|
75
|
+
const lower = path.toLowerCase();
|
|
76
|
+
if (lower.endsWith(".class") ||
|
|
77
|
+
lower.endsWith(".jar") ||
|
|
78
|
+
lower.endsWith(".war") ||
|
|
79
|
+
lower.endsWith(".ear")) {
|
|
80
|
+
return "jvm";
|
|
81
|
+
}
|
|
82
|
+
if (lower.endsWith(".pyc") ||
|
|
83
|
+
lower.endsWith(".pyo") ||
|
|
84
|
+
lower.endsWith(".whl") ||
|
|
85
|
+
lower.endsWith(".pyz") ||
|
|
86
|
+
lower.endsWith(".zipapp")) {
|
|
87
|
+
return "python";
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
/** Detect artifact format from file path. */
|
|
92
|
+
export function detectArtifactFormat(path) {
|
|
93
|
+
const lower = path.toLowerCase();
|
|
94
|
+
if (lower.endsWith(".class"))
|
|
95
|
+
return "class";
|
|
96
|
+
if (lower.endsWith(".jar"))
|
|
97
|
+
return "jar";
|
|
98
|
+
if (lower.endsWith(".war"))
|
|
99
|
+
return "war";
|
|
100
|
+
if (lower.endsWith(".ear"))
|
|
101
|
+
return "ear";
|
|
102
|
+
if (lower.endsWith(".pyc"))
|
|
103
|
+
return "pyc";
|
|
104
|
+
if (lower.endsWith(".pyo"))
|
|
105
|
+
return "pyo";
|
|
106
|
+
if (lower.endsWith(".whl"))
|
|
107
|
+
return "whl";
|
|
108
|
+
if (lower.endsWith(".pyz") || lower.endsWith(".zipapp"))
|
|
109
|
+
return "zipapp";
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
/** Classify bytecode symbol provenance. */
|
|
113
|
+
export function classifyProvenance(path, symbolName) {
|
|
114
|
+
const lower = path.toLowerCase();
|
|
115
|
+
// Standard library paths
|
|
116
|
+
if (lower.includes("/stdlib/") ||
|
|
117
|
+
lower.includes("/site-packages/") ||
|
|
118
|
+
lower.includes("java/") ||
|
|
119
|
+
lower.includes("javax/") ||
|
|
120
|
+
lower.includes("sun/") ||
|
|
121
|
+
symbolName.startsWith("java.") ||
|
|
122
|
+
symbolName.startsWith("javax.") ||
|
|
123
|
+
symbolName.startsWith("sun.") ||
|
|
124
|
+
symbolName.startsWith("__")) {
|
|
125
|
+
return "standard_library";
|
|
126
|
+
}
|
|
127
|
+
// Generated code
|
|
128
|
+
if (lower.includes("/generated/") ||
|
|
129
|
+
lower.includes("_generated") ||
|
|
130
|
+
lower.includes("/build/") ||
|
|
131
|
+
lower.includes("/target/") ||
|
|
132
|
+
lower.includes("/dist-packages/") ||
|
|
133
|
+
lower.includes("/__pycache__/") ||
|
|
134
|
+
symbolName.includes("Generated") ||
|
|
135
|
+
symbolName.includes("_generated")) {
|
|
136
|
+
return "generated";
|
|
137
|
+
}
|
|
138
|
+
// Vendored code
|
|
139
|
+
if (lower.includes("/vendor/") ||
|
|
140
|
+
lower.includes("/vendored/") ||
|
|
141
|
+
lower.includes("/third_party/") ||
|
|
142
|
+
lower.includes("/3rdparty/") ||
|
|
143
|
+
lower.includes("/node_modules/") ||
|
|
144
|
+
lower.includes("/vendor/")) {
|
|
145
|
+
return "vendored";
|
|
146
|
+
}
|
|
147
|
+
// Bundled code
|
|
148
|
+
if (lower.includes("/bundle/") ||
|
|
149
|
+
lower.includes("/bundled/") ||
|
|
150
|
+
lower.includes(".jar!") ||
|
|
151
|
+
lower.includes(".war!")) {
|
|
152
|
+
return "bundled";
|
|
153
|
+
}
|
|
154
|
+
return "application";
|
|
155
|
+
}
|
|
156
|
+
/** Analyze a set of bytecode artifacts and produce a summary. */
|
|
157
|
+
export function analyzeBytecodeArtifacts(artifacts, family) {
|
|
158
|
+
const applicationSymbols = artifacts
|
|
159
|
+
.flatMap((a) => a.symbols)
|
|
160
|
+
.filter((s) => s.provenance === "application").length;
|
|
161
|
+
const generatedSymbols = artifacts
|
|
162
|
+
.flatMap((a) => a.symbols)
|
|
163
|
+
.filter((s) => s.provenance === "generated").length;
|
|
164
|
+
const vendoredSymbols = artifacts
|
|
165
|
+
.flatMap((a) => a.symbols)
|
|
166
|
+
.filter((s) => s.provenance === "vendored").length;
|
|
167
|
+
const standardLibrarySymbols = artifacts
|
|
168
|
+
.flatMap((a) => a.symbols)
|
|
169
|
+
.filter((s) => s.provenance === "standard_library").length;
|
|
170
|
+
return {
|
|
171
|
+
family,
|
|
172
|
+
artifacts: artifacts.slice(0, 10_000),
|
|
173
|
+
total_symbols: artifacts.reduce((sum, a) => sum + a.symbols.length, 0),
|
|
174
|
+
application_symbols: applicationSymbols,
|
|
175
|
+
generated_symbols: generatedSymbols,
|
|
176
|
+
vendored_symbols: vendoredSymbols,
|
|
177
|
+
standard_library_symbols: standardLibrarySymbols,
|
|
178
|
+
};
|
|
179
|
+
}
|