rea-agents 2.0.0 → 2.2.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 (273) hide show
  1. package/README.md +103 -38
  2. package/bridge/ghidra/ReaGhidraBridge.java +96 -11
  3. package/dist/application/AndroidApplicationService.js +17 -0
  4. package/dist/application/AppleApplicationService.js +17 -0
  5. package/dist/application/ArtifactExtraction.js +1 -1
  6. package/dist/application/ArtifactInventory/classify.js +42 -0
  7. package/dist/application/ArtifactInventory/hash.js +43 -0
  8. package/dist/application/ArtifactInventory/reader.js +41 -0
  9. package/dist/application/ArtifactInventory/scanCanonical.js +155 -0
  10. package/dist/application/ArtifactInventory/scanReader.js +124 -0
  11. package/dist/application/ArtifactInventory/types.js +10 -0
  12. package/dist/application/ArtifactInventory.js +9 -351
  13. package/dist/application/AuthorizedArtifactInventory.js +2 -2
  14. package/dist/application/BinarySession.js +47 -270
  15. package/dist/application/BinarySessionExecution.js +28 -0
  16. package/dist/application/BinarySessionOpen.js +39 -0
  17. package/dist/application/BinarySessionRecords.js +149 -0
  18. package/dist/application/BinarySessionStatus.js +75 -0
  19. package/dist/application/CapabilityInventory.js +24 -2
  20. package/dist/application/ClientRegistrationStatus.js +11 -4
  21. package/dist/application/CrossVersionInventory.js +8 -2
  22. package/dist/application/CrossVersionInvestigation.js +1 -23
  23. package/dist/application/CrossVersionInvestigationCollections.js +23 -0
  24. package/dist/application/DirectAnalysis.js +47 -44
  25. package/dist/application/Doctor.js +156 -238
  26. package/dist/application/DoctorDiagnostics.js +180 -0
  27. package/dist/application/ElectronBoundaryAnalysis.js +23 -7
  28. package/dist/application/ElectronBoundaryGraphWindows.js +32 -8
  29. package/dist/application/EnhancedToolPagination.js +22 -0
  30. package/dist/application/EnhancedToolTypes.js +4 -0
  31. package/dist/application/EnhancedTools.js +20 -37
  32. package/dist/application/InstrumentedJavaScriptReplayHost.js +36 -0
  33. package/dist/application/InventoryProjectionEvidence.js +41 -0
  34. package/dist/application/InvestigationProviders.js +12 -0
  35. package/dist/application/InvestigationWorkspaceStore.js +24 -10
  36. package/dist/application/JavaScriptArtifactAnalysis.js +45 -6
  37. package/dist/application/JavaScriptArtifactFiles.js +6 -2
  38. package/dist/application/JavaScriptArtifactGraphBuilder.js +23 -1
  39. package/dist/application/JavaScriptArtifactGraphBundlers.js +225 -0
  40. package/dist/application/JavaScriptArtifactGraphContext.js +37 -36
  41. package/dist/application/JavaScriptArtifactGraphDocuments.js +27 -4
  42. package/dist/application/JavaScriptArtifactGraphFindings.js +54 -8
  43. package/dist/application/JavaScriptArtifactGraphStructure.js +29 -101
  44. package/dist/application/JavaScriptArtifactPathResolution.js +269 -0
  45. package/dist/application/JavaScriptArtifactReconstruction.js +1 -1
  46. package/dist/application/JavaScriptJsonModules.js +39 -0
  47. package/dist/application/JavaScriptModuleRelationships.js +262 -0
  48. package/dist/application/JavaScriptReplayPermission.js +16 -0
  49. package/dist/application/JavaScriptReplayService.js +182 -156
  50. package/dist/application/LinuxHopper.js +10 -0
  51. package/dist/application/MacHopper.js +22 -11
  52. package/dist/application/NodeRuntimeCharacterizationService.js +196 -0
  53. package/dist/application/PermissionAuthority.js +106 -63
  54. package/dist/application/ProcessCaptureCapability.js +1 -1
  55. package/dist/application/ProcessCapturePermission.js +13 -0
  56. package/dist/application/ProcessCli.js +2 -12
  57. package/dist/application/ProcessHarness.js +1 -1
  58. package/dist/application/ProcessPairedExperiment.js +72 -0
  59. package/dist/application/ProjectPermissionStore.js +48 -9
  60. package/dist/application/RealHopperAssertions.js +76 -0
  61. package/dist/application/ReconstructionCoverageService.js +69 -0
  62. package/dist/application/ReconstructionCoverageWorkspaceStore.js +31 -0
  63. package/dist/application/RuntimeExecutableDiagnostics.js +172 -0
  64. package/dist/application/Setup.js +148 -260
  65. package/dist/application/SetupClientConfiguration.js +224 -0
  66. package/dist/application/SetupClients.js +24 -2
  67. package/dist/application/SetupPlan.js +124 -12
  68. package/dist/application/SetupSkill.js +54 -36
  69. package/dist/application/SupportedClients.js +1 -0
  70. package/dist/application/Uninstall.js +12 -3
  71. package/dist/application/Upgrade.js +16 -1
  72. package/dist/application/WindowsCapabilities.js +86 -0
  73. package/dist/artifacts/AsarArtifactReader.js +11 -0
  74. package/dist/browser/BrowserProcessStartup.js +88 -0
  75. package/dist/browser/CdpCaptureDocuments.js +12 -8
  76. package/dist/browser/CdpCaptureEventBodyShapes.js +75 -0
  77. package/dist/browser/CdpCaptureEventHandlers.js +336 -0
  78. package/dist/browser/CdpCaptureEventHelpers.js +71 -0
  79. package/dist/browser/CdpCaptureEventState.js +1 -0
  80. package/dist/browser/CdpCaptureEventTypes.js +1 -0
  81. package/dist/browser/CdpCaptureEvents.js +29 -496
  82. package/dist/browser/CdpObservationSession.js +51 -8
  83. package/dist/browser/CdpPageCapture.js +12 -133
  84. package/dist/browser/CdpPageCaptureScripts.js +97 -0
  85. package/dist/browser/CdpPageCaptureWorkers.js +46 -0
  86. package/dist/browser/CdpWebMcpDiscovery.js +38 -14
  87. package/dist/browser/PngVisualDiff.js +9 -2
  88. package/dist/catalogIdentity.js +4 -0
  89. package/dist/cli/artifactCommands.js +82 -0
  90. package/dist/cli/coreAnalysisCommands.js +232 -0
  91. package/dist/cli/managedCommands.js +397 -0
  92. package/dist/cli/managedProjectGraphCommand.js +24 -0
  93. package/dist/cli/options.js +9 -0
  94. package/dist/cli/setupCommands.js +113 -0
  95. package/dist/cli/types.js +1 -0
  96. package/dist/cli/utilityCommands.js +122 -0
  97. package/dist/cli.js +10 -768
  98. package/dist/cliApplicationCommands.js +118 -4
  99. package/dist/cliBrowserAdvancedCommands.js +73 -16
  100. package/dist/cliBrowserCommands.js +39 -115
  101. package/dist/cliCommandNames.js +4 -0
  102. package/dist/cliElectronCommands.js +33 -62
  103. package/dist/cliEvidenceCommands.js +13 -2
  104. package/dist/cliInvestigationCommands.js +53 -10
  105. package/dist/cliObservationOptions.js +137 -0
  106. package/dist/cliPolicyCommands.js +80 -46
  107. package/dist/cliSetup.js +306 -0
  108. package/dist/config/environment.js +107 -0
  109. package/dist/config/parseConfig.js +228 -0
  110. package/dist/config/parsers.js +68 -0
  111. package/dist/config/permissions.js +30 -0
  112. package/dist/config/types.js +1 -0
  113. package/dist/config.js +1 -375
  114. package/dist/contracts/applicationToolContracts.js +134 -0
  115. package/dist/contracts/electronToolContracts.js +51 -3
  116. package/dist/contracts/managedToolContracts.js +8 -3
  117. package/dist/contracts/managedWorkflowToolContracts.js +3 -3
  118. package/dist/contracts/providerSelection.js +2 -0
  119. package/dist/contracts/sessionStatusContract.js +26 -0
  120. package/dist/contracts/toolContractTypes.js +12 -1
  121. package/dist/contracts/toolContracts.js +5 -12
  122. package/dist/contracts/toolEffects.js +14 -0
  123. package/dist/contracts/toolOutputSchemaGroups.js +274 -0
  124. package/dist/contracts/toolOutputSchemaPrimitives.js +328 -0
  125. package/dist/contracts/toolOutputSchemas.js +2 -550
  126. package/dist/domain/analysisErrorPresentation.js +234 -0
  127. package/dist/domain/analysisErrorProjection.js +284 -0
  128. package/dist/domain/androidApplication.js +206 -0
  129. package/dist/domain/appleApplication.js +221 -0
  130. package/dist/domain/artifactComparison.js +34 -15
  131. package/dist/domain/binaryTarget.js +87 -37
  132. package/dist/domain/boundedCartesianProjection.js +15 -0
  133. package/dist/domain/browserObservation.js +1 -285
  134. package/dist/domain/browserObservationSchemas.js +286 -0
  135. package/dist/domain/electronStaticAnalysisBrowser.js +14 -2
  136. package/dist/domain/errors.js +4 -486
  137. package/dist/domain/functionComparison.js +4 -165
  138. package/dist/domain/functionComparisonDimensions.js +164 -0
  139. package/dist/domain/javascriptApplicationVersionItems.js +18 -6
  140. package/dist/domain/javascriptApplicationVersionKeys.js +8 -8
  141. package/dist/domain/javascriptExportInstrumentation.js +97 -0
  142. package/dist/domain/javascriptFeatureTraversal.js +19 -7
  143. package/dist/domain/javascriptRuntimeStaticCandidates.js +3 -1
  144. package/dist/domain/javascriptSemanticAnalysis.js +386 -0
  145. package/dist/domain/javascriptSemanticIr.js +30 -0
  146. package/dist/domain/javascriptSemanticProjection.js +366 -0
  147. package/dist/domain/javascriptSemanticState.js +40 -0
  148. package/dist/domain/javascriptSemanticTraversal.js +22 -0
  149. package/dist/domain/javascriptSemanticValues.js +352 -0
  150. package/dist/domain/javascriptStaticAnalysis.js +5 -221
  151. package/dist/domain/javascriptStaticAnalysisBundler.js +209 -0
  152. package/dist/domain/javascriptStaticAnalysisCalls.js +180 -0
  153. package/dist/domain/javascriptStaticAnalysisHelpers.js +71 -2
  154. package/dist/domain/knownPageCoverage.js +21 -0
  155. package/dist/domain/managedApplicationGraph.js +14 -364
  156. package/dist/domain/managedApplicationGraphCoverage.js +170 -0
  157. package/dist/domain/managedApplicationGraphNodeCoverage.js +6 -0
  158. package/dist/domain/managedApplicationGraphNodes.js +336 -0
  159. package/dist/domain/managedArtifact.js +16 -8
  160. package/dist/domain/managedMemberComparison.js +37 -391
  161. package/dist/domain/managedMemberComparisonCoverage.js +72 -0
  162. package/dist/domain/managedMemberComparisonMatch.js +356 -0
  163. package/dist/domain/managedNativeVerification.js +27 -389
  164. package/dist/domain/managedNativeVerificationMatch.js +272 -0
  165. package/dist/domain/managedNativeVerificationSchemas.js +141 -0
  166. package/dist/domain/managedReconstruction.js +82 -69
  167. package/dist/domain/managedRuntimeCorrelation.js +12 -3
  168. package/dist/domain/nodeRuntimeCharacterization.js +66 -0
  169. package/dist/domain/permissionPolicy.js +2 -0
  170. package/dist/domain/processComparison.js +19 -0
  171. package/dist/domain/processPairedExperiment.js +128 -0
  172. package/dist/domain/reconstructionCoverage.js +387 -0
  173. package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
  174. package/dist/domain/reconstructionVerificationSchemas.js +8 -0
  175. package/dist/domain/replayMachine.js +316 -0
  176. package/dist/domain/replayMachineRuntime.js +215 -0
  177. package/dist/domain/runtimeCharacterization.js +85 -0
  178. package/dist/domain/runtimeIdentification.js +210 -0
  179. package/dist/domain/webBundleAnalyzer.js +3 -409
  180. package/dist/domain/webBundleAnalyzerAst.js +77 -0
  181. package/dist/domain/webBundleAnalyzerInspection.js +307 -0
  182. package/dist/domain/webBundleAnalyzerResult.js +120 -0
  183. package/dist/dotnet/ManagedArtifactInspector.js +50 -29
  184. package/dist/dotnet/ManagedMemberInspector.js +51 -785
  185. package/dist/dotnet/ManagedMemberInspectorCore.js +297 -0
  186. package/dist/dotnet/ManagedMemberInstructionDecoder.js +427 -0
  187. package/dist/dotnet/ManagedMemberRows.js +120 -0
  188. package/dist/dotnet/ManagedMetadataInventory.js +42 -306
  189. package/dist/dotnet/ManagedMetadataInventoryRows.js +292 -0
  190. package/dist/dotnet/ManagedMetadataLayout.js +48 -111
  191. package/dist/dotnet/ManagedMetadataRowSizes.js +54 -0
  192. package/dist/dotnet/ManagedMethodBodyReader.js +143 -0
  193. package/dist/dotnet/ManagedNativeBoundaryHelpers.js +311 -0
  194. package/dist/dotnet/ManagedNativeBoundaryInspector.js +102 -350
  195. package/dist/dotnet/ManagedPeReader.js +59 -28
  196. package/dist/evaluation/CodexAgentEval.js +132 -0
  197. package/dist/generatedPackageMetadata.js +2 -2
  198. package/dist/ghidra/GhidraClient.js +76 -91
  199. package/dist/ghidra/GhidraClientStartup.js +29 -0
  200. package/dist/ghidra/GhidraClientWire.js +34 -0
  201. package/dist/ghidra/GhidraDefaults.js +1 -1
  202. package/dist/ghidra/GhidraDiagnostics.js +6 -1
  203. package/dist/ghidra/GhidraInstallation.js +20 -15
  204. package/dist/ghidra/GhidraLauncher.js +93 -29
  205. package/dist/ghidra/GhidraProvider.js +61 -161
  206. package/dist/ghidra/GhidraProviderCapabilities.js +173 -0
  207. package/dist/ghidra/GhidraSessionValues.js +2 -0
  208. package/dist/ghidra/GhidraSocketConnection.js +44 -7
  209. package/dist/ghidra/GhidraTargetSnapshot.js +30 -0
  210. package/dist/ghidra/GhidraTransport.js +71 -0
  211. package/dist/identity.js +4 -2
  212. package/dist/main/messages.js +5 -0
  213. package/dist/main/reload.js +49 -0
  214. package/dist/main/shutdown.js +25 -0
  215. package/dist/main/startup.js +14 -0
  216. package/dist/main/state.js +26 -0
  217. package/dist/main/transport.js +61 -0
  218. package/dist/main/types.js +1 -0
  219. package/dist/main.js +35 -146
  220. package/dist/process/PrivateRuntimeRoot.js +3 -2
  221. package/dist/process/ProcessOwnership.js +35 -0
  222. package/dist/process/ProviderProcess.js +2 -0
  223. package/dist/replay/JavaScriptReplayWorker.js +64 -50
  224. package/dist/replay/LinuxJavaScriptReplayRunner.js +173 -390
  225. package/dist/replay/LinuxJavaScriptReplaySandbox.js +140 -0
  226. package/dist/replay/ReplayOutcome.js +95 -0
  227. package/dist/replay/ReplayProcessLifecycle.js +71 -0
  228. package/dist/server/ProcessCaptureElicitation.js +157 -0
  229. package/dist/server/createServer.js +124 -56
  230. package/dist/server/javascriptApplicationResult.js +85 -0
  231. package/dist/server/registerApplicationTools/characterization.js +57 -0
  232. package/dist/server/registerApplicationTools/compareVersions.js +34 -0
  233. package/dist/server/registerApplicationTools/controlledReplay.js +38 -0
  234. package/dist/server/registerApplicationTools/coverage.js +84 -0
  235. package/dist/server/registerApplicationTools/helpers.js +42 -0
  236. package/dist/server/registerApplicationTools/traceFeature.js +26 -0
  237. package/dist/server/registerApplicationTools/types.js +1 -0
  238. package/dist/server/registerApplicationTools.js +10 -112
  239. package/dist/server/registerBrowserTools.js +59 -83
  240. package/dist/server/registerElectronTools.js +48 -49
  241. package/dist/server/registerEnhancedTools.js +34 -42
  242. package/dist/server/registerEvidenceResources.js +56 -0
  243. package/dist/server/registerInvestigationTools/helpers.js +74 -0
  244. package/dist/server/registerInvestigationTools/types.js +1 -0
  245. package/dist/server/registerInvestigationTools.js +83 -116
  246. package/dist/server/registerJavaScriptApplicationGraphResource.js +69 -0
  247. package/dist/server/registerManagedTools.js +18 -1
  248. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +65 -0
  249. package/dist/server/registerManagedWorkflowTools/contract.js +8 -0
  250. package/dist/server/registerManagedWorkflowTools/evidence.js +43 -0
  251. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +39 -0
  252. package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +39 -0
  253. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +52 -0
  254. package/dist/server/registerManagedWorkflowTools/types.js +1 -0
  255. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +75 -0
  256. package/dist/server/registerManagedWorkflowTools.js +10 -274
  257. package/dist/server/registerOfficialTools.js +73 -59
  258. package/dist/server/registerSessionRecordTools.js +137 -0
  259. package/dist/server/registerSessionStatusTool.js +97 -26
  260. package/dist/server/registerSessionTools.js +60 -164
  261. package/dist/server/sessionAvailabilityPolicy.js +10 -0
  262. package/dist/server/toolRegistrationOptions.js +101 -3
  263. package/dist/server/toolResult.js +15 -4
  264. package/package.json +11 -11
  265. package/skills/reverse-engineer-anything/SKILL.md +76 -0
  266. package/skills/reverse-engineer-anything/references/controlled-replay.md +12 -0
  267. package/skills/reverse-engineer-anything/references/evidence-workflows.md +33 -0
  268. package/skills/reverse-engineer-anything/references/javascript-applications.md +25 -0
  269. package/skills/reverse-engineer-anything/references/native-and-artifacts.md +36 -0
  270. package/skills/reverse-engineer-anything/references/runtime-observation.md +24 -0
  271. package/scripts/prepare-node-pty.mjs +0 -35
  272. package/scripts/rebuild-native.mjs +0 -22
  273. package/skills/rea-analysis/SKILL.md +0 -222
