rea-agents 1.6.0 → 2.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 (238) hide show
  1. package/README.md +157 -66
  2. package/bridge/ghidra/ReaGhidraBridge.java +2075 -0
  3. package/bridge/hopper_bridge.py +13 -3
  4. package/dist/application/AbortablePromise.js +25 -0
  5. package/dist/application/AnalysisProvider.js +3 -0
  6. package/dist/application/AnalysisProviderEvaluation.js +60 -0
  7. package/dist/application/AnalysisProviderRegistry.js +228 -0
  8. package/dist/application/AnalysisSnapshotCache.js +41 -21
  9. package/dist/application/AnalysisSnapshotFiles.js +5 -6
  10. package/dist/application/BinarySession.js +218 -101
  11. package/dist/application/CapabilityInventory.js +18 -0
  12. package/dist/application/CompositeProvider.js +20 -8
  13. package/dist/application/CrossVersionInvestigation.js +10 -6
  14. package/dist/application/DirectAnalysis.js +49 -35
  15. package/dist/application/Doctor.js +110 -8
  16. package/dist/application/ElectronBoundaryAnalysis.js +96 -0
  17. package/dist/application/ElectronBoundaryGraph.js +9 -0
  18. package/dist/application/ElectronBoundaryGraphContext.js +62 -0
  19. package/dist/application/ElectronBoundaryGraphIpc.js +242 -0
  20. package/dist/application/ElectronBoundaryGraphNative.js +86 -0
  21. package/dist/application/ElectronBoundaryGraphWindows.js +199 -0
  22. package/dist/application/EnhancedTools.js +39 -14
  23. package/dist/application/InvestigationProviders.js +41 -0
  24. package/dist/application/JavaScriptApplicationEvidence.js +26 -0
  25. package/dist/application/JavaScriptApplicationEvidenceGraph.js +89 -0
  26. package/dist/application/JavaScriptApplicationService.js +74 -0
  27. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +29 -0
  28. package/dist/application/JavaScriptApplicationWorkflowService.js +90 -0
  29. package/dist/application/JavaScriptArtifactAnalysis.js +305 -0
  30. package/dist/application/JavaScriptArtifactAnalysisTypes.js +1 -0
  31. package/dist/application/JavaScriptArtifactFiles.js +231 -0
  32. package/dist/application/JavaScriptArtifactGraphAccumulator.js +54 -0
  33. package/dist/application/JavaScriptArtifactGraphBuilder.js +144 -0
  34. package/dist/application/JavaScriptArtifactGraphContext.js +205 -0
  35. package/dist/application/JavaScriptArtifactGraphDocuments.js +108 -0
  36. package/dist/application/JavaScriptArtifactGraphEvidence.js +99 -0
  37. package/dist/application/JavaScriptArtifactGraphFindings.js +271 -0
  38. package/dist/application/JavaScriptArtifactGraphStructure.js +409 -0
  39. package/dist/application/JavaScriptArtifactReconstruction.js +77 -0
  40. package/dist/application/JavaScriptArtifactReconstructionInput.js +18 -0
  41. package/dist/application/JavaScriptReplayPlanning.js +201 -0
  42. package/dist/application/JavaScriptReplayService.js +266 -0
  43. package/dist/application/JavaScriptRuntimeReconciliationEvidence.js +25 -0
  44. package/dist/application/JavaScriptRuntimeReconciliationService.js +27 -0
  45. package/dist/application/MacHopper.js +20 -4
  46. package/dist/application/ManagedApplicationGraphService.js +55 -0
  47. package/dist/application/ManagedMemberComparisonService.js +122 -0
  48. package/dist/application/ManagedNativeVerificationService.js +39 -0
  49. package/dist/application/ManagedReconstructionService.js +58 -0
  50. package/dist/application/ManagedRuntimeCorrelationService.js +103 -0
  51. package/dist/application/PermissionAuthority.js +1 -1
  52. package/dist/application/ProcessCaptureLifecycle.js +1 -1
  53. package/dist/application/ProcessHarness.js +1 -1
  54. package/dist/application/ProcessSampling.js +16 -12
  55. package/dist/application/ProjectPermissionStore.js +1 -0
  56. package/dist/application/SessionProviderRouter.js +219 -0
  57. package/dist/application/Setup.js +84 -60
  58. package/dist/application/SetupClients.js +1 -1
  59. package/dist/application/SetupPlan.js +9 -2
  60. package/dist/application/SupportedClients.js +40 -16
  61. package/dist/application/Upgrade.js +1 -1
  62. package/dist/application/runtime.js +11 -6
  63. package/dist/artifacts/AsarArtifactReader.js +23 -3
  64. package/dist/browser/CdpBrowserProvider.js +4 -2
  65. package/dist/browser/CdpCaptureEvents.js +49 -0
  66. package/dist/browser/CdpElectronInspection.js +106 -162
  67. package/dist/browser/CdpElectronProvider.js +9 -3
  68. package/dist/browser/CdpElectronScriptEvents.js +69 -0
  69. package/dist/browser/CdpElectronScripts.js +94 -0
  70. package/dist/browser/CdpElectronWorkers.js +56 -0
  71. package/dist/browser/CdpEndpoint.js +14 -1
  72. package/dist/browser/CdpPageCapture.js +8 -4
  73. package/dist/catalogIdentity.js +6 -42
  74. package/dist/cli.js +446 -34
  75. package/dist/cliApplicationCommands.js +62 -0
  76. package/dist/cliBrowserAdvancedCommands.js +5 -4
  77. package/dist/cliBrowserCommands.js +5 -4
  78. package/dist/cliCommandNames.js +56 -0
  79. package/dist/cliElectronCommands.js +106 -3
  80. package/dist/cliEvidenceCommands.js +4 -3
  81. package/dist/cliInvestigationCommands.js +2 -1
  82. package/dist/cliJsonInput.js +54 -0
  83. package/dist/cliPolicyCommands.js +2 -1
  84. package/dist/cliProcessCommands.js +3 -2
  85. package/dist/config.js +101 -2
  86. package/dist/contracts/applicationToolContracts.js +91 -0
  87. package/dist/contracts/artifactToolContracts.js +5 -9
  88. package/dist/contracts/browserToolContracts.js +14 -62
  89. package/dist/contracts/electronToolContracts.js +45 -19
  90. package/dist/contracts/enhancedInputs.js +2 -2
  91. package/dist/contracts/errorSchemas.js +1 -0
  92. package/dist/contracts/investigationExamples.js +0 -6
  93. package/dist/contracts/javascriptApplicationWorkflowExamples.js +46 -0
  94. package/dist/contracts/javascriptRuntimeReconciliationExample.js +208 -0
  95. package/dist/contracts/managedToolContracts.js +153 -0
  96. package/dist/contracts/managedWorkflowExamples.js +346 -0
  97. package/dist/contracts/managedWorkflowToolContracts.js +203 -0
  98. package/dist/contracts/nativeToolContracts.js +2 -6
  99. package/dist/contracts/promptContracts.js +18 -2
  100. package/dist/contracts/providerSelection.js +28 -0
  101. package/dist/contracts/sessionLifecycleInputs.js +2 -0
  102. package/dist/contracts/toolContractExamples.js +10 -25
  103. package/dist/contracts/toolContracts.js +69 -65
  104. package/dist/contracts/toolEffects.js +160 -0
  105. package/dist/contracts/toolOutputSchemas.js +152 -42
  106. package/dist/doctorRuntime.js +47 -0
  107. package/dist/domain/analysisProfile.js +78 -0
  108. package/dist/domain/analysisSnapshot.js +92 -46
  109. package/dist/domain/artifactComparison.js +3 -4
  110. package/dist/domain/artifactGraph.js +1 -0
  111. package/dist/domain/binaryTarget.js +4 -29
  112. package/dist/domain/browserObservation.js +3 -0
  113. package/dist/domain/bundleComparison.js +4 -4
  114. package/dist/domain/electronObservation.js +13 -0
  115. package/dist/domain/electronStaticAnalysis.js +9 -0
  116. package/dist/domain/electronStaticAnalysisBrowser.js +194 -0
  117. package/dist/domain/electronStaticAnalysisIpc.js +171 -0
  118. package/dist/domain/electronStaticAnalysisNative.js +164 -0
  119. package/dist/domain/electronStaticAnalysisTypes.js +1 -0
  120. package/dist/domain/electronStaticAnalysisValues.js +103 -0
  121. package/dist/domain/errors.js +148 -7
  122. package/dist/domain/evidence.js +44 -5
  123. package/dist/domain/evidenceBundle.js +9 -7
  124. package/dist/domain/functionComparison.js +9 -3
  125. package/dist/domain/functionComparisonNormalization.js +37 -0
  126. package/dist/domain/functionComparisonSchemas.js +3 -8
  127. package/dist/domain/functionDossierEvidence.js +4 -1
  128. package/dist/domain/hopperValues.js +66 -9
  129. package/dist/domain/inputIssueProjection.js +52 -0
  130. package/dist/domain/investigationWorkspace.js +2 -1
  131. package/dist/domain/javascriptApplicationAnalysis.js +155 -0
  132. package/dist/domain/javascriptApplicationChangeGraph.js +231 -0
  133. package/dist/domain/javascriptApplicationEvidenceSchemas.js +379 -0
  134. package/dist/domain/javascriptApplicationGraph.js +282 -0
  135. package/dist/domain/javascriptApplicationGraphSchemas.js +139 -0
  136. package/dist/domain/javascriptApplicationVersionComparison.js +116 -0
  137. package/dist/domain/javascriptApplicationVersionComparisonSchemas.js +139 -0
  138. package/dist/domain/javascriptApplicationVersionItems.js +221 -0
  139. package/dist/domain/javascriptApplicationVersionKeys.js +170 -0
  140. package/dist/domain/javascriptAstFingerprint.js +143 -0
  141. package/dist/domain/javascriptFeatureSeed.js +140 -0
  142. package/dist/domain/javascriptFeatureTrace.js +232 -0
  143. package/dist/domain/javascriptFeatureTraceSchemas.js +136 -0
  144. package/dist/domain/javascriptFeatureTraversal.js +88 -0
  145. package/dist/domain/javascriptNativeHandoff.js +85 -0
  146. package/dist/domain/javascriptReplay.js +361 -0
  147. package/dist/domain/javascriptRuntimeLoadState.js +106 -0
  148. package/dist/domain/javascriptRuntimeReconciliation.js +42 -0
  149. package/dist/domain/javascriptRuntimeReconciliationGraph.js +169 -0
  150. package/dist/domain/javascriptRuntimeReconciliationMatching.js +247 -0
  151. package/dist/domain/javascriptRuntimeReconciliationParsing.js +160 -0
  152. package/dist/domain/javascriptRuntimeReconciliationResult.js +119 -0
  153. package/dist/domain/javascriptRuntimeReconciliationRuntime.js +316 -0
  154. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +245 -0
  155. package/dist/domain/javascriptRuntimeStaticCandidates.js +191 -0
  156. package/dist/domain/javascriptStaticAnalysis.js +346 -0
  157. package/dist/domain/javascriptStaticAnalysisFindings.js +39 -0
  158. package/dist/domain/javascriptStaticAnalysisHelpers.js +274 -0
  159. package/dist/domain/javascriptStaticAnalysisState.js +23 -0
  160. package/dist/domain/javascriptStaticAnalysisTypes.js +1 -0
  161. package/dist/domain/managedApplicationGraph.js +556 -0
  162. package/dist/domain/managedArtifact.js +444 -0
  163. package/dist/domain/managedMemberComparison.js +565 -0
  164. package/dist/domain/managedNativeVerification.js +408 -0
  165. package/dist/domain/managedReconstruction.js +183 -0
  166. package/dist/domain/managedRuntimeCorrelation.js +175 -0
  167. package/dist/domain/reconstructionVerificationSchemas.js +1 -3
  168. package/dist/dotnet/ManagedArtifactInspector.js +318 -0
  169. package/dist/dotnet/ManagedMemberInspector.js +887 -0
  170. package/dist/dotnet/ManagedMetadataHeaps.js +131 -0
  171. package/dist/dotnet/ManagedMetadataInventory.js +368 -0
  172. package/dist/dotnet/ManagedMetadataLayout.js +322 -0
  173. package/dist/dotnet/ManagedNativeBoundaryInspector.js +391 -0
  174. package/dist/dotnet/ManagedPeReader.js +157 -0
  175. package/dist/dotnet/ManagedReaderFailure.js +10 -0
  176. package/dist/dotnet/ManagedStaticProvider.js +203 -0
  177. package/dist/generatedPackageMetadata.js +2 -2
  178. package/dist/ghidra/GhidraAnalysisProfile.js +37 -0
  179. package/dist/ghidra/GhidraClient.js +400 -0
  180. package/dist/ghidra/GhidraClientTypes.js +1 -0
  181. package/dist/ghidra/GhidraDefaults.js +20 -0
  182. package/dist/ghidra/GhidraDiagnostics.js +43 -0
  183. package/dist/ghidra/GhidraDoctor.js +59 -0
  184. package/dist/ghidra/GhidraFunctionValues.js +264 -0
  185. package/dist/ghidra/GhidraInstallation.js +239 -0
  186. package/dist/ghidra/GhidraInventoryValues.js +217 -0
  187. package/dist/ghidra/GhidraLauncher.js +139 -0
  188. package/dist/ghidra/GhidraProvider.js +366 -0
  189. package/dist/ghidra/GhidraRequestQueue.js +98 -0
  190. package/dist/ghidra/GhidraResponseBuffer.js +31 -0
  191. package/dist/ghidra/GhidraResponseRouter.js +24 -0
  192. package/dist/ghidra/GhidraSessionError.js +39 -0
  193. package/dist/ghidra/GhidraSessionValues.js +62 -0
  194. package/dist/ghidra/GhidraSocketConnection.js +46 -0
  195. package/dist/ghidra/protocol.js +69 -0
  196. package/dist/hopper/BridgeLauncher.js +19 -54
  197. package/dist/hopper/HopperAnalysisProfile.js +106 -0
  198. package/dist/hopper/HopperClient.js +154 -162
  199. package/dist/hopper/HopperProvider.js +99 -7
  200. package/dist/hopper/HopperSessionValues.js +27 -0
  201. package/dist/hopper/HopperSocketConnection.js +31 -0
  202. package/dist/main.js +14 -0
  203. package/dist/native/NativeMacOSProvider.js +3 -1
  204. package/dist/process/PendingOperations.js +59 -0
  205. package/dist/process/PrivateRuntimeRoot.js +33 -0
  206. package/dist/process/ProviderDeadline.js +95 -0
  207. package/dist/process/ProviderProcess.js +275 -0
  208. package/dist/replay/JavaScriptReplayWorker.js +286 -0
  209. package/dist/replay/LinuxJavaScriptReplayRunner.js +434 -0
  210. package/dist/replay/LinuxRuntimeClosure.js +46 -0
  211. package/dist/replay/LinuxSeccompPolicy.js +40 -0
  212. package/dist/replay/ReplayWorkerProtocol.js +55 -0
  213. package/dist/replay/SystemJavaScriptReplayHost.js +182 -0
  214. package/dist/server/createServer.js +53 -0
  215. package/dist/server/promptCompletion.js +9 -3
  216. package/dist/server/registerApplicationTools.js +115 -0
  217. package/dist/server/registerArtifactComparisonTool.js +16 -9
  218. package/dist/server/registerBrowserTools.js +33 -8
  219. package/dist/server/registerBundleComparisonTool.js +17 -20
  220. package/dist/server/registerElectronTools.js +45 -3
  221. package/dist/server/registerEnhancedTools.js +67 -19
  222. package/dist/server/registerEvidenceTools.js +5 -1
  223. package/dist/server/registerFunctionComparisonTool.js +14 -7
  224. package/dist/server/registerInvestigationTools.js +21 -17
  225. package/dist/server/registerManagedTools.js +6 -0
  226. package/dist/server/registerManagedWorkflowTools.js +277 -0
  227. package/dist/server/registerOfficialTools.js +11 -8
  228. package/dist/server/registerProcessComparisonTool.js +25 -47
  229. package/dist/server/registerSessionStatusTool.js +7 -7
  230. package/dist/server/registerSessionTools.js +57 -87
  231. package/dist/server/sessionEvidence.js +14 -19
  232. package/dist/server/toolInputValidation.js +77 -0
  233. package/dist/server/toolRegistrationOptions.js +79 -2
  234. package/dist/server/toolResult.js +25 -17
  235. package/package.json +17 -7
  236. package/scripts/rea.mjs +36 -2
  237. package/skills/rea-analysis/SKILL.md +59 -3
  238. /package/dist/{application → process}/ProcessOwnership.js +0 -0
