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
@@ -1046,29 +1046,65 @@ def _serve_connection(connection):
1046
1046
  if not line or len(line) > MAX_LINE_BYTES:
1047
1047
  break
1048
1048
  request_id = None
1049
+ authenticated = False
1049
1050
  should_stop = False
1050
1051
  try:
1051
1052
  request = json.loads(line.decode("utf-8"))
1052
1053
  if set(request) != {"id", "token", "method", "params"}:
1053
1054
  raise ValueError("Invalid bridge request shape")
1054
1055
  request_id = request["id"]
1056
+ if isinstance(request_id, bool) or not isinstance(request_id, int) or request_id < 0:
1057
+ raise ValueError("Invalid bridge request id")
1055
1058
  if not isinstance(request["token"], str) or not hmac.compare_digest(request["token"], REA_TOKEN):
1056
1059
  raise PermissionError("Invalid bridge capability")
1060
+ authenticated = True
1061
+ _write_message(file, {"id": request_id, "event": {
1062
+ "type": "progress",
1063
+ "phase": "hopper_bridge",
1064
+ "completed": 0,
1065
+ "total": 1,
1066
+ "message": "Hopper bridge started request",
1067
+ }})
1057
1068
  result = _dispatch(request["method"], request["params"])
1058
1069
  should_stop = request["method"] == "shutdown_document" or (
1059
1070
  request["method"] == "shutdown" and not result.get("cleanup_required", False)
1060
1071
  )
1061
- response = {"id": request_id, "result": _json_safe(result)}
1072
+ safe_result = _json_safe(result)
1073
+ _write_message(file, {"id": request_id, "event": {
1074
+ "type": "progress",
1075
+ "phase": "hopper_bridge",
1076
+ "completed": 1,
1077
+ "total": 1,
1078
+ "message": "Hopper bridge completed request",
1079
+ "terminal": True,
1080
+ }})
1081
+ response = {"id": request_id, "result": safe_result}
1062
1082
  except Exception as error:
1063
- response = {"id": request_id if isinstance(request_id, int) else 0, "error": {"code": -32000, "message": str(error)[:512], "type": _diagnostic_type(error)}}
1064
- file.write((json.dumps(response, separators=(",", ":")) + "\n").encode("utf-8"))
1065
- file.flush()
1083
+ diagnostic = _safe_diagnostic(error)
1084
+ if authenticated:
1085
+ _write_message(file, {"id": request_id, "event": {
1086
+ "type": "diagnostic",
1087
+ "error": diagnostic,
1088
+ }})
1089
+ response_id = request_id if (
1090
+ isinstance(request_id, int)
1091
+ and not isinstance(request_id, bool)
1092
+ and request_id >= 0
1093
+ ) else 0
1094
+ response = {"id": response_id, "error": diagnostic}
1095
+ _write_message(file, response)
1066
1096
  if should_stop:
1067
1097
  break
1068
1098
  file.close()
1069
1099
  connection.close()
1070
1100
 
1071
1101
 
1102
+ def _write_message(file, message):
1103
+ """Write and flush one compact bridge message."""
1104
+ file.write((json.dumps(message, separators=(",", ":")) + "\n").encode("utf-8"))
1105
+ file.flush()
1106
+
1107
+
1072
1108
  def _diagnostic_type(error):
1073
1109
  if isinstance(error, CapabilityUnavailableError):
1074
1110
  return "capability_unavailable"
@@ -1079,6 +1115,20 @@ def _diagnostic_type(error):
1079
1115
  return "bridge_exception"
1080
1116
 
1081
1117
 
1118
+ def _safe_diagnostic(error):
1119
+ """Project one exception without retaining provider or credential text."""
1120
+ diagnostic_type = _diagnostic_type(error)
1121
+ if diagnostic_type == "capability_unavailable":
1122
+ message = str(error)[:512]
1123
+ elif diagnostic_type == "authorization":
1124
+ message = "Invalid bridge capability"
1125
+ elif diagnostic_type == "invalid_request":
1126
+ message = "Invalid Hopper bridge request"
1127
+ else:
1128
+ message = "%s: Hopper bridge operation failed" % type(error).__name__[:128]
1129
+ return {"code": -32000, "message": message, "type": diagnostic_type}
1130
+
1131
+
1082
1132
  def _run():
