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
@@ -1,9 +1,9 @@
1
1
  /** Generated from package.json and package-lock.json; do not edit. */
2
2
  export const PACKAGE_METADATA = {
3
3
  name: "rea-agents",
4
- version: "2.5.0", // x-release-please-version
5
- serverSdkVersion: "2.0.0-beta.4",
6
- clientSdkVersion: "2.0.0-beta.4",
7
- coreSdkVersion: "2.0.0-beta.4",
4
+ version: "3.1.0", // x-release-please-version
5
+ serverSdkVersion: "2.0.0",
6
+ clientSdkVersion: "2.0.0",
7
+ coreSdkVersion: "2.0.0",
8
8
  skillVersion: "23",
9
9
  };
@@ -369,7 +369,7 @@ export class GhidraClient {
369
369
  return err(failure);
370
370
  }
371
371
  #interruptionFailure(deadline) {
372
- return deadline.cancelled
372
+ return deadline.interruption === "cancelled"
373
373
  ? this.#failure("cancelled", "Ghidra startup was cancelled")
374
374
  : this.#failure("timeout", "Ghidra startup deadline elapsed", undefined, {
375
375
  timeoutMs: deadline.timeoutMs,
@@ -22,7 +22,7 @@ export async function completeGhidraStartupHandshake(options) {
22
22
  }
23
23
  return parsed;
24
24
  }
25
- const interruptionFailure = (options) => options.deadline.cancelled
25
+ const interruptionFailure = (options) => options.deadline.interruption === "cancelled"
26
26
  ? options.failure("cancelled", "Ghidra startup was cancelled")
