rea-agents 6.2.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 (297) hide show
  1. package/README.md +18 -20
  2. package/bridge/hopper_bridge.py +2 -0
  3. package/dist/android/JadxProvider.js +8 -2
  4. package/dist/android/JadxSession.js +51 -9
  5. package/dist/application/BinaryTargetResolver.js +63 -17
  6. package/dist/application/BrowserScenarioEvidence.js +2 -2
  7. package/dist/application/ClientConfigurationDocument.js +28 -0
  8. package/dist/application/ClientRegistrationStatus.js +19 -6
  9. package/dist/application/DirectAnalysis.js +12 -6
  10. package/dist/application/DirectAnalysisCleanup.js +0 -1
  11. package/dist/application/DirectAnalysisStatus.js +2 -5
  12. package/dist/application/Doctor.js +25 -34
  13. package/dist/application/DoctorDiagnostics.js +1 -1
  14. package/dist/application/EvidenceBundleFiles.js +1 -1
  15. package/dist/application/InvestigationProviders.js +4 -4
  16. package/dist/application/JsonFiles.js +15 -15
  17. package/dist/application/LinuxHopper.js +2 -1
  18. package/dist/application/ReconstructionObligationCandidates.js +9 -2
  19. package/dist/application/ReconstructionObligationLedgerProjection.js +3 -1
  20. package/dist/application/RegularFileRead.js +17 -0
  21. package/dist/application/Setup.js +18 -7
  22. package/dist/application/SetupClientConfiguration.js +18 -7
  23. package/dist/application/SetupHost.js +6 -4
  24. package/dist/application/SetupPlan.js +19 -15
  25. package/dist/application/SetupSkill.js +57 -8
  26. package/dist/application/SupportedClients.js +43 -0
  27. package/dist/application/Uninstall.js +18 -2
  28. package/dist/application/UpdateMaintenance.js +6 -2
  29. package/dist/application/Utf8JsonInput.js +64 -0
  30. package/dist/application/WebScriptExportService.js +13 -6
  31. package/dist/application/android/AndroidAnalysisService.js +1 -1
  32. package/dist/application/binary/AnalysisSnapshotCache.js +5 -4
  33. package/dist/application/binary/BinarySession.js +16 -0
  34. package/dist/application/binary/BinarySessionOpen.js +9 -1
  35. package/dist/application/javascript/ElectronActiveEvidence.js +2 -2
  36. package/dist/application/javascript/ElectronBoundaryAnalysis.js +2 -2
  37. package/dist/application/javascript/ElectronBoundaryGraphNative.js +5 -1
  38. package/dist/application/javascript/JavaScriptApplicationEvidence.js +1 -0
  39. package/dist/application/javascript/JavaScriptApplicationEvidenceGraph.js +107 -46
  40. package/dist/application/javascript/JavaScriptApplicationService.js +1 -0
  41. package/dist/application/javascript/JavaScriptApplicationWorkflowService.js +59 -45
  42. package/dist/application/javascript/JavaScriptArtifactAnalysis.js +0 -6
  43. package/dist/application/javascript/JavaScriptArtifactGraphBuilder.js +8 -18
  44. package/dist/application/javascript/JavaScriptArtifactGraphFindings.js +34 -26
  45. package/dist/application/javascript/JavaScriptArtifactPathResolution.js +44 -12
  46. package/dist/application/javascript/JavaScriptArtifactReconstruction.js +6 -3
  47. package/dist/application/javascript/JavaScriptArtifactReconstructionInput.js +1 -0
  48. package/dist/application/javascript/JavaScriptJsonModules.js +2 -2
  49. package/dist/application/javascript/JavaScriptModuleRelationships.js +5 -17
  50. package/dist/application/javascript/JavaScriptRuntimeReconciliationService.js +11 -27
  51. package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +2 -2
  52. package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +8 -6
  53. package/dist/application/javascript/JavaScriptSemanticGraphChildProcessProjection.js +1 -1
  54. package/dist/application/javascript/JavaScriptSemanticGraphConstruction.js +7 -5
  55. package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +1 -1
  56. package/dist/application/javascript/JavaScriptSemanticGraphEvidence.js +1 -1
  57. package/dist/application/javascript/JavaScriptSemanticGraphFingerprintProjection.js +2 -2
  58. package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +2 -2
  59. package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +1 -1
  60. package/dist/application/javascript/JavaScriptSemanticGraphProjection.js +4 -4
  61. package/dist/application/javascript/JavaScriptSemanticGraphResourceProjection.js +1 -1
  62. package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +10 -7
  63. package/dist/application/javascript/JavaScriptSemanticTraceService.js +15 -10
  64. package/dist/application/native/NativeCallRoutes.js +2 -4
  65. package/dist/artifacts/ArtifactProvider.js +14 -16
  66. package/dist/artifacts/ArtifactProviderMetadata.js +1 -4
  67. package/dist/artifacts/AsarArtifactReader.js +81 -17
  68. package/dist/artifacts/DirectoryArtifactReader.js +2 -2
  69. package/dist/artifacts/NativeDmgArtifactReader.js +152 -67
  70. package/dist/artifacts/NativeDmgOwnership.js +109 -0
  71. package/dist/artifacts/apple/KeyedArchiveReader.js +54 -46
  72. package/dist/artifacts/apple/MachoLoadCommandReader.js +36 -6
  73. package/dist/artifacts/extraction/ArtifactExtraction.js +29 -11
  74. package/dist/artifacts/inventory/ArtifactGraphConstruction.js +7 -8
  75. package/dist/artifacts/inventory/classify.js +33 -14
  76. package/dist/artifacts/inventory/hashStableRootArtifact.js +37 -0
  77. package/dist/artifacts/inventory/scanCanonical.js +28 -22
  78. package/dist/artifacts/inventory/scanReader.js +7 -11
  79. package/dist/artifacts/javascript/JavaScriptArtifactFiles.js +65 -27
  80. package/dist/browser/CdpBrowserProvider.js +4 -3
  81. package/dist/browser/CdpCaptureStorageFingerprints.js +3 -3
  82. package/dist/browser/CdpElectronInspection.js +2 -2
  83. package/dist/browser/CdpElectronProvider.js +4 -3
  84. package/dist/browser/CdpElectronScripts.js +2 -2
  85. package/dist/browser/CdpWebMcpDiscovery.js +16 -13
  86. package/dist/browser/PlaywrightBrowserScenarioProvider.js +6 -6
  87. package/dist/browser/PlaywrightScenarioBrowser.js +145 -42
  88. package/dist/browser/PlaywrightScenarioSession.js +3 -11
  89. package/dist/browser/WebSourceMapFetcher.js +32 -6
  90. package/dist/browser/assets/ScenarioScriptCapture.js +8 -12
  91. package/dist/cli/coreAnalysisCommands.js +2 -2
  92. package/dist/cli/coreBinaryCommands.js +13 -9
  93. package/dist/cli/electronCommands.js +9 -10
  94. package/dist/cli/javascriptApplicationAnalysis.js +2 -12
  95. package/dist/cli/jsonOutput.js +3 -2
  96. package/dist/cli/streamedJsonOutput.js +83 -4
  97. package/dist/cli/utilityCommands.js +2 -4
  98. package/dist/cli.js +5 -2
  99. package/dist/cliJsonFile.js +179 -0
  100. package/dist/cliJsonInput.js +47 -34
  101. package/dist/cliObservationOptions.js +4 -0
  102. package/dist/composition/auxiliaryAnalysisProviders.js +5 -4
  103. package/dist/composition/browserScenario.js +2 -2
  104. package/dist/composition/directAnalysis.js +2 -3
  105. package/dist/contracts/artifactComparisonExample.js +5 -5
  106. package/dist/contracts/errorSchemas.js +3 -1
  107. package/dist/contracts/functionComparisonExample.js +8 -0
  108. package/dist/contracts/inputSchemaPresentation.js +94 -3
  109. package/dist/contracts/javascript/electronToolContracts.js +2 -1
  110. package/dist/contracts/javascript/javascriptApplicationWorkflowExamples.js +3 -2
  111. package/dist/contracts/javascript/javascriptExportShapeComparisonExample.js +6 -3
  112. package/dist/contracts/javascript/javascriptRuntimeReconciliationExample.js +8 -7
  113. package/dist/contracts/managed/managedToolContracts.js +3 -2
  114. package/dist/contracts/mobileApplicationGraphExamples.js +5 -5
  115. package/dist/contracts/native/nativeToolContracts.js +1 -1
  116. package/dist/contracts/sessionLifecycleInputs.js +4 -3
  117. package/dist/contracts/sessionStatusContract.js +3 -2
  118. package/dist/contracts/sessionToolContracts.js +3 -2
  119. package/dist/contracts/sessionToolSchemas.js +3 -2
  120. package/dist/contracts/toolOutputSchemaGroups.js +2 -2
  121. package/dist/contracts/toolOutputSchemaPrimitives.js +2 -5
  122. package/dist/domain/analysisErrorBase.js +5 -0
  123. package/dist/domain/analysisErrorPresentation.js +4 -2
  124. package/dist/domain/analysisSnapshot.js +3 -1
  125. package/dist/domain/analysisView/analysisView.js +1 -3
  126. package/dist/domain/android/androidPartialObservation.js +36 -0
  127. package/dist/domain/apple/dylibResolution.js +1 -1
  128. package/dist/domain/artifactComparison.js +4 -4
  129. package/dist/domain/artifactGraph.js +1 -1
  130. package/dist/domain/artifactIdentity.js +8 -8
  131. package/dist/domain/artifactInspection.js +8 -8
  132. package/dist/domain/artifactInventoryEvidence.js +5 -5
  133. package/dist/domain/browserCompleteness.js +3 -2
  134. package/dist/domain/browserScenarioCaptureValues.js +2 -2
  135. package/dist/domain/browserScenarioNormalization.js +3 -3
  136. package/dist/domain/browserScenarioValues.js +3 -2
  137. package/dist/domain/callPath.js +8 -10
  138. package/dist/domain/canonicalDigest.js +7 -1
  139. package/dist/domain/canonicalOrdering.js +1 -13
  140. package/dist/domain/changedBehavior.js +2 -3
  141. package/dist/domain/comparisonSemantics.js +0 -5
  142. package/dist/domain/digests.js +0 -3
  143. package/dist/domain/evidence.js +10 -5
  144. package/dist/domain/evidenceBundle.js +51 -33
  145. package/dist/domain/firmware/firmwareAnalysis.js +4 -3
  146. package/dist/domain/functionComparison.js +2 -1
  147. package/dist/domain/functionComparisonNormalization.js +4 -3
  148. package/dist/domain/functionComparisonResults.js +2 -2
  149. package/dist/domain/functionDossierEvidence.js +2 -1
  150. package/dist/domain/hopperValues.js +11 -15
  151. package/dist/domain/javascript/electronActiveObservation.js +4 -3
  152. package/dist/domain/javascript/electronStaticAnalysisBrowser.js +2 -2
  153. package/dist/domain/javascript/electronStaticAnalysisIpc.js +9 -1
  154. package/dist/domain/javascript/electronStaticAnalysisNative.js +5 -3
  155. package/dist/domain/javascript/electronStaticAnalysisValues.js +8 -4
  156. package/dist/domain/javascript/javascriptApplicationAnalysis.js +3 -1
  157. package/dist/domain/javascript/javascriptApplicationChangeGraph.js +12 -8
  158. package/dist/domain/javascript/javascriptApplicationEvidenceSchemas.js +4 -0
  159. package/dist/domain/javascript/javascriptApplicationGraph.js +15 -13
  160. package/dist/domain/javascript/javascriptApplicationVersionComparison.js +4 -4
  161. package/dist/domain/javascript/javascriptApplicationVersionComparisonSchemas.js +37 -22
  162. package/dist/domain/javascript/javascriptApplicationVersionItems.js +45 -34
  163. package/dist/domain/javascript/javascriptApplicationVersionKeys.js +7 -7
  164. package/dist/domain/javascript/javascriptAstFingerprint.js +2 -2
  165. package/dist/domain/javascript/javascriptAstValues.js +22 -0
  166. package/dist/domain/javascript/javascriptExportShapeComparison.js +3 -2
  167. package/dist/domain/javascript/javascriptExportShapeComparisonSchemas.js +31 -23
  168. package/dist/domain/javascript/javascriptExportShapeSelection.js +2 -2
  169. package/dist/domain/javascript/javascriptExportShapeVariants.js +3 -2
  170. package/dist/domain/javascript/javascriptFeatureSeed.js +5 -3
  171. package/dist/domain/javascript/javascriptFeatureTrace.js +7 -6
  172. package/dist/domain/javascript/javascriptFeatureTraceSchemas.js +17 -9
  173. package/dist/domain/javascript/javascriptFeatureTraversal.js +4 -4
  174. package/dist/domain/javascript/javascriptNativeHandoff.js +6 -6
  175. package/dist/domain/javascript/javascriptRuntimeObservation.js +8 -5
  176. package/dist/domain/javascript/javascriptRuntimeReconciliation.js +12 -6
  177. package/dist/domain/javascript/javascriptRuntimeReconciliationActive.js +9 -8
  178. package/dist/domain/javascript/javascriptRuntimeReconciliationCaptureParsing.js +212 -0
  179. package/dist/domain/javascript/javascriptRuntimeReconciliationGraph.js +5 -4
  180. package/dist/domain/javascript/javascriptRuntimeReconciliationInputValidation.js +28 -0
  181. package/dist/domain/javascript/javascriptRuntimeReconciliationMatching.js +5 -5
  182. package/dist/domain/javascript/javascriptRuntimeReconciliationParsing.js +12 -223
  183. package/dist/domain/javascript/javascriptRuntimeReconciliationResult.js +2 -2
  184. package/dist/domain/javascript/javascriptRuntimeReconciliationRuntime.js +15 -4
  185. package/dist/domain/javascript/javascriptRuntimeReconciliationSchemas.js +2 -2
  186. package/dist/domain/javascript/javascriptRuntimeStaticCandidates.js +7 -6
  187. package/dist/domain/javascript/javascriptSemanticAnalysis.js +200 -8
  188. package/dist/domain/javascript/javascriptSemanticCallResolution.js +9 -7
  189. package/dist/domain/javascript/javascriptSemanticChildProcesses.js +2 -2
  190. package/dist/domain/javascript/javascriptSemanticCoverage.js +20 -0
  191. package/dist/domain/javascript/javascriptSemanticDataEffectHelpers.js +7 -9
  192. package/dist/domain/javascript/javascriptSemanticDataEffects.js +4 -11
  193. package/dist/domain/javascript/javascriptSemanticFingerprints.js +2 -2
  194. package/dist/domain/javascript/javascriptSemanticGraph.js +142 -35
  195. package/dist/domain/javascript/javascriptSemanticGraphSchemas.js +19 -1
  196. package/dist/domain/javascript/javascriptSemanticIr.js +0 -4
  197. package/dist/domain/javascript/javascriptSemanticIterationSources.js +106 -0
  198. package/dist/domain/javascript/javascriptSemanticMemberMutations.js +497 -113
  199. package/dist/domain/javascript/javascriptSemanticMutationInitializers.js +190 -0
  200. package/dist/domain/javascript/javascriptSemanticMutationValues.js +41 -27
  201. package/dist/domain/javascript/javascriptSemanticObjects.js +2 -6
  202. package/dist/domain/javascript/javascriptSemanticPrimitives.js +7 -2
  203. package/dist/domain/javascript/javascriptSemanticProjection.js +20 -14
  204. package/dist/domain/javascript/javascriptSemanticPromises.js +15 -21
  205. package/dist/domain/javascript/javascriptSemanticPropertyPaths.js +23 -0
  206. package/dist/domain/javascript/javascriptSemanticProvenance.js +3 -3
  207. package/dist/domain/javascript/javascriptSemanticQuery.js +8 -2
  208. package/dist/domain/javascript/javascriptSemanticQueryIdentity.js +3 -2
  209. package/dist/domain/javascript/javascriptSemanticQuerySchemas.js +8 -9
  210. package/dist/domain/javascript/javascriptSemanticRequireOrigin.js +16 -10
  211. package/dist/domain/javascript/javascriptSemanticReturns.js +23 -27
  212. package/dist/domain/javascript/javascriptSemanticTraversal.js +6 -1
  213. package/dist/domain/javascript/javascriptSemanticValues.js +135 -24
  214. package/dist/domain/javascript/javascriptSourceMapPaths.js +11 -1
  215. package/dist/domain/javascript/javascriptSourceParser.js +34 -9
  216. package/dist/domain/javascript/javascriptStaticAnalysisBundler.js +5 -6
  217. package/dist/domain/javascript/javascriptStaticAnalysisHelpers.js +26 -15
  218. package/dist/domain/javascript/sourceToBundleComparison.js +7 -5
  219. package/dist/domain/javascript/sourceToBundleSignals.js +7 -7
  220. package/dist/domain/jsonSerialization.js +109 -55
  221. package/dist/domain/jsonShape.js +46 -19
  222. package/dist/domain/localPath.js +10 -4
  223. package/dist/domain/managed/managedApplicationGraph.js +10 -6
  224. package/dist/domain/managed/managedApplicationGraphNodes.js +82 -57
  225. package/dist/domain/managed/managedMemberComparisonMatch.js +6 -7
  226. package/dist/domain/native/nativeCallObservation.js +2 -4
  227. package/dist/domain/native/nativeValueFlow.js +5 -11
  228. package/dist/domain/native/objcSwiftMetadata.js +15 -17
  229. package/dist/domain/process/processCapture.js +11 -10
  230. package/dist/domain/process/processCaptureCoverage.js +8 -5
  231. package/dist/domain/process/processCaptureExample.js +43 -0
  232. package/dist/domain/process/processCaptureValidation.js +4 -3
  233. package/dist/domain/process/processComparison.js +0 -23
  234. package/dist/domain/process/processScenario.js +3 -3
  235. package/dist/domain/process/processTraceEvaluation.js +4 -4
  236. package/dist/domain/process/processTraceSpecification.js +1 -3
  237. package/dist/domain/providerCleanupError.js +6 -2
  238. package/dist/domain/reconstructionCoverage.js +2 -1
  239. package/dist/domain/reconstructionUnknowns.js +4 -3
  240. package/dist/domain/reconstructionVerification.js +3 -2
  241. package/dist/domain/referenceSourceGraph.js +7 -7
  242. package/dist/domain/referenceSourceImportParsing.js +34 -45
  243. package/dist/domain/residualUnknown.js +3 -2
  244. package/dist/domain/staticRuntimeCorrelation.js +2 -1
  245. package/dist/domain/swiftSymbolClassification.js +6 -1
  246. package/dist/domain/symbolAnalysis.js +17 -2
  247. package/dist/domain/unicodeCodePointOrder.js +6 -0
  248. package/dist/domain/webBundleAnalyzerInspection.js +9 -1
  249. package/dist/domain/webCaptureDiff.js +71 -29
  250. package/dist/domain/webCaptureDiffSchemas.js +2 -8
  251. package/dist/domain/webInventory.js +3 -2
  252. package/dist/domain/webMcpDiscovery.js +4 -3
  253. package/dist/domain/webScriptExport.js +1 -1
  254. package/dist/dotnet/ManagedMemberInstructionDecoder.js +1 -2
  255. package/dist/dotnet/ManagedStaticProvider.js +10 -7
  256. package/dist/dotnet/ManagedStaticProviderMetadata.js +1 -4
  257. package/dist/filesystem/RegularFile.js +41 -0
  258. package/dist/generatedPackageMetadata.js +1 -1
  259. package/dist/ghidra/GhidraClient.js +14 -4
  260. package/dist/ghidra/GhidraInstallation.js +111 -10
  261. package/dist/ghidra/GhidraLauncher.js +43 -19
  262. package/dist/hopper/HopperCleanup.js +1 -1
  263. package/dist/ida/IdaOperationRunner.js +2 -0
  264. package/dist/ida/IdaSessionClient.js +4 -2
  265. package/dist/inspector/JavaScriptRuntimeScope.js +9 -5
  266. package/dist/inspector/V8InspectorCaptureProjection.js +46 -13
  267. package/dist/inspector/V8InspectorProvider.js +60 -8
  268. package/dist/main/shutdown.js +76 -32
  269. package/dist/main/transport.js +1 -1
  270. package/dist/native/AppleObjcDispatchFacets.js +3 -3
  271. package/dist/native/AppleObjcProperties.js +17 -7
  272. package/dist/native/LldbCallTracer.js +241 -75
  273. package/dist/native/NativeMacOSProvider.js +10 -5
  274. package/dist/native/NativeMacOSProviderMetadata.js +1 -2
  275. package/dist/process/ProcessOwnershipObservation.js +9 -13
  276. package/dist/process/capture/FilesystemSnapshot.js +88 -18
  277. package/dist/process/capture/ProcessCaptureLifecycle.js +13 -27
  278. package/dist/process/capture/ProcessFilesystemEffects.js +19 -4
  279. package/dist/process/capture/ProcessHarness.js +8 -21
  280. package/dist/server/analysisAdmission.js +8 -0
  281. package/dist/server/createServer.js +22 -23
  282. package/dist/server/registerApplicationTools/compareExportShapes.js +2 -1
  283. package/dist/server/registerApplicationTools/helpers.js +3 -2
  284. package/dist/server/registerArtifactTools.js +2 -2
  285. package/dist/server/registerCloseLifecycleTool.js +6 -4
  286. package/dist/server/registerEnhancedTools.js +78 -73
  287. package/dist/server/registerEvidenceTools.js +54 -46
  288. package/dist/server/registerManagedTools.js +7 -4
  289. package/dist/server/registerOfficialTools.js +31 -25
  290. package/dist/server/registerSessionTools.js +9 -3
  291. package/native/windows/build/manifest.json +1 -1
  292. package/package.json +6 -3
  293. package/skills/reverse-engineer-anything/SKILL.md +5 -5
  294. package/skills/reverse-engineer-anything/references/native-and-artifacts.md +9 -0
  295. package/dist/artifacts/inventory/policy.js +0 -2
  296. package/dist/domain/managed/managedApplicationGraphNodeCoverage.js +0 -6
  297. package/dist/server/registerNativeTools.js +0 -6
