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,277 @@
1
+ import { isAbsolute } from "node:path";
2
+ import { z } from "zod";
3
+ const absolutePathSchema = z
4
+ .string()
5
+ .min(1)
6
+ .max(16_384)
7
+ .refine(isAbsolute, "path must be absolute");
8
+ const windowIndexSchema = z.number().int().min(0).max(99);
9
+ const deepLinkUrlSchema = z
10
+ .string()
11
+ .min(1)
12
+ .max(4_096)
13
+ .refine((value) => {
14
+ try {
15
+ return new URL(value).protocol.length > 0;
16
+ }
17
+ catch {
18
+ return false;
19
+ }
20
+ }, "deep-link url must be an absolute URL");
21
+ const actionSchema = z.discriminatedUnion("kind", [
22
+ z.strictObject({
23
+ step_id: z.string().min(1).max(128),
24
+ kind: z.literal("click"),
25
+ selector: z.string().min(1).max(512),
26
+ window_index: windowIndexSchema.default(0),
27
+ }),
28
+ z.strictObject({
29
+ step_id: z.string().min(1).max(128),
30
+ kind: z.literal("wait"),
31
+ duration_ms: z.number().int().min(0).max(10_000),
32
+ window_index: windowIndexSchema.optional(),
33
+ }),
34
+ z.strictObject({
35
+ step_id: z.string().min(1).max(128),
36
+ kind: z.literal("renderer-reload"),
37
+ window_index: windowIndexSchema.default(0),
38
+ }),
39
+ z.strictObject({
40
+ step_id: z.string().min(1).max(128),
41
+ kind: z.literal("renderer-crash"),
42
+ window_index: windowIndexSchema.default(0),
43
+ }),
44
+ z.strictObject({
45
+ step_id: z.string().min(1).max(128),
46
+ kind: z.literal("deep-link"),
47
+ delivery: z.enum(["open-url", "second-instance"]),
48
+ url: deepLinkUrlSchema,
49
+ }),
50
+ ]);
51
+ const limitsSchema = z.strictObject({
52
+ max_duration_ms: z.number().int().min(1).max(120_000).default(60_000),
53
+ action_timeout_ms: z.number().int().min(1).max(30_000).default(5_000),
54
+ max_actions: z.number().int().min(1).max(100).default(20),
55
+ max_ipc_events: z.number().int().min(1).max(10_000).default(2_000),
56
+ max_runtime_events: z.number().int().min(1).max(20_000).default(5_000),
57
+ max_processes: z.number().int().min(1).max(100).default(32),
58
+ max_windows: z.number().int().min(1).max(100).default(32),
59
+ });
60
+ /** Input for one explicit, provider-owned Electron runtime experiment. */
61
+ export const electronActiveObservationInputSchema = z
62
+ .strictObject({
63
+ schema_version: z.literal(1),
64
+ executable_path: absolutePathSchema,
65
+ application_path: absolutePathSchema,
66
+ application_root: absolutePathSchema,
67
+ args: z.array(z.string().max(4_096)).max(32).default([]),
68
+ actions: z.array(actionSchema).max(100).default([]),
69
+ limits: limitsSchema.default({
70
+ max_duration_ms: 60_000,
71
+ action_timeout_ms: 5_000,
72
+ max_actions: 20,
73
+ max_ipc_events: 2_000,
74
+ max_runtime_events: 5_000,
75
+ max_processes: 32,
76
+ max_windows: 32,
77
+ }),
78
+ approved: z.literal(true),
79
+ })
80
+ .superRefine((input, context) => {
81
+ if (input.actions.length > input.limits.max_actions)
82
+ context.addIssue({
83
+ code: "custom",
84
+ path: ["actions"],
85
+ message: "actions exceed the configured max_actions limit",
86
+ });
87
+ });
88
+ const ipcEventSchema = z.strictObject({
89
+ sequence: z.number().int().min(1),
90
+ correlation_id: z.string().max(256).nullable().default(null),
91
+ kind: z.enum([
92
+ "main-handler-invocation",
93
+ "main-event-invocation",
94
+ "utility-process-fork",
95
+ "utility-process-message",
96
+ "ipc-main-to-renderer",
97
+ "ipc-utility-to-main",
98
+ "ipc-renderer-send",
99
+ "ipc-renderer-invoke",
100
+ "ipc-renderer-post-message",
101
+ ]),
102
+ event: z.string().max(128).nullable().optional(),
103
+ phase: z
104
+ .enum(["attempted", "completed", "blocked", "failed", "observed"])
105
+ .nullable()
106
+ .optional(),
107
+ channel: z.string().max(1_024).nullable(),
108
+ channel_truncated: z.boolean().default(false),
109
+ direction: z
110
+ .enum([
111
+ "renderer-to-main",
112
+ "main-to-renderer",
113
+ "main-to-utility",
114
+ "utility-to-main",
115
+ ])
116
+ .nullable()
117
+ .optional(),
118
+ sender: z.string().max(256).nullable().optional(),
119
+ receiver: z.string().max(256).nullable().optional(),
120
+ frame: z.string().max(256).nullable().default(null),
121
+ target: z.string().max(256).nullable().optional(),
122
+ argument_shapes: z.array(z.string().max(64)).max(32),
123
+ argument_shapes_truncated: z.boolean().default(false),
124
+ result_shape: z.string().max(64).nullable(),
125
+ process_type: z.string().max(128).nullable(),
126
+ source: z.string().max(64).default("electron-active-hook"),
127
+ capture_method: z
128
+ .enum(["api-wrapper", "event-emitter", "process-hook"])
129
+ .default("api-wrapper"),
130
+ artifact_path: z.string().max(16_384).nullable().default(null),
131
+ artifact_sha256: z
132
+ .string()
133
+ .regex(/^[a-f0-9]{64}$/u)
134
+ .nullable()
135
+ .default(null),
136
+ error: z.boolean(),
137
+ });
138
+ const timelineEventSchema = z.strictObject({
139
+ sequence: z.number().int().min(1),
140
+ correlation_id: z.string().max(256).nullable().default(null),
141
+ kind: z.enum([
142
+ "main-handler-invocation",
143
+ "main-event-invocation",
144
+ "utility-process-fork",
145
+ "utility-process-message",
146
+ "ipc-main-to-renderer",
147
+ "ipc-utility-to-main",
148
+ "ipc-renderer-send",
149
+ "ipc-renderer-invoke",
150
+ "ipc-renderer-post-message",
151
+ "app-lifecycle",
152
+ "window-lifecycle",
153
+ "web-contents-lifecycle",
154
+ "navigation",
155
+ "shell-attempt",
156
+ "process-lifecycle",
157
+ "permission",
158
+ "popup-attempt",
159
+ "download",
160
+ "protocol",
161
+ "preload",
162
+ "native-addon",
163
+ "updater",
164
+ "error",
165
+ ]),
166
+ event: z.string().max(128).nullable(),
167
+ phase: z.enum(["attempted", "completed", "blocked", "failed", "observed"]),
168
+ channel: z.string().max(1_024).nullable(),
169
+ channel_truncated: z.boolean(),
170
+ direction: z
171
+ .enum([
172
+ "renderer-to-main",
173
+ "main-to-renderer",
174
+ "main-to-utility",
175
+ "utility-to-main",
176
+ ])
177
+ .nullable(),
178
+ sender: z.string().max(256).nullable(),
179
+ receiver: z.string().max(256).nullable(),
180
+ frame: z.string().max(256).nullable(),
181
+ target: z.string().max(256).nullable(),
182
+ argument_shapes: z.array(z.string().max(64)).max(32),
183
+ argument_shapes_truncated: z.boolean(),
184
+ result_shape: z.string().max(64).nullable(),
185
+ process_type: z.string().max(128).nullable(),
186
+ source: z.string().max(64),
187
+ capture_method: z.enum(["api-wrapper", "event-emitter", "process-hook"]),
188
+ artifact_path: z.string().max(16_384).nullable(),
189
+ artifact_sha256: z
190
+ .string()
191
+ .regex(/^[a-f0-9]{64}$/u)
192
+ .nullable(),
193
+ error: z.boolean(),
194
+ });
195
+ const processMetricSchema = z.strictObject({
196
+ pid: z.number().int().min(1),
197
+ type: z.string().min(1).max(128),
198
+ name: z.string().max(256).nullable(),
199
+ service_name: z.string().max(256).nullable(),
200
+ });
201
+ const windowResultSchema = z.strictObject({
202
+ window_id: z.string().max(256),
203
+ web_contents_id: z.string().max(256),
204
+ url: z.string().max(65_536),
205
+ title: z.string().max(16_384),
206
+ visible: z.boolean().nullable(),
207
+ destroyed: z.boolean(),
208
+ });
209
+ const coverageSchema = z.strictObject({
210
+ status: z.enum([
211
+ "complete",
212
+ "partial_attach",
213
+ "capture_truncated",
214
+ "hook_conflict",
215
+ "target_exited",
216
+ "cleanup_failed",
217
+ ]),
218
+ observed_event_families: z.array(z.string().max(128)).max(32),
219
+ unavailable_event_families: z.array(z.string().max(128)).max(32),
220
+ observed_roles: z.array(z.string().max(128)).max(16),
221
+ pre_capture_activity: z.literal("unavailable"),
222
+ });
223
+ const actionResultSchema = z.strictObject({
224
+ step_id: z.string().min(1).max(128),
225
+ kind: z.enum([
226
+ "click",
227
+ "wait",
228
+ "renderer-reload",
229
+ "renderer-crash",
230
+ "deep-link",
231
+ ]),
232
+ window_index: windowIndexSchema.nullable(),
233
+ target: z.string().max(256).nullable(),
234
+ status: z.enum(["completed", "failed", "cancelled"]),
235
+ elapsed_ms: z.number().int().min(0),
236
+ error: z.string().nullable(),
237
+ });
238
+ /** Bounded result of a provider-owned Electron runtime experiment. */
239
+ export const electronActiveObservationResultSchema = z.strictObject({
240
+ schema_version: z.literal(1),
241
+ application: z.strictObject({
242
+ executable_path: absolutePathSchema,
243
+ application_path: absolutePathSchema,
244
+ electron_version: z.string().min(1).max(256),
245
+ process_ownership: z.literal("provider-owned"),
246
+ cleanup: z.literal("terminated-owned-process"),
247
+ }),
248
+ actions: z.array(actionResultSchema).max(100),
249
+ windows: z.array(windowResultSchema).max(100),
250
+ windows_truncated: z.boolean(),
251
+ processes: z.strictObject({
252
+ items: z.array(processMetricSchema).max(100),
253
+ truncated: z.boolean(),
254
+ }),
255
+ ipc: z.strictObject({
256
+ events: z.array(ipcEventSchema).max(10_000),
257
+ observed: z.number().int().min(0),
258
+ retained: z.number().int().min(0),
259
+ truncated: z.boolean(),
260
+ }),
261
+ timeline: z
262
+ .strictObject({
263
+ events: z.array(timelineEventSchema).max(20_000),
264
+ observed: z.number().int().min(0),
265
+ retained: z.number().int().min(0),
266
+ truncated: z.boolean(),
267
+ })
268
+ .default({ events: [], observed: 0, retained: 0, truncated: false }),
269
+ coverage: coverageSchema.default({
270
+ status: "partial_attach",
271
+ observed_event_families: [],
272
+ unavailable_event_families: [],
273
+ observed_roles: [],
274
+ pre_capture_activity: "unavailable",
275
+ }),
276
+ limitations: z.array(z.string().max(4_096)).max(100),
277
+ });
@@ -25,13 +25,10 @@ export const listElectronTargetsInputSchema = z.object({
25
25
  limit: z.number().int().min(1).max(200).default(100),
26
26
  });
