rea-agents 3.0.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 +14 -16
- package/dist/application/AnalysisContextQueries.js +21 -9
- 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 +14 -16
- package/dist/application/BinarySessionRecords.js +31 -5
- 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 +134 -63
- package/dist/application/CrossVersionInventory.js +7 -6
- 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 +22 -20
- package/dist/application/EvidenceBundleCommands.js +5 -1
- package/dist/application/EvidenceLedger.js +8 -1
- package/dist/application/JavaScriptReplayPermission.js +1 -1
- package/dist/application/JavaScriptReplayService.js +23 -15
- package/dist/application/ManagedRuntimeCorrelationService.js +9 -5
- 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/SetupClientConfiguration.js +6 -1
- package/dist/application/WindowsCapabilities.js +5 -4
- 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/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 +12 -6
- 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 +1 -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 +27 -34
- package/dist/contracts/browserToolContracts.js +2 -2
- package/dist/contracts/electronToolContracts.js +30 -1
- package/dist/contracts/enhancedInputs.js +13 -29
- package/dist/contracts/functionWorkflowToolContracts.js +2 -3
- 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/sessionToolSchemas.js +61 -0
- package/dist/contracts/toolContractExamples.js +1 -0
- package/dist/contracts/toolContractHelpers.js +23 -0
- package/dist/contracts/toolContracts.js +5 -77
- package/dist/contracts/toolEffects.js +15 -0
- package/dist/contracts/toolOutputSchemaGroups.js +17 -2
- package/dist/contracts/toolOutputSchemaPrimitives.js +76 -26
- package/dist/contracts/toolSchemaMetadata.js +128 -0
- package/dist/doctorRuntime.js +1 -1
- 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 +33 -35
- package/dist/domain/callPath.js +3 -2
- package/dist/domain/conformanceReplay.js +3 -3
- package/dist/domain/conformanceTrustGate.js +151 -16
- package/dist/domain/customProtocolCapture.js +3 -3
- 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 +82 -79
- package/dist/domain/functionComparisonNormalization.js +15 -8
- package/dist/domain/functionDossierEvidence.js +9 -4
- package/dist/domain/hopperValues.js +68 -71
- package/dist/domain/inputIssueProjection.js +4 -1
- 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/knownPageCoverage.js +15 -7
- package/dist/domain/nativeApiBoundary.js +15 -7
- package/dist/domain/nodeRuntimeCharacterization.js +14 -13
- 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 +8 -6
- 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/generatedMcpToolCatalog.js +1 -1
- package/dist/generatedPackageMetadata.js +1 -1
- package/dist/ghidra/GhidraClient.js +1 -1
- package/dist/ghidra/GhidraClientStartup.js +1 -1
- package/dist/ghidra/GhidraFunctionValues.js +17 -15
- package/dist/ghidra/GhidraInventoryValues.js +57 -47
- package/dist/ghidra/GhidraProvider.js +18 -10
- package/dist/ghidra/GhidraProviderCapabilities.js +5 -1
- 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 +1 -1
- package/dist/hopper/HopperProvider.js +0 -14
- package/dist/hopper/LinuxPrivateDisplayProbe.js +16 -10
- package/dist/main/reload.js +1 -6
- package/dist/main/state.js +0 -14
- package/dist/main/transport.js +30 -37
- package/dist/main.js +17 -15
- package/dist/mcpDoctor.js +2 -24
- 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 +158 -94
- 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 +114 -122
- package/dist/server/registerEvidenceTools.js +5 -9
- package/dist/server/registerFunctionComparisonTool.js +11 -15
- package/dist/server/registerInvestigationTools.js +41 -57
- 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/registerReplayMachineTool.js +4 -10
- package/dist/server/registerSessionRecordTools.js +69 -40
- package/dist/server/registerSessionStatusTool.js +13 -28
- package/dist/server/registerSessionTools.js +36 -52
- package/dist/server/sessionAvailabilityPolicy.js +2 -1
- package/dist/server/sessionToolPolicies.js +1 -5
- package/dist/server/toolRegistrationOptions.js +4 -192
- package/dist/server/toolResult.js +2 -18
- package/package.json +22 -14
- package/scripts/electron-active-hook-boundaries.cjs +394 -0
- package/scripts/electron-active-hook.cjs +501 -0
- package/scripts/rea.mjs +1 -11
- package/skills/reverse-engineer-anything/SKILL.md +2 -2
- package/dist/server/DynamicToolAvailability.js +0 -70
- package/dist/server/LazyToolCatalog.js +0 -134
- package/dist/server/hydrateServerTools.js +0 -191
- package/dist/server/toolInputValidation.js +0 -77
- package/scripts/package-runner-bootstrap.mjs +0 -72
|
@@ -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
|
+
});
|
package/scripts/rea.mjs
CHANGED
|
@@ -4,8 +4,6 @@ import { access } from "node:fs/promises";
|
|
|
4
4
|
import { dirname, resolve } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
|
|
7
|
-
import { runPackageRunnerSetupBootstrap } from "./package-runner-bootstrap.mjs";
|
|
8
|
-
|
|
9
7
|
// Route production MCP before importing Incur. Incur owns registration helpers
|
|
10
8
|
// such as `mcp add`, while only dist/main.js may serve the stdio tool catalog.
|
|
11
9
|
const args = process.argv.slice(2);
|
|
@@ -17,21 +15,13 @@ const isMcpMode =
|
|
|
17
15
|
args.length === 1 && (args[0] === "--mcp" || args[0] === "mcp");
|
|
18
16
|
const isMcpDoctorMode = args[0] === "mcp" && args[1] === "doctor";
|
|
19
17
|
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
20
|
-
const bootstrapExitCode = await runPackageRunnerSetupBootstrap({
|
|
21
|
-
args,
|
|
22
|
-
environment: process.env,
|
|
23
|
-
packageRoot,
|
|
24
|
-
packageName: packageJson.name,
|
|
25
|
-
});
|
|
26
18
|
const runtimeFiles = isMcpMode
|
|
27
19
|
? ["dist/main.js"]
|
|
28
20
|
: isMcpDoctorMode
|
|
29
21
|
? ["dist/main.js", "dist/mcpDoctor.js"]
|
|
30
22
|
: ["dist/cli.js", "dist/cliOutput.js"];
|
|
31
23
|
|
|
32
|
-
if (
|
|
33
|
-
process.exitCode = bootstrapExitCode;
|
|
34
|
-
} else if (!(await compiledRuntimeExists(runtimeFiles))) {
|
|
24
|
+
if (!(await compiledRuntimeExists(runtimeFiles))) {
|
|
35
25
|
process.stderr.write(
|
|
36
26
|
`REA's compiled runtime is missing. Run \`npm ci\` in ${packageRoot} to install dependencies and build REA, then restart it. If this is an installed package, reinstall rea-agents.\n`,
|
|
37
27
|
);
|
|
@@ -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
|
|
@@ -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
|
-
};
|