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,458 @@
|
|
|
1
|
+
"""Runtime's phone driving: the driver a run opens, its guards and app approvals, and what the phone shows."""
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from . import engines, harness_api, orchestrate, permissions
|
|
8
|
+
from .agent_hooks import safe_allows
|
|
9
|
+
from .api_errors import APIError
|
|
10
|
+
from .catalog import APPS, register_app_names
|
|
11
|
+
from .compose import build_target_driver
|
|
12
|
+
from .device_info import DeviceInfo
|
|
13
|
+
from .drivers import WDA, resolve_wda_session
|
|
14
|
+
from .installed_apps import apps_view
|
|
15
|
+
from .installed_apps import merge as merge_installed
|
|
16
|
+
from .lockscreen import UNLOCK_WAIT_S
|
|
17
|
+
from .transport import HTTP
|
|
18
|
+
from .wda.frame_clock import attach_frame_clock
|
|
19
|
+
from .wda.guards import DriverRejection
|
|
20
|
+
from .wda.video import VideoUnavailable as WdaVideoUnavailable
|
|
21
|
+
from .wda.video import WdaVideo
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class PhoneNotReady(RuntimeError):
|
|
25
|
+
def __init__(self, message, code="phone_locked"):
|
|
26
|
+
super().__init__(message)
|
|
27
|
+
self.code = code
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# Locked phones and overlays (Control Center, Siri's glow) hang WDA's reads 8-20 s (measured).
|
|
31
|
+
PREFLIGHT_TIMEOUT = 4
|
|
32
|
+
|
|
33
|
+
# The app opens after the person answered "Allow Mobster to use …?", and the helper may have restarted meanwhile.
|
|
34
|
+
LAUNCH_RECOVER_S = 60
|
|
35
|
+
|
|
36
|
+
# The helper went away rather than refused the launch (frontier.CONNECTION_LOST, transport.NotSent).
|
|
37
|
+
LAUNCH_LOST = ("ConnectionRefusedError", "ConnectionResetError", "RemoteDisconnected", "BrokenPipeError",
|
|
38
|
+
"ConnectionAbortedError", "StaleSession", "nothing sent")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def launch_app(driver, bundle):
|
|
42
|
+
# After a lost request, open the app again only if it isn't in front: the look settles whether the request ran.
|
|
43
|
+
try:
|
|
44
|
+
driver.call("POST", "/wda/apps/activate", {"bundleId": bundle})
|
|
45
|
+
return
|
|
46
|
+
except Exception as error:
|
|
47
|
+
recover = getattr(driver, "recover", None)
|
|
48
|
+
if not callable(recover) or not any(mark in str(error) for mark in LAUNCH_LOST):
|
|
49
|
+
raise
|
|
50
|
+
recover(timeout=LAUNCH_RECOVER_S)
|
|
51
|
+
try:
|
|
52
|
+
front = (driver.call("GET", "/wda/activeAppInfo", None, PREFLIGHT_TIMEOUT) or {}).get("bundleId")
|
|
53
|
+
except Exception:
|
|
54
|
+
front = None
|
|
55
|
+
if front != bundle:
|
|
56
|
+
driver.call("POST", "/wda/apps/activate", {"bundleId": bundle})
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def prepare_wda_phone(driver, guard=None):
|
|
60
|
+
# The guard decides in code, before any model call; Home then clears Control Center, Siri and the app switcher.
|
|
61
|
+
from .agent_hooks import safe_check
|
|
62
|
+
from .lockscreen import DetectGuard
|
|
63
|
+
verdict = safe_check(guard if guard is not None else DetectGuard(), driver, "preflight")
|
|
64
|
+
if verdict.state == "stop":
|
|
65
|
+
raise PhoneNotReady(verdict.message, verdict.code or "phone_locked")
|
|
66
|
+
try:
|
|
67
|
+
driver.call("POST", "/wda/pressButton", {"name": "home"}, PREFLIGHT_TIMEOUT)
|
|
68
|
+
except Exception:
|
|
69
|
+
raise PhoneNotReady("Your iPhone isn't responding. Unlock it, close Control Center or Siri if they're "
|
|
70
|
+
"open, then try again. It may have gone to the Home Screen; "
|
|
71
|
+
"nothing else was done.") from None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def is_scheduled(idempotency_key):
|
|
75
|
+
from .graph.dispatch import unattended
|
|
76
|
+
key = idempotency_key or ""
|
|
77
|
+
return unattended(key) or key.startswith("workflow:") and ":scheduled:" in key
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def person_started(origin, idempotency_key=None):
|
|
81
|
+
return origin in harness_api.INTERACTIVE and not is_scheduled(idempotency_key)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# A person asked for these from elsewhere: their caller sees phoneWait and tells the person what to do.
|
|
85
|
+
UNLOCK_WAIT_ORIGINS = frozenset({"mcp", "remote", "console"})
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def waits_for_unlock(origin, idempotency_key=None):
|
|
89
|
+
return (person_started(origin, idempotency_key)
|
|
90
|
+
or origin in UNLOCK_WAIT_ORIGINS and not is_scheduled(idempotency_key))
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class PhoneAppsGuard:
|
|
94
|
+
def __init__(self, inner, allowed):
|
|
95
|
+
self._inner, self._allowed = inner, frozenset(allowed)
|
|
96
|
+
|
|
97
|
+
def __getattr__(self, name):
|
|
98
|
+
return getattr(self._inner, name)
|
|
99
|
+
|
|
100
|
+
def allows_app(self, bundle_id):
|
|
101
|
+
if bundle_id not in self._allowed:
|
|
102
|
+
return False
|
|
103
|
+
inner = getattr(self._inner, "allows_app", None)
|
|
104
|
+
return bool(inner(bundle_id)) if callable(inner) else True
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@dataclass(frozen=True)
|
|
108
|
+
class RunSetup:
|
|
109
|
+
phase: object
|
|
110
|
+
hold: object
|
|
111
|
+
finish_phone: object
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class NoAwakeLease:
|
|
115
|
+
def acquire(self, owner):
|
|
116
|
+
pass
|
|
117
|
+
|
|
118
|
+
def release(self, owner):
|
|
119
|
+
pass
|
|
120
|
+
|
|
121
|
+
def close(self, timeout=5.0):
|
|
122
|
+
pass
|
|
123
|
+
|
|
124
|
+
def status(self):
|
|
125
|
+
return {"status": "unsupported", "owners": 0, "bundleId": None, "error": None}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class NoVideo:
|
|
129
|
+
closed = False
|
|
130
|
+
|
|
131
|
+
def status(self):
|
|
132
|
+
return {"status": "unavailable", "reason": "Live video source is not configured",
|
|
133
|
+
"configured": False, "viewers": 0}
|
|
134
|
+
|
|
135
|
+
def set_quality(self, *args, **kwargs):
|
|
136
|
+
pass
|
|
137
|
+
|
|
138
|
+
def subscribe(self):
|
|
139
|
+
raise WdaVideoUnavailable("Live video source is not configured")
|
|
140
|
+
|
|
141
|
+
def close(self):
|
|
142
|
+
self.closed = True
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# Restart, cancellation and failure paths rely on one closable handle per run, pooled or not.
|
|
146
|
+
class PooledLease:
|
|
147
|
+
def __init__(self, pool, owner):
|
|
148
|
+
self.pool, self.owner = pool, owner
|
|
149
|
+
|
|
150
|
+
def close(self):
|
|
151
|
+
pool, self.pool = self.pool, None
|
|
152
|
+
if pool is not None:
|
|
153
|
+
pool.release(self.owner)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def runner_restart(manager):
|
|
157
|
+
if manager is None or not callable(getattr(manager, "start_runner", None)):
|
|
158
|
+
return None
|
|
159
|
+
|
|
160
|
+
def restart():
|
|
161
|
+
if getattr(manager, "transport", None) != "usb" or getattr(manager, "runner", None) is None:
|
|
162
|
+
raise LookupError("Mobster doesn't run this phone's runner over USB now")
|
|
163
|
+
manager.start_runner()
|
|
164
|
+
return manager.runner_announced
|
|
165
|
+
return restart
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def planned_apps(run):
|
|
169
|
+
try:
|
|
170
|
+
plan = getattr(run, "plan", None)
|
|
171
|
+
if not plan and getattr(run, "longform", None):
|
|
172
|
+
plan = orchestrate.long_plan(run.longform["plan"])
|
|
173
|
+
return [app["bundleId"] for app in (plan or {}).get("apps") or ()
|
|
174
|
+
if isinstance(app, dict) and isinstance(app.get("bundleId"), str) and app["bundleId"]]
|
|
175
|
+
except Exception: # noqa: BLE001 -- the plan's apps ask when they open instead
|
|
176
|
+
return []
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class PhoneDriverMixin:
|
|
180
|
+
def phone_for(self, run):
|
|
181
|
+
phone = getattr(run, "phone", None)
|
|
182
|
+
fleet = getattr(self, "fleet", None)
|
|
183
|
+
return phone if phone is not None else fleet.primary if fleet is not None else None
|
|
184
|
+
|
|
185
|
+
def apps_for(self, phone):
|
|
186
|
+
return self.apps() if phone is None or phone.primary else phone.apps()
|
|
187
|
+
|
|
188
|
+
# Target hooks: the private package's runtime (harness_api.EngineHooks.runtime_for) overrides these.
|
|
189
|
+
def make_pool(self, config):
|
|
190
|
+
return None
|
|
191
|
+
|
|
192
|
+
def make_device_info(self, config):
|
|
193
|
+
return DeviceInfo()
|
|
194
|
+
|
|
195
|
+
def make_awake_lease(self):
|
|
196
|
+
return NoAwakeLease()
|
|
197
|
+
|
|
198
|
+
def make_video(self, config):
|
|
199
|
+
return NoVideo()
|
|
200
|
+
|
|
201
|
+
def target_status(self):
|
|
202
|
+
wda = bool(self.config.wda_url)
|
|
203
|
+
ready, health = False, None
|
|
204
|
+
if wda:
|
|
205
|
+
with self.inventory_lock:
|
|
206
|
+
if not self.wda_health_at or time.monotonic() - self.wda_health_at > 5:
|
|
207
|
+
client = None
|
|
208
|
+
try:
|
|
209
|
+
client = HTTP(self.config.wda_url)
|
|
210
|
+
response = client.request("GET", "/status", timeout=2)
|
|
211
|
+
self.wda_ready = response.get("value", {}).get("ready") is True
|
|
212
|
+
if isinstance(response.get("sessionId"), str) and response["sessionId"]:
|
|
213
|
+
self.wda_session_id = response["sessionId"]
|
|
214
|
+
except Exception:
|
|
215
|
+
self.wda_ready = False
|
|
216
|
+
finally:
|
|
217
|
+
if client:
|
|
218
|
+
client.close()
|
|
219
|
+
self.wda_health_at = time.monotonic()
|
|
220
|
+
ready = self.wda_ready
|
|
221
|
+
# /status answers even when WDA cannot reach a locked or overlaid phone.
|
|
222
|
+
health = self.manager.health_error() if self.manager is not None else None
|
|
223
|
+
if ready and health:
|
|
224
|
+
ready = False
|
|
225
|
+
return {"device": wda, "ready": ready, "health": health, "can_act": wda, "driver": "wda",
|
|
226
|
+
"screen_reading": False}
|
|
227
|
+
|
|
228
|
+
def primary_udid(self):
|
|
229
|
+
if self.manager is None:
|
|
230
|
+
return None
|
|
231
|
+
try:
|
|
232
|
+
return getattr(self.manager, "pinned", None) or self.manager.settings().get("udid")
|
|
233
|
+
except Exception:
|
|
234
|
+
return None
|
|
235
|
+
|
|
236
|
+
def app_killer(self, phone, primary):
|
|
237
|
+
from . import app_killer
|
|
238
|
+
if primary:
|
|
239
|
+
udid = self.primary_udid()
|
|
240
|
+
return app_killer.device(udid) if udid else None
|
|
241
|
+
udid = getattr(phone, "udid", None)
|
|
242
|
+
if not udid:
|
|
243
|
+
return None
|
|
244
|
+
return {"usb": app_killer.device, "simulator": app_killer.simulator}.get(getattr(phone, "kind", None),
|
|
245
|
+
lambda _: None)(udid)
|
|
246
|
+
|
|
247
|
+
def phone_guard(self, run, phone):
|
|
248
|
+
from .lockscreen import guard_for
|
|
249
|
+
primary = phone is None or phone.primary
|
|
250
|
+
udid = None
|
|
251
|
+
if primary:
|
|
252
|
+
udid = self.primary_udid()
|
|
253
|
+
elif getattr(phone, "kind", None) == "usb":
|
|
254
|
+
udid = phone.udid
|
|
255
|
+
key = run.idempotency_key or ""
|
|
256
|
+
mode = "schedule" if is_scheduled(key) else "interactive"
|
|
257
|
+
wait_s = UNLOCK_WAIT_S if waits_for_unlock(getattr(run, "origin", None), run.idempotency_key) else 0
|
|
258
|
+
return guard_for(device_id=udid, wda_url=self.config.wda_url if primary else phone.wda_url, mode=mode,
|
|
259
|
+
approve=run.request_approval, emit=run.emit, usb=bool(udid), wait_s=wait_s,
|
|
260
|
+
cancelled=run.stop.is_set)
|
|
261
|
+
|
|
262
|
+
def not_ready_message(self, status):
|
|
263
|
+
return "Your iPhone is not ready for live tasks. Try again when it is available."
|
|
264
|
+
|
|
265
|
+
def conversation_allowed(self, run):
|
|
266
|
+
# In memory, newest 256 conversations: a restart asks again, which is the safe direction.
|
|
267
|
+
thread_id = (run.extras or {}).get("threadId") if isinstance(getattr(run, "extras", None), dict) else None
|
|
268
|
+
if not isinstance(thread_id, str) or not thread_id:
|
|
269
|
+
return None
|
|
270
|
+
with self.lock:
|
|
271
|
+
allowed = self._conversation_apps.pop(thread_id, None) or set()
|
|
272
|
+
self._conversation_apps[thread_id] = allowed
|
|
273
|
+
while len(self._conversation_apps) > 256:
|
|
274
|
+
del self._conversation_apps[next(iter(self._conversation_apps))]
|
|
275
|
+
return allowed
|
|
276
|
+
|
|
277
|
+
def make_guard(self, run, phone):
|
|
278
|
+
guard = self.phone_guard(run, phone)
|
|
279
|
+
origin = getattr(run, "origin", None)
|
|
280
|
+
# Read live: switching an app off in Settings › Safety takes effect mid-run.
|
|
281
|
+
guard = permissions.PermissionGuard(guard, lambda: permissions.from_env().apps,
|
|
282
|
+
{a["bundleId"]: a["name"] for a in self.apps() if a.get("bundleId")},
|
|
283
|
+
outside=origin in permissions.policy.OUTSIDE_ORIGINS,
|
|
284
|
+
ask=run.request_approval, grants=self.permission_exceptions(),
|
|
285
|
+
conversation=self.conversation_allowed(run))
|
|
286
|
+
if isinstance(getattr(run, "phone_apps", None), frozenset):
|
|
287
|
+
guard = PhoneAppsGuard(guard, run.phone_apps)
|
|
288
|
+
return guard
|
|
289
|
+
|
|
290
|
+
def approve_start_apps(self, run, phone=None):
|
|
291
|
+
# One card before any app opens (owner, 14 Oct); None when Stop came, PhoneNotReady when one is declined.
|
|
292
|
+
try:
|
|
293
|
+
named = orchestrate.named_apps(run.goal,
|
|
294
|
+
[a for a in self.apps_for(phone) if a.get("installed") is not False])
|
|
295
|
+
except Exception: # noqa: BLE001 -- the named apps ask when they open instead
|
|
296
|
+
named = []
|
|
297
|
+
starting = ([run.app.get("bundleId")] + [pin.get("bundleId") for pin in run.pinned_apps or ()]
|
|
298
|
+
+ [app.get("bundleId") for app in named] + planned_apps(run) + sorted(run.allowed_bundles or ()))
|
|
299
|
+
request = getattr(run.guard, "request", None)
|
|
300
|
+
if not callable(request) or request([b for b in starting if b]):
|
|
301
|
+
return True
|
|
302
|
+
if run.stop.is_set():
|
|
303
|
+
return None
|
|
304
|
+
take = getattr(run.guard, "take_instruction", None)
|
|
305
|
+
instruction = take() if callable(take) else None
|
|
306
|
+
if instruction and run.engine == engines.SMART:
|
|
307
|
+
# "Say what to do instead": the task starts without those apps and the words reach the agent.
|
|
308
|
+
message = run.steering.put(instruction, source="app")
|
|
309
|
+
run.emit({"event": "user_message", "id": message.id, "text": message.text, "source": message.source})
|
|
310
|
+
declined = {b for b in starting if b and not safe_allows(run.guard, b)}
|
|
311
|
+
if run.app.get("bundleId") in declined:
|
|
312
|
+
run.start_on_home = True
|
|
313
|
+
return True
|
|
314
|
+
# Say why without a second card: the task can't start anyway.
|
|
315
|
+
refusal = getattr(run.guard, "refusal", None)
|
|
316
|
+
said = refusal([b for b in starting if b]) if callable(refusal) else None
|
|
317
|
+
raise PhoneNotReady(said or f"Mobster didn't open {run.app['name']}.", code="blocked_app")
|
|
318
|
+
|
|
319
|
+
def allows_app(self, run_id, bundle):
|
|
320
|
+
# Fails closed for an unknown run.
|
|
321
|
+
run = self.runs.get(run_id)
|
|
322
|
+
guard = getattr(run, "guard", None) if run is not None else None
|
|
323
|
+
if guard is None:
|
|
324
|
+
return bundle in (None, "", "com.apple.springboard")
|
|
325
|
+
return safe_allows(guard, bundle)
|
|
326
|
+
|
|
327
|
+
def check_app(self, app):
|
|
328
|
+
if app.get("installed") is False:
|
|
329
|
+
raise ValueError(f"{app['name']} isn't installed on your iPhone")
|
|
330
|
+
|
|
331
|
+
def verify_phone(self, phone, wda_url):
|
|
332
|
+
from .wda import identity as wda_identity
|
|
333
|
+
manager = self.manager if phone is None or phone.primary else getattr(phone, "manager", None)
|
|
334
|
+
saved = {}
|
|
335
|
+
try:
|
|
336
|
+
saved = manager.settings() if manager is not None else {}
|
|
337
|
+
except Exception: # noqa: BLE001 -- nothing saved: nothing to compare
|
|
338
|
+
pass
|
|
339
|
+
name = (getattr(phone, "name", None) if phone is not None else None) or saved.get("device_name")
|
|
340
|
+
try:
|
|
341
|
+
wda_identity.verify(wda_url, name=name, model=getattr(phone, "model", None) if phone else None)
|
|
342
|
+
except wda_identity.WrongDevice as error:
|
|
343
|
+
raise APIError(str(error), 409, "wrong_device") from None
|
|
344
|
+
|
|
345
|
+
def open_driver(self, run, trace, setup):
|
|
346
|
+
# setup.hold hands the driver to the caller, which closes it; None when the run was stopped meanwhile.
|
|
347
|
+
phone = self.phone_for(run)
|
|
348
|
+
primary = phone is None or phone.primary
|
|
349
|
+
wda_url = self.config.wda_url if primary else phone.wda_url
|
|
350
|
+
if wda_url and (phone is None or getattr(phone, "kind", "usb") == "usb"):
|
|
351
|
+
self.verify_phone(phone, wda_url)
|
|
352
|
+
with trace.span("setup.driver"):
|
|
353
|
+
session = (self.wda_session() if primary else phone.wda_session()) if wda_url else None
|
|
354
|
+
driver = setup.hold(build_target_driver(wda_url=wda_url, session=session,
|
|
355
|
+
expected_bundle=run.app["bundleId"]))
|
|
356
|
+
if isinstance(driver, WDA):
|
|
357
|
+
driver.killer = self.app_killer(phone, primary)
|
|
358
|
+
driver.runner_restart = runner_restart(self.manager if primary else getattr(phone, "manager", None))
|
|
359
|
+
state_db = getattr(self.config, "state_db", None)
|
|
360
|
+
if isinstance(driver, WDA) and state_db and WDA.overlay_hint_path is None:
|
|
361
|
+
# Kept across restarts: the first read otherwise fails for ~9 s under the Siri overlay.
|
|
362
|
+
WDA.load_overlay_hints(str(Path(state_db).parent / "wda-overlay-hints.json"))
|
|
363
|
+
video = self.video if primary else phone.video
|
|
364
|
+
if isinstance(driver, WDA) and isinstance(video, WdaVideo):
|
|
365
|
+
# Subscribing keeps the relay's MJPEG stream up; closing the driver releases it.
|
|
366
|
+
attach_frame_clock(driver, video, log_dir=Path(state_db).parent if state_db else None)
|
|
367
|
+
if run.stop.is_set():
|
|
368
|
+
return None
|
|
369
|
+
setup.phase("preflight")
|
|
370
|
+
run.guard = self.make_guard(run, phone)
|
|
371
|
+
with trace.span("setup.preflight"):
|
|
372
|
+
prepare_wda_phone(driver, run.guard)
|
|
373
|
+
if run.stop.is_set():
|
|
374
|
+
return None # Stop pressed during the check: the app stays shut.
|
|
375
|
+
if not self.approve_start_apps(run, phone):
|
|
376
|
+
return None
|
|
377
|
+
if not run.app.get("bundleId") or getattr(run, "start_on_home", False):
|
|
378
|
+
setup.phase("reading_app")
|
|
379
|
+
return driver
|
|
380
|
+
run.emit({"event": "app_launch_started", "app": run.app["name"]})
|
|
381
|
+
setup.phase("launching")
|
|
382
|
+
with trace.span("launch.activate"):
|
|
383
|
+
launch_app(driver, run.app["bundleId"])
|
|
384
|
+
run.emit({"event": "app_launch_acknowledged", "app": run.app["name"]})
|
|
385
|
+
setup.phase("reading_app")
|
|
386
|
+
return driver
|
|
387
|
+
|
|
388
|
+
def smart_client(self):
|
|
389
|
+
return engines.acquire_client(engines.smart_key())
|
|
390
|
+
|
|
391
|
+
def apps(self):
|
|
392
|
+
inventory = self.installed_apps.snapshot() if self.installed_apps else None
|
|
393
|
+
apps = merge_installed(APPS, inventory)
|
|
394
|
+
if inventory is not None:
|
|
395
|
+
register_app_names({app["bundleId"]: app["name"] for app in apps if app.get("foundOnPhone")})
|
|
396
|
+
return apps
|
|
397
|
+
|
|
398
|
+
def icon_bundles(self):
|
|
399
|
+
return {app["bundleId"] for app in self.apps() if app.get("foundOnPhone") or app.get("installed") is True}
|
|
400
|
+
|
|
401
|
+
def apps_payload(self, phone=None):
|
|
402
|
+
if phone is not None and not phone.primary:
|
|
403
|
+
installed = getattr(phone, "installed_apps", None)
|
|
404
|
+
if installed is None:
|
|
405
|
+
return {"apps": phone.apps(), "inventory": {"state": "unknown", "at": None}}
|
|
406
|
+
return apps_view(APPS, installed)
|
|
407
|
+
view = apps_view(APPS, self.installed_apps)
|
|
408
|
+
if view["inventory"]["state"] == "live":
|
|
409
|
+
register_app_names({app["bundleId"]: app["name"] for app in view["apps"] if app.get("foundOnPhone")})
|
|
410
|
+
return view
|
|
411
|
+
|
|
412
|
+
def preview(self, run, final=False):
|
|
413
|
+
# Operator-only: never fed to the agent, captured off the accessibility hot path.
|
|
414
|
+
if (not run.phone_finished and run.mode == "live" and callable(run.capture)
|
|
415
|
+
and (final or run.status in {"running", "queued"})):
|
|
416
|
+
if not run.image_lock.acquire(blocking=False):
|
|
417
|
+
return {"image": run.image, "source": run.mode, "capturedAt": run.image_captured_at}
|
|
418
|
+
try:
|
|
419
|
+
if run.phone_finished:
|
|
420
|
+
return {"image": run.image, "source": run.mode, "capturedAt": run.image_captured_at}
|
|
421
|
+
if final or time.monotonic() - run.image_at > 1:
|
|
422
|
+
try:
|
|
423
|
+
captured = run.capture(timeout=3)
|
|
424
|
+
if captured:
|
|
425
|
+
run.image = captured
|
|
426
|
+
run.image_captured_at = time.time() * 1000
|
|
427
|
+
except DriverRejection as exc:
|
|
428
|
+
if exc.code in {"app_preview_uniform", "app_preview_unavailable", "app_preview_oversized"}:
|
|
429
|
+
run.image, run.image_captured_at = None, None
|
|
430
|
+
except Exception:
|
|
431
|
+
pass # Preview failure never blocks the agent's observations.
|
|
432
|
+
run.image_at = time.monotonic()
|
|
433
|
+
finally:
|
|
434
|
+
run.image_lock.release()
|
|
435
|
+
return {"image": run.image, "source": run.mode, "capturedAt": run.image_captured_at}
|
|
436
|
+
|
|
437
|
+
def wda_session(self):
|
|
438
|
+
with self.wda_session_lock:
|
|
439
|
+
self.wda_session_id = resolve_wda_session(self.config.wda_url, preferred=self.wda_session_id)
|
|
440
|
+
return self.wda_session_id
|
|
441
|
+
|
|
442
|
+
def limitations(self, *, key, device, ready, wda, can_act=None, health=None, engine_reason=None):
|
|
443
|
+
reasons = []
|
|
444
|
+
managed = getattr(self, "setup", None) is not None
|
|
445
|
+
if not key:
|
|
446
|
+
reasons.append(engine_reason if engine_reason and engine_reason != engines.NO_SMART_KEY
|
|
447
|
+
else engines.no_key_reason(managed))
|
|
448
|
+
if not self.config.enable_live:
|
|
449
|
+
reasons.append("Live runs are off; enable them to act on the phone")
|
|
450
|
+
manager = getattr(self, "manager", None)
|
|
451
|
+
if manager is not None and manager.expired():
|
|
452
|
+
reasons.append("Mobster's helper needs a refresh: its signature expired. Refresh it in Setup")
|
|
453
|
+
if device and not ready:
|
|
454
|
+
reasons.append(health or (f"WebDriverAgent is not answering at {self.config.wda_url}" if wda
|
|
455
|
+
else "Your iPhone is currently unreachable"))
|
|
456
|
+
if not (wda or can_act):
|
|
457
|
+
reasons.append("No iPhone attached: start the agent with --manage-device or --wda-url")
|
|
458
|
+
return reasons
|