rea-agents 1.6.0 → 2.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 (238) hide show
  1. package/README.md +157 -66
  2. package/bridge/ghidra/ReaGhidraBridge.java +2075 -0
  3. package/bridge/hopper_bridge.py +13 -3
  4. package/dist/application/AbortablePromise.js +25 -0
  5. package/dist/application/AnalysisProvider.js +3 -0
  6. package/dist/application/AnalysisProviderEvaluation.js +60 -0
  7. package/dist/application/AnalysisProviderRegistry.js +228 -0
  8. package/dist/application/AnalysisSnapshotCache.js +41 -21
  9. package/dist/application/AnalysisSnapshotFiles.js +5 -6
  10. package/dist/application/BinarySession.js +218 -101
  11. package/dist/application/CapabilityInventory.js +18 -0
  12. package/dist/application/CompositeProvider.js +20 -8
  13. package/dist/application/CrossVersionInvestigation.js +10 -6
  14. package/dist/application/DirectAnalysis.js +49 -35
  15. package/dist/application/Doctor.js +110 -8
  16. package/dist/application/ElectronBoundaryAnalysis.js +96 -0
  17. package/dist/application/ElectronBoundaryGraph.js +9 -0
  18. package/dist/application/ElectronBoundaryGraphContext.js +62 -0
  19. package/dist/application/ElectronBoundaryGraphIpc.js +242 -0
  20. package/dist/application/ElectronBoundaryGraphNative.js +86 -0
  21. package/dist/application/ElectronBoundaryGraphWindows.js +199 -0
  22. package/dist/application/EnhancedTools.js +39 -14
  23. package/dist/application/InvestigationProviders.js +41 -0
  24. package/dist/application/JavaScriptApplicationEvidence.js +26 -0
  25. package/dist/application/JavaScriptApplicationEvidenceGraph.js +89 -0
  26. package/dist/application/JavaScriptApplicationService.js +74 -0
  27. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +29 -0
  28. package/dist/application/JavaScriptApplicationWorkflowService.js +90 -0
  29. package/dist/application/JavaScriptArtifactAnalysis.js +305 -0
  30. package/dist/application/JavaScriptArtifactAnalysisTypes.js +1 -0
  31. package/dist/application/JavaScriptArtifactFiles.js +231 -0
  32. package/dist/application/JavaScriptArtifactGraphAccumulator.js +54 -0
  33. package/dist/application/JavaScriptArtifactGraphBuilder.js +144 -0
  34. package/dist/application/JavaScriptArtifactGraphContext.js +205 -0
  35. package/dist/application/JavaScriptArtifactGraphDocuments.js +108 -0
  36. package/dist/application/JavaScriptArtifactGraphEvidence.js +99 -0
  37. package/dist/application/JavaScriptArtifactGraphFindings.js +271 -0
  38. package/dist/application/JavaScriptArtifactGraphStructure.js +409 -0
  39. package/dist/application/JavaScriptArtifactReconstruction.js +77 -0
  40. package/dist/application/JavaScriptArtifactReconstructionInput.js +18 -0
  41. package/dist/application/JavaScriptReplayPlanning.js +201 -0
  42. package/dist/application/JavaScriptReplayService.js +266 -0
  43. package/dist/application/JavaScriptRuntimeReconciliationEvidence.js +25 -0
  44. package/dist/application/JavaScriptRuntimeReconciliationService.js +27 -0
  45. package/dist/application/MacHopper.js +20 -4
  46. package/dist/application/ManagedApplicationGraphService.js +55 -0
  47. package/dist/application/ManagedMemberComparisonService.js +122 -0
  48. package/dist/application/ManagedNativeVerificationService.js +39 -0
  49. package/dist/application/ManagedReconstructionService.js +58 -0
  50. package/dist/application/ManagedRuntimeCorrelationService.js +103 -0
  51. package/dist/application/PermissionAuthority.js +1 -1
  52. package/dist/application/ProcessCaptureLifecycle.js +1 -1
  53. package/dist/application/ProcessHarness.js +1 -1
  54. package/dist/application/ProcessSampling.js +16 -12
  55. package/dist/application/ProjectPermissionStore.js +1 -0
  56. package/dist/application/SessionProviderRouter.js +219 -0
  57. package/dist/application/Setup.js +84 -60
  58. package/dist/application/SetupClients.js +1 -1
  59. package/dist/application/SetupPlan.js +9 -2
  60. package/dist/application/SupportedClients.js +40 -16
  61. package/dist/application/Upgrade.js +1 -1
  62. package/dist/application/runtime.js +11 -6
  63. package/dist/artifacts/AsarArtifactReader.js +23 -3
  64. package/dist/browser/CdpBrowserProvider.js +4 -2
  65. package/dist/browser/CdpCaptureEvents.js +49 -0
  66. package/dist/browser/CdpElectronInspection.js +106 -162
  67. package/dist/browser/CdpElectronProvider.js +9 -3
  68. package/dist/browser/CdpElectronScriptEvents.js +69 -0
  69. package/dist/browser/CdpElectronScripts.js +94 -0
  70. package/dist/browser/CdpElectronWorkers.js +56 -0
  71. package/dist/browser/CdpEndpoint.js +14 -1
  72. package/dist/browser/CdpPageCapture.js +8 -4
  73. package/dist/catalogIdentity.js +6 -42
  74. package/dist/cli.js +446 -34
  75. package/dist/cliApplicationCommands.js +62 -0
  76. package/dist/cliBrowserAdvancedCommands.js +5 -4
  77. package/dist/cliBrowserCommands.js +5 -4
  78. package/dist/cliCommandNames.js +56 -0
  79. package/dist/cliElectronCommands.js +106 -3
  80. package/dist/cliEvidenceCommands.js +4 -3
  81. package/dist/cliInvestigationCommands.js +2 -1
  82. package/dist/cliJsonInput.js +54 -0
  83. package/dist/cliPolicyCommands.js +2 -1
  84. package/dist/cliProcessCommands.js +3 -2
  85. package/dist/config.js +101 -2
  86. package/dist/contracts/applicationToolContracts.js +91 -0
  87. package/dist/contracts/artifactToolContracts.js +5 -9
  88. package/dist/contracts/browserToolContracts.js +14 -62
  89. package/dist/contracts/electronToolContracts.js +45 -19
  90. package/dist/contracts/enhancedInputs.js +2 -2
  91. package/dist/contracts/errorSchemas.js +1 -0
  92. package/dist/contracts/investigationExamples.js +0 -6
  93. package/dist/contracts/javascriptApplicationWorkflowExamples.js +46 -0
  94. package/dist/contracts/javascriptRuntimeReconciliationExample.js +208 -0
  95. package/dist/contracts/managedToolContracts.js +153 -0
  96. package/dist/contracts/managedWorkflowExamples.js +346 -0
  97. package/dist/contracts/managedWorkflowToolContracts.js +203 -0
  98. package/dist/contracts/nativeToolContracts.js +2 -6
  99. package/dist/contracts/promptContracts.js +18 -2
  100. package/dist/contracts/providerSelection.js +28 -0
  101. package/dist/contracts/sessionLifecycleInputs.js +2 -0
  102. package/dist/contracts/toolContractExamples.js +10 -25
  103. package/dist/contracts/toolContracts.js +69 -65
  104. package/dist/contracts/toolEffects.js +160 -0
  105. package/dist/contracts/toolOutputSchemas.js +152 -42
  106. package/dist/doctorRuntime.js +47 -0
  107. package/dist/domain/analysisProfile.js +78 -0
  108. package/dist/domain/analysisSnapshot.js +92 -46
  109. package/dist/domain/artifactComparison.js +3 -4
  110. package/dist/domain/artifactGraph.js +1 -0
  111. package/dist/domain/binaryTarget.js +4 -29
  112. package/dist/domain/browserObservation.js +3 -0
  113. package/dist/domain/bundleComparison.js +4 -4
  114. package/dist/domain/electronObservation.js +13 -0
  115. package/dist/domain/electronStaticAnalysis.js +9 -0
  116. package/dist/domain/electronStaticAnalysisBrowser.js +194 -0
  117. package/dist/domain/electronStaticAnalysisIpc.js +171 -0
  118. package/dist/domain/electronStaticAnalysisNative.js +164 -0
  119. package/dist/domain/electronStaticAnalysisTypes.js +1 -0
  120. package/dist/domain/electronStaticAnalysisValues.js +103 -0
  121. package/dist/domain/errors.js +148 -7
  122. package/dist/domain/evidence.js +44 -5
  123. package/dist/domain/evidenceBundle.js +9 -7
  124. package/dist/domain/functionComparison.js +9 -3
  125. package/dist/domain/functionComparisonNormalization.js +37 -0
  126. package/dist/domain/functionComparisonSchemas.js +3 -8
  127. package/dist/domain/functionDossierEvidence.js +4 -1
  128. package/dist/domain/hopperValues.js +66 -9
  129. package/dist/domain/inputIssueProjection.js +52 -0
  130. package/dist/domain/investigationWorkspace.js +2 -1
  131. package/dist/domain/javascriptApplicationAnalysis.js +155 -0
  132. package/dist/domain/javascriptApplicationChangeGraph.js +231 -0
  133. package/dist/domain/javascriptApplicationEvidenceSchemas.js +379 -0
  134. package/dist/domain/javascriptApplicationGraph.js +282 -0
  135. package/dist/domain/javascriptApplicationGraphSchemas.js +139 -0
  136. package/dist/domain/javascriptApplicationVersionComparison.js +116 -0
  137. package/dist/domain/javascriptApplicationVersionComparisonSchemas.js +139 -0
  138. package/dist/domain/javascriptApplicationVersionItems.js +221 -0
  139. package/dist/domain/javascriptApplicationVersionKeys.js +170 -0
  140. package/dist/domain/javascriptAstFingerprint.js +143 -0
  141. package/dist/domain/javascriptFeatureSeed.js +140 -0
  142. package/dist/domain/javascriptFeatureTrace.js +232 -0
  143. package/dist/domain/javascriptFeatureTraceSchemas.js +136 -0
  144. package/dist/domain/javascriptFeatureTraversal.js +88 -0
  145. package/dist/domain/javascriptNativeHandoff.js +85 -0
  146. package/dist/domain/javascriptReplay.js +361 -0
  147. package/dist/domain/javascriptRuntimeLoadState.js +106 -0
  148. package/dist/domain/javascriptRuntimeReconciliation.js +42 -0
  149. package/dist/domain/javascriptRuntimeReconciliationGraph.js +169 -0
  150. package/dist/domain/javascriptRuntimeReconciliationMatching.js +247 -0
  151. package/dist/domain/javascriptRuntimeReconciliationParsing.js +160 -0
  152. package/dist/domain/javascriptRuntimeReconciliationResult.js +119 -0
  153. package/dist/domain/javascriptRuntimeReconciliationRuntime.js +316 -0
  154. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +245 -0
  155. package/dist/domain/javascriptRuntimeStaticCandidates.js +191 -0
  156. package/dist/domain/javascriptStaticAnalysis.js +346 -0
  157. package/dist/domain/javascriptStaticAnalysisFindings.js +39 -0
  158. package/dist/domain/javascriptStaticAnalysisHelpers.js +274 -0
  159. package/dist/domain/javascriptStaticAnalysisState.js +23 -0
  160. package/dist/domain/javascriptStaticAnalysisTypes.js +1 -0
  161. package/dist/domain/managedApplicationGraph.js +556 -0
  162. package/dist/domain/managedArtifact.js +444 -0
  163. package/dist/domain/managedMemberComparison.js +565 -0
  164. package/dist/domain/managedNativeVerification.js +408 -0
  165. package/dist/domain/managedReconstruction.js +183 -0
  166. package/dist/domain/managedRuntimeCorrelation.js +175 -0
  167. package/dist/domain/reconstructionVerificationSchemas.js +1 -3
  168. package/dist/dotnet/ManagedArtifactInspector.js +318 -0
  169. package/dist/dotnet/ManagedMemberInspector.js +887 -0
  170. package/dist/dotnet/ManagedMetadataHeaps.js +131 -0
  171. package/dist/dotnet/ManagedMetadataInventory.js +368 -0
  172. package/dist/dotnet/ManagedMetadataLayout.js +322 -0
  173. package/dist/dotnet/ManagedNativeBoundaryInspector.js +391 -0
  174. package/dist/dotnet/ManagedPeReader.js +157 -0
  175. package/dist/dotnet/ManagedReaderFailure.js +10 -0
  176. package/dist/dotnet/ManagedStaticProvider.js +203 -0
  177. package/dist/generatedPackageMetadata.js +2 -2
  178. package/dist/ghidra/GhidraAnalysisProfile.js +37 -0
  179. package/dist/ghidra/GhidraClient.js +400 -0
  180. package/dist/ghidra/GhidraClientTypes.js +1 -0
  181. package/dist/ghidra/GhidraDefaults.js +20 -0
  182. package/dist/ghidra/GhidraDiagnostics.js +43 -0
  183. package/dist/ghidra/GhidraDoctor.js +59 -0
  184. package/dist/ghidra/GhidraFunctionValues.js +264 -0
  185. package/dist/ghidra/GhidraInstallation.js +239 -0
  186. package/dist/ghidra/GhidraInventoryValues.js +217 -0
  187. package/dist/ghidra/GhidraLauncher.js +139 -0
  188. package/dist/ghidra/GhidraProvider.js +366 -0
  189. package/dist/ghidra/GhidraRequestQueue.js +98 -0
  190. package/dist/ghidra/GhidraResponseBuffer.js +31 -0
  191. package/dist/ghidra/GhidraResponseRouter.js +24 -0
  192. package/dist/ghidra/GhidraSessionError.js +39 -0
  193. package/dist/ghidra/GhidraSessionValues.js +62 -0
  194. package/dist/ghidra/GhidraSocketConnection.js +46 -0
  195. package/dist/ghidra/protocol.js +69 -0
  196. package/dist/hopper/BridgeLauncher.js +19 -54
  197. package/dist/hopper/HopperAnalysisProfile.js +106 -0
  198. package/dist/hopper/HopperClient.js +154 -162
  199. package/dist/hopper/HopperProvider.js +99 -7
  200. package/dist/hopper/HopperSessionValues.js +27 -0
  201. package/dist/hopper/HopperSocketConnection.js +31 -0
  202. package/dist/main.js +14 -0
  203. package/dist/native/NativeMacOSProvider.js +3 -1
  204. package/dist/process/PendingOperations.js +59 -0
  205. package/dist/process/PrivateRuntimeRoot.js +33 -0
  206. package/dist/process/ProviderDeadline.js +95 -0
  207. package/dist/process/ProviderProcess.js +275 -0
  208. package/dist/replay/JavaScriptReplayWorker.js +286 -0
  209. package/dist/replay/LinuxJavaScriptReplayRunner.js +434 -0
  210. package/dist/replay/LinuxRuntimeClosure.js +46 -0
  211. package/dist/replay/LinuxSeccompPolicy.js +40 -0
  212. package/dist/replay/ReplayWorkerProtocol.js +55 -0
  213. package/dist/replay/SystemJavaScriptReplayHost.js +182 -0
  214. package/dist/server/createServer.js +53 -0
  215. package/dist/server/promptCompletion.js +9 -3
  216. package/dist/server/registerApplicationTools.js +115 -0
  217. package/dist/server/registerArtifactComparisonTool.js +16 -9
  218. package/dist/server/registerBrowserTools.js +33 -8
  219. package/dist/server/registerBundleComparisonTool.js +17 -20
  220. package/dist/server/registerElectronTools.js +45 -3
  221. package/dist/server/registerEnhancedTools.js +67 -19
  222. package/dist/server/registerEvidenceTools.js +5 -1
  223. package/dist/server/registerFunctionComparisonTool.js +14 -7
  224. package/dist/server/registerInvestigationTools.js +21 -17
  225. package/dist/server/registerManagedTools.js +6 -0
  226. package/dist/server/registerManagedWorkflowTools.js +277 -0
  227. package/dist/server/registerOfficialTools.js +11 -8
  228. package/dist/server/registerProcessComparisonTool.js +25 -47
  229. package/dist/server/registerSessionStatusTool.js +7 -7
  230. package/dist/server/registerSessionTools.js +57 -87
  231. package/dist/server/sessionEvidence.js +14 -19
  232. package/dist/server/toolInputValidation.js +77 -0
  233. package/dist/server/toolRegistrationOptions.js +79 -2
  234. package/dist/server/toolResult.js +25 -17
  235. package/package.json +17 -7
  236. package/scripts/rea.mjs +36 -2
  237. package/skills/rea-analysis/SKILL.md +59 -3
  238. /package/dist/{application → process}/ProcessOwnership.js +0 -0
