rea-agents 2.5.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/README.md +20 -12
  2. package/bridge/ghidra/ReaGhidraBridge.java +477 -4
  3. package/bridge/hopper_bridge.py +54 -4
  4. package/dist/application/AnalysisContextQueries.js +142 -0
  5. package/dist/application/AnalysisSnapshotCache.js +4 -2
  6. package/dist/application/ApplicationWorkflowEvidenceResolver.js +19 -11
  7. package/dist/application/ArtifactInventory/policy.js +17 -0
  8. package/dist/application/ArtifactInventory/reader.js +1 -4
  9. package/dist/application/ArtifactInventory/scanCanonical.js +0 -3
  10. package/dist/application/ArtifactInventory/scanReader.js +7 -7
  11. package/dist/application/ArtifactInventory/types.js +1 -5
  12. package/dist/application/BinarySession.js +19 -20
  13. package/dist/application/BinarySessionComposition.js +21 -0
  14. package/dist/application/BinarySessionRecords.js +106 -10
  15. package/dist/application/BinarySessionStatus.js +11 -5
  16. package/dist/application/BrowserEvidence.js +3 -5
  17. package/dist/application/CapabilityClientRequirements.js +26 -0
  18. package/dist/application/CapabilityInventory.js +140 -55
  19. package/dist/application/ClientRegistrationStatus.js +4 -1
  20. package/dist/application/CrossVersionInventory.js +7 -6
  21. package/dist/application/DirectAnalysis.js +6 -2
  22. package/dist/application/ElectronActiveEvidence.js +55 -0
  23. package/dist/application/ElectronActiveObservationPort.js +1 -0
  24. package/dist/application/ElectronActiveObservationService.js +81 -0
  25. package/dist/application/EnhancedTools.js +49 -17
  26. package/dist/application/EvidenceBundleCommands.js +5 -1
  27. package/dist/application/EvidenceLedger.js +53 -17
  28. package/dist/application/JavaScriptArtifactAnalysis.js +13 -4
  29. package/dist/application/JavaScriptReplayPermission.js +1 -1
  30. package/dist/application/JavaScriptReplayService.js +23 -15
  31. package/dist/application/LazyAnalysisProvider.js +77 -0
  32. package/dist/application/LoopbackReplay.js +1 -1
  33. package/dist/application/ManagedRuntimeCorrelationService.js +9 -5
  34. package/dist/application/NativeApiInspection.js +80 -0
  35. package/dist/application/NodeRuntimeCharacterizationService.js +8 -9
  36. package/dist/application/ProcessCaptureLifecycle.js +5 -0
  37. package/dist/application/ProcessCli.js +2 -1
  38. package/dist/application/ProcessHarness.js +8 -3
  39. package/dist/application/ProcessNormalization.js +2 -1
  40. package/dist/application/ProjectPermissionStore.js +1 -0
  41. package/dist/application/ReferenceSourceImport.js +2 -2
  42. package/dist/application/SessionProviderRouter.js +6 -6
  43. package/dist/application/SetupClientConfiguration.js +10 -3
  44. package/dist/application/WindowsCapabilities.js +5 -4
  45. package/dist/application/runtime.js +26 -9
  46. package/dist/artifacts/ArtifactProvider.js +8 -10
  47. package/dist/artifacts/SafeOutputTree.js +7 -8
  48. package/dist/browser/CdpCaptureStorageFingerprints.js +10 -7
  49. package/dist/browser/CdpElectronInspection.js +3 -1
  50. package/dist/browser/JavaScriptRuntimeScope.js +5 -0
  51. package/dist/browser/PlaywrightBrowserScenarioProvider.js +8 -2
  52. package/dist/browser/PlaywrightElectronActiveActions.js +324 -0
  53. package/dist/browser/PlaywrightElectronActiveProvider.js +294 -0
  54. package/dist/browser/PlaywrightScenarioBrowser.js +4 -4
  55. package/dist/browser/PlaywrightScenarioSession.js +4 -4
  56. package/dist/browser/SensitiveTextCapture.js +1 -1
  57. package/dist/browser/V8InspectorCaptureProjection.js +1 -0
  58. package/dist/browser/V8InspectorProvider.js +3 -3
  59. package/dist/catalogIdentity.js +15 -9
  60. package/dist/cli/artifactCommands.js +5 -3
  61. package/dist/cli/coreAnalysisCommands.js +41 -0
  62. package/dist/cli/managedCommands.js +1 -1
  63. package/dist/cliApplicationCommands.js +2 -2
  64. package/dist/cliBrowserAdvancedCommands.js +11 -5
  65. package/dist/cliBrowserCommands.js +14 -7
  66. package/dist/cliCommandNames.js +2 -0
  67. package/dist/cliElectronCommands.js +46 -4
  68. package/dist/cliJavaScriptRuntimeCommands.js +14 -6
  69. package/dist/cliObservationOptions.js +4 -0
  70. package/dist/cliPolicyCommands.js +1 -0
  71. package/dist/config/browserScenario.js +77 -0
  72. package/dist/config/electronAutomation.js +35 -0
  73. package/dist/config/environment.js +6 -0
  74. package/dist/config/javascriptReplay.js +41 -0
  75. package/dist/config/managedRuntime.js +25 -0
  76. package/dist/config/parseConfig.js +56 -200
  77. package/dist/config/parsers.js +10 -1
  78. package/dist/config/passiveObservation.js +157 -0
  79. package/dist/config/processCapture.js +47 -0
  80. package/dist/contracts/applicationToolContracts.js +2 -5
  81. package/dist/contracts/applicationWorkflowInputContracts.js +86 -96
  82. package/dist/contracts/artifactToolContracts.js +35 -37
  83. package/dist/contracts/browserToolContracts.js +2 -2
  84. package/dist/contracts/electronToolContracts.js +30 -1
  85. package/dist/contracts/enhancedInputs.js +21 -27
  86. package/dist/contracts/functionWorkflowToolContracts.js +29 -0
  87. package/dist/contracts/managedToolContracts.js +4 -9
  88. package/dist/contracts/managedWorkflowExamples.js +12 -9
  89. package/dist/contracts/managedWorkflowToolContracts.js +30 -27
  90. package/dist/contracts/nativeToolContracts.js +2 -3
  91. package/dist/contracts/promptContracts.js +14 -15
  92. package/dist/contracts/sessionToolSchemas.js +61 -0
  93. package/dist/contracts/toolContractExamples.js +4 -0
  94. package/dist/contracts/toolContractHelpers.js +23 -0
  95. package/dist/contracts/toolContracts.js +12 -67
  96. package/dist/contracts/toolEffects.js +19 -0
  97. package/dist/contracts/toolOutputSchemaGroups.js +66 -11
  98. package/dist/contracts/toolOutputSchemaPrimitives.js +76 -26
  99. package/dist/contracts/toolSchemaMetadata.js +128 -0
  100. package/dist/doctorRuntime.js +1 -1
  101. package/dist/domain/analysisErrorPresentation.js +8 -2
  102. package/dist/domain/analysisErrorProjection.js +1 -0
  103. package/dist/domain/androidApplication.js +2 -0
  104. package/dist/domain/appleApplication.js +2 -0
  105. package/dist/domain/binaryTarget.js +7 -5
  106. package/dist/domain/binaryTargetTypes.js +1 -0
  107. package/dist/domain/browserCaptureComparison.js +21 -69
  108. package/dist/domain/browserObservation.js +22 -9
  109. package/dist/domain/bytecodeProvider.js +177 -0
  110. package/dist/domain/callPath.js +3 -2
  111. package/dist/domain/conformancePackage.js +169 -0
  112. package/dist/domain/conformanceReplay.js +104 -0
  113. package/dist/domain/conformanceTrustGate.js +328 -0
  114. package/dist/domain/customProtocolCapture.js +137 -0
  115. package/dist/domain/electronActiveObservation.js +277 -0
  116. package/dist/domain/electronObservation.js +15 -11
  117. package/dist/domain/electronStaticAnalysisValues.js +4 -1
  118. package/dist/domain/eventProcessTree.js +217 -0
  119. package/dist/domain/evidenceBundle.js +47 -0
  120. package/dist/domain/functionComparisonNormalization.js +15 -8
  121. package/dist/domain/functionDossierEvidence.js +9 -4
  122. package/dist/domain/hopperStartupFailure.js +1 -1
  123. package/dist/domain/hopperValues.js +68 -68
  124. package/dist/domain/inputIssueProjection.js +11 -2
  125. package/dist/domain/investigationWorkspace.js +16 -15
  126. package/dist/domain/javascriptExportShapeComparisonSchemas.js +2 -2
  127. package/dist/domain/javascriptReplay.js +79 -63
  128. package/dist/domain/javascriptRuntimeObservation.js +1 -0
  129. package/dist/domain/javascriptRuntimeReconciliationActive.js +89 -0
  130. package/dist/domain/javascriptRuntimeReconciliationGraph.js +11 -10
  131. package/dist/domain/javascriptRuntimeReconciliationMatching.js +57 -49
  132. package/dist/domain/javascriptRuntimeReconciliationParsing.js +5 -1
  133. package/dist/domain/javascriptRuntimeReconciliationResult.js +21 -14
  134. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
  135. package/dist/domain/javascriptSemanticAnalysis.js +8 -12
  136. package/dist/domain/javascriptSourceParser.js +15 -0
  137. package/dist/domain/javascriptStaticAnalysis.js +8 -12
  138. package/dist/domain/knownPageCoverage.js +15 -7
  139. package/dist/domain/mobileApplicationInvestigation.js +159 -0
  140. package/dist/domain/nativeApiBoundary.js +138 -0
  141. package/dist/domain/nodeRuntimeCharacterization.js +14 -13
  142. package/dist/domain/objcSwiftMetadata.js +150 -0
  143. package/dist/domain/packageAnalysis.js +123 -0
  144. package/dist/domain/peInspection.js +196 -0
  145. package/dist/domain/processCaptureReactiveValidation.js +8 -3
  146. package/dist/domain/processCaptureValidation.js +7 -3
  147. package/dist/domain/processComparison.js +12 -7
  148. package/dist/domain/processObservation.js +5 -6
  149. package/dist/domain/processReactiveMatching.js +14 -7
  150. package/dist/domain/processReactiveTransition.js +9 -3
  151. package/dist/domain/processScenario.js +6 -3
  152. package/dist/domain/processTraceComparison.js +3 -2
  153. package/dist/domain/protocolCapture.js +245 -0
  154. package/dist/domain/reconstructionReadinessSchemas.js +30 -2
  155. package/dist/domain/referenceSourceImportParsing.js +2 -2
  156. package/dist/domain/replayMachineRuntime.js +5 -3
  157. package/dist/domain/sourceToBundleComparison.js +2 -2
  158. package/dist/domain/sourceToBundleComparisonSchemas.js +8 -8
  159. package/dist/domain/sourceToBundleSignals.js +7 -1
  160. package/dist/domain/staticRuntimeCorrelation.js +7 -5
  161. package/dist/domain/webBundleAnalysis.js +14 -14
  162. package/dist/domain/webCaptureDiff.js +15 -12
  163. package/dist/dotnet/ManagedNativeBoundaryInspector.js +2 -3
  164. package/dist/dotnet/ManagedStaticProvider.js +34 -5
  165. package/dist/generatedMcpToolCatalog.js +37 -0
  166. package/dist/generatedPackageMetadata.js +4 -4
  167. package/dist/ghidra/GhidraClient.js +1 -1
  168. package/dist/ghidra/GhidraClientStartup.js +1 -1
  169. package/dist/ghidra/GhidraDefaults.js +1 -1
  170. package/dist/ghidra/GhidraFunctionValues.js +44 -16
  171. package/dist/ghidra/GhidraInventoryValues.js +57 -47
  172. package/dist/ghidra/GhidraProvider.js +18 -10
  173. package/dist/ghidra/GhidraProviderCapabilities.js +45 -39
  174. package/dist/ghidra/GhidraSocketConnection.js +1 -1
  175. package/dist/ghidra/protocol.js +19 -42
  176. package/dist/hopper/BridgeLauncher.js +3 -1
  177. package/dist/hopper/HopperAnalysisProfile.js +2 -4
  178. package/dist/hopper/HopperCleanup.js +5 -6
  179. package/dist/hopper/HopperClient.js +27 -3
  180. package/dist/hopper/HopperProvider.js +42 -44
  181. package/dist/hopper/HopperRequestQueue.js +32 -4
  182. package/dist/hopper/HopperResponseStream.js +2 -2
  183. package/dist/hopper/LinuxPrivateDisplayProbe.js +16 -10
  184. package/dist/hopper/protocol.js +63 -21
  185. package/dist/main/reload.js +1 -6
  186. package/dist/main/state.js +0 -14
  187. package/dist/main/transport.js +31 -41
  188. package/dist/main.js +17 -13
  189. package/dist/mcpDoctor.js +4 -26
  190. package/dist/mcpStartupPolicy.js +14 -0
  191. package/dist/process/PrivateRuntimeRoot.js +17 -0
  192. package/dist/process/ProcessOwnership.js +64 -128
  193. package/dist/process/ProcessOwnershipIdentity.js +13 -0
  194. package/dist/process/ProcessOwnershipObservation.js +88 -0
  195. package/dist/process/ProcessOwnershipProcessTree.js +22 -0
  196. package/dist/process/ProviderDeadline.js +8 -12
  197. package/dist/process/WindowsAuthority.js +32 -0
  198. package/dist/reference/ReferenceSourceReader.js +3 -3
  199. package/dist/reference/ReferenceSourceReaderEntries.js +2 -2
  200. package/dist/replay/JavaScriptReplayWorker.js +95 -11
  201. package/dist/replay/JavaScriptReplayWorkerTypes.js +1 -0
  202. package/dist/replay/LinuxJavaScriptReplayRunner.js +10 -15
  203. package/dist/replay/ReplayOutcome.js +26 -15
  204. package/dist/replay/ReplayWorkerProtocol.js +34 -29
  205. package/dist/server/createServer.js +101 -144
  206. package/dist/server/mcpClientMetadata.js +32 -0
  207. package/dist/server/registerApplicationTools/characterization.js +6 -13
  208. package/dist/server/registerApplicationTools/compareExportShapes.js +2 -7
  209. package/dist/server/registerApplicationTools/compareSourceToBundle.js +2 -7
  210. package/dist/server/registerApplicationTools/compareVersions.js +3 -8
  211. package/dist/server/registerApplicationTools/controlledReplay.js +6 -11
  212. package/dist/server/registerApplicationTools/coverage.js +13 -19
  213. package/dist/server/registerApplicationTools/obligationLedger.js +1 -6
  214. package/dist/server/registerApplicationTools/readiness.js +1 -6
  215. package/dist/server/registerApplicationTools/traceFeature.js +3 -8
  216. package/dist/server/registerApplicationTools/traceSemantics.js +1 -6
  217. package/dist/server/registerArtifactComparisonTool.js +12 -16
  218. package/dist/server/registerBrowserScenarioTool.js +1 -6
  219. package/dist/server/registerBrowserTools.js +37 -79
  220. package/dist/server/registerBundleComparisonTool.js +10 -14
  221. package/dist/server/registerCloseLifecycleTool.js +6 -14
  222. package/dist/server/registerElectronTools.js +30 -47
  223. package/dist/server/registerEnhancedTools.js +124 -122
  224. package/dist/server/registerEvidenceResources.js +50 -101
  225. package/dist/server/registerEvidenceTools.js +5 -9
  226. package/dist/server/registerFunctionComparisonTool.js +11 -15
  227. package/dist/server/registerInvestigationTools.js +42 -59
  228. package/dist/server/registerJavaScriptApplicationGraphResource.js +0 -4
  229. package/dist/server/registerJavaScriptRuntimeObservationTools.js +13 -27
  230. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +4 -9
  231. package/dist/server/registerManagedWorkflowTools/contract.js +2 -3
  232. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +3 -8
  233. package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +3 -8
  234. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +8 -13
  235. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +4 -9
  236. package/dist/server/registerOfficialTools.js +8 -9
  237. package/dist/server/registerProcessComparisonTool.js +19 -24
  238. package/dist/server/registerReconstructionObligationLedgerResource.js +0 -7
  239. package/dist/server/registerReconstructionReadinessResource.js +0 -7
  240. package/dist/server/registerReplayMachineTool.js +4 -10
  241. package/dist/server/registerSessionRecordTools.js +146 -47
  242. package/dist/server/registerSessionStatusTool.js +14 -29
  243. package/dist/server/registerSessionTools.js +45 -41
  244. package/dist/server/sessionAvailabilityPolicy.js +2 -1
  245. package/dist/server/sessionToolPolicies.js +1 -5
  246. package/dist/server/toolRegistrationOptions.js +4 -177
  247. package/dist/server/toolResult.js +14 -18
  248. package/package.json +35 -16
  249. package/scripts/electron-active-hook-boundaries.cjs +394 -0
  250. package/scripts/electron-active-hook.cjs +501 -0
  251. package/skills/reverse-engineer-anything/SKILL.md +10 -3
  252. package/dist/server/DynamicToolAvailability.js +0 -70
  253. package/dist/server/toolInputValidation.js +0 -77
