@deeeed/metamask-harness 0.51.0 → 0.51.2

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/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.51.2 - 2026-09-14
6
+
7
+ ### Fixed
8
+
9
+ - Mobile native builds no longer pass `--no-bundler` to Expo: a Debug configuration starts the bundler regardless, so 0.51.1 left Expo attached to a stray Metro on 8081 and the launch never returned. Instead the build env answers Expo's one `lsof` lookup for the Metro listener from the harness's `metro.pid`; Expo's 350 ms lsof budget is what a busy Mac missed. A reused Metro listener now records its pid too.
10
+
11
+ ## 0.51.1 - 2026-09-13
12
+
13
+ ### Fixed
14
+
15
+ - Mobile native builds run `expo run:ios` / `run:android` with `--no-bundler` (and without `--port`, which Expo refuses next to it): the harness owns Metro on the watcher port, and Expo's post-build port re-check (lsof under a 350 ms budget) aborted a successful 45-minute build on a loaded machine with "Port became busy running another process while the app was compiling".
16
+ - Mobile `verify` waits for the React Native bridge to settle (bounded, best effort) before its live smoke, so a checkout is no longer reported not ready when the app is still hydrating right after a launch or a fixture unlock. `mm-harness prepare` on a fresh full slot build had failed at the final `verify` step this way while a retry a minute later passed.
5
17
  ## 0.51.0 - 2026-09-13
6
18
 
7
19
  ### Added
@@ -81,6 +81,46 @@ for _rb in "$SCRIPT_DIR/../shared/activate-repo-ruby.sh" "$SCRIPT_DIR/lib/activa
81
81
  [ -f "$_rb" ] && { . "$_rb"; break; }
82
82
  done
83
83
  unset _rb
84
+ # shellcheck disable=SC1091
85
+ for _hp in "$SCRIPT_DIR/../shared/harness-path.sh" "$SCRIPT_DIR/lib/harness-path.sh"; do
86
+ [ -f "$_hp" ] && { . "$_hp"; break; }
87
+ done
88
+ unset _hp
89
+
90
+ # Expo's run:ios / run:android bookkeeping asks lsof which process listens on
91
+ # the Metro port, before and after the native build, under a 350 ms budget.
92
+ # lsof scans every process on the machine, so a busy Mac misses that budget
93
+ # and Expo aborts a finished build with "Port became busy running another
94
+ # process while the app was compiling". The harness started that listener and
95
+ # recorded it in metro.pid: answer that one query from the record and hand
96
+ # every other lsof call to the real binary.
97
+ write_lsof_shim() {
98
+ local dir="$1" real_lsof
99
+ real_lsof="$(command -v lsof 2>/dev/null || true)"
100
+ [ -n "$real_lsof" ] || return 0
101
+ {
102
+ printf '#!/usr/bin/env bash\n'
103
+ printf 'REAL_LSOF=%q\n' "$real_lsof"
104
+ cat <<'SHIM'
105
+ # Exactly Expo's listener query and nothing else. A recycled pid after a Metro
106
+ # death is the only way this can lie, and a dead Metro fails the build anyway.
107
+ if [ $# -eq 4 ] && [ "$1" = "-i:${MM_HARNESS_BUILD_WATCHER_PORT:-}" ] && [ "$2" = "-P" ] && [ "$3" = "-t" ] && [ "$4" = "-sTCP:LISTEN" ] \
108
+ && [ -f "${MM_HARNESS_METRO_PID_FILE:-/nonexistent}" ]; then
109
+ pid="$(cat "$MM_HARNESS_METRO_PID_FILE" 2>/dev/null)"
110
+ if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then printf '%s\n' "$pid"; exit 0; fi
111
+ fi
112
+ exec "$REAL_LSOF" "$@"
113
+ SHIM
114
+ } > "$dir/lsof"
115
+ chmod +x "$dir/lsof"
116
+ }
117
+
118
+ metro_pid_file() {
119
+ command -v recipe_runtime_dir >/dev/null 2>&1 || return 1
120
+ local runtime
121
+ runtime="$(recipe_runtime_dir)" || return 1
122
+ printf '%s/%s/metro.pid' "$TARGET" "$runtime"
123
+ }
84
124
 
85
125
  # --- iOS helpers --------------------------------------------------------------
86
126
 
@@ -90,7 +130,7 @@ ios_app_installed() {
90
130
  }
91
131
 
92
132
  run_ios_native_build() (
93
- local sim_target="$1" bundle_id="$2" reason="$3" build_env="" build_script="" build_type=""
133
+ local sim_target="$1" bundle_id="$2" reason="$3" build_env="" build_script="" build_type="" shim_dir=""
94
134
  case "$bundle_id" in
95
135
  io.metamask.MetaMask|io.metamask) build_script="start:ios"; build_type="main" ;;
96
136
  io.metamask.MetaMask-Flask) build_script="start:ios:flask"; build_type="flask" ;;
