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,5 +1,4 @@
1
1
  import { z } from "zod";
2
- import { jsonValueSchema } from "./jsonValue.js";
3
2
  import { AnalysisOutputError, HopperProtocolError } from "./errors.js";
4
3
  import { err, ok } from "./result.js";
5
4
  import { nativeApiBoundarySchema } from "./nativeApiBoundary.js";
@@ -35,31 +34,24 @@ const segmentSchema = z.object({
35
34
  writable: z.boolean().nullable().default(null),
36
35
  executable: z.boolean().nullable().default(null),
37
36
  });
38
- const addressedPageSchema = z
39
- .object({
37
+ const addressedPageFacts = {
40
38
  items: z.array(z.object({ address: z.string(), value: z.string() })),
41
39
  offset: z.number().int().min(0),
42
40
  limit: z.number().int().min(1),
43
41
  total: z.number().int().min(0),
44
- next_offset: z.number().int().min(0).nullable(),
45
- has_more: z.boolean(),
46
- })
47
- .superRefine((value, context) => {
48
- if (value.has_more && value.next_offset === null) {
49
- context.addIssue({
50
- code: "custom",
51
- message: "a page with more results must provide next_offset",
52
- path: ["next_offset"],
53
- });
54
- }
55
- if (!value.has_more && value.next_offset !== null) {
56
- context.addIssue({
57
- code: "custom",
58
- message: "a complete page must not provide next_offset",
59
- path: ["next_offset"],
60
- });
61
- }
62
- });
42
+ };
43
+ const addressedPageSchema = z.discriminatedUnion("has_more", [
44
+ z.object({
45
+ ...addressedPageFacts,
46
+ has_more: z.literal(true),
47
+ next_offset: z.number().int().min(0),
48
+ }),
49
+ z.object({
50
+ ...addressedPageFacts,
51
+ has_more: z.literal(false),
52
+ next_offset: z.null(),
53
+ }),
54
+ ]);
63
55
  const unavailableAnalysisFactSchema = z
64
56
  .object({ available: z.literal(false), reason: z.string() })
65
57
  .strict();
@@ -84,38 +76,42 @@ export const localVariableSchema = z
84
76
  provenance: z.string().min(1),
85
77
  })
86
78
  .strict();
87
- const boundedSchema = (item) => z
88
- .object({
89
- items: z.array(item),
90
- total: z.number().int().min(0).nullable(),
91
- returned: z.number().int().min(0),
92
- truncated: z.boolean(),
93
- next_offset: z.number().int().min(0).nullable(),
94
- })
95
- .strict()
96
- .superRefine((value, context) => {
97
- if (value.returned !== value.items.length) {
98
- context.addIssue({
99
- code: "custom",
100
- message: "returned must equal the number of items",
101
- path: ["returned"],
102
- });
103
- }
104
- if (value.total !== null && value.total < value.returned) {
105
- context.addIssue({
106
- code: "custom",
107
- message: "total cannot be smaller than returned",
108
- path: ["total"],
109
- });
110
- }
111
- if (value.next_offset !== null && !value.truncated) {
112
- context.addIssue({
113
- code: "custom",
114
- message: "a continuation requires truncated output",
115
- path: ["next_offset"],
116
- });
117
- }
118
- });
79
+ const boundedSchema = (item) => {
80
+ const boundedFacts = {
81
+ items: z.array(item),
82
+ total: z.number().int().min(0).nullable(),
83
+ returned: z.number().int().min(0),
84
+ };
85
+ return z
86
+ .discriminatedUnion("truncated", [
87
+ z.strictObject({
88
+ ...boundedFacts,
89
+ truncated: z.literal(false),
90
+ next_offset: z.null(),
91
+ }),
92
+ z.strictObject({
93
+ ...boundedFacts,
94
+ truncated: z.literal(true),
95
+ next_offset: z.number().int().min(0).nullable(),
96
+ }),
97
+ ])
98
+ .superRefine((value, context) => {
99
+ if (value.returned !== value.items.length) {
100
+ context.addIssue({
101
+ code: "custom",
102
+ message: "returned must equal the number of items",
103
+ path: ["returned"],
104
+ });
105
+ }
106
+ if (value.total !== null && value.total < value.returned) {
107
+ context.addIssue({
108
+ code: "custom",
109
+ message: "total cannot be smaller than returned",
110
+ path: ["total"],
111
+ });
112
+ }
113
+ });
114
+ };
119
115
  /** Provider-neutral bounded raw-instruction window for one analyzed function. */
