rea-agents 1.7.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 (156) hide show
  1. package/README.md +38 -31
  2. package/dist/application/CapabilityInventory.js +18 -0
  3. package/dist/application/CrossVersionInvestigation.js +10 -6
  4. package/dist/application/Doctor.js +56 -6
  5. package/dist/application/ElectronBoundaryAnalysis.js +96 -0
  6. package/dist/application/ElectronBoundaryGraph.js +9 -0
  7. package/dist/application/ElectronBoundaryGraphContext.js +62 -0
  8. package/dist/application/ElectronBoundaryGraphIpc.js +242 -0
  9. package/dist/application/ElectronBoundaryGraphNative.js +86 -0
  10. package/dist/application/ElectronBoundaryGraphWindows.js +199 -0
  11. package/dist/application/EnhancedTools.js +38 -13
  12. package/dist/application/InvestigationProviders.js +30 -0
  13. package/dist/application/JavaScriptApplicationEvidence.js +26 -0
  14. package/dist/application/JavaScriptApplicationEvidenceGraph.js +89 -0
  15. package/dist/application/JavaScriptApplicationService.js +74 -0
  16. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +29 -0
  17. package/dist/application/JavaScriptApplicationWorkflowService.js +90 -0
  18. package/dist/application/JavaScriptArtifactAnalysis.js +7 -1
  19. package/dist/application/JavaScriptArtifactGraphBuilder.js +59 -16
  20. package/dist/application/JavaScriptArtifactGraphEvidence.js +24 -14
  21. package/dist/application/JavaScriptArtifactReconstruction.js +3 -0
  22. package/dist/application/JavaScriptArtifactReconstructionInput.js +2 -83
  23. package/dist/application/JavaScriptReplayPlanning.js +201 -0
  24. package/dist/application/JavaScriptReplayService.js +266 -0
  25. package/dist/application/JavaScriptRuntimeReconciliationEvidence.js +25 -0
  26. package/dist/application/JavaScriptRuntimeReconciliationService.js +27 -0
  27. package/dist/application/ManagedApplicationGraphService.js +55 -0
  28. package/dist/application/ManagedMemberComparisonService.js +122 -0
  29. package/dist/application/ManagedNativeVerificationService.js +39 -0
  30. package/dist/application/ManagedReconstructionService.js +58 -0
  31. package/dist/application/ManagedRuntimeCorrelationService.js +103 -0
  32. package/dist/application/PermissionAuthority.js +1 -1
  33. package/dist/application/ProcessSampling.js +15 -11
  34. package/dist/application/ProjectPermissionStore.js +1 -0
  35. package/dist/application/runtime.js +2 -0
  36. package/dist/browser/CdpCaptureEvents.js +49 -0
  37. package/dist/browser/CdpElectronInspection.js +106 -162
  38. package/dist/browser/CdpElectronProvider.js +5 -1
  39. package/dist/browser/CdpElectronScriptEvents.js +69 -0
  40. package/dist/browser/CdpElectronScripts.js +94 -0
  41. package/dist/browser/CdpElectronWorkers.js +56 -0
  42. package/dist/browser/CdpPageCapture.js +8 -4
  43. package/dist/catalogIdentity.js +4 -1
  44. package/dist/cli.js +388 -0
  45. package/dist/cliApplicationCommands.js +62 -0
  46. package/dist/cliCommandNames.js +13 -0
  47. package/dist/cliElectronCommands.js +103 -1
  48. package/dist/cliJsonInput.js +54 -0
  49. package/dist/config.js +83 -0
  50. package/dist/contracts/applicationToolContracts.js +91 -0
  51. package/dist/contracts/artifactToolContracts.js +5 -9
  52. package/dist/contracts/browserToolContracts.js +14 -62
  53. package/dist/contracts/electronToolContracts.js +45 -19
  54. package/dist/contracts/errorSchemas.js +1 -0
  55. package/dist/contracts/investigationExamples.js +0 -6
  56. package/dist/contracts/javascriptApplicationWorkflowExamples.js +46 -0
  57. package/dist/contracts/javascriptRuntimeReconciliationExample.js +208 -0
  58. package/dist/contracts/managedToolContracts.js +153 -0
  59. package/dist/contracts/managedWorkflowExamples.js +346 -0
  60. package/dist/contracts/managedWorkflowToolContracts.js +203 -0
  61. package/dist/contracts/nativeToolContracts.js +2 -6
  62. package/dist/contracts/promptContracts.js +18 -2
  63. package/dist/contracts/toolContractExamples.js +10 -25
  64. package/dist/contracts/toolContracts.js +47 -45
  65. package/dist/contracts/toolEffects.js +160 -0
  66. package/dist/contracts/toolOutputSchemas.js +46 -31
  67. package/dist/doctorRuntime.js +42 -1
  68. package/dist/domain/artifactComparison.js +3 -4
  69. package/dist/domain/browserObservation.js +3 -0
  70. package/dist/domain/bundleComparison.js +4 -4
  71. package/dist/domain/electronObservation.js +13 -0
  72. package/dist/domain/electronStaticAnalysis.js +9 -0
  73. package/dist/domain/electronStaticAnalysisBrowser.js +194 -0
  74. package/dist/domain/electronStaticAnalysisIpc.js +171 -0
  75. package/dist/domain/electronStaticAnalysisNative.js +164 -0
  76. package/dist/domain/electronStaticAnalysisTypes.js +1 -0
  77. package/dist/domain/electronStaticAnalysisValues.js +103 -0
  78. package/dist/domain/errors.js +67 -1
  79. package/dist/domain/functionComparisonSchemas.js +3 -8
  80. package/dist/domain/inputIssueProjection.js +52 -0
  81. package/dist/domain/javascriptApplicationAnalysis.js +155 -0
  82. package/dist/domain/javascriptApplicationChangeGraph.js +231 -0
  83. package/dist/domain/javascriptApplicationEvidenceSchemas.js +18 -0
  84. package/dist/domain/javascriptApplicationGraph.js +2 -1
  85. package/dist/domain/javascriptApplicationGraphSchemas.js +7 -0
  86. package/dist/domain/javascriptApplicationVersionComparison.js +116 -0
  87. package/dist/domain/javascriptApplicationVersionComparisonSchemas.js +139 -0
  88. package/dist/domain/javascriptApplicationVersionItems.js +221 -0
  89. package/dist/domain/javascriptApplicationVersionKeys.js +170 -0
  90. package/dist/domain/javascriptFeatureSeed.js +140 -0
  91. package/dist/domain/javascriptFeatureTrace.js +232 -0
  92. package/dist/domain/javascriptFeatureTraceSchemas.js +136 -0
  93. package/dist/domain/javascriptFeatureTraversal.js +88 -0
  94. package/dist/domain/javascriptNativeHandoff.js +85 -0
  95. package/dist/domain/javascriptReplay.js +361 -0
  96. package/dist/domain/javascriptRuntimeLoadState.js +106 -0
  97. package/dist/domain/javascriptRuntimeReconciliation.js +42 -0
  98. package/dist/domain/javascriptRuntimeReconciliationGraph.js +169 -0
  99. package/dist/domain/javascriptRuntimeReconciliationMatching.js +247 -0
  100. package/dist/domain/javascriptRuntimeReconciliationParsing.js +160 -0
  101. package/dist/domain/javascriptRuntimeReconciliationResult.js +119 -0
  102. package/dist/domain/javascriptRuntimeReconciliationRuntime.js +316 -0
  103. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +245 -0
  104. package/dist/domain/javascriptRuntimeStaticCandidates.js +191 -0
  105. package/dist/domain/javascriptStaticAnalysis.js +31 -43
  106. package/dist/domain/javascriptStaticAnalysisFindings.js +39 -0
  107. package/dist/domain/javascriptStaticAnalysisHelpers.js +10 -0
  108. package/dist/domain/javascriptStaticAnalysisState.js +6 -0
  109. package/dist/domain/managedApplicationGraph.js +556 -0
  110. package/dist/domain/managedArtifact.js +444 -0
  111. package/dist/domain/managedMemberComparison.js +565 -0
  112. package/dist/domain/managedNativeVerification.js +408 -0
  113. package/dist/domain/managedReconstruction.js +183 -0
  114. package/dist/domain/managedRuntimeCorrelation.js +175 -0
  115. package/dist/domain/reconstructionVerificationSchemas.js +1 -3
  116. package/dist/dotnet/ManagedArtifactInspector.js +318 -0
  117. package/dist/dotnet/ManagedMemberInspector.js +887 -0
  118. package/dist/dotnet/ManagedMetadataHeaps.js +131 -0
  119. package/dist/dotnet/ManagedMetadataInventory.js +368 -0
  120. package/dist/dotnet/ManagedMetadataLayout.js +322 -0
  121. package/dist/dotnet/ManagedNativeBoundaryInspector.js +391 -0
  122. package/dist/dotnet/ManagedPeReader.js +157 -0
  123. package/dist/dotnet/ManagedReaderFailure.js +10 -0
  124. package/dist/dotnet/ManagedStaticProvider.js +203 -0
  125. package/dist/generatedPackageMetadata.js +2 -2
  126. package/dist/ghidra/GhidraProvider.js +6 -0
  127. package/dist/main.js +14 -0
  128. package/dist/replay/JavaScriptReplayWorker.js +286 -0
  129. package/dist/replay/LinuxJavaScriptReplayRunner.js +434 -0
  130. package/dist/replay/LinuxRuntimeClosure.js +46 -0
  131. package/dist/replay/LinuxSeccompPolicy.js +40 -0
  132. package/dist/replay/ReplayWorkerProtocol.js +55 -0
  133. package/dist/replay/SystemJavaScriptReplayHost.js +182 -0
  134. package/dist/server/createServer.js +52 -0
  135. package/dist/server/registerApplicationTools.js +115 -0
  136. package/dist/server/registerArtifactComparisonTool.js +16 -9
  137. package/dist/server/registerBrowserTools.js +33 -8
  138. package/dist/server/registerBundleComparisonTool.js +17 -20
  139. package/dist/server/registerElectronTools.js +45 -3
  140. package/dist/server/registerEnhancedTools.js +58 -13
  141. package/dist/server/registerEvidenceTools.js +5 -1
  142. package/dist/server/registerFunctionComparisonTool.js +14 -7
  143. package/dist/server/registerInvestigationTools.js +21 -17
  144. package/dist/server/registerManagedTools.js +6 -0
  145. package/dist/server/registerManagedWorkflowTools.js +277 -0
  146. package/dist/server/registerOfficialTools.js +8 -8
  147. package/dist/server/registerProcessComparisonTool.js +25 -47
  148. package/dist/server/registerSessionStatusTool.js +7 -7
  149. package/dist/server/registerSessionTools.js +51 -86
  150. package/dist/server/sessionEvidence.js +14 -19
  151. package/dist/server/toolInputValidation.js +77 -0
  152. package/dist/server/toolRegistrationOptions.js +79 -2
  153. package/dist/server/toolResult.js +25 -17
  154. package/package.json +12 -4
  155. package/scripts/rea.mjs +1 -1
  156. package/skills/rea-analysis/SKILL.md +59 -3
