rea-agents 2.5.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 (253) hide show
  1. package/README.md +20 -12
  2. package/bridge/ghidra/ReaGhidraBridge.java +477 -4
  3. package/bridge/hopper_bridge.py +54 -4
  4. package/dist/application/AnalysisContextQueries.js +142 -0
  5. package/dist/application/AnalysisSnapshotCache.js +4 -2
  6. package/dist/application/ApplicationWorkflowEvidenceResolver.js +19 -11
  7. package/dist/application/ArtifactInventory/policy.js +17 -0
  8. package/dist/application/ArtifactInventory/reader.js +1 -4
  9. package/dist/application/ArtifactInventory/scanCanonical.js +0 -3
  10. package/dist/application/ArtifactInventory/scanReader.js +7 -7
  11. package/dist/application/ArtifactInventory/types.js +1 -5
  12. package/dist/application/BinarySession.js +19 -20
  13. package/dist/application/BinarySessionComposition.js +21 -0
  14. package/dist/application/BinarySessionRecords.js +106 -10
  15. package/dist/application/BinarySessionStatus.js +11 -5
  16. package/dist/application/BrowserEvidence.js +3 -5
  17. package/dist/application/CapabilityClientRequirements.js +26 -0
  18. package/dist/application/CapabilityInventory.js +140 -55
  19. package/dist/application/ClientRegistrationStatus.js +4 -1
  20. package/dist/application/CrossVersionInventory.js +7 -6
  21. package/dist/application/DirectAnalysis.js +6 -2
  22. package/dist/application/ElectronActiveEvidence.js +55 -0
  23. package/dist/application/ElectronActiveObservationPort.js +1 -0
  24. package/dist/application/ElectronActiveObservationService.js +81 -0
  25. package/dist/application/EnhancedTools.js +49 -17
  26. package/dist/application/EvidenceBundleCommands.js +5 -1
  27. package/dist/application/EvidenceLedger.js +53 -17
  28. package/dist/application/JavaScriptArtifactAnalysis.js +13 -4
  29. package/dist/application/JavaScriptReplayPermission.js +1 -1
  30. package/dist/application/JavaScriptReplayService.js +23 -15
  31. package/dist/application/LazyAnalysisProvider.js +77 -0
  32. package/dist/application/LoopbackReplay.js +1 -1
  33. package/dist/application/ManagedRuntimeCorrelationService.js +9 -5
  34. package/dist/application/NativeApiInspection.js +80 -0
  35. package/dist/application/NodeRuntimeCharacterizationService.js +8 -9
  36. package/dist/application/ProcessCaptureLifecycle.js +5 -0
  37. package/dist/application/ProcessCli.js +2 -1
  38. package/dist/application/ProcessHarness.js +8 -3
  39. package/dist/application/ProcessNormalization.js +2 -1
  40. package/dist/application/ProjectPermissionStore.js +1 -0
  41. package/dist/application/ReferenceSourceImport.js +2 -2
  42. package/dist/application/SessionProviderRouter.js +6 -6
  43. package/dist/application/SetupClientConfiguration.js +10 -3
  44. package/dist/application/WindowsCapabilities.js +5 -4
  45. package/dist/application/runtime.js +26 -9
  46. package/dist/artifacts/ArtifactProvider.js +8 -10
  47. package/dist/artifacts/SafeOutputTree.js +7 -8
  48. package/dist/browser/CdpCaptureStorageFingerprints.js +10 -7
  49. package/dist/browser/CdpElectronInspection.js +3 -1
  50. package/dist/browser/JavaScriptRuntimeScope.js +5 -0
  51. package/dist/browser/PlaywrightBrowserScenarioProvider.js +8 -2
  52. package/dist/browser/PlaywrightElectronActiveActions.js +324 -0
  53. package/dist/browser/PlaywrightElectronActiveProvider.js +294 -0
  54. package/dist/browser/PlaywrightScenarioBrowser.js +4 -4
  55. package/dist/browser/PlaywrightScenarioSession.js +4 -4
  56. package/dist/browser/SensitiveTextCapture.js +1 -1
  57. package/dist/browser/V8InspectorCaptureProjection.js +1 -0
  58. package/dist/browser/V8InspectorProvider.js +3 -3
  59. package/dist/catalogIdentity.js +15 -9
  60. package/dist/cli/artifactCommands.js +5 -3
  61. package/dist/cli/coreAnalysisCommands.js +41 -0
  62. package/dist/cli/managedCommands.js +1 -1
  63. package/dist/cliApplicationCommands.js +2 -2
  64. package/dist/cliBrowserAdvancedCommands.js +11 -5
  65. package/dist/cliBrowserCommands.js +14 -7
  66. package/dist/cliCommandNames.js +2 -0
  67. package/dist/cliElectronCommands.js +46 -4
  68. package/dist/cliJavaScriptRuntimeCommands.js +14 -6
  69. package/dist/cliObservationOptions.js +4 -0
  70. package/dist/cliPolicyCommands.js +1 -0
  71. package/dist/config/browserScenario.js +77 -0
  72. package/dist/config/electronAutomation.js +35 -0
  73. package/dist/config/environment.js +6 -0
  74. package/dist/config/javascriptReplay.js +41 -0
  75. package/dist/config/managedRuntime.js +25 -0
  76. package/dist/config/parseConfig.js +56 -200
  77. package/dist/config/parsers.js +10 -1
  78. package/dist/config/passiveObservation.js +157 -0
  79. package/dist/config/processCapture.js +47 -0
  80. package/dist/contracts/applicationToolContracts.js +2 -5
  81. package/dist/contracts/applicationWorkflowInputContracts.js +86 -96
  82. package/dist/contracts/artifactToolContracts.js +35 -37
  83. package/dist/contracts/browserToolContracts.js +2 -2
  84. package/dist/contracts/electronToolContracts.js +30 -1
  85. package/dist/contracts/enhancedInputs.js +21 -27
  86. package/dist/contracts/functionWorkflowToolContracts.js +29 -0
  87. package/dist/contracts/managedToolContracts.js +4 -9
  88. package/dist/contracts/managedWorkflowExamples.js +12 -9
  89. package/dist/contracts/managedWorkflowToolContracts.js +30 -27
  90. package/dist/contracts/nativeToolContracts.js +2 -3
  91. package/dist/contracts/promptContracts.js +14 -15
  92. package/dist/contracts/sessionToolSchemas.js +61 -0
  93. package/dist/contracts/toolContractExamples.js +4 -0
  94. package/dist/contracts/toolContractHelpers.js +23 -0
  95. package/dist/contracts/toolContracts.js +12 -67
  96. package/dist/contracts/toolEffects.js +19 -0
  97. package/dist/contracts/toolOutputSchemaGroups.js +66 -11
  98. package/dist/contracts/toolOutputSchemaPrimitives.js +76 -26
  99. package/dist/contracts/toolSchemaMetadata.js +128 -0
  100. package/dist/doctorRuntime.js +1 -1
  101. package/dist/domain/analysisErrorPresentation.js +8 -2
  102. package/dist/domain/analysisErrorProjection.js +1 -0
  103. package/dist/domain/androidApplication.js +2 -0
  104. package/dist/domain/appleApplication.js +2 -0
  105. package/dist/domain/binaryTarget.js +7 -5
  106. package/dist/domain/binaryTargetTypes.js +1 -0
  107. package/dist/domain/browserCaptureComparison.js +21 -69
  108. package/dist/domain/browserObservation.js +22 -9
  109. package/dist/domain/bytecodeProvider.js +177 -0
  110. package/dist/domain/callPath.js +3 -2
  111. package/dist/domain/conformancePackage.js +169 -0
  112. package/dist/domain/conformanceReplay.js +104 -0
  113. package/dist/domain/conformanceTrustGate.js +328 -0
  114. package/dist/domain/customProtocolCapture.js +137 -0
  115. package/dist/domain/electronActiveObservation.js +277 -0
  116. package/dist/domain/electronObservation.js +15 -11
  117. package/dist/domain/electronStaticAnalysisValues.js +4 -1
  118. package/dist/domain/eventProcessTree.js +217 -0
  119. package/dist/domain/evidenceBundle.js +47 -0
  120. package/dist/domain/functionComparisonNormalization.js +15 -8
  121. package/dist/domain/functionDossierEvidence.js +9 -4
  122. package/dist/domain/hopperStartupFailure.js +1 -1
  123. package/dist/domain/hopperValues.js +68 -68
  124. package/dist/domain/inputIssueProjection.js +11 -2
  125. package/dist/domain/investigationWorkspace.js +16 -15
  126. package/dist/domain/javascriptExportShapeComparisonSchemas.js +2 -2
  127. package/dist/domain/javascriptReplay.js +79 -63
  128. package/dist/domain/javascriptRuntimeObservation.js +1 -0
  129. package/dist/domain/javascriptRuntimeReconciliationActive.js +89 -0
  130. package/dist/domain/javascriptRuntimeReconciliationGraph.js +11 -10
  131. package/dist/domain/javascriptRuntimeReconciliationMatching.js +57 -49
  132. package/dist/domain/javascriptRuntimeReconciliationParsing.js +5 -1
  133. package/dist/domain/javascriptRuntimeReconciliationResult.js +21 -14
  134. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
  135. package/dist/domain/javascriptSemanticAnalysis.js +8 -12
  136. package/dist/domain/javascriptSourceParser.js +15 -0
  137. package/dist/domain/javascriptStaticAnalysis.js +8 -12
  138. package/dist/domain/knownPageCoverage.js +15 -7
  139. package/dist/domain/mobileApplicationInvestigation.js +159 -0
  140. package/dist/domain/nativeApiBoundary.js +138 -0
  141. package/dist/domain/nodeRuntimeCharacterization.js +14 -13
  142. package/dist/domain/objcSwiftMetadata.js +150 -0
  143. package/dist/domain/packageAnalysis.js +123 -0
  144. package/dist/domain/peInspection.js +196 -0
  145. package/dist/domain/processCaptureReactiveValidation.js +8 -3
  146. package/dist/domain/processCaptureValidation.js +7 -3
  147. package/dist/domain/processComparison.js +12 -7
  148. package/dist/domain/processObservation.js +5 -6
  149. package/dist/domain/processReactiveMatching.js +14 -7
  150. package/dist/domain/processReactiveTransition.js +9 -3
  151. package/dist/domain/processScenario.js +6 -3
  152. package/dist/domain/processTraceComparison.js +3 -2
  153. package/dist/domain/protocolCapture.js +245 -0
  154. package/dist/domain/reconstructionReadinessSchemas.js +30 -2
  155. package/dist/domain/referenceSourceImportParsing.js +2 -2
  156. package/dist/domain/replayMachineRuntime.js +5 -3
  157. package/dist/domain/sourceToBundleComparison.js +2 -2
  158. package/dist/domain/sourceToBundleComparisonSchemas.js +8 -8
  159. package/dist/domain/sourceToBundleSignals.js +7 -1
  160. package/dist/domain/staticRuntimeCorrelation.js +7 -5
  161. package/dist/domain/webBundleAnalysis.js +14 -14
  162. package/dist/domain/webCaptureDiff.js +15 -12
  163. package/dist/dotnet/ManagedNativeBoundaryInspector.js +2 -3
  164. package/dist/dotnet/ManagedStaticProvider.js +34 -5
  165. package/dist/generatedMcpToolCatalog.js +37 -0
  166. package/dist/generatedPackageMetadata.js +4 -4
  167. package/dist/ghidra/GhidraClient.js +1 -1
  168. package/dist/ghidra/GhidraClientStartup.js +1 -1
  169. package/dist/ghidra/GhidraDefaults.js +1 -1
  170. package/dist/ghidra/GhidraFunctionValues.js +44 -16
  171. package/dist/ghidra/GhidraInventoryValues.js +57 -47
  172. package/dist/ghidra/GhidraProvider.js +18 -10
  173. package/dist/ghidra/GhidraProviderCapabilities.js +45 -39
  174. package/dist/ghidra/GhidraSocketConnection.js +1 -1
  175. package/dist/ghidra/protocol.js +19 -42
  176. package/dist/hopper/BridgeLauncher.js +3 -1
  177. package/dist/hopper/HopperAnalysisProfile.js +2 -4
  178. package/dist/hopper/HopperCleanup.js +5 -6
  179. package/dist/hopper/HopperClient.js +27 -3
  180. package/dist/hopper/HopperProvider.js +42 -44
  181. package/dist/hopper/HopperRequestQueue.js +32 -4
  182. package/dist/hopper/HopperResponseStream.js +2 -2
  183. package/dist/hopper/LinuxPrivateDisplayProbe.js +16 -10
  184. package/dist/hopper/protocol.js +63 -21
  185. package/dist/main/reload.js +1 -6
  186. package/dist/main/state.js +0 -14
  187. package/dist/main/transport.js +31 -41
  188. package/dist/main.js +17 -13
  189. package/dist/mcpDoctor.js +4 -26
  190. package/dist/mcpStartupPolicy.js +14 -0
  191. package/dist/process/PrivateRuntimeRoot.js +17 -0
  192. package/dist/process/ProcessOwnership.js +64 -128
  193. package/dist/process/ProcessOwnershipIdentity.js +13 -0
  194. package/dist/process/ProcessOwnershipObservation.js +88 -0
  195. package/dist/process/ProcessOwnershipProcessTree.js +22 -0
  196. package/dist/process/ProviderDeadline.js +8 -12
  197. package/dist/process/WindowsAuthority.js +32 -0
  198. package/dist/reference/ReferenceSourceReader.js +3 -3
  199. package/dist/reference/ReferenceSourceReaderEntries.js +2 -2
  200. package/dist/replay/JavaScriptReplayWorker.js +95 -11
  201. package/dist/replay/JavaScriptReplayWorkerTypes.js +1 -0
  202. package/dist/replay/LinuxJavaScriptReplayRunner.js +10 -15
  203. package/dist/replay/ReplayOutcome.js +26 -15
  204. package/dist/replay/ReplayWorkerProtocol.js +34 -29
  205. package/dist/server/createServer.js +101 -144
  206. package/dist/server/mcpClientMetadata.js +32 -0
  207. package/dist/server/registerApplicationTools/characterization.js +6 -13
  208. package/dist/server/registerApplicationTools/compareExportShapes.js +2 -7
  209. package/dist/server/registerApplicationTools/compareSourceToBundle.js +2 -7
  210. package/dist/server/registerApplicationTools/compareVersions.js +3 -8
  211. package/dist/server/registerApplicationTools/controlledReplay.js +6 -11
  212. package/dist/server/registerApplicationTools/coverage.js +13 -19
  213. package/dist/server/registerApplicationTools/obligationLedger.js +1 -6
  214. package/dist/server/registerApplicationTools/readiness.js +1 -6
  215. package/dist/server/registerApplicationTools/traceFeature.js +3 -8
  216. package/dist/server/registerApplicationTools/traceSemantics.js +1 -6
  217. package/dist/server/registerArtifactComparisonTool.js +12 -16
  218. package/dist/server/registerBrowserScenarioTool.js +1 -6
  219. package/dist/server/registerBrowserTools.js +37 -79
  220. package/dist/server/registerBundleComparisonTool.js +10 -14
  221. package/dist/server/registerCloseLifecycleTool.js +6 -14
  222. package/dist/server/registerElectronTools.js +30 -47
  223. package/dist/server/registerEnhancedTools.js +124 -122
  224. package/dist/server/registerEvidenceResources.js +50 -101
  225. package/dist/server/registerEvidenceTools.js +5 -9
  226. package/dist/server/registerFunctionComparisonTool.js +11 -15
  227. package/dist/server/registerInvestigationTools.js +42 -59
  228. package/dist/server/registerJavaScriptApplicationGraphResource.js +0 -4
  229. package/dist/server/registerJavaScriptRuntimeObservationTools.js +13 -27
  230. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +4 -9
  231. package/dist/server/registerManagedWorkflowTools/contract.js +2 -3
  232. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +3 -8
  233. package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +3 -8
  234. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +8 -13
  235. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +4 -9
  236. package/dist/server/registerOfficialTools.js +8 -9
  237. package/dist/server/registerProcessComparisonTool.js +19 -24
  238. package/dist/server/registerReconstructionObligationLedgerResource.js +0 -7
  239. package/dist/server/registerReconstructionReadinessResource.js +0 -7
  240. package/dist/server/registerReplayMachineTool.js +4 -10
  241. package/dist/server/registerSessionRecordTools.js +146 -47
  242. package/dist/server/registerSessionStatusTool.js +14 -29
  243. package/dist/server/registerSessionTools.js +45 -41
  244. package/dist/server/sessionAvailabilityPolicy.js +2 -1
  245. package/dist/server/sessionToolPolicies.js +1 -5
  246. package/dist/server/toolRegistrationOptions.js +4 -177
  247. package/dist/server/toolResult.js +14 -18
  248. package/package.json +35 -16
  249. package/scripts/electron-active-hook-boundaries.cjs +394 -0
  250. package/scripts/electron-active-hook.cjs +501 -0
  251. package/skills/reverse-engineer-anything/SKILL.md +10 -3
  252. package/dist/server/DynamicToolAvailability.js +0 -70
  253. package/dist/server/toolInputValidation.js +0 -77
