sim-mirror 2.1.0__tar.gz → 2.2.0__tar.gz
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.
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/PKG-INFO +17 -9
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/README.md +16 -8
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/THIRD_PARTY_LICENSES.md +27 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/docs/README.md +2 -1
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/examples/README.md +3 -1
- sim_mirror-2.2.0/examples/android-app/README.md +37 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/examples/claude-code-cli/README.md +2 -2
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/examples/codex/README.md +1 -1
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/examples/cursor/README.md +1 -1
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/examples/fastapi-embed/README.md +1 -1
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Wire.swift +1 -1
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/client-input.schema.json +2 -2
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/common.schema.json +10 -5
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/http.schema.json +6 -2
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/status.schema.json +3 -3
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/pyproject.toml +3 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/_version.py +1 -1
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/destination.py +34 -14
- sim_mirror-2.2.0/src/sim_mirror/build/gradle.py +483 -0
- sim_mirror-2.2.0/src/sim_mirror/build/gradle_log.py +73 -0
- sim_mirror-2.2.0/src/sim_mirror/build/junit.py +125 -0
- sim_mirror-2.2.0/src/sim_mirror/build/project_files.py +52 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/provider.py +33 -12
- sim_mirror-2.2.0/src/sim_mirror/build/runner.py +450 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/stamp.py +40 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/xcodebuild.py +153 -382
- sim_mirror-2.2.0/src/sim_mirror/cli/android.py +135 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/context.py +40 -1
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/devices.py +17 -5
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/doctor.py +1 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/main.py +2 -1
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/stop.py +6 -2
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/config/model.py +11 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/config/schema.py +65 -3
- sim_mirror-2.2.0/src/sim_mirror/connectors/android/__init__.py +2 -0
- sim_mirror-2.2.0/src/sim_mirror/connectors/android/adb_input.py +125 -0
- sim_mirror-2.2.0/src/sim_mirror/connectors/android/connector.py +230 -0
- sim_mirror-2.2.0/src/sim_mirror/connectors/android/geometry.py +115 -0
- sim_mirror-2.2.0/src/sim_mirror/connectors/android/keys.py +55 -0
- sim_mirror-2.2.0/src/sim_mirror/connectors/android/scrcpy.py +269 -0
- sim_mirror-2.2.0/src/sim_mirror/connectors/android/scrcpy_roles.py +202 -0
- sim_mirror-2.2.0/src/sim_mirror/connectors/android/scrcpy_source.py +204 -0
- sim_mirror-2.2.0/src/sim_mirror/connectors/android/screen.py +69 -0
- sim_mirror-2.2.0/src/sim_mirror/connectors/android/uiautomator.py +256 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/base.py +23 -3
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/iphone/connector.py +2 -1
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/iphone/wda_roles.py +3 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/registry.py +26 -3
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/actions.py +9 -4
- sim_mirror-2.2.0/src/sim_mirror/core/android_backend.py +254 -0
- sim_mirror-2.2.0/src/sim_mirror/core/android_control.py +424 -0
- sim_mirror-2.2.0/src/sim_mirror/core/android_devices.py +249 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/backends.py +32 -6
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/control.py +24 -1
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/device_changes.py +36 -13
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/frames.py +23 -2
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/instance.py +7 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/manager.py +42 -21
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/runtime.py +53 -6
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/screen_input.py +16 -2
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/screen_relay.py +2 -1
- sim_mirror-2.2.0/src/sim_mirror/core/touch.py +212 -0
- sim_mirror-2.2.0/src/sim_mirror/doctor/android.py +118 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/doctor/checks.py +47 -9
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/host_copy.py +23 -0
- sim_mirror-2.2.0/src/sim_mirror/platform/adb.py +488 -0
- sim_mirror-2.2.0/src/sim_mirror/platform/android_sdk.py +164 -0
- sim_mirror-2.2.0/src/sim_mirror/platform/emulator.py +268 -0
- sim_mirror-2.2.0/src/sim_mirror/platform/identifiers.py +69 -0
- sim_mirror-2.2.0/src/sim_mirror/platform/java.py +71 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/xcode.py +10 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/protocol/_generated.py +28 -8
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/http_routes.py +5 -4
- sim_mirror-2.2.0/src/sim_mirror/server/static/viewer/start.js +35 -0
- sim_mirror-2.2.0/src/sim_mirror/testing/adb.py +422 -0
- sim_mirror-2.2.0/src/sim_mirror/testing/android_sdk.py +43 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fakes.py +79 -2
- sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-am-start-bad.txt +3 -0
- sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-am-start.txt +8 -0
- sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-logcat-uid.txt +12 -0
- sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-package-missing.txt +1 -0
- sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-package.txt +45 -0
- sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-pm-uid.txt +2 -0
- sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-uiautomator-landscape.xml +1 -0
- sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-uiautomator-search.xml +1 -0
- sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-uiautomator-settings.xml +1 -0
- sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-window-search.txt +493 -0
- sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-window-settings.txt +491 -0
- sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/gradle-aapt-error.log +55 -0
- sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/gradle-kotlin-error.log +51 -0
- sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/gradle-output-metadata.json +21 -0
- sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/gradle-test-failure.log +166 -0
- sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/junit-android-failure.xml +48 -0
- sim_mirror-2.2.0/src/sim_mirror/testing/gradle.py +123 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/guards.py +29 -5
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/rig.py +10 -0
- sim_mirror-2.2.0/src/sim_mirror/testing/scrcpy.py +148 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/app.py +32 -12
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/device.py +56 -21
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/schemas.py +29 -22
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/tests/unit/protocol/test_messages.py +1 -0
- sim_mirror-2.1.0/src/sim_mirror/core/touch.py +0 -99
- sim_mirror-2.1.0/src/sim_mirror/platform/identifiers.py +0 -41
- sim_mirror-2.1.0/src/sim_mirror/server/static/viewer/start.js +0 -35
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/.gitignore +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/LICENSE +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/NOTICE +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/docs/media/README.md +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/examples/custom-connector/README.md +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/examples/embed-host/README.md +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/examples/iframe/README.md +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/examples/token-budget/README.md +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/examples/web-component/README.md +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Package.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Accessibility.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Arguments.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Capture.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/FrameScheduler.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Input.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/JSON.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Orientation.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Recording.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Requests.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Rotation.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Screen.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Server.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Video.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/AccessibilityReader.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/CaptureDevice.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/Disclaimed.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/Framebuffer.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/Frameworks.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/H264Stream.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/HIDTransports.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/Pictures.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/PixelSource.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/RecordingRenderer.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/ScreenFeed.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/SimDeviceHandle.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/SimulatorDevice.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/UnixSocket.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/UsbCapture.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/Warming.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/ObjCGuard/ObjCGuard.m +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/ObjCGuard/include/ObjCGuard.h +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/sim-mirror-helper/main.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Support/Info.plist +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/Fixtures/wire-vectors.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/HelperCoreTests/AccessibilityTests.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/HelperCoreTests/ArgumentsTests.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/HelperCoreTests/CaptureTests.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/HelperCoreTests/InputTests.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/HelperCoreTests/OrientationTests.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/HelperCoreTests/PictureTests.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/HelperCoreTests/RecordingTests.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/HelperCoreTests/RotationTests.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/HelperCoreTests/ServerTests.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/HelperCoreTests/WireTests.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/README.md +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/app-sdk/v1/examples/error-inactive.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/app-sdk/v1/examples/error-unauthorized.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/app-sdk/v1/examples/hierarchy-alert.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/app-sdk/v1/examples/hierarchy-keyboard.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/app-sdk/v1/examples/hierarchy-swiftui.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/app-sdk/v1/examples/hierarchy-tagged.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/app-sdk/v1/examples/hierarchy-uikit.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/app-sdk/v1/examples/listing.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/app-sdk/v1/hierarchy.schema.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/app-sdk/v1/listing.schema.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/agent-event.schema.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/close-codes.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/constants.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/hello.schema.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/input-refused.schema.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/screen-text.schema.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/settings.schema.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/stream.schema.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/scripts/hatch_build.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/__main__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/api.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/checkouts.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/schemes.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/source.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/wda.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/xcresult.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/xctestplan.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/app_command.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/config_command.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/device_command.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/helper.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/mcp.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/open_viewer.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/record.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/serve.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/settings_command.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/tokens.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/tools.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/version.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/wda.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/xcode.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/config/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/config/discovery.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/config/env.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/config/observe_languages.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/config/provenance.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/config/settings_store.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/config/toml_source.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/config/writer.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/app/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/app/client.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/app/discovery.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/app/document.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/app/errors.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/app/merge.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/app/reader.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/app/wire.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/helper_process.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/idb/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/idb/companion.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/idb/connector.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/idb/engine.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/idb/frameworks.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/idb/orientation.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/idb/proto/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/idb/proto/idb.proto +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/idb/proto/idb_grpc.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/idb/proto/idb_pb2.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/iphone/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/iphone/cable.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/iphone/capture.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/iphone/screen.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/iphone/wda.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/iphone/wda_client.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/iphone/wda_setup.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/iphone/wda_source.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/mcpbridge/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/mcpbridge/client.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/mcpbridge/connector.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/mcpbridge/hierarchy.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/mcpbridge/merge.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/mcpbridge/reader.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/native/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/native/client.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/native/connector.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/native/helper.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/native/wire.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/simctl/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/simctl/capture.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/simctl/connector.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/availability.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/device_logs.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/device_settings.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/devices.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/events.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/gestures.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/reaper.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/recording_sources.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/recordings.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/refusals.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/render.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/signing.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/status.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/text_entry.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/text_overlay.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/tickets.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/app.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/auth.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/confirmations.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/health.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/lease.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/lifecycle.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/passes.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/pauses.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/policy.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/tokens.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/doctor/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/doctor/macos.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/doctor/real_devices.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/doctor/report.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/doctor/tap.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/doctor/worktree.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/hosting.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/mcp/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/mcp/launcher.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/mcp/relay.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/bar_names.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/budget.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/imagehash.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/in_front.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/model.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/occlusion.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/ocr.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/orientation.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/readers.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/settle.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/snapshot.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/system_alert.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/vision/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/vision/helper.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/vision/probe.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/vision/text_recognizer.swift +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/wait.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/codesign.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/developer_dir.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/device_data.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/devicectl.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/errors.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/git.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/images.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/json_lines.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/keyboard.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/keychain.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/lockdown.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/process.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/simctl.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/swift.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/swiftpm.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/usbmux.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/xcrun.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/protocol/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/protocol/messages.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/py.typed +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/scope.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/seams.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/agent_routes.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/envelope.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/log_redaction.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/pages.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/security.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/settings_routes.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/settings_view.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/socket_routes.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/static/viewer/embed.html +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/static/viewer/index.html +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/storage/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/storage/app_support.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/storage/claims.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/storage/private.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/app_sdk.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/asgi.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/checkouts.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/contract.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/daemon.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-alert-ios27.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-alert-ipad-landscape-left-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-alert-ipad-upside-down-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-alert-turned-left-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-alert-turned-right-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-alert-upright-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-app-sdk-alert.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-app-sdk-keyboard.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-app-sdk-swiftui.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-app-sdk-tagged.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-app-sdk-uikit.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-files-navigation-bar-de-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-files-tab-bar-de-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-floating-button-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-health-tab-bar-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-home-complete.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-home-ios27.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-keyboard-ios27.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-native-files-navigation-bar-de-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-probe-ios27.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-probe-ipad-upside-down-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-probe-rotated-left-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-safari-ios27.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-safari-typed.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-settings-back-button-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-settings-interactable.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-settings-ios27.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-settings-search-field-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-settings-toolbar-ja-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-settings-under-navigation-bar-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-turned-landscape-left-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-turned-landscape-right-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-turned-maps-alert-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-turned-portrait-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-turned-reminders-portrait-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-turned-safari-landscape-left-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-turned-safari-landscape-right-ios26.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/development-certificate.pem +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/devicectl-appearance.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/devicectl-apps.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/devicectl-devices.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/devicectl-displays.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/devicectl-launch-missing.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/devicectl-launch.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/devicectl-lock-state.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/devicectl-processes.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/devicectl-screenshot.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/mcpbridge-answers.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/mcpbridge-hierarchy-alert.txt +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/mcpbridge-hierarchy-home.txt +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/mcpbridge-hierarchy-keyboard.txt +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/mcpbridge-hierarchy-probe.txt +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/mcpbridge-hierarchy-safari.txt +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/mcpbridge-hierarchy-settings.txt +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/simctl-devices.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/simctl-runtimes.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcodebuild-list-names.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcodebuild-list.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcodebuild-settings-test.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcodebuild-settings.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcodebuild-test-plans-none.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcodebuild-test-plans.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-build-broken.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-build-ok.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-build-results-unbuilt.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-test-summary-retries.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-test-summary-swift-testing-xcode27.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-test-summary-swift-testing.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-test-summary-unbuilt.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-test-summary.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-test-tests-retries.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-test-tests-swift-testing-xcode27.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-test-tests-swift-testing.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-test-tests.json +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcscheme-staging.xcscheme +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcscheme-test-plans.xcscheme +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xctestplan-everything.xctestplan +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xctestplan-units-only.xctestplan +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/native.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/pictures.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/recording.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/usbmux.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/vision.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/wda.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/__init__.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/act.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/context.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/record.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/registry.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/results.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/screenshot.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/snapshot.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/validation.py +0 -0
- {sim_mirror-2.1.0 → sim_mirror-2.2.0}/viewer/README.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sim-mirror
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Mirror and drive iOS Simulators and real iPhones from Claude Code, CLI agents and the browser.
|
|
5
5
|
Project-URL: Homepage, https://github.com/AndrewKochulab/sim-mirror
|
|
6
6
|
Project-URL: Documentation, https://github.com/AndrewKochulab/sim-mirror/tree/main/docs
|
|
@@ -39,7 +39,7 @@ Description-Content-Type: text/markdown
|
|
|
39
39
|
|
|
40
40
|
# SimMirror
|
|
41
41
|
|
|
42
|
-
**Mirror and drive iOS Simulators
|
|
42
|
+
**Mirror and drive iOS Simulators, real iPhones and Android devices from Claude Code, CLI agents and the browser.**
|
|
43
43
|
|
|
44
44
|
[](https://github.com/AndrewKochulab/sim-mirror/actions/workflows/ci.yml)
|
|
45
45
|
[](LICENSE)
|
|
@@ -52,16 +52,18 @@ through its notes, then fills in and saves a new one, the agent's cursor gliding
|
|
|
52
52
|
*A real session, sped up four times. [The whole recording](https://github.com/AndrewKochulab/sim-mirror/releases/download/v1.2.0/sim-mirror-plugin-demo.mp4)
|
|
53
53
|
runs 1m 39s.*
|
|
54
54
|
|
|
55
|
-
A live iOS Simulator -- or your own iPhone, over its cable -- in any browser tab or
|
|
55
|
+
A live iOS Simulator -- or your own iPhone, over its cable, or an Android emulator or phone -- in any browser tab or
|
|
56
|
+
web page, an animated cursor that
|
|
56
57
|
shows exactly what your AI agent is about to tap, and token-efficient UI snapshots so agents read the screen as compact
|
|
57
58
|
text instead of screenshots. Record any screen as an MP4 or a GIF for a pull request. Works with Claude Code, Codex,
|
|
58
59
|
Cursor and any other MCP client.
|
|
59
60
|
|
|
60
|
-
> **Status: 2.
|
|
61
|
+
> **Status: 2.2.** The agent tools, the viewer, the protocol and the embedding API are stable, and a check holds every
|
|
61
62
|
> release to [what SimMirror promises not to break](docs/stability.md). 2.0 brought real iPhones and iPads beside the
|
|
62
63
|
> simulators -- live over the cable, driven through WebDriverAgent -- and records any screen as an MP4 or a GIF. 2.1
|
|
63
64
|
> reads and touches apps turned to landscape, keeps taps off what a tab bar covers, builds the worktree the agent works
|
|
64
|
-
> in, and adds observe mode for walkthroughs on accounts an agent must not change.
|
|
65
|
+
> in, and adds observe mode for walkthroughs on accounts an agent must not change. 2.2 adds Android emulators and
|
|
66
|
+
> phones, with the same viewer, cursor and tools. It removes nothing 1.x promised.
|
|
65
67
|
|
|
66
68
|
## Why SimMirror
|
|
67
69
|
|
|
@@ -89,7 +91,7 @@ Cursor and any other MCP client.
|
|
|
89
91
|
**Any MCP client**, as a stdio server:
|
|
90
92
|
|
|
91
93
|
```sh
|
|
92
|
-
claude mcp add sim-mirror -- uvx --from sim-mirror==2.
|
|
94
|
+
claude mcp add sim-mirror -- uvx --from sim-mirror==2.2.0 sim-mirror mcp
|
|
93
95
|
```
|
|
94
96
|
|
|
95
97
|
Configurations for [Codex](docs/clients/codex.md), [Cursor](docs/clients/cursor.md) and
|
|
@@ -98,7 +100,7 @@ Configurations for [Codex](docs/clients/codex.md), [Cursor](docs/clients/cursor.
|
|
|
98
100
|
**The command**, for `sim-mirror open`, `doctor` and the rest:
|
|
99
101
|
|
|
100
102
|
```sh
|
|
101
|
-
uv tool install sim-mirror==2.
|
|
103
|
+
uv tool install sim-mirror==2.2.0
|
|
102
104
|
# or
|
|
103
105
|
brew install andrewkochulab/tap/sim-mirror
|
|
104
106
|
```
|
|
@@ -165,6 +167,11 @@ location through Xcode's `devicectl`; and touching, typing and its element tree
|
|
|
165
167
|
with a click and signed by your project's own team -- a tap lands in about a third of a second. It is reached only over
|
|
166
168
|
the cable, and what SimMirror changes on it is put back when it is let go. See [Real devices](docs/real-devices.md).
|
|
167
169
|
|
|
170
|
+
**Android.** Android emulators and phones sit beside the simulators, with the same viewer, cursor and tools: adb
|
|
171
|
+
lists, starts and drives them, scrcpy's server -- set up once with a click -- shows the screen live, UI Automator reads
|
|
172
|
+
it for snapshots, and `sim_build_run` and `sim_test` build a Gradle project with its own wrapper. A phone is never
|
|
173
|
+
started or shut down, and what SimMirror changes on it is put back. See [Android](docs/android.md).
|
|
174
|
+
|
|
168
175
|
**Recording.** The viewer's Record button, `sim_record` or `sim-mirror record` keep a device's screen as an MP4, a GIF
|
|
169
176
|
or both, with each touch drawn where it landed and a 9:41 status bar, and `preset: "pr"` keeps one small enough for
|
|
170
177
|
a pull request. See [Recording](docs/recording.md).
|
|
@@ -219,6 +226,7 @@ an image at about 750 pixels a token).
|
|
|
219
226
|
| Xcode | 26 and 27 |
|
|
220
227
|
| Connectors | native helper (full control), idb_companion 1.5 (full control), simctl (view-only) |
|
|
221
228
|
| Real devices | an iPhone or iPad that Xcode's `devicectl` reaches, by cable (view-only without WebDriverAgent) |
|
|
229
|
+
| Android | emulators and phones adb reaches, with the Android SDK; scrcpy 5.0.1 for the live screen; Gradle builds |
|
|
222
230
|
| App SDK | Debug builds on the iOS Simulator, iOS 16 or later |
|
|
223
231
|
| Clients | Claude Code, Codex, Cursor, any stdio MCP client |
|
|
224
232
|
| Browsers | Chrome, Safari, Firefox, Edge |
|
|
@@ -244,8 +252,8 @@ the [command line](docs/reference/cli.md) and the [protocol](docs/reference/prot
|
|
|
244
252
|
| **v1.0** | Stable protocol and embedding API, held by a check; PyPI, npm and the MCP Registry; a cursor that stays while the agent works |
|
|
245
253
|
| **v1.2** | SimMirror's own native helper instead of idb_companion, screens read from their pixels and settling past endless animations, an optional in-app debug SDK, and a Homebrew tap |
|
|
246
254
|
| **v2.0** | Real iPhones and iPads: the live screen over the cable, apps, logs, look and location without signing; full control through WebDriverAgent; recording a screen as an MP4 or GIF |
|
|
247
|
-
| **v2.1**
|
|
248
|
-
| **
|
|
255
|
+
| **v2.1** | Apps turned to landscape and `sim_device rotate`, taps kept off what bars cover, builds of the agent's worktree, observe mode, `sim-mirror stop`, and recordings sized for a pull request |
|
|
256
|
+
| **v2.2** (now) | Android emulators and phones with the same viewer, cursor and tools: adb, scrcpy's live screen, and Gradle builds |
|
|
249
257
|
| **Website & launch** | Landing page, video tutorials and guides |
|
|
250
258
|
|
|
251
259
|
See [ROADMAP.md](ROADMAP.md) and the [milestones](https://github.com/AndrewKochulab/sim-mirror/milestones). How
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# SimMirror
|
|
4
4
|
|
|
5
|
-
**Mirror and drive iOS Simulators
|
|
5
|
+
**Mirror and drive iOS Simulators, real iPhones and Android devices from Claude Code, CLI agents and the browser.**
|
|
6
6
|
|
|
7
7
|
[](https://github.com/AndrewKochulab/sim-mirror/actions/workflows/ci.yml)
|
|
8
8
|
[](LICENSE)
|
|
@@ -15,16 +15,18 @@ through its notes, then fills in and saves a new one, the agent's cursor gliding
|
|
|
15
15
|
*A real session, sped up four times. [The whole recording](https://github.com/AndrewKochulab/sim-mirror/releases/download/v1.2.0/sim-mirror-plugin-demo.mp4)
|
|
16
16
|
runs 1m 39s.*
|
|
17
17
|
|
|
18
|
-
A live iOS Simulator -- or your own iPhone, over its cable -- in any browser tab or
|
|
18
|
+
A live iOS Simulator -- or your own iPhone, over its cable, or an Android emulator or phone -- in any browser tab or
|
|
19
|
+
web page, an animated cursor that
|
|
19
20
|
shows exactly what your AI agent is about to tap, and token-efficient UI snapshots so agents read the screen as compact
|
|
20
21
|
text instead of screenshots. Record any screen as an MP4 or a GIF for a pull request. Works with Claude Code, Codex,
|
|
21
22
|
Cursor and any other MCP client.
|
|
22
23
|
|
|
23
|
-
> **Status: 2.
|
|
24
|
+
> **Status: 2.2.** The agent tools, the viewer, the protocol and the embedding API are stable, and a check holds every
|
|
24
25
|
> release to [what SimMirror promises not to break](docs/stability.md). 2.0 brought real iPhones and iPads beside the
|
|
25
26
|
> simulators -- live over the cable, driven through WebDriverAgent -- and records any screen as an MP4 or a GIF. 2.1
|
|
26
27
|
> reads and touches apps turned to landscape, keeps taps off what a tab bar covers, builds the worktree the agent works
|
|
27
|
-
> in, and adds observe mode for walkthroughs on accounts an agent must not change.
|
|
28
|
+
> in, and adds observe mode for walkthroughs on accounts an agent must not change. 2.2 adds Android emulators and
|
|
29
|
+
> phones, with the same viewer, cursor and tools. It removes nothing 1.x promised.
|
|
28
30
|
|
|
29
31
|
## Why SimMirror
|
|
30
32
|
|
|
@@ -52,7 +54,7 @@ Cursor and any other MCP client.
|
|
|
52
54
|
**Any MCP client**, as a stdio server:
|
|
53
55
|
|
|
54
56
|
```sh
|
|
55
|
-
claude mcp add sim-mirror -- uvx --from sim-mirror==2.
|
|
57
|
+
claude mcp add sim-mirror -- uvx --from sim-mirror==2.2.0 sim-mirror mcp
|
|
56
58
|
```
|
|
57
59
|
|
|
58
60
|
Configurations for [Codex](docs/clients/codex.md), [Cursor](docs/clients/cursor.md) and
|
|
@@ -61,7 +63,7 @@ Configurations for [Codex](docs/clients/codex.md), [Cursor](docs/clients/cursor.
|
|
|
61
63
|
**The command**, for `sim-mirror open`, `doctor` and the rest:
|
|
62
64
|
|
|
63
65
|
```sh
|
|
64
|
-
uv tool install sim-mirror==2.
|
|
66
|
+
uv tool install sim-mirror==2.2.0
|
|
65
67
|
# or
|
|
66
68
|
brew install andrewkochulab/tap/sim-mirror
|
|
67
69
|
```
|
|
@@ -128,6 +130,11 @@ location through Xcode's `devicectl`; and touching, typing and its element tree
|
|
|
128
130
|
with a click and signed by your project's own team -- a tap lands in about a third of a second. It is reached only over
|
|
129
131
|
the cable, and what SimMirror changes on it is put back when it is let go. See [Real devices](docs/real-devices.md).
|
|
130
132
|
|
|
133
|
+
**Android.** Android emulators and phones sit beside the simulators, with the same viewer, cursor and tools: adb
|
|
134
|
+
lists, starts and drives them, scrcpy's server -- set up once with a click -- shows the screen live, UI Automator reads
|
|
135
|
+
it for snapshots, and `sim_build_run` and `sim_test` build a Gradle project with its own wrapper. A phone is never
|
|
136
|
+
started or shut down, and what SimMirror changes on it is put back. See [Android](docs/android.md).
|
|
137
|
+
|
|
131
138
|
**Recording.** The viewer's Record button, `sim_record` or `sim-mirror record` keep a device's screen as an MP4, a GIF
|
|
132
139
|
or both, with each touch drawn where it landed and a 9:41 status bar, and `preset: "pr"` keeps one small enough for
|
|
133
140
|
a pull request. See [Recording](docs/recording.md).
|
|
@@ -182,6 +189,7 @@ an image at about 750 pixels a token).
|
|
|
182
189
|
| Xcode | 26 and 27 |
|
|
183
190
|
| Connectors | native helper (full control), idb_companion 1.5 (full control), simctl (view-only) |
|
|
184
191
|
| Real devices | an iPhone or iPad that Xcode's `devicectl` reaches, by cable (view-only without WebDriverAgent) |
|
|
192
|
+
| Android | emulators and phones adb reaches, with the Android SDK; scrcpy 5.0.1 for the live screen; Gradle builds |
|
|
185
193
|
| App SDK | Debug builds on the iOS Simulator, iOS 16 or later |
|
|
186
194
|
| Clients | Claude Code, Codex, Cursor, any stdio MCP client |
|
|
187
195
|
| Browsers | Chrome, Safari, Firefox, Edge |
|
|
@@ -207,8 +215,8 @@ the [command line](docs/reference/cli.md) and the [protocol](docs/reference/prot
|
|
|
207
215
|
| **v1.0** | Stable protocol and embedding API, held by a check; PyPI, npm and the MCP Registry; a cursor that stays while the agent works |
|
|
208
216
|
| **v1.2** | SimMirror's own native helper instead of idb_companion, screens read from their pixels and settling past endless animations, an optional in-app debug SDK, and a Homebrew tap |
|
|
209
217
|
| **v2.0** | Real iPhones and iPads: the live screen over the cable, apps, logs, look and location without signing; full control through WebDriverAgent; recording a screen as an MP4 or GIF |
|
|
210
|
-
| **v2.1**
|
|
211
|
-
| **
|
|
218
|
+
| **v2.1** | Apps turned to landscape and `sim_device rotate`, taps kept off what bars cover, builds of the agent's worktree, observe mode, `sim-mirror stop`, and recordings sized for a pull request |
|
|
219
|
+
| **v2.2** (now) | Android emulators and phones with the same viewer, cursor and tools: adb, scrcpy's live screen, and Gradle builds |
|
|
212
220
|
| **Website & launch** | Landing page, video tutorials and guides |
|
|
213
221
|
|
|
214
222
|
See [ROADMAP.md](ROADMAP.md) and the [milestones](https://github.com/AndrewKochulab/sim-mirror/milestones). How
|
|
@@ -127,5 +127,32 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
127
127
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
+
## scrcpy server
|
|
131
|
+
|
|
132
|
+
- **What:** the server SimMirror runs on an Android device to stream its screen as H.264 and take its touches, keys
|
|
133
|
+
and text ([Android](docs/android.md)). It is **not** shipped: a person's setup (Set up touch, or `sim-mirror android
|
|
134
|
+
setup`) fetches release 5.0.1's `scrcpy-server-v5.0.1`, checks its size and SHA-256
|
|
135
|
+
(`764eb6f79811d5211fe9df341120882ba9994c7a61b897d7bf3fb662e53bc536`), and keeps it on your Mac; it is pushed to a
|
|
136
|
+
device only while SimMirror shows it, and is unchanged.
|
|
137
|
+
- **Source:** [Genymobile/scrcpy](https://github.com/Genymobile/scrcpy)
|
|
138
|
+
- **License:** Apache-2.0
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
Copyright (C) 2018 Genymobile
|
|
142
|
+
Copyright (C) 2018-2026 Romain Vimont
|
|
143
|
+
|
|
144
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
145
|
+
you may not use this file except in compliance with the License.
|
|
146
|
+
You may obtain a copy of the License at
|
|
147
|
+
|
|
148
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
149
|
+
|
|
150
|
+
Unless required by applicable law or agreed to in writing, software
|
|
151
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
152
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
153
|
+
See the License for the specific language governing permissions and
|
|
154
|
+
limitations under the License.
|
|
155
|
+
```
|
|
156
|
+
|
|
130
157
|
Runtime dependencies installed from PyPI and npm (FastAPI, Uvicorn, grpclib, protobuf, tomlkit, Pillow and others) are
|
|
131
158
|
not redistributed here; each carries its own license in its package.
|
|
@@ -13,10 +13,11 @@
|
|
|
13
13
|
- [Cursor](clients/cursor.md)
|
|
14
14
|
- [Any other MCP client](clients/other-mcp.md)
|
|
15
15
|
|
|
16
|
-
## Use it with a real device, and record
|
|
16
|
+
## Use it with a real device or Android, and record
|
|
17
17
|
|
|
18
18
|
- [Real devices](real-devices.md) -- a cabled iPhone or iPad: its live screen, apps and logs, and WebDriverAgent for
|
|
19
19
|
touch, typing and the element tree
|
|
20
|
+
- [Android](android.md) -- Android emulators and phones: adb, scrcpy's live screen, and Gradle builds and tests
|
|
20
21
|
- [Recording](recording.md) -- a screen as an MP4 or a GIF, with each touch drawn, and a demo in a pull request
|
|
21
22
|
|
|
22
23
|
## Change its settings
|
|
@@ -14,7 +14,9 @@ Each folder is one way to use SimMirror, small enough to copy.
|
|
|
14
14
|
| [custom-connector](custom-connector/) | A connector of your own, installed through the `sim_mirror.connectors` entry point, with contract tests |
|
|
15
15
|
| [token-budget](token-budget/) | Measuring what each tool's answer costs an agent |
|
|
16
16
|
| [app-sdk](app-sdk/) | An iOS app sharing its own views through SimMirrorKit: icon buttons, a tap gesture, a hand-drawn control with a describer, `.simMirror` tags |
|
|
17
|
+
| [android-app](android-app/) | An Android app and its instrumented tests, which `sim_build_run` and `sim_test` build with its Gradle wrapper |
|
|
17
18
|
|
|
18
|
-
Every example assumes a Mac with Xcode and a booted-or-bootable simulator
|
|
19
|
+
Every example assumes a Mac with Xcode and a booted-or-bootable simulator -- android-app, the Android SDK and an
|
|
20
|
+
emulator instead -- and `sim-mirror doctor` passing. The
|
|
19
21
|
examples are tested with SimMirror's own suite (`tests/examples/`), without starting a simulator; app-sdk's hosted
|
|
20
22
|
tests run on a simulator with `make sdk-app-test`.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Android app
|
|
2
|
+
|
|
3
|
+
A grocery list in one Kotlin activity, with two instrumented tests: the smallest Android project `sim_build_run` and
|
|
4
|
+
`sim_test` build, install and test on an Android emulator or phone.
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
examples/android-app/
|
|
8
|
+
├── settings.gradle.kts the Gradle build SimMirror finds
|
|
9
|
+
├── gradlew, gradle/wrapper/ its own wrapper: Gradle 9.3.1, checked by its SHA-256
|
|
10
|
+
└── app/ the one app module (AGP 9.1, Kotlin built in)
|
|
11
|
+
├── src/main/ MainActivity: type an item, press Add
|
|
12
|
+
└── src/androidTest/ MainActivityTest: startsEmpty, addsAnItem
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Try it
|
|
16
|
+
|
|
17
|
+
With an Android emulator chosen (`sim_device list`, then `choose`) and `build.tools` on, point the build at this
|
|
18
|
+
folder and ask the agent to
|
|
19
|
+
|
|
20
|
+
- build and run it: `sim_build_run` with `folder: "examples/android-app"` builds `:app:assembleDebug`, installs
|
|
21
|
+
`app-debug.apk` and launches `dev.simmirror.example`;
|
|
22
|
+
- run its tests: `sim_test` runs `:app:connectedDebugAndroidTest` on the device and answers with what failed and where;
|
|
23
|
+
`only_testing: ["dev.simmirror.example.MainActivityTest/addsAnItem"]` runs one;
|
|
24
|
+
- launch it with an item already on the list: `sim_app` `launch` with `args: ["item=Milk"]` -- each launch argument is
|
|
25
|
+
a string extra of the launch intent.
|
|
26
|
+
|
|
27
|
+
Gradle needs a JDK (17 or later): Android Studio's own is found, or name one with `android.java_home`. The first build
|
|
28
|
+
fetches Gradle and the Android Gradle plugin, which takes a minute; later builds take seconds.
|
|
29
|
+
|
|
30
|
+
From a shell, the same build is
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
cd examples/android-app
|
|
34
|
+
./gradlew :app:assembleDebug
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
SimMirror's own suite never builds this project; `make live-android` does, on an emulator.
|
|
@@ -16,7 +16,7 @@ Its tools are named `mcp__plugin_sim-mirror_sim-mirror__sim_snapshot` and so on.
|
|
|
16
16
|
## Without the plugin
|
|
17
17
|
|
|
18
18
|
```sh
|
|
19
|
-
claude mcp add sim-mirror -- uvx --from sim-mirror==2.
|
|
19
|
+
claude mcp add sim-mirror -- uvx --from sim-mirror==2.2.0 sim-mirror mcp
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
Add `--scope project` before the name to write it to the project's `.mcp.json` for everyone working on it. Its tools
|
|
@@ -30,7 +30,7 @@ simulator (its scope) and this folder as the only place builds and installs may
|
|
|
30
30
|
## Watch it
|
|
31
31
|
|
|
32
32
|
```sh
|
|
33
|
-
uvx --from sim-mirror==2.
|
|
33
|
+
uvx --from sim-mirror==2.2.0 sim-mirror open
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
opens this folder's viewer in your browser. Every gesture the agent makes is drawn there as a cursor just before it
|
|
@@ -6,7 +6,7 @@ Add [config.toml](config.toml)'s table to `~/.codex/config.toml`, then start Cod
|
|
|
6
6
|
and installs may reach. The commented `args` pin a project by name and path instead.
|
|
7
7
|
- `tool_timeout_sec` is raised because `sim_build_run` and `sim_test` can take minutes (they are there only when build
|
|
8
8
|
tools are switched on).
|
|
9
|
-
- Watch and take over in a browser: `uvx --from sim-mirror==2.
|
|
9
|
+
- Watch and take over in a browser: `uvx --from sim-mirror==2.2.0 sim-mirror open`
|
|
10
10
|
in the same folder.
|
|
11
11
|
|
|
12
12
|
The tools are the same for every client; see [claude-code-cli](../claude-code-cli/) for a first prompt to try.
|
|
@@ -6,7 +6,7 @@ one), and enable the server in Cursor's MCP settings.
|
|
|
6
6
|
- `sim-mirror mcp` gives the agent the simulator of the folder it starts in, and that folder as the only place builds
|
|
7
7
|
and installs may reach. If the tools act on the wrong project, append `"--scope", "my-app", "--root",
|
|
8
8
|
"/absolute/path/to/my-app"` to `args`.
|
|
9
|
-
- Watch and take over in a browser: `uvx --from sim-mirror==2.
|
|
9
|
+
- Watch and take over in a browser: `uvx --from sim-mirror==2.2.0 sim-mirror open`
|
|
10
10
|
in the same folder.
|
|
11
11
|
|
|
12
12
|
The tools are the same for every client; see [claude-code-cli](../claude-code-cli/) for a first prompt to try.
|
|
@@ -5,7 +5,7 @@ A Python application with SimMirror inside it: [app.py](app.py). No daemon runs;
|
|
|
5
5
|
|
|
6
6
|
```sh
|
|
7
7
|
cd examples/fastapi-embed
|
|
8
|
-
EXAMPLE_KEY=change-me uv run --with "sim-mirror==2.
|
|
8
|
+
EXAMPLE_KEY=change-me uv run --with "sim-mirror==2.2.0" \
|
|
9
9
|
uvicorn --factory app:create_app --port 7484
|
|
10
10
|
```
|
|
11
11
|
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
"enum": ["down", "move", "up", "cancel"]
|
|
19
19
|
},
|
|
20
20
|
"PanelButton": {
|
|
21
|
-
"description": "The hardware buttons a person may press from a viewer.",
|
|
21
|
+
"description": "The hardware buttons a person may press from a viewer, where the device has them (Device.buttons): Back, the app switcher and the volume buttons are an Android device's.",
|
|
22
22
|
"x-constant": "PANEL_BUTTONS",
|
|
23
|
-
"enum": ["home", "lock", "side", "siri"]
|
|
23
|
+
"enum": ["home", "lock", "side", "siri", "back", "app_switch", "volume_up", "volume_down"]
|
|
24
24
|
},
|
|
25
25
|
"KeyName": {
|
|
26
26
|
"description": "Keys that are not text. Text is sent whole, as a text input.",
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
]
|
|
32
32
|
},
|
|
33
33
|
"DeviceKind": {
|
|
34
|
-
"description": "What a device is: a simulator on this Mac,
|
|
34
|
+
"description": "What a device is: a simulator on this Mac, a real iPhone or iPad connected to it, or an Android device -- an emulator on this Mac or a phone adb reaches.",
|
|
35
35
|
"x-constant": "DEVICE_KINDS",
|
|
36
|
-
"enum": ["simulator", "physical"]
|
|
36
|
+
"enum": ["simulator", "physical", "android"]
|
|
37
37
|
},
|
|
38
38
|
"Connection": {
|
|
39
39
|
"description": "How a real device reaches this Mac: by cable, or over the network.",
|
|
@@ -107,11 +107,16 @@
|
|
|
107
107
|
},
|
|
108
108
|
"kind": {
|
|
109
109
|
"$ref": "#/$defs/DeviceKind",
|
|
110
|
-
"description": "Whether it is a simulator
|
|
110
|
+
"description": "Whether it is a simulator, a real iPhone or iPad, or an Android device. An older server does not send it: read it as simulator."
|
|
111
111
|
},
|
|
112
112
|
"connection": {
|
|
113
113
|
"oneOf": [{ "$ref": "#/$defs/Connection" }, { "type": "null" }],
|
|
114
|
-
"description": "How a real device reaches this Mac; null for a simulator. An older server does not send it."
|
|
114
|
+
"description": "How a real device reaches this Mac; null for a simulator or an emulator. An older server does not send it."
|
|
115
|
+
},
|
|
116
|
+
"buttons": {
|
|
117
|
+
"type": "array",
|
|
118
|
+
"items": { "$ref": "client-input.schema.json#/$defs/PanelButton" },
|
|
119
|
+
"description": "The hardware buttons that can be pressed on this device now; empty when none can. An older server does not send it: read it as home and lock while the device has input_button."
|
|
115
120
|
},
|
|
116
121
|
"recording": {
|
|
117
122
|
"oneOf": [{ "$ref": "#/$defs/RecordingState" }, { "type": "null" }],
|
|
@@ -122,7 +127,7 @@
|
|
|
122
127
|
"description": "Whether the device is light or dark, as SimMirror last read or set it; null until it knows. An older server does not send it."
|
|
123
128
|
}
|
|
124
129
|
},
|
|
125
|
-
"required": ["udid", "name", "runtime", "state", "reason", "since_ms", "viewers", "busy", "created", "booted_by_us", "screen", "app_hierarchy", "kind", "connection", "recording", "appearance"]
|
|
130
|
+
"required": ["udid", "name", "runtime", "state", "reason", "since_ms", "viewers", "busy", "created", "booted_by_us", "screen", "app_hierarchy", "kind", "connection", "buttons", "recording", "appearance"]
|
|
126
131
|
},
|
|
127
132
|
"RecordingState": {
|
|
128
133
|
"description": "A recording of a device's screen under way.",
|
|
@@ -54,10 +54,14 @@
|
|
|
54
54
|
"stopped": { "type": "boolean" },
|
|
55
55
|
"shut_down": {
|
|
56
56
|
"type": "boolean",
|
|
57
|
-
"description": "Whether the device was shut down too: only a simulator, and only when asked."
|
|
57
|
+
"description": "Whether the device was shut down too: only a simulator or an emulator, and only when asked."
|
|
58
|
+
},
|
|
59
|
+
"kind": {
|
|
60
|
+
"description": "What kind of device was let go; null when none was running. An older server does not send it.",
|
|
61
|
+
"oneOf": [{ "$ref": "common.schema.json#/$defs/DeviceKind" }, { "type": "null" }]
|
|
58
62
|
}
|
|
59
63
|
},
|
|
60
|
-
"required": ["stopped", "shut_down"]
|
|
64
|
+
"required": ["stopped", "shut_down", "kind"]
|
|
61
65
|
},
|
|
62
66
|
"DeviceList": {
|
|
63
67
|
"description": "GET a scope's devices: the simulators it could use, for a picker.",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
]
|
|
67
67
|
},
|
|
68
68
|
"DeviceChoice": {
|
|
69
|
-
"description": "A device a scope could use, for a device picker: a simulator on this Mac,
|
|
69
|
+
"description": "A device a scope could use, for a device picker: a simulator on this Mac, a real device connected to it, or an Android emulator or phone.",
|
|
70
70
|
"type": "object",
|
|
71
71
|
"properties": {
|
|
72
72
|
"udid": { "type": "string" },
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"runtime": { "type": "string" },
|
|
75
75
|
"state": {
|
|
76
76
|
"type": "string",
|
|
77
|
-
"description": "What simctl says of a simulator, such as Booted or Shutdown; Connected or Disconnected for a real device."
|
|
77
|
+
"description": "What simctl says of a simulator, such as Booted or Shutdown; Connected or Disconnected for a real device; Booted or Shutdown for an Android emulator, and Connected, Unauthorized or Offline for an Android phone."
|
|
78
78
|
},
|
|
79
79
|
"created": { "type": "boolean" },
|
|
80
80
|
"kind": {
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
},
|
|
84
84
|
"connection": {
|
|
85
85
|
"oneOf": [{ "$ref": "common.schema.json#/$defs/Connection" }, { "type": "null" }],
|
|
86
|
-
"description": "How a real device reaches this Mac; null for a simulator."
|
|
86
|
+
"description": "How a real device reaches this Mac; null for a simulator or an Android emulator."
|
|
87
87
|
},
|
|
88
88
|
"detail": {
|
|
89
89
|
"type": ["string", "null"],
|
|
@@ -145,6 +145,9 @@ markers = [
|
|
|
145
145
|
# tests/live/test_device_live.py: a cabled phone, driven only by `make live-device` with
|
|
146
146
|
# SIM_MIRROR_LIVE_DEVICE_UDID set; skipped everywhere else.
|
|
147
147
|
"live_device: drives a real, cabled phone",
|
|
148
|
+
# tests/live/test_android_live.py: a running Android emulator, driven only by `make live-android` with
|
|
149
|
+
# SIM_MIRROR_LIVE_ANDROID_UDID set; skipped everywhere else.
|
|
150
|
+
"live_android: drives a real, running Android emulator",
|
|
148
151
|
]
|
|
149
152
|
|
|
150
153
|
[tool.coverage.run]
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
A test run uses the scope's own device unless the call names another -- to run the tests on an older iOS, or on an
|
|
5
5
|
iPad, without changing which device the scope shows. It is named the way a person names it, ``{"name": "iPhone 17"}``
|
|
6
6
|
or ``{"udid": "…"}``, with ``"runtime": "iOS 26.5"`` to choose between simulators of one name, and must be one of the
|
|
7
|
-
iOS simulators the scope's Xcode lists (`DeviceManager.devices`)
|
|
8
|
-
with the ones there are, so an agent
|
|
7
|
+
iOS simulators the scope's Xcode lists (`DeviceManager.devices`) -- or, for an Android device's tests, one of the
|
|
8
|
+
Android devices running here. A name that matches none, or several, is refused with the ones there are, so an agent
|
|
9
|
+
can pick again rather than guess.
|
|
9
10
|
|
|
10
11
|
Whether the device is someone else's to use is the provider's to ask (`build/provider.py`): this only reads the call.
|
|
11
12
|
"""
|
|
@@ -13,6 +14,7 @@ Whether the device is someone else's to use is the provider's to ask (`build/pro
|
|
|
13
14
|
from __future__ import annotations
|
|
14
15
|
|
|
15
16
|
from collections.abc import Sequence
|
|
17
|
+
from dataclasses import dataclass
|
|
16
18
|
from typing import NoReturn
|
|
17
19
|
|
|
18
20
|
from sim_mirror.build.xcodebuild import BuildRefused
|
|
@@ -32,11 +34,29 @@ USAGE = (
|
|
|
32
34
|
)
|
|
33
35
|
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
@dataclass(frozen=True)
|
|
38
|
+
class Wording:
|
|
39
|
+
"""How a refusal names the devices a destination can be."""
|
|
40
|
+
|
|
41
|
+
usage: str
|
|
42
|
+
noun: str
|
|
43
|
+
where: str
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
SIMULATORS = Wording(USAGE, "simulator", "on this Mac for this Xcode")
|
|
47
|
+
ANDROID = Wording(
|
|
48
|
+
'destination is {"name": "Pixel 9"} or {"udid": "…"}, with "runtime": "Android 16 (API 36)" to choose between '
|
|
49
|
+
"devices of one name",
|
|
50
|
+
"Android device",
|
|
51
|
+
"running here",
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _text(value: object, wording: Wording) -> str | None:
|
|
36
56
|
if value is None:
|
|
37
57
|
return None
|
|
38
58
|
if not isinstance(value, str) or not value.strip() or len(value) > TEXT_MAX or not value.isprintable():
|
|
39
|
-
raise BuildRefused(
|
|
59
|
+
raise BuildRefused(wording.usage)
|
|
40
60
|
return value.strip()
|
|
41
61
|
|
|
42
62
|
|
|
@@ -50,13 +70,13 @@ def _listed(choices: Sequence[DeviceChoice]) -> str:
|
|
|
50
70
|
return shown + (f" and {more} more" if more > 0 else "") if shown else "none"
|
|
51
71
|
|
|
52
72
|
|
|
53
|
-
def choose_destination(choices: Sequence[DeviceChoice], value: object) -> DeviceChoice:
|
|
54
|
-
"""The
|
|
73
|
+
def choose_destination(choices: Sequence[DeviceChoice], value: object, wording: Wording = SIMULATORS) -> DeviceChoice:
|
|
74
|
+
"""The device a call's ``destination`` names, from the ones the scope could use. Raises `BuildRefused`."""
|
|
55
75
|
if not isinstance(value, dict) or not value.keys() <= KEYS or ("name" in value) == ("udid" in value):
|
|
56
|
-
raise BuildRefused(
|
|
57
|
-
name, udid, runtime = _text(value.get("name"
|
|
76
|
+
raise BuildRefused(wording.usage)
|
|
77
|
+
name, udid, runtime = (_text(value.get(key), wording) for key in ("name", "udid", "runtime"))
|
|
58
78
|
if udid is not None and kind_of(udid) is None:
|
|
59
|
-
raise BuildRefused(f"{udid!r} is not a simulator's or a real device's udid; {
|
|
79
|
+
raise BuildRefused(f"{udid!r} is not a simulator's or a real device's udid; {wording.usage}")
|
|
60
80
|
found = [
|
|
61
81
|
choice
|
|
62
82
|
for choice in choices
|
|
@@ -67,16 +87,16 @@ def choose_destination(choices: Sequence[DeviceChoice], value: object) -> Device
|
|
|
67
87
|
if len(found) == 1:
|
|
68
88
|
return found[0]
|
|
69
89
|
if found:
|
|
70
|
-
_several(name or "", found)
|
|
90
|
+
_several(name or "", found, wording)
|
|
71
91
|
wanted = udid or (f"{name} ({runtime})" if runtime else name)
|
|
72
|
-
raise BuildRefused(f"there is no
|
|
92
|
+
raise BuildRefused(f"there is no {wording.noun} {wanted} {wording.where}; there are {_listed(choices)}")
|
|
73
93
|
|
|
74
94
|
|
|
75
|
-
def _several(name: str, found: Sequence[DeviceChoice]) -> NoReturn:
|
|
95
|
+
def _several(name: str, found: Sequence[DeviceChoice], wording: Wording) -> NoReturn:
|
|
76
96
|
runtimes = sorted({choice["runtime"] for choice in found})
|
|
77
97
|
if len(runtimes) == len(found):
|
|
78
|
-
raise BuildRefused(f"several
|
|
98
|
+
raise BuildRefused(f"several {wording.noun}s are named {name}; add a runtime: {', '.join(runtimes)}")
|
|
79
99
|
raise BuildRefused(
|
|
80
|
-
f"several
|
|
100
|
+
f"several {wording.noun}s are named {name} on one runtime; name one by udid: "
|
|
81
101
|
+ ", ".join(f"{choice['udid']} ({choice['runtime']})" for choice in found[:LISTED_MAX])
|
|
82
102
|
)
|