@@ -0,0 +1,203 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readFile, stat } from "node:fs/promises";
3
+ import { createAnalysisExecution, } from "../application/AnalysisProvider.js";
4
+ import { MANAGED_STATIC_PROVIDER } from "../application/InvestigationProviders.js";
5
+ import { MANAGED_TOOL_CONTRACTS, managedArtifactInputSchema, managedMemberInputSchema, managedNativeBoundaryInputSchema, } from "../contracts/managedToolContracts.js";
6
+ import { AnalysisCancelledError, AnalysisCapabilityUnavailableError, EvidenceIntegrityError, ProviderAdapterError, } from "../domain/errors.js";
7
+ import { err, ok } from "../domain/result.js";
8
+ import { inspectManagedArtifactBytes } from "./ManagedArtifactInspector.js";
9
+ import { inspectManagedMembersBytes } from "./ManagedMemberInspector.js";
10
+ import { inspectManagedNativeBoundariesBytes } from "./ManagedNativeBoundaryInspector.js";
11
+ const IDENTITY = Object.freeze(MANAGED_STATIC_PROVIDER);
12
+ /** Execution-free managed PE/CLI auxiliary provider. */
13
+ export class ManagedStaticProvider {
14
+ #capabilities = Object.freeze(MANAGED_TOOL_CONTRACTS.map((contract) => Object.freeze({
15
+ provider: IDENTITY,
16
+ operation: contract.name,
17
+ inputContractVersion: 1,
18
+ outputContractVersion: 1,
19
+ available: true,
20
+ reason: null,
21
+ pagination: "offset",
22
+ exhaustive: false,
23
+ effects: Object.freeze({
24
+ mutatesArtifact: false,
25
+ launchesProcess: false,
26
+ mayShowUi: false,
27
+ mayAccessNetwork: false,
28
+ mayWriteFilesystem: false,
29
+ changesPermissions: false,
30
+ requiresRoot: false,
31
+ }),
32
+ limits: Object.freeze({
33
+ maxResults: 500,
34
+ maxPayloadBytes: 4 * 1024 * 1024,
35
+ timeoutMs: null,
36
+ }),
37
+ limitations: limitationsFor(contract.name),
38
+ })));
39
+ identity() {
40
+ return IDENTITY;
41
+ }
42
+ capabilities() {
43
+ return this.#capabilities;
44
+ }
45
+ createClient(target) {
46
+ return new ManagedStaticClient(target);
47
+ }
48
+ }
49
+ class ManagedStaticClient {
50
+ target;
51
+ constructor(target) {
52
+ this.target = target;
53
+ }
54
+ async execute(operation, parameters, options) {
55
+ if (operation === "health")
56
+ return ok(createAnalysisExecution(null, IDENTITY));
57
+ if (!isManagedOperation(operation))
58
+ return err(new AnalysisCapabilityUnavailableError(IDENTITY.id, operation, "Operation is not implemented by the managed static provider."));
59
+ if (this.target.format !== "pe")
60
+ return err(new AnalysisCapabilityUnavailableError(IDENTITY.id, operation, `Managed static triage requires a PE target; observed ${this.target.format}.`));
61
+ try {
62
+ if (options?.signal?.aborted === true)
63
+ return err(new AnalysisCancelledError(operation));
64
+ const maxFileBytes = maxRequestedFileBytes(operation, parameters);
65
+ const metadata = await stat(this.target.path);
66
+ if (metadata.size > maxFileBytes)
67
+ return err(new AnalysisCapabilityUnavailableError(IDENTITY.id, operation, `Artifact size ${String(metadata.size)} exceeds max_file_bytes ${String(maxFileBytes)}.`));
68
+ const bytes = await readFile(this.target.path, options?.signal === undefined ? undefined : { signal: options.signal });
69
+ if (bytes.length > maxFileBytes)
70
+ return err(new AnalysisCapabilityUnavailableError(IDENTITY.id, operation, `Artifact grew beyond max_file_bytes ${String(maxFileBytes)} while it was read.`));
71
+ const observedDigest = createHash("sha256").update(bytes).digest("hex");
72
+ if (observedDigest !== this.target.sha256)
73
+ return err(new EvidenceIntegrityError(`Managed artifact digest changed after open: expected ${this.target.sha256}, observed ${observedDigest} at ${this.target.path}`));
74
+ const result = inspectManagedOperation(operation, parameters, bytes, this.target);
75
+ return ok(createAnalysisExecution(result, IDENTITY, {
76
+ rawResult: null,
77
+ limitations: result.limitations,
78
+ subject: this.target,
79
+ locations: managedLocations(result),
80
+ }));
81
+ }
82
+ catch (cause) {
83
+ if (options?.signal?.aborted === true)
84
+ return err(new AnalysisCancelledError(operation));
85
+ return err(new ProviderAdapterError(IDENTITY.id, operation, { cause }));
86
+ }
87
+ }
88
+ close() {
89
+ return Promise.resolve();
90
+ }
91
+ }
92
+ const isManagedOperation = (operation) => MANAGED_TOOL_CONTRACTS.some(({ name }) => name === operation);
93
+ const limitationsFor = (operation) => Object.freeze(operation === "inspect_managed_artifact"
94
+ ? [
95
+ "This capability inventories PE/CLI identity only; inspect_managed_members admits bounded metadata members, signatures, and CIL anchors.",
96
+ "It never loads the target assembly, resolves dependencies through a CLR, decompiles C#, or executes target code.",
97
+ ]
98
+ : operation === "inspect_managed_native_boundaries"
99
+ ? [
100
+ "This capability inventories managed declarations for native boundaries only; native exports, thunks, and addresses require separate native-provider evidence.",
101
+ "It never loads the target assembly, resolves dependencies through a CLR, decompiles C#, or executes target code.",
102
+ ]
103
+ : [
104
+ "This capability decodes bounded PE/CLI metadata members, signatures, and file-backed method bodies; decompiled C# and cross-build matching are separate future contracts.",
105
+ "It never loads the target assembly, resolves dependencies through a CLR, decompiles C#, or executes target code.",
106
+ ]);
107
+ const maxRequestedFileBytes = (operation, parameters) => {
108
+ if (operation === "inspect_managed_artifact")
109
+ return managedArtifactInputSchema.parse(parameters).max_file_bytes;
110
+ if (operation === "inspect_managed_native_boundaries")
111
+ return managedNativeBoundaryInputSchema.parse(parameters).max_file_bytes;
112
+ return managedMemberInputSchema.parse(parameters).max_file_bytes;
113
+ };
114
+ const inspectManagedOperation = (operation, parameters, bytes, target) => {
115
+ if (operation === "inspect_managed_artifact") {
116
+ const input = managedArtifactInputSchema.parse(parameters);
117
+ return inspectManagedArtifactBytes(bytes, target, {
118
+ referenceOffset: input.reference_offset,
119
+ referenceLimit: input.reference_limit,
120
+ resourceOffset: input.resource_offset,
121
+ resourceLimit: input.resource_limit,
122
+ attributeOffset: input.attribute_offset,
123
+ attributeLimit: input.attribute_limit,
124
+ maxMetadataBytes: input.max_metadata_bytes,
125
+ maxTableRows: input.max_table_rows,
126
+ maxHeapItemBytes: input.max_heap_item_bytes,
127
+ });
128
+ }
129
+ if (operation === "inspect_managed_native_boundaries") {
130
+ const input = managedNativeBoundaryInputSchema.parse(parameters);
131
+ return inspectManagedNativeBoundariesBytes(bytes, target, {
132
+ moduleRefOffset: input.module_ref_offset,
133
+ moduleRefLimit: input.module_ref_limit,
134
+ importOffset: input.import_offset,
135
+ importLimit: input.import_limit,
136
+ implementationOffset: input.implementation_offset,
137
+ implementationLimit: input.implementation_limit,
138
+ maxMetadataBytes: input.max_metadata_bytes,
139
+ maxTableRows: input.max_table_rows,
140
+ maxHeapItemBytes: input.max_heap_item_bytes,
141
+ });
142
+ }
143
+ const input = managedMemberInputSchema.parse(parameters);
144
+ return inspectManagedMembersBytes(bytes, target, {
145
+ typeOffset: input.type_offset,
146
+ typeLimit: input.type_limit,
147
+ methodOffset: input.method_offset,
148
+ methodLimit: input.method_limit,
149
+ fieldOffset: input.field_offset,
150
+ fieldLimit: input.field_limit,
151
+ memberRefOffset: input.member_ref_offset,
152
+ memberRefLimit: input.member_ref_limit,
153
+ edgeOffset: input.edge_offset,
154
+ edgeLimit: input.edge_limit,
155
+ instructionAnchorLimit: input.instruction_anchor_limit,
156
+ maxMetadataBytes: input.max_metadata_bytes,
157
+ maxTableRows: input.max_table_rows,
158
+ maxHeapItemBytes: input.max_heap_item_bytes,
159
+ maxMethodBodyBytes: input.max_method_body_bytes,
160
+ maxMethodInstructions: input.max_method_instructions,
161
+ });
162
+ };
163
+ const managedLocations = (result) => {
164
+ if ("pe" in result) {
165
+ if (result.pe.cli === null)
166
+ return [{ kind: "file-offset", offset: 0 }];
167
+ return [
168
+ {
169
+ kind: "file-offset-range",
170
+ start: result.pe.cli.header_offset,
171
+ end: result.pe.cli.header_offset + result.pe.cli.header_size,
172
+ },
173
+ ...[result.module, result.assembly]
174
+ .filter((value) => value !== null)
175
+ .map((value) => ({
176
+ kind: "file-offset",
177
+ offset: value.row_offset,
178
+ })),
179
+ ];
180
+ }
181
+ if ("methods" in result)
182
+ return [
183
+ ...(result.module === null
184
+ ? [{ kind: "file-offset", offset: 0 }]
185
+ : [{ kind: "file-offset", offset: result.module.row_offset }]),
186
+ ...result.methods.items
187
+ .filter((method) => method.body.file_offset !== null)
188
+ .slice(0, 8)
189
+ .map((method) => ({
190
+ kind: "file-offset",
191
+ offset: method.body.file_offset ?? 0,
192
+ })),
193
+ ];
194
+ return [
195
+ ...(result.module === null
196
+ ? [{ kind: "file-offset", offset: 0 }]
197
+ : [{ kind: "file-offset", offset: result.module.row_offset }]),
198
+ ...result.pinvoke_imports.items.slice(0, 8).map((mapping) => ({
199
+ kind: "file-offset",
200
+ offset: mapping.row_offset,
201
+ })),
202
+ ];
203
+ };
@@ -1,9 +1,9 @@
1
1
  /** Generated from package.json and package-lock.json; do not edit. */