@@ -1,9 +1,9 @@
1
1
  import { mkdir } from "node:fs/promises";
2
- import { basename, dirname, join } from "node:path";
2
+ import { basename, dirname, join, win32 } from "node:path";
3
3
  import writeFileAtomic from "write-file-atomic";
4
4
  import { AnalysisCancelledError } from "../domain/errors.js";
5
5
  import { err, ok } from "../domain/result.js";
6
- import { cleanupOwnedProcessGroup } from "../process/ProcessOwnership.js";
6
+ import { cleanupOwnedProcessGroup, cleanupWindowsProcessTree, } from "../process/ProcessOwnership.js";
7
7
  import { spawnOwnedProviderProcess, } from "../process/ProviderProcess.js";
8
8
  import { GHIDRA_ANALYSIS_TIMEOUT_SECONDS, GHIDRA_MAX_CPU, GHIDRA_MAX_HEAP, } from "./GhidraDefaults.js";
9
9
  import { ghidraJavaEnvironment } from "./GhidraInstallation.js";
@@ -24,6 +24,7 @@ export class GhidraHeadlessLauncher {
24
24
  if (isAborted(options.signal))
25
25
  return err(new AnalysisCancelledError("open_binary"));
26
26
  const paths = ghidraRuntimePaths(session.runtimeRoot);
27
+ const platform = this.options.platform ?? process.platform;
27
28
  let started;
28
29
  try {
29
30
  await Promise.all([
@@ -35,30 +36,42 @@ export class GhidraHeadlessLauncher {
35
36
  paths.dataRoot,
36
37
  ].map((path) => mkdir(path, { recursive: true, mode: 0o700 })));
37
38
  await writeFileAtomic(paths.descriptorPath, `${JSON.stringify({
38
- schema_version: 1,
39
- socket_path: session.socketPath,
39
+ schema_version: 2,
40
+ transport: session.transport,
41
+ endpoint_path: session.endpointPath,
40
42
  token: session.token,
41
43
  run_id: session.runId,
44
+ target_sha256: session.targetSha256,
42
45
  provider_version: session.providerVersion,
43
46
  profile_digest: session.profileDigest,
44
47
  })}\n`, { encoding: "utf8", mode: 0o600 });
45
48
  if (isAborted(options.signal))
46
49
  return err(new AnalysisCancelledError("open_binary"));
50
+ const headlessArguments = ghidraHeadlessArguments({
51
+ projectRoot: paths.projectRoot,
52
+ targetPath: session.targetPath,
53
+ bridgeScriptPath: this.options.bridgeScriptPath,
54
+ descriptorPath: paths.descriptorPath,
55
+ ghidraLogPath: paths.ghidraLogPath,
56
+ scriptLogPath: paths.scriptLogPath,
57
+ });
58
+ const command = ghidraHeadlessCommand({
59
+ platform,
60
+ analyzeHeadlessPath: this.options.analyzeHeadlessPath,
61
+ arguments: headlessArguments,
62
+ ...(this.options.comSpec === undefined
63
+ ? {}
64
+ : { comSpec: this.options.comSpec }),
65
+ });
47
66
  started = await spawnOwnedProviderProcess({
48
- command: this.options.analyzeHeadlessPath,
49
- arguments: ghidraHeadlessArguments({
50
- projectRoot: paths.projectRoot,
51
- targetPath: session.targetPath,
52
- bridgeScriptPath: this.options.bridgeScriptPath,
53
- descriptorPath: paths.descriptorPath,
54
- ghidraLogPath: paths.ghidraLogPath,
55
- scriptLogPath: paths.scriptLogPath,
56
- }),
67
+ command: command.command,
68
+ arguments: command.arguments,
57
69
  runId: session.runId,
58
70
  // analyzeHeadless is an interpreter-driven script. Parent identity and
59
71
  // the per-process run token remain the cleanup authority.
60
72
  expectedCommand: null,
61
- env: ghidraLaunchEnvironment(paths, this.options.javaHome),
73
+ windowsVerbatimArguments: platform === "win32",
74
+ env: ghidraLaunchEnvironment(paths, this.options.javaHome, platform),
62
75
  });
63
76
  await writeFileAtomic(paths.ownershipPath, `${JSON.stringify({
64
77
  schema_version: 1,
@@ -66,18 +79,21 @@ export class GhidraHeadlessLauncher {
66
79
  pid: started.ownership.leaderPid,
67
80
  process_group_id: started.ownership.processGroupId,
68
81
  parent_pid: process.pid,
82
+ ownership_kind: platform === "win32"
83
+ ? "windows-process-tree-p0"
84
+ : "posix-process-group",
69
85
  launcher: this.options.analyzeHeadlessPath,
70
86
  created_at: new Date().toISOString(),
71
87
  })}\n`, { encoding: "utf8", mode: 0o600 });
72
88
  if (isAborted(options.signal)) {
73
- await cleanupOwnedProcessGroup(started.ownership);
89
+ await cleanupStartedProcess(started, platform);
74
90
  return err(new AnalysisCancelledError("open_binary"));
75
91
  }
76
- const ownership = started.ownership;
92
+ const spawned = started;
77
93
  return ok({
78
- process: started.process,
94
+ process: spawned.process,
79
95
  ownsProcessLifetime: true,
80
- cleanup: () => cleanupOwnedProcessGroup(ownership),
96
+ cleanup: () => cleanupStartedProcess(spawned, platform),
81
97
  projectRoot: paths.projectRoot,
82
98
  ghidraLogPath: paths.ghidraLogPath,
83
99
  scriptLogPath: paths.scriptLogPath,
@@ -85,13 +101,49 @@ export class GhidraHeadlessLauncher {
85
101
  }
86
102
  catch (cause) {
87
103
  if (started !== undefined)
88
- await cleanupOwnedProcessGroup(started.ownership).catch(() => undefined);
104
+ await cleanupStartedProcess(started, platform).catch(() => undefined);
89
105
  return isAborted(options.signal)
90
106
  ? err(new AnalysisCancelledError("open_binary"))
91
107
  : err(new GhidraLaunchError("Ghidra headless launch failed", { cause }));
92
108
  }
93
109
  }
94
110
  }
111
+ /** Build a direct POSIX launch or a conservatively quoted Windows batch call. */
112
+ export const ghidraHeadlessCommand = (options) => {
113
+ if (options.platform !== "win32")
114
+ return {
115
+ command: options.analyzeHeadlessPath,
116
+ arguments: [...options.arguments],
117
+ };
118
+ const comSpec = options.comSpec ??
119
+ process.env.ComSpec ??
120
+ (process.env.SystemRoot === undefined
121
+ ? "C:\\Windows\\System32\\cmd.exe"
122
+ : win32.join(process.env.SystemRoot, "System32", "cmd.exe"));
123
+ if (!win32.isAbsolute(comSpec) ||
124
+ win32.basename(comSpec).toLowerCase() !== "cmd.exe")
125
+ throw new GhidraLaunchError("Windows ComSpec must be an absolute cmd.exe path");
126
+ const tokens = [options.analyzeHeadlessPath, ...options.arguments].map(quoteWindowsBatchToken);
127
+ const invocation = `"${tokens.join(" ")}"`;
128
+ if (invocation.length > 30_000)
129
+ throw new GhidraLaunchError("Windows Ghidra command exceeds the P0 length limit");
130
+ return {
131
+ command: comSpec,
132
+ arguments: ["/d", "/e:on", "/v:off", "/s", "/c", invocation],
133
+ };
134
+ };
135
+ const quoteWindowsBatchToken = (value) => {
136
+ if (value.length === 0 ||
137
+ value.includes("\0") ||
138
+ value.includes("\r") ||
139
+ value.includes("\n") ||
140
+ /["%^!&|<>]/u.test(value))
141
+ throw new GhidraLaunchError("Windows Ghidra P0 paths cannot contain command-interpreter metacharacters");
142
+ return `"${value}"`;
143
+ };
144
+ const cleanupStartedProcess = (started, platform) => platform === "win32"
145
+ ? cleanupWindowsProcessTree(started.ownership.leaderPid)
146
+ : cleanupOwnedProcessGroup(started.ownership);
95
147
  /** Build the complete read-only headless invocation in deterministic order. */
96
148
  export const ghidraHeadlessArguments = (options) => [
97
149
  options.projectRoot,
@@ -126,14 +178,26 @@ const ghidraRuntimePaths = (runtimeRoot) => ({
126
178
  ghidraLogPath: join(runtimeRoot, "ghidra.log"),
127
179
  scriptLogPath: join(runtimeRoot, "script.log"),
128
180
  });
129
- const ghidraLaunchEnvironment = (paths, javaHome) => ({
130
- ...ghidraJavaEnvironment(javaHome),
131
- HOME: paths.homeRoot,
132
- TMPDIR: paths.tempRoot,
133
- XDG_CACHE_HOME: paths.cacheRoot,
134
- XDG_CONFIG_HOME: paths.configRoot,
135
- XDG_DATA_HOME: paths.dataRoot,
136
- GHIDRA_HEADLESS_MAXMEM: GHIDRA_MAX_HEAP,
137
- GHIDRA_HEADLESS_JAVA_OPTIONS: `-Duser.home=${paths.homeRoot} -Djava.io.tmpdir=${paths.tempRoot}`,
138
- });
181
+ const ghidraLaunchEnvironment = (paths, javaHome, platform) => {
182
+ const javaOptions = platform === "win32"
183
+ ? `"-Duser.home=${paths.homeRoot}" "-Djava.io.tmpdir=${paths.tempRoot}"`
184
+ : `-Duser.home=${paths.homeRoot} -Djava.io.tmpdir=${paths.tempRoot}`;
185
+ return {
186
+ ...ghidraJavaEnvironment(javaHome, process.env, platform),
187
+ HOME: paths.homeRoot,
188
+ TMPDIR: paths.tempRoot,
189
+ ...(platform === "win32"
190
+ ? {
191
+ USERPROFILE: paths.homeRoot,
192
+ TEMP: paths.tempRoot,
193
+ TMP: paths.tempRoot,
194
+ }
195
+ : {}),
196
+ XDG_CACHE_HOME: paths.cacheRoot,
197
+ XDG_CONFIG_HOME: paths.configRoot,
198
+ XDG_DATA_HOME: paths.dataRoot,
199
+ GHIDRA_HEADLESS_MAXMEM: GHIDRA_MAX_HEAP,
200
+ GHIDRA_HEADLESS_JAVA_OPTIONS: javaOptions,
201
+ };
202
+ };
139
203
  const isAborted = (signal) => signal?.aborted === true;
@@ -2,169 +2,18 @@ import { fileURLToPath } from "node:url";
2
2
  import { createAnalysisExecution, } from "../application/AnalysisProvider.js";
3
3
  import { AnalysisCancelledError, AnalysisCapabilityUnavailableError, AnalysisInputError, AnalysisTimeoutError, ProviderAdapterError, } from "../domain/errors.js";
4
4
  import { err, ok } from "../domain/result.js";
5
- import { ENHANCED_TOOL_CONTRACTS, OFFICIAL_TOOL_CONTRACTS, } from "../contracts/toolContracts.js";
6
5
  import { GhidraClient } from "./GhidraClient.js";
7
- import { GHIDRA_ANALYSIS_TIMEOUT_SECONDS, GHIDRA_DECOMPILE_REQUEST_TIMEOUT_MS, GHIDRA_DECOMPILE_TIMEOUT_SECONDS, GHIDRA_MAX_LINE_BYTES, GHIDRA_REQUEST_TIMEOUT_MS, GHIDRA_STARTUP_TIMEOUT_MS, } from "./GhidraDefaults.js";
8
- import { GHIDRA_FUNCTION_OPERATIONS, isGhidraFunctionOperation, parseGhidraFunctionInput, parseGhidraFunctionResult, } from "./GhidraFunctionValues.js";
9
- import { GHIDRA_INVENTORY_OPERATIONS, isGhidraInventoryOperation, parseGhidraInventoryInput, parseGhidraInventoryResult, } from "./GhidraInventoryValues.js";
6
+ import { GHIDRA_ANALYSIS_TIMEOUT_SECONDS, GHIDRA_DECOMPILE_REQUEST_TIMEOUT_MS, GHIDRA_DECOMPILE_TIMEOUT_SECONDS, GHIDRA_STARTUP_TIMEOUT_MS, } from "./GhidraDefaults.js";
7
+ import { isGhidraFunctionOperation, parseGhidraFunctionInput, parseGhidraFunctionResult, } from "./GhidraFunctionValues.js";
8
+ import { isGhidraInventoryOperation, parseGhidraInventoryInput, parseGhidraInventoryResult, } from "./GhidraInventoryValues.js";
10
9
  import { ghidraInstallationDiagnostics, inspectGhidraInstallation, } from "./GhidraInstallation.js";
11
10
  import { GhidraHeadlessLauncher } from "./GhidraLauncher.js";
12
11
  import { resolveGhidraAnalysisProfile } from "./GhidraAnalysisProfile.js";
13
- /** Public identity committed by every Ghidra-backed observation. */
14
- export const GHIDRA_PROVIDER_IDENTITY = Object.freeze({
15
- id: "ghidra",
16
- name: "Ghidra",
17
- version: null,
18
- });
19
- const providerContractByName = new Map([...OFFICIAL_TOOL_CONTRACTS, ...ENHANCED_TOOL_CONTRACTS].map((contract) => [
20
- contract.name,
21
- contract,
22
- ]));
23
- /** Provider-neutral read-only contracts implemented by the Ghidra adapter. */
24
- export const GHIDRA_PROVIDER_TOOL_CONTRACTS = Object.freeze([...GHIDRA_INVENTORY_OPERATIONS, ...GHIDRA_FUNCTION_OPERATIONS].map((operation) => {
25
- const contract = providerContractByName.get(operation);
26
- if (contract === undefined)
27
- throw new TypeError(`Missing provider-neutral contract for ${operation}`);
28
- return contract;
29
- }));
30
- const PAGINATED_OPERATIONS = new Set([
31
- "list_names",
32
- "list_procedures",
33
- "list_strings",
34
- "search_procedures",
35
- "search_strings",
36
- "procedure_references",
37
- "analyze_function",
38
- ]);
39
- const SEARCH_OPERATIONS = new Set([
40
- "search_procedures",
41
- "search_strings",
42
- ]);
43
- const DECOMPILE_OPERATIONS = new Set([
44
- "procedure_pseudo_code",
45
- "analyze_function",
46
- ]);
47
- const healthLimitations = Object.freeze([
48
- "The session serves operations only after default Ghidra auto-analysis completes; an analysis timeout fails the open instead of exposing partial results.",
49
- "The imported Program and temporary project are ephemeral, read-only to REA, and deleted on close.",
50
- ]);
51
- const limitationsFor = (operation) => {
52
- const common = [
53
- ...healthLimitations,
54
- "Default-space addresses use lowercase 0x-prefixed hexadecimal; other address spaces use <percent-encoded-space>:0x<hex>.",
55
- ];
56
- switch (operation) {
57
- case "list_documents":
58
- return [
59
- ...common,
60
- "A headless Ghidra session contains exactly one imported Program, unlike Hopper's multi-document GUI session.",
61
- ];
62
- case "list_names":
63
- return [
64
- ...common,
65
- "The symbol inventory includes memory and external symbols, including dynamic symbols, but excludes variable and no-address namespace records.",
66
- ];
67
- case "list_procedures":
68
- case "procedure_address":
69
- return [
70
- ...common,
71
- "External functions and local thunks are distinct; procedure metadata identifies both and preserves a thunk target when Ghidra resolves one.",
72
- ];
73
- case "list_strings":
74
- return [
75
- ...common,
76
- "Only Ghidra-defined string Data is observed; charset is reported, while a non-missing terminator cannot distinguish a present terminator from a fixed or Pascal layout.",
77
- "Returned values are bounded to 1,024 Unicode code points and mark value_truncated instead of silently crossing the wire budget.",
78
- ];
79
- case "list_segments":
80
- return [
81
- ...common,
82
- "Memory-block end addresses are exclusive; permissions come from Ghidra MemoryBlock flags rather than inference from section names.",
83
- ];
84
- case "search_procedures":
85
- case "search_strings":
86
- return [
87
- ...common,
88
- "Literal search enforces 1,000,000 cumulative work units; regex mode also accepts only a conservative finite Java-regex subset with 10,000 static paths and 4,096 UTF-16 code units per candidate.",
89
- ];
90
- case "procedure_pseudo_code":
91
- return [
92
- ...common,
93
- "Pseudocode is Ghidra decompiler output, not original source and not text-equivalent to Hopper output; each decompile has a 30-second native deadline.",
94
- "External functions and functions without an analyzable body return null; other decompiler failures remain explicit.",
95
- ];
96
- case "procedure_assembly":
97
- return [
98
- ...common,
99
- "Assembly is Ghidra Listing text and fails rather than silently truncating when the 100,000-instruction or 1 MiB wire bound is exceeded.",
100
- ];
101
- case "procedure_callers":
102
- case "procedure_callees":
103
- return [
104
- ...common,
105
- "Only resolved Ghidra call references are returned; unresolved computed or indirect calls remain unknown, while function classifications distinguish thunks and externals.",
106
- ];
107
- case "xrefs":
108
- return [
109
- ...common,
110
- "The direct address list projects exact Ghidra references to one address but does not expose their kinds; procedure_references and analyze_function preserve available kind metadata.",
111
- "Synthetic Ghidra entry-point references without actionable memory sources are omitted.",
112
- ];
113
- case "procedure_references":
114
- return [
115
- ...common,
116
- "Reference kinds are direct Ghidra ReferenceManager observations; unresolved computed flows without a target are absent and remain unknown.",
117
- "Synthetic Ghidra entry-point references without actionable memory sources are omitted.",
118
- "Instruction scans stop at max_instructions; a truncated scan reports an unknown total and no false continuation.",
119
- ];
120
- case "analyze_function":
121
- return [
122
- ...common,
123
- "The dossier combines Ghidra FunctionManager, Listing, ReferenceManager, BasicBlockModel, and decompiler observations; provider-specific pseudocode and assembly are not cross-provider text invariants.",
124
- "Resolved reference metadata identifies computed, indirect, external, call, jump, and data edges; unresolved targetless flows remain unknown, and function classifications distinguish thunks and externals.",
125
- "Synthetic Ghidra entry-point references without actionable memory sources are omitted.",
126
- "The Java bridge serializes one function request per Program through a bounded 32-request queue and applies a 30-second native decompilation deadline.",
127
- ];
128
- default:
129
- return common;
130
- }
131
- };
132
- const CAPABILITIES = Object.freeze(GHIDRA_PROVIDER_TOOL_CONTRACTS.map((contract) => Object.freeze({
133
- provider: GHIDRA_PROVIDER_IDENTITY,
134
- operation: contract.name,
135
- inputContractVersion: 1,
136
- outputContractVersion: 1,
137
- available: true,
138
- reason: null,
139
- pagination: PAGINATED_OPERATIONS.has(contract.name)
140
- ? "offset"
141
- : "none",
142
- exhaustive: !PAGINATED_OPERATIONS.has(contract.name),
143
- effects: Object.freeze({
144
- mutatesArtifact: false,
145
- launchesProcess: true,
146
- mayShowUi: false,
147
- mayAccessNetwork: false,
148
- mayWriteFilesystem: true,
149
- changesPermissions: false,
150
- requiresRoot: false,
151
- }),
152
- limits: Object.freeze({
153
- maxResults: PAGINATED_OPERATIONS.has(contract.name)
154
- ? SEARCH_OPERATIONS.has(contract.name)
155
- ? 100
156
- : 500
157
- : null,
158
- maxPayloadBytes: GHIDRA_MAX_LINE_BYTES,
159
- timeoutMs: DECOMPILE_OPERATIONS.has(contract.name)
160
- ? GHIDRA_DECOMPILE_REQUEST_TIMEOUT_MS
161
- : GHIDRA_REQUEST_TIMEOUT_MS,
162
- }),
163
- limitations: Object.freeze(limitationsFor(contract.name)),
164
- })));
12
+ import { CAPABILITIES, WINDOWS_P0_CAPABILITIES, GHIDRA_PROVIDER_IDENTITY, GHIDRA_PROVIDER_TOOL_CONTRACTS, healthLimitations, windowsP0Limitations, limitationsFor, } from "./GhidraProviderCapabilities.js";
13
+ export { GHIDRA_PROVIDER_IDENTITY, GHIDRA_PROVIDER_TOOL_CONTRACTS };
165
14
  const SUPPORTED_ARCHITECTURES = new Set(["x86", "x86_64", "arm", "arm64"]);
166
15
  const SUPPORTED_FORMATS = new Set(["elf", "pe", "mach-o"]);
167
- /** Linux Ghidra candidate backed by an isolated read-only headless import. */
16
+ /** Ghidra candidate backed by an isolated read-only headless import. */
168
17
  export class GhidraProvider {
169
18
  config;
170
19
  logger;
@@ -181,7 +30,9 @@ export class GhidraProvider {
181
30
  return GHIDRA_PROVIDER_IDENTITY;
182
31
  }
183
32
  capabilities() {
184
- return CAPABILITIES;
33
+ return (this.installationHost?.platform ?? process.platform) === "win32"
34
+ ? WINDOWS_P0_CAPABILITIES
35
+ : CAPABILITIES;
185
36
  }
186
37
  inspectAvailability() {
187
38
  const installation = this.#inspectInstallation();
@@ -201,10 +52,14 @@ export class GhidraProvider {
201
52
  };
202
53
  }
203
54
  inspectTargetSupport(target) {
55
+ const hostPlatform = this.installationHost?.platform ?? process.platform;
204
56
  const diagnostics = {
57
+ host_platform: hostPlatform,
205
58
  target_kind: target.kind,
206
59
  target_format: target.format,
207
60
  architecture: target.architecture ?? null,
61
+ executable_role: target.executableRole ?? null,
62
+ managed: target.managed ?? null,
208
63
  };
209
64
  if (target.kind !== "executable")
210
65
  return {
@@ -213,6 +68,8 @@ export class GhidraProvider {
213
68
  reason: `Ghidra v1 imports executable targets, not ${target.kind} targets.`,
214
69
  diagnostics,
215
70
  };
71
+ if (hostPlatform === "win32")
72
+ return inspectWindowsP0TargetSupport(target, diagnostics);
216
73
  if (!SUPPORTED_FORMATS.has(target.format))
217
74
  return {
218
75
  status: "unsupported",
@@ -244,6 +101,7 @@ export class GhidraProvider {
244
101
  if (!prerequisites.ok)
245
102
  return unavailableClient(prerequisites.error);
246
103
  const committedProfile = prerequisites.value.profile;
104
+ const providerLimitations = installation.platform === "win32" ? windowsP0Limitations : [];
247
105
  const client = this.clientFactory({
248
106
  launcher: new GhidraHeadlessLauncher({
249
107
  analyzeHeadlessPath: prerequisites.value.analyzeHeadlessPath,
@@ -251,8 +109,13 @@ export class GhidraProvider {
251
109
  ? {}
252
110
  : { javaHome: this.config.ghidraJavaHome }),
253
111
  bridgeScriptPath: fileURLToPath(new URL("../../bridge/ghidra/ReaGhidraBridge.java", import.meta.url)),
112
+ platform: installation.platform,
254
113
  }),
255
114
  targetPath: target.path,
115
+ targetSha256: target.sha256,
116
+ transport: installation.platform === "win32"
117
+ ? "authenticated-loopback-tcp"
118
+ : "unix-socket",
256
119
  providerVersion: prerequisites.value.providerVersion,
257
120
  profileDigest: committedProfile.digest,
258
121
  logger: this.logger.child({ layer: "ghidra-bridge" }),
@@ -269,7 +132,7 @@ export class GhidraProvider {
269
132
  return err(projectSessionError(operation, started.error));
270
133
  return ok(createAnalysisExecution(started.value, committedProfile.provider, {
271
134
  analysisProfile: committedProfile,
272
- limitations: healthLimitations,
135
+ limitations: [...healthLimitations, ...providerLimitations],
273
136
  }));
274
137
  }
275
138
  const input = isGhidraFunctionOperation(operation)
@@ -279,7 +142,8 @@ export class GhidraProvider {
279
142
  return input;
280
143
  const called = await client.callTool(operation, input.value, {
281
144
  ...(options?.signal === undefined ? {} : { signal: options.signal }),
282
- ...(DECOMPILE_OPERATIONS.has(operation)
145
+ ...(operation === "procedure_pseudo_code" ||
146
+ operation === "analyze_function"
283
147
  ? { timeoutMs: GHIDRA_DECOMPILE_REQUEST_TIMEOUT_MS }
284
148
  : {}),
285
149
  });
@@ -293,7 +157,7 @@ export class GhidraProvider {
293
157
  return ok(createAnalysisExecution(result.value, committedProfile.provider, {
294
158
  rawResult: called.value,
295
159
  analysisProfile: committedProfile,
296
- limitations: limitationsFor(operation),
160
+ limitations: [...limitationsFor(operation), ...providerLimitations],
297
161
  }));
298
162
  },
299
163
  close: () => client.close(),
@@ -321,6 +185,42 @@ export class GhidraProvider {
321
185
  return this.#installation;
322
186
  }
323
187
  }
188
+ const inspectWindowsP0TargetSupport = (target, diagnostics) => {
189
+ if (target.format !== "pe")
190
+ return {
191
+ status: "unsupported",
192
+ code: "target_format_unsupported",
193
+ reason: "Windows Ghidra P0 accepts PE targets only.",
194
+ diagnostics,
195
+ };
196
+ if (target.architecture !== "x86_64")
197
+ return {
198
+ status: "unsupported",
199
+ code: "architecture_unsupported",
200
+ reason: "Windows Ghidra P0 accepts x86-64 PE targets only.",
201
+ diagnostics,
202
+ };
203
+ if (target.executableRole !== "application")
204
+ return {
205
+ status: "unsupported",
206
+ code: "target_role_unsupported",
207
+ reason: "Windows Ghidra P0 accepts PE applications, not DLL or non-executable images.",
208
+ diagnostics,
209
+ };
210
+ if (target.managed !== false)
211
+ return {
212
+ status: "unsupported",
213
+ code: "managed_target_unsupported",
214
+ reason: "Windows Ghidra P0 accepts native PE applications; managed or unclassified PE targets are unsupported.",
215
+ diagnostics,
216
+ };
217
+ return {
218
+ status: "supported",
219
+ code: null,
220
+ reason: null,
221
+ diagnostics,
222
+ };
223
+ };
324
224
  const ghidraClientPrerequisites = (target, profile, installation) => {
325
225
  if (target.kind !== "executable")
326
226
  return err(new AnalysisCapabilityUnavailableError("ghidra", "health", `Ghidra cannot import ${target.kind} targets through this adapter.`));
@@ -0,0 +1,173 @@
1
+ import { ENHANCED_TOOL_CONTRACTS, OFFICIAL_TOOL_CONTRACTS, } from "../contracts/toolContracts.js";
2
+ import { GHIDRA_DECOMPILE_REQUEST_TIMEOUT_MS, GHIDRA_MAX_LINE_BYTES, GHIDRA_REQUEST_TIMEOUT_MS, } from "./GhidraDefaults.js";
3
+ import { GHIDRA_FUNCTION_OPERATIONS } from "./GhidraFunctionValues.js";
4
+ import { GHIDRA_INVENTORY_OPERATIONS } from "./GhidraInventoryValues.js";
5
+ /** Public identity committed by every Ghidra-backed observation. */
6
+ export const GHIDRA_PROVIDER_IDENTITY = Object.freeze({
7
+ id: "ghidra",
8
+ name: "Ghidra",
9
+ version: null,
10
+ });
11
+ const providerContractByName = new Map([...OFFICIAL_TOOL_CONTRACTS, ...ENHANCED_TOOL_CONTRACTS].map((contract) => [
12
+ contract.name,
13
+ contract,
14
+ ]));
15
+ /** Provider-neutral read-only contracts implemented by the Ghidra adapter. */
16
+ export const GHIDRA_PROVIDER_TOOL_CONTRACTS = Object.freeze([...GHIDRA_INVENTORY_OPERATIONS, ...GHIDRA_FUNCTION_OPERATIONS].map((operation) => {
17
+ const contract = providerContractByName.get(operation);
18
+ if (contract === undefined)
19
+ throw new TypeError(`Missing provider-neutral contract for ${operation}`);
20
+ return contract;
21
+ }));
22
+ const PAGINATED_OPERATIONS = new Set([
23
+ "list_names",
24
+ "list_procedures",
25
+ "list_strings",
26
+ "search_procedures",
27
+ "search_strings",
28
+ "procedure_references",
29
+ "analyze_function",
30
+ ]);
31
+ const SEARCH_OPERATIONS = new Set([
32
+ "search_procedures",
33
+ "search_strings",
34
+ ]);
35
+ const DECOMPILE_OPERATIONS = new Set([
36
+ "procedure_pseudo_code",
37
+ "analyze_function",
38
+ ]);
39
+ /** Health limitations shared by every Ghidra-backed capability. */
40
+ export const healthLimitations = Object.freeze([
41
+ "The session serves operations only after default Ghidra auto-analysis completes; an analysis timeout fails the open instead of exposing partial results.",
42
+ "The imported Program and temporary project are ephemeral, read-only to REA, and deleted on close.",
43
+ ]);
44
+ /** Additional limitations applied to the experimental Windows x64 P0 boundary. */
45
+ export const windowsP0Limitations = Object.freeze([
46
+ "Windows Ghidra P0 accepts approved native x86-64 PE applications only; DLL, managed, hostile, sensitive, and mutable-path targets are unsupported.",
47
+ "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.",
48
+ "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.",
49
+ ]);
50
+ /** Limitation text for one admitted operation, including the common base. */
51
+ export const limitationsFor = (operation) => {
52
+ const common = [
53
+ ...healthLimitations,
54
+ "Default-space addresses use lowercase 0x-prefixed hexadecimal; other address spaces use <percent-encoded-space>:0x<hex>.",
55
+ ];
56
+ switch (operation) {
57
+ case "list_documents":
58
+ return [
59
+ ...common,
60
+ "A headless Ghidra session contains exactly one imported Program, unlike Hopper's multi-document GUI session.",
61
+ ];
62
+ case "list_names":
63
+ return [
64
+ ...common,
65
+ "The symbol inventory includes memory and external symbols, including dynamic symbols, but excludes variable and no-address namespace records.",
66
+ ];
67
+ case "list_procedures":
68
+ case "procedure_address":
69
+ return [
70
+ ...common,
71
+ "External functions and local thunks are distinct; procedure metadata identifies both and preserves a thunk target when Ghidra resolves one.",
72
+ ];
73
+ case "list_strings":
74
+ return [
75
+ ...common,
76
+ "Only Ghidra-defined string Data is observed; charset is reported, while a non-missing terminator cannot distinguish a present terminator from a fixed or Pascal layout.",
77
+ "Returned values are bounded to 1,024 Unicode code points and mark value_truncated instead of silently crossing the wire budget.",
78
+ ];
79
+ case "list_segments":
80
+ return [
81
+ ...common,
82
+ "Memory-block end addresses are exclusive; permissions come from Ghidra MemoryBlock flags rather than inference from section names.",
83
+ ];
84
+ case "search_procedures":
85
+ case "search_strings":
86
+ return [
87
+ ...common,
88
+ "Literal search enforces 1,000,000 cumulative work units; regex mode also accepts only a conservative finite Java-regex subset with 10,000 static paths and 4,096 UTF-16 code units per candidate.",
89
+ ];
90
+ case "procedure_pseudo_code":
91
+ return [
92
+ ...common,
93
+ "Pseudocode is Ghidra decompiler output, not original source and not text-equivalent to Hopper output; each decompile has a 30-second native deadline.",
94
+ "External functions and functions without an analyzable body return null; other decompiler failures remain explicit.",
95
+ ];
96
+ case "procedure_assembly":
97
+ return [
98
+ ...common,
99
+ "Assembly is Ghidra Listing text and fails rather than silently truncating when the 100,000-instruction or 1 MiB wire bound is exceeded.",
100
+ ];
101
+ case "procedure_callers":
102
+ case "procedure_callees":
103
+ return [
104
+ ...common,
105
+ "Only resolved Ghidra call references are returned; unresolved computed or indirect calls remain unknown, while function classifications distinguish thunks and externals.",
106
+ ];
107
+ case "xrefs":
108
+ return [
109
+ ...common,
110
+ "The direct address list projects exact Ghidra references to one address but does not expose their kinds; procedure_references and analyze_function preserve available kind metadata.",
111
+ "Synthetic Ghidra entry-point references without actionable memory sources are omitted.",
112
+ ];
113
+ case "procedure_references":
114
+ return [
115
+ ...common,
116
+ "Reference kinds are direct Ghidra ReferenceManager observations; unresolved computed flows without a target are absent and remain unknown.",
117
+ "Synthetic Ghidra entry-point references without actionable memory sources are omitted.",
118
+ "Instruction scans stop at max_instructions; a truncated scan reports an unknown total and no false continuation.",
119
+ ];
120
+ case "analyze_function":
121
+ return [
122
+ ...common,
123
+ "The dossier combines Ghidra FunctionManager, Listing, ReferenceManager, BasicBlockModel, and decompiler observations; provider-specific pseudocode and assembly are not cross-provider text invariants.",
124
+ "Resolved reference metadata identifies computed, indirect, external, call, jump, and data edges; unresolved targetless flows remain unknown, and function classifications distinguish thunks and externals.",
125
+ "Synthetic Ghidra entry-point references without actionable memory sources are omitted.",
126
+ "The Java bridge serializes one function request per Program through a bounded 32-request queue and applies a 30-second native decompilation deadline.",
127
+ ];
128
+ default:
129
+ return common;
130
+ }
131
+ };
132
+ /** 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
+ })));
166
+ /** Capabilities advertised for the experimental Windows x64 P0 boundary. */
167
+ export const WINDOWS_P0_CAPABILITIES = Object.freeze(CAPABILITIES.map((capability) => Object.freeze({
168
+ ...capability,
169
+ limitations: Object.freeze([
170
+ ...capability.limitations,
171
+ ...windowsP0Limitations,
172
+ ]),
173
+ })));