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,361 @@
1
+ import { z } from "zod";
2
+ import { evidenceEnvelopeSchema } from "./evidence.js";
3
+ const digestSchema = z.string().regex(/^[a-f0-9]{64}$/u);
4
+ const absolutePathSchema = z.string().startsWith("/").max(4096);
5
+ const aliasSchema = z
6
+ .string()
7
+ .min(1)
8
+ .max(256)
9
+ .regex(/^[A-Za-z0-9_./:@-]+$/u);
10
+ const replayModuleSchema = z
11
+ .object({
12
+ alias: aliasSchema,
13
+ path: absolutePathSchema,
14
+ format: z.enum(["esm", "commonjs-factory"]),
15
+ role: z.enum(["module", "stub"]).default("module"),
16
+ dependencies: z
17
+ .record(z.string().min(1).max(256), aliasSchema)
18
+ .refine((value) => Object.keys(value).length <= 128, {
19
+ message: "Replay modules may declare at most 128 dependencies",
20
+ })
21
+ .default({}),
22
+ })
23
+ .strict();
24
+ const replaySideSchema = z
25
+ .object({
26
+ modules: z.array(replayModuleSchema).min(1).max(128),
27
+ entry_alias: aliasSchema,
28
+ entry_export: z.string().min(1).max(256).default("default"),
29
+ })
30
+ .strict();
31
+ const explicitCaseSchema = z
32
+ .object({
33
+ case_id: z.string().min(1).max(128),
34
+ arguments: z.array(z.json()).max(16),
35
+ })
36
+ .strict();
37
+ const generatorSchema = z
38
+ .object({
39
+ preset: z.enum([
40
+ "parser-boundaries",
41
+ "sanitizer-boundaries",
42
+ "clipboard-boundaries",
43
+ ]),
44
+ seed: z.number().int().min(0).max(0xffff_ffff),
45
+ count: z.number().int().min(1).max(64),
46
+ })
47
+ .strict();
48
+ const replayLimitsSchema = z
49
+ .object({
50
+ wall_time_ms: z.number().int().min(100).max(10_000).default(3_000),
51
+ memory_bytes: z
52
+ .number()
53
+ .int()
54
+ .min(16 * 1024 * 1024)
55
+ .max(512 * 1024 * 1024)
56
+ .default(128 * 1024 * 1024),
57
+ tasks: z.number().int().min(1).max(32).default(8),
58
+ cpu_quota_percent: z.number().int().min(1).max(100).default(50),
59
+ tmpfs_bytes: z
60
+ .number()
61
+ .int()
62
+ .min(1024 * 1024)
63
+ .max(64 * 1024 * 1024)
64
+ .default(16 * 1024 * 1024),
65
+ module_bytes: z
66
+ .number()
67
+ .int()
68
+ .min(1)
69
+ .max(16 * 1024 * 1024)
70
+ .default(4 * 1024 * 1024),
71
+ input_bytes: z
72
+ .number()
73
+ .int()
74
+ .min(1)
75
+ .max(1024 * 1024)
76
+ .default(256 * 1024),
77
+ protocol_bytes: z
78
+ .number()
79
+ .int()
80
+ .min(1024 * 1024)
81
+ .max(64 * 1024 * 1024)
82
+ .default(16 * 1024 * 1024),
83
+ output_bytes: z
84
+ .number()
85
+ .int()
86
+ .min(1)
87
+ .max(4 * 1024 * 1024)
88
+ .default(512 * 1024),
89
+ stderr_bytes: z
90
+ .number()
91
+ .int()
92
+ .min(0)
93
+ .max(256 * 1024)
94
+ .default(32 * 1024),
95
+ result_depth: z.number().int().min(1).max(64).default(16),
96
+ result_nodes: z.number().int().min(1).max(100_000).default(10_000),
97
+ })
98
+ .strict();
99
+ const determinismSchema = z
100
+ .object({
101
+ clock_iso: z.iso.datetime().default("2000-01-01T00:00:00.000Z"),
102
+ random_seed: z.number().int().min(0).max(0xffff_ffff).default(0),
103
+ locale: z.literal("en-US").default("en-US"),
104
+ timezone: z.literal("UTC").default("UTC"),
105
+ platform: z.literal("linux").default("linux"),
106
+ })
107
+ .strict();
108
+ export const controlledReplayInputSchema = z
109
+ .object({
110
+ mode: z.enum(["plan", "execute"]),
111
+ left: replaySideSchema,
112
+ right: replaySideSchema.optional(),
113
+ cases: z.array(explicitCaseSchema).max(128).default([]),
114
+ generator: generatorSchema.optional(),
115
+ determinism: determinismSchema.default({
116
+ clock_iso: "2000-01-01T00:00:00.000Z",
117
+ random_seed: 0,
118
+ locale: "en-US",
119
+ timezone: "UTC",
120
+ platform: "linux",
121
+ }),
122
+ limits: replayLimitsSchema.default({
123
+ wall_time_ms: 3_000,
124
+ memory_bytes: 128 * 1024 * 1024,
125
+ tasks: 8,
126
+ cpu_quota_percent: 50,
127
+ tmpfs_bytes: 16 * 1024 * 1024,
128
+ module_bytes: 4 * 1024 * 1024,
129
+ input_bytes: 256 * 1024,
130
+ protocol_bytes: 16 * 1024 * 1024,
131
+ output_bytes: 512 * 1024,
132
+ stderr_bytes: 32 * 1024,
133
+ result_depth: 16,
134
+ result_nodes: 10_000,
135
+ }),
136
+ approved: z.boolean().default(false),
137
+ plan_digest: digestSchema.optional(),
138
+ reproducer_export: z
139
+ .object({
140
+ path: absolutePathSchema,
141
+ approved: z.boolean(),
142
+ include_sources: z.boolean().default(false),
143
+ })
144
+ .strict()
145
+ .optional(),
146
+ })
147
+ .strict()
148
+ .superRefine((value, context) => {
149
+ if (value.cases.length === 0 && value.generator === undefined)
150
+ context.addIssue({
151
+ code: "custom",
152
+ path: ["cases"],
153
+ message: "At least one explicit or generated case is required",
154
+ });
155
+ if (value.cases.length + (value.generator?.count ?? 0) > 128)
156
+ context.addIssue({
157
+ code: "custom",
158
+ path: ["generator", "count"],
159
+ message: "Explicit and generated replay cases must total at most 128",
160
+ });
161
+ if (value.mode === "execute" &&
162
+ (value.approved !== true || value.plan_digest === undefined))
163
+ context.addIssue({
164
+ code: "custom",
165
+ path: ["approved"],
166
+ message: "Execution requires literal approval and a plan digest",
167
+ });
168
+ });
169
+ const moduleCommitmentSchema = z
170
+ .object({
171
+ alias: aliasSchema,
172
+ canonical_path: z.string().min(1),
173
+ format: z.enum(["esm", "commonjs-factory"]),
174
+ role: z.enum(["module", "stub"]),
175
+ byte_count: z.number().int().min(0),
176
+ sha256: digestSchema,
177
+ dependencies: z.record(z.string(), aliasSchema),
178
+ })
179
+ .strict();
180
+ const runtimeIdentitySchema = z
181
+ .object({
182
+ path: z.string().min(1),
183
+ version: z.string().min(1),
184
+ sha256: digestSchema,
185
+ })
186
+ .strict();
187
+ const runtimeFileIdentitySchema = z
188
+ .object({
189
+ source_path: z.string().min(1),
190
+ destination_path: z.string().min(1),
191
+ sha256: digestSchema,
192
+ })
193
+ .strict();
194
+ const replayPlanSchema = z
195
+ .object({
196
+ schema_version: z.literal(1),
197
+ plan_digest: digestSchema,
198
+ policy_version: z.literal("linux-bwrap-systemd-v1"),
199
+ policy_sha256: digestSchema,
200
+ network: z.literal("none"),
201
+ filesystem: z
202
+ .object({
203
+ host_writes: z.literal(false),
204
+ private_tmpfs_bytes: z.number().int(),
205
+ })
206
+ .strict(),
207
+ runtime: z
208
+ .object({
209
+ executable: runtimeIdentitySchema,
210
+ worker: runtimeIdentitySchema,
211
+ read_only_files: z.array(runtimeFileIdentitySchema).min(1),
212
+ })
213
+ .strict(),
214
+ sandbox: z
215
+ .object({
216
+ bubblewrap: runtimeIdentitySchema,
217
+ systemd_run: runtimeIdentitySchema,
218
+ systemctl: runtimeIdentitySchema,
219
+ shell: runtimeIdentitySchema,
220
+ seccomp_sha256: digestSchema,
221
+ })
222
+ .strict(),
223
+ left: z
224
+ .object({
225
+ modules: z.array(moduleCommitmentSchema),
226
+ entry_alias: aliasSchema,
227
+ entry_export: z.string(),
228
+ })
229
+ .strict(),
230
+ right: z
231
+ .object({
232
+ modules: z.array(moduleCommitmentSchema),
233
+ entry_alias: aliasSchema,
234
+ entry_export: z.string(),
235
+ })
236
+ .strict()
237
+ .optional(),
238
+ cases: z.array(z
239
+ .object({
240
+ case_id: z.string(),
241
+ arguments: z.array(z.json()),
242
+ sha256: digestSchema,
243
+ })
244
+ .strict()),
245
+ determinism: determinismSchema,
246
+ limits: replayLimitsSchema,
247
+ effects: z.array(z.string()),
248
+ reproducer_export: z
249
+ .object({
250
+ path: z.string().min(1),
251
+ include_sources: z.boolean(),
252
+ authority: z.literal("evidence_write"),
253
+ })
254
+ .strict()
255
+ .nullable(),
256
+ })
257
+ .strict();
258
+ const replayOutcomeSchema = z
259
+ .object({
260
+ case_id: z.string(),
261
+ outcome: z.enum([
262
+ "return",
263
+ "exception",
264
+ "serialization_error",
265
+ "denied",
266
+ "timeout",
267
+ "oom",
268
+ "crash",
269
+ "cancelled",
270
+ "protocol_error",
271
+ ]),
272
+ value: z.json().optional(),
273
+ exception: z
274
+ .object({
275
+ name: z.string(),
276
+ message: z.string(),
277
+ stack: z.string().nullable(),
278
+ })
279
+ .strict()
280
+ .optional(),
281
+ input_sha256: digestSchema,
282
+ output_sha256: digestSchema.nullable(),
283
+ truncated: z.boolean(),
284
+ })
285
+ .strict();
286
+ export const replayExecutionResultSchema = z
287
+ .object({
288
+ schema_version: z.literal(1),
289
+ plan_digest: digestSchema,
290
+ outcomes: z.array(replayOutcomeSchema),
291
+ comparison: z
292
+ .array(z
293
+ .object({
294
+ case_id: z.string(),
295
+ status: z.enum(["equal", "changed", "unknown"]),
296
+ left_index: z.number().int(),
297
+ right_index: z.number().int(),
298
+ })
299
+ .strict())
300
+ .optional(),
301
+ stderr: z.string(),
302
+ termination: z.enum([
303
+ "completed",
304
+ "timeout",
305
+ "oom",
306
+ "crash",
307
+ "cancelled",
308
+ "protocol_error",
309
+ ]),
310
+ cleanup: z
311
+ .object({
312
+ state: z.enum(["complete", "incomplete"]),
313
+ residual_resources: z.array(z.string()),
314
+ })
315
+ .strict(),
316
+ limitations: z.array(z.string()),
317
+ reproducer: z
318
+ .discriminatedUnion("state", [
319
+ z
320
+ .object({
321
+ state: z.literal("written"),
322
+ path: z.string(),
323
+ sha256: digestSchema,
324
+ })
325
+ .strict(),
326
+ z
327
+ .object({
328
+ state: z.literal("failed"),
329
+ path: z.string(),
330
+ error: z.string(),
331
+ })
332
+ .strict(),
333
+ ])
334
+ .nullable(),
335
+ })
336
+ .strict();
337
+ export const replayEvidenceSchema = evidenceEnvelopeSchema
338
+ .omit({ normalized_result: true })
339
+ .extend({ normalized_result: replayExecutionResultSchema });
340
+ export const controlledReplayOutputSchema = z
341
+ .object({
342
+ phase: z.enum(["plan", "execute"]),
343
+ plan: replayPlanSchema.nullable(),
344
+ source_evidence: z.array(replayEvidenceSchema),
345
+ evidence: replayEvidenceSchema.nullable(),
346
+ })
347
+ .strict()
348
+ .superRefine((value, context) => {
349
+ if ((value.phase === "plan" &&
350
+ (value.plan === null ||
351
+ value.evidence !== null ||
352
+ value.source_evidence.length !== 0)) ||
353
+ (value.phase === "execute" &&
354
+ (value.plan !== null ||
355
+ value.evidence === null ||
356
+ value.source_evidence.length === 0)))
357
+ context.addIssue({
358
+ code: "custom",
359
+ message: "Replay output phase does not match its payload",
360
+ });
361
+ });
@@ -0,0 +1,106 @@
1
+ import { compareCodePoints, } from "./javascriptApplicationGraph.js";
2
+ import { createStaticRuntimeScope, mappedRuntimePaths, staticNodeWithinRuntimeScope, } from "./javascriptRuntimeStaticCandidates.js";
3
+ /** Classify static code presence without claiming bundled module execution. */
4
+ export const classifyStaticLoadStates = (layers, runtimeEntities, matches, options) => {
5
+ const states = [];
6
+ let totalStates = 0;
7
+ for (const layer of layers) {
8
+ const projection = classifyLayer(layer, runtimeEntities, matches, {
9
+ reconciliationComplete: options.reconciliationComplete,
10
+ maximumStates: Math.max(0, options.maximumStates - states.length),
11
+ });
12
+ totalStates += projection.total;
13
+ states.push(...projection.states);
14
+ }
15
+ return { states, omittedStates: totalStates - states.length };
16
+ };
17
+ const classifyLayer = (layer, runtimeEntities, matches, options) => {
18
+ const nodes = layer.graph.nodes.filter(isLoadStateNode);
19
+ if (options.maximumStates === 0)
20
+ return { states: [], total: nodes.length };
21
+ const direct = new Map();
22
+ for (const match of matches)
23
+ if (match.status === "matched" &&
24
+ match.static_layer_id === layer.layerId &&
25
+ match.static_node_id !== null)
26
+ append(direct, match.static_node_id, match.runtime_node_id);
27
+ const resident = residentNodes(layer, new Set(direct.keys()));
28
+ const runtimeScope = createStaticRuntimeScope(layer, runtimeEntities);
29
+ const scopedEntities = runtimeEntities.filter((entity) => mappedRuntimePaths(layer, entity).length > 0);
30
+ const layerComplete = options.reconciliationComplete &&
31
+ layer.graph.coverage.status === "complete" &&
32
+ scopedEntities.length > 0 &&
33
+ scopedEntities.every(({ capture }) => captureScriptsComplete(capture.evidence.evidence_id, runtimeEntities));
34
+ const states = nodes.slice(0, options.maximumStates).map((node) => {
35
+ const runtimeNodeIds = uniqueSorted(direct.get(node.node_id) ?? []);
36
+ if (runtimeNodeIds.length > 0)
37
+ return state(layer, node, {
38
+ status: "loaded",
39
+ runtimeNodeIds,
40
+ reason: "runtime-script-correspondence",
41
+ });
42
+ if (resident.has(node.node_id))
43
+ return state(layer, node, {
44
+ status: "resident-in-loaded-asset",
45
+ runtimeNodeIds: [],
46
+ reason: "containing-asset-was-loaded",
47
+ });
48
+ const nodeWithinScope = staticNodeWithinRuntimeScope(node, runtimeScope);
49
+ if (layerComplete && nodeWithinScope)
50
+ return state(layer, node, {
51
+ status: "not-observed-in-capture",
52
+ runtimeNodeIds: [],
53
+ reason: "not-observed-in-bounded-capture",
54
+ });
55
+ return state(layer, node, {
56
+ status: "unknown",
57
+ runtimeNodeIds: [],
58
+ reason: !nodeWithinScope
59
+ ? "layer-outside-runtime-scope"
60
+ : "static-or-runtime-coverage-incomplete",
61
+ });
62
+ });
63
+ return { states, total: nodes.length };
64
+ };
65
+ const residentNodes = (layer, directlyLoaded) => {
66
+ const nodeKinds = new Map(layer.graph.nodes.map(({ node_id: id, kind }) => [id, kind]));
67
+ const children = new Map();
68
+ for (const edge of layer.graph.edges)
69
+ if (edge.relation === "contains")
70
+ append(children, edge.source_node_id, edge.target_node_id);
71
+ const pending = [...directlyLoaded].filter((nodeId) => nodeKinds.get(nodeId) === "javascript-asset");
72
+ const resident = new Set();
73
+ for (let index = 0; index < pending.length; index += 1) {
74
+ const current = pending[index];
75
+ if (current === undefined)
76
+ break;
77
+ for (const child of children.get(current) ?? []) {
78
+ if (resident.has(child))
79
+ continue;
80
+ resident.add(child);
81
+ pending.push(child);
82
+ }
83
+ }
84
+ return resident;
85
+ };
86
+ const append = (values, key, value) => {
87
+ const current = values.get(key);
88
+ if (current === undefined)
89
+ values.set(key, [value]);
90
+ else
91
+ current.push(value);
92
+ };
93
+ const captureScriptsComplete = (evidenceId, entities) => entities.find(({ capture }) => capture.evidence.evidence_id === evidenceId)
94
+ ?.capture.scriptsCompleteWithinScope === true;
95
+ const isLoadStateNode = (node) => node.kind === "javascript-asset" ||
96
+ node.kind === "javascript-chunk" ||
97
+ node.kind === "javascript-module";
98
+ const state = (layer, node, input) => ({
99
+ static_layer_id: layer.layerId,
100
+ static_node_id: node.node_id,
101
+ kind: node.kind,
102
+ status: input.status,
103
+ runtime_node_ids: [...input.runtimeNodeIds],
104
+ reason: input.reason,
105
+ });
106
+ const uniqueSorted = (values) => [...new Set(values)].sort(compareCodePoints);
@@ -0,0 +1,42 @@
1
+ import { classifyStaticLoadStates } from "./javascriptRuntimeLoadState.js";
2
+ import { buildReconciledApplicationGraph } from "./javascriptRuntimeReconciliationGraph.js";
3
+ import { reconcileRuntimeEntities } from "./javascriptRuntimeReconciliationMatching.js";
4
+ import { parseRuntimeCaptures, parseStaticLayers, } from "./javascriptRuntimeReconciliationParsing.js";
5
+ import { createJavaScriptRuntimeReconciliationResult } from "./javascriptRuntimeReconciliationResult.js";
6
+ import { reconcileJavaScriptRuntimeInputSchema } from "./javascriptRuntimeReconciliationSchemas.js";
7
+ import { projectRuntimeCaptures } from "./javascriptRuntimeReconciliationRuntime.js";
8
+ import { collectStaticRuntimeCandidates } from "./javascriptRuntimeStaticCandidates.js";
9
+ /** Reconcile static JAG layers with authorized passive CDP Evidence. */
10
+ export const reconcileJavaScriptRuntime = (input) => {
11
+ const parsed = reconcileJavaScriptRuntimeInputSchema.parse(input);
12
+ const layers = parseStaticLayers(parsed.static_layers);
13
+ const captures = parseRuntimeCaptures(parsed.runtime_observations);
14
+ const runtime = projectRuntimeCaptures(captures, parsed.limits.max_runtime_entities);
15
+ const candidates = collectStaticRuntimeCandidates(layers);
16
+ const matching = reconcileRuntimeEntities({
17
+ entities: runtime.entities,
18
+ candidates,
19
+ layers,
20
+ maximumItems: parsed.limits.max_reconciliation_items,
21
+ });
22
+ const loadStates = classifyStaticLoadStates(layers, runtime.entities, matching.items, {
23
+ maximumStates: parsed.limits.max_static_load_states,
24
+ reconciliationComplete: runtime.omittedEntities === 0 && matching.omittedItems === 0,
25
+ });
26
+ const graph = buildReconciledApplicationGraph({
27
+ layers,
28
+ captures,
29
+ runtime,
30
+ reconciliationEdges: matching.edges,
31
+ omittedReconciliationItems: matching.omittedItems,
32
+ });
33
+ return createJavaScriptRuntimeReconciliationResult({
34
+ layers,
35
+ captures,
36
+ runtime,
37
+ matching,
38
+ loadStates,
39
+ graph: graph.graph,
40
+ omittedGraphItems: graph.omittedGraphItems,
41
+ });
42
+ };
@@ -0,0 +1,169 @@
1
+ import { compareCodePoints, createJavaScriptApplicationGraph, createJavaScriptApplicationNode, } from "./javascriptApplicationGraph.js";
2
+ /** Merge source graphs, runtime nodes, and inferred mappings into one valid JAG. */
3
+ export const buildReconciledApplicationGraph = (input) => {
4
+ const merged = mergeNodes([
5
+ ...input.layers.flatMap(({ graph }) => graph.nodes),
6
+ ...input.runtime.nodes,
7
+ ]);
8
+ const allEdges = uniqueEdges([
9
+ ...input.layers.flatMap(({ graph }) => graph.edges),
10
+ ...input.runtime.edges,
11
+ ...input.reconciliationEdges,
12
+ ]);
13
+ const bounded = boundGraphContent(input, merged.nodes, allEdges);
14
+ const facts = graphCoverageFacts(input, merged.omittedObservations + bounded.omittedItems);
15
+ const graph = createJavaScriptApplicationGraph({
16
+ schema: "JavaScriptApplicationGraph",
17
+ schema_version: 1,
18
+ root_node_ids: bounded.rootNodeIds,
19
+ nodes: bounded.nodes,
20
+ edges: bounded.edges,
21
+ coverage: graphCoverage(input, facts, bounded.nodes.length),
22
+ limitations: uniqueSorted([
23
+ ...input.layers.flatMap(({ graph }) => graph.limitations),
24
+ "Runtime presence is bounded to passive capture windows and does not prove feature execution.",
25
+ "Cross-layer observed_as edges are inferences; digest equality proves byte identity only.",
26
+ "Source-map relationships retain their original static authority and are not promoted into runtime matches.",
27
+ ...(facts.inputTruncated
28
+ ? [
29
+ "One or more source graphs or passive captures were incomplete or truncated.",
30
+ ]
31
+ : []),
32
+ ...(facts.outputTruncated
33
+ ? [
34
+ "The reconciled graph omitted entities or classifications at caller limits.",
35
+ ]
36
+ : []),
37
+ ]),
38
+ });
39
+ return {
40
+ graph,
41
+ omittedGraphItems: merged.omittedObservations + bounded.omittedItems,
42
+ };
43
+ };
44
+ const boundGraphContent = (input, nodes, edges) => {
45
+ const allRoots = preferredRootIds(input);
46
+ const rootNodeIds = allRoots.slice(0, 1_000);
47
+ const roots = new Set(rootNodeIds);
48
+ const sortedNodes = [...nodes].sort((left, right) => compareCodePoints(left.node_id, right.node_id));
49
+ const retainedNodes = [
50
+ ...sortedNodes.filter(({ node_id: id }) => roots.has(id)),
51
+ ...sortedNodes.filter(({ node_id: id }) => !roots.has(id)),
52
+ ].slice(0, 100_000);
53
+ const retainedIds = new Set(retainedNodes.map(({ node_id: id }) => id));
54
+ const retainedEdges = [...edges]
55
+ .sort((left, right) => compareCodePoints(left.edge_id, right.edge_id))
56
+ .filter(({ source_node_id: source, target_node_id: target }) => retainedIds.has(source) && retainedIds.has(target))
57
+ .slice(0, 200_000);
58
+ return {
59
+ rootNodeIds,
60
+ nodes: retainedNodes,
61
+ edges: retainedEdges,
62
+ omittedItems: allRoots.length -
63
+ rootNodeIds.length +
64
+ (nodes.length - retainedNodes.length) +
65
+ (edges.length - retainedEdges.length),
66
+ };
67
+ };
68
+ const preferredRootIds = (input) => {
69
+ const runtime = [...input.runtime.targetNodeByEvidenceId.values()].map(({ node_id: id }) => id);
70
+ const application = input.layers
71
+ .filter(({ role }) => role === "application")
72
+ .flatMap(({ graph }) => graph.root_node_ids);
73
+ const supplemental = input.layers
74
+ .filter(({ role }) => role !== "application")
75
+ .flatMap(({ graph }) => graph.root_node_ids);
76
+ return [...new Set([...runtime, ...application, ...supplemental])];
77
+ };
78
+ const graphCoverageFacts = (input, omittedNodeObservations) => {
79
+ const projectionOmissions = input.runtime.omittedEntities +
80
+ input.omittedReconciliationItems +
81
+ omittedNodeObservations;
82
+ const captureTruncated = input.captures.some(({ inspection }) => inspection.completeness.conditions.includes("truncated"));
83
+ const captureHasUnknownOmissions = input.captures.some(({ inspection }) => inspection.completeness.unavailable_sections.length > 0);
84
+ const inputTruncated = input.layers.some(({ graph }) => graph.coverage.truncated) ||
85
+ captureTruncated;
86
+ const outputTruncated = projectionOmissions > 0;
87
+ const sourceOmissions = input.layers.reduce((total, { graph }) => total + (graph.coverage.omitted_count ?? 0), 0);
88
+ const omissionsKnown = !captureTruncated &&
89
+ !captureHasUnknownOmissions &&
90
+ input.layers.every(({ graph }) => graph.coverage.omitted_count !== null);
91
+ return {
92
+ projectionOmissions,
93
+ knownOmissions: projectionOmissions + sourceOmissions,
94
+ omissionsKnown,
95
+ inputTruncated,
96
+ outputTruncated,
97
+ truncated: inputTruncated || outputTruncated,
98
+ complete: !inputTruncated &&
99
+ !outputTruncated &&
100
+ input.layers.every(({ graph }) => graph.coverage.status === "complete") &&
101
+ input.captures.every(({ inspection }) => inspection.completeness.status === "complete_within_window"),
102
+ };
103
+ };
104
+ const graphCoverage = (input, facts, nodeCount) => facts.complete
105
+ ? { status: "complete", truncated: false, omitted_count: 0, limits: [] }
106
+ : facts.truncated
107
+ ? {
108
+ status: "partial",
109
+ truncated: true,
110
+ omitted_count: facts.omissionsKnown ? facts.knownOmissions : null,
111
+ limits: [
112
+ ...(facts.inputTruncated
113
+ ? [
114
+ {
115
+ name: "runtime-reconciliation-input-coverage",
116
+ value: input.layers.length + input.captures.length,
117
+ unit: "items",
118
+ },
119
+ ]
120
+ : []),
121
+ ...(facts.outputTruncated
122
+ ? [
123
+ {
124
+ name: "runtime-reconciliation-output-limits",
125
+ value: nodeCount,
126
+ unit: "items",
127
+ },
128
+ ]
129
+ : []),
130
+ ],
131
+ }
132
+ : {
133
+ status: "partial",
134
+ truncated: false,
135
+ omitted_count: facts.omissionsKnown ? facts.knownOmissions : null,
136
+ limits: [],
137
+ };
138
+ const mergeNodes = (nodes) => {
139
+ const grouped = new Map();
140
+ for (const node of nodes)
141
+ grouped.set(node.node_id, [...(grouped.get(node.node_id) ?? []), node]);
142
+ let omittedObservations = 0;
143
+ const merged = [...grouped.values()].map((group) => {
144
+ const first = group[0];
145
+ if (first === undefined)
146
+ throw new TypeError("Empty JAG node group");
147
+ if (group.some(({ kind, identity }) => kind !== first.kind ||
148
+ JSON.stringify(identity) !== JSON.stringify(first.identity)))
149
+ throw new TypeError("Colliding JAG node identifiers disagree");
150
+ const observations = [
151
+ ...new Map(group
152
+ .flatMap(({ observations: values }) => values)
153
+ .map((observation) => [observation.observation_id, observation])).values(),
154
+ ].sort((left, right) => compareCodePoints(left.observation_id, right.observation_id));
155
+ omittedObservations += Math.max(0, observations.length - 64);
156
+ return createJavaScriptApplicationNode({
157
+ kind: first.kind,
158
+ identity: first.identity,
159
+ observations: observations
160
+ .slice(0, 64)
161
+ .map(({ observation_id: _id, identifier_strategy: _strategy, ...value }) => value),
162
+ });
163
+ });
164
+ return { nodes: merged, omittedObservations };
165
+ };
166
+ const uniqueEdges = (edges) => [
167
+ ...new Map(edges.map((edge) => [edge.edge_id, edge])).values(),
168
+ ];
169
+ const uniqueSorted = (values) => [...new Set(values)].sort(compareCodePoints);