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
@@ -1,28 +1,13 @@
1
1
  import { z } from "zod";
2
+ import { providerCapability, } from "../contracts/toolOutputSchemaPrimitives.js";
2
3
  import { GENERATED_MCP_TOOL_CATALOG } from "../generatedMcpToolCatalog.js";
4
+ import { clientRequirementsFor, NO_CLIENT_FEATURES, } from "./CapabilityClientRequirements.js";
3
5
  const statusSchema = z.object({
4
6
  open: z.boolean(),
5
7
  kind: z.enum(["executable", "database", "archive", "artifact"]).optional(),
6
8
  format: z.string().optional(),
7
- capabilities: z.array(z.object({
8
- operation: z.string(),
9
- available: z.boolean(),
10
- reason: z.string().nullable(),
11
- availability_code: z.string().nullable().optional(),
12
- })),
9
+ capabilities: z.array(providerCapability),
13
10
  });
14
- const NO_CLIENT_FEATURES = {
15
- elicitation_form: false,
16
- elicitation_url: false,
17
- roots: false,
18
- sampling: false,
19
- };
20
- const CLIENT_FEATURE_REQUIREMENTS = {
21
- capture_process_scenario: {
22
- required: [],
23
- optional: ["elicitation_form"],
24
- },
25
- };
26
11
  const ENHANCED_REQUIREMENTS = {
27
12
  swift_classes: ["list_procedures"],
28
13
  get_objc_classes: ["list_names"],
@@ -46,24 +31,24 @@ const ENHANCED_REQUIREMENTS = {
46
31
  "resolve_containing_procedure",
47
32
  ],
48
33
  };
49
- const SESSION_COMPOSITION_REQUIREMENTS = {
50
- get_navigation_context: [
51
- "current_document",
52
- "current_address",
53
- "resolve_containing_procedure",
54
- ],
55
- };
34
+ const NAVIGATION_CONTEXT_MODES = [
35
+ {
36
+ name: "current_selection",
37
+ requirements: [
38
+ "current_document",
39
+ "current_address",
40
+ "resolve_containing_procedure",
41
+ ],
42
+ },
43
+ {
44
+ name: "explicit_document",
45
+ requirements: ["current_address", "resolve_containing_procedure"],
46
+ },
47
+ ];
56
48
  /** Build stable per-operation availability for discovery and tool visibility. */