27
27
  /** Input for passive structural inspection of one Electron file page. */
28
- export const inspectElectronPageInputSchema = z
29
- .object({
28
+ const inspectElectronPageFacts = {
30
29
  ...approvedElectronInput,
31
30
  target_id: z.string().trim().min(1).max(256),
32
31
  observation_ms: z.number().int().min(0).max(10_000).default(100),
33
- include_script_sources: z.boolean().default(false),
34
- source_capture_approved: z.boolean().default(false),
35
32
  limits: z
36
33
  .object({
37
34
  max_frames: z.number().int().min(1).max(1_000).default(200),
@@ -61,14 +58,21 @@ export const inspectElectronPageInputSchema = z
61
58
  max_script_source_bytes: 1_024 * 1_024,
62
59
  max_total_script_source_bytes: 4 * 1_024 * 1_024,
63
60
  }),
64
- })
61
+ };
62
+ export const inspectElectronPageInputSchema = z
63
+ .union([
64
+ z.object({
65
+ ...inspectElectronPageFacts,
66
+ include_script_sources: z.literal(false).default(false),
67
+ source_capture_approved: z.literal(false).default(false),
68
+ }),
69
+ z.object({
70
+ ...inspectElectronPageFacts,
71
+ include_script_sources: z.literal(true),
72
+ source_capture_approved: z.literal(true),
73
+ }),
74
+ ])
65
75
  .superRefine((input, context) => {
66
- if (input.include_script_sources && !input.source_capture_approved)
67
- context.addIssue({
68
- code: "custom",
69
- path: ["source_capture_approved"],
70
- message: "Electron script source capture requires separate approval",
71
- });
72
76
  if (input.limits.max_script_source_bytes >
73
77
  input.limits.max_total_script_source_bytes)
74
78
  context.addIssue({
@@ -51,7 +51,10 @@ export const collectContextBridgeMembers = (node, maximum = 128) => {
51
51
  unknown: 1,
52
52
  omitted: 0,
53
53
  };
54
- const state = { members: [], unknown: 0 };
54
+ const state = {
55
+ members: [],
56
+ unknown: 0,
57
+ };
55
58
  collectMembersAt(node, "", 0, state);
56
59
  const members = [...new Set(state.members)].sort(compareCodePoints);
57
60
  return {
@@ -0,0 +1,217 @@
1
+ import { z } from "zod";
2
+ /** Event types for event-backed process-tree capture. */
3
+ export const processEventTypeSchema = z.enum([
4
+ "spawn",
5
+ "exit",
6
+ "re_exec",
7
+ "reparent",
8
+ "signal",
9
+ "name_change",
10
+ "thread_create",
11
+ "thread_exit",
12
+ ]);
13
+ /** A single event-backed process-tree event. */
14
+ export const processTreeEventSchema = z.strictObject({
15
+ /** Monotonic event sequence number. */
16
+ sequence: z.number().int().nonnegative(),
17
+ /** Event timestamp in milliseconds. */
18
+ at_ms: z.number().int().nonnegative(),
19
+ /** Event type. */
20
+ type: processEventTypeSchema,
21
+ /** Process ID. */
22
+ pid: z.number().int().positive(),
23
+ /** Parent process ID. */
24
+ ppid: z.number().int().nullable(),
25
+ /** Process name if known. */
26
+ process_name: z.string().nullable(),
27
+ /** Executable path if known. */
28
+ executable: z.string().nullable(),
29
+ /** Command line arguments. */
30
+ arguments: z.array(z.string()).default([]),
31
+ /** Previous PID (for reparent events). */
32
+ previous_pid: z.number().int().nullable(),
33
+ /** Previous PPID (for reparent events). */
34
+ previous_ppid: z.number().int().nullable(),
35
+ /** Exit code (for exit events). */
36
+ exit_code: z.number().int().nullable(),
37
+ /** Signal number (for signal events). */
38
+ signal: z.number().int().nullable(),
39
+ /** Thread ID (for thread events). */
40
+ tid: z.number().int().nullable(),
41
+ });
42
+ /** Process node in a reconstructed tree. */
43
+ export const processNodeSchema = z.strictObject({
44
+ pid: z.number().int().positive(),
45
+ ppid: z.number().int().nullable(),
46
+ process_name: z.string().nullable(),
47
+ executable: z.string().nullable(),
48
+ arguments: z.array(z.string()).default([]),
49
+ children: z.array(z.number().int()).default([]),
50
+ spawn_time_ms: z.number().int().nullable(),
51
+ exit_time_ms: z.number().int().nullable(),
52
+ exit_code: z.number().int().nullable(),
53
+ is_re_exec: z.boolean().default(false),
54
+ is_reparented: z.boolean().default(false),
55
+ previous_ppid: z.number().int().nullable(),
56
+ });
57
+ /** Result of event-backed process-tree reconstruction. */
58
+ export const processTreeReconstructionSchema = z.strictObject({
59
+ /** Root PID of the process tree. */
60
+ root_pid: z.number().int().positive(),
61
+ /** All reconstructed process nodes. */
62
+ processes: z.array(processNodeSchema).min(0).max(10_000),
63
+ /** Events that were consumed. */
64
+ events_consumed: z.number().int().nonnegative(),
65
+ /** Events that could not be matched. */
66
+ events_unmatched: z.number().int().nonnegative(),
67
+ /** Short-lived descendants that were missed by sampling. */
68
+ short_lived_descendants: z.number().int().nonnegative(),
69
+ /** Whether any re-exec was detected. */
70
+ has_re_exec: z.boolean().default(false),
71
+ /** Whether any reparenting was detected. */
72
+ has_reparenting: z.boolean().default(false),
73
+ });
74
+ const applyProcessTreeEvent = (event, state) => {
75
+ let node = state.nodes.get(event.pid);
76
+ switch (event.type) {
77
+ case "spawn": {
78
+ if (!node) {
79
+ node = {
80
+ pid: event.pid,
81
+ ppid: event.ppid,
82
+ process_name: event.process_name,
83
+ executable: event.executable,
84
+ arguments: event.arguments,
85
+ children: [],
86
+ spawn_time_ms: event.at_ms,
87
+ exit_time_ms: null,
88
+ exit_code: null,
89
+ is_re_exec: false,
90
+ is_reparented: false,
91
+ previous_ppid: null,
92
+ };
93
+ state.nodes.set(event.pid, node);
94
+ }
95
+ if (event.ppid !== null) {
96
+ const parentChildren = state.children.get(event.ppid) ?? [];
97
+ parentChildren.push(event.pid);
98
+ state.children.set(event.ppid, parentChildren);
99
+ }
100
+ break;
101
+ }
102
+ case "exit":
103
+ if (node) {
104
+ node.exit_time_ms = event.at_ms;
105
+ node.exit_code = event.exit_code;
106
+ if (node.spawn_time_ms !== null &&
107
+ event.at_ms - node.spawn_time_ms < 100)
108
+ state.shortLivedDescendants++;
109
+ }
110
+ else
111
+ state.eventsUnmatched++;
112
+ break;
113
+ case "re_exec":
114
+ if (node) {
115
+ node.is_re_exec = true;
116
+ node.executable = event.executable ?? node.executable;
117
+ node.arguments = event.arguments;
118
+ state.hasReExec = true;
119
+ }
120
+ else
121
+ state.eventsUnmatched++;
122
+ break;
123
+ case "reparent":
124
+ if (node) {
125
+ node.previous_ppid = node.ppid;
126
+ node.ppid = event.ppid;
127
+ node.is_reparented = true;
128
+ state.hasReparenting = true;
129
+ }
130
+ else
131
+ state.eventsUnmatched++;
132
+ break;
133
+ case "signal":
134
+ case "name_change":
135
+ case "thread_create":
136
+ case "thread_exit":
137
+ // These events are recorded but don't modify the tree structure.
138
+ break;
139
+ }
140
+ };
141
+ /** Reconstruct a process tree from event-backed capture. */
142
+ export function reconstructProcessTree(events, rootPid) {
143
+ const nodes = new Map();
144
+ const children = new Map();
145
+ let eventsConsumed = 0;
146
+ const state = {
147
+ nodes,
148
+ children,
149
+ eventsUnmatched: 0,
150
+ hasReExec: false,
151
+ hasReparenting: false,
152
+ shortLivedDescendants: 0,
153
+ };
154
+ const sorted = [...events].sort((a, b) => a.at_ms - b.at_ms);
155
+ for (const event of sorted) {
156
+ eventsConsumed++;
157
+ applyProcessTreeEvent(event, state);
158
+ }
159
+ // Attach children to nodes
160
+ for (const [pid, childPids] of children) {
161
+ const node = nodes.get(pid);
162
+ if (node)
163
+ node.children = childPids;
164
+ }
165
+ return {
166
+ root_pid: rootPid,
167
+ processes: [...nodes.values()],
168
+ events_consumed: eventsConsumed,
169
+ events_unmatched: state.eventsUnmatched,
170
+ short_lived_descendants: state.shortLivedDescendants,
171
+ has_re_exec: state.hasReExec,
172
+ has_reparenting: state.hasReparenting,
173
+ };
174
+ }
175
+ /** Get all descendant PIDs of a given root PID. */
176
+ export function getDescendants(processes, rootPid) {
177
+ const byPid = new Map(processes.map((p) => [p.pid, p]));
178
+ const visited = new Set();
179
+ const result = [];
180
+ const queue = [rootPid];
181
+ while (queue.length > 0) {
182
+ const pid = queue.shift();
183
+ if (pid === undefined)
184
+ break;
185
+ if (visited.has(pid))
186
+ continue;
187
+ visited.add(pid);
188
+ const node = byPid.get(pid);
189
+ if (node) {
190
+ for (const child of node.children) {
191
+ if (!visited.has(child)) {
192
+ result.push(child);
193
+ queue.push(child);
194
+ }
195
+ }
196
+ }
197
+ }
198
+ return result;
199
+ }
200
+ /** Check if a process tree contains a specific PID. */
201
+ export function containsProcess(processes, pid) {
202
+ return processes.some((p) => p.pid === pid);
203
+ }
204
+ /** Get the maximum tree depth from the root. */
205
+ export function maxTreeDepth(processes, rootPid) {
206
+ const byPid = new Map(processes.map((p) => [p.pid, p]));
207
+ function depth(pid, visited) {
208
+ if (visited.has(pid))
209
+ return 0;
210
+ visited.add(pid);
211
+ const node = byPid.get(pid);
212
+ if (!node || node.children.length === 0)
213
+ return 0;
214
+ return 1 + Math.max(...node.children.map((c) => depth(c, visited)));
215
+ }
216
+ return depth(rootPid, new Set());
217
+ }
@@ -163,6 +163,53 @@ const validateVerifiedResolution = (unknown, evidenceById) => {
163
163
  if (qualifies !== true)
164
164
  throw new TypeError(`Residual unknown ${unknown.unknown_id} has no qualifying resolution evidence`);
165
165
  };
166
+ /**
167
+ * Validate one new residual-unknown revision against an already valid ledger.
168
+ * This keeps ordinary mutations proportional to the affected revision while
169
+ * full bundle imports continue to validate the complete graph.
170
+ */
171
+ export const validateResidualUnknownAddition = (unknown, evidenceById, currentHeads) => {
172
+ const current = currentHeads.get(unknown.unknown_id);
173
+ if (current === undefined
174
+ ? unknown.revision !== 1 || unknown.previous_revision_digest !== null
175
+ : unknown.revision !== current.revision + 1 ||
176
+ unknown.previous_revision_digest !== current.revision_digest)
177
+ throw new TypeError(`Residual unknown ${unknown.unknown_id} revision chain is broken`);
178
+ for (const evidenceId of referencedEvidenceIds(unknown))
179
+ if (!evidenceById.has(evidenceId))
180
+ throw new TypeError(`Residual unknown references missing evidence ${evidenceId}`);
181
+ for (const relationship of unknown.relationships)
182
+ if (relationship.unknown_id !== unknown.unknown_id &&
183
+ !currentHeads.has(relationship.unknown_id))
184
+ throw new TypeError(`Residual unknown references missing unknown ${relationship.unknown_id}`);
185
+ if (unknown.resolution?.disposition === "verified")
186
+ validateVerifiedResolution(unknown, evidenceById);
187
+ for (const relationship of unknown.relationships)
188
+ if (relationship.type === "depends-on" &&
189
+ reachesUnknown(relationship.unknown_id, unknown.unknown_id, currentHeads, unknown))
190
+ throw new TypeError("Residual unknown dependency graph contains a cycle");
191
+ };
192
+ const reachesUnknown = (start, goal, currentHeads, candidate) => {
193
+ const pending = [start];
194
+ const visited = new Set();
195
+ while (pending.length > 0) {
196
+ const id = pending.pop();
197
+ if (id === undefined)
198
+ break;
199
+ if (id === goal)
200
+ return true;
201
+ if (visited.has(id))
202
+ continue;
203
+ visited.add(id);
204
+ const unknown = id === candidate.unknown_id ? candidate : currentHeads.get(id);
205
+ if (unknown === undefined)
206
+ continue;
207
+ for (const relationship of unknown.relationships)
208
+ if (relationship.type === "depends-on")
209
+ pending.push(relationship.unknown_id);
210
+ }
211
+ return false;
212
+ };
166
213
  const evidenceQualifies = (unknown, evidence) => {
167
214
  if (unknown.required_authority !== null &&
168
215
  evidence.authority !== unknown.required_authority)
@@ -123,14 +123,21 @@ export const stringAndNameProjection = (snapshot) => {
123
123
  : sorted(values);
124
124
  };
125
125
  export const sorted = (values) => [...values].sort((left, right) => canonicalJson(left).localeCompare(canonicalJson(right)));
126
- export const combineCoverage = (left, right) => ({
127
- items: [...left.items, ...right.items],
128
- total: left.total === null || right.total === null
129
- ? null
130
- : left.total + right.total,
131
- complete: left.complete && right.complete,
132
- truncated: left.truncated || right.truncated,
133
- });
126
+ export const combineCoverage = (left, right) => {
127
+ const base = {
128
+ items: [...left.items, ...right.items],
129
+ total: left.total === null || right.total === null
130
+ ? null
131
+ : left.total + right.total,
132
+ };
133
+ return left.complete && right.complete
134
+ ? { ...base, complete: true, truncated: false }
135
+ : {
136
+ ...base,
137
+ complete: false,
138
+ truncated: left.truncated || right.truncated,
139
+ };
140
+ };
134
141
  export const project = (collection, mapper) => collection.items.map(mapper);
135
142
  export const isAutoName = (name) => /^(?:sub_[0-9a-f]+|fcn\.)/iu.test(name);
136
143
  const parseAddress = (value) => /^0x[0-9a-f]+$/iu.test(value) ? BigInt(value) : null;
@@ -109,8 +109,9 @@ const mergePseudocode = (pages) => {
109
109
  return {
110
110
  text: orderedValues(characters).join(""),
111
111
  total,
112
- complete,
113
- truncated: !complete,
112
+ ...(complete
113
+ ? { complete: true, truncated: false }
114
+ : { complete: false, truncated: true }),
114
115
  };
115
116
  };
116
117
  const mergeCollection = (pages, field) => {
@@ -140,8 +141,12 @@ const mergeCollection = (pages, field) => {
140
141
  return {
141
142
  items: orderedValues(items),
142
143
  total,
143
- complete,
144
- truncated: scanLimited || (!unavailable && !complete),
144
+ ...(complete
145
+ ? { complete: true, truncated: false }
146
+ : {
147
+ complete: false,
148
+ truncated: scanLimited || !unavailable,
149
+ }),
145
150
  };
146
151
  };
147
152
  const collectionOffset = (page, field) => field === "assembly"
@@ -27,7 +27,7 @@ const failures = [
27
27
  [
28
28
  75,
29
29
  "hopper_exited_during_startup",
30
- "Hopper exited before the REA bridge was ready. Run rea doctor and retry the analysis.",
30
+ "Hopper exited before the REA bridge was ready. In CI, run rea doctor --provider hopper --detail full --json; if Hopper showed a UI or license prompt, complete it in the runner user session, otherwise close stale Hopper sessions and retry.",
31
31
  ],
32
32
  [
33
33
  76,