rea-agents 6.2.0 → 6.3.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 (297) hide show
  1. package/README.md +18 -20
  2. package/bridge/hopper_bridge.py +2 -0
  3. package/dist/android/JadxProvider.js +8 -2
  4. package/dist/android/JadxSession.js +51 -9
  5. package/dist/application/BinaryTargetResolver.js +63 -17
  6. package/dist/application/BrowserScenarioEvidence.js +2 -2
  7. package/dist/application/ClientConfigurationDocument.js +28 -0
  8. package/dist/application/ClientRegistrationStatus.js +19 -6
  9. package/dist/application/DirectAnalysis.js +12 -6
  10. package/dist/application/DirectAnalysisCleanup.js +0 -1
  11. package/dist/application/DirectAnalysisStatus.js +2 -5
  12. package/dist/application/Doctor.js +25 -34
  13. package/dist/application/DoctorDiagnostics.js +1 -1
  14. package/dist/application/EvidenceBundleFiles.js +1 -1
  15. package/dist/application/InvestigationProviders.js +4 -4
  16. package/dist/application/JsonFiles.js +15 -15
  17. package/dist/application/LinuxHopper.js +2 -1
  18. package/dist/application/ReconstructionObligationCandidates.js +9 -2
  19. package/dist/application/ReconstructionObligationLedgerProjection.js +3 -1
  20. package/dist/application/RegularFileRead.js +17 -0
  21. package/dist/application/Setup.js +18 -7
  22. package/dist/application/SetupClientConfiguration.js +18 -7
  23. package/dist/application/SetupHost.js +6 -4
  24. package/dist/application/SetupPlan.js +19 -15
  25. package/dist/application/SetupSkill.js +57 -8
  26. package/dist/application/SupportedClients.js +43 -0
  27. package/dist/application/Uninstall.js +18 -2
  28. package/dist/application/UpdateMaintenance.js +6 -2
  29. package/dist/application/Utf8JsonInput.js +64 -0
  30. package/dist/application/WebScriptExportService.js +13 -6
  31. package/dist/application/android/AndroidAnalysisService.js +1 -1
  32. package/dist/application/binary/AnalysisSnapshotCache.js +5 -4
  33. package/dist/application/binary/BinarySession.js +16 -0
  34. package/dist/application/binary/BinarySessionOpen.js +9 -1
  35. package/dist/application/javascript/ElectronActiveEvidence.js +2 -2
  36. package/dist/application/javascript/ElectronBoundaryAnalysis.js +2 -2
  37. package/dist/application/javascript/ElectronBoundaryGraphNative.js +5 -1
  38. package/dist/application/javascript/JavaScriptApplicationEvidence.js +1 -0
  39. package/dist/application/javascript/JavaScriptApplicationEvidenceGraph.js +107 -46
  40. package/dist/application/javascript/JavaScriptApplicationService.js +1 -0
  41. package/dist/application/javascript/JavaScriptApplicationWorkflowService.js +59 -45
  42. package/dist/application/javascript/JavaScriptArtifactAnalysis.js +0 -6
  43. package/dist/application/javascript/JavaScriptArtifactGraphBuilder.js +8 -18
  44. package/dist/application/javascript/JavaScriptArtifactGraphFindings.js +34 -26
  45. package/dist/application/javascript/JavaScriptArtifactPathResolution.js +44 -12
  46. package/dist/application/javascript/JavaScriptArtifactReconstruction.js +6 -3
  47. package/dist/application/javascript/JavaScriptArtifactReconstructionInput.js +1 -0
  48. package/dist/application/javascript/JavaScriptJsonModules.js +2 -2
  49. package/dist/application/javascript/JavaScriptModuleRelationships.js +5 -17
  50. package/dist/application/javascript/JavaScriptRuntimeReconciliationService.js +11 -27
  51. package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +2 -2
  52. package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +8 -6
  53. package/dist/application/javascript/JavaScriptSemanticGraphChildProcessProjection.js +1 -1
  54. package/dist/application/javascript/JavaScriptSemanticGraphConstruction.js +7 -5
  55. package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +1 -1
  56. package/dist/application/javascript/JavaScriptSemanticGraphEvidence.js +1 -1
  57. package/dist/application/javascript/JavaScriptSemanticGraphFingerprintProjection.js +2 -2
  58. package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +2 -2
  59. package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +1 -1
  60. package/dist/application/javascript/JavaScriptSemanticGraphProjection.js +4 -4
  61. package/dist/application/javascript/JavaScriptSemanticGraphResourceProjection.js +1 -1
  62. package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +10 -7
  63. package/dist/application/javascript/JavaScriptSemanticTraceService.js +15 -10
  64. package/dist/application/native/NativeCallRoutes.js +2 -4
  65. package/dist/artifacts/ArtifactProvider.js +14 -16
  66. package/dist/artifacts/ArtifactProviderMetadata.js +1 -4
  67. package/dist/artifacts/AsarArtifactReader.js +81 -17
  68. package/dist/artifacts/DirectoryArtifactReader.js +2 -2
  69. package/dist/artifacts/NativeDmgArtifactReader.js +152 -67
  70. package/dist/artifacts/NativeDmgOwnership.js +109 -0
  71. package/dist/artifacts/apple/KeyedArchiveReader.js +54 -46
  72. package/dist/artifacts/apple/MachoLoadCommandReader.js +36 -6
  73. package/dist/artifacts/extraction/ArtifactExtraction.js +29 -11
  74. package/dist/artifacts/inventory/ArtifactGraphConstruction.js +7 -8
  75. package/dist/artifacts/inventory/classify.js +33 -14
  76. package/dist/artifacts/inventory/hashStableRootArtifact.js +37 -0
  77. package/dist/artifacts/inventory/scanCanonical.js +28 -22
  78. package/dist/artifacts/inventory/scanReader.js +7 -11
  79. package/dist/artifacts/javascript/JavaScriptArtifactFiles.js +65 -27
  80. package/dist/browser/CdpBrowserProvider.js +4 -3
  81. package/dist/browser/CdpCaptureStorageFingerprints.js +3 -3
  82. package/dist/browser/CdpElectronInspection.js +2 -2
  83. package/dist/browser/CdpElectronProvider.js +4 -3
  84. package/dist/browser/CdpElectronScripts.js +2 -2
  85. package/dist/browser/CdpWebMcpDiscovery.js +16 -13
  86. package/dist/browser/PlaywrightBrowserScenarioProvider.js +6 -6
  87. package/dist/browser/PlaywrightScenarioBrowser.js +145 -42
  88. package/dist/browser/PlaywrightScenarioSession.js +3 -11
  89. package/dist/browser/WebSourceMapFetcher.js +32 -6
  90. package/dist/browser/assets/ScenarioScriptCapture.js +8 -12
  91. package/dist/cli/coreAnalysisCommands.js +2 -2
  92. package/dist/cli/coreBinaryCommands.js +13 -9
  93. package/dist/cli/electronCommands.js +9 -10
  94. package/dist/cli/javascriptApplicationAnalysis.js +2 -12
  95. package/dist/cli/jsonOutput.js +3 -2
  96. package/dist/cli/streamedJsonOutput.js +83 -4
  97. package/dist/cli/utilityCommands.js +2 -4
  98. package/dist/cli.js +5 -2
  99. package/dist/cliJsonFile.js +179 -0
  100. package/dist/cliJsonInput.js +47 -34
  101. package/dist/cliObservationOptions.js +4 -0
  102. package/dist/composition/auxiliaryAnalysisProviders.js +5 -4
  103. package/dist/composition/browserScenario.js +2 -2
  104. package/dist/composition/directAnalysis.js +2 -3
  105. package/dist/contracts/artifactComparisonExample.js +5 -5
  106. package/dist/contracts/errorSchemas.js +3 -1
  107. package/dist/contracts/functionComparisonExample.js +8 -0
  108. package/dist/contracts/inputSchemaPresentation.js +94 -3
  109. package/dist/contracts/javascript/electronToolContracts.js +2 -1
  110. package/dist/contracts/javascript/javascriptApplicationWorkflowExamples.js +3 -2
  111. package/dist/contracts/javascript/javascriptExportShapeComparisonExample.js +6 -3
  112. package/dist/contracts/javascript/javascriptRuntimeReconciliationExample.js +8 -7
  113. package/dist/contracts/managed/managedToolContracts.js +3 -2
  114. package/dist/contracts/mobileApplicationGraphExamples.js +5 -5
  115. package/dist/contracts/native/nativeToolContracts.js +1 -1
  116. package/dist/contracts/sessionLifecycleInputs.js +4 -3
  117. package/dist/contracts/sessionStatusContract.js +3 -2
  118. package/dist/contracts/sessionToolContracts.js +3 -2
  119. package/dist/contracts/sessionToolSchemas.js +3 -2
  120. package/dist/contracts/toolOutputSchemaGroups.js +2 -2
  121. package/dist/contracts/toolOutputSchemaPrimitives.js +2 -5
  122. package/dist/domain/analysisErrorBase.js +5 -0
  123. package/dist/domain/analysisErrorPresentation.js +4 -2
  124. package/dist/domain/analysisSnapshot.js +3 -1
  125. package/dist/domain/analysisView/analysisView.js +1 -3
  126. package/dist/domain/android/androidPartialObservation.js +36 -0
  127. package/dist/domain/apple/dylibResolution.js +1 -1
  128. package/dist/domain/artifactComparison.js +4 -4
  129. package/dist/domain/artifactGraph.js +1 -1
  130. package/dist/domain/artifactIdentity.js +8 -8
  131. package/dist/domain/artifactInspection.js +8 -8
  132. package/dist/domain/artifactInventoryEvidence.js +5 -5
  133. package/dist/domain/browserCompleteness.js +3 -2
  134. package/dist/domain/browserScenarioCaptureValues.js +2 -2
  135. package/dist/domain/browserScenarioNormalization.js +3 -3
  136. package/dist/domain/browserScenarioValues.js +3 -2
  137. package/dist/domain/callPath.js +8 -10
  138. package/dist/domain/canonicalDigest.js +7 -1
  139. package/dist/domain/canonicalOrdering.js +1 -13
  140. package/dist/domain/changedBehavior.js +2 -3
  141. package/dist/domain/comparisonSemantics.js +0 -5
  142. package/dist/domain/digests.js +0 -3
  143. package/dist/domain/evidence.js +10 -5
  144. package/dist/domain/evidenceBundle.js +51 -33
  145. package/dist/domain/firmware/firmwareAnalysis.js +4 -3
  146. package/dist/domain/functionComparison.js +2 -1
  147. package/dist/domain/functionComparisonNormalization.js +4 -3
  148. package/dist/domain/functionComparisonResults.js +2 -2
  149. package/dist/domain/functionDossierEvidence.js +2 -1
  150. package/dist/domain/hopperValues.js +11 -15
  151. package/dist/domain/javascript/electronActiveObservation.js +4 -3
  152. package/dist/domain/javascript/electronStaticAnalysisBrowser.js +2 -2
  153. package/dist/domain/javascript/electronStaticAnalysisIpc.js +9 -1
  154. package/dist/domain/javascript/electronStaticAnalysisNative.js +5 -3
  155. package/dist/domain/javascript/electronStaticAnalysisValues.js +8 -4
  156. package/dist/domain/javascript/javascriptApplicationAnalysis.js +3 -1
  157. package/dist/domain/javascript/javascriptApplicationChangeGraph.js +12 -8
  158. package/dist/domain/javascript/javascriptApplicationEvidenceSchemas.js +4 -0
  159. package/dist/domain/javascript/javascriptApplicationGraph.js +15 -13
  160. package/dist/domain/javascript/javascriptApplicationVersionComparison.js +4 -4
  161. package/dist/domain/javascript/javascriptApplicationVersionComparisonSchemas.js +37 -22
  162. package/dist/domain/javascript/javascriptApplicationVersionItems.js +45 -34
  163. package/dist/domain/javascript/javascriptApplicationVersionKeys.js +7 -7
  164. package/dist/domain/javascript/javascriptAstFingerprint.js +2 -2
  165. package/dist/domain/javascript/javascriptAstValues.js +22 -0
  166. package/dist/domain/javascript/javascriptExportShapeComparison.js +3 -2
  167. package/dist/domain/javascript/javascriptExportShapeComparisonSchemas.js +31 -23
  168. package/dist/domain/javascript/javascriptExportShapeSelection.js +2 -2
  169. package/dist/domain/javascript/javascriptExportShapeVariants.js +3 -2
  170. package/dist/domain/javascript/javascriptFeatureSeed.js +5 -3
  171. package/dist/domain/javascript/javascriptFeatureTrace.js +7 -6
  172. package/dist/domain/javascript/javascriptFeatureTraceSchemas.js +17 -9
  173. package/dist/domain/javascript/javascriptFeatureTraversal.js +4 -4
  174. package/dist/domain/javascript/javascriptNativeHandoff.js +6 -6
  175. package/dist/domain/javascript/javascriptRuntimeObservation.js +8 -5
  176. package/dist/domain/javascript/javascriptRuntimeReconciliation.js +12 -6
  177. package/dist/domain/javascript/javascriptRuntimeReconciliationActive.js +9 -8
  178. package/dist/domain/javascript/javascriptRuntimeReconciliationCaptureParsing.js +212 -0
  179. package/dist/domain/javascript/javascriptRuntimeReconciliationGraph.js +5 -4
  180. package/dist/domain/javascript/javascriptRuntimeReconciliationInputValidation.js +28 -0
  181. package/dist/domain/javascript/javascriptRuntimeReconciliationMatching.js +5 -5
  182. package/dist/domain/javascript/javascriptRuntimeReconciliationParsing.js +12 -223
  183. package/dist/domain/javascript/javascriptRuntimeReconciliationResult.js +2 -2
  184. package/dist/domain/javascript/javascriptRuntimeReconciliationRuntime.js +15 -4
  185. package/dist/domain/javascript/javascriptRuntimeReconciliationSchemas.js +2 -2
  186. package/dist/domain/javascript/javascriptRuntimeStaticCandidates.js +7 -6
  187. package/dist/domain/javascript/javascriptSemanticAnalysis.js +200 -8
  188. package/dist/domain/javascript/javascriptSemanticCallResolution.js +9 -7
  189. package/dist/domain/javascript/javascriptSemanticChildProcesses.js +2 -2
  190. package/dist/domain/javascript/javascriptSemanticCoverage.js +20 -0
  191. package/dist/domain/javascript/javascriptSemanticDataEffectHelpers.js +7 -9
  192. package/dist/domain/javascript/javascriptSemanticDataEffects.js +4 -11
  193. package/dist/domain/javascript/javascriptSemanticFingerprints.js +2 -2
  194. package/dist/domain/javascript/javascriptSemanticGraph.js +142 -35
  195. package/dist/domain/javascript/javascriptSemanticGraphSchemas.js +19 -1
  196. package/dist/domain/javascript/javascriptSemanticIr.js +0 -4
  197. package/dist/domain/javascript/javascriptSemanticIterationSources.js +106 -0
  198. package/dist/domain/javascript/javascriptSemanticMemberMutations.js +497 -113
  199. package/dist/domain/javascript/javascriptSemanticMutationInitializers.js +190 -0
  200. package/dist/domain/javascript/javascriptSemanticMutationValues.js +41 -27
  201. package/dist/domain/javascript/javascriptSemanticObjects.js +2 -6
  202. package/dist/domain/javascript/javascriptSemanticPrimitives.js +7 -2
  203. package/dist/domain/javascript/javascriptSemanticProjection.js +20 -14
  204. package/dist/domain/javascript/javascriptSemanticPromises.js +15 -21
  205. package/dist/domain/javascript/javascriptSemanticPropertyPaths.js +23 -0
  206. package/dist/domain/javascript/javascriptSemanticProvenance.js +3 -3
  207. package/dist/domain/javascript/javascriptSemanticQuery.js +8 -2
  208. package/dist/domain/javascript/javascriptSemanticQueryIdentity.js +3 -2
  209. package/dist/domain/javascript/javascriptSemanticQuerySchemas.js +8 -9
  210. package/dist/domain/javascript/javascriptSemanticRequireOrigin.js +16 -10
  211. package/dist/domain/javascript/javascriptSemanticReturns.js +23 -27
  212. package/dist/domain/javascript/javascriptSemanticTraversal.js +6 -1
  213. package/dist/domain/javascript/javascriptSemanticValues.js +135 -24
  214. package/dist/domain/javascript/javascriptSourceMapPaths.js +11 -1
  215. package/dist/domain/javascript/javascriptSourceParser.js +34 -9
  216. package/dist/domain/javascript/javascriptStaticAnalysisBundler.js +5 -6
  217. package/dist/domain/javascript/javascriptStaticAnalysisHelpers.js +26 -15
  218. package/dist/domain/javascript/sourceToBundleComparison.js +7 -5
  219. package/dist/domain/javascript/sourceToBundleSignals.js +7 -7
  220. package/dist/domain/jsonSerialization.js +109 -55
  221. package/dist/domain/jsonShape.js +46 -19
  222. package/dist/domain/localPath.js +10 -4
  223. package/dist/domain/managed/managedApplicationGraph.js +10 -6
  224. package/dist/domain/managed/managedApplicationGraphNodes.js +82 -57
  225. package/dist/domain/managed/managedMemberComparisonMatch.js +6 -7
  226. package/dist/domain/native/nativeCallObservation.js +2 -4
  227. package/dist/domain/native/nativeValueFlow.js +5 -11
  228. package/dist/domain/native/objcSwiftMetadata.js +15 -17
  229. package/dist/domain/process/processCapture.js +11 -10
  230. package/dist/domain/process/processCaptureCoverage.js +8 -5
  231. package/dist/domain/process/processCaptureExample.js +43 -0
  232. package/dist/domain/process/processCaptureValidation.js +4 -3
  233. package/dist/domain/process/processComparison.js +0 -23
  234. package/dist/domain/process/processScenario.js +3 -3
  235. package/dist/domain/process/processTraceEvaluation.js +4 -4
  236. package/dist/domain/process/processTraceSpecification.js +1 -3
  237. package/dist/domain/providerCleanupError.js +6 -2
  238. package/dist/domain/reconstructionCoverage.js +2 -1
  239. package/dist/domain/reconstructionUnknowns.js +4 -3
  240. package/dist/domain/reconstructionVerification.js +3 -2
  241. package/dist/domain/referenceSourceGraph.js +7 -7
  242. package/dist/domain/referenceSourceImportParsing.js +34 -45
  243. package/dist/domain/residualUnknown.js +3 -2
  244. package/dist/domain/staticRuntimeCorrelation.js +2 -1
  245. package/dist/domain/swiftSymbolClassification.js +6 -1
  246. package/dist/domain/symbolAnalysis.js +17 -2
  247. package/dist/domain/unicodeCodePointOrder.js +6 -0
  248. package/dist/domain/webBundleAnalyzerInspection.js +9 -1
  249. package/dist/domain/webCaptureDiff.js +71 -29
  250. package/dist/domain/webCaptureDiffSchemas.js +2 -8
  251. package/dist/domain/webInventory.js +3 -2
  252. package/dist/domain/webMcpDiscovery.js +4 -3
  253. package/dist/domain/webScriptExport.js +1 -1
  254. package/dist/dotnet/ManagedMemberInstructionDecoder.js +1 -2
  255. package/dist/dotnet/ManagedStaticProvider.js +10 -7
  256. package/dist/dotnet/ManagedStaticProviderMetadata.js +1 -4
  257. package/dist/filesystem/RegularFile.js +41 -0
  258. package/dist/generatedPackageMetadata.js +1 -1
  259. package/dist/ghidra/GhidraClient.js +14 -4
  260. package/dist/ghidra/GhidraInstallation.js +111 -10
  261. package/dist/ghidra/GhidraLauncher.js +43 -19
  262. package/dist/hopper/HopperCleanup.js +1 -1
  263. package/dist/ida/IdaOperationRunner.js +2 -0
  264. package/dist/ida/IdaSessionClient.js +4 -2
  265. package/dist/inspector/JavaScriptRuntimeScope.js +9 -5
  266. package/dist/inspector/V8InspectorCaptureProjection.js +46 -13
  267. package/dist/inspector/V8InspectorProvider.js +60 -8
  268. package/dist/main/shutdown.js +76 -32
  269. package/dist/main/transport.js +1 -1
  270. package/dist/native/AppleObjcDispatchFacets.js +3 -3
  271. package/dist/native/AppleObjcProperties.js +17 -7
  272. package/dist/native/LldbCallTracer.js +241 -75
  273. package/dist/native/NativeMacOSProvider.js +10 -5
  274. package/dist/native/NativeMacOSProviderMetadata.js +1 -2
  275. package/dist/process/ProcessOwnershipObservation.js +9 -13
  276. package/dist/process/capture/FilesystemSnapshot.js +88 -18
  277. package/dist/process/capture/ProcessCaptureLifecycle.js +13 -27
  278. package/dist/process/capture/ProcessFilesystemEffects.js +19 -4
  279. package/dist/process/capture/ProcessHarness.js +8 -21
  280. package/dist/server/analysisAdmission.js +8 -0
  281. package/dist/server/createServer.js +22 -23
  282. package/dist/server/registerApplicationTools/compareExportShapes.js +2 -1
  283. package/dist/server/registerApplicationTools/helpers.js +3 -2
  284. package/dist/server/registerArtifactTools.js +2 -2
  285. package/dist/server/registerCloseLifecycleTool.js +6 -4
  286. package/dist/server/registerEnhancedTools.js +78 -73
  287. package/dist/server/registerEvidenceTools.js +54 -46
  288. package/dist/server/registerManagedTools.js +7 -4
  289. package/dist/server/registerOfficialTools.js +31 -25
  290. package/dist/server/registerSessionTools.js +9 -3
  291. package/native/windows/build/manifest.json +1 -1
  292. package/package.json +6 -3
  293. package/skills/reverse-engineer-anything/SKILL.md +5 -5
  294. package/skills/reverse-engineer-anything/references/native-and-artifacts.md +9 -0
  295. package/dist/artifacts/inventory/policy.js +0 -2
  296. package/dist/domain/managed/managedApplicationGraphNodeCoverage.js +0 -6
  297. package/dist/server/registerNativeTools.js +0 -6
