rea-agents 2.4.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 (186) 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/BinarySession.js +15 -4
  7. package/dist/application/BinarySessionStatus.js +31 -1
  8. package/dist/application/BrowserEvidence.js +14 -0
  9. package/dist/application/BrowserScenarioCapturePort.js +1 -0
  10. package/dist/application/BrowserScenarioCaptureService.js +53 -0
  11. package/dist/application/BrowserScenarioEvidence.js +40 -0
  12. package/dist/application/CallPathTracing.js +160 -0
  13. package/dist/application/CapabilityInventory.js +68 -12
  14. package/dist/application/CompositeProvider.js +10 -1
  15. package/dist/application/DirectAnalysis.js +7 -2
  16. package/dist/application/EnhancedLiteralTracing.js +118 -0
  17. package/dist/application/EnhancedTools.js +35 -121
  18. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +13 -0
  19. package/dist/application/JavaScriptApplicationWorkflowService.js +27 -1
  20. package/dist/application/JavaScriptRuntimeObservationEvidence.js +34 -0
  21. package/dist/application/JavaScriptRuntimeObservationPort.js +1 -0
  22. package/dist/application/JavaScriptRuntimeObservationService.js +46 -0
  23. package/dist/application/JavaScriptSemanticGraphAsyncProjection.js +147 -0
  24. package/dist/application/JavaScriptSemanticGraphBuilder.js +34 -6
  25. package/dist/application/JavaScriptSemanticGraphChildProcessProjection.js +156 -0
  26. package/dist/application/JavaScriptSemanticGraphConstruction.js +2 -2
  27. package/dist/application/JavaScriptSemanticGraphDataProjection.js +203 -0
  28. package/dist/application/JavaScriptSemanticGraphFingerprintProjection.js +25 -0
  29. package/dist/application/JavaScriptSemanticGraphFlowProjection.js +129 -8
  30. package/dist/application/JavaScriptSemanticGraphObjectProjection.js +81 -0
  31. package/dist/application/JavaScriptSemanticGraphProjection.js +14 -7
  32. package/dist/application/JavaScriptSemanticGraphResourceProjection.js +59 -0
  33. package/dist/application/JavaScriptSemanticGraphValueProjection.js +77 -0
  34. package/dist/application/ProcessReactiveEffects.js +6 -0
  35. package/dist/application/ProcessReactiveHarness.js +16 -1
  36. package/dist/application/ProjectPermissionStore.js +1 -0
  37. package/dist/application/ReconstructionObligationAuthority.js +72 -0
  38. package/dist/application/ReconstructionObligationCandidates.js +265 -0
  39. package/dist/application/ReconstructionObligationLedgerDiagnostics.js +47 -0
  40. package/dist/application/ReconstructionObligationLedgerEvaluation.js +263 -0
  41. package/dist/application/ReconstructionObligationLedgerProjection.js +86 -0
  42. package/dist/application/ReconstructionObligationLedgerService.js +72 -0
  43. package/dist/application/ReconstructionObligationOriginalCases.js +33 -0
  44. package/dist/application/ReconstructionObligationPolicies.js +132 -0
  45. package/dist/application/ReconstructionReadinessService.js +48 -0
  46. package/dist/artifacts/ArtifactProvider.js +87 -22
  47. package/dist/browser/BrowserScenarioSecrets.js +53 -0
  48. package/dist/browser/BrowserScenarioSessionPort.js +1 -0
  49. package/dist/browser/CdpBrowserProvider.js +2 -2
  50. package/dist/browser/CdpCaptureDocuments.js +57 -0
  51. package/dist/browser/CdpCaptureStorage.js +71 -29
  52. package/dist/browser/CdpCaptureStorageFingerprints.js +328 -0
  53. package/dist/browser/CdpEndpoint.js +8 -6
  54. package/dist/browser/CdpPageCapture.js +2 -0
  55. package/dist/browser/JavaScriptRuntimeScope.js +38 -0
  56. package/dist/browser/PlaywrightBrowserScenarioProvider.js +253 -0
  57. package/dist/browser/PlaywrightExecutionBoundary.js +42 -0
  58. package/dist/browser/PlaywrightScenarioActions.js +62 -0
  59. package/dist/browser/PlaywrightScenarioArtifacts.js +238 -0
  60. package/dist/browser/PlaywrightScenarioBrowser.js +144 -0
  61. package/dist/browser/PlaywrightScenarioEvents.js +301 -0
  62. package/dist/browser/PlaywrightScenarioSession.js +300 -0
  63. package/dist/browser/V8InspectorCaptureProjection.js +110 -0
  64. package/dist/browser/V8InspectorEndpoint.js +72 -0
  65. package/dist/browser/V8InspectorProvider.js +267 -0
  66. package/dist/catalogIdentity.js +8 -0
  67. package/dist/cli/artifactCommands.js +39 -0
  68. package/dist/cli/coreAnalysisCommands.js +37 -0
  69. package/dist/cli.js +4 -0
  70. package/dist/cliApplicationCommands.js +30 -2
  71. package/dist/cliBrowserAdvancedCommands.js +17 -5
  72. package/dist/cliBrowserCommands.js +1 -0
  73. package/dist/cliBrowserScenarioCommands.js +43 -0
  74. package/dist/cliCommandNames.js +8 -0
  75. package/dist/cliJavaScriptRuntimeCommands.js +164 -0
  76. package/dist/cliObservationOptions.js +4 -0
  77. package/dist/cliPolicyCommands.js +1 -0
  78. package/dist/config/environment.js +12 -0
  79. package/dist/config/parseConfig.js +88 -17
  80. package/dist/contracts/analysisSearchContract.js +14 -0
  81. package/dist/contracts/applicationToolContracts.js +86 -2
  82. package/dist/contracts/applicationWorkflowInputContracts.js +18 -0
  83. package/dist/contracts/artifactToolContracts.js +22 -0
  84. package/dist/contracts/browserProviderToolContracts.js +7 -0
  85. package/dist/contracts/browserScenarioToolContracts.js +81 -0
  86. package/dist/contracts/browserToolContracts.js +88 -98
  87. package/dist/contracts/enhancedInputs.js +25 -6
  88. package/dist/contracts/functionInstructionContract.js +8 -0
  89. package/dist/contracts/hopperMemoryContracts.js +22 -0
  90. package/dist/contracts/javascriptApplicationWorkflowExamples.js +42 -0
  91. package/dist/contracts/javascriptRuntimeObservationToolContracts.js +58 -0
  92. package/dist/contracts/reconstructionReadinessExample.js +436 -0
  93. package/dist/contracts/toolContractExamples.js +5 -0
  94. package/dist/contracts/toolContractTypes.js +1 -0
  95. package/dist/contracts/toolContracts.js +13 -21
  96. package/dist/contracts/toolEffects.js +21 -0
  97. package/dist/contracts/toolOutputSchemaGroups.js +70 -20
  98. package/dist/contracts/toolOutputSchemaPrimitives.js +37 -0
  99. package/dist/domain/analysisErrorProjection.js +8 -0
  100. package/dist/domain/artifactInspection.js +347 -0
  101. package/dist/domain/browserCaptureComparison.js +82 -0
  102. package/dist/domain/browserObservation.js +8 -1
  103. package/dist/domain/browserObservationErrors.js +1 -0
  104. package/dist/domain/browserObservationSchemas.js +26 -0
  105. package/dist/domain/browserScenario.js +165 -0
  106. package/dist/domain/browserScenarioCapture.js +57 -0
  107. package/dist/domain/browserScenarioCaptureValues.js +204 -0
  108. package/dist/domain/browserScenarioDiff.js +324 -0
  109. package/dist/domain/browserScenarioDiffValues.js +157 -0
  110. package/dist/domain/browserScenarioNormalization.js +45 -0
  111. package/dist/domain/browserScenarioValues.js +372 -0
  112. package/dist/domain/hopperValues.js +10 -0
  113. package/dist/domain/javascriptRuntimeObservation.js +170 -0
  114. package/dist/domain/javascriptRuntimeReconciliationParsing.js +120 -2
  115. package/dist/domain/javascriptRuntimeReconciliationResult.js +3 -3
  116. package/dist/domain/javascriptRuntimeReconciliationRuntime.js +2 -2
  117. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
  118. package/dist/domain/javascriptSemanticAnalysis.js +5 -4
  119. package/dist/domain/javascriptSemanticAsyncEffects.js +253 -0
  120. package/dist/domain/javascriptSemanticChildProcesses.js +237 -0
  121. package/dist/domain/javascriptSemanticDataEffectHelpers.js +125 -0
  122. package/dist/domain/javascriptSemanticDataEffects.js +284 -0
  123. package/dist/domain/javascriptSemanticDerivedAnalysis.js +41 -0
  124. package/dist/domain/javascriptSemanticFingerprints.js +174 -0
  125. package/dist/domain/javascriptSemanticIr.js +21 -1
  126. package/dist/domain/javascriptSemanticObjects.js +115 -0
  127. package/dist/domain/javascriptSemanticPromises.js +290 -0
  128. package/dist/domain/javascriptSemanticResources.js +136 -0
  129. package/dist/domain/javascriptStaticAnalysis.js +4 -3
  130. package/dist/domain/javascriptStaticAnalysisBundler.js +38 -0
  131. package/dist/domain/javascriptStaticAnalysisCalls.js +23 -1
  132. package/dist/domain/javascriptStaticAnalysisHelpers.js +8 -0
  133. package/dist/domain/processCapture.js +8 -2
  134. package/dist/domain/processReactiveScenario.js +1 -0
  135. package/dist/domain/processReactiveTransition.js +9 -4
  136. package/dist/domain/providerCleanupError.js +11 -0
  137. package/dist/domain/reconstructionObligationLedgerSchemas.js +278 -0
  138. package/dist/domain/reconstructionReadiness.js +121 -0
  139. package/dist/domain/reconstructionReadinessFindingHelpers.js +17 -0
  140. package/dist/domain/reconstructionReadinessIntegrityFindings.js +118 -0
  141. package/dist/domain/reconstructionReadinessJourneyFindings.js +193 -0
  142. package/dist/domain/reconstructionReadinessSchemas.js +240 -0
  143. package/dist/domain/sourceToBundleComparison.js +335 -0
  144. package/dist/domain/sourceToBundleComparisonSchemas.js +133 -0
  145. package/dist/domain/sourceToBundleSignals.js +202 -0
  146. package/dist/domain/webCaptureDiff.js +141 -27
  147. package/dist/domain/webScreenshot.js +1 -1
  148. package/dist/generatedPackageMetadata.js +1 -1
  149. package/dist/ghidra/GhidraDefaults.js +1 -1
  150. package/dist/ghidra/GhidraFunctionValues.js +13 -1
  151. package/dist/ghidra/GhidraProviderCapabilities.js +7 -0
  152. package/dist/hopper/HopperCleanup.js +158 -0
  153. package/dist/hopper/HopperClient.js +69 -99
  154. package/dist/hopper/HopperProvider.js +20 -1
  155. package/dist/hopper/HopperRequestQueue.js +187 -0
  156. package/dist/hopper/HopperResponseStream.js +46 -0
  157. package/dist/hopper/protocol.js +1 -0
  158. package/dist/main/transport.js +24 -24
  159. package/dist/main.js +6 -0
  160. package/dist/mcpDoctor.js +25 -2
  161. package/dist/process/ProcessCommandIdentity.js +19 -0
  162. package/dist/process/ProcessOwnership.js +11 -8
  163. package/dist/server/DynamicToolAvailability.js +70 -0
  164. package/dist/server/createServer.js +46 -1
  165. package/dist/server/lifecycleProgress.js +10 -0
  166. package/dist/server/permissionFailure.js +12 -0
  167. package/dist/server/registerApplicationTools/compareSourceToBundle.js +35 -0
  168. package/dist/server/registerApplicationTools/helpers.js +11 -7
  169. package/dist/server/registerApplicationTools/obligationLedger.js +27 -0
  170. package/dist/server/registerApplicationTools/readiness.js +55 -0
  171. package/dist/server/registerApplicationTools.js +6 -0
  172. package/dist/server/registerArtifactTools.js +9 -1
  173. package/dist/server/registerBrowserScenarioTool.js +25 -0
  174. package/dist/server/registerBrowserTools.js +2 -2
  175. package/dist/server/registerCloseLifecycleTool.js +57 -0
  176. package/dist/server/registerEnhancedTools.js +16 -5
  177. package/dist/server/registerEvidenceResources.js +4 -0
  178. package/dist/server/registerEvidenceTools.js +9 -2
  179. package/dist/server/registerJavaScriptRuntimeObservationTools.js +37 -0
  180. package/dist/server/registerReconstructionObligationLedgerResource.js +39 -0
  181. package/dist/server/registerReconstructionReadinessResource.js +39 -0
  182. package/dist/server/registerSessionStatusTool.js +11 -8
  183. package/dist/server/registerSessionTools.js +11 -57
  184. package/dist/server/sessionAvailabilityPolicy.js +10 -8
  185. package/package.json +12 -6
  186. package/skills/reverse-engineer-anything/SKILL.md +2 -2