@@ -15,7 +15,7 @@ import { connectHopperSocketOnce } from "./HopperSocketConnection.js";
15
15
  import { hopperLauncherFailureDiagnostic } from "./HopperProcessDiagnostic.js";
16
16
  import { HopperRequestQueue, } from "./HopperRequestQueue.js";
17
17
  import { HopperResponseStream } from "./HopperResponseStream.js";
18
- import { responseResult } from "./protocol.js";
18
+ import { responseResult, } from "./protocol.js";
19
19
  const SHUTDOWN_TIMEOUT_MS = 30_000;
20
20
  const MAX_QUEUED_REQUESTS = 64;
21
21
  const SESSION_ROOT = process.platform === "darwin" ? "/tmp" : tmpdir();
@@ -76,7 +76,7 @@ export class HopperClient {
76
76
  });
77
77
  });
78
78
  this.#responses = new HopperResponseStream({
79
- accept: (response) => this.#requests.accept(response.id, responseResult(response)),
79
+ accept: (message) => this.#acceptBridgeMessage(message),
80
80
  hasQueued: (id) => this.#requests.hasQueued(id),
81
81
  nextRequestId: () => this.#nextId,
82
82
  abort: (message, cause) => this.#abortProtocol(message, cause),
@@ -333,6 +333,30 @@ export class HopperClient {
333
333
  socket.on("error", this.#onSocketError);
334
334
  socket.on("close", this.#onSocketClose);
335
335
  }
336
+ #acceptBridgeMessage(message) {
337
+ if (!("event" in message))
338
+ return this.#requests.accept(message.id, responseResult(message));
339
+ if (!this.#requests.acceptEvent(message))
340
+ return false;
341
+ this.#emitBridgeDiagnostic(message);
342
+ return true;
343
+ }
344
+ #emitBridgeDiagnostic(message) {
345
+ if (message.event.type !== "diagnostic")
346
+ return;
347
+ try {
348
+ this.#options.onDiagnostic?.({
349
+ type: "bridge-diagnostic",
350
+ request_id: message.id,
351
+ code: message.event.error.code,
352
+ category: message.event.error.type,
353
+ message: message.event.error.message,
354
+ });
355
+ }
356
+ catch {
357
+ this.#logger.warn({ requestId: message.id }, "Hopper bridge diagnostic consumer rejected an event");
358
+ }
359
+ }
336
360
  #detachSocket(socket) {
