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
@@ -133,7 +133,13 @@ class TimelineCapture {
133
133
  targetTerminated() {
134
134
  if (this.#endReason !== undefined)
135
135
  return;
136
- this.#add("target_terminated", {}, null, null, "target_terminated");
136
+ this.#add({
137
+ type: "target_terminated",
138
+ params: {},
139
+ rawUrl: null,
140
+ requestId: null,
141
+ detail: "target_terminated",
142
+ });
137
143
  this.end("target_terminated");
138
144
  }
139
145
  setFinalUrl(rawUrl) {
@@ -145,7 +151,13 @@ class TimelineCapture {
145
151
  return;
146
152
  const reason = safeDetail(params.reason);
147
153
  this.#pendingReload = reason === "reload";
148
- this.#add("navigation_requested", params, stringValue(params.url), null, reason);
154
+ this.#add({
155
+ type: "navigation_requested",
156
+ params,
157
+ rawUrl: stringValue(params.url) ?? null,
158
+ requestId: null,
159
+ detail: reason,
160
+ });
149
161
  }
150
162
  #navigationCommitted(params) {
151
163
  const frame = recordValue(params.frame);
@@ -153,7 +165,13 @@ class TimelineCapture {
153
165
  return;
154
166
  const rawUrl = stringValue(frame?.url);
155
167
  const destination = scopedUrl(rawUrl, this.allowedOrigins);
156
- this.#add(this.#pendingReload ? "same_origin_reload" : "navigation_committed", { ...params, frameId: frame?.id, loaderId: frame?.loaderId }, rawUrl, null, safeDetail(frame?.transitionType));
168
+ this.#add({
169
+ type: this.#pendingReload ? "same_origin_reload" : "navigation_committed",
170
+ params: { ...params, frameId: frame?.id, loaderId: frame?.loaderId },
171
+ rawUrl: rawUrl ?? null,
172
+ requestId: null,
173
+ detail: safeDetail(frame?.transitionType),
174
+ });
157
175
  this.#pendingReload = false;
158
176
  if (destination.scope === "approved")
159
177
  this.finalUrl = destination.url;
@@ -168,7 +186,13 @@ class TimelineCapture {
168
186
  return;
169
187
  const rawUrl = stringValue(params.url);
170
188
  const destination = scopedUrl(rawUrl, this.allowedOrigins);
171
- this.#add("same_document_navigation", params, rawUrl, null, null);
189
+ this.#add({
190
+ type: "same_document_navigation",
191
+ params,
192
+ rawUrl: rawUrl ?? null,
193
+ requestId: null,
194
+ detail: null,
195
+ });
172
196
  if (destination.scope === "approved")
173
197
  this.finalUrl = destination.url;
174
198
  else {
@@ -184,7 +208,13 @@ class TimelineCapture {
184
208
  const request = recordValue(params.request);
185
209
  const rawUrl = stringValue(request?.url);
186
210
  const destination = scopedUrl(rawUrl, this.allowedOrigins);
187
- this.#add("redirect", params, rawUrl, stringValue(params.requestId) ?? null, null);
211
+ this.#add({
212
+ type: "redirect",
213
+ params,
214
+ rawUrl: rawUrl ?? null,
215
+ requestId: stringValue(params.requestId) ?? null,
216
+ detail: null,
217
+ });
188
218
  if (destination.scope !== "approved") {
189
219
  this.completeness.exclude("timeline", "out_of_target_scope");
190
220
  this.end("target_left_scope");
@@ -194,14 +224,27 @@ class TimelineCapture {
194
224
  const frame = stringValue(params.frameId);
195
225
  if (frame !== undefined && frame !== this.mainFrameId)
196
226
  return;
197
- this.#add("load_failed", params, null, stringValue(params.requestId) ?? null, safeNetworkError(params.errorText));
227
+ this.#add({
228
+ type: "load_failed",
229
+ params,
230
+ rawUrl: null,
231
+ requestId: stringValue(params.requestId) ?? null,
232
+ detail: safeNetworkError(params.errorText),
233
+ });
198
234
  }
199
235
  #lifecycle(params) {
200
236
  if (stringValue(params.frameId) !== this.mainFrameId)
201
237
  return;
202
- this.#add("lifecycle", params, null, null, safeDetail(params.name));
238
+ this.#add({
239
+ type: "lifecycle",
240
+ params,
241
+ rawUrl: null,
242
+ requestId: null,
243
+ detail: safeDetail(params.name),
244
+ });
203
245
  }
