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
@@ -7,7 +7,7 @@ import { STRICT_INTEGRITY_POLICY, } from "./types.js";
7
7
  import { hashReadable } from "../ArtifactHash.js";
8
8
  const UNAVAILABLE_UNPACKED_LIMITATION = "ASAR unpacked companion bytes were unavailable; no content hash or child artifact was produced.";
9
9
  const emptyScan = () => ({ nodes: new Map(), occurrences: [], pendingContradictions: [] });
10
- export const scanReader = async (reader, signal, integrity = STRICT_INTEGRITY_POLICY) => {
10
+ export const scanReader = async (reader, ownedReaders, signal, integrity = STRICT_INTEGRITY_POLICY) => {
11
11
  const { nodes, occurrences, pendingContradictions } = emptyScan();
12
12
  if (reader === undefined)
13
13
  return { nodes, occurrences, pendingContradictions };
@@ -21,6 +21,7 @@ export const scanReader = async (reader, signal, integrity = STRICT_INTEGRITY_PO
21
21
  occurrenceByPath: new Map(),
22
22
  registry: new ArtifactPathRegistry(),
23
23
  expandedContainerIds: new Set(),
24
+ ownedReaders,
24
25
  };
25
26
  await visitArtifactEntries(context, reader, "");
26
27
  // Archive directories may appear after their children. Resolve containment
@@ -36,7 +37,6 @@ const visitArtifactEntries = async (context, currentReader, prefix) => {
36
37
  reader: currentReader,
37
38
  prefix,
38
39
  iterator: currentReader.entries(context.signal)[Symbol.asyncIterator](),
39
- owned: false,
40
40
  },
41
41
  ];
42
42
  try {
@@ -47,8 +47,6 @@ const visitArtifactEntries = async (context, currentReader, prefix) => {
47
47
  const next = await frame.iterator.next();
48
48
  if (next.done) {
49
49
  stack.pop();
50
- if (frame.owned)
51
- await frame.reader.close();
52
50
  continue;
53
51
  }
54
52
  const entry = next.value;
@@ -81,26 +79,24 @@ const visitArtifactEntries = async (context, currentReader, prefix) => {
81
79
  }
82
80
  context.occurrences.push(occurrence);
83
81
  context.occurrenceByPath.set(logicalPath, occurrence);
84
- if (expandableAsar && digested?.mismatched !== true) {
82
+ if (expandableAsar && digested !== undefined && !digested.mismatched) {
85
83
  const nested = new AsarArtifactReader(entry.adapterKey);
84
+ context.ownedReaders.push(nested);
85
+ await nested.prepareContainer(digested.node.sha256, context.signal);
86
86
  // Only traversed containers can own members, not opaque ASAR-named files.
87
87
  context.expandedContainerIds.add(occurrence.occurrence_id);
88
88
  stack.push({
89
89
  reader: nested,
90
90
  prefix: logicalPath,
91
91
  iterator: nested.entries(context.signal)[Symbol.asyncIterator](),
92
- owned: true,
93
92
  });
94
93
  }
95
94
  }
96
95
  }
97
96
  finally {
98
- await Promise.allSettled(stack
99
- .filter(({ owned }) => owned)
100
- .map(async ({ reader, iterator }) => {
97
+ // Readers remain owned by the inventory until its complete observation is built.
98
+ for (const { iterator } of stack)
101
99
  await iterator.return?.();
102
- await reader.close();
103
- }));
104
100
  }
105
101
  };
106
102
  const digestArtifactEntry = async (context, currentReader, entry, logicalPath) => {
@@ -1,6 +1,6 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { isAbsolute } from "node:path";
3
- import { compareCodePoints } from "../../domain/canonicalOrdering.js";
3
+ import { compareUnicodeCodePoints } from "../../domain/unicodeCodePointOrder.js";
4
4
  import { AsarArtifactReader } from "../AsarArtifactReader.js";
5
5
  import { ArtifactPathRegistry, normalizeArtifactPath, } from "../ArtifactPaths.js";
6
6
  import { ArtifactReaderFailure, } from "../ArtifactReader.js";
@@ -12,7 +12,7 @@ export const readJavaScriptArtifactFiles = async (reader, snapshot, signal) => {
12
12
  const root = snapshot.nodes.find(({ artifact_id }) => artifact_id === snapshot.manifest.root_artifact_id);
13
13
  if (root === undefined)
14
14
  throw new ArtifactReaderFailure("integrity", "Root artifact node is missing");
15
- await verifyEntryBytes(reader.openContainer(signal), { path: ".", sha256: root.sha256, bytes: root.size }, signal);
15
+ await verifyEntryBytes(await reader.openContainer(signal), { path: ".", sha256: root.sha256, bytes: root.size }, signal);
16
16
  }
17
17
  const inventory = expectedInventory(snapshot);
18
18
  const expected = inventory.files;
@@ -27,11 +27,11 @@ export const readJavaScriptArtifactFiles = async (reader, snapshot, signal) => {
27
27
  invalidUtf8: 0,
28
28
  };
29
29
  await visitReader(reader, "", snapshot.manifest.root_sha256, context);
30
- const files = context.files.sort((left, right) => compareCodePoints(left.path, right.path));
30
+ const files = context.files.sort((left, right) => compareUnicodeCodePoints(left.path, right.path));
31
31
  assertExpectedFilesWereVisited(expected, files);
32
32
  return {
33
33
  files,
34
- containers: context.containers.sort((left, right) => compareCodePoints(left.path, right.path)),
34
+ containers: context.containers.sort((left, right) => compareUnicodeCodePoints(left.path, right.path)),
35
35
  text_bytes_read: context.textBytes,
36
36
  invalid_utf8_files: context.invalidUtf8,
37
37
  };
@@ -43,9 +43,10 @@ const visitReader = async (reader, prefix, containerSha256, context) => {
43
43
  prefix,
44
44
  containerSha256,
45
45
  iterator: reader.entries(context.signal)[Symbol.asyncIterator](),
46
- owned: false,
47
46
  },
48
47
  ];
48
+ const ownedReaders = [];
49
+ let failure;
49
50
  try {
50
51
  while (stack.length > 0) {
51
52
  const frame = stack.at(-1);
@@ -54,8 +55,6 @@ const visitReader = async (reader, prefix, containerSha256, context) => {
54
55
  const next = await frame.iterator.next();
55
56
  if (next.done) {
56
57
  stack.pop();
57
- if (frame.owned)
58
- await frame.reader.close();
59
58
  continue;
60
59
  }
61
60
  const entry = next.value;
@@ -64,17 +63,32 @@ const visitReader = async (reader, prefix, containerSha256, context) => {
64
63
  const nestedAsar = isFilesystemAsar(entry, path);
65
64
  context.registry.add(path, nestedAsar ? "directory" : entry.kind);
66
65
  if (nestedAsar) {
67
- const inventory = expectedContainer(path, context);
66
+ const container = context.expectedContainers.get(path);
67
+ // Inventory deliberately does not expand unverified or unavailable
68
+ // nested archives. Keep the same boundary here when reconstruction
69
+ // reads the active entries again.
70
+ if (container === undefined)
71
+ throw new ArtifactReaderFailure("integrity", `Nested ASAR was not present in inventory: ${path}`);
72
+ if (container.hash_status === "mismatched")
73
+ continue;
74
+ if (container.hash_status === "unavailable")
75
+ throw new ArtifactReaderFailure("unavailable", `Nested ASAR bytes were unavailable during inventory: ${path}`);
76
+ if (container.hash_status !== "verified")
77
+ throw new ArtifactReaderFailure("integrity", `Nested ASAR was not integrity-verified: ${path}`);
78
+ const inventory = container.inventory;
79
+ if (inventory === null)
80
+ throw new ArtifactReaderFailure("integrity", `Verified nested ASAR has no inventory node: ${path}`);
68
81
  await verifyEntryBytes(await frame.reader.open(entry, context.signal), inventory, context.signal);
69
82
  context.containers.push(inventory);
70
83
  const nested = new AsarArtifactReader(entry.adapterKey);
84
+ ownedReaders.push(nested);
71
85
  stack.push({
72
86
  reader: nested,
73
87
  prefix: path,
74
88
  containerSha256: inventory.sha256,
75
89
  iterator: nested.entries(context.signal)[Symbol.asyncIterator](),
76
- owned: true,
77
90
  });
91
+ await nested.prepareContainer(inventory.sha256, context.signal);
78
92
  continue;
79
93
  }
80
94
  const expected = context.expected.get(path);
@@ -97,20 +111,31 @@ const visitReader = async (reader, prefix, containerSha256, context) => {
97
111
  });
98
112
  }
99
113
  }
114
+ catch (cause) {
115
+ failure = { cause };
116
+ }
100
117
  finally {
101
- await Promise.allSettled(stack
102
- .filter(({ owned }) => owned)
103
- .map(async ({ reader, iterator }) => {
104
- await iterator.return?.();
105
- await reader.close();
106
- }));
118
+ for (const { iterator } of stack) {
119
+ try {
120
+ await iterator.return?.();
121
+ }
122
+ catch (cause) {
123
+ failure ??= { cause };
124
+ }
125
+ }
126
+ for (const owned of ownedReaders.reverse()) {
127
+ try {
128
+ await owned.close();
129
+ }
130
+ catch (cause) {
131
+ failure = {
132
+ cause: ArtifactReaderFailure.withCleanup(failure?.cause ?? cause, ArtifactReaderFailure.cleanupObservation(cause, `nested ASAR reader for ${prefix}`)),
133
+ };
134
+ }
135
+ }
107
136
  }
108
- };
109
- const expectedContainer = (path, context) => {
110
- const container = context.expectedContainers.get(path);
111
- if (container === undefined)
112
- throw new ArtifactReaderFailure("integrity", `Nested ASAR disappeared from inventory: ${path}`);
113
- return container;
137
+ if (failure !== undefined)
138
+ throw failure.cause;
114
139
  };
115
140
  const readText = async (context, input) => {
116
141
  if (input.expected.kind === "native-addon") {
@@ -155,8 +180,18 @@ const expectedInventory = (snapshot) => {
155
180
  const files = new Map();
156
181
  const containers = new Map();
157
182
  for (const occurrence of snapshot.occurrences) {
158
- if (occurrence.artifact_id === null || occurrence.logical_path === ".")
183
+ if (occurrence.logical_path === ".")
159
184
  continue;
185
+ const isNestedAsar = occurrence.entry_kind === "file" &&
186
+ occurrence.logical_path.toLowerCase().endsWith(".asar");
187
+ if (occurrence.artifact_id === null) {
188
+ if (isNestedAsar)
189
+ containers.set(occurrence.logical_path, {
190
+ hash_status: occurrence.hash_status,
191
+ inventory: null,
192
+ });
193
+ continue;
194
+ }
160
195
  const node = nodes.get(occurrence.artifact_id);
161
196
  if (node === undefined)
162
197
  throw new ArtifactReaderFailure("integrity", `Artifact inventory node is missing: ${occurrence.logical_path}`);
@@ -165,12 +200,15 @@ const expectedInventory = (snapshot) => {
165
200
  // node_modules/@zip.js remains a graph node and must never be opened.
166
201
  if (occurrence.entry_kind !== "file")
167
202
  continue;
168
- if (occurrence.logical_path.toLowerCase().endsWith(".asar"))
203
+ if (isNestedAsar)
169
204
  containers.set(occurrence.logical_path, {
170
- path: occurrence.logical_path,
171
- sha256: node.sha256,
172
- bytes: node.size,
173
- inventory_artifact_id: node.artifact_id,
205
+ hash_status: occurrence.hash_status,
206
+ inventory: {
207
+ path: occurrence.logical_path,
208
+ sha256: node.sha256,
209
+ bytes: node.size,
210
+ inventory_artifact_id: node.artifact_id,
211
+ },
174
212
  });
175
213
  const kind = relevantKind(occurrence.logical_path);
176
214
  if (kind === undefined)
@@ -21,12 +21,11 @@ import { discoverWebMcp } from "./CdpWebMcpDiscovery.js";
21
21
  import { captureCdpScreenshot } from "./CdpScreenshot.js";
22
22
  import { comparePngScreenshots } from "./PngVisualDiff.js";
23
23
  import { CDP_BROWSER_PROVIDER_IDENTITY } from "./providerIdentities.js";
24
- const IDENTITY = CDP_BROWSER_PROVIDER_IDENTITY;
25
24
  const CLEANUP_DOMAINS = ["Network", "Debugger", "Runtime", "Page"];
26
25
  /** Passive browser observation through a selected user-owned CDP endpoint. */
27
26
  export class CdpBrowserProvider {
28
27
  identity() {
29
- return IDENTITY;
28
+ return CDP_BROWSER_PROVIDER_IDENTITY;
30
29
  }
31
30
  async listTargets(input, options = {}) {
32
31
  try {
@@ -262,4 +261,6 @@ const providerError = (cause, operation) => cause instanceof BrowserObservationE
262
261
  ? new BrowserObservationError(operation, cause.reason, { cause })
263
262
  : cause instanceof AnalysisError
264
263
  ? cause
265
- : new ProviderAdapterError(IDENTITY.id, operation, { cause });
264
+ : new ProviderAdapterError(CDP_BROWSER_PROVIDER_IDENTITY.id, operation, {
265
+ cause,
266
+ });
@@ -1,6 +1,6 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import canonicalize from "canonicalize";
3
- import { compareCodePoints } from "../domain/canonicalOrdering.js";
3
+ import { compareUnicodeCodePoints } from "../domain/unicodeCodePointOrder.js";
4
4
  import { CdpConnection } from "./CdpConnection.js";
5
5
  import { optionalCdpCommand } from "./CdpOptionalCommand.js";
6
6
  import { recordValue, recordsValue, cdpStringValue, } from "./CdpCaptureValues.js";
@@ -16,7 +16,7 @@ export const captureStorageFingerprints = async ({ context, origin, cookieUrl, l
16
16
  await addCookies(run, cookieUrl);
17
17
  await addIndexedDb(run, origin, indexedDbNames);
18
18
  await addCaches(run, caches);
19
- state.items.sort((left, right) => compareCodePoints(`${left.scope}:${left.identity_sha256}`, `${right.scope}:${right.identity_sha256}`));
19
+ state.items.sort((left, right) => compareUnicodeCodePoints(`${left.scope}:${left.identity_sha256}`, `${right.scope}:${right.identity_sha256}`));
20
20
  const complete = state.complete && state.items.every(({ complete }) => complete);
21
21
  return { items: state.items, complete };
22
22
  };
@@ -282,7 +282,7 @@ const stableValue = (value) => {
282
282
  return String(value);
283
283
  return Object.fromEntries(Object.entries(record)
284
284
  .filter(([key]) => key !== "objectId" && key !== "customPreview")
285
- .sort(([left], [right]) => compareCodePoints(left, right))
285
+ .sort(([left], [right]) => compareUnicodeCodePoints(left, right))
286
286
  .map(([key, item]) => [key, stableValue(item)]));
287
287
  };
288
288
  const stableValueComplete = (value) => {
@@ -1,4 +1,4 @@
1
- import { canonicalDigest } from "../domain/comparisonSemantics.js";
1
+ import { digestCanonicalValue } from "../domain/canonicalDigest.js";
2
2
  import { BrowserObservationError } from "../domain/browserObservationError.js";
3
3
  import { CdpCaptureCompleteness } from "./CdpCaptureCompleteness.js";
4
4
  import { delayWithCancellation, numberValue, recordValue, recordsValue, requiredRecord, cdpStringValue, } from "./CdpCaptureValues.js";
@@ -176,7 +176,7 @@ const captureResources = async (context, completeness) => {
176
176
  ? null
177
177
  : Math.max(0, numberValue(resource.contentSize) ?? 0),
178
178
  };
179
- const resourceKey = `electron_resource_${canonicalDigest(item, "CDP capture")}`;
179
+ const resourceKey = `electron_resource_${digestCanonicalValue(item, "CDP capture")}`;
180
180
  if (seen.has(resourceKey))
181
181
  continue;
182
182
  seen.add(resourceKey);
@@ -9,11 +9,10 @@ import { closeCdpTargetSession, openCdpTargetSession, } from "./CdpTargetSession
9
9
  import { inspectCdpElectronPage } from "./CdpElectronInspection.js";
10
10
  import { authorizedElectronFile } from "./ElectronFileScope.js";
11
11
  import { CDP_ELECTRON_PROVIDER_IDENTITY } from "./providerIdentities.js";
12
- const IDENTITY = CDP_ELECTRON_PROVIDER_IDENTITY;
13
12
  /** Passive Electron provider for local file pages exposed by loopback CDP. */
14
13
  export class CdpElectronProvider {
15
14
  identity() {
16
- return IDENTITY;
15
+ return CDP_ELECTRON_PROVIDER_IDENTITY;
17
16
  }
18
17
  async listTargets(input, options = {}) {
19
18
  try {
@@ -106,4 +105,6 @@ const providerError = (cause, operation) => cause instanceof BrowserObservationE
106
105
  ? new BrowserObservationError(operation, cause.reason, { cause })
107
106
  : cause instanceof AnalysisError
108
107
  ? cause
109
- : new ProviderAdapterError(IDENTITY.id, operation, { cause });
108
+ : new ProviderAdapterError(CDP_ELECTRON_PROVIDER_IDENTITY.id, operation, {
109
+ cause,
110
+ });
@@ -1,4 +1,4 @@
1
- import { canonicalDigest } from "../domain/comparisonSemantics.js";
1
+ import { digestCanonicalValue } from "../domain/canonicalDigest.js";
2
2
  import { createWebTextArtifact } from "../domain/webContentArtifact.js";
3
3
  import { CdpCaptureCompleteness } from "./CdpCaptureCompleteness.js";
4
4
  import { requiredScriptSource } from "./CdpCaptureValues.js";
@@ -27,7 +27,7 @@ export const captureElectronScripts = async (input) => {
27
27
  is_module: script.isModule,
28
28
  language: script.language,
29
29
  };
30
- const scriptKey = `electron_script_${canonicalDigest(identity, "CDP capture")}`;
30
+ const scriptKey = `electron_script_${digestCanonicalValue(identity, "CDP capture")}`;
31
31
  if (seen.has(scriptKey))
32
32
  continue;
33
33
  seen.add(scriptKey);
@@ -1,5 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
- import { inferJsonShape } from "../domain/jsonShape.js";
2
+ import { jsonValueSchema } from "../domain/jsonValue.js";
3
+ import { digestCanonicalValue } from "../domain/canonicalDigest.js";
4
+ import { compositeKey } from "../domain/unicodeCodePointOrder.js";
3
5
  import { CdpCaptureCompleteness } from "./CdpCaptureCompleteness.js";
4
6
  import { BrowserObservationError } from "../domain/browserObservationError.js";
5
7
  import { allowedSanitizedUrl, delayWithCancellation, numberValue, recordValue, recordsValue, cdpStringValue, } from "./CdpCaptureValues.js";
@@ -265,6 +267,10 @@ const normalizeTool = (value, input, frames, completeness) => {
265
267
  }
266
268
  const description = cdpStringValue(value.description) ?? "";
267
269
  const annotations = recordValue(value.annotations);
270
+ const declaration = jsonValueSchema.safeParse(value.inputSchema);
271
+ if (!declaration.success)
272
+ completeness.exclude("webmcp_tools", "invalid_protocol_value");
273
+ const schema = declaration.success ? declaration.data : null;
268
274
  return {
269
275
  tool_key: toolKey(frame.url, frameId, name),
270
276
  name,
@@ -275,7 +281,10 @@ const normalizeTool = (value, input, frames, completeness) => {
275
281
  declaration_kind: numberValue(value.backendNodeId) === undefined
276
282
  ? "imperative"
277
283
  : "declarative",
278
- input_schema_shape: schemaShape(value.inputSchema),
284
+ input_schema: schema,
285
+ input_schema_sha256: declaration.success
286
+ ? digestCanonicalValue(schema)
287
+ : null,
279
288
  annotations: {
280
289
  read_only: booleanOrNull(annotations?.readOnly),
281
290
  untrusted_content: booleanOrNull(annotations?.untrustedContent),
@@ -285,15 +294,6 @@ const normalizeTool = (value, input, frames, completeness) => {
285
294
  trust: "page-declared-untrusted",
286
295
  };
287
296
  };
288
- const schemaShape = (value) => {
289
- if (recordValue(value) === undefined)
290
- return null;
291
- const encoded = JSON.stringify(value);
292
- const shape = inferJsonShape(encoded);
293
- if (shape === null)
294
- throw new BrowserObservationError("inspect_web_page", "protocol_error");
295
- return shape;
296
- };
297
297
  const registrationSource = (stack, allowedOrigins) => {
298
298
  const frame = recordsValue(stack?.callFrames)[0];
299
299
  const url = allowedSanitizedUrl(frame?.url, allowedOrigins);
@@ -327,8 +327,11 @@ const buildWebMcpResult = (options) => {
327
327
  };
328
328
  const toolKey = (frameUrl, frameId, name) =>
329
329
  // Registrations without a known admitted frame are excluded above, so the
330
- // frame ID here always distinguishes owners and keys cannot collapse.
331
- `webmcp_${createHash("sha256").update(`${frameUrl}\0${frameId}\0${name}`).digest("hex")}`;
330
+ // frame ID here always distinguishes owners. Composite tuple keeps a NUL
331
+ // inside one field from collapsing two registrations before hashing.
332
+ `webmcp_${createHash("sha256")
333
+ .update(compositeKey([frameUrl, frameId, name]))
334
+ .digest("hex")}`;
332
335
  const booleanOrNull = (value) => typeof value === "boolean" ? value : null;
333
336
  const integerOrNull = (value) => {
334
337
  const number = numberValue(value);
@@ -135,11 +135,11 @@ const globalCompleteness = (scenario, session, steps) => {
135
135
  missing.push("events");
136
136
  return classifyBrowserScenarioCompleteness(missing, truncated);
137
137
  };
138
- const runScenario = async (factory, scenario, options) => {
138
+ const runScenario = async (openSession, scenario, options) => {
139
139
  if (options.signal?.aborted === true)
140
140
  throw new BrowserObservationError(OPERATION, "cancelled");
141
141
  const startedAt = Date.now();
142
- const session = await factory.open(scenario, options.signal === undefined ? {} : { signal: options.signal });
142
+ const session = await openSession(scenario, options.signal === undefined ? {} : { signal: options.signal });
143
143
  const steps = [];
144
144
  let operationOutcome = { ok: true };
145
145
  try {
@@ -225,16 +225,16 @@ const runScenario = async (factory, scenario, options) => {
225
225
  };
226
226
  /** Controlled Playwright/CDP scenario driver with exact process ownership. */
227
227
  export class PlaywrightBrowserScenarioProvider {
228
- factory;
229
- constructor(factory) {
230
- this.factory = factory;
228
+ openSession;
229
+ constructor(openSession) {
230
+ this.openSession = openSession;
231
231
  }
232
232
  identity() {
233
233
  return PLAYWRIGHT_BROWSER_SCENARIO_PROVIDER_IDENTITY;
234
234
  }
235
235
  async captureScenario(scenario, options = {}) {
236
236
  try {
237
- return ok(await runScenario(this.factory, scenario, options));
237
+ return ok(await runScenario(this.openSession, scenario, options));
238
238
  }
239
239
  catch (cause) {
240
240
  if (cause instanceof AnalysisError)