rea-agents 2.0.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. package/README.md +103 -38
  2. package/bridge/ghidra/ReaGhidraBridge.java +96 -11
  3. package/dist/application/AndroidApplicationService.js +17 -0
  4. package/dist/application/AppleApplicationService.js +17 -0
  5. package/dist/application/ArtifactExtraction.js +1 -1
  6. package/dist/application/ArtifactInventory/classify.js +42 -0
  7. package/dist/application/ArtifactInventory/hash.js +43 -0
  8. package/dist/application/ArtifactInventory/reader.js +41 -0
  9. package/dist/application/ArtifactInventory/scanCanonical.js +155 -0
  10. package/dist/application/ArtifactInventory/scanReader.js +124 -0
  11. package/dist/application/ArtifactInventory/types.js +10 -0
  12. package/dist/application/ArtifactInventory.js +9 -351
  13. package/dist/application/AuthorizedArtifactInventory.js +2 -2
  14. package/dist/application/BinarySession.js +47 -270
  15. package/dist/application/BinarySessionExecution.js +28 -0
  16. package/dist/application/BinarySessionOpen.js +39 -0
  17. package/dist/application/BinarySessionRecords.js +149 -0
  18. package/dist/application/BinarySessionStatus.js +75 -0
  19. package/dist/application/CapabilityInventory.js +24 -2
  20. package/dist/application/ClientRegistrationStatus.js +11 -4
  21. package/dist/application/CrossVersionInventory.js +8 -2
  22. package/dist/application/CrossVersionInvestigation.js +1 -23
  23. package/dist/application/CrossVersionInvestigationCollections.js +23 -0
  24. package/dist/application/DirectAnalysis.js +47 -44
  25. package/dist/application/Doctor.js +156 -238
  26. package/dist/application/DoctorDiagnostics.js +180 -0
  27. package/dist/application/ElectronBoundaryAnalysis.js +23 -7
  28. package/dist/application/ElectronBoundaryGraphWindows.js +32 -8
  29. package/dist/application/EnhancedToolPagination.js +22 -0
  30. package/dist/application/EnhancedToolTypes.js +4 -0
  31. package/dist/application/EnhancedTools.js +20 -37
  32. package/dist/application/InstrumentedJavaScriptReplayHost.js +36 -0
  33. package/dist/application/InventoryProjectionEvidence.js +41 -0
  34. package/dist/application/InvestigationProviders.js +12 -0
  35. package/dist/application/InvestigationWorkspaceStore.js +24 -10
  36. package/dist/application/JavaScriptArtifactAnalysis.js +45 -6
  37. package/dist/application/JavaScriptArtifactFiles.js +6 -2
  38. package/dist/application/JavaScriptArtifactGraphBuilder.js +23 -1
  39. package/dist/application/JavaScriptArtifactGraphBundlers.js +225 -0
  40. package/dist/application/JavaScriptArtifactGraphContext.js +37 -36
  41. package/dist/application/JavaScriptArtifactGraphDocuments.js +27 -4
  42. package/dist/application/JavaScriptArtifactGraphFindings.js +54 -8
  43. package/dist/application/JavaScriptArtifactGraphStructure.js +29 -101
  44. package/dist/application/JavaScriptArtifactPathResolution.js +269 -0
  45. package/dist/application/JavaScriptArtifactReconstruction.js +1 -1
  46. package/dist/application/JavaScriptJsonModules.js +39 -0
  47. package/dist/application/JavaScriptModuleRelationships.js +262 -0
  48. package/dist/application/JavaScriptReplayPermission.js +16 -0
  49. package/dist/application/JavaScriptReplayService.js +182 -156
  50. package/dist/application/LinuxHopper.js +10 -0
  51. package/dist/application/MacHopper.js +22 -11
  52. package/dist/application/NodeRuntimeCharacterizationService.js +196 -0
  53. package/dist/application/PermissionAuthority.js +106 -63
  54. package/dist/application/ProcessCaptureCapability.js +1 -1
  55. package/dist/application/ProcessCapturePermission.js +13 -0
  56. package/dist/application/ProcessCli.js +2 -12
  57. package/dist/application/ProcessHarness.js +1 -1
  58. package/dist/application/ProcessPairedExperiment.js +72 -0
  59. package/dist/application/ProjectPermissionStore.js +48 -9
  60. package/dist/application/RealHopperAssertions.js +76 -0
  61. package/dist/application/ReconstructionCoverageService.js +69 -0
  62. package/dist/application/ReconstructionCoverageWorkspaceStore.js +31 -0
  63. package/dist/application/RuntimeExecutableDiagnostics.js +172 -0
  64. package/dist/application/Setup.js +148 -260
  65. package/dist/application/SetupClientConfiguration.js +224 -0
  66. package/dist/application/SetupClients.js +24 -2
  67. package/dist/application/SetupPlan.js +124 -12
  68. package/dist/application/SetupSkill.js +54 -36
  69. package/dist/application/SupportedClients.js +1 -0
  70. package/dist/application/Uninstall.js +12 -3
  71. package/dist/application/Upgrade.js +16 -1
  72. package/dist/application/WindowsCapabilities.js +86 -0
  73. package/dist/artifacts/AsarArtifactReader.js +11 -0
  74. package/dist/browser/BrowserProcessStartup.js +88 -0
  75. package/dist/browser/CdpCaptureDocuments.js +12 -8
  76. package/dist/browser/CdpCaptureEventBodyShapes.js +75 -0
  77. package/dist/browser/CdpCaptureEventHandlers.js +336 -0
  78. package/dist/browser/CdpCaptureEventHelpers.js +71 -0
  79. package/dist/browser/CdpCaptureEventState.js +1 -0
  80. package/dist/browser/CdpCaptureEventTypes.js +1 -0
  81. package/dist/browser/CdpCaptureEvents.js +29 -496
  82. package/dist/browser/CdpObservationSession.js +51 -8
  83. package/dist/browser/CdpPageCapture.js +12 -133
  84. package/dist/browser/CdpPageCaptureScripts.js +97 -0
  85. package/dist/browser/CdpPageCaptureWorkers.js +46 -0
  86. package/dist/browser/CdpWebMcpDiscovery.js +38 -14
  87. package/dist/browser/PngVisualDiff.js +9 -2
  88. package/dist/catalogIdentity.js +4 -0
  89. package/dist/cli/artifactCommands.js +82 -0
  90. package/dist/cli/coreAnalysisCommands.js +232 -0
  91. package/dist/cli/managedCommands.js +397 -0
  92. package/dist/cli/managedProjectGraphCommand.js +24 -0
  93. package/dist/cli/options.js +9 -0
  94. package/dist/cli/setupCommands.js +113 -0
  95. package/dist/cli/types.js +1 -0
  96. package/dist/cli/utilityCommands.js +122 -0
  97. package/dist/cli.js +10 -768
  98. package/dist/cliApplicationCommands.js +118 -4
  99. package/dist/cliBrowserAdvancedCommands.js +73 -16
  100. package/dist/cliBrowserCommands.js +39 -115
  101. package/dist/cliCommandNames.js +4 -0
  102. package/dist/cliElectronCommands.js +33 -62
  103. package/dist/cliEvidenceCommands.js +13 -2
  104. package/dist/cliInvestigationCommands.js +53 -10
  105. package/dist/cliObservationOptions.js +137 -0
  106. package/dist/cliPolicyCommands.js +80 -46
  107. package/dist/cliSetup.js +306 -0
  108. package/dist/config/environment.js +107 -0
  109. package/dist/config/parseConfig.js +228 -0
  110. package/dist/config/parsers.js +68 -0
  111. package/dist/config/permissions.js +30 -0
  112. package/dist/config/types.js +1 -0
  113. package/dist/config.js +1 -375
  114. package/dist/contracts/applicationToolContracts.js +134 -0
  115. package/dist/contracts/electronToolContracts.js +51 -3
  116. package/dist/contracts/managedToolContracts.js +8 -3
  117. package/dist/contracts/managedWorkflowToolContracts.js +3 -3
  118. package/dist/contracts/providerSelection.js +2 -0
  119. package/dist/contracts/sessionStatusContract.js +26 -0
  120. package/dist/contracts/toolContractTypes.js +12 -1
  121. package/dist/contracts/toolContracts.js +5 -12
  122. package/dist/contracts/toolEffects.js +14 -0
  123. package/dist/contracts/toolOutputSchemaGroups.js +274 -0
  124. package/dist/contracts/toolOutputSchemaPrimitives.js +328 -0
  125. package/dist/contracts/toolOutputSchemas.js +2 -550
  126. package/dist/domain/analysisErrorPresentation.js +234 -0
  127. package/dist/domain/analysisErrorProjection.js +284 -0
  128. package/dist/domain/androidApplication.js +206 -0
  129. package/dist/domain/appleApplication.js +221 -0
  130. package/dist/domain/artifactComparison.js +34 -15
  131. package/dist/domain/binaryTarget.js +87 -37
  132. package/dist/domain/boundedCartesianProjection.js +15 -0
  133. package/dist/domain/browserObservation.js +1 -285
  134. package/dist/domain/browserObservationSchemas.js +286 -0
  135. package/dist/domain/electronStaticAnalysisBrowser.js +14 -2
  136. package/dist/domain/errors.js +4 -486
  137. package/dist/domain/functionComparison.js +4 -165
  138. package/dist/domain/functionComparisonDimensions.js +164 -0
  139. package/dist/domain/javascriptApplicationVersionItems.js +18 -6
  140. package/dist/domain/javascriptApplicationVersionKeys.js +8 -8
  141. package/dist/domain/javascriptExportInstrumentation.js +97 -0
  142. package/dist/domain/javascriptFeatureTraversal.js +19 -7
  143. package/dist/domain/javascriptRuntimeStaticCandidates.js +3 -1
  144. package/dist/domain/javascriptSemanticAnalysis.js +386 -0
  145. package/dist/domain/javascriptSemanticIr.js +30 -0
  146. package/dist/domain/javascriptSemanticProjection.js +366 -0
  147. package/dist/domain/javascriptSemanticState.js +40 -0
  148. package/dist/domain/javascriptSemanticTraversal.js +22 -0
  149. package/dist/domain/javascriptSemanticValues.js +352 -0
  150. package/dist/domain/javascriptStaticAnalysis.js +5 -221
  151. package/dist/domain/javascriptStaticAnalysisBundler.js +209 -0
  152. package/dist/domain/javascriptStaticAnalysisCalls.js +180 -0
  153. package/dist/domain/javascriptStaticAnalysisHelpers.js +71 -2
  154. package/dist/domain/knownPageCoverage.js +21 -0
  155. package/dist/domain/managedApplicationGraph.js +14 -364
  156. package/dist/domain/managedApplicationGraphCoverage.js +170 -0
  157. package/dist/domain/managedApplicationGraphNodeCoverage.js +6 -0
  158. package/dist/domain/managedApplicationGraphNodes.js +336 -0
  159. package/dist/domain/managedArtifact.js +16 -8
  160. package/dist/domain/managedMemberComparison.js +37 -391
  161. package/dist/domain/managedMemberComparisonCoverage.js +72 -0
  162. package/dist/domain/managedMemberComparisonMatch.js +356 -0
  163. package/dist/domain/managedNativeVerification.js +27 -389
  164. package/dist/domain/managedNativeVerificationMatch.js +272 -0
  165. package/dist/domain/managedNativeVerificationSchemas.js +141 -0
  166. package/dist/domain/managedReconstruction.js +82 -69
  167. package/dist/domain/managedRuntimeCorrelation.js +12 -3
  168. package/dist/domain/nodeRuntimeCharacterization.js +66 -0
  169. package/dist/domain/permissionPolicy.js +2 -0
  170. package/dist/domain/processComparison.js +19 -0
  171. package/dist/domain/processPairedExperiment.js +128 -0
  172. package/dist/domain/reconstructionCoverage.js +387 -0
  173. package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
  174. package/dist/domain/reconstructionVerificationSchemas.js +8 -0
  175. package/dist/domain/replayMachine.js +316 -0
  176. package/dist/domain/replayMachineRuntime.js +215 -0
  177. package/dist/domain/runtimeCharacterization.js +85 -0
  178. package/dist/domain/runtimeIdentification.js +210 -0
  179. package/dist/domain/webBundleAnalyzer.js +3 -409
  180. package/dist/domain/webBundleAnalyzerAst.js +77 -0
  181. package/dist/domain/webBundleAnalyzerInspection.js +307 -0
  182. package/dist/domain/webBundleAnalyzerResult.js +120 -0
  183. package/dist/dotnet/ManagedArtifactInspector.js +50 -29
  184. package/dist/dotnet/ManagedMemberInspector.js +51 -785
  185. package/dist/dotnet/ManagedMemberInspectorCore.js +297 -0
  186. package/dist/dotnet/ManagedMemberInstructionDecoder.js +427 -0
  187. package/dist/dotnet/ManagedMemberRows.js +120 -0
  188. package/dist/dotnet/ManagedMetadataInventory.js +42 -306
  189. package/dist/dotnet/ManagedMetadataInventoryRows.js +292 -0
  190. package/dist/dotnet/ManagedMetadataLayout.js +48 -111
  191. package/dist/dotnet/ManagedMetadataRowSizes.js +54 -0
  192. package/dist/dotnet/ManagedMethodBodyReader.js +143 -0
  193. package/dist/dotnet/ManagedNativeBoundaryHelpers.js +311 -0
  194. package/dist/dotnet/ManagedNativeBoundaryInspector.js +102 -350
  195. package/dist/dotnet/ManagedPeReader.js +59 -28
  196. package/dist/evaluation/CodexAgentEval.js +132 -0
  197. package/dist/generatedPackageMetadata.js +2 -2
  198. package/dist/ghidra/GhidraClient.js +76 -91
  199. package/dist/ghidra/GhidraClientStartup.js +29 -0
  200. package/dist/ghidra/GhidraClientWire.js +34 -0
  201. package/dist/ghidra/GhidraDefaults.js +1 -1
  202. package/dist/ghidra/GhidraDiagnostics.js +6 -1
  203. package/dist/ghidra/GhidraInstallation.js +20 -15
  204. package/dist/ghidra/GhidraLauncher.js +93 -29
  205. package/dist/ghidra/GhidraProvider.js +61 -161
  206. package/dist/ghidra/GhidraProviderCapabilities.js +173 -0
  207. package/dist/ghidra/GhidraSessionValues.js +2 -0
  208. package/dist/ghidra/GhidraSocketConnection.js +44 -7
  209. package/dist/ghidra/GhidraTargetSnapshot.js +30 -0
  210. package/dist/ghidra/GhidraTransport.js +71 -0
  211. package/dist/identity.js +4 -2
  212. package/dist/main/messages.js +5 -0
  213. package/dist/main/reload.js +49 -0
  214. package/dist/main/shutdown.js +25 -0
  215. package/dist/main/startup.js +14 -0
  216. package/dist/main/state.js +26 -0
  217. package/dist/main/transport.js +61 -0
  218. package/dist/main/types.js +1 -0
  219. package/dist/main.js +35 -146
  220. package/dist/process/PrivateRuntimeRoot.js +3 -2
  221. package/dist/process/ProcessOwnership.js +35 -0
  222. package/dist/process/ProviderProcess.js +2 -0
  223. package/dist/replay/JavaScriptReplayWorker.js +64 -50
  224. package/dist/replay/LinuxJavaScriptReplayRunner.js +173 -390
  225. package/dist/replay/LinuxJavaScriptReplaySandbox.js +140 -0
  226. package/dist/replay/ReplayOutcome.js +95 -0
  227. package/dist/replay/ReplayProcessLifecycle.js +71 -0
  228. package/dist/server/ProcessCaptureElicitation.js +157 -0
  229. package/dist/server/createServer.js +124 -56
  230. package/dist/server/javascriptApplicationResult.js +85 -0
  231. package/dist/server/registerApplicationTools/characterization.js +57 -0
  232. package/dist/server/registerApplicationTools/compareVersions.js +34 -0
  233. package/dist/server/registerApplicationTools/controlledReplay.js +38 -0
  234. package/dist/server/registerApplicationTools/coverage.js +84 -0
  235. package/dist/server/registerApplicationTools/helpers.js +42 -0
  236. package/dist/server/registerApplicationTools/traceFeature.js +26 -0
  237. package/dist/server/registerApplicationTools/types.js +1 -0
  238. package/dist/server/registerApplicationTools.js +10 -112
  239. package/dist/server/registerBrowserTools.js +59 -83
  240. package/dist/server/registerElectronTools.js +48 -49
  241. package/dist/server/registerEnhancedTools.js +34 -42
  242. package/dist/server/registerEvidenceResources.js +56 -0
  243. package/dist/server/registerInvestigationTools/helpers.js +74 -0
  244. package/dist/server/registerInvestigationTools/types.js +1 -0
  245. package/dist/server/registerInvestigationTools.js +83 -116
  246. package/dist/server/registerJavaScriptApplicationGraphResource.js +69 -0
  247. package/dist/server/registerManagedTools.js +18 -1
  248. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +65 -0
  249. package/dist/server/registerManagedWorkflowTools/contract.js +8 -0
  250. package/dist/server/registerManagedWorkflowTools/evidence.js +43 -0
  251. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +39 -0
  252. package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +39 -0
  253. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +52 -0
  254. package/dist/server/registerManagedWorkflowTools/types.js +1 -0
  255. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +75 -0
  256. package/dist/server/registerManagedWorkflowTools.js +10 -274
  257. package/dist/server/registerOfficialTools.js +73 -59
  258. package/dist/server/registerSessionRecordTools.js +137 -0
  259. package/dist/server/registerSessionStatusTool.js +97 -26
  260. package/dist/server/registerSessionTools.js +60 -164
  261. package/dist/server/sessionAvailabilityPolicy.js +10 -0
  262. package/dist/server/toolRegistrationOptions.js +101 -3
  263. package/dist/server/toolResult.js +15 -4
  264. package/package.json +11 -11
  265. package/skills/reverse-engineer-anything/SKILL.md +76 -0
  266. package/skills/reverse-engineer-anything/references/controlled-replay.md +12 -0
  267. package/skills/reverse-engineer-anything/references/evidence-workflows.md +33 -0
  268. package/skills/reverse-engineer-anything/references/javascript-applications.md +25 -0
  269. package/skills/reverse-engineer-anything/references/native-and-artifacts.md +36 -0
  270. package/skills/reverse-engineer-anything/references/runtime-observation.md +24 -0
  271. package/scripts/prepare-node-pty.mjs +0 -35
  272. package/scripts/rebuild-native.mjs +0 -22
  273. package/skills/rea-analysis/SKILL.md +0 -222
