rea-agents 2.4.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/README.md +91 -19
  2. package/bridge/ghidra/ReaGhidraBridge.java +524 -4
  3. package/bridge/hopper_bridge.py +313 -28
  4. package/dist/application/AnalysisClientCleanup.js +14 -0
  5. package/dist/application/AnalysisContextQueries.js +130 -0
  6. package/dist/application/AnalysisSnapshotCache.js +4 -2
  7. package/dist/application/ApplicationWorkflowEvidenceResolver.js +31 -13
  8. package/dist/application/ArtifactInventory/scanCanonical.js +1 -1
  9. package/dist/application/BinarySession.js +20 -8
  10. package/dist/application/BinarySessionComposition.js +21 -0
  11. package/dist/application/BinarySessionRecords.js +79 -9
  12. package/dist/application/BinarySessionStatus.js +31 -1
  13. package/dist/application/BrowserEvidence.js +14 -0
  14. package/dist/application/BrowserScenarioCapturePort.js +1 -0
  15. package/dist/application/BrowserScenarioCaptureService.js +53 -0
  16. package/dist/application/BrowserScenarioEvidence.js +40 -0
  17. package/dist/application/CallPathTracing.js +160 -0
  18. package/dist/application/CapabilityInventory.js +84 -14
  19. package/dist/application/ClientRegistrationStatus.js +4 -1
  20. package/dist/application/CompositeProvider.js +10 -1
  21. package/dist/application/DirectAnalysis.js +13 -4
  22. package/dist/application/EnhancedLiteralTracing.js +118 -0
  23. package/dist/application/EnhancedTools.js +71 -127
  24. package/dist/application/EvidenceLedger.js +45 -16
  25. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +13 -0
  26. package/dist/application/JavaScriptApplicationWorkflowService.js +27 -1
  27. package/dist/application/JavaScriptArtifactAnalysis.js +13 -4
  28. package/dist/application/JavaScriptRuntimeObservationEvidence.js +34 -0
  29. package/dist/application/JavaScriptRuntimeObservationPort.js +1 -0
  30. package/dist/application/JavaScriptRuntimeObservationService.js +46 -0
  31. package/dist/application/JavaScriptSemanticGraphAsyncProjection.js +147 -0
  32. package/dist/application/JavaScriptSemanticGraphBuilder.js +34 -6
  33. package/dist/application/JavaScriptSemanticGraphChildProcessProjection.js +156 -0
  34. package/dist/application/JavaScriptSemanticGraphConstruction.js +2 -2
  35. package/dist/application/JavaScriptSemanticGraphDataProjection.js +203 -0
  36. package/dist/application/JavaScriptSemanticGraphFingerprintProjection.js +25 -0
  37. package/dist/application/JavaScriptSemanticGraphFlowProjection.js +129 -8
  38. package/dist/application/JavaScriptSemanticGraphObjectProjection.js +81 -0
  39. package/dist/application/JavaScriptSemanticGraphProjection.js +14 -7
  40. package/dist/application/JavaScriptSemanticGraphResourceProjection.js +59 -0
  41. package/dist/application/JavaScriptSemanticGraphValueProjection.js +77 -0
  42. package/dist/application/LazyAnalysisProvider.js +77 -0
  43. package/dist/application/LoopbackReplay.js +1 -1
  44. package/dist/application/NativeApiInspection.js +80 -0
  45. package/dist/application/ProcessReactiveEffects.js +6 -0
  46. package/dist/application/ProcessReactiveHarness.js +16 -1
  47. package/dist/application/ProjectPermissionStore.js +1 -0
  48. package/dist/application/ReconstructionObligationAuthority.js +72 -0
  49. package/dist/application/ReconstructionObligationCandidates.js +265 -0
  50. package/dist/application/ReconstructionObligationLedgerDiagnostics.js +47 -0
  51. package/dist/application/ReconstructionObligationLedgerEvaluation.js +263 -0
  52. package/dist/application/ReconstructionObligationLedgerProjection.js +86 -0
  53. package/dist/application/ReconstructionObligationLedgerService.js +72 -0
  54. package/dist/application/ReconstructionObligationOriginalCases.js +33 -0
  55. package/dist/application/ReconstructionObligationPolicies.js +132 -0
  56. package/dist/application/ReconstructionReadinessService.js +48 -0
  57. package/dist/application/SessionProviderRouter.js +6 -6
  58. package/dist/application/SetupClientConfiguration.js +4 -2
  59. package/dist/application/runtime.js +26 -9
  60. package/dist/artifacts/ArtifactProvider.js +87 -22
  61. package/dist/browser/BrowserScenarioSecrets.js +53 -0
  62. package/dist/browser/BrowserScenarioSessionPort.js +1 -0
  63. package/dist/browser/CdpBrowserProvider.js +2 -2
  64. package/dist/browser/CdpCaptureDocuments.js +57 -0
  65. package/dist/browser/CdpCaptureStorage.js +71 -29
  66. package/dist/browser/CdpCaptureStorageFingerprints.js +328 -0
  67. package/dist/browser/CdpEndpoint.js +8 -6
  68. package/dist/browser/CdpPageCapture.js +2 -0
  69. package/dist/browser/JavaScriptRuntimeScope.js +38 -0
  70. package/dist/browser/PlaywrightBrowserScenarioProvider.js +259 -0
  71. package/dist/browser/PlaywrightExecutionBoundary.js +42 -0
  72. package/dist/browser/PlaywrightScenarioActions.js +62 -0
  73. package/dist/browser/PlaywrightScenarioArtifacts.js +238 -0
  74. package/dist/browser/PlaywrightScenarioBrowser.js +144 -0
  75. package/dist/browser/PlaywrightScenarioEvents.js +301 -0
  76. package/dist/browser/PlaywrightScenarioSession.js +300 -0
  77. package/dist/browser/V8InspectorCaptureProjection.js +110 -0
  78. package/dist/browser/V8InspectorEndpoint.js +72 -0
  79. package/dist/browser/V8InspectorProvider.js +267 -0
  80. package/dist/catalogIdentity.js +11 -3
  81. package/dist/cli/artifactCommands.js +44 -3
  82. package/dist/cli/coreAnalysisCommands.js +78 -0
  83. package/dist/cli.js +4 -0
  84. package/dist/cliApplicationCommands.js +30 -2
  85. package/dist/cliBrowserAdvancedCommands.js +17 -5
  86. package/dist/cliBrowserCommands.js +1 -0
  87. package/dist/cliBrowserScenarioCommands.js +43 -0
  88. package/dist/cliCommandNames.js +9 -0
  89. package/dist/cliJavaScriptRuntimeCommands.js +164 -0
  90. package/dist/cliObservationOptions.js +4 -0
  91. package/dist/cliPolicyCommands.js +1 -0
  92. package/dist/config/environment.js +12 -0
  93. package/dist/config/parseConfig.js +88 -17
  94. package/dist/contracts/analysisSearchContract.js +14 -0
  95. package/dist/contracts/applicationToolContracts.js +86 -2
  96. package/dist/contracts/applicationWorkflowInputContracts.js +18 -0
  97. package/dist/contracts/artifactToolContracts.js +29 -2
  98. package/dist/contracts/browserProviderToolContracts.js +7 -0
  99. package/dist/contracts/browserScenarioToolContracts.js +81 -0
  100. package/dist/contracts/browserToolContracts.js +88 -98
  101. package/dist/contracts/enhancedInputs.js +35 -6
  102. package/dist/contracts/functionInstructionContract.js +8 -0
  103. package/dist/contracts/functionWorkflowToolContracts.js +30 -0
  104. package/dist/contracts/hopperMemoryContracts.js +22 -0
  105. package/dist/contracts/javascriptApplicationWorkflowExamples.js +42 -0
  106. package/dist/contracts/javascriptRuntimeObservationToolContracts.js +58 -0
  107. package/dist/contracts/promptContracts.js +14 -15
  108. package/dist/contracts/reconstructionReadinessExample.js +436 -0
  109. package/dist/contracts/toolContractExamples.js +8 -0
  110. package/dist/contracts/toolContractTypes.js +1 -0
  111. package/dist/contracts/toolContracts.js +34 -25
  112. package/dist/contracts/toolEffects.js +25 -0
  113. package/dist/contracts/toolOutputSchemaGroups.js +120 -30
  114. package/dist/contracts/toolOutputSchemaPrimitives.js +37 -0
  115. package/dist/domain/analysisErrorPresentation.js +8 -2
  116. package/dist/domain/analysisErrorProjection.js +9 -0
  117. package/dist/domain/artifactInspection.js +347 -0
  118. package/dist/domain/browserCaptureComparison.js +82 -0
  119. package/dist/domain/browserObservation.js +8 -1
  120. package/dist/domain/browserObservationErrors.js +1 -0
  121. package/dist/domain/browserObservationSchemas.js +26 -0
  122. package/dist/domain/browserScenario.js +165 -0
  123. package/dist/domain/browserScenarioCapture.js +57 -0
  124. package/dist/domain/browserScenarioCaptureValues.js +204 -0
  125. package/dist/domain/browserScenarioDiff.js +324 -0
  126. package/dist/domain/browserScenarioDiffValues.js +157 -0
  127. package/dist/domain/browserScenarioNormalization.js +45 -0
  128. package/dist/domain/browserScenarioValues.js +372 -0
  129. package/dist/domain/bytecodeProvider.js +179 -0
  130. package/dist/domain/conformancePackage.js +169 -0
  131. package/dist/domain/conformanceReplay.js +104 -0
  132. package/dist/domain/conformanceTrustGate.js +193 -0
  133. package/dist/domain/customProtocolCapture.js +137 -0
  134. package/dist/domain/eventProcessTree.js +214 -0
  135. package/dist/domain/evidenceBundle.js +47 -0
  136. package/dist/domain/hopperStartupFailure.js +1 -1
  137. package/dist/domain/hopperValues.js +14 -1
  138. package/dist/domain/inputIssueProjection.js +7 -1
  139. package/dist/domain/javascriptRuntimeObservation.js +170 -0
  140. package/dist/domain/javascriptRuntimeReconciliationParsing.js +120 -2
  141. package/dist/domain/javascriptRuntimeReconciliationResult.js +3 -3
  142. package/dist/domain/javascriptRuntimeReconciliationRuntime.js +2 -2
  143. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
  144. package/dist/domain/javascriptSemanticAnalysis.js +13 -16
  145. package/dist/domain/javascriptSemanticAsyncEffects.js +253 -0
  146. package/dist/domain/javascriptSemanticChildProcesses.js +237 -0
  147. package/dist/domain/javascriptSemanticDataEffectHelpers.js +125 -0
  148. package/dist/domain/javascriptSemanticDataEffects.js +284 -0
  149. package/dist/domain/javascriptSemanticDerivedAnalysis.js +41 -0
  150. package/dist/domain/javascriptSemanticFingerprints.js +174 -0
  151. package/dist/domain/javascriptSemanticIr.js +21 -1
  152. package/dist/domain/javascriptSemanticObjects.js +115 -0
  153. package/dist/domain/javascriptSemanticPromises.js +290 -0
  154. package/dist/domain/javascriptSemanticResources.js +136 -0
  155. package/dist/domain/javascriptSourceParser.js +15 -0
  156. package/dist/domain/javascriptStaticAnalysis.js +12 -15
  157. package/dist/domain/javascriptStaticAnalysisBundler.js +38 -0
  158. package/dist/domain/javascriptStaticAnalysisCalls.js +23 -1
  159. package/dist/domain/javascriptStaticAnalysisHelpers.js +8 -0
  160. package/dist/domain/mobileApplicationInvestigation.js +159 -0
  161. package/dist/domain/nativeApiBoundary.js +130 -0
  162. package/dist/domain/objcSwiftMetadata.js +150 -0
  163. package/dist/domain/packageAnalysis.js +123 -0
  164. package/dist/domain/peInspection.js +196 -0
  165. package/dist/domain/processCapture.js +8 -2
  166. package/dist/domain/processReactiveScenario.js +1 -0
  167. package/dist/domain/processReactiveTransition.js +9 -4
  168. package/dist/domain/protocolCapture.js +243 -0
  169. package/dist/domain/providerCleanupError.js +11 -0
  170. package/dist/domain/reconstructionObligationLedgerSchemas.js +278 -0
  171. package/dist/domain/reconstructionReadiness.js +121 -0
  172. package/dist/domain/reconstructionReadinessFindingHelpers.js +17 -0
  173. package/dist/domain/reconstructionReadinessIntegrityFindings.js +118 -0
  174. package/dist/domain/reconstructionReadinessJourneyFindings.js +193 -0
  175. package/dist/domain/reconstructionReadinessSchemas.js +240 -0
  176. package/dist/domain/sourceToBundleComparison.js +335 -0
  177. package/dist/domain/sourceToBundleComparisonSchemas.js +133 -0
  178. package/dist/domain/sourceToBundleSignals.js +202 -0
  179. package/dist/domain/webCaptureDiff.js +141 -27
  180. package/dist/domain/webScreenshot.js +1 -1
  181. package/dist/dotnet/ManagedStaticProvider.js +34 -5
  182. package/dist/generatedMcpToolCatalog.js +37 -0
  183. package/dist/generatedPackageMetadata.js +4 -4
  184. package/dist/ghidra/GhidraDefaults.js +1 -1
  185. package/dist/ghidra/GhidraFunctionValues.js +40 -2
  186. package/dist/ghidra/GhidraProviderCapabilities.js +47 -38
  187. package/dist/hopper/HopperCleanup.js +158 -0
  188. package/dist/hopper/HopperClient.js +93 -99
  189. package/dist/hopper/HopperProvider.js +61 -30
  190. package/dist/hopper/HopperRequestQueue.js +215 -0
  191. package/dist/hopper/HopperResponseStream.js +46 -0
  192. package/dist/hopper/protocol.js +63 -20
  193. package/dist/main/transport.js +24 -27
  194. package/dist/main.js +14 -6
  195. package/dist/mcpDoctor.js +27 -4
  196. package/dist/mcpStartupPolicy.js +14 -0
  197. package/dist/process/ProcessCommandIdentity.js +19 -0
  198. package/dist/process/ProcessOwnership.js +11 -8
  199. package/dist/server/DynamicToolAvailability.js +70 -0
  200. package/dist/server/LazyToolCatalog.js +134 -0
  201. package/dist/server/createServer.js +92 -154
  202. package/dist/server/hydrateServerTools.js +191 -0
  203. package/dist/server/lifecycleProgress.js +10 -0
  204. package/dist/server/permissionFailure.js +12 -0
  205. package/dist/server/registerApplicationTools/compareSourceToBundle.js +35 -0
  206. package/dist/server/registerApplicationTools/helpers.js +11 -7
  207. package/dist/server/registerApplicationTools/obligationLedger.js +27 -0
  208. package/dist/server/registerApplicationTools/readiness.js +55 -0
  209. package/dist/server/registerApplicationTools.js +6 -0
  210. package/dist/server/registerArtifactTools.js +9 -1
  211. package/dist/server/registerBrowserScenarioTool.js +25 -0
  212. package/dist/server/registerBrowserTools.js +2 -2
  213. package/dist/server/registerCloseLifecycleTool.js +57 -0
  214. package/dist/server/registerEnhancedTools.js +28 -7
  215. package/dist/server/registerEvidenceResources.js +54 -101
  216. package/dist/server/registerEvidenceTools.js +9 -2
  217. package/dist/server/registerInvestigationTools.js +1 -2
  218. package/dist/server/registerJavaScriptApplicationGraphResource.js +0 -4
  219. package/dist/server/registerJavaScriptRuntimeObservationTools.js +37 -0
  220. package/dist/server/registerReconstructionObligationLedgerResource.js +32 -0
  221. package/dist/server/registerReconstructionReadinessResource.js +32 -0
  222. package/dist/server/registerSessionRecordTools.js +82 -12
  223. package/dist/server/registerSessionStatusTool.js +11 -8
  224. package/dist/server/registerSessionTools.js +32 -58
  225. package/dist/server/sessionAvailabilityPolicy.js +10 -8
  226. package/dist/server/toolRegistrationOptions.js +21 -6
  227. package/dist/server/toolResult.js +12 -0
  228. package/package.json +28 -11
  229. package/scripts/package-runner-bootstrap.mjs +72 -0
  230. package/scripts/rea.mjs +11 -1
  231. package/skills/reverse-engineer-anything/SKILL.md +10 -3
