rea-agents 2.4.0 → 3.0.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 (231) hide show
  1. package/README.md +91 -19
  2. package/bridge/ghidra/ReaGhidraBridge.java +524 -4
  3. package/bridge/hopper_bridge.py +313 -28
  4. package/dist/application/AnalysisClientCleanup.js +14 -0
  5. package/dist/application/AnalysisContextQueries.js +130 -0
  6. package/dist/application/AnalysisSnapshotCache.js +4 -2
  7. package/dist/application/ApplicationWorkflowEvidenceResolver.js +31 -13
  8. package/dist/application/ArtifactInventory/scanCanonical.js +1 -1
  9. package/dist/application/BinarySession.js +20 -8
  10. package/dist/application/BinarySessionComposition.js +21 -0
  11. package/dist/application/BinarySessionRecords.js +79 -9
  12. package/dist/application/BinarySessionStatus.js +31 -1
  13. package/dist/application/BrowserEvidence.js +14 -0
  14. package/dist/application/BrowserScenarioCapturePort.js +1 -0
  15. package/dist/application/BrowserScenarioCaptureService.js +53 -0
  16. package/dist/application/BrowserScenarioEvidence.js +40 -0
  17. package/dist/application/CallPathTracing.js +160 -0
  18. package/dist/application/CapabilityInventory.js +84 -14
  19. package/dist/application/ClientRegistrationStatus.js +4 -1
  20. package/dist/application/CompositeProvider.js +10 -1
  21. package/dist/application/DirectAnalysis.js +13 -4
  22. package/dist/application/EnhancedLiteralTracing.js +118 -0
  23. package/dist/application/EnhancedTools.js +71 -127
  24. package/dist/application/EvidenceLedger.js +45 -16
  25. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +13 -0
  26. package/dist/application/JavaScriptApplicationWorkflowService.js +27 -1
  27. package/dist/application/JavaScriptArtifactAnalysis.js +13 -4
  28. package/dist/application/JavaScriptRuntimeObservationEvidence.js +34 -0
  29. package/dist/application/JavaScriptRuntimeObservationPort.js +1 -0
  30. package/dist/application/JavaScriptRuntimeObservationService.js +46 -0
  31. package/dist/application/JavaScriptSemanticGraphAsyncProjection.js +147 -0
  32. package/dist/application/JavaScriptSemanticGraphBuilder.js +34 -6
  33. package/dist/application/JavaScriptSemanticGraphChildProcessProjection.js +156 -0
  34. package/dist/application/JavaScriptSemanticGraphConstruction.js +2 -2
  35. package/dist/application/JavaScriptSemanticGraphDataProjection.js +203 -0
  36. package/dist/application/JavaScriptSemanticGraphFingerprintProjection.js +25 -0
  37. package/dist/application/JavaScriptSemanticGraphFlowProjection.js +129 -8
  38. package/dist/application/JavaScriptSemanticGraphObjectProjection.js +81 -0
  39. package/dist/application/JavaScriptSemanticGraphProjection.js +14 -7
  40. package/dist/application/JavaScriptSemanticGraphResourceProjection.js +59 -0
  41. package/dist/application/JavaScriptSemanticGraphValueProjection.js +77 -0
  42. package/dist/application/LazyAnalysisProvider.js +77 -0
  43. package/dist/application/LoopbackReplay.js +1 -1
  44. package/dist/application/NativeApiInspection.js +80 -0
  45. package/dist/application/ProcessReactiveEffects.js +6 -0
  46. package/dist/application/ProcessReactiveHarness.js +16 -1
  47. package/dist/application/ProjectPermissionStore.js +1 -0
  48. package/dist/application/ReconstructionObligationAuthority.js +72 -0
  49. package/dist/application/ReconstructionObligationCandidates.js +265 -0
  50. package/dist/application/ReconstructionObligationLedgerDiagnostics.js +47 -0
  51. package/dist/application/ReconstructionObligationLedgerEvaluation.js +263 -0
  52. package/dist/application/ReconstructionObligationLedgerProjection.js +86 -0
  53. package/dist/application/ReconstructionObligationLedgerService.js +72 -0
  54. package/dist/application/ReconstructionObligationOriginalCases.js +33 -0
  55. package/dist/application/ReconstructionObligationPolicies.js +132 -0
  56. package/dist/application/ReconstructionReadinessService.js +48 -0
  57. package/dist/application/SessionProviderRouter.js +6 -6
  58. package/dist/application/SetupClientConfiguration.js +4 -2
  59. package/dist/application/runtime.js +26 -9
  60. package/dist/artifacts/ArtifactProvider.js +87 -22
  61. package/dist/browser/BrowserScenarioSecrets.js +53 -0
  62. package/dist/browser/BrowserScenarioSessionPort.js +1 -0
  63. package/dist/browser/CdpBrowserProvider.js +2 -2
  64. package/dist/browser/CdpCaptureDocuments.js +57 -0
  65. package/dist/browser/CdpCaptureStorage.js +71 -29
  66. package/dist/browser/CdpCaptureStorageFingerprints.js +328 -0
  67. package/dist/browser/CdpEndpoint.js +8 -6
  68. package/dist/browser/CdpPageCapture.js +2 -0
  69. package/dist/browser/JavaScriptRuntimeScope.js +38 -0
  70. package/dist/browser/PlaywrightBrowserScenarioProvider.js +259 -0
  71. package/dist/browser/PlaywrightExecutionBoundary.js +42 -0
  72. package/dist/browser/PlaywrightScenarioActions.js +62 -0
  73. package/dist/browser/PlaywrightScenarioArtifacts.js +238 -0
  74. package/dist/browser/PlaywrightScenarioBrowser.js +144 -0
  75. package/dist/browser/PlaywrightScenarioEvents.js +301 -0
  76. package/dist/browser/PlaywrightScenarioSession.js +300 -0
  77. package/dist/browser/V8InspectorCaptureProjection.js +110 -0
  78. package/dist/browser/V8InspectorEndpoint.js +72 -0
  79. package/dist/browser/V8InspectorProvider.js +267 -0
  80. package/dist/catalogIdentity.js +11 -3
  81. package/dist/cli/artifactCommands.js +44 -3
  82. package/dist/cli/coreAnalysisCommands.js +78 -0
  83. package/dist/cli.js +4 -0
  84. package/dist/cliApplicationCommands.js +30 -2
  85. package/dist/cliBrowserAdvancedCommands.js +17 -5
  86. package/dist/cliBrowserCommands.js +1 -0
  87. package/dist/cliBrowserScenarioCommands.js +43 -0
  88. package/dist/cliCommandNames.js +9 -0
  89. package/dist/cliJavaScriptRuntimeCommands.js +164 -0
  90. package/dist/cliObservationOptions.js +4 -0
  91. package/dist/cliPolicyCommands.js +1 -0
  92. package/dist/config/environment.js +12 -0
  93. package/dist/config/parseConfig.js +88 -17
  94. package/dist/contracts/analysisSearchContract.js +14 -0
  95. package/dist/contracts/applicationToolContracts.js +86 -2
  96. package/dist/contracts/applicationWorkflowInputContracts.js +18 -0
  97. package/dist/contracts/artifactToolContracts.js +29 -2
  98. package/dist/contracts/browserProviderToolContracts.js +7 -0
  99. package/dist/contracts/browserScenarioToolContracts.js +81 -0
  100. package/dist/contracts/browserToolContracts.js +88 -98
  101. package/dist/contracts/enhancedInputs.js +35 -6
  102. package/dist/contracts/functionInstructionContract.js +8 -0
  103. package/dist/contracts/functionWorkflowToolContracts.js +30 -0
  104. package/dist/contracts/hopperMemoryContracts.js +22 -0
  105. package/dist/contracts/javascriptApplicationWorkflowExamples.js +42 -0
  106. package/dist/contracts/javascriptRuntimeObservationToolContracts.js +58 -0
  107. package/dist/contracts/promptContracts.js +14 -15
  108. package/dist/contracts/reconstructionReadinessExample.js +436 -0
  109. package/dist/contracts/toolContractExamples.js +8 -0
  110. package/dist/contracts/toolContractTypes.js +1 -0
  111. package/dist/contracts/toolContracts.js +34 -25
  112. package/dist/contracts/toolEffects.js +25 -0
  113. package/dist/contracts/toolOutputSchemaGroups.js +120 -30
  114. package/dist/contracts/toolOutputSchemaPrimitives.js +37 -0
  115. package/dist/domain/analysisErrorPresentation.js +8 -2
  116. package/dist/domain/analysisErrorProjection.js +9 -0
  117. package/dist/domain/artifactInspection.js +347 -0
  118. package/dist/domain/browserCaptureComparison.js +82 -0
  119. package/dist/domain/browserObservation.js +8 -1
  120. package/dist/domain/browserObservationErrors.js +1 -0
  121. package/dist/domain/browserObservationSchemas.js +26 -0
  122. package/dist/domain/browserScenario.js +165 -0
  123. package/dist/domain/browserScenarioCapture.js +57 -0
  124. package/dist/domain/browserScenarioCaptureValues.js +204 -0
  125. package/dist/domain/browserScenarioDiff.js +324 -0
  126. package/dist/domain/browserScenarioDiffValues.js +157 -0
  127. package/dist/domain/browserScenarioNormalization.js +45 -0
  128. package/dist/domain/browserScenarioValues.js +372 -0
  129. package/dist/domain/bytecodeProvider.js +179 -0
  130. package/dist/domain/conformancePackage.js +169 -0
  131. package/dist/domain/conformanceReplay.js +104 -0
  132. package/dist/domain/conformanceTrustGate.js +193 -0
  133. package/dist/domain/customProtocolCapture.js +137 -0
  134. package/dist/domain/eventProcessTree.js +214 -0
  135. package/dist/domain/evidenceBundle.js +47 -0
  136. package/dist/domain/hopperStartupFailure.js +1 -1
  137. package/dist/domain/hopperValues.js +14 -1
  138. package/dist/domain/inputIssueProjection.js +7 -1
  139. package/dist/domain/javascriptRuntimeObservation.js +170 -0
  140. package/dist/domain/javascriptRuntimeReconciliationParsing.js +120 -2
  141. package/dist/domain/javascriptRuntimeReconciliationResult.js +3 -3
  142. package/dist/domain/javascriptRuntimeReconciliationRuntime.js +2 -2
  143. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
  144. package/dist/domain/javascriptSemanticAnalysis.js +13 -16
  145. package/dist/domain/javascriptSemanticAsyncEffects.js +253 -0
  146. package/dist/domain/javascriptSemanticChildProcesses.js +237 -0
  147. package/dist/domain/javascriptSemanticDataEffectHelpers.js +125 -0
  148. package/dist/domain/javascriptSemanticDataEffects.js +284 -0
  149. package/dist/domain/javascriptSemanticDerivedAnalysis.js +41 -0
  150. package/dist/domain/javascriptSemanticFingerprints.js +174 -0
  151. package/dist/domain/javascriptSemanticIr.js +21 -1
  152. package/dist/domain/javascriptSemanticObjects.js +115 -0
  153. package/dist/domain/javascriptSemanticPromises.js +290 -0
  154. package/dist/domain/javascriptSemanticResources.js +136 -0
  155. package/dist/domain/javascriptSourceParser.js +15 -0
  156. package/dist/domain/javascriptStaticAnalysis.js +12 -15
  157. package/dist/domain/javascriptStaticAnalysisBundler.js +38 -0
  158. package/dist/domain/javascriptStaticAnalysisCalls.js +23 -1
  159. package/dist/domain/javascriptStaticAnalysisHelpers.js +8 -0
  160. package/dist/domain/mobileApplicationInvestigation.js +159 -0
  161. package/dist/domain/nativeApiBoundary.js +130 -0
  162. package/dist/domain/objcSwiftMetadata.js +150 -0
  163. package/dist/domain/packageAnalysis.js +123 -0
  164. package/dist/domain/peInspection.js +196 -0
  165. package/dist/domain/processCapture.js +8 -2
  166. package/dist/domain/processReactiveScenario.js +1 -0
  167. package/dist/domain/processReactiveTransition.js +9 -4
  168. package/dist/domain/protocolCapture.js +243 -0
  169. package/dist/domain/providerCleanupError.js +11 -0
  170. package/dist/domain/reconstructionObligationLedgerSchemas.js +278 -0
  171. package/dist/domain/reconstructionReadiness.js +121 -0
  172. package/dist/domain/reconstructionReadinessFindingHelpers.js +17 -0
  173. package/dist/domain/reconstructionReadinessIntegrityFindings.js +118 -0
  174. package/dist/domain/reconstructionReadinessJourneyFindings.js +193 -0
  175. package/dist/domain/reconstructionReadinessSchemas.js +240 -0
  176. package/dist/domain/sourceToBundleComparison.js +335 -0
  177. package/dist/domain/sourceToBundleComparisonSchemas.js +133 -0
  178. package/dist/domain/sourceToBundleSignals.js +202 -0
  179. package/dist/domain/webCaptureDiff.js +141 -27
  180. package/dist/domain/webScreenshot.js +1 -1
  181. package/dist/dotnet/ManagedStaticProvider.js +34 -5
  182. package/dist/generatedMcpToolCatalog.js +37 -0
  183. package/dist/generatedPackageMetadata.js +4 -4
  184. package/dist/ghidra/GhidraDefaults.js +1 -1
  185. package/dist/ghidra/GhidraFunctionValues.js +40 -2
  186. package/dist/ghidra/GhidraProviderCapabilities.js +47 -38
  187. package/dist/hopper/HopperCleanup.js +158 -0
  188. package/dist/hopper/HopperClient.js +93 -99
  189. package/dist/hopper/HopperProvider.js +61 -30
  190. package/dist/hopper/HopperRequestQueue.js +215 -0
  191. package/dist/hopper/HopperResponseStream.js +46 -0
  192. package/dist/hopper/protocol.js +63 -20
  193. package/dist/main/transport.js +24 -27
  194. package/dist/main.js +14 -6
  195. package/dist/mcpDoctor.js +27 -4
  196. package/dist/mcpStartupPolicy.js +14 -0
  197. package/dist/process/ProcessCommandIdentity.js +19 -0
  198. package/dist/process/ProcessOwnership.js +11 -8
  199. package/dist/server/DynamicToolAvailability.js +70 -0
  200. package/dist/server/LazyToolCatalog.js +134 -0
  201. package/dist/server/createServer.js +92 -154
  202. package/dist/server/hydrateServerTools.js +191 -0
  203. package/dist/server/lifecycleProgress.js +10 -0
  204. package/dist/server/permissionFailure.js +12 -0
  205. package/dist/server/registerApplicationTools/compareSourceToBundle.js +35 -0
  206. package/dist/server/registerApplicationTools/helpers.js +11 -7
  207. package/dist/server/registerApplicationTools/obligationLedger.js +27 -0
  208. package/dist/server/registerApplicationTools/readiness.js +55 -0
  209. package/dist/server/registerApplicationTools.js +6 -0
  210. package/dist/server/registerArtifactTools.js +9 -1
  211. package/dist/server/registerBrowserScenarioTool.js +25 -0
  212. package/dist/server/registerBrowserTools.js +2 -2
  213. package/dist/server/registerCloseLifecycleTool.js +57 -0
  214. package/dist/server/registerEnhancedTools.js +28 -7
  215. package/dist/server/registerEvidenceResources.js +54 -101
  216. package/dist/server/registerEvidenceTools.js +9 -2
  217. package/dist/server/registerInvestigationTools.js +1 -2
  218. package/dist/server/registerJavaScriptApplicationGraphResource.js +0 -4
  219. package/dist/server/registerJavaScriptRuntimeObservationTools.js +37 -0
  220. package/dist/server/registerReconstructionObligationLedgerResource.js +32 -0
  221. package/dist/server/registerReconstructionReadinessResource.js +32 -0
  222. package/dist/server/registerSessionRecordTools.js +82 -12
  223. package/dist/server/registerSessionStatusTool.js +11 -8
  224. package/dist/server/registerSessionTools.js +32 -58
  225. package/dist/server/sessionAvailabilityPolicy.js +10 -8
  226. package/dist/server/toolRegistrationOptions.js +21 -6
  227. package/dist/server/toolResult.js +12 -0
  228. package/package.json +28 -11
  229. package/scripts/package-runner-bootstrap.mjs +72 -0
  230. package/scripts/rea.mjs +11 -1
  231. package/skills/reverse-engineer-anything/SKILL.md +10 -3
