rea-agents 2.3.0 → 2.5.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.
Files changed (209) hide show
  1. package/README.md +80 -18
  2. package/bridge/ghidra/ReaGhidraBridge.java +48 -1
  3. package/bridge/hopper_bridge.py +259 -24
  4. package/dist/application/AnalysisClientCleanup.js +14 -0
  5. package/dist/application/ApplicationWorkflowEvidenceResolver.js +31 -13
  6. package/dist/application/ArtifactExtraction.js +5 -1
  7. package/dist/application/ArtifactGraphConstruction.js +3 -15
  8. package/dist/application/ArtifactInventory/classify.js +5 -1
  9. package/dist/application/ArtifactInventory/reader.js +2 -0
  10. package/dist/application/BinarySession.js +15 -4
  11. package/dist/application/BinarySessionStatus.js +32 -1
  12. package/dist/application/BrowserEvidence.js +14 -0
  13. package/dist/application/BrowserScenarioCapturePort.js +1 -0
  14. package/dist/application/BrowserScenarioCaptureService.js +53 -0
  15. package/dist/application/BrowserScenarioEvidence.js +40 -0
  16. package/dist/application/CallPathTracing.js +160 -0
  17. package/dist/application/CapabilityInventory.js +79 -15
  18. package/dist/application/CompositeProvider.js +10 -1
  19. package/dist/application/DirectAnalysis.js +7 -2
  20. package/dist/application/EnhancedLiteralTracing.js +118 -0
  21. package/dist/application/EnhancedTools.js +35 -121
  22. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +13 -0
  23. package/dist/application/JavaScriptApplicationWorkflowService.js +27 -1
  24. package/dist/application/JavaScriptRuntimeObservationEvidence.js +34 -0
  25. package/dist/application/JavaScriptRuntimeObservationPort.js +1 -0
  26. package/dist/application/JavaScriptRuntimeObservationService.js +46 -0
  27. package/dist/application/JavaScriptSemanticGraphAsyncProjection.js +147 -0
  28. package/dist/application/JavaScriptSemanticGraphBuilder.js +34 -6
  29. package/dist/application/JavaScriptSemanticGraphChildProcessProjection.js +156 -0
  30. package/dist/application/JavaScriptSemanticGraphConstruction.js +2 -2
  31. package/dist/application/JavaScriptSemanticGraphDataProjection.js +203 -0
  32. package/dist/application/JavaScriptSemanticGraphFingerprintProjection.js +25 -0
  33. package/dist/application/JavaScriptSemanticGraphFlowProjection.js +129 -8
  34. package/dist/application/JavaScriptSemanticGraphObjectProjection.js +81 -0
  35. package/dist/application/JavaScriptSemanticGraphProjection.js +14 -7
  36. package/dist/application/JavaScriptSemanticGraphResourceProjection.js +59 -0
  37. package/dist/application/JavaScriptSemanticGraphValueProjection.js +77 -0
  38. package/dist/application/ProcessCaptureEnvironment.js +26 -0
  39. package/dist/application/ProcessCaptureLifecycle.js +1 -0
  40. package/dist/application/ProcessCheckpoints.js +5 -0
  41. package/dist/application/ProcessHarness.js +45 -34
  42. package/dist/application/ProcessNormalization.js +6 -0
  43. package/dist/application/ProcessReactiveCoordinator.js +10 -3
  44. package/dist/application/ProcessReactiveEffects.js +15 -1
  45. package/dist/application/ProcessReactiveHarness.js +100 -0
  46. package/dist/application/ProcessReactiveObservations.js +101 -16
  47. package/dist/application/ProjectPermissionStore.js +1 -0
  48. package/dist/application/ReconstructionObligationAuthority.js +72 -0
  49. package/dist/application/ReconstructionObligationCandidates.js +265 -0
  50. package/dist/application/ReconstructionObligationLedgerDiagnostics.js +47 -0
  51. package/dist/application/ReconstructionObligationLedgerEvaluation.js +263 -0
  52. package/dist/application/ReconstructionObligationLedgerProjection.js +86 -0
  53. package/dist/application/ReconstructionObligationLedgerService.js +72 -0
  54. package/dist/application/ReconstructionObligationOriginalCases.js +33 -0
  55. package/dist/application/ReconstructionObligationPolicies.js +132 -0
  56. package/dist/application/ReconstructionReadinessService.js +48 -0
  57. package/dist/artifacts/ArtifactProvider.js +87 -22
  58. package/dist/browser/BrowserScenarioSecrets.js +53 -0
  59. package/dist/browser/BrowserScenarioSessionPort.js +1 -0
  60. package/dist/browser/CdpBrowserProvider.js +2 -2
  61. package/dist/browser/CdpCaptureDocuments.js +57 -0
  62. package/dist/browser/CdpCaptureStorage.js +71 -29
  63. package/dist/browser/CdpCaptureStorageFingerprints.js +328 -0
  64. package/dist/browser/CdpEndpoint.js +8 -6
  65. package/dist/browser/CdpPageCapture.js +2 -0
  66. package/dist/browser/JavaScriptRuntimeScope.js +38 -0
  67. package/dist/browser/PlaywrightBrowserScenarioProvider.js +253 -0
  68. package/dist/browser/PlaywrightExecutionBoundary.js +42 -0
  69. package/dist/browser/PlaywrightScenarioActions.js +62 -0
  70. package/dist/browser/PlaywrightScenarioArtifacts.js +238 -0
  71. package/dist/browser/PlaywrightScenarioBrowser.js +144 -0
  72. package/dist/browser/PlaywrightScenarioEvents.js +301 -0
  73. package/dist/browser/PlaywrightScenarioSession.js +300 -0
  74. package/dist/browser/V8InspectorCaptureProjection.js +110 -0
  75. package/dist/browser/V8InspectorEndpoint.js +72 -0
  76. package/dist/browser/V8InspectorProvider.js +267 -0
  77. package/dist/catalogIdentity.js +8 -0
  78. package/dist/cli/artifactCommands.js +39 -0
  79. package/dist/cli/coreAnalysisCommands.js +37 -0
  80. package/dist/cli.js +4 -0
  81. package/dist/cliApplicationCommands.js +30 -2
  82. package/dist/cliBrowserAdvancedCommands.js +17 -5
  83. package/dist/cliBrowserCommands.js +1 -0
  84. package/dist/cliBrowserScenarioCommands.js +43 -0
  85. package/dist/cliCommandNames.js +8 -0
  86. package/dist/cliJavaScriptRuntimeCommands.js +164 -0
  87. package/dist/cliObservationOptions.js +4 -0
  88. package/dist/cliPolicyCommands.js +1 -0
  89. package/dist/config/environment.js +12 -0
  90. package/dist/config/parseConfig.js +88 -17
  91. package/dist/contracts/analysisSearchContract.js +14 -0
  92. package/dist/contracts/applicationToolContracts.js +86 -2
  93. package/dist/contracts/applicationWorkflowInputContracts.js +18 -0
  94. package/dist/contracts/artifactToolContracts.js +22 -0
  95. package/dist/contracts/browserProviderToolContracts.js +7 -0
  96. package/dist/contracts/browserScenarioToolContracts.js +81 -0
  97. package/dist/contracts/browserToolContracts.js +88 -98
  98. package/dist/contracts/enhancedInputs.js +25 -6
  99. package/dist/contracts/functionInstructionContract.js +8 -0
  100. package/dist/contracts/hopperMemoryContracts.js +22 -0
  101. package/dist/contracts/javascriptApplicationWorkflowExamples.js +42 -0
  102. package/dist/contracts/javascriptRuntimeObservationToolContracts.js +58 -0
  103. package/dist/contracts/reconstructionReadinessExample.js +436 -0
  104. package/dist/contracts/toolContractExamples.js +5 -0
  105. package/dist/contracts/toolContractTypes.js +1 -0
  106. package/dist/contracts/toolContracts.js +13 -21
  107. package/dist/contracts/toolEffects.js +21 -0
  108. package/dist/contracts/toolOutputSchemaGroups.js +70 -20
  109. package/dist/contracts/toolOutputSchemaPrimitives.js +40 -0
  110. package/dist/domain/analysisErrorProjection.js +8 -0
  111. package/dist/domain/analysisSnapshot.js +2 -0
  112. package/dist/domain/artifactGraph.js +2 -0
  113. package/dist/domain/artifactInspection.js +347 -0
  114. package/dist/domain/binaryTarget.js +3 -6
  115. package/dist/domain/browserCaptureComparison.js +82 -0
  116. package/dist/domain/browserObservation.js +8 -1
  117. package/dist/domain/browserObservationErrors.js +1 -0
  118. package/dist/domain/browserObservationSchemas.js +26 -0
  119. package/dist/domain/browserScenario.js +165 -0
  120. package/dist/domain/browserScenarioCapture.js +57 -0
  121. package/dist/domain/browserScenarioCaptureValues.js +204 -0
  122. package/dist/domain/browserScenarioDiff.js +324 -0
  123. package/dist/domain/browserScenarioDiffValues.js +157 -0
  124. package/dist/domain/browserScenarioNormalization.js +45 -0
  125. package/dist/domain/browserScenarioValues.js +372 -0
  126. package/dist/domain/evidence.js +2 -0
  127. package/dist/domain/hopperValues.js +10 -0
  128. package/dist/domain/javascriptRuntimeObservation.js +170 -0
  129. package/dist/domain/javascriptRuntimeReconciliationParsing.js +120 -2
  130. package/dist/domain/javascriptRuntimeReconciliationResult.js +3 -3
  131. package/dist/domain/javascriptRuntimeReconciliationRuntime.js +2 -2
  132. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
  133. package/dist/domain/javascriptSemanticAnalysis.js +5 -4
  134. package/dist/domain/javascriptSemanticAsyncEffects.js +253 -0
  135. package/dist/domain/javascriptSemanticChildProcesses.js +237 -0
  136. package/dist/domain/javascriptSemanticDataEffectHelpers.js +125 -0
  137. package/dist/domain/javascriptSemanticDataEffects.js +284 -0
  138. package/dist/domain/javascriptSemanticDerivedAnalysis.js +41 -0
  139. package/dist/domain/javascriptSemanticFingerprints.js +174 -0
  140. package/dist/domain/javascriptSemanticIr.js +21 -1
  141. package/dist/domain/javascriptSemanticObjects.js +115 -0
  142. package/dist/domain/javascriptSemanticPromises.js +290 -0
  143. package/dist/domain/javascriptSemanticResources.js +136 -0
  144. package/dist/domain/javascriptStaticAnalysis.js +4 -3
  145. package/dist/domain/javascriptStaticAnalysisBundler.js +38 -0
  146. package/dist/domain/javascriptStaticAnalysisCalls.js +23 -1
  147. package/dist/domain/javascriptStaticAnalysisHelpers.js +8 -0
  148. package/dist/domain/processCapture.js +71 -1
  149. package/dist/domain/processCaptureReactiveValidation.js +175 -0
  150. package/dist/domain/processCaptureValidation.js +2 -0
  151. package/dist/domain/processObservation.js +15 -6
  152. package/dist/domain/processReactiveRuntime.js +21 -10
  153. package/dist/domain/processReactiveScenario.js +1 -0
  154. package/dist/domain/processReactiveTransition.js +17 -10
  155. package/dist/domain/processScenario.js +21 -0
  156. package/dist/domain/providerCleanupError.js +11 -0
  157. package/dist/domain/reconstructionObligationLedgerSchemas.js +278 -0
  158. package/dist/domain/reconstructionReadiness.js +121 -0
  159. package/dist/domain/reconstructionReadinessFindingHelpers.js +17 -0
  160. package/dist/domain/reconstructionReadinessIntegrityFindings.js +118 -0
  161. package/dist/domain/reconstructionReadinessJourneyFindings.js +193 -0
  162. package/dist/domain/reconstructionReadinessSchemas.js +240 -0
  163. package/dist/domain/sourceToBundleComparison.js +335 -0
  164. package/dist/domain/sourceToBundleComparisonSchemas.js +133 -0
  165. package/dist/domain/sourceToBundleSignals.js +202 -0
  166. package/dist/domain/webCaptureDiff.js +141 -27
  167. package/dist/domain/webScreenshot.js +1 -1
  168. package/dist/domain/zipPackageFormat.js +20 -0
  169. package/dist/generatedPackageMetadata.js +1 -1
  170. package/dist/ghidra/GhidraDefaults.js +1 -1
  171. package/dist/ghidra/GhidraFunctionValues.js +13 -1
  172. package/dist/ghidra/GhidraProviderCapabilities.js +7 -0
  173. package/dist/hopper/HopperCleanup.js +158 -0
  174. package/dist/hopper/HopperClient.js +69 -99
  175. package/dist/hopper/HopperProvider.js +20 -1
  176. package/dist/hopper/HopperRequestQueue.js +187 -0
  177. package/dist/hopper/HopperResponseStream.js +46 -0
  178. package/dist/hopper/protocol.js +1 -0
  179. package/dist/main/transport.js +24 -24
  180. package/dist/main.js +6 -0
  181. package/dist/mcpDoctor.js +25 -2
  182. package/dist/native/NativeMacOSProvider.js +1 -0
  183. package/dist/process/ProcessCommandIdentity.js +19 -0
  184. package/dist/process/ProcessOwnership.js +11 -8
  185. package/dist/server/DynamicToolAvailability.js +70 -0
  186. package/dist/server/createServer.js +46 -1
  187. package/dist/server/lifecycleProgress.js +10 -0
  188. package/dist/server/permissionFailure.js +12 -0
  189. package/dist/server/registerApplicationTools/compareSourceToBundle.js +35 -0
  190. package/dist/server/registerApplicationTools/helpers.js +11 -7
  191. package/dist/server/registerApplicationTools/obligationLedger.js +27 -0
  192. package/dist/server/registerApplicationTools/readiness.js +55 -0
  193. package/dist/server/registerApplicationTools.js +6 -0
  194. package/dist/server/registerArtifactTools.js +9 -1
  195. package/dist/server/registerBrowserScenarioTool.js +25 -0
  196. package/dist/server/registerBrowserTools.js +2 -2
  197. package/dist/server/registerCloseLifecycleTool.js +57 -0
  198. package/dist/server/registerEnhancedTools.js +16 -5
  199. package/dist/server/registerEvidenceResources.js +4 -0
  200. package/dist/server/registerEvidenceTools.js +9 -2
  201. package/dist/server/registerJavaScriptRuntimeObservationTools.js +37 -0
  202. package/dist/server/registerReconstructionObligationLedgerResource.js +39 -0
  203. package/dist/server/registerReconstructionReadinessResource.js +39 -0
  204. package/dist/server/registerSessionStatusTool.js +11 -8
  205. package/dist/server/registerSessionTools.js +11 -57
  206. package/dist/server/sessionAvailabilityPolicy.js +10 -8
  207. package/package.json +12 -6
  208. package/skills/reverse-engineer-anything/SKILL.md +4 -3
  209. package/skills/reverse-engineer-anything/references/native-and-artifacts.md +2 -2
