rea-agents 6.0.0 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (343) hide show
  1. package/README.md +23 -17
  2. package/bridge/android/ReaJadxBridge.java +14 -5
  3. package/bridge/ghidra/ReaGhidraBridge.java +173 -47
  4. package/bridge/hopper_bridge.py +310 -128
  5. package/bridge/mitmproxy/capture.py +0 -2
  6. package/bridge/native/rea_lldb_tracer.py +630 -94
  7. package/bridge/process/ProcessRunTokenReader.swift +39 -5
  8. package/bridge/pwntools/recorded_crash_impl.py +4 -0
  9. package/dist/android/JadxConfiguration.js +196 -33
  10. package/dist/android/JadxMcpTransport.js +4 -0
  11. package/dist/android/JadxProtocol.js +6 -0
  12. package/dist/android/JadxProvider.js +19 -2
  13. package/dist/android/JadxSession.js +23 -4
  14. package/dist/application/AnalysisContextQueries.js +8 -35
  15. package/dist/application/AnalysisDocument.js +32 -0
  16. package/dist/application/AppBundleExecutable.js +67 -21
  17. package/dist/application/CallPathTracing.js +19 -3
  18. package/dist/application/CapabilityInventory.js +6 -3
  19. package/dist/application/ClientConfigurationDocument.js +871 -6
  20. package/dist/application/ClientRegistrationIdentity.js +26 -5
  21. package/dist/application/ClientRegistrationStatus.js +29 -14
  22. package/dist/application/DirectAnalysis.js +27 -37
  23. package/dist/application/Doctor.js +4 -2
  24. package/dist/application/DoctorScope.js +25 -13
  25. package/dist/application/EnhancedLiteralTracing.js +22 -25
  26. package/dist/application/EnhancedTools.js +13 -11
  27. package/dist/application/EvidenceBundleFiles.js +23 -11
  28. package/dist/application/FunctionAnalysisEvidence.js +2 -3
  29. package/dist/application/InventoryProjectionEvidence.js +4 -3
  30. package/dist/application/InvestigationProviders.js +3 -2
  31. package/dist/application/JsonFiles.js +50 -28
  32. package/dist/application/ProcedureAddressResolution.js +11 -0
  33. package/dist/application/ReconstructionCoverageService.js +7 -4
  34. package/dist/application/ReconstructionObligationLedgerService.js +4 -3
  35. package/dist/application/Setup.js +13 -1
  36. package/dist/application/SetupClientConfiguration.js +10 -15
  37. package/dist/application/SetupHost.js +5 -2
  38. package/dist/application/SetupPlan.js +5 -3
  39. package/dist/application/SupportedClients.js +34 -1
  40. package/dist/application/Uninstall.js +4 -3
  41. package/dist/application/Update.js +18 -3
  42. package/dist/application/UpdateRuntime.js +46 -25
  43. package/dist/application/WebModuleTraceService.js +4 -2
  44. package/dist/application/WebNetworkCaptureService.js +4 -2
  45. package/dist/application/WebRuntimeService.js +5 -3
  46. package/dist/application/WebScriptExportService.js +2 -2
  47. package/dist/application/WebSourceLocationService.js +4 -2
  48. package/dist/application/WorkflowEvidence.js +82 -0
  49. package/dist/application/binary/AnalysisProviderEvaluation.js +21 -5
  50. package/dist/application/binary/AnalysisProviderRegistry.js +2 -0
  51. package/dist/application/binary/AnalysisSnapshotCache.js +3 -6
  52. package/dist/application/binary/BinarySession.js +95 -68
  53. package/dist/application/binary/BinarySessionOpen.js +3 -3
  54. package/dist/application/binary/BinarySessionRecords.js +25 -3
  55. package/dist/application/binary/BinarySessionStatus.js +17 -1
  56. package/dist/application/binary/CompositeProvider.js +13 -0
  57. package/dist/application/binary/LazyAnalysisProvider.js +3 -0
  58. package/dist/application/binaryDiagnostics/BinaryLayoutService.js +4 -2
  59. package/dist/application/binaryDiagnostics/RecordedCrashService.js +4 -2
  60. package/dist/application/evm/EvmInterfaceService.js +4 -2
  61. package/dist/application/investigation/EvidenceLedger.js +21 -7
  62. package/dist/application/investigation/InvestigationRecords.js +8 -0
  63. package/dist/application/javascript/JavaScriptAnalysisControl.js +34 -0
  64. package/dist/application/javascript/JavaScriptApplicationEvidence.js +24 -3
  65. package/dist/application/javascript/JavaScriptApplicationEvidenceGraph.js +19 -2
  66. package/dist/application/javascript/JavaScriptApplicationService.js +22 -15
  67. package/dist/application/javascript/JavaScriptApplicationWorkflowService.js +5 -5
  68. package/dist/application/javascript/JavaScriptArtifactAnalysis.js +5 -4
  69. package/dist/application/javascript/JavaScriptArtifactGraphBuilder.js +39 -7
  70. package/dist/application/javascript/JavaScriptArtifactPathResolution.js +6 -3
  71. package/dist/application/javascript/JavaScriptArtifactReconstruction.js +11 -3
  72. package/dist/application/javascript/JavaScriptModuleRelationships.js +37 -8
  73. package/dist/application/javascript/JavaScriptRecoveryService.js +4 -2
  74. package/dist/application/javascript/JavaScriptRuntimeObservationService.js +3 -1
  75. package/dist/application/javascript/JavaScriptRuntimeReconciliationService.js +3 -3
  76. package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +63 -61
  77. package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +23 -1
  78. package/dist/application/managed/ManagedApplicationGraphService.js +4 -3
  79. package/dist/application/managed/ManagedMemberComparisonService.js +7 -4
  80. package/dist/application/managed/ManagedNativeVerificationService.js +4 -3
  81. package/dist/application/managed/ManagedReconstructionService.js +4 -3
  82. package/dist/application/process/ProcessCli.js +14 -6
  83. package/dist/application/process/ProcessEvidence.js +4 -3
  84. package/dist/application/workflowInputError.js +18 -0
  85. package/dist/artifacts/ArtifactProvider.js +12 -2
  86. package/dist/artifacts/MachOSliceArtifactReader.js +98 -14
  87. package/dist/artifacts/NativeDmgArtifactReader.js +13 -6
  88. package/dist/artifacts/apple/AppleAssetCatalogAnalysis.js +22 -3
  89. package/dist/artifacts/apple/InterfaceBuilderAnalysis.js +176 -56
  90. package/dist/artifacts/apple/InterfaceBuilderDecodeBudget.js +195 -0
  91. package/dist/artifacts/apple/KeyedArchiveReader.js +36 -22
  92. package/dist/artifacts/apple/MachoLoadCommandReader.js +92 -31
  93. package/dist/artifacts/apple/NibArchive.js +81 -14
  94. package/dist/artifacts/apple/NibViewHierarchy.js +10 -3
  95. package/dist/artifacts/apple/PlistNumberLiterals.js +164 -0
  96. package/dist/artifacts/inventory/ArtifactGraphConstruction.js +13 -8
  97. package/dist/artifacts/inventory/scanCanonical.js +11 -14
  98. package/dist/artifacts/javascript/JavaScriptArtifactFiles.js +6 -2
  99. package/dist/browser/CdpCaptureCompleteness.js +2 -0
  100. package/dist/browser/CdpCaptureEventHandlers.js +76 -11
  101. package/dist/browser/CdpCaptureEventTypes.js +5 -1
  102. package/dist/browser/CdpCaptureEvents.js +25 -0
  103. package/dist/browser/CdpConnection.js +30 -11
  104. package/dist/browser/CdpOptionalCommand.js +2 -3
  105. package/dist/browser/CdpPageCapture.js +23 -1
  106. package/dist/browser/PlaywrightElectronActiveActions.js +32 -23
  107. package/dist/browser/PlaywrightElectronActiveProjection.js +141 -0
  108. package/dist/browser/PlaywrightElectronActiveProvider.js +123 -124
  109. package/dist/browser/WebSourceMapFetcher.js +426 -72
  110. package/dist/browser/assets/LocalWebScriptArtifacts.js +2 -2
  111. package/dist/browser/history/CaptureFailures.js +37 -1
  112. package/dist/browser/history/CaptureRelease.js +5 -0
  113. package/dist/browser/history/HarCaptureAdapter.js +3 -3
  114. package/dist/browser/history/HarJson.js +3 -2
  115. package/dist/browser/history/HistoricalCaptureDecoder.js +4 -2
  116. package/dist/cli/analysisSelector.js +23 -0
  117. package/dist/cli/applicationCommands.js +2 -3
  118. package/dist/cli/coreBinaryCommands.js +70 -12
  119. package/dist/cli/electronCommands.js +7 -6
  120. package/dist/cli/javascriptApplicationAnalysis.js +7 -3
  121. package/dist/cli/jsonOutput.js +4 -99
  122. package/dist/cli/nativeCallCommands.js +2 -3
  123. package/dist/cli/webRuntimeCommands.js +8 -8
  124. package/dist/cli.js +2 -1
  125. package/dist/cliCommandNames.js +0 -1
  126. package/dist/cliJsonInput.js +9 -4
  127. package/dist/config/environment.js +4 -0
  128. package/dist/config/ghidraStartupTimeout.js +17 -0
  129. package/dist/config/mcpResponseBudget.js +22 -0
  130. package/dist/config/parseConfig.js +2 -1
  131. package/dist/contracts/enhancedInputs.js +5 -3
  132. package/dist/contracts/enhancedToolContracts.js +3 -3
  133. package/dist/contracts/hopperMemoryContracts.js +2 -5
  134. package/dist/contracts/javascript/electronToolContracts.js +1 -1
  135. package/dist/contracts/managed/managedToolContracts.js +2 -4
  136. package/dist/contracts/native/nativeToolContracts.js +4 -2
  137. package/dist/contracts/officialToolContracts.js +14 -15
  138. package/dist/contracts/promptContracts.js +3 -3
  139. package/dist/contracts/sessionLifecycleInputs.js +3 -7
  140. package/dist/contracts/sessionStatusContract.js +2 -4
  141. package/dist/contracts/sessionToolContracts.js +4 -6
  142. package/dist/contracts/sessionToolSchemas.js +2 -5
  143. package/dist/contracts/toolContractExamples.js +0 -1
  144. package/dist/contracts/toolContractHelpers.js +4 -1
  145. package/dist/contracts/toolEffects.js +0 -1
  146. package/dist/contracts/toolOutputSchemaGroups.js +28 -27
  147. package/dist/contracts/toolOutputSchemaPrimitives.js +18 -0
  148. package/dist/contracts/toolSchemaMetadata.js +69 -10
  149. package/dist/contracts/webNetworkCaptureToolContracts.js +1 -1
  150. package/dist/domain/analysisErrorBase.js +8 -3
  151. package/dist/domain/analysisErrorCore.js +3 -1
  152. package/dist/domain/analysisErrorPresentation.js +72 -17
  153. package/dist/domain/analysisErrorProjection.js +106 -27
  154. package/dist/domain/android/androidAnalysis.js +2 -4
  155. package/dist/domain/android/androidApplication.js +17 -9
  156. package/dist/domain/apple/appleApplication.js +41 -14
  157. package/dist/domain/apple/dyldEnvironment.js +73 -0
  158. package/dist/domain/apple/dylibResolution.js +120 -9
  159. package/dist/domain/apple/dylibResolutionFindings.js +9 -7
  160. package/dist/domain/apple/interfaceBuilderGraph.js +25 -13
  161. package/dist/domain/apple/interfaceBuilderKeyedArchive.js +13 -3
  162. package/dist/domain/apple/keyedArchive.js +9 -1
  163. package/dist/domain/apple/machoContainer.js +54 -0
  164. package/dist/domain/apple/plistNumbers.js +76 -0
  165. package/dist/domain/artifactIdentity.js +29 -0
  166. package/dist/domain/artifactInventoryEvidence.js +19 -24
  167. package/dist/domain/bridgeCandidateProjection.js +71 -0
  168. package/dist/domain/browserCompleteness.js +1 -0
  169. package/dist/domain/browserObservationError.js +24 -5
  170. package/dist/domain/browserScenarioValues.js +2 -6
  171. package/dist/domain/bundleComparison.js +3 -2
  172. package/dist/domain/canonicalJsonDigestSteps.js +133 -0
  173. package/dist/domain/canonicalOrdering.js +9 -5
  174. package/dist/domain/changedBehavior.js +6 -6
  175. package/dist/domain/comparisonSourceEvidence.js +40 -0
  176. package/dist/domain/configurationErrors.js +1 -1
  177. package/dist/domain/evidence.js +64 -9
  178. package/dist/domain/evidenceBundle.js +42 -1
  179. package/dist/domain/evidenceErrors.js +12 -1
  180. package/dist/domain/explicitSensitiveFailure.js +17 -1
  181. package/dist/domain/firmware/firmwareAnalysis.js +6 -7
  182. package/dist/domain/hopperErrors.js +23 -2
  183. package/dist/domain/hopperValues.js +51 -8
  184. package/dist/domain/immutableJson.js +114 -0
  185. package/dist/domain/inputIssueProjection.js +3 -0
  186. package/dist/domain/javascript/electronActiveObservation.js +30 -4
  187. package/dist/domain/javascript/electronStaticAnalysisValues.js +6 -12
  188. package/dist/domain/javascript/javascriptApplicationAnalysis.js +71 -23
  189. package/dist/domain/javascript/javascriptApplicationGraph.js +13 -0
  190. package/dist/domain/javascript/javascriptAstValues.js +20 -0
  191. package/dist/domain/javascript/javascriptRecovery.js +3 -8
  192. package/dist/domain/javascript/javascriptSemanticAnalysis.js +97 -2
  193. package/dist/domain/javascript/javascriptSemanticCoverage.js +6 -5
  194. package/dist/domain/javascript/javascriptSemanticDataEffectHelpers.js +9 -17
  195. package/dist/domain/javascript/javascriptSemanticDataEffects.js +22 -5
  196. package/dist/domain/javascript/javascriptSemanticGraph.js +13 -0
  197. package/dist/domain/javascript/javascriptSemanticGraphSchemas.js +1 -0
  198. package/dist/domain/javascript/javascriptSemanticPrimitives.js +25 -17
  199. package/dist/domain/javascript/javascriptSemanticQuerySchemas.js +8 -4
  200. package/dist/domain/javascript/javascriptSemanticResourceLimits.js +77 -0
  201. package/dist/domain/javascript/javascriptSemanticValues.js +83 -11
  202. package/dist/domain/javascript/javascriptSourceParser.js +6 -2
  203. package/dist/domain/javascript/javascriptStaticAnalysis.js +22 -17
  204. package/dist/domain/javascript/javascriptStaticAnalysisBundler.js +5 -3
  205. package/dist/domain/javascript/javascriptStaticAnalysisCalls.js +14 -4
  206. package/dist/domain/javascript/javascriptStaticAnalysisFindings.js +66 -7
  207. package/dist/domain/javascript/javascriptStaticAnalysisHelpers.js +28 -16
  208. package/dist/domain/javascript/javascriptStaticAnalysisState.js +3 -2
  209. package/dist/domain/jsonSerialization.js +109 -0
  210. package/dist/domain/jsonValue.js +90 -6
  211. package/dist/domain/localPath.js +6 -0
  212. package/dist/domain/managed/managedApplicationGraph.js +10 -10
  213. package/dist/domain/managed/managedInspectionEvidence.js +16 -0
  214. package/dist/domain/managed/managedMemberComparisonMatch.js +5 -9
  215. package/dist/domain/managed/managedNativeVerification.js +3 -9
  216. package/dist/domain/native/fileOffsetPartialObservation.js +1 -0
  217. package/dist/domain/native/nativeCallObservation.js +33 -11
  218. package/dist/domain/native/nativeCallPartialObservation.js +33 -0
  219. package/dist/domain/process/processCapture.js +8 -4
  220. package/dist/domain/process/processComparison.js +38 -4
  221. package/dist/domain/process/processScenario.js +11 -10
  222. package/dist/domain/propertyListKeys.js +1 -1
  223. package/dist/domain/propertyListXmlText.js +19 -0
  224. package/dist/domain/providerAdapterError.js +1 -1
  225. package/dist/domain/providerOperationHealth.js +54 -0
  226. package/dist/domain/reconstructionVerification.js +6 -43
  227. package/dist/domain/reconstructionVerificationSchemas.js +2 -2
  228. package/dist/domain/staticRuntimeCorrelation.js +6 -43
  229. package/dist/domain/webBundleAnalysis.js +20 -8
  230. package/dist/domain/webBundleAnalyzerInspection.js +13 -8
  231. package/dist/domain/webBundleAnalyzerResult.js +41 -2
  232. package/dist/domain/webRuntime.js +19 -5
  233. package/dist/domain/webSourceLocation.js +1 -0
  234. package/dist/firmware/FirmwareFiles.js +1 -1
  235. package/dist/generatedPackageMetadata.js +1 -1
  236. package/dist/ghidra/GhidraAnalysisProfile.js +5 -0
  237. package/dist/ghidra/GhidraClient.js +47 -14
  238. package/dist/ghidra/GhidraDiagnostics.js +7 -7
  239. package/dist/ghidra/GhidraFunctionValues.js +10 -7
  240. package/dist/ghidra/GhidraInstallation.js +18 -21
  241. package/dist/ghidra/GhidraInventoryValues.js +14 -4
  242. package/dist/ghidra/GhidraJavaLaunch.js +62 -0
  243. package/dist/ghidra/GhidraLauncher.js +33 -16
  244. package/dist/ghidra/GhidraProviderCapabilities.js +14 -2
  245. package/dist/ghidra/GhidraProviderClient.js +23 -12
  246. package/dist/ghidra/GhidraSessionError.js +11 -7
  247. package/dist/ghidra/GhidraTargetSnapshot.js +47 -12
  248. package/dist/ghidra/GhidraTransport.js +20 -0
  249. package/dist/hopper/BridgeLauncher.js +31 -11
  250. package/dist/hopper/HopperAnalysisProfile.js +62 -4
  251. package/dist/hopper/HopperCleanup.js +15 -3
  252. package/dist/hopper/HopperClient.js +222 -14
  253. package/dist/hopper/HopperFileOffset.js +237 -0
  254. package/dist/hopper/HopperMachOImage.js +196 -0
  255. package/dist/hopper/HopperOperationStage.js +6 -0
  256. package/dist/hopper/HopperProvider.js +63 -9
  257. package/dist/hopper/HopperProviderCapabilities.js +19 -1
  258. package/dist/hopper/HopperRegexSearch.js +137 -0
  259. package/dist/hopper/HopperRegexWorker.js +27 -0
  260. package/dist/hopper/HopperRequestQueue.js +68 -19
  261. package/dist/hopper/HopperTargetLease.js +3 -2
  262. package/dist/inspector/JavaScriptRuntimeScope.js +9 -1
  263. package/dist/inspector/V8InspectorCaptureProjection.js +8 -3
  264. package/dist/inspector/V8InspectorProvider.js +47 -11
  265. package/dist/javascript/sourceMaps/DecodedSourceMap.js +47 -0
  266. package/dist/javascript/sourceMaps/SourceMapCommand.js +16 -0
  267. package/dist/javascript/sourceMaps/SourceMapFormat.js +79 -31
  268. package/dist/javascript/sourceMaps/TraceSourceMap.js +14 -28
  269. package/dist/mcpDoctor.js +62 -2
  270. package/dist/native/AppleDispatchCoverage.js +47 -6
  271. package/dist/native/AppleDispatchDecodeFacts.js +6 -0
  272. package/dist/native/AppleDispatchMetadata.js +6 -3
  273. package/dist/native/AppleMachoFixups.js +48 -24
  274. package/dist/native/AppleMachoSelection.js +32 -16
  275. package/dist/native/AppleObjcCategories.js +6 -2
  276. package/dist/native/AppleObjcDispatchFacets.js +5 -2
  277. package/dist/native/AppleObjcProperties.js +2 -1
  278. package/dist/native/AppleSwiftDispatchFacets.js +27 -21
  279. package/dist/native/AppleSwiftVtables.js +21 -15
  280. package/dist/native/CommandRunner.js +81 -84
  281. package/dist/native/LldbCallTracer.js +365 -102
  282. package/dist/native/LldbRetainedObservations.js +178 -0
  283. package/dist/native/NativeCallObservation.js +62 -3
  284. package/dist/native/NativeMacOSProvider.js +98 -17
  285. package/dist/native/SignatureTargetBinding.js +155 -0
  286. package/dist/native/parsers/lipo.js +71 -1
  287. package/dist/native/pwndbg/PwndbgCoreContext.js +25 -5
  288. package/dist/native/pwntools/RecordedCrashStructureBindings.js +2 -0
  289. package/dist/process/DarwinProcessRunTokenReader.js +8 -9
  290. package/dist/process/ExecFileOutput.js +20 -0
  291. package/dist/process/OwnedCommand.js +7 -2
  292. package/dist/process/ProcessOwnership.js +203 -53
  293. package/dist/process/ProcessOwnershipObservation.js +49 -4
  294. package/dist/process/ProviderProcess.js +38 -7
  295. package/dist/process/capture/ProcessCaptureError.js +2 -2
  296. package/dist/process/capture/ProcessCaptureLifecycle.js +100 -34
  297. package/dist/server/EvidenceMcpServer.js +146 -0
  298. package/dist/server/createServer.js +15 -8
  299. package/dist/server/registerAndroidTools.js +2 -4
  300. package/dist/server/registerApplicationTools/helpers.js +2 -4
  301. package/dist/server/registerArtifactComparisonTool.js +11 -7
  302. package/dist/server/registerBinaryDiagnosticsTools.js +2 -4
  303. package/dist/server/registerBrowserScenarioTool.js +2 -4
  304. package/dist/server/registerBrowserTools.js +2 -4
  305. package/dist/server/registerBundleComparisonTool.js +2 -3
  306. package/dist/server/registerCloseLifecycleTool.js +8 -18
  307. package/dist/server/registerElectronTools.js +2 -4
  308. package/dist/server/registerEnhancedTools.js +18 -59
  309. package/dist/server/registerEvidenceTools.js +2 -4
  310. package/dist/server/registerEvmTools.js +2 -4
  311. package/dist/server/registerFirmwareTools.js +2 -4
  312. package/dist/server/registerFunctionComparisonTool.js +10 -6
  313. package/dist/server/registerInvestigationTools.js +7 -7
  314. package/dist/server/registerJavaScriptRecoveryTool.js +2 -4
  315. package/dist/server/registerJavaScriptRuntimeObservationTools.js +2 -4
  316. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +2 -4
  317. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +2 -4
  318. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +2 -4
  319. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +2 -4
  320. package/dist/server/registerOfficialTools.js +2 -4
  321. package/dist/server/registerProcessComparisonTool.js +71 -45
  322. package/dist/server/registerRecordedCrashTools.js +2 -4
  323. package/dist/server/registerSessionRecordTools.js +5 -6
  324. package/dist/server/registerSessionStatusTool.js +17 -3
  325. package/dist/server/registerSessionTools.js +11 -3
  326. package/dist/server/registerWebModuleTool.js +2 -4
  327. package/dist/server/registerWebNetworkCaptureTool.js +2 -4
  328. package/dist/server/registerWebRuntimeTools.js +3 -7
  329. package/dist/server/registerWebScriptTool.js +2 -4
  330. package/dist/server/registerWebSourceLocationTool.js +2 -4
  331. package/dist/server/runDerivedOperation.js +15 -3
  332. package/dist/server/sessionAvailabilityPolicy.js +0 -1
  333. package/dist/server/toolRegistrationOptions.js +2 -2
  334. package/dist/server/toolResult.js +62 -10
  335. package/dist/server/toolResultEncoding.js +33 -0
  336. package/install.sh +1 -1
  337. package/native/windows/build/manifest.json +1 -1
  338. package/package.json +8 -3
  339. package/scripts/electron-active-hook-boundaries.cjs +18 -20
  340. package/scripts/electron-active-hook.cjs +241 -37
  341. package/skills/reverse-engineer-anything/SKILL.md +11 -3
  342. package/skills/reverse-engineer-anything/references/javascript-applications.md +8 -1
  343. package/dist/ghidra/GhidraDefaults.js +0 -2