@@ -1,10 +1,12 @@
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, 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
6
  import { invalidEnhancedInput, } from "./EnhancedToolTypes.js";
7
7
  import { readAllAddressed } from "./EnhancedToolPagination.js";
8
+ import { traceCallPath } from "./CallPathTracing.js";
9
+ import { traceLiteralFeature } from "./EnhancedLiteralTracing.js";
8
10
  /**
9
11
  * Composes direct provider operations into bounded reverse-engineering tools.
10
12
  * Direct callers use `execute`; adapters that own validation use
@@ -17,6 +19,10 @@ export class EnhancedTools {
17
19
  }
18
20
  /** Parse an untrusted direct-call input once, then dispatch exhaustively. */
19
21
  execute(name, input, signal) {
22
+ if (name === "trace_feature" ||
23
+ name === "find_code_for_string" ||
24
+ name === "trace_call_path")
25
+ return this.#executeTracing(name, input, signal);
20
26
  switch (name) {
21
27
  case "swift_classes": {
22
28
  const parsed = enhancedInputSchemas.swift_classes.safeParse(input);
@@ -64,12 +70,6 @@ export class EnhancedTools {
64
70
  ? this.executeValidated({ name, input: parsed.data }, signal)
65
71
  : invalidEnhancedInput(name, parsed.error);
66
72
  }
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
73
  }
74
74
  }
75
75
  /** Dispatch input already parsed by a trusted adapter boundary. */
@@ -94,9 +94,27 @@ export class EnhancedTools {
94
94
  case "analyze_function":
95
95
  return this.#analyzeFunction(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
+ }
100
118
  async #analyzeFunction(input, signal) {
101
119
  const result = await this.#call("analyze_function", input, signal);
102
120
  return result.ok ? parseFunctionDossier(result.value) : result;
@@ -217,18 +235,18 @@ export class EnhancedTools {
217
235
  });
