rea-agents 3.2.0 → 4.0.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 (434) hide show
  1. package/README.md +183 -332
  2. package/bridge/ghidra/ReaGhidraBridge.java +561 -74
  3. package/bridge/hopper_bridge.py +70 -27
  4. package/bridge/native/ReaNativeUI.swift +157 -0
  5. package/dist/application/AnalysisContextQueries.js +19 -5
  6. package/dist/application/AnalysisSnapshotCache.js +30 -11
  7. package/dist/application/AppleAssetCatalogAnalysis.js +171 -0
  8. package/dist/application/ArtifactExtractionDestination.js +0 -12
  9. package/dist/application/ArtifactGraphConstruction.js +44 -11
  10. package/dist/application/ArtifactInventory/classify.js +7 -15
  11. package/dist/application/ArtifactInventory/hash.js +4 -2
  12. package/dist/application/ArtifactInventory/policy.js +2 -17
  13. package/dist/application/ArtifactInventory/reader.js +3 -3
  14. package/dist/application/ArtifactInventory/scanCanonical.js +2 -2
  15. package/dist/application/ArtifactInventory/scanReader.js +12 -4
  16. package/dist/application/ArtifactInventory/types.js +0 -3
  17. package/dist/application/BinarySession.js +28 -43
  18. package/dist/application/BinarySessionExecution.js +37 -1
  19. package/dist/application/BinaryTargetResolver.js +50 -4
  20. package/dist/application/BrowserEvidence.js +36 -7
  21. package/dist/application/BrowserObservationService.js +17 -44
  22. package/dist/application/BrowserScenarioCaptureService.js +2 -35
  23. package/dist/application/BrowserScenarioEvidence.js +13 -9
  24. package/dist/application/CapabilityClientRequirements.js +2 -11
  25. package/dist/application/CapabilityInventory.js +21 -35
  26. package/dist/application/ClientConfigurationDocument.js +84 -7
  27. package/dist/application/ClientRegistrationIdentity.js +32 -0
  28. package/dist/application/ClientRegistrationStatus.js +59 -6
  29. package/dist/application/DirectAnalysis.js +37 -58
  30. package/dist/application/DirectAnalysisStatus.js +4 -4
  31. package/dist/application/Doctor.js +89 -80
  32. package/dist/application/DoctorDiagnostics.js +2 -26
  33. package/dist/application/DoctorScope.js +8 -14
  34. package/dist/application/ElectronActiveEvidence.js +10 -27
  35. package/dist/application/ElectronActiveObservationService.js +9 -36
  36. package/dist/application/ElectronBoundaryAnalysis.js +2 -0
  37. package/dist/application/ElectronBoundaryGraphNative.js +1 -1
  38. package/dist/application/ElectronEvidence.js +8 -3
  39. package/dist/application/ElectronObservationService.js +9 -25
  40. package/dist/application/EnhancedLiteralTracing.js +4 -8
  41. package/dist/application/EnhancedTools.js +15 -35
  42. package/dist/application/FilesystemSnapshot.js +7 -8
  43. package/dist/application/JavaScriptApplicationEvidenceGraph.js +2 -1
  44. package/dist/application/JavaScriptApplicationWorkflowService.js +31 -7
  45. package/dist/application/JavaScriptArtifactAnalysis.js +6 -4
  46. package/dist/application/JavaScriptArtifactFiles.js +5 -0
  47. package/dist/application/JavaScriptArtifactPathResolution.js +179 -47
  48. package/dist/application/JavaScriptRuntimeObservationEvidence.js +6 -3
  49. package/dist/application/JavaScriptRuntimeObservationService.js +9 -25
  50. package/dist/application/JavaScriptRuntimeReconciliationService.js +45 -4
  51. package/dist/application/JavaScriptSemanticGraphAsyncProjection.js +11 -0
  52. package/dist/application/JavaScriptSemanticGraphChildProcessProjection.js +11 -0
  53. package/dist/application/JavaScriptSemanticGraphDataProjection.js +11 -0
  54. package/dist/application/JavaScriptSemanticGraphFlowProjection.js +14 -5
  55. package/dist/application/JsonFiles.js +1 -1
  56. package/dist/application/LazyAnalysisProvider.js +27 -6
  57. package/dist/application/ManagedMemberComparisonService.js +19 -6
  58. package/dist/application/NativeApiInspection.js +2 -0
  59. package/dist/application/NativeCallRoutes.js +72 -0
  60. package/dist/application/NativeDispatchMetadataInspection.js +33 -0
  61. package/dist/application/NativeUiActionTrace.js +73 -49
  62. package/dist/application/NativeValueTrace.js +320 -0
  63. package/dist/application/ProcessCaptureCapability.js +32 -5
  64. package/dist/application/ProcessCaptureEnvironment.js +9 -26
  65. package/dist/application/ProcessCaptureError.js +1 -5
  66. package/dist/application/ProcessCaptureJournal.js +3 -40
  67. package/dist/application/ProcessCaptureLifecycle.js +102 -111
  68. package/dist/application/ProcessCli.js +18 -25
  69. package/dist/application/ProcessEvidence.js +5 -7
  70. package/dist/application/ProcessFilesystemEffects.js +36 -0
  71. package/dist/application/ProcessHarness.js +41 -120
  72. package/dist/application/ProcessNormalization.js +2 -17
  73. package/dist/application/ProcessScenarioRuntimeValidation.js +76 -0
  74. package/dist/application/ReferenceSourceImport.js +3 -4
  75. package/dist/application/Setup.js +236 -84
  76. package/dist/application/SetupClientConfiguration.js +14 -9
  77. package/dist/application/SetupPlan.js +138 -86
  78. package/dist/application/SetupSkill.js +0 -1
  79. package/dist/application/SupportedClients.js +102 -21
  80. package/dist/application/Uninstall.js +31 -20
  81. package/dist/application/Update.js +93 -0
  82. package/dist/application/UpdateMaintenance.js +108 -0
  83. package/dist/application/UpdateRuntime.js +126 -0
  84. package/dist/application/runtime.js +13 -2
  85. package/dist/artifacts/ArtifactPaths.js +6 -8
  86. package/dist/artifacts/ArtifactProvider.js +94 -41
  87. package/dist/artifacts/AsarArtifactReader.js +19 -4
  88. package/dist/artifacts/KeyedArchiveReader.js +110 -0
  89. package/dist/artifacts/MachOSliceArtifactReader.js +53 -5
  90. package/dist/artifacts/ZipArtifactReader.js +18 -1
  91. package/dist/browser/BrowserScenarioSecrets.js +28 -1
  92. package/dist/browser/CdpBrowserProvider.js +36 -15
  93. package/dist/browser/CdpCaptureDocuments.js +22 -8
  94. package/dist/browser/CdpCaptureEventHandlers.js +14 -5
  95. package/dist/browser/CdpCaptureEventHelpers.js +13 -0
  96. package/dist/browser/CdpCaptureEvents.js +10 -1
  97. package/dist/browser/CdpElectronInspection.js +5 -10
  98. package/dist/browser/CdpElectronProvider.js +1 -5
  99. package/dist/browser/CdpElectronScripts.js +1 -1
  100. package/dist/browser/CdpEndpoint.js +3 -2
  101. package/dist/browser/CdpObservationSession.js +14 -10
  102. package/dist/browser/CdpPageCapture.js +1 -1
  103. package/dist/browser/CdpPageCaptureScripts.js +1 -1
  104. package/dist/browser/CdpSafeMetadata.js +5 -4
  105. package/dist/browser/CdpScreenshot.js +16 -5
  106. package/dist/browser/CdpTargetSession.js +25 -4
  107. package/dist/browser/CdpWebMcpDiscovery.js +93 -20
  108. package/dist/browser/JavaScriptRuntimeScope.js +28 -2
  109. package/dist/browser/PlaywrightBrowserScenarioProvider.js +9 -8
  110. package/dist/browser/PlaywrightElectronActiveActions.js +3 -10
  111. package/dist/browser/PlaywrightElectronActiveProvider.js +5 -5
  112. package/dist/browser/PlaywrightScenarioActions.js +1 -1
  113. package/dist/browser/PlaywrightScenarioArtifacts.js +13 -25
  114. package/dist/browser/PlaywrightScenarioBrowser.js +28 -25
  115. package/dist/browser/PlaywrightScenarioEvents.js +82 -93
  116. package/dist/browser/PlaywrightScenarioSession.js +27 -123
  117. package/dist/browser/PngVisualDiff.js +22 -3
  118. package/dist/browser/V8InspectorCaptureProjection.js +7 -1
  119. package/dist/browser/V8InspectorProvider.js +60 -7
  120. package/dist/browser/WebSourceMapFetcher.js +99 -53
  121. package/dist/cli/artifactCommands.js +56 -12
  122. package/dist/cli/coreAnalysisCommands.js +110 -0
  123. package/dist/cli/managedCommands.js +1 -31
  124. package/dist/cli/setupCommands.js +16 -14
  125. package/dist/cli/utilityCommands.js +61 -4
  126. package/dist/cli.js +5 -7
  127. package/dist/cliApplicationCommands.js +0 -83
  128. package/dist/cliBrowserAdvancedCommands.js +7 -11
  129. package/dist/cliBrowserCommands.js +15 -23
  130. package/dist/cliBrowserContext.js +3 -24
  131. package/dist/cliBrowserScenarioCommands.js +2 -10
  132. package/dist/cliCommandNames.js +82 -7
  133. package/dist/cliElectronCommands.js +10 -36
  134. package/dist/cliJavaScriptRuntimeCommands.js +6 -30
  135. package/dist/cliJsonInput.js +4 -2
  136. package/dist/cliLogging.js +16 -7
  137. package/dist/cliObservationOptions.js +1 -1
  138. package/dist/cliOutput.js +2 -4
  139. package/dist/cliProcessCommands.js +6 -33
  140. package/dist/cliSetup.js +90 -160
  141. package/dist/config/environment.js +2 -78
  142. package/dist/config/parseConfig.js +18 -109
  143. package/dist/config/parsers.js +0 -23
  144. package/dist/contracts/applicationToolContracts.js +1 -118
  145. package/dist/contracts/artifactToolContracts.js +11 -19
  146. package/dist/contracts/browserScenarioToolContracts.js +1 -5
  147. package/dist/contracts/browserToolContracts.js +9 -16
  148. package/dist/contracts/electronToolContracts.js +5 -6
  149. package/dist/contracts/enhancedInputs.js +3 -2
  150. package/dist/contracts/errorSchemas.js +16 -40
  151. package/dist/contracts/functionWorkflowToolContracts.js +2 -2
  152. package/dist/contracts/javascriptApplicationWorkflowExamples.js +2 -2
  153. package/dist/contracts/javascriptRuntimeObservationToolContracts.js +4 -4
  154. package/dist/contracts/javascriptRuntimeReconciliationExample.js +1 -1
  155. package/dist/contracts/managedToolContracts.js +7 -4
  156. package/dist/contracts/managedWorkflowExamples.js +0 -22
  157. package/dist/contracts/managedWorkflowToolContracts.js +16 -31
  158. package/dist/contracts/nativeToolContracts.js +9 -0
  159. package/dist/contracts/promptContracts.js +6 -6
  160. package/dist/contracts/sessionToolSchemas.js +3 -3
  161. package/dist/contracts/toolContractExamples.js +4 -3
  162. package/dist/contracts/toolContracts.js +18 -7
  163. package/dist/contracts/toolEffects.js +34 -21
  164. package/dist/contracts/toolOutputSchemaGroups.js +18 -5
  165. package/dist/contracts/toolOutputSchemaPrimitives.js +9 -6
  166. package/dist/contracts/toolSchemaMetadata.js +5 -8
  167. package/dist/doctorRuntime.js +0 -41
  168. package/dist/domain/analysisErrorPresentation.js +4 -28
  169. package/dist/domain/analysisErrorProjection.js +33 -50
  170. package/dist/domain/analysisProfile.js +1 -1
  171. package/dist/domain/analysisSnapshot.js +77 -3
  172. package/dist/domain/androidApplication.js +5 -4
  173. package/dist/domain/appleApplication.js +5 -4
  174. package/dist/domain/appleAssetCatalog.js +127 -0
  175. package/dist/domain/artifactComparison.js +7 -11
  176. package/dist/domain/artifactGraph.js +8 -6
  177. package/dist/domain/artifactInspection.js +13 -12
  178. package/dist/domain/binaryTarget.js +23 -9
  179. package/dist/domain/browserObservation.js +43 -24
  180. package/dist/domain/browserObservationSchemas.js +2 -1
  181. package/dist/domain/browserScenario.js +7 -107
  182. package/dist/domain/browserScenarioCapture.js +0 -1
  183. package/dist/domain/browserScenarioCaptureValues.js +5 -4
  184. package/dist/domain/browserScenarioDiff.js +1 -3
  185. package/dist/domain/browserScenarioValues.js +16 -107
  186. package/dist/domain/bundleComparison.js +18 -17
  187. package/dist/domain/callPathSchemas.js +17 -7
  188. package/dist/domain/changedBehavior.js +2 -3
  189. package/dist/domain/comparisonSemantics.js +19 -0
  190. package/dist/domain/completionLedgerGeneration.js +3 -2
  191. package/dist/domain/conformancePackage.js +2 -1
  192. package/dist/domain/conformanceTrustGate.js +3 -5
  193. package/dist/domain/customProtocolCapture.js +2 -2
  194. package/dist/domain/digests.js +30 -0
  195. package/dist/domain/dosMz.js +83 -0
  196. package/dist/domain/electronActiveObservation.js +7 -5
  197. package/dist/domain/electronObservation.js +3 -2
  198. package/dist/domain/electronStaticAnalysisNative.js +15 -6
  199. package/dist/domain/emptyArraySchema.js +3 -0
  200. package/dist/domain/errors.js +10 -28
  201. package/dist/domain/evidence.js +5 -3
  202. package/dist/domain/evidenceCompletionLedger.js +3 -2
  203. package/dist/domain/functionComparisonNormalization.js +24 -18
  204. package/dist/domain/functionComparisonResults.js +3 -7
  205. package/dist/domain/functionComparisonSchemas.js +3 -2
  206. package/dist/domain/hopperValues.js +108 -8
  207. package/dist/domain/javascriptApplicationAnalysis.js +4 -7
  208. package/dist/domain/javascriptApplicationEvidenceSchemas.js +4 -3
  209. package/dist/domain/javascriptApplicationGraphSchemas.js +8 -7
  210. package/dist/domain/javascriptApplicationVersionComparisonSchemas.js +9 -7
  211. package/dist/domain/javascriptApplicationVersionItems.js +12 -18
  212. package/dist/domain/javascriptAstValues.js +4 -0
  213. package/dist/domain/javascriptExportShapeComparison.js +1 -6
  214. package/dist/domain/javascriptExportShapeComparisonSchemas.js +6 -10
  215. package/dist/domain/javascriptExportShapeVariants.js +15 -2
  216. package/dist/domain/javascriptFeatureTraceSchemas.js +8 -7
  217. package/dist/domain/javascriptRuntimeObservation.js +14 -2
  218. package/dist/domain/javascriptRuntimeReconciliationMatching.js +8 -0
  219. package/dist/domain/javascriptRuntimeReconciliationParsing.js +4 -2
  220. package/dist/domain/javascriptRuntimeReconciliationResult.js +6 -4
  221. package/dist/domain/javascriptRuntimeReconciliationRuntime.js +15 -4
  222. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +19 -18
  223. package/dist/domain/javascriptRuntimeStaticCandidates.js +18 -6
  224. package/dist/domain/javascriptSemanticAnalysis.js +57 -19
  225. package/dist/domain/javascriptSemanticAsyncEffects.js +39 -40
  226. package/dist/domain/javascriptSemanticCalls.js +46 -27
  227. package/dist/domain/javascriptSemanticChildProcesses.js +43 -50
  228. package/dist/domain/javascriptSemanticDataEffectHelpers.js +91 -18
  229. package/dist/domain/javascriptSemanticDataEffects.js +22 -10
  230. package/dist/domain/javascriptSemanticGraphSchemas.js +8 -6
  231. package/dist/domain/javascriptSemanticObjects.js +13 -3
  232. package/dist/domain/javascriptSemanticProjection.js +144 -38
  233. package/dist/domain/javascriptSemanticPromises.js +14 -27
  234. package/dist/domain/javascriptSemanticQuerySchemas.js +6 -9
  235. package/dist/domain/javascriptSemanticResources.js +2 -5
  236. package/dist/domain/javascriptSemanticState.js +4 -0
  237. package/dist/domain/javascriptSemanticTraceSchemas.js +2 -1
  238. package/dist/domain/javascriptSemanticTraversal.js +13 -5
  239. package/dist/domain/javascriptSemanticValues.js +10 -9
  240. package/dist/domain/javascriptSourceParser.js +5 -1
  241. package/dist/domain/javascriptStaticAnalysisCalls.js +8 -5
  242. package/dist/domain/javascriptStaticAnalysisHelpers.js +16 -7
  243. package/dist/domain/keyedArchive.js +181 -0
  244. package/dist/domain/managedApplicationGraph.js +4 -3
  245. package/dist/domain/managedArtifact.js +2 -1
  246. package/dist/domain/managedMemberComparison.js +18 -13
  247. package/dist/domain/managedMemberComparisonCoverage.js +2 -1
  248. package/dist/domain/managedMemberComparisonItems.js +27 -7
  249. package/dist/domain/managedMemberComparisonMatch.js +22 -6
  250. package/dist/domain/managedNativeVerificationMatch.js +2 -2
  251. package/dist/domain/managedNativeVerificationSchemas.js +7 -5
  252. package/dist/domain/managedReconstruction.js +6 -5
  253. package/dist/domain/nativeApiBoundary.js +7 -0
  254. package/dist/domain/nativeDataType.js +51 -0
  255. package/dist/domain/nativeInspection.js +0 -1
  256. package/dist/domain/nativeInstruction.js +82 -0
  257. package/dist/domain/nativeInvestigationGraph.js +9 -5
  258. package/dist/domain/nativeUiObservation.js +123 -0
  259. package/dist/domain/nativeValueFlow.js +17 -0
  260. package/dist/domain/nativeValueTrace.js +64 -0
  261. package/dist/domain/objcSwiftMetadata.js +39 -0
  262. package/dist/domain/peInspection.js +1 -0
  263. package/dist/domain/processCapture.js +5 -55
  264. package/dist/domain/processCaptureExample.js +0 -9
  265. package/dist/domain/processCaptureValidation.js +13 -144
  266. package/dist/domain/processComparison.js +3 -25
  267. package/dist/domain/processObservation.js +0 -29
  268. package/dist/domain/processScenario.js +28 -228
  269. package/dist/domain/processTraceDimensionProjection.js +0 -15
  270. package/dist/domain/processTraceEvaluation.js +0 -6
  271. package/dist/domain/protocolCapture.js +8 -36
  272. package/dist/domain/reconstructionCoverage.js +3 -2
  273. package/dist/domain/reconstructionObligationLedgerSchemas.js +4 -12
  274. package/dist/domain/reconstructionReadinessSchemas.js +4 -3
  275. package/dist/domain/reconstructionVerification.js +2 -1
  276. package/dist/domain/reconstructionVerificationSchemas.js +6 -13
  277. package/dist/domain/referenceSourceClassification.js +0 -110
  278. package/dist/domain/referenceSourceGraph.js +15 -5
  279. package/dist/domain/residualUnknown.js +3 -2
  280. package/dist/domain/runtimeIdentification.js +6 -5
  281. package/dist/domain/sourceMapContents.js +5 -0
  282. package/dist/domain/sourceToBundleComparison.js +3 -10
  283. package/dist/domain/sourceToBundleComparisonSchemas.js +7 -6
  284. package/dist/domain/sourceToBundleSignals.js +9 -3
  285. package/dist/domain/staticRuntimeCorrelation.js +5 -11
  286. package/dist/domain/webBundleAnalysis.js +17 -9
  287. package/dist/domain/webBundleAnalyzer.js +1 -1
  288. package/dist/domain/webCaptureDiff.js +5 -11
  289. package/dist/domain/webCaptureDiffSchemas.js +2 -1
  290. package/dist/domain/webMcpDiscovery.js +2 -1
  291. package/dist/dotnet/ManagedMemberInspectorCore.js +15 -7
  292. package/dist/dotnet/ManagedMemberInstructionDecoder.js +57 -40
  293. package/dist/dotnet/ManagedMemberRows.js +2 -0
  294. package/dist/dotnet/ManagedMethodBodyReader.js +15 -8
  295. package/dist/dotnet/ManagedPeReader.js +2 -0
  296. package/dist/generatedMcpToolCatalog.js +1 -1
  297. package/dist/generatedPackageMetadata.js +2 -2
  298. package/dist/ghidra/GhidraAnalysisProfile.js +15 -5
  299. package/dist/ghidra/GhidraClient.js +38 -8
  300. package/dist/ghidra/GhidraFunctionValues.js +56 -20
  301. package/dist/ghidra/GhidraInstallation.js +7 -4
  302. package/dist/ghidra/GhidraInventoryValues.js +44 -9
  303. package/dist/ghidra/GhidraLauncher.js +18 -3
  304. package/dist/ghidra/GhidraProvider.js +23 -2
  305. package/dist/ghidra/GhidraRequestQueue.js +45 -4
  306. package/dist/ghidra/GhidraSessionValues.js +5 -0
  307. package/dist/hopper/HopperAnalysisProfile.js +2 -0
  308. package/dist/hopper/HopperProvider.js +29 -6
  309. package/dist/hopper/HopperTargetLease.js +18 -4
  310. package/dist/logger.js +0 -13
  311. package/dist/main/messages.js +0 -1
  312. package/dist/main/reload.js +3 -32
  313. package/dist/main/shutdown.js +1 -2
  314. package/dist/main/transport.js +0 -17
  315. package/dist/main.js +0 -10
  316. package/dist/native/AppleDispatchMetadata.js +582 -0
  317. package/dist/native/AppleObjcProtocols.js +88 -0
  318. package/dist/native/AppleSwiftVtables.js +86 -0
  319. package/dist/native/CommandRunner.js +1 -1
  320. package/dist/native/NativeHostCapabilities.js +23 -0
  321. package/dist/native/NativeMacOSProvider.js +61 -9
  322. package/dist/native/NativeMachoInspection.js +39 -6
  323. package/dist/native/NativeUiHelperRuntime.js +42 -0
  324. package/dist/native/NativeUiObservation.js +174 -0
  325. package/dist/native/parsers/codesign.js +4 -1
  326. package/dist/native/parsers/dyldInfo.js +51 -25
  327. package/dist/native/parsers/lipo.js +13 -4
  328. package/dist/native/parsers/otool.js +84 -39
  329. package/dist/native/parsers/plist.js +2 -1
  330. package/dist/process/ExecFileOutput.js +5 -1
  331. package/dist/process/ProcessOwnership.js +69 -33
  332. package/dist/process/ProcessOwnershipObservation.js +31 -12
  333. package/dist/process/ProviderProcess.js +4 -2
  334. package/dist/reference/ReferenceSourceReaderEntries.js +48 -31
  335. package/dist/reference/ReferenceSourceReaderErrors.js +24 -0
  336. package/dist/reference/ReferenceSourceReaderFile.js +11 -5
  337. package/dist/reference/ReferenceSourceReaderValidate.js +22 -8
  338. package/dist/server/createServer.js +7 -62
  339. package/dist/server/registerApplicationTools/helpers.js +2 -9
  340. package/dist/server/registerApplicationTools.js +0 -4
  341. package/dist/server/registerArtifactComparisonTool.js +1 -1
  342. package/dist/server/registerBrowserScenarioTool.js +4 -2
  343. package/dist/server/registerBrowserTools.js +7 -7
  344. package/dist/server/registerBundleComparisonTool.js +1 -1
  345. package/dist/server/registerCloseLifecycleTool.js +1 -1
  346. package/dist/server/registerElectronTools.js +10 -4
  347. package/dist/server/registerEnhancedTools.js +20 -12
  348. package/dist/server/registerEvidenceTools.js +4 -28
  349. package/dist/server/registerFunctionComparisonTool.js +1 -1
  350. package/dist/server/registerInvestigationTools.js +6 -6
  351. package/dist/server/registerJavaScriptRuntimeObservationTools.js +2 -2
  352. package/dist/server/registerManagedTools.js +28 -14
  353. package/dist/server/registerManagedWorkflowTools.js +0 -2
  354. package/dist/server/registerProcessComparisonTool.js +1 -3
  355. package/dist/server/registerSessionRecordTools.js +9 -9
  356. package/dist/server/registerSessionStatusTool.js +1 -1
  357. package/dist/server/registerSessionTools.js +28 -57
  358. package/dist/server/sessionAvailabilityPolicy.js +2 -3
  359. package/dist/server/sessionToolPolicies.js +0 -4
  360. package/dist/server/toolResult.js +8 -10
  361. package/package.json +32 -22
  362. package/skills/reverse-engineer-anything/SKILL.md +15 -11
  363. package/skills/reverse-engineer-anything/references/evidence-workflows.md +3 -2
  364. package/skills/reverse-engineer-anything/references/javascript-applications.md +3 -2
  365. package/skills/reverse-engineer-anything/references/native-and-artifacts.md +8 -6
  366. package/skills/reverse-engineer-anything/references/runtime-observation.md +15 -11
  367. package/dist/application/CommandShimReplay.js +0 -152
  368. package/dist/application/ConfiguredRoots.js +0 -19
  369. package/dist/application/InstrumentedJavaScriptReplayHost.js +0 -36
  370. package/dist/application/JavaScriptReplayPermission.js +0 -16
  371. package/dist/application/JavaScriptReplayPlanning.js +0 -207
  372. package/dist/application/JavaScriptReplayService.js +0 -274
  373. package/dist/application/LoopbackReplay.js +0 -389
  374. package/dist/application/LoopbackReplayRecorder.js +0 -129
  375. package/dist/application/ManagedRuntimeCorrelationService.js +0 -104
  376. package/dist/application/NodeRuntimeCharacterizationService.js +0 -191
  377. package/dist/application/PermissionAuthority.js +0 -268
  378. package/dist/application/PermissionConfiguration.js +0 -26
  379. package/dist/application/PermissionFailure.js +0 -5
  380. package/dist/application/ProcessCaptureAuthority.js +0 -24
  381. package/dist/application/ProcessCapturePermission.js +0 -13
  382. package/dist/application/ProcessCheckpoints.js +0 -178
  383. package/dist/application/ProcessReactiveCoordinator.js +0 -223
  384. package/dist/application/ProcessReactiveEffects.js +0 -153
  385. package/dist/application/ProcessReactiveHarness.js +0 -106
  386. package/dist/application/ProcessReactiveObservations.js +0 -105
  387. package/dist/application/ProjectPermissionStore.js +0 -199
  388. package/dist/application/RuntimeExecutableDiagnostics.js +0 -198
  389. package/dist/application/Upgrade.js +0 -134
  390. package/dist/browser/SensitiveTextCapture.js +0 -8
  391. package/dist/cliPolicyCommands.js +0 -185
  392. package/dist/config/browserScenario.js +0 -77
  393. package/dist/config/electronAutomation.js +0 -35
  394. package/dist/config/javascriptReplay.js +0 -41
  395. package/dist/config/managedRuntime.js +0 -25
  396. package/dist/config/passiveObservation.js +0 -87
  397. package/dist/config/permissions.js +0 -23
  398. package/dist/config/processCapture.js +0 -47
  399. package/dist/contracts/replayMachineExample.js +0 -37
  400. package/dist/domain/javascriptExportInstrumentation.js +0 -95
  401. package/dist/domain/javascriptReplay.js +0 -360
  402. package/dist/domain/managedRuntimeCorrelation.js +0 -181
  403. package/dist/domain/nodeRuntimeCharacterization.js +0 -63
  404. package/dist/domain/permissionPolicy.js +0 -176
  405. package/dist/domain/processCaptureReactiveSchema.js +0 -68
  406. package/dist/domain/processCaptureReactiveValidation.js +0 -180
  407. package/dist/domain/processReactiveCheckpointDataflow.js +0 -32
  408. package/dist/domain/processReactiveMatching.js +0 -196
  409. package/dist/domain/processReactiveRuntime.js +0 -116
  410. package/dist/domain/processReactiveScenario.js +0 -296
  411. package/dist/domain/processReactiveScenarioPreflight.js +0 -95
  412. package/dist/domain/processReactiveTransition.js +0 -187
  413. package/dist/domain/replayMachine.js +0 -320
  414. package/dist/domain/replayMachineRun.js +0 -168
  415. package/dist/domain/replayMachineRuntime.js +0 -296
  416. package/dist/domain/replayMachineValues.js +0 -84
  417. package/dist/domain/runtimeCharacterization.js +0 -84
  418. package/dist/replay/JavaScriptReplayWorker.js +0 -382
  419. package/dist/replay/JavaScriptReplayWorkerTypes.js +0 -1
  420. package/dist/replay/LinuxJavaScriptReplayRunner.js +0 -216
  421. package/dist/replay/LinuxJavaScriptReplaySandbox.js +0 -121
  422. package/dist/replay/LinuxRuntimeClosure.js +0 -44
  423. package/dist/replay/LinuxSeccompPolicy.js +0 -40
  424. package/dist/replay/ReplayOutcome.js +0 -104
  425. package/dist/replay/ReplayProcessLifecycle.js +0 -96
  426. package/dist/replay/ReplaySeccompFile.js +0 -29
  427. package/dist/replay/ReplayWorkerProtocol.js +0 -58
  428. package/dist/replay/SystemJavaScriptReplayHost.js +0 -153
  429. package/dist/server/ProcessCaptureElicitation.js +0 -153
  430. package/dist/server/registerApplicationTools/characterization.js +0 -46
  431. package/dist/server/registerApplicationTools/controlledReplay.js +0 -31
  432. package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +0 -29
  433. package/dist/server/registerReplayMachineTool.js +0 -14
  434. package/skills/reverse-engineer-anything/references/controlled-replay.md +0 -12
