@leejungkiin/awkit 1.7.1 → 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.
Files changed (245) hide show
  1. package/bin/awk.js +576 -84
  2. package/core/CLAUDE.md +1 -1
  3. package/core/GEMINI.md +148 -167
  4. package/core/GEMINI.md.bak +149 -116
  5. package/core/skill-runtime-manifest.json +3 -0
  6. package/docs/Claude Fable 5.md +3826 -0
  7. package/docs/android_kotlin_system_instruction.md +210 -0
  8. package/docs/brainstorm_ponytail_integration.md +146 -0
  9. package/docs/brainstorm_smart_setup.md +113 -0
  10. package/docs/deep-research-report (1).md +293 -0
  11. package/docs/history/GEMINI.v1.md +135 -0
  12. package/docs/history/brainstorm_antigravity_unified_architecture.v1.md +105 -0
  13. package/docs/history/implementation_plan.v1.md +58 -0
  14. package/package.json +4 -1
  15. package/scripts/artifact-storage.js +130 -0
  16. package/scripts/automation-gate.js +35 -2
  17. package/scripts/claude-plan.js +76 -0
  18. package/scripts/dependency-manager.js +210 -0
  19. package/scripts/exec-rtk.js +11 -5
  20. package/scripts/i18n-helper.js +381 -0
  21. package/scripts/multi-model-pipeline.js +144 -0
  22. package/skill-packs/mobile-ios/pack.json +4 -2
  23. package/skill-packs/reverse-engineering/pack.json +1 -0
  24. package/skills/CATALOG.md +20 -0
  25. package/skills/GEMINI.md +9 -1
  26. package/skills/TRIGGER_INDEX.md +10 -0
  27. package/skills/ai-music/SKILL.md +275 -0
  28. package/skills/android-re-analyzer/SKILL.md +238 -0
  29. package/skills/android-re-analyzer/references/api-extraction-patterns.md +119 -0
  30. package/skills/android-re-analyzer/references/call-flow-analysis.md +176 -0
  31. package/skills/android-re-analyzer/references/fernflower-usage.md +115 -0
  32. package/skills/android-re-analyzer/references/jadx-usage.md +116 -0
  33. package/skills/android-re-analyzer/references/setup-guide.md +221 -0
  34. package/skills/android-re-analyzer/scripts/check-deps.sh +129 -0
  35. package/skills/android-re-analyzer/scripts/decompile.sh +375 -0
  36. package/skills/android-re-analyzer/scripts/find-api-calls.sh +118 -0
  37. package/skills/android-re-analyzer/scripts/install-dep.sh +448 -0
  38. package/skills/animal-island-ui-style/SKILL.md +1450 -0
  39. package/skills/app-store-review-agent/SKILL.md +164 -0
  40. package/skills/app-store-review-agent/references/guidelines/README.md +154 -0
  41. package/skills/app-store-review-agent/references/guidelines/by-app-type/ai_apps.md +37 -0
  42. package/skills/app-store-review-agent/references/guidelines/by-app-type/all_apps.md +50 -0
  43. package/skills/app-store-review-agent/references/guidelines/by-app-type/crypto_finance.md +31 -0
  44. package/skills/app-store-review-agent/references/guidelines/by-app-type/games.md +31 -0
  45. package/skills/app-store-review-agent/references/guidelines/by-app-type/health_fitness.md +31 -0
  46. package/skills/app-store-review-agent/references/guidelines/by-app-type/kids.md +27 -0
  47. package/skills/app-store-review-agent/references/guidelines/by-app-type/macos.md +38 -0
  48. package/skills/app-store-review-agent/references/guidelines/by-app-type/social_ugc.md +32 -0
  49. package/skills/app-store-review-agent/references/guidelines/by-app-type/subscription_iap.md +34 -0
  50. package/skills/app-store-review-agent/references/guidelines/by-app-type/vpn.md +18 -0
  51. package/skills/app-store-review-agent/references/rules/design/minimum_functionality.md +96 -0
  52. package/skills/app-store-review-agent/references/rules/design/sign_in_with_apple.md +54 -0
  53. package/skills/app-store-review-agent/references/rules/entitlements/unused_entitlements.md +83 -0
  54. package/skills/app-store-review-agent/references/rules/metadata/accurate_metadata.md +54 -0
  55. package/skills/app-store-review-agent/references/rules/metadata/apple_trademark.md +99 -0
  56. package/skills/app-store-review-agent/references/rules/metadata/china_storefront.md +72 -0
  57. package/skills/app-store-review-agent/references/rules/metadata/competitor_terms.md +56 -0
  58. package/skills/app-store-review-agent/references/rules/metadata/subscription_metadata.md +81 -0
  59. package/skills/app-store-review-agent/references/rules/privacy/privacy_manifest.md +84 -0
  60. package/skills/app-store-review-agent/references/rules/privacy/unnecessary_data.md +60 -0
  61. package/skills/app-store-review-agent/references/rules/subscription/misleading_pricing.md +63 -0
  62. package/skills/app-store-review-agent/references/rules/subscription/missing_tos_pp.md +54 -0
  63. package/skills/awf-ponytail/SKILL.md +91 -0
  64. package/skills/awf-ponytail-review/SKILL.md +67 -0
  65. package/skills/awf-session-restore/SKILL.md +3 -3
  66. package/skills/brainstorm-agent/SKILL.md +11 -2
  67. package/skills/brainstorm-agent/templates/brief-template.md +8 -0
  68. package/skills/claude-planner/SKILL.md +47 -0
  69. package/skills/code-review/SKILL.md +87 -0
  70. package/skills/expo-game-development/SKILL.md +163 -0
  71. package/skills/flutter/LICENSE.txt +202 -0
  72. package/skills/flutter/SKILL.md +127 -0
  73. package/skills/flutter-project-creater/LICENSE.txt +202 -0
  74. package/skills/flutter-project-creater/SKILL.md +106 -0
  75. package/skills/game-developer/SKILL.md +163 -0
  76. package/skills/game-developer/references/ecs-patterns.md +501 -0
  77. package/skills/game-developer/references/multiplayer-networking.md +475 -0
  78. package/skills/game-developer/references/performance-optimization.md +422 -0
  79. package/skills/game-developer/references/unity-patterns.md +271 -0
  80. package/skills/game-developer/references/unreal-cpp.md +352 -0
  81. package/skills/generate-gui-assets/SKILL.md +305 -0
  82. package/skills/generate-gui-assets/agents/openai.yaml +4 -0
  83. package/skills/generate-gui-assets/references/catalog-schema.md +58 -0
  84. package/skills/generate-gui-assets/references/extraction-techniques.md +21 -0
  85. package/skills/generate-gui-assets/references/prompt-patterns.md +58 -0
  86. package/skills/generate-gui-assets/scripts/__pycache__/clean_chroma_edges.cpython-311.pyc +0 -0
  87. package/skills/generate-gui-assets/scripts/build_gui_contact_sheet.py +51 -0
  88. package/skills/generate-gui-assets/scripts/clean_chroma_edges.py +262 -0
  89. package/skills/generate-gui-assets/scripts/copy_approved_icons.py +64 -0
  90. package/skills/generate-gui-assets/scripts/prepare_gui_asset_run.py +91 -0
  91. package/skills/generate-gui-assets/scripts/suggest_grid_options.py +63 -0
  92. package/skills/generate-gui-assets/scripts/validate_gui_catalog.py +50 -0
  93. package/skills/godot-game-development/SKILL.md +142 -0
  94. package/skills/hatch-pet/LICENSE.txt +201 -0
  95. package/skills/hatch-pet/SKILL.md +420 -0
  96. package/skills/hatch-pet/agents/openai.yaml +4 -0
  97. package/skills/hatch-pet/references/animation-rows.md +29 -0
  98. package/skills/hatch-pet/references/codex-pet-contract.md +35 -0
  99. package/skills/hatch-pet/references/qa-rubric.md +60 -0
  100. package/skills/hatch-pet/scripts/__pycache__/clean_chroma_edges.cpython-311.pyc +0 -0
  101. package/skills/hatch-pet/scripts/clean_chroma_edges.py +262 -0
  102. package/skills/hatch-pet/scripts/compose_atlas.py +150 -0
  103. package/skills/hatch-pet/scripts/derive_running_left_from_running_right.py +143 -0
  104. package/skills/hatch-pet/scripts/extract_strip_frames.py +323 -0
  105. package/skills/hatch-pet/scripts/finalize_pet_run.py +382 -0
  106. package/skills/hatch-pet/scripts/generate_pet_images.py +287 -0
  107. package/skills/hatch-pet/scripts/inspect_frames.py +246 -0
  108. package/skills/hatch-pet/scripts/make_contact_sheet.py +96 -0
  109. package/skills/hatch-pet/scripts/package_custom_pet.py +108 -0
  110. package/skills/hatch-pet/scripts/pet_job_status.py +117 -0
  111. package/skills/hatch-pet/scripts/prepare_pet_run.py +673 -0
  112. package/skills/hatch-pet/scripts/queue_pet_repairs.py +172 -0
  113. package/skills/hatch-pet/scripts/record_imagegen_result.py +250 -0
  114. package/skills/hatch-pet/scripts/render_animation_videos.py +134 -0
  115. package/skills/hatch-pet/scripts/render_animation_videos.sh +5 -0
  116. package/skills/hatch-pet/scripts/validate_atlas.py +139 -0
  117. package/skills/i18n-orchestrator/SKILL.md +37 -0
  118. package/skills/ios-simulator-skill/SKILL.md +390 -0
  119. package/skills/ios-simulator-skill/scripts/accessibility_audit.py +300 -0
  120. package/skills/ios-simulator-skill/scripts/app_launcher.py +326 -0
  121. package/skills/ios-simulator-skill/scripts/app_state_capture.py +400 -0
  122. package/skills/ios-simulator-skill/scripts/appearance.py +385 -0
  123. package/skills/ios-simulator-skill/scripts/build_and_test.py +348 -0
  124. package/skills/ios-simulator-skill/scripts/clipboard.py +103 -0
  125. package/skills/ios-simulator-skill/scripts/common/__init__.py +61 -0
  126. package/skills/ios-simulator-skill/scripts/common/cache_utils.py +289 -0
  127. package/skills/ios-simulator-skill/scripts/common/device_utils.py +462 -0
  128. package/skills/ios-simulator-skill/scripts/common/env_config.py +35 -0
  129. package/skills/ios-simulator-skill/scripts/common/hang_pipeline.py +862 -0
  130. package/skills/ios-simulator-skill/scripts/common/hang_sessions.py +490 -0
  131. package/skills/ios-simulator-skill/scripts/common/idb_utils.py +180 -0
  132. package/skills/ios-simulator-skill/scripts/common/screenshot_utils.py +338 -0
  133. package/skills/ios-simulator-skill/scripts/container.py +668 -0
  134. package/skills/ios-simulator-skill/scripts/gesture.py +394 -0
  135. package/skills/ios-simulator-skill/scripts/hang_watcher.py +1533 -0
  136. package/skills/ios-simulator-skill/scripts/keyboard.py +391 -0
  137. package/skills/ios-simulator-skill/scripts/localization_audit.py +483 -0
  138. package/skills/ios-simulator-skill/scripts/location.py +467 -0
  139. package/skills/ios-simulator-skill/scripts/log_monitor.py +493 -0
  140. package/skills/ios-simulator-skill/scripts/model_inspector.py +645 -0
  141. package/skills/ios-simulator-skill/scripts/navigator.py +461 -0
  142. package/skills/ios-simulator-skill/scripts/privacy_manager.py +310 -0
  143. package/skills/ios-simulator-skill/scripts/push_notification.py +240 -0
  144. package/skills/ios-simulator-skill/scripts/screen_mapper.py +296 -0
  145. package/skills/ios-simulator-skill/scripts/sim_health_check.sh +245 -0
  146. package/skills/ios-simulator-skill/scripts/sim_list.py +299 -0
  147. package/skills/ios-simulator-skill/scripts/simctl_boot.py +312 -0
  148. package/skills/ios-simulator-skill/scripts/simctl_create.py +316 -0
  149. package/skills/ios-simulator-skill/scripts/simctl_delete.py +357 -0
  150. package/skills/ios-simulator-skill/scripts/simctl_erase.py +351 -0
  151. package/skills/ios-simulator-skill/scripts/simctl_shutdown.py +290 -0
  152. package/skills/ios-simulator-skill/scripts/simulator_selector.py +375 -0
  153. package/skills/ios-simulator-skill/scripts/status_bar.py +250 -0
  154. package/skills/ios-simulator-skill/scripts/test_recorder.py +323 -0
  155. package/skills/ios-simulator-skill/scripts/visual_diff.py +235 -0
  156. package/skills/ios-simulator-skill/scripts/xcode/__init__.py +13 -0
  157. package/skills/ios-simulator-skill/scripts/xcode/builder.py +397 -0
  158. package/skills/ios-simulator-skill/scripts/xcode/cache.py +204 -0
  159. package/skills/ios-simulator-skill/scripts/xcode/config.py +178 -0
  160. package/skills/ios-simulator-skill/scripts/xcode/reporter.py +343 -0
  161. package/skills/ios-simulator-skill/scripts/xcode/xcresult.py +451 -0
  162. package/skills/ios-visual-qa-strategist/SKILL.md +111 -0
  163. package/skills/ios-visual-qa-strategist/agents/openai.yaml +4 -0
  164. package/skills/ios-visual-qa-strategist/references/ios-tool-selection.md +61 -0
  165. package/skills/ios-visual-qa-strategist/references/minimal-capture-policy.md +56 -0
  166. package/skills/ios-visual-qa-strategist/references/visual-reasoning-heuristics.md +53 -0
  167. package/skills/orchestrator/SKILL.md +0 -20
  168. package/skills/persistent-storage/SKILL.md +55 -0
  169. package/skills/short-maker/SKILL.md +23 -0
  170. package/skills/short-maker/scripts/effects.js +56 -0
  171. package/skills/short-maker/scripts/shortmaker-bridge.js +332 -0
  172. package/skills/short-maker/scripts/videomix.js +601 -0
  173. package/skills/short-maker/templates/hyperframes/cinematic-character.template.html +172 -0
  174. package/skills/short-maker/templates/hyperframes/index.template.html +194 -0
  175. package/skills/smali-to-kotlin/SKILL.md +128 -0
  176. package/skills/smali-to-kotlin/examples/getting-started/tech-stack.md +58 -0
  177. package/skills/smali-to-kotlin/examples/pipeline/data-ui-parity.md +118 -0
  178. package/skills/smali-to-kotlin/examples/pipeline/scanner-and-bootstrap.md +106 -0
  179. package/skills/smali-to-kotlin/library-patterns.md +189 -0
  180. package/skills/smali-to-kotlin/phase-0-discovery.md +128 -0
  181. package/skills/smali-to-kotlin/phase-1-architecture.md +166 -0
  182. package/skills/smali-to-kotlin/phase-2-blueprint-ui.md +347 -0
  183. package/skills/smali-to-kotlin/phase-2-blueprint.md +228 -0
  184. package/skills/smali-to-kotlin/phase-3-build.md +248 -0
  185. package/skills/smali-to-kotlin/phase-3-logic-build.md +268 -0
  186. package/skills/smali-to-kotlin/smali-reading-guide.md +310 -0
  187. package/skills/smali-to-kotlin/templates/app-map.md +101 -0
  188. package/skills/smali-to-kotlin/templates/architecture.md +142 -0
  189. package/skills/smali-to-kotlin/templates/blueprint.md +145 -0
  190. package/skills/spec-gate/SKILL.md +6 -2
  191. package/skills/symphony-enforcer/SKILL.md +8 -0
  192. package/skills/symphony-enforcer/examples/mindful-stop.md +2 -0
  193. package/skills/symphony-enforcer/examples/three-phase.md +16 -0
  194. package/skills/symphony-enforcer/examples/trigger-points.md +7 -1
  195. package/skills/unity-game-development/SKILL.md +231 -0
  196. package/skills/video-edit/SKILL.md +36 -0
  197. package/skills/video-edit/scripts/video_edit.py +324 -0
  198. package/templates/project-identity/android.json +2 -2
  199. package/templates/project-identity/backend-nestjs.json +2 -2
  200. package/templates/project-identity/expo.json +2 -2
  201. package/templates/project-identity/ios.json +2 -2
  202. package/templates/project-identity/web-nextjs.json +2 -2
  203. package/templates/setup-mapping.json +48 -0
  204. package/templates/specs/design-template.md +161 -71
  205. package/templates/specs/requirements-template.md +65 -133
  206. package/templates/specs/task-spec-template.xml +3 -0
  207. package/workflows/_uncategorized/critic.md +40 -0
  208. package/workflows/_uncategorized/git-rebase-flow.md +81 -0
  209. package/workflows/_uncategorized/image-gen.md +118 -0
  210. package/workflows/_uncategorized/multi-model-pipeline.md +60 -0
  211. package/workflows/_uncategorized/pixel-gen.md +86 -0
  212. package/workflows/_uncategorized/pixel-setup.md +90 -0
  213. package/workflows/_uncategorized/ponytail-review.md +59 -0
  214. package/workflows/_uncategorized/reverse-android-build.md +222 -0
  215. package/workflows/_uncategorized/reverse-android-design.md +139 -0
  216. package/workflows/_uncategorized/reverse-android-discover.md +150 -0
  217. package/workflows/_uncategorized/reverse-android-scan.md +158 -0
  218. package/workflows/_uncategorized/reverse-android.md +143 -0
  219. package/workflows/_uncategorized/reverse-ios-build.md +240 -0
  220. package/workflows/_uncategorized/reverse-ios-design.md +112 -0
  221. package/workflows/_uncategorized/reverse-ios-discover.md +120 -0
  222. package/workflows/_uncategorized/reverse-ios-scan.md +155 -0
  223. package/workflows/_uncategorized/reverse-ios.md +152 -0
  224. package/workflows/_uncategorized/safety-router.md +34 -0
  225. package/workflows/_uncategorized/teach.md +89 -0
  226. package/workflows/_uncategorized/verify-ui.md +53 -0
  227. package/workflows/_uncategorized/visualize-screenshots.md +34 -0
  228. package/workflows/ads/ads-analyst.md +201 -0
  229. package/workflows/ads/ads-audit.md +106 -0
  230. package/workflows/ads/ads-optimize.md +97 -0
  231. package/workflows/ads/ads-targeting.md +241 -0
  232. package/workflows/ads/adsExpert.md +160 -0
  233. package/workflows/ads/smali-ads-config.md +400 -0
  234. package/workflows/ads/smali-ads-flow.md +331 -0
  235. package/workflows/ads/smali-ads-interstitial.md +377 -0
  236. package/workflows/ads/smali-ads-native.md +382 -0
  237. package/workflows/context/teach.md +89 -0
  238. package/workflows/gitnexus.md +8 -8
  239. package/workflows/lifecycle/brainstorm.md +43 -0
  240. package/workflows/lifecycle/code.md +5 -0
  241. package/workflows/lifecycle/init.md +23 -5
  242. package/workflows/lifecycle/multi-model-pipeline.md +60 -0
  243. package/workflows/quality/ponytail-review.md +59 -0
  244. package/workflows/roles/critic.md +40 -0
  245. 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()