@leejungkiin/awkit 1.7.0 → 1.7.4
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.
- package/bin/awk.js +576 -84
- package/core/CLAUDE.md +1 -1
- package/core/GEMINI.md +148 -167
- package/core/GEMINI.md.bak +149 -116
- package/core/skill-runtime-manifest.json +3 -0
- package/docs/Claude Fable 5.md +3826 -0
- package/docs/android_kotlin_system_instruction.md +210 -0
- package/docs/brainstorm_ponytail_integration.md +146 -0
- package/docs/brainstorm_smart_setup.md +113 -0
- package/docs/deep-research-report (1).md +293 -0
- package/docs/history/GEMINI.v1.md +135 -0
- package/docs/history/brainstorm_antigravity_unified_architecture.v1.md +105 -0
- package/docs/history/implementation_plan.v1.md +58 -0
- package/package.json +4 -1
- package/scripts/artifact-storage.js +130 -0
- package/scripts/automation-gate.js +40 -7
- package/scripts/claude-plan.js +76 -0
- package/scripts/dependency-manager.js +210 -0
- package/scripts/exec-rtk.js +11 -5
- package/scripts/i18n-helper.js +381 -0
- package/scripts/multi-model-pipeline.js +144 -0
- package/skill-packs/mobile-ios/pack.json +4 -2
- package/skill-packs/reverse-engineering/pack.json +1 -0
- package/skills/CATALOG.md +20 -0
- package/skills/GEMINI.md +9 -1
- package/skills/TRIGGER_INDEX.md +10 -0
- package/skills/ai-music/SKILL.md +275 -0
- package/skills/android-re-analyzer/SKILL.md +238 -0
- package/skills/android-re-analyzer/references/api-extraction-patterns.md +119 -0
- package/skills/android-re-analyzer/references/call-flow-analysis.md +176 -0
- package/skills/android-re-analyzer/references/fernflower-usage.md +115 -0
- package/skills/android-re-analyzer/references/jadx-usage.md +116 -0
- package/skills/android-re-analyzer/references/setup-guide.md +221 -0
- package/skills/android-re-analyzer/scripts/check-deps.sh +129 -0
- package/skills/android-re-analyzer/scripts/decompile.sh +375 -0
- package/skills/android-re-analyzer/scripts/find-api-calls.sh +118 -0
- package/skills/android-re-analyzer/scripts/install-dep.sh +448 -0
- package/skills/animal-island-ui-style/SKILL.md +1450 -0
- package/skills/app-store-review-agent/SKILL.md +164 -0
- package/skills/app-store-review-agent/references/guidelines/README.md +154 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/ai_apps.md +37 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/all_apps.md +50 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/crypto_finance.md +31 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/games.md +31 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/health_fitness.md +31 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/kids.md +27 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/macos.md +38 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/social_ugc.md +32 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/subscription_iap.md +34 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/vpn.md +18 -0
- package/skills/app-store-review-agent/references/rules/design/minimum_functionality.md +96 -0
- package/skills/app-store-review-agent/references/rules/design/sign_in_with_apple.md +54 -0
- package/skills/app-store-review-agent/references/rules/entitlements/unused_entitlements.md +83 -0
- package/skills/app-store-review-agent/references/rules/metadata/accurate_metadata.md +54 -0
- package/skills/app-store-review-agent/references/rules/metadata/apple_trademark.md +99 -0
- package/skills/app-store-review-agent/references/rules/metadata/china_storefront.md +72 -0
- package/skills/app-store-review-agent/references/rules/metadata/competitor_terms.md +56 -0
- package/skills/app-store-review-agent/references/rules/metadata/subscription_metadata.md +81 -0
- package/skills/app-store-review-agent/references/rules/privacy/privacy_manifest.md +84 -0
- package/skills/app-store-review-agent/references/rules/privacy/unnecessary_data.md +60 -0
- package/skills/app-store-review-agent/references/rules/subscription/misleading_pricing.md +63 -0
- package/skills/app-store-review-agent/references/rules/subscription/missing_tos_pp.md +54 -0
- package/skills/awf-ponytail/SKILL.md +91 -0
- package/skills/awf-ponytail-review/SKILL.md +67 -0
- package/skills/awf-session-restore/SKILL.md +3 -3
- package/skills/brainstorm-agent/SKILL.md +11 -2
- package/skills/brainstorm-agent/templates/brief-template.md +8 -0
- package/skills/claude-planner/SKILL.md +47 -0
- package/skills/code-review/SKILL.md +87 -0
- package/skills/expo-game-development/SKILL.md +163 -0
- package/skills/flutter/LICENSE.txt +202 -0
- package/skills/flutter/SKILL.md +127 -0
- package/skills/flutter-project-creater/LICENSE.txt +202 -0
- package/skills/flutter-project-creater/SKILL.md +106 -0
- package/skills/game-developer/SKILL.md +163 -0
- package/skills/game-developer/references/ecs-patterns.md +501 -0
- package/skills/game-developer/references/multiplayer-networking.md +475 -0
- package/skills/game-developer/references/performance-optimization.md +422 -0
- package/skills/game-developer/references/unity-patterns.md +271 -0
- package/skills/game-developer/references/unreal-cpp.md +352 -0
- package/skills/generate-gui-assets/SKILL.md +305 -0
- package/skills/generate-gui-assets/agents/openai.yaml +4 -0
- package/skills/generate-gui-assets/references/catalog-schema.md +58 -0
- package/skills/generate-gui-assets/references/extraction-techniques.md +21 -0
- package/skills/generate-gui-assets/references/prompt-patterns.md +58 -0
- package/skills/generate-gui-assets/scripts/__pycache__/clean_chroma_edges.cpython-311.pyc +0 -0
- package/skills/generate-gui-assets/scripts/build_gui_contact_sheet.py +51 -0
- package/skills/generate-gui-assets/scripts/clean_chroma_edges.py +262 -0
- package/skills/generate-gui-assets/scripts/copy_approved_icons.py +64 -0
- package/skills/generate-gui-assets/scripts/prepare_gui_asset_run.py +91 -0
- package/skills/generate-gui-assets/scripts/suggest_grid_options.py +63 -0
- package/skills/generate-gui-assets/scripts/validate_gui_catalog.py +50 -0
- package/skills/godot-game-development/SKILL.md +142 -0
- package/skills/hatch-pet/LICENSE.txt +201 -0
- package/skills/hatch-pet/SKILL.md +420 -0
- package/skills/hatch-pet/agents/openai.yaml +4 -0
- package/skills/hatch-pet/references/animation-rows.md +29 -0
- package/skills/hatch-pet/references/codex-pet-contract.md +35 -0
- package/skills/hatch-pet/references/qa-rubric.md +60 -0
- package/skills/hatch-pet/scripts/__pycache__/clean_chroma_edges.cpython-311.pyc +0 -0
- package/skills/hatch-pet/scripts/clean_chroma_edges.py +262 -0
- package/skills/hatch-pet/scripts/compose_atlas.py +150 -0
- package/skills/hatch-pet/scripts/derive_running_left_from_running_right.py +143 -0
- package/skills/hatch-pet/scripts/extract_strip_frames.py +323 -0
- package/skills/hatch-pet/scripts/finalize_pet_run.py +382 -0
- package/skills/hatch-pet/scripts/generate_pet_images.py +287 -0
- package/skills/hatch-pet/scripts/inspect_frames.py +246 -0
- package/skills/hatch-pet/scripts/make_contact_sheet.py +96 -0
- package/skills/hatch-pet/scripts/package_custom_pet.py +108 -0
- package/skills/hatch-pet/scripts/pet_job_status.py +117 -0
- package/skills/hatch-pet/scripts/prepare_pet_run.py +673 -0
- package/skills/hatch-pet/scripts/queue_pet_repairs.py +172 -0
- package/skills/hatch-pet/scripts/record_imagegen_result.py +250 -0
- package/skills/hatch-pet/scripts/render_animation_videos.py +134 -0
- package/skills/hatch-pet/scripts/render_animation_videos.sh +5 -0
- package/skills/hatch-pet/scripts/validate_atlas.py +139 -0
- package/skills/i18n-orchestrator/SKILL.md +37 -0
- package/skills/ios-simulator-skill/SKILL.md +390 -0
- package/skills/ios-simulator-skill/scripts/accessibility_audit.py +300 -0
- package/skills/ios-simulator-skill/scripts/app_launcher.py +326 -0
- package/skills/ios-simulator-skill/scripts/app_state_capture.py +400 -0
- package/skills/ios-simulator-skill/scripts/appearance.py +385 -0
- package/skills/ios-simulator-skill/scripts/build_and_test.py +348 -0
- package/skills/ios-simulator-skill/scripts/clipboard.py +103 -0
- package/skills/ios-simulator-skill/scripts/common/__init__.py +61 -0
- package/skills/ios-simulator-skill/scripts/common/cache_utils.py +289 -0
- package/skills/ios-simulator-skill/scripts/common/device_utils.py +462 -0
- package/skills/ios-simulator-skill/scripts/common/env_config.py +35 -0
- package/skills/ios-simulator-skill/scripts/common/hang_pipeline.py +862 -0
- package/skills/ios-simulator-skill/scripts/common/hang_sessions.py +490 -0
- package/skills/ios-simulator-skill/scripts/common/idb_utils.py +180 -0
- package/skills/ios-simulator-skill/scripts/common/screenshot_utils.py +338 -0
- package/skills/ios-simulator-skill/scripts/container.py +668 -0
- package/skills/ios-simulator-skill/scripts/gesture.py +394 -0
- package/skills/ios-simulator-skill/scripts/hang_watcher.py +1533 -0
- package/skills/ios-simulator-skill/scripts/keyboard.py +391 -0
- package/skills/ios-simulator-skill/scripts/localization_audit.py +483 -0
- package/skills/ios-simulator-skill/scripts/location.py +467 -0
- package/skills/ios-simulator-skill/scripts/log_monitor.py +493 -0
- package/skills/ios-simulator-skill/scripts/model_inspector.py +645 -0
- package/skills/ios-simulator-skill/scripts/navigator.py +461 -0
- package/skills/ios-simulator-skill/scripts/privacy_manager.py +310 -0
- package/skills/ios-simulator-skill/scripts/push_notification.py +240 -0
- package/skills/ios-simulator-skill/scripts/screen_mapper.py +296 -0
- package/skills/ios-simulator-skill/scripts/sim_health_check.sh +245 -0
- package/skills/ios-simulator-skill/scripts/sim_list.py +299 -0
- package/skills/ios-simulator-skill/scripts/simctl_boot.py +312 -0
- package/skills/ios-simulator-skill/scripts/simctl_create.py +316 -0
- package/skills/ios-simulator-skill/scripts/simctl_delete.py +357 -0
- package/skills/ios-simulator-skill/scripts/simctl_erase.py +351 -0
- package/skills/ios-simulator-skill/scripts/simctl_shutdown.py +290 -0
- package/skills/ios-simulator-skill/scripts/simulator_selector.py +375 -0
- package/skills/ios-simulator-skill/scripts/status_bar.py +250 -0
- package/skills/ios-simulator-skill/scripts/test_recorder.py +323 -0
- package/skills/ios-simulator-skill/scripts/visual_diff.py +235 -0
- package/skills/ios-simulator-skill/scripts/xcode/__init__.py +13 -0
- package/skills/ios-simulator-skill/scripts/xcode/builder.py +397 -0
- package/skills/ios-simulator-skill/scripts/xcode/cache.py +204 -0
- package/skills/ios-simulator-skill/scripts/xcode/config.py +178 -0
- package/skills/ios-simulator-skill/scripts/xcode/reporter.py +343 -0
- package/skills/ios-simulator-skill/scripts/xcode/xcresult.py +451 -0
- package/skills/ios-visual-qa-strategist/SKILL.md +111 -0
- package/skills/ios-visual-qa-strategist/agents/openai.yaml +4 -0
- package/skills/ios-visual-qa-strategist/references/ios-tool-selection.md +61 -0
- package/skills/ios-visual-qa-strategist/references/minimal-capture-policy.md +56 -0
- package/skills/ios-visual-qa-strategist/references/visual-reasoning-heuristics.md +53 -0
- package/skills/orchestrator/SKILL.md +0 -20
- package/skills/persistent-storage/SKILL.md +55 -0
- package/skills/short-maker/SKILL.md +23 -0
- package/skills/short-maker/scripts/effects.js +56 -0
- package/skills/short-maker/scripts/shortmaker-bridge.js +332 -0
- package/skills/short-maker/scripts/videomix.js +601 -0
- package/skills/short-maker/templates/hyperframes/cinematic-character.template.html +172 -0
- package/skills/short-maker/templates/hyperframes/index.template.html +194 -0
- package/skills/smali-to-kotlin/SKILL.md +128 -0
- package/skills/smali-to-kotlin/examples/getting-started/tech-stack.md +58 -0
- package/skills/smali-to-kotlin/examples/pipeline/data-ui-parity.md +118 -0
- package/skills/smali-to-kotlin/examples/pipeline/scanner-and-bootstrap.md +106 -0
- package/skills/smali-to-kotlin/library-patterns.md +189 -0
- package/skills/smali-to-kotlin/phase-0-discovery.md +128 -0
- package/skills/smali-to-kotlin/phase-1-architecture.md +166 -0
- package/skills/smali-to-kotlin/phase-2-blueprint-ui.md +347 -0
- package/skills/smali-to-kotlin/phase-2-blueprint.md +228 -0
- package/skills/smali-to-kotlin/phase-3-build.md +248 -0
- package/skills/smali-to-kotlin/phase-3-logic-build.md +268 -0
- package/skills/smali-to-kotlin/smali-reading-guide.md +310 -0
- package/skills/smali-to-kotlin/templates/app-map.md +101 -0
- package/skills/smali-to-kotlin/templates/architecture.md +142 -0
- package/skills/smali-to-kotlin/templates/blueprint.md +145 -0
- package/skills/spec-gate/SKILL.md +6 -2
- package/skills/symphony-enforcer/SKILL.md +8 -0
- package/skills/symphony-enforcer/examples/mindful-stop.md +2 -0
- package/skills/symphony-enforcer/examples/three-phase.md +16 -0
- package/skills/symphony-enforcer/examples/trigger-points.md +7 -1
- package/skills/unity-game-development/SKILL.md +231 -0
- package/skills/verification-gate/SKILL.md +4 -2
- package/skills/video-edit/SKILL.md +36 -0
- package/skills/video-edit/scripts/video_edit.py +324 -0
- package/templates/setup-mapping.json +48 -0
- package/templates/specs/design-template.md +161 -71
- package/templates/specs/requirements-template.md +65 -133
- package/templates/specs/task-spec-template.xml +3 -0
- package/workflows/_uncategorized/critic.md +40 -0
- package/workflows/_uncategorized/git-rebase-flow.md +81 -0
- package/workflows/_uncategorized/image-gen.md +118 -0
- package/workflows/_uncategorized/multi-model-pipeline.md +60 -0
- package/workflows/_uncategorized/pixel-gen.md +86 -0
- package/workflows/_uncategorized/pixel-setup.md +90 -0
- package/workflows/_uncategorized/ponytail-review.md +59 -0
- package/workflows/_uncategorized/reverse-android-build.md +222 -0
- package/workflows/_uncategorized/reverse-android-design.md +139 -0
- package/workflows/_uncategorized/reverse-android-discover.md +150 -0
- package/workflows/_uncategorized/reverse-android-scan.md +158 -0
- package/workflows/_uncategorized/reverse-android.md +143 -0
- package/workflows/_uncategorized/reverse-ios-build.md +240 -0
- package/workflows/_uncategorized/reverse-ios-design.md +112 -0
- package/workflows/_uncategorized/reverse-ios-discover.md +120 -0
- package/workflows/_uncategorized/reverse-ios-scan.md +155 -0
- package/workflows/_uncategorized/reverse-ios.md +152 -0
- package/workflows/_uncategorized/safety-router.md +34 -0
- package/workflows/_uncategorized/teach.md +89 -0
- package/workflows/_uncategorized/verify-ui.md +53 -0
- package/workflows/_uncategorized/visualize-screenshots.md +34 -0
- package/workflows/ads/ads-analyst.md +201 -0
- package/workflows/ads/ads-audit.md +106 -0
- package/workflows/ads/ads-optimize.md +97 -0
- package/workflows/ads/ads-targeting.md +241 -0
- package/workflows/ads/adsExpert.md +160 -0
- package/workflows/ads/smali-ads-config.md +400 -0
- package/workflows/ads/smali-ads-flow.md +331 -0
- package/workflows/ads/smali-ads-interstitial.md +377 -0
- package/workflows/ads/smali-ads-native.md +382 -0
- package/workflows/context/teach.md +89 -0
- package/workflows/gitnexus.md +8 -8
- package/workflows/lifecycle/brainstorm.md +43 -0
- package/workflows/lifecycle/code.md +5 -0
- package/workflows/lifecycle/init.md +23 -5
- package/workflows/lifecycle/multi-model-pipeline.md +60 -0
- package/workflows/quality/ponytail-review.md +59 -0
- package/workflows/roles/critic.md +40 -0
- package/workflows/roles/safety-router.md +34 -0
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Intelligent Simulator Selector
|
|
4
|
+
|
|
5
|
+
Suggests the best available iOS simulators based on:
|
|
6
|
+
- Recently used (from config)
|
|
7
|
+
- Latest iOS version
|
|
8
|
+
- Common models for testing
|
|
9
|
+
- Boot status
|
|
10
|
+
|
|
11
|
+
Usage Examples:
|
|
12
|
+
# Get suggestions for user selection
|
|
13
|
+
python scripts/simulator_selector.py --suggest
|
|
14
|
+
|
|
15
|
+
# List all available simulators
|
|
16
|
+
python scripts/simulator_selector.py --list
|
|
17
|
+
|
|
18
|
+
# Boot a specific simulator
|
|
19
|
+
python scripts/simulator_selector.py --boot "67A99DF0-27BD-4507-A3DE-B7D8C38F764A"
|
|
20
|
+
|
|
21
|
+
# Get suggestions as JSON for programmatic use
|
|
22
|
+
python scripts/simulator_selector.py --suggest --json
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import argparse
|
|
26
|
+
import json
|
|
27
|
+
import re
|
|
28
|
+
import subprocess
|
|
29
|
+
import sys
|
|
30
|
+
from datetime import datetime
|
|
31
|
+
from pathlib import Path
|
|
32
|
+
from typing import Optional
|
|
33
|
+
|
|
34
|
+
# Try to import config from build_and_test if available
|
|
35
|
+
try:
|
|
36
|
+
from xcode.config import Config
|
|
37
|
+
except ImportError:
|
|
38
|
+
Config = None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class SimulatorInfo:
|
|
42
|
+
"""Information about an iOS simulator."""
|
|
43
|
+
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
name: str,
|
|
47
|
+
udid: str,
|
|
48
|
+
ios_version: str,
|
|
49
|
+
status: str,
|
|
50
|
+
):
|
|
51
|
+
"""Initialize simulator info."""
|
|
52
|
+
self.name = name
|
|
53
|
+
self.udid = udid
|
|
54
|
+
self.ios_version = ios_version
|
|
55
|
+
self.status = status
|
|
56
|
+
self.reasons: list[str] = []
|
|
57
|
+
|
|
58
|
+
def to_dict(self) -> dict:
|
|
59
|
+
"""Convert to dictionary."""
|
|
60
|
+
return {
|
|
61
|
+
"device": self.name,
|
|
62
|
+
"udid": self.udid,
|
|
63
|
+
"ios": self.ios_version,
|
|
64
|
+
"status": self.status,
|
|
65
|
+
"reasons": self.reasons,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class SimulatorSelector:
|
|
70
|
+
"""Intelligent simulator selection."""
|
|
71
|
+
|
|
72
|
+
# Common iPhone models ranked by testing priority
|
|
73
|
+
COMMON_MODELS = [
|
|
74
|
+
"iPhone 16 Pro",
|
|
75
|
+
"iPhone 16",
|
|
76
|
+
"iPhone 15 Pro",
|
|
77
|
+
"iPhone 15",
|
|
78
|
+
"iPhone SE (3rd generation)",
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
def __init__(self):
|
|
82
|
+
"""Initialize selector."""
|
|
83
|
+
self.simulators: list[SimulatorInfo] = []
|
|
84
|
+
self.config: dict | None = None
|
|
85
|
+
self.last_used_simulator: str | None = None
|
|
86
|
+
|
|
87
|
+
# Load config if available
|
|
88
|
+
if Config:
|
|
89
|
+
try:
|
|
90
|
+
config = Config.load()
|
|
91
|
+
self.last_used_simulator = config.get_preferred_simulator()
|
|
92
|
+
except Exception:
|
|
93
|
+
pass
|
|
94
|
+
|
|
95
|
+
def list_simulators(self) -> list[SimulatorInfo]:
|
|
96
|
+
"""
|
|
97
|
+
List all available simulators.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
List of SimulatorInfo objects
|
|
101
|
+
"""
|
|
102
|
+
try:
|
|
103
|
+
result = subprocess.run(
|
|
104
|
+
["xcrun", "simctl", "list", "devices", "--json"],
|
|
105
|
+
capture_output=True,
|
|
106
|
+
text=True,
|
|
107
|
+
check=True,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
data = json.loads(result.stdout)
|
|
111
|
+
simulators = []
|
|
112
|
+
|
|
113
|
+
# Parse devices by iOS version
|
|
114
|
+
for runtime, devices in data.get("devices", {}).items():
|
|
115
|
+
# Extract iOS version from runtime (e.g., "com.apple.CoreSimulator.SimRuntime.iOS-18-0")
|
|
116
|
+
ios_version_match = re.search(r"iOS-(\d+-\d+)", runtime)
|
|
117
|
+
if not ios_version_match:
|
|
118
|
+
continue
|
|
119
|
+
|
|
120
|
+
ios_version = ios_version_match.group(1).replace("-", ".")
|
|
121
|
+
|
|
122
|
+
for device in devices:
|
|
123
|
+
name = device.get("name", "")
|
|
124
|
+
udid = device.get("udid", "")
|
|
125
|
+
is_available = device.get("isAvailable", False)
|
|
126
|
+
|
|
127
|
+
if not is_available or "iPhone" not in name:
|
|
128
|
+
continue
|
|
129
|
+
|
|
130
|
+
status = device.get("state", "").capitalize()
|
|
131
|
+
sim_info = SimulatorInfo(name, udid, ios_version, status)
|
|
132
|
+
simulators.append(sim_info)
|
|
133
|
+
|
|
134
|
+
self.simulators = simulators
|
|
135
|
+
return simulators
|
|
136
|
+
|
|
137
|
+
except subprocess.CalledProcessError as e:
|
|
138
|
+
print(f"Error listing simulators: {e.stderr}", file=sys.stderr)
|
|
139
|
+
return []
|
|
140
|
+
except json.JSONDecodeError as e:
|
|
141
|
+
print(f"Error parsing simulator list: {e}", file=sys.stderr)
|
|
142
|
+
return []
|
|
143
|
+
|
|
144
|
+
def get_suggestions(self, count: int = 4) -> list[SimulatorInfo]:
|
|
145
|
+
"""
|
|
146
|
+
Get top N suggested simulators.
|
|
147
|
+
|
|
148
|
+
Ranking factors:
|
|
149
|
+
1. Recently used (from config)
|
|
150
|
+
2. Latest iOS version
|
|
151
|
+
3. Common models
|
|
152
|
+
4. Boot status (Booted preferred)
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
count: Number of suggestions to return
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
List of suggested SimulatorInfo objects
|
|
159
|
+
"""
|
|
160
|
+
if not self.simulators:
|
|
161
|
+
return []
|
|
162
|
+
|
|
163
|
+
# Score each simulator
|
|
164
|
+
scored = []
|
|
165
|
+
for sim in self.simulators:
|
|
166
|
+
score = self._score_simulator(sim)
|
|
167
|
+
scored.append((score, sim))
|
|
168
|
+
|
|
169
|
+
# Sort by score (descending)
|
|
170
|
+
scored.sort(key=lambda x: x[0], reverse=True)
|
|
171
|
+
|
|
172
|
+
# Return top N
|
|
173
|
+
suggestions = [sim for _, sim in scored[:count]]
|
|
174
|
+
|
|
175
|
+
# Add reasons to each suggestion
|
|
176
|
+
for i, sim in enumerate(suggestions, 1):
|
|
177
|
+
if i == 1:
|
|
178
|
+
sim.reasons.append("Recommended")
|
|
179
|
+
|
|
180
|
+
# Check if recently used
|
|
181
|
+
if self.last_used_simulator and self.last_used_simulator == sim.name:
|
|
182
|
+
sim.reasons.append("Recently used")
|
|
183
|
+
|
|
184
|
+
# Check if latest iOS
|
|
185
|
+
latest_ios = max(s.ios_version for s in self.simulators)
|
|
186
|
+
if sim.ios_version == latest_ios:
|
|
187
|
+
sim.reasons.append("Latest iOS")
|
|
188
|
+
|
|
189
|
+
# Check if common model
|
|
190
|
+
for j, model in enumerate(self.COMMON_MODELS):
|
|
191
|
+
if model in sim.name:
|
|
192
|
+
sim.reasons.append(f"#{j+1} common model")
|
|
193
|
+
break
|
|
194
|
+
|
|
195
|
+
# Check if booted
|
|
196
|
+
if sim.status == "Booted":
|
|
197
|
+
sim.reasons.append("Currently running")
|
|
198
|
+
|
|
199
|
+
return suggestions
|
|
200
|
+
|
|
201
|
+
def _score_simulator(self, sim: SimulatorInfo) -> float:
|
|
202
|
+
"""
|
|
203
|
+
Score a simulator for ranking.
|
|
204
|
+
|
|
205
|
+
Higher score = better recommendation.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
sim: Simulator to score
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
Score value
|
|
212
|
+
"""
|
|
213
|
+
score = 0.0
|
|
214
|
+
|
|
215
|
+
# Recently used gets highest priority (100 points)
|
|
216
|
+
if self.last_used_simulator and self.last_used_simulator == sim.name:
|
|
217
|
+
score += 100
|
|
218
|
+
|
|
219
|
+
# Latest iOS version (50 points)
|
|
220
|
+
latest_ios = max(s.ios_version for s in self.simulators)
|
|
221
|
+
if sim.ios_version == latest_ios:
|
|
222
|
+
score += 50
|
|
223
|
+
|
|
224
|
+
# Common models (30-20 points based on ranking)
|
|
225
|
+
for i, model in enumerate(self.COMMON_MODELS):
|
|
226
|
+
if model in sim.name:
|
|
227
|
+
score += 30 - (i * 2) # Higher ranking models get more points
|
|
228
|
+
break
|
|
229
|
+
|
|
230
|
+
# Currently booted (10 points)
|
|
231
|
+
if sim.status == "Booted":
|
|
232
|
+
score += 10
|
|
233
|
+
|
|
234
|
+
# iOS version number (minor factor for breaking ties)
|
|
235
|
+
ios_numeric = float(sim.ios_version.replace(".", ""))
|
|
236
|
+
score += ios_numeric * 0.1
|
|
237
|
+
|
|
238
|
+
return score
|
|
239
|
+
|
|
240
|
+
def boot_simulator(self, udid: str) -> bool:
|
|
241
|
+
"""
|
|
242
|
+
Boot a simulator.
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
udid: Simulator UDID
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
True if successful, False otherwise
|
|
249
|
+
"""
|
|
250
|
+
try:
|
|
251
|
+
subprocess.run(
|
|
252
|
+
["xcrun", "simctl", "boot", udid],
|
|
253
|
+
capture_output=True,
|
|
254
|
+
check=True,
|
|
255
|
+
)
|
|
256
|
+
return True
|
|
257
|
+
except subprocess.CalledProcessError as e:
|
|
258
|
+
print(f"Error booting simulator: {e.stderr}", file=sys.stderr)
|
|
259
|
+
return False
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def format_suggestions(suggestions: list[SimulatorInfo], json_format: bool = False) -> str:
|
|
263
|
+
"""
|
|
264
|
+
Format suggestions for output.
|
|
265
|
+
|
|
266
|
+
Args:
|
|
267
|
+
suggestions: List of suggestions
|
|
268
|
+
json_format: If True, output as JSON
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
Formatted string
|
|
272
|
+
"""
|
|
273
|
+
if json_format:
|
|
274
|
+
data = {"suggestions": [s.to_dict() for s in suggestions]}
|
|
275
|
+
return json.dumps(data, indent=2)
|
|
276
|
+
|
|
277
|
+
if not suggestions:
|
|
278
|
+
return "No simulators available"
|
|
279
|
+
|
|
280
|
+
lines = ["Available Simulators:\n"]
|
|
281
|
+
for i, sim in enumerate(suggestions, 1):
|
|
282
|
+
lines.append(f"{i}. {sim.name} (iOS {sim.ios_version})")
|
|
283
|
+
if sim.reasons:
|
|
284
|
+
lines.append(f" {', '.join(sim.reasons)}")
|
|
285
|
+
lines.append(f" UDID: {sim.udid}")
|
|
286
|
+
lines.append("")
|
|
287
|
+
|
|
288
|
+
return "\n".join(lines)
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def main():
|
|
292
|
+
"""Main entry point."""
|
|
293
|
+
parser = argparse.ArgumentParser(
|
|
294
|
+
description="Intelligent iOS simulator selector",
|
|
295
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
296
|
+
epilog="""
|
|
297
|
+
Examples:
|
|
298
|
+
# Get suggestions for user selection
|
|
299
|
+
python scripts/simulator_selector.py --suggest
|
|
300
|
+
|
|
301
|
+
# List all available simulators
|
|
302
|
+
python scripts/simulator_selector.py --list
|
|
303
|
+
|
|
304
|
+
# Boot a specific simulator
|
|
305
|
+
python scripts/simulator_selector.py --boot <UDID>
|
|
306
|
+
|
|
307
|
+
# Get suggestions as JSON
|
|
308
|
+
python scripts/simulator_selector.py --suggest --json
|
|
309
|
+
""",
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
parser.add_argument(
|
|
313
|
+
"--suggest",
|
|
314
|
+
action="store_true",
|
|
315
|
+
help="Get top simulator suggestions",
|
|
316
|
+
)
|
|
317
|
+
parser.add_argument(
|
|
318
|
+
"--list",
|
|
319
|
+
action="store_true",
|
|
320
|
+
help="List all available simulators",
|
|
321
|
+
)
|
|
322
|
+
parser.add_argument(
|
|
323
|
+
"--boot",
|
|
324
|
+
metavar="UDID",
|
|
325
|
+
help="Boot specific simulator by UDID",
|
|
326
|
+
)
|
|
327
|
+
parser.add_argument(
|
|
328
|
+
"--json",
|
|
329
|
+
action="store_true",
|
|
330
|
+
help="Output as JSON",
|
|
331
|
+
)
|
|
332
|
+
parser.add_argument(
|
|
333
|
+
"--count",
|
|
334
|
+
type=int,
|
|
335
|
+
default=4,
|
|
336
|
+
help="Number of suggestions (default: 4)",
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
args = parser.parse_args()
|
|
340
|
+
|
|
341
|
+
selector = SimulatorSelector()
|
|
342
|
+
|
|
343
|
+
if args.boot:
|
|
344
|
+
# Boot specific simulator
|
|
345
|
+
success = selector.boot_simulator(args.boot)
|
|
346
|
+
if success:
|
|
347
|
+
print(f"Booted simulator: {args.boot}")
|
|
348
|
+
return 0
|
|
349
|
+
return 1
|
|
350
|
+
|
|
351
|
+
if args.list:
|
|
352
|
+
# List all simulators
|
|
353
|
+
simulators = selector.list_simulators()
|
|
354
|
+
output = format_suggestions(simulators, args.json)
|
|
355
|
+
print(output)
|
|
356
|
+
return 0
|
|
357
|
+
|
|
358
|
+
if args.suggest:
|
|
359
|
+
# Get suggestions
|
|
360
|
+
selector.list_simulators()
|
|
361
|
+
suggestions = selector.get_suggestions(args.count)
|
|
362
|
+
output = format_suggestions(suggestions, args.json)
|
|
363
|
+
print(output)
|
|
364
|
+
return 0
|
|
365
|
+
|
|
366
|
+
# Default: show suggestions
|
|
367
|
+
selector.list_simulators()
|
|
368
|
+
suggestions = selector.get_suggestions(args.count)
|
|
369
|
+
output = format_suggestions(suggestions, args.json)
|
|
370
|
+
print(output)
|
|
371
|
+
return 0
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
if __name__ == "__main__":
|
|
375
|
+
sys.exit(main())
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
iOS Status Bar Controller
|
|
4
|
+
|
|
5
|
+
Override simulator status bar for clean screenshots and testing.
|
|
6
|
+
Control time, network, wifi, battery display.
|
|
7
|
+
|
|
8
|
+
Usage: python scripts/status_bar.py --preset clean
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import argparse
|
|
12
|
+
import subprocess
|
|
13
|
+
import sys
|
|
14
|
+
|
|
15
|
+
from common import resolve_udid
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class StatusBarController:
|
|
19
|
+
"""Controls iOS simulator status bar appearance."""
|
|
20
|
+
|
|
21
|
+
# Preset configurations
|
|
22
|
+
PRESETS = {
|
|
23
|
+
"clean": {
|
|
24
|
+
"time": "9:41",
|
|
25
|
+
"data_network": "5g",
|
|
26
|
+
"wifi_mode": "active",
|
|
27
|
+
"battery_state": "charged",
|
|
28
|
+
"battery_level": 100,
|
|
29
|
+
},
|
|
30
|
+
"testing": {
|
|
31
|
+
"time": "11:11",
|
|
32
|
+
"data_network": "4g",
|
|
33
|
+
"wifi_mode": "active",
|
|
34
|
+
"battery_state": "discharging",
|
|
35
|
+
"battery_level": 50,
|
|
36
|
+
},
|
|
37
|
+
"low_battery": {
|
|
38
|
+
"time": "9:41",
|
|
39
|
+
"data_network": "5g",
|
|
40
|
+
"wifi_mode": "active",
|
|
41
|
+
"battery_state": "discharging",
|
|
42
|
+
"battery_level": 20,
|
|
43
|
+
},
|
|
44
|
+
"airplane": {
|
|
45
|
+
"time": "9:41",
|
|
46
|
+
"data_network": "none",
|
|
47
|
+
"wifi_mode": "failed",
|
|
48
|
+
"battery_state": "charged",
|
|
49
|
+
"battery_level": 100,
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
def __init__(self, udid: str | None = None):
|
|
54
|
+
"""Initialize status bar controller.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
udid: Optional device UDID (auto-detects booted simulator if None)
|
|
58
|
+
"""
|
|
59
|
+
self.udid = udid
|
|
60
|
+
|
|
61
|
+
def override(
|
|
62
|
+
self,
|
|
63
|
+
time: str | None = None,
|
|
64
|
+
data_network: str | None = None,
|
|
65
|
+
wifi_mode: str | None = None,
|
|
66
|
+
battery_state: str | None = None,
|
|
67
|
+
battery_level: int | None = None,
|
|
68
|
+
) -> bool:
|
|
69
|
+
"""
|
|
70
|
+
Override status bar appearance.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
time: Time in HH:MM format (e.g., "9:41")
|
|
74
|
+
data_network: Network type (none, 1x, 3g, 4g, 5g, lte, lte-a)
|
|
75
|
+
wifi_mode: WiFi state (active, searching, failed)
|
|
76
|
+
battery_state: Battery state (charging, charged, discharging)
|
|
77
|
+
battery_level: Battery percentage (0-100)
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
Success status
|
|
81
|
+
"""
|
|
82
|
+
cmd = ["xcrun", "simctl", "status_bar"]
|
|
83
|
+
|
|
84
|
+
if self.udid:
|
|
85
|
+
cmd.append(self.udid)
|
|
86
|
+
else:
|
|
87
|
+
cmd.append("booted")
|
|
88
|
+
|
|
89
|
+
cmd.append("override")
|
|
90
|
+
|
|
91
|
+
# Add parameters if provided
|
|
92
|
+
if time:
|
|
93
|
+
cmd.extend(["--time", time])
|
|
94
|
+
if data_network:
|
|
95
|
+
cmd.extend(["--dataNetwork", data_network])
|
|
96
|
+
if wifi_mode:
|
|
97
|
+
cmd.extend(["--wifiMode", wifi_mode])
|
|
98
|
+
if battery_state:
|
|
99
|
+
cmd.extend(["--batteryState", battery_state])
|
|
100
|
+
if battery_level is not None:
|
|
101
|
+
cmd.extend(["--batteryLevel", str(battery_level)])
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
subprocess.run(cmd, capture_output=True, check=True)
|
|
105
|
+
return True
|
|
106
|
+
except subprocess.CalledProcessError:
|
|
107
|
+
return False
|
|
108
|
+
|
|
109
|
+
def clear(self) -> bool:
|
|
110
|
+
"""
|
|
111
|
+
Clear status bar override and restore defaults.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
Success status
|
|
115
|
+
"""
|
|
116
|
+
cmd = ["xcrun", "simctl", "status_bar"]
|
|
117
|
+
|
|
118
|
+
if self.udid:
|
|
119
|
+
cmd.append(self.udid)
|
|
120
|
+
else:
|
|
121
|
+
cmd.append("booted")
|
|
122
|
+
|
|
123
|
+
cmd.append("clear")
|
|
124
|
+
|
|
125
|
+
try:
|
|
126
|
+
subprocess.run(cmd, capture_output=True, check=True)
|
|
127
|
+
return True
|
|
128
|
+
except subprocess.CalledProcessError:
|
|
129
|
+
return False
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def main():
|
|
133
|
+
"""Main entry point."""
|
|
134
|
+
parser = argparse.ArgumentParser(
|
|
135
|
+
description="Override iOS simulator status bar for screenshots and testing"
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# Preset option
|
|
139
|
+
parser.add_argument(
|
|
140
|
+
"--preset",
|
|
141
|
+
choices=list(StatusBarController.PRESETS.keys()),
|
|
142
|
+
help="Use preset configuration (clean, testing, low-battery, airplane)",
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# Custom options
|
|
146
|
+
parser.add_argument(
|
|
147
|
+
"--time",
|
|
148
|
+
help="Override time (HH:MM format, e.g., '9:41')",
|
|
149
|
+
)
|
|
150
|
+
parser.add_argument(
|
|
151
|
+
"--data-network",
|
|
152
|
+
choices=["none", "1x", "3g", "4g", "5g", "lte", "lte-a"],
|
|
153
|
+
help="Data network type",
|
|
154
|
+
)
|
|
155
|
+
parser.add_argument(
|
|
156
|
+
"--wifi-mode",
|
|
157
|
+
choices=["active", "searching", "failed"],
|
|
158
|
+
help="WiFi state",
|
|
159
|
+
)
|
|
160
|
+
parser.add_argument(
|
|
161
|
+
"--battery-state",
|
|
162
|
+
choices=["charging", "charged", "discharging"],
|
|
163
|
+
help="Battery state",
|
|
164
|
+
)
|
|
165
|
+
parser.add_argument(
|
|
166
|
+
"--battery-level",
|
|
167
|
+
type=int,
|
|
168
|
+
help="Battery level 0-100",
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# Other options
|
|
172
|
+
parser.add_argument(
|
|
173
|
+
"--clear",
|
|
174
|
+
action="store_true",
|
|
175
|
+
help="Clear status bar override and restore defaults",
|
|
176
|
+
)
|
|
177
|
+
parser.add_argument(
|
|
178
|
+
"--udid",
|
|
179
|
+
help="Device UDID (auto-detects booted simulator if not provided)",
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
args = parser.parse_args()
|
|
183
|
+
|
|
184
|
+
# Resolve UDID with auto-detection
|
|
185
|
+
try:
|
|
186
|
+
udid = resolve_udid(args.udid)
|
|
187
|
+
except RuntimeError as e:
|
|
188
|
+
print(f"Error: {e}")
|
|
189
|
+
sys.exit(1)
|
|
190
|
+
|
|
191
|
+
controller = StatusBarController(udid=udid)
|
|
192
|
+
|
|
193
|
+
# Clear mode
|
|
194
|
+
if args.clear:
|
|
195
|
+
if controller.clear():
|
|
196
|
+
print("Status bar override cleared - defaults restored")
|
|
197
|
+
else:
|
|
198
|
+
print("Failed to clear status bar override")
|
|
199
|
+
sys.exit(1)
|
|
200
|
+
|
|
201
|
+
# Preset mode
|
|
202
|
+
elif args.preset:
|
|
203
|
+
preset = StatusBarController.PRESETS[args.preset]
|
|
204
|
+
if controller.override(**preset):
|
|
205
|
+
print(f"Status bar: {args.preset} preset applied")
|
|
206
|
+
print(
|
|
207
|
+
f" Time: {preset['time']}, "
|
|
208
|
+
f"Network: {preset['data_network']}, "
|
|
209
|
+
f"Battery: {preset['battery_level']}%"
|
|
210
|
+
)
|
|
211
|
+
else:
|
|
212
|
+
print(f"Failed to apply {args.preset} preset")
|
|
213
|
+
sys.exit(1)
|
|
214
|
+
|
|
215
|
+
# Custom mode
|
|
216
|
+
elif any(
|
|
217
|
+
[
|
|
218
|
+
args.time,
|
|
219
|
+
args.data_network,
|
|
220
|
+
args.wifi_mode,
|
|
221
|
+
args.battery_state,
|
|
222
|
+
args.battery_level is not None,
|
|
223
|
+
]
|
|
224
|
+
):
|
|
225
|
+
if controller.override(
|
|
226
|
+
time=args.time,
|
|
227
|
+
data_network=args.data_network,
|
|
228
|
+
wifi_mode=args.wifi_mode,
|
|
229
|
+
battery_state=args.battery_state,
|
|
230
|
+
battery_level=args.battery_level,
|
|
231
|
+
):
|
|
232
|
+
output = "Status bar override applied:"
|
|
233
|
+
if args.time:
|
|
234
|
+
output += f" Time={args.time}"
|
|
235
|
+
if args.data_network:
|
|
236
|
+
output += f" Network={args.data_network}"
|
|
237
|
+
if args.battery_level is not None:
|
|
238
|
+
output += f" Battery={args.battery_level}%"
|
|
239
|
+
print(output)
|
|
240
|
+
else:
|
|
241
|
+
print("Failed to override status bar")
|
|
242
|
+
sys.exit(1)
|
|
243
|
+
|
|
244
|
+
else:
|
|
245
|
+
parser.print_help()
|
|
246
|
+
sys.exit(1)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
if __name__ == "__main__":
|
|
250
|
+
main()
|