mobster-cli 0.4.3__py3-none-any.whl

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 (1009) hide show
  1. mobile_agent/__init__.py +4 -0
  2. mobile_agent/__main__.py +598 -0
  3. mobile_agent/accounts/__init__.py +1 -0
  4. mobile_agent/accounts/context.py +80 -0
  5. mobile_agent/accounts/mcp.py +55 -0
  6. mobile_agent/accounts/pacing.py +318 -0
  7. mobile_agent/accounts/register.py +78 -0
  8. mobile_agent/accounts/routes.py +212 -0
  9. mobile_agent/accounts/routing.py +69 -0
  10. mobile_agent/accounts/screen.py +273 -0
  11. mobile_agent/accounts/stats.py +54 -0
  12. mobile_agent/accounts/store.py +394 -0
  13. mobile_agent/agent_hooks.py +123 -0
  14. mobile_agent/ai_plans/__init__.py +7 -0
  15. mobile_agent/ai_plans/agents.py +96 -0
  16. mobile_agent/ai_plans/claude_code.py +208 -0
  17. mobile_agent/ai_plans/cli.py +400 -0
  18. mobile_agent/ai_plans/codex.py +258 -0
  19. mobile_agent/ai_plans/compat_chat.py +307 -0
  20. mobile_agent/ai_plans/device_login.py +164 -0
  21. mobile_agent/ai_plans/draft_client.py +68 -0
  22. mobile_agent/ai_plans/gemini.py +137 -0
  23. mobile_agent/ai_plans/instructions.py +65 -0
  24. mobile_agent/ai_plans/mcp_http.py +160 -0
  25. mobile_agent/ai_plans/phone_tools.py +892 -0
  26. mobile_agent/ai_plans/providers.py +235 -0
  27. mobile_agent/ai_plans/routes.py +160 -0
  28. mobile_agent/ai_plans/runner.py +400 -0
  29. mobile_agent/ai_plans/vault.py +114 -0
  30. mobile_agent/alerts.py +337 -0
  31. mobile_agent/android/__init__.py +18 -0
  32. mobile_agent/android/adb.py +268 -0
  33. mobile_agent/android/conditions.py +128 -0
  34. mobile_agent/android/doctor.py +54 -0
  35. mobile_agent/android/driver.py +137 -0
  36. mobile_agent/android/emulator.py +216 -0
  37. mobile_agent/android/logs.py +85 -0
  38. mobile_agent/android/manager.py +225 -0
  39. mobile_agent/android/records.py +31 -0
  40. mobile_agent/android/tree.py +96 -0
  41. mobile_agent/answer_shapes.py +230 -0
  42. mobile_agent/api_devices.py +333 -0
  43. mobile_agent/api_errors.py +17 -0
  44. mobile_agent/api_get.py +249 -0
  45. mobile_agent/api_http.py +467 -0
  46. mobile_agent/api_post.py +453 -0
  47. mobile_agent/api_routes.py +173 -0
  48. mobile_agent/app_api/__init__.py +4 -0
  49. mobile_agent/app_api/cli.py +151 -0
  50. mobile_agent/app_api/endpoints.py +193 -0
  51. mobile_agent/app_api/mcp.py +54 -0
  52. mobile_agent/app_api/openapi.py +146 -0
  53. mobile_agent/app_api/reading.py +172 -0
  54. mobile_agent/app_api/register.py +10 -0
  55. mobile_agent/app_api/screen.py +216 -0
  56. mobile_agent/app_api/service.py +382 -0
  57. mobile_agent/app_api/sessions.py +404 -0
  58. mobile_agent/app_api/tokens.py +167 -0
  59. mobile_agent/app_choice.py +131 -0
  60. mobile_agent/app_icons.py +183 -0
  61. mobile_agent/app_killer.py +69 -0
  62. mobile_agent/artifacts.py +606 -0
  63. mobile_agent/attach/__init__.py +13 -0
  64. mobile_agent/attach/cli.py +46 -0
  65. mobile_agent/attach/flutter.py +28 -0
  66. mobile_agent/attach/score.py +119 -0
  67. mobile_agent/attach/web.py +13 -0
  68. mobile_agent/attachments/__init__.py +1 -0
  69. mobile_agent/attachments/agent.py +418 -0
  70. mobile_agent/attachments/extract.py +217 -0
  71. mobile_agent/attachments/mcp.py +104 -0
  72. mobile_agent/attachments/register.py +73 -0
  73. mobile_agent/attachments/routes.py +326 -0
  74. mobile_agent/attachments/service.py +170 -0
  75. mobile_agent/attachments/sniff.py +152 -0
  76. mobile_agent/attachments/store.py +441 -0
  77. mobile_agent/audit_verify.py +436 -0
  78. mobile_agent/bench/README.md +410 -0
  79. mobile_agent/bench/__init__.py +0 -0
  80. mobile_agent/bench/__main__.py +394 -0
  81. mobile_agent/bench/ab.py +168 -0
  82. mobile_agent/bench/actuation.py +368 -0
  83. mobile_agent/bench/agents/__init__.py +9 -0
  84. mobile_agent/bench/agents/base.py +105 -0
  85. mobile_agent/bench/agents/plan_clients.py +245 -0
  86. mobile_agent/bench/agents/smart.py +533 -0
  87. mobile_agent/bench/checks.py +358 -0
  88. mobile_agent/bench/decide_gate.py +214 -0
  89. mobile_agent/bench/diagnose.py +181 -0
  90. mobile_agent/bench/evals/__init__.py +14 -0
  91. mobile_agent/bench/evals/build.py +565 -0
  92. mobile_agent/bench/evals/checkpoint.py +214 -0
  93. mobile_agent/bench/evals/irt.py +219 -0
  94. mobile_agent/bench/evals/l0.py +647 -0
  95. mobile_agent/bench/evals/l1.py +866 -0
  96. mobile_agent/bench/evals/models.py +124 -0
  97. mobile_agent/bench/evals/pairwise.py +189 -0
  98. mobile_agent/bench/evals/proxy.py +90 -0
  99. mobile_agent/bench/evals/sets.py +149 -0
  100. mobile_agent/bench/evals/traces.py +446 -0
  101. mobile_agent/bench/fixtures.py +176 -0
  102. mobile_agent/bench/guard_replay.py +129 -0
  103. mobile_agent/bench/h2-manifest.json +20 -0
  104. mobile_agent/bench/h3-manifest.json +20 -0
  105. mobile_agent/bench/heldout-manifest.json +32 -0
  106. mobile_agent/bench/heldout.py +375 -0
  107. mobile_agent/bench/iosworld.py +901 -0
  108. mobile_agent/bench/iosworld_stats.py +510 -0
  109. mobile_agent/bench/llm_units.py +116 -0
  110. mobile_agent/bench/manifest.json +93 -0
  111. mobile_agent/bench/metrics.py +66 -0
  112. mobile_agent/bench/phone.py +44 -0
  113. mobile_agent/bench/replay.py +172 -0
  114. mobile_agent/bench/report.py +207 -0
  115. mobile_agent/bench/runner.py +456 -0
  116. mobile_agent/bench/safety.py +310 -0
  117. mobile_agent/bench/stream_timing.py +213 -0
  118. mobile_agent/bench/suite.py +444 -0
  119. mobile_agent/bench/sweep.py +176 -0
  120. mobile_agent/bench/tape.py +798 -0
  121. mobile_agent/bench/tape_replay.py +88 -0
  122. mobile_agent/bench/trace_evals.py +128 -0
  123. mobile_agent/bench/trace_view.py +81 -0
  124. mobile_agent/bench/truth/iphone15pro.json +138 -0
  125. mobile_agent/bench/truth.py +340 -0
  126. mobile_agent/bench/tuning.py +543 -0
  127. mobile_agent/bench/tuning_analysis.py +656 -0
  128. mobile_agent/bench/vague-heldout-manifest.json +12 -0
  129. mobile_agent/bench/vague_rubric.py +135 -0
  130. mobile_agent/bench/vague_run.py +243 -0
  131. mobile_agent/brand.py +454 -0
  132. mobile_agent/brand_fonts.py +756 -0
  133. mobile_agent/build_identity.py +21 -0
  134. mobile_agent/cable_bt.py +623 -0
  135. mobile_agent/cable_bt_runtime.py +128 -0
  136. mobile_agent/catalog.py +69 -0
  137. mobile_agent/chart_svg.py +415 -0
  138. mobile_agent/chat_here.py +189 -0
  139. mobile_agent/cli_constants.py +5 -0
  140. mobile_agent/cli_parser.py +611 -0
  141. mobile_agent/cli_run.py +115 -0
  142. mobile_agent/compiled_read/__init__.py +21 -0
  143. mobile_agent/compiled_read/delta.py +89 -0
  144. mobile_agent/compiled_read/extractors.py +202 -0
  145. mobile_agent/compiled_read/routes.py +56 -0
  146. mobile_agent/completion.py +267 -0
  147. mobile_agent/compose.py +48 -0
  148. mobile_agent/config.py +114 -0
  149. mobile_agent/connectors/__init__.py +1 -0
  150. mobile_agent/connectors/api_session.py +76 -0
  151. mobile_agent/connectors/callback_page.py +146 -0
  152. mobile_agent/connectors/client.py +582 -0
  153. mobile_agent/connectors/github_app.py +55 -0
  154. mobile_agent/connectors/graph_api.py +396 -0
  155. mobile_agent/connectors/imports.py +170 -0
  156. mobile_agent/connectors/issue.py +66 -0
  157. mobile_agent/connectors/keystore.py +85 -0
  158. mobile_agent/connectors/marks.py +222 -0
  159. mobile_agent/connectors/oauth.py +476 -0
  160. mobile_agent/connectors/picker.py +228 -0
  161. mobile_agent/connectors/presets.py +591 -0
  162. mobile_agent/connectors/register.py +48 -0
  163. mobile_agent/connectors/routes.py +153 -0
  164. mobile_agent/connectors/service.py +966 -0
  165. mobile_agent/connectors/shared.py +136 -0
  166. mobile_agent/connectors/skill.py +446 -0
  167. mobile_agent/connectors/slack_api.py +269 -0
  168. mobile_agent/connectors/steps.py +92 -0
  169. mobile_agent/connectors/store.py +144 -0
  170. mobile_agent/connectors/vault.py +72 -0
  171. mobile_agent/console.py +178 -0
  172. mobile_agent/content_queue/__init__.py +1 -0
  173. mobile_agent/content_queue/client.py +263 -0
  174. mobile_agent/content_queue/importing.py +153 -0
  175. mobile_agent/content_queue/media_check.py +224 -0
  176. mobile_agent/content_queue/prompt.py +64 -0
  177. mobile_agent/content_queue/register.py +91 -0
  178. mobile_agent/content_queue/routes.py +370 -0
  179. mobile_agent/content_queue/runner.py +475 -0
  180. mobile_agent/content_queue/store.py +521 -0
  181. mobile_agent/contract.py +996 -0
  182. mobile_agent/contract_asks.py +248 -0
  183. mobile_agent/contract_prompt.py +45 -0
  184. mobile_agent/contract_screen.py +981 -0
  185. mobile_agent/contract_view.py +84 -0
  186. mobile_agent/corpus/__init__.py +26 -0
  187. mobile_agent/corpus/cli.py +63 -0
  188. mobile_agent/corpus/consent.py +55 -0
  189. mobile_agent/corpus/listener.py +76 -0
  190. mobile_agent/corpus/register.py +9 -0
  191. mobile_agent/corpus/skeleton.py +72 -0
  192. mobile_agent/corpus/store.py +143 -0
  193. mobile_agent/costs.py +161 -0
  194. mobile_agent/decider_scope.py +40 -0
  195. mobile_agent/decision_provider.py +189 -0
  196. mobile_agent/deeplinks.py +352 -0
  197. mobile_agent/device_info.py +116 -0
  198. mobile_agent/device_manager.py +978 -0
  199. mobile_agent/device_status.py +195 -0
  200. mobile_agent/device_targets.py +217 -0
  201. mobile_agent/devices.py +676 -0
  202. mobile_agent/devkit/__init__.py +64 -0
  203. mobile_agent/devkit/account_cli.py +90 -0
  204. mobile_agent/devkit/asc.py +562 -0
  205. mobile_agent/devkit/asc_cli.py +214 -0
  206. mobile_agent/devkit/ci.py +737 -0
  207. mobile_agent/devkit/ci_cli.py +196 -0
  208. mobile_agent/devkit/ci_hosts.py +194 -0
  209. mobile_agent/devkit/es256.py +197 -0
  210. mobile_agent/devkit/expo.py +440 -0
  211. mobile_agent/devkit/expo_cli.py +405 -0
  212. mobile_agent/devkit/expo_dev.py +203 -0
  213. mobile_agent/devkit/expo_routes.py +90 -0
  214. mobile_agent/devkit/fixtures_cli.py +133 -0
  215. mobile_agent/devkit/fixtures_routes.py +82 -0
  216. mobile_agent/devkit/links.py +375 -0
  217. mobile_agent/devkit/links_cli.py +123 -0
  218. mobile_agent/devkit/links_routes.py +83 -0
  219. mobile_agent/devkit/nightly.py +152 -0
  220. mobile_agent/devkit/shots.py +203 -0
  221. mobile_agent/devkit/testflight.py +155 -0
  222. mobile_agent/devkit/testflight_cli.py +127 -0
  223. mobile_agent/devkit/testflight_routes.py +111 -0
  224. mobile_agent/devkit/xcode.py +236 -0
  225. mobile_agent/devkit/xcode_cli.py +101 -0
  226. mobile_agent/devtools.py +419 -0
  227. mobile_agent/doctor.py +509 -0
  228. mobile_agent/doctor_fix.py +467 -0
  229. mobile_agent/downloads.py +55 -0
  230. mobile_agent/drivers.py +793 -0
  231. mobile_agent/dry_run.py +102 -0
  232. mobile_agent/effect_ledger.py +83 -0
  233. mobile_agent/engine_health.py +378 -0
  234. mobile_agent/engine_hooks.py +96 -0
  235. mobile_agent/engines.py +408 -0
  236. mobile_agent/env_file.py +63 -0
  237. mobile_agent/env_secrets.py +149 -0
  238. mobile_agent/errors.py +15 -0
  239. mobile_agent/evals/__init__.py +3 -0
  240. mobile_agent/evals/app_survey.py +149 -0
  241. mobile_agent/evals/development/__init__.py +1 -0
  242. mobile_agent/evals/development/score.py +276 -0
  243. mobile_agent/evals/latency_report.py +312 -0
  244. mobile_agent/evals/offline_report.py +374 -0
  245. mobile_agent/evals/oracles.py +298 -0
  246. mobile_agent/evals/redteam/__init__.py +15 -0
  247. mobile_agent/evals/redteam/__main__.py +72 -0
  248. mobile_agent/evals/redteam/cases.py +730 -0
  249. mobile_agent/evals/redteam/harness.py +604 -0
  250. mobile_agent/evals/redteam/live.py +139 -0
  251. mobile_agent/evals/redteam/plain.py +85 -0
  252. mobile_agent/evals/vision/__init__.py +0 -0
  253. mobile_agent/evals/vision/images/dog_001.jpg +0 -0
  254. mobile_agent/evals/vision/images/dog_002.jpg +0 -0
  255. mobile_agent/evals/vision/images/dog_003.jpg +0 -0
  256. mobile_agent/evals/vision/images/dog_004.jpg +0 -0
  257. mobile_agent/evals/vision/images/dog_005.jpg +0 -0
  258. mobile_agent/evals/vision/images/dog_006.jpg +0 -0
  259. mobile_agent/evals/vision/images/dog_007.jpg +0 -0
  260. mobile_agent/evals/vision/images/dog_010.jpg +0 -0
  261. mobile_agent/evals/vision/images/dog_011.jpg +0 -0
  262. mobile_agent/evals/vision/images/dog_013.jpg +0 -0
  263. mobile_agent/evals/vision/images/dog_014.jpg +0 -0
  264. mobile_agent/evals/vision/images/dog_015.jpg +0 -0
  265. mobile_agent/evals/vision/images/dog_016.jpg +0 -0
  266. mobile_agent/evals/vision/images/dog_017.jpg +0 -0
  267. mobile_agent/evals/vision/images/dog_019.jpg +0 -0
  268. mobile_agent/evals/vision/images/dog_020.jpg +0 -0
  269. mobile_agent/evals/vision/images/dog_021.jpg +0 -0
  270. mobile_agent/evals/vision/images/dog_022.jpg +0 -0
  271. mobile_agent/evals/vision/images/dog_023.jpg +0 -0
  272. mobile_agent/evals/vision/images/dog_024.jpg +0 -0
  273. mobile_agent/evals/vision/images/dog_026.jpg +0 -0
  274. mobile_agent/evals/vision/images/dog_027.jpg +0 -0
  275. mobile_agent/evals/vision/images/dog_034.jpg +0 -0
  276. mobile_agent/evals/vision/images/dog_035.jpg +0 -0
  277. mobile_agent/evals/vision/images/dog_038.jpg +0 -0
  278. mobile_agent/evals/vision/images/dog_042.jpg +0 -0
  279. mobile_agent/evals/vision/images/dog_047.jpg +0 -0
  280. mobile_agent/evals/vision/images/dog_052.jpg +0 -0
  281. mobile_agent/evals/vision/images/dog_058.jpg +0 -0
  282. mobile_agent/evals/vision/images/dog_062.jpg +0 -0
  283. mobile_agent/evals/vision/images/eyes_000.jpg +0 -0
  284. mobile_agent/evals/vision/images/eyes_010.jpg +0 -0
  285. mobile_agent/evals/vision/images/eyes_011.jpg +0 -0
  286. mobile_agent/evals/vision/images/eyes_015.jpg +0 -0
  287. mobile_agent/evals/vision/images/eyes_016.jpg +0 -0
  288. mobile_agent/evals/vision/images/eyes_017.jpg +0 -0
  289. mobile_agent/evals/vision/images/eyes_019.jpg +0 -0
  290. mobile_agent/evals/vision/images/eyes_021.jpg +0 -0
  291. mobile_agent/evals/vision/images/eyes_025.jpg +0 -0
  292. mobile_agent/evals/vision/images/eyes_026.jpg +0 -0
  293. mobile_agent/evals/vision/images/eyes_027.jpg +0 -0
  294. mobile_agent/evals/vision/images/eyes_030.jpg +0 -0
  295. mobile_agent/evals/vision/images/eyes_032.jpg +0 -0
  296. mobile_agent/evals/vision/images/eyes_033.jpg +0 -0
  297. mobile_agent/evals/vision/images/eyes_034.jpg +0 -0
  298. mobile_agent/evals/vision/images/eyes_035.jpg +0 -0
  299. mobile_agent/evals/vision/images/eyes_036.jpg +0 -0
  300. mobile_agent/evals/vision/images/eyes_037.jpg +0 -0
  301. mobile_agent/evals/vision/images/eyes_039.jpg +0 -0
  302. mobile_agent/evals/vision/images/eyes_040.jpg +0 -0
  303. mobile_agent/evals/vision/images/eyes_041.jpg +0 -0
  304. mobile_agent/evals/vision/images/eyes_042.jpg +0 -0
  305. mobile_agent/evals/vision/images/eyes_043.jpg +0 -0
  306. mobile_agent/evals/vision/images/eyes_044.jpg +0 -0
  307. mobile_agent/evals/vision/images/eyes_046.jpg +0 -0
  308. mobile_agent/evals/vision/images/eyes_047.jpg +0 -0
  309. mobile_agent/evals/vision/images/eyes_048.jpg +0 -0
  310. mobile_agent/evals/vision/images/eyes_049.jpg +0 -0
  311. mobile_agent/evals/vision/images/eyes_051.jpg +0 -0
  312. mobile_agent/evals/vision/images/eyes_053.jpg +0 -0
  313. mobile_agent/evals/vision/images/eyes_054.jpg +0 -0
  314. mobile_agent/evals/vision/images/eyes_055.jpg +0 -0
  315. mobile_agent/evals/vision/images/eyes_058.jpg +0 -0
  316. mobile_agent/evals/vision/images/eyes_059.jpg +0 -0
  317. mobile_agent/evals/vision/images/receipt_002.jpg +0 -0
  318. mobile_agent/evals/vision/images/receipt_003.jpg +0 -0
  319. mobile_agent/evals/vision/images/receipt_004.jpg +0 -0
  320. mobile_agent/evals/vision/images/receipt_007.jpg +0 -0
  321. mobile_agent/evals/vision/images/receipt_009.jpg +0 -0
  322. mobile_agent/evals/vision/images/receipt_010.jpg +0 -0
  323. mobile_agent/evals/vision/images/receipt_011.jpg +0 -0
  324. mobile_agent/evals/vision/images/receipt_012.jpg +0 -0
  325. mobile_agent/evals/vision/images/receipt_013.jpg +0 -0
  326. mobile_agent/evals/vision/images/receipt_014.jpg +0 -0
  327. mobile_agent/evals/vision/images/receipt_016.jpg +0 -0
  328. mobile_agent/evals/vision/images/receipt_017.jpg +0 -0
  329. mobile_agent/evals/vision/images/receipt_023.jpg +0 -0
  330. mobile_agent/evals/vision/images/receipt_027.jpg +0 -0
  331. mobile_agent/evals/vision/images/receipt_029.jpg +0 -0
  332. mobile_agent/evals/vision/images/receipt_032.jpg +0 -0
  333. mobile_agent/evals/vision/images/receipt_033.jpg +0 -0
  334. mobile_agent/evals/vision/images/receipt_036.jpg +0 -0
  335. mobile_agent/evals/vision/images/receipt_041.jpg +0 -0
  336. mobile_agent/evals/vision/images/receipt_043.jpg +0 -0
  337. mobile_agent/evals/vision/images/receipt_047.jpg +0 -0
  338. mobile_agent/evals/vision/images/receipt_049.jpg +0 -0
  339. mobile_agent/evals/vision/images/receipt_051.jpg +0 -0
  340. mobile_agent/evals/vision/images/receipt_053.jpg +0 -0
  341. mobile_agent/evals/vision/images/receipt_056.jpg +0 -0
  342. mobile_agent/evals/vision/images/receipt_057.jpg +0 -0
  343. mobile_agent/evals/vision/images/receipt_058.jpg +0 -0
  344. mobile_agent/evals/vision/images/receipt_059.jpg +0 -0
  345. mobile_agent/evals/vision/images/receipt_060.jpg +0 -0
  346. mobile_agent/evals/vision/images/receipt_061.jpg +0 -0
  347. mobile_agent/evals/vision/images/receipt_062.jpg +0 -0
  348. mobile_agent/evals/vision/images/receipt_063.jpg +0 -0
  349. mobile_agent/evals/vision/images/receipt_064.jpg +0 -0
  350. mobile_agent/evals/vision/images/receipt_065.jpg +0 -0
  351. mobile_agent/evals/vision/images/receipt_066.jpg +0 -0
  352. mobile_agent/evals/vision/images/receipt_067.jpg +0 -0
  353. mobile_agent/evals/vision/images/receipt_068.jpg +0 -0
  354. mobile_agent/evals/vision/images/receipt_069.jpg +0 -0
  355. mobile_agent/evals/vision/images/receipt_070.jpg +0 -0
  356. mobile_agent/evals/vision/images/receipt_071.jpg +0 -0
  357. mobile_agent/evals/vision/images/sunglasses_000.jpg +0 -0
  358. mobile_agent/evals/vision/images/sunglasses_001.jpg +0 -0
  359. mobile_agent/evals/vision/images/sunglasses_002.jpg +0 -0
  360. mobile_agent/evals/vision/images/sunglasses_004.jpg +0 -0
  361. mobile_agent/evals/vision/images/sunglasses_005.jpg +0 -0
  362. mobile_agent/evals/vision/images/sunglasses_008.jpg +0 -0
  363. mobile_agent/evals/vision/images/sunglasses_009.jpg +0 -0
  364. mobile_agent/evals/vision/images/sunglasses_010.jpg +0 -0
  365. mobile_agent/evals/vision/images/sunglasses_012.jpg +0 -0
  366. mobile_agent/evals/vision/images/sunglasses_013.jpg +0 -0
  367. mobile_agent/evals/vision/images/sunglasses_015.jpg +0 -0
  368. mobile_agent/evals/vision/images/sunglasses_016.jpg +0 -0
  369. mobile_agent/evals/vision/images/sunglasses_017.jpg +0 -0
  370. mobile_agent/evals/vision/images/sunglasses_018.jpg +0 -0
  371. mobile_agent/evals/vision/images/sunglasses_021.jpg +0 -0
  372. mobile_agent/evals/vision/images/sunglasses_022.jpg +0 -0
  373. mobile_agent/evals/vision/images/sunglasses_023.jpg +0 -0
  374. mobile_agent/evals/vision/images/sunglasses_024.jpg +0 -0
  375. mobile_agent/evals/vision/images/sunglasses_030.jpg +0 -0
  376. mobile_agent/evals/vision/images/sunglasses_031.jpg +0 -0
  377. mobile_agent/evals/vision/images/sunglasses_032.jpg +0 -0
  378. mobile_agent/evals/vision/images/sunglasses_033.jpg +0 -0
  379. mobile_agent/evals/vision/images/sunglasses_034.jpg +0 -0
  380. mobile_agent/evals/vision/images/sunglasses_036.jpg +0 -0
  381. mobile_agent/evals/vision/images/sunglasses_038.jpg +0 -0
  382. mobile_agent/evals/vision/images/sunglasses_039.jpg +0 -0
  383. mobile_agent/evals/vision/images/sunglasses_040.jpg +0 -0
  384. mobile_agent/evals/vision/images/sunglasses_041.jpg +0 -0
  385. mobile_agent/evals/vision/manifest.json +2355 -0
  386. mobile_agent/eventbus.py +110 -0
  387. mobile_agent/explain.py +34 -0
  388. mobile_agent/failure_line.py +197 -0
  389. mobile_agent/fanout.py +663 -0
  390. mobile_agent/feedback/__init__.py +2 -0
  391. mobile_agent/feedback/bundle.py +204 -0
  392. mobile_agent/feedback/outbox.py +196 -0
  393. mobile_agent/feedback/register.py +9 -0
  394. mobile_agent/feedback/routes.py +177 -0
  395. mobile_agent/fleet.py +841 -0
  396. mobile_agent/fleet_health.py +729 -0
  397. mobile_agent/fleet_phone.py +186 -0
  398. mobile_agent/frontier/__init__.py +79 -0
  399. mobile_agent/frontier/act.py +380 -0
  400. mobile_agent/frontier/actions.py +70 -0
  401. mobile_agent/frontier/agent.py +256 -0
  402. mobile_agent/frontier/approvals.py +366 -0
  403. mobile_agent/frontier/hooks.py +199 -0
  404. mobile_agent/frontier/interrupts.py +125 -0
  405. mobile_agent/frontier/observe.py +331 -0
  406. mobile_agent/frontier/phases.py +381 -0
  407. mobile_agent/frontier/pipeline.py +61 -0
  408. mobile_agent/frontier/prompt.py +384 -0
  409. mobile_agent/frontier/protocol.py +91 -0
  410. mobile_agent/frontier/safety.py +467 -0
  411. mobile_agent/frontier/saved.py +375 -0
  412. mobile_agent/frontier/screen.py +419 -0
  413. mobile_agent/frontier/skills.py +147 -0
  414. mobile_agent/frontier/stages/__init__.py +1 -0
  415. mobile_agent/frontier/stages/after.py +192 -0
  416. mobile_agent/frontier/stages/approve.py +138 -0
  417. mobile_agent/frontier/stages/controls.py +115 -0
  418. mobile_agent/frontier/stages/ends.py +102 -0
  419. mobile_agent/frontier/stages/gate.py +92 -0
  420. mobile_agent/frontier/stages/guards.py +132 -0
  421. mobile_agent/frontier/stages/points.py +155 -0
  422. mobile_agent/frontier/stages/send.py +177 -0
  423. mobile_agent/frontier/turn.py +151 -0
  424. mobile_agent/full_disk_access.py +83 -0
  425. mobile_agent/gemini.py +69 -0
  426. mobile_agent/genuine.py +120 -0
  427. mobile_agent/graph/__init__.py +4 -0
  428. mobile_agent/graph/catalog.py +789 -0
  429. mobile_agent/graph/chain.py +306 -0
  430. mobile_agent/graph/dispatch.py +98 -0
  431. mobile_agent/graph/draft.py +373 -0
  432. mobile_agent/graph/edit.py +76 -0
  433. mobile_agent/graph/estimate.py +189 -0
  434. mobile_agent/graph/expr.py +562 -0
  435. mobile_agent/graph/functions.py +271 -0
  436. mobile_agent/graph/infer.py +144 -0
  437. mobile_agent/graph/nodes.py +936 -0
  438. mobile_agent/graph/phone_steps.py +178 -0
  439. mobile_agent/graph/rerun.py +327 -0
  440. mobile_agent/graph/run.py +899 -0
  441. mobile_agent/graph/schema.py +842 -0
  442. mobile_agent/graph/state.py +161 -0
  443. mobile_agent/graph/values.py +198 -0
  444. mobile_agent/harness/__init__.py +2 -0
  445. mobile_agent/harness/checkpoints.py +468 -0
  446. mobile_agent/harness/control.py +101 -0
  447. mobile_agent/harness/prewarm.py +213 -0
  448. mobile_agent/harness/register.py +43 -0
  449. mobile_agent/harness/routes.py +114 -0
  450. mobile_agent/harness/settings.py +66 -0
  451. mobile_agent/harness/tools/__init__.py +67 -0
  452. mobile_agent/harness/tools/ask_user.py +102 -0
  453. mobile_agent/harness/tools/watch.py +120 -0
  454. mobile_agent/harness_api.py +815 -0
  455. mobile_agent/hedge.py +203 -0
  456. mobile_agent/help_topics.py +305 -0
  457. mobile_agent/hints.py +248 -0
  458. mobile_agent/history.py +69 -0
  459. mobile_agent/home.py +214 -0
  460. mobile_agent/http_pool.py +175 -0
  461. mobile_agent/image_policy.py +139 -0
  462. mobile_agent/inbox.py +148 -0
  463. mobile_agent/installed_apps.py +344 -0
  464. mobile_agent/integrations/__init__.py +1 -0
  465. mobile_agent/integrations/cli.py +472 -0
  466. mobile_agent/integrations/client_files.py +65 -0
  467. mobile_agent/integrations/clients.py +998 -0
  468. mobile_agent/integrations/doctor.py +185 -0
  469. mobile_agent/integrations/jsonc.py +383 -0
  470. mobile_agent/integrations/routes.py +135 -0
  471. mobile_agent/integrations/rules.py +112 -0
  472. mobile_agent/integrations/server_options.py +46 -0
  473. mobile_agent/integrations/skill.py +152 -0
  474. mobile_agent/integrations/skill_files.py +10 -0
  475. mobile_agent/integrations/textedit.py +309 -0
  476. mobile_agent/intents/__init__.py +17 -0
  477. mobile_agent/intents/atlas.py +216 -0
  478. mobile_agent/intents/callback.py +44 -0
  479. mobile_agent/intents/cli.py +55 -0
  480. mobile_agent/intents/harvest.py +91 -0
  481. mobile_agent/intents/plan.py +93 -0
  482. mobile_agent/ios/__init__.py +1 -0
  483. mobile_agent/ios/guide.py +16 -0
  484. mobile_agent/ios/kb.py +212 -0
  485. mobile_agent/ios/kb_data.py +1588 -0
  486. mobile_agent/ios/mcp.py +44 -0
  487. mobile_agent/ios/register.py +8 -0
  488. mobile_agent/ios/system.py +369 -0
  489. mobile_agent/journal.py +531 -0
  490. mobile_agent/keychain_acl.py +374 -0
  491. mobile_agent/keys.py +395 -0
  492. mobile_agent/latency_overlap.py +36 -0
  493. mobile_agent/latency_trace.py +170 -0
  494. mobile_agent/learned/__init__.py +15 -0
  495. mobile_agent/learned/app_path.py +160 -0
  496. mobile_agent/learned/code_read.py +38 -0
  497. mobile_agent/learned/parts.py +546 -0
  498. mobile_agent/learned/programs.py +691 -0
  499. mobile_agent/learned/register.py +171 -0
  500. mobile_agent/learned/routes.py +61 -0
  501. mobile_agent/learned/taught.py +329 -0
  502. mobile_agent/learned/teach.py +538 -0
  503. mobile_agent/learned/workflows.py +647 -0
  504. mobile_agent/learned/zero.py +41 -0
  505. mobile_agent/links.py +37 -0
  506. mobile_agent/listen.py +607 -0
  507. mobile_agent/lock_spike.py +278 -0
  508. mobile_agent/lockscreen.py +526 -0
  509. mobile_agent/login.py +354 -0
  510. mobile_agent/longform/__init__.py +15 -0
  511. mobile_agent/longform/ads.py +191 -0
  512. mobile_agent/longform/blocks.py +117 -0
  513. mobile_agent/longform/budget.py +265 -0
  514. mobile_agent/longform/context.py +285 -0
  515. mobile_agent/longform/costs.py +93 -0
  516. mobile_agent/longform/digest.py +145 -0
  517. mobile_agent/longform/extract.py +508 -0
  518. mobile_agent/longform/feed.py +505 -0
  519. mobile_agent/longform/followup.py +168 -0
  520. mobile_agent/longform/frames.py +82 -0
  521. mobile_agent/longform/identity.py +87 -0
  522. mobile_agent/longform/inbox.py +221 -0
  523. mobile_agent/longform/items.py +425 -0
  524. mobile_agent/longform/models.py +115 -0
  525. mobile_agent/longform/notebook.py +329 -0
  526. mobile_agent/longform/plan.py +614 -0
  527. mobile_agent/longform/recall.py +195 -0
  528. mobile_agent/longform/receipts.py +81 -0
  529. mobile_agent/longform/register.py +124 -0
  530. mobile_agent/longform/report.py +343 -0
  531. mobile_agent/longform/routes.py +102 -0
  532. mobile_agent/longform/session.py +644 -0
  533. mobile_agent/longform/store.py +146 -0
  534. mobile_agent/longform/synthesis.py +347 -0
  535. mobile_agent/mac_tools.py +223 -0
  536. mobile_agent/manual_control.py +143 -0
  537. mobile_agent/maps.py +149 -0
  538. mobile_agent/marks.py +92 -0
  539. mobile_agent/mcp_server/__init__.py +3 -0
  540. mobile_agent/mcp_server/__main__.py +29 -0
  541. mobile_agent/mcp_server/action_journal.py +24 -0
  542. mobile_agent/mcp_server/action_tools.py +638 -0
  543. mobile_agent/mcp_server/approvals.py +219 -0
  544. mobile_agent/mcp_server/catalog.py +92 -0
  545. mobile_agent/mcp_server/cli.py +194 -0
  546. mobile_agent/mcp_server/codes.py +147 -0
  547. mobile_agent/mcp_server/device_tools.py +306 -0
  548. mobile_agent/mcp_server/direct.py +272 -0
  549. mobile_agent/mcp_server/expo_tools.py +105 -0
  550. mobile_agent/mcp_server/phone_tools.py +510 -0
  551. mobile_agent/mcp_server/protocol.py +364 -0
  552. mobile_agent/mcp_server/registry.py +55 -0
  553. mobile_agent/mcp_server/run_tools.py +531 -0
  554. mobile_agent/mcp_server/schemas.py +425 -0
  555. mobile_agent/mcp_server/screen_tools.py +168 -0
  556. mobile_agent/mcp_server/session.py +469 -0
  557. mobile_agent/mcp_server/support.py +145 -0
  558. mobile_agent/mcp_server/tools.py +493 -0
  559. mobile_agent/memory/__init__.py +9 -0
  560. mobile_agent/memory/cli.py +207 -0
  561. mobile_agent/memory/extract.py +191 -0
  562. mobile_agent/memory/listener.py +100 -0
  563. mobile_agent/memory/model.py +144 -0
  564. mobile_agent/memory/project.py +96 -0
  565. mobile_agent/memory/provider.py +127 -0
  566. mobile_agent/memory/register.py +21 -0
  567. mobile_agent/memory/retrieval.py +172 -0
  568. mobile_agent/memory/routes.py +216 -0
  569. mobile_agent/memory/runs.py +124 -0
  570. mobile_agent/memory/store.py +806 -0
  571. mobile_agent/memory/writer.py +278 -0
  572. mobile_agent/mirroring.py +585 -0
  573. mobile_agent/mirroring_runtime.py +221 -0
  574. mobile_agent/model_clients.py +604 -0
  575. mobile_agent/narrate.py +813 -0
  576. mobile_agent/native_helpers.py +84 -0
  577. mobile_agent/netxray/__init__.py +1 -0
  578. mobile_agent/netxray/analyze.py +322 -0
  579. mobile_agent/netxray/attribution.py +62 -0
  580. mobile_agent/netxray/capture.py +88 -0
  581. mobile_agent/netxray/cli.py +142 -0
  582. mobile_agent/netxray/job.py +219 -0
  583. mobile_agent/netxray/mobster-pcap.c +560 -0
  584. mobile_agent/netxray/packets.py +410 -0
  585. mobile_agent/netxray/pcapng.py +223 -0
  586. mobile_agent/netxray/register.py +93 -0
  587. mobile_agent/netxray/report.py +214 -0
  588. mobile_agent/netxray/store.py +48 -0
  589. mobile_agent/netxray/summary.py +157 -0
  590. mobile_agent/netxray/target.py +67 -0
  591. mobile_agent/netxray/tool.py +66 -0
  592. mobile_agent/netxray/trackers.py +194 -0
  593. mobile_agent/notify_triggers/__init__.py +1 -0
  594. mobile_agent/notify_triggers/rules.py +39 -0
  595. mobile_agent/notify_triggers/sources.py +315 -0
  596. mobile_agent/notify_triggers/watch.py +135 -0
  597. mobile_agent/offers.py +86 -0
  598. mobile_agent/orchestrate.py +215 -0
  599. mobile_agent/outlets/__init__.py +1 -0
  600. mobile_agent/outlets/connect.py +249 -0
  601. mobile_agent/outlets/folder.py +180 -0
  602. mobile_agent/outlets/hooks.py +453 -0
  603. mobile_agent/outlets/inbound.py +472 -0
  604. mobile_agent/outlets/inbound_reply.py +57 -0
  605. mobile_agent/outlets/inbound_routes.py +81 -0
  606. mobile_agent/outlets/kinds.py +308 -0
  607. mobile_agent/outlets/mail.py +110 -0
  608. mobile_agent/outlets/net.py +86 -0
  609. mobile_agent/outlets/notion.py +244 -0
  610. mobile_agent/outlets/register.py +56 -0
  611. mobile_agent/outlets/routes.py +135 -0
  612. mobile_agent/outlets/service.py +580 -0
  613. mobile_agent/outlets/sheets.py +169 -0
  614. mobile_agent/outlets/slack.py +177 -0
  615. mobile_agent/outlets/store.py +194 -0
  616. mobile_agent/outlets/vault.py +80 -0
  617. mobile_agent/outlets/webhook.py +316 -0
  618. mobile_agent/output_contract.py +141 -0
  619. mobile_agent/owner_presence.py +211 -0
  620. mobile_agent/ownership.py +219 -0
  621. mobile_agent/packs/__init__.py +1 -0
  622. mobile_agent/packs/calendar.py +243 -0
  623. mobile_agent/packs/context.py +68 -0
  624. mobile_agent/packs/core.py +757 -0
  625. mobile_agent/packs/front_door.py +316 -0
  626. mobile_agent/packs/heal.py +214 -0
  627. mobile_agent/packs/health.py +122 -0
  628. mobile_agent/packs/insights.py +76 -0
  629. mobile_agent/packs/instagram.py +640 -0
  630. mobile_agent/packs/linkedin.py +106 -0
  631. mobile_agent/packs/maps.py +196 -0
  632. mobile_agent/packs/mcp.py +149 -0
  633. mobile_agent/packs/messages.py +270 -0
  634. mobile_agent/packs/notes.py +226 -0
  635. mobile_agent/packs/photos.py +166 -0
  636. mobile_agent/packs/pins.py +47 -0
  637. mobile_agent/packs/reddit.py +110 -0
  638. mobile_agent/packs/register.py +276 -0
  639. mobile_agent/packs/rows.py +108 -0
  640. mobile_agent/packs/safari.py +143 -0
  641. mobile_agent/packs/settings.py +253 -0
  642. mobile_agent/packs/social.py +300 -0
  643. mobile_agent/packs/threads.py +97 -0
  644. mobile_agent/packs/tiktok.py +455 -0
  645. mobile_agent/packs/tools.py +290 -0
  646. mobile_agent/packs/x.py +127 -0
  647. mobile_agent/packs/youtube.py +199 -0
  648. mobile_agent/parity.py +270 -0
  649. mobile_agent/paths.py +99 -0
  650. mobile_agent/perception.py +470 -0
  651. mobile_agent/permissions/__init__.py +32 -0
  652. mobile_agent/permissions/consequence.py +535 -0
  653. mobile_agent/permissions/exceptions.py +99 -0
  654. mobile_agent/permissions/gate.py +316 -0
  655. mobile_agent/permissions/outside.py +316 -0
  656. mobile_agent/permissions/policy.py +288 -0
  657. mobile_agent/permissions/project_policy.py +411 -0
  658. mobile_agent/permissions/register.py +148 -0
  659. mobile_agent/permissions/rules.py +291 -0
  660. mobile_agent/phone_io/__init__.py +146 -0
  661. mobile_agent/phone_io/cli.py +427 -0
  662. mobile_agent/phone_io/clipboard.py +78 -0
  663. mobile_agent/phone_io/controls.py +78 -0
  664. mobile_agent/phone_io/files.py +289 -0
  665. mobile_agent/phone_io/handoff.py +123 -0
  666. mobile_agent/phone_io/icloud.py +118 -0
  667. mobile_agent/phone_io/install.py +188 -0
  668. mobile_agent/phone_io/network_capture.py +188 -0
  669. mobile_agent/phone_io/network_cli.py +138 -0
  670. mobile_agent/phone_io/network_profiles.py +138 -0
  671. mobile_agent/phone_io/photos.py +512 -0
  672. mobile_agent/phone_io/recording.py +115 -0
  673. mobile_agent/phone_io/secrets.py +146 -0
  674. mobile_agent/phone_io/transfer.py +895 -0
  675. mobile_agent/phone_io/tunnel.py +129 -0
  676. mobile_agent/phone_ready.py +91 -0
  677. mobile_agent/pinning.py +158 -0
  678. mobile_agent/plan_gate.py +807 -0
  679. mobile_agent/plugins/__init__.py +3 -0
  680. mobile_agent/plugins/install.py +163 -0
  681. mobile_agent/plugins/manifest.py +242 -0
  682. mobile_agent/plugins/register.py +15 -0
  683. mobile_agent/plugins/routes.py +82 -0
  684. mobile_agent/plugins/service.py +322 -0
  685. mobile_agent/plugins/skills.py +76 -0
  686. mobile_agent/plugins/store.py +79 -0
  687. mobile_agent/pool.py +285 -0
  688. mobile_agent/power_watch.py +275 -0
  689. mobile_agent/premium_model.py +22 -0
  690. mobile_agent/project_env.py +291 -0
  691. mobile_agent/project_env_cli.py +74 -0
  692. mobile_agent/project_env_routes.py +55 -0
  693. mobile_agent/projects/__init__.py +27 -0
  694. mobile_agent/projects/ci.py +332 -0
  695. mobile_agent/projects/clone.py +339 -0
  696. mobile_agent/projects/drafts.py +158 -0
  697. mobile_agent/projects/folder.py +436 -0
  698. mobile_agent/projects/github.py +131 -0
  699. mobile_agent/projects/register.py +31 -0
  700. mobile_agent/projects/revisions.py +253 -0
  701. mobile_agent/projects/routes.py +234 -0
  702. mobile_agent/projects/runs.py +297 -0
  703. mobile_agent/projects/service.py +695 -0
  704. mobile_agent/projects/setup.py +84 -0
  705. mobile_agent/projects/store.py +379 -0
  706. mobile_agent/projects/sync.py +380 -0
  707. mobile_agent/projects/workflow_files.py +270 -0
  708. mobile_agent/replay_core/__init__.py +26 -0
  709. mobile_agent/replay_core/checks.py +594 -0
  710. mobile_agent/replay_core/engine.py +596 -0
  711. mobile_agent/replay_core/heal.py +364 -0
  712. mobile_agent/replay_core/path.py +240 -0
  713. mobile_agent/replay_core/recorder.py +206 -0
  714. mobile_agent/replay_core/store.py +171 -0
  715. mobile_agent/result_blocks.py +941 -0
  716. mobile_agent/run.py +642 -0
  717. mobile_agent/run_delivery.py +123 -0
  718. mobile_agent/run_executor.py +200 -0
  719. mobile_agent/run_export.py +284 -0
  720. mobile_agent/run_gif.py +891 -0
  721. mobile_agent/runner_hints.py +86 -0
  722. mobile_agent/runner_renewal.py +205 -0
  723. mobile_agent/runtime_create.py +549 -0
  724. mobile_agent/runtime_driver.py +458 -0
  725. mobile_agent/runtime_limits.py +319 -0
  726. mobile_agent/runtime_queue.py +394 -0
  727. mobile_agent/runtime_runs.py +383 -0
  728. mobile_agent/runtime_status.py +181 -0
  729. mobile_agent/runtime_teach.py +295 -0
  730. mobile_agent/runtime_work.py +599 -0
  731. mobile_agent/screen_text.py +101 -0
  732. mobile_agent/secret_filter.py +113 -0
  733. mobile_agent/serve.py +160 -0
  734. mobile_agent/server.py +363 -0
  735. mobile_agent/service_support.py +42 -0
  736. mobile_agent/settle/__init__.py +1 -0
  737. mobile_agent/settle/predict.py +102 -0
  738. mobile_agent/settle/replay.py +92 -0
  739. mobile_agent/settle/store.py +93 -0
  740. mobile_agent/settle/stream.py +43 -0
  741. mobile_agent/setup_cli.py +225 -0
  742. mobile_agent/setup_errors.py +87 -0
  743. mobile_agent/setup_service.py +527 -0
  744. mobile_agent/share.py +104 -0
  745. mobile_agent/signing.py +184 -0
  746. mobile_agent/sim/__init__.py +6 -0
  747. mobile_agent/sim/__main__.py +26 -0
  748. mobile_agent/sim/api.py +952 -0
  749. mobile_agent/sim/apps.py +172 -0
  750. mobile_agent/sim/biometrics.py +84 -0
  751. mobile_agent/sim/cli.py +271 -0
  752. mobile_agent/sim/doctor.py +293 -0
  753. mobile_agent/sim/governor.py +90 -0
  754. mobile_agent/sim/holders.py +88 -0
  755. mobile_agent/sim/models.py +62 -0
  756. mobile_agent/sim/registry.py +161 -0
  757. mobile_agent/sim/simctl.py +269 -0
  758. mobile_agent/sim/wda.py +618 -0
  759. mobile_agent/sim/xcode.py +74 -0
  760. mobile_agent/skills/__init__.py +12 -0
  761. mobile_agent/skills/codes.py +597 -0
  762. mobile_agent/skills/notifications.py +281 -0
  763. mobile_agent/skills/open_url.py +127 -0
  764. mobile_agent/smart_events.py +588 -0
  765. mobile_agent/smart_result.py +490 -0
  766. mobile_agent/smart_run.py +413 -0
  767. mobile_agent/state.py +662 -0
  768. mobile_agent/states.py +217 -0
  769. mobile_agent/steering.py +70 -0
  770. mobile_agent/style.py +178 -0
  771. mobile_agent/supervised.py +234 -0
  772. mobile_agent/swift/helper_bt_hid.swift +534 -0
  773. mobile_agent/swift/helper_doc_text.swift +184 -0
  774. mobile_agent/swift/helper_draft_reply.swift +170 -0
  775. mobile_agent/swift/helper_map.swift +110 -0
  776. mobile_agent/swift/helper_mirroring.swift +1099 -0
  777. mobile_agent/swift/helper_mjpeg_mp4.swift +103 -0
  778. mobile_agent/swift/helper_pdf.swift +100 -0
  779. mobile_agent/swift/helper_phone_audio.swift +993 -0
  780. mobile_agent/swift/helper_phone_screen.swift +416 -0
  781. mobile_agent/swift/helper_screen_text.swift +24 -0
  782. mobile_agent/swift/helper_transfer.swift +246 -0
  783. mobile_agent/swift/ocr.swift +22 -0
  784. mobile_agent/task_policy.py +337 -0
  785. mobile_agent/team_signing/__init__.py +34 -0
  786. mobile_agent/team_signing/apple_ca.py +37 -0
  787. mobile_agent/team_signing/bundle.py +136 -0
  788. mobile_agent/team_signing/cli.py +208 -0
  789. mobile_agent/team_signing/identity.py +248 -0
  790. mobile_agent/team_signing/ledger.py +105 -0
  791. mobile_agent/team_signing/prebuilt.py +61 -0
  792. mobile_agent/team_signing/resign.py +256 -0
  793. mobile_agent/team_signing/service.py +382 -0
  794. mobile_agent/team_signing/tooling.py +243 -0
  795. mobile_agent/team_signing/writes.py +268 -0
  796. mobile_agent/terminal_image.py +81 -0
  797. mobile_agent/testkit/__init__.py +1 -0
  798. mobile_agent/testkit/a11y_baseline.py +132 -0
  799. mobile_agent/testkit/api.py +403 -0
  800. mobile_agent/testkit/capsule.py +400 -0
  801. mobile_agent/testkit/capsule_cli.py +57 -0
  802. mobile_agent/testkit/cli.py +948 -0
  803. mobile_agent/testkit/cli_arguments.py +193 -0
  804. mobile_agent/testkit/comparison.py +288 -0
  805. mobile_agent/testkit/comparison_cli.py +41 -0
  806. mobile_agent/testkit/discover.py +257 -0
  807. mobile_agent/testkit/editor.py +243 -0
  808. mobile_agent/testkit/execute.py +515 -0
  809. mobile_agent/testkit/github_checks.py +248 -0
  810. mobile_agent/testkit/gitref.py +66 -0
  811. mobile_agent/testkit/heal_review.py +176 -0
  812. mobile_agent/testkit/health.py +480 -0
  813. mobile_agent/testkit/history.py +255 -0
  814. mobile_agent/testkit/hosted_results.py +321 -0
  815. mobile_agent/testkit/input_files.py +173 -0
  816. mobile_agent/testkit/jobs.py +285 -0
  817. mobile_agent/testkit/junit_verdict.py +33 -0
  818. mobile_agent/testkit/maestro.py +802 -0
  819. mobile_agent/testkit/mcp.py +562 -0
  820. mobile_agent/testkit/mcp_comparison.py +88 -0
  821. mobile_agent/testkit/minimize.py +471 -0
  822. mobile_agent/testkit/minimizer_cli.py +48 -0
  823. mobile_agent/testkit/notify.py +212 -0
  824. mobile_agent/testkit/phone_video.py +191 -0
  825. mobile_agent/testkit/pr.py +491 -0
  826. mobile_agent/testkit/pr_report.py +562 -0
  827. mobile_agent/testkit/prbuild.py +148 -0
  828. mobile_agent/testkit/proof_report.py +55 -0
  829. mobile_agent/testkit/provenance.py +119 -0
  830. mobile_agent/testkit/prrun.py +244 -0
  831. mobile_agent/testkit/recent.py +166 -0
  832. mobile_agent/testkit/recipes.py +146 -0
  833. mobile_agent/testkit/record.py +204 -0
  834. mobile_agent/testkit/register.py +288 -0
  835. mobile_agent/testkit/reports.py +998 -0
  836. mobile_agent/testkit/repro.py +432 -0
  837. mobile_agent/testkit/scenario.py +440 -0
  838. mobile_agent/testkit/scenario_cli.py +37 -0
  839. mobile_agent/testkit/snapshots_cli.py +60 -0
  840. mobile_agent/testkit/suite.py +670 -0
  841. mobile_agent/testkit/targets.py +497 -0
  842. mobile_agent/testkit/xctest.py +378 -0
  843. mobile_agent/threads/__init__.py +1 -0
  844. mobile_agent/threads/chat_once.py +264 -0
  845. mobile_agent/threads/cli.py +740 -0
  846. mobile_agent/threads/client.py +326 -0
  847. mobile_agent/threads/context.py +246 -0
  848. mobile_agent/threads/mcp.py +739 -0
  849. mobile_agent/threads/recent.py +34 -0
  850. mobile_agent/threads/register.py +54 -0
  851. mobile_agent/threads/routes.py +188 -0
  852. mobile_agent/threads/service.py +975 -0
  853. mobile_agent/threads/store.py +361 -0
  854. mobile_agent/threads/summary.py +117 -0
  855. mobile_agent/threads/term.py +101 -0
  856. mobile_agent/threads/workflow_cli.py +104 -0
  857. mobile_agent/tls.py +36 -0
  858. mobile_agent/traces.py +271 -0
  859. mobile_agent/tracks.py +235 -0
  860. mobile_agent/transport.py +271 -0
  861. mobile_agent/triggers/__init__.py +1 -0
  862. mobile_agent/triggers/actions.py +204 -0
  863. mobile_agent/triggers/model.py +146 -0
  864. mobile_agent/triggers/register.py +29 -0
  865. mobile_agent/triggers/routes.py +101 -0
  866. mobile_agent/triggers/service.py +387 -0
  867. mobile_agent/triggers/store.py +142 -0
  868. mobile_agent/tui/__init__.py +89 -0
  869. mobile_agent/tui/app.py +582 -0
  870. mobile_agent/tui/chrome.py +321 -0
  871. mobile_agent/tui/commands.py +375 -0
  872. mobile_agent/tui/demo_phone.py +369 -0
  873. mobile_agent/tui/images.py +29 -0
  874. mobile_agent/tui/keys.py +64 -0
  875. mobile_agent/tui/prompt.py +195 -0
  876. mobile_agent/tui/render.py +395 -0
  877. mobile_agent/tui/screens.py +180 -0
  878. mobile_agent/tui/session.py +308 -0
  879. mobile_agent/tui/tasks.py +287 -0
  880. mobile_agent/tui/theme.py +118 -0
  881. mobile_agent/tui/widgets.py +272 -0
  882. mobile_agent/update_check.py +213 -0
  883. mobile_agent/usage.py +184 -0
  884. mobile_agent/verify/__init__.py +0 -0
  885. mobile_agent/verify/__main__.py +41 -0
  886. mobile_agent/verify/a11y.py +189 -0
  887. mobile_agent/verify/actions.py +290 -0
  888. mobile_agent/verify/assertions.py +570 -0
  889. mobile_agent/verify/audit.py +312 -0
  890. mobile_agent/verify/business.py +221 -0
  891. mobile_agent/verify/business_run.py +131 -0
  892. mobile_agent/verify/business_state.py +168 -0
  893. mobile_agent/verify/check_schema.py +398 -0
  894. mobile_agent/verify/checks.py +614 -0
  895. mobile_agent/verify/cli.py +423 -0
  896. mobile_agent/verify/conditions.py +483 -0
  897. mobile_agent/verify/crashes.py +321 -0
  898. mobile_agent/verify/device_audit.py +246 -0
  899. mobile_agent/verify/dialogs.py +287 -0
  900. mobile_agent/verify/evidence.py +705 -0
  901. mobile_agent/verify/fixtures.py +305 -0
  902. mobile_agent/verify/flow.py +213 -0
  903. mobile_agent/verify/l10n.py +141 -0
  904. mobile_agent/verify/netcerts.py +67 -0
  905. mobile_agent/verify/netproxy.py +356 -0
  906. mobile_agent/verify/netrun.py +81 -0
  907. mobile_agent/verify/netshim.m +28 -0
  908. mobile_agent/verify/netshim.py +48 -0
  909. mobile_agent/verify/netstubs.py +132 -0
  910. mobile_agent/verify/overlay.py +174 -0
  911. mobile_agent/verify/perf.py +239 -0
  912. mobile_agent/verify/proof.py +192 -0
  913. mobile_agent/verify/replay_admission.py +48 -0
  914. mobile_agent/verify/report.py +952 -0
  915. mobile_agent/verify/run_cleanup.py +67 -0
  916. mobile_agent/verify/run_links.py +48 -0
  917. mobile_agent/verify/run_perf.py +44 -0
  918. mobile_agent/verify/run_secrets.py +39 -0
  919. mobile_agent/verify/runner.py +976 -0
  920. mobile_agent/verify/runs.py +57 -0
  921. mobile_agent/verify/screen_coverage.py +181 -0
  922. mobile_agent/verify/smart.py +106 -0
  923. mobile_agent/verify/snapshot_run.py +114 -0
  924. mobile_agent/verify/snapshots.py +306 -0
  925. mobile_agent/verify/sound.py +335 -0
  926. mobile_agent/verify/source_observation.py +130 -0
  927. mobile_agent/verify/system_surfaces/__init__.py +7 -0
  928. mobile_agent/verify/system_surfaces/play.py +106 -0
  929. mobile_agent/verify/system_surfaces/spec.py +139 -0
  930. mobile_agent/verify/system_surfaces/stage.py +138 -0
  931. mobile_agent/verify/system_surfaces/surfaces.py +121 -0
  932. mobile_agent/verify/tree.py +223 -0
  933. mobile_agent/verify/verdict.py +377 -0
  934. mobile_agent/verify/wire.py +392 -0
  935. mobile_agent/verify/wirestore.py +176 -0
  936. mobile_agent/waiting/__init__.py +1 -0
  937. mobile_agent/waiting/contacts.py +73 -0
  938. mobile_agent/waiting/drafts.py +136 -0
  939. mobile_agent/waiting/job.py +145 -0
  940. mobile_agent/waiting/messages.py +174 -0
  941. mobile_agent/waiting/rank.py +115 -0
  942. mobile_agent/waiting/register.py +26 -0
  943. mobile_agent/watch.py +502 -0
  944. mobile_agent/wda/__init__.py +2 -0
  945. mobile_agent/wda/frame_clock.py +646 -0
  946. mobile_agent/wda/frame_source.py +325 -0
  947. mobile_agent/wda/frame_store.py +115 -0
  948. mobile_agent/wda/gate.py +163 -0
  949. mobile_agent/wda/gestures.py +291 -0
  950. mobile_agent/wda/guards.py +94 -0
  951. mobile_agent/wda/identity.py +55 -0
  952. mobile_agent/wda/observe.py +884 -0
  953. mobile_agent/wda/patches.py +856 -0
  954. mobile_agent/wda/point_gestures.py +150 -0
  955. mobile_agent/wda/source.py +32 -0
  956. mobile_agent/wda/system_dialogs.py +571 -0
  957. mobile_agent/wda/text.py +694 -0
  958. mobile_agent/wda/timeouts.py +77 -0
  959. mobile_agent/wda/video.py +505 -0
  960. mobile_agent/wda/watchdog.py +243 -0
  961. mobile_agent/wireless/__init__.py +15 -0
  962. mobile_agent/wireless/api.py +354 -0
  963. mobile_agent/wireless/cli.py +287 -0
  964. mobile_agent/wireless/devicectl.py +229 -0
  965. mobile_agent/wireless/exposure.py +33 -0
  966. mobile_agent/wireless/mobster-wifi-pair.c +122 -0
  967. mobile_agent/wireless/monitor.py +332 -0
  968. mobile_agent/wireless/network.py +334 -0
  969. mobile_agent/wireless/onboarding.py +293 -0
  970. mobile_agent/wireless/pair.py +124 -0
  971. mobile_agent/wireless/probe.py +322 -0
  972. mobile_agent/wireless/register.py +8 -0
  973. mobile_agent/wireless/relay.py +179 -0
  974. mobile_agent/wireless/result.py +87 -0
  975. mobile_agent/wireless/store.py +85 -0
  976. mobile_agent/wireless/switch.py +77 -0
  977. mobile_agent/wireless/transport.py +118 -0
  978. mobile_agent/wireless/words.py +81 -0
  979. mobile_agent/wireless/xctestrun.py +83 -0
  980. mobile_agent/workflow_tools.py +59 -0
  981. mobile_agent/workflows/__init__.py +2 -0
  982. mobile_agent/workflows/brief.py +201 -0
  983. mobile_agent/workflows/cron.py +110 -0
  984. mobile_agent/workflows/health.py +257 -0
  985. mobile_agent/workflows/history.py +126 -0
  986. mobile_agent/workflows/records.py +442 -0
  987. mobile_agent/workflows/runs.py +1000 -0
  988. mobile_agent/workflows/scheduler.py +134 -0
  989. mobile_agent/workflows/service.py +973 -0
  990. mobile_agent/workflows/starters.py +285 -0
  991. mobile_agent/workflows/triggers.py +248 -0
  992. mobile_agent/xray/__init__.py +1 -0
  993. mobile_agent/xray/app_cli.py +116 -0
  994. mobile_agent/xray/cli.py +21 -0
  995. mobile_agent/xray/crawl.py +754 -0
  996. mobile_agent/xray/diff.py +171 -0
  997. mobile_agent/xray/diff_cli.py +43 -0
  998. mobile_agent/xray/job.py +184 -0
  999. mobile_agent/xray/paywall.py +188 -0
  1000. mobile_agent/xray/policy.py +305 -0
  1001. mobile_agent/xray/register.py +43 -0
  1002. mobile_agent/xray/report.py +283 -0
  1003. mobile_agent/xray/screens.py +117 -0
  1004. mobster_cli-0.4.3.dist-info/METADATA +93 -0
  1005. mobster_cli-0.4.3.dist-info/RECORD +1009 -0
  1006. mobster_cli-0.4.3.dist-info/WHEEL +5 -0
  1007. mobster_cli-0.4.3.dist-info/entry_points.txt +3 -0
  1008. mobster_cli-0.4.3.dist-info/licenses/LICENSE +21 -0
  1009. mobster_cli-0.4.3.dist-info/top_level.txt +1 -0
