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
@@ -3,18 +3,22 @@ import { constants, statSync } from "node:fs";
3
3
  import { open, mkdtemp, rm, stat } from "node:fs/promises";
4
4
  import { tmpdir } from "node:os";
5
5
  import { join } from "node:path";
6
- import { digestProcessCommitment, parseProcessCapture, partialProcessCaptureObservationSchema, processComparisonContract, processScenarioCommitment, } from "../../domain/process/processCapture.js";
6
+ import { setTimeout as delay } from "node:timers/promises";
7
+ import { digestProcessCommitment, processComparisonContract, processScenarioCommitment, } from "../../domain/process/processScenario.js";
8
+ import { parseProcessCapture } from "../../domain/process/processCaptureParsing.js";
7
9
  import { PRODUCT_IDENTITY } from "../../identity.js";
8
10
  import { snapshotRoots } from "./FilesystemSnapshot.js";
9
11
  import { classifyFilesystemEffects } from "./ProcessFilesystemEffects.js";
10
12
  import { cleanupOwnedProcessGroup, verifyNoTokenOwnedProcesses, } from "../ProcessOwnership.js";
11
13
  import { observeOwnedProcessGroup, prepareProcessOwnershipInspection, systemProcessOwnershipHost, } from "../ProcessOwnershipObservation.js";
12
- import { describeProcessCaptureExecutionFailure, ProcessCaptureError, } from "./ProcessCaptureError.js";
14
+ import { describeProcessCaptureExecutionFailure, normalizeCaptureFailure, ProcessCaptureError, } from "./ProcessCaptureError.js";
13
15
  import { assertNotCancelled } from "./ProcessScenarioRuntimeValidation.js";
14
16
  import { normalizeProcessElapsedTime, normalizeProcessSamples, normalizeProcessText, } from "./ProcessNormalization.js";
15
17
  import { PROCESS_PROVIDER } from "../../domain/process/processEvidenceProvider.js";
16
18
  import { TerminalRenderer } from "./TerminalRenderer.js";
19
+ import { hasCaptureTruncation, } from "../../domain/process/processCaptureCoverage.js";
17
20
  import { scheduleProcessInterval } from "./ProcessTimer.js";
21
+ import { partialProcessCaptureObservationSchema } from "../../domain/process/processCapture.js";
18
22
  /** Seed explicit observation availability before capture completion begins. */
