sim-mirror 2.0.0__tar.gz → 2.1.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 (403) hide show
  1. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/PKG-INFO +46 -25
  2. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/README.md +44 -23
  3. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/examples/claude-code-cli/README.md +2 -2
  4. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/examples/codex/README.md +1 -1
  5. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/examples/cursor/README.md +1 -1
  6. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/examples/fastapi-embed/README.md +1 -1
  7. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperCore/Accessibility.swift +23 -7
  8. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperCore/Arguments.swift +2 -2
  9. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperCore/Input.swift +1 -1
  10. sim_mirror-2.1.0/helper/Sources/HelperCore/Orientation.swift +117 -0
  11. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperCore/Recording.swift +48 -0
  12. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperCore/Requests.swift +36 -3
  13. sim_mirror-2.1.0/helper/Sources/HelperCore/Rotation.swift +58 -0
  14. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperCore/Screen.swift +2 -1
  15. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperCore/Server.swift +15 -3
  16. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperCore/Wire.swift +1 -1
  17. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperPlatform/AccessibilityReader.swift +56 -6
  18. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperPlatform/CaptureDevice.swift +9 -1
  19. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperPlatform/RecordingRenderer.swift +4 -3
  20. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperPlatform/SimulatorDevice.swift +33 -10
  21. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Tests/Fixtures/wire-vectors.json +8 -0
  22. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Tests/HelperCoreTests/AccessibilityTests.swift +8 -4
  23. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Tests/HelperCoreTests/ArgumentsTests.swift +1 -1
  24. sim_mirror-2.1.0/helper/Tests/HelperCoreTests/OrientationTests.swift +113 -0
  25. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Tests/HelperCoreTests/RecordingTests.swift +17 -0
  26. sim_mirror-2.1.0/helper/Tests/HelperCoreTests/RotationTests.swift +41 -0
  27. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Tests/HelperCoreTests/ServerTests.swift +47 -6
  28. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/README.md +6 -4
  29. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/app-sdk/v1/examples/hierarchy-alert.json +3 -1
  30. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/app-sdk/v1/hierarchy.schema.json +2 -2
  31. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/v1/common.schema.json +7 -2
  32. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/v1/constants.json +2 -1
  33. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/v1/http.schema.json +22 -2
  34. sim_mirror-2.1.0/protocol/v1/input-refused.schema.json +12 -0
  35. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/pyproject.toml +4 -1
  36. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/_version.py +1 -1
  37. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/api.py +5 -0
  38. sim_mirror-2.1.0/src/sim_mirror/build/checkouts.py +259 -0
  39. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/build/provider.py +85 -17
  40. sim_mirror-2.1.0/src/sim_mirror/build/schemes.py +129 -0
  41. sim_mirror-2.1.0/src/sim_mirror/build/source.py +59 -0
  42. sim_mirror-2.1.0/src/sim_mirror/build/stamp.py +152 -0
  43. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/build/xcodebuild.py +208 -34
  44. sim_mirror-2.1.0/src/sim_mirror/build/xctestplan.py +105 -0
  45. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/cli/config_command.py +33 -2
  46. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/cli/context.py +12 -0
  47. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/cli/doctor.py +2 -0
  48. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/cli/main.py +3 -2
  49. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/cli/mcp.py +3 -0
  50. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/cli/record.py +35 -5
  51. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/cli/serve.py +3 -1
  52. sim_mirror-2.1.0/src/sim_mirror/cli/stop.py +128 -0
  53. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/config/model.py +10 -0
  54. sim_mirror-2.1.0/src/sim_mirror/config/observe_languages.py +91 -0
  55. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/config/schema.py +117 -5
  56. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/app/document.py +8 -6
  57. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/base.py +28 -4
  58. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/idb/companion.py +3 -3
  59. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/idb/connector.py +4 -2
  60. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/idb/engine.py +56 -3
  61. sim_mirror-2.1.0/src/sim_mirror/connectors/idb/orientation.py +157 -0
  62. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/iphone/connector.py +7 -4
  63. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/iphone/wda_roles.py +9 -3
  64. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/native/client.py +24 -4
  65. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/native/connector.py +18 -4
  66. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/actions.py +327 -44
  67. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/backends.py +24 -1
  68. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/control.py +47 -1
  69. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/device_changes.py +16 -2
  70. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/instance.py +27 -1
  71. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/manager.py +170 -15
  72. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/recordings.py +143 -8
  73. sim_mirror-2.1.0/src/sim_mirror/core/refusals.py +255 -0
  74. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/runtime.py +24 -5
  75. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/screen_input.py +17 -9
  76. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/screen_relay.py +38 -5
  77. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/signing.py +4 -2
  78. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/daemon/app.py +75 -1
  79. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/daemon/auth.py +21 -4
  80. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/daemon/lease.py +5 -0
  81. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/daemon/lifecycle.py +28 -0
  82. sim_mirror-2.1.0/src/sim_mirror/daemon/pauses.py +46 -0
  83. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/daemon/policy.py +3 -2
  84. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/doctor/checks.py +10 -2
  85. sim_mirror-2.1.0/src/sim_mirror/doctor/worktree.py +89 -0
  86. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/host_copy.py +33 -0
  87. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/hosting.py +32 -5
  88. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/mcp/launcher.py +157 -35
  89. sim_mirror-2.1.0/src/sim_mirror/mcp/relay.py +625 -0
  90. sim_mirror-2.1.0/src/sim_mirror/perception/bar_names.py +49 -0
  91. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/perception/imagehash.py +12 -7
  92. sim_mirror-2.1.0/src/sim_mirror/perception/in_front.py +116 -0
  93. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/perception/model.py +20 -1
  94. sim_mirror-2.1.0/src/sim_mirror/perception/occlusion.py +346 -0
  95. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/perception/ocr.py +66 -20
  96. sim_mirror-2.1.0/src/sim_mirror/perception/orientation.py +177 -0
  97. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/perception/readers.py +71 -13
  98. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/perception/settle.py +52 -23
  99. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/perception/snapshot.py +72 -15
  100. sim_mirror-2.1.0/src/sim_mirror/perception/system_alert.py +87 -0
  101. sim_mirror-2.1.0/src/sim_mirror/platform/codesign.py +38 -0
  102. sim_mirror-2.1.0/src/sim_mirror/platform/git.py +63 -0
  103. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/platform/simctl.py +16 -3
  104. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/protocol/__init__.py +2 -0
  105. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/protocol/_generated.py +27 -0
  106. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/protocol/messages.py +7 -1
  107. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/seams.py +15 -1
  108. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/server/http_routes.py +22 -6
  109. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/server/static/viewer/embed.html +1 -6
  110. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/server/static/viewer/index.html +1 -6
  111. sim_mirror-2.1.0/src/sim_mirror/server/static/viewer/start.js +35 -0
  112. sim_mirror-2.1.0/src/sim_mirror/testing/checkouts.py +72 -0
  113. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/contract.py +2 -0
  114. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/daemon.py +3 -0
  115. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fakes.py +63 -4
  116. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-alert-ipad-landscape-left-ios26.json +551 -0
  117. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-alert-ipad-upside-down-ios26.json +491 -0
  118. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-alert-turned-left-ios26.json +457 -0
  119. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-alert-turned-right-ios26.json +491 -0
  120. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-alert-upright-ios26.json +469 -0
  121. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-files-navigation-bar-de-ios26.json +551 -0
  122. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-files-tab-bar-de-ios26.json +495 -0
  123. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-floating-button-ios26.json +541 -0
  124. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-health-tab-bar-ios26.json +488 -0
  125. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-native-files-navigation-bar-de-ios26.json +427 -0
  126. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-probe-ipad-upside-down-ios26.json +133 -0
  127. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-probe-rotated-left-ios26.json +133 -0
  128. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-settings-back-button-ios26.json +395 -0
  129. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-settings-search-field-ios26.json +426 -0
  130. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-settings-toolbar-ja-ios26.json +397 -0
  131. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-settings-under-navigation-bar-ios26.json +533 -0
  132. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-turned-landscape-left-ios26.json +363 -0
  133. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-turned-landscape-right-ios26.json +363 -0
  134. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-turned-maps-alert-ios26.json +382 -0
  135. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-turned-portrait-ios26.json +370 -0
  136. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-turned-reminders-portrait-ios26.json +345 -0
  137. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-turned-safari-landscape-left-ios26.json +1166 -0
  138. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/ax-turned-safari-landscape-right-ios26.json +1166 -0
  139. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/xcodebuild-settings-test.json +55 -0
  140. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/xcscheme-staging.xcscheme +91 -0
  141. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/xcscheme-test-plans.xcscheme +86 -0
  142. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/xctestplan-everything.xctestplan +38 -0
  143. sim_mirror-2.1.0/src/sim_mirror/testing/fixtures/xctestplan-units-only.xctestplan +42 -0
  144. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/native.py +6 -0
  145. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/rig.py +18 -1
  146. sim_mirror-2.1.0/src/sim_mirror/tools/act.py +50 -0
  147. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/tools/app.py +31 -2
  148. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/tools/context.py +10 -3
  149. sim_mirror-2.1.0/src/sim_mirror/tools/device.py +240 -0
  150. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/tools/record.py +6 -1
  151. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/tools/registry.py +9 -2
  152. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/tools/results.py +2 -0
  153. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/tools/schemas.py +79 -17
  154. sim_mirror-2.0.0/src/sim_mirror/mcp/relay.py +0 -316
  155. sim_mirror-2.0.0/src/sim_mirror/server/static/viewer/start.js +0 -32
  156. sim_mirror-2.0.0/src/sim_mirror/tools/act.py +0 -31
  157. sim_mirror-2.0.0/src/sim_mirror/tools/device.py +0 -128
  158. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/.gitignore +0 -0
  159. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/LICENSE +0 -0
  160. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/NOTICE +0 -0
  161. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/THIRD_PARTY_LICENSES.md +0 -0
  162. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/docs/README.md +0 -0
  163. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/docs/media/README.md +0 -0
  164. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/examples/README.md +0 -0
  165. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/examples/custom-connector/README.md +0 -0
  166. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/examples/embed-host/README.md +0 -0
  167. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/examples/iframe/README.md +0 -0
  168. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/examples/token-budget/README.md +0 -0
  169. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/examples/web-component/README.md +0 -0
  170. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Package.swift +0 -0
  171. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperCore/Capture.swift +0 -0
  172. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperCore/FrameScheduler.swift +0 -0
  173. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperCore/JSON.swift +0 -0
  174. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperCore/Video.swift +0 -0
  175. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperPlatform/Disclaimed.swift +0 -0
  176. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperPlatform/Framebuffer.swift +0 -0
  177. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperPlatform/Frameworks.swift +0 -0
  178. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperPlatform/H264Stream.swift +0 -0
  179. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperPlatform/HIDTransports.swift +0 -0
  180. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperPlatform/Pictures.swift +0 -0
  181. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperPlatform/PixelSource.swift +0 -0
  182. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperPlatform/ScreenFeed.swift +0 -0
  183. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperPlatform/SimDeviceHandle.swift +0 -0
  184. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperPlatform/UnixSocket.swift +0 -0
  185. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperPlatform/UsbCapture.swift +0 -0
  186. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/HelperPlatform/Warming.swift +0 -0
  187. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/ObjCGuard/ObjCGuard.m +0 -0
  188. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/ObjCGuard/include/ObjCGuard.h +0 -0
  189. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Sources/sim-mirror-helper/main.swift +0 -0
  190. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Support/Info.plist +0 -0
  191. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Tests/HelperCoreTests/CaptureTests.swift +0 -0
  192. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Tests/HelperCoreTests/InputTests.swift +0 -0
  193. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Tests/HelperCoreTests/PictureTests.swift +0 -0
  194. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/helper/Tests/HelperCoreTests/WireTests.swift +0 -0
  195. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/app-sdk/v1/examples/error-inactive.json +0 -0
  196. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/app-sdk/v1/examples/error-unauthorized.json +0 -0
  197. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/app-sdk/v1/examples/hierarchy-keyboard.json +0 -0
  198. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/app-sdk/v1/examples/hierarchy-swiftui.json +0 -0
  199. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/app-sdk/v1/examples/hierarchy-tagged.json +0 -0
  200. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/app-sdk/v1/examples/hierarchy-uikit.json +0 -0
  201. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/app-sdk/v1/examples/listing.json +0 -0
  202. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/app-sdk/v1/listing.schema.json +0 -0
  203. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/v1/agent-event.schema.json +0 -0
  204. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/v1/client-input.schema.json +0 -0
  205. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/v1/close-codes.json +0 -0
  206. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/v1/hello.schema.json +0 -0
  207. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/v1/screen-text.schema.json +0 -0
  208. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/v1/settings.schema.json +0 -0
  209. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/v1/status.schema.json +0 -0
  210. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/protocol/v1/stream.schema.json +0 -0
  211. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/scripts/hatch_build.py +0 -0
  212. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/__init__.py +0 -0
  213. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/__main__.py +0 -0
  214. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/build/__init__.py +0 -0
  215. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/build/destination.py +0 -0
  216. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/build/wda.py +0 -0
  217. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/build/xcresult.py +0 -0
  218. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/cli/__init__.py +0 -0
  219. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/cli/app_command.py +0 -0
  220. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/cli/device_command.py +0 -0
  221. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/cli/devices.py +0 -0
  222. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/cli/helper.py +0 -0
  223. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/cli/open_viewer.py +0 -0
  224. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/cli/settings_command.py +0 -0
  225. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/cli/tokens.py +0 -0
  226. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/cli/tools.py +0 -0
  227. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/cli/version.py +0 -0
  228. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/cli/wda.py +0 -0
  229. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/cli/xcode.py +0 -0
  230. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/config/__init__.py +0 -0
  231. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/config/discovery.py +0 -0
  232. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/config/env.py +0 -0
  233. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/config/provenance.py +0 -0
  234. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/config/settings_store.py +0 -0
  235. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/config/toml_source.py +0 -0
  236. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/config/writer.py +0 -0
  237. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/__init__.py +0 -0
  238. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/app/__init__.py +0 -0
  239. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/app/client.py +0 -0
  240. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/app/discovery.py +0 -0
  241. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/app/errors.py +0 -0
  242. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/app/merge.py +0 -0
  243. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/app/reader.py +0 -0
  244. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/app/wire.py +0 -0
  245. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/helper_process.py +0 -0
  246. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/idb/__init__.py +0 -0
  247. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/idb/frameworks.py +0 -0
  248. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/idb/proto/__init__.py +0 -0
  249. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/idb/proto/idb.proto +0 -0
  250. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/idb/proto/idb_grpc.py +0 -0
  251. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/idb/proto/idb_pb2.py +0 -0
  252. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/iphone/__init__.py +0 -0
  253. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/iphone/cable.py +0 -0
  254. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/iphone/capture.py +0 -0
  255. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/iphone/screen.py +0 -0
  256. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/iphone/wda.py +0 -0
  257. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/iphone/wda_client.py +0 -0
  258. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/iphone/wda_setup.py +0 -0
  259. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/iphone/wda_source.py +0 -0
  260. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/mcpbridge/__init__.py +0 -0
  261. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/mcpbridge/client.py +0 -0
  262. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/mcpbridge/connector.py +0 -0
  263. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/mcpbridge/hierarchy.py +0 -0
  264. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/mcpbridge/merge.py +0 -0
  265. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/mcpbridge/reader.py +0 -0
  266. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/native/__init__.py +0 -0
  267. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/native/helper.py +0 -0
  268. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/native/wire.py +0 -0
  269. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/registry.py +0 -0
  270. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/simctl/__init__.py +0 -0
  271. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/simctl/capture.py +0 -0
  272. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/connectors/simctl/connector.py +0 -0
  273. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/__init__.py +0 -0
  274. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/availability.py +0 -0
  275. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/device_logs.py +0 -0
  276. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/device_settings.py +0 -0
  277. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/devices.py +0 -0
  278. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/events.py +0 -0
  279. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/frames.py +0 -0
  280. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/gestures.py +0 -0
  281. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/reaper.py +0 -0
  282. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/recording_sources.py +0 -0
  283. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/render.py +0 -0
  284. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/status.py +0 -0
  285. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/text_entry.py +0 -0
  286. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/text_overlay.py +0 -0
  287. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/tickets.py +0 -0
  288. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/core/touch.py +0 -0
  289. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/daemon/__init__.py +0 -0
  290. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/daemon/confirmations.py +0 -0
  291. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/daemon/health.py +0 -0
  292. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/daemon/passes.py +0 -0
  293. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/daemon/tokens.py +0 -0
  294. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/doctor/__init__.py +0 -0
  295. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/doctor/macos.py +0 -0
  296. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/doctor/real_devices.py +0 -0
  297. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/doctor/report.py +0 -0
  298. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/doctor/tap.py +0 -0
  299. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/mcp/__init__.py +0 -0
  300. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/perception/__init__.py +0 -0
  301. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/perception/budget.py +0 -0
  302. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/perception/vision/__init__.py +0 -0
  303. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/perception/vision/helper.py +0 -0
  304. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/perception/vision/probe.py +0 -0
  305. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/perception/vision/text_recognizer.swift +0 -0
  306. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/perception/wait.py +0 -0
  307. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/platform/__init__.py +0 -0
  308. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/platform/developer_dir.py +0 -0
  309. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/platform/device_data.py +0 -0
  310. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/platform/devicectl.py +0 -0
  311. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/platform/errors.py +0 -0
  312. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/platform/identifiers.py +0 -0
  313. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/platform/images.py +0 -0
  314. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/platform/json_lines.py +0 -0
  315. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/platform/keyboard.py +0 -0
  316. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/platform/keychain.py +0 -0
  317. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/platform/lockdown.py +0 -0
  318. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/platform/process.py +0 -0
  319. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/platform/swift.py +0 -0
  320. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/platform/swiftpm.py +0 -0
  321. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/platform/usbmux.py +0 -0
  322. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/platform/xcode.py +0 -0
  323. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/platform/xcrun.py +0 -0
  324. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/py.typed +0 -0
  325. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/scope.py +0 -0
  326. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/server/__init__.py +0 -0
  327. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/server/agent_routes.py +0 -0
  328. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/server/envelope.py +0 -0
  329. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/server/log_redaction.py +0 -0
  330. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/server/pages.py +0 -0
  331. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/server/security.py +0 -0
  332. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/server/settings_routes.py +0 -0
  333. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/server/settings_view.py +0 -0
  334. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/server/socket_routes.py +0 -0
  335. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/storage/__init__.py +0 -0
  336. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/storage/app_support.py +0 -0
  337. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/storage/claims.py +0 -0
  338. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/storage/private.py +0 -0
  339. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/__init__.py +0 -0
  340. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/app_sdk.py +0 -0
  341. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/asgi.py +0 -0
  342. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/ax-alert-ios27.json +0 -0
  343. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/ax-app-sdk-alert.json +0 -0
  344. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/ax-app-sdk-keyboard.json +0 -0
  345. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/ax-app-sdk-swiftui.json +0 -0
  346. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/ax-app-sdk-tagged.json +0 -0
  347. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/ax-app-sdk-uikit.json +0 -0
  348. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/ax-home-complete.json +0 -0
  349. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/ax-home-ios27.json +0 -0
  350. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/ax-keyboard-ios27.json +0 -0
  351. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/ax-probe-ios27.json +0 -0
  352. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/ax-safari-ios27.json +0 -0
  353. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/ax-safari-typed.json +0 -0
  354. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/ax-settings-interactable.json +0 -0
  355. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/ax-settings-ios27.json +0 -0
  356. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/development-certificate.pem +0 -0
  357. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/devicectl-appearance.json +0 -0
  358. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/devicectl-apps.json +0 -0
  359. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/devicectl-devices.json +0 -0
  360. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/devicectl-displays.json +0 -0
  361. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/devicectl-launch-missing.json +0 -0
  362. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/devicectl-launch.json +0 -0
  363. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/devicectl-lock-state.json +0 -0
  364. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/devicectl-processes.json +0 -0
  365. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/devicectl-screenshot.json +0 -0
  366. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/mcpbridge-answers.json +0 -0
  367. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/mcpbridge-hierarchy-alert.txt +0 -0
  368. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/mcpbridge-hierarchy-home.txt +0 -0
  369. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/mcpbridge-hierarchy-keyboard.txt +0 -0
  370. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/mcpbridge-hierarchy-probe.txt +0 -0
  371. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/mcpbridge-hierarchy-safari.txt +0 -0
  372. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/mcpbridge-hierarchy-settings.txt +0 -0
  373. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/simctl-devices.json +0 -0
  374. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/simctl-runtimes.json +0 -0
  375. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/xcodebuild-list-names.json +0 -0
  376. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/xcodebuild-list.json +0 -0
  377. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/xcodebuild-settings.json +0 -0
  378. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/xcodebuild-test-plans-none.json +0 -0
  379. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/xcodebuild-test-plans.json +0 -0
  380. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/xcresult-build-broken.json +0 -0
  381. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/xcresult-build-ok.json +0 -0
  382. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/xcresult-build-results-unbuilt.json +0 -0
  383. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/xcresult-test-summary-retries.json +0 -0
  384. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/xcresult-test-summary-swift-testing-xcode27.json +0 -0
  385. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/xcresult-test-summary-swift-testing.json +0 -0
  386. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/xcresult-test-summary-unbuilt.json +0 -0
  387. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/xcresult-test-summary.json +0 -0
  388. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/xcresult-test-tests-retries.json +0 -0
  389. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/xcresult-test-tests-swift-testing-xcode27.json +0 -0
  390. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/xcresult-test-tests-swift-testing.json +0 -0
  391. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/fixtures/xcresult-test-tests.json +0 -0
  392. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/guards.py +0 -0
  393. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/pictures.py +0 -0
  394. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/recording.py +0 -0
  395. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/usbmux.py +0 -0
  396. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/vision.py +0 -0
  397. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/testing/wda.py +0 -0
  398. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/tools/__init__.py +0 -0
  399. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/tools/screenshot.py +0 -0
  400. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/tools/snapshot.py +0 -0
  401. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/src/sim_mirror/validation.py +0 -0
  402. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/tests/unit/protocol/test_messages.py +0 -0
  403. {sim_mirror-2.0.0 → sim_mirror-2.1.0}/viewer/README.md +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sim-mirror
