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,6 +1,7 @@
1
1
  import { constants } from "node:fs";
2
2
  import { lstat, open, opendir, realpath } from "node:fs/promises";
3
3
  import { isAbsolute, join, relative, sep } from "node:path";
4
+ import { compareCodePoints } from "../domain/canonicalOrdering.js";
4
5
  import { ArtifactReaderFailure, } from "./ArtifactReader.js";
5
6
  /** Deterministic, non-symlink-following directory reader. */
6
7
  export class DirectoryArtifactReader {
@@ -38,7 +39,7 @@ export class DirectoryArtifactReader {
38
39
  await handle.close().catch(() => undefined);
39
40
  }
40
41
  await withDirectoryIoContext("inspect directory", directory, () => assertContainedDirectory(root, directory));
41
- children.sort((left, right) => left.localeCompare(right, "en"));
42
+ children.sort(compareCodePoints);
42
43
  const directories = [];
43
44
  for (const name of children) {
44
45
  abortIfNeeded(signal);
@@ -12,7 +12,7 @@ export class MachOSliceArtifactReader {
12
12
  runner;
13
13
  format = "file";
14
14
  #command;
15
- constructor(path, runner = new XcrunCommandRunner()) {
15
+ constructor(path, environment, runner = new XcrunCommandRunner(environment)) {
16
16
  this.path = path;
17
17
  this.runner = runner;
18
18
  }
@@ -175,7 +175,7 @@ const lipoMatchesSlice = (reported, observed, structurallyUnique) => {
175
175
  reported.cpu_type_code !== null ||
176
176
  reported.cpu_subtype_code !== null;
177
177
  return ((hasPhysicalIdentity || structurallyUnique) &&
178
- reported.name === observed.architecture &&
178
+ lipoNameMatches(reported.name, observed.architecture) &&
179
179
  (reported.file_offset === null ||
180
180
  reported.file_offset === observed.slice_offset) &&
181
181
  (reported.size === null || reported.size === observed.slice_size) &&
@@ -187,6 +187,13 @@ const lipoMatchesSlice = (reported, observed, structurallyUnique) => {
187
187
  observed.fat_alignment_exponent === null ||
188
188
  reported.alignment === 2 ** observed.fat_alignment_exponent));
189
189
  };
190
+ /**
191
+ * Newer lipo names an arm64e ABI variant `arm64e.<variant>` (for example
192
+ * `arm64e.v1` for pointer-auth ABI version 1). The FAT table names that slice
193
+ * `arm64e`; its physical identity is still compared field by field.
194
+ */
195
+ const lipoNameMatches = (reported, observed) => reported === observed ||
196
+ (observed === "arm64e" && /^arm64e\.[A-Za-z0-9_]+$/u.test(reported));
190
197
  const parseSliceKeyInteger = (value) => {
191
198
  if (value === undefined || !/^\d+$/u.test(value))
192
199
  return null;
@@ -7,6 +7,13 @@ import { ArtifactReaderFailure, } from "./ArtifactReader.js";
7
7
  import { DirectoryArtifactReader } from "./DirectoryArtifactReader.js";
8
8
  import { execFileOutput } from "../process/ExecFileOutput.js";
9
9
  const DETACH_TIMEOUT_MS = 120_000;
10
+ /**
11
+ * Waits before rechecking devices whose detach failed. A related device's
12
+ * later detach can eject one, `hdiutil info` can still list an ejected device
13
+ * briefly, and a volume can report busy just after it was read.
14
+ */
15
+ const DETACH_SETTLE_DELAYS_MS = [250, 500, 1000];
16
+ const delay = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
10
17
  const attachOutputSchema = z.object({
11
18
  "system-entities": z.array(z.object({
12
19
  "dev-entry": z.string().startsWith("/dev/"),
@@ -18,10 +25,12 @@ const infoOutputSchema = z.object({
18
25
  "system-entities": z.array(z.object({ "dev-entry": z.string() })),
19
26
  })),
20
27
  });
21
- const systemHost = {
28
+ const createSystemHost = (environment) => ({
29
+ delay,
22
30
  async run(arguments_, signal, options) {
23
31
  try {
24
32
  const { stdout, stderr } = await execFileOutput("/usr/bin/hdiutil", [...arguments_], {
33
+ env: environment,
25
34
  ...(options === undefined ? {} : { timeout: options.timeoutMs }),
26
35
  ...(signal === undefined ? {} : { signal }),
27
36
  });
@@ -41,7 +50,7 @@ const systemHost = {
41
50
  throw new ArtifactReaderFailure(commandFailureReason(cause, arguments_[0]), `hdiutil ${arguments_[0] ?? "operation"} failed: ${describeCommandFailure(cause, arguments_)}`, { cause });
42
51
  }
43
52
  },
44
- };
53
+ });
45
54
  /** Read-only macOS DMG adapter that owns attachment and reverse-order detach. */
46
55
  export class NativeDmgArtifactReader {
47
56
  path;
@@ -56,10 +65,10 @@ export class NativeDmgArtifactReader {
56
65
  this.host = host;
57
66
  }
58
67
  /** Verify and attach one image beneath an exclusively owned temporary root. */
59
- static async create(path, signal, host = systemHost) {
60
- if (process.platform !== "darwin" && host === systemHost)
68
+ static async create(path, environment, signal, host) {
69
+ if (process.platform !== "darwin" && host === undefined)
61
70
  throw new ArtifactReaderFailure("unavailable", "Native DMG traversal is available only on macOS");
62
- const reader = new NativeDmgArtifactReader(path, host);
71
+ const reader = new NativeDmgArtifactReader(path, host ?? createSystemHost(environment));
63
72
  await reader.attach(signal);
64
73
  return reader;
65
74
  }
@@ -80,24 +89,36 @@ export class NativeDmgArtifactReader {
80
89
  }
81
90
  async close() {
82
91
  let detachFailure;
83
- const remainingDevices = [];
92
+ let remainingDevices = [];
84
93
  for (const device of [...this.#devices].reverse()) {
85
- try {
86
- await runChecked(this.host, ["detach", device], undefined, {
87
- timeoutMs: DETACH_TIMEOUT_MS,
88
- });
89
- this.#provenance.push(command(["detach", device], ["mount"]));
94
+ const failure = await this.#detach(device);
95
+ if (failure !== undefined) {
96
+ remainingDevices.push(device);
97
+ detachFailure ??= failure;
90
98
  }
91
- catch (cause) {
92
- // Detaching a synthesized APFS container also ejects the image that
93
- // backs it, so a later whole disk of the same image may already be
94
- // gone. Only a device that is still attached is a cleanup failure.
95
- if (await this.#isAttached(device)) {
96
- remainingDevices.push(device);
97
- detachFailure ??= cause;
99
+ }
100
+ // Detaching a synthesized APFS container also ejects the image that backs
101
+ // it, so a device whose own detach failed may be gone by the end of the
102
+ // pass, and hdiutil can list an ejected device or report busy briefly.
103
+ // Only a device that stays attached through every recheck is a failure.
104
+ for (const delayMs of DETACH_SETTLE_DELAYS_MS) {
105
+ if (remainingDevices.length === 0)
106
+ break;
107
+ await (this.host.delay ?? delay)(delayMs);
108
+ const stillAttached = [];
109
+ for (const device of remainingDevices) {
110
+ if (!(await this.#isAttached(device)))
111
+ continue;
112
+ const failure = await this.#detach(device);
113
+ if (failure !== undefined) {
114
+ stillAttached.push(device);
115
+ detachFailure = failure;
98
116
  }
99
117
  }
118
+ remainingDevices = stillAttached;
100
119
  }
120
+ if (remainingDevices.length === 0)
121
+ detachFailure = undefined;
101
122
  this.#devices = remainingDevices.reverse();
102
123
  if (this.#devices.length === 0 && this.#mountRoot !== undefined)
103
124
  await rm(this.#mountRoot, { recursive: true, force: true }).then(() => {
@@ -107,7 +128,31 @@ export class NativeDmgArtifactReader {
107
128
  detachFailure ??= cause;
108
129
  });
109
130
  if (detachFailure !== undefined)
110
- throw new ArtifactReaderFailure("unavailable", `DMG detach or mount-root cleanup failed for ${JSON.stringify(this.path)}: ${failureMessage(detachFailure)}`, { cause: detachFailure });
131
+ throw new ArtifactReaderFailure("unavailable", `DMG detach or mount-root cleanup failed for ${JSON.stringify(this.path)}: ${failureMessage(detachFailure)}`, {
132
+ cause: detachFailure,
133
+ cleanup: {
134
+ reason: failureMessage(detachFailure),
135
+ resources: [
136
+ ...this.#devices.map((device) => `DMG device ${device}`),
137
+ ...(this.#mountRoot === undefined
138
+ ? []
139
+ : [`DMG mount root ${this.#mountRoot}`]),
140
+ ],
141
+ },
142
+ });
143
+ }
144
+ /** Detach one device; return the failure only while it remains attached. */
145
+ async #detach(device) {
146
+ try {
147
+ await runChecked(this.host, ["detach", device], undefined, {
148
+ timeoutMs: DETACH_TIMEOUT_MS,
149
+ });
150
+ this.#provenance.push(command(["detach", device], ["mount"]));
151
+ return undefined;
152
+ }
153
+ catch (cause) {
154
+ return (await this.#isAttached(device)) ? cause : undefined;
155
+ }
111
156
  }
112
157
  /**
113
158
  * Report whether hdiutil still lists a device; unknown state counts as
@@ -175,7 +220,7 @@ export class NativeDmgArtifactReader {
175
220
  cleanupFailure = cleanupCause;
176
221
  }
177
222
  if (cleanupFailure !== undefined)
178
- throw new ArtifactReaderFailure("unavailable", `DMG attach failed and cleanup could not detach every device: ${failureMessage(cause)}; cleanup: ${failureMessage(cleanupFailure)}`, { cause: new AggregateError([cause, cleanupFailure]) });
223
+ throw ArtifactReaderFailure.withCleanup(cause, ArtifactReaderFailure.cleanupObservation(cleanupFailure, `DMG mount root ${this.#mountRoot ?? this.path}`));
179
224
  throw cause;
180
225
  }
181
226
  }
@@ -129,7 +129,13 @@ export class SafeOutputTree {
129
129
  async rollback() {
130
130
  if (this.#published)
131
131
  return structuredClone(this.#cleanup);
132
- await rm(this.#outputRoot, { recursive: true, force: true });
132
+ let removalFailure;
133
+ try {
134
+ await rm(this.#outputRoot, { recursive: true, force: true });
135
+ }
136
+ catch (cause) {
137
+ removalFailure = cause;
138
+ }
133
139
  const absent = await isAbsent(this.#outputRoot);
134
140
  this.#cleanup = absent
135
141
  ? { status: "complete", residualPaths: [] }
@@ -138,7 +144,15 @@ export class SafeOutputTree {
138
144
  residualPaths: [basename(this.#outputRoot)],
139
145
  };
140
146
  if (!absent)
141
- throw new ArtifactReaderFailure("integrity", "Extraction output cleanup could not be verified");
147
+ throw new ArtifactReaderFailure("integrity", `Extraction output cleanup could not be verified${removalFailure === undefined ? "" : `: ${removalFailure instanceof Error ? removalFailure.message : String(removalFailure)}`}`, {
148
+ cause: removalFailure,
149
+ cleanup: {
150
+ reason: removalFailure instanceof Error
151
+ ? removalFailure.message
152
+ : "Extraction output root remains after rollback",
153
+ resources: [this.#outputRoot],
154
+ },
155
+ });
142
156
  return structuredClone(this.#cleanup);
143
157
  }
144
158
  async #prepareParent(relativePath) {
@@ -5,10 +5,12 @@ import { Reader, ZipReader } from "@zip.js/zip.js";
5
5
  import { ArtifactReaderFailure, } from "./ArtifactReader.js";
6
6
  class NodeFileReader extends Reader {
7
7
  path;
8
+ maximumReadBytes;
8
9
  #handle;
9
- constructor(path) {
10
+ constructor(path, maximumReadBytes) {
10
11
  super(path);
11
12
  this.path = path;
13
+ this.maximumReadBytes = maximumReadBytes;
12
14
  }
13
15
  async init() {
14
16
  this.#handle = await open(this.path, "r");
@@ -18,7 +20,11 @@ class NodeFileReader extends Reader {
18
20
  const handle = this.#handle;
19
21
  if (handle === undefined)
20
22
  throw new Error("ZIP reader is not initialized");
21
- const bytes = Buffer.alloc(Math.min(length, this.size - index));
23
+ const readBytes = Math.min(length, this.size - index);
24
+ if (this.maximumReadBytes !== undefined &&
25
+ readBytes > this.maximumReadBytes)
26
+ throw new ArtifactReaderFailure("limit", `ZIP metadata read requires ${readBytes} bytes, exceeding the ${this.maximumReadBytes}-byte read budget`);
27
+ const bytes = Buffer.alloc(readBytes);
22
28
  const read = await handle.read(bytes, 0, bytes.length, index);
23
29
  return bytes.subarray(0, read.bytesRead);
24
30
  }
@@ -33,9 +39,10 @@ export class ZipArtifactReader {
33
39
  #source;
34
40
  #reader;
35
41
  #entries = new Map();
36
- constructor(path, format) {
42
+ /** Optionally bound each metadata read before allocating its backing buffer. */
43
+ constructor(path, format, maximumMetadataReadBytes) {
37
44
  this.format = format;
38
- this.#source = new NodeFileReader(path);
45
+ this.#source = new NodeFileReader(path, maximumMetadataReadBytes);
39
46
  this.#reader = new ZipReader(this.#source, {
40
47
  checkSignature: true,
41
48
  checkOverlappingEntry: true,
@@ -39,7 +39,8 @@ export const analyzeAppleAssetCatalogs = async (input) => {
39
39
  const inspected = await inspectAssetCatalogEntry({
40
40
  reader,
41
41
  entry,
42
- runAssetUtil: input.runAssetUtil ?? runAssetUtil,
42
+ runAssetUtil: input.runAssetUtil ??
43
+ ((path, signal) => runAssetUtil(path, input.environment, signal)),
43
44
  ...(input.signal === undefined ? {} : { signal: input.signal }),
44
45
  });
45
46
  totalMetadataBytes += inspected.metadataBytes;
@@ -150,9 +151,10 @@ export const collectInterfaceBuilderResourceKeys = (nodes) => nodes.flatMap((nod
150
151
  ]
151
152
  : []);
152
153
  });
153
- const runAssetUtil = async (path, signal) => {
154
+ const runAssetUtil = async (path, environment, signal) => {
154
155
  try {
155
156
  return (await execFileOutput(ASSETUTIL, ["--info", path], {
157
+ env: environment,
156
158
  timeout: 60_000,
157
159
  maxBuffer: MAX_CATALOG_BYTES,
158
160
  ...(signal === undefined ? {} : { signal }),
@@ -2,11 +2,14 @@ import { createHash } from "node:crypto";
2
2
  import { constants } from "node:fs";
3
3
  import { lstat, open, readlink, realpath } from "node:fs/promises";
4
4
  import { join, relative, sep } from "node:path";
5
+ import { AnalysisInputError } from "../../domain/analysisErrorCore.js";
5
6
  import { resolveTreePath } from "../../domain/apple/dyldPaths.js";
6
7
  import { dylibResolutionInputSchema, dylibResolutionResultSchema, traceDylibLoading, } from "../../domain/apple/dylibResolution.js";
8
+ import { projectInputIssues } from "../../domain/inputIssueProjection.js";
7
9
  import { ArtifactReaderFailure } from "../ArtifactReader.js";
8
10
  import { DirectoryArtifactReader } from "../DirectoryArtifactReader.js";
9
11
  import { hasMachoMagic, readMachoImage } from "./MachoLoadCommandReader.js";
12
+ const OPERATION = "trace_dylib_resolution";
10
13
  const HASH_CHUNK_BYTES = 1024 * 1024;
11
14
  /** Lazily probed, symlink-preserving view of one analyzed directory. */
12
15
  class FilesystemTreeView {
@@ -64,7 +67,7 @@ class FilesystemTreeView {
64
67
  export const traceDylibResolution = async (options) => {
65
68
  const parsed = dylibResolutionInputSchema.safeParse(options.parameters);
66
69
  if (!parsed.success)
67
- throw new ArtifactReaderFailure("path", "roots must be normalized paths relative to the analyzed root");
70
+ throw new AnalysisInputError(OPERATION, { cause: parsed.error }, projectInputIssues(parsed.error.issues, options.parameters));
68
71
  // Canonicalization is inside the translated region: a revoked permission
69
72
  // keeps its reason and path.
70
73
  let root = options.rootPath;
@@ -79,7 +82,7 @@ export const traceDylibResolution = async (options) => {
79
82
  : options.enumerateRoots
80
83
  ? await executableRoots(root, view, options.signal)
81
84
  : { roots: [target], unclassified: [] };
82
- const roots = await requireMachoRoots(view, requested);
85
+ const roots = await requireMachoRoots(view, requested, parsed.data.roots !== undefined);
83
86
  const trace = await traceDylibLoading(view, {
84
87
  roots,
85
88
  unclassified,
@@ -151,17 +154,24 @@ const compare = (left, right) => left < right ? -1 : left > right ? 1 : 0;
151
154
  /**
152
155
  * Resolve each root segment by segment, as dependency candidates are, so a
153
156
  * symlink in an intermediate directory cannot lead outside the analyzed root.
157
+ * A root the caller selected that fails is an input error on that root; a
158
+ * root REA derived itself keeps reporting an artifact failure.
154
159
  */
155
- const requireMachoRoots = async (view, roots) => {
160
+ const requireMachoRoots = async (view, roots, callerSelected) => {
156
161
  const resolved = [];
157
- for (const path of roots) {
162
+ for (const [index, path] of roots.entries()) {
163
+ const reject = (reason, message) => callerSelected
164
+ ? new AnalysisInputError(OPERATION, undefined, [
165
+ { path: ["roots", index], reason: "invalid_value", message },
166
+ ])
167
+ : new ArtifactReaderFailure(reason, message);
158
168
  const lookup = await resolveTreePath(view, path);
159
169
  if (lookup.kind === "escapes")
160
- throw new ArtifactReaderFailure("path", `Root ${path} resolves outside the analyzed root`);
170
+ throw reject("path", `Root ${path} resolves outside the analyzed root`);
161
171
  if (lookup.kind !== "file")
162
- throw new ArtifactReaderFailure("path", `Root ${path} is not a regular file in the analyzed root`);
172
+ throw reject("path", `Root ${path} is not a regular file in the analyzed root`);
163
173
  if ((await view.image(lookup.path)).status === "not-mach-o")
164
- throw new ArtifactReaderFailure("format", `Root ${path} is not a Mach-O image`);
174
+ throw reject("format", `Root ${path} is not a Mach-O image`);
165
175
  if (!resolved.includes(lookup.path))
166
176
  resolved.push(lookup.path);
167
177
  }
@@ -1,12 +1,13 @@
1
1
  import { createHash } from "node:crypto";
2
+ import { join } from "node:path";
2
3
  import { parseBinary } from "plist";
3
4
  import { z } from "zod";
4
- import { AnalysisInputError } from "../../domain/analysisErrorCore.js";
5
+ import { AnalysisInputError, AnalysisUnsupportedTargetError, } from "../../domain/analysisErrorCore.js";
5
6
  import { projectPlistValue } from "../../domain/apple/plistValue.js";
6
7
  import { createPlistNumberProjection } from "../../domain/apple/plistNumbers.js";
7
8
  import { binaryPlistNumberLiterals, xmlPlistNumberLiterals, } from "./PlistNumberLiterals.js";
8
9
  import { omittedPrototypeKeysLimitation, parseXmlPropertyList, } from "../../domain/propertyListKeys.js";
9
- import { keyedArchiveInputSchema, keyedArchiveResultSchema, projectKeyedArchive, } from "../../domain/apple/keyedArchive.js";
10
+ import { KeyedArchiveKindError, keyedArchiveInputSchema, keyedArchiveResultSchema, projectKeyedArchive, } from "../../domain/apple/keyedArchive.js";
10
11
  import { DirectoryArtifactReader } from "../DirectoryArtifactReader.js";
11
12
  import { ArtifactReaderFailure } from "../ArtifactReader.js";
12
13
  import { decodeXmlPlistText } from "../../domain/propertyListXmlText.js";
@@ -16,7 +17,7 @@ export const decodeKeyedArchiveBytes = (bytes, selection) => {
16
17
  if (bytes.length > MAX_BYTES)
17
18
  throw new RangeError("Keyed archive exceeds 64 MiB");
18
19
  if (bytes.subarray(0, 10).toString("ascii") === "NIBArchive")
19
- throw new TypeError("Selected file is a compiled NIBArchive, not a Foundation plist archive; decode it with decode_interface_builder");
20
+ throw new KeyedArchiveKindError("Selected file is a compiled NIBArchive, not a Foundation plist archive; decode it with decode_interface_builder", "nib-archive");
20
21
  const binary = bytes.subarray(0, 8).toString("ascii") === "bplist00";
21
22
  const xmlText = binary ? undefined : decodeXmlPlistText(bytes);
22
23
  const parsed = binary
@@ -56,6 +57,17 @@ const normalizePlist = (value) => {
56
57
  throw new RangeError("Keyed archive contains a non-finite real");
57
58
  return projected.value;
58
59
  };
60
+ /**
61
+ * Point to the workflow that reads the selected kind of file on this host.
62
+ * decode_interface_builder is portable; inspect_plist requires macOS.
63
+ */
64
+ const keyedArchiveKindRemediation = (kind, platform) => {
65
+ if (kind === "nib-archive")
66
+ return "Decode compiled NIBArchive files with decode_interface_builder on the app bundle.";
67
+ return platform === "darwin"
68
+ ? "Inspect an ordinary property list with inspect_plist; inspect_keyed_archive decodes NSKeyedArchiver archives only."
69
+ : "Select an NSKeyedArchiver archive; inspect_keyed_archive decodes only those. inspect_plist, which reads ordinary property lists, requires a macOS host.";
70
+ };
59
71
  /** Read exactly one regular, contained bundle entry without following symlinks. */
60
72
  export const inspectBundleKeyedArchive = async (input) => {
61
73
  const selected = keyedArchiveInputSchema.parse(input.parameters);
@@ -103,6 +115,12 @@ export const inspectBundleKeyedArchive = async (input) => {
103
115
  catch (cause) {
104
116
  if (cause instanceof AnalysisInputError)
105
117
  throw cause;
118
+ // An intact file of another kind is not a damaged archive.
119
+ if (cause instanceof KeyedArchiveKindError)
120
+ throw new AnalysisUnsupportedTargetError("inspect_keyed_archive", join(input.bundlePath, entry.path), cause.message, {
121
+ cause,
122
+ remediationAction: keyedArchiveKindRemediation(cause.kind, input.platform ?? process.platform),
123
+ });
106
124
  throw new ArtifactReaderFailure(cause instanceof RangeError ? "limit" : "format", `Cannot decode selected Foundation keyed archive: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
107
125
  }
108
126
  }
@@ -1,19 +1,26 @@
1
1
  import { lstat, realpath } from "node:fs/promises";
2
+ import { compareCodePoints } from "../../domain/canonicalOrdering.js";
2
3
  import { canonicalDigest } from "../../domain/comparisonSemantics.js";
3
4
  import { AsarArtifactReader } from "../AsarArtifactReader.js";
4
5
  import { ArtifactPathRegistry, normalizeArtifactPath, } from "../ArtifactPaths.js";
5
6
  import { ArtifactReaderFailure, } from "../ArtifactReader.js";
7
+ import { abortIfNeeded } from "../ArtifactHash.js";
6
8
  import { DirectoryArtifactReader } from "../DirectoryArtifactReader.js";
7
9
  import { SafeOutputTree } from "../SafeOutputTree.js";
8
10
  import { ZipArtifactReader } from "../ZipArtifactReader.js";
9
11
  import { MachOSliceArtifactReader } from "../MachOSliceArtifactReader.js";
10
12
  import { artifactExtractionResultSchema, } from "../../domain/artifactGraph.js";
13
+ import { AnalysisUnsupportedTargetError } from "../../domain/analysisErrorCore.js";
11
14
  import { scanArtifactInventory } from "../inventory/ArtifactInventory.js";
12
15
  /** Extract every regular inventory occurrence into an exclusively owned absent root. */
13
16
  export const extractArtifact = async (input, signal) => {
17
+ // Cancellation wins over every later refusal, including unsupported formats.
18
+ abortIfNeeded(signal);
14
19
  const sourcePath = await realpath(input.inputPath);
20
+ await requireExtractableFormat(sourcePath, input);
15
21
  const snapshot = await scanArtifactInventory(sourcePath, {
16
22
  signal,
23
+ environment: input.environment,
17
24
  });
18
25
  const selectedOccurrences = snapshot.occurrences.filter((occurrence) => (occurrence.entry_kind === "file" || occurrence.entry_kind === "slice") &&
19
26
  occurrence.logical_path !== ".");
@@ -29,11 +36,14 @@ export const extractArtifact = async (input, signal) => {
29
36
  nodes,
30
37
  };
31
38
  const selected = selectedOccurrences.map((occurrence) => {
39
+ // REA never decrypts archive entries, so an encrypted entry makes the
40
+ // complete extraction unsupported rather than the archive invalid.
41
+ if (occurrence.encrypted)
42
+ throw new AnalysisUnsupportedTargetError("extract_artifact", input.inputPath, `Archive entry ${occurrence.logical_path} is encrypted; REA does not decrypt archive entries, so the archive cannot be extracted completely`);
32
43
  if ((occurrence.entry_kind !== "file" && occurrence.entry_kind !== "slice") ||
33
44
  occurrence.artifact_id === null ||
34
- occurrence.encrypted ||
35
45
  occurrence.logical_path === ".")
36
- throw new ArtifactReaderFailure("format", `Selected occurrence is not an extractable regular child file: ${occurrence.occurrence_id}`);
46
+ throw new ArtifactReaderFailure("format", `Selected occurrence is not an extractable regular child file: ${occurrence.logical_path} (${occurrence.occurrence_id})`);
37
47
  const node = inventory.nodes.get(occurrence.artifact_id);
38
48
  if (node === undefined)
39
49
  throw new ArtifactReaderFailure("integrity", `Selected occurrence has no inventory node: ${occurrence.occurrence_id}`);
@@ -49,11 +59,13 @@ export const extractArtifact = async (input, signal) => {
49
59
  };
50
60
  const materializeSelection = async ({ input, sourcePath, inventory, selected, signal, }) => {
51
61
  const byPath = new Map(selected.map((item) => [item.occurrence.logical_path, item]));
52
- const reader = await createReader(sourcePath, input.inputFormat);
53
- const output = await SafeOutputTree.create(input.outputRoot);
62
+ const reader = await createReader(sourcePath, input);
63
+ let output;
64
+ let readerCloseAttempted = false;
54
65
  let readerClosed = false;
55
66
  const extracted = [];
56
67
  try {
68
+ output = await SafeOutputTree.create(input.outputRoot);
57
69
  const materialized = [];
58
70
  const registry = new ArtifactPathRegistry();
59
71
  for await (const entry of reader.entries(signal)) {
@@ -77,20 +89,53 @@ const materializeSelection = async ({ input, sourcePath, inventory, selected, si
77
89
  });
78
90
  materialized.push(selectedItem);
79
91
  }
92
+ readerCloseAttempted = true;
80
93
  await reader.close();
81
94
  readerClosed = true;
82
- extracted.sort((left, right) => left.relative_path.localeCompare(right.relative_path, "en"));
95
+ extracted.sort((left, right) => compareCodePoints(left.relative_path, right.relative_path));
83
96
  const result = createExtractionResult(input, inventory, materialized, extracted);
84
97
  await output.commit();
85
98
  return result;
86
99
  }
87
100
  catch (cause) {
88
- if (!readerClosed)
89
- await reader.close().catch((cause) => {
90
- // best-effort cleanup: reader close must not mask the extraction failure.
91
- void cause;
101
+ const cleanupFailures = [];
102
+ if (readerCloseAttempted && !readerClosed)
103
+ cleanupFailures.push({
104
+ cause,
105
+ resource: `artifact reader for ${sourcePath}`,
92
106
  });
93
- await output.rollback();
107
+ if (!readerCloseAttempted) {
108
+ try {
109
+ readerCloseAttempted = true;
110
+ await reader.close();
111
+ }
112
+ catch (cleanupCause) {
113
+ cleanupFailures.push({
114
+ cause: cleanupCause,
115
+ resource: `artifact reader for ${sourcePath}`,
116
+ });
117
+ }
118
+ }
119
+ if (output !== undefined) {
120
+ try {
121
+ await output.rollback();
122
+ }
123
+ catch (cleanupCause) {
124
+ cleanupFailures.push({
125
+ cause: cleanupCause,
126
+ resource: input.outputRoot,
127
+ });
128
+ }
129
+ }
130
+ if (cleanupFailures.length > 0) {
131
+ const observations = cleanupFailures.map(({ cause: cleanupCause, resource }) => ArtifactReaderFailure.cleanupObservation(cleanupCause, resource));
132
+ throw ArtifactReaderFailure.withCleanup(cause, {
133
+ reason: observations.map(({ reason }) => reason).join("; "),
134
+ resources: [
135
+ ...new Set(observations.flatMap(({ resources }) => resources)),
136
+ ],
137
+ });
138
+ }
94
139
  throw cause;
95
140
  }
96
141
  };
@@ -99,7 +144,7 @@ const createExtractionResult = (input, inventory, selected, extracted) => {
99
144
  source_manifest_id: inventory.manifest.manifest_id,
100
145
  selected_occurrence_ids: selected
101
146
  .map(({ occurrence }) => occurrence.occurrence_id)
102
- .sort((left, right) => left.localeCompare(right)),
147
+ .sort(compareCodePoints),
103
148
  files_sha256: canonicalDigest(extracted, "Artifact"),
104
149
  output_root_alias: "$OUTPUT_ROOT",
105
150
  };
@@ -133,20 +178,32 @@ const collectNodes = (items, selected, output) => {
133
178
  if (selected.has(item.artifact_id))
134
179
  output.set(item.artifact_id, item);
135
180
  };
136
- const createReader = async (path, format) => {
137
- if ((await lstat(path)).isDirectory())
181
+ const ZIP_FORMATS = ["ipa", "apk", "msix", "appx", "zip"];
182
+ const isZipFormat = (format) => ZIP_FORMATS.includes(format);
183
+ /**
184
+ * Refuse a format without an extraction reader before inventory work starts.
185
+ * The target kind, not the host, is unsupported by extraction. The error keeps
186
+ * the caller's spelling of the path; I/O uses the canonical path.
187
+ */
188
+ const requireExtractableFormat = async (path, input) => {
189
+ const format = input.inputFormat;
190
+ const directory = (await lstat(path)).isDirectory();
191
+ if (!directory &&
192
+ format !== "asar" &&
193
+ format !== "mach-o" &&
194
+ !isZipFormat(format))
195
+ throw new AnalysisUnsupportedTargetError("extract_artifact", input.inputPath, `Artifact format has no extraction reader: ${format}`);
196
+ return directory;
197
+ };
198
+ const createReader = async (path, input) => {
199
+ const format = input.inputFormat;
200
+ if (await requireExtractableFormat(path, input))
138
201
  return new DirectoryArtifactReader(path);
139
202
  if (format === "asar")
140
203
  return new AsarArtifactReader(path);
141
- if (format === "ipa" ||
142
- format === "apk" ||
143
- format === "msix" ||
144
- format === "appx" ||
145
- format === "zip")
204
+ if (isZipFormat(format))
146
205
  return new ZipArtifactReader(path, format);
147
- if (format === "mach-o")
148
- return new MachOSliceArtifactReader(path);
149
- throw new ArtifactReaderFailure("unavailable", `Artifact format has no extraction reader: ${format}`);
206
+ return new MachOSliceArtifactReader(path, input.environment);
150
207
  };
151
208
  const preflight = (entry) => {
152
209
  if ((entry.kind !== "file" && entry.kind !== "slice") || entry.encrypted)