rea-agents 2.0.0 → 2.2.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 (273) hide show
  1. package/README.md +103 -38
  2. package/bridge/ghidra/ReaGhidraBridge.java +96 -11
  3. package/dist/application/AndroidApplicationService.js +17 -0
  4. package/dist/application/AppleApplicationService.js +17 -0
  5. package/dist/application/ArtifactExtraction.js +1 -1
  6. package/dist/application/ArtifactInventory/classify.js +42 -0
  7. package/dist/application/ArtifactInventory/hash.js +43 -0
  8. package/dist/application/ArtifactInventory/reader.js +41 -0
  9. package/dist/application/ArtifactInventory/scanCanonical.js +155 -0
  10. package/dist/application/ArtifactInventory/scanReader.js +124 -0
  11. package/dist/application/ArtifactInventory/types.js +10 -0
  12. package/dist/application/ArtifactInventory.js +9 -351
  13. package/dist/application/AuthorizedArtifactInventory.js +2 -2
  14. package/dist/application/BinarySession.js +47 -270
  15. package/dist/application/BinarySessionExecution.js +28 -0
  16. package/dist/application/BinarySessionOpen.js +39 -0
  17. package/dist/application/BinarySessionRecords.js +149 -0
  18. package/dist/application/BinarySessionStatus.js +75 -0
  19. package/dist/application/CapabilityInventory.js +24 -2
  20. package/dist/application/ClientRegistrationStatus.js +11 -4
  21. package/dist/application/CrossVersionInventory.js +8 -2
  22. package/dist/application/CrossVersionInvestigation.js +1 -23
  23. package/dist/application/CrossVersionInvestigationCollections.js +23 -0
  24. package/dist/application/DirectAnalysis.js +47 -44
  25. package/dist/application/Doctor.js +156 -238
  26. package/dist/application/DoctorDiagnostics.js +180 -0
  27. package/dist/application/ElectronBoundaryAnalysis.js +23 -7
  28. package/dist/application/ElectronBoundaryGraphWindows.js +32 -8
  29. package/dist/application/EnhancedToolPagination.js +22 -0
  30. package/dist/application/EnhancedToolTypes.js +4 -0
  31. package/dist/application/EnhancedTools.js +20 -37
  32. package/dist/application/InstrumentedJavaScriptReplayHost.js +36 -0
  33. package/dist/application/InventoryProjectionEvidence.js +41 -0
  34. package/dist/application/InvestigationProviders.js +12 -0
  35. package/dist/application/InvestigationWorkspaceStore.js +24 -10
  36. package/dist/application/JavaScriptArtifactAnalysis.js +45 -6
  37. package/dist/application/JavaScriptArtifactFiles.js +6 -2
  38. package/dist/application/JavaScriptArtifactGraphBuilder.js +23 -1
  39. package/dist/application/JavaScriptArtifactGraphBundlers.js +225 -0
  40. package/dist/application/JavaScriptArtifactGraphContext.js +37 -36
  41. package/dist/application/JavaScriptArtifactGraphDocuments.js +27 -4
  42. package/dist/application/JavaScriptArtifactGraphFindings.js +54 -8
  43. package/dist/application/JavaScriptArtifactGraphStructure.js +29 -101
  44. package/dist/application/JavaScriptArtifactPathResolution.js +269 -0
  45. package/dist/application/JavaScriptArtifactReconstruction.js +1 -1
  46. package/dist/application/JavaScriptJsonModules.js +39 -0
  47. package/dist/application/JavaScriptModuleRelationships.js +262 -0
  48. package/dist/application/JavaScriptReplayPermission.js +16 -0
  49. package/dist/application/JavaScriptReplayService.js +182 -156
  50. package/dist/application/LinuxHopper.js +10 -0
  51. package/dist/application/MacHopper.js +22 -11
  52. package/dist/application/NodeRuntimeCharacterizationService.js +196 -0
  53. package/dist/application/PermissionAuthority.js +106 -63
  54. package/dist/application/ProcessCaptureCapability.js +1 -1
  55. package/dist/application/ProcessCapturePermission.js +13 -0
  56. package/dist/application/ProcessCli.js +2 -12
  57. package/dist/application/ProcessHarness.js +1 -1
  58. package/dist/application/ProcessPairedExperiment.js +72 -0
  59. package/dist/application/ProjectPermissionStore.js +48 -9
  60. package/dist/application/RealHopperAssertions.js +76 -0
  61. package/dist/application/ReconstructionCoverageService.js +69 -0
  62. package/dist/application/ReconstructionCoverageWorkspaceStore.js +31 -0
  63. package/dist/application/RuntimeExecutableDiagnostics.js +172 -0
  64. package/dist/application/Setup.js +148 -260
  65. package/dist/application/SetupClientConfiguration.js +224 -0
  66. package/dist/application/SetupClients.js +24 -2
  67. package/dist/application/SetupPlan.js +124 -12
  68. package/dist/application/SetupSkill.js +54 -36
  69. package/dist/application/SupportedClients.js +1 -0
  70. package/dist/application/Uninstall.js +12 -3
  71. package/dist/application/Upgrade.js +16 -1
  72. package/dist/application/WindowsCapabilities.js +86 -0
  73. package/dist/artifacts/AsarArtifactReader.js +11 -0
  74. package/dist/browser/BrowserProcessStartup.js +88 -0
  75. package/dist/browser/CdpCaptureDocuments.js +12 -8
  76. package/dist/browser/CdpCaptureEventBodyShapes.js +75 -0
  77. package/dist/browser/CdpCaptureEventHandlers.js +336 -0
  78. package/dist/browser/CdpCaptureEventHelpers.js +71 -0
  79. package/dist/browser/CdpCaptureEventState.js +1 -0
  80. package/dist/browser/CdpCaptureEventTypes.js +1 -0
  81. package/dist/browser/CdpCaptureEvents.js +29 -496
  82. package/dist/browser/CdpObservationSession.js +51 -8
  83. package/dist/browser/CdpPageCapture.js +12 -133
  84. package/dist/browser/CdpPageCaptureScripts.js +97 -0
  85. package/dist/browser/CdpPageCaptureWorkers.js +46 -0
  86. package/dist/browser/CdpWebMcpDiscovery.js +38 -14
  87. package/dist/browser/PngVisualDiff.js +9 -2
  88. package/dist/catalogIdentity.js +4 -0
  89. package/dist/cli/artifactCommands.js +82 -0
  90. package/dist/cli/coreAnalysisCommands.js +232 -0
  91. package/dist/cli/managedCommands.js +397 -0
  92. package/dist/cli/managedProjectGraphCommand.js +24 -0
  93. package/dist/cli/options.js +9 -0
  94. package/dist/cli/setupCommands.js +113 -0
  95. package/dist/cli/types.js +1 -0
  96. package/dist/cli/utilityCommands.js +122 -0
  97. package/dist/cli.js +10 -768
  98. package/dist/cliApplicationCommands.js +118 -4
  99. package/dist/cliBrowserAdvancedCommands.js +73 -16
  100. package/dist/cliBrowserCommands.js +39 -115
  101. package/dist/cliCommandNames.js +4 -0
  102. package/dist/cliElectronCommands.js +33 -62
  103. package/dist/cliEvidenceCommands.js +13 -2
  104. package/dist/cliInvestigationCommands.js +53 -10
  105. package/dist/cliObservationOptions.js +137 -0
  106. package/dist/cliPolicyCommands.js +80 -46
  107. package/dist/cliSetup.js +306 -0
  108. package/dist/config/environment.js +107 -0
  109. package/dist/config/parseConfig.js +228 -0
  110. package/dist/config/parsers.js +68 -0
  111. package/dist/config/permissions.js +30 -0
  112. package/dist/config/types.js +1 -0
  113. package/dist/config.js +1 -375
  114. package/dist/contracts/applicationToolContracts.js +134 -0
  115. package/dist/contracts/electronToolContracts.js +51 -3
  116. package/dist/contracts/managedToolContracts.js +8 -3
  117. package/dist/contracts/managedWorkflowToolContracts.js +3 -3
  118. package/dist/contracts/providerSelection.js +2 -0
  119. package/dist/contracts/sessionStatusContract.js +26 -0
  120. package/dist/contracts/toolContractTypes.js +12 -1
  121. package/dist/contracts/toolContracts.js +5 -12
  122. package/dist/contracts/toolEffects.js +14 -0
  123. package/dist/contracts/toolOutputSchemaGroups.js +274 -0
  124. package/dist/contracts/toolOutputSchemaPrimitives.js +328 -0
  125. package/dist/contracts/toolOutputSchemas.js +2 -550
  126. package/dist/domain/analysisErrorPresentation.js +234 -0
  127. package/dist/domain/analysisErrorProjection.js +284 -0
  128. package/dist/domain/androidApplication.js +206 -0
  129. package/dist/domain/appleApplication.js +221 -0
  130. package/dist/domain/artifactComparison.js +34 -15
  131. package/dist/domain/binaryTarget.js +87 -37
  132. package/dist/domain/boundedCartesianProjection.js +15 -0
  133. package/dist/domain/browserObservation.js +1 -285
  134. package/dist/domain/browserObservationSchemas.js +286 -0
  135. package/dist/domain/electronStaticAnalysisBrowser.js +14 -2
  136. package/dist/domain/errors.js +4 -486
  137. package/dist/domain/functionComparison.js +4 -165
  138. package/dist/domain/functionComparisonDimensions.js +164 -0
  139. package/dist/domain/javascriptApplicationVersionItems.js +18 -6
  140. package/dist/domain/javascriptApplicationVersionKeys.js +8 -8
  141. package/dist/domain/javascriptExportInstrumentation.js +97 -0
  142. package/dist/domain/javascriptFeatureTraversal.js +19 -7
  143. package/dist/domain/javascriptRuntimeStaticCandidates.js +3 -1
  144. package/dist/domain/javascriptSemanticAnalysis.js +386 -0
  145. package/dist/domain/javascriptSemanticIr.js +30 -0
  146. package/dist/domain/javascriptSemanticProjection.js +366 -0
  147. package/dist/domain/javascriptSemanticState.js +40 -0
  148. package/dist/domain/javascriptSemanticTraversal.js +22 -0
  149. package/dist/domain/javascriptSemanticValues.js +352 -0
  150. package/dist/domain/javascriptStaticAnalysis.js +5 -221
  151. package/dist/domain/javascriptStaticAnalysisBundler.js +209 -0
  152. package/dist/domain/javascriptStaticAnalysisCalls.js +180 -0
  153. package/dist/domain/javascriptStaticAnalysisHelpers.js +71 -2
  154. package/dist/domain/knownPageCoverage.js +21 -0
  155. package/dist/domain/managedApplicationGraph.js +14 -364
  156. package/dist/domain/managedApplicationGraphCoverage.js +170 -0
  157. package/dist/domain/managedApplicationGraphNodeCoverage.js +6 -0
  158. package/dist/domain/managedApplicationGraphNodes.js +336 -0
  159. package/dist/domain/managedArtifact.js +16 -8
  160. package/dist/domain/managedMemberComparison.js +37 -391
  161. package/dist/domain/managedMemberComparisonCoverage.js +72 -0
  162. package/dist/domain/managedMemberComparisonMatch.js +356 -0
  163. package/dist/domain/managedNativeVerification.js +27 -389
  164. package/dist/domain/managedNativeVerificationMatch.js +272 -0
  165. package/dist/domain/managedNativeVerificationSchemas.js +141 -0
  166. package/dist/domain/managedReconstruction.js +82 -69
  167. package/dist/domain/managedRuntimeCorrelation.js +12 -3
  168. package/dist/domain/nodeRuntimeCharacterization.js +66 -0
  169. package/dist/domain/permissionPolicy.js +2 -0
  170. package/dist/domain/processComparison.js +19 -0
  171. package/dist/domain/processPairedExperiment.js +128 -0
  172. package/dist/domain/reconstructionCoverage.js +387 -0
  173. package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
  174. package/dist/domain/reconstructionVerificationSchemas.js +8 -0
  175. package/dist/domain/replayMachine.js +316 -0
  176. package/dist/domain/replayMachineRuntime.js +215 -0
  177. package/dist/domain/runtimeCharacterization.js +85 -0
  178. package/dist/domain/runtimeIdentification.js +210 -0
  179. package/dist/domain/webBundleAnalyzer.js +3 -409
  180. package/dist/domain/webBundleAnalyzerAst.js +77 -0
  181. package/dist/domain/webBundleAnalyzerInspection.js +307 -0
  182. package/dist/domain/webBundleAnalyzerResult.js +120 -0
  183. package/dist/dotnet/ManagedArtifactInspector.js +50 -29
  184. package/dist/dotnet/ManagedMemberInspector.js +51 -785
  185. package/dist/dotnet/ManagedMemberInspectorCore.js +297 -0
  186. package/dist/dotnet/ManagedMemberInstructionDecoder.js +427 -0
  187. package/dist/dotnet/ManagedMemberRows.js +120 -0
  188. package/dist/dotnet/ManagedMetadataInventory.js +42 -306
  189. package/dist/dotnet/ManagedMetadataInventoryRows.js +292 -0
  190. package/dist/dotnet/ManagedMetadataLayout.js +48 -111
  191. package/dist/dotnet/ManagedMetadataRowSizes.js +54 -0
  192. package/dist/dotnet/ManagedMethodBodyReader.js +143 -0
  193. package/dist/dotnet/ManagedNativeBoundaryHelpers.js +311 -0
  194. package/dist/dotnet/ManagedNativeBoundaryInspector.js +102 -350
  195. package/dist/dotnet/ManagedPeReader.js +59 -28
  196. package/dist/evaluation/CodexAgentEval.js +132 -0
  197. package/dist/generatedPackageMetadata.js +2 -2
  198. package/dist/ghidra/GhidraClient.js +76 -91
  199. package/dist/ghidra/GhidraClientStartup.js +29 -0
  200. package/dist/ghidra/GhidraClientWire.js +34 -0
  201. package/dist/ghidra/GhidraDefaults.js +1 -1
  202. package/dist/ghidra/GhidraDiagnostics.js +6 -1
  203. package/dist/ghidra/GhidraInstallation.js +20 -15
  204. package/dist/ghidra/GhidraLauncher.js +93 -29
  205. package/dist/ghidra/GhidraProvider.js +61 -161
  206. package/dist/ghidra/GhidraProviderCapabilities.js +173 -0
  207. package/dist/ghidra/GhidraSessionValues.js +2 -0
  208. package/dist/ghidra/GhidraSocketConnection.js +44 -7
  209. package/dist/ghidra/GhidraTargetSnapshot.js +30 -0
  210. package/dist/ghidra/GhidraTransport.js +71 -0
  211. package/dist/identity.js +4 -2
  212. package/dist/main/messages.js +5 -0
  213. package/dist/main/reload.js +49 -0
  214. package/dist/main/shutdown.js +25 -0
  215. package/dist/main/startup.js +14 -0
  216. package/dist/main/state.js +26 -0
  217. package/dist/main/transport.js +61 -0
  218. package/dist/main/types.js +1 -0
  219. package/dist/main.js +35 -146
  220. package/dist/process/PrivateRuntimeRoot.js +3 -2
  221. package/dist/process/ProcessOwnership.js +35 -0
  222. package/dist/process/ProviderProcess.js +2 -0
  223. package/dist/replay/JavaScriptReplayWorker.js +64 -50
  224. package/dist/replay/LinuxJavaScriptReplayRunner.js +173 -390
  225. package/dist/replay/LinuxJavaScriptReplaySandbox.js +140 -0
  226. package/dist/replay/ReplayOutcome.js +95 -0
  227. package/dist/replay/ReplayProcessLifecycle.js +71 -0
  228. package/dist/server/ProcessCaptureElicitation.js +157 -0
  229. package/dist/server/createServer.js +124 -56
  230. package/dist/server/javascriptApplicationResult.js +85 -0
  231. package/dist/server/registerApplicationTools/characterization.js +57 -0
  232. package/dist/server/registerApplicationTools/compareVersions.js +34 -0
  233. package/dist/server/registerApplicationTools/controlledReplay.js +38 -0
  234. package/dist/server/registerApplicationTools/coverage.js +84 -0
  235. package/dist/server/registerApplicationTools/helpers.js +42 -0
  236. package/dist/server/registerApplicationTools/traceFeature.js +26 -0
  237. package/dist/server/registerApplicationTools/types.js +1 -0
  238. package/dist/server/registerApplicationTools.js +10 -112
  239. package/dist/server/registerBrowserTools.js +59 -83
  240. package/dist/server/registerElectronTools.js +48 -49
  241. package/dist/server/registerEnhancedTools.js +34 -42
  242. package/dist/server/registerEvidenceResources.js +56 -0
  243. package/dist/server/registerInvestigationTools/helpers.js +74 -0
  244. package/dist/server/registerInvestigationTools/types.js +1 -0
  245. package/dist/server/registerInvestigationTools.js +83 -116
  246. package/dist/server/registerJavaScriptApplicationGraphResource.js +69 -0
  247. package/dist/server/registerManagedTools.js +18 -1
  248. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +65 -0
  249. package/dist/server/registerManagedWorkflowTools/contract.js +8 -0
  250. package/dist/server/registerManagedWorkflowTools/evidence.js +43 -0
  251. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +39 -0
  252. package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +39 -0
  253. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +52 -0
  254. package/dist/server/registerManagedWorkflowTools/types.js +1 -0
  255. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +75 -0
  256. package/dist/server/registerManagedWorkflowTools.js +10 -274
  257. package/dist/server/registerOfficialTools.js +73 -59
  258. package/dist/server/registerSessionRecordTools.js +137 -0
  259. package/dist/server/registerSessionStatusTool.js +97 -26
  260. package/dist/server/registerSessionTools.js +60 -164
  261. package/dist/server/sessionAvailabilityPolicy.js +10 -0
  262. package/dist/server/toolRegistrationOptions.js +101 -3
  263. package/dist/server/toolResult.js +15 -4
  264. package/package.json +11 -11
  265. package/skills/reverse-engineer-anything/SKILL.md +76 -0
  266. package/skills/reverse-engineer-anything/references/controlled-replay.md +12 -0
  267. package/skills/reverse-engineer-anything/references/evidence-workflows.md +33 -0
  268. package/skills/reverse-engineer-anything/references/javascript-applications.md +25 -0
  269. package/skills/reverse-engineer-anything/references/native-and-artifacts.md +36 -0
  270. package/skills/reverse-engineer-anything/references/runtime-observation.md +24 -0
  271. package/scripts/prepare-node-pty.mjs +0 -35
  272. package/scripts/rebuild-native.mjs +0 -22
  273. package/skills/rea-analysis/SKILL.md +0 -222