2
2
  export const PACKAGE_METADATA = {
3
3
  name: "rea-agents",
4
- version: "1.7.0",
4
+ version: "2.0.0",
5
5
  serverSdkVersion: "2.0.0-beta.4",
6
6
  clientSdkVersion: "2.0.0-beta.4",
7
7
  coreSdkVersion: "2.0.0-beta.4",
8
- skillVersion: "14",
8
+ skillVersion: "20",
9
9
  };
@@ -307,6 +307,12 @@ export class GhidraProvider {
307
307
  ...(this.config.ghidraJavaHome === undefined
308
308
  ? {}
309
309
  : { javaHome: this.config.ghidraJavaHome }),
310
+ ...(this.installationHost?.platform === undefined
311
+ ? {}
312
+ : { platform: this.installationHost.platform }),
313
+ ...(this.installationHost?.architecture === undefined
314
+ ? {}
315
+ : { architecture: this.installationHost.architecture }),
310
316
  };
311
317
  this.#installation ??=
312
318
  this.installationHost === undefined
package/dist/main.js CHANGED
@@ -89,6 +89,14 @@ export const run = async (dependencies = runtimeDependencies()) => {
89
89
  roots: [...config.value.analysisSnapshotFilePolicy.roots],
90
90
  };
91
91
  const runtimeInvestigationRoots = [...config.value.investigationInputRoots];