3
- Version: 2.0.0
4
- Summary: Mirror and drive the iOS Simulator from Claude Code, CLI agents and the browser.
3
+ Version: 2.1.0
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
7
7
  Project-URL: Issues, https://github.com/AndrewKochulab/sim-mirror/issues
@@ -39,7 +39,7 @@ Description-Content-Type: text/markdown
39
39
 
40
40
  # SimMirror
41
41
 
42
- **Mirror and drive the iOS Simulator from Claude Code, CLI agents and the browser.**
42
+ **Mirror and drive iOS Simulators and real iPhones 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,14 +52,16 @@ 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 in any browser tab or web page, an animated cursor that shows exactly what your AI agent is about
56
- to tap, and token-efficient UI snapshots so agents read the screen as compact text instead of screenshots. Works with
57
- Claude Code, Codex, Cursor and any other MCP client.
55
+ A live iOS Simulator -- or your own iPhone, over its cable -- in any browser tab or web page, an animated cursor that
56
+ shows exactly what your AI agent is about to tap, and token-efficient UI snapshots so agents read the screen as compact
57
+ text instead of screenshots. Record any screen as an MP4 or a GIF for a pull request. Works with Claude Code, Codex,
58
+ Cursor and any other MCP client.
58
59
 
59
- > **Status: 2.0.** The agent tools, the viewer, the protocol and the embedding API are stable, and a check holds every
60
- > release to [what SimMirror promises not to break](docs/stability.md). 2.0 brings real iPhones and iPads beside the
61
- > simulators -- live over the cable, driven through WebDriverAgent -- and records any screen as an MP4 or a GIF. It
62
- > removes nothing 1.x promised.
60
+ > **Status: 2.1.** The agent tools, the viewer, the protocol and the embedding API are stable, and a check holds every
61
+ > release to [what SimMirror promises not to break](docs/stability.md). 2.0 brought real iPhones and iPads beside the
62
+ > simulators -- live over the cable, driven through WebDriverAgent -- and records any screen as an MP4 or a GIF. 2.1
63
+ > 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.
63
65
 