@@ -128,6 +128,10 @@ class CapabilityUnavailableError(Exception):
128
128
  """The active Hopper build lacks one admitted public API operation."""
129
129
 
130
130
 
131
+ class InvalidRequestError(Exception):
132
+ """Caller input failed bridge request or operation validation."""
133
+
134
+
131
135
  EXHAUSTIVE_ANALYSIS_METHODS = frozenset(
132
136
  (
133
137
  "analyze_function",
@@ -150,6 +154,11 @@ EXHAUSTIVE_ANALYSIS_METHODS = frozenset(
150
154
 
151
155
 
152
156
  def _hex(value):
157
+ if not isinstance(value, int) or isinstance(value, bool):
158
+ try:
159
+ value = int(str(value), 16)
160
+ except ValueError as error:
161
+ raise ValueError("Hopper returned a non-hexadecimal address") from error
153
162
  return "0x%x" % value
154
163
 
155
164
 
@@ -177,8 +186,8 @@ def _document(name=None):
177
186
  current = api.current_document()
178
187
  if current is not None and current.getDocumentName() == name:
179
188
  return current
180
- raise ValueError("Hopper document name is ambiguous")
181
- raise ValueError("Unknown Hopper document")
189
+ raise InvalidRequestError("Hopper document name is ambiguous")
190
+ raise InvalidRequestError("Unknown Hopper document")
182
191
  if _selected_document is not None:
183
192
  for candidate in documents:
184
193
  if candidate.getDocumentName() == _selected_document:
@@ -188,7 +197,7 @@ def _document(name=None):
188
197
  return session_document
189
198
  current = api.current_document()
190
199
  if current is None:
191
- raise ValueError("No Hopper document is loaded")
200
+ raise CapabilityUnavailableError("No Hopper document is loaded")
192
201
  return current
193
202
 
194
203
 
@@ -197,20 +206,20 @@ def _address(document, value=None):
197
206
  if value is None:
198
207
  return document.getCurrentAddress()
199
208
  if not isinstance(value, str):
200
- raise ValueError("Address must be a string")
209
+ raise InvalidRequestError("Address must be a string")
201
210
  try:
202
211
  return int(value, 16)
203
212
  except ValueError:
204
213
  result = document.getAddressForName(value)
205
214
  if result in BAD_ADDRESSES:
206
- raise ValueError("Unknown Hopper address or name")
215
+ raise InvalidRequestError("Unknown Hopper address or name")
207
216
  return result
208
217
 
209
218
 
210
219
  def _segment(document, address):
211
220
  result = document.getSegmentAtAddress(address)
212
221
  if result is None:
213
- raise ValueError("Address is outside every segment")
222
+ raise InvalidRequestError("Address is outside every segment")
214
223
  return result
215
224
 
216
225
 
@@ -218,7 +227,7 @@ def _procedure(document, value=None):
218
227
  address = document.getCurrentAddress() if value is None else _address(document, value)
219
228
  result = _segment(document, address).getProcedureAtAddress(address)
220
229
  if result is None:
221
- raise ValueError("No procedure exists at the requested address")
230
+ raise InvalidRequestError("No procedure exists at the requested address")
222
231
  return result
223
232
 
224
233
 
@@ -232,6 +241,10 @@ def _procedure_identity(procedure):
232
241
  "address": _hex(procedure.getEntryPoint()),
233
242
  "name": _procedure_name(procedure),
234
243
  "classification": None,
244
+ "body": {
245
+ "available": False,
246
+ "reason": "Hopper's public Python API does not expose complete function body ranges",
247
+ },
235
248
  }
236
249
 
237
250
 
@@ -278,7 +291,7 @@ def _procedure_references(document, params):
278
291
  procedure = _procedure(document, params.get("procedure"))
279
292
  direction = params.get("direction", "outgoing")
280
293
  if direction not in ("incoming", "outgoing"):
281
- raise ValueError("direction must be incoming or outgoing")
294
+ raise InvalidRequestError("direction must be incoming or outgoing")
282
295
  addresses = _instruction_addresses(procedure)
283
296
  edges = set()
284
297
  for address in addresses:
@@ -300,6 +313,12 @@ def _procedure_references(document, params):
300
313
  })