@@ -0,0 +1,55 @@
1
+ import { evaluateReconstructionReadinessValidated, resolveReconstructionReadinessRequest, } from "../../application/ReconstructionReadinessService.js";
2
+ import { applicationToolContract } from "../../contracts/applicationToolContracts.js";
3
+ import { reconstructionReadinessInputSchema } from "../../domain/reconstructionReadinessSchemas.js";
4
+ import { reconstructionReadinessReportSchema } from "../../domain/reconstructionReadinessSchemas.js";
5
+ import { logToolExecution } from "../toolLogging.js";
6
+ import { safeParseToolInput } from "../toolInputValidation.js";
7
+ import { toolRegistrationOptions } from "../toolRegistrationOptions.js";
8
+ import { toCallToolResult } from "../toolResult.js";
9
+ import { recordSources } from "./helpers.js";
10
+ const contract = applicationToolContract("evaluate_reconstruction_readiness");
11
+ /** Register deterministic public-contract reconstruction conformance. */
12
+ export const registerReconstructionReadinessTool = (server, options) => {
13
+ server.registerTool(contract.name, toolRegistrationOptions(contract), async (input) => {
14
+ const parsed = safeParseToolInput(reconstructionReadinessInputSchema, input, contract.name);
15
+ if (!parsed.ok)
16
+ return toCallToolResult(parsed, contract);
17
+ const resolved = resolveReconstructionReadinessRequest(parsed.value);
18
+ if (!resolved.ok)
19
+ return toCallToolResult(resolved, contract);
20
+ const result = await logToolExecution(options.logger, contract.name, () => Promise.resolve(evaluateReconstructionReadinessValidated(resolved.value)));
21
+ if (!result.ok)
22
+ return toCallToolResult(result, contract);
23
+ const recorded = recordSources(options.recordEvidence, resolved.value.evidence_bundle.records);
24
+ if (!recorded.ok)
25
+ return toCallToolResult(recorded, contract);
26
+ const recordedResult = options.recordEvidence?.(result.value);
27
+ if (recordedResult !== undefined && !recordedResult.ok)
28
+ return toCallToolResult(recordedResult, contract);
29
+ const report = reconstructionReadinessReportSchema.parse(result.value.normalized_result);
30
+ const reportUri = `rea://evidence/${result.value.evidence_id}/reconstruction-readiness-report`;
31
+ const projection = {
32
+ schema: report.schema,
33
+ schema_version: report.schema_version,
34
+ report_id: report.report_id,
35
+ source_digest: report.source_digest,
36
+ report_digest: report.report_digest,
37
+ status: report.status,
38
+ summary: report.summary,
39
+ metrics: report.metrics,
40
+ report_resource_uri: reportUri,
41
+ };
42
+ return toCallToolResult({ ok: true, value: result.value }, contract, {
43
+ evidenceResourcesAvailable: recordedResult !== undefined,
44
+ evidenceResultProjection: projection,
45
+ evidenceTextProjection: projection,
46
+ resourceLinks: [
47
+ {
48
+ uri: reportUri,
49
+ name: report.report_id,
50
+ description: "Full deterministic reconstruction readiness report",
51
+ },
52
+ ],
53
+ });
54
+ });
55
+ };
@@ -1,17 +1,23 @@
1
1
  import { registerTraceFeatureTool } from "./registerApplicationTools/traceFeature.js";
