rea-agents 2.0.0 → 2.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 (246) hide show
  1. package/README.md +78 -32
  2. package/bridge/ghidra/ReaGhidraBridge.java +96 -11
  3. package/dist/application/ArtifactExtraction.js +1 -1
  4. package/dist/application/ArtifactInventory/classify.js +42 -0
  5. package/dist/application/ArtifactInventory/hash.js +43 -0
  6. package/dist/application/ArtifactInventory/reader.js +41 -0
  7. package/dist/application/ArtifactInventory/scanCanonical.js +155 -0
  8. package/dist/application/ArtifactInventory/scanReader.js +124 -0
  9. package/dist/application/ArtifactInventory/types.js +10 -0
  10. package/dist/application/ArtifactInventory.js +9 -351
  11. package/dist/application/AuthorizedArtifactInventory.js +2 -2
  12. package/dist/application/BinarySession.js +47 -270
  13. package/dist/application/BinarySessionExecution.js +28 -0
  14. package/dist/application/BinarySessionOpen.js +39 -0
  15. package/dist/application/BinarySessionRecords.js +149 -0
  16. package/dist/application/BinarySessionStatus.js +75 -0
  17. package/dist/application/CapabilityInventory.js +24 -2
  18. package/dist/application/ClientRegistrationStatus.js +1 -1
  19. package/dist/application/CrossVersionInventory.js +8 -2
  20. package/dist/application/CrossVersionInvestigation.js +1 -23
  21. package/dist/application/CrossVersionInvestigationCollections.js +23 -0
  22. package/dist/application/DirectAnalysis.js +47 -44
  23. package/dist/application/Doctor.js +156 -238
  24. package/dist/application/DoctorDiagnostics.js +180 -0
  25. package/dist/application/ElectronBoundaryAnalysis.js +23 -7
  26. package/dist/application/ElectronBoundaryGraphWindows.js +32 -8
  27. package/dist/application/EnhancedToolPagination.js +22 -0
  28. package/dist/application/EnhancedToolTypes.js +4 -0
  29. package/dist/application/EnhancedTools.js +20 -37
  30. package/dist/application/InstrumentedJavaScriptReplayHost.js +36 -0
  31. package/dist/application/InvestigationWorkspaceStore.js +24 -10
  32. package/dist/application/JavaScriptArtifactAnalysis.js +45 -6
  33. package/dist/application/JavaScriptArtifactFiles.js +6 -2
  34. package/dist/application/JavaScriptArtifactGraphBuilder.js +23 -1
  35. package/dist/application/JavaScriptArtifactGraphBundlers.js +225 -0
  36. package/dist/application/JavaScriptArtifactGraphContext.js +37 -36
  37. package/dist/application/JavaScriptArtifactGraphDocuments.js +27 -4
  38. package/dist/application/JavaScriptArtifactGraphFindings.js +54 -8
  39. package/dist/application/JavaScriptArtifactGraphStructure.js +29 -101
  40. package/dist/application/JavaScriptArtifactPathResolution.js +269 -0
  41. package/dist/application/JavaScriptArtifactReconstruction.js +1 -1
  42. package/dist/application/JavaScriptJsonModules.js +39 -0
  43. package/dist/application/JavaScriptModuleRelationships.js +262 -0
  44. package/dist/application/JavaScriptReplayPermission.js +16 -0
  45. package/dist/application/JavaScriptReplayService.js +182 -156
  46. package/dist/application/LinuxHopper.js +10 -0
  47. package/dist/application/MacHopper.js +22 -11
  48. package/dist/application/NodeRuntimeCharacterizationService.js +196 -0
  49. package/dist/application/PermissionAuthority.js +106 -63
  50. package/dist/application/ProcessCaptureCapability.js +1 -1
  51. package/dist/application/ProcessCapturePermission.js +13 -0
  52. package/dist/application/ProcessCli.js +2 -12
  53. package/dist/application/ProcessHarness.js +1 -1
  54. package/dist/application/ProjectPermissionStore.js +48 -9
  55. package/dist/application/RealHopperAssertions.js +76 -0
  56. package/dist/application/ReconstructionCoverageService.js +69 -0
  57. package/dist/application/ReconstructionCoverageWorkspaceStore.js +31 -0
  58. package/dist/application/RuntimeExecutableDiagnostics.js +172 -0
  59. package/dist/application/Setup.js +147 -259
  60. package/dist/application/SetupClientConfiguration.js +220 -0
  61. package/dist/application/SetupClients.js +24 -2
  62. package/dist/application/SetupPlan.js +123 -12
  63. package/dist/application/SetupSkill.js +26 -12
  64. package/dist/application/SupportedClients.js +1 -0
  65. package/dist/application/Uninstall.js +6 -3
  66. package/dist/application/WindowsCapabilities.js +86 -0
  67. package/dist/artifacts/AsarArtifactReader.js +11 -0
  68. package/dist/browser/BrowserProcessStartup.js +88 -0
  69. package/dist/browser/CdpCaptureDocuments.js +12 -8
  70. package/dist/browser/CdpCaptureEventBodyShapes.js +75 -0
  71. package/dist/browser/CdpCaptureEventHandlers.js +336 -0
  72. package/dist/browser/CdpCaptureEventHelpers.js +71 -0
  73. package/dist/browser/CdpCaptureEventState.js +1 -0
  74. package/dist/browser/CdpCaptureEventTypes.js +1 -0
  75. package/dist/browser/CdpCaptureEvents.js +29 -496
  76. package/dist/browser/CdpObservationSession.js +51 -8
  77. package/dist/browser/CdpPageCapture.js +12 -133
  78. package/dist/browser/CdpPageCaptureScripts.js +97 -0
  79. package/dist/browser/CdpPageCaptureWorkers.js +46 -0
  80. package/dist/browser/CdpWebMcpDiscovery.js +38 -14
  81. package/dist/browser/PngVisualDiff.js +9 -2
  82. package/dist/catalogIdentity.js +4 -0
  83. package/dist/cli/artifactCommands.js +82 -0
  84. package/dist/cli/coreAnalysisCommands.js +232 -0
  85. package/dist/cli/managedCommands.js +397 -0
  86. package/dist/cli/managedProjectGraphCommand.js +24 -0
  87. package/dist/cli/options.js +9 -0
  88. package/dist/cli/setupCommands.js +108 -0
  89. package/dist/cli/types.js +1 -0
  90. package/dist/cli/utilityCommands.js +122 -0
  91. package/dist/cli.js +10 -768
  92. package/dist/cliApplicationCommands.js +118 -4
  93. package/dist/cliBrowserAdvancedCommands.js +73 -16
  94. package/dist/cliBrowserCommands.js +39 -115
  95. package/dist/cliCommandNames.js +4 -0
  96. package/dist/cliElectronCommands.js +33 -62
  97. package/dist/cliEvidenceCommands.js +13 -2
  98. package/dist/cliInvestigationCommands.js +53 -10
  99. package/dist/cliObservationOptions.js +137 -0
  100. package/dist/cliPolicyCommands.js +80 -46
  101. package/dist/cliSetup.js +289 -0
  102. package/dist/config/environment.js +107 -0
  103. package/dist/config/parseConfig.js +228 -0
  104. package/dist/config/parsers.js +68 -0
  105. package/dist/config/permissions.js +30 -0
  106. package/dist/config/types.js +1 -0
  107. package/dist/config.js +1 -375
  108. package/dist/contracts/applicationToolContracts.js +134 -0
  109. package/dist/contracts/managedToolContracts.js +1 -1
  110. package/dist/contracts/managedWorkflowToolContracts.js +3 -3
  111. package/dist/contracts/providerSelection.js +2 -0
  112. package/dist/contracts/toolContracts.js +2 -2
  113. package/dist/contracts/toolEffects.js +14 -0
  114. package/dist/contracts/toolOutputSchemaGroups.js +232 -0
  115. package/dist/contracts/toolOutputSchemaPrimitives.js +327 -0
  116. package/dist/contracts/toolOutputSchemas.js +2 -550
  117. package/dist/domain/analysisErrorPresentation.js +234 -0
  118. package/dist/domain/analysisErrorProjection.js +284 -0
  119. package/dist/domain/artifactComparison.js +34 -15
  120. package/dist/domain/binaryTarget.js +87 -37
  121. package/dist/domain/browserObservation.js +1 -285
  122. package/dist/domain/browserObservationSchemas.js +286 -0
  123. package/dist/domain/electronStaticAnalysisBrowser.js +14 -2
  124. package/dist/domain/errors.js +4 -486
  125. package/dist/domain/functionComparison.js +4 -165
  126. package/dist/domain/functionComparisonDimensions.js +164 -0
  127. package/dist/domain/javascriptApplicationVersionItems.js +18 -6
  128. package/dist/domain/javascriptApplicationVersionKeys.js +8 -8
  129. package/dist/domain/javascriptExportInstrumentation.js +97 -0
  130. package/dist/domain/javascriptFeatureTraversal.js +19 -7
  131. package/dist/domain/javascriptRuntimeStaticCandidates.js +3 -1
  132. package/dist/domain/javascriptSemanticAnalysis.js +386 -0
  133. package/dist/domain/javascriptSemanticIr.js +30 -0
  134. package/dist/domain/javascriptSemanticProjection.js +366 -0
  135. package/dist/domain/javascriptSemanticState.js +40 -0
  136. package/dist/domain/javascriptSemanticTraversal.js +22 -0
  137. package/dist/domain/javascriptSemanticValues.js +352 -0
  138. package/dist/domain/javascriptStaticAnalysis.js +5 -221
  139. package/dist/domain/javascriptStaticAnalysisBundler.js +209 -0
  140. package/dist/domain/javascriptStaticAnalysisCalls.js +180 -0
  141. package/dist/domain/javascriptStaticAnalysisHelpers.js +71 -2
  142. package/dist/domain/knownPageCoverage.js +21 -0
  143. package/dist/domain/managedApplicationGraph.js +14 -364
  144. package/dist/domain/managedApplicationGraphCoverage.js +170 -0
  145. package/dist/domain/managedApplicationGraphNodeCoverage.js +6 -0
  146. package/dist/domain/managedApplicationGraphNodes.js +336 -0
  147. package/dist/domain/managedArtifact.js +16 -8
  148. package/dist/domain/managedMemberComparison.js +37 -391
  149. package/dist/domain/managedMemberComparisonCoverage.js +72 -0
  150. package/dist/domain/managedMemberComparisonMatch.js +356 -0
  151. package/dist/domain/managedNativeVerification.js +27 -389
  152. package/dist/domain/managedNativeVerificationMatch.js +272 -0
  153. package/dist/domain/managedNativeVerificationSchemas.js +141 -0
  154. package/dist/domain/managedReconstruction.js +82 -69
  155. package/dist/domain/managedRuntimeCorrelation.js +12 -3
  156. package/dist/domain/nodeRuntimeCharacterization.js +66 -0
  157. package/dist/domain/permissionPolicy.js +2 -0
  158. package/dist/domain/reconstructionCoverage.js +387 -0
  159. package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
  160. package/dist/domain/reconstructionVerificationSchemas.js +8 -0
  161. package/dist/domain/runtimeCharacterization.js +85 -0
  162. package/dist/domain/webBundleAnalyzer.js +3 -409
  163. package/dist/domain/webBundleAnalyzerAst.js +77 -0
  164. package/dist/domain/webBundleAnalyzerInspection.js +307 -0
  165. package/dist/domain/webBundleAnalyzerResult.js +120 -0
  166. package/dist/dotnet/ManagedArtifactInspector.js +50 -29
  167. package/dist/dotnet/ManagedMemberInspector.js +51 -785
  168. package/dist/dotnet/ManagedMemberInspectorCore.js +297 -0
  169. package/dist/dotnet/ManagedMemberInstructionDecoder.js +427 -0
  170. package/dist/dotnet/ManagedMemberRows.js +120 -0
  171. package/dist/dotnet/ManagedMetadataInventory.js +42 -306
  172. package/dist/dotnet/ManagedMetadataInventoryRows.js +292 -0
  173. package/dist/dotnet/ManagedMetadataLayout.js +48 -111
  174. package/dist/dotnet/ManagedMetadataRowSizes.js +54 -0
  175. package/dist/dotnet/ManagedMethodBodyReader.js +143 -0
  176. package/dist/dotnet/ManagedNativeBoundaryHelpers.js +311 -0
  177. package/dist/dotnet/ManagedNativeBoundaryInspector.js +102 -350
  178. package/dist/dotnet/ManagedPeReader.js +59 -28
  179. package/dist/generatedPackageMetadata.js +2 -2
  180. package/dist/ghidra/GhidraClient.js +76 -91
  181. package/dist/ghidra/GhidraClientStartup.js +29 -0
  182. package/dist/ghidra/GhidraClientWire.js +34 -0
  183. package/dist/ghidra/GhidraDefaults.js +1 -1
  184. package/dist/ghidra/GhidraDiagnostics.js +6 -1
  185. package/dist/ghidra/GhidraInstallation.js +20 -15
  186. package/dist/ghidra/GhidraLauncher.js +93 -29
  187. package/dist/ghidra/GhidraProvider.js +61 -161
  188. package/dist/ghidra/GhidraProviderCapabilities.js +173 -0
  189. package/dist/ghidra/GhidraSessionValues.js +2 -0
  190. package/dist/ghidra/GhidraSocketConnection.js +44 -7
  191. package/dist/ghidra/GhidraTargetSnapshot.js +30 -0
  192. package/dist/ghidra/GhidraTransport.js +71 -0
  193. package/dist/identity.js +3 -2
  194. package/dist/main/messages.js +5 -0
  195. package/dist/main/reload.js +49 -0
  196. package/dist/main/shutdown.js +25 -0
  197. package/dist/main/startup.js +14 -0
  198. package/dist/main/state.js +26 -0
  199. package/dist/main/transport.js +61 -0
  200. package/dist/main/types.js +1 -0
  201. package/dist/main.js +35 -146
  202. package/dist/process/PrivateRuntimeRoot.js +3 -2
  203. package/dist/process/ProcessOwnership.js +35 -0
  204. package/dist/process/ProviderProcess.js +2 -0
  205. package/dist/replay/JavaScriptReplayWorker.js +64 -50
  206. package/dist/replay/LinuxJavaScriptReplayRunner.js +173 -390
  207. package/dist/replay/LinuxJavaScriptReplaySandbox.js +140 -0
  208. package/dist/replay/ReplayOutcome.js +95 -0
  209. package/dist/replay/ReplayProcessLifecycle.js +71 -0
  210. package/dist/server/ProcessCaptureElicitation.js +157 -0
  211. package/dist/server/createServer.js +119 -54
  212. package/dist/server/registerApplicationTools/characterization.js +57 -0
  213. package/dist/server/registerApplicationTools/compareVersions.js +34 -0
  214. package/dist/server/registerApplicationTools/controlledReplay.js +38 -0
  215. package/dist/server/registerApplicationTools/coverage.js +84 -0
  216. package/dist/server/registerApplicationTools/helpers.js +42 -0
  217. package/dist/server/registerApplicationTools/traceFeature.js +26 -0
  218. package/dist/server/registerApplicationTools/types.js +1 -0
  219. package/dist/server/registerApplicationTools.js +10 -112
  220. package/dist/server/registerBrowserTools.js +59 -83
  221. package/dist/server/registerElectronTools.js +31 -46
  222. package/dist/server/registerEnhancedTools.js +34 -42
  223. package/dist/server/registerEvidenceResources.js +54 -0
  224. package/dist/server/registerInvestigationTools/helpers.js +74 -0
  225. package/dist/server/registerInvestigationTools/types.js +1 -0
  226. package/dist/server/registerInvestigationTools.js +83 -116
  227. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +65 -0
  228. package/dist/server/registerManagedWorkflowTools/contract.js +8 -0
  229. package/dist/server/registerManagedWorkflowTools/evidence.js +43 -0
  230. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +39 -0
  231. package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +39 -0
  232. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +52 -0
  233. package/dist/server/registerManagedWorkflowTools/types.js +1 -0
  234. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +75 -0
  235. package/dist/server/registerManagedWorkflowTools.js +10 -274
  236. package/dist/server/registerOfficialTools.js +73 -59
  237. package/dist/server/registerSessionRecordTools.js +137 -0
  238. package/dist/server/registerSessionStatusTool.js +2 -1
  239. package/dist/server/registerSessionTools.js +60 -164
  240. package/dist/server/sessionAvailabilityPolicy.js +10 -0
  241. package/dist/server/toolRegistrationOptions.js +101 -3
  242. package/dist/server/toolResult.js +5 -0
  243. package/package.json +10 -11
  244. package/skills/{rea-analysis → reverse-engineer-anything}/SKILL.md +20 -7
  245. package/scripts/prepare-node-pty.mjs +0 -35
  246. package/scripts/rebuild-native.mjs +0 -22
