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,245 @@
1
+ import { isAbsolute, resolve } from "node:path";
2
+ import { z } from "zod";
3
+ import { evidenceSchema } from "./evidence.js";
4
+ import { compareCodePoints, javascriptApplicationGraphSchema, } from "./javascriptApplicationGraph.js";
5
+ const digestSchema = z.string().regex(/^[a-f0-9]{64}$/u);
6
+ const evidenceIdSchema = z.string().regex(/^ev_[a-f0-9]{64}$/u);
7
+ const nodeIdSchema = z.string().regex(/^jag_node_[a-f0-9]{64}$/u);
8
+ const boundedTextSchema = z.string().min(1).max(4_096);
9
+ const safePrefixSchema = z
10
+ .string()
11
+ .max(4_096)
12
+ .refine((value) => value === "" ||
13
+ (!value.startsWith("/") &&
14
+ !value.includes("\\") &&
15
+ value.split("/").every((part) => !["", ".", ".."].includes(part))), "Artifact prefix must be empty or a safe relative POSIX path");
16
+ const runtimeFileMappingSchema = z.strictObject({
17
+ kind: z.literal("file-root"),
18
+ root: z
19
+ .string()
20
+ .min(1)
21
+ .max(16_384)
22
+ .refine(isAbsolute, "Runtime file mapping root must be absolute")
23
+ .overwrite((value) => resolve(value)),
24
+ artifact_prefix: safePrefixSchema.default(""),
25
+ });
26
+ const runtimeUrlMappingSchema = z.strictObject({
27
+ kind: z.literal("url-prefix"),
28
+ prefix: z
29
+ .string()
30
+ .min(1)
31
+ .max(16_384)
32
+ .refine((value) => normalizeRuntimeUrlPrefix(value) !== null, "Runtime URL prefix must be HTTP(S) without credentials, query, or fragment")
33
+ .overwrite((value) => normalizeRuntimeUrlPrefix(value) ?? value),
34
+ artifact_prefix: safePrefixSchema.default(""),
35
+ });
36
+ const normalizeRuntimeUrlPrefix = (value) => {
37
+ let url;
38
+ try {
39
+ url = new URL(value);
40
+ }
41
+ catch {
42
+ return null;
43
+ }
44
+ if (!["http:", "https:"].includes(url.protocol) ||
45
+ url.username !== "" ||
46
+ url.password !== "" ||
47
+ url.search !== "" ||
48
+ url.hash !== "")
49
+ return null;
50
+ if (!url.pathname.endsWith("/"))
51
+ url.pathname += "/";
52
+ return url.href;
53
+ };
54
+ /** Caller-declared translation from an authorized runtime location to a layer. */
55
+ const runtimeLocationMappingSchema = z.discriminatedUnion("kind", [
56
+ runtimeFileMappingSchema,
57
+ runtimeUrlMappingSchema,
58
+ ]);
59
+ const staticLayerSchema = z.strictObject({
60
+ role: z.enum(["application", "cache", "assets"]),
61
+ analysis: evidenceSchema,
62
+ runtime_mappings: z
63
+ .array(runtimeLocationMappingSchema)
64
+ .max(32)
65
+ .overwrite(normalizeRuntimeMappings)
66
+ .default([]),
67
+ });
68
+ function normalizeRuntimeMappings(mappings) {
69
+ return [
70
+ ...new Map(mappings.map((mapping) => [runtimeMappingKey(mapping), mapping])).values(),
71
+ ].sort((left, right) => compareCodePoints(runtimeMappingKey(left), runtimeMappingKey(right)));
72
+ }
73
+ function runtimeMappingKey(mapping) {
74
+ return mapping.kind === "file-root"
75
+ ? `file-root\0${mapping.root}\0${mapping.artifact_prefix}`
76
+ : `url-prefix\0${mapping.prefix}\0${mapping.artifact_prefix}`;
77
+ }
78
+ const reconciliationLimitsSchema = z.strictObject({
79
+ max_runtime_entities: z.number().int().min(1).max(50_000).default(10_000),
80
+ max_reconciliation_items: z.number().int().min(1).max(50_000).default(20_000),
81
+ max_static_load_states: z.number().int().min(1).max(50_000).default(20_000),
82
+ });
83
+ /** Evidence-backed static layers and passive captures to reconcile. */
84
+ export const reconcileJavaScriptRuntimeInputSchema = z
85
+ .strictObject({
86
+ static_layers: z.array(staticLayerSchema).min(1).max(8),
87
+ runtime_observations: z.array(evidenceSchema).min(1).max(32),
88
+ limits: reconciliationLimitsSchema.default({
89
+ max_runtime_entities: 10_000,
90
+ max_reconciliation_items: 20_000,
91
+ max_static_load_states: 20_000,
92
+ }),
93
+ })
94
+ .superRefine((input, context) => {
95
+ if (input.static_layers.filter(({ role }) => role === "application")
96
+ .length !== 1)
97
+ context.addIssue({
98
+ code: "custom",
99
+ path: ["static_layers"],
100
+ message: "Exactly one application static layer is required",
101
+ });
102
+ const staticIds = input.static_layers.map(({ analysis }) => analysis.evidence_id);
103
+ if (new Set(staticIds).size !== staticIds.length)
104
+ context.addIssue({
105
+ code: "custom",
106
+ path: ["static_layers"],
107
+ message: "Static layer Evidence must be unique",
108
+ });
109
+ const runtimeIds = input.runtime_observations.map(({ evidence_id: id }) => id);
110
+ if (new Set(runtimeIds).size !== runtimeIds.length)
111
+ context.addIssue({
112
+ code: "custom",
113
+ path: ["runtime_observations"],
114
+ message: "Runtime observation Evidence must be unique",
115
+ });
116
+ if (input.limits.max_runtime_entities < input.runtime_observations.length)
117
+ context.addIssue({
118
+ code: "custom",
119
+ path: ["limits", "max_runtime_entities"],
120
+ message: "Runtime entity limit must retain one target per observation",
121
+ });
122
+ });
123
+ const layerSummarySchema = z.strictObject({
124
+ layer_id: z.string().regex(/^jrl_[a-f0-9]{64}$/u),
125
+ role: z.enum(["application", "cache", "assets"]),
126
+ evidence_id: evidenceIdSchema,
127
+ graph_id: z.string().regex(/^jag_[a-f0-9]{64}$/u),
128
+ root_artifact_sha256: digestSchema,
129
+ input_path: z.string().min(1).max(16_384),
130
+ format: z.enum(["asar", "directory"]),
131
+ runtime_mappings: z.array(runtimeLocationMappingSchema).max(32),
132
+ });
133
+ const captureSummarySchema = z.strictObject({
134
+ evidence_id: evidenceIdSchema,
135
+ capture_sha256: digestSchema,
136
+ kind: z.enum(["browser", "electron"]),
137
+ target_node_id: nodeIdSchema,
138
+ target_key: boundedTextSchema,
139
+ target_location: boundedTextSchema,
140
+ frames: z.number().int().min(0),
141
+ scripts: z.number().int().min(0),
142
+ workers: z.number().int().min(0),
143
+ scripts_complete_within_scope: z.boolean(),
144
+ });
145
+ const reconciliationReasonSchema = z.enum([
146
+ "content-and-location-match",
147
+ "unique-content-match",
148
+ "unique-location-match",
149
+ "ambiguous-static-candidates",
150
+ "captured-content-disagrees-with-static-location",
151
+ "no-static-content-match",
152
+ "no-authorized-location-mapping",
153
+ "runtime-frame-unattributed",
154
+ "static-or-runtime-coverage-incomplete",
155
+ "reconciliation-limit-reached",
156
+ ]);
157
+ const reconciliationItemSchema = z.strictObject({
158
+ reconciliation_id: z.string().regex(/^jrr_item_[a-f0-9]{64}$/u),
159
+ entity_kind: z.enum(["target", "frame", "script", "worker"]),
160
+ runtime_evidence_id: evidenceIdSchema,
161
+ runtime_node_id: nodeIdSchema,
162
+ static_layer_id: z
163
+ .string()
164
+ .regex(/^jrl_[a-f0-9]{64}$/u)
165
+ .nullable(),
166
+ static_node_id: nodeIdSchema.nullable(),
167
+ status: z.enum(["matched", "ambiguous", "unmatched", "unknown"]),
168
+ basis: z.enum([
169
+ "content-and-location",
170
+ "content-sha256",
171
+ "module-source-sha256",
172
+ "artifact-path",
173
+ "operator-file-mapping",
174
+ "operator-url-mapping",
175
+ "none",
176
+ ]),
177
+ confidence: z.enum(["exact", "high", "medium", "low", "unknown"]),
178
+ reason: reconciliationReasonSchema,
179
+ candidate_static_count: z.number().int().min(0).max(800_000),
180
+ candidate_static_nodes: z
181
+ .array(z.strictObject({
182
+ static_layer_id: z.string().regex(/^jrl_[a-f0-9]{64}$/u),
183
+ static_node_id: nodeIdSchema,
184
+ }))
185
+ .max(1_000),
186
+ });
187
+ const staticLoadStateSchema = z.strictObject({
188
+ static_layer_id: z.string().regex(/^jrl_[a-f0-9]{64}$/u),
189
+ static_node_id: nodeIdSchema,
190
+ kind: z.enum(["javascript-asset", "javascript-chunk", "javascript-module"]),
191
+ status: z.enum([
192
+ "loaded",
193
+ "resident-in-loaded-asset",
194
+ "not-observed-in-capture",
195
+ "unknown",
196
+ ]),
197
+ runtime_node_ids: z.array(nodeIdSchema).max(10_000),
198
+ reason: z.enum([
199
+ "runtime-script-correspondence",
200
+ "containing-asset-was-loaded",
201
+ "not-observed-in-bounded-capture",
202
+ "layer-outside-runtime-scope",
203
+ "static-or-runtime-coverage-incomplete",
204
+ ]),
205
+ });
206
+ /** Deterministic static/passive-runtime reconciliation with a combined JAG. */
207
+ export const javascriptRuntimeReconciliationResultSchema = z.strictObject({
208
+ schema_version: z.literal(1),
209
+ reconciliation_id: z.string().regex(/^jrr_[a-f0-9]{64}$/u),
210
+ static_layers: z.array(layerSummarySchema).min(1).max(8),
211
+ runtime_captures: z.array(captureSummarySchema).min(1).max(32),
212
+ graph: javascriptApplicationGraphSchema,
213
+ summary: z.strictObject({
214
+ runtime_targets: z.number().int().min(0),
215
+ runtime_frames: z.number().int().min(0),
216
+ runtime_scripts: z.number().int().min(0),
217
+ runtime_workers: z.number().int().min(0),
218
+ matched: z.number().int().min(0),
219
+ ambiguous: z.number().int().min(0),
220
+ unmatched: z.number().int().min(0),
221
+ unknown: z.number().int().min(0),
222
+ static_loaded: z.number().int().min(0),
223
+ static_resident: z.number().int().min(0),
224
+ static_not_observed: z.number().int().min(0),
225
+ static_unknown: z.number().int().min(0),
226
+ }),
227
+ reconciliations: z.array(reconciliationItemSchema).max(50_000),
228
+ static_load_states: z.array(staticLoadStateSchema).max(50_000),
229
+ source_map_authority: z.strictObject({
230
+ used_for_primary_matching: z.literal(false),
231
+ static_layers_with_read_approval: z.number().int().min(0),
232
+ runtime_script_declarations: z.number().int().min(0),
233
+ limitation: boundedTextSchema,
234
+ }),
235
+ coverage: z.strictObject({
236
+ status: z.enum(["complete-within-inputs", "partial", "truncated"]),
237
+ truncated: z.boolean(),
238
+ omitted_runtime_entities: z.number().int().min(0),
239
+ omitted_reconciliation_items: z.number().int().min(0),
240
+ omitted_static_load_states: z.number().int().min(0),
241
+ omitted_graph_items: z.number().int().min(0),
242
+ }),
243
+ evidence_links: z.array(evidenceIdSchema).min(2).max(40),
244
+ limitations: z.array(boundedTextSchema).max(1_000),
245
+ });
@@ -0,0 +1,191 @@
1
+ import { isAbsolute, posix, relative } from "node:path";
2
+ import { compareCodePoints, } from "./javascriptApplicationGraph.js";
3
+ /** Index statically reconstructed entities that can receive runtime matches. */
4
+ export const collectStaticRuntimeCandidates = (layers) => layers
5
+ .flatMap((layer) => candidatesForLayer(layer))
6
+ .sort((left, right) => compareCodePoints(left.layer.layerId, right.layer.layerId) ||
7
+ compareCodePoints(left.node.node_id, right.node.node_id));
8
+ /** Translate one already-authorized runtime location into artifact paths. */
9
+ export const mappedRuntimePaths = (layer, entity) => {
10
+ const paths = [];
11
+ if (entity.location.kind === "file" && layer.result.format === "directory") {
12
+ const path = pathBelowRoot(layer.result.input_path, entity.location.value);
13
+ if (path !== null)
14
+ paths.push({ path, basis: "artifact-path" });
15
+ }
16
+ for (const mapping of layer.runtimeMappings) {
17
+ const suffix = mapping.kind === "file-root" && entity.location.kind === "file"
18
+ ? pathBelowRoot(mapping.root, entity.location.value)
19
+ : mapping.kind === "url-prefix" && entity.location.kind === "url"
20
+ ? pathBelowUrlPrefix(mapping.prefix, entity.location.value)
21
+ : null;
22
+ if (suffix === null)
23
+ continue;
24
+ const path = safeArtifactPath(mapping.artifact_prefix, suffix);
25
+ if (path === null)
26
+ continue;
27
+ paths.push({
28
+ path,
29
+ basis: mapping.kind === "file-root"
30
+ ? "operator-file-mapping"
31
+ : "operator-url-mapping",
32
+ });
33
+ }
34
+ return uniqueMappedPaths(paths);
35
+ };
36
+ /** Precompute the artifact prefixes exercised by a bounded runtime set. */
37
+ export const createStaticRuntimeScope = (layer, entities) => ({
38
+ artifactPrefixes: activeArtifactPrefixes(layer, entities),
39
+ pathsByNodeId: indexStaticPaths(layer.graph),
40
+ });
41
+ /** Whether one static node falls under a mapping exercised by this runtime set. */
42
+ export const staticNodeWithinRuntimeScope = (node, scope) => (scope.pathsByNodeId.get(node.node_id) ?? []).some((path) => scope.artifactPrefixes.some((prefix) => pathWithinPrefix(path, prefix)));
43
+ const candidatesForLayer = (layer) => {
44
+ const graph = layer.graph;
45
+ const pathsByNodeId = indexStaticPaths(graph);
46
+ return graph.nodes.flatMap((node) => {
47
+ const category = candidateCategory(node);
48
+ if (category === null)
49
+ return [];
50
+ return [
51
+ {
52
+ layer,
53
+ node,
54
+ category,
55
+ paths: pathsByNodeId.get(node.node_id) ?? [],
56
+ digests: candidateDigests(node),
57
+ },
58
+ ];
59
+ });
60
+ };
61
+ const candidateCategory = (node) => {
62
+ if (node.kind === "electron-renderer")
63
+ return "renderer";
64
+ if (node.kind === "javascript-asset" || node.kind === "javascript-module")
65
+ return "javascript";
66
+ if (node.kind === "worker")
67
+ return "worker";
68
+ if (node.kind === "service-worker")
69
+ return "service-worker";
70
+ return null;
71
+ };
72
+ const indexStaticPaths = (graph) => {
73
+ const nodes = new Map(graph.nodes.map((candidate) => [candidate.node_id, candidate]));
74
+ const relatedBySource = new Map();
75
+ for (const edge of graph.edges) {
76
+ if (edge.relation !== "maps_to")
77
+ continue;
78
+ const target = nodes.get(edge.target_node_id);
79
+ if (target === undefined)
80
+ continue;
81
+ const related = relatedBySource.get(edge.source_node_id);
82
+ if (related === undefined)
83
+ relatedBySource.set(edge.source_node_id, [target]);
84
+ else
85
+ related.push(target);
86
+ }
87
+ return new Map(graph.nodes.map((node) => [
88
+ node.node_id,
89
+ uniqueSorted([
90
+ ...nodePaths(node),
91
+ ...(relatedBySource.get(node.node_id) ?? []).flatMap(nodePaths),
92
+ ]),
93
+ ]));
94
+ };
95
+ const nodePaths = (node) => {
96
+ const paths = [];
97
+ if (node.identity.strategy === "canonical-path")
98
+ paths.push(node.identity.path);
99
+ for (const observation of node.observations) {
100
+ for (const property of ["path", "resolved_path", "declared_path"])
101
+ if (typeof observation.properties[property] === "string")
102
+ paths.push(observation.properties[property]);
103
+ if (observation.evidence.location.available &&
104
+ observation.evidence.location.value.kind === "artifact-path")
105
+ paths.push(observation.evidence.location.value.path);
106
+ }
107
+ return paths
108
+ .map(normalizeArtifactPath)
109
+ .filter((path) => path !== null && path !== "artifact-root");
110
+ };
111
+ const candidateDigests = (node) => {
112
+ const values = [];
113
+ if (node.kind === "javascript-asset" &&
114
+ node.identity.strategy === "content-digest")
115
+ values.push({
116
+ sha256: node.identity.sha256,
117
+ basis: "content-sha256",
118
+ });
119
+ if (node.kind === "javascript-module")
120
+ for (const observation of node.observations) {
121
+ const digest = observation.properties.source_sha256;
122
+ if (typeof digest === "string" && /^[a-f0-9]{64}$/u.test(digest))
123
+ values.push({ sha256: digest, basis: "module-source-sha256" });
124
+ }
125
+ return [
126
+ ...new Map(values.map((value) => [`${value.basis}:${value.sha256}`, value])).values(),
127
+ ];
128
+ };
129
+ const pathBelowRoot = (root, value) => {
130
+ const remainder = relative(root, value);
131
+ if (remainder === "" ||
132
+ remainder.startsWith("..") ||
133
+ isAbsolute(remainder) ||
134
+ remainder.includes("\\"))
135
+ return null;
136
+ return normalizeArtifactPath(remainder);
137
+ };
138
+ const pathBelowUrlPrefix = (prefix, value) => {
139
+ let base;
140
+ let candidate;
141
+ try {
142
+ base = new URL(prefix);
143
+ candidate = new URL(value);
144
+ }
145
+ catch {
146
+ return null;
147
+ }
148
+ if (base.origin !== candidate.origin ||
149
+ !candidate.pathname.startsWith(base.pathname))
150
+ return null;
151
+ try {
152
+ return normalizeArtifactPath(decodeURIComponent(candidate.pathname.slice(base.pathname.length)));
153
+ }
154
+ catch {
155
+ return null;
156
+ }
157
+ };
158
+ const activeArtifactPrefixes = (layer, entities) => {
159
+ const prefixes = new Set();
160
+ if (layer.result.format === "directory" &&
161
+ entities.some(({ location }) => location.kind === "file" &&
162
+ pathBelowRoot(layer.result.input_path, location.value) !== null))
163
+ prefixes.add("");
164
+ for (const mapping of layer.runtimeMappings)
165
+ if (entities.some(({ location }) => mapping.kind === "file-root" && location.kind === "file"
166
+ ? pathBelowRoot(mapping.root, location.value) !== null
167
+ : mapping.kind === "url-prefix" && location.kind === "url"
168
+ ? pathBelowUrlPrefix(mapping.prefix, location.value) !== null
169
+ : false))
170
+ prefixes.add(mapping.artifact_prefix);
171
+ return [...prefixes].sort(compareCodePoints);
172
+ };
173
+ const pathWithinPrefix = (path, prefix) => prefix === "" || path === prefix || path.startsWith(`${prefix}/`);
174
+ const safeArtifactPath = (prefix, suffix) => normalizeArtifactPath(prefix === "" ? suffix : posix.join(prefix, suffix));
175
+ const normalizeArtifactPath = (value) => {
176
+ const normalized = posix
177
+ .normalize(value.replaceAll("\\", "/"))
178
+ .replace(/^\.\//u, "");
179
+ return normalized !== "" &&
180
+ normalized !== "." &&
181
+ normalized !== ".." &&
182
+ !normalized.startsWith("/") &&
183
+ !normalized.startsWith("../")
184
+ ? normalized
185
+ : null;
186
+ };
187
+ const uniqueMappedPaths = (values) => [
188
+ ...new Map(values.map((value) => [`${value.basis}:${value.path}`, value])).values(),
189
+ ].sort((left, right) => compareCodePoints(left.path, right.path) ||
190
+ compareCodePoints(left.basis, right.basis));
191
+ const uniqueSorted = (values) => [...new Set(values)].sort(compareCodePoints);