@@ -434,10 +434,18 @@ export const releaseProcessResources = async (options) => {
434
434
  };
435
435
  }
436
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
+ };
437
445
  const cleaned = await host.cleanupProcessGroup({
438
446
  runId: options.runId,
439
- leaderPid: options.terminal.pid,
440
- processGroupId: options.terminal.pid,
447
+ leaderPid: terminalPid,
448
+ processGroupId: terminalPid,
441
449
  sweepTokenOwnedProcesses: true,
442
450
  ...(options.sampledProcessGroupIds === undefined
443
451
  ? {}
@@ -446,14 +454,26 @@ export const releaseProcessResources = async (options) => {
446
454
  ? {}
447
455
  : { captureBaseline: options.captureBaseline }),
448
456
  });
457
+ const unverified = [...(cleaned.unverified ?? [])];
449
458
  if (!cleaned.cleaned) {
450
459
  ownedProcessGroup = { state: "unverified", reason: cleaned.reason };
451
460
  }
452
461
  else {
453
- const verified = await verifyTokenOwnedProcessesUntilSettled(() => host.verifyTokenOwnedProcesses(options.runId, undefined, options.captureBaseline));
462
+ const verified = await verifyTokenOwnedProcessesUntilSettled(() => host.verifyTokenOwnedProcesses(options.runId, undefined, options.captureBaseline, relation));
463
+ unverified.push(...(verified.unverified ?? []));
454
464
  if (!verified.cleaned)
455
465
  ownedProcessGroup = { state: "unverified", reason: verified.reason };
456
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
+ };
457
477
  }
