rea-agents 2.4.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.
Files changed (231) hide show
  1. package/README.md +91 -19
  2. package/bridge/ghidra/ReaGhidraBridge.java +524 -4
  3. package/bridge/hopper_bridge.py +313 -28
  4. package/dist/application/AnalysisClientCleanup.js +14 -0
  5. package/dist/application/AnalysisContextQueries.js +130 -0
  6. package/dist/application/AnalysisSnapshotCache.js +4 -2
  7. package/dist/application/ApplicationWorkflowEvidenceResolver.js +31 -13
  8. package/dist/application/ArtifactInventory/scanCanonical.js +1 -1
  9. package/dist/application/BinarySession.js +20 -8
  10. package/dist/application/BinarySessionComposition.js +21 -0
  11. package/dist/application/BinarySessionRecords.js +79 -9
  12. package/dist/application/BinarySessionStatus.js +31 -1
  13. package/dist/application/BrowserEvidence.js +14 -0
  14. package/dist/application/BrowserScenarioCapturePort.js +1 -0
  15. package/dist/application/BrowserScenarioCaptureService.js +53 -0
  16. package/dist/application/BrowserScenarioEvidence.js +40 -0
  17. package/dist/application/CallPathTracing.js +160 -0
  18. package/dist/application/CapabilityInventory.js +84 -14
  19. package/dist/application/ClientRegistrationStatus.js +4 -1
  20. package/dist/application/CompositeProvider.js +10 -1
  21. package/dist/application/DirectAnalysis.js +13 -4
  22. package/dist/application/EnhancedLiteralTracing.js +118 -0
  23. package/dist/application/EnhancedTools.js +71 -127
  24. package/dist/application/EvidenceLedger.js +45 -16
  25. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +13 -0
  26. package/dist/application/JavaScriptApplicationWorkflowService.js +27 -1
  27. package/dist/application/JavaScriptArtifactAnalysis.js +13 -4
  28. package/dist/application/JavaScriptRuntimeObservationEvidence.js +34 -0
  29. package/dist/application/JavaScriptRuntimeObservationPort.js +1 -0
  30. package/dist/application/JavaScriptRuntimeObservationService.js +46 -0
  31. package/dist/application/JavaScriptSemanticGraphAsyncProjection.js +147 -0
  32. package/dist/application/JavaScriptSemanticGraphBuilder.js +34 -6
  33. package/dist/application/JavaScriptSemanticGraphChildProcessProjection.js +156 -0
  34. package/dist/application/JavaScriptSemanticGraphConstruction.js +2 -2
  35. package/dist/application/JavaScriptSemanticGraphDataProjection.js +203 -0
  36. package/dist/application/JavaScriptSemanticGraphFingerprintProjection.js +25 -0
  37. package/dist/application/JavaScriptSemanticGraphFlowProjection.js +129 -8
  38. package/dist/application/JavaScriptSemanticGraphObjectProjection.js +81 -0
  39. package/dist/application/JavaScriptSemanticGraphProjection.js +14 -7
  40. package/dist/application/JavaScriptSemanticGraphResourceProjection.js +59 -0
  41. package/dist/application/JavaScriptSemanticGraphValueProjection.js +77 -0
  42. package/dist/application/LazyAnalysisProvider.js +77 -0
  43. package/dist/application/LoopbackReplay.js +1 -1
  44. package/dist/application/NativeApiInspection.js +80 -0
  45. package/dist/application/ProcessReactiveEffects.js +6 -0
  46. package/dist/application/ProcessReactiveHarness.js +16 -1
  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/application/SessionProviderRouter.js +6 -6
  58. package/dist/application/SetupClientConfiguration.js +4 -2
  59. package/dist/application/runtime.js +26 -9
  60. package/dist/artifacts/ArtifactProvider.js +87 -22
  61. package/dist/browser/BrowserScenarioSecrets.js +53 -0
  62. package/dist/browser/BrowserScenarioSessionPort.js +1 -0
  63. package/dist/browser/CdpBrowserProvider.js +2 -2
  64. package/dist/browser/CdpCaptureDocuments.js +57 -0
  65. package/dist/browser/CdpCaptureStorage.js +71 -29
  66. package/dist/browser/CdpCaptureStorageFingerprints.js +328 -0
  67. package/dist/browser/CdpEndpoint.js +8 -6
  68. package/dist/browser/CdpPageCapture.js +2 -0
  69. package/dist/browser/JavaScriptRuntimeScope.js +38 -0
  70. package/dist/browser/PlaywrightBrowserScenarioProvider.js +259 -0
  71. package/dist/browser/PlaywrightExecutionBoundary.js +42 -0
  72. package/dist/browser/PlaywrightScenarioActions.js +62 -0
  73. package/dist/browser/PlaywrightScenarioArtifacts.js +238 -0
  74. package/dist/browser/PlaywrightScenarioBrowser.js +144 -0
  75. package/dist/browser/PlaywrightScenarioEvents.js +301 -0
  76. package/dist/browser/PlaywrightScenarioSession.js +300 -0
  77. package/dist/browser/V8InspectorCaptureProjection.js +110 -0
  78. package/dist/browser/V8InspectorEndpoint.js +72 -0
  79. package/dist/browser/V8InspectorProvider.js +267 -0
  80. package/dist/catalogIdentity.js +11 -3
  81. package/dist/cli/artifactCommands.js +44 -3
  82. package/dist/cli/coreAnalysisCommands.js +78 -0
  83. package/dist/cli.js +4 -0
  84. package/dist/cliApplicationCommands.js +30 -2
  85. package/dist/cliBrowserAdvancedCommands.js +17 -5
  86. package/dist/cliBrowserCommands.js +1 -0
  87. package/dist/cliBrowserScenarioCommands.js +43 -0
  88. package/dist/cliCommandNames.js +9 -0
  89. package/dist/cliJavaScriptRuntimeCommands.js +164 -0
  90. package/dist/cliObservationOptions.js +4 -0
  91. package/dist/cliPolicyCommands.js +1 -0
  92. package/dist/config/environment.js +12 -0
  93. package/dist/config/parseConfig.js +88 -17
  94. package/dist/contracts/analysisSearchContract.js +14 -0
  95. package/dist/contracts/applicationToolContracts.js +86 -2
  96. package/dist/contracts/applicationWorkflowInputContracts.js +18 -0
  97. package/dist/contracts/artifactToolContracts.js +29 -2
  98. package/dist/contracts/browserProviderToolContracts.js +7 -0
  99. package/dist/contracts/browserScenarioToolContracts.js +81 -0
  100. package/dist/contracts/browserToolContracts.js +88 -98
  101. package/dist/contracts/enhancedInputs.js +35 -6
  102. package/dist/contracts/functionInstructionContract.js +8 -0
  103. package/dist/contracts/functionWorkflowToolContracts.js +30 -0
  104. package/dist/contracts/hopperMemoryContracts.js +22 -0
  105. package/dist/contracts/javascriptApplicationWorkflowExamples.js +42 -0
  106. package/dist/contracts/javascriptRuntimeObservationToolContracts.js +58 -0
  107. package/dist/contracts/promptContracts.js +14 -15
  108. package/dist/contracts/reconstructionReadinessExample.js +436 -0
  109. package/dist/contracts/toolContractExamples.js +8 -0
  110. package/dist/contracts/toolContractTypes.js +1 -0
  111. package/dist/contracts/toolContracts.js +34 -25
  112. package/dist/contracts/toolEffects.js +25 -0
  113. package/dist/contracts/toolOutputSchemaGroups.js +120 -30
  114. package/dist/contracts/toolOutputSchemaPrimitives.js +37 -0
  115. package/dist/domain/analysisErrorPresentation.js +8 -2
  116. package/dist/domain/analysisErrorProjection.js +9 -0
  117. package/dist/domain/artifactInspection.js +347 -0
  118. package/dist/domain/browserCaptureComparison.js +82 -0
  119. package/dist/domain/browserObservation.js +8 -1
  120. package/dist/domain/browserObservationErrors.js +1 -0
  121. package/dist/domain/browserObservationSchemas.js +26 -0
  122. package/dist/domain/browserScenario.js +165 -0
  123. package/dist/domain/browserScenarioCapture.js +57 -0
  124. package/dist/domain/browserScenarioCaptureValues.js +204 -0
  125. package/dist/domain/browserScenarioDiff.js +324 -0
  126. package/dist/domain/browserScenarioDiffValues.js +157 -0
  127. package/dist/domain/browserScenarioNormalization.js +45 -0
  128. package/dist/domain/browserScenarioValues.js +372 -0
  129. package/dist/domain/bytecodeProvider.js +179 -0
  130. package/dist/domain/conformancePackage.js +169 -0
  131. package/dist/domain/conformanceReplay.js +104 -0
  132. package/dist/domain/conformanceTrustGate.js +193 -0
  133. package/dist/domain/customProtocolCapture.js +137 -0
  134. package/dist/domain/eventProcessTree.js +214 -0
  135. package/dist/domain/evidenceBundle.js +47 -0
  136. package/dist/domain/hopperStartupFailure.js +1 -1
  137. package/dist/domain/hopperValues.js +14 -1
  138. package/dist/domain/inputIssueProjection.js +7 -1
  139. package/dist/domain/javascriptRuntimeObservation.js +170 -0
  140. package/dist/domain/javascriptRuntimeReconciliationParsing.js +120 -2
  141. package/dist/domain/javascriptRuntimeReconciliationResult.js +3 -3
  142. package/dist/domain/javascriptRuntimeReconciliationRuntime.js +2 -2
  143. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
  144. package/dist/domain/javascriptSemanticAnalysis.js +13 -16
  145. package/dist/domain/javascriptSemanticAsyncEffects.js +253 -0
  146. package/dist/domain/javascriptSemanticChildProcesses.js +237 -0
  147. package/dist/domain/javascriptSemanticDataEffectHelpers.js +125 -0
  148. package/dist/domain/javascriptSemanticDataEffects.js +284 -0
  149. package/dist/domain/javascriptSemanticDerivedAnalysis.js +41 -0
  150. package/dist/domain/javascriptSemanticFingerprints.js +174 -0
  151. package/dist/domain/javascriptSemanticIr.js +21 -1
  152. package/dist/domain/javascriptSemanticObjects.js +115 -0
  153. package/dist/domain/javascriptSemanticPromises.js +290 -0
  154. package/dist/domain/javascriptSemanticResources.js +136 -0
  155. package/dist/domain/javascriptSourceParser.js +15 -0
  156. package/dist/domain/javascriptStaticAnalysis.js +12 -15
  157. package/dist/domain/javascriptStaticAnalysisBundler.js +38 -0
  158. package/dist/domain/javascriptStaticAnalysisCalls.js +23 -1
  159. package/dist/domain/javascriptStaticAnalysisHelpers.js +8 -0
  160. package/dist/domain/mobileApplicationInvestigation.js +159 -0
  161. package/dist/domain/nativeApiBoundary.js +130 -0
  162. package/dist/domain/objcSwiftMetadata.js +150 -0
  163. package/dist/domain/packageAnalysis.js +123 -0
  164. package/dist/domain/peInspection.js +196 -0
  165. package/dist/domain/processCapture.js +8 -2
  166. package/dist/domain/processReactiveScenario.js +1 -0
  167. package/dist/domain/processReactiveTransition.js +9 -4
  168. package/dist/domain/protocolCapture.js +243 -0
  169. package/dist/domain/providerCleanupError.js +11 -0
  170. package/dist/domain/reconstructionObligationLedgerSchemas.js +278 -0
  171. package/dist/domain/reconstructionReadiness.js +121 -0
  172. package/dist/domain/reconstructionReadinessFindingHelpers.js +17 -0
  173. package/dist/domain/reconstructionReadinessIntegrityFindings.js +118 -0
  174. package/dist/domain/reconstructionReadinessJourneyFindings.js +193 -0
  175. package/dist/domain/reconstructionReadinessSchemas.js +240 -0
  176. package/dist/domain/sourceToBundleComparison.js +335 -0
  177. package/dist/domain/sourceToBundleComparisonSchemas.js +133 -0
  178. package/dist/domain/sourceToBundleSignals.js +202 -0
  179. package/dist/domain/webCaptureDiff.js +141 -27
  180. package/dist/domain/webScreenshot.js +1 -1
  181. package/dist/dotnet/ManagedStaticProvider.js +34 -5
  182. package/dist/generatedMcpToolCatalog.js +37 -0
  183. package/dist/generatedPackageMetadata.js +4 -4
  184. package/dist/ghidra/GhidraDefaults.js +1 -1
  185. package/dist/ghidra/GhidraFunctionValues.js +40 -2
  186. package/dist/ghidra/GhidraProviderCapabilities.js +47 -38
  187. package/dist/hopper/HopperCleanup.js +158 -0
  188. package/dist/hopper/HopperClient.js +93 -99
  189. package/dist/hopper/HopperProvider.js +61 -30
  190. package/dist/hopper/HopperRequestQueue.js +215 -0
  191. package/dist/hopper/HopperResponseStream.js +46 -0
  192. package/dist/hopper/protocol.js +63 -20
  193. package/dist/main/transport.js +24 -27
  194. package/dist/main.js +14 -6
  195. package/dist/mcpDoctor.js +27 -4
  196. package/dist/mcpStartupPolicy.js +14 -0
  197. package/dist/process/ProcessCommandIdentity.js +19 -0
  198. package/dist/process/ProcessOwnership.js +11 -8
  199. package/dist/server/DynamicToolAvailability.js +70 -0
  200. package/dist/server/LazyToolCatalog.js +134 -0
  201. package/dist/server/createServer.js +92 -154
  202. package/dist/server/hydrateServerTools.js +191 -0
  203. package/dist/server/lifecycleProgress.js +10 -0
  204. package/dist/server/permissionFailure.js +12 -0
  205. package/dist/server/registerApplicationTools/compareSourceToBundle.js +35 -0
  206. package/dist/server/registerApplicationTools/helpers.js +11 -7
  207. package/dist/server/registerApplicationTools/obligationLedger.js +27 -0
  208. package/dist/server/registerApplicationTools/readiness.js +55 -0
  209. package/dist/server/registerApplicationTools.js +6 -0
  210. package/dist/server/registerArtifactTools.js +9 -1
  211. package/dist/server/registerBrowserScenarioTool.js +25 -0
  212. package/dist/server/registerBrowserTools.js +2 -2
  213. package/dist/server/registerCloseLifecycleTool.js +57 -0
  214. package/dist/server/registerEnhancedTools.js +28 -7
  215. package/dist/server/registerEvidenceResources.js +54 -101
  216. package/dist/server/registerEvidenceTools.js +9 -2
  217. package/dist/server/registerInvestigationTools.js +1 -2
  218. package/dist/server/registerJavaScriptApplicationGraphResource.js +0 -4
  219. package/dist/server/registerJavaScriptRuntimeObservationTools.js +37 -0
  220. package/dist/server/registerReconstructionObligationLedgerResource.js +32 -0
  221. package/dist/server/registerReconstructionReadinessResource.js +32 -0
  222. package/dist/server/registerSessionRecordTools.js +82 -12
  223. package/dist/server/registerSessionStatusTool.js +11 -8
  224. package/dist/server/registerSessionTools.js +32 -58
  225. package/dist/server/sessionAvailabilityPolicy.js +10 -8
  226. package/dist/server/toolRegistrationOptions.js +21 -6
  227. package/dist/server/toolResult.js +12 -0
  228. package/package.json +28 -11
  229. package/scripts/package-runner-bootstrap.mjs +72 -0
  230. package/scripts/rea.mjs +11 -1
  231. package/skills/reverse-engineer-anything/SKILL.md +10 -3
