rea-agents 6.1.0 → 6.3.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 (573) hide show
  1. package/README.md +24 -24
  2. package/bridge/ghidra/ReaGhidraBridge.java +32 -4
  3. package/bridge/hopper_bridge.py +8 -1
  4. package/dist/android/JadxConfiguration.js +87 -7
  5. package/dist/android/JadxMcpTransport.js +14 -2
  6. package/dist/android/JadxProvider.js +64 -36
  7. package/dist/android/JadxSession.js +51 -9
  8. package/dist/application/BinaryTargetResolver.js +68 -20
  9. package/dist/application/BrowserEvidence.js +3 -8
  10. package/dist/application/BrowserScenarioEvidence.js +4 -20
  11. package/dist/application/CapabilityInventory.js +43 -9
  12. package/dist/application/ClientConfigurationDocument.js +97 -25
  13. package/dist/application/ClientRegistrationStatus.js +19 -6
  14. package/dist/application/DirectAnalysis.js +41 -20
  15. package/dist/application/DirectAnalysisCleanup.js +71 -0
  16. package/dist/application/DirectAnalysisStatus.js +3 -7
  17. package/dist/application/Doctor.js +40 -53
  18. package/dist/application/DoctorDiagnostics.js +2 -3
  19. package/dist/application/EnhancedTools.js +51 -6
  20. package/dist/application/EvidenceBundleFiles.js +8 -3
  21. package/dist/application/InvestigationProviders.js +13 -5
  22. package/dist/application/JsonFiles.js +56 -23
  23. package/dist/application/LinuxHopper.js +11 -7
  24. package/dist/application/MacHopper.js +15 -18
  25. package/dist/application/RealHopperAssertions.js +0 -11
  26. package/dist/application/ReconstructionObligationCandidates.js +10 -3
  27. package/dist/application/ReconstructionObligationLedgerProjection.js +3 -1
  28. package/dist/application/ReferenceSourceImportEntries.js +1 -1
  29. package/dist/application/RegularFileRead.js +17 -0
  30. package/dist/application/Setup.js +26 -23
  31. package/dist/application/SetupClientConfiguration.js +18 -7
  32. package/dist/application/SetupHost.js +20 -29
  33. package/dist/application/SetupPlan.js +24 -20
  34. package/dist/application/SetupSkill.js +57 -8
  35. package/dist/application/SupportedClients.js +43 -0
  36. package/dist/application/Uninstall.js +98 -30
  37. package/dist/application/UpdateMaintenance.js +13 -7
  38. package/dist/application/UpdateRuntime.js +12 -12
  39. package/dist/application/Utf8JsonInput.js +64 -0
  40. package/dist/application/WebScriptExportService.js +38 -5
  41. package/dist/application/WorkflowEvidence.js +25 -2
  42. package/dist/application/XrefsAddressResolution.js +45 -0
  43. package/dist/application/analysisView/AnalysisViewService.js +76 -0
  44. package/dist/application/android/AndroidAnalysisService.js +1 -1
  45. package/dist/application/binary/AnalysisClientCleanup.js +30 -5
  46. package/dist/application/binary/AnalysisProviderEvaluation.js +1 -2
  47. package/dist/application/binary/AnalysisProviderRegistry.js +2 -6
  48. package/dist/application/binary/AnalysisSnapshotCache.js +13 -10
  49. package/dist/application/binary/BinarySession.js +86 -29
  50. package/dist/application/binary/BinarySessionComposition.js +1 -3
  51. package/dist/application/binary/BinarySessionExecution.js +3 -5
  52. package/dist/application/binary/BinarySessionOpen.js +10 -2
  53. package/dist/application/binary/BinarySessionRecords.js +1 -1
  54. package/dist/application/binary/BinarySessionStatus.js +1 -6
  55. package/dist/application/binary/CompositeProvider.js +4 -18
  56. package/dist/application/binary/LazyAnalysisProvider.js +5 -5
  57. package/dist/application/binary/SessionProviderRouter.js +27 -135
  58. package/dist/application/homebrew.js +48 -0
  59. package/dist/application/javascript/ElectronActiveEvidence.js +10 -14
  60. package/dist/application/javascript/ElectronBoundaryAnalysis.js +2 -2
  61. package/dist/application/javascript/ElectronBoundaryGraphNative.js +5 -1
  62. package/dist/application/javascript/JavaScriptApplicationEvidence.js +3 -6
  63. package/dist/application/javascript/JavaScriptApplicationEvidenceGraph.js +107 -46
  64. package/dist/application/javascript/JavaScriptApplicationService.js +7 -1
  65. package/dist/application/javascript/JavaScriptApplicationWorkflowService.js +59 -45
  66. package/dist/application/javascript/JavaScriptArtifactAnalysis.js +5 -9
  67. package/dist/application/javascript/JavaScriptArtifactGraphBuilder.js +19 -27
  68. package/dist/application/javascript/JavaScriptArtifactGraphBundlers.js +11 -3
  69. package/dist/application/javascript/JavaScriptArtifactGraphContext.js +9 -0
  70. package/dist/application/javascript/JavaScriptArtifactGraphDocuments.js +8 -5
  71. package/dist/application/javascript/JavaScriptArtifactGraphFindings.js +46 -29
  72. package/dist/application/javascript/JavaScriptArtifactGraphStructure.js +0 -1
  73. package/dist/application/javascript/JavaScriptArtifactPathResolution.js +86 -27
  74. package/dist/application/javascript/JavaScriptArtifactReconstruction.js +52 -9
  75. package/dist/application/javascript/JavaScriptArtifactReconstructionInput.js +1 -0
  76. package/dist/application/javascript/JavaScriptJsonModules.js +2 -2
  77. package/dist/application/javascript/JavaScriptModuleRelationships.js +6 -18
  78. package/dist/application/javascript/JavaScriptRuntimeObservationService.js +3 -3
  79. package/dist/application/javascript/JavaScriptRuntimeReconciliationService.js +11 -27
  80. package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +4 -5
  81. package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +8 -6
  82. package/dist/application/javascript/JavaScriptSemanticGraphChildProcessProjection.js +2 -3
  83. package/dist/application/javascript/JavaScriptSemanticGraphConstruction.js +7 -5
  84. package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +3 -4
  85. package/dist/application/javascript/JavaScriptSemanticGraphEvidence.js +1 -1
  86. package/dist/application/javascript/JavaScriptSemanticGraphFingerprintProjection.js +2 -2
  87. package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +3 -7
  88. package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +76 -47
  89. package/dist/application/javascript/JavaScriptSemanticGraphProjection.js +4 -4
  90. package/dist/application/javascript/JavaScriptSemanticGraphResourceProjection.js +3 -4
  91. package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +51 -25
  92. package/dist/application/javascript/JavaScriptSemanticTraceService.js +15 -10
  93. package/dist/application/managed/ManagedMemberComparisonService.js +2 -1
  94. package/dist/application/managed/ManagedNativeVerificationService.js +2 -1
  95. package/dist/application/native/NativeCallRoutes.js +2 -4
  96. package/dist/application/process/ProcessCli.js +11 -11
  97. package/dist/application/process/ProcessEvidence.js +0 -1
  98. package/dist/artifacts/ArtifactProvider.js +53 -30
  99. package/dist/artifacts/ArtifactProviderMetadata.js +1 -4
  100. package/dist/artifacts/ArtifactReader.js +31 -0
  101. package/dist/artifacts/AsarArtifactReader.js +81 -17
  102. package/dist/artifacts/DirectoryArtifactReader.js +2 -1
  103. package/dist/artifacts/MachOSliceArtifactReader.js +9 -2
  104. package/dist/artifacts/NativeDmgArtifactReader.js +207 -77
  105. package/dist/artifacts/NativeDmgOwnership.js +109 -0
  106. package/dist/artifacts/SafeOutputTree.js +16 -2
  107. package/dist/artifacts/ZipArtifactReader.js +11 -4
  108. package/dist/artifacts/apple/AppleAssetCatalogAnalysis.js +4 -2
  109. package/dist/artifacts/apple/DylibResolutionReader.js +17 -7
  110. package/dist/artifacts/apple/KeyedArchiveReader.js +68 -42
  111. package/dist/artifacts/apple/MachoLoadCommandReader.js +36 -6
  112. package/dist/artifacts/extraction/ArtifactExtraction.js +104 -29
  113. package/dist/artifacts/inventory/ArtifactGraphConstruction.js +71 -66
  114. package/dist/artifacts/inventory/ArtifactInventory.js +0 -1
  115. package/dist/artifacts/inventory/classify.js +33 -14
  116. package/dist/artifacts/inventory/hashStableRootArtifact.js +37 -0
  117. package/dist/artifacts/inventory/reader.js +3 -3
  118. package/dist/artifacts/inventory/scanCanonical.js +64 -34
  119. package/dist/artifacts/inventory/scanReader.js +12 -20
  120. package/dist/artifacts/javascript/JavaScriptArtifactFiles.js +65 -27
  121. package/dist/browser/BrowserScenarioPartialObservation.js +106 -0
  122. package/dist/browser/CdpBrowserProvider.js +6 -6
  123. package/dist/browser/CdpCaptureEventHandlers.js +2 -4
  124. package/dist/browser/CdpCaptureEvents.js +0 -1
  125. package/dist/browser/CdpCaptureStorageFingerprints.js +3 -3
  126. package/dist/browser/CdpCaptureValues.js +20 -0
  127. package/dist/browser/CdpElectronInspection.js +2 -2
  128. package/dist/browser/CdpElectronProvider.js +4 -5
  129. package/dist/browser/CdpElectronScriptEvents.js +2 -8
  130. package/dist/browser/CdpElectronScripts.js +4 -5
  131. package/dist/browser/CdpPageCaptureScripts.js +2 -3
  132. package/dist/browser/CdpSafeMetadata.js +10 -10
  133. package/dist/browser/CdpWebMcpDiscovery.js +16 -13
  134. package/dist/browser/PlaywrightBrowserScenarioProvider.js +64 -49
  135. package/dist/browser/PlaywrightElectronActiveActions.js +2 -56
  136. package/dist/browser/PlaywrightElectronActiveProvider.js +10 -6
  137. package/dist/browser/PlaywrightScenarioArtifacts.js +1 -1
  138. package/dist/browser/PlaywrightScenarioBrowser.js +269 -66
  139. package/dist/browser/PlaywrightScenarioEvents.js +1 -1
  140. package/dist/browser/PlaywrightScenarioSession.js +41 -32
  141. package/dist/browser/WebSourceMapFetcher.js +32 -6
  142. package/dist/browser/assets/ScenarioScriptCapture.js +8 -12
  143. package/dist/browser/assets/ScriptCaptureAdapters.js +1 -1
  144. package/dist/browser/history/CaptureFailures.js +6 -2
  145. package/dist/browser/history/MitmproxyCaptureAdapter.js +4 -2
  146. package/dist/catalogIdentity.js +0 -1
  147. package/dist/cli/analysisViewCommands.js +36 -0
  148. package/dist/cli/artifactCommands.js +11 -12
  149. package/dist/cli/coreAnalysisCommands.js +3 -3
  150. package/dist/cli/coreBinaryCommands.js +37 -28
  151. package/dist/cli/coreNativeCommands.js +9 -10
  152. package/dist/cli/electronCommands.js +12 -13
  153. package/dist/cli/interactiveSetup.js +6 -6
  154. package/dist/cli/javascriptApplicationAnalysis.js +2 -12
  155. package/dist/cli/jsonOutput.js +3 -2
  156. package/dist/cli/managedCommands.js +7 -8
  157. package/dist/cli/nativeCallCommands.js +1 -2
  158. package/dist/cli/omittableDefaults.js +50 -0
  159. package/dist/cli/processCommands.js +3 -2
  160. package/dist/cli/setupCommands.js +16 -15
  161. package/dist/cli/streamedJsonOutput.js +83 -4
  162. package/dist/cli/utilityCommands.js +10 -12
  163. package/dist/cli.js +19 -8
  164. package/dist/cliBrowserScenarioCommands.js +2 -2
  165. package/dist/cliCommandNames.js +1 -0
  166. package/dist/cliJsonFile.js +179 -0
  167. package/dist/cliJsonInput.js +60 -33
  168. package/dist/cliObservationOptions.js +4 -0
  169. package/dist/cliOutput.js +0 -38
  170. package/dist/composition/auxiliaryAnalysisProviders.js +30 -25
  171. package/dist/composition/binary.js +9 -9
  172. package/dist/composition/browserScenario.js +2 -1
  173. package/dist/composition/directAnalysis.js +20 -14
  174. package/dist/composition/electronScenario.js +1 -1
  175. package/dist/composition/optionalObservationProviders.js +12 -7
  176. package/dist/config/environment.js +6 -0
  177. package/dist/config/ghidraStartupTimeout.js +4 -9
  178. package/dist/config/homeDirectory.js +12 -0
  179. package/dist/config/mcpResponseBudget.js +9 -1
  180. package/dist/config/parseConfig.js +7 -3
  181. package/dist/config/parsers.js +19 -22
  182. package/dist/contracts/analysisViewToolContracts.js +56 -0
  183. package/dist/contracts/applicationToolContracts.js +5 -4
  184. package/dist/contracts/artifactComparisonExample.js +7 -7
  185. package/dist/contracts/artifactToolContracts.js +1 -1
  186. package/dist/contracts/browserScenarioToolContracts.js +1 -1
  187. package/dist/contracts/browserToolContracts.js +19 -15
  188. package/dist/contracts/enhancedInputs.js +2 -2
  189. package/dist/contracts/enhancedToolContracts.js +4 -3
  190. package/dist/contracts/errorSchemas.js +3 -1
  191. package/dist/contracts/evm/evmToolContracts.js +1 -1
  192. package/dist/contracts/functionComparisonExample.js +8 -0
  193. package/dist/contracts/functionWorkflowToolContracts.js +1 -1
  194. package/dist/contracts/inputSchemaPresentation.js +181 -0
  195. package/dist/contracts/investigationExamples.js +4 -3
  196. package/dist/contracts/javascript/electronToolContracts.js +3 -2
  197. package/dist/contracts/javascript/javascriptApplicationWorkflowExamples.js +3 -22
  198. package/dist/contracts/javascript/javascriptExportShapeComparisonExample.js +248 -0
  199. package/dist/contracts/javascript/javascriptRuntimeObservationToolContracts.js +1 -1
  200. package/dist/contracts/javascript/javascriptRuntimeReconciliationExample.js +8 -7
  201. package/dist/contracts/managed/managedToolContracts.js +8 -12
  202. package/dist/contracts/managed/managedWorkflowToolContracts.js +1 -1
  203. package/dist/contracts/mobileApplicationGraphExamples.js +8 -8
  204. package/dist/contracts/native/binaryDiagnosticsToolContracts.js +1 -1
  205. package/dist/contracts/native/nativeToolContracts.js +2 -2
  206. package/dist/contracts/officialToolContracts.js +2 -1
  207. package/dist/contracts/promptContracts.js +2 -2
  208. package/dist/contracts/providerSelection.js +1 -1
  209. package/dist/contracts/sessionLifecycleInputs.js +4 -3
  210. package/dist/contracts/sessionStatusContract.js +3 -2
  211. package/dist/contracts/sessionToolContracts.js +17 -4
  212. package/dist/contracts/sessionToolSchemas.js +4 -16
  213. package/dist/contracts/toolContracts.js +2 -0
  214. package/dist/contracts/toolEffects.js +1 -0
  215. package/dist/contracts/toolOutputSchemaGroups.js +138 -94
  216. package/dist/contracts/toolOutputSchemaPrimitives.js +13 -26
  217. package/dist/contracts/toolSchemaMetadata.js +18 -69
  218. package/dist/contracts/webNetworkCaptureToolContracts.js +1 -1
  219. package/dist/contracts/webRuntimeToolContracts.js +1 -1
  220. package/dist/contracts/webScriptToolContracts.js +1 -1
  221. package/dist/doctorRuntime.js +7 -5
  222. package/dist/domain/analysisErrorBase.js +5 -0
  223. package/dist/domain/analysisErrorCore.js +3 -0
  224. package/dist/domain/analysisErrorPresentation.js +22 -5
  225. package/dist/domain/analysisErrorProjection.js +24 -5
  226. package/dist/domain/analysisSnapshot.js +31 -31
  227. package/dist/domain/analysisView/analysisView.js +241 -0
  228. package/dist/domain/analysisView/analysisViewCoverage.js +19 -0
  229. package/dist/domain/analysisView/binaryLayoutView.js +159 -0
  230. package/dist/domain/analysisView/javascriptApplicationView.js +238 -0
  231. package/dist/domain/android/androidApplication.js +1 -1
  232. package/dist/domain/android/androidPartialObservation.js +36 -0
  233. package/dist/domain/apple/appleApplication.js +1 -1
  234. package/dist/domain/apple/dylibResolution.js +10 -3
  235. package/dist/domain/apple/interfaceBuilderGraph.js +0 -1
  236. package/dist/domain/apple/keyedArchive.js +26 -2
  237. package/dist/domain/artifactComparison.js +15 -6
  238. package/dist/domain/artifactGraph.js +17 -4
  239. package/dist/domain/artifactIdentity.js +8 -8
  240. package/dist/domain/artifactInspection.js +8 -8
  241. package/dist/domain/artifactInventoryEvidence.js +9 -16
  242. package/dist/domain/artifactOperationError.js +3 -3
  243. package/dist/domain/artifactPartialObservation.js +1 -0
  244. package/dist/domain/artifactPathSyntax.js +49 -0
  245. package/dist/domain/binaryTarget.js +39 -13
  246. package/dist/domain/browserCaptureComparison.js +13 -49
  247. package/dist/domain/browserCompleteness.js +3 -2
  248. package/dist/domain/browserNetworkEvidence.js +10 -4
  249. package/dist/domain/browserObservation.js +0 -1
  250. package/dist/domain/browserObservationSchemas.js +14 -3
  251. package/dist/domain/browserScenario.js +0 -1
  252. package/dist/domain/browserScenarioCapture.js +1 -2
  253. package/dist/domain/browserScenarioCaptureValues.js +2 -2
  254. package/dist/domain/browserScenarioDiff.js +0 -2
  255. package/dist/domain/browserScenarioDiffEvidence.js +0 -12
  256. package/dist/domain/browserScenarioDiffValues.js +2 -2
  257. package/dist/domain/browserScenarioNormalization.js +3 -3
  258. package/dist/domain/browserScenarioValues.js +6 -6
  259. package/dist/domain/callPath.js +15 -18
  260. package/dist/domain/callPathSchemas.js +2 -2
  261. package/dist/domain/canonicalDigest.js +7 -1
  262. package/dist/domain/canonicalOrdering.js +1 -13
  263. package/dist/domain/changedBehavior.js +5 -6
  264. package/dist/domain/comparisonSemantics.js +0 -5
  265. package/dist/domain/completionLedgerGeneration.js +2 -1
  266. package/dist/domain/configurationErrors.js +12 -0
  267. package/dist/domain/conformancePackage.js +4 -3
  268. package/dist/domain/digests.js +0 -3
  269. package/dist/domain/evidence.js +19 -40
  270. package/dist/domain/evidenceBundle.js +58 -42
  271. package/dist/domain/evidenceCompletionLedger.js +2 -1
  272. package/dist/domain/firmware/firmwareAnalysis.js +4 -3
  273. package/dist/domain/functionComparison.js +6 -6
  274. package/dist/domain/functionComparisonDimensions.js +120 -87
  275. package/dist/domain/functionComparisonNormalization.js +26 -36
  276. package/dist/domain/functionComparisonResults.js +3 -6
  277. package/dist/domain/functionComparisonSchemas.js +2 -8
  278. package/dist/domain/functionDossierEvidence.js +4 -38
  279. package/dist/domain/hopperValues.js +11 -15
  280. package/dist/domain/javascript/electronActiveObservation.js +29 -71
  281. package/dist/domain/javascript/electronObservation.js +14 -3
  282. package/dist/domain/javascript/electronStaticAnalysisBrowser.js +12 -11
  283. package/dist/domain/javascript/electronStaticAnalysisIpc.js +11 -2
  284. package/dist/domain/javascript/electronStaticAnalysisNative.js +7 -4
  285. package/dist/domain/javascript/electronStaticAnalysisValues.js +8 -4
  286. package/dist/domain/javascript/javascriptApplicationAnalysis.js +3 -1
  287. package/dist/domain/javascript/javascriptApplicationChangeGraph.js +12 -8
  288. package/dist/domain/javascript/javascriptApplicationEvidenceSchemas.js +6 -0
  289. package/dist/domain/javascript/javascriptApplicationGraph.js +41 -16
  290. package/dist/domain/javascript/javascriptApplicationGraphSchemas.js +9 -2
  291. package/dist/domain/javascript/javascriptApplicationVersionComparison.js +4 -4
  292. package/dist/domain/javascript/javascriptApplicationVersionComparisonSchemas.js +37 -22
  293. package/dist/domain/javascript/javascriptApplicationVersionItems.js +50 -36
  294. package/dist/domain/javascript/javascriptApplicationVersionKeys.js +9 -8
  295. package/dist/domain/javascript/javascriptAstFingerprint.js +2 -2
  296. package/dist/domain/javascript/javascriptAstValues.js +22 -0
  297. package/dist/{application/javascript/JavaScriptReturnShapeProjection.js → domain/javascript/javascriptExportReturnShapeProjection.js} +4 -4
  298. package/dist/domain/javascript/javascriptExportShapeComparison.js +10 -3
  299. package/dist/domain/javascript/javascriptExportShapeComparisonIdentity.js +6 -1
  300. package/dist/domain/javascript/javascriptExportShapeComparisonSchemas.js +58 -22
  301. package/dist/domain/javascript/javascriptExportShapeSelection.js +7 -7
  302. package/dist/domain/javascript/javascriptExportShapeVariants.js +70 -16
  303. package/dist/domain/javascript/javascriptFeatureSeed.js +25 -3
  304. package/dist/domain/javascript/javascriptFeatureTrace.js +7 -6
  305. package/dist/domain/javascript/javascriptFeatureTraceSchemas.js +17 -9
  306. package/dist/domain/javascript/javascriptFeatureTraversal.js +4 -5
  307. package/dist/domain/javascript/javascriptNativeHandoff.js +7 -7
  308. package/dist/domain/javascript/javascriptRuntimeLoadState.js +0 -1
  309. package/dist/domain/javascript/javascriptRuntimeObservation.js +18 -7
  310. package/dist/domain/javascript/javascriptRuntimeReconciliation.js +12 -6
  311. package/dist/domain/javascript/javascriptRuntimeReconciliationActive.js +9 -8
  312. package/dist/domain/javascript/javascriptRuntimeReconciliationCaptureParsing.js +212 -0
  313. package/dist/domain/javascript/javascriptRuntimeReconciliationGraph.js +5 -4
  314. package/dist/domain/javascript/javascriptRuntimeReconciliationInputValidation.js +28 -0
  315. package/dist/domain/javascript/javascriptRuntimeReconciliationMatching.js +6 -6
  316. package/dist/domain/javascript/javascriptRuntimeReconciliationParsing.js +12 -222
  317. package/dist/domain/javascript/javascriptRuntimeReconciliationResult.js +2 -2
  318. package/dist/domain/javascript/javascriptRuntimeReconciliationRuntime.js +15 -4
  319. package/dist/domain/javascript/javascriptRuntimeReconciliationSchemas.js +2 -2
  320. package/dist/domain/javascript/javascriptRuntimeStaticCandidates.js +7 -7
  321. package/dist/domain/javascript/javascriptSemanticAnalysis.js +209 -11
  322. package/dist/domain/javascript/javascriptSemanticAsyncEffects.js +2 -1
  323. package/dist/domain/javascript/javascriptSemanticCallResolution.js +9 -7
  324. package/dist/domain/javascript/javascriptSemanticCalls.js +2 -1
  325. package/dist/domain/javascript/javascriptSemanticChildProcesses.js +4 -3
  326. package/dist/domain/javascript/javascriptSemanticCoverage.js +20 -0
  327. package/dist/domain/javascript/javascriptSemanticDataEffectHelpers.js +7 -9
  328. package/dist/domain/javascript/javascriptSemanticDataEffects.js +4 -11
  329. package/dist/domain/javascript/javascriptSemanticFingerprints.js +2 -2
  330. package/dist/domain/javascript/javascriptSemanticGraph.js +220 -71
  331. package/dist/domain/javascript/javascriptSemanticGraphSchemas.js +19 -1
  332. package/dist/domain/javascript/javascriptSemanticIr.js +0 -4
  333. package/dist/domain/javascript/javascriptSemanticIterationSources.js +106 -0
  334. package/dist/domain/javascript/javascriptSemanticMemberMutations.js +515 -74
  335. package/dist/domain/javascript/javascriptSemanticMutationInitializers.js +190 -0
  336. package/dist/domain/javascript/javascriptSemanticMutationValues.js +44 -36
  337. package/dist/domain/javascript/javascriptSemanticObjects.js +79 -42
  338. package/dist/domain/javascript/javascriptSemanticPrimitives.js +8 -14
  339. package/dist/domain/javascript/javascriptSemanticProjection.js +21 -16
  340. package/dist/domain/javascript/javascriptSemanticPromises.js +16 -21
  341. package/dist/domain/javascript/javascriptSemanticPropertyPaths.js +23 -0
  342. package/dist/domain/javascript/javascriptSemanticProvenance.js +3 -3
  343. package/dist/domain/javascript/javascriptSemanticQuery.js +8 -2
  344. package/dist/domain/javascript/javascriptSemanticQueryIdentity.js +3 -2
  345. package/dist/domain/javascript/javascriptSemanticQuerySchemas.js +8 -9
  346. package/dist/domain/javascript/javascriptSemanticRequireOrigin.js +16 -10
  347. package/dist/domain/javascript/javascriptSemanticResourceLimits.js +1 -1
  348. package/dist/domain/javascript/javascriptSemanticResources.js +1 -1
  349. package/dist/domain/javascript/javascriptSemanticReturns.js +55 -44
  350. package/dist/domain/javascript/javascriptSemanticSlots.js +72 -0
  351. package/dist/domain/javascript/javascriptSemanticTraversal.js +6 -1
  352. package/dist/domain/javascript/javascriptSemanticValues.js +180 -76
  353. package/dist/domain/javascript/javascriptSourceMapPaths.js +114 -0
  354. package/dist/domain/javascript/javascriptSourceParser.js +34 -9
  355. package/dist/domain/javascript/javascriptStaticAnalysisBundler.js +5 -6
  356. package/dist/domain/javascript/javascriptStaticAnalysisCalls.js +2 -1
  357. package/dist/domain/javascript/javascriptStaticAnalysisHelpers.js +26 -16
  358. package/dist/domain/javascript/sourceToBundleComparison.js +19 -8
  359. package/dist/domain/javascript/sourceToBundleSignals.js +53 -25
  360. package/dist/domain/jsonSerialization.js +109 -55
  361. package/dist/domain/jsonShape.js +46 -19
  362. package/dist/domain/localPath.js +10 -4
  363. package/dist/domain/managed/managedApplicationGraph.js +10 -6
  364. package/dist/domain/managed/managedApplicationGraphNodes.js +82 -57
  365. package/dist/domain/managed/managedArtifact.js +6 -4
  366. package/dist/domain/managed/managedMemberComparison.js +2 -9
  367. package/dist/domain/managed/managedMemberComparisonMatch.js +6 -7
  368. package/dist/domain/managed/managedNativeVerification.js +0 -2
  369. package/dist/domain/managed/managedNativeVerificationMatch.js +9 -3
  370. package/dist/domain/native/binaryLayout.js +2 -3
  371. package/dist/domain/native/nativeApiBoundary.js +1 -1
  372. package/dist/domain/native/nativeCallObservation.js +3 -3
  373. package/dist/domain/native/nativeInstruction.js +7 -0
  374. package/dist/domain/native/nativeValueFlow.js +5 -11
  375. package/dist/domain/native/objcSwiftMetadata.js +15 -17
  376. package/dist/domain/native/recordedCrash.js +2 -3
  377. package/dist/domain/offsetDateTime.js +17 -0
  378. package/dist/domain/process/processCapture.js +22 -20
  379. package/dist/domain/process/processCaptureCoverage.js +70 -0
  380. package/dist/domain/process/processCaptureExample.js +45 -1
  381. package/dist/domain/process/processCaptureParsing.js +1 -34
  382. package/dist/domain/process/processCaptureValidation.js +82 -13
  383. package/dist/domain/process/processComparison.js +39 -43
  384. package/dist/domain/process/processObservation.js +10 -2
  385. package/dist/domain/process/processScenario.js +24 -2
  386. package/dist/domain/process/processTraceComparison.js +0 -2
  387. package/dist/domain/process/processTraceDimensionProjection.js +1 -1
  388. package/dist/domain/process/processTraceEvaluation.js +19 -15
  389. package/dist/domain/process/processTraceSpecification.js +4 -7
  390. package/dist/domain/providerAdapterError.js +2 -0
  391. package/dist/domain/providerCleanupError.js +6 -2
  392. package/dist/domain/reconstructionCoverage.js +7 -3
  393. package/dist/domain/reconstructionObligationLedgerSchemas.js +2 -1
  394. package/dist/domain/reconstructionReadinessSchemas.js +2 -1
  395. package/dist/domain/reconstructionUnknowns.js +4 -3
  396. package/dist/domain/reconstructionVerification.js +6 -5
  397. package/dist/domain/reconstructionVerificationSchemas.js +2 -1
  398. package/dist/domain/referenceSourceGraph.js +27 -28
  399. package/dist/domain/referenceSourceImportParsing.js +34 -45
  400. package/dist/domain/residualUnknown.js +3 -2
  401. package/dist/domain/staticRuntimeCorrelation.js +4 -3
  402. package/dist/domain/stringPatterns.js +6 -0
  403. package/dist/domain/swiftSymbolClassification.js +66 -0
  404. package/dist/domain/symbolAnalysis.js +83 -20
  405. package/dist/domain/unicodeCodePointOrder.js +6 -0
  406. package/dist/domain/webBundleAnalyzerInspection.js +9 -1
  407. package/dist/domain/webCaptureDiff.js +71 -30
  408. package/dist/domain/webCaptureDiffSchemas.js +8 -11
  409. package/dist/domain/webEventListeners.js +3 -2
  410. package/dist/domain/webExecution.js +3 -2
  411. package/dist/domain/webInventory.js +3 -2
  412. package/dist/domain/webMcpDiscovery.js +4 -3
  413. package/dist/domain/webRuntime.js +0 -2
  414. package/dist/domain/webScriptExport.js +2 -2
  415. package/dist/dotnet/ManagedArtifactInspector.js +2 -19
  416. package/dist/dotnet/ManagedMemberInspector.js +12 -18
  417. package/dist/dotnet/ManagedMemberInspectorCore.js +47 -44
  418. package/dist/dotnet/ManagedMemberInstructionDecoder.js +1 -2
  419. package/dist/dotnet/ManagedMemberRows.js +75 -62
  420. package/dist/dotnet/ManagedMetadataInventory.js +16 -22
  421. package/dist/dotnet/ManagedMethodBodyReader.js +4 -0
  422. package/dist/dotnet/ManagedNativeBoundaryHelpers.js +109 -94
  423. package/dist/dotnet/ManagedNativeBoundaryInspector.js +12 -21
  424. package/dist/dotnet/ManagedReaderFailure.js +16 -0
  425. package/dist/dotnet/ManagedStaticProvider.js +13 -12
  426. package/dist/dotnet/ManagedStaticProviderMetadata.js +1 -4
  427. package/dist/evaluation/AgentEvaluationFixtures.js +250 -0
  428. package/dist/evaluation/AgentEvaluationReport.js +28 -0
  429. package/dist/evaluation/CodexAgentEval.js +12 -8
  430. package/dist/evaluation/KnownAnswerEvaluation.js +281 -0
  431. package/dist/evm/EvmoleInterfaceProvider.js +2 -1
  432. package/dist/filesystem/RegularFile.js +41 -0
  433. package/dist/firmware/FirmwareCommand.js +9 -5
  434. package/dist/firmware/FirmwareProvider.js +4 -4
  435. package/dist/generatedPackageMetadata.js +2 -2
  436. package/dist/ghidra/GhidraAnalysisProfile.js +3 -6
  437. package/dist/ghidra/GhidraClient.js +105 -36
  438. package/dist/ghidra/GhidraClientStartup.js +0 -2
  439. package/dist/ghidra/GhidraDoctor.js +6 -5
  440. package/dist/ghidra/GhidraFunctionValues.js +3 -5
  441. package/dist/ghidra/GhidraInstallation.js +151 -22
  442. package/dist/ghidra/GhidraJavaLaunch.js +6 -2
  443. package/dist/ghidra/GhidraLauncher.js +58 -26
  444. package/dist/ghidra/GhidraProvider.js +6 -2
  445. package/dist/ghidra/GhidraProviderCapabilities.js +6 -0
  446. package/dist/ghidra/GhidraProviderClient.js +13 -3
  447. package/dist/ghidra/GhidraSessionError.js +2 -0
  448. package/dist/ghidra/GhidraSessionRoot.js +39 -0
  449. package/dist/ghidra/extensions/GhidraExtensions.js +17 -10
  450. package/dist/ghidra/extensions/nativeaot/NativeAotAdapter.js +8 -2
  451. package/dist/hopper/BridgeLauncher.js +34 -45
  452. package/dist/hopper/HopperAnalysisProfile.js +3 -8
  453. package/dist/hopper/HopperCleanup.js +56 -27
  454. package/dist/hopper/HopperClient.js +86 -65
  455. package/dist/hopper/HopperMachOImage.js +3 -2
  456. package/dist/hopper/HopperProvider.js +16 -18
  457. package/dist/hopper/HopperRegexSearch.js +3 -6
  458. package/dist/hopper/HopperTargetLease.js +132 -49
  459. package/dist/hopper/LinuxPrivateDisplayProbe.js +6 -0
  460. package/dist/ida/IdaConfiguration.js +8 -3
  461. package/dist/ida/IdaInput.js +1 -7
  462. package/dist/ida/IdaMcpConnection.js +8 -4
  463. package/dist/ida/IdaOperationRunner.js +5 -3
  464. package/dist/ida/IdaProvider.js +8 -12
  465. package/dist/ida/IdaSessionClient.js +24 -20
  466. package/dist/ida/IdaWorkspace.js +12 -13
  467. package/dist/inspector/JavaScriptRuntimeScope.js +9 -5
  468. package/dist/inspector/V8InspectorCaptureProjection.js +47 -14
  469. package/dist/inspector/V8InspectorProvider.js +97 -35
  470. package/dist/javascript/recovery/WakaruCommand.js +7 -2
  471. package/dist/javascript/recovery/WakaruExecution.js +5 -2
  472. package/dist/main/shutdown.js +81 -29
  473. package/dist/main/startup.js +9 -2
  474. package/dist/main/transport.js +23 -3
  475. package/dist/main.js +11 -18
  476. package/dist/native/AppleMachoSelection.js +16 -6
  477. package/dist/native/AppleObjcDispatchFacets.js +3 -3
  478. package/dist/native/AppleObjcProperties.js +17 -7
  479. package/dist/native/CommandRunner.js +9 -7
  480. package/dist/native/LldbCallTracer.js +249 -77
  481. package/dist/native/NativeMacOSProvider.js +32 -17
  482. package/dist/native/NativeMacOSProviderMetadata.js +1 -2
  483. package/dist/native/NativeUiHelperRuntime.js +11 -2
  484. package/dist/native/NativeUiObservation.js +2 -2
  485. package/dist/native/pwntools/PwntoolsDecoder.js +2 -1
  486. package/dist/process/DarwinProcessRunTokenReader.js +16 -2
  487. package/dist/process/ExecFileOutput.js +88 -6
  488. package/dist/process/PrivateRuntimeRoot.js +10 -5
  489. package/dist/process/ProcessOwnership.js +1 -4
  490. package/dist/process/ProcessOwnershipObservation.js +18 -16
  491. package/dist/process/ProviderProcess.js +1 -3
  492. package/dist/process/capture/FilesystemSnapshot.js +131 -24
  493. package/dist/process/capture/ProcessCaptureError.js +13 -0
  494. package/dist/process/capture/ProcessCaptureLifecycle.js +148 -74
  495. package/dist/process/capture/ProcessFilesystemEffects.js +51 -6
  496. package/dist/process/capture/ProcessHarness.js +16 -33
  497. package/dist/process/capture/ProcessNormalization.js +20 -2
  498. package/dist/process/capture/ProcessSampling.js +25 -2
  499. package/dist/process/capture/TerminalRenderer.js +14 -0
  500. package/dist/process/snapshotEnvironment.js +14 -0
  501. package/dist/server/EvidenceMcpServer.js +25 -14
  502. package/dist/server/analysisAdmission.js +8 -0
  503. package/dist/server/createServer.js +71 -59
  504. package/dist/server/mcpClientMetadata.js +12 -5
  505. package/dist/server/promptCompletion.js +3 -8
  506. package/dist/server/registerAnalysisViewTool.js +15 -0
  507. package/dist/server/registerAndroidTools.js +2 -3
  508. package/dist/server/registerApplicationTools/compareExportShapes.js +6 -6
  509. package/dist/server/registerApplicationTools/compareSourceToBundle.js +4 -5
  510. package/dist/server/registerApplicationTools/compareVersions.js +4 -5
  511. package/dist/server/registerApplicationTools/coverage.js +1 -2
  512. package/dist/server/registerApplicationTools/helpers.js +4 -4
  513. package/dist/server/registerApplicationTools/obligationLedger.js +4 -5
  514. package/dist/server/registerApplicationTools/projectMobileApplicationGraph.js +3 -4
  515. package/dist/server/registerApplicationTools/traceFeature.js +4 -5
  516. package/dist/server/registerApplicationTools/traceSemantics.js +4 -5
  517. package/dist/server/registerArtifactComparisonTool.js +4 -5
  518. package/dist/server/registerArtifactTools.js +2 -2
  519. package/dist/server/registerBinaryDiagnosticsTools.js +2 -3
  520. package/dist/server/registerBrowserScenarioTool.js +3 -4
  521. package/dist/server/registerBrowserTools.js +13 -16
  522. package/dist/server/registerBundleComparisonTool.js +5 -6
  523. package/dist/server/registerCloseLifecycleTool.js +8 -7
  524. package/dist/server/registerElectronTools.js +10 -13
  525. package/dist/server/registerEnhancedTools.js +82 -77
  526. package/dist/server/registerEvidenceTools.js +54 -47
  527. package/dist/server/registerEvmTools.js +2 -3
  528. package/dist/server/registerFirmwareTools.js +2 -3
  529. package/dist/server/registerFunctionComparisonTool.js +7 -8
  530. package/dist/server/registerInvestigationTools.js +14 -15
  531. package/dist/server/registerJavaScriptRecoveryTool.js +2 -3
  532. package/dist/server/registerJavaScriptRuntimeObservationTools.js +6 -6
  533. package/dist/server/registerManagedTools.js +7 -4
  534. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +5 -6
  535. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +4 -5
  536. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +6 -7
  537. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +6 -7
  538. package/dist/server/registerOfficialTools.js +32 -41
  539. package/dist/server/registerProcessComparisonTool.js +8 -8
  540. package/dist/server/registerRecordedCrashTools.js +2 -3
  541. package/dist/server/registerSessionRecordTools.js +15 -19
  542. package/dist/server/registerSessionStatusTool.js +3 -4
  543. package/dist/server/registerSessionTools.js +19 -19
  544. package/dist/server/registerWebModuleTool.js +2 -3
  545. package/dist/server/registerWebNetworkCaptureTool.js +2 -3
  546. package/dist/server/registerWebRuntimeTools.js +4 -5
  547. package/dist/server/registerWebScriptTool.js +2 -3
  548. package/dist/server/registerWebSourceLocationTool.js +2 -3
  549. package/dist/server/toolResult.js +66 -94
  550. package/dist/server/toolResultEncoding.js +11 -10
  551. package/dist/windows/WindowsNativeLoader.js +1 -0
  552. package/dist/windows/WindowsOwnedProcess.js +60 -15
  553. package/dist/windows/WindowsPrivateRuntime.js +7 -8
  554. package/native/windows/README.md +3 -1
  555. package/native/windows/build/manifest.json +2 -2
  556. package/native/windows/build/rea-windows-x64.node +0 -0
  557. package/package.json +42 -30
  558. package/scripts/rea.mjs +3 -6
  559. package/skills/reverse-engineer-anything/SKILL.md +14 -13
  560. package/skills/reverse-engineer-anything/references/android-applications.md +6 -3
  561. package/skills/reverse-engineer-anything/references/evidence-workflows.md +8 -4
  562. package/skills/reverse-engineer-anything/references/javascript-applications.md +16 -6
  563. package/skills/reverse-engineer-anything/references/native-and-artifacts.md +18 -0
  564. package/dist/artifacts/inventory/policy.js +0 -2
  565. package/dist/config.js +0 -1
  566. package/dist/contracts/browserCaptureToolInputSchema.js +0 -43
  567. package/dist/contracts/process/processCaptureExample.js +0 -2
  568. package/dist/contracts/toolOutputSchemas.js +0 -2
  569. package/dist/domain/managed/managedApplicationGraphNodeCoverage.js +0 -6
  570. package/dist/main/reload.js +0 -12
  571. package/dist/main/state.js +0 -3
  572. package/dist/server/registerNativeTools.js +0 -6
  573. package/dist/server/sessionToolPolicies.js +0 -2