@@ -202,19 +202,6 @@ const differingContractFields = (left, right) => [...new Set([...Object.keys(lef
202
202
  !Object.hasOwn(right, field) ||
203
203
  canonicalize(left[field]) !== canonicalize(right[field]))
204
204
  .sort();
205
- const truncatedComparison = () => ({
206
- status: "truncated",
207
- terminal: "truncated",
208
- interaction: "truncated",
209
- exit: "truncated",
210
- filesystem: "truncated",
211
- process: "truncated",
212
- first_divergence: {
213
- status: "unknown",
214
- reason: "At least one capture is truncated.",
215
- },
216
- limitations: ["At least one capture is truncated."],
217
- });
218
205
  const applyTraceVerdict = (dimensions, specification, trace, captures) => {
219
206
  const traceShowsDifference = processTraceOutcomesDiffer(trace);
220
207
  const traceStatus = trace.verdict === "unknown"
@@ -275,16 +262,6 @@ const compareDimensions = (left, right, sameNormalization) => {
275
262
  */
276
263
  export const compareProcessCaptures = (left, right, options = {}) => {
277
264
  assertComparable(left, right, options);
278
- if ((left.truncated && left.truncation_details === undefined) ||
279
- (right.truncated && right.truncation_details === undefined)) {
280
- const truncated = truncatedComparison();
281
- return options.traceSpecification === undefined
282
- ? truncated
283
- : {
284
- ...truncated,
285
- trace: compareProcessTraces(left, right, options.traceSpecification),
286
- };
287
- }
288
265
  const sameNormalization = sameJsonValue(left.normalization, right.normalization);
289
266
  const exactDimensions = compareDimensions(left, right, sameNormalization);
290
267
  const trace = options.traceSpecification === undefined
@@ -4,7 +4,7 @@ import { z } from "zod";
4
4
  const positiveBudget = z.number().int().safe().positive();
5
5
  const timedEventBase = { at_ms: z.number().int().safe().nonnegative() };
6
6
  const reservedRunIdEnvironmentName = "REA_PROCESS_RUN_ID";
7
- const ENVIRONMENT_NAME_CHARACTER = "[^=\\u0000]";
7
+ const ENVIRONMENT_NAME_CHARACTER = "[^=\\x00]";
8
8
  /**
9
9
  * Nonempty environment names other than the reserved run identifier. The
10
10
  * exclusion is spelled as a complement instead of a negative look-ahead,
@@ -18,7 +18,7 @@ const environmentNamePattern = (reserved) => {
18
18
  const character = reserved[index] ?? "";
19
19
  // Diverge here, match the next reserved character, or (after a nonempty
20
20
  // prefix) end the name early.
21
- const choice = `[^=\\u0000${character}]${ENVIRONMENT_NAME_CHARACTER}*|${character}${rest}`;
21
+ const choice = `[^=\\x00${character}]${ENVIRONMENT_NAME_CHARACTER}*|${character}${rest}`;
22
22
  rest = index === 0 ? choice : `(?:${choice})?`;
23
23
  }
24
24
  return new RegExp(`^(?:${rest})$`, "u");
@@ -33,7 +33,7 @@ const environmentName = z
33
33
  });
34
34
  const childProcessString = z
35
35
  .string()
36
- .regex(/^[^\u0000]*$/u, "Values passed to operating-system APIs cannot contain NUL");
36
+ .regex(/^[^\x00]*$/u, "Values passed to operating-system APIs cannot contain NUL");
37
37
  export const normalizationSchema = z.object({
38
38
  paths: z.boolean(),
39
39
  pids: z.boolean(),
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { processSourceTruncated } from "./processCaptureCoverage.js";
3
- import { processObservationLocationSchema, projectProcessObservation, } from "./processObservation.js";
4
- import { canonicalTraceJson, comparableTracePayload, processTraceCardinalityBounds, } from "./processTraceSpecification.js";
3
+ import { comparableProcessObservationPayload, processObservationLocationSchema, projectProcessObservation, } from "./processObservation.js";
4
+ import { canonicalTraceJson, processTraceCardinalityBounds, } from "./processTraceSpecification.js";
5
5
  const identifierSchema = z.string().regex(/^[A-Za-z][A-Za-z0-9._\x2d]{0,63}$/u);
6
6
  const matchedEventSchema = z.strictObject({
7
7
  event_id: identifierSchema,
@@ -121,10 +121,10 @@ const matchRecords = (records, specification) => {
121
121
  for (const event of specification.events) {
122
122
  const ignoredFields = event.ignore_fields ?? [];
123
123
  ignoredFieldsBySource.set(event.source, ignoredFields);
124
- eventsByKey.set(`${event.source}\0${canonicalTraceJson(comparableTracePayload(event.exact, ignoredFields))}`, event);
124
+ eventsByKey.set(`${event.source}\0${canonicalTraceJson(comparableProcessObservationPayload(event.exact, ignoredFields))}`, event);
125
125
  }
126
126
  for (const record of records) {
127
- const match = eventsByKey.get(`${record.source}\0${canonicalTraceJson(comparableTracePayload(record.payload, ignoredFieldsBySource.get(record.source)))}`);
127
+ const match = eventsByKey.get(`${record.source}\0${canonicalTraceJson(comparableProcessObservationPayload(record.payload, ignoredFieldsBySource.get(record.source)))}`);
128
128
  if (match === undefined)
129
129
  return failure({
130
130
  kind: "predicate",
@@ -86,8 +86,6 @@ export const canonicalTraceJson = (value) => {
86
86
  throw new TypeError("Trace specification contains a non-JSON value");
87
87
  return serialized;
88
88
  };
89
- /** Remove only explicitly declared schedule metadata before exact matching. */
90
- export const comparableTracePayload = (value, ignoredFields = []) => comparableProcessObservationPayload(value, ignoredFields);
91
89
  export const processTraceCardinalityBounds = (cardinality) => {
92
90
  switch (cardinality.kind) {
93
91
  case "required":
@@ -352,7 +350,7 @@ export const processTraceSpecificationSchema = specificationShapeSchema.superRef
352
350
  message: "exact payload must omit every ignored schedule field",
353
351
  path: ["events", index, "exact"],
354
352
  });
355
- const predicate = `${event.source}\0${canonicalTraceJson(comparableTracePayload(event.exact, ignoredFields))}`;
353
+ const predicate = `${event.source}\0${canonicalTraceJson(comparableProcessObservationPayload(event.exact, ignoredFields))}`;
356
354
  if (predicates.has(predicate))
357
355
  context.addIssue({
358
356
  code: "custom",
@@ -7,8 +7,12 @@ export class ProviderCleanupError extends ProviderAdapterError {
7
7
  constructor(providerId, resources, diagnostics,
8
8
  /** Identify the operation owning these resources; binary callers retain their default. */
9
9
  options) {
10
- const { operation = "close_binary", ...errorOptions } = options ?? {};
11
- super(providerId, operation, { ...errorOptions, diagnostics });
10
+ const { operation = "close_binary", partialObservation, ...errorOptions } = options ?? {};
11
+ super(providerId, operation, {
12
+ ...errorOptions,
13
+ ...(partialObservation === undefined ? {} : { partialObservation }),
14
+ diagnostics,
15
+ });
12
16
  this.cleanupResources = [...resources];
13
17
  }
14
18
  }
@@ -1,6 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import canonicalize from "canonicalize";
3
3
  import { z } from "zod";
4
+ import { compareUnicodeCodePoints, compositeKey, } from "./unicodeCodePointOrder.js";
4
5
  import { evidenceBundleSchema, parseEvidenceBundle } from "./evidenceBundle.js";
5
6
  import { evaluateReconstructionClaims, evaluateReconstructionPackageProofs, evaluateReconstructionSurfaces, evaluateReconstructionCoverageRisks, recommendedReconstructionProbes, } from "./reconstructionCoverageEvaluation.js";
6
7
  import { digestSchema } from "./../domain/digests.js";
@@ -315,7 +316,7 @@ const closureStatus = (reasons) => {
315
316
  return "unknown";
316
317
  return "partial";
317
318
  };
318
- const reasonOrder = (left, right) => `${left.code}:${left.subject_id}`.localeCompare(`${right.code}:${right.subject_id}`);
319
+ const reasonOrder = (left, right) => compareUnicodeCodePoints(compositeKey([left.code, left.subject_id]), compositeKey([right.code, right.subject_id]));
319
320
  const digest = (value) => {
320
321
  const encoded = canonicalize(value);
321
322
  if (encoded === undefined)
@@ -1,4 +1,5 @@
1
1
  import { uniqueSorted } from "./canonicalOrdering.js";
2
+ import { compareUnicodeCodePoints, compositeKey, } from "./unicodeCodePointOrder.js";
2
3
  /** Select the latest revision of each residual unknown. */
3
4
  export const reconstructionUnknownHeads = (revisions) => {
4
5
  const heads = new Map();
@@ -44,7 +45,7 @@ export const reconstructionClaimUnknowns = (heads, comparisonId, sourceIds) => {
44
45
  const unknown = heads.get(id);
45
46
  return unknown === undefined ? [] : [unknown];
46
47
  })
47
- .sort((left, right) => left.unknown_id.localeCompare(right.unknown_id, "en"));
48
+ .sort((left, right) => compareUnicodeCodePoints(left.unknown_id, right.unknown_id));
48
49
  };
49
50
  /** Aggregate deterministic probes for unresolved claims. */
50
51
  export const reconstructionProbes = (results, heads) => {
@@ -57,7 +58,7 @@ export const reconstructionProbes = (results, heads) => {
57
58
  const probes = unknowns.flatMap(({ recommended_probes: items }) => items);
58
59
  const candidates = probes.length > 0 ? probes : [defaultProbe(result.kind)];
59
60
  for (const probe of candidates) {
60
- const key = `${probe.operation}\0${probe.rationale}`;
61
+ const key = compositeKey([probe.operation, probe.rationale]);
61
62
  const current = output.get(key) ?? {
62
63
  ...probe,
63
64
  claim_ids: [],
@@ -71,7 +72,7 @@ export const reconstructionProbes = (results, heads) => {
71
72
  output.set(key, current);
72
73
  }
73
74
  }
74
- const sorted = [...output.values()].sort((left, right) => `${left.operation}\0${left.rationale}`.localeCompare(`${right.operation}\0${right.rationale}`, "en"));
75
+ const sorted = [...output.values()].sort((left, right) => compareUnicodeCodePoints(compositeKey([left.operation, left.rationale]), compositeKey([right.operation, right.rationale])));
75
76
  return sorted;
76
77
  };
77
78
  const defaultProbe = (kind) => kind === "behavioral"
@@ -4,6 +4,7 @@ import { z } from "zod";
4
4
  import { artifactComparisonResultSchema } from "./artifactComparison.js";
5
5
  import { artifactInventoryResultSchema } from "./artifactGraph.js";
6
6
  import { uniqueSorted } from "./canonicalOrdering.js";
7
+ import { compareUnicodeCodePoints } from "./unicodeCodePointOrder.js";
7
8
  import { comparisonSourceEvidenceSides } from "./comparisonSourceEvidence.js";
8
9
  import { parseEvidence } from "./evidence.js";
9
10
  import { parseEvidenceBundle } from "./evidenceBundle.js";
@@ -42,7 +43,7 @@ export const verifyReconstruction = (specificationInput, bundleInput) => {
42
43
  const heads = reconstructionUnknownHeads(bundle.unknowns);
43
44
  const results = specification.claims
44
45
  .map((claim) => evaluateClaim(claim, records, heads))
45
- .sort((left, right) => left.claim_id.localeCompare(right.claim_id, "en"));
46
+ .sort((left, right) => compareUnicodeCodePoints(left.claim_id, right.claim_id));
46
47
  const failed = count(results, "fail");
47
48
  const unresolved = count(results, "unknown");
48
49
  const probes = reconstructionProbes(results, heads);
@@ -51,7 +52,7 @@ export const verifyReconstruction = (specificationInput, bundleInput) => {
51
52
  status: failed > 0 ? "fail" : unresolved > 0 ? "unknown" : "pass",
52
53
  specification_sha256: digest({
53
54
  ...specification,
54
- claims: [...specification.claims].sort((left, right) => left.claim_id.localeCompare(right.claim_id, "en")),
55
+ claims: [...specification.claims].sort((left, right) => compareUnicodeCodePoints(left.claim_id, right.claim_id)),
55
56
  }),
56
57
  summary: {
57
58
  total: results.length,
@@ -1,6 +1,7 @@
1
1
  import { posix } from "node:path";
2
2
  import { z } from "zod";
3
- import { canonicalDigest, canonicalJson } from "./comparisonSemantics.js";
3
+ import { canonicalJson } from "./comparisonSemantics.js";
4
+ import { digestCanonicalValue } from "./canonicalDigest.js";
4
5
  import { compareUnicodeCodePoints } from "./unicodeCodePointOrder.js";
5
6
  import { digestSchema } from "./../domain/digests.js";
6
7
  import { prefixedDigestSchema } from "./../domain/digests.js";
@@ -109,8 +110,6 @@ const exclusionSchema = z.strictObject({
109
110
  reason: z.enum([
110
111
  "configured-secret",
111
112
  "symlink-escape",
112
- "size-limit",
113
- "inventory-limit",
114
113
  "unreadable",
115
114
  "caller-excluded",
116
115
  ]),
@@ -331,7 +330,7 @@ const rootCommitment = (entries, exclusions) => ({
331
330
  }),
332
331
  exclusions,
333
332
  });
334
- const computeRootSha256 = (entries, exclusions) => canonicalDigest(rootCommitment(entries, exclusions), "Reference source graph");
333
+ const computeRootSha256 = (entries, exclusions) => digestCanonicalValue(rootCommitment(entries, exclusions), "Reference source graph");
335
334
  /** Build and internally commit a normalized historical source graph. */
336
335
  export const createHistoricalSourceGraph = (input) => {
337
336
  const parsed = historicalSourceGraphInputSchema.parse(input);
@@ -343,7 +342,7 @@ export const createHistoricalSourceGraph = (input) => {
343
342
  /** Parse a graph and reject stale or caller-invented root commitments. */
344
343
  export const parseHistoricalSourceGraph = (input) => historicalSourceGraphSchema.parse(input);
345
344
  /** Compute a deterministic graph commitment containing no absolute root path. */
346
- export const computeHistoricalSourceGraphSha256 = (input) => canonicalDigest(parseHistoricalSourceGraph(input), "Reference source graph");
345
+ export const computeHistoricalSourceGraphSha256 = (input) => digestCanonicalValue(parseHistoricalSourceGraph(input), "Reference source graph");
347
346
  /** Build a deterministic, relocation-independent manifest for a source graph. */
348
347
  export const createHistoricalSourceManifest = (input) => {
349
348
  const graph = parseHistoricalSourceGraph(input);
@@ -358,14 +357,15 @@ export const createHistoricalSourceManifest = (input) => {
358
357
  };
359
358
  return historicalSourceManifestBaseSchema.parse({
360
359
  ...semantic,
361
- manifest_id: `hsm_${canonicalDigest(semantic, "Reference source graph")}`,
360
+ manifest_id: `hsm_${digestCanonicalValue(semantic, "Reference source graph")}`,
362
361
  });
363
362
  };
364
363
  /** Parse and verify a historical source manifest's semantic identifier. */
365
364
  export const parseHistoricalSourceManifest = (input) => {
366
365
  const manifest = historicalSourceManifestBaseSchema.parse(input);
367
366
  const { manifest_id: manifestId, ...semantic } = manifest;
368
- if (`hsm_${canonicalDigest(semantic, "Reference source graph")}` !== manifestId)
367
+ if (`hsm_${digestCanonicalValue(semantic, "Reference source graph")}` !==
368
+ manifestId)
369
369
  throw new TypeError("Historical source manifest identifier does not match");
370
370
  return manifest;
371
371
  };
@@ -1,5 +1,7 @@
1
1
  import { parse } from "@babel/parser";
2
- import { isCallExpression, isExportAllDeclaration, isExportNamedDeclaration, isIdentifier, isImport, isImportDeclaration, isImportExpression, isMemberExpression, isNode, isStringLiteral, isTSExternalModuleReference, isTSImportEqualsDeclaration, isTSModuleDeclaration, } from "@babel/types";
2
+ import { traverseJavaScriptAst } from "./javascript/javascriptSemanticTraversal.js";
3
+ import { parserPluginsForPath } from "./javascript/javascriptSourceParser.js";
4
+ import { isCallExpression, isExportAllDeclaration, isExportNamedDeclaration, isIdentifier, isImport, isImportDeclaration, isImportExpression, isMemberExpression, isStringLiteral, isTSExternalModuleReference, isTSImportEqualsDeclaration, isTSModuleDeclaration, } from "@babel/types";
3
5
  const codeSourceLanguages = new Set(["JavaScript", "TypeScript", "JSX", "TSX"]);
4
6
  const safeModuleName = (node) => {
5
7
  if (isStringLiteral(node))
@@ -112,40 +114,18 @@ const isRequireCallee = (callee) => {
112
114
  }
113
115
  return false;
114
116
  };
115
- const isImportCallee = (callee) => isImport(callee);
116
- const collectModuleExpressions = (node, targets) => {
117
- if (node === null || node === undefined)
118
- return;
119
- if (typeof node !== "object")
120
- return;
121
- if (Array.isArray(node)) {
122
- for (const item of node)
123
- collectModuleExpressions(item, targets);
124
- return;
125
- }
126
- if (!isNode(node))
127
- return;
128
- if (isCallExpression(node) || isImportExpression(node)) {
129
- targets.push(node);
130
- }
131
- for (const value of Object.values(node)) {
132
- if (value !== null &&
133
- value !== undefined &&
134
- typeof value === "object" &&
135
- !isSourceLocation(value)) {
136
- collectModuleExpressions(value, targets);
137
- }
138
- }
139
- };
140
- const isSourceLocation = (value) => typeof value === "object" &&
141
- value !== null &&
142
- "start" in value &&
143
- "end" in value &&
144
- !("type" in value);
145
117
  const extractRequireAndDynamicImports = (body, from_path, relationships) => {
118
+ // Single traversal owner: iterative, VISITOR_KEYS-gated, no recursion over
119
+ // loc/comment objects. Survives deeply nested generated member chains that
120
+ // overflowed the previous hand-rolled Object.values walker.
146
121
  const expressions = [];
147
122
  for (const statement of body)
148
- collectModuleExpressions(statement, expressions);
123
+ traverseJavaScriptAst(statement, {
124
+ enter: (node) => {
125
+ if (isCallExpression(node) || isImportExpression(node))
126
+ expressions.push(node);
127
+ },
128
+ });
149
129
  for (const call of expressions) {
150
130
  if (isImportExpression(call)) {
151
131
  const specifier = safeModuleName(call.source);
@@ -171,7 +151,7 @@ const extractRequireAndDynamicImports = (body, from_path, relationships) => {
171
151
  }
172
152
  continue;
173
153
  }
174
- if (isImportCallee(call.callee) && isModuleExpression(first)) {
154
+ if (isImport(call.callee) && isModuleExpression(first)) {
175
155
  const result = moduleSpecifierFromExpression(first);
176
156
  if (result !== undefined) {
177
157
  appendRelationship(relationships, {
@@ -185,17 +165,11 @@ const extractRequireAndDynamicImports = (body, from_path, relationships) => {
185
165
  }
186
166
  };
187
167
  const parseWithBabel = (path, source, language) => {
188
- const plugins = ["jsx"];
189
- if (language === "TypeScript" || language === "TSX") {
190
- plugins.push([
191
- "typescript",
192
- {
193
- dts: path.endsWith(".d.ts") ||
194
- path.endsWith(".d.mts") ||
195
- path.endsWith(".d.cts"),
196
- },
197
- ]);
198
- }
168
+ // Single parser-mode owner: path-driven plugins (dts/JSX/mts) shared with
169
+ // the semantic pipeline. `language` only gates non-JS/TS callers upstream;
170
+ // TypeScript syntax must parse identically here and in semantic analysis.
171
+ void language;
172
+ const plugins = parserPluginsForPath(path);
199
173
  try {
200
174
  const ast = parse(source, {
201
175
  sourceType: "unambiguous",
@@ -218,7 +192,22 @@ const parseWithBabel = (path, source, language) => {
218
192
  export const parseReferenceSourceImports = (path, bytes, language) => {
219
193
  if (language !== null && !codeSourceLanguages.has(language))
220
194
  return { relationships: [], parse_failures: [] };
221
- const source = new TextDecoder("utf-8", { fatal: false }).decode(bytes);
195
+ let source;
196
+ try {
197
+ source = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
198
+ }
199
+ catch {
200
+ return {
201
+ relationships: [],
202
+ parse_failures: [
203
+ {
204
+ path,
205
+ parser: "utf-8",
206
+ reason: "Source bytes are not valid UTF-8; import targets were not parsed.",
207
+ },
208
+ ],
209
+ };
210
+ }
222
211
  const { ast, reasons } = parseWithBabel(path, source, language);
223
212
  const parseFailures = reasons.map((reason) => ({
224
213
  path,
@@ -1,6 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import canonicalize from "canonicalize";
3
3
  import { z } from "zod";
4
+ import { compareUnicodeCodePoints, compositeKey, } from "./unicodeCodePointOrder.js";
4
5
  import { prefixedDigestSchema } from "./../domain/digests.js";
5
6
  const evidenceIdSchema = prefixedDigestSchema("ev");
6
7
  const unknownIdSchema = prefixedDigestSchema("unk");
@@ -232,5 +233,5 @@ const canonicalJson = (value) => {
232
233
  throw new TypeError("Unknown identity failed");
233
234
  return serialized;
234
235
  };
235
- const sortedUnique = (values) => [...new Set(values)].sort((left, right) => left.localeCompare(right));
236
- const sortedRelationships = (values) => [...values].sort((left, right) => `${left.type}:${left.unknown_id}`.localeCompare(`${right.type}:${right.unknown_id}`));
236
+ const sortedUnique = (values) => [...new Set(values)].sort(compareUnicodeCodePoints);
237
+ const sortedRelationships = (values) => [...values].sort((left, right) => compareUnicodeCodePoints(compositeKey([left.type, left.unknown_id]), compositeKey([right.type, right.unknown_id])));
@@ -3,6 +3,7 @@ import canonicalize from "canonicalize";
3
3
  import { z } from "zod";
4
4
  import { artifactComparisonResultSchema } from "./artifactComparison.js";
5
5
  import { uniqueSorted } from "./canonicalOrdering.js";
6
+ import { compareUnicodeCodePoints } from "./unicodeCodePointOrder.js";
6
7
  import { comparisonSourceEvidenceIds } from "./comparisonSourceEvidence.js";
7
8
  import { evidenceSchema, parseEvidence } from "./evidence.js";
8
9
  import { functionComparisonResultSchema } from "./functionComparisonSchemas.js";
@@ -146,7 +147,7 @@ export const correlateStaticAndRuntime = (input) => {
146
147
  const runtimeById = byId(runtimeEvidence);
147
148
  const correlations = parsed.mappings
148
149
  .map((mapping) => correlate(mapping, staticById, runtimeById))
149
- .sort((left, right) => left.correlation_id.localeCompare(right.correlation_id, "en"));
150
+ .sort((left, right) => compareUnicodeCodePoints(left.correlation_id, right.correlation_id));
150
151
  if (new Set(correlations.map(({ correlation_id: id }) => id)).size !==
151
152
  correlations.length)
152
153
  throw new TypeError("Static/runtime correlation rejects duplicate mappings");
@@ -37,7 +37,12 @@ export const classifySwiftSymbol = (name) => {
37
37
  const kind = mangling.charAt(end);
38
38
  const nominal = NOMINAL_CATEGORIES.get(kind);
39
39
  if (nominal === undefined) {
40
- if (kind === "E" && category !== null)
40
+ // Current swiftc emits protocol descriptors as `…<Nominal>Mp` without
41
+ // the nominal `P` marker (e.g. `_$s4main7ScoringMp`). Decode that exact
42
+ // suffix; unknown substitution encodings stay unclassified, never guessed.
43
+ if (mangling.slice(end) === "Mp")
44
+ category = "protocols";
45
+ else if (kind === "E" && category !== null)
41
46
  category = "extensions";
42
47
  break;
43
48
  }
@@ -1,8 +1,20 @@
1
1
  import { classifySwiftSymbol, } from "./swiftSymbolClassification.js";
2
+ /** Objective-C class definition markers emitted by modern Apple clang. */
3
+ const OBJC_CLASS_MARKER = "OBJC_CLASS_$_";
4
+ /** Local class records emitted by Apple's fragile Objective-C ABI. */
5
+ const LEGACY_OBJC_CLASS_PREFIX = "l_OBJC_CLASS_";
6
+ /**
7
+ * Objective-C protocol declaration marker. `PROTOCOL_REFERENCE` slots
8
+ * share the substring but are uses, not definitions.
9
+ */
10
+ const OBJC_PROTOCOL_MARKER = "OBJC_PROTOCOL_$_";
2
11
  /** Select and deduplicate Objective-C class labels. */
3
12
  export const discoverObjcClasses = (names, pattern) => {
4
13
  const classes = uniqueByName(names
5
- .filter(({ name }) => ["OBJC_CLASS", "OBJC_$_CLASS"].some((marker) => name.includes(marker)))
14
+ .filter(({ name }) => name.includes(OBJC_CLASS_MARKER) ||
15
+ (name.startsWith(LEGACY_OBJC_CLASS_PREFIX) &&
16
+ name.length > LEGACY_OBJC_CLASS_PREFIX.length &&
17
+ !/^l_OBJC_CLASS_NAME_(?:\.\d+)?$/u.test(name)))
6
18
  .filter(({ name }) => pattern.length === 0 || name.includes(pattern)));
7
19
  return {
8
20
  count: classes.length,
@@ -11,7 +23,10 @@ export const discoverObjcClasses = (names, pattern) => {
11
23
  };
12
24
  /** Select and deduplicate Objective-C and Swift protocol labels. */
13
25
  export const discoverObjcProtocols = (names) => {
14
- const protocols = uniqueByName(names.filter(({ name }) => name.includes("OBJC_PROTOCOL") || name.includes("_TtP")));
26
+ const protocols = uniqueByName(names.filter(({ name }) => name.includes(OBJC_PROTOCOL_MARKER) ||
27
+ name.includes("_TtP") ||
28
+ (name.endsWith("Mp") &&
29
+ classifySwiftSymbol(name)?.category === "protocols")));
15
30
  return {
16
31
  count: protocols.length,
17
32
  protocols: protocols.map(toJsonEntry),
@@ -15,3 +15,9 @@ export const compareUnicodeCodePoints = (left, right) => {
15
15
  return 0;
16
16
  return leftIndex === left.length ? -1 : 1;
17
17
  };
18
+ /**
19
+ * Collision-free composite key for deduplication/sorting. `\0`-joins
20
+ * collide when any component contains NUL (valid in JS property names);
21
+ * a JSON tuple escapes every component. Single owner for composite keys.
22
+ */
23
+ export const compositeKey = (parts) => JSON.stringify(parts);
@@ -1,6 +1,7 @@
1
1
  import { parse } from "@babel/parser";
2
2
  import * as t from "@babel/types";
3
3
  import { sanitizeEndpointCandidate } from "./browserObservation.js";
4
+ import { compositeKey } from "./unicodeCodePointOrder.js";
4
5
  import { traverseJavaScriptAst } from "./javascript/javascriptSemanticTraversal.js";
5
6
  import { classifyParsedJavaScriptOpenReceivers } from "./javascript/javascriptSemanticAnalysis.js";
6
7
  import { semanticStaticPropertyName } from "./javascript/javascriptAstValues.js";
@@ -169,7 +170,14 @@ const addWebMcpDeclaration = (script, node, accumulator) => {
169
170
  ].filter(Boolean)
170
171
  : [])
171
172
  : [];
172
- const key = `webmcp\0${script.script_key}\0${name ?? ""}\0${schemaPropertyNames.join("\0")}`;
173
+ // Property names are a variable-length source-derived list: NUL-joins
174
+ // would collapse ["a\0b"] with ["a", "b"] and drop a declaration.
175
+ const key = compositeKey([
176
+ "webmcp",
177
+ script.script_key,
178
+ name ?? "",
179
+ schemaPropertyNames,
180
+ ]);
173
181
  addUnique(accumulator, key, () => accumulator.webMcp.push({
174
182
  name: name ?? null,
175
183
  description: description ?? null,