@@ -12,9 +12,16 @@ import { ghidraJavaLaunch } from "./GhidraJavaLaunch.js";
12
12
  import { snapshotGhidraExtensions, } from "./extensions/GhidraExtensions.js";
13
13
  /** Local launch failure retained as the cause of a provider-neutral error. */
14
14
  export class GhidraLaunchError extends Error {
15
+ #partialLaunch;
15
16
  constructor(message, options) {
16
- super(message, options);
17
+ const { partialLaunch, ...errorOptions } = options ?? {};
18
+ super(message, errorOptions);
17
19
  this.name = "GhidraLaunchError";
20
+ this.#partialLaunch = partialLaunch;
21
+ }
22
+ /** Process ownership retained for the client to retry an incomplete rollback. */
23
+ get partialLaunch() {
24
+ return this.#partialLaunch;
18
25
  }
19
26
  }
20
27
  /** Launch Ghidra without copying scripts into or modifying its installation. */
@@ -89,7 +96,7 @@ export class GhidraHeadlessLauncher {
89
96
  : { signal: options.signal }),
90
97
  })
91
98
  : { ...scriptCommand, environment };
92
- started = await spawnOwnedProviderProcess({
99
+ started = await (this.options.spawnProcess ?? spawnOwnedProviderProcess)({
93
100
  command: command.command,
94
101
  arguments: command.arguments,
95
102
  runId: session.runId,
@@ -102,6 +109,7 @@ export class GhidraHeadlessLauncher {
102
109
  hostEnvironment: {},
103
110
  ...(options.signal === undefined ? {} : { signal: options.signal }),
104
111
  });
112
+ const partialLaunch = ownedGhidraLaunch(started, paths, platform);
105
113
  await writeGhidraRuntimeFile(paths.ownershipPath, `${JSON.stringify({
106
114
  run_id: session.runId,
107
115
  transport: session.transport,
@@ -115,29 +123,45 @@ export class GhidraHeadlessLauncher {
115
123
  created_at: new Date().toISOString(),
116
124
  })}\n`, platform);
117
125
  if (isAborted(options.signal)) {
118
- await cleanupStartedProcess(started, platform);
119
- return err(new AnalysisCancelledError("open_binary"));
126
+ throw new AnalysisCancelledError("open_binary");
120
127
  }
121
- const spawned = started;
122
- return ok({
123
- ...ownedGhidraProcess(spawned, platform),
124
- projectRoot: paths.projectRoot,
125
- ghidraLogPath: paths.ghidraLogPath,
126
- scriptLogPath: paths.scriptLogPath,
127
- });
128
+ return ok(partialLaunch);
128
129
  }
129
130
  catch (cause) {
130
- if (started !== undefined)
131
- await cleanupStartedProcess(started, platform).catch((cause) => {
132
- // best-effort cleanup: started-process cleanup must not mask the launch failure.
133
- void cause;
134
- });
135
- return isAborted(options.signal)
136
- ? err(new AnalysisCancelledError("open_binary"))
137
- : err(new GhidraLaunchError("Ghidra headless launch failed", { cause }));
131
+ const primary = isAborted(options.signal)
132
+ ? new AnalysisCancelledError("open_binary", { cause })
133
+ : new GhidraLaunchError("Ghidra headless launch failed", { cause });
134
+ if (started === undefined)
135
+ return err(primary);
136
+ let cleanupFailure;
137
+ try {
138
+ const cleanup = await cleanupStartedProcess(started, platform);
139
+ if (!cleanup.cleaned)
140
+ cleanupFailure = new Error(`Ghidra process cleanup was incomplete: ${cleanup.reason}`);
141
+ }
142
+ catch (failure) {
143
+ cleanupFailure = failure;
144
+ }
145
+ if (cleanupFailure !== undefined) {
146
+ const partialLaunch = ownedGhidraLaunch(started, paths, platform);
147
+ const primaryMessage = isAborted(options.signal)
148
+ ? primary.message
149
+ : `Ghidra headless launch failed: ${cause instanceof Error ? cause.message : String(cause)}`;
150
+ return err(new GhidraLaunchError(`${primaryMessage}; process cleanup remains incomplete`, {
151
+ cause: new AggregateError([primary, cleanupFailure], "Ghidra launch rollback did not release its process", { cause: primary }),
152
+ partialLaunch,
153
+ }));
154
+ }
155
+ return err(primary);
138
156
  }
139
157
  }
140
158
  }
