rea-agents 3.0.0 → 3.1.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 (219) hide show
  1. package/README.md +14 -16
  2. package/dist/application/AnalysisContextQueries.js +21 -9
  3. package/dist/application/ApplicationWorkflowEvidenceResolver.js +19 -11
  4. package/dist/application/ArtifactInventory/policy.js +17 -0
  5. package/dist/application/ArtifactInventory/reader.js +1 -4
  6. package/dist/application/ArtifactInventory/scanCanonical.js +0 -3
  7. package/dist/application/ArtifactInventory/scanReader.js +7 -7
  8. package/dist/application/ArtifactInventory/types.js +1 -5
  9. package/dist/application/BinarySession.js +14 -16
  10. package/dist/application/BinarySessionRecords.js +31 -5
  11. package/dist/application/BinarySessionStatus.js +11 -5
  12. package/dist/application/BrowserEvidence.js +3 -5
  13. package/dist/application/CapabilityClientRequirements.js +26 -0
  14. package/dist/application/CapabilityInventory.js +134 -63
  15. package/dist/application/CrossVersionInventory.js +7 -6
  16. package/dist/application/ElectronActiveEvidence.js +55 -0
  17. package/dist/application/ElectronActiveObservationPort.js +1 -0
  18. package/dist/application/ElectronActiveObservationService.js +81 -0
  19. package/dist/application/EnhancedTools.js +22 -20
  20. package/dist/application/EvidenceBundleCommands.js +5 -1
  21. package/dist/application/EvidenceLedger.js +8 -1
  22. package/dist/application/JavaScriptReplayPermission.js +1 -1
  23. package/dist/application/JavaScriptReplayService.js +23 -15
  24. package/dist/application/ManagedRuntimeCorrelationService.js +9 -5
  25. package/dist/application/NodeRuntimeCharacterizationService.js +8 -9
  26. package/dist/application/ProcessCaptureLifecycle.js +5 -0
  27. package/dist/application/ProcessCli.js +2 -1
  28. package/dist/application/ProcessHarness.js +8 -3
  29. package/dist/application/ProcessNormalization.js +2 -1
  30. package/dist/application/ProjectPermissionStore.js +1 -0
  31. package/dist/application/ReferenceSourceImport.js +2 -2
  32. package/dist/application/SetupClientConfiguration.js +6 -1
  33. package/dist/application/WindowsCapabilities.js +5 -4
  34. package/dist/artifacts/ArtifactProvider.js +8 -10
  35. package/dist/artifacts/SafeOutputTree.js +7 -8
  36. package/dist/browser/CdpCaptureStorageFingerprints.js +10 -7
  37. package/dist/browser/CdpElectronInspection.js +3 -1
  38. package/dist/browser/JavaScriptRuntimeScope.js +5 -0
  39. package/dist/browser/PlaywrightElectronActiveActions.js +324 -0
  40. package/dist/browser/PlaywrightElectronActiveProvider.js +294 -0
  41. package/dist/browser/PlaywrightScenarioBrowser.js +4 -4
  42. package/dist/browser/PlaywrightScenarioSession.js +4 -4
  43. package/dist/browser/SensitiveTextCapture.js +1 -1
  44. package/dist/browser/V8InspectorCaptureProjection.js +1 -0
  45. package/dist/browser/V8InspectorProvider.js +3 -3
  46. package/dist/catalogIdentity.js +12 -6
  47. package/dist/cli/managedCommands.js +1 -1
  48. package/dist/cliApplicationCommands.js +2 -2
  49. package/dist/cliBrowserAdvancedCommands.js +11 -5
  50. package/dist/cliBrowserCommands.js +14 -7
  51. package/dist/cliCommandNames.js +1 -0
  52. package/dist/cliElectronCommands.js +46 -4
  53. package/dist/cliJavaScriptRuntimeCommands.js +14 -6
  54. package/dist/cliObservationOptions.js +4 -0
  55. package/dist/cliPolicyCommands.js +1 -0
  56. package/dist/config/browserScenario.js +77 -0
  57. package/dist/config/electronAutomation.js +35 -0
  58. package/dist/config/environment.js +6 -0
  59. package/dist/config/javascriptReplay.js +41 -0
  60. package/dist/config/managedRuntime.js +25 -0
  61. package/dist/config/parseConfig.js +56 -200
  62. package/dist/config/parsers.js +10 -1
  63. package/dist/config/passiveObservation.js +157 -0
  64. package/dist/config/processCapture.js +47 -0
  65. package/dist/contracts/applicationToolContracts.js +2 -5
  66. package/dist/contracts/applicationWorkflowInputContracts.js +86 -96
  67. package/dist/contracts/artifactToolContracts.js +27 -34
  68. package/dist/contracts/browserToolContracts.js +2 -2
  69. package/dist/contracts/electronToolContracts.js +30 -1
  70. package/dist/contracts/enhancedInputs.js +13 -29
  71. package/dist/contracts/functionWorkflowToolContracts.js +2 -3
  72. package/dist/contracts/managedToolContracts.js +4 -9
  73. package/dist/contracts/managedWorkflowExamples.js +12 -9
  74. package/dist/contracts/managedWorkflowToolContracts.js +30 -27
  75. package/dist/contracts/nativeToolContracts.js +2 -3
  76. package/dist/contracts/sessionToolSchemas.js +61 -0
  77. package/dist/contracts/toolContractExamples.js +1 -0
  78. package/dist/contracts/toolContractHelpers.js +23 -0
  79. package/dist/contracts/toolContracts.js +5 -77
  80. package/dist/contracts/toolEffects.js +15 -0
  81. package/dist/contracts/toolOutputSchemaGroups.js +17 -2
  82. package/dist/contracts/toolOutputSchemaPrimitives.js +76 -26
  83. package/dist/contracts/toolSchemaMetadata.js +128 -0
  84. package/dist/doctorRuntime.js +1 -1
  85. package/dist/domain/androidApplication.js +2 -0
  86. package/dist/domain/appleApplication.js +2 -0
  87. package/dist/domain/binaryTarget.js +7 -5
  88. package/dist/domain/binaryTargetTypes.js +1 -0
  89. package/dist/domain/browserCaptureComparison.js +21 -69
  90. package/dist/domain/browserObservation.js +22 -9
  91. package/dist/domain/bytecodeProvider.js +33 -35
  92. package/dist/domain/callPath.js +3 -2
  93. package/dist/domain/conformanceReplay.js +3 -3
  94. package/dist/domain/conformanceTrustGate.js +151 -16
  95. package/dist/domain/customProtocolCapture.js +3 -3
  96. package/dist/domain/electronActiveObservation.js +277 -0
  97. package/dist/domain/electronObservation.js +15 -11
  98. package/dist/domain/electronStaticAnalysisValues.js +4 -1
  99. package/dist/domain/eventProcessTree.js +82 -79
  100. package/dist/domain/functionComparisonNormalization.js +15 -8
  101. package/dist/domain/functionDossierEvidence.js +9 -4
  102. package/dist/domain/hopperValues.js +68 -71
  103. package/dist/domain/inputIssueProjection.js +4 -1
  104. package/dist/domain/investigationWorkspace.js +16 -15
  105. package/dist/domain/javascriptExportShapeComparisonSchemas.js +2 -2
  106. package/dist/domain/javascriptReplay.js +79 -63
  107. package/dist/domain/javascriptRuntimeObservation.js +1 -0
  108. package/dist/domain/javascriptRuntimeReconciliationActive.js +89 -0
  109. package/dist/domain/javascriptRuntimeReconciliationGraph.js +11 -10
  110. package/dist/domain/javascriptRuntimeReconciliationMatching.js +57 -49
  111. package/dist/domain/javascriptRuntimeReconciliationParsing.js +5 -1
  112. package/dist/domain/javascriptRuntimeReconciliationResult.js +21 -14
  113. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
  114. package/dist/domain/knownPageCoverage.js +15 -7
  115. package/dist/domain/nativeApiBoundary.js +15 -7
  116. package/dist/domain/nodeRuntimeCharacterization.js +14 -13
  117. package/dist/domain/processCaptureReactiveValidation.js +8 -3
  118. package/dist/domain/processCaptureValidation.js +7 -3
  119. package/dist/domain/processComparison.js +12 -7
  120. package/dist/domain/processObservation.js +5 -6
  121. package/dist/domain/processReactiveMatching.js +14 -7
  122. package/dist/domain/processReactiveTransition.js +9 -3
  123. package/dist/domain/processScenario.js +6 -3
  124. package/dist/domain/processTraceComparison.js +3 -2
  125. package/dist/domain/protocolCapture.js +8 -6
  126. package/dist/domain/reconstructionReadinessSchemas.js +30 -2
  127. package/dist/domain/referenceSourceImportParsing.js +2 -2
  128. package/dist/domain/replayMachineRuntime.js +5 -3
  129. package/dist/domain/sourceToBundleComparison.js +2 -2
  130. package/dist/domain/sourceToBundleComparisonSchemas.js +8 -8
  131. package/dist/domain/sourceToBundleSignals.js +7 -1
  132. package/dist/domain/staticRuntimeCorrelation.js +7 -5
  133. package/dist/domain/webBundleAnalysis.js +14 -14
  134. package/dist/domain/webCaptureDiff.js +15 -12
  135. package/dist/dotnet/ManagedNativeBoundaryInspector.js +2 -3
  136. package/dist/generatedMcpToolCatalog.js +1 -1
  137. package/dist/generatedPackageMetadata.js +1 -1
  138. package/dist/ghidra/GhidraClient.js +1 -1
  139. package/dist/ghidra/GhidraClientStartup.js +1 -1
  140. package/dist/ghidra/GhidraFunctionValues.js +17 -15
  141. package/dist/ghidra/GhidraInventoryValues.js +57 -47
  142. package/dist/ghidra/GhidraProvider.js +18 -10
  143. package/dist/ghidra/GhidraProviderCapabilities.js +5 -1
  144. package/dist/ghidra/GhidraSocketConnection.js +1 -1
  145. package/dist/ghidra/protocol.js +19 -42
  146. package/dist/hopper/BridgeLauncher.js +3 -1
  147. package/dist/hopper/HopperAnalysisProfile.js +2 -4
  148. package/dist/hopper/HopperCleanup.js +5 -6
  149. package/dist/hopper/HopperClient.js +1 -1
  150. package/dist/hopper/HopperProvider.js +0 -14
  151. package/dist/hopper/LinuxPrivateDisplayProbe.js +16 -10
  152. package/dist/main/reload.js +1 -6
  153. package/dist/main/state.js +0 -14
  154. package/dist/main/transport.js +30 -37
  155. package/dist/main.js +17 -15
  156. package/dist/mcpDoctor.js +2 -24
  157. package/dist/process/PrivateRuntimeRoot.js +17 -0
  158. package/dist/process/ProcessOwnership.js +64 -128
  159. package/dist/process/ProcessOwnershipIdentity.js +13 -0
  160. package/dist/process/ProcessOwnershipObservation.js +88 -0
  161. package/dist/process/ProcessOwnershipProcessTree.js +22 -0
  162. package/dist/process/ProviderDeadline.js +8 -12
  163. package/dist/process/WindowsAuthority.js +32 -0
  164. package/dist/reference/ReferenceSourceReader.js +3 -3
  165. package/dist/reference/ReferenceSourceReaderEntries.js +2 -2
  166. package/dist/replay/JavaScriptReplayWorker.js +95 -11
  167. package/dist/replay/JavaScriptReplayWorkerTypes.js +1 -0
  168. package/dist/replay/LinuxJavaScriptReplayRunner.js +10 -15
  169. package/dist/replay/ReplayOutcome.js +26 -15
  170. package/dist/replay/ReplayWorkerProtocol.js +34 -29
  171. package/dist/server/createServer.js +158 -94
  172. package/dist/server/mcpClientMetadata.js +32 -0
  173. package/dist/server/registerApplicationTools/characterization.js +6 -13
  174. package/dist/server/registerApplicationTools/compareExportShapes.js +2 -7
  175. package/dist/server/registerApplicationTools/compareSourceToBundle.js +2 -7
  176. package/dist/server/registerApplicationTools/compareVersions.js +3 -8
  177. package/dist/server/registerApplicationTools/controlledReplay.js +6 -11
  178. package/dist/server/registerApplicationTools/coverage.js +13 -19
  179. package/dist/server/registerApplicationTools/obligationLedger.js +1 -6
  180. package/dist/server/registerApplicationTools/readiness.js +1 -6
  181. package/dist/server/registerApplicationTools/traceFeature.js +3 -8
  182. package/dist/server/registerApplicationTools/traceSemantics.js +1 -6
  183. package/dist/server/registerArtifactComparisonTool.js +12 -16
  184. package/dist/server/registerBrowserScenarioTool.js +1 -6
  185. package/dist/server/registerBrowserTools.js +37 -79
  186. package/dist/server/registerBundleComparisonTool.js +10 -14
  187. package/dist/server/registerCloseLifecycleTool.js +6 -14
  188. package/dist/server/registerElectronTools.js +30 -47
  189. package/dist/server/registerEnhancedTools.js +114 -122
  190. package/dist/server/registerEvidenceTools.js +5 -9
  191. package/dist/server/registerFunctionComparisonTool.js +11 -15
  192. package/dist/server/registerInvestigationTools.js +41 -57
  193. package/dist/server/registerJavaScriptRuntimeObservationTools.js +13 -27
  194. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +4 -9
  195. package/dist/server/registerManagedWorkflowTools/contract.js +2 -3
  196. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +3 -8
  197. package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +3 -8
  198. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +8 -13
  199. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +4 -9
  200. package/dist/server/registerOfficialTools.js +8 -9
  201. package/dist/server/registerProcessComparisonTool.js +19 -24
  202. package/dist/server/registerReplayMachineTool.js +4 -10
  203. package/dist/server/registerSessionRecordTools.js +69 -40
  204. package/dist/server/registerSessionStatusTool.js +13 -28
  205. package/dist/server/registerSessionTools.js +36 -52
  206. package/dist/server/sessionAvailabilityPolicy.js +2 -1
  207. package/dist/server/sessionToolPolicies.js +1 -5
  208. package/dist/server/toolRegistrationOptions.js +4 -192
  209. package/dist/server/toolResult.js +2 -18
  210. package/package.json +22 -14
  211. package/scripts/electron-active-hook-boundaries.cjs +394 -0
  212. package/scripts/electron-active-hook.cjs +501 -0
  213. package/scripts/rea.mjs +1 -11
  214. package/skills/reverse-engineer-anything/SKILL.md +2 -2
  215. package/dist/server/DynamicToolAvailability.js +0 -70
  216. package/dist/server/LazyToolCatalog.js +0 -134
  217. package/dist/server/hydrateServerTools.js +0 -191
  218. package/dist/server/toolInputValidation.js +0 -77
  219. package/scripts/package-runner-bootstrap.mjs +0 -72
