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
mobile_agent/states.py
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"""The one table of states that stop Mobster, each with its words and its fix.
|
|
2
|
+
|
|
3
|
+
A row is one state and one cause: what happened in a sentence, what to do in a sentence, and the fix. Every surface that
|
|
4
|
+
names a state reads its words here: the Mac app, ``mobster mcp``'s ``status`` and ``mobster serve`` (through
|
|
5
|
+
``engine_health``), and ``mobster doctor`` and ``mobster sim doctor`` (through ``doctor``). Nothing else holds a copy.
|
|
6
|
+
``tests/test_states.py`` fails when a surface says a state in other words, or claims a row it can't produce.
|
|
7
|
+
|
|
8
|
+
The fix is one of six kinds, so a state never shows a dead end:
|
|
9
|
+
|
|
10
|
+
- ``Auto``: Mobster does it, because it touches only Mobster's own state and nothing another program is running.
|
|
11
|
+
- ``Ask``: Mobster does it after it names the process or command and the person says yes. Never without a terminal.
|
|
12
|
+
- ``Guided``: a guided flow (``mobster login``, ``mobster setup``) that asks its own questions.
|
|
13
|
+
- ``Yours``: the person does it, on the iPhone or with the cable; ``picture`` names the picture of the iPhone's screen
|
|
14
|
+
that shows the taps. Mobster notices and goes on.
|
|
15
|
+
- ``Run``: a command Mobster prints and never runs for the person (a download, opening the app).
|
|
16
|
+
- ``Wait``: Mobster is already on it, or it clears by itself.
|
|
17
|
+
|
|
18
|
+
``{phone}`` is the phone's name, or "your iPhone"; ``{Phone}`` is the same at the start of a sentence. A model's own
|
|
19
|
+
sentence (``engine_health.classify_model``) replaces a row's ``message``, never its step.
|
|
20
|
+
|
|
21
|
+
Nothing here acts on the phone. It only says what to do.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from dataclasses import dataclass
|
|
25
|
+
from typing import NoReturn, assert_never
|
|
26
|
+
|
|
27
|
+
READY = "ready"
|
|
28
|
+
WAITING_FOR_PHONE = "waiting_for_phone"
|
|
29
|
+
HELPER_DOWN = "helper_down"
|
|
30
|
+
NO_PHONE = "no_phone"
|
|
31
|
+
MODEL_UNAVAILABLE = "model_unavailable"
|
|
32
|
+
LIVE_OFF = "live_off"
|
|
33
|
+
STOPPING = "stopping"
|
|
34
|
+
# Named by whoever asks, when the process doesn't answer (engine_health.from_silence).
|
|
35
|
+
SLOW = "slow"
|
|
36
|
+
FROZEN = "frozen"
|
|
37
|
+
DOWN = "down"
|
|
38
|
+
RESTARTING = "restarting"
|
|
39
|
+
|
|
40
|
+
STATES = (READY, WAITING_FOR_PHONE, HELPER_DOWN, NO_PHONE, MODEL_UNAVAILABLE, LIVE_OFF, STOPPING,
|
|
41
|
+
SLOW, FROZEN, DOWN, RESTARTING)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# -- the fix ----------------------------------------------------------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
@dataclass(frozen=True)
|
|
47
|
+
class Auto:
|
|
48
|
+
action: str
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass(frozen=True)
|
|
52
|
+
class Ask:
|
|
53
|
+
action: str
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass(frozen=True)
|
|
57
|
+
class Guided:
|
|
58
|
+
command: str
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass(frozen=True)
|
|
62
|
+
class Yours:
|
|
63
|
+
picture: str | None = None
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass(frozen=True)
|
|
67
|
+
class Run:
|
|
68
|
+
command: str
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass(frozen=True)
|
|
72
|
+
class Wait:
|
|
73
|
+
why: str
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
Fix = Auto | Ask | Guided | Yours | Run | Wait
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def unreachable(fix) -> NoReturn:
|
|
80
|
+
assert_never(fix)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def fix_public(fix):
|
|
84
|
+
"""The fix as a client reads it: {"kind", ...}. ``action`` names what ``Auto`` and ``Ask`` run
|
|
85
|
+
(doctor_fix.ACTIONS)."""
|
|
86
|
+
match fix:
|
|
87
|
+
case Auto(action) | Ask(action):
|
|
88
|
+
return {"kind": type(fix).__name__.lower(), "action": action}
|
|
89
|
+
case Guided(command) | Run(command):
|
|
90
|
+
return {"kind": type(fix).__name__.lower(), "command": command}
|
|
91
|
+
case Yours(picture):
|
|
92
|
+
return {"kind": "yours", **({"picture": picture} if picture else {})}
|
|
93
|
+
case Wait(why):
|
|
94
|
+
return {"kind": "wait", "why": why}
|
|
95
|
+
unreachable(fix)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def how(fix):
|
|
99
|
+
"""One sentence on what Mobster does about the row, for the docs and the reports."""
|
|
100
|
+
match fix:
|
|
101
|
+
case Auto():
|
|
102
|
+
return "`mobster doctor --fix` does this for you."
|
|
103
|
+
case Ask():
|
|
104
|
+
return "`mobster doctor --fix` names what it would stop and asks you first."
|
|
105
|
+
case Guided(command):
|
|
106
|
+
return f"`{command}` walks you through it."
|
|
107
|
+
case Yours():
|
|
108
|
+
return "You do this one. Mobster notices and goes on."
|
|
109
|
+
case Run(command):
|
|
110
|
+
return f"Run `{command}`. Mobster doesn't run it for you."
|
|
111
|
+
case Wait(why):
|
|
112
|
+
return why
|
|
113
|
+
unreachable(fix)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
# -- the rows ---------------------------------------------------------------------------------------------------------
|
|
117
|
+
|
|
118
|
+
# Where a row shows today. A surface listed here is tested to produce it (tests/test_states.py).
|
|
119
|
+
ENGINE = ("app", "mcp") # engine_health: the Mac app, `mobster mcp` status, `mobster serve`
|
|
120
|
+
DOCTOR = ("cli",) # `mobster doctor` and `mobster sim doctor`
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@dataclass(frozen=True)
|
|
124
|
+
class Row:
|
|
125
|
+
state: str
|
|
126
|
+
cause: str
|
|
127
|
+
message: str
|
|
128
|
+
step: str
|
|
129
|
+
need: str | None
|
|
130
|
+
fix: Fix
|
|
131
|
+
surfaces: tuple[str, ...] = ENGINE
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
# The next step of the three a task waits on is the sentence the task's caller (MCP, Mobster Remote) passes on.
|
|
135
|
+
ROWS = (
|
|
136
|
+
Row(WAITING_FOR_PHONE, "locked", "{Phone} is locked.",
|
|
137
|
+
"Unlock {phone}: the task goes on as soon as it's unlocked.", "unlock", Yours(), ENGINE + DOCTOR),
|
|
138
|
+
Row(WAITING_FOR_PHONE, "unplugged", "{Phone} is unplugged.",
|
|
139
|
+
"Plug {phone} back into the Mac: the task goes on when it's back.", "plug_in", Yours(), ENGINE + DOCTOR),
|
|
140
|
+
Row(WAITING_FOR_PHONE, "wifi_lost", "{Phone} is out of reach over Wi-Fi.",
|
|
141
|
+
"Bring {phone} back near the Mac, or plug it in: the task goes on when it's back.", "bring_back", Yours(),
|
|
142
|
+
ENGINE + DOCTOR),
|
|
143
|
+
Row(WAITING_FOR_PHONE, "helper_restarting", "Mobster's helper on {phone} is restarting.",
|
|
144
|
+
"Keep {phone} unlocked. This takes a few seconds.", None, Wait("Mobster starts the helper again by itself.")),
|
|
145
|
+
Row(WAITING_FOR_PHONE, "developer_mode_off", "Developer Mode is off on {phone}.",
|
|
146
|
+
"Turn it on in Settings › Privacy & Security › Developer Mode, then restart {phone}.", "developer_mode",
|
|
147
|
+
Yours("developer-mode"), ENGINE + DOCTOR),
|
|
148
|
+
Row(WAITING_FOR_PHONE, "trust_needed", "{Phone} doesn't trust Mobster's helper yet.",
|
|
149
|
+
"On {phone}, open Settings › General › VPN & Device Management and trust your developer app.", "trust",
|
|
150
|
+
Yours("trust-developer-app"), ENGINE + DOCTOR),
|
|
151
|
+
Row(WAITING_FOR_PHONE, "ui_automation_off", "UI Automation is off on {phone}.",
|
|
152
|
+
"On {phone}, turn on Settings › Developer › Enable UI Automation, and keep it unlocked while the helper "
|
|
153
|
+
"starts.", "ui_automation", Yours("ui-automation"), ENGINE + DOCTOR),
|
|
154
|
+
Row(WAITING_FOR_PHONE, "not_responding", "{Phone} isn't responding.",
|
|
155
|
+
"Unlock {phone} and close Control Center or Siri if they're open.", "clear_screen", Yours()),
|
|
156
|
+
Row(WAITING_FOR_PHONE, "computer_untrusted", "{Phone} doesn't trust this Mac yet.",
|
|
157
|
+
"On {phone}, tap Trust, then enter your passcode. Mobster never enters it.", "trust_computer",
|
|
158
|
+
Yours("trust-this-computer"), DOCTOR),
|
|
159
|
+
Row(HELPER_DOWN, "exposed",
|
|
160
|
+
"Mobster stopped its helper on {phone} because it answered on the phone's network address.",
|
|
161
|
+
"Build the helper again in Devices, then start it.", None, Guided("mobster setup")),
|
|
162
|
+
Row(HELPER_DOWN, "signature_expired", "Mobster's helper on {phone} has expired.",
|
|
163
|
+
"Refresh it in Devices.", None, Auto("rebuild_helper"), ENGINE + DOCTOR),
|
|
164
|
+
Row(HELPER_DOWN, "not_built", "Mobster's helper isn't on {phone} yet.",
|
|
165
|
+
"Set it up in Devices.", None, Guided("mobster setup"), ENGINE + DOCTOR),
|
|
166
|
+
Row(HELPER_DOWN, "failing", "Mobster's helper on {phone} keeps stopping.",
|
|
167
|
+
"Unlock {phone} and check Developer Mode, then start the helper in Devices.", None, Auto("start_helper")),
|
|
168
|
+
Row(HELPER_DOWN, "stopped", "Mobster's helper on {phone} isn't running.",
|
|
169
|
+
"Start it in Devices.", None, Auto("start_helper"), ENGINE + DOCTOR),
|
|
170
|
+
Row(HELPER_DOWN, "not_answering", "Mobster's helper on {phone} isn't answering.",
|
|
171
|
+
"Check that {phone} is on and reachable, then try again.", None, Yours()),
|
|
172
|
+
Row(HELPER_DOWN, "port_taken", "Another program is using the port Mobster's helper needs on this Mac.",
|
|
173
|
+
"Quit that program, or let Mobster name it and stop it with your OK.", None, Ask("free_port"), DOCTOR),
|
|
174
|
+
Row(NO_PHONE, "none_chosen", "No iPhone is set up.", "Add one in Devices.", None, Guided("mobster setup"),
|
|
175
|
+
ENGINE + DOCTOR),
|
|
176
|
+
Row(NO_PHONE, "none_attached", "No iPhone is attached.", "Start Mobster with a device, or add one in Devices.",
|
|
177
|
+
None, Guided("mobster setup")),
|
|
178
|
+
Row(NO_PHONE, "no_runtime", "No iOS Simulator runtime is installed.",
|
|
179
|
+
"Download one with xcodebuild -downloadPlatform iOS.", None, Run("xcodebuild -downloadPlatform iOS"), DOCTOR),
|
|
180
|
+
Row(MODEL_UNAVAILABLE, "no_key", "No AI account is connected.", "Connect your AI account in Settings › Models.",
|
|
181
|
+
None, Guided("mobster login"), ENGINE + DOCTOR),
|
|
182
|
+
Row(MODEL_UNAVAILABLE, "no_credit", "Your AI account is out of credit.",
|
|
183
|
+
"Add credit at your AI account, then try again.", None, Yours()),
|
|
184
|
+
Row(MODEL_UNAVAILABLE, "key_rejected", "Your AI account didn't accept your key.",
|
|
185
|
+
"Check your key in Settings › Models.", None, Guided("mobster login")),
|
|
186
|
+
Row(MODEL_UNAVAILABLE, "network_gone", "This Mac has no network.", "Join a network, then try again.", None,
|
|
187
|
+
Yours(), DOCTOR),
|
|
188
|
+
Row(LIVE_OFF, "disabled", "Live runs are off.", "Turn them on in Settings to act on the phone.", None, Yours()),
|
|
189
|
+
Row(STOPPING, "closing", "Mobster is closing.", "Open it again when you need it.", None,
|
|
190
|
+
Wait("Mobster is closing. Open it again when you need it.")),
|
|
191
|
+
Row(SLOW, "slow_answer", "Mobster is slow to answer.", "Wait a few seconds. Nothing is lost.", None,
|
|
192
|
+
Wait("Mobster answers again by itself.")),
|
|
193
|
+
Row(FROZEN, "no_answer", "Mobster stopped responding.",
|
|
194
|
+
"Restart Mobster. A task in flight is kept in History and is not resent.", None, Ask("restart_service"),
|
|
195
|
+
ENGINE + DOCTOR),
|
|
196
|
+
Row(DOWN, "not_running", "Mobster isn't running.", "Open the Mobster app.", None, Run("open -a Mobster"),
|
|
197
|
+
ENGINE + DOCTOR),
|
|
198
|
+
Row(RESTARTING, "restarted", "Mobster restarted.", "Wait a moment while it reconnects.", None,
|
|
199
|
+
Wait("Mobster reconnects by itself.")),
|
|
200
|
+
)
|
|
201
|
+
BY_CAUSE = {row.cause: row for row in ROWS}
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def row(cause):
|
|
205
|
+
"""The row for a cause (KeyError for one the table doesn't have). Every cause belongs to one state."""
|
|
206
|
+
return BY_CAUSE[cause]
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def words(state, cause, phone=None, message=None):
|
|
210
|
+
"""(message, next_step, need) for a state and cause, with the phone's name in. ``message`` replaces the table's
|
|
211
|
+
(a model's own sentence). KeyError for a pair the table doesn't have."""
|
|
212
|
+
found = BY_CAUSE[cause]
|
|
213
|
+
if found.state != state:
|
|
214
|
+
raise KeyError((state, cause))
|
|
215
|
+
name = (phone or "").strip() or "your iPhone"
|
|
216
|
+
fields = {"phone": name, "Phone": name[:1].upper() + name[1:]}
|
|
217
|
+
return (message or found.message.format(**fields)), found.step.format(**fields), found.need
|
mobile_agent/steering.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Messages the user sends a run while it works: ``Run.steer`` queues them and the frontier drains them each turn."""
|
|
2
|
+
|
|
3
|
+
import threading
|
|
4
|
+
import time
|
|
5
|
+
import uuid
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
|
|
8
|
+
SOURCES = ("app", "tui", "cli", "mcp", "voice", "remote")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass(frozen=True)
|
|
12
|
+
class SteerMessage:
|
|
13
|
+
id: str
|
|
14
|
+
text: str
|
|
15
|
+
at: float
|
|
16
|
+
source: str
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class SteeringFull(ValueError):
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class SteeringQueue:
|
|
24
|
+
MAX_PENDING = 10
|
|
25
|
+
MAX_CHARS = 2000
|
|
26
|
+
|
|
27
|
+
def __init__(self):
|
|
28
|
+
self._lock = threading.Lock()
|
|
29
|
+
self._pending = []
|
|
30
|
+
self._closed = False
|
|
31
|
+
self.paused = threading.Event()
|
|
32
|
+
|
|
33
|
+
def put(self, text, *, source="app"):
|
|
34
|
+
if not isinstance(text, str):
|
|
35
|
+
raise ValueError("A message is text")
|
|
36
|
+
text = text.strip()
|
|
37
|
+
if not text:
|
|
38
|
+
raise ValueError("Write a message first")
|
|
39
|
+
if len(text) > self.MAX_CHARS:
|
|
40
|
+
raise ValueError(f"A message can be at most {self.MAX_CHARS:,} characters")
|
|
41
|
+
if source not in SOURCES:
|
|
42
|
+
raise ValueError("Unknown message source")
|
|
43
|
+
with self._lock:
|
|
44
|
+
if self._closed:
|
|
45
|
+
raise ValueError("This task has finished")
|
|
46
|
+
if len(self._pending) >= self.MAX_PENDING:
|
|
47
|
+
raise SteeringFull("Mobster's agent has 10 messages it hasn't read yet. Wait for it to catch up.")
|
|
48
|
+
message = SteerMessage(uuid.uuid4().hex[:12], text, time.time(), source)
|
|
49
|
+
self._pending.append(message)
|
|
50
|
+
return message
|
|
51
|
+
|
|
52
|
+
def drain(self):
|
|
53
|
+
with self._lock:
|
|
54
|
+
out, self._pending = self._pending, []
|
|
55
|
+
return out
|
|
56
|
+
|
|
57
|
+
def pending(self):
|
|
58
|
+
with self._lock:
|
|
59
|
+
return len(self._pending)
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def closed(self):
|
|
63
|
+
with self._lock:
|
|
64
|
+
return self._closed
|
|
65
|
+
|
|
66
|
+
def close(self):
|
|
67
|
+
with self._lock:
|
|
68
|
+
self._closed = True
|
|
69
|
+
out, self._pending = self._pending, []
|
|
70
|
+
return out
|
mobile_agent/style.py
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"""Colour and layout for plain terminal output: help, doctor, tables, `run`'s steps."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import time
|
|
6
|
+
|
|
7
|
+
from . import brand
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _roles(palette):
|
|
11
|
+
"""The roles terminal text takes: violet text, the second and third ink, and the three status tones."""
|
|
12
|
+
return {"accent": palette["violet-text"], "secondary": palette["ink-2"], "tertiary": palette["ink-3"],
|
|
13
|
+
"green": palette["green"], "amber": palette["amber"], "coral": palette["coral"]}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
SPINNER = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏" # braille frames for a step in progress; the terminal UI, `run` and `setup` share them
|
|
17
|
+
|
|
18
|
+
DARK, LIGHT = _roles(brand.DARK), _roles(brand.LIGHT)
|
|
19
|
+
# Older role names, kept so every caller reads the same.
|
|
20
|
+
ALIASES = {"muted": "secondary", "faint": "tertiary", "red": "coral", "dim": "tertiary"}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def xterm256(value):
|
|
24
|
+
"""The xterm-256 colour nearest ``value`` (#rrggbb): from the 6x6x6 cube or the grey ramp."""
|
|
25
|
+
r, g, b = brand.rgb(value)
|
|
26
|
+
steps = (0, 95, 135, 175, 215, 255)
|
|
27
|
+
|
|
28
|
+
def nearest(channel):
|
|
29
|
+
return min(range(6), key=lambda i: abs(steps[i] - channel))
|
|
30
|
+
cube = (nearest(r), nearest(g), nearest(b))
|
|
31
|
+
cube_rgb = tuple(steps[i] for i in cube)
|
|
32
|
+
grey = max(0, min(23, round(((r + g + b) / 3 - 8) / 10)))
|
|
33
|
+
grey_rgb = (8 + grey * 10,) * 3
|
|
34
|
+
|
|
35
|
+
def distance(other):
|
|
36
|
+
return sum((a - b) ** 2 for a, b in zip((r, g, b), other))
|
|
37
|
+
if distance(grey_rgb) < distance(cube_rgb):
|
|
38
|
+
return 232 + grey
|
|
39
|
+
return 16 + 36 * cube[0] + 6 * cube[1] + cube[2]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def truecolor():
|
|
43
|
+
return os.environ.get("COLORTERM", "").lower() in {"truecolor", "24bit"}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
_theme = None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def theme():
|
|
50
|
+
"""The theme, light or dark: $MOBSTER_THEME, else $COLORFGBG, else the terminal's answer."""
|
|
51
|
+
global _theme
|
|
52
|
+
chosen = os.environ.get("MOBSTER_THEME", "").strip().lower()
|
|
53
|
+
if chosen in {"light", "dark"}:
|
|
54
|
+
return chosen
|
|
55
|
+
if _theme is None:
|
|
56
|
+
_theme = _detect_theme()
|
|
57
|
+
return _theme
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _detect_theme():
|
|
61
|
+
colorfgbg = os.environ.get("COLORFGBG", "")
|
|
62
|
+
if colorfgbg:
|
|
63
|
+
background = colorfgbg.split(";")[-1]
|
|
64
|
+
if background.isdigit():
|
|
65
|
+
return "light" if int(background) in {7, 9, 10, 11, 12, 13, 14, 15} else "dark"
|
|
66
|
+
rgb = _query_background()
|
|
67
|
+
if rgb is None:
|
|
68
|
+
return "dark"
|
|
69
|
+
luminance = sum(weight * channel for weight, channel in zip((.2126, .7152, .0722), rgb))
|
|
70
|
+
return "light" if luminance > .5 else "dark"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _query_background(timeout=.2):
|
|
74
|
+
"""The terminal's background as (r, g, b) in 0..1, from OSC 11, or None."""
|
|
75
|
+
# tmux and screen answer for themselves, not for the terminal behind them.
|
|
76
|
+
if os.environ.get("TMUX") or os.environ.get("STY") or os.environ.get("TERM", "").startswith("screen") \
|
|
77
|
+
or os.environ.get("CI"):
|
|
78
|
+
return None
|
|
79
|
+
try:
|
|
80
|
+
import select
|
|
81
|
+
import termios
|
|
82
|
+
if not (sys.stdin.isatty() and sys.stdout.isatty()):
|
|
83
|
+
return None
|
|
84
|
+
fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY)
|
|
85
|
+
except (OSError, ImportError, ValueError, AttributeError):
|
|
86
|
+
return None
|
|
87
|
+
answer = b""
|
|
88
|
+
try:
|
|
89
|
+
old = termios.tcgetattr(fd)
|
|
90
|
+
raw = termios.tcgetattr(fd)
|
|
91
|
+
raw[3] &= ~(termios.ECHO | termios.ICANON)
|
|
92
|
+
raw[6][termios.VMIN], raw[6][termios.VTIME] = 0, 0
|
|
93
|
+
termios.tcsetattr(fd, termios.TCSANOW, raw)
|
|
94
|
+
try:
|
|
95
|
+
# Device attributes (ESC [c) follow: every terminal answers them, so one that ignores OSC 11 ends the
|
|
96
|
+
# wait at once and leaves no late reply in the shell's input.
|
|
97
|
+
os.write(fd, b"\033]11;?\033\\\033[c")
|
|
98
|
+
deadline = time.monotonic() + timeout
|
|
99
|
+
while time.monotonic() < deadline:
|
|
100
|
+
ready, _, _ = select.select([fd], [], [], max(0.0, deadline - time.monotonic()))
|
|
101
|
+
if not ready:
|
|
102
|
+
break
|
|
103
|
+
chunk = os.read(fd, 256)
|
|
104
|
+
if not chunk:
|
|
105
|
+
break
|
|
106
|
+
answer += chunk
|
|
107
|
+
if b"\033[?" in answer and answer.endswith(b"c"):
|
|
108
|
+
break # the device attributes came: any OSC 11 answer came before them
|
|
109
|
+
finally:
|
|
110
|
+
termios.tcsetattr(fd, termios.TCSAFLUSH, old)
|
|
111
|
+
except Exception: # noqa: BLE001 -- a terminal that can't be asked is a dark one
|
|
112
|
+
return None
|
|
113
|
+
finally:
|
|
114
|
+
os.close(fd)
|
|
115
|
+
import re
|
|
116
|
+
found = re.search(rb"\]11;rgba?:([0-9a-fA-F]+)/([0-9a-fA-F]+)/([0-9a-fA-F]+)", answer)
|
|
117
|
+
if not found:
|
|
118
|
+
return None
|
|
119
|
+
return tuple(int(part, 16) / (16 ** len(part) - 1) for part in found.groups())
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class Palette:
|
|
123
|
+
"""``paint(text, *roles)``: roles accent, secondary, tertiary, green, amber, coral, bold, underline."""
|
|
124
|
+
|
|
125
|
+
def __init__(self, enabled, light=None):
|
|
126
|
+
self.codes = {}
|
|
127
|
+
if not enabled:
|
|
128
|
+
return
|
|
129
|
+
values = LIGHT if (theme() == "light" if light is None else light) else DARK
|
|
130
|
+
full = truecolor()
|
|
131
|
+
for role, value in values.items():
|
|
132
|
+
r, g, b = brand.rgb(value)
|
|
133
|
+
self.codes[role] = f"38;2;{r};{g};{b}" if full else f"38;5;{xterm256(value)}"
|
|
134
|
+
self.codes.update(bold="1", text="39", underline="4")
|
|
135
|
+
for old, new in ALIASES.items():
|
|
136
|
+
self.codes[old] = self.codes[new]
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def enabled(self):
|
|
140
|
+
return bool(self.codes)
|
|
141
|
+
|
|
142
|
+
def __call__(self, text, *roles):
|
|
143
|
+
if not self.codes or not text:
|
|
144
|
+
return text
|
|
145
|
+
return "".join(f"\033[{self.codes[role]}m" for role in roles) + text + "\033[0m"
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def color_enabled(stream):
|
|
149
|
+
try:
|
|
150
|
+
tty = stream.isatty()
|
|
151
|
+
except (AttributeError, ValueError):
|
|
152
|
+
return False
|
|
153
|
+
return bool(tty) and "NO_COLOR" not in os.environ and os.environ.get("TERM") != "dumb" \
|
|
154
|
+
and os.environ.get("MOBSTER_PLAIN", "") not in {"1", "true", "yes"}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def palette(stream=None):
|
|
158
|
+
"""The palette for ``stream`` (stdout by default): colour on an interactive terminal that allows it."""
|
|
159
|
+
return Palette(color_enabled(sys.stdout if stream is None else stream))
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def columns(default=100):
|
|
163
|
+
try:
|
|
164
|
+
return int(os.environ.get("COLUMNS") or os.get_terminal_size().columns)
|
|
165
|
+
except (OSError, ValueError):
|
|
166
|
+
return default
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def wrap(text, width, indent=0, first=None):
|
|
170
|
+
"""``text`` wrapped at ``width``, with a hanging ``indent``."""
|
|
171
|
+
import re
|
|
172
|
+
import textwrap
|
|
173
|
+
first = indent if first is None else first
|
|
174
|
+
# textwrap breaks only at ASCII whitespace, so a no-break space holds a command together.
|
|
175
|
+
held = re.sub(r"\bmobster(?: -{0,2}[a-z][\w-]*){1,2}|--[a-z][\w-]* [A-Z]+\b",
|
|
176
|
+
lambda match: match[0].replace(" ", "\u00a0"), text)
|
|
177
|
+
return textwrap.fill(held, width=max(24, width), initial_indent=" " * first, subsequent_indent=" " * indent,
|
|
178
|
+
break_long_words=False, break_on_hyphens=False).replace("\u00a0", " ")
|