rea-agents 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -32
- package/bridge/ghidra/ReaGhidraBridge.java +96 -11
- 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 +1 -1
- 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/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/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 +147 -259
- package/dist/application/SetupClientConfiguration.js +220 -0
- package/dist/application/SetupClients.js +24 -2
- package/dist/application/SetupPlan.js +123 -12
- package/dist/application/SetupSkill.js +26 -12
- package/dist/application/SupportedClients.js +1 -0
- package/dist/application/Uninstall.js +6 -3
- 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 +108 -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 +289 -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/managedToolContracts.js +1 -1
- package/dist/contracts/managedWorkflowToolContracts.js +3 -3
- package/dist/contracts/providerSelection.js +2 -0
- package/dist/contracts/toolContracts.js +2 -2
- package/dist/contracts/toolEffects.js +14 -0
- package/dist/contracts/toolOutputSchemaGroups.js +232 -0
- package/dist/contracts/toolOutputSchemaPrimitives.js +327 -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/artifactComparison.js +34 -15
- package/dist/domain/binaryTarget.js +87 -37
- 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/reconstructionCoverage.js +387 -0
- package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
- package/dist/domain/reconstructionVerificationSchemas.js +8 -0
- package/dist/domain/runtimeCharacterization.js +85 -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/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 +3 -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 +119 -54
- 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 +31 -46
- package/dist/server/registerEnhancedTools.js +34 -42
- package/dist/server/registerEvidenceResources.js +54 -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/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 +2 -1
- 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 +5 -0
- package/package.json +10 -11
- package/skills/{rea-analysis → reverse-engineer-anything}/SKILL.md +20 -7
- package/scripts/prepare-node-pty.mjs +0 -35
- package/scripts/rebuild-native.mjs +0 -22
|
@@ -1,58 +1,47 @@
|
|
|
1
|
-
import { access
|
|
2
|
-
import { constants as fsConstants } from "node:fs";
|
|
1
|
+
import { access } from "node:fs/promises";
|
|
3
2
|
import { homedir } from "node:os";
|
|
4
|
-
import {
|
|
5
|
-
import { z } from "zod";
|
|
6
|
-
import writeFileAtomic from "write-file-atomic";
|
|
7
|
-
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
|
|
3
|
+
import { resolve } from "node:path";
|
|
8
4
|
import { PRODUCT_IDENTITY } from "../identity.js";
|
|
9
5
|
import { supportsNodeVersion } from "../domain/runtimeVersion.js";
|
|
10
|
-
import { resolveClientConfigTransactionPath } from "./ClientConfigPath.js";
|
|
11
6
|
import { runDoctor, systemDoctorHost, } from "./Doctor.js";
|
|
12
7
|
import { installLinuxHopper, readLinuxDistribution, } from "./LinuxHopper.js";
|
|
13
8
|
import { installMacHopper } from "./MacHopper.js";
|
|
14
9
|
import { configureDetectedClients } from "./SetupClients.js";
|
|
15
10
|
import { supportedClients } from "./SupportedClients.js";
|
|
16
11
|
import { canonicalSkillNeedsInstall, installCanonicalSkill, } from "./SetupSkill.js";
|
|
17
|
-
import {
|
|
12
|
+
import { discoverSetupActions } from "./SetupPlan.js";
|
|
13
|
+
import { clientConfigurationAligned, configureJsonClient, configureTomlClient, inspectClientConfiguration, } from "./SetupClientConfiguration.js";
|
|
14
|
+
export { configureJsonClient, configureTomlClient };
|
|
18
15
|
import { setupInstallFailure, } from "./SetupInstallFailure.js";
|
|
19
|
-
export { canonicalSkillNeedsInstall, installCanonicalSkill
|
|
16
|
+
export { canonicalSkillNeedsInstall, installCanonicalSkill };
|
|
20
17
|
const registrationCommand = () => process.env.npm_command === "exec"
|
|
21
|
-
? ["npx", "-y", PRODUCT_IDENTITY.
|
|
18
|
+
? ["npx", "-y", PRODUCT_IDENTITY.packageSpecifier, "mcp"]
|
|
22
19
|
: [resolve(process.argv[1] ?? PRODUCT_IDENTITY.cliBinary), "mcp"];
|
|
23
|
-
/**
|
|
24
|
-
* Install prerequisites and configure detected clients idempotently.
|
|
25
|
-
* Discovery always precedes mutation. Interactive confirmation or explicit
|
|
26
|
-
* unattended options authorize only the actions represented in the result.
|
|
27
|
-
*/
|
|
20
|
+
/** Discover, approve, and apply setup actions idempotently. */
|
|
28
21
|
export const runSetup = async (options, host = systemSetupHost(), confirm) => {
|
|
29
22
|
const appliedActions = [];
|
|
30
23
|
let plannedActions = [];
|
|
31
24
|
const clients = {};
|
|
32
|
-
const fail =
|
|
33
|
-
status: "needs_human",
|
|
34
|
-
plannedActions,
|
|
35
|
-
appliedActions,
|
|
36
|
-
clients,
|
|
37
|
-
doctor: await host.doctor(),
|
|
38
|
-
remediation,
|
|
39
|
-
});
|
|
25
|
+
const fail = (remediation) => setupFailure(remediation, [host, plannedActions, appliedActions, clients]);
|
|
40
26
|
const unsupported = await hostRemediation(host, options.installHopper);
|
|
41
27
|
if (unsupported !== undefined)
|
|
42
28
|
return fail(unsupported);
|
|
43
29
|
let hopperPath = await host.hopperPath();
|
|
44
30
|
let providerEnvironment = await initialProviderEnvironment(host, hopperPath);
|
|
45
|
-
const discovery = await discoverSetupActions(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
31
|
+
const discovery = await discoverSetupActions({
|
|
32
|
+
host,
|
|
33
|
+
providerEnvironment,
|
|
34
|
+
command: registrationCommand(),
|
|
35
|
+
forceHopperInstall: options.installHopper,
|
|
36
|
+
proposeHopper: options.proposeHopper ?? true,
|
|
37
|
+
selectedClientIds: options.clientIds,
|
|
38
|
+
installSkillSelection: options.installSkill,
|
|
39
|
+
});
|
|
40
|
+
if (discovery.blocker !== undefined)
|
|
41
|
+
return fail(discovery.blocker);
|
|
42
|
+
const selection = await resolveSetupSelection(options, discovery, confirm);
|
|
43
|
+
plannedActions = selection.plannedActions;
|
|
44
|
+
if (!selection.approved)
|
|
56
45
|
return {
|
|
57
46
|
status: confirm === undefined ? "needs_confirmation" : "planned",
|
|
58
47
|
plannedActions,
|
|
@@ -61,25 +50,21 @@ export const runSetup = async (options, host = systemSetupHost(), confirm) => {
|
|
|
61
50
|
doctor: await host.doctor(),
|
|
62
51
|
remediation: "Review the setup plan, then rerun interactively or with --yes.",
|
|
63
52
|
};
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
HOPPER_LAUNCHER_PATH: installed.launcherPath,
|
|
80
|
-
};
|
|
81
|
-
appliedActions.push("installed_hopper");
|
|
82
|
-
detectedClients = await filterClientsNeedingConfigure(host, detectedClients, providerEnvironment, registrationCommand());
|
|
53
|
+
let detectedClients = selection.detectedClients;
|
|
54
|
+
if (selection.installHopper &&
|
|
55
|
+
(selection.interactiveApproval || options.installHopper)) {
|
|
56
|
+
const install = await installHopperAction({
|
|
57
|
+
host,
|
|
58
|
+
options,
|
|
59
|
+
plannedActions,
|
|
60
|
+
appliedActions,
|
|
61
|
+
clients,
|
|
62
|
+
detectedClients,
|
|
63
|
+
providerEnvironment,
|
|
64
|
+
});
|
|
65
|
+
if ("failure" in install)
|
|
66
|
+
return install.failure;
|
|
67
|
+
({ hopperPath, providerEnvironment, detectedClients } = install);
|
|
83
68
|
}
|
|
84
69
|
const clientFailure = await configureDetectedClients({
|
|
85
70
|
host,
|
|
@@ -88,16 +73,15 @@ export const runSetup = async (options, host = systemSetupHost(), confirm) => {
|
|
|
88
73
|
command: registrationCommand(),
|
|
89
74
|
clients,
|
|
90
75
|
appliedActions,
|
|
76
|
+
...(options.onProgress === undefined
|
|
77
|
+
? {}
|
|
78
|
+
: { onProgress: options.onProgress }),
|
|
91
79
|
});
|
|
92
80
|
if (clientFailure !== undefined)
|
|
93
81
|
return fail(clientFailure);
|
|
94
|
-
if (installSkill
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return fail("REA analysis skill could not be installed or verified. Check permissions for `~/.agents/skills`, then rerun setup.");
|
|
98
|
-
if (skill === "installed")
|
|
99
|
-
appliedActions.push("installed_skill");
|
|
100
|
-
}
|
|
82
|
+
if (selection.installSkill &&
|
|
83
|
+
!(await installSkillAction(host, options, appliedActions)))
|
|
84
|
+
return fail("REA analysis skill could not be installed or verified. Check permissions for `~/.agents/skills`, then rerun setup.");
|
|
101
85
|
const doctor = await host.doctor();
|
|
102
86
|
const remediation = finalSetupRemediation(host.platform, appliedActions.includes("installed_hopper"), doctor.healthy, hopperPath);
|
|
103
87
|
return {
|
|
@@ -109,30 +93,114 @@ export const runSetup = async (options, host = systemSetupHost(), confirm) => {
|
|
|
109
93
|
...(remediation === undefined ? {} : { remediation }),
|
|
110
94
|
};
|
|
111
95
|
};
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
96
|
+
const resolveSetupSelection = async (options, discovery, confirm) => {
|
|
97
|
+
let { installHopper, installSkill, detectedClients, plannedActions } = discovery;
|
|
98
|
+
let approved = options.approved || plannedActions.length === 0;
|
|
99
|
+
let interactiveApproval = false;
|
|
100
|
+
if (!approved && confirm !== undefined && !options.structured) {
|
|
101
|
+
const decision = await confirm(plannedActions);
|
|
102
|
+
if (typeof decision === "boolean") {
|
|
103
|
+
interactiveApproval = decision;
|
|
104
|
+
approved = decision;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
const selected = new Set(decision.selectedActionIds);
|
|
108
|
+
plannedActions = plannedActions.filter(({ id }) => selected.has(id));
|
|
109
|
+
installHopper = plannedActions.some(({ kind }) => kind === "install_hopper");
|
|
110
|
+
installSkill = plannedActions.some(({ kind }) => kind === "install_skill");
|
|
111
|
+
detectedClients = detectedClients.filter((client) => selected.has(`configure_client:${client.name}`));
|
|
112
|
+
interactiveApproval = decision.approved;
|
|
113
|
+
approved = decision.approved || plannedActions.length === 0;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
129
116
|
return {
|
|
117
|
+
approved,
|
|
118
|
+
interactiveApproval,
|
|
130
119
|
installHopper,
|
|
131
120
|
installSkill,
|
|
132
|
-
detectedClients
|
|
121
|
+
detectedClients,
|
|
133
122
|
plannedActions,
|
|
134
123
|
};
|
|
135
124
|
};
|
|
125
|
+
const installHopperAction = async (input) => {
|
|
126
|
+
const label = "Hopper deep-analysis provider";
|
|
127
|
+
emitProgress(input.options, {
|
|
128
|
+
actionId: "install_hopper",
|
|
129
|
+
label,
|
|
130
|
+
state: "started",
|
|
131
|
+
});
|
|
132
|
+
const installed = await input.host.installHopper(input.options.installHopper);
|
|
133
|
+
if (installed.status === "failed") {
|
|
134
|
+
emitProgress(input.options, {
|
|
135
|
+
actionId: "install_hopper",
|
|
136
|
+
label,
|
|
137
|
+
state: "failed",
|
|
138
|
+
detail: installed.remediation,
|
|
139
|
+
});
|
|
140
|
+
return {
|
|
141
|
+
failure: {
|
|
142
|
+
status: "needs_human",
|
|
143
|
+
plannedActions: input.plannedActions,
|
|
144
|
+
appliedActions: input.appliedActions,
|
|
145
|
+
clients: input.clients,
|
|
146
|
+
doctor: await input.host.doctor(),
|
|
147
|
+
code: installed.code,
|
|
148
|
+
remediation: installed.remediation,
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
input.appliedActions.push("installed_hopper");
|
|
153
|
+
emitProgress(input.options, {
|
|
154
|
+
actionId: "install_hopper",
|
|
155
|
+
label,
|
|
156
|
+
state: "completed",
|
|
157
|
+
detail: installed.launcherPath,
|
|
158
|
+
});
|
|
159
|
+
const providerEnvironment = {
|
|
160
|
+
...input.providerEnvironment,
|
|
161
|
+
HOPPER_LAUNCHER_PATH: installed.launcherPath,
|
|
162
|
+
};
|
|
163
|
+
return {
|
|
164
|
+
hopperPath: installed.launcherPath,
|
|
165
|
+
providerEnvironment,
|
|
166
|
+
detectedClients: await filterClientsNeedingConfigure(input.host, input.detectedClients, providerEnvironment, registrationCommand()),
|
|
167
|
+
};
|
|
168
|
+
};
|
|
169
|
+
const installSkillAction = async (host, options, appliedActions) => {
|
|
170
|
+
const label = "REA reverse-engineering skill";
|
|
171
|
+
emitProgress(options, {
|
|
172
|
+
actionId: "install_skill",
|
|
173
|
+
label,
|
|
174
|
+
state: "started",
|
|
175
|
+
});
|
|
176
|
+
const skill = await host.installSkill();
|
|
177
|
+
if (skill === "failed") {
|
|
178
|
+
emitProgress(options, {
|
|
179
|
+
actionId: "install_skill",
|
|
180
|
+
label,
|
|
181
|
+
state: "failed",
|
|
182
|
+
});
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
if (skill === "installed")
|
|
186
|
+
appliedActions.push("installed_skill");
|
|
187
|
+
emitProgress(options, {
|
|
188
|
+
actionId: "install_skill",
|
|
189
|
+
label,
|
|
190
|
+
state: skill === "installed" ? "completed" : "warning",
|
|
191
|
+
...(skill === "unchanged" ? { detail: "Already current" } : {}),
|
|
192
|
+
});
|
|
193
|
+
return true;
|
|
194
|
+
};
|
|
195
|
+
const setupFailure = async (remediation, [host, plannedActions, appliedActions, clients]) => ({
|
|
196
|
+
status: "needs_human",
|
|
197
|
+
plannedActions,
|
|
198
|
+
appliedActions,
|
|
199
|
+
clients,
|
|
200
|
+
doctor: await host.doctor(),
|
|
201
|
+
remediation,
|
|
202
|
+
});
|
|
203
|
+
const emitProgress = (options, event) => options.onProgress?.(event);
|
|
136
204
|
const filterClientsNeedingConfigure = async (host, detectedClients, providerEnvironment, command) => {
|
|
137
205
|
const needs = await Promise.all(detectedClients.map((client) => host.clientNeedsConfigure(client, providerEnvironment, command)));
|
|
138
206
|
return detectedClients.filter((_, index) => needs[index]);
|
|
@@ -202,6 +270,7 @@ export const systemSetupHost = (doctorHost = systemDoctorHost()) => {
|
|
|
202
270
|
? configureTomlClient(client, providerEnvironment, command)
|
|
203
271
|
: configureJsonClient(client, providerEnvironment, command),
|
|
204
272
|
clientNeedsConfigure: (client, providerEnvironment, command) => clientConfigurationAligned(client, providerEnvironment, command).then((aligned) => !aligned),
|
|
273
|
+
inspectClientConfiguration: inspectClientConfiguration,
|
|
205
274
|
skillNeedsInstall: () => canonicalSkillNeedsInstall(homedir()),
|
|
206
275
|
installSkill: () => installCanonicalSkill(homedir()),
|
|
207
276
|
doctor: () => runDoctor(undefined, doctorHost),
|
|
@@ -215,133 +284,6 @@ export const detectClients = async (home) => {
|
|
|
215
284
|
detected.push(candidate);
|
|
216
285
|
return detected;
|
|
217
286
|
};
|
|
218
|
-
/** Back up, atomically update, and semantically read back one JSON MCP configuration. */
|
|
219
|
-
export const configureJsonClient = async (client, environment = {}, command = [
|
|
220
|
-
"npx",
|
|
221
|
-
"-y",
|
|
222
|
-
PRODUCT_IDENTITY.packageName,
|
|
223
|
-
"mcp",
|
|
224
|
-
]) => {
|
|
225
|
-
const transactionPath = await resolveClientConfigTransactionPath(client.configPath);
|
|
226
|
-
if (transactionPath === undefined)
|
|
227
|
-
return { status: "failed", reason: "path" };
|
|
228
|
-
let document = {};
|
|
229
|
-
let original;
|
|
230
|
-
try {
|
|
231
|
-
original = await readFile(transactionPath, "utf8");
|
|
232
|
-
document = parseObject(original);
|
|
233
|
-
}
|
|
234
|
-
catch (cause) {
|
|
235
|
-
if (!isMissing(cause))
|
|
236
|
-
return { status: "failed", reason: "readback" };
|
|
237
|
-
}
|
|
238
|
-
let servers;
|
|
239
|
-
try {
|
|
240
|
-
servers = parseOptionalObject(document.mcpServers);
|
|
241
|
-
}
|
|
242
|
-
catch {
|
|
243
|
-
return { status: "failed", reason: "readback" };
|
|
244
|
-
}
|
|
245
|
-
const desired = clientConfigurationDesired(normalizeProviderEnvironment(environment), command);
|
|
246
|
-
if (JSON.stringify(servers[PRODUCT_IDENTITY.mcpServerKey]) ===
|
|
247
|
-
JSON.stringify(desired))
|
|
248
|
-
return { status: "unchanged" };
|
|
249
|
-
let backupPath;
|
|
250
|
-
if (original !== undefined) {
|
|
251
|
-
backupPath = `${client.configPath}.rea.backup`;
|
|
252
|
-
if (!(await preserveConfigBackup(transactionPath, backupPath)))
|
|
253
|
-
return { status: "failed", reason: "backup" };
|
|
254
|
-
}
|
|
255
|
-
document.mcpServers = {
|
|
256
|
-
...servers,
|
|
257
|
-
[PRODUCT_IDENTITY.mcpServerKey]: desired,
|
|
258
|
-
};
|
|
259
|
-
const encoded = `${JSON.stringify(document, null, 2)}\n`;
|
|
260
|
-
try {
|
|
261
|
-
await mkdir(dirname(client.configPath), { recursive: true });
|
|
262
|
-
await writeFileAtomic(transactionPath, encoded, {
|
|
263
|
-
encoding: "utf8",
|
|
264
|
-
mode: 0o600,
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
catch {
|
|
268
|
-
return { status: "failed", reason: "write" };
|
|
269
|
-
}
|
|
270
|
-
try {
|
|
271
|
-
const readback = parseObject(await readFile(transactionPath, "utf8"));
|
|
272
|
-
const value = parseOptionalObject(readback.mcpServers)[PRODUCT_IDENTITY.mcpServerKey];
|
|
273
|
-
if (JSON.stringify(value) !== JSON.stringify(desired)) {
|
|
274
|
-
await restoreConfig(transactionPath, original);
|
|
275
|
-
return { status: "failed", reason: "readback" };
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
catch {
|
|
279
|
-
await restoreConfig(transactionPath, original);
|
|
280
|
-
return { status: "failed", reason: "readback" };
|
|
281
|
-
}
|
|
282
|
-
return {
|
|
283
|
-
status: "configured",
|
|
284
|
-
...(backupPath === undefined ? {} : { backupPath }),
|
|
285
|
-
};
|
|
286
|
-
};
|
|
287
|
-
/** Back up, atomically update, and semantically read back Codex TOML configuration. */
|
|
288
|
-
export const configureTomlClient = async (client, environment = {}, command = [
|
|
289
|
-
"npx",
|
|
290
|
-
"-y",
|
|
291
|
-
PRODUCT_IDENTITY.packageName,
|
|
292
|
-
"mcp",
|
|
293
|
-
]) => {
|
|
294
|
-
const transactionPath = await resolveClientConfigTransactionPath(client.configPath);
|
|
295
|
-
if (transactionPath === undefined)
|
|
296
|
-
return { status: "failed", reason: "path" };
|
|
297
|
-
let document = {};
|
|
298
|
-
let original;
|
|
299
|
-
try {
|
|
300
|
-
original = await readFile(transactionPath, "utf8");
|
|
301
|
-
document = objectSchema.parse(parseToml(original));
|
|
302
|
-
}
|
|
303
|
-
catch (cause) {
|
|
304
|
-
if (!isMissing(cause))
|
|
305
|
-
return { status: "failed", reason: "readback" };
|
|
306
|
-
}
|
|
307
|
-
let servers;
|
|
308
|
-
try {
|
|
309
|
-
servers = parseOptionalObject(document.mcp_servers);
|
|
310
|
-
}
|
|
311
|
-
catch {
|
|
312
|
-
return { status: "failed", reason: "readback" };
|
|
313
|
-
}
|
|
314
|
-
const desired = clientConfigurationDesired(normalizeProviderEnvironment(environment), command);
|
|
315
|
-
if (JSON.stringify(servers[PRODUCT_IDENTITY.mcpServerKey]) ===
|
|
316
|
-
JSON.stringify(desired))
|
|
317
|
-
return { status: "unchanged" };
|
|
318
|
-
const backupPath = original === undefined ? undefined : `${client.configPath}.rea.backup`;
|
|
319
|
-
if (backupPath !== undefined &&
|
|
320
|
-
!(await preserveConfigBackup(transactionPath, backupPath)))
|
|
321
|
-
return { status: "failed", reason: "backup" };
|
|
322
|
-
document.mcp_servers = {
|
|
323
|
-
...servers,
|
|
324
|
-
[PRODUCT_IDENTITY.mcpServerKey]: desired,
|
|
325
|
-
};
|
|
326
|
-
try {
|
|
327
|
-
await mkdir(dirname(client.configPath), { recursive: true });
|
|
328
|
-
await writeFileAtomic(transactionPath, stringifyToml(document), {
|
|
329
|
-
encoding: "utf8",
|
|
330
|
-
mode: 0o600,
|
|
331
|
-
});
|
|
332
|
-
const readback = objectSchema.parse(parseToml(await readFile(transactionPath, "utf8")));
|
|
333
|
-
if (JSON.stringify(parseOptionalObject(readback.mcp_servers)[PRODUCT_IDENTITY.mcpServerKey]) !== JSON.stringify(desired))
|
|
334
|
-
throw new Error("TOML readback mismatch");
|
|
335
|
-
}
|
|
336
|
-
catch {
|
|
337
|
-
await restoreConfig(transactionPath, original);
|
|
338
|
-
return { status: "failed", reason: "readback" };
|
|
339
|
-
}
|
|
340
|
-
return {
|
|
341
|
-
status: "configured",
|
|
342
|
-
...(backupPath === undefined ? {} : { backupPath }),
|
|
343
|
-
};
|
|
344
|
-
};
|
|
345
287
|
const major = (version) => Number.parseInt(version.split(".")[0] ?? "0", 10);
|
|
346
288
|
const exists = async (path) => {
|
|
347
289
|
try {
|
|
@@ -352,60 +294,6 @@ const exists = async (path) => {
|
|
|
352
294
|
return false;
|
|
353
295
|
}
|
|
354
296
|
};
|
|
355
|
-
const preserveConfigBackup = async (source, destination) => {
|
|
356
|
-
try {
|
|
357
|
-
await copyFile(source, destination, fsConstants.COPYFILE_EXCL);
|
|
358
|
-
return true;
|
|
359
|
-
}
|
|
360
|
-
catch (cause) {
|
|
361
|
-
return cause instanceof Error && "code" in cause && cause.code === "EEXIST";
|
|
362
|
-
}
|
|
363
|
-
};
|
|
364
|
-
const objectSchema = z.record(z.string(), z.unknown());
|
|
365
|
-
const parseOptionalObject = (value) => value === undefined ? {} : objectSchema.parse(value);
|
|
366
|
-
const parseObject = (text) => objectSchema.parse(JSON.parse(text));
|
|
367
|
-
const isMissing = (cause) => cause instanceof Error && "code" in cause && cause.code === "ENOENT";
|
|
368
|
-
const restoreConfig = async (path, original) => {
|
|
369
|
-
try {
|
|
370
|
-
if (original === undefined)
|
|
371
|
-
await rm(path, { force: true });
|
|
372
|
-
else
|
|
373
|
-
await writeFile(path, original, { encoding: "utf8", mode: 0o600 });
|
|
374
|
-
}
|
|
375
|
-
catch {
|
|
376
|
-
// The backup remains available for the remediation reported by setup.
|
|
377
|
-
}
|
|
378
|
-
};
|
|
379
|
-
const clientConfigurationDesired = (providerEnvironment, command) => {
|
|
380
|
-
const environment = Object.fromEntries(Object.entries(providerEnvironment).sort(([left], [right]) => left.localeCompare(right)));
|
|
381
|
-
return {
|
|
382
|
-
command: command[0] ?? PRODUCT_IDENTITY.cliBinary,
|
|
383
|
-
args: command.slice(1),
|
|
384
|
-
...(Object.keys(environment).length === 0 ? {} : { env: environment }),
|
|
385
|
-
};
|
|
386
|
-
};
|
|
387
|
-
const clientConfigurationAligned = async (client, providerEnvironment, command) => {
|
|
388
|
-
const desired = clientConfigurationDesired(providerEnvironment, command);
|
|
389
|
-
try {
|
|
390
|
-
const original = await readFile(client.configPath, "utf8");
|
|
391
|
-
if (client.format === "toml") {
|
|
392
|
-
const document = objectSchema.parse(parseToml(original));
|
|
393
|
-
const servers = parseOptionalObject(document.mcp_servers);
|
|
394
|
-
return (JSON.stringify(servers[PRODUCT_IDENTITY.mcpServerKey]) ===
|
|
395
|
-
JSON.stringify(desired));
|
|
396
|
-
}
|
|
397
|
-
const document = parseObject(original);
|
|
398
|
-
const servers = parseOptionalObject(document.mcpServers);
|
|
399
|
-
return (JSON.stringify(servers[PRODUCT_IDENTITY.mcpServerKey]) ===
|
|
400
|
-
JSON.stringify(desired));
|
|
401
|
-
}
|
|
402
|
-
catch {
|
|
403
|
-
return false;
|
|
404
|
-
}
|
|
405
|
-
};
|
|
406
|
-
const normalizeProviderEnvironment = (environment) => typeof environment === "string"
|
|
407
|
-
? { HOPPER_LAUNCHER_PATH: environment }
|
|
408
|
-
: environment;
|
|
409
297
|
const providerRegistrationEnvironment = (inspections) => Object.fromEntries(inspections
|
|
410
298
|
.filter(({ available }) => available)
|
|
411
299
|
.flatMap(({ registrationEnvironment }) => Object.entries(registrationEnvironment))
|