@@ -0,0 +1,294 @@
1
+ import { realpath } from "node:fs/promises";
2
+ import { randomUUID } from "node:crypto";
3
+ import { fileURLToPath } from "node:url";
4
+ import { _electron as electron } from "playwright-core";
5
+ import { electronActiveObservationResultSchema, } from "../domain/electronActiveObservation.js";
6
+ import { AnalysisError, BrowserObservationError, ProviderAdapterError, } from "../domain/errors.js";
7
+ import { isPathContained } from "../domain/permissionPolicy.js";
8
+ import { err, ok } from "../domain/result.js";
9
+ import { cleanupOwnedProcessGroup, cleanupWindowsProcessTree, observeOwnedProcessLineage, selectCapturedProcessGroupIds, verifyNoTokenOwnedProcesses, } from "../process/ProcessOwnership.js";
10
+ import { runElectronActions, readApplicationState, runWithExecutionLimits, } from "./PlaywrightElectronActiveActions.js";
11
+ const OPERATION = "capture_electron_scenario";
12
+ /** Public identity for provider-owned Electron runtime experiments. */
13
+ export const PLAYWRIGHT_ELECTRON_ACTIVE_PROVIDER_IDENTITY = Object.freeze({
14
+ id: "rea-playwright-electron-active",
15
+ name: "REA Playwright active Electron observation provider",
16
+ version: "1",
17
+ });
18
+ const hookPath = fileURLToPath(new URL("../../scripts/electron-active-hook.cjs", import.meta.url));
19
+ const observableEventFamilies = [
20
+ "app-lifecycle",
21
+ "window-lifecycle",
22
+ "web-contents-lifecycle",
23
+ "navigation",
24
+ "shell-attempt",
25
+ "process-lifecycle",
26
+ "permission",
27
+ "popup-attempt",
28
+ "download",
29
+ "protocol",
30
+ "preload",
31
+ "preload-configuration",
32
+ "renderer-ipc",
33
+ "native-addon",
34
+ "updater",
35
+ "error",
36
+ "ipc",
37
+ ];
38
+ const ipcEventKinds = new Set([
39
+ "main-handler-invocation",
40
+ "main-event-invocation",
41
+ "utility-process-fork",
42
+ "utility-process-message",
43
+ "ipc-main-to-renderer",
44
+ "ipc-utility-to-main",
45
+ "ipc-renderer-send",
46
+ "ipc-renderer-invoke",
47
+ "ipc-renderer-post-message",
48
+ ]);
49
+ const createCoverage = (hookSnapshot) => {
50
+ const observedEventFamilies = [
51
+ ...new Set(hookSnapshot.events.map(({ kind, process_type }) => {
52
+ if (kind === "preload" && process_type === "main")
53
+ return "preload-configuration";
54
+ if (kind.startsWith("ipc-renderer") && process_type !== "renderer")
55
+ return "ipc";
56
+ return ipcEventKinds.has(kind) ? "ipc" : kind;
57
+ })),
58
+ ].sort();
59
+ const unavailableEventFamilies = new Set(observableEventFamilies.filter((family) => !observedEventFamilies.includes(family)));
60
+ const observedRoles = [
61
+ ...new Set(hookSnapshot.events.flatMap(({ process_type, kind }) => [
62
+ ...(process_type === null ? [] : [process_type]),
63
+ ...(kind === "window-lifecycle" ? ["window"] : []),
64
+ ...(kind === "web-contents-lifecycle" || kind === "navigation"
65
+ ? ["web_contents"]
66
+ : []),
67
+ ...(kind === "preload" && process_type === "preload"
68
+ ? ["preload"]
69
+ : []),
70
+ ...(kind.startsWith("ipc-renderer") && process_type === "renderer"
71
+ ? ["renderer"]
72
+ : []),
73
+ ])),
74
+ ].sort();
75
+ const rendererContextObserved = hookSnapshot.events.some(({ process_type }) => process_type === "renderer" || process_type === "preload");
76
+ if (!rendererContextObserved) {
77
+ unavailableEventFamilies.add("preload");
78
+ unavailableEventFamilies.add("renderer-ipc");
79
+ }
80
+ return {
81
+ status: hookSnapshot.hook_error
82
+ ? "hook_conflict"
83
+ : hookSnapshot.truncated
84
+ ? "capture_truncated"
85
+ : "partial_attach",
86
+ observed_event_families: observedEventFamilies,
87
+ unavailable_event_families: [...unavailableEventFamilies].sort(),
88
+ observed_roles: observedRoles,
89
+ pre_capture_activity: "unavailable",
90
+ };
91
+ };
92
+ /** Launch an owned Electron application through the official Playwright API. */
93
+ export class PlaywrightElectronActiveProvider {
94
+ identity() {
95
+ return PLAYWRIGHT_ELECTRON_ACTIVE_PROVIDER_IDENTITY;
96
+ }
97
+ async capture(input, options = {}) {
98
+ let application;
99
+ let ownership;
100
+ let lineage;
101
+ let outcome;
102
+ const runId = randomUUID();
103
+ try {
104
+ if (options.signal?.aborted === true)
105
+ throw new BrowserObservationError(OPERATION, "cancelled");
106
+ const deadline = Date.now() + input.limits.max_duration_ms;
107
+ const paths = await canonicalPaths(input);
108
+ application = await electron.launch({
109
+ executablePath: paths.executable,
110
+ cwd: paths.root,
111
+ env: safeElectronEnvironment(input.limits.max_ipc_events, input.limits.max_runtime_events, runId),
112
+ args: ["-r", hookPath, paths.application, ...input.args],
113
+ timeout: Math.max(1, deadline - Date.now()),
114
+ });
115
+ const leaderPid = application.process().pid;
116
+ if (typeof leaderPid !== "number" ||
117
+ !Number.isSafeInteger(leaderPid) ||
118
+ leaderPid <= 0)
119
+ throw new BrowserObservationError(OPERATION, "process_ownership_unavailable");
120
+ ownership = {
121
+ runId,
122
+ leaderPid,
123
+ processGroupId: leaderPid,
124
+ expectedParentPid: process.pid,
125
+ expectedCommand: paths.executable,
126
+ sweepTokenOwnedProcesses: true,
127
+ };
128
+ const actions = await runElectronActions(application, input, options, deadline);
129
+ const state = await runWithExecutionLimits(readApplicationState(application, input.limits.max_windows), options.signal, deadline);
130
+ outcome = ok(createResult(paths, input, actions, state));
131
+ }
132
+ catch (cause) {
133
+ outcome = err(providerError(cause));
134
+ }
135
+ if (application !== undefined) {
136
+ if (ownership !== undefined)
137
+ lineage = await observeOwnedProcessLineage(ownership);
138
+ let closeError;
139
+ try {
140
+ await runWithExecutionLimits(application.close(), undefined, Date.now() + 5_000);
141
+ }
142
+ catch (cause) {
143
+ closeError = cause;
144
+ }
145
+ const cleanup = ownership === undefined
146
+ ? {
147
+ cleaned: false,
148
+ reason: "owned Electron process identity was unavailable",
149
+ }
150
+ : await cleanupElectronProcesses(ownership, lineage);
151
+ if (!cleanup.cleaned)
152
+ return err(providerError(new BrowserObservationError(OPERATION, "cleanup_failed", {
153
+ cause: new Error(cleanup.reason),
154
+ })));
155
+ if (closeError !== undefined)
156
+ return err(providerError(closeError));
157
+ }
158
+ return outcome;
159
+ }
160
+ }
161
+ const cleanupElectronProcesses = async (ownership, lineage) => {
162
+ if (process.platform === "win32") {
163
+ const root = await cleanupWindowsProcessTree(ownership.leaderPid);
164
+ if (!root.cleaned)
165
+ return root;
166
+ if (lineage?.status !== "verified")
167
+ return {
168
+ cleaned: false,
169
+ reason: "owned Electron lineage was unavailable; helper cleanup was not proven",
170
+ };
171
+ for (const descendant of lineage.lineage.descendants) {
172
+ const result = await cleanupWindowsProcessTree(descendant.pid);
173
+ if (!result.cleaned)
174
+ return result;
175
+ }
176
+ return root;
177
+ }
178
+ if (lineage?.status !== "verified") {
179
+ const root = await cleanupOwnedProcessGroup(ownership);
180
+ return root.cleaned
181
+ ? {
182
+ cleaned: false,
183
+ reason: "owned Electron lineage was unavailable; helper cleanup was not proven",
184
+ }
185
+ : root;
186
+ }
187
+ const groupIds = selectCapturedProcessGroupIds(ownership.leaderPid, lineage.lineage.descendants.map(({ pid, processGroupId }) => ({
188
+ pid,
189
+ process_group_id: processGroupId,
190
+ })));
191
+ let signaled = false;
192
+ for (const processGroupId of groupIds) {
193
+ const cleanupOwnership = processGroupId === ownership.processGroupId
194
+ ? { ...ownership, leaderPid: processGroupId, processGroupId }
195
+ : {
196
+ runId: ownership.runId,
197
+ leaderPid: processGroupId,
198
+ processGroupId,
199
+ };
200
+ const result = await cleanupOwnedProcessGroup(cleanupOwnership);
201
+ if (!result.cleaned)
202
+ return result;
203
+ signaled ||= result.signaled;
204
+ }
205
+ const remaining = await verifyNoTokenOwnedProcesses(ownership.runId);
206
+ if (!remaining.cleaned)
207
+ return remaining;
208
+ return { cleaned: true, signaled };
209
+ };
210
+ const createResult = (paths, input, actions, state) => {
211
+ const { hookSnapshot } = state;
212
+ const ipcEvents = hookSnapshot.events.filter(({ kind }) => ipcEventKinds.has(kind));
213
+ return electronActiveObservationResultSchema.parse({
214
+ schema_version: 1,
215
+ application: {
216
+ executable_path: paths.executable,
217
+ application_path: paths.application,
218
+ electron_version: state.electronVersion,
219
+ process_ownership: "provider-owned",
220
+ cleanup: "terminated-owned-process",
221
+ },
222
+ actions,
223
+ windows: state.windows.slice(0, input.limits.max_windows),
224
+ windows_truncated: state.windowsTruncated,
225
+ processes: {
226
+ items: state.metrics.slice(0, input.limits.max_processes),
227
+ truncated: state.metrics.length > input.limits.max_processes,
228
+ },
229
+ ipc: {
230
+ events: ipcEvents.slice(0, input.limits.max_ipc_events),
231
+ observed: hookSnapshot.observed_ipc,
232
+ retained: Math.min(ipcEvents.length, input.limits.max_ipc_events),
233
+ truncated: hookSnapshot.truncated ||
234
+ ipcEvents.length > input.limits.max_ipc_events,
235
+ },
236
+ timeline: {
237
+ events: hookSnapshot.events.slice(0, input.limits.max_runtime_events),
238
+ observed: hookSnapshot.observed,
239
+ retained: Math.min(hookSnapshot.events.length, input.limits.max_runtime_events),
240
+ truncated: hookSnapshot.truncated ||
241
+ hookSnapshot.events.length > input.limits.max_runtime_events,
242
+ },
243
+ coverage: createCoverage(hookSnapshot),
244
+ limitations: [
245
+ "IPC payloads are represented only by bounded value shapes; values are never retained, channels are capped at 1,024 characters, and argument-shape arrays at 32 entries.",
246
+ "IPC direction and sender/receiver identifiers are observed only where Electron exposes them at the hooked boundary.",
247
+ "The runtime timeline records bounded lifecycle, navigation, shell, permission, popup, download, protocol, preload, native-addon, process, and IPC events; activity before hook installation is unavailable.",
248
+ "The preload and renderer process contexts are not instrumented by the main-process -r hook; preload configuration and contextBridge API-shape events are main-boundary observations, not proof of renderer-side execution.",
249
+ "Process metrics are an Electron API snapshot and do not prove hostile-local-user isolation.",
250
+ "External shell opens, external navigation, permission grants, downloads, popup windows, updater relaunches, and OS integration are blocked and recorded by the active hook; other application filesystem and network behavior is not sandboxed by this provider.",
251
+ ...(state.windowsTruncated
252
+ ? ["Windows beyond max_windows were not retained."]
253
+ : []),
254
+ ...(hookSnapshot.hook_error
255
+ ? ["The active IPC hook could not be installed."]
256
+ : []),
257
+ ],
258
+ });
259
+ };
260
+ const canonicalPaths = async (input) => {
261
+ const [executable, application, root] = await Promise.all([
262
+ realpath(input.executable_path),
263
+ realpath(input.application_path),
264
+ realpath(input.application_root),
265
+ ]);
266
+ if (!isPathContained(root, application))
267
+ throw new BrowserObservationError(OPERATION, "target_not_allowed");
268
+ return { executable, application, root };
269
+ };
270
+ const safeElectronEnvironment = (maxIpcEvents, maxRuntimeEvents, runId) => Object.fromEntries([
271
+ ...[
272
+ "HOME",
273
+ "LANG",
274
+ "PATH",
275
+ "TMP",
276
+ "TMPDIR",
277
+ "USER",
278
+ "DISPLAY",
279
+ "WAYLAND_DISPLAY",
280
+ ]
281
+ .map((name) => [name, process.env[name]])
282
+ .filter((entry) => entry[1] !== undefined),
283
+ ["REA_ELECTRON_ACTIVE_MAX_IPC_EVENTS", String(maxIpcEvents)],
284
+ [
285
+ "REA_ELECTRON_ACTIVE_MAX_RUNTIME_EVENTS",
286
+ String(maxRuntimeEvents),
287
+ ],
288
+ ["REA_PROCESS_RUN_ID", runId],
289
+ ]);
290
+ const providerError = (cause) => cause instanceof AnalysisError
291
+ ? cause
292
+ : new ProviderAdapterError(PLAYWRIGHT_ELECTRON_ACTIVE_PROVIDER_IDENTITY.id, OPERATION, {
293
+ cause,
294
+ });
@@ -89,9 +89,9 @@ export const openPlaywrightScenarioBrowser = async (scenario, environment, maxim
89
89
  await configureAttachedEnvironment(target.context, target.page, scenario);
90
90
  return { ...target, browser, profilePath: undefined };
91
91
  }
