rea-agents 1.7.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 (156) hide show
  1. package/README.md +38 -31
  2. package/dist/application/CapabilityInventory.js +18 -0
  3. package/dist/application/CrossVersionInvestigation.js +10 -6
  4. package/dist/application/Doctor.js +56 -6
  5. package/dist/application/ElectronBoundaryAnalysis.js +96 -0
  6. package/dist/application/ElectronBoundaryGraph.js +9 -0
  7. package/dist/application/ElectronBoundaryGraphContext.js +62 -0
  8. package/dist/application/ElectronBoundaryGraphIpc.js +242 -0
  9. package/dist/application/ElectronBoundaryGraphNative.js +86 -0
  10. package/dist/application/ElectronBoundaryGraphWindows.js +199 -0
  11. package/dist/application/EnhancedTools.js +38 -13
  12. package/dist/application/InvestigationProviders.js +30 -0
  13. package/dist/application/JavaScriptApplicationEvidence.js +26 -0
  14. package/dist/application/JavaScriptApplicationEvidenceGraph.js +89 -0
  15. package/dist/application/JavaScriptApplicationService.js +74 -0
  16. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +29 -0
  17. package/dist/application/JavaScriptApplicationWorkflowService.js +90 -0
  18. package/dist/application/JavaScriptArtifactAnalysis.js +7 -1
  19. package/dist/application/JavaScriptArtifactGraphBuilder.js +59 -16
  20. package/dist/application/JavaScriptArtifactGraphEvidence.js +24 -14
  21. package/dist/application/JavaScriptArtifactReconstruction.js +3 -0
  22. package/dist/application/JavaScriptArtifactReconstructionInput.js +2 -83
  23. package/dist/application/JavaScriptReplayPlanning.js +201 -0
  24. package/dist/application/JavaScriptReplayService.js +266 -0
  25. package/dist/application/JavaScriptRuntimeReconciliationEvidence.js +25 -0
  26. package/dist/application/JavaScriptRuntimeReconciliationService.js +27 -0
  27. package/dist/application/ManagedApplicationGraphService.js +55 -0
  28. package/dist/application/ManagedMemberComparisonService.js +122 -0
  29. package/dist/application/ManagedNativeVerificationService.js +39 -0
  30. package/dist/application/ManagedReconstructionService.js +58 -0
  31. package/dist/application/ManagedRuntimeCorrelationService.js +103 -0
  32. package/dist/application/PermissionAuthority.js +1 -1
  33. package/dist/application/ProcessSampling.js +15 -11
  34. package/dist/application/ProjectPermissionStore.js +1 -0
  35. package/dist/application/runtime.js +2 -0
  36. package/dist/browser/CdpCaptureEvents.js +49 -0
  37. package/dist/browser/CdpElectronInspection.js +106 -162
  38. package/dist/browser/CdpElectronProvider.js +5 -1
  39. package/dist/browser/CdpElectronScriptEvents.js +69 -0
  40. package/dist/browser/CdpElectronScripts.js +94 -0
  41. package/dist/browser/CdpElectronWorkers.js +56 -0
  42. package/dist/browser/CdpPageCapture.js +8 -4
  43. package/dist/catalogIdentity.js +4 -1
  44. package/dist/cli.js +388 -0
  45. package/dist/cliApplicationCommands.js +62 -0
  46. package/dist/cliCommandNames.js +13 -0
  47. package/dist/cliElectronCommands.js +103 -1
  48. package/dist/cliJsonInput.js +54 -0
  49. package/dist/config.js +83 -0
  50. package/dist/contracts/applicationToolContracts.js +91 -0
  51. package/dist/contracts/artifactToolContracts.js +5 -9
  52. package/dist/contracts/browserToolContracts.js +14 -62
  53. package/dist/contracts/electronToolContracts.js +45 -19
  54. package/dist/contracts/errorSchemas.js +1 -0
  55. package/dist/contracts/investigationExamples.js +0 -6
  56. package/dist/contracts/javascriptApplicationWorkflowExamples.js +46 -0
  57. package/dist/contracts/javascriptRuntimeReconciliationExample.js +208 -0
  58. package/dist/contracts/managedToolContracts.js +153 -0
  59. package/dist/contracts/managedWorkflowExamples.js +346 -0
  60. package/dist/contracts/managedWorkflowToolContracts.js +203 -0
  61. package/dist/contracts/nativeToolContracts.js +2 -6
  62. package/dist/contracts/promptContracts.js +18 -2
  63. package/dist/contracts/toolContractExamples.js +10 -25
  64. package/dist/contracts/toolContracts.js +47 -45
  65. package/dist/contracts/toolEffects.js +160 -0
  66. package/dist/contracts/toolOutputSchemas.js +46 -31
  67. package/dist/doctorRuntime.js +42 -1
  68. package/dist/domain/artifactComparison.js +3 -4
  69. package/dist/domain/browserObservation.js +3 -0
  70. package/dist/domain/bundleComparison.js +4 -4
  71. package/dist/domain/electronObservation.js +13 -0
  72. package/dist/domain/electronStaticAnalysis.js +9 -0
  73. package/dist/domain/electronStaticAnalysisBrowser.js +194 -0
  74. package/dist/domain/electronStaticAnalysisIpc.js +171 -0
  75. package/dist/domain/electronStaticAnalysisNative.js +164 -0
  76. package/dist/domain/electronStaticAnalysisTypes.js +1 -0
  77. package/dist/domain/electronStaticAnalysisValues.js +103 -0
  78. package/dist/domain/errors.js +67 -1
  79. package/dist/domain/functionComparisonSchemas.js +3 -8
  80. package/dist/domain/inputIssueProjection.js +52 -0
  81. package/dist/domain/javascriptApplicationAnalysis.js +155 -0
  82. package/dist/domain/javascriptApplicationChangeGraph.js +231 -0
  83. package/dist/domain/javascriptApplicationEvidenceSchemas.js +18 -0
  84. package/dist/domain/javascriptApplicationGraph.js +2 -1
  85. package/dist/domain/javascriptApplicationGraphSchemas.js +7 -0
  86. package/dist/domain/javascriptApplicationVersionComparison.js +116 -0
  87. package/dist/domain/javascriptApplicationVersionComparisonSchemas.js +139 -0
  88. package/dist/domain/javascriptApplicationVersionItems.js +221 -0
  89. package/dist/domain/javascriptApplicationVersionKeys.js +170 -0
  90. package/dist/domain/javascriptFeatureSeed.js +140 -0
  91. package/dist/domain/javascriptFeatureTrace.js +232 -0
  92. package/dist/domain/javascriptFeatureTraceSchemas.js +136 -0
  93. package/dist/domain/javascriptFeatureTraversal.js +88 -0
  94. package/dist/domain/javascriptNativeHandoff.js +85 -0
  95. package/dist/domain/javascriptReplay.js +361 -0
  96. package/dist/domain/javascriptRuntimeLoadState.js +106 -0
  97. package/dist/domain/javascriptRuntimeReconciliation.js +42 -0
  98. package/dist/domain/javascriptRuntimeReconciliationGraph.js +169 -0
  99. package/dist/domain/javascriptRuntimeReconciliationMatching.js +247 -0
  100. package/dist/domain/javascriptRuntimeReconciliationParsing.js +160 -0
  101. package/dist/domain/javascriptRuntimeReconciliationResult.js +119 -0
  102. package/dist/domain/javascriptRuntimeReconciliationRuntime.js +316 -0
  103. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +245 -0
  104. package/dist/domain/javascriptRuntimeStaticCandidates.js +191 -0
  105. package/dist/domain/javascriptStaticAnalysis.js +31 -43
  106. package/dist/domain/javascriptStaticAnalysisFindings.js +39 -0
  107. package/dist/domain/javascriptStaticAnalysisHelpers.js +10 -0
  108. package/dist/domain/javascriptStaticAnalysisState.js +6 -0
  109. package/dist/domain/managedApplicationGraph.js +556 -0
  110. package/dist/domain/managedArtifact.js +444 -0
  111. package/dist/domain/managedMemberComparison.js +565 -0
  112. package/dist/domain/managedNativeVerification.js +408 -0
  113. package/dist/domain/managedReconstruction.js +183 -0
  114. package/dist/domain/managedRuntimeCorrelation.js +175 -0
  115. package/dist/domain/reconstructionVerificationSchemas.js +1 -3
  116. package/dist/dotnet/ManagedArtifactInspector.js +318 -0
  117. package/dist/dotnet/ManagedMemberInspector.js +887 -0
  118. package/dist/dotnet/ManagedMetadataHeaps.js +131 -0
  119. package/dist/dotnet/ManagedMetadataInventory.js +368 -0
  120. package/dist/dotnet/ManagedMetadataLayout.js +322 -0
  121. package/dist/dotnet/ManagedNativeBoundaryInspector.js +391 -0
  122. package/dist/dotnet/ManagedPeReader.js +157 -0
  123. package/dist/dotnet/ManagedReaderFailure.js +10 -0
  124. package/dist/dotnet/ManagedStaticProvider.js +203 -0
  125. package/dist/generatedPackageMetadata.js +2 -2
  126. package/dist/ghidra/GhidraProvider.js +6 -0
  127. package/dist/main.js +14 -0
  128. package/dist/replay/JavaScriptReplayWorker.js +286 -0
  129. package/dist/replay/LinuxJavaScriptReplayRunner.js +434 -0
  130. package/dist/replay/LinuxRuntimeClosure.js +46 -0
  131. package/dist/replay/LinuxSeccompPolicy.js +40 -0
  132. package/dist/replay/ReplayWorkerProtocol.js +55 -0
  133. package/dist/replay/SystemJavaScriptReplayHost.js +182 -0
  134. package/dist/server/createServer.js +52 -0
  135. package/dist/server/registerApplicationTools.js +115 -0
  136. package/dist/server/registerArtifactComparisonTool.js +16 -9
  137. package/dist/server/registerBrowserTools.js +33 -8
  138. package/dist/server/registerBundleComparisonTool.js +17 -20
  139. package/dist/server/registerElectronTools.js +45 -3
  140. package/dist/server/registerEnhancedTools.js +58 -13
  141. package/dist/server/registerEvidenceTools.js +5 -1
  142. package/dist/server/registerFunctionComparisonTool.js +14 -7
  143. package/dist/server/registerInvestigationTools.js +21 -17
  144. package/dist/server/registerManagedTools.js +6 -0
  145. package/dist/server/registerManagedWorkflowTools.js +277 -0
  146. package/dist/server/registerOfficialTools.js +8 -8
  147. package/dist/server/registerProcessComparisonTool.js +25 -47
  148. package/dist/server/registerSessionStatusTool.js +7 -7
  149. package/dist/server/registerSessionTools.js +51 -86
  150. package/dist/server/sessionEvidence.js +14 -19
  151. package/dist/server/toolInputValidation.js +77 -0
  152. package/dist/server/toolRegistrationOptions.js +79 -2
  153. package/dist/server/toolResult.js +25 -17
  154. package/package.json +12 -4
  155. package/scripts/rea.mjs +1 -1
  156. package/skills/rea-analysis/SKILL.md +59 -3
