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
@@ -1,18 +1,33 @@
1
1
  import { Cli, z } from "incur";
2
2
  import { compareApplicationVersionsEvidence, traceApplicationFeatureEvidence, } from "./application/JavaScriptApplicationWorkflowService.js";
3
3
  import { runControlledReplay } from "./application/JavaScriptReplayService.js";
4
+ import { executeNodeCharacterization, prepareNodeCharacterization, } from "./application/NodeRuntimeCharacterizationService.js";
5
+ import { commitReconstructionCoverage, queryReconstructionCoverage, reconstructionCoverageCommitInputSchema, reconstructionCoverageQueryInputSchema, } from "./application/ReconstructionCoverageService.js";
6
+ import { authorizeFileReadWithDeferredWrite, authorizeRootPermission, } from "./application/DeferredFileAuthorization.js";
4
7
  import { loadConfiguredPermissionAuthority } from "./application/PermissionConfiguration.js";
5
8
  import { CLI_COMMANDS } from "./cliCommandNames.js";
6
9
  import { parseCliJsonInput } from "./cliJsonInput.js";
7
10
  import { logCliCommand } from "./cliLogging.js";
8
- import { AnalysisInputError, projectAnalysisError } from "./domain/errors.js";
11
+ import { AnalysisInputError, projectAnalysisError, } from "./domain/errors.js";
9
12
  import { parseConfig } from "./config.js";
10
13
  import { LinuxJavaScriptReplayRunner } from "./replay/LinuxJavaScriptReplayRunner.js";
11
14
  import { SystemJavaScriptReplayHost } from "./replay/SystemJavaScriptReplayHost.js";
12
15
  /** Register CLI equivalents of provider-neutral application graph workflows. */