@@ -1,10 +1,14 @@
1
1
  import { enhancedInputSchemas } from "../contracts/enhancedInputs.js";
2
2
  import { AnalysisCancelledError, AnalysisOutputError, projectAnalysisError, } from "../domain/errors.js";
3
- import { addressDistance, parseAddressedPage, parseDocuments, parseFunctionDossier, parseListCount, parseRelatedAddresses, parseSegments, } from "../domain/hopperValues.js";
3
+ import { addressDistance, functionDossierSchema, parseDocuments, parseFunctionDossier, parseListCount, parseRelatedAddresses, parseSegments, } from "../domain/hopperValues.js";
4
4
  import { err, ok } from "../domain/result.js";
5
5
  import { categorizeSwiftTypes, discoverObjcClasses, discoverObjcProtocols, discoverSwiftClasses, } from "../domain/symbolAnalysis.js";
6
+ import { jsonValueSchema } from "../domain/jsonValue.js";
6
7
  import { invalidEnhancedInput, } from "./EnhancedToolTypes.js";
7
8
  import { readAllAddressed } from "./EnhancedToolPagination.js";
9
+ import { traceCallPath } from "./CallPathTracing.js";
10
+ import { traceLiteralFeature } from "./EnhancedLiteralTracing.js";
11
+ import { projectNativeApiInspection } from "./NativeApiInspection.js";
8
12
  /**
9
13
  * Composes direct provider operations into bounded reverse-engineering tools.
10
14
  * Direct callers use `execute`; adapters that own validation use
@@ -17,6 +21,12 @@ export class EnhancedTools {
17
21
  }
18
22
  /** Parse an untrusted direct-call input once, then dispatch exhaustively. */