337
361
  socket.off("data", this.#onSocketData);
338
362
  socket.off("error", this.#onSocketError);
@@ -375,6 +399,6 @@ export class HopperClient {
375
399
  }
376
400
  }
377
401
  const isAborted = (signal) => signal?.aborted === true;
378
- const startupInterruption = (deadline) => deadline.cancelled
402
+ const startupInterruption = (deadline) => deadline.interruption === "cancelled"
379
403
  ? new HopperCancelledError()
380
404
  : new HopperTimeoutError(deadline.timeoutMs);
@@ -3,7 +3,7 @@ import { accessSync, constants } from "node:fs";
3
3
  import { createAnalysisExecution } from "../application/AnalysisProvider.js";
4
4
  import { AnalysisCapabilityUnavailableError } from "../domain/errors.js";
5
5
  import { err } from "../domain/result.js";
6
- import { ENHANCED_TOOL_CONTRACTS, OFFICIAL_TOOL_CONTRACTS, } from "../contracts/toolContracts.js";
6
+ import { GENERATED_MCP_TOOL_CATALOG } from "../generatedMcpToolCatalog.js";
7
7
  import { HopperApplicationLauncher } from "./BridgeLauncher.js";
8
8
  import { hopperLoaderArgsForTarget, resolveHopperAnalysisProfile, } from "./HopperAnalysisProfile.js";
9
9
  import { HopperClient } from "./HopperClient.js";
@@ -24,36 +24,47 @@ const MUTATING_OPERATIONS = new Set([
24
24
  ]);
25
25
  /** Tool contracts implemented directly by the Hopper adapter. */
26
26
  export const HOPPER_PROVIDER_TOOL_CONTRACTS = Object.freeze([
27
- ...OFFICIAL_TOOL_CONTRACTS,
28
- ...ENHANCED_TOOL_CONTRACTS.filter((contract) => contract.name === "analyze_function"),
27
+ ...GENERATED_MCP_TOOL_CATALOG.filter(({ kind }) => kind === "official-proxy"),
28
+ ...GENERATED_MCP_TOOL_CATALOG.filter(({ name }) => name === "analyze_function"),
29
29
  ]);
30
- const CAPABILITIES = Object.freeze(HOPPER_PROVIDER_TOOL_CONTRACTS.map((contract) => Object.freeze({
31
- provider: IDENTITY,
32
- operation: contract.name,
33
- inputContractVersion: 1,
34
- outputContractVersion: 1,
35
- available: true,
36
- reason: null,
37
- pagination: "offset" in contract.inputSchema.shape ? "offset" : "none",
38
- exhaustive: false,
39
- effects: Object.freeze({
40
- mutatesArtifact: MUTATING_OPERATIONS.has(contract.name),
41
- launchesProcess: true,
42
- mayShowUi: true,
43
- mayAccessNetwork: false,
44
- mayWriteFilesystem: MUTATING_OPERATIONS.has(contract.name),
45
- changesPermissions: false,
46
- requiresRoot: false,
47
- }),
48
- limits: Object.freeze({
49
- maxResults: null,
50
- maxPayloadBytes: contract.name === "read_bytes" ? 4_096 : null,
51
- timeoutMs: null,
52
- }),
53
- limitations: Object.freeze([
54
- "Results depend on Hopper's completed static analysis.",
55
- ]),
56
- })));
30
+ const CAPABILITIES = Object.freeze(HOPPER_PROVIDER_TOOL_CONTRACTS.map((contract) => {
31
+ const operation = contract.analysisOperation;
32
+ if (operation === null)
33
+ throw new TypeError(`Missing analysis operation for ${contract.name}`);
34
+ return Object.freeze({
35
+ provider: IDENTITY,
36
+ operation,
37
+ inputContractVersion: 1,
38
+ outputContractVersion: 1,
39
+ available: true,
40
+ reason: null,
41
+ pagination: isRecord(contract.inputSchema.properties) &&
42
+ "offset" in contract.inputSchema.properties
43
+ ? "offset"
44
+ : "none",
45
+ exhaustive: false,
46
+ effects: Object.freeze({
47
+ mutatesArtifact: MUTATING_OPERATIONS.has(contract.name),
48
+ launchesProcess: true,
49
+ mayShowUi: true,
50
+ mayAccessNetwork: false,
51
+ mayWriteFilesystem: MUTATING_OPERATIONS.has(contract.name),
52
+ changesPermissions: false,
53
+ requiresRoot: false,
54
+ }),
55
+ limits: Object.freeze({
56
+ maxResults: null,
57
+ maxPayloadBytes: contract.name === "read_bytes" ? 4_096 : null,
58
+ timeoutMs: null,
59
+ }),
60
+ limitations: Object.freeze([
61
+ "Results depend on Hopper's completed static analysis.",
62
+ ]),
63
+ });
64
+ }));
65
+ function isRecord(value) {
66
+ return typeof value === "object" && value !== null && !Array.isArray(value);
67
+ }
57
68
  /** Concrete analysis provider backed by REA's private Hopper bridge. */
58
69
  export class HopperProvider {
59
70
  config;
@@ -118,20 +129,6 @@ export class HopperProvider {
118
129
  reason: null,
119
130
  diagnostics,
120
131
  };
121
- if (!["mach-o", "elf", "pe"].includes(target.format))
122
- return {
123
- status: "unsupported",
124
- code: "target_format_unsupported",
125
- reason: `Hopper cannot open ${target.format} through this adapter.`,
126
- diagnostics,
127
- };
128
- if (target.architecture === undefined)
129
- return {
130
- status: "unsupported",
131
- code: "architecture_unsupported",
132
- reason: "Hopper requires a supported concrete target architecture.",
133
- diagnostics,
134
- };
135
132
  return {
136
133
  status: "supported",
137
134
  code: null,
@@ -178,6 +175,7 @@ export class HopperProvider {
178
175
  }),
179
176
  ...(context === undefined ? {} : { runId: context.runId }),
180
177
  logger: this.logger.child({ layer: "bridge" }),
178
+ onDiagnostic: (diagnostic) => this.logger.info(diagnostic, "Hopper bridge reported a diagnostic"),
181
179
  });
