rea-agents 1.6.0 → 2.0.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 (238) hide show
  1. package/README.md +157 -66
  2. package/bridge/ghidra/ReaGhidraBridge.java +2075 -0
  3. package/bridge/hopper_bridge.py +13 -3
  4. package/dist/application/AbortablePromise.js +25 -0
  5. package/dist/application/AnalysisProvider.js +3 -0
  6. package/dist/application/AnalysisProviderEvaluation.js +60 -0
  7. package/dist/application/AnalysisProviderRegistry.js +228 -0
  8. package/dist/application/AnalysisSnapshotCache.js +41 -21
  9. package/dist/application/AnalysisSnapshotFiles.js +5 -6
  10. package/dist/application/BinarySession.js +218 -101
  11. package/dist/application/CapabilityInventory.js +18 -0
  12. package/dist/application/CompositeProvider.js +20 -8
  13. package/dist/application/CrossVersionInvestigation.js +10 -6
  14. package/dist/application/DirectAnalysis.js +49 -35
  15. package/dist/application/Doctor.js +110 -8
  16. package/dist/application/ElectronBoundaryAnalysis.js +96 -0
  17. package/dist/application/ElectronBoundaryGraph.js +9 -0
  18. package/dist/application/ElectronBoundaryGraphContext.js +62 -0
  19. package/dist/application/ElectronBoundaryGraphIpc.js +242 -0
  20. package/dist/application/ElectronBoundaryGraphNative.js +86 -0
  21. package/dist/application/ElectronBoundaryGraphWindows.js +199 -0
  22. package/dist/application/EnhancedTools.js +39 -14
  23. package/dist/application/InvestigationProviders.js +41 -0
  24. package/dist/application/JavaScriptApplicationEvidence.js +26 -0
  25. package/dist/application/JavaScriptApplicationEvidenceGraph.js +89 -0
  26. package/dist/application/JavaScriptApplicationService.js +74 -0
  27. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +29 -0
  28. package/dist/application/JavaScriptApplicationWorkflowService.js +90 -0
  29. package/dist/application/JavaScriptArtifactAnalysis.js +305 -0
  30. package/dist/application/JavaScriptArtifactAnalysisTypes.js +1 -0
  31. package/dist/application/JavaScriptArtifactFiles.js +231 -0
  32. package/dist/application/JavaScriptArtifactGraphAccumulator.js +54 -0
  33. package/dist/application/JavaScriptArtifactGraphBuilder.js +144 -0
  34. package/dist/application/JavaScriptArtifactGraphContext.js +205 -0
  35. package/dist/application/JavaScriptArtifactGraphDocuments.js +108 -0
  36. package/dist/application/JavaScriptArtifactGraphEvidence.js +99 -0
  37. package/dist/application/JavaScriptArtifactGraphFindings.js +271 -0
  38. package/dist/application/JavaScriptArtifactGraphStructure.js +409 -0
  39. package/dist/application/JavaScriptArtifactReconstruction.js +77 -0
  40. package/dist/application/JavaScriptArtifactReconstructionInput.js +18 -0
  41. package/dist/application/JavaScriptReplayPlanning.js +201 -0
  42. package/dist/application/JavaScriptReplayService.js +266 -0
  43. package/dist/application/JavaScriptRuntimeReconciliationEvidence.js +25 -0
  44. package/dist/application/JavaScriptRuntimeReconciliationService.js +27 -0
  45. package/dist/application/MacHopper.js +20 -4
  46. package/dist/application/ManagedApplicationGraphService.js +55 -0
  47. package/dist/application/ManagedMemberComparisonService.js +122 -0
  48. package/dist/application/ManagedNativeVerificationService.js +39 -0
  49. package/dist/application/ManagedReconstructionService.js +58 -0
  50. package/dist/application/ManagedRuntimeCorrelationService.js +103 -0
  51. package/dist/application/PermissionAuthority.js +1 -1
  52. package/dist/application/ProcessCaptureLifecycle.js +1 -1
  53. package/dist/application/ProcessHarness.js +1 -1
  54. package/dist/application/ProcessSampling.js +16 -12
  55. package/dist/application/ProjectPermissionStore.js +1 -0
  56. package/dist/application/SessionProviderRouter.js +219 -0
  57. package/dist/application/Setup.js +84 -60
  58. package/dist/application/SetupClients.js +1 -1
  59. package/dist/application/SetupPlan.js +9 -2
  60. package/dist/application/SupportedClients.js +40 -16
  61. package/dist/application/Upgrade.js +1 -1
  62. package/dist/application/runtime.js +11 -6
  63. package/dist/artifacts/AsarArtifactReader.js +23 -3
  64. package/dist/browser/CdpBrowserProvider.js +4 -2
  65. package/dist/browser/CdpCaptureEvents.js +49 -0
  66. package/dist/browser/CdpElectronInspection.js +106 -162
  67. package/dist/browser/CdpElectronProvider.js +9 -3
  68. package/dist/browser/CdpElectronScriptEvents.js +69 -0
  69. package/dist/browser/CdpElectronScripts.js +94 -0
  70. package/dist/browser/CdpElectronWorkers.js +56 -0
  71. package/dist/browser/CdpEndpoint.js +14 -1
  72. package/dist/browser/CdpPageCapture.js +8 -4
  73. package/dist/catalogIdentity.js +6 -42
  74. package/dist/cli.js +446 -34
  75. package/dist/cliApplicationCommands.js +62 -0
  76. package/dist/cliBrowserAdvancedCommands.js +5 -4
  77. package/dist/cliBrowserCommands.js +5 -4
  78. package/dist/cliCommandNames.js +56 -0
  79. package/dist/cliElectronCommands.js +106 -3
  80. package/dist/cliEvidenceCommands.js +4 -3
  81. package/dist/cliInvestigationCommands.js +2 -1
  82. package/dist/cliJsonInput.js +54 -0
  83. package/dist/cliPolicyCommands.js +2 -1
  84. package/dist/cliProcessCommands.js +3 -2
  85. package/dist/config.js +101 -2
  86. package/dist/contracts/applicationToolContracts.js +91 -0
  87. package/dist/contracts/artifactToolContracts.js +5 -9
  88. package/dist/contracts/browserToolContracts.js +14 -62
  89. package/dist/contracts/electronToolContracts.js +45 -19
  90. package/dist/contracts/enhancedInputs.js +2 -2
  91. package/dist/contracts/errorSchemas.js +1 -0
  92. package/dist/contracts/investigationExamples.js +0 -6
  93. package/dist/contracts/javascriptApplicationWorkflowExamples.js +46 -0
  94. package/dist/contracts/javascriptRuntimeReconciliationExample.js +208 -0
  95. package/dist/contracts/managedToolContracts.js +153 -0
  96. package/dist/contracts/managedWorkflowExamples.js +346 -0
  97. package/dist/contracts/managedWorkflowToolContracts.js +203 -0
  98. package/dist/contracts/nativeToolContracts.js +2 -6
  99. package/dist/contracts/promptContracts.js +18 -2
  100. package/dist/contracts/providerSelection.js +28 -0
  101. package/dist/contracts/sessionLifecycleInputs.js +2 -0
  102. package/dist/contracts/toolContractExamples.js +10 -25
  103. package/dist/contracts/toolContracts.js +69 -65
  104. package/dist/contracts/toolEffects.js +160 -0
  105. package/dist/contracts/toolOutputSchemas.js +152 -42
  106. package/dist/doctorRuntime.js +47 -0
  107. package/dist/domain/analysisProfile.js +78 -0
  108. package/dist/domain/analysisSnapshot.js +92 -46
  109. package/dist/domain/artifactComparison.js +3 -4
  110. package/dist/domain/artifactGraph.js +1 -0
  111. package/dist/domain/binaryTarget.js +4 -29
  112. package/dist/domain/browserObservation.js +3 -0
  113. package/dist/domain/bundleComparison.js +4 -4
  114. package/dist/domain/electronObservation.js +13 -0
  115. package/dist/domain/electronStaticAnalysis.js +9 -0
  116. package/dist/domain/electronStaticAnalysisBrowser.js +194 -0
  117. package/dist/domain/electronStaticAnalysisIpc.js +171 -0
  118. package/dist/domain/electronStaticAnalysisNative.js +164 -0
  119. package/dist/domain/electronStaticAnalysisTypes.js +1 -0
  120. package/dist/domain/electronStaticAnalysisValues.js +103 -0
  121. package/dist/domain/errors.js +148 -7
  122. package/dist/domain/evidence.js +44 -5
  123. package/dist/domain/evidenceBundle.js +9 -7
  124. package/dist/domain/functionComparison.js +9 -3
  125. package/dist/domain/functionComparisonNormalization.js +37 -0
  126. package/dist/domain/functionComparisonSchemas.js +3 -8
  127. package/dist/domain/functionDossierEvidence.js +4 -1
  128. package/dist/domain/hopperValues.js +66 -9
  129. package/dist/domain/inputIssueProjection.js +52 -0
  130. package/dist/domain/investigationWorkspace.js +2 -1
  131. package/dist/domain/javascriptApplicationAnalysis.js +155 -0
  132. package/dist/domain/javascriptApplicationChangeGraph.js +231 -0
  133. package/dist/domain/javascriptApplicationEvidenceSchemas.js +379 -0
  134. package/dist/domain/javascriptApplicationGraph.js +282 -0
  135. package/dist/domain/javascriptApplicationGraphSchemas.js +139 -0
  136. package/dist/domain/javascriptApplicationVersionComparison.js +116 -0
  137. package/dist/domain/javascriptApplicationVersionComparisonSchemas.js +139 -0
  138. package/dist/domain/javascriptApplicationVersionItems.js +221 -0
  139. package/dist/domain/javascriptApplicationVersionKeys.js +170 -0
  140. package/dist/domain/javascriptAstFingerprint.js +143 -0
  141. package/dist/domain/javascriptFeatureSeed.js +140 -0
  142. package/dist/domain/javascriptFeatureTrace.js +232 -0
  143. package/dist/domain/javascriptFeatureTraceSchemas.js +136 -0
  144. package/dist/domain/javascriptFeatureTraversal.js +88 -0
  145. package/dist/domain/javascriptNativeHandoff.js +85 -0
  146. package/dist/domain/javascriptReplay.js +361 -0
  147. package/dist/domain/javascriptRuntimeLoadState.js +106 -0
  148. package/dist/domain/javascriptRuntimeReconciliation.js +42 -0
  149. package/dist/domain/javascriptRuntimeReconciliationGraph.js +169 -0
  150. package/dist/domain/javascriptRuntimeReconciliationMatching.js +247 -0
  151. package/dist/domain/javascriptRuntimeReconciliationParsing.js +160 -0
  152. package/dist/domain/javascriptRuntimeReconciliationResult.js +119 -0
  153. package/dist/domain/javascriptRuntimeReconciliationRuntime.js +316 -0
  154. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +245 -0
  155. package/dist/domain/javascriptRuntimeStaticCandidates.js +191 -0
  156. package/dist/domain/javascriptStaticAnalysis.js +346 -0
  157. package/dist/domain/javascriptStaticAnalysisFindings.js +39 -0
  158. package/dist/domain/javascriptStaticAnalysisHelpers.js +274 -0
  159. package/dist/domain/javascriptStaticAnalysisState.js +23 -0
  160. package/dist/domain/javascriptStaticAnalysisTypes.js +1 -0
  161. package/dist/domain/managedApplicationGraph.js +556 -0
  162. package/dist/domain/managedArtifact.js +444 -0
  163. package/dist/domain/managedMemberComparison.js +565 -0
  164. package/dist/domain/managedNativeVerification.js +408 -0
  165. package/dist/domain/managedReconstruction.js +183 -0
  166. package/dist/domain/managedRuntimeCorrelation.js +175 -0
  167. package/dist/domain/reconstructionVerificationSchemas.js +1 -3
  168. package/dist/dotnet/ManagedArtifactInspector.js +318 -0
  169. package/dist/dotnet/ManagedMemberInspector.js +887 -0
  170. package/dist/dotnet/ManagedMetadataHeaps.js +131 -0
  171. package/dist/dotnet/ManagedMetadataInventory.js +368 -0
  172. package/dist/dotnet/ManagedMetadataLayout.js +322 -0
  173. package/dist/dotnet/ManagedNativeBoundaryInspector.js +391 -0
  174. package/dist/dotnet/ManagedPeReader.js +157 -0
  175. package/dist/dotnet/ManagedReaderFailure.js +10 -0
  176. package/dist/dotnet/ManagedStaticProvider.js +203 -0
  177. package/dist/generatedPackageMetadata.js +2 -2
  178. package/dist/ghidra/GhidraAnalysisProfile.js +37 -0
  179. package/dist/ghidra/GhidraClient.js +400 -0
  180. package/dist/ghidra/GhidraClientTypes.js +1 -0
  181. package/dist/ghidra/GhidraDefaults.js +20 -0
  182. package/dist/ghidra/GhidraDiagnostics.js +43 -0
  183. package/dist/ghidra/GhidraDoctor.js +59 -0
  184. package/dist/ghidra/GhidraFunctionValues.js +264 -0
  185. package/dist/ghidra/GhidraInstallation.js +239 -0
  186. package/dist/ghidra/GhidraInventoryValues.js +217 -0
  187. package/dist/ghidra/GhidraLauncher.js +139 -0
  188. package/dist/ghidra/GhidraProvider.js +366 -0
  189. package/dist/ghidra/GhidraRequestQueue.js +98 -0
  190. package/dist/ghidra/GhidraResponseBuffer.js +31 -0
  191. package/dist/ghidra/GhidraResponseRouter.js +24 -0
  192. package/dist/ghidra/GhidraSessionError.js +39 -0
  193. package/dist/ghidra/GhidraSessionValues.js +62 -0
  194. package/dist/ghidra/GhidraSocketConnection.js +46 -0
  195. package/dist/ghidra/protocol.js +69 -0
  196. package/dist/hopper/BridgeLauncher.js +19 -54
  197. package/dist/hopper/HopperAnalysisProfile.js +106 -0
  198. package/dist/hopper/HopperClient.js +154 -162
  199. package/dist/hopper/HopperProvider.js +99 -7
  200. package/dist/hopper/HopperSessionValues.js +27 -0
  201. package/dist/hopper/HopperSocketConnection.js +31 -0
  202. package/dist/main.js +14 -0
  203. package/dist/native/NativeMacOSProvider.js +3 -1
  204. package/dist/process/PendingOperations.js +59 -0
  205. package/dist/process/PrivateRuntimeRoot.js +33 -0
  206. package/dist/process/ProviderDeadline.js +95 -0
  207. package/dist/process/ProviderProcess.js +275 -0
  208. package/dist/replay/JavaScriptReplayWorker.js +286 -0
  209. package/dist/replay/LinuxJavaScriptReplayRunner.js +434 -0
  210. package/dist/replay/LinuxRuntimeClosure.js +46 -0
  211. package/dist/replay/LinuxSeccompPolicy.js +40 -0
  212. package/dist/replay/ReplayWorkerProtocol.js +55 -0
  213. package/dist/replay/SystemJavaScriptReplayHost.js +182 -0
  214. package/dist/server/createServer.js +53 -0
  215. package/dist/server/promptCompletion.js +9 -3
  216. package/dist/server/registerApplicationTools.js +115 -0
  217. package/dist/server/registerArtifactComparisonTool.js +16 -9
  218. package/dist/server/registerBrowserTools.js +33 -8
  219. package/dist/server/registerBundleComparisonTool.js +17 -20
  220. package/dist/server/registerElectronTools.js +45 -3
  221. package/dist/server/registerEnhancedTools.js +67 -19
  222. package/dist/server/registerEvidenceTools.js +5 -1
  223. package/dist/server/registerFunctionComparisonTool.js +14 -7
  224. package/dist/server/registerInvestigationTools.js +21 -17
  225. package/dist/server/registerManagedTools.js +6 -0
  226. package/dist/server/registerManagedWorkflowTools.js +277 -0
  227. package/dist/server/registerOfficialTools.js +11 -8
  228. package/dist/server/registerProcessComparisonTool.js +25 -47
  229. package/dist/server/registerSessionStatusTool.js +7 -7
  230. package/dist/server/registerSessionTools.js +57 -87
  231. package/dist/server/sessionEvidence.js +14 -19
  232. package/dist/server/toolInputValidation.js +77 -0
  233. package/dist/server/toolRegistrationOptions.js +79 -2
  234. package/dist/server/toolResult.js +25 -17
  235. package/package.json +17 -7
  236. package/scripts/rea.mjs +36 -2
  237. package/skills/rea-analysis/SKILL.md +59 -3
  238. /package/dist/{application → process}/ProcessOwnership.js +0 -0
