rea-agents 3.2.1 → 4.0.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 +183 -332
- package/bridge/ghidra/ReaGhidraBridge.java +561 -74
- package/bridge/hopper_bridge.py +70 -27
- package/bridge/native/ReaNativeUI.swift +157 -0
- package/dist/application/AnalysisContextQueries.js +19 -5
- package/dist/application/AnalysisSnapshotCache.js +30 -11
- package/dist/application/AppleAssetCatalogAnalysis.js +171 -0
- package/dist/application/ArtifactExtractionDestination.js +0 -12
- package/dist/application/ArtifactGraphConstruction.js +44 -11
- package/dist/application/ArtifactInventory/classify.js +7 -15
- package/dist/application/ArtifactInventory/hash.js +4 -2
- package/dist/application/ArtifactInventory/policy.js +2 -17
- package/dist/application/ArtifactInventory/reader.js +3 -3
- package/dist/application/ArtifactInventory/scanCanonical.js +2 -2
- package/dist/application/ArtifactInventory/scanReader.js +12 -4
- package/dist/application/ArtifactInventory/types.js +0 -3
- package/dist/application/BinarySession.js +28 -43
- package/dist/application/BinarySessionExecution.js +37 -1
- package/dist/application/BinaryTargetResolver.js +50 -4
- package/dist/application/BrowserEvidence.js +36 -7
- package/dist/application/BrowserObservationService.js +17 -44
- package/dist/application/BrowserScenarioCaptureService.js +2 -35
- package/dist/application/BrowserScenarioEvidence.js +13 -9
- package/dist/application/CapabilityClientRequirements.js +2 -11
- package/dist/application/CapabilityInventory.js +21 -35
- package/dist/application/ClientConfigurationDocument.js +84 -7
- package/dist/application/ClientRegistrationIdentity.js +32 -0
- package/dist/application/ClientRegistrationStatus.js +59 -6
- package/dist/application/DirectAnalysis.js +37 -58
- package/dist/application/DirectAnalysisStatus.js +4 -4
- package/dist/application/Doctor.js +89 -80
- package/dist/application/DoctorDiagnostics.js +2 -26
- package/dist/application/DoctorScope.js +8 -14
- package/dist/application/ElectronActiveEvidence.js +10 -27
- package/dist/application/ElectronActiveObservationService.js +9 -36
- package/dist/application/ElectronBoundaryAnalysis.js +2 -0
- package/dist/application/ElectronBoundaryGraphNative.js +1 -1
- package/dist/application/ElectronEvidence.js +8 -3
- package/dist/application/ElectronObservationService.js +9 -25
- package/dist/application/EnhancedLiteralTracing.js +4 -8
- package/dist/application/EnhancedTools.js +15 -35
- package/dist/application/FilesystemSnapshot.js +7 -8
- package/dist/application/JavaScriptApplicationEvidenceGraph.js +2 -1
- package/dist/application/JavaScriptApplicationWorkflowService.js +31 -7
- package/dist/application/JavaScriptArtifactAnalysis.js +6 -4
- package/dist/application/JavaScriptArtifactFiles.js +5 -0
- package/dist/application/JavaScriptArtifactPathResolution.js +179 -47
- package/dist/application/JavaScriptRuntimeObservationEvidence.js +6 -3
- package/dist/application/JavaScriptRuntimeObservationService.js +9 -25
- package/dist/application/JavaScriptRuntimeReconciliationService.js +45 -4
- package/dist/application/JavaScriptSemanticGraphAsyncProjection.js +11 -0
- package/dist/application/JavaScriptSemanticGraphChildProcessProjection.js +11 -0
- package/dist/application/JavaScriptSemanticGraphDataProjection.js +11 -0
- package/dist/application/JavaScriptSemanticGraphFlowProjection.js +14 -5
- package/dist/application/JsonFiles.js +1 -1
- package/dist/application/LazyAnalysisProvider.js +27 -6
- package/dist/application/ManagedMemberComparisonService.js +19 -6
- package/dist/application/NativeApiInspection.js +2 -0
- package/dist/application/NativeCallRoutes.js +72 -0
- package/dist/application/NativeDispatchMetadataInspection.js +33 -0
- package/dist/application/NativeUiActionTrace.js +73 -49
- package/dist/application/NativeValueTrace.js +320 -0
- package/dist/application/ProcessCaptureCapability.js +32 -5
- package/dist/application/ProcessCaptureEnvironment.js +9 -26
- package/dist/application/ProcessCaptureError.js +1 -5
- package/dist/application/ProcessCaptureJournal.js +3 -40
- package/dist/application/ProcessCaptureLifecycle.js +102 -111
- package/dist/application/ProcessCli.js +18 -25
- package/dist/application/ProcessEvidence.js +5 -7
- package/dist/application/ProcessFilesystemEffects.js +36 -0
- package/dist/application/ProcessHarness.js +41 -120
- package/dist/application/ProcessNormalization.js +2 -17
- package/dist/application/ProcessScenarioRuntimeValidation.js +76 -0
- package/dist/application/ReferenceSourceImport.js +3 -4
- package/dist/application/Setup.js +236 -84
- package/dist/application/SetupClientConfiguration.js +14 -9
- package/dist/application/SetupPlan.js +138 -86
- package/dist/application/SetupSkill.js +0 -1
- package/dist/application/SupportedClients.js +102 -21
- package/dist/application/Uninstall.js +31 -20
- package/dist/application/Update.js +93 -0
- package/dist/application/UpdateMaintenance.js +108 -0
- package/dist/application/UpdateRuntime.js +126 -0
- package/dist/application/runtime.js +13 -2
- package/dist/artifacts/ArtifactPaths.js +6 -8
- package/dist/artifacts/ArtifactProvider.js +94 -41
- package/dist/artifacts/AsarArtifactReader.js +19 -4
- package/dist/artifacts/KeyedArchiveReader.js +110 -0
- package/dist/artifacts/MachOSliceArtifactReader.js +53 -5
- package/dist/artifacts/ZipArtifactReader.js +18 -1
- package/dist/browser/BrowserScenarioSecrets.js +28 -1
- package/dist/browser/CdpBrowserProvider.js +36 -15
- package/dist/browser/CdpCaptureDocuments.js +22 -8
- package/dist/browser/CdpCaptureEventHandlers.js +14 -5
- package/dist/browser/CdpCaptureEventHelpers.js +13 -0
- package/dist/browser/CdpCaptureEvents.js +10 -1
- package/dist/browser/CdpElectronInspection.js +5 -10
- package/dist/browser/CdpElectronProvider.js +1 -5
- package/dist/browser/CdpElectronScripts.js +1 -1
- package/dist/browser/CdpEndpoint.js +3 -2
- package/dist/browser/CdpObservationSession.js +14 -10
- package/dist/browser/CdpPageCapture.js +1 -1
- package/dist/browser/CdpPageCaptureScripts.js +1 -1
- package/dist/browser/CdpSafeMetadata.js +5 -4
- package/dist/browser/CdpScreenshot.js +16 -5
- package/dist/browser/CdpTargetSession.js +25 -4
- package/dist/browser/CdpWebMcpDiscovery.js +93 -20
- package/dist/browser/JavaScriptRuntimeScope.js +28 -2
- package/dist/browser/PlaywrightBrowserScenarioProvider.js +9 -8
- package/dist/browser/PlaywrightElectronActiveActions.js +3 -10
- package/dist/browser/PlaywrightElectronActiveProvider.js +5 -5
- package/dist/browser/PlaywrightScenarioActions.js +1 -1
- package/dist/browser/PlaywrightScenarioArtifacts.js +13 -25
- package/dist/browser/PlaywrightScenarioBrowser.js +28 -25
- package/dist/browser/PlaywrightScenarioEvents.js +82 -93
- package/dist/browser/PlaywrightScenarioSession.js +27 -123
- package/dist/browser/PngVisualDiff.js +22 -3
- package/dist/browser/V8InspectorCaptureProjection.js +7 -1
- package/dist/browser/V8InspectorProvider.js +60 -7
- package/dist/browser/WebSourceMapFetcher.js +99 -53
- package/dist/cli/artifactCommands.js +56 -12
- package/dist/cli/coreAnalysisCommands.js +110 -0
- package/dist/cli/managedCommands.js +1 -31
- package/dist/cli/setupCommands.js +16 -14
- package/dist/cli/utilityCommands.js +61 -4
- package/dist/cli.js +5 -7
- package/dist/cliApplicationCommands.js +0 -83
- package/dist/cliBrowserAdvancedCommands.js +7 -11
- package/dist/cliBrowserCommands.js +15 -23
- package/dist/cliBrowserContext.js +3 -24
- package/dist/cliBrowserScenarioCommands.js +2 -10
- package/dist/cliCommandNames.js +82 -7
- package/dist/cliElectronCommands.js +10 -36
- package/dist/cliJavaScriptRuntimeCommands.js +6 -30
- package/dist/cliJsonInput.js +4 -2
- package/dist/cliLogging.js +16 -7
- package/dist/cliObservationOptions.js +1 -1
- package/dist/cliOutput.js +2 -4
- package/dist/cliProcessCommands.js +6 -33
- package/dist/cliSetup.js +90 -160
- package/dist/config/environment.js +2 -78
- package/dist/config/parseConfig.js +18 -109
- package/dist/config/parsers.js +0 -23
- package/dist/contracts/applicationToolContracts.js +1 -118
- package/dist/contracts/artifactToolContracts.js +11 -19
- package/dist/contracts/browserScenarioToolContracts.js +1 -5
- package/dist/contracts/browserToolContracts.js +9 -16
- package/dist/contracts/electronToolContracts.js +5 -6
- package/dist/contracts/enhancedInputs.js +3 -2
- package/dist/contracts/errorSchemas.js +16 -40
- package/dist/contracts/functionWorkflowToolContracts.js +2 -2
- package/dist/contracts/javascriptApplicationWorkflowExamples.js +2 -2
- package/dist/contracts/javascriptRuntimeObservationToolContracts.js +4 -4
- package/dist/contracts/javascriptRuntimeReconciliationExample.js +1 -1
- package/dist/contracts/managedToolContracts.js +7 -4
- package/dist/contracts/managedWorkflowExamples.js +0 -22
- package/dist/contracts/managedWorkflowToolContracts.js +16 -31
- package/dist/contracts/nativeToolContracts.js +9 -0
- package/dist/contracts/promptContracts.js +6 -6
- package/dist/contracts/sessionToolSchemas.js +3 -3
- package/dist/contracts/toolContractExamples.js +4 -3
- package/dist/contracts/toolContracts.js +18 -7
- package/dist/contracts/toolEffects.js +34 -21
- package/dist/contracts/toolOutputSchemaGroups.js +18 -5
- package/dist/contracts/toolOutputSchemaPrimitives.js +9 -6
- package/dist/contracts/toolSchemaMetadata.js +5 -8
- package/dist/doctorRuntime.js +0 -41
- package/dist/domain/analysisErrorPresentation.js +4 -28
- package/dist/domain/analysisErrorProjection.js +33 -50
- package/dist/domain/analysisProfile.js +1 -1
- package/dist/domain/analysisSnapshot.js +77 -3
- package/dist/domain/androidApplication.js +5 -4
- package/dist/domain/appleApplication.js +5 -4
- package/dist/domain/appleAssetCatalog.js +127 -0
- package/dist/domain/artifactComparison.js +7 -11
- package/dist/domain/artifactGraph.js +8 -6
- package/dist/domain/artifactInspection.js +13 -12
- package/dist/domain/binaryTarget.js +23 -9
- package/dist/domain/browserObservation.js +43 -24
- package/dist/domain/browserObservationSchemas.js +2 -1
- package/dist/domain/browserScenario.js +7 -107
- package/dist/domain/browserScenarioCapture.js +0 -1
- package/dist/domain/browserScenarioCaptureValues.js +5 -4
- package/dist/domain/browserScenarioDiff.js +1 -3
- package/dist/domain/browserScenarioValues.js +16 -107
- package/dist/domain/bundleComparison.js +18 -17
- package/dist/domain/callPathSchemas.js +17 -7
- package/dist/domain/changedBehavior.js +2 -3
- package/dist/domain/comparisonSemantics.js +19 -0
- package/dist/domain/completionLedgerGeneration.js +3 -2
- package/dist/domain/conformancePackage.js +2 -1
- package/dist/domain/conformanceTrustGate.js +3 -5
- package/dist/domain/customProtocolCapture.js +2 -2
- package/dist/domain/digests.js +30 -0
- package/dist/domain/dosMz.js +83 -0
- package/dist/domain/electronActiveObservation.js +7 -5
- package/dist/domain/electronObservation.js +3 -2
- package/dist/domain/electronStaticAnalysisNative.js +15 -6
- package/dist/domain/emptyArraySchema.js +3 -0
- package/dist/domain/errors.js +10 -28
- package/dist/domain/evidence.js +5 -3
- package/dist/domain/evidenceCompletionLedger.js +3 -2
- package/dist/domain/functionComparisonNormalization.js +24 -18
- package/dist/domain/functionComparisonResults.js +3 -7
- package/dist/domain/functionComparisonSchemas.js +3 -2
- package/dist/domain/hopperValues.js +108 -8
- package/dist/domain/javascriptApplicationAnalysis.js +4 -7
- package/dist/domain/javascriptApplicationEvidenceSchemas.js +4 -3
- package/dist/domain/javascriptApplicationGraphSchemas.js +8 -7
- package/dist/domain/javascriptApplicationVersionComparisonSchemas.js +9 -7
- package/dist/domain/javascriptApplicationVersionItems.js +12 -18
- package/dist/domain/javascriptAstValues.js +4 -0
- package/dist/domain/javascriptExportShapeComparison.js +1 -6
- package/dist/domain/javascriptExportShapeComparisonSchemas.js +6 -10
- package/dist/domain/javascriptExportShapeVariants.js +15 -2
- package/dist/domain/javascriptFeatureTraceSchemas.js +8 -7
- package/dist/domain/javascriptRuntimeObservation.js +14 -2
- package/dist/domain/javascriptRuntimeReconciliationMatching.js +8 -0
- package/dist/domain/javascriptRuntimeReconciliationParsing.js +4 -2
- package/dist/domain/javascriptRuntimeReconciliationResult.js +6 -4
- package/dist/domain/javascriptRuntimeReconciliationRuntime.js +15 -4
- package/dist/domain/javascriptRuntimeReconciliationSchemas.js +19 -18
- package/dist/domain/javascriptRuntimeStaticCandidates.js +18 -6
- package/dist/domain/javascriptSemanticAnalysis.js +57 -19
- package/dist/domain/javascriptSemanticAsyncEffects.js +39 -40
- package/dist/domain/javascriptSemanticCalls.js +46 -27
- package/dist/domain/javascriptSemanticChildProcesses.js +43 -50
- package/dist/domain/javascriptSemanticDataEffectHelpers.js +91 -18
- package/dist/domain/javascriptSemanticDataEffects.js +22 -10
- package/dist/domain/javascriptSemanticGraphSchemas.js +8 -6
- package/dist/domain/javascriptSemanticObjects.js +13 -3
- package/dist/domain/javascriptSemanticProjection.js +144 -38
- package/dist/domain/javascriptSemanticPromises.js +14 -27
- package/dist/domain/javascriptSemanticQuerySchemas.js +6 -9
- package/dist/domain/javascriptSemanticResources.js +2 -5
- package/dist/domain/javascriptSemanticState.js +4 -0
- package/dist/domain/javascriptSemanticTraceSchemas.js +2 -1
- package/dist/domain/javascriptSemanticTraversal.js +13 -5
- package/dist/domain/javascriptSemanticValues.js +10 -9
- package/dist/domain/javascriptSourceParser.js +5 -1
- package/dist/domain/javascriptStaticAnalysisCalls.js +8 -5
- package/dist/domain/javascriptStaticAnalysisHelpers.js +16 -7
- package/dist/domain/keyedArchive.js +181 -0
- package/dist/domain/managedApplicationGraph.js +4 -3
- package/dist/domain/managedArtifact.js +2 -1
- package/dist/domain/managedMemberComparison.js +18 -13
- package/dist/domain/managedMemberComparisonCoverage.js +2 -1
- package/dist/domain/managedMemberComparisonItems.js +27 -7
- package/dist/domain/managedMemberComparisonMatch.js +22 -6
- package/dist/domain/managedNativeVerificationMatch.js +2 -2
- package/dist/domain/managedNativeVerificationSchemas.js +7 -5
- package/dist/domain/managedReconstruction.js +6 -5
- package/dist/domain/nativeApiBoundary.js +7 -0
- package/dist/domain/nativeDataType.js +51 -0
- package/dist/domain/nativeInspection.js +0 -1
- package/dist/domain/nativeInstruction.js +82 -0
- package/dist/domain/nativeInvestigationGraph.js +9 -5
- package/dist/domain/nativeUiObservation.js +123 -0
- package/dist/domain/nativeValueFlow.js +17 -0
- package/dist/domain/nativeValueTrace.js +64 -0
- package/dist/domain/objcSwiftMetadata.js +39 -0
- package/dist/domain/peInspection.js +1 -0
- package/dist/domain/processCapture.js +5 -55
- package/dist/domain/processCaptureExample.js +0 -9
- package/dist/domain/processCaptureValidation.js +13 -144
- package/dist/domain/processComparison.js +3 -25
- package/dist/domain/processObservation.js +0 -29
- package/dist/domain/processScenario.js +28 -228
- package/dist/domain/processTraceDimensionProjection.js +0 -15
- package/dist/domain/processTraceEvaluation.js +0 -6
- package/dist/domain/protocolCapture.js +8 -36
- package/dist/domain/reconstructionCoverage.js +3 -2
- package/dist/domain/reconstructionObligationLedgerSchemas.js +4 -12
- package/dist/domain/reconstructionReadinessSchemas.js +4 -3
- package/dist/domain/reconstructionVerification.js +2 -1
- package/dist/domain/reconstructionVerificationSchemas.js +6 -13
- package/dist/domain/referenceSourceClassification.js +0 -110
- package/dist/domain/referenceSourceGraph.js +15 -5
- package/dist/domain/residualUnknown.js +3 -2
- package/dist/domain/runtimeIdentification.js +6 -5
- package/dist/domain/sourceMapContents.js +5 -0
- package/dist/domain/sourceToBundleComparison.js +3 -10
- package/dist/domain/sourceToBundleComparisonSchemas.js +7 -6
- package/dist/domain/sourceToBundleSignals.js +9 -3
- package/dist/domain/staticRuntimeCorrelation.js +5 -11
- package/dist/domain/webBundleAnalysis.js +17 -9
- package/dist/domain/webBundleAnalyzer.js +1 -1
- package/dist/domain/webCaptureDiff.js +5 -11
- package/dist/domain/webCaptureDiffSchemas.js +2 -1
- package/dist/domain/webMcpDiscovery.js +2 -1
- package/dist/dotnet/ManagedMemberInspectorCore.js +15 -7
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +57 -40
- package/dist/dotnet/ManagedMemberRows.js +2 -0
- package/dist/dotnet/ManagedMethodBodyReader.js +15 -8
- package/dist/dotnet/ManagedPeReader.js +2 -0
- package/dist/generatedMcpToolCatalog.js +1 -1
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraAnalysisProfile.js +15 -5
- package/dist/ghidra/GhidraClient.js +38 -8
- package/dist/ghidra/GhidraFunctionValues.js +56 -20
- package/dist/ghidra/GhidraInstallation.js +7 -4
- package/dist/ghidra/GhidraInventoryValues.js +44 -9
- package/dist/ghidra/GhidraLauncher.js +18 -3
- package/dist/ghidra/GhidraProvider.js +23 -2
- package/dist/ghidra/GhidraRequestQueue.js +45 -4
- package/dist/ghidra/GhidraSessionValues.js +5 -0
- package/dist/hopper/HopperAnalysisProfile.js +2 -0
- package/dist/hopper/HopperProvider.js +29 -6
- package/dist/hopper/HopperTargetLease.js +18 -4
- package/dist/logger.js +0 -13
- package/dist/main/messages.js +0 -1
- package/dist/main/reload.js +3 -32
- package/dist/main/shutdown.js +1 -2
- package/dist/main/transport.js +0 -17
- package/dist/main.js +0 -10
- package/dist/native/AppleDispatchMetadata.js +582 -0
- package/dist/native/AppleObjcProtocols.js +88 -0
- package/dist/native/AppleSwiftVtables.js +86 -0
- package/dist/native/CommandRunner.js +1 -1
- package/dist/native/NativeHostCapabilities.js +23 -0
- package/dist/native/NativeMacOSProvider.js +61 -9
- package/dist/native/NativeMachoInspection.js +39 -6
- package/dist/native/NativeUiHelperRuntime.js +42 -0
- package/dist/native/NativeUiObservation.js +174 -0
- package/dist/native/parsers/codesign.js +4 -1
- package/dist/native/parsers/dyldInfo.js +51 -25
- package/dist/native/parsers/lipo.js +13 -4
- package/dist/native/parsers/otool.js +84 -39
- package/dist/native/parsers/plist.js +2 -1
- package/dist/process/ExecFileOutput.js +5 -1
- package/dist/process/ProcessOwnership.js +69 -33
- package/dist/process/ProcessOwnershipObservation.js +31 -12
- package/dist/process/ProviderProcess.js +4 -2
- package/dist/reference/ReferenceSourceReaderEntries.js +48 -31
- package/dist/reference/ReferenceSourceReaderErrors.js +24 -0
- package/dist/reference/ReferenceSourceReaderFile.js +11 -5
- package/dist/reference/ReferenceSourceReaderValidate.js +22 -8
- package/dist/server/createServer.js +7 -62
- package/dist/server/registerApplicationTools/helpers.js +2 -9
- package/dist/server/registerApplicationTools.js +0 -4
- package/dist/server/registerArtifactComparisonTool.js +1 -1
- package/dist/server/registerBrowserScenarioTool.js +4 -2
- package/dist/server/registerBrowserTools.js +7 -7
- package/dist/server/registerBundleComparisonTool.js +1 -1
- package/dist/server/registerCloseLifecycleTool.js +1 -1
- package/dist/server/registerElectronTools.js +10 -4
- package/dist/server/registerEnhancedTools.js +20 -12
- package/dist/server/registerEvidenceTools.js +4 -28
- package/dist/server/registerFunctionComparisonTool.js +1 -1
- package/dist/server/registerInvestigationTools.js +6 -6
- package/dist/server/registerJavaScriptRuntimeObservationTools.js +2 -2
- package/dist/server/registerManagedTools.js +28 -14
- package/dist/server/registerManagedWorkflowTools.js +0 -2
- package/dist/server/registerProcessComparisonTool.js +1 -3
- package/dist/server/registerSessionRecordTools.js +9 -9
- package/dist/server/registerSessionStatusTool.js +1 -1
- package/dist/server/registerSessionTools.js +28 -57
- package/dist/server/sessionAvailabilityPolicy.js +2 -3
- package/dist/server/sessionToolPolicies.js +0 -4
- package/dist/server/toolResult.js +8 -10
- package/package.json +32 -22
- package/skills/reverse-engineer-anything/SKILL.md +15 -11
- package/skills/reverse-engineer-anything/references/evidence-workflows.md +3 -2
- package/skills/reverse-engineer-anything/references/javascript-applications.md +3 -2
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +8 -6
- package/skills/reverse-engineer-anything/references/runtime-observation.md +15 -11
- package/dist/application/CommandShimReplay.js +0 -152
- package/dist/application/ConfiguredRoots.js +0 -19
- package/dist/application/InstrumentedJavaScriptReplayHost.js +0 -36
- package/dist/application/JavaScriptReplayPermission.js +0 -16
- package/dist/application/JavaScriptReplayPlanning.js +0 -207
- package/dist/application/JavaScriptReplayService.js +0 -274
- package/dist/application/LoopbackReplay.js +0 -389
- package/dist/application/LoopbackReplayRecorder.js +0 -129
- package/dist/application/ManagedRuntimeCorrelationService.js +0 -104
- package/dist/application/NodeRuntimeCharacterizationService.js +0 -191
- package/dist/application/PermissionAuthority.js +0 -268
- package/dist/application/PermissionConfiguration.js +0 -26
- package/dist/application/PermissionFailure.js +0 -5
- package/dist/application/ProcessCaptureAuthority.js +0 -24
- package/dist/application/ProcessCapturePermission.js +0 -13
- package/dist/application/ProcessCheckpoints.js +0 -178
- package/dist/application/ProcessReactiveCoordinator.js +0 -223
- package/dist/application/ProcessReactiveEffects.js +0 -153
- package/dist/application/ProcessReactiveHarness.js +0 -106
- package/dist/application/ProcessReactiveObservations.js +0 -105
- package/dist/application/ProjectPermissionStore.js +0 -199
- package/dist/application/RuntimeExecutableDiagnostics.js +0 -198
- package/dist/application/Upgrade.js +0 -134
- package/dist/browser/SensitiveTextCapture.js +0 -8
- package/dist/cliPolicyCommands.js +0 -185
- package/dist/config/browserScenario.js +0 -77
- package/dist/config/electronAutomation.js +0 -35
- package/dist/config/javascriptReplay.js +0 -41
- package/dist/config/managedRuntime.js +0 -25
- package/dist/config/passiveObservation.js +0 -87
- package/dist/config/permissions.js +0 -23
- package/dist/config/processCapture.js +0 -47
- package/dist/contracts/replayMachineExample.js +0 -37
- package/dist/domain/javascriptExportInstrumentation.js +0 -95
- package/dist/domain/javascriptReplay.js +0 -360
- package/dist/domain/managedRuntimeCorrelation.js +0 -181
- package/dist/domain/nodeRuntimeCharacterization.js +0 -63
- package/dist/domain/permissionPolicy.js +0 -176
- package/dist/domain/processCaptureReactiveSchema.js +0 -68
- package/dist/domain/processCaptureReactiveValidation.js +0 -180
- package/dist/domain/processReactiveCheckpointDataflow.js +0 -32
- package/dist/domain/processReactiveMatching.js +0 -196
- package/dist/domain/processReactiveRuntime.js +0 -116
- package/dist/domain/processReactiveScenario.js +0 -296
- package/dist/domain/processReactiveScenarioPreflight.js +0 -95
- package/dist/domain/processReactiveTransition.js +0 -187
- package/dist/domain/replayMachine.js +0 -320
- package/dist/domain/replayMachineRun.js +0 -168
- package/dist/domain/replayMachineRuntime.js +0 -296
- package/dist/domain/replayMachineValues.js +0 -84
- package/dist/domain/runtimeCharacterization.js +0 -84
- package/dist/replay/JavaScriptReplayWorker.js +0 -382
- package/dist/replay/JavaScriptReplayWorkerTypes.js +0 -1
- package/dist/replay/LinuxJavaScriptReplayRunner.js +0 -216
- package/dist/replay/LinuxJavaScriptReplaySandbox.js +0 -121
- package/dist/replay/LinuxRuntimeClosure.js +0 -44
- package/dist/replay/LinuxSeccompPolicy.js +0 -40
- package/dist/replay/ReplayOutcome.js +0 -104
- package/dist/replay/ReplayProcessLifecycle.js +0 -96
- package/dist/replay/ReplaySeccompFile.js +0 -29
- package/dist/replay/ReplayWorkerProtocol.js +0 -58
- package/dist/replay/SystemJavaScriptReplayHost.js +0 -153
- package/dist/server/ProcessCaptureElicitation.js +0 -153
- package/dist/server/registerApplicationTools/characterization.js +0 -46
- package/dist/server/registerApplicationTools/controlledReplay.js +0 -31
- package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +0 -29
- package/dist/server/registerReplayMachineTool.js +0 -14
- package/skills/reverse-engineer-anything/references/controlled-replay.md +0 -12
package/bridge/hopper_bridge.py
CHANGED
|
@@ -128,6 +128,10 @@ class CapabilityUnavailableError(Exception):
|
|
|
128
128
|
"""The active Hopper build lacks one admitted public API operation."""
|
|
129
129
|
|
|
130
130
|
|
|
131
|
+
class InvalidRequestError(Exception):
|
|
132
|
+
"""Caller input failed bridge request or operation validation."""
|
|
133
|
+
|
|
134
|
+
|
|
131
135
|
EXHAUSTIVE_ANALYSIS_METHODS = frozenset(
|
|
132
136
|
(
|
|
133
137
|
"analyze_function",
|
|
@@ -150,6 +154,11 @@ EXHAUSTIVE_ANALYSIS_METHODS = frozenset(
|
|
|
150
154
|
|
|
151
155
|
|
|
152
156
|
def _hex(value):
|
|
157
|
+
if not isinstance(value, int) or isinstance(value, bool):
|
|
158
|
+
try:
|
|
159
|
+
value = int(str(value), 16)
|
|
160
|
+
except ValueError as error:
|
|
161
|
+
raise ValueError("Hopper returned a non-hexadecimal address") from error
|
|
153
162
|
return "0x%x" % value
|
|
154
163
|
|
|
155
164
|
|
|
@@ -177,8 +186,8 @@ def _document(name=None):
|
|
|
177
186
|
current = api.current_document()
|
|
178
187
|
if current is not None and current.getDocumentName() == name:
|
|
179
188
|
return current
|
|
180
|
-
raise
|
|
181
|
-
raise
|
|
189
|
+
raise InvalidRequestError("Hopper document name is ambiguous")
|
|
190
|
+
raise InvalidRequestError("Unknown Hopper document")
|
|
182
191
|
if _selected_document is not None:
|
|
183
192
|
for candidate in documents:
|
|
184
193
|
if candidate.getDocumentName() == _selected_document:
|
|
@@ -188,7 +197,7 @@ def _document(name=None):
|
|
|
188
197
|
return session_document
|
|
189
198
|
current = api.current_document()
|
|
190
199
|
if current is None:
|
|
191
|
-
raise
|
|
200
|
+
raise CapabilityUnavailableError("No Hopper document is loaded")
|
|
192
201
|
return current
|
|
193
202
|
|
|
194
203
|
|
|
@@ -197,20 +206,20 @@ def _address(document, value=None):
|
|
|
197
206
|
if value is None:
|
|
198
207
|
return document.getCurrentAddress()
|
|
199
208
|
if not isinstance(value, str):
|
|
200
|
-
raise
|
|
209
|
+
raise InvalidRequestError("Address must be a string")
|
|
201
210
|
try:
|
|
202
211
|
return int(value, 16)
|
|
203
212
|
except ValueError:
|
|
204
213
|
result = document.getAddressForName(value)
|
|
205
214
|
if result in BAD_ADDRESSES:
|
|
206
|
-
raise
|
|
215
|
+
raise InvalidRequestError("Unknown Hopper address or name")
|
|
207
216
|
return result
|
|
208
217
|
|
|
209
218
|
|
|
210
219
|
def _segment(document, address):
|
|
211
220
|
result = document.getSegmentAtAddress(address)
|
|
212
221
|
if result is None:
|
|
213
|
-
raise
|
|
222
|
+
raise InvalidRequestError("Address is outside every segment")
|
|
214
223
|
return result
|
|
215
224
|
|
|
216
225
|
|
|
@@ -218,7 +227,7 @@ def _procedure(document, value=None):
|
|
|
218
227
|
address = document.getCurrentAddress() if value is None else _address(document, value)
|
|
219
228
|
result = _segment(document, address).getProcedureAtAddress(address)
|
|
220
229
|
if result is None:
|
|
221
|
-
raise
|
|
230
|
+
raise InvalidRequestError("No procedure exists at the requested address")
|
|
222
231
|
return result
|
|
223
232
|
|
|
224
233
|
|
|
@@ -232,6 +241,10 @@ def _procedure_identity(procedure):
|
|
|
232
241
|
"address": _hex(procedure.getEntryPoint()),
|
|
233
242
|
"name": _procedure_name(procedure),
|
|
234
243
|
"classification": None,
|
|
244
|
+
"body": {
|
|
245
|
+
"available": False,
|
|
246
|
+
"reason": "Hopper's public Python API does not expose complete function body ranges",
|
|
247
|
+
},
|
|
235
248
|
}
|
|
236
249
|
|
|
237
250
|
|
|
@@ -278,7 +291,7 @@ def _procedure_references(document, params):
|
|
|
278
291
|
procedure = _procedure(document, params.get("procedure"))
|
|
279
292
|
direction = params.get("direction", "outgoing")
|
|
280
293
|
if direction not in ("incoming", "outgoing"):
|
|
281
|
-
raise
|
|
294
|
+
raise InvalidRequestError("direction must be incoming or outgoing")
|
|
282
295
|
addresses = _instruction_addresses(procedure)
|
|
283
296
|
edges = set()
|
|
284
297
|
for address in addresses:
|
|
@@ -300,6 +313,12 @@ def _procedure_references(document, params):
|
|
|
300
313
|
})
|
|
301
314
|
return {
|
|
302
315
|
"procedure": _procedure_identity(procedure), "direction": direction,
|
|
316
|
+
"reference_kinds_available": False,
|
|
317
|
+
# The public Hopper API returns observed references but does not expose
|
|
318
|
+
# enough flow metadata to enumerate calls with no resolved target.
|
|
319
|
+
# Keep the required list field explicit; the provider records this as
|
|
320
|
+
# unknown coverage rather than claiming the list is exhaustive.
|
|
321
|
+
"unresolved_calls": [],
|
|
303
322
|
"references": items,
|
|
304
323
|
}
|
|
305
324
|
|
|
@@ -366,13 +385,13 @@ def _search_inventory(document, kind):
|
|
|
366
385
|
def _search_results(document, kind, params):
|
|
367
386
|
pattern = params.get("pattern")
|
|
368
387
|
if not isinstance(pattern, str) or not pattern:
|
|
369
|
-
raise
|
|
388
|
+
raise InvalidRequestError("pattern must be a non-empty string")
|
|
370
389
|
mode = params.get("mode", "literal")
|
|
371
390
|
if mode not in ("literal", "regex"):
|
|
372
|
-
raise
|
|
391
|
+
raise InvalidRequestError("mode must be literal or regex")
|
|
373
392
|
case_sensitive = params.get("case_sensitive", False)
|
|
374
393
|
if not isinstance(case_sensitive, bool):
|
|
375
|
-
raise
|
|
394
|
+
raise InvalidRequestError("case_sensitive must be a boolean")
|
|
376
395
|
|
|
377
396
|
if mode == "literal":
|
|
378
397
|
needle = pattern if case_sensitive else pattern.casefold()
|
|
@@ -381,7 +400,7 @@ def _search_results(document, kind, params):
|
|
|
381
400
|
try:
|
|
382
401
|
expression = re.compile(pattern, 0 if case_sensitive else re.IGNORECASE)
|
|
383
402
|
except (re.error, OverflowError) as error:
|
|
384
|
-
raise
|
|
403
|
+
raise InvalidRequestError("Invalid regex pattern") from error
|
|
385
404
|
matches = lambda value: expression.search(value) is not None
|
|
386
405
|
|
|
387
406
|
selected = []
|
|
@@ -544,7 +563,11 @@ def _analyze_function(document, params):
|
|
|
544
563
|
referenced_strings.sort(key=lambda item: (int(item["address"], 16), int(item["source_address"], 16)))
|
|
545
564
|
referenced_names.sort(key=lambda item: (int(item["address"], 16), int(item["source_address"], 16)))
|
|
546
565
|
return {
|
|
547
|
-
"procedure": {
|
|
566
|
+
"procedure": {
|
|
567
|
+
**_procedure_identity(procedure),
|
|
568
|
+
"signature": procedure.signatureString(),
|
|
569
|
+
"locals": _procedure_locals(procedure),
|
|
570
|
+
},
|
|
548
571
|
"pseudocode": pseudo,
|
|
549
572
|
"assembly": assembly_lines,
|
|
550
573
|
"comments": comments,
|
|
@@ -618,9 +641,9 @@ def _dispatch(method, params):
|
|
|
618
641
|
if method == "read_bytes":
|
|
619
642
|
length = params.get("length", 256)
|
|
620
643
|
if isinstance(length, bool) or not isinstance(length, int):
|
|
621
|
-
raise
|
|
644
|
+
raise InvalidRequestError("Byte-read length must be an integer")
|
|
622
645
|
if length < 1:
|
|
623
|
-
raise
|
|
646
|
+
raise InvalidRequestError("Byte-read length must be at least 1")
|
|
624
647
|
reader = getattr(document, "readBytes", None)
|
|
625
648
|
if not callable(reader):
|
|
626
649
|
raise CapabilityUnavailableError(
|
|
@@ -654,7 +677,7 @@ def _dispatch(method, params):
|
|
|
654
677
|
or offset in BAD_ADDRESSES
|
|
655
678
|
or offset < 0
|
|
656
679
|
):
|
|
657
|
-
raise
|
|
680
|
+
raise InvalidRequestError("Address has no authoritative file-offset mapping")
|
|
658
681
|
return {"address": _hex(address), "file_offset": offset}
|
|
659
682
|
if method == "resolve_containing_procedure":
|
|
660
683
|
address = _address(document, params.get("address"))
|
|
@@ -690,7 +713,7 @@ def _dispatch(method, params):
|
|
|
690
713
|
else:
|
|
691
714
|
result = document.getInstructionStart(max(0, target - 1))
|
|
692
715
|
if result in BAD_ADDRESSES:
|
|
693
|
-
raise
|
|
716
|
+
raise InvalidRequestError("No adjacent address")
|
|
694
717
|
return _hex(result)
|
|
695
718
|
if method == "list_segments":
|
|
696
719
|
result = []
|
|
@@ -729,14 +752,14 @@ def _dispatch(method, params):
|
|
|
729
752
|
if requested is not None:
|
|
730
753
|
key = _hex(_address(document, requested))
|
|
731
754
|
values = {key: values[key]} if key in values else {}
|
|
732
|
-
return [{"address":
|
|
755
|
+
return [{"address": address, "value": value} for address, value in values.items()]
|
|
733
756
|
if method == "list_names":
|
|
734
757
|
result = dict(_search_inventory(document, "name"))
|
|
735
758
|
requested = params.get("address")
|
|
736
759
|
if requested is not None:
|
|
737
760
|
key = _hex(_address(document, requested))
|
|
738
761
|
result = {key: result[key]} if key in result else {}
|
|
739
|
-
return [{"address":
|
|
762
|
+
return [{"address": address, "value": value} for address, value in result.items()]
|
|
740
763
|
if method in ("search_procedures", "search_strings"):
|
|
741
764
|
kind = "procedure" if method == "search_procedures" else "string"
|
|
742
765
|
return _search_results(document, kind, params)
|
|
@@ -755,7 +778,16 @@ def _dispatch(method, params):
|
|
|
755
778
|
if method == "procedure_info":
|
|
756
779
|
blocks = list(procedure.basicBlockIterator())
|
|
757
780
|
length = sum(max(0, block.getEndingAddress() - block.getStartingAddress()) for block in blocks)
|
|
758
|
-
return {
|
|
781
|
+
return {
|
|
782
|
+
"name": _procedure_name(procedure),
|
|
783
|
+
"entrypoint": _hex(procedure.getEntryPoint()),
|
|
784
|
+
"basicblock_count": procedure.getBasicBlockCount(),
|
|
785
|
+
"length": length,
|
|
786
|
+
"signature": procedure.signatureString(),
|
|
787
|
+
"locals": _procedure_locals(procedure),
|
|
788
|
+
"classification": None,
|
|
789
|
+
"body": _procedure_identity(procedure)["body"],
|
|
790
|
+
}
|
|
759
791
|
if method == "set_address_name":
|
|
760
792
|
address = _address(document, params.get("address"))
|
|
761
793
|
try:
|
|
@@ -789,7 +821,7 @@ def _dispatch(method, params):
|
|
|
789
821
|
address = _address(document, params.get("address"))
|
|
790
822
|
document.removeBookmarkAtAddress(address)
|
|
791
823
|
return not document.hasBookmarkAtAddress(address)
|
|
792
|
-
raise
|
|
824
|
+
raise InvalidRequestError("Unknown bridge method")
|
|
793
825
|
|
|
794
826
|
|
|
795
827
|
def _serve_connection(connection):
|
|
@@ -803,13 +835,24 @@ def _serve_connection(connection):
|
|
|
803
835
|
authenticated = False
|
|
804
836
|
should_stop = False
|
|
805
837
|
try:
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
838
|
+
try:
|
|
839
|
+
request = json.loads(line.decode("utf-8"))
|
|
840
|
+
except (UnicodeDecodeError, json.JSONDecodeError) as error:
|
|
841
|
+
raise InvalidRequestError("Invalid bridge request JSON") from error
|
|
842
|
+
if not isinstance(request, dict) or set(request) != {"id", "token", "method", "params"}:
|
|
843
|
+
raise InvalidRequestError("Invalid bridge request shape")
|
|
809
844
|
request_id = request["id"]
|
|
810
845
|
if isinstance(request_id, bool) or not isinstance(request_id, int) or request_id < 0:
|
|
811
|
-
raise
|
|
812
|
-
if
|
|
846
|
+
raise InvalidRequestError("Invalid bridge request id")
|
|
847
|
+
if (
|
|
848
|
+
not isinstance(request["method"], str) or not request["method"]
|
|
849
|
+
or not isinstance(request["params"], dict)
|
|
850
|
+
):
|
|
851
|
+
raise InvalidRequestError("Invalid bridge method or parameters")
|
|
852
|
+
if (
|
|
853
|
+
not isinstance(request["token"], str) or not request["token"].isascii()
|
|
854
|
+
or not hmac.compare_digest(request["token"], REA_TOKEN)
|
|
855
|
+
):
|
|
813
856
|
raise PermissionError("Invalid bridge capability")
|
|
814
857
|
authenticated = True
|
|
815
858
|
_write_message(file, {"id": request_id, "event": {
|
|
@@ -864,7 +907,7 @@ def _diagnostic_type(error):
|
|
|
864
907
|
return "capability_unavailable"
|
|
865
908
|
if isinstance(error, PermissionError):
|
|
866
909
|
return "authorization"
|
|
867
|
-
if isinstance(error,
|
|
910
|
+
if isinstance(error, InvalidRequestError):
|
|
868
911
|
return "invalid_request"
|
|
869
912
|
return "bridge_exception"
|
|
870
913
|
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import AppKit
|
|
2
|
+
import ApplicationServices
|
|
3
|
+
import CryptoKit
|
|
4
|
+
import ScreenCaptureKit
|
|
5
|
+
import Darwin
|
|
6
|
+
|
|
7
|
+
struct Request: Decodable {
|
|
8
|
+
var pid: Int32
|
|
9
|
+
var window_id: UInt32
|
|
10
|
+
var executable: String
|
|
11
|
+
var sha256: String
|
|
12
|
+
var launch_time: Double?
|
|
13
|
+
var screenshot: Bool
|
|
14
|
+
var accessibility: Bool
|
|
15
|
+
var max_nodes: Int
|
|
16
|
+
var action: Action?
|
|
17
|
+
}
|
|
18
|
+
struct Action: Decodable { var kind: String; var path: [Int]?; var direction: String?; var text: String? }
|
|
19
|
+
struct BoundaryFailure: Error { var code: String; var message: String }
|
|
20
|
+
func fail(_ code: String, _ message: String) throws -> Never { throw BoundaryFailure(code: code, message: message) }
|
|
21
|
+
func attribute(_ element: AXUIElement, _ key: String) -> CFTypeRef? {
|
|
22
|
+
var value: CFTypeRef?
|
|
23
|
+
return AXUIElementCopyAttributeValue(element, key as CFString, &value) == .success ? value : nil
|
|
24
|
+
}
|
|
25
|
+
func childCount(_ element: AXUIElement) -> Int {
|
|
26
|
+
var count = 0
|
|
27
|
+
return AXUIElementGetAttributeValueCount(element, kAXChildrenAttribute as CFString, &count) == .success ? count : 0
|
|
28
|
+
}
|
|
29
|
+
func children(_ element: AXUIElement, limit: Int) -> [AXUIElement] {
|
|
30
|
+
var value: CFArray?
|
|
31
|
+
let count = min(limit, childCount(element))
|
|
32
|
+
if count == 0 { return [] }
|
|
33
|
+
return AXUIElementCopyAttributeValues(element, kAXChildrenAttribute as CFString, 0, count, &value) == .success ? value as? [AXUIElement] ?? [] : []
|
|
34
|
+
}
|
|
35
|
+
func text(_ element: AXUIElement, _ key: String) -> Any { (attribute(element, key) as? String) ?? NSNull() as Any }
|
|
36
|
+
func windowBounds(_ element: AXUIElement) -> CGRect? {
|
|
37
|
+
guard let p = attribute(element, kAXPositionAttribute), let s = attribute(element, kAXSizeAttribute),
|
|
38
|
+
CFGetTypeID(p) == AXValueGetTypeID(), CFGetTypeID(s) == AXValueGetTypeID() else { return nil }
|
|
39
|
+
var point = CGPoint.zero; var size = CGSize.zero
|
|
40
|
+
guard AXValueGetValue(p as! AXValue, .cgPoint, &point), AXValueGetValue(s as! AXValue, .cgSize, &size) else { return nil }
|
|
41
|
+
return CGRect(origin: point, size: size)
|
|
42
|
+
}
|
|
43
|
+
func observe(_ request: Request) async throws -> [String: Any] {
|
|
44
|
+
guard let app = NSRunningApplication(processIdentifier: request.pid), let url = app.executableURL else {
|
|
45
|
+
try fail("target-mismatch", "Selected PID does not expose an application executable URL")
|
|
46
|
+
}
|
|
47
|
+
guard let canonicalPointer = realpath(url.path, nil) else { try fail("target-mismatch", "Running executable path cannot be resolved") }
|
|
48
|
+
defer { free(canonicalPointer) }
|
|
49
|
+
let canonicalExecutable = String(cString: canonicalPointer)
|
|
50
|
+
guard canonicalExecutable == request.executable else {
|
|
51
|
+
try fail("target-mismatch", "Selected PID executable \(canonicalExecutable) differs from active target \(request.executable)")
|
|
52
|
+
}
|
|
53
|
+
guard let launch = app.launchDate?.timeIntervalSince1970 else {
|
|
54
|
+
try fail("process-identity-unavailable", "Selected application does not expose a launch time; stable PID reuse checks are unavailable")
|
|
55
|
+
}
|
|
56
|
+
if let expected = request.launch_time, expected != launch { try fail("process-replaced", "Selected process was replaced") }
|
|
57
|
+
let executableSize = (try FileManager.default.attributesOfItem(atPath: url.path)[.size] as? NSNumber)?.int64Value ?? -1
|
|
58
|
+
guard executableSize >= 0 && executableSize <= 256 * 1024 * 1024 else { try fail("target-limit", "Running executable exceeds the 256 MiB identity-check budget") }
|
|
59
|
+
let executableBytes = try Data(contentsOf: url, options: .mappedIfSafe)
|
|
60
|
+
guard SHA256.hash(data: executableBytes).map({ String(format: "%02x", $0) }).joined() == request.sha256 else {
|
|
61
|
+
try fail("target-mismatch", "Running executable bytes differ from the active target digest")
|
|
62
|
+
}
|
|
63
|
+
guard let windows = CGWindowListCopyWindowInfo([.optionIncludingWindow], request.window_id) as? [[String: Any]],
|
|
64
|
+
windows.count == 1, let window = windows.first,
|
|
65
|
+
(window[kCGWindowOwnerPID as String] as? NSNumber)?.int32Value == request.pid,
|
|
66
|
+
(window[kCGWindowLayer as String] as? NSNumber)?.intValue == 0,
|
|
67
|
+
let boundsDictionary = window[kCGWindowBounds as String] as? [String: Any],
|
|
68
|
+
let bounds = CGRect(dictionaryRepresentation: boundsDictionary as CFDictionary) else {
|
|
69
|
+
try fail("window-mismatch", "Selected window is absent or belongs to another process")
|
|
70
|
+
}
|
|
71
|
+
if request.screenshot && !CGPreflightScreenCaptureAccess() {
|
|
72
|
+
try fail("screen-recording-denied", "Grant Screen Recording to the REA host in System Settings > Privacy & Security, then retry; no broad capture fallback is used")
|
|
73
|
+
}
|
|
74
|
+
var selected: AXUIElement?
|
|
75
|
+
if request.accessibility || request.action != nil {
|
|
76
|
+
guard AXIsProcessTrusted() else { try fail("accessibility-denied", "Grant Accessibility to the REA host in System Settings > Privacy & Security, then retry") }
|
|
77
|
+
let application = AXUIElementCreateApplication(request.pid)
|
|
78
|
+
AXUIElementSetMessagingTimeout(application, 2)
|
|
79
|
+
guard let axWindows = attribute(application, kAXWindowsAttribute) as? [AXUIElement] else {
|
|
80
|
+
try fail("accessibility-unavailable", "Selected application does not expose accessibility windows")
|
|
81
|
+
}
|
|
82
|
+
let matches = axWindows.filter { windowBounds($0) == bounds }
|
|
83
|
+
guard matches.count == 1 else { try fail("ambiguous-window", "Accessibility window geometry does not identify exactly one selected window; selected CG bounds \(bounds), AX candidates \(axWindows.map { String(describing: windowBounds($0)) })") }
|
|
84
|
+
selected = matches[0]
|
|
85
|
+
}
|
|
86
|
+
if let action = request.action, let root = selected {
|
|
87
|
+
var element = root
|
|
88
|
+
for index in action.path ?? [] {
|
|
89
|
+
var selectedChild: CFArray?
|
|
90
|
+
guard index >= 0 && index < childCount(element),
|
|
91
|
+
AXUIElementCopyAttributeValues(element, kAXChildrenAttribute as CFString, index, 1, &selectedChild) == .success,
|
|
92
|
+
let item = (selectedChild as? [AXUIElement])?.first else { try fail("element-missing", "Selected accessibility path no longer exists") }
|
|
93
|
+
element = item
|
|
94
|
+
}
|
|
95
|
+
var owner: pid_t = 0
|
|
96
|
+
guard AXUIElementGetPid(element, &owner) == .success && owner == request.pid else { try fail("element-owner-mismatch", "Selected element belongs to another process") }
|
|
97
|
+
let outcome: AXError
|
|
98
|
+
switch action.kind {
|
|
99
|
+
case "click": outcome = AXUIElementPerformAction(element, kAXPressAction as CFString)
|
|
100
|
+
case "scroll": outcome = AXUIElementPerformAction(element, (action.direction == "increment" ? kAXIncrementAction : kAXDecrementAction) as CFString)
|
|
101
|
+
case "key-entry": outcome = AXUIElementSetAttributeValue(element, kAXValueAttribute as CFString, (action.text ?? "") as CFString)
|
|
102
|
+
default: try fail("unsupported-action", "Only selected-element press, increment/decrement and text-value entry are admitted")
|
|
103
|
+
}
|
|
104
|
+
guard outcome == .success else { try fail("action-failed", "Accessibility action failed with AXError \(outcome.rawValue)") }
|
|
105
|
+
}
|
|
106
|
+
var nodes: [[String: Any]] = []; var truncated = false
|
|
107
|
+
if request.accessibility, let root = selected {
|
|
108
|
+
var pending: [(AXUIElement, [Int])] = [(root, [])]
|
|
109
|
+
while let (element, path) = pending.popLast() {
|
|
110
|
+
if nodes.count >= request.max_nodes { truncated = true; break }
|
|
111
|
+
let totalChildren = childCount(element)
|
|
112
|
+
var actions: CFArray?
|
|
113
|
+
AXUIElementCopyActionNames(element, &actions)
|
|
114
|
+
nodes.append(["path": path, "role": text(element, kAXRoleAttribute), "title": text(element, kAXTitleAttribute), "value": text(element, kAXValueAttribute), "actions": actions as? [String] ?? [], "children_count": totalChildren])
|
|
115
|
+
if path.count >= 32 { if totalChildren > 0 { truncated = true }; continue }
|
|
116
|
+
let available = max(0, request.max_nodes - nodes.count - pending.count)
|
|
117
|
+
let count = min(available, totalChildren)
|
|
118
|
+
let items = children(element, limit: count)
|
|
119
|
+
if totalChildren > count { truncated = true }
|
|
120
|
+
for index in (0..<count).reversed() { pending.append((items[index], path + [index])) }
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
var screenshot: Any = NSNull()
|
|
124
|
+
if request.screenshot {
|
|
125
|
+
guard #available(macOS 14, *) else { try fail("unsupported-host", "Selected-window screenshots require macOS 14 or later") }
|
|
126
|
+
let content = try await SCShareableContent.excludingDesktopWindows(true, onScreenWindowsOnly: false)
|
|
127
|
+
guard let scWindow = content.windows.first(where: { $0.windowID == request.window_id && $0.owningApplication?.processID == request.pid }) else {
|
|
128
|
+
try fail("capture-window-missing", "Selected window disappeared before capture")
|
|
129
|
+
}
|
|
130
|
+
guard bounds.width > 0 && bounds.height > 0 && bounds.width <= 100000 && bounds.height <= 100000 else { try fail("window-bounds", "Selected window has invalid or oversized geometry") }
|
|
131
|
+
let filter = SCContentFilter(desktopIndependentWindow: scWindow)
|
|
132
|
+
let configuration = SCStreamConfiguration()
|
|
133
|
+
let scale = min(1, 2048 / max(bounds.width, bounds.height))
|
|
134
|
+
configuration.width = max(1, Int(bounds.width * scale)); configuration.height = max(1, Int(bounds.height * scale))
|
|
135
|
+
configuration.showsCursor = false
|
|
136
|
+
let image = try await SCScreenshotManager.captureImage(contentFilter: filter, configuration: configuration)
|
|
137
|
+
guard let png = NSBitmapImageRep(cgImage: image).representation(using: .png, properties: [:]) else {
|
|
138
|
+
try fail("capture-failed", "Selected-window PNG encoding failed")
|
|
139
|
+
}
|
|
140
|
+
screenshot = ["mime_type": "image/png", "base64": png.base64EncodedString(), "sha256": SHA256.hash(data: png).map({ String(format: "%02x", $0) }).joined(), "width": image.width, "height": image.height]
|
|
141
|
+
}
|
|
142
|
+
return ["window": ["pid": request.pid, "window_id": request.window_id, "executable": request.executable, "launch_time": launch, "title": window[kCGWindowName as String] as? String ?? ""], "nodes": nodes, "truncated": truncated, "screenshot": screenshot, "gaps": request.accessibility ? [] : ["Accessibility capture was disabled"]]
|
|
143
|
+
}
|
|
144
|
+
Task { @MainActor in
|
|
145
|
+
do {
|
|
146
|
+
let request = try JSONDecoder().decode(Request.self, from: Data(CommandLine.arguments[1].utf8))
|
|
147
|
+
let result = try await observe(request)
|
|
148
|
+
let output = try JSONSerialization.data(withJSONObject: ["ok": true, "result": result], options: [.sortedKeys])
|
|
149
|
+
FileHandle.standardOutput.write(output)
|
|
150
|
+
} catch {
|
|
151
|
+
let failure = error as? BoundaryFailure
|
|
152
|
+
let output: [String: Any] = ["ok": false, "code": failure?.code ?? "capture-failed", "message": failure?.message ?? error.localizedDescription]
|
|
153
|
+
if let data = try? JSONSerialization.data(withJSONObject: output, options: [.sortedKeys]) { FileHandle.standardOutput.write(data) }
|
|
154
|
+
}
|
|
155
|
+
exit(0)
|
|
156
|
+
}
|
|
157
|
+
RunLoop.main.run()
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { AnalysisOutputError } from "../domain/errors.js";
|
|
1
|
+
import { AnalysisCapabilityUnavailableError, AnalysisOutputError, } from "../domain/errors.js";
|
|
2
|
+
import { parseDocuments } from "../domain/hopperValues.js";
|
|
2
3
|
import { err, ok } from "../domain/result.js";
|
|
3
4
|
const parameters = (document, address) => ({
|
|
4
5
|
...(document === undefined ? {} : { document }),
|
|
@@ -77,8 +78,22 @@ const resolveDocument = async (analysis, document, signal) => {
|
|
|
77
78
|
if (document !== undefined)
|
|
78
79
|
return ok(document);
|
|
79
80
|
const current = await analysis.execute("current_document", {}, executionOptions(signal));
|
|
80
|
-
if (!current.ok)
|
|
81
|
-
|
|
81
|
+
if (!current.ok) {
|
|
82
|
+
if (!(current.error instanceof AnalysisCapabilityUnavailableError))
|
|
83
|
+
return current;
|
|
84
|
+
const listed = await analysis.execute("list_documents", {}, executionOptions(signal));
|
|
85
|
+
if (!listed.ok)
|
|
86
|
+
return listed;
|
|
87
|
+
const parsed = parseDocuments(listed.value.result);
|
|
88
|
+
if (!parsed.ok)
|
|
89
|
+
return err(new AnalysisOutputError("list_documents", "expected one document identity when resolving a headless provider", { cause: parsed.error }));
|
|
90
|
+
if (parsed.value.length !== 1)
|
|
91
|
+
return err(new AnalysisOutputError("list_documents", `expected exactly one document identity for a provider without current-document selection, received ${parsed.value.length}`));
|
|
92
|
+
const [documentName] = parsed.value;
|
|
93
|
+
if (documentName === undefined)
|
|
94
|
+
return err(new AnalysisOutputError("list_documents", "provider returned no document identity"));
|
|
95
|
+
return ok(documentName);
|
|
96
|
+
}
|
|
82
97
|
return typeof current.value.result === "string"
|
|
83
98
|
? ok(current.value.result)
|
|
84
99
|
: err(new AnalysisOutputError("current_document", "expected a document identity string"));
|
|
@@ -93,8 +108,7 @@ const facet = (result, operation) => result?.ok === true
|
|
|
93
108
|
const isMissingCurrentProcedure = (error) => /(?:no procedure exists|not in a procedure)/iu.test(error.message);
|
|
94
109
|
const isRequestLevelFailure = (error) => error._tag === "AnalysisCancelledError" ||
|
|
95
110
|
error._tag === "AnalysisTimeoutError" ||
|
|
96
|
-
error._tag === "NoBinaryOpenError"
|
|
97
|
-
error._tag === "PermissionRequiredError";
|
|
111
|
+
error._tag === "NoBinaryOpenError";
|
|
98
112
|
const containingProcedureName = (value) => {
|
|
99
113
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
100
114
|
return null;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EvidenceIntegrityError, NoBinaryOpenError, } from "../domain/errors.js";
|
|
2
2
|
import { err, ok } from "../domain/result.js";
|
|
3
|
-
import { analysisQueryId, createAnalysisSnapshotEntry, snapshotBinding, snapshotMatchesProfile, snapshotMatchesTarget, snapshotTarget, } from "../domain/analysisSnapshot.js";
|
|
3
|
+
import { analysisQueryId, createAnalysisSnapshotEntry, snapshotBinding, snapshotMatchesProfile, snapshotMatchesTarget, snapshotTarget, parseAnalysisSnapshot, } from "../domain/analysisSnapshot.js";
|
|
4
4
|
import { GENERATED_MCP_TOOL_CATALOG } from "../generatedMcpToolCatalog.js";
|
|
5
5
|
const STATEFUL_OPERATIONS = new Set([
|
|
6
6
|
"health",
|
|
@@ -75,21 +75,40 @@ export class AnalysisSnapshotCache {
|
|
|
75
75
|
export(target, profile, evidenceBundle) {
|
|
76
76
|
if (target === undefined || profile === undefined)
|
|
77
77
|
return err(new NoBinaryOpenError());
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
binding
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
78
|
+
try {
|
|
79
|
+
const snapshotTargetIdentity = snapshotTarget(target);
|
|
80
|
+
const binding = snapshotBinding(profile);
|
|
81
|
+
const retainedEvidence = structuredClone(evidenceBundle);
|
|
82
|
+
return ok(parseAnalysisSnapshot({
|
|
83
|
+
target: snapshotTargetIdentity,
|
|
84
|
+
binding,
|
|
85
|
+
entries: this.entries(),
|
|
86
|
+
evidence_bundle: retainedEvidence,
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
catch (cause) {
|
|
90
|
+
return err(new EvidenceIntegrityError("Analysis snapshot validation failed", {
|
|
91
|
+
cause,
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
84
94
|
}
|
|
85
95
|
/** Validate target identity, merge evidence atomically, then stage entries. */
|
|
86
96
|
import(snapshot, active, mergeEvidence) {
|
|
97
|
+
let validated;
|
|
98
|
+
try {
|
|
99
|
+
validated = parseAnalysisSnapshot(snapshot);
|
|
100
|
+
}
|
|
101
|
+
catch (cause) {
|
|
102
|
+
return err(new EvidenceIntegrityError("Analysis snapshot validation failed", {
|
|
103
|
+
cause,
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
87
106
|
if (active !== undefined &&
|
|
88
|
-
(!snapshotMatchesTarget(
|
|
89
|
-
!snapshotMatchesProfile(
|
|
107
|
+
(!snapshotMatchesTarget(validated.target, active.target) ||
|
|
108
|
+
!snapshotMatchesProfile(validated.binding, active.profile)))
|
|
90
109
|
return err(new EvidenceIntegrityError("Analysis snapshot profile_mismatch: target, provider, or analysis profile does not match the active binary"));
|
|
91
|
-
const importedEvidence = mergeEvidence(
|
|
92
|
-
return importedEvidence.ok ? ok(this.stage(
|
|
110
|
+
const importedEvidence = mergeEvidence(validated.evidence_bundle);
|
|
111
|
+
return importedEvidence.ok ? ok(this.stage(validated)) : importedEvidence;
|
|
93
112
|
}
|
|
94
113
|
/** Return canonical entries for persistence. */
|
|
95
114
|
entries() {
|