64
66
  ## Why SimMirror
65
67
 
@@ -71,6 +73,9 @@ Claude Code, Codex, Cursor and any other MCP client.
71
73
  in batches with waits, and reach for a screenshot only when a question is visual.
72
74
  - **Read screens accessibility cannot.** A game or a canvas reads from its pixels, and an app under development can
73
75
  share its own views, so icon-only buttons and hand-drawn controls read by name.
76
+ - **Test on a real iPhone.** Plug it in and it sits beside the simulators: live over the cable at up to 60 fps, touched
77
+ and typed on from the browser or by an agent, and given back everything SimMirror changed on it.
78
+ - **Show what happened.** Record a flow as an MP4 or a GIF with every touch drawn in, and put it in a pull request.
74
79
 
75
80
  ## Install
76
81
 
@@ -84,7 +89,7 @@ Claude Code, Codex, Cursor and any other MCP client.
84
89
  **Any MCP client**, as a stdio server:
85
90
 
86
91
  ```sh
87
- claude mcp add sim-mirror -- uvx --from sim-mirror==2.0.0 sim-mirror mcp
92
+ claude mcp add sim-mirror -- uvx --from sim-mirror==2.1.0 sim-mirror mcp
88
93
  ```
89
94
 
90
95
  Configurations for [Codex](docs/clients/codex.md), [Cursor](docs/clients/cursor.md) and
