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
@@ -1,4 +1,5 @@
1
- import { McpServer } from "@modelcontextprotocol/server";
1
+ import { randomBytes } from "node:crypto";
2
+ import { CLIENT_CAPABILITIES_META_KEY, createRequestStateCodec, McpServer, PROTOCOL_VERSION_META_KEY, } from "@modelcontextprotocol/server";
2
3
  import { PRODUCT_IDENTITY } from "../identity.js";
3
4
  import { registerEnhancedTools } from "./registerEnhancedTools.js";
4
5
  import { registerOfficialTools } from "./registerOfficialTools.js";
@@ -14,8 +15,11 @@ import { createServerIdentity } from "../serverIdentity.js";
14
15
  import { registerBrowserTools } from "./registerBrowserTools.js";
15
16
  import { registerElectronTools } from "./registerElectronTools.js";
16
17
  import { registerApplicationTools } from "./registerApplicationTools.js";
18
+ const TARGET_FREE_INSTRUCTIONS = "REA analyzes shipped artifacts and approved runtime evidence; use repository tools for source. Route: ASAR/JavaScript -> analyze_javascript_application; archive/package -> inventory_artifact; managed PE/CLI -> inspect_managed_artifact; browser/Electron runtime -> list_browser_targets/list_electron_targets; native binary/database -> open_binary, then binary_overview. Start with summaries and cite Evidence IDs. Never repeat identical analysis or read full Evidence unless a missing detail requires it.";
19
+ const ACTIVE_TARGET_INSTRUCTIONS = "REA analyzes the active reverse-engineering target. Start native analysis with binary_overview, then narrow with analyze_function, literal search, callers, callees, and xrefs. Prefer summary views, never repeat an identical call, and read full Evidence only when the task requires it.";
17
20
  import { LinuxJavaScriptReplayRunner } from "../replay/LinuxJavaScriptReplayRunner.js";
18
21
  import { SystemJavaScriptReplayHost } from "../replay/SystemJavaScriptReplayHost.js";
