rea-agents 1.4.0 → 1.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 +34 -12
- package/dist/application/AnalysisSnapshotCache.js +8 -6
- package/dist/application/ArtifactGraphConstruction.js +11 -2
- package/dist/application/ArtifactInventory.js +3 -2
- package/dist/application/AuthorizedArtifactInventory.js +2 -1
- package/dist/application/BinarySession.js +12 -7
- package/dist/application/BoundedJsonFiles.js +6 -29
- package/dist/application/BrowserEvidence.js +35 -0
- package/dist/application/BrowserObservationPort.js +1 -0
- package/dist/application/BrowserObservationService.js +52 -0
- package/dist/application/CapabilityInventory.js +7 -0
- package/dist/application/ConfiguredRoots.js +19 -0
- package/dist/application/CrossVersionInvestigation.js +6 -0
- package/dist/application/DeferredFileAuthorization.js +61 -0
- package/dist/application/DirectAnalysis.js +38 -18
- package/dist/application/EvidenceLedger.js +6 -5
- package/dist/application/InvestigationWorkspaceStore.js +2 -26
- package/dist/application/ProcessCaptureAuthority.js +3 -2
- package/dist/application/ProcessCaptureLifecycle.js +18 -8
- package/dist/application/ProcessCheckpoints.js +1 -1
- package/dist/application/ProcessCli.js +17 -5
- package/dist/application/ProcessHarness.js +6 -19
- package/dist/application/ProcessNormalization.js +17 -2
- package/dist/application/ProcessOwnership.js +4 -3
- package/dist/application/ProcessSampling.js +52 -17
- package/dist/application/ProjectPermissionStore.js +106 -3
- package/dist/application/ReferenceSourceImportPolicy.js +3 -2
- package/dist/application/TerminalRenderer.js +1 -1
- package/dist/artifacts/MachOSliceArtifactReader.js +1 -1
- package/dist/artifacts/NativeDmgArtifactReader.js +1 -1
- package/dist/artifacts/SafeOutputTree.js +3 -3
- package/dist/browser/CdpBrowserProvider.js +158 -0
- package/dist/browser/CdpCaptureDocuments.js +140 -0
- package/dist/browser/CdpCaptureEvents.js +248 -0
- package/dist/browser/CdpCaptureStorage.js +53 -0
- package/dist/browser/CdpCaptureValues.js +70 -0
- package/dist/browser/CdpConnection.js +218 -0
- package/dist/browser/CdpEndpoint.js +114 -0
- package/dist/browser/CdpOptionalCommand.js +15 -0
- package/dist/browser/CdpPageCapture.js +273 -0
- package/dist/catalogIdentity.js +2 -0
- package/dist/cli.js +2 -0
- package/dist/cliBrowserCommands.js +136 -0
- package/dist/cliInvestigationCommands.js +19 -34
- package/dist/cliPolicyCommands.js +13 -10
- package/dist/config.js +44 -0
- package/dist/contracts/browserToolContracts.js +80 -0
- package/dist/contracts/errorSchemas.js +2 -0
- package/dist/contracts/toolContracts.js +3 -5
- package/dist/domain/browserObservation.js +361 -0
- package/dist/domain/changedBehavior.js +4 -15
- package/dist/domain/errors.js +41 -0
- package/dist/domain/jsonLimits.js +26 -0
- package/dist/domain/permissionPolicy.js +6 -2
- package/dist/domain/processCapture.js +3 -1
- package/dist/domain/processComparison.js +22 -34
- package/dist/domain/reconstructionVerification.js +2 -15
- package/dist/domain/reconstructionVerificationSchemas.js +2 -0
- package/dist/domain/staticRuntimeCorrelation.js +2 -0
- package/dist/domain/symbolAnalysis.js +1 -1
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/main.js +6 -0
- package/dist/native/CommandRunner.js +11 -4
- package/dist/server/createServer.js +7 -0
- package/dist/server/registerBrowserTools.js +36 -0
- package/dist/server/registerInvestigationTools.js +30 -35
- package/dist/server/registerProcessComparisonTool.js +2 -0
- package/dist/server/registerSessionTools.js +15 -2
- package/dist/server/runDerivedOperation.js +10 -2
- package/package.json +2 -1
- package/scripts/rea.mjs +1 -1
- package/skills/rea-analysis/SKILL.md +18 -3
|
@@ -7,7 +7,7 @@ import { parseEvidence } from "./evidence.js";
|
|
|
7
7
|
import { parseEvidenceBundle } from "./evidenceBundle.js";
|
|
8
8
|
import { functionComparisonResultSchema } from "./functionComparison.js";
|
|
9
9
|
import { functionDossierSchema } from "./hopperValues.js";
|
|
10
|
-
import { processCaptureComparisonSchema, processCaptureSchema, } from "./processCapture.js";
|
|
10
|
+
import { deriveProcessComparisonStatus, PROCESS_COMPARISON_DIMENSIONS, processCaptureComparisonSchema, processCaptureSchema, } from "./processCapture.js";
|
|
11
11
|
import { reconstructionClaimResultSchema, reconstructionSpecificationSchema, reconstructionVerificationResultSchema, } from "./reconstructionVerificationSchemas.js";
|
|
12
12
|
import { reconstructionClaimUnknowns, reconstructionProbes, reconstructionUnknownHeads, } from "./reconstructionUnknowns.js";
|
|
13
13
|
const evidenceIdSchema = z.string().regex(/^ev_[a-f0-9]{64}$/u);
|
|
@@ -219,20 +219,7 @@ const observedStatus = (claim, evidence) => {
|
|
|
219
219
|
return result.status;
|
|
220
220
|
};
|
|
221
221
|
const validateProcessStatus = (result) => {
|
|
222
|
-
const
|
|
223
|
-
result.terminal,
|
|
224
|
-
result.exit,
|
|
225
|
-
result.filesystem,
|
|
226
|
-
result.protocol,
|
|
227
|
-
result.process,
|
|
228
|
-
];
|
|
229
|
-
const expected = dimensions.includes("truncated")
|
|
230
|
-
? "truncated"
|
|
231
|
-
: dimensions.some((status) => ["added", "removed", "changed"].includes(status))
|
|
232
|
-
? "changed"
|
|
233
|
-
: dimensions.includes("unknown")
|
|
234
|
-
? "unknown"
|
|
235
|
-
: "unchanged";
|
|
222
|
+
const expected = deriveProcessComparisonStatus(PROCESS_COMPARISON_DIMENSIONS.map((dimension) => result[dimension]));
|
|
236
223
|
if (result.status !== expected)
|
|
237
224
|
throw new TypeError("Process comparison status contradicts its dimensions");
|
|
238
225
|
};
|
|
@@ -18,10 +18,12 @@ const functionDimensionSchema = z.enum([
|
|
|
18
18
|
]);
|
|
19
19
|
const runtimeDimensionSchema = z.enum([
|
|
20
20
|
"terminal",
|
|
21
|
+
"interaction",
|
|
21
22
|
"exit",
|
|
22
23
|
"filesystem",
|
|
23
24
|
"protocol",
|
|
24
25
|
"process",
|
|
26
|
+
"shim",
|
|
25
27
|
]);
|
|
26
28
|
const expectedPatternSchema = z.enum([
|
|
27
29
|
"cochanged",
|
|
@@ -14,7 +14,7 @@ export const discoverSwiftClasses = (procedures, pattern) => {
|
|
|
14
14
|
/** Select and deduplicate Objective-C class labels. */
|
|
15
15
|
export const discoverObjcClasses = (names, pattern) => {
|
|
16
16
|
const classes = uniqueByName(names
|
|
17
|
-
.filter(({ name }) => ["OBJC_CLASS", "OBJC_$_CLASS"].some((marker) => name.includes(marker))
|
|
17
|
+
.filter(({ name }) => ["OBJC_CLASS", "OBJC_$_CLASS"].some((marker) => name.includes(marker)))
|
|
18
18
|
.filter(({ name }) => pattern.length === 0 || name.includes(pattern)));
|
|
19
19
|
return {
|
|
20
20
|
count: classes.length,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/** Generated from package.json and package-lock.json; do not edit. */
|
|
2
2
|
export const PACKAGE_METADATA = {
|
|
3
3
|
name: "rea-agents",
|
|
4
|
-
version: "1.
|
|
4
|
+
version: "1.5.0",
|
|
5
5
|
serverSdkVersion: "2.0.0-beta.4",
|
|
6
6
|
clientSdkVersion: "2.0.0-beta.4",
|
|
7
7
|
coreSdkVersion: "2.0.0-beta.4",
|
|
8
|
-
skillVersion: "
|
|
8
|
+
skillVersion: "13",
|
|
9
9
|
};
|
package/dist/main.js
CHANGED
|
@@ -9,6 +9,7 @@ import { createLogger } from "./logger.js";
|
|
|
9
9
|
import { projectAnalysisError } from "./domain/errors.js";
|
|
10
10
|
import { readProjectPermissionStore } from "./application/ProjectPermissionStore.js";
|
|
11
11
|
import { loadConfiguredPermissionAuthority } from "./application/PermissionConfiguration.js";
|
|
12
|
+
import { CdpBrowserProvider } from "./browser/CdpBrowserProvider.js";
|
|
12
13
|
const MCP_CONNECTION_LOST = "REA lost its MCP client connection. Restart REA from your MCP client.";
|
|
13
14
|
const MCP_CONNECTION_START_FAILED = "REA could not start its MCP connection. Restart REA from your MCP client; run `rea doctor` if it fails again.";
|
|
14
15
|
const MCP_SHUTDOWN_FAILED = "REA could not close cleanly. End the REA process before starting it again.";
|
|
@@ -50,6 +51,7 @@ export const run = async (dependencies = runtimeDependencies()) => {
|
|
|
50
51
|
return 1;
|
|
51
52
|
}
|
|
52
53
|
const session = createBinarySession(config.value, logger);
|
|
54
|
+
const browserObservation = new CdpBrowserProvider();
|
|
53
55
|
if (config.value.hopperTargetPath !== undefined) {
|
|
54
56
|
const opened = await session.open(config.value.hopperTargetPath, {
|
|
55
57
|
targetKind: config.value.hopperTargetKind,
|
|
@@ -90,10 +92,14 @@ export const run = async (dependencies = runtimeDependencies()) => {
|
|
|
90
92
|
investigationInputRoots: runtimeInvestigationRoots,
|
|
91
93
|
analysisSnapshotFilePolicy: runtimeSnapshotPolicy,
|
|
92
94
|
permissionAuthority: permissionAuthority.value,
|
|
95
|
+
browserObservation,
|
|
93
96
|
artifactIntegrityContinueEnabled: () => currentConfig.artifactIntegrityContinueEnabled,
|
|
94
97
|
availabilityPolicy: () => ({
|
|
95
98
|
processCaptureEnabled: currentConfig.processExecutionPolicy.enabled,
|
|
96
99
|
evidenceFileRoots: currentConfig.evidenceFilePolicy.roots.length,
|
|
100
|
+
browserObservationEnabled: currentConfig.browserObservationEnabled &&
|
|
101
|
+
currentConfig.browserCdpEndpoints.length > 0 &&
|
|
102
|
+
currentConfig.browserAllowedOrigins.length > 0,
|
|
97
103
|
}),
|
|
98
104
|
});
|
|
99
105
|
liveServers.add(server);
|
|
@@ -16,7 +16,11 @@ export class NativeCommandFailure extends Error {
|
|
|
16
16
|
}
|
|
17
17
|
/** Run allowlisted Xcode tools directly with bounded output and no shell. */
|
|
18
18
|
export class XcrunCommandRunner {
|
|
19
|
+
resolveTool;
|
|
19
20
|
#resolved = new Map();
|
|
21
|
+
constructor(resolveTool = (tool) => resolveXcrunTool(tool)) {
|
|
22
|
+
this.resolveTool = resolveTool;
|
|
23
|
+
}
|
|
20
24
|
run(tool, arguments_, options) {
|
|
21
25
|
if (!ALLOWED_TOOLS.has(tool))
|
|
22
26
|
return Promise.resolve(err(new NativeCommandFailure(tool, "unavailable")));
|
|
@@ -37,13 +41,16 @@ export class XcrunCommandRunner {
|
|
|
37
41
|
: captured;
|
|
38
42
|
});
|
|
39
43
|
}
|
|
40
|
-
#resolve(tool) {
|
|
44
|
+
async #resolve(tool) {
|
|
41
45
|
const existing = this.#resolved.get(tool);
|
|
42
46
|
if (existing !== undefined)
|
|
43
47
|
return existing;
|
|
44
|
-
const pending = resolveTool(tool);
|
|
48
|
+
const pending = this.resolveTool(tool);
|
|
45
49
|
this.#resolved.set(tool, pending);
|
|
46
|
-
|
|
50
|
+
const resolved = await pending;
|
|
51
|
+
if (!resolved.ok && this.#resolved.get(tool) === pending)
|
|
52
|
+
this.#resolved.delete(tool);
|
|
53
|
+
return resolved;
|
|
47
54
|
}
|
|
48
55
|
}
|
|
49
56
|
const ALLOWED_TOOLS = new Set([
|
|
@@ -59,7 +66,7 @@ const ALLOWED_TOOLS = new Set([
|
|
|
59
66
|
"swift-demangle",
|
|
60
67
|
"vtool",
|
|
61
68
|
]);
|
|
62
|
-
const
|
|
69
|
+
const resolveXcrunTool = async (tool) => {
|
|
63
70
|
const found = await captureProcess("/usr/bin/xcrun", ["--find", tool], "xcrun", { timeoutMs: 5_000, maxOutputBytes: 64 * 1024 });
|
|
64
71
|
if (!found.ok || found.value.exitCode !== 0)
|
|
65
72
|
return err(new NativeCommandFailure(tool, "unavailable"));
|
|
@@ -9,6 +9,7 @@ import { silentLogger } from "../logger.js";
|
|
|
9
9
|
import { registerGuidedPrompts } from "./registerPrompts.js";
|
|
10
10
|
import { registerEvidenceResources } from "./registerEvidenceResources.js";
|
|
11
11
|
import { createServerIdentity } from "../serverIdentity.js";
|
|
12
|
+
import { registerBrowserTools } from "./registerBrowserTools.js";
|
|
12
13
|
/**
|
|
13
14
|
* Construct one MCP server without acquiring subprocess resources.
|
|
14
15
|
* Supplying a session adds target lifecycle tools; omitting it retains the
|
|
@@ -93,6 +94,12 @@ export const createServer = (analysis, session, options = {}) => {
|
|
|
93
94
|
? {}
|
|
94
95
|
: { permissionAuthority: options.permissionAuthority }),
|
|
95
96
|
});
|
|
97
|
+
registerBrowserTools(server, {
|
|
98
|
+
logger: toolLogger,
|
|
99
|
+
browser: options.browserObservation,
|
|
100
|
+
permissionAuthority: options.permissionAuthority,
|
|
101
|
+
recordEvidence,
|
|
102
|
+
});
|
|
96
103
|
registerGuidedPrompts(server, analysis, session);
|
|
97
104
|
if (session !== undefined) {
|
|
98
105
|
registerEvidenceResources(server, session);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { inspectWebPage, listBrowserTargets, } from "../application/BrowserObservationService.js";
|
|
2
|
+
import { BROWSER_TOOL_CONTRACTS } from "../contracts/browserToolContracts.js";
|
|
3
|
+
import { inspectWebPageInputSchema, listBrowserTargetsInputSchema, } from "../domain/browserObservation.js";
|
|
4
|
+
import { logToolExecution } from "./toolLogging.js";
|
|
5
|
+
import { toCallToolResult } from "./toolResult.js";
|
|
6
|
+
import { toolRegistrationOptions } from "./toolRegistrationOptions.js";
|
|
7
|
+
import { mcpProgressReporter } from "./mcpProgress.js";
|
|
8
|
+
/** Register browser tools even when policy/provider availability denies execution. */
|
|
9
|
+
export const registerBrowserTools = (server, options) => {
|
|
10
|
+
const [listContract, inspectContract] = BROWSER_TOOL_CONTRACTS;
|
|
11
|
+
server.registerTool(listContract.name, toolRegistrationOptions(listContract), async (input, context) => {
|
|
12
|
+
const parsed = listBrowserTargetsInputSchema.parse(input);
|
|
13
|
+
const result = await logToolExecution(options.logger, listContract.name, () => listBrowserTargets(options.browser, options.permissionAuthority, parsed, { signal: context.mcpReq.signal }));
|
|
14
|
+
if (!result.ok)
|
|
15
|
+
return toCallToolResult(result, listContract);
|
|
16
|
+
return evidenceResult(options, listContract, result.value);
|
|
17
|
+
});
|
|
18
|
+
server.registerTool(inspectContract.name, toolRegistrationOptions(inspectContract), async (input, context) => {
|
|
19
|
+
const parsed = inspectWebPageInputSchema.parse(input);
|
|
20
|
+
const result = await logToolExecution(options.logger, inspectContract.name, () => inspectWebPage(options.browser, options.permissionAuthority, parsed, {
|
|
21
|
+
signal: context.mcpReq.signal,
|
|
22
|
+
progress: mcpProgressReporter(context),
|
|
23
|
+
}));
|
|
24
|
+
if (!result.ok)
|
|
25
|
+
return toCallToolResult(result, inspectContract);
|
|
26
|
+
return evidenceResult(options, inspectContract, result.value);
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
const evidenceResult = (options, contract, evidence) => {
|
|
30
|
+
const recorded = options.recordEvidence?.(evidence);
|
|
31
|
+
return recorded !== undefined && !recorded.ok
|
|
32
|
+
? toCallToolResult(recorded, contract)
|
|
33
|
+
: toCallToolResult({ ok: true, value: evidence }, contract, {
|
|
34
|
+
evidenceResourcesAvailable: recorded !== undefined,
|
|
35
|
+
});
|
|
36
|
+
};
|
|
@@ -10,9 +10,9 @@ import { err, ok } from "../domain/result.js";
|
|
|
10
10
|
import { CALL_PATH_PROVIDER, CHANGED_BEHAVIOR_PROVIDER, RECONSTRUCTION_PROVIDER, STATIC_RUNTIME_PROVIDER, } from "./sessionToolPolicies.js";
|
|
11
11
|
import { toCallToolResult } from "./toolResult.js";
|
|
12
12
|
import { recordDerivedEvidence } from "./recordDerivedEvidence.js";
|
|
13
|
-
import { AnalysisProtocolError, PermissionRequiredError, } from "../domain/errors.js";
|
|
14
13
|
import { mcpProgressReporter } from "./mcpProgress.js";
|
|
15
14
|
import { runDerivedOperation } from "./runDerivedOperation.js";
|
|
15
|
+
import { authorizeFileReadWithDeferredWrite, authorizeRootPermission, } from "../application/DeferredFileAuthorization.js";
|
|
16
16
|
/** Register Evidence-composed differential investigation workflows. */
|
|
17
17
|
export const registerInvestigationTools = (server, session, contracts, policies) => {
|
|
18
18
|
registerChangedBehavior(server, session, contracts[0], policies);
|
|
@@ -33,42 +33,37 @@ const registerChangedBehavior = (server, session, contract, policies) => {
|
|
|
33
33
|
const parsed = changedBehaviorInputSchema.parse(input);
|
|
34
34
|
if (parsed.investigation_run !== undefined) {
|
|
35
35
|
const progress = mcpProgressReporter(context);
|
|
36
|
+
let workspaceAuthorization;
|
|
36
37
|
if (policies.permissionAuthority !== undefined) {
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
executables: [],
|
|
58
|
-
environment_names: [],
|
|
59
|
-
network: "none",
|
|
60
|
-
mount: false,
|
|
61
|
-
operation_identity: `${contract.name}:${scope.capability}:${scope.roots.join(":")}`,
|
|
62
|
-
}, scope.capability === "investigation_input" ? "read" : "write");
|
|
63
|
-
if (!authorized.ok)
|
|
64
|
-
return toCallToolResult(err(authorized.error instanceof PermissionRequiredError
|
|
65
|
-
? authorized.error
|
|
66
|
-
: new AnalysisProtocolError(authorized.error.message, {
|
|
67
|
-
cause: authorized.error,
|
|
68
|
-
})), contract);
|
|
69
|
-
}
|
|
38
|
+
const authorizedWorkspace = await authorizeFileReadWithDeferredWrite(policies.permissionAuthority, {
|
|
39
|
+
path: parsed.investigation_run.workspace_path,
|
|
40
|
+
readCapability: "investigation_workspace_read",
|
|
41
|
+
writeCapability: "investigation_workspace_write",
|
|
42
|
+
operation: contract.name,
|
|
43
|
+
});
|
|
44
|
+
if (!authorizedWorkspace.ok)
|
|
45
|
+
return toCallToolResult(authorizedWorkspace, contract);
|
|
46
|
+
workspaceAuthorization = authorizedWorkspace.value;
|
|
47
|
+
const authorizedInput = await authorizeRootPermission(policies.permissionAuthority, {
|
|
48
|
+
capability: "investigation_input",
|
|
49
|
+
roots: [
|
|
50
|
+
parsed.investigation_run.left_path,
|
|
51
|
+
parsed.investigation_run.right_path,
|
|
52
|
+
],
|
|
53
|
+
access: "read",
|
|
54
|
+
operation: contract.name,
|
|
55
|
+
});
|
|
56
|
+
if (!authorizedInput.ok)
|
|
57
|
+
return toCallToolResult(authorizedInput, contract);
|
|
70
58
|
}
|
|
71
|
-
const investigated = await runCrossVersionInvestigation(parsed.investigation_run, policies.evidenceFiles,
|
|
59
|
+
const investigated = await runCrossVersionInvestigation(parsed.investigation_run, policies.evidenceFiles, {
|
|
60
|
+
...investigationExecution(session, context.mcpReq.signal, policies.inputRoots, policies.integrityContinueEnabled?.() ?? false, progress),
|
|
61
|
+
...(workspaceAuthorization === undefined
|
|
62
|
+
? {}
|
|
63
|
+
: {
|
|
64
|
+
authorizeWorkspaceWrite: workspaceAuthorization.authorizeWrite,
|
|
65
|
+
}),
|
|
66
|
+
});
|
|
72
67
|
if (!investigated.ok)
|
|
73
68
|
return toCallToolResult(investigated, contract);
|
|
74
69
|
const workspace = investigated.value.workspace;
|
|
@@ -95,10 +95,12 @@ const comparisonUnknownInput = (parsed, comparison) => {
|
|
|
95
95
|
return undefined;
|
|
96
96
|
const differingScopes = [
|
|
97
97
|
["terminal", comparison.terminal],
|
|
98
|
+
["interaction", comparison.interaction],
|
|
98
99
|
["exit", comparison.exit],
|
|
99
100
|
["filesystem", comparison.filesystem],
|
|
100
101
|
["protocol", comparison.protocol],
|
|
101
102
|
["process", comparison.process],
|
|
103
|
+
["shim", comparison.shim],
|
|
102
104
|
]
|
|
103
105
|
.filter(([, status]) => status !== "unchanged")
|
|
104
106
|
.map(([scope]) => scope)
|
|
@@ -170,6 +170,8 @@ const registerEvidenceTools = ({ server, session, exportContract, importContract
|
|
|
170
170
|
if (!loaded.ok)
|
|
171
171
|
return toCallToolResult(loaded, importContract);
|
|
172
172
|
const imported = session.importEvidenceBundle(loaded.value);
|
|
173
|
+
if (imported.ok && imported.value > 0)
|
|
174
|
+
server.sendResourceListChanged();
|
|
173
175
|
return imported.ok
|
|
174
176
|
? toCallToolResult(ok({
|
|
175
177
|
imported: imported.value,
|
|
@@ -213,13 +215,23 @@ const registerUnknownTools = ({ server, session, contracts: [listContract, recor
|
|
|
213
215
|
inputSchema: recordContract.inputSchema,
|
|
214
216
|
outputSchema: recordContract.outputSchema,
|
|
215
217
|
annotations: recordContract.annotations,
|
|
216
|
-
}, (input) =>
|
|
218
|
+
}, (input) => {
|
|
219
|
+
const recorded = session.recordUnknown(recordUnknownInputSchema.parse(input));
|
|
220
|
+
if (recorded.ok)
|
|
221
|
+
server.sendResourceListChanged();
|
|
222
|
+
return toCallToolResult(recorded, recordContract);
|
|
223
|
+
});
|
|
217
224
|
server.registerTool(updateContract.name, {
|
|
218
225
|
description: updateContract.description,
|
|
219
226
|
inputSchema: updateContract.inputSchema,
|
|
220
227
|
outputSchema: updateContract.outputSchema,
|
|
221
228
|
annotations: updateContract.annotations,
|
|
222
|
-
}, (input) =>
|
|
229
|
+
}, (input) => {
|
|
230
|
+
const updated = session.updateUnknown(updateUnknownInputSchema.parse(input));
|
|
231
|
+
if (updated.ok)
|
|
232
|
+
server.sendResourceListChanged();
|
|
233
|
+
return toCallToolResult(updated, updateContract);
|
|
234
|
+
});
|
|
223
235
|
server.registerTool(verifyContract.name, {
|
|
224
236
|
description: verifyContract.description,
|
|
225
237
|
inputSchema: verifyContract.inputSchema,
|
|
@@ -342,6 +354,7 @@ export const registerSessionTools = (server, session, logger, options = {}) => {
|
|
|
342
354
|
(() => ({
|
|
343
355
|
processCaptureEnabled: processPolicy.enabled,
|
|
344
356
|
evidenceFileRoots: evidenceFilePolicy.roots.length,
|
|
357
|
+
browserObservationEnabled: false,
|
|
345
358
|
})),
|
|
346
359
|
...(options.permissionAuthority === undefined
|
|
347
360
|
? {}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { setImmediate } from "node:timers/promises";
|
|
2
|
-
import { AnalysisCancelledError } from "../domain/errors.js";
|
|
2
|
+
import { AnalysisCancelledError, AnalysisInputError, } from "../domain/errors.js";
|
|
3
3
|
import { err, ok } from "../domain/result.js";
|
|
4
4
|
import { mcpProgressReporter } from "./mcpProgress.js";
|
|
5
5
|
/** Run synchronous derived work with transport yields and a publication guard. */
|
|
@@ -14,7 +14,15 @@ export const runDerivedOperation = async (context, operation, compute) => {
|
|
|
14
14
|
await setImmediate();
|
|
15
15
|
if (context.mcpReq.signal.aborted)
|
|
16
16
|
return err(new AnalysisCancelledError(operation));
|
|
17
|
-
|
|
17
|
+
let value;
|
|
18
|
+
try {
|
|
19
|
+
value = compute();
|
|
20
|
+
}
|
|
21
|
+
catch (cause) {
|
|
22
|
+
return err(cause instanceof AnalysisCancelledError
|
|
23
|
+
? cause
|
|
24
|
+
: new AnalysisInputError(operation, { cause }));
|
|
25
|
+
}
|
|
18
26
|
await progress.report({
|
|
19
27
|
phase: "compute",
|
|
20
28
|
completed: 1,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rea-agents",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Reverse engineer anything from your terminal or agent with one CLI and MCP server.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
"test:watch": "vitest",
|
|
71
71
|
"typecheck": "tsc --noEmit",
|
|
72
72
|
"verify:hopper": "npm run build && node scripts/verify-real-hopper.mjs",
|
|
73
|
+
"verify:browser": "npm run build && node scripts/verify-real-browser.mjs",
|
|
73
74
|
"verify:hopper:linux": "npm run build && node scripts/verify-real-hopper-linux.mjs",
|
|
74
75
|
"verify:setup:linux": "npm run build && node scripts/verify-linux-setup-e2e.mjs",
|
|
75
76
|
"build:fixtures": "node scripts/build-conformance-fixtures.mjs",
|
package/scripts/rea.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// Route production MCP before importing Incur. Incur owns registration helpers
|
|
4
|
-
// such as `mcp add`, while only dist/main.js may serve the
|
|
4
|
+
// such as `mcp add`, while only dist/main.js may serve the 70-tool stdio server.
|
|
5
5
|
const args = process.argv.slice(2);
|
|
6
6
|
const { default: packageJson } = await import("../package.json", {
|
|
7
7
|
with: { type: "json" },
|
|
@@ -1,15 +1,30 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: rea-analysis
|
|
3
|
-
description: Reverse engineer apps with REA. Explore how features work, then build a version tailored to your project.
|
|
3
|
+
description: Reverse engineer apps and websites with REA. Explore how features work, then build a version tailored to your project.
|
|
4
4
|
metadata:
|
|
5
|
-
version: "
|
|
6
|
-
tool_count:
|
|
5
|
+
version: "13"
|
|
6
|
+
tool_count: 70
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# REA
|
|
10
10
|
|
|
11
11
|
Use REA when the user wants to understand how an app or feature works, compare app versions, decompile code, or build a similar feature.
|
|
12
12
|
|
|
13
|
+
For a website already open in a user-owned Chrome-family browser, use
|
|
14
|
+
`list_browser_targets` and `inspect_web_page` instead of opening a binary. Ask
|
|
15
|
+
the user to approve the exact page origins and loopback CDP endpoint before the
|
|
16
|
+
first call. Browser observation is disabled unless the operator configured
|
|
17
|
+
`REA_BROWSER_OBSERVE_ENABLED`, `REA_BROWSER_CDP_ENDPOINTS_JSON`, and
|
|
18
|
+
`REA_BROWSER_ALLOWED_ORIGINS_JSON` before starting REA.
|
|
19
|
+
|
|
20
|
+
Browser inspection is passive. Never claim that it clicked, navigated,
|
|
21
|
+
evaluated page JavaScript, captured prior activity, or contained the page's
|
|
22
|
+
network. Query values, headers, bodies, cookies, storage values, console values,
|
|
23
|
+
and WebSocket payloads are deliberately absent. Request script sources or
|
|
24
|
+
storage key names only when the user separately approves those more sensitive
|
|
25
|
+
outputs. Treat truncation and attach-window coverage as explicit limitations,
|
|
26
|
+
and cite the returned Evidence v2 IDs.
|
|
27
|
+
|
|
13
28
|
## Understand the request
|
|
14
29
|
|
|
15
30
|
Identify the app and what the user wants to understand or build. Do not ask for information they already provided.
|