rea-agents 1.7.0 → 2.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 (333) hide show
  1. package/README.md +112 -59
  2. package/bridge/ghidra/ReaGhidraBridge.java +96 -11
  3. package/dist/application/ArtifactExtraction.js +1 -1
  4. package/dist/application/ArtifactInventory/classify.js +42 -0
  5. package/dist/application/ArtifactInventory/hash.js +43 -0
  6. package/dist/application/ArtifactInventory/reader.js +41 -0
  7. package/dist/application/ArtifactInventory/scanCanonical.js +155 -0
  8. package/dist/application/ArtifactInventory/scanReader.js +124 -0
  9. package/dist/application/ArtifactInventory/types.js +10 -0
  10. package/dist/application/ArtifactInventory.js +9 -351
  11. package/dist/application/AuthorizedArtifactInventory.js +2 -2
  12. package/dist/application/BinarySession.js +47 -270
  13. package/dist/application/BinarySessionExecution.js +28 -0
  14. package/dist/application/BinarySessionOpen.js +39 -0
  15. package/dist/application/BinarySessionRecords.js +149 -0
  16. package/dist/application/BinarySessionStatus.js +75 -0
  17. package/dist/application/CapabilityInventory.js +42 -2
  18. package/dist/application/ClientRegistrationStatus.js +1 -1
  19. package/dist/application/CrossVersionInventory.js +8 -2
  20. package/dist/application/CrossVersionInvestigation.js +11 -29
  21. package/dist/application/CrossVersionInvestigationCollections.js +23 -0
  22. package/dist/application/DirectAnalysis.js +47 -44
  23. package/dist/application/Doctor.js +165 -197
  24. package/dist/application/DoctorDiagnostics.js +180 -0
  25. package/dist/application/ElectronBoundaryAnalysis.js +112 -0
  26. package/dist/application/ElectronBoundaryGraph.js +9 -0
  27. package/dist/application/ElectronBoundaryGraphContext.js +62 -0
  28. package/dist/application/ElectronBoundaryGraphIpc.js +242 -0
  29. package/dist/application/ElectronBoundaryGraphNative.js +86 -0
  30. package/dist/application/ElectronBoundaryGraphWindows.js +223 -0
  31. package/dist/application/EnhancedToolPagination.js +22 -0
  32. package/dist/application/EnhancedToolTypes.js +4 -0
  33. package/dist/application/EnhancedTools.js +58 -50
  34. package/dist/application/InstrumentedJavaScriptReplayHost.js +36 -0
  35. package/dist/application/InvestigationProviders.js +30 -0
  36. package/dist/application/InvestigationWorkspaceStore.js +24 -10
  37. package/dist/application/JavaScriptApplicationEvidence.js +26 -0
  38. package/dist/application/JavaScriptApplicationEvidenceGraph.js +89 -0
  39. package/dist/application/JavaScriptApplicationService.js +74 -0
  40. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +29 -0
  41. package/dist/application/JavaScriptApplicationWorkflowService.js +90 -0
  42. package/dist/application/JavaScriptArtifactAnalysis.js +52 -7
  43. package/dist/application/JavaScriptArtifactFiles.js +6 -2
  44. package/dist/application/JavaScriptArtifactGraphBuilder.js +82 -17
  45. package/dist/application/JavaScriptArtifactGraphBundlers.js +225 -0
  46. package/dist/application/JavaScriptArtifactGraphContext.js +37 -36
  47. package/dist/application/JavaScriptArtifactGraphDocuments.js +27 -4
  48. package/dist/application/JavaScriptArtifactGraphEvidence.js +24 -14
  49. package/dist/application/JavaScriptArtifactGraphFindings.js +54 -8
  50. package/dist/application/JavaScriptArtifactGraphStructure.js +29 -101
  51. package/dist/application/JavaScriptArtifactPathResolution.js +269 -0
  52. package/dist/application/JavaScriptArtifactReconstruction.js +4 -1
  53. package/dist/application/JavaScriptArtifactReconstructionInput.js +2 -83
  54. package/dist/application/JavaScriptJsonModules.js +39 -0
  55. package/dist/application/JavaScriptModuleRelationships.js +262 -0
  56. package/dist/application/JavaScriptReplayPermission.js +16 -0
  57. package/dist/application/JavaScriptReplayPlanning.js +201 -0
  58. package/dist/application/JavaScriptReplayService.js +292 -0
  59. package/dist/application/JavaScriptRuntimeReconciliationEvidence.js +25 -0
  60. package/dist/application/JavaScriptRuntimeReconciliationService.js +27 -0
  61. package/dist/application/LinuxHopper.js +10 -0
  62. package/dist/application/MacHopper.js +22 -11
  63. package/dist/application/ManagedApplicationGraphService.js +55 -0
  64. package/dist/application/ManagedMemberComparisonService.js +122 -0
  65. package/dist/application/ManagedNativeVerificationService.js +39 -0
  66. package/dist/application/ManagedReconstructionService.js +58 -0
  67. package/dist/application/ManagedRuntimeCorrelationService.js +103 -0
  68. package/dist/application/NodeRuntimeCharacterizationService.js +196 -0
  69. package/dist/application/PermissionAuthority.js +106 -63
  70. package/dist/application/ProcessCaptureCapability.js +1 -1
  71. package/dist/application/ProcessCapturePermission.js +13 -0
  72. package/dist/application/ProcessCli.js +2 -12
  73. package/dist/application/ProcessHarness.js +1 -1
  74. package/dist/application/ProcessSampling.js +15 -11
  75. package/dist/application/ProjectPermissionStore.js +49 -9
  76. package/dist/application/RealHopperAssertions.js +76 -0
  77. package/dist/application/ReconstructionCoverageService.js +69 -0
  78. package/dist/application/ReconstructionCoverageWorkspaceStore.js +31 -0
  79. package/dist/application/RuntimeExecutableDiagnostics.js +172 -0
  80. package/dist/application/Setup.js +147 -259
  81. package/dist/application/SetupClientConfiguration.js +220 -0
  82. package/dist/application/SetupClients.js +24 -2
  83. package/dist/application/SetupPlan.js +123 -12
  84. package/dist/application/SetupSkill.js +26 -12
  85. package/dist/application/SupportedClients.js +1 -0
  86. package/dist/application/Uninstall.js +6 -3
  87. package/dist/application/WindowsCapabilities.js +86 -0
  88. package/dist/application/runtime.js +2 -0
  89. package/dist/artifacts/AsarArtifactReader.js +11 -0
  90. package/dist/browser/BrowserProcessStartup.js +88 -0
  91. package/dist/browser/CdpCaptureDocuments.js +12 -8
  92. package/dist/browser/CdpCaptureEventBodyShapes.js +75 -0
  93. package/dist/browser/CdpCaptureEventHandlers.js +336 -0
  94. package/dist/browser/CdpCaptureEventHelpers.js +71 -0
  95. package/dist/browser/CdpCaptureEventState.js +1 -0
  96. package/dist/browser/CdpCaptureEventTypes.js +1 -0
  97. package/dist/browser/CdpCaptureEvents.js +46 -464
  98. package/dist/browser/CdpElectronInspection.js +106 -162
  99. package/dist/browser/CdpElectronProvider.js +5 -1
  100. package/dist/browser/CdpElectronScriptEvents.js +69 -0
  101. package/dist/browser/CdpElectronScripts.js +94 -0
  102. package/dist/browser/CdpElectronWorkers.js +56 -0
  103. package/dist/browser/CdpObservationSession.js +51 -8
  104. package/dist/browser/CdpPageCapture.js +12 -129
  105. package/dist/browser/CdpPageCaptureScripts.js +97 -0
  106. package/dist/browser/CdpPageCaptureWorkers.js +46 -0
  107. package/dist/browser/CdpWebMcpDiscovery.js +38 -14
  108. package/dist/browser/PngVisualDiff.js +9 -2
  109. package/dist/catalogIdentity.js +8 -1
  110. package/dist/cli/artifactCommands.js +82 -0
  111. package/dist/cli/coreAnalysisCommands.js +232 -0
  112. package/dist/cli/managedCommands.js +397 -0
  113. package/dist/cli/managedProjectGraphCommand.js +24 -0
  114. package/dist/cli/options.js +9 -0
  115. package/dist/cli/setupCommands.js +108 -0
  116. package/dist/cli/types.js +1 -0
  117. package/dist/cli/utilityCommands.js +122 -0
  118. package/dist/cli.js +13 -383
  119. package/dist/cliApplicationCommands.js +176 -0
  120. package/dist/cliBrowserAdvancedCommands.js +73 -16
  121. package/dist/cliBrowserCommands.js +39 -115
  122. package/dist/cliCommandNames.js +17 -0
  123. package/dist/cliElectronCommands.js +100 -27
  124. package/dist/cliEvidenceCommands.js +13 -2
  125. package/dist/cliInvestigationCommands.js +53 -10
  126. package/dist/cliJsonInput.js +54 -0
  127. package/dist/cliObservationOptions.js +137 -0
  128. package/dist/cliPolicyCommands.js +80 -46
  129. package/dist/cliSetup.js +289 -0
  130. package/dist/config/environment.js +107 -0
  131. package/dist/config/parseConfig.js +228 -0
  132. package/dist/config/parsers.js +68 -0
  133. package/dist/config/permissions.js +30 -0
  134. package/dist/config/types.js +1 -0
  135. package/dist/config.js +1 -292
  136. package/dist/contracts/applicationToolContracts.js +225 -0
  137. package/dist/contracts/artifactToolContracts.js +5 -9
  138. package/dist/contracts/browserToolContracts.js +14 -62
  139. package/dist/contracts/electronToolContracts.js +45 -19
  140. package/dist/contracts/errorSchemas.js +1 -0
  141. package/dist/contracts/investigationExamples.js +0 -6
  142. package/dist/contracts/javascriptApplicationWorkflowExamples.js +46 -0
  143. package/dist/contracts/javascriptRuntimeReconciliationExample.js +208 -0
  144. package/dist/contracts/managedToolContracts.js +153 -0
  145. package/dist/contracts/managedWorkflowExamples.js +346 -0
  146. package/dist/contracts/managedWorkflowToolContracts.js +203 -0
  147. package/dist/contracts/nativeToolContracts.js +2 -6
  148. package/dist/contracts/promptContracts.js +18 -2
  149. package/dist/contracts/providerSelection.js +2 -0
  150. package/dist/contracts/toolContractExamples.js +10 -25
  151. package/dist/contracts/toolContracts.js +49 -47
  152. package/dist/contracts/toolEffects.js +174 -0
  153. package/dist/contracts/toolOutputSchemaGroups.js +232 -0
  154. package/dist/contracts/toolOutputSchemaPrimitives.js +327 -0
  155. package/dist/contracts/toolOutputSchemas.js +2 -535
  156. package/dist/doctorRuntime.js +42 -1
  157. package/dist/domain/analysisErrorPresentation.js +234 -0
  158. package/dist/domain/analysisErrorProjection.js +284 -0
  159. package/dist/domain/artifactComparison.js +37 -19
  160. package/dist/domain/binaryTarget.js +87 -37
  161. package/dist/domain/browserObservation.js +1 -282
  162. package/dist/domain/browserObservationSchemas.js +286 -0
  163. package/dist/domain/bundleComparison.js +4 -4
  164. package/dist/domain/electronObservation.js +13 -0
  165. package/dist/domain/electronStaticAnalysis.js +9 -0
  166. package/dist/domain/electronStaticAnalysisBrowser.js +206 -0
  167. package/dist/domain/electronStaticAnalysisIpc.js +171 -0
  168. package/dist/domain/electronStaticAnalysisNative.js +164 -0
  169. package/dist/domain/electronStaticAnalysisTypes.js +1 -0
  170. package/dist/domain/electronStaticAnalysisValues.js +103 -0
  171. package/dist/domain/errors.js +32 -448
  172. package/dist/domain/functionComparison.js +4 -165
  173. package/dist/domain/functionComparisonDimensions.js +164 -0
  174. package/dist/domain/functionComparisonSchemas.js +3 -8
  175. package/dist/domain/inputIssueProjection.js +52 -0
  176. package/dist/domain/javascriptApplicationAnalysis.js +155 -0
  177. package/dist/domain/javascriptApplicationChangeGraph.js +231 -0
  178. package/dist/domain/javascriptApplicationEvidenceSchemas.js +18 -0
  179. package/dist/domain/javascriptApplicationGraph.js +2 -1
  180. package/dist/domain/javascriptApplicationGraphSchemas.js +7 -0
  181. package/dist/domain/javascriptApplicationVersionComparison.js +116 -0
  182. package/dist/domain/javascriptApplicationVersionComparisonSchemas.js +139 -0
  183. package/dist/domain/javascriptApplicationVersionItems.js +233 -0
  184. package/dist/domain/javascriptApplicationVersionKeys.js +170 -0
  185. package/dist/domain/javascriptExportInstrumentation.js +97 -0
  186. package/dist/domain/javascriptFeatureSeed.js +140 -0
  187. package/dist/domain/javascriptFeatureTrace.js +232 -0
  188. package/dist/domain/javascriptFeatureTraceSchemas.js +136 -0
  189. package/dist/domain/javascriptFeatureTraversal.js +100 -0
  190. package/dist/domain/javascriptNativeHandoff.js +85 -0
  191. package/dist/domain/javascriptReplay.js +361 -0
  192. package/dist/domain/javascriptRuntimeLoadState.js +106 -0
  193. package/dist/domain/javascriptRuntimeReconciliation.js +42 -0
  194. package/dist/domain/javascriptRuntimeReconciliationGraph.js +169 -0
  195. package/dist/domain/javascriptRuntimeReconciliationMatching.js +247 -0
  196. package/dist/domain/javascriptRuntimeReconciliationParsing.js +160 -0
  197. package/dist/domain/javascriptRuntimeReconciliationResult.js +119 -0
  198. package/dist/domain/javascriptRuntimeReconciliationRuntime.js +316 -0
  199. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +245 -0
  200. package/dist/domain/javascriptRuntimeStaticCandidates.js +193 -0
  201. package/dist/domain/javascriptSemanticAnalysis.js +386 -0
  202. package/dist/domain/javascriptSemanticIr.js +30 -0
  203. package/dist/domain/javascriptSemanticProjection.js +366 -0
  204. package/dist/domain/javascriptSemanticState.js +40 -0
  205. package/dist/domain/javascriptSemanticTraversal.js +22 -0
  206. package/dist/domain/javascriptSemanticValues.js +352 -0
  207. package/dist/domain/javascriptStaticAnalysis.js +26 -254
  208. package/dist/domain/javascriptStaticAnalysisBundler.js +209 -0
  209. package/dist/domain/javascriptStaticAnalysisCalls.js +180 -0
  210. package/dist/domain/javascriptStaticAnalysisFindings.js +39 -0
  211. package/dist/domain/javascriptStaticAnalysisHelpers.js +81 -2
  212. package/dist/domain/javascriptStaticAnalysisState.js +6 -0
  213. package/dist/domain/knownPageCoverage.js +21 -0
  214. package/dist/domain/managedApplicationGraph.js +206 -0
  215. package/dist/domain/managedApplicationGraphCoverage.js +170 -0
  216. package/dist/domain/managedApplicationGraphNodeCoverage.js +6 -0
  217. package/dist/domain/managedApplicationGraphNodes.js +336 -0
  218. package/dist/domain/managedArtifact.js +452 -0
  219. package/dist/domain/managedMemberComparison.js +211 -0
  220. package/dist/domain/managedMemberComparisonCoverage.js +72 -0
  221. package/dist/domain/managedMemberComparisonMatch.js +356 -0
  222. package/dist/domain/managedNativeVerification.js +46 -0
  223. package/dist/domain/managedNativeVerificationMatch.js +272 -0
  224. package/dist/domain/managedNativeVerificationSchemas.js +141 -0
  225. package/dist/domain/managedReconstruction.js +196 -0
  226. package/dist/domain/managedRuntimeCorrelation.js +184 -0
  227. package/dist/domain/nodeRuntimeCharacterization.js +66 -0
  228. package/dist/domain/permissionPolicy.js +2 -0
  229. package/dist/domain/reconstructionCoverage.js +387 -0
  230. package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
  231. package/dist/domain/reconstructionVerificationSchemas.js +9 -3
  232. package/dist/domain/runtimeCharacterization.js +85 -0
  233. package/dist/domain/webBundleAnalyzer.js +3 -409
  234. package/dist/domain/webBundleAnalyzerAst.js +77 -0
  235. package/dist/domain/webBundleAnalyzerInspection.js +307 -0
  236. package/dist/domain/webBundleAnalyzerResult.js +120 -0
  237. package/dist/dotnet/ManagedArtifactInspector.js +339 -0
  238. package/dist/dotnet/ManagedMemberInspector.js +153 -0
  239. package/dist/dotnet/ManagedMemberInspectorCore.js +297 -0
  240. package/dist/dotnet/ManagedMemberInstructionDecoder.js +427 -0
  241. package/dist/dotnet/ManagedMemberRows.js +120 -0
  242. package/dist/dotnet/ManagedMetadataHeaps.js +131 -0
  243. package/dist/dotnet/ManagedMetadataInventory.js +104 -0
  244. package/dist/dotnet/ManagedMetadataInventoryRows.js +292 -0
  245. package/dist/dotnet/ManagedMetadataLayout.js +259 -0
  246. package/dist/dotnet/ManagedMetadataRowSizes.js +54 -0
  247. package/dist/dotnet/ManagedMethodBodyReader.js +143 -0
  248. package/dist/dotnet/ManagedNativeBoundaryHelpers.js +311 -0
  249. package/dist/dotnet/ManagedNativeBoundaryInspector.js +143 -0
  250. package/dist/dotnet/ManagedPeReader.js +188 -0
  251. package/dist/dotnet/ManagedReaderFailure.js +10 -0
  252. package/dist/dotnet/ManagedStaticProvider.js +203 -0
  253. package/dist/generatedPackageMetadata.js +2 -2
  254. package/dist/ghidra/GhidraClient.js +76 -91
  255. package/dist/ghidra/GhidraClientStartup.js +29 -0
  256. package/dist/ghidra/GhidraClientWire.js +34 -0
  257. package/dist/ghidra/GhidraDefaults.js +1 -1
  258. package/dist/ghidra/GhidraDiagnostics.js +6 -1
  259. package/dist/ghidra/GhidraInstallation.js +20 -15
  260. package/dist/ghidra/GhidraLauncher.js +93 -29
  261. package/dist/ghidra/GhidraProvider.js +67 -161
  262. package/dist/ghidra/GhidraProviderCapabilities.js +173 -0
  263. package/dist/ghidra/GhidraSessionValues.js +2 -0
  264. package/dist/ghidra/GhidraSocketConnection.js +44 -7
  265. package/dist/ghidra/GhidraTargetSnapshot.js +30 -0
  266. package/dist/ghidra/GhidraTransport.js +71 -0
  267. package/dist/identity.js +3 -2
  268. package/dist/main/messages.js +5 -0
  269. package/dist/main/reload.js +49 -0
  270. package/dist/main/shutdown.js +25 -0
  271. package/dist/main/startup.js +14 -0
  272. package/dist/main/state.js +26 -0
  273. package/dist/main/transport.js +61 -0
  274. package/dist/main/types.js +1 -0
  275. package/dist/main.js +35 -132
  276. package/dist/process/PrivateRuntimeRoot.js +3 -2
  277. package/dist/process/ProcessOwnership.js +35 -0
  278. package/dist/process/ProviderProcess.js +2 -0
  279. package/dist/replay/JavaScriptReplayWorker.js +300 -0
  280. package/dist/replay/LinuxJavaScriptReplayRunner.js +217 -0
  281. package/dist/replay/LinuxJavaScriptReplaySandbox.js +140 -0
  282. package/dist/replay/LinuxRuntimeClosure.js +46 -0
  283. package/dist/replay/LinuxSeccompPolicy.js +40 -0
  284. package/dist/replay/ReplayOutcome.js +95 -0
  285. package/dist/replay/ReplayProcessLifecycle.js +71 -0
  286. package/dist/replay/ReplayWorkerProtocol.js +55 -0
  287. package/dist/replay/SystemJavaScriptReplayHost.js +182 -0
  288. package/dist/server/ProcessCaptureElicitation.js +157 -0
  289. package/dist/server/createServer.js +158 -41
  290. package/dist/server/registerApplicationTools/characterization.js +57 -0
  291. package/dist/server/registerApplicationTools/compareVersions.js +34 -0
  292. package/dist/server/registerApplicationTools/controlledReplay.js +38 -0
  293. package/dist/server/registerApplicationTools/coverage.js +84 -0
  294. package/dist/server/registerApplicationTools/helpers.js +42 -0
  295. package/dist/server/registerApplicationTools/traceFeature.js +26 -0
  296. package/dist/server/registerApplicationTools/types.js +1 -0
  297. package/dist/server/registerApplicationTools.js +13 -0
  298. package/dist/server/registerArtifactComparisonTool.js +16 -9
  299. package/dist/server/registerBrowserTools.js +61 -60
  300. package/dist/server/registerBundleComparisonTool.js +17 -20
  301. package/dist/server/registerElectronTools.js +39 -12
  302. package/dist/server/registerEnhancedTools.js +52 -15
  303. package/dist/server/registerEvidenceResources.js +54 -0
  304. package/dist/server/registerEvidenceTools.js +5 -1
  305. package/dist/server/registerFunctionComparisonTool.js +14 -7
  306. package/dist/server/registerInvestigationTools/helpers.js +74 -0
  307. package/dist/server/registerInvestigationTools/types.js +1 -0
  308. package/dist/server/registerInvestigationTools.js +103 -132
  309. package/dist/server/registerManagedTools.js +6 -0
  310. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +65 -0
  311. package/dist/server/registerManagedWorkflowTools/contract.js +8 -0
  312. package/dist/server/registerManagedWorkflowTools/evidence.js +43 -0
  313. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +39 -0
  314. package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +39 -0
  315. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +52 -0
  316. package/dist/server/registerManagedWorkflowTools/types.js +1 -0
  317. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +75 -0
  318. package/dist/server/registerManagedWorkflowTools.js +13 -0
  319. package/dist/server/registerOfficialTools.js +81 -67
  320. package/dist/server/registerProcessComparisonTool.js +25 -47
  321. package/dist/server/registerSessionRecordTools.js +137 -0
  322. package/dist/server/registerSessionStatusTool.js +9 -8
  323. package/dist/server/registerSessionTools.js +77 -216
  324. package/dist/server/sessionAvailabilityPolicy.js +10 -0
  325. package/dist/server/sessionEvidence.js +14 -19
  326. package/dist/server/toolInputValidation.js +77 -0
  327. package/dist/server/toolRegistrationOptions.js +177 -2
  328. package/dist/server/toolResult.js +30 -17
  329. package/package.json +21 -14
  330. package/scripts/rea.mjs +1 -1
  331. package/skills/{rea-analysis → reverse-engineer-anything}/SKILL.md +75 -6
  332. package/scripts/prepare-node-pty.mjs +0 -35
  333. package/scripts/rebuild-native.mjs +0 -22