@@ -0,0 +1,110 @@
1
+ import { createHash } from "node:crypto";
2
+ import { authorizeRuntimeLocation } from "./JavaScriptRuntimeScope.js";
3
+ /** Empty durable-location exclusion counters. */
4
+ export const createInspectorExclusionCounts = () => ({
5
+ outside_file_roots: 0,
6
+ outside_origins: 0,
7
+ unsupported_location: 0,
8
+ });
9
+ /** Stable safety and protocol limitations shared by target-list Evidence. */
10
+ export const describeInspectorTargetLimitations = () => [
11
+ "REA attaches to an already-running exact target and never launches, resumes, evaluates, pauses, or mutates it.",
12
+ "Only Runtime.enable and Debugger.enable are sent; source text, object values, EventEmitter activity, and Electron IPC are not inspected.",
13
+ "Target IDs and locations are authorized, but the Inspector protocol does not authenticate an operating-system process ID or Electron role.",
14
+ "No runtime graph depth is traversed because passive Inspector events do not establish require/import caller edges.",
15
+ ];
16
+ /** Canonically authorize, deduplicate, and sort one bounded raw capture. */
17
+ export const finalizeInspectorCapture = async ({ input, runtime, target, roots, state, }) => {
18
+ const exclusions = createInspectorExclusionCounts();
19
+ const scripts = new Map();
20
+ for (const draft of state.scripts) {
21
+ const decision = await authorizeRuntimeLocation(draft.rawUrl, roots, input.allowed_origins);
22
+ if (!decision.allowed) {
23
+ exclusions[decision.reason] += 1;
24
+ continue;
25
+ }
26
+ const script = scriptFromDraft(draft, decision.location);
27
+ scripts.set(script.script_key, script);
28
+ }
29
+ const items = [...scripts.values()].sort((left, right) => left.script_key < right.script_key
30
+ ? -1
31
+ : left.script_key > right.script_key
32
+ ? 1
33
+ : 0);
34
+ const contexts = [...state.contexts.values()]
35
+ .map((context) => ({
36
+ context_key: context.contextKey,
37
+ state: context.state,
38
+ name: null,
39
+ origin: context.origin,
40
+ }))
41
+ .sort((left, right) => left.context_key < right.context_key
42
+ ? -1
43
+ : left.context_key > right.context_key
44
+ ? 1
45
+ : 0);
46
+ return {
47
+ schema_version: 1,
48
+ runtime,
49
+ target: {
50
+ target_id: target.id,
51
+ protocol_type: target.type,
52
+ attached: target.attached,
53
+ location: target.location,
54
+ runtime_kind: input.runtime_kind,
55
+ runtime_kind_authority: "caller-declared-unverified",
56
+ },
57
+ capture: {
58
+ observation_ms: input.observation_ms,
59
+ events_observed: state.eventsObserved,
60
+ events_retained: state.eventsRetained,
61
+ events_dropped: state.eventsDropped,
62
+ metadata_bytes_retained: state.metadataBytes,
63
+ truncated: state.truncated,
64
+ truncation_reasons: [...state.truncationReasons].sort(),
65
+ },
66
+ scripts: {
67
+ items,
68
+ observed_total: state.scriptsObserved,
69
+ excluded: {
70
+ ...exclusions,
71
+ invalid_protocol_value: state.invalidScripts,
72
+ },
73
+ },
74
+ execution_contexts: contexts,
75
+ directly_observed: [
76
+ "Debugger.scriptParsed established script presence within the bounded capture window.",
77
+ "Runtime execution-context lifecycle events established context creation, destruction, or clearing.",
78
+ ],
79
+ unavailable_without_instrumentation: [
80
+ "require/import caller-to-callee edges",
81
+ "EventEmitter emissions and listener invocation",
82
+ "Electron IPC messages and handlers",
83
+ "script unload events",
84
+ ],
85
+ unknowns: [
86
+ "Scripts collected before attachment may have been garbage-collected and therefore omitted.",
87
+ "A bounded observation window cannot establish that an unobserved script or behavior never occurs.",
88
+ "The declared Node/Electron process role is not authenticated by the Inspector protocol.",
89
+ ],
90
+ limitations: describeInspectorTargetLimitations(),
91
+ };
92
+ };
93
+ const scriptFromDraft = (draft, location) => {
94
+ const stable = JSON.stringify({
95
+ location,
96
+ execution_context_key: draft.executionContextKey,
97
+ cdp_hash: draft.cdpHash,
98
+ length: draft.length,
99
+ is_module: draft.isModule,
100
+ });
101
+ return {
102
+ script_key: `v8_script_${createHash("sha256").update(stable).digest("hex")}`,
103
+ location,
104
+ execution_context_key: draft.executionContextKey,
105
+ cdp_hash: draft.cdpHash,
106
+ length: draft.length,
107
+ is_module: draft.isModule,
108
+ status: "observed-loaded",
109
+ };
110
+ };
@@ -0,0 +1,72 @@
1
+ import { z } from "zod";
2
+ import { BrowserObservationError, } from "../domain/errors.js";
3
+ import { parseCdpEndpointValue, readBoundedCdpJson } from "./CdpEndpoint.js";
4
+ const MAX_VERSION_BYTES = 64 * 1_024;
5
+ const MAX_TARGET_LIST_BYTES = 2 * 1_024 * 1_024;
6
+ const versionSchema = z
7
+ .object({
8
+ Browser: z.string().min(1).max(1_024),
9
+ "Protocol-Version": z.string().min(1).max(100),
10
+ "V8-Version": z.string().max(1_024).optional(),
11
+ })
12
+ .passthrough();
13
+ const targetSchema = z
14
+ .object({
15
+ id: z.string().min(1).max(256),
16
+ type: z.string().min(1).max(100),
17
+ url: z.string().max(65_536),
18
+ attached: z.boolean().default(false),
19
+ webSocketDebuggerUrl: z.string().min(1).max(2_048),
20
+ })
21
+ .passthrough();
22
+ const targetsSchema = z.array(targetSchema).max(1_000);
23
+ /** Discover bounded Node/Electron Inspector targets from one loopback endpoint. */
24
+ export const discoverV8Inspector = async (endpoint, operation, signal) => {
25
+ const [versionInput, targetsInput] = await Promise.all([
26
+ readBoundedCdpJson(new URL("/json/version", endpoint), MAX_VERSION_BYTES, operation, signal),
27
+ readBoundedCdpJson(new URL("/json/list", endpoint), MAX_TARGET_LIST_BYTES, operation, signal),
28
+ ]);
29
+ const version = parseCdpEndpointValue(versionSchema, versionInput, operation);
30
+ const targets = parseCdpEndpointValue(targetsSchema, targetsInput, operation);
31
+ return {
32
+ runtime: {
33
+ product: version.Browser,
34
+ protocol_version: version["Protocol-Version"],
35
+ v8_version: version["V8-Version"] ?? null,
36
+ },
37
+ targets: targets.map((target) => ({
38
+ id: target.id,
39
+ type: target.type,
40
+ url: target.url,
41
+ attached: target.attached,
42
+ webSocketUrl: validatedInspectorWebSocket(endpoint, target.id, target.webSocketDebuggerUrl, operation),
43
+ })),
44
+ };
45
+ };
46
+ const validatedInspectorWebSocket = (endpoint, targetId, reported, operation) => {
47
+ let socket;
48
+ try {
49
+ socket = new URL(reported);
50
+ }
51
+ catch (cause) {
52
+ throw new BrowserObservationError(operation, "invalid_endpoint_response", {
53
+ cause,
54
+ });
55
+ }
56
+ const trusted = new URL(endpoint);
57
+ const allowedPaths = new Set([
58
+ `/${targetId}`,
59
+ `/devtools/node/${targetId}`,
60
+ `/devtools/page/${targetId}`,
61
+ ]);
62
+ if (socket.protocol !== "ws:" ||
63
+ socket.port !== trusted.port ||
64
+ socket.username !== "" ||
65
+ socket.password !== "" ||
66
+ socket.search !== "" ||
67
+ socket.hash !== "" ||
68
+ !allowedPaths.has(socket.pathname))
69
+ throw new BrowserObservationError(operation, "invalid_endpoint_response");
70
+ socket.hostname = trusted.hostname;
71
+ return socket.href;
72
+ };
@@ -0,0 +1,267 @@
1
+ import { javascriptRuntimeObservationSchema, javascriptRuntimeTargetListSchema, } from "../domain/javascriptRuntimeObservation.js";
2
+ import { AnalysisError, BrowserObservationError, ProviderAdapterError, } from "../domain/errors.js";
3
+ import { err, ok } from "../domain/result.js";
4
+ import { boundedText, numberValue, recordValue, stringValue, delayWithCancellation, } from "./CdpCaptureValues.js";
5
+ import { CdpConnection } from "./CdpConnection.js";
6
+ import { authorizeRuntimeLocation, canonicalRuntimeRoots, } from "./JavaScriptRuntimeScope.js";
7
+ import { createInspectorExclusionCounts, describeInspectorTargetLimitations, finalizeInspectorCapture, } from "./V8InspectorCaptureProjection.js";
8
+ import { discoverV8Inspector, } from "./V8InspectorEndpoint.js";
9
+ /** Public identity committed by passive V8 Inspector observations. */
10
+ export const V8_INSPECTOR_PROVIDER_IDENTITY = Object.freeze({
11
+ id: "rea-v8-inspector",
12
+ name: "REA passive Node/Electron V8 Inspector provider",
13
+ version: "1",
14
+ });
15
+ /** Attach-only provider; sends only Runtime.enable and Debugger.enable. */
16
+ export class V8InspectorProvider {
17
+ identity() {
18
+ return V8_INSPECTOR_PROVIDER_IDENTITY;
19
+ }
20
+ async listTargets(input, options = {}) {
21
+ try {
22
+ const roots = await canonicalRuntimeRoots(input.allowed_file_roots);
23
+ const discovery = await discoverV8Inspector(input.inspector_endpoint, "list_javascript_runtime_targets", options.signal);
24
+ const allowed = [];
25
+ const excluded = createInspectorExclusionCounts();
26
+ for (const target of discovery.targets) {
27
+ const decision = await authorizeRuntimeLocation(target.url, roots, input.allowed_origins);
28
+ if (!decision.allowed) {
29
+ excluded[decision.reason] += 1;
30
+ continue;
31
+ }
32
+ if (decision.location.kind === "builtin") {
33
+ excluded.unsupported_location += 1;
34
+ continue;
35
+ }
36
+ allowed.push({ ...target, location: decision.location });
37
+ }
38
+ allowed.sort((left, right) => left.id < right.id ? -1 : left.id > right.id ? 1 : 0);
39
+ const items = allowed
40
+ .slice(input.offset, input.offset + input.limit)
41
+ .map(projectTarget);
42
+ const nextOffset = input.offset + items.length;
43
+ return ok(javascriptRuntimeTargetListSchema.parse({
44
+ schema_version: 1,
45
+ runtime: discovery.runtime,
46
+ targets: {
47
+ items,
48
+ offset: input.offset,
49
+ limit: input.limit,
50
+ total: allowed.length,
51
+ next_offset: nextOffset < allowed.length ? nextOffset : null,
52
+ has_more: nextOffset < allowed.length,
53
+ },
54
+ excluded: { ...excluded, unconnectable: 0 },
55
+ limitations: describeInspectorTargetLimitations(),
56
+ }));
57
+ }
58
+ catch (cause) {
59
+ return err(providerError(cause, "list_javascript_runtime_targets"));
60
+ }
61
+ }
62
+ async observe(input, options = {}) {
63
+ let connection;
64
+ try {
65
+ const roots = await canonicalRuntimeRoots(input.allowed_file_roots);
66
+ const discovery = await discoverV8Inspector(input.inspector_endpoint, "observe_javascript_runtime", options.signal);
67
+ const target = await authorizedTarget(discovery.targets, input, roots);
68
+ assertRuntimeKind(target, input.runtime_kind);
69
+ connection = await CdpConnection.connect(target.webSocketUrl, "observe_javascript_runtime", options.signal);
70
+ const state = emptyCaptureState();
71
+ const removeListener = connection.onEvent((event) => ingestEvent(event, input, state));
72
+ try {
73
+ await connection.send("Runtime.enable", {}, undefined, options.signal);
74
+ await connection.send("Debugger.enable", {}, undefined, options.signal);
75
+ await waitForCapture(connection, input.observation_ms, options.signal);
76
+ }
77
+ finally {
78
+ removeListener();
79
+ }
80
+ const result = await finalizeInspectorCapture({
81
+ input,
82
+ runtime: discovery.runtime,
83
+ target,
84
+ roots,
85
+ state,
86
+ });
87
+ return ok(javascriptRuntimeObservationSchema.parse(result));
88
+ }
89
+ catch (cause) {
90
+ return err(providerError(cause, "observe_javascript_runtime"));
91
+ }
92
+ finally {
93
+ await connection?.close();
94
+ }
95
+ }
96
+ }
97
+ const projectTarget = (target) => ({
98
+ target_id: target.id,
99
+ protocol_type: target.type,
100
+ attached: target.attached,
101
+ location: target.location,
102
+ });
103
+ const authorizedTarget = async (targets, input, roots) => {
104
+ const target = targets.find(({ id }) => id === input.target_id);
105
+ if (target === undefined)
106
+ throw new BrowserObservationError("observe_javascript_runtime", "target_not_found");
107
+ const decision = await authorizeRuntimeLocation(target.url, roots, input.allowed_origins);
108
+ if (target.attached ||
109
+ !decision.allowed ||
110
+ decision.location.kind === "builtin")
111
+ throw new BrowserObservationError("observe_javascript_runtime", "target_not_allowed");
112
+ return { ...target, location: decision.location };
113
+ };
114
+ const assertRuntimeKind = (target, kind) => {
115
+ const accepted = kind === "electron-preload" || kind === "electron-renderer"
116
+ ? target.type === "page"
117
+ : target.type === "node";
118
+ if (!accepted)
119
+ throw new BrowserObservationError("observe_javascript_runtime", "target_not_allowed");
120
+ };
121
+ const emptyCaptureState = () => ({
122
+ scripts: [],
123
+ contexts: new Map(),
124
+ eventsObserved: 0,
125
+ eventsRetained: 0,
126
+ eventsDropped: 0,
127
+ metadataBytes: 0,
128
+ scriptsObserved: 0,
129
+ invalidScripts: 0,
130
+ truncated: false,
131
+ truncationReasons: new Set(),
132
+ });
133
+ const ingestEvent = (event, input, state) => {
134
+ if (event.method !== "Debugger.scriptParsed" &&
135
+ event.method !== "Debugger.scriptFailedToParse" &&
136
+ event.method !== "Runtime.executionContextCreated" &&
137
+ event.method !== "Runtime.executionContextDestroyed" &&
138
+ event.method !== "Runtime.executionContextsCleared")
139
+ return;
140
+ state.eventsObserved += 1;
141
+ if (state.eventsObserved > input.limits.max_events) {
142
+ drop(state, "max_events");
143
+ return;
144
+ }
145
+ if (event.method === "Debugger.scriptParsed") {
146
+ ingestScript(event, input, state);
147
+ return;
148
+ }
149
+ if (event.method === "Debugger.scriptFailedToParse") {
150
+ state.invalidScripts += 1;
151
+ retainEvent(state, 0, input);
152
+ return;
153
+ }
154
+ ingestContext(event, input, state);
155
+ };
156
+ const ingestScript = (event, input, state) => {
157
+ state.scriptsObserved += 1;
158
+ const value = recordValue(event.params);
159
+ const rawUrl = stringValue(value?.url);
160
+ if (rawUrl === undefined ||
161
+ rawUrl === "" ||
162
+ Buffer.byteLength(rawUrl) > input.limits.max_location_bytes) {
163
+ state.invalidScripts += 1;
164
+ retainEvent(state, 0, input);
165
+ return;
166
+ }
167
+ if (state.scripts.length >= input.limits.max_scripts) {
168
+ drop(state, "max_scripts");
169
+ return;
170
+ }
171
+ const draft = {
172
+ rawUrl,
173
+ executionContextKey: contextKey(value?.executionContextId),
174
+ cdpHash: boundedText(value?.hash, 512),
175
+ length: nonnegativeInteger(value?.length),
176
+ isModule: value?.isModule === true,
177
+ };
178
+ const bytes = metadataBytes(draft);
179
+ if (!retainEvent(state, bytes, input))
180
+ return;
181
+ state.scripts.push(draft);
182
+ };
183
+ const ingestContext = (event, input, state) => {
184
+ if (event.method === "Runtime.executionContextsCleared") {
185
+ for (const context of state.contexts.values())
186
+ context.state = "cleared";
187
+ retainEvent(state, 0, input);
188
+ return;
189
+ }
190
+ const parameters = recordValue(event.params);
191
+ const runtimeContext = event.method === "Runtime.executionContextCreated"
192
+ ? recordValue(parameters?.context)
193
+ : parameters;
194
+ const key = contextKey(event.method === "Runtime.executionContextCreated"
195
+ ? runtimeContext?.id
196
+ : runtimeContext?.executionContextId);
197
+ if (key === null) {
198
+ retainEvent(state, 0, input);
199
+ return;
200
+ }
201
+ if (state.contexts.size >= input.limits.max_execution_contexts &&
202
+ !state.contexts.has(key)) {
203
+ drop(state, "max_execution_contexts");
204
+ return;
205
+ }
206
+ const origin = event.method === "Runtime.executionContextCreated"
207
+ ? boundedText(runtimeContext?.origin, 4_096)
208
+ : null;
209
+ const draft = {
210
+ contextKey: key,
211
+ state: event.method === "Runtime.executionContextCreated"
212
+ ? "created"
213
+ : "destroyed",
214
+ origin: origin !== null && input.allowed_origins.includes(origin) ? origin : null,
215
+ };
216
+ const bytes = metadataBytes(draft);
217
+ if (!retainEvent(state, bytes, input))
218
+ return;
219
+ state.contexts.set(key, draft);
220
+ };
221
+ const retainEvent = (state, bytes, input) => {
222
+ if (state.metadataBytes + bytes > input.limits.max_total_metadata_bytes) {
223
+ drop(state, "max_total_metadata_bytes");
224
+ return false;
225
+ }
226
+ state.metadataBytes += bytes;
227
+ state.eventsRetained += 1;
228
+ return true;
229
+ };
230
+ const drop = (state, reason) => {
231
+ state.eventsDropped += 1;
232
+ state.truncated = true;
233
+ state.truncationReasons.add(reason);
234
+ };
235
+ const waitForCapture = async (connection, observationMs, signal) => {
236
+ let removeDisconnect = () => undefined;
237
+ const disconnected = new Promise((_resolve, reject) => {
238
+ removeDisconnect = connection.onDisconnect(() => reject(new BrowserObservationError("observe_javascript_runtime", "disconnected")));
239
+ });
240
+ try {
241
+ await Promise.race([
242
+ delayWithCancellation(observationMs, "observe_javascript_runtime", signal),
243
+ disconnected,
244
+ ]);
245
+ }
246
+ finally {
247
+ removeDisconnect();
248
+ }
249
+ };
250
+ const metadataBytes = (value) => Buffer.byteLength(JSON.stringify(value));
251
+ const nonnegativeInteger = (value) => {
252
+ const parsed = numberValue(value);
253
+ return parsed === undefined ? 0 : Math.max(0, Math.trunc(parsed));
254
+ };
255
+ const contextKey = (value) => {
256
+ const identifier = numberValue(value);
257
+ return identifier !== undefined && Number.isSafeInteger(identifier)
258
+ ? String(identifier)
259
+ : null;
260
+ };
261
+ const providerError = (cause, operation) => {
262
+ if (cause instanceof AnalysisError)
263
+ return cause;
264
+ return new ProviderAdapterError(V8_INSPECTOR_PROVIDER_IDENTITY.id, operation, {
265
+ cause,
266
+ });
267
+ };
@@ -59,6 +59,14 @@ export const MCP_RESOURCE_TEMPLATE_CATALOG = [
59
59
  name: "reconstruction-coverage-revision",
60
60
  uri_template: "rea://reconstruction-coverage/{workspaceId}/revision/{revision}",
61
61
  },