458
478
  }
459
479
  let temporaryRoot = {
@@ -511,41 +531,53 @@ export const captureTerminalFrames = (options) => {
511
531
  };
512
532
  export const resolveProcessResult = (capture, executionFailure, cleanup, observations, partialContext) => {
513
533
  const cleanupFailure = cleanupReportFailure(cleanup);
514
- if (cleanupFailure !== undefined) {
515
- const cleanupResources = Object.entries(cleanup)
516
- .filter(([, outcome]) => outcome.state === "failed" || outcome.state === "unverified")
517
- .map(([resource]) => resource);
518
- const executionFailureReason = describeProcessCaptureExecutionFailure(executionFailure);
519
- let partialObservation;
520
- if (capture !== undefined || observations !== undefined) {
521
- const normalizedObservations = observations === undefined || partialContext === undefined
522
- ? observations
523
- : normalizePartialProcessObservations(observations, partialContext);
524
- const partialPayload = capture === undefined
525
- ? { observations: normalizedObservations }
526
- : { capture };
527
- const pendingCapture = capture === undefined
528
- ? undefined
529
- : {
530
- ...capture,
531
- settlement: {
534
+ const executionFailureReason = describeProcessCaptureExecutionFailure(executionFailure);
535
+ let partialObservation;
536
+ if ((cleanupFailure !== undefined || executionFailure !== undefined) &&
537
+ (capture !== undefined || observations !== undefined)) {
538
+ const normalizedObservations = observations === undefined || partialContext === undefined
539
+ ? observations
540
+ : normalizePartialProcessObservations(observations, partialContext);
541
+ if (capture === undefined) {
542
+ if (normalizedObservations !== undefined) {
543
+ const partialResult = partialProcessCaptureObservationSchema.safeParse({
544
+ observations: normalizedObservations,
545
+ cleanup,
546
+ execution_failure: executionFailureReason ?? null,
547
+ });
548
+ if (partialResult.success)
549
+ partialObservation = partialResult.data;
550
+ }
551
+ }
552
+ else {
553
+ const captureData = "cleanup" in capture
554
+ ? (() => {
555
+ const { cleanup: _cleanup, ...data } = capture;
556
+ void _cleanup;
557
+ return data;
558
+ })()
559
+ : capture;
560
+ const settlement = cleanupFailure !== undefined
561
+ ? { ...capture.settlement, cleanup_outcome: "failed" }
562
+ : capture.settlement.state === "quiesced"
563
+ ? {
532
564
  ...capture.settlement,
533
- cleanup_outcome: "failed",
534
- },
535
- };
565
+ cleanup_outcome: "not_required",
566
+ }
567
+ : { ...capture.settlement, cleanup_outcome: "cleaned" };
536
568
  const partialResult = partialProcessCaptureObservationSchema.safeParse({
537
- ...partialPayload,
538
- ...(pendingCapture === undefined
539
- ? {}
540
- : {
541
- capture: Object.fromEntries(Object.entries(pendingCapture).filter(([key]) => key !== "cleanup")),
542
- }),
569
+ capture: { ...captureData, settlement },
543
570
  cleanup,
544
571
  execution_failure: executionFailureReason ?? null,
545
572
  });
546
573
  if (partialResult.success)
547
574
  partialObservation = partialResult.data;
548
575
  }
576
+ }
577
+ if (cleanupFailure !== undefined) {
578
+ const cleanupResources = Object.entries(cleanup)
579
+ .filter(([, outcome]) => outcome.state === "failed" || outcome.state === "unverified")
580
+ .map(([resource]) => resource);
549
581
  throw new ProcessCaptureError(cleanupFailure, {
550
582
  cause: executionFailure,
551
583
  reason: "cleanup_incomplete",
@@ -557,20 +589,43 @@ export const resolveProcessResult = (capture, executionFailure, cleanup, observa
557
589
  cleanupReport: cleanup,
558
590
  });
559
591
  }
560
- if (executionFailure instanceof ProcessCaptureError)
561
- throw executionFailure;
592
+ if (executionFailure instanceof ProcessCaptureError) {
593
+ const retainedExecutionFailure = executionFailure.executionFailure ?? executionFailureReason;
594
+ const retainedPartialObservation = executionFailure.partialObservation ?? partialObservation;
595
+ throw new ProcessCaptureError(executionFailure.message, {
596
+ cause: executionFailure,
597
+ ...(executionFailure.userMessage === undefined
598
+ ? {}
599
+ : { userMessage: executionFailure.userMessage }),
600
+ ...(executionFailure.userCategory === undefined
601
+ ? {}
602
+ : { userCategory: executionFailure.userCategory }),
603
+ reason: executionFailure.reason,
604
+ cleanupResources: executionFailure.cleanupResources,
605
+ ...(retainedExecutionFailure === undefined
606
+ ? {}
607
+ : { executionFailure: retainedExecutionFailure }),
608
+ ...(retainedPartialObservation === undefined
609
+ ? {}
610
+ : { partialObservation: retainedPartialObservation }),
611
+ cleanupReport: executionFailure.cleanupReport ?? cleanup,
612
+ });
613
+ }
562
614
  if (executionFailure !== undefined) {
563
- const executionFailureReason = describeProcessCaptureExecutionFailure(executionFailure);
564
615
  throw new ProcessCaptureError("process capture failed", {
565
616
  cause: executionFailure,
617
+ reason: "capture_failed",
566
618
  ...(executionFailureReason === undefined
567
619
  ? {}
568
620
  : { executionFailure: executionFailureReason }),
621
+ ...(partialObservation === undefined ? {} : { partialObservation }),
622
+ cleanupReport: cleanup,
569
623
  });
570
624
  }
571
625
  if (capture === undefined)
572
626
  throw new ProcessCaptureError("process capture produced no result");
573
- if ("cleanup" in capture)
627
+ const unverifiedProcesses = cleanup.owned_process_group.unverified_processes;
628
+ if ("cleanup" in capture && unverifiedProcesses === undefined)
574
629
  return capture;
575
630
  const settlement = capture.settlement.state === "quiesced"
576
631
  ? { ...capture.settlement, cleanup_outcome: "not_required" }
@@ -579,9 +634,20 @@ export const resolveProcessResult = (capture, executionFailure, cleanup, observa
579
634
  return parseProcessCapture({
580
635
  ...capture,
581
636
  settlement,
637
+ residual_unknowns: [
638
+ ...capture.residual_unknowns,
639
+ ...(unverifiedProcesses ?? []).map(({ pid, reason }) => ({
640
+ scope: "process",
641
+ reason: `Ownership of unrelated process ${String(pid)} could not be verified; it was left untouched: ${reason}`,
642
+ })),
643
+ ],
582
644
  cleanup: {
645
+ ...("cleanup" in capture ? capture.cleanup : {}),
583
646
  owned_process_group: "verified",
584
647
  temporary_root: "removed",
648
+ ...(unverifiedProcesses === undefined
649
+ ? {}
650
+ : { unverified_processes: unverifiedProcesses }),
585
651
  },
586
652
  });
587
653
  }
@@ -0,0 +1,146 @@
1
+ import { McpServer, isCallToolResult, isJSONRPCRequest, isJSONRPCNotification, isJSONRPCResultResponse, } from "@modelcontextprotocol/server";
2
+ import { analysisErrorProjectionSchema } from "../contracts/errorSchemas.js";
3
+ import { parseMcpResponseBudget } from "../config/mcpResponseBudget.js";
4
+ import { AnalysisResourceConstraintError } from "../domain/analysisErrorCore.js";
5
+ import { projectAnalysisError } from "../domain/analysisErrorProjection.js";
6
+ import { createEvidence } from "../domain/evidence.js";
7
+ import { jsonObjectSchema } from "../domain/jsonValue.js";
8
+ import { toErrorToolResult } from "./toolResult.js";
9
+ import { encodeToolResult, MCP_RESULT_BUDGET_BYTES, } from "./toolResultEncoding.js";
10
+ /** Bind oversized MCP error recovery to this server's Evidence ledger. */
11
+ export class EvidenceMcpServer extends McpServer {
12
+ recordEvidence;
13
+ constructor(info, options, recordEvidence) {
14
+ super(info, options);
15
+ this.recordEvidence = recordEvidence;
16
+ }
17
+ /** Preserve the SDK transport lifecycle while retaining oversized errors. */
18
+ connect(transport) {
19
+ return super.connect(new ErrorEvidenceTransport(transport, this.recordEvidence));
20
+ }
21
+ }
22
+ class ErrorEvidenceTransport {
23
+ transport;
24
+ recordEvidence;
25
+ onclose;
26
+ onerror;
27
+ onmessage;
28
+ hasPerRequestStream;
29
+ pendingTools = new Map();
30
+ constructor(transport, recordEvidence) {
31
+ this.transport = transport;
32
+ this.recordEvidence = recordEvidence;
33
+ if (transport.hasPerRequestStream !== undefined)
34
+ this.hasPerRequestStream = transport.hasPerRequestStream;
35
+ transport.onmessage = (message, extra) => {
36
+ if (isJSONRPCRequest(message) &&
37
+ message.method === "tools/call" &&
38
+ typeof message.params?.["name"] === "string")
39
+ this.pendingTools.set(message.id, message.params["name"]);
40
+ // The SDK suppresses replies after cancellation, so send() cannot release
41
+ // this bookkeeping. Keep transport authentication outside retained data.
42
+ if (isJSONRPCNotification(message) &&
43
+ message.method === "notifications/cancelled") {
44
+ const id = message.params?.["requestId"];
45
+ if (typeof id === "string" || typeof id === "number")
46
+ this.pendingTools.delete(id);
47
+ }
48
+ this.onmessage?.(message, extra);
49
+ };
50
+ transport.onerror = (error) => this.onerror?.(error);
51
+ transport.onclose = () => {
52
+ this.pendingTools.clear();
53
+ this.onclose?.();
54
+ };
55
+ }
56
+ get sessionId() {
57
+ return this.transport.sessionId;
58
+ }
59
+ set sessionId(value) {
60
+ this.transport.sessionId = value;
61
+ }
62
+ start() {
63
+ return this.transport.start();
64
+ }
65
+ async close() {
66
+ try {
67
+ await this.transport.close();
68
+ }
69
+ finally {
70
+ this.pendingTools.clear();
71
+ }
72
+ }
73
+ setProtocolVersion(version) {
74
+ this.transport.setProtocolVersion?.(version);
75
+ }
76
+ setSupportedProtocolVersions(versions) {
77
+ this.transport.setSupportedProtocolVersions?.(versions);
78
+ }
79
+ async send(message, options) {
80
+ const id = "id" in message &&
81
+ (typeof message.id === "string" || typeof message.id === "number")
82
+ ? message.id
83
+ : undefined;
84
+ const tool = id === undefined ? undefined : this.pendingTools.get(id);
85
+ try {
86
+ await this.transport.send(this.recoverError(message, tool), options);
87
+ }
88
+ finally {
89
+ if (!isJSONRPCRequest(message) && id !== undefined)
90
+ this.pendingTools.delete(id);
91
+ }
92
+ }
93
+ recoverError(message, tool) {
94
+ if (!isJSONRPCResultResponse(message) ||
95
+ !isCallToolResult(message.result) ||
96
+ message.result.isError !== true ||
97
+ message.result.structuredContent === undefined)
98
+ return message;
99
+ const structured = jsonObjectSchema.parse(message.result.structuredContent);
100
+ const configured = parseMcpResponseBudget(process.env.REA_MCP_MAX_RESPONSE_BYTES);
101
+ const budget = configured.ok && configured.value !== undefined
102
+ ? configured.value - 1024
103
+ : MCP_RESULT_BUDGET_BYTES;
104
+ const encoded = encodeToolResult(structured, budget);
105
+ if (encoded.ok)
106
+ return message;
107
+ const operation = tool ?? "mcp_tool_error";
108
+ const originalError = analysisErrorProjectionSchema.safeParse(structured["error"]);
109
+ // Retain the already projected diagnostic. Transport authentication and raw
110
+ // request arguments are deliberately excluded: the application owns their
111
+ // explicit sensitivity policy, and its error projection is authoritative.
112
+ const evidence = createEvidence(undefined, { id: "rea-mcp", name: "REA MCP delivery", version: "1" }, {
113
+ operation: "mcp_tool_error",
114
+ parameters: { tool_name: operation },
115
+ result: structured,
116
+ rawResult: jsonObjectSchema.parse(message.result),
117
+ });
118
+ const recorded = this.recordEvidence?.(evidence);
119
+ const retained = recorded !== undefined && recorded.ok;
120
+ const failure = new AnalysisResourceConstraintError(operation, "transport", "The tool failed, but its complete error response exceeds the MCP response budget.", {
121
+ boundary: "mcp-response",
122
+ ...(originalError.success
123
+ ? { original_error_code: originalError.data.code }
124
+ : {}),
125
+ result_budget_bytes: budget,
126
+ response_bytes_at_least: encoded.bytesAtLeast,
127
+ constraint: encoded.constraint,
128
+ ...(retained
129
+ ? {
130
+ evidence_reference: {
131
+ kind: "retained-evidence",
132
+ evidence_id: evidence.evidence_id,
133
+ },
134
+ }
135
+ : { retention: recorded === undefined ? "unavailable" : "failed" }),
136
+ ...(recorded !== undefined && !recorded.ok
137
+ ? { retention_error: projectAnalysisError(recorded.error) }
138
+ : {}),
139
+ }, {
140
+ remediationAction: retained
141
+ ? "Export the retained original error through export_evidence_bundle to a caller-selected path. The connection remains usable."
142
+ : "Configure a larger REA_MCP_MAX_RESPONSE_BYTES and matching client receive buffer, then retry. The original error could not be retained by this server.",
143
+ });
144
+ return { ...message, result: toErrorToolResult(failure) };
145
+ }
146
+ }
@@ -4,7 +4,7 @@ import { registerRecordedCrashTools } from "./registerRecordedCrashTools.js";
4
4
  import { createRecordedCrashService } from "../composition/binaryDiagnostics.js";
5
5
  import { registerBinaryDiagnosticsTools } from "./registerBinaryDiagnosticsTools.js";
6
6
  import { createBinaryLayoutService } from "../composition/binaryDiagnostics.js";
7
- import { McpServer } from "@modelcontextprotocol/server";
7
+ import { EvidenceMcpServer } from "./EvidenceMcpServer.js";
8
8
  import { isAbsolute } from "node:path";
9
9
  import { PRODUCT_IDENTITY } from "../identity.js";
10
10
  import { silentLogger } from "../logger.js";
@@ -66,9 +66,6 @@ const installSessionToolAvailability = (server, session, options) => {
66
66
  firmwareExtractionEnabled: options.firmwareAnalysis !== undefined ||
67
67
  (process.platform === "linux" &&
68
68
  isAbsolute(process.env.REA_UNBLOB_COMMAND ?? "")),
69
- androidAnalysisEnabled: options.androidAnalysis !== undefined ||
70
- ((process.platform === "linux" || process.platform === "darwin") &&
71
- isAbsolute(process.env.REA_JADX_MCP_JAR ?? "")),
72
69
  browserObservationEnabled: options.browserObservation !== undefined,
73
70
  javascriptRecoveryEnabled: options.javascriptRecovery !== undefined ||
74
71
  (process.platform === "linux" &&
@@ -84,7 +81,7 @@ const installSessionToolAvailability = (server, session, options) => {
84
81
  policy,
85
82
  };
86
83
  };
87
- const createMcpServer = (session) => new McpServer({
84
+ const createMcpServer = (session) => new EvidenceMcpServer({
88
85
  name: PRODUCT_IDENTITY.mcpServerKey,
89
86
  version: PRODUCT_IDENTITY.packageVersion,
90
87
  }, {
@@ -92,7 +89,9 @@ const createMcpServer = (session) => new McpServer({
92
89
  instructions: session === undefined
93
90
  ? ACTIVE_TARGET_INSTRUCTIONS
94
91
  : TARGET_FREE_INSTRUCTIONS,
95
- });
92
+ }, session === undefined
93
+ ? undefined
94
+ : (evidence) => session.recordEvidence(evidence));
96
95
  /**
97
96
  * Construct one MCP server without acquiring subprocess resources.
98
97
  * Supplying a session adds target lifecycle tools; omitting it retains the
@@ -102,6 +101,7 @@ export const createServer = (analysis, session, options = {}) => {
102
101
  const startedAt = new Date().toISOString();
103
102
  const logger = options.logger ?? silentLogger;
104
103
  const server = createMcpServer(session);
104
+ const android = options.androidAnalysis ?? createAndroidAnalysisProvider();
105
105
  const availability = installSessionToolAvailability(server, session, options);
106
106
  const toolLogger = logger.child({ layer: "server" });
107
107
  const { evidenceById, activeTarget, recordEvidence, recordEvidenceWithUnknown, } = createSessionRecorders(server, session);
@@ -117,7 +117,6 @@ export const createServer = (analysis, session, options = {}) => {
117
117
  recordEvidenceWithUnknown,
118
118
  };
119
119
  registerBinaryAnalysisTools(toolContext);
120
- const android = options.androidAnalysis ?? createAndroidAnalysisProvider();
121
120
  const previousOnclose = server.server.onclose;
122
121
  server.server.onclose = () => {
123
122
  previousOnclose?.();
@@ -150,6 +149,7 @@ export const createServer = (analysis, session, options = {}) => {
150
149
  ...(availability === undefined
151
150
  ? {}
152
151
  : { availabilityPolicy: availability.policy }),
152
+ androidAnalysisAvailability: (signal) => android.inspectAvailability(signal),
153
153
  startedAt,
154
154
  });
155
155
  }
@@ -158,7 +158,8 @@ export const createServer = (analysis, session, options = {}) => {
158
158
  const createSessionRecorders = (server, session) => ({
159
159
  evidenceById: session === undefined
160
160
  ? undefined
161
- : (evidenceId) => session.evidenceById(evidenceId),
161
+ : (evidenceId) => session.evidenceForAnalysis?.(evidenceId) ??
162
+ session.evidenceById(evidenceId),
162
163
  activeTarget: session === undefined ? undefined : () => session.activeTarget(),
163
164
  recordEvidence: session === undefined
164
165
  ? undefined
@@ -187,6 +188,12 @@ const registerBinaryAnalysisTools = ({ server, analysis, session, logger, active
187
188
  registerEnhancedTools(server, analysis, {
188
189
  ...analysisOptions,
189
190
  analysisProfile: session === undefined ? undefined : () => session.analysisProfile(),
191
+ allowsSnapshotReplay: session === undefined
192
+ ? undefined
193
+ : (operation) => session.allowsSnapshotReplay(operation),
194
+ recordWorkflowSnapshot: session === undefined
195
+ ? undefined
196
+ : (input) => session.recordWorkflowSnapshot(input),
190
197
  });
191
198
  const evidenceOptions = { logger, activeTarget, recordEvidence };
192
199
  registerNativeTools(server, analysis, evidenceOptions);
@@ -2,7 +2,7 @@ import { AndroidAnalysisService } from "../application/android/AndroidAnalysisSe
2
2
  import { toolContract } from "../contracts/toolContracts.js";
3
3
  import { logToolExecution } from "./toolLogging.js";
4
4
  import { toolRegistrationOptions } from "./toolRegistrationOptions.js";
5
- import { toCallToolResult } from "./toolResult.js";
5
+ import { toCallToolResult, toEvidenceToolResult } from "./toolResult.js";
6
6
  /** Bind Android handlers to their exact named contracts through shared workflows. */
7
7
  export const registerAndroidTools = (server, service, logger, recordEvidence) => {
8
8
  const handler = (contract) => {
@@ -12,9 +12,7 @@ export const registerAndroidTools = (server, service, logger, recordEvidence) =>
12
12
  if (!result.ok)
13
13
  return toCallToolResult(result, contract);
14
14
  const recorded = recordEvidence?.(result.value);
15
- return recorded !== undefined && !recorded.ok
16
- ? toCallToolResult(recorded, contract)
17
- : toCallToolResult(result, contract);
15
+ return toEvidenceToolResult(result.value, contract, recorded);
18
16
  };
19
17
  };
20
18
  const packageContract = toolContract("inspect_android_package");
@@ -1,12 +1,10 @@
1
1
  import { APPLICATION_TOOL_CONTRACTS } from "../../contracts/applicationToolContracts.js";
2
- import { toCallToolResult } from "../toolResult.js";
2
+ import { toEvidenceToolResult } from "../toolResult.js";
3
3
  export const recordResult = (options, contract, evidence, unknownKind) => {
4
4
  const recorded = unknownKind === undefined
5
5
  ? options.recordEvidence?.(evidence)
6
6
  : options.recordEvidenceWithUnknown?.(evidence, unknownRegistration(evidence, unknownKind));
7
- if (recorded !== undefined && !recorded.ok)
8
- return toCallToolResult(recorded, contract);
9
- return toCallToolResult({ ok: true, value: evidence }, contract);
7
+ return toEvidenceToolResult(evidence, contract, recorded);
10
8
  };
11
9
  const unknownRegistration = (evidence, kind) => ({
12
10
  question: kind === "application-version-comparison"
@@ -6,7 +6,7 @@ import { recordDerivedEvidence } from "./recordDerivedEvidence.js";
6
6
  import { runDerivedOperation } from "./runDerivedOperation.js";
7
7
  import { ARTIFACT_COMPARISON_PROVIDER } from "./sessionToolPolicies.js";
8
8
  import { toolRegistrationOptions } from "./toolRegistrationOptions.js";
9
- import { toCallToolResult } from "./toolResult.js";
9
+ import { toCallToolResult, toEvidenceToolResult } from "./toolResult.js";
10
10
  /** Register Evidence-backed deterministic artifact comparison. */
11
11
  export const registerArtifactComparisonTool = (server, session, contract) => {
12
12
  server.registerTool(contract.name, toolRegistrationOptions(contract), async (input, context) => {
@@ -39,18 +39,22 @@ export const registerArtifactComparisonTool = (server, session, contract) => {
39
39
  limitations: comparison.limitations,
40
40
  evidenceLinks: [...leftEvidenceIds, ...rightEvidenceIds],
41
41
  });
42
- return toCallToolResult(recordDerivedEvidence(session, evidence, artifactUnknownInput(left, right, comparison.status)), contract);
42
+ return toEvidenceToolResult(evidence, contract, recordDerivedEvidence(session, evidence, artifactUnknownInput(left, right, comparison.status, evidence.evidence_id)));
43
43
  });
44
44
  };
45
- const artifactUnknownInput = (left, right, status) => {
46
- if (status === "unchanged" || left.evidence_id === right.evidence_id)
45
+ const artifactUnknownInput = (left, right, status, comparisonEvidenceId) => {
46
+ if (status === "unchanged")
47
47
  return undefined;
48
+ const contradictory = (status === "changed" || status === "contradiction") &&
49
+ left.evidence_id !== right.evidence_id;
48
50
  return {
49
- question: `Artifact comparison is ${status}`,
51
+ question: `Artifact comparison is ${status} (comparison ${comparisonEvidenceId})`,
50
52
  severity: status === "unknown" || status === "truncated" ? "high" : "medium",
51
53
  domain: "artifact-comparison",
52
- supporting_evidence_ids: [left.evidence_id],
53
- contradicting_evidence_ids: [right.evidence_id],
54
+ supporting_evidence_ids: contradictory
55
+ ? [left.evidence_id]
56
+ : [...new Set([left.evidence_id, right.evidence_id])],
57
+ contradicting_evidence_ids: contradictory ? [right.evidence_id] : [],
54
58
  required_authority: "shipped-artifact",
55
59
  required_confidence: "observed",
56
60
  required_environment: null,
@@ -1,7 +1,7 @@
1
1
  import { toolContract } from "../contracts/toolContracts.js";
2
2
  import { logToolExecution } from "./toolLogging.js";
3
3
  import { toolRegistrationOptions } from "./toolRegistrationOptions.js";
4
- import { toCallToolResult } from "./toolResult.js";
4
+ import { toCallToolResult, toEvidenceToolResult } from "./toolResult.js";
5
5
  /** Bind offline layout inspection to its named contract and session Evidence owner. */
6
6
  export const registerBinaryDiagnosticsTools = (server, service, logger, recordEvidence) => {
7
7
  const contract = toolContract("inspect_binary_layout");
@@ -10,8 +10,6 @@ export const registerBinaryDiagnosticsTools = (server, service, logger, recordEv
10
10
  if (!result.ok)
11
11
  return toCallToolResult(result, contract);
12
12
  const recorded = recordEvidence?.(result.value);
13
- return recorded !== undefined && !recorded.ok
14
- ? toCallToolResult(recorded, contract)
15
- : toCallToolResult(result, contract);
13
+ return toEvidenceToolResult(result.value, contract, recorded);
16
14
  });
17
15
  };
@@ -5,7 +5,7 @@ import { toolContract } from "../contracts/toolContracts.js";
5
5
  import { browserScenarioSchema } from "../domain/browserScenario.js";
6
6
  import { logToolExecution } from "./toolLogging.js";
7
7
  import { toolRegistrationOptions } from "./toolRegistrationOptions.js";
8
- import { toCallToolResult } from "./toolResult.js";
8
+ import { toCallToolResult, toEvidenceToolResult } from "./toolResult.js";
9
9
  /** Register the browser scenario tool with execution-time provider diagnostics. */
10
10
  export const registerBrowserScenarioTool = (server, options) => {
11
11
  const contract = toolContract("capture_browser_scenario");
@@ -19,8 +19,6 @@ export const registerBrowserScenarioTool = (server, options) => {
19
19
  if (!result.ok)
20
20
  return toCallToolResult(result, contract);
21
21
  const recorded = options.recordEvidence?.(result.value);
22
- return recorded !== undefined && !recorded.ok
23
- ? toCallToolResult(recorded, contract)
24
- : toCallToolResult({ ok: true, value: result.value }, contract);
22
+ return toEvidenceToolResult(result.value, contract, recorded);
25
23
  });
26
24
  };
@@ -7,7 +7,7 @@ import { inspectWebPageInputSchema } from "../domain/browserObservation.js";
7
7
  import { mcpProgressReporter } from "./mcpProgress.js";
8
8
  import { logToolExecution } from "./toolLogging.js";
9
9
  import { toolRegistrationOptions } from "./toolRegistrationOptions.js";
10
- import { toCallToolResult } from "./toolResult.js";
10
+ import { toCallToolResult, toEvidenceToolResult } from "./toolResult.js";
11
11
  /** Register browser tools with execution-time provider diagnostics. */
12
12
  // oxlint-disable-next-line max-lines-per-function -- direct SDK calls retain each schema-handler type correlation.
13
13
  export const registerBrowserTools = (server, options) => {
@@ -56,7 +56,5 @@ const runBrowserTool = async (options, contract, request, execute) => {
56
56
  };
57
57
  const evidenceResult = (options, contract, evidence) => {
58
58
  const recorded = options.recordEvidence?.(evidence);
59
- return recorded !== undefined && !recorded.ok
60
- ? toCallToolResult(recorded, contract)
61
- : toCallToolResult({ ok: true, value: evidence }, contract);
59
+ return toEvidenceToolResult(evidence, contract, recorded);
62
60
  };
@@ -3,11 +3,10 @@ import { toolContract } from "../contracts/toolContracts.js";
3
3
  import { compareBundles } from "../domain/bundleComparison.js";
4
4
  import { createEvidence } from "../domain/evidence.js";
5
5
  import { jsonValueSchema } from "../domain/jsonValue.js";
6
- import { ok } from "../domain/result.js";
7
6
  import { runDerivedOperation } from "./runDerivedOperation.js";
8
7
  import { BUNDLE_COMPARISON_PROVIDER } from "./sessionToolPolicies.js";
9
8
  import { toolRegistrationOptions } from "./toolRegistrationOptions.js";
10
- import { toCallToolResult } from "./toolResult.js";
9
+ import { toCallToolResult, toEvidenceToolResult } from "./toolResult.js";
11
10
  /** Register canonical Evidence bundle comparison. */
12
11
  export const registerBundleComparisonTool = (server, session, contract) => {
13
12
  server.registerTool(contract.name, toolRegistrationOptions(contract), async (input, context) => {
@@ -37,6 +36,6 @@ export const registerBundleComparisonTool = (server, session, contract) => {
37
36
  limitations: comparison.limitations,
38
37
  });
39
38
  const recorded = session.recordEvidence(evidence);
40
- return toCallToolResult(recorded.ok ? ok(evidence) : recorded, contract);
39
+ return toEvidenceToolResult(evidence, contract, recorded);
41
40
  });
42
41
  };
@@ -1,6 +1,5 @@
1
- import { writeAnalysisSnapshot } from "../application/binary/AnalysisSnapshotFiles.js";
2
- import { ok } from "../domain/result.js";
3
1
  import { reportLifecycleEnd, reportLifecycleStart, } from "./lifecycleProgress.js";
2
+ import { ok } from "../domain/result.js";
4
3
  import { mcpProgressReporter } from "./mcpProgress.js";
5
4
  import { logToolExecution } from "./toolLogging.js";
6
5
  import { toolRegistrationOptions } from "./toolRegistrationOptions.js";
@@ -9,27 +8,18 @@ import { toCallToolResult } from "./toolResult.js";
9
8
  export const registerCloseLifecycleTool = ({ server, session, logger, closeContract, }) => {
10
9
  server.registerTool(closeContract.name, toolRegistrationOptions(closeContract), async (input, context) => {
11
10
  const progress = mcpProgressReporter(context);
12
- if (input.snapshot_path === undefined) {
11
+ const snapshotPath = input.snapshot_path;
12
+ if (snapshotPath === undefined) {
13
13
  await reportLifecycleStart(progress, closeContract.name);
14
14
  const closed = await logToolExecution(logger, closeContract.name, () => session.close({ progress }));
15
15
  await reportLifecycleEnd(progress, closeContract.name, closed.ok);
16
16
  return toCallToolResult(closed, closeContract);
17
17
  }
18
- const snapshot = session.exportAnalysisSnapshot();
19
- if (!snapshot.ok)
20
- return toCallToolResult(snapshot, closeContract);
21
- const written = await writeAnalysisSnapshot(snapshot.value, input.snapshot_path, input.overwrite);
22
- if (!written.ok)
23
- return toCallToolResult(written, closeContract);
24
- await reportLifecycleStart(progress, closeContract.name, "snapshot written; closing provider");
25
- const closed = await logToolExecution(logger, closeContract.name, () => session.close({ progress }));
18
+ await reportLifecycleStart(progress, closeContract.name, "saving snapshot; closing provider");
19
+ const closed = await logToolExecution(logger, closeContract.name, () => session.closeWithSnapshot(snapshotPath, input.overwrite, {
20
+ progress,
21
+ }));
26
22
  await reportLifecycleEnd(progress, closeContract.name, closed.ok);
27
- return closed.ok
28
- ? toCallToolResult(ok({
29
- path: written.value.path,
30
- bytes: written.value.bytes,
31
- entries: snapshot.value.entries.length,
32
- }), closeContract)
33
- : toCallToolResult(closed, closeContract);
23
+ return toCallToolResult(closed.ok ? ok({ ...closed.value }) : closed, closeContract);
34
24
  });
35
25
  };
@@ -9,7 +9,7 @@ import { inspectElectronPageInputSchema } from "../domain/javascript/electronObs
9
9
  import { mcpProgressReporter } from "./mcpProgress.js";
10
10
  import { logToolExecution } from "./toolLogging.js";
11
11
  import { toolRegistrationOptions } from "./toolRegistrationOptions.js";
12
- import { toCallToolResult } from "./toolResult.js";
12
+ import { toCallToolResult, toEvidenceToolResult } from "./toolResult.js";
13
13
  /** Register Electron tools even when a provider is absent. */
14
14
  // oxlint-disable-next-line max-lines-per-function -- direct SDK calls retain each schema-handler type correlation.
15
15
  export const registerElectronTools = (server, options) => {
@@ -55,7 +55,5 @@ const runElectronTool = async (options, contract, request, execute) => {
55
55
  };
56
56
  const evidenceResult = (options, contract, evidence) => {
57
57
  const recorded = options.recordEvidence?.(evidence);
58
- return recorded !== undefined && !recorded.ok
59
- ? toCallToolResult(recorded, contract)
60
- : toCallToolResult({ ok: true, value: evidence }, contract);
58
+ return toEvidenceToolResult(evidence, contract, recorded);
61
59
  };