19
23
  execute(name, input, signal) {
24
+ if (name === "trace_feature" ||
25
+ name === "find_code_for_string" ||
26
+ name === "trace_call_path")
27
+ return this.#executeTracing(name, input, signal);
28
+ if (name === "analyze_function" || name === "inspect_native_api")
29
+ return this.#executeFunctionAnalysis(name, input, signal);
20
30
  switch (name) {
21
31
  case "swift_classes": {
22
32
  const parsed = enhancedInputSchemas.swift_classes.safeParse(input);
@@ -58,18 +68,6 @@ export class EnhancedTools {
58
68
  ? this.executeValidated({ name, input: parsed.data }, signal)
59
69
  : invalidEnhancedInput(name, parsed.error);
60
70
  }
61
- case "analyze_function": {
62
- const parsed = enhancedInputSchemas.analyze_function.safeParse(input);
63
- return parsed.success
64
- ? this.executeValidated({ name, input: parsed.data }, signal)
65
- : invalidEnhancedInput(name, parsed.error);
66
- }
67
- case "trace_feature": {
68
- const parsed = enhancedInputSchemas.trace_feature.safeParse(input);
69
- return parsed.success
70
- ? this.executeValidated({ name, input: parsed.data }, signal)
71
- : invalidEnhancedInput(name, parsed.error);
72
- }
73
71
  }
74
72
  }
75
73
  /** Dispatch input already parsed by a trusted adapter boundary. */
@@ -93,14 +91,64 @@ export class EnhancedTools {
93
91
  return this.#binaryOverview(call.input, signal);
94
92
  case "analyze_function":
95
93
  return this.#analyzeFunction(call.input, signal);
94
+ case "inspect_native_api":
95
+ return this.#inspectNativeApi(call.input, signal);
96
96
  case "trace_feature":
97
- return this.#traceFeature(call.input, signal);
97
+ return traceLiteralFeature((name, arguments_, operationSignal) => this.#call(name, arguments_, operationSignal), call.input, "feature", signal);
98
+ case "find_code_for_string":
99
+ return traceLiteralFeature((name, arguments_, operationSignal) => this.#call(name, arguments_, operationSignal), call.input, "string", signal);
100
+ case "trace_call_path":
101
+ return traceCallPath((name, arguments_, operationSignal) => this.#call(name, arguments_, operationSignal), call.input, signal);
98
102
  }
99
103
  }
104
+ #executeTracing(name, input, signal) {
105
+ const parsed = enhancedInputSchemas[name].safeParse(input);
106
+ if (!parsed.success)
107
+ return invalidEnhancedInput(name, parsed.error);
108
+ if (name === "trace_call_path")
109
+ return this.executeValidated({
110
+ name,
111
+ input: enhancedInputSchemas.trace_call_path.parse(parsed.data),
112
+ }, signal);
113
+ return this.executeValidated({
114
+ name,
115
+ input: enhancedInputSchemas[name].parse(parsed.data),
116
+ }, signal);
117
+ }
118
+ #executeFunctionAnalysis(name, input, signal) {
119
+ const parsed = enhancedInputSchemas[name].safeParse(input);
120
+ if (!parsed.success)
121
+ return invalidEnhancedInput(name, parsed.error);
122
+ if (name === "analyze_function")
123
+ return this.executeValidated({
124
+ name,
125
+ input: enhancedInputSchemas.analyze_function.parse(parsed.data),
126
+ }, signal);
127
+ return this.executeValidated({
128
+ name,
129
+ input: enhancedInputSchemas.inspect_native_api.parse(parsed.data),
130
+ }, signal);
131
+ }
100
132
  async #analyzeFunction(input, signal) {
101
133
  const result = await this.#call("analyze_function", input, signal);
102
134
  return result.ok ? parseFunctionDossier(result.value) : result;
103
135
  }
