rea-agents 6.3.0 → 6.4.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 +7 -4
- package/bridge/ghidra/ReaGhidraApplySeeds.java +151 -0
- package/bridge/ghidra/ReaGhidraBridge.java +597 -209
- package/bridge/ghidra/ReaGhidraNoReturnFix.java +123 -0
- package/dist/adb/AdbConfiguration.js +88 -0
- package/dist/adb/AdbDeviceOutput.js +186 -0
- package/dist/adb/AdbProvider.js +1190 -0
- package/dist/adb/AdbShellOutput.js +309 -0
- package/dist/android/AndroidTargetSnapshot.js +104 -22
- package/dist/android/JadxConfiguration.js +44 -24
- package/dist/android/JadxProvider.js +51 -19
- package/dist/apktool/ApktoolConfiguration.js +84 -0
- package/dist/apktool/ApktoolDecodeOutput.js +59 -0
- package/dist/apktool/ApktoolProvider.js +506 -0
- package/dist/application/AnalysisProvider.js +8 -2
- package/dist/application/AppBundleExecutable.js +27 -22
- package/dist/application/BinaryTargetResolver.js +22 -2
- package/dist/application/CapabilityInventory.js +11 -1
- package/dist/application/ClientConfigurationDocument.js +70 -0
- package/dist/application/ClientConfigurationFiles.js +91 -0
- package/dist/application/ClientRegistrationEnvironment.js +35 -0
- package/dist/application/ClientRegistrationStatus.js +66 -31
- package/dist/application/DirectAnalysis.js +2 -2
- package/dist/application/DirectAnalysisCleanup.js +1 -1
- package/dist/application/DirectAnalysisStatus.js +1 -1
- package/dist/application/Doctor.js +5 -3
- package/dist/application/DoctorDiagnostics.js +1 -1
- package/dist/application/EvidenceBundleCommands.js +6 -12
- package/dist/application/GeminiClientSettings.js +139 -0
- package/dist/application/HermesClientHome.js +115 -0
- package/dist/application/HopperDownload.js +39 -0
- package/dist/application/InvestigationProviders.js +6 -0
- package/dist/application/JsonFiles.js +6 -5
- package/dist/{cliJsonFile.js → application/JsonInputFile.js} +108 -35
- package/dist/application/LinuxHopper.js +4 -12
- package/dist/application/MacHopper.js +172 -149
- package/dist/application/MipsElfAbiFlags.js +140 -0
- package/dist/application/ProviderOperationExecution.js +31 -0
- package/dist/application/ReconstructionObligationCandidates.js +9 -3
- package/dist/application/ReferenceSourceImport.js +76 -29
- package/dist/application/ReferenceSourceImportEntries.js +18 -9
- package/dist/application/ReferenceSourceImportPolicy.js +99 -23
- package/dist/application/ReferenceSourceImportTypes.js +30 -22
- package/dist/application/ReferenceSourceVcsAdapter.js +145 -30
- package/dist/application/RegularFileRead.js +93 -7
- package/dist/application/Setup.js +54 -6
- package/dist/application/SetupClientConfiguration.js +116 -16
- package/dist/application/SetupHost.js +102 -24
- package/dist/application/SetupPlan.js +5 -8
- package/dist/application/SetupSkill.js +58 -39
- package/dist/application/SupportedClients.js +290 -65
- package/dist/application/Uninstall.js +158 -10
- package/dist/application/UpdateMaintenance.js +17 -21
- package/dist/application/Utf8JsonInput.js +7 -0
- package/dist/application/WebScriptExportService.js +131 -65
- package/dist/application/WebSourceLocationService.js +3 -0
- package/dist/application/adb/AdbDeviceAnalysisPort.js +1 -0
- package/dist/application/adb/AdbDeviceAnalysisService.js +13 -0
- package/dist/application/analysisView/AnalysisViewService.js +40 -2
- package/dist/application/apktool/ApktoolResourceAnalysisPort.js +1 -0
- package/dist/application/apktool/ApktoolResourceAnalysisService.js +13 -0
- package/dist/application/binary/AnalysisClientCleanup.js +0 -24
- package/dist/application/binary/BinarySession.js +2 -1
- package/dist/application/binaryDiagnostics/BinaryLayoutService.js +2 -1
- package/dist/application/binaryDiagnostics/PeResourcesPort.js +1 -0
- package/dist/application/binaryDiagnostics/PeResourcesService.js +111 -0
- package/dist/application/binaryDiagnostics/RecordedCrashService.js +2 -1
- package/dist/application/evm/EvmInterfaceService.js +3 -0
- package/dist/application/firmware/FirmwareAnalysisService.js +3 -0
- package/dist/application/investigation/InspectEvidenceBundle.js +18 -0
- package/dist/application/javascript/ElectronBoundaryGraphContext.js +3 -2
- package/dist/application/javascript/ElectronBoundaryGraphIpc.js +2 -2
- package/dist/application/javascript/ElectronBoundaryGraphNative.js +19 -6
- package/dist/application/javascript/ElectronBoundaryGraphWindows.js +3 -3
- package/dist/application/javascript/JavaScriptApplicationService.js +22 -11
- package/dist/application/javascript/JavaScriptApplicationWorkflowEvidence.js +5 -6
- package/dist/application/javascript/JavaScriptArtifactAnalysis.js +171 -30
- package/dist/application/javascript/JavaScriptArtifactGraphAccumulator.js +14 -16
- package/dist/application/javascript/JavaScriptArtifactGraphBuilder.js +67 -19
- package/dist/application/javascript/JavaScriptArtifactGraphBundlers.js +4 -3
- package/dist/application/javascript/JavaScriptArtifactGraphContext.js +11 -5
- package/dist/application/javascript/JavaScriptArtifactGraphFindings.js +19 -16
- package/dist/application/javascript/JavaScriptArtifactGraphStructure.js +92 -10
- package/dist/application/javascript/JavaScriptArtifactPathResolution.js +258 -235
- package/dist/application/javascript/JavaScriptArtifactReconstruction.js +115 -26
- package/dist/application/javascript/JavaScriptArtifactReconstructionInput.js +4 -1
- package/dist/application/javascript/JavaScriptModuleRelationships.js +6 -4
- package/dist/application/javascript/JavaScriptRecoveryService.js +3 -0
- package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +9 -3
- package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +199 -61
- package/dist/application/javascript/JavaScriptSemanticGraphConstruction.js +12 -19
- package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +4 -1
- package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +5 -3
- package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +5 -3
- package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +19 -8
- package/dist/application/jeb/JebAnalysisPort.js +1 -0
- package/dist/application/jeb/JebAnalysisService.js +13 -0
- package/dist/application/managed/ManagedApplicationGraphService.js +1 -1
- package/dist/application/native/NativeUiActionTrace.js +16 -8
- package/dist/application/native/NativeValueTrace.js +23 -6
- package/dist/application/process/ProcessCli.js +25 -20
- package/dist/artifacts/ArtifactPaths.js +129 -8
- package/dist/artifacts/ArtifactProvider.js +20 -15
- package/dist/artifacts/ArtifactReader.js +23 -0
- package/dist/artifacts/ArtifactResourceScope.js +100 -0
- package/dist/artifacts/AsarArtifactReader.js +176 -102
- package/dist/artifacts/AsarHeader.js +24 -0
- package/dist/artifacts/DirectoryArtifactReader.js +168 -65
- package/dist/artifacts/MachOSliceArtifactReader.js +116 -39
- package/dist/artifacts/NativeDmgArtifactReader.js +29 -22
- package/dist/artifacts/SafeOutputTree.js +245 -70
- package/dist/artifacts/SafeOutputTreeCleanup.js +45 -0
- package/dist/artifacts/SafeOutputTreeCreationFailure.js +20 -0
- package/dist/artifacts/SafeOutputTreeIdentity.js +42 -0
- package/dist/artifacts/SafeOutputTreeReadback.js +33 -0
- package/dist/artifacts/ZipArtifactReader.js +77 -27
- package/dist/artifacts/apple/InterfaceBuilderAnalysis.js +58 -18
- package/dist/artifacts/apple/InterfaceBuilderDecodeBudget.js +62 -24
- package/dist/artifacts/apple/KeyedArchiveReader.js +32 -13
- package/dist/artifacts/extraction/ArtifactExtraction.js +110 -86
- package/dist/artifacts/inventory/ArtifactGraphConstruction.js +110 -43
- package/dist/artifacts/inventory/ArtifactInventory.js +5 -4
- package/dist/artifacts/inventory/classify.js +75 -32
- package/dist/artifacts/inventory/hashStableRootArtifact.js +48 -15
- package/dist/artifacts/inventory/reader.js +13 -5
- package/dist/artifacts/inventory/scanCanonical.js +62 -25
- package/dist/artifacts/inventory/scanReader.js +38 -11
- package/dist/artifacts/javascript/JavaScriptArtifactFiles.js +15 -9
- package/dist/artifacts/javascript/JavaScriptSourceAnalysis.js +3 -0
- package/dist/browser/BrowserScenarioPartialObservation.js +8 -2
- package/dist/browser/BrowserScenarioSecrets.js +52 -37
- package/dist/browser/CdpBrowserProvider.js +5 -0
- package/dist/browser/CdpCaptureDocuments.js +40 -6
- package/dist/browser/CdpCaptureDomSvg.js +210 -0
- package/dist/browser/CdpCaptureEventBodyShapes.js +4 -8
- package/dist/browser/CdpCaptureEventHandlers.js +26 -9
- package/dist/browser/CdpCaptureEvents.js +4 -9
- package/dist/browser/CdpConnection.js +22 -5
- package/dist/browser/CdpPageCapture.js +1 -1
- package/dist/browser/CdpTargetSession.js +30 -34
- package/dist/browser/CdpWebMcpDiscovery.js +32 -10
- package/dist/browser/ElectronFileScope.js +99 -9
- package/dist/browser/PlaywrightBrowserScenarioProvider.js +60 -4
- package/dist/browser/PlaywrightElectronActiveProvider.js +11 -6
- package/dist/browser/PlaywrightScenarioArtifacts.js +5 -5
- package/dist/browser/PlaywrightScenarioBrowser.js +69 -7
- package/dist/browser/PlaywrightScenarioSession.js +127 -54
- package/dist/browser/PlaywrightScenarioStorage.js +507 -0
- package/dist/browser/PngVisualDiff.js +198 -29
- package/dist/browser/WebSourceMapFetcher.js +3 -3
- package/dist/browser/assets/LocalWebScriptArtifacts.js +3 -1
- package/dist/browser/assets/PublishWebScripts.js +75 -20
- package/dist/browser/assets/WebArtifactReads.js +23 -1
- package/dist/browser/assets/WebSourceLocationArtifacts.js +1 -0
- package/dist/browser/execution/CdpExecutionCapture.js +3 -3
- package/dist/browser/execution/CdpPreciseCoverage.js +5 -8
- package/dist/browser/history/HarCapture.js +14 -0
- package/dist/browser/history/HarCaptureProcess.js +2 -10
- package/dist/browser/history/MitmproxyCaptureAdapter.js +3 -1
- package/dist/browser/modules/WebModuleArtifacts.js +1 -0
- package/dist/cli/adbCommands.js +337 -0
- package/dist/cli/analysisViewCommands.js +39 -1
- package/dist/cli/apktoolCommands.js +53 -0
- package/dist/cli/artifactCommands.js +8 -11
- package/dist/cli/binaryDiagnosticsCommands.js +19 -1
- package/dist/cli/browserAdvancedCommands.js +65 -36
- package/dist/cli/coreBinaryCommands.js +0 -5
- package/dist/cli/coreNativeCommands.js +1 -14
- package/dist/cli/electronCommands.js +6 -1
- package/dist/cli/evmCommands.js +13 -4
- package/dist/cli/firmwareCommands.js +7 -2
- package/dist/cli/javascriptApplicationAnalysis.js +17 -1
- package/dist/cli/javascriptRecoveryCommands.js +22 -15
- package/dist/cli/jebCommands.js +99 -0
- package/dist/cli/jsonOutput.js +11 -4
- package/dist/cli/referenceSourceImportStatus.js +7 -0
- package/dist/cli/setupCommands.js +15 -3
- package/dist/cli/utilityCommands.js +66 -18
- package/dist/cli/webScriptCommands.js +20 -1
- package/dist/cli/webSourceLocationCommands.js +21 -9
- package/dist/cli.js +6 -0
- package/dist/cliBrowserScenarioCommands.js +2 -1
- package/dist/cliCommandNames.js +32 -0
- package/dist/cliJsonInput.js +2 -2
- package/dist/cliObservationOptions.js +3 -0
- package/dist/composition/adb.js +3 -0
- package/dist/composition/apktool.js +3 -0
- package/dist/composition/binaryDiagnostics.js +4 -0
- package/dist/composition/directAnalysis.js +12 -4
- package/dist/composition/javascriptAnalysisWorkerProcess.js +48 -0
- package/dist/composition/jeb.js +6 -0
- package/dist/config/environment.js +10 -0
- package/dist/config/ghidraLanguageOverride.js +9 -0
- package/dist/config/mcpInputSchemaProfile.js +27 -0
- package/dist/config/parseConfig.js +28 -1
- package/dist/contracts/adb/adbToolContracts.js +353 -0
- package/dist/contracts/advertisedInputExamples.js +48 -0
- package/dist/contracts/analysisDetail.js +10 -0
- package/dist/contracts/analysisViewToolContracts.js +17 -2
- package/dist/contracts/apktool/apktoolToolContracts.js +33 -0
- package/dist/contracts/artifactToolContracts.js +8 -5
- package/dist/contracts/browserToolContracts.js +1 -1
- package/dist/contracts/compactInputSchema.js +256 -0
- package/dist/contracts/functionWorkflowToolContracts.js +1 -1
- package/dist/contracts/inputSchemaPresentation.js +10 -10
- package/dist/contracts/javascript/electronToolContracts.js +15 -3
- package/dist/contracts/javascript/javascriptRecoveryToolContracts.js +1 -1
- package/dist/contracts/jeb/jebToolContracts.js +64 -0
- package/dist/contracts/native/binaryDiagnosticsToolContracts.js +25 -3
- package/dist/contracts/officialToolContracts.js +5 -5
- package/dist/contracts/sessionToolContracts.js +2 -2
- package/dist/contracts/sessionToolSchemas.js +6 -2
- package/dist/contracts/toolContractExamples.js +6 -0
- package/dist/contracts/toolContractTypes.js +3 -0
- package/dist/contracts/toolContracts.js +6 -0
- package/dist/contracts/toolEffects.js +167 -0
- package/dist/contracts/toolOutputSchemaGroups.js +5 -3
- package/dist/contracts/toolSchemaMetadata.js +82 -7
- package/dist/domain/adb/adbDeviceAnalysis.js +583 -0
- package/dist/domain/analysisErrorCleanup.js +29 -0
- package/dist/domain/analysisErrorPresentation.js +18 -6
- package/dist/domain/analysisErrorProjection.js +4 -1
- package/dist/domain/analysisSnapshot.js +2 -1
- package/dist/domain/analysisView/analysisView.js +52 -2
- package/dist/domain/analysisView/binaryLayoutView.js +2 -0
- package/dist/domain/analysisView/javascriptApplicationView.js +2 -0
- package/dist/domain/analysisView/nativeFunctionView.js +155 -0
- package/dist/domain/android/androidApplication.js +25 -20
- package/dist/domain/apktool/apktoolResourceAnalysis.js +77 -0
- package/dist/domain/apple/appleApplication.js +40 -23
- package/dist/domain/apple/appleBundleAnatomy.js +95 -28
- package/dist/domain/apple/dyldPaths.js +9 -1
- package/dist/domain/apple/dylibResolution.js +2 -2
- package/dist/domain/apple/interfaceBuilderGraph.js +22 -19
- package/dist/domain/apple/interfaceBuilderKeyedArchive.js +10 -1
- package/dist/domain/artifactComparison.js +35 -7
- package/dist/domain/artifactGraph.js +5 -3
- package/dist/domain/artifactIdentity.js +30 -2
- package/dist/domain/artifactInspection.js +3 -43
- package/dist/domain/artifactIntegrityPolicy.js +10 -0
- package/dist/domain/artifactInventoryEvidence.js +11 -12
- package/dist/domain/artifactPathSyntax.js +1 -1
- package/dist/domain/binaryTarget.js +16 -0
- package/dist/domain/binaryTargetTypes.js +8 -1
- package/dist/domain/browserObservationSchemas.js +8 -4
- package/dist/domain/canonicalJsonDigestSteps.js +34 -12
- package/dist/domain/compactStringIdentity.js +9 -0
- package/dist/domain/evidence.js +2 -1
- package/dist/domain/evidenceRecordSummary.js +144 -0
- package/dist/domain/inputIssueProjection.js +16 -1
- package/dist/domain/javascript/electronStaticAnalysisBrowser.js +12 -13
- package/dist/domain/javascript/electronStaticAnalysisIpc.js +11 -20
- package/dist/domain/javascript/electronStaticAnalysisNative.js +70 -40
- package/dist/domain/javascript/electronStaticAnalysisValues.js +16 -0
- package/dist/domain/javascript/javascriptAnalysisResourceControls.js +45 -0
- package/dist/domain/javascript/javascriptApplicationAnalysis.js +4 -1
- package/dist/domain/javascript/javascriptApplicationChangeGraph.js +6 -6
- package/dist/domain/javascript/javascriptApplicationGraph.js +79 -18
- package/dist/domain/javascript/javascriptApplicationProjectionResources.js +35 -0
- package/dist/domain/javascript/javascriptApplicationVersionItems.js +28 -12
- package/dist/domain/javascript/javascriptApplicationVersionKeys.js +9 -1
- package/dist/domain/javascript/javascriptAstFingerprint.js +58 -31
- package/dist/domain/javascript/javascriptAstValues.js +32 -0
- package/dist/domain/javascript/javascriptElectronMemberWrites.js +50 -0
- package/dist/domain/javascript/javascriptModuleSemanticIr.js +15 -0
- package/dist/domain/javascript/javascriptNativeHandoff.js +6 -1
- package/dist/domain/javascript/javascriptRpcEndpoints.js +253 -0
- package/dist/domain/javascript/javascriptRuntimeLoadState.js +1 -3
- package/dist/domain/javascript/javascriptRuntimeReconciliationGraph.js +7 -2
- package/dist/domain/javascript/javascriptRuntimeStaticCandidates.js +8 -11
- package/dist/domain/javascript/javascriptSemanticAnalysis.js +190 -33
- package/dist/domain/javascript/javascriptSemanticCallableResults.js +42 -0
- package/dist/domain/javascript/javascriptSemanticCalls.js +8 -1
- package/dist/domain/javascript/javascriptSemanticDerivedAnalysis.js +15 -4
- package/dist/domain/javascript/javascriptSemanticFileProjection.js +1 -0
- package/dist/domain/javascript/javascriptSemanticFingerprints.js +42 -41
- package/dist/domain/javascript/javascriptSemanticGraph.js +69 -23
- package/dist/domain/javascript/javascriptSemanticGraphSchemas.js +2 -10
- package/dist/domain/javascript/javascriptSemanticIterationSources.js +40 -7
- package/dist/domain/javascript/javascriptSemanticMemberMutations.js +341 -87
- package/dist/domain/javascript/javascriptSemanticMutationValues.js +78 -35
- package/dist/domain/javascript/javascriptSemanticObjectReferences.js +381 -0
- package/dist/domain/javascript/javascriptSemanticObjects.js +7 -1
- package/dist/domain/javascript/javascriptSemanticProjection.js +52 -14
- package/dist/domain/javascript/javascriptSemanticPropertyPaths.js +77 -0
- package/dist/domain/javascript/javascriptSemanticQuery.js +27 -29
- package/dist/domain/javascript/javascriptSemanticQueryIdentity.js +1 -3
- package/dist/domain/javascript/javascriptSemanticReturnedReferences.js +219 -0
- package/dist/domain/javascript/javascriptSemanticReturns.js +13 -23
- package/dist/domain/javascript/javascriptSemanticState.js +22 -2
- package/dist/domain/javascript/javascriptSemanticTraversal.js +19 -1
- package/dist/domain/javascript/javascriptSemanticValues.js +47 -19
- package/dist/domain/javascript/javascriptSourceAnalysis.js +1 -0
- package/dist/domain/javascript/javascriptStaticAnalysis.js +29 -17
- package/dist/domain/javascript/javascriptStaticAnalysisBundler.js +8 -6
- package/dist/domain/javascript/javascriptStaticAnalysisCalls.js +49 -5
- package/dist/domain/javascript/javascriptStaticAnalysisFindings.js +8 -4
- package/dist/domain/javascript/javascriptStaticAnalysisState.js +1 -0
- package/dist/domain/jeb/jebAnalysis.js +114 -0
- package/dist/domain/jsonShape.js +63 -52
- package/dist/domain/jsonValue.js +3 -0
- package/dist/domain/managed/managedApplicationGraph.js +37 -0
- package/dist/domain/managed/managedApplicationGraphCoverage.js +8 -2
- package/dist/domain/managed/managedApplicationGraphNodes.js +32 -22
- package/dist/domain/managed/managedArtifact.js +1 -0
- package/dist/domain/managed/managedInspectionEvidence.js +13 -0
- package/dist/domain/native/nativeAotPe.js +1408 -0
- package/dist/domain/native/nativeInstruction.js +21 -0
- package/dist/domain/native/nativeMetadataRecovery.js +79 -6
- package/dist/domain/native/peResources.js +94 -0
- package/dist/domain/nativeConvention.js +33 -0
- package/dist/domain/process/processCapture.js +91 -1
- package/dist/domain/process/processCaptureExample.js +24 -0
- package/dist/domain/process/processCaptureValidation.js +79 -0
- package/dist/domain/process/processScenario.js +59 -7
- package/dist/domain/propertyListKeys.js +3 -1
- package/dist/domain/referenceSourceGraph.js +25 -16
- package/dist/domain/referenceSourceImportParsing.js +6 -3
- package/dist/domain/referenceSourcePathIdentity.js +22 -0
- package/dist/domain/referenceSourceRequireBindings.js +137 -0
- package/dist/domain/webBundleAnalyzerInspection.js +14 -2
- package/dist/domain/webCaptureDiff.js +102 -4
- package/dist/domain/webScriptExportError.js +10 -4
- package/dist/domain/webScriptExportPlan.js +7 -13
- package/dist/domain/zipPackageFormat.js +4 -1
- package/dist/domain/zodCollectionSteps.js +24 -0
- package/dist/dotnet/ManagedArtifactInspector.js +55 -43
- package/dist/dotnet/ManagedDecodeBudget.js +80 -0
- package/dist/dotnet/ManagedMemberInspector.js +13 -6
- package/dist/dotnet/ManagedMemberInspectorCore.js +2 -2
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +4 -2
- package/dist/dotnet/ManagedMemberRows.js +9 -4
- package/dist/dotnet/ManagedMetadataHeaps.js +15 -5
- package/dist/dotnet/ManagedMetadataInventoryRows.js +20 -11
- package/dist/dotnet/ManagedMetadataLayout.js +10 -4
- package/dist/dotnet/ManagedMethodBodyReader.js +8 -3
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +3 -2
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +49 -34
- package/dist/dotnet/ManagedPeReader.js +41 -25
- package/dist/dotnet/ManagedReaderFailure.js +2 -1
- package/dist/dotnet/ManagedStaticProvider.js +55 -24
- package/dist/evaluation/AgentEvaluationReport.js +9 -5
- package/dist/evaluation/CodexAgentEval.js +43 -13
- package/dist/evm/EvmoleFailures.js +0 -2
- package/dist/evm/EvmoleInterfaceProvider.js +67 -2
- package/dist/filesystem/OwnedDirectoryHandle.js +29 -0
- package/dist/filesystem/OwnedFileHandle.js +36 -0
- package/dist/filesystem/RegularFile.js +33 -1
- package/dist/filesystem/StableFileHash.js +46 -0
- package/dist/filesystem/readFileHandleChunks.js +26 -0
- package/dist/firmware/FirmwareCommand.js +25 -3
- package/dist/firmware/FirmwareFiles.js +23 -8
- package/dist/firmware/FirmwareProvider.js +156 -32
- package/dist/firmware/FirmwarePublication.js +24 -3
- package/dist/firmware/FirmwareRelease.js +1 -0
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraAnalysisProfile.js +55 -4
- package/dist/ghidra/GhidraAnalysisSeeds.js +211 -0
- package/dist/ghidra/GhidraClient.js +76 -4
- package/dist/ghidra/GhidraDiagnostics.js +11 -8
- package/dist/ghidra/GhidraFunctionValues.js +26 -2
- package/dist/ghidra/GhidraInstallation.js +1 -1
- package/dist/ghidra/GhidraInventoryValues.js +23 -1
- package/dist/ghidra/GhidraLanguageCatalog.js +99 -0
- package/dist/ghidra/GhidraLauncher.js +80 -39
- package/dist/ghidra/GhidraLoadImageAttest.js +49 -2
- package/dist/ghidra/GhidraMipsProfile.js +79 -0
- package/dist/ghidra/GhidraProvider.js +57 -9
- package/dist/ghidra/GhidraProviderCapabilities.js +18 -8
- package/dist/ghidra/GhidraProviderClient.js +282 -21
- package/dist/ghidra/GhidraSessionValues.js +9 -2
- package/dist/hopper/HopperAnalysisProfile.js +2 -0
- package/dist/hopper/HopperClient.js +15 -6
- package/dist/hopper/HopperMachOImage.js +2 -0
- package/dist/hopper/HopperProvider.js +13 -2
- package/dist/ida/IdaOperationRunner.js +8 -2
- package/dist/ida/IdaProvider.js +7 -0
- package/dist/ida/IdaSessionClient.js +3 -1
- package/dist/ida/IdaWorkspace.js +4 -2
- package/dist/javascript/analysis/JavaScriptAnalysisTransfer.js +326 -0
- package/dist/javascript/analysis/JavaScriptAnalysisWorker.js +520 -0
- package/dist/javascript/analysis/JavaScriptAnalysisWorkerProtocol.js +63 -0
- package/dist/javascript/analysis/JavaScriptAnalysisWorkerSchemas.js +521 -0
- package/dist/javascript/analysis/JavaScriptAnalysisWorkerServer.js +116 -0
- package/dist/javascript/recovery/RecoveryFiles.js +18 -7
- package/dist/javascript/recovery/WakaruCommand.js +22 -9
- package/dist/javascript/recovery/WakaruExecution.js +11 -7
- package/dist/javascript/recovery/WakaruProvider.js +139 -16
- package/dist/javascript/recovery/WakaruPublication.js +14 -4
- package/dist/javascript/recovery/WakaruRelease.js +10 -3
- package/dist/javascript/recovery/WakaruReport.js +12 -7
- package/dist/javascript/recovery/WakaruVersion.js +24 -0
- package/dist/javascript/sourceMaps/SourceMapCommand.js +16 -3
- package/dist/javascript/sourceMaps/SourceMapDecoder.js +63 -7
- package/dist/javascript/sourceMaps/SourceMapFormat.js +15 -4
- package/dist/jeb/JebMcpConnection.js +179 -0
- package/dist/jeb/JebMcpEndpoint.js +40 -0
- package/dist/jeb/JebProvider.js +299 -0
- package/dist/mcpDoctor.js +15 -6
- package/dist/native/AppleDispatchCoverage.js +25 -12
- package/dist/native/AppleDispatchMetadata.js +14 -7
- package/dist/native/AppleMachoFixups.js +71 -15
- package/dist/native/AppleMachoSelection.js +23 -3
- package/dist/native/NativeMacOSProvider.js +91 -16
- package/dist/native/NativeMachoInspection.js +11 -7
- package/dist/native/NativeUiHelperRuntime.js +6 -1
- package/dist/native/NativeUiObservation.js +4 -3
- package/dist/native/pe/PeResourceLayout.js +120 -0
- package/dist/native/pe/PeResourceParser.js +286 -0
- package/dist/native/pe/PeResourcesProvider.js +63 -0
- package/dist/process/BoundedFileBytes.js +30 -7
- package/dist/process/DarwinProcessRunTokenReader.js +8 -3
- package/dist/process/OwnedCommand.js +4 -3
- package/dist/process/ProcessOwnership.js +104 -112
- package/dist/process/ProcessOwnershipObservation.js +96 -39
- package/dist/process/ProcessOwnershipProcessTree.js +4 -4
- package/dist/process/ProcessRunTokenObservations.js +48 -0
- package/dist/process/ProviderDiagnosticRedaction.js +17 -0
- package/dist/process/ProviderProcess.js +4 -3
- package/dist/process/capture/FilesystemSnapshot.js +28 -4
- package/dist/process/capture/ProcessCaptureLifecycle.js +350 -59
- package/dist/process/capture/ProcessCaptureProgress.js +62 -0
- package/dist/process/capture/ProcessHarness.js +194 -26
- package/dist/process/capture/ProcessNormalization.js +3 -1
- package/dist/process/capture/ProcessScenarioRuntimeValidation.js +5 -2
- package/dist/process/capture/TerminalRenderer.js +24 -7
- package/dist/reference/ReferenceSourceReader.js +22 -5
- package/dist/reference/ReferenceSourceReaderEntries.js +114 -51
- package/dist/reference/ReferenceSourceReaderErrors.js +12 -0
- package/dist/reference/ReferenceSourceReaderFile.js +50 -10
- package/dist/reference/ReferenceSourceReaderValidate.js +4 -4
- package/dist/server/EvidenceMcpServer.js +36 -1
- package/dist/server/admittedToolOperation.js +9 -0
- package/dist/server/contractToolHandler.js +21 -0
- package/dist/server/createServer.js +97 -25
- package/dist/server/registerAdbTools.js +36 -0
- package/dist/server/registerAnalysisViewTool.js +4 -9
- package/dist/server/registerAndroidTools.js +3 -12
- package/dist/server/registerApktoolTools.js +14 -0
- package/dist/server/registerApplicationTools/compareExportShapes.js +4 -6
- package/dist/server/registerApplicationTools/compareSourceToBundle.js +4 -5
- package/dist/server/registerApplicationTools/compareVersions.js +3 -2
- package/dist/server/registerApplicationTools/coverage.js +3 -2
- package/dist/server/registerApplicationTools/obligationLedger.js +3 -2
- package/dist/server/registerApplicationTools/projectMobileApplicationGraph.js +3 -2
- package/dist/server/registerApplicationTools/traceFeature.js +3 -2
- package/dist/server/registerApplicationTools/traceSemantics.js +4 -5
- package/dist/server/registerArtifactComparisonTool.js +5 -2
- package/dist/server/registerBinaryDiagnosticsTools.js +16 -4
- package/dist/server/registerBrowserScenarioTool.js +10 -7
- package/dist/server/registerBrowserTools.js +12 -9
- package/dist/server/registerBundleComparisonTool.js +16 -2
- package/dist/server/registerCloseLifecycleTool.js +32 -3
- package/dist/server/registerElectronTools.js +28 -10
- package/dist/server/registerEvmTools.js +4 -9
- package/dist/server/registerFirmwareTools.js +3 -11
- package/dist/server/registerFunctionComparisonTool.js +5 -2
- package/dist/server/registerJavaScriptRecoveryTool.js +4 -9
- package/dist/server/registerJavaScriptRuntimeObservationTools.js +9 -6
- package/dist/server/registerJebTools.js +16 -0
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +4 -6
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +3 -2
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +3 -2
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +3 -2
- package/dist/server/registerPeResourcesTool.js +9 -0
- package/dist/server/registerProcessComparisonTool.js +5 -2
- package/dist/server/registerRecordedCrashTools.js +4 -9
- package/dist/server/registerSessionRecordTools.js +2 -1
- package/dist/server/registerSessionTools.js +49 -18
- package/dist/server/registerWebModuleTool.js +4 -9
- package/dist/server/registerWebNetworkCaptureTool.js +4 -9
- package/dist/server/registerWebRuntimeTools.js +6 -5
- package/dist/server/registerWebScriptTool.js +6 -3
- package/dist/server/registerWebSourceLocationTool.js +4 -9
- package/dist/server/toolResult.js +21 -2
- package/dist/windows/WindowsPrivateRuntime.js +12 -5
- package/install.sh +7 -4
- package/licenses/nativeaot-parser-MIT.txt +28 -0
- package/native/windows/build/manifest.json +2 -2
- package/native/windows/build/rea-windows-x64.node +0 -0
- package/package.json +33 -5
- package/scripts/rea.mjs +16 -1
- package/skills/reverse-engineer-anything/SKILL.md +52 -51
- package/skills/reverse-engineer-anything/references/connection-and-recovery.md +127 -0
- package/skills/reverse-engineer-anything/references/evidence-workflows.md +8 -0
- package/skills/reverse-engineer-anything/references/javascript-applications.md +92 -13
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +22 -1
|
@@ -1,17 +1,103 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { lstat, stat } from "node:fs/promises";
|
|
2
|
+
import { RegularFileAdmissionFailure, openRegularFile, sameRegularFileState, RegularFileChangedError, } from "../filesystem/RegularFile.js";
|
|
3
|
+
import { OwnedFileHandle } from "../filesystem/OwnedFileHandle.js";
|
|
4
|
+
import { readBoundedFileBytes } from "../process/BoundedFileBytes.js";
|
|
5
|
+
/** A close failed after reading; this error transfers the exact handle owner. */
|
|
6
|
+
export class RegularFileCleanupFailure extends Error {
|
|
7
|
+
path;
|
|
8
|
+
owner;
|
|
9
|
+
outcome;
|
|
10
|
+
cleanupCause;
|
|
11
|
+
constructor(path, owner, outcome, cleanupCause) {
|
|
12
|
+
super(`Regular file cleanup failed: ${path}`, {
|
|
13
|
+
cause: outcome.kind === "failed" ? outcome.cause : cleanupCause,
|
|
14
|
+
});
|
|
15
|
+
this.path = path;
|
|
16
|
+
this.owner = owner;
|
|
17
|
+
this.outcome = outcome;
|
|
18
|
+
this.cleanupCause = cleanupCause;
|
|
19
|
+
this.name = "RegularFileCleanupFailure";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Retry a failed close through its retained owner and report any remaining cleanup. */
|
|
23
|
+
export const retryRegularFileCleanup = async (failure, resources) => {
|
|
24
|
+
const released = await resources.release({
|
|
25
|
+
kind: "file-handle",
|
|
26
|
+
handle: failure.owner,
|
|
27
|
+
resource: failure.path,
|
|
28
|
+
});
|
|
29
|
+
if (released.kind === "released")
|
|
30
|
+
return { outcome: failure.outcome };
|
|
31
|
+
return {
|
|
32
|
+
outcome: failure.outcome,
|
|
33
|
+
cleanup: {
|
|
34
|
+
reason: `${failureMessage(failure.cleanupCause)}; retry: ${failureMessage(released.cause)}`,
|
|
35
|
+
resources: [failure.path],
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
const failureMessage = (cause) => cause instanceof Error ? cause.message : String(cause);
|
|
2
40
|
/** Admit one regular-file handle, retain it through the consumer, and always close it. */
|
|
3
|
-
export const withRegularFile = async (path, read,
|
|
4
|
-
const
|
|
41
|
+
export const withRegularFile = async (path, read, options = {}) => {
|
|
42
|
+
const { signal } = options;
|
|
43
|
+
let handle;
|
|
44
|
+
try {
|
|
45
|
+
handle = await openRegularFile(path, {
|
|
46
|
+
symlinks: options.symlinks ?? "follow",
|
|
47
|
+
signal,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
catch (cause) {
|
|
51
|
+
if (!(cause instanceof RegularFileAdmissionFailure))
|
|
52
|
+
throw cause;
|
|
53
|
+
throw new RegularFileCleanupFailure(path, cause.owner, { kind: "failed", cause: cause.cause }, cause.cleanupCause);
|
|
54
|
+
}
|
|
55
|
+
const owner = new OwnedFileHandle(handle);
|
|
56
|
+
let outcome;
|
|
5
57
|
try {
|
|
6
58
|
const stats = await handle.stat();
|
|
7
59
|
signal?.throwIfAborted();
|
|
8
60
|
const value = await read(handle, stats);
|
|
9
61
|
signal?.throwIfAborted();
|
|
10
|
-
|
|
62
|
+
const [opened, currentPath] = await Promise.all([
|
|
63
|
+
handle.stat(),
|
|
64
|
+
options.symlinks === "reject" ? lstat(path) : stat(path),
|
|
65
|
+
]);
|
|
66
|
+
if (!sameRegularFileState(stats, opened) ||
|
|
67
|
+
!sameRegularFileState(stats, currentPath))
|
|
68
|
+
throw new RegularFileChangedError(path);
|
|
69
|
+
outcome = { kind: "completed", value };
|
|
70
|
+
}
|
|
71
|
+
catch (cause) {
|
|
72
|
+
outcome = { kind: "failed", cause };
|
|
11
73
|
}
|
|
12
|
-
|
|
13
|
-
await
|
|
74
|
+
try {
|
|
75
|
+
await owner.close();
|
|
76
|
+
}
|
|
77
|
+
catch (cleanupCause) {
|
|
78
|
+
throw new RegularFileCleanupFailure(path, owner, outcome, cleanupCause);
|
|
14
79
|
}
|
|
80
|
+
if (outcome.kind === "failed")
|
|
81
|
+
throw outcome.cause;
|
|
82
|
+
return outcome.value;
|
|
15
83
|
};
|
|
16
84
|
/** Admit a regular file without waiting for a pipe, then read its verified handle. */
|
|
17
|
-
export const readRegularFile = (path,
|
|
85
|
+
export const readRegularFile = (path, options = {}) => withRegularFile(path, async (handle, stats) => {
|
|
86
|
+
const bytes = await readBoundedFileBytes(handle, stats.size, options.signal);
|
|
87
|
+
if (bytes === undefined || bytes.length !== stats.size)
|
|
88
|
+
throw new RegularFileChangedError(path);
|
|
89
|
+
return bytes;
|
|
90
|
+
}, options);
|
|
91
|
+
/** Read one admitted regular file as UTF-8 without waiting on a pipe. */
|
|
92
|
+
export const readRegularFileText = async (path, options = {}) => {
|
|
93
|
+
try {
|
|
94
|
+
return (await readRegularFile(path, options)).toString("utf8");
|
|
95
|
+
}
|
|
96
|
+
catch (cause) {
|
|
97
|
+
if (cause instanceof RegularFileCleanupFailure &&
|
|
98
|
+
cause.outcome.kind === "completed" &&
|
|
99
|
+
Buffer.isBuffer(cause.outcome.value))
|
|
100
|
+
throw new RegularFileCleanupFailure(cause.path, cause.owner, { kind: "completed", value: cause.outcome.value.toString("utf8") }, cause.cleanupCause);
|
|
101
|
+
throw cause;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
@@ -2,8 +2,49 @@ import { manualRegistrationRemediation, } from "./SupportedClients.js";
|
|
|
2
2
|
import { configureDetectedClients } from "./SetupClients.js";
|
|
3
3
|
import { discoverSetupState, planSetupActions } from "./SetupPlan.js";
|
|
4
4
|
import { filterClientsNeedingConfigure, hostRemediation, systemSetupHost, } from "./SetupHost.js";
|
|
5
|
+
import { AnalysisError } from "../domain/analysisErrorBase.js";
|
|
6
|
+
import { analysisErrorWithCleanupFailure } from "../domain/analysisErrorCleanup.js";
|
|
7
|
+
import { ProviderCleanupError } from "../domain/providerCleanupError.js";
|
|
5
8
|
/** Discover, approve, and apply setup actions idempotently. */
|
|
6
9
|
export const runSetup = async (options, host = systemSetupHost(), confirm) => {
|
|
10
|
+
let result;
|
|
11
|
+
let primaryFailure;
|
|
12
|
+
let threw = false;
|
|
13
|
+
try {
|
|
14
|
+
result = await runSetupWorkflow(options, host, confirm);
|
|
15
|
+
}
|
|
16
|
+
catch (cause) {
|
|
17
|
+
threw = true;
|
|
18
|
+
primaryFailure = cause;
|
|
19
|
+
}
|
|
20
|
+
let cleanupFailure;
|
|
21
|
+
try {
|
|
22
|
+
cleanupFailure = await host.close?.();
|
|
23
|
+
}
|
|
24
|
+
catch (cause) {
|
|
25
|
+
cleanupFailure = `Setup resource cleanup failed: ${failureMessage(cause)}`;
|
|
26
|
+
}
|
|
27
|
+
if (threw) {
|
|
28
|
+
if (cleanupFailure !== undefined && primaryFailure instanceof AnalysisError)
|
|
29
|
+
throw analysisErrorWithCleanupFailure(primaryFailure, new ProviderCleanupError("setup", primaryFailure.cleanupResources, { reason: cleanupFailure }, { operation: "setup" }), "setup");
|
|
30
|
+
if (cleanupFailure !== undefined)
|
|
31
|
+
throw new AggregateError([primaryFailure, new Error(cleanupFailure)], "Setup and resource cleanup failed.", { cause: primaryFailure });
|
|
32
|
+
throw primaryFailure;
|
|
33
|
+
}
|
|
34
|
+
if (result === undefined)
|
|
35
|
+
throw new Error("Setup returned no result.");
|
|
36
|
+
if (cleanupFailure === undefined)
|
|
37
|
+
return result;
|
|
38
|
+
return {
|
|
39
|
+
...result,
|
|
40
|
+
status: "needs_human",
|
|
41
|
+
code: result.code ?? "cleanup_failed",
|
|
42
|
+
remediation: result.remediation
|
|
43
|
+
? `${result.remediation} ${cleanupFailure}`
|
|
44
|
+
: cleanupFailure,
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
const runSetupWorkflow = async (options, host, confirm) => {
|
|
7
48
|
const appliedActions = [];
|
|
8
49
|
let plannedActions = [];
|
|
9
50
|
const clients = {};
|
|
@@ -27,6 +68,7 @@ export const runSetup = async (options, host = systemSetupHost(), confirm) => {
|
|
|
27
68
|
options.readinessScope?.clients === undefined &&
|
|
28
69
|
options.allDetectedClients !== true &&
|
|
29
70
|
options.installHopper !== true &&
|
|
71
|
+
options.skillClientIds === undefined &&
|
|
30
72
|
options.installSkill === undefined;
|
|
31
73
|
const interactiveSelection = confirm !== undefined && !options.structured && clientSelectionAllowed;
|
|
32
74
|
let selectedClientIds = options.allDetectedClients
|
|
@@ -34,9 +76,11 @@ export const runSetup = async (options, host = systemSetupHost(), confirm) => {
|
|
|
34
76
|
: (options.clientIds ??
|
|
35
77
|
options.readinessScope?.clients ??
|
|
36
78
|
discovery.defaultClientIds);
|
|
37
|
-
let
|
|
79
|
+
let selectedSkillClientIds = options.skillClientIds ?? selectedClientIds;
|
|
80
|
+
let skillNeedsInstall = await host.skillNeedsInstall(selectedSkillClientIds);
|
|
38
81
|
let skillSelected = options.installSkill === true ||
|
|
39
|
-
(options.installSkill !== false &&
|
|
82
|
+
(options.installSkill !== false &&
|
|
83
|
+
(selectedClientIds.length > 0 || selectedSkillClientIds.length > 0));
|
|
40
84
|
let installSkill = skillSelected && skillNeedsInstall;
|
|
41
85
|
let planDiscovery = discovery;
|
|
42
86
|
if (interactiveSelection) {
|
|
@@ -89,6 +133,7 @@ export const runSetup = async (options, host = systemSetupHost(), confirm) => {
|
|
|
89
133
|
selectedClientIds.length === 0) ||
|
|
90
134
|
(options.installSkill !== false && selectedClientIds.length > 0);
|
|
91
135
|
installSkill = skillSelected && skillNeedsInstall;
|
|
136
|
+
selectedSkillClientIds = selectedClientIds;
|
|
92
137
|
}
|
|
93
138
|
const planned = await planSetupActions({
|
|
94
139
|
discovery: planDiscovery,
|
|
@@ -96,7 +141,7 @@ export const runSetup = async (options, host = systemSetupHost(), confirm) => {
|
|
|
96
141
|
providerEnvironment,
|
|
97
142
|
command: host.registrationCommand,
|
|
98
143
|
clientIds: selectedClientIds,
|
|
99
|
-
skillClientIds:
|
|
144
|
+
skillClientIds: selectedSkillClientIds,
|
|
100
145
|
installSkill,
|
|
101
146
|
});
|
|
102
147
|
plannedActions = planned.plannedActions;
|
|
@@ -188,7 +233,7 @@ export const runSetup = async (options, host = systemSetupHost(), confirm) => {
|
|
|
188
233
|
if (clientFailure !== undefined)
|
|
189
234
|
return fail(clientFailure);
|
|
190
235
|
if (planSelection.installSkill &&
|
|
191
|
-
!(await installSkillAction(host, options, appliedActions,
|
|
236
|
+
!(await installSkillAction(host, options, appliedActions, selectedSkillClientIds)))
|
|
192
237
|
return fail("REA analysis skill could not be installed or verified. Check permissions for its planned skill directories, then rerun setup.");
|
|
193
238
|
const doctor = summarizeDoctor(await host.doctor(readinessScope));
|
|
194
239
|
const remediation = combineRemediation(finalSetupRemediation(host.platform, appliedActions.includes("installed_hopper"), doctor.healthy, hopperPath), manualRemediation);
|
|
@@ -234,8 +279,10 @@ const installHopperAction = async (input) => {
|
|
|
234
279
|
emitProgress(input.options, {
|
|
235
280
|
actionId: "install_hopper",
|
|
236
281
|
label,
|
|
237
|
-
state: "completed",
|
|
238
|
-
detail: installed.
|
|
282
|
+
state: installed.cleanupFailure === undefined ? "completed" : "warning",
|
|
283
|
+
detail: installed.cleanupFailure === undefined
|
|
284
|
+
? installed.launcherPath
|
|
285
|
+
: `${installed.launcherPath}; ${installed.cleanupFailure}`,
|
|
239
286
|
});
|
|
240
287
|
const providerEnvironment = {
|
|
241
288
|
...input.providerEnvironment,
|
|
@@ -345,3 +392,4 @@ const summarizeDoctor = (report) => ({
|
|
|
345
392
|
},
|
|
346
393
|
}),
|
|
347
394
|
});
|
|
395
|
+
const failureMessage = (cause) => cause instanceof Error ? cause.message : String(cause);
|
|
@@ -1,42 +1,82 @@
|
|
|
1
|
+
import { readClientPolicyBlock } from "./GeminiClientSettings.js";
|
|
2
|
+
import { readClientConfigurationFiles } from "./ClientConfigurationFiles.js";
|
|
1
3
|
import { clientRegistrationEntry, clientConfigurationValuesEqual, clientServerListedDisabled, clientServerPath, legacyClientServerPath, OMP_DISABLED_SERVERS_KEY, parseClientConfiguration, serializeClientConfiguration, withClientServers, } from "./ClientConfigurationDocument.js";
|
|
2
4
|
import { constants as fsConstants } from "node:fs";
|
|
3
|
-
import { copyFile, mkdir,
|
|
5
|
+
import { copyFile, mkdir, rm, writeFile } from "node:fs/promises";
|
|
4
6
|
import { dirname } from "node:path";
|
|
5
7
|
import writeFileAtomic from "write-file-atomic";
|
|
8
|
+
import { clientRegistrationEnvironment } from "./ClientRegistrationEnvironment.js";
|
|
6
9
|
import { PRODUCT_IDENTITY } from "../identity.js";
|
|
7
10
|
import { npxRegistrationCommand } from "./ClientRegistrationIdentity.js";
|
|
8
11
|
import { MCP_STARTUP_POLICY } from "../mcpStartupPolicy.js";
|
|
9
12
|
import { resolveClientConfigTransactionPath } from "./ClientConfigPath.js";
|
|
13
|
+
import { readRegularFileText, RegularFileCleanupFailure, } from "./RegularFileRead.js";
|
|
10
14
|
/** Configure one supported client's native stdio MCP registration shape. */
|
|
11
15
|
export const configureClientConfiguration = (client, environment = {}, command = npxRegistrationCommand()) => {
|
|
12
|
-
if (client.
|
|
13
|
-
return Promise.resolve({ status: "failed", reason: "
|
|
14
|
-
return configureClientDocument(client, environment, command
|
|
16
|
+
if (client.configPathError !== undefined)
|
|
17
|
+
return Promise.resolve({ status: "failed", reason: "path" });
|
|
18
|
+
return configureClientDocument(client, environment, command);
|
|
15
19
|
};
|
|
16
|
-
const configureClientDocument = async (client, environment, command
|
|
20
|
+
const configureClientDocument = async (client, environment, command) => {
|
|
21
|
+
const format = client.format;
|
|
22
|
+
if (format === undefined || format === "unsupported")
|
|
23
|
+
return { status: "failed", reason: "readback" };
|
|
24
|
+
const files = await readClientConfigurationFiles(client);
|
|
25
|
+
if (!files.ok) {
|
|
26
|
+
throwCleanupFailure(files.error);
|
|
27
|
+
return { status: "failed", reason: "readback" };
|
|
28
|
+
}
|
|
29
|
+
const policy = await readClientPolicyBlock(client, undefined, clientConfigurationDesired(client, environment, command, files.value.at(-1)));
|
|
30
|
+
if (!policy.ok) {
|
|
31
|
+
throwCleanupFailure(policy.error);
|
|
32
|
+
return { status: "failed", reason: "readback" };
|
|
33
|
+
}
|
|
34
|
+
if (policy.value !== undefined)
|
|
35
|
+
return { status: "failed", reason: "readback" };
|
|
17
36
|
const transactionPath = await resolveClientConfigTransactionPath(client.configPath);
|
|
18
37
|
if (transactionPath === undefined)
|
|
19
38
|
return { status: "failed", reason: "path" };
|
|
20
39
|
let original;
|
|
21
40
|
try {
|
|
22
|
-
original = await
|
|
41
|
+
original = await readRegularFileText(transactionPath);
|
|
23
42
|
}
|
|
24
43
|
catch (cause) {
|
|
44
|
+
if (cause instanceof RegularFileCleanupFailure)
|
|
45
|
+
throw cause;
|
|
25
46
|
if (!isMissing(cause))
|
|
26
47
|
return { status: "failed", reason: "readback" };
|
|
27
48
|
}
|
|
28
49
|
let parsed;
|
|
29
50
|
try {
|
|
30
51
|
parsed = parseClientConfiguration(original ?? (format === "toml" || format === "grok" ? "" : "{}"), format);
|
|
52
|
+
const policy = await readClientPolicyBlock(client, parsed, clientConfigurationDesired(client, environment, command, parsed));
|
|
53
|
+
if (!policy.ok) {
|
|
54
|
+
throwCleanupFailure(policy.error);
|
|
55
|
+
return { status: "failed", reason: "readback" };
|
|
56
|
+
}
|
|
57
|
+
if (policy.value !== undefined)
|
|
58
|
+
return { status: "failed", reason: "readback" };
|
|
31
59
|
}
|
|
32
60
|
catch (cause) {
|
|
61
|
+
if (cause instanceof RegularFileCleanupFailure)
|
|
62
|
+
throw cause;
|
|
33
63
|
// Malformed existing configuration fails the readback gate.
|
|
34
64
|
void cause;
|
|
35
65
|
return { status: "failed", reason: "readback" };
|
|
36
66
|
}
|
|
37
|
-
const desired = clientConfigurationDesired(client, environment, command, parsed
|
|
67
|
+
const desired = clientConfigurationDesired(client, environment, command, parsed);
|
|
38
68
|
if (registrationCurrent(parsed, desired))
|
|
39
69
|
return { status: "unchanged" };
|
|
70
|
+
return persistClientConfiguration({
|
|
71
|
+
client,
|
|
72
|
+
transactionPath,
|
|
73
|
+
format,
|
|
74
|
+
original,
|
|
75
|
+
parsed,
|
|
76
|
+
desired,
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
const persistClientConfiguration = async ({ client, transactionPath, format, original, parsed, desired, }) => {
|
|
40
80
|
const backupPath = original === undefined ? undefined : `${client.configPath}.rea.backup`;
|
|
41
81
|
if (backupPath !== undefined &&
|
|
42
82
|
!(await preserveConfigBackup(transactionPath, backupPath)))
|
|
@@ -74,13 +114,15 @@ const configureClientDocument = async (client, environment, command, format) =>
|
|
|
74
114
|
return { status: "failed", reason: "write" };
|
|
75
115
|
}
|
|
76
116
|
try {
|
|
77
|
-
const readback = parseClientConfiguration(await
|
|
117
|
+
const readback = parseClientConfiguration(await readRegularFileText(transactionPath), format);
|
|
78
118
|
if (!registrationCurrent(readback, desired)) {
|
|
79
119
|
await restoreConfig(transactionPath, original);
|
|
80
120
|
return { status: "failed", reason: "readback" };
|
|
81
121
|
}
|
|
82
122
|
}
|
|
83
123
|
catch (cause) {
|
|
124
|
+
if (cause instanceof RegularFileCleanupFailure)
|
|
125
|
+
throw cause;
|
|
84
126
|
// Readback failure restores the transaction before reporting.
|
|
85
127
|
void cause;
|
|
86
128
|
await restoreConfig(transactionPath, original);
|
|
@@ -93,12 +135,27 @@ const configureClientDocument = async (client, environment, command, format) =>
|
|
|
93
135
|
};
|
|
94
136
|
/** Determine whether an existing client configuration matches the desired registration. */
|
|
95
137
|
export const clientConfigurationAligned = async (client, providerEnvironment, command) => {
|
|
138
|
+
if (client.configPathError !== undefined)
|
|
139
|
+
return false;
|
|
96
140
|
try {
|
|
97
|
-
const
|
|
141
|
+
const files = await readClientConfigurationFiles(client);
|
|
142
|
+
if (!files.ok) {
|
|
143
|
+
throwCleanupFailure(files.error);
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
const original = await readRegularFileText(client.configPath);
|
|
98
147
|
const parsed = parseClientConfiguration(original, client.format);
|
|
99
|
-
|
|
148
|
+
const policy = await readClientPolicyBlock(client, parsed, clientConfigurationDesired(client, providerEnvironment, command, parsed));
|
|
149
|
+
if (!policy.ok) {
|
|
150
|
+
throwCleanupFailure(policy.error);
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
return (policy.value === undefined &&
|
|
154
|
+
registrationCurrent(parsed, clientConfigurationDesired(client, providerEnvironment, command, parsed)));
|
|
100
155
|
}
|
|
101
156
|
catch (cause) {
|
|
157
|
+
if (cause instanceof RegularFileCleanupFailure)
|
|
158
|
+
throw cause;
|
|
102
159
|
// Unreadable configuration is treated as not aligned so setup repairs it.
|
|
103
160
|
void cause;
|
|
104
161
|
return false;
|
|
@@ -106,8 +163,28 @@ export const clientConfigurationAligned = async (client, providerEnvironment, co
|
|
|
106
163
|
};
|
|
107
164
|
/** Preflight one client configuration before setup presents any mutations. */
|
|
108
165
|
export const inspectClientConfiguration = async (client, providerEnvironment, command) => {
|
|
166
|
+
if (client.configPathError !== undefined)
|
|
167
|
+
return { status: "invalid", remediation: client.configPathError };
|
|
109
168
|
if (client.format === "unsupported")
|
|
110
169
|
return { status: "already_current" };
|
|
170
|
+
const files = await readClientConfigurationFiles(client);
|
|
171
|
+
if (!files.ok) {
|
|
172
|
+
throwCleanupFailure(files.error);
|
|
173
|
+
return {
|
|
174
|
+
status: "invalid",
|
|
175
|
+
remediation: files.error.detail,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const policy = await readClientPolicyBlock(client, undefined, clientConfigurationDesired(client, providerEnvironment, command, files.value.at(-1)));
|
|
179
|
+
if (!policy.ok) {
|
|
180
|
+
throwCleanupFailure(policy.error);
|
|
181
|
+
return {
|
|
182
|
+
status: "invalid",
|
|
183
|
+
remediation: policy.error.detail,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
if (policy.value !== undefined)
|
|
187
|
+
return { status: "invalid", remediation: policy.value };
|
|
111
188
|
const transactionPath = await resolveClientConfigTransactionPath(client.configPath);
|
|
112
189
|
if (transactionPath === undefined)
|
|
113
190
|
return {
|
|
@@ -116,23 +193,37 @@ export const inspectClientConfiguration = async (client, providerEnvironment, co
|
|
|
116
193
|
};
|
|
117
194
|
let original;
|
|
118
195
|
try {
|
|
119
|
-
original = await
|
|
196
|
+
original = await readRegularFileText(transactionPath);
|
|
120
197
|
}
|
|
121
198
|
catch (cause) {
|
|
199
|
+
if (cause instanceof RegularFileCleanupFailure)
|
|
200
|
+
throw cause;
|
|
122
201
|
if (isMissing(cause))
|
|
123
202
|
return { status: "create" };
|
|
124
203
|
return {
|
|
125
204
|
status: "invalid",
|
|
126
|
-
remediation:
|
|
205
|
+
remediation: `The configuration file could not be read. Check its permissions before rerunning setup. ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
127
206
|
};
|
|
128
207
|
}
|
|
129
208
|
try {
|
|
130
209
|
const parsed = parseClientConfiguration(original, client.format);
|
|
131
|
-
const
|
|
210
|
+
const policy = await readClientPolicyBlock(client, parsed, clientConfigurationDesired(client, providerEnvironment, command, parsed));
|
|
211
|
+
if (!policy.ok) {
|
|
212
|
+
throwCleanupFailure(policy.error);
|
|
213
|
+
return {
|
|
214
|
+
status: "invalid",
|
|
215
|
+
remediation: policy.error.detail,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
if (policy.value !== undefined)
|
|
219
|
+
return { status: "invalid", remediation: policy.value };
|
|
220
|
+
const desired = clientConfigurationDesired(client, providerEnvironment, command, parsed);
|
|
132
221
|
if (registrationCurrent(parsed, desired))
|
|
133
222
|
return { status: "already_current" };
|
|
134
223
|
}
|
|
135
224
|
catch (cause) {
|
|
225
|
+
if (cause instanceof RegularFileCleanupFailure)
|
|
226
|
+
throw cause;
|
|
136
227
|
// Malformed configuration is reported with the invalid remediation.
|
|
137
228
|
void cause;
|
|
138
229
|
return {
|
|
@@ -146,6 +237,10 @@ export const inspectClientConfiguration = async (client, providerEnvironment, co
|
|
|
146
237
|
};
|
|
147
238
|
};
|
|
148
239
|
const isMissing = (cause) => cause instanceof Error && "code" in cause && cause.code === "ENOENT";
|
|
240
|
+
const throwCleanupFailure = (error) => {
|
|
241
|
+
if (error.cleanupFailure !== undefined)
|
|
242
|
+
throw error.cleanupFailure;
|
|
243
|
+
};
|
|
149
244
|
const preserveConfigBackup = async (source, destination) => {
|
|
150
245
|
try {
|
|
151
246
|
await copyFile(source, destination, fsConstants.COPYFILE_EXCL);
|
|
@@ -171,9 +266,14 @@ const restoreConfig = async (path, original) => {
|
|
|
171
266
|
const registrationCurrent = (parsed, desired) => clientConfigurationValuesEqual(parsed.servers[PRODUCT_IDENTITY.mcpServerKey], desired) &&
|
|
172
267
|
!Object.hasOwn(parsed.legacyServers, PRODUCT_IDENTITY.mcpServerKey) &&
|
|
173
268
|
!clientServerListedDisabled(parsed, PRODUCT_IDENTITY.mcpServerKey);
|
|
174
|
-
const clientConfigurationDesired = (client, providerEnvironment, command,
|
|
175
|
-
const
|
|
176
|
-
|
|
269
|
+
const clientConfigurationDesired = (client, providerEnvironment, command, parsed) => {
|
|
270
|
+
const format = parsed?.dialect ?? client.format ?? "json";
|
|
271
|
+
// Preserve explicitly configured server settings, never the ambient process
|
|
272
|
+
// environment. Newly discovered provider paths win only for their own keys.
|
|
273
|
+
const environment = clientRegistrationEnvironment(parsed, providerEnvironment);
|
|
274
|
+
if (!environment.ok)
|
|
275
|
+
throw environment.error;
|
|
276
|
+
const registration = clientRegistrationEntry(format, command.length === 0 ? [PRODUCT_IDENTITY.cliBinary, "mcp"] : command, environment.value);
|
|
177
277
|
return {
|
|
178
278
|
...registration,
|
|
179
279
|
...(client.name === "codex" || client.name === "grok_build"
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { access } from "node:fs/promises";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
|
+
import { ArtifactResourceScope } from "../artifacts/ArtifactResourceScope.js";
|
|
4
|
+
import { ArtifactReaderFailure } from "../artifacts/ArtifactReader.js";
|
|
5
|
+
import { ConfigurationError } from "../domain/configurationErrors.js";
|
|
3
6
|
import { PRODUCT_IDENTITY } from "../identity.js";
|
|
4
7
|
import { npxRegistrationCommand } from "./ClientRegistrationIdentity.js";
|
|
5
8
|
import { SUPPORTED_NODE_VERSION_PROSE, supportsNodeVersion, } from "../domain/runtimeVersion.js";
|
|
6
9
|
import { runDoctor, systemDoctorHost } from "./Doctor.js";
|
|
7
10
|
import { installLinuxHopper, readLinuxDistribution, systemLinuxHopperInstallHost, } from "./LinuxHopper.js";
|
|
8
11
|
import { installMacHopper, systemMacHopperInstallHost } from "./MacHopper.js";
|
|
9
|
-
import { supportedClients } from "./SupportedClients.js";
|
|
10
|
-
import {
|
|
12
|
+
import { clientEvidencePaths, supportedClients, } from "./SupportedClients.js";
|
|
13
|
+
import { skillDestinations, canonicalSkillNeedsInstall, installCanonicalSkill, } from "./SetupSkill.js";
|
|
11
14
|
import { clientConfigurationAligned, configureClientConfiguration, inspectClientConfiguration, } from "./SetupClientConfiguration.js";
|
|
12
15
|
import { setupInstallFailure } from "./SetupInstallFailure.js";
|
|
16
|
+
import { RegularFileCleanupFailure, retryRegularFileCleanup, } from "./RegularFileRead.js";
|
|
13
17
|
import { providerRegistrationEnvironment } from "./SetupRegistrationEnvironment.js";
|
|
14
18
|
/** Resolve the executable and arguments used in a managed MCP registration. */
|
|
15
19
|
export const setupRegistrationCommand = (platform, useNpmRunner) => useNpmRunner
|
|
@@ -40,22 +44,26 @@ export const hostRemediation = async (host, installHopper) => {
|
|
|
40
44
|
}
|
|
41
45
|
if ((await host.linuxDistribution())?.supported === true)
|
|
42
46
|
return undefined;
|
|
43
|
-
return "Automated Hopper setup supports Ubuntu 24.04+, Fedora 41+, Nobara 44+, 64-bit Arch Linux, and
|
|
47
|
+
return "Automated Hopper setup supports Ubuntu 24.04+, Fedora 41+, Nobara 44+, 64-bit Arch Linux, CachyOS, and Omarchy; configure an existing supported provider instead.";
|
|
44
48
|
};
|
|
45
49
|
/** Production setup effects for Hopper, agent configuration, and the canonical skill directory. */
|
|
46
50
|
export const systemSetupHost = (selectedDoctorHost = undefined, environment = process.env) => {
|
|
47
51
|
const doctorHost = selectedDoctorHost ?? systemDoctorHost({ environment });
|
|
48
52
|
const platform = doctorHost.platform;
|
|
49
53
|
const { homeDirectory } = doctorHost;
|
|
50
|
-
const
|
|
54
|
+
const macHopperHost = platform === "darwin"
|
|
55
|
+
? systemMacHopperInstallHost(homeDirectory, environment)
|
|
56
|
+
: undefined;
|
|
57
|
+
const resources = new ArtifactResourceScope();
|
|
51
58
|
return {
|
|
52
59
|
platform,
|
|
53
60
|
homeDirectory,
|
|
54
|
-
|
|
61
|
+
skillDestinations: (clientIds) => skillDestinations(homeDirectory, clientIds, environment, platform),
|
|
55
62
|
registrationCommand: setupRegistrationCommand(platform, environment.npm_command === "exec"),
|
|
56
63
|
nodeVersion: process.versions.node,
|
|
57
64
|
macosVersion: () => doctorHost.macosVersion(),
|
|
58
65
|
linuxDistribution: readLinuxDistribution,
|
|
66
|
+
close: () => closeSetupResources(resources, macHopperHost),
|
|
59
67
|
initialSetupState: async (scope) => {
|
|
60
68
|
const diagnosis = await runDoctor(undefined, doctorHost, scope);
|
|
61
69
|
return {
|
|
@@ -72,41 +80,111 @@ export const systemSetupHost = (selectedDoctorHost = undefined, environment = pr
|
|
|
72
80
|
};
|
|
73
81
|
},
|
|
74
82
|
installHopper: async (replaceExisting) => {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
83
|
+
if (platform === "linux") {
|
|
84
|
+
const result = await installLinuxHopper(systemLinuxHopperInstallHost(environment));
|
|
85
|
+
return result.status === "installed"
|
|
86
|
+
? result
|
|
87
|
+
: setupInstallFailure(result.reason);
|
|
88
|
+
}
|
|
89
|
+
if (macHopperHost === undefined)
|
|
90
|
+
return setupInstallFailure("unsupported_host");
|
|
91
|
+
const result = await installMacHopper({ replaceExisting }, macHopperHost);
|
|
78
92
|
if (result.status === "installed")
|
|
79
|
-
return
|
|
80
|
-
|
|
93
|
+
return {
|
|
94
|
+
status: "installed",
|
|
95
|
+
launcherPath: result.launcherPath,
|
|
96
|
+
...(result.cleanupFailure === undefined
|
|
97
|
+
? {}
|
|
98
|
+
: { cleanupFailure: result.cleanupFailure }),
|
|
99
|
+
};
|
|
100
|
+
const failure = setupInstallFailure(result.reason);
|
|
101
|
+
if (result.cleanupFailure === undefined)
|
|
102
|
+
return failure;
|
|
103
|
+
return failure.status === "failed"
|
|
104
|
+
? {
|
|
105
|
+
...failure,
|
|
106
|
+
remediation: `${failure.remediation} ${result.cleanupFailure}`,
|
|
107
|
+
}
|
|
108
|
+
: failure;
|
|
81
109
|
},
|
|
82
110
|
detectedClients: () => detectClients(homeDirectory, platform, environment),
|
|
83
111
|
supportedClients: () => Promise.resolve(supportedClients(homeDirectory, platform, environment)),
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
clientNeedsConfigure: (client, providerEnvironment, command) => client.format === "unsupported"
|
|
88
|
-
? Promise.resolve(false)
|
|
89
|
-
: clientConfigurationAligned(client, providerEnvironment, command).then((aligned) => !aligned),
|
|
90
|
-
inspectClientConfiguration: inspectClientConfiguration,
|
|
91
|
-
skillNeedsInstall: (clientIds) => canonicalSkillNeedsInstall(homeDirectory, clientIds, claudeSkillsDirectory),
|
|
92
|
-
installSkill: (clientIds) => installCanonicalSkill(homeDirectory, clientIds, claudeSkillsDirectory),
|
|
112
|
+
...clientConfigurationOperations(resources),
|
|
113
|
+
skillNeedsInstall: (clientIds) => canonicalSkillNeedsInstall(homeDirectory, clientIds, environment, platform),
|
|
114
|
+
installSkill: (clientIds) => installCanonicalSkill(homeDirectory, clientIds, environment, platform),
|
|
93
115
|
doctor: (scope) => runDoctor(undefined, doctorHost, scope),
|
|
94
116
|
};
|
|
95
117
|
};
|
|
118
|
+
const clientConfigurationOperations = (resources) => ({
|
|
119
|
+
configureClient: (client, providerEnvironment, command) => runClientConfigurationOperation(resources, async () => client.format === "unsupported"
|
|
120
|
+
? { status: "skipped" }
|
|
121
|
+
: configureClientConfiguration(client, providerEnvironment, command)),
|
|
122
|
+
clientNeedsConfigure: (client, providerEnvironment, command) => runClientConfigurationOperation(resources, async () => client.format === "unsupported"
|
|
123
|
+
? false
|
|
124
|
+
: !(await clientConfigurationAligned(client, providerEnvironment, command))),
|
|
125
|
+
inspectClientConfiguration: (client, providerEnvironment, command) => runClientConfigurationOperation(resources, () => inspectClientConfiguration(client, providerEnvironment, command)),
|
|
126
|
+
});
|
|
127
|
+
const closeSetupResources = async (resources, macHopperHost) => {
|
|
128
|
+
const [resourceCleanup, hopperCleanup] = await Promise.allSettled([
|
|
129
|
+
resources.close(),
|
|
130
|
+
Promise.resolve().then(() => macHopperHost?.close()),
|
|
131
|
+
]);
|
|
132
|
+
const failures = [];
|
|
133
|
+
if (hopperCleanup.status === "rejected")
|
|
134
|
+
failures.push(`Hopper host cleanup failed: ${errorMessage(hopperCleanup.reason)}`);
|
|
135
|
+
else if (hopperCleanup.value !== undefined)
|
|
136
|
+
failures.push(hopperCleanup.value);
|
|
137
|
+
if (resourceCleanup.status === "rejected")
|
|
138
|
+
failures.push(errorMessage(resourceCleanup.reason));
|
|
139
|
+
return failures.length === 0 ? undefined : failures.join("; ");
|
|
140
|
+
};
|
|
141
|
+
const runClientConfigurationOperation = async (resources, operation) => {
|
|
142
|
+
try {
|
|
143
|
+
return await resources.run(async () => {
|
|
144
|
+
try {
|
|
145
|
+
return await operation();
|
|
146
|
+
}
|
|
147
|
+
catch (cause) {
|
|
148
|
+
if (!(cause instanceof RegularFileCleanupFailure))
|
|
149
|
+
throw cause;
|
|
150
|
+
const cleanup = await retryRegularFileCleanup(cause, resources);
|
|
151
|
+
const primary = cleanup.outcome.kind === "failed"
|
|
152
|
+
? cleanup.outcome.cause
|
|
153
|
+
: cause.cleanupCause;
|
|
154
|
+
throw configurationCleanupError(`Could not safely access client configuration at ${cause.path}: ${errorMessage(primary)}`, cause, cleanup.cleanup);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
catch (cause) {
|
|
159
|
+
if (cause instanceof ArtifactReaderFailure)
|
|
160
|
+
throw configurationCleanupError(cause.message, cause, cause.cleanup);
|
|
161
|
+
throw cause;
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
const configurationCleanupError = (message, cause, cleanup) => new ConfigurationError(message, {
|
|
165
|
+
cause,
|
|
166
|
+
settings: [{ setting: "client configuration", constraint: message }],
|
|
167
|
+
...(cleanup === undefined ? {} : { cleanup }),
|
|
168
|
+
});
|
|
169
|
+
const errorMessage = (cause) => cause instanceof Error ? cause.message : String(cause);
|
|
96
170
|
/** Detect supported agents from their config files or stable installation markers. */
|
|
97
171
|
export const detectClients = async (home, platform = process.platform, environment = process.env) => {
|
|
98
172
|
const detected = [];
|
|
99
173
|
for (const candidate of supportedClients(home, platform, environment)) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
]);
|
|
104
|
-
if (hasConfig || hasMarker)
|
|
174
|
+
if (candidate.configPathError !== undefined)
|
|
175
|
+
continue;
|
|
176
|
+
if (await clientEvidencePresent(candidate))
|
|
105
177
|
detected.push(candidate);
|
|
106
178
|
}
|
|
107
179
|
return detected;
|
|
108
180
|
};
|
|
109
181
|
const major = (version) => Number.parseInt(version.split(".")[0] ?? "0", 10);
|
|
182
|
+
const clientEvidencePresent = async (client) => {
|
|
183
|
+
for (const path of clientEvidencePaths(client))
|
|
184
|
+
if (await exists(path))
|
|
185
|
+
return true;
|
|
186
|
+
return false;
|
|
187
|
+
};
|
|
110
188
|
const exists = async (path) => {
|
|
111
189
|
try {
|
|
112
190
|
await access(path);
|