2
2
  import { registerTraceJavaScriptSemanticsTool } from "./registerApplicationTools/traceSemantics.js";
3
3
  import { registerCompareApplicationVersionsTool } from "./registerApplicationTools/compareVersions.js";
4
+ import { registerCompareSourceToBundleTool } from "./registerApplicationTools/compareSourceToBundle.js";
4
5
  import { registerCompareJavaScriptExportShapesTool } from "./registerApplicationTools/compareExportShapes.js";
5
6
  import { registerControlledReplayTool } from "./registerApplicationTools/controlledReplay.js";
6
7
  import { registerCharacterizationTools } from "./registerApplicationTools/characterization.js";
7
8
  import { registerCoverageTools } from "./registerApplicationTools/coverage.js";
9
+ import { registerReconstructionObligationLedgerTool } from "./registerApplicationTools/obligationLedger.js";
10
+ import { registerReconstructionReadinessTool } from "./registerApplicationTools/readiness.js";
8
11
  /** Register provider-neutral JavaScript application graph workflows. */
9
12
  export const registerApplicationTools = (server, options) => {
10
13
  registerTraceFeatureTool(server, options);
11
14
  registerTraceJavaScriptSemanticsTool(server, options);
12
15
  registerCompareApplicationVersionsTool(server, options);
16
+ registerCompareSourceToBundleTool(server, options);
13
17
  registerCompareJavaScriptExportShapesTool(server, options);
14
18
  registerControlledReplayTool(server, options);
15
19
  registerCharacterizationTools(server, options);
20
+ registerReconstructionObligationLedgerTool(server, options);
21
+ registerReconstructionReadinessTool(server, options);
16
22
  registerCoverageTools(server, options);
17
23
  };