mobile_agent/hedge.py ADDED
@@ -0,0 +1,203 @@
1
+ """Hedged model requests: cut the tail of identical-input calls, which are pure reads, so a twin costs only tokens."""
2
+
3
+ import os
4
+ import re
5
+ import threading
6
+ import time
7
+ from collections import deque
8
+
9
+ from .transport import TransportError
10
+
11
+ MIN_SAMPLES = 20
12
+ WINDOW = 64
13
+ RESEND_MIN_SECONDS = .5
14
+ _STATUS = re.compile(r"HTTP (\d{3});")
15
+ _EXCEPTION = re.compile(r"HTTP ([A-Za-z_]+); ")
16
+ # Our own encoding or decoding: resending the same request fails the same way.
17
+ _OWN_FAULTS = frozenset({"ValueError", "RecursionError"})
18
+
19
+
20
+ def transient(error):
21
+ """Whether a model request failed in transit, so sending it again may succeed."""
22
+ if not isinstance(error, TransportError):
23
+ return False
24
+ message = str(error)
25
+ status = _STATUS.match(message)
26
+ if status:
27
+ return status.group(1) == "429" or status.group(1).startswith("5")
28
+ if message.startswith("Incomplete HTTP response"):
29
+ return True
30
+ name = _EXCEPTION.match(message)
31
+ return bool(name) and name.group(1) not in _OWN_FAULTS
32
+
33
+
34
+ def _env_ratio():
35
+ try:
36
+ value = float(os.environ.get("MOBSTER_HEDGE_RATIO", "0.1"))
37
+ except ValueError:
38
+ return .1
39
+ return min(max(value, 0.0), 1.0)
40
+
41
+
42
+ def enabled():
43
+ return os.environ.get("MOBSTER_HEDGE", "1").strip().lower() not in {"0", "off", "false", "no"}
44
+
45
+
46
+ class LatencyWindow:
47
+ """Recent successful latencies per purpose (seconds)."""
48
+
49
+ def __init__(self, size=WINDOW):
50
+ self.size = size
51
+ self._values = {}
52
+ self._lock = threading.Lock()
53
+
54
+ def add(self, purpose, seconds):
55
+ with self._lock:
56
+ values = self._values.get(purpose)
57
+ if values is None:
58
+ values = self._values[purpose] = deque(maxlen=self.size)
59
+ values.append(seconds)
60
+
61
+ def quantile(self, purpose, q):
62
+ with self._lock:
63
+ values = sorted(self._values.get(purpose, ()))
64
+ if len(values) < MIN_SAMPLES:
65
+ return None
66
+ index = min(len(values) - 1, max(0, int(round(q * (len(values) - 1)))))
67
+ return values[index]
68
+
69
+ def count(self, purpose):
70
+ with self._lock:
71
+ return len(self._values.get(purpose, ()))
72
+
73
+
74
+ class HedgeBudget:
75
+ """Token bucket: each primary call earns ``ratio`` tokens; a hedge spends one."""
76
+
77
+ def __init__(self, ratio=None, burst=2.0):
78
+ self.ratio = _env_ratio() if ratio is None else ratio
79
+ self.burst = burst
80
+ self.tokens = burst
81
+ self.primaries = 0
82
+ self.hedges = 0
83
+ self._lock = threading.Lock()
84
+
85
+ def earn(self):
86
+ with self._lock:
87
+ self.primaries += 1
88
+ self.tokens = min(self.burst, self.tokens + self.ratio)
89
+
90
+ def spend(self):
91
+ with self._lock:
92
+ if self.tokens < 1:
93
+ return False
94
+ self.tokens -= 1
95
+ self.hedges += 1
96
+ return True
97
+
98
+
99
+ # A primary past max(STALL_MIN_SECONDS, STALL_FACTOR x the hedge delay) is stalled, not slow: it gets a rescue twin even
100
+ # with the budget spent.
101
+ STALL_MIN_SECONDS, STALL_FACTOR = 10.0, 3.0
102
+
103
+
104
+ class Hedger:
105
+ def __init__(self, quantile=.9, window=None, budget=None, floor=None, default=None,
106
+ any_floor=.8, any_default=.8, stall_min=STALL_MIN_SECONDS):
107
+ self.q = quantile
108
+ self.window = window or LatencyWindow()
109
+ self.budget = budget or HedgeBudget()
110
+ self.floor, self.default = dict(floor or {}), dict(default or {})
111
+ self.any_floor, self.any_default = any_floor, any_default
112
+ self.resends = 0
113
+ self.rescues = 0
114
+ self.stall_min = stall_min
115
+
116
+ def delay(self, purpose):
117
+ """Seconds to wait for the primary before a twin may be sent."""
118
+ observed = self.window.quantile(purpose, self.q)
119
+ floor = self.floor.get(purpose, self.any_floor)
120
+ if observed is None:
121
+ return max(floor, self.default.get(purpose, self.any_default))
122
+ return max(floor, observed)
123
+
124
+ def run(self, purpose, attempt, *, timeout, on_attempt=None, clock=time.monotonic):
125
+ """Run ``attempt(index, timeout)`` and maybe a twin; return the first success."""
126
+ self.budget.earn()
127
+ started = clock()
128
+ done = threading.Condition()
129
+ results = {} # index -> (ok, value, end)
130
+
131
+ def worker(index, budget_left):
132
+ t0 = clock()
133
+ try:
134
+ value, ok = attempt(index, budget_left), True
135
+ except BaseException as error: # Re-raised on the caller's thread.
136
+ value, ok = error, False
137
+ end = clock()
138
+ if ok:
139
+ self.window.add(purpose, end - t0)
140
+ with done:
141
+ won = ok and not any(item[0] for item in results.values())
142
+ results[index] = (ok, value, end)
143
+ done.notify_all()
144
+ if on_attempt is not None:
145
+ try:
146
+ on_attempt(index, t0, end, ok, won)
147
+ except Exception:
148
+ pass
149
+
150
+ threading.Thread(target=worker, args=(0, timeout), name="mobster-hedge-0", daemon=True).start()
151
+ wait = self.delay(purpose)
152
+ hedged = False
153
+ with done:
154
+ done.wait_for(lambda: 0 in results, timeout=min(wait, timeout))
155
+ primary_done = 0 in results
156
+ if not primary_done:
157
+ remaining = timeout - (clock() - started)
158
+ if remaining > .05 and self.budget.spend():
159
+ hedged = True
160
+ threading.Thread(target=worker, args=(1, remaining), name="mobster-hedge-1",
161
+ daemon=True).start()
162
+ if not primary_done and not hedged:
163
+ # No hedge budget: wait until the call looks stalled, then send a rescue twin anyway.
164
+ stall = max(self.stall_min, STALL_FACTOR * wait)
165
+ with done:
166
+ done.wait_for(lambda: 0 in results, timeout=max(0.0, min(stall, timeout) - (clock() - started)))
167
+ primary_done = 0 in results
168
+ remaining = timeout - (clock() - started)
169
+ if not primary_done and remaining > RESEND_MIN_SECONDS:
170
+ hedged = True
171
+ self.rescues += 1
172
+ threading.Thread(target=worker, args=(1, remaining), name="mobster-rescue-1",
173
+ daemon=True).start()
174
+ attempts = 2 if hedged else 1
175
+ resent = False
176
+ with done:
177
+ while True:
178
+ success = next((item for item in results.values() if item[0]), None)
179
+ if success is not None:
180
+ return success[1]
181
+ if len(results) == attempts:
182
+ remaining = timeout - (clock() - started)
183
+ if not resent and transient(results[0][1]) and remaining >= RESEND_MIN_SECONDS:
184
+ # Failed in transit with time to spare: resend once on a fresh connection; not a hedge.
185
+ resent = True
186
+ index, attempts = attempts, attempts + 1
187
+ self.resends += 1
188
+ threading.Thread(target=worker, args=(index, remaining), name=f"mobster-resend-{index}",
189
+ daemon=True).start()
190
+ continue
191
+ raise results[0][1]
192
+ left = timeout - (clock() - started) + .25
193
+ if left <= 0:
194
+ # Say how many requests were in flight, so a stalled twin is told apart from a missing hedge.
195
+ raise TimeoutError(f"Model call deadline exceeded ({attempts} request"
196
+ f"{'s' if attempts > 1 else ''} in flight)")
197
+ done.wait(timeout=left)
198
+
199
+
200
+ # A decision call carries a 6-15k token prompt and answers in seconds; the floor keeps twins for real outliers.
201
+ FRONTIER_FLOOR, FRONTIER_DEFAULT = 4.0, 8.0
202
+
203
+ HEDGERS = {"anthropic": Hedger(any_floor=FRONTIER_FLOOR, any_default=FRONTIER_DEFAULT)}
@@ -0,0 +1,305 @@
1
+ """`mobster --help`, `mobster help --all` and the help topics (`environment`, `exit-codes`, `tui`)."""
2
+
3
+ import os
4
+
5
+ from . import links
6
+ from .cli_constants import DEFAULT_WDA_URL
7
+
8
+ HERO = "Test and automate apps on real iPhones."
9
+ # What the command does, in plain words: the task, the cable, the approval, and the agents you already have. No
10
+ # Codex or Cursor until S7 (MESSAGING §1.3). Proposed for MESSAGING §1.1 in polish/cli/HANDOFF-messaging.md.
11
+ LINE_2 = ("Type a task and Mobster's agent does it on your iPhone, over USB from your Mac. It asks before it sends, "
12
+ "buys, posts or deletes. Claude Code and your own agents can use the phone too.")
13
+
14
+ # Every command and its one line, in the order `mobster --help` lists them. The parser uses the same lines.
15
+ HELP = {
16
+ "login": "save your Claude or OpenAI key, or a plan's or provider's",
17
+ "doctor": "check your iPhone, key and tools; --fix fixes what it can",
18
+ "setup": "set up your iPhone for Mobster, one step at a time",
19
+ "devices": "list the iPhones and simulators Mobster can use",
20
+ "chat": "talk to Mobster's agent; follow-ups know what earlier tasks found",
21
+ "workflow": "print a saved workflow's steps in the order they run",
22
+ "run": "run one task and print each step (JSON lines when piped)",
23
+ "memory": "see and edit what Mobster remembers",
24
+ "history": "list past tasks",
25
+ "export": "save a past task as a captioned GIF or MP4",
26
+ "screen": "show your iPhone's screen in the terminal",
27
+ "test": "run your app's saved checks on simulators and iPhones, with reports",
28
+ "verify": "run one check once, from flags or a file, and print passed or failed",
29
+ "mcp": "let your coding agent use the phone and check your app",
30
+ "sim": "create and clean up Mobster's simulators",
31
+ "ci": "run your checks on every pull request, on a hosted runner or a Mac of yours",
32
+ "account": "make, list and revoke the CI tokens a hosted CI runner signs in with",
33
+ "expo": "open your Expo app on a simulator or your iPhone, and build it",
34
+ "asc": "read App Store Connect feedback and builds, make screenshots",
35
+ "testflight": "list your TestFlight builds and install one on your iPhone",
36
+ "xcode": "run your checks after every simulator build in Xcode",
37
+ "links": "list your app’s deep links and check that each lands on its screen",
38
+ "fixtures": "list the app states your checks start from, and put a simulator in one",
39
+ "xray": "map an app's screens and paywalls, or see who your apps talk to",
40
+ "signing": "put Mobster's helper on an iPhone without Xcode, for a paid team",
41
+ "serve": "start the local API that Mobster for Mac and other clients use",
42
+ "phone": "set your iPhone's clipboard, put files on it, or install a build",
43
+ "alerts": "test the webhook that hears about scheduled tasks",
44
+ "audit": "check a Team plan audit export offline",
45
+ "env": "keep a project's test credentials in your Keychain, for its checks",
46
+ "demo": "run a scripted task: no phone, no keys",
47
+ "completion": "print a shell completion script (zsh, bash or fish)",
48
+ "update": "say whether a newer Mobster is out, and where to get it",
49
+ "version": "print the version",
50
+ "logout": "remove a saved key, or forget a plan's or provider's, on this Mac",
51
+ "help": "show the help for a command or a topic",
52
+ "wifi": "use an iPhone without the cable, over the encrypted Wi-Fi link",
53
+ "api": "serve every app on your iPhone as a local, read-only API",
54
+ "tui": "open the terminal UI (what `mobster` does on its own)",
55
+ "build-ocr": "compile the optional Apple Vision OCR helper (needs Xcode)",
56
+ }
57
+
58
+ # The commands a first-time user types. Everything else is in `mobster help --all`, and works the same.
59
+ GROUPS = (("Commands", ("doctor", "devices", "test", "mcp")),)
60
+ MORE = ("login", "setup", "chat", "workflow", "run", "memory", "history", "export", "screen", "xray", "verify", "sim",
61
+ "ci", "account", "expo",
62
+ "asc", "testflight", "xcode", "fixtures", "links", "serve", "api", "phone", "alerts", "audit", "env", "demo",
63
+ "completion", "update", "version", "logout")
64
+ # Registered, but never in the top-level help: internals, the parser's own aliases, and switches that are off.
65
+ HIDDEN = ("help", "tui", "build-ocr", "wifi", "signing")
66
+ COMMANDS = tuple(HELP)
67
+
68
+ # (the command, its task and options): the command is painted as a command, the rest as text.
69
+ EXAMPLES = (
70
+ ("mobster doctor", "--fix"),
71
+ ("mobster", '"Turn on Dark Mode"'),
72
+ ("mobster chat", '"Find my last message from Kate Bell"'),
73
+ ("mobster run", """"What's my battery level?" --execute --json"""),
74
+ ("mobster test", ""),
75
+ ("mobster mcp install", "--all"),
76
+ )
77
+
78
+ # The options every terminal knows to look for, and the two that change what a command does.
79
+ OPTIONS = (
80
+ ("-h, --help", "show this help; after a command, that command's help"),
81
+ ("--version", "print the version"),
82
+ ("--demo", "try Mobster on a pretend iPhone: no phone or key needed"),
83
+ ("--json", "print JSON for scripts, on run, chat, doctor and devices"),
84
+ )
85
+
86
+ TOPICS = {
87
+ "environment": "every variable Mobster reads",
88
+ "exit-codes": "what each exit code means",
89
+ "tui": "the terminal UI's options and keys",
90
+ }
91
+
92
+ # One table for every command's exit codes: `mobster help exit-codes` and the docs' reference render it.
93
+ EXIT_CODES = (
94
+ ("0", "done", "verify and test: passed"),
95
+ ("1", "the task or check didn't succeed", "verify and test: failed"),
96
+ ("2", "usage error: a mistyped command or option", "verify and test: needs review; chat: it waits for you"),
97
+ ("3", "couldn't run: no phone, no key, nothing serving", "verify and test: usage errors too"),
98
+ ("4", "chat: still working when --wait ran out; the task goes on", ""),
99
+ ("130", "stopped with ctrl+c (128 + the signal for SIGTERM and SIGHUP)", ""),
100
+ )
101
+
102
+ # (name, default, meaning) for the variables people set. Every other MOBSTER_ variable the code reads is a tuning or
103
+ # development switch, listed by name under TUNING.
104
+ ENVIRONMENT = (
105
+ ("Keys", (
106
+ ("ANTHROPIC_API_KEY", "", "your Claude key: Mobster's agent runs on Claude"),
107
+ ("OPENAI_API_KEY", "", "your OpenAI key: Mobster's agent runs on OpenAI"),
108
+ ("MOBSTER_SMART_PROVIDER", "", "anthropic, openai, or a plan or provider from `mobster login status`: what "
109
+ "Mobster's agent runs on when several are saved"),
110
+ ("MOBSTER_SMART_MODEL", "", "the model Mobster's agent runs on, instead of the default for your key"),
111
+ ("TEXT_MODEL", "", "a helper model, such as Gemini on Vertex AI to describe audio (with TEXT_MODEL_API_KEY, "
112
+ "TEXT_MODEL_BASE_URL, TEXT_MODEL_PROVIDER)"),
113
+ ("MOBSTER_HELPER_PROVIDER", "", "the helper's provider, as Mobster for Mac saves it"),
114
+ )),
115
+ ("Files and folders", (
116
+ ("MOBSTER_ENV_FILE", "", "a KEY=VALUE file every command loads, like --env-file"),
117
+ ("MOBSTER_DATA_DIR", "~/Library/Application Support/app.mobster.desktop/dev",
118
+ "where verify, sim and mcp keep simulators and builds"),
119
+ ("MOBSTER_RUNS_DIR", "./.mobster/runs", "where verify and test write their reports"),
120
+ ("MOBSTER_MEMORY_DIR", "", "where what Mobster remembers is kept"),
121
+ )),
122
+ ("Your iPhone", (
123
+ ("MOBSTER_WDA_URL", DEFAULT_WDA_URL, "the iPhone's address (the --wda-url default)"),
124
+ ("MOBSTER_WDA_DEVICES", "", "more phone addresses for `mobster devices`, comma-separated"),
125
+ ("MOBSTER_ENABLE_LIVE", "1", "0 stops tasks from tapping and typing in the terminal UI"),
126
+ ("MOBSTER_PERMISSION_MODE", "ask_important", "ask_all, ask_important or dont_ask (full access)"),
127
+ ("MOBSTER_ASK_BEFORE_ACTING", "1", "0 is the older name for MOBSTER_PERMISSION_MODE=dont_ask"),
128
+ ("MOBSTER_APP_ACCESS", "ask", "all: every app counts as allowed (scripts and tests only)"),
129
+ ("MOBSTER_APPS_ALLOWED", "", "bundle IDs that count as allowed (scripts and tests only)"),
130
+ ("MOBSTER_OUTSIDE_BLOCKED_APPS", "", "bundle IDs agents outside Mobster never open, comma-separated"),
131
+ ("MOBSTER_BLOCKED_APPS", "", "bundle IDs Mobster's agent must never open, comma-separated"),
132
+ ("MOBSTER_ASK_USER", "on", "off stops Mobster's agent from asking you questions mid-task"),
133
+ ("MOBSTER_PHONE_VIEW", "auto", "image, text or off: how the terminal UI shows the phone"),
134
+ ("MOBSTER_MAX_SIMS", "", "the most simulators `mobster test` boots at once"),
135
+ ("MOBSTER_TEAM_KEY", "", "your team's upload key from the console (<team id>:mtk_…): `mobster test --share` "
136
+ "uploads with it in CI (Team plan)"),
137
+ )),
138
+ ("Mobster for Mac and `mobster serve`", (
139
+ ("MOBSTER_URL", "", "the Mobster that `mobster chat` talks to (default: the running Mac app's "
140
+ "address, else http://127.0.0.1:8765)"),
141
+ ("MOBSTER_API_TOKEN", "", "that Mobster's API token (or MOBSTER_API_TOKEN_FILE, a file holding it)"),
142
+ ("MOBSTER_TASK_COST_LIMIT", "", "stop a task once it has cost this many US dollars"),
143
+ ("MOBSTER_MONTHLY_LIMIT", "", "stop starting tasks once this month has cost this many US dollars"),
144
+ ("MOBSTER_ALERT_WEBHOOK_URL", "", "where a scheduled task's failures and approvals are posted"),
145
+ ("MOBSTER_KEEP_AWAKE", "1", "0 lets the Mac sleep while tasks run or workflows are scheduled"),
146
+ ("MOBSTER_MAC_BATTERY_WARN", "20", "warn tasks when the Mac's battery is at or under this percent; off"),
147
+ ("MOBSTER_PHONE_BATTERY_PAUSE", "10", "pause long and scheduled tasks at this phone battery percent "
148
+ "while it isn't charging; off"),
149
+ ("MOBSTER_LISTEN", "", "off: WATCH sees the screen only and MCP's listen isn't listed (on by default)"),
150
+ )),
151
+ ("Output", (
152
+ ("NO_COLOR", "", "any value turns colour off"),
153
+ ("MOBSTER_PLAIN", "", "1: plain text, no colour or spinners (for screen readers and logs)"),
154
+ ("MOBSTER_THEME", "", "light or dark: the colours for your terminal's background (default: asked)"),
155
+ ("MOBSTER_NO_UPDATE_CHECK", "", "1 turns off the daily check for a new release"),
156
+ ("CI", "", "any value: no update check, no questions"),
157
+ )),
158
+ )
159
+
160
+ TUNING = ("MOBSTER_API_TOKEN_FILE", "MOBSTER_APP_SESSION", "MOBSTER_CAPTURE_GATE", "MOBSTER_FRAME_CLOCK_LOG",
161
+ "MOBSTER_FRAME_CLOCK_TRACE", "MOBSTER_GLIDE", "MOBSTER_HEDGE", "MOBSTER_HEDGE_RATIO",
162
+ "MOBSTER_IPHONE_TOOLS", "MOBSTER_NO_DEVICES", "MOBSTER_PRINT_TIMING", "MOBSTER_RENEW_WINDOW_HOURS",
163
+ "MOBSTER_SEARCH_PATHS", "MOBSTER_SIM_PORT_BASE", "MOBSTER_SIM_WDA_XCTESTRUN", "MOBSTER_SKIP_SWIFT",
164
+ "MOBSTER_TYPING_FREQUENCY", "MOBSTER_VIDEO_DETAIL", "MOBSTER_VIDEO_FPS", "MOBSTER_WIFI_TRANSPORT",
165
+ "MOBSTER_HOME", "MOBSTER_BIN_DIR", "MOBSTER_INSTALL_BASE_URL", "MOBSTER_NO_MODIFY_PATH")
166
+
167
+ AGENT_VARIABLES = ("CLAUDECODE", "CLAUDE_CODE_ENTRYPOINT", "CODEX_SANDBOX", "CODEX_MANAGED_BY_NPM", "OPENCODE",
168
+ "CURSOR_AGENT", "GEMINI_CLI")
169
+
170
+
171
+ def under_agent(env=None):
172
+ """Whether a coding agent runs this command (it sets one of AGENT_VARIABLES)."""
173
+ env = os.environ if env is None else env
174
+ return any(env.get(name) for name in AGENT_VARIABLES)
175
+
176
+
177
+ def visible(name, env=None):
178
+ """Whether ``name`` is offered by shell completion: hidden commands never; `wifi` only when its switch is on."""
179
+ if name == "wifi":
180
+ from .wireless import transport_on
181
+ return transport_on(env)
182
+ return name not in HIDDEN
183
+
184
+
185
+ def top_level(paint, width=100):
186
+ """`mobster --help`: one description column for every section, purple only for what you type."""
187
+ def heading(text):
188
+ return paint(text, "bold")
189
+
190
+ def command(words):
191
+ """``mobster <command> [options]``: the words to type in accent, the placeholders in grey."""
192
+ return " ".join(paint(word, "tertiary" if word[0] in '"<[' else "accent") for word in words.split(" "))
193
+
194
+ usage = (("mobster", "open Mobster in this terminal"), ('mobster "TASK"', "open it and run TASK"),
195
+ ("mobster <command> [options]", "run one of the commands below"))
196
+ learn = [("mobster help <command>", "options and examples for one command")]
197
+ learn += [(f"mobster help {topic}", words) for topic, words in TOPICS.items()]
198
+ learn += [("mobster help --all",
199
+ f"all {len(MORE) + sum(map(len, (n for _, n in GROUPS)))} commands, with login, chat, run and sim")]
200
+ rows = [left for left, _ in usage + tuple(learn)] + [flag for flag, _ in OPTIONS]
201
+ for _, names in GROUPS:
202
+ rows += list(names)
203
+ texts = [words for _, words in usage + tuple(learn) + OPTIONS] + [HELP[name] for name in rows if name in HELP]
204
+ # One column for every section; a terminal too narrow for it gets the short one the command names need.
205
+ column = max(len(left) for left in rows) + 2
206
+ if 2 + column + max(len(text) for text in texts) > width:
207
+ column = max(len(name) for name in rows if name in HELP or name.startswith("-")) + 2
208
+
209
+ def row(left, words, painted=None):
210
+ pad = " " * max(2, column - len(left))
211
+ if len(left) >= column:
212
+ return " " + (painted or paint(left, "accent")) + "\n" + " " * (2 + column) + words
213
+ return " " + (painted or paint(left, "accent")) + pad + words
214
+
215
+ lines = [paint(HERO, "bold")]
216
+ lines += _wrap(LINE_2, width).splitlines()
217
+ lines += ["", heading("Usage")]
218
+ lines += [row(left, words, command(left)) for left, words in usage]
219
+ for title, names in GROUPS:
220
+ lines += ["", heading(title)]
221
+ lines += [row(name, HELP[name]) for name in names]
222
+ lines += ["", heading("Options")]
223
+ lines += [row(flag, words) for flag, words in OPTIONS]
224
+ lines += ["", heading("Examples")]
225
+ lines += [" " + paint("$ ", "tertiary") + paint(cmd, "accent") + (" " + rest if rest else "")
226
+ for cmd, rest in EXAMPLES]
227
+ lines += ["", heading("Learn more")]
228
+ lines += [row(left, words, command(left)) for left, words in learn]
229
+ lines += [row("Docs", paint(links.DOCS, "accent", "underline"), "Docs")]
230
+ if under_agent():
231
+ lines += ["", "Running under an agent? Use " + paint("mobster mcp", "accent") + ", or "
232
+ + paint("--json", "accent") + " on run, chat, doctor and devices."]
233
+ return "\n".join(lines) + "\n"
234
+
235
+
236
+ def all_commands(paint, helps):
237
+ """`mobster help --all`: every command the parser has, the hidden ones too. ``helps``: {name: help}."""
238
+ lines = [paint("Every command", "bold")]
239
+ width = max(len(name) for name in helps) + 2
240
+ for name in sorted(helps):
241
+ lines.append(" " + paint(name.ljust(width), "accent") + (helps[name] or HELP.get(name, "")))
242
+ lines += ["", "Options and examples for one: " + paint("mobster help <command>", "accent")]
243
+ return "\n".join(lines)
244
+
245
+
246
+ def environment(paint, width=100):
247
+ lines = [paint("Environment variables", "bold"),
248
+ _wrap("Mobster reads these from the environment, an --env-file, $MOBSTER_ENV_FILE and, last, the keys "
249
+ "Mobster for Mac saved on this Mac. A variable already set wins.", width)]
250
+ for title, rows in ENVIRONMENT:
251
+ lines += ["", paint(title, "bold")]
252
+ for name, default, meaning in rows:
253
+ lines.append(" " + paint(name, "accent"))
254
+ text = meaning + (f" (default: {default})" if default else "")
255
+ lines.append(_wrap(text, width, indent=4))
256
+ lines += ["", paint("Tuning and development", "bold"),
257
+ _wrap("These change how Mobster's agent works and are for development: " + ", ".join(TUNING) + ".",
258
+ width, indent=2),
259
+ "", "More: " + paint(links.page("configuration", "environment-variables"), "accent")]
260
+ return "\n".join(lines)
261
+
262
+
263
+ def exit_codes(paint, width=100):
264
+ lines = [paint("Exit codes", "bold"),
265
+ _wrap("Every command exits with one of these. Scripts can tell a usage error (2) from a phone or key "
266
+ "that isn't there (3).", width), ""]
267
+ for code, meaning, exception in EXIT_CODES:
268
+ lines.append(" " + paint(code.ljust(5), "accent") + meaning)
269
+ if exception:
270
+ lines.append(" " * 7 + paint(exception, "tertiary"))
271
+ lines += ["", "Each command's own codes are at the end of its help: " + paint("mobster help run", "accent")]
272
+ return "\n".join(lines)
273
+
274
+
275
+ TUI_OPTIONS = (
276
+ ('"TASK"', "open with TASK and run it (it waits in the box until your iPhone and key are ready)"),
277
+ ("-c, --continue", "continue your last conversation"),
278
+ ("--resume [ID]", "open a past task and put it back in the box (the latest without an ID)"),
279
+ ("--demo", "a scripted phone and policy: no iPhone, no keys, no model calls"),
280
+ ("--device NAME", "the iPhone or simulator to use, from `mobster devices`"),
281
+ ("--app NAME", "start with this app chosen (a name or bundle ID)"),
282
+ ("--env-file PATH", "load keys and settings from a KEY=VALUE file [env: MOBSTER_ENV_FILE]"),
283
+ ("--no-bell", "don't ring the terminal bell when Mobster needs you"),
284
+ ("--wda-url URL", "the phone's address, for a phone you set up by hand [env: MOBSTER_WDA_URL]"),
285
+ )
286
+
287
+
288
+ def tui(paint, width=100, keys=()):
289
+ lines = [paint("The terminal UI", "bold"),
290
+ _wrap("`mobster` on its own opens Mobster in this terminal: tell it what to do, watch each step, and "
291
+ "answer when it asks before it sends, buys, posts or deletes.", width), "",
292
+ paint("Usage", "bold"), " " + paint('mobster [options] ["TASK"]', "accent"), "",
293
+ paint("Options", "bold")]
294
+ for flag, words in TUI_OPTIONS:
295
+ lines.append(" " + paint(flag.ljust(18), "accent") + words)
296
+ if keys:
297
+ lines += ["", paint("Keys", "bold")]
298
+ lines += [" " + paint(key.ljust(18), "accent") + words for key, words in keys]
299
+ lines += ["", "More: " + paint(links.TUI, "accent")]
300
+ return "\n".join(lines)
301
+
302
+
303
+ def _wrap(text, width, indent=0):
304
+ from .style import wrap
305
+ return wrap(text, min(width, 100), indent=indent)