301
314
  return {
302
315
  "procedure": _procedure_identity(procedure), "direction": direction,
316
+ "reference_kinds_available": False,
317
+ # The public Hopper API returns observed references but does not expose
318
+ # enough flow metadata to enumerate calls with no resolved target.
319
+ # Keep the required list field explicit; the provider records this as
320
+ # unknown coverage rather than claiming the list is exhaustive.
321
+ "unresolved_calls": [],
303
322
  "references": items,
304
323
  }
305
324
 
@@ -366,13 +385,13 @@ def _search_inventory(document, kind):
366
385
  def _search_results(document, kind, params):
367
386
  pattern = params.get("pattern")
368
387
  if not isinstance(pattern, str) or not pattern:
369
- raise ValueError("pattern must be a non-empty string")
388
+ raise InvalidRequestError("pattern must be a non-empty string")
370
389
  mode = params.get("mode", "literal")
371
390
  if mode not in ("literal", "regex"):
372
- raise ValueError("mode must be literal or regex")
391
+ raise InvalidRequestError("mode must be literal or regex")
373
392
  case_sensitive = params.get("case_sensitive", False)
374
393
  if not isinstance(case_sensitive, bool):
375
- raise ValueError("case_sensitive must be a boolean")
394
+ raise InvalidRequestError("case_sensitive must be a boolean")
376
395
 