@@ -1,6 +1,14 @@
1
1
  import { ARTIFACT_TOOL_CONTRACTS } from "../contracts/artifactToolContracts.js";
2
2
  import { registerEvidenceTools } from "./registerEvidenceTools.js";
3
+ import { artifactInspectionResultSchema } from "../domain/artifactInspection.js";
3
4
  /** Register deterministic artifact inventory and safe extraction operations. */
4
5
  export const registerArtifactTools = (server, analysis, options) => {
5
- registerEvidenceTools(server, analysis, ARTIFACT_TOOL_CONTRACTS, options);
6
+ registerEvidenceTools(server, analysis, ARTIFACT_TOOL_CONTRACTS, {
7
+ ...options,
8
+ sourceEvidence: (operation, result) => operation === "inspect_artifact"
9
+ ? artifactInspectionResultSchema
10
+ .parse(result)
11
+ .substeps.map(({ evidence }) => evidence)
12
+ : [],
13
+ });
6
14
  };
@@ -0,0 +1,25 @@
1
+ import { captureBrowserScenario } from "../application/BrowserScenarioCaptureService.js";
2
+ import { BROWSER_SCENARIO_TOOL_CONTRACTS } from "../contracts/browserScenarioToolContracts.js";
3
+ import { browserScenarioSchema } from "../domain/browserScenario.js";
4
+ import { logToolExecution } from "./toolLogging.js";
5
+ import { safeParseToolInput } from "./toolInputValidation.js";
6
+ import { toolRegistrationOptions } from "./toolRegistrationOptions.js";
7
+ import { toCallToolResult } from "./toolResult.js";
8
+ /** Register the controlled browser scenario tool even when policy disables it. */
9
+ export const registerBrowserScenarioTool = (server, options) => {
10
+ const [contract] = BROWSER_SCENARIO_TOOL_CONTRACTS;
11
+ server.registerTool(contract.name, toolRegistrationOptions(contract), async (input, context) => {
12
+ const parsed = safeParseToolInput(browserScenarioSchema, input, contract.name);
13
+ if (!parsed.ok)
14
+ return toCallToolResult(parsed, contract);
15
+ const result = await logToolExecution(options.logger, contract.name, () => captureBrowserScenario(options.provider, options.permissionAuthority, parsed.value, { signal: context.mcpReq.signal }));
16
+ if (!result.ok)
17
+ return toCallToolResult(result, contract);
18
+ const recorded = options.recordEvidence?.(result.value);
19
+ return recorded !== undefined && !recorded.ok
20
+ ? toCallToolResult(recorded, contract)
21
+ : toCallToolResult({ ok: true, value: result.value }, contract, {
22
+ evidenceResourcesAvailable: recorded !== undefined,
23
+ });
24
+ });
25
+ };
@@ -4,7 +4,7 @@ import { inspectWebPageInputSchema, listBrowserTargetsInputSchema, } from "../do
4
4
  import { analyzeWebBundleInputSchema } from "../domain/webBundleAnalysis.js";
5
5
  import { observeWebSessionInputSchema } from "../domain/browserSession.js";
6
6
  import { discoverWebMcpToolsInputSchema } from "../domain/webMcpDiscovery.js";
7
- import { compareWebCapturesInputSchema } from "../domain/webCaptureDiff.js";
7
+ import { browserCaptureComparisonInputSchema } from "../domain/browserCaptureComparison.js";
8
8
  import { captureWebScreenshotInputSchema, compareWebScreenshotsInputSchema, } from "../domain/webScreenshot.js";
9
9
  import { logToolExecution } from "./toolLogging.js";
10
10
  import { toCallToolResult } from "./toolResult.js";
@@ -55,7 +55,7 @@ export const registerBrowserTools = (server, options) => {
55
55
  });
56
56
  registerBrowserTool(server, options, {
57
57
  contract: captureDiffContract,
58
- schema: compareWebCapturesInputSchema,
58
+ schema: browserCaptureComparisonInputSchema,
59
59
  execute: (parsed, _context) => compareWebCaptureEvidence(options.browser, parsed),
60
60
  });