92
+ const runtimeJavascriptReplayPolicy = {
93
+ ...config.value.javascriptReplayPolicy,
94
+ roots: [...config.value.javascriptReplayPolicy.roots],
95
+ };
96
+ const runtimeManagedRuntimePolicy = {
97
+ ...config.value.managedRuntimePolicy,
98
+ roots: [...config.value.managedRuntimePolicy.roots],
99
+ };
92
100
  const liveServers = new Set();
93
101
  let handle;
94
102
  try {
@@ -103,6 +111,8 @@ export const run = async (dependencies = runtimeDependencies()) => {
103
111
  browserObservation,
104
112
  electronObservation,
105
113
  artifactIntegrityContinueEnabled: () => currentConfig.artifactIntegrityContinueEnabled,
114
+ javascriptReplayPolicy: runtimeJavascriptReplayPolicy,
115
+ managedRuntimePolicy: runtimeManagedRuntimePolicy,
106
116
  availabilityPolicy: () => ({
107
117
  processCaptureEnabled: currentConfig.processExecutionPolicy.enabled,
108
118
  evidenceFileRoots: currentConfig.evidenceFilePolicy.roots.length,
@@ -112,6 +122,8 @@ export const run = async (dependencies = runtimeDependencies()) => {
112
122
  electronObservationEnabled: currentConfig.electronObservationEnabled &&
113
123
  currentConfig.electronCdpEndpoints.length > 0 &&
114
124
  currentConfig.electronFileRoots.length > 0,
125
+ javascriptReplayEnabled: currentConfig.javascriptReplayPolicy.enabled,
126
+ managedRuntimeEnabled: currentConfig.managedRuntimePolicy.enabled,
115
127
  }),
116
128
  });
117
129
  liveServers.add(server);
@@ -162,6 +174,8 @@ export const run = async (dependencies = runtimeDependencies()) => {
162
174
  Object.assign(runtimeEvidencePolicy, refreshed.value.evidenceFilePolicy);
163
175
  Object.assign(runtimeSnapshotPolicy, refreshed.value.analysisSnapshotFilePolicy);
164
176
  runtimeInvestigationRoots.splice(0, runtimeInvestigationRoots.length, ...refreshed.value.investigationInputRoots);
177
+ Object.assign(runtimeJavascriptReplayPolicy, refreshed.value.javascriptReplayPolicy);
178
+ Object.assign(runtimeManagedRuntimePolicy, refreshed.value.managedRuntimePolicy);
165
179
  for (const server of liveServers)
166
180
  server.sendToolListChanged();
167
181
  });