92
- catch (error) {
92
+ catch (cause) {
93
93
  await browser.close();
94
- throw error;
94
+ throw cause;
95
95
  }
96
96
  }
97
97
  const profilePath = await mkdtemp(join(tmpdir(), "rea-browser-scenario-"));
@@ -125,9 +125,9 @@ export const openPlaywrightScenarioBrowser = async (scenario, environment, maxim
125
125
  const page = context.pages()[0] ?? (await context.newPage());
126
126
  return { context, page, browser, profilePath };
127
127
  }
128
- catch (error) {
128
+ catch (cause) {
129
129
  await rm(profilePath, { recursive: true, force: true, maxRetries: 3 });
130
- throw error;
130
+ throw cause;
131
131
  }
132
132
  };
133
133
  export const closePlaywrightScenarioBrowser = async ({ context, browser, profilePath, }) => {
@@ -201,11 +201,11 @@ export class PlaywrightScenarioSession {
201
201
  try {
202
202
  opened = await withPlaywrightExecutionBoundary(() => opening, remaining(), options.signal);
203
203
  }
204
- catch (error) {
204
+ catch (cause) {
205
205
  void opening
206
206
  .then((lateOpened) => closePlaywrightScenarioBrowser(lateOpened))
207
207
  .catch(() => undefined);
208
- throw error;
208
+ throw cause;
209
209
  }
210
210
  try {
211
211
  await withPlaywrightExecutionBoundary(() => initializePage(opened.context, opened.page, scenario, secrets), remaining(), options.signal);
@@ -224,9 +224,9 @@ export class PlaywrightScenarioSession {
224
224
  }), remaining(), options.signal);
225
225
  return session;
226
226
  }
227
- catch (error) {
227
+ catch (cause) {
228
228
  await closePlaywrightScenarioBrowser(opened);
229
- throw error;
229
+ throw cause;
230
230
  }
231
231
  }
232
232
  currentUrl() {
@@ -1,4 +1,4 @@
1
- const SECRET_ASSIGNMENT = /\b(authorization|api[_-]?key|access[_-]?token|refresh[_-]?token|password|passwd|secret|cookie|session)\b\s*[:=]\s*(?:Bearer\s+[A-Za-z0-9._~+/=-]+|"[^"]*"|'[^']*'|[^\s,;]+)/giu;
1
+ const SECRET_ASSIGNMENT = /\b(authorization|api[_-]?key|access[_-]?token|refresh[_-]?token|token|password|passwd|secret|cookie|session)\b\s*[:=]\s*(?:Bearer\s+[A-Za-z0-9._~+/=-]+|"[^"]*"|'[^']*'|[^\s,;]+)/giu;
2
2
  const BEARER = /\bBearer\s+[A-Za-z0-9._~+/=-]+/giu;
3
3
  const JWT = /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/gu;
4
4
  /** Redact credential-shaped substrings before approved console text is retained. */
@@ -11,6 +11,7 @@ export const describeInspectorTargetLimitations = () => [
11
11
  "REA attaches to an already-running exact target and never launches, resumes, evaluates, pauses, or mutates it.",
12
12
  "Only Runtime.enable and Debugger.enable are sent; source text, object values, EventEmitter activity, and Electron IPC are not inspected.",
13
13
  "Target IDs and locations are authorized, but the Inspector protocol does not authenticate an operating-system process ID or Electron role.",
14
+ "Some Electron main targets report only file://; for those targets, the first approved file root is recorded as a scope fallback and script locations are authorized independently.",
14
15
  "No runtime graph depth is traversed because passive Inspector events do not establish require/import caller edges.",
15
16
  ];
16
17
  /** Canonically authorize, deduplicate, and sort one bounded raw capture. */
@@ -3,7 +3,7 @@ import { AnalysisError, BrowserObservationError, ProviderAdapterError, } from ".
3
3
  import { err, ok } from "../domain/result.js";
4
4
  import { boundedText, numberValue, recordValue, stringValue, delayWithCancellation, } from "./CdpCaptureValues.js";
5
5
  import { CdpConnection } from "./CdpConnection.js";
6
- import { authorizeRuntimeLocation, canonicalRuntimeRoots, } from "./JavaScriptRuntimeScope.js";
6
+ import { authorizeRuntimeTargetLocation, canonicalRuntimeRoots, } from "./JavaScriptRuntimeScope.js";
7
7
  import { createInspectorExclusionCounts, describeInspectorTargetLimitations, finalizeInspectorCapture, } from "./V8InspectorCaptureProjection.js";
8
8
  import { discoverV8Inspector, } from "./V8InspectorEndpoint.js";
9
9
  /** Public identity committed by passive V8 Inspector observations. */
@@ -24,7 +24,7 @@ export class V8InspectorProvider {
24
24
  const allowed = [];
25
25
  const excluded = createInspectorExclusionCounts();
26
26
  for (const target of discovery.targets) {
27
- const decision = await authorizeRuntimeLocation(target.url, roots, input.allowed_origins);
27
+ const decision = await authorizeRuntimeTargetLocation(target.url, target.type, roots, input.allowed_origins);
28
28
  if (!decision.allowed) {
29
29
  excluded[decision.reason] += 1;
30
30
  continue;
@@ -104,7 +104,7 @@ const authorizedTarget = async (targets, input, roots) => {
104
104
  const target = targets.find(({ id }) => id === input.target_id);
105
105
  if (target === undefined)
106
106
  throw new BrowserObservationError("observe_javascript_runtime", "target_not_found");
107
- const decision = await authorizeRuntimeLocation(target.url, roots, input.allowed_origins);
107
+ const decision = await authorizeRuntimeTargetLocation(target.url, target.type, roots, input.allowed_origins);
108
108
  if (target.attached ||
109
109
  !decision.allowed ||
110
110
  decision.location.kind === "builtin")
@@ -12,12 +12,18 @@ const toolCatalog = TOOL_CONTRACTS.map((contract) => ({
12
12
  description: contract.description,
13
13
  effects: { ...contract.effects },
14
14
  annotations: contract.annotations,
15
- input_schema: z.toJSONSchema(contract.inputSchema, {
16
- unrepresentable: "any",
17
- }),
18
- output_schema: z.toJSONSchema(contract.outputSchema, {
19
- unrepresentable: "any",
20
- }),
15
+ input_schema: {
16
+ type: "object",
17
+ ...z.toJSONSchema(contract.inputSchema, {
18
+ unrepresentable: "any",
19
+ }),
20
+ },
21
+ output_schema: {
22
+ type: "object",
23
+ ...z.toJSONSchema(contract.outputSchema, {
24
+ unrepresentable: "any",
25
+ }),
26
+ },
21
27
  })).sort((left, right) => left.name.localeCompare(right.name));
22
28
  const promptCatalog = PROMPT_CONTRACTS.map((contract) => ({
23
29
  name: contract.name,
@@ -388,7 +388,7 @@ const registerPlanManagedRuntimeCorrelation = (cli, logger) => {
388
388
  if (!authority.ok)
389
389
  return projectAnalysisError(authority.error);
390
390
  const result = await planManagedRuntimeCorrelationEvidence({
391
- policy: config.value.managedRuntimePolicy,
391
+ policy: () => config.value.managedRuntimePolicy,
392
392
  authority: authority.value,
393
393
  }, input.value);
394
394
  return result.ok ? result.value : projectAnalysisError(result.error);
@@ -75,7 +75,7 @@ export const registerApplicationCommands = (cli, logger) => {
75
75
  if (!authority.ok)
76
76
  return projectAnalysisError(authority.error);
77
77
  const result = await runControlledReplay({
78
- policy: config.value.javascriptReplayPolicy,
78
+ policy: () => config.value.javascriptReplayPolicy,
79
79
  host: new SystemJavaScriptReplayHost(),
80
80
  runner: new LinuxJavaScriptReplayRunner(),
81
81
  authority: authority.value,
@@ -193,7 +193,7 @@ const configuredAuthority = async () => {
193
193
  : { ok: false, error: projectAnalysisError(configured.error) };
194
194
  };
195
195
  const replayDependencies = (config, authority) => ({
196
- policy: config.javascriptReplayPolicy,
196
+ policy: () => config.javascriptReplayPolicy,
197
197
  host: new SystemJavaScriptReplayHost(),
198
198
  runner: new LinuxJavaScriptReplayRunner(),
199
199
  authority,
@@ -4,7 +4,7 @@ import { loadConfiguredPermissionAuthority } from "./application/PermissionConfi
4
4
  import { CdpBrowserProvider } from "./browser/CdpBrowserProvider.js";
5
5
  import { logCliCommand } from "./cliLogging.js";
6
6
  import { parseConfig } from "./config.js";
7
- import { AnalysisInputError, projectAnalysisError } from "./domain/errors.js";
7
+ import { AnalysisCapabilityUnavailableError, AnalysisInputError, projectAnalysisError, } from "./domain/errors.js";
8
8
  import { browserCaptureComparisonInputSchema } from "./domain/browserCaptureComparison.js";
9
9
  import { discoverWebMcpToolsInputSchema } from "./domain/webMcpDiscovery.js";
10
10
  import { captureWebScreenshotInputSchema, compareWebScreenshotsInputSchema, } from "./domain/webScreenshot.js";
@@ -69,7 +69,7 @@ const registerWebMcp = (cli, logger) => {
69
69
  .describe("Maximum nesting depth in one declared tool schema"),
70
70
  }),
71
71
  run: ({ args, options }) => logCliCommand(logger, "discover-webmcp-tools", async () => {
72
- const context = await browserContext();
72
+ const context = await browserContext("discover_webmcp_tools");
73
73
  if (!context.ok)
74
74
  return context.error;
75
75
  const parsed = discoverWebMcpToolsInputSchema.safeParse({
@@ -155,7 +155,7 @@ const registerScreenshot = (cli, logger) => {
155
155
  .describe("Maximum captured PNG size"),
156
156
  }),
157
157
  run: ({ args, options }) => logCliCommand(logger, "capture-web-screenshot", async () => {
158
- const context = await browserContext();
158
+ const context = await browserContext("capture_web_screenshot");
159
159
  if (!context.ok)
160
160
  return context.error;
161
161
  const parsed = captureWebScreenshotInputSchema.safeParse({
@@ -210,10 +210,16 @@ const registerScreenshotDiff = (cli, logger) => {
210
210
  }),
211
211
  });
212
212
  };
213
- const browserContext = async () => {
213
+ const browserContext = async (operation) => {
214
214
  const config = parseConfig(process.env);
215
215
  if (!config.ok)
216
216
  return { ok: false, error: cliError(config.error) };
217
+ const policy = config.value.browserObservationPolicy;
218
+ if (policy.status === "disabled")
219
+ return {
220
+ ok: false,
221
+ error: cliError(new AnalysisCapabilityUnavailableError("rea-cdp-browser", operation, "browser observation is disabled; configure exact endpoints and origins before enabling it")),
222
+ };
217
223
  const authority = await loadConfiguredPermissionAuthority(config.value);
218
224
  if (!authority.ok)
219
225
  return { ok: false, error: cliError(authority.error) };
@@ -221,7 +227,7 @@ const browserContext = async () => {
221
227
  ok: true,
222
228
  authority: authority.value,
223
229
  provider: new CdpBrowserProvider(),
224
- allowedBrowserOrigins: config.value.browserAllowedOrigins,
230
+ allowedBrowserOrigins: policy.allowedOrigins,
225
231
  };
226
232
  };
227
233
  const parseJson = (value) => {
@@ -7,7 +7,7 @@ import { parseConfig } from "./config.js";
7
7
  import { inspectWebPageInputSchema, listBrowserTargetsInputSchema, } from "./domain/browserObservation.js";
8
8
  import { analyzeWebBundleInputSchema } from "./domain/webBundleAnalysis.js";
9
9
  import { observeWebSessionInputSchema } from "./domain/browserSession.js";
10
- import { AnalysisInputError, projectAnalysisError } from "./domain/errors.js";
10
+ import { AnalysisCapabilityUnavailableError, AnalysisInputError, projectAnalysisError, } from "./domain/errors.js";
11
11
  import { CLI_COMMANDS } from "./cliCommandNames.js";
12
12
  import { browserPageInspectionOptions } from "./cliObservationOptions.js";
13
13
  const browserScopeOptions = {
@@ -49,7 +49,7 @@ const registerTargetList = (cli, logger) => {
49
49
  limit: boundedCount("browser targets to return", 200, 100),
50
50
  }),
51
51
  run: ({ args, options }) => logCliCommand(logger, "list-browser-targets", async () => {
52
- const context = await browserContext();
52
+ const context = await browserContext("list_browser_targets");
53
53
  if (!context.ok)
54
54
  return context.error;
55
55
  const parsed = listBrowserTargetsInputSchema.safeParse({
@@ -75,7 +75,7 @@ const registerPageInspection = (cli, logger) => {
75
75
  }),
76
76
  options: browserPageInspectionOptions,
77
77
  run: ({ args, options }) => logCliCommand(logger, "inspect-web-page", async () => {
78
- const context = await browserContext();
78
+ const context = await browserContext("inspect_web_page");
79
79
  if (!context.ok)
80
80
  return context.error;
81
81
  const parsed = inspectWebPageInputSchema.safeParse({
@@ -92,6 +92,7 @@ const registerPageInspection = (cli, logger) => {
92
92
  include_websocket_shapes: options.includeWebsocketShapes,
93
93
  websocket_shape_approved: options.websocketShapeApproved,
94
94
  include_script_sources: options.includeScriptSources,
95
+ source_capture_approved: options.sourceCaptureApproved,
95
96
  include_storage_keys: options.includeStorageKeys,
96
97
  include_storage_fingerprints: options.includeStorageFingerprints,
97
98
  limits: {
@@ -157,7 +158,7 @@ const registerBundleAnalysis = (cli, logger) => {
157
158
  maxOriginalSources: boundedCount("original source files", 20_000, 2_000),
158
159
  }),
159
160
  run: ({ args, options }) => logCliCommand(logger, "analyze-web-bundle", async () => {
160
- const context = await browserContext();
161
+ const context = await browserContext("analyze_web_bundle");
161
162
  if (!context.ok)
162
163
  return context.error;
163
164
  const parsed = analyzeWebBundleInputSchema.safeParse({
@@ -200,7 +201,7 @@ const registerObservationSession = (cli, logger) => {
200
201
  maxTimelineEvents: boundedCount("timeline events", 20_000, 2_000),
201
202
  }),
202
203
  run: ({ args, options }) => logCliCommand(logger, "observe-web-session", async () => {
203
- const context = await browserContext();
204
+ const context = await browserContext("observe_web_session");
204
205
  if (!context.ok)
205
206
  return context.error;
206
207
  const parsed = observeWebSessionInputSchema.safeParse({
@@ -218,10 +219,16 @@ const registerObservationSession = (cli, logger) => {
218
219
  }),
219
220
  });
220
221
  };
221
- const browserContext = async () => {
222
+ const browserContext = async (operation) => {
222
223
  const config = parseConfig(process.env);
223
224
  if (!config.ok)
224
225
  return { ok: false, error: cliError(config.error) };
226
+ const policy = config.value.browserObservationPolicy;
227
+ if (policy.status === "disabled")
228
+ return {
229
+ ok: false,
230
+ error: cliError(new AnalysisCapabilityUnavailableError("rea-cdp-browser", operation, "browser observation is disabled; configure exact endpoints and origins before enabling it")),
231
+ };
225
232
  const authority = await loadConfiguredPermissionAuthority(config.value);
226
233
  if (!authority.ok)
227
234
  return { ok: false, error: cliError(authority.error) };
@@ -229,7 +236,7 @@ const browserContext = async () => {
229
236
  ok: true,
230
237
  authority: authority.value,
231
238
  provider: new CdpBrowserProvider(),
232
- allowedBrowserOrigins: config.value.browserAllowedOrigins,
239
+ allowedBrowserOrigins: policy.allowedOrigins,
233
240
  };
234
241
  };
235
242
  const cliError = (error) => ({
@@ -50,6 +50,7 @@ export const CLI_COMMANDS = Object.freeze({
50
50
  captureBrowserScenario: "capture-browser-scenario",
51
51
  listElectronTargets: "list-electron-targets",
52
52
  inspectElectronPage: "inspect-electron-page",
53
+ captureElectronScenario: "capture-electron-scenario",
53
54
  listJavaScriptRuntimeTargets: "list-javascript-runtime-targets",
54
55
  observeJavaScriptRuntime: "observe-javascript-runtime",
55
56
  analyzeJavaScriptApplication: "analyze-javascript-application",