377
396
  if mode == "literal":
378
397
  needle = pattern if case_sensitive else pattern.casefold()
@@ -381,7 +400,7 @@ def _search_results(document, kind, params):
381
400
  try:
382
401
  expression = re.compile(pattern, 0 if case_sensitive else re.IGNORECASE)
383
402
  except (re.error, OverflowError) as error:
384
- raise ValueError("Invalid regex pattern") from error
403
+ raise InvalidRequestError("Invalid regex pattern") from error
385
404
  matches = lambda value: expression.search(value) is not None
386
405
 
387
406
  selected = []
@@ -544,7 +563,11 @@ def _analyze_function(document, params):
544
563
  referenced_strings.sort(key=lambda item: (int(item["address"], 16), int(item["source_address"], 16)))
545
564
  referenced_names.sort(key=lambda item: (int(item["address"], 16), int(item["source_address"], 16)))
546
565
  return {
547
- "procedure": {"address": _hex(procedure.getEntryPoint()), "name": _procedure_name(procedure), "classification": None, "signature": procedure.signatureString(), "locals": _procedure_locals(procedure)},
566
+ "procedure": {
567
+ **_procedure_identity(procedure),
568
+ "signature": procedure.signatureString(),
569
+ "locals": _procedure_locals(procedure),
570
+ },
548
571
  "pseudocode": pseudo,
549
572
  "assembly": assembly_lines,
550
573
  "comments": comments,
@@ -618,9 +641,9 @@ def _dispatch(method, params):
618
641
  if method == "read_bytes":
619
642
  length = params.get("length", 256)
620
643
  if isinstance(length, bool) or not isinstance(length, int):
621
- raise ValueError("Byte-read length must be an integer")
644
+ raise InvalidRequestError("Byte-read length must be an integer")
622
645
  if length < 1:
623
- raise ValueError("Byte-read length must be at least 1")
646
+ raise InvalidRequestError("Byte-read length must be at least 1")
624
647
  reader = getattr(document, "readBytes", None)
625
648
  if not callable(reader):
626
649
  raise CapabilityUnavailableError(
@@ -654,7 +677,7 @@ def _dispatch(method, params):
654
677
  or offset in BAD_ADDRESSES
655
678
  or offset < 0
656
679
  ):
657
- raise ValueError("Address has no authoritative file-offset mapping")
680
+ raise InvalidRequestError("Address has no authoritative file-offset mapping")
658
681
  return {"address": _hex(address), "file_offset": offset}
659
682
  if method == "resolve_containing_procedure":
660
683
  address = _address(document, params.get("address"))
@@ -690,7 +713,7 @@ def _dispatch(method, params):
690
713
  else:
691
714
  result = document.getInstructionStart(max(0, target - 1))
692
715
  if result in BAD_ADDRESSES:
693
- raise ValueError("No adjacent address")
716
+ raise InvalidRequestError("No adjacent address")
694
717
  return _hex(result)
695
718
  if method == "list_segments":
696
719
  result = []
@@ -729,14 +752,14 @@ def _dispatch(method, params):
729
752
  if requested is not None:
730
753
  key = _hex(_address(document, requested))
731
754
  values = {key: values[key]} if key in values else {}
732
- return [{"address": _hex(address), "value": value} for address, value in sorted(values.items())]
755
+ return [{"address": address, "value": value} for address, value in values.items()]
733
756
  if method == "list_names":
734
757
  result = dict(_search_inventory(document, "name"))
735
758
  requested = params.get("address")
736
759
  if requested is not None:
737
760
  key = _hex(_address(document, requested))
738
761
  result = {key: result[key]} if key in result else {}
739
- return [{"address": _hex(address), "value": value} for address, value in sorted(result.items(), key=lambda item: int(item[0]))]
762
+ return [{"address": address, "value": value} for address, value in result.items()]
740
763
  if method in ("search_procedures", "search_strings"):
741
764
  kind = "procedure" if method == "search_procedures" else "string"
742
765
  return _search_results(document, kind, params)
@@ -755,7 +778,16 @@ def _dispatch(method, params):
755
778
  if method == "procedure_info":
756
779
  blocks = list(procedure.basicBlockIterator())
757
780
  length = sum(max(0, block.getEndingAddress() - block.getStartingAddress()) for block in blocks)
758
- return {"name": _procedure_name(procedure), "entrypoint": _hex(procedure.getEntryPoint()), "basicblock_count": procedure.getBasicBlockCount(), "length": length, "signature": procedure.signatureString(), "locals": _procedure_locals(procedure), "classification": None}
781
+ return {
782
+ "name": _procedure_name(procedure),
783
+ "entrypoint": _hex(procedure.getEntryPoint()),
784
+ "basicblock_count": procedure.getBasicBlockCount(),
785
+ "length": length,
786
+ "signature": procedure.signatureString(),
787
+ "locals": _procedure_locals(procedure),
788
+ "classification": None,
789
+ "body": _procedure_identity(procedure)["body"],
790
+ }
759
791
  if method == "set_address_name":
760
792
  address = _address(document, params.get("address"))
761
793
  try:
@@ -789,7 +821,7 @@ def _dispatch(method, params):
789
821
  address = _address(document, params.get("address"))
790
822
  document.removeBookmarkAtAddress(address)
791
823
  return not document.hasBookmarkAtAddress(address)
792
- raise ValueError("Unknown bridge method")
824
+ raise InvalidRequestError("Unknown bridge method")
793
825
 
794
826
 
795
827
  def _serve_connection(connection):
@@ -803,13 +835,24 @@ def _serve_connection(connection):
803
835
  authenticated = False
804
836
  should_stop = False
805
837
  try:
806
- request = json.loads(line.decode("utf-8"))
807
- if set(request) != {"id", "token", "method", "params"}:
808
- raise ValueError("Invalid bridge request shape")
838
+ try:
839
+ request = json.loads(line.decode("utf-8"))
840
+ except (UnicodeDecodeError, json.JSONDecodeError) as error:
841
+ raise InvalidRequestError("Invalid bridge request JSON") from error
842
+ if not isinstance(request, dict) or set(request) != {"id", "token", "method", "params"}:
843
+ raise InvalidRequestError("Invalid bridge request shape")
809
844
  request_id = request["id"]
810
845
  if isinstance(request_id, bool) or not isinstance(request_id, int) or request_id < 0:
811
- raise ValueError("Invalid bridge request id")
812
- if not isinstance(request["token"], str) or not hmac.compare_digest(request["token"], REA_TOKEN):
846
+ raise InvalidRequestError("Invalid bridge request id")
847
+ if (
848
+ not isinstance(request["method"], str) or not request["method"]
849
+ or not isinstance(request["params"], dict)
850
+ ):
851
+ raise InvalidRequestError("Invalid bridge method or parameters")
852
+ if (
853
+ not isinstance(request["token"], str) or not request["token"].isascii()
854
+ or not hmac.compare_digest(request["token"], REA_TOKEN)
855
+ ):
813
856
  raise PermissionError("Invalid bridge capability")
814
857
  authenticated = True
815
858
  _write_message(file, {"id": request_id, "event": {
@@ -864,7 +907,7 @@ def _diagnostic_type(error):
864
907
  return "capability_unavailable"
865
908
  if isinstance(error, PermissionError):
866
909
  return "authorization"
867
- if isinstance(error, (ValueError, TypeError, KeyError)):
910
+ if isinstance(error, InvalidRequestError):
868
911
  return "invalid_request"
869
912
  return "bridge_exception"
870
913
 
@@ -0,0 +1,157 @@
1
+ import AppKit
2
+ import ApplicationServices
3
+ import CryptoKit
4
+ import ScreenCaptureKit
5
+ import Darwin
6
+
7
+ struct Request: Decodable {
8
+ var pid: Int32
9
+ var window_id: UInt32
10
+ var executable: String
11
+ var sha256: String
12
+ var launch_time: Double?
13
+ var screenshot: Bool
14
+ var accessibility: Bool
15
+ var max_nodes: Int
16
+ var action: Action?
17
+ }
18
+ struct Action: Decodable { var kind: String; var path: [Int]?; var direction: String?; var text: String? }
19
+ struct BoundaryFailure: Error { var code: String; var message: String }
20
+ func fail(_ code: String, _ message: String) throws -> Never { throw BoundaryFailure(code: code, message: message) }
21
+ func attribute(_ element: AXUIElement, _ key: String) -> CFTypeRef? {
22
+ var value: CFTypeRef?
23
+ return AXUIElementCopyAttributeValue(element, key as CFString, &value) == .success ? value : nil
24
+ }
25
+ func childCount(_ element: AXUIElement) -> Int {
26
+ var count = 0
27
+ return AXUIElementGetAttributeValueCount(element, kAXChildrenAttribute as CFString, &count) == .success ? count : 0
28
+ }
29
+ func children(_ element: AXUIElement, limit: Int) -> [AXUIElement] {
30
+ var value: CFArray?
31
+ let count = min(limit, childCount(element))
32
+ if count == 0 { return [] }
33
+ return AXUIElementCopyAttributeValues(element, kAXChildrenAttribute as CFString, 0, count, &value) == .success ? value as? [AXUIElement] ?? [] : []
34
+ }
35
+ func text(_ element: AXUIElement, _ key: String) -> Any { (attribute(element, key) as? String) ?? NSNull() as Any }
36
+ func windowBounds(_ element: AXUIElement) -> CGRect? {
37
+ guard let p = attribute(element, kAXPositionAttribute), let s = attribute(element, kAXSizeAttribute),
38
+ CFGetTypeID(p) == AXValueGetTypeID(), CFGetTypeID(s) == AXValueGetTypeID() else { return nil }
39
+ var point = CGPoint.zero; var size = CGSize.zero
40
+ guard AXValueGetValue(p as! AXValue, .cgPoint, &point), AXValueGetValue(s as! AXValue, .cgSize, &size) else { return nil }
41
+ return CGRect(origin: point, size: size)
42
+ }
43
+ func observe(_ request: Request) async throws -> [String: Any] {
44
+ guard let app = NSRunningApplication(processIdentifier: request.pid), let url = app.executableURL else {
45
+ try fail("target-mismatch", "Selected PID does not expose an application executable URL")
46
+ }
47
+ guard let canonicalPointer = realpath(url.path, nil) else { try fail("target-mismatch", "Running executable path cannot be resolved") }
48
+ defer { free(canonicalPointer) }
49
+ let canonicalExecutable = String(cString: canonicalPointer)
50
+ guard canonicalExecutable == request.executable else {
51
+ try fail("target-mismatch", "Selected PID executable \(canonicalExecutable) differs from active target \(request.executable)")
52
+ }
53
+ guard let launch = app.launchDate?.timeIntervalSince1970 else {
54
+ try fail("process-identity-unavailable", "Selected application does not expose a launch time; stable PID reuse checks are unavailable")
55
+ }
56
+ if let expected = request.launch_time, expected != launch { try fail("process-replaced", "Selected process was replaced") }
57
+ let executableSize = (try FileManager.default.attributesOfItem(atPath: url.path)[.size] as? NSNumber)?.int64Value ?? -1
58
+ guard executableSize >= 0 && executableSize <= 256 * 1024 * 1024 else { try fail("target-limit", "Running executable exceeds the 256 MiB identity-check budget") }
59
+ let executableBytes = try Data(contentsOf: url, options: .mappedIfSafe)
60
+ guard SHA256.hash(data: executableBytes).map({ String(format: "%02x", $0) }).joined() == request.sha256 else {
61
+ try fail("target-mismatch", "Running executable bytes differ from the active target digest")
62
+ }
63
+ guard let windows = CGWindowListCopyWindowInfo([.optionIncludingWindow], request.window_id) as? [[String: Any]],
64
+ windows.count == 1, let window = windows.first,
65
+ (window[kCGWindowOwnerPID as String] as? NSNumber)?.int32Value == request.pid,
66
+ (window[kCGWindowLayer as String] as? NSNumber)?.intValue == 0,
67
+ let boundsDictionary = window[kCGWindowBounds as String] as? [String: Any],
68
+ let bounds = CGRect(dictionaryRepresentation: boundsDictionary as CFDictionary) else {
69
+ try fail("window-mismatch", "Selected window is absent or belongs to another process")
70
+ }
71
+ if request.screenshot && !CGPreflightScreenCaptureAccess() {
72
+ try fail("screen-recording-denied", "Grant Screen Recording to the REA host in System Settings > Privacy & Security, then retry; no broad capture fallback is used")
73
+ }
74
+ var selected: AXUIElement?
75
+ if request.accessibility || request.action != nil {
76
+ guard AXIsProcessTrusted() else { try fail("accessibility-denied", "Grant Accessibility to the REA host in System Settings > Privacy & Security, then retry") }
77
+ let application = AXUIElementCreateApplication(request.pid)
78
+ AXUIElementSetMessagingTimeout(application, 2)
79
+ guard let axWindows = attribute(application, kAXWindowsAttribute) as? [AXUIElement] else {
80
+ try fail("accessibility-unavailable", "Selected application does not expose accessibility windows")
81
+ }
82
+ let matches = axWindows.filter { windowBounds($0) == bounds }
83
+ guard matches.count == 1 else { try fail("ambiguous-window", "Accessibility window geometry does not identify exactly one selected window; selected CG bounds \(bounds), AX candidates \(axWindows.map { String(describing: windowBounds($0)) })") }
84
+ selected = matches[0]
85
+ }
86
+ if let action = request.action, let root = selected {
87
+ var element = root
88
+ for index in action.path ?? [] {
89
+ var selectedChild: CFArray?
90
+ guard index >= 0 && index < childCount(element),
91
+ AXUIElementCopyAttributeValues(element, kAXChildrenAttribute as CFString, index, 1, &selectedChild) == .success,
92
+ let item = (selectedChild as? [AXUIElement])?.first else { try fail("element-missing", "Selected accessibility path no longer exists") }
93
+ element = item
94
+ }
95
+ var owner: pid_t = 0
96
+ guard AXUIElementGetPid(element, &owner) == .success && owner == request.pid else { try fail("element-owner-mismatch", "Selected element belongs to another process") }
97
+ let outcome: AXError
98
+ switch action.kind {
99
+ case "click": outcome = AXUIElementPerformAction(element, kAXPressAction as CFString)
100
+ case "scroll": outcome = AXUIElementPerformAction(element, (action.direction == "increment" ? kAXIncrementAction : kAXDecrementAction) as CFString)
101
+ case "key-entry": outcome = AXUIElementSetAttributeValue(element, kAXValueAttribute as CFString, (action.text ?? "") as CFString)
102
+ default: try fail("unsupported-action", "Only selected-element press, increment/decrement and text-value entry are admitted")
103
+ }
104
+ guard outcome == .success else { try fail("action-failed", "Accessibility action failed with AXError \(outcome.rawValue)") }
105
+ }
106
+ var nodes: [[String: Any]] = []; var truncated = false
107
+ if request.accessibility, let root = selected {
108
+ var pending: [(AXUIElement, [Int])] = [(root, [])]
109
+ while let (element, path) = pending.popLast() {
110
+ if nodes.count >= request.max_nodes { truncated = true; break }
111
+ let totalChildren = childCount(element)
112
+ var actions: CFArray?
113
+ AXUIElementCopyActionNames(element, &actions)
114
+ nodes.append(["path": path, "role": text(element, kAXRoleAttribute), "title": text(element, kAXTitleAttribute), "value": text(element, kAXValueAttribute), "actions": actions as? [String] ?? [], "children_count": totalChildren])
115
+ if path.count >= 32 { if totalChildren > 0 { truncated = true }; continue }
116
+ let available = max(0, request.max_nodes - nodes.count - pending.count)
117
+ let count = min(available, totalChildren)
118
+ let items = children(element, limit: count)
119
+ if totalChildren > count { truncated = true }
120
+ for index in (0..<count).reversed() { pending.append((items[index], path + [index])) }
121
+ }
122
+ }
123
+ var screenshot: Any = NSNull()
124
+ if request.screenshot {
125
+ guard #available(macOS 14, *) else { try fail("unsupported-host", "Selected-window screenshots require macOS 14 or later") }
126
+ let content = try await SCShareableContent.excludingDesktopWindows(true, onScreenWindowsOnly: false)
127
+ guard let scWindow = content.windows.first(where: { $0.windowID == request.window_id && $0.owningApplication?.processID == request.pid }) else {
128
+ try fail("capture-window-missing", "Selected window disappeared before capture")
129
+ }
130
+ guard bounds.width > 0 && bounds.height > 0 && bounds.width <= 100000 && bounds.height <= 100000 else { try fail("window-bounds", "Selected window has invalid or oversized geometry") }
131
+ let filter = SCContentFilter(desktopIndependentWindow: scWindow)
132
+ let configuration = SCStreamConfiguration()
133
+ let scale = min(1, 2048 / max(bounds.width, bounds.height))
134
+ configuration.width = max(1, Int(bounds.width * scale)); configuration.height = max(1, Int(bounds.height * scale))
135
+ configuration.showsCursor = false
136
+ let image = try await SCScreenshotManager.captureImage(contentFilter: filter, configuration: configuration)
137
+ guard let png = NSBitmapImageRep(cgImage: image).representation(using: .png, properties: [:]) else {
138
+ try fail("capture-failed", "Selected-window PNG encoding failed")
139
+ }
140
+ screenshot = ["mime_type": "image/png", "base64": png.base64EncodedString(), "sha256": SHA256.hash(data: png).map({ String(format: "%02x", $0) }).joined(), "width": image.width, "height": image.height]
141
+ }
142
+ return ["window": ["pid": request.pid, "window_id": request.window_id, "executable": request.executable, "launch_time": launch, "title": window[kCGWindowName as String] as? String ?? ""], "nodes": nodes, "truncated": truncated, "screenshot": screenshot, "gaps": request.accessibility ? [] : ["Accessibility capture was disabled"]]
143
+ }
144
+ Task { @MainActor in
145
+ do {
146
+ let request = try JSONDecoder().decode(Request.self, from: Data(CommandLine.arguments[1].utf8))
147
+ let result = try await observe(request)
148
+ let output = try JSONSerialization.data(withJSONObject: ["ok": true, "result": result], options: [.sortedKeys])
149
+ FileHandle.standardOutput.write(output)
150
+ } catch {
151
+ let failure = error as? BoundaryFailure
152
+ let output: [String: Any] = ["ok": false, "code": failure?.code ?? "capture-failed", "message": failure?.message ?? error.localizedDescription]
153
+ if let data = try? JSONSerialization.data(withJSONObject: output, options: [.sortedKeys]) { FileHandle.standardOutput.write(data) }
154
+ }
155
+ exit(0)
156
+ }
157
+ RunLoop.main.run()
@@ -1,4 +1,5 @@
1
- import { AnalysisOutputError } from "../domain/errors.js";
1
+ import { AnalysisCapabilityUnavailableError, AnalysisOutputError, } from "../domain/errors.js";
2
+ import { parseDocuments } from "../domain/hopperValues.js";
2
3
  import { err, ok } from "../domain/result.js";
3
4
  const parameters = (document, address) => ({
4
5
  ...(document === undefined ? {} : { document }),
@@ -77,8 +78,22 @@ const resolveDocument = async (analysis, document, signal) => {
77
78
  if (document !== undefined)
78
79
  return ok(document);
79
80
  const current = await analysis.execute("current_document", {}, executionOptions(signal));
80
- if (!current.ok)
81
- return current;
81
+ if (!current.ok) {
82
+ if (!(current.error instanceof AnalysisCapabilityUnavailableError))
83
+ return current;
84
+ const listed = await analysis.execute("list_documents", {}, executionOptions(signal));
85
+ if (!listed.ok)
86
+ return listed;
87
+ const parsed = parseDocuments(listed.value.result);
88
+ if (!parsed.ok)
89
+ return err(new AnalysisOutputError("list_documents", "expected one document identity when resolving a headless provider", { cause: parsed.error }));
90
+ if (parsed.value.length !== 1)
91
+ return err(new AnalysisOutputError("list_documents", `expected exactly one document identity for a provider without current-document selection, received ${parsed.value.length}`));
92
+ const [documentName] = parsed.value;
93
+ if (documentName === undefined)
94
+ return err(new AnalysisOutputError("list_documents", "provider returned no document identity"));
95
+ return ok(documentName);
96
+ }
82
97
  return typeof current.value.result === "string"
83
98
  ? ok(current.value.result)
84
99
  : err(new AnalysisOutputError("current_document", "expected a document identity string"));
@@ -93,8 +108,7 @@ const facet = (result, operation) => result?.ok === true
93
108
  const isMissingCurrentProcedure = (error) => /(?:no procedure exists|not in a procedure)/iu.test(error.message);
94
109
  const isRequestLevelFailure = (error) => error._tag === "AnalysisCancelledError" ||
95
110
  error._tag === "AnalysisTimeoutError" ||
96
- error._tag === "NoBinaryOpenError" ||
97
- error._tag === "PermissionRequiredError";
111
+ error._tag === "NoBinaryOpenError";
98
112
  const containingProcedureName = (value) => {
99
113
  if (typeof value !== "object" || value === null || Array.isArray(value))
100
114
  return null;
@@ -1,6 +1,6 @@
1
1
  import { EvidenceIntegrityError, NoBinaryOpenError, } from "../domain/errors.js";
2
2
  import { err, ok } from "../domain/result.js";
3
- import { analysisQueryId, createAnalysisSnapshotEntry, snapshotBinding, snapshotMatchesProfile, snapshotMatchesTarget, snapshotTarget, } from "../domain/analysisSnapshot.js";
3
+ import { analysisQueryId, createAnalysisSnapshotEntry, snapshotBinding, snapshotMatchesProfile, snapshotMatchesTarget, snapshotTarget, parseAnalysisSnapshot, } from "../domain/analysisSnapshot.js";
4
4
  import { GENERATED_MCP_TOOL_CATALOG } from "../generatedMcpToolCatalog.js";
5
5
  const STATEFUL_OPERATIONS = new Set([
6
6
  "health",
@@ -75,21 +75,40 @@ export class AnalysisSnapshotCache {
75
75
  export(target, profile, evidenceBundle) {
76
76
  if (target === undefined || profile === undefined)
77
77
  return err(new NoBinaryOpenError());
78
- return ok({
79
- target: snapshotTarget(target),
80
- binding: snapshotBinding(profile),
81
- entries: this.entries(),
82
- evidence_bundle: structuredClone(evidenceBundle),
83
- });
78
+ try {
79
+ const snapshotTargetIdentity = snapshotTarget(target);
80
+ const binding = snapshotBinding(profile);
81
+ const retainedEvidence = structuredClone(evidenceBundle);
82
+ return ok(parseAnalysisSnapshot({
83
+ target: snapshotTargetIdentity,
84
+ binding,
85
+ entries: this.entries(),
86
+ evidence_bundle: retainedEvidence,
87
+ }));
88
+ }
89
+ catch (cause) {
90
+ return err(new EvidenceIntegrityError("Analysis snapshot validation failed", {
91
+ cause,
92
+ }));
93
+ }
84
94
  }
85
95
  /** Validate target identity, merge evidence atomically, then stage entries. */
86
96
  import(snapshot, active, mergeEvidence) {
97
+ let validated;
98
+ try {
99
+ validated = parseAnalysisSnapshot(snapshot);
100
+ }
101
+ catch (cause) {
102
+ return err(new EvidenceIntegrityError("Analysis snapshot validation failed", {
103
+ cause,
104
+ }));
105
+ }
87
106
  if (active !== undefined &&
88
- (!snapshotMatchesTarget(snapshot.target, active.target) ||
89
- !snapshotMatchesProfile(snapshot.binding, active.profile)))
107
+ (!snapshotMatchesTarget(validated.target, active.target) ||
108
+ !snapshotMatchesProfile(validated.binding, active.profile)))
90
109
  return err(new EvidenceIntegrityError("Analysis snapshot profile_mismatch: target, provider, or analysis profile does not match the active binary"));
91
- const importedEvidence = mergeEvidence(snapshot.evidence_bundle);
92
- return importedEvidence.ok ? ok(this.stage(snapshot)) : importedEvidence;
110
+ const importedEvidence = mergeEvidence(validated.evidence_bundle);
111
+ return importedEvidence.ok ? ok(this.stage(validated)) : importedEvidence;
93
112
  }
94
113
  /** Return canonical entries for persistence. */
95
114
  entries() {