2424 simdeck_artifact_url :
2525 description : Optional URL to a prebuilt simdeck binary tarball
2626 required : false
27+ simdeck_repository :
28+ description : GitHub repository to clone when SimDeck is not present in the target repo
29+ required : false
30+ default : NativeScript/SimDeck
31+ simdeck_ref :
32+ description : Optional SimDeck branch, tag, or SHA to check out
33+ required : false
2734 stream_quality :
2835 description : SimDeck realtime stream quality profile
2936 required : false
3037 default : ci-software
38+ webrtc_ice_servers :
39+ description : Comma-separated ICE server URLs for browser and provider WebRTC
40+ required : false
41+ default : stun:stun.l.google.com:19302
42+ webrtc_ice_username :
43+ description : Optional TURN username
44+ required : false
45+ webrtc_ice_credential :
46+ description : Optional TURN credential
47+ required : false
48+ webrtc_ice_transport_policy :
49+ description : Browser ICE transport policy
50+ required : false
51+ default : all
3152
3253permissions :
3354 actions : read
5071 github-token : ${{ github.token }}
5172 path : simdeck-artifact
5273
53- - name : Install cloudflared
54- shell : bash
55- run : |
56- set -euo pipefail
57- brew install cloudflare/cloudflare/cloudflared
58-
5974 - name : Register provider workflow
6075 shell : bash
6176 env :
7186 \"providerToken\":\"$PROVIDER_TOKEN\",
7287 \"providerRunId\":\"$GITHUB_RUN_ID\",
7388 \"providerRunUrl\":\"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID\",
74- \"status\":\"running \",
89+ \"status\":\"building \",
7590 \"simulatorName\":\"GitHub Actions macOS runner\"
7691 }" \
7792 "$SIMDECK_CLOUD_URL/api/actions/providers/register"
8095 shell : bash
8196 env :
8297 SIMDECK_ARTIFACT_URL : ${{ inputs.simdeck_artifact_url }}
98+ SIMDECK_REPOSITORY : ${{ inputs.simdeck_repository || 'NativeScript/SimDeck' }}
99+ SIMDECK_REF : ${{ inputs.simdeck_ref }}
83100 run : |
84101 set -euo pipefail
85102 if [[ -n "${SIMDECK_ARTIFACT_URL:-}" ]]; then
@@ -90,7 +107,16 @@ jobs:
90107 ./scripts/build-client.sh
91108 ./scripts/build-cli.sh
92109 else
93- git clone --depth 1 https://github.com/NativeScript/SimDeck.git simdeck-src
110+ simdeck_repo="${SIMDECK_REPOSITORY:-NativeScript/SimDeck}"
111+ if [[ ! "$simdeck_repo" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]]; then
112+ echo "Invalid SimDeck repository: $simdeck_repo"
113+ exit 1
114+ fi
115+ clone_args=(--depth 1)
116+ if [[ -n "${SIMDECK_REF:-}" ]]; then
117+ clone_args+=(--branch "$SIMDECK_REF")
118+ fi
119+ git clone "${clone_args[@]}" "https://github.com/$simdeck_repo.git" simdeck-src
94120 ./simdeck-src/scripts/build-client.sh
95121 ./simdeck-src/scripts/build-cli.sh
96122 mkdir -p build
@@ -110,10 +136,34 @@ jobs:
110136 PREVIEW_ID : ${{ inputs.preview_id }}
111137 PROVIDER_TOKEN : ${{ inputs.provider_token }}
112138 BUNDLE_ID : ${{ inputs.bundle_id }}
113- SIMDECK_ALLOWED_ORIGINS : ${{ inputs.simdeck_cloud_url }}
139+ SIMDECK_ALLOWED_ORIGINS : " *"
140+ SIMDECK_WEBRTC_ICE_SERVERS : ${{ inputs.webrtc_ice_servers }}
141+ SIMDECK_WEBRTC_ICE_USERNAME : ${{ inputs.webrtc_ice_username }}
142+ SIMDECK_WEBRTC_ICE_CREDENTIAL : ${{ inputs.webrtc_ice_credential }}
143+ SIMDECK_WEBRTC_ICE_TRANSPORT_POLICY : ${{ inputs.webrtc_ice_transport_policy }}
114144 SIMDECK_STREAM_QUALITY : ${{ inputs.stream_quality || 'ci-software' }}
145+ RUST_LOG : info,wtransport=warn,quinn=warn
146+ RUST_BACKTRACE : full
147+ NSUnbufferedIO : YES
115148 run : |
116149 set -euo pipefail
150+ run_with_timeout() {
151+ local limit="$1"
152+ shift
153+ "$@" &
154+ local pid="$!"
155+ local elapsed=0
156+ while kill -0 "$pid" 2>/dev/null; do
157+ if (( elapsed >= limit )); then
158+ kill "$pid" 2>/dev/null || true
159+ wait "$pid" 2>/dev/null || true
160+ return 124
161+ fi
162+ sleep 1
163+ elapsed=$((elapsed + 1))
164+ done
165+ wait "$pid"
166+ }
117167
118168 ios_udid="$(xcrun simctl list devices available --json | python3 -c '
119169 import json, sys
@@ -129,17 +179,10 @@ jobs:
129179 ')"
130180
131181 xcrun simctl boot "$ios_udid" || true
132- xcrun simctl bootstatus "$ios_udid" -b
133-
134- app_path=""
135- if [[ -d simdeck-artifact ]]; then
136- app_path="$(find simdeck-artifact -maxdepth 6 -type d -name '*.app' | head -n 1 || true)"
137- fi
138- if [[ -n "$app_path" ]]; then
139- xcrun simctl install "$ios_udid" "$app_path"
140- fi
141- if [[ -n "${BUNDLE_ID:-}" ]]; then
142- xcrun simctl launch "$ios_udid" "$BUNDLE_ID" || true
182+ if ! run_with_timeout 180 xcrun simctl bootstatus "$ios_udid" -b; then
183+ echo "simctl bootstatus timed out"
184+ xcrun simctl list devices "$ios_udid" || true
185+ exit 1
143186 fi
144187
145188 ./build/simdeck serve \
@@ -152,11 +195,20 @@ jobs:
152195 > simdeck.log 2>&1 &
153196 simdeck_pid="$!"
154197
198+ dump_logs() {
199+ echo "--- simdeck.log ---"
200+ cat simdeck.log || true
201+ echo "--- private bridge log ---"
202+ cat /tmp/simdeck-private-bridge.log || true
203+ echo "--- crash reports ---"
204+ find "$HOME/Library/Logs/DiagnosticReports" -maxdepth 1 -type f \( -name 'simdeck*.ips' -o -name 'simdeck*.crash' \) -print -exec cat {} \; || true
205+ }
206+
155207 healthy=0
156208 for _ in {1..120}; do
157209 if ! kill -0 "$simdeck_pid" 2>/dev/null; then
158210 echo "simdeck exited before health check passed"
159- cat simdeck.log || true
211+ dump_logs
160212 exit 1
161213 fi
162214 if curl -fsS http://127.0.0.1:4310/api/health >/dev/null; then
@@ -167,28 +219,50 @@ jobs:
167219 done
168220 if [[ "$healthy" != "1" ]]; then
169221 echo "simdeck did not become healthy"
170- cat simdeck.log || true
222+ dump_logs
171223 exit 1
172224 fi
173225
174- cloudflared tunnel --url http://127.0.0.1:4310 \
175- > cloudflared.log 2>&1 &
176- cloudflared_pid="$!"
177-
178- tunnel_url=""
179- for _ in {1..120}; do
180- tunnel_url="$(grep -Eo 'https://[-a-zA-Z0-9.]+\.trycloudflare\.com' cloudflared.log | head -n 1 || true)"
181- if [[ -n "$tunnel_url" ]]; then
182- break
183- fi
184- sleep 1
185- done
226+ echo "Prewarming private simulator stream"
227+ if ! run_with_timeout 60 curl -fsS -X POST "http://127.0.0.1:4310/api/simulators/$ios_udid/refresh?simdeckToken=$PROVIDER_TOKEN"; then
228+ echo "SimDeck private stream prewarm failed"
229+ dump_logs
230+ exit 1
231+ fi
232+ echo
233+ echo "Private simulator stream prewarmed"
186234
187- if [[ -z "$tunnel_url" ]]; then
188- echo "cloudflared did not print a trycloudflare.com URL"
189- cat cloudflared.log || true
235+ provider_base_url="$SIMDECK_CLOUD_URL/simulator/$PREVIEW_ID"
236+ bridge_script="scripts/studio-provider-bridge.mjs"
237+ if [[ ! -f "$bridge_script" && -f "simdeck-src/scripts/studio-provider-bridge.mjs" ]]; then
238+ bridge_script="simdeck-src/scripts/studio-provider-bridge.mjs"
239+ fi
240+ if [[ ! -f "$bridge_script" ]]; then
241+ echo "SimDeck Studio provider bridge script was not found"
190242 exit 1
191243 fi
244+ SIMDECK_LOCAL_URL="http://127.0.0.1:4310" \
245+ SIMDECK_STUDIO_URL="$provider_base_url" \
246+ node "$bridge_script" \
247+ > simdeck-provider-bridge.log 2>&1 &
248+ bridge_pid="$!"
249+
250+ (
251+ while true; do
252+ sleep 15
253+ echo "::group::SimDeck diagnostics $(date -u +%Y-%m-%dT%H:%M:%SZ)"
254+ curl -fsS "http://127.0.0.1:4310/api/metrics" || true
255+ echo
256+ echo "--- simdeck webrtc log tail ---"
257+ grep -E 'WebRTC|ICE|candidate|peer connection|H264|h264|frame write|bootstrap' simdeck.log | tail -n 120 || true
258+ echo "--- private bridge log tail ---"
259+ tail -n 80 /tmp/simdeck-private-bridge.log || true
260+ echo "--- provider bridge log tail ---"
261+ tail -n 40 simdeck-provider-bridge.log || true
262+ echo "::endgroup::"
263+ done
264+ ) &
265+ diagnostics_pid="$!"
192266
193267 register() {
194268 curl -fsS \
@@ -198,7 +272,7 @@ jobs:
198272 \"providerToken\":\"$PROVIDER_TOKEN\",
199273 \"providerRunId\":\"$GITHUB_RUN_ID\",
200274 \"providerRunUrl\":\"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID\",
201- \"baseUrl\":\"$tunnel_url/?simdeckToken=$PROVIDER_TOKEN&transport=webrtc&device=$ios_udid \",
275+ \"baseUrl\":\"$provider_base_url \",
202276 \"simulatorUdid\":\"$ios_udid\",
203277 \"simulatorName\":\"GitHub Actions macOS runner\",
204278 \"runtimeName\":\"$(xcrun simctl getenv "$ios_udid" SIMULATOR_RUNTIME_VERSION 2>/dev/null || true)\",
@@ -209,7 +283,22 @@ jobs:
209283 }
210284
211285 register
212- echo "SimDeck tunnel: $tunnel_url"
286+ echo "SimDeck Studio URL: $provider_base_url"
287+
288+ app_path=""
289+ if [[ -d simdeck-artifact ]]; then
290+ app_path="$(find simdeck-artifact -maxdepth 6 -type d -name '*.app' | head -n 1 || true)"
291+ fi
292+ if [[ -n "$app_path" ]]; then
293+ echo "Installing simulator artifact from $app_path"
294+ run_with_timeout 120 xcrun simctl install "$ios_udid" "$app_path" || echo "simctl install timed out or failed"
295+ fi
296+ if [[ -n "${BUNDLE_ID:-}" ]]; then
297+ echo "Launching $BUNDLE_ID"
298+ run_with_timeout 30 xcrun simctl launch "$ios_udid" "$BUNDLE_ID" || true
299+ run_with_timeout 5 xcrun simctl io "$ios_udid" screenshot /tmp/simdeck-provider-app-screen.png >/tmp/simdeck-app-screenshot.log 2>&1 || cat /tmp/simdeck-app-screenshot.log || true
300+ fi
301+
213302 deadline=$((SECONDS + 1800))
214303 while true; do
215304 sleep 30
@@ -223,13 +312,16 @@ jobs:
223312 fi
224313 if ! kill -0 "$simdeck_pid" 2>/dev/null; then
225314 echo "simdeck exited"
226- cat simdeck.log || true
315+ dump_logs
227316 exit 1
228317 fi
229- if ! kill -0 "$cloudflared_pid " 2>/dev/null; then
230- echo "cloudflared exited"
231- cat cloudflared .log || true
318+ if ! kill -0 "$bridge_pid " 2>/dev/null; then
319+ echo "provider bridge exited"
320+ cat simdeck-provider-bridge .log || true
232321 exit 1
233322 fi
323+ if ! kill -0 "$diagnostics_pid" 2>/dev/null; then
324+ echo "diagnostics loop exited"
325+ fi
234326 register
235327 done
0 commit comments