@@ -11,31 +11,74 @@ const investigationOptionsSchema = z.object({
11
11
  .boolean()
12
12
  .default(false)
13
13
  .describe("Approve persistent workspace writes"),
14
- workspaceName: z.string().trim().min(1).max(200).default("default"),
15
- expectedRevision: z.number().int().min(1).optional(),
14
+ workspaceName: z
15
+ .string()
16
+ .trim()
17
+ .min(1)
18
+ .max(200)
19
+ .default("default")
20
+ .describe("Logical name recorded in the investigation workspace"),
21
+ expectedRevision: z
22
+ .number()
23
+ .int()
24
+ .min(1)
25
+ .optional()
26
+ .describe("Required current workspace revision for an atomic update"),
16
27
  replayRunId: z
17
28
  .string()
18
29
  .regex(/^run_[a-f0-9]{64}$/u)
19
30
  .optional()
20
31
  .describe("Replay one verified complete workspace run without rescanning"),
21
- maxEntries: z.number().int().min(1).max(50_000).default(10_000),
32
+ maxEntries: z
33
+ .number()
34
+ .int()
35
+ .min(1)
36
+ .max(50_000)
37
+ .default(10_000)
38
+ .describe("Maximum artifact entries to inspect per version"),
22
39
  maxTotalBytes: z
23
40
  .number()
24
41
  .int()
25
42
  .min(1)
26
43
  .max(Number.MAX_SAFE_INTEGER)
27
- .default(1_073_741_824),
44
+ .default(1_073_741_824)
45
+ .describe("Maximum total uncompressed artifact content to inspect"),
28
46
  maxEntryBytes: z
29
47
  .number()
30
48
  .int()
31
49
  .min(1)
32
50
  .max(Number.MAX_SAFE_INTEGER)
33
- .default(268_435_456),
34
- pageSize: z.number().int().min(1).max(500).default(500),
35
- changeLimit: z.number().int().min(1).max(500).default(500),
36
- integrityPolicy: z.enum(["fail", "record-and-continue"]).default("fail"),
37
- integrityContinueApproved: z.boolean().default(false),
38
- maxIntegrityMismatches: z.number().int().min(1).max(100).default(10),
51
+ .default(268_435_456)
52
+ .describe("Maximum uncompressed content to inspect for one entry"),
53
+ pageSize: z
54
+ .number()
55
+ .int()
56
+ .min(1)
57
+ .max(500)
58
+ .default(500)
59
+ .describe("Maximum graph items loaded per investigation page"),
60
+ changeLimit: z
61
+ .number()
62
+ .int()
63
+ .min(1)
64
+ .max(500)
65
+ .default(500)
66
+ .describe("Maximum version changes to record"),
67
+ integrityPolicy: z
68
+ .enum(["fail", "record-and-continue"])
69
+ .default("fail")
70
+ .describe("Behavior when declared artifact integrity does not match"),
71
+ integrityContinueApproved: z
72
+ .boolean()
73
+ .default(false)
74
+ .describe("Approve continuing after recorded integrity mismatches"),
75
+ maxIntegrityMismatches: z
76
+ .number()
77
+ .int()
78
+ .min(1)
79
+ .max(100)
80
+ .default(10)
81
+ .describe("Maximum integrity mismatches to record before stopping"),
39
82
  });
