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,291 @@
|
|
|
1
|
+
"""Today's rules as the permission gate reads them: a one-time code, and a change that stays on the phone. No I/O."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
import unicodedata
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
TYPE_OPS = frozenset({"TYPE", "SET_TEXT"})
|
|
8
|
+
RETURN_OPS = frozenset({"SUBMIT", "TYPE_SUBMIT"})
|
|
9
|
+
TAP_OPS = frozenset({"TAP", "LONG_PRESS", "TAP_XY"})
|
|
10
|
+
ADJUST_OPS = frozenset({"INCREMENT", "DECREMENT"})
|
|
11
|
+
SWITCH_ROLES = frozenset({"Switch", "Toggle", "CheckBox"})
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class Action:
|
|
16
|
+
"""One action as the gate sees it. ``typed``: what already waits in the screen's composer (None: unknown)."""
|
|
17
|
+
op: str
|
|
18
|
+
label: str = ""
|
|
19
|
+
role: str | None = None
|
|
20
|
+
value: str | None = None
|
|
21
|
+
app: str = ""
|
|
22
|
+
app_name: str = ""
|
|
23
|
+
text: str | None = None
|
|
24
|
+
typed: str | None = None
|
|
25
|
+
screen: str = ""
|
|
26
|
+
context: str = ""
|
|
27
|
+
goal: str = ""
|
|
28
|
+
# The field's placeholder and accessibility identifier, where an app's textContentType ("oneTimeCode") shows.
|
|
29
|
+
hint: str = ""
|
|
30
|
+
# The rows the run saw that hold the typed digits; () when none, None when it can't say (code_entry then asks).
|
|
31
|
+
origins: tuple | None = None
|
|
32
|
+
# The control's frame and the screen's elements, for the consequence signals that read the screen around it.
|
|
33
|
+
rect: tuple = ()
|
|
34
|
+
around: tuple = ()
|
|
35
|
+
# The screen was read from pixels only (iPhone Mirroring, a video and Bluetooth connection).
|
|
36
|
+
pixels: bool = False
|
|
37
|
+
# A named icon's glyph ("paper plane", "heart", "trash"), read beside its name: a glyph that commits still asks.
|
|
38
|
+
glyph: str = ""
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
_PUNCT = re.compile(r"[\"“”'‘’«»!?¡¿…]+")
|
|
42
|
+
_TAIL = re.compile(r"\s*(?:[·•|,\-–—:]\s*)?(?:[$€£¥₩₽₹]\s?\d[\d.,]*|\d[\d.,]*\s?(?:[$€£¥₩₽₹]|usd|eur|円|元|원)|"
|
|
43
|
+
r"\(\d+\)|\d+)\s*$", re.I)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def norm(text):
|
|
47
|
+
"""``text`` folded for matching: NFKC, lower case,
|
|
48
|
+
quotes and trailing prices or counts dropped, spaces collapsed."""
|
|
49
|
+
text = unicodedata.normalize("NFKC", text or "").replace(" ", " ")
|
|
50
|
+
text = " ".join(_PUNCT.sub(" ", text.casefold()).split())
|
|
51
|
+
for _ in range(2):
|
|
52
|
+
shorter = _TAIL.sub("", text).strip(" ·•|,-–—:")
|
|
53
|
+
if not shorter:
|
|
54
|
+
break
|
|
55
|
+
text = shorter
|
|
56
|
+
return text
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def words_of(label):
|
|
60
|
+
"""The words of ``label``, folded by ``norm``."""
|
|
61
|
+
return re.findall(r"[\w'’-]+", norm(label))
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
CODE_WORDS = ("verification code", "one-time code", "one time code", "one-time passcode", "one-time password", "otp",
|
|
65
|
+
"2fa", "2fa code", "two-factor code", "authentication code", "authenticator code", "login code",
|
|
66
|
+
"sign-in code", "security code sent", "sms code", "text code", "enter code", "enter the code",
|
|
67
|
+
"6-digit code", "enter the 6-digit code", "confirmation code", "código de verificación",
|
|
68
|
+
"código de verificação", "código de confirmación", "código de confirmação", "code de vérification",
|
|
69
|
+
"code de confirmation", "code à usage unique", "bestätigungscode", "verifizierungscode",
|
|
70
|
+
"sicherheitscode", "einmalcode", "codice di verifica", "codice di conferma", "verificatiecode",
|
|
71
|
+
"bevestigingscode", "verifieringskod", "bekräftelsekod", "kod weryfikacyjny", "kod sms",
|
|
72
|
+
"doğrulama kodu", "onay kodu", "код подтверждения", "код из смс", "код из sms", "одноразовый код",
|
|
73
|
+
"код підтвердження", "認証コード", "確認コード", "ワンタイムパスワード", "验证码", "驗證碼", "校验码",
|
|
74
|
+
"인증번호", "인증 번호", "인증 코드", "mã xác minh", "mã xác nhận", "mã otp", "kode verifikasi",
|
|
75
|
+
"kode otp",
|
|
76
|
+
"รหัสยืนยัน", "รหัส otp", "קוד אימות", "رمز التحقق", "رمز التأكيد", "सत्यापन कोड", "ओटीपी")
|
|
77
|
+
_CJK = re.compile(r"[-ヿ㐀-䶿一-鿿가-豈----ۿऀ-ॿ]")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _phrases(phrases):
|
|
81
|
+
"""One regex for ``phrases``: whole words in spaced scripts, substrings in scripts without spaces."""
|
|
82
|
+
spaced = sorted((p for p in phrases if not _CJK.search(p)), key=len, reverse=True)
|
|
83
|
+
other = sorted((p for p in phrases if _CJK.search(p)), key=len, reverse=True)
|
|
84
|
+
parts = []
|
|
85
|
+
if spaced:
|
|
86
|
+
parts.append(r"(?<![\w-])(?:" + "|".join(re.escape(p) for p in spaced) + r")(?![\w-])")
|
|
87
|
+
if other:
|
|
88
|
+
parts.append("(?:" + "|".join(re.escape(p) for p in other) + ")")
|
|
89
|
+
return re.compile("|".join(parts))
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
_CODE = _phrases(CODE_WORDS)
|
|
93
|
+
# A field that may ask for a code or a PIN, in any language ("Code", "Access code", "Código SMS", "PIN").
|
|
94
|
+
_CODE_FIELD = re.compile(r"(?:\b(?:code|codes|pin|otp|2fa|passcode|código|codigo|codice|kod|kode|kodu|mã)\b|код|コード|"
|
|
95
|
+
r"暗証|验证|驗證|密码|코드|인증|รหัส|קוד|رمز)", re.I)
|
|
96
|
+
# An app's own name for a one-time code field (textContentType oneTimeCode, an "otp" identifier).
|
|
97
|
+
_ONE_TIME_HINT = re.compile(r"one.?time.?code|onetimecode|\botp\b|verification.?code|sms.?code|2fa|two.?factor", re.I)
|
|
98
|
+
# A screen asking for a code without naming the field: "We sent a code to •••• 42", a two-factor title.
|
|
99
|
+
_CODE_SCREEN = re.compile(r"\b(?:sent (?:you )?(?:a|an|the|your) (?:\d+.digit )?(?:code|pin)|texted you|"
|
|
100
|
+
r"code (?:was )?sent|"
|
|
101
|
+
r"two.?factor|2.?step|two.?step|2fa|verify (?:it'?s you|your (?:identity|account|number|"
|
|
102
|
+
r"email|phone))|authentication|security code|login code|sign.?in code|enter (?:the )?code|"
|
|
103
|
+
r"check your (?:phone|email|messages|texts))\b", re.I)
|
|
104
|
+
# Fields that take digits and aren't codes: typing digits there is just typing.
|
|
105
|
+
_NOT_CODE_FIELD = re.compile(r"\b(?:quantity|qty|amount|price|total|tip|phone|mobile number|telephone|zip|postal|"
|
|
106
|
+
r"post ?code|postcode|year|age|guests?|people|adults|children|size|weight|height|count|"
|
|
107
|
+
r"number of|minutes?|hours?|days?|page|search|find|rating|score|reps|sets|calories|"
|
|
108
|
+
r"steps|distance|duration|timer|alarm)\b", re.I)
|
|
109
|
+
# A row that sends a one-time code, beyond the code words.
|
|
110
|
+
_OTP_TEXT = re.compile(r"\bis your (?:[\w.&'’-]+ ){0,3}(?:code|pin|passcode)\b|"
|
|
111
|
+
r"\byour (?:[\w.&'’-]+ ){0,3}(?:code|pin|passcode)"
|
|
112
|
+
r"(?: is)?\s*[::]?\s*[A-Z]?-?\d|"
|
|
113
|
+
r"\b(?:do not|don'?t|never) share\b|(?:^|[\s(])[A-Z]{1,3}-\d{4,8}\b|"
|
|
114
|
+
r"\bexpires? in \d+\s*(?:min|mins|minutes|m)\b|\buse \d{4,10} to\b", re.I)
|
|
115
|
+
# Controls whose value a wheel or a slider sets: a timer's minutes, a date. Never a code box.
|
|
116
|
+
_PICKER_ROLES = frozenset({"PickerWheel", "Picker", "DatePicker", "Slider", "Stepper", "SegmentedControl"})
|
|
117
|
+
_DIGITS = re.compile(r"^\s*(?:\d[\s-]?){4,10}\s*$")
|
|
118
|
+
_ONE_DIGIT = re.compile(r"^\s*\d\s*$")
|
|
119
|
+
SEARCH_WORDS = re.compile(r"\b(?:search|find|where to|look up|query|filter)\b", re.I)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def looks_like_otp(text):
|
|
123
|
+
"""Whether a row reads like a one-time code sent to the person."""
|
|
124
|
+
text = str(text or "")
|
|
125
|
+
return bool(_CODE.search(norm(text)) or _CODE_SCREEN.search(text) or _OTP_TEXT.search(text))
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def code_entry(action, text=None):
|
|
129
|
+
"""Typing or submitting a one-time code, which asks in every mode; a wheel or a slider never does."""
|
|
130
|
+
op = (action.op or "").upper()
|
|
131
|
+
if op not in TYPE_OPS and op not in RETURN_OPS:
|
|
132
|
+
return False
|
|
133
|
+
text = text if text is not None else (action.text or (action.typed if op in RETURN_OPS else None) or "")
|
|
134
|
+
if not text.strip() or action.role in _PICKER_ROLES:
|
|
135
|
+
return False
|
|
136
|
+
field = norm(f"{action.label} {action.hint}")
|
|
137
|
+
if _CODE.search(field) or _ONE_TIME_HINT.search(f"{action.label} {action.hint}"):
|
|
138
|
+
return True
|
|
139
|
+
around = f"{action.screen} {action.context}"
|
|
140
|
+
asked = bool(_CODE.search(norm(around)) or _CODE_SCREEN.search(around))
|
|
141
|
+
sent = action.origins is not None and any(looks_like_otp(row) for row in action.origins)
|
|
142
|
+
if _DIGITS.match(text):
|
|
143
|
+
if _CODE_FIELD.search(field) or asked or sent:
|
|
144
|
+
return True
|
|
145
|
+
if action.role == "SearchField" or _NOT_CODE_FIELD.search(field):
|
|
146
|
+
return False
|
|
147
|
+
return action.origins is None # digits from nowhere a code was sent: just typing; unknown: ask
|
|
148
|
+
if _ONE_DIGIT.match(text):
|
|
149
|
+
# One box of a code ("_ _ _ _ _ _"): a code screen, a code field, digits a code sent, or (unknown) a bare box.
|
|
150
|
+
return asked or sent or bool(_CODE_FIELD.search(field)) or (not field.strip() and action.origins is None)
|
|
151
|
+
return False
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
# A control's first word that changes something on the phone: a list, a note, a setting, a draft.
|
|
155
|
+
CHANGE_FIRST = frozenset({
|
|
156
|
+
"save", "add", "remove", "archive", "unarchive", "mark", "pin", "unpin", "mute", "unmute", "hide", "unhide",
|
|
157
|
+
"turn", "enable", "disable", "allow", "deny", "block", "unblock", "reset", "clear", "set", "rename", "move",
|
|
158
|
+
"favorite", "favourite", "unfavorite", "star", "unstar", "flag", "unflag", "restore", "lock", "unlock", "apply",
|
|
159
|
+
"update", "change", "create", "accept", "decline", "confirm", "submit", "done", "like", "unlike", "complete",
|
|
160
|
+
"join", "leave", "download", "upload", "install", "uninstall", "delete", "erase", "trash", "duplicate", "copy to",
|
|
161
|
+
"keep", "approve", "reject", "dismiss all", "snooze"})
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def changes(action):
|
|
165
|
+
"""The act of a change that stays on the phone, else None."""
|
|
166
|
+
op = (action.op or "").upper()
|
|
167
|
+
label = norm(action.label)
|
|
168
|
+
if op in ADJUST_OPS:
|
|
169
|
+
return "change"
|
|
170
|
+
if op in RETURN_OPS:
|
|
171
|
+
searching = action.role == "SearchField" or bool(SEARCH_WORDS.search(label))
|
|
172
|
+
return None if searching else "submit"
|
|
173
|
+
if op not in TAP_OPS:
|
|
174
|
+
return None
|
|
175
|
+
if action.role in SWITCH_ROLES:
|
|
176
|
+
return "setting"
|
|
177
|
+
words = label.split()
|
|
178
|
+
if not words:
|
|
179
|
+
return None
|
|
180
|
+
first = words[0]
|
|
181
|
+
if first in CHANGE_FIRST or " ".join(words[:2]) in CHANGE_FIRST:
|
|
182
|
+
return "save" if first == "save" else "change"
|
|
183
|
+
return None
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
# A control's first word that reacts, follows or reposts where others see it, or blocks or reports someone, -> its act.
|
|
187
|
+
OUTSIDE_FIRST = {"like": "react", "unlike": "react", "react": "react", "follow": "follow", "unfollow": "unfollow",
|
|
188
|
+
"repost": "post",
|
|
189
|
+
"retweet": "post", "reblog": "post", "block": "block", "unblock": "block", "report": "report"}
|
|
190
|
+
# Rows (not controls) whose words only say what they show: a song "Like a Prayer, Madonna" names no act.
|
|
191
|
+
CONTENT_ROLES = frozenset({"Cell", "StaticText", "Image", "Icon"})
|
|
192
|
+
ROW_WORDS = 4
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def outside_act(action):
|
|
196
|
+
"""The act of a tap that reacts, follows, reposts, blocks or reports, else None; only a first word names one."""
|
|
197
|
+
if (action.op or "").upper() not in TAP_OPS or action.role in ("TextField", "TextView", "SecureTextField",
|
|
198
|
+
"SearchField"):
|
|
199
|
+
return None
|
|
200
|
+
label = " ".join((action.label or "").split())
|
|
201
|
+
words = words_of(label)
|
|
202
|
+
if not words or words[0] not in OUTSIDE_FIRST:
|
|
203
|
+
return None
|
|
204
|
+
if action.role in CONTENT_ROLES and ("," in label or len(words) > ROW_WORDS):
|
|
205
|
+
return None
|
|
206
|
+
return OUTSIDE_FIRST[words[0]]
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
# A commit's or change's act -> the kind an allow rule remembers; an act not here is never remembered.
|
|
210
|
+
RULE_KINDS = {
|
|
211
|
+
"send_message": "send", "send": "send", "reply": "send", "comment": "comment", "post": "post", "publish": "post",
|
|
212
|
+
"tweet": "post", "react": "react", "like": "react", "follow": "follow", "subscribe": "follow",
|
|
213
|
+
"unfollow": "unfollow",
|
|
214
|
+
"unsubscribe": "unfollow", "share": "share", "call": "call", "dial": "call", "facetime": "call", "join": "join",
|
|
215
|
+
"leave": "leave", "accept": "accept", "save": "save", "archive": "archive", "setting": "setting",
|
|
216
|
+
"change": "change"}
|
|
217
|
+
# How the card and Settings › Safety name each kind: "Don't ask again for sending messages in Messages".
|
|
218
|
+
RULE_WORDS = {
|
|
219
|
+
"send": "sending messages", "comment": "comments", "post": "posting", "react": "reactions",
|
|
220
|
+
"follow": "following", "unfollow": "unfollowing", "share": "sharing", "call": "calls", "join": "joining",
|
|
221
|
+
"leave": "leaving", "accept": "accepting", "save": "saving", "archive": "archiving",
|
|
222
|
+
"setting": "switching settings",
|
|
223
|
+
"change": "changes"}
|
|
224
|
+
RULE_OP = "ACT"
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
# Words that undo something for good: never remembered, whatever kind of action they're part of.
|
|
228
|
+
DESTRUCTIVE = re.compile(r"\b(?:delete|erase|trash|remove|clear|reset|wipe|discard|destroy|deactivate|"
|
|
229
|
+
r"close (?:my |your |the )?account)\b", re.I)
|
|
230
|
+
# A price on a control or the screen ("$4.99/month", "Send $50.00", "€12", "1,200 coins").
|
|
231
|
+
PRICE = re.compile(r"(?:[$€£¥₩₽₹]\s?\d|\d[\d.,]*\s?(?:€|zł|kr|₽|円|元|원|usd|eur|gbp|coins?|gems?)\b|"
|
|
232
|
+
r"/\s?(?:mo|month|yr|year|wk|week)\b|\bper (?:month|year|week)\b|\bfree trial\b)", re.I)
|
|
233
|
+
# A screen about money: sending or moving it, paying, a balance, a checkout.
|
|
234
|
+
MONEY_WORDS = re.compile(r"\b(?:pay|payment|payments|paid|send money|request money|transfer|zelle|venmo|paypal|"
|
|
235
|
+
r"cash app|wallet|balance|bank|checkout|check out|purchase|buy|order total|subtotal|total|"
|
|
236
|
+
r"tip|donate|donation|subscription|billing|invoice|card ending|apple pay|google pay|crypto|"
|
|
237
|
+
r"bitcoin|invest|trade|deposit|withdraw)\b", re.I)
|
|
238
|
+
# Apps that span other apps (the Home Screen, iOS's own sheets): a rule there would follow the person everywhere.
|
|
239
|
+
SYSTEM_BUNDLES = frozenset({"com.apple.springboard", "com.apple.PassbookUIService", "com.apple.ios.StoreKitUIService",
|
|
240
|
+
"com.apple.AuthKitUIService", "com.apple.SafariViewService", "com.apple.sharing",
|
|
241
|
+
"com.apple.ShareSheetUI", "com.apple.InCallService", "com.apple.purplebuddy"})
|
|
242
|
+
_SYSTEM = re.compile(r"(?:UIService|ViewService|SheetUI)$")
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def money_context(action):
|
|
246
|
+
"""Whether ``action`` is near money: an amount on it or the screen, money words, or a finance or password app."""
|
|
247
|
+
from .policy import sensitive_category
|
|
248
|
+
text = " ".join(str(part or "") for part in (action.label, action.value, action.text, action.typed, action.screen,
|
|
249
|
+
action.context))
|
|
250
|
+
return bool(AMOUNT.search(text) or PRICE.search(text) or MONEY_WORDS.search(norm(text))
|
|
251
|
+
or sensitive_category(action.app, action.app_name))
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def system_app(bundle):
|
|
255
|
+
return not bundle or bundle in SYSTEM_BUNDLES or bool(_SYSTEM.search(bundle))
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def rememberable(action, act):
|
|
259
|
+
"""The kind of allow rule a "Don't ask again" may add or use for ``act`` here, or None."""
|
|
260
|
+
kind = RULE_KINDS.get((act or "").strip().casefold())
|
|
261
|
+
if kind is None or system_app(action.app) or code_entry(action):
|
|
262
|
+
return None
|
|
263
|
+
if DESTRUCTIVE.search(f"{action.label} {act or ''}") or money_context(action):
|
|
264
|
+
return None
|
|
265
|
+
return kind
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def rule_words(kind, app_name):
|
|
269
|
+
words = RULE_WORDS.get(kind, kind)
|
|
270
|
+
return f"Don’t ask again for {words} in {app_name}" if app_name else f"Don’t ask again for {words}"
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
AMOUNT = re.compile(r"(?:[$€£¥₩₽₹]\s?\d[\d,]*(?:\.\d{1,2})?|\d[\d.,]*\s?(?:€|zł|kr|₽|円|元|원|usd|eur))", re.I)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def screen_context(elements, limit=300):
|
|
277
|
+
"""The few words on a screen that say what an action there means."""
|
|
278
|
+
picked = []
|
|
279
|
+
for element in elements or ():
|
|
280
|
+
label, value = getattr(element, "label", "") or "", getattr(element, "value", "") or ""
|
|
281
|
+
text = " ".join(f"{label} {value if value != label else ''}".split())
|
|
282
|
+
if not text or getattr(element, "role", None) not in ("StaticText", "Other", "Cell", "Alert", "Sheet", "Button",
|
|
283
|
+
"Link"):
|
|
284
|
+
continue
|
|
285
|
+
folded = norm(text)
|
|
286
|
+
if AMOUNT.search(text) or element.role in ("Alert", "Sheet") or _CODE.search(folded) or any(
|
|
287
|
+
word in folded for word in ("total", "cannot be undone", "can't be undone", "permanently")):
|
|
288
|
+
picked.append(text[:80])
|
|
289
|
+
if sum(len(p) + 3 for p in picked) >= limit:
|
|
290
|
+
break
|
|
291
|
+
return " · ".join(picked)[:limit]
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"""Phone I/O outside tasks: the clipboard (clipboard.py), installing a build (install.py), files to and from an app's
|
|
2
|
+
Documents folder (files.py), Photos and files both ways by every route (transfer.py with photos.py, tunnel.py,
|
|
3
|
+
icloud.py and handoff.py), and the phone's buttons and lock (controls.py). `mobster phone` (cli.py), the MCP tools
|
|
4
|
+
set_clipboard, install_app, send_media, pull_media and press_button, and the files track (attachments/: PUT_FILE,
|
|
5
|
+
the app's "Put on iPhone…", MCP's put_file, get_file and list_files) use them.
|
|
6
|
+
|
|
7
|
+
``wda(record)`` holds the device's lease (one Mobster process at a time, as a task or an MCP session does) and
|
|
8
|
+
yields a request function in WebDriverAgent's session. These modules run outside a task, so none of them is
|
|
9
|
+
journaled; the person's own command, or the tool's own approval, is the go-ahead. None of them reads the screen to
|
|
10
|
+
decide what to do or taps an app. What acts on the phone or the Mac, and nothing more:
|
|
11
|
+
- network_capture.py (only `mobster phone network capture`) runs rvictl and tcpdump on this Mac to save a USB packet
|
|
12
|
+
trace; no task and no MCP tool reaches it. network_profiles.py only writes files.
|
|
13
|
+
- controls.py presses Home and the volume buttons, and locks the screen (it never unlocks).
|
|
14
|
+
- transfer._accept_airdrop reads an alert's text (as a match condition only) and taps Accept on an alert that says
|
|
15
|
+
AirDrop, only while Mobster's own AirDrop send runs.
|
|
16
|
+
- transfer.open_on_mirroring and handoff.mirroring_drop act through the iPhone Mirroring window: open an app with
|
|
17
|
+
Spotlight, drop files on the window.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import contextlib
|
|
21
|
+
import signal
|
|
22
|
+
import threading
|
|
23
|
+
import urllib.error
|
|
24
|
+
import urllib.request
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class PhoneIOError(Exception):
|
|
28
|
+
def __init__(self, message, code="failed", fix=""):
|
|
29
|
+
super().__init__(message)
|
|
30
|
+
self.code, self.fix = code, fix
|
|
31
|
+
|
|
32
|
+
def public(self):
|
|
33
|
+
return {"code": self.code, "message": str(self), "fix": self.fix or None}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# `mobster phone` exit codes per error code.
|
|
37
|
+
EXIT_CODES = {"usage": 2, "no_device": 3, "tools": 3, "needs_cable": 3}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def exit_code(error):
|
|
41
|
+
return EXIT_CODES.get(getattr(error, "code", ""), 1)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@contextlib.contextmanager
|
|
45
|
+
def capture_cancellation(*, defer=False):
|
|
46
|
+
"""Route termination through capture cleanup; defer a nested spawn until its handle is owned."""
|
|
47
|
+
if threading.current_thread() is not threading.main_thread():
|
|
48
|
+
yield
|
|
49
|
+
return
|
|
50
|
+
previous = {number: signal.getsignal(number) for number in (signal.SIGINT, signal.SIGTERM, signal.SIGHUP)}
|
|
51
|
+
pending = None
|
|
52
|
+
|
|
53
|
+
def cancel(number, frame):
|
|
54
|
+
nonlocal pending
|
|
55
|
+
if defer:
|
|
56
|
+
pending = number
|
|
57
|
+
return
|
|
58
|
+
# A repeated termination request must not interrupt the bounded stop already in progress.
|
|
59
|
+
for number in previous:
|
|
60
|
+
signal.signal(number, signal.SIG_IGN)
|
|
61
|
+
raise KeyboardInterrupt
|
|
62
|
+
|
|
63
|
+
try:
|
|
64
|
+
for number in previous:
|
|
65
|
+
signal.signal(number, cancel)
|
|
66
|
+
yield
|
|
67
|
+
finally:
|
|
68
|
+
for number, handler in previous.items():
|
|
69
|
+
signal.signal(number, handler)
|
|
70
|
+
if pending is not None:
|
|
71
|
+
signal.raise_signal(pending)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def choose_device(name=None, records=None):
|
|
75
|
+
"""The device ``name`` names (an id, UDID or name), else the primary iPhone, else the only device there is."""
|
|
76
|
+
from .. import devices
|
|
77
|
+
if records is None:
|
|
78
|
+
records = devices.discover(probe=False)
|
|
79
|
+
if name:
|
|
80
|
+
try:
|
|
81
|
+
return devices.resolve(records, name)
|
|
82
|
+
except LookupError as error:
|
|
83
|
+
raise PhoneIOError(str(error), "no_device") from None
|
|
84
|
+
for pick in ([r for r in records if r.get("primary")], [r for r in records if r.get("kind") == "usb"
|
|
85
|
+
and r.get("state") == "ready"], records):
|
|
86
|
+
if len(pick) == 1:
|
|
87
|
+
return pick[0]
|
|
88
|
+
if not records:
|
|
89
|
+
raise PhoneIOError("Mobster sees no device.", "no_device",
|
|
90
|
+
"Plug in an iPhone set up in the Mobster app, or prepare a simulator.")
|
|
91
|
+
raise PhoneIOError("Several devices are here: " + ", ".join(f"{r['name']} ({r['id']})" for r in records[:6])
|
|
92
|
+
+ ".", "usage", "Name one with --device.")
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class Calls:
|
|
96
|
+
def __init__(self, request):
|
|
97
|
+
self.request = request
|
|
98
|
+
|
|
99
|
+
def call(self, method, path, body=None, timeout=15):
|
|
100
|
+
return self.request(method, path, body, timeout)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def checked_request(send):
|
|
104
|
+
"""``request`` over ``send``: the answer's value, else PhoneIOError (``unknown_route`` on a 404).
|
|
105
|
+
A value with ``error`` among other keys is the runner's own answer, not a refusal."""
|
|
106
|
+
def request(method, path, body=None, timeout=15):
|
|
107
|
+
try:
|
|
108
|
+
answer = send(method, path, body, timeout)
|
|
109
|
+
except urllib.error.HTTPError as error:
|
|
110
|
+
if error.code == 404:
|
|
111
|
+
raise PhoneIOError("WebDriverAgent doesn't know that command.", "unknown_route") from None
|
|
112
|
+
raise PhoneIOError(f"WebDriverAgent didn't answer (HTTP {error.code}).", "failed",
|
|
113
|
+
"Keep the iPhone unlocked and connected, then try again.") from None
|
|
114
|
+
except Exception as error:
|
|
115
|
+
raise PhoneIOError(f"WebDriverAgent didn't answer ({type(error).__name__}).", "failed",
|
|
116
|
+
"Keep the iPhone unlocked and connected, then try again.") from None
|
|
117
|
+
value = answer.get("value") if isinstance(answer, dict) else None
|
|
118
|
+
envelope = (isinstance(value, dict) and bool(value.get("error"))
|
|
119
|
+
and set(value) <= {"error", "message", "traceback"})
|
|
120
|
+
if envelope or (isinstance(answer, dict) and answer.get("status", 0) not in (0, None)):
|
|
121
|
+
raise PhoneIOError("WebDriverAgent refused the request.", "failed",
|
|
122
|
+
"Keep the iPhone unlocked, then try again.")
|
|
123
|
+
return value
|
|
124
|
+
return request
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@contextlib.contextmanager
|
|
128
|
+
def wda(record, *, opener=None, lease=None):
|
|
129
|
+
"""Yield ``request(method, path, body=None, timeout=15)`` in the device's WDA session, holding its lease."""
|
|
130
|
+
from ..device_targets import WdaDevice
|
|
131
|
+
if not record.get("wdaUrl"):
|
|
132
|
+
raise PhoneIOError(f"“{record.get('name') or record.get('id')}” isn't set up yet.", "no_device",
|
|
133
|
+
record.get("reason") or "Set it up in the Mobster app.")
|
|
134
|
+
device = WdaDevice(record, lease=lease, opener=opener or urllib.request.urlopen)
|
|
135
|
+
try:
|
|
136
|
+
held = device.acquire()
|
|
137
|
+
except Exception as error:
|
|
138
|
+
from ..verify.actions import ActionNotDispatched
|
|
139
|
+
if type(error) is ActionNotDispatched and error.kind in ("busy", "environment"):
|
|
140
|
+
raise PhoneIOError(str(error), "device_busy", getattr(error, "fix", "")) from None
|
|
141
|
+
raise PhoneIOError(str(error), "no_device", getattr(error, "fix", "")) from None
|
|
142
|
+
try:
|
|
143
|
+
request = checked_request(device._in_session)
|
|
144
|
+
yield request
|
|
145
|
+
finally:
|
|
146
|
+
held.release()
|