rea-agents 2.3.0 → 2.5.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 +80 -18
- package/bridge/ghidra/ReaGhidraBridge.java +48 -1
- package/bridge/hopper_bridge.py +259 -24
- package/dist/application/AnalysisClientCleanup.js +14 -0
- package/dist/application/ApplicationWorkflowEvidenceResolver.js +31 -13
- package/dist/application/ArtifactExtraction.js +5 -1
- package/dist/application/ArtifactGraphConstruction.js +3 -15
- package/dist/application/ArtifactInventory/classify.js +5 -1
- package/dist/application/ArtifactInventory/reader.js +2 -0
- package/dist/application/BinarySession.js +15 -4
- package/dist/application/BinarySessionStatus.js +32 -1
- package/dist/application/BrowserEvidence.js +14 -0
- package/dist/application/BrowserScenarioCapturePort.js +1 -0
- package/dist/application/BrowserScenarioCaptureService.js +53 -0
- package/dist/application/BrowserScenarioEvidence.js +40 -0
- package/dist/application/CallPathTracing.js +160 -0
- package/dist/application/CapabilityInventory.js +79 -15
- package/dist/application/CompositeProvider.js +10 -1
- package/dist/application/DirectAnalysis.js +7 -2
- package/dist/application/EnhancedLiteralTracing.js +118 -0
- package/dist/application/EnhancedTools.js +35 -121
- package/dist/application/JavaScriptApplicationWorkflowEvidence.js +13 -0
- package/dist/application/JavaScriptApplicationWorkflowService.js +27 -1
- package/dist/application/JavaScriptRuntimeObservationEvidence.js +34 -0
- package/dist/application/JavaScriptRuntimeObservationPort.js +1 -0
- package/dist/application/JavaScriptRuntimeObservationService.js +46 -0
- package/dist/application/JavaScriptSemanticGraphAsyncProjection.js +147 -0
- package/dist/application/JavaScriptSemanticGraphBuilder.js +34 -6
- package/dist/application/JavaScriptSemanticGraphChildProcessProjection.js +156 -0
- package/dist/application/JavaScriptSemanticGraphConstruction.js +2 -2
- package/dist/application/JavaScriptSemanticGraphDataProjection.js +203 -0
- package/dist/application/JavaScriptSemanticGraphFingerprintProjection.js +25 -0
- package/dist/application/JavaScriptSemanticGraphFlowProjection.js +129 -8
- package/dist/application/JavaScriptSemanticGraphObjectProjection.js +81 -0
- package/dist/application/JavaScriptSemanticGraphProjection.js +14 -7
- package/dist/application/JavaScriptSemanticGraphResourceProjection.js +59 -0
- package/dist/application/JavaScriptSemanticGraphValueProjection.js +77 -0
- package/dist/application/ProcessCaptureEnvironment.js +26 -0
- package/dist/application/ProcessCaptureLifecycle.js +1 -0
- package/dist/application/ProcessCheckpoints.js +5 -0
- package/dist/application/ProcessHarness.js +45 -34
- package/dist/application/ProcessNormalization.js +6 -0
- package/dist/application/ProcessReactiveCoordinator.js +10 -3
- package/dist/application/ProcessReactiveEffects.js +15 -1
- package/dist/application/ProcessReactiveHarness.js +100 -0
- package/dist/application/ProcessReactiveObservations.js +101 -16
- package/dist/application/ProjectPermissionStore.js +1 -0
- package/dist/application/ReconstructionObligationAuthority.js +72 -0
- package/dist/application/ReconstructionObligationCandidates.js +265 -0
- package/dist/application/ReconstructionObligationLedgerDiagnostics.js +47 -0
- package/dist/application/ReconstructionObligationLedgerEvaluation.js +263 -0
- package/dist/application/ReconstructionObligationLedgerProjection.js +86 -0
- package/dist/application/ReconstructionObligationLedgerService.js +72 -0
- package/dist/application/ReconstructionObligationOriginalCases.js +33 -0
- package/dist/application/ReconstructionObligationPolicies.js +132 -0
- package/dist/application/ReconstructionReadinessService.js +48 -0
- package/dist/artifacts/ArtifactProvider.js +87 -22
- package/dist/browser/BrowserScenarioSecrets.js +53 -0
- package/dist/browser/BrowserScenarioSessionPort.js +1 -0
- package/dist/browser/CdpBrowserProvider.js +2 -2
- package/dist/browser/CdpCaptureDocuments.js +57 -0
- package/dist/browser/CdpCaptureStorage.js +71 -29
- package/dist/browser/CdpCaptureStorageFingerprints.js +328 -0
- package/dist/browser/CdpEndpoint.js +8 -6
- package/dist/browser/CdpPageCapture.js +2 -0
- package/dist/browser/JavaScriptRuntimeScope.js +38 -0
- package/dist/browser/PlaywrightBrowserScenarioProvider.js +253 -0
- package/dist/browser/PlaywrightExecutionBoundary.js +42 -0
- package/dist/browser/PlaywrightScenarioActions.js +62 -0
- package/dist/browser/PlaywrightScenarioArtifacts.js +238 -0
- package/dist/browser/PlaywrightScenarioBrowser.js +144 -0
- package/dist/browser/PlaywrightScenarioEvents.js +301 -0
- package/dist/browser/PlaywrightScenarioSession.js +300 -0
- package/dist/browser/V8InspectorCaptureProjection.js +110 -0
- package/dist/browser/V8InspectorEndpoint.js +72 -0
- package/dist/browser/V8InspectorProvider.js +267 -0
- package/dist/catalogIdentity.js +8 -0
- package/dist/cli/artifactCommands.js +39 -0
- package/dist/cli/coreAnalysisCommands.js +37 -0
- package/dist/cli.js +4 -0
- package/dist/cliApplicationCommands.js +30 -2
- package/dist/cliBrowserAdvancedCommands.js +17 -5
- package/dist/cliBrowserCommands.js +1 -0
- package/dist/cliBrowserScenarioCommands.js +43 -0
- package/dist/cliCommandNames.js +8 -0
- package/dist/cliJavaScriptRuntimeCommands.js +164 -0
- package/dist/cliObservationOptions.js +4 -0
- package/dist/cliPolicyCommands.js +1 -0
- package/dist/config/environment.js +12 -0
- package/dist/config/parseConfig.js +88 -17
- package/dist/contracts/analysisSearchContract.js +14 -0
- package/dist/contracts/applicationToolContracts.js +86 -2
- package/dist/contracts/applicationWorkflowInputContracts.js +18 -0
- package/dist/contracts/artifactToolContracts.js +22 -0
- package/dist/contracts/browserProviderToolContracts.js +7 -0
- package/dist/contracts/browserScenarioToolContracts.js +81 -0
- package/dist/contracts/browserToolContracts.js +88 -98
- package/dist/contracts/enhancedInputs.js +25 -6
- package/dist/contracts/functionInstructionContract.js +8 -0
- package/dist/contracts/hopperMemoryContracts.js +22 -0
- package/dist/contracts/javascriptApplicationWorkflowExamples.js +42 -0
- package/dist/contracts/javascriptRuntimeObservationToolContracts.js +58 -0
- package/dist/contracts/reconstructionReadinessExample.js +436 -0
- package/dist/contracts/toolContractExamples.js +5 -0
- package/dist/contracts/toolContractTypes.js +1 -0
- package/dist/contracts/toolContracts.js +13 -21
- package/dist/contracts/toolEffects.js +21 -0
- package/dist/contracts/toolOutputSchemaGroups.js +70 -20
- package/dist/contracts/toolOutputSchemaPrimitives.js +40 -0
- package/dist/domain/analysisErrorProjection.js +8 -0
- package/dist/domain/analysisSnapshot.js +2 -0
- package/dist/domain/artifactGraph.js +2 -0
- package/dist/domain/artifactInspection.js +347 -0
- package/dist/domain/binaryTarget.js +3 -6
- package/dist/domain/browserCaptureComparison.js +82 -0
- package/dist/domain/browserObservation.js +8 -1
- package/dist/domain/browserObservationErrors.js +1 -0
- package/dist/domain/browserObservationSchemas.js +26 -0
- package/dist/domain/browserScenario.js +165 -0
- package/dist/domain/browserScenarioCapture.js +57 -0
- package/dist/domain/browserScenarioCaptureValues.js +204 -0
- package/dist/domain/browserScenarioDiff.js +324 -0
- package/dist/domain/browserScenarioDiffValues.js +157 -0
- package/dist/domain/browserScenarioNormalization.js +45 -0
- package/dist/domain/browserScenarioValues.js +372 -0
- package/dist/domain/evidence.js +2 -0
- package/dist/domain/hopperValues.js +10 -0
- package/dist/domain/javascriptRuntimeObservation.js +170 -0
- package/dist/domain/javascriptRuntimeReconciliationParsing.js +120 -2
- package/dist/domain/javascriptRuntimeReconciliationResult.js +3 -3
- package/dist/domain/javascriptRuntimeReconciliationRuntime.js +2 -2
- package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
- package/dist/domain/javascriptSemanticAnalysis.js +5 -4
- package/dist/domain/javascriptSemanticAsyncEffects.js +253 -0
- package/dist/domain/javascriptSemanticChildProcesses.js +237 -0
- package/dist/domain/javascriptSemanticDataEffectHelpers.js +125 -0
- package/dist/domain/javascriptSemanticDataEffects.js +284 -0
- package/dist/domain/javascriptSemanticDerivedAnalysis.js +41 -0
- package/dist/domain/javascriptSemanticFingerprints.js +174 -0
- package/dist/domain/javascriptSemanticIr.js +21 -1
- package/dist/domain/javascriptSemanticObjects.js +115 -0
- package/dist/domain/javascriptSemanticPromises.js +290 -0
- package/dist/domain/javascriptSemanticResources.js +136 -0
- package/dist/domain/javascriptStaticAnalysis.js +4 -3
- package/dist/domain/javascriptStaticAnalysisBundler.js +38 -0
- package/dist/domain/javascriptStaticAnalysisCalls.js +23 -1
- package/dist/domain/javascriptStaticAnalysisHelpers.js +8 -0
- package/dist/domain/processCapture.js +71 -1
- package/dist/domain/processCaptureReactiveValidation.js +175 -0
- package/dist/domain/processCaptureValidation.js +2 -0
- package/dist/domain/processObservation.js +15 -6
- package/dist/domain/processReactiveRuntime.js +21 -10
- package/dist/domain/processReactiveScenario.js +1 -0
- package/dist/domain/processReactiveTransition.js +17 -10
- package/dist/domain/processScenario.js +21 -0
- package/dist/domain/providerCleanupError.js +11 -0
- package/dist/domain/reconstructionObligationLedgerSchemas.js +278 -0
- package/dist/domain/reconstructionReadiness.js +121 -0
- package/dist/domain/reconstructionReadinessFindingHelpers.js +17 -0
- package/dist/domain/reconstructionReadinessIntegrityFindings.js +118 -0
- package/dist/domain/reconstructionReadinessJourneyFindings.js +193 -0
- package/dist/domain/reconstructionReadinessSchemas.js +240 -0
- package/dist/domain/sourceToBundleComparison.js +335 -0
- package/dist/domain/sourceToBundleComparisonSchemas.js +133 -0
- package/dist/domain/sourceToBundleSignals.js +202 -0
- package/dist/domain/webCaptureDiff.js +141 -27
- package/dist/domain/webScreenshot.js +1 -1
- package/dist/domain/zipPackageFormat.js +20 -0
- package/dist/generatedPackageMetadata.js +1 -1
- package/dist/ghidra/GhidraDefaults.js +1 -1
- package/dist/ghidra/GhidraFunctionValues.js +13 -1
- package/dist/ghidra/GhidraProviderCapabilities.js +7 -0
- package/dist/hopper/HopperCleanup.js +158 -0
- package/dist/hopper/HopperClient.js +69 -99
- package/dist/hopper/HopperProvider.js +20 -1
- package/dist/hopper/HopperRequestQueue.js +187 -0
- package/dist/hopper/HopperResponseStream.js +46 -0
- package/dist/hopper/protocol.js +1 -0
- package/dist/main/transport.js +24 -24
- package/dist/main.js +6 -0
- package/dist/mcpDoctor.js +25 -2
- package/dist/native/NativeMacOSProvider.js +1 -0
- package/dist/process/ProcessCommandIdentity.js +19 -0
- package/dist/process/ProcessOwnership.js +11 -8
- package/dist/server/DynamicToolAvailability.js +70 -0
- package/dist/server/createServer.js +46 -1
- package/dist/server/lifecycleProgress.js +10 -0
- package/dist/server/permissionFailure.js +12 -0
- package/dist/server/registerApplicationTools/compareSourceToBundle.js +35 -0
- package/dist/server/registerApplicationTools/helpers.js +11 -7
- package/dist/server/registerApplicationTools/obligationLedger.js +27 -0
- package/dist/server/registerApplicationTools/readiness.js +55 -0
- package/dist/server/registerApplicationTools.js +6 -0
- package/dist/server/registerArtifactTools.js +9 -1
- package/dist/server/registerBrowserScenarioTool.js +25 -0
- package/dist/server/registerBrowserTools.js +2 -2
- package/dist/server/registerCloseLifecycleTool.js +57 -0
- package/dist/server/registerEnhancedTools.js +16 -5
- package/dist/server/registerEvidenceResources.js +4 -0
- package/dist/server/registerEvidenceTools.js +9 -2
- package/dist/server/registerJavaScriptRuntimeObservationTools.js +37 -0
- package/dist/server/registerReconstructionObligationLedgerResource.js +39 -0
- package/dist/server/registerReconstructionReadinessResource.js +39 -0
- package/dist/server/registerSessionStatusTool.js +11 -8
- package/dist/server/registerSessionTools.js +11 -57
- package/dist/server/sessionAvailabilityPolicy.js +10 -8
- package/package.json +12 -6
- package/skills/reverse-engineer-anything/SKILL.md +4 -3
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +2 -2
package/dist/mcpDoctor.js
CHANGED
|
@@ -61,10 +61,11 @@ const inspectProductionMcpSession = async (client, deadline, signal) => {
|
|
|
61
61
|
client.listResources(undefined, request),
|
|
62
62
|
client.listResourceTemplates(undefined, request),
|
|
63
63
|
client.readResource({ uri: "rea://server/identity" }, request),
|
|
64
|
-
client.callTool({ name: "binary_session", arguments: {} }, request),
|
|
64
|
+
client.callTool({ name: "binary_session", arguments: { detail: "full" } }, request),
|
|
65
65
|
]);
|
|
66
|
+
const expectedToolNames = availableToolNames(requestFlow.structuredContent) ?? [];
|
|
66
67
|
const inventory = {
|
|
67
|
-
tools: compareInventory(
|
|
68
|
+
tools: compareInventory(expectedToolNames, tools.tools.map(({ name }) => name)),
|
|
68
69
|
prompts: compareInventory(PROMPT_CONTRACTS.map(({ name }) => name), prompts.prompts.map(({ name }) => name)),
|
|
69
70
|
resources: compareInventory(MCP_RESOURCE_CATALOG.map(({ name }) => name), resources.resources.map(({ name }) => name)),
|
|
70
71
|
resource_templates: compareInventory(MCP_RESOURCE_TEMPLATE_CATALOG.map(({ name }) => name), templates.resourceTemplates.map(({ name }) => name)),
|
|
@@ -116,6 +117,28 @@ const inspectProductionMcpSession = async (client, deadline, signal) => {
|
|
|
116
117
|
checks,
|
|
117
118
|
};
|
|
118
119
|
};
|
|
120
|
+
const availableToolNames = (structuredContent) => {
|
|
121
|
+
if (typeof structuredContent !== "object" || structuredContent === null)
|
|
122
|
+
return undefined;
|
|
123
|
+
const result = Reflect.get(structuredContent, "result");
|
|
124
|
+
if (typeof result !== "object" || result === null)
|
|
125
|
+
return undefined;
|
|
126
|
+
const availability = Reflect.get(result, "tool_availability");
|
|
127
|
+
if (!Array.isArray(availability))
|
|
128
|
+
return undefined;
|
|
129
|
+
const names = [];
|
|
130
|
+
for (const item of availability) {
|
|
131
|
+
if (typeof item !== "object" || item === null)
|
|
132
|
+
return undefined;
|
|
133
|
+
const name = Reflect.get(item, "name");
|
|
134
|
+
const available = Reflect.get(item, "available");
|
|
135
|
+
if (typeof name !== "string" || typeof available !== "boolean")
|
|
136
|
+
return undefined;
|
|
137
|
+
if (available)
|
|
138
|
+
names.push(name);
|
|
139
|
+
}
|
|
140
|
+
return names;
|
|
141
|
+
};
|
|
119
142
|
/**
|
|
120
143
|
* Dispatcher entry for `rea mcp doctor`, kept separate from Incur MCP setup.
|
|
121
144
|
* @public
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { basename } from "node:path";
|
|
2
|
+
/** Match process-table command text while handling macOS executable-name normalization. */
|
|
3
|
+
export const matchesOwnedProcessCommand = (actual, expected, platform = process.platform) => {
|
|
4
|
+
const actualCommand = actual.trim();
|
|
5
|
+
const expectedCommand = expected.trim();
|
|
6
|
+
if (actualCommand === expectedCommand ||
|
|
7
|
+
actualCommand.startsWith(`${expectedCommand} `))
|
|
8
|
+
return true;
|
|
9
|
+
if (platform !== "darwin")
|
|
10
|
+
return false;
|
|
11
|
+
const actualExecutable = actualCommand.split(/\s+/u, 1)[0];
|
|
12
|
+
const expectedExecutable = expectedCommand.split(/\s+/u, 1)[0];
|
|
13
|
+
const normalizedActualExecutable = actualExecutable?.startsWith("(") === true && actualExecutable.endsWith(")")
|
|
14
|
+
? actualExecutable.slice(1, -1)
|
|
15
|
+
: actualExecutable;
|
|
16
|
+
return (normalizedActualExecutable !== undefined &&
|
|
17
|
+
expectedExecutable !== undefined &&
|
|
18
|
+
basename(normalizedActualExecutable) === basename(expectedExecutable));
|
|
19
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { execFile } from "node:child_process";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { promisify } from "node:util";
|
|
4
|
+
import { matchesOwnedProcessCommand } from "./ProcessCommandIdentity.js";
|
|
4
5
|
const execFileAsync = promisify(execFile);
|
|
5
6
|
/**
|
|
6
7
|
* Terminate one Windows process tree through the platform utility.
|
|
@@ -168,8 +169,8 @@ const launcherIdentityFailure = (launcher, ownership) => {
|
|
|
168
169
|
launcher.parentPid !== ownership.expectedParentPid)
|
|
169
170
|
return "owned launcher parent identity did not match";
|
|
170
171
|
if (ownership.expectedCommand !== undefined &&
|
|
171
|
-
!
|
|
172
|
-
return
|
|
172
|
+
!matchesOwnedProcessCommand(launcher.command, ownership.expectedCommand))
|
|
173
|
+
return `owned launcher command identity did not match (observed=${launcher.command}; expected=${ownership.expectedCommand})`;
|
|
173
174
|
return null;
|
|
174
175
|
};
|
|
175
176
|
const revalidateOwnedProcessGroup = async (processGroupId, ownership, host) => {
|
|
@@ -218,6 +219,12 @@ const processOwnershipFailures = async (members, runId, host) => {
|
|
|
218
219
|
failures.push({ pid: member.pid, reason: "run-token-mismatch" });
|
|
219
220
|
}
|
|
220
221
|
catch {
|
|
222
|
+
try {
|
|
223
|
+
const live = liveProcesses(await host.listProcesses());
|
|
224
|
+
if (!live.some(({ pid }) => pid === member.pid))
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
catch { }
|
|
221
228
|
failures.push({ pid: member.pid, reason: "environment-unreadable" });
|
|
222
229
|
}
|
|
223
230
|
}
|
|
@@ -280,8 +287,8 @@ export const observeOwnedProcessLineage = async (ownership, host = systemHost) =
|
|
|
280
287
|
launcher.parentPid !== ownership.expectedParentPid)
|
|
281
288
|
return unavailableLineage(ownership, "owned launcher parent identity did not match");
|
|
282
289
|
if (ownership.expectedCommand !== undefined &&
|
|
283
|
-
!
|
|
284
|
-
return unavailableLineage(ownership,
|
|
290
|
+
!matchesOwnedProcessCommand(launcher.command, ownership.expectedCommand))
|
|
291
|
+
return unavailableLineage(ownership, `owned launcher command identity did not match (observed=${launcher.command}; expected=${ownership.expectedCommand})`);
|
|
285
292
|
const descendants = descendantsOf(launcher.pid, processes);
|
|
286
293
|
for (const member of [launcher, ...descendants]) {
|
|
287
294
|
try {
|
|
@@ -340,7 +347,3 @@ const unavailableLineage = (ownership, reason) => ({
|
|
|
340
347
|
reason,
|
|
341
348
|
});
|
|
342
349
|
const liveProcesses = (members) => members.filter(({ state }) => !state.startsWith("Z"));
|
|
343
|
-
const commandMatches = (actual, expected) => {
|
|
344
|
-
return (actual.trim() === expected.trim() ||
|
|
345
|
-
actual.trim().startsWith(`${expected.trim()} `));
|
|
346
|
-
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { buildCapabilityInventory, } from "../application/CapabilityInventory.js";
|
|
2
|
+
/**
|
|
3
|
+
* Track public SDK tool handles and keep their visible state synchronized with
|
|
4
|
+
* the same availability projection returned by `binary_session`.
|
|
5
|
+
*/
|
|
6
|
+
export const installDynamicToolAvailability = (server, session, policy) => {
|
|
7
|
+
const tools = new Map();
|
|
8
|
+
const originalRegisterTool = server.registerTool.bind(server);
|
|
9
|
+
const originalSendToolListChanged = server.sendToolListChanged.bind(server);
|
|
10
|
+
let synchronizing = false;
|
|
11
|
+
const controller = {
|
|
12
|
+
synchronize: () => {
|
|
13
|
+
if (synchronizing)
|
|
14
|
+
return false;
|
|
15
|
+
synchronizing = true;
|
|
16
|
+
try {
|
|
17
|
+
const availability = new Map(buildCapabilityInventory(session.status(), policy(), clientFeatures(server)).map((item) => [item.name, item.available]));
|
|
18
|
+
let changed = false;
|
|
19
|
+
for (const [name, tool] of tools) {
|
|
20
|
+
const enabled = availability.get(name) === true;
|
|
21
|
+
if (tool.enabled === enabled)
|
|
22
|
+
continue;
|
|
23
|
+
changed = true;
|
|
24
|
+
if (enabled)
|
|
25
|
+
tool.enable();
|
|
26
|
+
else
|
|
27
|
+
tool.disable();
|
|
28
|
+
}
|
|
29
|
+
return changed;
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
synchronizing = false;
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
const wrappedRegisterTool = (...args) => {
|
|
37
|
+
const name = args[0];
|
|
38
|
+
if (typeof name !== "string")
|
|
39
|
+
throw new TypeError("MCP tool registration requires a string name");
|
|
40
|
+
const registered = Reflect.apply(originalRegisterTool, server, args);
|
|
41
|
+
if (!isRegisteredTool(registered))
|
|
42
|
+
throw new TypeError(`MCP SDK did not return a tool handle for ${name}`);
|
|
43
|
+
tools.set(name, registered);
|
|
44
|
+
return registered;
|
|
45
|
+
};
|
|
46
|
+
if (!Reflect.set(server, "registerTool", wrappedRegisterTool))
|
|
47
|
+
throw new TypeError("Unable to install dynamic MCP tool registration");
|
|
48
|
+
if (!Reflect.set(server, "sendToolListChanged", () => {
|
|
49
|
+
if (controller.synchronize())
|
|
50
|
+
originalSendToolListChanged();
|
|
51
|
+
}))
|
|
52
|
+
throw new TypeError("Unable to install dynamic MCP tool notifications");
|
|
53
|
+
return controller;
|
|
54
|
+
};
|
|
55
|
+
const clientFeatures = (server) => {
|
|
56
|
+
const capabilities = server.server.getClientCapabilities();
|
|
57
|
+
return {
|
|
58
|
+
elicitation_form: capabilities?.elicitation?.form !== undefined,
|
|
59
|
+
elicitation_url: capabilities?.elicitation?.url !== undefined,
|
|
60
|
+
roots: capabilities?.roots !== undefined,
|
|
61
|
+
sampling: capabilities?.sampling !== undefined,
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
const isRegisteredTool = (value) => {
|
|
65
|
+
if (typeof value !== "object" || value === null)
|
|
66
|
+
return false;
|
|
67
|
+
return (typeof Reflect.get(value, "enabled") === "boolean" &&
|
|
68
|
+
typeof Reflect.get(value, "enable") === "function" &&
|
|
69
|
+
typeof Reflect.get(value, "disable") === "function");
|
|
70
|
+
};
|
|
@@ -13,13 +13,39 @@ import { registerGuidedPrompts } from "./registerPrompts.js";
|
|
|
13
13
|
import { registerEvidenceResources } from "./registerEvidenceResources.js";
|
|
14
14
|
import { createServerIdentity } from "../serverIdentity.js";
|
|
15
15
|
import { registerBrowserTools } from "./registerBrowserTools.js";
|
|
16
|
+
import { registerBrowserScenarioTool } from "./registerBrowserScenarioTool.js";
|
|
16
17
|
import { registerElectronTools } from "./registerElectronTools.js";
|
|
18
|
+
import { registerJavaScriptRuntimeObservationTools } from "./registerJavaScriptRuntimeObservationTools.js";
|
|
17
19
|
import { registerApplicationTools } from "./registerApplicationTools.js";
|
|
18
|
-
|
|
20
|
+
import { sessionAvailabilityPolicy } from "./sessionAvailabilityPolicy.js";
|
|
21
|
+
import { DENY_EVIDENCE_FILE_POLICY, DENY_PROCESS_POLICY, } from "./sessionToolPolicies.js";
|
|
22
|
+
import { installDynamicToolAvailability } from "./DynamicToolAvailability.js";
|
|
23
|
+
const TARGET_FREE_INSTRUCTIONS = "REA analyzes shipped artifacts. Route: ASAR/JavaScript -> analyze_javascript_application (configured root); archive/package -> inspect_artifact; managed PE/CLI -> inspect_managed_artifact; passive browser/Electron -> list_browser_targets/list_electron_targets; approved browser interaction -> capture_browser_scenario; Node/Electron Inspector -> list_javascript_runtime_targets; native binary/database -> open_binary, then binary_overview. Check binary_session policy. Start with summaries and cite Evidence IDs. Never repeat identical analysis or read full Evidence without need.";
|
|
19
24
|
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.";
|
|
20
25
|
import { LinuxJavaScriptReplayRunner } from "../replay/LinuxJavaScriptReplayRunner.js";
|
|
21
26
|
import { SystemJavaScriptReplayHost } from "../replay/SystemJavaScriptReplayHost.js";
|
|
22
27
|
import { PROCESS_CAPTURE_ELICITATION_POLICY, } from "./ProcessCaptureElicitation.js";
|
|
28
|
+
const installSessionToolAvailability = (server, session, options) => {
|
|
29
|
+
if (session === undefined)
|
|
30
|
+
return undefined;
|
|
31
|
+
const policy = sessionAvailabilityPolicy(options.availabilityPolicy, {
|
|
32
|
+
processPolicy: options.processPolicy ?? DENY_PROCESS_POLICY,
|
|
33
|
+
evidenceFilePolicy: options.evidenceFilePolicy ?? DENY_EVIDENCE_FILE_POLICY,
|
|
34
|
+
investigationInputRoots: options.investigationInputRoots ?? [],
|
|
35
|
+
optionalFeatures: {
|
|
36
|
+
browserObservationEnabled: options.browserObservation !== undefined,
|
|
37
|
+
browserScenarioEnabled: options.browserScenarioCapture !== undefined,
|
|
38
|
+
electronObservationEnabled: options.electronObservation !== undefined,
|
|
39
|
+
v8InspectorObservationEnabled: options.javascriptRuntimeObservation !== undefined,
|
|
40
|
+
javascriptReplayEnabled: options.javascriptReplayPolicy?.enabled ?? false,
|
|
41
|
+
managedRuntimeEnabled: options.managedRuntimePolicy?.enabled ?? false,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
return {
|
|
45
|
+
policy,
|
|
46
|
+
controller: installDynamicToolAvailability(server, session, policy),
|
|
47
|
+
};
|
|
48
|
+
};
|
|
23
49
|
/**
|
|
24
50
|
* Construct one MCP server without acquiring subprocess resources.
|
|
25
51
|
* Supplying a session adds target lifecycle tools; omitting it retains the
|
|
@@ -50,9 +76,12 @@ export const createServer = (analysis, session, options = {}) => {
|
|
|
50
76
|
? ACTIVE_TARGET_INSTRUCTIONS
|
|
51
77
|
: TARGET_FREE_INSTRUCTIONS,
|
|
52
78
|
});
|
|
79
|
+
const dynamicTools = installSessionToolAvailability(server, session, options);
|
|
53
80
|
server.server.onclose = () => {
|
|
54
81
|
permissionAuthority?.clearSessionGrants();
|
|
55
82
|
};
|
|
83
|
+
if (dynamicTools !== undefined)
|
|
84
|
+
server.server.oninitialized = () => server.sendToolListChanged();
|
|
56
85
|
session?.onAvailabilityChanged?.(() => server.sendToolListChanged());
|
|
57
86
|
registerServerIdentityResource(server, startedAt);
|
|
58
87
|
const toolLogger = logger.child({ layer: "server" });
|
|
@@ -75,6 +104,9 @@ export const createServer = (analysis, session, options = {}) => {
|
|
|
75
104
|
registerEvidenceResources(server, session);
|
|
76
105
|
registerSessionTools(server, session, toolLogger, {
|
|
77
106
|
...options,
|
|
107
|
+
...(dynamicTools === undefined
|
|
108
|
+
? {}
|
|
109
|
+
: { availabilityPolicy: dynamicTools.policy }),
|
|
78
110
|
...(permissionAuthority === undefined ? {} : { permissionAuthority }),
|
|
79
111
|
startedAt,
|
|
80
112
|
processCaptureElicitation: {
|
|
@@ -94,6 +126,7 @@ export const createServer = (analysis, session, options = {}) => {
|
|
|
94
126
|
},
|
|
95
127
|
});
|
|
96
128
|
}
|
|
129
|
+
dynamicTools?.controller.synchronize();
|
|
97
130
|
return server;
|
|
98
131
|
};
|
|
99
132
|
const createSessionRecorders = (server, session) => ({
|
|
@@ -195,12 +228,24 @@ const registerObservationTools = ({ server, session, options, logger, permission
|
|
|
195
228
|
permissionAuthority,
|
|
196
229
|
recordEvidence,
|
|
197
230
|
});
|
|
231
|
+
registerBrowserScenarioTool(server, {
|
|
232
|
+
logger,
|
|
233
|
+
provider: options.browserScenarioCapture,
|
|
234
|
+
permissionAuthority,
|
|
235
|
+
recordEvidence,
|
|
236
|
+
});
|
|
198
237
|
registerElectronTools(server, {
|
|
199
238
|
logger,
|
|
200
239
|
electron: options.electronObservation,
|
|
201
240
|
permissionAuthority,
|
|
202
241
|
recordEvidence,
|
|
203
242
|
});
|
|
243
|
+
registerJavaScriptRuntimeObservationTools(server, {
|
|
244
|
+
logger,
|
|
245
|
+
runtime: options.javascriptRuntimeObservation,
|
|
246
|
+
permissionAuthority,
|
|
247
|
+
recordEvidence,
|
|
248
|
+
});
|
|
204
249
|
registerApplicationTools(server, {
|
|
205
250
|
logger,
|
|
206
251
|
recordEvidence,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Report one lifecycle operation start through the shared monotonic boundary. */
|
|
2
|
+
export const reportLifecycleStart = (progress, phase, message = "started") => progress.report({ phase, completed: 0, total: 1, message });
|
|
3
|
+
/** Report one lifecycle operation's terminal disposition. */
|
|
4
|
+
export const reportLifecycleEnd = (progress, phase, succeeded) => progress.report({
|
|
5
|
+
phase,
|
|
6
|
+
completed: 1,
|
|
7
|
+
total: 1,
|
|
8
|
+
message: succeeded ? "completed" : "failed",
|
|
9
|
+
terminal: true,
|
|
10
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AnalysisProtocolError, PermissionRequiredError, } from "../domain/errors.js";
|
|
2
|
+
import { err } from "../domain/result.js";
|
|
3
|
+
/** Preserve a typed permission denial or contain an unexpected authority error. */
|
|
4
|
+
export const permissionFailure = (failure) => {
|
|
5
|
+
if (failure.ok)
|
|
6
|
+
return err(new AnalysisProtocolError("Expected a denied permission"));
|
|
7
|
+
return err(failure.error instanceof PermissionRequiredError
|
|
8
|
+
? failure.error
|
|
9
|
+
: new AnalysisProtocolError(failure.error.message, {
|
|
10
|
+
cause: failure.error,
|
|
11
|
+
}));
|
|
12
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { compareSourceToBundleEvidenceValidated } from "../../application/JavaScriptApplicationWorkflowService.js";
|
|
2
|
+
import { resolveCompareSourceToBundleRequestValidated } from "../../application/ApplicationWorkflowEvidenceResolver.js";
|
|
3
|
+
import { applicationToolContract } from "../../contracts/applicationToolContracts.js";
|
|
4
|
+
import { compareSourceToBundleRequestSchema } from "../../contracts/applicationWorkflowInputContracts.js";
|
|
5
|
+
import { sourceToBundleComparisonResultSchema } from "../../domain/sourceToBundleComparisonSchemas.js";
|
|
6
|
+
import { logToolExecution } from "../toolLogging.js";
|
|
7
|
+
import { safeParseToolInput } from "../toolInputValidation.js";
|
|
8
|
+
import { toolRegistrationOptions } from "../toolRegistrationOptions.js";
|
|
9
|
+
import { toCallToolResult } from "../toolResult.js";
|
|
10
|
+
import { recordResult, recordSources } from "./helpers.js";
|
|
11
|
+
const contract = applicationToolContract("compare_source_to_bundle");
|
|
12
|
+
/** Register conservative historical-source to bundle comparison. */
|
|
13
|
+
export const registerCompareSourceToBundleTool = (server, options) => {
|
|
14
|
+
server.registerTool(contract.name, toolRegistrationOptions(contract), async (input) => {
|
|
15
|
+
const parsedInput = safeParseToolInput(compareSourceToBundleRequestSchema, input, contract.name);
|
|
16
|
+
if (!parsedInput.ok)
|
|
17
|
+
return toCallToolResult(parsedInput, contract);
|
|
18
|
+
const resolved = resolveCompareSourceToBundleRequestValidated(parsedInput.value, options.evidenceLookup);
|
|
19
|
+
if (!resolved.ok)
|
|
20
|
+
return toCallToolResult(resolved, contract);
|
|
21
|
+
const result = await logToolExecution(options.logger, contract.name, () => Promise.resolve(compareSourceToBundleEvidenceValidated(resolved.value)));
|
|
22
|
+
if (!result.ok)
|
|
23
|
+
return toCallToolResult(result, contract);
|
|
24
|
+
const recorded = recordSources(options.recordEvidence, [
|
|
25
|
+
resolved.value.application,
|
|
26
|
+
]);
|
|
27
|
+
if (!recorded.ok)
|
|
28
|
+
return toCallToolResult(recorded, contract);
|
|
29
|
+
const comparison = sourceToBundleComparisonResultSchema.parse(result.value.normalized_result);
|
|
30
|
+
return recordResult(options, contract, result.value, resolved.value.unknown_registry_approved === true &&
|
|
31
|
+
comparison.summary.unknown > 0
|
|
32
|
+
? "source-to-bundle-comparison"
|
|
33
|
+
: undefined);
|
|
34
|
+
});
|
|
35
|
+
};
|
|
@@ -23,7 +23,9 @@ const unknownRegistration = (evidence, kind) => ({
|
|
|
23
23
|
approved: true,
|
|
24
24
|
question: kind === "application-version-comparison"
|
|
25
25
|
? "Which application entities remain unmatched or ambiguous across these versions?"
|
|
26
|
-
:
|
|
26
|
+
: kind === "source-to-bundle-comparison"
|
|
27
|
+
? "Which historical source files remain unmatched or ambiguously mapped to the shipped bundle?"
|
|
28
|
+
: "Which selected JavaScript export return shapes remain dynamic, incomplete, or ambiguously paired?",
|
|
27
29
|
severity: "medium",
|
|
28
30
|
domain: kind,
|
|
29
31
|
supporting_evidence_ids: [evidence.evidence_id],
|
|
@@ -43,12 +45,14 @@ const unknownRegistration = (evidence, kind) => ({
|
|
|
43
45
|
rationale: "Add approved passive runtime Evidence without promoting it to static fact.",
|
|
44
46
|
},
|
|
45
47
|
]
|
|
46
|
-
:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
: kind === "source-to-bundle-comparison"
|
|
49
|
+
? []
|
|
50
|
+
: [
|
|
51
|
+
{
|
|
52
|
+
operation: "run_controlled_replay",
|
|
53
|
+
rationale: "Validate exact approved module behavior separately when runtime semantics are required.",
|
|
54
|
+
},
|
|
55
|
+
]),
|
|
52
56
|
],
|
|
53
57
|
relationships: [],
|
|
54
58
|
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { buildReconstructionObligationLedgerEvidenceValidated, resolveReconstructionObligationLedgerRequest, } from "../../application/ReconstructionObligationLedgerService.js";
|
|
2
|
+
import { applicationToolContract } from "../../contracts/applicationToolContracts.js";
|
|
3
|
+
import { reconstructionObligationLedgerInputSchema } from "../../domain/reconstructionObligationLedgerSchemas.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
|
+
import { recordResult, recordSources } from "./helpers.js";
|
|
9
|
+
const contract = applicationToolContract("build_reconstruction_obligation_ledger");
|
|
10
|
+
/** Register conservative reconstruction-obligation generation and closure. */
|
|
11
|
+
export const registerReconstructionObligationLedgerTool = (server, options) => {
|
|
12
|
+
server.registerTool(contract.name, toolRegistrationOptions(contract), async (input) => {
|
|
13
|
+
const parsed = safeParseToolInput(reconstructionObligationLedgerInputSchema, input, contract.name);
|
|
14
|
+
if (!parsed.ok)
|
|
15
|
+
return toCallToolResult(parsed, contract);
|
|
16
|
+
const resolved = resolveReconstructionObligationLedgerRequest(parsed.value);
|
|
17
|
+
if (!resolved.ok)
|
|
18
|
+
return toCallToolResult(resolved, contract);
|
|
19
|
+
const result = await logToolExecution(options.logger, contract.name, () => Promise.resolve(buildReconstructionObligationLedgerEvidenceValidated(resolved.value)));
|
|
20
|
+
if (!result.ok)
|
|
21
|
+
return toCallToolResult(result, contract);
|
|
22
|
+
const recorded = recordSources(options.recordEvidence, resolved.value.evidence_bundle.records);
|
|
23
|
+
if (!recorded.ok)
|
|
24
|
+
return toCallToolResult(recorded, contract);
|
|
25
|
+
return recordResult(options, contract, result.value);
|
|
26
|
+
});
|
|
27
|
+
};
|
|
@@ -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,
|
|
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 {
|
|
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:
|
|
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
|
+
};
|