22
+ import { PROCESS_CAPTURE_ELICITATION_POLICY, } from "./ProcessCaptureElicitation.js";
19
23
  /**
20
24
  * Construct one MCP server without acquiring subprocess resources.
21
25
  * Supplying a session adds target lifecycle tools; omitting it retains the
@@ -24,6 +28,11 @@ import { SystemJavaScriptReplayHost } from "../replay/SystemJavaScriptReplayHost
24
28
  export const createServer = (analysis, session, options = {}) => {
25
29
  const startedAt = new Date().toISOString();
26
30
  const logger = options.logger ?? silentLogger;
31
+ const permissionAuthority = options.permissionAuthority?.createConnectionAuthority();
32
+ const processCaptureStateCodec = createRequestStateCodec({
33
+ key: randomBytes(32),
34
+ ttlSeconds: PROCESS_CAPTURE_ELICITATION_POLICY.stateTtlSeconds,
35
+ });
27
36
  const server = new McpServer({
28
37
  name: PRODUCT_IDENTITY.mcpServerKey,
29
38
  version: PRODUCT_IDENTITY.packageVersion,
@@ -32,17 +41,88 @@ export const createServer = (analysis, session, options = {}) => {
32
41
  tools: { listChanged: true },
33
42
  resources: { listChanged: true },
34
43
  },
44
+ inputRequired: {
45
+ maxRounds: 3,
46
+ roundTimeoutMs: PROCESS_CAPTURE_ELICITATION_POLICY.roundTimeoutMs,
47
+ },
48
+ requestState: { verify: processCaptureStateCodec.verify },
35
49
  instructions: session === undefined
36
- ? "Reverse-engineering tools for an active analysis target. Start with binary_overview."
37
- : "Reverse-engineering tools for configured analysis providers. Open a target with open_binary, then start with binary_overview.",
50
+ ? ACTIVE_TARGET_INSTRUCTIONS
51
+ : TARGET_FREE_INSTRUCTIONS,
38
52
  });
53
+ server.server.onclose = () => {
54
+ permissionAuthority?.clearSessionGrants();
55
+ };
39
56
  session?.onAvailabilityChanged?.(() => server.sendToolListChanged());
57
+ registerServerIdentityResource(server, startedAt);
58
+ const toolLogger = logger.child({ layer: "server" });
59
+ const { activeTarget, recordEvidence, recordEvidenceWithUnknown } = createSessionRecorders(server, session);
60
+ const toolContext = {
61
+ server,
62
+ analysis,
63
+ session,
64
+ options,
65
+ logger: toolLogger,
66
+ permissionAuthority,
67
+ activeTarget,
68
+ recordEvidence,
69
+ recordEvidenceWithUnknown,
70
+ };
71
+ registerBinaryAnalysisTools(toolContext);
72
+ registerObservationTools(toolContext);
73
+ registerGuidedPrompts(server, analysis, session);
74
+ if (session !== undefined) {
75
+ registerEvidenceResources(server, session);
76
+ registerSessionTools(server, session, toolLogger, {
77
+ ...options,
78
+ ...(permissionAuthority === undefined ? {} : { permissionAuthority }),
79
+ startedAt,
80
+ processCaptureElicitation: {
81
+ stateCodec: processCaptureStateCodec,
82
+ supported: (context) => {
83
+ const envelope = context.mcpReq.envelope;
84
+ const version = envelope?.[PROTOCOL_VERSION_META_KEY];
85
+ const capabilities = envelope?.[CLIENT_CAPABILITIES_META_KEY];
86
+ return (typeof version === "string" &&
87
+ PROCESS_CAPTURE_ELICITATION_POLICY.protocolVersions.some((supported) => supported === version) &&
88
+ isRecord(capabilities) &&
89
+ isRecord(capabilities.elicitation) &&
90
+ capabilities.elicitation.form !== undefined);
91
+ },
92
+ now: Date.now,
93
+ consumedNonces: new Map(),
94
+ },
95
+ });
96
+ }
97
+ return server;
98
+ };
99
+ const createSessionRecorders = (server, session) => ({
100
+ activeTarget: session === undefined ? undefined : () => session.activeTarget(),
101
+ recordEvidence: session === undefined
102
+ ? undefined
103
+ : (evidence) => {
104
+ const recorded = session.recordEvidence(evidence);
105
+ if (recorded.ok && recorded.value === "added")
106
+ server.sendResourceListChanged();
107
+ return recorded;
108
+ },
109
+ recordEvidenceWithUnknown: session === undefined
110
+ ? undefined
111
+ : (evidence, input) => {
112
+ const recorded = session.recordEvidenceWithUnknown(evidence, input);
113
+ if (recorded.ok)
114
+ server.sendResourceListChanged();
115
+ return recorded;
116
+ },
117
+ });
118
+ const registerServerIdentityResource = (server, startedAt) => {
40
119
  server.registerResource("server-identity", "rea://server/identity", {
41
120
  title: "REA server identity",
42
121
  description: "Live package, SDK, protocol, and catalog identity.",
43
122
  mimeType: "application/json",
44
123
  }, (uri) => {
45
124
  const client = server.server.getClientVersion();
125
+ const protocolVersion = server.server.getNegotiatedProtocolVersion();
46
126
  return {
47
127
  contents: [
48
128
  {
@@ -51,72 +131,50 @@ export const createServer = (analysis, session, options = {}) => {
51
131
  text: JSON.stringify(createServerIdentity({
52
132
  startedAt,
53
133
  ...(client === undefined ? {} : { client }),
54
- ...(server.server.getNegotiatedProtocolVersion() === undefined
55
- ? {}
56
- : {
57
- protocolVersion: server.server.getNegotiatedProtocolVersion(),
58
- }),
134
+ ...(protocolVersion === undefined ? {} : { protocolVersion }),
59
135
  }), null, 2),
60
136
  },
61
137
  ],
62
138
  };
63
139
  });
64
- const toolLogger = logger.child({ layer: "server" });
65
- const activeTarget = session === undefined ? undefined : () => session.activeTarget();
66
- const recordEvidence = session === undefined
67
- ? undefined
68
- : (evidence) => {
69
- const recorded = session.recordEvidence(evidence);
70
- if (recorded.ok && recorded.value === "added")
71
- server.sendResourceListChanged();
72
- return recorded;
73
- };
74
- const recordEvidenceWithUnknown = session === undefined
140
+ };
141
+ const registerBinaryAnalysisTools = ({ server, analysis, session, options, logger, permissionAuthority, activeTarget, recordEvidence, recordEvidenceWithUnknown, }) => {
142
+ const recordUnknown = session === undefined
75
143
  ? undefined
76
- : (evidence, input) => {
77
- const recorded = session.recordEvidenceWithUnknown(evidence, input);
78
- if (recorded.ok)
79
- server.sendResourceListChanged();
80
- return recorded;
81
- };
144
+ : (input) => session.recordUnknown(input);
82
145
  registerOfficialTools(server, analysis, {
83
- logger: toolLogger,
146
+ logger,
84
147
  activeTarget,
85
148
  recordEvidence,
86
- recordUnknown: session === undefined
87
- ? undefined
88
- : (input) => session.recordUnknown(input),
149
+ recordUnknown,
89
150
  });
90
151
  registerEnhancedTools(server, analysis, {
91
- logger: toolLogger,
152
+ logger,
92
153
  activeTarget,
93
154
  analysisProfile: session === undefined ? undefined : () => session.analysisProfile(),
94
155
  recordEvidence,
95
- recordUnknown: session === undefined
96
- ? undefined
97
- : (input) => session.recordUnknown(input),
156
+ recordUnknown,
98
157
  });
99
158
  registerNativeTools(server, analysis, {
100
- logger: toolLogger,
159
+ logger,
101
160
  activeTarget,
102
161
  recordEvidence,
103
162
  });
104
163
  registerArtifactTools(server, analysis, {
105
- logger: toolLogger,
164
+ logger,
106
165
  activeTarget,
107
166
  recordEvidence,
108
- ...(options.permissionAuthority === undefined
109
- ? {}
110
- : { permissionAuthority: options.permissionAuthority }),
167
+ ...(permissionAuthority === undefined ? {} : { permissionAuthority }),
111
168
  });
112
169
  registerManagedTools(server, analysis, {
113
- logger: toolLogger,
170
+ logger,
114
171
  activeTarget,
115
172
  recordEvidence,
173
+ session,
116
174
  });
117
175
  if (session !== undefined)
118
176
  registerManagedWorkflowTools(server, {
119
- logger: toolLogger,
177
+ logger,
120
178
  recordEvidence,
121
179
  recordEvidenceWithUnknown,
122
180
  session,
@@ -126,25 +184,43 @@ export const createServer = (analysis, session, options = {}) => {
126
184
  roots: [],
127
185
  executablePath: "/usr/bin/dotnet",
128
186
  },
129
- authority: options.permissionAuthority,
187
+ authority: permissionAuthority,
130
188
  },
131
189
  });
190
+ };
191
+ const registerObservationTools = ({ server, session, options, logger, permissionAuthority, recordEvidence, recordEvidenceWithUnknown, }) => {
132
192
  registerBrowserTools(server, {
133
- logger: toolLogger,
193
+ logger,
134
194
  browser: options.browserObservation,
135
- permissionAuthority: options.permissionAuthority,
195
+ permissionAuthority,
136
196
  recordEvidence,
137
197
  });
138
198
  registerElectronTools(server, {
139
- logger: toolLogger,
199
+ logger,
140
200
  electron: options.electronObservation,
141
- permissionAuthority: options.permissionAuthority,
201
+ permissionAuthority,
142
202
  recordEvidence,
143
203
  });
144
204
  registerApplicationTools(server, {
145
- logger: toolLogger,
205
+ logger,
146
206
  recordEvidence,
147
207
  recordEvidenceWithUnknown,
208
+ evidenceFilePolicy: options.evidenceFilePolicy ?? {
209
+ roots: [],
210
+ maxBytes: 1,
211
+ maxDepth: 1,
212
+ maxStringLength: 1,
213
+ maxNodes: 1,
214
+ },
215
+ permissionAuthority,
216
+ retainCoverageWorkspace: session === undefined
217
+ ? undefined
218
+ : (workspace) => {
219
+ const retained = session.retainReconstructionCoverageWorkspace(workspace);
220
+ if (retained === "added")
221
+ server.sendResourceListChanged();
222
+ return retained;
223
+ },
148
224
  replay: {
149
225
  policy: options.javascriptReplayPolicy ?? {
150
226
  enabled: false,
@@ -157,16 +233,8 @@ export const createServer = (analysis, session, options = {}) => {
157
233
  },
158
234
  host: options.javascriptReplayHost ?? new SystemJavaScriptReplayHost(),
159
235
  runner: options.javascriptReplayRunner ?? new LinuxJavaScriptReplayRunner(),
160
- authority: options.permissionAuthority,
236
+ authority: permissionAuthority,
161
237
  },
162
238
  });
163
- registerGuidedPrompts(server, analysis, session);
164
- if (session !== undefined) {
165
- registerEvidenceResources(server, session);
166
- registerSessionTools(server, session, toolLogger, {
167
- ...options,
168
- startedAt,
169
- });
170
- }
171
- return server;
172
239
  };
240
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -0,0 +1,85 @@
1
+ import { javascriptApplicationAnalysisResultSchema } from "../domain/javascriptApplicationAnalysis.js";
2
+ import { compareCodePoints } from "../domain/javascriptApplicationGraph.js";
3
+ import { javascriptApplicationAnalysisSummarySchema } from "../contracts/electronToolContracts.js";
4
+ const DEFAULT_GRAPH_PAGE_LIMIT = 100;
5
+ const ROOT_SAMPLE_LIMIT = 10;
6
+ const TOP_FINDING_LIMIT = 20;
7
+ const FINDING_PRIORITY = {
8
+ "browser-window": 0,
9
+ "electron-preload": 1,
10
+ "context-bridge-api": 2,
11
+ "ipc-channel": 3,
12
+ "ipc-handler": 4,
13
+ "electron-utility": 5,
14
+ endpoint: 6,
15
+ storage: 7,
16
+ worker: 8,
17
+ "service-worker": 9,
18
+ "native-addon": 10,
19
+ "native-export": 11,
20
+ "source-map": 12,
21
+ };
22
+ /** Project complete JavaScript application Evidence into a bounded agent result. */
23
+ export const summarizeJavaScriptApplicationEvidence = (evidence) => {
24
+ const result = javascriptApplicationAnalysisResultSchema.parse(evidence.normalized_result);
25
+ const nodeKinds = new Map();
26
+ for (const node of result.graph.nodes)
27
+ nodeKinds.set(node.kind, (nodeKinds.get(node.kind) ?? 0) + 1);
28
+ const rootItems = result.graph.root_node_ids.slice(0, ROOT_SAMPLE_LIMIT);
29
+ const pageRoot = `rea://evidence/${evidence.evidence_id}/application-graph`;
30
+ const topFindings = [...result.graph.nodes]
31
+ .sort((left, right) => (FINDING_PRIORITY[left.kind] ?? Number.MAX_SAFE_INTEGER) -
32
+ (FINDING_PRIORITY[right.kind] ?? Number.MAX_SAFE_INTEGER) ||
33
+ compareCodePoints(left.node_id, right.node_id))
34
+ .slice(0, TOP_FINDING_LIMIT)
35
+ .map((node) => {
36
+ const observation = node.observations[0];
37
+ if (observation === undefined)
38
+ throw new TypeError("Application graph node has no observation");
39
+ return {
40
+ node_id: node.node_id,
41
+ kind: node.kind,
42
+ label: observation.label,
43
+ authority: observation.evidence.authority,
44
+ state: observation.evidence.state,
45
+ confidence: observation.evidence.confidence,
46
+ location: observation.evidence.location,
47
+ };
48
+ });
49
+ const { graph: _graph, ...summary } = result;
50
+ const unknowns = new Set([
51
+ ...result.limitations,
52
+ ...result.graph.limitations,
53
+ ]);
54
+ if (result.statistics.parse_failures > 0)
55
+ unknowns.add(`${String(result.statistics.parse_failures)} JavaScript file(s) could not be parsed.`);
56
+ if (result.statistics.truncated_scopes > 0)
57
+ unknowns.add(`${String(result.statistics.truncated_scopes)} analysis scope(s) were truncated.`);
58
+ if (result.graph.coverage.status !== "complete")
59
+ unknowns.add(`Application graph coverage is ${result.graph.coverage.status}; omitted facts remain unknown.`);
60
+ return javascriptApplicationAnalysisSummarySchema.parse({
61
+ ...summary,
62
+ unknowns: [...unknowns],
63
+ graph: {
64
+ graph_id: result.graph.graph_id,
65
+ node_count: result.graph.nodes.length,
66
+ edge_count: result.graph.edges.length,
67
+ roots: {
68
+ items: rootItems,
69
+ total: result.graph.root_node_ids.length,
70
+ truncated: rootItems.length < result.graph.root_node_ids.length,
71
+ },
72
+ node_kinds: [...nodeKinds]
73
+ .sort(([left], [right]) => compareCodePoints(left, right))
74
+ .map(([kind, count]) => ({ kind, count })),
75
+ top_findings: topFindings,
76
+ coverage: result.graph.coverage,
77
+ limitations: result.graph.limitations,
78
+ pages: {
79
+ nodes: `${pageRoot}/nodes/offset/0/limit/${String(DEFAULT_GRAPH_PAGE_LIMIT)}`,
80
+ edges: `${pageRoot}/edges/offset/0/limit/${String(DEFAULT_GRAPH_PAGE_LIMIT)}`,
81
+ page_limit: DEFAULT_GRAPH_PAGE_LIMIT,
82
+ },
83
+ },
84
+ });
85
+ };
@@ -0,0 +1,57 @@
1
+ import { executeNodeCharacterization, prepareNodeCharacterization, } from "../../application/NodeRuntimeCharacterizationService.js";
2
+ import { APPLICATION_TOOL_CONTRACTS } from "../../contracts/applicationToolContracts.js";
3
+ import { nodeCharacterizationExecutionInputSchema, nodeCharacterizationExecutionOutputSchema, nodeCharacterizationPreparationInputSchema, nodeCharacterizationPreparationOutputSchema, } from "../../domain/nodeRuntimeCharacterization.js";
4
+ import { parseEvidence } from "../../domain/evidence.js";
5
+ import { logToolExecution } from "../toolLogging.js";
6
+ import { toCallToolResult } from "../toolResult.js";
7
+ import { toolRegistrationOptions } from "../toolRegistrationOptions.js";
8
+ import { safeParseToolInput } from "../toolInputValidation.js";
9
+ import { mcpProgressReporter } from "../mcpProgress.js";
10
+ import { recordSources } from "./helpers.js";
11
+ const prepareContract = APPLICATION_TOOL_CONTRACTS[3];
12
+ const executeContract = APPLICATION_TOOL_CONTRACTS[4];
13
+ /** Register node runtime characterization prepare and execute tools. */
14
+ export const registerCharacterizationTools = (server, options) => {
15
+ server.registerTool(prepareContract.name, toolRegistrationOptions(prepareContract), async (input, context) => {
16
+ const parsed = safeParseToolInput(nodeCharacterizationPreparationInputSchema, input, prepareContract.name);
17
+ if (!parsed.ok)
18
+ return toCallToolResult(parsed, prepareContract);
19
+ const result = await logToolExecution(options.logger, prepareContract.name, () => prepareNodeCharacterization(options.replay, parsed.value, {
20
+ signal: context.mcpReq.signal,
21
+ progress: mcpProgressReporter(context),
22
+ }));
23
+ if (!result.ok)
24
+ return toCallToolResult(result, prepareContract);
25
+ const output = nodeCharacterizationPreparationOutputSchema.parse(result.value);
26
+ const recorded = options.recordEvidence?.(parseEvidence(output.transformation_evidence));
27
+ if (recorded !== undefined && !recorded.ok)
28
+ return toCallToolResult(recorded, prepareContract);
29
+ return toCallToolResult(result, prepareContract, {
30
+ evidenceResourcesAvailable: options.recordEvidence !== undefined,
31
+ });
32
+ });
33
+ server.registerTool(executeContract.name, toolRegistrationOptions(executeContract), async (input, context) => {
34
+ const parsed = safeParseToolInput(nodeCharacterizationExecutionInputSchema, input, executeContract.name);
35
+ if (!parsed.ok)
36
+ return toCallToolResult(parsed, executeContract);
37
+ const result = await logToolExecution(options.logger, executeContract.name, () => executeNodeCharacterization(options.replay, parsed.value, {
38
+ signal: context.mcpReq.signal,
39
+ progress: mcpProgressReporter(context),
40
+ }));
41
+ if (!result.ok)
42
+ return toCallToolResult(result, executeContract);
43
+ const output = nodeCharacterizationExecutionOutputSchema.parse(result.value);
44
+ const sources = [
45
+ output.transformation_evidence,
46
+ ...output.replay.source_evidence,
47
+ ...(output.replay.evidence === null ? [] : [output.replay.evidence]),
48
+ output.evidence,
49
+ ].map((item) => parseEvidence(item));
50
+ const recorded = recordSources(options.recordEvidence, sources);
51
+ if (!recorded.ok)
52
+ return toCallToolResult(recorded, executeContract);
53
+ return toCallToolResult(result, executeContract, {
54
+ evidenceResourcesAvailable: options.recordEvidence !== undefined,
55
+ });
56
+ });
57
+ };
@@ -0,0 +1,34 @@
1
+ import { compareApplicationVersionsEvidenceValidated } from "../../application/JavaScriptApplicationWorkflowService.js";
2
+ import { APPLICATION_TOOL_CONTRACTS } from "../../contracts/applicationToolContracts.js";
3
+ import { compareApplicationVersionsInputSchema } from "../../domain/javascriptApplicationVersionComparisonSchemas.js";
4
+ import { applicationVersionComparisonResultSchema } from "../../domain/javascriptApplicationVersionComparisonSchemas.js";
5
+ import { logToolExecution } from "../toolLogging.js";
6
+ import { toCallToolResult } from "../toolResult.js";
7
+ import { toolRegistrationOptions } from "../toolRegistrationOptions.js";
8
+ import { safeParseToolInput } from "../toolInputValidation.js";
9
+ import { recordResult, recordSources } from "./helpers.js";
10
+ const compareContract = APPLICATION_TOOL_CONTRACTS[1];
11
+ /** Register the provider-neutral JavaScript version comparison tool. */
12
+ export const registerCompareApplicationVersionsTool = (server, options) => {
13
+ server.registerTool(compareContract.name, toolRegistrationOptions(compareContract), async (input) => {
14
+ const parsedInput = safeParseToolInput(compareApplicationVersionsInputSchema, input, compareContract.name);
15
+ if (!parsedInput.ok)
16
+ return toCallToolResult(parsedInput, compareContract);
17
+ const parsed = parsedInput.value;
18
+ const result = await logToolExecution(options.logger, compareContract.name, () => Promise.resolve(compareApplicationVersionsEvidenceValidated(parsed)));
19
+ if (!result.ok)
20
+ return toCallToolResult(result, compareContract);
21
+ const sources = [
22
+ parsed.left,
23
+ parsed.right,
24
+ ...parsed.left_native_observations,
25
+ ...parsed.right_native_observations,
26
+ ];
27
+ const recorded = recordSources(options.recordEvidence, sources);
28
+ if (!recorded.ok)
29
+ return toCallToolResult(recorded, compareContract);
30
+ const comparison = applicationVersionComparisonResultSchema.parse(result.value.normalized_result);
31
+ const unknown = comparison.summary.unknown > 0;
32
+ return recordResult(options, compareContract, result.value, parsed.unknown_registry_approved === true && unknown);
33
+ });
34
+ };
@@ -0,0 +1,38 @@
1
+ import { runControlledReplayValidated } from "../../application/JavaScriptReplayService.js";
2
+ import { APPLICATION_TOOL_CONTRACTS } from "../../contracts/applicationToolContracts.js";
3
+ import { controlledReplayInputSchema, controlledReplayOutputSchema, } from "../../domain/javascriptReplay.js";
4
+ import { parseEvidence } from "../../domain/evidence.js";
5
+ import { logToolExecution } from "../toolLogging.js";
6
+ import { toCallToolResult } from "../toolResult.js";
7
+ import { toolRegistrationOptions } from "../toolRegistrationOptions.js";
8
+ import { safeParseToolInput } from "../toolInputValidation.js";
9
+ import { mcpProgressReporter } from "../mcpProgress.js";
10
+ import { recordSources } from "./helpers.js";
11
+ const replayContract = APPLICATION_TOOL_CONTRACTS[2];
12
+ /** Register the controlled JavaScript replay tool. */
13
+ export const registerControlledReplayTool = (server, options) => {
14
+ server.registerTool(replayContract.name, toolRegistrationOptions(replayContract), async (input, context) => {
15
+ const parsedInput = safeParseToolInput(controlledReplayInputSchema, input, replayContract.name);
16
+ if (!parsedInput.ok)
17
+ return toCallToolResult(parsedInput, replayContract);
18
+ const parsed = parsedInput.value;
19
+ const result = await logToolExecution(options.logger, replayContract.name, () => runControlledReplayValidated(options.replay, parsed, {
20
+ signal: context.mcpReq.signal,
21
+ progress: mcpProgressReporter(context),
22
+ }));
23
+ if (!result.ok)
24
+ return toCallToolResult(result, replayContract);
25
+ const output = controlledReplayOutputSchema.parse(result.value);
26
+ if (output.evidence !== null) {
27
+ const sourcesRecorded = recordSources(options.recordEvidence, output.source_evidence.map((item) => parseEvidence(item)));
28
+ if (!sourcesRecorded.ok)
29
+ return toCallToolResult(sourcesRecorded, replayContract);
30
+ const recorded = options.recordEvidence?.(parseEvidence(output.evidence));
31
+ if (recorded !== undefined && !recorded.ok)
32
+ return toCallToolResult(recorded, replayContract);
33
+ }
34
+ return toCallToolResult(result, replayContract, {
35
+ evidenceResourcesAvailable: output.evidence !== null && options.recordEvidence !== undefined,
36
+ });
37
+ });
38
+ };
@@ -0,0 +1,84 @@
1
+ import { commitReconstructionCoverage, queryReconstructionCoverage, } from "../../application/ReconstructionCoverageService.js";
2
+ import { readReconstructionCoverageWorkspace } from "../../application/ReconstructionCoverageWorkspaceStore.js";
3
+ import { authorizeFileReadWithDeferredWrite, authorizeRootPermission, } from "../../application/DeferredFileAuthorization.js";
4
+ import { APPLICATION_TOOL_CONTRACTS } from "../../contracts/applicationToolContracts.js";
5
+ import { reconstructionCoverageCommitInputSchema, reconstructionCoverageQueryInputSchema, } from "../../application/ReconstructionCoverageService.js";
6
+ import { reconstructionClosureResultSchema } from "../../domain/reconstructionCoverage.js";
7
+ import { AnalysisCapabilityUnavailableError, EvidenceIntegrityError, } from "../../domain/errors.js";
8
+ import { err } from "../../domain/result.js";
9
+ import { logToolExecution } from "../toolLogging.js";
10
+ import { toCallToolResult } from "../toolResult.js";
11
+ import { toolRegistrationOptions } from "../toolRegistrationOptions.js";
12
+ import { safeParseToolInput } from "../toolInputValidation.js";
13
+ import { coverageWorkspaceUri } from "./helpers.js";
14
+ const commitContract = APPLICATION_TOOL_CONTRACTS[5];
15
+ const queryContract = APPLICATION_TOOL_CONTRACTS[6];
16
+ /** Register reconstruction coverage commit and query tools. */
17
+ export const registerCoverageTools = (server, options) => {
18
+ registerCommitTool(server, options);
19
+ registerQueryTool(server, options);
20
+ };
21
+ const registerCommitTool = (server, options) => {
22
+ server.registerTool(commitContract.name, toolRegistrationOptions(commitContract), async (input, context) => {
23
+ const parsed = safeParseToolInput(reconstructionCoverageCommitInputSchema, input, commitContract.name);
24
+ if (!parsed.ok)
25
+ return toCallToolResult(parsed, commitContract);
26
+ if (options.permissionAuthority === undefined)
27
+ return toCallToolResult(err(new AnalysisCapabilityUnavailableError("rea-reconstruction-coverage", commitContract.name, "workspace permission policy is not configured")), commitContract);
28
+ const authorization = await authorizeFileReadWithDeferredWrite(options.permissionAuthority, {
29
+ path: parsed.value.workspace_path,
30
+ readCapability: "investigation_workspace_read",
31
+ writeCapability: "investigation_workspace_write",
32
+ operation: commitContract.name,
33
+ });
34
+ if (!authorization.ok)
35
+ return toCallToolResult(authorization, commitContract);
36
+ const write = await authorization.value.authorizeWrite();
37
+ if (!write.ok)
38
+ return toCallToolResult(write, commitContract);
39
+ const result = await logToolExecution(options.logger, commitContract.name, () => commitReconstructionCoverage(parsed.value, options.evidenceFilePolicy, { signal: context.mcpReq.signal }));
40
+ if (!result.ok)
41
+ return toCallToolResult(result, commitContract);
42
+ options.retainCoverageWorkspace?.(parsed.value.workspace);
43
+ return toCallToolResult(result, commitContract, {
44
+ resourceLinks: options.retainCoverageWorkspace === undefined
45
+ ? []
46
+ : [
47
+ {
48
+ uri: coverageWorkspaceUri(parsed.value.workspace),
49
+ name: parsed.value.workspace.workspace_id,
50
+ description: "Session-retained reconstruction coverage workspace revision",
51
+ },
52
+ ],
53
+ });
54
+ });
55
+ };
56
+ const registerQueryTool = (server, options) => {
57
+ server.registerTool(queryContract.name, toolRegistrationOptions(queryContract), async (input, context) => {
58
+ const parsed = safeParseToolInput(reconstructionCoverageQueryInputSchema, input, queryContract.name);
59
+ if (!parsed.ok)
60
+ return toCallToolResult(parsed, queryContract);
61
+ if (options.permissionAuthority === undefined)
62
+ return toCallToolResult(err(new AnalysisCapabilityUnavailableError("rea-reconstruction-coverage", queryContract.name, "workspace permission policy is not configured")), queryContract);
63
+ const authorized = await authorizeRootPermission(options.permissionAuthority, {
64
+ capability: "investigation_workspace_read",
65
+ roots: [parsed.value.workspace_path],
66
+ access: "read",
67
+ operation: queryContract.name,
68
+ });
69
+ if (!authorized.ok)
70
+ return toCallToolResult(authorized, queryContract);
71
+ const result = await logToolExecution(options.logger, queryContract.name, () => queryReconstructionCoverage(parsed.value, options.evidenceFilePolicy, Date.now(), { signal: context.mcpReq.signal }));
72
+ if (result.ok && options.retainCoverageWorkspace !== undefined) {
73
+ const closure = reconstructionClosureResultSchema.parse(result.value);
74
+ const loaded = await readReconstructionCoverageWorkspace(parsed.value.workspace_path, options.evidenceFilePolicy);
75
+ if (!loaded.ok)
76
+ return toCallToolResult(loaded, queryContract);
77
+ if (loaded.value === null ||
78
+ loaded.value.revision_sha256 !== closure.workspace_revision_sha256)
79
+ return toCallToolResult(err(new EvidenceIntegrityError("workspace changed while its closure was being retained")), queryContract);
80
+ options.retainCoverageWorkspace(loaded.value);
81
+ }
82
+ return toCallToolResult(result, queryContract);
83
+ });
84
+ };
@@ -0,0 +1,42 @@
1
+ import { APPLICATION_TOOL_CONTRACTS } from "../../contracts/applicationToolContracts.js";
2
+ import { toCallToolResult } from "../toolResult.js";
3
+ export const coverageWorkspaceUri = (workspace) => `rea://reconstruction-coverage/${workspace.workspace_id}/revision/${String(workspace.revision)}`;
4
+ export const recordSources = (recordEvidence, sources) => {
5
+ for (const source of sources) {
6
+ const recorded = recordEvidence?.(source);
7
+ if (recorded !== undefined && !recorded.ok)
8
+ return recorded;
9
+ }
10
+ return { ok: true, value: null };
11
+ };
12
+ export const recordResult = (options, contract, evidence, recordUnknown = false) => {
13
+ const recorded = recordUnknown
14
+ ? options.recordEvidenceWithUnknown?.(evidence, {
15
+ approved: true,
16
+ question: "Which application entities remain unmatched or ambiguous across these versions?",
17
+ severity: "medium",
18
+ domain: "application-version-comparison",
19
+ supporting_evidence_ids: [evidence.evidence_id],
20
+ contradicting_evidence_ids: [],
21
+ required_authority: "shipped-artifact",
22
+ required_confidence: "observed",
23
+ required_environment: null,
24
+ recommended_probes: [
25
+ {
26
+ operation: "analyze_javascript_application",
27
+ rationale: "Repeat static reconstruction with complete artifacts and source maps when available.",
28
+ },
29
+ {
30
+ operation: "reconcile_javascript_runtime",
31
+ rationale: "Add approved passive runtime Evidence without promoting it to static fact.",
32
+ },
33
+ ],
34
+ relationships: [],
35
+ })
36
+ : options.recordEvidence?.(evidence);
37
+ if (recorded !== undefined && !recorded.ok)
38
+ return toCallToolResult(recorded, contract);
39
+ return toCallToolResult({ ok: true, value: evidence }, contract, {
40
+ evidenceResourcesAvailable: recorded !== undefined,
41
+ });
42
+ };
@@ -0,0 +1,26 @@
1
+ import { traceApplicationFeatureEvidenceValidated } from "../../application/JavaScriptApplicationWorkflowService.js";
2
+ import { APPLICATION_TOOL_CONTRACTS } from "../../contracts/applicationToolContracts.js";
3
+ import { traceApplicationFeatureInputSchema } from "../../domain/javascriptFeatureTraceSchemas.js";
4
+ import { logToolExecution } from "../toolLogging.js";
5
+ import { toCallToolResult } from "../toolResult.js";
6
+ import { toolRegistrationOptions } from "../toolRegistrationOptions.js";
7
+ import { safeParseToolInput } from "../toolInputValidation.js";
8
+ import { recordResult, recordSources } from "./helpers.js";
9
+ const traceContract = APPLICATION_TOOL_CONTRACTS[0];
10
+ /** Register the provider-neutral JavaScript feature trace tool. */
11
+ export const registerTraceFeatureTool = (server, options) => {
12
+ server.registerTool(traceContract.name, toolRegistrationOptions(traceContract), async (input) => {
13
+ const parsedInput = safeParseToolInput(traceApplicationFeatureInputSchema, input, traceContract.name);
14
+ if (!parsedInput.ok)
15
+ return toCallToolResult(parsedInput, traceContract);
16
+ const parsed = parsedInput.value;
17
+ const result = await logToolExecution(options.logger, traceContract.name, () => Promise.resolve(traceApplicationFeatureEvidenceValidated(parsed)));
18
+ if (!result.ok)
19
+ return toCallToolResult(result, traceContract);
20
+ const sources = [parsed.application, ...parsed.native_observations];
21
+ const recorded = recordSources(options.recordEvidence, sources);
22
+ if (!recorded.ok)
23
+ return toCallToolResult(recorded, traceContract);
24
+ return recordResult(options, traceContract, result.value);
25
+ });
26
+ };
@@ -0,0 +1 @@
1
+ export {};