1083
1133
  """Own a permission-restricted, single-client Unix socket for this bridge."""
1084
1134
  if os.path.exists(REA_SOCKET):
@@ -0,0 +1,142 @@
1
+ import { AnalysisOutputError } from "../domain/errors.js";
2
+ import { err, ok } from "../domain/result.js";
3
+ const parameters = (document, address) => ({
4
+ ...(document === undefined ? {} : { document }),
5
+ ...(address === undefined ? {} : { address }),
6
+ });
7
+ const executionOptions = (signal) => signal === undefined ? {} : { signal };
8
+ /** Compose the provider's volatile selection state into one coherent query. */
9
+ export const getNavigationContext = async (analysis, input, signal) => {
10
+ const document = input.document ??
11
+ (await analysis.execute("current_document", {}, executionOptions(signal)));
12
+ if (typeof document !== "string" && !document.ok)
13
+ return document;
14
+ const documentName = typeof document === "string" ? document : document.value.result;
15
+ const documentArgs = typeof documentName === "string" ? parameters(documentName) : {};
16
+ const address = await analysis.execute("current_address", documentArgs, executionOptions(signal));
17
+ if (!address.ok)
18
+ return address;
19
+ if (typeof address.value.result !== "string")
20
+ return ok({
21
+ document: documentName,
22
+ address: address.value.result,
23
+ procedure: null,
24
+ });
25
+ const procedure = await analysis.execute("resolve_containing_procedure", parameters(typeof documentName === "string" ? documentName : undefined, address.value.result), executionOptions(signal));
26
+ if (!procedure.ok) {
27
+ if (!isMissingCurrentProcedure(procedure.error))
28
+ return procedure;
29
+ return ok({
30
+ document: documentName,
31
+ address: address.value.result,
32
+ procedure: null,
33
+ });
34
+ }
35
+ return ok({
36
+ document: documentName,
37
+ address: address.value.result,
38
+ procedure: containingProcedureName(procedure.value.result),
39
+ });
40
+ };
41
+ /** Inspect bounded provider-neutral facets at one explicit reproducible address. */
42
+ export const inspectAddressContext = async (analysis, input, signal) => {
43
+ const document = await resolveDocument(analysis, input.document, signal);
44
+ if (!document.ok)
45
+ return document;
46
+ const args = parameters(document.value, input.address);
47
+ const operations = [
48
+ "address_name",
49
+ "resolve_containing_procedure",
50
+ "comment",
51
+ "inline_comment",
52
+ "list_bookmarks",
53
+ ];
54
+ const results = await Promise.all(operations.map((operation) => analysis.execute(operation, operation === "list_bookmarks" ? parameters(document.value) : args, executionOptions(signal))));
55
+ for (const result of results) {
56
+ if (!result.ok && isRequestLevelFailure(result.error))
57
+ return result;
58
+ }
59
+ const name = facet(results[0], operations[0]);
60
+ const procedure = facet(results[1], operations[1]);
61
+ const comment = facet(results[2], operations[2]);
62
+ const inlineComment = facet(results[3], operations[3]);
63
+ const bookmarks = facet(results[4], operations[4]);
64
+ return ok({
65
+ address: input.address,
66
+ document: document.value,
67
+ name,
68
+ procedure,
69
+ comment,
70
+ inline_comment: inlineComment,
71
+ bookmarks: bookmarks.state === "available"
72
+ ? matchingBookmarks(bookmarks.value, resolvedAddress(results[1], input.address))
73
+ : bookmarks,
74
+ });
75
+ };
76
+ const resolveDocument = async (analysis, document, signal) => {
77
+ if (document !== undefined)
78
+ return ok(document);
79
+ const current = await analysis.execute("current_document", {}, executionOptions(signal));
80
+ if (!current.ok)
81
+ return current;
82
+ return typeof current.value.result === "string"
83
+ ? ok(current.value.result)
84
+ : err(new AnalysisOutputError("current_document", "expected a document identity string"));
85
+ };
86
+ const facet = (result, operation) => result?.ok === true
87
+ ? { state: "available", value: result.value.result }
88
+ : {
89
+ state: "unavailable",
90
+ reason: result?.error.message ?? `${operation} returned no result`,
91
+ remediation: `Call ${operation} directly to inspect provider availability and diagnostics.`,
92
+ };
93
+ const isMissingCurrentProcedure = (error) => /(?:no procedure exists|not in a procedure)/iu.test(error.message);
94
+ const isRequestLevelFailure = (error) => error._tag === "AnalysisCancelledError" ||
95
+ error._tag === "AnalysisTimeoutError" ||
96
+ error._tag === "NoBinaryOpenError" ||
97
+ error._tag === "PermissionRequiredError";
98
+ const containingProcedureName = (value) => {
99
+ if (typeof value !== "object" || value === null || Array.isArray(value))
100
+ return null;
101
+ if (value.found !== true)
102
+ return null;
103
+ const procedure = value.procedure;
104
+ if (typeof procedure !== "object" ||
105
+ procedure === null ||
106
+ Array.isArray(procedure))
107
+ return null;
108
+ return typeof procedure.name === "string" ? procedure.name : null;
109
+ };
110
+ const resolvedAddress = (result, fallback) => {
111
+ if (result?.ok !== true)
112
+ return fallback;
113
+ const value = result.value.result;
114
+ if (typeof value !== "object" || value === null || Array.isArray(value))
115
+ return fallback;
116
+ return typeof value.query_address === "string"
117
+ ? value.query_address
118
+ : fallback;
119
+ };
120
+ const matchingBookmarks = (value, address) => {
121
+ if (!Array.isArray(value))
122
+ return {
123
+ state: "unavailable",
124
+ reason: "list_bookmarks returned malformed output; expected an array.",
125
+ remediation: "Retry list_bookmarks directly and report the provider output shape if it remains malformed.",
126
+ };
127
+ if (!value.every(isBookmark))
128
+ return {
129
+ state: "unavailable",
130
+ reason: "list_bookmarks returned malformed entries; expected address and name strings.",
131
+ remediation: "Retry list_bookmarks directly and report the provider output shape if it remains malformed.",
132
+ };
133
+ return {
134
+ state: "available",
135
+ value: value.filter((bookmark) => bookmark.address === address),
136
+ };
137
+ };
138
+ const isBookmark = (value) => typeof value === "object" &&
139
+ value !== null &&
140
+ !Array.isArray(value) &&
141
+ typeof value.address === "string" &&
142
+ typeof value.name === "string";
@@ -1,7 +1,7 @@
1
1
  import { EvidenceIntegrityError, NoBinaryOpenError, } from "../domain/errors.js";
