claudecode-omc 5.6.6 → 5.6.8
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/.local/skills/THIRD_PARTY_LICENSES/AvdLee-SwiftUI-Agent-Skill.LICENSE +21 -0
- package/.local/skills/THIRD_PARTY_LICENSES/Dimillian-Skills.LICENSE +21 -0
- package/.local/skills/THIRD_PARTY_LICENSES/README.md +36 -0
- package/.local/skills/THIRD_PARTY_LICENSES/twostraws-swiftui-agent-skill.LICENSE +21 -0
- package/.local/skills/h5-to-swiftui/SKILL.md +201 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/README.md +176 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/h5-twin/index.html +52 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/h5-twin/style.css +133 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/swiftui-twin/Package.swift +26 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/swiftui-twin/Sources/CalibrationScreen/CalibrationScreen.swift +142 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/swiftui-twin-divergent/Package.swift +32 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/swiftui-twin-divergent/Sources/CalibrationScreenDivergent/CalibrationScreenDivergent.swift +122 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/tokens.json +42 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/index.html +14 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/package.json +20 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/public/api/articles/001.json +96 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/public/api/articles/index.json +89 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/App.jsx +22 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/App.module.css +11 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/ArticleCard.jsx +53 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/ArticleCard.module.css +139 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/NavBar.jsx +37 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/NavBar.module.css +72 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/TagCloud.jsx +30 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/TagCloud.module.css +50 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/TrendChart.jsx +159 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/TrendChart.module.css +21 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/main.jsx +12 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/screens/ArticleScreen.jsx +182 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/screens/ArticleScreen.module.css +294 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/screens/FeedScreen.jsx +147 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/screens/FeedScreen.module.css +161 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/styles/global.css +50 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/styles/tokens.css +103 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/vite.config.js +6 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/data/tasks.js +67 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/index.html +26 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/router.js +73 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/screens/detail.js +164 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/screens/home.js +53 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/screens/list.js +87 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/styles/app.css +342 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/styles/tokens.css +68 -0
- package/.local/skills/h5-to-swiftui/references/css-to-swiftui-map.md +205 -0
- package/.local/skills/h5-to-swiftui/references/design-token-extraction.md +209 -0
- package/.local/skills/h5-to-swiftui/references/high-risk-triage.md +209 -0
- package/.local/skills/h5-to-swiftui/references/render-equivalence-calibration.md +193 -0
- package/.local/skills/h5-to-swiftui/references/stack-detection.md +160 -0
- package/.local/skills/h5-to-swiftui/references/visual-diff-loop-protocol.md +365 -0
- package/.local/skills/h5-to-swiftui/scripts/_calib-consts.mjs +150 -0
- package/.local/skills/h5-to-swiftui/scripts/_imglib.mjs +547 -0
- package/.local/skills/h5-to-swiftui/scripts/_provenance.mjs +123 -0
- package/.local/skills/h5-to-swiftui/scripts/calibrate-render.mjs +625 -0
- package/.local/skills/h5-to-swiftui/scripts/capture-reference.mjs +386 -0
- package/.local/skills/h5-to-swiftui/scripts/detect-stack.mjs +305 -0
- package/.local/skills/h5-to-swiftui/scripts/evaluate-convergence.mjs +1093 -0
- package/.local/skills/h5-to-swiftui/scripts/extract-tokens.mjs +600 -0
- package/.local/skills/h5-to-swiftui/scripts/mark-overlay.mjs +379 -0
- package/.local/skills/h5-to-swiftui/scripts/pixel-diff.mjs +530 -0
- package/.local/skills/h5-to-swiftui/scripts/sim-screenshot.sh +544 -0
- package/.local/skills/ios-debugger-agent/SKILL.md +51 -0
- package/.local/skills/ios-debugger-agent/agents/openai.yaml +4 -0
- package/.local/skills/swift-concurrency-expert/SKILL.md +105 -0
- package/.local/skills/swift-concurrency-expert/agents/openai.yaml +4 -0
- package/.local/skills/swift-concurrency-expert/references/approachable-concurrency.md +63 -0
- package/.local/skills/swift-concurrency-expert/references/swift-6-2-concurrency.md +272 -0
- package/.local/skills/swift-concurrency-expert/references/swiftui-concurrency-tour-wwdc.md +33 -0
- package/.local/skills/swiftui-expert-skill/SKILL.md +162 -0
- package/.local/skills/swiftui-expert-skill/references/accessibility-patterns.md +215 -0
- package/.local/skills/swiftui-expert-skill/references/animation-advanced.md +403 -0
- package/.local/skills/swiftui-expert-skill/references/animation-basics.md +284 -0
- package/.local/skills/swiftui-expert-skill/references/animation-transitions.md +326 -0
- package/.local/skills/swiftui-expert-skill/references/charts-accessibility.md +135 -0
- package/.local/skills/swiftui-expert-skill/references/charts.md +602 -0
- package/.local/skills/swiftui-expert-skill/references/focus-patterns.md +299 -0
- package/.local/skills/swiftui-expert-skill/references/image-optimization.md +203 -0
- package/.local/skills/swiftui-expert-skill/references/latest-apis.md +488 -0
- package/.local/skills/swiftui-expert-skill/references/layout-best-practices.md +266 -0
- package/.local/skills/swiftui-expert-skill/references/liquid-glass.md +423 -0
- package/.local/skills/swiftui-expert-skill/references/list-patterns.md +446 -0
- package/.local/skills/swiftui-expert-skill/references/macos-scenes.md +318 -0
- package/.local/skills/swiftui-expert-skill/references/macos-views.md +357 -0
- package/.local/skills/swiftui-expert-skill/references/macos-window-styling.md +303 -0
- package/.local/skills/swiftui-expert-skill/references/performance-patterns.md +403 -0
- package/.local/skills/swiftui-expert-skill/references/scroll-patterns.md +293 -0
- package/.local/skills/swiftui-expert-skill/references/sheet-navigation-patterns.md +363 -0
- package/.local/skills/swiftui-expert-skill/references/state-management.md +388 -0
- package/.local/skills/swiftui-expert-skill/references/text-patterns.md +32 -0
- package/.local/skills/swiftui-expert-skill/references/trace-analysis.md +295 -0
- package/.local/skills/swiftui-expert-skill/references/trace-recording.md +134 -0
- package/.local/skills/swiftui-expert-skill/references/view-structure.md +780 -0
- package/.local/skills/swiftui-expert-skill/scripts/__pycache__/analyze_trace.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/__pycache__/record_trace.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/analyze_trace.py +301 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__init__.py +1 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/__init__.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/causes.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/correlate.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/events.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/hangs.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/hitches.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/summary.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/swiftui.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/time_profiler.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/xctrace.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/xml_utils.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/causes.py +187 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/correlate.py +179 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/events.py +291 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/hangs.py +108 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/hitches.py +145 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/summary.py +243 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/swiftui.py +195 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/time_profiler.py +135 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/xctrace.py +117 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/xml_utils.py +224 -0
- package/.local/skills/swiftui-expert-skill/scripts/record_trace.py +252 -0
- package/.local/skills/swiftui-liquid-glass/SKILL.md +90 -0
- package/.local/skills/swiftui-liquid-glass/agents/openai.yaml +4 -0
- package/.local/skills/swiftui-liquid-glass/references/liquid-glass.md +280 -0
- package/.local/skills/swiftui-performance-audit/SKILL.md +106 -0
- package/.local/skills/swiftui-performance-audit/agents/openai.yaml +4 -0
- package/.local/skills/swiftui-performance-audit/references/code-smells.md +150 -0
- package/.local/skills/swiftui-performance-audit/references/demystify-swiftui-performance-wwdc23.md +46 -0
- package/.local/skills/swiftui-performance-audit/references/optimizing-swiftui-performance-instruments.md +29 -0
- package/.local/skills/swiftui-performance-audit/references/profiling-intake.md +44 -0
- package/.local/skills/swiftui-performance-audit/references/report-template.md +47 -0
- package/.local/skills/swiftui-performance-audit/references/understanding-hangs-in-your-app.md +33 -0
- package/.local/skills/swiftui-performance-audit/references/understanding-improving-swiftui-performance.md +52 -0
- package/.local/skills/swiftui-pro/SKILL.md +108 -0
- package/.local/skills/swiftui-pro/agents/openai.yaml +10 -0
- package/.local/skills/swiftui-pro/assets/swiftui-pro-icon.png +0 -0
- package/.local/skills/swiftui-pro/assets/swiftui-pro-icon.svg +29 -0
- package/.local/skills/swiftui-pro/references/accessibility.md +13 -0
- package/.local/skills/swiftui-pro/references/api.md +39 -0
- package/.local/skills/swiftui-pro/references/data.md +43 -0
- package/.local/skills/swiftui-pro/references/design.md +32 -0
- package/.local/skills/swiftui-pro/references/hygiene.md +9 -0
- package/.local/skills/swiftui-pro/references/navigation.md +14 -0
- package/.local/skills/swiftui-pro/references/performance.md +46 -0
- package/.local/skills/swiftui-pro/references/swift.md +56 -0
- package/.local/skills/swiftui-pro/references/views.md +36 -0
- package/.local/skills/swiftui-ui-patterns/SKILL.md +95 -0
- package/.local/skills/swiftui-ui-patterns/agents/openai.yaml +4 -0
- package/.local/skills/swiftui-ui-patterns/references/app-wiring.md +201 -0
- package/.local/skills/swiftui-ui-patterns/references/async-state.md +96 -0
- package/.local/skills/swiftui-ui-patterns/references/components-index.md +50 -0
- package/.local/skills/swiftui-ui-patterns/references/controls.md +57 -0
- package/.local/skills/swiftui-ui-patterns/references/deeplinks.md +66 -0
- package/.local/skills/swiftui-ui-patterns/references/focus.md +90 -0
- package/.local/skills/swiftui-ui-patterns/references/form.md +97 -0
- package/.local/skills/swiftui-ui-patterns/references/grids.md +71 -0
- package/.local/skills/swiftui-ui-patterns/references/haptics.md +71 -0
- package/.local/skills/swiftui-ui-patterns/references/input-toolbar.md +51 -0
- package/.local/skills/swiftui-ui-patterns/references/lightweight-clients.md +93 -0
- package/.local/skills/swiftui-ui-patterns/references/list.md +86 -0
- package/.local/skills/swiftui-ui-patterns/references/loading-placeholders.md +38 -0
- package/.local/skills/swiftui-ui-patterns/references/macos-settings.md +71 -0
- package/.local/skills/swiftui-ui-patterns/references/matched-transitions.md +59 -0
- package/.local/skills/swiftui-ui-patterns/references/media.md +73 -0
- package/.local/skills/swiftui-ui-patterns/references/menu-bar.md +101 -0
- package/.local/skills/swiftui-ui-patterns/references/navigationstack.md +159 -0
- package/.local/skills/swiftui-ui-patterns/references/overlay.md +45 -0
- package/.local/skills/swiftui-ui-patterns/references/performance.md +62 -0
- package/.local/skills/swiftui-ui-patterns/references/previews.md +48 -0
- package/.local/skills/swiftui-ui-patterns/references/scroll-reveal.md +133 -0
- package/.local/skills/swiftui-ui-patterns/references/scrollview.md +87 -0
- package/.local/skills/swiftui-ui-patterns/references/searchable.md +71 -0
- package/.local/skills/swiftui-ui-patterns/references/sheets.md +155 -0
- package/.local/skills/swiftui-ui-patterns/references/split-views.md +72 -0
- package/.local/skills/swiftui-ui-patterns/references/tabview.md +114 -0
- package/.local/skills/swiftui-ui-patterns/references/theming.md +71 -0
- package/.local/skills/swiftui-ui-patterns/references/title-menus.md +93 -0
- package/.local/skills/swiftui-ui-patterns/references/top-bar.md +49 -0
- package/.local/skills/swiftui-view-refactor/SKILL.md +202 -0
- package/.local/skills/swiftui-view-refactor/agents/openai.yaml +4 -0
- package/.local/skills/swiftui-view-refactor/references/mv-patterns.md +161 -0
- package/bundled/manifest.json +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# sim-screenshot.sh — Stage 5: iOS Simulator render + capture for SwiftUI snapshot host
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# sim-screenshot.sh --probe
|
|
6
|
+
# Print capability JSON to stdout and exit 0.
|
|
7
|
+
# { "schema":"h5-to-swiftui/simprobe@1", "xcode":bool, "simctl":bool,
|
|
8
|
+
# "xcodebuild":bool, "available_runtimes":[...],
|
|
9
|
+
# "stage5_ready":bool, "ok":bool }
|
|
10
|
+
# stage5_ready is true ONLY iff every required tool is present AND at
|
|
11
|
+
# least one simulator runtime is available — tools-present alone is
|
|
12
|
+
# misleading (you cannot capture without a runtime). ok mirrors
|
|
13
|
+
# stage5_ready. The probe itself always exits 0 (diagnostic only).
|
|
14
|
+
#
|
|
15
|
+
# sim-screenshot.sh --project <path> --scheme <scheme> --device "iPhone 15 Pro"
|
|
16
|
+
# --component <Name> --out <output.png>
|
|
17
|
+
# Build the snapshot host project, boot the simulator, capture the
|
|
18
|
+
# per-component snapshot and write it to <output.png>.
|
|
19
|
+
# Exit 0 on success.
|
|
20
|
+
#
|
|
21
|
+
# sim-screenshot.sh --help
|
|
22
|
+
# Print this usage and exit 0.
|
|
23
|
+
#
|
|
24
|
+
# Capability gate (no-fake spine):
|
|
25
|
+
# If xcrun simctl or xcodebuild is unavailable, the build fails, OR the
|
|
26
|
+
# --project path does not exist (cannot yield a build artifact), writes
|
|
27
|
+
# blocked.json next to --out and exits 3.
|
|
28
|
+
# Build failure NEVER produces a PNG. No fake convergence. Only pure usage
|
|
29
|
+
# errors (missing required flags) exit 1.
|
|
30
|
+
#
|
|
31
|
+
# Simulator selection:
|
|
32
|
+
# The first available runtime for the requested device model is used.
|
|
33
|
+
# "Available" means listed by xcrun simctl list devices --json. If multiple
|
|
34
|
+
# runtimes match, the highest-version one is selected (sort -r on the
|
|
35
|
+
# runtime identifier, which is lexicographically ordered by version).
|
|
36
|
+
# The selected runtime and device UDID are recorded in the blocked.json on
|
|
37
|
+
# failure and in a companion .meta.json on success.
|
|
38
|
+
#
|
|
39
|
+
# Dependencies:
|
|
40
|
+
# xcrun (Xcode command-line tools), simctl, xcodebuild
|
|
41
|
+
# All are checked at runtime; missing tools => blocked.json + exit 3.
|
|
42
|
+
#
|
|
43
|
+
# Exit codes:
|
|
44
|
+
# 0 -- success (PNG written) OR probe completed OR --help
|
|
45
|
+
# 1 -- pure usage error (missing required flags)
|
|
46
|
+
# 3 -- capability gate: no-xcode | build-failed | no-runtime |
|
|
47
|
+
# project-missing | capture-failed (blocked.json written)
|
|
48
|
+
#
|
|
49
|
+
# POSIX bash; set -euo pipefail.
|
|
50
|
+
|
|
51
|
+
set -euo pipefail
|
|
52
|
+
|
|
53
|
+
# ── Constants ─────────────────────────────────────────────────────────────────
|
|
54
|
+
|
|
55
|
+
SCHEMA_BLOCKED="h5-to-swiftui/blocked@1"
|
|
56
|
+
SCHEMA_PROBE="h5-to-swiftui/simprobe@1"
|
|
57
|
+
STAGE="5"
|
|
58
|
+
|
|
59
|
+
# ── Helpers ───────────────────────────────────────────────────────────────────
|
|
60
|
+
|
|
61
|
+
die() {
|
|
62
|
+
echo "Error: $*" >&2
|
|
63
|
+
exit 1
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# Write blocked.json next to --out path.
|
|
67
|
+
# $1 out_path $2 component $3 reason
|
|
68
|
+
# $4.. optional extra fields, each as a literal "key=value" token; every
|
|
69
|
+
# extra is emitted as its own JSON string line (valid + consistent
|
|
70
|
+
# with the probe/meta artifacts — no same-line concatenation).
|
|
71
|
+
write_blocked() {
|
|
72
|
+
local out_path="$1"
|
|
73
|
+
local component="$2"
|
|
74
|
+
local reason="$3"
|
|
75
|
+
shift 3
|
|
76
|
+
|
|
77
|
+
local blocked_path
|
|
78
|
+
blocked_path="$(dirname "$out_path")/blocked.json"
|
|
79
|
+
|
|
80
|
+
# Base fields, one key per line.
|
|
81
|
+
{
|
|
82
|
+
printf '{\n'
|
|
83
|
+
printf ' "schema": "%s",\n' "$SCHEMA_BLOCKED"
|
|
84
|
+
printf ' "stage": "%s",\n' "$STAGE"
|
|
85
|
+
printf ' "component": "%s",\n' "$component"
|
|
86
|
+
# reason is last UNLESS extras follow; emit comma conditionally.
|
|
87
|
+
if [ "$#" -gt 0 ]; then
|
|
88
|
+
printf ' "reason": "%s",\n' "$reason"
|
|
89
|
+
local n=$#
|
|
90
|
+
local idx=0
|
|
91
|
+
local pair key val
|
|
92
|
+
for pair in "$@"; do
|
|
93
|
+
idx=$((idx + 1))
|
|
94
|
+
key="${pair%%=*}"
|
|
95
|
+
val="${pair#*=}"
|
|
96
|
+
if [ "$idx" -lt "$n" ]; then
|
|
97
|
+
printf ' "%s": "%s",\n' "$key" "$val"
|
|
98
|
+
else
|
|
99
|
+
printf ' "%s": "%s"\n' "$key" "$val"
|
|
100
|
+
fi
|
|
101
|
+
done
|
|
102
|
+
else
|
|
103
|
+
printf ' "reason": "%s"\n' "$reason"
|
|
104
|
+
fi
|
|
105
|
+
printf '}\n'
|
|
106
|
+
} > "$blocked_path"
|
|
107
|
+
|
|
108
|
+
echo "Wrote: $blocked_path" >&2
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# Check whether a command exists on PATH
|
|
112
|
+
have_cmd() {
|
|
113
|
+
command -v "$1" > /dev/null 2>&1
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
# ── Probe mode ────────────────────────────────────────────────────────────────
|
|
117
|
+
|
|
118
|
+
do_probe() {
|
|
119
|
+
local has_xcode=false
|
|
120
|
+
local has_simctl=false
|
|
121
|
+
local has_xcodebuild=false
|
|
122
|
+
local runtimes_json='[]'
|
|
123
|
+
|
|
124
|
+
if have_cmd xcrun; then
|
|
125
|
+
has_xcode=true
|
|
126
|
+
|
|
127
|
+
# simctl
|
|
128
|
+
if xcrun simctl help > /dev/null 2>&1; then
|
|
129
|
+
has_simctl=true
|
|
130
|
+
|
|
131
|
+
# Collect available runtimes (name field where isAvailable=true).
|
|
132
|
+
# Use awk for POSIX portability; store the program in a variable to
|
|
133
|
+
# avoid single-quote nesting issues.
|
|
134
|
+
local raw
|
|
135
|
+
raw="$(xcrun simctl list runtimes --json 2>/dev/null || printf '{}')"
|
|
136
|
+
|
|
137
|
+
# awk program: emit JSON array of runtime name strings
|
|
138
|
+
local awk_prog
|
|
139
|
+
awk_prog='BEGIN { is_avail=0; name=""; first=1; printf "[" }
|
|
140
|
+
/"isAvailable"[[:space:]]*:[[:space:]]*true/ { is_avail=1 }
|
|
141
|
+
/"name"[[:space:]]*:/ {
|
|
142
|
+
n=split($0,a,"\""); for(i=1;i<=n;i++) { if(a[i]=="name") { name=a[i+2]; break } }
|
|
143
|
+
}
|
|
144
|
+
/^[[:space:]]*\}/ {
|
|
145
|
+
if (is_avail && name != "") {
|
|
146
|
+
if (!first) printf ","
|
|
147
|
+
printf "\"%s\"", name
|
|
148
|
+
first=0
|
|
149
|
+
}
|
|
150
|
+
is_avail=0; name=""
|
|
151
|
+
}
|
|
152
|
+
END { printf "]\n" }'
|
|
153
|
+
|
|
154
|
+
runtimes_json="$(printf '%s' "$raw" | awk "$awk_prog" 2>/dev/null || printf '[]')"
|
|
155
|
+
fi
|
|
156
|
+
|
|
157
|
+
# xcodebuild
|
|
158
|
+
if xcrun xcodebuild -version > /dev/null 2>&1; then
|
|
159
|
+
has_xcodebuild=true
|
|
160
|
+
fi
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
# Tools present?
|
|
164
|
+
local tools_present=true
|
|
165
|
+
if [ "$has_xcode" = "false" ] || [ "$has_simctl" = "false" ] || [ "$has_xcodebuild" = "false" ]; then
|
|
166
|
+
tools_present=false
|
|
167
|
+
fi
|
|
168
|
+
|
|
169
|
+
# At least one runtime available? (runtimes_json is "[]" when none)
|
|
170
|
+
local has_runtime=false
|
|
171
|
+
if [ "$runtimes_json" != "[]" ] && [ -n "$runtimes_json" ]; then
|
|
172
|
+
has_runtime=true
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
# stage5_ready: tools AND >=1 runtime. Tools-present alone is misleading —
|
|
176
|
+
# a capture cannot happen without a runtime, so ok must reflect that.
|
|
177
|
+
local stage5_ready=false
|
|
178
|
+
if [ "$tools_present" = "true" ] && [ "$has_runtime" = "true" ]; then
|
|
179
|
+
stage5_ready=true
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
printf '{\n "schema": "%s",\n "xcode": %s,\n "simctl": %s,\n "xcodebuild": %s,\n "available_runtimes": %s,\n "stage5_ready": %s,\n "ok": %s\n}\n' \
|
|
183
|
+
"$SCHEMA_PROBE" \
|
|
184
|
+
"$has_xcode" \
|
|
185
|
+
"$has_simctl" \
|
|
186
|
+
"$has_xcodebuild" \
|
|
187
|
+
"$runtimes_json" \
|
|
188
|
+
"$stage5_ready" \
|
|
189
|
+
"$stage5_ready"
|
|
190
|
+
|
|
191
|
+
exit 0
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
# ── Capability check (for non-probe modes) ────────────────────────────────────
|
|
195
|
+
|
|
196
|
+
# Returns 0 if all required tools are present, sets BLOCK_REASON on failure.
|
|
197
|
+
BLOCK_REASON=""
|
|
198
|
+
check_capabilities() {
|
|
199
|
+
if ! have_cmd xcrun; then
|
|
200
|
+
BLOCK_REASON="no-xcode"
|
|
201
|
+
return 1
|
|
202
|
+
fi
|
|
203
|
+
if ! xcrun simctl help > /dev/null 2>&1; then
|
|
204
|
+
BLOCK_REASON="no-xcode"
|
|
205
|
+
return 1
|
|
206
|
+
fi
|
|
207
|
+
if ! xcrun xcodebuild -version > /dev/null 2>&1; then
|
|
208
|
+
BLOCK_REASON="no-xcode"
|
|
209
|
+
return 1
|
|
210
|
+
fi
|
|
211
|
+
return 0
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
# ── Runtime + device selection ────────────────────────────────────────────────
|
|
215
|
+
|
|
216
|
+
# Finds the best available simulator for the requested device model.
|
|
217
|
+
# Outputs: <runtime_identifier>|<udid> (single line, highest version first)
|
|
218
|
+
# Returns 1 (empty output) if no matching device/runtime is found.
|
|
219
|
+
find_simulator() {
|
|
220
|
+
local device_model="$1" # e.g. "iPhone 15 Pro"
|
|
221
|
+
|
|
222
|
+
# List all available devices as JSON
|
|
223
|
+
local raw
|
|
224
|
+
raw="$(xcrun simctl list devices --json 2>/dev/null || printf '{}')"
|
|
225
|
+
|
|
226
|
+
# awk program stored in variable to avoid single-quote quoting issues.
|
|
227
|
+
# Walk the JSON; track current runtime key; for each device entry matching
|
|
228
|
+
# device_model with isAvailable=true, emit "runtime|udid".
|
|
229
|
+
local awk_prog
|
|
230
|
+
awk_prog='BEGIN { cur_rt=""; cur_name=""; cur_udid=""; cur_avail=0 }
|
|
231
|
+
/^[[:space:]]*"com\.apple\.CoreSimulator\.SimRuntime\./ {
|
|
232
|
+
n=split($0,a,"\""); for(i=1;i<=n;i++) {
|
|
233
|
+
if(a[i] ~ /^com\.apple\.CoreSimulator\.SimRuntime\./) { cur_rt=a[i]; break }
|
|
234
|
+
}
|
|
235
|
+
cur_name=""; cur_udid=""; cur_avail=0
|
|
236
|
+
}
|
|
237
|
+
/"name"[[:space:]]*:/ {
|
|
238
|
+
n=split($0,a,"\""); for(i=1;i<=n;i++) { if(a[i]=="name") { cur_name=a[i+2]; break } }
|
|
239
|
+
}
|
|
240
|
+
/"udid"[[:space:]]*:/ {
|
|
241
|
+
n=split($0,a,"\""); for(i=1;i<=n;i++) { if(a[i]=="udid") { cur_udid=a[i+2]; break } }
|
|
242
|
+
}
|
|
243
|
+
/"isAvailable"[[:space:]]*:[[:space:]]*true/ { cur_avail=1 }
|
|
244
|
+
/^[[:space:]]*\}/ {
|
|
245
|
+
if (cur_avail && cur_name==model && cur_udid!="") {
|
|
246
|
+
print cur_rt "|" cur_udid
|
|
247
|
+
}
|
|
248
|
+
cur_avail=0; cur_name=""; cur_udid=""
|
|
249
|
+
}'
|
|
250
|
+
|
|
251
|
+
printf '%s' "$raw" | awk -v model="$device_model" "$awk_prog" | sort -r | head -1
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
# ── Build snapshot host ───────────────────────────────────────────────────────
|
|
255
|
+
|
|
256
|
+
build_snapshot_host() {
|
|
257
|
+
local project_path="$1"
|
|
258
|
+
local scheme="$2"
|
|
259
|
+
local sdk="$3" # e.g. "iphonesimulator"
|
|
260
|
+
local destination="$4" # xcodebuild -destination value
|
|
261
|
+
local build_log="$5"
|
|
262
|
+
|
|
263
|
+
xcrun xcodebuild \
|
|
264
|
+
-project "$project_path" \
|
|
265
|
+
-scheme "$scheme" \
|
|
266
|
+
-sdk "$sdk" \
|
|
267
|
+
-destination "$destination" \
|
|
268
|
+
-configuration Debug \
|
|
269
|
+
build \
|
|
270
|
+
> "$build_log" 2>&1
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
# ── Main capture flow ─────────────────────────────────────────────────────────
|
|
274
|
+
|
|
275
|
+
do_capture() {
|
|
276
|
+
local project_path="$1"
|
|
277
|
+
local scheme="$2"
|
|
278
|
+
local device_model="$3"
|
|
279
|
+
local component="$4"
|
|
280
|
+
local out_png="$5"
|
|
281
|
+
|
|
282
|
+
local out_dir
|
|
283
|
+
out_dir="$(dirname "$out_png")"
|
|
284
|
+
mkdir -p "$out_dir"
|
|
285
|
+
|
|
286
|
+
# 1. Capability gate
|
|
287
|
+
if ! check_capabilities; then
|
|
288
|
+
echo "Error: required toolchain unavailable: $BLOCK_REASON" >&2
|
|
289
|
+
echo "Install Xcode and command-line tools, then re-run." >&2
|
|
290
|
+
write_blocked "$out_png" "$component" "$BLOCK_REASON"
|
|
291
|
+
exit 3
|
|
292
|
+
fi
|
|
293
|
+
|
|
294
|
+
# 2. Find simulator
|
|
295
|
+
echo "Looking for simulator: $device_model" >&2
|
|
296
|
+
local sim_info
|
|
297
|
+
sim_info="$(find_simulator "$device_model" || true)"
|
|
298
|
+
|
|
299
|
+
if [ -z "$sim_info" ]; then
|
|
300
|
+
echo "Error: no available simulator found for device \"$device_model\"." >&2
|
|
301
|
+
echo "Run: xcrun simctl list devices" >&2
|
|
302
|
+
write_blocked "$out_png" "$component" "no-runtime" \
|
|
303
|
+
"device=$device_model"
|
|
304
|
+
exit 3
|
|
305
|
+
fi
|
|
306
|
+
|
|
307
|
+
local runtime_id udid
|
|
308
|
+
runtime_id="${sim_info%%|*}"
|
|
309
|
+
udid="${sim_info##*|}"
|
|
310
|
+
|
|
311
|
+
echo "Selected runtime: $runtime_id" >&2
|
|
312
|
+
echo "Selected UDID: $udid" >&2
|
|
313
|
+
|
|
314
|
+
# Extract human-readable runtime name from the identifier
|
|
315
|
+
# e.g. com.apple.CoreSimulator.SimRuntime.iOS-17-5 -> iOS 17.5
|
|
316
|
+
local runtime_name
|
|
317
|
+
runtime_name="$(printf '%s' "$runtime_id" | sed -E 's/.*\.iOS-([0-9]+)-([0-9]+)$/iOS \1.\2/')"
|
|
318
|
+
echo "Runtime name: $runtime_name" >&2
|
|
319
|
+
|
|
320
|
+
# 3. Build the snapshot host project
|
|
321
|
+
echo "Building $scheme in $project_path ..." >&2
|
|
322
|
+
local build_log
|
|
323
|
+
build_log="$(mktemp /tmp/sim-screenshot-build.XXXXXX.log)"
|
|
324
|
+
|
|
325
|
+
local sdk="iphonesimulator"
|
|
326
|
+
local destination="platform=iOS Simulator,id=$udid"
|
|
327
|
+
|
|
328
|
+
if ! build_snapshot_host "$project_path" "$scheme" "$sdk" "$destination" "$build_log"; then
|
|
329
|
+
echo "Error: xcodebuild failed. Build log: $build_log" >&2
|
|
330
|
+
echo "--- Last 20 lines of build log ---" >&2
|
|
331
|
+
tail -20 "$build_log" >&2
|
|
332
|
+
echo "----------------------------------" >&2
|
|
333
|
+
write_blocked "$out_png" "$component" "build-failed" \
|
|
334
|
+
"build_log=$build_log" "runtime=$runtime_name" "udid=$udid"
|
|
335
|
+
# NEVER produce a png on build failure
|
|
336
|
+
exit 3
|
|
337
|
+
fi
|
|
338
|
+
|
|
339
|
+
echo "Build succeeded." >&2
|
|
340
|
+
rm -f "$build_log"
|
|
341
|
+
|
|
342
|
+
# 4. Boot simulator (idempotent -- already booted is fine)
|
|
343
|
+
echo "Booting simulator $udid ..." >&2
|
|
344
|
+
|
|
345
|
+
# Check current sim state using awk (stored in variable to avoid quoting issues)
|
|
346
|
+
local awk_state
|
|
347
|
+
awk_state='BEGIN { found=0 }
|
|
348
|
+
/"udid"/ { if ($0 ~ udid) found=1 }
|
|
349
|
+
/"state"/ {
|
|
350
|
+
if (found) {
|
|
351
|
+
n=split($0,a,"\""); for(i=1;i<=n;i++) { if(a[i]=="state") { print a[i+2]; found=0; break } }
|
|
352
|
+
}
|
|
353
|
+
}'
|
|
354
|
+
local boot_status
|
|
355
|
+
boot_status="$(xcrun simctl list devices --json 2>/dev/null | \
|
|
356
|
+
awk -v udid="$udid" "$awk_state" | head -1 || true)"
|
|
357
|
+
|
|
358
|
+
if [ "$boot_status" != "Booted" ]; then
|
|
359
|
+
xcrun simctl boot "$udid" 2>&1 | sed 's/^/ [simctl boot] /' >&2 || true
|
|
360
|
+
# Wait for boot completion (bootstatus blocks until the sim is ready)
|
|
361
|
+
xcrun simctl bootstatus "$udid" -b >&2 || true
|
|
362
|
+
else
|
|
363
|
+
echo "Simulator already booted." >&2
|
|
364
|
+
fi
|
|
365
|
+
|
|
366
|
+
# 5. Launch the app / snapshot host
|
|
367
|
+
# The snapshot host is expected to write a PNG when launched with the
|
|
368
|
+
# component name as a launch argument. We launch it, wait for render,
|
|
369
|
+
# then capture with simctl io screenshot.
|
|
370
|
+
local bundle_id="$scheme"
|
|
371
|
+
|
|
372
|
+
echo "Launching snapshot host for component: $component ..." >&2
|
|
373
|
+
if ! xcrun simctl launch "$udid" "$bundle_id" \
|
|
374
|
+
--component "$component" \
|
|
375
|
+
2>&1 | sed 's/^/ [simctl launch] /' >&2; then
|
|
376
|
+
echo "Error: simctl launch failed for bundle $bundle_id on $udid." >&2
|
|
377
|
+
write_blocked "$out_png" "$component" "build-failed" \
|
|
378
|
+
"detail=simctl launch failed" "bundle_id=$bundle_id" "runtime=$runtime_name" "udid=$udid"
|
|
379
|
+
exit 3
|
|
380
|
+
fi
|
|
381
|
+
|
|
382
|
+
# Give the app time to render the snapshot
|
|
383
|
+
sleep 2
|
|
384
|
+
|
|
385
|
+
# 6. Capture screenshot via simctl io
|
|
386
|
+
echo "Capturing screenshot from simulator ..." >&2
|
|
387
|
+
if ! xcrun simctl io "$udid" screenshot "$out_png" 2>&1 | sed 's/^/ [simctl io] /' >&2; then
|
|
388
|
+
echo "Error: simctl io screenshot failed." >&2
|
|
389
|
+
write_blocked "$out_png" "$component" "build-failed" \
|
|
390
|
+
"detail=simctl io screenshot failed" "runtime=$runtime_name" "udid=$udid"
|
|
391
|
+
exit 3
|
|
392
|
+
fi
|
|
393
|
+
|
|
394
|
+
if [ ! -f "$out_png" ]; then
|
|
395
|
+
echo "Error: screenshot not found at $out_png after capture." >&2
|
|
396
|
+
write_blocked "$out_png" "$component" "build-failed" \
|
|
397
|
+
"detail=output PNG not produced" "runtime=$runtime_name" "udid=$udid"
|
|
398
|
+
exit 3
|
|
399
|
+
fi
|
|
400
|
+
|
|
401
|
+
# 7. Write companion .meta.json
|
|
402
|
+
local meta_path="${out_png%.png}.meta.json"
|
|
403
|
+
local ts
|
|
404
|
+
ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
405
|
+
printf '{\n "schema": "h5-to-swiftui/simsnapshot@1",\n "component": "%s",\n "device": "%s",\n "runtime": "%s",\n "udid": "%s",\n "png": "%s",\n "captured_at": "%s"\n}\n' \
|
|
406
|
+
"$component" "$device_model" "$runtime_name" "$udid" "$out_png" "$ts" > "$meta_path"
|
|
407
|
+
|
|
408
|
+
echo "Screenshot: $out_png" >&2
|
|
409
|
+
echo "Meta: $meta_path" >&2
|
|
410
|
+
echo "Capture complete." >&2
|
|
411
|
+
exit 0
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
# ── CLI dispatch ──────────────────────────────────────────────────────────────
|
|
415
|
+
|
|
416
|
+
if [ $# -eq 0 ]; then
|
|
417
|
+
echo "Error: no arguments given. Run with --help for usage." >&2
|
|
418
|
+
exit 1
|
|
419
|
+
fi
|
|
420
|
+
|
|
421
|
+
# Handle --help first (before set -e touches anything)
|
|
422
|
+
for arg in "$@"; do
|
|
423
|
+
if [ "$arg" = "--help" ] || [ "$arg" = "-h" ]; then
|
|
424
|
+
printf '%s\n' \
|
|
425
|
+
"sim-screenshot.sh -- Stage 5: iOS Simulator render + capture" \
|
|
426
|
+
"" \
|
|
427
|
+
"Usage:" \
|
|
428
|
+
" sim-screenshot.sh --probe" \
|
|
429
|
+
" Print capability JSON to stdout and exit 0. The JSON includes" \
|
|
430
|
+
" stage5_ready (true iff tools present AND >=1 runtime); ok mirrors" \
|
|
431
|
+
" stage5_ready — tools-present alone is NOT enough to capture." \
|
|
432
|
+
"" \
|
|
433
|
+
" sim-screenshot.sh --project <path> --scheme <scheme> \\" \
|
|
434
|
+
" --device \"iPhone 15 Pro\" \\" \
|
|
435
|
+
" --component <Name> --out <output.png>" \
|
|
436
|
+
" Build the snapshot host, boot the simulator, capture the per-component" \
|
|
437
|
+
" snapshot, and write it to <output.png>. Exit 0 on success." \
|
|
438
|
+
"" \
|
|
439
|
+
" sim-screenshot.sh --help" \
|
|
440
|
+
" Print this usage and exit 0." \
|
|
441
|
+
"" \
|
|
442
|
+
"Arguments (capture mode):" \
|
|
443
|
+
" --project <path> Path to the .xcodeproj snapshot host project (required)" \
|
|
444
|
+
" --scheme <scheme> Xcode scheme to build; also used as the app bundle ID (required)" \
|
|
445
|
+
" --device <name> Device model, e.g. \"iPhone 15 Pro\" (required)" \
|
|
446
|
+
" --component <Name> SwiftUI component name to snapshot (required)" \
|
|
447
|
+
" --out <path> Output PNG path (required)" \
|
|
448
|
+
"" \
|
|
449
|
+
"Capability gate (no-fake spine):" \
|
|
450
|
+
" If xcrun simctl/xcodebuild is unavailable, the build fails, OR the" \
|
|
451
|
+
" --project path does not exist (cannot yield a build artifact), this" \
|
|
452
|
+
" writes blocked.json next to --out and exits 3. Build failure NEVER" \
|
|
453
|
+
" produces a PNG. Only pure usage errors (missing required flags) exit 1." \
|
|
454
|
+
"" \
|
|
455
|
+
"Simulator selection:" \
|
|
456
|
+
" The highest-version available runtime matching the requested device model" \
|
|
457
|
+
" is selected via xcrun simctl list devices --json. The selection is" \
|
|
458
|
+
" recorded in the .meta.json companion file written on success." \
|
|
459
|
+
"" \
|
|
460
|
+
"Exit codes:" \
|
|
461
|
+
" 0 Success (PNG written) or probe completed" \
|
|
462
|
+
" 1 Pure usage error (missing required flags)" \
|
|
463
|
+
" 3 Capability gate: no-xcode | build-failed | no-runtime |" \
|
|
464
|
+
" project-missing | capture-failed (blocked.json written)" \
|
|
465
|
+
"" \
|
|
466
|
+
"Examples:" \
|
|
467
|
+
" sim-screenshot.sh --probe" \
|
|
468
|
+
" sim-screenshot.sh --project SnapshotHost.xcodeproj \\" \
|
|
469
|
+
" --scheme com.example.SnapshotHost \\" \
|
|
470
|
+
" --device \"iPhone 15 Pro\" \\" \
|
|
471
|
+
" --component ProductCard \\" \
|
|
472
|
+
" --out artifacts/ProductCard.png"
|
|
473
|
+
exit 0
|
|
474
|
+
fi
|
|
475
|
+
done
|
|
476
|
+
|
|
477
|
+
# Handle --probe
|
|
478
|
+
for arg in "$@"; do
|
|
479
|
+
if [ "$arg" = "--probe" ]; then
|
|
480
|
+
do_probe
|
|
481
|
+
# do_probe calls exit 0 internally
|
|
482
|
+
fi
|
|
483
|
+
done
|
|
484
|
+
|
|
485
|
+
# Parse capture-mode arguments
|
|
486
|
+
PROJECT_PATH=""
|
|
487
|
+
SCHEME=""
|
|
488
|
+
DEVICE_MODEL=""
|
|
489
|
+
COMPONENT=""
|
|
490
|
+
OUT_PNG=""
|
|
491
|
+
|
|
492
|
+
while [ $# -gt 0 ]; do
|
|
493
|
+
case "$1" in
|
|
494
|
+
--project)
|
|
495
|
+
[ $# -ge 2 ] || die "--project requires an argument."
|
|
496
|
+
PROJECT_PATH="$2"; shift 2 ;;
|
|
497
|
+
--scheme)
|
|
498
|
+
[ $# -ge 2 ] || die "--scheme requires an argument."
|
|
499
|
+
SCHEME="$2"; shift 2 ;;
|
|
500
|
+
--device)
|
|
501
|
+
[ $# -ge 2 ] || die "--device requires an argument."
|
|
502
|
+
DEVICE_MODEL="$2"; shift 2 ;;
|
|
503
|
+
--component)
|
|
504
|
+
[ $# -ge 2 ] || die "--component requires an argument."
|
|
505
|
+
COMPONENT="$2"; shift 2 ;;
|
|
506
|
+
--out)
|
|
507
|
+
[ $# -ge 2 ] || die "--out requires an argument."
|
|
508
|
+
OUT_PNG="$2"; shift 2 ;;
|
|
509
|
+
--sim-runtime|--browser|--model-id)
|
|
510
|
+
# Accepted but unused in capture mode (informational flags for callers)
|
|
511
|
+
shift 2 ;;
|
|
512
|
+
*)
|
|
513
|
+
die "Unknown argument: $1. Run with --help for usage." ;;
|
|
514
|
+
esac
|
|
515
|
+
done
|
|
516
|
+
|
|
517
|
+
# Validate required capture-mode args
|
|
518
|
+
MISSING_ARGS=""
|
|
519
|
+
[ -z "$PROJECT_PATH" ] && MISSING_ARGS="$MISSING_ARGS --project"
|
|
520
|
+
[ -z "$SCHEME" ] && MISSING_ARGS="$MISSING_ARGS --scheme"
|
|
521
|
+
[ -z "$DEVICE_MODEL" ] && MISSING_ARGS="$MISSING_ARGS --device"
|
|
522
|
+
[ -z "$COMPONENT" ] && MISSING_ARGS="$MISSING_ARGS --component"
|
|
523
|
+
[ -z "$OUT_PNG" ] && MISSING_ARGS="$MISSING_ARGS --out"
|
|
524
|
+
|
|
525
|
+
if [ -n "$MISSING_ARGS" ]; then
|
|
526
|
+
echo "Error: missing required arguments:$MISSING_ARGS" >&2
|
|
527
|
+
echo "Run with --help for usage." >&2
|
|
528
|
+
exit 1
|
|
529
|
+
fi
|
|
530
|
+
|
|
531
|
+
# A --project that does not exist is a capture-mode path that cannot yield a
|
|
532
|
+
# build artifact. It MUST go through the no-fake guarantee: write_blocked
|
|
533
|
+
# (stage 5, reason project-missing) and exit 3 — never a bare exit 1, which
|
|
534
|
+
# would bypass the no-fake-success spine. (Pure usage errors above still exit 1.)
|
|
535
|
+
if [ ! -e "$PROJECT_PATH" ]; then
|
|
536
|
+
echo "Error: --project not found: $PROJECT_PATH" >&2
|
|
537
|
+
echo "Cannot produce a build artifact — blocking (no fake success)." >&2
|
|
538
|
+
mkdir -p "$(dirname "$OUT_PNG")"
|
|
539
|
+
write_blocked "$OUT_PNG" "$COMPONENT" "project-missing" \
|
|
540
|
+
"detail=--project path does not exist" "project=$PROJECT_PATH"
|
|
541
|
+
exit 3
|
|
542
|
+
fi
|
|
543
|
+
|
|
544
|
+
do_capture "$PROJECT_PATH" "$SCHEME" "$DEVICE_MODEL" "$COMPONENT" "$OUT_PNG"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ios-debugger-agent
|
|
3
|
+
description: Use XcodeBuildMCP to build, run, launch, and debug the current iOS project on a booted simulator. Trigger when asked to run an iOS app, interact with the simulator UI, inspect on-screen state, capture logs/console output, or diagnose runtime behavior using XcodeBuildMCP tools.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# iOS Debugger Agent
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
Use XcodeBuildMCP to build and run the current project scheme on a booted iOS simulator, interact with the UI, and capture logs. Prefer the MCP tools for simulator control, logs, and view inspection.
|
|
10
|
+
|
|
11
|
+
## Core Workflow
|
|
12
|
+
Follow this sequence unless the user asks for a narrower action.
|
|
13
|
+
|
|
14
|
+
### 1) Discover the booted simulator
|
|
15
|
+
- Call `mcp__XcodeBuildMCP__list_sims` and select the simulator with state `Booted`.
|
|
16
|
+
- If none are booted, ask the user to boot one (do not boot automatically unless asked).
|
|
17
|
+
|
|
18
|
+
### 2) Set session defaults
|
|
19
|
+
- Call `mcp__XcodeBuildMCP__session-set-defaults` with:
|
|
20
|
+
- `projectPath` or `workspacePath` (whichever the repo uses)
|
|
21
|
+
- `scheme` for the current app
|
|
22
|
+
- `simulatorId` from the booted device
|
|
23
|
+
- Optional: `configuration: "Debug"`, `useLatestOS: true`
|
|
24
|
+
|
|
25
|
+
### 3) Build + run (when requested)
|
|
26
|
+
- Call `mcp__XcodeBuildMCP__build_run_sim`.
|
|
27
|
+
- **If the build fails**, check the error output and retry (optionally with `preferXcodebuild: true`) or escalate to the user before attempting any UI interaction.
|
|
28
|
+
- **After a successful build**, verify the app launched by calling `mcp__XcodeBuildMCP__describe_ui` or `mcp__XcodeBuildMCP__screenshot` before proceeding to UI interaction.
|
|
29
|
+
- If the app is already built and only launch is requested, use `mcp__XcodeBuildMCP__launch_app_sim`.
|
|
30
|
+
- If bundle id is unknown:
|
|
31
|
+
1) `mcp__XcodeBuildMCP__get_sim_app_path`
|
|
32
|
+
2) `mcp__XcodeBuildMCP__get_app_bundle_id`
|
|
33
|
+
|
|
34
|
+
## UI Interaction & Debugging
|
|
35
|
+
Use these when asked to inspect or interact with the running app.
|
|
36
|
+
|
|
37
|
+
- **Describe UI**: `mcp__XcodeBuildMCP__describe_ui` before tapping or swiping.
|
|
38
|
+
- **Tap**: `mcp__XcodeBuildMCP__tap` (prefer `id` or `label`; use coordinates only if needed).
|
|
39
|
+
- **Type**: `mcp__XcodeBuildMCP__type_text` after focusing a field.
|
|
40
|
+
- **Gestures**: `mcp__XcodeBuildMCP__gesture` for common scrolls and edge swipes.
|
|
41
|
+
- **Screenshot**: `mcp__XcodeBuildMCP__screenshot` for visual confirmation.
|
|
42
|
+
|
|
43
|
+
## Logs & Console Output
|
|
44
|
+
- Start logs: `mcp__XcodeBuildMCP__start_sim_log_cap` with the app bundle id.
|
|
45
|
+
- Stop logs: `mcp__XcodeBuildMCP__stop_sim_log_cap` and summarize important lines.
|
|
46
|
+
- For console output, set `captureConsole: true` and relaunch if required.
|
|
47
|
+
|
|
48
|
+
## Troubleshooting
|
|
49
|
+
- If build fails, ask whether to retry with `preferXcodebuild: true`.
|
|
50
|
+
- If the wrong app launches, confirm the scheme and bundle id.
|
|
51
|
+
- If UI elements are not hittable, re-run `describe_ui` after layout changes.
|