rea-agents 2.0.0 → 2.2.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 (273) hide show
  1. package/README.md +103 -38
  2. package/bridge/ghidra/ReaGhidraBridge.java +96 -11
  3. package/dist/application/AndroidApplicationService.js +17 -0
  4. package/dist/application/AppleApplicationService.js +17 -0
  5. package/dist/application/ArtifactExtraction.js +1 -1
  6. package/dist/application/ArtifactInventory/classify.js +42 -0
  7. package/dist/application/ArtifactInventory/hash.js +43 -0
  8. package/dist/application/ArtifactInventory/reader.js +41 -0
  9. package/dist/application/ArtifactInventory/scanCanonical.js +155 -0
  10. package/dist/application/ArtifactInventory/scanReader.js +124 -0
  11. package/dist/application/ArtifactInventory/types.js +10 -0
  12. package/dist/application/ArtifactInventory.js +9 -351
  13. package/dist/application/AuthorizedArtifactInventory.js +2 -2
  14. package/dist/application/BinarySession.js +47 -270
  15. package/dist/application/BinarySessionExecution.js +28 -0
  16. package/dist/application/BinarySessionOpen.js +39 -0
  17. package/dist/application/BinarySessionRecords.js +149 -0
  18. package/dist/application/BinarySessionStatus.js +75 -0
  19. package/dist/application/CapabilityInventory.js +24 -2
  20. package/dist/application/ClientRegistrationStatus.js +11 -4
  21. package/dist/application/CrossVersionInventory.js +8 -2
  22. package/dist/application/CrossVersionInvestigation.js +1 -23
  23. package/dist/application/CrossVersionInvestigationCollections.js +23 -0
  24. package/dist/application/DirectAnalysis.js +47 -44
  25. package/dist/application/Doctor.js +156 -238
  26. package/dist/application/DoctorDiagnostics.js +180 -0
  27. package/dist/application/ElectronBoundaryAnalysis.js +23 -7
  28. package/dist/application/ElectronBoundaryGraphWindows.js +32 -8
  29. package/dist/application/EnhancedToolPagination.js +22 -0
  30. package/dist/application/EnhancedToolTypes.js +4 -0
  31. package/dist/application/EnhancedTools.js +20 -37
  32. package/dist/application/InstrumentedJavaScriptReplayHost.js +36 -0
  33. package/dist/application/InventoryProjectionEvidence.js +41 -0
  34. package/dist/application/InvestigationProviders.js +12 -0
  35. package/dist/application/InvestigationWorkspaceStore.js +24 -10
  36. package/dist/application/JavaScriptArtifactAnalysis.js +45 -6
  37. package/dist/application/JavaScriptArtifactFiles.js +6 -2
  38. package/dist/application/JavaScriptArtifactGraphBuilder.js +23 -1
  39. package/dist/application/JavaScriptArtifactGraphBundlers.js +225 -0
  40. package/dist/application/JavaScriptArtifactGraphContext.js +37 -36
  41. package/dist/application/JavaScriptArtifactGraphDocuments.js +27 -4
  42. package/dist/application/JavaScriptArtifactGraphFindings.js +54 -8
  43. package/dist/application/JavaScriptArtifactGraphStructure.js +29 -101
  44. package/dist/application/JavaScriptArtifactPathResolution.js +269 -0
  45. package/dist/application/JavaScriptArtifactReconstruction.js +1 -1
  46. package/dist/application/JavaScriptJsonModules.js +39 -0
  47. package/dist/application/JavaScriptModuleRelationships.js +262 -0
  48. package/dist/application/JavaScriptReplayPermission.js +16 -0
  49. package/dist/application/JavaScriptReplayService.js +182 -156
  50. package/dist/application/LinuxHopper.js +10 -0
  51. package/dist/application/MacHopper.js +22 -11
  52. package/dist/application/NodeRuntimeCharacterizationService.js +196 -0
  53. package/dist/application/PermissionAuthority.js +106 -63
  54. package/dist/application/ProcessCaptureCapability.js +1 -1
  55. package/dist/application/ProcessCapturePermission.js +13 -0
  56. package/dist/application/ProcessCli.js +2 -12
  57. package/dist/application/ProcessHarness.js +1 -1
  58. package/dist/application/ProcessPairedExperiment.js +72 -0
  59. package/dist/application/ProjectPermissionStore.js +48 -9
  60. package/dist/application/RealHopperAssertions.js +76 -0
  61. package/dist/application/ReconstructionCoverageService.js +69 -0
  62. package/dist/application/ReconstructionCoverageWorkspaceStore.js +31 -0
  63. package/dist/application/RuntimeExecutableDiagnostics.js +172 -0
  64. package/dist/application/Setup.js +148 -260
  65. package/dist/application/SetupClientConfiguration.js +224 -0
  66. package/dist/application/SetupClients.js +24 -2
  67. package/dist/application/SetupPlan.js +124 -12
  68. package/dist/application/SetupSkill.js +54 -36
  69. package/dist/application/SupportedClients.js +1 -0
  70. package/dist/application/Uninstall.js +12 -3
  71. package/dist/application/Upgrade.js +16 -1
  72. package/dist/application/WindowsCapabilities.js +86 -0
  73. package/dist/artifacts/AsarArtifactReader.js +11 -0
  74. package/dist/browser/BrowserProcessStartup.js +88 -0
  75. package/dist/browser/CdpCaptureDocuments.js +12 -8
  76. package/dist/browser/CdpCaptureEventBodyShapes.js +75 -0
  77. package/dist/browser/CdpCaptureEventHandlers.js +336 -0
  78. package/dist/browser/CdpCaptureEventHelpers.js +71 -0
  79. package/dist/browser/CdpCaptureEventState.js +1 -0
  80. package/dist/browser/CdpCaptureEventTypes.js +1 -0
  81. package/dist/browser/CdpCaptureEvents.js +29 -496
  82. package/dist/browser/CdpObservationSession.js +51 -8
  83. package/dist/browser/CdpPageCapture.js +12 -133
  84. package/dist/browser/CdpPageCaptureScripts.js +97 -0
  85. package/dist/browser/CdpPageCaptureWorkers.js +46 -0
  86. package/dist/browser/CdpWebMcpDiscovery.js +38 -14
  87. package/dist/browser/PngVisualDiff.js +9 -2
  88. package/dist/catalogIdentity.js +4 -0
  89. package/dist/cli/artifactCommands.js +82 -0
  90. package/dist/cli/coreAnalysisCommands.js +232 -0
  91. package/dist/cli/managedCommands.js +397 -0
  92. package/dist/cli/managedProjectGraphCommand.js +24 -0
  93. package/dist/cli/options.js +9 -0
  94. package/dist/cli/setupCommands.js +113 -0
  95. package/dist/cli/types.js +1 -0
  96. package/dist/cli/utilityCommands.js +122 -0
  97. package/dist/cli.js +10 -768
  98. package/dist/cliApplicationCommands.js +118 -4
  99. package/dist/cliBrowserAdvancedCommands.js +73 -16
  100. package/dist/cliBrowserCommands.js +39 -115
  101. package/dist/cliCommandNames.js +4 -0
  102. package/dist/cliElectronCommands.js +33 -62
  103. package/dist/cliEvidenceCommands.js +13 -2
  104. package/dist/cliInvestigationCommands.js +53 -10
  105. package/dist/cliObservationOptions.js +137 -0
  106. package/dist/cliPolicyCommands.js +80 -46
  107. package/dist/cliSetup.js +306 -0
  108. package/dist/config/environment.js +107 -0
  109. package/dist/config/parseConfig.js +228 -0
  110. package/dist/config/parsers.js +68 -0
  111. package/dist/config/permissions.js +30 -0
  112. package/dist/config/types.js +1 -0
  113. package/dist/config.js +1 -375
  114. package/dist/contracts/applicationToolContracts.js +134 -0
  115. package/dist/contracts/electronToolContracts.js +51 -3
  116. package/dist/contracts/managedToolContracts.js +8 -3
  117. package/dist/contracts/managedWorkflowToolContracts.js +3 -3
  118. package/dist/contracts/providerSelection.js +2 -0
  119. package/dist/contracts/sessionStatusContract.js +26 -0
  120. package/dist/contracts/toolContractTypes.js +12 -1
  121. package/dist/contracts/toolContracts.js +5 -12
  122. package/dist/contracts/toolEffects.js +14 -0
  123. package/dist/contracts/toolOutputSchemaGroups.js +274 -0
  124. package/dist/contracts/toolOutputSchemaPrimitives.js +328 -0
  125. package/dist/contracts/toolOutputSchemas.js +2 -550
  126. package/dist/domain/analysisErrorPresentation.js +234 -0
  127. package/dist/domain/analysisErrorProjection.js +284 -0
  128. package/dist/domain/androidApplication.js +206 -0
  129. package/dist/domain/appleApplication.js +221 -0
  130. package/dist/domain/artifactComparison.js +34 -15
  131. package/dist/domain/binaryTarget.js +87 -37
  132. package/dist/domain/boundedCartesianProjection.js +15 -0
  133. package/dist/domain/browserObservation.js +1 -285
  134. package/dist/domain/browserObservationSchemas.js +286 -0
  135. package/dist/domain/electronStaticAnalysisBrowser.js +14 -2
  136. package/dist/domain/errors.js +4 -486
  137. package/dist/domain/functionComparison.js +4 -165
  138. package/dist/domain/functionComparisonDimensions.js +164 -0
  139. package/dist/domain/javascriptApplicationVersionItems.js +18 -6
  140. package/dist/domain/javascriptApplicationVersionKeys.js +8 -8
  141. package/dist/domain/javascriptExportInstrumentation.js +97 -0
  142. package/dist/domain/javascriptFeatureTraversal.js +19 -7
  143. package/dist/domain/javascriptRuntimeStaticCandidates.js +3 -1
  144. package/dist/domain/javascriptSemanticAnalysis.js +386 -0
  145. package/dist/domain/javascriptSemanticIr.js +30 -0
  146. package/dist/domain/javascriptSemanticProjection.js +366 -0
  147. package/dist/domain/javascriptSemanticState.js +40 -0
  148. package/dist/domain/javascriptSemanticTraversal.js +22 -0
  149. package/dist/domain/javascriptSemanticValues.js +352 -0
  150. package/dist/domain/javascriptStaticAnalysis.js +5 -221
  151. package/dist/domain/javascriptStaticAnalysisBundler.js +209 -0
  152. package/dist/domain/javascriptStaticAnalysisCalls.js +180 -0
  153. package/dist/domain/javascriptStaticAnalysisHelpers.js +71 -2
  154. package/dist/domain/knownPageCoverage.js +21 -0
  155. package/dist/domain/managedApplicationGraph.js +14 -364
  156. package/dist/domain/managedApplicationGraphCoverage.js +170 -0
  157. package/dist/domain/managedApplicationGraphNodeCoverage.js +6 -0
  158. package/dist/domain/managedApplicationGraphNodes.js +336 -0
  159. package/dist/domain/managedArtifact.js +16 -8
  160. package/dist/domain/managedMemberComparison.js +37 -391
  161. package/dist/domain/managedMemberComparisonCoverage.js +72 -0
  162. package/dist/domain/managedMemberComparisonMatch.js +356 -0
  163. package/dist/domain/managedNativeVerification.js +27 -389
  164. package/dist/domain/managedNativeVerificationMatch.js +272 -0
  165. package/dist/domain/managedNativeVerificationSchemas.js +141 -0
  166. package/dist/domain/managedReconstruction.js +82 -69
  167. package/dist/domain/managedRuntimeCorrelation.js +12 -3
  168. package/dist/domain/nodeRuntimeCharacterization.js +66 -0
  169. package/dist/domain/permissionPolicy.js +2 -0
  170. package/dist/domain/processComparison.js +19 -0
  171. package/dist/domain/processPairedExperiment.js +128 -0
  172. package/dist/domain/reconstructionCoverage.js +387 -0
  173. package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
  174. package/dist/domain/reconstructionVerificationSchemas.js +8 -0
  175. package/dist/domain/replayMachine.js +316 -0
  176. package/dist/domain/replayMachineRuntime.js +215 -0
  177. package/dist/domain/runtimeCharacterization.js +85 -0
  178. package/dist/domain/runtimeIdentification.js +210 -0
  179. package/dist/domain/webBundleAnalyzer.js +3 -409
  180. package/dist/domain/webBundleAnalyzerAst.js +77 -0
  181. package/dist/domain/webBundleAnalyzerInspection.js +307 -0
  182. package/dist/domain/webBundleAnalyzerResult.js +120 -0
  183. package/dist/dotnet/ManagedArtifactInspector.js +50 -29
  184. package/dist/dotnet/ManagedMemberInspector.js +51 -785
  185. package/dist/dotnet/ManagedMemberInspectorCore.js +297 -0
  186. package/dist/dotnet/ManagedMemberInstructionDecoder.js +427 -0
  187. package/dist/dotnet/ManagedMemberRows.js +120 -0
  188. package/dist/dotnet/ManagedMetadataInventory.js +42 -306
  189. package/dist/dotnet/ManagedMetadataInventoryRows.js +292 -0
  190. package/dist/dotnet/ManagedMetadataLayout.js +48 -111
  191. package/dist/dotnet/ManagedMetadataRowSizes.js +54 -0
  192. package/dist/dotnet/ManagedMethodBodyReader.js +143 -0
  193. package/dist/dotnet/ManagedNativeBoundaryHelpers.js +311 -0
  194. package/dist/dotnet/ManagedNativeBoundaryInspector.js +102 -350
  195. package/dist/dotnet/ManagedPeReader.js +59 -28
  196. package/dist/evaluation/CodexAgentEval.js +132 -0
  197. package/dist/generatedPackageMetadata.js +2 -2
  198. package/dist/ghidra/GhidraClient.js +76 -91
  199. package/dist/ghidra/GhidraClientStartup.js +29 -0
  200. package/dist/ghidra/GhidraClientWire.js +34 -0
  201. package/dist/ghidra/GhidraDefaults.js +1 -1
  202. package/dist/ghidra/GhidraDiagnostics.js +6 -1
  203. package/dist/ghidra/GhidraInstallation.js +20 -15
  204. package/dist/ghidra/GhidraLauncher.js +93 -29
  205. package/dist/ghidra/GhidraProvider.js +61 -161
  206. package/dist/ghidra/GhidraProviderCapabilities.js +173 -0
  207. package/dist/ghidra/GhidraSessionValues.js +2 -0
  208. package/dist/ghidra/GhidraSocketConnection.js +44 -7
  209. package/dist/ghidra/GhidraTargetSnapshot.js +30 -0
  210. package/dist/ghidra/GhidraTransport.js +71 -0
  211. package/dist/identity.js +4 -2
  212. package/dist/main/messages.js +5 -0
  213. package/dist/main/reload.js +49 -0
  214. package/dist/main/shutdown.js +25 -0
  215. package/dist/main/startup.js +14 -0
  216. package/dist/main/state.js +26 -0
  217. package/dist/main/transport.js +61 -0
  218. package/dist/main/types.js +1 -0
  219. package/dist/main.js +35 -146
  220. package/dist/process/PrivateRuntimeRoot.js +3 -2
  221. package/dist/process/ProcessOwnership.js +35 -0
  222. package/dist/process/ProviderProcess.js +2 -0
  223. package/dist/replay/JavaScriptReplayWorker.js +64 -50
  224. package/dist/replay/LinuxJavaScriptReplayRunner.js +173 -390
  225. package/dist/replay/LinuxJavaScriptReplaySandbox.js +140 -0
  226. package/dist/replay/ReplayOutcome.js +95 -0
  227. package/dist/replay/ReplayProcessLifecycle.js +71 -0
  228. package/dist/server/ProcessCaptureElicitation.js +157 -0
  229. package/dist/server/createServer.js +124 -56
  230. package/dist/server/javascriptApplicationResult.js +85 -0
  231. package/dist/server/registerApplicationTools/characterization.js +57 -0
  232. package/dist/server/registerApplicationTools/compareVersions.js +34 -0
  233. package/dist/server/registerApplicationTools/controlledReplay.js +38 -0
  234. package/dist/server/registerApplicationTools/coverage.js +84 -0
  235. package/dist/server/registerApplicationTools/helpers.js +42 -0
  236. package/dist/server/registerApplicationTools/traceFeature.js +26 -0
  237. package/dist/server/registerApplicationTools/types.js +1 -0
  238. package/dist/server/registerApplicationTools.js +10 -112
  239. package/dist/server/registerBrowserTools.js +59 -83
  240. package/dist/server/registerElectronTools.js +48 -49
  241. package/dist/server/registerEnhancedTools.js +34 -42
  242. package/dist/server/registerEvidenceResources.js +56 -0
  243. package/dist/server/registerInvestigationTools/helpers.js +74 -0
  244. package/dist/server/registerInvestigationTools/types.js +1 -0
  245. package/dist/server/registerInvestigationTools.js +83 -116
  246. package/dist/server/registerJavaScriptApplicationGraphResource.js +69 -0
  247. package/dist/server/registerManagedTools.js +18 -1
  248. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +65 -0
  249. package/dist/server/registerManagedWorkflowTools/contract.js +8 -0
  250. package/dist/server/registerManagedWorkflowTools/evidence.js +43 -0
  251. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +39 -0
  252. package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +39 -0
  253. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +52 -0
  254. package/dist/server/registerManagedWorkflowTools/types.js +1 -0
  255. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +75 -0
  256. package/dist/server/registerManagedWorkflowTools.js +10 -274
  257. package/dist/server/registerOfficialTools.js +73 -59
  258. package/dist/server/registerSessionRecordTools.js +137 -0
  259. package/dist/server/registerSessionStatusTool.js +97 -26
  260. package/dist/server/registerSessionTools.js +60 -164
  261. package/dist/server/sessionAvailabilityPolicy.js +10 -0
  262. package/dist/server/toolRegistrationOptions.js +101 -3
  263. package/dist/server/toolResult.js +15 -4
  264. package/package.json +11 -11
  265. package/skills/reverse-engineer-anything/SKILL.md +76 -0
  266. package/skills/reverse-engineer-anything/references/controlled-replay.md +12 -0
  267. package/skills/reverse-engineer-anything/references/evidence-workflows.md +33 -0
  268. package/skills/reverse-engineer-anything/references/javascript-applications.md +25 -0
  269. package/skills/reverse-engineer-anything/references/native-and-artifacts.md +36 -0
  270. package/skills/reverse-engineer-anything/references/runtime-observation.md +24 -0
  271. package/scripts/prepare-node-pty.mjs +0 -35
  272. package/scripts/rebuild-native.mjs +0 -22
  273. package/skills/rea-analysis/SKILL.md +0 -222