27
27
  : options.failure("timeout", "Ghidra startup deadline elapsed", undefined, {
28
28
  timeoutMs: options.startupTimeoutMs,
@@ -17,4 +17,4 @@ export const GHIDRA_MAX_QUEUED_REQUESTS = 32;
17
17
  /** Maximum encoded response line accepted from the Java bridge. */
18
18
  export const GHIDRA_MAX_LINE_BYTES = 1024 * 1024;
19
19
  /** Version of REA's Java bridge handshake and request protocol. */
20
- export const GHIDRA_BRIDGE_VERSION = 5;
20
+ export const GHIDRA_BRIDGE_VERSION = 6;
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { AnalysisInputError, AnalysisOutputError } from "../domain/errors.js";
3
3
  import { functionInstructionWindowSchema, functionDossierSchema, } from "../domain/hopperValues.js";
4
- import { jsonObjectSchema, jsonValueSchema, } from "../domain/jsonValue.js";
4
+ import { nativeApiBoundarySchema } from "../domain/nativeApiBoundary.js";
5
5
  import { err, ok } from "../domain/result.js";
6
6
  import { ghidraBoundedIdentifierSchema, ghidraCanonicalAddressSchema, } from "./GhidraInventoryValues.js";
7
7
  /** Read-only function operations admitted by the Ghidra adapter. */
@@ -89,7 +89,7 @@ const inputSchemas = {
89
89
  export const parseGhidraFunctionInput = (operation, value) => {
90
90
  const parsed = inputSchemas[operation].safeParse(value);
91
91
  return parsed.success
92
- ? ok(jsonObjectSchema.parse(parsed.data))
92
+ ? ok(parsed.data)
93
93
  : err(new AnalysisInputError(operation, { cause: parsed.error }));
94
94
  };
95
95
  const classification = z
@@ -142,15 +142,24 @@ const referenceEdge = z
142
142
  kind: referenceKind,
143
143
  })
144
144
  .strict();
145
- const boundedReferences = z
146
- .object({
145
+ const boundedReferenceFacts = {
147
146
  items: z.array(referenceEdge),
148
147
  total: z.number().int().min(0).nullable(),
149
148
  returned: z.number().int().min(0),
150
- truncated: z.boolean(),
151
- next_offset: z.number().int().min(0).nullable(),
152
- })
153
- .strict()
149
+ };
150
+ const boundedReferences = z
151
+ .discriminatedUnion("truncated", [
152
+ z.strictObject({
153
+ ...boundedReferenceFacts,
154
+ truncated: z.literal(false),
155
+ next_offset: z.null(),
156
+ }),
157
+ z.strictObject({
158
+ ...boundedReferenceFacts,
159
+ truncated: z.literal(true),
160
+ next_offset: z.number().int().min(0).nullable(),
161
+ }),
162
+ ])
154
163
  .superRefine((value, context) => {
155
164
  if (value.returned !== value.items.length)
156
165
  context.addIssue({
@@ -164,12 +173,6 @@ const boundedReferences = z
164
173
  path: ["total"],
165
174
  message: "total cannot be smaller than returned",
166
175
  });
167
- if (value.next_offset !== null && !value.truncated)
168
- context.addIssue({
169
- code: "custom",
170
- path: ["next_offset"],
171
- message: "a continuation requires truncated output",
172
- });
173
176
  });
174
177
  const procedureReferences = z
175
178
  .object({
@@ -191,7 +194,32 @@ const procedureInfo = z
191
194
  classification,
192
195
  })
193
196
  .strict();
194
- const ghidraFunctionDossier = functionDossierSchema.superRefine((value, context) => {
197
+ const ghidraNativeApiBoundary = nativeApiBoundarySchema.superRefine((value, context) => {
198
+ if (!value.available)
199
+ return;
200
+ if (value.provenance !== "ghidra-high-function")
201
+ context.addIssue({
202
+ code: "custom",
203
+ message: "Ghidra native API observations require HighFunction provenance",
204
+ });
205
+ const addresses = value.jump_tables.flatMap((table) => [
206
+ table.dispatch_address,
207
+ ...table.data_sources.map(({ address }) => address),
208
+ ...table.mappings.flatMap(({ target_address, data_addresses }) => [
209
+ target_address,
210
+ ...data_addresses,
211
+ ]),
212
+ ]);
213
+ if (addresses.some((address) => !ghidraCanonicalAddressSchema.safeParse(address).success))
214
+ context.addIssue({
215
+ code: "custom",
216
+ message: "Ghidra native API observation contains a non-canonical address",
217
+ });
218
+ });
219
+ const ghidraFunctionDossier = functionDossierSchema
220
+ .extend({ native_api: ghidraNativeApiBoundary })
221
+ .strict()
222
+ .superRefine((value, context) => {
195
223
  const addresses = [
196
224
  value.procedure.address,
197
225
  ...value.comments.items.map(({ address }) => address),
@@ -261,7 +289,7 @@ const resultSchemas = {
261
289
  export const parseGhidraFunctionResult = (operation, value) => {
262
290
  const parsed = resultSchemas[operation].safeParse(value);
263
291
  return parsed.success
264
- ? ok(jsonValueSchema.parse(parsed.data))
292
+ ? ok(parsed.data)
265
293
  : err(new AnalysisOutputError(operation, "Ghidra bridge output did not match the function-analysis contract", { cause: parsed.error }));
266
294
  };
267
295
  const referenceAddresses = (edge) => [
@@ -1,6 +1,5 @@
1
1
  import { z } from "zod";
2
2
  import { AnalysisInputError, AnalysisOutputError } from "../domain/errors.js";
3
- import { jsonObjectSchema, jsonValueSchema, } from "../domain/jsonValue.js";
4
3
  import { err, ok } from "../domain/result.js";
5
4
  /** Read-only direct operations admitted by the Ghidra v1 adapter. */
6
5
  export const GHIDRA_INVENTORY_OPERATIONS = [
@@ -60,7 +59,7 @@ export const parseGhidraInventoryInput = (operation, value) => {
60
59
  const parsed = inputSchemas[operation].safeParse(value);
61
60
  if (!parsed.success)
62
61
  return err(new AnalysisInputError(operation, { cause: parsed.error }));
63
- return ok(jsonObjectSchema.parse(parsed.data));
62
+ return ok(parsed.data);
64
63
  };
65
64
  export const ghidraCanonicalAddressSchema = z
66
65
  .string()
@@ -104,50 +103,61 @@ const procedureItem = z
104
103
  .strict();
105
104
  const stringItem = z.object({ ...baseItem, string: stringFacts }).strict();
106
105
  const searchItem = z.object(baseItem).strict();
107
- const pageSchema = (item, maximumLimit) => z
108
- .object({
109
- items: z.array(item),
110
- offset: z.number().int().min(0),
111
- limit: z.number().int().min(1).max(maximumLimit),
112
- total: z.number().int().min(0),
113
- next_offset: z.number().int().min(0).nullable(),
114
- has_more: z.boolean(),
115
- })
116
- .strict()
117
- .superRefine((page, context) => {
118
- const next = page.offset + page.items.length;
119
- const hasMore = next < page.total;
120
- if (page.items.length > page.limit)
121
- context.addIssue({
122
- code: "custom",
123
- path: ["items"],
124
- message: "page exceeds its declared limit",
125
- });
126
- if (page.items.length > 0 && next > page.total)
127
- context.addIssue({
128
- code: "custom",
129
- path: ["total"],
130
- message: "page items exceed its exact total",
131
- });
132
- if (hasMore && page.items.length === 0)
133
- context.addIssue({
134
- code: "custom",
135
- path: ["items"],
136
- message: "page continuation must advance its offset",
137
- });
138
- if (page.has_more !== hasMore)
139
- context.addIssue({
140
- code: "custom",
141
- path: ["has_more"],
142
- message: "page continuation does not match its exact total",
143
- });
144
- if (page.next_offset !== (hasMore ? next : null))
145
- context.addIssue({
146
- code: "custom",
147
- path: ["next_offset"],
148
- message: "page continuation offset is inconsistent",
149
- });
150
- });
106
+ const pageSchema = (item, maximumLimit) => {
107
+ const pageFacts = {
108
+ items: z.array(item),
109
+ offset: z.number().int().min(0),
110
+ limit: z.number().int().min(1).max(maximumLimit),
111
+ total: z.number().int().min(0),
112
+ };
113
+ return z
114
+ .discriminatedUnion("has_more", [
115
+ z.strictObject({
116
+ ...pageFacts,
117
+ has_more: z.literal(true),
118
+ next_offset: z.number().int().min(0),
119
+ }),
120
+ z.strictObject({
121
+ ...pageFacts,
122
+ has_more: z.literal(false),
123
+ next_offset: z.null(),
124
+ }),
125
+ ])
126
+ .superRefine((page, context) => {
127
+ const next = page.offset + page.items.length;
128
+ const hasMore = next < page.total;
129
+ if (page.items.length > page.limit)
130
+ context.addIssue({
131
+ code: "custom",
132
+ path: ["items"],
133
+ message: "page exceeds its declared limit",
134
+ });
135
+ if (page.items.length > 0 && next > page.total)
136
+ context.addIssue({
137
+ code: "custom",
138
+ path: ["total"],
139
+ message: "page items exceed its exact total",
140
+ });
141
+ if (hasMore && page.items.length === 0)
142
+ context.addIssue({
143
+ code: "custom",
144
+ path: ["items"],
145
+ message: "page continuation must advance its offset",
146
+ });
147
+ if (page.has_more !== hasMore)
148
+ context.addIssue({
149
+ code: "custom",
150
+ path: ["has_more"],
151
+ message: "page continuation does not match its exact total",
152
+ });
153
+ if (page.next_offset !== (hasMore ? next : null))
154
+ context.addIssue({
155
+ code: "custom",
156
+ path: ["next_offset"],
157
+ message: "page continuation offset is inconsistent",
158
+ });
159
+ });
160
+ };
151
161
  const availablePermissions = z
152
162
  .object({
153
163
  available: z.literal(true),
@@ -212,6 +222,6 @@ const resultSchemas = {
212
222
  export const parseGhidraInventoryResult = (operation, value) => {
213
223
  const parsed = resultSchemas[operation].safeParse(value);
214
224
  return parsed.success
215
- ? ok(jsonValueSchema.parse(parsed.data))
225
+ ? ok(parsed.data)
216
226
  : err(new AnalysisOutputError(operation, "Ghidra bridge output did not match the inventory contract", { cause: parsed.error }));
217
227
  };
@@ -1,5 +1,6 @@
1
1
  import { fileURLToPath } from "node:url";
2
2
  import { createAnalysisExecution, } from "../application/AnalysisProvider.js";
3
+ import { jsonObjectSchema } from "../domain/jsonValue.js";
3
4
  import { AnalysisCancelledError, AnalysisCapabilityUnavailableError, AnalysisInputError, AnalysisTimeoutError, ProviderAdapterError, } from "../domain/errors.js";
4
5
  import { err, ok } from "../domain/result.js";
5
6
  import { GhidraClient } from "./GhidraClient.js";
@@ -10,9 +11,9 @@ import { ghidraInstallationDiagnostics, inspectGhidraInstallation, } from "./Ghi
10
11
  import { GhidraHeadlessLauncher } from "./GhidraLauncher.js";
11
12
  import { resolveGhidraAnalysisProfile } from "./GhidraAnalysisProfile.js";
12
13
  import { CAPABILITIES, WINDOWS_P0_CAPABILITIES, GHIDRA_PROVIDER_IDENTITY, GHIDRA_PROVIDER_TOOL_CONTRACTS, healthLimitations, windowsP0Limitations, limitationsFor, } from "./GhidraProviderCapabilities.js";
14
+ import { WINDOWS_NATIVE_AUTHORITY_UNAVAILABLE_REASON, hasWindowsNativeAuthority, windowsNativeCapabilities, } from "../process/WindowsAuthority.js";
13
15
  export { GHIDRA_PROVIDER_IDENTITY, GHIDRA_PROVIDER_TOOL_CONTRACTS };
14
16
  const SUPPORTED_ARCHITECTURES = new Set(["x86", "x86_64", "arm", "arm64"]);
15
- const SUPPORTED_FORMATS = new Set(["elf", "pe", "mach-o"]);
16
17
  /** Ghidra candidate backed by an isolated read-only headless import. */
17
18
  export class GhidraProvider {
18
19
  config;
@@ -37,6 +38,18 @@ export class GhidraProvider {
37
38
  inspectAvailability() {
38
39
  const installation = this.#inspectInstallation();
39
40
  const diagnostics = ghidraInstallationDiagnostics(installation);
41
+ if (installation.available &&
42
+ installation.platform === "win32" &&
43
+ !hasWindowsNativeAuthority(installation.platform))
44
+ return {
45
+ status: "unavailable",
46
+ code: "unsupported_host",
47
+ reason: WINDOWS_NATIVE_AUTHORITY_UNAVAILABLE_REASON,
48
+ diagnostics: {
49
+ ...diagnostics,
50
+ windows_security: jsonObjectSchema.parse(windowsNativeCapabilities(installation.platform)),
51
+ },
52
+ };
40
53
  return installation.available
41
54
  ? {
42
55
  status: "available",
@@ -70,15 +83,7 @@ export class GhidraProvider {
70
83
  };
71
84
  if (hostPlatform === "win32")
72
85
  return inspectWindowsP0TargetSupport(target, diagnostics);
73
- if (!SUPPORTED_FORMATS.has(target.format))
74
- return {
75
- status: "unsupported",
76
- code: "target_format_unsupported",
77
- reason: `Ghidra v1 does not import ${target.format} through this adapter.`,
78
- diagnostics,
79
- };
80
- if (target.architecture === undefined ||
81
- !SUPPORTED_ARCHITECTURES.has(target.architecture))
86
+ if (!SUPPORTED_ARCHITECTURES.has(target.architecture))
82
87
  return {
83
88
  status: "unsupported",
84
89
  code: "architecture_unsupported",
@@ -237,6 +242,9 @@ const ghidraClientPrerequisites = (target, profile, installation) => {
237
242
  return err(new ProviderAdapterError("ghidra", "health", {
238
243
  diagnostics: ghidraInstallationDiagnostics(installation),
239
244
  }));
245
+ if (installation.platform === "win32" &&
246
+ !hasWindowsNativeAuthority(installation.platform))
247
+ return err(new AnalysisCapabilityUnavailableError("ghidra", "health", WINDOWS_NATIVE_AUTHORITY_UNAVAILABLE_REASON));
240
248
  if (profile === undefined || profile.provider.id !== "ghidra")
241
249
  return err(new ProviderAdapterError("ghidra", "health"));
242
250
  return ok({
@@ -1,4 +1,5 @@
1
- import { ENHANCED_TOOL_CONTRACTS, OFFICIAL_TOOL_CONTRACTS, } from "../contracts/toolContracts.js";
1
+ import { WINDOWS_NATIVE_AUTHORITY_UNAVAILABLE_REASON } from "../process/WindowsAuthority.js";
2
+ import { GENERATED_MCP_TOOL_CATALOG } from "../generatedMcpToolCatalog.js";
2
3
  import { GHIDRA_DECOMPILE_REQUEST_TIMEOUT_MS, GHIDRA_MAX_LINE_BYTES, GHIDRA_REQUEST_TIMEOUT_MS, } from "./GhidraDefaults.js";
3
4
  import { GHIDRA_FUNCTION_OPERATIONS } from "./GhidraFunctionValues.js";
4
5
  import { GHIDRA_INVENTORY_OPERATIONS } from "./GhidraInventoryValues.js";
@@ -8,10 +9,7 @@ export const GHIDRA_PROVIDER_IDENTITY = Object.freeze({
8
9
  name: "Ghidra",
9
10
  version: null,
10
11
  });
11
- const providerContractByName = new Map([...OFFICIAL_TOOL_CONTRACTS, ...ENHANCED_TOOL_CONTRACTS].map((contract) => [
12
- contract.name,
13
- contract,
14
- ]));
12
+ const providerContractByName = new Map(GENERATED_MCP_TOOL_CATALOG.filter(({ kind }) => kind === "official-proxy" || kind === "enhanced").map((contract) => [contract.name, contract]));
15
13
  /** Provider-neutral read-only contracts implemented by the Ghidra adapter. */
16
14
  export const GHIDRA_PROVIDER_TOOL_CONTRACTS = Object.freeze([...GHIDRA_INVENTORY_OPERATIONS, ...GHIDRA_FUNCTION_OPERATIONS].map((operation) => {
17
15
  const contract = providerContractByName.get(operation);
@@ -46,7 +44,7 @@ export const healthLimitations = Object.freeze([
46
44
  export const windowsP0Limitations = Object.freeze([
47
45
  "Windows Ghidra P0 accepts approved native x86-64 PE applications only; DLL, managed, hostile, sensitive, and mutable-path targets are unsupported.",
48
46
  "The Windows bridge uses authenticated IPv4 loopback because Node path-based IPC does not expose Java AF_UNIX sockets; the endpoint file contains no bearer token.",
49
- "Windows P0 process-tree cleanup uses bounded taskkill termination and does not claim Job Object ownership, private DACL enforcement, or reparse-point-safe path authority.",
47
+ "Windows P0 is not admitted until a native authority proves Job Object ownership, private DACL enforcement, and reparse-safe path admission; bounded taskkill cleanup and chmod(0700) do not prove those controls.",
50
48
  ]);
51
49
  /** Limitation text for one admitted operation, including the common base. */
52
50
  export const limitationsFor = (operation) => {
@@ -137,42 +135,50 @@ export const limitationsFor = (operation) => {
137
135
  }
138
136
  };
139
137
  /** Provider-neutral capabilities advertised by every non-Windows Ghidra session. */
140
- export const CAPABILITIES = Object.freeze(GHIDRA_PROVIDER_TOOL_CONTRACTS.map((contract) => Object.freeze({
141
- provider: GHIDRA_PROVIDER_IDENTITY,
142
- operation: contract.name,
143
- inputContractVersion: 1,
144
- outputContractVersion: 1,
145
- available: true,
146
- reason: null,
147
- pagination: PAGINATED_OPERATIONS.has(contract.name)
148
- ? "offset"
149
- : "none",
150
- exhaustive: !PAGINATED_OPERATIONS.has(contract.name),
151
- effects: Object.freeze({
152
- mutatesArtifact: false,
153
- launchesProcess: true,
154
- mayShowUi: false,
155
- mayAccessNetwork: false,
156
- mayWriteFilesystem: true,
157
- changesPermissions: false,
158
- requiresRoot: false,
159
- }),
160
- limits: Object.freeze({
161
- maxResults: PAGINATED_OPERATIONS.has(contract.name)
162
- ? SEARCH_OPERATIONS.has(contract.name)
163
- ? 100
164
- : 500
165
- : null,
166
- maxPayloadBytes: GHIDRA_MAX_LINE_BYTES,
167
- timeoutMs: DECOMPILE_OPERATIONS.has(contract.name)
168
- ? GHIDRA_DECOMPILE_REQUEST_TIMEOUT_MS
169
- : GHIDRA_REQUEST_TIMEOUT_MS,
170
- }),
171
- limitations: Object.freeze(limitationsFor(contract.name)),
172
- })));
138
+ export const CAPABILITIES = Object.freeze(GHIDRA_PROVIDER_TOOL_CONTRACTS.map((contract) => {
139
+ const operation = contract.analysisOperation;
140
+ if (operation === null)
141
+ throw new TypeError(`Missing analysis operation for ${contract.name}`);
142
+ return Object.freeze({
143
+ provider: GHIDRA_PROVIDER_IDENTITY,
144
+ operation,
145
+ inputContractVersion: 1,
146
+ outputContractVersion: 1,
147
+ available: true,
148
+ reason: null,
149
+ pagination: PAGINATED_OPERATIONS.has(contract.name)
150
+ ? "offset"
151
+ : "none",
152
+ exhaustive: !PAGINATED_OPERATIONS.has(contract.name),
153
+ effects: Object.freeze({
154
+ mutatesArtifact: false,
155
+ launchesProcess: true,
156
+ mayShowUi: false,
157
+ mayAccessNetwork: false,
158
+ mayWriteFilesystem: true,
159
+ changesPermissions: false,
160
+ requiresRoot: false,
161
+ }),
162
+ limits: Object.freeze({
163
+ maxResults: PAGINATED_OPERATIONS.has(contract.name)
164
+ ? SEARCH_OPERATIONS.has(contract.name)
165
+ ? 100
166
+ : 500
167
+ : null,
168
+ maxPayloadBytes: GHIDRA_MAX_LINE_BYTES,
169
+ timeoutMs: DECOMPILE_OPERATIONS.has(contract.name)
170
+ ? GHIDRA_DECOMPILE_REQUEST_TIMEOUT_MS
171
+ : GHIDRA_REQUEST_TIMEOUT_MS,
172
+ }),
173
+ limitations: Object.freeze(limitationsFor(contract.name)),
174
+ });
175
+ }));
173
176
  /** Capabilities advertised for the experimental Windows x64 P0 boundary. */
174
177
  export const WINDOWS_P0_CAPABILITIES = Object.freeze(CAPABILITIES.map((capability) => Object.freeze({
175
178
  ...capability,
179
+ available: false,
180
+ reason: WINDOWS_NATIVE_AUTHORITY_UNAVAILABLE_REASON,
181
+ availabilityCode: "unsupported_host",
176
182
  limitations: Object.freeze([
177
183
  ...capability.limitations,
178
184
  ...windowsP0Limitations,
@@ -76,7 +76,7 @@ const connectGhidraSocketOnce = (target, signal) => new Promise((resolve) => {
76
76
  if (signal.aborted)
77
77
  onAbort();
78
78
  });
79
- const interruptionFailure = (options) => options.deadline.cancelled
79
+ const interruptionFailure = (options) => options.deadline.interruption === "cancelled"
80
80
  ? options.failure("cancelled", "Ghidra startup was cancelled")
81
81
  : options.failure("timeout", "Ghidra startup deadline elapsed", undefined, {
82
82
  timeoutMs: options.startupTimeoutMs,
@@ -1,46 +1,23 @@
1
1
  import { z } from "zod";
2
2
  import { jsonValueSchema } from "../domain/jsonValue.js";
3
3
  import { err, ok } from "../domain/result.js";
4
- const responseSchema = z
5
- .object({
6
- id: z.number().int().positive(),
7
- ok: z.boolean(),
8
- result: jsonValueSchema.optional(),
9
- error: z
10
- .object({
11
- code: z.string().min(1).max(128),
12
- message: z.string().min(1).max(4_096),
13
- })
14
- .strict()
15
- .optional(),
16
- })
17
- .strict()
18
- .superRefine((value, context) => {
19
- if (value.ok && value.result === undefined)
20
- context.addIssue({
21
- code: "custom",
22
- path: ["result"],
23
- message: "Successful Ghidra response requires a result",
24
- });
25
- if (!value.ok && value.error === undefined)
26
- context.addIssue({
27
- code: "custom",
28
- path: ["error"],
29
- message: "Failed Ghidra response requires an error",
30
- });
31
- if (!value.ok && value.result !== undefined)
32
- context.addIssue({
33
- code: "custom",
34
- path: ["result"],
35
- message: "Failed Ghidra response cannot include a result",
36
- });
37
- if (value.ok && value.error !== undefined)
38
- context.addIssue({
39
- code: "custom",
40
- path: ["error"],
41
- message: "Successful Ghidra response cannot include an error",
42
- });
43
- });
4
+ const responseSchema = z.discriminatedUnion("ok", [
5
+ z.strictObject({
6
+ id: z.number().int().positive(),
7
+ ok: z.literal(true),
8
+ result: jsonValueSchema,
9
+ }),
10
+ z.strictObject({
11
+ id: z.number().int().positive(),
12
+ ok: z.literal(false),
13
+ error: z
14
+ .object({
15
+ code: z.string().min(1).max(128),
16
+ message: z.string().min(1).max(4_096),
17
+ })
18
+ .strict(),
19
+ }),
20
+ ]);
44
21
  /** Expected operation failure returned by the authenticated Java bridge. */
45
22
  export class GhidraRemoteError extends Error {
46
23
  code;
@@ -65,5 +42,5 @@ export const parseGhidraResponseLine = (line) => {
65
42
  };
66
43
  /** Project one validated response into its result or remote failure. */
67
44
  export const ghidraResponseResult = (response) => response.ok
68
- ? ok(response.result ?? null)
69
- : err(new GhidraRemoteError(response.error?.code ?? "bridge_error", response.error?.message ?? "Ghidra bridge request failed"));
45
+ ? ok(response.result)
46
+ : err(new GhidraRemoteError(response.error.code, response.error.message));
@@ -99,7 +99,9 @@ export class HopperApplicationLauncher {
99
99
  process: child,
100
100
  ownsProcessLifetime: true,
101
101
  ownership: started.ownership,
102
- shutdownByCleanup: ownsProcessLifetime,
102
+ shutdownMode: ownsProcessLifetime
103
+ ? "process-cleanup"
104
+ : "bridge-request",
103
105
  cleanup: () => cleanupOwnedProcessGroup(started.ownership),
104
106
  });
105
107
  }
@@ -49,9 +49,9 @@ export const resolveHopperAnalysisProfile = async (target, options) => {
49
49
  export const hopperLoaderArgsForTarget = (target) => {
50
50
  if (target.kind === "database")
51
51
  return ok([]);
52
- const architecture = target.architecture;
53
- if (architecture === undefined)
52
+ if (target.kind !== "executable")
54
53
  return err(new ProviderAdapterError("hopper", "resolve_analysis_profile"));
54
+ const architecture = target.architecture;
55
55
  const flag = hopperArchitectureFlag(architecture);
56
56
  switch (target.format) {
57
57
  case "mach-o":
@@ -62,8 +62,6 @@ export const hopperLoaderArgsForTarget = (target) => {
62
62
  return ok(["-l", "ELF", flag]);
63
63
  case "pe":
64
64
  return ok(["-l", "WinPE", flag]);
65
- default:
66
- return err(new ProviderAdapterError("hopper", "resolve_analysis_profile"));
67
65
  }
68
66
  };
69
67
  const hopperArchitectureFlag = (architecture) => {
@@ -10,7 +10,6 @@ export const cleanupHopperSession = async (input) => {
10
10
  resources: new Set(),
11
11
  cleanupResult: undefined,
12
12
  shutdownConfirmed: false,
13
- ownedProcessStopped: false,
14
13
  };
15
14
  await report(input.progress, 0, "requesting Hopper document shutdown");
16
15
  await requestShutdown(input, state);
@@ -38,8 +37,7 @@ const requestShutdown = async (input, state) => {
38
37
  .catch(() => err(new HopperProcessError(null)));
39
38
  if (shutdown.ok &&
40
39
  isHopperCleanupRequired(shutdown.value) &&
41
- input.launch?.shutdownByCleanup === true &&
42
- input.launch.cleanup !== undefined) {
40
+ input.launch?.shutdownMode === "process-cleanup") {
43
41
  state.cleanupResult = await input.launch
44
42
  .cleanup()
45
43
  .catch(providerCleanupFailure);
@@ -82,7 +80,9 @@ const stopProcess = async (input, state) => {
82
80
  }
83
81
  input.logger.info(diagnostic, "Owned Hopper launcher shutdown completed");
84
82
  if (stopped.status !== "incomplete") {
85
- state.ownedProcessStopped = stopped.status !== "not-owned";
83
+ if (input.launch?.shutdownMode === "process-cleanup" &&
84
+ stopped.status !== "not-owned")
85
+ state.shutdownConfirmed = true;
86
86
  return;
87
87
  }
88
88
  const processGroupId = supervisor.launch.ownership?.processGroupId;
@@ -95,8 +95,7 @@ const stopProcess = async (input, state) => {
95
95
  };
96
96
  const recordUnconfirmedDocument = (input, state) => {
97
97
  if ((input.socket === undefined && input.launch === undefined) ||
98
- state.shutdownConfirmed ||
99
- state.ownedProcessStopped)
98
+ state.shutdownConfirmed)
100
99
  return;
101
100
  state.resources.add("hopper-document");
102
101
  state.issues.push({