62
+ {
63
+ name: "reconstruction-obligation-ledger-page",
64
+ uri_template: "rea://evidence/{evidenceId}/reconstruction-obligation-ledger",
65
+ },
66
+ {
67
+ name: "reconstruction-readiness-report",
68
+ uri_template: "rea://evidence/{evidenceId}/reconstruction-readiness-report",
69
+ },
62
70
  {
63
71
  name: "javascript-application-graph-page",
64
72
  uri_template: "rea://evidence/{evidenceId}/application-graph/{collection}/offset/{offset}/limit/{limit}",
@@ -3,6 +3,11 @@ import { runProviderAnalysis } from "../application/DirectAnalysis.js";
3
3
  import { logCliCommand } from "../cliLogging.js";
4
4
  import { CLI_COMMANDS } from "../cliCommandNames.js";
5
5
  export const registerArtifactCommands = (cli, logger) => {
6
+ registerInventoryCommand(cli, logger);
7
+ registerInspectionCommand(cli, logger);
8
+ registerExtractionCommand(cli, logger);
9
+ };
10
+ const registerInventoryCommand = (cli, logger) => {
6
11
  cli.command(CLI_COMMANDS.inventoryArtifact, {
7
12
  description: "Build a bounded deterministic artifact graph",
8
13
  args: z.object({
@@ -61,6 +66,8 @@ export const registerArtifactCommands = (cli, logger) => {
61
66
  native_mount_approved: options.nativeMountApproved,
62
67
  }, logger)),
63
68
  });
69
+ };
70
+ const registerExtractionCommand = (cli, logger) => {
64
71
  cli.command(CLI_COMMANDS.extractArtifact, {
65
72
  description: "Extract explicitly selected artifact occurrences safely",
66
73
  args: z.object({
@@ -80,3 +87,35 @@ export const registerArtifactCommands = (cli, logger) => {
80
87
  }, logger)),
81
88
  });
82
89
  };
90
+ const registerInspectionCommand = (cli, logger) => {
91
+ cli.command(CLI_COMMANDS.inspectArtifact, {
92
+ description: "Inspect one artifact with bounded observations and explicit next probes",
93
+ args: z.object({
94
+ path: z.string().describe("Application or package path"),
95
+ }),
96
+ options: z.object({
97
+ maxObservations: z
98
+ .number()
99
+ .int()
100
+ .min(1)
101
+ .max(500)
102
+ .default(100)
103
+ .describe("Maximum retained observations"),
104
+ maxRelationships: z
105
+ .number()
106
+ .int()
107
+ .min(1)
108
+ .max(500)
109
+ .default(100)
110
+ .describe("Maximum retained derived relationships"),
111
+ }),
112
+ alias: {
113
+ maxObservations: "max-observations",
114
+ maxRelationships: "max-relationships",
115
+ },
116
+ run: ({ args, options }) => logCliCommand(logger, "inspect-artifact", () => runProviderAnalysis(args.path, "inspect_artifact", {
117
+ max_observations: options.maxObservations,
118
+ max_relationships: options.maxRelationships,
119
+ }, logger)),
120
+ });
121
+ };
@@ -9,6 +9,7 @@ import { runCliJavaScriptApplicationAnalysis } from "./javascriptApplicationAnal
9
9
  export const registerCoreAnalysisCommands = (cli, logger) => {
10
10
  registerCoreCommands(cli, logger);
11
11
  registerFunctionCommand(cli, logger);
12
+ registerInstructionsCommand(cli, logger);
12
13
  registerSearchCommand(cli, logger);
13
14
  registerXrefsCommand(cli, logger);
14
15
  registerTraceCommand(cli, logger);
@@ -212,6 +213,42 @@ const registerFunctionCommand = (cli, logger) => {
212
213
  }, directAnalysisOptions(logger, options.snapshot, options.provider))),