@@ -1,5 +1,4 @@
1
1
  import { constants } from "node:fs";
2
- import { createReadStream } from "node:fs";
3
2
  import { createHash } from "node:crypto";
4
3
  import { access, open, readFile, realpath, stat, } from "node:fs/promises";
5
4
  import { execFile } from "node:child_process";
@@ -22,43 +21,42 @@ export const parseBinaryTarget = async (input, cwd = process.cwd(), hostArchitec
22
21
  if (!resolved.ok)
23
22
  return err(resolved.error);
24
23
  const path = resolved.value;
25
- if (!(await stat(path)).isFile())
26
- return err(new BinaryTargetError(path, "target is not a regular file"));
27
- if (targetKind === "database" ||
28
- (targetKind === undefined && path.toLowerCase().endsWith(".hop")))
29
- return ok({
30
- path,
31
- sourcePath: canonical,
32
- sha256: await sha256File(path),
33
- kind: "database",
34
- format: "analysis-database",
35
- });
36
24
  const handle = await open(path, "r");
37
- let detected;
38
25
  try {
26
+ if (!(await handle.stat()).isFile())
27
+ return err(new BinaryTargetError(path, "target is not a regular file"));
28
+ if (targetKind === "database" ||
29
+ (targetKind === undefined && path.toLowerCase().endsWith(".hop")))
30
+ return ok({
31
+ path,
32
+ sourcePath: canonical,
33
+ sha256: await sha256Handle(handle),
34
+ kind: "database",
35
+ format: "analysis-database",
36
+ });
39
37
  const artifactFormat = await detectArtifactFormat(path, handle);
40
38
  if (artifactFormat !== undefined)
41
39
  return ok({
42
40
  path,
43
41
  sourcePath: canonical,
44
- sha256: await sha256File(path),
42
+ sha256: await sha256Handle(handle),
45
43
  kind: isArchiveFormat(artifactFormat) ? "archive" : "artifact",
46
44
  format: artifactFormat,
47
45
  });
48
- detected = await readExecutableMetadata(handle, hostArchitecture);
46
+ const detected = await readExecutableMetadata(handle, hostArchitecture);
47
+ if (!detected.ok)
48
+ return err(new BinaryTargetError(path, detected.error));
49
+ return ok({
50
+ path,
51
+ sourcePath: canonical,
52
+ sha256: await sha256Handle(handle),
53
+ kind: "executable",
54
+ ...detected.value,
55
+ });
49
56
  }
50
57
  finally {
51
58
  await handle.close();
52
59
  }
53
- if (!detected.ok)
54
- return err(new BinaryTargetError(path, detected.error));
55
- return ok({
56
- path,
57
- sourcePath: canonical,
58
- sha256: await sha256File(path),
59
- kind: "executable",
60
- ...detected.value,
61
- });
62
60
  }
