@deeeed/metamask-harness 0.6.2 → 0.7.0
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 +77 -0
- package/adapters/extension/inject.mjs +7 -0
- package/adapters/extension/reattach.sh +210 -0
- package/adapters/extension/start-watch.sh +11 -17
- package/adapters/manifest.json +65 -9
- package/adapters/mobile/lib/tmux-viewer.sh +31 -10
- package/adapters/mobile/open-device.sh +14 -1
- package/adapters/mobile/stop-metro.sh +1 -1
- package/adapters/mobile/yarn-setup.sh +15 -1
- package/adapters/shared/activate-repo-ruby.sh +124 -0
- package/adapters/shared/open-log-window.sh +55 -0
- package/adapters/shared/resolve-farmslot-ports-core.mjs +3 -205
- package/adapters/shared/resolve-farmslot-ports.mjs +4 -19
- package/adapters/shared/resolve-farmslot-ports.sh +6 -104
- package/adapters/shared/resolve-slot-ports-core.mjs +213 -0
- package/adapters/shared/resolve-slot-ports.mjs +20 -0
- package/adapters/shared/resolve-slot-ports.sh +110 -0
- package/adapters/shared/tmux-session.sh +35 -0
- package/dist/adapters/extension/runtime-decision.js +4 -0
- package/dist/adapters/mobile/provision.js +25 -2
- package/dist/adapters/{resolve-farmslot-ports.js → resolve-slot-ports.js} +4 -2
- package/dist/adapters/slot-ports.js +8 -10
- package/dist/cli-commands.js +1 -1
- package/dist/commands/call.js +5 -0
- package/dist/commands/doctor.js +21 -1
- package/dist/commands/fixtures.js +5 -3
- package/dist/commands/launch/extension.js +80 -6
- package/dist/commands/launch/index.js +10 -1
- package/dist/commands/list-executables.js +48 -0
- package/dist/commands/logs.js +25 -2
- package/dist/commands/manifest.js +27 -7
- package/dist/commands/parse-args.js +1 -0
- package/dist/commands/run.js +3 -4
- package/dist/live-adapter-contract.js +30 -9
- package/dist/mm-harness-cli.js +3 -1
- package/dist/paths.js +4 -1
- package/package.json +1 -1
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# activate-repo-ruby.sh — pin the target repo's declared Ruby for non-interactive spawns
|
|
2
|
+
#
|
|
3
|
+
# iOS pod/gem work (yarn setup, native build) reads Ruby from PATH. Under tmux /
|
|
4
|
+
# nohup / a cold checkout the PATH is the system Ruby, which does not match the
|
|
5
|
+
# repo's .ruby-version and fails `bundle install` / `pod install` with native gem
|
|
6
|
+
# build errors. Sourced by the leaves that trigger pods so they run the pinned
|
|
7
|
+
# Ruby, mirroring activate-repo-node.sh for Node.
|
|
8
|
+
#
|
|
9
|
+
# On success sets REPO_RUBY_VERSION / REPO_RUBY_BIN / REPO_RUBY_BIN_DIR /
|
|
10
|
+
# REPO_RUBY_PATH_PREFIX and prepends the bin dir to PATH.
|
|
11
|
+
#
|
|
12
|
+
# Usage:
|
|
13
|
+
# . /path/to/activate-repo-ruby.sh
|
|
14
|
+
# activate_repo_ruby [target-dir] # 0 pinned; 1 none declared; 2 declared but unresolved
|
|
15
|
+
# activate_repo_ruby_best_effort [dir] # never fails the caller; warns + teaches on 2
|
|
16
|
+
|
|
17
|
+
_repo_ruby_matches_req() {
|
|
18
|
+
local req="$1" actual="${2:-}"
|
|
19
|
+
[ -n "$actual" ] || actual="$("$REPO_RUBY_BIN" -e 'print RUBY_VERSION' 2>/dev/null || true)"
|
|
20
|
+
[ -n "$actual" ] || return 1
|
|
21
|
+
[ "$actual" = "$req" ] && return 0
|
|
22
|
+
case "$req" in
|
|
23
|
+
*.*.*) return 1 ;;
|
|
24
|
+
*.*) [[ "$actual" == "$req."* ]] ;;
|
|
25
|
+
*) [[ "$actual" == "$req"* ]] ;;
|
|
26
|
+
esac
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
_repo_ruby_set_from_bin() {
|
|
30
|
+
local candidate="$1"
|
|
31
|
+
[ -n "$candidate" ] && [ -x "$candidate" ] || return 1
|
|
32
|
+
REPO_RUBY_BIN="$candidate"
|
|
33
|
+
REPO_RUBY_BIN_DIR="$(cd "$(dirname "$REPO_RUBY_BIN")" && pwd)"
|
|
34
|
+
REPO_RUBY_PATH_PREFIX="${REPO_RUBY_BIN_DIR}:"
|
|
35
|
+
export PATH="${REPO_RUBY_BIN_DIR}:${PATH}"
|
|
36
|
+
return 0
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
_repo_ruby_try_req() {
|
|
40
|
+
local target="$1" req="$2"
|
|
41
|
+
[ -n "$req" ] || return 1
|
|
42
|
+
REPO_RUBY_VERSION="$req"
|
|
43
|
+
|
|
44
|
+
if command -v asdf >/dev/null 2>&1; then
|
|
45
|
+
local asdf_root
|
|
46
|
+
asdf_root="$(asdf where ruby "$req" 2>/dev/null || true)"
|
|
47
|
+
if [ -n "$asdf_root" ] && _repo_ruby_set_from_bin "$asdf_root/bin/ruby" && _repo_ruby_matches_req "$req"; then
|
|
48
|
+
echo "[env] ruby $("$REPO_RUBY_BIN" -e 'print RUBY_VERSION') from .ruby-version/.tool-versions via asdf ($req)" >&2
|
|
49
|
+
return 0
|
|
50
|
+
fi
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
if command -v rbenv >/dev/null 2>&1; then
|
|
54
|
+
local rbenv_root
|
|
55
|
+
rbenv_root="$(rbenv root 2>/dev/null || true)"
|
|
56
|
+
if [ -n "$rbenv_root" ] && _repo_ruby_set_from_bin "$rbenv_root/versions/$req/bin/ruby" && _repo_ruby_matches_req "$req"; then
|
|
57
|
+
echo "[env] ruby $("$REPO_RUBY_BIN" -e 'print RUBY_VERSION') from .ruby-version via rbenv ($req)" >&2
|
|
58
|
+
return 0
|
|
59
|
+
fi
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
if command -v mise >/dev/null 2>&1; then
|
|
63
|
+
local mise_bin
|
|
64
|
+
mise_bin="$(mise x -C "$target" -- which ruby 2>/dev/null || true)"
|
|
65
|
+
if _repo_ruby_set_from_bin "$mise_bin" && _repo_ruby_matches_req "$req"; then
|
|
66
|
+
echo "[env] ruby $("$REPO_RUBY_BIN" -e 'print RUBY_VERSION') from .ruby-version via mise ($req)" >&2
|
|
67
|
+
return 0
|
|
68
|
+
fi
|
|
69
|
+
fi
|
|
70
|
+
return 1
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
activate_repo_ruby() {
|
|
74
|
+
local target="${1:-.}"
|
|
75
|
+
REPO_RUBY_VERSION=""
|
|
76
|
+
REPO_RUBY_BIN=""
|
|
77
|
+
REPO_RUBY_BIN_DIR=""
|
|
78
|
+
REPO_RUBY_PATH_PREFIX=""
|
|
79
|
+
|
|
80
|
+
local declared=false req=""
|
|
81
|
+
if [ -f "$target/.ruby-version" ]; then
|
|
82
|
+
declared=true
|
|
83
|
+
req="$(tr -d ' \t\r\n' < "$target/.ruby-version")"
|
|
84
|
+
req="${req#ruby-}"
|
|
85
|
+
_repo_ruby_try_req "$target" "$req" && return 0
|
|
86
|
+
fi
|
|
87
|
+
if [ -z "$req" ] && [ -f "$target/.tool-versions" ]; then
|
|
88
|
+
declared=true
|
|
89
|
+
req="$(awk '/^ruby / {print $2; exit}' "$target/.tool-versions")"
|
|
90
|
+
_repo_ruby_try_req "$target" "$req" && return 0
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
if [ "$declared" != true ]; then
|
|
94
|
+
return 1
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
# Declared already-on-PATH match (e.g. chruby/system already correct).
|
|
98
|
+
local path_ruby
|
|
99
|
+
path_ruby="$(command -v ruby 2>/dev/null || true)"
|
|
100
|
+
if [ -n "$req" ] && _repo_ruby_set_from_bin "$path_ruby" && _repo_ruby_matches_req "$req"; then
|
|
101
|
+
echo "[env] ruby $("$REPO_RUBY_BIN" -e 'print RUBY_VERSION') already on PATH ($req)" >&2
|
|
102
|
+
return 0
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
REPO_RUBY_BIN=""
|
|
106
|
+
REPO_RUBY_BIN_DIR=""
|
|
107
|
+
REPO_RUBY_PATH_PREFIX=""
|
|
108
|
+
return 2
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# Best-effort: never fails the caller. On a declared-but-unresolved Ruby, warn with
|
|
112
|
+
# a teaching hint so a subsequent pod/gem failure is diagnosable (system Ruby).
|
|
113
|
+
activate_repo_ruby_best_effort() {
|
|
114
|
+
local target="${1:-.}"
|
|
115
|
+
# Guard the call so a non-zero return (no version / unresolved) never trips the
|
|
116
|
+
# caller's set -e before we can inspect the code.
|
|
117
|
+
local rc=0
|
|
118
|
+
activate_repo_ruby "$target" || rc=$?
|
|
119
|
+
if [ "$rc" -eq 2 ]; then
|
|
120
|
+
echo "[env] repo pins ruby ${REPO_RUBY_VERSION:-?} (.ruby-version/.tool-versions) but no installed manager provided it; using system ruby." >&2
|
|
121
|
+
echo " Next: install it — asdf install ruby ${REPO_RUBY_VERSION:-<version>} (or rbenv install) — then re-run, so iOS gems build against the pinned Ruby" >&2
|
|
122
|
+
fi
|
|
123
|
+
return 0
|
|
124
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# open-log-window.sh — (re)open a read-only tmux tail window for a dev-server log
|
|
3
|
+
# in the run-owned session, WITHOUT touching the dev-server process. Idempotent:
|
|
4
|
+
# an existing same-name window is replaced with a fresh tail. Used by
|
|
5
|
+
# `mm-harness logs --window` to recover a window that was closed while Metro/webpack
|
|
6
|
+
# keeps running.
|
|
7
|
+
#
|
|
8
|
+
# Args: --window <name> --log <path> [--runtime-dir <dir>]
|
|
9
|
+
# Exit: 0 opened; 1 no run-owned session / no tmux / log missing (teaches); 2 bad args.
|
|
10
|
+
set -euo pipefail
|
|
11
|
+
|
|
12
|
+
WINDOW=""
|
|
13
|
+
LOG=""
|
|
14
|
+
RUNTIME_DIR=""
|
|
15
|
+
require_value() { [ "$#" -ge 2 ] || { echo "Missing value for $1" >&2; exit 2; }; }
|
|
16
|
+
while [ "$#" -gt 0 ]; do
|
|
17
|
+
case "$1" in
|
|
18
|
+
--window) require_value "$@"; WINDOW="$2"; shift 2 ;;
|
|
19
|
+
--log) require_value "$@"; LOG="$2"; shift 2 ;;
|
|
20
|
+
--runtime-dir) require_value "$@"; RUNTIME_DIR="$2"; shift 2 ;;
|
|
21
|
+
-h|--help) echo "Usage: open-log-window.sh --window <name> --log <path> [--runtime-dir <dir>]"; exit 0 ;;
|
|
22
|
+
*) echo "Unknown arg: $1" >&2; exit 2 ;;
|
|
23
|
+
esac
|
|
24
|
+
done
|
|
25
|
+
[ -n "$WINDOW" ] && [ -n "$LOG" ] || { echo "open-log-window: --window and --log are required" >&2; exit 2; }
|
|
26
|
+
|
|
27
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
28
|
+
# shellcheck disable=SC1091
|
|
29
|
+
for _src in "$SCRIPT_DIR/tmux-session.sh" "$SCRIPT_DIR/lib/tmux-session.sh"; do
|
|
30
|
+
[ -f "$_src" ] && { . "$_src"; break; }
|
|
31
|
+
done
|
|
32
|
+
unset _src
|
|
33
|
+
|
|
34
|
+
if ! command -v tmux >/dev/null 2>&1; then
|
|
35
|
+
echo "open-log-window: tmux is not installed; cannot open a log window." >&2
|
|
36
|
+
echo " Next: tail the log directly — mm-harness logs --full" >&2
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
if [ ! -f "$LOG" ]; then
|
|
40
|
+
echo "open-log-window: no log at $LOG (dev server not started for this checkout)." >&2
|
|
41
|
+
echo " Next: start it — mm-harness launch" >&2
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
session=""
|
|
45
|
+
command -v resolve_run_tmux_session >/dev/null 2>&1 && session="$(resolve_run_tmux_session "$RUNTIME_DIR")"
|
|
46
|
+
if [ -z "$session" ] || ! tmux has-session -t "=$session" 2>/dev/null; then
|
|
47
|
+
echo "open-log-window: no run-owned tmux session to place the window in." >&2
|
|
48
|
+
echo " Next: run inside your slot's tmux session, or set RECIPE_TMUX_SESSION=<session>, then retry" >&2
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
tmux kill-window -t "${session}:${WINDOW}" 2>/dev/null || true
|
|
53
|
+
log_q="$(printf '%q' "$LOG")"
|
|
54
|
+
tmux new-window -d -t "$session" -n "$WINDOW" "exec tail -n +1 -F $log_q"
|
|
55
|
+
echo "log window → tmux ${session}:${WINDOW}" >&2
|
|
@@ -1,205 +1,3 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import os from 'node:os';
|
|
5
|
-
import path from 'node:path';
|
|
6
|
-
import { fileURLToPath } from 'node:url';
|
|
7
|
-
|
|
8
|
-
const coreDir = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
-
|
|
10
|
-
function pathDefault(key) {
|
|
11
|
-
for (const candidate of [
|
|
12
|
-
path.join(coreDir, 'path-defaults.json'),
|
|
13
|
-
path.join(coreDir, '../../adapters/shared/path-defaults.json'),
|
|
14
|
-
]) {
|
|
15
|
-
if (!fs.existsSync(candidate)) continue;
|
|
16
|
-
const value = JSON.parse(fs.readFileSync(candidate, 'utf8'))[key];
|
|
17
|
-
if (value) return value;
|
|
18
|
-
}
|
|
19
|
-
throw new Error(`Missing path default: ${key}`);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function recipeRuntimeDir() {
|
|
23
|
-
return process.env.RECIPE_RUNTIME_DIR || pathDefault('recipeRuntimeDir');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function formatKvLines(kv) {
|
|
27
|
-
const lines = [];
|
|
28
|
-
if (kv.CDP_PORT !== undefined) lines.push(`CDP_PORT=${kv.CDP_PORT}`);
|
|
29
|
-
if (kv.WATCHER_PORT !== undefined) lines.push(`WATCHER_PORT=${kv.WATCHER_PORT}`);
|
|
30
|
-
if (kv.SLOT_ID) lines.push(`SLOT_ID=${kv.SLOT_ID}`);
|
|
31
|
-
if (kv.IOS_SIMULATOR) lines.push(`IOS_SIMULATOR=${kv.IOS_SIMULATOR}`);
|
|
32
|
-
return lines.length ? `${lines.join('\n')}\n` : '';
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function realRepoPath(repo) {
|
|
36
|
-
if (!repo) return null;
|
|
37
|
-
try {
|
|
38
|
-
return fs.realpathSync(repo);
|
|
39
|
-
} catch {
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function inferSlotSuffix(repo) {
|
|
45
|
-
const base = path.basename(repo);
|
|
46
|
-
const m = /-(\d+)$/u.exec(base);
|
|
47
|
-
return m ? m[1] : null;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function scoreSlot(slot, slotSuffix) {
|
|
51
|
-
const resources = slot.resources ?? {};
|
|
52
|
-
const cdp = resources.browser?.cdp_port;
|
|
53
|
-
const port = resources['dev-server']?.port;
|
|
54
|
-
const simulator = resources['ios-sim']?.simulator;
|
|
55
|
-
const session = slot.session ?? '';
|
|
56
|
-
const slotId = slot.id ?? '';
|
|
57
|
-
let score = 0;
|
|
58
|
-
if (cdp !== undefined) score += 100;
|
|
59
|
-
if (port !== undefined) score += 10;
|
|
60
|
-
if (slotSuffix) {
|
|
61
|
-
if (session === `mme-${slotSuffix}`) score += 50;
|
|
62
|
-
if (slotId.endsWith(`mme-${slotSuffix}`) || slotId.includes(`-mme-${slotSuffix}`)) score += 40;
|
|
63
|
-
}
|
|
64
|
-
if (!slotId.toLowerCase().includes('demo')) score += 5;
|
|
65
|
-
return [score, cdp, port, slotId, simulator];
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function resolveFarmslotPortsByRepo(repo) {
|
|
69
|
-
const realRepo = realRepoPath(repo);
|
|
70
|
-
if (!realRepo) return null;
|
|
71
|
-
|
|
72
|
-
const slotSuffix = inferSlotSuffix(realRepo);
|
|
73
|
-
const roots = [];
|
|
74
|
-
// A slot checkout lives at <workspace>/repos/<slot>; that workspace's own
|
|
75
|
-
// pool is the authoritative one for this repo — machine-global fallbacks
|
|
76
|
-
// (env root, dev checkout) apply only when the repo is not workspace-shaped.
|
|
77
|
-
if (path.basename(path.dirname(realRepo)) === 'repos') {
|
|
78
|
-
roots.push(path.join(path.dirname(path.dirname(realRepo)), 'farmslot'));
|
|
79
|
-
}
|
|
80
|
-
if (process.env.FARMSLOT_ROOT) roots.push(process.env.FARMSLOT_ROOT);
|
|
81
|
-
roots.push(path.join(os.homedir(), 'dev', 'farmslot'));
|
|
82
|
-
|
|
83
|
-
for (const root of roots) {
|
|
84
|
-
if (!root || !fs.existsSync(path.join(root, 'pool'))) continue;
|
|
85
|
-
const poolDir = path.join(root, 'pool');
|
|
86
|
-
let best = null;
|
|
87
|
-
|
|
88
|
-
for (const name of fs.readdirSync(poolDir).sort()) {
|
|
89
|
-
if (!name.endsWith('.json') || name.includes('.bak.')) continue;
|
|
90
|
-
let data;
|
|
91
|
-
try {
|
|
92
|
-
data = JSON.parse(fs.readFileSync(path.join(poolDir, name), 'utf8'));
|
|
93
|
-
} catch {
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
for (const slot of data.slots ?? []) {
|
|
97
|
-
const slotRepo = slot.repo ?? '';
|
|
98
|
-
if (!slotRepo) continue;
|
|
99
|
-
let slotReal;
|
|
100
|
-
try {
|
|
101
|
-
slotReal = fs.realpathSync(slotRepo);
|
|
102
|
-
} catch {
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
if (slotReal !== realRepo) continue;
|
|
106
|
-
const scored = scoreSlot(slot, slotSuffix);
|
|
107
|
-
if (!best || scored[0] > best[0]) best = scored;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (best) {
|
|
112
|
-
const [, cdp, port, slotId, simulator] = best;
|
|
113
|
-
return formatKvLines({
|
|
114
|
-
...(cdp !== undefined ? { CDP_PORT: cdp } : {}),
|
|
115
|
-
...(port !== undefined ? { WATCHER_PORT: port } : {}),
|
|
116
|
-
...(slotId ? { SLOT_ID: slotId } : {}),
|
|
117
|
-
...(simulator ? { IOS_SIMULATOR: simulator } : {}),
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export function resolveDefaultExtensionPorts(repo) {
|
|
125
|
-
const n = inferSlotSuffix(repo);
|
|
126
|
-
if (!n) return null;
|
|
127
|
-
return formatKvLines({
|
|
128
|
-
CDP_PORT: 6660 + Number(n),
|
|
129
|
-
WATCHER_PORT: 9010 + Number(n),
|
|
130
|
-
SLOT_ID: `local-extension-${n}`,
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export function resolveExtensionRuntimePorts(repo) {
|
|
135
|
-
return resolveFarmslotPortsByRepo(repo) ?? resolveDefaultExtensionPorts(repo) ?? '';
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export function resolveMobileSlotDefaults(repo) {
|
|
139
|
-
const n = inferSlotSuffix(repo);
|
|
140
|
-
if (!n) return null;
|
|
141
|
-
return formatKvLines({
|
|
142
|
-
WATCHER_PORT: 8060 + Number(n),
|
|
143
|
-
IOS_SIMULATOR: `mm-${n}`,
|
|
144
|
-
SLOT_ID: `local-mobile-${n}`,
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export function resolveMobileRuntimeContext(repo) {
|
|
149
|
-
const ctxPath = path.join(repo, recipeRuntimeDir(), 'agentic-runtime.json');
|
|
150
|
-
if (fs.existsSync(ctxPath)) {
|
|
151
|
-
try {
|
|
152
|
-
const c = JSON.parse(fs.readFileSync(ctxPath, 'utf8'));
|
|
153
|
-
if (c.simulator || (c.metroPort != null && c.metroPort !== '')) {
|
|
154
|
-
return formatKvLines({
|
|
155
|
-
...(c.metroPort != null && c.metroPort !== '' ? { WATCHER_PORT: c.metroPort } : {}),
|
|
156
|
-
...(c.simulator ? { IOS_SIMULATOR: c.simulator } : {}),
|
|
157
|
-
...(c.slotId ? { SLOT_ID: c.slotId } : {}),
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
} catch {
|
|
161
|
-
/* unreadable context falls through to the provision baseline */
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
return resolveMobileProvisionBaseline(repo);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// A provisioned-but-unprepared slot has no agentic-runtime.json yet, but the
|
|
168
|
-
// provision baseline records the same authoritative simulator/port identity —
|
|
169
|
-
// without it, a fresh slot's first launch degrades to the simctl `booted`
|
|
170
|
-
// alias and misses the installed dev client entirely.
|
|
171
|
-
function resolveMobileProvisionBaseline(repo) {
|
|
172
|
-
const basePath = path.join(repo, recipeRuntimeDir(), 'runway-provision.json');
|
|
173
|
-
if (!fs.existsSync(basePath)) return null;
|
|
174
|
-
try {
|
|
175
|
-
const c = JSON.parse(fs.readFileSync(basePath, 'utf8'));
|
|
176
|
-
const simulator = c.simulator?.name || c.simulator?.udid;
|
|
177
|
-
const watcherPort = c.watcherPort != null && c.watcherPort !== '' ? c.watcherPort : undefined;
|
|
178
|
-
if (!simulator && watcherPort === undefined) return null;
|
|
179
|
-
return formatKvLines({
|
|
180
|
-
...(watcherPort !== undefined ? { WATCHER_PORT: watcherPort } : {}),
|
|
181
|
-
...(simulator ? { IOS_SIMULATOR: simulator } : {}),
|
|
182
|
-
...(c.slotId ? { SLOT_ID: c.slotId } : {}),
|
|
183
|
-
});
|
|
184
|
-
} catch {
|
|
185
|
-
return null;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
export function resolveMobileRuntimePorts(repo) {
|
|
190
|
-
return (
|
|
191
|
-
resolveMobileRuntimeContext(repo)
|
|
192
|
-
?? resolveFarmslotPortsByRepo(repo)
|
|
193
|
-
?? resolveMobileSlotDefaults(repo)
|
|
194
|
-
?? ''
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
export const cliFns = {
|
|
199
|
-
resolve_farmslot_ports_by_repo: resolveFarmslotPortsByRepo,
|
|
200
|
-
resolve_default_extension_ports: resolveDefaultExtensionPorts,
|
|
201
|
-
resolve_extension_runtime_ports: (repo) => resolveExtensionRuntimePorts(repo) || null,
|
|
202
|
-
resolve_mobile_runtime_context: resolveMobileRuntimeContext,
|
|
203
|
-
resolve_mobile_slot_defaults: resolveMobileSlotDefaults,
|
|
204
|
-
resolve_mobile_runtime_ports: (repo) => resolveMobileRuntimePorts(repo) || null,
|
|
205
|
-
};
|
|
1
|
+
// Back-compat shim: the port-resolution core is now resolve-slot-ports-core.mjs.
|
|
2
|
+
// Re-exports it verbatim for one release so importers of the old path keep resolving.
|
|
3
|
+
export * from './resolve-slot-ports-core.mjs';
|
|
@@ -1,20 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const [, , fn, repo] = process.argv;
|
|
7
|
-
if (!fn || fn === '-h' || fn === '--help') {
|
|
8
|
-
process.stderr.write('Usage: resolve-farmslot-ports.mjs <fn> <repo>\n');
|
|
9
|
-
process.exit(fn ? 0 : 2);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const handler = cliFns[fn];
|
|
13
|
-
if (!handler) {
|
|
14
|
-
process.stderr.write(`resolve-farmslot-ports: unknown fn: ${fn}\n`);
|
|
15
|
-
process.exit(2);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const out = handler(repo ?? '.');
|
|
19
|
-
if (!out?.trim()) process.exit(1);
|
|
20
|
-
process.stdout.write(out.endsWith('\n') ? out : `${out}\n`);
|
|
2
|
+
// Back-compat shim: this leaf is now resolve-slot-ports.mjs. Delegates to it for one
|
|
3
|
+
// release so `node resolve-farmslot-ports.mjs <fn> <repo>` keeps working (the new CLI
|
|
4
|
+
// reads the same argv positions on import).
|
|
5
|
+
import './resolve-slot-ports.mjs';
|
|
@@ -1,105 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
#
|
|
7
|
-
|
|
8
|
-
# . resolve-farmslot-ports.sh
|
|
9
|
-
# resolve_extension_runtime_ports /path/to/metamask-extension-N
|
|
10
|
-
# -> prints CDP_PORT=... WATCHER_PORT=... SLOT_ID=... lines
|
|
11
|
-
|
|
12
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
13
|
-
_RESOLVE_PORTS_MJS="$SCRIPT_DIR/resolve-farmslot-ports.mjs"
|
|
14
|
-
|
|
15
|
-
_resolve_ports_cli() {
|
|
16
|
-
node "$_RESOLVE_PORTS_MJS" "$1" "${2:-.}"
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
resolve_farmslot_ports_by_repo() {
|
|
20
|
-
_resolve_ports_cli resolve_farmslot_ports_by_repo "$1"
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
infer_extension_slot_suffix() {
|
|
24
|
-
local repo="$1" base
|
|
25
|
-
base="$(basename "$repo")"
|
|
26
|
-
if [[ "$base" =~ -([0-9]+)$ ]]; then
|
|
27
|
-
printf '%s' "${BASH_REMATCH[1]}"
|
|
28
|
-
return 0
|
|
29
|
-
fi
|
|
30
|
-
return 1
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
resolve_default_extension_ports() {
|
|
34
|
-
_resolve_ports_cli resolve_default_extension_ports "$1"
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
resolve_extension_runtime_ports() {
|
|
38
|
-
_resolve_ports_cli resolve_extension_runtime_ports "${1:-.}"
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
apply_resolved_extension_ports() {
|
|
42
|
-
local repo="${1:-.}" line key val from_pool=false resolved=""
|
|
43
|
-
if resolved="$(_resolve_ports_cli resolve_farmslot_ports_by_repo "$repo" 2>/dev/null)"; then
|
|
44
|
-
from_pool=true
|
|
45
|
-
elif resolved="$(_resolve_ports_cli resolve_default_extension_ports "$repo" 2>/dev/null)"; then
|
|
46
|
-
from_pool=false
|
|
47
|
-
else
|
|
48
|
-
return 0
|
|
49
|
-
fi
|
|
50
|
-
while IFS= read -r line; do
|
|
51
|
-
[ -n "$line" ] || continue
|
|
52
|
-
key="${line%%=*}"
|
|
53
|
-
val="${line#*=}"
|
|
54
|
-
case "$key" in
|
|
55
|
-
CDP_PORT)
|
|
56
|
-
if [ "$from_pool" = true ] || [ -z "${CDP_PORT:-}" ]; then CDP_PORT="$val"; fi
|
|
57
|
-
;;
|
|
58
|
-
WATCHER_PORT)
|
|
59
|
-
if [ "$from_pool" = true ] || [ -z "${WATCHER_PORT:-}" ]; then WATCHER_PORT="$val"; fi
|
|
60
|
-
;;
|
|
61
|
-
SLOT_ID)
|
|
62
|
-
if [ "$from_pool" = true ] || [ -z "${RECIPE_SLOT_ID:-}" ]; then RECIPE_SLOT_ID="$val"; fi
|
|
63
|
-
;;
|
|
64
|
-
esac
|
|
65
|
-
done <<< "$resolved"
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
resolve_mobile_slot_defaults() {
|
|
69
|
-
_resolve_ports_cli resolve_mobile_slot_defaults "$1"
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
resolve_mobile_runtime_context() {
|
|
73
|
-
_resolve_ports_cli resolve_mobile_runtime_context "$1"
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
resolve_mobile_runtime_ports() {
|
|
77
|
-
_resolve_ports_cli resolve_mobile_runtime_ports "${1:-.}"
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
apply_resolved_mobile_ports() {
|
|
81
|
-
local repo="${1:-.}" line key val from_pool=false resolved=""
|
|
82
|
-
if resolved="$(_resolve_ports_cli resolve_farmslot_ports_by_repo "$repo" 2>/dev/null)"; then
|
|
83
|
-
from_pool=true
|
|
84
|
-
elif resolved="$(_resolve_ports_cli resolve_mobile_slot_defaults "$repo" 2>/dev/null)"; then
|
|
85
|
-
from_pool=false
|
|
86
|
-
else
|
|
87
|
-
return 0
|
|
88
|
-
fi
|
|
89
|
-
while IFS= read -r line; do
|
|
90
|
-
[ -n "$line" ] || continue
|
|
91
|
-
key="${line%%=*}"
|
|
92
|
-
val="${line#*=}"
|
|
93
|
-
case "$key" in
|
|
94
|
-
WATCHER_PORT)
|
|
95
|
-
if [ "$from_pool" = true ] || [ -z "${WATCHER_PORT:-}" ]; then WATCHER_PORT="$val"; fi
|
|
96
|
-
;;
|
|
97
|
-
IOS_SIMULATOR)
|
|
98
|
-
if [ "$from_pool" = true ] || [ -z "${IOS_SIMULATOR:-}" ]; then IOS_SIMULATOR="$val"; fi
|
|
99
|
-
;;
|
|
100
|
-
SLOT_ID)
|
|
101
|
-
if [ "$from_pool" = true ] || [ -z "${RECIPE_SLOT_ID:-}" ]; then RECIPE_SLOT_ID="$val"; fi
|
|
102
|
-
;;
|
|
103
|
-
esac
|
|
104
|
-
done <<< "$resolved"
|
|
105
|
-
}
|
|
2
|
+
# Back-compat shim: this wrapper is now resolve-slot-ports.sh. Sources it for one
|
|
3
|
+
# release so old callers keep the same sourced function names (including the
|
|
4
|
+
# resolve_farmslot_ports_by_repo alias defined there).
|
|
5
|
+
_SHIM_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
# shellcheck disable=SC1091
|
|
7
|
+
. "$_SHIM_DIR/resolve-slot-ports.sh"
|