rea-agents 2.0.0 → 2.2.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 +103 -38
- package/bridge/ghidra/ReaGhidraBridge.java +96 -11
- package/dist/application/AndroidApplicationService.js +17 -0
- package/dist/application/AppleApplicationService.js +17 -0
- package/dist/application/ArtifactExtraction.js +1 -1
- package/dist/application/ArtifactInventory/classify.js +42 -0
- package/dist/application/ArtifactInventory/hash.js +43 -0
- package/dist/application/ArtifactInventory/reader.js +41 -0
- package/dist/application/ArtifactInventory/scanCanonical.js +155 -0
- package/dist/application/ArtifactInventory/scanReader.js +124 -0
- package/dist/application/ArtifactInventory/types.js +10 -0
- package/dist/application/ArtifactInventory.js +9 -351
- package/dist/application/AuthorizedArtifactInventory.js +2 -2
- package/dist/application/BinarySession.js +47 -270
- package/dist/application/BinarySessionExecution.js +28 -0
- package/dist/application/BinarySessionOpen.js +39 -0
- package/dist/application/BinarySessionRecords.js +149 -0
- package/dist/application/BinarySessionStatus.js +75 -0
- package/dist/application/CapabilityInventory.js +24 -2
- package/dist/application/ClientRegistrationStatus.js +11 -4
- package/dist/application/CrossVersionInventory.js +8 -2
- package/dist/application/CrossVersionInvestigation.js +1 -23
- package/dist/application/CrossVersionInvestigationCollections.js +23 -0
- package/dist/application/DirectAnalysis.js +47 -44
- package/dist/application/Doctor.js +156 -238
- package/dist/application/DoctorDiagnostics.js +180 -0
- package/dist/application/ElectronBoundaryAnalysis.js +23 -7
- package/dist/application/ElectronBoundaryGraphWindows.js +32 -8
- package/dist/application/EnhancedToolPagination.js +22 -0
- package/dist/application/EnhancedToolTypes.js +4 -0
- package/dist/application/EnhancedTools.js +20 -37
- package/dist/application/InstrumentedJavaScriptReplayHost.js +36 -0
- package/dist/application/InventoryProjectionEvidence.js +41 -0
- package/dist/application/InvestigationProviders.js +12 -0
- package/dist/application/InvestigationWorkspaceStore.js +24 -10
- package/dist/application/JavaScriptArtifactAnalysis.js +45 -6
- package/dist/application/JavaScriptArtifactFiles.js +6 -2
- package/dist/application/JavaScriptArtifactGraphBuilder.js +23 -1
- package/dist/application/JavaScriptArtifactGraphBundlers.js +225 -0
- package/dist/application/JavaScriptArtifactGraphContext.js +37 -36
- package/dist/application/JavaScriptArtifactGraphDocuments.js +27 -4
- package/dist/application/JavaScriptArtifactGraphFindings.js +54 -8
- package/dist/application/JavaScriptArtifactGraphStructure.js +29 -101
- package/dist/application/JavaScriptArtifactPathResolution.js +269 -0
- package/dist/application/JavaScriptArtifactReconstruction.js +1 -1
- package/dist/application/JavaScriptJsonModules.js +39 -0
- package/dist/application/JavaScriptModuleRelationships.js +262 -0
- package/dist/application/JavaScriptReplayPermission.js +16 -0
- package/dist/application/JavaScriptReplayService.js +182 -156
- package/dist/application/LinuxHopper.js +10 -0
- package/dist/application/MacHopper.js +22 -11
- package/dist/application/NodeRuntimeCharacterizationService.js +196 -0
- package/dist/application/PermissionAuthority.js +106 -63
- package/dist/application/ProcessCaptureCapability.js +1 -1
- package/dist/application/ProcessCapturePermission.js +13 -0
- package/dist/application/ProcessCli.js +2 -12
- package/dist/application/ProcessHarness.js +1 -1
- package/dist/application/ProcessPairedExperiment.js +72 -0
- package/dist/application/ProjectPermissionStore.js +48 -9
- package/dist/application/RealHopperAssertions.js +76 -0
- package/dist/application/ReconstructionCoverageService.js +69 -0
- package/dist/application/ReconstructionCoverageWorkspaceStore.js +31 -0
- package/dist/application/RuntimeExecutableDiagnostics.js +172 -0
- package/dist/application/Setup.js +148 -260
- package/dist/application/SetupClientConfiguration.js +224 -0
- package/dist/application/SetupClients.js +24 -2
- package/dist/application/SetupPlan.js +124 -12
- package/dist/application/SetupSkill.js +54 -36
- package/dist/application/SupportedClients.js +1 -0
- package/dist/application/Uninstall.js +12 -3
- package/dist/application/Upgrade.js +16 -1
- package/dist/application/WindowsCapabilities.js +86 -0
- package/dist/artifacts/AsarArtifactReader.js +11 -0
- package/dist/browser/BrowserProcessStartup.js +88 -0
- package/dist/browser/CdpCaptureDocuments.js +12 -8
- package/dist/browser/CdpCaptureEventBodyShapes.js +75 -0
- package/dist/browser/CdpCaptureEventHandlers.js +336 -0
- package/dist/browser/CdpCaptureEventHelpers.js +71 -0
- package/dist/browser/CdpCaptureEventState.js +1 -0
- package/dist/browser/CdpCaptureEventTypes.js +1 -0
- package/dist/browser/CdpCaptureEvents.js +29 -496
- package/dist/browser/CdpObservationSession.js +51 -8
- package/dist/browser/CdpPageCapture.js +12 -133
- package/dist/browser/CdpPageCaptureScripts.js +97 -0
- package/dist/browser/CdpPageCaptureWorkers.js +46 -0
- package/dist/browser/CdpWebMcpDiscovery.js +38 -14
- package/dist/browser/PngVisualDiff.js +9 -2
- package/dist/catalogIdentity.js +4 -0
- package/dist/cli/artifactCommands.js +82 -0
- package/dist/cli/coreAnalysisCommands.js +232 -0
- package/dist/cli/managedCommands.js +397 -0
- package/dist/cli/managedProjectGraphCommand.js +24 -0
- package/dist/cli/options.js +9 -0
- package/dist/cli/setupCommands.js +113 -0
- package/dist/cli/types.js +1 -0
- package/dist/cli/utilityCommands.js +122 -0
- package/dist/cli.js +10 -768
- package/dist/cliApplicationCommands.js +118 -4
- package/dist/cliBrowserAdvancedCommands.js +73 -16
- package/dist/cliBrowserCommands.js +39 -115
- package/dist/cliCommandNames.js +4 -0
- package/dist/cliElectronCommands.js +33 -62
- package/dist/cliEvidenceCommands.js +13 -2
- package/dist/cliInvestigationCommands.js +53 -10
- package/dist/cliObservationOptions.js +137 -0
- package/dist/cliPolicyCommands.js +80 -46
- package/dist/cliSetup.js +306 -0
- package/dist/config/environment.js +107 -0
- package/dist/config/parseConfig.js +228 -0
- package/dist/config/parsers.js +68 -0
- package/dist/config/permissions.js +30 -0
- package/dist/config/types.js +1 -0
- package/dist/config.js +1 -375
- package/dist/contracts/applicationToolContracts.js +134 -0
- package/dist/contracts/electronToolContracts.js +51 -3
- package/dist/contracts/managedToolContracts.js +8 -3
- package/dist/contracts/managedWorkflowToolContracts.js +3 -3
- package/dist/contracts/providerSelection.js +2 -0
- package/dist/contracts/sessionStatusContract.js +26 -0
- package/dist/contracts/toolContractTypes.js +12 -1
- package/dist/contracts/toolContracts.js +5 -12
- package/dist/contracts/toolEffects.js +14 -0
- package/dist/contracts/toolOutputSchemaGroups.js +274 -0
- package/dist/contracts/toolOutputSchemaPrimitives.js +328 -0
- package/dist/contracts/toolOutputSchemas.js +2 -550
- package/dist/domain/analysisErrorPresentation.js +234 -0
- package/dist/domain/analysisErrorProjection.js +284 -0
- package/dist/domain/androidApplication.js +206 -0
- package/dist/domain/appleApplication.js +221 -0
- package/dist/domain/artifactComparison.js +34 -15
- package/dist/domain/binaryTarget.js +87 -37
- package/dist/domain/boundedCartesianProjection.js +15 -0
- package/dist/domain/browserObservation.js +1 -285
- package/dist/domain/browserObservationSchemas.js +286 -0
- package/dist/domain/electronStaticAnalysisBrowser.js +14 -2
- package/dist/domain/errors.js +4 -486
- package/dist/domain/functionComparison.js +4 -165
- package/dist/domain/functionComparisonDimensions.js +164 -0
- package/dist/domain/javascriptApplicationVersionItems.js +18 -6
- package/dist/domain/javascriptApplicationVersionKeys.js +8 -8
- package/dist/domain/javascriptExportInstrumentation.js +97 -0
- package/dist/domain/javascriptFeatureTraversal.js +19 -7
- package/dist/domain/javascriptRuntimeStaticCandidates.js +3 -1
- package/dist/domain/javascriptSemanticAnalysis.js +386 -0
- package/dist/domain/javascriptSemanticIr.js +30 -0
- package/dist/domain/javascriptSemanticProjection.js +366 -0
- package/dist/domain/javascriptSemanticState.js +40 -0
- package/dist/domain/javascriptSemanticTraversal.js +22 -0
- package/dist/domain/javascriptSemanticValues.js +352 -0
- package/dist/domain/javascriptStaticAnalysis.js +5 -221
- package/dist/domain/javascriptStaticAnalysisBundler.js +209 -0
- package/dist/domain/javascriptStaticAnalysisCalls.js +180 -0
- package/dist/domain/javascriptStaticAnalysisHelpers.js +71 -2
- package/dist/domain/knownPageCoverage.js +21 -0
- package/dist/domain/managedApplicationGraph.js +14 -364
- package/dist/domain/managedApplicationGraphCoverage.js +170 -0
- package/dist/domain/managedApplicationGraphNodeCoverage.js +6 -0
- package/dist/domain/managedApplicationGraphNodes.js +336 -0
- package/dist/domain/managedArtifact.js +16 -8
- package/dist/domain/managedMemberComparison.js +37 -391
- package/dist/domain/managedMemberComparisonCoverage.js +72 -0
- package/dist/domain/managedMemberComparisonMatch.js +356 -0
- package/dist/domain/managedNativeVerification.js +27 -389
- package/dist/domain/managedNativeVerificationMatch.js +272 -0
- package/dist/domain/managedNativeVerificationSchemas.js +141 -0
- package/dist/domain/managedReconstruction.js +82 -69
- package/dist/domain/managedRuntimeCorrelation.js +12 -3
- package/dist/domain/nodeRuntimeCharacterization.js +66 -0
- package/dist/domain/permissionPolicy.js +2 -0
- package/dist/domain/processComparison.js +19 -0
- package/dist/domain/processPairedExperiment.js +128 -0
- package/dist/domain/reconstructionCoverage.js +387 -0
- package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
- package/dist/domain/reconstructionVerificationSchemas.js +8 -0
- package/dist/domain/replayMachine.js +316 -0
- package/dist/domain/replayMachineRuntime.js +215 -0
- package/dist/domain/runtimeCharacterization.js +85 -0
- package/dist/domain/runtimeIdentification.js +210 -0
- package/dist/domain/webBundleAnalyzer.js +3 -409
- package/dist/domain/webBundleAnalyzerAst.js +77 -0
- package/dist/domain/webBundleAnalyzerInspection.js +307 -0
- package/dist/domain/webBundleAnalyzerResult.js +120 -0
- package/dist/dotnet/ManagedArtifactInspector.js +50 -29
- package/dist/dotnet/ManagedMemberInspector.js +51 -785
- package/dist/dotnet/ManagedMemberInspectorCore.js +297 -0
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +427 -0
- package/dist/dotnet/ManagedMemberRows.js +120 -0
- package/dist/dotnet/ManagedMetadataInventory.js +42 -306
- package/dist/dotnet/ManagedMetadataInventoryRows.js +292 -0
- package/dist/dotnet/ManagedMetadataLayout.js +48 -111
- package/dist/dotnet/ManagedMetadataRowSizes.js +54 -0
- package/dist/dotnet/ManagedMethodBodyReader.js +143 -0
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +311 -0
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +102 -350
- package/dist/dotnet/ManagedPeReader.js +59 -28
- package/dist/evaluation/CodexAgentEval.js +132 -0
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraClient.js +76 -91
- package/dist/ghidra/GhidraClientStartup.js +29 -0
- package/dist/ghidra/GhidraClientWire.js +34 -0
- package/dist/ghidra/GhidraDefaults.js +1 -1
- package/dist/ghidra/GhidraDiagnostics.js +6 -1
- package/dist/ghidra/GhidraInstallation.js +20 -15
- package/dist/ghidra/GhidraLauncher.js +93 -29
- package/dist/ghidra/GhidraProvider.js +61 -161
- package/dist/ghidra/GhidraProviderCapabilities.js +173 -0
- package/dist/ghidra/GhidraSessionValues.js +2 -0
- package/dist/ghidra/GhidraSocketConnection.js +44 -7
- package/dist/ghidra/GhidraTargetSnapshot.js +30 -0
- package/dist/ghidra/GhidraTransport.js +71 -0
- package/dist/identity.js +4 -2
- package/dist/main/messages.js +5 -0
- package/dist/main/reload.js +49 -0
- package/dist/main/shutdown.js +25 -0
- package/dist/main/startup.js +14 -0
- package/dist/main/state.js +26 -0
- package/dist/main/transport.js +61 -0
- package/dist/main/types.js +1 -0
- package/dist/main.js +35 -146
- package/dist/process/PrivateRuntimeRoot.js +3 -2
- package/dist/process/ProcessOwnership.js +35 -0
- package/dist/process/ProviderProcess.js +2 -0
- package/dist/replay/JavaScriptReplayWorker.js +64 -50
- package/dist/replay/LinuxJavaScriptReplayRunner.js +173 -390
- package/dist/replay/LinuxJavaScriptReplaySandbox.js +140 -0
- package/dist/replay/ReplayOutcome.js +95 -0
- package/dist/replay/ReplayProcessLifecycle.js +71 -0
- package/dist/server/ProcessCaptureElicitation.js +157 -0
- package/dist/server/createServer.js +124 -56
- package/dist/server/javascriptApplicationResult.js +85 -0
- package/dist/server/registerApplicationTools/characterization.js +57 -0
- package/dist/server/registerApplicationTools/compareVersions.js +34 -0
- package/dist/server/registerApplicationTools/controlledReplay.js +38 -0
- package/dist/server/registerApplicationTools/coverage.js +84 -0
- package/dist/server/registerApplicationTools/helpers.js +42 -0
- package/dist/server/registerApplicationTools/traceFeature.js +26 -0
- package/dist/server/registerApplicationTools/types.js +1 -0
- package/dist/server/registerApplicationTools.js +10 -112
- package/dist/server/registerBrowserTools.js +59 -83
- package/dist/server/registerElectronTools.js +48 -49
- package/dist/server/registerEnhancedTools.js +34 -42
- package/dist/server/registerEvidenceResources.js +56 -0
- package/dist/server/registerInvestigationTools/helpers.js +74 -0
- package/dist/server/registerInvestigationTools/types.js +1 -0
- package/dist/server/registerInvestigationTools.js +83 -116
- package/dist/server/registerJavaScriptApplicationGraphResource.js +69 -0
- package/dist/server/registerManagedTools.js +18 -1
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +65 -0
- package/dist/server/registerManagedWorkflowTools/contract.js +8 -0
- package/dist/server/registerManagedWorkflowTools/evidence.js +43 -0
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +39 -0
- package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +39 -0
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +52 -0
- package/dist/server/registerManagedWorkflowTools/types.js +1 -0
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +75 -0
- package/dist/server/registerManagedWorkflowTools.js +10 -274
- package/dist/server/registerOfficialTools.js +73 -59
- package/dist/server/registerSessionRecordTools.js +137 -0
- package/dist/server/registerSessionStatusTool.js +97 -26
- package/dist/server/registerSessionTools.js +60 -164
- package/dist/server/sessionAvailabilityPolicy.js +10 -0
- package/dist/server/toolRegistrationOptions.js +101 -3
- package/dist/server/toolResult.js +15 -4
- package/package.json +11 -11
- package/skills/reverse-engineer-anything/SKILL.md +76 -0
- 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 +25 -0
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +36 -0
- package/skills/reverse-engineer-anything/references/runtime-observation.md +24 -0
- package/scripts/prepare-node-pty.mjs +0 -35
- package/scripts/rebuild-native.mjs +0 -22
- package/skills/rea-analysis/SKILL.md +0 -222
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { constants as fsConstants } from "node:fs";
|
|
2
|
+
import { copyFile, mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import writeFileAtomic from "write-file-atomic";
|
|
6
|
+
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
|
|
7
|
+
import { PRODUCT_IDENTITY } from "../identity.js";
|
|
8
|
+
import { resolveClientConfigTransactionPath } from "./ClientConfigPath.js";
|
|
9
|
+
const defaultCommand = () => [
|
|
10
|
+
"npx",
|
|
11
|
+
"-y",
|
|
12
|
+
PRODUCT_IDENTITY.registrationPackageSpecifier,
|
|
13
|
+
"mcp",
|
|
14
|
+
];
|
|
15
|
+
const CODEX_STARTUP_TIMEOUT_SECONDS = 30;
|
|
16
|
+
/** Back up, atomically update, and semantically read back one JSON MCP configuration. */
|
|
17
|
+
export const configureJsonClient = async (client, environment = {}, command = defaultCommand()) => {
|
|
18
|
+
const transactionPath = await resolveClientConfigTransactionPath(client.configPath);
|
|
19
|
+
if (transactionPath === undefined)
|
|
20
|
+
return { status: "failed", reason: "path" };
|
|
21
|
+
let document = {};
|
|
22
|
+
let original;
|
|
23
|
+
try {
|
|
24
|
+
original = await readFile(transactionPath, "utf8");
|
|
25
|
+
document = parseObject(original);
|
|
26
|
+
}
|
|
27
|
+
catch (cause) {
|
|
28
|
+
if (!isMissing(cause))
|
|
29
|
+
return { status: "failed", reason: "readback" };
|
|
30
|
+
}
|
|
31
|
+
let servers;
|
|
32
|
+
try {
|
|
33
|
+
servers = parseOptionalObject(document.mcpServers);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return { status: "failed", reason: "readback" };
|
|
37
|
+
}
|
|
38
|
+
const desired = clientConfigurationDesired(client, normalizeProviderEnvironment(environment), command);
|
|
39
|
+
if (sameConfiguration(servers[PRODUCT_IDENTITY.mcpServerKey], desired))
|
|
40
|
+
return { status: "unchanged" };
|
|
41
|
+
let backupPath;
|
|
42
|
+
if (original !== undefined) {
|
|
43
|
+
backupPath = `${client.configPath}.rea.backup`;
|
|
44
|
+
if (!(await preserveConfigBackup(transactionPath, backupPath)))
|
|
45
|
+
return { status: "failed", reason: "backup" };
|
|
46
|
+
}
|
|
47
|
+
document.mcpServers = {
|
|
48
|
+
...servers,
|
|
49
|
+
[PRODUCT_IDENTITY.mcpServerKey]: desired,
|
|
50
|
+
};
|
|
51
|
+
try {
|
|
52
|
+
await mkdir(dirname(client.configPath), { recursive: true });
|
|
53
|
+
await writeFileAtomic(transactionPath, `${JSON.stringify(document, null, 2)}\n`, {
|
|
54
|
+
encoding: "utf8",
|
|
55
|
+
mode: 0o600,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return { status: "failed", reason: "write" };
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const readback = parseObject(await readFile(transactionPath, "utf8"));
|
|
63
|
+
if (!sameConfiguration(parseOptionalObject(readback.mcpServers)[PRODUCT_IDENTITY.mcpServerKey], desired)) {
|
|
64
|
+
await restoreConfig(transactionPath, original);
|
|
65
|
+
return { status: "failed", reason: "readback" };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
await restoreConfig(transactionPath, original);
|
|
70
|
+
return { status: "failed", reason: "readback" };
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
status: "configured",
|
|
74
|
+
...(backupPath === undefined ? {} : { backupPath }),
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
/** Back up, atomically update, and semantically read back Codex TOML configuration. */
|
|
78
|
+
export const configureTomlClient = async (client, environment = {}, command = defaultCommand()) => {
|
|
79
|
+
const transactionPath = await resolveClientConfigTransactionPath(client.configPath);
|
|
80
|
+
if (transactionPath === undefined)
|
|
81
|
+
return { status: "failed", reason: "path" };
|
|
82
|
+
let document = {};
|
|
83
|
+
let original;
|
|
84
|
+
try {
|
|
85
|
+
original = await readFile(transactionPath, "utf8");
|
|
86
|
+
document = objectSchema.parse(parseToml(original));
|
|
87
|
+
}
|
|
88
|
+
catch (cause) {
|
|
89
|
+
if (!isMissing(cause))
|
|
90
|
+
return { status: "failed", reason: "readback" };
|
|
91
|
+
}
|
|
92
|
+
let servers;
|
|
93
|
+
try {
|
|
94
|
+
servers = parseOptionalObject(document.mcp_servers);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return { status: "failed", reason: "readback" };
|
|
98
|
+
}
|
|
99
|
+
const desired = clientConfigurationDesired(client, normalizeProviderEnvironment(environment), command);
|
|
100
|
+
if (sameConfiguration(servers[PRODUCT_IDENTITY.mcpServerKey], desired))
|
|
101
|
+
return { status: "unchanged" };
|
|
102
|
+
const backupPath = original === undefined ? undefined : `${client.configPath}.rea.backup`;
|
|
103
|
+
if (backupPath !== undefined &&
|
|
104
|
+
!(await preserveConfigBackup(transactionPath, backupPath)))
|
|
105
|
+
return { status: "failed", reason: "backup" };
|
|
106
|
+
document.mcp_servers = {
|
|
107
|
+
...servers,
|
|
108
|
+
[PRODUCT_IDENTITY.mcpServerKey]: desired,
|
|
109
|
+
};
|
|
110
|
+
try {
|
|
111
|
+
await mkdir(dirname(client.configPath), { recursive: true });
|
|
112
|
+
await writeFileAtomic(transactionPath, stringifyToml(document), {
|
|
113
|
+
encoding: "utf8",
|
|
114
|
+
mode: 0o600,
|
|
115
|
+
});
|
|
116
|
+
const readback = objectSchema.parse(parseToml(await readFile(transactionPath, "utf8")));
|
|
117
|
+
if (!sameConfiguration(parseOptionalObject(readback.mcp_servers)[PRODUCT_IDENTITY.mcpServerKey], desired))
|
|
118
|
+
throw new Error("TOML readback mismatch");
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
await restoreConfig(transactionPath, original);
|
|
122
|
+
return { status: "failed", reason: "readback" };
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
status: "configured",
|
|
126
|
+
...(backupPath === undefined ? {} : { backupPath }),
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
/** Determine whether an existing client configuration matches the desired registration. */
|
|
130
|
+
export const clientConfigurationAligned = async (client, providerEnvironment, command) => {
|
|
131
|
+
const desired = clientConfigurationDesired(client, providerEnvironment, command);
|
|
132
|
+
try {
|
|
133
|
+
const original = await readFile(client.configPath, "utf8");
|
|
134
|
+
const document = client.format === "toml"
|
|
135
|
+
? objectSchema.parse(parseToml(original))
|
|
136
|
+
: parseObject(original);
|
|
137
|
+
const servers = parseOptionalObject(client.format === "toml" ? document.mcp_servers : document.mcpServers);
|
|
138
|
+
return sameConfiguration(servers[PRODUCT_IDENTITY.mcpServerKey], desired);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
/** Preflight one client configuration before setup presents any mutations. */
|
|
145
|
+
export const inspectClientConfiguration = async (client, providerEnvironment, command) => {
|
|
146
|
+
if (client.format === "unsupported")
|
|
147
|
+
return { status: "already_current" };
|
|
148
|
+
const transactionPath = await resolveClientConfigTransactionPath(client.configPath);
|
|
149
|
+
if (transactionPath === undefined)
|
|
150
|
+
return {
|
|
151
|
+
status: "invalid",
|
|
152
|
+
remediation: "The configuration path is unsafe or unresolved. Check ownership and symbolic links before rerunning setup.",
|
|
153
|
+
};
|
|
154
|
+
let original;
|
|
155
|
+
try {
|
|
156
|
+
original = await readFile(transactionPath, "utf8");
|
|
157
|
+
}
|
|
158
|
+
catch (cause) {
|
|
159
|
+
if (isMissing(cause))
|
|
160
|
+
return { status: "create" };
|
|
161
|
+
return {
|
|
162
|
+
status: "invalid",
|
|
163
|
+
remediation: "The configuration file could not be read. Check its permissions before rerunning setup.",
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const desired = clientConfigurationDesired(client, providerEnvironment, command);
|
|
167
|
+
try {
|
|
168
|
+
const document = client.format === "toml"
|
|
169
|
+
? objectSchema.parse(parseToml(original))
|
|
170
|
+
: parseObject(original);
|
|
171
|
+
const servers = parseOptionalObject(client.format === "toml" ? document.mcp_servers : document.mcpServers);
|
|
172
|
+
if (sameConfiguration(servers[PRODUCT_IDENTITY.mcpServerKey], desired))
|
|
173
|
+
return { status: "already_current" };
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
return {
|
|
177
|
+
status: "invalid",
|
|
178
|
+
remediation: "The existing configuration is malformed. Repair it before setup applies any other changes.",
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
status: "update",
|
|
183
|
+
backupPath: `${client.configPath}.rea.backup`,
|
|
184
|
+
};
|
|
185
|
+
};
|
|
186
|
+
const objectSchema = z.record(z.string(), z.unknown());
|
|
187
|
+
const parseOptionalObject = (value) => value === undefined ? {} : objectSchema.parse(value);
|
|
188
|
+
const parseObject = (text) => objectSchema.parse(JSON.parse(text));
|
|
189
|
+
const isMissing = (cause) => cause instanceof Error && "code" in cause && cause.code === "ENOENT";
|
|
190
|
+
const sameConfiguration = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
191
|
+
const preserveConfigBackup = async (source, destination) => {
|
|
192
|
+
try {
|
|
193
|
+
await copyFile(source, destination, fsConstants.COPYFILE_EXCL);
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
catch (cause) {
|
|
197
|
+
return cause instanceof Error && "code" in cause && cause.code === "EEXIST";
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
const restoreConfig = async (path, original) => {
|
|
201
|
+
try {
|
|
202
|
+
if (original === undefined)
|
|
203
|
+
await rm(path, { force: true });
|
|
204
|
+
else
|
|
205
|
+
await writeFile(path, original, { encoding: "utf8", mode: 0o600 });
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
// The backup remains available for the remediation reported by setup.
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
const clientConfigurationDesired = (client, providerEnvironment, command) => {
|
|
212
|
+
const environment = Object.fromEntries(Object.entries(providerEnvironment).sort(([left], [right]) => left.localeCompare(right)));
|
|
213
|
+
return {
|
|
214
|
+
command: command[0] ?? PRODUCT_IDENTITY.cliBinary,
|
|
215
|
+
args: command.slice(1),
|
|
216
|
+
...(client.name === "codex"
|
|
217
|
+
? { startup_timeout_sec: CODEX_STARTUP_TIMEOUT_SECONDS }
|
|
218
|
+
: {}),
|
|
219
|
+
...(Object.keys(environment).length === 0 ? {} : { env: environment }),
|
|
220
|
+
};
|
|
221
|
+
};
|
|
222
|
+
const normalizeProviderEnvironment = (environment) => typeof environment === "string"
|
|
223
|
+
? { HOPPER_LAUNCHER_PATH: environment }
|
|
224
|
+
: environment;
|
|
@@ -11,12 +11,34 @@ const failedConfigurationMessage = (reason) => {
|
|
|
11
11
|
export const configureDetectedClients = async (options) => {
|
|
12
12
|
let failure;
|
|
13
13
|
for (const client of options.detectedClients) {
|
|
14
|
+
const actionId = `configure_client:${client.name}`;
|
|
15
|
+
const label = client.displayName ?? client.name;
|
|
16
|
+
options.onProgress?.({ actionId, label, state: "started" });
|
|
14
17
|
const result = await options.host.configureClient(client, options.providerEnvironment, options.command);
|
|
15
18
|
options.clients[client.name] = result;
|
|
16
|
-
if (result.status === "failed")
|
|
19
|
+
if (result.status === "failed") {
|
|
17
20
|
failure ??= failedConfigurationMessage(result.reason);
|
|
18
|
-
|
|
21
|
+
options.onProgress?.({
|
|
22
|
+
actionId,
|
|
23
|
+
label,
|
|
24
|
+
state: "failed",
|
|
25
|
+
detail: failedConfigurationMessage(result.reason),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
else if (result.status === "configured") {
|
|
19
29
|
options.appliedActions.push(`configured_${client.name}`);
|
|
30
|
+
options.onProgress?.({ actionId, label, state: "completed" });
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
options.onProgress?.({
|
|
34
|
+
actionId,
|
|
35
|
+
label,
|
|
36
|
+
state: "warning",
|
|
37
|
+
detail: result.status === "unchanged"
|
|
38
|
+
? "Already current"
|
|
39
|
+
: "Manual configuration required",
|
|
40
|
+
});
|
|
41
|
+
}
|
|
20
42
|
}
|
|
21
43
|
return failure;
|
|
22
44
|
};
|
|
@@ -1,38 +1,150 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { PRODUCT_IDENTITY } from "../identity.js";
|
|
4
|
+
import { linuxHopperInstallDisclosure, } from "./LinuxHopper.js";
|
|
5
|
+
import { macHopperInstallDisclosure } from "./MacHopper.js";
|
|
1
6
|
/** Build the complete setup mutation plan before approval. */
|
|
2
|
-
|
|
3
|
-
...(installHopper
|
|
7
|
+
const setupPlan = (input) => [
|
|
8
|
+
...(input.installHopper
|
|
4
9
|
? [
|
|
5
10
|
{
|
|
11
|
+
id: "install_hopper",
|
|
6
12
|
kind: "install_hopper",
|
|
7
|
-
|
|
8
|
-
|
|
13
|
+
label: "Hopper deep-analysis provider",
|
|
14
|
+
target: input.platform === "darwin"
|
|
15
|
+
? join(homedir(), "Applications/Hopper Disassembler.app")
|
|
9
16
|
: "system package manager",
|
|
10
|
-
detail: platform === "linux"
|
|
17
|
+
detail: input.platform === "linux"
|
|
11
18
|
? "Download, verify, and install Hopper plus its Xvfb demo-session dependencies. For the supported demo build, REA uses a private display and selects Hopper's offered demo mode for each analysis session."
|
|
12
19
|
: "Download the official Hopper package, verify it, and install it. Hopper may show its demo or license prompt when first opened.",
|
|
13
20
|
external: true,
|
|
21
|
+
operation: "install",
|
|
22
|
+
...(input.platform === "linux"
|
|
23
|
+
? input.linuxPackageFamily === undefined
|
|
24
|
+
? {}
|
|
25
|
+
: linuxDisclosure(input.linuxPackageFamily)
|
|
26
|
+
: {
|
|
27
|
+
networkOrigins: macHopperInstallDisclosure.networkOrigins,
|
|
28
|
+
commands: macHopperInstallDisclosure.commands,
|
|
29
|
+
}),
|
|
14
30
|
},
|
|
15
31
|
]
|
|
16
32
|
: []),
|
|
17
|
-
...clients
|
|
18
|
-
.filter(({
|
|
19
|
-
.map((client) => ({
|
|
33
|
+
...input.clients
|
|
34
|
+
.filter(({ client }) => client.format !== "unsupported")
|
|
35
|
+
.map(({ client, operation, backupPath }) => ({
|
|
36
|
+
id: `configure_client:${client.name}`,
|
|
20
37
|
kind: "configure_client",
|
|
38
|
+
label: client.displayName ?? client.name,
|
|
21
39
|
target: client.configPath,
|
|
22
|
-
detail: clientConfigurationDetail(client.name, providerEnvironment),
|
|
40
|
+
detail: clientConfigurationDetail(client.displayName ?? client.name, input.providerEnvironment),
|
|
23
41
|
external: false,
|
|
42
|
+
operation,
|
|
43
|
+
...(backupPath === undefined ? {} : { backupPath }),
|
|
24
44
|
})),
|
|
25
|
-
...(installSkill
|
|
45
|
+
...(input.installSkill
|
|
26
46
|
? [
|
|
27
47
|
{
|
|
48
|
+
id: "install_skill",
|
|
28
49
|
kind: "install_skill",
|
|
29
|
-
|
|
30
|
-
|
|
50
|
+
label: "REA reverse-engineering skill",
|
|
51
|
+
target: join(homedir(), ".agents/skills", PRODUCT_IDENTITY.skillName),
|
|
52
|
+
detail: "Install or update the bundled REA reverse-engineering skill and on-demand references.",
|
|
31
53
|
external: false,
|
|
54
|
+
operation: "install",
|
|
32
55
|
},
|
|
33
56
|
]
|
|
34
57
|
: []),
|
|
35
58
|
];
|
|
59
|
+
/** Discover and preflight the complete set of selectable setup actions. */
|
|
60
|
+
export const discoverSetupActions = async (input) => {
|
|
61
|
+
const { host, providerEnvironment, command } = input;
|
|
62
|
+
const initialDoctor = await host.doctor();
|
|
63
|
+
const linuxHopperRepairNeeded = initialDoctor.checks.some(({ name, ok, detail }) => !ok &&
|
|
64
|
+
(name === "hopper-demo-runtime" ||
|
|
65
|
+
(name === "hopper-version" && detail === "/opt/hopper/bin/Hopper")));
|
|
66
|
+
const installHopper = input.forceHopperInstall ||
|
|
67
|
+
(input.proposeHopper &&
|
|
68
|
+
(Object.keys(providerEnvironment).length === 0 ||
|
|
69
|
+
linuxHopperRepairNeeded));
|
|
70
|
+
const [allDetectedClients, skillNeedsInstall] = await Promise.all([
|
|
71
|
+
host.detectedClients(),
|
|
72
|
+
host.skillNeedsInstall(),
|
|
73
|
+
]);
|
|
74
|
+
const selectedClientIdSet = input.selectedClientIds === undefined
|
|
75
|
+
? undefined
|
|
76
|
+
: new Set(input.selectedClientIds);
|
|
77
|
+
const detectedClients = allDetectedClients.filter(({ name }) => selectedClientIdSet === undefined || selectedClientIdSet.has(name));
|
|
78
|
+
const installSkill = input.installSkillSelection === false ? false : skillNeedsInstall;
|
|
79
|
+
const clients = installHopper
|
|
80
|
+
? detectedClients
|
|
81
|
+
: await filterClientsNeedingConfigure({
|
|
82
|
+
host,
|
|
83
|
+
clients: detectedClients,
|
|
84
|
+
providerEnvironment,
|
|
85
|
+
command,
|
|
86
|
+
});
|
|
87
|
+
const inspections = await inspectClients({
|
|
88
|
+
host,
|
|
89
|
+
clients,
|
|
90
|
+
providerEnvironment,
|
|
91
|
+
command,
|
|
92
|
+
});
|
|
93
|
+
const invalid = inspections.find(({ inspection }) => inspection.status === "invalid");
|
|
94
|
+
const blocker = invalid?.inspection.status === "invalid"
|
|
95
|
+
? `${invalid.client.displayName ?? invalid.client.name}: ${invalid.inspection.remediation}`
|
|
96
|
+
: undefined;
|
|
97
|
+
const clientPlans = inspections.flatMap(({ client, inspection }) => inspection.status === "create" ||
|
|
98
|
+
inspection.status === "update" ||
|
|
99
|
+
(installHopper && inspection.status === "already_current")
|
|
100
|
+
? [
|
|
101
|
+
{
|
|
102
|
+
client,
|
|
103
|
+
operation: inspection.status === "already_current"
|
|
104
|
+
? "update"
|
|
105
|
+
: inspection.status,
|
|
106
|
+
...(inspection.status !== "already_current" &&
|
|
107
|
+
inspection.backupPath !== undefined
|
|
108
|
+
? { backupPath: inspection.backupPath }
|
|
109
|
+
: {}),
|
|
110
|
+
},
|
|
111
|
+
]
|
|
112
|
+
: []);
|
|
113
|
+
const linuxDistribution = host.platform === "linux" ? await host.linuxDistribution() : undefined;
|
|
114
|
+
return {
|
|
115
|
+
initialDoctor,
|
|
116
|
+
installHopper,
|
|
117
|
+
installSkill,
|
|
118
|
+
detectedClients: clientPlans.map(({ client }) => client),
|
|
119
|
+
plannedActions: setupPlan({
|
|
120
|
+
platform: host.platform,
|
|
121
|
+
installHopper,
|
|
122
|
+
installSkill,
|
|
123
|
+
clients: clientPlans,
|
|
124
|
+
providerEnvironment,
|
|
125
|
+
...(linuxDistribution?.packageFamily === undefined
|
|
126
|
+
? {}
|
|
127
|
+
: { linuxPackageFamily: linuxDistribution.packageFamily }),
|
|
128
|
+
}),
|
|
129
|
+
blocker,
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
const inspectClients = async (input) => Promise.all(input.clients.map(async (client) => ({
|
|
133
|
+
client,
|
|
134
|
+
inspection: (await input.host.inspectClientConfiguration?.(client, input.providerEnvironment, input.command)) ?? { status: "update" },
|
|
135
|
+
})));
|
|
136
|
+
const filterClientsNeedingConfigure = async (input) => {
|
|
137
|
+
const needs = await Promise.all(input.clients.map((client) => input.host.clientNeedsConfigure(client, input.providerEnvironment, input.command)));
|
|
138
|
+
return input.clients.filter((_, index) => needs[index]);
|
|
139
|
+
};
|
|
140
|
+
const linuxDisclosure = (family) => {
|
|
141
|
+
const disclosure = linuxHopperInstallDisclosure(family, process.getuid?.() === 0);
|
|
142
|
+
return {
|
|
143
|
+
networkOrigins: [disclosure.downloadUrl],
|
|
144
|
+
commands: disclosure.commands,
|
|
145
|
+
integrity: `${String(disclosure.expectedBytes)} bytes · SHA-1 ${disclosure.expectedSha1}`,
|
|
146
|
+
};
|
|
147
|
+
};
|
|
36
148
|
const clientConfigurationDetail = (client, environment) => {
|
|
37
149
|
const entries = Object.entries(environment)
|
|
38
150
|
.sort(([left], [right]) => left.localeCompare(right))
|
|
@@ -2,59 +2,77 @@ 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
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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);
|
|
14
|
+
const readOptionalText = async (path) => {
|
|
15
|
+
try {
|
|
16
|
+
return await readFile(path, "utf8");
|
|
17
|
+
}
|
|
18
|
+
catch (cause) {
|
|
19
|
+
if (cause instanceof Error && "code" in cause && cause.code === "ENOENT")
|
|
20
|
+
return undefined;
|
|
21
|
+
throw cause;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
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. */
|
|
10
33
|
export const canonicalSkillNeedsInstall = async (home) => {
|
|
11
34
|
try {
|
|
12
|
-
|
|
13
|
-
return (await readFile(destination, "utf8")) !== content;
|
|
35
|
+
return (await canonicalSkillFiles(home)).some(({ content, original }) => original !== content);
|
|
14
36
|
}
|
|
15
37
|
catch {
|
|
16
38
|
return true;
|
|
17
39
|
}
|
|
18
40
|
};
|
|
19
|
-
|
|
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. */
|
|
20
51
|
export const installCanonicalSkill = async (home) => {
|
|
21
|
-
let
|
|
22
|
-
let backup = `${destination}.rea.backup`;
|
|
23
|
-
let original;
|
|
52
|
+
let changed = [];
|
|
24
53
|
try {
|
|
25
54
|
const canonical = await canonicalSkillFiles(home);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const { content } = canonical;
|
|
29
|
-
original = await readFile(destination, "utf8").catch(() => undefined);
|
|
30
|
-
if (original === content)
|
|
55
|
+
changed = canonical.filter(({ content, original }) => original !== content);
|
|
56
|
+
if (changed.length === 0)
|
|
31
57
|
return "unchanged";
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if ((await readFile(destination, "utf8")) !== content)
|
|
43
|
-
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}`);
|
|
44
68
|
return "installed";
|
|
45
69
|
}
|
|
46
70
|
catch {
|
|
47
71
|
try {
|
|
48
|
-
|
|
49
|
-
await rm(destination, { force: true });
|
|
50
|
-
else
|
|
51
|
-
await writeFileAtomic(destination, original, {
|
|
52
|
-
encoding: "utf8",
|
|
53
|
-
mode: 0o600,
|
|
54
|
-
});
|
|
72
|
+
await restoreSkillFiles(changed);
|
|
55
73
|
}
|
|
56
74
|
catch {
|
|
57
|
-
//
|
|
75
|
+
// Per-file backups remain beside changed files for operator recovery.
|
|
58
76
|
}
|
|
59
77
|
return "failed";
|
|
60
78
|
}
|
|
@@ -59,6 +59,7 @@ export const SUPPORTED_CLIENT_DEFINITIONS = [
|
|
|
59
59
|
/** Describe every client location that setup, doctor, or uninstall may inspect. */
|
|
60
60
|
export const supportedClients = (home) => SUPPORTED_CLIENT_DEFINITIONS.map((definition) => ({
|
|
61
61
|
name: definition.name,
|
|
62
|
+
displayName: definition.displayName,
|
|
62
63
|
configPath: join(home, ...definition.configPath),
|
|
63
64
|
markerPath: join(home, ...definition.markerPath),
|
|
64
65
|
format: definition.format,
|
|
@@ -39,7 +39,7 @@ export const runUninstall = async (purgeData, host = systemUninstallHost()) => {
|
|
|
39
39
|
export const systemUninstallHost = (home = homedir(), fileSystem = systemFileSystem) => ({
|
|
40
40
|
clients: () => Promise.resolve(supportedClients(home)),
|
|
41
41
|
removeClient: (client) => removeClient(client, fileSystem),
|
|
42
|
-
removeSkill: () =>
|
|
42
|
+
removeSkill: () => removeManagedSkills(home, fileSystem),
|
|
43
43
|
purgeData: async () => [
|
|
44
44
|
await removeManagedPath(join(home, ".rea/cache"), "cache", fileSystem),
|
|
45
45
|
await removeManagedPath(join(home, ".rea/state"), "state", fileSystem),
|
|
@@ -127,8 +127,16 @@ const isOwnedRegistration = (value) => {
|
|
|
127
127
|
args.length === 1 &&
|
|
128
128
|
args[0] === "mcp") ||
|
|
129
129
|
(command === "npx" &&
|
|
130
|
-
JSON.stringify(args) ===
|
|
131
|
-
JSON.stringify([
|
|
130
|
+
(JSON.stringify(args) ===
|
|
131
|
+
JSON.stringify([
|
|
132
|
+
"-y",
|
|
133
|
+
PRODUCT_IDENTITY.registrationPackageSpecifier,
|
|
134
|
+
"mcp",
|
|
135
|
+
]) ||
|
|
136
|
+
JSON.stringify(args) ===
|
|
137
|
+
JSON.stringify(["-y", PRODUCT_IDENTITY.packageSpecifier, "mcp"]) ||
|
|
138
|
+
JSON.stringify(args) ===
|
|
139
|
+
JSON.stringify(["-y", PRODUCT_IDENTITY.packageName, "mcp"]))));
|
|
132
140
|
};
|
|
133
141
|
const removeManagedPath = async (path, name, fileSystem) => {
|
|
134
142
|
try {
|
|
@@ -144,6 +152,7 @@ const removeManagedPath = async (path, name, fileSystem) => {
|
|
|
144
152
|
: item(name, "failed", "This item could not be removed. Check file permissions, then rerun uninstall.");
|
|
145
153
|
}
|
|
146
154
|
};
|
|
155
|
+
const removeManagedSkills = async (home, fileSystem) => removeManagedPath(join(home, ".agents/skills", PRODUCT_IDENTITY.skillName), "skill", fileSystem);
|
|
147
156
|
const item = (name, status, detail) => ({ name, status, detail });
|
|
148
157
|
const objectSchema = z.record(z.string(), z.unknown());
|
|
149
158
|
const optionalObject = (value) => value === undefined ? {} : objectSchema.parse(value);
|
|
@@ -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,
|