@@ -2,9 +2,8 @@ import { createHash } from "node:crypto";
2
2
  import { posix } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import * as t from "@babel/types";
5
- import { readExactJavaScriptLiteral, semanticStaticPropertyName, } from "./javascriptAstValues.js";
6
- import { compareCodePoints } from "../canonicalOrdering.js";
7
- export { propertyName, semanticStaticPropertyName, } from "./javascriptAstValues.js";
5
+ import { readExactJavaScriptLiteral, semanticStaticPropertyName, unwrapJavaScriptExpression, } from "./javascriptAstValues.js";
6
+ import { compareUnicodeCodePoints, compositeKey, } from "../unicodeCodePointOrder.js";
8
7
  /** Explicit result for source text that Babel cannot parse. */
9
8
  export const failedJavaScriptStaticAnalysis = () => ({
10
9
  parse_status: "failed",
@@ -68,8 +67,9 @@ const findChunkRuntime = (node) => {
68
67
  pending.push(current.right, current.left);
69
68
  continue;
70
69
  }
71
- if (t.isParenthesizedExpression(current) || t.isTSAsExpression(current))
72
- pending.push(current.expression);
70
+ const unwrapped = unwrapJavaScriptExpression(current).node;
71
+ if (unwrapped !== current)
72
+ pending.push(unwrapped);
73
73
  }
74
74
  return undefined;
75
75
  };