@@ -0,0 +1,140 @@
1
+ import { open } from "node:fs/promises";
2
+ import { dirname } from "node:path";
3
+ import { digestJson, } from "../application/JavaScriptReplayPlanning.js";
4
+ import { buildLinuxX64ReplaySeccomp } from "./LinuxSeccompPolicy.js";
5
+ import { resolveLinuxRuntimeClosure } from "./LinuxRuntimeClosure.js";
6
+ export const assertRuntimeCommitment = (prepared, closure) => {
7
+ const observed = closure.map((item) => ({
8
+ source_path: item.sourcePath,
9
+ destination_path: item.destinationPath,
10
+ sha256: item.sha256,
11
+ }));
12
+ if (digestJson(observed) !==
13
+ digestJson(prepared.publicPlan.runtime.read_only_files))
14
+ throw new TypeError("Replay runtime closure changed after approval");
15
+ };
16
+ export const temporaryFilterHandle = async () => {
17
+ const { mkdtemp, writeFile, rm } = await import("node:fs/promises");
18
+ const { tmpdir } = await import("node:os");
19
+ const { join } = await import("node:path");
20
+ const directory = await mkdtemp(join(tmpdir(), "rea-replay-filter-"));
21
+ const path = join(directory, "seccomp.bpf");
22
+ await writeFile(path, buildLinuxX64ReplaySeccomp(), { mode: 0o600 });
23
+ const handle = await open(path, "r");
24
+ return {
25
+ path,
26
+ handle,
27
+ close: async () => {
28
+ await handle.close();
29
+ await rm(directory, { recursive: true, force: true });
30
+ },
31
+ };
32
+ };
33
+ export const systemdArguments = (options) => {
34
+ const { unit, policy, prepared, workerPath, closure, filterPath } = options;
35
+ const limits = prepared.publicPlan.limits;
36
+ const descriptorPaths = [
37
+ filterPath,
38
+ ...closure.map(({ sourcePath }) => sourcePath),
39
+ workerPath,
40
+ ];
41
+ const workerFd = descriptorPaths.length + 2;
42
+ const wrapper = descriptorPaths
43
+ .map((_, index) => `exec ${String(index + 3)}<"$1"; shift`)
44
+ .concat('exec "$@"')
45
+ .join("\n");
46
+ return [
47
+ "--user",
48
+ "--pipe",
49
+ "--wait",
50
+ "--service-type=exec",
51
+ "--quiet",
52
+ `--unit=${unit}`,
53
+ `--property=MemoryMax=${String(limits.memory_bytes)}`,
54
+ "--property=MemorySwapMax=0",
55
+ `--property=TasksMax=${String(limits.tasks)}`,
56
+ `--property=CPUQuota=${String(limits.cpu_quota_percent)}%`,
57
+ "--property=KillMode=control-group",
58
+ "--property=SendSIGKILL=yes",
59
+ "--",
60
+ policy.shellPath,
61
+ "-c",
62
+ wrapper,
63
+ "rea-replay-wrapper",
64
+ ...descriptorPaths,
65
+ policy.bubblewrapPath,
66
+ "--unshare-all",
67
+ "--unshare-user",
68
+ "--disable-userns",
69
+ "--new-session",
70
+ "--die-with-parent",
71
+ "--cap-drop",
72
+ "ALL",
73
+ "--clearenv",
74
+ "--setenv",
75
+ "HOME",
76
+ "/work",
77
+ "--setenv",
78
+ "TMPDIR",
79
+ "/tmp",
80
+ "--setenv",
81
+ "TZ",
82
+ "UTC",
83
+ "--setenv",
84
+ "LANG",
85
+ "C",
86
+ "--setenv",
87
+ "LC_ALL",
88
+ "C",
89
+ "--tmpfs",
90
+ "/",
91
+ "--dir",
92
+ "/runtime",
93
+ "--dir",
94
+ "/work",
95
+ "--size",
96
+ String(limits.tmpfs_bytes),
97
+ "--tmpfs",
98
+ "/tmp",
99
+ ...bindArguments(closure),
100
+ "--ro-bind-fd",
101
+ String(workerFd),
102
+ "/runtime/worker.js",
103
+ "--proc",
104
+ "/proc",
105
+ "--dev",
106
+ "/dev",
107
+ "--remount-ro",
108
+ "/",
109
+ "--chdir",
110
+ "/work",
111
+ "--seccomp",
112
+ "3",
113
+ "--",
114
+ "/runtime/node",
115
+ `--max-old-space-size=${String(Math.max(8, Math.floor(limits.memory_bytes / 1024 / 1024 / 2)))}`,
116
+ "--experimental-vm-modules",
117
+ "--permission",
118
+ "--allow-fs-read=/runtime/worker.js",
119
+ "/runtime/worker.js",
120
+ ];
121
+ };
122
+ const bindArguments = (closure) => {
123
+ const arguments_ = [];
124
+ const directories = new Set();
125
+ for (const [index, item] of closure.entries()) {
126
+ const destination = item.destinationPath;
127
+ let parent = dirname(destination);
128
+ const chain = [];
129
+ while (parent !== "/" && !directories.has(parent)) {
130
+ chain.push(parent);
131
+ parent = dirname(parent);
132
+ }
133
+ for (const directory of chain.reverse()) {
134
+ directories.add(directory);
135
+ arguments_.push("--dir", directory);
136
+ }
137
+ arguments_.push("--ro-bind-fd", String(index + 4), destination);
138
+ }
139
+ return arguments_;
140
+ };
@@ -0,0 +1,95 @@
1
+ import { digestJson, } from "../application/JavaScriptReplayPlanning.js";
2
+ import { jsonValueSchema } from "../domain/jsonValue.js";
3
+ export const workerRequest = (prepared) => ({
4
+ schemaVersion: 1,
5
+ left: workerSide(prepared.publicPlan.left, prepared.leftSources),
6
+ ...(prepared.publicPlan.right === undefined ||
7
+ prepared.rightSources === undefined
8
+ ? {}
9
+ : { right: workerSide(prepared.publicPlan.right, prepared.rightSources) }),
10
+ cases: prepared.publicPlan.cases.map((item) => ({
11
+ caseId: item.case_id,
12
+ arguments: item.arguments,
13
+ inputSha256: item.sha256,
14
+ })),
15
+ determinism: {
16
+ clockIso: prepared.publicPlan.determinism.clock_iso,
17
+ randomSeed: prepared.publicPlan.determinism.random_seed,
18
+ },
19
+ limits: {
20
+ resultDepth: prepared.publicPlan.limits.result_depth,
21
+ resultNodes: prepared.publicPlan.limits.result_nodes,
22
+ exceptionBytes: Math.min(64 * 1024, prepared.publicPlan.limits.output_bytes),
23
+ },
24
+ });
25
+ const workerSide = (side, sources) => ({
26
+ modules: side.modules.map((module) => ({
27
+ alias: module.alias,
28
+ format: module.format,
29
+ dependencies: module.dependencies,
30
+ source: sources[module.alias] ?? "",
31
+ })),
32
+ entryAlias: side.entry_alias,
33
+ entryExport: side.entry_export,
34
+ });
35
+ export const commitOutcomes = (outcomes) => outcomes.map((outcome) => {
36
+ const semantic = outcome.value === undefined ? (outcome.exception ?? null) : outcome.value;
37
+ return {
38
+ case_id: outcome.case_id,
39
+ outcome: outcome.outcome,
40
+ ...(outcome.value === undefined
41
+ ? {}
42
+ : { value: jsonValueSchema.parse(outcome.value) }),
43
+ ...(outcome.exception === undefined
44
+ ? {}
45
+ : { exception: outcome.exception }),
46
+ input_sha256: outcome.input_sha256,
47
+ output_sha256: digestJson(semantic),
48
+ truncated: false,
49
+ };
50
+ });
51
+ export const compareOutcomes = (left, right) => left.map((item, index) => ({
52
+ case_id: item.case_id,
53
+ status: right[index] === undefined
54
+ ? "unknown"
55
+ : item.outcome === right[index].outcome &&
56
+ item.output_sha256 === right[index].output_sha256
57
+ ? "equal"
58
+ : "changed",
59
+ left_index: index,
60
+ right_index: index,
61
+ }));
62
+ export const terminationResult = (options) => {
63
+ const { prepared, stderr, termination, cleanup, limitation } = options;
64
+ const outcomes = prepared.publicPlan.cases.map((item) => ({
65
+ case_id: item.case_id,
66
+ outcome: termination,
67
+ input_sha256: item.sha256,
68
+ output_sha256: null,
69
+ truncated: termination === "protocol_error",
70
+ }));
71
+ const differential = prepared.publicPlan.right !== undefined;
72
+ return {
73
+ schema_version: 1,
74
+ plan_digest: prepared.publicPlan.plan_digest,
75
+ outcomes: [...outcomes, ...(differential ? outcomes : [])],
76
+ ...(differential
77
+ ? {
78
+ comparison: outcomes.map((item, index) => ({
79
+ case_id: item.case_id,
80
+ status: "unknown",
81
+ left_index: index,
82
+ right_index: index,
83
+ })),
84
+ }
85
+ : {}),
86
+ stderr,
87
+ termination,
88
+ cleanup,
89
+ limitations: [
90
+ limitation ??
91
+ `Replay terminated with ${termination}; the requested functional result remains unknown.`,
92
+ ],
93
+ reproducer: null,
94
+ };
95
+ };
@@ -0,0 +1,71 @@
1
+ import { spawn } from "node:child_process";
2
+ export const boundedCollector = (maximum) => {
3
+ const chunks = [];
4
+ let bytes = 0;
5
+ let overflow = false;
6
+ return {
7
+ append: (chunk) => {
8
+ const retained = chunk.subarray(0, Math.max(0, maximum - bytes));
9
+ if (retained.byteLength > 0)
10
+ chunks.push(retained);
11
+ bytes += retained.byteLength;
12
+ if (retained.byteLength < chunk.byteLength)
13
+ overflow = true;
14
+ },
15
+ value: () => Buffer.concat(chunks).toString("utf8"),
16
+ exceeded: () => overflow,
17
+ };
18
+ };
19
+ const collect = async (executable, arguments_, maximum) => new Promise((resolve, reject) => {
20
+ const child = spawn(executable, [...arguments_], {
21
+ stdio: ["ignore", "pipe", "pipe"],
22
+ });
23
+ const stdout = boundedCollector(maximum);
24
+ const stderr = boundedCollector(maximum);
25
+ const timeout = setTimeout(() => child.kill("SIGKILL"), 5_000);
26
+ timeout.unref();
27
+ child.stdout?.on("data", stdout.append);
28
+ child.stderr?.on("data", stderr.append);
29
+ child.once("error", (error) => {
30
+ clearTimeout(timeout);
31
+ reject(error);
32
+ });
33
+ child.once("close", (code) => {
34
+ clearTimeout(timeout);
35
+ resolve({ code, stdout: stdout.value(), stderr: stderr.value() });
36
+ });
37
+ });
38
+ export const killUnit = async (systemctl, unit) => {
39
+ try {
40
+ await collect(systemctl, ["--user", "kill", "--kill-whom=all", "--signal=SIGKILL", unit], 4096);
41
+ }
42
+ catch {
43
+ /* cleanup continues */
44
+ }
45
+ };
46
+ export const observeCleanup = async (systemctl, unit) => {
47
+ try {
48
+ const state = await collect(systemctl, ["--user", "show", "--property=ActiveState", "--value", unit], 4096);
49
+ const activeState = state.stdout.trim();
50
+ if (state.code !== 0 ||
51
+ activeState === "inactive" ||
52
+ activeState === "failed" ||
53
+ activeState.length === 0) {
54
+ await collect(systemctl, ["--user", "reset-failed", unit], 4096);
55
+ return { state: "complete", residual_resources: [] };
56
+ }
57
+ return { state: "incomplete", residual_resources: [unit] };
58
+ }
59
+ catch {
60
+ return { state: "incomplete", residual_resources: [unit] };
61
+ }
62
+ };
63
+ export const observeUnitResult = async (systemctl, unit) => {
64
+ try {
65
+ const result = await collect(systemctl, ["--user", "show", "--property=Result", "--value", unit], 4096);
66
+ return result.stdout.trim();
67
+ }
68
+ catch {
69
+ return "unknown";
70
+ }
71
+ };
@@ -0,0 +1,157 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { acceptedContent, inputRequired, inputResponse, } from "@modelcontextprotocol/server";
3
+ import { z } from "zod";
4
+ import { PermissionRequiredError } from "../domain/errors.js";
5
+ import { isPermissionRequestWithinCeiling, } from "../domain/permissionPolicy.js";
6
+ const RESPONSE_KEY = "process_capture_grant";
7
+ const STATE_VERSION = 1;
8
+ /** Shared continuation, replay, and round limits for process capture consent. */
9
+ export const PROCESS_CAPTURE_ELICITATION_POLICY = {
10
+ protocolVersions: ["2026-07-28"],
11
+ stateTtlSeconds: 600,
12
+ roundTimeoutMs: 600_000,
13
+ maxConsumedNonces: 4_096,
14
+ };
15
+ const grantResponseSchema = z.strictObject({
16
+ lifetime: z.enum(["once", "session"]).meta({ default: "session" }),
17
+ });
18
+ const grantResponseJsonSchema = { ...z.toJSONSchema(grantResponseSchema) };
19
+ // MCP elicitation accepts a reduced JSON Schema subset. These generator
20
+ // annotations do not change the schema's fields or validation semantics; the
21
+ // Standard Schema marker would make the SDK regenerate the removed keywords.
22
+ Reflect.deleteProperty(grantResponseJsonSchema, "$schema");
23
+ Reflect.deleteProperty(grantResponseJsonSchema, "additionalProperties");
24
+ const stateSchema = z.strictObject({
25
+ version: z.literal(STATE_VERSION),
26
+ nonce: z.string().uuid(),
27
+ request: z.strictObject({
28
+ capability: z.literal("process_capture"),
29
+ roots: z.array(z.string()),
30
+ executables: z.array(z.string()),
31
+ environment_names: z.array(z.string()),
32
+ origins: z.array(z.string()).optional(),
33
+ network: z.enum(["none", "loopback", "external"]),
34
+ mount: z.boolean(),
35
+ operation_identity: z.string(),
36
+ }),
37
+ });
38
+ /** Authorize capture or return a signed MCP input-required continuation. */
39
+ export const authorizeProcessCaptureWithElicitation = async (authority, request, context, elicitation) => {
40
+ const supported = elicitation.supported(context);
41
+ const initial = await authority.authorize(request, "read", {
42
+ elicitationSupported: supported,
43
+ });
44
+ if (initial.ok || !(initial.error instanceof PermissionRequiredError))
45
+ return initial;
46
+ const denied = initial.error;
47
+ if (!supported ||
48
+ denied.requested.capability !== "process_capture" ||
49
+ denied.ceiling === null ||
50
+ !isPermissionRequestWithinCeiling(denied.requested, denied.ceiling))
51
+ return initial;
52
+ const encodedState = context.mcpReq.requestState();
53
+ if (encodedState !== undefined) {
54
+ const state = stateSchema.safeParse(encodedState);
55
+ if (!state.success || !sameRequest(state.data.request, denied.requested))
56
+ return initial;
57
+ const response = inputResponse(context.mcpReq.inputResponses, RESPONSE_KEY);
58
+ if (response.kind === "elicit") {
59
+ if (!consumeNonce(elicitation.consumedNonces, state.data.nonce, elicitation.now()))
60
+ return initial;
61
+ }
62
+ if (response.kind === "elicit" && response.action === "accept") {
63
+ const content = acceptedContent(context.mcpReq.inputResponses, RESPONSE_KEY, grantResponseSchema);
64
+ if (content === undefined)
65
+ return initial;
66
+ return grantAndAuthorize(authority, state.data.request, content.lifetime);
67
+ }
68
+ if (response.kind === "elicit" &&
69
+ (response.action === "decline" || response.action === "cancel"))
70
+ return initial;
71
+ }
72
+ const state = await elicitation.stateCodec.mint({
73
+ version: STATE_VERSION,
74
+ nonce: randomUUID(),
75
+ request: {
76
+ capability: "process_capture",
77
+ roots: [...denied.requested.roots],
78
+ executables: [...denied.requested.executables],
79
+ environment_names: [...denied.requested.environment_names],
80
+ network: denied.requested.network,
81
+ mount: denied.requested.mount,
82
+ operation_identity: denied.requested.operation_identity,
83
+ ...(denied.requested.origins === undefined
84
+ ? {}
85
+ : { origins: [...denied.requested.origins] }),
86
+ },
87
+ });
88
+ return inputRequired({
89
+ inputRequests: {
90
+ [RESPONSE_KEY]: inputRequired.elicit({
91
+ message: permissionMessage(denied.requested),
92
+ requestedSchema: grantResponseJsonSchema,
93
+ }),
94
+ },
95
+ requestState: state,
96
+ });
97
+ };
98
+ const grantAndAuthorize = async (authority, request, lifetime) => {
99
+ const grant = {
100
+ ...request,
101
+ grant_id: `elicited:${randomUUID()}`,
102
+ lifetime,
103
+ operation_identity: lifetime === "once" ? request.operation_identity : null,
104
+ expires_at: null,
105
+ };
106
+ const granted = authority.grant(grant);
107
+ if (!granted.ok)
108
+ return authority.authorize(request, "read", {
109
+ elicitationSupported: true,
110
+ });
111
+ let authorized;
112
+ try {
113
+ authorized = await authority.authorize(request, "read", {
114
+ elicitationSupported: true,
115
+ });
116
+ }
117
+ catch (cause) {
118
+ authority.revoke(grant.grant_id);
119
+ throw cause;
120
+ }
121
+ if (!authorized.ok)
122
+ authority.revoke(grant.grant_id);
123
+ return authorized;
124
+ };
125
+ const sameRequest = (left, right) => left.capability === right.capability &&
126
+ left.network === right.network &&
127
+ left.mount === right.mount &&
128
+ left.operation_identity === right.operation_identity &&
129
+ sameOptionalStrings(left.origins, right.origins) &&
130
+ sameStrings(left.roots, right.roots) &&
131
+ sameStrings(left.executables, right.executables) &&
132
+ sameStrings(left.environment_names, right.environment_names);
133
+ const sameStrings = (left, right) => left.length === right.length &&
134
+ left.every((value, index) => value === right[index]);
135
+ const sameOptionalStrings = (left, right) => left === undefined
136
+ ? right === undefined
137
+ : right !== undefined && sameStrings(left, right);
138
+ const consumeNonce = (consumed, nonce, now) => {
139
+ for (const [candidate, expiresAt] of consumed)
140
+ if (expiresAt <= now)
141
+ consumed.delete(candidate);
142
+ if (consumed.has(nonce) ||
143
+ consumed.size >= PROCESS_CAPTURE_ELICITATION_POLICY.maxConsumedNonces)
144
+ return false;
145
+ consumed.set(nonce, now + PROCESS_CAPTURE_ELICITATION_POLICY.stateTtlSeconds * 1_000);
146
+ return true;
147
+ };
148
+ const permissionMessage = (request) => [
149
+ "Allow REA to run this exact process-capture scope?",
150
+ `Executable: ${request.executables.join(", ") || "none"}`,
151
+ `Filesystem roots: ${request.roots.join(", ") || "none"}`,
152
+ `Environment names: ${request.environment_names.join(", ") || "none"}`,
153
+ `Origins: ${request.origins?.join(", ") || "none"}`,
154
+ `Network: ${request.network}`,
155
+ `Mount access: ${request.mount ? "yes" : "no"}`,
156
+ "Choose whether the grant applies once or for this MCP session.",
157
+ ].join("\n");