182
180
  return {
183
181
  execute: async (operation, parameters, options) => {
@@ -59,6 +59,28 @@ export class HopperRequestQueue {
59
59
  this.#drain();
60
60
  return true;
61
61
  }
62
+ /** Forward one correlated bridge event without releasing the wire request. */
63
+ acceptEvent(event) {
64
+ const entry = this.#active;
65
+ if (entry === undefined || entry.id !== event.id)
66
+ return false;
67
+ if (event.event.type === "progress" && !entry.callerSettled) {
68
+ if (event.event.terminal === true && entry.heartbeat !== undefined) {
69
+ clearInterval(entry.heartbeat);
70
+ entry.heartbeat = undefined;
71
+ }
72
+ this.#reportUpdate(entry, {
73
+ phase: event.event.phase,
74
+ completed: event.event.completed,
75
+ total: event.event.total,
76
+ message: event.event.message,
77
+ ...(event.event.terminal === undefined
78
+ ? {}
79
+ : { terminal: event.event.terminal }),
80
+ });
81
+ }
82
+ return true;
83
+ }
62
84
  /** Fail the active wire request and every request still waiting in the FIFO. */
63
85
  failAll(error) {
64
86
  const active = this.#active;
@@ -175,13 +197,19 @@ export class HopperRequestQueue {
175
197
  entry.signal.removeEventListener("abort", entry.onAbort);
176
198
  }
177
199
  #report(entry, message) {
178
- void entry.progress
179
- ?.report({
200
+ this.#reportUpdate(entry, {
180
201
  phase: "hopper_request",
181
202
  completed: 0,
182
203
  total: 1,
183
204
  message,
184
- })
185
- .catch(() => undefined);
205
+ });
206
+ }
207
+ #reportUpdate(entry, update) {
208
+ try {
209
+ void Promise.resolve(entry.progress?.report(update)).catch(() => undefined);
210
+ }
211
+ catch {
212
+ // Progress observation cannot change the request outcome.
213
+ }
186
214
  }
