rea-agents 2.5.0 → 3.1.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 +20 -12
- package/bridge/ghidra/ReaGhidraBridge.java +477 -4
- package/bridge/hopper_bridge.py +54 -4
- package/dist/application/AnalysisContextQueries.js +142 -0
- package/dist/application/AnalysisSnapshotCache.js +4 -2
- package/dist/application/ApplicationWorkflowEvidenceResolver.js +19 -11
- package/dist/application/ArtifactInventory/policy.js +17 -0
- package/dist/application/ArtifactInventory/reader.js +1 -4
- package/dist/application/ArtifactInventory/scanCanonical.js +0 -3
- package/dist/application/ArtifactInventory/scanReader.js +7 -7
- package/dist/application/ArtifactInventory/types.js +1 -5
- package/dist/application/BinarySession.js +19 -20
- package/dist/application/BinarySessionComposition.js +21 -0
- package/dist/application/BinarySessionRecords.js +106 -10
- package/dist/application/BinarySessionStatus.js +11 -5
- package/dist/application/BrowserEvidence.js +3 -5
- package/dist/application/CapabilityClientRequirements.js +26 -0
- package/dist/application/CapabilityInventory.js +140 -55
- package/dist/application/ClientRegistrationStatus.js +4 -1
- package/dist/application/CrossVersionInventory.js +7 -6
- package/dist/application/DirectAnalysis.js +6 -2
- package/dist/application/ElectronActiveEvidence.js +55 -0
- package/dist/application/ElectronActiveObservationPort.js +1 -0
- package/dist/application/ElectronActiveObservationService.js +81 -0
- package/dist/application/EnhancedTools.js +49 -17
- package/dist/application/EvidenceBundleCommands.js +5 -1
- package/dist/application/EvidenceLedger.js +53 -17
- package/dist/application/JavaScriptArtifactAnalysis.js +13 -4
- package/dist/application/JavaScriptReplayPermission.js +1 -1
- package/dist/application/JavaScriptReplayService.js +23 -15
- package/dist/application/LazyAnalysisProvider.js +77 -0
- package/dist/application/LoopbackReplay.js +1 -1
- package/dist/application/ManagedRuntimeCorrelationService.js +9 -5
- package/dist/application/NativeApiInspection.js +80 -0
- package/dist/application/NodeRuntimeCharacterizationService.js +8 -9
- package/dist/application/ProcessCaptureLifecycle.js +5 -0
- package/dist/application/ProcessCli.js +2 -1
- package/dist/application/ProcessHarness.js +8 -3
- package/dist/application/ProcessNormalization.js +2 -1
- package/dist/application/ProjectPermissionStore.js +1 -0
- package/dist/application/ReferenceSourceImport.js +2 -2
- package/dist/application/SessionProviderRouter.js +6 -6
- package/dist/application/SetupClientConfiguration.js +10 -3
- package/dist/application/WindowsCapabilities.js +5 -4
- package/dist/application/runtime.js +26 -9
- package/dist/artifacts/ArtifactProvider.js +8 -10
- package/dist/artifacts/SafeOutputTree.js +7 -8
- package/dist/browser/CdpCaptureStorageFingerprints.js +10 -7
- package/dist/browser/CdpElectronInspection.js +3 -1
- package/dist/browser/JavaScriptRuntimeScope.js +5 -0
- package/dist/browser/PlaywrightBrowserScenarioProvider.js +8 -2
- package/dist/browser/PlaywrightElectronActiveActions.js +324 -0
- package/dist/browser/PlaywrightElectronActiveProvider.js +294 -0
- package/dist/browser/PlaywrightScenarioBrowser.js +4 -4
- package/dist/browser/PlaywrightScenarioSession.js +4 -4
- package/dist/browser/SensitiveTextCapture.js +1 -1
- package/dist/browser/V8InspectorCaptureProjection.js +1 -0
- package/dist/browser/V8InspectorProvider.js +3 -3
- package/dist/catalogIdentity.js +15 -9
- package/dist/cli/artifactCommands.js +5 -3
- package/dist/cli/coreAnalysisCommands.js +41 -0
- package/dist/cli/managedCommands.js +1 -1
- package/dist/cliApplicationCommands.js +2 -2
- package/dist/cliBrowserAdvancedCommands.js +11 -5
- package/dist/cliBrowserCommands.js +14 -7
- package/dist/cliCommandNames.js +2 -0
- package/dist/cliElectronCommands.js +46 -4
- package/dist/cliJavaScriptRuntimeCommands.js +14 -6
- package/dist/cliObservationOptions.js +4 -0
- package/dist/cliPolicyCommands.js +1 -0
- package/dist/config/browserScenario.js +77 -0
- package/dist/config/electronAutomation.js +35 -0
- package/dist/config/environment.js +6 -0
- package/dist/config/javascriptReplay.js +41 -0
- package/dist/config/managedRuntime.js +25 -0
- package/dist/config/parseConfig.js +56 -200
- package/dist/config/parsers.js +10 -1
- package/dist/config/passiveObservation.js +157 -0
- package/dist/config/processCapture.js +47 -0
- package/dist/contracts/applicationToolContracts.js +2 -5
- package/dist/contracts/applicationWorkflowInputContracts.js +86 -96
- package/dist/contracts/artifactToolContracts.js +35 -37
- package/dist/contracts/browserToolContracts.js +2 -2
- package/dist/contracts/electronToolContracts.js +30 -1
- package/dist/contracts/enhancedInputs.js +21 -27
- package/dist/contracts/functionWorkflowToolContracts.js +29 -0
- package/dist/contracts/managedToolContracts.js +4 -9
- package/dist/contracts/managedWorkflowExamples.js +12 -9
- package/dist/contracts/managedWorkflowToolContracts.js +30 -27
- package/dist/contracts/nativeToolContracts.js +2 -3
- package/dist/contracts/promptContracts.js +14 -15
- package/dist/contracts/sessionToolSchemas.js +61 -0
- package/dist/contracts/toolContractExamples.js +4 -0
- package/dist/contracts/toolContractHelpers.js +23 -0
- package/dist/contracts/toolContracts.js +12 -67
- package/dist/contracts/toolEffects.js +19 -0
- package/dist/contracts/toolOutputSchemaGroups.js +66 -11
- package/dist/contracts/toolOutputSchemaPrimitives.js +76 -26
- package/dist/contracts/toolSchemaMetadata.js +128 -0
- package/dist/doctorRuntime.js +1 -1
- package/dist/domain/analysisErrorPresentation.js +8 -2
- package/dist/domain/analysisErrorProjection.js +1 -0
- package/dist/domain/androidApplication.js +2 -0
- package/dist/domain/appleApplication.js +2 -0
- package/dist/domain/binaryTarget.js +7 -5
- package/dist/domain/binaryTargetTypes.js +1 -0
- package/dist/domain/browserCaptureComparison.js +21 -69
- package/dist/domain/browserObservation.js +22 -9
- package/dist/domain/bytecodeProvider.js +177 -0
- package/dist/domain/callPath.js +3 -2
- package/dist/domain/conformancePackage.js +169 -0
- package/dist/domain/conformanceReplay.js +104 -0
- package/dist/domain/conformanceTrustGate.js +328 -0
- package/dist/domain/customProtocolCapture.js +137 -0
- package/dist/domain/electronActiveObservation.js +277 -0
- package/dist/domain/electronObservation.js +15 -11
- package/dist/domain/electronStaticAnalysisValues.js +4 -1
- package/dist/domain/eventProcessTree.js +217 -0
- package/dist/domain/evidenceBundle.js +47 -0
- package/dist/domain/functionComparisonNormalization.js +15 -8
- package/dist/domain/functionDossierEvidence.js +9 -4
- package/dist/domain/hopperStartupFailure.js +1 -1
- package/dist/domain/hopperValues.js +68 -68
- package/dist/domain/inputIssueProjection.js +11 -2
- package/dist/domain/investigationWorkspace.js +16 -15
- package/dist/domain/javascriptExportShapeComparisonSchemas.js +2 -2
- package/dist/domain/javascriptReplay.js +79 -63
- package/dist/domain/javascriptRuntimeObservation.js +1 -0
- package/dist/domain/javascriptRuntimeReconciliationActive.js +89 -0
- package/dist/domain/javascriptRuntimeReconciliationGraph.js +11 -10
- package/dist/domain/javascriptRuntimeReconciliationMatching.js +57 -49
- package/dist/domain/javascriptRuntimeReconciliationParsing.js +5 -1
- package/dist/domain/javascriptRuntimeReconciliationResult.js +21 -14
- package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
- package/dist/domain/javascriptSemanticAnalysis.js +8 -12
- package/dist/domain/javascriptSourceParser.js +15 -0
- package/dist/domain/javascriptStaticAnalysis.js +8 -12
- package/dist/domain/knownPageCoverage.js +15 -7
- package/dist/domain/mobileApplicationInvestigation.js +159 -0
- package/dist/domain/nativeApiBoundary.js +138 -0
- package/dist/domain/nodeRuntimeCharacterization.js +14 -13
- package/dist/domain/objcSwiftMetadata.js +150 -0
- package/dist/domain/packageAnalysis.js +123 -0
- package/dist/domain/peInspection.js +196 -0
- package/dist/domain/processCaptureReactiveValidation.js +8 -3
- package/dist/domain/processCaptureValidation.js +7 -3
- package/dist/domain/processComparison.js +12 -7
- package/dist/domain/processObservation.js +5 -6
- package/dist/domain/processReactiveMatching.js +14 -7
- package/dist/domain/processReactiveTransition.js +9 -3
- package/dist/domain/processScenario.js +6 -3
- package/dist/domain/processTraceComparison.js +3 -2
- package/dist/domain/protocolCapture.js +245 -0
- package/dist/domain/reconstructionReadinessSchemas.js +30 -2
- package/dist/domain/referenceSourceImportParsing.js +2 -2
- package/dist/domain/replayMachineRuntime.js +5 -3
- package/dist/domain/sourceToBundleComparison.js +2 -2
- package/dist/domain/sourceToBundleComparisonSchemas.js +8 -8
- package/dist/domain/sourceToBundleSignals.js +7 -1
- package/dist/domain/staticRuntimeCorrelation.js +7 -5
- package/dist/domain/webBundleAnalysis.js +14 -14
- package/dist/domain/webCaptureDiff.js +15 -12
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +2 -3
- package/dist/dotnet/ManagedStaticProvider.js +34 -5
- package/dist/generatedMcpToolCatalog.js +37 -0
- package/dist/generatedPackageMetadata.js +4 -4
- package/dist/ghidra/GhidraClient.js +1 -1
- package/dist/ghidra/GhidraClientStartup.js +1 -1
- package/dist/ghidra/GhidraDefaults.js +1 -1
- package/dist/ghidra/GhidraFunctionValues.js +44 -16
- package/dist/ghidra/GhidraInventoryValues.js +57 -47
- package/dist/ghidra/GhidraProvider.js +18 -10
- package/dist/ghidra/GhidraProviderCapabilities.js +45 -39
- package/dist/ghidra/GhidraSocketConnection.js +1 -1
- package/dist/ghidra/protocol.js +19 -42
- package/dist/hopper/BridgeLauncher.js +3 -1
- package/dist/hopper/HopperAnalysisProfile.js +2 -4
- package/dist/hopper/HopperCleanup.js +5 -6
- package/dist/hopper/HopperClient.js +27 -3
- package/dist/hopper/HopperProvider.js +42 -44
- package/dist/hopper/HopperRequestQueue.js +32 -4
- package/dist/hopper/HopperResponseStream.js +2 -2
- package/dist/hopper/LinuxPrivateDisplayProbe.js +16 -10
- package/dist/hopper/protocol.js +63 -21
- package/dist/main/reload.js +1 -6
- package/dist/main/state.js +0 -14
- package/dist/main/transport.js +31 -41
- package/dist/main.js +17 -13
- package/dist/mcpDoctor.js +4 -26
- package/dist/mcpStartupPolicy.js +14 -0
- package/dist/process/PrivateRuntimeRoot.js +17 -0
- package/dist/process/ProcessOwnership.js +64 -128
- package/dist/process/ProcessOwnershipIdentity.js +13 -0
- package/dist/process/ProcessOwnershipObservation.js +88 -0
- package/dist/process/ProcessOwnershipProcessTree.js +22 -0
- package/dist/process/ProviderDeadline.js +8 -12
- package/dist/process/WindowsAuthority.js +32 -0
- package/dist/reference/ReferenceSourceReader.js +3 -3
- package/dist/reference/ReferenceSourceReaderEntries.js +2 -2
- package/dist/replay/JavaScriptReplayWorker.js +95 -11
- package/dist/replay/JavaScriptReplayWorkerTypes.js +1 -0
- package/dist/replay/LinuxJavaScriptReplayRunner.js +10 -15
- package/dist/replay/ReplayOutcome.js +26 -15
- package/dist/replay/ReplayWorkerProtocol.js +34 -29
- package/dist/server/createServer.js +101 -144
- package/dist/server/mcpClientMetadata.js +32 -0
- package/dist/server/registerApplicationTools/characterization.js +6 -13
- package/dist/server/registerApplicationTools/compareExportShapes.js +2 -7
- package/dist/server/registerApplicationTools/compareSourceToBundle.js +2 -7
- package/dist/server/registerApplicationTools/compareVersions.js +3 -8
- package/dist/server/registerApplicationTools/controlledReplay.js +6 -11
- package/dist/server/registerApplicationTools/coverage.js +13 -19
- package/dist/server/registerApplicationTools/obligationLedger.js +1 -6
- package/dist/server/registerApplicationTools/readiness.js +1 -6
- package/dist/server/registerApplicationTools/traceFeature.js +3 -8
- package/dist/server/registerApplicationTools/traceSemantics.js +1 -6
- package/dist/server/registerArtifactComparisonTool.js +12 -16
- package/dist/server/registerBrowserScenarioTool.js +1 -6
- package/dist/server/registerBrowserTools.js +37 -79
- package/dist/server/registerBundleComparisonTool.js +10 -14
- package/dist/server/registerCloseLifecycleTool.js +6 -14
- package/dist/server/registerElectronTools.js +30 -47
- package/dist/server/registerEnhancedTools.js +124 -122
- package/dist/server/registerEvidenceResources.js +50 -101
- package/dist/server/registerEvidenceTools.js +5 -9
- package/dist/server/registerFunctionComparisonTool.js +11 -15
- package/dist/server/registerInvestigationTools.js +42 -59
- package/dist/server/registerJavaScriptApplicationGraphResource.js +0 -4
- package/dist/server/registerJavaScriptRuntimeObservationTools.js +13 -27
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +4 -9
- package/dist/server/registerManagedWorkflowTools/contract.js +2 -3
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +3 -8
- package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +3 -8
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +8 -13
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +4 -9
- package/dist/server/registerOfficialTools.js +8 -9
- package/dist/server/registerProcessComparisonTool.js +19 -24
- package/dist/server/registerReconstructionObligationLedgerResource.js +0 -7
- package/dist/server/registerReconstructionReadinessResource.js +0 -7
- package/dist/server/registerReplayMachineTool.js +4 -10
- package/dist/server/registerSessionRecordTools.js +146 -47
- package/dist/server/registerSessionStatusTool.js +14 -29
- package/dist/server/registerSessionTools.js +45 -41
- package/dist/server/sessionAvailabilityPolicy.js +2 -1
- package/dist/server/sessionToolPolicies.js +1 -5
- package/dist/server/toolRegistrationOptions.js +4 -177
- package/dist/server/toolResult.js +14 -18
- package/package.json +35 -16
- package/scripts/electron-active-hook-boundaries.cjs +394 -0
- package/scripts/electron-active-hook.cjs +501 -0
- package/skills/reverse-engineer-anything/SKILL.md +10 -3
- package/dist/server/DynamicToolAvailability.js +0 -70
- package/dist/server/toolInputValidation.js +0 -77
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
createElectronActiveBoundaryPatches,
|
|
5
|
+
} = require("./electron-active-hook-boundaries.cjs");
|
|
6
|
+
|
|
7
|
+
const boundedEnvironmentNumber = (name, fallback) => {
|
|
8
|
+
const value = Number(process.env[name]);
|
|
9
|
+
return Number.isInteger(value)
|
|
10
|
+
? Math.min(20_000, Math.max(1, value))
|
|
11
|
+
: fallback;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const MAX_EVENT_NAME_LENGTH = 128;
|
|
15
|
+
const MAX_CHANNEL_LENGTH = 1_024;
|
|
16
|
+
const MAX_IDENTIFIER_LENGTH = 256;
|
|
17
|
+
const MAX_ARGUMENT_SHAPES = 32;
|
|
18
|
+
const maxEvents = boundedEnvironmentNumber(
|
|
19
|
+
"REA_ELECTRON_ACTIVE_MAX_RUNTIME_EVENTS",
|
|
20
|
+
5_000,
|
|
21
|
+
);
|
|
22
|
+
const ipcEventKinds = new Set([
|
|
23
|
+
"main-handler-invocation",
|
|
24
|
+
"main-event-invocation",
|
|
25
|
+
"utility-process-fork",
|
|
26
|
+
"utility-process-message",
|
|
27
|
+
"ipc-main-to-renderer",
|
|
28
|
+
"ipc-utility-to-main",
|
|
29
|
+
"ipc-renderer-send",
|
|
30
|
+
"ipc-renderer-invoke",
|
|
31
|
+
"ipc-renderer-post-message",
|
|
32
|
+
]);
|
|
33
|
+
const events = [];
|
|
34
|
+
let observed = 0;
|
|
35
|
+
let observedIpc = 0;
|
|
36
|
+
let observedRuntime = 0;
|
|
37
|
+
let truncated = false;
|
|
38
|
+
let sequence = 0;
|
|
39
|
+
let correlationSequence = 0;
|
|
40
|
+
|
|
41
|
+
const boundedString = (value, maximum) =>
|
|
42
|
+
typeof value === "string" ? value.slice(0, maximum) : null;
|
|
43
|
+
|
|
44
|
+
const shape = (value, depth = 0) => {
|
|
45
|
+
if (depth > 2 || value === null) return value === null ? "null" : "nested";
|
|
46
|
+
if (Array.isArray(value)) return "array";
|
|
47
|
+
switch (typeof value) {
|
|
48
|
+
case "string":
|
|
49
|
+
return "string";
|
|
50
|
+
case "number":
|
|
51
|
+
return "number";
|
|
52
|
+
case "boolean":
|
|
53
|
+
return "boolean";
|
|
54
|
+
case "undefined":
|
|
55
|
+
return "undefined";
|
|
56
|
+
case "function":
|
|
57
|
+
return "function";
|
|
58
|
+
case "object":
|
|
59
|
+
return "object";
|
|
60
|
+
default:
|
|
61
|
+
return "unknown";
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const isAllowedNavigation = (value) => {
|
|
66
|
+
if (typeof value !== "string") return true;
|
|
67
|
+
try {
|
|
68
|
+
const parsed = new URL(value);
|
|
69
|
+
if (["file:", "data:", "about:"].includes(parsed.protocol)) return true;
|
|
70
|
+
return (
|
|
71
|
+
["http:", "https:"].includes(parsed.protocol) &&
|
|
72
|
+
["127.0.0.1", "localhost", "[::1]", "::1"].includes(parsed.hostname)
|
|
73
|
+
);
|
|
74
|
+
} catch {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const processType = () =>
|
|
80
|
+
typeof process.type === "string" && process.type.length > 0
|
|
81
|
+
? process.type.slice(0, MAX_IDENTIFIER_LENGTH)
|
|
82
|
+
: "main";
|
|
83
|
+
|
|
84
|
+
const identity = (value, prefix) => {
|
|
85
|
+
if (value === null || value === undefined) return null;
|
|
86
|
+
const id = value.id;
|
|
87
|
+
const processId = value.pid;
|
|
88
|
+
return typeof id === "string" || typeof id === "number"
|
|
89
|
+
? `${prefix}:${String(id)}`.slice(0, MAX_IDENTIFIER_LENGTH)
|
|
90
|
+
: typeof processId === "number"
|
|
91
|
+
? `${prefix}:pid:${String(processId)}`.slice(0, MAX_IDENTIFIER_LENGTH)
|
|
92
|
+
: null;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const frameIdentity = (event) => {
|
|
96
|
+
const frame = event?.senderFrame ?? event?.frame;
|
|
97
|
+
const id = frame?.frameTreeNodeId ?? frame?.routingId ?? frame?.id;
|
|
98
|
+
return typeof id === "string" || typeof id === "number"
|
|
99
|
+
? `frame:${String(id)}`.slice(0, MAX_IDENTIFIER_LENGTH)
|
|
100
|
+
: null;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const record = (event) => {
|
|
104
|
+
observed += 1;
|
|
105
|
+
if (ipcEventKinds.has(event.kind)) observedIpc += 1;
|
|
106
|
+
else observedRuntime += 1;
|
|
107
|
+
if (events.length >= maxEvents) {
|
|
108
|
+
truncated = true;
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
const raw = {
|
|
112
|
+
sequence: ++sequence,
|
|
113
|
+
correlation_id:
|
|
114
|
+
typeof event.correlation_id === "string"
|
|
115
|
+
? event.correlation_id
|
|
116
|
+
: `capture:${process.pid}:${++correlationSequence}`,
|
|
117
|
+
event: null,
|
|
118
|
+
phase: "observed",
|
|
119
|
+
channel: null,
|
|
120
|
+
channel_truncated: false,
|
|
121
|
+
direction: null,
|
|
122
|
+
sender: null,
|
|
123
|
+
receiver: null,
|
|
124
|
+
frame: null,
|
|
125
|
+
target: null,
|
|
126
|
+
argument_shapes: [],
|
|
127
|
+
argument_shapes_truncated: false,
|
|
128
|
+
result_shape: null,
|
|
129
|
+
process_type: processType(),
|
|
130
|
+
source: "electron-active-hook",
|
|
131
|
+
capture_method: "api-wrapper",
|
|
132
|
+
artifact_path: null,
|
|
133
|
+
artifact_sha256: null,
|
|
134
|
+
error: false,
|
|
135
|
+
...event,
|
|
136
|
+
};
|
|
137
|
+
const argumentShapes = Array.isArray(raw.argument_shapes)
|
|
138
|
+
? raw.argument_shapes
|
|
139
|
+
: [];
|
|
140
|
+
events.push({
|
|
141
|
+
...raw,
|
|
142
|
+
correlation_id: boundedString(raw.correlation_id, MAX_IDENTIFIER_LENGTH),
|
|
143
|
+
event: boundedString(raw.event, MAX_EVENT_NAME_LENGTH),
|
|
144
|
+
channel: boundedString(raw.channel, MAX_CHANNEL_LENGTH),
|
|
145
|
+
channel_truncated:
|
|
146
|
+
raw.channel_truncated === true ||
|
|
147
|
+
(typeof raw.channel === "string" &&
|
|
148
|
+
raw.channel.length > MAX_CHANNEL_LENGTH),
|
|
149
|
+
sender: boundedString(raw.sender, MAX_IDENTIFIER_LENGTH),
|
|
150
|
+
receiver: boundedString(raw.receiver, MAX_IDENTIFIER_LENGTH),
|
|
151
|
+
frame: boundedString(raw.frame, MAX_IDENTIFIER_LENGTH),
|
|
152
|
+
target: boundedString(raw.target, MAX_IDENTIFIER_LENGTH),
|
|
153
|
+
argument_shapes: argumentShapes
|
|
154
|
+
.slice(0, MAX_ARGUMENT_SHAPES)
|
|
155
|
+
.map((value) => boundedString(value, 64) ?? "unknown"),
|
|
156
|
+
argument_shapes_truncated:
|
|
157
|
+
raw.argument_shapes_truncated === true ||
|
|
158
|
+
argumentShapes.length > MAX_ARGUMENT_SHAPES,
|
|
159
|
+
result_shape: boundedString(raw.result_shape, 64),
|
|
160
|
+
process_type: boundedString(raw.process_type, MAX_IDENTIFIER_LENGTH),
|
|
161
|
+
artifact_path: boundedString(raw.artifact_path, 16_384),
|
|
162
|
+
artifact_sha256: boundedString(raw.artifact_sha256, 64),
|
|
163
|
+
});
|
|
164
|
+
return events.at(-1);
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const recordRuntime = (kind, event, phase, details = {}) =>
|
|
168
|
+
record({ kind, event, phase, ...details });
|
|
169
|
+
|
|
170
|
+
const recordIpc = (kind, channel, args, details = {}) =>
|
|
171
|
+
(() => {
|
|
172
|
+
const values = Array.isArray(args) ? args : [];
|
|
173
|
+
return record({
|
|
174
|
+
kind,
|
|
175
|
+
channel: typeof channel === "string" ? channel : null,
|
|
176
|
+
argument_shapes: values
|
|
177
|
+
.slice(0, MAX_ARGUMENT_SHAPES)
|
|
178
|
+
.map((value) => shape(value)),
|
|
179
|
+
argument_shapes_truncated: values.length > MAX_ARGUMENT_SHAPES,
|
|
180
|
+
...details,
|
|
181
|
+
});
|
|
182
|
+
})();
|
|
183
|
+
|
|
184
|
+
const patchEmitter = (emitter, observeEvent) => {
|
|
185
|
+
if (emitter === null || emitter === undefined) return;
|
|
186
|
+
const original = emitter.emit;
|
|
187
|
+
if (typeof original !== "function") return;
|
|
188
|
+
if (emitter.__reaElectronActiveEmitPatched === true) return;
|
|
189
|
+
try {
|
|
190
|
+
emitter.__reaElectronActiveEmitPatched = true;
|
|
191
|
+
emitter.emit = function patchedEmit(event, ...args) {
|
|
192
|
+
if (typeof event === "string") observeEvent.call(this, event, args);
|
|
193
|
+
return original.call(this, event, ...args);
|
|
194
|
+
};
|
|
195
|
+
} catch {
|
|
196
|
+
globalThis.__reaElectronActiveHookError = true;
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const recordInvocation = (kind, channel, event, args) =>
|
|
201
|
+
recordIpc(kind, channel, args, {
|
|
202
|
+
direction: "renderer-to-main",
|
|
203
|
+
sender: identity(event?.sender, "webContents"),
|
|
204
|
+
receiver: "main",
|
|
205
|
+
frame: frameIdentity(event),
|
|
206
|
+
process_type: "main",
|
|
207
|
+
error: false,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const patchIpcMain = (ipcMain) => {
|
|
211
|
+
if (ipcMain === null || ipcMain === undefined) return;
|
|
212
|
+
for (const [method, kind] of [
|
|
213
|
+
["handle", "main-handler-invocation"],
|
|
214
|
+
["on", "main-event-invocation"],
|
|
215
|
+
["once", "main-event-invocation"],
|
|
216
|
+
]) {
|
|
217
|
+
const original = ipcMain[method];
|
|
218
|
+
if (typeof original !== "function") continue;
|
|
219
|
+
ipcMain[method] = function patchedIpcMain(channel, listener) {
|
|
220
|
+
if (typeof listener !== "function")
|
|
221
|
+
return original.call(this, channel, listener);
|
|
222
|
+
const wrapped =
|
|
223
|
+
kind === "main-handler-invocation"
|
|
224
|
+
? async function wrappedHandler(event, ...args) {
|
|
225
|
+
const recorded = recordInvocation(kind, channel, event, args);
|
|
226
|
+
try {
|
|
227
|
+
const result = await listener.call(this, event, ...args);
|
|
228
|
+
if (recorded !== null) recorded.result_shape = shape(result);
|
|
229
|
+
return result;
|
|
230
|
+
} catch (cause) {
|
|
231
|
+
if (recorded !== null) recorded.error = true;
|
|
232
|
+
throw cause;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
: function wrappedEventListener(event, ...args) {
|
|
236
|
+
const recorded = recordInvocation(kind, channel, event, args);
|
|
237
|
+
try {
|
|
238
|
+
return listener.call(this, event, ...args);
|
|
239
|
+
} catch (cause) {
|
|
240
|
+
if (recorded !== null) recorded.error = true;
|
|
241
|
+
throw cause;
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
return original.call(this, channel, wrapped);
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
const patchNavigationMethods = (webContents, contentsId) => {
|
|
250
|
+
for (const method of ["loadURL", "loadFile", "loadDataURL"]) {
|
|
251
|
+
const original = webContents[method];
|
|
252
|
+
if (typeof original !== "function") continue;
|
|
253
|
+
webContents[method] = function patchedNavigation(...args) {
|
|
254
|
+
recordRuntime("navigation", method, "attempted", {
|
|
255
|
+
target: contentsId,
|
|
256
|
+
argument_shapes: args.map((value) => shape(value)),
|
|
257
|
+
});
|
|
258
|
+
if (method === "loadURL" && !isAllowedNavigation(args[0])) {
|
|
259
|
+
recordRuntime("navigation", method, "blocked", {
|
|
260
|
+
target: contentsId,
|
|
261
|
+
error: true,
|
|
262
|
+
});
|
|
263
|
+
return Promise.reject(new Error("External navigation is blocked"));
|
|
264
|
+
}
|
|
265
|
+
try {
|
|
266
|
+
const result = original.apply(this, args);
|
|
267
|
+
if (result !== null && typeof result?.then === "function")
|
|
268
|
+
return result.then(
|
|
269
|
+
(value) => {
|
|
270
|
+
recordRuntime("navigation", method, "completed", {
|
|
271
|
+
target: contentsId,
|
|
272
|
+
});
|
|
273
|
+
return value;
|
|
274
|
+
},
|
|
275
|
+
(cause) => {
|
|
276
|
+
recordRuntime("navigation", method, "failed", {
|
|
277
|
+
target: contentsId,
|
|
278
|
+
error: true,
|
|
279
|
+
});
|
|
280
|
+
throw cause;
|
|
281
|
+
},
|
|
282
|
+
);
|
|
283
|
+
recordRuntime("navigation", method, "completed", {
|
|
284
|
+
target: contentsId,
|
|
285
|
+
});
|
|
286
|
+
return result;
|
|
287
|
+
} catch (cause) {
|
|
288
|
+
recordRuntime("navigation", method, "failed", {
|
|
289
|
+
target: contentsId,
|
|
290
|
+
error: true,
|
|
291
|
+
});
|
|
292
|
+
throw cause;
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
const patchWebContentsIpc = (webContents, contentsId) => {
|
|
299
|
+
const originalSend = webContents.send;
|
|
300
|
+
if (typeof originalSend === "function")
|
|
301
|
+
webContents.send = function patchedSend(channel, ...args) {
|
|
302
|
+
const recorded = recordIpc("ipc-main-to-renderer", channel, args, {
|
|
303
|
+
direction: "main-to-renderer",
|
|
304
|
+
sender: "main",
|
|
305
|
+
receiver: contentsId,
|
|
306
|
+
target: contentsId,
|
|
307
|
+
process_type: "main",
|
|
308
|
+
error: false,
|
|
309
|
+
});
|
|
310
|
+
try {
|
|
311
|
+
const result = originalSend.call(this, channel, ...args);
|
|
312
|
+
if (recorded !== null) recorded.result_shape = shape(result);
|
|
313
|
+
return result;
|
|
314
|
+
} catch (cause) {
|
|
315
|
+
if (recorded !== null) recorded.error = true;
|
|
316
|
+
throw cause;
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
const originalPostMessage = webContents.postMessage;
|
|
320
|
+
if (typeof originalPostMessage === "function")
|
|
321
|
+
webContents.postMessage = function patchedPostMessage(
|
|
322
|
+
channel,
|
|
323
|
+
message,
|
|
324
|
+
transfer,
|
|
325
|
+
) {
|
|
326
|
+
const recorded = recordIpc(
|
|
327
|
+
"ipc-main-to-renderer",
|
|
328
|
+
channel,
|
|
329
|
+
[message, transfer],
|
|
330
|
+
{
|
|
331
|
+
direction: "main-to-renderer",
|
|
332
|
+
sender: "main",
|
|
333
|
+
receiver: contentsId,
|
|
334
|
+
target: contentsId,
|
|
335
|
+
process_type: "main",
|
|
336
|
+
error: false,
|
|
337
|
+
},
|
|
338
|
+
);
|
|
339
|
+
try {
|
|
340
|
+
const result = originalPostMessage.call(
|
|
341
|
+
this,
|
|
342
|
+
channel,
|
|
343
|
+
message,
|
|
344
|
+
transfer,
|
|
345
|
+
);
|
|
346
|
+
if (recorded !== null) recorded.result_shape = shape(result);
|
|
347
|
+
return result;
|
|
348
|
+
} catch (cause) {
|
|
349
|
+
if (recorded !== null) recorded.error = true;
|
|
350
|
+
throw cause;
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
const patchWebContents = (webContents, windowId) => {
|
|
356
|
+
if (webContents === null || webContents === undefined) return;
|
|
357
|
+
const contentsId = identity(webContents, "webContents");
|
|
358
|
+
patchEmitter(webContents, (event, args) => {
|
|
359
|
+
const navigation = [
|
|
360
|
+
"did-start-loading",
|
|
361
|
+
"did-stop-loading",
|
|
362
|
+
"did-finish-load",
|
|
363
|
+
"did-fail-load",
|
|
364
|
+
"did-frame-finish-load",
|
|
365
|
+
"will-navigate",
|
|
366
|
+
"will-redirect",
|
|
367
|
+
].includes(event);
|
|
368
|
+
const kind = navigation
|
|
369
|
+
? "navigation"
|
|
370
|
+
: [
|
|
371
|
+
"console-message",
|
|
372
|
+
"render-process-gone",
|
|
373
|
+
"crashed",
|
|
374
|
+
"unresponsive",
|
|
375
|
+
"responsive",
|
|
376
|
+
].includes(event)
|
|
377
|
+
? "error"
|
|
378
|
+
: event === "did-create-window"
|
|
379
|
+
? "popup-attempt"
|
|
380
|
+
: "web-contents-lifecycle";
|
|
381
|
+
if (event === "will-navigate" || event === "will-redirect") {
|
|
382
|
+
if (!isAllowedNavigation(args[1])) {
|
|
383
|
+
const preventDefault = args[0]?.preventDefault;
|
|
384
|
+
if (typeof preventDefault === "function") preventDefault.call(args[0]);
|
|
385
|
+
recordRuntime("navigation", event, "blocked", {
|
|
386
|
+
target: contentsId,
|
|
387
|
+
sender: windowId,
|
|
388
|
+
argument_shapes: args.map((value) => shape(value)),
|
|
389
|
+
error: true,
|
|
390
|
+
});
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
recordRuntime(kind, event, "observed", {
|
|
395
|
+
target: contentsId,
|
|
396
|
+
sender: windowId,
|
|
397
|
+
argument_shapes: args.map((value) => shape(value)),
|
|
398
|
+
error: kind === "error",
|
|
399
|
+
});
|
|
400
|
+
if (event === "did-create-window") {
|
|
401
|
+
const childWindow = args[0];
|
|
402
|
+
patchWebContents(
|
|
403
|
+
childWindow?.webContents,
|
|
404
|
+
identity(childWindow, "window"),
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
patchNavigationMethods(webContents, contentsId);
|
|
409
|
+
patchWebContentsIpc(webContents, contentsId);
|
|
410
|
+
boundaries.patchWindowOpenHandler(webContents, contentsId);
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
const patchBrowserWindow = (electron) => {
|
|
414
|
+
const original = electron.BrowserWindow;
|
|
415
|
+
if (typeof original !== "function") return;
|
|
416
|
+
electron.BrowserWindow = new Proxy(original, {
|
|
417
|
+
construct(target, args, newTarget) {
|
|
418
|
+
const window = Reflect.construct(target, args, newTarget);
|
|
419
|
+
const targetId = identity(window, "window");
|
|
420
|
+
recordRuntime("window-lifecycle", "created", "completed", {
|
|
421
|
+
target: targetId,
|
|
422
|
+
argument_shapes: args.map((value) => shape(value)),
|
|
423
|
+
});
|
|
424
|
+
const preload = args[0]?.webPreferences?.preload;
|
|
425
|
+
if (typeof preload === "string")
|
|
426
|
+
recordRuntime("preload", "configured", "completed", {
|
|
427
|
+
target: targetId,
|
|
428
|
+
artifact_path: preload,
|
|
429
|
+
});
|
|
430
|
+
patchEmitter(window, (event) =>
|
|
431
|
+
recordRuntime("window-lifecycle", event, "observed", {
|
|
432
|
+
target: targetId,
|
|
433
|
+
}),
|
|
434
|
+
);
|
|
435
|
+
patchWebContents(window.webContents, targetId);
|
|
436
|
+
return window;
|
|
437
|
+
},
|
|
438
|
+
});
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
const boundaries = createElectronActiveBoundaryPatches({
|
|
442
|
+
identity,
|
|
443
|
+
patchEmitter,
|
|
444
|
+
processType,
|
|
445
|
+
recordIpc,
|
|
446
|
+
recordRuntime,
|
|
447
|
+
shape,
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
try {
|
|
451
|
+
const electron = require("electron");
|
|
452
|
+
patchEmitter(electron.app, (event, args) =>
|
|
453
|
+
recordRuntime(
|
|
454
|
+
event === "open-url" || event === "second-instance"
|
|
455
|
+
? "protocol"
|
|
456
|
+
: "app-lifecycle",
|
|
457
|
+
event,
|
|
458
|
+
"observed",
|
|
459
|
+
{
|
|
460
|
+
target: "app",
|
|
461
|
+
argument_shapes: args.map((value) => shape(value)),
|
|
462
|
+
process_type: "main",
|
|
463
|
+
},
|
|
464
|
+
),
|
|
465
|
+
);
|
|
466
|
+
patchIpcMain(electron.ipcMain);
|
|
467
|
+
boundaries.patchIpcRenderer(electron.ipcRenderer);
|
|
468
|
+
boundaries.patchContextBridge(electron.contextBridge);
|
|
469
|
+
patchBrowserWindow(electron);
|
|
470
|
+
boundaries.patchUtilityProcess(electron.utilityProcess);
|
|
471
|
+
boundaries.patchShell(electron.shell);
|
|
472
|
+
boundaries.patchSessionManager(electron.session);
|
|
473
|
+
boundaries.patchApplicationEffects(electron.app);
|
|
474
|
+
boundaries.patchNativeAddonLoading();
|
|
475
|
+
boundaries.patchChildProcess();
|
|
476
|
+
process.once("uncaughtException", (cause, origin) => {
|
|
477
|
+
recordRuntime("process-lifecycle", "uncaught-exception", "observed", {
|
|
478
|
+
argument_shapes: [shape(cause), shape(origin)],
|
|
479
|
+
error: true,
|
|
480
|
+
});
|
|
481
|
+
throw cause;
|
|
482
|
+
});
|
|
483
|
+
process.once("unhandledRejection", (reason, promise) => {
|
|
484
|
+
recordRuntime("process-lifecycle", "unhandled-rejection", "observed", {
|
|
485
|
+
argument_shapes: [shape(reason), shape(promise)],
|
|
486
|
+
error: true,
|
|
487
|
+
});
|
|
488
|
+
throw reason;
|
|
489
|
+
});
|
|
490
|
+
} catch {
|
|
491
|
+
globalThis.__reaElectronActiveHookError = true;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
globalThis.__reaElectronActiveSnapshot = () => ({
|
|
495
|
+
events: events.slice(),
|
|
496
|
+
observed,
|
|
497
|
+
observed_ipc: observedIpc,
|
|
498
|
+
observed_runtime: observedRuntime,
|
|
499
|
+
truncated,
|
|
500
|
+
hook_error: globalThis.__reaElectronActiveHookError === true,
|
|
501
|
+
});
|
|
@@ -3,8 +3,8 @@ name: reverse-engineer-anything
|
|
|
3
3
|
description: Reverse engineer native, managed, Electron/JavaScript, packaged, and browser applications with REA. Use shipped-artifact or approved runtime evidence to explain features, compare versions, decompile code, or guide a reconstruction. Skip REA for ordinary source-repository architecture analysis.
|
|
4
4
|
metadata:
|
|
5
5
|
version: "23"
|
|
6
|
-
tool_count:
|
|
7
|
-
catalog_digest: "
|
|
6
|
+
tool_count: 116
|
|
7
|
+
catalog_digest: "bab5657d9525ec4f798d0a9ef6001412d9c11f77fb0ddc925c7076fd10921dc9"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# REA
|
|
@@ -23,7 +23,8 @@ Choose the first tool from the target the user supplied. Do not call
|
|
|
23
23
|
- ASAR or extracted JavaScript/Electron tree:
|
|
24
24
|
`analyze_javascript_application`.
|
|
25
25
|
- Archive, application package, ZIP/APK/IPA/MSIX/AppX, or DMG:
|
|
26
|
-
`
|
|
26
|
+
`open_binary` with the supplied local path, then `inspect_artifact` or
|
|
27
|
+
`inventory_artifact` (both operate on the active target and accept no path).
|
|
27
28
|
- Managed PE/CLI assembly: `inspect_managed_artifact`.
|
|
28
29
|
- User-owned browser page already open: `list_browser_targets`.
|
|
29
30
|
- User-owned Electron runtime already open: `list_electron_targets`.
|
|
@@ -34,6 +35,12 @@ If the app is missing, ask which app to inspect. Resolve a human-readable app
|
|
|
34
35
|
name to one clear installed artifact when possible; ask only when matches are
|
|
35
36
|
ambiguous. Never choose an example app on the user's behalf.
|
|
36
37
|
|
|
38
|
+
In a target-free session, use `open_binary` to bind any archive/package or
|
|
39
|
+
native target whose analysis tool operates on the active target. Do not call a
|
|
40
|
+
tool hidden from `tools/list`; inspect `binary_session` with
|
|
41
|
+
`detail: "capabilities"` for the exact remediation when a desired capability
|
|
42
|
+
is unavailable.
|
|
43
|
+
|
|
37
44
|
## Work summary-first
|
|
38
45
|
|
|
39
46
|
Start with the default summary projection. Do not repeat an identical tool call.
|
|
@@ -1,70 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { AnalysisInputError, } from "../domain/errors.js";
|
|
3
|
-
import { projectInputIssues } from "../domain/inputIssueProjection.js";
|
|
4
|
-
import { err, ok } from "../domain/result.js";
|
|
5
|
-
import { closeObjectSchemas } from "./toolRegistrationOptions.js";
|
|
6
|
-
/** Parse one MCP request exactly once and retain only schema-owned correction data. */
|
|
7
|
-
export const safeParseToolInput = (schema, input, operation) => {
|
|
8
|
-
const unknownIssues = unknownArgumentIssues(schema, input);
|
|
9
|
-
if (unknownIssues.length > 0)
|
|
10
|
-
return err(new AnalysisInputError(operation, undefined, unknownIssues));
|
|
11
|
-
const parsed = schema.safeParse(input);
|
|
12
|
-
return parsed.success
|
|
13
|
-
? ok(parsed.data)
|
|
14
|
-
: err(new AnalysisInputError(operation, undefined, projectInputIssues(parsed.error.issues, input)));
|
|
15
|
-
};
|
|
16
|
-
const schemaCache = new WeakMap();
|
|
17
|
-
const unknownArgumentIssues = (schema, input) => {
|
|
18
|
-
let jsonSchema = schemaCache.get(schema);
|
|
19
|
-
if (jsonSchema === undefined) {
|
|
20
|
-
const converter = schema["~standard"].jsonSchema?.input;
|
|
21
|
-
if (converter === undefined)
|
|
22
|
-
throw new TypeError("Tool input schema does not expose Standard JSON Schema");
|
|
23
|
-
jsonSchema = closeObjectSchemas(converter({ target: "draft-2020-12" }));
|
|
24
|
-
schemaCache.set(schema, jsonSchema);
|
|
25
|
-
}
|
|
26
|
-
return scanUnknownArguments(input, jsonSchema, jsonSchema, []);
|
|
27
|
-
};
|
|
28
|
-
const scanUnknownArguments = (value, schema, root, path) => {
|
|
29
|
-
const resolved = resolveSchema(schema, root);
|
|
30
|
-
if (Array.isArray(value)) {
|
|
31
|
-
const items = objectValue(resolved.items);
|
|
32
|
-
return items === undefined
|
|
33
|
-
? []
|
|
34
|
-
: value.flatMap((item, index) => scanUnknownArguments(item, items, root, [...path, index]));
|
|
35
|
-
}
|
|
36
|
-
if (!isObject(value))
|
|
37
|
-
return [];
|
|
38
|
-
const variants = schemaVariants(resolved, root);
|
|
39
|
-
const properties = Object.fromEntries(variants.flatMap((variant) => Object.entries(objectValue(variant.properties) ?? {})));
|
|
40
|
-
const closed = variants.length > 0 &&
|
|
41
|
-
variants.every((variant) => variant.additionalProperties !== true &&
|
|
42
|
-
!isObject(variant.additionalProperties));
|
|
43
|
-
const issues = [];
|
|
44
|
-
for (const [key, child] of Object.entries(value)) {
|
|
45
|
-
const propertySchema = objectValue(properties[key]);
|
|
46
|
-
if (propertySchema === undefined) {
|
|
47
|
-
if (closed)
|
|
48
|
-
issues.push({ path: [...path, key], reason: "unknown_argument" });
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
issues.push(...scanUnknownArguments(child, propertySchema, root, [...path, key]));
|
|
52
|
-
}
|
|
53
|
-
return issues;
|
|
54
|
-
};
|
|
55
|
-
const schemaVariants = (schema, root) => {
|
|
56
|
-
const resolved = resolveSchema(schema, root);
|
|
57
|
-
const variants = [resolved.oneOf, resolved.anyOf, resolved.allOf]
|
|
58
|
-
.flatMap((value) => (Array.isArray(value) ? value : []))
|
|
59
|
-
.flatMap((value) => {
|
|
60
|
-
const object = objectValue(value);
|
|
61
|
-
return object === undefined ? [] : schemaVariants(object, root);
|
|
62
|
-
});
|
|
63
|
-
if (variants.length > 0)
|
|
64
|
-
return variants;
|
|
65
|
-
return resolved.type === "object" || isObject(resolved.properties)
|
|
66
|
-
? [resolved]
|
|
67
|
-
: [];
|
|
68
|
-
};
|
|
69
|
-
const resolveSchema = (schema, root) => {
|
|
70
|
-
const reference = schema.$ref;
|
|
71
|
-
if (typeof reference !== "string" || !reference.startsWith("#/$defs/"))
|
|
72
|
-
return schema;
|
|
73
|
-
const definition = objectValue(objectValue(root.$defs)?.[reference.slice(8)]);
|
|
74
|
-
return definition === undefined ? schema : definition;
|
|
75
|
-
};
|
|
76
|
-
const isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
77
|
-
const objectValue = (value) => isObject(value) ? value : undefined;
|