rea-agents 2.5.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/README.md +20 -12
  2. package/bridge/ghidra/ReaGhidraBridge.java +477 -4
  3. package/bridge/hopper_bridge.py +54 -4
  4. package/dist/application/AnalysisContextQueries.js +142 -0
  5. package/dist/application/AnalysisSnapshotCache.js +4 -2
  6. package/dist/application/ApplicationWorkflowEvidenceResolver.js +19 -11
  7. package/dist/application/ArtifactInventory/policy.js +17 -0
  8. package/dist/application/ArtifactInventory/reader.js +1 -4
  9. package/dist/application/ArtifactInventory/scanCanonical.js +0 -3
  10. package/dist/application/ArtifactInventory/scanReader.js +7 -7
  11. package/dist/application/ArtifactInventory/types.js +1 -5
  12. package/dist/application/BinarySession.js +19 -20
  13. package/dist/application/BinarySessionComposition.js +21 -0
  14. package/dist/application/BinarySessionRecords.js +106 -10
  15. package/dist/application/BinarySessionStatus.js +11 -5
  16. package/dist/application/BrowserEvidence.js +3 -5
  17. package/dist/application/CapabilityClientRequirements.js +26 -0
  18. package/dist/application/CapabilityInventory.js +140 -55
  19. package/dist/application/ClientRegistrationStatus.js +4 -1
  20. package/dist/application/CrossVersionInventory.js +7 -6
  21. package/dist/application/DirectAnalysis.js +6 -2
  22. package/dist/application/ElectronActiveEvidence.js +55 -0
  23. package/dist/application/ElectronActiveObservationPort.js +1 -0
  24. package/dist/application/ElectronActiveObservationService.js +81 -0
  25. package/dist/application/EnhancedTools.js +49 -17
  26. package/dist/application/EvidenceBundleCommands.js +5 -1
  27. package/dist/application/EvidenceLedger.js +53 -17
  28. package/dist/application/JavaScriptArtifactAnalysis.js +13 -4
  29. package/dist/application/JavaScriptReplayPermission.js +1 -1
  30. package/dist/application/JavaScriptReplayService.js +23 -15
  31. package/dist/application/LazyAnalysisProvider.js +77 -0
  32. package/dist/application/LoopbackReplay.js +1 -1
  33. package/dist/application/ManagedRuntimeCorrelationService.js +9 -5
  34. package/dist/application/NativeApiInspection.js +80 -0
  35. package/dist/application/NodeRuntimeCharacterizationService.js +8 -9
  36. package/dist/application/ProcessCaptureLifecycle.js +5 -0
  37. package/dist/application/ProcessCli.js +2 -1
  38. package/dist/application/ProcessHarness.js +8 -3
  39. package/dist/application/ProcessNormalization.js +2 -1
  40. package/dist/application/ProjectPermissionStore.js +1 -0
  41. package/dist/application/ReferenceSourceImport.js +2 -2
  42. package/dist/application/SessionProviderRouter.js +6 -6
  43. package/dist/application/SetupClientConfiguration.js +10 -3
  44. package/dist/application/WindowsCapabilities.js +5 -4
  45. package/dist/application/runtime.js +26 -9
  46. package/dist/artifacts/ArtifactProvider.js +8 -10
  47. package/dist/artifacts/SafeOutputTree.js +7 -8
  48. package/dist/browser/CdpCaptureStorageFingerprints.js +10 -7
  49. package/dist/browser/CdpElectronInspection.js +3 -1
  50. package/dist/browser/JavaScriptRuntimeScope.js +5 -0
  51. package/dist/browser/PlaywrightBrowserScenarioProvider.js +8 -2
  52. package/dist/browser/PlaywrightElectronActiveActions.js +324 -0
  53. package/dist/browser/PlaywrightElectronActiveProvider.js +294 -0
  54. package/dist/browser/PlaywrightScenarioBrowser.js +4 -4
  55. package/dist/browser/PlaywrightScenarioSession.js +4 -4
  56. package/dist/browser/SensitiveTextCapture.js +1 -1
  57. package/dist/browser/V8InspectorCaptureProjection.js +1 -0
  58. package/dist/browser/V8InspectorProvider.js +3 -3
  59. package/dist/catalogIdentity.js +15 -9
  60. package/dist/cli/artifactCommands.js +5 -3
  61. package/dist/cli/coreAnalysisCommands.js +41 -0
  62. package/dist/cli/managedCommands.js +1 -1
  63. package/dist/cliApplicationCommands.js +2 -2
  64. package/dist/cliBrowserAdvancedCommands.js +11 -5
  65. package/dist/cliBrowserCommands.js +14 -7
  66. package/dist/cliCommandNames.js +2 -0
  67. package/dist/cliElectronCommands.js +46 -4
  68. package/dist/cliJavaScriptRuntimeCommands.js +14 -6
  69. package/dist/cliObservationOptions.js +4 -0
  70. package/dist/cliPolicyCommands.js +1 -0
  71. package/dist/config/browserScenario.js +77 -0
  72. package/dist/config/electronAutomation.js +35 -0
  73. package/dist/config/environment.js +6 -0
  74. package/dist/config/javascriptReplay.js +41 -0
  75. package/dist/config/managedRuntime.js +25 -0
  76. package/dist/config/parseConfig.js +56 -200
  77. package/dist/config/parsers.js +10 -1
  78. package/dist/config/passiveObservation.js +157 -0
  79. package/dist/config/processCapture.js +47 -0
  80. package/dist/contracts/applicationToolContracts.js +2 -5
  81. package/dist/contracts/applicationWorkflowInputContracts.js +86 -96
  82. package/dist/contracts/artifactToolContracts.js +35 -37
  83. package/dist/contracts/browserToolContracts.js +2 -2
  84. package/dist/contracts/electronToolContracts.js +30 -1
  85. package/dist/contracts/enhancedInputs.js +21 -27
  86. package/dist/contracts/functionWorkflowToolContracts.js +29 -0
  87. package/dist/contracts/managedToolContracts.js +4 -9
  88. package/dist/contracts/managedWorkflowExamples.js +12 -9
  89. package/dist/contracts/managedWorkflowToolContracts.js +30 -27
  90. package/dist/contracts/nativeToolContracts.js +2 -3
  91. package/dist/contracts/promptContracts.js +14 -15
  92. package/dist/contracts/sessionToolSchemas.js +61 -0
  93. package/dist/contracts/toolContractExamples.js +4 -0
  94. package/dist/contracts/toolContractHelpers.js +23 -0
  95. package/dist/contracts/toolContracts.js +12 -67
  96. package/dist/contracts/toolEffects.js +19 -0
  97. package/dist/contracts/toolOutputSchemaGroups.js +66 -11
  98. package/dist/contracts/toolOutputSchemaPrimitives.js +76 -26
  99. package/dist/contracts/toolSchemaMetadata.js +128 -0
  100. package/dist/doctorRuntime.js +1 -1
  101. package/dist/domain/analysisErrorPresentation.js +8 -2
  102. package/dist/domain/analysisErrorProjection.js +1 -0
  103. package/dist/domain/androidApplication.js +2 -0
  104. package/dist/domain/appleApplication.js +2 -0
  105. package/dist/domain/binaryTarget.js +7 -5
  106. package/dist/domain/binaryTargetTypes.js +1 -0
  107. package/dist/domain/browserCaptureComparison.js +21 -69
  108. package/dist/domain/browserObservation.js +22 -9
  109. package/dist/domain/bytecodeProvider.js +177 -0
  110. package/dist/domain/callPath.js +3 -2
  111. package/dist/domain/conformancePackage.js +169 -0
  112. package/dist/domain/conformanceReplay.js +104 -0
  113. package/dist/domain/conformanceTrustGate.js +328 -0
  114. package/dist/domain/customProtocolCapture.js +137 -0
  115. package/dist/domain/electronActiveObservation.js +277 -0
  116. package/dist/domain/electronObservation.js +15 -11
  117. package/dist/domain/electronStaticAnalysisValues.js +4 -1
  118. package/dist/domain/eventProcessTree.js +217 -0
  119. package/dist/domain/evidenceBundle.js +47 -0
  120. package/dist/domain/functionComparisonNormalization.js +15 -8
  121. package/dist/domain/functionDossierEvidence.js +9 -4
  122. package/dist/domain/hopperStartupFailure.js +1 -1
  123. package/dist/domain/hopperValues.js +68 -68
  124. package/dist/domain/inputIssueProjection.js +11 -2
  125. package/dist/domain/investigationWorkspace.js +16 -15
  126. package/dist/domain/javascriptExportShapeComparisonSchemas.js +2 -2
  127. package/dist/domain/javascriptReplay.js +79 -63
  128. package/dist/domain/javascriptRuntimeObservation.js +1 -0
  129. package/dist/domain/javascriptRuntimeReconciliationActive.js +89 -0
  130. package/dist/domain/javascriptRuntimeReconciliationGraph.js +11 -10
  131. package/dist/domain/javascriptRuntimeReconciliationMatching.js +57 -49
  132. package/dist/domain/javascriptRuntimeReconciliationParsing.js +5 -1
  133. package/dist/domain/javascriptRuntimeReconciliationResult.js +21 -14
  134. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
  135. package/dist/domain/javascriptSemanticAnalysis.js +8 -12
  136. package/dist/domain/javascriptSourceParser.js +15 -0
  137. package/dist/domain/javascriptStaticAnalysis.js +8 -12
  138. package/dist/domain/knownPageCoverage.js +15 -7
  139. package/dist/domain/mobileApplicationInvestigation.js +159 -0
  140. package/dist/domain/nativeApiBoundary.js +138 -0
  141. package/dist/domain/nodeRuntimeCharacterization.js +14 -13
  142. package/dist/domain/objcSwiftMetadata.js +150 -0
  143. package/dist/domain/packageAnalysis.js +123 -0
  144. package/dist/domain/peInspection.js +196 -0
  145. package/dist/domain/processCaptureReactiveValidation.js +8 -3
  146. package/dist/domain/processCaptureValidation.js +7 -3
  147. package/dist/domain/processComparison.js +12 -7
  148. package/dist/domain/processObservation.js +5 -6
  149. package/dist/domain/processReactiveMatching.js +14 -7
  150. package/dist/domain/processReactiveTransition.js +9 -3
  151. package/dist/domain/processScenario.js +6 -3
  152. package/dist/domain/processTraceComparison.js +3 -2
  153. package/dist/domain/protocolCapture.js +245 -0
  154. package/dist/domain/reconstructionReadinessSchemas.js +30 -2
  155. package/dist/domain/referenceSourceImportParsing.js +2 -2
  156. package/dist/domain/replayMachineRuntime.js +5 -3
  157. package/dist/domain/sourceToBundleComparison.js +2 -2
  158. package/dist/domain/sourceToBundleComparisonSchemas.js +8 -8
  159. package/dist/domain/sourceToBundleSignals.js +7 -1
  160. package/dist/domain/staticRuntimeCorrelation.js +7 -5
  161. package/dist/domain/webBundleAnalysis.js +14 -14
  162. package/dist/domain/webCaptureDiff.js +15 -12
  163. package/dist/dotnet/ManagedNativeBoundaryInspector.js +2 -3
  164. package/dist/dotnet/ManagedStaticProvider.js +34 -5
  165. package/dist/generatedMcpToolCatalog.js +37 -0
  166. package/dist/generatedPackageMetadata.js +4 -4
  167. package/dist/ghidra/GhidraClient.js +1 -1
  168. package/dist/ghidra/GhidraClientStartup.js +1 -1
  169. package/dist/ghidra/GhidraDefaults.js +1 -1
  170. package/dist/ghidra/GhidraFunctionValues.js +44 -16
  171. package/dist/ghidra/GhidraInventoryValues.js +57 -47
  172. package/dist/ghidra/GhidraProvider.js +18 -10
  173. package/dist/ghidra/GhidraProviderCapabilities.js +45 -39
  174. package/dist/ghidra/GhidraSocketConnection.js +1 -1
  175. package/dist/ghidra/protocol.js +19 -42
  176. package/dist/hopper/BridgeLauncher.js +3 -1
  177. package/dist/hopper/HopperAnalysisProfile.js +2 -4
  178. package/dist/hopper/HopperCleanup.js +5 -6
  179. package/dist/hopper/HopperClient.js +27 -3
  180. package/dist/hopper/HopperProvider.js +42 -44
  181. package/dist/hopper/HopperRequestQueue.js +32 -4
  182. package/dist/hopper/HopperResponseStream.js +2 -2
  183. package/dist/hopper/LinuxPrivateDisplayProbe.js +16 -10
  184. package/dist/hopper/protocol.js +63 -21
  185. package/dist/main/reload.js +1 -6
  186. package/dist/main/state.js +0 -14
  187. package/dist/main/transport.js +31 -41
  188. package/dist/main.js +17 -13
  189. package/dist/mcpDoctor.js +4 -26
  190. package/dist/mcpStartupPolicy.js +14 -0
  191. package/dist/process/PrivateRuntimeRoot.js +17 -0
  192. package/dist/process/ProcessOwnership.js +64 -128
  193. package/dist/process/ProcessOwnershipIdentity.js +13 -0
  194. package/dist/process/ProcessOwnershipObservation.js +88 -0
  195. package/dist/process/ProcessOwnershipProcessTree.js +22 -0
  196. package/dist/process/ProviderDeadline.js +8 -12
  197. package/dist/process/WindowsAuthority.js +32 -0
  198. package/dist/reference/ReferenceSourceReader.js +3 -3
  199. package/dist/reference/ReferenceSourceReaderEntries.js +2 -2
  200. package/dist/replay/JavaScriptReplayWorker.js +95 -11
  201. package/dist/replay/JavaScriptReplayWorkerTypes.js +1 -0
  202. package/dist/replay/LinuxJavaScriptReplayRunner.js +10 -15
  203. package/dist/replay/ReplayOutcome.js +26 -15
  204. package/dist/replay/ReplayWorkerProtocol.js +34 -29
  205. package/dist/server/createServer.js +101 -144
  206. package/dist/server/mcpClientMetadata.js +32 -0
  207. package/dist/server/registerApplicationTools/characterization.js +6 -13
  208. package/dist/server/registerApplicationTools/compareExportShapes.js +2 -7
  209. package/dist/server/registerApplicationTools/compareSourceToBundle.js +2 -7
  210. package/dist/server/registerApplicationTools/compareVersions.js +3 -8
  211. package/dist/server/registerApplicationTools/controlledReplay.js +6 -11
  212. package/dist/server/registerApplicationTools/coverage.js +13 -19
  213. package/dist/server/registerApplicationTools/obligationLedger.js +1 -6
  214. package/dist/server/registerApplicationTools/readiness.js +1 -6
  215. package/dist/server/registerApplicationTools/traceFeature.js +3 -8
  216. package/dist/server/registerApplicationTools/traceSemantics.js +1 -6
  217. package/dist/server/registerArtifactComparisonTool.js +12 -16
  218. package/dist/server/registerBrowserScenarioTool.js +1 -6
  219. package/dist/server/registerBrowserTools.js +37 -79
  220. package/dist/server/registerBundleComparisonTool.js +10 -14
  221. package/dist/server/registerCloseLifecycleTool.js +6 -14
  222. package/dist/server/registerElectronTools.js +30 -47
  223. package/dist/server/registerEnhancedTools.js +124 -122
  224. package/dist/server/registerEvidenceResources.js +50 -101
  225. package/dist/server/registerEvidenceTools.js +5 -9
  226. package/dist/server/registerFunctionComparisonTool.js +11 -15
  227. package/dist/server/registerInvestigationTools.js +42 -59
  228. package/dist/server/registerJavaScriptApplicationGraphResource.js +0 -4
  229. package/dist/server/registerJavaScriptRuntimeObservationTools.js +13 -27
  230. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +4 -9
  231. package/dist/server/registerManagedWorkflowTools/contract.js +2 -3
  232. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +3 -8
  233. package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +3 -8
  234. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +8 -13
  235. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +4 -9
  236. package/dist/server/registerOfficialTools.js +8 -9
  237. package/dist/server/registerProcessComparisonTool.js +19 -24
  238. package/dist/server/registerReconstructionObligationLedgerResource.js +0 -7
  239. package/dist/server/registerReconstructionReadinessResource.js +0 -7
  240. package/dist/server/registerReplayMachineTool.js +4 -10
  241. package/dist/server/registerSessionRecordTools.js +146 -47
  242. package/dist/server/registerSessionStatusTool.js +14 -29
  243. package/dist/server/registerSessionTools.js +45 -41
  244. package/dist/server/sessionAvailabilityPolicy.js +2 -1
  245. package/dist/server/sessionToolPolicies.js +1 -5
  246. package/dist/server/toolRegistrationOptions.js +4 -177
  247. package/dist/server/toolResult.js +14 -18
  248. package/package.json +35 -16
  249. package/scripts/electron-active-hook-boundaries.cjs +394 -0
  250. package/scripts/electron-active-hook.cjs +501 -0
  251. package/skills/reverse-engineer-anything/SKILL.md +10 -3
  252. package/dist/server/DynamicToolAvailability.js +0 -70
  253. package/dist/server/toolInputValidation.js +0 -77