57
49
  export const buildCapabilityInventory = (sessionStatus, policy, clientFeatures = NO_CLIENT_FEATURES) => {
58
50
  const status = statusSchema.parse(sessionStatus);
59
- const descriptors = new Map(status.capabilities.map((descriptor) => [
60
- descriptor.operation,
61
- {
62
- available: descriptor.available,
63
- reason: descriptor.reason,
64
- availability_code: descriptor.availability_code ?? null,
65
- },
66
- ]));
51
+ const descriptors = new Map(status.capabilities.map((descriptor) => [descriptor.operation, descriptor]));
67
52
  return GENERATED_MCP_TOOL_CATALOG.map((contract) => {
68
53
  const availability = availabilityFor({
69
54
  name: contract.name,
@@ -75,16 +60,15 @@ export const buildCapabilityInventory = (sessionStatus, policy, clientFeatures =
75
60
  });
76
61
  const clientRequirements = clientRequirementsFor(contract.name, clientFeatures);
77
62
  const clientBlocked = clientRequirements.missing_required.length > 0;
78
- return {
63
+ const facts = {
79
64
  name: contract.name,
80
65
  surface: contract.kind,
81
- available: availability.reason === "available" && !clientBlocked,
82
- reason: clientBlocked
83
- ? "client_capability_missing"
84
- : availability.reason,
85
- remediation: clientBlocked
86
- ? `Use an MCP client that supports: ${clientRequirements.missing_required.join(", ")}.`
87
- : availability.remediation,
66
+ ...(availability.defaultModeAvailable === undefined
67
+ ? {}
68
+ : { default_mode_available: availability.defaultModeAvailable }),
69
+ ...(availability.modes === undefined
70
+ ? {}
71
+ : { modes: [...availability.modes] }),
88
72
  client_requirements: clientRequirements,
89
73
  effects: { ...contract.effects },
90
74
  annotations: {
@@ -94,24 +78,31 @@ export const buildCapabilityInventory = (sessionStatus, policy, clientFeatures =
94
78
  open_world: contract.annotations.openWorldHint ?? true,
95
79
  },
96
80
  };
81
+ if (clientBlocked)
82
+ return {
83
+ ...facts,
84
+ available: false,
85
+ reason: "client_capability_missing",
86
+ remediation: `Use an MCP client that supports: ${clientRequirements.missing_required.join(", ")}.`,
87
+ };
88
+ return availability.reason === "available"
89
+ ? {
90
+ ...facts,
91
+ available: true,
92
+ reason: availability.reason,
93
+ remediation: null,
94
+ }
95
+ : {
96
+ ...facts,
97
+ available: false,
98
+ reason: availability.reason,
99
+ remediation: availability.remediation,
100
+ };
97
101
  }).sort((left, right) => left.name.localeCompare(right.name));
98
102
  };
99
- const clientRequirementsFor = (name, clientFeatures) => {
100
- const requirements = CLIENT_FEATURE_REQUIREMENTS[name] ?? {
101
- required: [],
102
- optional: [],
103
- };
104
- return {
105
- required: [...requirements.required],
106
- optional: [...requirements.optional],
107
- missing_required: requirements.required.filter((feature) => !clientFeatures[feature]),
108
- missing_optional: requirements.optional.filter((feature) => !clientFeatures[feature]),
109
- };
110
- };
111
103
  const availabilityFor = (context) => {
112
- const sessionComposition = SESSION_COMPOSITION_REQUIREMENTS[context.name];
113
- if (sessionComposition !== undefined)
114
- return composedAvailabilityFor(sessionComposition, context.descriptors);
104
+ if (context.name === "get_navigation_context")
105
+ return navigationContextAvailability(context.descriptors);
115
106
  const javascriptApplication = javascriptApplicationAvailability(context);
116
107
  if (javascriptApplication !== null)
117
108
  return javascriptApplication;
@@ -166,13 +157,9 @@ const policyAvailability = ({ name, kind, policy, }) => {
166
157
  reason: "policy_disabled",
167
158
  remediation: "Configure or grant an evidence_read root.",
168
159
  };
169
- if (kind === "electron-provider")
170
- return policy.electronObservationEnabled === true
171
- ? { reason: "available", remediation: null }
172
- : {
173
- reason: "policy_disabled",
174
- remediation: "Enable Electron observation and configure a loopback CDP endpoint and canonical file roots.",
175
- };
160
+ const electron = electronPolicyAvailability(name, kind, policy);
161
+ if (electron !== null)
162
+ return electron;
176
163
  if (kind === "runtime-provider")
177
164
  return policy.v8InspectorObservationEnabled === true
178
165
  ? { reason: "available", remediation: null }
@@ -184,6 +171,23 @@ const policyAvailability = ({ name, kind, policy, }) => {
184
171
  return { reason: "available", remediation: null };
185
172
  return null;
186
173
  };
174
+ const electronPolicyAvailability = (name, kind, policy) => {
175
+ if (kind !== "electron-provider")
176
+ return null;
177
+ if (name === "capture_electron_scenario")
178
+ return policy.electronAutomationEnabled === true
179
+ ? { reason: "available", remediation: null }
180
+ : {
181
+ reason: "policy_disabled",
182
+ remediation: "Enable active Electron automation and configure exact executable and application roots.",
183
+ };
184
+ return policy.electronObservationEnabled === true
185
+ ? { reason: "available", remediation: null }
186
+ : {
187
+ reason: "policy_disabled",
188
+ remediation: "Enable Electron observation and configure a loopback CDP endpoint and canonical file roots.",
189
+ };
190
+ };
187
191
  const browserPolicyAvailability = (name, kind, policy) => {
188
192
  if (name === "capture_browser_scenario")
189
193
  return policy.browserScenarioEnabled === true
@@ -272,3 +276,70 @@ const composedAvailabilityFor = (requirements, descriptors) => {
272
276
  };
273
277
  return { reason: "available", remediation: null };
274
278
  };
279
+ const navigationContextAvailability = (descriptors) => {
280
+ const modeResults = NAVIGATION_CONTEXT_MODES.map((mode) => {
281
+ const availability = composedAvailabilityFor(mode.requirements, descriptors);
282
+ if (availability.reason === "available")
283
+ return {
284
+ name: mode.name,
285
+ available: true,
286
+ reason: availability.reason,
287
+ missing_operations: [],
288
+ remediation: null,
289
+ };
290
+ return {
291
+ name: mode.name,
292
+ available: false,
293
+ reason: availability.reason,
294
+ missing_operations: mode.requirements.filter((operation) => {
295
+ const descriptor = descriptors.get(operation);
296
+ return descriptor === undefined || descriptor.available === false;
297
+ }),
298
+ remediation: availability.remediation,
299
+ };
300
+ });
301
+ const modes = modeResults.map((mode) => mode.available
302
+ ? {
303
+ name: mode.name,
304
+ available: true,
305
+ missing_operations: [],
306
+ remediation: null,
307
+ }
308
+ : {
309
+ name: mode.name,
310
+ available: false,
311
+ missing_operations: [...mode.missing_operations],
312
+ remediation: mode.remediation,
313
+ });
314
+ const availableMode = modeResults.find((mode) => mode.available);
315
+ const failures = modeResults.flatMap((mode) => mode.available ? [] : [mode]);
316
+ const failure = failures.sort((left, right) => navigationFailurePriority(left.reason) -
317
+ navigationFailurePriority(right.reason))[0];
318
+ const specificFailureRemediation = failure?.reason === "provider_missing" ? undefined : failure?.remediation;
319
+ const facts = {
320
+ defaultModeAvailable: modes[0]?.available ?? false,
321
+ modes,
322
+ };
323
+ if (availableMode !== undefined)
324
+ return { ...facts, reason: "available", remediation: null };
325
+ return {
326
+ ...facts,
327
+ reason: failure?.reason ?? "provider_missing",
328
+ remediation: specificFailureRemediation ??
329
+ `Configure a provider for one of: ${modes
330
+ .flatMap((mode) => mode.missing_operations)
331
+ .join(", ")}.`,
332
+ };
333
+ };
334
+ const navigationFailurePriority = (reason) => {
335
+ switch (reason) {
336
+ case "unsupported_host":
337
+ return 0;
338
+ case "provider_unavailable":
339
+ return 1;
340
+ case "provider_missing":
341
+ return 2;
342
+ default:
343
+ return 3;
344
+ }
345
+ };
@@ -6,6 +6,7 @@ import { err, ok } from "../domain/result.js";
6
6
  import { paginateArtifactInventory, } from "./ArtifactInventory.js";
7
7
  import { scanAuthorizedArtifactInventory } from "./AuthorizedArtifactInventory.js";
8
8
  import { ARTIFACT_GRAPH_PROVIDER } from "./InvestigationProviders.js";
9
+ import { resolveArtifactIntegrityPolicy } from "./ArtifactInventory/policy.js";
9
10
  export const AUTOMATIC_RUN_LIMITATION = "Automatic cross-version runs compare shipped artifact structure only; they do not execute either version.";
10
11
  /** Start both independent version scans while preserving left/right identity. */
11
12
  export const scanVersionInventories = async (options, scanner = scanAuthorizedArtifactInventory) => {
@@ -27,12 +28,12 @@ export const scanVersions = async (input, inputRoots, signal, integrityContinueE
27
28
  if (signal?.aborted === true)
28
29
  return err(new AnalysisCancelledError("find_changed_behavior"));
29
30
  const limits = artifactLimits(input.options);
30
- const integrity = {
31
- mode: input.integrity_policy,
32
- approved: input.integrity_continue_approved,
33
- enabled: integrityContinueEnabled,
34
- maxMismatches: input.max_integrity_mismatches,
35
- };
31
+ const integrity = resolveArtifactIntegrityPolicy(input.integrity_policy === "fail"
32
+ ? { mode: "fail" }
33
+ : {
34
+ mode: input.integrity_policy,
35
+ maxMismatches: input.max_integrity_mismatches,
36
+ }, integrityContinueEnabled);
36
37
  return ok(await scanVersionInventories({
37
38
  leftPath: input.left_path,
38
39
  rightPath: input.right_path,
@@ -0,0 +1,55 @@
1
+ import { createEvidence } from "../domain/evidence.js";
2
+ import { jsonValueSchema } from "../domain/jsonValue.js";
3
+ import { digestJson } from "./JavaScriptReplayPlanning.js";
4
+ /** Create Evidence v2 without retaining arbitrary runtime argument values. */
5
+ export const createElectronActiveEvidence = (input, result, provider) => createEvidence(undefined, provider, {
6
+ predicateType: "rea.electron-active-scenario/v1",
7
+ operation: "capture_electron_scenario",
8
+ parameters: parameters(input),
9
+ result: jsonValueSchema.parse(result),
10
+ confidence: "observed",
11
+ authority: "controlled-replay",
12
+ environment: {
13
+ id: `${result.application.electron_version}@${process.platform}`,
14
+ platform: process.platform,
15
+ architecture: process.arch,
16
+ isolation: "none",
17
+ },
18
+ limitations: result.limitations,
19
+ });
20
+ const scenarioProjection = (input) => ({
21
+ approved: input.approved,
22
+ schema_version: input.schema_version,
23
+ executable_path: input.executable_path,
24
+ application_path: input.application_path,
25
+ application_root: input.application_root,
26
+ args: redactArguments(input.args),
27
+ actions: input.actions.map(({ step_id, kind }) => ({ step_id, kind })),
28
+ limits: input.limits,
29
+ });
30
+ const parameters = (input) => ({
31
+ ...scenarioProjection(input),
32
+ scenario_sha256: digestJson(scenarioProjection(input)),
33
+ });
34
+ const redactArguments = (arguments_) => {
35
+ let redactNext = false;
36
+ return arguments_.map((argument) => {
37
+ if (redactNext) {
38
+ redactNext = false;
39
+ return "<redacted>";
40
+ }
41
+ if (sensitiveFlag.test(argument)) {
42
+ redactNext = true;
43
+ return argument;
44
+ }
45
+ return redactArgument(argument);
46
+ });
47
+ };
48
+ const sensitiveFlag = /^--?(?:password|token|secret|api[-_]?key|authorization|cookie)$/iu;
49
+ const redactArgument = (argument) => {
50
+ if (/^--?(?:password|token|secret|api[-_]?key|authorization|cookie)=/iu.test(argument))
51
+ return `${argument.slice(0, argument.indexOf("=") + 1)}<redacted>`;
52
+ return argument.length > 256
53
+ ? `${argument.slice(0, 256)}<redacted>`
54
+ : argument;
55
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,81 @@
1
+ import { realpath } from "node:fs/promises";
2
+ import { digestJson } from "./JavaScriptReplayPlanning.js";
3
+ import { AnalysisCapabilityUnavailableError, AnalysisInputError, AnalysisProtocolError, PermissionRequiredError, } from "../domain/errors.js";
4
+ import { isPathContained } from "../domain/permissionPolicy.js";
5
+ import { err } from "../domain/result.js";
6
+ import { createElectronActiveEvidence } from "./ElectronActiveEvidence.js";
7
+ const OPERATION = "capture_electron_scenario";
8
+ const PROVIDER_ID = "rea-playwright-electron-active";
9
+ const canonicalizeInput = async (input) => {
10
+ try {
11
+ const [executablePath, applicationPath, applicationRoot] = await Promise.all([
12
+ realpath(input.executable_path),
13
+ realpath(input.application_path),
14
+ realpath(input.application_root),
15
+ ]);
16
+ if (!isPathContained(applicationRoot, applicationPath))
17
+ return err(new AnalysisInputError(OPERATION, undefined, [
18
+ {
19
+ path: ["application_path"],
20
+ reason: "invalid_value",
21
+ message: "application_path must remain beneath application_root after symlink resolution",
22
+ },
23
+ ]));
24
+ return {
25
+ ok: true,
26
+ value: {
27
+ ...input,
28
+ executable_path: executablePath,
29
+ application_path: applicationPath,
30
+ application_root: applicationRoot,
31
+ },
32
+ };
33
+ }
34
+ catch (cause) {
35
+ return err(new AnalysisInputError(OPERATION, { cause }, [
36
+ {
37
+ path: ["application_path"],
38
+ reason: "invalid_format",
39
+ message: "Electron executable, application, and root must resolve to existing paths",
40
+ },
41
+ ]));
42
+ }
43
+ };
44
+ const authorize = async (authority, input) => {
45
+ const canonical = await canonicalizeInput(input);
46
+ if (!canonical.ok)
47
+ return canonical;
48
+ if (authority === undefined)
49
+ return err(new AnalysisCapabilityUnavailableError(PROVIDER_ID, OPERATION, "active Electron observation permission policy is not configured"));
50
+ const authorized = await authority.authorize({
51
+ capability: "electron_automate",
52
+ roots: [canonical.value.application_root],
53
+ executables: [canonical.value.executable_path],
54
+ environment_names: [],
55
+ network: "external",
56
+ mount: false,
57
+ operation_identity: `${OPERATION}:${digestJson(canonical.value)}`,
58
+ }, "write");
59
+ if (!authorized.ok)
60
+ return err(authorized.error instanceof PermissionRequiredError
61
+ ? authorized.error
62
+ : new AnalysisProtocolError(authorized.error.message, {
63
+ cause: authorized.error,
64
+ }));
65
+ return canonical;
66
+ };
67
+ /** Authorize and execute one bounded, provider-owned Electron experiment. */
68
+ export const captureElectronScenario = async (provider, authority, input, options = {}) => {
69
+ const authorized = await authorize(authority, input);
70
+ if (!authorized.ok)
71
+ return authorized;
72
+ if (provider === undefined)
73
+ return err(new AnalysisCapabilityUnavailableError(PROVIDER_ID, OPERATION, "active Electron observation provider is not configured"));
74
+ const captured = await provider.capture(authorized.value, options);
75
+ return captured.ok
76
+ ? {
77
+ ok: true,
78
+ value: createElectronActiveEvidence(authorized.value, captured.value, provider.identity()),
79
+ }
80
+ : captured;
81
+ };
@@ -102,32 +102,34 @@ export class EnhancedTools {
102
102
  }
103
103
  }
104
104
  #executeTracing(name, input, signal) {
105
- const parsed = enhancedInputSchemas[name].safeParse(input);
105
+ if (name === "trace_call_path") {
106
+ const parsed = enhancedInputSchemas.trace_call_path.safeParse(input);
107
+ if (!parsed.success)
108
+ return invalidEnhancedInput(name, parsed.error);
109
+ return this.executeValidated({ name, input: parsed.data }, signal);
110
+ }
111
+ if (name === "trace_feature") {
112
+ const parsed = enhancedInputSchemas.trace_feature.safeParse(input);
113
+ if (!parsed.success)
114
+ return invalidEnhancedInput(name, parsed.error);
115
+ return this.executeValidated({ name, input: parsed.data }, signal);
116
+ }
117
+ const parsed = enhancedInputSchemas.find_code_for_string.safeParse(input);
106
118
  if (!parsed.success)
107
119
  return invalidEnhancedInput(name, parsed.error);
108
- if (name === "trace_call_path")
109
- return this.executeValidated({
110
- name,
111
- input: enhancedInputSchemas.trace_call_path.parse(parsed.data),
112
- }, signal);
113
- return this.executeValidated({
114
- name,
115
- input: enhancedInputSchemas[name].parse(parsed.data),
116
- }, signal);
120
+ return this.executeValidated({ name, input: parsed.data }, signal);
117
121
  }
118
122
  #executeFunctionAnalysis(name, input, signal) {
119
- const parsed = enhancedInputSchemas[name].safeParse(input);
123
+ if (name === "analyze_function") {
124
+ const parsed = enhancedInputSchemas.analyze_function.safeParse(input);
125
+ if (!parsed.success)
126
+ return invalidEnhancedInput(name, parsed.error);
127
+ return this.executeValidated({ name, input: parsed.data }, signal);
128
+ }
129
+ const parsed = enhancedInputSchemas.inspect_native_api.safeParse(input);
120
130
  if (!parsed.success)
121
131
  return invalidEnhancedInput(name, parsed.error);
122
- if (name === "analyze_function")
123
- return this.executeValidated({
124
- name,
125
- input: enhancedInputSchemas.analyze_function.parse(parsed.data),
126
- }, signal);
127
- return this.executeValidated({
128
- name,
129
- input: enhancedInputSchemas.inspect_native_api.parse(parsed.data),
130
- }, signal);
132
+ return this.executeValidated({ name, input: parsed.data }, signal);
131
133
  }
132
134
  async #analyzeFunction(input, signal) {
133
135
  const result = await this.#call("analyze_function", input, signal);
@@ -12,7 +12,11 @@ export const importEvidenceBundleCommand = async (path, policy) => {
12
12
  const ledger = createLedger();
13
13
  const imported = ledger.import(loaded.value);
14
14
  return imported.ok
15
- ? ok({ imported: imported.value, total: ledger.export().records.length })
15
+ ? ok({
16
+ imported: imported.value.recordsAdded,
17
+ unknowns_added: imported.value.unknownsAdded,
18
+ total: ledger.export().records.length,
19
+ })
16
20
  : imported;
17
21
  };
18
22
  /** Validate a source bundle and atomically export canonical bytes. */
@@ -63,6 +63,7 @@ export class EvidenceLedger {
63
63
  pending.set(evidence.evidence_id, evidence);
64
64
  }
65
65
  const pendingUnknowns = new Map(this.#unknownRevisions);
66
+ let unknownsAdded = 0;
66
67
  for (const unknown of bundle.unknowns) {
67
68
  const key = unknownRevisionKey(unknown);
68
69
  const existing = pendingUnknowns.get(key);
@@ -70,6 +71,8 @@ export class EvidenceLedger {
70
71
  existing.revision_digest !== unknown.revision_digest)
71
72
  return err(new EvidenceIntegrityError("Conflicting unknown revision"));
72
73
  pendingUnknowns.set(key, unknown);
74
+ if (existing === undefined)
75
+ unknownsAdded += 1;
73
76
  }
74
77
  const checked = this.#validateCandidate(pending, pendingUnknowns);
75
78
  if (!checked.ok) {
@@ -81,7 +84,11 @@ export class EvidenceLedger {
81
84
  }
82
85
  const added = pending.size - this.#records.size;
83
86
  this.#commit(pending, pendingUnknowns, checked.value);
84
- return ok(added);
87
+ return ok({
88
+ recordsAdded: added,
89
+ unknownsAdded,
90
+ changed: added > 0 || unknownsAdded > 0,
91
+ });
85
92
  }
86
93
  /** Export records in deterministic, semantically irrelevant ID order. */
87
94
  export() {
@@ -12,5 +12,5 @@ export const replayPermissionRequest = (input, policy) => ({
12
12
  environment_names: [],
13
13
  network: "none",
14
14
  mount: true,
15
- operation_identity: `run_controlled_replay:${input.plan_digest ?? "plan"}`,
15
+ operation_identity: `run_controlled_replay:${input.mode === "plan" ? "plan" : input.plan_digest}`,
16
16
  });
@@ -19,10 +19,10 @@ export const runControlledReplay = async (dependencies, rawInput, options = {})
19
19
  };
20
20
  /** Plan or execute replay input already parsed by a trusted adapter. */
21
21
  export const runControlledReplayValidated = async (dependencies, input, options = {}) => {
22
- const authorized = await authorizeReplay(dependencies, input, options.signal);
22
+ const authorized = await authorizeReplay(dependencies, dependencies.policy(), input, options.signal);
23
23
  if (!authorized.ok)
24
24
  return authorized;
25
- const prepared = await prepareValidatedReplay(dependencies, input, options.signal);
25
+ const prepared = await prepareValidatedReplay(dependencies, authorized.value, input, options.signal);
26
26
  if (!prepared.ok)
27
27
  return prepared;
28
28
  if (isAborted(options.signal))
@@ -35,11 +35,17 @@ export const runControlledReplayValidated = async (dependencies, input, options
35
35
  evidence: null,
36
36
  }));
37
37
  if (input.plan_digest !== prepared.value.publicPlan.plan_digest)
38
- return err(new ReplayPlanStaleError(input.plan_digest ?? "", prepared.value.publicPlan.plan_digest));
38
+ return err(new ReplayPlanStaleError(input.plan_digest, prepared.value.publicPlan.plan_digest));
39
39
  const exportContext = await authorizeReproducerExport(dependencies.authority, input, prepared.value);
40
40
  if (!exportContext.ok)
41
41
  return exportContext;
42
- const executed = await executeValidatedReplay(dependencies, prepared.value, exportContext.value, options);
42
+ const executed = await executeValidatedReplay({
43
+ runner: dependencies.runner,
44
+ policy: authorized.value,
45
+ prepared: prepared.value,
46
+ exportContext: exportContext.value,
47
+ options,
48
+ });
43
49
  if (!executed.ok)
44
50
  return executed;
45
51
  try {
@@ -51,14 +57,14 @@ export const runControlledReplayValidated = async (dependencies, input, options
51
57
  : "Controlled replay could not establish or clean up its sandbox", { cause }));
52
58
  }
53
59
  };
54
- const authorizeReplay = async (dependencies, input, signal) => {
55
- if (!dependencies.policy.enabled)
60
+ const authorizeReplay = async (dependencies, policy, input, signal) => {
61
+ if (policy.status === "disabled")
56
62
  return err(new AnalysisCapabilityUnavailableError("rea-javascript-replay", OPERATION, "controlled replay is disabled; configure exact roots and executables before enabling it"));
57
63
  if (dependencies.authority === undefined)
58
64
  return err(new AnalysisCapabilityUnavailableError("rea-javascript-replay", OPERATION, "JavaScript replay permission policy is not configured"));
59
65
  if (isAborted(signal))
60
66
  return err(new AnalysisCancelledError(OPERATION));
61
- const request = replayPermissionRequest(input, dependencies.policy);
67
+ const request = replayPermissionRequest(input, policy);
62
68
  const authorized = input.mode === "plan"
63
69
  ? await dependencies.authority.explain(request, "read")
64
70
  : await dependencies.authority.authorize(request, "read");
@@ -68,13 +74,13 @@ const authorizeReplay = async (dependencies, input, signal) => {
68
74
  : new AnalysisProtocolError(authorized.error.message, {
69
75
  cause: authorized.error,
70
76
  }));
71
- return ok(true);
77
+ return ok(policy);
72
78
  };
73
- const prepareValidatedReplay = async (dependencies, input, signal) => {
79
+ const prepareValidatedReplay = async (dependencies, policy, input, signal) => {
74
80
  if (isAborted(signal))
75
81
  return err(new AnalysisCancelledError(OPERATION));
76
82
  try {
77
- return ok(await prepareReplayPlan(input, dependencies.policy, dependencies.host));
83
+ return ok(await prepareReplayPlan(input, policy, dependencies.host));
78
84
  }
79
85
  catch (cause) {
80
86
  return err(new AnalysisCapabilityUnavailableError("rea-javascript-replay", OPERATION, cause instanceof Error ? cause.message : "replay planning failed"));
@@ -83,8 +89,6 @@ const prepareValidatedReplay = async (dependencies, input, signal) => {
83
89
  const authorizeReproducerExport = async (authority, input, prepared) => {
84
90
  if (input.reproducer_export === undefined)
85
91
  return ok(undefined);
86
- if (input.reproducer_export.approved !== true)
87
- return err(new AnalysisInputError(`${OPERATION}:reproducer_export`));
88
92
  if (authority === undefined)
89
93
  return err(new AnalysisCapabilityUnavailableError("rea-javascript-replay", OPERATION, "JavaScript replay permission policy is not configured"));
90
94
  const exportAuthorized = await authority.authorize({
@@ -112,7 +116,8 @@ const authorizeReproducerExport = async (authority, input, prepared) => {
112
116
  includeSources: input.reproducer_export.include_sources === true,
113
117
  });
114
118
  };
115
- const executeValidatedReplay = async (dependencies, prepared, exportContext, options) => {
119
+ const executeValidatedReplay = async (context) => {
120
+ const { runner, policy, prepared, exportContext, options } = context;
116
121
  await options.progress?.report({
117
122
  phase: OPERATION,
118
123
  completed: 0,
@@ -122,7 +127,7 @@ const executeValidatedReplay = async (dependencies, prepared, exportContext, opt
122
127
  if (isAborted(options.signal))
123
128
  return err(new AnalysisCancelledError(OPERATION));
124
129
  try {
125
- let executed = replayExecutionResultSchema.parse(await dependencies.runner.execute(prepared, dependencies.policy, options.signal));
130
+ let executed = replayExecutionResultSchema.parse(await runner.execute(prepared, policy, options.signal));
126
131
  await options.progress?.report({
127
132
  phase: OPERATION,
128
133
  completed: 1,
@@ -289,4 +294,7 @@ const createReplayEvidence = (prepared, executed, side, outcomes) => {
289
294
  })),
290
295
  });
291
296
  };
292
- const asJson = (value) => jsonValueSchema.parse(JSON.parse(JSON.stringify(controlledReplayOutputSchema.parse(value))));
297
+ const asJson = (value) => {
298
+ const serialized = JSON.parse(JSON.stringify(controlledReplayOutputSchema.parse(value)));
299
+ return jsonValueSchema.parse(serialized);
300
+ };