package/dist/cli.js CHANGED
@@ -3,7 +3,12 @@ import { fileURLToPath } from "node:url";
3
3
  import { createInterface } from "node:readline/promises";
4
4
  import { runDoctor } from "./application/Doctor.js";
5
5
  import { runDirectAnalysis, runProviderAnalysis, runSessionStatus, } from "./application/DirectAnalysis.js";
6
- import { runSetup } from "./application/Setup.js";
6
+ import { compareManagedMemberPaths } from "./application/ManagedMemberComparisonService.js";
7
+ import { projectManagedApplicationGraphEvidence } from "./application/ManagedApplicationGraphService.js";
8
+ import { verifyManagedNativeBoundariesEvidence } from "./application/ManagedNativeVerificationService.js";
9
+ import { importManagedReconstructionEvidence } from "./application/ManagedReconstructionService.js";
10
+ import { planManagedRuntimeCorrelationEvidence } from "./application/ManagedRuntimeCorrelationService.js";
11
+ import { runSetup, systemSetupHost, } from "./application/Setup.js";
7
12
  import { runUninstall } from "./application/Uninstall.js";
8
13
  import { runUpgrade, systemUpgradeHost } from "./application/Upgrade.js";
9
14
  import { PRODUCT_IDENTITY } from "./identity.js";