@@ -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.4.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.0.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
  };
@@ -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 = 4;
20
+ export const GHIDRA_BRIDGE_VERSION = 6;
@@ -1,7 +1,8 @@
1
1
  import { z } from "zod";
2
2
  import { AnalysisInputError, AnalysisOutputError } from "../domain/errors.js";
3
- import { functionDossierSchema, } from "../domain/hopperValues.js";
3
+ import { functionInstructionWindowSchema, functionDossierSchema, } from "../domain/hopperValues.js";
4
4
  import { jsonObjectSchema, jsonValueSchema, } from "../domain/jsonValue.js";
5
+ import { nativeApiBoundarySchema } from "../domain/nativeApiBoundary.js";
5
6
  import { err, ok } from "../domain/result.js";
6
7
  import { ghidraBoundedIdentifierSchema, ghidraCanonicalAddressSchema, } from "./GhidraInventoryValues.js";
7
8
  /** Read-only function operations admitted by the Ghidra adapter. */
@@ -12,6 +13,7 @@ export const GHIDRA_FUNCTION_OPERATIONS = [
12
13
  "procedure_callers",
13
14
  "procedure_info",
14
15
  "procedure_pseudo_code",
16
+ "read_function_instructions",
15
17
  "procedure_references",
16
18
  "xrefs",
17
19
  ];