@@ -0,0 +1,52 @@
1
+ /** Project Zod failures to secret-safe caller correction metadata. */
2
+ export const projectInputIssues = (issues, input) => issues.flatMap((issue) => projectIssue(issue, input));
3
+ const projectIssue = (issue, input) => {
4
+ const path = issue.path.flatMap((part) => typeof part === "string" || typeof part === "number" ? [part] : []);
5
+ if (issue.code === "unrecognized_keys")
6
+ return issue.keys.map((key) => ({
7
+ path: [...path, key],
8
+ reason: "unknown_argument",
9
+ }));
10
+ if (issue.code === "invalid_type")
11
+ return [
12
+ {
13
+ path,
14
+ reason: valueAtPath(input, path) === undefined
15
+ ? "missing_argument"
16
+ : "invalid_type",
17
+ expected: safeExpected(issue.expected),
18
+ },
19
+ ];
20
+ if (issue.code === "too_small")
21
+ return [boundedIssue(path, "minimum", numericBound(issue.minimum))];
22
+ if (issue.code === "too_big")
23
+ return [boundedIssue(path, "maximum", numericBound(issue.maximum))];
24
+ if (issue.code === "invalid_format")
25
+ return [{ path, reason: "invalid_format", expected: issue.format }];
26
+ if (issue.code === "invalid_value")
27
+ return [
28
+ {
29
+ path,
30
+ reason: "invalid_value",
31
+ expected: issue.values.filter(isSafeExpected),
32
+ },
33
+ ];
34
+ return [{ path, reason: "invalid_value" }];
35
+ };
36
+ const valueAtPath = (input, path) => {
37
+ let current = input;
38
+ for (const part of path) {
39
+ if (typeof current !== "object" || current === null)
40
+ return undefined;
41
+ current = current[part];
42
+ }
43
+ return current;
44
+ };
45
+ const numericBound = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
46
+ const isSafeExpected = (value) => value === null || ["string", "number", "boolean"].includes(typeof value);
47
+ const safeExpected = (value) => isSafeExpected(value) ? value : "schema-defined value";
48
+ const boundedIssue = (path, key, value) => ({
49
+ path,
50
+ reason: "out_of_range",
51
+ ...(value === undefined ? {} : { [key]: value }),
52
+ });
@@ -125,7 +125,8 @@ export const investigationRunSummarySchema = z.object({
125
125
  comparison_evidence_id: evidenceIdSchema,
126
126
  limitations: z.array(z.string().max(4_096)).max(100),
127
127
  });