218
236
  }
219
237
  async #binaryOverview(input, signal) {
220
- const [segmentsResult, documentsResult, procedures, stringsResult] = await Promise.all([
238
+ const [segmentsResult, documentsResult, proceduresResult, stringsResult] = await Promise.all([
221
239
  this.#call("list_segments", {}, signal),
222
240
  this.#call("list_documents", {}, signal),
223
- this.#allAddressed("list_procedures", signal),
224
- this.#call("list_strings", {}, signal),
241
+ this.#call("list_procedures", { offset: 0, limit: 1 }, signal),
242
+ this.#call("list_strings", { offset: 0, limit: 1 }, signal),
225
243
  ]);
226
244
  if (!segmentsResult.ok)
227
245
  return segmentsResult;
228
246
  if (!documentsResult.ok)
229
247
  return documentsResult;
230
- if (!procedures.ok)
231
- return procedures;
248
+ if (!proceduresResult.ok)
249
+ return proceduresResult;
232
250
  if (!stringsResult.ok)
233
251
  return stringsResult;
234
252
  const segments = parseSegments(segmentsResult.value);
@@ -237,6 +255,9 @@ export class EnhancedTools {
237
255
  const documents = parseDocuments(documentsResult.value);
238
256
  if (!documents.ok)
239
257
  return documents;
258
+ const procedureCount = parseListCount(proceduresResult.value, "procedures");
259
+ if (!procedureCount.ok)
260
+ return procedureCount;
240
261
  const stringCount = parseListCount(stringsResult.value, "strings");
241
262
  if (!stringCount.ok)
242
263
  return stringCount;
@@ -249,117 +270,10 @@ export class EnhancedTools {
249
270
  ? { name, start, end, length: addressDistance(start, end) }
250
271
  : { name, start, end }),
251
272
  segment_count: segments.value.length,
252
- procedure_count: procedures.value.length,
273
+ procedure_count: procedureCount.value,
253
274
  string_count: stringCount.value,
254
275
  });
255
276
  }
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
277
  async #allAddressed(tool, signal) {
