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.
- package/README.md +103 -38
- package/bridge/ghidra/ReaGhidraBridge.java +96 -11
- package/dist/application/AndroidApplicationService.js +17 -0
- package/dist/application/AppleApplicationService.js +17 -0
- package/dist/application/ArtifactExtraction.js +1 -1
- package/dist/application/ArtifactInventory/classify.js +42 -0
- package/dist/application/ArtifactInventory/hash.js +43 -0
- package/dist/application/ArtifactInventory/reader.js +41 -0
- package/dist/application/ArtifactInventory/scanCanonical.js +155 -0
- package/dist/application/ArtifactInventory/scanReader.js +124 -0
- package/dist/application/ArtifactInventory/types.js +10 -0
- package/dist/application/ArtifactInventory.js +9 -351
- package/dist/application/AuthorizedArtifactInventory.js +2 -2
- package/dist/application/BinarySession.js +47 -270
- package/dist/application/BinarySessionExecution.js +28 -0
- package/dist/application/BinarySessionOpen.js +39 -0
- package/dist/application/BinarySessionRecords.js +149 -0
- package/dist/application/BinarySessionStatus.js +75 -0
- package/dist/application/CapabilityInventory.js +24 -2
- package/dist/application/ClientRegistrationStatus.js +11 -4
- package/dist/application/CrossVersionInventory.js +8 -2
- package/dist/application/CrossVersionInvestigation.js +1 -23
- package/dist/application/CrossVersionInvestigationCollections.js +23 -0
- package/dist/application/DirectAnalysis.js +47 -44
- package/dist/application/Doctor.js +156 -238
- package/dist/application/DoctorDiagnostics.js +180 -0
- package/dist/application/ElectronBoundaryAnalysis.js +23 -7
- package/dist/application/ElectronBoundaryGraphWindows.js +32 -8
- package/dist/application/EnhancedToolPagination.js +22 -0
- package/dist/application/EnhancedToolTypes.js +4 -0
- package/dist/application/EnhancedTools.js +20 -37
- package/dist/application/InstrumentedJavaScriptReplayHost.js +36 -0
- package/dist/application/InventoryProjectionEvidence.js +41 -0
- package/dist/application/InvestigationProviders.js +12 -0
- package/dist/application/InvestigationWorkspaceStore.js +24 -10
- package/dist/application/JavaScriptArtifactAnalysis.js +45 -6
- package/dist/application/JavaScriptArtifactFiles.js +6 -2
- package/dist/application/JavaScriptArtifactGraphBuilder.js +23 -1
- package/dist/application/JavaScriptArtifactGraphBundlers.js +225 -0
- package/dist/application/JavaScriptArtifactGraphContext.js +37 -36
- package/dist/application/JavaScriptArtifactGraphDocuments.js +27 -4
- package/dist/application/JavaScriptArtifactGraphFindings.js +54 -8
- package/dist/application/JavaScriptArtifactGraphStructure.js +29 -101
- package/dist/application/JavaScriptArtifactPathResolution.js +269 -0
- package/dist/application/JavaScriptArtifactReconstruction.js +1 -1
- package/dist/application/JavaScriptJsonModules.js +39 -0
- package/dist/application/JavaScriptModuleRelationships.js +262 -0
- package/dist/application/JavaScriptReplayPermission.js +16 -0
- package/dist/application/JavaScriptReplayService.js +182 -156
- package/dist/application/LinuxHopper.js +10 -0
- package/dist/application/MacHopper.js +22 -11
- package/dist/application/NodeRuntimeCharacterizationService.js +196 -0
- package/dist/application/PermissionAuthority.js +106 -63
- package/dist/application/ProcessCaptureCapability.js +1 -1
- package/dist/application/ProcessCapturePermission.js +13 -0
- package/dist/application/ProcessCli.js +2 -12
- package/dist/application/ProcessHarness.js +1 -1
- package/dist/application/ProcessPairedExperiment.js +72 -0
- package/dist/application/ProjectPermissionStore.js +48 -9
- package/dist/application/RealHopperAssertions.js +76 -0
- package/dist/application/ReconstructionCoverageService.js +69 -0
- package/dist/application/ReconstructionCoverageWorkspaceStore.js +31 -0
- package/dist/application/RuntimeExecutableDiagnostics.js +172 -0
- package/dist/application/Setup.js +148 -260
- package/dist/application/SetupClientConfiguration.js +224 -0
- package/dist/application/SetupClients.js +24 -2
- package/dist/application/SetupPlan.js +124 -12
- package/dist/application/SetupSkill.js +54 -36
- package/dist/application/SupportedClients.js +1 -0
- package/dist/application/Uninstall.js +12 -3
- package/dist/application/Upgrade.js +16 -1
- package/dist/application/WindowsCapabilities.js +86 -0
- package/dist/artifacts/AsarArtifactReader.js +11 -0
- package/dist/browser/BrowserProcessStartup.js +88 -0
- package/dist/browser/CdpCaptureDocuments.js +12 -8
- package/dist/browser/CdpCaptureEventBodyShapes.js +75 -0
- package/dist/browser/CdpCaptureEventHandlers.js +336 -0
- package/dist/browser/CdpCaptureEventHelpers.js +71 -0
- package/dist/browser/CdpCaptureEventState.js +1 -0
- package/dist/browser/CdpCaptureEventTypes.js +1 -0
- package/dist/browser/CdpCaptureEvents.js +29 -496
- package/dist/browser/CdpObservationSession.js +51 -8
- package/dist/browser/CdpPageCapture.js +12 -133
- package/dist/browser/CdpPageCaptureScripts.js +97 -0
- package/dist/browser/CdpPageCaptureWorkers.js +46 -0
- package/dist/browser/CdpWebMcpDiscovery.js +38 -14
- package/dist/browser/PngVisualDiff.js +9 -2
- package/dist/catalogIdentity.js +4 -0
- package/dist/cli/artifactCommands.js +82 -0
- package/dist/cli/coreAnalysisCommands.js +232 -0
- package/dist/cli/managedCommands.js +397 -0
- package/dist/cli/managedProjectGraphCommand.js +24 -0
- package/dist/cli/options.js +9 -0
- package/dist/cli/setupCommands.js +113 -0
- package/dist/cli/types.js +1 -0
- package/dist/cli/utilityCommands.js +122 -0
- package/dist/cli.js +10 -768
- package/dist/cliApplicationCommands.js +118 -4
- package/dist/cliBrowserAdvancedCommands.js +73 -16
- package/dist/cliBrowserCommands.js +39 -115
- package/dist/cliCommandNames.js +4 -0
- package/dist/cliElectronCommands.js +33 -62
- package/dist/cliEvidenceCommands.js +13 -2
- package/dist/cliInvestigationCommands.js +53 -10
- package/dist/cliObservationOptions.js +137 -0
- package/dist/cliPolicyCommands.js +80 -46
- package/dist/cliSetup.js +306 -0
- package/dist/config/environment.js +107 -0
- package/dist/config/parseConfig.js +228 -0
- package/dist/config/parsers.js +68 -0
- package/dist/config/permissions.js +30 -0
- package/dist/config/types.js +1 -0
- package/dist/config.js +1 -375
- package/dist/contracts/applicationToolContracts.js +134 -0
- package/dist/contracts/electronToolContracts.js +51 -3
- package/dist/contracts/managedToolContracts.js +8 -3
- package/dist/contracts/managedWorkflowToolContracts.js +3 -3
- package/dist/contracts/providerSelection.js +2 -0
- package/dist/contracts/sessionStatusContract.js +26 -0
- package/dist/contracts/toolContractTypes.js +12 -1
- package/dist/contracts/toolContracts.js +5 -12
- package/dist/contracts/toolEffects.js +14 -0
- package/dist/contracts/toolOutputSchemaGroups.js +274 -0
- package/dist/contracts/toolOutputSchemaPrimitives.js +328 -0
- package/dist/contracts/toolOutputSchemas.js +2 -550
- package/dist/domain/analysisErrorPresentation.js +234 -0
- package/dist/domain/analysisErrorProjection.js +284 -0
- package/dist/domain/androidApplication.js +206 -0
- package/dist/domain/appleApplication.js +221 -0
- package/dist/domain/artifactComparison.js +34 -15
- package/dist/domain/binaryTarget.js +87 -37
- package/dist/domain/boundedCartesianProjection.js +15 -0
- package/dist/domain/browserObservation.js +1 -285
- package/dist/domain/browserObservationSchemas.js +286 -0
- package/dist/domain/electronStaticAnalysisBrowser.js +14 -2
- package/dist/domain/errors.js +4 -486
- package/dist/domain/functionComparison.js +4 -165
- package/dist/domain/functionComparisonDimensions.js +164 -0
- package/dist/domain/javascriptApplicationVersionItems.js +18 -6
- package/dist/domain/javascriptApplicationVersionKeys.js +8 -8
- package/dist/domain/javascriptExportInstrumentation.js +97 -0
- package/dist/domain/javascriptFeatureTraversal.js +19 -7
- package/dist/domain/javascriptRuntimeStaticCandidates.js +3 -1
- package/dist/domain/javascriptSemanticAnalysis.js +386 -0
- package/dist/domain/javascriptSemanticIr.js +30 -0
- package/dist/domain/javascriptSemanticProjection.js +366 -0
- package/dist/domain/javascriptSemanticState.js +40 -0
- package/dist/domain/javascriptSemanticTraversal.js +22 -0
- package/dist/domain/javascriptSemanticValues.js +352 -0
- package/dist/domain/javascriptStaticAnalysis.js +5 -221
- package/dist/domain/javascriptStaticAnalysisBundler.js +209 -0
- package/dist/domain/javascriptStaticAnalysisCalls.js +180 -0
- package/dist/domain/javascriptStaticAnalysisHelpers.js +71 -2
- package/dist/domain/knownPageCoverage.js +21 -0
- package/dist/domain/managedApplicationGraph.js +14 -364
- package/dist/domain/managedApplicationGraphCoverage.js +170 -0
- package/dist/domain/managedApplicationGraphNodeCoverage.js +6 -0
- package/dist/domain/managedApplicationGraphNodes.js +336 -0
- package/dist/domain/managedArtifact.js +16 -8
- package/dist/domain/managedMemberComparison.js +37 -391
- package/dist/domain/managedMemberComparisonCoverage.js +72 -0
- package/dist/domain/managedMemberComparisonMatch.js +356 -0
- package/dist/domain/managedNativeVerification.js +27 -389
- package/dist/domain/managedNativeVerificationMatch.js +272 -0
- package/dist/domain/managedNativeVerificationSchemas.js +141 -0
- package/dist/domain/managedReconstruction.js +82 -69
- package/dist/domain/managedRuntimeCorrelation.js +12 -3
- package/dist/domain/nodeRuntimeCharacterization.js +66 -0
- package/dist/domain/permissionPolicy.js +2 -0
- package/dist/domain/processComparison.js +19 -0
- package/dist/domain/processPairedExperiment.js +128 -0
- package/dist/domain/reconstructionCoverage.js +387 -0
- package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
- package/dist/domain/reconstructionVerificationSchemas.js +8 -0
- package/dist/domain/replayMachine.js +316 -0
- package/dist/domain/replayMachineRuntime.js +215 -0
- package/dist/domain/runtimeCharacterization.js +85 -0
- package/dist/domain/runtimeIdentification.js +210 -0
- package/dist/domain/webBundleAnalyzer.js +3 -409
- package/dist/domain/webBundleAnalyzerAst.js +77 -0
- package/dist/domain/webBundleAnalyzerInspection.js +307 -0
- package/dist/domain/webBundleAnalyzerResult.js +120 -0
- package/dist/dotnet/ManagedArtifactInspector.js +50 -29
- package/dist/dotnet/ManagedMemberInspector.js +51 -785
- package/dist/dotnet/ManagedMemberInspectorCore.js +297 -0
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +427 -0
- package/dist/dotnet/ManagedMemberRows.js +120 -0
- package/dist/dotnet/ManagedMetadataInventory.js +42 -306
- package/dist/dotnet/ManagedMetadataInventoryRows.js +292 -0
- package/dist/dotnet/ManagedMetadataLayout.js +48 -111
- package/dist/dotnet/ManagedMetadataRowSizes.js +54 -0
- package/dist/dotnet/ManagedMethodBodyReader.js +143 -0
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +311 -0
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +102 -350
- package/dist/dotnet/ManagedPeReader.js +59 -28
- package/dist/evaluation/CodexAgentEval.js +132 -0
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraClient.js +76 -91
- package/dist/ghidra/GhidraClientStartup.js +29 -0
- package/dist/ghidra/GhidraClientWire.js +34 -0
- package/dist/ghidra/GhidraDefaults.js +1 -1
- package/dist/ghidra/GhidraDiagnostics.js +6 -1
- package/dist/ghidra/GhidraInstallation.js +20 -15
- package/dist/ghidra/GhidraLauncher.js +93 -29
- package/dist/ghidra/GhidraProvider.js +61 -161
- package/dist/ghidra/GhidraProviderCapabilities.js +173 -0
- package/dist/ghidra/GhidraSessionValues.js +2 -0
- package/dist/ghidra/GhidraSocketConnection.js +44 -7
- package/dist/ghidra/GhidraTargetSnapshot.js +30 -0
- package/dist/ghidra/GhidraTransport.js +71 -0
- package/dist/identity.js +4 -2
- package/dist/main/messages.js +5 -0
- package/dist/main/reload.js +49 -0
- package/dist/main/shutdown.js +25 -0
- package/dist/main/startup.js +14 -0
- package/dist/main/state.js +26 -0
- package/dist/main/transport.js +61 -0
- package/dist/main/types.js +1 -0
- package/dist/main.js +35 -146
- package/dist/process/PrivateRuntimeRoot.js +3 -2
- package/dist/process/ProcessOwnership.js +35 -0
- package/dist/process/ProviderProcess.js +2 -0
- package/dist/replay/JavaScriptReplayWorker.js +64 -50
- package/dist/replay/LinuxJavaScriptReplayRunner.js +173 -390
- package/dist/replay/LinuxJavaScriptReplaySandbox.js +140 -0
- package/dist/replay/ReplayOutcome.js +95 -0
- package/dist/replay/ReplayProcessLifecycle.js +71 -0
- package/dist/server/ProcessCaptureElicitation.js +157 -0
- package/dist/server/createServer.js +124 -56
- package/dist/server/javascriptApplicationResult.js +85 -0
- package/dist/server/registerApplicationTools/characterization.js +57 -0
- package/dist/server/registerApplicationTools/compareVersions.js +34 -0
- package/dist/server/registerApplicationTools/controlledReplay.js +38 -0
- package/dist/server/registerApplicationTools/coverage.js +84 -0
- package/dist/server/registerApplicationTools/helpers.js +42 -0
- package/dist/server/registerApplicationTools/traceFeature.js +26 -0
- package/dist/server/registerApplicationTools/types.js +1 -0
- package/dist/server/registerApplicationTools.js +10 -112
- package/dist/server/registerBrowserTools.js +59 -83
- package/dist/server/registerElectronTools.js +48 -49
- package/dist/server/registerEnhancedTools.js +34 -42
- package/dist/server/registerEvidenceResources.js +56 -0
- package/dist/server/registerInvestigationTools/helpers.js +74 -0
- package/dist/server/registerInvestigationTools/types.js +1 -0
- package/dist/server/registerInvestigationTools.js +83 -116
- package/dist/server/registerJavaScriptApplicationGraphResource.js +69 -0
- package/dist/server/registerManagedTools.js +18 -1
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +65 -0
- package/dist/server/registerManagedWorkflowTools/contract.js +8 -0
- package/dist/server/registerManagedWorkflowTools/evidence.js +43 -0
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +39 -0
- package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +39 -0
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +52 -0
- package/dist/server/registerManagedWorkflowTools/types.js +1 -0
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +75 -0
- package/dist/server/registerManagedWorkflowTools.js +10 -274
- package/dist/server/registerOfficialTools.js +73 -59
- package/dist/server/registerSessionRecordTools.js +137 -0
- package/dist/server/registerSessionStatusTool.js +97 -26
- package/dist/server/registerSessionTools.js +60 -164
- package/dist/server/sessionAvailabilityPolicy.js +10 -0
- package/dist/server/toolRegistrationOptions.js +101 -3
- package/dist/server/toolResult.js +15 -4
- package/package.json +11 -11
- package/skills/reverse-engineer-anything/SKILL.md +76 -0
- package/skills/reverse-engineer-anything/references/controlled-replay.md +12 -0
- package/skills/reverse-engineer-anything/references/evidence-workflows.md +33 -0
- package/skills/reverse-engineer-anything/references/javascript-applications.md +25 -0
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +36 -0
- package/skills/reverse-engineer-anything/references/runtime-observation.md +24 -0
- package/scripts/prepare-node-pty.mjs +0 -35
- package/scripts/rebuild-native.mjs +0 -22
- package/skills/rea-analysis/SKILL.md +0 -222
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
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
|
-
?
|
|
37
|
-
:
|
|
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
|
-
...(
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
const
|
|
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
|
-
: (
|
|
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
|
|
146
|
+
logger,
|
|
84
147
|
activeTarget,
|
|
85
148
|
recordEvidence,
|
|
86
|
-
recordUnknown
|
|
87
|
-
? undefined
|
|
88
|
-
: (input) => session.recordUnknown(input),
|
|
149
|
+
recordUnknown,
|
|
89
150
|
});
|
|
90
151
|
registerEnhancedTools(server, analysis, {
|
|
91
|
-
logger
|
|
152
|
+
logger,
|
|
92
153
|
activeTarget,
|
|
93
154
|
analysisProfile: session === undefined ? undefined : () => session.analysisProfile(),
|
|
94
155
|
recordEvidence,
|
|
95
|
-
recordUnknown
|
|
96
|
-
? undefined
|
|
97
|
-
: (input) => session.recordUnknown(input),
|
|
156
|
+
recordUnknown,
|
|
98
157
|
});
|
|
99
158
|
registerNativeTools(server, analysis, {
|
|
100
|
-
logger
|
|
159
|
+
logger,
|
|
101
160
|
activeTarget,
|
|
102
161
|
recordEvidence,
|
|
103
162
|
});
|
|
104
163
|
registerArtifactTools(server, analysis, {
|
|
105
|
-
logger
|
|
164
|
+
logger,
|
|
106
165
|
activeTarget,
|
|
107
166
|
recordEvidence,
|
|
108
|
-
...(
|
|
109
|
-
? {}
|
|
110
|
-
: { permissionAuthority: options.permissionAuthority }),
|
|
167
|
+
...(permissionAuthority === undefined ? {} : { permissionAuthority }),
|
|
111
168
|
});
|
|
112
169
|
registerManagedTools(server, analysis, {
|
|
113
|
-
logger
|
|
170
|
+
logger,
|
|
114
171
|
activeTarget,
|
|
115
172
|
recordEvidence,
|
|
173
|
+
session,
|
|
116
174
|
});
|
|
117
175
|
if (session !== undefined)
|
|
118
176
|
registerManagedWorkflowTools(server, {
|
|
119
|
-
logger
|
|
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:
|
|
187
|
+
authority: permissionAuthority,
|
|
130
188
|
},
|
|
131
189
|
});
|
|
190
|
+
};
|
|
191
|
+
const registerObservationTools = ({ server, session, options, logger, permissionAuthority, recordEvidence, recordEvidenceWithUnknown, }) => {
|
|
132
192
|
registerBrowserTools(server, {
|
|
133
|
-
logger
|
|
193
|
+
logger,
|
|
134
194
|
browser: options.browserObservation,
|
|
135
|
-
permissionAuthority
|
|
195
|
+
permissionAuthority,
|
|
136
196
|
recordEvidence,
|
|
137
197
|
});
|
|
138
198
|
registerElectronTools(server, {
|
|
139
|
-
logger
|
|
199
|
+
logger,
|
|
140
200
|
electron: options.electronObservation,
|
|
141
|
-
permissionAuthority
|
|
201
|
+
permissionAuthority,
|
|
142
202
|
recordEvidence,
|
|
143
203
|
});
|
|
144
204
|
registerApplicationTools(server, {
|
|
145
|
-
logger
|
|
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:
|
|
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 {};
|