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.
Files changed (447) hide show
  1. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/PKG-INFO +17 -9
  2. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/README.md +16 -8
  3. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/THIRD_PARTY_LICENSES.md +27 -0
  4. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/docs/README.md +2 -1
  5. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/examples/README.md +3 -1
  6. sim_mirror-2.2.0/examples/android-app/README.md +37 -0
  7. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/examples/claude-code-cli/README.md +2 -2
  8. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/examples/codex/README.md +1 -1
  9. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/examples/cursor/README.md +1 -1
  10. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/examples/fastapi-embed/README.md +1 -1
  11. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Wire.swift +1 -1
  12. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/client-input.schema.json +2 -2
  13. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/common.schema.json +10 -5
  14. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/http.schema.json +6 -2
  15. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/status.schema.json +3 -3
  16. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/pyproject.toml +3 -0
  17. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/_version.py +1 -1
  18. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/destination.py +34 -14
  19. sim_mirror-2.2.0/src/sim_mirror/build/gradle.py +483 -0
  20. sim_mirror-2.2.0/src/sim_mirror/build/gradle_log.py +73 -0
  21. sim_mirror-2.2.0/src/sim_mirror/build/junit.py +125 -0
  22. sim_mirror-2.2.0/src/sim_mirror/build/project_files.py +52 -0
  23. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/provider.py +33 -12
  24. sim_mirror-2.2.0/src/sim_mirror/build/runner.py +450 -0
  25. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/stamp.py +40 -0
  26. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/xcodebuild.py +153 -382
  27. sim_mirror-2.2.0/src/sim_mirror/cli/android.py +135 -0
  28. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/context.py +40 -1
  29. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/devices.py +17 -5
  30. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/doctor.py +1 -0
  31. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/main.py +2 -1
  32. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/stop.py +6 -2
  33. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/config/model.py +11 -0
  34. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/config/schema.py +65 -3
  35. sim_mirror-2.2.0/src/sim_mirror/connectors/android/__init__.py +2 -0
  36. sim_mirror-2.2.0/src/sim_mirror/connectors/android/adb_input.py +125 -0
  37. sim_mirror-2.2.0/src/sim_mirror/connectors/android/connector.py +230 -0
  38. sim_mirror-2.2.0/src/sim_mirror/connectors/android/geometry.py +115 -0
  39. sim_mirror-2.2.0/src/sim_mirror/connectors/android/keys.py +55 -0
  40. sim_mirror-2.2.0/src/sim_mirror/connectors/android/scrcpy.py +269 -0
  41. sim_mirror-2.2.0/src/sim_mirror/connectors/android/scrcpy_roles.py +202 -0
  42. sim_mirror-2.2.0/src/sim_mirror/connectors/android/scrcpy_source.py +204 -0
  43. sim_mirror-2.2.0/src/sim_mirror/connectors/android/screen.py +69 -0
  44. sim_mirror-2.2.0/src/sim_mirror/connectors/android/uiautomator.py +256 -0
  45. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/base.py +23 -3
  46. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/iphone/connector.py +2 -1
  47. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/iphone/wda_roles.py +3 -0
  48. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/registry.py +26 -3
  49. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/actions.py +9 -4
  50. sim_mirror-2.2.0/src/sim_mirror/core/android_backend.py +254 -0
  51. sim_mirror-2.2.0/src/sim_mirror/core/android_control.py +424 -0
  52. sim_mirror-2.2.0/src/sim_mirror/core/android_devices.py +249 -0
  53. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/backends.py +32 -6
  54. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/control.py +24 -1
  55. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/device_changes.py +36 -13
  56. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/frames.py +23 -2
  57. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/instance.py +7 -0
  58. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/manager.py +42 -21
  59. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/runtime.py +53 -6
  60. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/screen_input.py +16 -2
  61. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/screen_relay.py +2 -1
  62. sim_mirror-2.2.0/src/sim_mirror/core/touch.py +212 -0
  63. sim_mirror-2.2.0/src/sim_mirror/doctor/android.py +118 -0
  64. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/doctor/checks.py +47 -9
  65. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/host_copy.py +23 -0
  66. sim_mirror-2.2.0/src/sim_mirror/platform/adb.py +488 -0
  67. sim_mirror-2.2.0/src/sim_mirror/platform/android_sdk.py +164 -0
  68. sim_mirror-2.2.0/src/sim_mirror/platform/emulator.py +268 -0
  69. sim_mirror-2.2.0/src/sim_mirror/platform/identifiers.py +69 -0
  70. sim_mirror-2.2.0/src/sim_mirror/platform/java.py +71 -0
  71. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/xcode.py +10 -0
  72. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/protocol/_generated.py +28 -8
  73. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/http_routes.py +5 -4
  74. sim_mirror-2.2.0/src/sim_mirror/server/static/viewer/start.js +35 -0
  75. sim_mirror-2.2.0/src/sim_mirror/testing/adb.py +422 -0
  76. sim_mirror-2.2.0/src/sim_mirror/testing/android_sdk.py +43 -0
  77. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fakes.py +79 -2
  78. sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-am-start-bad.txt +3 -0
  79. sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-am-start.txt +8 -0
  80. sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-logcat-uid.txt +12 -0
  81. sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-package-missing.txt +1 -0
  82. sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-package.txt +45 -0
  83. sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-pm-uid.txt +2 -0
  84. sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-uiautomator-landscape.xml +1 -0
  85. sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-uiautomator-search.xml +1 -0
  86. sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-uiautomator-settings.xml +1 -0
  87. sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-window-search.txt +493 -0
  88. sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/android-window-settings.txt +491 -0
  89. sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/gradle-aapt-error.log +55 -0
  90. sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/gradle-kotlin-error.log +51 -0
  91. sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/gradle-output-metadata.json +21 -0
  92. sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/gradle-test-failure.log +166 -0
  93. sim_mirror-2.2.0/src/sim_mirror/testing/fixtures/junit-android-failure.xml +48 -0
  94. sim_mirror-2.2.0/src/sim_mirror/testing/gradle.py +123 -0
  95. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/guards.py +29 -5
  96. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/rig.py +10 -0
  97. sim_mirror-2.2.0/src/sim_mirror/testing/scrcpy.py +148 -0
  98. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/app.py +32 -12
  99. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/device.py +56 -21
  100. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/schemas.py +29 -22
  101. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/tests/unit/protocol/test_messages.py +1 -0
  102. sim_mirror-2.1.0/src/sim_mirror/core/touch.py +0 -99
  103. sim_mirror-2.1.0/src/sim_mirror/platform/identifiers.py +0 -41
  104. sim_mirror-2.1.0/src/sim_mirror/server/static/viewer/start.js +0 -35
  105. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/.gitignore +0 -0
  106. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/LICENSE +0 -0
  107. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/NOTICE +0 -0
  108. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/docs/media/README.md +0 -0
  109. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/examples/custom-connector/README.md +0 -0
  110. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/examples/embed-host/README.md +0 -0
  111. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/examples/iframe/README.md +0 -0
  112. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/examples/token-budget/README.md +0 -0
  113. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/examples/web-component/README.md +0 -0
  114. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Package.swift +0 -0
  115. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Accessibility.swift +0 -0
  116. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Arguments.swift +0 -0
  117. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Capture.swift +0 -0
  118. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/FrameScheduler.swift +0 -0
  119. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Input.swift +0 -0
  120. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/JSON.swift +0 -0
  121. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Orientation.swift +0 -0
  122. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Recording.swift +0 -0
  123. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Requests.swift +0 -0
  124. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Rotation.swift +0 -0
  125. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Screen.swift +0 -0
  126. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Server.swift +0 -0
  127. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperCore/Video.swift +0 -0
  128. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/AccessibilityReader.swift +0 -0
  129. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/CaptureDevice.swift +0 -0
  130. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/Disclaimed.swift +0 -0
  131. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/Framebuffer.swift +0 -0
  132. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/Frameworks.swift +0 -0
  133. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/H264Stream.swift +0 -0
  134. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/HIDTransports.swift +0 -0
  135. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/Pictures.swift +0 -0
  136. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/PixelSource.swift +0 -0
  137. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/RecordingRenderer.swift +0 -0
  138. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/ScreenFeed.swift +0 -0
  139. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/SimDeviceHandle.swift +0 -0
  140. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/SimulatorDevice.swift +0 -0
  141. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/UnixSocket.swift +0 -0
  142. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/UsbCapture.swift +0 -0
  143. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/HelperPlatform/Warming.swift +0 -0
  144. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/ObjCGuard/ObjCGuard.m +0 -0
  145. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/ObjCGuard/include/ObjCGuard.h +0 -0
  146. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Sources/sim-mirror-helper/main.swift +0 -0
  147. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Support/Info.plist +0 -0
  148. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/Fixtures/wire-vectors.json +0 -0
  149. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/HelperCoreTests/AccessibilityTests.swift +0 -0
  150. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/HelperCoreTests/ArgumentsTests.swift +0 -0
  151. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/HelperCoreTests/CaptureTests.swift +0 -0
  152. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/HelperCoreTests/InputTests.swift +0 -0
  153. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/HelperCoreTests/OrientationTests.swift +0 -0
  154. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/HelperCoreTests/PictureTests.swift +0 -0
  155. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/HelperCoreTests/RecordingTests.swift +0 -0
  156. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/HelperCoreTests/RotationTests.swift +0 -0
  157. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/HelperCoreTests/ServerTests.swift +0 -0
  158. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/helper/Tests/HelperCoreTests/WireTests.swift +0 -0
  159. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/README.md +0 -0
  160. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/app-sdk/v1/examples/error-inactive.json +0 -0
  161. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/app-sdk/v1/examples/error-unauthorized.json +0 -0
  162. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/app-sdk/v1/examples/hierarchy-alert.json +0 -0
  163. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/app-sdk/v1/examples/hierarchy-keyboard.json +0 -0
  164. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/app-sdk/v1/examples/hierarchy-swiftui.json +0 -0
  165. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/app-sdk/v1/examples/hierarchy-tagged.json +0 -0
  166. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/app-sdk/v1/examples/hierarchy-uikit.json +0 -0
  167. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/app-sdk/v1/examples/listing.json +0 -0
  168. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/app-sdk/v1/hierarchy.schema.json +0 -0
  169. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/app-sdk/v1/listing.schema.json +0 -0
  170. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/agent-event.schema.json +0 -0
  171. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/close-codes.json +0 -0
  172. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/constants.json +0 -0
  173. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/hello.schema.json +0 -0
  174. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/input-refused.schema.json +0 -0
  175. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/screen-text.schema.json +0 -0
  176. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/settings.schema.json +0 -0
  177. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/protocol/v1/stream.schema.json +0 -0
  178. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/scripts/hatch_build.py +0 -0
  179. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/__init__.py +0 -0
  180. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/__main__.py +0 -0
  181. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/api.py +0 -0
  182. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/__init__.py +0 -0
  183. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/checkouts.py +0 -0
  184. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/schemes.py +0 -0
  185. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/source.py +0 -0
  186. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/wda.py +0 -0
  187. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/xcresult.py +0 -0
  188. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/build/xctestplan.py +0 -0
  189. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/__init__.py +0 -0
  190. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/app_command.py +0 -0
  191. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/config_command.py +0 -0
  192. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/device_command.py +0 -0
  193. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/helper.py +0 -0
  194. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/mcp.py +0 -0
  195. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/open_viewer.py +0 -0
  196. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/record.py +0 -0
  197. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/serve.py +0 -0
  198. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/settings_command.py +0 -0
  199. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/tokens.py +0 -0
  200. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/tools.py +0 -0
  201. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/version.py +0 -0
  202. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/wda.py +0 -0
  203. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/cli/xcode.py +0 -0
  204. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/config/__init__.py +0 -0
  205. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/config/discovery.py +0 -0
  206. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/config/env.py +0 -0
  207. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/config/observe_languages.py +0 -0
  208. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/config/provenance.py +0 -0
  209. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/config/settings_store.py +0 -0
  210. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/config/toml_source.py +0 -0
  211. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/config/writer.py +0 -0
  212. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/__init__.py +0 -0
  213. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/app/__init__.py +0 -0
  214. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/app/client.py +0 -0
  215. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/app/discovery.py +0 -0
  216. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/app/document.py +0 -0
  217. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/app/errors.py +0 -0
  218. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/app/merge.py +0 -0
  219. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/app/reader.py +0 -0
  220. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/app/wire.py +0 -0
  221. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/helper_process.py +0 -0
  222. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/idb/__init__.py +0 -0
  223. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/idb/companion.py +0 -0
  224. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/idb/connector.py +0 -0
  225. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/idb/engine.py +0 -0
  226. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/idb/frameworks.py +0 -0
  227. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/idb/orientation.py +0 -0
  228. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/idb/proto/__init__.py +0 -0
  229. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/idb/proto/idb.proto +0 -0
  230. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/idb/proto/idb_grpc.py +0 -0
  231. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/idb/proto/idb_pb2.py +0 -0
  232. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/iphone/__init__.py +0 -0
  233. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/iphone/cable.py +0 -0
  234. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/iphone/capture.py +0 -0
  235. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/iphone/screen.py +0 -0
  236. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/iphone/wda.py +0 -0
  237. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/iphone/wda_client.py +0 -0
  238. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/iphone/wda_setup.py +0 -0
  239. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/iphone/wda_source.py +0 -0
  240. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/mcpbridge/__init__.py +0 -0
  241. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/mcpbridge/client.py +0 -0
  242. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/mcpbridge/connector.py +0 -0
  243. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/mcpbridge/hierarchy.py +0 -0
  244. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/mcpbridge/merge.py +0 -0
  245. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/mcpbridge/reader.py +0 -0
  246. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/native/__init__.py +0 -0
  247. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/native/client.py +0 -0
  248. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/native/connector.py +0 -0
  249. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/native/helper.py +0 -0
  250. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/native/wire.py +0 -0
  251. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/simctl/__init__.py +0 -0
  252. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/simctl/capture.py +0 -0
  253. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/connectors/simctl/connector.py +0 -0
  254. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/__init__.py +0 -0
  255. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/availability.py +0 -0
  256. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/device_logs.py +0 -0
  257. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/device_settings.py +0 -0
  258. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/devices.py +0 -0
  259. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/events.py +0 -0
  260. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/gestures.py +0 -0
  261. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/reaper.py +0 -0
  262. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/recording_sources.py +0 -0
  263. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/recordings.py +0 -0
  264. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/refusals.py +0 -0
  265. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/render.py +0 -0
  266. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/signing.py +0 -0
  267. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/status.py +0 -0
  268. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/text_entry.py +0 -0
  269. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/text_overlay.py +0 -0
  270. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/core/tickets.py +0 -0
  271. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/__init__.py +0 -0
  272. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/app.py +0 -0
  273. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/auth.py +0 -0
  274. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/confirmations.py +0 -0
  275. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/health.py +0 -0
  276. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/lease.py +0 -0
  277. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/lifecycle.py +0 -0
  278. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/passes.py +0 -0
  279. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/pauses.py +0 -0
  280. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/policy.py +0 -0
  281. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/daemon/tokens.py +0 -0
  282. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/doctor/__init__.py +0 -0
  283. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/doctor/macos.py +0 -0
  284. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/doctor/real_devices.py +0 -0
  285. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/doctor/report.py +0 -0
  286. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/doctor/tap.py +0 -0
  287. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/doctor/worktree.py +0 -0
  288. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/hosting.py +0 -0
  289. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/mcp/__init__.py +0 -0
  290. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/mcp/launcher.py +0 -0
  291. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/mcp/relay.py +0 -0
  292. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/__init__.py +0 -0
  293. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/bar_names.py +0 -0
  294. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/budget.py +0 -0
  295. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/imagehash.py +0 -0
  296. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/in_front.py +0 -0
  297. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/model.py +0 -0
  298. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/occlusion.py +0 -0
  299. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/ocr.py +0 -0
  300. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/orientation.py +0 -0
  301. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/readers.py +0 -0
  302. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/settle.py +0 -0
  303. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/snapshot.py +0 -0
  304. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/system_alert.py +0 -0
  305. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/vision/__init__.py +0 -0
  306. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/vision/helper.py +0 -0
  307. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/vision/probe.py +0 -0
  308. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/vision/text_recognizer.swift +0 -0
  309. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/perception/wait.py +0 -0
  310. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/__init__.py +0 -0
  311. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/codesign.py +0 -0
  312. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/developer_dir.py +0 -0
  313. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/device_data.py +0 -0
  314. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/devicectl.py +0 -0
  315. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/errors.py +0 -0
  316. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/git.py +0 -0
  317. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/images.py +0 -0
  318. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/json_lines.py +0 -0
  319. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/keyboard.py +0 -0
  320. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/keychain.py +0 -0
  321. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/lockdown.py +0 -0
  322. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/process.py +0 -0
  323. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/simctl.py +0 -0
  324. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/swift.py +0 -0
  325. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/swiftpm.py +0 -0
  326. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/usbmux.py +0 -0
  327. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/platform/xcrun.py +0 -0
  328. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/protocol/__init__.py +0 -0
  329. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/protocol/messages.py +0 -0
  330. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/py.typed +0 -0
  331. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/scope.py +0 -0
  332. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/seams.py +0 -0
  333. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/__init__.py +0 -0
  334. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/agent_routes.py +0 -0
  335. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/envelope.py +0 -0
  336. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/log_redaction.py +0 -0
  337. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/pages.py +0 -0
  338. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/security.py +0 -0
  339. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/settings_routes.py +0 -0
  340. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/settings_view.py +0 -0
  341. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/socket_routes.py +0 -0
  342. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/static/viewer/embed.html +0 -0
  343. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/server/static/viewer/index.html +0 -0
  344. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/storage/__init__.py +0 -0
  345. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/storage/app_support.py +0 -0
  346. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/storage/claims.py +0 -0
  347. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/storage/private.py +0 -0
  348. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/__init__.py +0 -0
  349. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/app_sdk.py +0 -0
  350. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/asgi.py +0 -0
  351. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/checkouts.py +0 -0
  352. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/contract.py +0 -0
  353. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/daemon.py +0 -0
  354. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-alert-ios27.json +0 -0
  355. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-alert-ipad-landscape-left-ios26.json +0 -0
  356. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-alert-ipad-upside-down-ios26.json +0 -0
  357. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-alert-turned-left-ios26.json +0 -0
  358. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-alert-turned-right-ios26.json +0 -0
  359. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-alert-upright-ios26.json +0 -0
  360. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-app-sdk-alert.json +0 -0
  361. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-app-sdk-keyboard.json +0 -0
  362. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-app-sdk-swiftui.json +0 -0
  363. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-app-sdk-tagged.json +0 -0
  364. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-app-sdk-uikit.json +0 -0
  365. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-files-navigation-bar-de-ios26.json +0 -0
  366. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-files-tab-bar-de-ios26.json +0 -0
  367. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-floating-button-ios26.json +0 -0
  368. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-health-tab-bar-ios26.json +0 -0
  369. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-home-complete.json +0 -0
  370. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-home-ios27.json +0 -0
  371. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-keyboard-ios27.json +0 -0
  372. {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
  373. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-probe-ios27.json +0 -0
  374. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-probe-ipad-upside-down-ios26.json +0 -0
  375. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-probe-rotated-left-ios26.json +0 -0
  376. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-safari-ios27.json +0 -0
  377. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-safari-typed.json +0 -0
  378. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-settings-back-button-ios26.json +0 -0
  379. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-settings-interactable.json +0 -0
  380. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-settings-ios27.json +0 -0
  381. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-settings-search-field-ios26.json +0 -0
  382. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-settings-toolbar-ja-ios26.json +0 -0
  383. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-settings-under-navigation-bar-ios26.json +0 -0
  384. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-turned-landscape-left-ios26.json +0 -0
  385. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-turned-landscape-right-ios26.json +0 -0
  386. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-turned-maps-alert-ios26.json +0 -0
  387. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-turned-portrait-ios26.json +0 -0
  388. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-turned-reminders-portrait-ios26.json +0 -0
  389. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-turned-safari-landscape-left-ios26.json +0 -0
  390. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/ax-turned-safari-landscape-right-ios26.json +0 -0
  391. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/development-certificate.pem +0 -0
  392. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/devicectl-appearance.json +0 -0
  393. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/devicectl-apps.json +0 -0
  394. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/devicectl-devices.json +0 -0
  395. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/devicectl-displays.json +0 -0
  396. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/devicectl-launch-missing.json +0 -0
  397. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/devicectl-launch.json +0 -0
  398. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/devicectl-lock-state.json +0 -0
  399. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/devicectl-processes.json +0 -0
  400. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/devicectl-screenshot.json +0 -0
  401. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/mcpbridge-answers.json +0 -0
  402. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/mcpbridge-hierarchy-alert.txt +0 -0
  403. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/mcpbridge-hierarchy-home.txt +0 -0
  404. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/mcpbridge-hierarchy-keyboard.txt +0 -0
  405. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/mcpbridge-hierarchy-probe.txt +0 -0
  406. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/mcpbridge-hierarchy-safari.txt +0 -0
  407. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/mcpbridge-hierarchy-settings.txt +0 -0
  408. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/simctl-devices.json +0 -0
  409. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/simctl-runtimes.json +0 -0
  410. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcodebuild-list-names.json +0 -0
  411. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcodebuild-list.json +0 -0
  412. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcodebuild-settings-test.json +0 -0
  413. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcodebuild-settings.json +0 -0
  414. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcodebuild-test-plans-none.json +0 -0
  415. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcodebuild-test-plans.json +0 -0
  416. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-build-broken.json +0 -0
  417. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-build-ok.json +0 -0
  418. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-build-results-unbuilt.json +0 -0
  419. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-test-summary-retries.json +0 -0
  420. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-test-summary-swift-testing-xcode27.json +0 -0
  421. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-test-summary-swift-testing.json +0 -0
  422. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-test-summary-unbuilt.json +0 -0
  423. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-test-summary.json +0 -0
  424. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-test-tests-retries.json +0 -0
  425. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-test-tests-swift-testing-xcode27.json +0 -0
  426. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-test-tests-swift-testing.json +0 -0
  427. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcresult-test-tests.json +0 -0
  428. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcscheme-staging.xcscheme +0 -0
  429. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xcscheme-test-plans.xcscheme +0 -0
  430. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xctestplan-everything.xctestplan +0 -0
  431. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/fixtures/xctestplan-units-only.xctestplan +0 -0
  432. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/native.py +0 -0
  433. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/pictures.py +0 -0
  434. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/recording.py +0 -0
  435. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/usbmux.py +0 -0
  436. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/vision.py +0 -0
  437. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/testing/wda.py +0 -0
  438. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/__init__.py +0 -0
  439. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/act.py +0 -0
  440. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/context.py +0 -0
  441. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/record.py +0 -0
  442. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/registry.py +0 -0
  443. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/results.py +0 -0
  444. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/screenshot.py +0 -0
  445. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/tools/snapshot.py +0 -0
  446. {sim_mirror-2.1.0 → sim_mirror-2.2.0}/src/sim_mirror/validation.py +0 -0
  447. {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.1.0
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 and real iPhones from Claude Code, CLI agents and the browser.**
42
+ **Mirror and drive iOS Simulators, real iPhones and Android devices from Claude Code, CLI agents and the browser.**
43
43
 
44
44
  [![CI](https://github.com/AndrewKochulab/sim-mirror/actions/workflows/ci.yml/badge.svg)](https://github.com/AndrewKochulab/sim-mirror/actions/workflows/ci.yml)
45
45
  [![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](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 web page, an animated cursor that
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.1.** The agent tools, the viewer, the protocol and the embedding API are stable, and a check holds every
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. It removes nothing 1.x promised.
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.1.0 sim-mirror mcp
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.1.0
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** (now) | 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 |
248
- | **Android** | Android emulator support with the same viewer, cursor and tools |
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 and real iPhones from Claude Code, CLI agents and the browser.**
5
+ **Mirror and drive iOS Simulators, real iPhones and Android devices from Claude Code, CLI agents and the browser.**
6
6
 
7
7
  [![CI](https://github.com/AndrewKochulab/sim-mirror/actions/workflows/ci.yml/badge.svg)](https://github.com/AndrewKochulab/sim-mirror/actions/workflows/ci.yml)
8
8
  [![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](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 web page, an animated cursor that
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.1.** The agent tools, the viewer, the protocol and the embedding API are stable, and a check holds every
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. It removes nothing 1.x promised.
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.1.0 sim-mirror mcp
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.1.0
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** (now) | 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 |
211
- | **Android** | Android emulator support with the same viewer, cursor and tools |
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, and `sim-mirror doctor` passing. The
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.1.0 sim-mirror mcp
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.1.0 sim-mirror open
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.1.0 sim-mirror open`
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.1.0 sim-mirror open`
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.1.0" \
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
 
@@ -3,7 +3,7 @@ import Foundation
3
3
 
4
4
  /// The helper's version, which is SimMirror's: SimMirror refuses a helper of another version.
5
5
  public enum HelperVersion {
6
- public static let current = "2.1.0"
6
+ public static let current = "2.2.0"
7
7
  }
8
8
 
9
9
  /// What a frame on the socket is.
@@ -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, or a real iPhone or iPad connected to it.",
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 or a real device. An older server does not send it: read it as 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, or a real device connected to it.",
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]
@@ -1,4 +1,4 @@
1
1
  # SPDX-License-Identifier: Apache-2.0
2
2
  """The package version, read by the build backend and by `sim-mirror version`."""
3
3
 
4
- __version__ = "2.1.0"
4
+ __version__ = "2.2.0"
@@ -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`). A name that matches none, or several, is refused
8
- with the ones there are, so an agent can pick again rather than guess.
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
- def _text(value: object) -> str | None:
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(USAGE)
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 simulator a call's ``destination`` names, from the ones the scope could use. Raises `BuildRefused`."""
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(USAGE)
57
- name, udid, runtime = _text(value.get("name")), _text(value.get("udid")), _text(value.get("runtime"))
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; {USAGE}")
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 simulator {wanted} on this Mac for this Xcode; there are {_listed(choices)}")
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 simulators are named {name}; add a runtime: {', '.join(runtimes)}")
98
+ raise BuildRefused(f"several {wording.noun}s are named {name}; add a runtime: {', '.join(runtimes)}")
79
99
  raise BuildRefused(
80
- f"several simulators are named {name} on one runtime; name one by udid: "
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
  )