rea-agents 6.0.0 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (343) hide show
  1. package/README.md +23 -17
  2. package/bridge/android/ReaJadxBridge.java +14 -5
  3. package/bridge/ghidra/ReaGhidraBridge.java +173 -47
  4. package/bridge/hopper_bridge.py +310 -128
  5. package/bridge/mitmproxy/capture.py +0 -2
  6. package/bridge/native/rea_lldb_tracer.py +630 -94
  7. package/bridge/process/ProcessRunTokenReader.swift +39 -5
  8. package/bridge/pwntools/recorded_crash_impl.py +4 -0
  9. package/dist/android/JadxConfiguration.js +196 -33
  10. package/dist/android/JadxMcpTransport.js +4 -0
  11. package/dist/android/JadxProtocol.js +6 -0
  12. package/dist/android/JadxProvider.js +19 -2
  13. package/dist/android/JadxSession.js +23 -4
  14. package/dist/application/AnalysisContextQueries.js +8 -35
  15. package/dist/application/AnalysisDocument.js +32 -0
  16. package/dist/application/AppBundleExecutable.js +67 -21
  17. package/dist/application/CallPathTracing.js +19 -3
  18. package/dist/application/CapabilityInventory.js +6 -3
  19. package/dist/application/ClientConfigurationDocument.js +871 -6
  20. package/dist/application/ClientRegistrationIdentity.js +26 -5
  21. package/dist/application/ClientRegistrationStatus.js +29 -14
  22. package/dist/application/DirectAnalysis.js +27 -37
  23. package/dist/application/Doctor.js +4 -2
  24. package/dist/application/DoctorScope.js +25 -13
  25. package/dist/application/EnhancedLiteralTracing.js +22 -25
  26. package/dist/application/EnhancedTools.js +13 -11
  27. package/dist/application/EvidenceBundleFiles.js +23 -11
  28. package/dist/application/FunctionAnalysisEvidence.js +2 -3
  29. package/dist/application/InventoryProjectionEvidence.js +4 -3
  30. package/dist/application/InvestigationProviders.js +3 -2
  31. package/dist/application/JsonFiles.js +50 -28
  32. package/dist/application/ProcedureAddressResolution.js +11 -0
  33. package/dist/application/ReconstructionCoverageService.js +7 -4
  34. package/dist/application/ReconstructionObligationLedgerService.js +4 -3
  35. package/dist/application/Setup.js +13 -1
  36. package/dist/application/SetupClientConfiguration.js +10 -15
  37. package/dist/application/SetupHost.js +5 -2
  38. package/dist/application/SetupPlan.js +5 -3
  39. package/dist/application/SupportedClients.js +34 -1
  40. package/dist/application/Uninstall.js +4 -3
  41. package/dist/application/Update.js +18 -3
  42. package/dist/application/UpdateRuntime.js +46 -25
  43. package/dist/application/WebModuleTraceService.js +4 -2
  44. package/dist/application/WebNetworkCaptureService.js +4 -2
  45. package/dist/application/WebRuntimeService.js +5 -3
  46. package/dist/application/WebScriptExportService.js +2 -2
  47. package/dist/application/WebSourceLocationService.js +4 -2
  48. package/dist/application/WorkflowEvidence.js +82 -0
  49. package/dist/application/binary/AnalysisProviderEvaluation.js +21 -5
  50. package/dist/application/binary/AnalysisProviderRegistry.js +2 -0
  51. package/dist/application/binary/AnalysisSnapshotCache.js +3 -6
  52. package/dist/application/binary/BinarySession.js +95 -68
  53. package/dist/application/binary/BinarySessionOpen.js +3 -3
  54. package/dist/application/binary/BinarySessionRecords.js +25 -3
  55. package/dist/application/binary/BinarySessionStatus.js +17 -1
  56. package/dist/application/binary/CompositeProvider.js +13 -0
  57. package/dist/application/binary/LazyAnalysisProvider.js +3 -0
  58. package/dist/application/binaryDiagnostics/BinaryLayoutService.js +4 -2
  59. package/dist/application/binaryDiagnostics/RecordedCrashService.js +4 -2
  60. package/dist/application/evm/EvmInterfaceService.js +4 -2
  61. package/dist/application/investigation/EvidenceLedger.js +21 -7
  62. package/dist/application/investigation/InvestigationRecords.js +8 -0
  63. package/dist/application/javascript/JavaScriptAnalysisControl.js +34 -0
  64. package/dist/application/javascript/JavaScriptApplicationEvidence.js +24 -3
  65. package/dist/application/javascript/JavaScriptApplicationEvidenceGraph.js +19 -2
  66. package/dist/application/javascript/JavaScriptApplicationService.js +22 -15
  67. package/dist/application/javascript/JavaScriptApplicationWorkflowService.js +5 -5
  68. package/dist/application/javascript/JavaScriptArtifactAnalysis.js +5 -4
  69. package/dist/application/javascript/JavaScriptArtifactGraphBuilder.js +39 -7
  70. package/dist/application/javascript/JavaScriptArtifactPathResolution.js +6 -3
  71. package/dist/application/javascript/JavaScriptArtifactReconstruction.js +11 -3
  72. package/dist/application/javascript/JavaScriptModuleRelationships.js +37 -8
  73. package/dist/application/javascript/JavaScriptRecoveryService.js +4 -2
  74. package/dist/application/javascript/JavaScriptRuntimeObservationService.js +3 -1
  75. package/dist/application/javascript/JavaScriptRuntimeReconciliationService.js +3 -3
  76. package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +63 -61
  77. package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +23 -1
  78. package/dist/application/managed/ManagedApplicationGraphService.js +4 -3
  79. package/dist/application/managed/ManagedMemberComparisonService.js +7 -4
  80. package/dist/application/managed/ManagedNativeVerificationService.js +4 -3
  81. package/dist/application/managed/ManagedReconstructionService.js +4 -3
  82. package/dist/application/process/ProcessCli.js +14 -6
  83. package/dist/application/process/ProcessEvidence.js +4 -3
  84. package/dist/application/workflowInputError.js +18 -0
  85. package/dist/artifacts/ArtifactProvider.js +12 -2
  86. package/dist/artifacts/MachOSliceArtifactReader.js +98 -14
  87. package/dist/artifacts/NativeDmgArtifactReader.js +13 -6
  88. package/dist/artifacts/apple/AppleAssetCatalogAnalysis.js +22 -3
  89. package/dist/artifacts/apple/InterfaceBuilderAnalysis.js +176 -56
  90. package/dist/artifacts/apple/InterfaceBuilderDecodeBudget.js +195 -0
  91. package/dist/artifacts/apple/KeyedArchiveReader.js +36 -22
  92. package/dist/artifacts/apple/MachoLoadCommandReader.js +92 -31
  93. package/dist/artifacts/apple/NibArchive.js +81 -14
  94. package/dist/artifacts/apple/NibViewHierarchy.js +10 -3
  95. package/dist/artifacts/apple/PlistNumberLiterals.js +164 -0
  96. package/dist/artifacts/inventory/ArtifactGraphConstruction.js +13 -8
  97. package/dist/artifacts/inventory/scanCanonical.js +11 -14
  98. package/dist/artifacts/javascript/JavaScriptArtifactFiles.js +6 -2
  99. package/dist/browser/CdpCaptureCompleteness.js +2 -0
  100. package/dist/browser/CdpCaptureEventHandlers.js +76 -11
  101. package/dist/browser/CdpCaptureEventTypes.js +5 -1
  102. package/dist/browser/CdpCaptureEvents.js +25 -0
  103. package/dist/browser/CdpConnection.js +30 -11
  104. package/dist/browser/CdpOptionalCommand.js +2 -3
  105. package/dist/browser/CdpPageCapture.js +23 -1
  106. package/dist/browser/PlaywrightElectronActiveActions.js +32 -23
  107. package/dist/browser/PlaywrightElectronActiveProjection.js +141 -0
  108. package/dist/browser/PlaywrightElectronActiveProvider.js +123 -124
  109. package/dist/browser/WebSourceMapFetcher.js +426 -72
  110. package/dist/browser/assets/LocalWebScriptArtifacts.js +2 -2
  111. package/dist/browser/history/CaptureFailures.js +37 -1
  112. package/dist/browser/history/CaptureRelease.js +5 -0
  113. package/dist/browser/history/HarCaptureAdapter.js +3 -3
  114. package/dist/browser/history/HarJson.js +3 -2
  115. package/dist/browser/history/HistoricalCaptureDecoder.js +4 -2
  116. package/dist/cli/analysisSelector.js +23 -0
  117. package/dist/cli/applicationCommands.js +2 -3
  118. package/dist/cli/coreBinaryCommands.js +70 -12
  119. package/dist/cli/electronCommands.js +7 -6
  120. package/dist/cli/javascriptApplicationAnalysis.js +7 -3
  121. package/dist/cli/jsonOutput.js +4 -99
  122. package/dist/cli/nativeCallCommands.js +2 -3
  123. package/dist/cli/webRuntimeCommands.js +8 -8
  124. package/dist/cli.js +2 -1
  125. package/dist/cliCommandNames.js +0 -1
  126. package/dist/cliJsonInput.js +9 -4
  127. package/dist/config/environment.js +4 -0
  128. package/dist/config/ghidraStartupTimeout.js +17 -0
  129. package/dist/config/mcpResponseBudget.js +22 -0
  130. package/dist/config/parseConfig.js +2 -1
  131. package/dist/contracts/enhancedInputs.js +5 -3
  132. package/dist/contracts/enhancedToolContracts.js +3 -3
  133. package/dist/contracts/hopperMemoryContracts.js +2 -5
  134. package/dist/contracts/javascript/electronToolContracts.js +1 -1
  135. package/dist/contracts/managed/managedToolContracts.js +2 -4
  136. package/dist/contracts/native/nativeToolContracts.js +4 -2
  137. package/dist/contracts/officialToolContracts.js +14 -15
  138. package/dist/contracts/promptContracts.js +3 -3
  139. package/dist/contracts/sessionLifecycleInputs.js +3 -7
  140. package/dist/contracts/sessionStatusContract.js +2 -4
  141. package/dist/contracts/sessionToolContracts.js +4 -6
  142. package/dist/contracts/sessionToolSchemas.js +2 -5
  143. package/dist/contracts/toolContractExamples.js +0 -1
  144. package/dist/contracts/toolContractHelpers.js +4 -1
  145. package/dist/contracts/toolEffects.js +0 -1
  146. package/dist/contracts/toolOutputSchemaGroups.js +28 -27
  147. package/dist/contracts/toolOutputSchemaPrimitives.js +18 -0
  148. package/dist/contracts/toolSchemaMetadata.js +69 -10
  149. package/dist/contracts/webNetworkCaptureToolContracts.js +1 -1
  150. package/dist/domain/analysisErrorBase.js +8 -3
  151. package/dist/domain/analysisErrorCore.js +3 -1
  152. package/dist/domain/analysisErrorPresentation.js +72 -17
  153. package/dist/domain/analysisErrorProjection.js +106 -27
  154. package/dist/domain/android/androidAnalysis.js +2 -4
  155. package/dist/domain/android/androidApplication.js +17 -9
  156. package/dist/domain/apple/appleApplication.js +41 -14
  157. package/dist/domain/apple/dyldEnvironment.js +73 -0
  158. package/dist/domain/apple/dylibResolution.js +120 -9
  159. package/dist/domain/apple/dylibResolutionFindings.js +9 -7
  160. package/dist/domain/apple/interfaceBuilderGraph.js +25 -13
  161. package/dist/domain/apple/interfaceBuilderKeyedArchive.js +13 -3
  162. package/dist/domain/apple/keyedArchive.js +9 -1
  163. package/dist/domain/apple/machoContainer.js +54 -0
  164. package/dist/domain/apple/plistNumbers.js +76 -0
  165. package/dist/domain/artifactIdentity.js +29 -0
  166. package/dist/domain/artifactInventoryEvidence.js +19 -24
  167. package/dist/domain/bridgeCandidateProjection.js +71 -0
  168. package/dist/domain/browserCompleteness.js +1 -0
  169. package/dist/domain/browserObservationError.js +24 -5
  170. package/dist/domain/browserScenarioValues.js +2 -6
  171. package/dist/domain/bundleComparison.js +3 -2
  172. package/dist/domain/canonicalJsonDigestSteps.js +133 -0
  173. package/dist/domain/canonicalOrdering.js +9 -5
  174. package/dist/domain/changedBehavior.js +6 -6
  175. package/dist/domain/comparisonSourceEvidence.js +40 -0
  176. package/dist/domain/configurationErrors.js +1 -1
  177. package/dist/domain/evidence.js +64 -9
  178. package/dist/domain/evidenceBundle.js +42 -1
  179. package/dist/domain/evidenceErrors.js +12 -1
  180. package/dist/domain/explicitSensitiveFailure.js +17 -1
  181. package/dist/domain/firmware/firmwareAnalysis.js +6 -7
  182. package/dist/domain/hopperErrors.js +23 -2
  183. package/dist/domain/hopperValues.js +51 -8
  184. package/dist/domain/immutableJson.js +114 -0
  185. package/dist/domain/inputIssueProjection.js +3 -0
  186. package/dist/domain/javascript/electronActiveObservation.js +30 -4
  187. package/dist/domain/javascript/electronStaticAnalysisValues.js +6 -12
  188. package/dist/domain/javascript/javascriptApplicationAnalysis.js +71 -23
  189. package/dist/domain/javascript/javascriptApplicationGraph.js +13 -0
  190. package/dist/domain/javascript/javascriptAstValues.js +20 -0
  191. package/dist/domain/javascript/javascriptRecovery.js +3 -8
  192. package/dist/domain/javascript/javascriptSemanticAnalysis.js +97 -2
  193. package/dist/domain/javascript/javascriptSemanticCoverage.js +6 -5
  194. package/dist/domain/javascript/javascriptSemanticDataEffectHelpers.js +9 -17
  195. package/dist/domain/javascript/javascriptSemanticDataEffects.js +22 -5
  196. package/dist/domain/javascript/javascriptSemanticGraph.js +13 -0
  197. package/dist/domain/javascript/javascriptSemanticGraphSchemas.js +1 -0
  198. package/dist/domain/javascript/javascriptSemanticPrimitives.js +25 -17
  199. package/dist/domain/javascript/javascriptSemanticQuerySchemas.js +8 -4
  200. package/dist/domain/javascript/javascriptSemanticResourceLimits.js +77 -0
  201. package/dist/domain/javascript/javascriptSemanticValues.js +83 -11
  202. package/dist/domain/javascript/javascriptSourceParser.js +6 -2
  203. package/dist/domain/javascript/javascriptStaticAnalysis.js +22 -17
  204. package/dist/domain/javascript/javascriptStaticAnalysisBundler.js +5 -3
  205. package/dist/domain/javascript/javascriptStaticAnalysisCalls.js +14 -4
  206. package/dist/domain/javascript/javascriptStaticAnalysisFindings.js +66 -7
  207. package/dist/domain/javascript/javascriptStaticAnalysisHelpers.js +28 -16
  208. package/dist/domain/javascript/javascriptStaticAnalysisState.js +3 -2
  209. package/dist/domain/jsonSerialization.js +109 -0
  210. package/dist/domain/jsonValue.js +90 -6
  211. package/dist/domain/localPath.js +6 -0
  212. package/dist/domain/managed/managedApplicationGraph.js +10 -10
  213. package/dist/domain/managed/managedInspectionEvidence.js +16 -0
  214. package/dist/domain/managed/managedMemberComparisonMatch.js +5 -9
  215. package/dist/domain/managed/managedNativeVerification.js +3 -9
  216. package/dist/domain/native/fileOffsetPartialObservation.js +1 -0
  217. package/dist/domain/native/nativeCallObservation.js +33 -11
  218. package/dist/domain/native/nativeCallPartialObservation.js +33 -0
  219. package/dist/domain/process/processCapture.js +8 -4
  220. package/dist/domain/process/processComparison.js +38 -4
  221. package/dist/domain/process/processScenario.js +11 -10
  222. package/dist/domain/propertyListKeys.js +1 -1
  223. package/dist/domain/propertyListXmlText.js +19 -0
  224. package/dist/domain/providerAdapterError.js +1 -1
  225. package/dist/domain/providerOperationHealth.js +54 -0
  226. package/dist/domain/reconstructionVerification.js +6 -43
  227. package/dist/domain/reconstructionVerificationSchemas.js +2 -2
  228. package/dist/domain/staticRuntimeCorrelation.js +6 -43
  229. package/dist/domain/webBundleAnalysis.js +20 -8
  230. package/dist/domain/webBundleAnalyzerInspection.js +13 -8
  231. package/dist/domain/webBundleAnalyzerResult.js +41 -2
  232. package/dist/domain/webRuntime.js +19 -5
  233. package/dist/domain/webSourceLocation.js +1 -0
  234. package/dist/firmware/FirmwareFiles.js +1 -1
  235. package/dist/generatedPackageMetadata.js +1 -1
  236. package/dist/ghidra/GhidraAnalysisProfile.js +5 -0
  237. package/dist/ghidra/GhidraClient.js +47 -14
  238. package/dist/ghidra/GhidraDiagnostics.js +7 -7
  239. package/dist/ghidra/GhidraFunctionValues.js +10 -7
  240. package/dist/ghidra/GhidraInstallation.js +18 -21
  241. package/dist/ghidra/GhidraInventoryValues.js +14 -4
  242. package/dist/ghidra/GhidraJavaLaunch.js +62 -0
  243. package/dist/ghidra/GhidraLauncher.js +33 -16
  244. package/dist/ghidra/GhidraProviderCapabilities.js +14 -2
  245. package/dist/ghidra/GhidraProviderClient.js +23 -12
  246. package/dist/ghidra/GhidraSessionError.js +11 -7
  247. package/dist/ghidra/GhidraTargetSnapshot.js +47 -12
  248. package/dist/ghidra/GhidraTransport.js +20 -0
  249. package/dist/hopper/BridgeLauncher.js +31 -11
  250. package/dist/hopper/HopperAnalysisProfile.js +62 -4
  251. package/dist/hopper/HopperCleanup.js +15 -3
  252. package/dist/hopper/HopperClient.js +222 -14
  253. package/dist/hopper/HopperFileOffset.js +237 -0
  254. package/dist/hopper/HopperMachOImage.js +196 -0
  255. package/dist/hopper/HopperOperationStage.js +6 -0
  256. package/dist/hopper/HopperProvider.js +63 -9
  257. package/dist/hopper/HopperProviderCapabilities.js +19 -1
  258. package/dist/hopper/HopperRegexSearch.js +137 -0
  259. package/dist/hopper/HopperRegexWorker.js +27 -0
  260. package/dist/hopper/HopperRequestQueue.js +68 -19
  261. package/dist/hopper/HopperTargetLease.js +3 -2
  262. package/dist/inspector/JavaScriptRuntimeScope.js +9 -1
  263. package/dist/inspector/V8InspectorCaptureProjection.js +8 -3
  264. package/dist/inspector/V8InspectorProvider.js +47 -11
  265. package/dist/javascript/sourceMaps/DecodedSourceMap.js +47 -0
  266. package/dist/javascript/sourceMaps/SourceMapCommand.js +16 -0
  267. package/dist/javascript/sourceMaps/SourceMapFormat.js +79 -31
  268. package/dist/javascript/sourceMaps/TraceSourceMap.js +14 -28
  269. package/dist/mcpDoctor.js +62 -2
  270. package/dist/native/AppleDispatchCoverage.js +47 -6
  271. package/dist/native/AppleDispatchDecodeFacts.js +6 -0
  272. package/dist/native/AppleDispatchMetadata.js +6 -3
  273. package/dist/native/AppleMachoFixups.js +48 -24
  274. package/dist/native/AppleMachoSelection.js +32 -16
  275. package/dist/native/AppleObjcCategories.js +6 -2
  276. package/dist/native/AppleObjcDispatchFacets.js +5 -2
  277. package/dist/native/AppleObjcProperties.js +2 -1
  278. package/dist/native/AppleSwiftDispatchFacets.js +27 -21
  279. package/dist/native/AppleSwiftVtables.js +21 -15
  280. package/dist/native/CommandRunner.js +81 -84
  281. package/dist/native/LldbCallTracer.js +365 -102
  282. package/dist/native/LldbRetainedObservations.js +178 -0
  283. package/dist/native/NativeCallObservation.js +62 -3
  284. package/dist/native/NativeMacOSProvider.js +98 -17
  285. package/dist/native/SignatureTargetBinding.js +155 -0
  286. package/dist/native/parsers/lipo.js +71 -1
  287. package/dist/native/pwndbg/PwndbgCoreContext.js +25 -5
  288. package/dist/native/pwntools/RecordedCrashStructureBindings.js +2 -0
  289. package/dist/process/DarwinProcessRunTokenReader.js +8 -9
  290. package/dist/process/ExecFileOutput.js +20 -0
  291. package/dist/process/OwnedCommand.js +7 -2
  292. package/dist/process/ProcessOwnership.js +203 -53
  293. package/dist/process/ProcessOwnershipObservation.js +49 -4
  294. package/dist/process/ProviderProcess.js +38 -7
  295. package/dist/process/capture/ProcessCaptureError.js +2 -2
  296. package/dist/process/capture/ProcessCaptureLifecycle.js +100 -34
  297. package/dist/server/EvidenceMcpServer.js +146 -0
  298. package/dist/server/createServer.js +15 -8
  299. package/dist/server/registerAndroidTools.js +2 -4
  300. package/dist/server/registerApplicationTools/helpers.js +2 -4
  301. package/dist/server/registerArtifactComparisonTool.js +11 -7
  302. package/dist/server/registerBinaryDiagnosticsTools.js +2 -4
  303. package/dist/server/registerBrowserScenarioTool.js +2 -4
  304. package/dist/server/registerBrowserTools.js +2 -4
  305. package/dist/server/registerBundleComparisonTool.js +2 -3
  306. package/dist/server/registerCloseLifecycleTool.js +8 -18
  307. package/dist/server/registerElectronTools.js +2 -4
  308. package/dist/server/registerEnhancedTools.js +18 -59
  309. package/dist/server/registerEvidenceTools.js +2 -4
  310. package/dist/server/registerEvmTools.js +2 -4
  311. package/dist/server/registerFirmwareTools.js +2 -4
  312. package/dist/server/registerFunctionComparisonTool.js +10 -6
  313. package/dist/server/registerInvestigationTools.js +7 -7
  314. package/dist/server/registerJavaScriptRecoveryTool.js +2 -4
  315. package/dist/server/registerJavaScriptRuntimeObservationTools.js +2 -4
  316. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +2 -4
  317. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +2 -4
  318. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +2 -4
  319. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +2 -4
  320. package/dist/server/registerOfficialTools.js +2 -4
  321. package/dist/server/registerProcessComparisonTool.js +71 -45
  322. package/dist/server/registerRecordedCrashTools.js +2 -4
  323. package/dist/server/registerSessionRecordTools.js +5 -6
  324. package/dist/server/registerSessionStatusTool.js +17 -3
  325. package/dist/server/registerSessionTools.js +11 -3
  326. package/dist/server/registerWebModuleTool.js +2 -4
  327. package/dist/server/registerWebNetworkCaptureTool.js +2 -4
  328. package/dist/server/registerWebRuntimeTools.js +3 -7
  329. package/dist/server/registerWebScriptTool.js +2 -4
  330. package/dist/server/registerWebSourceLocationTool.js +2 -4
  331. package/dist/server/runDerivedOperation.js +15 -3
  332. package/dist/server/sessionAvailabilityPolicy.js +0 -1
  333. package/dist/server/toolRegistrationOptions.js +2 -2
  334. package/dist/server/toolResult.js +62 -10
  335. package/dist/server/toolResultEncoding.js +33 -0
  336. package/install.sh +1 -1
  337. package/native/windows/build/manifest.json +1 -1
  338. package/package.json +8 -3
  339. package/scripts/electron-active-hook-boundaries.cjs +18 -20
  340. package/scripts/electron-active-hook.cjs +241 -37
  341. package/skills/reverse-engineer-anything/SKILL.md +11 -3
  342. package/skills/reverse-engineer-anything/references/javascript-applications.md +8 -1
  343. package/dist/ghidra/GhidraDefaults.js +0 -2