@@ -0,0 +1,409 @@
1
+ import { addArtifactContainsEdge, addAstContainsEdge, addUnavailableStaticParseScope, artifactLocalIdentity, createElectronRoleNode, javascriptAnalysisCoverage, linkElectronRoleToAsset, moduleLookupKey, resolveArtifactPath, } from "./JavaScriptArtifactGraphContext.js";
2
+ import { artifactObservationEvidence, astObservationEvidence, completeReconstructionCoverage, staticInferenceEvidence, } from "./JavaScriptArtifactGraphEvidence.js";
3
+ /** Create the exact root artifact node from the inventory manifest. */
4
+ export const createJavaScriptArtifactRootNode = (accumulator, snapshot) => {
5
+ const root = snapshot.nodes.find(({ artifact_id: id }) => id === snapshot.manifest.root_artifact_id);
6
+ if (root === undefined)
7
+ throw new TypeError("Artifact inventory root is missing");
8
+ return accumulator.addNode({
9
+ kind: "artifact",
10
+ identity: {
11
+ strategy: "content-digest",
12
+ stability: "global-exact",
13
+ sha256: root.sha256,
14
+ },
15
+ observations: [
16
+ {
17
+ label: "artifact root",
18
+ properties: {
19
+ format: snapshot.manifest.root_format,
20
+ bytes: root.size,
21
+ inventory_manifest_id: snapshot.manifest.manifest_id,
22
+ inventory_graph_sha256: snapshot.manifest.graph_sha256,
23
+ inventory_artifact_id: root.artifact_id,
24
+ },
25
+ evidence: artifactObservationEvidence({
26
+ sha256: root.sha256,
27
+ path: "artifact-root",
28
+ operation: "inventory-root",
29
+ coverage: completeReconstructionCoverage(),
30
+ limitations: [
31
+ "artifact-root is a path-independent alias; the application result retains the canonical local input path.",
32
+ ],
33
+ }),
34
+ },
35
+ ],
36
+ });
37
+ };
38
+ /** Project nested ASAR containers inventoried inside a directory. */
39
+ export const addJavaScriptArtifactContainers = (context) => {
40
+ for (const container of context.fileSet.containers) {
41
+ const node = context.accumulator.addNode({
42
+ kind: "artifact",
43
+ identity: {
44
+ strategy: "content-digest",
45
+ stability: "global-exact",
46
+ sha256: container.sha256,
47
+ },
48
+ observations: [
49
+ {
50
+ label: container.path,
51
+ properties: containerProperties(container),
52
+ evidence: artifactObservationEvidence({
53
+ sha256: container.sha256,
54
+ path: container.path,
55
+ operation: "inventory-nested-asar",
56
+ coverage: completeReconstructionCoverage(),
57
+ }),
58
+ },
59
+ ],
60
+ });
61
+ context.containerNodes.set(container.sha256, node);
62
+ context.accumulator.addEdge({
63
+ source_node_id: context.root.node_id,
64
+ target_node_id: node.node_id,
65
+ relation: "contains",
66
+ properties: { path: container.path, format: "asar" },
67
+ evidence: artifactObservationEvidence({
68
+ sha256: context.snapshot.manifest.root_sha256,
69
+ path: container.path,
70
+ operation: "inventory-nested-asar",
71
+ coverage: completeReconstructionCoverage(),
72
+ }),
73
+ });
74
+ }
75
+ };
76
+ /** Project relevant files, ASAR entries, and explicit unavailable parse scopes. */
77
+ export const addJavaScriptArtifactFiles = (context) => {
78
+ for (const analyzed of context.analysis.files) {
79
+ const { file } = analyzed;
80
+ const target = createFileTarget(context, file, analyzed.javascript);
81
+ context.fileNodes.set(file.path, target);
82
+ if (file.kind === "javascript")
83
+ context.assetNodes.set(file.path, target);
84
+ const entry = createAsarEntry(context, file);
85
+ const parent = context.containerNodes.get(file.container_sha256) ?? context.root;
86
+ if (entry === undefined)
87
+ addArtifactContainsEdge(context, {
88
+ source: parent,
89
+ target,
90
+ file,
91
+ operation: "inventory-file",
92
+ });
93
+ else {
94
+ addArtifactContainsEdge(context, {
95
+ source: parent,
96
+ target: entry,
97
+ file,
98
+ operation: "inventory-entry",
99
+ });
100
+ context.accumulator.addEdge({
101
+ source_node_id: entry.node_id,
102
+ target_node_id: target.node_id,
103
+ relation: "maps_to",
104
+ properties: { sha256: file.sha256 },
105
+ evidence: artifactObservationEvidence({
106
+ sha256: file.container_sha256,
107
+ path: file.path,
108
+ operation: "map-entry-content",
109
+ coverage: completeReconstructionCoverage(),
110
+ }),
111
+ });
112
+ }
113
+ if (file.kind === "javascript" &&
114
+ (analyzed.javascript === null ||
115
+ analyzed.javascript.parse_status === "failed"))
116
+ addUnavailableStaticParseScope(context, {
117
+ file,
118
+ asset: target,
119
+ operation: "parse-javascript",
120
+ limitation: file.text.included
121
+ ? "JavaScript syntax could not be parsed."
122
+ : `JavaScript text was unavailable: ${file.text.reason}.`,
123
+ });
124
+ const packageValue = context.analysis.packages.find(({ path }) => path === file.path);
125
+ if (packageValue?.status !== undefined &&
126
+ packageValue.status !== "included")
127
+ addUnavailableStaticParseScope(context, {
128
+ file,
129
+ asset: target,
130
+ operation: "parse-package-json",
131
+ limitation: packageValue.limitation ?? "Package metadata could not be parsed.",
132
+ });
133
+ const sourceMap = context.analysis.source_maps.find(({ path }) => path === file.path);
134
+ if (sourceMap !== undefined &&
135
+ (sourceMap.status === "invalid" || sourceMap.status === "not-approved"))
136
+ addUnavailableStaticParseScope(context, {
137
+ file,
138
+ asset: target,
139
+ operation: "parse-local-source-map",
140
+ limitation: sourceMap.limitation ?? "Source-map content could not be parsed.",
141
+ });
142
+ }
143
+ };
144
+ /** Project package metadata and its declared Electron roles. */
145
+ export const addJavaScriptPackageNodes = (context) => {
146
+ const roots = [];
147
+ for (const packageValue of context.analysis.packages) {
148
+ const file = context.filesByPath.get(packageValue.path);
149
+ if (file === undefined)
150
+ continue;
151
+ const node = context.accumulator.addNode({
152
+ kind: "package",
153
+ identity: artifactLocalIdentity(file.sha256, "package-json", file.path),
154
+ observations: [
155
+ {
156
+ label: packageValue.name ?? file.path,
157
+ properties: {
158
+ path: file.path,
159
+ name: packageValue.name,
160
+ version: packageValue.version,
161
+ main: packageValue.main,
162
+ renderer: packageValue.renderer,
163
+ parse_status: packageValue.status,
164
+ },
165
+ evidence: artifactObservationEvidence({
166
+ sha256: file.sha256,
167
+ path: file.path,
168
+ operation: "parse-package-json",
169
+ coverage: completeReconstructionCoverage(),
170
+ limitations: packageValue.limitation === null ? [] : [packageValue.limitation],
171
+ }),
172
+ },
173
+ ],
174
+ });
175
+ if (roots.length === 0) {
176
+ roots.push(node);
177
+ context.accumulator.addEdge({
178
+ source_node_id: node.node_id,
179
+ target_node_id: context.root.node_id,
180
+ relation: "contains",
181
+ properties: { basis: "package-metadata-within-artifact" },
182
+ evidence: staticInferenceEvidence({
183
+ sha256: file.sha256,
184
+ path: file.path,
185
+ operation: "associate-package-artifact",
186
+ coverage: completeReconstructionCoverage(),
187
+ }),
188
+ });
189
+ }
190
+ else
191
+ addArtifactContainsEdge(context, {
192
+ source: context.root,
193
+ target: node,
194
+ file,
195
+ operation: "inventory-package",
196
+ });
197
+ addPackageRole(context, {
198
+ packageNode: node,
199
+ packageFile: file,
200
+ kind: "electron-main",
201
+ declaredPath: packageValue.main,
202
+ });
203
+ addPackageRole(context, {
204
+ packageNode: node,
205
+ packageFile: file,
206
+ kind: "electron-renderer",
207
+ declaredPath: packageValue.renderer,
208
+ });
209
+ }
210
+ return roots;
211
+ };
212
+ /** Project Webpack/Rspack chunk and factory literals recovered from AST. */
213
+ export const addJavaScriptBundlerNodes = (context) => {
214
+ for (const analyzed of context.analysis.files) {
215
+ const { file, javascript } = analyzed;
216
+ const asset = context.assetNodes.get(file.path);
217
+ if (javascript === null || asset === undefined)
218
+ continue;
219
+ const coverage = javascriptAnalysisCoverage(javascript, context.input);
220
+ for (const registration of javascript.bundler_registrations) {
221
+ const chunkKey = `${registration.runtime}:${registration.chunk_keys.join(",")}`;
222
+ const chunk = context.accumulator.addNode({
223
+ kind: "javascript-chunk",
224
+ identity: artifactLocalIdentity(file.sha256, "bundler-chunk", chunkKey),
225
+ observations: [
226
+ {
227
+ label: chunkKey,
228
+ properties: {
229
+ path: file.path,
230
+ bundler: registration.bundler,
231
+ runtime: registration.runtime,
232
+ chunk_keys: registration.chunk_keys,
233
+ omitted_chunk_keys: registration.omitted_chunk_keys,
234
+ unknown_chunk_keys: registration.unknown_chunk_keys,
235
+ module_count: registration.modules.length,
236
+ },
237
+ evidence: astObservationEvidence({
238
+ sha256: file.sha256,
239
+ path: file.path,
240
+ range: registration.location,
241
+ operation: "extract-bundler-registration",
242
+ coverage,
243
+ limitations: javascript.limitations,
244
+ }),
245
+ },
246
+ ],
247
+ });
248
+ addAstContainsEdge(context, {
249
+ source: asset,
250
+ target: chunk,
251
+ file,
252
+ range: registration.location,
253
+ coverage,
254
+ properties: { bundler: registration.bundler },
255
+ });
256
+ for (const moduleValue of registration.modules) {
257
+ const module = context.accumulator.addNode({
258
+ kind: "javascript-module",
259
+ identity: artifactLocalIdentity(file.sha256, `${registration.runtime}:module`, moduleValue.module_key),
260
+ observations: [
261
+ {
262
+ label: moduleValue.module_key,
263
+ properties: {
264
+ path: file.path,
265
+ bundler: registration.bundler,
266
+ runtime: registration.runtime,
267
+ module_key: moduleValue.module_key,
268
+ source_sha256: moduleValue.source_sha256,
269
+ structural_fingerprint_sha256: moduleValue.structural_fingerprint_sha256,
270
+ structural_fingerprint_algorithm: moduleValue.structural_fingerprint_algorithm,
271
+ structural_fingerprint_status: moduleValue.structural_fingerprint_status,
272
+ exports: moduleValue.exports,
273
+ exports_truncated: moduleValue.exports_truncated,
274
+ },
275
+ evidence: astObservationEvidence({
276
+ sha256: file.sha256,
277
+ path: file.path,
278
+ range: moduleValue.location,
279
+ operation: "extract-bundler-module",
280
+ coverage,
281
+ limitations: javascript.limitations,
282
+ }),
283
+ },
284
+ ],
285
+ });
286
+ context.moduleNodes.set(moduleLookupKey(file.path, moduleValue.module_key), module);
287
+ addAstContainsEdge(context, {
288
+ source: chunk,
289
+ target: module,
290
+ file,
291
+ range: moduleValue.location,
292
+ coverage,
293
+ properties: { module_key: moduleValue.module_key },
294
+ });
295
+ }
296
+ }
297
+ }
298
+ };
299
+ const createFileTarget = (context, file, javascript) => {
300
+ const kind = artifactFileNodeKind(file.kind);
301
+ return context.accumulator.addNode({
302
+ kind,
303
+ identity: {
304
+ strategy: "content-digest",
305
+ stability: "global-exact",
306
+ sha256: file.sha256,
307
+ },
308
+ observations: [
309
+ {
310
+ label: file.path,
311
+ properties: {
312
+ path: file.path,
313
+ bytes: file.bytes,
314
+ inventory_artifact_id: file.inventory_artifact_id,
315
+ unpacked: file.unpacked,
316
+ file_kind: file.kind,
317
+ text_status: file.text.included ? "included" : file.text.reason,
318
+ parse_status: javascript?.parse_status ?? null,
319
+ vendor_markers: javascript?.vendors ?? [],
320
+ },
321
+ evidence: artifactObservationEvidence({
322
+ sha256: file.sha256,
323
+ path: file.path,
324
+ operation: "inventory-relevant-file",
325
+ coverage: completeReconstructionCoverage(),
326
+ }),
327
+ },
328
+ ],
329
+ });
330
+ };
331
+ const artifactFileNodeKind = (kind) => kind === "javascript"
332
+ ? "javascript-asset"
333
+ : kind === "source-map"
334
+ ? "source-map"
335
+ : kind === "native-addon"
336
+ ? "native-addon"
337
+ : "artifact";
338
+ const createAsarEntry = (context, file) => {
339
+ const isAsar = context.snapshot.manifest.root_format === "asar" ||
340
+ file.container_sha256 !== context.snapshot.manifest.root_sha256;
341
+ if (!isAsar)
342
+ return undefined;
343
+ return context.accumulator.addNode({
344
+ kind: "asar-entry",
345
+ identity: {
346
+ strategy: "canonical-path",
347
+ stability: "artifact-version",
348
+ artifact_sha256: file.container_sha256,
349
+ path: file.path,
350
+ },
351
+ observations: [
352
+ {
353
+ label: file.path,
354
+ properties: {
355
+ entry_sha256: file.sha256,
356
+ bytes: file.bytes,
357
+ unpacked: file.unpacked,
358
+ inventory_artifact_id: file.inventory_artifact_id,
359
+ },
360
+ evidence: artifactObservationEvidence({
361
+ sha256: file.container_sha256,
362
+ path: file.path,
363
+ operation: "inventory-asar-entry",
364
+ coverage: completeReconstructionCoverage(),
365
+ }),
366
+ },
367
+ ],
368
+ });
369
+ };
370
+ const addPackageRole = (context, input) => {
371
+ if (input.declaredPath === null)
372
+ return;
373
+ const resolvedPath = resolveArtifactPath(input.declaredPath, input.packageFile.path, context.filesByPath);
374
+ const role = createElectronRoleNode(context, {
375
+ kind: input.kind,
376
+ anchor: input.packageFile,
377
+ declaredPath: input.declaredPath,
378
+ resolvedPath,
379
+ mechanism: input.kind === "electron-main"
380
+ ? "package.json:main"
381
+ : "package.json:renderer",
382
+ });
383
+ context.accumulator.addEdge({
384
+ source_node_id: input.packageNode.node_id,
385
+ target_node_id: role.node_id,
386
+ relation: "loads",
387
+ properties: {
388
+ declared_path: input.declaredPath,
389
+ resolved_path: resolvedPath,
390
+ },
391
+ evidence: staticInferenceEvidence({
392
+ sha256: input.packageFile.sha256,
393
+ path: input.packageFile.path,
394
+ operation: "discover-package-entrypoint",
395
+ coverage: completeReconstructionCoverage(),
396
+ }),
397
+ });
398
+ linkElectronRoleToAsset(context, {
399
+ role,
400
+ anchor: input.packageFile,
401
+ path: resolvedPath,
402
+ });
403
+ };
404
+ const containerProperties = (container) => ({
405
+ path: container.path,
406
+ format: "asar",
407
+ bytes: container.bytes,
408
+ inventory_artifact_id: container.inventory_artifact_id,
409
+ });
@@ -0,0 +1,77 @@
1
+ import { lstat, realpath } from "node:fs/promises";
2
+ import { performance } from "node:perf_hooks";
3
+ import { AsarArtifactReader } from "../artifacts/AsarArtifactReader.js";
4
+ import { ArtifactReaderFailure, } from "../artifacts/ArtifactReader.js";
5
+ import { DirectoryArtifactReader } from "../artifacts/DirectoryArtifactReader.js";
6
+ import { analyzeJavaScriptArtifactFiles } from "./JavaScriptArtifactAnalysis.js";
7
+ import { readJavaScriptArtifactFiles } from "./JavaScriptArtifactFiles.js";
8
+ import { buildJavaScriptArtifactGraph } from "./JavaScriptArtifactGraphBuilder.js";
9
+ import { artifactLimitsForReconstruction, javascriptArtifactReconstructionInputSchema, } from "./JavaScriptArtifactReconstructionInput.js";
10
+ import { scanCanonicalArtifactInventory } from "./ArtifactInventory.js";
11
+ import { summarizeElectronBoundaries } from "./ElectronBoundaryAnalysis.js";
12
+ /** Reconstruct one local ASAR or extracted directory without executing code. */
13
+ export const reconstructJavaScriptArtifact = async (rawInput, signal) => {
14
+ const input = javascriptArtifactReconstructionInputSchema.parse(rawInput);
15
+ abortIfNeeded(signal);
16
+ const path = await realpath(input.input_path);
17
+ const format = await resolveFormat(path, input);
18
+ const snapshot = await scanCanonicalArtifactInventory(path, artifactLimitsForReconstruction(input), signal);
19
+ if (snapshot.manifest.root_format !== format)
20
+ throw new ArtifactReaderFailure("format", `Artifact inventory classified ${path} as ${snapshot.manifest.root_format}, not ${format}`);
21
+ const reader = createReader(path, format);
22
+ try {
23
+ const files = await readJavaScriptArtifactFiles(reader, snapshot, input, signal);
24
+ const analysis = analyzeJavaScriptArtifactFiles(files, input, () => performance.now());
25
+ abortIfNeeded(signal);
26
+ const graph = buildJavaScriptArtifactGraph(snapshot, files, analysis, input);
27
+ return {
28
+ input_path: path,
29
+ format,
30
+ root_artifact_sha256: snapshot.manifest.root_sha256,
31
+ inventory_manifest_id: snapshot.manifest.manifest_id,
32
+ inventory_graph_sha256: snapshot.manifest.graph_sha256,
33
+ graph,
34
+ electron_summary: summarizeElectronBoundaries(analysis),
35
+ statistics: {
36
+ relevant_files: files.files.length,
37
+ nested_asar_containers: files.containers.length,
38
+ text_files_selected: files.text_files_selected,
39
+ text_bytes_read: files.text_bytes_read,
40
+ omitted_text_files: files.omitted_text_files,
41
+ limit_omitted_text_files: files.limit_omitted_text_files,
42
+ policy_filtered_text_files: files.policy_filtered_text_files,
43
+ invalid_utf8_files: files.invalid_utf8_files,
44
+ parsed_javascript_files: analysis.files.filter(({ javascript }) => javascript !== null).length,
45
+ visited_ast_nodes: analysis.visited_ast_nodes,
46
+ findings: analysis.findings,
47
+ modules: analysis.modules,
48
+ parse_failures: analysis.parse_failures,
49
+ truncated_scopes: analysis.truncated_scopes,
50
+ },
51
+ limitations: analysis.limitations,
52
+ };
53
+ }
54
+ finally {
55
+ await reader.close();
56
+ }
57
+ };
58
+ const resolveFormat = async (path, input) => {
59
+ const metadata = await lstat(path);
60
+ const observed = metadata.isDirectory()
61
+ ? "directory"
62
+ : metadata.isFile() && path.toLowerCase().endsWith(".asar")
63
+ ? "asar"
64
+ : undefined;
65
+ if (observed === undefined)
66
+ throw new ArtifactReaderFailure("format", `JavaScript artifact reconstruction accepts only a directory or .asar file: ${path}`);
67
+ if (input.format !== "auto" && input.format !== observed)
68
+ throw new ArtifactReaderFailure("format", `Requested ${input.format} input but observed ${observed}: ${path}`);
69
+ return observed;
70
+ };
71
+ const createReader = (path, format) => format === "asar"
72
+ ? new AsarArtifactReader(path)
73
+ : new DirectoryArtifactReader(path);
74
+ const abortIfNeeded = (signal) => {
75
+ if (signal?.aborted === true)
76
+ throw new ArtifactReaderFailure("cancelled", "JavaScript artifact reconstruction cancelled");
77
+ };
@@ -0,0 +1,18 @@
1
+ import { z } from "zod";
2
+ import { JAVASCRIPT_APPLICATION_ANALYSIS_DEFAULT_LIMITS, javascriptApplicationAnalysisLimitsSchema, } from "../domain/javascriptApplicationAnalysis.js";
3
+ /** Local ASAR/directory reconstruction request with explicit source-map authority. */
4
+ export const javascriptArtifactReconstructionInputSchema = z.strictObject({
5
+ input_path: z.string().min(1).max(16_384),
6
+ format: z.enum(["auto", "asar", "directory"]).default("auto"),
7
+ source_map_read_approved: z.boolean().default(false),
8
+ limits: javascriptApplicationAnalysisLimitsSchema.default(JAVASCRIPT_APPLICATION_ANALYSIS_DEFAULT_LIMITS),
9
+ });
10
+ /** Project reconstruction limits into the shared artifact traversal policy. */
11
+ export const artifactLimitsForReconstruction = (input) => ({
12
+ maxEntries: input.limits.max_entries,
13
+ maxTotalBytes: input.limits.max_total_artifact_bytes,
14
+ maxEntryBytes: input.limits.max_artifact_entry_bytes,
15
+ maxCompressionRatio: input.limits.max_compression_ratio,
16
+ maxDepth: input.limits.max_depth,
17
+ maxPathBytes: input.limits.max_path_bytes,
18
+ });