@@ -0,0 +1,232 @@
1
+ import { createHash } from "node:crypto";
2
+ import canonicalize from "canonicalize";
3
+ import { compareCodePoints, createJavaScriptApplicationGraph, } from "./javascriptApplicationGraph.js";
4
+ import { applicationFeatureTraceResultSchema, } from "./javascriptFeatureTraceSchemas.js";
5
+ import { findApplicationFeatureSeeds, } from "./javascriptFeatureSeed.js";
6
+ import { traverseApplicationFeature, } from "./javascriptFeatureTraversal.js";
7
+ import { buildJavaScriptNativeHandoffs } from "./javascriptNativeHandoff.js";
8
+ /** Trace a literal feature through a bounded, authority-preserving JAG. */
9
+ export const traceApplicationFeature = (input) => {
10
+ const allSeedMatches = findApplicationFeatureSeeds(input.graph.nodes, input.seed);
11
+ const seedMatches = allSeedMatches.slice(0, input.limits.max_seed_matches);
12
+ if (seedMatches.length === 0)
13
+ return noMatchResult(input);
14
+ const traversal = traverseApplicationFeature(input.graph, seedMatches.map(({ node_id: id }) => id), input.direction, input.limits);
15
+ const graph = traceGraph(input, seedMatches, traversal, allSeedMatches.length);
16
+ const allPaths = terminalPaths(traversal, seedMatches);
17
+ const paths = allPaths.slice(0, input.limits.max_paths);
18
+ const nativeHandoffs = buildJavaScriptNativeHandoffs(traversal.nodes, traversal.edges, input.nativeEvidence);
19
+ const evidenceLinks = uniqueSorted([
20
+ input.sourceEvidenceId,
21
+ ...nativeHandoffs.flatMap(({ evidence_ids: ids }) => ids),
22
+ ]);
23
+ const omissions = traceOmissions(input, traversal, allSeedMatches.length, allPaths.length);
24
+ const semantic = {
25
+ schema_version: 1,
26
+ source_evidence_id: input.sourceEvidenceId,
27
+ source_graph_id: input.graph.graph_id,
28
+ seed: input.seed,
29
+ direction: input.direction,
30
+ seed_matches: seedMatches,
31
+ graph,
32
+ paths,
33
+ native_handoffs: nativeHandoffs,
34
+ summary: {
35
+ matched_seeds: seedMatches.length,
36
+ traced_nodes: traversal.nodes.length,
37
+ traced_edges: traversal.edges.length,
38
+ terminal_paths: paths.length,
39
+ native_handoffs: nativeHandoffs.length,
40
+ ...factSummary(traversal.nodes, traversal.edges),
41
+ },
42
+ coverage: {
43
+ status: traceCoverageStatus(input.graph, omissions),
44
+ source_graph_status: input.graph.coverage.status,
45
+ scanned_nodes: input.graph.nodes.length,
46
+ total_seed_matches: allSeedMatches.length,
47
+ ...omissions,
48
+ frontier_node_ids: traversal.frontierNodeIds,
49
+ },
50
+ evidence_links: evidenceLinks,
51
+ limitations: traceLimitations(input.graph, omissions),
52
+ };
53
+ return applicationFeatureTraceResultSchema.parse({
54
+ ...semantic,
55
+ trace_id: `jatr_${digestCanonical(semantic)}`,
56
+ });
57
+ };
58
+ const noMatchResult = (input) => {
59
+ const semantic = {
60
+ schema_version: 1,
61
+ source_evidence_id: input.sourceEvidenceId,
62
+ source_graph_id: input.graph.graph_id,
63
+ seed: input.seed,
64
+ direction: input.direction,
65
+ seed_matches: [],
66
+ graph: null,
67
+ paths: [],
68
+ native_handoffs: [],
69
+ summary: {
70
+ matched_seeds: 0,
71
+ traced_nodes: 0,
72
+ traced_edges: 0,
73
+ terminal_paths: 0,
74
+ native_handoffs: 0,
75
+ observed_facts: 0,
76
+ inferred_facts: 0,
77
+ unknown_facts: 0,
78
+ unavailable_facts: 0,
79
+ },
80
+ coverage: {
81
+ status: "no-match",
82
+ source_graph_status: input.graph.coverage.status,
83
+ scanned_nodes: input.graph.nodes.length,
84
+ total_seed_matches: 0,
85
+ omitted_seed_matches: 0,
86
+ omitted_nodes: 0,
87
+ omitted_edges: 0,
88
+ omitted_paths: 0,
89
+ frontier_node_ids: [],
90
+ },
91
+ evidence_links: [input.sourceEvidenceId],
92
+ limitations: uniqueSorted([
93
+ "No graph entity matched the literal seed; this is not evidence that the feature is absent.",
94
+ ...sourceCoverageLimitations(input.graph),
95
+ ]),
96
+ };
97
+ return applicationFeatureTraceResultSchema.parse({
98
+ ...semantic,
99
+ trace_id: `jatr_${digestCanonical(semantic)}`,
100
+ });
101
+ };
102
+ const traceGraph = (input, seedMatches, traversal, totalSeedMatches) => {
103
+ const omitted = traversal.omittedNodeCount +
104
+ traversal.omittedEdgeCount +
105
+ (totalSeedMatches - seedMatches.length);
106
+ return createJavaScriptApplicationGraph({
107
+ schema: "JavaScriptApplicationGraph",
108
+ schema_version: 1,
109
+ root_node_ids: uniqueSorted(seedMatches.map(({ node_id: id }) => id)),
110
+ nodes: traversal.nodes,
111
+ edges: traversal.edges,
112
+ coverage: traceGraphCoverage(input.graph, input.limits, omitted),
113
+ limitations: uniqueSorted([
114
+ ...input.graph.limitations,
115
+ "Trace edges retain their source authority; graph connectivity does not prove runtime execution or reachability.",
116
+ ...(omitted === 0
117
+ ? []
118
+ : ["Trace output stopped at explicit caller bounds."]),
119
+ ]),
120
+ });
121
+ };
122
+ const traceGraphCoverage = (source, limits, omitted) => {
123
+ if (omitted > 0)
124
+ return {
125
+ status: "partial",
126
+ truncated: true,
127
+ omitted_count: omitted,
128
+ limits: [
129
+ {
130
+ name: "max-seed-matches",
131
+ value: limits.max_seed_matches,
132
+ unit: "items",
133
+ },
134
+ { name: "max-depth", value: limits.max_depth, unit: "depth" },
135
+ { name: "max-nodes", value: limits.max_nodes, unit: "items" },
136
+ { name: "max-edges", value: limits.max_edges, unit: "items" },
137
+ ],
138
+ };
139
+ return source.coverage.status === "complete"
140
+ ? { status: "complete", truncated: false, omitted_count: 0, limits: [] }
141
+ : {
142
+ status: source.coverage.status,
143
+ truncated: source.coverage.truncated,
144
+ omitted_count: source.coverage.omitted_count,
145
+ limits: source.coverage.limits,
146
+ };
147
+ };
148
+ const terminalPaths = (traversal, seeds) => {
149
+ const seedIds = new Set(seeds.map(({ node_id: id }) => id));
150
+ const edgeById = new Map(traversal.edges.map((edge) => [edge.edge_id, edge]));
151
+ return traversal.nodes
152
+ .filter((node) => isTerminal(node) &&
153
+ (!seedIds.has(node.node_id) || traversal.nodes.length === 1))
154
+ .map((node) => pathTo(node, traversal.predecessors, edgeById))
155
+ .filter((path) => path !== null)
156
+ .sort((left, right) => compareCodePoints(left.path_id, right.path_id));
157
+ };
158
+ const pathTo = (node, predecessors, edgeById) => {
159
+ const nodeIds = [node.node_id];
160
+ const edgeIds = [];
161
+ let current = node.node_id;
162
+ while (predecessors.has(current)) {
163
+ const predecessor = predecessors.get(current);
164
+ if (predecessor === undefined)
165
+ break;
166
+ nodeIds.push(predecessor.previousNodeId);
167
+ edgeIds.push(predecessor.edgeId);
168
+ current = predecessor.previousNodeId;
169
+ }
170
+ nodeIds.reverse();
171
+ edgeIds.reverse();
172
+ const edges = edgeIds
173
+ .map((edgeId) => edgeById.get(edgeId))
174
+ .filter((edge) => edge !== undefined);
175
+ if (edges.length !== edgeIds.length)
176
+ return null;
177
+ const semantic = {
178
+ start_node_id: nodeIds[0] ?? node.node_id,
179
+ end_node_id: node.node_id,
180
+ end_kind: node.kind,
181
+ node_ids: nodeIds,
182
+ edge_ids: edgeIds,
183
+ authorities: uniqueSorted(edges.map(({ evidence }) => evidence.authority)),
184
+ contains_inference: edges.some(({ evidence }) => evidence.state === "inferred"),
185
+ };
186
+ return { ...semantic, path_id: `jatp_${digestCanonical(semantic)}` };
187
+ };
188
+ const isTerminal = (node) => ["endpoint", "storage", "native-addon", "native-export", "unknown"].includes(node.kind);
189
+ const factSummary = (nodes, edges) => {
190
+ const states = [
191
+ ...nodes.flatMap(({ observations }) => observations.map(({ evidence }) => evidence.state)),
192
+ ...edges.map(({ evidence }) => evidence.state),
193
+ ];
194
+ return {
195
+ observed_facts: states.filter((state) => state === "observed").length,
196
+ inferred_facts: states.filter((state) => state === "inferred").length,
197
+ unknown_facts: states.filter((state) => state === "unknown").length,
198
+ unavailable_facts: states.filter((state) => state === "unavailable").length,
199
+ };
200
+ };
201
+ const traceOmissions = (input, traversal, seedMatches, paths) => ({
202
+ omitted_seed_matches: Math.max(0, seedMatches - input.limits.max_seed_matches),
203
+ omitted_nodes: traversal.omittedNodeCount,
204
+ omitted_edges: traversal.omittedEdgeCount,
205
+ omitted_paths: Math.max(0, paths - input.limits.max_paths),
206
+ });
207
+ const traceCoverageStatus = (graph, omissions) => Object.values(omissions).some((value) => value > 0)
208
+ ? "truncated"
209
+ : graph.coverage.status === "complete"
210
+ ? "complete-within-source"
211
+ : "partial";
212
+ const traceLimitations = (graph, omissions) => uniqueSorted([
213
+ "A trace reports graph relationships, not proof that code executed or that a feature is reachable in every state.",
214
+ "Static, native, passive-runtime, inferred, and unknown facts retain their original authority in the returned graph.",
215
+ "Native handoffs never open a binary or invoke a provider automatically; snapshot reuse remains provider/profile/target exact.",
216
+ ...sourceCoverageLimitations(graph),
217
+ ...(Object.values(omissions).some((value) => value > 0)
218
+ ? ["Trace results were truncated at explicit caller limits."]
219
+ : []),
220
+ ]);
221
+ const sourceCoverageLimitations = (graph) => graph.coverage.status === "complete"
222
+ ? []
223
+ : [
224
+ "The source application graph is incomplete; unmatched seeds and frontiers remain unknown.",
225
+ ];
226
+ const digestCanonical = (value) => {
227
+ const encoded = canonicalize(value);
228
+ if (encoded === undefined)
229
+ throw new TypeError("Feature trace could not canonicalize data");
230
+ return createHash("sha256").update(encoded).digest("hex");
231
+ };
232
+ const uniqueSorted = (values) => [...new Set(values)].sort(compareCodePoints);
@@ -0,0 +1,136 @@
1
+ import { z } from "zod";
2
+ import { evidenceSchema, providerSchema } from "./evidence.js";
3
+ import { javascriptApplicationGraphSchema } from "./javascriptApplicationGraph.js";
4
+ const digestSchema = z.string().regex(/^[a-f0-9]{64}$/u);
5
+ const evidenceIdSchema = z.string().regex(/^ev_[a-f0-9]{64}$/u);
6
+ const nodeIdSchema = z.string().regex(/^jag_node_[a-f0-9]{64}$/u);
7
+ const edgeIdSchema = z.string().regex(/^jag_edge_[a-f0-9]{64}$/u);
8
+ const boundedTextSchema = z.string().min(1).max(4_096);
9
+ /** Literal starting point for one bounded application trace. */
10
+ const applicationFeatureSeedSchema = z.strictObject({
11
+ kind: z.enum([
12
+ "node-id",
13
+ "route",
14
+ "string",
15
+ "api",
16
+ "channel",
17
+ "module",
18
+ "native-export",
19
+ ]),
20
+ value: boundedTextSchema,
21
+ match: z.enum(["exact", "contains"]).nullable().default(null),
22
+ case_sensitive: z.boolean().default(false),
23
+ });
24
+ const featureTraceLimitsSchema = z.strictObject({
25
+ max_seed_matches: z.number().int().min(1).max(1_000).default(25),
26
+ max_depth: z.number().int().min(0).max(64).default(12),
27
+ max_nodes: z.number().int().min(1).max(50_000).default(2_000),
28
+ max_edges: z.number().int().min(1).max(100_000).default(4_000),
29
+ max_paths: z.number().int().min(1).max(1_000).default(100),
30
+ });
31
+ /** Evidence-backed application graph and explicit trace bounds. */
32
+ export const traceApplicationFeatureInputSchema = z
33
+ .strictObject({
34
+ application: evidenceSchema,
35
+ native_observations: z.array(evidenceSchema).max(64).default([]),
36
+ seed: applicationFeatureSeedSchema,
37
+ direction: z.enum(["outgoing", "incoming", "both"]).default("both"),
38
+ limits: featureTraceLimitsSchema.default({
39
+ max_seed_matches: 25,
40
+ max_depth: 12,
41
+ max_nodes: 2_000,
42
+ max_edges: 4_000,
43
+ max_paths: 100,
44
+ }),
45
+ })
46
+ .superRefine((input, context) => {
47
+ const ids = input.native_observations.map(({ evidence_id: id }) => id);
48
+ if (new Set(ids).size !== ids.length)
49
+ context.addIssue({
50
+ code: "custom",
51
+ path: ["native_observations"],
52
+ message: "Native observations must be unique",
53
+ });
54
+ });
55
+ const seedMatchSchema = z.strictObject({
56
+ node_id: nodeIdSchema,
57
+ kind: z.string().min(1).max(128),
58
+ basis: z.enum(["node-id", "label", "identity", "property"]),
59
+ field: z.string().min(1).max(256),
60
+ });
61
+ const tracePathSchema = z.strictObject({
62
+ path_id: z.string().regex(/^jatp_[a-f0-9]{64}$/u),
63
+ start_node_id: nodeIdSchema,
64
+ end_node_id: nodeIdSchema,
65
+ end_kind: z.string().min(1).max(128),
66
+ node_ids: z.array(nodeIdSchema).min(1).max(65),
67
+ edge_ids: z.array(edgeIdSchema).max(64),
68
+ authorities: z.array(z.string().min(1).max(128)).max(16),
69
+ contains_inference: z.boolean(),
70
+ });
71
+ const nativeHandoffSchema = z.strictObject({
72
+ native_node_id: nodeIdSchema,
73
+ artifact_sha256: digestSchema,
74
+ artifact_path: z.string().min(1).max(4_096).nullable(),
75
+ export_node_ids: z.array(nodeIdSchema).max(1_000),
76
+ requested_exports: z.array(boundedTextSchema).max(1_000),
77
+ status: z.enum(["evidence-linked", "requires-provider-analysis"]),
78
+ providers: z.array(providerSchema).max(64),
79
+ evidence_ids: z.array(evidenceIdSchema).max(64),
80
+ recommended_tools: z
81
+ .array(z.enum([
82
+ "open_binary",
83
+ "binary_overview",
84
+ "search_procedures",
85
+ "analyze_function",
86
+ "xrefs",
87
+ ]))
88
+ .max(5),
89
+ });
90
+ /** Evidence-preserving bounded subgraph and native-analysis frontiers. */
91
+ export const applicationFeatureTraceResultSchema = z.strictObject({
92
+ schema_version: z.literal(1),
93
+ trace_id: z.string().regex(/^jatr_[a-f0-9]{64}$/u),
94
+ source_evidence_id: evidenceIdSchema,
95
+ source_graph_id: z.string().regex(/^jag_[a-f0-9]{64}$/u),
96
+ seed: applicationFeatureSeedSchema,
97
+ direction: z.enum(["outgoing", "incoming", "both"]),
98
+ seed_matches: z.array(seedMatchSchema).max(1_000),
99
+ graph: javascriptApplicationGraphSchema.nullable(),
100
+ paths: z.array(tracePathSchema).max(1_000),
101
+ native_handoffs: z.array(nativeHandoffSchema).max(10_000),
102
+ summary: z.strictObject({
103
+ matched_seeds: z.number().int().min(0),
104
+ traced_nodes: z.number().int().min(0),
105
+ traced_edges: z.number().int().min(0),
106
+ terminal_paths: z.number().int().min(0),
107
+ native_handoffs: z.number().int().min(0),
108
+ observed_facts: z.number().int().min(0),
109
+ inferred_facts: z.number().int().min(0),
110
+ unknown_facts: z.number().int().min(0),
111
+ unavailable_facts: z.number().int().min(0),
112
+ }),
113
+ coverage: z.strictObject({
114
+ status: z.enum([
115
+ "complete-within-source",
116
+ "partial",
117
+ "truncated",
118
+ "no-match",
119
+ ]),
120
+ source_graph_status: z.enum([
121
+ "complete",
122
+ "partial",
123
+ "unknown",
124
+ "unavailable",
125
+ ]),
126
+ scanned_nodes: z.number().int().min(0),
127
+ total_seed_matches: z.number().int().min(0),
128
+ omitted_seed_matches: z.number().int().min(0),
129
+ omitted_nodes: z.number().int().min(0),
130
+ omitted_edges: z.number().int().min(0),
131
+ omitted_paths: z.number().int().min(0),
132
+ frontier_node_ids: z.array(nodeIdSchema).max(50_000),
133
+ }),
134
+ evidence_links: z.array(evidenceIdSchema).min(1).max(65),
135
+ limitations: z.array(boundedTextSchema).max(1_000),
136
+ });
@@ -0,0 +1,100 @@
1
+ import { compareCodePoints, } from "./javascriptApplicationGraph.js";
2
+ /** Traverse a JAG without treating edge inference as observed reachability. */
3
+ export const traverseApplicationFeature = (graph, seedNodeIds, direction, limits) => {
4
+ const nodeById = new Map(graph.nodes.map((node) => [node.node_id, node]));
5
+ const adjacency = buildAdjacency(graph.edges, direction);
6
+ const visited = new Set(seedNodeIds);
7
+ const retainedEdges = new Map();
8
+ const omittedNodes = new Set();
9
+ const omittedEdges = new Set();
10
+ const frontier = new Set();
11
+ const depths = new Map(seedNodeIds.map((nodeId) => [nodeId, 0]));
12
+ const predecessors = new Map();
13
+ const queue = [...seedNodeIds];
14
+ for (let offset = 0; offset < queue.length; offset += 1) {
15
+ const current = queue[offset];
16
+ if (current === undefined)
17
+ continue;
18
+ const depth = depths.get(current) ?? 0;
19
+ for (const entry of adjacency.get(current) ?? []) {
20
+ if (depth >= limits.max_depth) {
21
+ recordOmission({
22
+ entry,
23
+ current,
24
+ omittedNodes,
25
+ omittedEdges,
26
+ frontier,
27
+ });
28
+ continue;
29
+ }
30
+ if (!visited.has(entry.nextNodeId) && visited.size >= limits.max_nodes) {
31
+ recordOmission({
32
+ entry,
33
+ current,
34
+ omittedNodes,
35
+ omittedEdges,
36
+ frontier,
37
+ });
38
+ continue;
39
+ }
40
+ if (!retainedEdges.has(entry.edge.edge_id) &&
41
+ retainedEdges.size >= limits.max_edges) {
42
+ omittedEdges.add(entry.edge.edge_id);
43
+ frontier.add(current);
44
+ frontier.add(entry.nextNodeId);
45
+ continue;
46
+ }
47
+ retainedEdges.set(entry.edge.edge_id, entry.edge);
48
+ if (visited.has(entry.nextNodeId))
49
+ continue;
50
+ if (!nodeById.has(entry.nextNodeId))
51
+ continue;
52
+ visited.add(entry.nextNodeId);
53
+ depths.set(entry.nextNodeId, depth + 1);
54
+ predecessors.set(entry.nextNodeId, {
55
+ previousNodeId: current,
56
+ edgeId: entry.edge.edge_id,
57
+ });
58
+ queue.push(entry.nextNodeId);
59
+ }
60
+ }
61
+ return {
62
+ nodes: [...visited]
63
+ .map((nodeId) => nodeById.get(nodeId))
64
+ .filter((node) => node !== undefined)
65
+ .sort((left, right) => compareCodePoints(left.node_id, right.node_id)),
66
+ edges: [...retainedEdges.values()].sort((left, right) => compareCodePoints(left.edge_id, right.edge_id)),
67
+ depths,
68
+ predecessors,
69
+ frontierNodeIds: [...frontier].sort(compareCodePoints),
70
+ omittedNodeCount: omittedNodes.size,
71
+ omittedEdgeCount: omittedEdges.size,
72
+ };
73
+ };
74
+ const buildAdjacency = (edges, direction) => {
75
+ const adjacency = new Map();
76
+ for (const edge of edges) {
77
+ if (direction !== "incoming")
78
+ addAdjacency(adjacency, edge.source_node_id, {
79
+ edge,
80
+ nextNodeId: edge.target_node_id,
81
+ });
82
+ if (direction !== "outgoing")
83
+ addAdjacency(adjacency, edge.target_node_id, {
84
+ edge,
85
+ nextNodeId: edge.source_node_id,
86
+ });
87
+ }
88
+ for (const entries of adjacency.values())
89
+ entries.sort((left, right) => compareCodePoints(`${left.edge.edge_id}\0${left.nextNodeId}`, `${right.edge.edge_id}\0${right.nextNodeId}`));
90
+ return adjacency;
91
+ };
92
+ const addAdjacency = (adjacency, nodeId, entry) => {
93
+ adjacency.set(nodeId, [...(adjacency.get(nodeId) ?? []), entry]);
94
+ };
95
+ const recordOmission = (context) => {
96
+ context.omittedNodes.add(context.entry.nextNodeId);
97
+ context.omittedEdges.add(context.entry.edge.edge_id);
98
+ context.frontier.add(context.current);
99
+ context.frontier.add(context.entry.nextNodeId);
100
+ };
@@ -0,0 +1,85 @@
1
+ import { compareCodePoints, } from "./javascriptApplicationGraph.js";
2
+ /** Build provider-neutral addon targets and link exact-subject native Evidence. */
3
+ export const buildJavaScriptNativeHandoffs = (nodes, edges, nativeEvidence) => {
4
+ const nodeById = new Map(nodes.map((node) => [node.node_id, node]));
5
+ return nodes
6
+ .filter(({ kind }) => kind === "native-addon")
7
+ .flatMap((node) => {
8
+ const digest = artifactDigest(node);
9
+ if (digest === null)
10
+ return [];
11
+ const linked = nativeEvidence.filter(({ subject }) => subject?.digest.sha256 === digest);
12
+ const exportNodes = nativeExportNodes(node, edges, nodeById);
13
+ return [
14
+ {
15
+ native_node_id: node.node_id,
16
+ artifact_sha256: digest,
17
+ artifact_path: artifactPath(node),
18
+ export_node_ids: exportNodes.map(({ node_id: id }) => id),
19
+ requested_exports: requestedExports(exportNodes),
20
+ status: linked.length === 0
21
+ ? "requires-provider-analysis"
22
+ : "evidence-linked",
23
+ providers: uniqueProviders(linked),
24
+ evidence_ids: linked
25
+ .map(({ evidence_id: id }) => id)
26
+ .sort(compareCodePoints),
27
+ recommended_tools: [
28
+ "open_binary",
29
+ "binary_overview",
30
+ "search_procedures",
31
+ "analyze_function",
32
+ "xrefs",
33
+ ],
34
+ },
35
+ ];
36
+ })
37
+ .sort((left, right) => compareCodePoints(left.native_node_id, right.native_node_id));
38
+ };
39
+ const artifactDigest = (node) => {
40
+ if (node.identity.strategy === "content-digest")
41
+ return node.identity.sha256;
42
+ const observation = node.observations.find(({ evidence }) => evidence.artifact.available);
43
+ return observation?.evidence.artifact.available === true
44
+ ? observation.evidence.artifact.sha256
45
+ : null;
46
+ };
47
+ const artifactPath = (node) => {
48
+ for (const { evidence } of node.observations)
49
+ if (evidence.location.available &&
50
+ evidence.location.value.kind === "artifact-path")
51
+ return evidence.location.value.path;
52
+ return null;
53
+ };
54
+ const nativeExportNodes = (addon, edges, nodeById) => {
55
+ const ids = edges.flatMap((edge) => {
56
+ if (edge.source_node_id === addon.node_id &&
57
+ ["contains", "exposes"].includes(edge.relation))
58
+ return [edge.target_node_id];
59
+ if (edge.target_node_id === addon.node_id &&
60
+ ["imports", "loads"].includes(edge.relation))
61
+ return [edge.source_node_id];
62
+ return [];
63
+ });
64
+ return [...new Set(ids)]
65
+ .map((id) => nodeById.get(id))
66
+ .filter((node) => node?.kind === "native-export")
67
+ .sort((left, right) => compareCodePoints(left.node_id, right.node_id));
68
+ };
69
+ const requestedExports = (nodes) => {
70
+ const values = nodes.flatMap((node) => node.observations.flatMap((observation) => [
71
+ ...(observation.label === null ? [] : [observation.label]),
72
+ ...stringArray(observation.properties.requested_members),
73
+ ...stringArray(observation.properties.members),
74
+ ]));
75
+ return [...new Set(values)].sort(compareCodePoints).slice(0, 1_000);
76
+ };
77
+ const stringArray = (value) => Array.isArray(value)
78
+ ? value.filter((item) => typeof item === "string")
79
+ : [];
80
+ const uniqueProviders = (evidence) => [
81
+ ...new Map(evidence.map(({ provider }) => [
82
+ `${provider.id}\0${provider.name}\0${provider.version ?? ""}`,
83
+ provider,
84
+ ])).values(),
85
+ ].sort((left, right) => compareCodePoints(`${left.id}\0${left.name}\0${left.version ?? ""}`, `${right.id}\0${right.name}\0${right.version ?? ""}`));