rea-agents 5.0.0 → 6.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 (275) hide show
  1. package/README.md +157 -650
  2. package/bridge/mitmproxy/capture.py +210 -0
  3. package/bridge/native/rea_lldb_tracer.py +303 -0
  4. package/bridge/process/ProcessRunTokenReader.swift +263 -0
  5. package/bridge/process/ProcessRunTokenReaderMain.swift +35 -0
  6. package/bridge/pwndbg/core_context.py +101 -0
  7. package/bridge/pwndbg/launch.py +39 -0
  8. package/bridge/pwndbg/launch_impl.py +34 -0
  9. package/bridge/pwntools/decoder_runtime.py +59 -0
  10. package/bridge/pwntools/layout.py +39 -0
  11. package/bridge/pwntools/layout_impl.py +309 -0
  12. package/bridge/pwntools/recorded_crash.py +39 -0
  13. package/bridge/pwntools/recorded_crash_impl.py +143 -0
  14. package/dist/android/JadxProvider.js +1 -0
  15. package/dist/application/CapabilityInventory.js +21 -0
  16. package/dist/application/DirectAnalysis.js +97 -23
  17. package/dist/application/EvidenceBundleFiles.js +1 -1
  18. package/dist/application/ReconstructionObligationCandidates.js +5 -1
  19. package/dist/application/WebNetworkCapturePort.js +1 -0
  20. package/dist/application/WebNetworkCaptureService.js +132 -0
  21. package/dist/application/WindowsCapabilities.js +1 -1
  22. package/dist/application/binary/AnalysisSnapshotCache.js +49 -6
  23. package/dist/application/binary/BinarySession.js +38 -10
  24. package/dist/application/binary/BinarySessionOpen.js +16 -3
  25. package/dist/application/binary/BinarySessionRecords.js +20 -0
  26. package/dist/application/binaryDiagnostics/BinaryLayoutPort.js +1 -0
  27. package/dist/application/binaryDiagnostics/BinaryLayoutService.js +57 -0
  28. package/dist/application/binaryDiagnostics/RecordedCrashPort.js +1 -0
  29. package/dist/application/binaryDiagnostics/RecordedCrashService.js +60 -0
  30. package/dist/application/evm/EvmInterfacePort.js +1 -0
  31. package/dist/application/evm/EvmInterfaceService.js +62 -0
  32. package/dist/application/javascript/JavaScriptApplicationEvidence.js +1 -2
  33. package/dist/application/javascript/JavaScriptApplicationService.js +15 -2
  34. package/dist/application/javascript/JavaScriptArtifactAnalysis.js +42 -23
  35. package/dist/application/javascript/JavaScriptArtifactGraphDocuments.js +26 -2
  36. package/dist/application/javascript/JavaScriptArtifactPathResolution.js +74 -24
  37. package/dist/application/javascript/JavaScriptArtifactReconstruction.js +23 -10
  38. package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +7 -7
  39. package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +145 -70
  40. package/dist/application/javascript/JavaScriptSemanticGraphChildProcessProjection.js +14 -15
  41. package/dist/application/javascript/JavaScriptSemanticGraphConstruction.js +41 -1
  42. package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +7 -7
  43. package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +5 -9
  44. package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +3 -3
  45. package/dist/application/javascript/JavaScriptSemanticGraphProjection.js +118 -12
  46. package/dist/application/javascript/JavaScriptSemanticGraphResourceProjection.js +3 -3
  47. package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +5 -5
  48. package/dist/application/{ProcessCli.js → process/ProcessCli.js} +10 -10
  49. package/dist/application/{ProcessEvidence.js → process/ProcessEvidence.js} +4 -4
  50. package/dist/artifacts/ArtifactProvider.js +30 -3
  51. package/dist/artifacts/ArtifactProviderMetadata.js +2 -1
  52. package/dist/artifacts/ZipArtifactReader.js +3 -0
  53. package/dist/artifacts/apple/DylibResolutionReader.js +259 -0
  54. package/dist/artifacts/apple/MachoLoadCommandReader.js +294 -0
  55. package/dist/{application → artifacts/extraction}/ArtifactExtraction.js +10 -10
  56. package/dist/{application → artifacts/inventory}/ArtifactGraphConstruction.js +3 -3
  57. package/dist/{application → artifacts/inventory}/ArtifactInventory.js +4 -4
  58. package/dist/{application/ArtifactInventory → artifacts/inventory}/classify.js +2 -2
  59. package/dist/{application/ArtifactInventory → artifacts/inventory}/reader.js +5 -5
  60. package/dist/{application/ArtifactInventory → artifacts/inventory}/scanCanonical.js +3 -3
  61. package/dist/{application/ArtifactInventory → artifacts/inventory}/scanReader.js +5 -5
  62. package/dist/artifacts/readStableArtifact.js +20 -4
  63. package/dist/browser/CdpCaptureEventHandlers.js +90 -2
  64. package/dist/browser/CdpCaptureEvents.js +9 -0
  65. package/dist/browser/PlaywrightElectronActiveProvider.js +12 -3
  66. package/dist/browser/history/CaptureFailures.js +101 -0
  67. package/dist/browser/history/CaptureFormatError.js +10 -0
  68. package/dist/browser/history/CaptureRedaction.js +65 -0
  69. package/dist/browser/history/CaptureRelease.js +12 -0
  70. package/dist/browser/history/HarCapture.js +165 -0
  71. package/dist/browser/history/HarCaptureAdapter.js +20 -0
  72. package/dist/browser/history/HarCaptureProcess.js +57 -0
  73. package/dist/browser/history/HarJson.js +91 -0
  74. package/dist/browser/history/HarSchema.js +72 -0
  75. package/dist/browser/history/HistoricalCaptureDecoder.js +186 -0
  76. package/dist/browser/history/HistoricalCaptureFormatAdapter.js +1 -0
  77. package/dist/browser/history/MitmproxyCaptureAdapter.js +42 -0
  78. package/dist/cli/artifactCommands.js +26 -1
  79. package/dist/cli/binaryDiagnosticsCommands.js +39 -0
  80. package/dist/cli/coreAnalysisCommands.js +2 -2
  81. package/dist/cli/coreBinaryCommands.js +8 -8
  82. package/dist/cli/electronCommands.js +16 -9
  83. package/dist/cli/evmCommands.js +24 -0
  84. package/dist/cli/firmwareCommands.js +6 -3
  85. package/dist/cli/javascriptApplicationAnalysis.js +16 -3
  86. package/dist/cli/jsonOutput.js +133 -0
  87. package/dist/cli/nativeCallCommands.js +35 -0
  88. package/dist/cli/processCommands.js +1 -1
  89. package/dist/cli/streamedJsonOutput.js +56 -0
  90. package/dist/cli/utilityCommands.js +2 -0
  91. package/dist/cli/webNetworkCaptureCommands.js +40 -0
  92. package/dist/cli.js +9 -3
  93. package/dist/cliBrowserScenarioCommands.js +2 -2
  94. package/dist/cliCommandNames.js +6 -0
  95. package/dist/cliJsonInput.js +30 -1
  96. package/dist/cliOutput.js +21 -6
  97. package/dist/composition/binaryDiagnostics.js +8 -0
  98. package/dist/composition/evm.js +4 -0
  99. package/dist/composition/webNetworkCaptures.js +6 -0
  100. package/dist/contracts/artifactToolContracts.js +6 -0
  101. package/dist/contracts/browserCaptureToolInputSchema.js +43 -0
  102. package/dist/contracts/browserToolContracts.js +4 -3
  103. package/dist/contracts/errorSchemas.js +8 -1
  104. package/dist/contracts/evm/evmToolContracts.js +20 -0
  105. package/dist/contracts/investigationExamples.js +2 -2
  106. package/dist/contracts/managed/managedToolContracts.js +7 -3
  107. package/dist/contracts/native/binaryDiagnosticsToolContracts.js +42 -0
  108. package/dist/contracts/native/nativeToolContracts.js +17 -1
  109. package/dist/contracts/officialToolContracts.js +12 -9
  110. package/dist/contracts/process/processCaptureExample.js +2 -0
  111. package/dist/contracts/sessionLifecycleInputs.js +22 -5
  112. package/dist/contracts/sessionStatusContract.js +10 -2
  113. package/dist/contracts/sessionToolContracts.js +8 -1
  114. package/dist/contracts/sessionToolSchemas.js +10 -3
  115. package/dist/contracts/toolContractExamples.js +1 -1
  116. package/dist/contracts/toolContracts.js +6 -0
  117. package/dist/contracts/toolEffects.js +30 -0
  118. package/dist/contracts/toolOutputSchemaGroups.js +5 -1
  119. package/dist/contracts/toolOutputSchemaPrimitives.js +1 -1
  120. package/dist/contracts/webNetworkCaptureToolContracts.js +24 -0
  121. package/dist/domain/analysisErrorBase.js +15 -0
  122. package/dist/domain/analysisErrorCore.js +59 -5
  123. package/dist/domain/analysisErrorPresentation.js +29 -1
  124. package/dist/domain/analysisErrorProjection.js +52 -2
  125. package/dist/domain/analysisSnapshot.js +166 -2
  126. package/dist/domain/apple/dyldPaths.js +81 -0
  127. package/dist/domain/apple/dylibResolution.js +367 -0
  128. package/dist/domain/apple/dylibResolutionFindings.js +75 -0
  129. package/dist/domain/artifactPathSyntax.js +1 -1
  130. package/dist/domain/browserObservation.js +1 -1
  131. package/dist/domain/browserObservationSchemas.js +13 -0
  132. package/dist/domain/browserScenarioValues.js +9 -2
  133. package/dist/domain/callPathSchemas.js +1 -1
  134. package/dist/domain/canonicalDigest.js +13 -1
  135. package/dist/domain/changedBehavior.js +3 -3
  136. package/dist/domain/comparisonStatus.js +2 -30
  137. package/dist/domain/conformanceTrustGate.js +0 -16
  138. package/dist/domain/evidence.js +17 -5
  139. package/dist/domain/evm/evmInterface.js +63 -0
  140. package/dist/domain/explicitSensitiveFailure.js +92 -0
  141. package/dist/domain/explicitSensitiveValues.js +10 -0
  142. package/dist/domain/firmware/firmwareAnalysis.js +8 -1
  143. package/dist/domain/javascript/electronActiveObservation.js +9 -4
  144. package/dist/domain/javascript/htmlArtifactReferences.js +40 -0
  145. package/dist/domain/javascript/javascriptExportShapeComparison.js +21 -5
  146. package/dist/domain/javascript/javascriptExportShapeVariants.js +0 -10
  147. package/dist/domain/javascript/javascriptSemanticGraph.js +21 -5
  148. package/dist/domain/jsonValue.js +4 -0
  149. package/dist/domain/localPath.js +2 -0
  150. package/dist/domain/native/binaryLayout.js +357 -0
  151. package/dist/domain/native/nativeCallObservation.js +164 -0
  152. package/dist/domain/native/objcSwiftMetadata.js +0 -39
  153. package/dist/domain/native/recordedCrash.js +266 -0
  154. package/dist/domain/native/recordedCrashNoteCoverage.js +73 -0
  155. package/dist/domain/{processCapture.js → process/processCapture.js} +139 -2
  156. package/dist/domain/{processCaptureExample.js → process/processCaptureExample.js} +5 -0
  157. package/dist/domain/process/processCaptureParsing.js +54 -0
  158. package/dist/domain/{processCaptureValidation.js → process/processCaptureValidation.js} +18 -2
  159. package/dist/domain/{processComparison.js → process/processComparison.js} +1 -1
  160. package/dist/domain/{processObservation.js → process/processObservation.js} +1 -1
  161. package/dist/domain/{processTraceSpecification.js → process/processTraceSpecification.js} +1 -1
  162. package/dist/domain/providerSelectionError.js +4 -2
  163. package/dist/domain/reconstructionVerification.js +3 -3
  164. package/dist/domain/reconstructionVerificationSchemas.js +1 -1
  165. package/dist/domain/residualUnknown.js +3 -2
  166. package/dist/domain/staticRuntimeCorrelation.js +3 -3
  167. package/dist/domain/webCaptureDiff.js +1 -0
  168. package/dist/domain/webNetworkCapture.js +118 -0
  169. package/dist/domain/webNetworkCaptureCoordinates.js +58 -0
  170. package/dist/dotnet/ManagedExceptionRegionValidation.js +41 -0
  171. package/dist/dotnet/ManagedMemberInspector.js +4 -2
  172. package/dist/dotnet/ManagedMemberInspectorCore.js +38 -32
  173. package/dist/dotnet/ManagedMemberInstructionDecoder.js +23 -7
  174. package/dist/dotnet/ManagedMemberRows.js +14 -3
  175. package/dist/dotnet/ManagedMetadataHeaps.js +20 -2
  176. package/dist/dotnet/ManagedMetadataInventory.js +38 -28
  177. package/dist/dotnet/ManagedMetadataInventoryRows.js +24 -10
  178. package/dist/dotnet/ManagedMethodBodyReader.js +7 -1
  179. package/dist/dotnet/ManagedNativeBoundaryHelpers.js +15 -3
  180. package/dist/dotnet/ManagedNativeBoundaryInspector.js +3 -1
  181. package/dist/dotnet/ManagedPeReader.js +11 -0
  182. package/dist/evm/EvmBytecodeCarrier.js +21 -0
  183. package/dist/evm/EvmWorkerLimits.js +40 -0
  184. package/dist/evm/EvmoleFailures.js +126 -0
  185. package/dist/evm/EvmoleInterfaceAdapter.js +53 -0
  186. package/dist/evm/EvmoleInterfaceProvider.js +273 -0
  187. package/dist/evm/EvmoleInterfaceWorker.js +87 -0
  188. package/dist/evm/EvmoleRelease.js +16 -0
  189. package/dist/firmware/FirmwareCommand.js +1 -0
  190. package/dist/generatedPackageMetadata.js +2 -2
  191. package/dist/ghidra/GhidraLauncher.js +1 -0
  192. package/dist/ghidra/GhidraProvider.js +2 -2
  193. package/dist/ghidra/GhidraProviderCapabilities.js +1 -1
  194. package/dist/hopper/BridgeLauncher.js +2 -0
  195. package/dist/hopper/LinuxPrivateDisplayProbe.js +4 -2
  196. package/dist/javascript/recovery/WakaruCommand.js +3 -0
  197. package/dist/javascript/sourceMaps/SourceMapCommand.js +1 -0
  198. package/dist/native/CommandRunner.js +2 -1
  199. package/dist/native/LldbCallTracer.js +278 -0
  200. package/dist/native/NativeCallObservation.js +135 -0
  201. package/dist/native/NativeMacOSProvider.js +19 -3
  202. package/dist/native/NativeMacOSProviderMetadata.js +8 -3
  203. package/dist/native/pwndbg/PwndbgCoreContext.js +160 -0
  204. package/dist/native/pwntools/PwntoolsDecoder.js +203 -0
  205. package/dist/native/pwntools/PwntoolsFailures.js +180 -0
  206. package/dist/native/pwntools/PwntoolsLayoutProvider.js +36 -0
  207. package/dist/native/pwntools/PwntoolsRecordedCrashProvider.js +75 -0
  208. package/dist/native/pwntools/PwntoolsRelease.js +19 -0
  209. package/dist/native/pwntools/PwntoolsResourceLimits.js +76 -0
  210. package/dist/native/pwntools/RecordedCrashSourceBindings.js +46 -0
  211. package/dist/native/pwntools/RecordedCrashStructureBindings.js +101 -0
  212. package/dist/process/DarwinProcessRunTokenReader.js +294 -0
  213. package/dist/process/OwnedCommand.js +113 -0
  214. package/dist/process/ProcessOwnership.js +263 -33
  215. package/dist/process/ProcessOwnershipObservation.js +161 -24
  216. package/dist/process/ProviderProcess.js +30 -3
  217. package/dist/{application → process/capture}/ProcessCaptureCapability.js +15 -0
  218. package/dist/{application → process/capture}/ProcessCaptureError.js +17 -1
  219. package/dist/process/capture/ProcessCaptureLifecycle.js +615 -0
  220. package/dist/{application → process/capture}/ProcessHarness.js +195 -29
  221. package/dist/{application → process/capture}/ProcessSampling.js +2 -2
  222. package/dist/server/createServer.js +22 -0
  223. package/dist/server/promptCompletion.js +10 -3
  224. package/dist/server/registerBinaryDiagnosticsTools.js +17 -0
  225. package/dist/server/registerEvidenceTools.js +1 -1
  226. package/dist/server/registerEvmTools.js +17 -0
  227. package/dist/server/registerProcessComparisonTool.js +1 -1
  228. package/dist/server/registerRecordedCrashTools.js +17 -0
  229. package/dist/server/registerSessionTools.js +2 -2
  230. package/dist/server/registerWebNetworkCaptureTool.js +28 -0
  231. package/dist/server/sessionAvailabilityPolicy.js +3 -0
  232. package/dist/server/sessionToolPolicies.js +1 -1
  233. package/dist/server/toolResult.js +1 -1
  234. package/native/windows/build/manifest.json +2 -2
  235. package/native/windows/build/rea-windows-x64.node +0 -0
  236. package/package.json +37 -9
  237. package/scripts/rea.mjs +11 -3
  238. package/skills/reverse-engineer-anything/SKILL.md +23 -3
  239. package/skills/reverse-engineer-anything/references/native-and-artifacts.md +29 -0
  240. package/third_party/README.md +60 -0
  241. package/third_party/evmole/LICENSE +21 -0
  242. package/third_party/evmole/README.md +22 -0
  243. package/third_party/pwndbg/LICENSE.md +21 -0
  244. package/third_party/pwndbg/README.md +23 -0
  245. package/third_party/pwntools/README.md +40 -0
  246. package/dist/application/AuthorizedArtifactInventory.js +0 -7
  247. package/dist/application/ProcessCaptureLifecycle.js +0 -299
  248. package/dist/application/StoreFileLock.js +0 -124
  249. package/dist/contracts/processCaptureExample.js +0 -2
  250. package/dist/domain/bytecodeProvider.js +0 -178
  251. package/dist/domain/customProtocolCapture.js +0 -137
  252. package/dist/domain/eventProcessTree.js +0 -225
  253. package/dist/domain/mobileApplicationInvestigation.js +0 -159
  254. package/dist/domain/packageAnalysis.js +0 -123
  255. package/dist/domain/peInspection.js +0 -197
  256. package/dist/domain/processCaptureParsing.js +0 -21
  257. package/dist/domain/protocolCapture.js +0 -217
  258. package/dist/domain/runtimeIdentification.js +0 -212
  259. package/dist/generatedMcpToolCatalog.js +0 -37
  260. /package/dist/application/{ArtifactExtractionDestination.js → artifacts/ArtifactExtractionDestination.js} +0 -0
  261. /package/dist/{application/ArtifactInventory → artifacts/inventory}/policy.js +0 -0
  262. /package/dist/{application/ArtifactInventory → artifacts/inventory}/types.js +0 -0
  263. /package/dist/domain/{processEvidenceProvider.js → process/processEvidenceProvider.js} +0 -0
  264. /package/dist/domain/{processScenario.js → process/processScenario.js} +0 -0
  265. /package/dist/domain/{processTraceComparison.js → process/processTraceComparison.js} +0 -0
  266. /package/dist/domain/{processTraceDimensionProjection.js → process/processTraceDimensionProjection.js} +0 -0
  267. /package/dist/domain/{processTraceEvaluation.js → process/processTraceEvaluation.js} +0 -0
  268. /package/dist/{application → process/capture}/FilesystemSnapshot.js +0 -0
  269. /package/dist/{application → process/capture}/ProcessCaptureEnvironment.js +0 -0
  270. /package/dist/{application → process/capture}/ProcessCaptureJournal.js +0 -0
  271. /package/dist/{application → process/capture}/ProcessFilesystemEffects.js +0 -0
  272. /package/dist/{application → process/capture}/ProcessNormalization.js +0 -0
  273. /package/dist/{application → process/capture}/ProcessScenarioRuntimeValidation.js +0 -0
  274. /package/dist/{application → process/capture}/ProcessTimer.js +0 -0
  275. /package/dist/{application → process/capture}/TerminalRenderer.js +0 -0