19
23
  export const createProcessCaptureObservationBuffer = (options) => ({
20
24
  target_pid: {
@@ -92,6 +96,9 @@ export const buildCaptureResult = (options) => {
92
96
  const sensitiveInputUnknown = "Sensitive scripted input values are redacted from process capture Evidence.";
93
97
  const filesystemObservationUnknown = "No filesystem observation paths were selected; filesystem effects remain unknown.";
94
98
  const hasFilesystemObservations = options.scenario.filesystem_observation_paths.length > 0;
99
+ const filesystemEffects = classifyFilesystemEffects(options.before, options.after);
100
+ const hasUnknownFilesystemEffects = filesystemEffects.some(({ status }) => status === "unknown");
101
+ const incompleteFilesystemUnknown = "Path absence in incomplete enumeration or below an unfollowed symbolic link remains unknown.";
95
102
  return {
96
103
  manifest: options.manifest,
97
104
  normalization: options.scenario.normalization,
@@ -111,8 +118,13 @@ export const buildCaptureResult = (options) => {
111
118
  event_journal: options.eventJournal,
112
119
  files_before: options.before.files,
113
120
  files_after: options.after.files,
114
- filesystem_effects: classifyFilesystemEffects(options.before.files, options.after.files),
115
- truncated: options.truncated,
121
+ filesystem_effects: filesystemEffects,
122
+ truncated: options.truncationDetails === undefined
123
+ ? options.truncated
124
+ : hasCaptureTruncation(options.truncationDetails),
125
+ ...(options.truncationDetails === undefined
126
+ ? {}
127
+ : { truncation_details: options.truncationDetails }),
116
128
  limitations: [
117
129
  "The executable digest is a prelaunch file sample; matching path metadata immediately after spawn does not prove an atomic operating-system image binding.",
118
130
  "Process trees are sampled and may omit short-lived descendants.",
@@ -122,6 +134,10 @@ export const buildCaptureResult = (options) => {
122
134
  "Filesystem observations are before/after snapshots, not syscall traces.",
123
135
  "Inherited host environment variables are not recorded and may affect results.",
124
136
  ...(!hasFilesystemObservations ? [filesystemObservationUnknown] : []),
137
+ ...(hasUnknownFilesystemEffects ? [incompleteFilesystemUnknown] : []),
138
+ ...(options.truncationDetails === undefined
139
+ ? []
140
+ : captureCoverageUnknowns(options.truncationDetails).map(({ reason }) => reason)),
125
141
  ...(hasSensitiveScriptedInput ? [sensitiveInputUnknown] : []),
126
142
  ],
127
143
  residual_unknowns: [
@@ -149,12 +165,58 @@ export const buildCaptureResult = (options) => {
149
165
  },
150
166
  ]
151
167
  : []),
168
+ ...(hasUnknownFilesystemEffects
169
+ ? [
170
+ {
171
+ scope: "filesystem",
172
+ reason: incompleteFilesystemUnknown,
173
+ },
174
+ ]
175
+ : []),
152
176
  ...(hasSensitiveScriptedInput
153
177
  ? [{ scope: "interaction", reason: sensitiveInputUnknown }]
154
178
  : []),
179
+ ...(options.truncationDetails === undefined
180
+ ? []
181
+ : captureCoverageUnknowns(options.truncationDetails).filter(({ scope }) => scope !== "terminal")),
155
182
  ],
156
183
  };
157
184
  };
185
+ const captureCoverageUnknowns = (details) => {
186
+ const unknowns = [];
187
+ if (details.raw_terminal.observed_frames > details.raw_terminal.retained_frames)
188
+ unknowns.push({
189
+ scope: "terminal",
190
+ reason: "Raw PTY chunks exceeded output_bytes and were omitted; rendered states also lack those inputs. See truncation_details.raw_terminal.",
191
+ });
192
+ if (details.rendered_terminal.observed_frames >
193
+ details.rendered_terminal.retained_frames)
194
+ unknowns.push({
195
+ scope: "terminal",
196
+ reason: "Cumulative rendered state and visible-line bytes exceeded output_bytes; whole rendered frames were omitted. Raw PTY coverage is reported separately. See truncation_details.rendered_terminal.",
197
+ });
198
+ for (const [name, coverage] of [
199
+ ["before", details.filesystem_before],
200
+ ["after_settlement", details.filesystem_after],
201
+ ]) {
202
+ if (coverage.enumeration_truncated)
203
+ unknowns.push({
204
+ scope: "filesystem",
205
+ reason: `Filesystem ${name} path enumeration was incomplete: ${coverage.enumeration_reasons.join(", ")}. See truncation_details.`,
206
+ });
207
+ if (coverage.hash_omissions.length > 0)
208
+ unknowns.push({
209
+ scope: "filesystem",
210
+ reason: `Filesystem ${name} omitted ${String(coverage.hash_omissions.length)} whole-file digests; per-path reasons and remaining file_bytes budget are in truncation_details.`,
211
+ });
212
+ }
213
+ if (details.process.sampling_partial)
214
+ unknowns.push({
215
+ scope: "process",
216
+ reason: "Process sampling stopped with incomplete observations; sample_limit is reported in truncation_details.process.",
217
+ });
218
+ return unknowns;
219
+ };
158
220
  const identityFromStats = (stats) => ({
159
221
  dev: stats.dev,
160
222
  ino: stats.ino,
@@ -301,7 +363,8 @@ export const createRunManifest = async (scenario, startedAt, completedAt, execut
301
363
  normalization_sha256: digestProcessCommitment(scenario.normalization),
302
364
  };
303
365
  };
304
- export const observeSettlement = async (runId, processGroupIds, settleMs, recordEvent = () => undefined, platform = process.platform) => {
366
+ export const observeSettlement = async (runId, processGroupIds, settleMs, recordEvent = () => undefined, platform = process.platform, signal) => {
367
+ assertNotCancelled(signal);
305
368
  if (platform === "win32") {
306
369
  recordEvent("lifecycle", 1);
307
370
  return { state: "unverifiable", elapsed_ms: 0 };
@@ -310,11 +373,9 @@ export const observeSettlement = async (runId, processGroupIds, settleMs, record
310
373
  let consecutiveEmpty = 0;
311
374
  let deadlineReached = false;
312
375
  while (!deadlineReached) {
313
- const observations = await Promise.all([...new Set(processGroupIds)].map((processGroupId) => observeOwnedProcessGroup({
314
- runId,
315
- leaderPid: processGroupId,
316
- processGroupId,
317
- })));
376
+ assertNotCancelled(signal);
377
+ const observations = await Promise.all([...new Set(processGroupIds)].map((processGroupId) => observeOwnedProcessGroup({ runId, leaderPid: processGroupId, processGroupId }, undefined, signal)));
378
+ assertNotCancelled(signal);
318
379
  if (observations.some(({ state }) => state === "unverifiable")) {
319
380
  recordEvent("lifecycle", 1);
320
381
  return { state: "unverifiable", elapsed_ms: Date.now() - started };
@@ -331,7 +392,7 @@ export const observeSettlement = async (runId, processGroupIds, settleMs, record
331
392
  deadlineReached = Date.now() - started >= settleMs;
332
393
  if (deadlineReached)
333
394
  break;
334
- await new Promise((resolve) => setTimeout(resolve, 50));
395
+ await delay(50, undefined, { signal });
335
396
  }
336
397
  recordEvent("lifecycle", 1);
337
398
  return { state: "alive_at_deadline", elapsed_ms: Date.now() - started };
@@ -403,6 +464,50 @@ const verifyTokenOwnedProcessesUntilSettled = async (verify) => {
403
464
  }
404
465
  return result;
405
466
  };
467
+ const releaseCapturedProcessGroup = async (ownership, host) => {
468
+ if (host.platform === "win32")
469
+ return {
470
+ state: "unverified",
471
+ reason: "owned process cleanup is unverifiable on Windows without process-job authority",
472
+ };
473
+ let outcome = {
474
+ state: "cleaned",
475
+ reason: null,
476
+ };
477
+ const unverified = [];
478
+ try {
479
+ const cleaned = await host.cleanupProcessGroup(ownership);
480
+ unverified.push(...(cleaned.unverified ?? []));
481
+ if (!cleaned.cleaned) {
482
+ outcome = { state: "unverified", reason: cleaned.reason };
483
+ }
484
+ else {
485
+ const verified = await verifyTokenOwnedProcessesUntilSettled(() => host.verifyTokenOwnedProcesses(ownership.runId, undefined, ownership.captureBaseline, ownership));
486
+ unverified.push(...(verified.unverified ?? []));
487
+ if (!verified.cleaned)
488
+ outcome = { state: "unverified", reason: verified.reason };
489
+ }
490
+ }
491
+ catch (cause) {
492
+ outcome = {
493
+ state: "failed",
494
+ reason: cause instanceof Error
495
+ ? cause.message || cause.name || "owned process cleanup failed"
496
+ : "owned process cleanup failed",
497
+ };
498
+ }
499
+ return unverified.length === 0
500
+ ? outcome
501
+ : {
502
+ ...outcome,
503
+ unverified_processes: [
504
+ ...new Map(unverified.map(({ pid, diagnostic }) => [
505
+ `${String(pid)}:${diagnostic}`,
506
+ { pid, reason: diagnostic },
507
+ ])).values(),
508
+ ],
509
+ };
510
+ };
406
511
  export const releaseProcessResources = async (options) => {
407
512
  const host = options.host ?? processCaptureCleanupHost;
408
513
  for (const timer of options.timers)
@@ -422,60 +527,20 @@ export const releaseProcessResources = async (options) => {
422
527
  : "renderer dispose failed",
423
528
  };
424
529
  }
425
- let ownedProcessGroup = {
426
- state: options.terminal === undefined ? "not_required" : "cleaned",
427
- reason: null,
428
- };
429
- if (options.terminal !== undefined) {
430
- if (host.platform === "win32") {
431
- ownedProcessGroup = {
432
- state: "unverified",
433
- reason: "owned process cleanup is unverifiable on Windows without process-job authority",
434
- };
435
- }
436
- else {
437
- const terminalPid = options.terminal.pid;
438
- const relation = {
439
- leaderPid: terminalPid,
440
- processGroupId: terminalPid,
441
- ...(options.sampledProcessGroupIds === undefined
442
- ? {}
443
- : { sampledProcessGroupIds: options.sampledProcessGroupIds }),
444
- };
445
- const cleaned = await host.cleanupProcessGroup({
446
- runId: options.runId,
447
- leaderPid: terminalPid,
448
- processGroupId: terminalPid,
449
- sweepTokenOwnedProcesses: true,
450
- ...(options.sampledProcessGroupIds === undefined
451
- ? {}
452
- : { sampledProcessGroupIds: options.sampledProcessGroupIds }),
453
- ...(options.captureBaseline === undefined
454
- ? {}
455
- : { captureBaseline: options.captureBaseline }),
456
- });
457
- const unverified = [...(cleaned.unverified ?? [])];
458
- if (!cleaned.cleaned) {
459
- ownedProcessGroup = { state: "unverified", reason: cleaned.reason };
460
- }
461
- else {
462
- const verified = await verifyTokenOwnedProcessesUntilSettled(() => host.verifyTokenOwnedProcesses(options.runId, undefined, options.captureBaseline, relation));
463
- unverified.push(...(verified.unverified ?? []));
464
- if (!verified.cleaned)
465
- ownedProcessGroup = { state: "unverified", reason: verified.reason };
466
- }
467
- if (unverified.length > 0)
468
- ownedProcessGroup = {
469
- ...ownedProcessGroup,
470
- unverified_processes: [
471
- ...new Map(unverified.map(({ pid, diagnostic }) => [
472
- `${String(pid)}:${diagnostic}`,
473
- { pid, reason: diagnostic },
474
- ])).values(),
475
- ],
476
- };
477
- }
478
- }
530
+ const ownedProcessGroup = options.terminal === undefined
531
+ ? { state: "not_required", reason: null }
532
+ : await releaseCapturedProcessGroup({
533
+ runId: options.runId,
534
+ leaderPid: options.terminal.pid,
535
+ processGroupId: options.terminal.pid,
536
+ sweepTokenOwnedProcesses: true,
537
+ ...(options.sampledProcessGroupIds === undefined
538
+ ? {}
539
+ : { sampledProcessGroupIds: options.sampledProcessGroupIds }),
540
+ ...(options.captureBaseline === undefined
541
+ ? {}
542
+ : { captureBaseline: options.captureBaseline }),
543
+ }, host);
479
544
  let temporaryRoot = {
480
545
  state: "cleaned",
481
546
  reason: null,
@@ -507,12 +572,14 @@ export const cleanupReportFailure = (report) => {
507
572
  };
508
573
  export const captureTerminalFrames = (options) => {
509
574
  let outputBytes = 0;
510
- let truncated = false;
575
+ let observedBytes = 0;
576
+ let observedFrames = 0;
511
577
  options.terminal.onData((data) => {
512
578
  options.onOutput();
513
579
  const bytes = Buffer.byteLength(data);
580
+ observedBytes += bytes;
581
+ observedFrames += 1;
514
582
  if (outputBytes + bytes > options.scenario.limits.output_bytes) {
515
- truncated = true;
516
583
  return;
517
584
  }
518
585
  outputBytes += bytes;
@@ -523,11 +590,18 @@ export const captureTerminalFrames = (options) => {
523
590
  sequence,
524
591
  at_ms: atMs,
525
592
  data: normalized,
593
+ ...(normalized === data ? {} : { raw_data: data }),
526
594
  });
527
595
  options.renderer.write(data, atMs);
528
596
  options.recordEvent("frames", sequence);
529
597
  });
530
- return () => truncated;
598
+ return () => ({
599
+ budget_bytes: options.scenario.limits.output_bytes,
600
+ observed_bytes: observedBytes,
601
+ retained_bytes: outputBytes,
602
+ observed_frames: observedFrames,
603
+ retained_frames: options.frames.length,
604
+ });
531
605
  };
532
606
  export const resolveProcessResult = (capture, executionFailure, cleanup, observations, partialContext) => {
533
607
  const cleanupFailure = cleanupReportFailure(cleanup);
@@ -660,16 +734,30 @@ export const prepareProcessCapture = async (scenario, signal, captureSnapshot =
660
734
  await host.prepareOwnershipInspector?.(signal);
661
735
  assertNotCancelled(signal);
662
736
  const before = await captureSnapshot(scenario, signal);
737
+ const runId = randomUUID();
663
738
  const temporaryRoot = await host.createTemporaryRoot();
664
739
  try {
665
740
  assertNotCancelled(signal);
666
- const runId = randomUUID();
667
741
  const ownershipBaseline = (await host.captureOwnershipBaseline?.(signal)) ?? [];
668
742
  assertNotCancelled(signal);
669
743
  return { temporaryRoot, runId, ownershipBaseline, before };
670
744
  }
671
745
  catch (cause) {
672
- await host.cleanup(temporaryRoot);
746
+ const cleanup = await releaseProcessResources({
747
+ timers: new Set(),
748
+ terminal: undefined,
749
+ renderer: undefined,
750
+ runId,
751
+ temporaryRoot,
752
+ host: { ...processCaptureCleanupHost, removeTemporaryRoot: host.cleanup },
753
+ });
754
+ resolveProcessResult(undefined, normalizeCaptureFailure(cause, signal), cleanup, createProcessCaptureObservationBuffer({
755
+ frames: [],
756
+ interactions: [],
757
+ samples: [],
758
+ eventJournal: [],
759
+ before,
760
+ }), { scenario });
673
761
  throw cause;
674
762
  }
675
763
  };
@@ -1,12 +1,42 @@
1
- /** Classify path-stable filesystem effects between two bounded states. */
1
+ import { sep } from "node:path";
2
+ const unobservedAbsenceReason = (path, phase, completeRoots, filesByPath) => {
3
+ const alias = path.slice(0, path.indexOf(":"));
4
+ if (!completeRoots.has(alias))
5
+ return `The ${phase} snapshot did not exhaust path enumeration under ${alias}; absence remains unknown.`;
6
+ const rootPath = `${alias}:.`;
7
+ if (path !== rootPath && filesByPath.get(rootPath)?.type === "symlink")
8
+ return `The ${phase} snapshot did not follow the symbolic link at ${rootPath}; descendant absence remains unknown.`;
9
+ for (let index = path.lastIndexOf(sep); index > 0; index = path.lastIndexOf(sep, index - 1)) {
10
+ const parent = path.slice(0, index);
11
+ if (filesByPath.get(parent)?.type === "symlink")
12
+ return `The ${phase} snapshot did not follow the symbolic link at ${parent}; descendant absence remains unknown.`;
13
+ }
14
+ return undefined;
15
+ };
16
+ /** Classify effects only when a snapshot establishes the missing path's absence. */
2
17
  export const classifyFilesystemEffects = (before, after) => {
3
- const beforeByPath = new Map(before.map((file) => [file.path, file]));
4
- const afterByPath = new Map(after.map((file) => [file.path, file]));
18
+ const beforeByPath = new Map(before.files.map((file) => [file.path, file]));
19
+ const afterByPath = new Map(after.files.map((file) => [file.path, file]));
20
+ const beforeCompleteRoots = new Set(before.completeRoots);
21
+ const afterCompleteRoots = new Set(after.completeRoots);
5
22
  return [...new Set([...beforeByPath.keys(), ...afterByPath.keys()])]
6
23
  .sort()
7
24
  .map((path) => {
8
25
  const beforeFile = beforeByPath.get(path) ?? null;
9
26
  const afterFile = afterByPath.get(path) ?? null;
27
+ const reason = beforeFile === null
28
+ ? unobservedAbsenceReason(path, "before", beforeCompleteRoots, beforeByPath)
29
+ : afterFile === null
30
+ ? unobservedAbsenceReason(path, "after", afterCompleteRoots, afterByPath)
31
+ : undefined;
32
+ if (reason !== undefined)
33
+ return {
34
+ path,
35
+ status: "unknown",
36
+ before: beforeFile,
37
+ after: afterFile,
38
+ reason,
39
+ };
10
40
  if (beforeFile === null) {
11
41
  if (afterFile === null)
12
42
  throw new TypeError(`Filesystem effect ${path} has no file state`);
@@ -1,9 +1,8 @@
1
- import { parseProcessCapture } from "../../domain/process/processCapture.js";
1
+ import { parseProcessCapture } from "../../domain/process/processCaptureParsing.js";
2
2
  import { err, ok } from "../../domain/result.js";
3
3
  import { AnalysisCapabilityUnavailableError } from "../../domain/analysisErrorCore.js";
4
4
  import {} from "../../domain/analysisErrorBase.js";
5
- import { describeProcessCaptureExecutionFailure, ProcessCaptureError, processCaptureCancelled, } from "./ProcessCaptureError.js";
6
- export { ProcessCaptureError } from "./ProcessCaptureError.js";
5
+ import { describeProcessCaptureExecutionFailure, ProcessCaptureError, normalizeCaptureFailure, processCaptureCancelled, } from "./ProcessCaptureError.js";
7
6
  import { startProcessSampler } from "./ProcessSampling.js";
8
7
  import { snapshotRoots } from "./FilesystemSnapshot.js";
9
8
  import { TerminalRenderer } from "./TerminalRenderer.js";
@@ -15,14 +14,11 @@ import { createProcessCaptureJournal, scheduleScenarioInteractions, } from "./Pr
15
14
  import { makeProcessCaptureEnvironment } from "./ProcessCaptureEnvironment.js";
16
15
  import { classifyFilesystemEffects } from "./ProcessFilesystemEffects.js";
17
16
  import { processCaptureOwnershipUnavailableReason } from "./ProcessCaptureCapability.js";
18
- import { DarwinProcessOwnershipInspectionError } from "../DarwinProcessRunTokenReader.js";
19
- export { probeProcessCaptureCapability } from "./ProcessCaptureCapability.js";
20
17
  const cleanupFailedStartup = async (options) => {
21
18
  const sampledProcessGroupIds = options.terminal !== undefined &&
22
19
  options.observations?.process_samples.state === "available"
23
20
  ? selectCapturedProcessGroupIds(options.terminal.pid, options.observations.process_samples.value).filter((groupId) => groupId !== options.terminal?.pid)
24
21
  : undefined;
25
- options.terminal?.kill("SIGKILL");
26
22
  if (options.observations !== undefined && options.renderer !== undefined) {
27
23
  try {
28
24
  options.observations.rendered_frames = {
@@ -89,7 +85,7 @@ const startCaptureRuntime = async (options) => {
89
85
  value: scenario.normalization.pids ? 1 : terminal.pid,
90
86
  };
91
87
  const executableIdentity = observeLaunchedExecutable(scenario.executable, selectedExecutable);
92
- const framesTruncated = captureTerminalFrames({
88
+ const rawTerminalRetention = captureTerminalFrames({
93
89
  ...options,
94
90
  terminal,
95
91
  started,
@@ -117,7 +113,7 @@ const startCaptureRuntime = async (options) => {
117
113
  startedAt,
118
114
  executableIdentity,
119
115
  lastOutput: () => lastOutput,
120
- framesTruncated,
116
+ rawTerminalRetention,
121
117
  stopSampler,
122
118
  };
123
119
  }
@@ -181,18 +177,6 @@ const finishProcessRun = async (options) => {
181
177
  : { scenario: options.scenario, rootPid };
182
178
  return resolveProcessResult(cleanupFailure === undefined ? verifiedCapture : capture, executionFailure, cleanup, options.observations, partialContext);
183
179
  };
184
- /** Preserve typed process-inspection preflight failures at the capture boundary. */
185
- export const normalizeCaptureFailure = (cause, signal) => {
186
- if (cause instanceof ProcessCaptureError)
187
- return cause;
188
- if (cause instanceof DarwinProcessOwnershipInspectionError)
189
- return new ProcessCaptureError(cause.message, { cause });
190
- if (signal?.aborted === true &&
191
- (cause === signal.reason ||
192
- (cause instanceof Error && cause.name === "AbortError")))
193
- return processCaptureCancelled();
194
- return cause;
195
- };
196
180
  const completeCapture = async (options) => {
197
181
  const unavailableReason = (stage, cause) => `${stage} failed: ${cause instanceof Error ? cause.message : "unknown failure"}`;
198
182
  const { runtime, scenario } = options;
@@ -201,7 +185,7 @@ const completeCapture = async (options) => {
201
185
  throw processCaptureCancelled();
202
186
  let settlement;
203
187
  try {
204
- settlement = await observeSettlement(options.runId, selectCapturedProcessGroupIds(runtime.terminal.pid, options.samples), scenario.settle_ms, options.recordEvent, options.hostPlatform);
188
+ settlement = await observeSettlement(options.runId, selectCapturedProcessGroupIds(runtime.terminal.pid, options.samples), scenario.settle_ms, options.recordEvent, options.hostPlatform, options.signal);
205
189
  }
206
190
  catch (cause) {
207
191
  options.observationBuffer.settlement = {
@@ -214,7 +198,8 @@ const completeCapture = async (options) => {
214
198
  state: "available",
215
199
  value: settlement,
216
200
  };
217
- const samplingPartial = (await runtime.stopSampler()).partial;
201
+ const sampling = await runtime.stopSampler();
202
+ const samplingPartial = sampling.partial;
218
203
  await settleProcessCaptureJournal(options.eventJournal);
219
204
  assertNotCancelled(options.signal);
220
205
  let after;
@@ -266,7 +251,7 @@ const completeCapture = async (options) => {
266
251
  name: "after_settlement",
267
252
  at_ms: Math.max(0, Date.now() - runtime.started),
268
253
  files: after.files,
269
- effects: classifyFilesystemEffects(options.before.files, after.files),
254
+ effects: classifyFilesystemEffects(options.before, after),
270
255
  truncated: after.truncated,
271
256
  },
272
257
  ];
@@ -284,7 +269,8 @@ const completeCapture = async (options) => {
284
269
  options.observationBuffer.manifest = { state: "available", value: manifest };
285
270
  const truncated = options.initiallyTruncated ||
286
271
  after.truncated ||
287
- runtime.framesTruncated() ||
272
+ runtime.rawTerminalRetention().observed_frames >
273
+ runtime.rawTerminalRetention().retained_frames ||
288
274
  checkpoints.some(({ truncated: partial }) => partial) ||
289
275
  samplingPartial ||
290
276
  runtime.renderer.truncated();
@@ -295,6 +281,17 @@ const completeCapture = async (options) => {
295
281
  before: options.before,
296
282
  after,
297
283
  truncated,
284
+ ...(options.before.coverage === undefined || after.coverage === undefined
285
+ ? {}
286
+ : {
287
+ truncationDetails: {
288
+ raw_terminal: runtime.rawTerminalRetention(),
289
+ rendered_terminal: runtime.renderer.retention(),
290
+ filesystem_before: options.before.coverage,
291
+ filesystem_after: after.coverage,
292
+ process: sampling.coverage,
293
+ },
294
+ }),
298
295
  scenario,
299
296
  rootPid: runtime.terminal.pid,
300
297
  samplingPartial,
@@ -389,7 +386,6 @@ const runProcessScenario = async (scenario, signal, hostEnvironment = process.en
389
386
  });
390
387
  }
391
388
  catch (cause) {
392
- runtime?.terminal.kill("SIGKILL");
393
389
  executionFailure = normalizeCaptureFailure(cause, signal);
394
390
  if (runtime !== undefined &&
395
391
  observations.rendered_frames.state === "unavailable" &&
@@ -1,3 +1,4 @@
1
+ import { isIP } from "node:net";
1
2
  /** Bucket one elapsed process-capture timestamp under scenario normalization. */
2
3
  export const normalizeProcessElapsedTime = (elapsedMs, timeBucketMs) => Math.floor(elapsedMs / timeBucketMs) * timeBucketMs;
3
4
  /** Normalize one terminal/protocol payload under explicitly selected scenario rules. */
@@ -10,14 +11,31 @@ export const normalizeProcessText = (value, scenario, temporaryRoot, pid) => {
10
11
  for (const [index, root] of scenario.filesystem_observation_paths.entries())
11
12
  normalized = normalized.replaceAll(root, `<filesystem-root-${String(index)}>`);
12
13
  }
14
+ if (scenario.normalization.ports)
15
+ normalized = normalizePortTokens(normalized);
13
16
  if (scenario.normalization.pids)
14
17
  normalized = normalizePidTokens(normalized, [pid]);
15
- if (scenario.normalization.ports)
16
- normalized = normalized.replaceAll(/(?<=[:=])\d{2,5}\b/g, "<port>");
17
18
  for (const pattern of scenario.normalization.patterns)
18
19
  normalized = normalized.replaceAll(pattern.pattern, pattern.replacement);
19
20
  return normalized;
20
21
  };
22
+ // A port may end a sentence, but a period followed by a letter, digit, or
23
+ // underscore in any script continues a decimal, version, or host name and is
24
+ // not a port boundary.
25
+ // PTY chunks are normalized independently, so a period that ends the chunk
26
+ // stays unnormalized: its continuation may arrive in the next chunk.
27
+ const normalizePortTokens = (value) => {
28
+ const endpointNormalized = value.replaceAll(/(\b[a-z][a-z0-9+.-]*:\/\/[^\s/?#"'<>]+|\blocalhost|\b(?:\d{1,3}\.){3}\d{1,3}|\[[\da-f:.%]+\]):(\d{1,5})(?![\p{L}\p{N}_@:]|\.(?:[\p{L}\p{N}_]|$))/giu, (match, endpoint, port) => {
29
+ if (Number(port) > 65_535)
30
+ return match;
31
+ const isEndpoint = endpoint.includes("://")
32
+ ? URL.canParse(`${endpoint}:${port}`)
33
+ : endpoint.toLowerCase() === "localhost" ||
34
+ isIP(endpoint.replace(/^\[|\]$/gu, "")) !== 0;
35
+ return isEndpoint ? `${endpoint}:<port>` : match;
36
+ });
37
+ return endpointNormalized.replaceAll(/(\b(?:port|tcp_port|udp_port|listen)\b["']?\s*[:=]\s*)(\d{1,5})(?![\p{L}\p{N}_]|\.(?:[\p{L}\p{N}_]|$))/giu, (match, prefix, port) => Number(port) <= 65_535 ? `${prefix}<port>` : match);
38
+ };
21
39
  /** Project sampled observations under the caller-selected normalization rules. */
22
40
  export const normalizeProcessSamples = (samples, scenario, rootPid) => {
23
41
  const identifiers = [
@@ -328,6 +328,9 @@ export const startProcessSampler = (options) => {
328
328
  let stopped = false;
329
329
  let abortCurrent;
330
330
  let partial = false;
331
+ let limitReached = false;
332
+ let samplingFailures = 0;
333
+ let firstSamplingFailure = null;
331
334
  let rootInitialized = false;
332
335
  const sample = () => {
333
336
  if (stopped || pending !== undefined)
@@ -363,6 +366,7 @@ export const startProcessSampler = (options) => {
363
366
  continue;
364
367
  if (samples.length >= limit) {
365
368
  partial = true;
369
+ limitReached = true;
366
370
  continue;
367
371
  }
368
372
  lastObservations.set(value.pid, observation);
@@ -372,8 +376,16 @@ export const startProcessSampler = (options) => {
372
376
  }
373
377
  })
374
378
  .catch((cause) => {
375
- if (!(cause instanceof Error && cause.name === "AbortError"))
379
+ if (!(cause instanceof Error && cause.name === "AbortError")) {
376
380
  partial = true;
381
+ samplingFailures += 1;
382
+ firstSamplingFailure ??=
383
+ cause instanceof Error
384
+ ? `${cause.name}: ${cause.message}`
385
+ : typeof cause === "string"
386
+ ? cause
387
+ : `Unexpected sampling rejection (${typeof cause})`;
388
+ }
377
389
  })
378
390
  .then(() => {
379
391
  abortCurrent = undefined;
@@ -387,6 +399,17 @@ export const startProcessSampler = (options) => {
387
399
  clearInterval(timer);
388
400
  abortCurrent?.();
389
401
  await pending;
390
- return { partial };
402
+ return {
403
+ partial,
404
+ coverage: {
405
+ sample_limit: limit,
406
+ sampling_partial: partial,
407
+ retained_samples: samples.length,
408
+ sample_limit_reached: limitReached,
409
+ sampling_failures: samplingFailures,
410
+ first_sampling_failure: firstSamplingFailure,
411
+ coverage: "sampled",
412
+ },
413
+ };
391
414
  };
392
415
  };
@@ -19,6 +19,8 @@ export class TerminalRenderer {
19
19
  #frames = [];
20
20
  #pending = Promise.resolve();
21
21
  #capturedBytes = 0;
22
+ #observedBytes = 0;
23
+ #observedFrames = 0;
22
24
  #truncated = false;
23
25
  constructor(options) {
24
26
  this.options = options;
@@ -55,6 +57,16 @@ export class TerminalRenderer {
55
57
  truncated() {
56
58
  return this.#truncated;
57
59
  }
60
+ /** Budget accounting after awaiting queued writes with frames(). */
61
+ retention() {
62
+ return {
63
+ budget_bytes: this.options.maxBytes,
64
+ observed_bytes: this.#observedBytes,
65
+ retained_bytes: this.#capturedBytes,
66
+ observed_frames: this.#observedFrames,
67
+ retained_frames: this.#frames.length,
68
+ };
69
+ }
58
70
  /** Release addon and terminal resources after all writes settle. */
59
71
  async dispose() {
60
72
  await this.#pending;
@@ -71,6 +83,8 @@ export class TerminalRenderer {
71
83
  const serializedState = this.options.normalize(this.#serializeAddon.serialize());
72
84
  const bytes = Buffer.byteLength(serializedState) +
73
85
  lines.reduce((total, line) => total + Buffer.byteLength(line), 0);
86
+ this.#observedBytes += bytes;
87
+ this.#observedFrames += 1;
74
88
  if (this.#capturedBytes + bytes > this.options.maxBytes) {
75
89
  this.#truncated = true;
76
90
  return;
@@ -0,0 +1,14 @@
1
+ /** Snapshot caller-selected variables using Node child-process key semantics. */
2
+ export const snapshotEnvironment = (environment, platform = process.platform) => {
3
+ if (platform !== "win32")
4
+ return Object.freeze({ ...environment });
5
+ const snapshot = {};
6
+ // Node sorts keys lexicographically and forwards the first case-insensitive
7
+ // match on Windows. Canonical keys also make subsequent lookups deterministic.
8
+ for (const key of Object.keys(environment).sort()) {
9
+ const canonicalKey = key.toUpperCase();
10
+ if (!Object.hasOwn(snapshot, canonicalKey))
11
+ snapshot[canonicalKey] = environment[key];
12
+ }
13
+ return Object.freeze(snapshot);
14
+ };