@@ -3,7 +3,7 @@ import { AnalysisError, BrowserObservationError, ProviderAdapterError, } from ".
3
3
  import { err, ok } from "../domain/result.js";
4
4
  import { boundedText, numberValue, recordValue, stringValue, delayWithCancellation, } from "./CdpCaptureValues.js";
5
5
  import { CdpConnection } from "./CdpConnection.js";
6
- import { authorizeRuntimeLocation, canonicalRuntimeRoots, } from "./JavaScriptRuntimeScope.js";
6
+ import { authorizeRuntimeTargetLocation, canonicalRuntimeRoots, } from "./JavaScriptRuntimeScope.js";
7
7
  import { createInspectorExclusionCounts, describeInspectorTargetLimitations, finalizeInspectorCapture, } from "./V8InspectorCaptureProjection.js";
8
8
  import { discoverV8Inspector, } from "./V8InspectorEndpoint.js";
9
9
  /** Public identity committed by passive V8 Inspector observations. */
@@ -24,7 +24,7 @@ export class V8InspectorProvider {
24
24
  const allowed = [];
25
25
  const excluded = createInspectorExclusionCounts();
26
26
  for (const target of discovery.targets) {
27
- const decision = await authorizeRuntimeLocation(target.url, roots, input.allowed_origins);
27
+ const decision = await authorizeRuntimeTargetLocation(target.url, target.type, roots, input.allowed_origins);
28
28
  if (!decision.allowed) {
29
29
  excluded[decision.reason] += 1;
30
30
  continue;
@@ -104,7 +104,7 @@ const authorizedTarget = async (targets, input, roots) => {
104
104
  const target = targets.find(({ id }) => id === input.target_id);
105
105
  if (target === undefined)
106
106
  throw new BrowserObservationError("observe_javascript_runtime", "target_not_found");
107
- const decision = await authorizeRuntimeLocation(target.url, roots, input.allowed_origins);
107
+ const decision = await authorizeRuntimeTargetLocation(target.url, target.type, roots, input.allowed_origins);
108
108
  if (target.attached ||
109
109
  !decision.allowed ||
110
110
  decision.location.kind === "builtin")
@@ -12,12 +12,18 @@ const toolCatalog = TOOL_CONTRACTS.map((contract) => ({
12
12
  description: contract.description,
13
13
  effects: { ...contract.effects },
14
14
  annotations: contract.annotations,
15
- input_schema: z.toJSONSchema(contract.inputSchema, {
16
- unrepresentable: "any",
17
- }),
18
- output_schema: z.toJSONSchema(contract.outputSchema, {
19
- unrepresentable: "any",
20
- }),
15
+ input_schema: {
16
+ type: "object",
17
+ ...z.toJSONSchema(contract.inputSchema, {
18
+ unrepresentable: "any",
19
+ }),
20
+ },
21
+ output_schema: {
22
+ type: "object",
23
+ ...z.toJSONSchema(contract.outputSchema, {
24
+ unrepresentable: "any",
25
+ }),
26
+ },
21
27
  })).sort((left, right) => left.name.localeCompare(right.name));
22
28
  const promptCatalog = PROMPT_CONTRACTS.map((contract) => ({
23
29
  name: contract.name,
@@ -29,7 +35,7 @@ const promptCatalog = PROMPT_CONTRACTS.map((contract) => ({
29
35
  /** Canonical fixed resources exposed by every target-free MCP session. */
30
36
  export const MCP_RESOURCE_CATALOG = [
31
37
  { name: "server-identity", uri: "rea://server/identity" },
32
- { name: "active-residual-unknowns", uri: "rea://unknowns/active" },
38
+ { name: "analysis-snapshot", uri: "rea://snapshot/current" },
33
39
  ];
34
40
  /** Canonical resource templates exposed by every target-free MCP session. */
35
41
  export const MCP_RESOURCE_TEMPLATE_CATALOG = [
@@ -40,8 +46,8 @@ export const MCP_RESOURCE_TEMPLATE_CATALOG = [
40
46
  },
41
47
  { name: "residual-unknown", uri_template: "rea://unknown/{unknownId}" },
42
48
  {
43
- name: "analysis-snapshot",
44
- uri_template: "rea://snapshot/{snapshotDigest}",
49
+ name: "evidence-bundle",
50
+ uri_template: "rea://evidence-bundle/{bundleDigest}",
45
51
  },
46
52
  {
47
53
  name: "artifact-page",
@@ -73,17 +73,19 @@ const registerExtractionCommand = (cli, logger) => {
73
73
  args: z.object({
74
74
  path: z.string().describe("Application or package path"),
75
75
  outputRoot: z.string().describe("Absent absolute output root"),
76
+ }),
77
+ options: z.object({
76
78
  occurrenceIds: z
77
79
  .array(z.string().regex(/^occ_[a-f0-9]{64}$/u))
78
80
  .min(1)
79
81
  .max(500)
80
82
  .describe("Exact artifact occurrence IDs selected for extraction"),
81
83
  }),
82
- alias: { outputRoot: "output-root", occurrenceIds: "occurrence-ids" },
83
- run: ({ args }) => logCliCommand(logger, "extract-artifact", () => runProviderAnalysis(args.path, "extract_artifact", {
84
+ alias: { occurrenceIds: "occurrence-ids" },
85
+ run: ({ args, options }) => logCliCommand(logger, "extract-artifact", () => runProviderAnalysis(args.path, "extract_artifact", {
84
86
  approved: true,
85
87
  output_root: args.outputRoot,
86
- occurrence_ids: args.occurrenceIds,
88
+ occurrence_ids: options.occurrenceIds,
87
89
  }, logger)),
88
90
  });
89
91
  };
@@ -9,6 +9,7 @@ import { runCliJavaScriptApplicationAnalysis } from "./javascriptApplicationAnal
9
9
  export const registerCoreAnalysisCommands = (cli, logger) => {
10
10
  registerCoreCommands(cli, logger);
11
11
  registerFunctionCommand(cli, logger);
12
+ registerNativeApiCommand(cli, logger);
12
13
  registerInstructionsCommand(cli, logger);
13
14
  registerSearchCommand(cli, logger);
14
15
  registerXrefsCommand(cli, logger);
@@ -213,6 +214,46 @@ const registerFunctionCommand = (cli, logger) => {
213
214
  }, directAnalysisOptions(logger, options.snapshot, options.provider))),
214
215
  });
215
216
  };
217
+ const registerNativeApiCommand = (cli, logger) => {
218
+ cli.command(CLI_COMMANDS.inspectNativeApi, {
219
+ description: "Reconstruct one native function API boundary with evidence",
220
+ args: z.object({
221
+ path: z.string().describe("App or program path"),
222
+ address: z.string().describe("Procedure name or address"),
223
+ }),
224
+ options: z.object({
225
+ maxPseudocodeChars: z
226
+ .number()
227
+ .int()
228
+ .min(1)
229
+ .max(100_000)
230
+ .default(20_000)
231
+ .describe("Maximum pseudocode characters to inspect"),
232
+ maxInstructions: z
233
+ .number()
234
+ .int()
235
+ .min(1)
236
+ .max(5_000)
237
+ .default(500)
238
+ .describe("Maximum assembly instructions to inspect"),
239
+ snapshot: z
240
+ .string()
241
+ .min(1)
242
+ .optional()
243
+ .describe("Load and update a local analysis snapshot"),
244
+ provider: providerSelectionOption,
245
+ }),
246
+ alias: {
247
+ maxPseudocodeChars: "max-pseudocode-chars",
248
+ maxInstructions: "max-instructions",
249
+ },
250
+ run: ({ args, options }) => logCliCommand(logger, "inspect-native-api", () => runDirectAnalysis(args.path, "inspect_native_api", {
251
+ procedure: args.address,
252
+ max_pseudocode_chars: options.maxPseudocodeChars,
253
+ max_instructions: options.maxInstructions,
254
+ }, directAnalysisOptions(logger, options.snapshot, options.provider))),
255
+ });
256
+ };
216
257
  const registerInstructionsCommand = (cli, logger) => {
217
258
  cli.command(CLI_COMMANDS.instructions, {
218
259
  description: "Read one bounded raw-instruction window without decompiling",
@@ -388,7 +388,7 @@ const registerPlanManagedRuntimeCorrelation = (cli, logger) => {
388
388
  if (!authority.ok)
389
389
  return projectAnalysisError(authority.error);
390
390
  const result = await planManagedRuntimeCorrelationEvidence({
391
- policy: config.value.managedRuntimePolicy,
391
+ policy: () => config.value.managedRuntimePolicy,
392
392
  authority: authority.value,
393
393
  }, input.value);
394
394
  return result.ok ? result.value : projectAnalysisError(result.error);
@@ -75,7 +75,7 @@ export const registerApplicationCommands = (cli, logger) => {
75
75
  if (!authority.ok)
76
76
  return projectAnalysisError(authority.error);
77
77
  const result = await runControlledReplay({
78
- policy: config.value.javascriptReplayPolicy,
78
+ policy: () => config.value.javascriptReplayPolicy,
79
79
  host: new SystemJavaScriptReplayHost(),
80
80
  runner: new LinuxJavaScriptReplayRunner(),
81
81
  authority: authority.value,
@@ -193,7 +193,7 @@ const configuredAuthority = async () => {
193
193
  : { ok: false, error: projectAnalysisError(configured.error) };
194
194
  };
195
195
  const replayDependencies = (config, authority) => ({
196
- policy: config.javascriptReplayPolicy,
196
+ policy: () => config.javascriptReplayPolicy,
197
197
  host: new SystemJavaScriptReplayHost(),
198
198
  runner: new LinuxJavaScriptReplayRunner(),
199
199
  authority,
@@ -4,7 +4,7 @@ import { loadConfiguredPermissionAuthority } from "./application/PermissionConfi
4
4
  import { CdpBrowserProvider } from "./browser/CdpBrowserProvider.js";
5
5
  import { logCliCommand } from "./cliLogging.js";
6
6
  import { parseConfig } from "./config.js";
7
- import { AnalysisInputError, projectAnalysisError } from "./domain/errors.js";
7
+ import { AnalysisCapabilityUnavailableError, AnalysisInputError, projectAnalysisError, } from "./domain/errors.js";
8
8
  import { browserCaptureComparisonInputSchema } from "./domain/browserCaptureComparison.js";
9
9
  import { discoverWebMcpToolsInputSchema } from "./domain/webMcpDiscovery.js";
10
10
  import { captureWebScreenshotInputSchema, compareWebScreenshotsInputSchema, } from "./domain/webScreenshot.js";
@@ -69,7 +69,7 @@ const registerWebMcp = (cli, logger) => {
69
69
  .describe("Maximum nesting depth in one declared tool schema"),
70
70
  }),
71
71
  run: ({ args, options }) => logCliCommand(logger, "discover-webmcp-tools", async () => {
72
- const context = await browserContext();
72
+ const context = await browserContext("discover_webmcp_tools");
73
73
  if (!context.ok)
74
74
  return context.error;
75
75
  const parsed = discoverWebMcpToolsInputSchema.safeParse({
@@ -155,7 +155,7 @@ const registerScreenshot = (cli, logger) => {
155
155
  .describe("Maximum captured PNG size"),
156
156
  }),
157
157
  run: ({ args, options }) => logCliCommand(logger, "capture-web-screenshot", async () => {
158
- const context = await browserContext();
158
+ const context = await browserContext("capture_web_screenshot");
159
159
  if (!context.ok)
160
160
  return context.error;
161
161
  const parsed = captureWebScreenshotInputSchema.safeParse({
@@ -210,10 +210,16 @@ const registerScreenshotDiff = (cli, logger) => {
210
210
  }),
211
211
  });
212
212
  };
213
- const browserContext = async () => {
213
+ const browserContext = async (operation) => {
214
214
  const config = parseConfig(process.env);
215
215
  if (!config.ok)
216
216
  return { ok: false, error: cliError(config.error) };
217
+ const policy = config.value.browserObservationPolicy;
218
+ if (policy.status === "disabled")
219
+ return {
220
+ ok: false,
221
+ error: cliError(new AnalysisCapabilityUnavailableError("rea-cdp-browser", operation, "browser observation is disabled; configure exact endpoints and origins before enabling it")),
222
+ };
217
223
  const authority = await loadConfiguredPermissionAuthority(config.value);
218
224
  if (!authority.ok)
219
225
  return { ok: false, error: cliError(authority.error) };
@@ -221,7 +227,7 @@ const browserContext = async () => {
221
227
  ok: true,
222
228
  authority: authority.value,
223
229
  provider: new CdpBrowserProvider(),
224
- allowedBrowserOrigins: config.value.browserAllowedOrigins,
230
+ allowedBrowserOrigins: policy.allowedOrigins,
225
231
  };
226
232
  };
227
233
  const parseJson = (value) => {
@@ -7,7 +7,7 @@ import { parseConfig } from "./config.js";
7
7
  import { inspectWebPageInputSchema, listBrowserTargetsInputSchema, } from "./domain/browserObservation.js";
8
8
  import { analyzeWebBundleInputSchema } from "./domain/webBundleAnalysis.js";
9
9
  import { observeWebSessionInputSchema } from "./domain/browserSession.js";
10
- import { AnalysisInputError, projectAnalysisError } from "./domain/errors.js";
10
+ import { AnalysisCapabilityUnavailableError, AnalysisInputError, projectAnalysisError, } from "./domain/errors.js";
11
11
  import { CLI_COMMANDS } from "./cliCommandNames.js";
12
12
  import { browserPageInspectionOptions } from "./cliObservationOptions.js";
13
13
  const browserScopeOptions = {
@@ -49,7 +49,7 @@ const registerTargetList = (cli, logger) => {
49
49
  limit: boundedCount("browser targets to return", 200, 100),
50
50
  }),
51
51
  run: ({ args, options }) => logCliCommand(logger, "list-browser-targets", async () => {
52
- const context = await browserContext();
52
+ const context = await browserContext("list_browser_targets");
53
53
  if (!context.ok)
54
54
  return context.error;
55
55
  const parsed = listBrowserTargetsInputSchema.safeParse({
@@ -75,7 +75,7 @@ const registerPageInspection = (cli, logger) => {
75
75
  }),
76
76
  options: browserPageInspectionOptions,
77
77
  run: ({ args, options }) => logCliCommand(logger, "inspect-web-page", async () => {
78
- const context = await browserContext();
78
+ const context = await browserContext("inspect_web_page");
79
79
  if (!context.ok)
80
80
  return context.error;
81
81
  const parsed = inspectWebPageInputSchema.safeParse({
@@ -92,6 +92,7 @@ const registerPageInspection = (cli, logger) => {
92
92
  include_websocket_shapes: options.includeWebsocketShapes,
93
93
  websocket_shape_approved: options.websocketShapeApproved,
94
94
  include_script_sources: options.includeScriptSources,
95
+ source_capture_approved: options.sourceCaptureApproved,
95
96
  include_storage_keys: options.includeStorageKeys,
96
97
  include_storage_fingerprints: options.includeStorageFingerprints,
97
98
  limits: {
@@ -157,7 +158,7 @@ const registerBundleAnalysis = (cli, logger) => {
157
158
  maxOriginalSources: boundedCount("original source files", 20_000, 2_000),
158
159
  }),
159
160
  run: ({ args, options }) => logCliCommand(logger, "analyze-web-bundle", async () => {
160
- const context = await browserContext();
161
+ const context = await browserContext("analyze_web_bundle");
161
162
  if (!context.ok)
162
163
  return context.error;
163
164
  const parsed = analyzeWebBundleInputSchema.safeParse({
@@ -200,7 +201,7 @@ const registerObservationSession = (cli, logger) => {
200
201
  maxTimelineEvents: boundedCount("timeline events", 20_000, 2_000),
201
202
  }),
202
203
  run: ({ args, options }) => logCliCommand(logger, "observe-web-session", async () => {
203
- const context = await browserContext();
204
+ const context = await browserContext("observe_web_session");
204
205
  if (!context.ok)
205
206
  return context.error;
206
207
  const parsed = observeWebSessionInputSchema.safeParse({
@@ -218,10 +219,16 @@ const registerObservationSession = (cli, logger) => {
218
219
  }),
219
220
  });
220
221
  };
221
- const browserContext = async () => {
222
+ const browserContext = async (operation) => {
222
223
  const config = parseConfig(process.env);
223
224
  if (!config.ok)
224
225
  return { ok: false, error: cliError(config.error) };
226
+ const policy = config.value.browserObservationPolicy;
227
+ if (policy.status === "disabled")
228
+ return {
229
+ ok: false,
230
+ error: cliError(new AnalysisCapabilityUnavailableError("rea-cdp-browser", operation, "browser observation is disabled; configure exact endpoints and origins before enabling it")),
231
+ };
225
232
  const authority = await loadConfiguredPermissionAuthority(config.value);
226
233
  if (!authority.ok)
227
234
  return { ok: false, error: cliError(authority.error) };
@@ -229,7 +236,7 @@ const browserContext = async () => {
229
236
  ok: true,
230
237
  authority: authority.value,
231
238
  provider: new CdpBrowserProvider(),
232
- allowedBrowserOrigins: config.value.browserAllowedOrigins,
239
+ allowedBrowserOrigins: policy.allowedOrigins,
233
240
  };
234
241
  };
235
242
  const cliError = (error) => ({
@@ -12,6 +12,7 @@ export const CLI_COMMANDS = Object.freeze({
12
12
  capabilities: "capabilities",
13
13
  providers: "providers",
14
14
  function: "function",
15
+ inspectNativeApi: "inspect-native-api",
15
16
  instructions: "instructions",
16
17
  search: "search",
17
18
  importReferenceSource: "import-reference-source",
@@ -49,6 +50,7 @@ export const CLI_COMMANDS = Object.freeze({
49
50
  captureBrowserScenario: "capture-browser-scenario",
50
51
  listElectronTargets: "list-electron-targets",
51
52
  inspectElectronPage: "inspect-electron-page",
53
+ captureElectronScenario: "capture-electron-scenario",
52
54
  listJavaScriptRuntimeTargets: "list-javascript-runtime-targets",
53
55
  observeJavaScriptRuntime: "observe-javascript-runtime",
54
56
  analyzeJavaScriptApplication: "analyze-javascript-application",
@@ -1,12 +1,15 @@
1
1
  import { Cli, z } from "incur";
2
2
  import { inspectElectronPage, listElectronTargets, } from "./application/ElectronObservationService.js";
3
+ import { captureElectronScenario } from "./application/ElectronActiveObservationService.js";
3
4
  import { reconcileJavaScriptRuntimeEvidence } from "./application/JavaScriptRuntimeReconciliationService.js";
4
5
  import { loadConfiguredPermissionAuthority } from "./application/PermissionConfiguration.js";
5
6
  import { CdpElectronProvider } from "./browser/CdpElectronProvider.js";
7
+ import { PlaywrightElectronActiveProvider } from "./browser/PlaywrightElectronActiveProvider.js";
6
8
  import { logCliCommand } from "./cliLogging.js";
7
9
  import { parseConfig } from "./config.js";
8
10
  import { inspectElectronPageInputSchema, listElectronTargetsInputSchema, } from "./domain/electronObservation.js";
9
- import { AnalysisInputError, projectAnalysisError } from "./domain/errors.js";
11
+ import { electronActiveObservationInputSchema } from "./domain/electronActiveObservation.js";
12
+ import { AnalysisCapabilityUnavailableError, AnalysisInputError, projectAnalysisError, } from "./domain/errors.js";
10
13
  import { CLI_COMMANDS } from "./cliCommandNames.js";
11
14
  import { parseCliJsonInput } from "./cliJsonInput.js";
12
15
  import { electronPageInspectionOptions, javascriptApplicationOptions, } from "./cliObservationOptions.js";
@@ -21,9 +24,33 @@ const scopeOptions = {
21
24
  /** Register CLI equivalents of the Electron MCP tools. */
22
25
  export const registerElectronCommands = (cli, logger) => {
23
26
  registerElectronObservationCommands(cli, logger);
27
+ registerElectronActiveCommand(cli, logger);
24
28
  registerJavaScriptApplicationCommand(cli, logger);
25
29
  registerJavaScriptRuntimeReconciliationCommand(cli, logger);
26
30
  };
31
+ const registerElectronActiveCommand = (cli, logger) => {
32
+ cli.command(CLI_COMMANDS.captureElectronScenario, {
33
+ description: "Run one approved, bounded owned Electron scenario",
34
+ args: z.object({
35
+ inputJson: z
36
+ .string()
37
+ .describe("Inline JSON or a JSON file matching capture_electron_scenario"),
38
+ }),
39
+ run: ({ args }) => logCliCommand(logger, CLI_COMMANDS.captureElectronScenario, async () => {
40
+ const input = await parseCliJsonInput(args.inputJson, "capture_electron_scenario");
41
+ if (!input.ok)
42
+ return input.error;
43
+ const parsed = electronActiveObservationInputSchema.safeParse(input.value);
44
+ if (!parsed.success)
45
+ return inputError("capture_electron_scenario");
46
+ const context = await electronContext();
47
+ if (!context.ok)
48
+ return context.error;
49
+ const result = await captureElectronScenario(context.activeProvider, context.authority, parsed.data);
50
+ return result.ok ? result.value : cliError(result.error);
51
+ }),
52
+ });
53
+ };
27
54
  const registerJavaScriptRuntimeReconciliationCommand = (cli, logger) => {
28
55
  cli.command(CLI_COMMANDS.reconcileJavaScriptRuntime, {
29
56
  description: "Reconcile static application and passive runtime Evidence JSON",
@@ -70,7 +97,7 @@ const registerElectronTargetList = (cli, logger) => {
70
97
  .describe("Maximum Electron targets to return"),
71
98
  }),
72
99
  run: ({ args, options }) => logCliCommand(logger, "list-electron-targets", async () => {
73
- const context = await electronContext();
100
+ const context = await electronObservationContext("list_electron_targets");
74
101
  if (!context.ok)
75
102
  return context.error;
76
103
  const parsed = listElectronTargetsInputSchema.safeParse({
@@ -98,7 +125,7 @@ const registerElectronPageInspection = (cli, logger) => {
98
125
  }),
99
126
  options: electronPageInspectionOptions,
100
127
  run: ({ args, options }) => logCliCommand(logger, "inspect-electron-page", async () => {
101
- const context = await electronContext();
128
+ const context = await electronObservationContext("inspect_electron_page");
102
129
  if (!context.ok)
103
130
  return context.error;
104
131
  const parsed = inspectElectronPageInputSchema.safeParse({
@@ -168,7 +195,22 @@ const electronContext = async () => {
168
195
  ok: true,
169
196
  authority: authority.value,
170
197
  provider: new CdpElectronProvider(),
171
- allowedFileRoots: config.value.electronFileRoots,
198
+ activeProvider: new PlaywrightElectronActiveProvider(),
199
+ observationPolicy: config.value.electronObservationPolicy,
200
+ };
201
+ };
202
+ const electronObservationContext = async (operation) => {
203
+ const context = await electronContext();
204
+ if (!context.ok)
205
+ return context;
206
+ if (context.observationPolicy.status === "disabled")
207
+ return {
208
+ ok: false,
209
+ error: cliError(new AnalysisCapabilityUnavailableError("rea-cdp-electron", operation, "Electron observation is disabled; configure exact endpoints and file roots before enabling it")),
210
+ };
211
+ return {
212
+ ...context,
213
+ allowedFileRoots: context.observationPolicy.fileRoots,
172
214
  };
173
215
  };
174
216
  const inputError = (operation) => cliError(new AnalysisInputError(operation));
@@ -5,8 +5,9 @@ import { V8InspectorProvider } from "./browser/V8InspectorProvider.js";
5
5
  import { CLI_COMMANDS } from "./cliCommandNames.js";
6
6
  import { logCliCommand } from "./cliLogging.js";
7
7
  import { parseConfig } from "./config.js";
8
+ import { v8InspectorLocationScopes } from "./config/passiveObservation.js";
8
9
  import { javascriptRuntimeKindSchema, listJavaScriptRuntimeTargetsInputSchema, observeJavaScriptRuntimeInputSchema, } from "./domain/javascriptRuntimeObservation.js";
9
- import { AnalysisInputError, projectAnalysisError } from "./domain/errors.js";
10
+ import { AnalysisCapabilityUnavailableError, AnalysisInputError, projectAnalysisError, } from "./domain/errors.js";
10
11
  const scopeOptions = {
11
12
  allowedFileRoots: z
12
13
  .array(z.string().min(1))
@@ -89,7 +90,7 @@ export const registerJavaScriptRuntimeObservationCommands = (cli, logger) => {
89
90
  }),
90
91
  options: listOptionsSchema,
91
92
  run: ({ args, options }) => logCliCommand(logger, CLI_COMMANDS.listJavaScriptRuntimeTargets, async () => {
92
- const context = await runtimeContext();
93
+ const context = await runtimeContext("list_javascript_runtime_targets");
93
94
  if (!context.ok)
94
95
  return context.error;
95
96
  const parsed = listJavaScriptRuntimeTargetsInputSchema.safeParse({
@@ -116,7 +117,7 @@ export const registerJavaScriptRuntimeObservationCommands = (cli, logger) => {
116
117
  }),
117
118
  options: observeOptionsSchema,
118
119
  run: ({ args, options }) => logCliCommand(logger, CLI_COMMANDS.observeJavaScriptRuntime, async () => {
119
- const context = await runtimeContext();
120
+ const context = await runtimeContext("observe_javascript_runtime");
120
121
  if (!context.ok)
121
122
  return context.error;
122
123
  const parsed = observeJavaScriptRuntimeInputSchema.safeParse({
@@ -142,19 +143,26 @@ export const registerJavaScriptRuntimeObservationCommands = (cli, logger) => {
142
143
  }),
143
144
  });
144
145
  };
145
- const runtimeContext = async () => {
146
+ const runtimeContext = async (operation) => {
146
147
  const config = parseConfig(process.env);
147
148
  if (!config.ok)
148
149
  return { ok: false, error: cliError(config.error) };
150
+ const policy = config.value.v8InspectorObservationPolicy;
151
+ if (policy.status === "disabled")
152
+ return {
153
+ ok: false,
154
+ error: cliError(new AnalysisCapabilityUnavailableError("rea-v8-inspector", operation, "V8 Inspector observation is disabled; configure exact endpoints and file or origin scopes before enabling it")),
155
+ };
149
156
  const authority = await loadConfiguredPermissionAuthority(config.value);
150
157
  if (!authority.ok)
151
158
  return { ok: false, error: cliError(authority.error) };
159
+ const scopes = v8InspectorLocationScopes(policy.locations);
152
160
  return {
153
161
  ok: true,
154
162
  authority: authority.value,
155
163
  provider: new V8InspectorProvider(),
156
- allowedFileRoots: config.value.v8InspectorFileRoots,
157
- allowedOrigins: config.value.v8InspectorAllowedOrigins,
164
+ allowedFileRoots: scopes.fileRoots,
165
+ allowedOrigins: scopes.allowedOrigins,
158
166
  };
159
167
  };
160
168
  const inputError = (operation) => cliError(new AnalysisInputError(operation));
@@ -50,6 +50,10 @@ export const browserPageInspectionOptions = z.object({
50
50
  .boolean()
51
51
  .default(false)
52
52
  .describe("Include bounded JavaScript source text"),
53
+ sourceCaptureApproved: z
54
+ .boolean()
55
+ .default(false)
56
+ .describe("Approve capturing bounded script source text"),
53
57
  includeStorageKeys: z
54
58
  .boolean()
55
59
  .default(false)
@@ -11,6 +11,7 @@ const capabilitySchema = z.enum([
11
11
  "browser_observe",
12
12
  "browser_automate",
13
13
  "electron_observe",
14
+ "electron_automate",
14
15
  "evidence_read",
15
16
  "evidence_write",
16
17
  "investigation_input",
@@ -0,0 +1,77 @@
1
+ import { ConfigurationError } from "../domain/errors.js";
2
+ import { err, ok } from "../domain/result.js";
3
+ import { browserEndpointSchema, browserOriginSchema, } from "../domain/browserObservation.js";
4
+ import { parseAbsoluteRoots, parseBrowserArray, parseStringArray, } from "./parsers.js";
5
+ import { browserNetworkScope, permissionScope } from "./permissions.js";
6
+ /** Parse controlled browser scenarios into a closed disabled or enabled policy. */
7
+ export const parseBrowserScenarioPolicy = (env) => {
8
+ const executableRoots = parseAbsoluteRoots(env.REA_BROWSER_SCENARIO_EXECUTABLE_ROOTS_JSON, "REA_BROWSER_SCENARIO_EXECUTABLE_ROOTS_JSON");
9
+ if (!executableRoots.ok)
10
+ return executableRoots;
11
+ const cdpEndpoints = parseBrowserArray(env.REA_BROWSER_SCENARIO_CDP_ENDPOINTS_JSON, "REA_BROWSER_SCENARIO_CDP_ENDPOINTS_JSON", browserEndpointSchema, 16);
12
+ if (!cdpEndpoints.ok)
13
+ return cdpEndpoints;
14
+ const allowedOrigins = parseBrowserArray(env.REA_BROWSER_SCENARIO_ALLOWED_ORIGINS_JSON, "REA_BROWSER_SCENARIO_ALLOWED_ORIGINS_JSON", browserOriginSchema, 32);
15
+ if (!allowedOrigins.ok)
16
+ return allowedOrigins;
17
+ const allowedEnvironment = parseStringArray(env.REA_BROWSER_SCENARIO_ALLOWED_ENV_JSON, "REA_BROWSER_SCENARIO_ALLOWED_ENV_JSON");
18
+ if (!allowedEnvironment.ok)
19
+ return allowedEnvironment;
20
+ if (env.REA_BROWSER_SCENARIO_ENABLED !== "true")
21
+ return ok({ status: "disabled" });
22
+ const [firstOrigin, ...remainingOrigins] = allowedOrigins.value;
23
+ if (firstOrigin === undefined)
24
+ return err(new ConfigurationError("REA_BROWSER_SCENARIO_ALLOWED_ORIGINS_JSON must encode at least one exact origin when browser scenarios are enabled"));
25
+ const target = parseTargetPolicy(executableRoots.value, cdpEndpoints.value);
26
+ if (!target.ok)
27
+ return target;
28
+ return ok({
29
+ status: "enabled",
30
+ target: target.value,
31
+ allowedOrigins: [firstOrigin, ...remainingOrigins],
32
+ allowedEnvironment: allowedEnvironment.value,
33
+ });
34
+ };
35
+ /** Add the separately permissioned controlled-browser ceiling. */
36
+ export const appendBrowserScenarioCeiling = (ceilings, policy) => {
37
+ if (policy.status === "disabled")
38
+ return;
39
+ const { executableRoots, cdpEndpoints } = targetScopes(policy.target);
40
+ ceilings.push(permissionScope("browser_automate", [], {
41
+ executables: executableRoots,
42
+ environment_names: policy.allowedEnvironment,
43
+ origins: [...cdpEndpoints, ...policy.allowedOrigins],
44
+ network: browserNetworkScope(policy.allowedOrigins),
45
+ }));
46
+ };
47
+ const parseTargetPolicy = (executableRoots, cdpEndpoints) => {
48
+ const [firstExecutableRoot, ...remainingExecutableRoots] = executableRoots;
49
+ const [firstCdpEndpoint, ...remainingCdpEndpoints] = cdpEndpoints;
50
+ if (firstExecutableRoot !== undefined && firstCdpEndpoint !== undefined)
51
+ return ok({
52
+ access: "launch-or-attach",
53
+ executableRoots: [firstExecutableRoot, ...remainingExecutableRoots],
54
+ cdpEndpoints: [firstCdpEndpoint, ...remainingCdpEndpoints],
55
+ });
56
+ if (firstExecutableRoot !== undefined)
57
+ return ok({
58
+ access: "launch",
59
+ executableRoots: [firstExecutableRoot, ...remainingExecutableRoots],
60
+ });
61
+ if (firstCdpEndpoint !== undefined)
62
+ return ok({
63
+ access: "attach",
64
+ cdpEndpoints: [firstCdpEndpoint, ...remainingCdpEndpoints],
65
+ });
66
+ return err(new ConfigurationError("Browser scenarios require at least one executable root or loopback CDP endpoint when enabled"));
67
+ };
68
+ const targetScopes = (target) => {
69
+ switch (target.access) {
70
+ case "launch":
71
+ return { executableRoots: target.executableRoots, cdpEndpoints: [] };
72
+ case "attach":
73
+ return { executableRoots: [], cdpEndpoints: target.cdpEndpoints };
74
+ case "launch-or-attach":
75
+ return target;
76
+ }
77
+ };
@@ -0,0 +1,35 @@
1
+ import { ConfigurationError } from "../domain/errors.js";
2
+ import { err, ok } from "../domain/result.js";
3
+ import { permissionScope } from "./permissions.js";
4
+ import { parseAbsoluteRoots } from "./parsers.js";
5
+ /** Parse active Electron automation into a closed disabled or enabled policy. */
6
+ export const parseElectronAutomationPolicy = (env) => {
7
+ const executableRoots = parseAbsoluteRoots(env.REA_ELECTRON_AUTOMATE_EXECUTABLE_ROOTS_JSON, "REA_ELECTRON_AUTOMATE_EXECUTABLE_ROOTS_JSON");
8
+ if (!executableRoots.ok)
9
+ return executableRoots;
10
+ const applicationRoots = parseAbsoluteRoots(env.REA_ELECTRON_AUTOMATE_APPLICATION_ROOTS_JSON, "REA_ELECTRON_AUTOMATE_APPLICATION_ROOTS_JSON");
11
+ if (!applicationRoots.ok)
12
+ return applicationRoots;
13
+ if (env.REA_ELECTRON_AUTOMATE_ENABLED !== "true")
14
+ return ok({ status: "disabled" });
15
+ const [firstExecutableRoot, ...remainingExecutableRoots] = executableRoots.value;
16
+ if (firstExecutableRoot === undefined)
17
+ return err(new ConfigurationError("REA_ELECTRON_AUTOMATE_EXECUTABLE_ROOTS_JSON must encode at least one absolute root when Electron automation is enabled"));
18
+ const [firstApplicationRoot, ...remainingApplicationRoots] = applicationRoots.value;
19
+ if (firstApplicationRoot === undefined)
20
+ return err(new ConfigurationError("REA_ELECTRON_AUTOMATE_APPLICATION_ROOTS_JSON must encode at least one absolute root when Electron automation is enabled"));
21
+ return ok({
22
+ status: "enabled",
23
+ executableRoots: [firstExecutableRoot, ...remainingExecutableRoots],
24
+ applicationRoots: [firstApplicationRoot, ...remainingApplicationRoots],
25
+ });
26
+ };
27
+ /** Add the separately permissioned, no-network Electron automation ceiling. */
28
+ export const appendElectronAutomationCeiling = (ceilings, policy) => {
29
+ if (policy.status === "disabled")
30
+ return;
31
+ ceilings.push(permissionScope("electron_automate", policy.applicationRoots, {
32
+ executables: policy.executableRoots,
33
+ network: "external",
34
+ }));
35
+ };
@@ -61,6 +61,12 @@ const environmentSchema = z
61
61
  REA_ELECTRON_OBSERVE_ENABLED: z.enum(["true", "false"]).default("false"),
62
62
  REA_ELECTRON_CDP_ENDPOINTS_JSON: z.string().default("[]"),
63
63
  REA_ELECTRON_FILE_ROOTS_JSON: z.string().default("[]"),
64
+ REA_ELECTRON_AUTOMATE_ENABLED: z.enum(["true", "false"]).default("false"),
65
+ REA_ELECTRON_AUTOMATE_AUTO_GRANT: z
66
+ .enum(["true", "false"])
67
+ .default("false"),
68
+ REA_ELECTRON_AUTOMATE_EXECUTABLE_ROOTS_JSON: z.string().default("[]"),
69
+ REA_ELECTRON_AUTOMATE_APPLICATION_ROOTS_JSON: z.string().default("[]"),
64
70
  REA_V8_INSPECTOR_OBSERVE_ENABLED: z
65
71
  .enum(["true", "false"])
66
72
  .default("false"),