136
+ async #inspectNativeApi(input, signal) {
137
+ const analysisInput = enhancedInputSchemas.analyze_function.parse({
138
+ procedure: input.procedure,
139
+ include_assembly: true,
140
+ max_pseudocode_chars: input.max_pseudocode_chars,
141
+ max_instructions: input.max_instructions,
142
+ });
143
+ const result = await this.#call("analyze_function", analysisInput, signal);
144
+ if (!result.ok)
145
+ return result;
146
+ const parsed = parseFunctionDossier(result.value);
147
+ if (!parsed.ok)
148
+ return parsed;
149
+ const dossier = functionDossierSchema.parse(parsed.value);
150
+ return ok(jsonValueSchema.parse(projectNativeApiInspection(dossier)));
151
+ }
104
152
  async #swiftClasses(pattern, signal) {
105
153
  const procedures = await this.#allAddressed("list_procedures", signal);
106
154
  return procedures.ok
@@ -217,18 +265,18 @@ export class EnhancedTools {
217
265
  });
218
266
  }
219
267
  async #binaryOverview(input, signal) {
220
- const [segmentsResult, documentsResult, procedures, stringsResult] = await Promise.all([
268
+ const [segmentsResult, documentsResult, proceduresResult, stringsResult] = await Promise.all([
221
269
  this.#call("list_segments", {}, signal),
222
270
  this.#call("list_documents", {}, signal),
223
- this.#allAddressed("list_procedures", signal),
224
- this.#call("list_strings", {}, signal),
271
+ this.#call("list_procedures", { offset: 0, limit: 1 }, signal),
272
+ this.#call("list_strings", { offset: 0, limit: 1 }, signal),
225
273
  ]);
226
274
  if (!segmentsResult.ok)
227
275
  return segmentsResult;
228
276
  if (!documentsResult.ok)
229
277
  return documentsResult;
230
- if (!procedures.ok)
231
- return procedures;
278
+ if (!proceduresResult.ok)
279
+ return proceduresResult;
232
280
  if (!stringsResult.ok)
233
281
  return stringsResult;
234
282
  const segments = parseSegments(segmentsResult.value);
@@ -237,6 +285,9 @@ export class EnhancedTools {
237
285
  const documents = parseDocuments(documentsResult.value);
238
286
  if (!documents.ok)
239
287
  return documents;
288
+ const procedureCount = parseListCount(proceduresResult.value, "procedures");
289
+ if (!procedureCount.ok)
290
+ return procedureCount;
240
291
  const stringCount = parseListCount(stringsResult.value, "strings");
241
292
  if (!stringCount.ok)
242
293
  return stringCount;
@@ -249,117 +300,10 @@ export class EnhancedTools {
249
300
  ? { name, start, end, length: addressDistance(start, end) }
250
301
  : { name, start, end }),
251
302
  segment_count: segments.value.length,
252
- procedure_count: procedures.value.length,
303
+ procedure_count: procedureCount.value,
253
304
  string_count: stringCount.value,
254
305
  });
255
306
  }