204
- #add(type, params, rawUrl, requestId, detail) {
246
+ #add(options) {
247
+ const { type, params, rawUrl = null, requestId = null, detail = null, } = options;
205
248
  const destination = rawUrl == null ? null : scopedUrl(rawUrl, this.allowedOrigins);
206
249
  if (this.timeline.length >= this.maximum) {
207
250
  this.completeness.drop("timeline_events");
@@ -1,11 +1,13 @@
1
1
  import { BrowserObservationError, } from "../domain/errors.js";
2
- import { reconcileCapturedWebScript, stableWebResources, stableWebScriptKey, } from "../domain/webInventory.js";
2
+ import { stableWebResources } from "../domain/webInventory.js";
3
3
  import { CdpConnection } from "./CdpConnection.js";
4
4
  import { CdpCaptureEvents } from "./CdpCaptureEvents.js";
5
5
  import { captureStorage } from "./CdpCaptureStorage.js";
6
6
  import { optionalCdpCommand } from "./CdpOptionalCommand.js";
7
7
  import { captureAccessibility, captureDom, captureFrames, captureResources, mainFrameUrl, } from "./CdpCaptureDocuments.js";
8
- import { allowedSanitizedUrl, boundedText, delayWithCancellation, isHttpUrl, recordValue, recordsValue, requiredRecord, sourceExcluded, sourceResult, stringValue, } from "./CdpCaptureValues.js";
8
+ import { allowedSanitizedUrl, delayWithCancellation, isHttpUrl, } from "./CdpCaptureValues.js";
9
+ import { captureScripts } from "./CdpPageCaptureScripts.js";
10
+ import { captureWorkers } from "./CdpPageCaptureWorkers.js";
9
11
  /** Capture and normalize one attached page without evaluating page JavaScript. */
10
12
  export const capturePage = async (context) => {
11
13
  const allowedOrigins = new Set(context.input.allowed_origins);
@@ -59,8 +61,14 @@ const captureAuthorizedPage = async (state) => {
59
61
  const accessibility = await accessibilityForFrames(state, frames);
60
62
  if (accessibility.total > accessibility.nodes.length)
61
63
  state.events.completeness.truncate("accessibility");
62
- const scripts = await captureScripts(context, state.events, resourceCapture.items, resources, new Set(frames.map((frame) => frame.frame_id)));
63
- const workerCapture = await captureWorkers(state, new Set(frames.map((frame) => frame.frame_id)));
64
+ const scripts = await captureScripts({
65
+ context,
66
+ events: state.events,
67
+ rawResources: resourceCapture.items,
68
+ resources,
69
+ frameIds: new Set(frames.map((frame) => frame.frame_id)),
70
+ });
71
+ const workerCapture = await captureWorkers({ context, allowedOrigins, limitations, events: state.events }, new Set(frames.map((frame) => frame.frame_id)));
64
72
  if (workerCapture.total > workerCapture.items.length)
65
73
  state.events.completeness.truncate("workers");
66
74
  const storageCapture = await captureStorage(context, frames[0]?.origin ?? new URL(attachedUrl).origin, limitations);
@@ -220,88 +228,6 @@ const accessibilityForFrames = async (state, frames) => {
220
228
  events.completeness.truncate("accessibility");
221
229
  return capture;
222
230
  };
223
- const captureScripts = async (context, events, rawResources, resources, frameIds) => {
224
- let totalSourceBytes = 0;
225
- const drafts = [];
226
- for (const script of events.scripts.values()) {
227
- let source = sourceExcluded("source capture was not approved");
228
- if (context.input.include_script_sources) {
229
- if (script.length > context.input.limits.max_script_source_bytes) {
230
- source = sourceExcluded("declared script length exceeds per-script limit");
231
- events.completeness.truncate("script_sources");
232
- }
233
- else if (totalSourceBytes + script.length >
234
- context.input.limits.max_total_script_source_bytes) {
235
- source = sourceExcluded("total script source limit reached");
236
- events.completeness.truncate("script_sources");
237
- }
238
- else {
239
- const result = requiredRecord(await context.connection.send("Debugger.getScriptSource", { scriptId: script.scriptId }, context.sessionId, context.signal));
240
- const content = stringValue(result.scriptSource) ?? "";
241
- const bytes = Buffer.byteLength(content);
242
- if (bytes > context.input.limits.max_script_source_bytes ||
243
- totalSourceBytes + bytes >
244
- context.input.limits.max_total_script_source_bytes) {
245
- source = sourceExcluded("actual source exceeds configured byte limits");
246
- events.completeness.truncate("script_sources");
247
- }
248
- else {
249
- source = sourceResult(content);
250
- totalSourceBytes += bytes;
251
- }
252
- }
253
- }
254
- const inventoryScript = {
255
- frame_id: events.frameForScript(script, frameIds),
256
- url: script.url,
257
- cdp_hash: script.hash,
258
- length: script.length,
259
- is_module: script.isModule,
260
- language: script.language,
261
- source_map_url: script.sourceMapUrl,
262
- };
263
- drafts.push({
264
- item: {
265
- ...inventoryScript,
266
- origin: script.origin,
267
- resource_reconciliation: reconcileCapturedWebScript({ ...inventoryScript, rawUrl: script.rawUrl }, rawResources, resources),
268
- source,
269
- },
270
- sourceMapRawUrl: script.sourceMapRawUrl,
271
- });
272
- }
273
- if (!context.input.include_script_sources)
274
- events.completeness.exclude("script_sources", "not_approved", events.scripts.size);
275
- const keyed = drafts.map((draft) => ({
276
- ...draft,
277
- base: stableWebScriptKey(draft.item),
278
- }));
279
- keyed.sort((left, right) => left.base.localeCompare(right.base) ||
280
- sourceDigest(left.item.source).localeCompare(sourceDigest(right.item.source)) ||
281
- (left.item.frame_id ?? "").localeCompare(right.item.frame_id ?? ""));
282
- const totals = new Map();
283
- for (const { base } of keyed)
284
- totals.set(base, (totals.get(base) ?? 0) + 1);
285
- const seen = new Map();
286
- const sourceMapRequests = [];
287
- const items = keyed.map(({ base, item, sourceMapRawUrl }) => {
288
- const occurrence = (seen.get(base) ?? 0) + 1;
289
- seen.set(base, occurrence);
290
- const scriptKey = totals.get(base) === 1 ? base : `${base}_${String(occurrence)}`;
291
- if (item.source_map_url !== null && sourceMapRawUrl !== null)
292
- sourceMapRequests.push({
293
- scriptKey,
294
- declaredUrl: item.source_map_url,
295
- fetchUrl: sourceMapRawUrl,
296
- });
297
- return { script_key: scriptKey, ...item };
298
- });
299
- return {
300
- inventory: { total: events.scripts.size, items },
301
- sourceMapRequests,
302
- };
303
- };
304
- const sourceDigest = (source) => (source.included ? source.artifact.sha256 : source.reason);
305
231
  const publicResource = ({ rawUrl: _rawUrl, ...resource }) => resource;
306
232
  const deduplicatedAgentHints = (hints) => {
307
233
  const seen = new Set();
@@ -313,53 +239,6 @@ const deduplicatedAgentHints = (hints) => {
313
239
  return true;
314
240
  });
315
241
  };
316
- const captureWorkers = async (state, frameIds) => {
317
- const { context, allowedOrigins, limitations, events } = state;
318
- const completeness = events.completeness;
319
- const result = await optionalCdpCommand({ ...context, sessionId: undefined }, "Target.getTargets", {}, limitations);
320
- const items = [];
321
- let total = 0;
322
- if (result === undefined)
323
- completeness.unavailable("workers");
324
- for (const target of recordsValue(recordValue(result)?.targetInfos)) {
325
- const type = stringValue(target.type) ?? "";
326
- const url = allowedSanitizedUrl(target.url, allowedOrigins);
327
- const relatedToPage = stringValue(target.openerId) === context.target.id ||
328
- (stringValue(target.parentFrameId) !== undefined &&
329
- frameIds.has(stringValue(target.parentFrameId) ?? ""));
330
- if (!type.includes("worker"))
331
- continue;
332
- if (!relatedToPage) {
333
- completeness.exclude("workers", "out_of_target_scope");
334
- continue;
335
- }
336
- if (url === undefined) {
337
- const rawUrl = stringValue(target.url);
338
- completeness.exclude("workers", rawUrl === undefined || rawUrl === ""
339
- ? "unattributed_origin"
340
- : isHttpUrl(rawUrl)
341
- ? "disallowed_origin"
342
- : "unsupported_url");
343
- continue;
344
- }
345
- total += 1;
346
- if (items.length >= context.input.limits.max_workers)
347
- continue;
348
- items.push({
349
- target_id: (stringValue(target.targetId) ?? "").slice(0, 256),
350
- type: type.slice(0, 100),
351
- url: url.url,
352
- origin: url.origin,
353
- attached: target.attached === true,
354
- opener_target_id: boundedText(target.openerId, 256) ?? null,
355
- parent_frame_id: boundedText(target.parentFrameId, 256) ?? null,
356
- });
357
- }
358
- return {
359
- total,
360
- items,
361
- };
362
- };
363
242
  const normalizedTarget = (target, currentUrl, allowedOrigins) => {
364
243
  const url = allowedSanitizedUrl(currentUrl, allowedOrigins);
365
244
  return {
@@ -0,0 +1,97 @@
1
+ import { reconcileCapturedWebScript, stableWebScriptKey, } from "../domain/webInventory.js";
2
+ import { requiredRecord, sourceExcluded, sourceResult, stringValue, } from "./CdpCaptureValues.js";
3
+ export const captureScripts = async (options) => {
4
+ const { context, events, rawResources, resources, frameIds } = options;
5
+ const state = {
6
+ context,
7
+ events,
8
+ frameIds,
9
+ rawResources,
10
+ resources,
11
+ totalSourceBytes: 0,
12
+ };
13
+ const drafts = [];
14
+ for (const script of events.scripts.values())
15
+ drafts.push(await buildScriptDraft(script, state));
16
+ if (!context.input.include_script_sources)
17
+ events.completeness.exclude("script_sources", "not_approved", events.scripts.size);
18
+ return keyAndBuildInventory(drafts, events.scripts.size);
19
+ };
20
+ const buildScriptDraft = async (script, state) => {
21
+ let source = state
22
+ .context.input.include_script_sources
23
+ ? await captureScriptSource(script, state)
24
+ : sourceExcluded("source capture was not approved");
25
+ const inventoryScript = {
26
+ frame_id: state.events.frameForScript(script, state.frameIds),
27
+ url: script.url,
28
+ cdp_hash: script.hash,
29
+ length: script.length,
30
+ is_module: script.isModule,
31
+ language: script.language,
32
+ source_map_url: script.sourceMapUrl,
33
+ };
34
+ return {
35
+ item: {
36
+ ...inventoryScript,
37
+ origin: script.origin,
38
+ resource_reconciliation: reconcileCapturedWebScript({ ...inventoryScript, rawUrl: script.rawUrl }, state.rawResources, state.resources),
39
+ source,
40
+ },
41
+ sourceMapRawUrl: script.sourceMapRawUrl,
42
+ };
43
+ };
44
+ const captureScriptSource = async (script, state) => {
45
+ const { context, events } = state;
46
+ if (script.length > context.input.limits.max_script_source_bytes) {
47
+ events.completeness.truncate("script_sources");
48
+ return sourceExcluded("declared script length exceeds per-script limit");
49
+ }
50
+ if (state.totalSourceBytes + script.length >
51
+ context.input.limits.max_total_script_source_bytes) {
52
+ events.completeness.truncate("script_sources");
53
+ return sourceExcluded("total script source limit reached");
54
+ }
55
+ const result = requiredRecord(await context.connection.send("Debugger.getScriptSource", { scriptId: script.scriptId }, context.sessionId, context.signal));
56
+ const content = stringValue(result.scriptSource) ?? "";
57
+ const bytes = Buffer.byteLength(content);
58
+ if (bytes > context.input.limits.max_script_source_bytes ||
59
+ state.totalSourceBytes + bytes >
60
+ context.input.limits.max_total_script_source_bytes) {
61
+ events.completeness.truncate("script_sources");
62
+ return sourceExcluded("actual source exceeds configured byte limits");
63
+ }
64
+ state.totalSourceBytes += bytes;
65
+ return sourceResult(content);
66
+ };
67
+ const keyAndBuildInventory = (drafts, scriptCount) => {
68
+ const keyed = drafts.map((draft) => ({
69
+ ...draft,
70
+ base: stableWebScriptKey(draft.item),
71
+ }));
72
+ keyed.sort((left, right) => left.base.localeCompare(right.base) ||
73
+ sourceDigest(left.item.source).localeCompare(sourceDigest(right.item.source)) ||
74
+ (left.item.frame_id ?? "").localeCompare(right.item.frame_id ?? ""));
75
+ const totals = new Map();
76
+ for (const { base } of keyed)
77
+ totals.set(base, (totals.get(base) ?? 0) + 1);
78
+ const seen = new Map();
79
+ const sourceMapRequests = [];
80
+ const items = keyed.map(({ base, item, sourceMapRawUrl }) => {
81
+ const occurrence = (seen.get(base) ?? 0) + 1;
82
+ seen.set(base, occurrence);
83
+ const scriptKey = totals.get(base) === 1 ? base : `${base}_${String(occurrence)}`;
84
+ if (item.source_map_url !== null && sourceMapRawUrl !== null)
85
+ sourceMapRequests.push({
86
+ scriptKey,
87
+ declaredUrl: item.source_map_url,
88
+ fetchUrl: sourceMapRawUrl,
89
+ });
90
+ return { script_key: scriptKey, ...item };
91
+ });
92
+ return {
93
+ inventory: { total: scriptCount, items },
94
+ sourceMapRequests,
95
+ };
96
+ };
97
+ const sourceDigest = (source) => (source.included ? source.artifact.sha256 : source.reason);
@@ -0,0 +1,46 @@
1
+ import { allowedSanitizedUrl, boundedText, isHttpUrl, recordValue, recordsValue, stringValue, } from "./CdpCaptureValues.js";
2
+ import { optionalCdpCommand } from "./CdpOptionalCommand.js";
3
+ export const captureWorkers = async (input, frameIds) => {
4
+ const { context, allowedOrigins, limitations, events } = input;
5
+ const completeness = events.completeness;
6
+ const result = await optionalCdpCommand({ ...context, sessionId: undefined }, "Target.getTargets", {}, limitations);
7
+ const items = [];
8
+ let total = 0;
9
+ if (result === undefined)
10
+ completeness.unavailable("workers");
11
+ for (const target of recordsValue(recordValue(result)?.targetInfos)) {
12
+ const type = stringValue(target.type) ?? "";
13
+ const url = allowedSanitizedUrl(target.url, allowedOrigins);
14
+ const relatedToPage = stringValue(target.openerId) === context.target.id ||
15
+ (stringValue(target.parentFrameId) !== undefined &&
16
+ frameIds.has(stringValue(target.parentFrameId) ?? ""));
17
+ if (!type.includes("worker"))
18
+ continue;
19
+ if (!relatedToPage) {
20
+ completeness.exclude("workers", "out_of_target_scope");
21
+ continue;
22
+ }
23
+ if (url === undefined) {
24
+ const rawUrl = stringValue(target.url);
25
+ completeness.exclude("workers", rawUrl === undefined || rawUrl === ""
26
+ ? "unattributed_origin"
27
+ : isHttpUrl(rawUrl)
28
+ ? "disallowed_origin"
29
+ : "unsupported_url");
30
+ continue;
31
+ }
32
+ total += 1;
33
+ if (items.length >= context.input.limits.max_workers)
34
+ continue;
35
+ items.push({
36
+ target_id: (stringValue(target.targetId) ?? "").slice(0, 256),
37
+ type: type.slice(0, 100),
38
+ url: url.url,
39
+ origin: url.origin,
40
+ attached: target.attached === true,
41
+ opener_target_id: boundedText(target.openerId, 256) ?? null,
42
+ parent_frame_id: boundedText(target.parentFrameId, 256) ?? null,
43
+ });
44
+ }
45
+ return { total, items };
46
+ };
@@ -35,7 +35,13 @@ export const discoverWebMcp = async (context) => {
35
35
  return;
36
36
  if (ingestFrameScopeEvent(event, frameScope))
37
37
  return;
38
- ingestWebMcpEvent(event, context.input, frameUrls, tools, completeness);
38
+ ingestWebMcpEvent({
39
+ event,
40
+ input: context.input,
41
+ frames: frameUrls,
42
+ tools,
43
+ completeness,
44
+ });
39
45
  });
40
46
  await context.progress?.report({
41
47
  phase: "browser_observation",
@@ -53,7 +59,14 @@ export const discoverWebMcp = async (context) => {
53
59
  // CDP sends the enable response before the required toolsAdded replay.
54
60
  await delayWithCancellation(Math.max(context.input.observation_ms, 25), "discover_webmcp_tools", context.signal);
55
61
  await assertStableAuthorizedFrame(context, initialUrl, origins);
56
- return result(context, frameTree, tools, completeness, limitations, available);
62
+ return buildWebMcpResult({
63
+ context,
64
+ frameTree,
65
+ tools,
66
+ completeness,
67
+ limitations,
68
+ available,
69
+ });
57
70
  }
58
71
  finally {
59
72
  removeListener();
@@ -70,18 +83,27 @@ const ingestFrameScopeEvent = (event, state) => {
70
83
  const params = recordValue(event.params);
71
84
  if (params === undefined)
72
85
  return false;
73
- if (event.method === "Page.frameDetached") {
74
- const frameId = stringValue(params.frameId);
75
- if (frameId === undefined || frameId.length > 256)
76
- state.completeness.exclude("webmcp_tools", "invalid_protocol_value");
77
- else
78
- removeFrame(frameId, state.frames, state.tools);
86
+ switch (event.method) {
87
+ case "Page.frameDetached":
88
+ return handleFrameDetached(params, state);
89
+ case "Page.frameNavigated":
90
+ return handleFrameUpdate(recordValue(params.frame), state);
91
+ case "Page.navigatedWithinDocument":
92
+ return handleFrameUpdate(params, state);
93
+ default:
94
+ return false;
95
+ }
96
+ };
97
+ const handleFrameDetached = (params, state) => {
98
+ const frameId = stringValue(params.frameId);
99
+ if (frameId === undefined || frameId.length > 256) {
100
+ state.completeness.exclude("webmcp_tools", "invalid_protocol_value");
79
101
  return true;
80
102
  }
81
- const frame = event.method === "Page.frameNavigated" ? recordValue(params.frame) : params;
82
- if (event.method !== "Page.frameNavigated" &&
83
- event.method !== "Page.navigatedWithinDocument")
84
- return false;
103
+ removeFrame(frameId, state.frames, state.tools);
104
+ return true;
105
+ };
106
+ const handleFrameUpdate = (frame, state) => {
85
107
  const frameId = stringValue(frame?.id) ?? stringValue(frame?.frameId);
86
108
  if (frameId === undefined || frameId.length > 256) {
87
109
  state.completeness.exclude("webmcp_tools", "invalid_protocol_value");
@@ -128,7 +150,8 @@ const assertStableAuthorizedFrame = async (context, initialUrl, origins) => {
128
150
  if (finalUrl !== initialUrl)
129
151
  throw new BrowserObservationError("inspect_web_page", "target_changed");
130
152
  };
131
- const ingestWebMcpEvent = (event, input, frames, tools, completeness) => {
153
+ const ingestWebMcpEvent = (options) => {
154
+ const { event, input, frames, tools, completeness } = options;
132
155
  const params = recordValue(event.params);
133
156
  if (params === undefined)
134
157
  return;
@@ -214,7 +237,8 @@ const registrationSource = (stack, allowedOrigins) => {
214
237
  column: integerOrNull(frame.columnNumber),
215
238
  };
216
239
  };
217
- const result = (context, frameTree, tools, completeness, limitations, available) => {
240
+ const buildWebMcpResult = (options) => {
241
+ const { context, frameTree, tools, completeness, limitations, available } = options;
218
242
  const targetUrl = mainFrameUrl(frameTree) ?? context.target.url;
219
243
  const sanitized = allowedSanitizedUrl(targetUrl, new Set(context.input.allowed_origins));
220
244
  return {
@@ -128,7 +128,13 @@ const unfilter = (raw, width, height, channels) => {
128
128
  const upperLeft = row > 0 && column >= channels
129
129
  ? (decoded[outputOffset + column - rowBytes - channels] ?? 0)
130
130
  : 0;
131
- decoded[outputOffset + column] = applyFilter(filter, source, left, above, upperLeft);
131
+ decoded[outputOffset + column] = applyFilter({
132
+ filter,
133
+ source,
134
+ left,
135
+ above,
136
+ upperLeft,
137
+ });
132
138
  }
133
139
  }
134
140
  if (channels === 4)
@@ -142,7 +148,8 @@ const unfilter = (raw, width, height, channels) => {
142
148
  }
143
149
  return rgba;
144
150
  };
145
- const applyFilter = (filter, source, left, above, upperLeft) => {
151
+ const applyFilter = (options) => {
152
+ const { filter, source, left, above, upperLeft } = options;
146
153
  switch (filter) {
147
154
  case 0:
148
155
  return source;
@@ -53,6 +53,10 @@ const resourceTemplateCatalog = [
53
53
  name: "investigation-workspace-revision",
54
54
  uri_template: "rea://workspace/{workspaceId}/revision/{revision}",
55
55
  },
56
+ {
57
+ name: "reconstruction-coverage-revision",
58
+ uri_template: "rea://reconstruction-coverage/{workspaceId}/revision/{revision}",
59
+ },
56
60
  ];
57
61
  const digest = (value) => {
58
62
  const encoded = canonicalize(value);
@@ -0,0 +1,82 @@
1
+ import { z } from "incur";
2
+ import { runProviderAnalysis } from "../application/DirectAnalysis.js";
3
+ import { logCliCommand } from "../cliLogging.js";
4
+ import { CLI_COMMANDS } from "../cliCommandNames.js";
5
+ export const registerArtifactCommands = (cli, logger) => {
6
+ cli.command(CLI_COMMANDS.inventoryArtifact, {
7
+ description: "Build a bounded deterministic artifact graph",
8
+ args: z.object({
9
+ path: z.string().describe("Application or package path"),
10
+ }),
11
+ options: z.object({
12
+ offset: z
13
+ .number()
14
+ .int()
15
+ .min(0)
16
+ .default(0)
17
+ .describe("Zero-based offset for graph nodes, occurrences, and edges"),
18
+ limit: z
19
+ .number()
20
+ .int()
21
+ .min(1)
22
+ .max(500)
23
+ .default(100)
24
+ .describe("Maximum nodes, occurrences, and edges per result section"),
25
+ integrityPolicy: z
26
+ .enum(["fail", "record-and-continue"])
27
+ .default("fail")
28
+ .describe("Behavior when declared artifact integrity does not match"),
29
+ integrityContinueApproved: z
30
+ .boolean()
31
+ .default(false)
32
+ .describe("Approve continuing after recorded integrity mismatches"),
33
+ maxIntegrityMismatches: z
34
+ .number()
35
+ .int()
36
+ .min(1)
37
+ .max(100)
38
+ .default(10)
39
+ .describe("Maximum integrity mismatches to record before stopping"),
40
+ nativeMountApproved: z
41
+ .boolean()
42
+ .default(false)
43
+ .describe("Approve read-only native mounting when required"),
44
+ }),
45
+ alias: {
46
+ integrityPolicy: "integrity-policy",
47
+ integrityContinueApproved: "integrity-continue-approved",
48
+ maxIntegrityMismatches: "max-integrity-mismatches",
49
+ nativeMountApproved: "native-mount-approved",
50
+ },
51
+ run: ({ args, options }) => logCliCommand(logger, "inventory-artifact", () => runProviderAnalysis(args.path, "inventory_artifact", {
52
+ node_offset: options.offset,
53
+ node_limit: options.limit,
54
+ occurrence_offset: options.offset,
55
+ occurrence_limit: options.limit,
56
+ edge_offset: options.offset,
57
+ edge_limit: options.limit,
58
+ integrity_policy: options.integrityPolicy,
59
+ integrity_continue_approved: options.integrityContinueApproved,
60
+ max_integrity_mismatches: options.maxIntegrityMismatches,
61
+ native_mount_approved: options.nativeMountApproved,
62
+ }, logger)),
63
+ });
64
+ cli.command(CLI_COMMANDS.extractArtifact, {
65
+ description: "Extract explicitly selected artifact occurrences safely",
66
+ args: z.object({
67
+ path: z.string().describe("Application or package path"),
68
+ outputRoot: z.string().describe("Absent absolute output root"),
69
+ occurrenceIds: z
70
+ .array(z.string().regex(/^occ_[a-f0-9]{64}$/u))
71
+ .min(1)
72
+ .max(500)
73
+ .describe("Exact artifact occurrence IDs selected for extraction"),
74
+ }),
75
+ alias: { outputRoot: "output-root", occurrenceIds: "occurrence-ids" },
76
+ run: ({ args }) => logCliCommand(logger, "extract-artifact", () => runProviderAnalysis(args.path, "extract_artifact", {
77
+ approved: true,
78
+ output_root: args.outputRoot,
79
+ occurrence_ids: args.occurrenceIds,
80
+ }, logger)),
81
+ });
82
+ };