@@ -0,0 +1,215 @@
1
+ import canonicalize from "canonicalize";
2
+ const parseJson = (value) => {
3
+ try {
4
+ return JSON.parse(value);
5
+ }
6
+ catch {
7
+ return undefined;
8
+ }
9
+ };
10
+ const atPath = (value, path) => {
11
+ let current = value;
12
+ for (const segment of path) {
13
+ if (typeof segment === "number") {
14
+ if (!Array.isArray(current))
15
+ return undefined;
16
+ current = current[segment];
17
+ continue;
18
+ }
19
+ if (typeof current !== "object" ||
20
+ current === null ||
21
+ !Object.hasOwn(current, segment))
22
+ return undefined;
23
+ current = current[segment];
24
+ }
25
+ return current;
26
+ };
27
+ const actionJsonBody = (transition) => {
28
+ for (const action of transition.actions)
29
+ if (action.type === "http_response")
30
+ return action.body;
31
+ else if (action.type === "websocket_send")
32
+ return action.data;
33
+ return undefined;
34
+ };
35
+ const readValue = (source, event, transition) => {
36
+ switch (source.source) {
37
+ case "request_header":
38
+ return event.headers[source.name.toLowerCase()];
39
+ case "request_json":
40
+ return atPath(parseJson(event.body), source.path);
41
+ case "websocket_json":
42
+ return atPath(parseJson(event.body), source.path);
43
+ case "action_json": {
44
+ const body = actionJsonBody(transition);
45
+ return body === undefined
46
+ ? undefined
47
+ : atPath(parseJson(body), source.path);
48
+ }
49
+ }
50
+ };
51
+ const triggerMatches = (transition, event) => {
52
+ const trigger = transition.trigger;
53
+ if (trigger.protocol !== event.protocol || trigger.path !== event.path)
54
+ return false;
55
+ if ("headers" in trigger &&
56
+ Object.entries(trigger.headers).some(([name, value]) => event.headers[name.toLowerCase()] !== value))
57
+ return false;
58
+ if (trigger.protocol === "http")
59
+ return (trigger.method === event.method &&
60
+ (trigger.body === null || trigger.body === event.body));
61
+ if (trigger.protocol === "websocket_message")
62
+ return trigger.body === null || trigger.body === event.body;
63
+ return true;
64
+ };
65
+ const isJsonCompatible = (value) => {
66
+ if (value === null || typeof value === "string" || typeof value === "boolean")
67
+ return true;
68
+ if (typeof value === "number")
69
+ return Number.isFinite(value);
70
+ if (Array.isArray(value))
71
+ return value.every(isJsonCompatible);
72
+ if (typeof value !== "object")
73
+ return false;
74
+ return Object.values(value).every(isJsonCompatible);
75
+ };
76
+ const replayValuesEqual = (left, right) => isJsonCompatible(left) &&
77
+ isJsonCompatible(right) &&
78
+ (Object.is(left, right) || canonicalize(left) === canonicalize(right));
79
+ /** Stateful evaluator for one validated replay-machine instance. */
80
+ export class ReplayMachineRuntime {
81
+ machine;
82
+ #variables = new Map();
83
+ #sensitiveValues = new Map();
84
+ #uses = new Map();
85
+ #stateVisits = new Map();
86
+ #timeline = [];
87
+ #state;
88
+ #connections = 0;
89
+ #messages = 0;
90
+ #bytes = 0;
91
+ #lastAtMs = 0;
92
+ constructor(machine) {
93
+ this.machine = machine;
94
+ this.#state = machine.initial_state;
95
+ this.#stateVisits.set(machine.initial_state, 1);
96
+ }
97
+ /** Current machine state after all accepted transitions. */
98
+ get state() {
99
+ return this.#state;
100
+ }
101
+ /** Ordered, secret-free transition records. */
102
+ get timeline() {
103
+ return this.#timeline;
104
+ }
105
+ /** Replace captured secret values with stable aliases before persistence. */
106
+ redact(value) {
107
+ let redacted = value;
108
+ const secrets = [...this.#sensitiveValues]
109
+ .flatMap(([variable, values]) => [...values].map((secret) => ({ variable, secret })))
110
+ .sort((left, right) => right.secret.length - left.secret.length ||
111
+ left.variable.localeCompare(right.variable));
112
+ for (const { variable, secret } of secrets)
113
+ redacted = redacted.replaceAll(secret, `<secret:${variable}>`);
114
+ return redacted;
115
+ }
116
+ /** Evaluate and, when admitted, commit one protocol event. */
117
+ dispatch(event) {
118
+ const normalizedEvent = {
119
+ ...event,
120
+ headers: Object.fromEntries(Object.entries(event.headers).map(([name, value]) => [
121
+ name.toLowerCase(),
122
+ value,
123
+ ])),
124
+ };
125
+ if (!this.#admitEvent(normalizedEvent))
126
+ return this.#refusal("limit_exhausted");
127
+ const matching = this.machine.transitions
128
+ .map((transition, declarationOrder) => ({
129
+ transition,
130
+ declarationOrder,
131
+ }))
132
+ .filter(({ transition }) => triggerMatches(transition, normalizedEvent));
133
+ const eligible = matching
134
+ .filter(({ transition }) => transition.from === this.#state)
135
+ .sort((left, right) => left.transition.priority - right.transition.priority ||
136
+ left.declarationOrder - right.declarationOrder);
137
+ if (eligible.length === 0)
138
+ return this.#refusal(matching.length === 0
139
+ ? "unmatched"
140
+ : normalizedEvent.protocol === "websocket_connect" &&
141
+ normalizedEvent.connection === "reconnect"
142
+ ? "unexpected_reconnect"
143
+ : "invalid_state");
144
+ const guarded = eligible.filter(({ transition }) => transition.guards.every((guard) => this.#variables.has(guard.variable) &&
145
+ replayValuesEqual(this.#variables.get(guard.variable), readValue(guard.value, normalizedEvent, transition))));
146
+ if (guarded.length === 0)
147
+ return this.#refusal("guard_failed");
148
+ if (this.#timeline.length >= this.machine.max_transitions)
149
+ return this.#refusal("transition_exhausted");
150
+ const usable = guarded.find(({ transition }) => (this.#uses.get(transition.id) ?? 0) < transition.max_uses);
151
+ if (usable === undefined)
152
+ return this.#refusal("transition_exhausted");
153
+ const transition = usable.transition;
154
+ const used = this.#uses.get(transition.id) ?? 0;
155
+ const nextState = this.machine.states.find(({ name }) => name === transition.to);
156
+ const nextVisits = (this.#stateVisits.get(transition.to) ?? 0) + 1;
157
+ if (nextState === undefined || nextVisits > nextState.max_visits)
158
+ return this.#refusal("limit_exhausted");
159
+ const captures = transition.captures.map((capture) => ({
160
+ ...capture,
161
+ captured: readValue(capture.value, normalizedEvent, transition),
162
+ }));
163
+ if (captures.some(({ captured, sensitive }) => !isJsonCompatible(captured) ||
164
+ (sensitive && typeof captured !== "string")))
165
+ return this.#refusal("invalid_capture");
166
+ for (const capture of captures) {
167
+ this.#variables.set(capture.variable, capture.captured);
168
+ if (capture.sensitive && typeof capture.captured === "string") {
169
+ const values = this.#sensitiveValues.get(capture.variable) ?? new Set();
170
+ if (capture.captured.length > 0)
171
+ values.add(capture.captured);
172
+ this.#sensitiveValues.set(capture.variable, values);
173
+ }
174
+ }
175
+ const record = {
176
+ sequence: this.#timeline.length,
177
+ transition_id: transition.id,
178
+ state_before: this.#state,
179
+ state_after: transition.to,
180
+ sensitive_aliases: captures
181
+ .filter(({ sensitive }) => sensitive)
182
+ .map(({ variable }) => variable)
183
+ .sort(),
184
+ };
185
+ this.#uses.set(transition.id, used + 1);
186
+ this.#stateVisits.set(transition.to, nextVisits);
187
+ this.#state = transition.to;
188
+ this.#timeline.push(record);
189
+ return {
190
+ outcome: "matched",
191
+ actions: transition.actions,
192
+ transition: record,
193
+ };
194
+ }
195
+ #admitEvent(event) {
196
+ const connections = this.#connections + (event.protocol === "websocket_connect" ? 1 : 0);
197
+ const messages = this.#messages + (event.protocol === "websocket_message" ? 1 : 0);
198
+ const bytes = this.#bytes + Buffer.byteLength(event.body);
199
+ if (!Number.isSafeInteger(event.at_ms) ||
200
+ event.at_ms < this.#lastAtMs ||
201
+ event.at_ms > this.machine.limits.duration_ms ||
202
+ connections > this.machine.limits.connections ||
203
+ messages > this.machine.limits.messages ||
204
+ bytes > this.machine.limits.bytes)
205
+ return false;
206
+ this.#connections = connections;
207
+ this.#messages = messages;
208
+ this.#bytes = bytes;
209
+ this.#lastAtMs = event.at_ms;
210
+ return true;
211
+ }
212
+ #refusal(outcome) {
213
+ return { outcome, actions: [], transition: null };
214
+ }
215
+ }
@@ -0,0 +1,85 @@
1
+ import { createHash } from "node:crypto";
2
+ import canonicalize from "canonicalize";
3
+ import { z } from "zod";
4
+ const digestSchema = z.string().regex(/^[a-f0-9]{64}$/u);
5
+ const stableIdSchema = z.string().regex(/^[A-Za-z][A-Za-z0-9._:/-]{0,199}$/u);
6
+ const runtimeIdentitySchema = z.strictObject({
7
+ family: z.string().trim().min(1).max(100),
8
+ provider_id: stableIdSchema,
9
+ executable_path: z.string().min(1).max(4_096),
10
+ executable_sha256: digestSchema,
11
+ version: z.string().trim().min(1).max(500),
12
+ profile_sha256: digestSchema,
13
+ });
14
+ const artifactIdentitySchema = z.strictObject({
15
+ path: z.string().min(1).max(4_096),
16
+ sha256: digestSchema,
17
+ byte_length: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
18
+ });
19
+ const callableIdentitySchema = z.strictObject({
20
+ callable_id: stableIdSchema,
21
+ module_id: stableIdSchema,
22
+ export_name: z.string().min(1).max(1_000),
23
+ semantic_evidence_id: z
24
+ .string()
25
+ .regex(/^ev_[a-f0-9]{64}$/u)
26
+ .nullable(),
27
+ selector_sha256: digestSchema,
28
+ });
29
+ export const runtimeCharacterizationPlanSchema = z.strictObject({
30
+ schema_version: z.literal(1),
31
+ plan_sha256: digestSchema,
32
+ preparation_sha256: digestSchema,
33
+ artifact: artifactIdentitySchema,
34
+ runtime: runtimeIdentitySchema,
35
+ callable: callableIdentitySchema,
36
+ working_directory: z.string().min(1).max(4_096),
37
+ isolated_home: z.string().min(1).max(4_096),
38
+ expected_effect: z.enum(["pure", "bounded-effects", "observation-only"]),
39
+ allowed_boundaries: z.array(stableIdSchema).max(1_000),
40
+ limits: z.strictObject({
41
+ max_calls: z.number().int().min(1).max(10_000),
42
+ max_processes: z.number().int().min(0).max(1_000),
43
+ max_files: z.number().int().min(0).max(100_000),
44
+ max_bytes: z.number().int().min(1).max(Number.MAX_SAFE_INTEGER),
45
+ max_handles: z.number().int().min(0).max(100_000),
46
+ timeout_ms: z.number().int().min(1).max(300_000),
47
+ idle_timeout_ms: z.number().int().min(1).max(300_000),
48
+ }),
49
+ determinism: z.strictObject({
50
+ clock: z.enum(["fixed", "real"]),
51
+ randomness: z.enum(["seeded", "system"]),
52
+ identifiers: z.enum(["deterministic", "runtime"]),
53
+ seed: z.number().int().min(0).max(0xffff_ffff),
54
+ }),
55
+ authority: z.strictObject({
56
+ preparation_approved: z.literal(true),
57
+ execution_approved: z.literal(false),
58
+ network: z.enum(["none", "loopback"]),
59
+ provider_owned_process_only: z.literal(true),
60
+ }),
61
+ });
62
+ /** Commit a provider-neutral preparation plan; execution requires a later approval. */
63
+ export const createRuntimeCharacterizationPlan = (input) => {
64
+ const parsed = runtimeCharacterizationPlanSchema
65
+ .omit({ plan_sha256: true })
66
+ .parse(input);
67
+ return runtimeCharacterizationPlanSchema.parse({
68
+ ...parsed,
69
+ plan_sha256: digest(parsed),
70
+ });
71
+ };
72
+ /** Parse a characterization plan and reject altered commitments. */
73
+ export const parseRuntimeCharacterizationPlan = (input) => {
74
+ const parsed = runtimeCharacterizationPlanSchema.parse(input);
75
+ const { plan_sha256: planSha256, ...semantic } = parsed;
76
+ if (planSha256 !== digest(semantic))
77
+ throw new TypeError("Runtime characterization plan digest is invalid");
78
+ return parsed;
79
+ };
80
+ const digest = (value) => {
81
+ const encoded = canonicalize(value);
82
+ if (encoded === undefined)
83
+ throw new TypeError("Runtime characterization plan is not canonical JSON");
84
+ return createHash("sha256").update(encoded).digest("hex");
85
+ };
@@ -0,0 +1,210 @@
1
+ import { createHash } from "node:crypto";
2
+ import canonicalize from "canonicalize";
3
+ import { z } from "zod";
4
+ import { parseArtifactInventoryEvidence } from "./artifactInventoryEvidence.js";
5
+ import { evidenceSchema } from "./evidence.js";
6
+ const digestSchema = z.string().regex(/^[a-f0-9]{64}$/u);
7
+ const evidenceIdSchema = z.string().regex(/^ev_[a-f0-9]{64}$/u);
8
+ const runtimeFamilySchema = z.enum([
9
+ "android",
10
+ "apple",
11
+ "javascript",
12
+ "jvm",
13
+ "native",
14
+ "webassembly",
15
+ ]);
16
+ const observationSchema = z.strictObject({
17
+ path: z.string().min(1).max(4_096),
18
+ artifact_id: z.string().regex(/^art_[a-f0-9]{64}$/u),
19
+ sha256: digestSchema,
20
+ format: z.string().min(1).max(100),
21
+ });
22
+ /** Authenticated artifact inventory pages to classify by runtime family. */
23
+ const runtimeIdentificationInputSchema = z.strictObject({
24
+ inventory_evidence: z.array(evidenceSchema).min(1).max(100),
25
+ limits: z
26
+ .strictObject({
27
+ max_observations: z.number().int().min(1).max(10_000).default(1_000),
28
+ })
29
+ .default({ max_observations: 1_000 }),
30
+ });
31
+ /** Provider-neutral runtime identification with explicit tooling availability. */
32
+ export const runtimeIdentificationResultSchema = z.strictObject({
33
+ schema_version: z.literal(1),
34
+ identification_id: z.string().regex(/^rid_[a-f0-9]{64}$/u),
35
+ root_sha256: digestSchema,
36
+ root_format: z.string().min(1).max(100),
37
+ source_evidence_ids: z.array(evidenceIdSchema).min(1).max(100),
38
+ runtimes: z.array(z.strictObject({
39
+ family: runtimeFamilySchema,
40
+ inspection: z.enum([
41
+ "available",
42
+ "provider-missing",
43
+ "provider-selection-required",
44
+ ]),
45
+ provider_id: z.string().min(1).max(200).nullable(),
46
+ reason: z.string().min(1).max(1_000).nullable(),
47
+ observations: z.array(observationSchema),
48
+ omitted_observations: z.number().int().min(0),
49
+ })),
50
+ coverage: z.strictObject({
51
+ status: z.enum(["complete-within-inventory", "partial", "truncated"]),
52
+ inventory_complete: z.boolean(),
53
+ omitted_observations: z.number().int().min(0),
54
+ }),
55
+ limitations: z.array(z.string().min(1).max(4_096)).max(100),
56
+ });
57
+ const PROVIDERS = {
58
+ android: {
59
+ inspection: "available",
60
+ id: "rea-android-application",
61
+ reason: null,
62
+ },
63
+ apple: { inspection: "available", id: "rea-apple-application", reason: null },
64
+ javascript: {
65
+ inspection: "available",
66
+ id: "rea-javascript-application",
67
+ reason: null,
68
+ },
69
+ jvm: {
70
+ inspection: "provider-missing",
71
+ id: null,
72
+ reason: "Install or configure a JVM bytecode-analysis provider.",
73
+ },
74
+ native: {
75
+ inspection: "provider-selection-required",
76
+ id: null,
77
+ reason: "Select an available native deep-analysis provider for this target and host.",
78
+ },
79
+ webassembly: {
80
+ inspection: "provider-missing",
81
+ id: null,
82
+ reason: "Install or configure a WebAssembly semantic-analysis provider.",
83
+ },
84
+ };
85
+ /** Identify runtime families without executing or semantically decoding target bytes. */
86
+ export const identifyRuntimes = (input) => {
87
+ const parsed = runtimeIdentificationInputSchema.parse(input);
88
+ const { evidence, inventory } = parseArtifactInventoryEvidence(parsed.inventory_evidence);
89
+ const nodes = new Map(inventory.nodes.map((node) => [node.artifact_id, node]));
90
+ const grouped = new Map();
91
+ const add = (family, observation) => {
92
+ const observations = grouped.get(family) ?? [];
93
+ observations.push(observation);
94
+ grouped.set(family, observations);
95
+ };
96
+ for (const occurrence of inventory.occurrences) {
97
+ if (occurrence.artifact_id === null)
98
+ continue;
99
+ const node = nodes.get(occurrence.artifact_id);
100
+ if (node === undefined)
101
+ throw new TypeError("Runtime observation has no artifact node");
102
+ const observation = {
103
+ path: occurrence.logical_path,
104
+ artifact_id: node.artifact_id,
105
+ sha256: node.sha256,
106
+ format: node.format,
107
+ };
108
+ for (const family of familiesFor(node.format, occurrence.logical_path))
109
+ add(family, observation);
110
+ }
111
+ const rootObservation = inventory.nodes.find(({ sha256 }) => sha256 === inventory.manifest.root_sha256);
112
+ if (rootObservation !== undefined)
113
+ for (const family of familiesFor(inventory.manifest.root_format, "."))
114
+ add(family, {
115
+ path: ".",
116
+ artifact_id: rootObservation.artifact_id,
117
+ sha256: rootObservation.sha256,
118
+ format: rootObservation.format,
119
+ });
120
+ let remaining = parsed.limits.max_observations;
121
+ let omitted = 0;
122
+ const runtimes = [...grouped.entries()]
123
+ .sort(([left], [right]) => compare(left, right))
124
+ .map(([family, values]) => {
125
+ const unique = deduplicate(values);
126
+ const observations = unique.slice(0, remaining);
127
+ remaining -= observations.length;
128
+ const omittedObservations = unique.length - observations.length;
129
+ omitted += omittedObservations;
130
+ const provider = providerFor(family, inventory.manifest.root_format);
131
+ return {
132
+ family,
133
+ inspection: provider.inspection,
134
+ provider_id: provider.id,
135
+ reason: provider.reason,
136
+ observations,
137
+ omitted_observations: omittedObservations,
138
+ };
139
+ });
140
+ const limitations = [
141
+ ...(!inventory.complete
142
+ ? [
143
+ "Source inventory pages are incomplete; absent runtimes remain unknown.",
144
+ ]
145
+ : []),
146
+ ...(omitted > 0
147
+ ? [`${String(omitted)} runtime observations were omitted by the limit.`]
148
+ : []),
149
+ "Runtime families are identified from exact artifact formats and paths; semantic claims require the named provider.",
150
+ ];
151
+ const withoutId = {
152
+ schema_version: 1,
153
+ root_sha256: inventory.manifest.root_sha256,
154
+ root_format: inventory.manifest.root_format,
155
+ source_evidence_ids: evidence
156
+ .map(({ evidence_id: id }) => id)
157
+ .sort(compare),
158
+ runtimes,
159
+ coverage: {
160
+ status: omitted > 0
161
+ ? "truncated"
162
+ : inventory.complete
163
+ ? "complete-within-inventory"
164
+ : "partial",
165
+ inventory_complete: inventory.complete,
166
+ omitted_observations: omitted,
167
+ },
168
+ limitations,
169
+ };
170
+ return runtimeIdentificationResultSchema.parse({
171
+ ...withoutId,
172
+ identification_id: `rid_${digest(withoutId)}`,
173
+ });
174
+ };
175
+ const providerFor = (family, rootFormat) => family === "android" && rootFormat !== "apk"
176
+ ? {
177
+ inspection: "provider-selection-required",
178
+ id: null,
179
+ reason: "Extract or select an APK root before using the Android application provider.",
180
+ }
181
+ : PROVIDERS[family];
182
+ const familiesFor = (format, path) => {
183
+ const families = new Set();
184
+ if (format === "apk" ||
185
+ format === "dex" ||
186
+ /(?:^|\/)[^/]+\.dex$/iu.test(path) ||
187
+ /(?:^|\/)AndroidManifest\.xml$/u.test(path))
188
+ families.add("android");
189
+ if (format === "ipa")
190
+ families.add("apple");
191
+ if (format === "javascript-bundle")
192
+ families.add("javascript");
193
+ if (format === "jvm-class" || /(?:^|\/)[^/]+\.class$/iu.test(path))
194
+ families.add("jvm");
195
+ if (["elf", "mach-o", "mach-o-universal", "pe"].includes(format))
196
+ families.add("native");
197
+ if (format === "webassembly" || /(?:^|\/)[^/]+\.wasm$/iu.test(path))
198
+ families.add("webassembly");
199
+ return [...families];
200
+ };
201
+ const deduplicate = (values) => [
202
+ ...new Map(values.map((value) => [`${value.path}\0${value.artifact_id}`, value])).values(),
203
+ ].sort((left, right) => compare(left.path, right.path));
204
+ const compare = (left, right) => left < right ? -1 : left > right ? 1 : 0;
205
+ const digest = (value) => {
206
+ const encoded = canonicalize(value);
207
+ if (encoded === undefined)
208
+ throw new TypeError("Runtime identification is not canonical JSON");
209
+ return createHash("sha256").update(encoded).digest("hex");
210
+ };