40
83
  /** Register the persistent cross-version CLI workflow. */
41
84
  export const registerInvestigationCommands = (cli, logger) => {
@@ -0,0 +1,137 @@
1
+ import { z } from "incur";
2
+ const boundedCount = (subject, maximum, fallback, minimum = 1) => z
3
+ .number()
4
+ .int()
5
+ .min(minimum)
6
+ .max(maximum)
7
+ .default(fallback)
8
+ .describe(`Maximum ${subject}`);
9
+ const boundedBytes = (subject, maximum, fallback) => boundedCount(`${subject} in bytes`, maximum, fallback);
10
+ const positiveCount = (subject, fallback) => z.number().int().min(1).default(fallback).describe(`Maximum ${subject}`);
11
+ const browserScopeOptions = {
12
+ allowedOrigins: z
13
+ .array(z.string().min(1))
14
+ .optional()
15
+ .describe("Exact origins to observe; defaults to REA_BROWSER_ALLOWED_ORIGINS_JSON"),
16
+ approved: z.boolean().default(false).describe("Approve passive observation"),
17
+ };
18
+ export const browserPageInspectionOptions = z.object({
19
+ ...browserScopeOptions,
20
+ observationMs: boundedCount("observation duration in milliseconds", 10_000, 500, 0),
21
+ includeAccessibilityText: z
22
+ .boolean()
23
+ .default(false)
24
+ .describe("Include bounded accessibility text"),
25
+ includeConsoleText: z
26
+ .boolean()
27
+ .default(false)
28
+ .describe("Include bounded console message text"),
29
+ consoleTextApproved: z
30
+ .boolean()
31
+ .default(false)
32
+ .describe("Approve capturing console message text"),
33
+ includeJsonBodyShapes: z
34
+ .boolean()
35
+ .default(false)
36
+ .describe("Include structural shapes of JSON response bodies"),
37
+ jsonBodySchemaApproved: z
38
+ .boolean()
39
+ .default(false)
40
+ .describe("Approve inspecting JSON response bodies for structural shapes"),
41
+ includeWebsocketShapes: z
42
+ .boolean()
43
+ .default(false)
44
+ .describe("Include structural shapes of WebSocket payloads"),
45
+ websocketShapeApproved: z
46
+ .boolean()
47
+ .default(false)
48
+ .describe("Approve inspecting WebSocket payloads for structural shapes"),
49
+ includeScriptSources: z
50
+ .boolean()
51
+ .default(false)
52
+ .describe("Include bounded JavaScript source text"),
53
+ includeStorageKeys: z
54
+ .boolean()
55
+ .default(false)
56
+ .describe("Include storage key names without values"),
57
+ maxFrames: boundedCount("page frames", 1_000, 200),
58
+ maxDomNodes: boundedCount("DOM nodes", 10_000, 2_000),
59
+ maxAxNodes: boundedCount("accessibility nodes", 10_000, 2_000),
60
+ maxAxTextFieldBytes: boundedBytes("one accessibility text field", 16 * 1_024, 1_024),
61
+ maxTotalAxTextBytes: boundedBytes("total accessibility text", 1_024 * 1_024, 64 * 1_024),
62
+ maxScripts: boundedCount("scripts", 1_000, 200),
63
+ maxResources: boundedCount("resources", 10_000, 2_000),
64
+ maxWorkers: boundedCount("workers", 5_000, 500),
65
+ maxStorageKeys: boundedCount("storage keys", 10_000, 1_000),
66
+ maxScriptSourceBytes: boundedBytes("one script source", 4 * 1_024 * 1_024, 1_024 * 1_024),
67
+ maxTotalScriptSourceBytes: boundedBytes("total script source", 16 * 1_024 * 1_024, 4 * 1_024 * 1_024),
68
+ maxNetworkEvents: boundedCount("network events", 10_000, 1_000),
69
+ maxConsoleEvents: boundedCount("console events", 2_000, 200),
70
+ maxConsoleTextFieldBytes: boundedBytes("one console text field", 16 * 1_024, 1_024),
71
+ maxTotalConsoleTextBytes: boundedBytes("total console text", 1_024 * 1_024, 64 * 1_024),
72
+ maxJsonBodyBytes: boundedBytes("one JSON response body", 4 * 1_024 * 1_024, 1_024 * 1_024),
73
+ maxTotalJsonBodyBytes: boundedBytes("total JSON response bodies", 16 * 1_024 * 1_024, 4 * 1_024 * 1_024),
74
+ maxJsonShapeNodes: boundedCount("JSON shape nodes", 100_000, 5_000),
75
+ maxJsonShapeDepth: boundedCount("JSON shape depth", 100, 20),
76
+ maxWebsocketEvents: boundedCount("WebSocket events", 5_000, 500),
77
+ maxWebsocketShapeBytes: boundedBytes("one WebSocket shape", 1_024 * 1_024, 64 * 1_024),
78
+ maxTotalWebsocketShapeBytes: boundedBytes("total WebSocket shapes", 16 * 1_024 * 1_024, 1_024 * 1_024),
79
+ });
80
+ const electronScopeOptions = {
81
+ allowedFileRoots: z
82
+ .array(z.string().min(1))
83
+ .optional()
84
+ .describe("Filesystem roots; defaults to REA_ELECTRON_FILE_ROOTS_JSON"),
85
+ approved: z.boolean().default(false).describe("Approve passive observation"),
86
+ };
87
+ export const electronPageInspectionOptions = z.object({
88
+ ...electronScopeOptions,
89
+ observationMs: boundedCount("observation duration in milliseconds", 10_000, 100, 0),
90
+ includeScriptSources: z
91
+ .boolean()
92
+ .default(false)
93
+ .describe("Include bounded JavaScript source text"),
94
+ sourceCaptureApproved: z
95
+ .boolean()
96
+ .default(false)
97
+ .describe("Approve capturing bounded script source text"),
98
+ maxFrames: boundedCount("page frames", 1_000, 200),
99
+ maxDomNodes: boundedCount("DOM nodes", 10_000, 2_000),
100
+ maxScripts: boundedCount("scripts", 2_000, 500),
101
+ maxResources: boundedCount("resources", 10_000, 2_000),
102
+ maxWorkers: boundedCount("workers", 5_000, 500),
103
+ maxScriptSourceBytes: boundedBytes("one captured script source", 4 * 1_024 * 1_024, 1_024 * 1_024),
104
+ maxTotalScriptSourceBytes: boundedBytes("total captured script source", 16 * 1_024 * 1_024, 4 * 1_024 * 1_024),
105
+ });
106
+ export const javascriptApplicationOptions = z.object({
107
+ approved: z
108
+ .boolean()
109
+ .default(false)
110
+ .describe("Approve reading the application artifact"),
111
+ format: z
112
+ .enum(["auto", "asar", "directory"])
113
+ .default("auto")
114
+ .describe("Application artifact format"),
115
+ sourceMapReadApproved: z
116
+ .boolean()
117
+ .default(false)
118
+ .describe("Approve reading local source maps referenced by the application"),
119
+ maxEntries: positiveCount("artifact entries to inspect", 8_000),
120
+ maxTotalArtifactBytes: positiveCount("total uncompressed artifact content to inspect", 512 * 1_024 * 1_024),
121
+ maxArtifactEntryBytes: positiveCount("uncompressed content for one artifact entry", 128 * 1_024 * 1_024),
122
+ maxCompressionRatio: z
123
+ .number()
124
+ .min(1)
125
+ .default(1_000)
126
+ .describe("Maximum accepted compressed-to-uncompressed expansion ratio"),
127
+ maxDepth: positiveCount("artifact directory depth", 64),
128
+ maxPathBytes: positiveCount("encoded artifact path length", 4_096),
129
+ maxTextFiles: positiveCount("text files to parse", 5_000),
130
+ maxTotalTextBytes: positiveCount("total text content to parse", 128 * 1_024 * 1_024),
131
+ maxTextFileBytes: positiveCount("size of one parsed text file", 8 * 1_024 * 1_024),
132
+ maxAstNodes: positiveCount("JavaScript AST nodes to parse", 2_000_000),
133
+ maxFindings: positiveCount("static-analysis findings to return", 8_000),
134
+ maxModules: positiveCount("application modules to project", 20_000),
135
+ maxSourceMapSources: positiveCount("original sources from source maps", 5_000),
136
+ maxParseMilliseconds: positiveCount("JavaScript parsing time in milliseconds", 30_000),
137
+ });
@@ -36,17 +36,40 @@ export const registerPolicyCommands = (cli, logger) => {
36
36
  cli.command(CLI_COMMANDS.policy, {
37
37
  description: "Inspect, explain, or revoke unified local permission grants",
38
38
  args: z.object({
39
- action: z.enum(["status", "list", "explain", "revoke"]),
40
- value: z.string().optional(),
39
+ action: z
40
+ .enum(["status", "list", "explain", "revoke"])
41
+ .describe("Permission-policy operation to perform"),
42
+ value: z
43
+ .string()
44
+ .optional()
45
+ .describe("Capability to explain or grant ID to revoke"),
41
46
  }),
42
47
  options: z.object({
43
- root: z.string().optional(),
44
- executable: z.string().optional(),
45
- environmentNames: z.array(z.string()).default([]),
46
- origins: z.array(z.string()).default([]),
47
- network: z.enum(["none", "loopback", "external"]).default("none"),
48
- mount: z.boolean().default(false),
49
- write: z.boolean().default(false),
48
+ root: z.string().optional().describe("Filesystem root to authorize"),
49
+ executable: z
50
+ .string()
51
+ .optional()
52
+ .describe("Executable path to authorize"),
53
+ environmentNames: z
54
+ .array(z.string())
55
+ .default([])
56
+ .describe("Environment variable names the operation may read"),
57
+ origins: z
58
+ .array(z.string())
59
+ .default([])
60
+ .describe("Exact browser origins the operation may access"),
61
+ network: z
62
+ .enum(["none", "loopback", "external"])
63
+ .default("none")
64
+ .describe("Maximum network scope to authorize"),
65
+ mount: z
66
+ .boolean()
67
+ .default(false)
68
+ .describe("Authorize mounting an artifact filesystem"),
69
+ write: z
70
+ .boolean()
71
+ .default(false)
72
+ .describe("Explain the write form of the requested capability"),
50
73
  yes: z
51
74
  .boolean()
52
75
  .default(false)
@@ -58,56 +81,67 @@ export const registerPolicyCommands = (cli, logger) => {
58
81
  if (!config.ok)
59
82
  return failure(config.error);
60
83
  if (args.action === "status")
61
- return {
62
- reload: "SIGHUP",
63
- restart_required: false,
64
- administrator_ceilings: config.value.permissionCeilings,
65
- project_store: config.value.permissionProjectStore ?? null,
66
- };
84
+ return policyStatus(config.value);
67
85
  if (args.action === "list")
68
- return readProjectGrants(config.value).then((result) => result.ok ? { grants: result.grants } : result.error);
69
- if (args.action === "revoke") {
70
- if (args.value === undefined)
71
- return { error: "Grant ID is required for policy revoke" };
72
- const { permissionProjectRoot, permissionProjectStore } = config.value;
73
- if (permissionProjectRoot === undefined ||
74
- permissionProjectStore === undefined)
75
- return { error: "Project policy is not configured" };
76
- const approval = await approvePolicyRevocation({
86
+ return policyList(config.value);
87
+ if (args.action === "revoke")
88
+ return policyRevoke({
89
+ config: config.value,
90
+ grantId: args.value,
77
91
  approved: options.yes,
78
92
  interactive: !agent && !formatExplicit && process.stdin.isTTY === true,
79
- grantId: args.value,
80
93
  confirm: confirmPolicyRevocation,
81
94
  });
82
- if (!approval.approved)
83
- return approval.reason === "required"
84
- ? {
85
- error: "Policy revoke requires confirmation. Rerun interactively or with --yes.",
86
- grant_id: args.value,
87
- }
88
- : {
89
- error: "Policy revocation was cancelled",
90
- grant_id: args.value,
91
- };
92
- const revoked = await revokeProjectPermissionGrant(permissionProjectStore, permissionProjectRoot, args.value);
93
- return revoked.ok && revoked.value
94
- ? {
95
- revoked: args.value,
96
- reload: "Send SIGHUP to the REA MCP process",
97
- }
98
- : revoked.ok
99
- ? { error: "Grant was not found", grant_id: args.value }
100
- : { error: revoked.error.message };
101
- }
102
95
  const capability = capabilitySchema.safeParse(args.value);
103
96
  if (!capability.success)
104
97
  return {
105
98
  error: "A registered capability is required for policy explain",
106
99
  };
107
- return explain(config.value, capability.data, options);
100
+ return policyExplain(config.value, capability.data, options);
108
101
  }),
109
102
  });
110
103
  };
104
+ const policyStatus = (config) => ({
105
+ reload: "SIGHUP",
106
+ restart_required: false,
107
+ administrator_ceilings: config.permissionCeilings,
108
+ project_store: config.permissionProjectStore ?? null,
109
+ });
110
+ const policyList = (config) => readProjectGrants(config).then((result) => result.ok ? { grants: result.grants } : result.error);
111
+ const policyRevoke = async (context) => {
112
+ if (context.grantId === undefined)
113
+ return { error: "Grant ID is required for policy revoke" };
114
+ const { permissionProjectRoot, permissionProjectStore } = context.config;
115
+ if (permissionProjectRoot === undefined ||
116
+ permissionProjectStore === undefined)
117
+ return { error: "Project policy is not configured" };
118
+ const approval = await approvePolicyRevocation({
119
+ approved: context.approved,
120
+ interactive: context.interactive,
121
+ grantId: context.grantId,
122
+ confirm: context.confirm,
123
+ });
124
+ if (!approval.approved)
125
+ return approval.reason === "required"
126
+ ? {
127
+ error: "Policy revoke requires confirmation. Rerun interactively or with --yes.",
128
+ grant_id: context.grantId,
129
+ }
130
+ : {
131
+ error: "Policy revocation was cancelled",
132
+ grant_id: context.grantId,
133
+ };
134
+ const revoked = await revokeProjectPermissionGrant(permissionProjectStore, permissionProjectRoot, context.grantId);
135
+ return revoked.ok && revoked.value
136
+ ? {
137
+ revoked: context.grantId,
138
+ reload: "Send SIGHUP to the REA MCP process",
139
+ }
140
+ : revoked.ok
141
+ ? { error: "Grant was not found", grant_id: context.grantId }
142
+ : { error: revoked.error.message };
143
+ };
144
+ const policyExplain = async (config, capability, options) => explain(config, capability, options);
111
145
  const confirmPolicyRevocation = async (grantId) => {
112
146
  const prompt = createInterface({
113
147
  input: process.stdin,
@@ -0,0 +1,289 @@
1
+ import { cancel, confirm, intro, isCancel, multiselect, outro, } from "@clack/prompts";
2
+ import { SUPPORTED_CLIENT_DEFINITIONS } from "./application/SupportedClients.js";
3
+ const clientDisplayNames = new Map(SUPPORTED_CLIENT_DEFINITIONS.map(({ name, displayName }) => [
4
+ name,
5
+ displayName,
6
+ ]));
7
+ const promptStreams = {
8
+ input: process.stdin,
9
+ output: process.stderr,
10
+ withGuide: true,
11
+ };
12
+ const agentAccessCapabilityId = "agent_access";
13
+ /** Run the inline setup picker, exact preflight, and default-No consent. */
14
+ export const confirmInteractiveSetup = async (actions, accessible) => {
15
+ intro("REA setup", promptStreams);
16
+ renderValueIntroduction();
17
+ renderDetectedSummary(actions);
18
+ renderKeyboardHelp(accessible);
19
+ const selectedActionIds = await selectSetupActions(actions, accessible);
20
+ if (selectedActionIds === undefined)
21
+ return cancelledDecision();
22
+ if (selectedActionIds.length === 0) {
23
+ cancel("Nothing selected. No changes were made.", promptStreams);
24
+ return { approved: false, selectedActionIds };
25
+ }
26
+ const selected = new Set(selectedActionIds);
27
+ const selectedActions = actions.filter(({ id }) => selected.has(id));
28
+ renderPreflight(selectedActions);
29
+ const approved = await confirm({
30
+ ...promptStreams,
31
+ message: selectedActions.length === 1
32
+ ? "Apply this change?"
33
+ : `Apply these ${String(selectedActions.length)} changes?`,
34
+ initialValue: false,
35
+ active: "Yes, apply",
36
+ inactive: "No, cancel",
37
+ });
38
+ if (isCancel(approved) || !approved) {
39
+ cancel("Setup cancelled. No changes were made.", promptStreams);
40
+ return { approved: false, selectedActionIds };
41
+ }
42
+ return { approved: true, selectedActionIds };
43
+ };
44
+ /** Render stable, append-only progress for real setup operations. */
45
+ export const renderSetupProgress = (event) => {
46
+ const symbol = event.state === "started"
47
+ ? "◇"
48
+ : event.state === "completed"
49
+ ? "◆"
50
+ : event.state === "warning"
51
+ ? "!"
52
+ : "✗";
53
+ const suffix = event.detail === undefined ? "" : ` · ${event.detail}`;
54
+ writeLine(`${symbol} ${event.label}${suffix}`);
55
+ };
56
+ /** Finish an interactive setup journey without exposing the full doctor catalog. */
57
+ export const renderInteractiveSetupResult = (result) => {
58
+ if (result.status === "ready") {
59
+ const changedClients = Object.entries(result.clients)
60
+ .filter(([, client]) => client.status === "configured")
61
+ .map(([client]) => clientDisplayNames.get(client) ?? client);
62
+ const readyClients = readyAgentClients(result, changedClients);
63
+ renderReadyCapabilities(result, readyClients);
64
+ outro(changedClients.length === 0
65
+ ? "REA is ready for local app analysis."
66
+ : `Restart ${changedClients.join(", ")} to load REA.`, promptStreams);
67
+ return;
68
+ }
69
+ if (result.status === "planned")
70
+ return;
71
+ writeLine(`! ${result.remediation ?? "Setup needs attention."}`);
72
+ outro("Run `rea doctor` for the remaining checks.", promptStreams);
73
+ };
74
+ /** Keep default non-TTY output actionable without emitting the full catalog. */
75
+ export const conciseSetupResult = (result) => ({
76
+ status: result.status,
77
+ plannedActions: result.plannedActions,
78
+ appliedActions: result.appliedActions,
79
+ clients: result.clients,
80
+ doctor: {
81
+ healthy: result.doctor.healthy,
82
+ checks: result.doctor.checks.filter(({ ok }) => !ok),
83
+ },
84
+ ...(result.code === undefined ? {} : { code: result.code }),
85
+ ...(result.remediation === undefined
86
+ ? {}
87
+ : { remediation: result.remediation }),
88
+ });
89
+ const selectSetupActions = async (actions, accessible) => {
90
+ const clientActions = actions.filter(({ kind }) => kind === "configure_client");
91
+ const componentActions = actions.filter(({ kind }) => kind !== "configure_client");
92
+ const capabilities = setupCapabilities(clientActions, componentActions);
93
+ const selectedCapabilities = accessible
94
+ ? await selectCapabilitiesAccessibly(capabilities)
95
+ : await selectCapabilities(capabilities);
96
+ if (selectedCapabilities === undefined)
97
+ return undefined;
98
+ const selectedCapabilityIds = new Set(selectedCapabilities);
99
+ const selectedActionIds = componentActions
100
+ .filter(({ id }) => selectedCapabilityIds.has(id))
101
+ .map(({ id }) => id);
102
+ if (!selectedCapabilityIds.has(agentAccessCapabilityId))
103
+ return selectedActionIds;
104
+ const selectedClients = accessible
105
+ ? await selectClientsAccessibly(clientActions)
106
+ : await selectClients(clientActions);
107
+ return selectedClients === undefined
108
+ ? undefined
109
+ : [...selectedClients, ...selectedActionIds];
110
+ };
111
+ const setupCapabilities = (clientActions, componentActions) => [
112
+ ...(clientActions.length === 0
113
+ ? []
114
+ : [
115
+ {
116
+ id: agentAccessCapabilityId,
117
+ label: "Coding-agent access (MCP)",
118
+ hint: `${String(clientActions.length)} detected ${clientActions.length === 1 ? "agent" : "agents"}`,
119
+ },
120
+ ]),
121
+ ...componentActions.map((action) => ({
122
+ id: action.id,
123
+ label: `${action.label} (${actionModality(action)})`,
124
+ hint: `${action.operation} · ${action.target}`,
125
+ })),
126
+ ];
127
+ const selectCapabilities = async (capabilities) => {
128
+ const selection = await multiselect({
129
+ ...promptStreams,
130
+ message: "What should REA set up?",
131
+ options: capabilities.map((capability) => ({
132
+ value: capability.id,
133
+ label: capability.label,
134
+ hint: capability.hint,
135
+ })),
136
+ required: false,
137
+ maxItems: Math.max(3, Math.min(capabilities.length, (process.stderr.rows ?? 24) - 8)),
138
+ showInstructions: true,
139
+ });
140
+ return isCancel(selection) ? undefined : selection;
141
+ };
142
+ const selectCapabilitiesAccessibly = async (capabilities) => {
143
+ const selected = [];
144
+ for (const capability of capabilities) {
145
+ const included = await confirm({
146
+ ...promptStreams,
147
+ message: `Set up ${capability.label}? ${capability.hint}`,
148
+ initialValue: false,
149
+ vertical: true,
150
+ });
151
+ if (isCancel(included))
152
+ return undefined;
153
+ if (included)
154
+ selected.push(capability.id);
155
+ }
156
+ return selected;
157
+ };
158
+ const selectClients = async (actions) => {
159
+ const selection = await multiselect({
160
+ ...promptStreams,
161
+ message: "Which agents should use REA?",
162
+ options: actions.map((action) => ({
163
+ value: action.id,
164
+ label: `${action.label} (detected)`,
165
+ hint: `${action.operation} · ${action.target}`,
166
+ })),
167
+ required: false,
168
+ maxItems: Math.max(3, Math.min(actions.length, (process.stderr.rows ?? 24) - 8)),
169
+ showInstructions: true,
170
+ });
171
+ return isCancel(selection) ? undefined : selection;
172
+ };
173
+ const selectClientsAccessibly = async (actions) => {
174
+ const selected = [];
175
+ for (const action of actions) {
176
+ const included = await confirm({
177
+ ...promptStreams,
178
+ message: `Configure ${action.label}? ${action.target}`,
179
+ initialValue: false,
180
+ vertical: true,
181
+ });
182
+ if (isCancel(included))
183
+ return undefined;
184
+ if (included)
185
+ selected.push(action.id);
186
+ }
187
+ return selected;
188
+ };
189
+ const renderValueIntroduction = () => {
190
+ writeLine("│ Understand local apps and binaries from your coding agent.");
191
+ writeLine("│");
192
+ writeLine("│ • Trace how a feature works with local evidence.");
193
+ writeLine("│ • Use the same analysis capabilities from REA's CLI and supported agents.");
194
+ writeLine("│ • Keep analyzed targets on this machine instead of uploading them to a hosted service.");
195
+ };
196
+ const renderDetectedSummary = (actions) => {
197
+ const clients = actions.filter(({ kind }) => kind === "configure_client");
198
+ writeLine("│");
199
+ if (clients.length === 0) {
200
+ writeLine("◆ No agent integrations need configuration");
201
+ }
202
+ else {
203
+ writeLine(`◆ Found ${String(clients.length)} supported ${clients.length === 1 ? "agent" : "agents"}`);
204
+ writeLine(`│ ${humanList(clients.map(({ label }) => label))}`);
205
+ }
206
+ };
207
+ const renderKeyboardHelp = (accessible) => {
208
+ writeLine("│");
209
+ writeLine(accessible
210
+ ? "│ Keys: Enter answer · Ctrl-C cancel"
211
+ : "│ Keys: ↑/↓ navigate · Space toggle · Enter confirm · Ctrl-C cancel");
212
+ };
213
+ const renderReadyCapabilities = (result, readyClients) => {
214
+ writeLine("◆ What you can do now");
215
+ const providers = readyProviders(result);
216
+ if (providers.length > 0)
217
+ writeLine(`│ Deep analysis: ${humanList(providers)}`);
218
+ if (readyClients.length > 0)
219
+ writeLine(`│ Agent access: ${humanList(readyClients)}`);
220
+ if (result.doctor.identity?.skill.state === "aligned")
221
+ writeLine("│ Guided reverse-engineering workflows: installed");
222
+ if (providers.length > 0)
223
+ writeLine("│ CLI: rea analyze /path/to/app");
224
+ const firstClient = readyClients[0];
225
+ if (firstClient !== undefined)
226
+ writeLine(`│ Try in ${firstClient}: "Use REA to explain how a feature works in /path/to/app."`);
227
+ };
228
+ const readyAgentClients = (result, changedClients) => {
229
+ const alignedClients = (result.doctor.identity?.registrations ?? [])
230
+ .filter(({ state }) => state === "aligned")
231
+ .map(({ client }) => clientDisplayNames.get(client) ?? client);
232
+ return [...new Set([...alignedClients, ...changedClients])];
233
+ };
234
+ const readyProviders = (result) => {
235
+ const providers = [
236
+ ...(result.doctor.hopperPath === undefined ? [] : ["Hopper"]),
237
+ ...(result.doctor.providerInspections ?? [])
238
+ .filter(({ available }) => available)
239
+ .map(({ id }) => displayProviderId(id)),
240
+ ];
241
+ return [...new Set(providers)];
242
+ };
243
+ const displayProviderId = (id) => id.length === 0 ? id : `${id[0]?.toUpperCase() ?? ""}${id.slice(1)}`;
244
+ const actionModality = (action) => {
245
+ if (action.kind === "configure_client")
246
+ return "MCP";
247
+ if (action.kind === "install_hopper")
248
+ return "provider";
249
+ return "skill";
250
+ };
251
+ const humanList = (values) => {
252
+ if (values.length < 2)
253
+ return values[0] ?? "";
254
+ if (values.length === 2)
255
+ return `${values[0]} and ${values[1]}`;
256
+ return `${values.slice(0, -1).join(", ")}, and ${values.at(-1)}`;
257
+ };
258
+ const renderPreflight = (actions) => {
259
+ writeLine("│");
260
+ writeLine("◆ Ready to review");
261
+ for (const action of actions) {
262
+ writeLine("│");
263
+ writeLine(`│ ${action.operation.toUpperCase()} ${action.label}`);
264
+ writeLine(`│ ${action.target}`);
265
+ if (action.backupPath !== undefined)
266
+ writeLine(`│ backup: ${action.backupPath}`);
267
+ for (const origin of action.networkOrigins ?? [])
268
+ writeLine(`│ network: ${origin}`);
269
+ if (action.integrity !== undefined)
270
+ writeLine(`│ integrity: ${action.integrity}`);
271
+ for (const command of action.commands ?? [])
272
+ writeLine(`│ command: ${command}`);
273
+ writeLine(`│ ${action.detail}`);
274
+ if (action.external)
275
+ writeLine("│ external software");
276
+ }
277
+ writeLine("│");
278
+ writeLine("│ REA will preserve unrelated configuration and will not install or upgrade Node.js, npm, Homebrew, Java, or Ghidra.");
279
+ };
280
+ const cancelledDecision = () => {
281
+ cancel("Setup cancelled. No changes were made.", promptStreams);
282
+ return {
283
+ approved: false,
284
+ selectedActionIds: [],
285
+ };
286
+ };
287
+ const writeLine = (line) => {
288
+ process.stderr.write(`${line}\n`);
289
+ };