256
- async #traceFeature(input, signal) {
257
- const searched = await this.#literalMatches(input, signal);
258
- if (!searched.ok)
259
- return searched;
260
- const residual = new Set();
261
- const traced = await this.#traceReferences(searched.value.matches, input.limit, input.max_operations - searched.value.operations, signal);
262
- if (!traced.ok)
263
- return traced;
264
- for (const reason of traced.value.residual)
265
- residual.add(reason);
266
- const operations = searched.value.operations + traced.value.operations;
267
- if (operations >= input.max_operations)
268
- residual.add("Investigation reached the operation budget.");
269
- if (searched.value.matches.length >= input.limit)
270
- residual.add("Literal matches reached the configured limit.");
271
- return ok({
272
- query: input.query,
273
- search_mode: "literal",
274
- operations_used: operations,
275
- operation_budget: input.max_operations,
276
- matches: searched.value.matches,
277
- references: traced.value.references,
278
- truncated: residual.size > 0,
279
- residual_unknowns: [...residual],
280
- });
281
- }
282
- async #literalMatches(input, signal) {
283
- let operations = 0;
284
- const matches = [];
285
- const needle = input.case_sensitive
286
- ? input.query
287
- : input.query.toLowerCase();
288
- for (const [tool, type] of [
289
- ["list_strings", "string"],
290
- ["list_procedures", "procedure"],
291
- ]) {
292
- let offset = 0;
293
- while (operations < input.max_operations &&
294
- matches.length < input.limit) {
295
- operations += 1;
296
- const result = await this.#call(tool, { offset, limit: 500 }, signal);
297
- if (!result.ok)
298
- return result;
299
- const page = parseAddressedPage(result.value);
300
- if (!page.ok)
301
- return page;
302
- for (const item of page.value.items) {
303
- const haystack = input.case_sensitive
304
- ? item.name
305
- : item.name.toLowerCase();
306
- if (haystack.includes(needle))
307
- matches.push({ type, address: item.address, value: item.name });
308
- if (matches.length >= input.limit)
309
- break;
310
- }
311
- if (!page.value.hasMore || page.value.nextOffset === null)
312
- break;
313
- offset = page.value.nextOffset;
314
- }
315
- }
316
- return ok({ matches, operations });
317
- }
318
- async #traceReferences(matches, limit, operationBudget, signal) {
319
- let operations = 0;
320
- const references = [];
321
- const residual = new Set();
322
- for (const match of matches) {
323
- if (operations >= operationBudget) {
324
- residual.add("Reference traversal stopped at the operation budget.");
325
- break;
326
- }
327
- operations += 1;
328
- const xrefs = await this.#call("xrefs", { address: match.address }, signal);
329
- if (!xrefs.ok)
330
- return xrefs;
331
- if (!Array.isArray(xrefs.value))
332
- return err(new AnalysisOutputError("xrefs", "provider returned a non-array result"));
333
- for (const source of xrefs.value) {
334
- if (typeof source !== "string")
335
- return err(new AnalysisOutputError("xrefs", "provider returned a non-address value"));
336
- if (operations >= operationBudget) {
337
- residual.add("Containing-procedure resolution stopped at the operation budget.");
338
- break;
339
- }
340
- operations += 1;
341
- const resolved = await this.#call("resolve_containing_procedure", { address: source }, signal);
342
- if (!resolved.ok)
343
- return resolved;
344
- references.push({
345
- target_address: match.address,
346
- source_address: source,
347
- containing_procedure: resolved.value,
348
- });
349
- if (references.length >= limit) {
350
- residual.add("Reference results reached the configured limit.");
351
- break;
352
- }
353
- }
354
- if (references.length >= limit)
355
- break;
356
- }
357
- return ok({
358
- references,
359
- operations,
360
- residual: [...residual],
361
- });
362
- }
363
307
  async #allAddressed(tool, signal) {