@@ -21,6 +26,11 @@ import { registerPolicyCommands } from "./cliPolicyCommands.js";
21
26
  import { registerBrowserCommands } from "./cliBrowserCommands.js";
22
27
  import { registerAdvancedBrowserCommands } from "./cliBrowserAdvancedCommands.js";
23
28
  import { registerElectronCommands } from "./cliElectronCommands.js";
29
+ import { registerApplicationCommands } from "./cliApplicationCommands.js";
30
+ import { CLI_COMMANDS } from "./cliCommandNames.js";
31
+ import { parseCliJsonInput } from "./cliJsonInput.js";
32
+ import { analysisProviderSelectorSchema, } from "./contracts/providerSelection.js";
33
+ import { createSystemDoctorHost } from "./doctorRuntime.js";
24
34
  /**
25
35
  * Build the one-shot Incur CLI without starting Hopper at import time.
26
36
  * Analysis commands acquire and close their own sessions; bare `mcp` and
@@ -56,6 +66,7 @@ export const createCli = () => {
56
66
  registerCapabilityCommands(cli, logger);
57
67
  registerNativeCommands(cli, logger);
58
68
  registerArtifactCommands(cli, logger);
69
+ registerManagedCommands(cli, logger);
59
70
  registerInvestigationCommands(cli, logger);
60
71
  registerEvidenceCommands(cli, logger);
61
72
  registerReferenceSourceCommand(cli, logger);
@@ -64,6 +75,7 @@ export const createCli = () => {
64
75
  registerBrowserCommands(cli, logger);
65
76
  registerAdvancedBrowserCommands(cli, logger);
66
77
  registerElectronCommands(cli, logger);
78
+ registerApplicationCommands(cli, logger);
67
79
  return cli;
68
80
  };
69
81
  const registerCoreCommands = (cli, logger) => {
@@ -75,35 +87,39 @@ const registerCoreCommands = (cli, logger) => {
75
87
  .min(1)
76
88
  .optional()
77
89
  .describe("Load and update a local analysis snapshot"),
90
+ provider: providerSelectionOption,
78
91
  });
79
- cli.command("analyze", {
92
+ cli.command(CLI_COMMANDS.analyze, {
80
93
  description: "Get an overview of an app",
81
94
  args: z.object({
82
- path: z.string().describe("App, program, or Hopper database path"),
95
+ path: z.string().describe("App, program, or analysis database path"),
83
96
  }),
84
97
  options: overviewOptions,
85
- run: ({ args, options }) => logCliCommand(logger, "analyze", () => runDirectAnalysis(args.path, "binary_overview", { detail: options.detail, limit: options.limit }, { logger, snapshotPath: options.snapshot })),
98
+ run: ({ args, options }) => logCliCommand(logger, "analyze", () => runDirectAnalysis(args.path, "binary_overview", { detail: options.detail, limit: options.limit }, directAnalysisOptions(logger, options.snapshot, options.provider))),
86
99
  });
87
- cli.command("inspect", {
100
+ cli.command(CLI_COMMANDS.inspect, {
88
101
  description: "Inspect an app overview with evidence",
89
102
  args: z.object({
90
- path: z.string().describe("App, program, or Hopper database path"),
103
+ path: z.string().describe("App, program, or analysis database path"),
91
104
  }),
92
105
  options: overviewOptions,
93
- run: ({ args, options }) => logCliCommand(logger, "inspect", () => runDirectAnalysis(args.path, "binary_overview", { detail: options.detail, limit: options.limit }, { logger, snapshotPath: options.snapshot })),
106
+ run: ({ args, options }) => logCliCommand(logger, "inspect", () => runDirectAnalysis(args.path, "binary_overview", { detail: options.detail, limit: options.limit }, directAnalysisOptions(logger, options.snapshot, options.provider))),
94
107
  });
95
- cli.command("decompile", {
108
+ cli.command(CLI_COMMANDS.decompile, {
96
109
  description: "Read one part of an app as code",
97
110
  args: z.object({
98
111
  path: z.string().describe("App or program path"),
99
112
  address: z.string().describe("Procedure address"),
100
113
  }),
101
- options: z.object({ snapshot: z.string().min(1).optional() }),
102
- run: ({ args, options }) => logCliCommand(logger, "decompile", () => runDirectAnalysis(args.path, "procedure_pseudo_code", { procedure: args.address }, { logger, snapshotPath: options.snapshot })),
114
+ options: z.object({
115
+ snapshot: z.string().min(1).optional(),
116
+ provider: providerSelectionOption,
117
+ }),
118
+ run: ({ args, options }) => logCliCommand(logger, "decompile", () => runDirectAnalysis(args.path, "procedure_pseudo_code", { procedure: args.address }, directAnalysisOptions(logger, options.snapshot, options.provider))),
103
119
  });
104
120
  };
105
121
  const registerSetupCommands = (cli, logger) => {
106
- cli.command("setup", {
122
+ cli.command(CLI_COMMANDS.setup, {
107
123
  description: "Install requirements and configure agents",
108
124
  options: z.object({
109
125
  yes: z
@@ -120,18 +136,18 @@ const registerSetupCommands = (cli, logger) => {
120
136
  approved: options.yes,
121
137
  installHopper: options.installHopper,
122
138
  structured: formatExplicit,
123
- }, undefined, options.yes || formatExplicit || process.stdin.isTTY !== true
139
+ }, systemSetupHost(createSystemDoctorHost()), options.yes || formatExplicit || process.stdin.isTTY !== true
124
140
  ? undefined
125
141
  : confirmSetup)),
126
142
  });
127
- cli.command("doctor", {
143
+ cli.command(CLI_COMMANDS.doctor, {
128
144
  description: "Check whether REA is ready",
129
145
  options: z.object({
130
146
  target: z.string().optional().describe("Optional app path to check"),
131
147
  }),
132
- run: ({ options }) => logCliCommand(logger, "doctor", () => runDoctor(options.target)),
148
+ run: ({ options }) => logCliCommand(logger, "doctor", () => runDoctor(options.target, createSystemDoctorHost())),
133
149
  });
134
- cli.command("uninstall", {
150
+ cli.command(CLI_COMMANDS.uninstall, {
135
151
  description: "Remove REA-owned agent configuration and skill files",
136
152
  options: z.object({
137
153
  purgeData: z
@@ -142,7 +158,7 @@ const registerSetupCommands = (cli, logger) => {
142
158
  alias: { purgeData: "purge-data" },
143
159
  run: ({ options }) => logCliCommand(logger, "uninstall", () => runUninstall(options.purgeData)),
144
160
  });
145
- cli.command("upgrade", {
161
+ cli.command(CLI_COMMANDS.upgrade, {
146
162
  description: "Upgrade a global npm installation to the latest REA release",
147
163
  run: ({ formatExplicit }) => logCliCommand(logger, "upgrade", () => runUpgrade(PRODUCT_IDENTITY.packageVersion, systemUpgradeHost(), formatExplicit ? "structured" : "human")),
148
164
  });
@@ -166,18 +182,21 @@ const confirmSetup = async (actions) => {
166
182
  }
167
183
  };
168
184
  const registerXrefsCommand = (cli, logger) => {
169
- cli.command("xrefs", {
185
+ cli.command(CLI_COMMANDS.xrefs, {
170
186
  description: "List bounded references to an analyzed address",
171
187
  args: z.object({
172
188
  path: z.string().describe("App or program path"),
173
189
  address: z.string().describe("Hexadecimal address"),
174
190
  }),
175
- options: z.object({ snapshot: z.string().min(1).optional() }),
176
- run: ({ args, options }) => logCliCommand(logger, "xrefs", () => runDirectAnalysis(args.path, "xrefs", { address: args.address }, { logger, snapshotPath: options.snapshot })),
191
+ options: z.object({
192
+ snapshot: z.string().min(1).optional(),
193
+ provider: providerSelectionOption,
194
+ }),
195
+ run: ({ args, options }) => logCliCommand(logger, "xrefs", () => runDirectAnalysis(args.path, "xrefs", { address: args.address }, directAnalysisOptions(logger, options.snapshot, options.provider))),
177
196
  });
178
197
  };
179
198
  const registerTraceCommand = (cli, logger) => {
180
- cli.command("trace", {
199
+ cli.command(CLI_COMMANDS.trace, {
181
200
  description: "Trace a bounded literal feature through analyzed references",
182
201
  args: z.object({
183
202
  path: z.string().describe("App or program path"),
@@ -188,6 +207,7 @@ const registerTraceCommand = (cli, logger) => {
188
207
  limit: z.number().int().min(1).max(100).default(20),
189
208
  maxOperations: z.number().int().min(1).max(100).default(20),
190
209
  snapshot: z.string().min(1).optional(),
210
+ provider: providerSelectionOption,
191
211
  }),
192
212
  alias: {
193
213
  caseSensitive: "case-sensitive",
@@ -198,11 +218,14 @@ const registerTraceCommand = (cli, logger) => {
198
218
  case_sensitive: options.caseSensitive,
199
219
  limit: options.limit,
200
220
  max_operations: options.maxOperations,
201
- }, { logger, snapshotPath: options.snapshot })),
221
+ }, directAnalysisOptions(logger, options.snapshot, options.provider))),
202
222
  });
203
223
  };
204
224
  const registerCapabilityCommands = (cli, logger) => {
205
- for (const command of ["capabilities", "providers"]) {
225
+ for (const command of [
226
+ CLI_COMMANDS.capabilities,
227
+ CLI_COMMANDS.providers,
228
+ ]) {
206
229
  cli.command(command, {
207
230
  description: command === "capabilities"
208
231
  ? "List provider capabilities and side effects"
@@ -212,7 +235,7 @@ const registerCapabilityCommands = (cli, logger) => {
212
235
  }
213
236
  };
214
237
  const registerFunctionCommand = (cli, logger) => {
215
- cli.command("function", {
238
+ cli.command(CLI_COMMANDS.function, {
216
239
  description: "Analyze one bounded function with evidence",
217
240
  args: z.object({
218
241
  path: z.string().describe("App or program path"),
@@ -224,6 +247,7 @@ const registerFunctionCommand = (cli, logger) => {
224
247
  maxPseudocodeChars: z.number().int().min(1).max(100_000).default(20_000),
225
248
  maxInstructions: z.number().int().min(1).max(5_000).default(500),
226
249
  snapshot: z.string().min(1).optional(),
250
+ provider: providerSelectionOption,
227
251
  }),
228
252
  alias: {
229
253
  includeAssembly: "include-assembly",
@@ -236,11 +260,11 @@ const registerFunctionCommand = (cli, logger) => {
236
260
  limit: options.limit,
237
261
  max_pseudocode_chars: options.maxPseudocodeChars,
238
262
  max_instructions: options.maxInstructions,
239
- }, { logger, snapshotPath: options.snapshot })),
263
+ }, directAnalysisOptions(logger, options.snapshot, options.provider))),
240
264
  });
241
265
  };
242
266
  const registerSearchCommand = (cli, logger) => {
243
- cli.command("search", {
267
+ cli.command(CLI_COMMANDS.search, {
244
268
  description: "Search bounded analyzed strings or procedure names",
245
269
  args: z.object({
246
270
  path: z.string().describe("App or program path"),
@@ -253,6 +277,7 @@ const registerSearchCommand = (cli, logger) => {
253
277
  offset: z.number().int().min(0).default(0),
254
278
  limit: z.number().int().min(1).max(100).default(100),
255
279
  snapshot: z.string().min(1).optional(),
280
+ provider: providerSelectionOption,
256
281
  }),
257
282
  alias: { caseSensitive: "case-sensitive" },
258
283
  run: ({ args, options }) => logCliCommand(logger, "search", () => runDirectAnalysis(args.path, options.kind === "strings" ? "search_strings" : "search_procedures", {
@@ -261,11 +286,11 @@ const registerSearchCommand = (cli, logger) => {
261
286
  case_sensitive: options.caseSensitive,
262
287
  offset: options.offset,
263
288
  limit: options.limit,
264
- }, { logger, snapshotPath: options.snapshot })),
289
+ }, directAnalysisOptions(logger, options.snapshot, options.provider))),
265
290
  });
266
291
  };
267
292
  const registerReferenceSourceCommand = (cli, logger) => {
268
- cli.command("import-reference-source", {
293
+ cli.command(CLI_COMMANDS.importReferenceSource, {
269
294
  description: "Import a bounded source tree as historical reference only",
270
295
  args: z.object({
271
296
  root: z
@@ -322,7 +347,7 @@ const registerReferenceSourceCommand = (cli, logger) => {
322
347
  });
323
348
  };
324
349
  const registerArtifactCommands = (cli, logger) => {
325
- cli.command("inventory-artifact", {
350
+ cli.command(CLI_COMMANDS.inventoryArtifact, {
326
351
  description: "Build a bounded deterministic artifact graph",
327
352
  args: z.object({
328
353
  path: z.string().describe("Application or package path"),
@@ -354,7 +379,7 @@ const registerArtifactCommands = (cli, logger) => {
354
379
  native_mount_approved: options.nativeMountApproved,
355
380
  }, logger)),
356
381
  });
357
- cli.command("extract-artifact", {
382
+ cli.command(CLI_COMMANDS.extractArtifact, {
358
383
  description: "Extract explicitly selected artifact occurrences safely",
359
384
  args: z.object({
360
385
  path: z.string().describe("Application or package path"),
@@ -372,11 +397,390 @@ const registerArtifactCommands = (cli, logger) => {
372
397
  }, logger)),
373
398
  });
374
399
  };
400
+ const registerManagedCommands = (cli, logger) => {
401
+ cli.command(CLI_COMMANDS.inspectManagedArtifact, {
402
+ description: "Inspect PE/CLI identity without loading target code",
403
+ args: z.object({
404
+ path: z.string().describe("Managed PE executable or assembly path"),
405
+ }),
406
+ options: z.object({
407
+ referenceOffset: z.number().int().min(0).default(0),
408
+ referenceLimit: z.number().int().min(1).max(500).default(100),
409
+ resourceOffset: z.number().int().min(0).default(0),
410
+ resourceLimit: z.number().int().min(1).max(500).default(100),
411
+ attributeOffset: z.number().int().min(0).default(0),
412
+ attributeLimit: z.number().int().min(1).max(500).default(100),
413
+ maxFileBytes: z
414
+ .number()
415
+ .int()
416
+ .min(4_096)
417
+ .max(1_073_741_824)
418
+ .default(268_435_456),
419
+ maxMetadataBytes: z
420
+ .number()
421
+ .int()
422
+ .min(256)
423
+ .max(268_435_456)
424
+ .default(67_108_864),
425
+ maxTableRows: z.number().int().min(1).max(1_000_000).default(100_000),
426
+ maxHeapItemBytes: z
427
+ .number()
428
+ .int()
429
+ .min(1)
430
+ .max(16_777_216)
431
+ .default(1_048_576),
432
+ }),
433
+ alias: {
434
+ referenceOffset: "reference-offset",
435
+ referenceLimit: "reference-limit",
436
+ resourceOffset: "resource-offset",
437
+ resourceLimit: "resource-limit",
438
+ attributeOffset: "attribute-offset",
439
+ attributeLimit: "attribute-limit",
440
+ maxFileBytes: "max-file-bytes",
441
+ maxMetadataBytes: "max-metadata-bytes",
442
+ maxTableRows: "max-table-rows",
443
+ maxHeapItemBytes: "max-heap-item-bytes",
444
+ },
445
+ run: ({ args, options }) => logCliCommand(logger, "inspect-managed-artifact", () => runProviderAnalysis(args.path, "inspect_managed_artifact", {
446
+ reference_offset: options.referenceOffset,
447
+ reference_limit: options.referenceLimit,
448
+ resource_offset: options.resourceOffset,
449
+ resource_limit: options.resourceLimit,
450
+ attribute_offset: options.attributeOffset,
451
+ attribute_limit: options.attributeLimit,
452
+ max_file_bytes: options.maxFileBytes,
453
+ max_metadata_bytes: options.maxMetadataBytes,
454
+ max_table_rows: options.maxTableRows,
455
+ max_heap_item_bytes: options.maxHeapItemBytes,
456
+ }, logger)),
457
+ });
458
+ cli.command(CLI_COMMANDS.inspectManagedMembers, {
459
+ description: "Inspect PE/CLI metadata members, signatures, and CIL anchors without loading target code",
460
+ args: z.object({
461
+ path: z.string().describe("Managed PE executable or assembly path"),
462
+ }),
463
+ options: z.object({
464
+ typeOffset: z.number().int().min(0).default(0),
465
+ typeLimit: z.number().int().min(1).max(500).default(100),
466
+ methodOffset: z.number().int().min(0).default(0),
467
+ methodLimit: z.number().int().min(1).max(500).default(100),
468
+ fieldOffset: z.number().int().min(0).default(0),
469
+ fieldLimit: z.number().int().min(1).max(500).default(100),
470
+ memberRefOffset: z.number().int().min(0).default(0),
471
+ memberRefLimit: z.number().int().min(1).max(500).default(100),
472
+ edgeOffset: z.number().int().min(0).default(0),
473
+ edgeLimit: z.number().int().min(1).max(1_000).default(250),
474
+ instructionAnchorLimit: z.number().int().min(0).max(500).default(100),
475
+ maxFileBytes: z
476
+ .number()
477
+ .int()
478
+ .min(4_096)
479
+ .max(1_073_741_824)
480
+ .default(268_435_456),
481
+ maxMetadataBytes: z
482
+ .number()
483
+ .int()
484
+ .min(256)
485
+ .max(268_435_456)
486
+ .default(67_108_864),
487
+ maxTableRows: z.number().int().min(1).max(1_000_000).default(100_000),
488
+ maxHeapItemBytes: z
489
+ .number()
490
+ .int()
491
+ .min(1)
492
+ .max(16_777_216)
493
+ .default(1_048_576),
494
+ maxMethodBodyBytes: z
495
+ .number()
496
+ .int()
497
+ .min(1)
498
+ .max(16_777_216)
499
+ .default(1_048_576),
500
+ maxMethodInstructions: z
501
+ .number()
502
+ .int()
503
+ .min(1)
504
+ .max(100_000)
505
+ .default(10_000),
506
+ }),
507
+ alias: {
508
+ typeOffset: "type-offset",
509
+ typeLimit: "type-limit",
510
+ methodOffset: "method-offset",
511
+ methodLimit: "method-limit",
512
+ fieldOffset: "field-offset",
513
+ fieldLimit: "field-limit",
514
+ memberRefOffset: "member-ref-offset",
515
+ memberRefLimit: "member-ref-limit",
516
+ edgeOffset: "edge-offset",
517
+ edgeLimit: "edge-limit",
518
+ instructionAnchorLimit: "instruction-anchor-limit",
519
+ maxFileBytes: "max-file-bytes",
520
+ maxMetadataBytes: "max-metadata-bytes",
521
+ maxTableRows: "max-table-rows",
522
+ maxHeapItemBytes: "max-heap-item-bytes",
523
+ maxMethodBodyBytes: "max-method-body-bytes",
524
+ maxMethodInstructions: "max-method-instructions",
525
+ },
526
+ run: ({ args, options }) => logCliCommand(logger, "inspect-managed-members", () => runProviderAnalysis(args.path, "inspect_managed_members", {
527
+ type_offset: options.typeOffset,
528
+ type_limit: options.typeLimit,
529
+ method_offset: options.methodOffset,
530
+ method_limit: options.methodLimit,
531
+ field_offset: options.fieldOffset,
532
+ field_limit: options.fieldLimit,
533
+ member_ref_offset: options.memberRefOffset,
534
+ member_ref_limit: options.memberRefLimit,
535
+ edge_offset: options.edgeOffset,
536
+ edge_limit: options.edgeLimit,
537
+ instruction_anchor_limit: options.instructionAnchorLimit,
538
+ max_file_bytes: options.maxFileBytes,
539
+ max_metadata_bytes: options.maxMetadataBytes,
540
+ max_table_rows: options.maxTableRows,
541
+ max_heap_item_bytes: options.maxHeapItemBytes,
542
+ max_method_body_bytes: options.maxMethodBodyBytes,
543
+ max_method_instructions: options.maxMethodInstructions,
544
+ }, logger)),
545
+ });
546
+ cli.command(CLI_COMMANDS.inspectManagedNativeBoundaries, {
547
+ description: "Inspect PE/CLI PInvoke and native implementation boundary declarations without loading target code",
548
+ args: z.object({
549
+ path: z.string().describe("Managed PE executable or assembly path"),
550
+ }),
551
+ options: z.object({
552
+ moduleRefOffset: z.number().int().min(0).default(0),
553
+ moduleRefLimit: z.number().int().min(1).max(500).default(100),
554
+ importOffset: z.number().int().min(0).default(0),
555
+ importLimit: z.number().int().min(1).max(500).default(100),
556
+ implementationOffset: z.number().int().min(0).default(0),
557
+ implementationLimit: z.number().int().min(1).max(500).default(100),
558
+ maxFileBytes: z
559
+ .number()
560
+ .int()
561
+ .min(4_096)
562
+ .max(1_073_741_824)
563
+ .default(268_435_456),
564
+ maxMetadataBytes: z
565
+ .number()
566
+ .int()
567
+ .min(256)
568
+ .max(268_435_456)
569
+ .default(67_108_864),
570
+ maxTableRows: z.number().int().min(1).max(1_000_000).default(100_000),
571
+ maxHeapItemBytes: z
572
+ .number()
573
+ .int()
574
+ .min(1)
575
+ .max(16_777_216)
576
+ .default(1_048_576),
577
+ }),
578
+ alias: {
579
+ moduleRefOffset: "module-ref-offset",
580
+ moduleRefLimit: "module-ref-limit",
581
+ importOffset: "import-offset",
582
+ importLimit: "import-limit",
583
+ implementationOffset: "implementation-offset",
584
+ implementationLimit: "implementation-limit",
585
+ maxFileBytes: "max-file-bytes",
586
+ maxMetadataBytes: "max-metadata-bytes",
587
+ maxTableRows: "max-table-rows",
588
+ maxHeapItemBytes: "max-heap-item-bytes",
589
+ },
590
+ run: ({ args, options }) => logCliCommand(logger, "inspect-managed-native-boundaries", () => runProviderAnalysis(args.path, "inspect_managed_native_boundaries", {
591
+ module_ref_offset: options.moduleRefOffset,
592
+ module_ref_limit: options.moduleRefLimit,
593
+ import_offset: options.importOffset,
594
+ import_limit: options.importLimit,
595
+ implementation_offset: options.implementationOffset,
596
+ implementation_limit: options.implementationLimit,
597
+ max_file_bytes: options.maxFileBytes,
598
+ max_metadata_bytes: options.maxMetadataBytes,
599
+ max_table_rows: options.maxTableRows,
600
+ max_heap_item_bytes: options.maxHeapItemBytes,
601
+ }, logger)),
602
+ });
603
+ cli.command(CLI_COMMANDS.compareManagedMembers, {
604
+ description: "Compare two managed PE/CLI member inventories without name-based matching",
605
+ args: z.object({
606
+ leftPath: z
607
+ .string()
608
+ .describe("Baseline managed PE executable or assembly"),
609
+ rightPath: z
610
+ .string()
611
+ .describe("Candidate managed PE executable or assembly"),
612
+ }),
613
+ options: z.object({
614
+ maxMethodMatches: z.number().int().min(1).max(50_000).default(10_000),
615
+ maxFieldMatches: z.number().int().min(0).max(50_000).default(5_000),
616
+ maxCandidates: z.number().int().min(1).max(500).default(50),
617
+ typeLimit: z.number().int().min(1).max(500).default(500),
618
+ methodLimit: z.number().int().min(1).max(500).default(500),
619
+ fieldLimit: z.number().int().min(1).max(500).default(500),
620
+ memberRefLimit: z.number().int().min(1).max(500).default(500),
621
+ edgeLimit: z.number().int().min(1).max(1_000).default(1_000),
622
+ instructionAnchorLimit: z.number().int().min(0).max(500).default(500),
623
+ maxFileBytes: z
624
+ .number()
625
+ .int()
626
+ .min(4_096)
627
+ .max(1_073_741_824)
628
+ .default(268_435_456),
629
+ maxMetadataBytes: z
630
+ .number()
631
+ .int()
632
+ .min(256)
633
+ .max(268_435_456)
634
+ .default(67_108_864),
635
+ maxTableRows: z.number().int().min(1).max(1_000_000).default(100_000),
636
+ maxHeapItemBytes: z
637
+ .number()
638
+ .int()
639
+ .min(1)
640
+ .max(16_777_216)
641
+ .default(1_048_576),
642
+ maxMethodBodyBytes: z
643
+ .number()
644
+ .int()
645
+ .min(1)
646
+ .max(16_777_216)
647
+ .default(1_048_576),
648
+ maxMethodInstructions: z
649
+ .number()
650
+ .int()
651
+ .min(1)
652
+ .max(100_000)
653
+ .default(100_000),
654
+ }),
655
+ alias: {
656
+ maxMethodMatches: "max-method-matches",
657
+ maxFieldMatches: "max-field-matches",
658
+ maxCandidates: "max-candidates",
659
+ typeLimit: "type-limit",
660
+ methodLimit: "method-limit",
661
+ fieldLimit: "field-limit",
662
+ memberRefLimit: "member-ref-limit",
663
+ edgeLimit: "edge-limit",
664
+ instructionAnchorLimit: "instruction-anchor-limit",
665
+ maxFileBytes: "max-file-bytes",
666
+ maxMetadataBytes: "max-metadata-bytes",
667
+ maxTableRows: "max-table-rows",
668
+ maxHeapItemBytes: "max-heap-item-bytes",
669
+ maxMethodBodyBytes: "max-method-body-bytes",
670
+ maxMethodInstructions: "max-method-instructions",
671
+ },
672
+ run: ({ args, options }) => logCliCommand(logger, "compare-managed-members", async () => {
673
+ const result = await compareManagedMemberPaths({
674
+ leftPath: args.leftPath,
675
+ rightPath: args.rightPath,
676
+ comparisonLimits: {
677
+ max_method_matches: options.maxMethodMatches,
678
+ max_field_matches: options.maxFieldMatches,
679
+ max_candidates: options.maxCandidates,
680
+ },
681
+ memberLimits: {
682
+ maxFileBytes: options.maxFileBytes,
683
+ typeOffset: 0,
684
+ typeLimit: options.typeLimit,
685
+ methodOffset: 0,
686
+ methodLimit: options.methodLimit,
687
+ fieldOffset: 0,
688
+ fieldLimit: options.fieldLimit,
689
+ memberRefOffset: 0,
690
+ memberRefLimit: options.memberRefLimit,
691
+ edgeOffset: 0,
692
+ edgeLimit: options.edgeLimit,
693
+ instructionAnchorLimit: options.instructionAnchorLimit,
694
+ maxMetadataBytes: options.maxMetadataBytes,
695
+ maxTableRows: options.maxTableRows,
696
+ maxHeapItemBytes: options.maxHeapItemBytes,
697
+ maxMethodBodyBytes: options.maxMethodBodyBytes,
698
+ maxMethodInstructions: options.maxMethodInstructions,
699
+ },
700
+ });
701
+ return result.ok
702
+ ? result.value
703
+ : {
704
+ error: "Managed member comparison failed",
705
+ ...projectAnalysisError(result.error),
706
+ };
707
+ }),
708
+ });
709
+ cli.command(CLI_COMMANDS.importManagedReconstruction, {
710
+ description: "Import decompiler-produced managed reconstruction against exact static member evidence",
711
+ args: z.object({
712
+ inputJson: z
713
+ .string()
714
+ .describe("Inline managed reconstruction JSON or JSON file path"),
715
+ }),
716
+ run: ({ args }) => logCliCommand(logger, "import-managed-reconstruction", async () => {
717
+ const input = await parseCliJsonInput(args.inputJson, "import-managed-reconstruction");
718
+ if (!input.ok)
719
+ return input.error;
720
+ const result = importManagedReconstructionEvidence(input.value);
721
+ return result.ok ? result.value : projectAnalysisError(result.error);
722
+ }),
723
+ });
724
+ cli.command(CLI_COMMANDS.verifyManagedNativeBoundaries, {
725
+ description: "Verify managed P/Invoke declarations against authenticated native Evidence",
726
+ args: z.object({
727
+ inputJson: z
728
+ .string()
729
+ .describe("Inline managed/native verification JSON or JSON file path"),
730
+ }),
731
+ run: ({ args }) => logCliCommand(logger, "verify-managed-native-boundaries", async () => {
732
+ const input = await parseCliJsonInput(args.inputJson, "verify-managed-native-boundaries");
733
+ if (!input.ok)
734
+ return input.error;
735
+ const result = verifyManagedNativeBoundariesEvidence(input.value);
736
+ return result.ok ? result.value : projectAnalysisError(result.error);
737
+ }),
738
+ });
739
+ cli.command(CLI_COMMANDS.planManagedRuntimeCorrelation, {
740
+ description: "Plan a separately authorized managed runtime-correlation experiment without executing target code",
741
+ args: z.object({
742
+ inputJson: z
743
+ .string()
744
+ .describe("Inline managed runtime-correlation JSON or JSON file path"),
745
+ }),
746
+ run: ({ args }) => logCliCommand(logger, "plan-managed-runtime-correlation", async () => {
747
+ const input = await parseCliJsonInput(args.inputJson, "plan-managed-runtime-correlation");
748
+ if (!input.ok)
749
+ return input.error;
750
+ const config = parseConfig(process.env);
751
+ if (!config.ok)
752
+ return projectAnalysisError(config.error);
753
+ const authority = await loadConfiguredPermissionAuthority(config.value);
754
+ if (!authority.ok)
755
+ return projectAnalysisError(authority.error);
756
+ const result = await planManagedRuntimeCorrelationEvidence({
757
+ policy: config.value.managedRuntimePolicy,
758
+ authority: authority.value,
759
+ }, input.value);
760
+ return result.ok ? result.value : projectAnalysisError(result.error);
761
+ }),
762
+ });
763
+ cli.command(CLI_COMMANDS.projectManagedApplicationGraph, {
764
+ description: "Project authenticated managed static Evidence into an application graph",
765
+ args: z.object({
766
+ inputJson: z
767
+ .string()
768
+ .describe("Inline managed application graph JSON or JSON file path"),
769
+ }),
770
+ run: ({ args }) => logCliCommand(logger, "project-managed-application-graph", async () => {
771
+ const input = await parseCliJsonInput(args.inputJson, "project-managed-application-graph");
772
+ if (!input.ok)
773
+ return input.error;
774
+ const result = projectManagedApplicationGraphEvidence(input.value);
775
+ return result.ok ? result.value : projectAnalysisError(result.error);
776
+ }),
777
+ });
778
+ };
375
779
  const registerNativeCommands = (cli, logger) => {
376
780
  for (const [command, tool] of [
377
- ["inspect-macho", "inspect_macho"],
378
- ["inspect-signature", "inspect_signature"],
379
- ["list-architectures", "list_architectures"],
781
+ [CLI_COMMANDS.inspectMacho, "inspect_macho"],
782
+ [CLI_COMMANDS.inspectSignature, "inspect_signature"],
783
+ [CLI_COMMANDS.listArchitectures, "list_architectures"],
380
784
  ]) {
381
785
  cli.command(command, {
382
786
  description: `Run ${tool} without launching Hopper`,
@@ -384,7 +788,7 @@ const registerNativeCommands = (cli, logger) => {
384
788
  run: ({ args }) => logCliCommand(logger, command, () => runProviderAnalysis(args.path, tool, {}, logger)),
385
789
  });
386
790
  }
387
- cli.command("inspect-plist", {
791
+ cli.command(CLI_COMMANDS.inspectPlist, {
388
792
  description: "Parse app plist metadata without launching Hopper",
389
793
  args: z.object({ path: z.string().describe("App or Mach-O path") }),
390
794
  options: z.object({
@@ -393,7 +797,7 @@ const registerNativeCommands = (cli, logger) => {
393
797
  alias: { relativePath: "relative-path" },
394
798
  run: ({ args, options }) => logCliCommand(logger, "inspect-plist", () => runProviderAnalysis(args.path, "inspect_plist", { relative_path: options.relativePath }, logger)),
395
799
  });
396
- cli.command("demangle-swift", {
800
+ cli.command(CLI_COMMANDS.demangleSwift, {
397
801
  description: "Demangle a bounded Swift symbol batch without Hopper",
398
802
  args: z.object({
399
803
  path: z.string().describe("Artifact path used for evidence identity"),
@@ -402,3 +806,11 @@ const registerNativeCommands = (cli, logger) => {
402
806
  run: ({ args }) => logCliCommand(logger, "demangle-swift", () => runProviderAnalysis(args.path, "demangle_swift", { symbols: args.symbols }, logger)),
403
807
  });
404
808
  };
809
+ const providerSelectionOption = analysisProviderSelectorSchema
810
+ .optional()
811
+ .describe("Bind deep analysis to a provider ID or use deterministic auto selection");
812
+ const directAnalysisOptions = (logger, snapshotPath, providerId) => ({
813
+ logger,
814
+ snapshotPath,
815
+ ...(providerId === undefined ? {} : { providerId }),
816
+ });