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
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  [![npm version](https://img.shields.io/npm/v/rea-agents?style=flat-square&color=cb3837)](https://www.npmjs.com/package/rea-agents)
12
12
  [![CI](https://img.shields.io/github/actions/workflow/status/morluto/rea/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/morluto/rea/actions/workflows/ci.yml)
13
13
  [![MCP tool catalog](https://img.shields.io/badge/MCP-tool_catalog-5c4ee5?style=flat-square)](docs/mcp-contracts.md#generated-catalog)
14
- [![Node.js 22+](https://img.shields.io/badge/Node.js-22.19%2B-339933?style=flat-square&logo=nodedotjs&logoColor=white)](https://nodejs.org/)
14
+ [![Node.js requirements](https://img.shields.io/badge/Node.js-requirements-339933?style=flat-square&logo=nodedotjs&logoColor=white)](#what-you-can-analyze)
15
15
  [![skills.sh](https://skills.sh/b/morluto/rea?style=flat-square)](https://skills.sh/morluto/rea/reverse-engineer-anything)
16
16
  [![MIT license](https://img.shields.io/badge/license-MIT-f4c430?style=flat-square)](LICENSE)
17
17
  [![Discord](https://img.shields.io/discord/1556595354999332884?logo=discord&logoColor=white&label=Discord&color=5865F2)](https://discord.gg/GkcryMnJDM)
@@ -28,7 +28,7 @@
28
28
 
29
29
  <img src="docs/assets/rea-hopper-analysis.png" alt="REA launching its analysis bridge inside Hopper while inspecting a native binary" width="1200" />
30
30
 
31
- <br />
31
+ <br /><br />
32
32
 
33
33
  <table aria-label="REA community">
34
34
  <tr>
@@ -52,7 +52,7 @@ See a feature in an app that you want in your own product? Ask your agent to inv
52
52
 
53
53
  REA connects your agent to tools for inspecting native binaries, JavaScript and Electron apps, .NET assemblies, and websites. You can also use the same tools from your terminal. Analysis runs locally, and results include the evidence and limitations behind each conclusion.
54
54
 
55
- Setup registers REA with your agent and installs matching workflow instructions. Native analysis can use an existing Hopper or Ghidra installation; setup can optionally install Hopper with approval. Static JavaScript analysis needs neither engine.
55
+ Setup registers REA with your agent and installs matching workflow instructions. Native analysis can use an existing Hopper, Ghidra, or IDA installation; setup can optionally install Hopper with approval. Static JavaScript analysis needs no native analysis engine.
56
56
 
57
57
  > **[Visit the REA website](https://rea.tools/)** for setup instructions, illustrated guides, and real case studies.
58
58
 
@@ -156,7 +156,7 @@ Additional tools and host support depend on the target:
156
156
  | JavaScript / Electron | Modules, imports, source maps, routes, IPC and native add-on relationships | Node.js and npm; [application analysis](https://rea.tools/guides/javascript/) |
157
157
  | Websites | Page structure, scripts, network observations and requested screenshots | A Chrome-family browser; [browser analysis](https://rea.tools/guides/browser/) |
158
158
  | Saved network captures | Requests, responses, exposed payloads and source locations | HAR; mitmdump on Linux for native mitmproxy captures; [capture guide](docs/web-network-captures.md) |
159
- | .NET assemblies | Metadata, CIL instructions, declared native dependencies and build comparisons | Static inspection; [managed-code guide](docs/managed-code-analysis.md) |
159
+ | .NET assemblies | Metadata, CIL instructions, declared native dependencies and build comparisons | None (static only); [managed-code guide](docs/managed-code-analysis.md) |
160
160
  | Android APKs | Manifest declarations, classes, decompiled methods and references | Headless JADX and a full JDK on Linux/macOS/Windows x64; [Android guide](docs/android-analysis.md) |
161
161
  | Firmware | Regions, extraction results and native-analysis handoffs | Binwalk / Unblob on Linux; [firmware guide](docs/firmware-analysis.md) |
162
162
  | Packages and resources | File inventories, digests, plists, Apple bundle anatomy and extracted resources | [Artifact and JavaScript guide](docs/javascript-artifact-reconstruction.md), [Apple applications](docs/apple-application-analysis.md) |
@@ -181,6 +181,8 @@ for features added since the latest npm release.
181
181
 
182
182
  ## Showcases
183
183
 
184
+ [![Illustrations of the DX-Ball sound-pan, Notion clipboard-bridge, and TH04 bullet-ring showcases](docs/assets/rea-showcases.png)](https://rea.tools/showcase/)
185
+
184
186
  ### DX-Ball: reconstruct a sound-pan calculation
185
187
 
186
188
  Follow a sound call into its position-to-pan helper, inspect the instructions,
@@ -243,7 +245,7 @@ ask you to choose demo mode or activate your license. See
243
245
  <details>
244
246
  <summary><strong>What does installing the skill from skills.sh do?</strong></summary>
245
247
 
246
- The skill supplies investigation instructions for your agent. Use `rea setup`
248
+ The skill supplies investigation instructions for your agent. Use `npx rea-agents setup`
247
249
  to register REA's MCP server and install the matching instructions, then restart
248
250
  your agent. See [skill-only installation](docs/installation.md#skill-only-installation).
249
251
 
@@ -303,23 +305,9 @@ For exact options, prerequisites and result contracts:
303
305
 
304
306
  Report vulnerabilities through [SECURITY.md](SECURITY.md).
305
307
 
306
- ## Contributing
307
-
308
- We'd love your help with REA! [Open an issue](https://github.com/morluto/rea/issues) to
309
- report a bug or suggest a feature, or [send a pull request](https://github.com/morluto/rea/pulls)
310
- to improve the code or docs.
311
-
312
- See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and checks,
313
- [testing](docs/testing.md) for verification lanes, and the
314
- [architecture map](docs/architecture.mermaid) for the project structure.
315
-
316
- ## Project links
317
-
318
- [Website](https://rea.tools/) · [npm](https://www.npmjs.com/package/rea-agents) · [skills.sh](https://skills.sh/morluto/rea/reverse-engineer-anything) · [Issues](https://github.com/morluto/rea/issues) · [Security](SECURITY.md)
319
-
320
308
  ## Star history
321
309
 
322
- 🎉 **30,000 GitHub stars — thank you!**
310
+ 🎉 **40,000 GitHub stars — thank you!**
323
311
 
324
312
  Thanks to everyone using REA, reporting bugs, requesting features, testing builds, and contributing fixes.
325
313
 
@@ -337,6 +325,16 @@ REA provides tools for lawful reverse-engineering research, analysis, and recons
337
325
 
338
326
  REA is an open-source software project. We have not issued or endorsed any cryptocurrency or token. Tokens using the REA name are not affiliated with the project.
339
327
 
328
+ ## Contributing
329
+
330
+ We'd love your help with REA! [Open an issue](https://github.com/morluto/rea/issues) to
331
+ report a bug or suggest a feature, or [send a pull request](https://github.com/morluto/rea/pulls)
332
+ to improve the code or docs.
333
+
334
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and checks,
335
+ [testing](docs/testing.md) for verification lanes, and the
336
+ [architecture map](docs/architecture.mermaid) for the project structure.
337
+
340
338
  ## License
341
339
 
342
340
  [MIT](LICENSE)
@@ -716,6 +716,8 @@ def _analyze_function(document, params):
716
716
  "referenced_strings": referenced_strings,
717
717
  "referenced_names": referenced_names,
718
718
  "basic_blocks": blocks,
719
+ "native_api": None,
720
+ "native_value_flow": None,
719
721
  "limitations": [
720
722
  "Native CallReference classifications are observed where available; detailed reference flags remain unknown.",
721
723
  "Hopper's public Python API does not expose equivalent external or thunk classification in this dossier.",
@@ -71,7 +71,7 @@ const cleanup = async (resources) => {
71
71
  }
72
72
  catch (cause) {
73
73
  // Retain an uncertain workspace until the caller can resolve process ownership.
74
- return err(new ProviderCleanupError("jadx", [
74
+ const error = new ProviderCleanupError("jadx", [
75
75
  session?.transport.runId ?? "unknown",
76
76
  ...(root === undefined ? [] : [root.path]),
77
77
  ], {
@@ -80,7 +80,10 @@ const cleanup = async (resources) => {
80
80
  provider_cleanup: cause instanceof ProviderCleanupError
81
81
  ? (cause.diagnostics ?? null)
82
82
  : null,
83
- }, { cause: previousError ?? cause }));
83
+ }, { cause: previousError ?? cause });
84
+ if (previousError?.partialObservation !== undefined)
85
+ error.retainPartialObservation(previousError.partialObservation);
86
+ return err(error);
84
87
  }
85
88
  try {
86
89
  await root?.close();
@@ -287,6 +290,9 @@ export class JadxProvider {
287
290
  signal: options?.signal,
288
291
  session,
289
292
  });
293
+ const partialObservation = session?.partialObservation();
294
+ if (partialObservation !== undefined)
295
+ previousError.retainPartialObservation(partialObservation);
290
296
  // Admission can fail before selecting an existing session for execution.
291
297
  root ??= this.#retained?.root;
292
298
  session ??= this.#retained?.session;
@@ -13,12 +13,28 @@ export class JadxSession {
13
13
  #client = new Client({ name: "rea-android-adapter", version: "1" });
14
14
  #loaded;
15
15
  #connected = false;
16
+ #partialContext;
17
+ #observedCalls = [];
18
+ #serverName = null;
19
+ #serverVersion = null;
20
+ #engineVersion = null;
16
21
  constructor(options, launcher) {
17
22
  this.transport = new JadxMcpTransport(options, launcher);
18
23
  }
19
24
  /** Analyze one admitted immutable APK, checking producer identity and selectors. */
20
25
  async execute(context) {
21
26
  const { request, target, snapshot, jarHash, signal } = context;
27
+ this.#partialContext = {
28
+ operation: request.operation,
29
+ selectedPath: request.input.path,
30
+ target,
31
+ jarHash,
32
+ bridgeHash: context.bridgeHash,
33
+ };
34
+ this.#observedCalls = [];
35
+ this.#serverName = null;
36
+ this.#serverVersion = null;
37
+ this.#engineVersion = null;
22
38
  const abort = () => {
23
39
  void this.transport.close().catch(() => undefined);
24
40
  };
@@ -26,17 +42,19 @@ export class JadxSession {
26
42
  try {
27
43
  signal.throwIfAborted();
28
44
  this.transport.beginOperation();
29
- const raw = [];
30
45
  if (!this.#connected) {
31
46
  await this.#client.connect(this.transport, { timeout: 30_000 });
32
47
  this.#connected = true;
33
48
  }
34
49
  const server = this.#client.getServerVersion();
50
+ this.#serverName = server?.name ?? null;
51
+ this.#serverVersion = server?.version ?? null;
35
52
  if (server?.name !== JADX_BRIDGE_IDENTITY.name ||
36
53
  server.version !== JADX_BRIDGE_IDENTITY.version)
37
54
  throw new AnalysisCapabilityUnavailableError("jadx", request.operation, `Expected ${JADX_BRIDGE_IDENTITY.name} ${JADX_BRIDGE_IDENTITY.version}; server reported ${server?.name ?? "unknown"} ${server?.version ?? "unknown"}.`);
38
- const tools = this.#tools(request, target, signal, raw);
55
+ const tools = this.#tools(request, target, signal);
39
56
  const runtime = jadxRuntimeSchema.parse(await tools.json("rea_jvm_status", {}));
57
+ this.#engineVersion = runtime.engine_reported_version;
40
58
  if (runtime.engine_reported_version !== JADX_RELEASE.version)
41
59
  throw new AnalysisCapabilityUnavailableError("jadx", request.operation, `Expected engine ${JADX_RELEASE.version}; JAR reported ${runtime.engine_reported_version}.`);
42
60
  const loaded = this.#loaded ??
@@ -63,7 +81,7 @@ export class JadxSession {
63
81
  bridge_sha256: context.bridgeHash,
64
82
  jar_sha256: jarHash,
65
83
  loaded,
66
- calls: raw,
84
+ calls: this.#observedCalls,
67
85
  },
68
86
  subject: target,
69
87
  limitations: JADX_LIMITATIONS,
@@ -76,6 +94,32 @@ export class JadxSession {
76
94
  signal.removeEventListener("abort", abort);
77
95
  }
78
96
  }
97
+ /** Facts and upstream replies retained if a later request step fails. */
98
+ partialObservation() {
99
+ const context = this.#partialContext;
100
+ if (context === undefined)
101
+ return undefined;
102
+ return {
103
+ provider_id: "jadx",
104
+ operation: context.operation,
105
+ target: {
106
+ selected_path: context.selectedPath,
107
+ path: context.target.path,
108
+ sha256: context.target.sha256,
109
+ format: "apk",
110
+ },
111
+ provider_facts: {
112
+ jar_sha256: context.jarHash,
113
+ bridge_sha256: context.bridgeHash,
114
+ bridge_name: JADX_BRIDGE_IDENTITY.name,
115
+ bridge_version: JADX_BRIDGE_IDENTITY.version,
116
+ server_name: this.#serverName,
117
+ server_version: this.#serverVersion,
118
+ engine_version: this.#engineVersion,
119
+ },
120
+ calls: this.#observedCalls,
121
+ };
122
+ }
79
123
  /** Whether the selected Java runtime established the REA bridge protocol. */
80
124
  initialized() {
81
125
  return this.#connected;
@@ -89,16 +133,14 @@ export class JadxSession {
89
133
  await this.transport.close();
90
134
  }
91
135
  }
92
- #tools(request, target, signal, raw) {
136
+ #tools(request, target, signal) {
93
137
  const call = async (name, input) => {
94
138
  signal.throwIfAborted();
95
139
  const response = await this.#client.callTool({ name, arguments: input }, { timeout: 120_000, signal });
140
+ const observedResponse = jsonValueSchema.parse(response);
141
+ const call = { operation: name, input, response: observedResponse };
142
+ this.#observedCalls.push(call);
96
143
  const envelope = parseJadxEnvelope(response, request.operation);
97
- raw.push({
98
- operation: name,
99
- input,
100
- response: jsonValueSchema.parse(response),
101
- });
102
144
  if (envelope.failed) {
103
145
  if (envelope.text.startsWith("{")) {
104
146
  const failure = jadxInputFailureSchema.safeParse(parseJadxJson(envelope.text, request.operation));
@@ -1,8 +1,10 @@
1
1
  import { constants } from "node:fs";
2
2
  import { createHash } from "node:crypto";
3
- import { access, open, realpath, stat, } from "node:fs/promises";
3
+ import { access, lstat, realpath, stat, } from "node:fs/promises";
4
4
  import { extname, isAbsolute, resolve } from "node:path";
5
5
  import { BinaryTargetError } from "../domain/configurationErrors.js";
6
+ import { openRegularFile, sameRegularFileState, } from "../filesystem/RegularFile.js";
7
+ import { AnalysisCancelledError } from "../domain/analysisErrorCore.js";
6
8
  import { err, ok } from "../domain/result.js";
7
9
  import { resolveAppBundleExecutable, } from "./AppBundleExecutable.js";
8
10
  import { validateDosComLength, } from "../domain/dosCom.js";
@@ -14,30 +16,41 @@ import { parseExecutableHeader, parsePeRecord, } from "../domain/binaryTarget.js
14
16
  * FAT Mach-O inputs select only a host-compatible architecture so setup remains
15
17
  * non-interactive; unsupported or ambiguous inputs are returned as typed errors.
16
18
  */
17
- export const parseBinaryTarget = async (input, cwd = process.cwd(), hostArchitecture = process.arch, targetKind, formatHint) => {
19
+ export const parseBinaryTarget = async (input, options = {}) => {
20
+ const cwd = options.cwd ?? process.cwd();
21
+ const hostArchitecture = options.hostArchitecture ?? process.arch;
22
+ const { targetKind, formatHint, signal } = options;
18
23
  const candidate = isAbsolute(input) ? input : resolve(cwd, input);
19
24
  try {
25
+ throwIfTargetResolutionCancelled(signal);
20
26
  await access(candidate, constants.R_OK);
27
+ throwIfTargetResolutionCancelled(signal);
21
28
  const canonical = await realpath(candidate);
29
+ throwIfTargetResolutionCancelled(signal);
22
30
  const resolved = await resolveAppBundle(canonical);
31
+ throwIfTargetResolutionCancelled(signal);
23
32
  if (!resolved.ok)
24
33
  return err(resolved.error);
25
34
  const { executable: path, infoPlist } = resolved.value;
26
35
  const bundle = infoPlist === undefined ? {} : { bundleInfoPlist: infoPlist };
27
- const handle = await open(path, "r");
36
+ const handle = await openRegularFile(path, {
37
+ symlinks: "reject",
38
+ signal,
39
+ });
28
40
  try {
29
- if (!(await handle.stat()).isFile())
30
- return err(new BinaryTargetError(path, "target is not a regular file"));
41
+ throwIfTargetResolutionCancelled(signal);
42
+ const metadata = await handle.stat();
43
+ throwIfTargetResolutionCancelled(signal);
31
44
  if (formatHint === "dos-com") {
32
45
  if (targetKind !== undefined && targetKind !== "executable")
33
46
  return err(new BinaryTargetError(path, "DOS COM format requires an executable target kind"));
34
- const length = validateDosComLength((await handle.stat()).size);
47
+ const length = validateDosComLength(metadata.size);
35
48
  if (!length.ok)
36
49
  return err(new BinaryTargetError(path, length.error));
37
50
  return ok({
38
51
  path,
39
52
  sourcePath: canonical,
40
- sha256: await sha256Handle(handle),
53
+ sha256: await sha256Handle(handle, path, metadata, signal),
41
54
  kind: "executable",
42
55
  format: "dos-com",
43
56
  architecture: "x86",
@@ -49,29 +62,29 @@ export const parseBinaryTarget = async (input, cwd = process.cwd(), hostArchitec
49
62
  return ok({
50
63
  path,
51
64
  sourcePath: process.platform === "win32" ? candidate : canonical,
52
- sha256: await sha256Handle(handle),
65
+ sha256: await sha256Handle(handle, path, metadata, signal),
53
66
  kind: "database",
54
67
  format: "analysis-database",
55
68
  });
56
- const artifactFormat = await detectArtifactFormat(path, handle);
69
+ const artifactFormat = await detectArtifactFormat(path, handle, signal);
57
70
  if (artifactFormat !== undefined) {
58
71
  const identity = {
59
72
  path,
60
73
  sourcePath: process.platform === "win32" ? candidate : canonical,
61
- sha256: await sha256Handle(handle),
74
+ sha256: await sha256Handle(handle, path, metadata, signal),
62
75
  };
63
76
  return isArchiveFormat(artifactFormat)
64
77
  ? ok({ ...identity, kind: "archive", format: artifactFormat })
65
78
  : ok({ ...identity, kind: "artifact", format: artifactFormat });
66
79
  }
67
- const detected = await readExecutableMetadata(handle, hostArchitecture);
80
+ const detected = await readExecutableMetadata(handle, hostArchitecture, signal);
68
81
  if (!detected.ok)
69
82
  return err(new BinaryTargetError(path, detected.error));
70
83
  return ok({
71
84
  path,
72
85
  sourcePath: process.platform === "win32" ? candidate : canonical,
73
86
  ...bundle,
74
- sha256: await sha256Handle(handle),
87
+ sha256: await sha256Handle(handle, path, metadata, signal),
75
88
  kind: "executable",
76
89
  ...detected.value,
77
90
  });
@@ -81,6 +94,10 @@ export const parseBinaryTarget = async (input, cwd = process.cwd(), hostArchitec
81
94
  }
82
95
  }
83
96
  catch (cause) {
97
+ if (cause instanceof AnalysisCancelledError)
98
+ return err(cause);
99
+ if (cause instanceof BinaryTargetError)
100
+ return err(cause);
84
101
  if (!(cause instanceof Error))
85
102
  throw cause;
86
103
  const code = filesystemErrorCode(cause);
@@ -103,14 +120,24 @@ const targetFailureReason = (code, detail) => {
103
120
  return `permission denied while reading target: ${detail}`;
104
121
  case "EISDIR":
105
122
  return `target is a directory, not a readable file: ${detail}`;
123
+ case "ENOTFILE":
124
+ return "target is not a regular file";
125
+ case "ELOOP":
126
+ return `target changed while being opened: ${detail}`;
106
127
  default:
107
128
  return `target could not be read (${code}): ${detail}`;
108
129
  }
109
130
  };
110
- const detectArtifactFormat = async (path, handle) => {
131
+ const throwIfTargetResolutionCancelled = (signal) => {
132
+ if (signal?.aborted === true)
133
+ throw new AnalysisCancelledError("resolve_binary_target");
134
+ };
135
+ const detectArtifactFormat = async (path, handle, signal) => {
136
+ throwIfTargetResolutionCancelled(signal);
111
137
  const lower = path.toLowerCase();
112
138
  const magic = Buffer.alloc(8);
113
139
  const observed = await handle.read(magic, 0, magic.length, 0);
140
+ throwIfTargetResolutionCancelled(signal);
114
141
  if (hasZipSignature(magic.subarray(0, observed.bytesRead))) {
115
142
  return zipPackageFormatForPath(lower) ?? "zip";
116
143
  }
@@ -122,10 +149,13 @@ const detectArtifactFormat = async (path, handle) => {
122
149
  magic.subarray(0, 4).toString("ascii") === "xar!")
123
150
  return "pkg";
124
151
  if (lower.endsWith(".dmg")) {
152
+ throwIfTargetResolutionCancelled(signal);
125
153
  const size = (await handle.stat()).size;
154
+ throwIfTargetResolutionCancelled(signal);
126
155
  if (size >= 512) {
127
156
  const trailer = Buffer.alloc(4);
128
157
  const read = await handle.read(trailer, 0, trailer.length, size - 512);
158
+ throwIfTargetResolutionCancelled(signal);
129
159
  if (read.bytesRead === 4 && trailer.toString("ascii") === "koly")
130
160
  return "dmg";
131
161
  }
@@ -142,17 +172,25 @@ const namedArtifactFormat = (lowerPath) => {
142
172
  return /\.(?:m?js|cjs)$/u.test(lowerPath) ? "javascript" : undefined;
143
173
  };
144
174
  const isArchiveFormat = (format) => ["zip", "ipa", "apk", "msix", "appx", "asar", "dmg", "pkg"].includes(format);
145
- const sha256Handle = async (handle) => {
175
+ const sha256Handle = async (handle, path, initial, signal) => {
146
176
  const hash = createHash("sha256");
147
177
  const chunk = Buffer.allocUnsafe(64 * 1024);
148
178
  let position = 0;
149
179
  while (true) {
180
+ throwIfTargetResolutionCancelled(signal);
150
181
  const observed = await handle.read(chunk, 0, chunk.length, position);
182
+ throwIfTargetResolutionCancelled(signal);
151
183
  if (observed.bytesRead === 0)
152
184
  break;
153
185
  hash.update(chunk.subarray(0, observed.bytesRead));
154
186
  position += observed.bytesRead;
155
187
  }
188
+ throwIfTargetResolutionCancelled(signal);
189
+ const [opened, currentPath] = await Promise.all([handle.stat(), lstat(path)]);
190
+ if (!sameRegularFileState(initial, opened) ||
191
+ !sameRegularFileState(initial, currentPath) ||
192
+ position !== initial.size)
193
+ throw new BinaryTargetError(path, "target changed while being read");
156
194
  return hash.digest("hex");
157
195
  };
158
196
  const resolveAppBundle = async (path) => {
@@ -165,19 +203,22 @@ const resolveAppBundle = async (path) => {
165
203
  }));
166
204
  return resolveAppBundleExecutable(path);
167
205
  };
168
- const readExecutableMetadata = async (handle, hostArchitecture) => {
206
+ const readExecutableMetadata = async (handle, hostArchitecture, signal) => {
207
+ throwIfTargetResolutionCancelled(signal);
169
208
  const prefix = Buffer.alloc(4096);
170
209
  const prefixRead = await handle.read(prefix, 0, prefix.length, 0);
210
+ throwIfTargetResolutionCancelled(signal);
171
211
  const bytes = prefix.subarray(0, prefixRead.bytesRead);
172
212
  // Header commitments such as Mach-O load commands and FAT slices are
173
213
  // checked against the whole file, not the probed prefix.
174
214
  const fileSize = (await handle.stat()).size;
215
+ throwIfTargetResolutionCancelled(signal);
175
216
  if (bytes.length >= 2 && bytes[0] === 0x4d && bytes[1] === 0x5a) {
176
217
  const offset = mzWindowsHeaderOffset(bytes);
177
218
  if (offset !== null) {
178
219
  if (offset < 64)
179
220
  return err("invalid Windows new-header offset in MZ image");
180
- return readPeMetadata(handle, offset);
221
+ return readPeMetadata(handle, offset, signal);
181
222
  }
182
223
  // MZ relocation records may extend past the initial probe; their format
183
224
  // bounds are at most 65535 records inside a 65535-paragraph header.
@@ -190,6 +231,7 @@ const readExecutableMetadata = async (handle, hostArchitecture) => {
190
231
  tableEnd <= fileSize) {
191
232
  const table = Buffer.alloc(tableEnd);
192
233
  const observed = await handle.read(table, 0, table.length, 0);
234
+ throwIfTargetResolutionCancelled(signal);
193
235
  return parseExecutableHeader(table.subarray(0, observed.bytesRead), hostArchitecture, fileSize);
194
236
  }
195
237
  return parseExecutableHeader(bytes, hostArchitecture, fileSize);
@@ -203,15 +245,18 @@ const readExecutableMetadata = async (handle, hostArchitecture) => {
203
245
  if (count <= 128 && required > bytes.length) {
204
246
  const header = Buffer.alloc(required);
205
247
  const headerRead = await handle.read(header, 0, header.length, 0);
248
+ throwIfTargetResolutionCancelled(signal);
206
249
  return parseExecutableHeader(header.subarray(0, headerRead.bytesRead), hostArchitecture, fileSize);
207
250
  }
208
251
  }
209
252
  }
210
253
  return parseExecutableHeader(bytes, hostArchitecture, fileSize);
211
254
  };
212
- const readPeMetadata = async (handle, offset) => {
255
+ const readPeMetadata = async (handle, offset, signal) => {
256
+ throwIfTargetResolutionCancelled(signal);
213
257
  const fileHeader = Buffer.alloc(24);
214
258
  const fileHeaderRead = await handle.read(fileHeader, 0, fileHeader.length, offset);
259
+ throwIfTargetResolutionCancelled(signal);
215
260
  if (fileHeaderRead.bytesRead !== fileHeader.length)
216
261
  return err("invalid or truncated PE header");
217
262
  const signature = fileHeader.toString("ascii", 0, 2);
@@ -222,6 +267,7 @@ const readPeMetadata = async (handle, offset) => {
222
267
  return err("invalid PE optional header size");
223
268
  const record = Buffer.alloc(24 + optionalHeaderSize);
224
269
  const recordRead = await handle.read(record, 0, record.length, offset);
270
+ throwIfTargetResolutionCancelled(signal);
225
271
  return recordRead.bytesRead === record.length
226
272
  ? parsePeRecord(record)
227
273
  : err("invalid or truncated PE header");
@@ -1,9 +1,9 @@
1
- import { canonicalDigest } from "../domain/comparisonSemantics.js";
1
+ import { digestCanonicalValue } from "../domain/canonicalDigest.js";
2
2
  import { createEvidence, } from "../domain/evidence.js";
3
3
  import { jsonObjectSchema, jsonValueSchema } from "../domain/jsonValue.js";
4
4
  const browserScenarioParameters = (scenario) => ({
5
5
  ...jsonObjectSchema.parse(scenario),
6
- scenario_sha256: canonicalDigest(scenario, "Browser scenario"),
6
+ scenario_sha256: digestCanonicalValue(scenario, "Browser scenario"),
7
7
  });
8
8
  /** Create Evidence without retaining resolved scenario secret values. */
9
9
  export const createBrowserScenarioEvidence = (scenario, capture, provider) => createEvidence(undefined, provider, {
@@ -858,6 +858,33 @@ const tomlServerEntry = (document, serverKey) => {
858
858
  /** Whether Grok Build's root disable list names `serverKey`. */
859
859
  export const grokServerListedDisabled = (document, serverKey) => Array.isArray(document.disabled_mcp_servers) &&
860
860
  document.disabled_mcp_servers.includes(serverKey);
861
+ /**
862
+ * OMP's user `disabledServers` denylist hides a server by name regardless of
863
+ * its entry, so a listed REA registration is not loaded.
864
+ */
865
+ export const OMP_DISABLED_SERVERS_KEY = "disabledServers";
866
+ /** Whether OMP's root `disabledServers` denylist names `serverKey`. */
867
+ export const ompServerListedDisabled = (document, serverKey) => {
868
+ const listed = document[OMP_DISABLED_SERVERS_KEY];
869
+ return Array.isArray(listed) && listed.includes(serverKey);
870
+ };
871
+ /** OMP's user `enabledServers` allowlist overrides an entry's `enabled: false`. */
872
+ const OMP_ENABLED_SERVERS_KEY = "enabledServers";
873
+ /**
874
+ * Whether OMP's allowlist forces `serverKey` on despite its entry's
875
+ * `enabled: false`. The `disabledServers` denylist still wins over it.
876
+ */
877
+ export const clientServerForcedEnabled = (parsed, serverKey) => {
878
+ if (parsed.dialect !== "omp")
879
+ return false;
880
+ const listed = parsed.document[OMP_ENABLED_SERVERS_KEY];
881
+ return Array.isArray(listed) && listed.includes(serverKey);
882
+ };
883
+ /** Whether a client's own disable list suppresses `serverKey`. */
884
+ export const clientServerListedDisabled = (parsed, serverKey) => (parsed.dialect === "grok" &&
885
+ grokServerListedDisabled(parsed.document, serverKey)) ||
886
+ (parsed.dialect === "omp" &&
887
+ ompServerListedDisabled(parsed.document, serverKey));
861
888
  /** Keep an existing Grok document intact aside from the REA server tables. */
862
889
  const serializeGrokConfiguration = (document, originalText) => {
863
890
  const entry = tomlServerEntry(document, PRODUCT_IDENTITY.mcpServerKey);
@@ -1051,6 +1078,7 @@ export const clientRegistrationEntry = (format, command, environment) => {
1051
1078
  : { environment: { ...environment } }),
1052
1079
  };
1053
1080
  case "vscode":
1081
+ case "omp":
1054
1082
  return {
1055
1083
  type: "stdio",
1056
1084
  command: executable,
@@ -1,4 +1,4 @@
1
- import { effectiveClientServer, grokServerListedDisabled, parseClientConfiguration, } from "./ClientConfigurationDocument.js";
1
+ import { clientServerForcedEnabled, clientServerListedDisabled, effectiveClientServer, parseClientConfiguration, } from "./ClientConfigurationDocument.js";
2
2
  import { access, readFile } from "node:fs/promises";
3
3
  import { resolve } from "node:path";
4
4
  import { z } from "zod";
@@ -29,7 +29,11 @@ export const readClientRegistrationStatuses = async (home, currentCommandPath =
29
29
  CODEX_HOME: options.environment.CODEX_HOME,
30
30
  COPILOT_HOME: options.environment.COPILOT_HOME,
31
31
  GROK_HOME: options.environment.GROK_HOME,
32
+ OMP_PROFILE: options.environment.OMP_PROFILE,
32
33
  OPENCODE_CONFIG: options.environment.OPENCODE_CONFIG,
34
+ PI_CODING_AGENT_DIR: options.environment.PI_CODING_AGENT_DIR,
35
+ PI_CONFIG_DIR: options.environment.PI_CONFIG_DIR,
36
+ PI_PROFILE: options.environment.PI_PROFILE,
33
37
  SAND_DATA_ROOT: options.environment.SAND_DATA_ROOT,
34
38
  XDG_CONFIG_HOME: options.environment.XDG_CONFIG_HOME,
35
39
  })) {
@@ -61,9 +65,8 @@ export const readClientRegistrationStatuses = async (home, currentCommandPath =
61
65
  registration.command,
62
66
  ...registration.args,
63
67
  ];
64
- statuses.push(configuredStatus(client.name, client.configPath, command, registrationAligned(registration, client, currentCommandPath, options.platform ?? process.platform) &&
65
- !(client.format === "grok" &&
66
- grokServerListedDisabled(parsed.document, PRODUCT_IDENTITY.mcpServerKey))
68
+ statuses.push(configuredStatus(client.name, client.configPath, command, registrationAligned(registration, client, currentCommandPath, options.platform ?? process.platform, clientServerForcedEnabled(parsed, PRODUCT_IDENTITY.mcpServerKey)) &&
69
+ !clientServerListedDisabled(parsed, PRODUCT_IDENTITY.mcpServerKey)
67
70
  ? "aligned"
68
71
  : "stale"));
69
72
  }
@@ -73,9 +76,10 @@ export const readClientRegistrationStatuses = async (home, currentCommandPath =
73
76
  }
74
77
  return statuses.sort((left, right) => left.client.localeCompare(right.client));
75
78
  };
76
- const registrationAligned = (registration, client, currentCommandPath, platform) => {
79
+ const registrationAligned = (registration, client, currentCommandPath, platform, forcedEnabled = false) => {
77
80
  const command = [registration.command, ...registration.args];
78
- if (registration.disabled === true || registration.enabled === false)
81
+ if (registration.disabled === true ||
82
+ (registration.enabled === false && !forcedEnabled))
79
83
  return false;
80
84
  if (!isOwnedClientRegistrationCommand(command, currentCommandPath))
81
85
  return false;
@@ -85,6 +89,11 @@ const registrationAligned = (registration, client, currentCommandPath, platform)
85
89
  return false;
86
90
  if (client.format === "vscode" && registration.type !== "stdio")
87
91
  return false;
92
+ // OMP infers stdio for a command entry without an explicit type.
93
+ if (client.format === "omp" &&
94
+ registration.type !== undefined &&
95
+ registration.type !== "stdio")
96
+ return false;
88
97
  if (client.format === "copilot_cli" &&
89
98
  (registration.type !== "stdio" ||
90
99
  JSON.stringify(registration.tools) !== JSON.stringify(["*"])))
@@ -127,6 +136,10 @@ const parseRegistration = (value, client) => {
127
136
  throw new TypeError("Expected an stdio registration");
128
137
  if (client.format === "commandcode" && registration.transport !== "stdio")
129
138
  throw new TypeError("Expected an stdio registration");
139
+ if (client.format === "omp" &&
140
+ registration.type !== undefined &&
141
+ registration.type !== "stdio")
142
+ throw new TypeError("Expected an stdio registration");
130
143
  return registration;
131
144
  };
132
145
  const remediation = "Run rea setup to refresh this registration, then restart the client.";