213
214
  });
214
215
  };
216
+ const registerInstructionsCommand = (cli, logger) => {
217
+ cli.command(CLI_COMMANDS.instructions, {
218
+ description: "Read one bounded raw-instruction window without decompiling",
219
+ args: z.object({
220
+ path: z.string().describe("App or program path"),
221
+ address: z.string().describe("Procedure name or address"),
222
+ }),
223
+ options: z.object({
224
+ offset: z
225
+ .number()
226
+ .int()
227
+ .min(0)
228
+ .max(100_000)
229
+ .default(0)
230
+ .describe("Zero-based instruction offset"),
231
+ limit: z
232
+ .number()
233
+ .int()
234
+ .min(1)
235
+ .max(500)
236
+ .default(64)
237
+ .describe("Maximum raw instructions to return"),
238
+ snapshot: z
239
+ .string()
240
+ .min(1)
241
+ .optional()
242
+ .describe("Load and update a local analysis snapshot"),
243
+ provider: providerSelectionOption,
244
+ }),
245
+ run: ({ args, options }) => logCliCommand(logger, CLI_COMMANDS.instructions, () => runDirectAnalysis(args.path, "read_function_instructions", {
246
+ procedure: args.address,
247
+ offset: options.offset,
248
+ limit: options.limit,
249
+ }, directAnalysisOptions(logger, options.snapshot, options.provider))),
250
+ });
251
+ };
215
252
  const registerSearchCommand = (cli, logger) => {
216
253
  cli.command(CLI_COMMANDS.search, {
217
254
  description: "Search bounded analyzed strings or procedure names",
package/dist/cli.js CHANGED
@@ -13,7 +13,9 @@ import { registerProcessCommands } from "./cliProcessCommands.js";
13
13
  import { registerPolicyCommands } from "./cliPolicyCommands.js";
14
14
  import { registerBrowserCommands } from "./cliBrowserCommands.js";
15
15
  import { registerAdvancedBrowserCommands } from "./cliBrowserAdvancedCommands.js";
16
+ import { registerBrowserScenarioCommands } from "./cliBrowserScenarioCommands.js";
16
17
  import { registerElectronCommands } from "./cliElectronCommands.js";
18
+ import { registerJavaScriptRuntimeObservationCommands } from "./cliJavaScriptRuntimeCommands.js";
17
19
  import { registerApplicationCommands } from "./cliApplicationCommands.js";
18
20
  /**
19
21
  * Build the one-shot Incur CLI without starting Hopper at import time.
@@ -52,7 +54,9 @@ export const createCli = () => {
52
54
  registerPolicyCommands(cli, logger);
53
55
  registerBrowserCommands(cli, logger);
54
56
  registerAdvancedBrowserCommands(cli, logger);
57
+ registerBrowserScenarioCommands(cli, logger);
55
58
  registerElectronCommands(cli, logger);
59
+ registerJavaScriptRuntimeObservationCommands(cli, logger);
56
60
  registerApplicationCommands(cli, logger);
57
61
  return cli;
58
62
  };
@@ -1,11 +1,13 @@
1
1
  import { Cli, z } from "incur";
2
- import { compareApplicationVersionsEvidenceValidated, compareJavaScriptExportShapesEvidenceValidated, traceApplicationFeatureEvidenceValidated, } from "./application/JavaScriptApplicationWorkflowService.js";
2
+ import { compareApplicationVersionsEvidenceValidated, compareJavaScriptExportShapesEvidenceValidated, compareSourceToBundleEvidenceValidated, traceApplicationFeatureEvidenceValidated, } from "./application/JavaScriptApplicationWorkflowService.js";
3
3
  import { traceJavaScriptSemanticsEvidenceValidated } from "./application/JavaScriptSemanticTraceService.js";
4
- import { resolveCompareApplicationVersionsRequest, resolveCompareJavaScriptExportShapesRequest, resolveTraceApplicationFeatureRequest, resolveTraceJavaScriptSemanticsRequest, } from "./application/ApplicationWorkflowEvidenceResolver.js";
4
+ import { resolveCompareApplicationVersionsRequest, resolveCompareJavaScriptExportShapesRequest, resolveCompareSourceToBundleRequest, resolveTraceApplicationFeatureRequest, resolveTraceJavaScriptSemanticsRequest, } from "./application/ApplicationWorkflowEvidenceResolver.js";
5
5
  import { readEvidenceBundle } from "./application/EvidenceBundleFiles.js";
6
6
  import { runControlledReplay } from "./application/JavaScriptReplayService.js";
7
7
  import { executeNodeCharacterization, prepareNodeCharacterization, } from "./application/NodeRuntimeCharacterizationService.js";
8
8
  import { commitReconstructionCoverage, queryReconstructionCoverage, reconstructionCoverageCommitInputSchema, reconstructionCoverageQueryInputSchema, } from "./application/ReconstructionCoverageService.js";
9
+ import { buildReconstructionObligationLedgerEvidenceValidated, resolveReconstructionObligationLedgerRequest, } from "./application/ReconstructionObligationLedgerService.js";
10
+ import { evaluateReconstructionReadinessValidated, resolveReconstructionReadinessRequest, } from "./application/ReconstructionReadinessService.js";
9
11
  import { authorizeFileReadWithDeferredWrite, authorizeRootPermission, } from "./application/DeferredFileAuthorization.js";
10
12
  import { loadConfiguredPermissionAuthority } from "./application/PermissionConfiguration.js";
11
13
  import { CLI_COMMANDS } from "./cliCommandNames.js";
@@ -41,6 +43,14 @@ export const registerApplicationCommands = (cli, logger) => {
41
43
  resolveInput: resolveCompareApplicationVersionsRequest,
42
44
  workflow: compareApplicationVersionsEvidenceValidated,
43
45
  });
46
+ registerJsonCommand({
47
+ cli,
48
+ logger,
49
+ name: CLI_COMMANDS.compareSourceToBundle,
50
+ description: "Compare committed historical source with authenticated application Evidence",
51
+ resolveInput: resolveCompareSourceToBundleRequest,
52
+ workflow: compareSourceToBundleEvidenceValidated,
53
+ });
44
54
  registerJsonCommand({
45
55
  cli,
46
56
  logger,
@@ -87,8 +97,26 @@ export const registerApplicationCommands = (cli, logger) => {
87
97
  description: "Execute one separately approved exact Node/JavaScript characterization",
88
98
  workflow: (config, authority, input) => executeNodeCharacterization(replayDependencies(config, authority), input),
89
99
  });
100
+ registerObligationLedgerCommand(cli, logger);
101
+ registerReadinessCommand(cli, logger);
90
102
  registerCoverageCommands(cli, logger);
91
103
  };
104
+ const registerObligationLedgerCommand = (cli, logger) => registerJsonCommand({
105
+ cli,
106
+ logger,
107
+ name: CLI_COMMANDS.buildReconstructionObligationLedger,
108
+ description: "Generate a deterministic Evidence-backed reconstruction obligation ledger page",
109
+ resolveInput: resolveReconstructionObligationLedgerRequest,
110
+ workflow: buildReconstructionObligationLedgerEvidenceValidated,
111
+ });
112
+ const registerReadinessCommand = (cli, logger) => registerJsonCommand({
113
+ cli,
114
+ logger,
115
+ name: CLI_COMMANDS.evaluateReconstructionReadiness,
116
+ description: "Evaluate a complete Evidence-backed reconstruction readiness journey",
117
+ resolveInput: resolveReconstructionReadinessRequest,
118
+ workflow: evaluateReconstructionReadinessValidated,
119
+ });
92
120
  const registerAuthorizedJsonCommand = ({ cli, logger, name, description, workflow, }) => {
93
121
  cli.command(name, {
94
122
  description,