@@ -102,11 +142,15 @@ run_ios_native_build() (
102
142
  printf '%s; installing with yarn %s (WATCHER_PORT=%s)\n' "$reason" "$build_script" "$PORT" >&2
103
143
  build_env="$(mktemp "${TMPDIR:-/tmp}/mm-harness-ios-build-env.XXXXXX")" || return 1
104
144
  chmod 600 "$build_env" || { rm -f "$build_env"; return 1; }
105
- trap 'rm -f "$build_env"' EXIT HUP INT TERM
145
+ shim_dir="$(mktemp -d "${TMPDIR:-/tmp}/mm-harness-build-shim.XXXXXX")" || { rm -f "$build_env"; return 1; }
146
+ trap 'rm -rf "$build_env" "$shim_dir"' EXIT HUP INT TERM
147
+ write_lsof_shim "$shim_dir"
106
148
  {
107
149
  printf 'export MM_HARNESS_BUILD_WATCHER_PORT=%q\n' "$PORT"
108
150
  printf 'export MM_HARNESS_BUILD_IOS_SIMULATOR=%q\n' "$sim_target"
109
151
  printf 'export MM_HARNESS_BUILD_TYPE=%q\n' "$build_type"
152
+ printf 'export MM_HARNESS_METRO_PID_FILE=%q\n' "$(metro_pid_file || true)"
153
+ printf 'export PATH=%q:"$PATH"\n' "$shim_dir"
110
154
  cat <<'BUILD_ENV'
111
155
  mm_harness_restore_build_target() {
112
156
  export WATCHER_PORT="$MM_HARNESS_BUILD_WATCHER_PORT"
@@ -281,7 +325,7 @@ android_app_installed() {
281
325
  }
282
326
 
283
327
  run_android_native_build() (
284
- local serial="$1" expo_device="$2" pkg="$3" reason="$4" build_env="" build_script=""
328
+ local serial="$1" expo_device="$2" pkg="$3" reason="$4" build_env="" build_script="" shim_dir=""
285
329
  case "$pkg" in
286
330
  io.metamask) build_script="start:android" ;;
287
331
  io.metamask.flask) build_script="start:android:flask" ;;
@@ -293,11 +337,15 @@ run_android_native_build() (
293
337
  printf '%s; installing with yarn %s (WATCHER_PORT=%s)\n' "$reason" "$build_script" "$PORT" >&2
294
338
  build_env="$(mktemp "${TMPDIR:-/tmp}/mm-harness-android-build-env.XXXXXX")" || return 1
295
339
  chmod 600 "$build_env" || { rm -f "$build_env"; return 1; }
296
- trap 'rm -f "$build_env"' EXIT HUP INT TERM
340
+ shim_dir="$(mktemp -d "${TMPDIR:-/tmp}/mm-harness-build-shim.XXXXXX")" || { rm -f "$build_env"; return 1; }
341
+ trap 'rm -rf "$build_env" "$shim_dir"' EXIT HUP INT TERM
342
+ write_lsof_shim "$shim_dir"
297
343
  {
298
344
  printf 'export MM_HARNESS_BUILD_ANDROID_SERIAL=%q\n' "$serial"
299
345
  printf 'export MM_HARNESS_BUILD_ANDROID_EXPO_DEVICE=%q\n' "$expo_device"
300
346
  printf 'export MM_HARNESS_BUILD_WATCHER_PORT=%q\n' "$PORT"
347
+ printf 'export MM_HARNESS_METRO_PID_FILE=%q\n' "$(metro_pid_file || true)"
348
+ printf 'export PATH=%q:"$PATH"\n' "$shim_dir"
301
349
  cat <<'BUILD_ENV'
302
350
  mm_harness_restore_android_build_target() {
303
351
  export WATCHER_PORT="$MM_HARNESS_BUILD_WATCHER_PORT"
@@ -218,6 +218,12 @@ if metro_ready; then
218
218
  rm -f "$PID_FILE"
219
219
  elif metro_listener_valid; then
220
220
  printf 'Metro already running and valid on port %s\n' "$PORT" >&2
221
+ # A reused listener still needs its record: the native build answers
222
+ # Expo's port lookup from metro.pid.
223
+ if [ ! -f "$PID_FILE" ]; then
224
+ lsof -nP -iTCP:"$PORT" -sTCP:LISTEN -t 2>/dev/null | head -1 > "$PID_FILE" || true
225
+ [ -s "$PID_FILE" ] || rm -f "$PID_FILE"
226
+ fi
221
227
  exit 0
222
228
  else
223
229
  stop_metro_listener || exit 1
@@ -414,6 +414,30 @@ if [ "$STATIC_ONLY" = false ]; then
414
414
 
415
415
  port_holder_json "$port" > "$ARTIFACTS/logs/port-holder.json"
416
416
 
417
+ # Right after a launch or a fixture unlock the app's JS thread can stay busy
418
+ # for a while (account hydration); a single CDP probe then times out although
419
+ # the runtime is healthy. When Metro holds the port, let wait-for-bridge
420
+ # absorb that settle before the smoke. Best effort and bounded: the smoke
421
+ # below is the check that counts. The installed overlay carries only this
422
+ # script, so the waiter is resolved from the runner source it was installed
423
+ # from.
424
+ if [ "$status" != "fail" ] && node -e 'process.exit(JSON.parse(require("fs").readFileSync(process.argv[1], "utf8")).listening ? 0 : 1)' "$ARTIFACTS/logs/port-holder.json" 2>/dev/null; then
425
+ wait_sh=""
426
+ for candidate in "$SCRIPT_DIR/wait-for-bridge.sh" "$(cat "$HARNESS_DIR/runner/.runner-source" 2>/dev/null || true)/adapters/mobile/wait-for-bridge.sh"; do
427
+ [ -f "$candidate" ] && { wait_sh="$candidate"; break; }
428
+ done
429
+ if [ -z "$wait_sh" ]; then
430
+ add_note "Mobile bridge settle skipped: wait-for-bridge.sh not found beside verify.sh or under runner/.runner-source; reinstall the runner."
431
+ elif MOBILE_BRIDGE_READY_TIMEOUT_MS="${MOBILE_BRIDGE_READY_TIMEOUT_MS:-90000}" \
432
+ MOBILE_BRIDGE_UNRESPONSIVE_GRACE_MS="${MOBILE_BRIDGE_UNRESPONSIVE_GRACE_MS:-90000}" \
433
+ bash "$wait_sh" --target "$TARGET" --port "$port" --platform "$PLATFORM" \
434
+ > "$ARTIFACTS/logs/wait-for-bridge.log" 2>&1; then
435
+ add_note "Mobile bridge settled before the live smoke (logs/wait-for-bridge.log)."
436
+ else
437
+ add_note "Mobile bridge settle did not complete (waiter exit $?); running the live smoke anyway (logs/wait-for-bridge.log)."
438
+ fi
439
+ fi
440
+
417
441
  cat > "$ARTIFACTS/mobile-v1-live-smoke.recipe.json" <<'JSON'
418
442
  {
419
443
  "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deeeed/metamask-harness",
3
- "version": "0.51.0",
3
+ "version": "0.51.2",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mm-harness": "bin/mm-harness"