rea-agents 5.0.0 → 6.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 +168 -655
- package/bridge/android/ReaJadxBridge.java +14 -5
- package/bridge/ghidra/ReaGhidraBridge.java +173 -47
- package/bridge/hopper_bridge.py +310 -128
- package/bridge/mitmproxy/capture.py +208 -0
- package/bridge/native/rea_lldb_tracer.py +839 -0
- package/bridge/process/ProcessRunTokenReader.swift +297 -0
- package/bridge/process/ProcessRunTokenReaderMain.swift +35 -0
- package/bridge/pwndbg/core_context.py +101 -0
- package/bridge/pwndbg/launch.py +39 -0
- package/bridge/pwndbg/launch_impl.py +34 -0
- package/bridge/pwntools/decoder_runtime.py +59 -0
- package/bridge/pwntools/layout.py +39 -0
- package/bridge/pwntools/layout_impl.py +309 -0
- package/bridge/pwntools/recorded_crash.py +39 -0
- package/bridge/pwntools/recorded_crash_impl.py +147 -0
- package/dist/android/JadxConfiguration.js +196 -33
- package/dist/android/JadxMcpTransport.js +4 -0
- package/dist/android/JadxProtocol.js +6 -0
- package/dist/android/JadxProvider.js +20 -2
- package/dist/android/JadxSession.js +23 -4
- package/dist/application/AnalysisContextQueries.js +8 -35
- package/dist/application/AnalysisDocument.js +32 -0
- package/dist/application/AppBundleExecutable.js +67 -21
- package/dist/application/CallPathTracing.js +19 -3
- package/dist/application/CapabilityInventory.js +27 -3
- package/dist/application/ClientConfigurationDocument.js +871 -6
- package/dist/application/ClientRegistrationIdentity.js +26 -5
- package/dist/application/ClientRegistrationStatus.js +29 -14
- package/dist/application/DirectAnalysis.js +97 -33
- package/dist/application/Doctor.js +4 -2
- package/dist/application/DoctorScope.js +25 -13
- package/dist/application/EnhancedLiteralTracing.js +22 -25
- package/dist/application/EnhancedTools.js +13 -11
- package/dist/application/EvidenceBundleFiles.js +24 -12
- package/dist/application/FunctionAnalysisEvidence.js +2 -3
- package/dist/application/InventoryProjectionEvidence.js +4 -3
- package/dist/application/InvestigationProviders.js +3 -2
- package/dist/application/JsonFiles.js +50 -28
- package/dist/application/ProcedureAddressResolution.js +11 -0
- package/dist/application/ReconstructionCoverageService.js +7 -4
- package/dist/application/ReconstructionObligationCandidates.js +5 -1
- package/dist/application/ReconstructionObligationLedgerService.js +4 -3
- package/dist/application/Setup.js +13 -1
- package/dist/application/SetupClientConfiguration.js +10 -15
- package/dist/application/SetupHost.js +5 -2
- package/dist/application/SetupPlan.js +5 -3
- package/dist/application/SupportedClients.js +34 -1
- package/dist/application/Uninstall.js +4 -3
- package/dist/application/Update.js +18 -3
- package/dist/application/UpdateRuntime.js +46 -25
- package/dist/application/WebModuleTraceService.js +4 -2
- package/dist/application/WebNetworkCapturePort.js +1 -0
- package/dist/application/WebNetworkCaptureService.js +134 -0
- package/dist/application/WebRuntimeService.js +5 -3
- package/dist/application/WebScriptExportService.js +2 -2
- package/dist/application/WebSourceLocationService.js +4 -2
- package/dist/application/WindowsCapabilities.js +1 -1
- package/dist/application/WorkflowEvidence.js +82 -0
- package/dist/application/binary/AnalysisProviderEvaluation.js +21 -5
- package/dist/application/binary/AnalysisProviderRegistry.js +2 -0
- package/dist/application/binary/AnalysisSnapshotCache.js +52 -12
- package/dist/application/binary/BinarySession.js +131 -76
- package/dist/application/binary/BinarySessionOpen.js +19 -6
- package/dist/application/binary/BinarySessionRecords.js +45 -3
- package/dist/application/binary/BinarySessionStatus.js +17 -1
- package/dist/application/binary/CompositeProvider.js +13 -0
- package/dist/application/binary/LazyAnalysisProvider.js +3 -0
- package/dist/application/binaryDiagnostics/BinaryLayoutPort.js +1 -0
- package/dist/application/binaryDiagnostics/BinaryLayoutService.js +59 -0
- package/dist/application/binaryDiagnostics/RecordedCrashPort.js +1 -0
- package/dist/application/binaryDiagnostics/RecordedCrashService.js +62 -0
- package/dist/application/evm/EvmInterfacePort.js +1 -0
- package/dist/application/evm/EvmInterfaceService.js +64 -0
- package/dist/application/investigation/EvidenceLedger.js +21 -7
- package/dist/application/investigation/InvestigationRecords.js +8 -0
- package/dist/application/javascript/JavaScriptAnalysisControl.js +34 -0
- package/dist/application/javascript/JavaScriptApplicationEvidence.js +25 -5
- package/dist/application/javascript/JavaScriptApplicationEvidenceGraph.js +19 -2
- package/dist/application/javascript/JavaScriptApplicationService.js +34 -14
- package/dist/application/javascript/JavaScriptApplicationWorkflowService.js +5 -5
- package/dist/application/javascript/JavaScriptArtifactAnalysis.js +47 -27
- package/dist/application/javascript/JavaScriptArtifactGraphBuilder.js +39 -7
- package/dist/application/javascript/JavaScriptArtifactGraphDocuments.js +26 -2
- package/dist/application/javascript/JavaScriptArtifactPathResolution.js +80 -27
- package/dist/application/javascript/JavaScriptArtifactReconstruction.js +33 -12
- package/dist/application/javascript/JavaScriptModuleRelationships.js +37 -8
- package/dist/application/javascript/JavaScriptRecoveryService.js +4 -2
- package/dist/application/javascript/JavaScriptRuntimeObservationService.js +3 -1
- package/dist/application/javascript/JavaScriptRuntimeReconciliationService.js +3 -3
- package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +7 -7
- package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +149 -72
- package/dist/application/javascript/JavaScriptSemanticGraphChildProcessProjection.js +14 -15
- package/dist/application/javascript/JavaScriptSemanticGraphConstruction.js +41 -1
- package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +7 -7
- package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +5 -9
- package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +3 -3
- package/dist/application/javascript/JavaScriptSemanticGraphProjection.js +118 -12
- package/dist/application/javascript/JavaScriptSemanticGraphResourceProjection.js +3 -3
- package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +27 -5
- package/dist/application/managed/ManagedApplicationGraphService.js +4 -3
- package/dist/application/managed/ManagedMemberComparisonService.js +7 -4
- package/dist/application/managed/ManagedNativeVerificationService.js +4 -3
- package/dist/application/managed/ManagedReconstructionService.js +4 -3
- package/dist/application/{ProcessCli.js → process/ProcessCli.js} +23 -15
- package/dist/application/{ProcessEvidence.js → process/ProcessEvidence.js} +8 -7
- package/dist/application/workflowInputError.js +18 -0
- package/dist/artifacts/ArtifactProvider.js +42 -5
- package/dist/artifacts/ArtifactProviderMetadata.js +2 -1
- package/dist/artifacts/MachOSliceArtifactReader.js +98 -14
- package/dist/artifacts/NativeDmgArtifactReader.js +13 -6
- package/dist/artifacts/ZipArtifactReader.js +3 -0
- package/dist/artifacts/apple/AppleAssetCatalogAnalysis.js +22 -3
- package/dist/artifacts/apple/DylibResolutionReader.js +259 -0
- package/dist/artifacts/apple/InterfaceBuilderAnalysis.js +176 -56
- package/dist/artifacts/apple/InterfaceBuilderDecodeBudget.js +195 -0
- package/dist/artifacts/apple/KeyedArchiveReader.js +36 -22
- package/dist/artifacts/apple/MachoLoadCommandReader.js +355 -0
- package/dist/artifacts/apple/NibArchive.js +81 -14
- package/dist/artifacts/apple/NibViewHierarchy.js +10 -3
- package/dist/artifacts/apple/PlistNumberLiterals.js +164 -0
- package/dist/{application → artifacts/extraction}/ArtifactExtraction.js +10 -10
- package/dist/{application → artifacts/inventory}/ArtifactGraphConstruction.js +16 -11
- package/dist/{application → artifacts/inventory}/ArtifactInventory.js +4 -4
- package/dist/{application/ArtifactInventory → artifacts/inventory}/classify.js +2 -2
- package/dist/{application/ArtifactInventory → artifacts/inventory}/reader.js +5 -5
- package/dist/{application/ArtifactInventory → artifacts/inventory}/scanCanonical.js +14 -17
- package/dist/{application/ArtifactInventory → artifacts/inventory}/scanReader.js +5 -5
- package/dist/artifacts/javascript/JavaScriptArtifactFiles.js +6 -2
- package/dist/artifacts/readStableArtifact.js +20 -4
- package/dist/browser/CdpCaptureCompleteness.js +2 -0
- package/dist/browser/CdpCaptureEventHandlers.js +165 -12
- package/dist/browser/CdpCaptureEventTypes.js +5 -1
- package/dist/browser/CdpCaptureEvents.js +34 -0
- package/dist/browser/CdpConnection.js +30 -11
- package/dist/browser/CdpOptionalCommand.js +2 -3
- package/dist/browser/CdpPageCapture.js +23 -1
- package/dist/browser/PlaywrightElectronActiveActions.js +32 -23
- package/dist/browser/PlaywrightElectronActiveProjection.js +141 -0
- package/dist/browser/PlaywrightElectronActiveProvider.js +130 -122
- package/dist/browser/WebSourceMapFetcher.js +426 -72
- package/dist/browser/assets/LocalWebScriptArtifacts.js +2 -2
- package/dist/browser/history/CaptureFailures.js +137 -0
- package/dist/browser/history/CaptureFormatError.js +10 -0
- package/dist/browser/history/CaptureRedaction.js +65 -0
- package/dist/browser/history/CaptureRelease.js +17 -0
- package/dist/browser/history/HarCapture.js +165 -0
- package/dist/browser/history/HarCaptureAdapter.js +20 -0
- package/dist/browser/history/HarCaptureProcess.js +57 -0
- package/dist/browser/history/HarJson.js +92 -0
- package/dist/browser/history/HarSchema.js +72 -0
- package/dist/browser/history/HistoricalCaptureDecoder.js +188 -0
- package/dist/browser/history/HistoricalCaptureFormatAdapter.js +1 -0
- package/dist/browser/history/MitmproxyCaptureAdapter.js +42 -0
- package/dist/cli/analysisSelector.js +23 -0
- package/dist/cli/applicationCommands.js +2 -3
- package/dist/cli/artifactCommands.js +26 -1
- package/dist/cli/binaryDiagnosticsCommands.js +39 -0
- package/dist/cli/coreAnalysisCommands.js +2 -2
- package/dist/cli/coreBinaryCommands.js +78 -20
- package/dist/cli/electronCommands.js +21 -13
- package/dist/cli/evmCommands.js +24 -0
- package/dist/cli/firmwareCommands.js +6 -3
- package/dist/cli/javascriptApplicationAnalysis.js +20 -3
- package/dist/cli/jsonOutput.js +38 -0
- package/dist/cli/nativeCallCommands.js +34 -0
- package/dist/cli/processCommands.js +1 -1
- package/dist/cli/streamedJsonOutput.js +56 -0
- package/dist/cli/utilityCommands.js +2 -0
- package/dist/cli/webNetworkCaptureCommands.js +40 -0
- package/dist/cli/webRuntimeCommands.js +8 -8
- package/dist/cli.js +11 -4
- package/dist/cliBrowserScenarioCommands.js +2 -2
- package/dist/cliCommandNames.js +6 -1
- package/dist/cliJsonInput.js +35 -1
- package/dist/cliOutput.js +21 -6
- package/dist/composition/binaryDiagnostics.js +8 -0
- package/dist/composition/evm.js +4 -0
- package/dist/composition/webNetworkCaptures.js +6 -0
- package/dist/config/environment.js +4 -0
- package/dist/config/ghidraStartupTimeout.js +17 -0
- package/dist/config/mcpResponseBudget.js +22 -0
- package/dist/config/parseConfig.js +2 -1
- package/dist/contracts/artifactToolContracts.js +6 -0
- package/dist/contracts/browserCaptureToolInputSchema.js +43 -0
- package/dist/contracts/browserToolContracts.js +4 -3
- package/dist/contracts/enhancedInputs.js +5 -3
- package/dist/contracts/enhancedToolContracts.js +3 -3
- package/dist/contracts/errorSchemas.js +8 -1
- package/dist/contracts/evm/evmToolContracts.js +20 -0
- package/dist/contracts/hopperMemoryContracts.js +2 -5
- package/dist/contracts/investigationExamples.js +2 -2
- package/dist/contracts/javascript/electronToolContracts.js +1 -1
- package/dist/contracts/managed/managedToolContracts.js +8 -6
- package/dist/contracts/native/binaryDiagnosticsToolContracts.js +42 -0
- package/dist/contracts/native/nativeToolContracts.js +21 -3
- package/dist/contracts/officialToolContracts.js +26 -24
- package/dist/contracts/process/processCaptureExample.js +2 -0
- package/dist/contracts/promptContracts.js +3 -3
- package/dist/contracts/sessionLifecycleInputs.js +18 -5
- package/dist/contracts/sessionStatusContract.js +8 -2
- package/dist/contracts/sessionToolContracts.js +8 -3
- package/dist/contracts/sessionToolSchemas.js +8 -4
- package/dist/contracts/toolContractExamples.js +1 -2
- package/dist/contracts/toolContractHelpers.js +4 -1
- package/dist/contracts/toolContracts.js +6 -0
- package/dist/contracts/toolEffects.js +30 -1
- package/dist/contracts/toolOutputSchemaGroups.js +33 -28
- package/dist/contracts/toolOutputSchemaPrimitives.js +19 -1
- package/dist/contracts/toolSchemaMetadata.js +69 -10
- package/dist/contracts/webNetworkCaptureToolContracts.js +24 -0
- package/dist/domain/analysisErrorBase.js +22 -2
- package/dist/domain/analysisErrorCore.js +61 -5
- package/dist/domain/analysisErrorPresentation.js +95 -12
- package/dist/domain/analysisErrorProjection.js +148 -19
- package/dist/domain/analysisSnapshot.js +166 -2
- package/dist/domain/android/androidAnalysis.js +2 -4
- package/dist/domain/android/androidApplication.js +17 -9
- package/dist/domain/apple/appleApplication.js +41 -14
- package/dist/domain/apple/dyldEnvironment.js +73 -0
- package/dist/domain/apple/dyldPaths.js +81 -0
- package/dist/domain/apple/dylibResolution.js +478 -0
- package/dist/domain/apple/dylibResolutionFindings.js +77 -0
- package/dist/domain/apple/interfaceBuilderGraph.js +25 -13
- package/dist/domain/apple/interfaceBuilderKeyedArchive.js +13 -3
- package/dist/domain/apple/keyedArchive.js +9 -1
- package/dist/domain/apple/machoContainer.js +54 -0
- package/dist/domain/apple/plistNumbers.js +76 -0
- package/dist/domain/artifactIdentity.js +29 -0
- package/dist/domain/artifactInventoryEvidence.js +19 -24
- package/dist/domain/artifactPathSyntax.js +1 -1
- package/dist/domain/bridgeCandidateProjection.js +71 -0
- package/dist/domain/browserCompleteness.js +1 -0
- package/dist/domain/browserObservation.js +1 -1
- package/dist/domain/browserObservationError.js +24 -5
- package/dist/domain/browserObservationSchemas.js +13 -0
- package/dist/domain/browserScenarioValues.js +5 -2
- package/dist/domain/bundleComparison.js +3 -2
- package/dist/domain/callPathSchemas.js +1 -1
- package/dist/domain/canonicalDigest.js +13 -1
- package/dist/domain/canonicalJsonDigestSteps.js +133 -0
- package/dist/domain/canonicalOrdering.js +9 -5
- package/dist/domain/changedBehavior.js +9 -9
- package/dist/domain/comparisonSourceEvidence.js +40 -0
- package/dist/domain/comparisonStatus.js +2 -30
- package/dist/domain/configurationErrors.js +1 -1
- package/dist/domain/conformanceTrustGate.js +0 -16
- package/dist/domain/evidence.js +78 -11
- package/dist/domain/evidenceBundle.js +42 -1
- package/dist/domain/evidenceErrors.js +12 -1
- package/dist/domain/evm/evmInterface.js +63 -0
- package/dist/domain/explicitSensitiveFailure.js +108 -0
- package/dist/domain/explicitSensitiveValues.js +10 -0
- package/dist/domain/firmware/firmwareAnalysis.js +10 -4
- package/dist/domain/hopperErrors.js +23 -2
- package/dist/domain/hopperValues.js +51 -8
- package/dist/domain/immutableJson.js +114 -0
- package/dist/domain/inputIssueProjection.js +3 -0
- package/dist/domain/javascript/electronActiveObservation.js +37 -6
- package/dist/domain/javascript/electronStaticAnalysisValues.js +6 -12
- package/dist/domain/javascript/htmlArtifactReferences.js +40 -0
- package/dist/domain/javascript/javascriptApplicationAnalysis.js +71 -23
- package/dist/domain/javascript/javascriptApplicationGraph.js +13 -0
- package/dist/domain/javascript/javascriptAstValues.js +20 -0
- package/dist/domain/javascript/javascriptExportShapeComparison.js +21 -5
- package/dist/domain/javascript/javascriptExportShapeVariants.js +0 -10
- package/dist/domain/javascript/javascriptRecovery.js +3 -8
- package/dist/domain/javascript/javascriptSemanticAnalysis.js +97 -2
- package/dist/domain/javascript/javascriptSemanticCoverage.js +6 -5
- package/dist/domain/javascript/javascriptSemanticDataEffectHelpers.js +9 -17
- package/dist/domain/javascript/javascriptSemanticDataEffects.js +22 -5
- package/dist/domain/javascript/javascriptSemanticGraph.js +34 -5
- package/dist/domain/javascript/javascriptSemanticGraphSchemas.js +1 -0
- package/dist/domain/javascript/javascriptSemanticPrimitives.js +25 -17
- package/dist/domain/javascript/javascriptSemanticQuerySchemas.js +8 -4
- package/dist/domain/javascript/javascriptSemanticResourceLimits.js +77 -0
- package/dist/domain/javascript/javascriptSemanticValues.js +83 -11
- package/dist/domain/javascript/javascriptSourceParser.js +6 -2
- package/dist/domain/javascript/javascriptStaticAnalysis.js +22 -17
- package/dist/domain/javascript/javascriptStaticAnalysisBundler.js +5 -3
- package/dist/domain/javascript/javascriptStaticAnalysisCalls.js +14 -4
- package/dist/domain/javascript/javascriptStaticAnalysisFindings.js +66 -7
- package/dist/domain/javascript/javascriptStaticAnalysisHelpers.js +28 -16
- package/dist/domain/javascript/javascriptStaticAnalysisState.js +3 -2
- package/dist/domain/jsonSerialization.js +109 -0
- package/dist/domain/jsonValue.js +91 -3
- package/dist/domain/localPath.js +8 -0
- package/dist/domain/managed/managedApplicationGraph.js +10 -10
- package/dist/domain/managed/managedInspectionEvidence.js +16 -0
- package/dist/domain/managed/managedMemberComparisonMatch.js +5 -9
- package/dist/domain/managed/managedNativeVerification.js +3 -9
- package/dist/domain/native/binaryLayout.js +357 -0
- package/dist/domain/native/fileOffsetPartialObservation.js +1 -0
- package/dist/domain/native/nativeCallObservation.js +186 -0
- package/dist/domain/native/nativeCallPartialObservation.js +33 -0
- package/dist/domain/native/objcSwiftMetadata.js +0 -39
- package/dist/domain/native/recordedCrash.js +266 -0
- package/dist/domain/native/recordedCrashNoteCoverage.js +73 -0
- package/dist/domain/{processCapture.js → process/processCapture.js} +143 -2
- package/dist/domain/{processCaptureExample.js → process/processCaptureExample.js} +5 -0
- package/dist/domain/process/processCaptureParsing.js +54 -0
- package/dist/domain/{processCaptureValidation.js → process/processCaptureValidation.js} +18 -2
- package/dist/domain/{processComparison.js → process/processComparison.js} +39 -5
- package/dist/domain/{processObservation.js → process/processObservation.js} +1 -1
- package/dist/domain/{processScenario.js → process/processScenario.js} +11 -10
- package/dist/domain/{processTraceSpecification.js → process/processTraceSpecification.js} +1 -1
- package/dist/domain/propertyListKeys.js +1 -1
- package/dist/domain/propertyListXmlText.js +19 -0
- package/dist/domain/providerAdapterError.js +1 -1
- package/dist/domain/providerOperationHealth.js +54 -0
- package/dist/domain/providerSelectionError.js +4 -2
- package/dist/domain/reconstructionVerification.js +9 -46
- package/dist/domain/reconstructionVerificationSchemas.js +3 -3
- package/dist/domain/residualUnknown.js +3 -2
- package/dist/domain/staticRuntimeCorrelation.js +9 -46
- package/dist/domain/webBundleAnalysis.js +20 -8
- package/dist/domain/webBundleAnalyzerInspection.js +13 -8
- package/dist/domain/webBundleAnalyzerResult.js +41 -2
- package/dist/domain/webCaptureDiff.js +1 -0
- package/dist/domain/webNetworkCapture.js +118 -0
- package/dist/domain/webNetworkCaptureCoordinates.js +58 -0
- package/dist/domain/webRuntime.js +19 -5
- package/dist/domain/webSourceLocation.js +1 -0
- package/dist/dotnet/ManagedExceptionRegionValidation.js +41 -0
- package/dist/dotnet/ManagedMemberInspector.js +4 -2
- package/dist/dotnet/ManagedMemberInspectorCore.js +38 -32
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +23 -7
- package/dist/dotnet/ManagedMemberRows.js +14 -3
- package/dist/dotnet/ManagedMetadataHeaps.js +20 -2
- package/dist/dotnet/ManagedMetadataInventory.js +38 -28
- package/dist/dotnet/ManagedMetadataInventoryRows.js +24 -10
- package/dist/dotnet/ManagedMethodBodyReader.js +7 -1
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +15 -3
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +3 -1
- package/dist/dotnet/ManagedPeReader.js +11 -0
- package/dist/evm/EvmBytecodeCarrier.js +21 -0
- package/dist/evm/EvmWorkerLimits.js +40 -0
- package/dist/evm/EvmoleFailures.js +126 -0
- package/dist/evm/EvmoleInterfaceAdapter.js +53 -0
- package/dist/evm/EvmoleInterfaceProvider.js +273 -0
- package/dist/evm/EvmoleInterfaceWorker.js +87 -0
- package/dist/evm/EvmoleRelease.js +16 -0
- package/dist/firmware/FirmwareCommand.js +1 -0
- package/dist/firmware/FirmwareFiles.js +1 -1
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraAnalysisProfile.js +5 -0
- package/dist/ghidra/GhidraClient.js +47 -14
- package/dist/ghidra/GhidraDiagnostics.js +7 -7
- package/dist/ghidra/GhidraFunctionValues.js +10 -7
- package/dist/ghidra/GhidraInstallation.js +18 -21
- package/dist/ghidra/GhidraInventoryValues.js +14 -4
- package/dist/ghidra/GhidraJavaLaunch.js +62 -0
- package/dist/ghidra/GhidraLauncher.js +34 -16
- package/dist/ghidra/GhidraProvider.js +2 -2
- package/dist/ghidra/GhidraProviderCapabilities.js +15 -3
- package/dist/ghidra/GhidraProviderClient.js +23 -12
- package/dist/ghidra/GhidraSessionError.js +11 -7
- package/dist/ghidra/GhidraTargetSnapshot.js +47 -12
- package/dist/ghidra/GhidraTransport.js +20 -0
- package/dist/hopper/BridgeLauncher.js +33 -11
- package/dist/hopper/HopperAnalysisProfile.js +62 -4
- package/dist/hopper/HopperCleanup.js +15 -3
- package/dist/hopper/HopperClient.js +222 -14
- package/dist/hopper/HopperFileOffset.js +237 -0
- package/dist/hopper/HopperMachOImage.js +196 -0
- package/dist/hopper/HopperOperationStage.js +6 -0
- package/dist/hopper/HopperProvider.js +63 -9
- package/dist/hopper/HopperProviderCapabilities.js +19 -1
- package/dist/hopper/HopperRegexSearch.js +137 -0
- package/dist/hopper/HopperRegexWorker.js +27 -0
- package/dist/hopper/HopperRequestQueue.js +68 -19
- package/dist/hopper/HopperTargetLease.js +3 -2
- package/dist/hopper/LinuxPrivateDisplayProbe.js +4 -2
- package/dist/inspector/JavaScriptRuntimeScope.js +9 -1
- package/dist/inspector/V8InspectorCaptureProjection.js +8 -3
- package/dist/inspector/V8InspectorProvider.js +47 -11
- package/dist/javascript/recovery/WakaruCommand.js +3 -0
- package/dist/javascript/sourceMaps/DecodedSourceMap.js +47 -0
- package/dist/javascript/sourceMaps/SourceMapCommand.js +17 -0
- package/dist/javascript/sourceMaps/SourceMapFormat.js +79 -31
- package/dist/javascript/sourceMaps/TraceSourceMap.js +14 -28
- package/dist/mcpDoctor.js +62 -2
- package/dist/native/AppleDispatchCoverage.js +47 -6
- package/dist/native/AppleDispatchDecodeFacts.js +6 -0
- package/dist/native/AppleDispatchMetadata.js +6 -3
- package/dist/native/AppleMachoFixups.js +48 -24
- package/dist/native/AppleMachoSelection.js +32 -16
- package/dist/native/AppleObjcCategories.js +6 -2
- package/dist/native/AppleObjcDispatchFacets.js +5 -2
- package/dist/native/AppleObjcProperties.js +2 -1
- package/dist/native/AppleSwiftDispatchFacets.js +27 -21
- package/dist/native/AppleSwiftVtables.js +21 -15
- package/dist/native/CommandRunner.js +82 -84
- package/dist/native/LldbCallTracer.js +541 -0
- package/dist/native/LldbRetainedObservations.js +178 -0
- package/dist/native/NativeCallObservation.js +194 -0
- package/dist/native/NativeMacOSProvider.js +117 -20
- package/dist/native/NativeMacOSProviderMetadata.js +8 -3
- package/dist/native/SignatureTargetBinding.js +155 -0
- package/dist/native/parsers/lipo.js +71 -1
- package/dist/native/pwndbg/PwndbgCoreContext.js +180 -0
- package/dist/native/pwntools/PwntoolsDecoder.js +203 -0
- package/dist/native/pwntools/PwntoolsFailures.js +180 -0
- package/dist/native/pwntools/PwntoolsLayoutProvider.js +36 -0
- package/dist/native/pwntools/PwntoolsRecordedCrashProvider.js +75 -0
- package/dist/native/pwntools/PwntoolsRelease.js +19 -0
- package/dist/native/pwntools/PwntoolsResourceLimits.js +76 -0
- package/dist/native/pwntools/RecordedCrashSourceBindings.js +46 -0
- package/dist/native/pwntools/RecordedCrashStructureBindings.js +103 -0
- package/dist/process/DarwinProcessRunTokenReader.js +293 -0
- package/dist/process/ExecFileOutput.js +20 -0
- package/dist/process/OwnedCommand.js +118 -0
- package/dist/process/ProcessOwnership.js +431 -51
- package/dist/process/ProcessOwnershipObservation.js +209 -27
- package/dist/process/ProviderProcess.js +68 -10
- package/dist/{application → process/capture}/ProcessCaptureCapability.js +15 -0
- package/dist/{application → process/capture}/ProcessCaptureError.js +18 -2
- package/dist/process/capture/ProcessCaptureLifecycle.js +681 -0
- package/dist/{application → process/capture}/ProcessHarness.js +195 -29
- package/dist/{application → process/capture}/ProcessSampling.js +2 -2
- package/dist/server/EvidenceMcpServer.js +146 -0
- package/dist/server/createServer.js +37 -8
- package/dist/server/promptCompletion.js +10 -3
- package/dist/server/registerAndroidTools.js +2 -4
- package/dist/server/registerApplicationTools/helpers.js +2 -4
- package/dist/server/registerArtifactComparisonTool.js +11 -7
- package/dist/server/registerBinaryDiagnosticsTools.js +15 -0
- package/dist/server/registerBrowserScenarioTool.js +2 -4
- package/dist/server/registerBrowserTools.js +2 -4
- package/dist/server/registerBundleComparisonTool.js +2 -3
- package/dist/server/registerCloseLifecycleTool.js +8 -18
- package/dist/server/registerElectronTools.js +2 -4
- package/dist/server/registerEnhancedTools.js +18 -59
- package/dist/server/registerEvidenceTools.js +3 -5
- package/dist/server/registerEvmTools.js +15 -0
- package/dist/server/registerFirmwareTools.js +2 -4
- package/dist/server/registerFunctionComparisonTool.js +10 -6
- package/dist/server/registerInvestigationTools.js +7 -7
- package/dist/server/registerJavaScriptRecoveryTool.js +2 -4
- package/dist/server/registerJavaScriptRuntimeObservationTools.js +2 -4
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +2 -4
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +2 -4
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +2 -4
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +2 -4
- package/dist/server/registerOfficialTools.js +2 -4
- package/dist/server/registerProcessComparisonTool.js +72 -46
- package/dist/server/registerRecordedCrashTools.js +15 -0
- package/dist/server/registerSessionRecordTools.js +5 -6
- package/dist/server/registerSessionStatusTool.js +17 -3
- package/dist/server/registerSessionTools.js +13 -5
- package/dist/server/registerWebModuleTool.js +2 -4
- package/dist/server/registerWebNetworkCaptureTool.js +26 -0
- package/dist/server/registerWebRuntimeTools.js +3 -7
- package/dist/server/registerWebScriptTool.js +2 -4
- package/dist/server/registerWebSourceLocationTool.js +2 -4
- package/dist/server/runDerivedOperation.js +15 -3
- package/dist/server/sessionAvailabilityPolicy.js +3 -1
- package/dist/server/sessionToolPolicies.js +1 -1
- package/dist/server/toolRegistrationOptions.js +2 -2
- package/dist/server/toolResult.js +63 -11
- package/dist/server/toolResultEncoding.js +33 -0
- package/install.sh +1 -1
- package/native/windows/build/manifest.json +2 -2
- package/native/windows/build/rea-windows-x64.node +0 -0
- package/package.json +42 -9
- package/scripts/electron-active-hook-boundaries.cjs +18 -20
- package/scripts/electron-active-hook.cjs +241 -37
- package/scripts/rea.mjs +11 -3
- package/skills/reverse-engineer-anything/SKILL.md +32 -4
- package/skills/reverse-engineer-anything/references/javascript-applications.md +8 -1
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +29 -0
- package/third_party/README.md +60 -0
- package/third_party/evmole/LICENSE +21 -0
- package/third_party/evmole/README.md +22 -0
- package/third_party/pwndbg/LICENSE.md +21 -0
- package/third_party/pwndbg/README.md +23 -0
- package/third_party/pwntools/README.md +40 -0
- package/dist/application/AuthorizedArtifactInventory.js +0 -7
- package/dist/application/ProcessCaptureLifecycle.js +0 -299
- package/dist/application/StoreFileLock.js +0 -124
- package/dist/contracts/processCaptureExample.js +0 -2
- package/dist/domain/bytecodeProvider.js +0 -178
- package/dist/domain/customProtocolCapture.js +0 -137
- package/dist/domain/eventProcessTree.js +0 -225
- package/dist/domain/mobileApplicationInvestigation.js +0 -159
- package/dist/domain/packageAnalysis.js +0 -123
- package/dist/domain/peInspection.js +0 -197
- package/dist/domain/processCaptureParsing.js +0 -21
- package/dist/domain/protocolCapture.js +0 -217
- package/dist/domain/runtimeIdentification.js +0 -212
- package/dist/generatedMcpToolCatalog.js +0 -37
- package/dist/ghidra/GhidraDefaults.js +0 -2
- /package/dist/application/{ArtifactExtractionDestination.js → artifacts/ArtifactExtractionDestination.js} +0 -0
- /package/dist/{application/ArtifactInventory → artifacts/inventory}/policy.js +0 -0
- /package/dist/{application/ArtifactInventory → artifacts/inventory}/types.js +0 -0
- /package/dist/domain/{processEvidenceProvider.js → process/processEvidenceProvider.js} +0 -0
- /package/dist/domain/{processTraceComparison.js → process/processTraceComparison.js} +0 -0
- /package/dist/domain/{processTraceDimensionProjection.js → process/processTraceDimensionProjection.js} +0 -0
- /package/dist/domain/{processTraceEvaluation.js → process/processTraceEvaluation.js} +0 -0
- /package/dist/{application → process/capture}/FilesystemSnapshot.js +0 -0
- /package/dist/{application → process/capture}/ProcessCaptureEnvironment.js +0 -0
- /package/dist/{application → process/capture}/ProcessCaptureJournal.js +0 -0
- /package/dist/{application → process/capture}/ProcessFilesystemEffects.js +0 -0
- /package/dist/{application → process/capture}/ProcessNormalization.js +0 -0
- /package/dist/{application → process/capture}/ProcessScenarioRuntimeValidation.js +0 -0
- /package/dist/{application → process/capture}/ProcessTimer.js +0 -0
- /package/dist/{application → process/capture}/TerminalRenderer.js +0 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
|
|
2
2
|
import { isDeepStrictEqual } from "node:util";
|
|
3
|
-
import { applyEdits, modify, parse as parseJsonc, printParseErrorCode, } from "jsonc-parser";
|
|
3
|
+
import { applyEdits, findNodeAtLocation, modify, parse as parseJsonc, parseTree, printParseErrorCode, } from "jsonc-parser";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
+
import { PRODUCT_IDENTITY } from "../identity.js";
|
|
5
6
|
const objectSchema = z.record(z.string(), z.unknown());
|
|
6
7
|
/** Compare parsed configuration values without depending on parser prototypes. */
|
|
7
8
|
export const clientConfigurationValuesEqual = (left, right) => isDeepStrictEqual(normalizeConfigurationValue(left), normalizeConfigurationValue(right));
|
|
@@ -18,6 +19,7 @@ const normalizeConfigurationValue = (value) => {
|
|
|
18
19
|
export const clientConfigurationServersKey = (format) => {
|
|
19
20
|
switch (format) {
|
|
20
21
|
case "toml":
|
|
22
|
+
case "grok":
|
|
21
23
|
return "mcp_servers";
|
|
22
24
|
case "opencode":
|
|
23
25
|
return "mcp";
|
|
@@ -27,9 +29,18 @@ export const clientConfigurationServersKey = (format) => {
|
|
|
27
29
|
return "mcpServers";
|
|
28
30
|
}
|
|
29
31
|
};
|
|
32
|
+
/**
|
|
33
|
+
* Whether raw configuration text holds no settings to preserve. Some clients
|
|
34
|
+
* create a zero-byte config file before any server is added.
|
|
35
|
+
*/
|
|
36
|
+
const isEmptyClientConfigurationText = (text) => text.replace(/^\uFEFF/, "").trim() === "";
|
|
30
37
|
const parseDocument = (text, format) => {
|
|
31
|
-
if (format === "toml")
|
|
38
|
+
if (format === "toml" || format === "grok")
|
|
32
39
|
return objectSchema.parse(parseToml(text));
|
|
40
|
+
// An empty file, which some clients create before any server is added,
|
|
41
|
+
// holds no settings to preserve.
|
|
42
|
+
if (isEmptyClientConfigurationText(text))
|
|
43
|
+
return {};
|
|
33
44
|
const errors = [];
|
|
34
45
|
// Accept a UTF-8 BOM without shifting diagnostics or editing the original text.
|
|
35
46
|
const jsonText = text.startsWith("\uFEFF") ? ` ${text.slice(1)}` : text;
|
|
@@ -101,16 +112,870 @@ const valueAt = (document, path) => {
|
|
|
101
112
|
}
|
|
102
113
|
return current;
|
|
103
114
|
};
|
|
115
|
+
const TOML_BASIC_ESCAPES = {
|
|
116
|
+
b: "\b",
|
|
117
|
+
t: "\t",
|
|
118
|
+
n: "\n",
|
|
119
|
+
f: "\f",
|
|
120
|
+
r: "\r",
|
|
121
|
+
e: "\u001b",
|
|
122
|
+
'"': '"',
|
|
123
|
+
"\\": "\\",
|
|
124
|
+
};
|
|
125
|
+
const skipHorizontalSpace = (line, index) => {
|
|
126
|
+
let next = index;
|
|
127
|
+
while (line[next] === " " || line[next] === "\t")
|
|
128
|
+
next += 1;
|
|
129
|
+
return next;
|
|
130
|
+
};
|
|
131
|
+
const decodeBasicEscape = (line, slash) => {
|
|
132
|
+
const escape = line[slash + 1];
|
|
133
|
+
if (escape === undefined)
|
|
134
|
+
return undefined;
|
|
135
|
+
const simple = TOML_BASIC_ESCAPES[escape];
|
|
136
|
+
if (simple !== undefined)
|
|
137
|
+
return { value: simple, next: slash + 2 };
|
|
138
|
+
// smol-toml accepts `\xHH` even though TOML 1.0 does not.
|
|
139
|
+
if (escape === "x") {
|
|
140
|
+
const hex = line.slice(slash + 2, slash + 4);
|
|
141
|
+
if (!/^[0-9A-Fa-f]{2}$/u.test(hex))
|
|
142
|
+
return undefined;
|
|
143
|
+
return {
|
|
144
|
+
value: String.fromCodePoint(Number.parseInt(hex, 16)),
|
|
145
|
+
next: slash + 4,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
if (escape !== "u" && escape !== "U")
|
|
149
|
+
return undefined;
|
|
150
|
+
const length = escape === "u" ? 4 : 8;
|
|
151
|
+
const hex = line.slice(slash + 2, slash + 2 + length);
|
|
152
|
+
if (!new RegExp(`^[0-9A-Fa-f]{${String(length)}}$`, "u").test(hex))
|
|
153
|
+
return undefined;
|
|
154
|
+
const code = Number.parseInt(hex, 16);
|
|
155
|
+
if (code > 0x10ffff || (code >= 0xd800 && code <= 0xdfff))
|
|
156
|
+
return undefined;
|
|
157
|
+
return { value: String.fromCodePoint(code), next: slash + 2 + length };
|
|
158
|
+
};
|
|
159
|
+
/** Read one single-line quoted key. Multiline quotes are not a header key. */
|
|
160
|
+
const parseQuotedKey = (line, start) => {
|
|
161
|
+
const quote = line[start];
|
|
162
|
+
if ((quote !== '"' && quote !== "'") ||
|
|
163
|
+
line.startsWith(quote === '"' ? '"""' : "'''", start))
|
|
164
|
+
return undefined;
|
|
165
|
+
if (quote === "'") {
|
|
166
|
+
const end = line.indexOf("'", start + 1);
|
|
167
|
+
if (end < 0 || line.slice(start + 1, end).includes("\n"))
|
|
168
|
+
return undefined;
|
|
169
|
+
return { value: line.slice(start + 1, end), next: end + 1 };
|
|
170
|
+
}
|
|
171
|
+
let value = "";
|
|
172
|
+
let index = start + 1;
|
|
173
|
+
while (index < line.length) {
|
|
174
|
+
const char = line[index];
|
|
175
|
+
if (char === "\n" || char === "\r")
|
|
176
|
+
return undefined;
|
|
177
|
+
if (char === '"')
|
|
178
|
+
return { value, next: index + 1 };
|
|
179
|
+
if (char !== "\\") {
|
|
180
|
+
value += char ?? "";
|
|
181
|
+
index += 1;
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
const decoded = decodeBasicEscape(line, index);
|
|
185
|
+
if (decoded === undefined)
|
|
186
|
+
return undefined;
|
|
187
|
+
value += decoded.value;
|
|
188
|
+
index = decoded.next;
|
|
189
|
+
}
|
|
190
|
+
return undefined;
|
|
191
|
+
};
|
|
192
|
+
const parseBareKey = (line, start) => {
|
|
193
|
+
let index = start;
|
|
194
|
+
while (/[A-Za-z0-9_-]/u.test(line[index] ?? ""))
|
|
195
|
+
index += 1;
|
|
196
|
+
if (index === start)
|
|
197
|
+
return undefined;
|
|
198
|
+
return { value: line.slice(start, index), next: index };
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* Parse a table header. Quoted segments stay one key, so `mcp_servers."rea.env"`
|
|
202
|
+
* is not the dotted path `mcp_servers.rea.env`.
|
|
203
|
+
*/
|
|
204
|
+
const parseTomlTableHeader = (line) => {
|
|
205
|
+
let index = skipHorizontalSpace(line, 0);
|
|
206
|
+
const array = line.startsWith("[[", index);
|
|
207
|
+
if (!array && line[index] !== "[")
|
|
208
|
+
return undefined;
|
|
209
|
+
index += array ? 2 : 1;
|
|
210
|
+
const path = [];
|
|
211
|
+
for (;;) {
|
|
212
|
+
index = skipHorizontalSpace(line, index);
|
|
213
|
+
const key = line[index] === '"' || line[index] === "'"
|
|
214
|
+
? parseQuotedKey(line, index)
|
|
215
|
+
: parseBareKey(line, index);
|
|
216
|
+
if (key === undefined)
|
|
217
|
+
return undefined;
|
|
218
|
+
path.push(key.value);
|
|
219
|
+
index = skipHorizontalSpace(line, key.next);
|
|
220
|
+
if (line[index] !== ".")
|
|
221
|
+
break;
|
|
222
|
+
index += 1;
|
|
223
|
+
}
|
|
224
|
+
const close = array ? "]]" : "]";
|
|
225
|
+
if (!line.startsWith(close, index))
|
|
226
|
+
return undefined;
|
|
227
|
+
index = skipHorizontalSpace(line, index + close.length);
|
|
228
|
+
if (index < line.length && line[index] !== "#")
|
|
229
|
+
return undefined;
|
|
230
|
+
return { path };
|
|
231
|
+
};
|
|
232
|
+
/**
|
|
233
|
+
* String state after one physical line, starting at `start`. A multiline
|
|
234
|
+
* closer does not end the scan: `""", """` closes one string and opens another.
|
|
235
|
+
*/
|
|
236
|
+
const tomlStringModeAfter = (line, mode, start = 0) => {
|
|
237
|
+
if (mode === "ml-basic" || mode === "ml-literal") {
|
|
238
|
+
const delimiter = mode === "ml-basic" ? '"""' : "'''";
|
|
239
|
+
const closed = closeMultiline(line, start, delimiter, mode === "ml-basic");
|
|
240
|
+
if (closed === undefined)
|
|
241
|
+
return mode;
|
|
242
|
+
return tomlStringModeAfter(line, "none", closed);
|
|
243
|
+
}
|
|
244
|
+
let index = start;
|
|
245
|
+
while (index < line.length) {
|
|
246
|
+
if (line[index] === "#")
|
|
247
|
+
return "none";
|
|
248
|
+
if (line.startsWith('"""', index)) {
|
|
249
|
+
const closed = closeMultiline(line, index + 3, '"""', true);
|
|
250
|
+
if (closed === undefined)
|
|
251
|
+
return "ml-basic";
|
|
252
|
+
index = closed;
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
if (line.startsWith("'''", index)) {
|
|
256
|
+
const closed = closeMultiline(line, index + 3, "'''", false);
|
|
257
|
+
if (closed === undefined)
|
|
258
|
+
return "ml-literal";
|
|
259
|
+
index = closed;
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
const quote = line[index];
|
|
263
|
+
if (quote === '"' || quote === "'") {
|
|
264
|
+
const quoted = parseQuotedKey(line, index);
|
|
265
|
+
if (quoted === undefined)
|
|
266
|
+
return "none";
|
|
267
|
+
index = quoted.next;
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
index += 1;
|
|
271
|
+
}
|
|
272
|
+
return "none";
|
|
273
|
+
};
|
|
274
|
+
/** Index after a multiline delimiter, or undefined when this line does not close it. */
|
|
275
|
+
const closeMultiline = (line, start, delimiter, escapes) => {
|
|
276
|
+
let index = start;
|
|
277
|
+
while (index < line.length) {
|
|
278
|
+
if (escapes && line[index] === "\\") {
|
|
279
|
+
if (line[index + 1] === undefined)
|
|
280
|
+
return undefined;
|
|
281
|
+
index += 2;
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
if (line.startsWith(delimiter, index)) {
|
|
285
|
+
// One or two quotes before the closer belong to the string: """keep""""
|
|
286
|
+
let end = index + delimiter.length;
|
|
287
|
+
const quote = delimiter[0];
|
|
288
|
+
let extra = 0;
|
|
289
|
+
while (extra < 2 && line[end] === quote) {
|
|
290
|
+
extra += 1;
|
|
291
|
+
end += 1;
|
|
292
|
+
}
|
|
293
|
+
return end;
|
|
294
|
+
}
|
|
295
|
+
index += 1;
|
|
296
|
+
}
|
|
297
|
+
return undefined;
|
|
298
|
+
};
|
|
299
|
+
const isBlankOrComment = (line) => {
|
|
300
|
+
const trimmed = line.trimStart();
|
|
301
|
+
return trimmed === "" || trimmed.startsWith("#");
|
|
302
|
+
};
|
|
303
|
+
const looksLikeTomlHeader = (line) => line.trimStart().startsWith("[");
|
|
304
|
+
/** `mcp_servers.<server>` and tables nested under it, compared by key segment. */
|
|
305
|
+
const isGrokServerTable = (path, serverKey) => path[0] === "mcp_servers" && path[1] === serverKey;
|
|
306
|
+
const parseKeyPath = (text, start) => {
|
|
307
|
+
const segments = [];
|
|
308
|
+
let index = start;
|
|
309
|
+
for (;;) {
|
|
310
|
+
index = skipHorizontalSpace(text, index);
|
|
311
|
+
const current = text[index];
|
|
312
|
+
if (current === undefined || current === "\n" || current === "\r")
|
|
313
|
+
return undefined;
|
|
314
|
+
const key = current === '"' || current === "'"
|
|
315
|
+
? parseQuotedKey(text, index)
|
|
316
|
+
: parseBareKey(text, index);
|
|
317
|
+
if (key === undefined)
|
|
318
|
+
return undefined;
|
|
319
|
+
segments.push(key.value);
|
|
320
|
+
index = skipHorizontalSpace(text, key.next);
|
|
321
|
+
if (text[index] !== ".")
|
|
322
|
+
return { segments, next: index };
|
|
323
|
+
index += 1;
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
const parseAssignment = (line) => {
|
|
327
|
+
const key = parseKeyPath(line, 0);
|
|
328
|
+
if (key === undefined)
|
|
329
|
+
return undefined;
|
|
330
|
+
const equals = skipHorizontalSpace(line, key.next);
|
|
331
|
+
if (line[equals] !== "=")
|
|
332
|
+
return undefined;
|
|
333
|
+
return { segments: key.segments, equals };
|
|
334
|
+
};
|
|
335
|
+
const skipWsAndComments = (text, start) => {
|
|
336
|
+
let index = start;
|
|
337
|
+
while (index < text.length) {
|
|
338
|
+
const char = text[index];
|
|
339
|
+
if (char === " " || char === "\t" || char === "\n" || char === "\r") {
|
|
340
|
+
index += 1;
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
if (char === "#") {
|
|
344
|
+
while (index < text.length && text[index] !== "\n")
|
|
345
|
+
index += 1;
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
return index;
|
|
349
|
+
}
|
|
350
|
+
return index;
|
|
351
|
+
};
|
|
352
|
+
/** Index after one TOML value. Containers and multiline strings may cross lines. */
|
|
353
|
+
const endOfTomlValue = (text, start) => {
|
|
354
|
+
const index = skipWsAndComments(text, start);
|
|
355
|
+
if (index >= text.length)
|
|
356
|
+
return index;
|
|
357
|
+
if (text.startsWith('"""', index)) {
|
|
358
|
+
const closed = closeMultiline(text, index + 3, '"""', true);
|
|
359
|
+
return closed ?? text.length;
|
|
360
|
+
}
|
|
361
|
+
if (text.startsWith("'''", index)) {
|
|
362
|
+
const closed = closeMultiline(text, index + 3, "'''", false);
|
|
363
|
+
return closed ?? text.length;
|
|
364
|
+
}
|
|
365
|
+
const quote = text[index];
|
|
366
|
+
if (quote === '"' || quote === "'") {
|
|
367
|
+
const quoted = parseQuotedKey(text, index);
|
|
368
|
+
return quoted === undefined ? text.length : quoted.next;
|
|
369
|
+
}
|
|
370
|
+
if (quote === "{" || quote === "[")
|
|
371
|
+
return endOfContainer(text, index);
|
|
372
|
+
let cursor = index;
|
|
373
|
+
while (cursor < text.length) {
|
|
374
|
+
const char = text[cursor];
|
|
375
|
+
if (char === "\n" ||
|
|
376
|
+
char === "#" ||
|
|
377
|
+
char === "," ||
|
|
378
|
+
char === "}" ||
|
|
379
|
+
char === "]")
|
|
380
|
+
break;
|
|
381
|
+
cursor += 1;
|
|
382
|
+
}
|
|
383
|
+
return cursor;
|
|
384
|
+
};
|
|
385
|
+
const endOfContainer = (text, open) => {
|
|
386
|
+
const closers = [text[open] === "{" ? "}" : "]"];
|
|
387
|
+
let index = open + 1;
|
|
388
|
+
while (index < text.length && closers.length > 0) {
|
|
389
|
+
if (text.startsWith('"""', index)) {
|
|
390
|
+
const closed = closeMultiline(text, index + 3, '"""', true);
|
|
391
|
+
if (closed === undefined)
|
|
392
|
+
return text.length;
|
|
393
|
+
index = closed;
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
if (text.startsWith("'''", index)) {
|
|
397
|
+
const closed = closeMultiline(text, index + 3, "'''", false);
|
|
398
|
+
if (closed === undefined)
|
|
399
|
+
return text.length;
|
|
400
|
+
index = closed;
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
const quote = text[index];
|
|
404
|
+
if (quote === '"' || quote === "'") {
|
|
405
|
+
const quoted = parseQuotedKey(text, index);
|
|
406
|
+
if (quoted === undefined)
|
|
407
|
+
return text.length;
|
|
408
|
+
index = quoted.next;
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
if (quote === "#") {
|
|
412
|
+
while (index < text.length && text[index] !== "\n")
|
|
413
|
+
index += 1;
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
if (quote === "{" || quote === "[") {
|
|
417
|
+
closers.push(quote === "{" ? "}" : "]");
|
|
418
|
+
index += 1;
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
if (quote === closers[closers.length - 1]) {
|
|
422
|
+
closers.pop();
|
|
423
|
+
index += 1;
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
index += 1;
|
|
427
|
+
}
|
|
428
|
+
return index;
|
|
429
|
+
};
|
|
430
|
+
/** TOML basic string. JSON leaves U+007F raw, which TOML rejects. */
|
|
431
|
+
const tomlBasicString = (value) => JSON.stringify(value).replaceAll("\u007f", "\\u007f");
|
|
432
|
+
const tomlInlineKey = (key) => /^[A-Za-z0-9_-]+$/u.test(key) ? key : tomlBasicString(key);
|
|
433
|
+
const tomlInlineValue = (value) => {
|
|
434
|
+
if (typeof value === "string")
|
|
435
|
+
return tomlBasicString(value);
|
|
436
|
+
if (typeof value === "boolean")
|
|
437
|
+
return value ? "true" : "false";
|
|
438
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
439
|
+
return String(value);
|
|
440
|
+
if (Array.isArray(value))
|
|
441
|
+
return `[${value.map((item) => tomlInlineValue(item)).join(", ")}]`;
|
|
442
|
+
if (typeof value === "object" && value !== null) {
|
|
443
|
+
const body = Object.entries(value)
|
|
444
|
+
.map(([key, nested]) => `${tomlInlineKey(key)} = ${tomlInlineValue(nested)}`)
|
|
445
|
+
.join(", ");
|
|
446
|
+
return `{ ${body} }`;
|
|
447
|
+
}
|
|
448
|
+
return '""';
|
|
449
|
+
};
|
|
450
|
+
const readTrivia = (text, start, limit) => {
|
|
451
|
+
let index = start;
|
|
452
|
+
while (index < limit) {
|
|
453
|
+
const char = text[index];
|
|
454
|
+
if (char === " " ||
|
|
455
|
+
char === "\t" ||
|
|
456
|
+
char === "\n" ||
|
|
457
|
+
char === "\r" ||
|
|
458
|
+
char === ",") {
|
|
459
|
+
index += 1;
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
if (char === "#") {
|
|
463
|
+
while (index < limit && text[index] !== "\n")
|
|
464
|
+
index += 1;
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
break;
|
|
468
|
+
}
|
|
469
|
+
return { text: text.slice(start, index), next: index };
|
|
470
|
+
};
|
|
471
|
+
const commasOutsideComments = (trivia) => trivia
|
|
472
|
+
.split("\n")
|
|
473
|
+
.map((part) => {
|
|
474
|
+
const comment = part.indexOf("#");
|
|
475
|
+
if (comment < 0)
|
|
476
|
+
return part.replaceAll(",", "");
|
|
477
|
+
return `${part.slice(0, comment).replaceAll(",", "")}${part.slice(comment)}`;
|
|
478
|
+
})
|
|
479
|
+
.join("\n");
|
|
480
|
+
const hasSeparatorComma = (trivia) => trivia.split("\n").some((part) => {
|
|
481
|
+
const comment = part.indexOf("#");
|
|
482
|
+
const code = comment < 0 ? part : part.slice(0, comment);
|
|
483
|
+
return code.includes(",");
|
|
484
|
+
});
|
|
485
|
+
/**
|
|
486
|
+
* Replace or remove `serverKey` inside one `{ ... }` table. A closed inline
|
|
487
|
+
* table cannot later grow a `[mcp_servers.rea]` header.
|
|
488
|
+
*/
|
|
489
|
+
const editGrokInlineTable = (table, serverKey, entry) => {
|
|
490
|
+
if (!table.startsWith("{"))
|
|
491
|
+
return undefined;
|
|
492
|
+
const end = endOfContainer(table, 0);
|
|
493
|
+
if (table[end - 1] !== "}")
|
|
494
|
+
return undefined;
|
|
495
|
+
const pairs = [];
|
|
496
|
+
let index = 1;
|
|
497
|
+
let trailing = "";
|
|
498
|
+
while (index < end - 1) {
|
|
499
|
+
const trivia = readTrivia(table, index, end - 1);
|
|
500
|
+
if (trivia.next >= end - 1) {
|
|
501
|
+
trailing = trivia.text;
|
|
502
|
+
break;
|
|
503
|
+
}
|
|
504
|
+
const key = parseKeyPath(table, trivia.next);
|
|
505
|
+
if (key === undefined)
|
|
506
|
+
return undefined;
|
|
507
|
+
const equals = skipWsAndComments(table, key.next);
|
|
508
|
+
if (table[equals] !== "=")
|
|
509
|
+
return undefined;
|
|
510
|
+
const valueEnd = endOfTomlValue(table, equals + 1);
|
|
511
|
+
if (valueEnd > end - 1)
|
|
512
|
+
return undefined;
|
|
513
|
+
pairs.push({
|
|
514
|
+
leading: trivia.text,
|
|
515
|
+
text: table.slice(trivia.next, valueEnd),
|
|
516
|
+
drop: key.segments[0] === serverKey,
|
|
517
|
+
});
|
|
518
|
+
index = valueEnd;
|
|
519
|
+
}
|
|
520
|
+
const insertion = entry === undefined
|
|
521
|
+
? undefined
|
|
522
|
+
: `${tomlInlineKey(serverKey)} = ${tomlInlineValue(entry)}`;
|
|
523
|
+
if (insertion === undefined && pairs.every((pair) => !pair.drop))
|
|
524
|
+
return table;
|
|
525
|
+
return rebuildInlineTable(pairs, trailing, insertion);
|
|
526
|
+
};
|
|
527
|
+
const rebuildInlineTable = (pairs, trailing, insertion) => rebuildDelimitedEntries(pairs, trailing, insertion, "{", "}");
|
|
528
|
+
/**
|
|
529
|
+
* Rebuild `{ ... }` or `[ ... ]` after dropping entries. An empty container
|
|
530
|
+
* keeps comment trivia; a table with no comments stays `{}`.
|
|
531
|
+
*/
|
|
532
|
+
const rebuildDelimitedEntries = (pairs, trailing, insertion, open, close) => {
|
|
533
|
+
const parts = [open];
|
|
534
|
+
let emitted = false;
|
|
535
|
+
// A comma already emitted in a dropped pair's comment trivia.
|
|
536
|
+
let separatorPending = false;
|
|
537
|
+
for (const pair of pairs) {
|
|
538
|
+
if (pair.drop) {
|
|
539
|
+
if (!pair.leading.includes("#"))
|
|
540
|
+
continue;
|
|
541
|
+
// A separator already emitted must not be repeated for the next field.
|
|
542
|
+
const dropped = !emitted || separatorPending
|
|
543
|
+
? commasOutsideComments(pair.leading)
|
|
544
|
+
: pair.leading;
|
|
545
|
+
parts.push(dropped);
|
|
546
|
+
separatorPending = separatorPending || hasSeparatorComma(dropped);
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
const kept = emitted ? pair.leading : commasOutsideComments(pair.leading);
|
|
550
|
+
parts.push(separatorPending ? commasOutsideComments(kept) : kept);
|
|
551
|
+
if (emitted && !separatorPending && !pair.leading.includes(","))
|
|
552
|
+
parts.push(", ");
|
|
553
|
+
separatorPending = false;
|
|
554
|
+
parts.push(pair.text);
|
|
555
|
+
emitted = true;
|
|
556
|
+
}
|
|
557
|
+
if (insertion !== undefined) {
|
|
558
|
+
if (!(emitted && separatorPending))
|
|
559
|
+
parts.push(emitted ? ", " : " ");
|
|
560
|
+
parts.push(insertion);
|
|
561
|
+
emitted = true;
|
|
562
|
+
}
|
|
563
|
+
if (!emitted) {
|
|
564
|
+
const retained = `${parts.slice(1).join("")}${commasOutsideComments(trailing)}`;
|
|
565
|
+
return retained.includes("#")
|
|
566
|
+
? `${open}${retained}${close}`
|
|
567
|
+
: `${open}${close}`;
|
|
568
|
+
}
|
|
569
|
+
const tail = commasOutsideComments(trailing);
|
|
570
|
+
parts.push(tail);
|
|
571
|
+
if (tail === "" && open === "{")
|
|
572
|
+
parts.push(" ");
|
|
573
|
+
parts.push(close);
|
|
574
|
+
return parts.join("");
|
|
575
|
+
};
|
|
576
|
+
/**
|
|
577
|
+
* Decoded TOML string, or undefined when the token is not a string.
|
|
578
|
+
* The document parser accepts multiline basic and literal strings.
|
|
579
|
+
*/
|
|
580
|
+
const tomlStringValue = (text) => {
|
|
581
|
+
try {
|
|
582
|
+
const value = parseToml(`value = ${text}`)["value"];
|
|
583
|
+
return typeof value === "string" ? value : undefined;
|
|
584
|
+
}
|
|
585
|
+
catch (cause) {
|
|
586
|
+
void cause;
|
|
587
|
+
return undefined;
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
/**
|
|
591
|
+
* Array text with `serverKey` removed. `""` means the assignment itself can
|
|
592
|
+
* be deleted. Undefined when the array cannot be edited safely.
|
|
593
|
+
*/
|
|
594
|
+
const tomlArrayWithoutString = (array, serverKey) => {
|
|
595
|
+
if (!array.startsWith("["))
|
|
596
|
+
return undefined;
|
|
597
|
+
const end = endOfContainer(array, 0);
|
|
598
|
+
if (end !== array.length || array[end - 1] !== "]")
|
|
599
|
+
return undefined;
|
|
600
|
+
const pairs = [];
|
|
601
|
+
let index = 1;
|
|
602
|
+
let trailing = "";
|
|
603
|
+
while (index < end - 1) {
|
|
604
|
+
const trivia = readTrivia(array, index, end - 1);
|
|
605
|
+
if (trivia.next >= end - 1) {
|
|
606
|
+
trailing = trivia.text;
|
|
607
|
+
break;
|
|
608
|
+
}
|
|
609
|
+
const valueEnd = endOfTomlValue(array, trivia.next);
|
|
610
|
+
if (valueEnd > end - 1)
|
|
611
|
+
return undefined;
|
|
612
|
+
const text = array.slice(trivia.next, valueEnd);
|
|
613
|
+
pairs.push({
|
|
614
|
+
leading: trivia.text,
|
|
615
|
+
text,
|
|
616
|
+
drop: tomlStringValue(text) === serverKey,
|
|
617
|
+
});
|
|
618
|
+
index = valueEnd;
|
|
619
|
+
}
|
|
620
|
+
if (pairs.every((pair) => !pair.drop))
|
|
621
|
+
return array;
|
|
622
|
+
const rebuilt = rebuildDelimitedEntries(pairs, trailing, undefined, "[", "]");
|
|
623
|
+
return rebuilt === "[]" ? "" : rebuilt;
|
|
624
|
+
};
|
|
625
|
+
/** Drop `serverKey` from a root `disabled_mcp_servers` array while installing. */
|
|
626
|
+
const disabledServerListEdit = (input) => {
|
|
627
|
+
if (input.entry === undefined ||
|
|
628
|
+
input.tablePath.length !== 0 ||
|
|
629
|
+
input.segments.length !== 1 ||
|
|
630
|
+
input.segments[0] !== "disabled_mcp_servers")
|
|
631
|
+
return { kind: "ignore" };
|
|
632
|
+
const open = skipWsAndComments(input.text, input.valueOffset);
|
|
633
|
+
if (input.text[open] !== "[")
|
|
634
|
+
return { kind: "ignore" };
|
|
635
|
+
const arrayText = input.text.slice(open, input.valueEnd);
|
|
636
|
+
const edited = tomlArrayWithoutString(arrayText, input.serverKey);
|
|
637
|
+
if (edited === undefined || edited === arrayText)
|
|
638
|
+
return { kind: "keep" };
|
|
639
|
+
if (edited === "") {
|
|
640
|
+
const suffix = input.text.slice(input.valueEnd, input.statementEnd);
|
|
641
|
+
const hash = suffix.indexOf("#");
|
|
642
|
+
return {
|
|
643
|
+
kind: "delete",
|
|
644
|
+
comment: hash < 0 ? undefined : suffix.slice(hash),
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
return {
|
|
648
|
+
kind: "replace",
|
|
649
|
+
text: `${input.text.slice(input.lineStart, open)}${edited}${input.text.slice(input.valueEnd, input.statementEnd)}`,
|
|
650
|
+
};
|
|
651
|
+
};
|
|
652
|
+
/** Lines that replace a disabled-server assignment, or undefined to leave it. */
|
|
653
|
+
const disabledServerListLines = (edit, lines, lineIndex, endLine) => {
|
|
654
|
+
switch (edit.kind) {
|
|
655
|
+
case "ignore":
|
|
656
|
+
return undefined;
|
|
657
|
+
case "keep":
|
|
658
|
+
return lines.slice(lineIndex, endLine + 1);
|
|
659
|
+
case "replace":
|
|
660
|
+
return edit.text.split("\n");
|
|
661
|
+
case "delete":
|
|
662
|
+
return edit.comment === undefined ? [] : [edit.comment];
|
|
663
|
+
default: {
|
|
664
|
+
const unreachable = edit;
|
|
665
|
+
return unreachable;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
/**
|
|
670
|
+
* Replace REA's Grok server tables and assignments. Comments that introduce a
|
|
671
|
+
* following table stay. Text inside strings is not treated as a header.
|
|
672
|
+
*/
|
|
673
|
+
const upsertGrokServerSection = (originalText, serverKey, entry) => {
|
|
674
|
+
// smol-toml accepts a leading BOM. Leave it in place or the first header is missed.
|
|
675
|
+
const bom = originalText.startsWith("\uFEFF");
|
|
676
|
+
const source = bom ? originalText.slice(1) : originalText;
|
|
677
|
+
// Keep a preceding \r on each line. Rewriting \r\n in the whole file would
|
|
678
|
+
// change string values. A file whose every break is CRLF gets a CRLF section.
|
|
679
|
+
const crlf = source.includes("\r\n") && !source.replaceAll("\r\n", "").includes("\n");
|
|
680
|
+
const text = source;
|
|
681
|
+
const lines = text.split("\n");
|
|
682
|
+
const lineStarts = [];
|
|
683
|
+
let cursor = 0;
|
|
684
|
+
for (const line of lines) {
|
|
685
|
+
lineStarts.push(cursor);
|
|
686
|
+
cursor += line.length + 1;
|
|
687
|
+
}
|
|
688
|
+
const kept = [];
|
|
689
|
+
const pending = [];
|
|
690
|
+
let skipping = false;
|
|
691
|
+
let inlineServerTable = false;
|
|
692
|
+
let mode = "none";
|
|
693
|
+
let tablePath = [];
|
|
694
|
+
const discardPending = () => {
|
|
695
|
+
pending.length = 0;
|
|
696
|
+
};
|
|
697
|
+
const flushPending = () => {
|
|
698
|
+
kept.push(...pending);
|
|
699
|
+
pending.length = 0;
|
|
700
|
+
};
|
|
701
|
+
const lineIndexAt = (offset) => {
|
|
702
|
+
let line = 0;
|
|
703
|
+
for (let index = 0; index < lineStarts.length; index += 1)
|
|
704
|
+
if ((lineStarts[index] ?? 0) <= offset)
|
|
705
|
+
line = index;
|
|
706
|
+
return line;
|
|
707
|
+
};
|
|
708
|
+
let lineIndex = 0;
|
|
709
|
+
while (lineIndex < lines.length) {
|
|
710
|
+
const physical = lines[lineIndex] ?? "";
|
|
711
|
+
const line = physical.endsWith("\r") ? physical.slice(0, -1) : physical;
|
|
712
|
+
if (mode !== "none") {
|
|
713
|
+
mode = tomlStringModeAfter(line, mode);
|
|
714
|
+
if (skipping)
|
|
715
|
+
discardPending();
|
|
716
|
+
else
|
|
717
|
+
kept.push(physical);
|
|
718
|
+
lineIndex += 1;
|
|
719
|
+
continue;
|
|
720
|
+
}
|
|
721
|
+
const header = parseTomlTableHeader(line);
|
|
722
|
+
if (header !== undefined) {
|
|
723
|
+
tablePath = header.path;
|
|
724
|
+
if (isGrokServerTable(header.path, serverKey)) {
|
|
725
|
+
discardPending();
|
|
726
|
+
skipping = true;
|
|
727
|
+
lineIndex += 1;
|
|
728
|
+
continue;
|
|
729
|
+
}
|
|
730
|
+
skipping = false;
|
|
731
|
+
flushPending();
|
|
732
|
+
kept.push(physical);
|
|
733
|
+
lineIndex += 1;
|
|
734
|
+
continue;
|
|
735
|
+
}
|
|
736
|
+
const assignment = parseAssignment(line);
|
|
737
|
+
if (assignment !== undefined) {
|
|
738
|
+
const lineStart = lineStarts[lineIndex] ?? 0;
|
|
739
|
+
const valueOffset = lineStart + assignment.equals + 1;
|
|
740
|
+
const valueEnd = endOfTomlValue(text, valueOffset);
|
|
741
|
+
let statementEnd = valueEnd;
|
|
742
|
+
while (statementEnd < text.length && text[statementEnd] !== "\n")
|
|
743
|
+
statementEnd += 1;
|
|
744
|
+
const endLine = lineIndexAt(Math.max(statementEnd - 1, lineStart));
|
|
745
|
+
if (skipping) {
|
|
746
|
+
discardPending();
|
|
747
|
+
lineIndex = endLine + 1;
|
|
748
|
+
mode = "none";
|
|
749
|
+
continue;
|
|
750
|
+
}
|
|
751
|
+
const disabledLines = disabledServerListLines(disabledServerListEdit({
|
|
752
|
+
text,
|
|
753
|
+
lineStart,
|
|
754
|
+
valueOffset,
|
|
755
|
+
valueEnd,
|
|
756
|
+
statementEnd,
|
|
757
|
+
tablePath,
|
|
758
|
+
segments: assignment.segments,
|
|
759
|
+
serverKey,
|
|
760
|
+
entry,
|
|
761
|
+
}), lines, lineIndex, endLine);
|
|
762
|
+
if (disabledLines !== undefined) {
|
|
763
|
+
flushPending();
|
|
764
|
+
kept.push(...disabledLines);
|
|
765
|
+
lineIndex = endLine + 1;
|
|
766
|
+
mode = "none";
|
|
767
|
+
continue;
|
|
768
|
+
}
|
|
769
|
+
const absolute = [...tablePath, ...assignment.segments];
|
|
770
|
+
const open = skipWsAndComments(text, valueOffset);
|
|
771
|
+
const closesServerTable = absolute.length === 1 &&
|
|
772
|
+
absolute[0] === "mcp_servers" &&
|
|
773
|
+
text[open] === "{";
|
|
774
|
+
if (closesServerTable || isGrokServerTable(absolute, serverKey)) {
|
|
775
|
+
if (closesServerTable) {
|
|
776
|
+
flushPending();
|
|
777
|
+
const edited = editGrokInlineTable(text.slice(open, valueEnd), serverKey, entry);
|
|
778
|
+
const prefix = text.slice(lineStart, open);
|
|
779
|
+
const suffix = text.slice(valueEnd, statementEnd);
|
|
780
|
+
const replacement = edited === undefined
|
|
781
|
+
? text.slice(lineStart, statementEnd)
|
|
782
|
+
: `${prefix}${edited}${suffix}`;
|
|
783
|
+
kept.push(...replacement.split("\n"));
|
|
784
|
+
inlineServerTable = true;
|
|
785
|
+
}
|
|
786
|
+
else
|
|
787
|
+
discardPending();
|
|
788
|
+
}
|
|
789
|
+
else {
|
|
790
|
+
flushPending();
|
|
791
|
+
for (let index = lineIndex; index <= endLine; index += 1)
|
|
792
|
+
kept.push(lines[index] ?? "");
|
|
793
|
+
}
|
|
794
|
+
lineIndex = endLine + 1;
|
|
795
|
+
mode = "none";
|
|
796
|
+
continue;
|
|
797
|
+
}
|
|
798
|
+
if (isBlankOrComment(line)) {
|
|
799
|
+
pending.push(physical);
|
|
800
|
+
lineIndex += 1;
|
|
801
|
+
continue;
|
|
802
|
+
}
|
|
803
|
+
mode = tomlStringModeAfter(line, "none");
|
|
804
|
+
if (skipping) {
|
|
805
|
+
if (looksLikeTomlHeader(line)) {
|
|
806
|
+
flushPending();
|
|
807
|
+
skipping = false;
|
|
808
|
+
tablePath = ["\0"];
|
|
809
|
+
kept.push(physical);
|
|
810
|
+
}
|
|
811
|
+
else
|
|
812
|
+
discardPending();
|
|
813
|
+
}
|
|
814
|
+
else {
|
|
815
|
+
flushPending();
|
|
816
|
+
kept.push(physical);
|
|
817
|
+
}
|
|
818
|
+
lineIndex += 1;
|
|
819
|
+
}
|
|
820
|
+
if (!skipping)
|
|
821
|
+
flushPending();
|
|
822
|
+
let body = kept.join("\n");
|
|
823
|
+
// The last kept CRLF line has no following LF from the join.
|
|
824
|
+
if (body.endsWith("\r"))
|
|
825
|
+
body += "\n";
|
|
826
|
+
if (entry !== undefined && !inlineServerTable) {
|
|
827
|
+
let fragment = stringifyToml({
|
|
828
|
+
mcp_servers: { [serverKey]: entry },
|
|
829
|
+
}).replace(/\n+$/u, "");
|
|
830
|
+
if (crlf)
|
|
831
|
+
fragment = fragment.replaceAll("\n", "\r\n");
|
|
832
|
+
const nl = crlf ? "\r\n" : "\n";
|
|
833
|
+
const endedWithNewline = body.endsWith("\n");
|
|
834
|
+
const base = body.replace(/\n+$/u, "");
|
|
835
|
+
const trimmed = endedWithNewline && base.endsWith("\r") ? base.slice(0, -1) : base;
|
|
836
|
+
body =
|
|
837
|
+
trimmed.length === 0
|
|
838
|
+
? `${fragment}${nl}`
|
|
839
|
+
: `${trimmed}${nl}${nl}${fragment}${nl}`;
|
|
840
|
+
}
|
|
841
|
+
return bom ? `\uFEFF${body}` : body;
|
|
842
|
+
};
|
|
843
|
+
const grokServerEntry = (document, serverKey) => {
|
|
844
|
+
const servers = objectSchema.safeParse(document.mcp_servers);
|
|
845
|
+
if (!servers.success || !Object.hasOwn(servers.data, serverKey))
|
|
846
|
+
return undefined;
|
|
847
|
+
return servers.data[serverKey];
|
|
848
|
+
};
|
|
849
|
+
/** Whether Grok Build's root disable list names `serverKey`. */
|
|
850
|
+
export const grokServerListedDisabled = (document, serverKey) => Array.isArray(document.disabled_mcp_servers) &&
|
|
851
|
+
document.disabled_mcp_servers.includes(serverKey);
|
|
852
|
+
/** Keep an existing Grok document intact aside from the REA server tables. */
|
|
853
|
+
const serializeGrokConfiguration = (document, originalText) => {
|
|
854
|
+
const entry = grokServerEntry(document, PRODUCT_IDENTITY.mcpServerKey);
|
|
855
|
+
if (originalText === undefined)
|
|
856
|
+
return stringifyToml(document);
|
|
857
|
+
return upsertGrokServerSection(originalText, PRODUCT_IDENTITY.mcpServerKey, entry);
|
|
858
|
+
};
|
|
859
|
+
/** Comments in the trivia between two properties. `undefined` when there are none. */
|
|
860
|
+
const commentsBetweenProperties = (gap) => {
|
|
861
|
+
const pieces = [];
|
|
862
|
+
let index = 0;
|
|
863
|
+
while (index < gap.length) {
|
|
864
|
+
const line = gap.indexOf("//", index);
|
|
865
|
+
const block = gap.indexOf("/*", index);
|
|
866
|
+
if (line < 0 && block < 0)
|
|
867
|
+
break;
|
|
868
|
+
const start = line < 0 ? block : block < 0 ? line : Math.min(line, block);
|
|
869
|
+
const lineComment = start === line;
|
|
870
|
+
const close = lineComment
|
|
871
|
+
? gap.indexOf("\n", start)
|
|
872
|
+
: gap.indexOf("*/", start + 2);
|
|
873
|
+
if (!lineComment && close < 0)
|
|
874
|
+
return undefined;
|
|
875
|
+
const end = lineComment ? (close < 0 ? gap.length : close) : close + 2;
|
|
876
|
+
const comment = gap.slice(start, end);
|
|
877
|
+
const lineBreak = gap.lastIndexOf("\n", start - 1);
|
|
878
|
+
if (lineBreak < 0)
|
|
879
|
+
pieces.push(` ${comment}`);
|
|
880
|
+
else {
|
|
881
|
+
const prefix = gap.slice(lineBreak + 1, start);
|
|
882
|
+
let indentEnd = 0;
|
|
883
|
+
while (prefix[indentEnd] === " " || prefix[indentEnd] === "\t")
|
|
884
|
+
indentEnd += 1;
|
|
885
|
+
const newline = lineBreak > 0 && gap[lineBreak - 1] === "\r" ? "\r\n" : "\n";
|
|
886
|
+
pieces.push(`${newline}${prefix.slice(0, indentEnd)}${comment}`);
|
|
887
|
+
}
|
|
888
|
+
index = end;
|
|
889
|
+
}
|
|
890
|
+
return pieces.length === 0 ? undefined : pieces.join("");
|
|
891
|
+
};
|
|
892
|
+
/**
|
|
893
|
+
* Delete an object property without taking a comment from the gap before it.
|
|
894
|
+
* jsonc-parser's removal span includes that gap, so a trailing comment on the
|
|
895
|
+
* previous property would disappear. Returns `undefined` to keep the stock edit.
|
|
896
|
+
*/
|
|
897
|
+
const deleteJsonPropertyPreservingComments = (text, path) => {
|
|
898
|
+
const root = parseTree(text, [], { allowTrailingComma: true });
|
|
899
|
+
const value = root === undefined ? undefined : findNodeAtLocation(root, [...path]);
|
|
900
|
+
const property = value?.parent;
|
|
901
|
+
const parent = property?.parent;
|
|
902
|
+
if (property === undefined ||
|
|
903
|
+
parent?.type !== "object" ||
|
|
904
|
+
property.type !== "property" ||
|
|
905
|
+
parent.children === undefined)
|
|
906
|
+
return undefined;
|
|
907
|
+
const propertyIndex = parent.children.indexOf(property);
|
|
908
|
+
const previous = parent.children[propertyIndex - 1];
|
|
909
|
+
if (propertyIndex <= 0 || previous === undefined)
|
|
910
|
+
return undefined;
|
|
911
|
+
const comments = commentsBetweenProperties(text.slice(previous.offset + previous.length, property.offset));
|
|
912
|
+
if (comments === undefined)
|
|
913
|
+
return undefined;
|
|
914
|
+
let removeEnd = property.offset + property.length;
|
|
915
|
+
const hasNext = parent.children[propertyIndex + 1] !== undefined;
|
|
916
|
+
if (hasNext) {
|
|
917
|
+
let comma = removeEnd;
|
|
918
|
+
while (comma < text.length) {
|
|
919
|
+
const char = text[comma];
|
|
920
|
+
if (char === " " || char === "\t" || char === "\r" || char === "\n") {
|
|
921
|
+
comma += 1;
|
|
922
|
+
continue;
|
|
923
|
+
}
|
|
924
|
+
if (text.startsWith("/*", comma)) {
|
|
925
|
+
const close = text.indexOf("*/", comma + 2);
|
|
926
|
+
if (close < 0)
|
|
927
|
+
return undefined;
|
|
928
|
+
comma = close + 2;
|
|
929
|
+
continue;
|
|
930
|
+
}
|
|
931
|
+
if (text.startsWith("//", comma)) {
|
|
932
|
+
while (comma < text.length &&
|
|
933
|
+
text[comma] !== "\n" &&
|
|
934
|
+
text[comma] !== "\r")
|
|
935
|
+
comma += 1;
|
|
936
|
+
continue;
|
|
937
|
+
}
|
|
938
|
+
break;
|
|
939
|
+
}
|
|
940
|
+
if (text[comma] !== ",")
|
|
941
|
+
return undefined;
|
|
942
|
+
removeEnd = comma + 1;
|
|
943
|
+
}
|
|
944
|
+
// A line comment runs to the next break. Keep the following token outside it.
|
|
945
|
+
const remainder = text.slice(removeEnd);
|
|
946
|
+
let suffix = `${hasNext ? "," : ""}${comments}`;
|
|
947
|
+
if (suffix.includes("//") &&
|
|
948
|
+
!suffix.endsWith("\n") &&
|
|
949
|
+
!suffix.endsWith("\r") &&
|
|
950
|
+
!remainder.startsWith("\n") &&
|
|
951
|
+
!remainder.startsWith("\r"))
|
|
952
|
+
suffix += "\n";
|
|
953
|
+
return `${text.slice(0, previous.offset + previous.length)}${suffix}${remainder}`;
|
|
954
|
+
};
|
|
104
955
|
/** Serialize a validated client document, retaining JSONC comments. */
|
|
105
956
|
export const serializeClientConfiguration = (document, format, originalText, editedPaths) => {
|
|
106
957
|
if (format === undefined || format === "unsupported")
|
|
107
958
|
throw new TypeError("client does not have a supported MCP config format");
|
|
108
959
|
if (format === "toml")
|
|
109
960
|
return stringifyToml(document);
|
|
110
|
-
if (
|
|
111
|
-
return
|
|
112
|
-
|
|
113
|
-
|
|
961
|
+
if (format === "grok")
|
|
962
|
+
return serializeGrokConfiguration(document, originalText);
|
|
963
|
+
// An empty original holds no comments or settings to preserve. Writing a
|
|
964
|
+
// fresh document also keeps a lone BOM from shifting past the closing brace.
|
|
965
|
+
if (originalText !== undefined &&
|
|
966
|
+
!isEmptyClientConfigurationText(originalText) &&
|
|
967
|
+
editedPaths !== undefined)
|
|
968
|
+
return editedPaths.reduce((text, path) => {
|
|
969
|
+
const value = valueAt(document, path);
|
|
970
|
+
if (value === undefined) {
|
|
971
|
+
const preserved = deleteJsonPropertyPreservingComments(text, path);
|
|
972
|
+
if (preserved !== undefined)
|
|
973
|
+
return preserved;
|
|
974
|
+
}
|
|
975
|
+
return applyEdits(text, modify(text, [...path], value, {
|
|
976
|
+
formattingOptions: { insertSpaces: true, tabSize: 2, eol: "\n" },
|
|
977
|
+
}));
|
|
978
|
+
}, originalText);
|
|
114
979
|
return `${JSON.stringify(document, null, 2)}\n`;
|
|
115
980
|
};
|
|
116
981
|
/** Key path of a named registration in the server table. */
|