@deeeed/metamask-harness 0.2.0 → 0.3.1
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 +33 -0
- package/README.md +47 -17
- package/{orchestration → adapters}/core/cleanup.sh +2 -2
- package/{orchestration → adapters}/core/inject.sh +8 -8
- package/{orchestration → adapters}/extension/cleanup.mjs +1 -1
- package/{orchestration → adapters}/extension/console-tail.mjs +3 -0
- package/{orchestration → adapters}/extension/ensure-browser.sh +4 -4
- package/{orchestration → adapters}/extension/inject.mjs +27 -31
- package/{orchestration → adapters}/extension/launch.sh +4 -4
- package/{orchestration → adapters}/extension/live.sh +5 -5
- package/{orchestration → adapters}/extension/readiness.mjs +12 -2
- package/{orchestration → adapters}/extension/refresh-build.sh +1 -1
- package/{orchestration → adapters}/extension/seed-fixture.sh +1 -1
- package/{orchestration → adapters}/extension/start-watch.sh +7 -7
- package/{runner → adapters}/extension/verify.sh +11 -11
- package/{orchestration → adapters}/extension/wallet-fixture-state.cjs +2 -2
- package/{orchestration → adapters}/manifest.json +96 -96
- package/{library/actions → adapters}/mobile/bridge-runtime/cdp-bridge.cjs +5 -5
- package/{orchestration → adapters}/mobile/cleanup.sh +3 -3
- package/{orchestration → adapters}/mobile/inject.sh +22 -24
- package/adapters/mobile/open-device.sh +260 -0
- package/{orchestration/compat-overlays → adapters/mobile/overlay/compat}/README.md +13 -4
- package/adapters/mobile/prewarm-bundle.sh +95 -0
- package/adapters/mobile/start-metro.sh +228 -0
- package/{runner → adapters}/mobile/verify.sh +6 -6
- package/adapters/mobile/wait-for-bridge.sh +108 -0
- package/adapters/mobile/yarn-setup.sh +20 -0
- package/{orchestration/lib → adapters/shared}/cli-ux.sh +5 -9
- package/{orchestration/lib → adapters/shared}/log-tui.mjs +57 -1
- package/{orchestration/lib → adapters/shared}/open-debug.mjs +32 -10
- package/{orchestration/lib → adapters/shared}/resolve-farmslot-ports.sh +47 -0
- package/adapters/shared/sync-wallet-fixture.sh +78 -0
- package/bin/mm-harness +37 -6
- package/docs/CLI-SPEC.md +41 -2
- package/docs/architecture.md +69 -38
- package/docs/runtime-file-conventions.md +3 -3
- package/library/actions/core/perps/_controller.mjs +1 -1
- package/library/actions/extension/platform/cdp.mjs +2 -2
- package/library/actions/extension/wallet/ensure_unlocked.mjs +1 -1
- package/library/actions/mobile/platform/bridge.mjs +1 -1
- package/library/actions/mobile/wallet/ensure_unlocked.mjs +1 -1
- package/library/actions/mobile/wallet/setup.mjs +2 -2
- package/library/library.json +1 -1
- package/package.json +8 -8
- package/{orchestration → src/adapters}/extension/runtime-decision.ts +5 -5
- package/{orchestration → src/adapters}/extension/runtime.ts +1 -1
- package/src/adapters/mobile/prepare.ts +210 -0
- package/{orchestration → src/adapters}/mobile/runtime-decision.ts +105 -5
- package/{runner/src → src}/adapters.ts +3 -3
- package/{orchestration/lib/cli-color.mjs → src/cli-color.ts} +21 -13
- package/{orchestration/lib/cli-commands.mjs → src/cli-commands.ts} +52 -45
- package/{orchestration/lib/cli-version.mjs → src/cli-version.ts} +35 -17
- package/{runner/src → src}/cli.ts +48 -40
- package/src/commands/debug.ts +63 -0
- package/src/commands/fixtures.ts +193 -0
- package/{runner/src → src}/commands/launch.ts +200 -54
- package/src/commands/logs.ts +83 -0
- package/{runner/src → src}/commands/shared.ts +40 -30
- package/src/commands/update.ts +316 -0
- package/{runner/src → src}/harness.ts +119 -16
- package/{runner/src → src}/heal-bounds.ts +20 -1
- package/src/index.ts +15 -0
- package/{runner/src → src}/live-adapter-contract.ts +1 -1
- package/{runner/src → src}/mm-harness-cli.ts +64 -3
- package/{runner/src → src}/paths.ts +2 -2
- package/{orchestration/lib/progress.mjs → src/progress.ts} +31 -21
- package/docs/extension-runtime-commands.md +0 -60
- package/docs/harness-cli.md +0 -43
- package/orchestration/compat-overlays/mobile/README.md +0 -13
- package/orchestration/doctor.mjs +0 -72
- package/orchestration/lib/cli-home.mjs +0 -354
- package/orchestration/lib/recipe-paths.mjs +0 -26
- package/orchestration/mobile/launch.sh +0 -137
- package/orchestration/mobile/live.sh +0 -125
- package/orchestration/porcelain/metamask-recipe +0 -99
- package/orchestration/porcelain/mm-recipe +0 -1591
- package/orchestration/porcelain/mme-recipe +0 -1181
- package/runner/src/commands/debug.ts +0 -44
- package/runner/src/commands/fixtures.ts +0 -99
- package/runner/src/commands/logs.ts +0 -60
- package/runner/src/index.ts +0 -6
- /package/{orchestration → adapters}/extension/launch-browser.cjs +0 -0
- /package/{orchestration → adapters}/extension/pin-remote-flags.cjs +0 -0
- /package/{orchestration → adapters}/extension/sidepanel-toggle.sh +0 -0
- /package/{orchestration → adapters}/extension/snapshot-dist.sh +0 -0
- /package/{library/actions → adapters}/mobile/bridge-runtime/lib/cdp-eval.cjs +0 -0
- /package/{library/actions → adapters}/mobile/bridge-runtime/lib/config.cjs +0 -0
- /package/{library/actions → adapters}/mobile/bridge-runtime/lib/issue-capture.cjs +0 -0
- /package/{library/actions → adapters}/mobile/bridge-runtime/lib/target-discovery.cjs +0 -0
- /package/{library/actions → adapters}/mobile/bridge-runtime/lib/ws-client.cjs +0 -0
- /package/{library/actions → adapters}/mobile/bridge-runtime/setup-wallet.sh +0 -0
- /package/{library/actions/mobile/app-overlay → adapters/mobile/overlay}/app/dev-tools/AgenticService/AgentStepHud.tsx.patch +0 -0
- /package/{library/actions/mobile/app-overlay → adapters/mobile/overlay}/app/dev-tools/AgenticService/AgenticService.ts.patch +0 -0
- /package/{orchestration/compat-overlays/mobile → adapters/mobile/overlay/compat}/rn81-message-event-source.patch +0 -0
- /package/{orchestration/lib → adapters/shared}/activate-repo-node.sh +0 -0
- /package/{orchestration/lib → adapters/shared}/ensure-runner-deps.sh +0 -0
- /package/{orchestration/lib → adapters/shared}/harness-path.sh +0 -0
- /package/{orchestration/lib → adapters/shared}/hash-helpers.sh +0 -0
- /package/{orchestration/lib → adapters/shared}/json-field.sh +0 -0
- /package/{orchestration/lib → adapters/shared}/path-defaults.json +0 -0
- /package/{orchestration → src/adapters}/extension/ensure-ready.ts +0 -0
- /package/{orchestration → src/adapters}/extension/extension-id.ts +0 -0
- /package/{orchestration → src/adapters}/mobile/deps-markers.ts +0 -0
- /package/{runner/src → src}/completions-cache.ts +0 -0
- /package/{runner/src → src}/doctor.ts +0 -0
- /package/{runner/src → src}/manifest.ts +0 -0
- /package/{runner/src → src}/recording-target.ts +0 -0
- /package/{runner/src → src}/run-recording.ts +0 -0
- /package/{runner/src → src}/runner.ts +0 -0
- /package/{runner/src → src}/types.ts +0 -0
|
@@ -42,21 +42,21 @@ done
|
|
|
42
42
|
|
|
43
43
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
44
44
|
RUNNER_DIR="$(cd "${SCRIPT_DIR}/../.." && pwd -P)"
|
|
45
|
-
ADAPTER_DIR="$RUNNER_DIR/
|
|
46
|
-
# compat-overlays: NOT applied here.
|
|
45
|
+
ADAPTER_DIR="$RUNNER_DIR/adapters/mobile"
|
|
46
|
+
# compat-overlays: NOT applied here. adapters/mobile/overlay/compat/ holds
|
|
47
47
|
# reversible patches applied only when injecting into HISTORICAL checkouts
|
|
48
48
|
# (replay/eval against old product commits, e.g. pre-RN-0.81 mobile); the
|
|
49
49
|
# operator/recipe-harness skill applies them manually before the rebuild.
|
|
50
|
-
# See
|
|
50
|
+
# See adapters/mobile/overlay/compat/README.md.
|
|
51
51
|
# shellcheck disable=SC1091
|
|
52
|
-
. "$SCRIPT_DIR/../
|
|
52
|
+
. "$SCRIPT_DIR/../shared/hash-helpers.sh"
|
|
53
53
|
# shellcheck disable=SC1091
|
|
54
|
-
for _hp in "$SCRIPT_DIR/../
|
|
54
|
+
for _hp in "$SCRIPT_DIR/../shared/harness-path.sh"; do
|
|
55
55
|
[ -f "$_hp" ] && { . "$_hp"; break; }
|
|
56
56
|
done
|
|
57
57
|
unset _hp
|
|
58
58
|
if ! command -v harness_root >/dev/null 2>&1; then
|
|
59
|
-
echo "mm-harness: shared lib
|
|
59
|
+
echo "mm-harness: shared lib adapters/shared/harness-path.sh not found; reinstall the runner." >&2
|
|
60
60
|
exit 1
|
|
61
61
|
fi
|
|
62
62
|
TARGET="$(cd "$TARGET" && pwd)"
|
|
@@ -134,7 +134,7 @@ install_v1_runner_assets() {
|
|
|
134
134
|
# quote — cannot break the generated wrapper or inject at runtime.
|
|
135
135
|
local runner_protocol_root_q runner_exec_q target_q
|
|
136
136
|
runner_protocol_root_q="$(printf '%q' "$METAMASK_RUNNER_PROTOCOL_ROOT")"
|
|
137
|
-
runner_exec_q="$(printf '%q' "$METAMASK_RUNNER_DIR/
|
|
137
|
+
runner_exec_q="$(printf '%q' "$METAMASK_RUNNER_DIR/bin/mm-harness")"
|
|
138
138
|
target_q="$(printf '%q' "$TARGET")"
|
|
139
139
|
{
|
|
140
140
|
printf '%s\n' '#!/usr/bin/env bash'
|
|
@@ -175,8 +175,8 @@ install_v1_runner_assets() {
|
|
|
175
175
|
printf 'export FARMSLOT_ROOT=${FARMSLOT_ROOT:-%s}\n' "$runner_protocol_root_q"
|
|
176
176
|
fi
|
|
177
177
|
printf 'exec %s "$@"\n' "$runner_exec_q"
|
|
178
|
-
} > "$HARNESS_DIR/runner/bin/
|
|
179
|
-
chmod +x "$HARNESS_DIR/runner/bin/
|
|
178
|
+
} > "$HARNESS_DIR/runner/bin/mm-harness"
|
|
179
|
+
chmod +x "$HARNESS_DIR/runner/bin/mm-harness"
|
|
180
180
|
if [ -n "$METAMASK_RUNNER_PROTOCOL_ROOT" ]; then
|
|
181
181
|
printf '%s\n' "$METAMASK_RUNNER_PROTOCOL_ROOT" > "$HARNESS_DIR/runner/.farmslot-root"
|
|
182
182
|
fi
|
|
@@ -199,19 +199,19 @@ install_v1_runner_assets() {
|
|
|
199
199
|
# Installed-layout back-compat (INTENTIONAL): targets keep a flat
|
|
200
200
|
# <harness>/scripts/ subtree assembled from the runner trees, so installed
|
|
201
201
|
# consumers are unaffected by runner-repo layout changes.
|
|
202
|
-
if [ -d "$METAMASK_RUNNER_DIR/
|
|
202
|
+
if [ -d "$METAMASK_RUNNER_DIR/adapters/mobile" ]; then
|
|
203
203
|
mkdir -p "$HARNESS_DIR/scripts"
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
204
|
+
# launch and live orchestration is now in-process (src/harness.ts + src/adapters/mobile/prepare.ts).
|
|
205
|
+
# Remove any copies left by older installs so stale scripts cannot shadow the in-process path.
|
|
206
|
+
rm -f "$HARNESS_DIR/scripts/launch.sh" "$HARNESS_DIR/scripts/live.sh"
|
|
207
|
+
cp "$METAMASK_RUNNER_DIR/adapters/mobile/verify.sh" "$HARNESS_DIR/scripts/verify.sh"
|
|
207
208
|
mkdir -p "$HARNESS_DIR/scripts/lib"
|
|
208
|
-
cp "$METAMASK_RUNNER_DIR/
|
|
209
|
-
cp "$METAMASK_RUNNER_DIR/
|
|
210
|
-
cp "$METAMASK_RUNNER_DIR/orchestration/lib/recipe-paths.mjs" "$HARNESS_DIR/scripts/lib/recipe-paths.mjs"
|
|
209
|
+
cp "$METAMASK_RUNNER_DIR/adapters/shared/harness-path.sh" "$HARNESS_DIR/scripts/lib/harness-path.sh"
|
|
210
|
+
cp "$METAMASK_RUNNER_DIR/adapters/shared/path-defaults.json" "$HARNESS_DIR/scripts/lib/path-defaults.json"
|
|
211
211
|
chmod -R u+rwX,go+rX "$HARNESS_DIR/scripts"
|
|
212
212
|
find "$HARNESS_DIR/scripts" -type f \( -name '*.sh' -o -name '*.cjs' -o -name '*.mjs' \) -exec chmod +x {} +
|
|
213
213
|
fi
|
|
214
|
-
if [ ! -x "$HARNESS_DIR/runner/bin/
|
|
214
|
+
if [ ! -x "$HARNESS_DIR/runner/bin/mm-harness" ]; then
|
|
215
215
|
echo "Refusing mobile recipe harness install: failed to make runner executable." >&2
|
|
216
216
|
return 1
|
|
217
217
|
fi
|
|
@@ -288,10 +288,8 @@ if [ "$FORCE_OVERLAY" = false ] && has_product_owned_mobile_harness; then
|
|
|
288
288
|
target,
|
|
289
289
|
protocolVersion: "v1",
|
|
290
290
|
actionManifestPath: harnessRel + "/action-manifest.json",
|
|
291
|
-
runnerEntrypoint: harnessRel + "/runner/bin/
|
|
291
|
+
runnerEntrypoint: harnessRel + "/runner/bin/mm-harness",
|
|
292
292
|
runtimeHelpers: {
|
|
293
|
-
launch: harnessRel + "/scripts/launch.sh",
|
|
294
|
-
live: harnessRel + "/scripts/live.sh",
|
|
295
293
|
verify: harnessRel + "/scripts/verify.sh"
|
|
296
294
|
},
|
|
297
295
|
installedPaths: [],
|
|
@@ -527,7 +525,7 @@ install_v1_runner_assets
|
|
|
527
525
|
|
|
528
526
|
mkdir -p "$TARGET/app/dev-tools/AgenticService"
|
|
529
527
|
while IFS= read -r -d '' overlay_file; do
|
|
530
|
-
rel="${overlay_file#$ADAPTER_DIR/
|
|
528
|
+
rel="${overlay_file#$ADAPTER_DIR/overlay/app/dev-tools/AgenticService/}"
|
|
531
529
|
dest_rel="${rel%.patch}"
|
|
532
530
|
dest="$TARGET/app/dev-tools/AgenticService/$dest_rel"
|
|
533
531
|
mkdir -p "$(dirname "$dest")"
|
|
@@ -537,7 +535,7 @@ while IFS= read -r -d '' overlay_file; do
|
|
|
537
535
|
# Exclude overlay *.test.* files: they are source tests for the overlay
|
|
538
536
|
# templates and must not ship into the product checkout, where the product's
|
|
539
537
|
# jest could pick them up on local runs.
|
|
540
|
-
done < <(find "$ADAPTER_DIR/
|
|
538
|
+
done < <(find "$ADAPTER_DIR/overlay/app/dev-tools/AgenticService" -type f ! -name '*.test.*' -print0)
|
|
541
539
|
|
|
542
540
|
node - "$TARGET" <<'NODE'
|
|
543
541
|
const fs = require('fs');
|
|
@@ -654,7 +652,7 @@ node -e '
|
|
|
654
652
|
target,
|
|
655
653
|
protocolVersion: "v1",
|
|
656
654
|
actionManifestPath: harnessRel + "/action-manifest.json",
|
|
657
|
-
runnerEntrypoint: harnessRel + "/runner/bin/
|
|
655
|
+
runnerEntrypoint: harnessRel + "/runner/bin/mm-harness",
|
|
658
656
|
runtimeHelpers: {
|
|
659
657
|
launch: harnessRel + "/scripts/launch.sh",
|
|
660
658
|
live: harnessRel + "/scripts/live.sh",
|
|
@@ -673,7 +671,7 @@ node -e '
|
|
|
673
671
|
fs.writeFileSync(manifestPath, JSON.stringify(m, null, 2) + "\n");
|
|
674
672
|
' "$RUNNER_DIR" "$SOURCE_REV" "$METAMASK_RUNNER_DIR" "$METAMASK_RUNNER_REVISION" "$METAMASK_RUNNER_SOURCE_KIND" "$ADAPTER_DIR" "$TARGET" "$BACKUP_DIR" "$SCRIPT_DIR" "$HARNESS_DIR/manifest.json" "${MOBILE_AGENTIC_SOURCE:-}" "$HARNESS_ROOT" "$HARNESS_REL" "$CLEANUP_COMMAND"
|
|
675
673
|
|
|
676
|
-
ENSURE_DEPS="$SCRIPT_DIR/../
|
|
674
|
+
ENSURE_DEPS="$SCRIPT_DIR/../shared/ensure-runner-deps.sh"
|
|
677
675
|
if [ -f "$ENSURE_DEPS" ]; then
|
|
678
676
|
bash "$ENSURE_DEPS" "$RUNNER_DIR"
|
|
679
677
|
fi
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# open-device — open the MetaMask Mobile dev client on a simulator or device.
|
|
3
|
+
#
|
|
4
|
+
# iOS: boots simulator if needed, writes EXDevMenuIsOnboardingFinished default,
|
|
5
|
+
# then opens via the expo-development-client deep link (disableOnboarding=1).
|
|
6
|
+
# Android: sets adb reverse for Metro port reachability, then opens via deep link.
|
|
7
|
+
# Preflight-mode guard: fast (teaching error if not installed), auto (install if missing),
|
|
8
|
+
# rebuild-native / clean (always rebuild), default (same as auto).
|
|
9
|
+
#
|
|
10
|
+
# Inputs:
|
|
11
|
+
# --platform ios|android (default ios)
|
|
12
|
+
# --target <metamask-mobile dir> (default $PWD)
|
|
13
|
+
# --simulator <udid|name|"booted"> iOS simulator (default: IOS_SIMULATOR env, else "booted")
|
|
14
|
+
# --adb-serial <serial> Android device serial (default: ADB_SERIAL env)
|
|
15
|
+
# --preflight-mode fast|auto|rebuild-native|clean (default: fast; env MOBILE_PREFLIGHT_MODE)
|
|
16
|
+
# Outputs:
|
|
17
|
+
# Progress on stderr; exit 0 pass; 1 open failed; 2 bad args.
|
|
18
|
+
#
|
|
19
|
+
# Single device op: open the dev client. Does not start Metro or install node_modules.
|
|
20
|
+
set -uo pipefail
|
|
21
|
+
|
|
22
|
+
PLATFORM="ios"
|
|
23
|
+
TARGET="$PWD"
|
|
24
|
+
SIMULATOR="${IOS_SIMULATOR:-${SIM_UDID:-booted}}"
|
|
25
|
+
ADB_SERIAL_ARG="${ADB_SERIAL:-${ANDROID_SERIAL:-}}"
|
|
26
|
+
PREFLIGHT_MODE="${MOBILE_PREFLIGHT_MODE:-fast}"
|
|
27
|
+
PORT="${WATCHER_PORT:-${METRO_PORT:-8081}}"
|
|
28
|
+
|
|
29
|
+
while [ "$#" -gt 0 ]; do
|
|
30
|
+
case "$1" in
|
|
31
|
+
--platform) PLATFORM="$2"; shift 2 ;;
|
|
32
|
+
--target) TARGET="$2"; shift 2 ;;
|
|
33
|
+
--simulator) SIMULATOR="$2"; shift 2 ;;
|
|
34
|
+
--adb-serial) ADB_SERIAL_ARG="$2"; shift 2 ;;
|
|
35
|
+
--preflight-mode) PREFLIGHT_MODE="$2"; shift 2 ;;
|
|
36
|
+
--port) PORT="$2"; shift 2 ;;
|
|
37
|
+
-h|--help)
|
|
38
|
+
printf 'Usage: open-device.sh [--platform ios|android] [--target <dir>]\n'
|
|
39
|
+
printf ' [--simulator <udid|name|booted>] [--adb-serial <serial>]\n'
|
|
40
|
+
printf ' [--preflight-mode fast|auto|rebuild-native|clean] [--port <n>]\n'
|
|
41
|
+
exit 0
|
|
42
|
+
;;
|
|
43
|
+
*) printf 'open-device: unknown arg: %s\n' "$1" >&2; exit 2 ;;
|
|
44
|
+
esac
|
|
45
|
+
done
|
|
46
|
+
|
|
47
|
+
case "$PLATFORM" in
|
|
48
|
+
ios|android) ;;
|
|
49
|
+
*) printf 'open-device: --platform must be ios or android (got: %s)\n' "$PLATFORM" >&2; exit 2 ;;
|
|
50
|
+
esac
|
|
51
|
+
|
|
52
|
+
TARGET="$(cd "$TARGET" && pwd)"
|
|
53
|
+
|
|
54
|
+
# --- iOS helpers --------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
ios_app_installed() {
|
|
57
|
+
local sim_target="$1" bundle_id="$2"
|
|
58
|
+
xcrun simctl get_app_container "$sim_target" "$bundle_id" app >/dev/null 2>&1
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
run_ios_native_build() {
|
|
62
|
+
local sim_target="$1" reason="$2"
|
|
63
|
+
printf '%s; installing with yarn start:ios (WATCHER_PORT=%s)\n' "$reason" "$PORT" >&2
|
|
64
|
+
(cd "$TARGET" && WATCHER_PORT="$PORT" METRO_PORT="$PORT" IOS_SIMULATOR="$sim_target" EXPO_NO_TYPESCRIPT_SETUP=1 yarn start:ios 2>&1)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
ensure_ios_app_for_mode() {
|
|
68
|
+
local sim_target="$1" bundle_id="$2" mode="$3"
|
|
69
|
+
case "$mode" in
|
|
70
|
+
fast)
|
|
71
|
+
if ios_app_installed "$sim_target" "$bundle_id"; then return 0; fi
|
|
72
|
+
printf >&2 'open-device: fast mode requires an installed iOS dev client (%s) on %s.\n' \
|
|
73
|
+
"$bundle_id" "$sim_target"
|
|
74
|
+
printf >&2 'Fast mode only prewarms the bundle and opens the existing client.\n'
|
|
75
|
+
printf >&2 'Next: use --preflight-mode auto to install if missing.\n'
|
|
76
|
+
return 1
|
|
77
|
+
;;
|
|
78
|
+
auto|default)
|
|
79
|
+
if ios_app_installed "$sim_target" "$bundle_id"; then return 0; fi
|
|
80
|
+
run_ios_native_build "$sim_target" "iOS dev client ${bundle_id} not installed on ${sim_target}"
|
|
81
|
+
;;
|
|
82
|
+
rebuild-native|clean)
|
|
83
|
+
run_ios_native_build "$sim_target" "Rebuilding iOS dev client ${bundle_id} (--preflight-mode ${mode})"
|
|
84
|
+
;;
|
|
85
|
+
*)
|
|
86
|
+
printf 'open-device: unknown --preflight-mode: %s\n' "$mode" >&2; return 2 ;;
|
|
87
|
+
esac
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
sim_udid_for_target() {
|
|
91
|
+
local target="$1"
|
|
92
|
+
# Already a UDID
|
|
93
|
+
if printf '%s' "$target" | grep -Eq '^[0-9A-Fa-f-]{36}$'; then
|
|
94
|
+
printf '%s\n' "$target"; return 0
|
|
95
|
+
fi
|
|
96
|
+
xcrun simctl list devices available 2>/dev/null \
|
|
97
|
+
| sed -n "s/.*${target} (\([0-9A-Fa-f-]*\)) (.*/\1/p" | head -1
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
boot_simulator_if_needed() {
|
|
101
|
+
local target="$1" state=""
|
|
102
|
+
[ "$target" != "booted" ] || return 0
|
|
103
|
+
local line=""
|
|
104
|
+
line="$(xcrun simctl list devices available 2>/dev/null | grep -F "${target} (" | head -1 || true)"
|
|
105
|
+
case "$line" in *"(Booted)"*) state="Booted" ;; *"(Shutdown)"*) state="Shutdown" ;; esac
|
|
106
|
+
[ "$state" = "Booted" ] && return 0
|
|
107
|
+
printf 'Booting iOS simulator %s%s\n' "$target" "${state:+ ($state)}" >&2
|
|
108
|
+
xcrun simctl boot "$target" 2>/dev/null || true
|
|
109
|
+
xcrun simctl bootstatus "$target" -b >/dev/null
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
show_simulator() {
|
|
113
|
+
local target="$1" udid=""
|
|
114
|
+
if [ "$target" = "booted" ]; then
|
|
115
|
+
printf 'Opening Simulator UI\n' >&2
|
|
116
|
+
open -a Simulator >/dev/null 2>&1 || true
|
|
117
|
+
else
|
|
118
|
+
udid="$(sim_udid_for_target "$target")"
|
|
119
|
+
if [ -n "$udid" ]; then
|
|
120
|
+
open -a Simulator --args -CurrentDeviceUDID "$udid" >/dev/null 2>&1 || true
|
|
121
|
+
else
|
|
122
|
+
open -a Simulator >/dev/null 2>&1 || true
|
|
123
|
+
fi
|
|
124
|
+
fi
|
|
125
|
+
osascript -e 'tell application "Simulator" to activate' >/dev/null 2>&1 || true
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
# --- Android helpers ----------------------------------------------------------
|
|
129
|
+
|
|
130
|
+
android_app_installed() {
|
|
131
|
+
local pkg="$1"
|
|
132
|
+
shift
|
|
133
|
+
adb "$@" shell pm list packages 2>/dev/null | grep -q "package:${pkg}"
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
run_android_native_build() {
|
|
137
|
+
local reason="$1"
|
|
138
|
+
printf '%s; installing with yarn start:android (WATCHER_PORT=%s)\n' "$reason" "$PORT" >&2
|
|
139
|
+
(cd "$TARGET" && WATCHER_PORT="$PORT" yarn start:android 2>&1)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
ensure_android_app_for_mode() {
|
|
143
|
+
local pkg="$1" mode="$2"
|
|
144
|
+
shift 2
|
|
145
|
+
case "$mode" in
|
|
146
|
+
fast)
|
|
147
|
+
if android_app_installed "$pkg" "$@"; then return 0; fi
|
|
148
|
+
printf >&2 'open-device: fast mode requires an installed Android dev client (%s).\n' "$pkg"
|
|
149
|
+
printf >&2 'Next: use --preflight-mode auto to install if missing.\n'
|
|
150
|
+
return 1
|
|
151
|
+
;;
|
|
152
|
+
auto|default)
|
|
153
|
+
if android_app_installed "$pkg" "$@"; then return 0; fi
|
|
154
|
+
run_android_native_build "Android dev client ${pkg} not installed"
|
|
155
|
+
;;
|
|
156
|
+
rebuild-native|clean)
|
|
157
|
+
run_android_native_build "Rebuilding Android dev client ${pkg} (--preflight-mode ${mode})"
|
|
158
|
+
;;
|
|
159
|
+
*)
|
|
160
|
+
printf 'open-device: unknown --preflight-mode: %s\n' "$mode" >&2; return 2 ;;
|
|
161
|
+
esac
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
# URL-encode using python3 (same as baseline).
|
|
165
|
+
urlencode() {
|
|
166
|
+
python3 - "$1" <<'PY'
|
|
167
|
+
import sys, urllib.parse
|
|
168
|
+
print(urllib.parse.quote(sys.argv[1], safe=''))
|
|
169
|
+
PY
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
# --- dispatch -----------------------------------------------------------------
|
|
173
|
+
|
|
174
|
+
BUNDLE_IDS=("${IOS_BUNDLE_ID:-io.metamask.MetaMask}" "io.metamask" "io.metamask.flask" "io.metamask.qa")
|
|
175
|
+
ANDROID_PKGS=("${ANDROID_PACKAGE_ID:-io.metamask}" "io.metamask.flask" "io.metamask.qa")
|
|
176
|
+
|
|
177
|
+
if [ "$PLATFORM" = "ios" ]; then
|
|
178
|
+
SIM_TARGET="$SIMULATOR"
|
|
179
|
+
# Expo dev-client URL scheme — drives both the deep link and the scheme-approval key.
|
|
180
|
+
DEV_CLIENT_SCHEME="${IOS_DEV_CLIENT_SCHEME:-expo-metamask}"
|
|
181
|
+
|
|
182
|
+
boot_simulator_if_needed "$SIM_TARGET"
|
|
183
|
+
show_simulator "$SIM_TARGET"
|
|
184
|
+
|
|
185
|
+
LAUNCHED=false
|
|
186
|
+
for BUNDLE_ID in "${BUNDLE_IDS[@]}"; do
|
|
187
|
+
ensure_ios_app_for_mode "$SIM_TARGET" "$BUNDLE_ID" "$PREFLIGHT_MODE" || continue
|
|
188
|
+
|
|
189
|
+
# Dismiss Expo dev-menu onboarding for clean headless runs.
|
|
190
|
+
xcrun simctl spawn "$SIM_TARGET" defaults write "$BUNDLE_ID" \
|
|
191
|
+
EXDevMenuIsOnboardingFinished -bool YES 2>/dev/null || true
|
|
192
|
+
|
|
193
|
+
# Pre-approve the dev-client deep-link scheme so openurl never pauses on the
|
|
194
|
+
# "Open in <App>?" dialog. The key encodes the CoreSimulator bridge + scheme;
|
|
195
|
+
# the value is the bundle ID of the approved handler.
|
|
196
|
+
xcrun simctl spawn "$SIM_TARGET" defaults write \
|
|
197
|
+
com.apple.launchservices.schemeapproval \
|
|
198
|
+
"com.apple.CoreSimulator.CoreSimulatorBridge-->${DEV_CLIENT_SCHEME}" \
|
|
199
|
+
-string "$BUNDLE_ID" 2>/dev/null || true
|
|
200
|
+
|
|
201
|
+
# Open via expo-development-client deep link so the app connects to our Metro.
|
|
202
|
+
ENCODED_URL="$(urlencode "http://localhost:${PORT}?disableOnboarding=1" 2>/dev/null \
|
|
203
|
+
|| printf 'http%%3A%%2F%%2Flocalhost%%3A%s%%3FdisableOnboarding%%3D1' "$PORT")"
|
|
204
|
+
DEEP_LINK="${DEV_CLIENT_SCHEME}://expo-development-client/?url=${ENCODED_URL}"
|
|
205
|
+
|
|
206
|
+
printf 'Launching iOS dev client %s on %s\n' "$BUNDLE_ID" "$SIM_TARGET" >&2
|
|
207
|
+
if xcrun simctl openurl "$SIM_TARGET" "$DEEP_LINK" 2>/dev/null; then
|
|
208
|
+
LAUNCHED=true
|
|
209
|
+
printf 'open-device: iOS dev client opened (%s on %s)\n' "$BUNDLE_ID" "$SIM_TARGET" >&2
|
|
210
|
+
break
|
|
211
|
+
fi
|
|
212
|
+
# Fallback: plain launch (older Expo / non-development-client build).
|
|
213
|
+
if xcrun simctl launch "$SIM_TARGET" "$BUNDLE_ID" 2>/dev/null; then
|
|
214
|
+
LAUNCHED=true
|
|
215
|
+
printf 'open-device: iOS dev client launched (fallback) (%s on %s)\n' "$BUNDLE_ID" "$SIM_TARGET" >&2
|
|
216
|
+
break
|
|
217
|
+
fi
|
|
218
|
+
done
|
|
219
|
+
|
|
220
|
+
if [ "$LAUNCHED" = false ]; then
|
|
221
|
+
printf 'open-device: no MetaMask bundle found on simulator %s\n' "$SIM_TARGET" >&2
|
|
222
|
+
printf ' tried: %s\n' "${BUNDLE_IDS[*]}" >&2
|
|
223
|
+
exit 1
|
|
224
|
+
fi
|
|
225
|
+
|
|
226
|
+
else
|
|
227
|
+
ADB_ARGS=()
|
|
228
|
+
[ -n "$ADB_SERIAL_ARG" ] && ADB_ARGS+=("-s" "$ADB_SERIAL_ARG")
|
|
229
|
+
|
|
230
|
+
# Reverse-tunnel Metro port so the device can reach localhost:PORT.
|
|
231
|
+
adb "${ADB_ARGS[@]}" reverse "tcp:${PORT}" "tcp:${PORT}" >/dev/null 2>&1 || \
|
|
232
|
+
printf 'open-device: adb reverse failed (non-fatal — device may already be reachable)\n' >&2
|
|
233
|
+
|
|
234
|
+
LAUNCHED=false
|
|
235
|
+
for PKG in "${ANDROID_PKGS[@]}"; do
|
|
236
|
+
ensure_android_app_for_mode "$PKG" "$PREFLIGHT_MODE" "${ADB_ARGS[@]}" || continue
|
|
237
|
+
|
|
238
|
+
ENCODED_URL="$(urlencode "http://localhost:${PORT}?disableOnboarding=1" 2>/dev/null \
|
|
239
|
+
|| printf 'http%%3A%%2F%%2Flocalhost%%3A%s%%3FdisableOnboarding%%3D1' "$PORT")"
|
|
240
|
+
DEEP_LINK="expo-metamask://expo-development-client/?url=${ENCODED_URL}"
|
|
241
|
+
|
|
242
|
+
printf 'Launching Android dev client %s\n' "$PKG" >&2
|
|
243
|
+
if adb "${ADB_ARGS[@]}" shell am start \
|
|
244
|
+
-a android.intent.action.VIEW \
|
|
245
|
+
-d "$DEEP_LINK" >/dev/null 2>&1; then
|
|
246
|
+
LAUNCHED=true
|
|
247
|
+
printf 'open-device: Android dev client opened (%s)\n' "$PKG" >&2
|
|
248
|
+
break
|
|
249
|
+
fi
|
|
250
|
+
done
|
|
251
|
+
|
|
252
|
+
if [ "$LAUNCHED" = false ]; then
|
|
253
|
+
printf 'open-device: no MetaMask package found on Android device %s\n' \
|
|
254
|
+
"${ADB_SERIAL_ARG:-<default>}" >&2
|
|
255
|
+
printf ' tried: %s\n' "${ANDROID_PKGS[*]}" >&2
|
|
256
|
+
exit 1
|
|
257
|
+
fi
|
|
258
|
+
fi
|
|
259
|
+
|
|
260
|
+
printf ' Next: mm-harness logs # tail Metro\n' >&2
|
|
@@ -7,13 +7,22 @@ up empty here by design: the feature's purpose is non-current checkouts.
|
|
|
7
7
|
|
|
8
8
|
- Purpose: make historical product checkouts bootable/bridgeable under the
|
|
9
9
|
current local toolchain so Recipe v1 evals can replay against them.
|
|
10
|
-
- When it applies: mobile checkouts predating React Native 0.81 polyfill
|
|
11
|
-
fixes (see mobile/README.md for the per-patch details).
|
|
10
|
+
- When it applies: mobile checkouts predating React Native 0.81 polyfill fixes.
|
|
12
11
|
- How it is applied: MANUALLY (no automatic apply logic in this repo).
|
|
13
12
|
The operator or the `/recipe-harness` skill applies the patch reversibly
|
|
14
13
|
before a historical rebuild (`git apply <patch>` in the product checkout,
|
|
15
14
|
`git apply -R` to remove) and records the overlay path in validation
|
|
16
|
-
evidence. `
|
|
15
|
+
evidence. `adapters/mobile/inject.sh` does NOT apply these.
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
Kept in the external runner repository, not Farmslot root scripts, so a
|
|
18
|
+
`/recipe-harness` skill can apply the same reversible overlay before a
|
|
19
|
+
historical rebuild and record the overlay path in validation evidence.
|
|
20
|
+
|
|
21
|
+
Listed in adapters/manifest.json (kind: compat-overlay) so the doctor
|
|
19
22
|
verifies the surface and this directory is never flagged as unused again.
|
|
23
|
+
|
|
24
|
+
## Patches
|
|
25
|
+
|
|
26
|
+
- `rn81-message-event-source.patch`: adds a read-only `MessageEvent.prototype.source`
|
|
27
|
+
getter for React Native 0.81 historical checkouts whose bundled polyfill omits
|
|
28
|
+
it while CDP websocket clients expect browser-compatible `MessageEvent` shape.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# prewarm-bundle — curl the Metro bundle URL before the dev client opens.
|
|
3
|
+
#
|
|
4
|
+
# Triggers Metro to compile and cache the bundle so the app connects instantly.
|
|
5
|
+
# Streams progress from the Metro log every 30s until the bundle curl finishes
|
|
6
|
+
# or MOBILE_BUNDLE_PREWARM_TIMEOUT seconds elapse.
|
|
7
|
+
# Set MOBILE_BUNDLE_PREWARM=0 to skip.
|
|
8
|
+
#
|
|
9
|
+
# Inputs:
|
|
10
|
+
# --platform ios|android (default ios)
|
|
11
|
+
# --target <metamask-mobile dir> (default $PWD)
|
|
12
|
+
# --port <number> (default WATCHER_PORT env, else METRO_PORT, else 8081)
|
|
13
|
+
# Outputs:
|
|
14
|
+
# Progress on stderr; exit 0 bundle ready; 1 timeout or curl error; 2 bad args.
|
|
15
|
+
#
|
|
16
|
+
# Single device op: prewarm the bundle. Does not start Metro or open the dev client.
|
|
17
|
+
set -uo pipefail
|
|
18
|
+
|
|
19
|
+
PLATFORM="ios"
|
|
20
|
+
TARGET="$PWD"
|
|
21
|
+
PORT="${WATCHER_PORT:-${METRO_PORT:-8081}}"
|
|
22
|
+
|
|
23
|
+
while [ "$#" -gt 0 ]; do
|
|
24
|
+
case "$1" in
|
|
25
|
+
--platform) PLATFORM="$2"; shift 2 ;;
|
|
26
|
+
--target) TARGET="$2"; shift 2 ;;
|
|
27
|
+
--port) PORT="$2"; shift 2 ;;
|
|
28
|
+
-h|--help)
|
|
29
|
+
printf 'Usage: prewarm-bundle.sh [--platform ios|android] [--target <dir>] [--port <n>]\n'
|
|
30
|
+
exit 0
|
|
31
|
+
;;
|
|
32
|
+
*) printf 'prewarm-bundle: unknown arg: %s\n' "$1" >&2; exit 2 ;;
|
|
33
|
+
esac
|
|
34
|
+
done
|
|
35
|
+
|
|
36
|
+
case "$PLATFORM" in
|
|
37
|
+
ios|android) ;;
|
|
38
|
+
*) printf 'prewarm-bundle: --platform must be ios or android (got: %s)\n' "$PLATFORM" >&2; exit 2 ;;
|
|
39
|
+
esac
|
|
40
|
+
|
|
41
|
+
TARGET="$(cd "$TARGET" && pwd)"
|
|
42
|
+
LOG_DIR="$TARGET/temp/recipe/runtime"
|
|
43
|
+
mkdir -p "$LOG_DIR"
|
|
44
|
+
METRO_LOG="$LOG_DIR/metro.log"
|
|
45
|
+
|
|
46
|
+
if [ "${MOBILE_BUNDLE_PREWARM:-1}" = "0" ]; then
|
|
47
|
+
printf 'Skipping %s bundle prewarm (MOBILE_BUNDLE_PREWARM=0)\n' "$PLATFORM" >&2
|
|
48
|
+
exit 0
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
TIMEOUT="${MOBILE_BUNDLE_PREWARM_TIMEOUT:-900}"
|
|
52
|
+
|
|
53
|
+
BUNDLE_URL="http://localhost:${PORT}/index.bundle?platform=${PLATFORM}&dev=true&hot=false&lazy=true&transform.engine=hermes&transform.bytecode=1&transform.routerRoot=app&unstable_transformProfile=hermes-stable"
|
|
54
|
+
|
|
55
|
+
printf 'Prewarming %s bundle before launching dev client (set MOBILE_BUNDLE_PREWARM=0 to skip)\n' "$PLATFORM" >&2
|
|
56
|
+
printf ' url: %s\n' "$BUNDLE_URL" >&2
|
|
57
|
+
|
|
58
|
+
curl -sfL --connect-timeout 5 --max-time "$TIMEOUT" -o /dev/null "$BUNDLE_URL" &
|
|
59
|
+
BUNDLE_PID=$!
|
|
60
|
+
|
|
61
|
+
ELAPSED=0
|
|
62
|
+
LAST_PROGRESS=""
|
|
63
|
+
while kill -0 "$BUNDLE_PID" 2>/dev/null; do
|
|
64
|
+
PROGRESS=""
|
|
65
|
+
if [ -f "$METRO_LOG" ]; then
|
|
66
|
+
PROGRESS="$(grep -E '^[[:space:]]*(iOS|Android).*index\.(js|tsx?).*%|Bundl(ed|ing)|Finished' "$METRO_LOG" 2>/dev/null | tail -1 | tr -d '\r' || true)"
|
|
67
|
+
fi
|
|
68
|
+
if [ -n "$PROGRESS" ] && [ "$PROGRESS" != "$LAST_PROGRESS" ]; then
|
|
69
|
+
printf 'Bundle progress: %s\n' "$PROGRESS" >&2
|
|
70
|
+
LAST_PROGRESS="$PROGRESS"
|
|
71
|
+
elif [ $((ELAPSED % 30)) -eq 0 ] && [ "$ELAPSED" -gt 0 ]; then
|
|
72
|
+
printf 'Waiting for %s bundle (%ss/%ss)%s\n' "$PLATFORM" "$ELAPSED" "$TIMEOUT" \
|
|
73
|
+
"${LAST_PROGRESS:+ — $LAST_PROGRESS}" >&2
|
|
74
|
+
fi
|
|
75
|
+
if [ "$ELAPSED" -ge "$TIMEOUT" ]; then
|
|
76
|
+
kill "$BUNDLE_PID" 2>/dev/null || true
|
|
77
|
+
wait "$BUNDLE_PID" 2>/dev/null || true
|
|
78
|
+
printf 'prewarm-bundle: %s bundle did not become ready before timeout (%ss)\n' "$PLATFORM" "$TIMEOUT" >&2
|
|
79
|
+
[ -f "$METRO_LOG" ] && tail -80 "$METRO_LOG" >&2 || true
|
|
80
|
+
printf ' Next: check %s for errors or reduce MOBILE_BUNDLE_PREWARM_TIMEOUT\n' "$METRO_LOG" >&2
|
|
81
|
+
exit 1
|
|
82
|
+
fi
|
|
83
|
+
sleep 3
|
|
84
|
+
ELAPSED=$((ELAPSED + 3))
|
|
85
|
+
done
|
|
86
|
+
|
|
87
|
+
if wait "$BUNDLE_PID"; then
|
|
88
|
+
printf '%s bundle ready\n' "$PLATFORM" >&2
|
|
89
|
+
exit 0
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
printf 'prewarm-bundle: %s bundle curl failed\n' "$PLATFORM" >&2
|
|
93
|
+
[ -f "$METRO_LOG" ] && tail -80 "$METRO_LOG" >&2 || true
|
|
94
|
+
printf ' Next: check %s for Metro errors\n' "$METRO_LOG" >&2
|
|
95
|
+
exit 1
|