63
61
  catch (cause) {
64
62
  return err(new BinaryTargetError(candidate, "path is not readable", { cause }));
@@ -107,10 +105,17 @@ const namedArtifactFormat = (lowerPath) => {
107
105
  return /\.(?:m?js|cjs)$/u.test(lowerPath) ? "javascript" : undefined;
108
106
  };
109
107
  const isArchiveFormat = (format) => ["zip", "ipa", "apk", "asar", "dmg", "pkg"].includes(format);
110
- const sha256File = async (path) => {
108
+ const sha256Handle = async (handle) => {
111
109
  const hash = createHash("sha256");
112
- for await (const chunk of createReadStream(path))
113
- hash.update(chunk);
110
+ const chunk = Buffer.allocUnsafe(64 * 1024);
111
+ let position = 0;
112
+ while (true) {
113
+ const observed = await handle.read(chunk, 0, chunk.length, position);
114
+ if (observed.bytesRead === 0)
115
+ break;
116
+ hash.update(chunk.subarray(0, observed.bytesRead));
117
+ position += observed.bytesRead;
118
+ }
114
119
  return hash.digest("hex");
115
120
  };
116
121
  const resolveAppBundle = async (path) => {
@@ -184,13 +189,7 @@ const readExecutableMetadata = async (handle, hostArchitecture) => {
184
189
  const bytes = prefix.subarray(0, prefixRead.bytesRead);
185
190
  if (bytes.length >= 64 && bytes[0] === 0x4d && bytes[1] === 0x5a) {
186
191
  const offset = bytes.readUInt32LE(0x3c);
187
- if (offset > bytes.length - 6) {
188
- const record = Buffer.alloc(6);
189
- const recordRead = await handle.read(record, 0, record.length, offset);
190
- return recordRead.bytesRead === record.length
191
- ? parsePeRecord(record)
192
- : err("invalid or truncated PE header");
193
- }
192
+ return readPeMetadata(handle, offset);
194
193
  }
195
194
  if (bytes.length >= 8) {
196
195
  const magic = bytes.readUInt32BE(0);
@@ -207,6 +206,20 @@ const readExecutableMetadata = async (handle, hostArchitecture) => {
207
206
  }
208
207
  return parseExecutableHeader(bytes, hostArchitecture);
209
208
  };
209
+ const readPeMetadata = async (handle, offset) => {
210
+ const fileHeader = Buffer.alloc(24);
211
+ const fileHeaderRead = await handle.read(fileHeader, 0, fileHeader.length, offset);
212
+ if (fileHeaderRead.bytesRead !== fileHeader.length)
213
+ return err("invalid or truncated PE header");
214
+ const optionalHeaderSize = fileHeader.readUInt16LE(20);
215
+ if (optionalHeaderSize > 4096)
216
+ return err("invalid PE optional header size");
217
+ const record = Buffer.alloc(24 + optionalHeaderSize);
218
+ const recordRead = await handle.read(record, 0, record.length, offset);
219
+ return recordRead.bytesRead === record.length
220
+ ? parsePeRecord(record)
221
+ : err("invalid or truncated PE header");
222
+ };
210
223
  /**
211
224
  * Parse supported executable headers without I/O. The caller supplies the host
212
225
  * architecture used for deterministic FAT Mach-O slice selection.
@@ -294,22 +307,59 @@ const parsePe = (bytes) => {
294
307
  if (bytes.length < 64)
295
308
  return err("truncated PE DOS header");
296
309
  const offset = bytes.readUInt32LE(0x3c);
297
- if (offset > bytes.length - 6)
310
+ if (offset > bytes.length - 24)
298
311
  return err("invalid or truncated PE header");
299
- return parsePeRecord(bytes.subarray(offset, offset + 6));
312
+ return parsePeRecord(bytes.subarray(offset));
300
313
  };
301
314
  const parsePeRecord = (record) => {
302
- if (record.length < 6 || record.toString("binary", 0, 4) !== "PE\u0000\u0000")
315
+ if (record.length < 24 ||
316
+ record.toString("binary", 0, 4) !== "PE\u0000\u0000")
303
317
  return err("invalid or truncated PE header");
304
318
  const architecture = peArchitecture(record.readUInt16LE(4));
305
319
  if (architecture === undefined)
306
320
  return err("unsupported PE architecture");
321
+ const optionalHeaderSize = record.readUInt16LE(20);
322
+ if (optionalHeaderSize > 4096 || record.length < 24 + optionalHeaderSize)
323
+ return err("invalid or truncated PE optional header");
324
+ const optionalHeader = record.subarray(24, 24 + optionalHeaderSize);
325
+ const managed = peManagedStatus(optionalHeader, architecture);
326
+ if (!managed.ok)
327
+ return managed;
328
+ const characteristics = record.readUInt16LE(22);
307
329
  return ok({
308
330
  format: "pe",
309
331
  architecture,
310
332
  availableArchitectures: [architecture],
333
+ executableRole: (characteristics & 0x0002) === 0
334
+ ? "non-executable"
335
+ : (characteristics & 0x2000) === 0
336
+ ? "application"
337
+ : "shared-library",
338
+ managed: managed.value,
311
339
  });
312
340
  };
341
+ const peManagedStatus = (optionalHeader, architecture) => {
342
+ if (optionalHeader.length < 2)
343
+ return err("truncated PE optional header");
344
+ const magic = optionalHeader.readUInt16LE(0);
345
+ const expectedMagic = architecture === "x86_64" || architecture === "arm64" ? 0x20b : 0x10b;
346
+ if (magic !== expectedMagic)
347
+ return err("PE optional-header magic does not match its architecture");
348
+ const directoryOffset = magic === 0x20b ? 112 : 96;
349
+ const directoryCountOffset = directoryOffset - 4;
350
+ if (optionalHeader.length < directoryCountOffset + 4)
351
+ return err("truncated PE optional header");
352
+ const directoryCount = optionalHeader.readUInt32LE(directoryCountOffset);
353
+ const requiredBytes = directoryOffset + directoryCount * 8;
354
+ if (!Number.isSafeInteger(requiredBytes) ||
355
+ requiredBytes > optionalHeader.length)
356
+ return err("truncated PE data-directory table");
357
+ if (directoryCount <= 14)
358
+ return ok(false);
359
+ const cliDirectory = directoryOffset + 14 * 8;
360
+ return ok(optionalHeader.readUInt32LE(cliDirectory) !== 0 ||
361
+ optionalHeader.readUInt32LE(cliDirectory + 4) !== 0);
362
+ };
313
363
  const machArchitecture = (cpu) => {
314
364
  switch (cpu) {
315
365
  case 7:
@@ -0,0 +1,15 @@
1
+ /** Project a Cartesian product without materializing values beyond the output limit. */
2
+ export const projectBoundedCartesian = (left, right, maximum, project) => {
3
+ const values = [];
4
+ for (const leftValue of left) {
5
+ for (const rightValue of right) {
6
+ if (values.length === maximum)
7
+ return {
8
+ values,
9
+ omitted: left.length * right.length - values.length,
10
+ };
11
+ values.push(project(leftValue, rightValue));
12
+ }
13
+ }
14
+ return { values, omitted: 0 };
15
+ };
@@ -1,7 +1,5 @@
1
1
  import { z } from "zod";
2
- import { browserCompletenessSchema } from "./browserCompleteness.js";
3
- import { webTextArtifactSchema } from "./webContentArtifact.js";
4
- import { jsonShapeSchema } from "./jsonShape.js";
2
+ export { browserTargetListSchema, webPageInspectionSchema, } from "./browserObservationSchemas.js";
5
3
  const parseExactOrigin = (value) => {
6
4
  let url;
7
5
  try {
@@ -306,285 +304,3 @@ export const sanitizeBrowserUrl = (value) => {
306
304
  redacted: wasTruncated || hadCredentials || hadFragment || names.length > 0,
307
305
  };
308
306
  };
309
- const browserVersionSchema = z.object({
310
- product: z.string(),
311
- protocol_version: z.string(),
312
- revision: z.string(),
313
- user_agent: z.string(),
314
- js_version: z.string(),
315
- });
316
- const browserTargetSchema = z.object({
317
- target_id: z.string(),
318
- type: z.string(),
319
- title: z.string(),
320
- url: z.string(),
321
- origin: z.string(),
322
- attached: z.boolean(),
323
- });
324
- /** Bounded and policy-filtered browser target discovery result. */
325
- export const browserTargetListSchema = z.object({
326
- schema_version: z.literal(1),
327
- browser: browserVersionSchema,
328
- targets: z.object({
329
- items: z.array(browserTargetSchema),
330
- offset: z.number().int().min(0),
331
- limit: z.number().int().min(1),
332
- total: z.number().int().min(0),
333
- next_offset: z.number().int().min(0).nullable(),
334
- has_more: z.boolean(),
335
- }),
336
- excluded: z.object({
337
- disallowed_origin: z.number().int().min(0),
338
- unsupported_url: z.number().int().min(0),
339
- non_page: z.number().int().min(0),
340
- }),
341
- limitations: z.array(z.string()),
342
- });
343
- const browserFrameSchema = z.object({
344
- frame_id: z.string(),
345
- parent_frame_id: z.string().nullable(),
346
- url: z.string(),
347
- origin: z.string().nullable(),
348
- });
349
- const browserDomNodeSchema = z.object({
350
- index: z.number().int().min(0),
351
- parent_index: z.number().int().min(-1),
352
- node_type: z.number().int().min(0),
353
- node_name: z.string(),
354
- node_value_length: z.number().int().min(0),
355
- attribute_names: z.array(z.string()),
356
- });
357
- const browserAxNodeSchema = z.object({
358
- node_id: z.string(),
359
- parent_id: z.string().nullable(),
360
- role: z.string().nullable(),
361
- name: z.string().nullable(),
362
- description: z.string().nullable(),
363
- ignored: z.boolean(),
364
- });
365
- const browserScriptSourceSchema = z.discriminatedUnion("included", [
366
- z.object({ included: z.literal(false), reason: z.string() }),
367
- z.object({
368
- included: z.literal(true),
369
- artifact: webTextArtifactSchema,
370
- }),
371
- ]);
372
- const browserResourceReconciliationSchema = z.discriminatedUnion("status", [
373
- z.object({ status: z.literal("exact"), resource_key: z.string() }),
374
- z.object({
375
- status: z.literal("ambiguous"),
376
- candidate_resource_keys: z.array(z.string()),
377
- }),
378
- z.object({
379
- status: z.literal("unmatched"),
380
- reason: z.literal("no_exact_sanitized_url"),
381
- }),
382
- ]);
383
- const browserScriptSchema = z.object({
384
- script_key: z.string().regex(/^scr_[a-f0-9]{64}(?:_[0-9]+)?$/u),
385
- frame_id: z.string().nullable().default(null),
386
- url: z.string(),
387
- origin: z.string().nullable(),
388
- cdp_hash: z.string(),
389
- length: z.number().int().min(0),
390
- is_module: z.boolean(),
391
- language: z.string().nullable(),
392
- source_map_url: z.string().nullable(),
393
- resource_reconciliation: browserResourceReconciliationSchema,
394
- source: browserScriptSourceSchema,
395
- });
396
- const browserResourceSchema = z.object({
397
- resource_key: z.string().regex(/^res_[a-f0-9]{64}$/u),
398
- url: z.string(),
399
- origin: z.string().nullable(),
400
- type: z.string(),
401
- mime_type: z.string(),
402
- content_size: z.number().min(0).nullable(),
403
- });
404
- const browserNetworkRequestSchema = z.object({
405
- request_id: z.string(),
406
- url: z.string(),
407
- origin: z.string().nullable(),
408
- method: z.string(),
409
- resource_type: z.string().nullable(),
410
- status: z.number().nullable(),
411
- mime_type: z.string().nullable(),
412
- encoded_data_length: z.number().min(0).nullable(),
413
- initiator: z.object({
414
- type: z.string(),
415
- url: z.string().nullable(),
416
- line: z.number().int().min(0).nullable(),
417
- column: z.number().int().min(0).nullable(),
418
- }),
419
- body_shapes: z.object({
420
- status: z.enum([
421
- "not_approved",
422
- "included",
423
- "partial",
424
- "unavailable",
425
- "truncated",
426
- ]),
427
- request: jsonShapeSchema.nullable(),
428
- response: jsonShapeSchema.nullable(),
429
- }),
430
- });
431
- const browserConsoleEventSchema = z.object({
432
- type: z.string(),
433
- timestamp: z.number(),
434
- argument_types: z.array(z.string()),
435
- url: z.string().nullable(),
436
- line: z.number().int().min(0).nullable(),
437
- column: z.number().int().min(0).nullable(),
438
- text_capture: z.object({
439
- status: z.enum(["not_approved", "included", "truncated"]),
440
- values: z.array(z.object({
441
- argument_index: z.number().int().min(0),
442
- type: z.string(),
443
- text: z.string(),
444
- })),
445
- retained_bytes: z.number().int().min(0),
446
- truncated_values: z.number().int().min(0),
447
- }),
448
- });
449
- const browserWebSocketEventSchema = z.object({
450
- request_id: z.string(),
451
- direction: z.enum(["sent", "received"]),
452
- opcode: z.number().int().min(0),
453
- payload_bytes: z.number().int().min(0),
454
- payload_shape: z
455
- .object({
456
- format: z.enum(["json", "text", "binary"]),
457
- json_shape: jsonShapeSchema.nullable(),
458
- truncated: z.boolean(),
459
- })
460
- .nullable(),
461
- });
462
- const browserWorkerSchema = z.object({
463
- target_id: z.string(),
464
- type: z.string(),
465
- url: z.string(),
466
- origin: z.string().nullable(),
467
- attached: z.boolean(),
468
- opener_target_id: z.string().nullable().default(null),
469
- parent_frame_id: z.string().nullable().default(null),
470
- });
471
- const browserCspSourceSchema = z.object({
472
- kind: z.enum([
473
- "keyword",
474
- "scheme",
475
- "approved_origin",
476
- "external_origin",
477
- "other",
478
- ]),
479
- value: z.string().nullable(),
480
- });
481
- const browserLinkMetadataSchema = z.object({
482
- href: z.string().nullable(),
483
- destination_scope: z.enum(["approved", "outside_policy", "unsupported"]),
484
- rel: z.array(z.string()),
485
- as: z.string().nullable(),
486
- type: z.string().nullable(),
487
- crossorigin: z.string().nullable(),
488
- });
489
- const browserAgentHintSchema = z.object({
490
- mechanism: z.enum([
491
- "link_rel",
492
- "dom_link_rel",
493
- "well_known_resource",
494
- "response_header",
495
- ]),
496
- declaration: z.string(),
497
- url: z.string().nullable(),
498
- trust: z.literal("page-declared-untrusted"),
499
- });
500
- const browserSafeMetadataSchema = z.object({
501
- responses: z.array(z.object({
502
- request_id: z.string(),
503
- url: z.string(),
504
- mime_type: z.string().nullable(),
505
- content_length: z.number().int().min(0).nullable(),
506
- content_encoding: z.string().nullable(),
507
- csp: z.object({
508
- directives: z.array(z.object({
509
- name: z.string(),
510
- sources: z.array(browserCspSourceSchema),
511
- })),
512
- nonce_count: z.number().int().min(0),
513
- hash_count: z.number().int().min(0),
514
- }),
515
- links: z.array(browserLinkMetadataSchema),
516
- policies: z.object({
517
- coop: z.string().nullable(),
518
- coep: z.string().nullable(),
519
- corp: z.string().nullable(),
520
- referrer_policy: z.string().nullable(),
521
- x_content_type_options: z.string().nullable(),
522
- permissions_policy_features: z.array(z.string()),
523
- }),
524
- })),
525
- dom_urls: z.array(z.object({
526
- node_index: z.number().int().min(0),
527
- attribute: z.enum(["href", "src", "action", "formaction", "poster"]),
528
- url: z.string().nullable(),
529
- destination_scope: z.enum(["approved", "outside_policy", "unsupported"]),
530
- })),
531
- agent_hints: z.array(browserAgentHintSchema),
532
- excluded_dom_urls: z.number().int().min(0),
533
- headers_allowlisted: z.literal(true),
534
- });
535
- /** Provider-neutral normalized result for one passive web-page observation. */
536
- export const webPageInspectionSchema = z.object({
537
- schema_version: z.literal(2),
538
- browser: browserVersionSchema,
539
- target: browserTargetSchema,
540
- capture_window: z.object({
541
- started_at: z.iso.datetime(),
542
- ended_at: z.iso.datetime(),
543
- observation_ms: z.number().int().min(0),
544
- }),
545
- completeness: browserCompletenessSchema,
546
- frames: z.array(browserFrameSchema),
547
- dom: z.object({
548
- total_nodes: z.number().int().min(0),
549
- nodes: z.array(browserDomNodeSchema),
550
- }),
551
- accessibility: z.object({
552
- total_nodes: z.number().int().min(0),
553
- text_capture: z.object({
554
- status: z.enum(["not_approved", "included", "truncated", "unavailable"]),
555
- retained_bytes: z.number().int().min(0),
556
- excluded_fields: z.number().int().min(0),
557
- truncated_fields: z.number().int().min(0),
558
- }),
559
- nodes: z.array(browserAxNodeSchema),
560
- }),
561
- scripts: z.object({
562
- total: z.number().int().min(0),
563
- items: z.array(browserScriptSchema),
564
- }),
565
- resources: z.array(browserResourceSchema),
566
- network: z.object({
567
- requests: z.array(browserNetworkRequestSchema),
568
- websocket_events: z.array(browserWebSocketEventSchema),
569
- coverage_started_at: z.iso.datetime(),
570
- prior_activity_available: z.literal(false),
571
- }),
572
- console: z.object({
573
- events: z.array(browserConsoleEventSchema),
574
- coverage_started_at: z.iso.datetime(),
575
- prior_activity_available: z.literal(false),
576
- }),
577
- workers: z.array(browserWorkerSchema),
578
- metadata: browserSafeMetadataSchema,
579
- storage: z.object({
580
- origin: z.string(),
581
- usage_bytes: z.number().min(0).nullable(),
582
- quota_bytes: z.number().min(0).nullable(),
583
- local_storage_keys: z.array(z.string()),
584
- session_storage_keys: z.array(z.string()),
585
- indexed_db_names: z.array(z.string()),
586
- cache_names: z.array(z.string()),
587
- values_redacted: z.literal(true),
588
- }),
589
- limitations: z.array(z.string()),
590
- });