rea-agents 3.0.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +83 -108
- package/bridge/ghidra/ReaGhidraBridge.java +609 -841
- package/bridge/hopper_bridge.py +99 -344
- package/dist/application/AbortablePromise.js +6 -3
- package/dist/application/AnalysisContextQueries.js +21 -9
- package/dist/application/AnalysisSnapshotCache.js +0 -1
- package/dist/application/AnalysisSnapshotFiles.js +7 -7
- package/dist/application/AndroidApplicationService.js +1 -1
- package/dist/application/AppleApplicationService.js +1 -1
- package/dist/application/ArtifactExtraction.js +35 -54
- package/dist/application/ArtifactExtractionDestination.js +17 -0
- package/dist/application/ArtifactGraphConstruction.js +2 -17
- package/dist/application/ArtifactInventory/classify.js +2 -6
- package/dist/application/ArtifactInventory/hash.js +2 -20
- package/dist/application/ArtifactInventory/policy.js +17 -0
- package/dist/application/ArtifactInventory/reader.js +1 -4
- package/dist/application/ArtifactInventory/scanCanonical.js +8 -15
- package/dist/application/ArtifactInventory/scanReader.js +76 -58
- package/dist/application/ArtifactInventory/types.js +1 -5
- package/dist/application/ArtifactInventory.js +6 -14
- package/dist/application/AuthorizedArtifactInventory.js +3 -13
- package/dist/application/BinarySession.js +54 -28
- package/dist/application/BinarySessionComposition.js +0 -11
- package/dist/application/BinarySessionOpen.js +2 -1
- package/dist/application/BinarySessionRecords.js +24 -86
- package/dist/application/BinarySessionStatus.js +16 -21
- package/dist/application/BinaryTargetResolver.js +216 -0
- package/dist/application/BrowserEvidence.js +39 -57
- package/dist/application/BrowserObservationService.js +3 -6
- package/dist/application/BrowserScenarioCaptureService.js +3 -6
- package/dist/application/BrowserScenarioEvidence.js +3 -3
- package/dist/application/CallPathTracing.js +2 -36
- package/dist/application/CapabilityClientRequirements.js +26 -0
- package/dist/application/CapabilityInventory.js +143 -77
- package/dist/application/ClientConfigurationDocument.js +27 -0
- package/dist/application/ClientRegistrationStatus.js +16 -13
- package/dist/application/CommandShimReplay.js +14 -1
- package/dist/application/DirectAnalysis.js +22 -46
- package/dist/application/DirectAnalysisStatus.js +5 -61
- package/dist/application/Doctor.js +11 -32
- package/dist/application/DoctorDiagnostics.js +1 -2
- package/dist/application/DoctorScope.js +1 -1
- package/dist/application/ElectronActiveEvidence.js +50 -0
- package/dist/application/ElectronActiveObservationPort.js +1 -0
- package/dist/application/ElectronActiveObservationService.js +78 -0
- package/dist/application/ElectronBoundaryAnalysis.js +7 -8
- package/dist/application/ElectronBoundaryGraphContext.js +1 -1
- package/dist/application/ElectronBoundaryGraphIpc.js +3 -3
- package/dist/application/ElectronBoundaryGraphNative.js +1 -2
- package/dist/application/ElectronBoundaryGraphWindows.js +6 -8
- package/dist/application/ElectronEvidence.js +4 -7
- package/dist/application/ElectronObservationService.js +5 -9
- package/dist/application/EnhancedLiteralTracing.js +42 -65
- package/dist/application/EnhancedTools.js +98 -64
- package/dist/application/EvidenceBundleCommands.js +16 -12
- package/dist/application/EvidenceBundleFiles.js +9 -15
- package/dist/application/EvidenceLedger.js +14 -42
- package/dist/application/FilesystemSnapshot.js +2 -3
- package/dist/application/InterfaceBuilderAnalysis.js +266 -0
- package/dist/application/InventoryProjectionEvidence.js +4 -2
- package/dist/application/InvestigationProviders.js +1 -1
- package/dist/application/JavaScriptApplicationEvidence.js +2 -5
- package/dist/application/JavaScriptApplicationEvidenceGraph.js +6 -10
- package/dist/application/JavaScriptApplicationService.js +6 -29
- package/dist/application/JavaScriptApplicationWorkflowEvidence.js +5 -5
- package/dist/application/JavaScriptApplicationWorkflowService.js +0 -8
- package/dist/application/JavaScriptArtifactAnalysis.js +38 -127
- package/dist/application/JavaScriptArtifactFiles.js +67 -107
- package/dist/application/JavaScriptArtifactGraphAccumulator.js +0 -7
- package/dist/application/JavaScriptArtifactGraphBuilder.js +7 -58
- package/dist/application/JavaScriptArtifactGraphBundlers.js +1 -6
- package/dist/application/JavaScriptArtifactGraphContext.js +12 -39
- package/dist/application/JavaScriptArtifactGraphDocuments.js +4 -11
- package/dist/application/JavaScriptArtifactGraphEvidence.js +0 -14
- package/dist/application/JavaScriptArtifactGraphFindings.js +3 -3
- package/dist/application/JavaScriptArtifactGraphStructure.js +16 -17
- package/dist/application/JavaScriptArtifactPathResolution.js +61 -49
- package/dist/application/JavaScriptArtifactReconstruction.js +5 -10
- package/dist/application/JavaScriptArtifactReconstructionInput.js +2 -14
- package/dist/application/JavaScriptJsonModules.js +2 -2
- package/dist/application/JavaScriptModuleRelationships.js +22 -27
- package/dist/application/JavaScriptReplayPermission.js +1 -1
- package/dist/application/JavaScriptReplayPlanning.js +9 -3
- package/dist/application/JavaScriptReplayService.js +29 -47
- package/dist/application/JavaScriptReturnShapeProjection.js +12 -42
- package/dist/application/JavaScriptRuntimeObservationEvidence.js +7 -8
- package/dist/application/JavaScriptRuntimeObservationService.js +4 -8
- package/dist/application/JavaScriptRuntimeReconciliationEvidence.js +2 -3
- package/dist/application/JavaScriptSemanticGraphBuilder.js +11 -41
- package/dist/application/JavaScriptSemanticGraphConstruction.js +5 -29
- package/dist/application/JavaScriptSemanticGraphEvidence.js +1 -1
- package/dist/application/JavaScriptSemanticGraphFingerprintProjection.js +1 -1
- package/dist/application/JavaScriptSemanticGraphFlowProjection.js +0 -13
- package/dist/application/JavaScriptSemanticGraphProjection.js +1 -3
- package/dist/application/JavaScriptSemanticTraceService.js +1 -10
- package/dist/application/JsonFiles.js +79 -0
- package/dist/application/LinuxHopper.js +11 -9
- package/dist/application/LoopbackReplay.js +26 -23
- package/dist/application/LoopbackReplayRecorder.js +29 -1
- package/dist/application/ManagedApplicationGraphService.js +1 -2
- package/dist/application/ManagedMemberComparisonService.js +11 -41
- package/dist/application/ManagedNativeVerificationService.js +1 -2
- package/dist/application/ManagedReconstructionService.js +1 -1
- package/dist/application/ManagedRuntimeCorrelationService.js +14 -13
- package/dist/application/NativeApiInspection.js +2 -7
- package/dist/application/NativeUiActionTrace.js +394 -0
- package/dist/application/NodeRuntimeCharacterizationService.js +11 -16
- package/dist/application/PermissionAuthority.js +15 -7
- package/dist/application/PermissionFailure.js +5 -0
- package/dist/application/ProcessCaptureAuthority.js +5 -7
- package/dist/application/ProcessCaptureJournal.js +3 -2
- package/dist/application/ProcessCaptureLifecycle.js +10 -12
- package/dist/application/ProcessCheckpoints.js +29 -11
- package/dist/application/ProcessCli.js +8 -17
- package/dist/application/ProcessEvidence.js +5 -7
- package/dist/application/ProcessHarness.js +60 -20
- package/dist/application/ProcessNormalization.js +2 -1
- package/dist/application/ProcessReactiveCoordinator.js +2 -4
- package/dist/application/ProcessReactiveEffects.js +9 -3
- package/dist/application/ProcessReactiveHarness.js +13 -7
- package/dist/application/ProcessSampling.js +2 -4
- package/dist/application/ProcessTimer.js +39 -0
- package/dist/application/ProjectPermissionStore.js +39 -95
- package/dist/application/RealHopperAssertions.js +20 -66
- package/dist/application/ReconstructionCoverageService.js +12 -58
- package/dist/application/ReconstructionObligationAuthority.js +2 -2
- package/dist/application/ReconstructionObligationCandidates.js +4 -4
- package/dist/application/ReconstructionObligationLedgerEvaluation.js +8 -15
- package/dist/application/ReconstructionObligationLedgerProjection.js +3 -7
- package/dist/application/ReconstructionObligationLedgerService.js +19 -38
- package/dist/application/ReferenceSourceImport.js +21 -47
- package/dist/application/ReferenceSourceImportEntries.js +2 -4
- package/dist/application/ReferenceSourceImportPolicy.js +5 -32
- package/dist/application/ReferenceSourceImportTypes.js +0 -16
- package/dist/application/RuntimeExecutableDiagnostics.js +55 -29
- package/dist/application/SessionProviderRouter.js +2 -2
- package/dist/application/Setup.js +1 -3
- package/dist/application/SetupClientConfiguration.js +22 -88
- package/dist/application/SetupRegistrationEnvironment.js +0 -7
- package/dist/application/StoreFileLock.js +119 -0
- package/dist/application/TerminalRenderer.js +2 -3
- package/dist/application/Uninstall.js +9 -14
- package/dist/application/UnknownEvidence.js +1 -1
- package/dist/application/WindowsCapabilities.js +5 -4
- package/dist/artifacts/ArtifactPaths.js +2 -5
- package/dist/artifacts/ArtifactProvider.js +43 -67
- package/dist/artifacts/DirectoryArtifactReader.js +13 -8
- package/dist/artifacts/MachOSliceArtifactReader.js +1 -5
- package/dist/artifacts/NativeDmgArtifactReader.js +11 -11
- package/dist/artifacts/NibArchive.js +269 -0
- package/dist/artifacts/SafeOutputTree.js +21 -31
- package/dist/browser/BrowserProcessStartup.js +1 -2
- package/dist/browser/CdpAuthorizedMainFrame.js +16 -0
- package/dist/browser/CdpBrowserProvider.js +3 -13
- package/dist/browser/CdpCanonicalJsonDigest.js +9 -0
- package/dist/browser/CdpCaptureDocuments.js +28 -76
- package/dist/browser/CdpCaptureEventBodyShapes.js +13 -33
- package/dist/browser/CdpCaptureEventHandlers.js +22 -87
- package/dist/browser/CdpCaptureEvents.js +2 -8
- package/dist/browser/CdpCaptureStorage.js +9 -20
- package/dist/browser/CdpCaptureStorageFingerprints.js +85 -95
- package/dist/browser/CdpCaptureValues.js +21 -21
- package/dist/browser/CdpConnection.js +10 -25
- package/dist/browser/CdpElectronInspection.js +29 -51
- package/dist/browser/CdpElectronProvider.js +10 -35
- package/dist/browser/CdpElectronScriptEvents.js +8 -16
- package/dist/browser/CdpElectronScripts.js +6 -35
- package/dist/browser/CdpElectronWorkers.js +6 -10
- package/dist/browser/CdpEndpoint.js +25 -41
- package/dist/browser/CdpObservationSession.js +14 -26
- package/dist/browser/CdpPageCapture.js +34 -48
- package/dist/browser/CdpPageCaptureScripts.js +1 -19
- package/dist/browser/CdpPageCaptureWorkers.js +6 -10
- package/dist/browser/CdpSafeMetadata.js +19 -22
- package/dist/browser/CdpScreenshot.js +3 -5
- package/dist/browser/CdpTargetSession.js +1 -2
- package/dist/browser/CdpWebMcpDiscovery.js +13 -22
- package/dist/browser/ElectronFileScope.js +8 -19
- package/dist/browser/JavaScriptRuntimeScope.js +10 -10
- package/dist/browser/PlaywrightBrowserScenarioProvider.js +31 -64
- package/dist/browser/PlaywrightElectronActiveActions.js +309 -0
- package/dist/browser/PlaywrightElectronActiveProvider.js +274 -0
- package/dist/browser/PlaywrightExecutionBoundary.js +16 -5
- package/dist/browser/PlaywrightScenarioActions.js +3 -7
- package/dist/browser/PlaywrightScenarioArtifacts.js +23 -92
- package/dist/browser/PlaywrightScenarioBrowser.js +7 -9
- package/dist/browser/PlaywrightScenarioEvents.js +45 -94
- package/dist/browser/PlaywrightScenarioSession.js +18 -34
- package/dist/browser/PngVisualDiff.js +22 -14
- package/dist/browser/SensitiveTextCapture.js +1 -18
- package/dist/browser/V8InspectorCaptureProjection.js +7 -7
- package/dist/browser/V8InspectorEndpoint.js +12 -14
- package/dist/browser/V8InspectorProvider.js +20 -61
- package/dist/browser/WebSourceMapFetcher.js +56 -176
- package/dist/catalogIdentity.js +12 -60
- package/dist/cli/artifactCommands.js +49 -77
- package/dist/cli/coreAnalysisCommands.js +83 -133
- package/dist/cli/javascriptApplicationAnalysis.js +1 -9
- package/dist/cli/managedCommands.js +6 -271
- package/dist/cli/setupCommands.js +3 -12
- package/dist/cli/utilityCommands.js +7 -41
- package/dist/cli.js +0 -2
- package/dist/cliApplicationCommands.js +44 -114
- package/dist/cliBrowserAdvancedCommands.js +12 -102
- package/dist/cliBrowserCommands.js +19 -124
- package/dist/cliBrowserContext.js +30 -0
- package/dist/cliCommandNames.js +5 -5
- package/dist/cliElectronCommands.js +49 -71
- package/dist/cliEvidenceCommands.js +8 -77
- package/dist/cliJavaScriptRuntimeCommands.js +18 -92
- package/dist/cliJsonInput.js +4 -14
- package/dist/cliObservationOptions.js +11 -92
- package/dist/cliPolicyCommands.js +2 -16
- package/dist/cliProcessCommands.js +3 -3
- package/dist/cliSetup.js +0 -13
- package/dist/config/browserScenario.js +77 -0
- package/dist/config/electronAutomation.js +35 -0
- package/dist/config/environment.js +6 -9
- package/dist/config/javascriptReplay.js +41 -0
- package/dist/config/managedRuntime.js +25 -0
- package/dist/config/parseConfig.js +56 -232
- package/dist/config/parsers.js +16 -28
- package/dist/config/passiveObservation.js +87 -0
- package/dist/config/permissions.js +0 -7
- package/dist/config/processCapture.js +47 -0
- package/dist/contracts/analysisSearchContract.js +2 -5
- package/dist/contracts/applicationToolContracts.js +58 -114
- package/dist/contracts/applicationWorkflowInputContracts.js +29 -114
- package/dist/contracts/artifactComparisonExample.js +58 -60
- package/dist/contracts/artifactToolContracts.js +37 -91
- package/dist/contracts/browserScenarioToolContracts.js +6 -51
- package/dist/contracts/browserToolContracts.js +10 -75
- package/dist/contracts/electronToolContracts.js +27 -98
- package/dist/contracts/enhancedInputs.js +31 -78
- package/dist/contracts/errorSchemas.js +0 -1
- package/dist/contracts/functionComparisonExample.js +10 -24
- package/dist/contracts/functionInstructionContract.js +1 -3
- package/dist/contracts/functionWorkflowToolContracts.js +4 -5
- package/dist/contracts/hopperMemoryContracts.js +3 -3
- package/dist/contracts/investigationExamples.js +14 -11
- package/dist/contracts/javascriptApplicationWorkflowExamples.js +12 -19
- package/dist/contracts/javascriptRuntimeObservationToolContracts.js +2 -20
- package/dist/contracts/javascriptRuntimeReconciliationExample.js +45 -12
- package/dist/contracts/managedToolContracts.js +10 -104
- package/dist/contracts/managedWorkflowExamples.js +77 -125
- package/dist/contracts/managedWorkflowToolContracts.js +51 -74
- package/dist/contracts/nativeToolContracts.js +9 -14
- package/dist/contracts/processCaptureExample.js +2 -69
- package/dist/contracts/promptContracts.js +49 -67
- package/dist/contracts/providerSelection.js +0 -1
- package/dist/contracts/reconstructionReadinessExample.js +1 -6
- package/dist/contracts/sessionStatusContract.js +1 -17
- package/dist/contracts/sessionToolSchemas.js +52 -0
- package/dist/contracts/toolContractExamples.js +11 -10
- package/dist/contracts/toolContractHelpers.js +19 -0
- package/dist/contracts/toolContracts.js +60 -143
- package/dist/contracts/toolEffects.js +16 -9
- package/dist/contracts/toolOutputSchemaGroups.js +47 -86
- package/dist/contracts/toolOutputSchemaPrimitives.js +72 -62
- package/dist/contracts/toolSchemaMetadata.js +117 -0
- package/dist/contracts/unknownContractExamples.js +0 -2
- package/dist/doctorRuntime.js +1 -1
- package/dist/domain/analysisErrorPresentation.js +46 -54
- package/dist/domain/analysisErrorProjection.js +28 -37
- package/dist/domain/analysisProfile.js +3 -31
- package/dist/domain/analysisSnapshot.js +3 -12
- package/dist/domain/androidApplication.js +15 -52
- package/dist/domain/appleApplication.js +24 -65
- package/dist/domain/artifactComparison.js +11 -29
- package/dist/domain/artifactGraph.js +14 -44
- package/dist/domain/artifactInspection.js +38 -69
- package/dist/domain/artifactInventoryEvidence.js +27 -21
- package/dist/domain/binaryTarget.js +2 -219
- package/dist/domain/binaryTargetTypes.js +1 -0
- package/dist/domain/browserCaptureComparison.js +35 -60
- package/dist/domain/browserObservation.js +45 -197
- package/dist/domain/browserObservationSchemas.js +5 -23
- package/dist/domain/browserScenario.js +11 -14
- package/dist/domain/browserScenarioCapture.js +11 -12
- package/dist/domain/browserScenarioCaptureValues.js +146 -84
- package/dist/domain/browserScenarioDiff.js +2 -59
- package/dist/domain/browserScenarioDiffEvidence.js +51 -0
- package/dist/domain/browserScenarioDiffValues.js +21 -38
- package/dist/domain/browserScenarioValues.js +80 -109
- package/dist/domain/browserSession.js +4 -7
- package/dist/domain/bundleComparison.js +6 -32
- package/dist/domain/bytecodeProvider.js +53 -54
- package/dist/domain/callPath.js +50 -169
- package/dist/domain/callPathSchemas.js +79 -0
- package/dist/domain/changedBehavior.js +34 -60
- package/dist/domain/completionLedgerGeneration.js +8 -14
- package/dist/domain/conformancePackage.js +126 -97
- package/dist/domain/conformanceReplay.js +39 -11
- package/dist/domain/conformanceTrustGate.js +174 -30
- package/dist/domain/customProtocolCapture.js +4 -4
- package/dist/domain/electronActiveObservation.js +244 -0
- package/dist/domain/electronObservation.js +21 -83
- package/dist/domain/electronStaticAnalysisBrowser.js +36 -46
- package/dist/domain/electronStaticAnalysisIpc.js +38 -14
- package/dist/domain/electronStaticAnalysisNative.js +1 -8
- package/dist/domain/electronStaticAnalysisValues.js +14 -18
- package/dist/domain/errors.js +33 -54
- package/dist/domain/eventProcessTree.js +101 -90
- package/dist/domain/evidence.js +2 -10
- package/dist/domain/evidenceBundle.js +3 -5
- package/dist/domain/evidenceCompletionLedger.js +6 -8
- package/dist/domain/functionComparison.js +4 -14
- package/dist/domain/functionComparisonNormalization.js +8 -8
- package/dist/domain/functionComparisonResults.js +25 -15
- package/dist/domain/functionComparisonSchemas.js +49 -33
- package/dist/domain/functionDossierEvidence.js +31 -151
- package/dist/domain/hopperStartupFailure.js +1 -1
- package/dist/domain/hopperValues.js +17 -141
- package/dist/domain/inputIssueProjection.js +4 -1
- package/dist/domain/interfaceBuilderGraph.js +654 -0
- package/dist/domain/javascriptApplicationAnalysis.js +8 -112
- package/dist/domain/javascriptApplicationChangeGraph.js +22 -82
- package/dist/domain/javascriptApplicationEvidenceSchemas.js +59 -47
- package/dist/domain/javascriptApplicationGraph.js +3 -13
- package/dist/domain/javascriptApplicationGraphSchemas.js +12 -34
- package/dist/domain/javascriptApplicationVersionComparison.js +26 -30
- package/dist/domain/javascriptApplicationVersionComparisonSchemas.js +123 -68
- package/dist/domain/javascriptApplicationVersionItems.js +120 -53
- package/dist/domain/javascriptApplicationVersionKeys.js +24 -11
- package/dist/domain/javascriptAstFingerprint.js +25 -58
- package/dist/domain/javascriptAstValues.js +9 -0
- package/dist/domain/javascriptExportInstrumentation.js +2 -4
- package/dist/domain/javascriptExportShapeComparison.js +6 -7
- package/dist/domain/javascriptExportShapeComparisonSchemas.js +70 -77
- package/dist/domain/javascriptExportShapeSelection.js +17 -19
- package/dist/domain/javascriptFeatureSeed.js +20 -12
- package/dist/domain/javascriptFeatureTrace.js +13 -67
- package/dist/domain/javascriptFeatureTraceSchemas.js +24 -52
- package/dist/domain/javascriptFeatureTraversal.js +1 -44
- package/dist/domain/javascriptNativeHandoff.js +1 -1
- package/dist/domain/javascriptReplay.js +100 -101
- package/dist/domain/javascriptRuntimeLoadState.js +3 -8
- package/dist/domain/javascriptRuntimeObservation.js +43 -103
- package/dist/domain/javascriptRuntimeReconciliation.js +1 -3
- package/dist/domain/javascriptRuntimeReconciliationActive.js +80 -0
- package/dist/domain/javascriptRuntimeReconciliationGraph.js +21 -33
- package/dist/domain/javascriptRuntimeReconciliationMatching.js +75 -61
- package/dist/domain/javascriptRuntimeReconciliationParsing.js +21 -46
- package/dist/domain/javascriptRuntimeReconciliationResult.js +25 -19
- package/dist/domain/javascriptRuntimeReconciliationRuntime.js +8 -12
- package/dist/domain/javascriptRuntimeReconciliationSchemas.js +34 -49
- package/dist/domain/javascriptRuntimeStaticCandidates.js +3 -3
- package/dist/domain/javascriptSemanticAnalysis.js +12 -45
- package/dist/domain/javascriptSemanticAsyncEffects.js +1 -9
- package/dist/domain/javascriptSemanticCallResolution.js +6 -16
- package/dist/domain/javascriptSemanticCalls.js +5 -32
- package/dist/domain/javascriptSemanticChildProcesses.js +1 -11
- package/dist/domain/javascriptSemanticCoverage.js +11 -0
- package/dist/domain/javascriptSemanticDataEffectHelpers.js +1 -8
- package/dist/domain/javascriptSemanticDataEffects.js +1 -11
- package/dist/domain/javascriptSemanticFingerprints.js +3 -5
- package/dist/domain/javascriptSemanticGraphSchemas.js +25 -51
- package/dist/domain/javascriptSemanticGraphSerialization.js +2 -13
- package/dist/domain/javascriptSemanticIr.js +1 -29
- package/dist/domain/javascriptSemanticObjects.js +1 -5
- package/dist/domain/javascriptSemanticPrimitives.js +2 -9
- package/dist/domain/javascriptSemanticProjection.js +0 -18
- package/dist/domain/javascriptSemanticPromises.js +9 -16
- package/dist/domain/javascriptSemanticProvenance.js +16 -19
- package/dist/domain/javascriptSemanticQuery.js +17 -139
- package/dist/domain/javascriptSemanticQueryAssessment.js +9 -37
- package/dist/domain/javascriptSemanticQueryIdentity.js +2 -23
- package/dist/domain/javascriptSemanticQuerySchemas.js +14 -107
- package/dist/domain/javascriptSemanticResources.js +1 -6
- package/dist/domain/javascriptSemanticReturns.js +10 -27
- package/dist/domain/javascriptSemanticValueTypes.js +1 -0
- package/dist/domain/javascriptSemanticValues.js +44 -62
- package/dist/domain/javascriptStaticAnalysis.js +21 -43
- package/dist/domain/javascriptStaticAnalysisBundler.js +34 -93
- package/dist/domain/javascriptStaticAnalysisCalls.js +17 -16
- package/dist/domain/javascriptStaticAnalysisFindings.js +3 -19
- package/dist/domain/javascriptStaticAnalysisHelpers.js +47 -88
- package/dist/domain/javascriptStaticAnalysisState.js +1 -5
- package/dist/domain/javascriptStaticAnalysisTypes.js +1 -0
- package/dist/domain/jsonShape.js +7 -33
- package/dist/domain/localPath.js +7 -0
- package/dist/domain/managedApplicationGraph.js +9 -41
- package/dist/domain/managedApplicationGraphCoverage.js +24 -156
- package/dist/domain/managedApplicationGraphNodes.js +10 -13
- package/dist/domain/managedArtifact.js +14 -27
- package/dist/domain/managedMemberComparison.js +90 -92
- package/dist/domain/managedMemberComparisonCoverage.js +11 -33
- package/dist/domain/managedMemberComparisonItems.js +221 -0
- package/dist/domain/managedMemberComparisonMatch.js +8 -208
- package/dist/domain/managedNativeVerification.js +3 -6
- package/dist/domain/managedNativeVerificationMatch.js +55 -59
- package/dist/domain/managedNativeVerificationSchemas.js +83 -47
- package/dist/domain/managedReconstruction.js +19 -23
- package/dist/domain/managedRuntimeCorrelation.js +6 -9
- package/dist/domain/nativeApiBoundary.js +17 -14
- package/dist/domain/nativeInspection.js +0 -2
- package/dist/domain/nativeInvestigationGraph.js +351 -0
- package/dist/domain/nativeValueFlow.js +61 -0
- package/dist/domain/nodeRuntimeCharacterization.js +15 -18
- package/dist/domain/objcSwiftMetadata.js +254 -0
- package/dist/domain/peInspection.js +1 -1
- package/dist/domain/permissionPolicy.js +13 -0
- package/dist/domain/processCapture.js +76 -113
- package/dist/domain/processCaptureExample.js +68 -0
- package/dist/domain/processCaptureParsing.js +21 -0
- package/dist/domain/processCaptureReactiveSchema.js +68 -0
- package/dist/domain/processCaptureReactiveValidation.js +8 -3
- package/dist/domain/processCaptureValidation.js +8 -10
- package/dist/domain/processComparison.js +12 -16
- package/dist/domain/processObservation.js +5 -6
- package/dist/domain/processReactiveMatching.js +32 -46
- package/dist/domain/processReactiveRuntime.js +4 -8
- package/dist/domain/processReactiveScenario.js +28 -94
- package/dist/domain/processReactiveScenarioPreflight.js +5 -30
- package/dist/domain/processReactiveTransition.js +42 -21
- package/dist/domain/processScenario.js +62 -93
- package/dist/domain/processTraceComparison.js +0 -7
- package/dist/domain/processTraceEvaluation.js +14 -4
- package/dist/domain/processTraceSpecification.js +11 -17
- package/dist/domain/protocolCapture.js +11 -9
- package/dist/domain/reconstructionCoverage.js +62 -129
- package/dist/domain/reconstructionCoverageEvaluation.js +17 -17
- package/dist/domain/reconstructionObligationLedgerSchemas.js +45 -72
- package/dist/domain/reconstructionReadiness.js +1 -2
- package/dist/domain/reconstructionReadinessSchemas.js +66 -40
- package/dist/domain/reconstructionUnknowns.js +3 -3
- package/dist/domain/reconstructionVerification.js +13 -47
- package/dist/domain/reconstructionVerificationSchemas.js +50 -38
- package/dist/domain/referenceSourceGraph.js +53 -61
- package/dist/domain/referenceSourceImportParsing.js +3 -7
- package/dist/domain/replayMachine.js +19 -31
- package/dist/domain/replayMachineRun.js +15 -63
- package/dist/domain/replayMachineRuntime.js +46 -44
- package/dist/domain/replayMachineValues.js +84 -0
- package/dist/domain/residualUnknown.js +25 -30
- package/dist/domain/runtimeCharacterization.js +15 -16
- package/dist/domain/runtimeIdentification.js +48 -47
- package/dist/domain/sourceToBundleComparison.js +11 -87
- package/dist/domain/sourceToBundleComparisonSchemas.js +25 -50
- package/dist/domain/sourceToBundleSignals.js +11 -16
- package/dist/domain/staticRuntimeCorrelation.js +44 -54
- package/dist/domain/symbolAnalysis.js +10 -19
- package/dist/domain/unicodeCodePointOrder.js +12 -0
- package/dist/domain/webBundleAnalysis.js +70 -99
- package/dist/domain/webBundleAnalyzer.js +2 -4
- package/dist/domain/webBundleAnalyzerAst.js +0 -13
- package/dist/domain/webBundleAnalyzerInspection.js +26 -52
- package/dist/domain/webBundleAnalyzerResult.js +7 -24
- package/dist/domain/webCaptureDiff.js +48 -85
- package/dist/domain/webCaptureDiffSchemas.js +86 -0
- package/dist/domain/webContentArtifact.js +1 -10
- package/dist/domain/webMcpDiscovery.js +3 -14
- package/dist/domain/webScreenshot.js +58 -34
- package/dist/domain/zipPackageFormat.js +7 -0
- package/dist/dotnet/ManagedArtifactInspector.js +17 -50
- package/dist/dotnet/ManagedMemberInspector.js +27 -58
- package/dist/dotnet/ManagedMemberInspectorCore.js +14 -51
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +2 -2
- package/dist/dotnet/ManagedMemberRows.js +16 -16
- package/dist/dotnet/ManagedMetadataHeaps.js +26 -8
- package/dist/dotnet/ManagedMetadataInventory.js +21 -30
- package/dist/dotnet/ManagedMetadataInventoryRows.js +57 -63
- package/dist/dotnet/ManagedMetadataLayout.js +3 -5
- package/dist/dotnet/ManagedMethodBodyReader.js +5 -30
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +19 -49
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +13 -42
- package/dist/dotnet/ManagedPeReader.js +2 -2
- package/dist/dotnet/ManagedStaticProvider.js +13 -71
- package/dist/generatedMcpToolCatalog.js +1 -1
- package/dist/generatedPackageMetadata.js +1 -1
- package/dist/ghidra/GhidraAnalysisProfile.js +3 -8
- package/dist/ghidra/GhidraClient.js +5 -13
- package/dist/ghidra/GhidraClientStartup.js +1 -1
- package/dist/ghidra/GhidraClientWire.js +9 -5
- package/dist/ghidra/GhidraDefaults.js +0 -18
- package/dist/ghidra/GhidraDiagnostics.js +0 -2
- package/dist/ghidra/GhidraDoctor.js +16 -12
- package/dist/ghidra/GhidraFunctionValues.js +67 -108
- package/dist/ghidra/GhidraInstallation.js +98 -42
- package/dist/ghidra/GhidraInventoryValues.js +18 -77
- package/dist/ghidra/GhidraLauncher.js +0 -8
- package/dist/ghidra/GhidraProvider.js +32 -31
- package/dist/ghidra/GhidraProviderCapabilities.js +11 -48
- package/dist/ghidra/GhidraRequestQueue.js +6 -30
- package/dist/ghidra/GhidraResponseBuffer.js +1 -7
- package/dist/ghidra/GhidraSessionValues.js +0 -2
- package/dist/ghidra/GhidraSocketConnection.js +1 -1
- package/dist/ghidra/GhidraTransport.js +4 -7
- package/dist/ghidra/protocol.js +19 -42
- package/dist/hopper/BridgeLauncher.js +115 -37
- package/dist/hopper/HopperAnalysisProfile.js +3 -5
- package/dist/hopper/HopperCleanup.js +11 -9
- package/dist/hopper/HopperClient.js +5 -8
- package/dist/hopper/HopperProcessDiagnostic.js +2 -2
- package/dist/hopper/HopperProvider.js +0 -30
- package/dist/hopper/HopperRequestQueue.js +21 -40
- package/dist/hopper/HopperResponseStream.js +1 -9
- package/dist/hopper/HopperSessionValues.js +3 -2
- package/dist/hopper/HopperTargetLease.js +119 -0
- package/dist/hopper/LinuxPrivateDisplayDiagnostic.js +24 -31
- package/dist/hopper/LinuxPrivateDisplayProbe.js +21 -26
- package/dist/hopper/protocol.js +6 -4
- package/dist/main/reload.js +1 -9
- package/dist/main/shutdown.js +1 -1
- package/dist/main/state.js +0 -23
- package/dist/main/transport.js +27 -39
- package/dist/main.js +17 -15
- package/dist/mcpDoctor.js +27 -69
- package/dist/native/CommandRunner.js +18 -25
- package/dist/native/NativeMacOSProvider.js +13 -38
- package/dist/native/NativeMachoInspection.js +1 -1
- package/dist/process/BoundedFileBytes.js +17 -0
- package/dist/process/ExecFileOutput.js +11 -0
- package/dist/process/PendingOperations.js +8 -6
- package/dist/process/PrivateRuntimeRoot.js +17 -0
- package/dist/process/ProcessOwnership.js +67 -130
- package/dist/process/ProcessOwnershipIdentity.js +13 -0
- package/dist/process/ProcessOwnershipObservation.js +87 -0
- package/dist/process/ProcessOwnershipProcessTree.js +22 -0
- package/dist/process/ProviderDeadline.js +8 -12
- package/dist/process/ProviderProcess.js +7 -28
- package/dist/process/WindowsAuthority.js +32 -0
- package/dist/reference/ReferenceSourceReader.js +8 -24
- package/dist/reference/ReferenceSourceReaderEntries.js +11 -39
- package/dist/reference/ReferenceSourceReaderFile.js +13 -31
- package/dist/reference/ReferenceSourceReaderPaths.js +3 -18
- package/dist/reference/ReferenceSourceReaderValidate.js +3 -6
- package/dist/replay/JavaScriptReplayWorker.js +95 -13
- package/dist/replay/JavaScriptReplayWorkerTypes.js +1 -0
- package/dist/replay/LinuxJavaScriptReplayRunner.js +42 -43
- package/dist/replay/LinuxJavaScriptReplaySandbox.js +0 -19
- package/dist/replay/LinuxRuntimeClosure.js +1 -3
- package/dist/replay/ReplayOutcome.js +27 -18
- package/dist/replay/ReplayProcessLifecycle.js +32 -7
- package/dist/replay/ReplaySeccompFile.js +29 -0
- package/dist/replay/ReplayWorkerProtocol.js +33 -30
- package/dist/replay/SystemJavaScriptReplayHost.js +45 -74
- package/dist/server/ProcessCaptureElicitation.js +4 -8
- package/dist/server/createServer.js +145 -119
- package/dist/server/mcpClientMetadata.js +32 -0
- package/dist/server/promptCompletion.js +37 -61
- package/dist/server/recordDerivedEvidence.js +1 -1
- package/dist/server/registerApplicationTools/characterization.js +10 -21
- package/dist/server/registerApplicationTools/compareExportShapes.js +6 -16
- package/dist/server/registerApplicationTools/compareSourceToBundle.js +6 -15
- package/dist/server/registerApplicationTools/compareVersions.js +6 -16
- package/dist/server/registerApplicationTools/controlledReplay.js +8 -15
- package/dist/server/registerApplicationTools/coverage.js +7 -78
- package/dist/server/registerApplicationTools/helpers.js +1 -13
- package/dist/server/registerApplicationTools/obligationLedger.js +4 -8
- package/dist/server/registerApplicationTools/traceFeature.js +6 -15
- package/dist/server/registerApplicationTools/traceSemantics.js +5 -13
- package/dist/server/registerApplicationTools.js +0 -2
- package/dist/server/registerArtifactComparisonTool.js +27 -35
- package/dist/server/registerBrowserScenarioTool.js +3 -8
- package/dist/server/registerBrowserTools.js +36 -81
- package/dist/server/registerBundleComparisonTool.js +10 -16
- package/dist/server/registerCloseLifecycleTool.js +5 -27
- package/dist/server/registerElectronTools.js +29 -65
- package/dist/server/registerEnhancedTools.js +118 -127
- package/dist/server/registerEvidenceTools.js +19 -30
- package/dist/server/registerFunctionComparisonTool.js +35 -34
- package/dist/server/registerInvestigationTools/helpers.js +3 -32
- package/dist/server/registerInvestigationTools.js +36 -148
- package/dist/server/registerJavaScriptRuntimeObservationTools.js +15 -27
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +16 -23
- package/dist/server/registerManagedWorkflowTools/contract.js +2 -3
- package/dist/server/registerManagedWorkflowTools/evidence.js +19 -35
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +4 -14
- package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +4 -14
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +11 -20
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +10 -21
- package/dist/server/registerOfficialTools.js +8 -51
- package/dist/server/registerProcessComparisonTool.js +43 -38
- package/dist/server/registerPrompts.js +19 -17
- package/dist/server/registerReplayMachineTool.js +4 -10
- package/dist/server/registerSessionRecordTools.js +36 -153
- package/dist/server/registerSessionStatusTool.js +18 -96
- package/dist/server/registerSessionTools.js +34 -91
- package/dist/server/sessionAvailabilityPolicy.js +2 -3
- package/dist/server/sessionEvidence.js +9 -15
- package/dist/server/sessionToolPolicies.js +1 -13
- package/dist/server/toolRegistrationOptions.js +4 -192
- package/dist/server/toolResult.js +15 -67
- package/dist/serverIdentity.js +0 -20
- package/install.sh +1 -1
- package/package.json +27 -15
- package/scripts/electron-active-hook-boundaries.cjs +394 -0
- package/scripts/electron-active-hook.cjs +469 -0
- package/scripts/hopper-demo-x11.py +13 -32
- package/scripts/rea.mjs +1 -11
- package/skills/reverse-engineer-anything/SKILL.md +46 -11
- package/skills/reverse-engineer-anything/references/evidence-workflows.md +6 -4
- package/skills/reverse-engineer-anything/references/javascript-applications.md +13 -13
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +12 -8
- package/dist/application/ApplicationWorkflowEvidenceResolver.js +0 -180
- package/dist/application/BoundedJsonFiles.js +0 -86
- package/dist/application/CrossVersionInventory.js +0 -128
- package/dist/application/CrossVersionInvestigation.js +0 -301
- package/dist/application/CrossVersionInvestigationCollections.js +0 -23
- package/dist/application/CrossVersionInvestigationEvidence.js +0 -64
- package/dist/application/CrossVersionInvestigationReplay.js +0 -170
- package/dist/application/DeferredFileAuthorization.js +0 -61
- package/dist/application/DoctorProjection.js +0 -43
- package/dist/application/EnhancedToolPagination.js +0 -22
- package/dist/application/EvidenceReferenceResolver.js +0 -26
- package/dist/application/InvestigationWorkspaceStore.js +0 -204
- package/dist/application/ProcessPairedExperiment.js +0 -72
- package/dist/application/ReconstructionCoverageWorkspaceStore.js +0 -31
- package/dist/application/ReconstructionReadinessService.js +0 -48
- package/dist/cliInvestigationCommands.js +0 -173
- package/dist/domain/boundedCartesianProjection.js +0 -15
- package/dist/domain/investigationWorkspace.js +0 -346
- package/dist/domain/jsonLimits.js +0 -26
- package/dist/domain/knownPageCoverage.js +0 -21
- package/dist/domain/processPairedExperiment.js +0 -128
- package/dist/server/DynamicToolAvailability.js +0 -70
- package/dist/server/LazyToolCatalog.js +0 -134
- package/dist/server/hydrateServerTools.js +0 -191
- package/dist/server/javascriptApplicationResult.js +0 -106
- package/dist/server/permissionFailure.js +0 -12
- package/dist/server/registerApplicationTools/readiness.js +0 -55
- package/dist/server/registerEvidenceResources.js +0 -315
- package/dist/server/registerJavaScriptApplicationGraphResource.js +0 -65
- package/dist/server/registerReconstructionObligationLedgerResource.js +0 -32
- package/dist/server/registerReconstructionReadinessResource.js +0 -32
- package/dist/server/toolInputValidation.js +0 -77
- package/scripts/package-runner-bootstrap.mjs +0 -72
|
@@ -13,8 +13,8 @@ import { assertNotCancelled, assertRealPathAuthority, } from "./ProcessCaptureAu
|
|
|
13
13
|
import { normalizeProcessElapsedTime, normalizeProcessSamples, normalizeProcessText, redactProtocolEvents, } from "./ProcessNormalization.js";
|
|
14
14
|
import { PROCESS_PROVIDER } from "./ProcessEvidence.js";
|
|
15
15
|
import { TerminalRenderer } from "./TerminalRenderer.js";
|
|
16
|
+
import { scheduleProcessInterval } from "./ProcessTimer.js";
|
|
16
17
|
export const buildCaptureResult = (options) => ({
|
|
17
|
-
schema_version: 4,
|
|
18
18
|
manifest: options.manifest,
|
|
19
19
|
normalization: options.scenario.normalization,
|
|
20
20
|
frames: options.frames,
|
|
@@ -33,7 +33,6 @@ export const buildCaptureResult = (options) => ({
|
|
|
33
33
|
shim_events: options.shimEvents,
|
|
34
34
|
protocol_events: redactProtocolEvents(options.replay.events, options.scenario),
|
|
35
35
|
replay_transitions: options.replay.transitions,
|
|
36
|
-
reactive_run: options.reactiveRun,
|
|
37
36
|
event_journal: options.eventJournal,
|
|
38
37
|
files_before: options.before.files,
|
|
39
38
|
files_after: options.after.files,
|
|
@@ -57,10 +56,6 @@ export const buildCaptureResult = (options) => ({
|
|
|
57
56
|
reason: "External network isolation is not enforced by this adapter.",
|
|
58
57
|
},
|
|
59
58
|
],
|
|
60
|
-
cleanup: {
|
|
61
|
-
owned_process_group: "verified",
|
|
62
|
-
temporary_root: "removed",
|
|
63
|
-
},
|
|
64
59
|
});
|
|
65
60
|
const hashFile = async (path) => {
|
|
66
61
|
const hash = createHash("sha256");
|
|
@@ -153,13 +148,12 @@ export const awaitTerminalExit = async ({ terminal, scenario, started, lastOutpu
|
|
|
153
148
|
recordEvent("interaction_events", sequence);
|
|
154
149
|
}
|
|
155
150
|
for (const timer of timers) {
|
|
156
|
-
|
|
157
|
-
clearInterval(timer);
|
|
151
|
+
timer.cancel();
|
|
158
152
|
}
|
|
159
153
|
timers.clear();
|
|
160
154
|
resolveExit({ ...exit, reason });
|
|
161
155
|
});
|
|
162
|
-
const timeout =
|
|
156
|
+
const timeout = scheduleProcessInterval(() => {
|
|
163
157
|
if (signal?.aborted === true) {
|
|
164
158
|
reason = "cancelled";
|
|
165
159
|
terminal.kill("SIGKILL");
|
|
@@ -177,7 +171,7 @@ export const awaitTerminalExit = async ({ terminal, scenario, started, lastOutpu
|
|
|
177
171
|
});
|
|
178
172
|
export const releaseProcessResources = async (options) => {
|
|
179
173
|
for (const timer of options.timers)
|
|
180
|
-
|
|
174
|
+
timer.cancel();
|
|
181
175
|
let failure;
|
|
182
176
|
try {
|
|
183
177
|
await options.replay?.close();
|
|
@@ -228,8 +222,7 @@ export const captureTerminalFrames = (options) => {
|
|
|
228
222
|
options.terminal.onData((data) => {
|
|
229
223
|
options.onOutput();
|
|
230
224
|
const bytes = Buffer.byteLength(data);
|
|
231
|
-
if (
|
|
232
|
-
outputBytes + bytes > options.scenario.limits.output_bytes) {
|
|
225
|
+
if (outputBytes + bytes > options.scenario.limits.output_bytes) {
|
|
233
226
|
truncated = true;
|
|
234
227
|
return;
|
|
235
228
|
}
|
|
@@ -264,6 +257,11 @@ export const resolveProcessResult = (capture, executionFailure, cleanupFailure)
|
|
|
264
257
|
return capture;
|
|
265
258
|
};
|
|
266
259
|
export const prepareProcessCapture = async (scenario, policy, signal, host = systemProcessPreparationHost) => {
|
|
260
|
+
if (policy.status === "disabled")
|
|
261
|
+
throw new ProcessCaptureError("process capture is disabled", {
|
|
262
|
+
userCategory: "permission_required",
|
|
263
|
+
userMessage: processPolicyMessage("process capture is disabled"),
|
|
264
|
+
});
|
|
267
265
|
const decision = authorizeProcessScenario(scenario, policy);
|
|
268
266
|
if (!decision.allowed)
|
|
269
267
|
throw new ProcessCaptureError(decision.reason, {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { snapshotRoots } from "./FilesystemSnapshot.js";
|
|
2
|
+
import { scheduleProcessDelay } from "./ProcessTimer.js";
|
|
2
3
|
/** Classify path-stable filesystem effects between two bounded states. */
|
|
3
4
|
export const classifyFilesystemEffects = (before, after) => {
|
|
4
5
|
const beforeByPath = new Map(before.map((file) => [file.path, file]));
|
|
@@ -8,14 +9,31 @@ export const classifyFilesystemEffects = (before, after) => {
|
|
|
8
9
|
.map((path) => {
|
|
9
10
|
const beforeFile = beforeByPath.get(path) ?? null;
|
|
10
11
|
const afterFile = afterByPath.get(path) ?? null;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
if (beforeFile === null) {
|
|
13
|
+
if (afterFile === null)
|
|
14
|
+
throw new TypeError(`Filesystem effect ${path} has no file state`);
|
|
15
|
+
return {
|
|
16
|
+
path,
|
|
17
|
+
status: "created",
|
|
18
|
+
before: null,
|
|
19
|
+
after: afterFile,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
if (afterFile === null)
|
|
23
|
+
return {
|
|
24
|
+
path,
|
|
25
|
+
status: "deleted",
|
|
26
|
+
before: beforeFile,
|
|
27
|
+
after: null,
|
|
28
|
+
};
|
|
29
|
+
return {
|
|
30
|
+
path,
|
|
31
|
+
status: JSON.stringify(beforeFile) === JSON.stringify(afterFile)
|
|
32
|
+
? "unchanged"
|
|
33
|
+
: "modified",
|
|
34
|
+
before: beforeFile,
|
|
35
|
+
after: afterFile,
|
|
36
|
+
};
|
|
19
37
|
});
|
|
20
38
|
};
|
|
21
39
|
/** Coordinates named lifecycle filesystem observations without overlapping scans. */
|
|
@@ -47,7 +65,7 @@ export class ProcessCheckpoints {
|
|
|
47
65
|
for (const checkpoint of scenario.checkpoints) {
|
|
48
66
|
if (checkpoint.trigger.type !== "time")
|
|
49
67
|
continue;
|
|
50
|
-
const timer =
|
|
68
|
+
const timer = scheduleProcessDelay(checkpoint.trigger.at_ms, () => this.capture(checkpoint.name));
|
|
51
69
|
this.#timers.add(timer);
|
|
52
70
|
}
|
|
53
71
|
}
|
|
@@ -124,7 +142,7 @@ export class ProcessCheckpoints {
|
|
|
124
142
|
/** Finish pending snapshots and return them in observation order. */
|
|
125
143
|
async finish(after) {
|
|
126
144
|
for (const timer of this.#timers)
|
|
127
|
-
|
|
145
|
+
timer.cancel();
|
|
128
146
|
await this.#pending;
|
|
129
147
|
const previous = this.#captures.at(-1)?.files ?? [];
|
|
130
148
|
const index = this.#captures.length;
|
|
@@ -141,7 +159,7 @@ export class ProcessCheckpoints {
|
|
|
141
159
|
/** Cancel scheduled captures and await any snapshot already in progress. */
|
|
142
160
|
async dispose() {
|
|
143
161
|
for (const timer of this.#timers)
|
|
144
|
-
|
|
162
|
+
timer.cancel();
|
|
145
163
|
this.#timers.clear();
|
|
146
164
|
await this.#pending;
|
|
147
165
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
+
import { projectPermissionFailure } from "./PermissionFailure.js";
|
|
1
2
|
import { readFile } from "node:fs/promises";
|
|
2
3
|
import { parseConfig } from "../config.js";
|
|
3
|
-
import { AnalysisError, AnalysisInputError,
|
|
4
|
+
import { AnalysisError, AnalysisInputError, projectAnalysisError, } from "../domain/errors.js";
|
|
4
5
|
import { createEvidence, parseEvidence } from "../domain/evidence.js";
|
|
5
6
|
import { jsonValueSchema } from "../domain/jsonValue.js";
|
|
6
7
|
import { projectInputIssues } from "../domain/inputIssueProjection.js";
|
|
7
8
|
import { processTraceSpecificationSchema } from "../domain/processTraceComparison.js";
|
|
8
|
-
import { compareProcessCaptures,
|
|
9
|
+
import { compareProcessCaptures, parseProcessScenario, parseProcessCapture, } from "../domain/processCapture.js";
|
|
9
10
|
import { captureProcessScenario } from "./ProcessHarness.js";
|
|
10
11
|
import { processCapturePermissionRequest } from "./ProcessCapturePermission.js";
|
|
11
12
|
import { PROCESS_PROVIDER, createProcessCaptureEvidence, } from "./ProcessEvidence.js";
|
|
12
13
|
import { loadConfiguredPermissionAuthority } from "./PermissionConfiguration.js";
|
|
13
|
-
const MAX_INPUT_BYTES = 64 * 1024 * 1024;
|
|
14
14
|
/** Capture one JSON scenario through the same policy and evidence contract as MCP. */
|
|
15
15
|
export const captureProcessScenarioFile = async (path) => {
|
|
16
16
|
try {
|
|
@@ -30,11 +30,7 @@ export const captureProcessScenarioFile = async (path) => {
|
|
|
30
30
|
return cliAnalysisError(authority.error);
|
|
31
31
|
const authorized = await authority.value.authorize(processCapturePermissionRequest(scenario), "read");
|
|
32
32
|
if (!authorized.ok)
|
|
33
|
-
return cliAnalysisError(authorized.error
|
|
34
|
-
? authorized.error
|
|
35
|
-
: new AnalysisProtocolError(authorized.error.message, {
|
|
36
|
-
cause: authorized.error,
|
|
37
|
-
}));
|
|
33
|
+
return cliAnalysisError(projectPermissionFailure(authorized.error));
|
|
38
34
|
const captured = await captureProcessScenario(scenario, config.value.processExecutionPolicy);
|
|
39
35
|
if (!captured.ok)
|
|
40
36
|
return cliAnalysisError(captured.error);
|
|
@@ -58,9 +54,7 @@ export const compareProcessEvidenceFiles = async (leftPath, rightPath, traceSpec
|
|
|
58
54
|
traceSpecification,
|
|
59
55
|
});
|
|
60
56
|
return createEvidence(undefined, PROCESS_PROVIDER, {
|
|
61
|
-
predicateType:
|
|
62
|
-
? "rea.process-comparison/v3"
|
|
63
|
-
: "rea.process-comparison/v4",
|
|
57
|
+
predicateType: "rea.process-comparison",
|
|
64
58
|
operation: "compare_process_captures",
|
|
65
59
|
parameters: {
|
|
66
60
|
left_evidence_id: left.id,
|
|
@@ -92,11 +86,9 @@ const parseCaptureEvidence = (input) => {
|
|
|
92
86
|
throw invalidCaptureEvidence();
|
|
93
87
|
}
|
|
94
88
|
if (evidence.operation !== "capture_process_scenario" ||
|
|
95
|
-
evidence.predicate_type !== "rea.process-capture
|
|
89
|
+
evidence.predicate_type !== "rea.process-capture" ||
|
|
96
90
|
evidence.provider.id !== PROCESS_PROVIDER.id ||
|
|
97
91
|
evidence.provider.version !== PROCESS_PROVIDER.version) {
|
|
98
|
-
if (evidence.predicate_type === "rea.process-capture/v3")
|
|
99
|
-
throw new ProcessCliFailure("invalid_input", LEGACY_PROCESS_CAPTURE_MESSAGE);
|
|
100
92
|
throw new ProcessCliFailure("invalid_input", "Capture evidence is not from the current process-capture workflow. Create new capture evidence, then try again.");
|
|
101
93
|
}
|
|
102
94
|
try {
|
|
@@ -125,10 +117,9 @@ const readJson = async (path) => {
|
|
|
125
117
|
catch {
|
|
126
118
|
throw new ProcessCliFailure("invalid_input", "Process input file could not be read. Check that the path exists and is readable.");
|
|
127
119
|
}
|
|
128
|
-
if (bytes.length > MAX_INPUT_BYTES)
|
|
129
|
-
throw new ProcessCliFailure("truncated", "Process input file is too large. Reduce it below 64 MiB, then try again.");
|
|
130
120
|
try {
|
|
131
|
-
|
|
121
|
+
const parsed = JSON.parse(bytes.toString("utf8"));
|
|
122
|
+
return parsed;
|
|
132
123
|
}
|
|
133
124
|
catch {
|
|
134
125
|
throw new ProcessCliFailure("invalid_input", "Process input file is not valid JSON. Repair the file, then try again.");
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { createEvidence } from "../domain/evidence.js";
|
|
2
2
|
import { jsonValueSchema } from "../domain/jsonValue.js";
|
|
3
|
-
|
|
4
|
-
/** Provider identity for controlled Process Capture v4 evidence. */
|
|
3
|
+
/** Provider identity for controlled process capture evidence. */
|
|
5
4
|
export const PROCESS_PROVIDER = {
|
|
6
5
|
id: "rea-process",
|
|
7
6
|
name: "REA deterministic process harness",
|
|
@@ -17,14 +16,13 @@ const processEvidenceParameters = (scenario) => ({
|
|
|
17
16
|
command_shim_count: scenario.command_shims.length,
|
|
18
17
|
normalization: scenario.normalization,
|
|
19
18
|
});
|
|
20
|
-
/** Create one canonical observed
|
|
19
|
+
/** Create one canonical observed process capture Evidence record. */
|
|
21
20
|
export const createProcessCaptureEvidence = (scenario, capture) => {
|
|
22
|
-
const validatedCapture = parseProcessCapture(capture);
|
|
23
21
|
return createEvidence(undefined, PROCESS_PROVIDER, {
|
|
24
|
-
predicateType: "rea.process-capture
|
|
22
|
+
predicateType: "rea.process-capture",
|
|
25
23
|
operation: "capture_process_scenario",
|
|
26
24
|
parameters: processEvidenceParameters(scenario),
|
|
27
|
-
result: jsonValueSchema.parse(
|
|
25
|
+
result: jsonValueSchema.parse(capture),
|
|
28
26
|
confidence: "observed",
|
|
29
27
|
authority: "controlled-replay",
|
|
30
28
|
environment: {
|
|
@@ -33,6 +31,6 @@ export const createProcessCaptureEvidence = (scenario, capture) => {
|
|
|
33
31
|
architecture: process.arch,
|
|
34
32
|
isolation: "process",
|
|
35
33
|
},
|
|
36
|
-
limitations:
|
|
34
|
+
limitations: capture.limitations,
|
|
37
35
|
});
|
|
38
36
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { parseProcessCapture } from "../domain/processCapture.js";
|
|
2
2
|
import { err, ok } from "../domain/result.js";
|
|
3
3
|
import { ProcessCaptureError, processCaptureCancelled, } from "./ProcessCaptureError.js";
|
|
4
4
|
export { ProcessCaptureError } from "./ProcessCaptureError.js";
|
|
@@ -33,11 +33,35 @@ const createTerminalRenderer = (scenario, temporaryRoot, terminalPid, recordEven
|
|
|
33
33
|
columns: scenario.terminal.columns,
|
|
34
34
|
rows: scenario.terminal.rows,
|
|
35
35
|
scrollback: scenario.terminal.scrollback,
|
|
36
|
-
maxFrames: scenario.limits.frames,
|
|
37
36
|
maxBytes: scenario.limits.output_bytes,
|
|
38
37
|
normalize: (value) => normalizeProcessText(value, scenario, temporaryRoot, terminalPid()),
|
|
39
38
|
recordEvent,
|
|
40
39
|
});
|
|
40
|
+
/**
|
|
41
|
+
* Wait until the capture journal stops growing.
|
|
42
|
+
*
|
|
43
|
+
* node-pty reports buffered output through `onData` callbacks rather than an
|
|
44
|
+
* awaitable read, so chunks can still be in flight after the child exits. The
|
|
45
|
+
* quiet interval is measured in elapsed time rather than scheduler turns:
|
|
46
|
+
* consecutive `setImmediate` turns elapse in microseconds, so any fixed number
|
|
47
|
+
* of them finishes long before a delayed pty callback under host contention,
|
|
48
|
+
* which is exactly when the trailing chunk matters. `maxWaitMs` bounds the
|
|
49
|
+
* total wait so a pathological stream cannot stall exit.
|
|
50
|
+
*/
|
|
51
|
+
const settleTrailingJournal = async (journal, quietMs = 25, maxWaitMs = 500) => {
|
|
52
|
+
const deadline = Date.now() + maxWaitMs;
|
|
53
|
+
let observed = journal.length;
|
|
54
|
+
let lastChangeAt = Date.now();
|
|
55
|
+
while (Date.now() < deadline) {
|
|
56
|
+
await new Promise((resolve) => setTimeout(resolve, 4));
|
|
57
|
+
if (journal.length !== observed) {
|
|
58
|
+
observed = journal.length;
|
|
59
|
+
lastChangeAt = Date.now();
|
|
60
|
+
}
|
|
61
|
+
else if (Date.now() - lastChangeAt >= quietMs)
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
41
65
|
const reactiveCapture = (options, protocolEvents) => ({
|
|
42
66
|
...options,
|
|
43
67
|
processSamples: options.samples,
|
|
@@ -154,24 +178,28 @@ const finishProcessRun = async (options) => {
|
|
|
154
178
|
});
|
|
155
179
|
await options.runtime?.reactive?.coordinator.close();
|
|
156
180
|
let { capture, executionFailure } = options;
|
|
157
|
-
|
|
158
|
-
|
|
181
|
+
let verifiedCapture;
|
|
182
|
+
if (capture !== undefined && cleanupFailure === undefined) {
|
|
183
|
+
const settlement = capture.settlement.state === "quiesced"
|
|
184
|
+
? { ...capture.settlement, cleanup_outcome: "not_required" }
|
|
185
|
+
: { ...capture.settlement, cleanup_outcome: "cleaned" };
|
|
186
|
+
const completedCapture = {
|
|
159
187
|
...capture,
|
|
160
188
|
reactive_run: projectProcessReactiveRun(options.runtime?.reactive),
|
|
161
|
-
settlement
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
: cleanupFailure === undefined
|
|
166
|
-
? "cleaned"
|
|
167
|
-
: "failed",
|
|
189
|
+
settlement,
|
|
190
|
+
cleanup: {
|
|
191
|
+
owned_process_group: "verified",
|
|
192
|
+
temporary_root: "removed",
|
|
168
193
|
},
|
|
169
194
|
};
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
195
|
+
try {
|
|
196
|
+
verifiedCapture = parseProcessCapture(completedCapture);
|
|
197
|
+
}
|
|
198
|
+
catch (cause) {
|
|
199
|
+
executionFailure = new ProcessCaptureError(`process capture validation failed${cause instanceof Error ? `: ${cause.message}` : ""}`, { cause });
|
|
200
|
+
}
|
|
173
201
|
}
|
|
174
|
-
return resolveProcessResult(
|
|
202
|
+
return resolveProcessResult(verifiedCapture, executionFailure, cleanupFailure);
|
|
175
203
|
};
|
|
176
204
|
const completeCapture = async (options) => {
|
|
177
205
|
const { runtime, scenario } = options;
|
|
@@ -184,13 +212,26 @@ const completeCapture = async (options) => {
|
|
|
184
212
|
}
|
|
185
213
|
throw processCaptureCancelled();
|
|
186
214
|
}
|
|
215
|
+
const settlement = await observeSettlement(options.runId, selectCapturedProcessGroupIds(runtime.terminal.pid, options.samples), scenario.settle_ms, options.recordEvent);
|
|
216
|
+
runtime.checkpoints.trigger("settled");
|
|
217
|
+
const samplingPartial = (await runtime.stopSampler()).partial;
|
|
187
218
|
if (runtime.reactive !== undefined) {
|
|
219
|
+
// Process, filesystem, shim, and protocol observations can be recorded
|
|
220
|
+
// during settlement after the PTY exits. Make target loss terminal only
|
|
221
|
+
// after that journal has drained, otherwise the coordinator's control
|
|
222
|
+
// priority discards a valid multi-source completion predicate.
|
|
223
|
+
//
|
|
224
|
+
// Draining the coordinator is not sufficient on its own: node-pty delivers
|
|
225
|
+
// buffered output through onData callbacks, which run outside the
|
|
226
|
+
// coordinator's queue. A trailing chunk that has not been delivered yet has
|
|
227
|
+
// produced no journal entry, so the drain has nothing to wait for and the
|
|
228
|
+
// target is declared lost while a terminal trigger is still satisfiable.
|
|
229
|
+
// Let any trailing chunks land first.
|
|
230
|
+
await settleTrailingJournal(options.eventJournal);
|
|
231
|
+
await runtime.reactive.coordinator.drain();
|
|
188
232
|
await runtime.reactive.coordinator.submit({ kind: "target_lost" });
|
|
189
233
|
runtime.reactive.unsubscribe();
|
|
190
234
|
}
|
|
191
|
-
const settlement = await observeSettlement(options.runId, selectCapturedProcessGroupIds(runtime.terminal.pid, options.samples), scenario.settle_ms, options.recordEvent);
|
|
192
|
-
runtime.checkpoints.trigger("settled");
|
|
193
|
-
const samplingPartial = (await runtime.stopSampler()).partial;
|
|
194
235
|
assertNotCancelled(options.signal);
|
|
195
236
|
const after = await snapshotRoots(scenario, options.signal);
|
|
196
237
|
const renderedFrames = await runtime.renderer.frames();
|
|
@@ -210,7 +251,6 @@ const completeCapture = async (options) => {
|
|
|
210
251
|
exit: { ...options.exit, reason },
|
|
211
252
|
samples: options.samples,
|
|
212
253
|
replay: runtime.replay,
|
|
213
|
-
reactiveRun: projectProcessReactiveRun(runtime.reactive),
|
|
214
254
|
before: options.before,
|
|
215
255
|
after,
|
|
216
256
|
truncated,
|
|
@@ -221,7 +261,7 @@ const completeCapture = async (options) => {
|
|
|
221
261
|
interactions: options.interactions,
|
|
222
262
|
checkpoints,
|
|
223
263
|
shimEvents: normalizedShimEvents(runtime, scenario, options.temporaryRoot),
|
|
224
|
-
settlement
|
|
264
|
+
settlement,
|
|
225
265
|
manifest,
|
|
226
266
|
eventJournal: options.eventJournal,
|
|
227
267
|
});
|
|
@@ -39,9 +39,10 @@ export const normalizeProcessSamples = (samples, scenario, rootPid) => {
|
|
|
39
39
|
mapping.set(identifier, mapping.size + 1);
|
|
40
40
|
const normalizeCommand = (command) => {
|
|
41
41
|
const normalized = normalizeProcessText(command, scenario, "<no-temporary-root>", rootPid);
|
|
42
|
-
|
|
42
|
+
const withNormalizedPids = scenario.normalization.pids
|
|
43
43
|
? normalizePidTokens(normalized, identifiers)
|
|
44
44
|
: normalized;
|
|
45
|
+
return withNormalizedPids.trim();
|
|
45
46
|
};
|
|
46
47
|
return samples.map((sample) => ({
|
|
47
48
|
at_ms: normalizeProcessElapsedTime(sample.at_ms, scenario.normalization.time_bucket_ms),
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { commitProcessReactiveProposal, createProcessReactiveSnapshot, reduceProcessReactiveScenario, } from "../domain/processReactiveRuntime.js";
|
|
2
|
+
import { scheduleProcessDelay } from "./ProcessTimer.js";
|
|
2
3
|
const systemTimerHost = {
|
|
3
|
-
schedule: (callback, delayMs) =>
|
|
4
|
-
const timer = setTimeout(callback, delayMs);
|
|
5
|
-
return { cancel: () => clearTimeout(timer) };
|
|
6
|
-
},
|
|
4
|
+
schedule: (callback, delayMs) => scheduleProcessDelay(delayMs, callback),
|
|
7
5
|
};
|
|
8
6
|
/**
|
|
9
7
|
* Serializes live observations, deadlines, and effect commits for one run.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createProcessObservation } from "../domain/processObservation.js";
|
|
2
|
+
import { normalizeProcessElapsedTime } from "./ProcessNormalization.js";
|
|
2
3
|
const elapsed = (host) => Math.max(0, host.now() - host.startedAtMs);
|
|
3
4
|
const interactionData = (action) => {
|
|
4
5
|
if (action.type === "send_input")
|
|
@@ -20,12 +21,17 @@ const interactionType = (action) => {
|
|
|
20
21
|
return "stdin_close";
|
|
21
22
|
return "signal";
|
|
22
23
|
};
|
|
23
|
-
const performTerminalAction = (
|
|
24
|
+
const performTerminalAction = (host, terminal, action, atMs) => {
|
|
24
25
|
if (action.type === "send_input")
|
|
25
26
|
terminal.write(action.data);
|
|
26
27
|
else if (action.type === "resize") {
|
|
27
28
|
terminal.resize(action.columns, action.rows);
|
|
28
|
-
|
|
29
|
+
// Rendered frames share the normalized clock used by captured terminal
|
|
30
|
+
// frames and by the scheduled-event resize path. Passing the raw elapsed
|
|
31
|
+
// time here stamped this frame on a different clock, so the next bucketed
|
|
32
|
+
// frame could appear to move backwards and fail capture validation with
|
|
33
|
+
// "rendered_frames: timestamps must be ordered".
|
|
34
|
+
host.renderer.resize(action.columns, action.rows, normalizeProcessElapsedTime(atMs, host.timeBucketMs));
|
|
29
35
|
}
|
|
30
36
|
else if (action.type === "close_stdin")
|
|
31
37
|
terminal.closeInput();
|
|
@@ -67,7 +73,7 @@ const executeTerminalAction = (host, action) => {
|
|
|
67
73
|
const atMs = elapsed(host);
|
|
68
74
|
let outcome = "dispatched";
|
|
69
75
|
try {
|
|
70
|
-
performTerminalAction(
|
|
76
|
+
performTerminalAction(host, terminal, action, atMs);
|
|
71
77
|
}
|
|
72
78
|
catch {
|
|
73
79
|
outcome = "failed";
|
|
@@ -49,6 +49,7 @@ export const startProcessReactiveHarness = (options) => {
|
|
|
49
49
|
journal: options.capture.journal,
|
|
50
50
|
startedAtMs: options.started,
|
|
51
51
|
now: Date.now,
|
|
52
|
+
timeBucketMs: options.scenario.normalization.time_bucket_ms,
|
|
52
53
|
}, actions, signal),
|
|
53
54
|
},
|
|
54
55
|
onDecision: (decision, input) => {
|
|
@@ -89,12 +90,17 @@ export const startProcessReactiveHarness = (options) => {
|
|
|
89
90
|
};
|
|
90
91
|
};
|
|
91
92
|
/** Project internal reducer state into the stable Process Capture shape. */
|
|
92
|
-
export const projectProcessReactiveRun = (harness) =>
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
93
|
+
export const projectProcessReactiveRun = (harness) => {
|
|
94
|
+
if (harness === undefined)
|
|
95
|
+
return null;
|
|
96
|
+
const snapshot = harness.coordinator.snapshot;
|
|
97
|
+
const completion = snapshot.status === "running"
|
|
98
|
+
? { status: snapshot.status, outcome: null }
|
|
99
|
+
: { status: snapshot.status, outcome: snapshot.outcome };
|
|
100
|
+
return {
|
|
101
|
+
...completion,
|
|
102
|
+
active_state: snapshot.active_state,
|
|
103
|
+
transitions: snapshot.transitions,
|
|
99
104
|
controls: harness.controls,
|
|
100
105
|
};
|
|
106
|
+
};
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { execFile } from "node:child_process";
|
|
2
1
|
import { readFile, readdir } from "node:fs/promises";
|
|
3
|
-
import {
|
|
2
|
+
import { execFileOutput } from "../process/ExecFileOutput.js";
|
|
4
3
|
import { readProcessRunId } from "../process/ProcessOwnership.js";
|
|
5
|
-
const execFileAsync = promisify(execFile);
|
|
6
4
|
const PROC_READ_CONCURRENCY = 64;
|
|
7
5
|
/** Prove that forkpty completed session setup and installed the run token. */
|
|
8
6
|
export const isInitializedPtyRoot = (options) => {
|
|
@@ -210,7 +208,7 @@ const sampleLinux = async (context) => {
|
|
|
210
208
|
return rows;
|
|
211
209
|
};
|
|
212
210
|
const readPsRows = async (signal) => {
|
|
213
|
-
const { stdout } = await
|
|
211
|
+
const { stdout } = await execFileOutput("ps", ["-axo", "pid=,ppid=,pgid=,sess=,command="], { signal });
|
|
214
212
|
return stdout
|
|
215
213
|
.split("\n")
|
|
216
214
|
.map((line) => /\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(.*)/u.exec(line))
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const systemTimerScheduler = (callback, delayMs) => {
|
|
2
|
+
const timer = setTimeout(callback, delayMs);
|
|
3
|
+
return { cancel: () => clearTimeout(timer) };
|
|
4
|
+
};
|
|
5
|
+
/** Schedule a delay using consecutive Node timers without shortening long waits. */
|
|
6
|
+
export const scheduleProcessDelay = (delayMs, callback, schedule = systemTimerScheduler) => {
|
|
7
|
+
if (!Number.isSafeInteger(delayMs) || delayMs < 0)
|
|
8
|
+
throw new RangeError("Process delay must be a nonnegative safe integer");
|
|
9
|
+
const maximumTimerDelay = 2_147_483_647;
|
|
10
|
+
let remaining = delayMs;
|
|
11
|
+
let timer;
|
|
12
|
+
let cancelled = false;
|
|
13
|
+
const scheduleNext = () => {
|
|
14
|
+
if (cancelled)
|
|
15
|
+
return;
|
|
16
|
+
const interval = Math.min(remaining, maximumTimerDelay);
|
|
17
|
+
timer = schedule(() => {
|
|
18
|
+
if (cancelled)
|
|
19
|
+
return;
|
|
20
|
+
remaining -= interval;
|
|
21
|
+
if (remaining === 0)
|
|
22
|
+
callback();
|
|
23
|
+
else
|
|
24
|
+
scheduleNext();
|
|
25
|
+
}, interval);
|
|
26
|
+
};
|
|
27
|
+
scheduleNext();
|
|
28
|
+
return {
|
|
29
|
+
cancel: () => {
|
|
30
|
+
cancelled = true;
|
|
31
|
+
timer?.cancel();
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
/** Create an owned interval that shares process-capture cancellation handling. */
|
|
36
|
+
export const scheduleProcessInterval = (callback, intervalMs) => {
|
|
37
|
+
const timer = setInterval(callback, intervalMs);
|
|
38
|
+
return { cancel: () => clearInterval(timer) };
|
|
39
|
+
};
|