364
308
  return readAllAddressed({
365
309
  call: (name, arguments_, operationSignal) => this.#call(name, arguments_, operationSignal),
@@ -1,5 +1,5 @@
1
1
  import canonicalize from "canonicalize";
2
- import { createEvidenceBundle, parseEvidenceBundle, } from "../domain/evidenceBundle.js";
2
+ import { createEvidenceBundle, parseEvidenceBundle, validateResidualUnknownAddition, } from "../domain/evidenceBundle.js";
3
3
  import { EvidenceIntegrityError, EvidenceLimitError, UnknownRegistryError, } from "../domain/errors.js";
4
4
  import { parseEvidence } from "../domain/evidence.js";
5
5
  import { createResidualUnknown, updateResidualUnknown, } from "../domain/residualUnknown.js";
@@ -142,26 +142,19 @@ export class EvidenceLedger {
142
142
  catch (cause) {
143
143
  return err(new UnknownRegistryError("invalid-transition", { cause }));
144
144
  }
145
- const pendingRecords = new Map(this.#records);
146
- pendingRecords.set(evidence.evidence_id, evidence);
147
145
  const existingUnknown = this.#unknownHeads.get(unknown.unknown_id);
148
146
  if (existingUnknown !== undefined) {
149
147
  if (existingUnknown.revision !== 1 ||
150
148
  existingUnknown.revision_digest !== unknown.revision_digest)
151
149
  return err(new UnknownRegistryError("already-exists"));
152
- const checked = this.#validateCandidate(pendingRecords, this.#unknownRevisions);
150
+ const checked = this.#appendIncremental([evidence]);
153
151
  if (!checked.ok)
154
152
  return checked;
155
- this.#commit(pendingRecords, this.#unknownRevisions, checked.value);
156
153
  return ok(null);
157
154
  }
158
- pendingRecords.set(mutation.evidence_id, mutation);
159
- const pendingUnknowns = new Map(this.#unknownRevisions);
160
- pendingUnknowns.set(unknownRevisionKey(unknown), unknown);
161
- const checked = this.#validateCandidate(pendingRecords, pendingUnknowns);
155
+ const checked = this.#appendIncremental([evidence, mutation], unknown);
162
156
  if (!checked.ok)
163
157
  return checked;
164
- this.#commit(pendingRecords, pendingUnknowns, checked.value);
165
158
  return ok(structuredClone(unknown));
166
159
  }
167
160
  /** Apply one approved full-state update using optimistic revision matching. */
@@ -218,16 +211,52 @@ export class EvidenceLedger {
218
211
  cause,
219
212
  }));
220
213
  }
221
- const pendingRecords = new Map(this.#records);
222
- pendingRecords.set(mutationEvidence.evidence_id, mutationEvidence);
223
- const pendingUnknowns = new Map(this.#unknownRevisions);
224
- pendingUnknowns.set(unknownRevisionKey(unknown), unknown);
225
- const checked = this.#validateCandidate(pendingRecords, pendingUnknowns);
214
+ const checked = this.#appendIncremental([mutationEvidence], unknown);
226
215
  if (!checked.ok)
227
216
  return checked;
228
- this.#commit(pendingRecords, pendingUnknowns, checked.value);
229
217
  return ok(structuredClone(unknown));
230
218
  }
219
+ #appendIncremental(records, unknown) {
220
+ const additions = new Map();
221
+ let addedBytes = 0;
222
+ for (const evidence of records) {
223
+ const existing = additions.get(evidence.evidence_id) ??
224
+ this.#records.get(evidence.evidence_id);
225
+ if (existing !== undefined) {
226
+ if (!recordsAgree(existing, evidence))
227
+ return err(new EvidenceIntegrityError("Conflicting evidence record"));
228
+ continue;
229
+ }
230
+ additions.set(evidence.evidence_id, evidence);
231
+ addedBytes += serializedBytes(evidence);
232
+ }
233
+ const unknownKey = unknown === undefined ? undefined : unknownRevisionKey(unknown);
234
+ if (unknownKey !== undefined && this.#unknownRevisions.has(unknownKey))
235
+ return err(new UnknownRegistryError("integrity"));
236
+ const unknownBytes = unknown === undefined ? 0 : serializedBytes(unknown);
237
+ if (this.#exceedsRecordLimit(this.#records.size + additions.size, this.#unknownRevisions.size + (unknown === undefined ? 0 : 1)))
238
+ return err(new EvidenceLimitError("records", this.limits.maxRecords));
239
+ if (this.#bytes + addedBytes + unknownBytes > this.limits.maxBytes)
240
+ return err(new EvidenceLimitError("bytes", this.limits.maxBytes));
241
+ if (unknown !== undefined)
242
+ try {
243
+ validateResidualUnknownAddition(unknown, {
244
+ get: (id) => additions.get(id) ?? this.#records.get(id),
245
+ has: (id) => additions.has(id) || this.#records.has(id),
246
+ }, this.#unknownHeads);
247
+ }
248
+ catch (cause) {
249
+ return err(new UnknownRegistryError("integrity", { cause }));
250
+ }
251
+ for (const [id, evidence] of additions)
252
+ this.#records.set(id, evidence);
253
+ if (unknown !== undefined && unknownKey !== undefined) {
254
+ this.#unknownRevisions.set(unknownKey, unknown);
255
+ this.#unknownHeads.set(unknown.unknown_id, unknown);
256
+ }
257
+ this.#bytes += addedBytes + unknownBytes;
258
+ return ok(undefined);
259
+ }
231
260
  #validateCandidate(records, unknowns) {
232
261
  if (this.#exceedsRecordLimit(records.size, unknowns.size))
233
262
  return err(new EvidenceLimitError("records", this.limits.maxRecords));
@@ -40,6 +40,19 @@ export const createApplicationVersionComparisonEvidence = (parameters, result) =
40
40
  limitations: result.limitations,
41
41
  evidenceLinks: result.evidence_links,
42
42
  });
43
+ /** Create derived Evidence for one historical-source to bundle comparison. */
44
+ export const createSourceToBundleComparisonEvidence = (parameters, result) => createEvidence(undefined, JAVASCRIPT_APPLICATION_WORKFLOW_PROVIDER, {
45
+ predicateType: "rea.source-to-bundle-comparison/v1",
46
+ operation: "compare_source_to_bundle",
47
+ parameters,
48
+ result: jsonValueSchema.parse(result),
49
+ rawResult: null,
50
+ confidence: "inferred",
51
+ authority: "analyst-inference",
52
+ environment: null,
53
+ limitations: result.limitations,
54
+ evidenceLinks: result.evidence_links,
55
+ });
43
56
  /** Create derived Evidence for one bounded static export-shape comparison. */
44
57
  export const createJavaScriptExportShapeComparisonEvidence = (parameters, result) => createEvidence(undefined, JAVASCRIPT_APPLICATION_WORKFLOW_PROVIDER, {
45
58
  predicateType: "rea.javascript-export-shape-comparison/v1",
@@ -8,8 +8,10 @@ import { compareJavaScriptExportShapesInputSchema } from "../domain/javascriptEx
8
8
  import { traceApplicationFeature } from "../domain/javascriptFeatureTrace.js";
9
9
  import { traceApplicationFeatureInputSchema } from "../domain/javascriptFeatureTraceSchemas.js";
10
10
  import { err, ok } from "../domain/result.js";
11
+ import { compareSourceToBundle } from "../domain/sourceToBundleComparison.js";
12
+ import { compareSourceToBundleInputSchema } from "../domain/sourceToBundleComparisonSchemas.js";
11
13
  import { parseApplicationGraphEvidence, parseNativeApplicationEvidence, } from "./JavaScriptApplicationEvidenceGraph.js";
12
- import { createApplicationFeatureTraceEvidence, createApplicationVersionComparisonEvidence, createJavaScriptExportShapeComparisonEvidence, } from "./JavaScriptApplicationWorkflowEvidence.js";
14
+ import { createApplicationFeatureTraceEvidence, createApplicationVersionComparisonEvidence, createJavaScriptExportShapeComparisonEvidence, createSourceToBundleComparisonEvidence, } from "./JavaScriptApplicationWorkflowEvidence.js";
13
15
  /** Authenticate Evidence and derive one bounded cross-layer feature trace. */
14
16
  export const traceApplicationFeatureEvidence = (rawInput) => {
15
17
  const operation = "trace_application_feature";
@@ -87,6 +89,30 @@ export const compareApplicationVersionsEvidenceValidated = (input) => {
87
89
  return workflowFailure(operation, cause);
88
90
  }
89
91
  };
92
+ /** Compare source and bundle inputs already parsed by a trusted adapter. */
93
+ export const compareSourceToBundleEvidenceValidated = (input) => {
94
+ const operation = "compare_source_to_bundle";
95
+ try {
96
+ const application = parseApplicationGraphEvidence(input.application);
97
+ const result = compareSourceToBundle({
98
+ reference: input.reference,
99
+ application: {
100
+ evidenceId: application.evidence.evidence_id,
101
+ rootArtifactSha256: application.rootArtifactSha256,
102
+ graph: application.graph,
103
+ },
104
+ limits: input.limits,
105
+ });
106
+ return ok(createSourceToBundleComparisonEvidence({
107
+ reference_root_sha256: input.reference.root_sha256,
108
+ application_evidence_id: application.evidence.evidence_id,
109
+ limits: input.limits,
110
+ }, result));
111
+ }
112
+ catch (cause) {
113
+ return workflowFailure(operation, cause);
114
+ }
115
+ };
90
116
  /**
91
117
  * Authenticate both graphs and compare one exact export return shape.
92
118
  * @public
@@ -1,7 +1,9 @@
1
1
  import { createHash } from "node:crypto";
2
- import { analyzeJavaScriptStaticSource } from "../domain/javascriptStaticAnalysis.js";
3
- import { analyzeJavaScriptSemantics } from "../domain/javascriptSemanticAnalysis.js";
2
+ import { analyzeParsedJavaScriptStaticSource } from "../domain/javascriptStaticAnalysis.js";
3
+ import { analyzeParsedJavaScriptSemantics } from "../domain/javascriptSemanticAnalysis.js";
4
4
  import { DEFAULT_JAVASCRIPT_SEMANTIC_LIMITS, } from "../domain/javascriptSemanticIr.js";
5
+ import { parseJavaScriptSource } from "../domain/javascriptSourceParser.js";
6
+ import { failedJavaScriptStaticAnalysis } from "../domain/javascriptStaticAnalysisHelpers.js";
5
7
  import { analyzeJavaScriptJsonModule } from "./JavaScriptJsonModules.js";
6
8
  /** Analyze selected text files under one shared AST, finding, module, and time budget. */
7
9
  export const analyzeJavaScriptArtifactFiles = (fileSet, input, now) => {
@@ -70,7 +72,14 @@ const analyzeArtifactFile = (file, context) => {
70
72
  state.truncatedScopes += 1;
71
73
  return;
72
74
  }
73
- const analysis = analyzeJavaScriptStaticSource(file.text.value, {
75
+ const parsed = parseJavaScriptSource(file.text.value);
76
+ if (parsed === null) {
77
+ const analysis = failedJavaScriptStaticAnalysis();
78
+ state.files.push({ file, javascript: analysis, semantic: null });
79
+ state.parseFailures += 1;
80
+ return;
81
+ }
82
+ const analysis = analyzeParsedJavaScriptStaticSource(file.text.value, parsed, {
74
83
  maxAstNodes: remainingNodes,
75
84
  maxFindings: remainingFindings,
76
85
  maxModules: remainingModules,
@@ -88,7 +97,7 @@ const analyzeArtifactFile = (file, context) => {
88
97
  maxModuleLinks: semanticFindingBudget,
89
98
  };
90
99
  const semantics = analysis.parse_status === "complete" || analysis.parse_status === "partial"
91
- ? analyzeJavaScriptSemantics(file.text.value, semanticLimits)
100
+ ? analyzeParsedJavaScriptSemantics(parsed, semanticLimits)
92
101
  : null;
93
102
  state.files.push({
94
103
  file,
@@ -0,0 +1,34 @@
1
+ import { createEvidence, } from "../domain/evidence.js";
2
+ import { jsonValueSchema } from "../domain/jsonValue.js";
3
+ /** Create deterministic Evidence v2 for one passive Inspector operation. */
4
+ export const createJavaScriptRuntimeObservationEvidence = (operation, input, result, provider) => createEvidence(undefined, provider, {
5
+ predicateType: operation === "list_javascript_runtime_targets"
6
+ ? "rea.javascript-runtime-target-list/v1"
7
+ : "rea.javascript-runtime-observation/v1",
8
+ operation,
9
+ parameters: parameters(input),
10
+ result: jsonValueSchema.parse(result),
11
+ rawResult: null,
12
+ confidence: "observed",
13
+ authority: "external-service",
14
+ environment: {
15
+ id: `${result.runtime.product}@${result.runtime.protocol_version}`,
16
+ platform: process.platform,
17
+ architecture: process.arch,
18
+ isolation: "none",
19
+ },
20
+ limitations: result.limitations,
21
+ });
22
+ const parameters = (input) => ({
23
+ inspector_endpoint: input.inspector_endpoint,
24
+ allowed_file_roots: input.allowed_file_roots,
25
+ allowed_origins: input.allowed_origins,
26
+ ...("target_id" in input
27
+ ? {
28
+ target_id: input.target_id,
29
+ runtime_kind: input.runtime_kind,
30
+ observation_ms: input.observation_ms,
31
+ limits: input.limits,
32
+ }
33
+ : { offset: input.offset, limit: input.limit }),
34
+ });
@@ -0,0 +1,46 @@
1
+ import { createJavaScriptRuntimeObservationEvidence } from "./JavaScriptRuntimeObservationEvidence.js";
2
+ import { AnalysisCapabilityUnavailableError, AnalysisProtocolError, PermissionRequiredError, } from "../domain/errors.js";
3
+ import { err, ok } from "../domain/result.js";
4
+ /** Authorize and list attachable Node/Electron Inspector targets. */
5
+ export const listJavaScriptRuntimeTargets = async (provider, authority, input, options = {}) => {
6
+ const ready = await prepare(provider, authority, input, "list_javascript_runtime_targets");
7
+ if (!ready.ok)
8
+ return ready;
9
+ const result = await ready.value.listTargets(input, options);
10
+ return result.ok
11
+ ? ok(createJavaScriptRuntimeObservationEvidence("list_javascript_runtime_targets", input, result.value, ready.value.identity()))
12
+ : result;
13
+ };
14
+ /** Authorize one bounded attach-only Inspector observation. */
15
+ export const observeJavaScriptRuntime = async (provider, authority, input, options = {}) => {
16
+ const ready = await prepare(provider, authority, input, "observe_javascript_runtime");
17
+ if (!ready.ok)
18
+ return ready;
19
+ const result = await ready.value.observe(input, options);
20
+ return result.ok
21
+ ? ok(createJavaScriptRuntimeObservationEvidence("observe_javascript_runtime", input, result.value, ready.value.identity()))
22
+ : result;
23
+ };
24
+ const prepare = async (provider, authority, input, operation) => {
25
+ if (authority === undefined)
26
+ return err(new AnalysisCapabilityUnavailableError("rea-v8-inspector", operation, "V8 Inspector observation permission policy is not configured"));
27
+ const authorized = await authority.authorize({
28
+ capability: "v8_inspector_observe",
29
+ roots: input.allowed_file_roots,
30
+ executables: [],
31
+ environment_names: [],
32
+ origins: [input.inspector_endpoint, ...input.allowed_origins],
33
+ network: "loopback",
34
+ mount: false,
35
+ operation_identity: `${operation}:${"target_id" in input ? input.target_id : input.inspector_endpoint}`,
36
+ }, "read");
37
+ if (!authorized.ok)
38
+ return err(authorized.error instanceof PermissionRequiredError
39
+ ? authorized.error
40
+ : new AnalysisProtocolError(authorized.error.message, {
41
+ cause: authorized.error,
42
+ }));
43
+ return provider === undefined
44
+ ? err(new AnalysisCapabilityUnavailableError("rea-v8-inspector", operation, "V8 Inspector observation provider is not configured"))
45
+ : ok(provider);
46
+ };