187
215
  }
@@ -1,4 +1,4 @@
1
- import { parseResponseLine } from "./protocol.js";
1
+ import { parseBridgeMessageLine, } from "./protocol.js";
2
2
  const MAX_LINE_BYTES = 10 * 1024 * 1024;
3
3
  /** Incrementally validates bounded Hopper NDJSON response frames. */
4
4
  export class HopperResponseStream {
@@ -29,7 +29,7 @@ export class HopperResponseStream {
29
29
  this.#buffer = "";
30
30
  }
31
31
  #acceptLine(line) {
32
- const parsed = parseResponseLine(line);
32
+ const parsed = parseBridgeMessageLine(line);
33
33
  if (!parsed.ok) {
34
34
  this.options.abort(parsed.error.message, parsed.error);
35
35
  return false;
@@ -42,7 +42,7 @@ export const selectLinuxPrivateDisplayStrategy = async (options) => {
42
42
  /** Run one helper probe in an owned process group with a hard output bound. */
43
43
  export const runLinuxPrivateDisplayProbe = async (strategy, options) => {
44
44
  if (options.signal?.aborted === true)
45
- return emptyProcessResult({ cancelled: true });
45
+ return emptyProcessResult("cancelled");
46
46
  const command = privateDisplayProbeCommand(options.helperPath, strategy);
47
47
  let started;
48
48
  try {
@@ -54,7 +54,7 @@ export const runLinuxPrivateDisplayProbe = async (strategy, options) => {
54
54
  });
55
55
  }
56
56
  catch {
57
- return emptyProcessResult();
57
+ return emptyProcessResult("launch-failed");
58
58
  }
59
59
  const launch = {
60
60
  process: started.process,
@@ -74,12 +74,15 @@ export const runLinuxPrivateDisplayProbe = async (strategy, options) => {
74
74
  supervisor.dispose();
75
75
  const snapshot = supervisor.snapshot();
76
76
  return {
77
+ outcome: outcome === "exit"
78
+ ? "exited"
79
+ : outcome === "timeout"
80
+ ? "timed-out"
81
+ : "cancelled",
77
82
  exitCode: snapshot.exitCode,
78
83
  stderr: snapshot.stderr.text,
79
84
  stderrBytes: snapshot.stderr.bytes,
80
85
  stderrTruncated: snapshot.stderr.truncated,
81
- timedOut: outcome === "timeout",
82
- cancelled: outcome === "cancelled",
83
86
  cleanupIncomplete,
84
87
  };
85
88
  };
@@ -119,16 +122,21 @@ const evaluatedProbe = async (strategy, options, timeoutMs, runner) => {
119
122
  diagnostic: syntheticDiagnostic(strategy, "probe_failed"),
120
123
  };
121
124
  }
122
- if (processResult.cancelled)
125
+ if (processResult.outcome === "cancelled")
123
126
  return {
124
127
  ok: false,
125
128
  diagnostic: syntheticDiagnostic(strategy, "cancelled"),
126
129
  };
127
- if (processResult.timedOut)
130
+ if (processResult.outcome === "timed-out")
128
131
  return {
129
132
  ok: false,
130
133
  diagnostic: syntheticDiagnostic(strategy, "probe_timeout"),
131
134
  };
135
+ if (processResult.outcome === "launch-failed")
136
+ return {
137
+ ok: false,
138
+ diagnostic: syntheticDiagnostic(strategy, "probe_failed"),
139
+ };
132
140
  if (processResult.cleanupIncomplete)
133
141
  return {
134
142
  ok: false,
@@ -182,15 +190,13 @@ const unavailable = (diagnostic) => ({
182
190
  : (hopperStartupExitCode(diagnostic.failure_code) ?? 70),
183
191
  diagnostic: { ...diagnostic, strategy: "unavailable" },
184
192
  });
185
- const emptyProcessResult = (overrides = {}) => ({
193
+ const emptyProcessResult = (outcome) => ({
194
+ outcome,
186
195
  exitCode: undefined,
187
196
  stderr: "",
188
197
  stderrBytes: 0,
189
198
  stderrTruncated: false,
190
- timedOut: false,
191
- cancelled: false,
192
199
  cleanupIncomplete: false,
193
- ...overrides,
194
200
  });
195
201
  const waitForProbeExit = async (supervisor, timeoutMs, signal) => {
196
202
  if (signal?.aborted === true)
@@ -2,30 +2,72 @@ import { z } from "zod";
2
2
  import { HopperProtocolError, HopperRemoteError } from "../domain/errors.js";
3
3
  import { jsonValueSchema } from "../domain/jsonValue.js";
4
4
  import { err, ok } from "../domain/result.js";
5
+ const remoteErrorSchema = z
6
+ .object({
7
+ code: z.number().int(),
8
+ message: z.string().max(512),
9
+ type: z
10
+ .enum([
11
+ "remote",
12
+ "authorization",
13
+ "invalid_request",
14
+ "capability_unavailable",
15
+ "bridge_exception",
16
+ ])
17
+ .default("remote"),
18
+ })
19
+ .strict();
5
20
  const responseSchema = z.union([
6
- z.object({
21
+ z
22
+ .object({
7
23
  id: z.number().int().nonnegative(),
8
24
  result: jsonValueSchema,
9
- }),
10
- z.object({
25
+ })
26
+ .strict(),
27
+ z
28
+ .object({
11
29
  id: z.number().int().nonnegative(),
12
- error: z.object({
13
- code: z.number().int(),
14
- message: z.string(),
15
- type: z
16
- .enum([
17
- "remote",
18
- "authorization",
19
- "invalid_request",
20
- "capability_unavailable",
21
- "bridge_exception",
22
- ])
23
- .default("remote"),
24
- }),
25
- }),
30
+ error: remoteErrorSchema,
31
+ })
32
+ .strict(),
26
33
  ]);
27
- /** Parse one complete Hopper NDJSON response line. */
28
- export const parseResponseLine = (line) => {
34
+ const eventSchema = z
35
+ .object({
36
+ id: z.number().int().nonnegative(),
37
+ event: z.discriminatedUnion("type", [
38
+ z
39
+ .object({
40
+ type: z.literal("progress"),
41
+ phase: z.string().min(1).max(64),
42
+ completed: z.number().nonnegative().finite(),
43
+ total: z.number().nonnegative().finite().nullable(),
44
+ message: z.string().min(1).max(512),
45
+ terminal: z.boolean().optional(),
46
+ })
47
+ .strict(),
48
+ z
49
+ .object({
50
+ type: z.literal("diagnostic"),
51
+ error: remoteErrorSchema,
52
+ })
53
+ .strict(),
54
+ ]),
55
+ })
56
+ .strict()
57
+ .superRefine((message, context) => {
58
+ if (message.event.type === "progress" &&
59
+ message.event.total !== null &&
60
+ message.event.completed > message.event.total) {
61
+ context.addIssue({
62
+ code: "custom",
63
+ message: "Progress total cannot be less than completed",
64
+ path: ["event", "total"],
65
+ });
66
+ }
67
+ });
68
+ const messageSchema = z.union([responseSchema, eventSchema]);
69
+ /** Parse one complete Hopper NDJSON response or event line. */
70
+ export const parseBridgeMessageLine = (line) => {
29
71
  let decoded;
30
72
  try {
31
73
  decoded = JSON.parse(line);
@@ -33,10 +75,10 @@ export const parseResponseLine = (line) => {
33
75
  catch (cause) {
34
76
  return err(new HopperProtocolError("Hopper returned malformed JSON", { cause }));
35
77
  }
36
- const parsed = responseSchema.safeParse(decoded);
78
+ const parsed = messageSchema.safeParse(decoded);
37
79
  return parsed.success
38
80
  ? ok(parsed.data)
39
- : err(new HopperProtocolError("Hopper returned a response outside the bridge contract", { cause: parsed.error }));
81
+ : err(new HopperProtocolError("Hopper returned a message outside the bridge contract", { cause: parsed.error }));
40
82
  };
41
83
  /** Project a parsed response into its result or expected remote failure. */
42
84
  export const responseResult = (response) => "error" in response
@@ -2,7 +2,7 @@ import { parseConfig } from "../config.js";
2
2
  import { readProjectPermissionStore } from "../application/ProjectPermissionStore.js";
3
3
  import { MCP_PERMISSION_RELOAD_FAILED } from "./messages.js";
4
4
  export const registerConfigReload = (input) => {
5
- const { dependencies, permissionAuthority, runtimeState, liveServers, serverLogger, } = input;
5
+ const { dependencies, permissionAuthority, runtimeState, serverLogger } = input;
6
6
  let reloadQueue = Promise.resolve();
7
7
  return (dependencies.registerReload?.(() => {
8
8
  const refreshed = parseConfig(dependencies.env);
@@ -33,14 +33,9 @@ export const registerConfigReload = (input) => {
33
33
  return;
34
34
  }
35
35
  runtimeState.currentConfig = refreshed.value;
36
- Object.assign(runtimeState.processPolicy, refreshed.value.processExecutionPolicy);
37
36
  Object.assign(runtimeState.evidencePolicy, refreshed.value.evidenceFilePolicy);
38
37
  Object.assign(runtimeState.snapshotPolicy, refreshed.value.analysisSnapshotFilePolicy);
39
38
  runtimeState.investigationRoots.splice(0, runtimeState.investigationRoots.length, ...refreshed.value.investigationInputRoots);
40
- Object.assign(runtimeState.javascriptReplayPolicy, refreshed.value.javascriptReplayPolicy);
41
- Object.assign(runtimeState.managedRuntimePolicy, refreshed.value.managedRuntimePolicy);
42
- for (const server of liveServers)
43
- server.sendToolListChanged();
44
39
  })
45
40
  .catch(() => {
46
41
  serverLogger.error(MCP_PERMISSION_RELOAD_FAILED);
@@ -1,11 +1,5 @@
1
1
  export const createRuntimeState = (config) => ({
2
2
  currentConfig: config,
3
- processPolicy: {
4
- ...config.processExecutionPolicy,
5
- executableRoots: [...config.processExecutionPolicy.executableRoots],
6
- workingRoots: [...config.processExecutionPolicy.workingRoots],
7
- allowedEnvironment: [...config.processExecutionPolicy.allowedEnvironment],
8
- },
9
3
  evidencePolicy: {
10
4
  ...config.evidenceFilePolicy,
11
5
  roots: [...config.evidenceFilePolicy.roots],
@@ -15,12 +9,4 @@ export const createRuntimeState = (config) => ({
15
9
  roots: [...config.analysisSnapshotFilePolicy.roots],
16
10
  },
17
11
  investigationRoots: [...config.investigationInputRoots],
18
- javascriptReplayPolicy: {
19
- ...config.javascriptReplayPolicy,
20
- roots: [...config.javascriptReplayPolicy.roots],
21
- },
22
- managedRuntimePolicy: {
23
- ...config.managedRuntimePolicy,
24
- roots: [...config.managedRuntimePolicy.roots],
25
- },
26
12
  });
@@ -1,31 +1,30 @@
1
- import { createServer } from "../server/createServer.js";
1
+ import { createServer, } from "../server/createServer.js";
2
2
  import { MCP_CONNECTION_LOST, MCP_CONNECTION_START_FAILED, } from "./messages.js";
3
3
  export const startMcpTransport = async (dependencies, session, serverContext) => {
4
- const liveServers = new Set();
5
4
  const { serverLogger } = serverContext;
5
+ let optionalProviders = {};
6
+ try {
7
+ optionalProviders = await serverContext.loadOptionalProviders();
8
+ }
9
+ catch {
10
+ serverLogger.warn("Optional MCP providers could not load; affected tools remain unavailable");
11
+ }
6
12
  let handle;
7
13
  try {
8
- handle = dependencies.serve(() => {
9
- const server = (dependencies.createServer ?? createServer)(session, session, {
10
- logger: serverContext.logger,
11
- processPolicy: serverContext.runtimeState.processPolicy,
12
- evidenceFilePolicy: serverContext.runtimeState.evidencePolicy,
13
- investigationInputRoots: serverContext.runtimeState.investigationRoots,
14
- analysisSnapshotFilePolicy: serverContext.runtimeState.snapshotPolicy,
15
- permissionAuthority: serverContext.permissionAuthority,
16
- browserObservation: serverContext.browserObservation,
17
- browserScenarioCapture: serverContext.browserScenarioCapture,
18
- electronObservation: serverContext.electronObservation,
19
- javascriptRuntimeObservation: serverContext.javascriptRuntimeObservation,
20
- artifactIntegrityContinueEnabled: () => serverContext.runtimeState.currentConfig
21
- .artifactIntegrityContinueEnabled,
22
- javascriptReplayPolicy: serverContext.runtimeState.javascriptReplayPolicy,
23
- managedRuntimePolicy: serverContext.runtimeState.managedRuntimePolicy,
24
- availabilityPolicy: () => runtimeAvailability(serverContext.runtimeState),
25
- });
26
- liveServers.add(server);
27
- return server;
28
- }, {
14
+ handle = dependencies.serve(() => (dependencies.createServer ?? createServer)(session, session, {
15
+ logger: serverContext.logger,
16
+ processPolicy: () => serverContext.runtimeState.currentConfig.processExecutionPolicy,
17
+ evidenceFilePolicy: serverContext.runtimeState.evidencePolicy,
18
+ investigationInputRoots: serverContext.runtimeState.investigationRoots,
19
+ analysisSnapshotFilePolicy: serverContext.runtimeState.snapshotPolicy,
20
+ permissionAuthority: serverContext.permissionAuthority,
21
+ ...optionalProviders,
22
+ artifactIntegrityContinueEnabled: () => serverContext.runtimeState.currentConfig
23
+ .artifactIntegrityContinueEnabled,
24
+ javascriptReplayPolicy: () => serverContext.runtimeState.currentConfig.javascriptReplayPolicy,
25
+ managedRuntimePolicy: () => serverContext.runtimeState.currentConfig.managedRuntimePolicy,
26
+ availabilityPolicy: () => runtimeAvailability(serverContext.runtimeState),
27
+ }), {
29
28
  onerror: () => {
30
29
  serverLogger.error(MCP_CONNECTION_LOST);
31
30
  dependencies.writeStderr(`${MCP_CONNECTION_LOST}\n`);
@@ -38,26 +37,17 @@ export const startMcpTransport = async (dependencies, session, serverContext) =>
38
37
  dependencies.writeStderr(`${MCP_CONNECTION_START_FAILED}\n`);
39
38
  return { ok: false };
40
39
  }
41
- return { ok: true, handle, liveServers };
40
+ return { ok: true, handle };
42
41
  };
43
42
  const runtimeAvailability = (state) => ({
44
- processCaptureEnabled: state.currentConfig.processExecutionPolicy.enabled,
43
+ processCaptureEnabled: state.currentConfig.processExecutionPolicy.status === "enabled",
45
44
  evidenceFileRoots: state.currentConfig.evidenceFilePolicy.roots.length,
46
45
  investigationInputRoots: state.currentConfig.investigationInputRoots.length,
47
- browserObservationEnabled: state.currentConfig.browserObservationEnabled &&
48
- state.currentConfig.browserCdpEndpoints.length > 0 &&
49
- state.currentConfig.browserAllowedOrigins.length > 0,
50
- browserScenarioEnabled: state.currentConfig.browserScenarioPolicy.enabled &&
51
- state.currentConfig.browserScenarioPolicy.allowedOrigins.length > 0 &&
52
- (state.currentConfig.browserScenarioPolicy.executableRoots.length > 0 ||
53
- state.currentConfig.browserScenarioPolicy.cdpEndpoints.length > 0),
54
- electronObservationEnabled: state.currentConfig.electronObservationEnabled &&
55
- state.currentConfig.electronCdpEndpoints.length > 0 &&
56
- state.currentConfig.electronFileRoots.length > 0,
57
- v8InspectorObservationEnabled: state.currentConfig.v8InspectorObservationEnabled &&
58
- state.currentConfig.v8InspectorEndpoints.length > 0 &&
59
- (state.currentConfig.v8InspectorFileRoots.length > 0 ||
60
- state.currentConfig.v8InspectorAllowedOrigins.length > 0),
61
- javascriptReplayEnabled: state.currentConfig.javascriptReplayPolicy.enabled,
62
- managedRuntimeEnabled: state.currentConfig.managedRuntimePolicy.enabled,
46
+ browserObservationEnabled: state.currentConfig.browserObservationPolicy.status === "enabled",
47
+ browserScenarioEnabled: state.currentConfig.browserScenarioPolicy.status === "enabled",
48
+ electronObservationEnabled: state.currentConfig.electronObservationPolicy.status === "enabled",
49
+ electronAutomationEnabled: state.currentConfig.electronAutomationPolicy.status === "enabled",
50
+ v8InspectorObservationEnabled: state.currentConfig.v8InspectorObservationPolicy.status === "enabled",
51
+ javascriptReplayEnabled: state.currentConfig.javascriptReplayPolicy.status === "enabled",
52
+ managedRuntimeEnabled: state.currentConfig.managedRuntimePolicy.status === "enabled",
63
53
  });
package/dist/main.js CHANGED
@@ -7,10 +7,6 @@ import { createBinarySession } from "./application/runtime.js";
7
7
  import { createLogger } from "./logger.js";
8
8
  import { projectAnalysisError } from "./domain/errors.js";
9
9
  import { loadConfiguredPermissionAuthority } from "./application/PermissionConfiguration.js";
10
- import { CdpBrowserProvider } from "./browser/CdpBrowserProvider.js";
11
- import { CdpElectronProvider } from "./browser/CdpElectronProvider.js";
12
- import { V8InspectorProvider } from "./browser/V8InspectorProvider.js";
13
- import { PlaywrightBrowserScenarioProvider } from "./browser/PlaywrightBrowserScenarioProvider.js";
14
10
  import { SERVER_START_FAILED } from "./main/messages.js";
15
11
  import { createRuntimeState } from "./main/state.js";
16
12
  import { openInitialTarget } from "./main/startup.js";
@@ -60,10 +56,6 @@ export const run = async (dependencies = runtimeDependencies()) => {
60
56
  return 1;
61
57
  }
62
58
  const session = createBinarySession(config.value, logger);
63
- const browserObservation = new CdpBrowserProvider();
64
- const browserScenarioCapture = new PlaywrightBrowserScenarioProvider();
65
- const electronObservation = new CdpElectronProvider();
66
- const javascriptRuntimeObservation = new V8InspectorProvider();
67
59
  const opened = await openInitialTarget(session, config.value, serverLogger, dependencies.writeStderr);
68
60
  if (!opened.ok)
69
61
  return opened.exitCode;
@@ -71,10 +63,23 @@ export const run = async (dependencies = runtimeDependencies()) => {
71
63
  const transport = await startMcpTransport(dependencies, session, {
72
64
  logger,
73
65
  serverLogger,
74
- browserObservation,
75
- browserScenarioCapture,
76
- electronObservation,
77
- javascriptRuntimeObservation,
66
+ loadOptionalProviders: dependencies.loadOptionalProviders ??
67
+ (async () => {
68
+ const [{ CdpBrowserProvider }, { PlaywrightBrowserScenarioProvider }, { CdpElectronProvider }, { PlaywrightElectronActiveProvider }, { V8InspectorProvider },] = await Promise.all([
69
+ import("./browser/CdpBrowserProvider.js"),
70
+ import("./browser/PlaywrightBrowserScenarioProvider.js"),
71
+ import("./browser/CdpElectronProvider.js"),
72
+ import("./browser/PlaywrightElectronActiveProvider.js"),
73
+ import("./browser/V8InspectorProvider.js"),
74
+ ]);
75
+ return {
76
+ browserObservation: new CdpBrowserProvider(),
77
+ browserScenarioCapture: new PlaywrightBrowserScenarioProvider(),
78
+ electronObservation: new CdpElectronProvider(),
79
+ electronActiveObservation: new PlaywrightElectronActiveProvider(),
80
+ javascriptRuntimeObservation: new V8InspectorProvider(),
81
+ };
82
+ }),
78
83
  permissionAuthority: permissionAuthority.value,
79
84
  runtimeState,
80
85
  });
@@ -84,7 +89,6 @@ export const run = async (dependencies = runtimeDependencies()) => {
84
89
  dependencies,
85
90
  permissionAuthority: permissionAuthority.value,
86
91
  runtimeState,
87
- liveServers: transport.liveServers,
88
92
  serverLogger,
89
93
  });
90
94
  createShutdown({