2
2
  import { err, ok } from "../domain/result.js";
3
3
  import { analysisQueryId, createAnalysisSnapshotEntry, snapshotBinding, snapshotMatchesProfile, snapshotMatchesTarget, snapshotTarget, } from "../domain/analysisSnapshot.js";
4
- import { OFFICIAL_TOOL_CONTRACTS } from "../contracts/toolContracts.js";
4
+ import { GENERATED_MCP_TOOL_CATALOG } from "../generatedMcpToolCatalog.js";
5
5
  const STATEFUL_OPERATIONS = new Set([
6
6
  "health",
7
7
  "current_address",
@@ -19,7 +19,9 @@ const CURSOR_DEFAULT_OPERATIONS = new Set([
19
19
  "prev_address",
20
20
  "xrefs",
21
21
  ]);
22
- const DOCUMENT_SCOPED_OPERATIONS = new Set(OFFICIAL_TOOL_CONTRACTS.map(({ name }) => name).filter((name) => name !== "current_document" &&
22
+ const DOCUMENT_SCOPED_OPERATIONS = new Set(GENERATED_MCP_TOOL_CATALOG.filter(({ kind }) => kind === "official-proxy")
23
+ .map(({ name }) => name)
24
+ .filter((name) => name !== "current_document" &&
23
25
  name !== "list_documents" &&
24
26
  name !== "set_current_document"));
25
27
  /** Whether an operation is immutable and independent of provider UI state. */
@@ -36,7 +36,7 @@ export const resolveTraceApplicationFeatureRequest = (input, lookup) => {
36
36
  };
37
37
  /** Resolve a trace request already parsed by the caller-facing contract. */
38
38
  export const resolveTraceApplicationFeatureRequestValidated = (input, lookup) => {
39
- const application = graphEvidence(input.application, input.application_evidence_id, lookup);
39
+ const application = graphEvidence(input, lookup);
40
40
  if (!application.ok)
41
41
  return application;
42
42
  const native = resolveEvidenceReferences(lookup, input.native_observation_evidence_ids);
@@ -63,7 +63,7 @@ export const resolveTraceJavaScriptSemanticsRequest = (input, lookup) => {
63
63
  };
64
64
  /** Resolve a semantic trace request already parsed by its public contract. */
65
65
  export const resolveTraceJavaScriptSemanticsRequestValidated = (input, lookup) => {
66
- const application = graphEvidence(input.application, input.application_evidence_id, lookup);
66
+ const application = graphEvidence(input, lookup);
67
67
  if (!application.ok)
68
68
  return application;
69
69
  const raw = { application: application.value, query: input.query };
@@ -81,10 +81,14 @@ export const resolveCompareApplicationVersionsRequest = (input, lookup) => {
81
81
  };
82
82
  /** Resolve a comparison request parsed by the caller-facing contract. */
83
83
  export const resolveCompareApplicationVersionsRequestValidated = (input, lookup) => {
84
- const left = graphEvidence(input.left, input.left_evidence_id, lookup);
84
+ const left = graphEvidence("left" in input
85
+ ? { application: input.left }
86
+ : { application_evidence_id: input.left_evidence_id }, lookup);
85
87
  if (!left.ok)
86
88
  return left;
87
- const right = graphEvidence(input.right, input.right_evidence_id, lookup);
89
+ const right = graphEvidence("right" in input
90
+ ? { application: input.right }
91
+ : { application_evidence_id: input.right_evidence_id }, lookup);
88
92
  if (!right.ok)
89
93
  return right;
90
94
  const leftNative = resolveEvidenceReferences(lookup, input.left_native_observation_evidence_ids);
@@ -123,7 +127,7 @@ export const resolveCompareSourceToBundleRequest = (input, lookup) => {
123
127
  };
124
128
  /** Resolve a historical-source comparison request parsed by its public contract. */
125
129
  export const resolveCompareSourceToBundleRequestValidated = (input, lookup) => {
126
- const application = graphEvidence(input.application, input.application_evidence_id, lookup);
130
+ const application = graphEvidence(input, lookup);
127
131
  if (!application.ok)
128
132
  return application;
129
133
  const raw = {
@@ -148,10 +152,14 @@ export const resolveCompareJavaScriptExportShapesRequest = (input, lookup) => {
148
152
  };
149
153
  /** Resolve an export-shape request already parsed by the adapter contract. */
150
154
  export const resolveCompareJavaScriptExportShapesRequestValidated = (input, lookup) => {
151
- const left = graphEvidence(input.left, input.left_evidence_id, lookup);
155
+ const left = graphEvidence("left" in input
156
+ ? { application: input.left }
157
+ : { application_evidence_id: input.left_evidence_id }, lookup);
152
158
  if (!left.ok)
153
159
  return left;
154
- const right = graphEvidence(input.right, input.right_evidence_id, lookup);
160
+ const right = graphEvidence("right" in input
161
+ ? { application: input.right }
162
+ : { application_evidence_id: input.right_evidence_id }, lookup);
155
163
  if (!right.ok)
156
164
  return right;
157
165
  const raw = {
@@ -171,10 +179,10 @@ export const resolveCompareJavaScriptExportShapesRequestValidated = (input, look
171
179
  ? ok(parsed.data)
172
180
  : invalid("compare_javascript_export_shapes", parsed.error, raw);
173
181
  };
174
- const graphEvidence = (evidence, evidenceId, lookup) => {
175
- if (evidence !== undefined)
176
- return ok(evidence);
177
- const resolved = resolveEvidenceReferences(lookup, evidenceId === undefined ? [] : [evidenceId], APPLICATION_GRAPH_IDENTITIES);
182
+ const graphEvidence = (source, lookup) => {
183
+ if ("application" in source)
184
+ return ok(source.application);
185
+ const resolved = resolveEvidenceReferences(lookup, [source.application_evidence_id], APPLICATION_GRAPH_IDENTITIES);
178
186
  return resolved.ok ? ok(resolved.value[0]) : resolved;
179
187
  };
180
188
  const invalid = (operation, cause, input) => err(new AnalysisInputError(operation, undefined, projectInputIssues(cause.issues, input)));
@@ -0,0 +1,17 @@
1
+ import { ArtifactReaderFailure } from "../../artifacts/ArtifactReader.js";
2
+ /** Resolve caller approval and operator policy before native reader selection. */
3
+ export const resolveNativeMountPolicy = (approved, enabled) => {
4
+ if (!approved)
5
+ return { status: "disabled" };
6
+ if (!enabled)
7
+ throw new ArtifactReaderFailure("unavailable", "Native DMG mounting is disabled by operator policy");
8
+ return { status: "approved" };
9
+ };
10
+ /** Resolve parsed caller intent and operator policy before artifact scanning. */
11
+ export const resolveArtifactIntegrityPolicy = (intent, enabled) => {
12
+ if (intent.mode === "fail")
13
+ return intent;
14
+ if (!enabled)
15
+ throw new ArtifactReaderFailure("policy", "Integrity continuation requires explicit approval and operator policy");
16
+ return intent;
17
+ };
@@ -1,5 +1,4 @@
1
1
  import { AsarArtifactReader } from "../../artifacts/AsarArtifactReader.js";
2
- import { ArtifactReaderFailure, } from "../../artifacts/ArtifactReader.js";
3
2
  import { DirectoryArtifactReader } from "../../artifacts/DirectoryArtifactReader.js";
4
3
  import { MachOSliceArtifactReader } from "../../artifacts/MachOSliceArtifactReader.js";
5
4
  import { NativeDmgArtifactReader } from "../../artifacts/NativeDmgArtifactReader.js";
@@ -21,10 +20,8 @@ export const createReader = async (path, format, nativeMount, signal) => {
21
20
  ? new MachOSliceArtifactReader(path)
22
21
  : undefined;
23
22
  case "dmg":
24
- if (!nativeMount.nativeMountApproved)
23
+ if (nativeMount.status === "disabled")
25
24
  return undefined;
26
- if (!nativeMount.nativeMountEnabled)
27
- throw new ArtifactReaderFailure("unavailable", "Native DMG mounting is disabled by operator policy");
28
25
  return NativeDmgArtifactReader.create(path, signal);
29
26
  default:
30
27
  return undefined;
@@ -10,9 +10,6 @@ import { scanReader, } from "./scanReader.js";
10
10
  import { NATIVE_MOUNT_DISABLED, STRICT_INTEGRITY_POLICY, } from "./types.js";
11
11
  export const scanCanonicalArtifactInventory = async (path, limits, options = {}) => {
12
12
  const integrity = options.integrity ?? STRICT_INTEGRITY_POLICY;
13
- if (integrity.mode === "record-and-continue" &&
14
- (!integrity.approved || !integrity.enabled))
15
- throw new ArtifactReaderFailure("unavailable", "Integrity continuation requires explicit approval and operator policy");
16
13
  const metadata = await lstat(path);
17
14
  const rootFormat = await classifyRoot(path, metadata.isDirectory());
18
15
  const rootDigest = metadata.isDirectory()
@@ -69,14 +69,14 @@ const digestArtifactEntry = async (context, currentReader, entry, logicalPath) =
69
69
  const digest = await hashReadable(await currentReader.open(entry, context.signal), Math.min(context.limits.maxEntryBytes, remainingBytes), context.signal);
70
70
  context.totalBytes += digest.bytes;
71
71
  const mismatched = entry.declaredSha256 !== null && entry.declaredSha256 !== digest.sha256;
72
- if (mismatched && context.integrity.mode === "fail")
73
- throw new ArtifactReaderFailure("integrity", `Artifact integrity metadata disagrees with content: ${logicalPath}`, undefined, {
74
- logicalPath,
75
- declaredSha256: entry.declaredSha256,
76
- calculatedSha256: digest.sha256,
77
- unpacked: entry.unpacked,
78
- });
79
72
  if (mismatched && entry.declaredSha256 !== null) {
73
+ if (context.integrity.mode === "fail")
74
+ throw new ArtifactReaderFailure("integrity", `Artifact integrity metadata disagrees with content: ${logicalPath}`, undefined, {
75
+ logicalPath,
76
+ declaredSha256: entry.declaredSha256,
77
+ calculatedSha256: digest.sha256,
78
+ unpacked: entry.unpacked,
79
+ });
80
80
  if (context.pendingContradictions.length >= context.integrity.maxMismatches)
81
81
  throw new ArtifactReaderFailure("limit", "Artifact integrity mismatch limit exceeded");
82
82
  context.pendingContradictions.push({
@@ -1,10 +1,6 @@
1
1
  export const NATIVE_MOUNT_DISABLED = {
2
- nativeMountApproved: false,
3
- nativeMountEnabled: false,
2
+ status: "disabled",
4
3
  };
5
4
  export const STRICT_INTEGRITY_POLICY = {
6
5
  mode: "fail",
7
- approved: false,
8
- enabled: false,
9
- maxMismatches: 1,
10
6
  };
@@ -2,15 +2,15 @@ import { randomUUID } from "node:crypto";
2
2
  import { analysisProfilesEqual, } from "../domain/analysisProfile.js";
3
3
  import { AnalysisCancelledError, ProviderAdapterError, } from "../domain/errors.js";
4
4
  import { err, ok } from "../domain/result.js";
5
- import { enhancedToolNameSchema } from "../contracts/enhancedInputs.js";
6
- import { OFFICIAL_TOOL_CONTRACTS } from "../contracts/toolContracts.js";
5
+ import { GENERATED_MCP_TOOL_CATALOG } from "../generatedMcpToolCatalog.js";
7
6
  import { SessionProviderRouter, } from "./SessionProviderRouter.js";
8
7
  import { BinarySessionRecords } from "./BinarySessionRecords.js";
9
8
  import { binarySessionStatus } from "./BinarySessionStatus.js";
10
9
  import { resolveSessionOpen, } from "./BinarySessionOpen.js";
11
10
  import { prepareSessionExecution } from "./BinarySessionExecution.js";
12
11
  import { closeAnalysisClient } from "./AnalysisClientCleanup.js";
13
- const OFFICIAL_OPERATIONS = new Set(OFFICIAL_TOOL_CONTRACTS.map(({ name }) => name));
12
+ const OFFICIAL_OPERATIONS = new Set(GENERATED_MCP_TOOL_CATALOG.filter(({ kind }) => kind === "official-proxy").map(({ name }) => name));
13
+ const ENHANCED_OPERATIONS = new Set(GENERATED_MCP_TOOL_CATALOG.filter(({ kind }) => kind === "enhanced").map(({ name }) => name));
14
14
  /**
15
15
  * Owns the single active target shared by CLI and MCP adapters.
16
16
  *
@@ -24,7 +24,7 @@ export class BinarySession extends BinarySessionRecords {
24
24
  #transition = Promise.resolve();
25
25
  #calls = new Set();
26
26
  #providerRouter;
27
- #runtimeAvailability = new Map();
27
+ #runtimeUnavailability = new Map();
28
28
  #availabilityListeners = new Set();
29
29
  constructor(provider, options = {}) {
30
30
  super();
@@ -42,7 +42,7 @@ export class BinarySession extends BinarySessionRecords {
42
42
  const exact = route.capabilities?.get(operation)?.provider;
43
43
  if (exact !== undefined)
44
44
  selected = exact;
45
- else if (enhancedToolNameSchema.safeParse(operation).success) {
45
+ else if (ENHANCED_OPERATIONS.has(operation)) {
46
46
  const providers = new Map();
47
47
  for (const descriptor of route.capabilities?.values() ?? [])
48
48
  if (descriptor.available &&
@@ -112,6 +112,7 @@ export class BinarySession extends BinarySessionRecords {
112
112
  if (!imported.ok)
113
113
  return imported;
114
114
  }
115
+ this.resetSnapshotInvalidation();
115
116
  return ok(target);
116
117
  }
117
118
  await this.#drainCalls();
@@ -184,7 +185,7 @@ export class BinarySession extends BinarySessionRecords {
184
185
  target: this.#active?.target,
185
186
  route: this.#currentRoute(),
186
187
  router: this.#providerRouter,
187
- runtimeAvailability: this.#runtimeAvailability,
188
+ runtimeUnavailability: this.#runtimeUnavailability,
188
189
  runId: this.#active?.runId,
189
190
  runtimeLineageSnapshots: this.#active?.client.runtimeLineageSnapshots?.() ?? [],
190
191
  requestActivitySnapshots: this.#active?.client.requestActivitySnapshots?.() ?? [],
@@ -245,12 +246,12 @@ export class BinarySession extends BinarySessionRecords {
245
246
  }
246
247
  #observeRuntimeAvailability(operation, result) {
247
248
  if (result.ok) {
248
- if (this.#setRuntimeAvailability(operation, true, null))
249
+ if (this.#markRuntimeAvailable(operation))
249
250
  this.#emitAvailabilityChanged();
250
251
  return;
251
252
  }
252
253
  if (result.error._tag === "AnalysisCapabilityUnavailableError") {
253
- if (this.#setRuntimeAvailability(operation, false, result.error.message))
254
+ if (this.#markRuntimeUnavailable(operation, result.error.message))
254
255
  this.#emitAvailabilityChanged();
255
256
  return;
256
257
  }
@@ -266,27 +267,25 @@ export class BinarySession extends BinarySessionRecords {
266
267
  for (const descriptor of capabilities?.values() ?? [])
267
268
  if (providerId !== undefined && descriptor.provider.id === providerId)
268
269
  changed =
269
- this.#setRuntimeAvailability(descriptor.operation, false, "Provider became unavailable during this session.") || changed;
270
+ this.#markRuntimeUnavailable(descriptor.operation, "Provider became unavailable during this session.") || changed;
270
271
  if (changed)
271
272
  this.#emitAvailabilityChanged();
272
273
  }
273
274
  }
274
- #setRuntimeAvailability(operation, available, reason) {
275
- const current = this.#runtimeAvailability.get(operation);
276
- if (current?.available === available && current.reason === reason)
277
- return false;
278
- if (available && current === undefined)
275
+ #markRuntimeAvailable(operation) {
276
+ return this.#runtimeUnavailability.delete(operation);
277
+ }
278
+ #markRuntimeUnavailable(operation, reason) {
279
+ const current = this.#runtimeUnavailability.get(operation);
280
+ if (current?.reason === reason)
279
281
  return false;
280
- if (available)
281
- this.#runtimeAvailability.delete(operation);
282
- else
283
- this.#runtimeAvailability.set(operation, { available, reason });
282
+ this.#runtimeUnavailability.set(operation, { reason });
284
283
  return true;
285
284
  }
286
285
  #clearRuntimeAvailability() {
287
- if (this.#runtimeAvailability.size === 0)
286
+ if (this.#runtimeUnavailability.size === 0)
288
287
  return;
289
- this.#runtimeAvailability.clear();
288
+ this.#runtimeUnavailability.clear();
290
289
  this.#emitAvailabilityChanged();
291
290
  }
292
291
  #emitAvailabilityChanged() {
@@ -0,0 +1,21 @@
1
+ import { AnalysisProviderRegistry } from "./AnalysisProviderRegistry.js";
2
+ import { BinarySession } from "./BinarySession.js";
3
+ import { SessionProviderRouter } from "./SessionProviderRouter.js";
4
+ const normalizeBinarySessionOptions = (optionsOrResolver) => typeof optionsOrResolver === "function"
5
+ ? { resolveAnalysisProfile: optionsOrResolver }
6
+ : (optionsOrResolver ?? {});
7
+ /**
8
+ * Compose one provider-neutral session from deep-provider selection and
9
+ * disjoint auxiliary operation families.
10
+ */
11
+ export const composeBinarySession = (registry, auxiliaryProviders = []) => new BinarySession(registry instanceof SessionProviderRouter
12
+ ? registry
13
+ : SessionProviderRouter.selectable(registry, auxiliaryProviders));
14
+ /**
15
+ * Compose a session through the same internal seam for focused adapter tests.
16
+ * The constructor remains private to this composition module, so callers test
17
+ * provider behavior without coupling to BinarySession construction.
18
+ */
19
+ export const composeBinarySessionFromFactory = (provider, optionsOrResolver) => new BinarySession(provider, normalizeBinarySessionOptions(optionsOrResolver));
20
+ /** Compose a focused session from any provider-shaped test seam. */
21
+ export const composeBinarySessionFromProvider = (provider, optionsOrResolver) => new BinarySession(provider, normalizeBinarySessionOptions(optionsOrResolver));