@@ -0,0 +1,80 @@
1
+ import { nativeApiInspectionResultSchema, } from "../domain/nativeApiBoundary.js";
2
+ const unavailableBoundary = () => ({
3
+ available: false,
4
+ reason: "The selected provider did not expose a structured native API boundary model.",
5
+ residual_unknowns: [
6
+ "What are the function's return and parameter boundary types?",
7
+ "Does this function dispatch through a jump table with recoverable data addresses?",
8
+ ],
9
+ });
10
+ /** Project one analyzed-function dossier into inspectable native API substeps. */
11
+ export const projectNativeApiInspection = (dossier) => {
12
+ const boundary = dossier.native_api ?? unavailableBoundary();
13
+ const unsupportedBranches = boundary.available
14
+ ? []
15
+ : ["structured-boundary-types", "jump-table-data-mapping"];
16
+ const residualUnknowns = boundary.available
17
+ ? availableResidualUnknowns(boundary)
18
+ : boundary.residual_unknowns;
19
+ return nativeApiInspectionResultSchema.parse({
20
+ schema_version: 1,
21
+ procedure: {
22
+ address: dossier.procedure.address,
23
+ name: dossier.procedure.name,
24
+ },
25
+ boundary,
26
+ substeps: [
27
+ {
28
+ operation: "analyze_function",
29
+ status: "completed",
30
+ observations: [
31
+ "provider function dossier",
32
+ "provider pseudocode classification",
33
+ "provider control-flow observations",
34
+ ],
35
+ },
36
+ {
37
+ operation: "project_native_api_boundary",
38
+ status: boundary.available ? "completed" : "unsupported",
39
+ observations: boundary.available
40
+ ? [
41
+ "return and parameter boundary types",
42
+ "confidence and inference evidence",
43
+ "jump-table dispatch, data, and target addresses",
44
+ ]
45
+ : [boundary.reason],
46
+ },
47
+ {
48
+ operation: "preserve_residual_unknowns",
49
+ status: "completed",
50
+ observations: residualUnknowns.length === 0
51
+ ? ["no additional structured-boundary unknowns"]
52
+ : residualUnknowns,
53
+ },
54
+ ],
55
+ unsupported_branches: unsupportedBranches,
56
+ residual_unknowns: residualUnknowns,
57
+ });
58
+ };
59
+ const availableResidualUnknowns = (boundary) => {
60
+ const unknowns = [];
61
+ if (boundary.parameters_truncated)
62
+ unknowns.push("Which additional parameters were omitted by the native API boundary limit?");
63
+ if (boundary.jump_tables_truncated)
64
+ unknowns.push("Which additional jump tables were omitted by the native API boundary limit?");
65
+ for (const table of boundary.jump_tables) {
66
+ if (table.data_sources_truncated || table.mappings_truncated)
67
+ unknowns.push(`Which additional data sources or targets were omitted for the jump table dispatched at ${table.dispatch_address}?`);
68
+ if (table.data_sources.length === 0)
69
+ unknowns.push(`What backing data address produced the jump table dispatched at ${table.dispatch_address}?`);
70
+ if (table.data_sources.some(({ entry_count: count, entry_size_bytes: size }) => count === null || size === null))
71
+ unknowns.push(`What are the exact entry size and count for candidate jump-table data dispatched at ${table.dispatch_address}?`);
72
+ if (table.mappings.some(({ case_value: value }) => value === null))
73
+ unknowns.push(`Which source-level case values correspond to every target dispatched at ${table.dispatch_address}?`);
74
+ }
75
+ for (const value of [boundary.return_type, ...boundary.parameters]) {
76
+ if (value.confidence === "low")
77
+ unknowns.push(`Can the inferred ${value.role} type ${value.data_type} be confirmed with imported metadata or an ABI probe?`);
78
+ }
79
+ return [...new Set(unknowns)];
80
+ };
@@ -3,7 +3,7 @@ import { z } from "zod";
3
3
  import { nodeCharacterizationExecutionInputSchema, nodeCharacterizationExecutionOutputSchema, nodeCharacterizationPreparationInputSchema, nodeCharacterizationPreparationOutputSchema, } from "../domain/nodeRuntimeCharacterization.js";
