rea-agents 6.1.0 → 6.2.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 (453) hide show
  1. package/README.md +7 -5
  2. package/bridge/ghidra/ReaGhidraBridge.java +32 -4
  3. package/bridge/hopper_bridge.py +6 -1
  4. package/dist/android/JadxConfiguration.js +87 -7
  5. package/dist/android/JadxMcpTransport.js +14 -2
  6. package/dist/android/JadxProvider.js +57 -35
  7. package/dist/application/BinaryTargetResolver.js +5 -3
  8. package/dist/application/BrowserEvidence.js +3 -8
  9. package/dist/application/BrowserScenarioEvidence.js +2 -18
  10. package/dist/application/CapabilityInventory.js +43 -9
  11. package/dist/application/ClientConfigurationDocument.js +69 -25
  12. package/dist/application/DirectAnalysis.js +29 -14
  13. package/dist/application/DirectAnalysisCleanup.js +72 -0
  14. package/dist/application/DirectAnalysisStatus.js +4 -5
  15. package/dist/application/Doctor.js +15 -19
  16. package/dist/application/DoctorDiagnostics.js +1 -2
  17. package/dist/application/EnhancedTools.js +51 -6
  18. package/dist/application/EvidenceBundleFiles.js +8 -3
  19. package/dist/application/InvestigationProviders.js +9 -1
  20. package/dist/application/JsonFiles.js +42 -9
  21. package/dist/application/LinuxHopper.js +9 -6
  22. package/dist/application/MacHopper.js +15 -18
  23. package/dist/application/RealHopperAssertions.js +0 -11
  24. package/dist/application/ReconstructionObligationCandidates.js +1 -1
  25. package/dist/application/ReferenceSourceImportEntries.js +1 -1
  26. package/dist/application/Setup.js +8 -16
  27. package/dist/application/SetupHost.js +16 -27
  28. package/dist/application/SetupPlan.js +6 -6
  29. package/dist/application/Uninstall.js +81 -29
  30. package/dist/application/UpdateMaintenance.js +7 -5
  31. package/dist/application/UpdateRuntime.js +12 -12
  32. package/dist/application/WebScriptExportService.js +30 -4
  33. package/dist/application/WorkflowEvidence.js +25 -2
  34. package/dist/application/XrefsAddressResolution.js +45 -0
  35. package/dist/application/analysisView/AnalysisViewService.js +76 -0
  36. package/dist/application/binary/AnalysisClientCleanup.js +30 -5
  37. package/dist/application/binary/AnalysisProviderEvaluation.js +1 -2
  38. package/dist/application/binary/AnalysisProviderRegistry.js +2 -6
  39. package/dist/application/binary/AnalysisSnapshotCache.js +10 -8
  40. package/dist/application/binary/BinarySession.js +70 -29
  41. package/dist/application/binary/BinarySessionComposition.js +1 -3
  42. package/dist/application/binary/BinarySessionExecution.js +3 -5
  43. package/dist/application/binary/BinarySessionOpen.js +1 -1
  44. package/dist/application/binary/BinarySessionRecords.js +1 -1
  45. package/dist/application/binary/BinarySessionStatus.js +1 -6
  46. package/dist/application/binary/CompositeProvider.js +4 -18
  47. package/dist/application/binary/LazyAnalysisProvider.js +5 -5
  48. package/dist/application/binary/SessionProviderRouter.js +27 -135
  49. package/dist/application/homebrew.js +48 -0
  50. package/dist/application/javascript/ElectronActiveEvidence.js +9 -13
  51. package/dist/application/javascript/JavaScriptApplicationEvidence.js +2 -6
  52. package/dist/application/javascript/JavaScriptApplicationService.js +6 -1
  53. package/dist/application/javascript/JavaScriptArtifactAnalysis.js +5 -3
  54. package/dist/application/javascript/JavaScriptArtifactGraphBuilder.js +11 -9
  55. package/dist/application/javascript/JavaScriptArtifactGraphBundlers.js +11 -3
  56. package/dist/application/javascript/JavaScriptArtifactGraphContext.js +9 -0
  57. package/dist/application/javascript/JavaScriptArtifactGraphDocuments.js +8 -5
  58. package/dist/application/javascript/JavaScriptArtifactGraphFindings.js +12 -3
  59. package/dist/application/javascript/JavaScriptArtifactGraphStructure.js +0 -1
  60. package/dist/application/javascript/JavaScriptArtifactPathResolution.js +43 -16
  61. package/dist/application/javascript/JavaScriptArtifactReconstruction.js +46 -6
  62. package/dist/application/javascript/JavaScriptModuleRelationships.js +1 -1
  63. package/dist/application/javascript/JavaScriptRuntimeObservationService.js +3 -3
  64. package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +2 -3
  65. package/dist/application/javascript/JavaScriptSemanticGraphChildProcessProjection.js +1 -2
  66. package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +2 -3
  67. package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +1 -5
  68. package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +75 -46
  69. package/dist/application/javascript/JavaScriptSemanticGraphResourceProjection.js +2 -3
  70. package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +42 -19
  71. package/dist/application/managed/ManagedMemberComparisonService.js +2 -1
  72. package/dist/application/managed/ManagedNativeVerificationService.js +2 -1
  73. package/dist/application/process/ProcessCli.js +11 -11
  74. package/dist/application/process/ProcessEvidence.js +0 -1
  75. package/dist/artifacts/ArtifactProvider.js +39 -14
  76. package/dist/artifacts/ArtifactReader.js +31 -0
  77. package/dist/artifacts/DirectoryArtifactReader.js +2 -1
  78. package/dist/artifacts/MachOSliceArtifactReader.js +9 -2
  79. package/dist/artifacts/NativeDmgArtifactReader.js +65 -20
  80. package/dist/artifacts/SafeOutputTree.js +16 -2
  81. package/dist/artifacts/ZipArtifactReader.js +11 -4
  82. package/dist/artifacts/apple/AppleAssetCatalogAnalysis.js +4 -2
  83. package/dist/artifacts/apple/DylibResolutionReader.js +17 -7
  84. package/dist/artifacts/apple/KeyedArchiveReader.js +21 -3
  85. package/dist/artifacts/extraction/ArtifactExtraction.js +78 -21
  86. package/dist/artifacts/inventory/ArtifactGraphConstruction.js +67 -61
  87. package/dist/artifacts/inventory/ArtifactInventory.js +0 -1
  88. package/dist/artifacts/inventory/reader.js +3 -3
  89. package/dist/artifacts/inventory/scanCanonical.js +48 -24
  90. package/dist/artifacts/inventory/scanReader.js +5 -9
  91. package/dist/browser/BrowserScenarioPartialObservation.js +106 -0
  92. package/dist/browser/CdpBrowserProvider.js +2 -3
  93. package/dist/browser/CdpCaptureEventHandlers.js +2 -4
  94. package/dist/browser/CdpCaptureEvents.js +0 -1
  95. package/dist/browser/CdpCaptureValues.js +20 -0
  96. package/dist/browser/CdpElectronProvider.js +0 -2
  97. package/dist/browser/CdpElectronScriptEvents.js +2 -8
  98. package/dist/browser/CdpElectronScripts.js +2 -3
  99. package/dist/browser/CdpPageCaptureScripts.js +2 -3
  100. package/dist/browser/CdpSafeMetadata.js +10 -10
  101. package/dist/browser/PlaywrightBrowserScenarioProvider.js +59 -44
  102. package/dist/browser/PlaywrightElectronActiveActions.js +2 -56
  103. package/dist/browser/PlaywrightElectronActiveProvider.js +10 -6
  104. package/dist/browser/PlaywrightScenarioArtifacts.js +1 -1
  105. package/dist/browser/PlaywrightScenarioBrowser.js +139 -39
  106. package/dist/browser/PlaywrightScenarioEvents.js +1 -1
  107. package/dist/browser/PlaywrightScenarioSession.js +39 -22
  108. package/dist/browser/assets/ScriptCaptureAdapters.js +1 -1
  109. package/dist/browser/history/CaptureFailures.js +6 -2
  110. package/dist/browser/history/MitmproxyCaptureAdapter.js +4 -2
  111. package/dist/catalogIdentity.js +0 -1
  112. package/dist/cli/analysisViewCommands.js +36 -0
  113. package/dist/cli/artifactCommands.js +11 -12
  114. package/dist/cli/coreAnalysisCommands.js +3 -3
  115. package/dist/cli/coreBinaryCommands.js +32 -27
  116. package/dist/cli/coreNativeCommands.js +9 -10
  117. package/dist/cli/electronCommands.js +4 -4
  118. package/dist/cli/interactiveSetup.js +6 -6
  119. package/dist/cli/managedCommands.js +7 -8
  120. package/dist/cli/nativeCallCommands.js +1 -2
  121. package/dist/cli/omittableDefaults.js +50 -0
  122. package/dist/cli/processCommands.js +3 -2
  123. package/dist/cli/setupCommands.js +16 -15
  124. package/dist/cli/utilityCommands.js +9 -9
  125. package/dist/cli.js +16 -8
  126. package/dist/cliBrowserScenarioCommands.js +2 -2
  127. package/dist/cliCommandNames.js +1 -0
  128. package/dist/cliJsonInput.js +15 -1
  129. package/dist/cliOutput.js +0 -38
  130. package/dist/composition/auxiliaryAnalysisProviders.js +27 -23
  131. package/dist/composition/binary.js +9 -9
  132. package/dist/composition/browserScenario.js +2 -1
  133. package/dist/composition/directAnalysis.js +20 -13
  134. package/dist/composition/electronScenario.js +1 -1
  135. package/dist/composition/optionalObservationProviders.js +12 -7
  136. package/dist/config/environment.js +6 -0
  137. package/dist/config/ghidraStartupTimeout.js +4 -9
  138. package/dist/config/homeDirectory.js +12 -0
  139. package/dist/config/mcpResponseBudget.js +9 -1
  140. package/dist/config/parseConfig.js +7 -3
  141. package/dist/config/parsers.js +19 -22
  142. package/dist/contracts/analysisViewToolContracts.js +56 -0
  143. package/dist/contracts/applicationToolContracts.js +5 -4
  144. package/dist/contracts/artifactComparisonExample.js +2 -2
  145. package/dist/contracts/artifactToolContracts.js +1 -1
  146. package/dist/contracts/browserScenarioToolContracts.js +1 -1
  147. package/dist/contracts/browserToolContracts.js +19 -15
  148. package/dist/contracts/enhancedInputs.js +2 -2
  149. package/dist/contracts/enhancedToolContracts.js +4 -3
  150. package/dist/contracts/evm/evmToolContracts.js +1 -1
  151. package/dist/contracts/functionWorkflowToolContracts.js +1 -1
  152. package/dist/contracts/inputSchemaPresentation.js +90 -0
  153. package/dist/contracts/investigationExamples.js +4 -3
  154. package/dist/contracts/javascript/electronToolContracts.js +1 -1
  155. package/dist/contracts/javascript/javascriptApplicationWorkflowExamples.js +0 -20
  156. package/dist/contracts/javascript/javascriptExportShapeComparisonExample.js +245 -0
  157. package/dist/contracts/javascript/javascriptRuntimeObservationToolContracts.js +1 -1
  158. package/dist/contracts/managed/managedToolContracts.js +5 -10
  159. package/dist/contracts/managed/managedWorkflowToolContracts.js +1 -1
  160. package/dist/contracts/mobileApplicationGraphExamples.js +3 -3
  161. package/dist/contracts/native/binaryDiagnosticsToolContracts.js +1 -1
  162. package/dist/contracts/native/nativeToolContracts.js +2 -2
  163. package/dist/contracts/officialToolContracts.js +2 -1
  164. package/dist/contracts/promptContracts.js +2 -2
  165. package/dist/contracts/providerSelection.js +1 -1
  166. package/dist/contracts/sessionToolContracts.js +14 -2
  167. package/dist/contracts/sessionToolSchemas.js +1 -14
  168. package/dist/contracts/toolContracts.js +2 -0
  169. package/dist/contracts/toolEffects.js +1 -0
  170. package/dist/contracts/toolOutputSchemaGroups.js +136 -92
  171. package/dist/contracts/toolOutputSchemaPrimitives.js +11 -21
  172. package/dist/contracts/toolSchemaMetadata.js +18 -69
  173. package/dist/contracts/webNetworkCaptureToolContracts.js +1 -1
  174. package/dist/contracts/webRuntimeToolContracts.js +1 -1
  175. package/dist/contracts/webScriptToolContracts.js +1 -1
  176. package/dist/doctorRuntime.js +7 -5
  177. package/dist/domain/analysisErrorCore.js +3 -0
  178. package/dist/domain/analysisErrorPresentation.js +18 -3
  179. package/dist/domain/analysisErrorProjection.js +24 -5
  180. package/dist/domain/analysisSnapshot.js +29 -31
  181. package/dist/domain/analysisView/analysisView.js +243 -0
  182. package/dist/domain/analysisView/analysisViewCoverage.js +19 -0
  183. package/dist/domain/analysisView/binaryLayoutView.js +159 -0
  184. package/dist/domain/analysisView/javascriptApplicationView.js +238 -0
  185. package/dist/domain/android/androidApplication.js +1 -1
  186. package/dist/domain/apple/appleApplication.js +1 -1
  187. package/dist/domain/apple/dylibResolution.js +10 -3
  188. package/dist/domain/apple/interfaceBuilderGraph.js +0 -1
  189. package/dist/domain/apple/keyedArchive.js +26 -2
  190. package/dist/domain/artifactComparison.js +15 -6
  191. package/dist/domain/artifactGraph.js +16 -3
  192. package/dist/domain/artifactInventoryEvidence.js +9 -16
  193. package/dist/domain/artifactOperationError.js +3 -3
  194. package/dist/domain/artifactPartialObservation.js +1 -0
  195. package/dist/domain/artifactPathSyntax.js +49 -0
  196. package/dist/domain/binaryTarget.js +39 -13
  197. package/dist/domain/browserCaptureComparison.js +13 -49
  198. package/dist/domain/browserNetworkEvidence.js +10 -4
  199. package/dist/domain/browserObservation.js +0 -1
  200. package/dist/domain/browserObservationSchemas.js +14 -3
  201. package/dist/domain/browserScenario.js +0 -1
  202. package/dist/domain/browserScenarioCapture.js +1 -2
  203. package/dist/domain/browserScenarioDiff.js +0 -2
  204. package/dist/domain/browserScenarioDiffEvidence.js +0 -12
  205. package/dist/domain/browserScenarioDiffValues.js +2 -2
  206. package/dist/domain/browserScenarioValues.js +3 -4
  207. package/dist/domain/callPath.js +8 -9
  208. package/dist/domain/callPathSchemas.js +2 -2
  209. package/dist/domain/changedBehavior.js +3 -3
  210. package/dist/domain/completionLedgerGeneration.js +2 -1
  211. package/dist/domain/configurationErrors.js +12 -0
  212. package/dist/domain/conformancePackage.js +4 -3
  213. package/dist/domain/evidence.js +10 -36
  214. package/dist/domain/evidenceBundle.js +7 -9
  215. package/dist/domain/evidenceCompletionLedger.js +2 -1
  216. package/dist/domain/functionComparison.js +4 -5
  217. package/dist/domain/functionComparisonDimensions.js +120 -87
  218. package/dist/domain/functionComparisonNormalization.js +23 -34
  219. package/dist/domain/functionComparisonResults.js +1 -4
  220. package/dist/domain/functionComparisonSchemas.js +2 -8
  221. package/dist/domain/functionDossierEvidence.js +2 -37
  222. package/dist/domain/javascript/electronActiveObservation.js +26 -69
  223. package/dist/domain/javascript/electronObservation.js +14 -3
  224. package/dist/domain/javascript/electronStaticAnalysisBrowser.js +10 -9
  225. package/dist/domain/javascript/electronStaticAnalysisIpc.js +2 -1
  226. package/dist/domain/javascript/electronStaticAnalysisNative.js +2 -1
  227. package/dist/domain/javascript/javascriptApplicationEvidenceSchemas.js +2 -0
  228. package/dist/domain/javascript/javascriptApplicationGraph.js +26 -3
  229. package/dist/domain/javascript/javascriptApplicationGraphSchemas.js +9 -2
  230. package/dist/domain/javascript/javascriptApplicationVersionItems.js +5 -2
  231. package/dist/domain/javascript/javascriptApplicationVersionKeys.js +2 -1
  232. package/dist/{application/javascript/JavaScriptReturnShapeProjection.js → domain/javascript/javascriptExportReturnShapeProjection.js} +4 -4
  233. package/dist/domain/javascript/javascriptExportShapeComparison.js +7 -1
  234. package/dist/domain/javascript/javascriptExportShapeComparisonIdentity.js +6 -1
  235. package/dist/domain/javascript/javascriptExportShapeComparisonSchemas.js +29 -1
  236. package/dist/domain/javascript/javascriptExportShapeSelection.js +5 -5
  237. package/dist/domain/javascript/javascriptExportShapeVariants.js +67 -14
  238. package/dist/domain/javascript/javascriptFeatureSeed.js +20 -0
  239. package/dist/domain/javascript/javascriptFeatureTraversal.js +0 -1
  240. package/dist/domain/javascript/javascriptNativeHandoff.js +1 -1
  241. package/dist/domain/javascript/javascriptRuntimeLoadState.js +0 -1
  242. package/dist/domain/javascript/javascriptRuntimeObservation.js +10 -2
  243. package/dist/domain/javascript/javascriptRuntimeReconciliationMatching.js +1 -1
  244. package/dist/domain/javascript/javascriptRuntimeReconciliationParsing.js +3 -2
  245. package/dist/domain/javascript/javascriptRuntimeStaticCandidates.js +0 -1
  246. package/dist/domain/javascript/javascriptSemanticAnalysis.js +9 -3
  247. package/dist/domain/javascript/javascriptSemanticAsyncEffects.js +2 -1
  248. package/dist/domain/javascript/javascriptSemanticCalls.js +2 -1
  249. package/dist/domain/javascript/javascriptSemanticChildProcesses.js +2 -1
  250. package/dist/domain/javascript/javascriptSemanticDataEffects.js +1 -1
  251. package/dist/domain/javascript/javascriptSemanticGraph.js +88 -46
  252. package/dist/domain/javascript/javascriptSemanticMemberMutations.js +77 -20
  253. package/dist/domain/javascript/javascriptSemanticMutationValues.js +21 -27
  254. package/dist/domain/javascript/javascriptSemanticObjects.js +83 -42
  255. package/dist/domain/javascript/javascriptSemanticPrimitives.js +1 -12
  256. package/dist/domain/javascript/javascriptSemanticProjection.js +2 -3
  257. package/dist/domain/javascript/javascriptSemanticPromises.js +2 -1
  258. package/dist/domain/javascript/javascriptSemanticResourceLimits.js +1 -1
  259. package/dist/domain/javascript/javascriptSemanticResources.js +1 -1
  260. package/dist/domain/javascript/javascriptSemanticReturns.js +32 -17
  261. package/dist/domain/javascript/javascriptSemanticSlots.js +72 -0
  262. package/dist/domain/javascript/javascriptSemanticValues.js +47 -54
  263. package/dist/domain/javascript/javascriptSourceMapPaths.js +104 -0
  264. package/dist/domain/javascript/javascriptStaticAnalysisCalls.js +2 -1
  265. package/dist/domain/javascript/javascriptStaticAnalysisHelpers.js +0 -1
  266. package/dist/domain/javascript/sourceToBundleComparison.js +12 -3
  267. package/dist/domain/javascript/sourceToBundleSignals.js +47 -19
  268. package/dist/domain/localPath.js +1 -1
  269. package/dist/domain/managed/managedArtifact.js +6 -4
  270. package/dist/domain/managed/managedMemberComparison.js +2 -9
  271. package/dist/domain/managed/managedNativeVerification.js +0 -2
  272. package/dist/domain/managed/managedNativeVerificationMatch.js +9 -3
  273. package/dist/domain/native/binaryLayout.js +2 -3
  274. package/dist/domain/native/nativeApiBoundary.js +1 -1
  275. package/dist/domain/native/nativeCallObservation.js +5 -3
  276. package/dist/domain/native/nativeInstruction.js +7 -0
  277. package/dist/domain/native/recordedCrash.js +2 -3
  278. package/dist/domain/offsetDateTime.js +17 -0
  279. package/dist/domain/process/processCapture.js +13 -12
  280. package/dist/domain/process/processCaptureCoverage.js +67 -0
  281. package/dist/domain/process/processCaptureExample.js +2 -1
  282. package/dist/domain/process/processCaptureParsing.js +1 -34
  283. package/dist/domain/process/processCaptureValidation.js +81 -13
  284. package/dist/domain/process/processComparison.js +41 -22
  285. package/dist/domain/process/processObservation.js +10 -2
  286. package/dist/domain/process/processScenario.js +24 -2
  287. package/dist/domain/process/processTraceComparison.js +0 -2
  288. package/dist/domain/process/processTraceDimensionProjection.js +1 -1
  289. package/dist/domain/process/processTraceEvaluation.js +15 -11
  290. package/dist/domain/process/processTraceSpecification.js +3 -4
  291. package/dist/domain/providerAdapterError.js +2 -0
  292. package/dist/domain/reconstructionCoverage.js +5 -2
  293. package/dist/domain/reconstructionObligationLedgerSchemas.js +2 -1
  294. package/dist/domain/reconstructionReadinessSchemas.js +2 -1
  295. package/dist/domain/reconstructionVerification.js +3 -3
  296. package/dist/domain/reconstructionVerificationSchemas.js +2 -1
  297. package/dist/domain/referenceSourceGraph.js +20 -21
  298. package/dist/domain/staticRuntimeCorrelation.js +2 -2
  299. package/dist/domain/stringPatterns.js +6 -0
  300. package/dist/domain/swiftSymbolClassification.js +61 -0
  301. package/dist/domain/symbolAnalysis.js +66 -18
  302. package/dist/domain/webCaptureDiff.js +0 -1
  303. package/dist/domain/webCaptureDiffSchemas.js +6 -3
  304. package/dist/domain/webEventListeners.js +3 -2
  305. package/dist/domain/webExecution.js +3 -2
  306. package/dist/domain/webRuntime.js +0 -2
  307. package/dist/domain/webScriptExport.js +1 -1
  308. package/dist/dotnet/ManagedArtifactInspector.js +2 -19
  309. package/dist/dotnet/ManagedMemberInspector.js +12 -18
  310. package/dist/dotnet/ManagedMemberInspectorCore.js +47 -44
  311. package/dist/dotnet/ManagedMemberRows.js +75 -62
  312. package/dist/dotnet/ManagedMetadataInventory.js +16 -22
  313. package/dist/dotnet/ManagedMethodBodyReader.js +4 -0
  314. package/dist/dotnet/ManagedNativeBoundaryHelpers.js +109 -94
  315. package/dist/dotnet/ManagedNativeBoundaryInspector.js +12 -21
  316. package/dist/dotnet/ManagedReaderFailure.js +16 -0
  317. package/dist/dotnet/ManagedStaticProvider.js +3 -5
  318. package/dist/evaluation/AgentEvaluationFixtures.js +250 -0
  319. package/dist/evaluation/AgentEvaluationReport.js +28 -0
  320. package/dist/evaluation/CodexAgentEval.js +12 -8
  321. package/dist/evaluation/KnownAnswerEvaluation.js +281 -0
  322. package/dist/evm/EvmoleInterfaceProvider.js +2 -1
  323. package/dist/firmware/FirmwareCommand.js +9 -5
  324. package/dist/firmware/FirmwareProvider.js +4 -4
  325. package/dist/generatedPackageMetadata.js +2 -2
  326. package/dist/ghidra/GhidraAnalysisProfile.js +3 -6
  327. package/dist/ghidra/GhidraClient.js +91 -32
  328. package/dist/ghidra/GhidraClientStartup.js +0 -2
  329. package/dist/ghidra/GhidraDoctor.js +6 -5
  330. package/dist/ghidra/GhidraFunctionValues.js +3 -5
  331. package/dist/ghidra/GhidraInstallation.js +40 -12
  332. package/dist/ghidra/GhidraJavaLaunch.js +6 -2
  333. package/dist/ghidra/GhidraLauncher.js +15 -7
  334. package/dist/ghidra/GhidraProvider.js +6 -2
  335. package/dist/ghidra/GhidraProviderCapabilities.js +6 -0
  336. package/dist/ghidra/GhidraProviderClient.js +13 -3
  337. package/dist/ghidra/GhidraSessionError.js +2 -0
  338. package/dist/ghidra/GhidraSessionRoot.js +39 -0
  339. package/dist/ghidra/extensions/GhidraExtensions.js +17 -10
  340. package/dist/ghidra/extensions/nativeaot/NativeAotAdapter.js +8 -2
  341. package/dist/hopper/BridgeLauncher.js +34 -45
  342. package/dist/hopper/HopperAnalysisProfile.js +3 -8
  343. package/dist/hopper/HopperCleanup.js +56 -27
  344. package/dist/hopper/HopperClient.js +86 -65
  345. package/dist/hopper/HopperMachOImage.js +3 -2
  346. package/dist/hopper/HopperProvider.js +16 -18
  347. package/dist/hopper/HopperRegexSearch.js +3 -6
  348. package/dist/hopper/HopperTargetLease.js +132 -49
  349. package/dist/hopper/LinuxPrivateDisplayProbe.js +6 -0
  350. package/dist/ida/IdaConfiguration.js +8 -3
  351. package/dist/ida/IdaInput.js +1 -7
  352. package/dist/ida/IdaMcpConnection.js +8 -4
  353. package/dist/ida/IdaOperationRunner.js +3 -3
  354. package/dist/ida/IdaProvider.js +8 -12
  355. package/dist/ida/IdaSessionClient.js +20 -18
  356. package/dist/ida/IdaWorkspace.js +12 -13
  357. package/dist/inspector/V8InspectorCaptureProjection.js +1 -1
  358. package/dist/inspector/V8InspectorProvider.js +38 -28
  359. package/dist/javascript/recovery/WakaruCommand.js +7 -2
  360. package/dist/javascript/recovery/WakaruExecution.js +5 -2
  361. package/dist/main/shutdown.js +11 -3
  362. package/dist/main/startup.js +9 -2
  363. package/dist/main/transport.js +22 -2
  364. package/dist/main.js +11 -18
  365. package/dist/native/AppleMachoSelection.js +16 -6
  366. package/dist/native/CommandRunner.js +9 -7
  367. package/dist/native/LldbCallTracer.js +8 -2
  368. package/dist/native/NativeMacOSProvider.js +25 -15
  369. package/dist/native/NativeUiHelperRuntime.js +11 -2
  370. package/dist/native/NativeUiObservation.js +2 -2
  371. package/dist/native/pwntools/PwntoolsDecoder.js +2 -1
  372. package/dist/process/DarwinProcessRunTokenReader.js +16 -2
  373. package/dist/process/ExecFileOutput.js +88 -6
  374. package/dist/process/PrivateRuntimeRoot.js +10 -5
  375. package/dist/process/ProcessOwnership.js +1 -4
  376. package/dist/process/ProcessOwnershipObservation.js +11 -5
  377. package/dist/process/ProviderProcess.js +1 -3
  378. package/dist/process/capture/FilesystemSnapshot.js +50 -13
  379. package/dist/process/capture/ProcessCaptureError.js +13 -0
  380. package/dist/process/capture/ProcessCaptureLifecycle.js +158 -70
  381. package/dist/process/capture/ProcessFilesystemEffects.js +33 -3
  382. package/dist/process/capture/ProcessHarness.js +21 -25
  383. package/dist/process/capture/ProcessNormalization.js +20 -2
  384. package/dist/process/capture/ProcessSampling.js +25 -2
  385. package/dist/process/capture/TerminalRenderer.js +14 -0
  386. package/dist/process/snapshotEnvironment.js +14 -0
  387. package/dist/server/EvidenceMcpServer.js +25 -14
  388. package/dist/server/createServer.js +49 -36
  389. package/dist/server/mcpClientMetadata.js +12 -5
  390. package/dist/server/promptCompletion.js +3 -8
  391. package/dist/server/registerAnalysisViewTool.js +15 -0
  392. package/dist/server/registerAndroidTools.js +2 -3
  393. package/dist/server/registerApplicationTools/compareExportShapes.js +4 -5
  394. package/dist/server/registerApplicationTools/compareSourceToBundle.js +4 -5
  395. package/dist/server/registerApplicationTools/compareVersions.js +4 -5
  396. package/dist/server/registerApplicationTools/coverage.js +1 -2
  397. package/dist/server/registerApplicationTools/helpers.js +1 -2
  398. package/dist/server/registerApplicationTools/obligationLedger.js +4 -5
  399. package/dist/server/registerApplicationTools/projectMobileApplicationGraph.js +3 -4
  400. package/dist/server/registerApplicationTools/traceFeature.js +4 -5
  401. package/dist/server/registerApplicationTools/traceSemantics.js +4 -5
  402. package/dist/server/registerArtifactComparisonTool.js +4 -5
  403. package/dist/server/registerBinaryDiagnosticsTools.js +2 -3
  404. package/dist/server/registerBrowserScenarioTool.js +3 -4
  405. package/dist/server/registerBrowserTools.js +13 -16
  406. package/dist/server/registerBundleComparisonTool.js +5 -6
  407. package/dist/server/registerCloseLifecycleTool.js +2 -3
  408. package/dist/server/registerElectronTools.js +10 -13
  409. package/dist/server/registerEnhancedTools.js +23 -23
  410. package/dist/server/registerEvidenceTools.js +3 -4
  411. package/dist/server/registerEvmTools.js +2 -3
  412. package/dist/server/registerFirmwareTools.js +2 -3
  413. package/dist/server/registerFunctionComparisonTool.js +7 -8
  414. package/dist/server/registerInvestigationTools.js +14 -15
  415. package/dist/server/registerJavaScriptRecoveryTool.js +2 -3
  416. package/dist/server/registerJavaScriptRuntimeObservationTools.js +6 -6
  417. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +5 -6
  418. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +4 -5
  419. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +6 -7
  420. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +6 -7
  421. package/dist/server/registerOfficialTools.js +4 -19
  422. package/dist/server/registerProcessComparisonTool.js +8 -8
  423. package/dist/server/registerRecordedCrashTools.js +2 -3
  424. package/dist/server/registerSessionRecordTools.js +15 -19
  425. package/dist/server/registerSessionStatusTool.js +3 -4
  426. package/dist/server/registerSessionTools.js +12 -18
  427. package/dist/server/registerWebModuleTool.js +2 -3
  428. package/dist/server/registerWebNetworkCaptureTool.js +2 -3
  429. package/dist/server/registerWebRuntimeTools.js +4 -5
  430. package/dist/server/registerWebScriptTool.js +2 -3
  431. package/dist/server/registerWebSourceLocationTool.js +2 -3
  432. package/dist/server/toolResult.js +66 -94
  433. package/dist/server/toolResultEncoding.js +11 -10
  434. package/dist/windows/WindowsNativeLoader.js +1 -0
  435. package/dist/windows/WindowsOwnedProcess.js +60 -15
  436. package/dist/windows/WindowsPrivateRuntime.js +7 -8
  437. package/native/windows/README.md +3 -1
  438. package/native/windows/build/manifest.json +2 -2
  439. package/native/windows/build/rea-windows-x64.node +0 -0
  440. package/package.json +39 -30
  441. package/scripts/rea.mjs +3 -6
  442. package/skills/reverse-engineer-anything/SKILL.md +9 -8
  443. package/skills/reverse-engineer-anything/references/android-applications.md +6 -3
  444. package/skills/reverse-engineer-anything/references/evidence-workflows.md +8 -4
  445. package/skills/reverse-engineer-anything/references/javascript-applications.md +16 -6
  446. package/skills/reverse-engineer-anything/references/native-and-artifacts.md +9 -0
  447. package/dist/config.js +0 -1
  448. package/dist/contracts/browserCaptureToolInputSchema.js +0 -43
  449. package/dist/contracts/process/processCaptureExample.js +0 -2
  450. package/dist/contracts/toolOutputSchemas.js +0 -2
  451. package/dist/main/reload.js +0 -12
  452. package/dist/main/state.js +0 -3
  453. package/dist/server/sessionToolPolicies.js +0 -2