364
278
  return readAllAddressed({
365
279
  call: (name, arguments_, operationSignal) => this.#call(name, arguments_, operationSignal),
@@ -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
@@ -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
+ };
@@ -0,0 +1,147 @@
1
+ import { createJavaScriptSemanticGraphUnknown } from "../domain/javascriptSemanticGraph.js";
2
+ import { addSemanticGraphNode, addSemanticGraphRelation, addSemanticGraphUnknown, constructSemanticGraphNode, } from "./JavaScriptSemanticGraphConstruction.js";
3
+ import { unknownSemanticEvidence } from "./JavaScriptSemanticGraphEvidence.js";
4
+ import { semanticCallSiteAt, } from "./JavaScriptSemanticGraphFlowProjection.js";
5
+ /** Project literal EventEmitter registrations, removals, and dispatches. */
6
+ export const projectSemanticEvents = (context) => {
7
+ const eventNodes = new Map();
8
+ for (const operation of context.ir.eventOperations) {
9
+ const eventKey = operation.eventName === null
10
+ ? operation.eventId
11
+ : `${operation.emitterKey}\u0000${operation.eventName}`;
12
+ const event = eventNodes.get(eventKey) ?? addEventNode(context, operation, eventKey);
13
+ if (event === null)
14
+ continue;
15
+ eventNodes.set(eventKey, event);
16
+ const relation = eventRelation(operation);
17
+ if (operation.kind === "dispatch")
18
+ addSemanticGraphRelation(context.state, {
19
+ source: eventEmitterNode(context, operation),
20
+ target: event,
21
+ relation,
22
+ resolution: operation.resolution === "complete" ? "resolved" : "candidate",
23
+ });
24
+ else {
25
+ const listener = addListenerNode(context, operation);
26
+ addSemanticGraphRelation(context.state, {
27
+ source: event,
28
+ target: listener,
29
+ relation,
30
+ resolution: operation.resolution === "complete" ? "resolved" : "candidate",
31
+ });
32
+ }
33
+ if (operation.resolution !== "complete")
34
+ addEventUnknown(context, operation, event, relation);
35
+ }
36
+ };
37
+ const addEventNode = (context, operation, eventKey) => addSemanticGraphNode(context.state, constructSemanticGraphNode(context.file, {
38
+ kind: "event",
39
+ roleKey: `event:${eventKey}`,
40
+ location: operation.eventName === null ? operation.location : null,
41
+ label: operation.eventName,
42
+ functionNodeId: null,
43
+ properties: {
44
+ emitter_key: operation.emitterKey,
45
+ event_name: operation.eventName,
46
+ },
47
+ }, context.state));
48
+ const addListenerNode = (context, operation) => addSemanticGraphNode(context.state, constructSemanticGraphNode(context.file, {
49
+ kind: "listener",
50
+ roleKey: `listener:${operation.eventId}`,
51
+ location: operation.listenerLocation ?? operation.location,
52
+ label: operation.eventName === null
53
+ ? operation.method
54
+ : `${operation.method}:${operation.eventName}`,
55
+ functionNodeId: operation.ownerCallableId === null
56
+ ? null
57
+ : (context.callableNodes.get(operation.ownerCallableId)?.node_id ??
58
+ null),
59
+ properties: {
60
+ emitter_key: operation.emitterKey,
61
+ event_name: operation.eventName,
62
+ method: operation.method,
63
+ },
64
+ }, context.state));
65
+ const eventEmitterNode = (context, operation) => (operation.emitterBindingId === null
66
+ ? undefined
67
+ : context.bindingNodes.get(operation.emitterBindingId)) ??
68
+ (operation.ownerCallableId === null
69
+ ? context.moduleNode
70
+ : (context.callableNodes.get(operation.ownerCallableId) ??
71
+ context.moduleNode));
72
+ const eventRelation = (operation) => operation.kind === "register"
73
+ ? "registers-listener"
74
+ : operation.kind === "remove"
75
+ ? "removes-listener"
76
+ : "dispatches-candidate";
77
+ const addEventUnknown = (context, operation, event, relation) => {
78
+ addSemanticGraphUnknown(context.state, createJavaScriptSemanticGraphUnknown({
79
+ node_id: event.node_id,
80
+ family: "event",
81
+ relation_kinds: [relation],
82
+ reason: "ambiguous-target",
83
+ detail: operation.eventName === null
84
+ ? `Dynamic ${operation.method} event name remains unresolved.`
85
+ : `Static ${operation.method} emitter identity is partial.`,
86
+ candidate_node_ids: [],
87
+ evidence: unknownSemanticEvidence(context.file, operation.location),
88
+ }));
89
+ };
90
+ /** Project Node timer scheduling and exact local handle cancellation. */
91
+ export const projectSemanticTimers = (context) => {
92
+ const timerNodes = new Map(context.ir.timerOperations.flatMap((operation) => {
93
+ if (operation.kind !== "schedule")
94
+ return [];
95
+ const owner = operation.ownerCallableId === null
96
+ ? undefined
97
+ : context.callableNodes.get(operation.ownerCallableId);
98
+ const timer = addSemanticGraphNode(context.state, constructSemanticGraphNode(context.file, {
99
+ kind: "timer",
100
+ roleKey: operation.timerId,
101
+ location: operation.location,
102
+ label: operation.method,
103
+ functionNodeId: owner?.node_id ?? null,
104
+ properties: {
105
+ delay_milliseconds: operation.delayMilliseconds,
106
+ method: operation.method,
107
+ },
108
+ }, context.state));
109
+ return timer === null ? [] : [[operation.timerId, timer]];
110
+ }));
111
+ for (const operation of context.ir.timerOperations)
112
+ if (operation.kind === "schedule")
113
+ projectTimerSchedule(context, operation, timerNodes);
114
+ else
115
+ projectTimerCancellation(context, operation, timerNodes);
116
+ };
117
+ const projectTimerSchedule = (context, operation, timerNodes) => {
118
+ addSemanticGraphRelation(context.state, {
119
+ source: semanticCallSiteAt(context, operation.location),
120
+ target: timerNodes.get(operation.timerId),
121
+ relation: "schedules-timer",
122
+ resolution: "resolved",
123
+ });
124
+ };
125
+ const projectTimerCancellation = (context, operation, timerNodes) => {
126
+ const callSite = semanticCallSiteAt(context, operation.location);
127
+ const target = operation.linkedTimerId === null
128
+ ? undefined
129
+ : timerNodes.get(operation.linkedTimerId);
130
+ addSemanticGraphRelation(context.state, {
131
+ source: callSite,
132
+ target,
133
+ relation: "cancels-timer",
134
+ resolution: operation.resolution === "complete" ? "resolved" : "candidate",
135
+ });
136
+ if (operation.resolution === "complete")
137
+ return;
138
+ addSemanticGraphUnknown(context.state, createJavaScriptSemanticGraphUnknown({
139
+ node_id: callSite?.node_id ?? null,
140
+ family: "timer",
141
+ relation_kinds: ["cancels-timer"],
142
+ reason: "ambiguous-target",
143
+ detail: `Static ${operation.method} handle resolution was ${operation.resolution}.`,
144
+ candidate_node_ids: [],
145
+ evidence: unknownSemanticEvidence(context.file, operation.location),
146
+ }));
147
+ };
@@ -1,16 +1,25 @@
1
1
  import { createJavaScriptSemanticGraph, } from "../domain/javascriptSemanticGraph.js";
2
2
  import { JAVASCRIPT_SEMANTIC_RELATION_FAMILIES, JAVASCRIPT_SEMANTIC_RELATION_FAMILY, } from "../domain/javascriptSemanticGraphSchemas.js";
3
+ import { sourceRangesEqual as rangesEqual } from "../domain/javascriptStaticAnalysisHelpers.js";
4
+ import { projectSemanticEvents, projectSemanticTimers, } from "./JavaScriptSemanticGraphAsyncProjection.js";
5
+ import { projectSemanticChildProcesses } from "./JavaScriptSemanticGraphChildProcessProjection.js";
6
+ import { projectSemanticBoundaries, projectSemanticConfiguration, projectSemanticRequests, } from "./JavaScriptSemanticGraphDataProjection.js";
7
+ import { projectSemanticResources } from "./JavaScriptSemanticGraphResourceProjection.js";
8
+ import { projectSemanticObjects } from "./JavaScriptSemanticGraphObjectProjection.js";
9
+ import { projectSemanticValues } from "./JavaScriptSemanticGraphValueProjection.js";
3
10
  import { inferredSemanticEvidenceAt } from "./JavaScriptSemanticGraphEvidence.js";
4
- import { projectSemanticClosureCaptures, projectSemanticFrontiers, projectSemanticReturnValues, semanticRecoveryLimits, } from "./JavaScriptSemanticGraphFlowProjection.js";
5
- import { owningSemanticCallableNode, semanticFamilyStatus, semanticNodesWithinRange, semanticRangesEqual as rangesEqual, } from "./JavaScriptSemanticGraphProjection.js";
11
+ import { projectSemanticFunctionFingerprints } from "./JavaScriptSemanticGraphFingerprintProjection.js";
12
+ import { projectSemanticClosureCaptures, projectSemanticFrontiers, projectSemanticPromises, projectSemanticReturnValues, semanticRecoveryLimits, } from "./JavaScriptSemanticGraphFlowProjection.js";
13
+ import { owningSemanticCallableNode, semanticFamilyStatus, semanticNodesWithinRange, } from "./JavaScriptSemanticGraphProjection.js";
6
14
  import { addSemanticFallbackRoot as addFallbackRoot, addSemanticGraphNode as addNode, addSemanticGraphRelation as addRelation, constructSemanticGraphNode as semanticNode, createSemanticGraphProjectionState as emptyState, MAX_APPLICATION_NODE_IDS_PER_SEMANTIC_NODE, MAX_SEMANTIC_GRAPH_NODES, MAX_SEMANTIC_GRAPH_RELATIONS, MAX_SEMANTIC_GRAPH_UNKNOWNS, } from "./JavaScriptSemanticGraphConstruction.js";
7
15
  /** Project bounded per-file semantic IR into an artifact-bound companion graph. */
8
16
  export const buildJavaScriptSemanticGraph = ({ rootArtifactSha256, applicationGraph, analysis, }) => {
9
17
  const state = emptyState(applicationGraph);
18
+ const fingerprints = [];
10
19
  for (const analyzed of analysis.files) {
11
20
  if (analyzed.semantic === null)
12
21
  continue;
13
- projectFile(analyzed.file, analyzed.semantic.ir, state);
22
+ fingerprints.push(...projectFile(analyzed.file, analyzed.semantic.ir, state));
14
23
  }
15
24
  if (state.roots.size === 0)
16
25
  addFallbackRoot(rootArtifactSha256, state);
@@ -25,7 +34,7 @@ export const buildJavaScriptSemanticGraph = ({ rootArtifactSha256, applicationGr
25
34
  root_node_ids: [...state.roots],
26
35
  nodes: [...state.nodes.values()],
27
36
  relations: [...state.relations.values()],
28
- fingerprints: [],
37
+ fingerprints,
29
38
  unknowns,
30
39
  coverage: {
31
40
  status: truncated ? "partial" : "unknown",
@@ -68,7 +77,15 @@ export const buildJavaScriptSemanticGraph = ({ rootArtifactSha256, applicationGr
68
77
  limitations: [
69
78
  "The semantic graph contains static syntax observations and conservative relationship candidates; it does not claim runtime execution.",
70
79
  "Local data flow does not claim control-flow-sensitive reaching definitions or arbitrary dynamic property resolution.",
71
- "Function fingerprints and promise, event, process, request, boundary, timer, configuration, and resource extraction are not available in this graph version's current extractor coverage.",
80
+ "Promise ownership covers explicit unshadowed Promise construction, static factories, aggregation, chaining, and await syntax only.",
81
+ "Function fingerprints are bounded static candidates; equal digests can remain ambiguous and do not prove behavioral equivalence.",
82
+ "Event extraction covers EventEmitter-style literal registrations, removals, and dispatch candidates; dynamic names remain unknown.",
83
+ "Timer extraction covers global or node:timers scheduling and exact local-handle cancellation.",
84
+ "Child-process extraction covers asynchronous node:child_process creation, literal argv/env/stdio options, exit/error listeners, and kill signals.",
85
+ "Configuration extraction covers process.env, process.argv, node:fs reads, and direct logical defaults.",
86
+ "Request extraction covers fetch, WebSocket, node:http/node:https construction, direct option fields, and exact local response consumers.",
87
+ "Boundary extraction covers unshadowed JSON/global coercions plus parse and validation method candidates.",
88
+ "Resource extraction covers built-in filesystem/network acquisition and exact local close/destroy/end handles.",
72
89
  ...(truncated
73
90
  ? [
74
91
  "Semantic graph projection reached one or more explicit hard limits.",
@@ -86,7 +103,7 @@ const projectFile = (file, ir, state) => {
86
103
  functionNodeId: null,
87
104
  }, state));
88
105
  if (moduleNode === null)
89
- return;
106
+ return [];
90
107
  state.roots.add(moduleNode.node_id);
91
108
  const callableNodes = new Map(ir.callables.flatMap((callable) => {
92
109
  const node = addNode(state, semanticNode(file, {
@@ -130,9 +147,20 @@ const projectFile = (file, ir, state) => {
130
147
  ])),
131
148
  };
132
149
  projectDefinitionsAndReferences(context);
150
+ projectSemanticValues(context);
151
+ projectSemanticObjects(context);
133
152
  projectCalls(context);
153
+ projectSemanticPromises(context);
154
+ projectSemanticEvents(context);
155
+ projectSemanticTimers(context);
156
+ projectSemanticChildProcesses(context);
157
+ projectSemanticConfiguration(context);
158
+ projectSemanticRequests(context);
159
+ projectSemanticBoundaries(context);
160
+ projectSemanticResources(context);
134
161
  projectSemanticClosureCaptures(context);
135
162
  projectSemanticFrontiers(context);
163
+ return projectSemanticFunctionFingerprints(file, ir, callableNodes);
136
164
  };
137
165
  const createReturnSiteNodes = (file, ir, callables, state) => {
138
166
  const result = new Map();