4
4
  import { AnalysisInputError, AnalysisProtocolError, ReplayPlanStaleError, } from "../domain/errors.js";
5
5
  import { createEvidence } from "../domain/evidence.js";
6
- import { controlledReplayOutputSchema } from "../domain/javascriptReplay.js";
6
+ import { controlledReplayOutputSchema, } from "../domain/javascriptReplay.js";
7
7
  import { createRuntimeCharacterizationPlan, } from "../domain/runtimeCharacterization.js";
8
8
  import { err, ok } from "../domain/result.js";
9
9
  import { jsonValueSchema } from "../domain/jsonValue.js";
@@ -37,7 +37,7 @@ export const executeNodeCharacterization = async (dependencies, rawInput, option
37
37
  if (prepared.value.plan.plan_sha256 !== parsed.data.approved_plan_sha256)
38
38
  return err(new ReplayPlanStaleError(parsed.data.approved_plan_sha256, prepared.value.plan.plan_sha256));
39
39
  const plannedReplay = controlledReplayOutputSchema.parse(prepared.value.replay);
40
- if (plannedReplay.phase !== "plan" || plannedReplay.plan === null)
40
+ if (plannedReplay.phase !== "plan")
41
41
  return err(new AnalysisProtocolError("Node characterization preparation did not produce a replay plan"));
42
42
  const host = new InstrumentedJavaScriptReplayHost(dependencies.host, parsed.data.preparation.instrumentation);
43
43
  const executed = await runControlledReplayValidated({ ...dependencies, host }, {
@@ -48,6 +48,9 @@ export const executeNodeCharacterization = async (dependencies, rawInput, option
48
48
  }, options);
49
49
  if (!executed.ok)
50
50
  return executed;
51
+ const replayOutput = controlledReplayOutputSchema.parse(executed.value);
52
+ if (replayOutput.phase !== "execute")
53
+ return err(new AnalysisProtocolError("Node characterization execution omitted replay Evidence"));
51
54
  if (host.instrumentation === null)
52
55
  return err(new AnalysisProtocolError("Node characterization execution omitted instrumentation evidence"));
53
56
  return ok(jsonValueSchema.parse(nodeCharacterizationExecutionOutputSchema.parse({
@@ -56,8 +59,8 @@ export const executeNodeCharacterization = async (dependencies, rawInput, option
56
59
  plan: prepared.value.plan,
57
60
  transformation: host.instrumentation.manifest,
58
61
  transformation_evidence: prepared.value.transformation_evidence,
59
- evidence: createCharacterizationEvidence(prepared.value, controlledReplayOutputSchema.parse(executed.value)),
60
- replay: controlledReplayOutputSchema.parse(executed.value),
62
+ evidence: createCharacterizationEvidence(prepared.value, replayOutput),
63
+ replay: replayOutput,
61
64
  })));
62
65
  };
63
66
  const prepareValidated = async (dependencies, input, options) => {
@@ -66,9 +69,7 @@ const prepareValidated = async (dependencies, input, options) => {
66
69
  if (!replay.ok)
67
70
  return replay;
68
71
  const output = controlledReplayOutputSchema.parse(replay.value);
69
- if (output.phase !== "plan" ||
70
- output.plan === null ||
71
- host.instrumentation === null)
72
+ if (output.phase !== "plan" || host.instrumentation === null)
72
73
  return err(new AnalysisProtocolError("Node characterization preparation omitted committed plan evidence"));
73
74
  const module = output.plan.left.modules.find(({ alias }) => alias === input.selected_alias);
74
75
  if (module === undefined)
@@ -109,8 +110,6 @@ const createTransformationEvidence = (input, instrumentation) => createEvidence(
109
110
  ],
110
111
  });
111
112
  const createCharacterizationEvidence = (prepared, replay) => {
112
- if (replay.phase !== "execute" || replay.evidence === null)
113
- throw new AnalysisProtocolError("Node characterization execution omitted replay Evidence");
114
113
  return createEvidence({
115
114
  path: prepared.plan.artifact.path,
116
115
  sha256: prepared.plan.artifact.sha256,
@@ -264,6 +264,11 @@ export const resolveProcessResult = (capture, executionFailure, cleanupFailure)
264
264
  return capture;
265
265
  };
266
266
  export const prepareProcessCapture = async (scenario, policy, signal, host = systemProcessPreparationHost) => {
267
+ if (policy.status === "disabled")
268
+ throw new ProcessCaptureError("process capture is disabled", {
269
+ userCategory: "permission_required",
270
+ userMessage: processPolicyMessage("process capture is disabled"),
271
+ });
267
272
  const decision = authorizeProcessScenario(scenario, policy);
268
273
  if (!decision.allowed)
269
274
  throw new ProcessCaptureError(decision.reason, {
@@ -128,7 +128,8 @@ const readJson = async (path) => {
128
128
  if (bytes.length > MAX_INPUT_BYTES)
129
129
  throw new ProcessCliFailure("truncated", "Process input file is too large. Reduce it below 64 MiB, then try again.");
130
130
  try {
131
- return JSON.parse(bytes.toString("utf8"));
131
+ const parsed = JSON.parse(bytes.toString("utf8"));
132
+ return parsed;
132
133
  }
133
134
  catch {
134
135
  throw new ProcessCliFailure("invalid_input", "Process input file is not valid JSON. Repair the file, then try again.");
@@ -184,13 +184,18 @@ const completeCapture = async (options) => {
184
184
  }
185
185
  throw processCaptureCancelled();
186
186
  }
187
+ const settlement = await observeSettlement(options.runId, selectCapturedProcessGroupIds(runtime.terminal.pid, options.samples), scenario.settle_ms, options.recordEvent);
188
+ runtime.checkpoints.trigger("settled");
189
+ const samplingPartial = (await runtime.stopSampler()).partial;
187
190
  if (runtime.reactive !== undefined) {
191
+ // Process, filesystem, shim, and protocol observations can be recorded
192
+ // during settlement after the PTY exits. Make target loss terminal only
193
+ // after that journal has drained, otherwise the coordinator's control
194
+ // priority discards a valid multi-source completion predicate.
195
+ await runtime.reactive.coordinator.drain();
188
196
  await runtime.reactive.coordinator.submit({ kind: "target_lost" });
189
197
  runtime.reactive.unsubscribe();
190
198
  }
191
- const settlement = await observeSettlement(options.runId, selectCapturedProcessGroupIds(runtime.terminal.pid, options.samples), scenario.settle_ms, options.recordEvent);
192
- runtime.checkpoints.trigger("settled");
193
- const samplingPartial = (await runtime.stopSampler()).partial;
194
199
  assertNotCancelled(options.signal);
195
200
  const after = await snapshotRoots(scenario, options.signal);
196
201
  const renderedFrames = await runtime.renderer.frames();
@@ -39,9 +39,10 @@ export const normalizeProcessSamples = (samples, scenario, rootPid) => {
39
39
  mapping.set(identifier, mapping.size + 1);
40
40
  const normalizeCommand = (command) => {
41
41
  const normalized = normalizeProcessText(command, scenario, "<no-temporary-root>", rootPid);
42
- return scenario.normalization.pids
42
+ const withNormalizedPids = scenario.normalization.pids
43
43
  ? normalizePidTokens(normalized, identifiers)
44
44
  : normalized;
45
+ return withNormalizedPids.trim();
45
46
  };
46
47
  return samples.map((sample) => ({
47
48
  at_ms: normalizeProcessElapsedTime(sample.at_ms, scenario.normalization.time_bucket_ms),
@@ -13,6 +13,7 @@ const grantSchema = z.object({
13
13
  "browser_observe",
14
14
  "browser_automate",
15
15
  "electron_observe",
16
+ "electron_automate",
16
17
  "evidence_read",
17
18
  "evidence_write",
18
19
  "investigation_input",
@@ -173,7 +173,7 @@ export const importReferenceSource = async (options) => {
173
173
  try {
174
174
  return ok(createHistoricalSourceGraph(input));
175
175
  }
176
- catch (error) {
177
- return err(failure("parse", error instanceof Error ? error.message : "Graph failed validation"));
176
+ catch (cause) {
177
+ return err(failure("parse", cause instanceof Error ? cause.message : "Graph failed validation"));
178
178
  }
179
179
  };
@@ -26,7 +26,7 @@ export class SessionProviderRouter {
26
26
  : (target, resolutionOptions) => provider.resolveAnalysisProfile?.(target, resolutionOptions) ??
27
27
  Promise.resolve(ok({ profile: null, compatibility: {} })));
28
28
  return new SessionProviderRouter({
29
- kind: "legacy",
29
+ kind: "single",
30
30
  provider,
31
31
  identity,
32
32
  capabilities,
@@ -61,7 +61,7 @@ export class SessionProviderRouter {
61
61
  }
62
62
  /** Provider identities exposed through the flat 1.x compatibility field. */
63
63
  providerIdentities(route) {
64
- if (this.runtime.kind === "legacy") {
64
+ if (this.runtime.kind === "single") {
65
65
  if (route.capabilities === undefined)
66
66
  return [route.identity];
67
67
  return uniqueProviderIdentities([...route.capabilities.values()].map(({ provider }) => provider));
@@ -86,7 +86,7 @@ export class SessionProviderRouter {
86
86
  compatibility: {},
87
87
  binding: null,
88
88
  selection: undefined,
89
- createClient: (target, context) => createLegacyClient(runtime, target, undefined, context),
89
+ createClient: (target, context) => createSingleProviderClient(runtime, target, undefined, context),
90
90
  };
91
91
  }
92
92
  /** Resolve target routes before any provider client is created. */
@@ -122,12 +122,12 @@ export class SessionProviderRouter {
122
122
  compatibility: normalized.value.compatibility,
123
123
  binding: null,
124
124
  selection: undefined,
125
- createClient: (openedTarget, context) => createLegacyClient(runtime, openedTarget, normalized.value.profile ?? undefined, context),
125
+ createClient: (openedTarget, context) => createSingleProviderClient(runtime, openedTarget, normalized.value.profile ?? undefined, context),
126
126
  });
127
127
  }
128
128
  /** Candidate status authoritative for the active or target-free route. */
129
129
  candidateStatuses(route) {
130
- if (this.runtime.kind === "legacy")
130
+ if (this.runtime.kind === "single")
131
131
  return [];
132
132
  return route.selection?.candidates ?? this.runtime.registry.candidates();
133
133
  }
@@ -160,7 +160,7 @@ const selectableRoute = (auxiliaryProviders, selection) => {
160
160
  emptyClient(identity),
161
161
  };
162
162
  };
163
- const createLegacyClient = (runtime, target, profile, context) => typeof runtime.provider === "function"
163
+ const createSingleProviderClient = (runtime, target, profile, context) => typeof runtime.provider === "function"
164
164
  ? runtime.provider(target, profile, context)
165
165
  : runtime.provider.createClient(target, profile, context);
166
166
  const emptyClient = (identity) => ({
@@ -1,10 +1,12 @@
1
1
  import { constants as fsConstants } from "node:fs";
2
2
  import { copyFile, mkdir, readFile, rm, writeFile } from "node:fs/promises";
3
3
  import { dirname } from "node:path";
4
+ import canonicalize from "canonicalize";
4
5
  import { z } from "zod";
5
6
  import writeFileAtomic from "write-file-atomic";
6
7
  import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
7
8
  import { PRODUCT_IDENTITY } from "../identity.js";
9
+ import { MCP_STARTUP_POLICY } from "../mcpStartupPolicy.js";
8
10
  import { resolveClientConfigTransactionPath } from "./ClientConfigPath.js";
9
11
  const defaultCommand = () => [
10
12
  "npx",
@@ -12,7 +14,6 @@ const defaultCommand = () => [
12
14
  PRODUCT_IDENTITY.registrationPackageSpecifier,
13
15
  "mcp",
14
16
  ];
15
- const CODEX_STARTUP_TIMEOUT_SECONDS = 30;
16
17
  /** Back up, atomically update, and semantically read back one JSON MCP configuration. */
17
18
  export const configureJsonClient = async (client, environment = {}, command = defaultCommand()) => {
18
19
  const transactionPath = await resolveClientConfigTransactionPath(client.configPath);
@@ -187,7 +188,11 @@ const objectSchema = z.record(z.string(), z.unknown());
187
188
  const parseOptionalObject = (value) => value === undefined ? {} : objectSchema.parse(value);
188
189
  const parseObject = (text) => objectSchema.parse(JSON.parse(text));
189
190
  const isMissing = (cause) => cause instanceof Error && "code" in cause && cause.code === "ENOENT";
190
- const sameConfiguration = (left, right) => JSON.stringify(left) === JSON.stringify(right);
191
+ const sameConfiguration = (left, right) => {
192
+ const encodedLeft = canonicalize(left);
193
+ const encodedRight = canonicalize(right);
194
+ return encodedLeft !== undefined && encodedLeft === encodedRight;
195
+ };
191
196
  const preserveConfigBackup = async (source, destination) => {
192
197
  try {
193
198
  await copyFile(source, destination, fsConstants.COPYFILE_EXCL);
@@ -214,7 +219,9 @@ const clientConfigurationDesired = (client, providerEnvironment, command) => {
214
219
  command: command[0] ?? PRODUCT_IDENTITY.cliBinary,
215
220
  args: command.slice(1),
216
221
  ...(client.name === "codex"
217
- ? { startup_timeout_sec: CODEX_STARTUP_TIMEOUT_SECONDS }
222
+ ? {
223
+ startup_timeout_sec: MCP_STARTUP_POLICY.codexStartupTimeoutSeconds,
224
+ }
218
225
  : {}),
219
226
  ...(Object.keys(environment).length === 0 ? {} : { env: environment }),
220
227
  };
@@ -2,6 +2,7 @@ import { constants } from "node:fs";
2
2
  import { mkdtemp, rm, symlink, writeFile } from "node:fs/promises";
3
3
  import { tmpdir } from "node:os";
4
4
  import { join } from "node:path";
5
+ import { windowsNativeCapabilities, } from "../process/WindowsAuthority.js";
5
6
  import { probeProcessCaptureCapability, } from "./ProcessCaptureCapability.js";
6
7
  /** Probe named prerequisites without converting missing controls into support. */
7
8
  export const probeWindowsCapabilities = async (dependencies = systemDependencies()) => {
@@ -17,11 +18,11 @@ export const probeWindowsCapabilities = async (dependencies = systemDependencies
17
18
  no_follow_open: dependencies.probeNoFollowOpen(),
18
19
  private_acl: dependencies.probePrivateAcl(),
19
20
  unix_domain_socket: dependencies.probeUnixDomainSocket(),
20
- pty: {
21
- available: pty.available,
22
- reason: pty.available ? null : pty.reason,
23
- },
21
+ pty: pty.available
22
+ ? { available: true, reason: null }
23
+ : { available: false, reason: pty.reason },
24
24
  },
25
+ security: windowsNativeCapabilities(dependencies.platform),
25
26
  };
26
27
  };
27
28
  const systemDependencies = () => ({
@@ -1,12 +1,10 @@
1
- import { BinarySession } from "./BinarySession.js";
2
1
  import { HopperProvider } from "../hopper/HopperProvider.js";
3
2
  import { GhidraProvider } from "../ghidra/GhidraProvider.js";
4
- import { NativeMacOSProvider } from "../native/NativeMacOSProvider.js";
5
- import { ArtifactProvider } from "../artifacts/ArtifactProvider.js";
6
- import { ManagedStaticProvider } from "../dotnet/ManagedStaticProvider.js";
7
3
  import { silentLogger } from "../logger.js";
4
+ import { GENERATED_AUXILIARY_PROVIDERS } from "../generatedMcpToolCatalog.js";
8
5
  import { AnalysisProviderRegistry } from "./AnalysisProviderRegistry.js";
9
- import { SessionProviderRouter } from "./SessionProviderRouter.js";
6
+ import { composeBinarySession } from "./BinarySessionComposition.js";
7
+ import { LazyAnalysisProvider } from "./LazyAnalysisProvider.js";
10
8
  /**
11
9
  * Compose the target-switching runtime shared directly by CLI and MCP adapters.
12
10
  * This is the sole production wiring point, so both adapters share identical
@@ -15,9 +13,28 @@ import { SessionProviderRouter } from "./SessionProviderRouter.js";
15
13
  export const createBinarySession = (config, logger = silentLogger) => {
16
14
  const hopper = new HopperProvider(config, logger);
17
15
  const ghidra = new GhidraProvider(config, logger);
18
- return new BinarySession(SessionProviderRouter.selectable(new AnalysisProviderRegistry([hopper, ghidra], config.analysisProvider), [
19
- new ArtifactProvider(config.artifactNativeMountEnabled, config.artifactIntegrityContinueEnabled),
20
- new NativeMacOSProvider(),
21
- new ManagedStaticProvider(),
16
+ const auxiliary = new Map(GENERATED_AUXILIARY_PROVIDERS.map((provider) => [
17
+ provider.identity.id,
18
+ provider,
22
19
  ]));
20
+ const lazyProvider = (id, load) => {
21
+ const generated = auxiliary.get(id);
22
+ if (generated === undefined)
23
+ throw new TypeError(`Missing generated provider metadata for ${id}`);
24
+ return new LazyAnalysisProvider({ ...generated, load });
25
+ };
26
+ return composeBinarySession(new AnalysisProviderRegistry([hopper, ghidra], config.analysisProvider), [
27
+ lazyProvider("rea-artifact-graph", async () => {
28
+ const { ArtifactProvider } = await import("../artifacts/ArtifactProvider.js");
29
+ return new ArtifactProvider(config.artifactNativeMountEnabled, config.artifactIntegrityContinueEnabled);
30
+ }),
31
+ lazyProvider("native-macos", async () => {
32
+ const { NativeMacOSProvider } = await import("../native/NativeMacOSProvider.js");
33
+ return new NativeMacOSProvider();
34
+ }),
35
+ lazyProvider("rea-dotnet-static", async () => {
36
+ const { ManagedStaticProvider } = await import("../dotnet/ManagedStaticProvider.js");
37
+ return new ManagedStaticProvider();
38
+ }),
39
+ ]);
23
40
  };
@@ -8,6 +8,7 @@ import { ArtifactReaderFailure, } from "./ArtifactReader.js";
8
8
  import { ARTIFACT_GRAPH_PROVIDER } from "../application/InvestigationProviders.js";
9
9
  import { createEvidence } from "../domain/evidence.js";
10
10
  import { createArtifactInspection } from "../domain/artifactInspection.js";
11
+ import { resolveArtifactIntegrityPolicy, resolveNativeMountPolicy, } from "../application/ArtifactInventory/policy.js";
11
12
  const IDENTITY = Object.freeze(ARTIFACT_GRAPH_PROVIDER);
12
13
  /** Read-only inventory and exclusively owned extraction provider. */
13
14
  export class ArtifactProvider {
@@ -180,16 +181,13 @@ class ArtifactClient {
180
181
  edgeLimit: parsed.edge_limit,
181
182
  }, {
182
183
  ...(options?.signal === undefined ? {} : { signal: options.signal }),
183
- nativeMount: {
184
- nativeMountApproved: parsed.native_mount_approved === true,
185
- nativeMountEnabled: this.nativeMountEnabled,
186
- },
187
- integrity: {
188
- mode: parsed.integrity_policy,
189
- approved: parsed.integrity_continue_approved === true,
190
- enabled: this.integrityContinueEnabled,
191
- maxMismatches: parsed.max_integrity_mismatches,
192
- },
184
+ nativeMount: resolveNativeMountPolicy(parsed.native_mount_approved === true, this.nativeMountEnabled),
185
+ integrity: resolveArtifactIntegrityPolicy(parsed.integrity_policy === "fail"
186
+ ? { mode: "fail" }
187
+ : {
188
+ mode: parsed.integrity_policy,
189
+ maxMismatches: parsed.max_integrity_mismatches,
190
+ }, this.integrityContinueEnabled),
193
191
  });
194
192
  }
195
193
  }
@@ -14,9 +14,7 @@ export class SafeOutputTree {
14
14
  #totalBytes = 0;
15
15
  #published = false;
16
16
  #cleanup = {
17
- attempted: false,
18
- verified: false,
19
- residualPaths: [],
17
+ status: "not-required",
20
18
  };
21
19
  constructor(outputRoot, stagingRoot, limits) {
22
20
  this.#outputRoot = outputRoot;
@@ -126,11 +124,12 @@ export class SafeOutputTree {
126
124
  return structuredClone(this.#cleanup);
127
125
  await rm(this.#stagingRoot, { recursive: true, force: true });
128
126
  const absent = await isAbsent(this.#stagingRoot);
129
- this.#cleanup = {
130
- attempted: true,
131
- verified: absent,
132
- residualPaths: absent ? [] : [basename(this.#stagingRoot)],
133
- };
127
+ this.#cleanup = absent
128
+ ? { status: "complete", residualPaths: [] }
129
+ : {
130
+ status: "incomplete",
131
+ residualPaths: [basename(this.#stagingRoot)],
132
+ };
134
133
  if (!absent)
135
134
  throw new ArtifactReaderFailure("integrity", "Extraction output cleanup could not be verified");
136
135
  return structuredClone(this.#cleanup);
@@ -19,13 +19,16 @@ export const captureStorageFingerprints = async ({ context, origin, local, sessi
19
19
  await addIndexedDb(run, origin, indexedDbNames);
20
20
  await addCaches(run, caches);
21
21
  state.items.sort((left, right) => compareCodePoints(`${left.scope}:${left.identity_sha256}`, `${right.scope}:${right.identity_sha256}`));
22
- return {
23
- items: state.items,
24
- complete: state.complete &&
25
- !state.truncated &&
26
- state.items.every(({ complete }) => complete),
27
- truncated: state.truncated,
28
- };
22
+ const complete = state.complete &&
23
+ !state.truncated &&
24
+ state.items.every(({ complete }) => complete);
25
+ return complete
26
+ ? { items: state.items, complete: true, truncated: false }
27
+ : {
28
+ items: state.items,
29
+ complete: false,
30
+ truncated: state.truncated,
31
+ };
29
32
  };
30
33
  const addStorageItems = (state, scope, items) => {
31
34
  for (const item of items)
@@ -44,7 +44,9 @@ export const inspectCdpElectronPage = async (context) => {
44
44
  };
45
45
  const runElectronInspection = async (context, state, startedAt) => {
46
46
  const frames = await authorizeInitialFrames(context, state);
47
- const main = frames[0];
47
+ const main = frames.at(0);
48
+ if (main === undefined)
49
+ throw new BrowserObservationError("inspect_web_page", "target_not_allowed");
48
50
  state.mainFrameId = main.frame_id;
49
51
  await enableElectronCapture(context);
50
52
  await delayWithCancellation(context.input.observation_ms, "inspect_electron_page", context.signal);
@@ -36,3 +36,8 @@ export const authorizeRuntimeLocation = async (value, roots, origins) => {
36
36
  },
37
37
  };
38
38
  };
39
+ /** Authorize a target whose Node Inspector URL omits its main entry path. */
40
+ export const authorizeRuntimeTargetLocation = async (value, targetType, roots, origins) =>
41
+ // A bare file:// URL contains no source identity. Do not attach to the
42
+ // first configured root merely because the target happens to be Node.
43
+ authorizeRuntimeLocation(value, roots, origins);
@@ -3,8 +3,14 @@ import { browserScenarioCaptureSchema, browserScenarioCompletenessSchema, browse
3
3
  import { AnalysisError, BrowserObservationError, ProviderAdapterError, } from "../domain/errors.js";
4
4
  import { err, ok } from "../domain/result.js";
5
5
  import { BrowserScenarioCaptureBudget } from "./PlaywrightScenarioArtifacts.js";
6
- import { PlaywrightScenarioSessionFactory } from "./PlaywrightScenarioSession.js";
7
6
  const OPERATION = "capture_browser_scenario";
7
+ let defaultFactory;
8
+ const lazyPlaywrightFactory = {
9
+ async open(scenario, options) {
10
+ defaultFactory ??= import("./PlaywrightScenarioSession.js").then(({ PlaywrightScenarioSessionFactory }) => new PlaywrightScenarioSessionFactory());
11
+ return (await defaultFactory).open(scenario, options);
12
+ },
13
+ };
8
14
  export const PLAYWRIGHT_BROWSER_SCENARIO_PROVIDER_IDENTITY = Object.freeze({
9
15
  id: "rea-playwright-browser-scenario",
10
16
  name: "REA Playwright browser scenario capture provider",
@@ -234,7 +240,7 @@ const runScenario = async (factory, scenario, options) => {
234
240
  /** Controlled Playwright/CDP scenario driver with exact process ownership. */
235
241
  export class PlaywrightBrowserScenarioProvider {
236
242
  factory;
237
- constructor(factory = new PlaywrightScenarioSessionFactory()) {
243
+ constructor(factory = lazyPlaywrightFactory) {
238
244
  this.factory = factory;
239
245
  }
240
246
  identity() {