120
116
  export const functionInstructionWindowSchema = z
121
117
  .object({
@@ -171,14 +167,22 @@ export const functionDossierSchema = z
171
167
  })
172
168
  .strict(),
173
169
  pseudocode: z
174
- .object({
175
- text: z.string(),
176
- total_chars: z.number().int().min(0),
177
- returned_chars: z.number().int().min(0),
178
- truncated: z.boolean(),
179
- next_offset: z.number().int().min(0).nullable(),
180
- })
181
- .strict()
170
+ .discriminatedUnion("truncated", [
171
+ z.strictObject({
172
+ text: z.string(),
173
+ total_chars: z.number().int().min(0),
174
+ returned_chars: z.number().int().min(0),
175
+ truncated: z.literal(false),
176
+ next_offset: z.null(),
177
+ }),
178
+ z.strictObject({
179
+ text: z.string(),
180
+ total_chars: z.number().int().min(0),
181
+ returned_chars: z.number().int().min(0),
182
+ truncated: z.literal(true),
183
+ next_offset: z.number().int().min(0).nullable(),
184
+ }),
185
+ ])
182
186
  .superRefine((value, context) => {
183
187
  if (value.returned_chars !== [...value.text].length) {
184
188
  context.addIssue({
@@ -194,13 +198,6 @@ export const functionDossierSchema = z
194
198
  path: ["total_chars"],
195
199
  });
196
200
  }
197
- if (value.next_offset !== null && !value.truncated) {
198
- context.addIssue({
199
- code: "custom",
200
- message: "a continuation requires truncated pseudocode",
201
- path: ["next_offset"],
202
- });
203
- }
204
201
  }),
205
202
  assembly: boundedSchema(z.string()),
206
203
  comments: boundedSchema(z
@@ -238,7 +235,7 @@ export const functionDossierSchema = z
238
235
  instruction_scan: z
239
236
  .object({ scanned: z.number().int().min(0), truncated: z.boolean() })
240
237
  .strict(),
241
- native_api: nativeApiBoundarySchema.optional(),
238
+ native_api: nativeApiBoundarySchema.nullable().default(null),
242
239
  limitations: z.array(z.string()).default([]),
243
240
  })
244
241
  .strict();
@@ -246,7 +243,7 @@ export const functionDossierSchema = z
246
243
  export const parseFunctionDossier = (value) => {
247
244
  const parsed = functionDossierSchema.safeParse(value);
248
245
  return parsed.success
249
- ? ok(jsonValueSchema.parse(parsed.data))
246
+ ? ok(parsed.data)
250
247
  : err(new AnalysisOutputError("analyze_function", "provider output did not match the dossier contract", { cause: parsed.error }));
251
248
  };
252
249
  /** Parse page entries and continuation metadata returned by list operations. */
@@ -2,6 +2,8 @@
2
2
  export const projectInputIssues = (issues, input) => issues.flatMap((issue) => projectIssue(issue, input));