@@ -0,0 +1,57 @@
1
+ import { isAbsolute } from "node:path";
2
+ import { AnalysisCancelledError, AnalysisInputError, AnalysisOutputError, } from "../../domain/analysisErrorCore.js";
3
+ import { createEvidence } from "../../domain/evidence.js";
4
+ import { inspectBinaryLayoutInputSchema, binaryLayoutSchema, } from "../../domain/native/binaryLayout.js";
5
+ import { projectInputIssues } from "../../domain/inputIssueProjection.js";
6
+ import { err, ok } from "../../domain/result.js";
7
+ const OPERATION = "inspect_binary_layout";
8
+ /** Shared CLI/MCP validation and Evidence composition for offline layout inspection. */
9
+ export class BinaryLayoutService {
10
+ provider;
11
+ constructor(provider) {
12
+ this.provider = provider;
13
+ }
14
+ /** Bind complete observations to the caller-selected artifact before creating Evidence. */
15
+ async inspect(rawInput, options) {
16
+ if (options?.signal?.aborted)
17
+ return err(new AnalysisCancelledError(OPERATION));
18
+ const input = inspectBinaryLayoutInputSchema.safeParse(rawInput);
19
+ if (!input.success)
20
+ return err(new AnalysisInputError(OPERATION, { cause: input.error }, projectInputIssues(input.error.issues, rawInput)));
21
+ if (!isAbsolute(input.data.path))
22
+ return err(new AnalysisInputError(OPERATION, undefined, [
23
+ {
24
+ path: ["path"],
25
+ reason: "invalid_format",
26
+ message: "Expected an absolute filesystem path on this host.",
27
+ },
28
+ ]));
29
+ const inspected = await this.provider.inspect(input.data, options);
30
+ if (!inspected.ok)
31
+ return inspected;
32
+ const diagnostics = binaryLayoutSchema.shape.diagnostics.safeParse(inspected.value.diagnostics);
33
+ const outputOptions = diagnostics.success
34
+ ? { capturedOutput: diagnostics.data }
35
+ : undefined;
36
+ if (options?.signal?.aborted)
37
+ return err(new AnalysisCancelledError(OPERATION, outputOptions));
38
+ const report = binaryLayoutSchema.safeParse(inspected.value);
39
+ if (!report.success || report.data.artifact.path !== input.data.path)
40
+ return err(new AnalysisOutputError(OPERATION, "Binary layout provider returned malformed evidence or changed the selected artifact identity.", outputOptions));
41
+ const value = report.data;
42
+ return ok(createEvidence({
43
+ path: value.artifact.path,
44
+ format: "elf",
45
+ architecture: "x86_64",
46
+ sha256: value.artifact.sha256,
47
+ }, this.provider.identity, {
48
+ operation: OPERATION,
49
+ parameters: input.data,
50
+ result: value,
51
+ rawResult: value,
52
+ confidence: "observed",
53
+ limitations: value.limitations,
54
+ locations: [{ kind: "artifact-path", path: value.artifact.path }],
55
+ }));
56
+ }
57
+ }
@@ -0,0 +1,60 @@
1
+ import { isAbsolute } from "node:path";
2
+ import { AnalysisCancelledError, AnalysisInputError, AnalysisOutputError, } from "../../domain/analysisErrorCore.js";
3
+ import { createEvidence } from "../../domain/evidence.js";
4
+ import { inspectRecordedCrashInputSchema, recordedCrashSchema, } from "../../domain/native/recordedCrash.js";
5
+ import { projectInputIssues } from "../../domain/inputIssueProjection.js";
6
+ import { err, ok } from "../../domain/result.js";
7
+ const OPERATION = "inspect_recorded_crash";
8
+ /** Shared CLI/MCP validation and Evidence composition for recorded crash inspection. */
9
+ export class RecordedCrashService {
10
+ provider;
11
+ constructor(provider) {
12
+ this.provider = provider;
13
+ }
14
+ /** Bind complete observations to the caller-selected artifact before creating Evidence. */
15
+ async inspect(rawInput, options) {
16
+ if (options?.signal?.aborted)
17
+ return err(new AnalysisCancelledError(OPERATION));
18
+ const input = inspectRecordedCrashInputSchema.safeParse(rawInput);
19
+ if (!input.success)
20
+ return err(new AnalysisInputError(OPERATION, { cause: input.error }, projectInputIssues(input.error.issues, rawInput)));
21
+ if (!isAbsolute(input.data.path))
22
+ return err(new AnalysisInputError(OPERATION, undefined, [
23
+ {
24
+ path: ["path"],
25
+ reason: "invalid_format",
26
+ message: "Expected an absolute filesystem path on this host.",
27
+ },
28
+ ]));
29
+ const inspected = await this.provider.inspect(input.data, options);
30
+ if (!inspected.ok)
31
+ return inspected;
32
+ const diagnostics = recordedCrashSchema.shape.diagnostics.safeParse(inspected.value.diagnostics);
33
+ const outputOptions = diagnostics.success
34
+ ? { capturedOutput: diagnostics.data }
35
+ : undefined;
36
+ if (options?.signal?.aborted)
37
+ return err(new AnalysisCancelledError(OPERATION, outputOptions));
38
+ const report = recordedCrashSchema.safeParse(inspected.value);
39
+ if (!report.success ||
40
+ report.data.artifact.path !== input.data.path ||
41
+ (report.data.debugger.status === "available") !==
42
+ input.data.include_debugger_context)
43
+ return err(new AnalysisOutputError(OPERATION, "Recorded crash provider returned malformed evidence or changed the selected artifact identity.", outputOptions));
44
+ const value = report.data;
45
+ return ok(createEvidence({
46
+ path: value.artifact.path,
47
+ format: "elf",
48
+ architecture: "x86_64",
49
+ sha256: value.artifact.sha256,
50
+ }, this.provider.identity, {
51
+ operation: OPERATION,
52
+ parameters: input.data,
53
+ result: value,
54
+ rawResult: value,
55
+ confidence: value.debugger.status === "available" ? "derived" : "observed",
56
+ limitations: value.limitations,
57
+ locations: [{ kind: "artifact-path", path: value.artifact.path }],
58
+ }));
59
+ }
60
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,62 @@
1
+ import { isAbsolute } from "node:path";
2
+ import { z } from "zod";
3
+ import { AnalysisCancelledError, AnalysisInputError, AnalysisOutputError, } from "../../domain/analysisErrorCore.js";
4
+ import { createEvidence } from "../../domain/evidence.js";
5
+ import { inspectEvmInterfaceInputSchema, evmInterfaceSchema, } from "../../domain/evm/evmInterface.js";
6
+ import { projectInputIssues } from "../../domain/inputIssueProjection.js";
7
+ import { err, ok } from "../../domain/result.js";
8
+ const OPERATION = "inspect_evm_interface";
9
+ const diagnosticsSchema = z.object({
10
+ diagnostics: evmInterfaceSchema.shape.diagnostics,
11
+ });
12
+ /** Shared carrier validation and typed inline Evidence for CLI/MCP. */
13
+ export class EvmInterfaceService {
14
+ provider;
15
+ constructor(provider) {
16
+ this.provider = provider;
17
+ }
18
+ /** Preserve selected byte identity while clearly labeling recovered ABI candidates as inferences. */
19
+ async inspect(rawInput, options) {
20
+ if (options?.signal?.aborted)
21
+ return err(new AnalysisCancelledError(OPERATION));
22
+ const input = inspectEvmInterfaceInputSchema.safeParse(rawInput);
23
+ if (!input.success)
24
+ return err(new AnalysisInputError(OPERATION, { cause: input.error }, projectInputIssues(input.error.issues, rawInput)));
25
+ if (!isAbsolute(input.data.path))
26
+ return err(new AnalysisInputError(OPERATION, undefined, [
27
+ {
28
+ path: ["path"],
29
+ reason: "invalid_format",
30
+ message: "Expected an absolute filesystem path on this host.",
31
+ },
32
+ ]));
33
+ const inspected = await this.provider.inspect(input.data, options);
34
+ if (!inspected.ok)
35
+ return inspected;
36
+ const diagnostics = diagnosticsSchema.safeParse(inspected.value.result);
37
+ const outputOptions = diagnostics.success
38
+ ? { capturedOutput: diagnostics.data.diagnostics }
39
+ : undefined;
40
+ if (options?.signal?.aborted)
41
+ return err(new AnalysisCancelledError(OPERATION, outputOptions));
42
+ const execution = inspected.value;
43
+ const report = evmInterfaceSchema.safeParse(execution.result);
44
+ if (!report.success ||
45
+ report.data.artifact.path !== input.data.path ||
46
+ report.data.artifact.encoding !== input.data.encoding ||
47
+ execution.subject?.path !== input.data.path ||
48
+ execution.subject.sha256 !== report.data.artifact.sha256)
49
+ return err(new AnalysisOutputError(OPERATION, "Interface adapter returned malformed data or changed the selected carrier identity/encoding.", outputOptions));
50
+ return ok(createEvidence(execution.subject, execution.provider, {
51
+ operation: OPERATION,
52
+ parameters: input.data,
53
+ result: report.data,
54
+ ...(execution.rawResult === null
55
+ ? {}
56
+ : { rawResult: execution.rawResult }),
57
+ confidence: "inferred",
58
+ locations: execution.locations,
59
+ limitations: execution.limitations,
60
+ }));
61
+ }
62
+ }
@@ -1,5 +1,4 @@
1
1
  import { createEvidence, } from "../../domain/evidence.js";
2
- import { jsonValueSchema } from "../../domain/jsonValue.js";
3
2
  import { JAVASCRIPT_APPLICATION_PROVIDER } from "../InvestigationProviders.js";
4
3
  /** Create Evidence for one deterministic local JavaScript application graph. */
5
4
  export const createJavaScriptApplicationEvidence = (input, result) => createEvidence({
@@ -10,7 +9,7 @@ export const createJavaScriptApplicationEvidence = (input, result) => createEvid
10
9
  predicateType: "rea.javascript-application-analysis",
11
10
  operation: "analyze_javascript_application",
12
11
  parameters: parameters(input),
13
- result: jsonValueSchema.parse(result),
12
+ result,
14
13
  rawResult: null,
15
14
  confidence: "derived",
16
15
  authority: "shipped-artifact",
@@ -30,13 +30,26 @@ export const analyzeJavaScriptApplicationValidated = async (input, options = {})
30
30
  const reconstructed = await reconstructJavaScriptArtifact({
31
31
  input_path: input.input_path,
32
32
  format: input.format,
33
- }, options.signal);
33
+ }, options.signal, options.progress);
34
34
  const { electron_summary: summary, ...application } = reconstructed;
35
+ await options.progress?.report({
36
+ phase: "validate_javascript_application_result",
37
+ completed: 0,
38
+ total: 1,
39
+ message: "Validating the application analysis result",
40
+ });
35
41
  const result = javascriptApplicationAnalysisResultSchema.parse({
36
42
  ...application,
37
43
  summary,
38
44
  limitations: reconstructed.graph.limitations,
39
45
  });
46
+ await options.progress?.report({
47
+ phase: "create_javascript_application_evidence",
48
+ completed: 0,
49
+ total: 1,
50
+ message: "Creating and hashing application analysis Evidence",
51
+ });
52
+ const evidence = createJavaScriptApplicationEvidence(input, result);
40
53
  await options.progress?.report({
41
54
  phase: "analyze_javascript_application",
42
55
  completed: 1,
@@ -44,7 +57,7 @@ export const analyzeJavaScriptApplicationValidated = async (input, options = {})
44
57
  message: "Application graph and Electron boundaries reconstructed",
45
58
  terminal: true,
46
59
  });
47
- return ok(createJavaScriptApplicationEvidence(input, result));
60
+ return ok(evidence);
48
61
  }