61
61
  registerBrowserTool(server, options, {
@@ -0,0 +1,57 @@
1
+ import { writeAnalysisSnapshot } from "../application/AnalysisSnapshotFiles.js";
2
+ import { closeBinaryInputSchema } from "../contracts/sessionLifecycleInputs.js";
3
+ import { ok } from "../domain/result.js";
4
+ import { reportLifecycleEnd, reportLifecycleStart, } from "./lifecycleProgress.js";
5
+ import { logToolExecution } from "./toolLogging.js";
6
+ import { toCallToolResult } from "./toolResult.js";
7
+ import { mcpProgressReporter } from "./mcpProgress.js";
8
+ import { permissionFailure } from "./permissionFailure.js";
9
+ import { safeParseToolInput } from "./toolInputValidation.js";
10
+ import { toolRegistrationOptions } from "./toolRegistrationOptions.js";
11
+ /** Register provider cleanup and optional pre-close snapshot persistence. */
12
+ export const registerCloseLifecycleTool = ({ server, session, logger, contracts: [, closeContract], snapshotFilePolicy, permissionAuthority, }) => {
13
+ server.registerTool(closeContract.name, toolRegistrationOptions(closeContract), async (input, context) => {
14
+ const parsedInput = safeParseToolInput(closeBinaryInputSchema, input, closeContract.name);
15
+ if (!parsedInput.ok)
16
+ return toCallToolResult(parsedInput, closeContract);
17
+ const parsed = parsedInput.value;
18
+ const progress = mcpProgressReporter(context);
19
+ if (parsed.snapshot_path === undefined) {
20
+ await reportLifecycleStart(progress, closeContract.name);
21
+ const closed = await logToolExecution(logger, closeContract.name, () => session.close({ progress }));
22
+ await reportLifecycleEnd(progress, closeContract.name, closed.ok);
23
+ server.sendToolListChanged();
24
+ return toCallToolResult(closed, closeContract);
25
+ }
26
+ if (permissionAuthority !== undefined) {
27
+ const authorized = await permissionAuthority.authorize({
28
+ capability: "snapshot_write",
29
+ roots: [parsed.snapshot_path],
30
+ executables: [],
31
+ environment_names: [],
32
+ network: "none",
33
+ mount: false,
34
+ operation_identity: `close_binary:snapshot:${parsed.snapshot_path}`,
35
+ }, "write");
36
+ if (!authorized.ok)
37
+ return toCallToolResult(permissionFailure(authorized), closeContract);
38
+ }
39
+ const snapshot = session.exportAnalysisSnapshot();
40
+ if (!snapshot.ok)
41
+ return toCallToolResult(snapshot, closeContract);
42
+ const written = await writeAnalysisSnapshot(snapshot.value, parsed.snapshot_path, parsed.overwrite, snapshotFilePolicy);
43
+ if (!written.ok)
44
+ return toCallToolResult(written, closeContract);
45
+ await reportLifecycleStart(progress, closeContract.name, "snapshot written; closing provider");
46
+ const closed = await logToolExecution(logger, closeContract.name, () => session.close({ progress }));
47
+ await reportLifecycleEnd(progress, closeContract.name, closed.ok);
48
+ server.sendToolListChanged();
49
+ return closed.ok
50
+ ? toCallToolResult(ok({
51
+ path: written.value.path,
52
+ bytes: written.value.bytes,
53
+ entries: snapshot.value.entries.length,
54
+ }), closeContract)
55
+ : toCallToolResult(closed, closeContract);
56
+ });
57
+ };
@@ -12,9 +12,8 @@ import { toolRegistrationOptions } from "./toolRegistrationOptions.js";
12
12
  import { safeParseToolInput } from "./toolInputValidation.js";
13
13
  /** Register composed workflows against the same port as direct bridge tools. */
14
14
  export const registerEnhancedTools = (server, analysis, options) => {
15
- const services = new EnhancedTools(analysis);
16
15
  for (const contract of ENHANCED_TOOL_CONTRACTS) {
17
- registerEnhancedTool(server, services, contract, {
16
+ registerEnhancedTool(server, analysis, contract, {
18
17
  logger: options.logger,
19
18
  activeTarget: options.activeTarget,
20
19
  analysisProfile: options.analysisProfile,
@@ -23,7 +22,7 @@ export const registerEnhancedTools = (server, analysis, options) => {
23
22
  });
24
23
  }
25
24
  };
26
- const registerEnhancedTool = (server, services, contract, registration) => {
25
+ const registerEnhancedTool = (server, analysis, contract, registration) => {
27
26
  const name = enhancedToolNameSchema.parse(contract.name);
28
27
  server.registerTool(name, toolRegistrationOptions(contract), async (input, context) => {
29
28
  const progress = mcpProgressReporter(context);
@@ -38,6 +37,12 @@ const registerEnhancedTool = (server, services, contract, registration) => {
38
37
  return toCallToolResult(validatedCall, contract);
39
38
  const parsedInput = validatedCall.value.input;
40
39
  const parameters = jsonParameters(parsedInput);
40
+ const services = new EnhancedTools({
41
+ execute: (operation, operationParameters, executionOptions) => analysis.execute(operation, operationParameters, {
42
+ ...executionOptions,
43
+ progress,
44
+ }),
45
+ });
41
46
  const result = await logToolExecution(registration.logger, name, () => services.executeValidated(validatedCall.value, context.mcpReq.signal));
42
47
  await progress.report({
43
48
  phase: name,
@@ -92,7 +97,10 @@ const ENHANCED_INPUT_PARSERS = {
92
97
  find_xrefs_to_name: (input) => safeParseToolInput(enhancedInputSchemas.find_xrefs_to_name, input, "find_xrefs_to_name"),
93
98
  binary_overview: (input) => safeParseToolInput(enhancedInputSchemas.binary_overview, input, "binary_overview"),
94
99
  analyze_function: (input) => safeParseToolInput(enhancedInputSchemas.analyze_function, input, "analyze_function"),
100
+ inspect_native_api: (input) => safeParseToolInput(enhancedInputSchemas.inspect_native_api, input, "inspect_native_api"),
95
101
  trace_feature: (input) => safeParseToolInput(enhancedInputSchemas.trace_feature, input, "trace_feature"),
102
+ find_code_for_string: (input) => safeParseToolInput(enhancedInputSchemas.find_code_for_string, input, "find_code_for_string"),
103
+ trace_call_path: (input) => safeParseToolInput(enhancedInputSchemas.trace_call_path, input, "trace_call_path"),
96
104
  };
97
105
  const parseEnhancedCall = (name, input) => {
98
106
  switch (name) {
@@ -114,13 +122,24 @@ const parseEnhancedCall = (name, input) => {
114
122
  return mapEnhancedCall(ENHANCED_INPUT_PARSERS.binary_overview(input), (value) => ({ name, input: value }));
115
123
  case "analyze_function":
116
124
  return mapEnhancedCall(ENHANCED_INPUT_PARSERS.analyze_function(input), (value) => ({ name, input: value }));
125
+ case "inspect_native_api":
126
+ return mapEnhancedCall(ENHANCED_INPUT_PARSERS.inspect_native_api(input), (value) => ({ name, input: value }));
117
127
  case "trace_feature":
118
128
  return mapEnhancedCall(ENHANCED_INPUT_PARSERS.trace_feature(input), (value) => ({ name, input: value }));
129
+ case "find_code_for_string":
130
+ return mapEnhancedCall(ENHANCED_INPUT_PARSERS.find_code_for_string(input), (value) => ({ name, input: value }));
131
+ case "trace_call_path":
132
+ return mapEnhancedCall(ENHANCED_INPUT_PARSERS.trace_call_path(input), (value) => ({ name, input: value }));
119
133
  }
120
134
  };
121
135
  const mapEnhancedCall = (parsed, project) => parsed.ok ? ok(project(parsed.value)) : parsed;
122
136
  const recordWorkflowUnknowns = ({ name, input, result, evidenceId, recordUnknown, }) => {
123
- if (name !== "trace_feature" ||
137
+ if (![
138
+ "trace_feature",
139
+ "find_code_for_string",
140
+ "trace_call_path",
141
+ "inspect_native_api",
142
+ ].includes(name) ||
124
143
  input.unknown_registry_approved !== true ||
125
144
  recordUnknown === undefined ||
126
145
  typeof result !== "object" ||
@@ -135,7 +154,7 @@ const recordWorkflowUnknowns = ({ name, input, result, evidenceId, recordUnknown
135
154
  approved: true,
136
155
  question,
137
156
  severity: "medium",
138
- domain: "control-flow",
157
+ domain: name === "inspect_native_api" ? "native-api" : "control-flow",
139
158
  supporting_evidence_ids: [evidenceId],
140
159
  contradicting_evidence_ids: [],
141
160
  required_authority: "shipped-artifact",
@@ -143,8 +162,10 @@ const recordWorkflowUnknowns = ({ name, input, result, evidenceId, recordUnknown
143
162
  required_environment: null,
144
163
  recommended_probes: [
145
164
  {
146
- operation: "trace_feature",
147
- rationale: "Continue with a larger bounded budget.",
165
+ operation: name,
166
+ rationale: name === "inspect_native_api"
167
+ ? "Confirm the unsupported boundary with a capable provider or ABI probe."
168
+ : "Continue with a larger bounded budget.",
148
169
  },
149
170
  ],
150
171
  relationships: [],
@@ -2,33 +2,31 @@ import { ResourceNotFoundError, ResourceTemplate, } from "@modelcontextprotocol/
2
2
  import { createHash } from "node:crypto";
3
3
  import canonicalize from "canonicalize";
4
4
  import { registerJavaScriptApplicationGraphResource } from "./registerJavaScriptApplicationGraphResource.js";
5
- const evidenceUri = (evidenceId) => `rea://evidence/${evidenceId}`;
5
+ import { registerReconstructionObligationLedgerResource } from "./registerReconstructionObligationLedgerResource.js";
6
+ import { registerReconstructionReadinessResource } from "./registerReconstructionReadinessResource.js";
6
7
  /** Expose immutable session-owned Evidence v2 records as MCP resources. */
7
8
  export const registerEvidenceResources = (server, session) => {
8
9
  registerReconstructionCoverageResource(server, session);
9
10
  registerInvestigationWorkspaceResource(server, session);
10
11
  registerSessionEvidenceResource(server, session);
11
- registerActiveResidualUnknownsResource(server, session);
12
+ registerEvidenceBundleResource(server, session);
12
13
  registerAnalysisSnapshotResource(server, session);
13
14
  registerArtifactPageResource(server, session);
14
15
  registerFunctionDossierResource(server, session);
15
16
  registerEvidenceSectionResource(server, session);
17
+ registerReconstructionObligationLedgerResource(server, session);
18
+ registerReconstructionReadinessResource(server, session);
16
19
  registerJavaScriptApplicationGraphResource(server, session);
17
20
  registerResidualUnknownResource(server, session);
21
+ session.onAnalysisSnapshotChanged?.(() => {
22
+ void server.server
23
+ .sendResourceUpdated({ uri: "rea://snapshot/current" })
24
+ .catch(() => undefined);
25
+ });
18
26
  };
19
27
  const registerReconstructionCoverageResource = (server, session) => {
20
28
  server.registerResource("reconstruction-coverage-revision", new ResourceTemplate("rea://reconstruction-coverage/{workspaceId}/revision/{revision}", {
21
- list: () => ({
22
- resources: session
23
- .reconstructionCoverageWorkspaces()
24
- .map((workspace) => ({
25
- uri: coverageWorkspaceUri(workspace.workspace_id, workspace.revision),
26
- name: `${workspace.workspace_id} revision ${String(workspace.revision)}`,
27
- title: `${workspace.name} coverage revision ${String(workspace.revision)}`,
28
- description: "Immutable evidence-backed reconstruction coverage workspace revision.",
29
- mimeType: "application/json",
30
- })),
31
- }),
29
+ list: undefined,
32
30
  }), {
33
31
  title: "Reconstruction coverage revision",
34
32
  description: "Canonical CAS-linked surfaces, owners, claims, verifiers, evidence, and completion boundaries.",
@@ -46,27 +44,7 @@ const registerReconstructionCoverageResource = (server, session) => {
46
44
  };
47
45
  const registerInvestigationWorkspaceResource = (server, session) => {
48
46
  server.registerResource("investigation-workspace-revision", new ResourceTemplate("rea://workspace/{workspaceId}/revision/{revision}", {
49
- list: () => ({
50
- resources: session.investigationWorkspaces().map((workspace) => ({
51
- uri: workspaceUri(workspace.workspace_id, workspace.revision),
52
- name: `${workspace.workspace_id} revision ${String(workspace.revision)}`,
53
- title: `${workspace.name} revision ${String(workspace.revision)}`,
54
- description: "Immutable CAS-linked investigation workspace revision.",
55
- mimeType: "application/json",
56
- })),
57
- }),
58
- complete: {
59
- workspaceId: (prefix) => [
60
- ...new Set(session
61
- .investigationWorkspaces()
62
- .map(({ workspace_id }) => workspace_id)),
63
- ].filter((workspaceId) => workspaceId.startsWith(prefix)),
64
- revision: (prefix, context) => session
65
- .investigationWorkspaces()
66
- .filter(({ workspace_id }) => context?.arguments?.workspaceId === workspace_id)
67
- .map(({ revision }) => String(revision))
68
- .filter((revision) => revision.startsWith(prefix)),
69
- },
47
+ list: undefined,
70
48
  }), {
71
49
  title: "Investigation workspace revision",
72
50
  description: "Immutable session-retained workspace with CAS linkage.",
@@ -84,21 +62,7 @@ const registerInvestigationWorkspaceResource = (server, session) => {
84
62
  };
85
63
  const registerSessionEvidenceResource = (server, session) => {
86
64
  server.registerResource("session-evidence", new ResourceTemplate("rea://evidence/{evidenceId}", {
87
- list: () => ({
88
- resources: session.exportEvidenceBundle().records.map((evidence) => ({
89
- uri: evidenceUri(evidence.evidence_id),
90
- name: evidence.evidence_id,
91
- title: `${evidence.operation} evidence`,
92
- description: `Session-owned Evidence v2 record for ${evidence.operation}.`,
93
- mimeType: "application/json",
94
- })),
95
- }),
96
- complete: {
97
- evidenceId: (prefix) => session
98
- .exportEvidenceBundle()
99
- .records.map(({ evidence_id }) => evidence_id)
100
- .filter((evidenceId) => evidenceId.startsWith(prefix)),
101
- },
65
+ list: undefined,
102
66
  }), {
103
67
  title: "Session evidence",
104
68
  description: "Immutable Evidence v2 records owned by this REA session.",
@@ -121,42 +85,52 @@ const registerSessionEvidenceResource = (server, session) => {
121
85
  };
122
86
  });
123
87
  };
124
- const registerActiveResidualUnknownsResource = (server, session) => {
125
- server.registerResource("active-residual-unknowns", "rea://unknowns/active", {
126
- title: "Active residual unknowns",
127
- description: "Current unresolved session-owned residual unknown heads.",
88
+ const registerEvidenceBundleResource = (server, session) => {
89
+ server.registerResource("evidence-bundle", new ResourceTemplate("rea://evidence-bundle/{bundleDigest}", {
90
+ list: undefined,
91
+ }), {
92
+ title: "Evidence bundle",
93
+ description: "Immutable session-retained canonical Evidence v2 bundle.",
128
94
  mimeType: "application/json",
129
- }, (uri) => jsonResource(uri.href, session.listUnknowns().filter(({ status }) => status !== "resolved")));
95
+ }, (uri, variables) => {
96
+ const digest = stringVariable(variables.bundleDigest, uri.href);
97
+ if (!/^[a-f0-9]{64}$/u.test(digest))
98
+ throw new ResourceNotFoundError(uri.href);
99
+ const text = session.retainedEvidenceBundle(digest);
100
+ if (text === undefined)
101
+ throw new ResourceNotFoundError(uri.href);
102
+ return {
103
+ contents: [
104
+ {
105
+ uri: uri.href,
106
+ mimeType: "application/json",
107
+ text,
108
+ },
109
+ ],
110
+ };
111
+ });
130
112
  };
131
113
  const registerAnalysisSnapshotResource = (server, session) => {
132
- server.registerResource("analysis-snapshot", new ResourceTemplate("rea://snapshot/{snapshotDigest}", {
133
- list: () => {
134
- const snapshot = session.exportAnalysisSnapshot();
135
- if (!snapshot.ok)
136
- return { resources: [] };
137
- const digest = contentDigest(snapshot.value);
138
- return {
139
- resources: [
140
- {
141
- uri: `rea://snapshot/${digest}`,
142
- name: digest,
143
- title: "Current analysis snapshot",
144
- description: "Immutable projection of the current target cache.",
145
- mimeType: "application/json",
146
- },
147
- ],
148
- };
149
- },
150
- }), {
114
+ server.registerResource("analysis-snapshot", "rea://snapshot/current", {
151
115
  title: "Analysis snapshot",
152
- description: "Current provider-neutral analysis snapshot by content digest.",
116
+ description: "Mutable provider-neutral analysis snapshot for the current native target.",
153
117
  mimeType: "application/json",
154
- }, (uri, variables) => {
155
- const requested = stringVariable(variables.snapshotDigest, uri.href);
118
+ }, (uri) => {
156
119
  const snapshot = session.exportAnalysisSnapshot();
157
- if (!snapshot.ok || contentDigest(snapshot.value) !== requested)
158
- throw new ResourceNotFoundError(uri.href);
159
- return jsonResource(uri.href, snapshot.value);
120
+ if (!snapshot.ok)
121
+ return jsonResource(uri.href, {
122
+ state: "unavailable",
123
+ reason: snapshot.error.message,
124
+ remediation: "Open a native target with a concrete analysis profile. After metadata mutation, call open_binary again for the current target to begin a fresh cache.",
125
+ });
126
+ return jsonResource(uri.href, {
127
+ state: "available",
128
+ target: snapshot.value.target,
129
+ profile: snapshot.value.binding,
130
+ content_digest: contentDigest(snapshot.value),
131
+ entry_count: snapshot.value.entries.length,
132
+ snapshot: snapshot.value,
133
+ });
160
134
  });
161
135
  };
162
136
  const registerArtifactPageResource = (server, session) => {
@@ -217,7 +191,6 @@ const registerEvidenceSectionResource = (server, session) => {
217
191
  server.registerResource("evidence-section", new ResourceTemplate("rea://evidence/{evidenceId}/section/{section}", {
218
192
  list: undefined,
219
193
  complete: {
220
- evidenceId: (prefix) => evidenceIds(session, prefix),
221
194
  section: (prefix) => EVIDENCE_SECTIONS.filter((section) => section.startsWith(prefix)),
222
195
  },
223
196
  }), {
@@ -247,21 +220,7 @@ const registerEvidenceSectionResource = (server, session) => {
247
220
  };
248
221
  const registerResidualUnknownResource = (server, session) => {
249
222
  server.registerResource("residual-unknown", new ResourceTemplate("rea://unknown/{unknownId}", {
250
- list: () => ({
251
- resources: session.listUnknowns().map((unknown) => ({
252
- uri: `rea://unknown/${unknown.unknown_id}`,
253
- name: unknown.unknown_id,
254
- title: unknown.question,
255
- description: `Current ${unknown.status} residual unknown revision.`,
256
- mimeType: "application/json",
257
- })),
258
- }),
259
- complete: {
260
- unknownId: (prefix) => session
261
- .listUnknowns()
262
- .map(({ unknown_id }) => unknown_id)
263
- .filter((unknownId) => unknownId.startsWith(prefix)),
264
- },
223
+ list: undefined,
265
224
  }), {
266
225
  title: "Residual unknown",
267
226
  description: "Current session-owned residual unknown head.",
@@ -279,8 +238,6 @@ const registerResidualUnknownResource = (server, session) => {
279
238
  return jsonResource(uri.href, { current: unknown, history });
280
239
  });
281
240
  };
282
- const coverageWorkspaceUri = (workspaceId, revision) => `rea://reconstruction-coverage/${workspaceId}/revision/${String(revision)}`;
283
- const workspaceUri = (workspaceId, revision) => `rea://workspace/${workspaceId}/revision/${String(revision)}`;
284
241
  const EVIDENCE_SECTIONS = [
285
242
  "result",
286
243
  "terminal",
@@ -291,10 +248,6 @@ const EVIDENCE_SECTIONS = [
291
248
  "occurrences",
292
249
  "edges",
293
250
  ];
294
- const evidenceIds = (session, prefix) => session
295
- .exportEvidenceBundle()
296
- .records.map(({ evidence_id }) => evidence_id)
297
- .filter((evidenceId) => evidenceId.startsWith(prefix));
298
251
  const stringVariable = (value, uri) => {
299
252
  if (typeof value !== "string")
300
253
  throw new ResourceNotFoundError(uri);
@@ -47,6 +47,7 @@ export const registerEvidenceTools = (server, analysis, contracts, options) => {
47
47
  });
48
48
  if (!execution.ok)
49
49
  return toCallToolResult(execution, contract);
50
+ const sourceEvidence = options.sourceEvidence?.(contract.name, execution.value.result) ?? [];
50
51
  const evidence = createEvidence(execution.value.subject ?? options.activeTarget?.(), execution.value.provider, {
51
52
  operation: contract.name,
52
53
  parameters,
@@ -54,7 +55,13 @@ export const registerEvidenceTools = (server, analysis, contracts, options) => {
54
55
  rawResult: execution.value.rawResult,
55
56
  limitations: execution.value.limitations,
56
57
  locations: execution.value.locations,
58
+ evidenceLinks: sourceEvidence.map(({ evidence_id: id }) => id),
57
59
  });
60
+ for (const source of sourceEvidence) {
61
+ const sourceRecorded = options.recordEvidence?.(source);
62
+ if (sourceRecorded !== undefined && !sourceRecorded.ok)
63
+ return toCallToolResult(sourceRecorded, contract);
64
+ }
58
65
  const recorded = options.recordEvidence?.(evidence);
59
66
  return recorded !== undefined && !recorded.ok
60
67
  ? toCallToolResult(recorded, contract)
@@ -76,7 +83,7 @@ const permissionRequest = (operation, parameters) => {
76
83
  mount: false,
77
84
  operation_identity: `extract_artifact:${parameters.output_root}`,
78
85
  };
79
- if (operation === "inventory_artifact" &&
86
+ if (["inventory_artifact", "inspect_artifact"].includes(operation) &&
80
87
  parameters.native_mount_approved === true)
81
88
  return {
82
89
  capability: "native_mount",
@@ -85,7 +92,7 @@ const permissionRequest = (operation, parameters) => {
85
92
  environment_names: [],
86
93
  network: "none",
87
94
  mount: true,
88
- operation_identity: "inventory_artifact:native_mount",
95
+ operation_identity: `${operation}:native_mount`,
89
96
  };
90
97
  return undefined;
91
98
  };
@@ -114,8 +114,7 @@ const runAutomaticInvestigation = async (input) => {
114
114
  if (!investigated.ok)
115
115
  return toCallToolResult(investigated, contract);
116
116
  const workspace = investigated.value.workspace;
117
- if (session.retainInvestigationWorkspace(workspace) === "added")
118
- input.server.sendResourceListChanged();
117
+ session.retainInvestigationWorkspace(workspace);
119
118
  const result = changedBehaviorResultSchema.parse(investigated.value.evidence.normalized_result);
120
119
  const toolResult = toCallToolResult(recordWorkflowEvidence(session, investigated.value.evidence, input.unknownRegistryApproved, isIncomplete(result.behavior_status), {
121
120
  question: `Automatic changed behavior run ${result.investigation_run?.run_id ?? "unknown"} remains ${result.behavior_status}`,
@@ -5,10 +5,6 @@ export const registerJavaScriptApplicationGraphResource = (server, session) => {
5
5
  server.registerResource("javascript-application-graph-page", new ResourceTemplate("rea://evidence/{evidenceId}/application-graph/{collection}/offset/{offset}/limit/{limit}", {
6
6
  list: undefined,
7
7
  complete: {
8
- evidenceId: (prefix) => session
9
- .exportEvidenceBundle()
10
- .records.map(({ evidence_id }) => evidence_id)
11
- .filter((evidenceId) => evidenceId.startsWith(prefix)),
12
8
  collection: (prefix) => ["nodes", "edges"].filter((name) => name.startsWith(prefix)),
13
9
  },
14
10
  }), {
@@ -0,0 +1,37 @@
1
+ import { listJavaScriptRuntimeTargets, observeJavaScriptRuntime, } from "../application/JavaScriptRuntimeObservationService.js";
2
+ import { JAVASCRIPT_RUNTIME_OBSERVATION_TOOL_CONTRACTS } from "../contracts/javascriptRuntimeObservationToolContracts.js";
3
+ import { listJavaScriptRuntimeTargetsInputSchema, observeJavaScriptRuntimeInputSchema, } from "../domain/javascriptRuntimeObservation.js";
4
+ import { logToolExecution } from "./toolLogging.js";
5
+ import { safeParseToolInput } from "./toolInputValidation.js";
6
+ import { toolRegistrationOptions } from "./toolRegistrationOptions.js";
7
+ import { toCallToolResult } from "./toolResult.js";
8
+ /** Register passive Inspector tools even when policy keeps them unavailable. */
9
+ export const registerJavaScriptRuntimeObservationTools = (server, options) => {
10
+ const [listContract, observeContract] = JAVASCRIPT_RUNTIME_OBSERVATION_TOOL_CONTRACTS;
11
+ registerRuntimeTool(server, options, {
12
+ contract: listContract,
13
+ schema: listJavaScriptRuntimeTargetsInputSchema,
14
+ execute: (parsed, signal) => listJavaScriptRuntimeTargets(options.runtime, options.permissionAuthority, parsed, { signal }),
15
+ });
16
+ registerRuntimeTool(server, options, {
17
+ contract: observeContract,
18
+ schema: observeJavaScriptRuntimeInputSchema,
19
+ execute: (parsed, signal) => observeJavaScriptRuntime(options.runtime, options.permissionAuthority, parsed, { signal }),
20
+ });
21
+ };
22
+ const registerRuntimeTool = (server, options, spec) => {
23
+ server.registerTool(spec.contract.name, toolRegistrationOptions(spec.contract), async (input, context) => {
24
+ const parsed = safeParseToolInput(spec.schema, input, spec.contract.name);
25
+ if (!parsed.ok)
26
+ return toCallToolResult(parsed, spec.contract);
27
+ const result = await logToolExecution(options.logger, spec.contract.name, () => spec.execute(parsed.value, context.mcpReq.signal));
28
+ if (!result.ok)
29
+ return toCallToolResult(result, spec.contract);
30
+ const recorded = options.recordEvidence?.(result.value);
31
+ return recorded !== undefined && !recorded.ok
32
+ ? toCallToolResult(recorded, spec.contract)
33
+ : toCallToolResult({ ok: true, value: result.value }, spec.contract, {
34
+ evidenceResourcesAvailable: recorded !== undefined,
35
+ });
36
+ });
37
+ };