@@ -66,6 +68,13 @@ const inputSchemas = {
66
68
  procedure_callers: z.object(directProcedure).strict(),
67
69
  procedure_info: z.object(directProcedure).strict(),
68
70
  procedure_pseudo_code: z.object(directProcedure).strict(),
71
+ read_function_instructions: z
72
+ .object({
73
+ ...directProcedure,
74
+ offset: z.number().int().min(0).max(100_000).default(0),
75
+ limit: z.number().int().min(1).max(500).default(64),
76
+ })
77
+ .strict(),
69
78
  procedure_references: z
70
79
  .object({
71
80
  ...directProcedure,
@@ -183,7 +192,32 @@ const procedureInfo = z
183
192
  classification,
184
193
  })
185
194
  .strict();
186
- const ghidraFunctionDossier = functionDossierSchema.superRefine((value, context) => {
195
+ const ghidraNativeApiBoundary = nativeApiBoundarySchema.superRefine((value, context) => {
196
+ if (!value.available)
197
+ return;
198
+ if (value.provenance !== "ghidra-high-function")
199
+ context.addIssue({
200
+ code: "custom",
201
+ message: "Ghidra native API observations require HighFunction provenance",
202
+ });
203
+ const addresses = value.jump_tables.flatMap((table) => [
204
+ table.dispatch_address,
205
+ ...table.data_sources.map(({ address }) => address),
206
+ ...table.mappings.flatMap(({ target_address, data_addresses }) => [
207
+ target_address,
208
+ ...data_addresses,
209
+ ]),
210
+ ]);
211
+ if (addresses.some((address) => !ghidraCanonicalAddressSchema.safeParse(address).success))
212
+ context.addIssue({
213
+ code: "custom",
214
+ message: "Ghidra native API observation contains a non-canonical address",
215
+ });
216
+ });
217
+ const ghidraFunctionDossier = functionDossierSchema
218
+ .extend({ native_api: ghidraNativeApiBoundary })
219
+ .strict()
220
+ .superRefine((value, context) => {
187
221
  const addresses = [
188
222
  value.procedure.address,
189
223
  ...value.comments.items.map(({ address }) => address),
@@ -235,6 +269,9 @@ const ghidraFunctionDossier = functionDossierSchema.superRefine((value, context)
235
269
  message: "Ghidra dossier omitted required uncertainty limitations",
236
270
  });
237
271
  });
272
+ const ghidraFunctionInstructionWindow = functionInstructionWindowSchema
273
+ .extend({ procedure: procedureIdentity })
274
+ .strict();
238
275
  const resultSchemas = {
239
276
  analyze_function: ghidraFunctionDossier,
240
277
  procedure_assembly: z.string(),
@@ -242,6 +279,7 @@ const resultSchemas = {
242
279
  procedure_callers: z.array(ghidraCanonicalAddressSchema),
243
280
  procedure_info: procedureInfo,
244
281
  procedure_pseudo_code: z.string().nullable(),
282
+ read_function_instructions: ghidraFunctionInstructionWindow,
245
283
  procedure_references: procedureReferences,
246
284
  xrefs: z.array(ghidraCanonicalAddressSchema),
247
285
  };
@@ -1,4 +1,4 @@
1
- import { ENHANCED_TOOL_CONTRACTS, OFFICIAL_TOOL_CONTRACTS, } from "../contracts/toolContracts.js";
1
+ import { GENERATED_MCP_TOOL_CATALOG } from "../generatedMcpToolCatalog.js";
2
2
  import { GHIDRA_DECOMPILE_REQUEST_TIMEOUT_MS, GHIDRA_MAX_LINE_BYTES, GHIDRA_REQUEST_TIMEOUT_MS, } from "./GhidraDefaults.js";
3
3
  import { GHIDRA_FUNCTION_OPERATIONS } from "./GhidraFunctionValues.js";
4
4
  import { GHIDRA_INVENTORY_OPERATIONS } from "./GhidraInventoryValues.js";
@@ -8,10 +8,7 @@ export const GHIDRA_PROVIDER_IDENTITY = Object.freeze({
8
8
  name: "Ghidra",
9
9
  version: null,
10
10
  });
11
- const providerContractByName = new Map([...OFFICIAL_TOOL_CONTRACTS, ...ENHANCED_TOOL_CONTRACTS].map((contract) => [
12
- contract.name,
13
- contract,
14
- ]));
11
+ const providerContractByName = new Map(GENERATED_MCP_TOOL_CATALOG.filter(({ kind }) => kind === "official-proxy" || kind === "enhanced").map((contract) => [contract.name, contract]));
15
12
  /** Provider-neutral read-only contracts implemented by the Ghidra adapter. */
16
13
  export const GHIDRA_PROVIDER_TOOL_CONTRACTS = Object.freeze([...GHIDRA_INVENTORY_OPERATIONS, ...GHIDRA_FUNCTION_OPERATIONS].map((operation) => {
17
14
  const contract = providerContractByName.get(operation);
@@ -26,6 +23,7 @@ const PAGINATED_OPERATIONS = new Set([
26
23
  "search_procedures",
27
24
  "search_strings",
28
25
  "procedure_references",
26
+ "read_function_instructions",
29
27
  "analyze_function",
30
28
  ]);
31
29
  const SEARCH_OPERATIONS = new Set([
@@ -93,6 +91,12 @@ export const limitationsFor = (operation) => {
93
91
  "Pseudocode is Ghidra decompiler output, not original source and not text-equivalent to Hopper output; each decompile has a 30-second native deadline.",
94
92
  "External functions and functions without an analyzable body return null; other decompiler failures remain explicit.",
95
93
  ];
94
+ case "read_function_instructions":
95
+ return [
96
+ ...common,
97
+ "This bounded fast path reads only the requested function instruction window and does not invoke the decompiler or whole-program string/name inventories.",
98
+ "Instruction text is Ghidra-specific and does not claim textual equivalence with Hopper output.",
99
+ ];
96
100
  case "procedure_assembly":
97
101
  return [
98
102
  ...common,
@@ -130,39 +134,44 @@ export const limitationsFor = (operation) => {
130
134
  }
131
135
  };
132
136
  /** Provider-neutral capabilities advertised by every non-Windows Ghidra session. */
133
- export const CAPABILITIES = Object.freeze(GHIDRA_PROVIDER_TOOL_CONTRACTS.map((contract) => Object.freeze({
134
- provider: GHIDRA_PROVIDER_IDENTITY,
135
- operation: contract.name,
136
- inputContractVersion: 1,
137
- outputContractVersion: 1,
138
- available: true,
139
- reason: null,
140
- pagination: PAGINATED_OPERATIONS.has(contract.name)
141
- ? "offset"
142
- : "none",
143
- exhaustive: !PAGINATED_OPERATIONS.has(contract.name),
144
- effects: Object.freeze({
145
- mutatesArtifact: false,
146
- launchesProcess: true,
147
- mayShowUi: false,
148
- mayAccessNetwork: false,
149
- mayWriteFilesystem: true,
150
- changesPermissions: false,
151
- requiresRoot: false,
152
- }),
153
- limits: Object.freeze({
154
- maxResults: PAGINATED_OPERATIONS.has(contract.name)
155
- ? SEARCH_OPERATIONS.has(contract.name)
156
- ? 100
157
- : 500
158
- : null,
159
- maxPayloadBytes: GHIDRA_MAX_LINE_BYTES,
160
- timeoutMs: DECOMPILE_OPERATIONS.has(contract.name)
161
- ? GHIDRA_DECOMPILE_REQUEST_TIMEOUT_MS
162
- : GHIDRA_REQUEST_TIMEOUT_MS,
163
- }),
164
- limitations: Object.freeze(limitationsFor(contract.name)),
165
- })));
137
+ export const CAPABILITIES = Object.freeze(GHIDRA_PROVIDER_TOOL_CONTRACTS.map((contract) => {
138
+ const operation = contract.analysisOperation;
139
+ if (operation === null)
140
+ throw new TypeError(`Missing analysis operation for ${contract.name}`);
141
+ return Object.freeze({
142
+ provider: GHIDRA_PROVIDER_IDENTITY,
143
+ operation,
144
+ inputContractVersion: 1,
145
+ outputContractVersion: 1,
146
+ available: true,
147
+ reason: null,
148
+ pagination: PAGINATED_OPERATIONS.has(contract.name)
149
+ ? "offset"
150
+ : "none",
151
+ exhaustive: !PAGINATED_OPERATIONS.has(contract.name),
152
+ effects: Object.freeze({
153
+ mutatesArtifact: false,
154
+ launchesProcess: true,
155
+ mayShowUi: false,
156
+ mayAccessNetwork: false,
157
+ mayWriteFilesystem: true,
158
+ changesPermissions: false,
159
+ requiresRoot: false,
160
+ }),
161
+ limits: Object.freeze({
162
+ maxResults: PAGINATED_OPERATIONS.has(contract.name)
163
+ ? SEARCH_OPERATIONS.has(contract.name)
164
+ ? 100
165
+ : 500
166
+ : null,
167
+ maxPayloadBytes: GHIDRA_MAX_LINE_BYTES,
168
+ timeoutMs: DECOMPILE_OPERATIONS.has(contract.name)
169
+ ? GHIDRA_DECOMPILE_REQUEST_TIMEOUT_MS
170
+ : GHIDRA_REQUEST_TIMEOUT_MS,
171
+ }),
172
+ limitations: Object.freeze(limitationsFor(contract.name)),
173
+ });
174
+ }));
166
175
  /** Capabilities advertised for the experimental Windows x64 P0 boundary. */
167
176
  export const WINDOWS_P0_CAPABILITIES = Object.freeze(CAPABILITIES.map((capability) => Object.freeze({
168
177
  ...capability,
@@ -0,0 +1,158 @@
1
+ import { HopperProcessError } from "../domain/errors.js";
2
+ import { ProviderCleanupError } from "../domain/providerCleanupError.js";
3
+ import { err, ok } from "../domain/result.js";
4
+ import { createOwnedHopperShutdownDiagnostic, providerCleanupFailure, } from "./HopperDiagnostics.js";
5
+ import { isHopperCleanupRequired, isHopperShutdownAcknowledgement, } from "./HopperSessionValues.js";
6
+ /** Close Hopper phases and retain every resource whose cleanup is unverified. */
7
+ export const cleanupHopperSession = async (input) => {
8
+ const state = {
9
+ issues: [],
10
+ resources: new Set(),
11
+ cleanupResult: undefined,
12
+ shutdownConfirmed: false,
13
+ ownedProcessStopped: false,
14
+ };
15
+ await report(input.progress, 0, "requesting Hopper document shutdown");
16
+ await requestShutdown(input, state);
17
+ await report(input.progress, 0.35, "releasing Hopper bridge transport");
18
+ input.releaseTransport(input.socket);
19
+ await stopProcess(input, state);
20
+ recordUnconfirmedDocument(input, state);
21
+ await report(input.progress, 0.75, "removing Hopper private runtime files");
22
+ await closeRuntimeRoot(input.runtimeRoot, state);
23
+ return cleanupOutcome(input, state);
24
+ };
25
+ const requestShutdown = async (input, state) => {
26
+ if (input.socket === undefined ||
27
+ input.socket.destroyed ||
28
+ input.activeRequest !== null) {
29
+ if (input.activeRequest !== null)
30
+ input.logger.warn({
31
+ method: input.activeRequest.operation,
32
+ callerState: input.activeRequest.callerState,
33
+ }, "Hopper shutdown skipped because a bridge operation remained active");
34
+ return;
35
+ }
36
+ const shutdown = await input
37
+ .request("shutdown")
38
+ .catch(() => err(new HopperProcessError(null)));
39
+ if (shutdown.ok &&
40
+ isHopperCleanupRequired(shutdown.value) &&
41
+ input.launch?.shutdownByCleanup === true &&
42
+ input.launch.cleanup !== undefined) {
43
+ state.cleanupResult = await input.launch
44
+ .cleanup()
45
+ .catch(providerCleanupFailure);
46
+ if (!state.cleanupResult.cleaned) {
47
+ state.shutdownConfirmed = await fallbackDocumentShutdown(input);
48
+ state.cleanupResult = await input.launch
49
+ .cleanup()
50
+ .catch(providerCleanupFailure);
51
+ }
52
+ }
53
+ else if (shutdown.ok) {
54
+ state.shutdownConfirmed = isHopperShutdownAcknowledgement(shutdown.value);
55
+ }
56
+ if (!shutdown.ok ||
57
+ (!state.shutdownConfirmed && state.cleanupResult === undefined))
58
+ input.logger.warn({ status: shutdown.ok ? "invalid-acknowledgement" : "failed" }, "Hopper document shutdown was not confirmed");
59
+ };
60
+ const fallbackDocumentShutdown = async (input) => {
61
+ const fallback = await input
62
+ .request("shutdown_document")
63
+ .catch(() => err(new HopperProcessError(null)));
64
+ const confirmed = fallback.ok && isHopperShutdownAcknowledgement(fallback.value);
65
+ if (!confirmed)
66
+ input.logger.warn({ status: fallback.ok ? "invalid-acknowledgement" : "failed" }, "Hopper document shutdown fallback was not confirmed");
67
+ return confirmed;
68
+ };
69
+ const stopProcess = async (input, state) => {
70
+ const supervisor = input.processSupervisor;
71
+ if (supervisor === undefined)
72
+ return;
73
+ const stopped = await supervisor.stop(state.cleanupResult === undefined
74
+ ? {}
75
+ : { cleanupResult: state.cleanupResult });
76
+ const diagnostic = createOwnedHopperShutdownDiagnostic(supervisor.launch, stopped, state.cleanupResult);
77
+ try {
78
+ input.onDiagnostic?.(diagnostic);
79
+ }
80
+ catch {
81
+ // Diagnostic consumers cannot change the already-observed cleanup result.
82
+ }
83
+ input.logger.info(diagnostic, "Owned Hopper launcher shutdown completed");
84
+ if (stopped.status !== "incomplete") {
85
+ state.ownedProcessStopped = stopped.status !== "not-owned";
86
+ return;
87
+ }
88
+ const processGroupId = supervisor.launch.ownership?.processGroupId;
89
+ const resource = processGroupId === undefined
90
+ ? "hopper-process"
91
+ : `process-group:${String(processGroupId)}`;
92
+ state.resources.add(resource);
93
+ state.issues.push({ resource, reason: stopped.reason });
94
+ input.logger.warn({ reason: stopped.reason }, "Owned launcher cleanup failed closed");
95
+ };
96
+ const recordUnconfirmedDocument = (input, state) => {
97
+ if ((input.socket === undefined && input.launch === undefined) ||
98
+ state.shutdownConfirmed ||
99
+ state.ownedProcessStopped)
100
+ return;
101
+ state.resources.add("hopper-document");
102
+ state.issues.push({
103
+ resource: "hopper-document",
104
+ reason: input.activeRequest === null
105
+ ? "authenticated shutdown acknowledgement was not observed"
106
+ : `bridge operation ${input.activeRequest.operation} remained active after caller ${input.activeRequest.callerState}`,
107
+ });
108
+ };
109
+ const closeRuntimeRoot = async (runtimeRoot, state) => {
110
+ try {
111
+ await runtimeRoot?.close();
112
+ }
113
+ catch (cause) {
114
+ const resource = runtimeRoot?.path ?? "hopper-runtime-root";
115
+ state.resources.add(resource);
116
+ state.issues.push({
117
+ resource,
118
+ reason: cause instanceof Error
119
+ ? cause.message
120
+ : "private runtime root cleanup failed",
121
+ });
122
+ }
123
+ };
124
+ const cleanupOutcome = (input, state) => {
125
+ if (state.issues.length === 0)
126
+ return ok(null);
127
+ return err(new ProviderCleanupError("hopper", [...state.resources], {
128
+ issues: cleanupIssueDetails(state.issues),
129
+ ...(input.runtimeRoot === undefined
130
+ ? {}
131
+ : { runtime_root: input.runtimeRoot.path }),
132
+ ...(input.activeRequest === null
133
+ ? {}
134
+ : { active_request: activityDetails(input.activeRequest) }),
135
+ }));
136
+ };
137
+ const cleanupIssueDetails = (issues) => issues.map((issue) => ({
138
+ resource: issue.resource,
139
+ reason: issue.reason,
140
+ }));
141
+ const activityDetails = (activity) => ({
142
+ request_id: activity.requestId,
143
+ operation: activity.operation,
144
+ elapsed_ms: activity.elapsedMs,
145
+ timeout_ms: activity.timeoutMs,
146
+ caller_state: activity.callerState,
147
+ queued_requests: activity.queuedRequests,
148
+ });
149
+ const report = async (progress, completed, message) => {
150
+ await progress
151
+ ?.report({
152
+ phase: "hopper_cleanup",
153
+ completed,
154
+ total: 1,
155
+ message,
156
+ })
157
+ .catch(() => undefined);
158
+ };