@@ -0,0 +1,286 @@
1
+ import { Script, SourceTextModule, SyntheticModule, createContext, } from "node:vm";
2
+ import { types } from "node:util";
3
+ class ReplayDeniedError extends Error {
4
+ name = "ReplayDeniedError";
5
+ }
6
+ const main = async () => {
7
+ const chunks = [];
8
+ for await (const chunk of process.stdin)
9
+ chunks.push(Buffer.from(chunk));
10
+ const request = JSON.parse(Buffer.concat(chunks).toString("utf8"));
11
+ if (request.schemaVersion !== 1)
12
+ throw new TypeError("Unsupported replay worker protocol");
13
+ const left = [];
14
+ const right = [];
15
+ for (let index = 0; index < request.cases.length; index += 1) {
16
+ const replayCase = request.cases[index];
17
+ if (replayCase === undefined)
18
+ continue;
19
+ left.push(await runCase(request.left, replayCase, request, index));
20
+ if (request.right !== undefined)
21
+ right.push(await runCase(request.right, replayCase, request, index));
22
+ }
23
+ process.stdout.write(JSON.stringify({
24
+ schema_version: 1,
25
+ left,
26
+ ...(request.right === undefined ? {} : { right }),
27
+ }));
28
+ };
29
+ const runCase = async (side, replayCase, request, index) => {
30
+ try {
31
+ const loaded = await loadEntry(side, request, index);
32
+ if (typeof loaded !== "function")
33
+ throw new TypeError(`Replay export is not callable: ${side.entryExport}`);
34
+ const returned = await Reflect.apply(loaded, undefined, [
35
+ ...replayCase.arguments,
36
+ ]);
37
+ try {
38
+ return {
39
+ case_id: replayCase.caseId,
40
+ outcome: "return",
41
+ value: projectValue(returned, request.limits.resultDepth, request.limits.resultNodes),
42
+ input_sha256: replayCase.inputSha256,
43
+ output_sha256: null,
44
+ truncated: false,
45
+ };
46
+ }
47
+ catch (error) {
48
+ return exceptionOutcome(replayCase, "serialization_error", error, request.limits.exceptionBytes);
49
+ }
50
+ }
51
+ catch (error) {
52
+ return exceptionOutcome(replayCase, error instanceof ReplayDeniedError ? "denied" : "exception", error, request.limits.exceptionBytes);
53
+ }
54
+ };
55
+ const loadEntry = async (side, request, caseIndex) => {
56
+ const modules = new Map(side.modules.map((module) => [module.alias, module]));
57
+ const context = deterministicContext(request, caseIndex);
58
+ const esmCache = new Map();
59
+ const commonJsCache = new Map();
60
+ const loadCommonJs = (alias) => {
61
+ const cached = commonJsCache.get(alias);
62
+ if (cached !== undefined)
63
+ return cached;
64
+ const descriptor = requiredModule(modules, alias);
65
+ if (descriptor.format !== "commonjs-factory")
66
+ throw new TypeError(`Synchronous require cannot load ESM module: ${alias}`);
67
+ const module = { exports: {} };
68
+ commonJsCache.set(alias, module.exports);
69
+ const requireModule = ((specifier) => {
70
+ const dependency = descriptor.dependencies[specifier];
71
+ if (dependency === undefined)
72
+ throw new ReplayDeniedError(`Undeclared require: ${specifier}`);
73
+ return loadCommonJs(dependency);
74
+ });
75
+ installRspackHelpers(requireModule);
76
+ const source = normalizeFactorySource(descriptor.source);
77
+ const factory = new Script(`(${source})`, {
78
+ filename: `/modules/${alias}.js`,
79
+ }).runInContext(context);
80
+ factory(module, module.exports, requireModule);
81
+ commonJsCache.set(alias, module.exports);
82
+ return module.exports;
83
+ };
84
+ const loadEsm = async (alias) => {
85
+ const cached = esmCache.get(alias);
86
+ if (cached !== undefined)
87
+ return cached;
88
+ const descriptor = requiredModule(modules, alias);
89
+ let module;
90
+ if (descriptor.format === "commonjs-factory") {
91
+ const exports = loadCommonJs(alias);
92
+ const names = [...new Set(["default", ...Object.keys(exports)])];
93
+ module = new SyntheticModule(names, function () {
94
+ this.setExport("default", exports);
95
+ for (const name of Object.keys(exports))
96
+ this.setExport(name, exports[name]);
97
+ }, { context, identifier: `rea:${alias}` });
98
+ }
99
+ else {
100
+ module = new SourceTextModule(descriptor.source, {
101
+ context,
102
+ identifier: `rea:${alias}`,
103
+ initializeImportMeta: (meta) => {
104
+ meta.url = `rea:${alias}`;
105
+ },
106
+ importModuleDynamically: () => {
107
+ throw new ReplayDeniedError("Dynamic import is unavailable in controlled replay");
108
+ },
109
+ });
110
+ }
111
+ esmCache.set(alias, module);
112
+ await module.link(async (specifier) => {
113
+ const dependency = descriptor.dependencies[specifier];
114
+ if (dependency === undefined)
115
+ throw new ReplayDeniedError(`Undeclared import: ${specifier}`);
116
+ return loadEsm(dependency);
117
+ });
118
+ await module.evaluate();
119
+ return module;
120
+ };
121
+ const entry = requiredModule(modules, side.entryAlias);
122
+ if (entry.format === "commonjs-factory") {
123
+ const exported = loadCommonJs(side.entryAlias);
124
+ return side.entryExport === "default"
125
+ ? (exported.default ?? exported)
126
+ : exported[side.entryExport];
127
+ }
128
+ const namespace = (await loadEsm(side.entryAlias)).namespace;
129
+ return namespace[side.entryExport];
130
+ };
131
+ const deterministicContext = (request, caseIndex) => {
132
+ let state = (request.determinism.randomSeed + caseIndex) >>> 0;
133
+ const random = () => {
134
+ state ^= state << 13;
135
+ state ^= state >>> 17;
136
+ state ^= state << 5;
137
+ return (state >>> 0) / 0x1_0000_0000;
138
+ };
139
+ const epoch = Date.parse(request.determinism.clockIso);
140
+ class ReplayDate extends Date {
141
+ constructor(...arguments_) {
142
+ super(arguments_.length === 0 ? epoch : arguments_[0]);
143
+ }
144
+ static now() {
145
+ return epoch;
146
+ }
147
+ }
148
+ const replayMath = Object.create(Math);
149
+ Object.defineProperty(replayMath, "random", { value: random });
150
+ return createContext({ Date: ReplayDate, Math: replayMath }, {
151
+ name: "rea-controlled-replay",
152
+ codeGeneration: { strings: false, wasm: false },
153
+ });
154
+ };
155
+ const installRspackHelpers = (require_) => {
156
+ require_.d = (exports, definitions) => {
157
+ for (const [name, getter] of Object.entries(definitions))
158
+ if (!Object.prototype.hasOwnProperty.call(exports, name))
159
+ Object.defineProperty(exports, name, { enumerable: true, get: getter });
160
+ };
161
+ require_.r = (exports) => {
162
+ Object.defineProperty(exports, "__esModule", { value: true });
163
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
164
+ };
165
+ require_.n = (module) => {
166
+ const getter = () => (module.__esModule === true ? module.default : module);
167
+ Object.defineProperty(getter, "a", { get: getter });
168
+ return getter;
169
+ };
170
+ require_.nmd = (module) => module;
171
+ };
172
+ const requiredModule = (modules, alias) => {
173
+ const module = modules.get(alias);
174
+ if (module === undefined)
175
+ throw new TypeError(`Undeclared module alias: ${alias}`);
176
+ return module;
177
+ };
178
+ const normalizeFactorySource = (source) => /^\s*\d+\s*\(/u.test(source)
179
+ ? source.replace(/^\s*\d+\s*\(/u, "function(")
180
+ : source;
181
+ const projectValue = (value, maximumDepth, maximumNodes) => {
182
+ let nodes = 0;
183
+ const visit = (candidate, depth, ancestors) => {
184
+ nodes += 1;
185
+ if (nodes > maximumNodes || depth > maximumDepth)
186
+ throw new RangeError("Replay result projection limit exceeded");
187
+ if (candidate === null ||
188
+ typeof candidate === "string" ||
189
+ typeof candidate === "boolean")
190
+ return candidate;
191
+ if (typeof candidate === "number") {
192
+ if (!Number.isFinite(candidate))
193
+ throw new TypeError("Non-finite replay result number");
194
+ return candidate;
195
+ }
196
+ if (typeof candidate !== "object")
197
+ throw new TypeError(`Unsupported replay result type: ${typeof candidate}`);
198
+ if (types.isProxy(candidate))
199
+ throw new TypeError("Proxy replay results are unavailable");
200
+ if (ancestors.has(candidate))
201
+ throw new TypeError("Cyclic replay result");
202
+ ancestors.add(candidate);
203
+ try {
204
+ const descriptors = Object.getOwnPropertyDescriptors(candidate);
205
+ const output = Array.isArray(candidate)
206
+ ? []
207
+ : {};
208
+ if (!Array.isArray(candidate)) {
209
+ const prototype = Object.getPrototypeOf(candidate);
210
+ if (prototype !== null && Object.getPrototypeOf(prototype) !== null)
211
+ throw new TypeError("Unsupported replay result prototype");
212
+ }
213
+ for (const [key, descriptor] of Object.entries(descriptors)) {
214
+ if (key === "length" && Array.isArray(candidate))
215
+ continue;
216
+ if (!("value" in descriptor))
217
+ throw new TypeError("Replay result accessors are unavailable");
218
+ if (Array.isArray(output)) {
219
+ if (!/^\d+$/u.test(key))
220
+ throw new TypeError("Replay arrays may only contain indexed values");
221
+ output[Number(key)] = visit(descriptor.value, depth + 1, ancestors);
222
+ }
223
+ else
224
+ output[key] = visit(descriptor.value, depth + 1, ancestors);
225
+ }
226
+ return output;
227
+ }
228
+ finally {
229
+ ancestors.delete(candidate);
230
+ }
231
+ };
232
+ return visit(value, 0, new Set());
233
+ };
234
+ const exceptionOutcome = (replayCase, outcome, error, maximumBytes) => {
235
+ const details = exceptionDetails(error);
236
+ const name = bounded(details.name, maximumBytes);
237
+ const message = bounded(details.message, maximumBytes);
238
+ const stack = details.stack === null ? null : bounded(details.stack, maximumBytes);
239
+ return {
240
+ case_id: replayCase.caseId,
241
+ outcome,
242
+ exception: { name, message, stack },
243
+ input_sha256: replayCase.inputSha256,
244
+ output_sha256: null,
245
+ truncated: false,
246
+ };
247
+ };
248
+ const exceptionDetails = (error) => {
249
+ if (typeof error !== "object" || error === null)
250
+ return { name: "Error", message: "Unknown replay exception", stack: null };
251
+ if (types.isProxy(error))
252
+ return { name: "Error", message: "Proxy replay exception", stack: null };
253
+ const own = Object.getOwnPropertyDescriptors(error);
254
+ const prototype = Object.getPrototypeOf(error);
255
+ const inherited = prototype === null ? {} : Object.getOwnPropertyDescriptors(prototype);
256
+ const stringValue = (descriptor) => descriptor !== undefined &&
257
+ "value" in descriptor &&
258
+ typeof descriptor.value === "string"
259
+ ? descriptor.value
260
+ : null;
261
+ return {
262
+ name: stringValue(own.name) ?? stringValue(inherited.name) ?? "Error",
263
+ message: stringValue(own.message) ?? "Unknown replay exception",
264
+ stack: stringValue(own.stack),
265
+ };
266
+ };
267
+ const bounded = (value, maximumBytes) => {
268
+ const bytes = Buffer.from(value);
269
+ if (bytes.byteLength <= maximumBytes)
270
+ return value;
271
+ const decoder = new TextDecoder("utf-8", { fatal: true });
272
+ for (let end = maximumBytes; end >= Math.max(0, maximumBytes - 3); end -= 1) {
273
+ try {
274
+ return decoder.decode(bytes.subarray(0, end));
275
+ }
276
+ catch {
277
+ /* try the preceding UTF-8 boundary */
278
+ }
279
+ }
280
+ return "";
281
+ };
282
+ void main().catch((error) => {
283
+ const message = error instanceof Error ? error.message : "Replay worker failed";
284
+ process.stderr.write(message.slice(0, 4096));
285
+ process.exitCode = 70;
286
+ });