rea-agents 2.5.0 → 3.1.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 (253) hide show
  1. package/README.md +20 -12
  2. package/bridge/ghidra/ReaGhidraBridge.java +477 -4
  3. package/bridge/hopper_bridge.py +54 -4
  4. package/dist/application/AnalysisContextQueries.js +142 -0
  5. package/dist/application/AnalysisSnapshotCache.js +4 -2
  6. package/dist/application/ApplicationWorkflowEvidenceResolver.js +19 -11
  7. package/dist/application/ArtifactInventory/policy.js +17 -0
  8. package/dist/application/ArtifactInventory/reader.js +1 -4
  9. package/dist/application/ArtifactInventory/scanCanonical.js +0 -3
  10. package/dist/application/ArtifactInventory/scanReader.js +7 -7
  11. package/dist/application/ArtifactInventory/types.js +1 -5
  12. package/dist/application/BinarySession.js +19 -20
  13. package/dist/application/BinarySessionComposition.js +21 -0
  14. package/dist/application/BinarySessionRecords.js +106 -10
  15. package/dist/application/BinarySessionStatus.js +11 -5
  16. package/dist/application/BrowserEvidence.js +3 -5
  17. package/dist/application/CapabilityClientRequirements.js +26 -0
  18. package/dist/application/CapabilityInventory.js +140 -55
  19. package/dist/application/ClientRegistrationStatus.js +4 -1
  20. package/dist/application/CrossVersionInventory.js +7 -6
  21. package/dist/application/DirectAnalysis.js +6 -2
  22. package/dist/application/ElectronActiveEvidence.js +55 -0
  23. package/dist/application/ElectronActiveObservationPort.js +1 -0
  24. package/dist/application/ElectronActiveObservationService.js +81 -0
  25. package/dist/application/EnhancedTools.js +49 -17
  26. package/dist/application/EvidenceBundleCommands.js +5 -1
  27. package/dist/application/EvidenceLedger.js +53 -17
  28. package/dist/application/JavaScriptArtifactAnalysis.js +13 -4
  29. package/dist/application/JavaScriptReplayPermission.js +1 -1
  30. package/dist/application/JavaScriptReplayService.js +23 -15
  31. package/dist/application/LazyAnalysisProvider.js +77 -0
  32. package/dist/application/LoopbackReplay.js +1 -1
  33. package/dist/application/ManagedRuntimeCorrelationService.js +9 -5
  34. package/dist/application/NativeApiInspection.js +80 -0
  35. package/dist/application/NodeRuntimeCharacterizationService.js +8 -9
  36. package/dist/application/ProcessCaptureLifecycle.js +5 -0
  37. package/dist/application/ProcessCli.js +2 -1
  38. package/dist/application/ProcessHarness.js +8 -3
  39. package/dist/application/ProcessNormalization.js +2 -1
  40. package/dist/application/ProjectPermissionStore.js +1 -0
  41. package/dist/application/ReferenceSourceImport.js +2 -2
  42. package/dist/application/SessionProviderRouter.js +6 -6
  43. package/dist/application/SetupClientConfiguration.js +10 -3
  44. package/dist/application/WindowsCapabilities.js +5 -4
  45. package/dist/application/runtime.js +26 -9
  46. package/dist/artifacts/ArtifactProvider.js +8 -10
  47. package/dist/artifacts/SafeOutputTree.js +7 -8
  48. package/dist/browser/CdpCaptureStorageFingerprints.js +10 -7
  49. package/dist/browser/CdpElectronInspection.js +3 -1
  50. package/dist/browser/JavaScriptRuntimeScope.js +5 -0
  51. package/dist/browser/PlaywrightBrowserScenarioProvider.js +8 -2
  52. package/dist/browser/PlaywrightElectronActiveActions.js +324 -0
  53. package/dist/browser/PlaywrightElectronActiveProvider.js +294 -0
  54. package/dist/browser/PlaywrightScenarioBrowser.js +4 -4
  55. package/dist/browser/PlaywrightScenarioSession.js +4 -4
  56. package/dist/browser/SensitiveTextCapture.js +1 -1
  57. package/dist/browser/V8InspectorCaptureProjection.js +1 -0
  58. package/dist/browser/V8InspectorProvider.js +3 -3
  59. package/dist/catalogIdentity.js +15 -9
  60. package/dist/cli/artifactCommands.js +5 -3
  61. package/dist/cli/coreAnalysisCommands.js +41 -0
  62. package/dist/cli/managedCommands.js +1 -1
  63. package/dist/cliApplicationCommands.js +2 -2
  64. package/dist/cliBrowserAdvancedCommands.js +11 -5
  65. package/dist/cliBrowserCommands.js +14 -7
  66. package/dist/cliCommandNames.js +2 -0
  67. package/dist/cliElectronCommands.js +46 -4
  68. package/dist/cliJavaScriptRuntimeCommands.js +14 -6
  69. package/dist/cliObservationOptions.js +4 -0
  70. package/dist/cliPolicyCommands.js +1 -0
  71. package/dist/config/browserScenario.js +77 -0
  72. package/dist/config/electronAutomation.js +35 -0
  73. package/dist/config/environment.js +6 -0
  74. package/dist/config/javascriptReplay.js +41 -0
  75. package/dist/config/managedRuntime.js +25 -0
  76. package/dist/config/parseConfig.js +56 -200
  77. package/dist/config/parsers.js +10 -1
  78. package/dist/config/passiveObservation.js +157 -0
  79. package/dist/config/processCapture.js +47 -0
  80. package/dist/contracts/applicationToolContracts.js +2 -5
  81. package/dist/contracts/applicationWorkflowInputContracts.js +86 -96
  82. package/dist/contracts/artifactToolContracts.js +35 -37
  83. package/dist/contracts/browserToolContracts.js +2 -2
  84. package/dist/contracts/electronToolContracts.js +30 -1
  85. package/dist/contracts/enhancedInputs.js +21 -27
  86. package/dist/contracts/functionWorkflowToolContracts.js +29 -0
  87. package/dist/contracts/managedToolContracts.js +4 -9
  88. package/dist/contracts/managedWorkflowExamples.js +12 -9
  89. package/dist/contracts/managedWorkflowToolContracts.js +30 -27
  90. package/dist/contracts/nativeToolContracts.js +2 -3
  91. package/dist/contracts/promptContracts.js +14 -15
  92. package/dist/contracts/sessionToolSchemas.js +61 -0
  93. package/dist/contracts/toolContractExamples.js +4 -0
  94. package/dist/contracts/toolContractHelpers.js +23 -0
  95. package/dist/contracts/toolContracts.js +12 -67
  96. package/dist/contracts/toolEffects.js +19 -0
  97. package/dist/contracts/toolOutputSchemaGroups.js +66 -11
  98. package/dist/contracts/toolOutputSchemaPrimitives.js +76 -26
  99. package/dist/contracts/toolSchemaMetadata.js +128 -0
  100. package/dist/doctorRuntime.js +1 -1
  101. package/dist/domain/analysisErrorPresentation.js +8 -2
  102. package/dist/domain/analysisErrorProjection.js +1 -0
  103. package/dist/domain/androidApplication.js +2 -0
  104. package/dist/domain/appleApplication.js +2 -0
  105. package/dist/domain/binaryTarget.js +7 -5
  106. package/dist/domain/binaryTargetTypes.js +1 -0
  107. package/dist/domain/browserCaptureComparison.js +21 -69
  108. package/dist/domain/browserObservation.js +22 -9
  109. package/dist/domain/bytecodeProvider.js +177 -0
  110. package/dist/domain/callPath.js +3 -2
  111. package/dist/domain/conformancePackage.js +169 -0
  112. package/dist/domain/conformanceReplay.js +104 -0
  113. package/dist/domain/conformanceTrustGate.js +328 -0
  114. package/dist/domain/customProtocolCapture.js +137 -0
  115. package/dist/domain/electronActiveObservation.js +277 -0
  116. package/dist/domain/electronObservation.js +15 -11
  117. package/dist/domain/electronStaticAnalysisValues.js +4 -1
  118. package/dist/domain/eventProcessTree.js +217 -0
  119. package/dist/domain/evidenceBundle.js +47 -0
  120. package/dist/domain/functionComparisonNormalization.js +15 -8
  121. package/dist/domain/functionDossierEvidence.js +9 -4
  122. package/dist/domain/hopperStartupFailure.js +1 -1
  123. package/dist/domain/hopperValues.js +68 -68
  124. package/dist/domain/inputIssueProjection.js +11 -2
  125. package/dist/domain/investigationWorkspace.js +16 -15
  126. package/dist/domain/javascriptExportShapeComparisonSchemas.js +2 -2
  127. package/dist/domain/javascriptReplay.js +79 -63
  128. package/dist/domain/javascriptRuntimeObservation.js +1 -0
  129. package/dist/domain/javascriptRuntimeReconciliationActive.js +89 -0
  130. package/dist/domain/javascriptRuntimeReconciliationGraph.js +11 -10
  131. package/dist/domain/javascriptRuntimeReconciliationMatching.js +57 -49
  132. package/dist/domain/javascriptRuntimeReconciliationParsing.js +5 -1
  133. package/dist/domain/javascriptRuntimeReconciliationResult.js +21 -14
  134. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
  135. package/dist/domain/javascriptSemanticAnalysis.js +8 -12
  136. package/dist/domain/javascriptSourceParser.js +15 -0
  137. package/dist/domain/javascriptStaticAnalysis.js +8 -12
  138. package/dist/domain/knownPageCoverage.js +15 -7
  139. package/dist/domain/mobileApplicationInvestigation.js +159 -0
  140. package/dist/domain/nativeApiBoundary.js +138 -0
  141. package/dist/domain/nodeRuntimeCharacterization.js +14 -13
  142. package/dist/domain/objcSwiftMetadata.js +150 -0
  143. package/dist/domain/packageAnalysis.js +123 -0
  144. package/dist/domain/peInspection.js +196 -0
  145. package/dist/domain/processCaptureReactiveValidation.js +8 -3
  146. package/dist/domain/processCaptureValidation.js +7 -3
  147. package/dist/domain/processComparison.js +12 -7
  148. package/dist/domain/processObservation.js +5 -6
  149. package/dist/domain/processReactiveMatching.js +14 -7
  150. package/dist/domain/processReactiveTransition.js +9 -3
  151. package/dist/domain/processScenario.js +6 -3
  152. package/dist/domain/processTraceComparison.js +3 -2
  153. package/dist/domain/protocolCapture.js +245 -0
  154. package/dist/domain/reconstructionReadinessSchemas.js +30 -2
  155. package/dist/domain/referenceSourceImportParsing.js +2 -2
  156. package/dist/domain/replayMachineRuntime.js +5 -3
  157. package/dist/domain/sourceToBundleComparison.js +2 -2
  158. package/dist/domain/sourceToBundleComparisonSchemas.js +8 -8
  159. package/dist/domain/sourceToBundleSignals.js +7 -1
  160. package/dist/domain/staticRuntimeCorrelation.js +7 -5
  161. package/dist/domain/webBundleAnalysis.js +14 -14
  162. package/dist/domain/webCaptureDiff.js +15 -12
  163. package/dist/dotnet/ManagedNativeBoundaryInspector.js +2 -3
  164. package/dist/dotnet/ManagedStaticProvider.js +34 -5
  165. package/dist/generatedMcpToolCatalog.js +37 -0
  166. package/dist/generatedPackageMetadata.js +4 -4
  167. package/dist/ghidra/GhidraClient.js +1 -1
  168. package/dist/ghidra/GhidraClientStartup.js +1 -1
  169. package/dist/ghidra/GhidraDefaults.js +1 -1
  170. package/dist/ghidra/GhidraFunctionValues.js +44 -16
  171. package/dist/ghidra/GhidraInventoryValues.js +57 -47
  172. package/dist/ghidra/GhidraProvider.js +18 -10
  173. package/dist/ghidra/GhidraProviderCapabilities.js +45 -39
  174. package/dist/ghidra/GhidraSocketConnection.js +1 -1
  175. package/dist/ghidra/protocol.js +19 -42
  176. package/dist/hopper/BridgeLauncher.js +3 -1
  177. package/dist/hopper/HopperAnalysisProfile.js +2 -4
  178. package/dist/hopper/HopperCleanup.js +5 -6
  179. package/dist/hopper/HopperClient.js +27 -3
  180. package/dist/hopper/HopperProvider.js +42 -44
  181. package/dist/hopper/HopperRequestQueue.js +32 -4
  182. package/dist/hopper/HopperResponseStream.js +2 -2
  183. package/dist/hopper/LinuxPrivateDisplayProbe.js +16 -10
  184. package/dist/hopper/protocol.js +63 -21
  185. package/dist/main/reload.js +1 -6
  186. package/dist/main/state.js +0 -14
  187. package/dist/main/transport.js +31 -41
  188. package/dist/main.js +17 -13
  189. package/dist/mcpDoctor.js +4 -26
  190. package/dist/mcpStartupPolicy.js +14 -0
  191. package/dist/process/PrivateRuntimeRoot.js +17 -0
  192. package/dist/process/ProcessOwnership.js +64 -128
  193. package/dist/process/ProcessOwnershipIdentity.js +13 -0
  194. package/dist/process/ProcessOwnershipObservation.js +88 -0
  195. package/dist/process/ProcessOwnershipProcessTree.js +22 -0
  196. package/dist/process/ProviderDeadline.js +8 -12
  197. package/dist/process/WindowsAuthority.js +32 -0
  198. package/dist/reference/ReferenceSourceReader.js +3 -3
  199. package/dist/reference/ReferenceSourceReaderEntries.js +2 -2
  200. package/dist/replay/JavaScriptReplayWorker.js +95 -11
  201. package/dist/replay/JavaScriptReplayWorkerTypes.js +1 -0
  202. package/dist/replay/LinuxJavaScriptReplayRunner.js +10 -15
  203. package/dist/replay/ReplayOutcome.js +26 -15
  204. package/dist/replay/ReplayWorkerProtocol.js +34 -29
  205. package/dist/server/createServer.js +101 -144
  206. package/dist/server/mcpClientMetadata.js +32 -0
  207. package/dist/server/registerApplicationTools/characterization.js +6 -13
  208. package/dist/server/registerApplicationTools/compareExportShapes.js +2 -7
  209. package/dist/server/registerApplicationTools/compareSourceToBundle.js +2 -7
  210. package/dist/server/registerApplicationTools/compareVersions.js +3 -8
  211. package/dist/server/registerApplicationTools/controlledReplay.js +6 -11
  212. package/dist/server/registerApplicationTools/coverage.js +13 -19
  213. package/dist/server/registerApplicationTools/obligationLedger.js +1 -6
  214. package/dist/server/registerApplicationTools/readiness.js +1 -6
  215. package/dist/server/registerApplicationTools/traceFeature.js +3 -8
  216. package/dist/server/registerApplicationTools/traceSemantics.js +1 -6
  217. package/dist/server/registerArtifactComparisonTool.js +12 -16
  218. package/dist/server/registerBrowserScenarioTool.js +1 -6
  219. package/dist/server/registerBrowserTools.js +37 -79
  220. package/dist/server/registerBundleComparisonTool.js +10 -14
  221. package/dist/server/registerCloseLifecycleTool.js +6 -14
  222. package/dist/server/registerElectronTools.js +30 -47
  223. package/dist/server/registerEnhancedTools.js +124 -122
  224. package/dist/server/registerEvidenceResources.js +50 -101
  225. package/dist/server/registerEvidenceTools.js +5 -9
  226. package/dist/server/registerFunctionComparisonTool.js +11 -15
  227. package/dist/server/registerInvestigationTools.js +42 -59
  228. package/dist/server/registerJavaScriptApplicationGraphResource.js +0 -4
  229. package/dist/server/registerJavaScriptRuntimeObservationTools.js +13 -27
  230. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +4 -9
  231. package/dist/server/registerManagedWorkflowTools/contract.js +2 -3
  232. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +3 -8
  233. package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +3 -8
  234. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +8 -13
  235. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +4 -9
  236. package/dist/server/registerOfficialTools.js +8 -9
  237. package/dist/server/registerProcessComparisonTool.js +19 -24
  238. package/dist/server/registerReconstructionObligationLedgerResource.js +0 -7
  239. package/dist/server/registerReconstructionReadinessResource.js +0 -7
  240. package/dist/server/registerReplayMachineTool.js +4 -10
  241. package/dist/server/registerSessionRecordTools.js +146 -47
  242. package/dist/server/registerSessionStatusTool.js +14 -29
  243. package/dist/server/registerSessionTools.js +45 -41
  244. package/dist/server/sessionAvailabilityPolicy.js +2 -1
  245. package/dist/server/sessionToolPolicies.js +1 -5
  246. package/dist/server/toolRegistrationOptions.js +4 -177
  247. package/dist/server/toolResult.js +14 -18
  248. package/package.json +35 -16
  249. package/scripts/electron-active-hook-boundaries.cjs +394 -0
  250. package/scripts/electron-active-hook.cjs +501 -0
  251. package/skills/reverse-engineer-anything/SKILL.md +10 -3
  252. package/dist/server/DynamicToolAvailability.js +0 -70
  253. package/dist/server/toolInputValidation.js +0 -77