@@ -103,26 +103,25 @@ export const staticArrayValues = (array) => {
103
103
  const value = argumentValue(element);
104
104
  return value === undefined ? [] : [value];
105
105
  });
106
- const values = [...new Set(staticValues)].sort(compareCodePoints);
106
+ const values = [...new Set(staticValues)].sort(compareUnicodeCodePoints);
107
107
  return {
108
108
  values,
109
109
  unknown: array.elements.length - staticValues.length,
110
110
  };
111
111
  };
112
- /** Resolve a path composed only from inert literal syntax. */
113
- export const staticPath = (node) => staticPathAt(node);
114
112
  /** Classify whether inert path syntax is a module specifier or file expression. */
115
113
  export const staticPathResolutionContext = (node) => isFilesystemPathExpression(node)
116
114
  ? "filesystem-expression"
117
115
  : "module-specifier";
118
- const staticPathAt = (node) => {
116
+ /** Resolve a path composed only from inert literal syntax. */
117
+ export const staticPath = (node) => {
119
118
  if (t.isStringLiteral(node))
120
119
  return node.value;
121
120
  if (t.isTemplateLiteral(node) && node.expressions.length === 0)
122
121
  return stringValue(node);
123
122
  if (t.isBinaryExpression(node, { operator: "+" })) {
124
- const left = staticPathAt(node.left);
125
- const right = staticPathAt(node.right);
123
+ const left = staticPath(node.left);
124
+ const right = staticPath(node.right);
126
125
  return left === undefined || right === undefined
127
126
  ? undefined
128
127
  : `${left}${right}`;
@@ -153,7 +152,7 @@ const staticCallPath = (node) => {
153
152
  for (const argument of node.arguments) {
154
153
  if (isDirectoryIdentity(argumentNode(argument)))
155
154
  continue;
156
- const value = t.isNode(argument) ? staticPathAt(argument) : undefined;
155
+ const value = t.isNode(argument) ? staticPath(argument) : undefined;
157
156
  if (value === undefined)
158
157
  return undefined;
159
158
  parts.push(value);
@@ -165,7 +164,7 @@ const staticFileUrlPath = (argument) => {
165
164
  return undefined;
166
165
  return isSourceFileUrl(argument)
167
166
  ? sourceRelativeFileUrlPath(argument)
168
- : staticPathAt(argument);
167
+ : staticPath(argument);
169
168
  };
170
169
  /** Project a known source-relative URL through the actual file URL decoder. */
171
170
  const sourceRelativeFileUrlPath = (node) => {
@@ -214,7 +213,7 @@ const staticResolvedPath = (node) => {
214
213
  parts.push(null);
215
214
  continue;
216
215
  }
217
- const value = t.isNode(argument) ? staticPathAt(argument) : undefined;
216
+ const value = t.isNode(argument) ? staticPath(argument) : undefined;
218
217
  // Validate every argument, including those before the last anchor.
219
218
  if (value === undefined)
220
219
  return undefined;
@@ -522,9 +521,20 @@ const pointForOffset = (source, offset) => {
522
521
  /** Observe known bundler/framework marker strings without claiming dependency use. */
523
522
  export const detectVendors = (source) => vendorPatterns.flatMap(({ name, patterns }) => patterns.some((pattern) => source.includes(pattern)) ? [name] : []);
524
523
  /** Commit the static semantic content used to deduplicate registrations. */
525
- export const registrationKey = (registration) => `${registration.runtime}\0${registration.chunk_keys.join("\0")}\0${String(registration.unknown_chunk_keys)}\0${registration.modules.map(({ module_key: key, source_sha256: digest }) => `${key}:${digest}`).join("\0")}`;
524
+ export const registrationKey = (registration) =>
525
+ // Collision-free tuple: chunk/module keys are variable-length source-derived
526
+ // lists, so NUL-joins would collapse ["a\0b"] with ["a", "b"].
527
+ compositeKey([
528
+ registration.runtime,
529
+ registration.chunk_keys,
530
+ String(registration.unknown_chunk_keys),
531
+ registration.modules.map(({ module_key: key, source_sha256: digest }) => [
532
+ key,
533
+ digest,
534
+ ]),
535
+ ]);
526
536
  /** Sort values by a deterministic unique semantic key. */
527
- export const sortedUnique = (values, key) => [...new Map(values.map((value) => [key(value), value])).values()].sort((left, right) => compareCodePoints(key(left), key(right)));
537
+ export const sortedUnique = (values, key) => [...new Map(values.map((value) => [key(value), value])).values()].sort((left, right) => compareUnicodeCodePoints(key(left), key(right)));
528
538
  /** Hash exact UTF-8 source text. */
529
539
  export const sha256Text = (value) => createHash("sha256").update(value).digest("hex");
530
540
  /** Recognized route-construction call suffixes. */
@@ -1,7 +1,9 @@
1
- import { compareCodePoints, uniqueSorted } from "../canonicalOrdering.js";
2
- import { absenceClaimable, canonicalDigest } from "../comparisonSemantics.js";
1
+ import { uniqueSorted } from "../canonicalOrdering.js";
2
+ import { compareUnicodeCodePoints } from "../unicodeCodePointOrder.js";
3
+ import { absenceClaimable } from "../comparisonSemantics.js";
4
+ import { digestCanonicalValue } from "../canonicalDigest.js";
3
5
  import { SOURCE_TO_BUNDLE_SIGNAL_WEIGHTS, sourceToBundleComparisonResultSchema, } from "./sourceToBundleComparisonSchemas.js";
4
- import { buildSourceToBundleCandidateIndex, candidateIdsForSource, historicalSourceFiles, scoreSourceToBundleCandidate, sourceBearingNodes, } from "./sourceToBundleSignals.js";
6
+ import { buildSourceToBundleCandidateIndex, candidateHasDigest, candidateIdsForSource, historicalSourceFiles, scoreSourceToBundleCandidate, sourceBearingNodes, } from "./sourceToBundleSignals.js";
5
7
  /** Compare historical source files to static source-bearing application nodes. */
6
8
  export const compareSourceToBundle = (input) => {
7
9
  const projection = projectComparison(input);
@@ -33,7 +35,7 @@ export const compareSourceToBundle = (input) => {
33
35
  };
34
36
  return sourceToBundleComparisonResultSchema.parse({
35
37
  ...semanticResult,
36
- comparison_id: `stbc_${canonicalDigest(semanticResult, "Source-to-bundle comparison")}`,
38
+ comparison_id: `stbc_${digestCanonicalValue(semanticResult, "Source-to-bundle comparison")}`,
37
39
  });
38
40
  };
39
41
  const projectComparison = (input) => {
@@ -63,7 +65,7 @@ const compareMappings = (input, projection) => {
63
65
  .map((nodeId) => scoreSourceToBundleCandidate(source, nodeId, projection.index))
64
66
  .filter((candidate) => candidate !== null)
65
67
  .sort(compareCandidates);
66
- const classification = classifyMapping(scored, projection.absenceComplete);
68
+ const classification = classifyMapping(scored, projection.absenceComplete, (nodeId) => source.sha256 !== null && candidateHasDigest(projection.index, nodeId));
67
69
  const semantic = {
68
70
  source_path: source.path,
69
71
  source_sha256: source.sha256,
@@ -103,7 +105,7 @@ const scoringModel = () => ({
103
105
  weight,
104
106
  })),
105
107
  });
106
- const classifyMapping = (candidates, absenceComplete) => {
108
+ const classifyMapping = (candidates, absenceComplete, digestComparable) => {
107
109
  const exact = candidates.filter((candidate) => hasSignal(candidate, "exact-source-digest"));
108
110
  if (exact.length === 1)
109
111
  return {
@@ -134,6 +136,15 @@ const classifyMapping = (candidates, absenceComplete) => {
134
136
  : pathCandidates.filter(({ score }) => score === topScore);
135
137
  if (topPathCandidates.length === 1) {
136
138
  const candidate = topPathCandidates[0];
139
+ if (candidate !== undefined && digestComparable(candidate.current_node_id))
140
+ return {
141
+ status: "modified",
142
+ confidence: candidate.confidence === "high" ? "high" : "medium",
143
+ currentNodeIds: [candidate.current_node_id],
144
+ limitations: [
145
+ "Location evidence links the source to the current node, but their source digests differ.",
146
+ ],
147
+ };
137
148
  return {
138
149
  status: "unknown",
139
150
  confidence: "unknown",
@@ -209,7 +220,7 @@ const markMergedMappings = (input, items) => {
209
220
  return { ...semantic, mapping_id: mappingId(input, semantic) };
210
221
  });
211
222
  };
212
- const mappingId = (input, item) => `stbc_item_${canonicalDigest({
223
+ const mappingId = (input, item) => `stbc_item_${digestCanonicalValue({
213
224
  reference_root_sha256: input.reference.root_sha256,
214
225
  application_graph_id: input.application.graph.graph_id,
215
226
  ...item,
@@ -247,4 +258,4 @@ const comparisonLimitations = (factors) => uniqueSorted([
247
258
  ]);
248
259
  const hasSignal = (candidate, kind) => candidate.signals.some((signal) => signal.kind === kind);
249
260
  const compareCandidates = (left, right) => right.score - left.score ||
250
- compareCodePoints(left.current_node_id, right.current_node_id);
261
+ compareUnicodeCodePoints(left.current_node_id, right.current_node_id);
@@ -1,5 +1,5 @@
1
1
  import { posix } from "node:path";
2
- import { compareCodePoints } from "../canonicalOrdering.js";
2
+ import { compareUnicodeCodePoints, compositeKey, } from "../unicodeCodePointOrder.js";
3
3
  import { SOURCE_TO_BUNDLE_SIGNAL_WEIGHTS, } from "./sourceToBundleComparisonSchemas.js";
4
4
  import { isDigest } from "../digests.js";
5
5
  const RELEVANT_NODE_KINDS = new Set([
@@ -24,11 +24,11 @@ const signalWeight = (kind) => {
24
24
  /** Keep source-bearing application nodes in stable identifier order. */
25
25
  export const sourceBearingNodes = (nodes) => nodes
26
26
  .filter(({ kind }) => RELEVANT_NODE_KINDS.has(kind))
27
- .sort((left, right) => compareCodePoints(left.node_id, right.node_id));
27
+ .sort((left, right) => compareUnicodeCodePoints(left.node_id, right.node_id));
28
28
  /** Keep historical source files in stable path order. */
29
29
  export const historicalSourceFiles = (graph) => graph.entries
30
30
  .filter((entry) => entry.kind === "file" && entry.classifications.includes("source"))
31
- .sort((left, right) => compareCodePoints(left.path, right.path));
31
+ .sort((left, right) => compareUnicodeCodePoints(left.path, right.path));
32
32
  /** Build deterministic candidate indices without assigning fuzzy matches. */
33
33
  export const buildSourceToBundleCandidateIndex = (nodes) => {
34
34
  const projections = nodes.map(projectCurrentNode);
@@ -39,7 +39,9 @@ export const buildSourceToBundleCandidateIndex = (nodes) => {
39
39
  for (const digest of projection.digests)
40
40
  addIndexValue(byDigest, digest, projection.node.node_id);
41
41
  for (const path of projection.paths) {
42
- for (const suffix of pathSuffixes(path.value))
42
+ for (const suffix of path.allowSuffix
43
+ ? pathSuffixes(path.value)
44
+ : [path.value])
43
45
  addIndexValue(byPathSuffix, suffix, projection.node.node_id);
44
46
  addIndexValue(byBasename, posix.basename(path.value), projection.node.node_id);
45
47
  }
@@ -63,7 +65,7 @@ export const candidateIdsForSource = (source, index) => {
63
65
  for (const group of groups) {
64
66
  if (group === undefined)
65
67
  continue;
66
- for (const nodeId of [...group].sort(compareCodePoints)) {
68
+ for (const nodeId of [...group].sort(compareUnicodeCodePoints)) {
67
69
  if (seen.has(nodeId))
68
70
  continue;
69
71
  seen.add(nodeId);
@@ -72,6 +74,8 @@ export const candidateIdsForSource = (source, index) => {
72
74
  }
73
75
  return output;
74
76
  };
77
+ /** Whether an indexed candidate carries any content digest to compare. */
78
+ export const candidateHasDigest = (index, nodeId) => (index.nodes.get(nodeId)?.digests.size ?? 0) > 0;
75
79
  /** Score one indexed candidate from explicit, caller-visible signals. */
76
80
  export const scoreSourceToBundleCandidate = (source, nodeId, index) => {
77
81
  const projection = index.nodes.get(nodeId);
@@ -97,16 +101,26 @@ const projectCurrentNode = (node) => {
97
101
  if (node.identity.strategy === "source-map-original") {
98
102
  if (node.identity.source_sha256 !== null)
99
103
  digests.add(node.identity.source_sha256);
100
- addPath(paths, "source-map-original", node.identity.original_source);
101
104
  }
102
105
  if (node.identity.strategy === "canonical-path")
103
106
  addPath(paths, "canonical-path", node.identity.path);
104
107
  for (const observation of node.observations) {
105
- const sourceDigest = observation.properties.source_sha256;
106
- if (typeof sourceDigest === "string" && isDigest(sourceDigest))
107
- digests.add(sourceDigest);
108
- for (const key of PATH_PROPERTIES)
109
- addJsonPath(paths, observation.properties[key]);
108
+ if (node.identity.strategy === "source-map-original") {
109
+ const resolution = observation.source_map_reference?.resolution;
110
+ if (resolution !== undefined && resolution.kind !== "unresolved")
111
+ paths.push({
112
+ kind: "source-map-original",
113
+ value: resolution.path,
114
+ allowSuffix: resolution.kind === "suffix",
115
+ });
116
+ }
117
+ else {
118
+ const sourceDigest = observation.properties.source_sha256;
119
+ if (typeof sourceDigest === "string" && isDigest(sourceDigest))
120
+ digests.add(sourceDigest);
121
+ for (const key of PATH_PROPERTIES)
122
+ addJsonPath(paths, observation.properties[key]);
123
+ }
110
124
  }
111
125
  return {
112
126
  node,
@@ -128,7 +142,9 @@ const candidateSignals = (source, current) => {
128
142
  if (exactPaths.length > 0)
129
143
  signals.push(signal("current-path-exact", source.path, exactPaths));
130
144
  const suffixPaths = otherPaths
131
- .filter(({ value }) => value !== source.path && value.endsWith(`/${source.path}`))
145
+ .filter(({ value, allowSuffix }) => allowSuffix &&
146
+ value !== source.path &&
147
+ value.endsWith(`/${source.path}`))
132
148
  .map(({ value }) => value);
133
149
  if (suffixPaths.length > 0)
134
150
  signals.push(signal("current-path-suffix", source.path, suffixPaths));
@@ -150,7 +166,7 @@ const signal = (kind, sourceValue, currentValues) => ({
150
166
  kind,
151
167
  weight: signalWeight(kind),
152
168
  source_value: sourceValue,
153
- current_values: [...new Set(currentValues)].sort(compareCodePoints),
169
+ current_values: [...new Set(currentValues)].sort(compareUnicodeCodePoints),
154
170
  });
155
171
  const candidateConfidence = (signals) => {
156
172
  const kinds = new Set(signals.map(({ kind }) => kind));
@@ -161,7 +177,8 @@ const candidateConfidence = (signals) => {
161
177
  return kinds.has("current-path-suffix") ? "medium" : "low";
162
178
  };
163
179
  const matchingPaths = (sourcePath, currentPaths) => currentPaths
164
- .filter(({ value }) => value === sourcePath || value.endsWith(`/${sourcePath}`))
180
+ .filter(({ value, allowSuffix }) => value === sourcePath ||
181
+ (allowSuffix && value.endsWith(`/${sourcePath}`)))
165
182
  .map(({ value }) => value);
166
183
  const addJsonPath = (paths, value) => {
167
184
  if (typeof value === "string")
@@ -170,28 +187,39 @@ const addJsonPath = (paths, value) => {
170
187
  const addPath = (paths, kind, raw) => {
171
188
  const value = normalizeCurrentPath(raw);
172
189
  if (value !== null)
173
- paths.push({ kind, value });
190
+ paths.push({ kind, value, allowSuffix: true });
174
191
  };
175
- /** Matches a `scheme://...` URL prefix; bare filesystem paths keep `?`/`#`. */
176
192
  const SCHEME_URL = /^[a-z][a-z0-9+.-]*:\/\//iu;
177
- /** Matches a `scheme://...` URL prefix with any run of slashes, for stripping. */
178
193
  const SCHEME_URL_PREFIX = /^[a-z][a-z0-9+.-]*:\/\/+/iu;
179
194
  const normalizeCurrentPath = (raw) => {
180
195
  const withoutQuery = SCHEME_URL.test(raw)
181
196
  ? (raw.split(/[?#]/u, 1)[0] ?? "")
182
197
  : raw;
183
- const withoutScheme = withoutQuery.replace(SCHEME_URL_PREFIX, "");
184
- const parts = withoutScheme
185
- .replaceAll("\\", "/")
186
- .split("/")
187
- .filter((part) => part !== "" && part !== ".");
188
- if (parts.length === 0 || parts.includes(".."))
198
+ const portable = withoutQuery
199
+ .replace(SCHEME_URL_PREFIX, "")
200
+ .replaceAll("\\", "/");
201
+ const parts = [];
202
+ for (const part of portable.split("/")) {
203
+ if (part === "" || part === ".")
204
+ continue;
205
+ if (part === "..") {
206
+ if (parts.length === 0)
207
+ return null;
208
+ parts.pop();
209
+ }
210
+ else
211
+ parts.push(part);
212
+ }
213
+ if (parts.length === 0)
189
214
  return null;
190
215
  return parts.join("/");
191
216
  };
192
217
  const uniquePaths = (paths) => [
193
- ...new Map(paths.map((path) => [`${path.kind}\0${path.value}`, path])).values(),
194
- ].sort((left, right) => compareCodePoints(`${left.kind}\0${left.value}`, `${right.kind}\0${right.value}`));
218
+ ...new Map(paths.map((path) => [
219
+ compositeKey([path.kind, path.value, String(path.allowSuffix)]),
220
+ path,
221
+ ])).values(),
222
+ ].sort((left, right) => compareUnicodeCodePoints(compositeKey([left.kind, left.value]), compositeKey([right.kind, right.value])));
195
223
  const pathSuffixes = (path) => {
196
224
  const parts = path.split("/");
197
225
  return parts.map((_, index) => parts.slice(index).join("/"));
@@ -1,10 +1,10 @@
1
1
  /** Encode ordinary JSON as bounded string parts without a document-sized allocation. */
2
2
  export function* jsonParts(value, pretty = false) {
3
- yield* encodeValue(value, pretty, 0, new Set(), false);
3
+ yield* encodeValue(value, pretty, false);
4
4
  }
5
5
  /** Encode validated JSON with canonical key ordering without allocating the whole document. */
6
6
  export function* canonicalJsonParts(value) {
7
- yield* encodeValue(value, false, 0, new Set(), true);
7
+ yield* encodeValue(value, false, true);
8
8
  }
9
9
  /** Buffer JSON parts while preserving complete UTF-16 surrogate pairs. */
10
10
  export function* bufferedJsonParts(parts) {
@@ -41,69 +41,123 @@ function* encodeString(value) {
41
41
  }
42
42
  yield '"';
43
43
  }
44
- function* encodeValue(value, pretty, depth, ancestors, canonical) {
45
- if (typeof value === "string") {
46
- yield* encodeString(value);
47
- return;
48
- }
49
- if (value === null || typeof value === "boolean") {
50
- yield value === null ? "null" : String(value);
51
- return;
52
- }
53
- if (typeof value === "number" && Number.isFinite(value)) {
54
- yield String(value);
55
- return;
56
- }
44
+ /** Encoded text accumulated before it is yielded as one part. */
45
+ const PART_CHARACTERS = 16 * 1024;
46
+ const indentation = [];
47
+ const indent = (depth) => (indentation[depth] ??= `\n${" ".repeat(depth)}`);
48
+ /** Encoded text of a scalar, or undefined for a container or a long string. */
49
+ const scalarText = (value) => {
50
+ if (typeof value === "string")
51
+ return value.length <= 8192 ? JSON.stringify(value) : undefined;
52
+ if (value === null)
53
+ return "null";
54
+ if (typeof value === "boolean")
55
+ return String(value);
56
+ if (typeof value === "number" && Number.isFinite(value))
57
+ return String(value);
58
+ return undefined;
59
+ };
60
+ const openContainer = (value, depth, ancestors, canonical) => {
57
61
  if (typeof value !== "object" || value === null)
58
62
  throw new TypeError("JSON output requires ordinary JSON values");
59
63
  if (ancestors.has(value))
60
64
  throw new TypeError("JSON output contains a circular reference");
61
- if (!Array.isArray(value) &&
62
- Object.prototype.toString.call(value) !== "[object Object]")
65
+ const array = Array.isArray(value);
66
+ if (!array && Object.prototype.toString.call(value) !== "[object Object]")
63
67
  throw new TypeError("JSON output requires ordinary JSON objects");
64
68
  ancestors.add(value);
65
- try {
66
- const array = Array.isArray(value);
67
- const keys = array ? undefined : Object.keys(value);
68
- if (canonical)
69
- keys?.sort();
70
- const count = array ? value.length : (keys?.length ?? 0);
71
- let written = 0;
72
- yield array ? "[" : "{";
73
- for (let index = 0; index < count; index += 1) {
74
- let item;
75
- let key;
76
- if (array) {
77
- item = value[index];
69
+ const keys = array ? undefined : Object.keys(value);
70
+ if (canonical)
71
+ keys?.sort();
72
+ const count = array ? value.length : (keys?.length ?? 0);
73
+ return { value, array, keys, count, depth, index: 0, written: 0 };
74
+ };
75
+ /** The next written member of a container, skipping values JSON omits. */
76
+ const nextMember = (frame) => {
77
+ while (frame.index < frame.count) {
78
+ const index = frame.index;
79
+ frame.index += 1;
80
+ if (frame.array)
81
+ return { key: undefined, item: Reflect.get(frame.value, index) };
82
+ const key = frame.keys?.[index];
83
+ if (key === undefined)
84
+ throw new TypeError("JSON object changed during serialization");
85
+ const item = Reflect.get(frame.value, key);
86
+ // Incur's filter can select inherited methods. Match native JSON's
87
+ // omission without eagerly reading the rest of a bounded result.
88
+ if (item !== undefined &&
89
+ typeof item !== "function" &&
90
+ typeof item !== "symbol")
91
+ return { key, item };
92
+ }
93
+ return undefined;
94
+ };
95
+ /**
96
+ * Encode iteratively into bounded parts. Recursive `yield*` delegation passed
97
+ * every token through one generator frame per nesting level, which dominated
98
+ * the cost of writing large nested results.
99
+ */
100
+ function* encodeValue(root, pretty, canonical) {
101
+ const ancestors = new Set();
102
+ const stack = [];
103
+ let buffer = "";
104
+ let pending = root;
105
+ let hasPending = true;
106
+ while (true) {
107
+ if (hasPending) {
108
+ hasPending = false;
109
+ const text = scalarText(pending);
110
+ if (text !== undefined)
111
+ buffer += text;
112
+ else if (typeof pending === "string") {
113
+ // A long string is split into surrogate-safe parts of its own.
114
+ if (buffer !== "")
115
+ yield buffer;
116
+ buffer = "";
117
+ yield* encodeString(pending);
78
118
  }
79
119
  else {
80
- key = keys?.[index];
81
- if (key === undefined)
82
- throw new TypeError("JSON object changed during serialization");
83
- item = Reflect.get(value, key);
84
- // Incur's filter can select inherited methods. Match native JSON's
85
- // omission without eagerly reading the rest of a bounded result.
86
- if (item === undefined ||
87
- typeof item === "function" ||
88
- typeof item === "symbol")
89
- continue;
120
+ const frame = openContainer(pending, stack.length, ancestors, canonical);
121
+ stack.push(frame);
122
+ buffer += frame.array ? "[" : "{";
90
123
  }
91
- if (written > 0)
92
- yield ",";
93
- if (pretty)
94
- yield `\n${" ".repeat(depth + 1)}`;
95
- if (key !== undefined) {
96
- yield* encodeString(key);
97
- yield pretty ? ": " : ":";
124
+ }
125
+ if (buffer.length >= PART_CHARACTERS) {
126
+ yield buffer;
127
+ buffer = "";
128
+ }
129
+ const frame = stack.at(-1);
130
+ if (frame === undefined)
131
+ break;
132
+ const member = nextMember(frame);
133
+ if (member === undefined) {
134
+ if (pretty && frame.written > 0)
135
+ buffer += indent(frame.depth);
136
+ buffer += frame.array ? "]" : "}";
137
+ ancestors.delete(frame.value);
138
+ stack.pop();
139
+ continue;
140
+ }
141
+ if (frame.written > 0)
142
+ buffer += ",";
143
+ if (pretty)
144
+ buffer += indent(frame.depth + 1);
145
+ if (member.key !== undefined) {
146
+ const key = scalarText(member.key);
147
+ if (key !== undefined)
148
+ buffer += key;
149
+ else {
150
+ if (buffer !== "")
151
+ yield buffer;
152
+ buffer = "";
153
+ yield* encodeString(member.key);
98
154
  }
99
- yield* encodeValue(item, pretty, depth + 1, ancestors, canonical);
100
- written += 1;
155
+ buffer += pretty ? ": " : ":";
101
156
  }
102
- if (pretty && written > 0)
103
- yield `\n${" ".repeat(depth)}`;
104
- yield array ? "]" : "}";
105
- }
106
- finally {
107
- ancestors.delete(value);
157
+ frame.written += 1;
158
+ pending = member.item;
159
+ hasPending = true;
108
160
  }
161
+ if (buffer !== "")
162
+ yield buffer;
109
163
  }
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { compareCodePoints } from "./canonicalOrdering.js";
2
+ import { compareUnicodeCodePoints } from "./unicodeCodePointOrder.js";
3
3
  const jsonValueTypeSchema = z.enum([
4
4
  "object",
5
5
  "array",
@@ -8,13 +8,17 @@ const jsonValueTypeSchema = z.enum([
8
8
  "boolean",
9
9
  "null",
10
10
  ]);
11
+ const jsonShapePathSegmentSchema = z.discriminatedUnion("kind", [
12
+ z.object({ kind: z.literal("property"), name: z.string() }),
13
+ z.object({ kind: z.literal("array-element") }),
14
+ ]);
11
15
  /** Value-free structural summary of one approved JSON payload. */
12
16
  export const jsonShapeSchema = z.object({
13
17
  root_type: jsonValueTypeSchema,
14
18
  node_count: z.number().int().min(1),
15
19
  max_depth_observed: z.number().int().min(0),
16
20
  properties: z.array(z.object({
17
- path: z.string(),
21
+ path: z.array(jsonShapePathSegmentSchema).min(1),
18
22
  types: z.array(jsonValueTypeSchema).min(1),
19
23
  observations: z.number().int().min(1),
20
24
  })),
@@ -31,7 +35,7 @@ export const inferJsonShape = (text) => {
31
35
  return null;
32
36
  }
33
37
  const properties = new Map();
34
- const pending = [{ value: root, path: "", depth: 0 }];
38
+ const pending = [{ value: root, path: [], depth: 0 }];
35
39
  let nodeCount = 0;
36
40
  let maxDepthObserved = 0;
37
41
  while (pending.length > 0) {
@@ -40,11 +44,26 @@ export const inferJsonShape = (text) => {
40
44
  break;
41
45
  nodeCount += 1;
42
46
  maxDepthObserved = Math.max(maxDepthObserved, current.depth);
47
+ if (current.path.length > 0) {
48
+ const key = JSON.stringify(current.path);
49
+ const type = jsonValueType(current.value);
50
+ const existing = properties.get(key);
51
+ if (existing === undefined)
52
+ properties.set(key, {
53
+ path: current.path,
54
+ types: new Set([type]),
55
+ observations: 1,
56
+ });
57
+ else {
58
+ existing.types.add(type);
59
+ existing.observations += 1;
60
+ }
61
+ }
43
62
  if (Array.isArray(current.value)) {
44
63
  for (let index = current.value.length - 1; index >= 0; index -= 1)
45
64
  pending.push({
46
65
  value: current.value[index],
47
- path: `${current.path}/*`,
66
+ path: [...current.path, { kind: "array-element" }],
48
67
  depth: current.depth + 1,
49
68
  });
50
69
  continue;
@@ -57,15 +76,10 @@ export const inferJsonShape = (text) => {
57
76
  if (entry === undefined)
58
77
  continue;
59
78
  const [name, value] = entry;
60
- const path = `${current.path}/${pointerName(name)}`;
61
- const type = jsonValueType(value);
62
- const existing = properties.get(path);
63
- if (existing === undefined)
64
- properties.set(path, { types: new Set([type]), observations: 1 });
65
- else {
66
- existing.types.add(type);
67
- existing.observations += 1;
68
- }
79
+ const path = [
80
+ ...current.path,
81
+ { kind: "property", name },
82
+ ];
69
83
  pending.push({ value, path, depth: current.depth + 1 });
70
84
  }
71
85
  }
@@ -73,14 +87,13 @@ export const inferJsonShape = (text) => {
73
87
  root_type: jsonValueType(root),
74
88
  node_count: nodeCount,
75
89
  max_depth_observed: maxDepthObserved,
76
- properties: [...properties.entries()]
77
- .map(([path, value]) => ({
78
- path,
90
+ properties: [...properties.values()]
91
+ .map((value) => ({
92
+ path: value.path,
79
93
  types: [...value.types].sort(),
80
94
  observations: value.observations,
81
95
  }))
82
- .sort((left, right) => left.path.localeCompare(right.path) ||
83
- compareCodePoints(left.path, right.path)),
96
+ .sort((left, right) => compareShapePaths(left.path, right.path)),
84
97
  });
85
98
  };
86
99
  const jsonValueType = (value) => {
@@ -100,4 +113,18 @@ const jsonValueType = (value) => {
100
113
  }
101
114
  };
102
115
  const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
103
- const pointerName = (value) => value.replaceAll("~", "~0").replaceAll("/", "~1");
116
+ const compareShapePaths = (left, right) => {
117
+ for (let index = 0; index < Math.min(left.length, right.length); index += 1) {
118
+ const a = left[index];
119
+ const b = right[index];
120
+ if (a === undefined || b === undefined)
121
+ break;
122
+ const order = compareUnicodeCodePoints(a.kind, b.kind) ||
123
+ (a.kind === "property" && b.kind === "property"
124
+ ? compareUnicodeCodePoints(a.name, b.name)
125
+ : 0);
126
+ if (order !== 0)
127
+ return order;
128
+ }
129
+ return left.length - right.length;
130
+ };