rea-agents 2.1.0 → 2.3.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 +84 -18
- package/dist/application/AndroidApplicationService.js +17 -0
- package/dist/application/AppleApplicationService.js +17 -0
- package/dist/application/ApplicationWorkflowEvidenceResolver.js +162 -0
- package/dist/application/BinarySession.js +9 -2
- package/dist/application/BinarySessionStatus.js +39 -1
- package/dist/application/CapabilityInventory.js +15 -0
- package/dist/application/ClientRegistrationStatus.js +11 -4
- package/dist/application/CommandShimReplay.js +6 -3
- package/dist/application/CompositeProvider.js +5 -2
- package/dist/application/DirectAnalysis.js +1 -20
- package/dist/application/DirectAnalysisStatus.js +83 -0
- package/dist/application/Doctor.js +34 -25
- package/dist/application/DoctorDiagnostics.js +1 -4
- package/dist/application/DoctorProjection.js +43 -0
- package/dist/application/DoctorScope.js +102 -0
- package/dist/application/EvidenceReferenceResolver.js +26 -0
- package/dist/application/InventoryProjectionEvidence.js +41 -0
- package/dist/application/InvestigationProviders.js +12 -0
- package/dist/application/JavaScriptApplicationEvidence.js +1 -1
- package/dist/application/JavaScriptApplicationEvidenceGraph.js +10 -1
- package/dist/application/JavaScriptApplicationService.js +3 -2
- package/dist/application/JavaScriptApplicationWorkflowEvidence.js +26 -0
- package/dist/application/JavaScriptApplicationWorkflowService.js +49 -1
- package/dist/application/JavaScriptArtifactReconstruction.js +7 -0
- package/dist/application/JavaScriptModuleRelationships.js +25 -1
- package/dist/application/JavaScriptReturnShapeProjection.js +111 -0
- package/dist/application/JavaScriptSemanticGraphBuilder.js +294 -0
- package/dist/application/JavaScriptSemanticGraphConstruction.js +144 -0
- package/dist/application/JavaScriptSemanticGraphEvidence.js +86 -0
- package/dist/application/JavaScriptSemanticGraphFlowProjection.js +72 -0
- package/dist/application/JavaScriptSemanticGraphProjection.js +33 -0
- package/dist/application/JavaScriptSemanticTraceService.js +45 -0
- package/dist/application/LoopbackReplay.js +277 -133
- package/dist/application/LoopbackReplayRecorder.js +101 -0
- package/dist/application/PermissionAuthority.js +7 -3
- package/dist/application/ProcessCaptureJournal.js +95 -0
- package/dist/application/ProcessCaptureLifecycle.js +24 -13
- package/dist/application/ProcessCheckpoints.js +30 -4
- package/dist/application/ProcessCli.js +26 -4
- package/dist/application/ProcessHarness.js +20 -50
- package/dist/application/ProcessNormalization.js +3 -2
- package/dist/application/ProcessPairedExperiment.js +72 -0
- package/dist/application/ProcessReactiveCoordinator.js +218 -0
- package/dist/application/ProcessReactiveEffects.js +133 -0
- package/dist/application/ProcessReactiveObservations.js +20 -0
- package/dist/application/ProcessSampling.js +2 -0
- package/dist/application/SessionProviderRouter.js +7 -6
- package/dist/application/Setup.js +14 -13
- package/dist/application/SetupClientConfiguration.js +10 -6
- package/dist/application/SetupPlan.js +4 -3
- package/dist/application/SetupRegistrationEnvironment.js +12 -0
- package/dist/application/SetupSkill.js +44 -40
- package/dist/application/TerminalRenderer.js +3 -1
- package/dist/application/Uninstall.js +7 -1
- package/dist/application/Upgrade.js +16 -1
- package/dist/browser/CdpEndpoint.js +37 -4
- package/dist/catalogIdentity.js +16 -7
- package/dist/cli/coreAnalysisCommands.js +34 -2
- package/dist/cli/javascriptApplicationAnalysis.js +19 -0
- package/dist/cli/setupCommands.js +84 -30
- package/dist/cli/utilityCommands.js +10 -2
- package/dist/cliApplicationCommands.js +79 -16
- package/dist/cliCommandNames.js +3 -0
- package/dist/cliElectronCommands.js +23 -33
- package/dist/cliObservationOptions.js +1 -1
- package/dist/cliOutput.js +56 -0
- package/dist/cliProcessCommands.js +32 -1
- package/dist/cliSetup.js +55 -29
- package/dist/contracts/applicationToolContracts.js +54 -7
- package/dist/contracts/applicationWorkflowInputContracts.js +119 -0
- package/dist/contracts/electronToolContracts.js +73 -4
- package/dist/contracts/javascriptApplicationWorkflowExamples.js +32 -9
- package/dist/contracts/managedToolContracts.js +7 -2
- package/dist/contracts/processCaptureExample.js +1 -0
- package/dist/contracts/replayMachineExample.js +37 -0
- package/dist/contracts/sessionStatusContract.js +26 -0
- package/dist/contracts/toolContractExamples.js +2 -0
- package/dist/contracts/toolContractTypes.js +12 -1
- package/dist/contracts/toolContracts.js +8 -11
- package/dist/contracts/toolEffects.js +3 -0
- package/dist/contracts/toolOutputSchemaGroups.js +53 -9
- package/dist/contracts/toolOutputSchemaPrimitives.js +73 -32
- package/dist/doctorRuntime.js +41 -0
- package/dist/domain/analysisErrorPresentation.js +5 -3
- package/dist/domain/analysisErrorProjection.js +7 -1
- package/dist/domain/androidApplication.js +206 -0
- package/dist/domain/appleApplication.js +221 -0
- package/dist/domain/boundedCartesianProjection.js +15 -0
- package/dist/domain/changedBehavior.js +5 -4
- package/dist/domain/completionLedgerGeneration.js +190 -0
- package/dist/domain/errors.js +4 -2
- package/dist/domain/evidenceCompletionLedger.js +113 -0
- package/dist/domain/hopperStartupFailure.js +9 -0
- package/dist/domain/javascriptApplicationAnalysis.js +44 -2
- package/dist/domain/javascriptExportShapeComparison.js +145 -0
- package/dist/domain/javascriptExportShapeComparisonIdentity.js +11 -0
- package/dist/domain/javascriptExportShapeComparisonSchemas.js +277 -0
- package/dist/domain/javascriptExportShapeSelection.js +132 -0
- package/dist/domain/javascriptExportShapeVariants.js +272 -0
- package/dist/domain/javascriptRuntimeReconciliationParsing.js +2 -2
- package/dist/domain/javascriptSemanticAnalysis.js +17 -36
- package/dist/domain/javascriptSemanticCallResolution.js +129 -0
- package/dist/domain/javascriptSemanticCalls.js +269 -0
- package/dist/domain/javascriptSemanticGraph.js +356 -0
- package/dist/domain/javascriptSemanticGraphSchemas.js +329 -0
- package/dist/domain/javascriptSemanticGraphSerialization.js +23 -0
- package/dist/domain/javascriptSemanticIr.js +14 -1
- package/dist/domain/javascriptSemanticPrimitives.js +36 -0
- package/dist/domain/javascriptSemanticProjection.js +36 -4
- package/dist/domain/javascriptSemanticProvenance.js +29 -0
- package/dist/domain/javascriptSemanticQuery.js +294 -0
- package/dist/domain/javascriptSemanticQueryAssessment.js +74 -0
- package/dist/domain/javascriptSemanticQueryIdentity.js +86 -0
- package/dist/domain/javascriptSemanticQueryRelations.js +15 -0
- package/dist/domain/javascriptSemanticQuerySchemas.js +188 -0
- package/dist/domain/javascriptSemanticReturns.js +187 -0
- package/dist/domain/javascriptSemanticState.js +32 -0
- package/dist/domain/javascriptSemanticTraceSchemas.js +14 -0
- package/dist/domain/javascriptSemanticValues.js +54 -70
- package/dist/domain/processCapture.js +36 -0
- package/dist/domain/processCaptureValidation.js +101 -12
- package/dist/domain/processComparison.js +96 -24
- package/dist/domain/processObservation.js +153 -0
- package/dist/domain/processPairedExperiment.js +128 -0
- package/dist/domain/processReactiveCheckpointDataflow.js +32 -0
- package/dist/domain/processReactiveMatching.js +210 -0
- package/dist/domain/processReactiveRuntime.js +109 -0
- package/dist/domain/processReactiveScenario.js +361 -0
- package/dist/domain/processReactiveScenarioPreflight.js +120 -0
- package/dist/domain/processReactiveTransition.js +159 -0
- package/dist/domain/processScenario.js +12 -0
- package/dist/domain/processTraceComparison.js +43 -0
- package/dist/domain/processTraceDimensionProjection.js +50 -0
- package/dist/domain/processTraceEvaluation.js +312 -0
- package/dist/domain/processTraceSpecification.js +373 -0
- package/dist/domain/reconstructionVerification.js +5 -4
- package/dist/domain/replayMachine.js +332 -0
- package/dist/domain/replayMachineRun.js +216 -0
- package/dist/domain/replayMachineRuntime.js +294 -0
- package/dist/domain/runtimeIdentification.js +210 -0
- package/dist/domain/staticRuntimeCorrelation.js +4 -2
- package/dist/evaluation/CodexAgentEval.js +156 -0
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraClient.js +13 -2
- package/dist/ghidra/GhidraDiagnostics.js +1 -0
- package/dist/ghidra/GhidraLauncher.js +7 -3
- package/dist/ghidra/GhidraProvider.js +8 -1
- package/dist/hopper/BridgeLauncher.js +56 -14
- package/dist/hopper/HopperClient.js +23 -10
- package/dist/hopper/HopperDiagnostics.js +14 -0
- package/dist/hopper/HopperProcessDiagnostic.js +14 -0
- package/dist/hopper/HopperProvider.js +8 -1
- package/dist/hopper/LinuxPrivateDisplayDiagnostic.js +72 -0
- package/dist/hopper/LinuxPrivateDisplayProbe.js +217 -0
- package/dist/identity.js +2 -1
- package/dist/main/transport.js +2 -0
- package/dist/mcpDoctor.js +310 -0
- package/dist/process/ProcessOwnership.js +200 -53
- package/dist/process/ProviderRunLineage.js +21 -0
- package/dist/server/createServer.js +8 -2
- package/dist/server/javascriptApplicationResult.js +106 -0
- package/dist/server/registerApplicationTools/characterization.js +3 -3
- package/dist/server/registerApplicationTools/compareExportShapes.js +37 -0
- package/dist/server/registerApplicationTools/compareVersions.js +12 -6
- package/dist/server/registerApplicationTools/controlledReplay.js +2 -2
- package/dist/server/registerApplicationTools/coverage.js +3 -3
- package/dist/server/registerApplicationTools/helpers.js +37 -25
- package/dist/server/registerApplicationTools/traceFeature.js +9 -5
- package/dist/server/registerApplicationTools/traceSemantics.js +30 -0
- package/dist/server/registerApplicationTools.js +4 -0
- package/dist/server/registerElectronTools.js +19 -5
- package/dist/server/registerEvidenceResources.js +7 -1
- package/dist/server/registerJavaScriptApplicationGraphResource.js +69 -0
- package/dist/server/registerManagedTools.js +18 -1
- package/dist/server/registerProcessComparisonTool.js +17 -7
- package/dist/server/registerReplayMachineTool.js +20 -0
- package/dist/server/registerSessionStatusTool.js +95 -25
- package/dist/server/registerSessionTools.js +12 -7
- package/dist/server/sessionAvailabilityPolicy.js +2 -1
- package/dist/server/toolResult.js +10 -4
- package/dist/serverIdentity.js +19 -0
- package/package.json +62 -29
- package/scripts/hopper-demo-x11.py +459 -61
- package/scripts/prepack.mjs +55 -0
- package/scripts/prepare.mjs +28 -0
- package/scripts/rea.mjs +26 -5
- package/skills/reverse-engineer-anything/SKILL.md +69 -228
- package/skills/reverse-engineer-anything/references/controlled-replay.md +12 -0
- package/skills/reverse-engineer-anything/references/evidence-workflows.md +33 -0
- package/skills/reverse-engineer-anything/references/javascript-applications.md +35 -0
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +36 -0
- package/skills/reverse-engineer-anything/references/runtime-observation.md +24 -0
|
@@ -2,7 +2,15 @@ import { mkdir, readFile, rm } from "node:fs/promises";
|
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import writeFileAtomic from "write-file-atomic";
|
|
4
4
|
import { PRODUCT_IDENTITY } from "../identity.js";
|
|
5
|
-
const
|
|
5
|
+
const SKILL_FILES = [
|
|
6
|
+
"SKILL.md",
|
|
7
|
+
"references/native-and-artifacts.md",
|
|
8
|
+
"references/javascript-applications.md",
|
|
9
|
+
"references/runtime-observation.md",
|
|
10
|
+
"references/evidence-workflows.md",
|
|
11
|
+
"references/controlled-replay.md",
|
|
12
|
+
];
|
|
13
|
+
const skillRoot = (home) => join(home, ".agents/skills", PRODUCT_IDENTITY.skillName);
|
|
6
14
|
const readOptionalText = async (path) => {
|
|
7
15
|
try {
|
|
8
16
|
return await readFile(path, "utf8");
|
|
@@ -13,62 +21,58 @@ const readOptionalText = async (path) => {
|
|
|
13
21
|
throw cause;
|
|
14
22
|
}
|
|
15
23
|
};
|
|
16
|
-
const canonicalSkillFiles = async (home) => ({
|
|
17
|
-
destination
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
const canonicalSkillFiles = async (home) => Promise.all(SKILL_FILES.map(async (relativePath) => {
|
|
25
|
+
const destination = join(skillRoot(home), relativePath);
|
|
26
|
+
return {
|
|
27
|
+
destination,
|
|
28
|
+
content: await readFile(new URL(`../../skills/${PRODUCT_IDENTITY.skillName}/${relativePath}`, import.meta.url), "utf8"),
|
|
29
|
+
original: await readOptionalText(destination),
|
|
30
|
+
};
|
|
31
|
+
}));
|
|
32
|
+
/** Report whether setup would change any file in the managed REA skill bundle. */
|
|
21
33
|
export const canonicalSkillNeedsInstall = async (home) => {
|
|
22
34
|
try {
|
|
23
|
-
|
|
24
|
-
return (await readOptionalText(destination)) !== content;
|
|
35
|
+
return (await canonicalSkillFiles(home)).some(({ content, original }) => original !== content);
|
|
25
36
|
}
|
|
26
37
|
catch {
|
|
27
38
|
return true;
|
|
28
39
|
}
|
|
29
40
|
};
|
|
30
|
-
|
|
41
|
+
const writeText = (path, content) => writeFileAtomic(path, content, { encoding: "utf8", mode: 0o600 });
|
|
42
|
+
const restoreSkillFiles = async (changed) => {
|
|
43
|
+
for (const { destination, original } of [...changed].reverse()) {
|
|
44
|
+
if (original === undefined)
|
|
45
|
+
await rm(destination, { force: true });
|
|
46
|
+
else
|
|
47
|
+
await writeText(destination, original);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
/** Transactionally install or upgrade the canonical REA skill and references. */
|
|
31
51
|
export const installCanonicalSkill = async (home) => {
|
|
32
|
-
let
|
|
33
|
-
let backup = `${destination}.rea.backup`;
|
|
34
|
-
let original;
|
|
35
|
-
let canonicalChanged = false;
|
|
52
|
+
let changed = [];
|
|
36
53
|
try {
|
|
37
54
|
const canonical = await canonicalSkillFiles(home);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const { content } = canonical;
|
|
41
|
-
original = await readOptionalText(destination);
|
|
42
|
-
if (original === content)
|
|
55
|
+
changed = canonical.filter(({ content, original }) => original !== content);
|
|
56
|
+
if (changed.length === 0)
|
|
43
57
|
return "unchanged";
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
await
|
|
53
|
-
|
|
54
|
-
mode: 0o600,
|
|
55
|
-
});
|
|
56
|
-
if ((await readFile(destination, "utf8")) !== content)
|
|
57
|
-
throw new Error("skill readback mismatch");
|
|
58
|
+
for (const { destination, original } of changed) {
|
|
59
|
+
await mkdir(dirname(destination), { recursive: true });
|
|
60
|
+
if (original !== undefined)
|
|
61
|
+
await writeText(`${destination}.rea.backup`, original);
|
|
62
|
+
}
|
|
63
|
+
for (const { destination, content } of changed)
|
|
64
|
+
await writeText(destination, content);
|
|
65
|
+
for (const { destination, content } of changed)
|
|
66
|
+
if ((await readFile(destination, "utf8")) !== content)
|
|
67
|
+
throw new Error(`skill readback mismatch: ${destination}`);
|
|
58
68
|
return "installed";
|
|
59
69
|
}
|
|
60
70
|
catch {
|
|
61
71
|
try {
|
|
62
|
-
|
|
63
|
-
await rm(destination, { force: true });
|
|
64
|
-
else if (canonicalChanged && original !== undefined)
|
|
65
|
-
await writeFileAtomic(destination, original, {
|
|
66
|
-
encoding: "utf8",
|
|
67
|
-
mode: 0o600,
|
|
68
|
-
});
|
|
72
|
+
await restoreSkillFiles(changed);
|
|
69
73
|
}
|
|
70
74
|
catch {
|
|
71
|
-
//
|
|
75
|
+
// Per-file backups remain beside changed files for operator recovery.
|
|
72
76
|
}
|
|
73
77
|
return "failed";
|
|
74
78
|
}
|
|
@@ -77,8 +77,9 @@ export class TerminalRenderer {
|
|
|
77
77
|
return;
|
|
78
78
|
}
|
|
79
79
|
this.#capturedBytes += bytes;
|
|
80
|
+
const sequence = this.#frames.length;
|
|
80
81
|
this.#frames.push({
|
|
81
|
-
sequence
|
|
82
|
+
sequence,
|
|
82
83
|
at_ms: atMs,
|
|
83
84
|
columns: this.#terminal.cols,
|
|
84
85
|
rows: this.#terminal.rows,
|
|
@@ -88,5 +89,6 @@ export class TerminalRenderer {
|
|
|
88
89
|
lines,
|
|
89
90
|
serialized_state: serializedState,
|
|
90
91
|
});
|
|
92
|
+
this.options.recordEvent?.("rendered_frames", sequence);
|
|
91
93
|
}
|
|
92
94
|
}
|
|
@@ -128,7 +128,13 @@ const isOwnedRegistration = (value) => {
|
|
|
128
128
|
args[0] === "mcp") ||
|
|
129
129
|
(command === "npx" &&
|
|
130
130
|
(JSON.stringify(args) ===
|
|
131
|
-
JSON.stringify([
|
|
131
|
+
JSON.stringify([
|
|
132
|
+
"-y",
|
|
133
|
+
PRODUCT_IDENTITY.registrationPackageSpecifier,
|
|
134
|
+
"mcp",
|
|
135
|
+
]) ||
|
|
136
|
+
JSON.stringify(args) ===
|
|
137
|
+
JSON.stringify(["-y", PRODUCT_IDENTITY.packageSpecifier, "mcp"]) ||
|
|
132
138
|
JSON.stringify(args) ===
|
|
133
139
|
JSON.stringify(["-y", PRODUCT_IDENTITY.packageName, "mcp"]))));
|
|
134
140
|
};
|
|
@@ -9,6 +9,7 @@ import { PRODUCT_IDENTITY } from "../identity.js";
|
|
|
9
9
|
const execFileAsync = promisify(execFile);
|
|
10
10
|
const registryResponseSchema = z.object({ version: z.string().min(1) });
|
|
11
11
|
const UPGRADE_COMMAND = "npm install --global rea-agents@latest";
|
|
12
|
+
const CLI_SCRIPT_PATH = fileURLToPath(new URL("../../scripts/rea.mjs", import.meta.url));
|
|
12
13
|
/** Check the npm registry and update the same global REA installation. */
|
|
13
14
|
export const runUpgrade = async (currentVersion, host = systemUpgradeHost(), output = "human") => {
|
|
14
15
|
const latestVersion = await host.latestVersion();
|
|
@@ -46,6 +47,12 @@ export const runUpgrade = async (currentVersion, host = systemUpgradeHost(), out
|
|
|
46
47
|
reason: "install",
|
|
47
48
|
remediation: `REA could not update through npm. Check npm registry access and global install permissions, then run: ${UPGRADE_COMMAND}`,
|
|
48
49
|
};
|
|
50
|
+
const integrationSyncResult = await host.syncAgentIntegration(output);
|
|
51
|
+
const integrationSync = integrationSyncResult === undefined
|
|
52
|
+
? "deferred"
|
|
53
|
+
: integrationSyncResult
|
|
54
|
+
? "setup_invoked"
|
|
55
|
+
: "failed";
|
|
49
56
|
return {
|
|
50
57
|
status: "upgraded",
|
|
51
58
|
previousVersion: currentVersion,
|
|
@@ -53,8 +60,11 @@ export const runUpgrade = async (currentVersion, host = systemUpgradeHost(), out
|
|
|
53
60
|
versionCheck: "available",
|
|
54
61
|
installMethod: "npm",
|
|
55
62
|
command: UPGRADE_COMMAND,
|
|
63
|
+
integrationSync,
|
|
56
64
|
clientRestartRequired: true,
|
|
57
|
-
remediation:
|
|
65
|
+
remediation: integrationSync === "setup_invoked"
|
|
66
|
+
? "The updated setup journey was opened to align registrations and the skill. Restart clients whose approved registration changed."
|
|
67
|
+
: "Run rea setup --all-detected to align registrations and the skill, then restart clients that may retain an older MCP server.",
|
|
58
68
|
};
|
|
59
69
|
};
|
|
60
70
|
/** Create the npm registry and subprocess effects for a production upgrade. */
|
|
@@ -79,6 +89,11 @@ export const systemUpgradeHost = () => ({
|
|
|
79
89
|
prefix,
|
|
80
90
|
`${PRODUCT_IDENTITY.packageName}@latest`,
|
|
81
91
|
], output),
|
|
92
|
+
syncAgentIntegration: (output) => output === "structured" ||
|
|
93
|
+
process.stdin.isTTY !== true ||
|
|
94
|
+
process.stderr.isTTY !== true
|
|
95
|
+
? Promise.resolve(undefined)
|
|
96
|
+
: runCommand(process.execPath, [CLI_SCRIPT_PATH, "setup", "--all-detected"], "human"),
|
|
82
97
|
});
|
|
83
98
|
const systemNpmInstallationHost = {
|
|
84
99
|
canonicalPath: realpath,
|
|
@@ -40,25 +40,58 @@ export const discoverCdpEndpoint = async (endpoint, operation, signal) => {
|
|
|
40
40
|
targets: targets.map((target) => ({
|
|
41
41
|
id: target.id,
|
|
42
42
|
type: target.type,
|
|
43
|
-
title: sanitizeTargetTitle(target.title),
|
|
43
|
+
title: sanitizeTargetTitle(target.title, target.url),
|
|
44
44
|
url: target.url,
|
|
45
45
|
attached: target.attached,
|
|
46
46
|
...targetWebSocket(endpoint, target, operation),
|
|
47
47
|
})),
|
|
48
48
|
};
|
|
49
49
|
};
|
|
50
|
-
const sanitizeTargetTitle = (value) => {
|
|
50
|
+
const sanitizeTargetTitle = (value, targetUrl) => {
|
|
51
51
|
let url;
|
|
52
52
|
try {
|
|
53
53
|
url = new URL(value);
|
|
54
54
|
}
|
|
55
55
|
catch {
|
|
56
|
-
return value;
|
|
56
|
+
return sanitizeTargetUrlAlias(value, targetUrl);
|
|
57
57
|
}
|
|
58
58
|
return url.protocol === "http:" || url.protocol === "https:"
|
|
59
59
|
? sanitizeBrowserUrl(value).url.slice(0, 16_384)
|
|
60
|
-
: value;
|
|
60
|
+
: sanitizeTargetUrlAlias(value, targetUrl);
|
|
61
|
+
};
|
|
62
|
+
const sanitizeTargetUrlAlias = (value, targetUrl) => {
|
|
63
|
+
let parsed;
|
|
64
|
+
try {
|
|
65
|
+
parsed = new URL(targetUrl);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
const markers = [parsed.origin, `//${parsed.host}`, parsed.host];
|
|
71
|
+
if (parsed.pathname !== "/")
|
|
72
|
+
markers.push(parsed.pathname);
|
|
73
|
+
const candidatePattern = new RegExp(`(?:${markers.map(escapeRegExp).join("|")})[^\\s<>"']*`, "gu");
|
|
74
|
+
return value
|
|
75
|
+
.replace(candidatePattern, (candidate) => sanitizeSameOriginTitleUrl(candidate, parsed))
|
|
76
|
+
.slice(0, 16_384);
|
|
77
|
+
};
|
|
78
|
+
const sanitizeSameOriginTitleUrl = (candidate, target) => {
|
|
79
|
+
let parsed;
|
|
80
|
+
try {
|
|
81
|
+
parsed = candidate.startsWith("//")
|
|
82
|
+
? new URL(`${target.protocol}${candidate}`)
|
|
83
|
+
: candidate.startsWith(target.host)
|
|
84
|
+
? new URL(`${target.protocol}//${candidate}`)
|
|
85
|
+
: new URL(candidate, target.origin);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return candidate;
|
|
89
|
+
}
|
|
90
|
+
return parsed.origin === target.origin && parsed.search !== ""
|
|
91
|
+
? sanitizeBrowserUrl(parsed.href).url
|
|
92
|
+
: candidate;
|
|
61
93
|
};
|
|
94
|
+
const escapeRegExp = (value) => value.replaceAll(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
62
95
|
/** Select a browser attachment socket or a direct socket for one page target. */
|
|
63
96
|
export const cdpTargetWebSocket = (discovery, target, operation) => {
|
|
64
97
|
const webSocket = availableCdpTargetWebSocket(discovery, target);
|
package/dist/catalogIdentity.js
CHANGED
|
@@ -26,11 +26,13 @@ const promptCatalog = PROMPT_CONTRACTS.map((contract) => ({
|
|
|
26
26
|
arguments: contract.arguments,
|
|
27
27
|
steps: contract.steps,
|
|
28
28
|
})).sort((left, right) => left.name.localeCompare(right.name));
|
|
29
|
-
|
|
29
|
+
/** Canonical fixed resources exposed by every target-free MCP session. */
|
|
30
|
+
export const MCP_RESOURCE_CATALOG = [
|
|
30
31
|
{ name: "server-identity", uri: "rea://server/identity" },
|
|
31
32
|
{ name: "active-residual-unknowns", uri: "rea://unknowns/active" },
|
|
32
33
|
];
|
|
33
|
-
|
|
34
|
+
/** Canonical resource templates exposed by every target-free MCP session. */
|
|
35
|
+
export const MCP_RESOURCE_TEMPLATE_CATALOG = [
|
|
34
36
|
{ name: "session-evidence", uri_template: "rea://evidence/{evidenceId}" },
|
|
35
37
|
{
|
|
36
38
|
name: "evidence-section",
|
|
@@ -57,6 +59,10 @@ const resourceTemplateCatalog = [
|
|
|
57
59
|
name: "reconstruction-coverage-revision",
|
|
58
60
|
uri_template: "rea://reconstruction-coverage/{workspaceId}/revision/{revision}",
|
|
59
61
|
},
|
|
62
|
+
{
|
|
63
|
+
name: "javascript-application-graph-page",
|
|
64
|
+
uri_template: "rea://evidence/{evidenceId}/application-graph/{collection}/offset/{offset}/limit/{limit}",
|
|
65
|
+
},
|
|
60
66
|
];
|
|
61
67
|
const digest = (value) => {
|
|
62
68
|
const encoded = canonicalize(value);
|
|
@@ -70,19 +76,22 @@ export const CATALOG_IDENTITY = {
|
|
|
70
76
|
cli_commands: CLI_COMMAND_NAMES.length,
|
|
71
77
|
mcp_tools: toolCatalog.length,
|
|
72
78
|
mcp_prompts: promptCatalog.length,
|
|
73
|
-
mcp_resources:
|
|
74
|
-
mcp_resource_templates:
|
|
79
|
+
mcp_resources: MCP_RESOURCE_CATALOG.length,
|
|
80
|
+
mcp_resource_templates: MCP_RESOURCE_TEMPLATE_CATALOG.length,
|
|
75
81
|
},
|
|
76
82
|
digests: {
|
|
77
83
|
tools_sha256: digest(toolCatalog),
|
|
78
84
|
prompts_sha256: digest(promptCatalog),
|
|
79
|
-
resources_sha256: digest({
|
|
85
|
+
resources_sha256: digest({
|
|
86
|
+
resourceCatalog: MCP_RESOURCE_CATALOG,
|
|
87
|
+
resourceTemplateCatalog: MCP_RESOURCE_TEMPLATE_CATALOG,
|
|
88
|
+
}),
|
|
80
89
|
combined_sha256: digest({
|
|
81
90
|
cli: CLI_COMMAND_NAMES,
|
|
82
91
|
tools: toolCatalog,
|
|
83
92
|
prompts: promptCatalog,
|
|
84
|
-
resources:
|
|
85
|
-
resource_templates:
|
|
93
|
+
resources: MCP_RESOURCE_CATALOG,
|
|
94
|
+
resource_templates: MCP_RESOURCE_TEMPLATE_CATALOG,
|
|
86
95
|
}),
|
|
87
96
|
},
|
|
88
97
|
tools: toolCatalog.map(({ name, surface, effects, annotations }) => ({
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { z } from "incur";
|
|
2
|
+
import { stat } from "node:fs/promises";
|
|
3
|
+
import { resolve } from "node:path";
|
|
2
4
|
import { runDirectAnalysis } from "../application/DirectAnalysis.js";
|
|
3
5
|
import { CLI_COMMANDS } from "../cliCommandNames.js";
|
|
4
6
|
import { logCliCommand } from "../cliLogging.js";
|
|
5
7
|
import { directAnalysisOptions, providerSelectionOption } from "./options.js";
|
|
8
|
+
import { runCliJavaScriptApplicationAnalysis } from "./javascriptApplicationAnalysis.js";
|
|
6
9
|
export const registerCoreAnalysisCommands = (cli, logger) => {
|
|
7
10
|
registerCoreCommands(cli, logger);
|
|
8
11
|
registerFunctionCommand(cli, logger);
|
|
@@ -30,13 +33,19 @@ const registerCoreCommands = (cli, logger) => {
|
|
|
30
33
|
.describe("Load and update a local analysis snapshot"),
|
|
31
34
|
provider: providerSelectionOption,
|
|
32
35
|
});
|
|
36
|
+
const analyzeOptions = overviewOptions.extend({
|
|
37
|
+
approved: z
|
|
38
|
+
.boolean()
|
|
39
|
+
.default(false)
|
|
40
|
+
.describe("Approve static analysis when the path is a JavaScript directory or ASAR"),
|
|
41
|
+
});
|
|
33
42
|
cli.command(CLI_COMMANDS.analyze, {
|
|
34
43
|
description: "Get an overview of an app",
|
|
35
44
|
args: z.object({
|
|
36
45
|
path: z.string().describe("App, program, or analysis database path"),
|
|
37
46
|
}),
|
|
38
|
-
options:
|
|
39
|
-
run: ({ args, options }) => logCliCommand(logger, "analyze", () =>
|
|
47
|
+
options: analyzeOptions,
|
|
48
|
+
run: ({ args, options }) => logCliCommand(logger, "analyze", () => runRoutedOverview(args.path, options, logger)),
|
|
40
49
|
});
|
|
41
50
|
cli.command(CLI_COMMANDS.inspect, {
|
|
42
51
|
description: "Inspect an app overview with evidence",
|
|
@@ -63,6 +72,29 @@ const registerCoreCommands = (cli, logger) => {
|
|
|
63
72
|
run: ({ args, options }) => logCliCommand(logger, "decompile", () => runDirectAnalysis(args.path, "procedure_pseudo_code", { procedure: args.address }, directAnalysisOptions(logger, options.snapshot, options.provider))),
|
|
64
73
|
});
|
|
65
74
|
};
|
|
75
|
+
const runRoutedOverview = async (path, options, logger) => {
|
|
76
|
+
if (options.provider === undefined &&
|
|
77
|
+
options.snapshot === undefined &&
|
|
78
|
+
(await isJavaScriptApplicationPath(path)))
|
|
79
|
+
return runCliJavaScriptApplicationAnalysis({
|
|
80
|
+
input_path: resolve(path),
|
|
81
|
+
approved: options.approved,
|
|
82
|
+
});
|
|
83
|
+
return runDirectAnalysis(path, "binary_overview", { detail: options.detail, limit: options.limit }, directAnalysisOptions(logger, options.snapshot, options.provider));
|
|
84
|
+
};
|
|
85
|
+
const isJavaScriptApplicationPath = async (path) => {
|
|
86
|
+
const lower = path.toLowerCase();
|
|
87
|
+
if (lower.endsWith(".asar"))
|
|
88
|
+
return true;
|
|
89
|
+
if (lower.endsWith(".app"))
|
|
90
|
+
return false;
|
|
91
|
+
try {
|
|
92
|
+
return (await stat(path)).isDirectory();
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
66
98
|
const registerXrefsCommand = (cli, logger) => {
|
|
67
99
|
cli.command(CLI_COMMANDS.xrefs, {
|
|
68
100
|
description: "List bounded references to an analyzed address",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { analyzeJavaScriptApplication } from "../application/JavaScriptApplicationService.js";
|
|
2
|
+
import { loadConfiguredPermissionAuthority } from "../application/PermissionConfiguration.js";
|
|
3
|
+
import { parseConfig } from "../config.js";
|
|
4
|
+
import { projectAnalysisError } from "../domain/errors.js";
|
|
5
|
+
/** Execute the shared one-shot CLI boundary for static JavaScript analysis. */
|
|
6
|
+
export const runCliJavaScriptApplicationAnalysis = async (input) => {
|
|
7
|
+
const config = parseConfig(process.env);
|
|
8
|
+
if (!config.ok)
|
|
9
|
+
return cliError(config.error);
|
|
10
|
+
const authority = await loadConfiguredPermissionAuthority(config.value);
|
|
11
|
+
if (!authority.ok)
|
|
12
|
+
return cliError(authority.error);
|
|
13
|
+
const result = await analyzeJavaScriptApplication(authority.value, input);
|
|
14
|
+
return result.ok ? result.value : cliError(result.error);
|
|
15
|
+
};
|
|
16
|
+
const cliError = (error) => ({
|
|
17
|
+
error: "JavaScript application analysis failed",
|
|
18
|
+
...projectAnalysisError(error),
|
|
19
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "incur";
|
|
2
|
-
import { runDoctor } from "../application/Doctor.js";
|
|
3
|
-
import { runSetup, systemSetupHost } from "../application/Setup.js";
|
|
2
|
+
import { DOCTOR_PROVIDER_IDS, runDoctor, } from "../application/Doctor.js";
|
|
3
|
+
import { runSetup, systemSetupHost, } from "../application/Setup.js";
|
|
4
4
|
import { runUninstall } from "../application/Uninstall.js";
|
|
5
5
|
import { runUpgrade, systemUpgradeHost } from "../application/Upgrade.js";
|
|
6
6
|
import { conciseSetupResult, confirmInteractiveSetup, renderInteractiveSetupResult, renderSetupProgress, } from "../cliSetup.js";
|
|
@@ -8,7 +8,19 @@ import { PRODUCT_IDENTITY } from "../identity.js";
|
|
|
8
8
|
import { logCliCommand } from "../cliLogging.js";
|
|
9
9
|
import { createSystemDoctorHost } from "../doctorRuntime.js";
|
|
10
10
|
import { CLI_COMMANDS } from "../cliCommandNames.js";
|
|
11
|
+
import { SUPPORTED_CLIENT_DEFINITIONS } from "../application/SupportedClients.js";
|
|
12
|
+
import { projectDoctorReport } from "../application/DoctorProjection.js";
|
|
13
|
+
const supportedClientIds = SUPPORTED_CLIENT_DEFINITIONS.map(({ name }) => name);
|
|
14
|
+
const supportedClientSchema = z
|
|
15
|
+
.string()
|
|
16
|
+
.refine((candidate) => supportedClientIds.some((name) => name === candidate), "Unsupported agent integration");
|
|
17
|
+
/** Register setup, doctor, uninstall, and upgrade CLI commands. */
|
|
11
18
|
export const registerSetupCommands = (cli, logger) => {
|
|
19
|
+
registerSetupCommand(cli, logger);
|
|
20
|
+
registerDoctorCommand(cli, logger);
|
|
21
|
+
registerMaintenanceCommands(cli, logger);
|
|
22
|
+
};
|
|
23
|
+
const registerSetupCommand = (cli, logger) => {
|
|
12
24
|
cli.command(CLI_COMMANDS.setup, {
|
|
13
25
|
description: "Install requirements and configure agents",
|
|
14
26
|
outputPolicy: "agent-only",
|
|
@@ -22,14 +34,7 @@ export const registerSetupCommands = (cli, logger) => {
|
|
|
22
34
|
.default(false)
|
|
23
35
|
.describe("Also approve Hopper installation with --yes"),
|
|
24
36
|
client: z
|
|
25
|
-
.array(
|
|
26
|
-
"claude_code",
|
|
27
|
-
"claude_desktop",
|
|
28
|
-
"codex",
|
|
29
|
-
"cursor",
|
|
30
|
-
"gemini_cli",
|
|
31
|
-
"windsurf",
|
|
32
|
-
]))
|
|
37
|
+
.array(supportedClientSchema)
|
|
33
38
|
.default([])
|
|
34
39
|
.describe("Agent integration to configure; repeat for multiple agents"),
|
|
35
40
|
allDetected: z
|
|
@@ -39,7 +44,7 @@ export const registerSetupCommands = (cli, logger) => {
|
|
|
39
44
|
skill: z
|
|
40
45
|
.boolean()
|
|
41
46
|
.optional()
|
|
42
|
-
.describe("
|
|
47
|
+
.describe("Override the bundled skill included with agent integrations"),
|
|
43
48
|
dryRun: z
|
|
44
49
|
.boolean()
|
|
45
50
|
.default(false)
|
|
@@ -48,17 +53,41 @@ export const registerSetupCommands = (cli, logger) => {
|
|
|
48
53
|
.boolean()
|
|
49
54
|
.default(false)
|
|
50
55
|
.describe("Use sequential accessible setup prompts"),
|
|
56
|
+
detail: z
|
|
57
|
+
.enum(["summary", "full"])
|
|
58
|
+
.default("summary")
|
|
59
|
+
.describe("Summary or complete setup and doctor diagnostics"),
|
|
51
60
|
}),
|
|
52
61
|
alias: { yes: "y" },
|
|
53
|
-
run: ({ options, formatExplicit
|
|
62
|
+
run: ({ options, formatExplicit }) => logCliCommand(logger, "setup", () => runSetupCommand({ options, formatExplicit })),
|
|
54
63
|
});
|
|
64
|
+
};
|
|
65
|
+
const registerDoctorCommand = (cli, logger) => {
|
|
55
66
|
cli.command(CLI_COMMANDS.doctor, {
|
|
56
67
|
description: "Check whether REA is ready",
|
|
57
68
|
options: z.object({
|
|
58
69
|
target: z.string().optional().describe("Optional app path to check"),
|
|
70
|
+
client: z
|
|
71
|
+
.array(supportedClientSchema)
|
|
72
|
+
.default([])
|
|
73
|
+
.describe("Agent registration whose readiness is required; repeatable"),
|
|
74
|
+
provider: z
|
|
75
|
+
.array(z.enum(DOCTOR_PROVIDER_IDS))
|
|
76
|
+
.default([])
|
|
77
|
+
.describe("Deep-analysis provider whose readiness is required"),
|
|
78
|
+
skill: z
|
|
79
|
+
.boolean()
|
|
80
|
+
.optional()
|
|
81
|
+
.describe("Require the installed REA skill identity to be aligned"),
|
|
82
|
+
detail: z
|
|
83
|
+
.enum(["summary", "full"])
|
|
84
|
+
.default("summary")
|
|
85
|
+
.describe("Summary or complete doctor diagnostics"),
|
|
59
86
|
}),
|
|
60
|
-
run: ({ options }) => logCliCommand(logger, "doctor", () => runDoctor(options.target, createSystemDoctorHost())),
|
|
87
|
+
run: ({ options }) => logCliCommand(logger, "doctor", () => runDoctor(options.target, createSystemDoctorHost(), doctorScope(options)).then((report) => projectDoctorReport(report, options.detail))),
|
|
61
88
|
});
|
|
89
|
+
};
|
|
90
|
+
const registerMaintenanceCommands = (cli, logger) => {
|
|
62
91
|
cli.command(CLI_COMMANDS.uninstall, {
|
|
63
92
|
description: "Remove REA-owned agent configuration and skill files",
|
|
64
93
|
options: z.object({
|
|
@@ -77,32 +106,57 @@ export const registerSetupCommands = (cli, logger) => {
|
|
|
77
106
|
};
|
|
78
107
|
const runSetupCommand = async (input) => {
|
|
79
108
|
const { options } = input;
|
|
80
|
-
const interactive =
|
|
81
|
-
!options.dryRun &&
|
|
82
|
-
!input.formatExplicit &&
|
|
83
|
-
process.stdin.isTTY === true &&
|
|
84
|
-
process.stderr.isTTY === true;
|
|
109
|
+
const interactive = setupIsInteractive(options, input.formatExplicit);
|
|
85
110
|
const hasExplicitScope = setupHasExplicitScope(options);
|
|
86
111
|
if (options.yes && !hasExplicitScope)
|
|
87
|
-
process.stderr.write("! Implicit `rea setup --yes` scope is deprecated; use `--all-detected
|
|
88
|
-
const result = await runSetup(
|
|
112
|
+
process.stderr.write("! Implicit `rea setup --yes` scope is deprecated; use `--all-detected` to retain it.\n");
|
|
113
|
+
const result = await runSetup(setupRunOptions(input, interactive, hasExplicitScope), systemSetupHost(createSystemDoctorHost()), interactive
|
|
114
|
+
? (actions) => confirmInteractiveSetup(actions, options.accessible)
|
|
115
|
+
: undefined);
|
|
116
|
+
if (interactive)
|
|
117
|
+
renderInteractiveSetupResult(result);
|
|
118
|
+
return options.detail === "full" ? result : conciseSetupResult(result);
|
|
119
|
+
};
|
|
120
|
+
const setupRunOptions = (input, interactive, hasExplicitScope) => {
|
|
121
|
+
const { options } = input;
|
|
122
|
+
const agentIntegrationSelected = options.allDetected || options.client.length > 0;
|
|
123
|
+
const hasSelectedClients = hasExplicitScope && !options.allDetected;
|
|
124
|
+
return {
|
|
89
125
|
approved: options.yes && !options.dryRun,
|
|
90
126
|
installHopper: options.installHopper,
|
|
91
127
|
structured: input.formatExplicit || options.dryRun,
|
|
92
128
|
proposeHopper: !hasExplicitScope || options.installHopper,
|
|
93
|
-
...(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
129
|
+
...(hasSelectedClients ? { clientIds: options.client } : {}),
|
|
130
|
+
...(hasExplicitScope
|
|
131
|
+
? { installSkill: options.skill ?? agentIntegrationSelected }
|
|
132
|
+
: {}),
|
|
97
133
|
...(interactive ? { onProgress: renderSetupProgress } : {}),
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
134
|
+
...(hasSelectedClients
|
|
135
|
+
? {
|
|
136
|
+
readinessScope: {
|
|
137
|
+
clients: options.client,
|
|
138
|
+
providers: options.installHopper ? ["hopper"] : [],
|
|
139
|
+
skill: options.skill ?? agentIntegrationSelected,
|
|
140
|
+
},
|
|
141
|
+
}
|
|
142
|
+
: {}),
|
|
143
|
+
};
|
|
104
144
|
};
|
|
145
|
+
const setupIsInteractive = (options, formatExplicit) => !options.yes &&
|
|
146
|
+
!options.dryRun &&
|
|
147
|
+
!formatExplicit &&
|
|
148
|
+
process.stdin.isTTY === true &&
|
|
149
|
+
process.stderr.isTTY === true;
|
|
105
150
|
const setupHasExplicitScope = (options) => options.allDetected ||
|
|
106
151
|
options.client.length > 0 ||
|
|
107
152
|
options.skill !== undefined ||
|
|
108
153
|
options.installHopper;
|
|
154
|
+
const doctorScope = (options) => options.client.length === 0 &&
|
|
155
|
+
options.provider.length === 0 &&
|
|
156
|
+
options.skill === undefined
|
|
157
|
+
? undefined
|
|
158
|
+
: {
|
|
159
|
+
clients: options.client,
|
|
160
|
+
providers: options.provider,
|
|
161
|
+
skill: options.skill === true,
|
|
162
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "incur";
|
|
2
|
-
import { runProviderAnalysis,
|
|
2
|
+
import { runCapabilityStatus, runProviderAnalysis, runProviderStatus, } from "../application/DirectAnalysis.js";
|
|
3
3
|
import { importReferenceSource } from "../application/ReferenceSourceImport.js";
|
|
4
4
|
import { projectReferenceSourceImportError } from "../application/ReferenceSourceImportTypes.js";
|
|
5
5
|
import { loadConfiguredPermissionAuthority } from "../application/PermissionConfiguration.js";
|
|
@@ -22,7 +22,15 @@ const registerCapabilityCommands = (cli, logger) => {
|
|
|
22
22
|
description: command === "capabilities"
|
|
23
23
|
? "List provider capabilities and side effects"
|
|
24
24
|
: "List configured analysis providers",
|
|
25
|
-
|
|
25
|
+
options: z.object({
|
|
26
|
+
detail: z
|
|
27
|
+
.enum(["summary", "full"])
|
|
28
|
+
.default("summary")
|
|
29
|
+
.describe("Summary or complete provider descriptors"),
|
|
30
|
+
}),
|
|
31
|
+
run: ({ options }) => logCliCommand(logger, command, () => command === CLI_COMMANDS.providers
|
|
32
|
+
? runProviderStatus(logger, options.detail)
|
|
33
|
+
: runCapabilityStatus(logger, options.detail)),
|
|
26
34
|
});
|
|
27
35
|
}
|
|
28
36
|
};
|