@@ -125,13 +125,20 @@ const matchTerminalText = (trigger, context) => {
125
125
  overflow: false,
126
126
  };
127
127
  };
128
- const mergeMatches = (matches) => ({
129
- matched: matches.every(({ matched }) => matched),
130
- eventIds: [...new Set(matches.flatMap(({ eventIds }) => eventIds))],
131
- consumeIds: [...new Set(matches.flatMap(({ consumeIds }) => consumeIds))],
132
- lastOrder: Math.max(-1, ...matches.map(({ lastOrder }) => lastOrder)),
133
- overflow: matches.some(({ overflow }) => overflow),
134
- });
128
+ const mergeMatches = (matches) => {
129
+ const base = {
130
+ eventIds: [...new Set(matches.flatMap(({ eventIds }) => eventIds))],
131
+ consumeIds: [...new Set(matches.flatMap(({ consumeIds }) => consumeIds))],
132
+ lastOrder: Math.max(-1, ...matches.map(({ lastOrder }) => lastOrder)),
133
+ };
134
+ return matches.every(({ matched }) => matched)
135
+ ? { ...base, matched: true, overflow: false }
136
+ : {
137
+ ...base,
138
+ matched: false,
139
+ overflow: matches.some(({ overflow }) => overflow),
140
+ };
141
+ };
135
142
  const matchEarliestPrefix = (trigger, context) => {
136
143
  for (const observation of context.snapshot.observations) {
137
144
  if (observation.capture_order <= context.afterOrder)
@@ -11,6 +11,8 @@ const incrementCounter = (counters, id) => {
11
11
  };
12
12
  /** Commit one uniquely selected transition after its declarative effects succeed. */
13
13
  const applyProcessReactiveTransition = (input) => {
14
+ if (input.effectResults.length !== input.transition.actions.length)
15
+ throw new TypeError("Reactive transition effects do not match the admitted actions");
14
16
  const outcome = input.transition.target.kind === "finish"
15
17
  ? input.transition.target.outcome
16
18
  : null;
@@ -31,13 +33,17 @@ const applyProcessReactiveTransition = (input) => {
31
33
  for (const eventId of input.consumeEventIds)
32
34
  consumed.add(eventId);
33
35
  const checkpoints = [...input.snapshot.checkpoints];
34
- for (const [index, action] of input.transition.actions.entries())
36
+ for (const [index, action] of input.transition.actions.entries()) {
37
+ const effect = input.effectResults[index];
38
+ if (effect === undefined)
39
+ throw new TypeError("Reactive transition effect is missing");
35
40
  if (action.type === "checkpoint")
36
41
  checkpoints.push({
37
42
  name: action.name,
38
- event_id: input.effectResults[index].observation.event_id,
39
- capture_order: input.effectResults[index].observation.capture_order,
43
+ event_id: effect.observation.event_id,
44
+ capture_order: effect.observation.capture_order,
40
45
  });
46
+ }
41
47
  const completedCaptureOrder = Math.max(input.observation.capture_order, ...input.effectResults.map(({ observation }) => observation.capture_order));
42
48
  let next = {
43
49
  ...input.snapshot,
@@ -283,7 +283,9 @@ export const processScenarioSchema = z
283
283
  .strict()
284
284
  .superRefine((scenario, context) => {
285
285
  for (let index = 1; index < scenario.events.length; index += 1) {
286
- if (scenario.events[index].at_ms < scenario.events[index - 1].at_ms) {
286
+ const event = scenario.events[index];
287
+ const previous = scenario.events[index - 1];
288
+ if (eventsOutOfOrder(event, previous)) {
287
289
  context.addIssue({
288
290
  code: "custom",
289
291
  message: "events must be ordered by at_ms",
@@ -361,15 +363,16 @@ export const processScenarioSchema = z
361
363
  path: ["replay"],
362
364
  });
363
365
  });
366
+ const eventsOutOfOrder = (event, previous) => event !== undefined && previous !== undefined && event.at_ms < previous.at_ms;
364
367
  /** Parse untrusted process scenario input and apply safe default budgets. */
365
368
  export const parseProcessScenario = (input) => processScenarioSchema.parse(input);
366
369
  const isWithin = (candidate, root) => resolve(candidate) === resolve(root) ||
367
370
  resolve(candidate).startsWith(`${resolve(root)}${resolve(root).endsWith("/") ? "" : "/"}`);
368
371
  /** Evaluate scenario authority before any process or filesystem side effect occurs. */
369
372
  export const authorizeProcessScenario = (scenario, policy) => {
370
- if (!policy.enabled)
373
+ if (policy.status === "disabled")
371
374
  return { allowed: false, reason: "process capture is disabled" };
372
- if (scenario.network_access === "host" && !policy.allowExternalNetwork)
375
+ if (scenario.network_access === "host" && policy.networkAccess === "none")
373
376
  return {
374
377
  allowed: false,
375
378
  reason: "host network access is not approved by operator policy",
@@ -9,8 +9,9 @@ export const compareProcessTraces = (left, right, specificationInput) => {
9
9
  ...validateProcessCapture(left),
10
10
  ...validateProcessCapture(right),
11
11
  ];
12
- if (captureIssues.length > 0)
13
- throw new TypeError(`Invalid Process Capture v4: ${captureIssues[0].path}`);
12
+ const firstCaptureIssue = captureIssues.at(0);
13
+ if (firstCaptureIssue !== undefined)
14
+ throw new TypeError(`Invalid Process Capture v4: ${firstCaptureIssue.path}`);
14
15
  const specification = processTraceSpecificationSchema.parse(specificationInput);
15
16
  const leftEvaluation = evaluateProcessTraceSide(left, specification);
16
17
  const rightEvaluation = evaluateProcessTraceSide(right, specification);
@@ -0,0 +1,245 @@
1
+ import { z } from "zod";
2
+ import { jsonValueSchema } from "./jsonValue.js";
3
+ /** Supported protocol families for structured protocol capture. */
4
+ export const protocolFamilySchema = z.enum([
5
+ "grpc",
6
+ "protobuf",
7
+ "json-rpc",
8
+ "messagepack",
9
+ ]);
10
+ /** A decoded field from a protocol message. */
11
+ export const decodedFieldSchema = z.strictObject({
12
+ /** Field name or path within the message structure. */
13
+ path: z.string().min(1),
14
+ /** Wire type or encoding hint. */
15
+ wire_type: z.string().nullable(),
16
+ /** Decoded field value. */
17
+ value: jsonValueSchema.nullable(),
18
+ /** Whether this field value was inferred rather than decoded. */
19
+ inferred: z.boolean().default(false),
20
+ });
21
+ /** Schema inference hypothesis for a repeated message pattern. */
22
+ export const schemaHypothesisSchema = z.strictObject({
23
+ /** Hypothesized field name. */
24
+ field_name: z.string().min(1),
25
+ /** Inferred type. */
26
+ inferred_type: z.string().min(1),
27
+ /** Confidence: 0-1 */
28
+ confidence: z.number().min(0).max(1),
29
+ /** Supporting evidence count. */
30
+ evidence_count: z.number().int().nonnegative(),
31
+ });
32
+ /** Result of decoding a single protocol message. */
33
+ export const protocolMessageSchema = z.strictObject({
34
+ /** Monotonic sequence number. */
35
+ sequence: z.number().int().nonnegative(),
36
+ /** Timestamp in milliseconds. */
37
+ at_ms: z.number().int().nonnegative(),
38
+ /** Protocol family. */
39
+ family: protocolFamilySchema,
40
+ /** Direction of the message. */
41
+ direction: z.enum(["request", "response"]),
42
+ /** Transport endpoint or path (e.g. gRPC method path). */
43
+ endpoint: z.string().nullable(),
44
+ /** Content type of the raw payload. */
45
+ content_type: z.string().nullable(),
46
+ /** Raw payload bytes as base64. */
47
+ raw_payload: z.string().nullable(),
48
+ /** Decoded fields from the payload. */
49
+ decoded_fields: z.array(decodedFieldSchema).default([]),
50
+ /** Inferred schema hypotheses. */
51
+ schema_hypotheses: z.array(schemaHypothesisSchema).default([]),
52
+ /** Whether decoding was truncated. */
53
+ truncated: z.boolean().default(false),
54
+ /** Whether credentials were detected and redacted. */
55
+ credentials_redacted: z.boolean().default(false),
56
+ });
57
+ /** A captured protocol session with messages and inferred schemas. */
58
+ export const protocolCaptureSchema = z.strictObject({
59
+ /** Protocol family for this capture. */
60
+ family: protocolFamilySchema,
61
+ /** Captured messages in order. */
62
+ messages: z.array(protocolMessageSchema).min(0).max(10_000),
63
+ /** Aggregated schema hypotheses across all messages. */
64
+ inferred_schema: z.array(schemaHypothesisSchema).default([]),
65
+ /** Whether any message was truncated. */
66
+ has_truncated: z.boolean().default(false),
67
+ /** Whether credentials were detected and redacted. */
68
+ credentials_detected: z.boolean().default(false),
69
+ });
70
+ /** Classification of a byte sequence as a known protocol family. */
71
+ export function classifyProtocolFamily(contentType, path) {
72
+ if (contentType) {
73
+ if (contentType.includes("application/grpc"))
74
+ return "grpc";
75
+ if (contentType.includes("application/x-protobuf"))
76
+ return "protobuf";
77
+ if (contentType.includes("application/json-rpc"))
78
+ return "json-rpc";
79
+ if (contentType.includes("application/msgpack") ||
80
+ contentType.includes("application/x-msgpack"))
81
+ return "messagepack";
82
+ }
83
+ if (path) {
84
+ if (path.startsWith("/grpc.") || path.includes("/grpc/"))
85
+ return "grpc";
86
+ if (path.includes("/json-rpc") || path.includes("/jsonrpc"))
87
+ return "json-rpc";
88
+ }
89
+ return null;
90
+ }
91
+ /** Credential-like field names that should be redacted. */
92
+ const CREDENTIAL_PATTERNS = [
93
+ "password",
94
+ "passwd",
95
+ "secret",
96
+ "token",
97
+ "api_key",
98
+ "apikey",
99
+ "authorization",
100
+ "auth",
101
+ "credential",
102
+ "private_key",
103
+ ];
104
+ /** Check if a field path looks like it may contain credentials. */
105
+ export function looksLikeCredential(path) {
106
+ const lower = path.toLowerCase();
107
+ return CREDENTIAL_PATTERNS.some((p) => lower.includes(p));
108
+ }
109
+ /** Decode a JSON-RPC message from raw payload bytes. */
110
+ export function decodeJsonRpc(rawPayload) {
111
+ const text = new TextDecoder().decode(rawPayload);
112
+ const parsed = jsonValueSchema.parse(JSON.parse(text));
113
+ const fields = [];
114
+ if (typeof parsed === "object" && parsed !== null) {
115
+ for (const [key, value] of Object.entries(parsed)) {
116
+ if (looksLikeCredential(key)) {
117
+ fields.push({
118
+ path: key,
119
+ wire_type: "json",
120
+ value: "[REDACTED]",
121
+ inferred: false,
122
+ });
123
+ }
124
+ else {
125
+ fields.push({
126
+ path: key,
127
+ wire_type: "json",
128
+ value,
129
+ inferred: false,
130
+ });
131
+ }
132
+ }
133
+ }
134
+ return { decoded_fields: fields, truncated: false };
135
+ }
136
+ /** Decode a MessagePack message (simplified: only checks basic structure). */
137
+ export function decodeMessagePack(rawPayload) {
138
+ const fields = [];
139
+ // MessagePack uses a single-byte type tag
140
+ if (rawPayload.length === 0) {
141
+ return { decoded_fields: [], truncated: false };
142
+ }
143
+ const tag = rawPayload[0];
144
+ if (tag === undefined)
145
+ return { decoded_fields: [], truncated: false };
146
+ // Map type: 0x80-0x8f (fixmap), 0xde (map16), 0xdf (map32)
147
+ if ((tag >= 0x80 && tag <= 0x8f) || tag === 0xde || tag === 0xdf) {
148
+ fields.push({
149
+ path: "type",
150
+ wire_type: "msgpack",
151
+ value: "map",
152
+ inferred: false,
153
+ });
154
+ }
155
+ // Array type: 0x90-0x9f (fixarray), 0xdc (array16), 0xdd (array32)
156
+ else if ((tag >= 0x90 && tag <= 0x9f) || tag === 0xdc || tag === 0xdd) {
157
+ fields.push({
158
+ path: "type",
159
+ wire_type: "msgpack",
160
+ value: "array",
161
+ inferred: false,
162
+ });
163
+ }
164
+ else {
165
+ fields.push({
166
+ path: "type",
167
+ wire_type: "msgpack",
168
+ value: "unknown",
169
+ inferred: true,
170
+ });
171
+ }
172
+ return {
173
+ decoded_fields: fields,
174
+ truncated: rawPayload.length > 10_000,
175
+ };
176
+ }
177
+ /** Decode a gRPC frame (5-byte header + protobuf payload). */
178
+ export function decodeGrpcFrame(rawPayload) {
179
+ // gRPC uses a 5-byte prefix: 1 byte compressed flag + 4 byte length
180
+ if (rawPayload.length < 5) {
181
+ return {
182
+ decoded_fields: [
183
+ {
184
+ path: "error",
185
+ wire_type: "grpc",
186
+ value: "frame too short",
187
+ inferred: false,
188
+ },
189
+ ],
190
+ truncated: false,
191
+ };
192
+ }
193
+ const compressed = rawPayload[0] !== 0;
194
+ const length = ((rawPayload[1] ?? 0) << 24) |
195
+ ((rawPayload[2] ?? 0) << 16) |
196
+ ((rawPayload[3] ?? 0) << 8) |
197
+ (rawPayload[4] ?? 0);
198
+ return {
199
+ decoded_fields: [
200
+ {
201
+ path: "compressed",
202
+ wire_type: "grpc",
203
+ value: compressed,
204
+ inferred: false,
205
+ },
206
+ {
207
+ path: "message_length",
208
+ wire_type: "grpc",
209
+ value: length,
210
+ inferred: false,
211
+ },
212
+ ],
213
+ truncated: length > 10_000,
214
+ };
215
+ }
216
+ /** Infer schema hypotheses from a set of decoded messages. */
217
+ export function inferMessageSchema(messages) {
218
+ const fieldCounts = new Map();
219
+ for (const msg of messages) {
220
+ for (const field of msg.decoded_fields) {
221
+ const existing = fieldCounts.get(field.path);
222
+ if (existing) {
223
+ existing.count++;
224
+ if (field.wire_type)
225
+ existing.types.add(field.wire_type);
226
+ }
227
+ else {
228
+ fieldCounts.set(field.path, {
229
+ count: 1,
230
+ types: new Set(field.wire_type ?? "unknown"),
231
+ });
232
+ }
233
+ }
234
+ }
235
+ const hypotheses = [];
236
+ for (const [field_name, data] of fieldCounts) {
237
+ hypotheses.push({
238
+ field_name,
239
+ inferred_type: [...data.types].join("|"),
240
+ confidence: Math.min(1, data.count / messages.length || 0),
241
+ evidence_count: data.count,
242
+ });
243
+ }
244
+ return hypotheses;
245
+ }
@@ -197,7 +197,21 @@ export const reconstructionReadinessInputSchema = z.strictObject({
197
197
  closure_history: z.array(closureObservationSchema).min(2).max(1_000),
198
198
  delegation_checks: z.array(delegationCheckSchema).min(1).max(1_000),
199
199
  replay: replaySchema,
200
- stages: z.array(stageSchema).max(20),
200
+ stages: z
201
+ .array(stageSchema)
202
+ .length(9)
203
+ .superRefine((stages, context) => {
204
+ const seen = new Set();
205
+ stages.forEach((stage, index) => {
206
+ if (seen.has(stage.stage_id))
207
+ context.addIssue({
208
+ code: "custom",
209
+ path: [index, "stage_id"],
210
+ message: "Readiness stage IDs must be unique",
211
+ });
212
+ seen.add(stage.stage_id);
213
+ });
214
+ }),
201
215
  });
202
216
  const findingSchema = z.strictObject({
203
217
  code: stableIdSchema,
@@ -233,7 +247,21 @@ export const reconstructionReadinessReportSchema = z.strictObject({
233
247
  cleanup_leak_count: z.number().int().min(0),
234
248
  nondeterministic_replay_count: z.number().int().min(0),
235
249
  }),
236
- stages: z.array(stageSchema).max(20),
250
+ stages: z
251
+ .array(stageSchema)
252
+ .length(9)
253
+ .superRefine((stages, context) => {
254
+ const seen = new Set();
255
+ stages.forEach((stage, index) => {
256
+ if (seen.has(stage.stage_id))
257
+ context.addIssue({
258
+ code: "custom",
259
+ path: [index, "stage_id"],
260
+ message: "Readiness stage IDs must be unique",
261
+ });
262
+ seen.add(stage.stage_id);
263
+ });
264
+ }),
237
265
  findings: z.array(findingSchema).max(10_000),
238
266
  evidence_links: z.array(evidenceIdSchema).max(100_000),
239
267
  snapshot: reconstructionReadinessInputSchema,
@@ -199,11 +199,11 @@ const parseWithBabel = (path, source, language) => {
199
199
  });
200
200
  return { ast, parseState: "parsed" };
201
201
  }
202
- catch (error) {
202
+ catch (cause) {
203
203
  return {
204
204
  ast: undefined,
205
205
  parseState: "unknown",
206
- reason: error instanceof Error ? error.message : "Parse failed",
206
+ reason: cause instanceof Error ? cause.message : "Parse failed",
207
207
  };
208
208
  }
209
209
  };
@@ -20,7 +20,7 @@ const replayEventHeadersSchema = z
20
20
  });
21
21
  });
22
22
  const replayEventFields = {
23
- at_ms: z.number().int().nonnegative().safe(),
23
+ at_ms: z.number().int().safe().nonnegative(),
24
24
  path: z.string().startsWith("/").max(8_192),
25
25
  headers: replayEventHeadersSchema,
26
26
  body: z.string().max(1_000_000),
@@ -51,7 +51,8 @@ export const replayMachineEventSchema = z.discriminatedUnion("protocol", [
51
51
  ]);
52
52
  const parseJson = (value) => {
53
53
  try {
54
- return JSON.parse(value);
54
+ const parsed = JSON.parse(value);
55
+ return parsed;
55
56
  }
56
57
  catch {
57
58
  return undefined;
@@ -70,7 +71,8 @@ const atPath = (value, path) => {
70
71
  current === null ||
71
72
  !Object.hasOwn(current, segment))
72
73
  return undefined;
73
- current = current[segment];
74
+ const next = Reflect.get(current, segment);
75
+ current = next;
74
76
  }
75
77
  return current;
76
78
  };
@@ -135,8 +135,8 @@ const comparisonCoverage = (projection, mappings, factors) => ({
135
135
  const scoringModel = () => ({
136
136
  algorithm: "rea-source-to-bundle-signals/v1",
137
137
  minimum_candidate_score: 20,
138
- weights: Object.entries(SOURCE_TO_BUNDLE_SIGNAL_WEIGHTS).map(([signal, weight]) => ({
139
- signal: signal,
138
+ weights: SOURCE_TO_BUNDLE_SIGNAL_WEIGHTS.map(([signal, weight]) => ({
139
+ signal,
140
140
  weight,
141
141
  })),
142
142
  });
@@ -6,14 +6,14 @@ const digestSchema = z.string().regex(/^[a-f0-9]{64}$/u);
6
6
  const evidenceIdSchema = z.string().regex(/^ev_[a-f0-9]{64}$/u);
7
7
  const nodeIdSchema = z.string().regex(/^jag_node_[a-f0-9]{64}$/u);
8
8
  const boundedTextSchema = z.string().min(1).max(4_096);
9
- export const SOURCE_TO_BUNDLE_SIGNAL_WEIGHTS = {
10
- "exact-source-digest": 100,
11
- "source-map-original-path": 70,
12
- "current-path-exact": 60,
13
- "current-path-suffix": 40,
14
- "basename-match": 20,
15
- "language-extension": 5,
16
- };
9
+ export const SOURCE_TO_BUNDLE_SIGNAL_WEIGHTS = [
10
+ ["exact-source-digest", 100],
11
+ ["source-map-original-path", 70],
12
+ ["current-path-exact", 60],
13
+ ["current-path-suffix", 40],
14
+ ["basename-match", 20],
15
+ ["language-extension", 5],
16
+ ];
17
17
  const sourceToBundleSignalKindSchema = z.enum([
18
18
  "exact-source-digest",
19
19
  "source-map-original-path",
@@ -14,6 +14,12 @@ const PATH_PROPERTIES = [
14
14
  "declared_path",
15
15
  ];
16
16
  const MAX_PATH_SUFFIXES = 128;
17
+ const signalWeight = (kind) => {
18
+ const entry = SOURCE_TO_BUNDLE_SIGNAL_WEIGHTS.find(([signal]) => signal === kind);
19
+ if (entry === undefined)
20
+ throw new TypeError(`Missing source-to-bundle signal weight: ${kind}`);
21
+ return entry[1];
22
+ };
17
23
  /** Keep source-bearing application nodes in stable identifier order. */
18
24
  export const sourceBearingNodes = (nodes) => nodes
19
25
  .filter(({ kind }) => RELEVANT_NODE_KINDS.has(kind))
@@ -145,7 +151,7 @@ const candidateSignals = (source, current) => {
145
151
  };
146
152
  const signal = (kind, sourceValue, currentValues) => ({
147
153
  kind,
148
- weight: SOURCE_TO_BUNDLE_SIGNAL_WEIGHTS[kind],
154
+ weight: signalWeight(kind),
149
155
  source_value: sourceValue,
150
156
  current_values: [...new Set(currentValues)].sort(compareText).slice(0, 64),
151
157
  });
@@ -242,11 +242,12 @@ const selectStatic = (evidence, selector) => {
242
242
  throw new TypeError("Function selector requires function comparison Evidence");
243
243
  const result = functionComparisonResultSchema.parse(evidence.normalized_result);
244
244
  const matches = result.dimensions.filter(({ dimension }) => dimension === selector.dimension);
245
- if (matches.length !== 1)
245
+ const match = matches.at(0);
246
+ if (matches.length !== 1 || match === undefined)
246
247
  throw new TypeError("Function selector must resolve exactly once");
247
248
  return {
248
- status: matches[0].status,
249
- conclusion_kind: matches[0].conclusion_kind,
249
+ status: match.status,
250
+ conclusion_kind: match.conclusion_kind,
250
251
  };
251
252
  }
252
253
  if (evidence.operation !== "compare_artifacts")
@@ -257,9 +258,10 @@ const selectStatic = (evidence, selector) => {
257
258
  result.changes.items.length !== result.changes.total)
258
259
  throw new TypeError("Static/runtime correlation requires complete artifact comparison pagination");
259
260
  const matches = result.changes.items.filter(({ logical_path: path }) => path === selector.logical_path);
260
- if (matches.length !== 1)
261
+ const match = matches.at(0);
262
+ if (matches.length !== 1 || match === undefined)
261
263
  throw new TypeError("Artifact selector must resolve exactly one reported delta");
262
- const status = matches[0].classification;
264
+ const status = match.classification;
263
265
  return {
264
266
  status,
265
267
  conclusion_kind: status === "contradiction"
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { inspectWebPageInputSchema } from "./browserObservation.js";
2
+ import { inspectWebPageWithSourceInputSchema } from "./browserObservation.js";
3
3
  import { webTextArtifactSchema } from "./webContentArtifact.js";
4
4
  const webBundleLimitsSchema = z.object({
5
5
  max_findings: z.number().int().min(1).max(10_000).default(1_000),
@@ -21,12 +21,7 @@ const webBundleLimitsSchema = z.object({
21
21
  max_original_sources: z.number().int().min(1).max(20_000).default(2_000),
22
22
  });
23
23
  /** Capture-and-analyze input with separate source and source-map approvals. */
24
- export const analyzeWebBundleInputSchema = inspectWebPageInputSchema
25
- .safeExtend({
26
- include_script_sources: z.literal(true).default(true),
27
- source_capture_approved: z.literal(true),
28
- fetch_source_maps: z.boolean().default(false),
29
- source_map_fetch_approved: z.boolean().default(false),
24
+ const analyzeWebBundleFactsSchema = inspectWebPageWithSourceInputSchema.safeExtend({
30
25
  analysis_limits: webBundleLimitsSchema.default({
31
26
  max_findings: 1_000,
32
27
  max_ast_nodes: 250_000,
@@ -36,14 +31,19 @@ export const analyzeWebBundleInputSchema = inspectWebPageInputSchema
36
31
  max_source_map_mappings: 10_000,
37
32
  max_original_sources: 2_000,
38
33
  }),
39
- })
34
+ });
35
+ export const analyzeWebBundleInputSchema = z
36
+ .union([
37
+ analyzeWebBundleFactsSchema.safeExtend({
38
+ fetch_source_maps: z.literal(false).default(false),
39
+ source_map_fetch_approved: z.literal(false).default(false),
40
+ }),
41
+ analyzeWebBundleFactsSchema.safeExtend({
42
+ fetch_source_maps: z.literal(true),
43
+ source_map_fetch_approved: z.literal(true),
44
+ }),
45
+ ])
40
46
  .superRefine((input, context) => {
41
- if (input.fetch_source_maps && !input.source_map_fetch_approved)
42
- context.addIssue({
43
- code: "custom",
44
- path: ["source_map_fetch_approved"],
45
- message: "Source-map network fetch requires separate approval",
46
- });
47
47
  if (input.analysis_limits.max_source_map_bytes >
48
48
  input.analysis_limits.max_total_source_map_bytes)
49
49
  context.addIssue({
@@ -228,20 +228,23 @@ const accessibilityComparable = (inspection) => {
228
228
  return { text, nodes, complete };
229
229
  };
230
230
  const accessibilityProjection = (accessibility, includeText, includeNodes) => {
231
- const result = {
232
- total_nodes: accessibility.total_nodes,
233
- };
234
231
  if (!includeNodes)
235
- return result;
232
+ return { total_nodes: accessibility.total_nodes };
236
233
  const nodeIndexes = new Map(accessibility.nodes.map((node, index) => [node.node_id, index]));
237
- result.nodes = accessibility.nodes.map((node) => ({
238
- parent_index: node.parent_id === null ? null : (nodeIndexes.get(node.parent_id) ?? -1),
239
- role: node.role,
240
- ignored: node.ignored,
241
- states: node.states,
242
- ...(includeText ? { name: node.name, description: node.description } : {}),
243
- }));
244
- return result;
234
+ return {
235
+ total_nodes: accessibility.total_nodes,
236
+ nodes: accessibility.nodes.map((node) => ({
237
+ parent_index: node.parent_id === null
238
+ ? null
239
+ : (nodeIndexes.get(node.parent_id) ?? -1),
240
+ role: node.role,
241
+ ignored: node.ignored,
242
+ states: node.states,
243
+ ...(includeText
244
+ ? { name: node.name, description: node.description }
245
+ : {}),
246
+ })),
247
+ };
245
248
  };
246
249
  const storageKeysComparable = (inspection) => sectionsComplete(inspection, ["storage_keys"]);
247
250
  const storageComparable = (before, after, keysComplete, usageComplete) => keysComplete &&
@@ -59,8 +59,7 @@ const emptyInspection = (target, bytes, classification, issues = []) => managedN
59
59
  "Static inspection does not load or execute target code, so native export resolution is not performed.",
60
60
  ],
61
61
  });
62
- const readBoundaryInventory = (bytes, pe, limits) => {
63
- const cli = pe.cli;
62
+ const readBoundaryInventory = (bytes, pe, cli, limits) => {
64
63
  const metadataOffset = pe.rvaToOffset(cli.metadata.rva, cli.metadata.size, "cli.metadata");
65
64
  const layout = readManagedMetadataLayout(bytes, metadataOffset, cli.metadata.size, limits.maxTableRows);
66
65
  const resourceDirectory = {
@@ -104,7 +103,7 @@ export const inspectManagedNativeBoundariesBytes = (bytes, target, limits) => {
104
103
  let layout;
105
104
  let inventory;
106
105
  try {
107
- ({ layout, inventory } = readBoundaryInventory(bytes, pe, limits));
106
+ ({ layout, inventory } = readBoundaryInventory(bytes, pe, pe.cli, limits));
108
107
  }
109
108
  catch (cause) {
110
109
  if (!(cause instanceof ManagedReaderFailure))