@@ -93,7 +98,7 @@ Configurations for [Codex](docs/clients/codex.md), [Cursor](docs/clients/cursor.
93
98
  **The command**, for `sim-mirror open`, `doctor` and the rest:
94
99
 
95
100
  ```sh
96
- uv tool install sim-mirror==2.0.0
101
+ uv tool install sim-mirror==2.1.0
97
102
  # or
98
103
  brew install andrewkochulab/tap/sim-mirror
99
104
  ```
@@ -103,8 +108,8 @@ brew install andrewkochulab/tap/sim-mirror
103
108
  [on PyPI](https://pypi.org/project/sim-mirror/) and in a [Homebrew tap](https://github.com/AndrewKochulab/homebrew-tap).
104
109
 
105
110
  **Requirements:** an Apple Silicon Mac, Xcode 26 or later, and [uv](https://docs.astral.sh/uv/) or Homebrew. Nothing
106
- else: SimMirror drives a simulator with its own helper, which comes in the package. Details in
107
- [Installation](docs/installation.md).
111
+ else: SimMirror drives a simulator with its own helper, which comes in the package. A real iPhone needs Developer Mode,
112
+ and an Apple development team to be touched. Details in [Installation](docs/installation.md).
108
113
 
109
114
  ## Quickstart
110
115
 
@@ -118,6 +123,12 @@ Then ask your agent:
118
123
  > Open Settings → General → About and tell me which iOS version this simulator runs. Use sim_snapshot rather than
119
124
  > screenshots.
120
125
 
126
+ With an iPhone plugged in, unlocked and in Developer Mode:
127
+
128
+ > Switch to my iPhone, build and run the app on it, walk through sign-up and record it as a GIF.
129
+
130
+ The first time, press **Set up touch** in the viewer: it builds WebDriverAgent with your project's own signing team.
131
+
121
132
  [Getting started](docs/getting-started.md) explains what happens along the way.
122
133
 
123
134
  ## Features
@@ -131,8 +142,13 @@ the viewer's own pointer glides there first (`agent.cursor_lead_ms`). Never the
131
142
 
132
143
  **Screen understanding.** A snapshot is a few lines -- `e2 button "General" (201,319)` -- with refs that stay with their
133
144
  elements across scrolls, a digest, and diffs. `sim_act` plays up to 20 steps in one call and waits for text, its
134
- absence, or the screen to settle -- past a spinner or a pulsing dot that never stops. See
135
- [Screen understanding](docs/screen-understanding.md).
145
+ absence, or the screen to settle -- past a spinner or a pulsing dot that never stops. An app turned to landscape is
146
+ read and touched in its own points, `sim_device rotate` turns a simulator, and a tap on what a tab bar, a toolbar or
147
+ the keyboard covers is refused with how to reach it. See [Screen understanding](docs/screen-understanding.md).
148
+
149
+ **Observe mode.** For a walkthrough on an account the agent must not change, `agent.observe` refuses a tap on what
150
+ reads like Delete, Save, Send or Sign out -- in English and a dozen other languages, or styled destructive by its app --
151
+ unless the call confirms it. See [Security](docs/security.md).
136
152
 
137
153
  **Reading pixels.** A screen whose accessibility says nothing -- a game, a canvas, an app still loading -- reads as the
138
154
  text macOS's Vision finds in it, with refs to tap and text to wait for, and the viewer can outline what was read
@@ -143,13 +159,15 @@ in a Debug build on the simulator it shares its own UIKit and SwiftUI views, so
143
159
  gesture or a hand-drawn control reads by name, and `.simMirror("Settings")` names a SwiftUI view. Optional, and nothing
144
160
  of it is in a Release build. See [The app SDK](docs/app-sdk.md).
145
161
 
146
- **Real devices.** A cabled iPhone or iPad shows up beside the simulators: its live screen over the cable, its apps,
147
- logs, look and location through Xcode's `devicectl`, and touching, typing and its element tree through a WebDriverAgent
148
- you build with your own team. What SimMirror changes on it is put back when it is let go. See
149
- [Real devices](docs/real-devices.md).
162
+ **Real devices.** A cabled iPhone or iPad shows up beside the simulators, and an agent can switch to it
163
+ (`sim_device list` and `choose`): its live screen over the cable, at about 55 frames a second; its apps, logs, look and
164
+ location through Xcode's `devicectl`; and touching, typing and its element tree through WebDriverAgent, set up once
165
+ 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
+ the cable, and what SimMirror changes on it is put back when it is let go. See [Real devices](docs/real-devices.md).
150
167
 
151
168
  **Recording.** The viewer's Record button, `sim_record` or `sim-mirror record` keep a device's screen as an MP4, a GIF
152
- or both, with each touch drawn where it landed and a 9:41 status bar. See [Recording](docs/recording.md).
169
+ or both, with each touch drawn where it landed and a 9:41 status bar, and `preset: "pr"` keeps one small enough for
170
+ a pull request. See [Recording](docs/recording.md).
153
171
 
154
172
  **Connectors.** SimMirror's own native helper gives full control with nothing to install; idb_companion still can,
155
173
  and the simctl connector mirrors the screen view-only when neither is there, and says why. `auto` uses the fastest that
@@ -172,7 +190,9 @@ scoped tokens, and one-shot codes in URL fragments. See [Security](docs/security
172
190
 
173
191
  **Build and test.** `sim_build_run` and `sim_test` build with xcodebuild for the agent's simulator, install and
174
192
  launch, and answer with only what failed and where -- each failing test named so it can be run again alone, and on
175
- another simulator when asked. Off by default, since they run commands: `sim-mirror config set build.tools true`.
193
+ another simulator when asked -- and with the folder, branch and commit they built. They build the git worktree the
194
+ agent works in, with the configuration its scheme runs. Off by default, since they run commands: `sim-mirror config
195
+ set build.tools true`.
176
196
 
177
197
  ## Measure the token cost
178
198
 
@@ -206,8 +226,8 @@ an image at about 750 pixels a token).
206
226
  Rows checked on real hardware are marked verified, with the date, in [Compatibility](docs/compatibility.md).
207
227
 
208
228
  From 1.0 the tools, the protocol, the embedding API, the viewer package, settings and the command line are held to
209
- [what SimMirror promises not to break](docs/stability.md): a release adds, and never breaks; 2.0 broke nothing. Connectors are the
210
- exception, and pin a minor version.
229
+ [what SimMirror promises not to break](docs/stability.md): a release adds, and never breaks; 2.0 broke nothing.
230
+ Connectors are the exception, and pin a minor version.
211
231
 
212
232
  ## Documentation
213
233
 
@@ -223,7 +243,8 @@ the [command line](docs/reference/cli.md) and the [protocol](docs/reference/prot
223
243
  | **v0.2** | Build, run and test tools, a settings panel, Xcode 27's UI hierarchy through `mcpbridge`, one shared daemon for many hosts |
224
244
  | **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 |
225
245
  | **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 |
226
- | **v2.0** (now) | 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 |
246
+ | **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 |
227
248
  | **Android** | Android emulator support with the same viewer, cursor and tools |
228
249
  | **Website & launch** | Landing page, video tutorials and guides |
229
250
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  # SimMirror
4
4
 
5
- **Mirror and drive the iOS Simulator from Claude Code, CLI agents and the browser.**
5
+ **Mirror and drive iOS Simulators and real iPhones 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,14 +15,16 @@ 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 in any browser tab or web page, an animated cursor that shows exactly what your AI agent is about
19
- to tap, and token-efficient UI snapshots so agents read the screen as compact text instead of screenshots. Works with
20
- Claude Code, Codex, Cursor and any other MCP client.
18
+ A live iOS Simulator -- or your own iPhone, over its cable -- in any browser tab or web page, an animated cursor that
19
+ shows exactly what your AI agent is about to tap, and token-efficient UI snapshots so agents read the screen as compact
20
+ text instead of screenshots. Record any screen as an MP4 or a GIF for a pull request. Works with Claude Code, Codex,
21
+ Cursor and any other MCP client.
21
22
 
22
- > **Status: 2.0.** The agent tools, the viewer, the protocol and the embedding API are stable, and a check holds every
23
- > release to [what SimMirror promises not to break](docs/stability.md). 2.0 brings real iPhones and iPads beside the
24
- > simulators -- live over the cable, driven through WebDriverAgent -- and records any screen as an MP4 or a GIF. It
25
- > removes nothing 1.x promised.
23
+ > **Status: 2.1.** The agent tools, the viewer, the protocol and the embedding API are stable, and a check holds every
24
+ > release to [what SimMirror promises not to break](docs/stability.md). 2.0 brought real iPhones and iPads beside the
25
+ > simulators -- live over the cable, driven through WebDriverAgent -- and records any screen as an MP4 or a GIF. 2.1
26
+ > 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.
26
28
 
27
29
  ## Why SimMirror
28
30
 
@@ -34,6 +36,9 @@ Claude Code, Codex, Cursor and any other MCP client.
34
36
  in batches with waits, and reach for a screenshot only when a question is visual.
35
37
  - **Read screens accessibility cannot.** A game or a canvas reads from its pixels, and an app under development can
36
38
  share its own views, so icon-only buttons and hand-drawn controls read by name.
39
+ - **Test on a real iPhone.** Plug it in and it sits beside the simulators: live over the cable at up to 60 fps, touched
40
+ and typed on from the browser or by an agent, and given back everything SimMirror changed on it.
41
+ - **Show what happened.** Record a flow as an MP4 or a GIF with every touch drawn in, and put it in a pull request.
37
42
 
38
43
  ## Install
39
44
 
@@ -47,7 +52,7 @@ Claude Code, Codex, Cursor and any other MCP client.
47
52
  **Any MCP client**, as a stdio server:
48
53
 
49
54
  ```sh
50
- claude mcp add sim-mirror -- uvx --from sim-mirror==2.0.0 sim-mirror mcp
55
+ claude mcp add sim-mirror -- uvx --from sim-mirror==2.1.0 sim-mirror mcp
51
56
  ```
52
57
 
53
58
  Configurations for [Codex](docs/clients/codex.md), [Cursor](docs/clients/cursor.md) and
@@ -56,7 +61,7 @@ Configurations for [Codex](docs/clients/codex.md), [Cursor](docs/clients/cursor.
56
61
  **The command**, for `sim-mirror open`, `doctor` and the rest:
57
62
 
58
63
  ```sh
59
- uv tool install sim-mirror==2.0.0
64
+ uv tool install sim-mirror==2.1.0
60
65
  # or
61
66
  brew install andrewkochulab/tap/sim-mirror
62
67
  ```
@@ -66,8 +71,8 @@ brew install andrewkochulab/tap/sim-mirror
66
71
  [on PyPI](https://pypi.org/project/sim-mirror/) and in a [Homebrew tap](https://github.com/AndrewKochulab/homebrew-tap).
67
72
 
68
73
  **Requirements:** an Apple Silicon Mac, Xcode 26 or later, and [uv](https://docs.astral.sh/uv/) or Homebrew. Nothing
69
- else: SimMirror drives a simulator with its own helper, which comes in the package. Details in
70
- [Installation](docs/installation.md).
74
+ else: SimMirror drives a simulator with its own helper, which comes in the package. A real iPhone needs Developer Mode,
75
+ and an Apple development team to be touched. Details in [Installation](docs/installation.md).
71
76
 
72
77
  ## Quickstart
73
78
 
@@ -81,6 +86,12 @@ Then ask your agent:
81
86
  > Open Settings → General → About and tell me which iOS version this simulator runs. Use sim_snapshot rather than
82
87
  > screenshots.
83
88
 
89
+ With an iPhone plugged in, unlocked and in Developer Mode:
90
+
91
+ > Switch to my iPhone, build and run the app on it, walk through sign-up and record it as a GIF.
92
+
93
+ The first time, press **Set up touch** in the viewer: it builds WebDriverAgent with your project's own signing team.
94
+
84
95
  [Getting started](docs/getting-started.md) explains what happens along the way.
85
96
 
86
97
  ## Features
@@ -94,8 +105,13 @@ the viewer's own pointer glides there first (`agent.cursor_lead_ms`). Never the
94
105
 
95
106
  **Screen understanding.** A snapshot is a few lines -- `e2 button "General" (201,319)` -- with refs that stay with their
96
107
  elements across scrolls, a digest, and diffs. `sim_act` plays up to 20 steps in one call and waits for text, its
97
- absence, or the screen to settle -- past a spinner or a pulsing dot that never stops. See
98
- [Screen understanding](docs/screen-understanding.md).
108
+ absence, or the screen to settle -- past a spinner or a pulsing dot that never stops. An app turned to landscape is
109
+ read and touched in its own points, `sim_device rotate` turns a simulator, and a tap on what a tab bar, a toolbar or
110
+ the keyboard covers is refused with how to reach it. See [Screen understanding](docs/screen-understanding.md).
111
+
112
+ **Observe mode.** For a walkthrough on an account the agent must not change, `agent.observe` refuses a tap on what
113
+ reads like Delete, Save, Send or Sign out -- in English and a dozen other languages, or styled destructive by its app --
114
+ unless the call confirms it. See [Security](docs/security.md).
99
115
 
100
116
  **Reading pixels.** A screen whose accessibility says nothing -- a game, a canvas, an app still loading -- reads as the
101
117
  text macOS's Vision finds in it, with refs to tap and text to wait for, and the viewer can outline what was read
@@ -106,13 +122,15 @@ in a Debug build on the simulator it shares its own UIKit and SwiftUI views, so
106
122
  gesture or a hand-drawn control reads by name, and `.simMirror("Settings")` names a SwiftUI view. Optional, and nothing
107
123
  of it is in a Release build. See [The app SDK](docs/app-sdk.md).
108
124
 
109
- **Real devices.** A cabled iPhone or iPad shows up beside the simulators: its live screen over the cable, its apps,
110
- logs, look and location through Xcode's `devicectl`, and touching, typing and its element tree through a WebDriverAgent
111
- you build with your own team. What SimMirror changes on it is put back when it is let go. See
112
- [Real devices](docs/real-devices.md).
125
+ **Real devices.** A cabled iPhone or iPad shows up beside the simulators, and an agent can switch to it
126
+ (`sim_device list` and `choose`): its live screen over the cable, at about 55 frames a second; its apps, logs, look and
127
+ location through Xcode's `devicectl`; and touching, typing and its element tree through WebDriverAgent, set up once
128
+ 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
+ the cable, and what SimMirror changes on it is put back when it is let go. See [Real devices](docs/real-devices.md).
113
130
 
114
131
  **Recording.** The viewer's Record button, `sim_record` or `sim-mirror record` keep a device's screen as an MP4, a GIF
115
- or both, with each touch drawn where it landed and a 9:41 status bar. See [Recording](docs/recording.md).
132
+ or both, with each touch drawn where it landed and a 9:41 status bar, and `preset: "pr"` keeps one small enough for
133
+ a pull request. See [Recording](docs/recording.md).
116
134
 
117
135
  **Connectors.** SimMirror's own native helper gives full control with nothing to install; idb_companion still can,
118
136
  and the simctl connector mirrors the screen view-only when neither is there, and says why. `auto` uses the fastest that
@@ -135,7 +153,9 @@ scoped tokens, and one-shot codes in URL fragments. See [Security](docs/security
135
153
 
136
154
  **Build and test.** `sim_build_run` and `sim_test` build with xcodebuild for the agent's simulator, install and
137
155
  launch, and answer with only what failed and where -- each failing test named so it can be run again alone, and on
138
- another simulator when asked. Off by default, since they run commands: `sim-mirror config set build.tools true`.
156
+ another simulator when asked -- and with the folder, branch and commit they built. They build the git worktree the
157
+ agent works in, with the configuration its scheme runs. Off by default, since they run commands: `sim-mirror config
158
+ set build.tools true`.
139
159
 
140
160
  ## Measure the token cost
141
161
 
@@ -169,8 +189,8 @@ an image at about 750 pixels a token).
169
189
  Rows checked on real hardware are marked verified, with the date, in [Compatibility](docs/compatibility.md).
170
190
 
171
191
  From 1.0 the tools, the protocol, the embedding API, the viewer package, settings and the command line are held to
172
- [what SimMirror promises not to break](docs/stability.md): a release adds, and never breaks; 2.0 broke nothing. Connectors are the
173
- exception, and pin a minor version.
192
+ [what SimMirror promises not to break](docs/stability.md): a release adds, and never breaks; 2.0 broke nothing.
193
+ Connectors are the exception, and pin a minor version.
174
194
 
175
195
  ## Documentation
176
196
 
@@ -186,7 +206,8 @@ the [command line](docs/reference/cli.md) and the [protocol](docs/reference/prot
186
206
  | **v0.2** | Build, run and test tools, a settings panel, Xcode 27's UI hierarchy through `mcpbridge`, one shared daemon for many hosts |
187
207
  | **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 |
188
208
  | **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 |
189
- | **v2.0** (now) | 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 |
209
+ | **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 |
190
211
  | **Android** | Android emulator support with the same viewer, cursor and tools |
191
212
  | **Website & launch** | Landing page, video tutorials and guides |
192
213
 
@@ -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.0.0 sim-mirror mcp
19
+ claude mcp add sim-mirror -- uvx --from sim-mirror==2.1.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.0.0 sim-mirror open
33
+ uvx --from sim-mirror==2.1.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.0.0 sim-mirror open`
9
+ - Watch and take over in a browser: `uvx --from sim-mirror==2.1.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.0.0 sim-mirror open`
9
+ - Watch and take over in a browser: `uvx --from sim-mirror==2.1.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.0.0" \
8
+ EXAMPLE_KEY=change-me uv run --with "sim-mirror==2.1.0" \
9
9
  uvicorn --factory app:create_app --port 7484
10
10
  ```
11
11
 
@@ -36,12 +36,17 @@ public enum AccessibilityValue: Equatable, Sendable {
36
36
  /// One element of a screen's accessibility tree, read from the device.
37
37
  ///
38
38
  /// Only what SimMirror reads of an element is kept. Each attribute is a round trip to the simulator, and a snapshot
39
- /// reads every element, so an attribute nothing reads -- a role's description, help text, custom actions -- is not
40
- /// asked for at all.
39
+ /// reads every element, so an attribute nothing reads -- help text, custom actions -- is not asked for at all. A role's
40
+ /// description is asked of a group only: it is how a navigation bar says what it is.
41
41
  public struct AXNode: Equatable, Sendable {
42
+ /// The role of an element that only holds others, as a navigation bar, a tab bar and a toolbar are listed.
43
+ public static let groupRole = "AXGroup"
44
+
42
45
  /// Its role as the accessibility API says it, ``AXButton``.
43
46
  public var role: String?
44
47
  public var subrole: String?
48
+ /// What its role is called, in the device's language: ``Nav bar`` for a navigation bar UIKit lists as a group.
49
+ public var roleDescription: String?
45
50
  public var label: String?
46
51
  public var title: String?
47
52
  public var identifier: String?
@@ -53,12 +58,14 @@ public struct AXNode: Equatable, Sendable {
53
58
  public var children: [AXNode]
54
59
 
55
60
  public init(
56
- role: String? = nil, subrole: String? = nil, label: String? = nil, title: String? = nil,
57
- identifier: String? = nil, value: AccessibilityValue? = nil, frame: Rect = Rect(x: 0, y: 0, width: 0, height: 0),
58
- traits: UInt64? = nil, enabled: Bool = true, children: [AXNode] = []
61
+ role: String? = nil, subrole: String? = nil, roleDescription: String? = nil, label: String? = nil,
62
+ title: String? = nil, identifier: String? = nil, value: AccessibilityValue? = nil,
63
+ frame: Rect = Rect(x: 0, y: 0, width: 0, height: 0), traits: UInt64? = nil, enabled: Bool = true,
64
+ children: [AXNode] = []
59
65
  ) {
60
66
  self.role = role
61
67
  self.subrole = subrole
68
+ self.roleDescription = roleDescription
62
69
  self.label = label
63
70
  self.title = title
64
71
  self.identifier = identifier
@@ -111,12 +118,15 @@ public enum AXDocument {
111
118
  "Tab", "Key", "DisclosureTriangle",
112
119
  ]
113
120
 
114
- public static func make(root: AXNode, screen: ScreenGeometry) -> JSONValue {
115
- let elements = kept(root)
121
+ /// The document of a tree. Its frames are the interface's points, and its ``orientation`` says how that interface
122
+ /// lies on the screen, whose portrait size ``screen`` is.
123
+ public static func make(_ tree: AXTree, screen: ScreenGeometry) -> JSONValue {
124
+ let elements = kept(tree.root)
116
125
  return .object([
117
126
  "backend": .string("native"),
118
127
  "elements": .array(elements),
119
128
  "modal": .null,
129
+ "orientation": .string(tree.orientation.rawValue),
120
130
  "screen": .object([
121
131
  "coordinate_space": .string("screen"),
122
132
  "width": .int(screen.widthPt),
@@ -126,6 +136,11 @@ public enum AXDocument {
126
136
  ])
127
137
  }
128
138
 
139
+ /// What was found at points of the screen: each element alone, as the document writes one, or null.
140
+ public static func found(_ nodes: [AXNode?]) -> JSONValue {
141
+ .object(["elements": .array(nodes.map { $0.map { element($0, children: []) } ?? .null })])
142
+ }
143
+
129
144
  /// A role without its ``AX`` prefix: ``AXButton`` is ``Button``.
130
145
  public static func type(of role: String?) -> String? {
131
146
  guard let role else { return nil }
@@ -148,6 +163,7 @@ public enum AXDocument {
148
163
  .object([
149
164
  "type": .text(type(of: node.role)),
150
165
  "subrole": .text(node.subrole),
166
+ "role_description": .text(node.roleDescription),
151
167
  "label": .text(node.label),
152
168
  "title": .text(node.title),
153
169
  "identifier": .text(node.identifier),
@@ -142,7 +142,7 @@ public struct ServeOptions: Equatable, Sendable {
142
142
  /// What `sim-mirror-helper version` prints.
143
143
  public struct VersionReport: Equatable, Sendable, Encodable {
144
144
  /// What this helper can do besides serving a simulator, so SimMirror asks only a helper that can.
145
- public static let features = ["render", "capture"]
145
+ public static let features = ["render", "capture", "rotate", "at"]
146
146
 
147
147
  public let version: String
148
148
  public let wire: Int
@@ -217,7 +217,7 @@ public struct SelfCheckReport: Equatable, Sendable, Encodable {
217
217
  return "\(jpeg.width)x\(jpeg.height), \(jpeg.data.count) bytes"
218
218
  }
219
219
  await check("input") { "through \(try device.input().transport.name)" }
220
- await check("element tree") { "\(count(try await device.tree())) elements" }
220
+ await check("element tree") { "\(count(try await device.tree().root)) elements" }
221
221
  return SelfCheckReport(parts: parts)
222
222
  }
223
223
 
@@ -2,7 +2,7 @@
2
2
  import Foundation
3
3
 
4
4
  /// One input event, as SimMirror sends it: a finger at a point, a hardware button or a keyboard key, down or up.
5
- /// Points are the device's points, portrait.
5
+ /// Points are the screen's own portrait points, whichever way an app's interface is turned: so is a simulator's digitizer.
6
6
  public struct HIDEvent: Equatable, Sendable, Codable {
7
7
  public enum Kind: String, Sendable, Codable { case touch, button, key }
8
8
  public enum Phase: String, Sendable, Codable { case down, up }
@@ -0,0 +1,117 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ import Foundation
3
+
4
+ /// How an app's interface lies on the device's screen, as UIKit names the four ways.
5
+ ///
6
+ /// A simulator's screen never turns: its framebuffer, its touches and `ScreenGeometry` are the device's portrait points
7
+ /// whichever way the interface is drawn. Accessibility answers in the interface's own points, so a tree read from an app
8
+ /// turned to landscape is 874 wide on a screen 402 wide. The orientation is what turns one into the other. The device
9
+ /// turned in Simulator.app is no different: measured on iOS 26.5, its framebuffer stays portrait too.
10
+ public enum InterfaceOrientation: String, Sendable, CaseIterable {
11
+ case portrait
12
+ case portraitUpsideDown = "portrait_upside_down"
13
+ case landscapeLeft = "landscape_left"
14
+ case landscapeRight = "landscape_right"
15
+
16
+ /// Whether the interface is the screen turned a quarter, so its width is the screen's height.
17
+ public var sideways: Bool {
18
+ self == .landscapeLeft || self == .landscapeRight
19
+ }
20
+
21
+ /// Where a point on the screen, in the screen's portrait points, is in the interface's points.
22
+ ///
23
+ /// Measured on an iPhone 17 Pro simulator: an app turned to landscape right is drawn with its top along the
24
+ /// screen's right edge, so the screen's top right corner is the interface's top left.
25
+ public func interfacePoint(x: Double, y: Double, on screen: ScreenGeometry) -> (x: Double, y: Double) {
26
+ let width = Double(screen.widthPt)
27
+ let height = Double(screen.heightPt)
28
+ switch self {
29
+ case .portrait: return (x, y)
30
+ case .portraitUpsideDown: return (width - x, height - y)
31
+ case .landscapeRight: return (y, width - x)
32
+ case .landscapeLeft: return (height - y, x)
33
+ }
34
+ }
35
+
36
+ /// Where a point of the interface, in its points, is on the screen, in the screen's portrait points.
37
+ public func screenPoint(x: Double, y: Double, on screen: ScreenGeometry) -> (x: Double, y: Double) {
38
+ let width = Double(screen.widthPt)
39
+ let height = Double(screen.heightPt)
40
+ switch self {
41
+ case .portrait: return (x, y)
42
+ case .portraitUpsideDown: return (width - x, height - y)
43
+ case .landscapeRight: return (width - y, x)
44
+ case .landscapeLeft: return (y, height - x)
45
+ }
46
+ }
47
+
48
+ /// How many of a tree's elements are looked for on the screen before points of it are.
49
+ static let elementsAsked = 4
50
+
51
+ /// The share of the screen probed for which way the interface is turned, across and down: inside the edges, and
52
+ /// nowhere two orientations put the same interface point.
53
+ static let probes: [(Double, Double)] = [
54
+ (0.3, 0.25), (0.7, 0.25), (0.3, 0.75), (0.7, 0.75), (0.5, 0.15), (0.5, 0.85), (0.2, 0.5), (0.8, 0.5),
55
+ ]
56
+
57
+ /// Which way a tree's interface is turned, from the size of its root -- the frontmost application -- and what is
58
+ /// found at points of the screen.
59
+ ///
60
+ /// An interface as wide as the screen is portrait or upside down, and one as wide as the screen is tall is one of the
61
+ /// landscapes. Which of the two is told by asking what is at a point of the screen (`hit`, answering the frame of
62
+ /// the element there in the interface's points, as the tree's are). The middle of one of the tree's small elements
63
+ /// is asked for where each of the two would put it on the screen: only the right one finds an element there. Then
64
+ /// points spread over the screen are asked: only the right one puts the point inside what is found. A point that
65
+ /// finds nothing, or an element both would put it in, tells nothing, and the next is asked. When none tells, the
66
+ /// first of the two: portrait, or landscape right -- where UIKit puts an app that takes either landscape.
67
+ public static func find(
68
+ _ root: AXNode, screen: ScreenGeometry, hit: (_ x: Double, _ y: Double) -> Rect?
69
+ ) -> InterfaceOrientation {
70
+ let interface = root.frame
71
+ let wideScreen = screen.widthPt > screen.heightPt
72
+ let quarter = interface.width > 0 && interface.height > 0 && (interface.width > interface.height) != wideScreen
73
+ let candidates: [InterfaceOrientation] = quarter ? [.landscapeRight, .landscapeLeft] : [.portrait, .portraitUpsideDown]
74
+ let most = Double(screen.widthPt * screen.heightPt) / 4
75
+ let small = leaves(root).filter { $0.width >= 4 && $0.height >= 4 && $0.width * $0.height <= most }
76
+ for frame in small.prefix(elementsAsked) {
77
+ let middle = (x: frame.x + frame.width / 2, y: frame.y + frame.height / 2)
78
+ let fitting = candidates.filter { candidate in
79
+ let point = candidate.screenPoint(x: middle.x, y: middle.y, on: screen)
80
+ return hit(point.x, point.y)?.contains(point: middle) ?? false
81
+ }
82
+ if fitting.count == 1 { return fitting[0] }
83
+ }
84
+ for (across, down) in probes {
85
+ let x = across * Double(screen.widthPt)
86
+ let y = down * Double(screen.heightPt)
87
+ guard let found = hit(x, y), found.width > 0, found.height > 0 else { continue }
88
+ let fitting = candidates.filter { found.contains(point: $0.interfacePoint(x: x, y: y, on: screen)) }
89
+ if fitting.count == 1 { return fitting[0] }
90
+ }
91
+ return candidates[0]
92
+ }
93
+
94
+ /// The frames of the elements with nothing inside them, in the tree's order.
95
+ static func leaves(_ node: AXNode) -> [Rect] {
96
+ node.children.isEmpty ? [node.frame] : node.children.flatMap(leaves)
97
+ }
98
+ }
99
+
100
+ extension Rect {
101
+ /// Whether a point is inside, edges included, give or take half a point.
102
+ func contains(point: (x: Double, y: Double)) -> Bool {
103
+ let slack = 0.5
104
+ return point.x >= x - slack && point.x <= x + width + slack && point.y >= y - slack && point.y <= y + height + slack
105
+ }
106
+ }
107
+
108
+ /// A screen's accessibility tree and the way its interface is turned, which its frames are measured in.
109
+ public struct AXTree: Equatable, Sendable {
110
+ public let root: AXNode
111
+ public let orientation: InterfaceOrientation
112
+
113
+ public init(root: AXNode, orientation: InterfaceOrientation = .portrait) {
114
+ self.root = root
115
+ self.orientation = orientation
116
+ }
117
+ }