@@ -1,5 +1,6 @@
1
1
  import { randomBytes, randomUUID } from "node:crypto";
2
- import { tmpdir } from "node:os";
2
+ import { AnalysisError } from "../domain/analysisErrorBase.js";
3
+ import { ProviderCleanupError } from "../domain/providerCleanupError.js";
3
4
  import { err, ok } from "../domain/result.js";
4
5
  import { silentLogger } from "../logger.js";
5
6
  import { PendingOperations } from "../process/PendingOperations.js";
@@ -20,8 +21,9 @@ import { connectGhidraSocket } from "./GhidraSocketConnection.js";
20
21
  import { createGhidraEndpoint, } from "./GhidraTransport.js";
21
22
  import { GhidraWire } from "./GhidraClientWire.js";
22
23
  import { completeGhidraStartupHandshake } from "./GhidraClientStartup.js";
24
+ import { ghidraSessionRoot } from "./GhidraSessionRoot.js";
23
25
  const SHUTDOWN_TIMEOUT_MS = 10_000;
24
- const SESSION_ROOT = tmpdir();
26
+ const SESSION_ROOT = ghidraSessionRoot();
25
27
  /** Owns an authenticated private Ghidra session with transport-bound mutation authority. */
26
28
  export class GhidraClient {
27
29
  #options;
@@ -91,10 +93,12 @@ export class GhidraClient {
91
93
  /** Launch Ghidra once and require its exact post-analysis handshake. */
92
94
  start(signal) {
93
95
  if (this.#closePromise !== undefined)
94
- return this.#closePromise.then(() => this.start(signal));
96
+ return this.#closePromise.then(() => this.start(signal), (cause) => err(new GhidraSessionError("process", "Ghidra cleanup remains incomplete", this.#diagnostics(), { cause, cleanupFailure: this.#cleanupError(cause) })));
95
97
  if (this.#startPromise !== undefined) {
96
98
  if (this.#startupController?.signal.aborted && !signal?.aborted)
97
- return this.#startPromise.then((result) => result.ok ? result : this.start(signal));
99
+ return this.#startPromise.then((result) => result.ok || result.error.cleanupFailure !== undefined
100
+ ? result
101
+ : this.start(signal));
98
102
  return this.#startPromise;
99
103
  }
100
104
  const controller = new AbortController();
@@ -153,8 +157,43 @@ export class GhidraClient {
153
157
  }
154
158
  }
155
159
  /** Stop the owned process group and remove all project/runtime artifacts. */
156
- close() {
157
- return this.#requestClose(false);
160
+ async close() {
161
+ try {
162
+ await this.#requestClose(false);
163
+ return ok(null);
164
+ }
165
+ catch (cause) {
166
+ return err(this.#cleanupError(cause));
167
+ }
168
+ }
169
+ #cleanupError(cause) {
170
+ if (cause instanceof AnalysisError && cause.cleanupIncomplete)
171
+ return cause;
172
+ return new ProviderCleanupError("ghidra", [
173
+ ...(this.#process === undefined ? [] : ["ghidra-process"]),
174
+ ...[this.#runtimeRoot, this.#socketRoot].flatMap((root) => root === undefined ? [] : [root.path]),
175
+ ], {
176
+ reason: cause instanceof Error ? cause.message : String(cause),
177
+ diagnostics: this.#diagnostics(),
178
+ }, { cause });
179
+ }
180
+ async #startupFailure(primary) {
181
+ try {
182
+ await this.#cleanup();
183
+ return err(primary);
184
+ }
185
+ catch (cause) {
186
+ return err(new GhidraSessionError(primary.kind, primary.message, primary.diagnostics, {
187
+ ...(primary.cause === undefined ? {} : { cause: primary.cause }),
188
+ ...(primary.timeoutMs === undefined
189
+ ? {}
190
+ : { timeoutMs: primary.timeoutMs }),
191
+ ...(primary.remoteCode === undefined
192
+ ? {}
193
+ : { remoteCode: primary.remoteCode }),
194
+ cleanupFailure: this.#cleanupError(cause),
195
+ }));
196
+ }
158
197
  }
159
198
  #requestClose(forceStop) {
160
199
  const starting = this.#startPromise;
@@ -218,8 +257,7 @@ export class GhidraClient {
218
257
  }
219
258
  catch (cause) {
220
259
  const failure = this.#failure("start", "Ghidra private endpoint allocation failed", cause);
221
- await this.#cleanup();
222
- return err(failure);
260
+ return this.#startupFailure(failure);
223
261
  }
224
262
  try {
225
263
  const snapshot = await createGhidraTargetSnapshot(this.#options.targetPath, this.#runtimeRoot.path, this.#options.targetSha256, { signal: deadline.signal, platform: this.#options.platform });
@@ -230,8 +268,7 @@ export class GhidraClient {
230
268
  if (deadline.signal.aborted)
231
269
  return this.#startupInterrupted(deadline);
232
270
  const failure = this.#failure("start", "Ghidra target snapshot failed admission", cause);
233
- await this.#cleanup();
234
- return err(failure);
271
+ return this.#startupFailure(failure);
235
272
  }
236
273
  if (deadline.signal.aborted)
237
274
  return this.#startupInterrupted(deadline);
@@ -258,8 +295,7 @@ export class GhidraClient {
258
295
  : launched.error instanceof GhidraSessionError
259
296
  ? launched.error
260
297
  : this.#failure("start", launched.error.message, launched.error);
261
- await this.#cleanup();
262
- return err(failure);
298
+ return this.#startupFailure(failure);
263
299
  }
264
300
  this.#launch = launched.value;
265
301
  this.#process = new ProviderProcessSupervisor(launched.value, {
@@ -268,21 +304,19 @@ export class GhidraClient {
268
304
  const connected = await this.#connect(endpoint, deadline);
269
305
  if (!connected.ok) {
270
306
  const failure = connected.error;
271
- await this.#cleanup();
272
- return err(failure);
307
+ return this.#startupFailure(failure);
273
308
  }
274
309
  const completed = await completeGhidraStartupHandshake({
275
310
  deadline,
276
311
  request: (method, params, requestOptions) => this.#wire.request(method, params, requestOptions),
277
312
  parseSessionInfo: (value) => this.#parseSessionInfo(value),
278
- cleanup: () => this.#cleanup(),
279
313
  failure: this.#failure,
280
314
  startupTimeoutMs: this.#options.startupTimeoutMs,
281
315
  });
282
- if (completed.ok) {
283
- await this.#lineage.observe(this.#launch);
284
- this.#requestQueue.reopen();
285
- }
316
+ if (!completed.ok)
317
+ return this.#startupFailure(completed.error);
318
+ await this.#lineage.observe(this.#launch);
319
+ this.#requestQueue.reopen();
286
320
  return completed;
287
321
  }
288
322
  async #connect(endpoint, deadline) {
@@ -389,18 +423,8 @@ export class GhidraClient {
389
423
  this.#lastDiagnostics = this.#diagnostics();
390
424
  this.#process = undefined;
391
425
  this.#launch = undefined;
392
- const runtimeRoot = this.#runtimeRoot;
393
- const socketRoot = this.#socketRoot;
394
- this.#runtimeRoot = undefined;
395
- this.#socketRoot = undefined;
396
426
  try {
397
- const removed = await Promise.allSettled([
398
- runtimeRoot?.close(),
399
- socketRoot?.close(),
400
- ]);
401
- const failed = removed.find((result) => result.status === "rejected");
402
- if (failed?.status === "rejected")
403
- throw failed.reason;
427
+ await this.#removeRuntimeRoots();
404
428
  }
405
429
  catch (cause) {
406
430
  if (forceStop)
@@ -420,6 +444,42 @@ export class GhidraClient {
420
444
  this.#closing = false;
421
445
  }
422
446
  }
447
+ /**
448
+ * Remove the runtime and socket roots, keeping each one that could not be
449
+ * removed so a later close retries it rather than reporting success.
450
+ */
451
+ async #removeRuntimeRoots() {
452
+ const roots = [
453
+ {
454
+ root: this.#runtimeRoot,
455
+ release: () => (this.#runtimeRoot = undefined),
456
+ },
457
+ { root: this.#socketRoot, release: () => (this.#socketRoot = undefined) },
458
+ ];
459
+ const leftovers = [];
460
+ let firstCause;
461
+ for (const { root, release } of roots) {
462
+ if (root === undefined)
463
+ continue;
464
+ try {
465
+ await root.close();
466
+ release();
467
+ }
468
+ catch (cause) {
469
+ firstCause ??= cause;
470
+ leftovers.push({
471
+ path: root.path,
472
+ reason: cause instanceof Error ? cause.message : String(cause),
473
+ });
474
+ }
475
+ }
476
+ if (leftovers.length > 0)
477
+ throw new ProviderCleanupError("ghidra", leftovers.map(({ path }) => path), {
478
+ reason: "Ghidra's private runtime directory could not be removed; it is retained for a later close.",
479
+ leftover_paths: leftovers.map(({ path }) => path),
480
+ failures: leftovers.map(({ path, reason }) => `${path}: ${reason}`),
481
+ }, { cause: firstCause });
482
+ }
423
483
  #redactAuthentication(value) {
424
484
  for (const token of this.#authenticationTokens)
425
485
  value = value.replaceAll(token, "[REDACTED]");
@@ -457,8 +517,7 @@ export class GhidraClient {
457
517
  }
458
518
  async #startupInterrupted(deadline) {
459
519
  const failure = this.#interruptionFailure(deadline);
460
- await this.#cleanup();
461
- return err(failure);
520
+ return this.#startupFailure(failure);
462
521
  }
463
522
  #interruptionFailure(deadline) {
464
523
  return deadline.interruption === "cancelled"
@@ -9,7 +9,6 @@ export async function completeGhidraStartupHandshake(options) {
9
9
  const failure = options.deadline.signal.aborted
10
10
  ? interruptionFailure(options)
11
11
  : ping.error;
12
- await options.cleanup();
13
12
  return err(failure);
14
13
  }
15
14
  const parsed = options.parseSessionInfo(ping.value);
@@ -17,7 +16,6 @@ export async function completeGhidraStartupHandshake(options) {
17
16
  const failure = parsed.ok
18
17
  ? options.failure("analysis_timeout", "Ghidra auto-analysis reached its per-file deadline")
19
18
  : parsed.error;
20
- await options.cleanup();
21
19
  return err(failure);
22
20
  }
23
21
  return parsed;
@@ -38,13 +38,14 @@ export const projectGhidraDoctorInspection = (inspection) => {
38
38
  };
39
39
  };
40
40
  /** Inspect the process-configured BYO Ghidra installation for `rea doctor`. */
41
- export const inspectSystemGhidraProvider = () => Promise.resolve(projectGhidraDoctorInspection(inspectGhidraInstallation({
42
- ...(process.env.GHIDRA_INSTALL_DIR === undefined
41
+ export const inspectSystemGhidraProvider = (environment) => Promise.resolve(projectGhidraDoctorInspection(inspectGhidraInstallation({
42
+ environment,
43
+ ...(environment.GHIDRA_INSTALL_DIR === undefined
43
44
  ? {}
44
- : { installDir: process.env.GHIDRA_INSTALL_DIR }),
45
- ...(process.env.JAVA_HOME === undefined
45
+ : { installDir: environment.GHIDRA_INSTALL_DIR }),
46
+ ...(environment.JAVA_HOME === undefined
46
47
  ? {}
47
- : { javaHome: process.env.JAVA_HOME }),
48
+ : { javaHome: environment.JAVA_HOME }),
48
49
  })));
49
50
  const selectedChecks = (inspection) => {
50
51
  const byName = new Map(inspection.checks.map((candidate) => [candidate.name, candidate]));
@@ -112,13 +112,11 @@ const procedureReferences = z
112
112
  procedure: procedureIdentity,
113
113
  direction: z.enum(["incoming", "outgoing"]),
114
114
  references: z.array(referenceEdge),
115
- reference_kinds_available: z.boolean().default(true),
116
- unresolved_calls: z
117
- .array(z.strictObject({
115
+ reference_kinds_available: z.boolean(),
116
+ unresolved_calls: z.array(z.strictObject({
118
117
  address: ghidraCanonicalAddressSchema,
119
118
  reason: z.string(),
120
- }))
121
- .default([]),
119
+ })),
122
120
  })
123
121
  .strict();
124
122
  const procedureInfo = z
@@ -1,9 +1,9 @@
1
+ import { snapshotEnvironment } from "../process/snapshotEnvironment.js";
1
2
  import { spawnSync } from "node:child_process";
2
3
  import { constants } from "node:fs";
3
4
  import { accessSync, readFileSync } from "node:fs";
4
5
  import { posix, win32 } from "node:path";
5
6
  import { ghidraApplicationProperties, ghidraJavaMajorAccepted, ghidraJavaRangeLabel, ghidraJavaRequirement, ghidraReleaseAccepted, ghidraReleaseCompatibility, ghidraReleaseLine, ghidraVersionDetail, SUPPORTED_GHIDRA_JAVA_MAJOR, SUPPORTED_GHIDRA_VERSION, } from "./GhidraInstallationPolicy.js";
6
- export { SUPPORTED_GHIDRA_JAVA_MAJOR, SUPPORTED_GHIDRA_VERSION };
7
7
  const NATIVE_PLATFORMS = {
8
8
  linux: { x64: "linux_x86_64", arm64: "linux_arm_64" },
9
9
  darwin: { x64: "mac_x86_64", arm64: "mac_arm_64" },
@@ -97,17 +97,15 @@ const installationCoordinates = (options, platform, architecture, host) => {
97
97
  ? undefined
98
98
  : ghidraApplicationProperties(properties),
99
99
  javaCommand,
100
- java: host.probeJava(javaCommand, ghidraJavaEnvironment(options.javaHome, process.env, platform)),
100
+ // The configuration check rejects a relative JAVA_HOME. Probing it would
101
+ // run whatever `bin/java` the current directory holds.
102
+ java: options.javaHome === undefined || path.isAbsolute(options.javaHome)
103
+ ? host.probeJava(javaCommand, ghidraJavaEnvironment(options.javaHome, options.environment, platform))
104
+ : undefined,
101
105
  };
102
106
  };
103
107
  const installationChecks = ({ coordinates, platform, architecture, javaHome, host, }) => [
104
- installationCheck({
105
- name: "configuration",
106
- passed: coordinates.installDir !== null,
107
- code: "not_configured",
108
- detail: coordinates.installDir ?? "GHIDRA_INSTALL_DIR is not set",
109
- remediation: `Set GHIDRA_INSTALL_DIR to an extracted Ghidra ${ghidraReleaseLine()} release directory.`,
110
- }),
108
+ configurationCheck(coordinates.installDir, javaHome, platform),
111
109
  installationCheck({
112
110
  name: "platform",
113
111
  passed: NATIVE_PLATFORMS[platform] !== undefined,
@@ -149,6 +147,35 @@ const installationChecks = ({ coordinates, platform, architecture, javaHome, hos
149
147
  }),
150
148
  javaCheck(coordinates.java, coordinates.javaCommand, javaHome, coordinates.properties),
151
149
  ];
150
+ /**
151
+ * REA's configuration parser, and so the MCP server and analysis, accept only
152
+ * absolute paths; a relative one that happens to resolve here must not pass.
153
+ */
154
+ const configurationCheck = (installDir, javaHome, platform) => {
155
+ const { isAbsolute } = platform === "win32" ? win32 : posix;
156
+ const relative = [
157
+ ...(installDir !== null && !isAbsolute(installDir)
158
+ ? ["GHIDRA_INSTALL_DIR"]
159
+ : []),
160
+ ...(javaHome !== undefined && !isAbsolute(javaHome) ? ["JAVA_HOME"] : []),
161
+ ];
162
+ if (installDir === null || relative.length === 0)
163
+ return installationCheck({
164
+ name: "configuration",
165
+ passed: installDir !== null,
166
+ code: "not_configured",
167
+ detail: installDir ?? "GHIDRA_INSTALL_DIR is not set",
168
+ remediation: `Set GHIDRA_INSTALL_DIR to an extracted Ghidra ${ghidraReleaseLine()} release directory.`,
169
+ });
170
+ const settings = relative.join(" and ");
171
+ return installationCheck({
172
+ name: "configuration",
173
+ passed: false,
174
+ code: "not_configured",
175
+ detail: `${settings} must be absolute`,
176
+ remediation: `Set ${settings} to ${relative.length === 1 ? "an absolute path" : "absolute paths"}. REA's analysis and MCP server reject relative paths even when they resolve from the current directory.`,
177
+ });
178
+ };
152
179
  /** Project an installation probe into caller-visible, secret-free diagnostics. */
153
180
  export const ghidraInstallationDiagnostics = (inspection) => ({
154
181
  install_dir: inspection.installDir,
@@ -169,9 +196,10 @@ export const ghidraInstallationDiagnostics = (inspection) => ({
169
196
  })),
170
197
  });
171
198
  /** Environment that makes an explicitly selected JDK win over PATH discovery. */
172
- export const ghidraJavaEnvironment = (javaHome, environment = process.env, platform = process.platform) => {
199
+ export const ghidraJavaEnvironment = (javaHome, environment, platform = process.platform) => {
200
+ const selectedEnvironment = snapshotEnvironment(environment, platform);
173
201
  const boundedEnvironment = {
174
- ...environment,
202
+ ...selectedEnvironment,
175
203
  _JAVA_OPTIONS: "",
176
204
  JAVA_TOOL_OPTIONS: "",
177
205
  JDK_JAVA_OPTIONS: "",
@@ -182,7 +210,7 @@ export const ghidraJavaEnvironment = (javaHome, environment = process.env, platf
182
210
  : {
183
211
  ...boundedEnvironment,
184
212
  JAVA_HOME: javaHome,
185
- PATH: `${(platform === "win32" ? win32 : posix).join(javaHome, "bin")}${platform === "win32" ? win32.delimiter : posix.delimiter}${environment.PATH ?? ""}`,
213
+ PATH: `${(platform === "win32" ? win32 : posix).join(javaHome, "bin")}${platform === "win32" ? win32.delimiter : posix.delimiter}${selectedEnvironment.PATH ?? ""}`,
186
214
  };
187
215
  };
188
216
  const installationCheck = (options) => options.passed
@@ -1,3 +1,4 @@
1
+ import { snapshotEnvironment } from "../process/snapshotEnvironment.js";
1
2
  import { dirname, join } from "node:path";
2
3
  import { execFileOutput } from "../process/ExecFileOutput.js";
3
4
  /** Launch coordinates obtained from Ghidra's own release configuration helper. */
@@ -16,7 +17,9 @@ export const ghidraJavaLaunch = async (options) => {
16
17
  "LaunchSupport",
17
18
  installRoot,
18
19
  ];
19
- const environment = { ...options.environment };
20
+ const environment = {
21
+ ...snapshotEnvironment(options.environment, options.platform),
22
+ };
20
23
  const configuredEnvironment = await execFileOutput(command, [...supportArguments, "-envvars"], {
21
24
  env: environment,
22
25
  ...(options.signal === undefined ? {} : { signal: options.signal }),
@@ -25,7 +28,8 @@ export const ghidraJavaLaunch = async (options) => {
25
28
  if (line === "")
26
29
  continue;
27
30
  const separator = line.indexOf("=");
28
- const key = line.slice(0, separator);
31
+ const sourceKey = line.slice(0, separator);
32
+ const key = options.platform === "win32" ? sourceKey.toUpperCase() : sourceKey;
29
33
  if (separator < 1 || !/^[A-Za-z_][A-Za-z0-9_]*$/u.test(key))
30
34
  throw new Error(`Invalid Ghidra LaunchSupport environment entry: ${line}`);
31
35
  if ((environment[key] ?? "") === "")
@@ -1,3 +1,4 @@
1
+ import { snapshotEnvironment } from "../process/snapshotEnvironment.js";
1
2
  import { mkdir } from "node:fs/promises";
2
3
  import { basename, dirname, join, win32 } from "node:path";
3
4
  import writeFileAtomic from "write-file-atomic";
@@ -20,7 +21,10 @@ export class GhidraLaunchError extends Error {
20
21
  export class GhidraHeadlessLauncher {
21
22
  options;
22
23
  constructor(options) {
23
- this.options = options;
24
+ this.options = {
25
+ ...options,
26
+ environment: snapshotEnvironment(options.environment, options.platform),
27
+ };
24
28
  }
25
29
  async launch(session, options = {}) {
26
30
  if (isAborted(options.signal))
@@ -60,6 +64,7 @@ export class GhidraHeadlessLauncher {
60
64
  : { dosMz: this.options.dosMz }),
61
65
  });
62
66
  const scriptCommand = ghidraHeadlessCommand({
67
+ environment: this.options.environment,
63
68
  platform,
64
69
  analyzeHeadlessPath: this.options.analyzeHeadlessPath,
65
70
  arguments: headlessArguments,
@@ -67,7 +72,7 @@ export class GhidraHeadlessLauncher {
67
72
  ? {}
68
73
  : { comSpec: this.options.comSpec }),
69
74
  });
70
- const environment = ghidraLaunchEnvironment(paths, this.options.javaHome, platform, scriptCommand.command);
75
+ const environment = ghidraLaunchEnvironment(paths, this.options.javaHome, platform, scriptCommand.command, this.options.environment);
71
76
  if (platform !== "win32" && this.options.javaHome === undefined)
72
77
  throw new GhidraLaunchError("POSIX Ghidra requires its inspected JDK home");
73
78
  const command = platform !== "win32" && this.options.javaHome !== undefined
@@ -94,6 +99,7 @@ export class GhidraHeadlessLauncher {
94
99
  windowsVerbatimArguments: platform === "win32",
95
100
  platform,
96
101
  env: command.environment,
102
+ hostEnvironment: {},
97
103
  ...(options.signal === undefined ? {} : { signal: options.signal }),
98
104
  });
99
105
  await writeGhidraRuntimeFile(paths.ownershipPath, `${JSON.stringify({
@@ -145,11 +151,13 @@ export const ghidraHeadlessCommand = (options) => {
145
151
  command: options.analyzeHeadlessPath,
146
152
  arguments: [...options.arguments],
147
153
  };
154
+ const environment = snapshotEnvironment(options.environment, options.platform);
155
+ const systemRoot = environment.SYSTEMROOT;
148
156
  const comSpec = options.comSpec ??
149
- process.env.ComSpec ??
150
- (process.env.SystemRoot === undefined
157
+ environment.COMSPEC ??
158
+ (systemRoot === undefined
151
159
  ? "C:\\Windows\\System32\\cmd.exe"
152
- : win32.join(process.env.SystemRoot, "System32", "cmd.exe"));
160
+ : win32.join(systemRoot, "System32", "cmd.exe"));
153
161
  if (!win32.isAbsolute(comSpec) ||
154
162
  win32.basename(comSpec).toLowerCase() !== "cmd.exe")
155
163
  throw new GhidraLaunchError("Windows ComSpec must be an absolute cmd.exe path");
@@ -265,9 +273,9 @@ const writeGhidraRuntimeFile = async (path, content, platform) => {
265
273
  }
266
274
  await writeFileAtomic(path, content, { encoding: "utf8", mode: 0o600 });
267
275
  };
268
- const ghidraLaunchEnvironment = (paths, javaHome, platform, executable) => {
276
+ const ghidraLaunchEnvironment = (paths, javaHome, platform, executable, selectedEnvironment) => {
269
277
  return {
270
- ...ghidraJavaEnvironment(javaHome, process.env, platform),
278
+ ...ghidraJavaEnvironment(javaHome, selectedEnvironment, platform),
271
279
  ...ghidraHeadlessJavaOptions(paths.homeRoot, paths.tempRoot, platform),
272
280
  HOME: paths.homeRoot,
273
281
  TMPDIR: paths.tempRoot,
@@ -1,3 +1,4 @@
1
+ import { snapshotEnvironment } from "../process/snapshotEnvironment.js";
1
2
  import {} from "../application/AnalysisProvider.js";
2
3
  import { createAnalysisProfile, } from "../domain/analysisProfile.js";
3
4
  import { jsonObjectSchema, jsonValueSchema, } from "../domain/jsonValue.js";
@@ -9,7 +10,6 @@ import { resolveGhidraExtensions } from "./extensions/GhidraExtensions.js";
9
10
  import { CAPABILITIES, windowsP0Capabilities, GHIDRA_PROVIDER_IDENTITY, GHIDRA_OPERATIONS, } from "./GhidraProviderCapabilities.js";
10
11
  import { createGhidraProviderClient, } from "./GhidraProviderClient.js";
11
12
  import { windowsNativeAuthorityUnavailableReason, hasWindowsNativeAuthority, windowsNativeCapabilities, } from "../process/WindowsAuthority.js";
12
- export { GHIDRA_PROVIDER_IDENTITY, GHIDRA_OPERATIONS };
13
13
  const SUPPORTED_ARCHITECTURES = new Set(["x86", "x86_64", "arm", "arm64"]);
14
14
  /** Ghidra candidate backed by an isolated ephemeral headless import. */
15
15
  export class GhidraProvider {
@@ -18,11 +18,13 @@ export class GhidraProvider {
18
18
  installationHost;
19
19
  clientFactory;
20
20
  #installation;
21
- constructor(config, logger, installationHost, clientFactory = (options) => new GhidraClient(options)) {
21
+ environment;
22
+ constructor(config, logger, environment, installationHost, clientFactory = (options) => new GhidraClient(options)) {
22
23
  this.config = config;
23
24
  this.logger = logger;
24
25
  this.installationHost = installationHost;
25
26
  this.clientFactory = clientFactory;
27
+ this.environment = snapshotEnvironment(environment, installationHost?.platform);
26
28
  }
27
29
  identity() {
28
30
  return GHIDRA_PROVIDER_IDENTITY;
@@ -125,6 +127,7 @@ export class GhidraProvider {
125
127
  createClient(target, profile, context) {
126
128
  return createGhidraProviderClient({
127
129
  config: this.config,
130
+ environment: this.environment,
128
131
  logger: this.logger,
129
132
  clientFactory: this.clientFactory,
130
133
  target,
@@ -135,6 +138,7 @@ export class GhidraProvider {
135
138
  }
136
139
  #inspectInstallation() {
137
140
  const options = {
141
+ environment: this.environment,
138
142
  ...(this.config.ghidraInstallDir === undefined
139
143
  ? {}
140
144
  : { installDir: this.config.ghidraInstallDir }),
@@ -146,6 +146,12 @@ export const CAPABILITIES = Object.freeze(GHIDRA_OPERATIONS.map((operation) => {
146
146
  operation,
147
147
  available: true,
148
148
  reason: null,
149
+ // Project writes are private import machinery. Analysis reads are bound
150
+ // to the artifact/profile; session annotations disable snapshot replay.
151
+ ...(operation === "annotate_native_function" ||
152
+ operation === "list_documents"
153
+ ? {}
154
+ : { cachePolicy: "snapshot" }),
149
155
  effects: Object.freeze({
150
156
  mutatesArtifact: operation === "annotate_native_function",
151
157
  launchesProcess: true,
@@ -1,3 +1,4 @@
1
+ import { analysisErrorWithCleanupFailure } from "../application/binary/AnalysisClientCleanup.js";
1
2
  import { fileURLToPath } from "node:url";
2
3
  import { createAnalysisExecution, } from "../application/AnalysisProvider.js";
3
4
  import { AnalysisCancelledError, AnalysisArtifactChangedError, AnalysisAccessDeniedError, AnalysisCapabilityUnavailableError, AnalysisInputError, AnalysisResourceConstraintError, AnalysisTimeoutError, } from "../domain/analysisErrorCore.js";
@@ -57,6 +58,7 @@ export const createGhidraProviderClient = (input) => {
57
58
  startupTimeoutMs: config.ghidraStartupTimeoutMs,
58
59
  platform: installation.platform,
59
60
  launcher: new GhidraHeadlessLauncher({
61
+ environment: input.environment,
60
62
  analyzeHeadlessPath: prerequisites.value.analyzeHeadlessPath,
61
63
  javaHome: prerequisites.value.javaHome,
62
64
  bridgeScriptPath: fileURLToPath(new URL("../../bridge/ghidra/ReaGhidraBridge.java", import.meta.url)),
@@ -87,8 +89,10 @@ export const createGhidraProviderClient = (input) => {
87
89
  extensionFailure = ghidraExtensionFailure(extensions, info.analysis_extensions ?? [], operation);
88
90
  if (extensionFailure === undefined)
89
91
  return undefined;
90
- await client.close();
91
- return extensionFailure;
92
+ const closed = await client.close();
93
+ return closed.ok
94
+ ? extensionFailure
95
+ : analysisErrorWithCleanupFailure(extensionFailure, closed.error, operation);
92
96
  };
93
97
  const releaseLimitation = unverifiedGhidraBuildLimitation(prerequisites.value.providerVersion);
94
98
  const sessionLimitations = [
@@ -181,9 +185,15 @@ const ghidraClientPrerequisites = (target, profile, installation) => {
181
185
  };
182
186
  const unavailableClient = (failure) => ({
183
187
  execute: () => Promise.resolve(err(failure)),
184
- close: () => Promise.resolve(),
188
+ close: () => Promise.resolve(ok(null)),
185
189
  });
186
190
  const projectSessionError = (operation, failure, startupTimeoutMs) => {
191
+ const primary = projectPrimarySessionError(operation, failure, startupTimeoutMs);
192
+ return failure.cleanupFailure === undefined
193
+ ? primary
194
+ : analysisErrorWithCleanupFailure(primary, failure.cleanupFailure, operation);
195
+ };
196
+ const projectPrimarySessionError = (operation, failure, startupTimeoutMs) => {
187
197
  if (failure.cause instanceof AnalysisAccessDeniedError)
188
198
  return new AnalysisAccessDeniedError(operation, failure.cause.path, failure.cause.systemCode, { cause: failure });
189
199
  if (failure.cause instanceof AnalysisArtifactChangedError)
@@ -4,6 +4,7 @@ export class GhidraSessionError extends Error {
4
4
  diagnostics;
5
5
  timeoutMs;
6
6
  remoteCode;
7
+ cleanupFailure;
7
8
  constructor(kind, message, diagnostics = {}, options = {}) {
8
9
  super(message, options);
9
10
  this.kind = kind;
@@ -11,6 +12,7 @@ export class GhidraSessionError extends Error {
11
12
  this.diagnostics = structuredClone(diagnostics);
12
13
  this.timeoutMs = options.timeoutMs;
13
14
  this.remoteCode = options.remoteCode;
15
+ this.cleanupFailure = options.cleanupFailure;
14
16
  }
15
17
  }
16
18
  /** Build a session failure while preserving bounded remote failure metadata. */
@@ -0,0 +1,39 @@
1
+ import { dirname, isAbsolute, resolve, sep } from "node:path";
2
+ import { tmpdir } from "node:os";
3
+ /** Session roots may not contain a dot-prefixed path element. */
4
+ const hasDotPrefixElement = (directory) => resolve(directory)
5
+ .split(sep)
6
+ .some((element) => element.startsWith("."));
7
+ /** Nearest ancestor of `directory`, inclusive, that has no dot-prefixed element. */
8
+ const nearestSafeAncestor = (directory) => {
9
+ let current = resolve(directory);
10
+ for (;;) {
11
+ if (!hasDotPrefixElement(current))
12
+ return current;
13
+ const parent = dirname(current);
14
+ if (parent === current)
15
+ return undefined;
16
+ current = parent;
17
+ }
18
+ };
19
+ /**
20
+ * Select a session root usable as the parent of a Ghidra project path.
21
+ *
22
+ * Ghidra validates every project path element with `NamingUtilities.checkName`
23
+ * and aborts the headless analyzer on any element that starts with `.`, so an
24
+ * inherited `TMPDIR` such as `~/.cache/<tool>` fails every Ghidra operation
25
+ * with a generic analysis failure. Prefer the inherited base when it is usable,
26
+ * then a dot-free platform temp directory, then the nearest dot-free ancestor.
27
+ */
28
+ export const ghidraSessionRoot = (options = {}) => {
29
+ const base = resolve(options.base ?? tmpdir());
30
+ if (!hasDotPrefixElement(base))
31
+ return base;
32
+ const platform = options.platform ?? process.platform;
33
+ const fallback = options.fallback ?? (platform === "win32" ? undefined : "/tmp");
34
+ if (fallback !== undefined &&
35
+ isAbsolute(fallback) &&
36
+ !hasDotPrefixElement(fallback))
37
+ return resolve(fallback);
38
+ return nearestSafeAncestor(base) ?? base;
39
+ };