@@ -0,0 +1,316 @@
1
+ import { createJavaScriptApplicationEdge, createJavaScriptApplicationNode, } from "./javascriptApplicationGraph.js";
2
+ /** Project authorized passive capture metadata into capture-scoped JAG nodes. */
3
+ export const projectRuntimeCaptures = (captures, maximumEntities) => {
4
+ if (maximumEntities < captures.length)
5
+ throw new TypeError("Runtime entity limit must admit one target for every capture");
6
+ const all = captures.flatMap(projectCapture);
7
+ const targets = all.filter(({ kind }) => kind === "target");
8
+ const nonTargets = all.filter(({ kind }) => kind !== "target");
9
+ const retained = [...targets, ...nonTargets].slice(0, maximumEntities);
10
+ const retainedIds = new Set(retained.map(({ node }) => node.node_id));
11
+ const nodes = retained.map(({ node }) => node);
12
+ const edges = captures
13
+ .flatMap((capture) => runtimeEdges(capture, all))
14
+ .filter(({ source_node_id: source, target_node_id: target }) => retainedIds.has(source) && retainedIds.has(target));
15
+ const targetNodeByEvidenceId = new Map(retained
16
+ .filter(({ kind }) => kind === "target")
17
+ .map(({ capture, node }) => [capture.evidence.evidence_id, node]));
18
+ return {
19
+ entities: retained,
20
+ nodes,
21
+ edges,
22
+ targetNodeByEvidenceId,
23
+ omittedEntities: all.length - retained.length,
24
+ };
25
+ };
26
+ const projectCapture = (capture) => {
27
+ const target = targetEntity(capture);
28
+ return [
29
+ target,
30
+ ...frameEntities(capture),
31
+ ...scriptEntities(capture),
32
+ ...workerEntities(capture),
33
+ ];
34
+ };
35
+ const targetEntity = (capture) => {
36
+ const target = capture.inspection.target;
37
+ const location = "url" in target
38
+ ? { kind: "url", value: target.url }
39
+ : { kind: "file", value: target.file_path };
40
+ return runtimeEntity(capture, {
41
+ kind: "target",
42
+ nodeKind: "target",
43
+ runtimeKey: target.target_id,
44
+ targetKey: target.target_id,
45
+ frameKey: null,
46
+ scriptKey: null,
47
+ location,
48
+ staticKind: "renderer",
49
+ sourceSha256: null,
50
+ label: target.title,
51
+ properties: {
52
+ runtime_type: target.type,
53
+ location: location.value.slice(0, 4_096),
54
+ attached: target.attached,
55
+ },
56
+ section: "target",
57
+ });
58
+ };
59
+ const frameEntities = (capture) => capture.inspection.frames.map((frame) => {
60
+ const location = "url" in frame
61
+ ? { kind: "url", value: frame.url }
62
+ : { kind: "file", value: frame.file_path };
63
+ return runtimeEntity(capture, {
64
+ kind: "frame",
65
+ nodeKind: "frame",
66
+ runtimeKey: frame.frame_id,
67
+ targetKey: capture.inspection.target.target_id,
68
+ frameKey: frame.frame_id,
69
+ scriptKey: null,
70
+ location,
71
+ staticKind: "renderer",
72
+ sourceSha256: null,
73
+ label: location.value,
74
+ properties: {
75
+ parent_frame_id: frame.parent_frame_id,
76
+ location: location.value.slice(0, 4_096),
77
+ },
78
+ section: "frames",
79
+ });
80
+ });
81
+ const scriptEntities = (capture) => capture.inspection.scripts.items.map((script) => {
82
+ const location = "url" in script
83
+ ? { kind: "url", value: script.url }
84
+ : { kind: "file", value: script.file_path };
85
+ return runtimeEntity(capture, {
86
+ kind: "script",
87
+ nodeKind: "runtime-script-instance",
88
+ runtimeKey: script.script_key,
89
+ targetKey: capture.inspection.target.target_id,
90
+ frameKey: script.frame_id,
91
+ scriptKey: script.script_key,
92
+ location,
93
+ staticKind: "javascript",
94
+ sourceSha256: script.source.included
95
+ ? script.source.artifact.sha256
96
+ : null,
97
+ label: location.value,
98
+ properties: {
99
+ location: location.value.slice(0, 4_096),
100
+ cdp_hash: script.cdp_hash,
101
+ length: script.length,
102
+ is_module: script.is_module,
103
+ language: script.language,
104
+ source_sha256: script.source.included
105
+ ? script.source.artifact.sha256
106
+ : null,
107
+ ...("source_map_url" in script
108
+ ? { source_map_url: script.source_map_url }
109
+ : {}),
110
+ },
111
+ section: "scripts",
112
+ ...(script.source.included
113
+ ? { artifactSha256: script.source.artifact.sha256 }
114
+ : {}),
115
+ });
116
+ });
117
+ const workerEntities = (capture) => capture.inspection.workers.map((worker) => {
118
+ const location = "url" in worker
119
+ ? { kind: "url", value: worker.url }
120
+ : { kind: "file", value: worker.file_path };
121
+ const serviceWorker = worker.type.includes("service");
122
+ return runtimeEntity(capture, {
123
+ kind: "worker",
124
+ nodeKind: serviceWorker ? "service-worker" : "worker",
125
+ runtimeKey: worker.target_id,
126
+ targetKey: worker.target_id,
127
+ frameKey: worker.parent_frame_id,
128
+ scriptKey: null,
129
+ location,
130
+ staticKind: serviceWorker ? "service-worker" : "worker",
131
+ sourceSha256: null,
132
+ label: location.value,
133
+ properties: {
134
+ runtime_type: worker.type,
135
+ location: location.value.slice(0, 4_096),
136
+ attached: worker.attached,
137
+ opener_target_id: worker.opener_target_id,
138
+ parent_frame_id: worker.parent_frame_id,
139
+ },
140
+ section: "workers",
141
+ });
142
+ });
143
+ const runtimeEntity = (capture, input) => ({
144
+ kind: input.kind,
145
+ section: input.section,
146
+ capture,
147
+ runtimeKey: input.runtimeKey,
148
+ location: input.location,
149
+ frameKey: input.frameKey,
150
+ sourceSha256: input.sourceSha256,
151
+ staticKind: input.staticKind,
152
+ node: createJavaScriptApplicationNode({
153
+ kind: input.nodeKind,
154
+ identity: {
155
+ strategy: "runtime-instance",
156
+ stability: "capture-only",
157
+ capture_sha256: capture.captureSha256,
158
+ runtime_key: input.runtimeKey,
159
+ },
160
+ observations: [
161
+ {
162
+ label: input.label.slice(0, 1_024) || null,
163
+ properties: input.properties,
164
+ evidence: runtimeEvidence(capture, input),
165
+ },
166
+ ],
167
+ }),
168
+ });
169
+ const runtimeEvidence = (capture, input) => ({
170
+ authority: "passive-cdp-runtime",
171
+ state: "observed",
172
+ confidence: "exact",
173
+ artifact: input.artifactSha256 === undefined
174
+ ? {
175
+ available: false,
176
+ reason: input.section === "scripts" ? "not-observed" : "not-applicable",
177
+ detail: input.section === "scripts"
178
+ ? "Script source bytes were not included in this passive capture."
179
+ : "This runtime entity has no standalone artifact bytes.",
180
+ }
181
+ : {
182
+ available: true,
183
+ artifact_id: `art_${input.artifactSha256}`,
184
+ sha256: input.artifactSha256,
185
+ },
186
+ location: {
187
+ available: true,
188
+ value: {
189
+ kind: "runtime",
190
+ capture_sha256: capture.captureSha256,
191
+ target_key: input.targetKey,
192
+ frame_key: input.frameKey,
193
+ script_key: input.scriptKey,
194
+ },
195
+ },
196
+ extractor: {
197
+ name: capture.evidence.provider.id,
198
+ version: capture.evidence.provider.version ??
199
+ (capture.kind === "browser" ? "2" : "1"),
200
+ operation: capture.kind === "browser" ? "inspect_web_page" : "inspect_electron_page",
201
+ executable_sha256: null,
202
+ },
203
+ coverage: runtimeSectionCoverage(capture, input.section),
204
+ limitations: [
205
+ "The entity was observed only within one bounded passive CDP capture.",
206
+ ...(runtimeSectionComplete(capture, input.section)
207
+ ? []
208
+ : [
209
+ `The runtime ${input.section} inventory was incomplete within this capture.`,
210
+ ]),
211
+ ],
212
+ evidence_ids: [capture.evidence.evidence_id],
213
+ });
214
+ const runtimeEdges = (capture, entities) => {
215
+ const local = entities.filter(({ capture: candidate }) => candidate.evidence.evidence_id === capture.evidence.evidence_id);
216
+ const target = local.find(({ kind }) => kind === "target");
217
+ if (target === undefined)
218
+ return [];
219
+ const frames = new Map(local
220
+ .filter(({ kind }) => kind === "frame")
221
+ .map((entity) => [entity.runtimeKey, entity]));
222
+ return local.flatMap((entity) => {
223
+ if (entity === target)
224
+ return [];
225
+ const parent = (entity.kind === "script" || entity.kind === "worker") &&
226
+ entity.frameKey !== null
227
+ ? (frames.get(entity.frameKey) ?? target)
228
+ : target;
229
+ return [
230
+ createJavaScriptApplicationEdge({
231
+ source_node_id: parent.node.node_id,
232
+ target_node_id: entity.node.node_id,
233
+ relation: entity.kind === "script" ? "loads" : "contains",
234
+ properties: { basis: "passive-cdp-observation" },
235
+ evidence: runtimeRelationshipEvidence(capture, entity),
236
+ }),
237
+ ];
238
+ });
239
+ };
240
+ const runtimeRelationshipEvidence = (capture, entity) => ({
241
+ authority: "passive-cdp-runtime",
242
+ state: "observed",
243
+ confidence: "exact",
244
+ artifact: {
245
+ available: false,
246
+ reason: "not-applicable",
247
+ detail: "The relationship is runtime metadata, not standalone bytes.",
248
+ },
249
+ location: {
250
+ available: true,
251
+ value: {
252
+ kind: "runtime",
253
+ capture_sha256: capture.captureSha256,
254
+ target_key: capture.inspection.target.target_id,
255
+ frame_key: entity.frameKey,
256
+ script_key: entity.kind === "script" ? entity.runtimeKey : null,
257
+ },
258
+ },
259
+ extractor: {
260
+ name: capture.evidence.provider.id,
261
+ version: capture.evidence.provider.version ??
262
+ (capture.kind === "browser" ? "2" : "1"),
263
+ operation: capture.kind === "browser" ? "inspect_web_page" : "inspect_electron_page",
264
+ executable_sha256: null,
265
+ },
266
+ coverage: runtimeSectionCoverage(capture, entity.section),
267
+ limitations: [
268
+ "The relationship was observed only within one bounded passive CDP capture.",
269
+ ],
270
+ evidence_ids: [capture.evidence.evidence_id],
271
+ });
272
+ const runtimeSectionComplete = (capture, section) => {
273
+ if (section === "target")
274
+ return true;
275
+ if (section === "scripts")
276
+ return capture.scriptsCompleteWithinScope;
277
+ return (!capture.inspection.completeness.truncated_sections.includes(section) &&
278
+ !capture.inspection.completeness.unavailable_sections.includes(section));
279
+ };
280
+ const runtimeSectionCoverage = (capture, section) => {
281
+ if (runtimeSectionComplete(capture, section))
282
+ return {
283
+ status: "complete",
284
+ truncated: false,
285
+ omitted_count: 0,
286
+ limits: [],
287
+ };
288
+ const truncated = section !== "target" &&
289
+ capture.inspection.completeness.truncated_sections.includes(section);
290
+ return {
291
+ status: "partial",
292
+ truncated,
293
+ omitted_count: null,
294
+ limits: truncated
295
+ ? [
296
+ {
297
+ name: `passive-cdp-${section}-limit`,
298
+ value: runtimeSectionCount(capture, section),
299
+ unit: "items",
300
+ },
301
+ ]
302
+ : [],
303
+ };
304
+ };
305
+ const runtimeSectionCount = (capture, section) => {
306
+ switch (section) {
307
+ case "target":
308
+ return 1;
309
+ case "frames":
310
+ return capture.inspection.frames.length;
311
+ case "scripts":
312
+ return capture.inspection.scripts.items.length;
313
+ case "workers":
314
+ return capture.inspection.workers.length;
315
+ }
316
+ };
@@ -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
+ });