3
3
  const projectIssue = (issue, input) => {
4
4
  const path = issue.path.flatMap((part) => typeof part === "string" || typeof part === "number" ? [part] : []);
5
+ if (issue.code === "invalid_union")
6
+ return issue.errors.flatMap((branch) => branch.flatMap((branchIssue) => projectIssue(branchIssue, input)));
5
7
  if (issue.code === "unrecognized_keys")
6
8
  return issue.keys.map((key) => ({
7
9
  path: [...path, key],
@@ -44,7 +46,8 @@ const valueAtPath = (input, path) => {
44
46
  for (const part of path) {
45
47
  if (typeof current !== "object" || current === null)
46
48
  return undefined;
47
- current = current[part];
49
+ const next = Reflect.get(current, part);
50
+ current = next;
48
51
  }
49
52
  return current;
50
53
  };
@@ -37,8 +37,7 @@ const DEFAULT_INVESTIGATION_RUN_OPTIONS = {
37
37
  change_limit: 500,
38
38
  };
39
39
  /** Explicit write approval and two local versions for an automatic run. */
40
- export const crossVersionInvestigationInputSchema = z
41
- .object({
40
+ const crossVersionInvestigationFacts = {
42
41
  approved: z.literal(true),
43
42
  workspace_path: z.string().min(1).max(4_096),
44
43
  workspace_name: z.string().trim().min(1).max(200).default("default"),
@@ -49,20 +48,22 @@ export const crossVersionInvestigationInputSchema = z
49
48
  .optional(),
50
49
  left_path: z.string().min(1).max(4_096),
51
50
  right_path: z.string().min(1).max(4_096),
52
- integrity_policy: z.enum(["fail", "record-and-continue"]).default("fail"),
53
- integrity_continue_approved: z.boolean().default(false),
54
- max_integrity_mismatches: z.number().int().min(1).max(100).default(10),
55
51
  options: investigationRunOptionsSchema.default(DEFAULT_INVESTIGATION_RUN_OPTIONS),
56
- })
57
- .superRefine((input, context) => {
58
- if (input.integrity_policy === "record-and-continue" &&
59
- input.integrity_continue_approved !== true)
60
- context.addIssue({
61
- code: "custom",
62
- path: ["integrity_continue_approved"],
63
- message: "record-and-continue requires explicit approval",
64
- });
65
- });
52
+ };
53
+ export const crossVersionInvestigationInputSchema = z.union([
54
+ z.object({
55
+ ...crossVersionInvestigationFacts,
56
+ integrity_policy: z.literal("fail").default("fail"),
57
+ integrity_continue_approved: z.literal(false).default(false),
58
+ max_integrity_mismatches: z.number().int().min(1).max(100).default(10),
59
+ }),
60
+ z.object({
61
+ ...crossVersionInvestigationFacts,
62
+ integrity_policy: z.literal("record-and-continue"),
63
+ integrity_continue_approved: z.literal(true),
64
+ max_integrity_mismatches: z.number().int().min(1).max(100).default(10),
65
+ }),
66
+ ]);
66
67
  const targetSchema = z.object({
67
68
  root_sha256: digestSchema,
68
69
  graph_sha256: digestSchema,
@@ -223,7 +223,7 @@ const comparisonChangeSchema = z.strictObject({
223
223
  right: valueAvailabilitySchema,
224
224
  left_source_range: sourceRangeSchema.nullable(),
225
225
  right_source_range: sourceRangeSchema.nullable(),
226
- evidence_links: z.tuple([evidenceIdSchema, evidenceIdSchema]),
226
+ evidence_links: z.array(evidenceIdSchema).length(2),
227
227
  limitations: z.array(boundedTextSchema).max(20),
228
228
  });
229
229
  /** Bounded static export-return comparison with explicit unknown semantics. */
@@ -267,7 +267,7 @@ export const javaScriptExportShapeComparisonResultSchema = z.strictObject({
267
267
  omitted_candidates: z.number().int().min(0),
268
268
  omitted_changes: z.number().int().min(0),
269
269
  }),
270
- evidence_links: z.tuple([evidenceIdSchema, evidenceIdSchema]),
270
+ evidence_links: z.array(evidenceIdSchema).length(2),
271
271
  limitations: z.array(boundedTextSchema).max(1_000),
272
272
  runtime_validation: z.strictObject({
273
273
  recommended_tool: z.literal("run_controlled_replay"),
@@ -105,9 +105,7 @@ const determinismSchema = z
105
105
  platform: z.literal("linux").default("linux"),
106
106
  })
107
107
  .strict();
108
- export const controlledReplayInputSchema = z
109
- .object({
110
- mode: z.enum(["plan", "execute"]),
108
+ const controlledReplayInputShape = {
111
109
  left: replaySideSchema,
112
110
  right: replaySideSchema.optional(),
113
111
  cases: z.array(explicitCaseSchema).max(128).default([]),
@@ -133,18 +131,32 @@ export const controlledReplayInputSchema = z
133
131
  result_depth: 16,
134
132
  result_nodes: 10_000,
135
133
  }),
136
- approved: z.boolean().default(false),
137
- plan_digest: digestSchema.optional(),
138
134
  reproducer_export: z
139
- .object({
135
+ .strictObject({
140
136
  path: absolutePathSchema,
141
- approved: z.boolean(),
137
+ approved: z.literal(true),
142
138
  include_sources: z.boolean().default(false),
143
139
  })
144
- .strict()
145
140
  .optional(),
146
- })
147
- .strict()
141
+ };
142
+ /** Parse a replay request that can only construct a plan. */
143
+ export const controlledReplayPlanInputSchema = z.strictObject({
144
+ ...controlledReplayInputShape,
145
+ mode: z.literal("plan"),
146
+ });
147
+ /** Parse a replay request carrying literal approval for one exact plan. */
148
+ export const controlledReplayExecutionInputSchema = z.strictObject({
149
+ ...controlledReplayInputShape,
150
+ mode: z.literal("execute"),
151
+ approved: z.literal(true),
152
+ plan_digest: digestSchema,
153
+ });
154
+ /** Parse a controlled replay request into its legal plan or execution state. */
155
+ export const controlledReplayInputSchema = z
156
+ .discriminatedUnion("mode", [
157
+ controlledReplayPlanInputSchema,
158
+ controlledReplayExecutionInputSchema,
159
+ ])
148
160
  .superRefine((value, context) => {
149
161
  if (value.cases.length === 0 && value.generator === undefined)
150
162
  context.addIssue({
@@ -158,13 +170,6 @@ export const controlledReplayInputSchema = z
158
170
  path: ["generator", "count"],
159
171
  message: "Explicit and generated replay cases must total at most 128",
160
172
  });
161
- if (value.mode === "execute" &&
162
- (value.approved !== true || value.plan_digest === undefined))
163
- context.addIssue({
164
- code: "custom",
165
- path: ["approved"],
166
- message: "Execution requires literal approval and a plan digest",
167
- });
168
173
  });
169
174
  const moduleCommitmentSchema = z
170
175
  .object({
@@ -201,7 +206,7 @@ const replayPlanSchema = z
201
206
  filesystem: z
202
207
  .object({
203
208
  host_writes: z.literal(false),
204
- private_tmpfs_bytes: z.number().int(),
209
+ private_tmpfs_bytes: z.number().int().nonnegative(),
205
210
  })
206
211
  .strict(),
207
212
  runtime: z
@@ -255,34 +260,45 @@ const replayPlanSchema = z
255
260
  .nullable(),
256
261
  })
257
262
  .strict();
258
- const replayOutcomeSchema = z
259
- .object({
263
+ const replayOutcomeFacts = {
260
264
  case_id: z.string(),
261
- outcome: z.enum([
262
- "return",
263
- "exception",
264
- "serialization_error",
265
- "denied",
266
- "timeout",
267
- "oom",
268
- "crash",
269
- "cancelled",
270
- "protocol_error",
271
- ]),
272
- value: z.json().optional(),
273
- exception: z
274
- .object({
275
- name: z.string(),
276
- message: z.string(),
277
- stack: z.string().nullable(),
278
- })
279
- .strict()
280
- .optional(),
281
265
  input_sha256: digestSchema,
282
- output_sha256: digestSchema.nullable(),
283
- truncated: z.boolean(),
266
+ };
267
+ const replayExceptionSchema = z
268
+ .object({
269
+ name: z.string(),
270
+ message: z.string(),
271
+ stack: z.string().nullable(),
284
272
  })
285
273
  .strict();
274
+ const replayOutcomeSchema = z.discriminatedUnion("outcome", [
275
+ z.strictObject({
276
+ ...replayOutcomeFacts,
277
+ outcome: z.literal("return"),
278
+ value: z.json(),
279
+ output_sha256: digestSchema,
280
+ truncated: z.literal(false),
281
+ }),
282
+ z.strictObject({
283
+ ...replayOutcomeFacts,
284
+ outcome: z.enum(["exception", "serialization_error", "denied"]),
285
+ exception: z.object(replayExceptionSchema.shape).strict(),
286
+ output_sha256: digestSchema,
287
+ truncated: z.literal(false),
288
+ }),
289
+ z.strictObject({
290
+ ...replayOutcomeFacts,
291
+ outcome: z.enum(["timeout", "oom", "crash", "cancelled"]),
292
+ output_sha256: z.null(),
293
+ truncated: z.literal(false),
294
+ }),
295
+ z.strictObject({
296
+ ...replayOutcomeFacts,
297
+ outcome: z.literal("protocol_error"),
298
+ output_sha256: z.null(),
299
+ truncated: z.literal(true),
300
+ }),
301
+ ]);
286
302
  export const replayExecutionResultSchema = z
287
303
  .object({
288
304
  schema_version: z.literal(1),
@@ -337,25 +353,25 @@ export const replayExecutionResultSchema = z
337
353
  export const replayEvidenceSchema = evidenceEnvelopeSchema
338
354
  .omit({ normalized_result: true })
339
355
  .extend({ normalized_result: replayExecutionResultSchema });
340
- export const controlledReplayOutputSchema = z
341
- .object({
342
- phase: z.enum(["plan", "execute"]),
343
- plan: replayPlanSchema.nullable(),
344
- source_evidence: z.array(replayEvidenceSchema),
345
- evidence: replayEvidenceSchema.nullable(),
346
- })
347
- .strict()
348
- .superRefine((value, context) => {
349
- if ((value.phase === "plan" &&
350
- (value.plan === null ||
351
- value.evidence !== null ||
352
- value.source_evidence.length !== 0)) ||
353
- (value.phase === "execute" &&
354
- (value.plan !== null ||
355
- value.evidence === null ||
356
- value.source_evidence.length === 0)))
357
- context.addIssue({
358
- code: "custom",
359
- message: "Replay output phase does not match its payload",
360
- });
356
+ /** A replay plan result with no claimed runtime observation. */
357
+ export const controlledReplayPlanOutputSchema = z.strictObject({
358
+ phase: z.literal("plan"),
359
+ plan: replayPlanSchema,
360
+ source_evidence: z
361
+ .array(replayEvidenceSchema)
362
+ .length(0)
363
+ .brand(),
364
+ evidence: z.null(),
365
+ });
366
+ /** An executed replay result with its required source and aggregate Evidence. */
367
+ export const controlledReplayExecutionOutputSchema = z.strictObject({
368
+ phase: z.literal("execute"),
369
+ plan: z.null(),
370
+ source_evidence: z.array(replayEvidenceSchema).min(1),
371
+ evidence: replayEvidenceSchema,
361
372
  });
373
+ /** Parse replay output into its legal plan or execution state. */
374
+ export const controlledReplayOutputSchema = z.discriminatedUnion("phase", [
375
+ controlledReplayPlanOutputSchema,
376
+ controlledReplayExecutionOutputSchema,
377
+ ]);
@@ -83,6 +83,7 @@ export const javascriptRuntimeLocationSchema = z.discriminatedUnion("kind", [
83
83
  z.strictObject({
84
84
  kind: z.literal("file"),
85
85
  file_path: z.string().min(1).max(16_384),
86
+ authority: z.literal("scope-fallback").optional(),
86
87
  }),
87
88
  z.strictObject({
88
89
  kind: z.literal("url"),
@@ -0,0 +1,89 @@
1
+ import { createHash } from "node:crypto";
2
+ import { isAbsolute, relative } from "node:path";
3
+ import canonicalize from "canonicalize";
4
+ import { z } from "zod";
5
+ import { classifyBrowserCompleteness, } from "./browserCompleteness.js";
6
+ import { electronActiveObservationResultSchema, } from "./electronActiveObservation.js";
7
+ /** Parse active Electron Evidence as a bounded, target-only runtime capture. */
8
+ export const parseActiveElectronCapture = (evidence) => {
9
+ assertIdentity(evidence);
10
+ const result = electronActiveObservationResultSchema.parse(evidence.normalized_result);
11
+ const parameters = z
12
+ .object({
13
+ approved: z.literal(true),
14
+ application_path: absolutePathSchema,
15
+ application_root: absolutePathSchema,
16
+ })
17
+ .passthrough()
18
+ .parse(evidence.parameters);
19
+ if (result.application.application_path !== parameters.application_path ||
20
+ !isWithinRoot(parameters.application_root, result.application.application_path))
21
+ throw new TypeError("Active Electron Evidence application path disagrees with its approved root");
22
+ return {
23
+ kind: "electron-active",
24
+ evidence,
25
+ inspection: normalizeInspection(result),
26
+ captureSha256: digestCanonical(result),
27
+ scriptsCompleteWithinScope: false,
28
+ };
29
+ };
30
+ const absolutePathSchema = z.string().min(1).max(16_384).refine(isAbsolute);
31
+ const assertIdentity = (evidence) => {
32
+ if (evidence.operation !== "capture_electron_scenario" ||
33
+ evidence.predicate_type !== "rea.electron-active-scenario/v1" ||
34
+ evidence.provider.id !== "rea-playwright-electron-active" ||
35
+ evidence.provider.name !==
36
+ "REA Playwright active Electron observation provider" ||
37
+ evidence.provider.version !== "1" ||
38
+ evidence.authority !== "controlled-replay" ||
39
+ evidence.confidence !== "observed")
40
+ throw new TypeError("Evidence does not match the supported capture_electron_scenario contract");
41
+ };
42
+ const normalizeInspection = (result) => ({
43
+ target: {
44
+ target_id: `electron-active:${digestCanonical(result.application.application_path).slice(0, 32)}`,
45
+ type: "electron-application",
46
+ title: result.application.application_path,
47
+ attached: true,
48
+ file_path: result.application.application_path,
49
+ },
50
+ frames: [],
51
+ scripts: { items: [] },
52
+ workers: [],
53
+ completeness: classifyBrowserCompleteness({
54
+ policyFilteredSections: new Set(),
55
+ attachLimitedSections: new Set(),
56
+ truncatedSections: new Set(result.windows_truncated ||
57
+ result.processes.truncated ||
58
+ result.ipc.truncated ||
59
+ result.timeline.truncated
60
+ ? ["timeline"]
61
+ : []),
62
+ unavailableSections: new Set([
63
+ "frames",
64
+ "scripts",
65
+ "script_sources",
66
+ "workers",
67
+ ]),
68
+ excluded: [],
69
+ droppedEvents: {
70
+ scripts: 0,
71
+ network_requests: 0,
72
+ console_events: 0,
73
+ websocket_connections: 0,
74
+ websocket_frames: 0,
75
+ webmcp_tools: 0,
76
+ timeline_events: result.timeline.truncated ? result.timeline.observed : 0,
77
+ },
78
+ }),
79
+ });
80
+ const digestCanonical = (value) => {
81
+ const encoded = canonicalize(value);
82
+ if (encoded === undefined)
83
+ throw new TypeError("Runtime reconciliation could not canonicalize input");
84
+ return createHash("sha256").update(encoded).digest("hex");
85
+ };
86
+ const isWithinRoot = (root, path) => {
87
+ const remainder = relative(root, path);
88
+ return (remainder === "" || (!remainder.startsWith("..") && !isAbsolute(remainder)));
89
+ };
@@ -24,7 +24,7 @@ export const buildReconciledApplicationGraph = (input) => {
24
24
  "Runtime presence is bounded to passive capture windows and does not prove feature execution.",
25
25
  "Cross-layer observed_as edges are inferences; digest equality proves byte identity only.",
26
26
  "Source-map relationships retain their original static authority and are not promoted into runtime matches.",
27
- ...(facts.inputTruncated
27
+ ...(facts.inputStatus === "truncated"
28
28
  ? [
29
29
  "One or more source graphs or passive captures were incomplete or truncated.",
30
30
  ]
@@ -83,6 +83,8 @@ const graphCoverageFacts = (input, omittedNodeObservations) => {
83
83
  const captureHasUnknownOmissions = input.captures.some(({ inspection }) => inspection.completeness.unavailable_sections.length > 0);
84
84
  const inputTruncated = input.layers.some(({ graph }) => graph.coverage.truncated) ||
85
85
  captureTruncated;
86
+ const inputComplete = input.layers.every(({ graph }) => graph.coverage.status === "complete") &&
87
+ input.captures.every(({ inspection }) => inspection.completeness.status === "complete_within_window");
86
88
  const outputTruncated = projectionOmissions > 0;
87
89
  const sourceOmissions = input.layers.reduce((total, { graph }) => total + (graph.coverage.omitted_count ?? 0), 0);
88
90
  const omissionsKnown = !captureTruncated &&
@@ -92,24 +94,23 @@ const graphCoverageFacts = (input, omittedNodeObservations) => {
92
94
  projectionOmissions,
93
95
  knownOmissions: projectionOmissions + sourceOmissions,
94
96
  omissionsKnown,
95
- inputTruncated,
97
+ inputStatus: inputTruncated
98
+ ? "truncated"
99
+ : inputComplete
100
+ ? "complete"
101
+ : "partial",
96
102
  outputTruncated,
97
- truncated: inputTruncated || outputTruncated,
98
- complete: !inputTruncated &&
99
- !outputTruncated &&
100
- input.layers.every(({ graph }) => graph.coverage.status === "complete") &&
101
- input.captures.every(({ inspection }) => inspection.completeness.status === "complete_within_window"),
102
103
  };
103
104
  };
104
- const graphCoverage = (input, facts, nodeCount) => facts.complete
105
+ const graphCoverage = (input, facts, nodeCount) => facts.inputStatus === "complete" && !facts.outputTruncated
105
106
  ? { status: "complete", truncated: false, omitted_count: 0, limits: [] }
106
- : facts.truncated
107
+ : facts.inputStatus === "truncated" || facts.outputTruncated
107
108
  ? {
108
109
  status: "partial",
109
110
  truncated: true,
110
111
  omitted_count: facts.omissionsKnown ? facts.knownOmissions : null,
111
112
  limits: [
112
- ...(facts.inputTruncated
113
+ ...(facts.inputStatus === "truncated"
113
114
  ? [
114
115
  {
115
116
  name: "runtime-reconciliation-input-coverage",