49
62
  catch (cause) {
50
63
  if (cause instanceof ArtifactReaderFailure)
@@ -1,4 +1,5 @@
1
1
  import { createHash } from "node:crypto";
2
+ import { setImmediate } from "node:timers/promises";
2
3
  import { analyzeParsedJavaScriptStaticSource } from "../../domain/javascript/javascriptStaticAnalysis.js";
3
4
  import { analyzeParsedJavaScriptSemantics } from "../../domain/javascript/javascriptSemanticAnalysis.js";
4
5
  import { parseJavaScriptSource } from "../../domain/javascript/javascriptSourceParser.js";
@@ -6,10 +7,39 @@ import { hasValidSourceMapContents } from "../../domain/sourceMapContents.js";
6
7
  import { flattenSourceMapLeaves } from "../../domain/sourceMapEnvelope.js";
7
8
  import { failedJavaScriptStaticAnalysis } from "../../domain/javascript/javascriptStaticAnalysisHelpers.js";
8
9
  import { analyzeJavaScriptJsonModule } from "./JavaScriptJsonModules.js";
10
+ import { htmlArtifactReferences } from "../../domain/javascript/htmlArtifactReferences.js";
9
11
  /** Analyze every text source from the artifact without a result quota. */
10
- export const analyzeJavaScriptArtifactFiles = (fileSet) => {
12
+ export const analyzeJavaScriptArtifactFiles = (fileSet) => analyzeArtifactFiles(fileSet, (_file, ir) => ir);
13
+ /** Project each file's full IR immediately, retaining only later module facts. */
14
+ export const analyzeAndProjectJavaScriptArtifactFiles = async (fileSet, projectSemantics, beforeFile) => {
11
15
  const state = emptyArtifactAnalysis();
12
- const context = { state };
16
+ const projectFileSemantics = (file, ir) => {
17
+ projectSemantics(file, ir);
18
+ const programScopes = ir.scopes.filter(({ kind }) => kind === "program");
19
+ const programScopeId = programScopes[0]?.scopeId;
20
+ const localNames = new Set(ir.moduleLinks.map(({ localName }) => localName));
21
+ const callableIds = new Set(ir.moduleLinks.map(({ callableId }) => callableId));
22
+ return {
23
+ scopes: programScopes,
24
+ bindings: ir.bindings.filter(({ name, scopeId }) => scopeId === programScopeId && localNames.has(name)),
25
+ callables: ir.callables.filter(({ callableId }) => callableIds.has(callableId)),
26
+ moduleLinks: ir.moduleLinks,
27
+ coverage: ir.coverage,
28
+ limitations: ir.limitations,
29
+ };
30
+ };
31
+ const context = { state, projectSemantics: projectFileSemantics };
32
+ for (const [index, file] of fileSet.files.entries()) {
33
+ // Let progress, cancellation and garbage collection run between files.
34
+ await setImmediate();
35
+ await beforeFile?.(file, index, fileSet.files.length);
36
+ analyzeArtifactFile(file, context);
37
+ }
38
+ return finalizeArtifactAnalysis(state);
39
+ };
40
+ const analyzeArtifactFiles = (fileSet, projectSemantics) => {
41
+ const state = emptyArtifactAnalysis();
42
+ const context = { state, projectSemantics };
13
43
  for (const file of fileSet.files)
14
44
  analyzeArtifactFile(file, context);
15
45
  return finalizeArtifactAnalysis(state);
@@ -62,7 +92,9 @@ const analyzeArtifactFile = (file, context) => {
62
92
  state.files.push({
63
93
  file,
64
94
  javascript: analysis,
65
- semantic: semantics === null ? null : { ir: semantics },
95
+ semantic: semantics === null
96
+ ? null
97
+ : { ir: context.projectSemantics(file, semantics) },
66
98
  });
67
99
  state.visitedNodes += analysis.visited_ast_nodes;
68
100
  state.findings += staticFindings + (semantics?.moduleLinks.length ?? 0);
@@ -137,26 +169,13 @@ const unavailablePackage = (file, limitation) => ({
137
169
  limitation,
138
170
  });
139
171
  const parseHtmlScripts = (path, text) => {
140
- const scripts = [];
141
- const baseHref = htmlBaseHref(text);
142
- const pattern = /<script\b[^>]*\bsrc\s*=\s*(["'])([^"']+)\1[^>]*>/giu;
143
- for (const match of text.matchAll(pattern)) {
144
- const script = match[2];
145
- if (script === undefined)
146
- continue;
147
- const start = match.index;
148
- scripts.push({
149
- html_path: path,
150
- script_path: script,
151
- base_href: baseHref,
152
- location: rangeForOffsets(text, start, start + match[0].length),
153
- });
154
- }
155
- return scripts;
156
- };
157
- const htmlBaseHref = (text) => {
158
- const match = /<base\b[^>]*\bhref\s*=\s*(["'])([^"']+)\1[^>]*>/iu.exec(text);
159
- return match?.[2] ?? null;
172
+ const { scripts, baseHref } = htmlArtifactReferences(text);
173
+ return scripts.map(({ scriptPath, startOffset, endOffset }) => ({
174
+ html_path: path,
175
+ script_path: scriptPath,
176
+ base_href: baseHref,
177
+ location: rangeForOffsets(text, startOffset, endOffset),
178
+ }));
160
179
  };
161
180
  const parseSourceMap = (file) => {
162
181
  if (!file.text.included)
@@ -1,5 +1,5 @@
1
1
  import { addArtifactContainsEdge, addStaticInferenceEdge, createElectronRoleNode, linkElectronRoleToAsset, } from "./JavaScriptArtifactGraphContext.js";
2
- import { artifactObservationEvidence } from "./JavaScriptArtifactGraphEvidence.js";
2
+ import { artifactObservationEvidence, staticInferenceEvidence, } from "./JavaScriptArtifactGraphEvidence.js";
3
3
  import { completeApplicationCoverage } from "../../domain/javascript/javascriptApplicationEvidenceSchemas.js";
4
4
  import { resolveArtifactPathByContext } from "./JavaScriptArtifactPathResolution.js";
5
5
  /** Project HTML renderer entrypoints and their local script assets. */
@@ -46,8 +46,32 @@ export const addJavaScriptHtmlRoles = (context) => {
46
46
  htmlBaseHref: script.base_href,
47
47
  });
48
48
  const resolvedPath = resolution.resolved_path;
49
- if (resolvedPath === null)
49
+ if (resolvedPath === null) {
50
+ context.accumulator.addNode({
51
+ kind: role.kind,
52
+ identity: role.identity,
53
+ observations: [
54
+ {
55
+ label: script.script_path,
56
+ properties: {
57
+ mechanism: "html-script-reference",
58
+ script_path: script.script_path,
59
+ base_href: script.base_href,
60
+ ...resolution,
61
+ },
62
+ evidence: staticInferenceEvidence({
63
+ sha256: html.sha256,
64
+ path: html.path,
65
+ range: script.location,
66
+ operation: "resolve-html-script-reference",
67
+ coverage: completeApplicationCoverage(),
68
+ limitations: resolution.limitations,
69
+ }),
70
+ },
71
+ ],
72
+ });
50
73
  continue;
74
+ }
51
75
  const resolved = context.fileNodes.get(resolvedPath);
52
76
  if (resolved === undefined)
53
77
  continue;
@@ -14,16 +14,24 @@ const EXTENSIONS = [
14
14
  const NODE_BUILTINS = new Set(builtinModules.map((name) => name.replace(/^node:/u, "")));
15
15
  /** Resolve one declaration under its exact syntax/metadata context. */
16
16
  export const resolveArtifactPathByContext = (input) => resolvePackagePath(input, new Set());
17
- const resolvePackagePath = (input, packageChain, mode = "full") => {
17
+ const resolvePackagePath = (input, packageChain, mode = "full", exportsTargetUrl = false) => {
18
18
  const rejected = rejectDeclaration(input);
19
19
  if (rejected !== null)
20
20
  return rejected;
21
- const candidate = contextualCandidate(input);
21
+ const candidate = contextualCandidate(input, exportsTargetUrl);
22
22
  if (typeof candidate !== "string")
23
23
  return candidate;
24
24
  const confined = confineCandidate(input, candidate);
25
25
  if (typeof confined !== "string")
26
26
  return confined;
27
+ if (input.context === "html-reference")
28
+ return outcome(input, resolveFileCandidates(input, [confined]) ?? {
29
+ resolvedPath: null,
30
+ status: "not-found",
31
+ limitations: [
32
+ `The exact HTML resource ${confined} was not found among the selected application files.`,
33
+ ],
34
+ });
27
35
  const resolved = mode === "files-and-index"
28
36
  ? (resolveFileCandidates(input, [
29
37
  ...fileCandidates(confined),
@@ -48,10 +56,11 @@ const rejectDeclaration = (input) => {
48
56
  ]);
49
57
  return null;
50
58
  };
51
- const contextualCandidate = (input) => {
59
+ const contextualCandidate = (input, exportsTargetUrl) => {
52
60
  const { context } = input;
53
- const declared = context === "html-reference" ||
61
+ let declared = context === "html-reference" ||
54
62
  context === "url-reference" ||
63
+ exportsTargetUrl ||
55
64
  (context === "module-specifier" && input.moduleKind !== "require")
56
65
  ? stripQueryAndFragment(input.declaredPath)
57
66
  : input.declaredPath;
@@ -72,6 +81,23 @@ const contextualCandidate = (input) => {
72
81
  return unresolvedOutcome(input, "external", [
73
82
  "URL schemes and protocol-relative URLs are outside this local artifact path context.",
74
83
  ]);
84
+ // Exports targets use URL paths for both loaders; legacy main fields remain literal.
85
+ if (exportsTargetUrl ||
86
+ (context === "module-specifier" && input.moduleKind !== "require")) {
87
+ try {
88
+ declared = decodeURIComponent(declared);
89
+ }
90
+ catch (cause) {
91
+ void cause;
92
+ return unresolvedOutcome(input, "rejected", [
93
+ "The module URL path contains malformed percent encoding.",
94
+ ]);
95
+ }
96
+ if (declared.includes("\0"))
97
+ return unresolvedOutcome(input, "rejected", [
98
+ "The decoded module URL path contains NUL.",
99
+ ]);
100
+ }
75
101
  const relative = declared.startsWith("/") ? declared.slice(1) : declared;
76
102
  return declared.startsWith("/")
77
103
  ? relative
@@ -206,6 +232,12 @@ const resolveCandidate = (input, candidate, packageChain) => {
206
232
  `Directory package metadata ${packagePath} is not valid package JSON.`,
207
233
  ],
208
234
  };
235
+ if (main.status === "rejected")
236
+ return {
237
+ resolvedPath: null,
238
+ status: "rejected",
239
+ limitations: [`Package metadata ${packagePath}: ${main.limitation}`],
240
+ };
209
241
  if (main.status === "unmatched")
210
242
  return {
211
243
  resolvedPath: null,
@@ -242,7 +274,7 @@ const resolveCandidate = (input, candidate, packageChain) => {
242
274
  return index;
243
275
  }
244
276
  // Preserve recursive artifact package lookup only after legacy file/index fallbacks.
245
- return candidateOutcome(resolvePackagePath(entryInput, chain));
277
+ return candidateOutcome(resolvePackagePath(entryInput, chain, "full", main.source === "exports"));
246
278
  };
247
279
  const candidateOutcome = (nested) => nested.resolution_status === "resolved"
248
280
  ? {
@@ -299,23 +331,35 @@ const packageEntry = (text, moduleKind, useExports) => {
299
331
  }
300
332
  };
301
333
  const packageExport = (value, moduleKind) => {
302
- if (typeof value === "string")
303
- return packagePathValue(value);
304
- if (typeof value !== "object" || value === null || Array.isArray(value))
305
- return { status: "invalid" };
306
- const root = Reflect.get(value, ".") ?? value;
307
- if (typeof root === "string")
308
- return packagePathValue(root);
309
- if (typeof root !== "object" || root === null || Array.isArray(root))
310
- return { status: "invalid" };
334
+ const root = typeof value === "object" && value !== null && Object.hasOwn(value, ".")
335
+ ? Reflect.get(value, ".")
336
+ : value;
311
337
  const flattened = exportTargets(root, packageExportConditions(moduleKind));
312
338
  if (flattened.kind === "invalid")
313
- return { status: "invalid" };
339
+ return { status: "rejected", limitation: flattened.limitation };
314
340
  const first = flattened.kind === "unmatched" ? undefined : flattened.values[0];
315
341
  return first === undefined
316
- ? { status: "unmatched", declared: Object.keys(root) }
342
+ ? {
343
+ status: "unmatched",
344
+ declared: typeof root === "object" && root !== null ? Object.keys(root) : [],
345
+ }
317
346
  : { status: "value", value: first };
318
347
  };
348
+ const invalidExportTarget = (value, reason) => ({
349
+ kind: "invalid",
350
+ limitation: `The package exports target ${JSON.stringify(value) ?? String(value)} ${reason}.`,
351
+ });
352
+ // Node checks raw target segments before URL normalization. Compare encoded
353
+ // segment names here; full URL decoding follows array target selection.
354
+ const forbiddenExportSegment = (value) => value
355
+ .slice(2)
356
+ .split(/[\\/]/u)
357
+ .find((raw) => {
358
+ const segment = raw.replace(/%[0-9a-f]{2}/giu, (encoded) => String.fromCharCode(Number.parseInt(encoded.slice(1), 16)));
359
+ return (segment === "." ||
360
+ segment === ".." ||
361
+ segment.toLowerCase() === "node_modules");
362
+ });
319
363
  /**
320
364
  * Resolve a target in Node's declared order. Explicit null blocks an active
321
365
  * condition, whereas an unmatched nested object permits the next condition.
@@ -323,30 +367,36 @@ const packageExport = (value, moduleKind) => {
323
367
  * preserves the final invalid-versus-null refusal if no string is selected.
324
368
  */
325
369
  const exportTargets = (value, conditions) => {
326
- if (typeof value === "string")
327
- return value.startsWith("./")
370
+ if (typeof value === "string") {
371
+ if (!value.startsWith("./"))
372
+ return invalidExportTarget(value, 'must start with "./"');
373
+ const forbidden = forbiddenExportSegment(value);
374
+ return forbidden === undefined
328
375
  ? { kind: "targets", values: [value] }
329
- : { kind: "invalid" };
376
+ : invalidExportTarget(value, `contains forbidden path segment ${JSON.stringify(forbidden)} before URL normalization`);
377
+ }
330
378
  if (value === null)
331
379
  return { kind: "targets", values: [] };
332
380
  if (Array.isArray(value)) {
333
- let invalid = false;
381
+ let invalid = null;
334
382
  for (const entry of value) {
335
383
  const nested = exportTargets(entry, conditions);
336
384
  if (nested.kind === "invalid") {
337
- invalid = true;
385
+ invalid = nested.limitation;
338
386
  continue;
339
387
  }
340
388
  if (nested.kind === "unmatched")
341
389
  continue;
342
- invalid = false;
390
+ invalid = null;
343
391
  if (nested.values.length > 0)
344
392
  return nested;
345
393
  }
346
- return invalid ? { kind: "invalid" } : { kind: "targets", values: [] };
394
+ return invalid === null
395
+ ? { kind: "targets", values: [] }
396
+ : { kind: "invalid", limitation: invalid };
347
397
  }
348
398
  if (typeof value !== "object")
349
- return { kind: "invalid" };
399
+ return invalidExportTarget(value, "must be a relative string, object, array, or null");
350
400
  for (const [condition, target] of Object.entries(value)) {
351
401
  if (!conditions.has(condition))
352
402
  continue;
@@ -1,15 +1,18 @@
1
1
  import { lstat, realpath } from "node:fs/promises";
2
2
  import { ArtifactReaderFailure } from "../../artifacts/ArtifactReader.js";
3
3
  import { createJavaScriptArtifactReader as createReader } from "../../artifacts/javascript/JavaScriptArtifactReader.js";
4
- import { analyzeJavaScriptArtifactFiles } from "./JavaScriptArtifactAnalysis.js";
4
+ import { analyzeAndProjectJavaScriptArtifactFiles } from "./JavaScriptArtifactAnalysis.js";
5
5
  import { readJavaScriptArtifactFiles } from "../../artifacts/javascript/JavaScriptArtifactFiles.js";
6
6
  import { buildJavaScriptArtifactGraph } from "./JavaScriptArtifactGraphBuilder.js";
7
7
  import { javascriptArtifactReconstructionInputSchema, } from "./JavaScriptArtifactReconstructionInput.js";
8
- import { scanCanonicalArtifactInventory } from "../ArtifactInventory.js";
8
+ import { scanCanonicalArtifactInventory } from "../../artifacts/inventory/ArtifactInventory.js";
9
9
  import { summarizeElectronBoundaries } from "./ElectronBoundaryAnalysis.js";
10
- import { buildJavaScriptSemanticGraph } from "./JavaScriptSemanticGraphBuilder.js";
10
+ import { createJavaScriptSemanticGraphProjection } from "./JavaScriptSemanticGraphBuilder.js";
11
11
  /** Reconstruct one local ASAR or extracted directory without executing code. */
12
- export const reconstructJavaScriptArtifact = async (rawInput, signal) => {
12
+ export const reconstructJavaScriptArtifact = async (rawInput, signal, progress) => {
13
+ const reportPhase = async (phase, message) => {
14
+ await progress?.report({ phase, completed: 0, total: 1, message });
15
+ };
13
16
  const input = javascriptArtifactReconstructionInputSchema.parse(rawInput);
14
17
  abortIfNeeded(signal);
15
18
  const path = await realpath(input.input_path);
@@ -19,15 +22,25 @@ export const reconstructJavaScriptArtifact = async (rawInput, signal) => {
19
22
  throw new ArtifactReaderFailure("format", `Artifact inventory classified ${path} as ${snapshot.manifest.root_format}, not ${format}`);
20
23
  const reader = createReader(path, format);
21
24
  try {
25
+ await reportPhase("read_javascript_artifacts", "Reading inventoried JavaScript application sources");
22
26
  const files = await readJavaScriptArtifactFiles(reader, snapshot, signal);
23
- const analysis = analyzeJavaScriptArtifactFiles(files);
27
+ await reportPhase("parse_javascript_sources", `Parsing and projecting ${String(files.files.length)} application source files`);
28
+ const semanticProjection = createJavaScriptSemanticGraphProjection();
29
+ const analysis = await analyzeAndProjectJavaScriptArtifactFiles(files, semanticProjection.projectFile, async (file, completed, total) => {
30
+ abortIfNeeded(signal);
31
+ await progress?.report({
32
+ phase: "parse_javascript_source",
33
+ completed: 0,
34
+ total: 1,
35
+ message: `Parsing and projecting ${file.path} (${String(completed + 1)}/${String(total)})`,
36
+ });
37
+ abortIfNeeded(signal);
38
+ });
24
39
  abortIfNeeded(signal);
40
+ await reportPhase("build_javascript_application_graph", "Constructing application and Electron boundary relationships");
25
41
  const graph = buildJavaScriptArtifactGraph(snapshot, files, analysis);
26
- const semanticGraph = buildJavaScriptSemanticGraph({
27
- rootArtifactSha256: snapshot.manifest.root_sha256,
28
- applicationGraph: graph,
29
- analysis,
30
- });
42
+ await reportPhase("build_javascript_semantic_graph", "Binding and validating static semantic relationships");
43
+ const semanticGraph = semanticProjection.finish(snapshot.manifest.root_sha256, graph, analysis);
31
44
  return {
32
45
  input_path: path,
33
46
  format,