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.
- mobile_agent/__init__.py +4 -0
- mobile_agent/__main__.py +598 -0
- mobile_agent/accounts/__init__.py +1 -0
- mobile_agent/accounts/context.py +80 -0
- mobile_agent/accounts/mcp.py +55 -0
- mobile_agent/accounts/pacing.py +318 -0
- mobile_agent/accounts/register.py +78 -0
- mobile_agent/accounts/routes.py +212 -0
- mobile_agent/accounts/routing.py +69 -0
- mobile_agent/accounts/screen.py +273 -0
- mobile_agent/accounts/stats.py +54 -0
- mobile_agent/accounts/store.py +394 -0
- mobile_agent/agent_hooks.py +123 -0
- mobile_agent/ai_plans/__init__.py +7 -0
- mobile_agent/ai_plans/agents.py +96 -0
- mobile_agent/ai_plans/claude_code.py +208 -0
- mobile_agent/ai_plans/cli.py +400 -0
- mobile_agent/ai_plans/codex.py +258 -0
- mobile_agent/ai_plans/compat_chat.py +307 -0
- mobile_agent/ai_plans/device_login.py +164 -0
- mobile_agent/ai_plans/draft_client.py +68 -0
- mobile_agent/ai_plans/gemini.py +137 -0
- mobile_agent/ai_plans/instructions.py +65 -0
- mobile_agent/ai_plans/mcp_http.py +160 -0
- mobile_agent/ai_plans/phone_tools.py +892 -0
- mobile_agent/ai_plans/providers.py +235 -0
- mobile_agent/ai_plans/routes.py +160 -0
- mobile_agent/ai_plans/runner.py +400 -0
- mobile_agent/ai_plans/vault.py +114 -0
- mobile_agent/alerts.py +337 -0
- mobile_agent/android/__init__.py +18 -0
- mobile_agent/android/adb.py +268 -0
- mobile_agent/android/conditions.py +128 -0
- mobile_agent/android/doctor.py +54 -0
- mobile_agent/android/driver.py +137 -0
- mobile_agent/android/emulator.py +216 -0
- mobile_agent/android/logs.py +85 -0
- mobile_agent/android/manager.py +225 -0
- mobile_agent/android/records.py +31 -0
- mobile_agent/android/tree.py +96 -0
- mobile_agent/answer_shapes.py +230 -0
- mobile_agent/api_devices.py +333 -0
- mobile_agent/api_errors.py +17 -0
- mobile_agent/api_get.py +249 -0
- mobile_agent/api_http.py +467 -0
- mobile_agent/api_post.py +453 -0
- mobile_agent/api_routes.py +173 -0
- mobile_agent/app_api/__init__.py +4 -0
- mobile_agent/app_api/cli.py +151 -0
- mobile_agent/app_api/endpoints.py +193 -0
- mobile_agent/app_api/mcp.py +54 -0
- mobile_agent/app_api/openapi.py +146 -0
- mobile_agent/app_api/reading.py +172 -0
- mobile_agent/app_api/register.py +10 -0
- mobile_agent/app_api/screen.py +216 -0
- mobile_agent/app_api/service.py +382 -0
- mobile_agent/app_api/sessions.py +404 -0
- mobile_agent/app_api/tokens.py +167 -0
- mobile_agent/app_choice.py +131 -0
- mobile_agent/app_icons.py +183 -0
- mobile_agent/app_killer.py +69 -0
- mobile_agent/artifacts.py +606 -0
- mobile_agent/attach/__init__.py +13 -0
- mobile_agent/attach/cli.py +46 -0
- mobile_agent/attach/flutter.py +28 -0
- mobile_agent/attach/score.py +119 -0
- mobile_agent/attach/web.py +13 -0
- mobile_agent/attachments/__init__.py +1 -0
- mobile_agent/attachments/agent.py +418 -0
- mobile_agent/attachments/extract.py +217 -0
- mobile_agent/attachments/mcp.py +104 -0
- mobile_agent/attachments/register.py +73 -0
- mobile_agent/attachments/routes.py +326 -0
- mobile_agent/attachments/service.py +170 -0
- mobile_agent/attachments/sniff.py +152 -0
- mobile_agent/attachments/store.py +441 -0
- mobile_agent/audit_verify.py +436 -0
- mobile_agent/bench/README.md +410 -0
- mobile_agent/bench/__init__.py +0 -0
- mobile_agent/bench/__main__.py +394 -0
- mobile_agent/bench/ab.py +168 -0
- mobile_agent/bench/actuation.py +368 -0
- mobile_agent/bench/agents/__init__.py +9 -0
- mobile_agent/bench/agents/base.py +105 -0
- mobile_agent/bench/agents/plan_clients.py +245 -0
- mobile_agent/bench/agents/smart.py +533 -0
- mobile_agent/bench/checks.py +358 -0
- mobile_agent/bench/decide_gate.py +214 -0
- mobile_agent/bench/diagnose.py +181 -0
- mobile_agent/bench/evals/__init__.py +14 -0
- mobile_agent/bench/evals/build.py +565 -0
- mobile_agent/bench/evals/checkpoint.py +214 -0
- mobile_agent/bench/evals/irt.py +219 -0
- mobile_agent/bench/evals/l0.py +647 -0
- mobile_agent/bench/evals/l1.py +866 -0
- mobile_agent/bench/evals/models.py +124 -0
- mobile_agent/bench/evals/pairwise.py +189 -0
- mobile_agent/bench/evals/proxy.py +90 -0
- mobile_agent/bench/evals/sets.py +149 -0
- mobile_agent/bench/evals/traces.py +446 -0
- mobile_agent/bench/fixtures.py +176 -0
- mobile_agent/bench/guard_replay.py +129 -0
- mobile_agent/bench/h2-manifest.json +20 -0
- mobile_agent/bench/h3-manifest.json +20 -0
- mobile_agent/bench/heldout-manifest.json +32 -0
- mobile_agent/bench/heldout.py +375 -0
- mobile_agent/bench/iosworld.py +901 -0
- mobile_agent/bench/iosworld_stats.py +510 -0
- mobile_agent/bench/llm_units.py +116 -0
- mobile_agent/bench/manifest.json +93 -0
- mobile_agent/bench/metrics.py +66 -0
- mobile_agent/bench/phone.py +44 -0
- mobile_agent/bench/replay.py +172 -0
- mobile_agent/bench/report.py +207 -0
- mobile_agent/bench/runner.py +456 -0
- mobile_agent/bench/safety.py +310 -0
- mobile_agent/bench/stream_timing.py +213 -0
- mobile_agent/bench/suite.py +444 -0
- mobile_agent/bench/sweep.py +176 -0
- mobile_agent/bench/tape.py +798 -0
- mobile_agent/bench/tape_replay.py +88 -0
- mobile_agent/bench/trace_evals.py +128 -0
- mobile_agent/bench/trace_view.py +81 -0
- mobile_agent/bench/truth/iphone15pro.json +138 -0
- mobile_agent/bench/truth.py +340 -0
- mobile_agent/bench/tuning.py +543 -0
- mobile_agent/bench/tuning_analysis.py +656 -0
- mobile_agent/bench/vague-heldout-manifest.json +12 -0
- mobile_agent/bench/vague_rubric.py +135 -0
- mobile_agent/bench/vague_run.py +243 -0
- mobile_agent/brand.py +454 -0
- mobile_agent/brand_fonts.py +756 -0
- mobile_agent/build_identity.py +21 -0
- mobile_agent/cable_bt.py +623 -0
- mobile_agent/cable_bt_runtime.py +128 -0
- mobile_agent/catalog.py +69 -0
- mobile_agent/chart_svg.py +415 -0
- mobile_agent/chat_here.py +189 -0
- mobile_agent/cli_constants.py +5 -0
- mobile_agent/cli_parser.py +611 -0
- mobile_agent/cli_run.py +115 -0
- mobile_agent/compiled_read/__init__.py +21 -0
- mobile_agent/compiled_read/delta.py +89 -0
- mobile_agent/compiled_read/extractors.py +202 -0
- mobile_agent/compiled_read/routes.py +56 -0
- mobile_agent/completion.py +267 -0
- mobile_agent/compose.py +48 -0
- mobile_agent/config.py +114 -0
- mobile_agent/connectors/__init__.py +1 -0
- mobile_agent/connectors/api_session.py +76 -0
- mobile_agent/connectors/callback_page.py +146 -0
- mobile_agent/connectors/client.py +582 -0
- mobile_agent/connectors/github_app.py +55 -0
- mobile_agent/connectors/graph_api.py +396 -0
- mobile_agent/connectors/imports.py +170 -0
- mobile_agent/connectors/issue.py +66 -0
- mobile_agent/connectors/keystore.py +85 -0
- mobile_agent/connectors/marks.py +222 -0
- mobile_agent/connectors/oauth.py +476 -0
- mobile_agent/connectors/picker.py +228 -0
- mobile_agent/connectors/presets.py +591 -0
- mobile_agent/connectors/register.py +48 -0
- mobile_agent/connectors/routes.py +153 -0
- mobile_agent/connectors/service.py +966 -0
- mobile_agent/connectors/shared.py +136 -0
- mobile_agent/connectors/skill.py +446 -0
- mobile_agent/connectors/slack_api.py +269 -0
- mobile_agent/connectors/steps.py +92 -0
- mobile_agent/connectors/store.py +144 -0
- mobile_agent/connectors/vault.py +72 -0
- mobile_agent/console.py +178 -0
- mobile_agent/content_queue/__init__.py +1 -0
- mobile_agent/content_queue/client.py +263 -0
- mobile_agent/content_queue/importing.py +153 -0
- mobile_agent/content_queue/media_check.py +224 -0
- mobile_agent/content_queue/prompt.py +64 -0
- mobile_agent/content_queue/register.py +91 -0
- mobile_agent/content_queue/routes.py +370 -0
- mobile_agent/content_queue/runner.py +475 -0
- mobile_agent/content_queue/store.py +521 -0
- mobile_agent/contract.py +996 -0
- mobile_agent/contract_asks.py +248 -0
- mobile_agent/contract_prompt.py +45 -0
- mobile_agent/contract_screen.py +981 -0
- mobile_agent/contract_view.py +84 -0
- mobile_agent/corpus/__init__.py +26 -0
- mobile_agent/corpus/cli.py +63 -0
- mobile_agent/corpus/consent.py +55 -0
- mobile_agent/corpus/listener.py +76 -0
- mobile_agent/corpus/register.py +9 -0
- mobile_agent/corpus/skeleton.py +72 -0
- mobile_agent/corpus/store.py +143 -0
- mobile_agent/costs.py +161 -0
- mobile_agent/decider_scope.py +40 -0
- mobile_agent/decision_provider.py +189 -0
- mobile_agent/deeplinks.py +352 -0
- mobile_agent/device_info.py +116 -0
- mobile_agent/device_manager.py +978 -0
- mobile_agent/device_status.py +195 -0
- mobile_agent/device_targets.py +217 -0
- mobile_agent/devices.py +676 -0
- mobile_agent/devkit/__init__.py +64 -0
- mobile_agent/devkit/account_cli.py +90 -0
- mobile_agent/devkit/asc.py +562 -0
- mobile_agent/devkit/asc_cli.py +214 -0
- mobile_agent/devkit/ci.py +737 -0
- mobile_agent/devkit/ci_cli.py +196 -0
- mobile_agent/devkit/ci_hosts.py +194 -0
- mobile_agent/devkit/es256.py +197 -0
- mobile_agent/devkit/expo.py +440 -0
- mobile_agent/devkit/expo_cli.py +405 -0
- mobile_agent/devkit/expo_dev.py +203 -0
- mobile_agent/devkit/expo_routes.py +90 -0
- mobile_agent/devkit/fixtures_cli.py +133 -0
- mobile_agent/devkit/fixtures_routes.py +82 -0
- mobile_agent/devkit/links.py +375 -0
- mobile_agent/devkit/links_cli.py +123 -0
- mobile_agent/devkit/links_routes.py +83 -0
- mobile_agent/devkit/nightly.py +152 -0
- mobile_agent/devkit/shots.py +203 -0
- mobile_agent/devkit/testflight.py +155 -0
- mobile_agent/devkit/testflight_cli.py +127 -0
- mobile_agent/devkit/testflight_routes.py +111 -0
- mobile_agent/devkit/xcode.py +236 -0
- mobile_agent/devkit/xcode_cli.py +101 -0
- mobile_agent/devtools.py +419 -0
- mobile_agent/doctor.py +509 -0
- mobile_agent/doctor_fix.py +467 -0
- mobile_agent/downloads.py +55 -0
- mobile_agent/drivers.py +793 -0
- mobile_agent/dry_run.py +102 -0
- mobile_agent/effect_ledger.py +83 -0
- mobile_agent/engine_health.py +378 -0
- mobile_agent/engine_hooks.py +96 -0
- mobile_agent/engines.py +408 -0
- mobile_agent/env_file.py +63 -0
- mobile_agent/env_secrets.py +149 -0
- mobile_agent/errors.py +15 -0
- mobile_agent/evals/__init__.py +3 -0
- mobile_agent/evals/app_survey.py +149 -0
- mobile_agent/evals/development/__init__.py +1 -0
- mobile_agent/evals/development/score.py +276 -0
- mobile_agent/evals/latency_report.py +312 -0
- mobile_agent/evals/offline_report.py +374 -0
- mobile_agent/evals/oracles.py +298 -0
- mobile_agent/evals/redteam/__init__.py +15 -0
- mobile_agent/evals/redteam/__main__.py +72 -0
- mobile_agent/evals/redteam/cases.py +730 -0
- mobile_agent/evals/redteam/harness.py +604 -0
- mobile_agent/evals/redteam/live.py +139 -0
- mobile_agent/evals/redteam/plain.py +85 -0
- mobile_agent/evals/vision/__init__.py +0 -0
- mobile_agent/evals/vision/images/dog_001.jpg +0 -0
- mobile_agent/evals/vision/images/dog_002.jpg +0 -0
- mobile_agent/evals/vision/images/dog_003.jpg +0 -0
- mobile_agent/evals/vision/images/dog_004.jpg +0 -0
- mobile_agent/evals/vision/images/dog_005.jpg +0 -0
- mobile_agent/evals/vision/images/dog_006.jpg +0 -0
- mobile_agent/evals/vision/images/dog_007.jpg +0 -0
- mobile_agent/evals/vision/images/dog_010.jpg +0 -0
- mobile_agent/evals/vision/images/dog_011.jpg +0 -0
- mobile_agent/evals/vision/images/dog_013.jpg +0 -0
- mobile_agent/evals/vision/images/dog_014.jpg +0 -0
- mobile_agent/evals/vision/images/dog_015.jpg +0 -0
- mobile_agent/evals/vision/images/dog_016.jpg +0 -0
- mobile_agent/evals/vision/images/dog_017.jpg +0 -0
- mobile_agent/evals/vision/images/dog_019.jpg +0 -0
- mobile_agent/evals/vision/images/dog_020.jpg +0 -0
- mobile_agent/evals/vision/images/dog_021.jpg +0 -0
- mobile_agent/evals/vision/images/dog_022.jpg +0 -0
- mobile_agent/evals/vision/images/dog_023.jpg +0 -0
- mobile_agent/evals/vision/images/dog_024.jpg +0 -0
- mobile_agent/evals/vision/images/dog_026.jpg +0 -0
- mobile_agent/evals/vision/images/dog_027.jpg +0 -0
- mobile_agent/evals/vision/images/dog_034.jpg +0 -0
- mobile_agent/evals/vision/images/dog_035.jpg +0 -0
- mobile_agent/evals/vision/images/dog_038.jpg +0 -0
- mobile_agent/evals/vision/images/dog_042.jpg +0 -0
- mobile_agent/evals/vision/images/dog_047.jpg +0 -0
- mobile_agent/evals/vision/images/dog_052.jpg +0 -0
- mobile_agent/evals/vision/images/dog_058.jpg +0 -0
- mobile_agent/evals/vision/images/dog_062.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_000.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_010.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_011.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_015.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_016.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_017.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_019.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_021.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_025.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_026.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_027.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_030.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_032.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_033.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_034.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_035.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_036.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_037.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_039.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_040.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_041.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_042.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_043.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_044.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_046.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_047.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_048.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_049.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_051.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_053.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_054.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_055.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_058.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_059.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_002.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_003.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_004.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_007.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_009.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_010.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_011.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_012.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_013.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_014.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_016.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_017.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_023.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_027.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_029.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_032.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_033.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_036.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_041.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_043.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_047.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_049.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_051.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_053.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_056.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_057.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_058.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_059.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_060.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_061.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_062.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_063.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_064.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_065.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_066.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_067.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_068.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_069.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_070.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_071.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_000.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_001.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_002.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_004.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_005.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_008.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_009.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_010.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_012.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_013.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_015.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_016.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_017.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_018.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_021.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_022.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_023.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_024.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_030.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_031.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_032.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_033.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_034.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_036.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_038.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_039.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_040.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_041.jpg +0 -0
- mobile_agent/evals/vision/manifest.json +2355 -0
- mobile_agent/eventbus.py +110 -0
- mobile_agent/explain.py +34 -0
- mobile_agent/failure_line.py +197 -0
- mobile_agent/fanout.py +663 -0
- mobile_agent/feedback/__init__.py +2 -0
- mobile_agent/feedback/bundle.py +204 -0
- mobile_agent/feedback/outbox.py +196 -0
- mobile_agent/feedback/register.py +9 -0
- mobile_agent/feedback/routes.py +177 -0
- mobile_agent/fleet.py +841 -0
- mobile_agent/fleet_health.py +729 -0
- mobile_agent/fleet_phone.py +186 -0
- mobile_agent/frontier/__init__.py +79 -0
- mobile_agent/frontier/act.py +380 -0
- mobile_agent/frontier/actions.py +70 -0
- mobile_agent/frontier/agent.py +256 -0
- mobile_agent/frontier/approvals.py +366 -0
- mobile_agent/frontier/hooks.py +199 -0
- mobile_agent/frontier/interrupts.py +125 -0
- mobile_agent/frontier/observe.py +331 -0
- mobile_agent/frontier/phases.py +381 -0
- mobile_agent/frontier/pipeline.py +61 -0
- mobile_agent/frontier/prompt.py +384 -0
- mobile_agent/frontier/protocol.py +91 -0
- mobile_agent/frontier/safety.py +467 -0
- mobile_agent/frontier/saved.py +375 -0
- mobile_agent/frontier/screen.py +419 -0
- mobile_agent/frontier/skills.py +147 -0
- mobile_agent/frontier/stages/__init__.py +1 -0
- mobile_agent/frontier/stages/after.py +192 -0
- mobile_agent/frontier/stages/approve.py +138 -0
- mobile_agent/frontier/stages/controls.py +115 -0
- mobile_agent/frontier/stages/ends.py +102 -0
- mobile_agent/frontier/stages/gate.py +92 -0
- mobile_agent/frontier/stages/guards.py +132 -0
- mobile_agent/frontier/stages/points.py +155 -0
- mobile_agent/frontier/stages/send.py +177 -0
- mobile_agent/frontier/turn.py +151 -0
- mobile_agent/full_disk_access.py +83 -0
- mobile_agent/gemini.py +69 -0
- mobile_agent/genuine.py +120 -0
- mobile_agent/graph/__init__.py +4 -0
- mobile_agent/graph/catalog.py +789 -0
- mobile_agent/graph/chain.py +306 -0
- mobile_agent/graph/dispatch.py +98 -0
- mobile_agent/graph/draft.py +373 -0
- mobile_agent/graph/edit.py +76 -0
- mobile_agent/graph/estimate.py +189 -0
- mobile_agent/graph/expr.py +562 -0
- mobile_agent/graph/functions.py +271 -0
- mobile_agent/graph/infer.py +144 -0
- mobile_agent/graph/nodes.py +936 -0
- mobile_agent/graph/phone_steps.py +178 -0
- mobile_agent/graph/rerun.py +327 -0
- mobile_agent/graph/run.py +899 -0
- mobile_agent/graph/schema.py +842 -0
- mobile_agent/graph/state.py +161 -0
- mobile_agent/graph/values.py +198 -0
- mobile_agent/harness/__init__.py +2 -0
- mobile_agent/harness/checkpoints.py +468 -0
- mobile_agent/harness/control.py +101 -0
- mobile_agent/harness/prewarm.py +213 -0
- mobile_agent/harness/register.py +43 -0
- mobile_agent/harness/routes.py +114 -0
- mobile_agent/harness/settings.py +66 -0
- mobile_agent/harness/tools/__init__.py +67 -0
- mobile_agent/harness/tools/ask_user.py +102 -0
- mobile_agent/harness/tools/watch.py +120 -0
- mobile_agent/harness_api.py +815 -0
- mobile_agent/hedge.py +203 -0
- mobile_agent/help_topics.py +305 -0
- mobile_agent/hints.py +248 -0
- mobile_agent/history.py +69 -0
- mobile_agent/home.py +214 -0
- mobile_agent/http_pool.py +175 -0
- mobile_agent/image_policy.py +139 -0
- mobile_agent/inbox.py +148 -0
- mobile_agent/installed_apps.py +344 -0
- mobile_agent/integrations/__init__.py +1 -0
- mobile_agent/integrations/cli.py +472 -0
- mobile_agent/integrations/client_files.py +65 -0
- mobile_agent/integrations/clients.py +998 -0
- mobile_agent/integrations/doctor.py +185 -0
- mobile_agent/integrations/jsonc.py +383 -0
- mobile_agent/integrations/routes.py +135 -0
- mobile_agent/integrations/rules.py +112 -0
- mobile_agent/integrations/server_options.py +46 -0
- mobile_agent/integrations/skill.py +152 -0
- mobile_agent/integrations/skill_files.py +10 -0
- mobile_agent/integrations/textedit.py +309 -0
- mobile_agent/intents/__init__.py +17 -0
- mobile_agent/intents/atlas.py +216 -0
- mobile_agent/intents/callback.py +44 -0
- mobile_agent/intents/cli.py +55 -0
- mobile_agent/intents/harvest.py +91 -0
- mobile_agent/intents/plan.py +93 -0
- mobile_agent/ios/__init__.py +1 -0
- mobile_agent/ios/guide.py +16 -0
- mobile_agent/ios/kb.py +212 -0
- mobile_agent/ios/kb_data.py +1588 -0
- mobile_agent/ios/mcp.py +44 -0
- mobile_agent/ios/register.py +8 -0
- mobile_agent/ios/system.py +369 -0
- mobile_agent/journal.py +531 -0
- mobile_agent/keychain_acl.py +374 -0
- mobile_agent/keys.py +395 -0
- mobile_agent/latency_overlap.py +36 -0
- mobile_agent/latency_trace.py +170 -0
- mobile_agent/learned/__init__.py +15 -0
- mobile_agent/learned/app_path.py +160 -0
- mobile_agent/learned/code_read.py +38 -0
- mobile_agent/learned/parts.py +546 -0
- mobile_agent/learned/programs.py +691 -0
- mobile_agent/learned/register.py +171 -0
- mobile_agent/learned/routes.py +61 -0
- mobile_agent/learned/taught.py +329 -0
- mobile_agent/learned/teach.py +538 -0
- mobile_agent/learned/workflows.py +647 -0
- mobile_agent/learned/zero.py +41 -0
- mobile_agent/links.py +37 -0
- mobile_agent/listen.py +607 -0
- mobile_agent/lock_spike.py +278 -0
- mobile_agent/lockscreen.py +526 -0
- mobile_agent/login.py +354 -0
- mobile_agent/longform/__init__.py +15 -0
- mobile_agent/longform/ads.py +191 -0
- mobile_agent/longform/blocks.py +117 -0
- mobile_agent/longform/budget.py +265 -0
- mobile_agent/longform/context.py +285 -0
- mobile_agent/longform/costs.py +93 -0
- mobile_agent/longform/digest.py +145 -0
- mobile_agent/longform/extract.py +508 -0
- mobile_agent/longform/feed.py +505 -0
- mobile_agent/longform/followup.py +168 -0
- mobile_agent/longform/frames.py +82 -0
- mobile_agent/longform/identity.py +87 -0
- mobile_agent/longform/inbox.py +221 -0
- mobile_agent/longform/items.py +425 -0
- mobile_agent/longform/models.py +115 -0
- mobile_agent/longform/notebook.py +329 -0
- mobile_agent/longform/plan.py +614 -0
- mobile_agent/longform/recall.py +195 -0
- mobile_agent/longform/receipts.py +81 -0
- mobile_agent/longform/register.py +124 -0
- mobile_agent/longform/report.py +343 -0
- mobile_agent/longform/routes.py +102 -0
- mobile_agent/longform/session.py +644 -0
- mobile_agent/longform/store.py +146 -0
- mobile_agent/longform/synthesis.py +347 -0
- mobile_agent/mac_tools.py +223 -0
- mobile_agent/manual_control.py +143 -0
- mobile_agent/maps.py +149 -0
- mobile_agent/marks.py +92 -0
- mobile_agent/mcp_server/__init__.py +3 -0
- mobile_agent/mcp_server/__main__.py +29 -0
- mobile_agent/mcp_server/action_journal.py +24 -0
- mobile_agent/mcp_server/action_tools.py +638 -0
- mobile_agent/mcp_server/approvals.py +219 -0
- mobile_agent/mcp_server/catalog.py +92 -0
- mobile_agent/mcp_server/cli.py +194 -0
- mobile_agent/mcp_server/codes.py +147 -0
- mobile_agent/mcp_server/device_tools.py +306 -0
- mobile_agent/mcp_server/direct.py +272 -0
- mobile_agent/mcp_server/expo_tools.py +105 -0
- mobile_agent/mcp_server/phone_tools.py +510 -0
- mobile_agent/mcp_server/protocol.py +364 -0
- mobile_agent/mcp_server/registry.py +55 -0
- mobile_agent/mcp_server/run_tools.py +531 -0
- mobile_agent/mcp_server/schemas.py +425 -0
- mobile_agent/mcp_server/screen_tools.py +168 -0
- mobile_agent/mcp_server/session.py +469 -0
- mobile_agent/mcp_server/support.py +145 -0
- mobile_agent/mcp_server/tools.py +493 -0
- mobile_agent/memory/__init__.py +9 -0
- mobile_agent/memory/cli.py +207 -0
- mobile_agent/memory/extract.py +191 -0
- mobile_agent/memory/listener.py +100 -0
- mobile_agent/memory/model.py +144 -0
- mobile_agent/memory/project.py +96 -0
- mobile_agent/memory/provider.py +127 -0
- mobile_agent/memory/register.py +21 -0
- mobile_agent/memory/retrieval.py +172 -0
- mobile_agent/memory/routes.py +216 -0
- mobile_agent/memory/runs.py +124 -0
- mobile_agent/memory/store.py +806 -0
- mobile_agent/memory/writer.py +278 -0
- mobile_agent/mirroring.py +585 -0
- mobile_agent/mirroring_runtime.py +221 -0
- mobile_agent/model_clients.py +604 -0
- mobile_agent/narrate.py +813 -0
- mobile_agent/native_helpers.py +84 -0
- mobile_agent/netxray/__init__.py +1 -0
- mobile_agent/netxray/analyze.py +322 -0
- mobile_agent/netxray/attribution.py +62 -0
- mobile_agent/netxray/capture.py +88 -0
- mobile_agent/netxray/cli.py +142 -0
- mobile_agent/netxray/job.py +219 -0
- mobile_agent/netxray/mobster-pcap.c +560 -0
- mobile_agent/netxray/packets.py +410 -0
- mobile_agent/netxray/pcapng.py +223 -0
- mobile_agent/netxray/register.py +93 -0
- mobile_agent/netxray/report.py +214 -0
- mobile_agent/netxray/store.py +48 -0
- mobile_agent/netxray/summary.py +157 -0
- mobile_agent/netxray/target.py +67 -0
- mobile_agent/netxray/tool.py +66 -0
- mobile_agent/netxray/trackers.py +194 -0
- mobile_agent/notify_triggers/__init__.py +1 -0
- mobile_agent/notify_triggers/rules.py +39 -0
- mobile_agent/notify_triggers/sources.py +315 -0
- mobile_agent/notify_triggers/watch.py +135 -0
- mobile_agent/offers.py +86 -0
- mobile_agent/orchestrate.py +215 -0
- mobile_agent/outlets/__init__.py +1 -0
- mobile_agent/outlets/connect.py +249 -0
- mobile_agent/outlets/folder.py +180 -0
- mobile_agent/outlets/hooks.py +453 -0
- mobile_agent/outlets/inbound.py +472 -0
- mobile_agent/outlets/inbound_reply.py +57 -0
- mobile_agent/outlets/inbound_routes.py +81 -0
- mobile_agent/outlets/kinds.py +308 -0
- mobile_agent/outlets/mail.py +110 -0
- mobile_agent/outlets/net.py +86 -0
- mobile_agent/outlets/notion.py +244 -0
- mobile_agent/outlets/register.py +56 -0
- mobile_agent/outlets/routes.py +135 -0
- mobile_agent/outlets/service.py +580 -0
- mobile_agent/outlets/sheets.py +169 -0
- mobile_agent/outlets/slack.py +177 -0
- mobile_agent/outlets/store.py +194 -0
- mobile_agent/outlets/vault.py +80 -0
- mobile_agent/outlets/webhook.py +316 -0
- mobile_agent/output_contract.py +141 -0
- mobile_agent/owner_presence.py +211 -0
- mobile_agent/ownership.py +219 -0
- mobile_agent/packs/__init__.py +1 -0
- mobile_agent/packs/calendar.py +243 -0
- mobile_agent/packs/context.py +68 -0
- mobile_agent/packs/core.py +757 -0
- mobile_agent/packs/front_door.py +316 -0
- mobile_agent/packs/heal.py +214 -0
- mobile_agent/packs/health.py +122 -0
- mobile_agent/packs/insights.py +76 -0
- mobile_agent/packs/instagram.py +640 -0
- mobile_agent/packs/linkedin.py +106 -0
- mobile_agent/packs/maps.py +196 -0
- mobile_agent/packs/mcp.py +149 -0
- mobile_agent/packs/messages.py +270 -0
- mobile_agent/packs/notes.py +226 -0
- mobile_agent/packs/photos.py +166 -0
- mobile_agent/packs/pins.py +47 -0
- mobile_agent/packs/reddit.py +110 -0
- mobile_agent/packs/register.py +276 -0
- mobile_agent/packs/rows.py +108 -0
- mobile_agent/packs/safari.py +143 -0
- mobile_agent/packs/settings.py +253 -0
- mobile_agent/packs/social.py +300 -0
- mobile_agent/packs/threads.py +97 -0
- mobile_agent/packs/tiktok.py +455 -0
- mobile_agent/packs/tools.py +290 -0
- mobile_agent/packs/x.py +127 -0
- mobile_agent/packs/youtube.py +199 -0
- mobile_agent/parity.py +270 -0
- mobile_agent/paths.py +99 -0
- mobile_agent/perception.py +470 -0
- mobile_agent/permissions/__init__.py +32 -0
- mobile_agent/permissions/consequence.py +535 -0
- mobile_agent/permissions/exceptions.py +99 -0
- mobile_agent/permissions/gate.py +316 -0
- mobile_agent/permissions/outside.py +316 -0
- mobile_agent/permissions/policy.py +288 -0
- mobile_agent/permissions/project_policy.py +411 -0
- mobile_agent/permissions/register.py +148 -0
- mobile_agent/permissions/rules.py +291 -0
- mobile_agent/phone_io/__init__.py +146 -0
- mobile_agent/phone_io/cli.py +427 -0
- mobile_agent/phone_io/clipboard.py +78 -0
- mobile_agent/phone_io/controls.py +78 -0
- mobile_agent/phone_io/files.py +289 -0
- mobile_agent/phone_io/handoff.py +123 -0
- mobile_agent/phone_io/icloud.py +118 -0
- mobile_agent/phone_io/install.py +188 -0
- mobile_agent/phone_io/network_capture.py +188 -0
- mobile_agent/phone_io/network_cli.py +138 -0
- mobile_agent/phone_io/network_profiles.py +138 -0
- mobile_agent/phone_io/photos.py +512 -0
- mobile_agent/phone_io/recording.py +115 -0
- mobile_agent/phone_io/secrets.py +146 -0
- mobile_agent/phone_io/transfer.py +895 -0
- mobile_agent/phone_io/tunnel.py +129 -0
- mobile_agent/phone_ready.py +91 -0
- mobile_agent/pinning.py +158 -0
- mobile_agent/plan_gate.py +807 -0
- mobile_agent/plugins/__init__.py +3 -0
- mobile_agent/plugins/install.py +163 -0
- mobile_agent/plugins/manifest.py +242 -0
- mobile_agent/plugins/register.py +15 -0
- mobile_agent/plugins/routes.py +82 -0
- mobile_agent/plugins/service.py +322 -0
- mobile_agent/plugins/skills.py +76 -0
- mobile_agent/plugins/store.py +79 -0
- mobile_agent/pool.py +285 -0
- mobile_agent/power_watch.py +275 -0
- mobile_agent/premium_model.py +22 -0
- mobile_agent/project_env.py +291 -0
- mobile_agent/project_env_cli.py +74 -0
- mobile_agent/project_env_routes.py +55 -0
- mobile_agent/projects/__init__.py +27 -0
- mobile_agent/projects/ci.py +332 -0
- mobile_agent/projects/clone.py +339 -0
- mobile_agent/projects/drafts.py +158 -0
- mobile_agent/projects/folder.py +436 -0
- mobile_agent/projects/github.py +131 -0
- mobile_agent/projects/register.py +31 -0
- mobile_agent/projects/revisions.py +253 -0
- mobile_agent/projects/routes.py +234 -0
- mobile_agent/projects/runs.py +297 -0
- mobile_agent/projects/service.py +695 -0
- mobile_agent/projects/setup.py +84 -0
- mobile_agent/projects/store.py +379 -0
- mobile_agent/projects/sync.py +380 -0
- mobile_agent/projects/workflow_files.py +270 -0
- mobile_agent/replay_core/__init__.py +26 -0
- mobile_agent/replay_core/checks.py +594 -0
- mobile_agent/replay_core/engine.py +596 -0
- mobile_agent/replay_core/heal.py +364 -0
- mobile_agent/replay_core/path.py +240 -0
- mobile_agent/replay_core/recorder.py +206 -0
- mobile_agent/replay_core/store.py +171 -0
- mobile_agent/result_blocks.py +941 -0
- mobile_agent/run.py +642 -0
- mobile_agent/run_delivery.py +123 -0
- mobile_agent/run_executor.py +200 -0
- mobile_agent/run_export.py +284 -0
- mobile_agent/run_gif.py +891 -0
- mobile_agent/runner_hints.py +86 -0
- mobile_agent/runner_renewal.py +205 -0
- mobile_agent/runtime_create.py +549 -0
- mobile_agent/runtime_driver.py +458 -0
- mobile_agent/runtime_limits.py +319 -0
- mobile_agent/runtime_queue.py +394 -0
- mobile_agent/runtime_runs.py +383 -0
- mobile_agent/runtime_status.py +181 -0
- mobile_agent/runtime_teach.py +295 -0
- mobile_agent/runtime_work.py +599 -0
- mobile_agent/screen_text.py +101 -0
- mobile_agent/secret_filter.py +113 -0
- mobile_agent/serve.py +160 -0
- mobile_agent/server.py +363 -0
- mobile_agent/service_support.py +42 -0
- mobile_agent/settle/__init__.py +1 -0
- mobile_agent/settle/predict.py +102 -0
- mobile_agent/settle/replay.py +92 -0
- mobile_agent/settle/store.py +93 -0
- mobile_agent/settle/stream.py +43 -0
- mobile_agent/setup_cli.py +225 -0
- mobile_agent/setup_errors.py +87 -0
- mobile_agent/setup_service.py +527 -0
- mobile_agent/share.py +104 -0
- mobile_agent/signing.py +184 -0
- mobile_agent/sim/__init__.py +6 -0
- mobile_agent/sim/__main__.py +26 -0
- mobile_agent/sim/api.py +952 -0
- mobile_agent/sim/apps.py +172 -0
- mobile_agent/sim/biometrics.py +84 -0
- mobile_agent/sim/cli.py +271 -0
- mobile_agent/sim/doctor.py +293 -0
- mobile_agent/sim/governor.py +90 -0
- mobile_agent/sim/holders.py +88 -0
- mobile_agent/sim/models.py +62 -0
- mobile_agent/sim/registry.py +161 -0
- mobile_agent/sim/simctl.py +269 -0
- mobile_agent/sim/wda.py +618 -0
- mobile_agent/sim/xcode.py +74 -0
- mobile_agent/skills/__init__.py +12 -0
- mobile_agent/skills/codes.py +597 -0
- mobile_agent/skills/notifications.py +281 -0
- mobile_agent/skills/open_url.py +127 -0
- mobile_agent/smart_events.py +588 -0
- mobile_agent/smart_result.py +490 -0
- mobile_agent/smart_run.py +413 -0
- mobile_agent/state.py +662 -0
- mobile_agent/states.py +217 -0
- mobile_agent/steering.py +70 -0
- mobile_agent/style.py +178 -0
- mobile_agent/supervised.py +234 -0
- mobile_agent/swift/helper_bt_hid.swift +534 -0
- mobile_agent/swift/helper_doc_text.swift +184 -0
- mobile_agent/swift/helper_draft_reply.swift +170 -0
- mobile_agent/swift/helper_map.swift +110 -0
- mobile_agent/swift/helper_mirroring.swift +1099 -0
- mobile_agent/swift/helper_mjpeg_mp4.swift +103 -0
- mobile_agent/swift/helper_pdf.swift +100 -0
- mobile_agent/swift/helper_phone_audio.swift +993 -0
- mobile_agent/swift/helper_phone_screen.swift +416 -0
- mobile_agent/swift/helper_screen_text.swift +24 -0
- mobile_agent/swift/helper_transfer.swift +246 -0
- mobile_agent/swift/ocr.swift +22 -0
- mobile_agent/task_policy.py +337 -0
- mobile_agent/team_signing/__init__.py +34 -0
- mobile_agent/team_signing/apple_ca.py +37 -0
- mobile_agent/team_signing/bundle.py +136 -0
- mobile_agent/team_signing/cli.py +208 -0
- mobile_agent/team_signing/identity.py +248 -0
- mobile_agent/team_signing/ledger.py +105 -0
- mobile_agent/team_signing/prebuilt.py +61 -0
- mobile_agent/team_signing/resign.py +256 -0
- mobile_agent/team_signing/service.py +382 -0
- mobile_agent/team_signing/tooling.py +243 -0
- mobile_agent/team_signing/writes.py +268 -0
- mobile_agent/terminal_image.py +81 -0
- mobile_agent/testkit/__init__.py +1 -0
- mobile_agent/testkit/a11y_baseline.py +132 -0
- mobile_agent/testkit/api.py +403 -0
- mobile_agent/testkit/capsule.py +400 -0
- mobile_agent/testkit/capsule_cli.py +57 -0
- mobile_agent/testkit/cli.py +948 -0
- mobile_agent/testkit/cli_arguments.py +193 -0
- mobile_agent/testkit/comparison.py +288 -0
- mobile_agent/testkit/comparison_cli.py +41 -0
- mobile_agent/testkit/discover.py +257 -0
- mobile_agent/testkit/editor.py +243 -0
- mobile_agent/testkit/execute.py +515 -0
- mobile_agent/testkit/github_checks.py +248 -0
- mobile_agent/testkit/gitref.py +66 -0
- mobile_agent/testkit/heal_review.py +176 -0
- mobile_agent/testkit/health.py +480 -0
- mobile_agent/testkit/history.py +255 -0
- mobile_agent/testkit/hosted_results.py +321 -0
- mobile_agent/testkit/input_files.py +173 -0
- mobile_agent/testkit/jobs.py +285 -0
- mobile_agent/testkit/junit_verdict.py +33 -0
- mobile_agent/testkit/maestro.py +802 -0
- mobile_agent/testkit/mcp.py +562 -0
- mobile_agent/testkit/mcp_comparison.py +88 -0
- mobile_agent/testkit/minimize.py +471 -0
- mobile_agent/testkit/minimizer_cli.py +48 -0
- mobile_agent/testkit/notify.py +212 -0
- mobile_agent/testkit/phone_video.py +191 -0
- mobile_agent/testkit/pr.py +491 -0
- mobile_agent/testkit/pr_report.py +562 -0
- mobile_agent/testkit/prbuild.py +148 -0
- mobile_agent/testkit/proof_report.py +55 -0
- mobile_agent/testkit/provenance.py +119 -0
- mobile_agent/testkit/prrun.py +244 -0
- mobile_agent/testkit/recent.py +166 -0
- mobile_agent/testkit/recipes.py +146 -0
- mobile_agent/testkit/record.py +204 -0
- mobile_agent/testkit/register.py +288 -0
- mobile_agent/testkit/reports.py +998 -0
- mobile_agent/testkit/repro.py +432 -0
- mobile_agent/testkit/scenario.py +440 -0
- mobile_agent/testkit/scenario_cli.py +37 -0
- mobile_agent/testkit/snapshots_cli.py +60 -0
- mobile_agent/testkit/suite.py +670 -0
- mobile_agent/testkit/targets.py +497 -0
- mobile_agent/testkit/xctest.py +378 -0
- mobile_agent/threads/__init__.py +1 -0
- mobile_agent/threads/chat_once.py +264 -0
- mobile_agent/threads/cli.py +740 -0
- mobile_agent/threads/client.py +326 -0
- mobile_agent/threads/context.py +246 -0
- mobile_agent/threads/mcp.py +739 -0
- mobile_agent/threads/recent.py +34 -0
- mobile_agent/threads/register.py +54 -0
- mobile_agent/threads/routes.py +188 -0
- mobile_agent/threads/service.py +975 -0
- mobile_agent/threads/store.py +361 -0
- mobile_agent/threads/summary.py +117 -0
- mobile_agent/threads/term.py +101 -0
- mobile_agent/threads/workflow_cli.py +104 -0
- mobile_agent/tls.py +36 -0
- mobile_agent/traces.py +271 -0
- mobile_agent/tracks.py +235 -0
- mobile_agent/transport.py +271 -0
- mobile_agent/triggers/__init__.py +1 -0
- mobile_agent/triggers/actions.py +204 -0
- mobile_agent/triggers/model.py +146 -0
- mobile_agent/triggers/register.py +29 -0
- mobile_agent/triggers/routes.py +101 -0
- mobile_agent/triggers/service.py +387 -0
- mobile_agent/triggers/store.py +142 -0
- mobile_agent/tui/__init__.py +89 -0
- mobile_agent/tui/app.py +582 -0
- mobile_agent/tui/chrome.py +321 -0
- mobile_agent/tui/commands.py +375 -0
- mobile_agent/tui/demo_phone.py +369 -0
- mobile_agent/tui/images.py +29 -0
- mobile_agent/tui/keys.py +64 -0
- mobile_agent/tui/prompt.py +195 -0
- mobile_agent/tui/render.py +395 -0
- mobile_agent/tui/screens.py +180 -0
- mobile_agent/tui/session.py +308 -0
- mobile_agent/tui/tasks.py +287 -0
- mobile_agent/tui/theme.py +118 -0
- mobile_agent/tui/widgets.py +272 -0
- mobile_agent/update_check.py +213 -0
- mobile_agent/usage.py +184 -0
- mobile_agent/verify/__init__.py +0 -0
- mobile_agent/verify/__main__.py +41 -0
- mobile_agent/verify/a11y.py +189 -0
- mobile_agent/verify/actions.py +290 -0
- mobile_agent/verify/assertions.py +570 -0
- mobile_agent/verify/audit.py +312 -0
- mobile_agent/verify/business.py +221 -0
- mobile_agent/verify/business_run.py +131 -0
- mobile_agent/verify/business_state.py +168 -0
- mobile_agent/verify/check_schema.py +398 -0
- mobile_agent/verify/checks.py +614 -0
- mobile_agent/verify/cli.py +423 -0
- mobile_agent/verify/conditions.py +483 -0
- mobile_agent/verify/crashes.py +321 -0
- mobile_agent/verify/device_audit.py +246 -0
- mobile_agent/verify/dialogs.py +287 -0
- mobile_agent/verify/evidence.py +705 -0
- mobile_agent/verify/fixtures.py +305 -0
- mobile_agent/verify/flow.py +213 -0
- mobile_agent/verify/l10n.py +141 -0
- mobile_agent/verify/netcerts.py +67 -0
- mobile_agent/verify/netproxy.py +356 -0
- mobile_agent/verify/netrun.py +81 -0
- mobile_agent/verify/netshim.m +28 -0
- mobile_agent/verify/netshim.py +48 -0
- mobile_agent/verify/netstubs.py +132 -0
- mobile_agent/verify/overlay.py +174 -0
- mobile_agent/verify/perf.py +239 -0
- mobile_agent/verify/proof.py +192 -0
- mobile_agent/verify/replay_admission.py +48 -0
- mobile_agent/verify/report.py +952 -0
- mobile_agent/verify/run_cleanup.py +67 -0
- mobile_agent/verify/run_links.py +48 -0
- mobile_agent/verify/run_perf.py +44 -0
- mobile_agent/verify/run_secrets.py +39 -0
- mobile_agent/verify/runner.py +976 -0
- mobile_agent/verify/runs.py +57 -0
- mobile_agent/verify/screen_coverage.py +181 -0
- mobile_agent/verify/smart.py +106 -0
- mobile_agent/verify/snapshot_run.py +114 -0
- mobile_agent/verify/snapshots.py +306 -0
- mobile_agent/verify/sound.py +335 -0
- mobile_agent/verify/source_observation.py +130 -0
- mobile_agent/verify/system_surfaces/__init__.py +7 -0
- mobile_agent/verify/system_surfaces/play.py +106 -0
- mobile_agent/verify/system_surfaces/spec.py +139 -0
- mobile_agent/verify/system_surfaces/stage.py +138 -0
- mobile_agent/verify/system_surfaces/surfaces.py +121 -0
- mobile_agent/verify/tree.py +223 -0
- mobile_agent/verify/verdict.py +377 -0
- mobile_agent/verify/wire.py +392 -0
- mobile_agent/verify/wirestore.py +176 -0
- mobile_agent/waiting/__init__.py +1 -0
- mobile_agent/waiting/contacts.py +73 -0
- mobile_agent/waiting/drafts.py +136 -0
- mobile_agent/waiting/job.py +145 -0
- mobile_agent/waiting/messages.py +174 -0
- mobile_agent/waiting/rank.py +115 -0
- mobile_agent/waiting/register.py +26 -0
- mobile_agent/watch.py +502 -0
- mobile_agent/wda/__init__.py +2 -0
- mobile_agent/wda/frame_clock.py +646 -0
- mobile_agent/wda/frame_source.py +325 -0
- mobile_agent/wda/frame_store.py +115 -0
- mobile_agent/wda/gate.py +163 -0
- mobile_agent/wda/gestures.py +291 -0
- mobile_agent/wda/guards.py +94 -0
- mobile_agent/wda/identity.py +55 -0
- mobile_agent/wda/observe.py +884 -0
- mobile_agent/wda/patches.py +856 -0
- mobile_agent/wda/point_gestures.py +150 -0
- mobile_agent/wda/source.py +32 -0
- mobile_agent/wda/system_dialogs.py +571 -0
- mobile_agent/wda/text.py +694 -0
- mobile_agent/wda/timeouts.py +77 -0
- mobile_agent/wda/video.py +505 -0
- mobile_agent/wda/watchdog.py +243 -0
- mobile_agent/wireless/__init__.py +15 -0
- mobile_agent/wireless/api.py +354 -0
- mobile_agent/wireless/cli.py +287 -0
- mobile_agent/wireless/devicectl.py +229 -0
- mobile_agent/wireless/exposure.py +33 -0
- mobile_agent/wireless/mobster-wifi-pair.c +122 -0
- mobile_agent/wireless/monitor.py +332 -0
- mobile_agent/wireless/network.py +334 -0
- mobile_agent/wireless/onboarding.py +293 -0
- mobile_agent/wireless/pair.py +124 -0
- mobile_agent/wireless/probe.py +322 -0
- mobile_agent/wireless/register.py +8 -0
- mobile_agent/wireless/relay.py +179 -0
- mobile_agent/wireless/result.py +87 -0
- mobile_agent/wireless/store.py +85 -0
- mobile_agent/wireless/switch.py +77 -0
- mobile_agent/wireless/transport.py +118 -0
- mobile_agent/wireless/words.py +81 -0
- mobile_agent/wireless/xctestrun.py +83 -0
- mobile_agent/workflow_tools.py +59 -0
- mobile_agent/workflows/__init__.py +2 -0
- mobile_agent/workflows/brief.py +201 -0
- mobile_agent/workflows/cron.py +110 -0
- mobile_agent/workflows/health.py +257 -0
- mobile_agent/workflows/history.py +126 -0
- mobile_agent/workflows/records.py +442 -0
- mobile_agent/workflows/runs.py +1000 -0
- mobile_agent/workflows/scheduler.py +134 -0
- mobile_agent/workflows/service.py +973 -0
- mobile_agent/workflows/starters.py +285 -0
- mobile_agent/workflows/triggers.py +248 -0
- mobile_agent/xray/__init__.py +1 -0
- mobile_agent/xray/app_cli.py +116 -0
- mobile_agent/xray/cli.py +21 -0
- mobile_agent/xray/crawl.py +754 -0
- mobile_agent/xray/diff.py +171 -0
- mobile_agent/xray/diff_cli.py +43 -0
- mobile_agent/xray/job.py +184 -0
- mobile_agent/xray/paywall.py +188 -0
- mobile_agent/xray/policy.py +305 -0
- mobile_agent/xray/register.py +43 -0
- mobile_agent/xray/report.py +283 -0
- mobile_agent/xray/screens.py +117 -0
- mobster_cli-0.4.3.dist-info/METADATA +93 -0
- mobster_cli-0.4.3.dist-info/RECORD +1009 -0
- mobster_cli-0.4.3.dist-info/WHEEL +5 -0
- mobster_cli-0.4.3.dist-info/entry_points.txt +3 -0
- mobster_cli-0.4.3.dist-info/licenses/LICENSE +21 -0
- mobster_cli-0.4.3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""What each app's transitions take to settle, learned from the settles themselves.
|
|
2
|
+
|
|
3
|
+
A key is (app bundle id, transition shape). A sample is the time from the end of the action's dispatch to the
|
|
4
|
+
first read of the screen that stayed (the arrival), in milliseconds. The store keeps the last WINDOW samples per
|
|
5
|
+
key and answers with their 90th percentile once it has MIN_SAMPLES. It holds numbers only: no screen text, no
|
|
6
|
+
labels. It is a file under the data folder (``settle/durations.json``), replaced atomically.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import math
|
|
11
|
+
import os
|
|
12
|
+
import threading
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
from ..paths import user_data_dir, write_text_atomic
|
|
16
|
+
|
|
17
|
+
FLAG = "MOBSTER_EXPERIMENTAL_SETTLE"
|
|
18
|
+
WINDOW = 40
|
|
19
|
+
MIN_SAMPLES = 5
|
|
20
|
+
MAX_KEYS = 256
|
|
21
|
+
# A prediction past this is not worth a blind wait: the polling cap (WDA_SETTLE_CAP_SECONDS) is near.
|
|
22
|
+
MAX_PREDICTION_MS = 1200.0
|
|
23
|
+
# Polling accepts a screen about this long (WDA_SETTLE_QUIET_SECONDS) after it arrived. A blind wait pays only when
|
|
24
|
+
# its p90 sits less than that above the typical (median) arrival; otherwise polling ends sooner on a typical settle.
|
|
25
|
+
QUIET_MS = 500.0
|
|
26
|
+
|
|
27
|
+
SHAPES = {"TAP": "tap", "DOUBLE_TAP": "tap", "LONG_PRESS": "tap", "SUBMIT": "submit", "TYPE": "type",
|
|
28
|
+
"SET_TEXT": "type", "LAUNCH_APP": "launch", "HOME": "home", "BACK": "back"}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def enabled():
|
|
32
|
+
return os.environ.get(FLAG, "").strip().casefold() in {"1", "true", "on", "yes"}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def shape_of(op):
|
|
36
|
+
"""A transition shape for an operation name: swipes by axis, the rest by kind, anything else 'other'."""
|
|
37
|
+
op = str(op or "")
|
|
38
|
+
if op.startswith("SWIPE_"):
|
|
39
|
+
return "swipe_" + ("y" if op in {"SWIPE_UP", "SWIPE_DOWN"} else "x")
|
|
40
|
+
return SHAPES.get(op, "other")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def percentile(samples, share):
|
|
44
|
+
"""Nearest rank: the smallest sample that at least ``share`` of the samples do not exceed."""
|
|
45
|
+
ordered = sorted(samples)
|
|
46
|
+
return ordered[max(0, math.ceil(share * len(ordered)) - 1)]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class SettleStore:
|
|
50
|
+
def __init__(self, path=None):
|
|
51
|
+
self.path = Path(path) if path else user_data_dir() / "settle" / "durations.json"
|
|
52
|
+
self._lock = threading.Lock()
|
|
53
|
+
self._data = self._load()
|
|
54
|
+
|
|
55
|
+
def _load(self):
|
|
56
|
+
try:
|
|
57
|
+
raw = json.loads(self.path.read_text(encoding="utf-8"))
|
|
58
|
+
return {key: [float(v) for v in values][-WINDOW:] for key, values in raw["samples"].items()
|
|
59
|
+
if isinstance(values, list)}
|
|
60
|
+
except (OSError, ValueError, KeyError, TypeError, AttributeError):
|
|
61
|
+
return {}
|
|
62
|
+
|
|
63
|
+
@staticmethod
|
|
64
|
+
def key(app, shape):
|
|
65
|
+
return f"{app}|{shape}"
|
|
66
|
+
|
|
67
|
+
def samples(self, app, shape):
|
|
68
|
+
with self._lock:
|
|
69
|
+
return list(self._data.get(self.key(app, shape), ()))
|
|
70
|
+
|
|
71
|
+
def p90(self, app, shape):
|
|
72
|
+
"""The predicted settle in ms, or None: too few samples, or too slow or too uneven to be worth a blind wait."""
|
|
73
|
+
values = self.samples(app, shape)
|
|
74
|
+
if len(values) < MIN_SAMPLES:
|
|
75
|
+
return None
|
|
76
|
+
value = percentile(values, .9)
|
|
77
|
+
return value if value <= MAX_PREDICTION_MS and value - percentile(values, .5) < QUIET_MS else None
|
|
78
|
+
|
|
79
|
+
def add(self, app, shape, ms):
|
|
80
|
+
if not app or not math.isfinite(ms) or ms < 0:
|
|
81
|
+
return
|
|
82
|
+
key = self.key(app, shape)
|
|
83
|
+
with self._lock:
|
|
84
|
+
values = self._data.pop(key, [])
|
|
85
|
+
values.append(round(float(ms), 1))
|
|
86
|
+
self._data[key] = values[-WINDOW:]
|
|
87
|
+
while len(self._data) > MAX_KEYS:
|
|
88
|
+
self._data.pop(next(iter(self._data)))
|
|
89
|
+
payload = json.dumps({"version": 1, "samples": self._data}, sort_keys=True)
|
|
90
|
+
try:
|
|
91
|
+
write_text_atomic(self.path, payload)
|
|
92
|
+
except OSError:
|
|
93
|
+
pass # A prediction is optional; a run never fails on it.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""A stream of the screen, used only to say "nothing moved", never to read it.
|
|
2
|
+
|
|
3
|
+
The accessibility read stays the observation. An observer answers one question: did the pixels stay still over a
|
|
4
|
+
window? Predictive settle (``predict.py``) asks it before it accepts a read it took after a learned wait.
|
|
5
|
+
|
|
6
|
+
* ``WdaMjpegObserver``: the FrameClock's view of WDA's MJPEG stream (``wda.video.WdaVideo``). WDA serves that
|
|
7
|
+
stream for iOS Simulators and for a phone over its own port; the FrameClock already decodes it at ~25 fps.
|
|
8
|
+
* ``PhoneScreenStream``: the phone's screen over the cable (pymobiledevice3's screen-capture service or CoreDevice).
|
|
9
|
+
A stub. Nothing in this repository has run it on a phone.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from typing import Protocol
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class StreamObserver(Protocol):
|
|
16
|
+
def still_between(self, start: float, end: float) -> bool | None:
|
|
17
|
+
"""True when no tile moved from ``start`` to ``end`` (time.monotonic seconds), False when one did, None
|
|
18
|
+
when the stream cannot say (stale, too few frames, a busy screen)."""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class WdaMjpegObserver:
|
|
22
|
+
"""The FrameClock watch of one action, as a StreamObserver."""
|
|
23
|
+
|
|
24
|
+
def __init__(self, clock, watch):
|
|
25
|
+
self.clock, self.watch = clock, watch
|
|
26
|
+
|
|
27
|
+
def still_between(self, start, end):
|
|
28
|
+
if not getattr(self.watch, "usable", False):
|
|
29
|
+
return None
|
|
30
|
+
try:
|
|
31
|
+
return bool(self.clock.quiet_between(self.watch, start, end))
|
|
32
|
+
except Exception:
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class PhoneScreenStream:
|
|
37
|
+
"""Unverified, 26 Oct 2026: written from pymobiledevice3's API surface, never run against a phone (no test
|
|
38
|
+
phone exists). It reports itself unavailable, so a caller falls back to the WDA stream or to AX polling."""
|
|
39
|
+
|
|
40
|
+
UNVERIFIED = "unverified 26 Oct 2026: no phone has run this path"
|
|
41
|
+
|
|
42
|
+
def still_between(self, start, end):
|
|
43
|
+
return None
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"""`mobster setup`: get your iPhone ready for Mobster, in the terminal, one step at a time."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
import time
|
|
6
|
+
|
|
7
|
+
STEPS = ("tools", "api_key", "phone", "wda_build", "wda_running", "live")
|
|
8
|
+
POLL = 2.0
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def render(state, paint, frame=0, width=100):
|
|
12
|
+
"""The checklist for ``state`` (SetupService.state()), as lines."""
|
|
13
|
+
from .style import SPINNER, wrap
|
|
14
|
+
steps = [step for step in state.get("steps") or () if step.get("id") in STEPS]
|
|
15
|
+
done = sum(1 for step in steps if step.get("state") == "done")
|
|
16
|
+
lines = [paint("Set up your iPhone", "bold") + paint(f"{done} of {len(steps)} done".rjust(
|
|
17
|
+
max(10, min(width, 72) - 18)), "tertiary"), ""]
|
|
18
|
+
for number, step in enumerate(steps, 1):
|
|
19
|
+
status = step.get("state")
|
|
20
|
+
glyph = {"done": paint("✓", "green"), "working": paint(SPINNER[frame % len(SPINNER)], "accent"),
|
|
21
|
+
"blocked": paint("○", "tertiary")}.get(status, paint("○", "accent"))
|
|
22
|
+
title = step.get("title") or step.get("id")
|
|
23
|
+
lines.append(f" {glyph} {number}. " + (paint(title, "tertiary") if status == "done" else
|
|
24
|
+
paint(title, "bold")))
|
|
25
|
+
detail = step.get("detail") or ""
|
|
26
|
+
if step.get("id") == "api_key" and status != "done":
|
|
27
|
+
detail = "Run `mobster login` in another terminal to add your Claude or OpenAI key."
|
|
28
|
+
if status == "blocked":
|
|
29
|
+
detail = ""
|
|
30
|
+
if detail and status != "done":
|
|
31
|
+
lines.append(paint(wrap(detail, min(width, 100) - 2, indent=7), "secondary"))
|
|
32
|
+
for command in step.get("commands") or () if status != "done" else ():
|
|
33
|
+
text = command.get("command") if isinstance(command, dict) else str(command)
|
|
34
|
+
if text:
|
|
35
|
+
lines.append(" " * 7 + paint(text, "accent"))
|
|
36
|
+
return lines
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def run(args):
|
|
40
|
+
"""Returns 0 when the phone is ready, 1 when a step failed, 3 when setup can't run here, 130 on ctrl+c."""
|
|
41
|
+
from .style import palette
|
|
42
|
+
paint = palette(sys.stdout)
|
|
43
|
+
as_json = bool(getattr(args, "json", False)) or not sys.stdout.isatty()
|
|
44
|
+
try:
|
|
45
|
+
runtime = open_runtime()
|
|
46
|
+
except Exception as error: # noqa: BLE001 -- the runtime's own sentence
|
|
47
|
+
print(f"mobster setup: {error}", file=sys.stderr)
|
|
48
|
+
return 3
|
|
49
|
+
setup = runtime.setup
|
|
50
|
+
shown = 0
|
|
51
|
+
frame = 0
|
|
52
|
+
last = None
|
|
53
|
+
try:
|
|
54
|
+
if getattr(args, "device", None):
|
|
55
|
+
choose(runtime, args.device)
|
|
56
|
+
while True:
|
|
57
|
+
state = setup.state()
|
|
58
|
+
frame += 1
|
|
59
|
+
if as_json:
|
|
60
|
+
public = {"complete": _ready(state), "steps": [{k: s.get(k) for k in ("id", "title", "state",
|
|
61
|
+
"detail")}
|
|
62
|
+
for s in state["steps"] if s["id"] in STEPS]}
|
|
63
|
+
if public != last:
|
|
64
|
+
print(json.dumps(public), flush=True)
|
|
65
|
+
last = public
|
|
66
|
+
else:
|
|
67
|
+
lines = render(state, paint, frame, _width())
|
|
68
|
+
if shown:
|
|
69
|
+
sys.stdout.write(f"\033[{shown}F\033[J")
|
|
70
|
+
sys.stdout.write("\n".join(lines) + "\n")
|
|
71
|
+
sys.stdout.flush()
|
|
72
|
+
shown = len(lines)
|
|
73
|
+
if _ready(state) and (state.get("wifi") or {}).get("state") != "pairing": # a Wi-Fi yes ends first
|
|
74
|
+
if not as_json:
|
|
75
|
+
name = (state.get("device") or {}).get("name") or "Your iPhone"
|
|
76
|
+
print("\n" + paint("✓ ", "green", "bold") + paint(f"{name} is ready.", "bold")
|
|
77
|
+
+ " Give it a first task: " + paint("mobster", "accent"))
|
|
78
|
+
return 0
|
|
79
|
+
failed = _failed(state)
|
|
80
|
+
if failed:
|
|
81
|
+
if not as_json:
|
|
82
|
+
print("\n" + paint("✗ ", "coral", "bold") + failed +
|
|
83
|
+
"\n Fix it, then run " + paint("mobster setup", "accent") + " again.")
|
|
84
|
+
return 1
|
|
85
|
+
action = _next_action(state)
|
|
86
|
+
if action is not None and not as_json:
|
|
87
|
+
shown = 0
|
|
88
|
+
if not _act(runtime, state, action, args, paint):
|
|
89
|
+
return 1
|
|
90
|
+
elif action is not None and as_json:
|
|
91
|
+
print(json.dumps({"waiting": action, "hint": _hint(state, action)}), flush=True)
|
|
92
|
+
return 1
|
|
93
|
+
time.sleep(POLL)
|
|
94
|
+
except KeyboardInterrupt:
|
|
95
|
+
print()
|
|
96
|
+
return 130
|
|
97
|
+
finally:
|
|
98
|
+
runtime.close(timeout=5)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _ready(state):
|
|
102
|
+
steps = {step["id"]: step["state"] for step in state.get("steps") or ()}
|
|
103
|
+
return all(steps.get(name) == "done" for name in ("phone", "wda_build", "wda_running", "live"))
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _failed(state):
|
|
107
|
+
build = state.get("build") or {}
|
|
108
|
+
if build.get("state") == "failed" and build.get("error"):
|
|
109
|
+
return build["error"]
|
|
110
|
+
return None
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _next_action(state):
|
|
114
|
+
steps = {step["id"]: step for step in state.get("steps") or ()}
|
|
115
|
+
build, running, live = steps.get("wda_build"), steps.get("wda_running"), steps.get("live")
|
|
116
|
+
if build and build["state"] == "todo":
|
|
117
|
+
return "build"
|
|
118
|
+
if running and running["state"] == "todo" and build and build["state"] == "done":
|
|
119
|
+
return "start"
|
|
120
|
+
if live and live["state"] == "todo":
|
|
121
|
+
return "live"
|
|
122
|
+
if (state.get("wifi") or {}).get("state") == "asking":
|
|
123
|
+
return "wifi"
|
|
124
|
+
return None
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _hint(state, action):
|
|
128
|
+
"""What a run with no terminal to ask on says instead of the question: it never takes a yes for granted."""
|
|
129
|
+
if action != "wifi":
|
|
130
|
+
return "run mobster setup on a terminal to answer"
|
|
131
|
+
name = json.dumps((state.get("device") or {}).get("name") or "your iPhone", ensure_ascii=False)
|
|
132
|
+
return (f"Wi-Fi stays off for this iPhone until you say yes: run mobster setup on a terminal to answer, or run "
|
|
133
|
+
f"mobster wifi on --device {name} with it plugged in")
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _yes(question, paint, default=True):
|
|
137
|
+
while True:
|
|
138
|
+
try:
|
|
139
|
+
answer = input(paint("? ", "accent", "bold") + question + (" [Y/n] " if default else " [y/N] ")
|
|
140
|
+
).strip().lower()
|
|
141
|
+
except EOFError:
|
|
142
|
+
return False
|
|
143
|
+
if answer == "":
|
|
144
|
+
return default
|
|
145
|
+
if answer in ("y", "yes"):
|
|
146
|
+
return True
|
|
147
|
+
if answer in ("n", "no"):
|
|
148
|
+
return False
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _act(runtime, state, action, args, paint):
|
|
152
|
+
setup = runtime.setup
|
|
153
|
+
name = (state.get("device") or {}).get("name") or "your iPhone"
|
|
154
|
+
if action == "build":
|
|
155
|
+
teams = state.get("teams") or []
|
|
156
|
+
team = getattr(args, "team", None) or (teams[0].get("id") if len(teams) == 1 else None)
|
|
157
|
+
if team is None and len(teams) > 1:
|
|
158
|
+
print("Which Apple Account signs Mobster's helper?")
|
|
159
|
+
for index, item in enumerate(teams, 1):
|
|
160
|
+
print(f" {paint(str(index), 'accent')} {item.get('label') or item.get('id')}")
|
|
161
|
+
choice = input("Choose a number: ").strip()
|
|
162
|
+
if not choice.isdigit() or not 1 <= int(choice) <= len(teams):
|
|
163
|
+
return False
|
|
164
|
+
team = teams[int(choice) - 1].get("id")
|
|
165
|
+
if team is None:
|
|
166
|
+
print("Sign in to Xcode first: open Xcode, then Xcode › Settings › Accounts, choose +, and sign in "
|
|
167
|
+
"with your Apple Account. Then run " + paint("mobster setup", "accent") + " again.")
|
|
168
|
+
return False
|
|
169
|
+
first = not (state.get("build") or {}).get("expires_at")
|
|
170
|
+
took = "The first install takes about 2 minutes." if first else "It's quicker than the first time."
|
|
171
|
+
if not _yes(f"Install Mobster's helper on {name}? Xcode signs it with your Apple Account. {took}", paint):
|
|
172
|
+
return False
|
|
173
|
+
setup.manager.start_build(team)
|
|
174
|
+
return True
|
|
175
|
+
if action == "start":
|
|
176
|
+
setup.manager.start_runner()
|
|
177
|
+
return True
|
|
178
|
+
if action == "live":
|
|
179
|
+
if not _yes("Let Mobster tap and type on your iPhone while a task runs? It asks before it sends, buys, "
|
|
180
|
+
"posts or deletes.", paint):
|
|
181
|
+
return False
|
|
182
|
+
setup.set_live(True)
|
|
183
|
+
return True
|
|
184
|
+
if action == "wifi":
|
|
185
|
+
yes = _yes(f"Use {name} over Wi-Fi when it's unplugged? Mobster turns on its Connect via network switch "
|
|
186
|
+
"over this cable, the same switch as in Xcode.", paint, default=False)
|
|
187
|
+
try:
|
|
188
|
+
setup.answer_wifi(state.get("device"), yes)
|
|
189
|
+
except LookupError:
|
|
190
|
+
pass # the question ended meanwhile: unplugged, or answered in the Mac app
|
|
191
|
+
if not yes:
|
|
192
|
+
print(f"Wi-Fi stays off for {name}. To turn it on later, plug it in and run "
|
|
193
|
+
+ paint("mobster wifi on", "accent") + ".")
|
|
194
|
+
return True
|
|
195
|
+
return True
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def choose(runtime, name):
|
|
199
|
+
state = runtime.setup.state()
|
|
200
|
+
wanted = name.casefold()
|
|
201
|
+
for device in state.get("devices") or ():
|
|
202
|
+
if wanted in {str(device.get("udid", "")).casefold(), str(device.get("name", "")).casefold()}:
|
|
203
|
+
runtime.manager.choose(device["udid"])
|
|
204
|
+
return
|
|
205
|
+
raise LookupError(f"No iPhone called {name} is plugged in.")
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def open_runtime():
|
|
209
|
+
"""The runtime `mobster serve --manage-device` runs, with no task history and the helper kept running on exit."""
|
|
210
|
+
import os
|
|
211
|
+
|
|
212
|
+
from . import server
|
|
213
|
+
from .cli_constants import DEFAULT_WDA_URL
|
|
214
|
+
from .config import app_env_file
|
|
215
|
+
from .paths import user_data_dir
|
|
216
|
+
from .tui.session import serve_config
|
|
217
|
+
config = serve_config(manage_device=True, wda_url=DEFAULT_WDA_URL, state_db=None,
|
|
218
|
+
enable_live=os.environ.get("MOBSTER_ENABLE_LIVE") == "1", data_dir=user_data_dir(),
|
|
219
|
+
env_file=app_env_file(), keep_runner=True)
|
|
220
|
+
return server.Runtime(config)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _width():
|
|
224
|
+
from .style import columns
|
|
225
|
+
return columns()
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""The setup failures people actually hit, as one line to act on and one button."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
# The failures, most specific first: a destination error can mention Developer Mode, so
|
|
6
|
+
# Developer Mode is tested before the generic "not available" wordings, and an expired
|
|
7
|
+
# Xcode sign-in is told apart from a missing team before "Pick your Apple team".
|
|
8
|
+
RULES = (
|
|
9
|
+
# iOS caps apps signed by a free Apple ID at 3 on the phone. Waiting never frees a slot; deleting one does.
|
|
10
|
+
("free_app_limit", "Delete an app you installed with Xcode from your iPhone. A free Apple Account allows 3",
|
|
11
|
+
"retry",
|
|
12
|
+
(r"maximum number of apps for free development", r"maximum number of installed apps using a free developer",
|
|
13
|
+
r"installed apps using a free (developer|development) profile")),
|
|
14
|
+
("app_id_limit",
|
|
15
|
+
"Your free Apple Account can make 10 app IDs a week. Wait a few days, or use a paid developer team",
|
|
16
|
+
"choose_team",
|
|
17
|
+
(r"maximum (number of )?app ?ids?", r"app id limit", r"may create up to \d+ app ids")),
|
|
18
|
+
("bundle_conflict", "The helper's app ID is taken by another team. Install again to give it one of your own",
|
|
19
|
+
"retry",
|
|
20
|
+
(r"cannot be registered to your development team.*not available", r"failed registering bundle identifier")),
|
|
21
|
+
# The team is chosen, but Xcode's sign-in for it lapsed: the likeliest way a renewal fails days later.
|
|
22
|
+
("xcode_signin", "Sign in again in Xcode › Settings › Accounts", "check_again",
|
|
23
|
+
(r"no account for team", r"no accounts? (with|for)\b", r"no accounts?: add a new account",
|
|
24
|
+
r"unable to log in with account", r"login details for account .* were rejected",
|
|
25
|
+
r"your session has expired")),
|
|
26
|
+
("no_team", "Choose your Apple Account", "choose_team",
|
|
27
|
+
(r"requires a development team", r"no signing certificate", r"signing certificate .* not found",
|
|
28
|
+
r"no team (was )?selected")),
|
|
29
|
+
("developer_mode", "Turn on Developer Mode: on your iPhone open Settings › Privacy & Security › Developer Mode",
|
|
30
|
+
"check_again",
|
|
31
|
+
(r"developer mode (is )?(disabled|off|not enabled)", r"enable developer mode",
|
|
32
|
+
r"developermodestatus.*false")),
|
|
33
|
+
("untrusted_developer", "Trust Mobster's helper on your iPhone: open Settings › General › VPN & Device "
|
|
34
|
+
"Management", "retry",
|
|
35
|
+
(r"not been explicitly trusted", r"developer app certificate is not trusted", r"untrusted developer",
|
|
36
|
+
r"invalid code signature", r"verify the developer app")),
|
|
37
|
+
# iOS asks for the passcode before UI automation starts unless the switch is on; unanswered, the start times out.
|
|
38
|
+
("ui_automation", "On your iPhone, turn on Settings › Developer › Enable UI Automation, and keep it unlocked",
|
|
39
|
+
"retry",
|
|
40
|
+
(r"timed out while enabling automation mode", r"failed to initialize for ui testing",
|
|
41
|
+
r"ui automation (is )?(disabled|not enabled|off)", r"hasn't enabled automation mode")),
|
|
42
|
+
# Mobster tries a build that failed this way again by itself once the phone reads unlocked (retry_locked_build).
|
|
43
|
+
("locked", "Unlock your iPhone and keep it unlocked. Mobster tries again by itself", "retry",
|
|
44
|
+
(r"device (is|was) locked", r"because the device is locked", r"could not,? be,? unlocked",
|
|
45
|
+
r"password protected \(-17\)", r"passcode (protected|is required)", r"unlock (your|the) (device|iphone)")),
|
|
46
|
+
("not_trusted", "Unlock your iPhone and tap Trust, then enter your passcode", "check_again",
|
|
47
|
+
(r"pairing dialog response pending", r"user denied pairing", r"trust this computer",
|
|
48
|
+
r"has not trusted this (computer|mac)", r"not trusted by (the )?(device|iphone)")),
|
|
49
|
+
("not_paired", "Unplug your iPhone, plug it back in and tap Trust", "check_again",
|
|
50
|
+
(r"invalid hostid", r"not paired", r"no pairing record", r"pairing (record )?(is )?(missing|invalid)",
|
|
51
|
+
r"could not (connect to lockdownd|pair)", r"lockdownd.*(-21|-3)\b")),
|
|
52
|
+
# Xcode installs what it lacks when it opens (Settings › Components for iOS): no Terminal command.
|
|
53
|
+
("xcode_components", "Open Xcode and let it finish installing: Settings › Components › iOS, then try again",
|
|
54
|
+
"retry",
|
|
55
|
+
(r"-runfirstlaunch", r"is not installed\. to use with xcode", r"download and install the platform",
|
|
56
|
+
r"required plugin failed to load", r"coresimulator is out of date", r"requires a newer version of xcode",
|
|
57
|
+
r"no ios (platform|sdk)", r"platform .* (is )?not installed")),
|
|
58
|
+
("disk_full", "Free up space on your Mac, then try again", "retry",
|
|
59
|
+
(r"no space left on device", r"disk (is )?full", r"not enough (free )?(disk )?space", r"errno 28",
|
|
60
|
+
r"out of disk space")),
|
|
61
|
+
)
|
|
62
|
+
PATTERNS = tuple((kind, fix, action, re.compile("|".join(patterns), re.I)) for kind, fix, action, patterns in RULES)
|
|
63
|
+
RAW_LIMIT = 4000
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def translate(text):
|
|
67
|
+
"""{"kind", "fix", "action", "raw"} for a failure people can act on, else None."""
|
|
68
|
+
if not isinstance(text, str) or not text.strip():
|
|
69
|
+
return None
|
|
70
|
+
for kind, fix, action, pattern in PATTERNS:
|
|
71
|
+
if pattern.search(text):
|
|
72
|
+
return {"kind": kind, "fix": fix, "action": action, "raw": raw_text(text)}
|
|
73
|
+
return None
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def raw_text(text):
|
|
77
|
+
"""The tool's own words, trimmed to the lines that say what failed (for "Details")."""
|
|
78
|
+
lines = [line.rstrip() for line in str(text).splitlines() if line.strip()]
|
|
79
|
+
errors = [line for line in lines if re.search(r"\berror\b|failed|ERROR", line)]
|
|
80
|
+
kept = errors[-12:] if errors else lines[-12:]
|
|
81
|
+
return "\n".join(kept)[-RAW_LIMIT:]
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def problem(text, fallback=None):
|
|
85
|
+
"""translate(text), or the raw text with no fix (``fix`` None) when nothing matches."""
|
|
86
|
+
return translate(text) or ({"kind": "unknown", "fix": None, "action": None, "raw": raw_text(text)}
|
|
87
|
+
if isinstance(text, str) and text.strip() else fallback)
|