159
+ const ownedGhidraLaunch = (spawned, paths, platform) => ({
160
+ ...ownedGhidraProcess(spawned, platform),
161
+ projectRoot: paths.projectRoot,
162
+ ghidraLogPath: paths.ghidraLogPath,
163
+ scriptLogPath: paths.scriptLogPath,
164
+ });
141
165
  const ownedGhidraProcess = (spawned, platform) => ({
142
166
  process: spawned.process,
143
167
  ownsProcessLifetime: true,
@@ -160,7 +160,7 @@ const stopProcess = async (input, state) => {
160
160
  }
161
161
  input.logger.info(diagnostic, "Owned Hopper launcher shutdown completed");
162
162
  if (stopped.status !== "incomplete") {
163
- if (input.resources.launch?.shutdownMode === "process-cleanup" &&
163
+ if (input.resources.launch?.providerLifetime === "launcher-process" &&
164
164
  stopped.status !== "not-owned")
165
165
  input.resources.shutdownConfirmed = true;
166
166
  state.processStopped = true;
@@ -288,6 +288,8 @@ export class IdaOperationRunner {
288
288
  referenced_strings: [],
289
289
  referenced_names: [],
290
290
  basic_blocks: [],
291
+ native_api: null,
292
+ native_value_flow: null,
291
293
  limitations: [
292
294
  ...IDA_LIMITATIONS,
293
295
  ...this.limitations,
@@ -101,8 +101,10 @@ export class IdaSessionClient {
101
101
  }
102
102
  const document = parameters.document;
103
103
  if (document !== undefined &&
104
- document !== this.target.path &&
105
- document !== this.target.sourcePath)
104
+ (typeof document !== "string" ||
105
+ (!sameIdaHostPath(document, this.target.path) &&
106
+ (this.target.sourcePath === undefined ||
107
+ !sameIdaHostPath(document, this.target.sourcePath)))))
106
108
  return err(new AnalysisInputError(operation, undefined, [
107
109
  {
108
110
  path: ["document"],
@@ -21,11 +21,6 @@ export const inspectorExclusionKey = (reason) => {
21
21
  /** Resolve a protocol location exposed by the explicitly selected Inspector endpoint. */
22
22
  export const authorizeRuntimeLocation = async (value, signal) => {
23
23
  throwIfRuntimeObservationCancelled(signal);
24
- if (value.startsWith("node:") && value.length > 0)
25
- return {
26
- allowed: true,
27
- location: { kind: "builtin", specifier: value },
28
- };
29
24
  if (value.startsWith("file:")) {
30
25
  const filePath = await authorizedElectronFile(value);
31
26
  throwIfRuntimeObservationCancelled(signal);
@@ -33,6 +28,15 @@ export const authorizeRuntimeLocation = async (value, signal) => {
33
28
  ? { allowed: false, reason: "not_approved" }
34
29
  : { allowed: true, location: { kind: "file", file_path: filePath } };
35
30
  }
31
+ return projectReportedRuntimeUrl(value);
32
+ };
33
+ /** Project non-file Inspector URLs without filesystem access. */
34
+ export const projectReportedRuntimeUrl = (value) => {
35
+ if (value.startsWith("node:") && value.length > 0)
36
+ return {
37
+ allowed: true,
38
+ location: { kind: "builtin", specifier: value },
39
+ };
36
40
  let url;
37
41
  try {
38
42
  url = new URL(value);
@@ -1,5 +1,5 @@
1
1
  import { createHash } from "node:crypto";
2
- import { authorizeRuntimeLocation, inspectorExclusionKey, throwIfRuntimeObservationCancelled, } from "./JavaScriptRuntimeScope.js";
2
+ import { authorizeRuntimeLocation, inspectorExclusionKey, projectReportedRuntimeUrl, throwIfRuntimeObservationCancelled, } from "./JavaScriptRuntimeScope.js";
3
3
  /** Empty durable-location exclusion counters. */
4
4
  export const createInspectorExclusionCounts = () => ({
5
5
  unsupported_location: 0,
@@ -15,26 +15,29 @@ export const describeInspectorTargetLimitations = () => [
15
15
  ];
16
16
  const LOCATION_AUTHORIZATION_WORKERS = 8;
17
17
  /** Canonically authorize, deduplicate, and sort one bounded raw capture. */
18
- export const finalizeInspectorCapture = async ({ input, runtime, target, state, authorizeLocation = authorizeRuntimeLocation, signal, }) => {
19
- throwIfRuntimeObservationCancelled(signal);
18
+ export const finalizeInspectorCapture = async ({ input, runtime, target, state, authorizeLocation = authorizeRuntimeLocation, locationMode = "verify", signal, }) => {
19
+ if (locationMode === "verify")
20
+ throwIfRuntimeObservationCancelled(signal);
20
21
  const exclusions = createInspectorExclusionCounts();
21
22
  const scripts = new Map();
22
23
  const draftsByUrl = new Map();
23
- for (const draft of state.scripts) {
24
- const drafts = draftsByUrl.get(draft.rawUrl) ?? [];
25
- drafts.push(draft);
26
- draftsByUrl.set(draft.rawUrl, drafts);
27
- }
24
+ if (locationMode === "verify")
25
+ for (const draft of state.scripts) {
26
+ const drafts = draftsByUrl.get(draft.rawUrl) ?? [];
27
+ drafts.push(draft);
28
+ draftsByUrl.set(draft.rawUrl, drafts);
29
+ }
28
30
  const groups = [...draftsByUrl];
29
31
  const authorizedGroups = new Array(groups.length);
30
32
  let nextGroup = 0;
31
33
  let stopScheduling = false;
34
+ let unresolvedScripts = 0;
32
35
  const worker = async () => {
33
36
  try {
34
37
  for (;;) {
35
- throwIfRuntimeObservationCancelled(signal);
36
38
  if (stopScheduling)
37
39
  return;
40
+ throwIfRuntimeObservationCancelled(signal);
38
41
  const index = nextGroup;
39
42
  nextGroup += 1;
40
43
  const group = groups[index];
@@ -53,12 +56,18 @@ export const finalizeInspectorCapture = async ({ input, runtime, target, state,
53
56
  throw cause;
54
57
  }
55
58
  };
56
- const workerResults = await Promise.allSettled(Array.from({ length: Math.min(LOCATION_AUTHORIZATION_WORKERS, groups.length) }, worker));
59
+ const workerResults = locationMode === "verify"
60
+ ? await Promise.allSettled(Array.from({ length: Math.min(LOCATION_AUTHORIZATION_WORKERS, groups.length) }, worker))
61
+ : [];
57
62
  const failedWorker = workerResults.find((result) => result.status === "rejected");
58
- throwIfRuntimeObservationCancelled(signal);
63
+ if (locationMode === "verify")
64
+ throwIfRuntimeObservationCancelled(signal);
59
65
  if (failedWorker?.status === "rejected")
60
66
  throw failedWorker.reason;
61
- for (const { drafts, decision } of authorizedGroups) {
67
+ for (const group of authorizedGroups) {
68
+ if (group === undefined)
69
+ continue;
70
+ const { drafts, decision } = group;
62
71
  for (const draft of drafts) {
63
72
  if (!decision.allowed) {
64
73
  exclusions[inspectorExclusionKey(decision.reason)] += 1;
@@ -68,6 +77,14 @@ export const finalizeInspectorCapture = async ({ input, runtime, target, state,
68
77
  scripts.set(script.script_key, script);
69
78
  }
70
79
  }
80
+ if (locationMode === "reported")
81
+ for (const draft of state.scripts) {
82
+ const location = partialScriptLocation(draft.rawUrl);
83
+ if (location.kind === "unresolved")
84
+ unresolvedScripts += 1;
85
+ const script = scriptFromDraft(draft, location);
86
+ scripts.set(script.script_key, script);
87
+ }
71
88
  const items = [...scripts.values()].sort((left, right) => left.script_key < right.script_key
72
89
  ? -1
73
90
  : left.script_key > right.script_key
@@ -85,7 +102,8 @@ export const finalizeInspectorCapture = async ({ input, runtime, target, state,
85
102
  : left.context_key > right.context_key
86
103
  ? 1
87
104
  : 0);
88
- throwIfRuntimeObservationCancelled(signal);
105
+ if (locationMode === "verify")
106
+ throwIfRuntimeObservationCancelled(signal);
89
107
  return {
90
108
  runtime,
91
109
  target: {
@@ -132,6 +150,11 @@ export const finalizeInspectorCapture = async ({ input, runtime, target, state,
132
150
  "The discovery-reported file location cannot be verified; loaded script locations are resolved independently from Debugger.scriptParsed.",
133
151
  ]
134
152
  : []),
153
+ ...(unresolvedScripts === 0
154
+ ? []
155
+ : [
156
+ `${String(unresolvedScripts)} observed script location${unresolvedScripts === 1 ? " remains" : "s remain"} unverified; raw URLs and script metadata are retained.`,
157
+ ]),
135
158
  "Scripts collected before attachment may have been garbage-collected and therefore omitted.",
136
159
  "A bounded observation window cannot establish that an unobserved script or behavior never occurs.",
137
160
  "The declared Node/Electron process role is not authenticated by the Inspector protocol.",
@@ -157,3 +180,13 @@ const scriptFromDraft = (draft, location) => {
157
180
  status: "observed-loaded",
158
181
  };
159
182
  };
183
+ const partialScriptLocation = (reportedUrl) => {
184
+ const projection = projectReportedRuntimeUrl(reportedUrl);
185
+ if (projection.allowed)
186
+ return projection.location;
187
+ return {
188
+ kind: "unresolved",
189
+ reported_url: reportedUrl,
190
+ reason: "location-authorization-not-attempted",
191
+ };
192
+ };
@@ -54,19 +54,30 @@ export class V8InspectorProvider {
54
54
  }
55
55
  async observe(input, options = {}) {
56
56
  let connection;
57
+ let discovery;
58
+ let target;
59
+ let state;
57
60
  let primaryFailure;
58
61
  let failed = false;
59
62
  let cleanupFailure;
60
63
  let cleanupFailed = false;
64
+ let connectionClosePromise;
61
65
  let outcome;
66
+ const closeConnection = () => {
67
+ if (connection === undefined)
68
+ return Promise.resolve();
69
+ connectionClosePromise ??= closeInspectorConnection(connection, options.signal);
70
+ return connectionClosePromise;
71
+ };
62
72
  try {
63
- const discovery = await discoverV8Inspector(input.inspector_endpoint, "observe_javascript_runtime", options.signal);
64
- const target = await authorizedTarget(discovery.targets, input, discovery.runtime.product);
73
+ discovery = await discoverV8Inspector(input.inspector_endpoint, "observe_javascript_runtime", options.signal);
74
+ target = await authorizedTarget(discovery.targets, input, discovery.runtime.product);
65
75
  if (input.runtime_kind !== undefined)
66
76
  assertRuntimeKind(target, input.runtime_kind);
67
77
  connection = await CdpConnection.connect(target.webSocketUrl, "observe_javascript_runtime", options.signal, { maxPayloadBytes: INSPECTOR_MAX_PAYLOAD_BYTES });
68
- const state = emptyCaptureState();
69
- const removeListener = connection.onEvent((event) => ingestEvent(event, state));
78
+ const captureState = emptyCaptureState();
79
+ state = captureState;
80
+ const removeListener = connection.onEvent((event) => ingestEvent(event, captureState));
70
81
  try {
71
82
  await connection.send("Runtime.enable", {}, undefined, options.signal);
72
83
  await connection.send("Debugger.enable", {}, undefined, options.signal);
@@ -79,7 +90,7 @@ export class V8InspectorProvider {
79
90
  input,
80
91
  runtime: discovery.runtime,
81
92
  target,
82
- state,
93
+ state: captureState,
83
94
  ...(options.signal === undefined ? {} : { signal: options.signal }),
84
95
  });
85
96
  outcome = ok(javascriptRuntimeObservationSchema.parse(result));
@@ -87,12 +98,53 @@ export class V8InspectorProvider {
87
98
  catch (cause) {
88
99
  failed = true;
89
100
  primaryFailure = cause;
90
- outcome = err(providerError(cause, "observe_javascript_runtime"));
101
+ let error = providerError(cause, "observe_javascript_runtime");
102
+ if (state !== undefined &&
103
+ discovery !== undefined &&
104
+ target !== undefined &&
105
+ (cause instanceof BrowserObservationError ||
106
+ options.signal?.aborted === true)) {
107
+ const reason = options.signal?.aborted === true
108
+ ? "cancelled"
109
+ : cause instanceof BrowserObservationError
110
+ ? cause.reason
111
+ : "protocol_error";
112
+ try {
113
+ await closeConnection();
114
+ }
115
+ catch (cause) {
116
+ cleanupFailed = true;
117
+ cleanupFailure = cause;
118
+ }
119
+ try {
120
+ const partialObservation = await finalizeInspectorCapture({
121
+ input,
122
+ runtime: discovery.runtime,
123
+ target,
124
+ state,
125
+ locationMode: "reported",
126
+ });
127
+ error = new BrowserObservationError("observe_javascript_runtime", reason, {
128
+ cause: error,
129
+ ...(error.userMessage === undefined
130
+ ? {}
131
+ : { detail: error.userMessage }),
132
+ partialObservation,
133
+ });
134
+ }
135
+ catch (projectionFailure) {
136
+ error = new BrowserObservationError("observe_javascript_runtime", reason, {
137
+ cause: new AggregateError([error, projectionFailure], "Inspector failure and partial-observation projection both failed"),
138
+ detail: `${error.message} Partial observations could not be projected.`,
139
+ });
140
+ }
141
+ }
142
+ outcome = err(error);
91
143
  }
92
144
  finally {
93
145
  if (connection !== undefined)
94
146
  try {
95
- await closeInspectorConnection(connection, options.signal);
147
+ await closeConnection();
96
148
  }
97
149
  catch (cause) {
98
150
  cleanupFailed = true;
@@ -212,7 +264,7 @@ const ingestScript = (event, state) => {
212
264
  state.scriptsObserved += 1;
213
265
  const value = recordValue(event.params);
214
266
  const rawUrl = cdpStringValue(value?.url);
215
- if (rawUrl === undefined || rawUrl === "") {
267
+ if (rawUrl === undefined) {
216
268
  state.invalidScripts += 1;
217
269
  retainEvent(state, 0);
218
270
  return;
@@ -3,24 +3,51 @@ import { projectAnalysisError } from "../domain/analysisErrorProjection.js";
3
3
  import { MCP_SHUTDOWN_FAILED } from "./messages.js";
4
4
  export const createShutdown = (input) => {
5
5
  const { handle, session, dependencies, serverLogger } = input;
6
- let shutdownPromise;
6
+ let shutdownAttempt;
7
+ const cleanupOwners = [
8
+ { close: () => handle.close(), closed: false },
9
+ ...(input.closeAndroid === undefined
10
+ ? []
11
+ : [{ close: input.closeAndroid, closed: false }]),
12
+ {
13
+ close: async () => {
14
+ const closed = await session.close({ retainProviderDocuments: true });
15
+ if (!closed.ok)
16
+ throw closed.error;
17
+ },
18
+ closed: false,
19
+ },
20
+ ];
21
+ let shutdownUnregistered = false;
7
22
  let unregisterShutdown = () => undefined;
8
23
  const shutdown = async () => {
9
- shutdownPromise ??= (async () => {
10
- unregisterShutdown();
11
- const results = await Promise.allSettled([
12
- handle.close(),
13
- input.closeAndroid?.(),
14
- session.close({ retainProviderDocuments: true }).then((closed) => {
15
- if (!closed.ok)
16
- throw closed.error;
17
- }),
18
- ]);
24
+ if (shutdownAttempt !== undefined)
25
+ return shutdownAttempt;
26
+ const pending = cleanupOwners.filter(({ closed }) => !closed);
27
+ const attempt = (async () => {
28
+ const results = await Promise.allSettled(pending.map(async (owner) => {
29
+ await owner.close();
30
+ owner.closed = true;
31
+ }));
32
+ const failures = [];
19
33
  for (const result of results)
20
34
  if (result.status === "rejected")
21
- throw result.reason;
35
+ failures.push(result.reason);
36
+ if (failures.length === 1)
37
+ throw failures[0];
38
+ if (failures.length > 1)
39
+ throw new AggregateError(failures, "Multiple MCP cleanup operations failed");
40
+ if (!shutdownUnregistered) {
41
+ unregisterShutdown();
42
+ shutdownUnregistered = true;
43
+ }
22
44
  })();
23
- return shutdownPromise;
45
+ shutdownAttempt = attempt;
46
+ void attempt.catch(() => {
47
+ if (shutdownAttempt === attempt)
48
+ shutdownAttempt = undefined;
49
+ });
50
+ return attempt;
24
51
  };
25
52
  const requestShutdown = () => {
26
53
  shutdown().catch((cause) => {
@@ -35,24 +62,41 @@ export const createShutdown = (input) => {
35
62
  unregisterShutdown = dependencies.registerShutdown(requestShutdown);
36
63
  return { shutdown, request: requestShutdown };
37
64
  };
38
- const describeShutdownFailure = (cause) => {
39
- if (cause instanceof AnalysisError)
40
- return { analysis_error: projectAnalysisError(cause) };
41
- if (cause instanceof Error) {
42
- const code = "code" in cause ? cause.code : undefined;
43
- return {
44
- name: cause.name,
45
- message: cause.message,
46
- ...(typeof code === "string" ||
47
- (typeof code === "number" && Number.isFinite(code))
48
- ? { code }
49
- : {}),
50
- };
65
+ const describeShutdownFailure = (cause) => describeShutdownFailureNode(cause, new WeakSet());
66
+ const describeShutdownFailureNode = (cause, active) => {
67
+ if (typeof cause === "object" && cause !== null) {
68
+ if (active.has(cause))
69
+ return { type: "cyclic_error" };
70
+ active.add(cause);
71
+ }
72
+ try {
73
+ if (cause instanceof AnalysisError)
74
+ return { analysis_error: projectAnalysisError(cause) };
75
+ if (cause instanceof Error) {
76
+ const code = "code" in cause ? cause.code : undefined;
77
+ return {
78
+ name: cause.name,
79
+ message: cause.message,
80
+ ...(typeof code === "string" ||
81
+ (typeof code === "number" && Number.isFinite(code))
82
+ ? { code }
83
+ : {}),
84
+ ...(cause instanceof AggregateError
85
+ ? {
86
+ errors: cause.errors.map((error) => describeShutdownFailureNode(error, active)),
87
+ }
88
+ : {}),
89
+ };
90
+ }
91
+ if (cause === null ||
92
+ typeof cause === "string" ||
93
+ typeof cause === "boolean" ||
94
+ (typeof cause === "number" && Number.isFinite(cause)))
95
+ return { type: cause === null ? "null" : typeof cause, value: cause };
96
+ return { type: typeof cause };
97
+ }
98
+ finally {
99
+ if (typeof cause === "object" && cause !== null)
100
+ active.delete(cause);
51
101
  }
52
- if (cause === null ||
53
- typeof cause === "string" ||
54
- typeof cause === "boolean" ||
55
- (typeof cause === "number" && Number.isFinite(cause)))
56
- return { type: cause === null ? "null" : typeof cause, value: cause };
57
- return { type: typeof cause };
58
102
  };
@@ -29,7 +29,7 @@ export const startMcpTransport = async (dependencies, session, serverContext) =>
29
29
  // The SDK can discard a discovery probe and construct a replacement server.
30
30
  const android = createAndroidAnalysisProvider(serverContext.environment);
31
31
  androidProviders.push(android);
32
- return (dependencies.createServer ?? createServer)(session, session, {
32
+ return (dependencies.createServer ?? createServer)({ kind: "session", session }, {
33
33
  logger: serverContext.logger,
34
34
  environment: serverContext.environment,
35
35
  delivery: serverContext.delivery,
@@ -146,7 +146,7 @@ export const decodeObjcDispatchFacets = (input) => {
146
146
  if (superclass.name === null && superclass.address === null && !root)
147
147
  failures.push(`Superclass of ${name} requires external binding resolution`);
148
148
  const ivarList = read.pointer(ro + 48n);
149
- let ivarCount = 0;
149
+ let ivarCount = meta ? null : 0;
150
150
  if (ivarList !== 0n && !meta) {
151
151
  const stride = read.u32(ivarList), count = read.u32(ivarList + 4n);
152
152
  if (stride !== 32)
@@ -198,8 +198,8 @@ export const decodeObjcDispatchFacets = (input) => {
198
198
  BigInt(Number.MAX_SAFE_INTEGER)
199
199
  ? Number(BigInt(item.implementation_address))
200
200
  : null,
201
- is_required: false,
202
- is_optional: false,
201
+ is_required: null,
202
+ is_optional: null,
203
203
  })),
204
204
  properties: readObjcPropertiesOf(read, read.pointer(ro + 64n), {
205
205
  owner: name,
@@ -5,19 +5,29 @@ import { issue } from "./AppleDispatchDecodeFacts.js";
5
5
  */
6
6
  export const parsePropertyAttributes = (name, attributes) => {
7
7
  const tokens = attributes.length === 0 ? [] : splitAttributes(attributes);
8
- const value = (code) => tokens.find((token) => token.startsWith(code))?.slice(1) ?? null;
8
+ const typeAttributes = tokens.filter((token) => token[0] === "T");
9
+ const typeAttribute = typeAttributes.length === 1 ? typeAttributes[0] : undefined;
10
+ const typeEncoding = typeAttribute !== undefined && typeAttribute.length > 1
11
+ ? typeAttribute.slice(1)
12
+ : null;
13
+ const value = (code) => tokens.find((token) => token[0] === code)?.slice(1) ?? null;
9
14
  return {
10
15
  name,
11
- type_encoding: value("T"),
16
+ type_encoding: typeEncoding,
12
17
  attributes: tokens.map((token) => ({
13
18
  name: token.slice(0, 1),
14
19
  value: token.slice(1),
15
- is_weak: token === "W",
16
- is_atomic: false,
17
- is_copy: token === "C",
18
- is_strong: token === "&",
19
20
  })),
20
- is_readonly: tokens.includes("R"),
21
+ atomicity: tokens.includes("N")
22
+ ? "nonatomic"
23
+ : typeEncoding === null
24
+ ? null
25
+ : "atomic",
26
+ is_readonly: tokens.includes("R")
27
+ ? true
28
+ : typeEncoding === null
29
+ ? null
30
+ : false,
21
31
  getter: value("G"),
22
32
  setter: value("S"),
23
33
  };