13
16
  export const registerApplicationCommands = (cli, logger) => {
14
- registerJsonCommand(cli, logger, CLI_COMMANDS.traceApplicationFeature, "Trace a typed seed through authenticated application Evidence JSON", traceApplicationFeatureEvidence);
15
- registerJsonCommand(cli, logger, CLI_COMMANDS.compareApplicationVersions, "Compare two authenticated JavaScript Application Graph versions", compareApplicationVersionsEvidence);
17
+ registerJsonCommand({
18
+ cli,
19
+ logger,
20
+ name: CLI_COMMANDS.traceApplicationFeature,
21
+ description: "Trace a typed seed through authenticated application Evidence JSON",
22
+ workflow: traceApplicationFeatureEvidence,
23
+ });
24
+ registerJsonCommand({
25
+ cli,
26
+ logger,
27
+ name: CLI_COMMANDS.compareApplicationVersions,
28
+ description: "Compare two authenticated JavaScript Application Graph versions",
29
+ workflow: compareApplicationVersionsEvidence,
30
+ });
16
31
  cli.command(CLI_COMMANDS.runControlledReplay, {
17
32
  description: "Plan or execute an approved extracted-module replay in the Linux sandbox",
18
33
  args: z.object({
@@ -37,8 +52,107 @@ export const registerApplicationCommands = (cli, logger) => {
37
52
  return result.ok ? result.value : projectAnalysisError(result.error);
38
53
  }),
39
54
  });
55
+ registerAuthorizedJsonCommand({
56
+ cli,
57
+ logger,
58
+ name: CLI_COMMANDS.prepareNodeCharacterization,
59
+ description: "Prepare one exact Node/JavaScript characterization without execution",
60
+ workflow: (config, authority, input) => prepareNodeCharacterization(replayDependencies(config, authority), input),
61
+ });
62
+ registerAuthorizedJsonCommand({
63
+ cli,
64
+ logger,
65
+ name: CLI_COMMANDS.executeNodeCharacterization,
66
+ description: "Execute one separately approved exact Node/JavaScript characterization",
67
+ workflow: (config, authority, input) => executeNodeCharacterization(replayDependencies(config, authority), input),
68
+ });
69
+ registerCoverageCommands(cli, logger);
70
+ };
71
+ const registerAuthorizedJsonCommand = ({ cli, logger, name, description, workflow, }) => {
72
+ cli.command(name, {
73
+ description,
74
+ args: z.object({
75
+ inputJson: z.string().describe("Inline workflow JSON or JSON file path"),
76
+ }),
77
+ run: ({ args }) => logCliCommand(logger, name, async () => {
78
+ const input = await parseCliJsonInput(args.inputJson, name);
79
+ if (!input.ok)
80
+ return input.error;
81
+ const configured = await configuredAuthority();
82
+ if (!configured.ok)
83
+ return configured.error;
84
+ const result = await workflow(configured.config, configured.authority, input.value);
85
+ return result.ok ? result.value : projectAnalysisError(result.error);
86
+ }),
87
+ });
88
+ };
89
+ const registerCoverageCommands = (cli, logger) => {
90
+ registerAuthorizedJsonCommand({
91
+ cli,
92
+ logger,
93
+ name: CLI_COMMANDS.commitReconstructionCoverage,
94
+ description: "Commit one canonical reconstruction coverage workspace revision",
95
+ workflow: async (config, authority, input) => {
96
+ const parsed = reconstructionCoverageCommitInputSchema.safeParse(input);
97
+ if (!parsed.success)
98
+ return {
99
+ ok: false,
100
+ error: new AnalysisInputError(CLI_COMMANDS.commitReconstructionCoverage, { cause: parsed.error }),
101
+ };
102
+ const authorization = await authorizeFileReadWithDeferredWrite(authority, {
103
+ path: parsed.data.workspace_path,
104
+ readCapability: "investigation_workspace_read",
105
+ writeCapability: "investigation_workspace_write",
106
+ operation: CLI_COMMANDS.commitReconstructionCoverage,
107
+ });
108
+ if (!authorization.ok)
109
+ return authorization;
110
+ const write = await authorization.value.authorizeWrite();
111
+ if (!write.ok)
112
+ return write;
113
+ return commitReconstructionCoverage(parsed.data, config.evidenceFilePolicy);
114
+ },
115
+ });
116
+ registerAuthorizedJsonCommand({
117
+ cli,
118
+ logger,
119
+ name: CLI_COMMANDS.queryReconstructionCoverage,
120
+ description: "Evaluate one fail-closed reconstruction coverage boundary",
121
+ workflow: async (config, authority, input) => {
122
+ const parsed = reconstructionCoverageQueryInputSchema.safeParse(input);
123
+ if (!parsed.success)
124
+ return {
125
+ ok: false,
126
+ error: new AnalysisInputError(CLI_COMMANDS.queryReconstructionCoverage, { cause: parsed.error }),
127
+ };
128
+ const authorized = await authorizeRootPermission(authority, {
129
+ capability: "investigation_workspace_read",
130
+ roots: [parsed.data.workspace_path],
131
+ access: "read",
132
+ operation: CLI_COMMANDS.queryReconstructionCoverage,
133
+ });
134
+ if (!authorized.ok)
135
+ return authorized;
136
+ return queryReconstructionCoverage(parsed.data, config.evidenceFilePolicy, Date.now());
137
+ },
138
+ });
139
+ };
140
+ const configuredAuthority = async () => {
141
+ const config = parseConfig(process.env);
142
+ if (!config.ok)
143
+ return { ok: false, error: projectAnalysisError(config.error) };
144
+ const authority = await loadConfiguredPermissionAuthority(config.value);
145
+ return authority.ok
146
+ ? { ok: true, config: config.value, authority: authority.value }
147
+ : { ok: false, error: projectAnalysisError(authority.error) };
40
148
  };
41
- const registerJsonCommand = (cli, logger, name, description, workflow) => {
149
+ const replayDependencies = (config, authority) => ({
150
+ policy: config.javascriptReplayPolicy,
151
+ host: new SystemJavaScriptReplayHost(),
152
+ runner: new LinuxJavaScriptReplayRunner(),
153
+ authority,
154
+ });
155
+ const registerJsonCommand = ({ cli, logger, name, description, workflow, }) => {
42
156
  cli.command(name, {
43
157
  description,
44
158
  args: z.object({
@@ -10,8 +10,11 @@ import { discoverWebMcpToolsInputSchema } from "./domain/webMcpDiscovery.js";
10
10
  import { captureWebScreenshotInputSchema, compareWebScreenshotsInputSchema, } from "./domain/webScreenshot.js";
11
11
  import { CLI_COMMANDS } from "./cliCommandNames.js";
12
12
  const scopeOptions = {
13
- allowedOrigins: z.array(z.string().min(1)).optional(),
14
- approved: z.boolean().default(false),
13
+ allowedOrigins: z
14
+ .array(z.string().min(1))
15
+ .optional()
16
+ .describe("Exact origins to observe; defaults to REA_BROWSER_ALLOWED_ORIGINS_JSON"),
17
+ approved: z.boolean().default(false).describe("Approve passive observation"),
15
18
  };
16
19
  /** Register WebMCP, capture-diff, and screenshot CLI equivalents. */
17
20
  export const registerAdvancedBrowserCommands = (cli, logger) => {
@@ -23,19 +26,47 @@ export const registerAdvancedBrowserCommands = (cli, logger) => {
23
26
  const registerWebMcp = (cli, logger) => {
24
27
  cli.command(CLI_COMMANDS.discoverWebMcpTools, {
25
28
  description: "Passively discover page-declared WebMCP tools",
26
- args: z.object({ endpoint: z.string(), targetId: z.string() }),
29
+ args: z.object({
30
+ endpoint: z.string().describe("Configured loopback CDP HTTP endpoint"),
31
+ targetId: z.string().describe("Target ID from list-browser-targets"),
32
+ }),
27
33
  options: z.object({
28
34
  ...scopeOptions,
29
- observationMs: z.number().int().min(0).max(10_000).default(100),
30
- maxTools: z.number().int().min(1).max(5_000).default(500),
35
+ observationMs: z
36
+ .number()
37
+ .int()
38
+ .min(0)
39
+ .max(10_000)
40
+ .default(100)
41
+ .describe("Observation duration in milliseconds"),
42
+ maxTools: z
43
+ .number()
44
+ .int()
45
+ .min(1)
46
+ .max(5_000)
47
+ .default(500)
48
+ .describe("Maximum page-declared WebMCP tools to return"),
31
49
  maxSchemaBytes: z
32
50
  .number()
33
51
  .int()
34
52
  .min(1)
35
53
  .max(1_024 * 1_024)
36
- .default(256 * 1_024),
37
- maxSchemaNodes: z.number().int().min(1).max(100_000).default(5_000),
38
- maxSchemaDepth: z.number().int().min(1).max(100).default(20),
54
+ .default(256 * 1_024)
55
+ .describe("Maximum serialized size of one declared tool schema"),
56
+ maxSchemaNodes: z
57
+ .number()
58
+ .int()
59
+ .min(1)
60
+ .max(100_000)
61
+ .default(5_000)
62
+ .describe("Maximum nodes in one declared tool schema"),
63
+ maxSchemaDepth: z
64
+ .number()
65
+ .int()
66
+ .min(1)
67
+ .max(100)
68
+ .default(20)
69
+ .describe("Maximum nesting depth in one declared tool schema"),
39
70
  }),
40
71
  run: ({ args, options }) => logCliCommand(logger, "discover-webmcp-tools", async () => {
41
72
  const context = await browserContext();
@@ -62,9 +93,18 @@ const registerWebMcp = (cli, logger) => {
62
93
  const registerCaptureDiff = (cli, logger) => {
63
94
  cli.command(CLI_COMMANDS.compareWebCaptures, {
64
95
  description: "Compare two normalized web capture JSON values",
65
- args: z.object({ beforeJson: z.string(), afterJson: z.string() }),
96
+ args: z.object({
97
+ beforeJson: z.string().describe("Earlier normalized web capture JSON"),
98
+ afterJson: z.string().describe("Later normalized web capture JSON"),
99
+ }),
66
100
  options: z.object({
67
- maxChanges: z.number().int().min(1).max(20_000).default(2_000),
101
+ maxChanges: z
102
+ .number()
103
+ .int()
104
+ .min(1)
105
+ .max(20_000)
106
+ .default(2_000)
107
+ .describe("Maximum normalized changes to return"),
68
108
  }),
69
109
  run: ({ args, options }) => logCliCommand(logger, "compare-web-captures", async () => {
70
110
  const before = parseJson(args.beforeJson);
@@ -84,16 +124,23 @@ const registerCaptureDiff = (cli, logger) => {
84
124
  const registerScreenshot = (cli, logger) => {
85
125
  cli.command(CLI_COMMANDS.captureWebScreenshot, {
86
126
  description: "Capture an explicitly approved visible page viewport",
87
- args: z.object({ endpoint: z.string(), targetId: z.string() }),
127
+ args: z.object({
128
+ endpoint: z.string().describe("Configured loopback CDP HTTP endpoint"),
129
+ targetId: z.string().describe("Target ID from list-browser-targets"),
130
+ }),
88
131
  options: z.object({
89
132
  ...scopeOptions,
90
- screenshotApproved: z.boolean().default(false),
133
+ screenshotApproved: z
134
+ .boolean()
135
+ .default(false)
136
+ .describe("Approve capturing the visible page viewport"),
91
137
  maximumImageBytes: z
92
138
  .number()
93
139
  .int()
94
140
  .min(1)
95
141
  .max(8 * 1_024 * 1_024)
96
- .default(4 * 1_024 * 1_024),
142
+ .default(4 * 1_024 * 1_024)
143
+ .describe("Maximum captured PNG size"),
97
144
  }),
98
145
  run: ({ args, options }) => logCliCommand(logger, "capture-web-screenshot", async () => {
99
146
  const context = await browserContext();
@@ -117,15 +164,25 @@ const registerScreenshot = (cli, logger) => {
117
164
  const registerScreenshotDiff = (cli, logger) => {
118
165
  cli.command(CLI_COMMANDS.compareWebScreenshots, {
119
166
  description: "Compare two self-verifying PNG artifact JSON values",
120
- args: z.object({ beforeJson: z.string(), afterJson: z.string() }),
167
+ args: z.object({
168
+ beforeJson: z.string().describe("Earlier screenshot artifact JSON"),
169
+ afterJson: z.string().describe("Later screenshot artifact JSON"),
170
+ }),
121
171
  options: z.object({
122
- channelThreshold: z.number().int().min(0).max(255).default(0),
172
+ channelThreshold: z
173
+ .number()
174
+ .int()
175
+ .min(0)
176
+ .max(255)
177
+ .default(0)
178
+ .describe("Per-channel difference threshold for changed pixels"),
123
179
  maximumPixels: z
124
180
  .number()
125
181
  .int()
126
182
  .min(1)
127
183
  .max(32_000_000)
128
- .default(16_000_000),
184
+ .default(16_000_000)
185
+ .describe("Maximum decoded pixels per screenshot"),
129
186
  }),
130
187
  run: ({ args, options }) => logCliCommand(logger, "compare-web-screenshots", async () => {
131
188
  const parsed = compareWebScreenshotsInputSchema.safeParse({
@@ -9,6 +9,7 @@ import { analyzeWebBundleInputSchema } from "./domain/webBundleAnalysis.js";
9
9
  import { observeWebSessionInputSchema } from "./domain/browserSession.js";
10
10
  import { AnalysisInputError, projectAnalysisError } from "./domain/errors.js";
11
11
  import { CLI_COMMANDS } from "./cliCommandNames.js";
12
+ import { browserPageInspectionOptions } from "./cliObservationOptions.js";
12
13
  const browserScopeOptions = {
13
14
  allowedOrigins: z
14
15
  .array(z.string().min(1))
@@ -16,6 +17,14 @@ const browserScopeOptions = {
16
17
  .describe("Exact origins to observe; defaults to REA_BROWSER_ALLOWED_ORIGINS_JSON"),
17
18
  approved: z.boolean().default(false).describe("Approve passive observation"),
18
19
  };
20
+ const boundedCount = (subject, maximum, fallback, minimum = 1) => z
21
+ .number()
22
+ .int()
23
+ .min(minimum)
24
+ .max(maximum)
25
+ .default(fallback)
26
+ .describe(`Maximum ${subject}`);
27
+ const boundedBytes = (subject, maximum, fallback) => boundedCount(`${subject} in bytes`, maximum, fallback);
19
28
  /** Register CLI equivalents of the passive browser MCP tools. */
20
29
  export const registerBrowserCommands = (cli, logger) => {
21
30
  registerTargetList(cli, logger);
@@ -31,8 +40,13 @@ const registerTargetList = (cli, logger) => {
31
40
  }),
32
41
  options: z.object({
33
42
  ...browserScopeOptions,
34
- offset: z.number().int().min(0).default(0),
35
- limit: z.number().int().min(1).max(200).default(100),
43
+ offset: z
44
+ .number()
45
+ .int()
46
+ .min(0)
47
+ .default(0)
48
+ .describe("Zero-based browser-target offset"),
49
+ limit: boundedCount("browser targets to return", 200, 100),
36
50
  }),
37
51
  run: ({ args, options }) => logCliCommand(logger, "list-browser-targets", async () => {
38
52
  const context = await browserContext();
@@ -59,91 +73,7 @@ const registerPageInspection = (cli, logger) => {
59
73
  endpoint: z.string().describe("Configured loopback CDP HTTP endpoint"),
60
74
  targetId: z.string().describe("Target ID from list-browser-targets"),
61
75
  }),
62
- options: z.object({
63
- ...browserScopeOptions,
64
- observationMs: z.number().int().min(0).max(10_000).default(500),
65
- includeAccessibilityText: z.boolean().default(false),
66
- includeConsoleText: z.boolean().default(false),
67
- consoleTextApproved: z.boolean().default(false),
68
- includeJsonBodyShapes: z.boolean().default(false),
69
- jsonBodySchemaApproved: z.boolean().default(false),
70
- includeWebsocketShapes: z.boolean().default(false),
71
- websocketShapeApproved: z.boolean().default(false),
72
- includeScriptSources: z.boolean().default(false),
73
- includeStorageKeys: z.boolean().default(false),
74
- maxFrames: z.number().int().min(1).max(1_000).default(200),
75
- maxDomNodes: z.number().int().min(1).max(10_000).default(2_000),
76
- maxAxNodes: z.number().int().min(1).max(10_000).default(2_000),
77
- maxAxTextFieldBytes: z
78
- .number()
79
- .int()
80
- .min(1)
81
- .max(16 * 1_024)
82
- .default(1_024),
83
- maxTotalAxTextBytes: z
84
- .number()
85
- .int()
86
- .min(1)
87
- .max(1_024 * 1_024)
88
- .default(64 * 1_024),
89
- maxScripts: z.number().int().min(1).max(1_000).default(200),
90
- maxResources: z.number().int().min(1).max(10_000).default(2_000),
91
- maxWorkers: z.number().int().min(1).max(5_000).default(500),
92
- maxStorageKeys: z.number().int().min(1).max(10_000).default(1_000),
93
- maxScriptSourceBytes: z
94
- .number()
95
- .int()
96
- .min(1)
97
- .max(4 * 1_024 * 1_024)
98
- .default(1_024 * 1_024),
99
- maxTotalScriptSourceBytes: z
100
- .number()
101
- .int()
102
- .min(1)
103
- .max(16 * 1_024 * 1_024)
104
- .default(4 * 1_024 * 1_024),
105
- maxNetworkEvents: z.number().int().min(1).max(10_000).default(1_000),
106
- maxConsoleEvents: z.number().int().min(1).max(2_000).default(200),
107
- maxConsoleTextFieldBytes: z
108
- .number()
109
- .int()
110
- .min(1)
111
- .max(16 * 1_024)
112
- .default(1_024),
113
- maxTotalConsoleTextBytes: z
114
- .number()
115
- .int()
116
- .min(1)
117
- .max(1_024 * 1_024)
118
- .default(64 * 1_024),
119
- maxJsonBodyBytes: z
120
- .number()
121
- .int()
122
- .min(1)
123
- .max(4 * 1_024 * 1_024)
124
- .default(1_024 * 1_024),
125
- maxTotalJsonBodyBytes: z
126
- .number()
127
- .int()
128
- .min(1)
129
- .max(16 * 1_024 * 1_024)
130
- .default(4 * 1_024 * 1_024),
131
- maxJsonShapeNodes: z.number().int().min(1).max(100_000).default(5_000),
132
- maxJsonShapeDepth: z.number().int().min(1).max(100).default(20),
133
- maxWebsocketEvents: z.number().int().min(1).max(5_000).default(500),
134
- maxWebsocketShapeBytes: z
135
- .number()
136
- .int()
137
- .min(1)
138
- .max(1_024 * 1_024)
139
- .default(64 * 1_024),
140
- maxTotalWebsocketShapeBytes: z
141
- .number()
142
- .int()
143
- .min(1)
144
- .max(16 * 1_024 * 1_024)
145
- .default(1_024 * 1_024),
146
- }),
76
+ options: browserPageInspectionOptions,
147
77
  run: ({ args, options }) => logCliCommand(logger, "inspect-web-page", async () => {
148
78
  const context = await browserContext();
149
79
  if (!context.ok)
@@ -204,32 +134,26 @@ const registerBundleAnalysis = (cli, logger) => {
204
134
  }),
205
135
  options: z.object({
206
136
  ...browserScopeOptions,
207
- sourceCaptureApproved: z.boolean().default(false),
208
- observationMs: z.number().int().min(0).max(10_000).default(500),
209
- fetchSourceMaps: z.boolean().default(false),
210
- sourceMapFetchApproved: z.boolean().default(false),
211
- maxFindings: z.number().int().min(1).max(10_000).default(1_000),
212
- maxAstNodes: z.number().int().min(1).max(2_000_000).default(250_000),
213
- maxSourceMaps: z.number().int().min(1).max(1_000).default(100),
214
- maxSourceMapBytes: z
215
- .number()
216
- .int()
217
- .min(1)
218
- .max(16 * 1_024 * 1_024)
219
- .default(4 * 1_024 * 1_024),
220
- maxTotalSourceMapBytes: z
221
- .number()
222
- .int()
223
- .min(1)
224
- .max(64 * 1_024 * 1_024)
225
- .default(16 * 1_024 * 1_024),
226
- maxSourceMapMappings: z
227
- .number()
228
- .int()
229
- .min(1)
230
- .max(100_000)
231
- .default(10_000),
232
- maxOriginalSources: z.number().int().min(1).max(20_000).default(2_000),
137
+ sourceCaptureApproved: z
138
+ .boolean()
139
+ .default(false)
140
+ .describe("Approve capturing bounded script source text"),
141
+ observationMs: boundedCount("observation duration in milliseconds", 10_000, 500, 0),
142
+ fetchSourceMaps: z
143
+ .boolean()
144
+ .default(false)
145
+ .describe("Fetch source maps referenced by captured scripts"),
146
+ sourceMapFetchApproved: z
147
+ .boolean()
148
+ .default(false)
149
+ .describe("Approve fetching referenced source maps from allowed origins"),
150
+ maxFindings: boundedCount("static-analysis findings", 10_000, 1_000),
151
+ maxAstNodes: boundedCount("JavaScript AST nodes", 2_000_000, 250_000),
152
+ maxSourceMaps: boundedCount("source maps", 1_000, 100),
153
+ maxSourceMapBytes: boundedBytes("one source map", 16 * 1_024 * 1_024, 4 * 1_024 * 1_024),
154
+ maxTotalSourceMapBytes: boundedBytes("total source maps", 64 * 1_024 * 1_024, 16 * 1_024 * 1_024),
155
+ maxSourceMapMappings: boundedCount("decoded source-map mappings", 100_000, 10_000),
156
+ maxOriginalSources: boundedCount("original source files", 20_000, 2_000),
233
157
  }),
234
158
  run: ({ args, options }) => logCliCommand(logger, "analyze-web-bundle", async () => {
235
159
  const context = await browserContext();
@@ -271,8 +195,8 @@ const registerObservationSession = (cli, logger) => {
271
195
  }),
272
196
  options: z.object({
273
197
  ...browserScopeOptions,
274
- observationMs: z.number().int().min(1).max(60_000).default(10_000),
275
- maxTimelineEvents: z.number().int().min(1).max(20_000).default(2_000),
198
+ observationMs: boundedCount("observation duration in milliseconds", 60_000, 10_000),
199
+ maxTimelineEvents: boundedCount("timeline events", 20_000, 2_000),
276
200
  }),
277
201
  run: ({ args, options }) => logCliCommand(logger, "observe-web-session", async () => {
278
202
  const context = await browserContext();
@@ -51,6 +51,10 @@ export const CLI_COMMANDS = Object.freeze({
51
51
  traceApplicationFeature: "trace-application-feature",
52
52
  compareApplicationVersions: "compare-application-versions",
53
53
  runControlledReplay: "run-controlled-replay",
54
+ prepareNodeCharacterization: "prepare-node-characterization",
55
+ executeNodeCharacterization: "execute-node-characterization",
56
+ commitReconstructionCoverage: "commit-reconstruction-coverage",
57
+ queryReconstructionCoverage: "query-reconstruction-coverage",
54
58
  });
55
59
  /** Ordered primary CLI inventory; aliases are intentionally excluded. */
56
60
  export const CLI_COMMAND_NAMES = Object.freeze(Object.values(CLI_COMMANDS));
@@ -11,12 +11,13 @@ import { analyzeJavaScriptApplicationInputSchema } from "./domain/javascriptAppl
11
11
  import { AnalysisInputError, projectAnalysisError } from "./domain/errors.js";
12
12
  import { CLI_COMMANDS } from "./cliCommandNames.js";
13
13
  import { parseCliJsonInput } from "./cliJsonInput.js";
14
+ import { electronPageInspectionOptions, javascriptApplicationOptions, } from "./cliObservationOptions.js";
14
15
  const scopeOptions = {
15
16
  allowedFileRoots: z
16
17
  .array(z.string().min(1))
17
18
  .optional()
18
19
  .describe("Filesystem roots; defaults to REA_ELECTRON_FILE_ROOTS_JSON"),
19
- approved: z.boolean().default(false),
20
+ approved: z.boolean().default(false).describe("Approve passive observation"),
20
21
  };
21
22
  /** Register CLI equivalents of the Electron MCP tools. */
22
23
  export const registerElectronCommands = (cli, logger) => {
@@ -42,13 +43,32 @@ const registerJavaScriptRuntimeReconciliationCommand = (cli, logger) => {
42
43
  });
43
44
  };
44
45
  const registerElectronObservationCommands = (cli, logger) => {
46
+ registerElectronTargetList(cli, logger);
47
+ registerElectronPageInspection(cli, logger);
48
+ };
49
+ const registerElectronTargetList = (cli, logger) => {
45
50
  cli.command(CLI_COMMANDS.listElectronTargets, {
46
51
  description: "List root-confined file pages from Electron CDP",
47
- args: z.object({ endpoint: z.string() }),
52
+ args: z.object({
53
+ endpoint: z
54
+ .string()
55
+ .describe("Configured loopback Electron CDP endpoint"),
56
+ }),
48
57
  options: z.object({
49
58
  ...scopeOptions,
50
- offset: z.number().int().min(0).default(0),
51
- limit: z.number().int().min(1).max(200).default(100),
59
+ offset: z
60
+ .number()
61
+ .int()
62
+ .min(0)
63
+ .default(0)
64
+ .describe("Zero-based Electron-target offset"),
65
+ limit: z
66
+ .number()
67
+ .int()
68
+ .min(1)
69
+ .max(200)
70
+ .default(100)
71
+ .describe("Maximum Electron targets to return"),
52
72
  }),
53
73
  run: ({ args, options }) => logCliCommand(logger, "list-electron-targets", async () => {
54
74
  const context = await electronContext();
@@ -67,32 +87,17 @@ const registerElectronObservationCommands = (cli, logger) => {
67
87
  return result.ok ? result.value : cliError(result.error);
68
88
  }),
69
89
  });
90
+ };
91
+ const registerElectronPageInspection = (cli, logger) => {
70
92
  cli.command(CLI_COMMANDS.inspectElectronPage, {
71
93
  description: "Passively inspect one root-confined Electron file page",
72
- args: z.object({ endpoint: z.string(), targetId: z.string() }),
73
- options: z.object({
74
- ...scopeOptions,
75
- observationMs: z.number().int().min(0).max(10_000).default(100),
76
- includeScriptSources: z.boolean().default(false),
77
- sourceCaptureApproved: z.boolean().default(false),
78
- maxFrames: z.number().int().min(1).max(1_000).default(200),
79
- maxDomNodes: z.number().int().min(1).max(10_000).default(2_000),
80
- maxScripts: z.number().int().min(1).max(2_000).default(500),
81
- maxResources: z.number().int().min(1).max(10_000).default(2_000),
82
- maxWorkers: z.number().int().min(1).max(5_000).default(500),
83
- maxScriptSourceBytes: z
84
- .number()
85
- .int()
86
- .min(1)
87
- .max(4 * 1_024 * 1_024)
88
- .default(1_024 * 1_024),
89
- maxTotalScriptSourceBytes: z
90
- .number()
91
- .int()
92
- .min(1)
93
- .max(16 * 1_024 * 1_024)
94
- .default(4 * 1_024 * 1_024),
94
+ args: z.object({
95
+ endpoint: z
96
+ .string()
97
+ .describe("Configured loopback Electron CDP endpoint"),
98
+ targetId: z.string().describe("Target ID from list-electron-targets"),
95
99
  }),
100
+ options: electronPageInspectionOptions,
96
101
  run: ({ args, options }) => logCliCommand(logger, "inspect-electron-page", async () => {
97
102
  const context = await electronContext();
98
103
  if (!context.ok)
@@ -128,41 +133,7 @@ const registerJavaScriptApplicationCommand = (cli, logger) => {
128
133
  args: z.object({
129
134
  path: z.string().describe("Absolute ASAR or extracted application path"),
130
135
  }),
131
- options: z.object({
132
- approved: z.boolean().default(false),
133
- format: z.enum(["auto", "asar", "directory"]).default("auto"),
134
- sourceMapReadApproved: z.boolean().default(false),
135
- maxEntries: z.number().int().min(1).default(8_000),
136
- maxTotalArtifactBytes: z
137
- .number()
138
- .int()
139
- .min(1)
140
- .default(512 * 1_024 * 1_024),
141
- maxArtifactEntryBytes: z
142
- .number()
143
- .int()
144
- .min(1)
145
- .default(128 * 1_024 * 1_024),
146
- maxCompressionRatio: z.number().min(1).default(1_000),
147
- maxDepth: z.number().int().min(1).default(64),
148
- maxPathBytes: z.number().int().min(1).default(4_096),
149
- maxTextFiles: z.number().int().min(1).default(5_000),
150
- maxTotalTextBytes: z
151
- .number()
152
- .int()
153
- .min(1)
154
- .default(128 * 1_024 * 1_024),
155
- maxTextFileBytes: z
156
- .number()
157
- .int()
158
- .min(1)
159
- .default(8 * 1_024 * 1_024),
160
- maxAstNodes: z.number().int().min(1).default(2_000_000),
161
- maxFindings: z.number().int().min(1).default(8_000),
162
- maxModules: z.number().int().min(1).default(20_000),
163
- maxSourceMapSources: z.number().int().min(1).default(5_000),
164
- maxParseMilliseconds: z.number().int().min(1).default(30_000),
165
- }),
136
+ options: javascriptApplicationOptions,
166
137
  run: ({ args, options }) => logCliCommand(logger, CLI_COMMANDS.analyzeJavaScriptApplication, async () => {
167
138
  const context = await electronContext();
168
139
  if (!context.ok)
@@ -56,8 +56,19 @@ export const registerEvidenceCommands = (cli, logger) => {
56
56
  right: z.string().describe("Right Evidence bundle JSON path"),
57
57
  }),
58
58
  options: z.object({
59
- offset: z.number().int().min(0).default(0),
60
- limit: z.number().int().min(1).max(500).default(100),
59
+ offset: z
60
+ .number()
61
+ .int()
62
+ .min(0)
63
+ .default(0)
64
+ .describe("Zero-based changed-record offset"),
65
+ limit: z
66
+ .number()
67
+ .int()
68
+ .min(1)
69
+ .max(500)
70
+ .default(100)
71
+ .describe("Maximum changed records to return"),
61
72
  }),
62
73
  run: ({ args, options }) => logCliCommand(logger, "compare", async () => {
63
74
  const config = parseConfig(process.env);