128
- const investigationWorkspaceSchema = z.object({
128
+ /** Durable schema for one revisioned cross-version investigation workspace. */
129
+ export const investigationWorkspaceSchema = z.object({
129
130
  workspace_version: z.literal(1),
130
131
  workspace_id: z.string().regex(/^ws_[a-f0-9]{64}$/u),
131
132
  name: z.string().trim().min(1).max(200),
@@ -0,0 +1,155 @@
1
+ import { isAbsolute } from "node:path";
2
+ import { z } from "zod";
3
+ import { javascriptApplicationGraphSchema } from "./javascriptApplicationGraph.js";
4
+ const MAX_GRAPH_NODES = 100_000;
5
+ const MAX_GRAPH_EDGES = 200_000;
6
+ const countSchema = z.number().int().min(0).max(Number.MAX_SAFE_INTEGER);
7
+ const digestSchema = z.string().regex(/^[a-f0-9]{64}$/u);
8
+ /** Default hard bounds for one local JavaScript application analysis. */
9
+ export const JAVASCRIPT_APPLICATION_ANALYSIS_DEFAULT_LIMITS = {
10
+ max_entries: 8_000,
11
+ max_total_artifact_bytes: 512 * 1_024 * 1_024,
12
+ max_artifact_entry_bytes: 128 * 1_024 * 1_024,
13
+ max_compression_ratio: 1_000,
14
+ max_depth: 64,
15
+ max_path_bytes: 4_096,
16
+ max_text_files: 5_000,
17
+ max_total_text_bytes: 128 * 1_024 * 1_024,
18
+ max_text_file_bytes: 8 * 1_024 * 1_024,
19
+ max_ast_nodes: 2_000_000,
20
+ max_findings: 8_000,
21
+ max_modules: 20_000,
22
+ max_source_map_sources: 5_000,
23
+ max_parse_milliseconds: 30_000,
24
+ };
25
+ /** Combined artifact, text, AST, and graph projection bounds. */
26
+ export const javascriptApplicationAnalysisLimitsSchema = z
27
+ .strictObject({
28
+ max_entries: z.number().int().min(1).max(1_000_000).default(8_000),
29
+ max_total_artifact_bytes: z
30
+ .number()
31
+ .int()
32
+ .min(1)
33
+ .max(Number.MAX_SAFE_INTEGER)
34
+ .default(512 * 1_024 * 1_024),
35
+ max_artifact_entry_bytes: z
36
+ .number()
37
+ .int()
38
+ .min(1)
39
+ .max(Number.MAX_SAFE_INTEGER)
40
+ .default(128 * 1_024 * 1_024),
41
+ max_compression_ratio: z.number().min(1).max(100_000).default(1_000),
42
+ max_depth: z.number().int().min(1).max(100).default(64),
43
+ max_path_bytes: z.number().int().min(1).max(65_535).default(4_096),
44
+ max_text_files: z.number().int().min(1).max(100_000).default(5_000),
45
+ max_total_text_bytes: z
46
+ .number()
47
+ .int()
48
+ .min(1)
49
+ .max(512 * 1_024 * 1_024)
50
+ .default(128 * 1_024 * 1_024),
51
+ max_text_file_bytes: z
52
+ .number()
53
+ .int()
54
+ .min(1)
55
+ .max(64 * 1_024 * 1_024)
56
+ .default(8 * 1_024 * 1_024),
57
+ max_ast_nodes: z.number().int().min(1).max(20_000_000).default(2_000_000),
58
+ max_findings: z.number().int().min(1).max(200_000).default(8_000),
59
+ max_modules: z.number().int().min(1).max(100_000).default(20_000),
60
+ max_source_map_sources: z.number().int().min(1).max(100_000).default(5_000),
61
+ max_parse_milliseconds: z
62
+ .number()
63
+ .int()
64
+ .min(1)
65
+ .max(300_000)
66
+ .default(30_000),
67
+ })
68
+ .superRefine((limits, context) => {
69
+ const projectedNodes = 7 * limits.max_entries +
70
+ 2 * limits.max_findings +
71
+ limits.max_modules +
72
+ limits.max_source_map_sources +
73
+ 1;
74
+ if (projectedNodes > MAX_GRAPH_NODES)
75
+ context.addIssue({
76
+ code: "custom",
77
+ path: ["max_entries"],
78
+ message: "Combined application-analysis limits can exceed the 100000-node graph contract",
79
+ });
80
+ const projectedEdges = 9 * limits.max_entries +
81
+ 6 * limits.max_findings +
82
+ limits.max_modules +
83
+ limits.max_source_map_sources;
84
+ if (projectedEdges > MAX_GRAPH_EDGES)
85
+ context.addIssue({
86
+ code: "custom",
87
+ path: ["max_entries"],
88
+ message: "Combined application-analysis limits can exceed the 200000-edge graph contract",
89
+ });
90
+ });
91
+ /** Public target-free request for bounded static JavaScript application analysis. */
92
+ export const analyzeJavaScriptApplicationInputSchema = z.strictObject({
93
+ input_path: z
94
+ .string()
95
+ .min(1)
96
+ .max(16_384)
97
+ .refine(isAbsolute, "JavaScript application input path must be absolute"),
98
+ format: z.enum(["auto", "asar", "directory"]).default("auto"),
99
+ approved: z.literal(true),
100
+ source_map_read_approved: z.boolean().default(false),
101
+ limits: javascriptApplicationAnalysisLimitsSchema.default(JAVASCRIPT_APPLICATION_ANALYSIS_DEFAULT_LIMITS),
102
+ });
103
+ /** Compact counts for the high-level Electron architecture/security surface. */
104
+ const electronBoundarySummarySchema = z.strictObject({
105
+ browser_windows: countSchema,
106
+ explicit_web_preferences: countSchema,
107
+ preload_entrypoints: countSchema,
108
+ context_bridge_apis: countSchema,
109
+ exposed_api_members: countSchema,
110
+ ipc: z.strictObject({
111
+ operations: countSchema,
112
+ literal_channels: countSchema,
113
+ dynamic_channel_operations: countSchema,
114
+ renderer_transmissions: countSchema,
115
+ renderer_listeners: countSchema,
116
+ main_handlers: countSchema,
117
+ paired_renderer_transmissions: countSchema,
118
+ ambiguous_renderer_transmissions: countSchema,
119
+ unpaired_literal_renderer_transmissions: countSchema,
120
+ }),
121
+ sender_validation_observations: countSchema,
122
+ utility_processes: countSchema,
123
+ resolved_utility_entrypoints: countSchema,
124
+ native_addon_bindings: countSchema,
125
+ resolved_native_addon_bindings: countSchema,
126
+ });
127
+ const reconstructionStatisticsSchema = z.strictObject({
128
+ relevant_files: countSchema,
129
+ nested_asar_containers: countSchema,
130
+ text_files_selected: countSchema,
131
+ text_bytes_read: countSchema,
132
+ omitted_text_files: countSchema,
133
+ limit_omitted_text_files: countSchema,
134
+ policy_filtered_text_files: countSchema,
135
+ invalid_utf8_files: countSchema,
136
+ parsed_javascript_files: countSchema,
137
+ visited_ast_nodes: countSchema,
138
+ findings: countSchema,
139
+ modules: countSchema,
140
+ parse_failures: countSchema,
141
+ truncated_scopes: countSchema,
142
+ });
143
+ /** Strict high-level result returned inside Evidence v2. */
144
+ export const javascriptApplicationAnalysisResultSchema = z.strictObject({
145
+ schema_version: z.literal(1),
146
+ input_path: z.string().min(1).max(16_384),
147
+ format: z.enum(["asar", "directory"]),
148
+ root_artifact_sha256: digestSchema,
149
+ inventory_manifest_id: z.string().regex(/^agm_[a-f0-9]{64}$/u),
150
+ inventory_graph_sha256: digestSchema,
151
+ graph: javascriptApplicationGraphSchema,
152
+ summary: electronBoundarySummarySchema,
153
+ statistics: reconstructionStatisticsSchema,
154
+ limitations: z.array(z.string().min(1).max(4_096)).max(1_000),
155
+ });
@@ -0,0 +1,231 @@
1
+ import { compareCodePoints, createJavaScriptApplicationEdge, createJavaScriptApplicationGraph, createJavaScriptApplicationNode, } from "./javascriptApplicationGraph.js";
2
+ /** Merge compared nodes and add inferred right-to-left changed_from edges. */
3
+ export const buildJavaScriptApplicationChangeGraph = (input) => {
4
+ const allNodes = nodeCandidates(input);
5
+ const preferredRoots = uniqueSorted([
6
+ ...input.right.root_node_ids,
7
+ ...input.left.root_node_ids,
8
+ ]).filter((nodeId) => allNodes.has(nodeId));
9
+ const orderedNodeIds = uniqueSorted([
10
+ ...preferredRoots,
11
+ ...input.items.flatMap(({ left_node_id: left, right_node_id: right }) => [
12
+ ...(right === null ? [] : [right]),
13
+ ...(left === null ? [] : [left]),
14
+ ]),
15
+ ]);
16
+ const retainedIds = orderedNodeIds.slice(0, input.limits.max_graph_nodes);
17
+ const retained = new Set(retainedIds);
18
+ const merged = mergeNodes(retainedIds.flatMap((nodeId) => allNodes.get(nodeId) ?? []));
19
+ const sourceEdges = uniqueEdges([
20
+ ...input.left.edges,
21
+ ...input.right.edges,
22
+ ]).filter(({ source_node_id: source, target_node_id: target }) => retained.has(source) && retained.has(target));
23
+ const comparisonEdges = input.items.flatMap((item) => changedFromEdge(item, input, retained));
24
+ const candidateEdges = uniqueEdges([...sourceEdges, ...comparisonEdges]);
25
+ const edges = candidateEdges.slice(0, input.limits.max_graph_edges);
26
+ const omittedNodes = Math.max(0, orderedNodeIds.length - retainedIds.length);
27
+ const omittedEdges = Math.max(0, candidateEdges.length - edges.length);
28
+ const graphOmissions = omittedNodes + omittedEdges + merged.omittedObservations;
29
+ const rootNodeIds = preferredRoots
30
+ .filter((nodeId) => retained.has(nodeId))
31
+ .slice(0, 1_000);
32
+ const fallbackRoot = merged.nodes[0]?.node_id;
33
+ const graph = createJavaScriptApplicationGraph({
34
+ schema: "JavaScriptApplicationGraph",
35
+ schema_version: 1,
36
+ root_node_ids: rootNodeIds.length > 0
37
+ ? rootNodeIds
38
+ : fallbackRoot === undefined
39
+ ? []
40
+ : [fallbackRoot],
41
+ nodes: merged.nodes,
42
+ edges,
43
+ coverage: changeGraphCoverage(input, graphOmissions),
44
+ limitations: uniqueSorted([
45
+ ...input.left.limitations.map((value) => `Left: ${value}`),
46
+ ...input.right.limitations.map((value) => `Right: ${value}`),
47
+ "changed_from edges are cross-version inferences and never promote structural or semantic matches to exact identity.",
48
+ "The change graph contains compared entities and their retained relationships; it is not an executable application.",
49
+ ...(graphOmissions === 0
50
+ ? []
51
+ : ["The change graph omitted content at explicit caller bounds."]),
52
+ ]),
53
+ });
54
+ return {
55
+ graph,
56
+ omittedNodes,
57
+ omittedEdges,
58
+ omittedObservations: merged.omittedObservations,
59
+ };
60
+ };
61
+ const nodeCandidates = (input) => {
62
+ const required = new Set([
63
+ ...input.left.root_node_ids,
64
+ ...input.right.root_node_ids,
65
+ ...input.items.flatMap(({ left_node_id: left, right_node_id: right }) => [
66
+ ...(left === null ? [] : [left]),
67
+ ...(right === null ? [] : [right]),
68
+ ]),
69
+ ]);
70
+ const output = new Map();
71
+ for (const node of [...input.left.nodes, ...input.right.nodes])
72
+ if (required.has(node.node_id))
73
+ output.set(node.node_id, [...(output.get(node.node_id) ?? []), node]);
74
+ return output;
75
+ };
76
+ const changedFromEdge = (item, input, retained) => {
77
+ const left = item.left_node_id;
78
+ const right = item.right_node_id;
79
+ if (item.match.status !== "matched" ||
80
+ item.status === "unchanged" ||
81
+ left === null ||
82
+ right === null ||
83
+ left === right ||
84
+ !retained.has(left) ||
85
+ !retained.has(right))
86
+ return [];
87
+ const evidence = comparisonEvidence(item, input);
88
+ return [
89
+ createJavaScriptApplicationEdge({
90
+ source_node_id: right,
91
+ target_node_id: left,
92
+ relation: "changed_from",
93
+ properties: {
94
+ comparison_item_id: item.item_id,
95
+ status: item.status,
96
+ match_basis: item.match.basis,
97
+ match_confidence: item.match.confidence,
98
+ dimensions: item.dimensions,
99
+ },
100
+ evidence,
101
+ }),
102
+ ];
103
+ };
104
+ const comparisonEvidence = (item, input) => {
105
+ const right = input.right.nodes.find(({ node_id: id }) => id === item.right_node_id);
106
+ const left = input.left.nodes.find(({ node_id: id }) => id === item.left_node_id);
107
+ const source = right?.observations[0]?.evidence ?? left?.observations[0]?.evidence;
108
+ const complete = input.left.coverage.status === "complete" &&
109
+ input.right.coverage.status === "complete" &&
110
+ input.omittedComparisonItems === 0;
111
+ return {
112
+ authority: "cross-version-comparison",
113
+ state: "inferred",
114
+ confidence: item.match.confidence === "medium" ? "medium" : "high",
115
+ artifact: source?.artifact ?? {
116
+ available: false,
117
+ reason: "unresolved",
118
+ detail: "Compared node has no artifact-backed observation.",
119
+ },
120
+ location: source?.location ?? {
121
+ available: false,
122
+ reason: "unresolved",
123
+ detail: "Compared node has no actionable source location.",
124
+ },
125
+ extractor: {
126
+ name: "rea-application-version-comparison",
127
+ version: "1",
128
+ operation: "compare_application_versions",
129
+ executable_sha256: null,
130
+ },
131
+ coverage: complete
132
+ ? { status: "complete", truncated: false, omitted_count: 0, limits: [] }
133
+ : {
134
+ status: "partial",
135
+ truncated: input.omittedComparisonItems > 0,
136
+ omitted_count: input.omittedComparisonItems > 0
137
+ ? input.omittedComparisonItems
138
+ : (source?.coverage.omitted_count ?? null),
139
+ limits: input.omittedComparisonItems > 0
140
+ ? [
141
+ {
142
+ name: "max-comparison-items",
143
+ value: input.limits.max_comparison_items,
144
+ unit: "items",
145
+ },
146
+ ]
147
+ : [],
148
+ },
149
+ limitations: [
150
+ "Cross-version pairing is inferred from the stated match basis; changed_from does not prove runtime reachability.",
151
+ ...item.limitations,
152
+ ],
153
+ evidence_ids: [input.leftEvidenceId, input.rightEvidenceId],
154
+ };
155
+ };
156
+ const changeGraphCoverage = (input, graphOmissions) => {
157
+ const outputOmissions = graphOmissions + input.omittedComparisonItems;
158
+ if (outputOmissions > 0)
159
+ return {
160
+ status: "partial",
161
+ truncated: true,
162
+ omitted_count: outputOmissions,
163
+ limits: [
164
+ {
165
+ name: "max-comparison-items",
166
+ value: input.limits.max_comparison_items,
167
+ unit: "items",
168
+ },
169
+ {
170
+ name: "max-graph-nodes",
171
+ value: input.limits.max_graph_nodes,
172
+ unit: "items",
173
+ },
174
+ {
175
+ name: "max-graph-edges",
176
+ value: input.limits.max_graph_edges,
177
+ unit: "items",
178
+ },
179
+ ],
180
+ };
181
+ if (input.left.coverage.status === "complete" &&
182
+ input.right.coverage.status === "complete")
183
+ return {
184
+ status: "complete",
185
+ truncated: false,
186
+ omitted_count: 0,
187
+ limits: [],
188
+ };
189
+ const counts = [
190
+ input.left.coverage.omitted_count,
191
+ input.right.coverage.omitted_count,
192
+ ];
193
+ return {
194
+ status: "partial",
195
+ truncated: false,
196
+ omitted_count: counts.every((value) => value !== null)
197
+ ? counts.reduce((total, value) => total + (value ?? 0), 0)
198
+ : null,
199
+ limits: [],
200
+ };
201
+ };
202
+ const mergeNodes = (nodes) => {
203
+ const groups = new Map();
204
+ for (const node of nodes)
205
+ groups.set(node.node_id, [...(groups.get(node.node_id) ?? []), node]);
206
+ let omittedObservations = 0;
207
+ const merged = [...groups.values()].map((group) => {
208
+ const first = group[0];
209
+ if (first === undefined)
210
+ throw new TypeError("Empty change-graph node group");
211
+ const observations = [
212
+ ...new Map(group
213
+ .flatMap(({ observations: values }) => values)
214
+ .map((observation) => [observation.observation_id, observation])).values(),
215
+ ].sort((left, right) => compareCodePoints(left.observation_id, right.observation_id));
216
+ omittedObservations += Math.max(0, observations.length - 64);
217
+ return createJavaScriptApplicationNode({
218
+ kind: first.kind,
219
+ identity: first.identity,
220
+ observations: observations
221
+ .slice(0, 64)
222
+ .map(({ observation_id: _id, identifier_strategy: _strategy, ...value }) => value),
223
+ });
224
+ });
225
+ return {
226
+ nodes: merged.sort((left, right) => compareCodePoints(left.node_id, right.node_id)),
227
+ omittedObservations,
228
+ };
229
+ };
230
+ const uniqueEdges = (edges) => [...new Map(edges.map((edge) => [edge.edge_id, edge])).values()].sort((left, right) => compareCodePoints(left.edge_id, right.edge_id));
231
+ const uniqueSorted = (values) => [...new Set(values)].sort(compareCodePoints);