@@ -112,6 +112,31 @@ enum RunTokenReadError: Error {
112
112
  case ambiguousEnvironmentBoundary
113
113
  }
114
114
 
115
+ @_silgen_name("csops")
116
+ private func csops(
117
+ _ pid: Int32,
118
+ _ ops: UInt32,
119
+ _ addr: UnsafeMutableRawPointer?,
120
+ _ size: Int
121
+ ) -> Int32
122
+
123
+ private let csOpsStatus: UInt32 = 0
124
+ private let csPlatformBinary: UInt32 = 0x0400_0000
125
+
126
+ /**
127
+ * Whether the target image is an Apple platform binary. Current macOS omits
128
+ * the environment of platform binaries from KERN_PROCARGS2 for every caller,
129
+ * so this distinguishes a policy-withheld environment from a process whose
130
+ * environment is genuinely absent or transiently unreadable.
131
+ */
132
+ func isPlatformBinary(pid: Int32) -> Bool {
133
+ var flags: UInt32 = 0
134
+ let result = withUnsafeMutablePointer(to: &flags) { pointer in
135
+ csops(pid, csOpsStatus, UnsafeMutableRawPointer(pointer), MemoryLayout<UInt32>.size)
136
+ }
137
+ return result == 0 && (flags & csPlatformBinary) != 0
138
+ }
139
+
115
140
  private func readRunToken(pid: Int32, pointerSize: Int) -> RunTokenObservation {
116
141
  var mib = [CTL_KERN, KERN_PROCARGS2, Int32(pid)]
117
142
  var size = 0
@@ -127,13 +152,25 @@ private func readRunToken(pid: Int32, pointerSize: Int) -> RunTokenObservation {
127
152
  }
128
153
  bytes = Array(bytes.prefix(size))
129
154
  do {
130
- return RunTokenObservation(pid: pid, state: "readable", run_id: try token(in: bytes, pointerSize: pointerSize), reason: nil)
155
+ let runId = try token(in: bytes, pointerSize: pointerSize)
156
+ // A complete empty environment is readable for an ordinary image. Apple
157
+ // platform images can expose the same layout after the kernel withholds
158
+ // their environment, so they remain explicitly unverified without a token.
159
+ if runId == nil && isPlatformBinary(pid: pid) {
160
+ return unavailable(pid: pid, reason: "platform_binary_environment_withheld")
161
+ }
162
+ return RunTokenObservation(pid: pid, state: "readable", run_id: runId, reason: nil)
131
163
  } catch RunTokenReadError.duplicateToken {
132
164
  return unavailable(pid: pid, reason: "duplicate_run_token")
133
165
  } catch RunTokenReadError.invalidTokenEncoding {
134
166
  return unavailable(pid: pid, reason: "invalid_run_token_encoding")
135
167
  } catch RunTokenReadError.environmentUnavailable {
136
- return unavailable(pid: pid, reason: "environment_unavailable")
168
+ return unavailable(
169
+ pid: pid,
170
+ reason: isPlatformBinary(pid: pid)
171
+ ? "platform_binary_environment_withheld"
172
+ : "environment_unavailable"
173
+ )
137
174
  } catch RunTokenReadError.appleVectorUnavailable {
138
175
  return unavailable(pid: pid, reason: "apple_vector_unavailable")
139
176
  } catch RunTokenReadError.ambiguousEnvironmentBoundary {
@@ -229,9 +266,6 @@ func token(in bytes: [UInt8], pointerSize: Int = MemoryLayout<UnsafeRawPointer>.
229
266
  throw RunTokenReadError.ambiguousEnvironmentBoundary
230
267
  }
231
268
  let environmentEntries = trailingEntries[..<appleVectorStart]
232
- guard !environmentEntries.isEmpty else {
233
- throw RunTokenReadError.environmentUnavailable
234
- }
235
269
  var found: String?
236
270
  for entry in environmentEntries {
237
271
  if entry.starts(with: Array("REA_PROCESS_RUN_ID=".utf8)) {
@@ -43,6 +43,10 @@ def inspect_core(path, cache):
43
43
  raise CoreFailure("unsupported-target", "Initial recorded-core profile requires ELF64 little-endian.")
44
44
  if len(content) < 64:
45
45
  raise CoreFailure("format", "Selected ELF64 core header is truncated.")
46
+ if content[6] != 1:
47
+ raise CoreFailure("format", "ELF identification version is not EV_CURRENT.")
48
+ if int.from_bytes(content[20:24], "little") != 1:
49
+ raise CoreFailure("format", "ELF header version is not EV_CURRENT.")
46
50
  # Linux commonly emits ELFOSABI_NONE (0), also accepted as GNU/Linux (3).
47
51
  # Other declared OSABIs must never select Linux note ctypes.
48
52
  if content[7] not in (0, 3) or content[8] != 0:
@@ -1,44 +1,130 @@
1
- import { access, realpath, stat } from "node:fs/promises";
2
1
  import { constants } from "node:fs";
2
+ import { access, realpath, stat } from "node:fs/promises";
3
3
  import { isAbsolute, join } from "node:path";
4
4
  import { AnalysisCapabilityUnavailableError } from "../domain/analysisErrorCore.js";
5
+ import { execFileOutput, execFileOutputFailure, } from "../process/ExecFileOutput.js";
5
6
  import { JADX_JAR_CONFIGURATION_REMEDIATION } from "./JadxRelease.js";
6
- /** Admit explicit local tooling without installing or changing host configuration. */
7
- export const resolveJadxConfiguration = async (environment, operation) => {
8
- const unavailable = (reason) => new AnalysisCapabilityUnavailableError("jadx", operation, reason);
9
- if (process.platform !== "linux" && process.platform !== "darwin")
10
- throw unavailable(`Android JADX subprocess ownership is unsupported on ${process.platform}; use Linux or macOS. The metadata bridge has real-provider verification on macOS arm64.`);
7
+ const JAVA_MODULE_LISTING_TIMEOUT_MS = 10_000;
8
+ const JAVA_MODULE_LISTING_MAX_OUTPUT_BYTES = 1024 * 1024;
9
+ class JadxConfigurationFailure extends Error {
10
+ code;
11
+ diagnostics;
12
+ constructor(code, message, diagnostics, options) {
13
+ super(message, options);
14
+ this.code = code;
15
+ this.diagnostics = diagnostics;
16
+ }
17
+ }
18
+ /** Inspect the same JAR and Java prerequisites that gate actual execution. */
19
+ export const inspectJadxAvailability = async (environment, signal) => {
20
+ try {
21
+ const configuration = await readJadxConfiguration(environment, signal);
22
+ return {
23
+ status: "available",
24
+ code: null,
25
+ reason: null,
26
+ diagnostics: {
27
+ configured: true,
28
+ java_executable: configuration.java,
29
+ jdk_compiler: true,
30
+ jar_path: configuration.jar,
31
+ },
32
+ };
33
+ }
34
+ catch (cause) {
35
+ if (signal?.aborted === true)
36
+ throw cause;
37
+ if (cause instanceof JadxConfigurationFailure)
38
+ return {
39
+ status: "unavailable",
40
+ code: cause.code,
41
+ reason: cause.message,
42
+ diagnostics: cause.diagnostics,
43
+ };
44
+ throw cause;
45
+ }
46
+ };
47
+ /** Resolve caller-selected tools and preserve the same prerequisite diagnostics. */
48
+ export const resolveJadxConfiguration = async (environment, operation, signal) => {
49
+ try {
50
+ return await readJadxConfiguration(environment, signal);
51
+ }
52
+ catch (cause) {
53
+ if (signal?.aborted === true)
54
+ throw cause;
55
+ if (!(cause instanceof JadxConfigurationFailure))
56
+ throw cause;
57
+ const output = cause.diagnostics;
58
+ throw new AnalysisCapabilityUnavailableError("jadx", operation, cause.message, {
59
+ cause,
60
+ userMessage: cause.message,
61
+ ...(typeof output.stdout === "string" &&
62
+ typeof output.stderr === "string"
63
+ ? {
64
+ capturedOutput: {
65
+ stdout: output.stdout,
66
+ stderr: output.stderr,
67
+ truncated: output.output_truncated === true,
68
+ },
69
+ }
70
+ : {}),
71
+ });
72
+ }
73
+ };
74
+ const readJadxConfiguration = async (environment, signal) => {
75
+ requireSupportedHost();
76
+ const jar = await resolveJar(environment);
77
+ const java = resolveJava(environment);
78
+ await requireJavaHomeExecutable(environment.JAVA_HOME, java);
79
+ const jvmArguments = resolveJvmArguments(environment);
80
+ await inspectJavaRuntime(java, environment, signal);
81
+ return { jar, java, jvmArguments };
82
+ };
83
+ const requireSupportedHost = () => {
84
+ if (process.platform === "linux" || process.platform === "darwin")
85
+ return;
86
+ throw configurationFailure("unsupported_host", `Android JADX subprocess ownership is unsupported on ${process.platform}; use Linux or macOS. The metadata bridge has real-provider verification on macOS arm64.`, { platform: process.platform });
87
+ };
88
+ const resolveJar = async (environment) => {
11
89
  const jar = environment.REA_JADX_MCP_JAR;
12
- if (environment.JAVA_HOME !== undefined && !isAbsolute(environment.JAVA_HOME))
13
- throw unavailable("JAVA_HOME must select an existing JDK by absolute path; omit it to use java on PATH.");
14
90
  if (jar === undefined || !isAbsolute(jar))
15
- throw unavailable(JADX_JAR_CONFIGURATION_REMEDIATION);
16
- const java = environment.JAVA_HOME === undefined
17
- ? "java"
18
- : join(environment.JAVA_HOME, "bin", "java");
91
+ throw configurationFailure("not_configured", JADX_JAR_CONFIGURATION_REMEDIATION, { jar_configured: false });
19
92
  try {
20
93
  await access(jar, constants.R_OK);
21
94
  if (!(await stat(jar)).isFile())
22
- throw unavailable(`REA_JADX_MCP_JAR is not a regular file: ${jar}`);
95
+ throw configurationFailure("executable_missing", `REA_JADX_MCP_JAR is not a regular file: ${jar}`, { jar_path: jar });
96
+ return await realpath(jar);
23
97
  }
24
98
  catch (cause) {
25
- if (cause instanceof AnalysisCapabilityUnavailableError)
99
+ if (cause instanceof JadxConfigurationFailure)
26
100
  throw cause;
27
- throw unavailable(`Cannot read REA_JADX_MCP_JAR ${jar}: ${cause instanceof Error ? cause.message : String(cause)}`);
28
- }
29
- if (environment.JAVA_HOME !== undefined) {
30
- try {
31
- await access(java, constants.R_OK | constants.X_OK);
32
- if (!(await stat(java)).isFile())
33
- throw unavailable(`JAVA_HOME java is not a regular file: ${java}`);
34
- }
35
- catch (cause) {
36
- if (cause instanceof AnalysisCapabilityUnavailableError)
37
- throw cause;
38
- throw unavailable(`Cannot execute JAVA_HOME java ${java}: ${cause instanceof Error ? cause.message : String(cause)}`);
39
- }
40
- }
41
- const jvmArguments = [];
101
+ throw configurationFailure("executable_missing", `Cannot read REA_JADX_MCP_JAR ${jar}: ${cause instanceof Error ? cause.message : String(cause)}`, { jar_path: jar }, cause);
102
+ }
103
+ };
104
+ const resolveJava = (environment) => {
105
+ if (environment.JAVA_HOME === undefined)
106
+ return "java";
107
+ if (isAbsolute(environment.JAVA_HOME))
108
+ return join(environment.JAVA_HOME, "bin", "java");
109
+ throw configurationFailure("open_options_invalid", "JAVA_HOME must select an existing JDK by absolute path; omit it to use java on PATH.", { java_home: environment.JAVA_HOME });
110
+ };
111
+ const requireJavaHomeExecutable = async (javaHome, java) => {
112
+ if (javaHome === undefined)
113
+ return;
114
+ try {
115
+ await access(java, constants.R_OK | constants.X_OK);
116
+ if ((await stat(java)).isFile())
117
+ return;
118
+ throw configurationFailure("runtime_missing", `JAVA_HOME java is not a regular file: ${java}`, { java_executable: java });
119
+ }
120
+ catch (cause) {
121
+ if (cause instanceof JadxConfigurationFailure)
122
+ throw cause;
123
+ throw configurationFailure("runtime_missing", `Cannot execute JAVA_HOME java ${java}: ${cause instanceof Error ? cause.message : String(cause)}`, { java_executable: java }, cause);
124
+ }
125
+ };
126
+ const resolveJvmArguments = (environment) => {
127
+ const result = [];
42
128
  for (const [name, prefix, suffix] of [
43
129
  ["REA_JADX_HEAP_MIB", "-Xmx", "m"],
44
130
  ["REA_JADX_ACTIVE_PROCESSOR_COUNT", "-XX:ActiveProcessorCount=", ""],
@@ -47,11 +133,88 @@ export const resolveJadxConfiguration = async (environment, operation) => {
47
133
  if (value === undefined)
48
134
  continue;
49
135
  if (!/^[1-9]\d*$/u.test(value) || !Number.isSafeInteger(Number(value)))
50
- throw unavailable(`${name} must be a positive safe integer; received ${value}.`);
136
+ throw configurationFailure("open_options_invalid", `${name} must be a positive safe integer; received ${value}.`, { setting: name, value });
51
137
  if (name === "REA_JADX_ACTIVE_PROCESSOR_COUNT" &&
52
138
  Number(value) > 2_147_483_647)
53
- throw unavailable(`${name} exceeds the JVM's signed 32-bit processor-count range.`);
54
- jvmArguments.push(`${prefix}${value}${suffix}`);
139
+ throw configurationFailure("open_options_invalid", `${name} exceeds the JVM's signed 32-bit processor-count range.`, { setting: name, value });
140
+ result.push(`${prefix}${value}${suffix}`);
141
+ }
142
+ return result;
143
+ };
144
+ const inspectJavaRuntime = async (java, environment, signal) => {
145
+ let stdout;
146
+ let stderr;
147
+ try {
148
+ ({ stdout, stderr } = await execFileOutput(java, ["--list-modules"], {
149
+ env: { ...environment },
150
+ timeout: JAVA_MODULE_LISTING_TIMEOUT_MS,
151
+ maxBuffer: JAVA_MODULE_LISTING_MAX_OUTPUT_BYTES,
152
+ ...(signal === undefined ? {} : { signal }),
153
+ }));
154
+ }
155
+ catch (cause) {
156
+ if (signal?.aborted === true)
157
+ throw cause;
158
+ const output = execFileOutputFailure(cause);
159
+ if (output === undefined)
160
+ throw cause;
161
+ const diagnostics = {
162
+ java_executable: java,
163
+ phase: "module-inspection",
164
+ exit_code: typeof output.code === "number" ? output.code : null,
165
+ process_error_code: typeof output.code === "string" ? output.code : null,
166
+ signal: output.signal,
167
+ killed: output.killed,
168
+ stdout: output.stdout,
169
+ stderr: output.stderr,
170
+ output_truncated: output.outputTruncated,
171
+ };
172
+ if (output.outputTruncated)
173
+ throw configurationFailure("version_unresolved", `The selected Java launcher ${java} exceeded the ${JAVA_MODULE_LISTING_MAX_OUTPUT_BYTES / (1024 * 1024)} MiB output budget while listing modules. REA retained partial output but could not establish compiler or version availability. Inspect the selected launcher for verbose or unbounded output; ` +
174
+ "java --list-modules should return a concise module listing.", {
175
+ ...diagnostics,
176
+ failure: "output_limit",
177
+ output_limit_bytes: JAVA_MODULE_LISTING_MAX_OUTPUT_BYTES,
178
+ }, cause);
179
+ if (output.killed)
180
+ throw configurationFailure("version_unresolved", `The selected Java launcher ${java} was terminated or did not finish the module-listing probe within ${JAVA_MODULE_LISTING_TIMEOUT_MS / 1000} seconds. Inspect the launcher and its startup responsiveness, then verify it returns compiler and version modules with java --list-modules.`, {
181
+ ...diagnostics,
182
+ failure: "probe_terminated",
183
+ deadline_ms: JAVA_MODULE_LISTING_TIMEOUT_MS,
184
+ }, cause);
185
+ throw configurationFailure("runtime_missing", `Cannot inspect selected Java runtime ${java}: ${output.stderr.trim() || errorText(cause)}. Select a full JDK including jdk.compiler via JAVA_HOME or PATH; verify it with java --list-modules.`, diagnostics, cause);
55
186
  }
56
- return { jar: await realpath(jar), java, jvmArguments };
187
+ const compiler = /^jdk\.compiler(?:@|$)/mu.test(stdout);
188
+ if (!compiler)
189
+ throw configurationFailure("runtime_missing", `Selected Java runtime ${java} does not provide jdk.compiler. Select a full JDK including jdk.compiler via JAVA_HOME or PATH; verify it with java --list-modules. A JRE cannot compile REA's source bridge.`, {
190
+ java_executable: java,
191
+ phase: "module-inspection",
192
+ jdk_compiler: false,
193
+ stdout,
194
+ stderr,
195
+ output_truncated: false,
196
+ });
197
+ const major = /^java\.base@(\d+)(?:[.+_-]|$)/mu.exec(stdout)?.[1];
198
+ if (major === undefined)
199
+ throw configurationFailure("version_unresolved", `The selected Java launcher ${java} did not report a parseable java.base version in its module listing. Inspect the launcher output and verify it with java --list-modules.`, {
200
+ java_executable: java,
201
+ phase: "module-inspection",
202
+ jdk_compiler: true,
203
+ java_major: null,
204
+ stdout,
205
+ stderr,
206
+ output_truncated: false,
207
+ });
208
+ if (Number(major) < 17)
209
+ throw configurationFailure("unsupported_version", `Selected Java runtime ${java} must be JDK 17 or newer and include jdk.compiler; verify it with java --list-modules.`, {
210
+ java_executable: java,
211
+ phase: "module-inspection",
212
+ jdk_compiler: true,
213
+ java_major: major ?? null,
214
+ stdout,
215
+ stderr,
216
+ output_truncated: false,
217
+ });
57
218
  };
219
+ const configurationFailure = (code, message, diagnostics, cause) => new JadxConfigurationFailure(code, message, diagnostics, cause === undefined ? undefined : { cause });
220
+ const errorText = (cause) => cause instanceof Error ? cause.message : String(cause);
@@ -78,6 +78,10 @@ export class JadxMcpTransport {
78
78
  diagnostics() {
79
79
  return this.#supervisor?.snapshot().stderr.text ?? "";
80
80
  }
81
+ /** Whether the retained startup/operation diagnostics lost bytes. */
82
+ diagnosticsTruncated() {
83
+ return this.#supervisor?.snapshot().diagnosticTruncated ?? false;
84
+ }
81
85
  /** Preserve the failed protocol/resource constraint after the SDK closes requests. */
82
86
  failureReason() {
83
87
  return this.#failure;
@@ -2,6 +2,12 @@ import { z } from "zod";
2
2
  import { AnalysisOutputError } from "../domain/analysisErrorCore.js";
3
3
  import { jsonValueSchema } from "../domain/jsonValue.js";
4
4
  const count = z.number().int().nonnegative();
5
+ /** Selector failures authored by REA's bridge, separate from arbitrary engine errors. */
6
+ export const jadxInputFailureSchema = z.strictObject({
7
+ kind: z.literal("invalid-input"),
8
+ field: z.enum(["class_name", "method_name", "overload_index"]),
9
+ message: z.string().min(1),
10
+ });
5
11
  /** Values observed inside the exact JVM producing the analysis. */
6
12
  export const jadxRuntimeSchema = z.object({
7
13
  engine_reported_version: z.string().min(1),
@@ -9,7 +9,7 @@ import { ProviderCleanupError } from "../domain/providerCleanupError.js";
9
9
  import { err, ok } from "../domain/result.js";
10
10
  import { PrivateRuntimeRoot } from "../process/PrivateRuntimeRoot.js";
11
11
  import { snapshotAndroidEngine, hashAndroidFile, snapshotAndroidTarget, } from "./AndroidTargetSnapshot.js";
12
- import { resolveJadxConfiguration } from "./JadxConfiguration.js";
12
+ import { inspectJadxAvailability, resolveJadxConfiguration, } from "./JadxConfiguration.js";
13
13
  import { JadxSession } from "./JadxSession.js";
14
14
  const OPERATION_TIMEOUT_MS = 120_000;
15
15
  const BRIDGE_SOURCE = fileURLToPath(new URL("../../bridge/android/ReaJadxBridge.java", import.meta.url));
@@ -38,6 +38,19 @@ const executionError = (context) => {
38
38
  });
39
39
  if (cause instanceof z.ZodError)
40
40
  return new AnalysisOutputError(request.operation, "JADX response violated the pinned upstream protocol", { cause });
41
+ if (session !== undefined && !session.initialized()) {
42
+ const stderr = session.transport.diagnostics();
43
+ const reason = `Java could not start REA's Android bridge using ${session.transport.options.command}: ${cause instanceof Error ? cause.message : String(cause)}.${stderr.length === 0 ? "" : ` Java diagnostics: ${stderr}`} Select a full JDK including jdk.compiler via JAVA_HOME, or a working java on PATH; verify it with java --list-modules. A JRE cannot compile REA's source bridge. If the JDK works, verify the REA bridge and configured JADX JAR installation.`;
44
+ return new AnalysisCapabilityUnavailableError("jadx", request.operation, reason, {
45
+ cause,
46
+ userMessage: reason,
47
+ capturedOutput: {
48
+ stdout: "",
49
+ stderr,
50
+ truncated: session.transport.diagnosticsTruncated(),
51
+ },
52
+ });
53
+ }
41
54
  return new ProviderAdapterError("jadx", request.operation, {
42
55
  cause,
43
56
  diagnostics: {
@@ -93,6 +106,10 @@ export class JadxProvider {
93
106
  this.environment = environment;
94
107
  this.launcher = launcher;
95
108
  }
109
+ /** Report actual local prerequisites without starting JADX or opening a target. */
110
+ inspectAvailability(signal) {
111
+ return inspectJadxAvailability(this.environment, signal);
112
+ }
96
113
  /** Serialize expensive work and bind both raw and normalized results to the APK. */
97
114
  async execute(target, request, options) {
98
115
  if (this.#shutdown.signal.aborted)
@@ -165,7 +182,7 @@ export class JadxProvider {
165
182
  try {
166
183
  if (target.format !== "apk")
167
184
  throw new AnalysisCapabilityUnavailableError("jadx", request.operation, `Target ${target.path} is ${target.format}; provide one standalone APK.`);
168
- const configuration = await resolveJadxConfiguration(this.environment, request.operation);
185
+ const configuration = await resolveJadxConfiguration(this.environment, request.operation, signal);
169
186
  signal.throwIfAborted();
170
187
  const jarHash = await hashAndroidFile(configuration.jar);
171
188
  const bridgeHash = await hashAndroidFile(BRIDGE_SOURCE);
@@ -1,17 +1,18 @@
1
1
  import { Client } from "@modelcontextprotocol/client";
2
2
  import { createAnalysisExecution, } from "../application/AnalysisProvider.js";
3
- import { AnalysisCapabilityUnavailableError, AnalysisOutputError, } from "../domain/analysisErrorCore.js";
3
+ import { AnalysisCapabilityUnavailableError, AnalysisInputError, AnalysisOutputError, } from "../domain/analysisErrorCore.js";
4
4
  import { jsonValueSchema } from "../domain/jsonValue.js";
5
5
  import { ProviderAdapterError } from "../domain/providerAdapterError.js";
6
6
  import { analyzeJadxRequest } from "./JadxAnalysis.js";
7
7
  import { JadxMcpTransport } from "./JadxMcpTransport.js";
8
- import { jadxLoadSchema, jadxRuntimeSchema, parseJadxEnvelope, parseJadxJson, } from "./JadxProtocol.js";
8
+ import { jadxLoadSchema, jadxInputFailureSchema, jadxRuntimeSchema, parseJadxEnvelope, parseJadxJson, } from "./JadxProtocol.js";
9
9
  import { JADX_BRIDGE_IDENTITY, JADX_RELEASE, JADX_PROVIDER_IDENTITY, JADX_LIMITATIONS, } from "./JadxRelease.js";
10
10
  /** One owned engine connection; its wire protocol stays inside the Android adapter. */
11
11
  export class JadxSession {
12
12
  transport;
13
13
  #client = new Client({ name: "rea-android-adapter", version: "1" });
14
14
  #loaded;
15
+ #connected = false;
15
16
  constructor(options, launcher) {
16
17
  this.transport = new JadxMcpTransport(options, launcher);
17
18
  }
@@ -26,8 +27,10 @@ export class JadxSession {
26
27
  signal.throwIfAborted();
27
28
  this.transport.beginOperation();
28
29
  const raw = [];
29
- if (this.#loaded === undefined)
30
+ if (!this.#connected) {
30
31
  await this.#client.connect(this.transport, { timeout: 30_000 });
32
+ this.#connected = true;
33
+ }
31
34
  const server = this.#client.getServerVersion();
32
35
  if (server?.name !== JADX_BRIDGE_IDENTITY.name ||
33
36
  server.version !== JADX_BRIDGE_IDENTITY.version)
@@ -73,6 +76,10 @@ export class JadxSession {
73
76
  signal.removeEventListener("abort", abort);
74
77
  }
75
78
  }
79
+ /** Whether the selected Java runtime established the REA bridge protocol. */
80
+ initialized() {
81
+ return this.#connected;
82
+ }
76
83
  /** Join owned cleanup even if SDK connection teardown itself fails. */
77
84
  async close() {
78
85
  try {
@@ -92,7 +99,18 @@ export class JadxSession {
92
99
  input,
93
100
  response: jsonValueSchema.parse(response),
94
101
  });
95
- if (envelope.failed)
102
+ if (envelope.failed) {
103
+ if (envelope.text.startsWith("{")) {
104
+ const failure = jadxInputFailureSchema.safeParse(parseJadxJson(envelope.text, request.operation));
105
+ if (failure.success)
106
+ throw new AnalysisInputError(request.operation, undefined, [
107
+ {
108
+ path: [failure.data.field],
109
+ reason: "invalid_value",
110
+ message: failure.data.message,
111
+ },
112
+ ]);
113
+ }
96
114
  throw new ProviderAdapterError("jadx", request.operation, {
97
115
  diagnostics: {
98
116
  upstream_operation: name,
@@ -101,6 +119,7 @@ export class JadxSession {
101
119
  target_sha256: target.sha256,
102
120
  },
103
121
  });
122
+ }
104
123
  return envelope.text;
105
124
  };
106
125
  return {
@@ -1,6 +1,7 @@
1
- import { AnalysisCapabilityUnavailableError, AnalysisOutputError, } from "../domain/analysisErrorCore.js";
1
+ import { AnalysisOutputError } from "../domain/analysisErrorCore.js";
2
2
  import {} from "../domain/analysisErrorBase.js";
3
- import { parseDocuments } from "../domain/hopperValues.js";
3
+ import { analysisBookmarkSchema } from "../domain/hopperValues.js";
4
+ import { resolveAnalysisDocument } from "./AnalysisDocument.js";
4
5
  import { err, ok } from "../domain/result.js";
5
6
  const parameters = (document, address) => ({
6
7
  ...(document === undefined ? {} : { document }),
@@ -42,7 +43,7 @@ export const getNavigationContext = async (analysis, input, signal) => {
42
43
  };
43
44
  /** Inspect bounded provider-neutral facets at one explicit reproducible address. */
44
45
  export const inspectAddressContext = async (analysis, input, signal) => {
45
- const document = await resolveDocument(analysis, input.document, signal);
46
+ const document = await resolveAnalysisDocument(analysis, input.document, signal);
46
47
  if (!document.ok)
47
48
  return document;
48
49
  const args = parameters(document.value, input.address);
@@ -75,30 +76,6 @@ export const inspectAddressContext = async (analysis, input, signal) => {
75
76
  : bookmarks,
76
77
  });
77
78
  };
78
- const resolveDocument = async (analysis, document, signal) => {
79
- if (document !== undefined)
80
- return ok(document);
81
- const current = await analysis.execute("current_document", {}, executionOptions(signal));
82
- if (!current.ok) {
83
- if (!(current.error instanceof AnalysisCapabilityUnavailableError))
84
- return current;
85
- const listed = await analysis.execute("list_documents", {}, executionOptions(signal));
86
- if (!listed.ok)
87
- return listed;
88
- const parsed = parseDocuments(listed.value.result);
89
- if (!parsed.ok)
90
- return err(new AnalysisOutputError("list_documents", "expected one document identity when resolving a headless provider", { cause: parsed.error }));
91
- if (parsed.value.length !== 1)
92
- return err(new AnalysisOutputError("list_documents", `expected exactly one document identity for a provider without current-document selection, received ${parsed.value.length}`));
93
- const [documentName] = parsed.value;
94
- if (documentName === undefined)
95
- return err(new AnalysisOutputError("list_documents", "provider returned no document identity"));
96
- return ok(documentName);
97
- }
98
- return typeof current.value.result === "string"
99
- ? ok(current.value.result)
100
- : err(new AnalysisOutputError("current_document", "expected a document identity string"));
101
- };
102
79
  const facet = (result, operation) => result?.ok === true
103
80
  ? { state: "available", value: result.value.result }
104
81
  : {
@@ -139,19 +116,15 @@ const matchingBookmarks = (value, address) => {
139
116
  reason: "list_bookmarks returned malformed output; expected an array.",
140
117
  remediation: "Retry list_bookmarks directly and report the provider output shape if it remains malformed.",
141
118
  };
142
- if (!value.every(isBookmark))
119
+ const parsed = analysisBookmarkSchema.array().safeParse(value);
120
+ if (!parsed.success)
143
121
  return {
144
122
  state: "unavailable",
145
- reason: "list_bookmarks returned malformed entries; expected address and name strings.",
123
+ reason: "list_bookmarks returned malformed entries; expected an address string and a string or null name.",
146
124
  remediation: "Retry list_bookmarks directly and report the provider output shape if it remains malformed.",
147
125
  };
148
126
  return {
149
127
  state: "available",
150
- value: value.filter((bookmark) => bookmark.address === address),
128
+ value: parsed.data.filter((bookmark) => bookmark.address === address),
151
129
  };
152
130
  };
153
- const isBookmark = (value) => typeof value === "object" &&
154
- value !== null &&
155
- !Array.isArray(value) &&
156
- typeof value.address === "string" &&
157
- typeof value.name === "string";
@@ -0,0 +1,32 @@
1
+ import { AnalysisCancelledError, AnalysisCapabilityUnavailableError, AnalysisOutputError, } from "../domain/analysisErrorCore.js";
2
+ import { parseDocuments } from "../domain/hopperValues.js";
3
+ import { err, ok } from "../domain/result.js";
4
+ const executionOptions = (signal) => signal === undefined ? undefined : { signal };
5
+ /** Resolve an explicit or provider-selected document without guessing among candidates. */
6
+ export const resolveAnalysisDocument = async (analysis, document, signal) => {
7
+ if (document !== undefined)
8
+ return ok(document);
9
+ if (signal?.aborted === true)
10
+ return err(new AnalysisCancelledError("current_document"));
11
+ const current = await analysis.execute("current_document", {}, executionOptions(signal));
12
+ if (!current.ok) {
13
+ if (!(current.error instanceof AnalysisCapabilityUnavailableError))
14
+ return current;
15
+ const listed = await analysis.execute("list_documents", {}, executionOptions(signal));
16
+ if (!listed.ok)
17
+ return listed;
18
+ const parsed = parseDocuments(listed.value.result);
19
+ if (!parsed.ok)
20
+ return err(new AnalysisOutputError("list_documents", "expected one document identity when resolving a headless provider", { cause: parsed.error }));
21
+ if (parsed.value.length !== 1)
22
+ return err(new AnalysisOutputError("list_documents", `expected exactly one document identity for a provider without current-document selection, received ${parsed.value.length}`));
23
+ const [documentName] = parsed.value;
24
+ if (documentName === undefined || documentName.length === 0)
25
+ return err(new AnalysisOutputError("list_documents", "provider returned no document identity"));
26
+ return ok(documentName);
27
+ }
28
+ return typeof current.value.result === "string" &&
29
+ current.value.result.length > 0
30
+ ? ok(current.value.result)
31
+ : err(new AnalysisOutputError("current_document", "expected a nonempty document identity string"));
32
+ };